#[path = "../../../../haematite/tests/common/runtime_options.rs"]
mod runtime_options;
use runtime_options::runtime_options;
use std::error::Error;
use std::path::{Path, PathBuf};
use haematite::Database;
use haematite::db::vacuum::CANONICAL_REFS_DIR;
use haematite::db::{DEFAULT_RECLAIM_MARK_BYTES, DatabaseConfig};
use haematite::store::NodeCacheBudget;
use super::Storage;
type TestResult = Result<(), Box<dyn Error>>;
fn keep_all(data_dir: PathBuf) -> DatabaseConfig {
DatabaseConfig {
data_dir,
shard_count: 2,
distributed: None,
executor_threads: Some(1),
node_cache_budget: Some(NodeCacheBudget::Unlimited),
retention: haematite::Retention::KeepAll,
}
}
fn kept_all_service_store(data_dir: &Path) -> TestResult {
let created = Storage::create(
keep_all(data_dir.to_path_buf()),
NodeCacheBudget::Unlimited,
fixture_long_wait_interval(),
)?;
drop(created);
Ok(())
}
fn mark_bytes(data_dir: &Path) -> Result<Option<u64>, Box<dyn Error>> {
Ok(Database::open_path_writer(data_dir, runtime_options())?.reclaim_mark_bytes())
}
fn code(opened: Result<Storage, super::Failure>) -> String {
opened.err().map(|failure| failure.code).unwrap_or_default()
}
#[test]
fn a_kept_all_service_store_is_moved_once() -> TestResult {
let directory = tempfile::tempdir()?;
let data_dir = directory.path().join("store");
kept_all_service_store(&data_dir)?;
assert_eq!(mark_bytes(&data_dir)?, None);
drop(Storage::open(
&data_dir,
NodeCacheBudget::Unlimited,
fixture_long_wait_interval(),
)?);
assert_eq!(mark_bytes(&data_dir)?, Some(DEFAULT_RECLAIM_MARK_BYTES));
let recorded = std::fs::read(data_dir.join("config.json"))?;
drop(Storage::open(
&data_dir,
NodeCacheBudget::Unlimited,
fixture_long_wait_interval(),
)?);
assert_eq!(std::fs::read(data_dir.join("config.json"))?, recorded);
Ok(())
}
#[test]
fn a_store_the_service_did_not_make_is_refused_and_not_moved() -> TestResult {
let directory = tempfile::tempdir()?;
let data_dir = directory.path().join("store");
drop(Database::create(
keep_all(data_dir.clone()),
runtime_options(),
)?);
std::fs::create_dir_all(data_dir.join(CANONICAL_REFS_DIR))?;
assert_eq!(
code(Storage::open(
&data_dir,
NodeCacheBudget::Unlimited,
fixture_long_wait_interval()
)),
"not_served"
);
assert_eq!(mark_bytes(&data_dir)?, None);
Ok(())
}
#[test]
fn a_torn_service_record_is_refused_by_name_and_not_moved() -> TestResult {
let directory = tempfile::tempdir()?;
let data_dir = directory.path().join("store");
kept_all_service_store(&data_dir)?;
for entry in std::fs::read_dir(data_dir.join(CANONICAL_REFS_DIR))? {
let path = entry?.path();
let bytes = std::fs::read(&path)?;
let torn = bytes
.get(..bytes.len().saturating_sub(1))
.unwrap_or_default();
std::fs::write(&path, torn)?;
}
let refused = code(Storage::open(
&data_dir,
NodeCacheBudget::Unlimited,
fixture_long_wait_interval(),
));
assert_eq!(refused, "service_record_unreadable");
assert_eq!(mark_bytes(&data_dir)?, None);
Ok(())
}
const fn fixture_long_wait_interval() -> std::time::Duration {
const LONG_WAIT_INTERVAL: std::time::Duration = std::time::Duration::from_secs(1);
LONG_WAIT_INTERVAL
}