librepages/src/tests.rs

292 lines
8.6 KiB
Rust

/*
* Copyright (C) 2022 Aravinth Manivannan <realaravinth@batsense.net>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
use std::sync::Arc;
use actix_web::{
body::{BoxBody, EitherBody},
dev::ServiceResponse,
error::ResponseError,
http::StatusCode,
};
use mktemp::Temp;
use serde::Serialize;
use crate::ctx::api::v1::auth::{Login, Register};
use crate::ctx::api::v1::pages::AddSite;
use crate::ctx::Ctx;
use crate::errors::*;
use crate::page::Page;
use crate::settings::Settings;
use crate::*;
pub const REPO_URL: &str = "https://github.com/mCaptcha/website/";
pub const BRANCH: &str = "gh-pages";
pub async fn get_ctx() -> (Temp, Arc<Ctx>) {
// mktemp::Temp is returned because the temp directory created
// is removed once the variable goes out of scope
let mut settings = Settings::new().unwrap();
let tmp_dir = Temp::new_dir().unwrap();
println!("[log] Test temp directory: {}", tmp_dir.to_str().unwrap());
let page_base_path = tmp_dir.as_path().join("base_path");
settings.page.base_path = page_base_path.to_str().unwrap().into();
settings.init();
println!("[log] Initialzing settings again with test config");
settings.init();
(tmp_dir, Ctx::new(settings).await)
}
#[allow(dead_code, clippy::upper_case_acronyms)]
pub struct FORM;
#[macro_export]
macro_rules! post_request {
($uri:expr) => {
actix_web::test::TestRequest::post().uri($uri)
};
($serializable:expr, $uri:expr) => {
actix_web::test::TestRequest::post()
.uri($uri)
.insert_header((actix_web::http::header::CONTENT_TYPE, "application/json"))
.set_payload(serde_json::to_string($serializable).unwrap())
};
($serializable:expr, $uri:expr, FORM) => {
actix_web::test::TestRequest::post()
.uri($uri)
.set_form($serializable)
};
}
#[macro_export]
macro_rules! get_request {
($app:expr,$route:expr ) => {
test::call_service(&$app, test::TestRequest::get().uri($route).to_request()).await
};
($app:expr, $route:expr, $cookies:expr) => {
test::call_service(
&$app,
test::TestRequest::get()
.uri($route)
.cookie($cookies)
.to_request(),
)
.await
};
}
#[macro_export]
macro_rules! delete_request {
($app:expr,$route:expr ) => {
test::call_service(&$app, test::TestRequest::delete().uri($route).to_request()).await
};
($app:expr, $route:expr, $cookies:expr) => {
test::call_service(
&$app,
test::TestRequest::delete()
.uri($route)
.cookie($cookies)
.to_request(),
)
.await
};
($app:expr, $route:expr, $cookies:expr, $serializable:expr, FORM) => {
test::call_service(
&$app,
test::TestRequest::delete()
.uri($route)
.set_form($serializable)
.cookie($cookies)
.to_request(),
)
.await
};
}
#[macro_export]
macro_rules! get_app {
($ctx:expr) => {
actix_web::test::init_service(
actix_web::App::new()
.app_data($crate::get_json_err())
.wrap($crate::get_identity_service(&$ctx.settings))
.wrap(actix_web::middleware::NormalizePath::new(
actix_web::middleware::TrailingSlash::Trim,
))
.configure($crate::services)
.app_data($crate::WebData::new($ctx.clone())),
)
};
}
/// Utility function to check for status of a test response, attempt response payload serialization
/// and print payload if response status doesn't match expected status
#[macro_export]
macro_rules! check_status {
($resp:expr, $expected:expr) => {
let status = $resp.status();
if status != $expected {
eprintln!(
"[error] Expected status code: {} received: {status}",
$expected
);
let response: serde_json::Value = actix_web::test::read_body_json($resp).await;
eprintln!("[error] Body:\n{:#?}", response);
assert_eq!(status, $expected);
panic!()
}
{
assert_eq!(status, $expected);
}
};
}
#[macro_export]
macro_rules! get_cookie {
($resp:expr) => {
$resp.response().cookies().next().unwrap().to_owned()
};
}
impl Ctx {
/// register and signin utility
pub async fn register_and_signin(
&self,
name: &str,
email: &str,
password: &str,
) -> (Login, ServiceResponse<EitherBody<BoxBody>>) {
self.register_test(name, email, password).await;
self.signin_test(name, password).await
}
pub fn to_arc(&self) -> Arc<Self> {
Arc::new(self.clone())
}
/// register utility
pub async fn register_test(&self, name: &str, email: &str, password: &str) {
let app = get_app!(self.to_arc()).await;
// 1. Register
let msg = Register {
username: name.into(),
password: password.into(),
confirm_password: password.into(),
email: email.into(),
};
println!("{:?}", msg);
let resp = actix_web::test::call_service(
&app,
post_request!(&msg, crate::V1_API_ROUTES.auth.register).to_request(),
)
.await;
if resp.status() != StatusCode::OK {
let resp_err: ErrorToResponse = actix_web::test::read_body_json(resp).await;
panic!("{}", resp_err.error);
}
}
/// signin util
pub async fn signin_test(
&self,
name: &str,
password: &str,
) -> (Login, ServiceResponse<EitherBody<BoxBody>>) {
let app = get_app!(self.to_arc()).await;
// 2. signin
let creds = Login {
login: name.into(),
password: password.into(),
};
let signin_resp = actix_web::test::call_service(
&app,
post_request!(&creds, V1_API_ROUTES.auth.login).to_request(),
)
.await;
assert_eq!(signin_resp.status(), StatusCode::OK);
(creds, signin_resp)
}
/// pub duplicate test
pub async fn bad_post_req_test<T: Serialize>(
&self,
name: &str,
password: &str,
url: &str,
payload: &T,
err: ServiceError,
) {
let (_, signin_resp) = self.signin_test(name, password).await;
let cookies = get_cookie!(signin_resp);
let app = get_app!(self.to_arc()).await;
let resp = actix_web::test::call_service(
&app,
post_request!(&payload, url)
.cookie(cookies.clone())
.to_request(),
)
.await;
assert_eq!(resp.status(), err.status_code());
let resp_err: ErrorToResponse = actix_web::test::read_body_json(resp).await;
//println!("{}", txt.error);
assert_eq!(resp_err.error, format!("{}", err));
}
/// bad post req test without payload
pub async fn bad_post_req_test_witout_payload(
&self,
name: &str,
password: &str,
url: &str,
err: ServiceError,
) {
let (_, signin_resp) = self.signin_test(name, password).await;
let app = get_app!(self.to_arc()).await;
let cookies = get_cookie!(signin_resp);
let resp = actix_web::test::call_service(
&app,
post_request!(url).cookie(cookies.clone()).to_request(),
)
.await;
assert_eq!(resp.status(), err.status_code());
let resp_err: ErrorToResponse = actix_web::test::read_body_json(resp).await;
//println!("{}", resp_err.error);
assert_eq!(resp_err.error, format!("{}", err));
}
pub async fn add_test_site(&self, owner: String) -> Page {
let msg = AddSite {
repo_url: REPO_URL.into(),
branch: BRANCH.into(),
owner,
};
self.add_site(msg).await.unwrap()
}
}