upleb.uk

Public git repos — served from a NIP-34 GRASP relay at git.upleb.uk

summaryrefslogtreecommitdiff
path: root/grasp-audit/src/audit.rs
diff options
context:
space:
mode:
authorDanConwayDev <DanConwayDev@protonmail.com>2025-12-02 21:20:17 +0000
committerDanConwayDev <DanConwayDev@protonmail.com>2025-12-02 21:20:17 +0000
commit72683beea066d066637e747c40dc859fb709babf (patch)
tree2db3462ebbcb7501e56491148cc3ffa7aa294071 /grasp-audit/src/audit.rs
parent5c10ca008413744b09136618eaa85275c997704c (diff)
refactor: rename AuditMode variants and change CLI default to shared
Breaking change: Renamed AuditMode enum variants for clarity: - AuditMode::CI -> AuditMode::Isolated (fresh fixtures per test) - AuditMode::Production -> AuditMode::Shared (reuse fixtures across tests) Config constructors renamed (with deprecated aliases): - AuditConfig::ci() -> AuditConfig::isolated() - AuditConfig::production() -> AuditConfig::shared() CLI default changed from 'ci' to 'shared' mode, which enables fixture caching across tests. This fixes the issue where fixtures were being re-created for every test in CLI mode. Fixture caching behavior: - Shared mode (CLI default): Uses client's cache, fixtures reused - Isolated mode (for cargo test): Local cache per TestContext
Diffstat (limited to 'grasp-audit/src/audit.rs')
-rw-r--r--grasp-audit/src/audit.rs100
1 files changed, 64 insertions, 36 deletions
diff --git a/grasp-audit/src/audit.rs b/grasp-audit/src/audit.rs
index b97ddb6..713c948 100644
--- a/grasp-audit/src/audit.rs
+++ b/grasp-audit/src/audit.rs
@@ -18,46 +18,75 @@ pub struct AuditConfig {
18 pub read_only: bool, 18 pub read_only: bool,
19} 19}
20 20
21/// Audit mode 21/// Audit mode for fixture management
22///
23/// Controls how test fixtures are cached and shared between tests.
22#[derive(Debug, Clone, Copy, PartialEq, Eq)] 24#[derive(Debug, Clone, Copy, PartialEq, Eq)]
23pub enum AuditMode { 25pub enum AuditMode {
24 /// Isolated CI/CD tests - only see own events 26 /// Isolated mode - each test creates fresh fixtures
25 CI, 27 ///
28 /// Use this mode when running tests in parallel (e.g., `cargo test`)
29 /// where each test needs complete isolation from other tests.
30 /// Each TestContext gets its own local cache.
31 Isolated,
26 32
27 /// Production audit - see all events, minimal writes 33 /// Shared mode - fixtures are cached and reused across tests
28 Production, 34 ///
35 /// Use this mode when running the CLI audit tool where tests run
36 /// sequentially and build on each other's fixtures. This is more
37 /// efficient as it avoids re-creating the same prerequisite events.
38 /// All TestContexts share the client's cache.
39 Shared,
29} 40}
30 41
31impl AuditConfig { 42impl AuditConfig {
32 /// Create config for CI/CD testing 43 /// Create config for isolated testing (e.g., cargo test)
33 pub fn ci() -> Self { 44 ///
34 let run_id = format!("ci-{}", &uuid::Uuid::new_v4().to_string()[..8]); 45 /// Each test creates fresh fixtures for complete test isolation.
46 /// Use this when running tests in parallel.
47 pub fn isolated() -> Self {
48 let run_id = format!("isolated-{}", &uuid::Uuid::new_v4().to_string()[..8]);
35 Self { 49 Self {
36 run_id, 50 run_id,
37 mode: AuditMode::CI, 51 mode: AuditMode::Isolated,
38 cleanup_after: Timestamp::now() + 3600, // 1 hour from now 52 cleanup_after: Timestamp::now() + 3600, // 1 hour from now
39 read_only: false, 53 read_only: false,
40 } 54 }
41 } 55 }
42 56
43 /// Create config for production audit 57 /// Create config for shared fixture mode (default for CLI)
44 pub fn production() -> Self { 58 ///
45 let run_id = format!("prod-audit-{}", Timestamp::now().as_u64()); 59 /// Fixtures are cached and reused across tests. Use this when
60 /// running the CLI audit tool where tests run sequentially.
61 pub fn shared() -> Self {
62 let run_id = format!("audit-{}", &uuid::Uuid::new_v4().to_string()[..8]);
46 Self { 63 Self {
47 run_id, 64 run_id,
48 mode: AuditMode::Production, 65 mode: AuditMode::Shared,
49 cleanup_after: Timestamp::now() + 300, // 5 minutes from now 66 cleanup_after: Timestamp::now() + 3600, // 1 hour from now
50 read_only: true, // Default to read-only for production 67 read_only: false,
51 } 68 }
52 } 69 }
53 70
71 /// Alias for isolated() - for backwards compatibility
72 #[deprecated(since = "0.2.0", note = "Use isolated() instead")]
73 pub fn ci() -> Self {
74 Self::isolated()
75 }
76
77 /// Alias for shared() - for backwards compatibility
78 #[deprecated(since = "0.2.0", note = "Use shared() instead")]
79 pub fn production() -> Self {
80 Self::shared()
81 }
82
54 /// Create config with custom run ID 83 /// Create config with custom run ID
55 pub fn with_run_id(run_id: String, mode: AuditMode) -> Self { 84 pub fn with_run_id(run_id: String, mode: AuditMode) -> Self {
56 Self { 85 Self {
57 run_id, 86 run_id,
58 mode, 87 mode,
59 cleanup_after: Timestamp::now() + 3600, 88 cleanup_after: Timestamp::now() + 3600,
60 read_only: mode == AuditMode::Production, 89 read_only: false,
61 } 90 }
62 } 91 }
63 92
@@ -72,11 +101,10 @@ impl AuditConfig {
72 /// 101 ///
73 /// 1. `["t", "grasp-audit-test-event"]` - Identifies all audit-related events 102 /// 1. `["t", "grasp-audit-test-event"]` - Identifies all audit-related events
74 /// 2. `["t", "audit-{run_id}"]` - Unique identifier for this audit run 103 /// 2. `["t", "audit-{run_id}"]` - Unique identifier for this audit run
75 /// - CI mode: `audit-ci-{uuid}` 104 /// - Isolated mode: `audit-isolated-{uuid}`
76 /// - Production mode: `audit-prod-audit-{timestamp}` 105 /// - Shared mode: `audit-audit-{uuid}`
77 /// 3. `["t", "audit-cleanup-after-{unix_timestamp}"]` - Cleanup timestamp 106 /// 3. `["t", "audit-cleanup-after-{unix_timestamp}"]` - Cleanup timestamp
78 /// - CI mode: Current time + 3600 seconds (1 hour) 107 /// - Default: Current time + 3600 seconds (1 hour)
79 /// - Production mode: Current time + 300 seconds (5 minutes)
80 /// 108 ///
81 /// # Purpose 109 /// # Purpose
82 /// 110 ///
@@ -90,7 +118,7 @@ impl AuditConfig {
90 /// ```rust 118 /// ```rust
91 /// use grasp_audit::AuditConfig; 119 /// use grasp_audit::AuditConfig;
92 /// 120 ///
93 /// let config = AuditConfig::ci(); 121 /// let config = AuditConfig::isolated();
94 /// let tags = config.audit_tags(); 122 /// let tags = config.audit_tags();
95 /// 123 ///
96 /// // Tags will look like: 124 /// // Tags will look like:
@@ -168,7 +196,7 @@ impl AuditEventBuilder {
168 /// use nostr_sdk::prelude::*; 196 /// use nostr_sdk::prelude::*;
169 /// use grasp_audit::{AuditConfig, AuditEventBuilder}; 197 /// use grasp_audit::{AuditConfig, AuditEventBuilder};
170 /// 198 ///
171 /// let config = AuditConfig::ci(); 199 /// let config = AuditConfig::isolated();
172 /// let keys = Keys::generate(); 200 /// let keys = Keys::generate();
173 /// 201 ///
174 /// // Create an event with a past timestamp 202 /// // Create an event with a past timestamp
@@ -209,26 +237,26 @@ mod tests {
209 use super::*; 237 use super::*;
210 238
211 #[test] 239 #[test]
212 fn test_ci_config() { 240 fn test_isolated_config() {
213 let config = AuditConfig::ci(); 241 let config = AuditConfig::isolated();
214 assert_eq!(config.mode, AuditMode::CI); 242 assert_eq!(config.mode, AuditMode::Isolated);
215 assert!(!config.read_only); 243 assert!(!config.read_only);
216 assert!(config.run_id.starts_with("ci-")); 244 assert!(config.run_id.starts_with("isolated-"));
217 } 245 }
218 246
219 #[test] 247 #[test]
220 fn test_production_config() { 248 fn test_shared_config() {
221 let config = AuditConfig::production(); 249 let config = AuditConfig::shared();
222 assert_eq!(config.mode, AuditMode::Production); 250 assert_eq!(config.mode, AuditMode::Shared);
223 assert!(config.read_only); 251 assert!(!config.read_only);
224 assert!(config.run_id.starts_with("prod-audit-")); 252 assert!(config.run_id.starts_with("audit-"));
225 } 253 }
226 254
227 #[test] 255 #[test]
228 fn test_audit_tags() { 256 fn test_audit_tags() {
229 use nostr_sdk::prelude::{Alphabet, SingleLetterTag}; 257 use nostr_sdk::prelude::{Alphabet, SingleLetterTag};
230 258
231 let config = AuditConfig::ci(); 259 let config = AuditConfig::isolated();
232 let tags = config.audit_tags(); 260 let tags = config.audit_tags();
233 261
234 assert_eq!(tags.len(), 3); 262 assert_eq!(tags.len(), 3);
@@ -252,7 +280,7 @@ mod tests {
252 // Check for "t" tag with "audit-{run_id}" 280 // Check for "t" tag with "audit-{run_id}"
253 assert!(tags.iter().any(|t| { 281 assert!(tags.iter().any(|t| {
254 t.content() 282 t.content()
255 .map(|c| c.starts_with("audit-ci-")) 283 .map(|c| c.starts_with("audit-isolated-"))
256 .unwrap_or(false) 284 .unwrap_or(false)
257 })); 285 }));
258 286
@@ -266,7 +294,7 @@ mod tests {
266 294
267 #[test] 295 #[test]
268 fn test_audit_event_builder() { 296 fn test_audit_event_builder() {
269 let config = AuditConfig::ci(); 297 let config = AuditConfig::isolated();
270 let keys = Keys::generate(); 298 let keys = Keys::generate();
271 299
272 let event = AuditEventBuilder::new(Kind::TextNote, "test", config.clone()) 300 let event = AuditEventBuilder::new(Kind::TextNote, "test", config.clone())
@@ -283,7 +311,7 @@ mod tests {
283 311
284 #[test] 312 #[test]
285 fn test_custom_timestamp_applied() { 313 fn test_custom_timestamp_applied() {
286 let config = AuditConfig::ci(); 314 let config = AuditConfig::isolated();
287 let keys = Keys::generate(); 315 let keys = Keys::generate();
288 let custom_ts = Timestamp::from(1700000000); 316 let custom_ts = Timestamp::from(1700000000);
289 317
@@ -302,7 +330,7 @@ mod tests {
302 330
303 #[test] 331 #[test]
304 fn test_default_timestamp_uses_current_time() { 332 fn test_default_timestamp_uses_current_time() {
305 let config = AuditConfig::ci(); 333 let config = AuditConfig::isolated();
306 let keys = Keys::generate(); 334 let keys = Keys::generate();
307 335
308 let before = Timestamp::now(); 336 let before = Timestamp::now();