upleb.uk

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

summaryrefslogtreecommitdiff
path: root/tests
diff options
context:
space:
mode:
authorDanConwayDev <DanConwayDev@protonmail.com>2025-11-20 22:15:03 +0000
committerDanConwayDev <DanConwayDev@protonmail.com>2025-11-20 22:20:28 +0000
commit519fdc66930280cd1772417dca327ed858333d64 (patch)
tree4b20e18ccbc7406106bc72316dc3e26f2b58495f /tests
parentca50f5b98f30d0933a510c05db86b608afee73a0 (diff)
refactor: isolate each grasp-audit lib test with minimal boilerplate
- Add isolated_test! macro pattern to nip34_announcements.rs and nip01_compliance.rs - Each test runs with its own fresh relay instance for complete isolation - Make all individual test functions public in grasp-audit library (nip01_smoke.rs, event_acceptance_policy.rs) - Eliminates 122 lines of boilerplate across integration tests - Tests: 15 GRASP-01 event acceptance policy tests + 6 NIP-01 smoke tests - Ensures tests don't interfere with each other, preventing flakiness
Diffstat (limited to 'tests')
-rw-r--r--tests/nip01_compliance.rs120
-rw-r--r--tests/nip34_announcements.rs168
2 files changed, 83 insertions, 205 deletions
diff --git a/tests/nip01_compliance.rs b/tests/nip01_compliance.rs
index 4cb2af4..6fb721a 100644
--- a/tests/nip01_compliance.rs
+++ b/tests/nip01_compliance.rs
@@ -1,13 +1,13 @@
1//! NIP-01 Compliance Integration Tests 1//! NIP-01 Compliance Integration Tests
2//! 2//!
3//! Tests ngit-grasp relay's NIP-01 compliance using grasp-audit library. 3//! Tests ngit-grasp relay's NIP-01 compliance using grasp-audit library.
4//! Avoids code duplication by delegating to grasp-audit's test suite. 4//! Uses isolated test pattern for complete test independence.
5//! 5//!
6//! # Test Strategy 6//! # Test Strategy
7//! 7//!
8//! - Uses TestRelay fixture for ngit-grasp relay lifecycle management 8//! - Each test runs in complete isolation with its own fresh relay instance
9//! - Uses grasp-audit's Nip01SmokeTests for actual test logic 9//! - Uses macro to eliminate boilerplate while maintaining test isolation
10//! - Minimal duplication - single source of truth in grasp-audit 10//! - Calls individual test methods from grasp-audit for minimal duplication
11//! 11//!
12//! # Running Tests 12//! # Running Tests
13//! 13//!
@@ -16,7 +16,7 @@
16//! cargo test --test nip01_compliance 16//! cargo test --test nip01_compliance
17//! 17//!
18//! # Run specific test 18//! # Run specific test
19//! cargo test --test nip01_compliance test_nip01_smoke 19//! cargo test --test nip01_compliance test_websocket_connection
20//! 20//!
21//! # With output 21//! # With output
22//! cargo test --test nip01_compliance -- --nocapture 22//! cargo test --test nip01_compliance -- --nocapture
@@ -27,87 +27,41 @@ mod common;
27use common::TestRelay; 27use common::TestRelay;
28use grasp_audit::*; 28use grasp_audit::*;
29 29
30/// Test NIP-01 smoke tests against ngit-grasp relay 30/// Macro to generate isolated integration tests
31/// 31///
32/// This test runs all NIP-01 smoke tests from grasp-audit against 32/// Each test runs with its own fresh relay instance to ensure complete isolation.
33/// the ngit-grasp relay implementation. 33/// This eliminates flakiness and ensures tests don't interfere with each other.
34/// 34macro_rules! isolated_test {
35/// Tests cover: 35 ($test_name:ident) => {
36/// - WebSocket connection 36 #[tokio::test]
37/// - Event send/receive 37 async fn $test_name() {
38/// - Subscriptions (REQ/CLOSE) 38 let relay = TestRelay::start().await;
39/// - Event validation (signature, ID) 39 let config = AuditConfig::ci();
40#[tokio::test] 40 let client = AuditClient::new(relay.url(), config)
41async fn test_nip01_smoke() { 41 .await
42 // Start test relay 42 .expect("Failed to create audit client");
43 let relay = TestRelay::start().await; 43
44 44 let result = specs::Nip01SmokeTests::$test_name(&client).await;
45 // Create audit client in CI mode (isolated testing) 45
46 let config = AuditConfig::ci(); 46 relay.stop().await;
47 let client = AuditClient::new(relay.url(), config) 47
48 .await 48 assert!(
49 .expect("Failed to create audit client"); 49 result.passed,
50 50 "{} failed: {}",
51 // Run all NIP-01 smoke tests 51 stringify!($test_name),
52 let results = specs::Nip01SmokeTests::run_all(&client).await; 52 result.error.as_deref().unwrap_or("unknown error")
53 53 );
54 // Print detailed report 54 }
55 results.print_report(); 55 };
56
57 // Stop relay
58 relay.stop().await;
59
60 // Assert all tests passed
61 assert!(
62 results.all_passed(),
63 "NIP-01 smoke tests failed: {}/{} passed",
64 results.passed_count(),
65 results.total_count()
66 );
67} 56}
68 57
69/// Test that relay properly validates events 58// Generate isolated tests for all NIP-01 smoke tests
70/// 59isolated_test!(test_websocket_connection);
71/// Critical security test - ensures relay validates: 60isolated_test!(test_send_receive_event);
72/// - Event signatures 61isolated_test!(test_create_subscription);
73/// - Event IDs 62isolated_test!(test_close_subscription);
74/// - Other NIP-01 requirements 63isolated_test!(test_reject_invalid_signature);
75#[tokio::test] 64isolated_test!(test_reject_invalid_event_id);
76async fn test_relay_validates_events() {
77 let relay = TestRelay::start().await;
78 let config = AuditConfig::ci();
79 let client = AuditClient::new(relay.url(), config)
80 .await
81 .expect("Failed to create audit client");
82
83 // Run smoke tests which include validation tests
84 let results = specs::Nip01SmokeTests::run_all(&client).await;
85
86 relay.stop().await;
87
88 // Filter to validation tests
89 let validation_tests: Vec<_> = results
90 .results
91 .iter()
92 .filter(|t| t.name.contains("reject") || t.name.contains("invalid"))
93 .collect();
94
95 // Should have validation tests
96 assert!(
97 !validation_tests.is_empty(),
98 "No validation tests found (these are critical for security)"
99 );
100
101 // All validation tests should pass
102 for test in validation_tests {
103 assert!(
104 test.passed,
105 "Validation test failed: {} - {}\nThis is a security issue!",
106 test.name,
107 test.error.as_deref().unwrap_or("unknown error")
108 );
109 }
110}
111 65
112/// Test relay lifecycle management 66/// Test relay lifecycle management
113/// 67///
diff --git a/tests/nip34_announcements.rs b/tests/nip34_announcements.rs
index f1cbd05..09d9c8f 100644
--- a/tests/nip34_announcements.rs
+++ b/tests/nip34_announcements.rs
@@ -5,9 +5,9 @@
5//! 5//!
6//! # Test Strategy 6//! # Test Strategy
7//! 7//!
8//! - Uses TestRelay fixture for ngit-grasp relay lifecycle management 8//! - Each test runs in complete isolation with its own fresh relay instance
9//! - Uses grasp-audit's EventAcceptancePolicyTests for actual test logic 9//! - Uses macro to eliminate boilerplate while maintaining test isolation
10//! - Minimal duplication - single source of truth in grasp-audit 10//! - Calls individual test methods from grasp-audit for minimal duplication
11//! 11//!
12//! # Running Tests 12//! # Running Tests
13//! 13//!
@@ -16,7 +16,7 @@
16//! cargo test --test nip34_announcements 16//! cargo test --test nip34_announcements
17//! 17//!
18//! # Run specific test 18//! # Run specific test
19//! cargo test --test nip34_announcements test_grasp01_event_acceptance 19//! cargo test --test nip34_announcements test_reject_orphan_kind1
20//! 20//!
21//! # With output 21//! # With output
22//! cargo test --test nip34_announcements -- --nocapture 22//! cargo test --test nip34_announcements -- --nocapture
@@ -27,124 +27,48 @@ mod common;
27use common::TestRelay; 27use common::TestRelay;
28use grasp_audit::*; 28use grasp_audit::*;
29 29
30/// Test GRASP-01 event acceptance policy against ngit-grasp relay 30/// Macro to generate isolated integration tests
31/// 31///
32/// This test runs all GRASP-01 event acceptance policy tests from grasp-audit 32/// Each test runs with its own fresh relay instance to ensure complete isolation.
33/// against the ngit-grasp relay implementation. 33/// This eliminates rate-limiting issues and ensures tests don't interfere with each other.
34/// 34macro_rules! isolated_test {
35/// Tests cover: 35 ($test_name:ident) => {
36/// - Repository announcement acceptance/rejection 36 #[tokio::test]
37/// - Repository state announcement acceptance 37 async fn $test_name() {
38/// - Events tagging accepted repositories 38 let relay = TestRelay::start().await;
39/// - Transitive event acceptance (events tagging accepted events) 39 let config = AuditConfig::ci();
40/// - Forward reference acceptance (events tagged by accepted events) 40 let client = AuditClient::new(relay.url(), config)
41/// - Rejection of unrelated events 41 .await
42#[tokio::test] 42 .expect("Failed to create audit client");
43async fn test_grasp01_event_acceptance() { 43
44 // Start test relay 44 let result = specs::EventAcceptancePolicyTests::$test_name(&client).await;
45 let relay = TestRelay::start().await; 45
46 46 relay.stop().await;
47 // Create audit client in CI mode (isolated testing) 47
48 let config = AuditConfig::ci(); 48 assert!(
49 let client = AuditClient::new(relay.url(), config) 49 result.passed,
50 .await 50 "{} failed: {}",
51 .expect("Failed to create audit client"); 51 stringify!($test_name),
52 52 result.error.as_deref().unwrap_or("unknown error")
53 // Run all GRASP-01 event acceptance policy tests 53 );
54 let results = specs::EventAcceptancePolicyTests::run_all(&client).await; 54 }
55 55 };
56 // Print detailed report
57 results.print_report();
58
59 // Stop relay
60 relay.stop().await;
61
62 // Assert all tests passed
63 assert!(
64 results.all_passed(),
65 "GRASP-01 event acceptance tests failed: {}/{} passed",
66 results.passed_count(),
67 results.total_count()
68 );
69} 56}
70 57
71/// Test that relay accepts valid repository announcements 58// Generate isolated tests for all GRASP-01 event acceptance policy tests
72/// 59isolated_test!(test_accept_valid_repo_announcement);
73/// Demonstrates running individual test categories from the suite 60isolated_test!(test_reject_repo_announcement_missing_clone_tag);
74#[tokio::test] 61isolated_test!(test_reject_repo_announcement_missing_relays_tag);
75async fn test_accepts_repository_announcements() { 62isolated_test!(test_accept_valid_repo_state_announcement);
76 let relay = TestRelay::start().await; 63isolated_test!(test_accept_issue_via_a_tag);
77 let config = AuditConfig::ci(); 64isolated_test!(test_accept_comment_via_capital_a_tag);
78 let client = AuditClient::new(relay.url(), config) 65isolated_test!(test_accept_kind1_via_q_tag);
79 .await 66isolated_test!(test_accept_issue_quoting_issue_via_q);
80 .expect("Failed to create audit client"); 67isolated_test!(test_accept_comment_via_capital_e_tag);
81 68isolated_test!(test_accept_kind1_via_e_tag);
82 // Run all tests 69isolated_test!(test_accept_kind1_referenced_in_issue);
83 let results = specs::EventAcceptancePolicyTests::run_all(&client).await; 70isolated_test!(test_accept_comment_referenced_in_comment);
84 71isolated_test!(test_accept_kind1_referenced_in_kind1);
85 relay.stop().await; 72isolated_test!(test_reject_orphan_issue);
86 73isolated_test!(test_reject_orphan_kind1);
87 // Filter to only repository announcement tests 74isolated_test!(test_reject_comment_quoting_other_repo); \ No newline at end of file
88 let announcement_tests: Vec<_> = results
89 .results
90 .iter()
91 .filter(|t| {
92 t.spec_ref.contains("repo") || t.name.contains("announcement") || t.name.contains("state")
93 })
94 .collect();
95
96 // Verify we have announcement tests
97 assert!(
98 !announcement_tests.is_empty(),
99 "No repository announcement tests found"
100 );
101
102 // All should pass
103 for test in announcement_tests {
104 assert!(
105 test.passed,
106 "Repository test failed: {} - {}",
107 test.name,
108 test.error.as_deref().unwrap_or("unknown error")
109 );
110 }
111}
112
113/// Test that relay properly validates clone and relays tags
114///
115/// This is a critical security requirement for GRASP-01
116#[tokio::test]
117async fn test_validates_service_tags() {
118 let relay = TestRelay::start().await;
119 let config = AuditConfig::ci();
120 let client = AuditClient::new(relay.url(), config)
121 .await
122 .expect("Failed to create audit client");
123
124 let results = specs::EventAcceptancePolicyTests::run_all(&client).await;
125
126 relay.stop().await;
127
128 // Filter to rejection tests (these verify tag validation)
129 let rejection_tests: Vec<_> = results
130 .results
131 .iter()
132 .filter(|t| t.name.contains("reject"))
133 .collect();
134
135 // Should have rejection tests
136 assert!(
137 !rejection_tests.is_empty(),
138 "No rejection tests found (these are critical for security)"
139 );
140
141 // All rejection tests should pass
142 for test in rejection_tests {
143 assert!(
144 test.passed,
145 "Rejection test failed: {} - {}\nThis is a security issue!",
146 test.name,
147 test.error.as_deref().unwrap_or("unknown error")
148 );
149 }
150}