// SPDX-FileCopyrightText: 2024 Aravinth Manivannan // // SPDX-License-Identifier: AGPL-3.0-or-later use derive_builder::Builder; use mockall::predicate::*; use mockall::*; use crate::identity::application::port::output::db::{emp_id_exists::*, get_invite::*}; use crate::identity::domain::{accept_invite_command::*, invite_accepted_event::*}; use super::errors::*; #[automock] #[async_trait::async_trait] pub trait EmployeeAcceptInviteUseCase: Send + Sync { async fn accept_invite(&self, cmd: AcceptInviteCommand) -> IdentityResult; async fn reject_invite(&self, cmd: AcceptInviteCommand) -> IdentityResult; } pub type EmployeeAcceptInviteServiceObj = std::sync::Arc; #[derive(Clone, Builder)] pub struct EmployeeAcceptInviteService { db_emp_id_exists_adapter: EmpIDExistsOutDBPortObj, db_get_invite_adapter: GetInviteOutDBPortObj, } #[async_trait::async_trait] impl EmployeeAcceptInviteUseCase for EmployeeAcceptInviteService { async fn reject_invite(&self, cmd: AcceptInviteCommand) -> IdentityResult { todo!("also change input and output types"); } async fn accept_invite(&self, cmd: AcceptInviteCommand) -> IdentityResult { if !self .db_emp_id_exists_adapter .emp_id_exists(cmd.emp_id()) .await? { return Err(IdentityError::EmployeeNotFound); } let invite = match self .db_get_invite_adapter .get_invite(*cmd.invite_id()) .await? { None => return Err(IdentityError::InviteNotFound), Some(invite) => invite, }; Ok(InviteAcceptedEventBuilder::default() .emp_id(*cmd.emp_id()) .invite_id(*cmd.invite_id()) .store_id(invite) .build() .unwrap()) } } #[cfg(test)] mod tests { use crate::{tests::bdd::*, utils::uuid::tests::*}; use super::*; impl EmployeeAcceptInviteService { pub fn mock_service( times: Option, cmd: AcceptInviteCommand, ) -> EmployeeAcceptInviteServiceObj { let res = InviteAcceptedEvent::get_event(&cmd); let mut m = MockEmployeeAcceptInviteUseCase::default(); if let Some(times) = times { m.expect_accept_invite() .times(times) .returning(move |_| Ok(res.clone())); } else { m.expect_accept_invite().returning(move |_| Ok(res.clone())); } std::sync::Arc::new(m) } } #[actix_rt::test] async fn test_service() { let s = EmployeeAcceptInviteServiceBuilder::default() .db_emp_id_exists_adapter(mock_emp_id_exists_db_port(IS_CALLED_ONLY_ONCE, true)) .db_get_invite_adapter(mock_get_invite_db_port(IS_CALLED_ONLY_ONCE)) .build() .unwrap(); { let cmd = AcceptInviteCommandBuilder::default() .emp_id(UUID) .invite_id(UUID) .build() .unwrap(); let res = s.accept_invite(cmd.clone()).await.unwrap(); assert_eq!(*res.emp_id(), UUID); assert_eq!(*res.invite_id(), UUID); assert_eq!(*res.store_id(), UUID); } } #[actix_rt::test] async fn test_service_invite_no_exist() { let s = EmployeeAcceptInviteServiceBuilder::default() .db_emp_id_exists_adapter(mock_emp_id_exists_db_port(IS_CALLED_ONLY_ONCE, true)) .db_get_invite_adapter(mock_get_invite_db_port_returns_none(IS_CALLED_ONLY_ONCE)) .build() .unwrap(); { let cmd = AcceptInviteCommandBuilder::default() .emp_id(UUID) .invite_id(UUID) .build() .unwrap(); assert_eq!( s.accept_invite(cmd.clone()).await.err(), Some(IdentityError::InviteNotFound) ); } } #[actix_rt::test] async fn test_service_emp_no_exist() { let s = EmployeeAcceptInviteServiceBuilder::default() .db_emp_id_exists_adapter(mock_emp_id_exists_db_port(IS_CALLED_ONLY_ONCE, false)) .db_get_invite_adapter(mock_get_invite_db_port(IS_NEVER_CALLED)) .build() .unwrap(); { let cmd = AcceptInviteCommandBuilder::default() .emp_id(UUID) .invite_id(UUID) .build() .unwrap(); assert_eq!( s.accept_invite(cmd.clone()).await.err(), Some(IdentityError::EmployeeNotFound) ); } } }