feat: test with mocks
ci/woodpecker/push/woodpecker Pipeline failed Details

This commit is contained in:
Aravinth Manivannan 2024-05-06 19:42:40 +05:30
parent 702cdbdd99
commit 36f1c1e0f4
Signed by: realaravinth
GPG Key ID: F8F50389936984FF
12 changed files with 192 additions and 88 deletions

78
Cargo.lock generated
View File

@ -255,6 +255,12 @@ dependencies = [
"libc",
]
[[package]]
name = "anstyle"
version = "1.0.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "038dfcf04a5feb68e9c60b21c9625a54c2c0616e79b72b0fd87075a056ae1d1b"
[[package]]
name = "async-trait"
version = "0.1.80"
@ -686,6 +692,12 @@ version = "0.15.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1aaf95b3e5c8f23aa320147307562d361db0ae0d51242340f558153b4eb2439b"
[[package]]
name = "downcast"
version = "0.11.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1435fa1053d8b2fbbe9be7e97eca7f33d37b28409959813daefc1446a14247f1"
[[package]]
name = "either"
version = "1.11.0"
@ -816,6 +828,7 @@ dependencies = [
"derive_more",
"lazy_static",
"log",
"mockall",
"pretty_env_logger",
"rand",
"reqwest",
@ -838,6 +851,12 @@ dependencies = [
"percent-encoding",
]
[[package]]
name = "fragile"
version = "2.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6c2141d6d6c8512188a7891b4b01590a45f6dac67afb4f255c4124dbb86d4eaa"
[[package]]
name = "futures-channel"
version = "0.3.30"
@ -1452,6 +1471,33 @@ dependencies = [
"windows-sys 0.48.0",
]
[[package]]
name = "mockall"
version = "0.12.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "43766c2b5203b10de348ffe19f7e54564b64f3d6018ff7648d1e2d6d3a0f0a48"
dependencies = [
"cfg-if",
"downcast",
"fragile",
"lazy_static",
"mockall_derive",
"predicates",
"predicates-tree",
]
[[package]]
name = "mockall_derive"
version = "0.12.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "af7cbce79ec385a1d4f54baa90a76401eb15d9cab93685f62e7e9f942aa00ae2"
dependencies = [
"cfg-if",
"proc-macro2",
"quote",
"syn 2.0.60",
]
[[package]]
name = "mutually_exclusive_features"
version = "0.0.3"
@ -1821,6 +1867,32 @@ version = "0.2.17"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de"
[[package]]
name = "predicates"
version = "3.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "68b87bfd4605926cdfefc1c3b5f8fe560e3feca9d5552cf68c466d3d8236c7e8"
dependencies = [
"anstyle",
"predicates-core",
]
[[package]]
name = "predicates-core"
version = "1.0.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b794032607612e7abeb4db69adb4e33590fa6cf1149e95fd7cb00e634b92f174"
[[package]]
name = "predicates-tree"
version = "1.0.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "368ba315fb8c5052ab692e68a0eefec6ec57b23a36959c14496f0b0df2c0cecf"
dependencies = [
"predicates-core",
"termtree",
]
[[package]]
name = "pretty_env_logger"
version = "0.5.0"
@ -2683,6 +2755,12 @@ dependencies = [
"winapi-util",
]
[[package]]
name = "termtree"
version = "0.4.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3369f5ac52d5eb6ab48c6b4ffdc8efbcad6b89c765749064ba298f2c68a16a76"
[[package]]
name = "thiserror"
version = "1.0.59"

View File

@ -28,7 +28,9 @@ tera = "1.19.1"
tracing = { version = "0.1.40", features = ["log"] }
tracing-actix-web = "0.7.10"
url = { version = "2.5.0", features = ["serde"] }
mockall = "0.12"
[dev-dependencies]
actix-rt= "2.9"
mockall = { version = "0.12", features = ["nightly"] }

View File

@ -55,3 +55,64 @@ impl RequestAuthorizationInterface for RequestAuthorizationHandler {
.finish())
}
}
#[cfg(test)]
mod tests {
use actix_web::http::{header, StatusCode};
use super::*;
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_adapter() {
let random_string = "foorand";
let url = Url::parse("http://test_ui_req_auth_interface_adapter").unwrap();
let oauth_provider = "test_ui_req_auth_interface_adapter";
let mut redirect_uri = url.clone();
redirect_uri.set_query(Some(&format!("state={random_string}")));
let mut mock_random_generate_string = MockGenerateRandomStringInterface::new();
mock_random_generate_string
.expect_get_random()
.times(1)
.return_const(random_string.to_string());
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()));
let mut mock_save_oauth_state = MockSaveOAuthState::new();
mock_save_oauth_state
.expect_save_oauth_state()
.times(1)
.returning(|_, _, _| Ok(()));
let adapter = RequestAuthorizationHandler::new(
Arc::new(mock_save_oauth_state),
Arc::new(mock_oauth_req_uri),
Arc::new(mock_random_generate_string),
url.clone(),
);
let res = adapter
.request_oauth_authorization(oauth_provider.into())
.await
.unwrap();
assert_eq!(res.status(), StatusCode::FOUND);
assert_eq!(
res.headers()
.get(header::LOCATION)
.unwrap()
.to_str()
.unwrap(),
redirect_uri.as_str()
);
}
}

View File

@ -2,8 +2,8 @@ use std::sync::Arc;
use sqlx::PgPool;
use crate::db::migrate::RunMigrations;
use crate::auth::application::port::out::db::save_oauth_state::SaveOAuthState;
use crate::db::migrate::RunMigrations;
pub mod postgres;

