upleb.uk

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

summaryrefslogtreecommitdiff
path: root/grasp-audit
diff options
context:
space:
mode:
authorDanConwayDev <DanConwayDev@protonmail.com>2026-02-13 09:24:51 +0000
committerDanConwayDev <DanConwayDev@protonmail.com>2026-02-13 09:24:51 +0000
commitf4e8e1089ae6e8e78c3576246d9747bb585fdc18 (patch)
tree37cd429b6c5468996178f1d9bbaafe6f789b3605 /grasp-audit
parentfaac6027deaf5f1e121c05df2d8a6336fd6eaf8d (diff)
test: add PR purgatory tests with PREvent2 fixtures
Add new fixtures for testing PR purgatory mechanism: - PREvent2Generated: PR event with different commit hash - PREvent2Sent: PR event sent to relay (enters purgatory) - PREvent2GitDataPushed: Git data pushed after event sent - PREvent2Served: Full fixture with event served Add PRTestCommit2 variant for second PR test commit. Update purgatory tests to use new fixtures for proper PR purgatory testing.
Diffstat (limited to 'grasp-audit')
-rw-r--r--grasp-audit/src/fixtures.rs242
-rw-r--r--grasp-audit/src/specs/grasp01/purgatory.rs144
2 files changed, 336 insertions, 50 deletions
diff --git a/grasp-audit/src/fixtures.rs b/grasp-audit/src/fixtures.rs
index 56d29ef..8a51d77 100644
--- a/grasp-audit/src/fixtures.rs
+++ b/grasp-audit/src/fixtures.rs
@@ -103,6 +103,17 @@ pub const RECURSIVE_MAINTAINER_DETERMINISTIC_COMMIT_HASH: &str =
103/// - Parent: none (root commit) 103/// - Parent: none (root commit)
104pub const PR_TEST_COMMIT_HASH: &str = "5a51b30e4615b572dcd5b9e487861b58605a5c21"; 104pub const PR_TEST_COMMIT_HASH: &str = "5a51b30e4615b572dcd5b9e487861b58605a5c21";
105 105
106/// Deterministic commit hash for second PR test fixtures (PRTestCommit2 variant)
107/// This is the hash produced by creating a commit with:
108/// - Message: "PR test deterministic commit 2"
109/// - File: test.txt containing "PR test deterministic commit 2\n" (with trailing newline)
110/// - Author date: 2024-01-01T00:00:00Z
111/// - Committer date: 2024-01-01T00:00:00Z
112/// - GPG signing: disabled
113/// - User: "GRASP Audit Test <test@grasp-audit.local>"
114/// - Parent: none (root commit)
115pub const PR_TEST_COMMIT_HASH_2: &str = "99420bc57835f5bc8ca20ab21a8d12850043920e";
116
106/// Types of test fixtures available 117/// Types of test fixtures available
107/// 118///
108/// ## Fixture Dependencies 119/// ## Fixture Dependencies
@@ -216,6 +227,50 @@ pub enum FixtureKind {
216 /// - Returns: the sent PR event 227 /// - Returns: the sent PR event
217 PREventSentAfterWrongPush, 228 PREventSentAfterWrongPush,
218 229
230 /// Second PR event generated (built) but NOT sent to relay
231 ///
232 /// Uses PR_TEST_COMMIT_HASH_2 (different from PR_TEST_COMMIT_HASH).
233 /// This allows testing purgatory mechanism with a separate PR event
234 /// that doesn't conflict with existing PR fixtures.
235 ///
236 /// - Requires ValidRepoServed (uses same repo_id, needs git data to exist)
237 /// - Signed by `client.pr_author_keys()`
238 /// - Kind 1618 (NIP-34 PR)
239 /// - Includes `c` tag pointing to PR_TEST_COMMIT_HASH_2
240 /// - NOT sent to relay
241 PREvent2Generated,
242
243 /// Second PR event sent to relay (enters purgatory)
244 ///
245 /// After this fixture:
246 /// - PR event is on relay but NOT served (in purgatory)
247 /// - No git data at refs/nostr/<pr-event-id>
248 ///
249 /// - Requires PREvent2Generated
250 /// - Sends the PR event to relay
251 /// - Returns: the sent PR event (in purgatory)
252 PREvent2Sent,
253
254 /// Git data pushed for second PR event AFTER event was sent
255 ///
256 /// After this fixture:
257 /// - PR event was in purgatory
258 /// - Correct commit pushed to refs/nostr/<pr-event-id>
259 /// - PR event should be released from purgatory
260 ///
261 /// - Requires PREvent2Sent
262 /// - Pushes correct commit (PR_TEST_COMMIT_HASH_2) to refs/nostr/<pr-event-id>
263 /// - Returns: the PR event (should now be served)
264 PREvent2GitDataPushed,
265
266 /// Full fixture: second PR event sent, git pushed, event served
267 ///
268 /// Combines PREvent2Sent + PREvent2GitDataPushed for convenience.
269 ///
270 /// - Requires PREvent2GitDataPushed
271 /// - Returns: the served PR event
272 PREvent2Served,
273
219 /// Owner's state event with git data successfully pushed (full 4-stage fixture) 274 /// Owner's state event with git data successfully pushed (full 4-stage fixture)
220 /// 275 ///
221 /// This fixture represents the complete flow for testing state push authorization: 276 /// This fixture represents the complete flow for testing state push authorization:
@@ -293,6 +348,12 @@ impl FixtureKind {
293 Self::PRWrongCommitPushedBeforeEvent => vec![Self::PREventGenerated], 348 Self::PRWrongCommitPushedBeforeEvent => vec![Self::PREventGenerated],
294 Self::PREventSentAfterWrongPush => vec![Self::PRWrongCommitPushedBeforeEvent], 349 Self::PREventSentAfterWrongPush => vec![Self::PRWrongCommitPushedBeforeEvent],
295 350
351 // Second PR event fixtures (for purgatory testing)
352 Self::PREvent2Generated => vec![Self::ValidRepoServed],
353 Self::PREvent2Sent => vec![Self::PREvent2Generated],
354 Self::PREvent2GitDataPushed => vec![Self::PREvent2Sent],
355 Self::PREvent2Served => vec![Self::PREvent2GitDataPushed],
356
296 Self::OwnerStateDataPushed => vec![Self::ValidRepoSent], 357 Self::OwnerStateDataPushed => vec![Self::ValidRepoSent],
297 358
298 // Fixtures that depend on RepoWithIssue 359 // Fixtures that depend on RepoWithIssue
@@ -329,6 +390,11 @@ impl FixtureKind {
329 Self::PRWrongCommitPushedBeforeEvent => true, 390 Self::PRWrongCommitPushedBeforeEvent => true,
330 // PREventSentAfterWrongPush sends the PR event internally 391 // PREventSentAfterWrongPush sends the PR event internally
331 Self::PREventSentAfterWrongPush => true, 392 Self::PREventSentAfterWrongPush => true,
393 // Second PR event fixtures handle their own events/git data
394 Self::PREvent2Generated => true,
395 Self::PREvent2Sent => true,
396 Self::PREvent2GitDataPushed => true,
397 Self::PREvent2Served => true,
332 // HeadSetToDevelopBranch sends its state event internally 398 // HeadSetToDevelopBranch sends its state event internally
333 Self::HeadSetToDevelopBranch => true, 399 Self::HeadSetToDevelopBranch => true,
334 // ValidRepoServed doesn't send anything itself, just returns cached event 400 // ValidRepoServed doesn't send anything itself, just returns cached event
@@ -800,6 +866,11 @@ impl<'a> TestContext<'a> {
800 self.build_pr_event_sent_after_wrong_push().await 866 self.build_pr_event_sent_after_wrong_push().await
801 } 867 }
802 868
869 FixtureKind::PREvent2Generated => self.build_pr_event_2_generated().await,
870 FixtureKind::PREvent2Sent => self.build_pr_event_2_sent().await,
871 FixtureKind::PREvent2GitDataPushed => self.build_pr_event_2_git_data_pushed().await,
872 FixtureKind::PREvent2Served => self.build_pr_event_2_served().await,
873
803 FixtureKind::OwnerStateDataPushed => self.build_owner_state_data_pushed().await, 874 FixtureKind::OwnerStateDataPushed => self.build_owner_state_data_pushed().await,
804 875
805 FixtureKind::MaintainerStateDataPushed => { 876 FixtureKind::MaintainerStateDataPushed => {
@@ -1561,6 +1632,173 @@ impl<'a> TestContext<'a> {
1561 Ok(pr_event) 1632 Ok(pr_event)
1562 } 1633 }
1563 1634
1635 /// Build PREvent2Generated fixture
1636 ///
1637 /// Creates a PR event with `c` tag pointing to PR_TEST_COMMIT_HASH_2.
1638 /// The event is NOT sent to the relay.
1639 async fn build_pr_event_2_generated(&self) -> Result<Event> {
1640 use nostr_sdk::prelude::*;
1641
1642 let repo = self.get_cached_dependency(FixtureKind::ValidRepoServed)?;
1643 let repo_id = self.extract_repo_id(&repo)?;
1644
1645 let base_time = Timestamp::now().as_secs();
1646 let pr_timestamp = Timestamp::from(base_time - 1);
1647
1648 self.client
1649 .event_builder(Kind::GitPullRequest, "Test PR 2 for GRASP validation")
1650 .tag(Tag::custom(
1651 TagKind::custom("a"),
1652 vec![format!(
1653 "30617:{}:{}",
1654 self.client.public_key().to_hex(),
1655 repo_id
1656 )],
1657 ))
1658 .tag(Tag::custom(
1659 TagKind::custom("c"),
1660 vec![PR_TEST_COMMIT_HASH_2.to_string()],
1661 ))
1662 .custom_time(pr_timestamp)
1663 .build(self.client.pr_author_keys())
1664 .map_err(|e| anyhow::anyhow!("Failed to build PR event 2: {}", e))
1665 }
1666
1667 /// Build PREvent2Sent fixture
1668 ///
1669 /// Sends the PR event to relay. Event should enter purgatory.
1670 async fn build_pr_event_2_sent(&self) -> Result<Event> {
1671 let pr_event = self.get_cached_dependency(FixtureKind::PREvent2Generated)?;
1672
1673 let (_, in_purgatory) = self
1674 .client
1675 .send_event_and_note_purgatory(pr_event.clone())
1676 .await?;
1677
1678 if !in_purgatory {
1679 return Err(anyhow::anyhow!(
1680 "PR event 2 was served immediately - purgatory not implemented"
1681 ));
1682 }
1683
1684 Ok(pr_event)
1685 }
1686
1687 /// Build PREvent2GitDataPushed fixture
1688 ///
1689 /// Pushes correct commit to refs/nostr/<pr-event-id> after event was sent.
1690 async fn build_pr_event_2_git_data_pushed(&self) -> Result<Event> {
1691 use nostr_sdk::prelude::*;
1692
1693 let pr_event = self.get_cached_dependency(FixtureKind::PREvent2Sent)?;
1694 let pr_event_id = pr_event.id.to_hex();
1695
1696 let repo = self.get_cached_dependency(FixtureKind::ValidRepoServed)?;
1697 let repo_id = self.extract_repo_id(&repo)?;
1698
1699 let relay_domain = self.get_relay_domain().await?;
1700
1701 let npub = repo
1702 .pubkey
1703 .to_bech32()
1704 .map_err(|e| anyhow::anyhow!("Failed to convert pubkey: {}", e))?;
1705
1706 let clone_path = clone_repo(&relay_domain, &npub, &repo_id)
1707 .map_err(|e| anyhow::anyhow!("Failed to clone repo: {}", e))?;
1708
1709 let cleanup = |path: &PathBuf| {
1710 let _ = fs::remove_dir_all(path);
1711 };
1712
1713 // Reset to orphan state and create deterministic root commit
1714 // Step 1: Create orphan branch (removes all history)
1715 let _ = Command::new("git")
1716 .args(["checkout", "--orphan", "pr-branch"])
1717 .current_dir(&clone_path)
1718 .output();
1719
1720 // Step 2: Clear staged files (orphan keeps files staged from previous branch)
1721 let _ = Command::new("git")
1722 .args(["rm", "-rf", "--cached", "."])
1723 .current_dir(&clone_path)
1724 .output();
1725
1726 // Step 3: Remove all working directory files for clean state (except .git)
1727 for entry in
1728 fs::read_dir(&clone_path).map_err(|e| anyhow::anyhow!("Failed to read dir: {}", e))?
1729 {
1730 if let Ok(entry) = entry {
1731 let path = entry.path();
1732 if path.file_name() != Some(std::ffi::OsStr::new(".git")) {
1733 let _ = fs::remove_file(&path).or_else(|_| fs::remove_dir_all(&path));
1734 }
1735 }
1736 }
1737
1738 let commit_hash = match create_deterministic_commit_with_variant(
1739 &clone_path,
1740 CommitVariant::PRTestCommit2,
1741 ) {
1742 Ok(h) => h,
1743 Err(e) => {
1744 cleanup(&clone_path);
1745 return Err(anyhow::anyhow!("Failed to create PR test commit 2: {}", e));
1746 }
1747 };
1748
1749 if commit_hash != PR_TEST_COMMIT_HASH_2 {
1750 cleanup(&clone_path);
1751 return Err(anyhow::anyhow!(
1752 "PR test commit 2 hash mismatch: got {}, expected {}",
1753 commit_hash,
1754 PR_TEST_COMMIT_HASH_2
1755 ));
1756 }
1757
1758 let push_output = Command::new("git")
1759 .args([
1760 "push",
1761 "origin",
1762 &format!("pr-branch:refs/nostr/{}", pr_event_id),
1763 ])
1764 .current_dir(&clone_path)
1765 .output()
1766 .map_err(|e| {
1767 cleanup(&clone_path);
1768 anyhow::anyhow!("Failed to execute git push: {}", e)
1769 })?;
1770
1771 cleanup(&clone_path);
1772
1773 if !push_output.status.success() {
1774 let stderr = String::from_utf8_lossy(&push_output.stderr);
1775 return Err(anyhow::anyhow!(
1776 "Push to refs/nostr/{} failed: {}",
1777 pr_event_id,
1778 stderr
1779 ));
1780 }
1781
1782 tokio::time::sleep(std::time::Duration::from_millis(500)).await;
1783
1784 Ok(pr_event)
1785 }
1786
1787 /// Build PREvent2Served fixture
1788 ///
1789 /// Full fixture: event sent, git pushed, event now served.
1790 async fn build_pr_event_2_served(&self) -> Result<Event> {
1791 let pr_event = self.get_cached_dependency(FixtureKind::PREvent2GitDataPushed)?;
1792
1793 if !self.client.is_event_on_relay(pr_event.id).await? {
1794 return Err(anyhow::anyhow!(
1795 "PR event 2 not released from purgatory after git push"
1796 ));
1797 }
1798
1799 Ok(pr_event)
1800 }
1801
1564 /// Get relay domain (host:port) from the connected relay 1802 /// Get relay domain (host:port) from the connected relay
1565 /// 1803 ///
1566 /// Extracts the domain from the relay URL for git HTTP operations. 1804 /// Extracts the domain from the relay URL for git HTTP operations.
@@ -1867,6 +2105,8 @@ pub enum CommitVariant {
1867 RecursiveMaintainer, 2105 RecursiveMaintainer,
1868 /// PR test commit variant - for PR event tests 2106 /// PR test commit variant - for PR event tests
1869 PRTestCommit, 2107 PRTestCommit,
2108 /// Second PR test commit variant - for second PR event tests
2109 PRTestCommit2,
1870} 2110}
1871 2111
1872impl CommitVariant { 2112impl CommitVariant {
@@ -1877,6 +2117,7 @@ impl CommitVariant {
1877 CommitVariant::Maintainer => "Maintainer initial commit\n", 2117 CommitVariant::Maintainer => "Maintainer initial commit\n",
1878 CommitVariant::RecursiveMaintainer => "Recursive maintainer initial commit\n", 2118 CommitVariant::RecursiveMaintainer => "Recursive maintainer initial commit\n",
1879 CommitVariant::PRTestCommit => "PR test deterministic commit\n", 2119 CommitVariant::PRTestCommit => "PR test deterministic commit\n",
2120 CommitVariant::PRTestCommit2 => "PR test deterministic commit 2\n",
1880 } 2121 }
1881 } 2122 }
1882 2123
@@ -1887,6 +2128,7 @@ impl CommitVariant {
1887 CommitVariant::Maintainer => "Maintainer initial commit", 2128 CommitVariant::Maintainer => "Maintainer initial commit",
1888 CommitVariant::RecursiveMaintainer => "Recursive maintainer initial commit", 2129 CommitVariant::RecursiveMaintainer => "Recursive maintainer initial commit",
1889 CommitVariant::PRTestCommit => "PR test deterministic commit", 2130 CommitVariant::PRTestCommit => "PR test deterministic commit",
2131 CommitVariant::PRTestCommit2 => "PR test deterministic commit 2",
1890 } 2132 }
1891 } 2133 }
1892} 2134}
diff --git a/grasp-audit/src/specs/grasp01/purgatory.rs b/grasp-audit/src/specs/grasp01/purgatory.rs
index 60b6096..27ab97b 100644
--- a/grasp-audit/src/specs/grasp01/purgatory.rs
+++ b/grasp-audit/src/specs/grasp01/purgatory.rs
@@ -49,9 +49,11 @@ impl PurgatoryTests {
49 results.add(Self::test_state_event_not_served_before_git_data(client).await); 49 results.add(Self::test_state_event_not_served_before_git_data(client).await);
50 results.add(Self::test_state_event_served_after_git_push(client).await); 50 results.add(Self::test_state_event_served_after_git_push(client).await);
51 51
52 // PR purgatory tests (feature not yet implemented) 52 // PR purgatory tests
53 results.add(Self::test_pr_event_not_served_before_git_data(client).await); 53 results.add(Self::test_pr_event_before_git_data_accepted_into_purgatory(client).await);
54 results.add(Self::test_pr_event_served_after_correct_push(client).await); 54 results.add(Self::test_pr_event_remains_in_purgatory_until_git_data(client).await);
55 results.add(Self::test_pr_event_git_push_accepted(client).await);
56 results.add(Self::test_pr_event_served_after_git_push(client).await);
55 57
56 results 58 results
57 } 59 }
@@ -515,37 +517,37 @@ impl PurgatoryTests {
515 /// 1. Send PR event for a repo 517 /// 1. Send PR event for a repo
516 /// 2. PR event is NOT queryable (in purgatory) 518 /// 2. PR event is NOT queryable (in purgatory)
517 /// 3. No git data exists at refs/nostr/<pr-event-id> 519 /// 3. No git data exists at refs/nostr/<pr-event-id>
518 pub async fn test_pr_event_not_served_before_git_data(client: &AuditClient) -> TestResult { 520 pub async fn test_pr_event_before_git_data_accepted_into_purgatory(
521 client: &AuditClient,
522 ) -> TestResult {
519 TestResult::new( 523 TestResult::new(
520 "pr_event_not_served_before_git_data", 524 "pr_event_before_git_data_accepted_into_purgatory",
521 SpecRef::PurgatoryAcceptUntilGitData, 525 SpecRef::PurgatoryAcceptUntilGitData,
522 "PR events SHOULD be accepted but not served until git data arrives", 526 "PR event SHOULD be accepted into purgatory when git data doesn't exist",
523 ) 527 )
524 .run(|| async { 528 .run(|| async {
525 let ctx = TestContext::new(client); 529 let ctx = TestContext::new(client);
526 530
527 // Get a repo announcement
528 let _repo = ctx
529 .get_fixture(FixtureKind::ValidRepoSent)
530 .await
531 .map_err(|e| format!("Failed to create repo: {}", e))?;
532
533 // Build PR event (not sent yet)
534 let pr_event = ctx 531 let pr_event = ctx
535 .build_fixture_only(FixtureKind::PREvent) 532 .get_fixture(FixtureKind::PREvent2Sent)
536 .await 533 .await
537 .map_err(|e| format!("Failed to build PR event: {}", e))?; 534 .map_err(|e| format!("Failed to send PR event: {}", e))?;
538 535
539 // Send PR event 536 let filter = Filter::new()
540 let (_, in_purgatory) = client 537 .kind(Kind::GitPullRequest)
541 .send_event_and_note_purgatory(pr_event.clone()) 538 .author(client.pr_author_keys().public_key())
539 .id(pr_event.id);
540
541 tokio::time::sleep(Duration::from_millis(300)).await;
542
543 let events = client
544 .query(filter)
542 .await 545 .await
543 .map_err(|e| format!("Failed to send PR event: {}", e))?; 546 .map_err(|e| format!("Failed to query PR events: {}", e))?;
544 547
545 if !in_purgatory { 548 if !events.is_empty() {
546 return Err(format!( 549 return Err(format!(
547 "PR event was served immediately - purgatory not implemented. \ 550 "PR event was served immediately - should be in purgatory. Event ID: {}",
548 Event ID: {} should NOT be queryable until git data arrives",
549 pr_event.id 551 pr_event.id
550 )); 552 ));
551 } 553 }
@@ -555,46 +557,89 @@ impl PurgatoryTests {
555 .await 557 .await
556 } 558 }
557 559
558 /// Test: PR event served after correct push 560 /// Test: PR event remains in purgatory until git data arrives
559 ///
560 /// Spec: GRASP-01 Line 22
561 /// "...kept in purgatory (not served) until the related git data arrives"
562 /// 561 ///
563 /// This test verifies: 562 /// Verifies the event stays in purgatory until matching git data is pushed.
564 /// 1. Send PR event (enters purgatory) 563 pub async fn test_pr_event_remains_in_purgatory_until_git_data(
565 /// 2. Push git data to refs/nostr/<pr-event-id> with correct commit 564 client: &AuditClient,
566 /// 3. PR event is now served 565 ) -> TestResult {
567 pub async fn test_pr_event_served_after_correct_push(client: &AuditClient) -> TestResult {
568 TestResult::new( 566 TestResult::new(
569 "pr_event_served_after_correct_push", 567 "pr_event_remains_in_purgatory_until_git_data",
570 SpecRef::PurgatoryAcceptUntilGitData, 568 SpecRef::PurgatoryAcceptUntilGitData,
571 "PR events SHOULD be served after matching git data arrives", 569 "PR event SHOULD remain in purgatory until git data arrives",
572 ) 570 )
573 .run(|| async { 571 .run(|| async {
574 let ctx = TestContext::new(client); 572 let ctx = TestContext::new(client);
575 573
576 // Get a repo with git data 574 let pr_event = ctx
577 let _existing_state = ctx 575 .get_fixture(FixtureKind::PREvent2Sent)
578 .get_fixture(FixtureKind::OwnerStateDataPushed)
579 .await 576 .await
580 .map_err(|e| format!("Failed to get existing repo: {}", e))?; 577 .map_err(|e| format!("Failed to get PR event: {}", e))?;
581 578
582 // Build PR event 579 tokio::time::sleep(Duration::from_millis(500)).await;
583 let pr_event = ctx 580
584 .build_fixture_only(FixtureKind::PREvent) 581 let filter = Filter::new()
582 .kind(Kind::GitPullRequest)
583 .author(client.pr_author_keys().public_key())
584 .id(pr_event.id);
585
586 let events = client
587 .query(filter)
585 .await 588 .await
586 .map_err(|e| format!("Failed to build PR event: {}", e))?; 589 .map_err(|e| format!("Failed to query PR events: {}", e))?;
590
591 if !events.is_empty() {
592 return Err(format!(
593 "PR event was served without git data - purgatory not working. Event ID: {}",
594 pr_event.id
595 ));
596 }
597
598 Ok(())
599 })
600 .await
601 }
587 602
588 // Send PR event (should enter purgatory) 603 /// Test: Git push accepted for PR event in purgatory
589 let (_, _in_purgatory) = client 604 ///
590 .send_event_and_note_purgatory(pr_event.clone()) 605 /// Verifies that pushing the correct commit to refs/nostr/<pr-event-id>
606 /// is accepted.
607 pub async fn test_pr_event_git_push_accepted(client: &AuditClient) -> TestResult {
608 TestResult::new(
609 "pr_event_git_push_accepted",
610 SpecRef::PurgatoryAcceptUntilGitData,
611 "Git push for PR event SHOULD be accepted",
612 )
613 .run(|| async {
614 let ctx = TestContext::new(client);
615
616 let _pr_event = ctx
617 .get_fixture(FixtureKind::PREvent2GitDataPushed)
591 .await 618 .await
592 .map_err(|e| format!("Failed to send PR event: {}", e))?; 619 .map_err(|e| format!("Failed to push git data for PR event: {}", e))?;
593 620
594 // TODO: Push git data to refs/nostr/<pr-event-id> 621 Ok(())
595 // This requires git operations similar to OwnerStateDataPushed 622 })
623 .await
624 }
625
626 /// Test: PR event served after git push
627 ///
628 /// Verifies the full purgatory release mechanism.
629 pub async fn test_pr_event_served_after_git_push(client: &AuditClient) -> TestResult {
630 TestResult::new(
631 "pr_event_served_after_git_push",
632 SpecRef::PurgatoryAcceptUntilGitData,
633 "PR event SHOULD be served after matching git data arrives",
634 )
635 .run(|| async {
636 let ctx = TestContext::new(client);
637
638 let pr_event = ctx
639 .get_fixture(FixtureKind::PREvent2Served)
640 .await
641 .map_err(|e| format!("Failed to complete purgatory release: {}", e))?;
596 642
597 // For now, verify the PR event exists
598 let filter = Filter::new() 643 let filter = Filter::new()
599 .kind(Kind::GitPullRequest) 644 .kind(Kind::GitPullRequest)
600 .author(client.pr_author_keys().public_key()) 645 .author(client.pr_author_keys().public_key())
@@ -607,8 +652,7 @@ impl PurgatoryTests {
607 652
608 if events.is_empty() { 653 if events.is_empty() {
609 return Err(format!( 654 return Err(format!(
610 "PR event not served after git push - purgatory release not implemented. \ 655 "PR event not served after git push. Event ID: {} should be queryable",
611 Event ID: {} should be queryable after git data arrives",
612 pr_event.id 656 pr_event.id
613 )); 657 ));
614 } 658 }