test: verify scoped authority storage lifetime and physical initialization
This commit is contained in:
@@ -5,6 +5,9 @@ edition.workspace = true
|
||||
license.workspace = true
|
||||
publish = false
|
||||
|
||||
[features]
|
||||
test-support = []
|
||||
|
||||
[dependencies]
|
||||
rusqlite.workspace = true
|
||||
thiserror.workspace = true
|
||||
|
||||
@@ -121,13 +121,28 @@ impl FeatureRegistration {
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "test-support")]
|
||||
#[path = "open_observation.rs"]
|
||||
mod open_observation;
|
||||
#[cfg(feature = "test-support")]
|
||||
pub use open_observation::OpenObservation;
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct RegisteredFeature {
|
||||
manager_id: Uuid,
|
||||
feature_id: String,
|
||||
#[cfg(feature = "test-support")]
|
||||
observation: Arc<open_observation::Counters>,
|
||||
}
|
||||
|
||||
impl RegisteredFeature {
|
||||
/// Instance-local physical-operation counters for fixture assertions. The
|
||||
/// observer retains no database and cannot replace or suppress durable I/O.
|
||||
#[cfg(feature = "test-support")]
|
||||
pub fn open_observation(&self) -> OpenObservation {
|
||||
self.observation.snapshot()
|
||||
}
|
||||
|
||||
pub fn feature_id(&self) -> &str {
|
||||
&self.feature_id
|
||||
}
|
||||
@@ -219,6 +234,8 @@ impl FeatureStorage {
|
||||
Ok(RegisteredFeature {
|
||||
manager_id: self.inner.id,
|
||||
feature_id,
|
||||
#[cfg(feature = "test-support")]
|
||||
observation: Arc::default(),
|
||||
})
|
||||
}
|
||||
|
||||
@@ -279,14 +296,32 @@ impl FeatureStorage {
|
||||
}
|
||||
|
||||
let feature_dir = self.feature_dir(scope_id);
|
||||
#[cfg(feature = "test-support")]
|
||||
let mut counted_sync = |path: &Path| {
|
||||
registration.observation.sync_attempt();
|
||||
let result = sync(path);
|
||||
if result.is_ok() {
|
||||
registration.observation.sync_success();
|
||||
}
|
||||
result
|
||||
};
|
||||
#[cfg(feature = "test-support")]
|
||||
durable_create_directory(&feature_dir, &mut counted_sync)?;
|
||||
#[cfg(not(feature = "test-support"))]
|
||||
durable_create_directory(&feature_dir, &mut sync)?;
|
||||
let path = feature_dir.join(format!("{}.sqlite", registration.feature_id));
|
||||
#[cfg(feature = "test-support")]
|
||||
registration.observation.open_attempt();
|
||||
let connection = Connection::open_with_flags(
|
||||
path,
|
||||
OpenFlags::SQLITE_OPEN_READ_WRITE | OpenFlags::SQLITE_OPEN_CREATE,
|
||||
)?;
|
||||
#[cfg(feature = "test-support")]
|
||||
registration.observation.open_success();
|
||||
configure_connection(&connection)?;
|
||||
migrate(&connection, ®istration.feature_id, migrations)?;
|
||||
#[cfg(feature = "test-support")]
|
||||
registration.observation.initialized();
|
||||
let connection = Arc::new(FeatureDatabaseInner {
|
||||
scope_id: scope_id.to_string(),
|
||||
feature_id: registration.feature_id.clone(),
|
||||
|
||||
@@ -0,0 +1,64 @@
|
||||
use std::sync::atomic::{AtomicU64, Ordering};
|
||||
|
||||
/// Read-only observations for one registration (and its clones) across its scopes.
|
||||
/// Counts real I/O boundaries, not API opens, and retains no physical database.
|
||||
#[derive(Clone, Copy, Debug, Default, PartialEq, Eq)]
|
||||
pub struct OpenObservation {
|
||||
pub physical_open_attempts: u64,
|
||||
pub physical_opens: u64,
|
||||
pub completed_initializations: u64,
|
||||
pub directory_sync_attempts: u64,
|
||||
pub directory_sync_successes: u64,
|
||||
}
|
||||
|
||||
impl OpenObservation {
|
||||
pub fn since(self, before: Self) -> Self {
|
||||
Self {
|
||||
physical_open_attempts: self.physical_open_attempts - before.physical_open_attempts,
|
||||
physical_opens: self.physical_opens - before.physical_opens,
|
||||
completed_initializations: self.completed_initializations
|
||||
- before.completed_initializations,
|
||||
directory_sync_attempts: self.directory_sync_attempts - before.directory_sync_attempts,
|
||||
directory_sync_successes: self.directory_sync_successes
|
||||
- before.directory_sync_successes,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Default)]
|
||||
pub(super) struct Counters {
|
||||
physical_open_attempts: AtomicU64,
|
||||
physical_opens: AtomicU64,
|
||||
completed_initializations: AtomicU64,
|
||||
directory_sync_attempts: AtomicU64,
|
||||
directory_sync_successes: AtomicU64,
|
||||
}
|
||||
|
||||
impl Counters {
|
||||
pub(super) fn snapshot(&self) -> OpenObservation {
|
||||
OpenObservation {
|
||||
physical_open_attempts: self.physical_open_attempts.load(Ordering::Relaxed),
|
||||
physical_opens: self.physical_opens.load(Ordering::Relaxed),
|
||||
completed_initializations: self.completed_initializations.load(Ordering::Relaxed),
|
||||
directory_sync_attempts: self.directory_sync_attempts.load(Ordering::Relaxed),
|
||||
directory_sync_successes: self.directory_sync_successes.load(Ordering::Relaxed),
|
||||
}
|
||||
}
|
||||
pub(super) fn open_attempt(&self) {
|
||||
self.physical_open_attempts.fetch_add(1, Ordering::Relaxed);
|
||||
}
|
||||
pub(super) fn open_success(&self) {
|
||||
self.physical_opens.fetch_add(1, Ordering::Relaxed);
|
||||
}
|
||||
pub(super) fn initialized(&self) {
|
||||
self.completed_initializations
|
||||
.fetch_add(1, Ordering::Relaxed);
|
||||
}
|
||||
pub(super) fn sync_attempt(&self) {
|
||||
self.directory_sync_attempts.fetch_add(1, Ordering::Relaxed);
|
||||
}
|
||||
pub(super) fn sync_success(&self) {
|
||||
self.directory_sync_successes
|
||||
.fetch_add(1, Ordering::Relaxed);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user