View File

@ -2,46 +2,3 @@ pub mod delete_oauth_state;
pub mod errors;
pub mod oauth_state_exists;
pub mod save_oauth_state;
#[cfg(test)]
pub mod tests {
use std::sync::{Arc, RwLock};
use url::Url;
use super::*;
use errors::*;
use save_oauth_state::SaveOAuthState;
#[derive(Clone, Default)]
pub struct MockDB {
pub calls: Arc<RwLock<Vec<Call>>>,
}
#[derive(Clone, Default)]
pub struct Call {
pub state: String,
pub oauth_provider: String,
pub redirect_uri: String,
}
#[async_trait::async_trait]
impl SaveOAuthState for MockDB {
async fn save_oauth_state(
&self,
state: &str,
oauth_provider: &str,
redirect_uri: &Url,
) -> OutDBPortResult<()> {
let mut calls = self.calls.write().unwrap();
calls.push(Call {
state: state.to_string(),
oauth_provider: oauth_provider.to_string(),
redirect_uri: redirect_uri.to_string(),
});
Ok(())
}
}
}

View File

@ -1,7 +1,10 @@
use mockall::predicate::*;
use mockall::*;
use url::Url;
use super::errors::*;
#[automock]
#[async_trait::async_trait]
pub trait SaveOAuthState: Send + Sync {
/// Save OAuth state code generated during authorization request, which will later be used to

View File

@ -2,29 +2,3 @@ pub mod errors;
pub mod oauth_auth_req_uri;
pub mod refresh_access_token;
pub mod request_access_token;
#[cfg(test)]
pub mod tests {
use url::Url;
use super::*;
use errors::*;
use oauth_auth_req_uri::OAuthAuthReqUri;
#[derive(Clone, Default)]
pub struct MockForge; // {
#[async_trait::async_trait]
impl OAuthAuthReqUri for MockForge {
fn oauth_auth_req_uri(
&self,
state: &str,
process_authorization_response_uri: &Url,
) -> OutForgePortResult<Url> {
let mut u = process_authorization_response_uri.clone();
u.set_query(Some(&format!("state={state}")));
Ok(u)
}
}
}

View File

@ -1,6 +1,9 @@
use super::errors::*;
use mockall::*;
use url::Url;
use super::errors::*;
#[automock]
pub trait OAuthAuthReqUri: Send + Sync {
fn oauth_auth_req_uri(
&self,

View File

@ -0,0 +1,8 @@
use super::errors::*;
use crate::auth::domain::AuthCode;
#[async_trait::async_trait]
pub trait RefreshAccessToken {
// returns ID of newly created user user
async fn refresh_access_token(&self, auth_code: &AuthCode) -> OutForgePortResult<AuthCode>;
}

View File

@ -0,0 +1,8 @@
use super::errors::*;
use crate::auth::domain::AuthCode;
#[async_trait::async_trait]
pub trait RequestAccessToken: Send + Sync {
// returns ID of newly created user user
async fn request_access_token(&self, code: &str) -> OutForgePortResult<AuthCode>;
}

View File

@ -75,8 +75,8 @@ mod tests {
use crate::auth::application::{
port::out::{
db::{save_oauth_state::MockSaveOAuthState, tests::MockDB},
forge::tests::MockForge,
db::save_oauth_state::MockSaveOAuthState,
forge::oauth_auth_req_uri::MockOAuthAuthReqUri,
},
services::request_authorization::command::RequestAuthorizationCommand,
};
@ -87,33 +87,40 @@ mod tests {
#[actix_rt::test]
async fn test_service() {
let random_string = "foorand";
let save_oauth_state = MockDB::default();
let oauth_auth_req_uri = MockForge;
let url = Url::parse("http://test_service_request_auth").unwrap();
let oauth_provider = "test_service_request_auth_oauth_provider";
let mut redirect_uri = url.clone();
redirect_uri.set_query(Some(&format!("state={random_string}")));
let mut mock_random_generate_string = MockGenerateRandomStringInterface::new();
mock_random_generate_string
.expect_get_random()
.times(1)
.return_const(random_string.to_string());
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()));
let mut mock_save_oauth_state = MockSaveOAuthState::new();
mock_save_oauth_state
.expect_save_oauth_state()
.times(1)
.returning(|_, _, _| Ok(()));
let s = RequestAuthorizationService::new(
Arc::new(save_oauth_state.clone()),
Arc::new(oauth_auth_req_uri),
Arc::new(mock_save_oauth_state),
Arc::new(mock_oauth_req_uri),
url.clone(),
Arc::new(mock_random_generate_string),
);
let cmd = RequestAuthorizationCommand::new_command(oauth_provider.to_owned()).unwrap();
let res = s.request_authorization(cmd).await.unwrap().to_string();
{
let save_oauth_state_ctx = save_oauth_state.calls.read().unwrap();
let call = save_oauth_state_ctx.first().unwrap();
assert_eq!(
res,
format!("http://test_service_request_auth/?state={}", &call.state)
);
assert_eq!(call.oauth_provider, oauth_provider);
assert_eq!(call.redirect_uri, url.to_string());
}
let res = s.request_authorization(cmd).await.unwrap();
assert_eq!(res, redirect_uri);
}
}

View File

@ -1,7 +1,10 @@
use std::sync::Arc;
use actix_web::web;
use mockall::predicate::*;
use mockall::*;
#[automock]
pub trait GenerateRandomStringInterface: Send + Sync {
fn get_random(&self, len: usize) -> String;
}