feat: test web ui login handlers with mocks

This commit is contained in:
Aravinth Manivannan 2024-05-06 20:49:44 +05:30
parent 36f1c1e0f4
commit 96ccb47aa8
Signed by: realaravinth
GPG key ID: F8F50389936984FF
5 changed files with 124 additions and 75 deletions

View file

@ -46,8 +46,6 @@ impl RequestAuthorizationInterface for RequestAuthorizationHandler {
self.generate_random_string.clone(),
);
log::info!("service found");
let cmd = RequestAuthorizationCommand::new_command(forge_name)?;
let auth_page = service.request_authorization(cmd).await?;
Ok(HttpResponse::Found()

View file

@ -5,18 +5,19 @@ use actix_web::{get, post, web, HttpResponse};
use url::Url;
use crate::auth::adapter::input::web::routes::RoutesRepository;
use crate::auth::adapter::out::forge::SupportedForges;
use crate::auth::adapter::out::forge::{
forge_repository::ForgeRepositoryInterface, SupportedForges,
};
use crate::auth::application::port::input::ui::{errors::*, login::RequestAuthorizationInterface};
use crate::auth::application::port::out::db::save_oauth_state::SaveOAuthState;
use crate::utils::random_string::GenerateRandomStringInterface;
use crate::ForgeRepository;
use super::template::{LoginCtxFactory, LoginPageInterface};
#[get("/login")]
#[tracing::instrument(name = "login page handler", skip(forges, routes, template))]
async fn login_page(
forges: web::Data<Arc<ForgeRepository>>,
forges: web::Data<Arc<dyn ForgeRepositoryInterface>>,
routes: web::Data<Arc<RoutesRepository>>,
template: web::Data<Arc<dyn LoginPageInterface>>,
) -> InUIResult<HttpResponse> {
@ -29,16 +30,16 @@ async fn login_page(
#[post("/oauth/forgejo/login")]
async fn request_oauth_authorization_forgejo(
forges: web::Data<Arc<ForgeRepository>>,
forges: web::Data<Arc<dyn ForgeRepositoryInterface>>,
save_oauth_state_adapter: web::Data<Arc<dyn SaveOAuthState>>,
routes: web::Data<Arc<RoutesRepository>>,
generate_random_string: web::Data<Arc<dyn GenerateRandomStringInterface>>,
routes: web::Data<Arc<RoutesRepository>>,
settings: web::Data<crate::settings::Settings>,
) -> InUIResult<HttpResponse> {
let oauth_auth_req_uri_adapter = &forges
.get_forge(&SupportedForges::Forgejo)
.get_forge_factory(&SupportedForges::Forgejo)
.unwrap()
.oauth_auth_req_uri_adapter;
.get_oauth_auth_req_uri_adapter();
let process_authorization_response_redirect_uri = Url::parse(&format!(
"{}://{}{}",
@ -46,7 +47,10 @@ async fn request_oauth_authorization_forgejo(
&settings.server.domain,
&routes.process_oauth_authorization_response(&SupportedForges::Forgejo)
))
.map_err(|_| InUIError::InternalServerError)?;
.map_err(|_| {
println!("mistake");
InUIError::InternalServerError
})?;
let web_adapter = super::adapter::RequestAuthorizationHandler::new(
save_oauth_state_adapter.as_ref().to_owned(),
@ -68,26 +72,34 @@ pub fn services(cfg: &mut web::ServiceConfig) {
#[cfg(test)]
mod tests {
use super::*;
use actix_web::http::{header, StatusCode};
use actix_web::{http::header::ContentType, test, App};
use crate::auth::adapter::input::web::login::template::load_templates;
use crate::auth::adapter::out::forge::forgejo::Forgejo;
use crate::auth::adapter::out::forge::forge_factory::{
ForgeAdapterFactoryInterface, MockForgeAdapterFactoryInterface,
};
use crate::auth::adapter::out::forge::forge_repository::MockForgeRepositoryInterface;
use crate::auth::application::port::out::forge::oauth_auth_req_uri::OAuthAuthReqUri;
use crate::auth::application::port::out::{
db::save_oauth_state::MockSaveOAuthState, forge::oauth_auth_req_uri::MockOAuthAuthReqUri,
};
use crate::utils::random_string::*;
#[actix_web::test]
async fn test_get_login_page() {
let settings = crate::settings::Settings::new().unwrap();
async fn test_login_page_handler() {
let mut mock_forges = MockForgeRepositoryInterface::default();
mock_forges
.expect_get_supported_forges()
.return_const(vec![SupportedForges::Forgejo])
.times(1);
let mock_forges: Arc<dyn ForgeRepositoryInterface> = Arc::new(mock_forges);
let forgejo = Forgejo::new(
settings.forges.forgejo.url.clone(),
settings.forges.forgejo.client_id.clone(),
settings.forges.forgejo.client_secret.clone(),
);
let forges = ForgeRepository::new(forgejo);
let routes = RoutesRepository::default();
let app = test::init_service(
App::new()
.app_data(web::Data::new(Arc::new(forges.clone())))
.app_data(web::Data::new(mock_forges))
.app_data(web::Data::new(Arc::new(routes.clone())))
.configure(load_templates)
.service(login_page),
@ -102,4 +114,91 @@ mod tests {
println!("{}", resp.status());
assert!(resp.status().is_success());
}
#[actix_web::test]
async fn test_ui_handler_request_oauth_authorization_forgejo() {
let random_string = "foorand";
let settings = crate::settings::Settings::new().unwrap();
let url = Url::parse("http://test_ui_handler_request_oauth_authorization_forgejo").unwrap();
let mut redirect_uri = url.clone();
redirect_uri.set_query(Some(&format!("state={random_string}")));
let mock_random_generate_string: Arc<dyn GenerateRandomStringInterface> = {
let mut mock_random_generate_string = MockGenerateRandomStringInterface::new();
mock_random_generate_string
.expect_get_random()
.times(1)
.return_const(random_string.to_string());
Arc::new(mock_random_generate_string)
};
let mock_oauth_req_uri: Arc<dyn OAuthAuthReqUri> = {
let r = redirect_uri.clone();
let mut mock_oauth_req_uri = MockOAuthAuthReqUri::new();
mock_oauth_req_uri
.expect_oauth_auth_req_uri()
.times(1)
.returning(move |_, _| Ok(r.clone()));
Arc::new(mock_oauth_req_uri)
};
let mock_save_oauth_state: Arc<dyn SaveOAuthState> = {
let mut mock_save_oauth_state = MockSaveOAuthState::new();
mock_save_oauth_state
.expect_save_oauth_state()
.times(1)
.returning(|_, _, _| Ok(()));
Arc::new(mock_save_oauth_state)
};
let mock_forges: Arc<dyn ForgeRepositoryInterface> = {
let mut mock_forge_factory = MockForgeAdapterFactoryInterface::default();
let a = mock_oauth_req_uri.clone();
mock_forge_factory
.expect_get_oauth_auth_req_uri_adapter()
.times(1)
.returning(move || a.clone());
let mock_forge_factory: Arc<dyn ForgeAdapterFactoryInterface> =
Arc::new(mock_forge_factory);
let mut mock_forges = MockForgeRepositoryInterface::default();
mock_forges
.expect_get_forge_factory()
.times(1)
.returning(move |_| Some(mock_forge_factory.clone()));
Arc::new(mock_forges)
};
let routes = RoutesRepository::default();
let app = test::init_service(
App::new()
.app_data(web::Data::new(mock_save_oauth_state.clone()))
.wrap(tracing_actix_web::TracingLogger::default())
.app_data(web::Data::new(mock_random_generate_string))
.app_data(web::Data::new(mock_forges))
.app_data(web::Data::new(Arc::new(routes.clone())))
.app_data(web::Data::new(settings.clone()))
.service(request_oauth_authorization_forgejo),
)
.await;
let req = test::TestRequest::post()
.uri("/oauth/forgejo/login")
.insert_header(ContentType::html())
.to_request();
let resp = test::call_service(&app, req).await;
let status = resp.status();
assert_eq!(status, StatusCode::FOUND);
assert_eq!(
resp.headers()
.get(header::LOCATION)
.unwrap()
.to_str()
.unwrap(),
redirect_uri.as_str()
);
}
}

View file

@ -8,7 +8,9 @@ pub mod out;
use crate::settings;
use out::db::DBAdapter;
use out::forge::{forgejo::Forgejo, ForgeRepository};
use out::forge::{forge_repository::ForgeRepository, forgejo::Forgejo};
use self::out::forge::forge_repository::ForgeRepositoryInterface;
pub fn load_adapters(
pool: PgPool,
@ -19,11 +21,11 @@ pub fn load_adapters(
settings.forges.forgejo.client_id.clone(),
settings.forges.forgejo.client_secret.clone(),
);
let forges = ForgeRepository::new(forgejo);
let forges: Arc<dyn ForgeRepositoryInterface> = Arc::new(ForgeRepository::new(forgejo));
let f = move |cfg: &mut web::ServiceConfig| {
cfg.app_data(web::Data::new(Arc::new(DBAdapter::new(pool))));
cfg.app_data(web::Data::new(Arc::new(forges.clone())));
cfg.app_data(web::Data::new(forges.clone()));
cfg.configure(input::web::load_ctx());
};

View file

@ -1,57 +1,12 @@
use std::collections::HashMap;
use std::str::FromStr;
use std::sync::Arc;
use derive_more::Display;
use serde::{Deserialize, Serialize};
use crate::auth::application::port::out::forge::oauth_auth_req_uri::OAuthAuthReqUri;
use self::forgejo::Forgejo;
pub mod forge_factory;
pub mod forge_repository;
pub mod forgejo;
#[derive(Clone)]
pub struct ForgeAdapter {
pub oauth_auth_req_uri_adapter: Arc<dyn OAuthAuthReqUri>,
}
#[derive(Clone, Default)]
pub struct ForgeRepository {
forges: HashMap<SupportedForges, ForgeAdapter>,
}
impl ForgeRepository {
fn add_forge(&mut self, name: SupportedForges, forge_factory: ForgeAdapter) {
self.forges.insert(name, forge_factory);
}
pub fn get_supported_forge_str(&self) -> Vec<String> {
self.forges
.clone()
.into_keys()
.map(|v| v.to_string())
.collect()
}
pub fn get_supported_forges(&self) -> Vec<SupportedForges> {
self.forges.clone().into_keys().collect()
}
pub fn get_forge(&self, name: &SupportedForges) -> Option<&ForgeAdapter> {
self.forges.get(name)
}
pub fn new(forgejo: Forgejo) -> Self {
let forgejo_adapter = ForgeAdapter {
oauth_auth_req_uri_adapter: Arc::new(forgejo),
};
let mut s = Self::default();
s.add_forge(SupportedForges::Forgejo, forgejo_adapter);
s
}
}
#[derive(Debug, Display, Clone, Hash, Serialize, Deserialize, PartialEq, Eq, PartialOrd, Ord)]
#[serde(rename_all = "lowercase")]
pub enum SupportedForges {

View file

@ -8,11 +8,6 @@ mod db;
mod settings;
mod utils;
pub use crate::auth::adapter::out::{
db::DBAdapter,
forge::{forgejo::Forgejo, ForgeRepository},
};
#[actix_web::main]
async fn main() {
let settings = settings::Settings::new().unwrap();