use super::{
AgentId, AuditEntry, AuditSink, CredentialStore, LifecycleStore, PolicyStore, RateLimitCounter, SessionRecord,
SessionStore, StorageError,
};
pub async fn assert_policy_store_conformance(store: &dyn PolicyStore, present: &AgentId, absent: &AgentId) {
store
.get_policy(present)
.await
.expect("get_policy(present) should resolve to a policy");
match store.get_policy(absent).await {
Err(StorageError::NotFound(_)) => {}
other => panic!("get_policy(absent) should return NotFound, got {other:?}"),
}
store
.invalidate(present)
.await
.expect("invalidate(present) should succeed");
store
.invalidate(absent)
.await
.expect("invalidate(absent) should be idempotent");
}
pub async fn assert_audit_sink_conformance(sink: &dyn AuditSink, event: AuditEntry) {
sink.emit(event).await.expect("emit should persist the entry");
}
pub async fn assert_session_store_conformance(store: &dyn SessionStore, record: SessionRecord) {
let id = record.session_id;
store.save(record.clone()).await.expect("save(new) should succeed");
let loaded = store.load(&id).await.expect("load(present) should return the record");
assert_eq!(loaded, record, "loaded record should equal the saved record");
store.delete(&id).await.expect("delete(present) should succeed");
match store.load(&id).await {
Err(StorageError::NotFound(_)) => {}
other => panic!("load(deleted) should return NotFound, got {other:?}"),
}
store.delete(&id).await.expect("delete(absent) should be idempotent");
}
pub async fn assert_credential_store_conformance(store: &dyn CredentialStore, key: &str, value: Vec<u8>) {
store
.put_secret(key, value.clone())
.await
.expect("put_secret(new) should succeed");
let got = store
.get_secret(key)
.await
.expect("get_secret(present) should return the value");
assert_eq!(got, value, "round-tripped secret bytes should match");
store
.delete_secret(key)
.await
.expect("delete_secret(present) should succeed");
match store.get_secret(key).await {
Err(StorageError::NotFound(_)) => {}
other => panic!("get_secret(deleted) should return NotFound, got {other:?}"),
}
store
.delete_secret(key)
.await
.expect("delete_secret(absent) should be idempotent");
}
pub async fn assert_rate_limit_counter_conformance(counter: &dyn RateLimitCounter, key: &str) {
const WINDOW_SECS: u64 = 3600;
assert_eq!(
counter.current(key).await.expect("current(fresh) should succeed"),
0,
"a key that was never incremented reads 0"
);
assert_eq!(
counter
.increment(key, 5, WINDOW_SECS)
.await
.expect("increment should succeed"),
5,
"first increment returns the amount added"
);
assert_eq!(
counter
.increment(key, 3, WINDOW_SECS)
.await
.expect("increment should succeed"),
8,
"second increment accumulates within the window"
);
assert_eq!(
counter.current(key).await.expect("current should succeed"),
8,
"current reflects the accumulated total"
);
counter.reset(key).await.expect("reset should succeed");
assert_eq!(
counter.current(key).await.expect("current after reset should succeed"),
0,
"reset returns the counter to 0"
);
counter.reset(key).await.expect("reset(absent) should be idempotent");
}
pub async fn assert_lifecycle_store_conformance(store: &dyn LifecycleStore, present: &AgentId, absent: &AgentId) {
store.register(present).await.expect("register should succeed");
store
.heartbeat(present)
.await
.expect("heartbeat(registered) should succeed");
match store.heartbeat(absent).await {
Err(StorageError::NotFound(_)) => {}
other => panic!("heartbeat(unregistered) should return NotFound, got {other:?}"),
}
store
.deregister(present)
.await
.expect("deregister(registered) should succeed");
match store.heartbeat(present).await {
Err(StorageError::NotFound(_)) => {}
other => panic!("heartbeat(deregistered) should return NotFound, got {other:?}"),
}
store
.deregister(present)
.await
.expect("deregister(present) should be idempotent");
store
.deregister(absent)
.await
.expect("deregister(absent) should be idempotent");
}