use crate::resource::RequestContext;
#[cfg(test)]
use crate::resource::TenantContext;
pub trait TenantValidator {
fn validate_tenant_context(
&self,
expected_tenant_id: &str,
context: &RequestContext,
) -> Result<(), String> {
match context.tenant_id() {
Some(actual_tenant_id) if actual_tenant_id == expected_tenant_id => Ok(()),
Some(actual_tenant_id) => Err(format!(
"Tenant mismatch: context has '{}', operation requested '{}'",
actual_tenant_id, expected_tenant_id
)),
None => Err(format!(
"Multi-tenant operation requested '{}' but context has no tenant",
expected_tenant_id
)),
}
}
fn validate_single_tenant_context(&self, context: &RequestContext) -> Result<(), String> {
match context.tenant_id() {
None => Ok(()),
Some(tenant_id) => Err(format!(
"Single-tenant operation but context has tenant '{}'",
tenant_id
)),
}
}
fn require_tenant_context(&self, context: &RequestContext) -> Result<(), String> {
match context.tenant_context {
Some(_) => Ok(()),
None => Err("Multi-tenant operation requires tenant context".to_string()),
}
}
}
impl<T> TenantValidator for T {}
#[cfg(test)]
mod tests {
use super::*;
struct MockValidator;
#[test]
fn test_tenant_validator_success() {
let validator = MockValidator;
let tenant_context = TenantContext {
tenant_id: "test-tenant".to_string(),
client_id: "client".to_string(),
permissions: Default::default(),
isolation_level: Default::default(),
};
let context = RequestContext::with_tenant_generated_id(tenant_context);
assert!(
validator
.validate_tenant_context("test-tenant", &context)
.is_ok()
);
assert!(validator.require_tenant_context(&context).is_ok());
}
#[test]
fn test_tenant_validator_failure() {
let validator = MockValidator;
let tenant_context = TenantContext {
tenant_id: "test-tenant".to_string(),
client_id: "client".to_string(),
permissions: Default::default(),
isolation_level: Default::default(),
};
let context = RequestContext::with_tenant_generated_id(tenant_context);
let result = validator.validate_tenant_context("different-tenant", &context);
assert!(result.is_err());
assert!(result.unwrap_err().contains("Tenant mismatch"));
}
#[test]
fn test_single_tenant_validation() {
let validator = MockValidator;
let context = RequestContext::with_generated_id();
assert!(validator.validate_single_tenant_context(&context).is_ok());
let tenant_context = TenantContext {
tenant_id: "test-tenant".to_string(),
client_id: "client".to_string(),
permissions: Default::default(),
isolation_level: Default::default(),
};
let multi_context = RequestContext::with_tenant_generated_id(tenant_context);
assert!(
validator
.validate_single_tenant_context(&multi_context)
.is_err()
);
}
#[test]
fn test_require_tenant_context() {
let validator = MockValidator;
let single_context = RequestContext::with_generated_id();
assert!(validator.require_tenant_context(&single_context).is_err());
let tenant_context = TenantContext {
tenant_id: "test-tenant".to_string(),
client_id: "client".to_string(),
permissions: Default::default(),
isolation_level: Default::default(),
};
let multi_context = RequestContext::with_tenant_generated_id(tenant_context);
assert!(validator.require_tenant_context(&multi_context).is_ok());
}
}