tidaldb/tidal/tests/sandboxed_storage.rs
jx12n 3bcfb3c576 feat: Bazel build, crate docs/ai-lookup, docker images, and engine hardening
- Add BUILD.bazel across tidal, tidal-net, tidal-server, tidalctl for bzlmod build
- Add tidal/ crate docs (README, CHANGELOG, CONTRIBUTING, AGENTS, CLAUDE, API, ARCHITECTURE) and ai-lookup reference
- Add docker standalone/cluster/deploy images, compose, and prometheus config
- Harden WAL (batch format, writer, dedup, diagnostics), text syncer/collectors, and vector registry
- Expand tidalctl CLI and tests; restructure WAL/visibility integration test suites
- Refine tidal-net transport/client/server and tidal-server cluster/scatter-gather
2026-06-07 18:29:38 -06:00

175 lines
5.8 KiB
Rust

#![allow(clippy::unwrap_used, clippy::expect_used, clippy::missing_panics_doc)]
//! Integration tests for the sandboxed storage layout.
//!
//! Validates that [`Paths`] and [`TempTidalHome`] provide correct,
//! isolated filesystem sandboxes for tidalDB instances.
use tidaldb::{TidalDb, db::temp::TempTidalHome};
// =============================================================================
// TempTidalHome isolation
// =============================================================================
#[test]
fn two_temp_homes_have_non_overlapping_paths() {
let home1 = TempTidalHome::new().unwrap();
let home2 = TempTidalHome::new().unwrap();
assert_ne!(
home1.path(),
home2.path(),
"two TempTidalHome instances must have different base paths"
);
// Verify neither is a prefix of the other (true isolation).
assert!(
!home1.path().starts_with(home2.path()),
"home1 should not be a subdirectory of home2"
);
assert!(
!home2.path().starts_with(home1.path()),
"home2 should not be a subdirectory of home1"
);
}
// =============================================================================
// Drop removes directory
// =============================================================================
#[test]
fn drop_removes_directory_with_contents() {
let path = {
let home = TempTidalHome::new().unwrap();
let p = home.path().to_owned();
// Create a file inside so the directory is non-empty.
std::fs::write(p.join("sentinel.txt"), b"test data").unwrap();
assert!(p.exists(), "directory should exist before drop");
p
// home dropped here
};
assert!(!path.exists(), "directory should be removed after drop");
}
// =============================================================================
// with_preserve keeps directory
// =============================================================================
#[test]
fn with_preserve_keeps_directory_after_drop() {
let path = {
let home = TempTidalHome::with_preserve().unwrap();
let p = home.path().to_owned();
std::fs::write(p.join("sentinel.txt"), b"test data").unwrap();
p
// home dropped here, but preserve=true
};
assert!(
path.exists(),
"directory should still exist after drop with preserve"
);
// Manual cleanup.
std::fs::remove_dir_all(&path).unwrap();
}
// =============================================================================
// Paths::ensure_all creates expected subdirectories
// =============================================================================
#[test]
fn ensure_all_creates_all_subdirectories() {
let home = TempTidalHome::new().unwrap();
let paths = home.paths();
// Before ensure_all, subdirectories should not exist.
assert!(!paths.wal_dir().exists());
assert!(!paths.items_dir().exists());
assert!(!paths.users_dir().exists());
assert!(!paths.creators_dir().exists());
assert!(!paths.cache_dir().exists());
paths.ensure_all().unwrap();
// After ensure_all, all subdirectories should exist.
assert!(paths.wal_dir().is_dir(), "wal dir should exist");
assert!(paths.items_dir().is_dir(), "items dir should exist");
assert!(paths.users_dir().is_dir(), "users dir should exist");
assert!(paths.creators_dir().is_dir(), "creators dir should exist");
assert!(paths.cache_dir().is_dir(), "cache dir should exist");
}
// =============================================================================
// Two builders with different TempTidalHome roots never collide
// =============================================================================
#[test]
fn two_builders_with_different_homes_are_isolated() {
let home1 = TempTidalHome::new().unwrap();
let home2 = TempTidalHome::new().unwrap();
let paths1 = home1.paths();
let paths2 = home2.paths();
paths1.ensure_all().unwrap();
paths2.ensure_all().unwrap();
// Write a file into home1's wal directory.
let sentinel1 = paths1.wal_dir().join("segment-001");
std::fs::write(&sentinel1, b"home1 wal data").unwrap();
// Write a file into home2's wal directory.
let sentinel2 = paths2.wal_dir().join("segment-001");
std::fs::write(&sentinel2, b"home2 wal data").unwrap();
// Verify each sees only its own data.
let data1 = std::fs::read(&sentinel1).unwrap();
let data2 = std::fs::read(&sentinel2).unwrap();
assert_eq!(data1, b"home1 wal data");
assert_eq!(data2, b"home2 wal data");
// Verify the other home's directory does not contain the wrong data.
assert_ne!(data1, data2);
}
// =============================================================================
// Builder integrates with Paths via TempTidalHome
// =============================================================================
#[test]
fn builder_with_temp_home_opens_successfully() {
let home = TempTidalHome::new().unwrap();
// The builder validates data_dir exists (TempTidalHome creates it).
// Resolved defaults (wal_dir, cache_dir) are populated after validation
// so they don't need to pre-exist.
let db = TidalDb::builder().with_data_dir(home.path()).open();
assert!(db.is_ok(), "builder with TempTidalHome should succeed");
}
#[test]
fn ensure_all_is_idempotent() {
let home = TempTidalHome::new().unwrap();
let paths = home.paths();
paths.ensure_all().unwrap();
// Write a file to verify it survives a second ensure_all.
std::fs::write(paths.wal_dir().join("segment-001"), b"data").unwrap();
paths.ensure_all().unwrap();
// File should still exist.
assert!(paths.wal_dir().join("segment-001").exists());
}
#[test]
fn paths_base_matches_temp_home_path() {
let home = TempTidalHome::new().unwrap();
let paths = home.paths();
assert_eq!(paths.base(), home.path());
}