shifty-backend/service_impl/src/test/booking.rs
2024-06-14 13:23:12 +02:00

733 lines
22 KiB
Rust

use crate::test::error_test::*;
use dao::booking::{BookingEntity, MockBookingDao};
use mockall::predicate::{always, eq};
use service::{
booking::Booking, clock::MockClockService, permission::Authentication,
sales_person::MockSalesPersonService, slot::MockSlotService, uuid_service::MockUuidService,
MockPermissionService, ValidationFailureItem,
};
use time::{Date, Month, PrimitiveDateTime, Time};
use uuid::{uuid, Uuid};
use super::error_test::NoneTypeExt;
use crate::booking::BookingServiceImpl;
use service::booking::BookingService;
pub fn default_id() -> Uuid {
uuid!("CEA260A0-112B-4970-936C-F7E529955BD0")
}
pub fn alternate_id() -> Uuid {
uuid!("CEA260A0-112B-4970-936C-F7E529955BD1")
}
pub fn default_version() -> Uuid {
uuid!("F79C462A-8D4E-42E1-8171-DB4DBD019E50")
}
pub fn alternate_version() -> Uuid {
uuid!("F79C462A-8D4E-42E1-8171-DB4DBD019E51")
}
pub fn default_sales_person_id() -> Uuid {
uuid!("04215DFE-13C4-413C-8C66-77AC741BB5F0")
}
pub fn default_slot_id() -> Uuid {
uuid!("7A7FF57A-782B-4C2E-A68B-4E2D81D79380")
}
pub fn default_booking() -> Booking {
Booking {
id: default_id(),
sales_person_id: default_sales_person_id(),
slot_id: default_slot_id(),
calendar_week: 3,
year: 2024,
created: Some(PrimitiveDateTime::new(
Date::from_calendar_date(2024, Month::January, 1).unwrap(),
Time::from_hms(0, 0, 0).unwrap(),
)),
deleted: None,
version: default_version(),
}
}
pub fn default_booking_entity() -> BookingEntity {
BookingEntity {
id: default_id(),
sales_person_id: default_sales_person_id(),
slot_id: default_slot_id(),
calendar_week: 3,
year: 2024,
created: PrimitiveDateTime::new(
Date::from_calendar_date(2024, Month::January, 1).unwrap(),
Time::from_hms(0, 0, 0).unwrap(),
),
deleted: None,
version: default_version(),
}
}
pub struct BookingServiceDependencies {
pub booking_dao: MockBookingDao,
pub permission_service: MockPermissionService,
pub clock_service: MockClockService,
pub uuid_service: MockUuidService,
pub sales_person_service: MockSalesPersonService,
pub slot_service: MockSlotService,
}
impl BookingServiceDependencies {
pub fn build_service(
self,
) -> BookingServiceImpl<
MockBookingDao,
MockPermissionService,
MockClockService,
MockUuidService,
MockSalesPersonService,
MockSlotService,
> {
BookingServiceImpl::new(
self.booking_dao.into(),
self.permission_service.into(),
self.clock_service.into(),
self.uuid_service.into(),
self.sales_person_service.into(),
self.slot_service.into(),
)
}
}
pub fn build_dependencies(permission: bool, role: &'static str) -> BookingServiceDependencies {
let mut booking_dao = MockBookingDao::new();
booking_dao
.expect_find_by_booking_data()
.returning(|_, _, _, _| Ok(None));
let mut permission_service = MockPermissionService::new();
permission_service
.expect_check_permission()
.with(eq(role), eq(().auth()))
.returning(move |_, _| {
if permission {
Ok(())
} else {
Err(service::ServiceError::Forbidden)
}
});
permission_service
.expect_check_permission()
.returning(move |_, _| Err(service::ServiceError::Forbidden));
let mut clock_service = MockClockService::new();
clock_service
.expect_time_now()
.returning(|| time::Time::from_hms(23, 42, 0).unwrap());
clock_service
.expect_date_now()
.returning(|| time::Date::from_calendar_date(2063, 4.try_into().unwrap(), 5).unwrap());
clock_service.expect_date_time_now().returning(|| {
time::PrimitiveDateTime::new(
time::Date::from_calendar_date(2063, 4.try_into().unwrap(), 5).unwrap(),
time::Time::from_hms(23, 42, 0).unwrap(),
)
});
let uuid_service = MockUuidService::new();
let mut sales_person_service = MockSalesPersonService::new();
sales_person_service
.expect_exists()
.returning(|_, _| Ok(true));
let mut slot_service = MockSlotService::new();
slot_service.expect_exists().returning(|_, _| Ok(true));
BookingServiceDependencies {
booking_dao,
permission_service,
clock_service,
uuid_service,
sales_person_service,
slot_service,
}
}
#[tokio::test]
async fn test_get_all() {
let mut deps = build_dependencies(true, "shiftplanner");
deps.booking_dao.expect_all().returning(|| {
Ok([
default_booking_entity(),
BookingEntity {
id: alternate_id(),
..default_booking_entity()
},
]
.into())
});
let service = deps.build_service();
let result = service.get_all(().auth()).await;
dbg!(&result);
assert!(result.is_ok());
let result = result.unwrap();
assert_eq!(result.len(), 2);
assert_eq!(result[0], default_booking());
assert_eq!(
result[1],
Booking {
id: alternate_id(),
..default_booking()
}
);
}
#[tokio::test]
async fn test_get_all_no_permission() {
let deps = build_dependencies(false, "shiftplanner");
let service = deps.build_service();
let result = service.get_all(().auth()).await;
test_forbidden(&result);
}
#[tokio::test]
async fn test_get() {
let mut deps = build_dependencies(true, "shiftplanner");
deps.booking_dao
.expect_find_by_id()
.with(eq(default_id()))
.returning(|_| Ok(Some(default_booking_entity())));
let service = deps.build_service();
let result = service.get(default_id(), ().auth()).await;
assert!(result.is_ok());
assert_eq!(result.unwrap(), default_booking());
}
#[tokio::test]
async fn test_get_not_found() {
let mut deps = build_dependencies(true, "shiftplanner");
deps.booking_dao
.expect_find_by_id()
.with(eq(default_id()))
.returning(|_| Ok(None));
let service = deps.build_service();
let result = service.get(default_id(), ().auth()).await;
test_not_found(&result, &default_id());
}
#[tokio::test]
async fn test_get_no_permission() {
let deps = build_dependencies(false, "shiftplanner");
let service = deps.build_service();
let result = service.get(default_id(), ().auth()).await;
test_forbidden(&result);
}
#[tokio::test]
async fn test_get_for_week() {
let mut deps = build_dependencies(true, "sales");
deps.booking_dao
.expect_find_by_week()
.with(eq(3), eq(2024))
.returning(|_, _| Ok([default_booking_entity()].into()));
let service = deps.build_service();
let result = service.get_for_week(3, 2024, ().auth()).await;
assert_eq!(result.unwrap(), [default_booking()].into());
}
#[tokio::test]
async fn test_get_for_week_shiftplanner_role() {
let mut deps = build_dependencies(true, "shiftplanner");
deps.booking_dao
.expect_find_by_week()
.with(eq(3), eq(2024))
.returning(|_, _| Ok([default_booking_entity()].into()));
let service = deps.build_service();
let result = service.get_for_week(3, 2024, ().auth()).await;
assert_eq!(result.unwrap(), [default_booking()].into());
}
#[tokio::test]
async fn test_get_for_week_no_permission() {
let deps = build_dependencies(false, "shiftplanner");
let service = deps.build_service();
let result = service.get_for_week(3, 2024, ().auth()).await;
test_forbidden(&result);
}
#[tokio::test]
async fn test_create() {
let mut deps = build_dependencies(true, "shiftplanner");
deps.booking_dao
.expect_create()
.with(
eq(BookingEntity {
created: generate_default_datetime(),
..default_booking_entity()
}),
eq("booking-service"),
)
.returning(|_, _| Ok(()));
deps.uuid_service
.expect_new_uuid()
.with(eq("booking-id"))
.returning(|_| default_id());
deps.uuid_service
.expect_new_uuid()
.with(eq("booking-version"))
.returning(|_| default_version());
let service = deps.build_service();
let result = service
.create(
&Booking {
id: Uuid::nil(),
version: Uuid::nil(),
created: None,
..default_booking()
},
().auth(),
)
.await;
assert!(result.is_ok());
assert_eq!(
result.unwrap(),
Booking {
created: Some(generate_default_datetime()),
..default_booking()
}
);
}
#[tokio::test]
async fn test_create_sales_user() {
let mut deps = build_dependencies(true, "sales");
deps.booking_dao
.expect_create()
.with(
eq(BookingEntity {
created: generate_default_datetime(),
..default_booking_entity()
}),
eq("booking-service"),
)
.returning(|_, _| Ok(()));
deps.uuid_service
.expect_new_uuid()
.with(eq("booking-id"))
.returning(|_| default_id());
deps.uuid_service
.expect_new_uuid()
.with(eq("booking-version"))
.returning(|_| default_version());
deps.sales_person_service
.expect_get_assigned_user()
.with(eq(default_sales_person_id()), always())
.returning(|_, _| Ok(Some("TESTUSER".into())));
deps.permission_service
.expect_check_user()
.with(eq("TESTUSER"), always())
.returning(|_, _| Ok(()));
let service = deps.build_service();
let result = service
.create(
&Booking {
id: Uuid::nil(),
version: Uuid::nil(),
created: None,
..default_booking()
},
().auth(),
)
.await;
assert!(result.is_ok());
assert_eq!(
result.unwrap(),
Booking {
created: Some(generate_default_datetime()),
..default_booking()
}
);
}
#[tokio::test]
async fn test_create_sales_user_not_exist() {
let mut deps = build_dependencies(true, "sales");
deps.booking_dao
.expect_create()
.with(
eq(BookingEntity {
created: generate_default_datetime(),
..default_booking_entity()
}),
eq("booking-service"),
)
.returning(|_, _| Ok(()));
deps.uuid_service
.expect_new_uuid()
.with(eq("booking-id"))
.returning(|_| default_id());
deps.uuid_service
.expect_new_uuid()
.with(eq("booking-version"))
.returning(|_| default_version());
deps.sales_person_service
.expect_get_assigned_user()
.with(eq(default_sales_person_id()), always())
.returning(|_, _| Ok(Some("TESTUSER".into())));
deps.permission_service
.expect_check_user()
.with(eq("TESTUSER"), always())
.returning(|_, _| Err(service::ServiceError::Forbidden));
let service = deps.build_service();
let result = service
.create(
&Booking {
id: Uuid::nil(),
version: Uuid::nil(),
created: None,
..default_booking()
},
().auth(),
)
.await;
test_forbidden(&result);
}
#[tokio::test]
async fn test_create_sales_user_no_permission() {
let mut deps = build_dependencies(true, "sales");
deps.booking_dao
.expect_create()
.with(
eq(BookingEntity {
created: generate_default_datetime(),
..default_booking_entity()
}),
eq("booking-service"),
)
.returning(|_, _| Ok(()));
deps.uuid_service
.expect_new_uuid()
.with(eq("booking-id"))
.returning(|_| default_id());
deps.uuid_service
.expect_new_uuid()
.with(eq("booking-version"))
.returning(|_| default_version());
deps.sales_person_service
.expect_get_assigned_user()
.with(eq(default_sales_person_id()), always())
.returning(|_, _| Ok(None));
let service = deps.build_service();
let result = service
.create(
&Booking {
id: Uuid::nil(),
version: Uuid::nil(),
created: None,
..default_booking()
},
().auth(),
)
.await;
test_forbidden(&result);
}
#[tokio::test]
async fn test_create_no_permission() {
let deps = build_dependencies(false, "shiftplanner");
let service = deps.build_service();
let result = service
.create(
&Booking {
id: Uuid::nil(),
version: Uuid::nil(),
..default_booking()
},
().auth(),
)
.await;
test_forbidden(&result);
}
#[tokio::test]
async fn test_create_with_id() {
let deps = build_dependencies(true, "shiftplanner");
let service = deps.build_service();
let result = service
.create(
&Booking {
version: Uuid::nil(),
..default_booking()
},
().auth(),
)
.await;
test_zero_id_error(&result);
}
#[tokio::test]
async fn test_create_with_version() {
let deps = build_dependencies(true, "shiftplanner");
let service = deps.build_service();
let result = service
.create(
&Booking {
id: Uuid::nil(),
..default_booking()
},
().auth(),
)
.await;
test_zero_version_error(&result);
}
#[tokio::test]
async fn test_create_with_created_fail() {
let deps = build_dependencies(true, "shiftplanner");
let service = deps.build_service();
let result = service
.create(
&Booking {
id: Uuid::nil(),
version: Uuid::nil(),
..default_booking()
},
().auth(),
)
.await;
test_validation_error(
&result,
&ValidationFailureItem::InvalidValue("created".into()),
1,
);
}
#[tokio::test]
async fn test_create_sales_person_does_not_exist() {
let mut deps = build_dependencies(true, "shiftplanner");
deps.sales_person_service.checkpoint();
deps.sales_person_service
.expect_exists()
.with(eq(default_sales_person_id()), eq(Authentication::Full))
.returning(|_, _| Ok(false));
let service = deps.build_service();
let result = service
.create(
&Booking {
id: Uuid::nil(),
version: Uuid::nil(),
created: None,
..default_booking()
},
().auth(),
)
.await;
dbg!(&result);
test_validation_error(
&result,
&ValidationFailureItem::IdDoesNotExist("sales_person_id".into(), default_sales_person_id()),
1,
);
}
#[tokio::test]
async fn test_create_booking_data_already_exists() {
let mut deps = build_dependencies(true, "shiftplanner");
deps.booking_dao.checkpoint();
deps.booking_dao
.expect_find_by_booking_data()
.with(
eq(default_sales_person_id()),
eq(default_slot_id()),
eq(3),
eq(2024),
)
.returning(|_, _, _, _| Ok(Some(default_booking_entity())));
let service = deps.build_service();
let result = service
.create(
&Booking {
id: Uuid::nil(),
version: Uuid::nil(),
created: None,
..default_booking()
},
().auth(),
)
.await;
test_validation_error(&result, &ValidationFailureItem::Duplicate, 1);
}
#[tokio::test]
async fn test_create_slot_does_not_exist() {
let mut deps = build_dependencies(true, "shiftplanner");
deps.slot_service.checkpoint();
deps.slot_service
.expect_exists()
.with(eq(default_slot_id()), eq(Authentication::Full))
.returning(|_, _| Ok(false));
let service = deps.build_service();
let result = service
.create(
&Booking {
id: Uuid::nil(),
version: Uuid::nil(),
created: None,
..default_booking()
},
().auth(),
)
.await;
test_validation_error(
&result,
&ValidationFailureItem::IdDoesNotExist("slot_id".into(), default_slot_id()),
1,
);
}
#[tokio::test]
async fn test_delete_no_permission() {
let mut deps = build_dependencies(false, "shiftplanner");
deps.booking_dao
.expect_find_by_id()
.with(eq(default_id()))
.returning(|_| Ok(Some(default_booking_entity())));
let service = deps.build_service();
let result = service.delete(default_id(), ().auth()).await;
test_forbidden(&result);
}
#[tokio::test]
async fn test_delete_not_found() {
let mut deps = build_dependencies(true, "shiftplanner");
deps.booking_dao
.expect_find_by_id()
.with(eq(default_id()))
.returning(|_| Ok(None));
let service = deps.build_service();
let result = service.delete(default_id(), ().auth()).await;
test_not_found(&result, &default_id());
}
#[tokio::test]
async fn test_delete() {
let mut deps = build_dependencies(true, "shiftplanner");
deps.booking_dao
.expect_find_by_id()
.with(eq(default_id()))
.returning(|_| Ok(Some(default_booking_entity())));
deps.booking_dao
.expect_update()
.with(
eq(BookingEntity {
deleted: Some(generate_default_datetime()),
version: alternate_version(),
..default_booking_entity()
}),
eq("booking-service"),
)
.returning(|_, _| Ok(()));
deps.uuid_service
.expect_new_uuid()
.with(eq("booking-version"))
.returning(|_| alternate_version());
let service = deps.build_service();
let result = service.delete(default_id(), ().auth()).await;
assert!(result.is_ok());
assert_eq!(result.unwrap(), ());
}
#[tokio::test]
async fn test_delete_sales_user() {
let mut deps = build_dependencies(true, "sales");
deps.booking_dao
.expect_find_by_id()
.with(eq(default_id()))
.returning(|_| Ok(Some(default_booking_entity())));
deps.booking_dao
.expect_update()
.with(
eq(BookingEntity {
deleted: Some(generate_default_datetime()),
version: alternate_version(),
..default_booking_entity()
}),
eq("booking-service"),
)
.returning(|_, _| Ok(()));
deps.uuid_service
.expect_new_uuid()
.with(eq("booking-version"))
.returning(|_| alternate_version());
deps.sales_person_service
.expect_get_assigned_user()
.with(eq(default_sales_person_id()), always())
.returning(|_, _| Ok(Some("TESTUSER".into())));
deps.permission_service
.expect_check_user()
.with(eq("TESTUSER"), always())
.returning(|_, _| Ok(()));
let service = deps.build_service();
let result = service.delete(default_id(), ().auth()).await;
assert!(result.is_ok());
assert_eq!(result.unwrap(), ());
}
#[tokio::test]
async fn test_delete_sales_user_not_exists() {
let mut deps = build_dependencies(true, "sales");
deps.booking_dao
.expect_find_by_id()
.with(eq(default_id()))
.returning(|_| Ok(Some(default_booking_entity())));
deps.booking_dao
.expect_update()
.with(
eq(BookingEntity {
deleted: Some(generate_default_datetime()),
version: alternate_version(),
..default_booking_entity()
}),
eq("booking-service"),
)
.returning(|_, _| Ok(()));
deps.uuid_service
.expect_new_uuid()
.with(eq("booking-version"))
.returning(|_| alternate_version());
deps.sales_person_service
.expect_get_assigned_user()
.with(eq(default_sales_person_id()), always())
.returning(|_, _| Ok(None));
let service = deps.build_service();
let result = service.delete(default_id(), ().auth()).await;
test_forbidden(&result);
}
#[tokio::test]
async fn test_delete_sales_user_not_allowed() {
let mut deps = build_dependencies(true, "sales");
deps.booking_dao
.expect_find_by_id()
.with(eq(default_id()))
.returning(|_| Ok(Some(default_booking_entity())));
deps.booking_dao
.expect_update()
.with(
eq(BookingEntity {
deleted: Some(generate_default_datetime()),
version: alternate_version(),
..default_booking_entity()
}),
eq("booking-service"),
)
.returning(|_, _| Ok(()));
deps.uuid_service
.expect_new_uuid()
.with(eq("booking-version"))
.returning(|_| alternate_version());
deps.sales_person_service
.expect_get_assigned_user()
.with(eq(default_sales_person_id()), always())
.returning(|_, _| Ok(Some("TESTUSER".into())));
deps.permission_service
.expect_check_user()
.with(eq("TESTUSER"), always())
.returning(|_, _| Err(service::ServiceError::Forbidden));
let service = deps.build_service();
let result = service.delete(default_id(), ().auth()).await;
test_forbidden(&result);
}