diff options
| -rw-r--r-- | tests/common/relay.rs | 11 | ||||
| -rw-r--r-- | tests/purgatory_sync.rs | 209 |
2 files changed, 143 insertions, 77 deletions
diff --git a/tests/common/relay.rs b/tests/common/relay.rs index 227849a..0ec9a2e 100644 --- a/tests/common/relay.rs +++ b/tests/common/relay.rs | |||
| @@ -213,8 +213,15 @@ impl TestRelay { | |||
| 213 | "RUST_LOG", | 213 | "RUST_LOG", |
| 214 | std::env::var("RUST_LOG").unwrap_or_else(|_| "info".to_string()), | 214 | std::env::var("RUST_LOG").unwrap_or_else(|_| "info".to_string()), |
| 215 | ) // Use RUST_LOG from environment or default to info | 215 | ) // Use RUST_LOG from environment or default to info |
| 216 | .stdout(Stdio::null()) // Suppress stdout for cleaner test output | 216 | .stdout( |
| 217 | .stderr(Stdio::null()); // Suppress stderr for cleaner test output | 217 | std::fs::OpenOptions::new() |
| 218 | .create(true) | ||
| 219 | .append(true) | ||
| 220 | .open(format!("/tmp/relay-{}.log", port)) | ||
| 221 | .map(Stdio::from) | ||
| 222 | .unwrap_or(Stdio::null()), | ||
| 223 | ) | ||
| 224 | .stderr(Stdio::inherit()); // Inherit stderr for test output | ||
| 218 | 225 | ||
| 219 | // Add bootstrap relay URL if provided | 226 | // Add bootstrap relay URL if provided |
| 220 | if let Some(ref bootstrap_url) = bootstrap_relay_url { | 227 | if let Some(ref bootstrap_url) = bootstrap_relay_url { |
diff --git a/tests/purgatory_sync.rs b/tests/purgatory_sync.rs index 72f3d81..304865d 100644 --- a/tests/purgatory_sync.rs +++ b/tests/purgatory_sync.rs | |||
| @@ -282,15 +282,20 @@ async fn test_state_event_syncs_from_remote() { | |||
| 282 | /// Test that a PR event entering purgatory triggers remote commit fetch | 282 | /// Test that a PR event entering purgatory triggers remote commit fetch |
| 283 | /// and is released once the commit is available. | 283 | /// and is released once the commit is available. |
| 284 | /// | 284 | /// |
| 285 | /// Scenario: | 285 | /// Flow on source relay: |
| 286 | /// 1. Start source relay with repository announcement | 286 | /// 1. Send announcement → purgatory (StateOnly - no git data yet) |
| 287 | /// 2. Create PR event (goes to purgatory - no git data yet) | 287 | /// 2. Send state event → purgatory (refs point to non-existent commits) |
| 288 | /// 3. Push commit to refs/nostr/<event-id> (authorized by PR event in purgatory) | 288 | /// 3. Push git data → promotes announcement to Full + releases state event |
| 289 | /// 4. PR event gets released from purgatory on source relay | 289 | /// 4. Send PR event → purgatory (announcement now Full, so PR events accepted) |
| 290 | /// 5. Start syncing relay | 290 | /// 5. Push PR commit → releases PR event |
| 291 | /// 6. Syncing relay syncs PR event (goes to purgatory - no local git data) | 291 | /// |
| 292 | /// 7. Syncing relay fetches commit from source's clone URL | 292 | /// Flow on syncing relay: |
| 293 | /// 8. Verify PR event is released and refs/nostr/<event-id> created on syncing relay | 293 | /// 6. Start syncing relay |
| 294 | /// 7. Syncs announcement → purgatory (StateOnly) | ||
| 295 | /// 8. Syncs state event → purgatory | ||
| 296 | /// 9. Fetches git data → promotes announcement (Full) + releases state event | ||
| 297 | /// 10. Syncs PR event → purgatory (announcement now Full) | ||
| 298 | /// 11. Fetches PR commit → releases PR event | ||
| 294 | #[tokio::test] | 299 | #[tokio::test] |
| 295 | async fn test_pr_event_syncs_from_remote() { | 300 | async fn test_pr_event_syncs_from_remote() { |
| 296 | // 1. Start source relay | 301 | // 1. Start source relay |
| @@ -313,8 +318,7 @@ async fn test_pr_event_syncs_from_remote() { | |||
| 313 | .to_bech32() | 318 | .to_bech32() |
| 314 | .expect("Failed to get npub"); | 319 | .expect("Failed to get npub"); |
| 315 | 320 | ||
| 316 | // 3. Create and send announcement listing BOTH relays | 321 | // 3. Create announcement listing BOTH relays |
| 317 | // This ensures the syncing relay will accept the PR event when it syncs | ||
| 318 | let announcement = create_repo_announcement( | 322 | let announcement = create_repo_announcement( |
| 319 | &owner_keys, | 323 | &owner_keys, |
| 320 | &[&source_relay.domain(), &syncing_domain], | 324 | &[&source_relay.domain(), &syncing_domain], |
| @@ -331,7 +335,7 @@ async fn test_pr_event_syncs_from_remote() { | |||
| 331 | // Wait for connection | 335 | // Wait for connection |
| 332 | tokio::time::sleep(Duration::from_millis(500)).await; | 336 | tokio::time::sleep(Duration::from_millis(500)).await; |
| 333 | 337 | ||
| 334 | // Send announcement to source relay (creates bare repo) | 338 | // Step 1: Send announcement to source relay → purgatory (StateOnly) |
| 335 | source_client | 339 | source_client |
| 336 | .send_event(&announcement) | 340 | .send_event(&announcement) |
| 337 | .await | 341 | .await |
| @@ -339,8 +343,52 @@ async fn test_pr_event_syncs_from_remote() { | |||
| 339 | 343 | ||
| 340 | tokio::time::sleep(Duration::from_millis(200)).await; | 344 | tokio::time::sleep(Duration::from_millis(200)).await; |
| 341 | 345 | ||
| 342 | // 4. Create and send PR event BEFORE pushing | 346 | // Step 2: Create and send state event → purgatory (no git data yet) |
| 343 | // The PR event goes to purgatory on source relay, which authorizes the push | 347 | let clone_urls = [ |
| 348 | format!( | ||
| 349 | "http://{}/{}/{}.git", | ||
| 350 | source_relay.domain(), | ||
| 351 | npub, | ||
| 352 | identifier | ||
| 353 | ), | ||
| 354 | format!("http://{}/{}/{}.git", syncing_domain, npub, identifier), | ||
| 355 | ]; | ||
| 356 | let relay_urls = [ | ||
| 357 | source_relay.url().to_string(), | ||
| 358 | format!("ws://{}", syncing_domain), | ||
| 359 | ]; | ||
| 360 | |||
| 361 | let state_event = create_state_event( | ||
| 362 | &owner_keys, | ||
| 363 | identifier, | ||
| 364 | &[("main", &commit_hash)], | ||
| 365 | &[], | ||
| 366 | &[&clone_urls[0], &clone_urls[1]], | ||
| 367 | &[&relay_urls[0], &relay_urls[1]], | ||
| 368 | ) | ||
| 369 | .expect("Failed to create state event"); | ||
| 370 | |||
| 371 | let state_event_id = state_event.id; | ||
| 372 | |||
| 373 | source_client | ||
| 374 | .send_event(&state_event) | ||
| 375 | .await | ||
| 376 | .expect("Failed to send state event to source"); | ||
| 377 | |||
| 378 | tokio::time::sleep(Duration::from_millis(200)).await; | ||
| 379 | |||
| 380 | // Step 3: Push git data to source relay | ||
| 381 | // This promotes the announcement from StateOnly to Full AND releases state event | ||
| 382 | push_to_relay(temp_dir.path(), &source_relay.domain(), &npub, identifier) | ||
| 383 | .expect("Push to source should succeed"); | ||
| 384 | |||
| 385 | // Wait for state event to be released from purgatory on source relay | ||
| 386 | wait_for_event_served(source_relay.url(), &state_event_id, Duration::from_secs(5)) | ||
| 387 | .await | ||
| 388 | .expect("State event should be served on source relay after push"); | ||
| 389 | |||
| 390 | // Step 4: Create and send PR event → purgatory | ||
| 391 | // NOW the announcement is promoted (Full), so PR events are accepted | ||
| 344 | let repo_coord = build_repo_coord(&owner_keys, identifier); | 392 | let repo_coord = build_repo_coord(&owner_keys, identifier); |
| 345 | 393 | ||
| 346 | let pr_event = create_pr_event( | 394 | let pr_event = create_pr_event( |
| @@ -367,11 +415,10 @@ async fn test_pr_event_syncs_from_remote() { | |||
| 367 | .await | 415 | .await |
| 368 | .expect("Failed to send PR event to source"); | 416 | .expect("Failed to send PR event to source"); |
| 369 | 417 | ||
| 370 | // Small delay to ensure PR event is processed into purgatory | ||
| 371 | tokio::time::sleep(Duration::from_millis(200)).await; | 418 | tokio::time::sleep(Duration::from_millis(200)).await; |
| 372 | 419 | ||
| 373 | // 5. Push commit to refs/nostr/<event-id> on source relay | 420 | // Step 5: Push PR commit to refs/nostr/<event-id> on source relay |
| 374 | // The PR event in purgatory authorizes this push | 421 | // This releases the PR event from purgatory |
| 375 | let ref_name = format!("refs/nostr/{}", pr_event_id.to_hex()); | 422 | let ref_name = format!("refs/nostr/{}", pr_event_id.to_hex()); |
| 376 | push_ref_to_relay( | 423 | push_ref_to_relay( |
| 377 | temp_dir.path(), | 424 | temp_dir.path(), |
| @@ -383,12 +430,12 @@ async fn test_pr_event_syncs_from_remote() { | |||
| 383 | ) | 430 | ) |
| 384 | .expect("Push to refs/nostr/<event-id> should succeed"); | 431 | .expect("Push to refs/nostr/<event-id> should succeed"); |
| 385 | 432 | ||
| 386 | // After push, PR event should be released from purgatory on source relay | 433 | // Wait for PR event to be released from purgatory on source relay |
| 387 | wait_for_event_served(source_relay.url(), &pr_event_id, Duration::from_secs(5)) | 434 | wait_for_event_served(source_relay.url(), &pr_event_id, Duration::from_secs(5)) |
| 388 | .await | 435 | .await |
| 389 | .expect("PR event should be served on source relay after push"); | 436 | .expect("PR event should be served on source relay after push"); |
| 390 | 437 | ||
| 391 | // 6. Start syncing relay (syncs from source) | 438 | // Step 6: Start syncing relay (syncs from source) |
| 392 | let syncing_relay = TestRelay::start_on_port_with_options( | 439 | let syncing_relay = TestRelay::start_on_port_with_options( |
| 393 | syncing_port, | 440 | syncing_port, |
| 394 | Some(source_relay.url().to_string()), | 441 | Some(source_relay.url().to_string()), |
| @@ -401,14 +448,13 @@ async fn test_pr_event_syncs_from_remote() { | |||
| 401 | .await | 448 | .await |
| 402 | .expect("Sync connection should establish"); | 449 | .expect("Sync connection should establish"); |
| 403 | 450 | ||
| 404 | // 7. Wait for PR event to be released on syncing relay | 451 | // Steps 7-11: Syncing relay syncs events |
| 405 | // The sync should: | 452 | // The sync should: |
| 406 | // a) Fetch the announcement and PR event from source relay | 453 | // a) Sync announcement → purgatory (StateOnly) |
| 407 | // b) Accept announcement (creates bare repo structure) | 454 | // b) Sync state event → purgatory |
| 408 | // c) Put PR event in purgatory (commit missing on syncing relay) | 455 | // c) Fetch git data → promotes announcement (Full) + releases state event |
| 409 | // d) Fetch commit from source relay's clone URL | 456 | // d) Sync PR event → purgatory (announcement now Full) |
| 410 | // e) Release the PR event from purgatory | 457 | // e) Fetch PR commit → releases PR event |
| 411 | // f) Create refs/nostr/<event-id> pointing to the commit | ||
| 412 | let found = wait_for_event_served( | 458 | let found = wait_for_event_served( |
| 413 | syncing_relay.url(), | 459 | syncing_relay.url(), |
| 414 | &pr_event_id, | 460 | &pr_event_id, |
| @@ -422,7 +468,7 @@ async fn test_pr_event_syncs_from_remote() { | |||
| 422 | found.err() | 468 | found.err() |
| 423 | ); | 469 | ); |
| 424 | 470 | ||
| 425 | // 8. Verify refs/nostr/<event-id> was created on syncing relay | 471 | // Verify refs/nostr/<event-id> was created on syncing relay |
| 426 | let ref_correct = | 472 | let ref_correct = |
| 427 | check_ref_at_commit(&syncing_domain, &npub, identifier, &ref_name, &commit_hash) | 473 | check_ref_at_commit(&syncing_domain, &npub, identifier, &ref_name, &commit_hash) |
| 428 | .await | 474 | .await |
| @@ -443,14 +489,20 @@ async fn test_pr_event_syncs_from_remote() { | |||
| 443 | /// Test that concurrent state and PR events for the same repository | 489 | /// Test that concurrent state and PR events for the same repository |
| 444 | /// both sync correctly. | 490 | /// both sync correctly. |
| 445 | /// | 491 | /// |
| 446 | /// Scenario: | 492 | /// Flow on source relay: |
| 447 | /// 1. Start source relay with repo containing two commits (main branch + PR commit) | 493 | /// 1. Send announcement → purgatory (StateOnly - no git data yet) |
| 448 | /// 2. Create and push both commits to source relay | 494 | /// 2. Send state event → purgatory (refs point to non-existent commits) |
| 449 | /// 3. Send both state event and PR event to source relay | 495 | /// 3. Push git data → promotes announcement to Full + releases state event |
| 450 | /// 4. Start syncing relay | 496 | /// 4. THEN send PR event → purgatory (announcement now Full, so PR events accepted) |
| 451 | /// 5. Wait for sync to fetch git data and release both events | 497 | /// 5. Push PR commit → releases PR event |
| 452 | /// 6. Verify both state event and PR event are served | 498 | /// |
| 453 | /// 7. Verify refs are correct for both (main branch and refs/nostr/<event-id>) | 499 | /// Flow on syncing relay: |
| 500 | /// 6. Start syncing relay | ||
| 501 | /// 7. Syncs announcement → purgatory (StateOnly) | ||
| 502 | /// 8. Syncs state event → purgatory | ||
| 503 | /// 9. Fetches git data → promotes announcement (Full) + releases state event | ||
| 504 | /// 10. Syncs PR event → purgatory (announcement now Full) | ||
| 505 | /// 11. Fetches PR commit → releases PR event | ||
| 454 | #[tokio::test] | 506 | #[tokio::test] |
| 455 | async fn test_concurrent_state_and_pr_sync() { | 507 | async fn test_concurrent_state_and_pr_sync() { |
| 456 | // 1. Start source relay | 508 | // 1. Start source relay |
| @@ -464,15 +516,13 @@ async fn test_concurrent_state_and_pr_sync() { | |||
| 464 | let syncing_domain = format!("127.0.0.1:{}", syncing_port); | 516 | let syncing_domain = format!("127.0.0.1:{}", syncing_port); |
| 465 | 517 | ||
| 466 | // 2. Create test repository with two commits | 518 | // 2. Create test repository with two commits |
| 467 | // First commit establishes the repo, second commit is used for both state and PR events | 519 | // First commit establishes the repo (for state event), second commit is for PR |
| 468 | let temp_dir = tempfile::tempdir().expect("Failed to create temp dir"); | 520 | let temp_dir = tempfile::tempdir().expect("Failed to create temp dir"); |
| 469 | let _first_commit = create_test_repo_with_commit(temp_dir.path(), CommitVariant::StateTest) | 521 | let _state_commit = create_test_repo_with_commit(temp_dir.path(), CommitVariant::StateTest) |
| 470 | .expect("Failed to create test repo"); | 522 | .expect("Failed to create test repo"); |
| 471 | 523 | ||
| 472 | // Add second commit - this becomes HEAD of main and is referenced by both events | 524 | // Add second commit - this is used for the PR event |
| 473 | // In a real scenario, the state event would reference the current branch state, | 525 | let pr_commit = |
| 474 | // and the PR would propose changes (which happen to be the same commit here for simplicity) | ||
| 475 | let head_commit = | ||
| 476 | add_commit_to_repo(temp_dir.path(), CommitVariant::PrTest).expect("Failed to add commit"); | 526 | add_commit_to_repo(temp_dir.path(), CommitVariant::PrTest).expect("Failed to add commit"); |
| 477 | 527 | ||
| 478 | let npub = owner_keys | 528 | let npub = owner_keys |
| @@ -480,7 +530,7 @@ async fn test_concurrent_state_and_pr_sync() { | |||
| 480 | .to_bech32() | 530 | .to_bech32() |
| 481 | .expect("Failed to get npub"); | 531 | .expect("Failed to get npub"); |
| 482 | 532 | ||
| 483 | // 3. Create and send announcement listing BOTH relays | 533 | // 3. Create announcement listing BOTH relays |
| 484 | let announcement = create_repo_announcement( | 534 | let announcement = create_repo_announcement( |
| 485 | &owner_keys, | 535 | &owner_keys, |
| 486 | &[&source_relay.domain(), &syncing_domain], | 536 | &[&source_relay.domain(), &syncing_domain], |
| @@ -497,7 +547,7 @@ async fn test_concurrent_state_and_pr_sync() { | |||
| 497 | // Wait for connection | 547 | // Wait for connection |
| 498 | tokio::time::sleep(Duration::from_millis(500)).await; | 548 | tokio::time::sleep(Duration::from_millis(500)).await; |
| 499 | 549 | ||
| 500 | // Send announcement to source relay (creates bare repo) | 550 | // Step 1: Send announcement to source relay → purgatory (StateOnly) |
| 501 | source_client | 551 | source_client |
| 502 | .send_event(&announcement) | 552 | .send_event(&announcement) |
| 503 | .await | 553 | .await |
| @@ -505,8 +555,7 @@ async fn test_concurrent_state_and_pr_sync() { | |||
| 505 | 555 | ||
| 506 | tokio::time::sleep(Duration::from_millis(200)).await; | 556 | tokio::time::sleep(Duration::from_millis(200)).await; |
| 507 | 557 | ||
| 508 | // 4. Create state event referencing the HEAD commit (pr_commit) | 558 | // Step 2: Create and send state event → purgatory (no git data yet) |
| 509 | // After add_commit_to_repo, main points to pr_commit (which includes state_commit in history) | ||
| 510 | let clone_urls = [ | 559 | let clone_urls = [ |
| 511 | format!( | 560 | format!( |
| 512 | "http://{}/{}/{}.git", | 561 | "http://{}/{}/{}.git", |
| @@ -521,11 +570,13 @@ async fn test_concurrent_state_and_pr_sync() { | |||
| 521 | format!("ws://{}", syncing_domain), | 570 | format!("ws://{}", syncing_domain), |
| 522 | ]; | 571 | ]; |
| 523 | 572 | ||
| 524 | // State event references main at head_commit (the current HEAD) | 573 | // State event references main at pr_commit (HEAD after add_commit_to_repo). |
| 574 | // push_to_relay uses `git push --all` which pushes main -> pr_commit (HEAD), | ||
| 575 | // so the state event must reference pr_commit for push validation to succeed. | ||
| 525 | let state_event = create_state_event( | 576 | let state_event = create_state_event( |
| 526 | &owner_keys, | 577 | &owner_keys, |
| 527 | identifier, | 578 | identifier, |
| 528 | &[("main", &head_commit)], | 579 | &[("main", &pr_commit)], |
| 529 | &[], | 580 | &[], |
| 530 | &[&clone_urls[0], &clone_urls[1]], | 581 | &[&clone_urls[0], &clone_urls[1]], |
| 531 | &[&relay_urls[0], &relay_urls[1]], | 582 | &[&relay_urls[0], &relay_urls[1]], |
| @@ -534,20 +585,31 @@ async fn test_concurrent_state_and_pr_sync() { | |||
| 534 | 585 | ||
| 535 | let state_event_id = state_event.id; | 586 | let state_event_id = state_event.id; |
| 536 | 587 | ||
| 537 | // Send state event to source relay (goes to purgatory - no git data yet) | ||
| 538 | source_client | 588 | source_client |
| 539 | .send_event(&state_event) | 589 | .send_event(&state_event) |
| 540 | .await | 590 | .await |
| 541 | .expect("Failed to send state event to source"); | 591 | .expect("Failed to send state event to source"); |
| 542 | 592 | ||
| 543 | // 5. Create PR event referencing the same commit (head_commit) | 593 | tokio::time::sleep(Duration::from_millis(200)).await; |
| 544 | // This simulates a PR that proposes the changes in head_commit | 594 | |
| 595 | // Step 3: Push git data to source relay | ||
| 596 | // This promotes the announcement from StateOnly to Full AND releases state event | ||
| 597 | push_to_relay(temp_dir.path(), &source_relay.domain(), &npub, identifier) | ||
| 598 | .expect("Push to source should succeed"); | ||
| 599 | |||
| 600 | // Wait for state event to be released from purgatory on source relay | ||
| 601 | wait_for_event_served(source_relay.url(), &state_event_id, Duration::from_secs(5)) | ||
| 602 | .await | ||
| 603 | .expect("State event should be served on source relay after push"); | ||
| 604 | |||
| 605 | // Step 4: Create and send PR event → purgatory | ||
| 606 | // NOW the announcement is promoted (Full), so PR events are accepted | ||
| 545 | let repo_coord = build_repo_coord(&owner_keys, identifier); | 607 | let repo_coord = build_repo_coord(&owner_keys, identifier); |
| 546 | 608 | ||
| 547 | let pr_event = create_pr_event( | 609 | let pr_event = create_pr_event( |
| 548 | &pr_author_keys, | 610 | &pr_author_keys, |
| 549 | &repo_coord, | 611 | &repo_coord, |
| 550 | &head_commit, | 612 | &pr_commit, |
| 551 | "Test PR for concurrent sync", | 613 | "Test PR for concurrent sync", |
| 552 | ) | 614 | ) |
| 553 | .expect("Failed to create PR event"); | 615 | .expect("Failed to create PR event"); |
| @@ -570,33 +632,25 @@ async fn test_concurrent_state_and_pr_sync() { | |||
| 570 | 632 | ||
| 571 | tokio::time::sleep(Duration::from_millis(200)).await; | 633 | tokio::time::sleep(Duration::from_millis(200)).await; |
| 572 | 634 | ||
| 573 | // 6. Push git data to source relay | 635 | // Step 5: Push PR commit to refs/nostr/<event-id> on source relay |
| 574 | // Push all branches (main contains both commits due to linear history) | 636 | // This releases the PR event from purgatory |
| 575 | push_to_relay(temp_dir.path(), &source_relay.domain(), &npub, identifier) | ||
| 576 | .expect("Push to source should succeed"); | ||
| 577 | |||
| 578 | // Also push the PR ref | ||
| 579 | let pr_ref_name = format!("refs/nostr/{}", pr_event_id.to_hex()); | 637 | let pr_ref_name = format!("refs/nostr/{}", pr_event_id.to_hex()); |
| 580 | push_ref_to_relay( | 638 | push_ref_to_relay( |
| 581 | temp_dir.path(), | 639 | temp_dir.path(), |
| 582 | &source_relay.domain(), | 640 | &source_relay.domain(), |
| 583 | &npub, | 641 | &npub, |
| 584 | identifier, | 642 | identifier, |
| 585 | &head_commit, | 643 | &pr_commit, |
| 586 | &pr_ref_name, | 644 | &pr_ref_name, |
| 587 | ) | 645 | ) |
| 588 | .expect("Push PR ref to source should succeed"); | 646 | .expect("Push PR ref to source should succeed"); |
| 589 | 647 | ||
| 590 | // After push, both events should be released from purgatory on source relay | 648 | // Wait for PR event to be released from purgatory on source relay |
| 591 | wait_for_event_served(source_relay.url(), &state_event_id, Duration::from_secs(5)) | ||
| 592 | .await | ||
| 593 | .expect("State event should be served on source relay after push"); | ||
| 594 | |||
| 595 | wait_for_event_served(source_relay.url(), &pr_event_id, Duration::from_secs(5)) | 649 | wait_for_event_served(source_relay.url(), &pr_event_id, Duration::from_secs(5)) |
| 596 | .await | 650 | .await |
| 597 | .expect("PR event should be served on source relay after push"); | 651 | .expect("PR event should be served on source relay after push"); |
| 598 | 652 | ||
| 599 | // 7. Start syncing relay (syncs from source) | 653 | // Step 6: Start syncing relay (syncs from source) |
| 600 | let syncing_relay = TestRelay::start_on_port_with_options( | 654 | let syncing_relay = TestRelay::start_on_port_with_options( |
| 601 | syncing_port, | 655 | syncing_port, |
| 602 | Some(source_relay.url().to_string()), | 656 | Some(source_relay.url().to_string()), |
| @@ -609,8 +663,13 @@ async fn test_concurrent_state_and_pr_sync() { | |||
| 609 | .await | 663 | .await |
| 610 | .expect("Sync connection should establish"); | 664 | .expect("Sync connection should establish"); |
| 611 | 665 | ||
| 612 | // 8. Wait for BOTH events to be released on syncing relay | 666 | // Steps 7-11: Syncing relay syncs events |
| 613 | // The sync should fetch git data and release both events | 667 | // The sync should: |
| 668 | // a) Sync announcement → purgatory (StateOnly) | ||
| 669 | // b) Sync state event → purgatory | ||
| 670 | // c) Fetch git data → promotes announcement (Full) + releases state event | ||
| 671 | // d) Sync PR event → purgatory (announcement now Full) | ||
| 672 | // e) Fetch PR commit → releases PR event | ||
| 614 | let state_found = wait_for_event_served( | 673 | let state_found = wait_for_event_served( |
| 615 | syncing_relay.url(), | 674 | syncing_relay.url(), |
| 616 | &state_event_id, | 675 | &state_event_id, |
| @@ -629,18 +688,18 @@ async fn test_concurrent_state_and_pr_sync() { | |||
| 629 | 688 | ||
| 630 | assert!( | 689 | assert!( |
| 631 | pr_found.is_ok(), | 690 | pr_found.is_ok(), |
| 632 | "PR event should be served after sync fetches git data: {:?}", | 691 | "PR event should be served after sync fetches commit: {:?}", |
| 633 | pr_found.err() | 692 | pr_found.err() |
| 634 | ); | 693 | ); |
| 635 | 694 | ||
| 636 | // 9. Verify refs are correct on syncing relay | 695 | // Verify refs are correct on syncing relay |
| 637 | // Check main branch points to head_commit (the HEAD) | 696 | // Check main branch points to pr_commit (HEAD after both commits) |
| 638 | let main_ref_correct = check_ref_at_commit( | 697 | let main_ref_correct = check_ref_at_commit( |
| 639 | &syncing_domain, | 698 | &syncing_domain, |
| 640 | &npub, | 699 | &npub, |
| 641 | identifier, | 700 | identifier, |
| 642 | "refs/heads/main", | 701 | "refs/heads/main", |
| 643 | &head_commit, | 702 | &pr_commit, // After push, main points to pr_commit (HEAD) |
| 644 | ) | 703 | ) |
| 645 | .await | 704 | .await |
| 646 | .expect("Failed to check main ref"); | 705 | .expect("Failed to check main ref"); |
| @@ -648,24 +707,24 @@ async fn test_concurrent_state_and_pr_sync() { | |||
| 648 | assert!( | 707 | assert!( |
| 649 | main_ref_correct, | 708 | main_ref_correct, |
| 650 | "main branch should point to HEAD commit ({})", | 709 | "main branch should point to HEAD commit ({})", |
| 651 | head_commit | 710 | pr_commit |
| 652 | ); | 711 | ); |
| 653 | 712 | ||
| 654 | // Check refs/nostr/<event-id> points to the same commit | 713 | // Check refs/nostr/<event-id> points to pr_commit |
| 655 | let pr_ref_correct = check_ref_at_commit( | 714 | let pr_ref_correct = check_ref_at_commit( |
| 656 | &syncing_domain, | 715 | &syncing_domain, |
| 657 | &npub, | 716 | &npub, |
| 658 | identifier, | 717 | identifier, |
| 659 | &pr_ref_name, | 718 | &pr_ref_name, |
| 660 | &head_commit, | 719 | &pr_commit, |
| 661 | ) | 720 | ) |
| 662 | .await | 721 | .await |
| 663 | .expect("Failed to check PR ref"); | 722 | .expect("Failed to check PR ref"); |
| 664 | 723 | ||
| 665 | assert!( | 724 | assert!( |
| 666 | pr_ref_correct, | 725 | pr_ref_correct, |
| 667 | "refs/nostr/<event-id> should point to commit ({})", | 726 | "refs/nostr/<event-id> should point to PR commit ({})", |
| 668 | head_commit | 727 | pr_commit |
| 669 | ); | 728 | ); |
| 670 | 729 | ||
| 671 | // Cleanup | 730 | // Cleanup |