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-12-11 16:45:34 +0000
committerDanConwayDev <DanConwayDev@protonmail.com>2025-12-11 16:46:01 +0000
commit52489d3b1a7d79e164b4cc901b53fd06c05ce1b1 (patch)
tree9be147a22a95b7634a8120a60f2cd8899805088a /tests
parent6d0447f31eb9f9282e60ac3c90c665a8b3781331 (diff)
sync: test sync works without negentropy and add disable option in sync
Diffstat (limited to 'tests')
-rw-r--r--tests/common/relay.rs55
-rw-r--r--tests/sync/bootstrap.rs108
2 files changed, 158 insertions, 5 deletions
diff --git a/tests/common/relay.rs b/tests/common/relay.rs
index 0b3926e..2dd526b 100644
--- a/tests/common/relay.rs
+++ b/tests/common/relay.rs
@@ -38,7 +38,21 @@ impl TestRelay {
38 38
39 /// Start relay on a specific port 39 /// Start relay on a specific port
40 pub async fn start_with_port(port: u16) -> Self { 40 pub async fn start_with_port(port: u16) -> Self {
41 Self::start_with_options(port, None).await 41 Self::start_with_full_options(port, None, false).await
42 }
43
44 /// Start relay on a specific port with full options
45 ///
46 /// This is useful for testing history sync where we need to:
47 /// 1. Start relay_b (first instance) to get its domain
48 /// 2. Stop relay_b
49 /// 3. Start relay_b (second instance) on SAME port with different options
50 pub async fn start_on_port_with_options(
51 port: u16,
52 bootstrap_relay_url: Option<String>,
53 disable_negentropy: bool,
54 ) -> Self {
55 Self::start_with_full_options(port, bootstrap_relay_url, disable_negentropy).await
42 } 56 }
43 57
44 /// Start relay with sync from another relay (bootstrap relay) 58 /// Start relay with sync from another relay (bootstrap relay)
@@ -58,11 +72,39 @@ impl TestRelay {
58 /// } 72 /// }
59 /// ``` 73 /// ```
60 pub async fn start_with_sync(bootstrap_relay_url: Option<String>) -> Self { 74 pub async fn start_with_sync(bootstrap_relay_url: Option<String>) -> Self {
61 Self::start_with_options(Self::find_free_port(), bootstrap_relay_url).await 75 Self::start_with_full_options(Self::find_free_port(), bootstrap_relay_url, false).await
76 }
77
78 /// Start relay with sync and negentropy disabled
79 ///
80 /// This is useful for testing that sync works without NIP-77 negentropy.
81 /// History sync will use REQ+EOSE instead of the more efficient negentropy protocol.
82 ///
83 /// # Example
84 ///
85 /// ```no_run
86 /// use common::TestRelay;
87 ///
88 /// #[tokio::test]
89 /// async fn test_sync_without_negentropy() {
90 /// let source = TestRelay::start().await;
91 /// let syncing = TestRelay::start_with_sync_no_negentropy(Some(source.url().into())).await;
92 /// // ... test sync behavior without negentropy ...
93 /// syncing.stop().await;
94 /// source.stop().await;
95 /// }
96 /// ```
97 pub async fn start_with_sync_no_negentropy(bootstrap_relay_url: Option<String>) -> Self {
98 Self::start_with_full_options(Self::find_free_port(), bootstrap_relay_url, true).await
62 } 99 }
63 100
64 /// Start relay with options 101 /// Start relay with options (internal, maintains backward compatibility)
65 async fn start_with_options(port: u16, bootstrap_relay_url: Option<String>) -> Self { 102 async fn start_with_options(port: u16, bootstrap_relay_url: Option<String>) -> Self {
103 Self::start_with_full_options(port, bootstrap_relay_url, false).await
104 }
105
106 /// Start relay with full options
107 async fn start_with_full_options(port: u16, bootstrap_relay_url: Option<String>, disable_negentropy: bool) -> Self {
66 let bind_address = format!("127.0.0.1:{}", port); 108 let bind_address = format!("127.0.0.1:{}", port);
67 let url = format!("ws://127.0.0.1:{}", port); 109 let url = format!("ws://127.0.0.1:{}", port);
68 110
@@ -108,6 +150,11 @@ impl TestRelay {
108 cmd.env("NGIT_SYNC_BOOTSTRAP_RELAY_URL", bootstrap_url); 150 cmd.env("NGIT_SYNC_BOOTSTRAP_RELAY_URL", bootstrap_url);
109 } 151 }
110 152
153 // Add negentropy disable flag if requested
154 if disable_negentropy {
155 cmd.env("NGIT_SYNC_DISABLE_NEGENTROPY", "true");
156 }
157
111 let process = cmd.spawn().expect("Failed to start relay process"); 158 let process = cmd.spawn().expect("Failed to start relay process");
112 159
113 let relay = Self { process, url, port }; 160 let relay = Self { process, url, port };
@@ -166,7 +213,7 @@ impl TestRelay {
166 } 213 }
167 214
168 /// Find a free port to use for testing 215 /// Find a free port to use for testing
169 fn find_free_port() -> u16 { 216 pub fn find_free_port() -> u16 {
170 use std::net::TcpListener; 217 use std::net::TcpListener;
171 218
172 // Bind to port 0 to get a random free port 219 // Bind to port 0 to get a random free port
diff --git a/tests/sync/bootstrap.rs b/tests/sync/bootstrap.rs
index 0d68609..8a181c9 100644
--- a/tests/sync/bootstrap.rs
+++ b/tests/sync/bootstrap.rs
@@ -305,4 +305,110 @@ async fn test_announcement_not_listing_relay_is_not_synced() {
305 announcement_id 305 announcement_id
306 ); 306 );
307 println!("SUCCESS: Announcement was correctly rejected by relay_b (not synced)"); 307 println!("SUCCESS: Announcement was correctly rejected by relay_b (not synced)");
308} \ No newline at end of file 308}
309
310/// Test: History sync (bootstrap) works without NIP-77 negentropy
311///
312/// This tests that HISTORY sync works when negentropy is disabled.
313/// History sync means: events that existed on the source relay BEFORE
314/// the syncing relay connected.
315///
316/// Scenario:
317/// 1. Start relay_b temporarily to get its domain (then stop it)
318/// 2. Start relay_a (source)
319/// 3. Create announcement listing both relay domains
320/// 4. Send announcement to relay_a (event exists BEFORE relay_b connects)
321/// 5. Start relay_b AGAIN on same port, with negentropy DISABLED
322/// 6. relay_b should sync the pre-existing event via REQ+EOSE (history sync)
323/// 7. Verify relay_b has the event
324///
325/// This is different from "live sync" where events arrive after connection.
326#[tokio::test]
327async fn test_history_sync_without_negentropy() {
328 // 1. First, start relay_b temporarily just to reserve a port and get its domain
329 let relay_b_port = TestRelay::find_free_port();
330 let relay_b_domain = format!("127.0.0.1:{}", relay_b_port);
331 println!(
332 "Reserved port {} for relay_b (domain: {})",
333 relay_b_port, relay_b_domain
334 );
335
336 // 2. Start relay_a (source relay)
337 let relay_a = TestRelay::start().await;
338 println!(
339 "relay_a started at {} (domain: {})",
340 relay_a.url(),
341 relay_a.domain()
342 );
343
344 // 3. Create test keys
345 let keys = Keys::generate();
346
347 // 4. Create announcement listing BOTH relay domains
348 // This event will exist on relay_a BEFORE relay_b ever connects
349 let announcement = create_repo_announcement(
350 &keys,
351 &[&relay_a.domain(), &relay_b_domain],
352 "test-repo-history-no-negentropy",
353 );
354 let announcement_id = announcement.id;
355
356 println!(
357 "Created announcement {} (kind {})",
358 announcement_id,
359 announcement.kind.as_u16()
360 );
361 for tag in announcement.tags.iter() {
362 println!(" Tag: {:?}", tag.as_slice());
363 }
364
365 // 5. Send announcement to relay_a (event now exists BEFORE relay_b connects)
366 let client_a = TestClient::new(relay_a.url(), keys.clone())
367 .await
368 .expect("Failed to connect to relay_a");
369
370 client_a
371 .send_event(&announcement)
372 .await
373 .expect("Failed to send announcement to relay_a");
374 println!("Announcement sent to relay_a (event exists BEFORE relay_b connects)");
375
376 client_a.disconnect().await;
377
378 // 6. Wait a moment to ensure the event is stored
379 tokio::time::sleep(Duration::from_millis(500)).await;
380
381 // 7. NOW start relay_b on the reserved port, with negentropy DISABLED
382 // This relay_b has never connected before - it needs to do HISTORY sync
383 let relay_b = TestRelay::start_on_port_with_options(
384 relay_b_port,
385 Some(relay_a.url().into()),
386 true, // disable_negentropy = true
387 ).await;
388 println!(
389 "relay_b started at {} (domain: {}) - negentropy DISABLED, will do HISTORY sync",
390 relay_b.url(),
391 relay_b.domain()
392 );
393
394 // 8. Wait for history sync to complete (using REQ+EOSE, not negentropy)
395 tokio::time::sleep(Duration::from_secs(3)).await;
396
397 // 9. Verify announcement synced to relay_b via HISTORY sync
398 let filter = Filter::new()
399 .kind(Kind::Custom(KIND_REPOSITORY_STATE))
400 .author(keys.public_key());
401
402 let synced = wait_for_event_on_relay(relay_b.url(), filter, Duration::from_secs(5)).await;
403
404 // 10. Cleanup
405 relay_b.stop().await;
406 relay_a.stop().await;
407
408 assert!(
409 synced,
410 "Announcement {} should have synced from relay_a to relay_b via HISTORY sync (REQ+EOSE, negentropy disabled)",
411 announcement_id
412 );
413 println!("SUCCESS: History sync works without negentropy (using REQ+EOSE fallback)");
414}