//! Integration tests for the sandboxed storage layout. //! //! Validates that [`Paths`] and [`TempTidalHome`] provide correct, //! isolated filesystem sandboxes for tidalDB instances. use tidaldb::TidalDb; use 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()); }