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>2026-01-07 15:39:48 +0000
committerDanConwayDev <DanConwayDev@protonmail.com>2026-01-07 15:39:48 +0000
commit1db877d53c4ff45971c69fecc5165c352ec316c9 (patch)
tree4e63366e49430320117ac7d207b9c2f034f8f7b5 /tests
parent7dcbc84806e7b3000835eb9132dfc4e9003e382a (diff)
test: add test_state_event_syncs_from_remote integration test
Implements Phase 3 of the purgatory sync integration test plan. Key changes: - Add immediate sync triggering for sync-received events that go to purgatory (instead of default 3-minute delay for user-submitted events) - TestRelay now respects RUST_LOG environment variable for debugging - New test verifies end-to-end flow: state event syncs from source relay, enters purgatory, git data is fetched from source's clone URL, and event is released and served
Diffstat (limited to 'tests')
-rw-r--r--tests/common/relay.rs7
-rw-r--r--tests/purgatory_sync.rs157
2 files changed, 158 insertions, 6 deletions
diff --git a/tests/common/relay.rs b/tests/common/relay.rs
index 55cc18e..8d20da6 100644
--- a/tests/common/relay.rs
+++ b/tests/common/relay.rs
@@ -144,10 +144,9 @@ impl TestRelay {
144 .env("NGIT_SYNC_STARTUP_JITTER_MS", "0") // No jitter for tests 144 .env("NGIT_SYNC_STARTUP_JITTER_MS", "0") // No jitter for tests
145 .env("NGIT_SYNC_DISCONNECT_CHECK_INTERVAL_SECS", "1") // Fast reconnect attempts for tests 145 .env("NGIT_SYNC_DISCONNECT_CHECK_INTERVAL_SECS", "1") // Fast reconnect attempts for tests
146 .env("NGIT_SYNC_BASE_BACKOFF_SECS", "1") // Fast backoff for tests (1s instead of 5s default) 146 .env("NGIT_SYNC_BASE_BACKOFF_SECS", "1") // Fast backoff for tests (1s instead of 5s default)
147 .env("RUST_LOG", "info") // Enable INFO logging for diagnostics 147 .env("RUST_LOG", std::env::var("RUST_LOG").unwrap_or_else(|_| "info".to_string())) // Use RUST_LOG from environment or default to info
148 .stdout(Stdio::null()) // Disable stderr for cleaner test output 148 .stdout(Stdio::null()) // Suppress stdout for cleaner test output
149 // .stdout(Stdio::inherit()) // Show stdout for diagnostics 149 .stderr(Stdio::null()); // Suppress stderr for cleaner test output
150 .stderr(Stdio::null()); // Disable stderr for cleaner test output
151 150
152 // Add bootstrap relay URL if provided 151 // Add bootstrap relay URL if provided
153 if let Some(ref bootstrap_url) = bootstrap_relay_url { 152 if let Some(ref bootstrap_url) = bootstrap_relay_url {
diff --git a/tests/purgatory_sync.rs b/tests/purgatory_sync.rs
index 1065c9d..3da086c 100644
--- a/tests/purgatory_sync.rs
+++ b/tests/purgatory_sync.rs
@@ -28,8 +28,9 @@
28mod common; 28mod common;
29 29
30use common::{ 30use common::{
31 create_repo_announcement, create_state_event, create_test_repo_with_commit, push_to_relay, 31 check_ref_at_commit, create_repo_announcement, create_state_event,
32 verify_event_not_served, wait_for_event_served, CommitVariant, TestRelay, 32 create_test_repo_with_commit, push_to_relay, verify_event_not_served, wait_for_event_served,
33 wait_for_sync_connection, CommitVariant, TestRelay,
33}; 34};
34use nostr_sdk::prelude::*; 35use nostr_sdk::prelude::*;
35use std::time::Duration; 36use std::time::Duration;
@@ -124,3 +125,155 @@ async fn test_push_triggers_unified_processing() {
124 client.disconnect().await; 125 client.disconnect().await;
125 relay.stop().await; 126 relay.stop().await;
126} 127}
128
129/// Test that a state event entering purgatory triggers remote git fetch
130/// and is released once the git data is available.
131///
132/// Scenario:
133/// 1. Start source relay with git repository containing test commit
134/// 2. Start syncing relay that syncs from source
135/// 3. Syncing relay syncs state event (goes to purgatory - no local git data)
136/// 4. Wait for sync to fetch git data from source's clone URL
137/// 5. Verify state event is released and served on syncing relay
138#[tokio::test]
139async fn test_state_event_syncs_from_remote() {
140 // 1. Start source relay
141 let source_relay = TestRelay::start().await;
142 let keys = Keys::generate();
143 let identifier = "state-sync-test-repo";
144
145 // Pre-allocate syncing relay port so we can include it in announcement
146 let syncing_port = TestRelay::find_free_port();
147 let syncing_domain = format!("127.0.0.1:{}", syncing_port);
148
149 // 2. Create test repository locally with deterministic commit
150 let temp_dir = tempfile::tempdir().expect("Failed to create temp dir");
151 let commit_hash = create_test_repo_with_commit(temp_dir.path(), CommitVariant::StateTest)
152 .expect("Failed to create test repo");
153
154 let npub = keys.public_key().to_bech32().expect("Failed to get npub");
155
156 // 3. Create and send announcement listing BOTH relays
157 // This ensures the syncing relay will accept the state event when it syncs
158 let announcement = create_repo_announcement(
159 &keys,
160 &[&source_relay.domain(), &syncing_domain],
161 identifier,
162 );
163
164 let source_client = Client::new(keys.clone());
165 source_client
166 .add_relay(source_relay.url())
167 .await
168 .expect("Failed to add source relay");
169 source_client.connect().await;
170
171 // Wait for connection
172 tokio::time::sleep(Duration::from_millis(500)).await;
173
174 // Send announcement to source relay
175 source_client
176 .send_event(&announcement)
177 .await
178 .expect("Failed to send announcement to source");
179
180 tokio::time::sleep(Duration::from_millis(200)).await;
181
182 // 4. Create and send state event BEFORE pushing
183 // The state event goes to purgatory on source relay, which authorizes the push
184 let clone_urls = [
185 format!(
186 "http://{}/{}/{}.git",
187 source_relay.domain(),
188 npub,
189 identifier
190 ),
191 format!("http://{}/{}/{}.git", syncing_domain, npub, identifier),
192 ];
193 let relay_urls = [
194 source_relay.url().to_string(),
195 format!("ws://{}", syncing_domain),
196 ];
197
198 let state_event = create_state_event(
199 &keys,
200 identifier,
201 &[("main", &commit_hash)],
202 &[],
203 &[&clone_urls[0], &clone_urls[1]],
204 &[&relay_urls[0], &relay_urls[1]],
205 )
206 .expect("Failed to create state event");
207
208 let state_event_id = state_event.id;
209
210 // Send state event to source relay (goes to purgatory - no git data yet)
211 source_client
212 .send_event(&state_event)
213 .await
214 .expect("Failed to send state event to source");
215
216 tokio::time::sleep(Duration::from_millis(200)).await;
217
218 // 5. Push git data to source relay
219 // The state event in purgatory authorizes this push
220 push_to_relay(temp_dir.path(), &source_relay.domain(), &npub, identifier)
221 .expect("Push to source should succeed");
222
223 // After push, state event should be released from purgatory on source relay
224 // Verify source relay is serving the state event
225 wait_for_event_served(source_relay.url(), &state_event_id, Duration::from_secs(5))
226 .await
227 .expect("State event should be served on source relay after push");
228
229 // 6. Start syncing relay (syncs from source)
230 let syncing_relay = TestRelay::start_on_port_with_options(
231 syncing_port,
232 Some(source_relay.url().to_string()),
233 false,
234 )
235 .await;
236
237 // Wait for sync connection to establish
238 wait_for_sync_connection(syncing_relay.url(), 1, Duration::from_secs(5))
239 .await
240 .expect("Sync connection should establish");
241
242 // 7. Wait for state event to be released on syncing relay
243 // The sync should:
244 // a) Fetch the announcement and state event from source relay
245 // b) Accept announcement (creates bare repo structure)
246 // c) Put state event in purgatory (git data missing on syncing relay)
247 // d) Fetch git data from source relay's clone URL
248 // e) Release the state event from purgatory
249 let found = wait_for_event_served(
250 syncing_relay.url(),
251 &state_event_id,
252 Duration::from_secs(30), // Allow time for sync + git fetch
253 )
254 .await;
255
256 assert!(
257 found.is_ok(),
258 "State event should be served after sync fetches git data: {:?}",
259 found.err()
260 );
261
262 // 8. Verify refs are correct on syncing relay
263 let ref_correct = check_ref_at_commit(
264 &syncing_domain,
265 &npub,
266 identifier,
267 "refs/heads/main",
268 &commit_hash,
269 )
270 .await
271 .expect("Failed to check ref");
272
273 assert!(ref_correct, "main branch should point to correct commit");
274
275 // Cleanup
276 source_client.disconnect().await;
277 syncing_relay.stop().await;
278 source_relay.stop().await;
279}