From d9c9ef2ff92b687f5ff5585b08b2eead8f139a02 Mon Sep 17 00:00:00 2001 From: DanConwayDev Date: Wed, 5 Nov 2025 11:48:35 +0000 Subject: feat(grasp-audit): improve test infrastructure and error handling - Fix compilation error in test setup (use .expect() instead of ?) - Add comprehensive error messages with troubleshooting guidance - Implement connection verification in AuditClient with retry logic - Update AGENTS.md with testing troubleshooting section - Verify all changes: 4/18 tests passing as expected Error messages now include: - Specific context about failures (event IDs, repo IDs, URLs) - Example commands for resolution (docker, nak verification) - References to helper scripts (test-ngit-relay.sh) Tests compile cleanly and run successfully against ngit-relay. --- grasp-audit/src/client.rs | 22 +++++++++++- grasp-audit/src/specs/grasp01_nostr_relay.rs | 53 ++++++++++++++++++---------- 2 files changed, 55 insertions(+), 20 deletions(-) (limited to 'grasp-audit/src') diff --git a/grasp-audit/src/client.rs b/grasp-audit/src/client.rs index 4831d3f..b80b59f 100644 --- a/grasp-audit/src/client.rs +++ b/grasp-audit/src/client.rs @@ -24,11 +24,12 @@ impl AuditClient { // Wait for connection to establish (with retries) let mut attempts = 0; + let mut connected = false; while attempts < 20 { tokio::time::sleep(Duration::from_millis(100)).await; let relays = client.relays().await; - let connected = relays.values().any(|r| r.is_connected()); + connected = relays.values().any(|r| r.is_connected()); if connected { break; @@ -37,6 +38,25 @@ impl AuditClient { attempts += 1; } + // Verify we actually connected + if !connected { + return Err(anyhow!( + "Failed to connect to relay at '{}'\n\ + \n\ + Possible causes:\n\ + • Relay is not running at this address\n\ + • Network connectivity issues\n\ + • Incorrect URL or port\n\ + \n\ + To start ngit-relay for testing:\n\ + docker run --rm -p 18081:8081 ghcr.io/danconwaydev/ngit-relay:latest\n\ + \n\ + Or use the test script:\n\ + cd grasp-audit && ./test-ngit-relay.sh", + relay_url + )); + } + // Give it a bit more time to stabilize tokio::time::sleep(Duration::from_millis(200)).await; diff --git a/grasp-audit/src/specs/grasp01_nostr_relay.rs b/grasp-audit/src/specs/grasp01_nostr_relay.rs index 7c4ef1e..5a93672 100644 --- a/grasp-audit/src/specs/grasp01_nostr_relay.rs +++ b/grasp-audit/src/specs/grasp01_nostr_relay.rs @@ -82,7 +82,7 @@ impl Grasp01NostrRelayTests { // Get npub for clone URL let npub = client.public_key().to_bech32() - .map_err(|e| format!("Failed to convert pubkey to npub: {}", e))?; + .map_err(|e| format!("Failed to convert public key to bech32 npub format: {}", e))?; // Build kind 30617 repository announcement let event = client.event_builder(Kind::GitRepoAnnouncement, "") @@ -92,11 +92,11 @@ impl Grasp01NostrRelayTests { .tag(Tag::custom(TagKind::Custom("clone".into()), vec![format!("{}/{}/{}.git", http_url, npub, repo_id)])) .tag(Tag::custom(TagKind::Custom("relays".into()), vec![relay_url.clone()])) .build(client.keys()) - .map_err(|e| format!("Failed to build event: {}", e))?; + .map_err(|e| format!("Failed to build repository announcement event (kind 30617): {}", e))?; // Send the event let event_id = client.send_event(event.clone()).await - .map_err(|e| format!("Failed to send event: {}", e))?; + .map_err(|e| format!("Failed to send repository announcement to relay: {}", e))?; // Query back to verify it was accepted and stored let filter = Filter::new() @@ -105,17 +105,23 @@ impl Grasp01NostrRelayTests { .identifier(&repo_id); let events = client.query(filter).await - .map_err(|e| format!("Failed to query events: {}", e))?; + .map_err(|e| format!("Failed to query events from relay: {}", e))?; // Verify we got the event back if events.is_empty() { - return Err("Event was not stored in relay (possibly rejected)".to_string()); + return Err(format!( + "Event was not stored in relay (possibly rejected). Event ID: {}, Repo ID: {}", + event_id, repo_id + )); } // Verify it's the same event let stored_event = events.iter() .find(|e| e.id == event_id) - .ok_or("Stored event ID doesn't match sent event")?; + .ok_or(format!( + "Stored event ID doesn't match sent event. Expected: {}, Got {} events", + event_id, events.len() + ))?; // Verify key tags are present let has_clone_tag = stored_event.tags.iter() @@ -158,7 +164,7 @@ impl Grasp01NostrRelayTests { let relay_url = client.client().relays().await .keys() .next() - .ok_or("No relay connected")? + .ok_or("No relay connected - client has no active relay connections")? .to_string(); // Create unique repository identifier @@ -186,11 +192,15 @@ impl Grasp01NostrRelayTests { .identifier(&repo_id); let events = client.query(filter).await - .map_err(|e| format!("Failed to query events: {}", e))?; + .map_err(|e| format!("Failed to query events from relay: {}", e))?; // Verify event was rejected (not stored) if events.iter().any(|e| e.id == event_id) { - return Err("Relay accepted announcement without service in clone tag - should reject".to_string()); + return Err(format!( + "Relay incorrectly accepted announcement without service in clone tag. \ + Event ID: {}, Clone URL: https://github.com/user/repo.git (should require {})", + event_id, relay_url + )); } Ok(()) @@ -650,16 +660,21 @@ mod tests { use super::*; use crate::AuditConfig; - #[tokio::test] - #[ignore] // Requires running relay - async fn test_grasp01_nostr_relay_against_relay() { - // Read relay URL from environment variable - must be supplied - let relay_url = std::env::var("RELAY_URL")?; - - let config = AuditConfig::ci(); - let client = AuditClient::new(&relay_url, config) - .await - .expect("Failed to connect to relay"); +#[tokio::test] +#[ignore] // Requires running relay +async fn test_grasp01_nostr_relay_against_relay() { + // Read relay URL from environment variable - must be supplied + let relay_url = std::env::var("RELAY_URL") + .expect("RELAY_URL environment variable must be set. Example: RELAY_URL=ws://localhost:18081"); + + let config = AuditConfig::ci(); + let client = AuditClient::new(&relay_url, config) + .await + .expect(&format!( + "Failed to connect to relay at {}. Ensure relay is running and accessible. \ + Try: docker run --rm -p 18081:8081 ghcr.io/danconwaydev/ngit-relay:latest", + relay_url + )); let results = Grasp01NostrRelayTests::run_all(&client).await; results.print_report(); -- cgit v1.2.3