#![cfg(feature = "strict-cap-binding")]
use tensor_wasm_core::types::TenantId;
use tensor_wasm_tenant::{
registry::RegistryError, TenantCapability, TenantContext, TenantRegistry,
};
fn make_ctx(id: u64) -> TenantContext {
TenantContext::builder(TenantId(id))
.with_memory_quota_bytes(4096)
.build()
}
#[test]
fn admin_cap_from_foreign_registry_is_rejected_via_strict_api() {
let (reg_a, cap_a) = TenantRegistry::new();
let (reg_b, cap_b) = TenantRegistry::new();
reg_a.register(make_ctx(100)).unwrap();
reg_b.register(make_ctx(200)).unwrap();
assert_eq!(
reg_b.len_strict(&cap_a).unwrap_err(),
RegistryError::CapabilityFromForeignRegistry,
);
assert_eq!(
reg_b.get_strict(TenantId(200), &cap_a).unwrap_err(),
RegistryError::CapabilityFromForeignRegistry,
);
assert_eq!(
reg_b.tenants_strict(&cap_a).unwrap_err(),
RegistryError::CapabilityFromForeignRegistry,
);
assert_eq!(
reg_b.unregister_strict(TenantId(200), &cap_a).unwrap_err(),
RegistryError::CapabilityFromForeignRegistry,
);
assert_eq!(reg_a.len_strict(&cap_a).unwrap(), 1);
assert!(reg_a.get_strict(TenantId(100), &cap_a).unwrap().is_some());
let snap = reg_a.tenants_strict(&cap_a).unwrap();
assert_eq!(snap.len(), 1);
assert_eq!(snap[0].id(), TenantId(100));
assert_eq!(
reg_a.len_strict(&cap_b).unwrap_err(),
RegistryError::CapabilityFromForeignRegistry,
);
}
#[test]
fn admin_cap_legacy_apis_silently_no_op_on_foreign_cap() {
let (reg_a, cap_a) = TenantRegistry::new();
let (reg_b, cap_b) = TenantRegistry::new();
reg_a.register(make_ctx(11)).unwrap();
reg_b.register(make_ctx(22)).unwrap();
assert!(reg_a.get(TenantId(11), &cap_b).is_none());
assert_eq!(reg_a.len(&cap_b), 0);
assert!(reg_a.tenants(&cap_b).is_empty());
assert!(reg_a.unregister(TenantId(11), &cap_b).is_none());
assert_eq!(reg_a.len(&cap_a), 1);
assert!(reg_a.get(TenantId(11), &cap_a).is_some());
}
#[test]
fn tenant_cap_from_foreign_registry_cannot_drive_quota() {
let (reg_a, _cap_a) = TenantRegistry::new();
let (reg_b, _cap_b) = TenantRegistry::new();
let (ctx_a, tcap_a) = reg_a.register_with_capability(make_ctx(7)).unwrap();
let (ctx_b, tcap_b) = reg_b.register_with_capability(make_ctx(7)).unwrap();
assert_eq!(ctx_a.bytes_in_use(), 0);
assert_eq!(ctx_b.bytes_in_use(), 0);
ctx_a.consume_bytes_with_capability(&tcap_a, 128).unwrap();
ctx_b.consume_bytes_with_capability(&tcap_b, 256).unwrap();
let err = ctx_b
.consume_bytes_with_capability(&tcap_a, 64)
.expect_err("foreign-registry cap must be refused under strict binding");
match err {
tensor_wasm_core::error::TensorWasmError::TenantIsolationViolation {
tenant_id, ..
} => {
assert_eq!(tenant_id, TenantId(7));
}
other => panic!("expected TenantIsolationViolation, got {other:?}"),
}
assert_eq!(ctx_b.bytes_in_use(), 256);
ctx_a
.release_bytes_with_capability(&tcap_b, 1)
.expect_err("foreign-registry cap must be refused under strict binding");
assert_eq!(ctx_a.bytes_in_use(), 128);
ctx_a.consume_bytes_with_capability(&tcap_a, 16).unwrap();
assert_eq!(ctx_a.bytes_in_use(), 144);
}
#[test]
fn clone_of_registry_shares_token_so_caps_remain_valid() {
let (reg, cap) = TenantRegistry::new();
let reg_clone = reg.clone();
reg.register(make_ctx(1)).unwrap();
assert_eq!(reg_clone.len_strict(&cap).unwrap(), 1);
assert!(reg_clone.get_strict(TenantId(1), &cap).unwrap().is_some());
}
#[test]
fn tenant_cap_is_clone_safe_and_continues_to_bind() {
let (reg, _) = TenantRegistry::new();
let (ctx, tcap) = reg.register_with_capability(make_ctx(99)).unwrap();
let tcap2: TenantCapability = tcap.clone();
ctx.consume_bytes_with_capability(&tcap2, 32).unwrap();
assert_eq!(ctx.bytes_in_use(), 32);
}