diff options
| -rw-r--r-- | tests/purgatory_sync.rs | 126 |
1 files changed, 126 insertions, 0 deletions
diff --git a/tests/purgatory_sync.rs b/tests/purgatory_sync.rs new file mode 100644 index 0000000..1065c9d --- /dev/null +++ b/tests/purgatory_sync.rs | |||
| @@ -0,0 +1,126 @@ | |||
| 1 | //! Purgatory Sync Integration Tests | ||
| 2 | //! | ||
| 3 | //! Tests that verify purgatory sync behavior: | ||
| 4 | //! - Events entering purgatory are released when git data arrives | ||
| 5 | //! - Git push triggers unified processing | ||
| 6 | //! - Remote sync fetches git data and releases events | ||
| 7 | //! | ||
| 8 | //! # Test Strategy | ||
| 9 | //! | ||
| 10 | //! These tests verify the end-to-end purgatory flow: | ||
| 11 | //! 1. State/PR events go to purgatory when git data is missing | ||
| 12 | //! 2. Git push triggers `process_newly_available_git_data` | ||
| 13 | //! 3. Events are released from purgatory when git data becomes available | ||
| 14 | //! | ||
| 15 | //! # Running Tests | ||
| 16 | //! | ||
| 17 | //! ```bash | ||
| 18 | //! # Run all purgatory sync tests | ||
| 19 | //! cargo test --test purgatory_sync | ||
| 20 | //! | ||
| 21 | //! # Run specific test | ||
| 22 | //! cargo test --test purgatory_sync test_push_triggers_unified_processing | ||
| 23 | //! | ||
| 24 | //! # With output for debugging | ||
| 25 | //! cargo test --test purgatory_sync -- --nocapture | ||
| 26 | //! ``` | ||
| 27 | |||
| 28 | mod common; | ||
| 29 | |||
| 30 | use common::{ | ||
| 31 | create_repo_announcement, create_state_event, create_test_repo_with_commit, push_to_relay, | ||
| 32 | verify_event_not_served, wait_for_event_served, CommitVariant, TestRelay, | ||
| 33 | }; | ||
| 34 | use nostr_sdk::prelude::*; | ||
| 35 | use std::time::Duration; | ||
| 36 | |||
| 37 | /// Test that a git push triggers `process_newly_available_git_data` and | ||
| 38 | /// releases state events from purgatory. | ||
| 39 | /// | ||
| 40 | /// Scenario: | ||
| 41 | /// 1. Start relay | ||
| 42 | /// 2. Create and send repository announcement | ||
| 43 | /// 3. Create and send state event (goes to purgatory - no git data yet) | ||
| 44 | /// 4. Verify event is NOT served (in purgatory) | ||
| 45 | /// 5. Git push the required commit | ||
| 46 | /// 6. Verify event IS now served (released from purgatory) | ||
| 47 | #[tokio::test] | ||
| 48 | async fn test_push_triggers_unified_processing() { | ||
| 49 | // 1. Start relay | ||
| 50 | let relay = TestRelay::start().await; | ||
| 51 | let keys = Keys::generate(); | ||
| 52 | let identifier = "push-test-repo"; | ||
| 53 | |||
| 54 | // 2. Create test repository locally with deterministic commit | ||
| 55 | let temp_dir = tempfile::tempdir().expect("Failed to create temp dir"); | ||
| 56 | let commit_hash = | ||
| 57 | create_test_repo_with_commit(temp_dir.path(), CommitVariant::StateTest) | ||
| 58 | .expect("Failed to create test repo"); | ||
| 59 | |||
| 60 | // 3. Create and send announcement | ||
| 61 | let announcement = create_repo_announcement(&keys, &[&relay.domain()], identifier); | ||
| 62 | |||
| 63 | let client = Client::new(keys.clone()); | ||
| 64 | client | ||
| 65 | .add_relay(relay.url()) | ||
| 66 | .await | ||
| 67 | .expect("Failed to add relay"); | ||
| 68 | client.connect().await; | ||
| 69 | |||
| 70 | // Wait for connection to be established | ||
| 71 | tokio::time::sleep(Duration::from_millis(500)).await; | ||
| 72 | |||
| 73 | // Send announcement | ||
| 74 | client | ||
| 75 | .send_event(&announcement) | ||
| 76 | .await | ||
| 77 | .expect("Failed to send announcement"); | ||
| 78 | |||
| 79 | // Small delay to ensure announcement is processed | ||
| 80 | tokio::time::sleep(Duration::from_millis(200)).await; | ||
| 81 | |||
| 82 | // 4. Create and send state event referencing the commit | ||
| 83 | // The state event has refs that point to commits we haven't pushed yet | ||
| 84 | let npub = keys.public_key().to_bech32().expect("Failed to get npub"); | ||
| 85 | let clone_url = format!("http://{}/{}/{}.git", relay.domain(), npub, identifier); | ||
| 86 | |||
| 87 | let state_event = create_state_event( | ||
| 88 | &keys, | ||
| 89 | identifier, | ||
| 90 | &[("main", &commit_hash)], | ||
| 91 | &[], | ||
| 92 | &[&clone_url], | ||
| 93 | &[relay.url()], | ||
| 94 | ) | ||
| 95 | .expect("Failed to create state event"); | ||
| 96 | |||
| 97 | let state_event_id = state_event.id; | ||
| 98 | client | ||
| 99 | .send_event(&state_event) | ||
| 100 | .await | ||
| 101 | .expect("Failed to send state event"); | ||
| 102 | |||
| 103 | // 5. Verify event is NOT served yet (in purgatory) | ||
| 104 | // Give a moment for the event to be processed into purgatory | ||
| 105 | tokio::time::sleep(Duration::from_millis(200)).await; | ||
| 106 | |||
| 107 | verify_event_not_served(relay.url(), &state_event_id, Duration::from_secs(1)) | ||
| 108 | .await | ||
| 109 | .expect("State event should NOT be served before git push (should be in purgatory)"); | ||
| 110 | |||
| 111 | // 6. Git push to relay (this should trigger process_newly_available_git_data) | ||
| 112 | push_to_relay(temp_dir.path(), &relay.domain(), &npub, identifier) | ||
| 113 | .expect("Git push should succeed"); | ||
| 114 | |||
| 115 | // 7. Verify event IS now served (released from purgatory) | ||
| 116 | let found_event = wait_for_event_served(relay.url(), &state_event_id, Duration::from_secs(5)) | ||
| 117 | .await | ||
| 118 | .expect("State event should be served after git push"); | ||
| 119 | |||
| 120 | // Verify it's the same event | ||
| 121 | assert_eq!(found_event.id, state_event_id); | ||
| 122 | |||
| 123 | // Cleanup | ||
| 124 | client.disconnect().await; | ||
| 125 | relay.stop().await; | ||
| 126 | } | ||