upleb.uk

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

summaryrefslogtreecommitdiff
path: root/grasp-audit/src/fixtures.rs
diff options
context:
space:
mode:
authorDanConwayDev <DanConwayDev@protonmail.com>2025-11-19 17:01:36 +0000
committerDanConwayDev <DanConwayDev@protonmail.com>2025-11-19 17:01:36 +0000
commitbf7f4d5381203d5c27b2811d62c5b1781533aa2b (patch)
tree26903bbf535d83abd7242370d8b6932eb80e3389 /grasp-audit/src/fixtures.rs
parentfa065ad128882755f2a988d6203b59a2ab5e38ff (diff)
fix some clippy fmt warnings
Diffstat (limited to 'grasp-audit/src/fixtures.rs')
-rw-r--r--grasp-audit/src/fixtures.rs162
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};
33pub enum FixtureKind { 33pub 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 {
49pub enum ContextMode { 49pub 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> {
286mod tests { 311mod 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}