use chrono::{TimeZone, Utc};
use skilj_core::access_control::{self, AccessLevel, Role, RoleAccessMapping, RoleStatus};
use skilj_core::bootstrap::{self, BootstrapSecret, ContextCreator};
use skilj_core::error::SkiljRejection;
use skilj_core::event_store::{BoundedContext, BoundedContextStatus};
fn timestamp(secs: i64) -> chrono::DateTime<Utc> {
Utc.timestamp_opt(secs, 0).unwrap()
}
fn superadmin(status: RoleStatus) -> Role {
Role {
id: "role-1".into(),
external_subject: "admin@example.com".into(),
name: "Admin".into(),
superadmin: true,
status,
created_at: timestamp(0),
revoked_at: None,
}
}
fn non_superadmin() -> Role {
Role {
superadmin: false,
id: "role-2".into(),
external_subject: "someone@example.com".into(),
..superadmin(RoleStatus::Active)
}
}
fn bounded_context(name: &str, status: BoundedContextStatus) -> BoundedContext {
BoundedContext {
name: name.into(),
status,
created_at: timestamp(0),
created_by: ContextCreator::SuperadminCreator {
role: superadmin(RoleStatus::Active),
},
template: None,
}
}
fn admin_bounded_context() -> BoundedContext {
bounded_context(
bootstrap::ADMIN_BOUNDED_CONTEXT_NAME,
BoundedContextStatus::Active,
)
}
fn access_mapping(
status: RoleStatus,
level: AccessLevel,
bounded_context: BoundedContext,
) -> RoleAccessMapping {
RoleAccessMapping {
role: superadmin(RoleStatus::Active),
bounded_context,
level,
can_read_sensitive: false,
scope: None,
capabilities: Default::default(),
delegable: Default::default(),
status,
created_at: timestamp(0),
revoked_at: None,
}
}
fn bootstrap_secret() -> BootstrapSecret {
BootstrapSecret {
secret: "high-entropy-bootstrap-secret".into(),
}
}
#[test]
fn bootstrap_secret_carries_its_declared_field() {
let b = bootstrap_secret();
assert_eq!(b.secret, "high-entropy-bootstrap-secret");
}
#[test]
fn generate_bootstrap_secret_produces_a_secret_when_no_active_superadmin_exists() {
let secret = bootstrap::generate_bootstrap_secret(&[]);
assert!(secret.is_some());
let secret = bootstrap::generate_bootstrap_secret(&[non_superadmin()]);
assert!(secret.is_some());
let secret = bootstrap::generate_bootstrap_secret(&[superadmin(RoleStatus::Revoked)]);
assert!(secret.is_some());
}
#[test]
fn generate_bootstrap_secret_is_none_once_an_active_superadmin_exists() {
let secret = bootstrap::generate_bootstrap_secret(&[superadmin(RoleStatus::Active)]);
assert!(secret.is_none());
}
#[test]
fn stamp_admin_bounded_context_produces_the_row_on_a_genuine_first_startup() {
let stamped = bootstrap::stamp_admin_bounded_context(None, timestamp(1000)).unwrap();
assert_eq!(stamped.name, bootstrap::ADMIN_BOUNDED_CONTEXT_NAME);
assert_eq!(stamped.status, BoundedContextStatus::Active);
assert_eq!(stamped.created_at, timestamp(1000));
assert_eq!(stamped.created_by, ContextCreator::SystemCreator);
}
#[test]
fn stamp_admin_bounded_context_is_none_once_the_row_already_exists() {
let already_stamped = admin_bounded_context();
let restamp_attempt =
bootstrap::stamp_admin_bounded_context(Some(&already_stamped), timestamp(9999));
assert!(restamp_attempt.is_none());
}
#[test]
fn superadmin_creator_carries_its_variant_specific_field() {
let role = superadmin(RoleStatus::Active);
let creator = ContextCreator::SuperadminCreator { role: role.clone() };
match creator {
ContextCreator::SuperadminCreator { role: r } => assert_eq!(r, role),
other => panic!("expected SuperadminCreator, got {other:?}"),
}
}
#[test]
fn system_creator_is_reachable_through_the_context_creator_type_guard() {
let creator = ContextCreator::SystemCreator;
match creator {
ContextCreator::SystemCreator => {}
other => panic!("expected SystemCreator, got {other:?}"),
}
}
#[test]
fn add_bounded_context_succeeds_and_stamps_the_full_entity_shape() {
let caller = superadmin(RoleStatus::Active);
let bc =
bootstrap::add_bounded_context(&caller, "billing".into(), &[], timestamp(1000)).unwrap();
assert_eq!(bc.name, "billing");
assert_eq!(bc.status, BoundedContextStatus::Active);
assert_eq!(bc.created_at, timestamp(1000));
match bc.created_by {
ContextCreator::SuperadminCreator { role } => assert_eq!(role, caller),
other => panic!("expected SuperadminCreator, got {other:?}"),
}
}
#[test]
fn add_bounded_context_rejects_a_revoked_caller() {
let caller = superadmin(RoleStatus::Revoked);
let err =
bootstrap::add_bounded_context(&caller, "billing".into(), &[], timestamp(0)).unwrap_err();
assert_eq!(err.code(), access_control::Error::RoleNotActive.code());
}
#[test]
fn add_bounded_context_rejects_a_non_superadmin_caller() {
let caller = non_superadmin();
let err =
bootstrap::add_bounded_context(&caller, "billing".into(), &[], timestamp(0)).unwrap_err();
assert_eq!(err.code(), access_control::Error::NotSuperadmin.code());
}
#[test]
fn add_bounded_context_rejects_a_name_already_taken() {
let caller = superadmin(RoleStatus::Active);
let existing = vec![bounded_context("billing", BoundedContextStatus::Active)];
let err = bootstrap::add_bounded_context(&caller, "billing".into(), &existing, timestamp(0))
.unwrap_err();
assert_eq!(err.code(), bootstrap::Error::BoundedContextNameTaken.code());
}
#[test]
fn add_bounded_context_rejects_the_admin_name_even_though_admin_was_never_added_by_this_rule() {
let caller = superadmin(RoleStatus::Active);
let existing = vec![admin_bounded_context()];
let err = bootstrap::add_bounded_context(
&caller,
bootstrap::ADMIN_BOUNDED_CONTEXT_NAME.into(),
&existing,
timestamp(0),
)
.unwrap_err();
assert_eq!(err.code(), bootstrap::Error::BoundedContextNameTaken.code());
}
#[test]
fn add_bounded_context_rejects_a_name_with_an_uppercase_character() {
let caller = superadmin(RoleStatus::Active);
let err =
bootstrap::add_bounded_context(&caller, "Billing".into(), &[], timestamp(0)).unwrap_err();
assert_eq!(
err.code(),
bootstrap::Error::InvalidBoundedContextName.code()
);
}
#[test]
fn add_bounded_context_rejects_a_name_starting_with_a_digit() {
let caller = superadmin(RoleStatus::Active);
let err =
bootstrap::add_bounded_context(&caller, "1billing".into(), &[], timestamp(0)).unwrap_err();
assert_eq!(
err.code(),
bootstrap::Error::InvalidBoundedContextName.code()
);
}
#[test]
fn add_bounded_context_rejects_a_name_over_forty_characters() {
let caller = superadmin(RoleStatus::Active);
let name = "a".repeat(41);
let err = bootstrap::add_bounded_context(&caller, name, &[], timestamp(0)).unwrap_err();
assert_eq!(
err.code(),
bootstrap::Error::InvalidBoundedContextName.code()
);
}
#[test]
fn add_bounded_context_accepts_a_name_at_exactly_the_length_cap() {
let caller = superadmin(RoleStatus::Active);
let name = format!("a{}", "1".repeat(39));
assert_eq!(name.len(), 40);
let bc = bootstrap::add_bounded_context(&caller, name.clone(), &[], timestamp(0)).unwrap();
assert_eq!(bc.name, name);
}
#[test]
fn list_bounded_contexts_succeeds_and_returns_every_context_unrestricted() {
let caller = superadmin(RoleStatus::Active);
let contexts = vec![
bounded_context("billing", BoundedContextStatus::Active),
bounded_context("legacy", BoundedContextStatus::Archived), ];
let listed = bootstrap::list_bounded_contexts(&caller, &contexts).unwrap();
assert_eq!(listed, contexts);
}
#[test]
fn list_bounded_contexts_rejects_a_revoked_caller() {
let caller = superadmin(RoleStatus::Revoked);
let err = bootstrap::list_bounded_contexts(&caller, &[]).unwrap_err();
assert_eq!(err.code(), access_control::Error::RoleNotActive.code());
}
#[test]
fn list_bounded_contexts_rejects_a_non_superadmin_caller() {
let caller = non_superadmin();
let err = bootstrap::list_bounded_contexts(&caller, &[]).unwrap_err();
assert_eq!(err.code(), access_control::Error::NotSuperadmin.code());
}
#[test]
fn archive_bounded_context_succeeds_and_moves_status_to_archived() {
let bc = bounded_context("billing", BoundedContextStatus::Active);
let mapping = access_mapping(RoleStatus::Active, AccessLevel::Admin, bc.clone());
let archived = bootstrap::archive_bounded_context(&mapping, &bc).unwrap();
assert_eq!(archived.status, BoundedContextStatus::Archived);
assert_eq!(archived.name, bc.name);
}
#[test]
fn archive_bounded_context_rejects_a_revoked_mapping() {
let bc = bounded_context("billing", BoundedContextStatus::Active);
let mapping = access_mapping(RoleStatus::Revoked, AccessLevel::Admin, bc.clone());
let err = bootstrap::archive_bounded_context(&mapping, &bc).unwrap_err();
assert_eq!(err.code(), access_control::Error::GrantNotActive.code());
}
#[test]
fn archive_bounded_context_rejects_a_write_level_mapping() {
let bc = bounded_context("billing", BoundedContextStatus::Active);
let mapping = access_mapping(RoleStatus::Active, AccessLevel::Write, bc.clone());
let err = bootstrap::archive_bounded_context(&mapping, &bc).unwrap_err();
assert_eq!(
err.code(),
access_control::Error::InsufficientAccessLevel.code()
);
}
#[test]
fn archive_bounded_context_rejects_a_mapping_scoped_to_a_different_context() {
let bc = bounded_context("billing", BoundedContextStatus::Active);
let other = bounded_context("orders", BoundedContextStatus::Active);
let mapping = access_mapping(RoleStatus::Active, AccessLevel::Admin, other);
let err = bootstrap::archive_bounded_context(&mapping, &bc).unwrap_err();
assert_eq!(
err.code(),
access_control::Error::GrantBoundedContextMismatch.code()
);
}
#[test]
fn archive_bounded_context_rejects_an_already_archived_context() {
let bc = bounded_context("billing", BoundedContextStatus::Archived);
let mapping = access_mapping(RoleStatus::Active, AccessLevel::Admin, bc.clone());
let err = bootstrap::archive_bounded_context(&mapping, &bc).unwrap_err();
assert_eq!(
err.code(),
skilj_core::event_store::Error::BoundedContextArchived.code()
);
}
#[test]
fn archive_bounded_context_rejects_the_admin_context() {
let bc = admin_bounded_context();
let mapping = access_mapping(RoleStatus::Active, AccessLevel::Admin, bc.clone());
let err = bootstrap::archive_bounded_context(&mapping, &bc).unwrap_err();
assert_eq!(
err.code(),
bootstrap::Error::CannotArchiveAdminContext.code()
);
}
#[test]
fn archive_bounded_context_only_ever_produces_the_archived_status() {
let bc = bounded_context("billing", BoundedContextStatus::Active);
let mapping = access_mapping(RoleStatus::Active, AccessLevel::Admin, bc.clone());
let archived = bootstrap::archive_bounded_context(&mapping, &bc).unwrap();
assert_eq!(archived.status, BoundedContextStatus::Archived);
}
#[test]
fn delete_bounded_context_succeeds_for_an_archived_non_admin_context() {
let caller = superadmin(RoleStatus::Active);
let bc = bounded_context("billing", BoundedContextStatus::Archived);
bootstrap::delete_bounded_context(&caller, &bc).unwrap();
}
#[test]
fn delete_bounded_context_rejects_a_revoked_caller() {
let caller = superadmin(RoleStatus::Revoked);
let bc = bounded_context("billing", BoundedContextStatus::Archived);
let err = bootstrap::delete_bounded_context(&caller, &bc).unwrap_err();
assert_eq!(err.code(), access_control::Error::RoleNotActive.code());
}
#[test]
fn delete_bounded_context_rejects_a_non_superadmin_caller() {
let caller = non_superadmin();
let bc = bounded_context("billing", BoundedContextStatus::Archived);
let err = bootstrap::delete_bounded_context(&caller, &bc).unwrap_err();
assert_eq!(err.code(), access_control::Error::NotSuperadmin.code());
}
#[test]
fn delete_bounded_context_rejects_a_still_active_context() {
let caller = superadmin(RoleStatus::Active);
let bc = bounded_context("billing", BoundedContextStatus::Active);
let err = bootstrap::delete_bounded_context(&caller, &bc).unwrap_err();
assert_eq!(
err.code(),
bootstrap::Error::BoundedContextNotArchived.code()
);
}
#[test]
fn delete_bounded_context_rejects_the_admin_context_even_if_archived() {
let caller = superadmin(RoleStatus::Active);
let bc = bounded_context(
bootstrap::ADMIN_BOUNDED_CONTEXT_NAME,
BoundedContextStatus::Archived,
);
let err = bootstrap::delete_bounded_context(&caller, &bc).unwrap_err();
assert_eq!(
err.code(),
bootstrap::Error::CannotDeleteAdminContext.code()
);
}
#[test]
fn create_superadmin_succeeds_and_stamps_the_full_entity_shape() {
let secret = bootstrap_secret();
let role = bootstrap::create_superadmin(
&secret,
"high-entropy-bootstrap-secret",
"Root".into(),
"root@example.com".into(),
&[],
"role-1".into(),
timestamp(1000),
)
.unwrap();
assert_eq!(role.id, "role-1");
assert_eq!(role.external_subject, "root@example.com");
assert_eq!(role.name, "Root");
assert!(role.superadmin);
assert_eq!(role.status, RoleStatus::Active);
assert_eq!(role.created_at, timestamp(1000));
}
#[test]
fn create_superadmin_rejects_when_an_active_superadmin_already_exists() {
let secret = bootstrap_secret();
let existing = vec![superadmin(RoleStatus::Active)];
let err = bootstrap::create_superadmin(
&secret,
"high-entropy-bootstrap-secret",
"Root".into(),
"root@example.com".into(),
&existing,
"role-2".into(),
timestamp(0),
)
.unwrap_err();
assert_eq!(err.code(), bootstrap::Error::SuperadminAlreadyExists.code());
}
#[test]
fn create_superadmin_succeeds_when_the_only_prior_superadmin_is_revoked() {
let secret = bootstrap_secret();
let existing = vec![superadmin(RoleStatus::Revoked)];
let role = bootstrap::create_superadmin(
&secret,
"high-entropy-bootstrap-secret",
"Root2".into(),
"root2@example.com".into(),
&existing,
"role-2".into(),
timestamp(0),
)
.unwrap();
assert!(role.superadmin);
}
#[test]
fn create_superadmin_rejects_a_wrong_secret() {
let secret = bootstrap_secret();
let err = bootstrap::create_superadmin(
&secret,
"wrong-secret",
"Root".into(),
"root@example.com".into(),
&[],
"role-1".into(),
timestamp(0),
)
.unwrap_err();
assert_eq!(err.code(), bootstrap::Error::BootstrapSecretMismatch.code());
}
#[test]
fn create_superadmin_rejects_an_external_subject_already_claimed() {
let secret = bootstrap_secret();
let existing = vec![non_superadmin()];
let err = bootstrap::create_superadmin(
&secret,
"high-entropy-bootstrap-secret",
"Root".into(),
"someone@example.com".into(),
&existing,
"role-1".into(),
timestamp(0),
)
.unwrap_err();
assert_eq!(
err.code(),
bootstrap::Error::ExternalSubjectAlreadyClaimed.code()
);
}