upleb.uk

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

summaryrefslogtreecommitdiff
path: root/grasp-audit/src/specs
diff options
context:
space:
mode:
authorDanConwayDev <DanConwayDev@protonmail.com>2025-11-28 03:50:51 +0000
committerDanConwayDev <DanConwayDev@protonmail.com>2025-11-28 03:50:51 +0000
commitb2a43ffbd965a2b561d7b4e4c582dfeadd099ed3 (patch)
tree39273494f7993f93b6ad8c5c2a726c37c9a7483f /grasp-audit/src/specs
parentf41550ea1898be2ec6c4be205e4cad0085400313 (diff)
test: rationalise repository creation tests
Diffstat (limited to 'grasp-audit/src/specs')
-rw-r--r--grasp-audit/src/specs/grasp01/repository_creation.rs155
1 files changed, 13 insertions, 142 deletions
diff --git a/grasp-audit/src/specs/grasp01/repository_creation.rs b/grasp-audit/src/specs/grasp01/repository_creation.rs
index 588187b..63b3dee 100644
--- a/grasp-audit/src/specs/grasp01/repository_creation.rs
+++ b/grasp-audit/src/specs/grasp01/repository_creation.rs
@@ -5,9 +5,9 @@
5//! 5//!
6//! ## Test Coverage 6//! ## Test Coverage
7//! 7//!
8//! - Repository creation on valid announcement (verified via HTTP) 8//! - Repository creation on valid announcement
9//! - Idempotent creation (no error if repo already exists) 9//! - Repository accessibility via Smart HTTP service (git-upload-pack)
10//! - Repository accessibility via Smart HTTP service 10//! - URL format: http://domain/npub/identifier.git
11//! 11//!
12//! ## Running Tests 12//! ## Running Tests
13//! 13//!
@@ -30,18 +30,18 @@ impl RepositoryCreationTests {
30 let mut results = crate::AuditResult::new("GRASP-01 Repository Creation Tests"); 30 let mut results = crate::AuditResult::new("GRASP-01 Repository Creation Tests");
31 31
32 results.add(Self::test_bare_repo_created_on_announcement(client, relay_domain).await); 32 results.add(Self::test_bare_repo_created_on_announcement(client, relay_domain).await);
33 results.add(Self::test_repo_creation_idempotent(client, relay_domain).await);
34 results.add(Self::test_repo_accessible_via_http(client, relay_domain).await);
35 33
36 results 34 results
37 } 35 }
38 36
39 /// Test that a bare repository is created when a valid announcement is accepted 37 /// Test that a bare repository is created when a valid announcement is accepted
38 /// and is accessible via Smart HTTP service
40 /// 39 ///
41 /// This test: 40 /// This test verifies:
42 /// 1. Sends a valid repository announcement via TestContext 41 /// 1. Sends a valid repository announcement via TestContext
43 /// 2. Verifies the announcement was accepted 42 /// 2. Verifies the announcement was accepted
44 /// 3. Verifies the repository is accessible via Smart HTTP service 43 /// 3. Repository responds to git-upload-pack service discovery
44 /// 4. URL format follows http://domain/npub/identifier.git pattern
45 pub async fn test_bare_repo_created_on_announcement( 45 pub async fn test_bare_repo_created_on_announcement(
46 client: &AuditClient, 46 client: &AuditClient,
47 relay_domain: &str, 47 relay_domain: &str,
@@ -56,7 +56,7 @@ impl RepositoryCreationTests {
56 return TestResult::new( 56 return TestResult::new(
57 test_name, 57 test_name,
58 "GRASP-01", 58 "GRASP-01",
59 "Bare repository must be created when announcement is accepted", 59 "Bare repository must be created and accessible via Smart HTTP when announcement is accepted",
60 ) 60 )
61 .fail(&format!("Failed to create repo fixture: {}", e)) 61 .fail(&format!("Failed to create repo fixture: {}", e))
62 } 62 }
@@ -77,7 +77,7 @@ impl RepositoryCreationTests {
77 return TestResult::new( 77 return TestResult::new(
78 test_name, 78 test_name,
79 "GRASP-01", 79 "GRASP-01",
80 "Bare repository must be created when announcement is accepted", 80 "Bare repository must be created and accessible via Smart HTTP when announcement is accepted",
81 ) 81 )
82 .fail("Repository announcement missing d tag") 82 .fail("Repository announcement missing d tag")
83 } 83 }
@@ -89,18 +89,18 @@ impl RepositoryCreationTests {
89 return TestResult::new( 89 return TestResult::new(
90 test_name, 90 test_name,
91 "GRASP-01", 91 "GRASP-01",
92 "Bare repository must be created when announcement is accepted", 92 "Bare repository must be created and accessible via Smart HTTP when announcement is accepted",
93 ) 93 )
94 .fail(&format!("Failed to convert pubkey to npub: {}", e)) 94 .fail(&format!("Failed to convert pubkey to npub: {}", e))
95 } 95 }
96 }; 96 };
97 97
98 // Verify repository exists via HTTP (info/refs endpoint) 98 // Verify repository exists and is accessible via HTTP (info/refs endpoint)
99 if let Err(e) = check_repo_accessible_via_http(relay_domain, &npub, &repo_id).await { 99 if let Err(e) = check_repo_accessible_via_http(relay_domain, &npub, &repo_id).await {
100 return TestResult::new( 100 return TestResult::new(
101 test_name, 101 test_name,
102 "GRASP-01", 102 "GRASP-01",
103 "Bare repository must be created when announcement is accepted", 103 "Bare repository must be created and accessible via Smart HTTP when announcement is accepted",
104 ) 104 )
105 .fail(&format!("Repository not accessible via HTTP: {}", e)); 105 .fail(&format!("Repository not accessible via HTTP: {}", e));
106 } 106 }
@@ -108,136 +108,7 @@ impl RepositoryCreationTests {
108 TestResult::new( 108 TestResult::new(
109 test_name, 109 test_name,
110 "GRASP-01", 110 "GRASP-01",
111 "Bare repository must be created when announcement is accepted", 111 "Bare repository must be created and accessible via Smart HTTP when announcement is accepted",
112 )
113 .pass()
114 }
115
116 /// Test that repository creation is idempotent
117 ///
118 /// This test:
119 /// 1. Sends a repository announcement (creates repo) via TestContext
120 /// 2. Sends the same announcement again
121 /// 3. Verifies no error occurs and repo still exists
122 pub async fn test_repo_creation_idempotent(
123 client: &AuditClient,
124 relay_domain: &str,
125 ) -> TestResult {
126 let test_name = "test_repo_creation_idempotent";
127 let ctx = TestContext::new(client);
128
129 // Create and send repository announcement first time via TestContext
130 let repo = match ctx.get_fixture(FixtureKind::ValidRepo).await {
131 Ok(r) => r,
132 Err(e) => {
133 return TestResult::new(
134 test_name,
135 "GRASP-01",
136 "Repository creation must be idempotent",
137 )
138 .fail(&format!("Failed to create repo fixture: {}", e))
139 }
140 };
141
142 // Wait for repository creation
143 tokio::time::sleep(std::time::Duration::from_millis(200)).await;
144
145 // Send the same announcement again (should be idempotent)
146 if let Err(e) = client.send_event(repo.clone()).await {
147 return TestResult::new(
148 test_name,
149 "GRASP-01",
150 "Repository creation must be idempotent",
151 )
152 .fail(&format!("Second send failed (not idempotent): {}", e));
153 }
154
155 // Wait again
156 tokio::time::sleep(std::time::Duration::from_millis(200)).await;
157
158 // Verify repository still exists and is accessible via HTTP
159 let repo_id = repo
160 .tags
161 .iter()
162 .find(|t| t.kind() == TagKind::d())
163 .and_then(|t| t.content())
164 .ok_or("Missing d tag")
165 .unwrap()
166 .to_string();
167
168 let npub = repo.pubkey.to_bech32().unwrap();
169
170 if let Err(e) = check_repo_accessible_via_http(relay_domain, &npub, &repo_id).await {
171 return TestResult::new(
172 test_name,
173 "GRASP-01",
174 "Repository creation must be idempotent",
175 )
176 .fail(&format!("Repository not accessible after second send: {}", e));
177 }
178
179 TestResult::new(
180 test_name,
181 "GRASP-01",
182 "Repository creation must be idempotent",
183 )
184 .pass()
185 }
186
187 /// Test that the repository is accessible via Smart HTTP service
188 ///
189 /// This test verifies:
190 /// 1. Repository responds to git-upload-pack service discovery
191 /// 2. URL format follows http://domain/npub/identifier.git pattern
192 pub async fn test_repo_accessible_via_http(
193 client: &AuditClient,
194 relay_domain: &str,
195 ) -> TestResult {
196 let test_name = "test_repo_accessible_via_http";
197 let ctx = TestContext::new(client);
198
199 // Create and send repository announcement via TestContext
200 let repo = match ctx.get_fixture(FixtureKind::ValidRepo).await {
201 Ok(r) => r,
202 Err(e) => {
203 return TestResult::new(
204 test_name,
205 "GRASP-01",
206 "Repository must be accessible via Smart HTTP service",
207 )
208 .fail(&format!("Failed to create repo fixture: {}", e))
209 }
210 };
211
212 // Wait for repository creation
213 tokio::time::sleep(std::time::Duration::from_millis(200)).await;
214
215 // Extract repo identifier and npub
216 let repo_id = repo
217 .tags
218 .iter()
219 .find(|t| t.kind() == TagKind::d())
220 .and_then(|t| t.content())
221 .ok_or("Missing d tag")
222 .unwrap()
223 .to_string();
224
225 let npub = repo.pubkey.to_bech32().unwrap();
226
227 // Verify repository is accessible via HTTP
228 if let Err(e) = check_repo_accessible_via_http(relay_domain, &npub, &repo_id).await {
229 return TestResult::new(
230 test_name,
231 "GRASP-01",
232 "Repository must be accessible via Smart HTTP service",
233 )
234 .fail(&e);
235 }
236
237 TestResult::new(
238 test_name,
239 "GRASP-01",
240 "Repository must be accessible via Smart HTTP service",
241 ) 112 )
242 .pass() 113 .pass()
243 } 114 }