use std::error::Error;
use std::num::{NonZeroU32, NonZeroUsize};
use std::time::Duration;
use haematite::{DatabaseConfig, NodeCacheBudget, Retention};
use super::{Limits, Listener, Service};
use crate::serve::storage::Storage;
type TestResult = Result<(), Box<dyn Error>>;
fn service(directory: &std::path::Path) -> Result<Service, Box<dyn Error>> {
let storage = Storage::create(
DatabaseConfig {
data_dir: directory.join("database"),
shard_count: 1,
distributed: None,
executor_threads: Some(1),
node_cache_budget: Some(NodeCacheBudget::Unlimited),
retention: Retention::reclaim(0),
},
NodeCacheBudget::Unlimited,
Duration::from_secs(1),
)?;
Ok(Service::new(storage, NonZeroU32::MIN)?)
}
fn limits() -> Limits {
Limits {
max_frame: NonZeroU32::MIN,
max_clients: NonZeroUsize::MIN,
frame_timeout: Duration::from_secs(1),
}
}
#[test]
fn a_refused_bind_does_not_activate_the_store() -> TestResult {
let directory = tempfile::tempdir()?;
let service = service(directory.path())?;
let socket = directory.path().join("service.socket");
let first = Listener::bind(&socket)?;
assert!(Listener::bind(&socket).is_err());
let status = service.reclaim_status()?;
assert_eq!(status.shards.len(), 1);
match &status.shards[0] {
haematite::db::ShardReclaimAnswer::Answered { status, .. } => {
assert_eq!(status.passes_finished, 0);
assert_eq!(status.given_back_nodes, 0);
assert_eq!(status.phase, haematite::db::ReclaimPhase::Idle);
}
haematite::db::ShardReclaimAnswer::NotAnswering { reason, .. } => {
return Err(reason.clone().into());
}
}
drop(first);
Ok(())
}
#[test]
fn listener_readiness_activates_only_after_setup_and_is_idempotent() -> TestResult {
let directory = tempfile::tempdir()?;
let service = service(directory.path())?;
let listener = Listener::bind(&directory.path().join("service.socket"))?;
let mut invalid = limits();
invalid.frame_timeout = Duration::ZERO;
assert!(Listener::begin_serving(&service, invalid).is_err());
assert!(service.quiesce_reclaim().is_err());
Listener::begin_serving(&service, limits())?;
Listener::begin_serving(&service, limits())?;
service.quiesce_reclaim()?;
let status = service.reclaim_status()?;
assert_eq!(status.shards.len(), 1);
match &status.shards[0] {
haematite::db::ShardReclaimAnswer::Answered { status, .. } => {
assert_eq!(status.phase, haematite::db::ReclaimPhase::Idle);
assert_eq!(status.passes_finished, 1);
}
haematite::db::ShardReclaimAnswer::NotAnswering { reason, .. } => {
return Err(reason.clone().into());
}
}
Ok(())
}