upleb.uk

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

summaryrefslogtreecommitdiff
path: root/tests/sync
diff options
context:
space:
mode:
authorDanConwayDev <DanConwayDev@protonmail.com>2025-12-10 21:55:31 +0000
committerDanConwayDev <DanConwayDev@protonmail.com>2025-12-10 21:57:02 +0000
commit46b306dcfa4850a688367c04e9e06e8d9c2883dc (patch)
tree6606ef21a60dbc8441dc97f960bf3684f51775bf /tests/sync
parent466a009d8248aab274a9da419e4c0d83a4b9f466 (diff)
fix: enable Layer 3 sync by adding root events to pending queue
When root events (issues/patches) are received via self-subscription, handle_root_event() was only updating the repo_sync_index directly. This caused process_batch() to early-return when pending.is_empty(), so Layer 3 filters for comments/replies were never created. The fix adds root events to both: 1. repo_sync_index (for immediate availability) 2. pending queue (to trigger Layer 3 filter creation in next batch) Critical: The pending entry must include relays from repo_sync_index so derive_relay_targets() knows where to send Layer 3 subscriptions. The Layer 3 test now verifies that events sent BEFORE the subscription is established are still synced - proving subscriptions without 'since' correctly fetch historical events. Enabled 4 previously ignored Layer 3 tests: - test_live_sync_layer3_events - test_layer3_sync_with_lowercase_e_tag - test_layer3_sync_with_uppercase_e_tag - test_layer3_sync_with_q_tag
Diffstat (limited to 'tests/sync')
-rw-r--r--tests/sync/live_sync.rs98
-rw-r--r--tests/sync/tag_variations.rs45
2 files changed, 73 insertions, 70 deletions
diff --git a/tests/sync/live_sync.rs b/tests/sync/live_sync.rs
index 9342cde..ebe1c0b 100644
--- a/tests/sync/live_sync.rs
+++ b/tests/sync/live_sync.rs
@@ -58,11 +58,8 @@ async fn test_live_sync_layer2_events() {
58 58
59 // 4. Create a repository announcement that lists BOTH relays 59 // 4. Create a repository announcement that lists BOTH relays
60 let repo_id = "test-repo-live-l2"; 60 let repo_id = "test-repo-live-l2";
61 let announcement = create_repo_announcement( 61 let announcement =
62 &keys, 62 create_repo_announcement(&keys, &[&relay_a.domain(), &relay_b.domain()], repo_id);
63 &[&relay_a.domain(), &relay_b.domain()],
64 repo_id,
65 );
66 63
67 println!( 64 println!(
68 "Created announcement {} (kind {})", 65 "Created announcement {} (kind {})",
@@ -123,7 +120,7 @@ async fn test_live_sync_layer2_events() {
123 .id(issue_id); 120 .id(issue_id);
124 121
125 let synced = wait_for_event_on_relay(relay_b.url(), filter, Duration::from_secs(5)).await; 122 let synced = wait_for_event_on_relay(relay_b.url(), filter, Duration::from_secs(5)).await;
126 123
127 println!("Issue {} synced to relay_b: {}", issue_id, synced); 124 println!("Issue {} synced to relay_b: {}", issue_id, synced);
128 125
129 // 10. Cleanup 126 // 10. Cleanup
@@ -150,15 +147,7 @@ async fn test_live_sync_layer2_events() {
150/// 6. Verify comment syncs to relay_b within 5 seconds 147/// 6. Verify comment syncs to relay_b within 5 seconds
151/// 7. Verify comment has correct 'E' tag reference 148/// 7. Verify comment has correct 'E' tag reference
152/// 149///
153/// # Note
154/// This test is currently ignored because Layer 3 (comment) sync is tracked separately
155/// and may not be fully implemented yet. See discovery.rs for context:
156/// > "Note: Layer 3 (comments on issues) sync is tracked separately and may
157/// > be implemented in future phases."
158///
159/// TODO: Enable this test when Layer 3 sync is implemented.
160#[tokio::test] 150#[tokio::test]
161#[ignore = "Layer 3 sync not yet implemented - comments don't sync via discovery"]
162async fn test_live_sync_layer3_events() { 151async fn test_live_sync_layer3_events() {
163 // 1. Start relays 152 // 1. Start relays
164 let relay_a = TestRelay::start().await; 153 let relay_a = TestRelay::start().await;
@@ -179,11 +168,8 @@ async fn test_live_sync_layer3_events() {
179 168
180 // 2. Create and send repository announcement to both relays 169 // 2. Create and send repository announcement to both relays
181 let repo_id = "test-repo-live-l3"; 170 let repo_id = "test-repo-live-l3";
182 let announcement = create_repo_announcement( 171 let announcement =
183 &keys, 172 create_repo_announcement(&keys, &[&relay_a.domain(), &relay_b.domain()], repo_id);
184 &[&relay_a.domain(), &relay_b.domain()],
185 repo_id,
186 );
187 173
188 let client_a = TestClient::new(relay_a.url(), keys.clone()) 174 let client_a = TestClient::new(relay_a.url(), keys.clone())
189 .await 175 .await
@@ -220,16 +206,8 @@ async fn test_live_sync_layer3_events() {
220 .expect("Failed to send issue"); 206 .expect("Failed to send issue");
221 println!("Layer 2 issue {} sent to relay_a", issue_id); 207 println!("Layer 2 issue {} sent to relay_a", issue_id);
222 208
223 // 5. Wait for issue to sync to relay_b 209 // 5. Create and send Layer 3 comment IMMEDIATELY (before waiting for sync)
224 tokio::time::sleep(Duration::from_secs(2)).await; 210 // This tests that subscriptions without 'since' will catch pre-existing events
225
226 let issue_filter = Filter::new()
227 .kind(Kind::Custom(KIND_ISSUE))
228 .id(issue_id);
229 let issue_synced = wait_for_event_on_relay(relay_b.url(), issue_filter, Duration::from_secs(3)).await;
230 println!("Issue synced to relay_b: {}", issue_synced);
231
232 // 6. Create and send Layer 3 comment (kind 1111, uppercase E tag)
233 let comment = build_layer3_comment_with_uppercase_e_tag( 211 let comment = build_layer3_comment_with_uppercase_e_tag(
234 &keys, 212 &keys,
235 &issue_id, 213 &issue_id,
@@ -238,7 +216,11 @@ async fn test_live_sync_layer3_events() {
238 .expect("Failed to create comment"); 216 .expect("Failed to create comment");
239 let comment_id = comment.id; 217 let comment_id = comment.id;
240 218
241 println!("Created comment {} (kind {})", comment_id, comment.kind.as_u16()); 219 println!(
220 "Created comment {} (kind {})",
221 comment_id,
222 comment.kind.as_u16()
223 );
242 for tag in comment.tags.iter() { 224 for tag in comment.tags.iter() {
243 println!(" Tag: {:?}", tag.as_slice()); 225 println!(" Tag: {:?}", tag.as_slice());
244 } 226 }
@@ -247,7 +229,15 @@ async fn test_live_sync_layer3_events() {
247 .send_event(&comment) 229 .send_event(&comment)
248 .await 230 .await
249 .expect("Failed to send comment"); 231 .expect("Failed to send comment");
250 println!("Layer 3 comment {} sent to relay_a", comment_id); 232 println!("Layer 3 comment {} sent to relay_a BEFORE Layer 3 subscription established", comment_id);
233
234 // 6. Now wait for issue to sync to relay_b (this triggers Layer 3 filter creation)
235 tokio::time::sleep(Duration::from_secs(2)).await;
236
237 let issue_filter = Filter::new().kind(Kind::Custom(KIND_ISSUE)).id(issue_id);
238 let issue_synced =
239 wait_for_event_on_relay(relay_b.url(), issue_filter, Duration::from_secs(3)).await;
240 println!("Issue synced to relay_b: {}", issue_synced);
251 241
252 client_a.disconnect().await; 242 client_a.disconnect().await;
253 client_b.disconnect().await; 243 client_b.disconnect().await;
@@ -258,8 +248,12 @@ async fn test_live_sync_layer3_events() {
258 .author(keys.public_key()) 248 .author(keys.public_key())
259 .id(comment_id); 249 .id(comment_id);
260 250
261 let comment_synced = wait_for_event_on_relay(relay_b.url(), comment_filter, Duration::from_secs(5)).await; 251 let comment_synced =
262 println!("Comment {} synced to relay_b: {}", comment_id, comment_synced); 252 wait_for_event_on_relay(relay_b.url(), comment_filter, Duration::from_secs(5)).await;
253 println!(
254 "Comment {} synced to relay_b: {}",
255 comment_id, comment_synced
256 );
263 257
264 // 8. Verify the comment has correct 'E' tag reference 258 // 8. Verify the comment has correct 'E' tag reference
265 let mut has_correct_ref = false; 259 let mut has_correct_ref = false;
@@ -269,12 +263,15 @@ async fn test_live_sync_layer3_events() {
269 if client.add_relay(relay_b.url()).await.is_ok() { 263 if client.add_relay(relay_b.url()).await.is_ok() {
270 client.connect().await; 264 client.connect().await;
271 tokio::time::sleep(Duration::from_millis(500)).await; 265 tokio::time::sleep(Duration::from_millis(500)).await;
272 266
273 let fetch_filter = Filter::new() 267 let fetch_filter = Filter::new()
274 .kind(Kind::Custom(KIND_COMMENT)) 268 .kind(Kind::Custom(KIND_COMMENT))
275 .id(comment_id); 269 .id(comment_id);
276 270
277 if let Ok(events) = client.fetch_events(fetch_filter, Duration::from_secs(2)).await { 271 if let Ok(events) = client
272 .fetch_events(fetch_filter, Duration::from_secs(2))
273 .await
274 {
278 if let Some(event) = events.first() { 275 if let Some(event) = events.first() {
279 // Check for 'E' tag with parent event ID 276 // Check for 'E' tag with parent event ID
280 for tag in event.tags.iter() { 277 for tag in event.tags.iter() {
@@ -347,11 +344,8 @@ async fn test_live_sync_event_ordering() {
347 344
348 // 2. Create and send repository announcement to both relays 345 // 2. Create and send repository announcement to both relays
349 let repo_id = "test-repo-ordering"; 346 let repo_id = "test-repo-ordering";
350 let announcement = create_repo_announcement( 347 let announcement =
351 &keys, 348 create_repo_announcement(&keys, &[&relay_a.domain(), &relay_b.domain()], repo_id);
352 &[&relay_a.domain(), &relay_b.domain()],
353 repo_id,
354 );
355 349
356 let client_a = TestClient::new(relay_a.url(), keys.clone()) 350 let client_a = TestClient::new(relay_a.url(), keys.clone())
357 .await 351 .await
@@ -387,12 +381,15 @@ async fn test_live_sync_event_ordering() {
387 &format!("Ordering Test Issue {}", i), 381 &format!("Ordering Test Issue {}", i),
388 ) 382 )
389 .expect("Failed to create issue"); 383 .expect("Failed to create issue");
390 384
391 // Store the created_at timestamp for ordering verification 385 // Store the created_at timestamp for ordering verification
392 expected_order_timestamps.push(issue.created_at); 386 expected_order_timestamps.push(issue.created_at);
393 issue_ids.push(issue.id); 387 issue_ids.push(issue.id);
394 388
395 println!("Created issue {} at timestamp {}", issue.id, issue.created_at); 389 println!(
390 "Created issue {} at timestamp {}",
391 issue.id, issue.created_at
392 );
396 393
397 client_a 394 client_a
398 .send_event(&issue) 395 .send_event(&issue)
@@ -412,7 +409,7 @@ async fn test_live_sync_event_ordering() {
412 // 6. Fetch all events from relay_b 409 // 6. Fetch all events from relay_b
413 let temp_keys = Keys::generate(); 410 let temp_keys = Keys::generate();
414 let client = Client::new(temp_keys); 411 let client = Client::new(temp_keys);
415 412
416 let events_found: Vec<Event>; 413 let events_found: Vec<Event>;
417 if client.add_relay(relay_b.url()).await.is_ok() { 414 if client.add_relay(relay_b.url()).await.is_ok() {
418 client.connect().await; 415 client.connect().await;
@@ -446,7 +443,11 @@ async fn test_live_sync_event_ordering() {
446 .filter(|e| issue_ids.contains(&e.id)) 443 .filter(|e| issue_ids.contains(&e.id))
447 .collect(); 444 .collect();
448 445
449 println!("Found {} test events (out of {} total)", test_events.len(), events_found.len()); 446 println!(
447 "Found {} test events (out of {} total)",
448 test_events.len(),
449 events_found.len()
450 );
450 451
451 // 8. Check ordering by created_at timestamp 452 // 8. Check ordering by created_at timestamp
452 let mut ordered_correctly = true; 453 let mut ordered_correctly = true;
@@ -470,8 +471,7 @@ async fn test_live_sync_event_ordering() {
470 ordered_correctly = false; 471 ordered_correctly = false;
471 println!( 472 println!(
472 "Order violation: {} ({}) > {} ({})", 473 "Order violation: {} ({}) > {} ({})",
473 window[0].id, window[0].created_at, 474 window[0].id, window[0].created_at, window[1].id, window[1].created_at
474 window[1].id, window[1].created_at
475 ); 475 );
476 } 476 }
477 } 477 }
@@ -492,4 +492,4 @@ async fn test_live_sync_event_ordering() {
492 ordered_correctly, 492 ordered_correctly,
493 "Events should be ordered by created_at timestamp" 493 "Events should be ordered by created_at timestamp"
494 ); 494 );
495} \ No newline at end of file 495}
diff --git a/tests/sync/tag_variations.rs b/tests/sync/tag_variations.rs
index a92fdbf..273a573 100644
--- a/tests/sync/tag_variations.rs
+++ b/tests/sync/tag_variations.rs
@@ -329,14 +329,7 @@ async fn test_layer2_sync_with_q_tag() {
329/// tags sync correctly between relays when referencing a Layer 2 event. 329/// tags sync correctly between relays when referencing a Layer 2 event.
330/// 330///
331/// The lowercase 'e' tag is the standard NIP-01 way to reference events by ID. 331/// The lowercase 'e' tag is the standard NIP-01 way to reference events by ID.
332///
333/// # Note
334/// This test is currently ignored because Layer 3 sync is not yet implemented.
335/// The test logic is complete and will work when Layer 3 sync is enabled.
336///
337/// TODO: Enable this test when Layer 3 sync is implemented.
338#[tokio::test] 332#[tokio::test]
339#[ignore = "Layer 3 sync not yet implemented - comments don't sync via discovery"]
340async fn test_layer3_sync_with_lowercase_e_tag() { 333async fn test_layer3_sync_with_lowercase_e_tag() {
341 // 1. Start relays 334 // 1. Start relays
342 let relay_a = TestRelay::start().await; 335 let relay_a = TestRelay::start().await;
@@ -406,6 +399,14 @@ async fn test_layer3_sync_with_lowercase_e_tag() {
406 println!("Issue synced to relay_b: {}", issue_synced); 399 println!("Issue synced to relay_b: {}", issue_synced);
407 assert!(issue_synced, "Layer 2 issue should sync first"); 400 assert!(issue_synced, "Layer 2 issue should sync first");
408 401
402 // Wait for Layer 3 subscriptions to be established
403 // After issue syncs, relay_b's SelfSubscriber needs time to:
404 // 1. Receive the synced issue via notify_event broadcast
405 // 2. Batch timer to tick (up to 200ms in tests)
406 // 3. Process batch and create Layer 3 filters
407 // 4. Subscribe to relay_a with Layer 3 filters
408 tokio::time::sleep(Duration::from_millis(500)).await;
409
409 // 6. Create and send Layer 3 reply with lowercase 'e' tag (kind 1) 410 // 6. Create and send Layer 3 reply with lowercase 'e' tag (kind 1)
410 let reply = build_layer3_reply_with_e_tag(&keys, &issue_id, "Reply with lowercase e tag") 411 let reply = build_layer3_reply_with_e_tag(&keys, &issue_id, "Reply with lowercase e tag")
411 .expect("Failed to create reply"); 412 .expect("Failed to create reply");
@@ -451,14 +452,7 @@ async fn test_layer3_sync_with_lowercase_e_tag() {
451/// tags sync correctly between relays when referencing a Layer 2 event. 452/// tags sync correctly between relays when referencing a Layer 2 event.
452/// 453///
453/// The uppercase 'E' tag is used in NIP-22 for comment events. 454/// The uppercase 'E' tag is used in NIP-22 for comment events.
454///
455/// # Note
456/// This test is currently ignored because Layer 3 sync is not yet implemented.
457/// The test logic is complete and will work when Layer 3 sync is enabled.
458///
459/// TODO: Enable this test when Layer 3 sync is implemented.
460#[tokio::test] 455#[tokio::test]
461#[ignore = "Layer 3 sync not yet implemented - comments don't sync via discovery"]
462async fn test_layer3_sync_with_uppercase_e_tag() { 456async fn test_layer3_sync_with_uppercase_e_tag() {
463 // 1. Start relays 457 // 1. Start relays
464 let relay_a = TestRelay::start().await; 458 let relay_a = TestRelay::start().await;
@@ -528,6 +522,14 @@ async fn test_layer3_sync_with_uppercase_e_tag() {
528 println!("Issue synced to relay_b: {}", issue_synced); 522 println!("Issue synced to relay_b: {}", issue_synced);
529 assert!(issue_synced, "Layer 2 issue should sync first"); 523 assert!(issue_synced, "Layer 2 issue should sync first");
530 524
525 // Wait for Layer 3 subscriptions to be established
526 // After issue syncs, relay_b's SelfSubscriber needs time to:
527 // 1. Receive the synced issue via notify_event broadcast
528 // 2. Batch timer to tick (up to 200ms in tests)
529 // 3. Process batch and create Layer 3 filters
530 // 4. Subscribe to relay_a with Layer 3 filters
531 tokio::time::sleep(Duration::from_millis(500)).await;
532
531 // 6. Create and send Layer 3 comment with uppercase 'E' tag (kind 1111) 533 // 6. Create and send Layer 3 comment with uppercase 'E' tag (kind 1111)
532 let comment = build_layer3_comment_with_uppercase_e_tag(&keys, &issue_id, "Comment with uppercase E tag") 534 let comment = build_layer3_comment_with_uppercase_e_tag(&keys, &issue_id, "Comment with uppercase E tag")
533 .expect("Failed to create comment"); 535 .expect("Failed to create comment");
@@ -573,14 +575,7 @@ async fn test_layer3_sync_with_uppercase_e_tag() {
573/// tags sync correctly between relays when referencing a Layer 2 event. 575/// tags sync correctly between relays when referencing a Layer 2 event.
574/// 576///
575/// The 'q' tag is used in NIP-18 for quotes/reposts. 577/// The 'q' tag is used in NIP-18 for quotes/reposts.
576///
577/// # Note
578/// This test is currently ignored because Layer 3 sync is not yet implemented.
579/// The test logic is complete and will work when Layer 3 sync is enabled.
580///
581/// TODO: Enable this test when Layer 3 sync is implemented.
582#[tokio::test] 578#[tokio::test]
583#[ignore = "Layer 3 sync not yet implemented - comments don't sync via discovery"]
584async fn test_layer3_sync_with_q_tag() { 579async fn test_layer3_sync_with_q_tag() {
585 // 1. Start relays 580 // 1. Start relays
586 let relay_a = TestRelay::start().await; 581 let relay_a = TestRelay::start().await;
@@ -650,6 +645,14 @@ async fn test_layer3_sync_with_q_tag() {
650 println!("Issue synced to relay_b: {}", issue_synced); 645 println!("Issue synced to relay_b: {}", issue_synced);
651 assert!(issue_synced, "Layer 2 issue should sync first"); 646 assert!(issue_synced, "Layer 2 issue should sync first");
652 647
648 // Wait for Layer 3 subscriptions to be established
649 // After issue syncs, relay_b's SelfSubscriber needs time to:
650 // 1. Receive the synced issue via notify_event broadcast
651 // 2. Batch timer to tick (up to 200ms in tests)
652 // 3. Process batch and create Layer 3 filters
653 // 4. Subscribe to relay_a with Layer 3 filters
654 tokio::time::sleep(Duration::from_millis(500)).await;
655
653 // 6. Create and send Layer 3 quote with 'q' tag (kind 1) 656 // 6. Create and send Layer 3 quote with 'q' tag (kind 1)
654 let quote = build_layer3_quote_with_q_tag(&keys, &issue_id, "Quote with q tag") 657 let quote = build_layer3_quote_with_q_tag(&keys, &issue_id, "Quote with q tag")
655 .expect("Failed to create quote"); 658 .expect("Failed to create quote");