diff options
| author | DanConwayDev <DanConwayDev@protonmail.com> | 2025-11-19 17:01:36 +0000 |
|---|---|---|
| committer | DanConwayDev <DanConwayDev@protonmail.com> | 2025-11-19 17:01:36 +0000 |
| commit | bf7f4d5381203d5c27b2811d62c5b1781533aa2b (patch) | |
| tree | 26903bbf535d83abd7242370d8b6932eb80e3389 /grasp-audit/src/fixtures.rs | |
| parent | fa065ad128882755f2a988d6203b59a2ab5e38ff (diff) | |
fix some clippy fmt warnings
Diffstat (limited to 'grasp-audit/src/fixtures.rs')
| -rw-r--r-- | grasp-audit/src/fixtures.rs | 162 |
1 files changed, 95 insertions, 67 deletions
diff --git a/grasp-audit/src/fixtures.rs b/grasp-audit/src/fixtures.rs index 71d64d3..8eee81f 100644 --- a/grasp-audit/src/fixtures.rs +++ b/grasp-audit/src/fixtures.rs | |||
| @@ -33,13 +33,13 @@ use std::sync::{Arc, Mutex}; | |||
| 33 | pub enum FixtureKind { | 33 | pub enum FixtureKind { |
| 34 | /// Basic repository announcement (kind 30617) | 34 | /// Basic repository announcement (kind 30617) |
| 35 | ValidRepo, | 35 | ValidRepo, |
| 36 | 36 | ||
| 37 | /// Repository with one issue (kind 1621) | 37 | /// Repository with one issue (kind 1621) |
| 38 | RepoWithIssue, | 38 | RepoWithIssue, |
| 39 | 39 | ||
| 40 | /// Repository with issue and comment (kind 1111) | 40 | /// Repository with issue and comment (kind 1111) |
| 41 | RepoWithComment, | 41 | RepoWithComment, |
| 42 | 42 | ||
| 43 | /// Repository state announcement (kind 30618) | 43 | /// Repository state announcement (kind 30618) |
| 44 | RepoState, | 44 | RepoState, |
| 45 | } | 45 | } |
| @@ -49,7 +49,7 @@ pub enum FixtureKind { | |||
| 49 | pub enum ContextMode { | 49 | pub enum ContextMode { |
| 50 | /// Create fresh fixtures for each request (test isolation) | 50 | /// Create fresh fixtures for each request (test isolation) |
| 51 | Isolated, | 51 | Isolated, |
| 52 | 52 | ||
| 53 | /// Reuse shared fixtures across requests (minimal events) | 53 | /// Reuse shared fixtures across requests (minimal events) |
| 54 | Shared, | 54 | Shared, |
| 55 | } | 55 | } |
| @@ -104,7 +104,7 @@ impl<'a> TestContext<'a> { | |||
| 104 | cache: Arc::new(Mutex::new(HashMap::new())), | 104 | cache: Arc::new(Mutex::new(HashMap::new())), |
| 105 | } | 105 | } |
| 106 | } | 106 | } |
| 107 | 107 | ||
| 108 | /// Create a test context with explicit mode override | 108 | /// Create a test context with explicit mode override |
| 109 | /// | 109 | /// |
| 110 | /// This is useful for testing the context itself or for advanced use cases | 110 | /// This is useful for testing the context itself or for advanced use cases |
| @@ -116,7 +116,7 @@ impl<'a> TestContext<'a> { | |||
| 116 | cache: Arc::new(Mutex::new(HashMap::new())), | 116 | cache: Arc::new(Mutex::new(HashMap::new())), |
| 117 | } | 117 | } |
| 118 | } | 118 | } |
| 119 | 119 | ||
| 120 | /// Get a fixture, creating it if needed based on mode | 120 | /// Get a fixture, creating it if needed based on mode |
| 121 | /// | 121 | /// |
| 122 | /// # Behavior | 122 | /// # Behavior |
| @@ -139,7 +139,7 @@ impl<'a> TestContext<'a> { | |||
| 139 | ContextMode::Shared => self.get_or_create_shared(kind).await, | 139 | ContextMode::Shared => self.get_or_create_shared(kind).await, |
| 140 | } | 140 | } |
| 141 | } | 141 | } |
| 142 | 142 | ||
| 143 | /// Get the underlying client for direct access | 143 | /// Get the underlying client for direct access |
| 144 | /// | 144 | /// |
| 145 | /// This allows tests to use the client directly when needed while still | 145 | /// This allows tests to use the client directly when needed while still |
| @@ -147,23 +147,27 @@ impl<'a> TestContext<'a> { | |||
| 147 | pub fn client(&self) -> &'a AuditClient { | 147 | pub fn client(&self) -> &'a AuditClient { |
| 148 | self.client | 148 | self.client |
| 149 | } | 149 | } |
| 150 | 150 | ||
| 151 | /// Get the current context mode | 151 | /// Get the current context mode |
| 152 | pub fn mode(&self) -> ContextMode { | 152 | pub fn mode(&self) -> ContextMode { |
| 153 | self.mode | 153 | self.mode |
| 154 | } | 154 | } |
| 155 | 155 | ||
| 156 | /// Create a fresh fixture (always creates new) | 156 | /// Create a fresh fixture (always creates new) |
| 157 | async fn create_fresh(&self, kind: FixtureKind) -> Result<Event> { | 157 | async fn create_fresh(&self, kind: FixtureKind) -> Result<Event> { |
| 158 | let event = self.build_fixture(kind).await | 158 | let event = self |
| 159 | .build_fixture(kind) | ||
| 160 | .await | ||
| 159 | .with_context(|| format!("Failed to build {:?} fixture", kind))?; | 161 | .with_context(|| format!("Failed to build {:?} fixture", kind))?; |
| 160 | 162 | ||
| 161 | self.client.send_event(event.clone()).await | 163 | self.client |
| 164 | .send_event(event.clone()) | ||
| 165 | .await | ||
| 162 | .with_context(|| format!("Failed to send {:?} fixture event to relay", kind))?; | 166 | .with_context(|| format!("Failed to send {:?} fixture event to relay", kind))?; |
| 163 | 167 | ||
| 164 | Ok(event) | 168 | Ok(event) |
| 165 | } | 169 | } |
| 166 | 170 | ||
| 167 | /// Get or create a shared fixture (caches for reuse) | 171 | /// Get or create a shared fixture (caches for reuse) |
| 168 | async fn get_or_create_shared(&self, kind: FixtureKind) -> Result<Event> { | 172 | async fn get_or_create_shared(&self, kind: FixtureKind) -> Result<Event> { |
| 169 | // Check cache first | 173 | // Check cache first |
| @@ -173,39 +177,54 @@ impl<'a> TestContext<'a> { | |||
| 173 | return Ok(event.clone()); | 177 | return Ok(event.clone()); |
| 174 | } | 178 | } |
| 175 | } | 179 | } |
| 176 | 180 | ||
| 177 | // Not in cache, create it | 181 | // Not in cache, create it |
| 178 | let event = self.build_fixture(kind).await | 182 | let event = self |
| 183 | .build_fixture(kind) | ||
| 184 | .await | ||
| 179 | .with_context(|| format!("Failed to build {:?} fixture for shared cache", kind))?; | 185 | .with_context(|| format!("Failed to build {:?} fixture for shared cache", kind))?; |
| 180 | 186 | ||
| 181 | self.client.send_event(event.clone()).await | 187 | self.client |
| 182 | .with_context(|| format!("Failed to send {:?} fixture event to relay (shared cache)", kind))?; | 188 | .send_event(event.clone()) |
| 183 | 189 | .await | |
| 190 | .with_context(|| { | ||
| 191 | format!( | ||
| 192 | "Failed to send {:?} fixture event to relay (shared cache)", | ||
| 193 | kind | ||
| 194 | ) | ||
| 195 | })?; | ||
| 196 | |||
| 184 | // Store in cache | 197 | // Store in cache |
| 185 | { | 198 | { |
| 186 | let mut cache = self.cache.lock().unwrap(); | 199 | let mut cache = self.cache.lock().unwrap(); |
| 187 | cache.insert(kind, event.clone()); | 200 | cache.insert(kind, event.clone()); |
| 188 | } | 201 | } |
| 189 | 202 | ||
| 190 | Ok(event) | 203 | Ok(event) |
| 191 | } | 204 | } |
| 192 | 205 | ||
| 193 | /// Build a fixture event (doesn't send it) | 206 | /// Build a fixture event (doesn't send it) |
| 194 | async fn build_fixture(&self, kind: FixtureKind) -> Result<Event> { | 207 | async fn build_fixture(&self, kind: FixtureKind) -> Result<Event> { |
| 195 | match kind { | 208 | match kind { |
| 196 | FixtureKind::ValidRepo => { | 209 | FixtureKind::ValidRepo => { |
| 197 | let test_name = format!("fixture-{:?}-{}", kind, &uuid::Uuid::new_v4().to_string()[..8]); | 210 | let test_name = format!( |
| 211 | "fixture-{:?}-{}", | ||
| 212 | kind, | ||
| 213 | &uuid::Uuid::new_v4().to_string()[..8] | ||
| 214 | ); | ||
| 198 | self.client.create_repo_announcement(&test_name).await | 215 | self.client.create_repo_announcement(&test_name).await |
| 199 | } | 216 | } |
| 200 | 217 | ||
| 201 | FixtureKind::RepoWithIssue => { | 218 | FixtureKind::RepoWithIssue => { |
| 202 | use nostr_sdk::prelude::*; | ||
| 203 | |||
| 204 | // First create and send repo | 219 | // First create and send repo |
| 205 | let test_name = format!("fixture-{:?}-{}", FixtureKind::ValidRepo, &uuid::Uuid::new_v4().to_string()[..8]); | 220 | let test_name = format!( |
| 221 | "fixture-{:?}-{}", | ||
| 222 | FixtureKind::ValidRepo, | ||
| 223 | &uuid::Uuid::new_v4().to_string()[..8] | ||
| 224 | ); | ||
| 206 | let repo = self.client.create_repo_announcement(&test_name).await?; | 225 | let repo = self.client.create_repo_announcement(&test_name).await?; |
| 207 | self.client.send_event(repo.clone()).await?; | 226 | self.client.send_event(repo.clone()).await?; |
| 208 | 227 | ||
| 209 | // Then create issue referencing it - this will have 'a' tag to repo | 228 | // Then create issue referencing it - this will have 'a' tag to repo |
| 210 | // Note: We build the issue but DON'T send it here - the caller will send it | 229 | // Note: We build the issue but DON'T send it here - the caller will send it |
| 211 | let issue = self.client.create_issue( | 230 | let issue = self.client.create_issue( |
| @@ -214,64 +233,70 @@ impl<'a> TestContext<'a> { | |||
| 214 | "Issue content for testing", | 233 | "Issue content for testing", |
| 215 | vec![], | 234 | vec![], |
| 216 | )?; | 235 | )?; |
| 217 | 236 | ||
| 218 | // Return the issue - tests can extract repo reference from its 'a' tag | 237 | // Return the issue - tests can extract repo reference from its 'a' tag |
| 219 | // The caller (create_fresh/get_or_create_shared) will send this event | 238 | // The caller (create_fresh/get_or_create_shared) will send this event |
| 220 | Ok(issue) | 239 | Ok(issue) |
| 221 | } | 240 | } |
| 222 | 241 | ||
| 223 | FixtureKind::RepoWithComment => { | 242 | FixtureKind::RepoWithComment => { |
| 224 | // First create repo with issue | 243 | // First create repo with issue |
| 225 | let test_name = format!("fixture-{:?}-{}", FixtureKind::ValidRepo, &uuid::Uuid::new_v4().to_string()[..8]); | 244 | let test_name = format!( |
| 245 | "fixture-{:?}-{}", | ||
| 246 | FixtureKind::ValidRepo, | ||
| 247 | &uuid::Uuid::new_v4().to_string()[..8] | ||
| 248 | ); | ||
| 226 | let repo = self.client.create_repo_announcement(&test_name).await?; | 249 | let repo = self.client.create_repo_announcement(&test_name).await?; |
| 227 | self.client.send_event(repo.clone()).await?; | 250 | self.client.send_event(repo.clone()).await?; |
| 228 | 251 | ||
| 229 | let issue = self.client.create_issue( | 252 | let issue = |
| 230 | &repo, | 253 | self.client |
| 231 | "Test Issue", | 254 | .create_issue(&repo, "Test Issue", "Issue content", vec![])?; |
| 232 | "Issue content", | ||
| 233 | vec![], | ||
| 234 | )?; | ||
| 235 | self.client.send_event(issue.clone()).await?; | 255 | self.client.send_event(issue.clone()).await?; |
| 236 | 256 | ||
| 237 | // Then create comment on issue | 257 | // Then create comment on issue |
| 238 | self.client.create_comment( | 258 | self.client.create_comment(&issue, "Test comment", vec![]) |
| 239 | &issue, | ||
| 240 | "Test comment", | ||
| 241 | vec![], | ||
| 242 | ) | ||
| 243 | } | 259 | } |
| 244 | 260 | ||
| 245 | FixtureKind::RepoState => { | 261 | FixtureKind::RepoState => { |
| 246 | use nostr_sdk::prelude::*; | 262 | use nostr_sdk::prelude::*; |
| 247 | 263 | ||
| 248 | // First create repo announcement | 264 | // First create repo announcement |
| 249 | let test_name = format!("fixture-{:?}-{}", FixtureKind::ValidRepo, &uuid::Uuid::new_v4().to_string()[..8]); | 265 | let test_name = format!( |
| 266 | "fixture-{:?}-{}", | ||
| 267 | FixtureKind::ValidRepo, | ||
| 268 | &uuid::Uuid::new_v4().to_string()[..8] | ||
| 269 | ); | ||
| 250 | let repo = self.client.create_repo_announcement(&test_name).await?; | 270 | let repo = self.client.create_repo_announcement(&test_name).await?; |
| 251 | self.client.send_event(repo.clone()).await?; | 271 | self.client.send_event(repo.clone()).await?; |
| 252 | 272 | ||
| 253 | // Extract repo_id from repo announcement | 273 | // Extract repo_id from repo announcement |
| 254 | let repo_id = repo.tags.iter() | 274 | let repo_id = repo |
| 275 | .tags | ||
| 276 | .iter() | ||
| 255 | .find(|t| t.kind() == TagKind::d()) | 277 | .find(|t| t.kind() == TagKind::d()) |
| 256 | .and_then(|t| t.content()) | 278 | .and_then(|t| t.content()) |
| 257 | .ok_or_else(|| anyhow::anyhow!("Missing d tag in repo announcement"))? | 279 | .ok_or_else(|| anyhow::anyhow!("Missing d tag in repo announcement"))? |
| 258 | .to_string(); | 280 | .to_string(); |
| 259 | 281 | ||
| 260 | // Create state announcement | 282 | // Create state announcement |
| 261 | self.client.event_builder(Kind::Custom(30618), "") | 283 | self.client |
| 284 | .event_builder(Kind::Custom(30618), "") | ||
| 262 | .tag(Tag::identifier(&repo_id)) | 285 | .tag(Tag::identifier(&repo_id)) |
| 263 | .tag(Tag::custom(TagKind::custom("refs/heads/main"), vec![ | 286 | .tag(Tag::custom( |
| 264 | "abc123def456789012345678901234567890abcd" | 287 | TagKind::custom("refs/heads/main"), |
| 265 | ])) | 288 | vec!["abc123def456789012345678901234567890abcd"], |
| 266 | .tag(Tag::custom(TagKind::custom("HEAD"), vec![ | 289 | )) |
| 267 | "ref: refs/heads/main" | 290 | .tag(Tag::custom( |
| 268 | ])) | 291 | TagKind::custom("HEAD"), |
| 292 | vec!["ref: refs/heads/main"], | ||
| 293 | )) | ||
| 269 | .build(self.client.keys()) | 294 | .build(self.client.keys()) |
| 270 | .map_err(|e| anyhow::anyhow!("Failed to build state announcement: {}", e)) | 295 | .map_err(|e| anyhow::anyhow!("Failed to build state announcement: {}", e)) |
| 271 | } | 296 | } |
| 272 | } | 297 | } |
| 273 | } | 298 | } |
| 274 | 299 | ||
| 275 | /// Clear the fixture cache | 300 | /// Clear the fixture cache |
| 276 | /// | 301 | /// |
| 277 | /// This is useful for tests that want to ensure fresh fixtures | 302 | /// This is useful for tests that want to ensure fresh fixtures |
| @@ -286,34 +311,37 @@ impl<'a> TestContext<'a> { | |||
| 286 | mod tests { | 311 | mod tests { |
| 287 | use super::*; | 312 | use super::*; |
| 288 | use crate::AuditConfig; | 313 | use crate::AuditConfig; |
| 289 | 314 | ||
| 290 | #[test] | 315 | #[test] |
| 291 | fn test_context_mode_from_audit_mode() { | 316 | fn test_context_mode_from_audit_mode() { |
| 292 | assert_eq!(ContextMode::from(AuditMode::CI), ContextMode::Isolated); | 317 | assert_eq!(ContextMode::from(AuditMode::CI), ContextMode::Isolated); |
| 293 | assert_eq!(ContextMode::from(AuditMode::Production), ContextMode::Shared); | 318 | assert_eq!( |
| 319 | ContextMode::from(AuditMode::Production), | ||
| 320 | ContextMode::Shared | ||
| 321 | ); | ||
| 294 | } | 322 | } |
| 295 | 323 | ||
| 296 | #[test] | 324 | #[test] |
| 297 | fn test_fixture_kind_hash() { | 325 | fn test_fixture_kind_hash() { |
| 298 | use std::collections::HashSet; | 326 | use std::collections::HashSet; |
| 299 | 327 | ||
| 300 | let mut set = HashSet::new(); | 328 | let mut set = HashSet::new(); |
| 301 | set.insert(FixtureKind::ValidRepo); | 329 | set.insert(FixtureKind::ValidRepo); |
| 302 | set.insert(FixtureKind::RepoWithIssue); | 330 | set.insert(FixtureKind::RepoWithIssue); |
| 303 | 331 | ||
| 304 | assert!(set.contains(&FixtureKind::ValidRepo)); | 332 | assert!(set.contains(&FixtureKind::ValidRepo)); |
| 305 | assert!(!set.contains(&FixtureKind::RepoWithComment)); | 333 | assert!(!set.contains(&FixtureKind::RepoWithComment)); |
| 306 | } | 334 | } |
| 307 | 335 | ||
| 308 | #[tokio::test] | 336 | #[tokio::test] |
| 309 | async fn test_context_creation() { | 337 | async fn test_context_creation() { |
| 310 | let config = AuditConfig::ci(); | 338 | let config = AuditConfig::ci(); |
| 311 | let client = crate::AuditClient::new_test(config); | 339 | let client = crate::AuditClient::new_test(config); |
| 312 | 340 | ||
| 313 | let ctx = TestContext::new(&client); | 341 | let ctx = TestContext::new(&client); |
| 314 | assert_eq!(ctx.mode(), ContextMode::Isolated); | 342 | assert_eq!(ctx.mode(), ContextMode::Isolated); |
| 315 | 343 | ||
| 316 | let ctx = TestContext::with_mode(&client, ContextMode::Shared); | 344 | let ctx = TestContext::with_mode(&client, ContextMode::Shared); |
| 317 | assert_eq!(ctx.mode(), ContextMode::Shared); | 345 | assert_eq!(ctx.mode(), ContextMode::Shared); |
| 318 | } | 346 | } |
| 319 | } \ No newline at end of file | 347 | } |