-
Notifications
You must be signed in to change notification settings - Fork 1
tests: own the temp vault directories, and bound them at the source #41
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: master
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -3824,6 +3824,7 @@ fn row_to_intent(row: &rusqlite::Row<'_>) -> rusqlite::Result<RefreshIntent> { | |
|
|
||
| #[cfg(test)] | ||
| mod tests { | ||
| use crate::test_support::TestTempDir; | ||
|
|
||
| /// The scrub shape leaves a WRITABLE store, which was the one claim in the restore | ||
| /// contract I had only read at source rather than exercised. | ||
|
|
@@ -3918,17 +3919,17 @@ mod tests { | |
| /// A scratch database path under the same temp-dir idiom the rest of this module | ||
| /// uses: pid plus a counter, so parallel test threads cannot collide and a recycled | ||
| /// pid on windows cannot inherit a previous run's directory. | ||
| fn scratch_db(label: &str) -> std::path::PathBuf { | ||
| fn scratch_db(label: &str) -> (TestTempDir, std::path::PathBuf) { | ||
| use std::sync::atomic::{AtomicU64, Ordering}; | ||
| static SEQ: AtomicU64 = AtomicU64::new(0); | ||
| let root = std::env::temp_dir().join(format!( | ||
| let root = TestTempDir::new(format!( | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. P2: These two tests migrated to TestTempDir but kept the manual Prompt for AI agents |
||
| "ck-restore-{}-{}-{}", | ||
| label, | ||
| std::process::id(), | ||
| SEQ.fetch_add(1, Ordering::Relaxed) | ||
| )); | ||
| std::fs::create_dir(&root).expect("scratch dir"); | ||
| root.join("store.db") | ||
| let path = root.join("store.db"); | ||
| (root, path) | ||
| } | ||
|
|
||
| /// The restore report answers on a file the house read-only form CANNOT open. | ||
|
|
@@ -3940,7 +3941,7 @@ mod tests { | |
| /// store and never exercise the reason the function opens differently. | ||
| #[test] | ||
| fn the_restore_report_reads_a_wal_header_with_no_sidecar() { | ||
| let path = scratch_db("restored"); | ||
| let (_root, path) = scratch_db("restored"); | ||
| { | ||
| let c = rusqlite::Connection::open(&path).expect("create"); | ||
| c.pragma_update(None, "journal_mode", "WAL").expect("wal"); | ||
|
|
@@ -4025,7 +4026,7 @@ mod tests { | |
| /// store, which this repo already fixed once by omitting the counts instead. | ||
| #[test] | ||
| fn a_missing_fence_table_is_absent_rather_than_zero() { | ||
| let path = scratch_db("nofence"); | ||
| let (_root, path) = scratch_db("nofence"); | ||
| { | ||
| let c = rusqlite::Connection::open(&path).expect("create"); | ||
| c.execute_batch( | ||
|
|
@@ -4062,7 +4063,7 @@ mod tests { | |
| fn the_online_grant_listing_keeps_read_and_sign_separate_and_orders_by_prefix() { | ||
| use std::sync::atomic::{AtomicU64, Ordering}; | ||
| static SEQ: AtomicU64 = AtomicU64::new(0); | ||
| let root = std::env::temp_dir().join(format!( | ||
| let root = TestTempDir::new(format!( | ||
| "ck-grantorder-{}-{}", | ||
| std::process::id(), | ||
| SEQ.fetch_add(1, Ordering::Relaxed) | ||
|
|
@@ -4131,7 +4132,7 @@ mod tests { | |
| fn a_store_ahead_of_this_binary_refuses_to_migrate() { | ||
| use std::sync::atomic::{AtomicU64, Ordering}; | ||
| static SEQ: AtomicU64 = AtomicU64::new(0); | ||
| let root = std::env::temp_dir().join(format!( | ||
| let root = TestTempDir::new(format!( | ||
| "ck-cred-ahead-{}-{}", | ||
| std::process::id(), | ||
| SEQ.fetch_add(1, Ordering::Relaxed) | ||
|
|
@@ -4175,10 +4176,10 @@ mod tests { | |
| use crate::oauth::OAuthCredential; | ||
| use cortexkit_store::{open_sqlite, Isolation, StorageBackend, StorageDescriptor}; | ||
|
|
||
| fn tmp_store(seed: u8) -> (std::path::PathBuf, EncryptedStore) { | ||
| fn tmp_store(seed: u8) -> (TestTempDir, EncryptedStore) { | ||
| use std::sync::atomic::{AtomicU64, Ordering}; | ||
| static SEQ: AtomicU64 = AtomicU64::new(0); | ||
| let root = std::env::temp_dir().join(format!( | ||
| let root = TestTempDir::new(format!( | ||
| "ck-cred-store-{}-{}", | ||
| std::process::id(), | ||
| SEQ.fetch_add(1, Ordering::Relaxed) | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,82 @@ | ||
| use std::{ | ||
| ops::Deref, | ||
| path::{Path, PathBuf}, | ||
| }; | ||
|
|
||
| /// A test-owned directory that is removed when its owner leaves scope. | ||
| #[derive(Debug)] | ||
| pub struct TestTempDir { | ||
| path: Option<PathBuf>, | ||
| } | ||
|
|
||
| impl TestTempDir { | ||
| pub fn new(name: impl AsRef<str>) -> Self { | ||
| let path = std::env::temp_dir().join(name.as_ref()); | ||
| Self::from_path(path) | ||
| } | ||
|
|
||
| pub fn from_path(path: PathBuf) -> Self { | ||
| // A reused PID can collide with an orphaned test directory; refuse rather than | ||
| // silently inherit a vault whose store and key material may not belong together. | ||
| std::fs::create_dir(&path) | ||
| .unwrap_or_else(|e| panic!("create test temp directory {}: {e}", path.display())); | ||
| Self { path: Some(path) } | ||
| } | ||
|
|
||
| pub fn path(&self) -> &Path { | ||
| self.path.as_deref().expect("test temp directory was kept") | ||
| } | ||
|
|
||
| /// Preserve evidence only when it must outlive this guard; current crash-cut tests do not. | ||
| pub fn keep(mut self) -> PathBuf { | ||
| self.path | ||
| .take() | ||
| .expect("test temp directory was already kept") | ||
| } | ||
| } | ||
|
|
||
| impl Deref for TestTempDir { | ||
| type Target = Path; | ||
|
|
||
| fn deref(&self) -> &Self::Target { | ||
| self.path() | ||
| } | ||
| } | ||
|
|
||
| impl AsRef<Path> for TestTempDir { | ||
| fn as_ref(&self) -> &Path { | ||
| self.path() | ||
| } | ||
| } | ||
|
|
||
| impl Drop for TestTempDir { | ||
| fn drop(&mut self) { | ||
| if let Some(path) = self.path.take() { | ||
| let _ = std::fs::remove_dir_all(path); | ||
| } | ||
| } | ||
| } | ||
|
|
||
| #[cfg(test)] | ||
| mod tests { | ||
| use super::TestTempDir; | ||
|
|
||
| #[test] | ||
| fn keep_disarms_removal() { | ||
| // The crash-cut suites still pass if keep() is broken because they inspect before | ||
| // their guards drop. This focused test is the only coverage that detects a clone | ||
| // here instead of take(), which would leave Drop armed and erase kept evidence. | ||
| let path = TestTempDir::new("ck-cred-test-support-keep").keep(); | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. P2: These unit tests use fixed temp names, so an interrupted Prompt for AI agents |
||
| assert!(path.exists(), "keep must leave crash-cut evidence behind"); | ||
| std::fs::remove_dir_all(path).expect("remove kept test directory"); | ||
| } | ||
|
|
||
| #[test] | ||
| fn drop_removes_directory() { | ||
| let path = { | ||
| let dir = TestTempDir::new("ck-cred-test-support-drop"); | ||
| dir.path().to_path_buf() | ||
| }; | ||
| assert!(!path.exists(), "drop must remove the test directory"); | ||
| } | ||
| } | ||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
P2:
migration-toolsis a production one-shot feature (ck_key_move/ck_key_verify write master-key material), not an integration test, yet it now pulls intest-support, contradicting the stated goal that test fixtures stay out of normal builds. Neither migration bin usestest_support/TestTempDirand neither has unit tests, so the dependency is unnecessary and widens the test-code surface in a master-key-handling tool. Drop thetest-supportdependency and keep the feature empty.Prompt for AI agents