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:
Diffstat (limited to 'tests')
-rw-r--r--tests/archive_read_only.rs59
-rw-r--r--tests/purgatory.rs4
-rw-r--r--tests/purgatory_persistence.rs26
3 files changed, 61 insertions, 28 deletions
diff --git a/tests/archive_read_only.rs b/tests/archive_read_only.rs
index be6959b..e39b4b2 100644
--- a/tests/archive_read_only.rs
+++ b/tests/archive_read_only.rs
@@ -165,6 +165,7 @@ async fn test_archive_read_only_creates_bare_repo() {
165 // c) Put state event in purgatory (git data missing on archive relay) 165 // c) Put state event in purgatory (git data missing on archive relay)
166 // d) Fetch git data from source relay's clone URL 166 // d) Fetch git data from source relay's clone URL
167 // e) Release the state event from purgatory 167 // e) Release the state event from purgatory
168
168 let found = wait_for_event_served( 169 let found = wait_for_event_served(
169 archive_relay.url(), 170 archive_relay.url(),
170 &state_event_id, 171 &state_event_id,
@@ -267,11 +268,13 @@ async fn test_archive_read_only_creates_bare_repo() {
267/// This verifies the security model: archive mode only syncs git data 268/// This verifies the security model: archive mode only syncs git data
268/// when there are state events to validate against. 269/// when there are state events to validate against.
269/// 270///
270/// Scenario: 271/// With announcement purgatory, the flow is:
271/// 1. Start source relay with announcement only (no state events) 272/// 1. Send announcement to source relay (goes to purgatory)
272/// 2. Start archive relay syncing from source 273/// 2. Send state event to source relay (goes to purgatory)
273/// 3. Archive relay syncs announcement (creates bare repo) 274/// 3. Push git data to source relay (promotes announcement and state event)
274/// 4. Verify git data is NOT synced (no state events to trigger purgatory sync) 275/// 4. Start archive relay with sync from source
276/// 5. Archive relay syncs the promoted announcement
277/// 6. Verify git data is NOT synced (archive has no state event to authorize git fetch)
275#[tokio::test] 278#[tokio::test]
276async fn test_archive_without_state_events_does_not_sync_git() { 279async fn test_archive_without_state_events_does_not_sync_git() {
277 // 1. Start source relay 280 // 1. Start source relay
@@ -290,7 +293,7 @@ async fn test_archive_without_state_events_does_not_sync_git() {
290 293
291 let npub = keys.public_key().to_bech32().expect("Failed to get npub"); 294 let npub = keys.public_key().to_bech32().expect("Failed to get npub");
292 295
293 // 3. Create and send announcement listing BOTH relays (but NO state event) 296 // 3. Create and send announcement listing BOTH relays
294 let announcement = create_repo_announcement( 297 let announcement = create_repo_announcement(
295 &keys, 298 &keys,
296 &[&source_relay.domain(), &archive_domain], 299 &[&source_relay.domain(), &archive_domain],
@@ -306,7 +309,7 @@ async fn test_archive_without_state_events_does_not_sync_git() {
306 309
307 tokio::time::sleep(Duration::from_millis(500)).await; 310 tokio::time::sleep(Duration::from_millis(500)).await;
308 311
309 // Send announcement to source relay 312 // Send announcement to source relay (goes to purgatory)
310 source_client 313 source_client
311 .send_event(&announcement) 314 .send_event(&announcement)
312 .await 315 .await
@@ -314,11 +317,39 @@ async fn test_archive_without_state_events_does_not_sync_git() {
314 317
315 tokio::time::sleep(Duration::from_millis(200)).await; 318 tokio::time::sleep(Duration::from_millis(200)).await;
316 319
317 // 4. Push git data to source relay (but no state event to authorize it) 320 // 4. Create and send state event to source relay (goes to purgatory)
318 // This push will fail because there's no state event in purgatory 321 let clone_url = format!(
319 // That's expected - we're testing that archive mode doesn't blindly fetch git data 322 "http://{}/{}/{}.git",
323 source_relay.domain(),
324 npub,
325 identifier
326 );
327 let relay_url = source_relay.url().to_string();
328
329 let state_event = create_state_event(
330 &keys,
331 identifier,
332 &[("main", &commit_hash)],
333 &[],
334 &[&clone_url],
335 &[&relay_url],
336 )
337 .expect("Failed to create state event");
338
339 source_client
340 .send_event(&state_event)
341 .await
342 .expect("Failed to send state event to source");
343
344 tokio::time::sleep(Duration::from_millis(200)).await;
345
346 // 5. Push git data to source relay (promotes announcement and state event)
347 push_to_relay(temp_dir.path(), &source_relay.domain(), &npub, identifier)
348 .expect("Push to source should succeed");
349
350 tokio::time::sleep(Duration::from_millis(500)).await;
320 351
321 // 5. Start archive relay 352 // 6. Start archive relay (without state event - we don't send state event to archive)
322 let archive_relay = TestRelay::start_with_archive_and_sync( 353 let archive_relay = TestRelay::start_with_archive_and_sync(
323 archive_port, 354 archive_port,
324 Some(source_relay.url().to_string()), 355 Some(source_relay.url().to_string()),
@@ -333,10 +364,10 @@ async fn test_archive_without_state_events_does_not_sync_git() {
333 .await 364 .await
334 .expect("Sync connection should establish"); 365 .expect("Sync connection should establish");
335 366
336 // Give time for any potential git sync to happen 367 // Give time for sync to fetch announcement
337 tokio::time::sleep(Duration::from_secs(3)).await; 368 tokio::time::sleep(Duration::from_secs(3)).await;
338 369
339 // 6. Verify bare repository was created (announcement was accepted) 370 // 7. Verify bare repository was created (announcement was synced and accepted to purgatory)
340 let repo_path = archive_relay 371 let repo_path = archive_relay
341 .git_data_path() 372 .git_data_path()
342 .join(format!("{}/{}.git", npub, identifier)); 373 .join(format!("{}/{}.git", npub, identifier));
@@ -346,7 +377,7 @@ async fn test_archive_without_state_events_does_not_sync_git() {
346 "Bare repository should be created for archive announcement" 377 "Bare repository should be created for archive announcement"
347 ); 378 );
348 379
349 // 7. Verify git data was NOT synced (no state events to trigger purgatory sync) 380 // 8. Verify git data was NOT synced (no state events on archive to trigger git fetch)
350 // Check that the commit does NOT exist in the archive relay's repo 381 // Check that the commit does NOT exist in the archive relay's repo
351 let output = tokio::process::Command::new("git") 382 let output = tokio::process::Command::new("git")
352 .args(["cat-file", "-t", &commit_hash]) 383 .args(["cat-file", "-t", &commit_hash])
diff --git a/tests/purgatory.rs b/tests/purgatory.rs
index e99540b..efc28c9 100644
--- a/tests/purgatory.rs
+++ b/tests/purgatory.rs
@@ -58,10 +58,10 @@ macro_rules! isolated_purgatory_test {
58} 58}
59 59
60// ============================================================ 60// ============================================================
61// Announcement Purgatory Tests (commented out - feature not yet implemented) 61// Announcement Purgatory Tests
62// ============================================================ 62// ============================================================
63 63
64// isolated_purgatory_test!(test_announcement_not_served_before_git_data); 64isolated_purgatory_test!(test_announcement_not_served_before_git_data);
65isolated_purgatory_test!(test_announcement_served_after_git_push); 65isolated_purgatory_test!(test_announcement_served_after_git_push);
66isolated_purgatory_test!(test_bare_repo_exists_for_purgatory_announcement); 66isolated_purgatory_test!(test_bare_repo_exists_for_purgatory_announcement);
67isolated_purgatory_test!(test_state_event_accepted_for_purgatory_announcement); 67isolated_purgatory_test!(test_state_event_accepted_for_purgatory_announcement);
diff --git a/tests/purgatory_persistence.rs b/tests/purgatory_persistence.rs
index fe37c33..5abbf15 100644
--- a/tests/purgatory_persistence.rs
+++ b/tests/purgatory_persistence.rs
@@ -120,7 +120,8 @@ async fn test_full_purgatory_save_restore_cycle() {
120 // so we'll focus on testing state and PR events persistence 120 // so we'll focus on testing state and PR events persistence
121 121
122 // Verify initial counts 122 // Verify initial counts
123 let (state_count, pr_count) = purgatory.count(); 123 let (announcement_count, state_count, pr_count) = purgatory.count();
124 assert_eq!(announcement_count, 0, "Should have 0 announcements");
124 assert_eq!(state_count, 2, "Should have 2 state events"); 125 assert_eq!(state_count, 2, "Should have 2 state events");
125 assert_eq!( 126 assert_eq!(
126 pr_count, 3, 127 pr_count, 3,
@@ -142,7 +143,8 @@ async fn test_full_purgatory_save_restore_cycle() {
142 ); 143 );
143 144
144 // Verify all data was restored 145 // Verify all data was restored
145 let (state_count2, pr_count2) = purgatory2.count(); 146 let (announcement_count2, state_count2, pr_count2) = purgatory2.count();
147 assert_eq!(announcement_count2, 0, "Should have 0 announcements after restore");
146 assert_eq!(state_count2, 2, "Should have 2 state events after restore"); 148 assert_eq!(state_count2, 2, "Should have 2 state events after restore");
147 assert_eq!( 149 assert_eq!(
148 pr_count2, 3, 150 pr_count2, 3,
@@ -275,7 +277,7 @@ async fn test_purgatory_downtime_adjustment() {
275 purgatory2.restore_from_disk(&state_path).unwrap(); 277 purgatory2.restore_from_disk(&state_path).unwrap();
276 278
277 // Verify event is still there (downtime was accounted for) 279 // Verify event is still there (downtime was accounted for)
278 let (state_count, _) = purgatory2.count(); 280 let (_, state_count, _) = purgatory2.count();
279 assert_eq!(state_count, 1); 281 assert_eq!(state_count, 1);
280 282
281 let repo1_states = purgatory2.find_state("repo1"); 283 let repo1_states = purgatory2.find_state("repo1");
@@ -401,7 +403,7 @@ async fn test_purgatory_restore_missing_file() {
401 assert!(result.is_err(), "Should error on missing file"); 403 assert!(result.is_err(), "Should error on missing file");
402 404
403 // Purgatory should still be usable (empty state) 405 // Purgatory should still be usable (empty state)
404 let (state_count, pr_count) = purgatory.count(); 406 let (_, state_count, pr_count) = purgatory.count();
405 assert_eq!(state_count, 0); 407 assert_eq!(state_count, 0);
406 assert_eq!(pr_count, 0); 408 assert_eq!(pr_count, 0);
407 409
@@ -410,7 +412,7 @@ async fn test_purgatory_restore_missing_file() {
410 let event = create_test_event(&keys, "test").await; 412 let event = create_test_event(&keys, "test").await;
411 purgatory.add_state(event, "repo1".to_string(), keys.public_key()); 413 purgatory.add_state(event, "repo1".to_string(), keys.public_key());
412 414
413 let (state_count, _) = purgatory.count(); 415 let (_, state_count, _) = purgatory.count();
414 assert_eq!(state_count, 1); 416 assert_eq!(state_count, 1);
415} 417}
416 418
@@ -461,7 +463,7 @@ async fn test_purgatory_restore_corrupted_file() {
461 assert!(result.is_err(), "Should error on corrupted file"); 463 assert!(result.is_err(), "Should error on corrupted file");
462 464
463 // Purgatory should still be usable 465 // Purgatory should still be usable
464 let (state_count, pr_count) = purgatory.count(); 466 let (_, state_count, pr_count) = purgatory.count();
465 assert_eq!(state_count, 0); 467 assert_eq!(state_count, 0);
466 assert_eq!(pr_count, 0); 468 assert_eq!(pr_count, 0);
467} 469}
@@ -504,7 +506,7 @@ async fn test_empty_purgatory_save_restore() {
504 purgatory2.restore_from_disk(&state_path).unwrap(); 506 purgatory2.restore_from_disk(&state_path).unwrap();
505 507
506 // Verify empty state 508 // Verify empty state
507 let (state_count, pr_count) = purgatory2.count(); 509 let (_, state_count, pr_count) = purgatory2.count();
508 assert_eq!(state_count, 0); 510 assert_eq!(state_count, 0);
509 assert_eq!(pr_count, 0); 511 assert_eq!(pr_count, 0);
510 assert_eq!(purgatory2.expired_count(), 0); 512 assert_eq!(purgatory2.expired_count(), 0);
@@ -591,7 +593,7 @@ async fn test_purgatory_continues_working_after_restore() {
591 purgatory2.add_state(event2.clone(), "repo2".to_string(), keys.public_key()); 593 purgatory2.add_state(event2.clone(), "repo2".to_string(), keys.public_key());
592 594
593 // Verify both old and new events work 595 // Verify both old and new events work
594 let (state_count, _) = purgatory2.count(); 596 let (_, state_count, _) = purgatory2.count();
595 assert_eq!(state_count, 2); 597 assert_eq!(state_count, 2);
596 598
597 let repo1_states = purgatory2.find_state("repo1"); 599 let repo1_states = purgatory2.find_state("repo1");
@@ -603,7 +605,7 @@ async fn test_purgatory_continues_working_after_restore() {
603 assert_eq!(repo2_states[0].event.id, event2.id); 605 assert_eq!(repo2_states[0].event.id, event2.id);
604 606
605 // Verify cleanup still works 607 // Verify cleanup still works
606 let (state_removed, pr_removed) = purgatory2.cleanup(); 608 let (_, state_removed, pr_removed) = purgatory2.cleanup();
607 // Nothing should be expired yet 609 // Nothing should be expired yet
608 assert_eq!(state_removed, 0); 610 assert_eq!(state_removed, 0);
609 assert_eq!(pr_removed, 0); 611 assert_eq!(pr_removed, 0);
@@ -684,15 +686,15 @@ async fn test_purgatory_entries_expired_during_downtime() {
684 purgatory2.restore_from_disk(&state_path).unwrap(); 686 purgatory2.restore_from_disk(&state_path).unwrap();
685 687
686 // Event should be restored 688 // Event should be restored
687 let (state_count, _) = purgatory2.count(); 689 let (_, state_count, _) = purgatory2.count();
688 assert_eq!(state_count, 1); 690 assert_eq!(state_count, 1);
689 691
690 // Cleanup should work (even if nothing is expired yet) 692 // Cleanup should work (even if nothing is expired yet)
691 let (state_removed, _) = purgatory2.cleanup(); 693 let (_, state_removed, _) = purgatory2.cleanup();
692 // Nothing expired yet since we didn't wait 30 minutes 694 // Nothing expired yet since we didn't wait 30 minutes
693 assert_eq!(state_removed, 0); 695 assert_eq!(state_removed, 0);
694 696
695 let (state_count, _) = purgatory2.count(); 697 let (_, state_count, _) = purgatory2.count();
696 assert_eq!(state_count, 1); 698 assert_eq!(state_count, 1);
697} 699}
698 700