upleb.uk

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

summaryrefslogtreecommitdiff
path: root/grasp-audit/src
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
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')
-rw-r--r--grasp-audit/src/audit.rs100
-rw-r--r--grasp-audit/src/bin/grasp-audit.rs13
-rw-r--r--grasp-audit/src/client.rs20
-rw-r--r--grasp-audit/src/fixtures.rs63
-rw-r--r--grasp-audit/src/lib.rs4
-rw-r--r--grasp-audit/src/specs/grasp01/cors.rs2
-rw-r--r--grasp-audit/src/specs/grasp01/event_acceptance_policy.rs2
-rw-r--r--grasp-audit/src/specs/grasp01/nip01_smoke.rs2
-rw-r--r--grasp-audit/src/specs/grasp01/nip11_document.rs2
-rw-r--r--grasp-audit/src/specs/grasp01/spec_requirements.rs2
10 files changed, 129 insertions, 81 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();
diff --git a/grasp-audit/src/bin/grasp-audit.rs b/grasp-audit/src/bin/grasp-audit.rs
index 48c1580..0d88bce 100644
--- a/grasp-audit/src/bin/grasp-audit.rs
+++ b/grasp-audit/src/bin/grasp-audit.rs
@@ -20,8 +20,11 @@ enum Commands {
20 #[arg(short, long)] 20 #[arg(short, long)]
21 relay: String, 21 relay: String,
22 22
23 /// Mode: ci or production 23 /// Fixture mode: shared (default) or isolated
24 #[arg(short, long, default_value = "ci")] 24 ///
25 /// - shared: Fixtures are cached and reused across tests (efficient for sequential test runs)
26 /// - isolated: Each test creates fresh fixtures (for parallel tests like cargo test)
27 #[arg(short, long, default_value = "shared")]
25 mode: String, 28 mode: String,
26 29
27 /// Spec to test (nip01-smoke, nip11, event-acceptance, cors, git-clone, push-auth, repo-creation, all) 30 /// Spec to test (nip01-smoke, nip11, event-acceptance, cors, git-clone, push-auth, repo-creation, all)
@@ -53,10 +56,14 @@ async fn main() -> Result<()> {
53 spec, 56 spec,
54 git_data_dir, 57 git_data_dir,
55 } => { 58 } => {
59 #[allow(deprecated)]
56 let mut config = match mode.as_str() { 60 let mut config = match mode.as_str() {
61 "shared" => AuditConfig::shared(),
62 "isolated" => AuditConfig::isolated(),
63 // Backwards compatibility aliases
57 "ci" => AuditConfig::ci(), 64 "ci" => AuditConfig::ci(),
58 "production" => AuditConfig::production(), 65 "production" => AuditConfig::production(),
59 _ => return Err(anyhow!("Invalid mode: {}. Use 'ci' or 'production'", mode)), 66 _ => return Err(anyhow!("Invalid mode: {}. Use 'shared' or 'isolated'", mode)),
60 }; 67 };
61 68
62 // Audit needs to create events to test the relay, so disable read-only mode 69 // Audit needs to create events to test the relay, so disable read-only mode
diff --git a/grasp-audit/src/client.rs b/grasp-audit/src/client.rs
index e4e9f07..21c70be 100644
--- a/grasp-audit/src/client.rs
+++ b/grasp-audit/src/client.rs
@@ -199,7 +199,7 @@ impl AuditClient {
199 /// ```no_run 199 /// ```no_run
200 /// # use grasp_audit::*; 200 /// # use grasp_audit::*;
201 /// # async fn example() -> anyhow::Result<()> { 201 /// # async fn example() -> anyhow::Result<()> {
202 /// let config = AuditConfig::ci(); 202 /// let config = AuditConfig::shared();
203 /// let client = AuditClient::new("ws://localhost:7000", config).await?; 203 /// let client = AuditClient::new("ws://localhost:7000", config).await?;
204 /// 204 ///
205 /// // Create event with automatic audit tags 205 /// // Create event with automatic audit tags
@@ -221,8 +221,8 @@ impl AuditClient {
221 pub async fn query(&self, mut filter: Filter) -> Result<Vec<Event>> { 221 pub async fn query(&self, mut filter: Filter) -> Result<Vec<Event>> {
222 use nostr_sdk::prelude::{Alphabet, SingleLetterTag}; 222 use nostr_sdk::prelude::{Alphabet, SingleLetterTag};
223 223
224 if self.config.mode == AuditMode::CI { 224 if self.config.mode == AuditMode::Isolated {
225 // In CI mode, only see our own audit events 225 // In Isolated mode, only see our own audit events
226 // Filter by "t" tags (hashtags) 226 // Filter by "t" tags (hashtags)
227 let t_tag = SingleLetterTag::lowercase(Alphabet::T); 227 let t_tag = SingleLetterTag::lowercase(Alphabet::T);
228 filter = filter 228 filter = filter
@@ -505,7 +505,7 @@ mod tests {
505 505
506 #[tokio::test] 506 #[tokio::test]
507 async fn test_client_creation() { 507 async fn test_client_creation() {
508 let config = AuditConfig::ci(); 508 let config = AuditConfig::isolated();
509 509
510 // This will fail if no relay is running, which is expected in tests 510 // This will fail if no relay is running, which is expected in tests
511 // In real usage, there should be a relay at the URL 511 // In real usage, there should be a relay at the URL
@@ -514,13 +514,13 @@ mod tests {
514 // We can't test connection without a running relay 514 // We can't test connection without a running relay
515 // But we can test that the client is created 515 // But we can test that the client is created
516 if let Ok(client) = result { 516 if let Ok(client) = result {
517 assert_eq!(client.config.mode, AuditMode::CI); 517 assert_eq!(client.config.mode, AuditMode::Isolated);
518 } 518 }
519 } 519 }
520 520
521 #[test] 521 #[test]
522 fn test_event_builder() { 522 fn test_event_builder() {
523 let config = AuditConfig::ci(); 523 let config = AuditConfig::isolated();
524 let keys = Keys::generate(); 524 let keys = Keys::generate();
525 let maintainer_keys = Keys::generate(); 525 let maintainer_keys = Keys::generate();
526 let recursive_maintainer_keys = Keys::generate(); 526 let recursive_maintainer_keys = Keys::generate();
@@ -543,7 +543,7 @@ mod tests {
543 543
544 #[test] 544 #[test]
545 fn test_audit_tags_automatically_added() { 545 fn test_audit_tags_automatically_added() {
546 let config = AuditConfig::ci(); 546 let config = AuditConfig::isolated();
547 let keys = Keys::generate(); 547 let keys = Keys::generate();
548 let maintainer_keys = Keys::generate(); 548 let maintainer_keys = Keys::generate();
549 let recursive_maintainer_keys = Keys::generate(); 549 let recursive_maintainer_keys = Keys::generate();
@@ -585,8 +585,8 @@ mod tests {
585 "Missing 'grasp-audit-test-event' tag" 585 "Missing 'grasp-audit-test-event' tag"
586 ); 586 );
587 assert!( 587 assert!(
588 tag_contents.iter().any(|t| t.starts_with("audit-ci-")), 588 tag_contents.iter().any(|t| t.starts_with("audit-isolated-")),
589 "Missing 'audit-ci-*' tag" 589 "Missing 'audit-isolated-*' tag"
590 ); 590 );
591 assert!( 591 assert!(
592 tag_contents 592 tag_contents
@@ -604,7 +604,7 @@ mod tests {
604 604
605 #[tokio::test] 605 #[tokio::test]
606 async fn test_create_repo_announcement_with_maintainers() { 606 async fn test_create_repo_announcement_with_maintainers() {
607 let config = AuditConfig::ci(); 607 let config = AuditConfig::isolated();
608 let client = AuditClient::new_test(config); 608 let client = AuditClient::new_test(config);
609 609
610 // Create test maintainer pubkeys (hex format) 610 // Create test maintainer pubkeys (hex format)
diff --git a/grasp-audit/src/fixtures.rs b/grasp-audit/src/fixtures.rs
index e5a80d7..cc2d2f6 100644
--- a/grasp-audit/src/fixtures.rs
+++ b/grasp-audit/src/fixtures.rs
@@ -3,19 +3,25 @@
3//! This module provides a TestContext abstraction that manages prerequisite events 3//! This module provides a TestContext abstraction that manages prerequisite events
4//! differently based on the audit mode: 4//! differently based on the audit mode:
5//! 5//!
6//! - **CI Mode (Isolated)**: Creates fresh events for each test, ensuring complete isolation 6//! - **Isolated Mode**: Creates fresh events for each test, ensuring complete isolation.
7//! - **Production Mode (Shared)**: Reuses shared fixtures to minimize event publication 7//! Use this for `cargo test` where tests run in parallel and need isolation.
8//! - **Shared Mode**: Reuses shared fixtures across tests to minimize event publication.
9//! Use this for CLI audit where tests run sequentially and build on each other.
8//! 10//!
9//! # Cache Sharing Strategy 11//! # Cache Sharing Strategy
10//! 12//!
11//! The fixture cache lives on the `AuditClient`, not on `TestContext`. This provides 13//! The caching behavior depends on the mode:
12//! natural cache sharing semantics:
13//! 14//!
14//! - **CLI mode**: Creates one `AuditClient` → fixtures shared across all tests 15//! - **Shared mode** (default for CLI): Uses the client's fixture cache, shared across
15//! - **cargo test**: Creates one `AuditClient` per test → fixtures isolated per test 16//! all TestContext instances. Fixtures are created once and reused.
17//! - **Isolated mode**: Each TestContext has its own local cache. Fixtures are created
18//! fresh for each TestContext, providing complete test isolation.
16//! 19//!
17//! This eliminates the need for global state while still enabling fixture reuse 20//! # When to Use Each Mode
18//! when appropriate. 21//!
22//! - **CLI audit tool**: Use Shared mode (default). Tests run sequentially and fixtures
23//! build on each other efficiently.
24//! - **cargo test**: Use Isolated mode. Tests run in parallel and need complete isolation.
19//! 25//!
20//! # What is a Fixture? 26//! # What is a Fixture?
21//! A fixture represents the state of a repository on a grasp server (events and git refs) 27//! A fixture represents the state of a repository on a grasp server (events and git refs)
@@ -36,7 +42,7 @@
36//! use grasp_audit::*; 42//! use grasp_audit::*;
37//! 43//!
38//! # async fn example() -> anyhow::Result<()> { 44//! # async fn example() -> anyhow::Result<()> {
39//! let config = AuditConfig::ci(); 45//! let config = AuditConfig::shared(); // Use shared() for CLI, isolated() for cargo test
40//! let client = AuditClient::new("ws://localhost:7000", config).await?; 46//! let client = AuditClient::new("ws://localhost:7000", config).await?;
41//! let ctx = TestContext::new(&client); 47//! let ctx = TestContext::new(&client);
42//! 48//!
@@ -341,8 +347,8 @@ pub enum ContextMode {
341impl From<AuditMode> for ContextMode { 347impl From<AuditMode> for ContextMode {
342 fn from(mode: AuditMode) -> Self { 348 fn from(mode: AuditMode) -> Self {
343 match mode { 349 match mode {
344 AuditMode::CI => ContextMode::Isolated, 350 AuditMode::Isolated => ContextMode::Isolated,
345 AuditMode::Production => ContextMode::Shared, 351 AuditMode::Shared => ContextMode::Shared,
346 } 352 }
347 } 353 }
348} 354}
@@ -350,30 +356,37 @@ impl From<AuditMode> for ContextMode {
350/// Test context for managing prerequisite events 356/// Test context for managing prerequisite events
351/// 357///
352/// The TestContext provides mode-aware fixture management: 358/// The TestContext provides mode-aware fixture management:
353/// - In Isolated mode: Creates fresh events for each test 359/// - In **Isolated mode**: Each TestContext has its own local cache, creating fresh
354/// - In Shared mode: Caches and reuses events across tests 360/// fixtures for each test. Use this for `cargo test` where tests run in parallel.
361/// - In **Shared mode**: Uses the client's fixture cache, shared across all TestContexts.
362/// Use this for CLI audit where tests run sequentially and build on each other.
355/// 363///
356/// # Cache Location 364/// # Mode Selection
357/// 365///
358/// The fixture cache lives on `AuditClient`, not on `TestContext`. This means: 366/// The mode is determined by `AuditConfig::mode`:
359/// - Multiple `TestContext` instances from the same client share the cache 367/// - `AuditConfig::isolated()` → Creates fresh fixtures per TestContext
360/// - CLI mode (one client) naturally shares fixtures across all tests 368/// - `AuditConfig::shared()` → Reuses fixtures across all TestContexts (default for CLI)
361/// - Test mode (one client per test) naturally isolates fixtures
362/// 369///
363/// # Example 370/// # Example
364/// 371///
365/// ```no_run 372/// ```no_run
366/// # use grasp_audit::*; 373/// # use grasp_audit::*;
367/// # async fn example() -> anyhow::Result<()> { 374/// # async fn example() -> anyhow::Result<()> {
368/// let config = AuditConfig::ci(); 375/// // For CLI audit (shared fixtures - default)
376/// let config = AuditConfig::shared();
369/// let client = AuditClient::new("ws://localhost:7000", config).await?; 377/// let client = AuditClient::new("ws://localhost:7000", config).await?;
370/// let ctx = TestContext::new(&client); 378/// let ctx = TestContext::new(&client);
371/// 379///
372/// // Get a repository fixture 380/// // Get a repository fixture - will be reused by subsequent TestContexts
373/// let repo = ctx.get_fixture(FixtureKind::ValidRepo).await?; 381/// let repo = ctx.get_fixture(FixtureKind::ValidRepo).await?;
374/// 382///
375/// // In CI mode: Creates new repo 383/// // For cargo test (isolated fixtures)
376/// // In Production mode: Returns cached repo 384/// let config = AuditConfig::isolated();
385/// let client = AuditClient::new("ws://localhost:7000", config).await?;
386/// let ctx = TestContext::new(&client);
387///
388/// // Get a repository fixture - fresh for this TestContext only
389/// let repo = ctx.get_fixture(FixtureKind::ValidRepo).await?;
377/// # Ok(()) 390/// # Ok(())
378/// # } 391/// # }
379/// ``` 392/// ```
@@ -1960,9 +1973,9 @@ mod tests {
1960 1973
1961 #[test] 1974 #[test]
1962 fn test_context_mode_from_audit_mode() { 1975 fn test_context_mode_from_audit_mode() {
1963 assert_eq!(ContextMode::from(AuditMode::CI), ContextMode::Isolated); 1976 assert_eq!(ContextMode::from(AuditMode::Isolated), ContextMode::Isolated);
1964 assert_eq!( 1977 assert_eq!(
1965 ContextMode::from(AuditMode::Production), 1978 ContextMode::from(AuditMode::Shared),
1966 ContextMode::Shared 1979 ContextMode::Shared
1967 ); 1980 );
1968 } 1981 }
@@ -1981,7 +1994,7 @@ mod tests {
1981 1994
1982 #[tokio::test] 1995 #[tokio::test]
1983 async fn test_context_creation() { 1996 async fn test_context_creation() {
1984 let config = AuditConfig::ci(); 1997 let config = AuditConfig::isolated();
1985 let client = crate::AuditClient::new_test(config); 1998 let client = crate::AuditClient::new_test(config);
1986 1999
1987 let ctx = TestContext::new(&client); 2000 let ctx = TestContext::new(&client);
diff --git a/grasp-audit/src/lib.rs b/grasp-audit/src/lib.rs
index 6df240f..655ee83 100644
--- a/grasp-audit/src/lib.rs
+++ b/grasp-audit/src/lib.rs
@@ -16,8 +16,8 @@
16//! 16//!
17//! #[tokio::main] 17//! #[tokio::main]
18//! async fn main() -> Result<(), Box<dyn std::error::Error>> { 18//! async fn main() -> Result<(), Box<dyn std::error::Error>> {
19//! // Create audit client for CI testing 19//! // Create audit client with shared fixtures (default for CLI)
20//! let config = AuditConfig::ci(); 20//! let config = AuditConfig::shared();
21//! let client = AuditClient::new("ws://localhost:7000", config).await?; 21//! let client = AuditClient::new("ws://localhost:7000", config).await?;
22//! 22//!
23//! // Run smoke tests 23//! // Run smoke tests
diff --git a/grasp-audit/src/specs/grasp01/cors.rs b/grasp-audit/src/specs/grasp01/cors.rs
index c877c04..409f2d3 100644
--- a/grasp-audit/src/specs/grasp01/cors.rs
+++ b/grasp-audit/src/specs/grasp01/cors.rs
@@ -459,7 +459,7 @@ mod tests {
459 .trim_end_matches('/') 459 .trim_end_matches('/')
460 .to_string(); 460 .to_string();
461 461
462 let config = AuditConfig::ci(); 462 let config = AuditConfig::isolated();
463 let client = AuditClient::new(&relay_url, config) 463 let client = AuditClient::new(&relay_url, config)
464 .await 464 .await
465 .unwrap_or_else(|_| { 465 .unwrap_or_else(|_| {
diff --git a/grasp-audit/src/specs/grasp01/event_acceptance_policy.rs b/grasp-audit/src/specs/grasp01/event_acceptance_policy.rs
index fee51db..89220ea 100644
--- a/grasp-audit/src/specs/grasp01/event_acceptance_policy.rs
+++ b/grasp-audit/src/specs/grasp01/event_acceptance_policy.rs
@@ -1139,7 +1139,7 @@ mod tests {
1139 "RELAY_URL environment variable must be set. Example: RELAY_URL=ws://localhost:18081", 1139 "RELAY_URL environment variable must be set. Example: RELAY_URL=ws://localhost:18081",
1140 ); 1140 );
1141 1141
1142 let config = AuditConfig::ci(); 1142 let config = AuditConfig::isolated();
1143 let client = AuditClient::new(&relay_url, config) 1143 let client = AuditClient::new(&relay_url, config)
1144 .await 1144 .await
1145 .unwrap_or_else(|_| { 1145 .unwrap_or_else(|_| {
diff --git a/grasp-audit/src/specs/grasp01/nip01_smoke.rs b/grasp-audit/src/specs/grasp01/nip01_smoke.rs
index 9a7d7d1..8a0a4d1 100644
--- a/grasp-audit/src/specs/grasp01/nip01_smoke.rs
+++ b/grasp-audit/src/specs/grasp01/nip01_smoke.rs
@@ -297,7 +297,7 @@ mod tests {
297 let relay_url = std::env::var("RELAY_URL") 297 let relay_url = std::env::var("RELAY_URL")
298 .expect("RELAY_URL environment variable must be set for integration tests"); 298 .expect("RELAY_URL environment variable must be set for integration tests");
299 299
300 let config = AuditConfig::ci(); 300 let config = AuditConfig::isolated();
301 let client = AuditClient::new(&relay_url, config) 301 let client = AuditClient::new(&relay_url, config)
302 .await 302 .await
303 .expect("Failed to connect to relay"); 303 .expect("Failed to connect to relay");
diff --git a/grasp-audit/src/specs/grasp01/nip11_document.rs b/grasp-audit/src/specs/grasp01/nip11_document.rs
index 33599b1..f4ca7b4 100644
--- a/grasp-audit/src/specs/grasp01/nip11_document.rs
+++ b/grasp-audit/src/specs/grasp01/nip11_document.rs
@@ -288,7 +288,7 @@ mod tests {
288 "RELAY_URL environment variable must be set. Example: RELAY_URL=ws://localhost:18081", 288 "RELAY_URL environment variable must be set. Example: RELAY_URL=ws://localhost:18081",
289 ); 289 );
290 290
291 let config = AuditConfig::ci(); 291 let config = AuditConfig::isolated();
292 let client = AuditClient::new(&relay_url, config) 292 let client = AuditClient::new(&relay_url, config)
293 .await 293 .await
294 .unwrap_or_else(|_| { 294 .unwrap_or_else(|_| {
diff --git a/grasp-audit/src/specs/grasp01/spec_requirements.rs b/grasp-audit/src/specs/grasp01/spec_requirements.rs
index 591fef1..9a833d8 100644
--- a/grasp-audit/src/specs/grasp01/spec_requirements.rs
+++ b/grasp-audit/src/specs/grasp01/spec_requirements.rs
@@ -206,4 +206,4 @@ mod tests {
206 fn test_requirement_count() { 206 fn test_requirement_count() {
207 assert_eq!(GRASP_01_REQUIREMENTS.len(), 19); 207 assert_eq!(GRASP_01_REQUIREMENTS.len(), 19);
208 } 208 }
209} \ No newline at end of file 209}