#![cfg(test)]
#![allow(dead_code)]
use std::collections::HashMap;
use std::sync::Arc;
use async_trait::async_trait;
use modkit_security::SecurityContext;
use tenant_resolver_sdk::{
GetAncestorsOptions, GetAncestorsResponse, GetDescendantsOptions, GetDescendantsResponse,
GetTenantsOptions, IsAncestorOptions, TenantId, TenantInfo, TenantRef, TenantResolverClient,
TenantResolverError, TenantStatus,
};
use uuid::Uuid;
use crate::domain::service::Service;
pub struct MockTr {
pub all: Vec<Uuid>,
pub parent: HashMap<Uuid, Option<Uuid>>,
pub descendants_error: bool,
}
impl MockTr {
pub fn empty() -> Self {
Self {
all: Vec::new(),
parent: HashMap::new(),
descendants_error: false,
}
}
pub fn with_hierarchy(all: Vec<Uuid>, parent: HashMap<Uuid, Option<Uuid>>) -> Self {
Self {
all,
parent,
descendants_error: false,
}
}
pub fn failing_descendants() -> Self {
Self {
all: Vec::new(),
parent: HashMap::new(),
descendants_error: true,
}
}
fn is_ancestor_of(&self, anc: Uuid, desc: Uuid) -> bool {
let mut cur = Some(desc);
while let Some(c) = cur {
match self.parent.get(&c).copied().flatten() {
Some(p) if p == anc => return true,
Some(p) => cur = Some(p),
None => return false,
}
}
false
}
fn collect_descendants(&self, root: Uuid) -> Vec<Uuid> {
self.all
.iter()
.copied()
.filter(|&t| t != root && self.is_ancestor_of(root, t))
.collect()
}
}
#[async_trait]
impl TenantResolverClient for MockTr {
async fn get_tenant(
&self,
_ctx: &SecurityContext,
id: TenantId,
) -> Result<TenantInfo, TenantResolverError> {
Err(TenantResolverError::TenantNotFound { tenant_id: id })
}
async fn get_root_tenant(
&self,
_ctx: &SecurityContext,
) -> Result<TenantInfo, TenantResolverError> {
Err(TenantResolverError::TenantNotFound {
tenant_id: TenantId(Uuid::nil()),
})
}
async fn get_tenants(
&self,
_ctx: &SecurityContext,
_ids: &[TenantId],
_options: &GetTenantsOptions,
) -> Result<Vec<TenantInfo>, TenantResolverError> {
Ok(vec![])
}
async fn get_ancestors(
&self,
_ctx: &SecurityContext,
id: TenantId,
_options: &GetAncestorsOptions,
) -> Result<GetAncestorsResponse, TenantResolverError> {
Ok(GetAncestorsResponse {
tenant: TenantRef {
id,
status: TenantStatus::Active,
tenant_type: None,
parent_id: None,
self_managed: false,
},
ancestors: vec![],
})
}
async fn get_descendants(
&self,
_ctx: &SecurityContext,
id: TenantId,
_options: &GetDescendantsOptions,
) -> Result<GetDescendantsResponse, TenantResolverError> {
if self.descendants_error {
return Err(TenantResolverError::Internal(
"simulated TR failure".to_owned(),
));
}
let tenant_ref = TenantRef {
id,
status: TenantStatus::Active,
tenant_type: None,
parent_id: self.parent.get(&id.0).copied().flatten().map(TenantId),
self_managed: false,
};
let descendants = self
.collect_descendants(id.0)
.into_iter()
.map(|d| TenantRef {
id: TenantId(d),
status: TenantStatus::Active,
tenant_type: None,
parent_id: self.parent.get(&d).copied().flatten().map(TenantId),
self_managed: false,
})
.collect();
Ok(GetDescendantsResponse {
tenant: tenant_ref,
descendants,
})
}
async fn is_ancestor(
&self,
_ctx: &SecurityContext,
ancestor_id: TenantId,
descendant_id: TenantId,
_options: &IsAncestorOptions,
) -> Result<bool, TenantResolverError> {
Ok(self.is_ancestor_of(ancestor_id.0, descendant_id.0))
}
}
pub fn setup_svc() -> (Service, [Uuid; 5]) {
let r = Uuid::now_v7();
let t1 = Uuid::now_v7();
let t2 = Uuid::now_v7();
let t3 = Uuid::now_v7();
let t4 = Uuid::now_v7();
let parent: HashMap<Uuid, Option<Uuid>> = [
(r, None),
(t1, Some(r)),
(t2, Some(t1)),
(t3, Some(t2)),
(t4, Some(t2)),
]
.into_iter()
.collect();
let mock = MockTr::with_hierarchy(vec![r, t1, t2, t3, t4], parent);
(Service::new(Arc::new(mock)), [r, t1, t2, t3, t4])
}