sync from monorepo @ 2452e92e
This commit is contained in:
@@ -0,0 +1,121 @@
|
||||
#![cfg(feature = "test-utils")]
|
||||
|
||||
use std::sync::Arc;
|
||||
|
||||
use dirigent_archivist::backend::mock::MockBackend;
|
||||
use dirigent_archivist::backend::ArchiveBackend;
|
||||
use dirigent_archivist::backend::HealthStatus;
|
||||
use dirigent_archivist::coordinator::Archivist;
|
||||
use dirigent_archivist::error::ArchivistError;
|
||||
use dirigent_archivist::registry::{ArchiveRegistration, FailureMode, WritePolicy};
|
||||
use dirigent_archivist::types::SessionMetadata;
|
||||
use uuid::Uuid;
|
||||
|
||||
async fn dual_backend_coordinator() -> (Archivist, Arc<MockBackend>, Arc<MockBackend>) {
|
||||
let a = Arc::new(MockBackend::new());
|
||||
let b = Arc::new(MockBackend::new());
|
||||
let regs = vec![
|
||||
Arc::new(ArchiveRegistration::new(
|
||||
"a".into(),
|
||||
"mock",
|
||||
a.clone() as Arc<dyn ArchiveBackend>,
|
||||
true,
|
||||
FailureMode::Required,
|
||||
0,
|
||||
true,
|
||||
WritePolicy::Inline,
|
||||
None,
|
||||
HealthStatus::Healthy,
|
||||
)),
|
||||
Arc::new(ArchiveRegistration::new(
|
||||
"b".into(),
|
||||
"mock",
|
||||
b.clone() as Arc<dyn ArchiveBackend>,
|
||||
true,
|
||||
FailureMode::Required,
|
||||
10,
|
||||
true,
|
||||
WritePolicy::Inline,
|
||||
None,
|
||||
HealthStatus::Healthy,
|
||||
)),
|
||||
];
|
||||
(Archivist::from_registrations(regs), a, b)
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn copy_session_carries_metadata_and_messages() {
|
||||
let (archivist, a, b) = dual_backend_coordinator().await;
|
||||
let scroll = Uuid::new_v4();
|
||||
|
||||
// Seed `a` only.
|
||||
a.put_session(SessionMetadata::stub(scroll)).await.unwrap();
|
||||
a.append_messages(scroll, vec![]).await.unwrap();
|
||||
|
||||
archivist.copy_session(scroll, "a", "b").await.unwrap();
|
||||
|
||||
assert!(b.get_session(scroll).await.unwrap().is_some());
|
||||
assert!(a.get_session(scroll).await.unwrap().is_some());
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn move_session_removes_from_source() {
|
||||
let (archivist, a, b) = dual_backend_coordinator().await;
|
||||
let scroll = Uuid::new_v4();
|
||||
a.put_session(SessionMetadata::stub(scroll)).await.unwrap();
|
||||
|
||||
archivist.move_session(scroll, "a", "b").await.unwrap();
|
||||
|
||||
assert!(a.get_session(scroll).await.unwrap().is_none());
|
||||
assert!(b.get_session(scroll).await.unwrap().is_some());
|
||||
assert_eq!(
|
||||
archivist.read_cache_size().await,
|
||||
1,
|
||||
"cache should now reflect the move"
|
||||
);
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn move_session_partial_failure_returns_partial_move_error() {
|
||||
let (archivist, a, b) = dual_backend_coordinator().await;
|
||||
let scroll = Uuid::new_v4();
|
||||
a.put_session(SessionMetadata::stub(scroll)).await.unwrap();
|
||||
|
||||
// The source-side delete happens AFTER the copy. Inject ONE write failure
|
||||
// AFTER the copy has already consumed the write capacity. `MockBackend`'s
|
||||
// inject_write_failures decrements on every mutating call — so we:
|
||||
// 1. perform the copy through the archivist (uses put_session+append on `b`,
|
||||
// but NO writes on `a`, since reads happen on the source side).
|
||||
// 2. THEN inject a write failure on `a` to make the delete fail.
|
||||
//
|
||||
// Actually `copy_session` reads from `a` then writes to `b`, no writes on `a`.
|
||||
// So we can safely inject BEFORE calling move_session: the only write on `a`
|
||||
// during move_session is the delete, which will hit the injected failure.
|
||||
|
||||
a.inject_write_failures(1);
|
||||
|
||||
let err = archivist.move_session(scroll, "a", "b").await.unwrap_err();
|
||||
assert!(matches!(err, ArchivistError::PartialMove { .. }));
|
||||
|
||||
// Both backends now have the session.
|
||||
assert!(a.get_session(scroll).await.unwrap().is_some());
|
||||
assert!(b.get_session(scroll).await.unwrap().is_some());
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn delete_session_fans_out_and_invalidates_cache() {
|
||||
let (archivist, a, b) = dual_backend_coordinator().await;
|
||||
let scroll = Uuid::new_v4();
|
||||
a.put_session(SessionMetadata::stub(scroll)).await.unwrap();
|
||||
b.put_session(SessionMetadata::stub(scroll)).await.unwrap();
|
||||
|
||||
// Prime the cache with a read.
|
||||
let _ = archivist.get_session_metadata(scroll, None).await.unwrap();
|
||||
assert_eq!(archivist.read_cache_size().await, 1);
|
||||
|
||||
archivist.delete_session(scroll, None).await.unwrap();
|
||||
|
||||
assert!(a.get_session(scroll).await.unwrap().is_none());
|
||||
assert!(b.get_session(scroll).await.unwrap().is_none());
|
||||
assert_eq!(archivist.read_cache_size().await, 0);
|
||||
}
|
||||
Reference in New Issue
Block a user