mirror of
https://relay.ngit.dev/npub15qydau2hjma6ngxkl2cyar74wzyjshvl65za5k5rl69264ar2exs5cyejr/ngit-grasp.git
synced 2026-10-05 15:08:24 +00:00
test: update sync tests to set up git data for purgatory flow
All sync tests now create a local git repo, send announcement + state event to the source relay, and push git data to release both from purgatory before the syncing relay starts bootstrap sync.
This commit is contained in:
+301
-35
@@ -507,41 +507,53 @@ fn check_sync_connections_in_metrics(metrics: &str, expected: usize) -> bool {
|
||||
/// assert!(found, "Expected event {} to sync to relay", event.id);
|
||||
/// ```
|
||||
pub async fn wait_for_event_on_relay(relay_url: &str, filter: Filter, timeout: Duration) -> bool {
|
||||
// Create a temporary client for querying
|
||||
let temp_keys = Keys::generate();
|
||||
let client = Client::new(temp_keys);
|
||||
let deadline = tokio::time::Instant::now() + timeout;
|
||||
let poll_interval = Duration::from_millis(200);
|
||||
|
||||
// Try to connect
|
||||
if client.add_relay(relay_url).await.is_err() {
|
||||
return false;
|
||||
}
|
||||
loop {
|
||||
// Create a fresh client for each poll attempt (avoids stale connection state)
|
||||
let temp_keys = Keys::generate();
|
||||
let client = Client::new(temp_keys);
|
||||
|
||||
client.connect().await;
|
||||
|
||||
// Wait for connection (brief timeout)
|
||||
let mut connected = false;
|
||||
for _ in 0..10 {
|
||||
tokio::time::sleep(Duration::from_millis(100)).await;
|
||||
let relays = client.relays().await;
|
||||
if relays.values().any(|r| r.is_connected()) {
|
||||
connected = true;
|
||||
break;
|
||||
if client.add_relay(relay_url).await.is_err() {
|
||||
if tokio::time::Instant::now() >= deadline {
|
||||
return false;
|
||||
}
|
||||
tokio::time::sleep(poll_interval).await;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
if !connected {
|
||||
client.disconnect().await;
|
||||
return false;
|
||||
}
|
||||
client.connect().await;
|
||||
|
||||
// Fetch events with the provided timeout
|
||||
let result = client.fetch_events(filter, timeout).await;
|
||||
// Wait for connection
|
||||
let mut connected = false;
|
||||
for _ in 0..10 {
|
||||
tokio::time::sleep(Duration::from_millis(100)).await;
|
||||
let relays = client.relays().await;
|
||||
if relays.values().any(|r| r.is_connected()) {
|
||||
connected = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
client.disconnect().await;
|
||||
if connected {
|
||||
// Use a short fetch window — if the event is there, EOSE comes back quickly
|
||||
let fetch_timeout = Duration::from_millis(500);
|
||||
let result = client.fetch_events(filter.clone(), fetch_timeout).await;
|
||||
client.disconnect().await;
|
||||
|
||||
match result {
|
||||
Ok(events) => !events.is_empty(),
|
||||
Err(_) => false,
|
||||
match result {
|
||||
Ok(events) if !events.is_empty() => return true,
|
||||
_ => {}
|
||||
}
|
||||
} else {
|
||||
client.disconnect().await;
|
||||
}
|
||||
|
||||
if tokio::time::Instant::now() >= deadline {
|
||||
return false;
|
||||
}
|
||||
tokio::time::sleep(poll_interval).await;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -774,6 +786,11 @@ impl MetricsTestHarness {
|
||||
self.source_relays[idx].domain()
|
||||
}
|
||||
|
||||
/// Get a reference to a source relay (for advanced test operations)
|
||||
pub fn source_relay(&self, idx: usize) -> &TestRelay {
|
||||
&self.source_relays[idx]
|
||||
}
|
||||
|
||||
/// Submit events to a specific source relay
|
||||
pub async fn submit_events(&self, source_idx: usize, events: &[Event]) -> Result<(), String> {
|
||||
let relay = &self.source_relays[source_idx];
|
||||
@@ -1099,6 +1116,259 @@ pub async fn send_to_relay_url(relay_url: &str, event: &Event) -> Result<(), Str
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Push git repository data to a relay to release a purgatory-held announcement.
|
||||
///
|
||||
/// Creates a local git repo, sends a state event, and pushes to the relay.
|
||||
/// Use this when you need to build a custom announcement but still need the
|
||||
/// relay to accept it (i.e., release it from purgatory).
|
||||
///
|
||||
/// # Arguments
|
||||
/// * `relay` - The relay to push to
|
||||
/// * `keys` - Keys of the repository owner
|
||||
/// * `identifier` - Repository identifier
|
||||
/// * `domains` - All domains in the announcement (for state event URLs)
|
||||
///
|
||||
/// # Returns
|
||||
/// `tempfile::TempDir` - Keep alive for test duration
|
||||
pub async fn push_git_data_to_relay(
|
||||
relay: &TestRelay,
|
||||
keys: &Keys,
|
||||
identifier: &str,
|
||||
domains: &[&str],
|
||||
) -> tempfile::TempDir {
|
||||
use super::purgatory_helpers::{
|
||||
create_state_event, create_test_repo_with_commit, push_to_relay, CommitVariant,
|
||||
};
|
||||
|
||||
let npub = keys
|
||||
.public_key()
|
||||
.to_bech32()
|
||||
.expect("Failed to convert public key to npub");
|
||||
|
||||
// Create local git repo
|
||||
let git_temp_dir = tempfile::tempdir().expect("Failed to create temp dir for git repo");
|
||||
let commit_hash = create_test_repo_with_commit(git_temp_dir.path(), CommitVariant::StateTest)
|
||||
.expect("Failed to create test git repo");
|
||||
|
||||
let clone_urls: Vec<String> = domains
|
||||
.iter()
|
||||
.map(|d| format!("http://{}/{}/{}.git", d, npub, identifier))
|
||||
.collect();
|
||||
let relay_urls: Vec<String> = domains.iter().map(|d| format!("ws://{}", d)).collect();
|
||||
|
||||
// Build and send state event with all domains' clone URLs
|
||||
let state_event = create_state_event(
|
||||
keys,
|
||||
identifier,
|
||||
&[("main", &commit_hash)],
|
||||
&[],
|
||||
&clone_urls.iter().map(|s| s.as_str()).collect::<Vec<_>>(),
|
||||
&relay_urls.iter().map(|s| s.as_str()).collect::<Vec<_>>(),
|
||||
)
|
||||
.expect("Failed to create state event");
|
||||
|
||||
send_to_relay(relay, &state_event)
|
||||
.await
|
||||
.expect("Failed to send state event");
|
||||
|
||||
// Git push to relay → releases state event from purgatory, authorizes push
|
||||
push_to_relay(git_temp_dir.path(), &relay.domain(), &npub, identifier)
|
||||
.expect("Failed to push git data to relay");
|
||||
|
||||
// Brief wait for push processing
|
||||
tokio::time::sleep(Duration::from_millis(500)).await;
|
||||
|
||||
git_temp_dir
|
||||
}
|
||||
|
||||
/// Like `push_git_data_to_relay` but writes a unique marker file so each call
|
||||
/// produces a distinct commit hash.
|
||||
///
|
||||
/// Use this when multiple callers push to the same relay with the same identifier
|
||||
/// but different keys — identical commit hashes cause git to skip pack transfer,
|
||||
/// which can leave the announcement in purgatory.
|
||||
///
|
||||
/// # Arguments
|
||||
/// * `relay` - The relay to push to
|
||||
/// * `keys` - Keys of the repository owner
|
||||
/// * `identifier` - Repository identifier
|
||||
/// * `domains` - All domains in the announcement (for state event URLs)
|
||||
/// * `unique_seed` - A string written into a `.unique` file to differentiate commits
|
||||
///
|
||||
/// # Returns
|
||||
/// `tempfile::TempDir` - Keep alive for test duration
|
||||
pub async fn push_unique_git_data_to_relay(
|
||||
relay: &TestRelay,
|
||||
keys: &Keys,
|
||||
identifier: &str,
|
||||
domains: &[&str],
|
||||
unique_seed: &str,
|
||||
) -> tempfile::TempDir {
|
||||
use super::purgatory_helpers::{create_state_event, push_to_relay};
|
||||
|
||||
let npub = keys
|
||||
.public_key()
|
||||
.to_bech32()
|
||||
.expect("Failed to convert public key to npub");
|
||||
|
||||
let git_temp_dir = tempfile::tempdir().expect("Failed to create temp dir for git repo");
|
||||
let path = git_temp_dir.path();
|
||||
|
||||
fn git(path: &std::path::Path, args: &[&str]) {
|
||||
let status = std::process::Command::new("git")
|
||||
.args(args)
|
||||
.current_dir(path)
|
||||
.env("GIT_AUTHOR_NAME", "Test User")
|
||||
.env("GIT_AUTHOR_EMAIL", "test@example.com")
|
||||
.env("GIT_COMMITTER_NAME", "Test User")
|
||||
.env("GIT_COMMITTER_EMAIL", "test@example.com")
|
||||
.env("GIT_AUTHOR_DATE", "2024-01-01T00:00:00+00:00")
|
||||
.env("GIT_COMMITTER_DATE", "2024-01-01T00:00:00+00:00")
|
||||
.output()
|
||||
.unwrap_or_else(|e| panic!("git {:?} failed to spawn: {}", args, e));
|
||||
assert!(
|
||||
status.status.success(),
|
||||
"git {:?} failed: {}",
|
||||
args,
|
||||
String::from_utf8_lossy(&status.stderr)
|
||||
);
|
||||
}
|
||||
|
||||
git(path, &["init", "--initial-branch=main"]);
|
||||
git(path, &["config", "user.email", "test@example.com"]);
|
||||
git(path, &["config", "user.name", "Test User"]);
|
||||
git(path, &["config", "commit.gpgsign", "false"]);
|
||||
|
||||
// Write a unique file so each maintainer gets a distinct commit hash
|
||||
std::fs::write(path.join("state_test.txt"), "State test content for purgatory sync")
|
||||
.expect("write state_test.txt");
|
||||
std::fs::write(path.join(".unique"), unique_seed).expect("write .unique");
|
||||
git(path, &["add", "."]);
|
||||
git(path, &["commit", "-m", "State test commit"]);
|
||||
|
||||
let commit_hash = {
|
||||
let out = std::process::Command::new("git")
|
||||
.args(["rev-parse", "HEAD"])
|
||||
.current_dir(path)
|
||||
.output()
|
||||
.expect("git rev-parse");
|
||||
String::from_utf8_lossy(&out.stdout).trim().to_string()
|
||||
};
|
||||
|
||||
let clone_urls: Vec<String> = domains
|
||||
.iter()
|
||||
.map(|d| format!("http://{}/{}/{}.git", d, npub, identifier))
|
||||
.collect();
|
||||
let relay_urls: Vec<String> = domains.iter().map(|d| format!("ws://{}", d)).collect();
|
||||
|
||||
let state_event = create_state_event(
|
||||
keys,
|
||||
identifier,
|
||||
&[("main", &commit_hash)],
|
||||
&[],
|
||||
&clone_urls.iter().map(|s| s.as_str()).collect::<Vec<_>>(),
|
||||
&relay_urls.iter().map(|s| s.as_str()).collect::<Vec<_>>(),
|
||||
)
|
||||
.expect("Failed to create state event");
|
||||
|
||||
send_to_relay(relay, &state_event)
|
||||
.await
|
||||
.expect("Failed to send state event");
|
||||
|
||||
push_to_relay(path, &relay.domain(), &npub, identifier)
|
||||
.expect("Failed to push git data to relay");
|
||||
|
||||
tokio::time::sleep(Duration::from_millis(500)).await;
|
||||
|
||||
git_temp_dir
|
||||
}
|
||||
|
||||
/// Set up a repository announcement on a relay with git data so it passes purgatory.
|
||||
///
|
||||
/// With the announcement purgatory feature, announcements (kind 30617) require git
|
||||
/// data before they are promoted to the relay's main DB. This helper:
|
||||
///
|
||||
/// 1. Creates a local git repo with a commit
|
||||
/// 2. Builds an announcement and state event (kind 30618) pointing to the relay
|
||||
/// 3. Sends both to the relay (they go to purgatory)
|
||||
/// 4. Git pushes to the relay → releases both from purgatory immediately
|
||||
/// 5. Returns the announcement event and temp dir (keep alive for test duration)
|
||||
///
|
||||
/// # Arguments
|
||||
/// * `relay` - The relay to set up the announcement on
|
||||
/// * `keys` - Keys to sign the announcement with (repo owner)
|
||||
/// * `domains` - All domains that should be listed in the announcement (including relay.domain())
|
||||
/// * `identifier` - Repository identifier (d-tag)
|
||||
///
|
||||
/// # Returns
|
||||
/// `(Event, tempfile::TempDir)` - The announcement event and temp dir.
|
||||
/// The temp dir MUST be kept alive for the duration of the test.
|
||||
pub async fn setup_announcement_on_relay(
|
||||
relay: &TestRelay,
|
||||
keys: &Keys,
|
||||
domains: &[&str],
|
||||
identifier: &str,
|
||||
) -> (Event, tempfile::TempDir) {
|
||||
use super::purgatory_helpers::{
|
||||
create_state_event, create_test_repo_with_commit, push_to_relay, CommitVariant,
|
||||
};
|
||||
|
||||
let npub = keys
|
||||
.public_key()
|
||||
.to_bech32()
|
||||
.expect("Failed to convert public key to npub");
|
||||
|
||||
// Create local git repo with a commit
|
||||
let git_temp_dir = tempfile::tempdir().expect("Failed to create temp dir for git repo");
|
||||
let commit_hash = create_test_repo_with_commit(git_temp_dir.path(), CommitVariant::StateTest)
|
||||
.expect("Failed to create test git repo");
|
||||
|
||||
// Build clone URLs and relay URLs from domains
|
||||
let clone_urls: Vec<String> = domains
|
||||
.iter()
|
||||
.map(|d| format!("http://{}/{}/{}.git", d, npub, identifier))
|
||||
.collect();
|
||||
let relay_urls: Vec<String> = domains.iter().map(|d| format!("ws://{}", d)).collect();
|
||||
|
||||
// Build announcement event (lists ALL domains for relay discovery)
|
||||
let announcement = EventBuilder::new(Kind::GitRepoAnnouncement, "Repository state")
|
||||
.tags(vec![
|
||||
Tag::identifier(identifier),
|
||||
Tag::custom(TagKind::custom("clone"), clone_urls.clone()),
|
||||
Tag::custom(TagKind::custom("relays"), relay_urls.clone()),
|
||||
])
|
||||
.sign_with_keys(keys)
|
||||
.expect("Failed to sign repo announcement");
|
||||
|
||||
// Build state event with all domains' clone URLs
|
||||
let state_event = create_state_event(
|
||||
keys,
|
||||
identifier,
|
||||
&[("main", &commit_hash)],
|
||||
&[],
|
||||
&clone_urls.iter().map(|s| s.as_str()).collect::<Vec<_>>(),
|
||||
&relay_urls.iter().map(|s| s.as_str()).collect::<Vec<_>>(),
|
||||
)
|
||||
.expect("Failed to create state event");
|
||||
|
||||
// Send announcement and state event to relay (both go to purgatory)
|
||||
send_to_relay(relay, &announcement)
|
||||
.await
|
||||
.expect("Failed to send announcement");
|
||||
send_to_relay(relay, &state_event)
|
||||
.await
|
||||
.expect("Failed to send state event");
|
||||
|
||||
// Git push to relay → releases both from purgatory
|
||||
push_to_relay(git_temp_dir.path(), &relay.domain(), &npub, identifier)
|
||||
.expect("Failed to push git data to relay");
|
||||
|
||||
// Brief wait for push processing
|
||||
tokio::time::sleep(Duration::from_millis(500)).await;
|
||||
|
||||
(announcement, git_temp_dir)
|
||||
}
|
||||
|
||||
/// Unified sync test helper that automatically determines sync mode.
|
||||
///
|
||||
/// This function sets up a complete sync test environment by determining whether
|
||||
@@ -1158,9 +1428,8 @@ pub async fn run_sync_test(historic_events: &[Event], live_events: &[Event]) ->
|
||||
|
||||
// 3. Create local git repo with a commit
|
||||
let git_temp_dir = tempfile::tempdir().expect("Failed to create temp dir for git repo");
|
||||
let commit_hash =
|
||||
create_test_repo_with_commit(git_temp_dir.path(), CommitVariant::StateTest)
|
||||
.expect("Failed to create test git repo");
|
||||
let commit_hash = create_test_repo_with_commit(git_temp_dir.path(), CommitVariant::StateTest)
|
||||
.expect("Failed to create test git repo");
|
||||
|
||||
// 4. Create keys and build URLs
|
||||
let keys = Keys::generate();
|
||||
@@ -1172,10 +1441,7 @@ pub async fn run_sync_test(historic_events: &[Event], live_events: &[Event]) ->
|
||||
// Clone URLs: source relay HTTP endpoint is where git data lives
|
||||
// The syncing relay's purgatory will fetch from source's clone URL
|
||||
let clone_url_source = format!("http://{}/{}/{}.git", source.domain(), npub, "test-repo");
|
||||
let clone_url_syncing = format!(
|
||||
"http://{}/{}/{}.git",
|
||||
syncing_domain, npub, "test-repo"
|
||||
);
|
||||
let clone_url_syncing = format!("http://{}/{}/{}.git", syncing_domain, npub, "test-repo");
|
||||
|
||||
let clone_urls = vec![clone_url_source.clone(), clone_url_syncing.clone()];
|
||||
let relay_urls = vec![
|
||||
|
||||
+50
-114
@@ -62,29 +62,26 @@ async fn test_discovers_layer3_via_layer2() {
|
||||
// 3. Create test keys
|
||||
let keys = Keys::generate();
|
||||
|
||||
// 4. Create a repository announcement that lists BOTH relays
|
||||
let announcement = create_repo_announcement(
|
||||
&keys,
|
||||
&[&relay_a.domain(), &relay_b.domain()],
|
||||
"test-repo-discovery",
|
||||
);
|
||||
let announcement_id = announcement.id;
|
||||
// 4. Set up repository announcement on relay_a with git data
|
||||
// (purgatory requires git data before announcements are accepted)
|
||||
let repo_id = "test-repo-discovery";
|
||||
let domains = vec![relay_a.domain(), relay_b.domain()];
|
||||
let domain_refs: Vec<&str> = domains.iter().map(|s| s.as_str()).collect();
|
||||
|
||||
let (announcement, _git_dir_a) =
|
||||
setup_announcement_on_relay(&relay_a, &keys, &domain_refs, repo_id).await;
|
||||
let announcement_id = announcement.id;
|
||||
println!(
|
||||
"Created announcement {} (kind {})",
|
||||
announcement_id,
|
||||
announcement.kind.as_u16()
|
||||
"Announcement {} set up on relay_a with git data",
|
||||
announcement_id
|
||||
);
|
||||
for tag in announcement.tags.iter() {
|
||||
println!(" Tag: {:?}", tag.as_slice());
|
||||
}
|
||||
|
||||
// 5. Build the repo coordinate for the 'a' tag in the patch
|
||||
let repo_coord = format!(
|
||||
"{}:{}:{}",
|
||||
Kind::GitRepoAnnouncement.as_u16(),
|
||||
keys.public_key().to_hex(),
|
||||
"test-repo-discovery"
|
||||
repo_id
|
||||
);
|
||||
|
||||
// 6. Create a patch event (Layer 2) that references the announcement
|
||||
@@ -97,21 +94,12 @@ async fn test_discovers_layer3_via_layer2() {
|
||||
let patch_id = patch.id;
|
||||
|
||||
println!("Created patch {} (kind {})", patch_id, patch.kind.as_u16());
|
||||
for tag in patch.tags.iter() {
|
||||
println!(" Tag: {:?}", tag.as_slice());
|
||||
}
|
||||
|
||||
// 7. Send announcement and patch to relay_a ONLY
|
||||
// 7. Send patch to relay_a
|
||||
let client_a = TestClient::new(relay_a.url(), keys.clone())
|
||||
.await
|
||||
.expect("Failed to connect to relay_a");
|
||||
|
||||
client_a
|
||||
.send_event(&announcement)
|
||||
.await
|
||||
.expect("Failed to send announcement to relay_a");
|
||||
println!("Announcement sent to relay_a");
|
||||
|
||||
client_a
|
||||
.send_event(&patch)
|
||||
.await
|
||||
@@ -120,18 +108,10 @@ async fn test_discovers_layer3_via_layer2() {
|
||||
|
||||
client_a.disconnect().await;
|
||||
|
||||
// 8. Send announcement to relay_b directly (triggers discovery of relay_a)
|
||||
let client_b = TestClient::new(relay_b.url(), keys.clone())
|
||||
.await
|
||||
.expect("Failed to connect to relay_b");
|
||||
|
||||
client_b
|
||||
.send_event(&announcement)
|
||||
.await
|
||||
.expect("Failed to send announcement to relay_b");
|
||||
println!("Announcement sent to relay_b (should trigger discovery of relay_a)");
|
||||
|
||||
client_b.disconnect().await;
|
||||
// 8. Set up announcement on relay_b (triggers discovery of relay_a)
|
||||
let (_announcement_b, _git_dir_b) =
|
||||
setup_announcement_on_relay(&relay_b, &keys, &domain_refs, repo_id).await;
|
||||
println!("Announcement set up on relay_b (should trigger discovery of relay_a)");
|
||||
|
||||
// 9. Wait for relay_b to discover relay_a and sync the patch
|
||||
println!("Waiting 3s for relay_b to discover relay_a and sync patch...");
|
||||
@@ -197,19 +177,20 @@ async fn test_relay_discovery_via_announcements_with_historic_sync() {
|
||||
// 3. Create test keys
|
||||
let keys = Keys::generate();
|
||||
|
||||
// 4. Create the event chain on relay_a:
|
||||
// 4. Set up repository on relay_a with git data and a Layer 2 issue
|
||||
|
||||
// Layer 1: Repository announcement
|
||||
let announcement = create_repo_announcement(
|
||||
&keys,
|
||||
&[&relay_a.domain(), &relay_b.domain()],
|
||||
"test-repo-chain",
|
||||
);
|
||||
// Layer 1: Set up announcement with git data
|
||||
let domains = vec![relay_a.domain(), relay_b.domain()];
|
||||
let domain_refs: Vec<&str> = domains.iter().map(|s| s.as_str()).collect();
|
||||
let repo_id = "test-repo-chain";
|
||||
|
||||
let (announcement, _git_dir_a) =
|
||||
setup_announcement_on_relay(&relay_a, &keys, &domain_refs, repo_id).await;
|
||||
let announcement_id = announcement.id;
|
||||
println!("Created announcement {} (Layer 1)", announcement_id);
|
||||
println!("Announcement {} set up on relay_a with git data (Layer 1)", announcement_id);
|
||||
|
||||
// Build repo coordinate for Layer 2 reference
|
||||
let repo_coord = repo_coord(&keys, "test-repo-chain");
|
||||
let repo_coord = repo_coord(&keys, repo_id);
|
||||
|
||||
// Layer 2: Issue referencing the repo
|
||||
let issue = build_layer2_issue_event(&keys, &repo_coord, "Test issue for chain discovery")
|
||||
@@ -217,35 +198,23 @@ async fn test_relay_discovery_via_announcements_with_historic_sync() {
|
||||
let issue_id = issue.id;
|
||||
println!("Created issue {} (Layer 2)", issue_id);
|
||||
|
||||
// 5. Send all events to relay_a
|
||||
// 5. Send issue to relay_a
|
||||
let client_a = TestClient::new(relay_a.url(), keys.clone())
|
||||
.await
|
||||
.expect("Failed to connect to relay_a");
|
||||
|
||||
client_a
|
||||
.send_event(&announcement)
|
||||
.await
|
||||
.expect("Failed to send announcement");
|
||||
client_a
|
||||
.send_event(&issue)
|
||||
.await
|
||||
.expect("Failed to send issue");
|
||||
|
||||
println!("Events sent to relay_a");
|
||||
println!("Issue sent to relay_a");
|
||||
client_a.disconnect().await;
|
||||
|
||||
// 6. Send only the announcement to relay_b (triggers discovery)
|
||||
let client_b = TestClient::new(relay_b.url(), keys.clone())
|
||||
.await
|
||||
.expect("Failed to connect to relay_b");
|
||||
|
||||
client_b
|
||||
.send_event(&announcement)
|
||||
.await
|
||||
.expect("Failed to send announcement to relay_b");
|
||||
println!("Announcement sent to relay_b (should trigger discovery)");
|
||||
|
||||
client_b.disconnect().await;
|
||||
// 6. Set up announcement on relay_b (triggers discovery of relay_a)
|
||||
let (_announcement_b, _git_dir_b) =
|
||||
setup_announcement_on_relay(&relay_b, &keys, &domain_refs, repo_id).await;
|
||||
println!("Announcement set up on relay_b (should trigger discovery of relay_a)");
|
||||
|
||||
// 7. Wait for sync
|
||||
println!("Waiting 3s for Layer 2 sync...");
|
||||
@@ -327,65 +296,32 @@ async fn test_recursive_relay_discovery_via_announcements_with_historic_sync() {
|
||||
let keys_x = Keys::generate();
|
||||
let keys_y = Keys::generate();
|
||||
|
||||
// 3. Create announcement_x on relay_b (lists all three relays: A+B+C)
|
||||
let announcement_x = create_repo_announcement(
|
||||
&keys_x,
|
||||
&[&relay_a.domain(), &relay_b.domain(), &relay_c.domain()],
|
||||
"repo-x-all-relays",
|
||||
);
|
||||
// 3. Set up announcement_x on relay_b (lists all three relays: A+B+C) with git data
|
||||
let domains_x = vec![relay_a.domain(), relay_b.domain(), relay_c.domain()];
|
||||
let domain_refs_x: Vec<&str> = domains_x.iter().map(|s| s.as_str()).collect();
|
||||
|
||||
let (announcement_x, _git_dir_b) =
|
||||
setup_announcement_on_relay(&relay_b, &keys_x, &domain_refs_x, "repo-x-all-relays").await;
|
||||
let announcement_x_id = announcement_x.id;
|
||||
println!("Created announcement_x {} listing A+B+C", announcement_x_id);
|
||||
for tag in announcement_x.tags.iter() {
|
||||
println!(" Tag: {:?}", tag.as_slice());
|
||||
}
|
||||
println!("announcement_x {} set up on relay_b with git data (listing A+B+C)", announcement_x_id);
|
||||
|
||||
// 4. Create announcement_y on relay_c (lists only A+C, NOT B)
|
||||
let announcement_y = create_repo_announcement(
|
||||
&keys_y,
|
||||
&[&relay_a.domain(), &relay_c.domain()],
|
||||
"repo-y-ac-only",
|
||||
);
|
||||
// 4. Set up announcement_y on relay_c (lists only A+C, NOT B) with git data
|
||||
let domains_y = vec![relay_a.domain(), relay_c.domain()];
|
||||
let domain_refs_y: Vec<&str> = domains_y.iter().map(|s| s.as_str()).collect();
|
||||
|
||||
let (announcement_y, _git_dir_c) =
|
||||
setup_announcement_on_relay(&relay_c, &keys_y, &domain_refs_y, "repo-y-ac-only").await;
|
||||
let announcement_y_id = announcement_y.id;
|
||||
println!(
|
||||
"Created announcement_y {} listing A+C only",
|
||||
announcement_y_id
|
||||
);
|
||||
for tag in announcement_y.tags.iter() {
|
||||
println!(" Tag: {:?}", tag.as_slice());
|
||||
}
|
||||
|
||||
// 5. Send announcement_x to relay_b only
|
||||
let client_b = TestClient::new(relay_b.url(), keys_x.clone())
|
||||
.await
|
||||
.expect("Failed to connect to relay_b");
|
||||
|
||||
client_b
|
||||
.send_event(&announcement_x)
|
||||
.await
|
||||
.expect("Failed to send announcement_x to relay_b");
|
||||
println!("announcement_x sent to relay_b");
|
||||
|
||||
client_b.disconnect().await;
|
||||
|
||||
// 6. Send announcement_y to relay_c only
|
||||
let client_c = TestClient::new(relay_c.url(), keys_y.clone())
|
||||
.await
|
||||
.expect("Failed to connect to relay_c");
|
||||
|
||||
client_c
|
||||
.send_event(&announcement_y)
|
||||
.await
|
||||
.expect("Failed to send announcement_y to relay_c");
|
||||
println!("announcement_y sent to relay_c");
|
||||
|
||||
client_c.disconnect().await;
|
||||
println!("announcement_y {} set up on relay_c with git data (listing A+C only)", announcement_y_id);
|
||||
|
||||
// 7. Wait for relay_a to:
|
||||
// - Sync from bootstrap relay_b (gets announcement_x)
|
||||
// - Discover relay_c from announcement_x's relays tag
|
||||
// - Connect to relay_c and sync announcement_y
|
||||
println!("Waiting 5s for recursive relay discovery...");
|
||||
tokio::time::sleep(Duration::from_secs(5)).await;
|
||||
// With purgatory, each relay needs to: sync announcement → purgatory → sync state event →
|
||||
// immediate purgatory sync → fetch git data → promote. Allow extra time for this.
|
||||
println!("Waiting 12s for recursive relay discovery (with purgatory flow)...");
|
||||
tokio::time::sleep(Duration::from_secs(12)).await;
|
||||
|
||||
// 8. Verify announcement_x was synced to relay_a (from bootstrap relay_b)
|
||||
let filter_x = Filter::new()
|
||||
|
||||
+11
-21
@@ -224,34 +224,24 @@ async fn test_history_sync_without_negentropy() {
|
||||
// Create keys
|
||||
let keys = Keys::generate();
|
||||
|
||||
// Create announcement listing BOTH relay domains
|
||||
// This event will exist on source BEFORE syncing relay ever connects
|
||||
let announcement = create_repo_announcement(
|
||||
// Set up announcement on source with git data
|
||||
// (purgatory requires git data before announcements are accepted)
|
||||
let domains = vec![source.domain(), syncing_domain.clone()];
|
||||
let domain_refs: Vec<&str> = domains.iter().map(|s| s.as_str()).collect();
|
||||
let (announcement, _git_dir) = setup_announcement_on_relay(
|
||||
&source,
|
||||
&keys,
|
||||
&[&source.domain(), &syncing_domain],
|
||||
&domain_refs,
|
||||
"test-repo-history-no-negentropy",
|
||||
);
|
||||
)
|
||||
.await;
|
||||
let announcement_id = announcement.id;
|
||||
|
||||
println!(
|
||||
"Created announcement {} (kind {})",
|
||||
announcement_id,
|
||||
announcement.kind.as_u16()
|
||||
"Announcement {} set up on source with git data (event exists BEFORE syncing relay connects)",
|
||||
announcement_id
|
||||
);
|
||||
|
||||
// Send announcement to source (event now exists BEFORE syncing relay connects)
|
||||
let client = TestClient::new(source.url(), keys.clone())
|
||||
.await
|
||||
.expect("Failed to connect to source");
|
||||
|
||||
client
|
||||
.send_event(&announcement)
|
||||
.await
|
||||
.expect("Failed to send announcement to source");
|
||||
println!("Announcement sent to source (event exists BEFORE syncing relay connects)");
|
||||
|
||||
client.disconnect().await;
|
||||
|
||||
// Wait to ensure event is stored
|
||||
tokio::time::sleep(Duration::from_millis(500)).await;
|
||||
|
||||
|
||||
+43
-76
@@ -56,43 +56,24 @@ async fn test_live_sync_layer2_events() {
|
||||
// 3. Create test keys
|
||||
let keys = Keys::generate();
|
||||
|
||||
// 4. Create a repository announcement that lists BOTH relays
|
||||
// 4. Create a repository announcement on both relays with git data
|
||||
// (purgatory requires git data before announcements are accepted)
|
||||
let repo_id = "test-repo-live-l2";
|
||||
let announcement =
|
||||
create_repo_announcement(&keys, &[&relay_a.domain(), &relay_b.domain()], repo_id);
|
||||
let domains = vec![relay_a.domain(), relay_b.domain()];
|
||||
let domain_refs: Vec<&str> = domains.iter().map(|s| s.as_str()).collect();
|
||||
|
||||
println!(
|
||||
"Created announcement {} (kind {})",
|
||||
announcement.id,
|
||||
announcement.kind.as_u16()
|
||||
);
|
||||
let (_announcement, _git_dir_a) =
|
||||
setup_announcement_on_relay(&relay_a, &keys, &domain_refs, repo_id).await;
|
||||
println!("Announcement set up on relay_a with git data");
|
||||
|
||||
// 5. Send announcement to relay_a
|
||||
let client_a = TestClient::new(relay_a.url(), keys.clone())
|
||||
.await
|
||||
.expect("Failed to connect to relay_a");
|
||||
let (_announcement_b, _git_dir_b) =
|
||||
setup_announcement_on_relay(&relay_b, &keys, &domain_refs, repo_id).await;
|
||||
println!("Announcement set up on relay_b with git data (triggers discovery)");
|
||||
|
||||
client_a
|
||||
.send_event(&announcement)
|
||||
.await
|
||||
.expect("Failed to send announcement to relay_a");
|
||||
println!("Announcement sent to relay_a");
|
||||
|
||||
// 6. Send announcement to relay_b (triggers discovery of relay_a)
|
||||
let client_b = TestClient::new(relay_b.url(), keys.clone())
|
||||
.await
|
||||
.expect("Failed to connect to relay_b");
|
||||
|
||||
client_b
|
||||
.send_event(&announcement)
|
||||
.await
|
||||
.expect("Failed to send announcement to relay_b");
|
||||
println!("Announcement sent to relay_b (triggers discovery)");
|
||||
|
||||
// 7. Wait for discovery to complete
|
||||
// 5. Wait for discovery to complete
|
||||
tokio::time::sleep(Duration::from_secs(1)).await;
|
||||
|
||||
// 8. Create and send a Layer 2 issue event (using helper)
|
||||
// 6. Create and send a Layer 2 issue event (using helper)
|
||||
let repo_coordinate = repo_coord(&keys, repo_id);
|
||||
let issue = build_layer2_issue_event(&keys, &repo_coordinate, "Test Issue for Live Sync")
|
||||
.expect("Failed to create issue event");
|
||||
@@ -104,6 +85,10 @@ async fn test_live_sync_layer2_events() {
|
||||
}
|
||||
|
||||
// Send issue to relay_a only
|
||||
let client_a = TestClient::new(relay_a.url(), keys.clone())
|
||||
.await
|
||||
.expect("Failed to connect to relay_a");
|
||||
|
||||
client_a
|
||||
.send_event(&issue)
|
||||
.await
|
||||
@@ -111,7 +96,6 @@ async fn test_live_sync_layer2_events() {
|
||||
println!("Issue sent to relay_a");
|
||||
|
||||
client_a.disconnect().await;
|
||||
client_b.disconnect().await;
|
||||
|
||||
// 9. Wait and verify event syncs to relay_b
|
||||
let filter = Filter::new()
|
||||
@@ -166,30 +150,19 @@ async fn test_live_sync_layer3_events() {
|
||||
|
||||
let keys = Keys::generate();
|
||||
|
||||
// 2. Create and send repository announcement to both relays
|
||||
// 2. Create and send repository announcement to both relays with git data
|
||||
// (purgatory requires git data before announcements are accepted)
|
||||
let repo_id = "test-repo-live-l3";
|
||||
let announcement =
|
||||
create_repo_announcement(&keys, &[&relay_a.domain(), &relay_b.domain()], repo_id);
|
||||
let domains = vec![relay_a.domain(), relay_b.domain()];
|
||||
let domain_refs: Vec<&str> = domains.iter().map(|s| s.as_str()).collect();
|
||||
|
||||
let client_a = TestClient::new(relay_a.url(), keys.clone())
|
||||
.await
|
||||
.expect("Failed to connect to relay_a");
|
||||
let (_announcement, _git_dir_a) =
|
||||
setup_announcement_on_relay(&relay_a, &keys, &domain_refs, repo_id).await;
|
||||
println!("Announcement set up on relay_a with git data");
|
||||
|
||||
let client_b = TestClient::new(relay_b.url(), keys.clone())
|
||||
.await
|
||||
.expect("Failed to connect to relay_b");
|
||||
|
||||
client_a
|
||||
.send_event(&announcement)
|
||||
.await
|
||||
.expect("Failed to send announcement to relay_a");
|
||||
println!("Announcement sent to relay_a");
|
||||
|
||||
client_b
|
||||
.send_event(&announcement)
|
||||
.await
|
||||
.expect("Failed to send announcement to relay_b");
|
||||
println!("Announcement sent to relay_b (triggers discovery)");
|
||||
let (_announcement_b, _git_dir_b) =
|
||||
setup_announcement_on_relay(&relay_b, &keys, &domain_refs, repo_id).await;
|
||||
println!("Announcement set up on relay_b with git data (triggers discovery)");
|
||||
|
||||
// 3. Wait for discovery
|
||||
tokio::time::sleep(Duration::from_secs(1)).await;
|
||||
@@ -200,6 +173,10 @@ async fn test_live_sync_layer3_events() {
|
||||
.expect("Failed to create issue");
|
||||
let issue_id = issue.id;
|
||||
|
||||
let client_a = TestClient::new(relay_a.url(), keys.clone())
|
||||
.await
|
||||
.expect("Failed to connect to relay_a");
|
||||
|
||||
client_a
|
||||
.send_event(&issue)
|
||||
.await
|
||||
@@ -243,7 +220,6 @@ async fn test_live_sync_layer3_events() {
|
||||
println!("Issue synced to relay_b: {}", issue_synced);
|
||||
|
||||
client_a.disconnect().await;
|
||||
client_b.disconnect().await;
|
||||
|
||||
// 7. Wait and verify comment syncs to relay_b
|
||||
let comment_filter = Filter::new()
|
||||
@@ -343,29 +319,17 @@ async fn test_live_sync_event_ordering() {
|
||||
|
||||
let keys = Keys::generate();
|
||||
|
||||
// 2. Create and send repository announcement to both relays
|
||||
// 2. Create and send repository announcement to both relays with git data
|
||||
// (purgatory requires git data before announcements are accepted)
|
||||
let repo_id = "test-repo-ordering";
|
||||
let announcement =
|
||||
create_repo_announcement(&keys, &[&relay_a.domain(), &relay_b.domain()], repo_id);
|
||||
let domains = vec![relay_a.domain(), relay_b.domain()];
|
||||
let domain_refs: Vec<&str> = domains.iter().map(|s| s.as_str()).collect();
|
||||
|
||||
let client_a = TestClient::new(relay_a.url(), keys.clone())
|
||||
.await
|
||||
.expect("Failed to connect to relay_a");
|
||||
|
||||
let client_b = TestClient::new(relay_b.url(), keys.clone())
|
||||
.await
|
||||
.expect("Failed to connect to relay_b");
|
||||
|
||||
client_a
|
||||
.send_event(&announcement)
|
||||
.await
|
||||
.expect("Failed to send announcement to relay_a");
|
||||
|
||||
client_b
|
||||
.send_event(&announcement)
|
||||
.await
|
||||
.expect("Failed to send announcement to relay_b");
|
||||
println!("Announcements sent to both relays");
|
||||
let (_announcement, _git_dir_a) =
|
||||
setup_announcement_on_relay(&relay_a, &keys, &domain_refs, repo_id).await;
|
||||
let (_announcement_b, _git_dir_b) =
|
||||
setup_announcement_on_relay(&relay_b, &keys, &domain_refs, repo_id).await;
|
||||
println!("Announcements set up on both relays with git data");
|
||||
|
||||
// 3. Wait for discovery
|
||||
tokio::time::sleep(Duration::from_secs(1)).await;
|
||||
@@ -375,6 +339,10 @@ async fn test_live_sync_event_ordering() {
|
||||
let mut issue_ids = Vec::new();
|
||||
let mut expected_order_timestamps = Vec::new();
|
||||
|
||||
let client_a = TestClient::new(relay_a.url(), keys.clone())
|
||||
.await
|
||||
.expect("Failed to connect to relay_a");
|
||||
|
||||
for i in 1..=3 {
|
||||
let issue = build_layer2_issue_event(
|
||||
&keys,
|
||||
@@ -402,7 +370,6 @@ async fn test_live_sync_event_ordering() {
|
||||
}
|
||||
|
||||
client_a.disconnect().await;
|
||||
client_b.disconnect().await;
|
||||
|
||||
// 5. Wait for all events to sync
|
||||
tokio::time::sleep(Duration::from_secs(3)).await;
|
||||
|
||||
@@ -7,7 +7,10 @@ use std::time::Duration;
|
||||
|
||||
use nostr_sdk::prelude::*;
|
||||
|
||||
use crate::common::{sync_helpers::*, TestRelay};
|
||||
use crate::common::{
|
||||
sync_helpers::*,
|
||||
TestRelay,
|
||||
};
|
||||
|
||||
/// Test that maintainer announcements are re-processed immediately when owner announcement accepted
|
||||
///
|
||||
@@ -37,10 +40,12 @@ async fn test_maintainer_announcement_reprocessed_immediately() {
|
||||
|
||||
let start = std::time::Instant::now();
|
||||
|
||||
// Step 1: Send maintainer announcement to relay_a (will be rejected - doesn't list relay_b)
|
||||
let client_a = TestClient::new(relay_a.url(), maintainer_keys.clone())
|
||||
.await
|
||||
.expect("Failed to connect to relay_a");
|
||||
// Step 1: Send maintainer announcement to relay_a (will be rejected by relay_b - doesn't list relay_b)
|
||||
// Use HTTP clone URL pointing to relay_a's git endpoint so it can be released from purgatory
|
||||
let maintainer_npub = maintainer_keys
|
||||
.public_key()
|
||||
.to_bech32()
|
||||
.expect("Failed to get npub");
|
||||
|
||||
let maintainer_announcement =
|
||||
EventBuilder::new(Kind::GitRepoAnnouncement, "Maintainer's repository")
|
||||
@@ -48,27 +53,50 @@ async fn test_maintainer_announcement_reprocessed_immediately() {
|
||||
Tag::identifier(identifier),
|
||||
Tag::custom(
|
||||
TagKind::custom("clone"),
|
||||
vec![format!("https://{}/{}.git", relay_a.domain(), identifier)],
|
||||
vec![format!(
|
||||
"http://{}/{}/{}.git",
|
||||
relay_a.domain(),
|
||||
maintainer_npub,
|
||||
identifier
|
||||
)],
|
||||
),
|
||||
Tag::custom(TagKind::custom("relays"), vec![relay_a.url().to_string()]),
|
||||
])
|
||||
.sign_with_keys(&maintainer_keys)
|
||||
.unwrap();
|
||||
|
||||
client_a.send_event(&maintainer_announcement).await.unwrap();
|
||||
send_to_relay(&relay_a, &maintainer_announcement)
|
||||
.await
|
||||
.unwrap();
|
||||
println!("✓ Maintainer announcement sent to relay_a");
|
||||
|
||||
// Step 2: Send owner announcement to relay_b (lists relay_a + maintainer)
|
||||
let client_b = TestClient::new(relay_b.url(), owner_keys.clone())
|
||||
.await
|
||||
.expect("Failed to connect to relay_b");
|
||||
// Push git data for maintainer's repo to relay_a → releases maintainer announcement from purgatory
|
||||
let _git_dir_maintainer = push_git_data_to_relay(
|
||||
&relay_a,
|
||||
&maintainer_keys,
|
||||
identifier,
|
||||
&[&relay_a.domain()],
|
||||
)
|
||||
.await;
|
||||
println!("✓ Maintainer git data pushed to relay_a (announcement released from purgatory)");
|
||||
|
||||
// Step 2: Set up owner announcement on relay_b (lists relay_a + maintainer) with git data
|
||||
let owner_npub = owner_keys
|
||||
.public_key()
|
||||
.to_bech32()
|
||||
.expect("Failed to get npub");
|
||||
|
||||
let owner_announcement = EventBuilder::new(Kind::GitRepoAnnouncement, "Owner's repository")
|
||||
.tags(vec![
|
||||
Tag::identifier(identifier),
|
||||
Tag::custom(
|
||||
TagKind::custom("clone"),
|
||||
vec![format!("https://{}/{}.git", relay_b.domain(), identifier)],
|
||||
vec![format!(
|
||||
"http://{}/{}/{}.git",
|
||||
relay_b.domain(),
|
||||
owner_npub,
|
||||
identifier
|
||||
)],
|
||||
),
|
||||
Tag::custom(
|
||||
TagKind::custom("relays"),
|
||||
@@ -82,9 +110,14 @@ async fn test_maintainer_announcement_reprocessed_immediately() {
|
||||
.sign_with_keys(&owner_keys)
|
||||
.unwrap();
|
||||
|
||||
client_b.send_event(&owner_announcement).await.unwrap();
|
||||
send_to_relay(&relay_b, &owner_announcement).await.unwrap();
|
||||
println!("✓ Owner announcement sent to relay_b");
|
||||
|
||||
// Push git data for owner's repo to relay_b → releases owner announcement from purgatory
|
||||
let _git_dir_owner =
|
||||
push_git_data_to_relay(&relay_b, &owner_keys, identifier, &[&relay_b.domain()]).await;
|
||||
println!("✓ Owner git data pushed to relay_b (announcement released from purgatory)");
|
||||
|
||||
// Step 3: Wait for sync and re-processing (relay_b discovers relay_a, syncs, re-processes)
|
||||
tokio::time::sleep(Duration::from_secs(3)).await;
|
||||
|
||||
@@ -114,15 +147,13 @@ async fn test_maintainer_announcement_reprocessed_immediately() {
|
||||
|
||||
// Step 5: Verify it happened quickly (not 24 hours!)
|
||||
assert!(
|
||||
elapsed.as_secs() < 10,
|
||||
"Re-processing should happen in <10 seconds, took {:?}",
|
||||
elapsed.as_secs() < 15,
|
||||
"Re-processing should happen in <15 seconds, took {:?}",
|
||||
elapsed
|
||||
);
|
||||
|
||||
println!("✅ Maintainer announcement re-processed in {:?}", elapsed);
|
||||
|
||||
client_a.disconnect().await;
|
||||
client_b.disconnect().await;
|
||||
relay_a.stop().await;
|
||||
relay_b.stop().await;
|
||||
}
|
||||
@@ -253,15 +284,18 @@ async fn test_multiple_maintainers_all_reprocessed() {
|
||||
|
||||
let identifier = "multi-maintainer-repo";
|
||||
|
||||
// Step 1: Send three maintainer announcements to relay_a
|
||||
let client_a = TestClient::new(relay_a.url(), maintainer1_keys.clone())
|
||||
.await
|
||||
.expect("Failed to connect to relay_a");
|
||||
|
||||
// Step 1: Send three maintainer announcements to relay_a with git data
|
||||
// (purgatory requires git data before announcements are accepted)
|
||||
let mut git_dirs_maintainers = Vec::new();
|
||||
for (idx, maintainer_keys) in [&maintainer1_keys, &maintainer2_keys, &maintainer3_keys]
|
||||
.iter()
|
||||
.enumerate()
|
||||
{
|
||||
let m_npub = maintainer_keys
|
||||
.public_key()
|
||||
.to_bech32()
|
||||
.expect("Failed to get npub");
|
||||
|
||||
let announcement = EventBuilder::new(
|
||||
Kind::GitRepoAnnouncement,
|
||||
format!("Maintainer {} repository", idx + 1),
|
||||
@@ -270,28 +304,45 @@ async fn test_multiple_maintainers_all_reprocessed() {
|
||||
Tag::identifier(identifier),
|
||||
Tag::custom(
|
||||
TagKind::custom("clone"),
|
||||
vec![format!("https://{}/{}.git", relay_a.domain(), identifier)],
|
||||
vec![format!(
|
||||
"http://{}/{}/{}.git",
|
||||
relay_a.domain(),
|
||||
m_npub,
|
||||
identifier
|
||||
)],
|
||||
),
|
||||
Tag::custom(TagKind::custom("relays"), vec![relay_a.url().to_string()]),
|
||||
])
|
||||
.sign_with_keys(maintainer_keys)
|
||||
.unwrap();
|
||||
|
||||
client_a.send_event(&announcement).await.unwrap();
|
||||
send_to_relay(&relay_a, &announcement).await.unwrap();
|
||||
|
||||
// Push git data to release each maintainer's announcement from purgatory
|
||||
let git_dir =
|
||||
push_git_data_to_relay(&relay_a, maintainer_keys, identifier, &[&relay_a.domain()])
|
||||
.await;
|
||||
git_dirs_maintainers.push(git_dir);
|
||||
}
|
||||
println!("✓ Three maintainer announcements sent to relay_a");
|
||||
println!("✓ Three maintainer announcements sent to relay_a with git data");
|
||||
|
||||
// Step 2: Send owner announcement to relay_b (lists relay_a + all three maintainers)
|
||||
let client_b = TestClient::new(relay_b.url(), owner_keys.clone())
|
||||
.await
|
||||
.expect("Failed to connect to relay_b");
|
||||
let owner_npub = owner_keys
|
||||
.public_key()
|
||||
.to_bech32()
|
||||
.expect("Failed to get npub");
|
||||
|
||||
let owner_announcement = EventBuilder::new(Kind::GitRepoAnnouncement, "Owner's repository")
|
||||
.tags(vec![
|
||||
Tag::identifier(identifier),
|
||||
Tag::custom(
|
||||
TagKind::custom("clone"),
|
||||
vec![format!("https://{}/{}.git", relay_b.domain(), identifier)],
|
||||
vec![format!(
|
||||
"http://{}/{}/{}.git",
|
||||
relay_b.domain(),
|
||||
owner_npub,
|
||||
identifier
|
||||
)],
|
||||
),
|
||||
Tag::custom(
|
||||
TagKind::custom("relays"),
|
||||
@@ -309,9 +360,14 @@ async fn test_multiple_maintainers_all_reprocessed() {
|
||||
.sign_with_keys(&owner_keys)
|
||||
.unwrap();
|
||||
|
||||
client_b.send_event(&owner_announcement).await.unwrap();
|
||||
send_to_relay(&relay_b, &owner_announcement).await.unwrap();
|
||||
println!("✓ Owner announcement sent to relay_b");
|
||||
|
||||
// Push git data for owner to relay_b → releases owner announcement from purgatory
|
||||
let _git_dir_owner =
|
||||
push_git_data_to_relay(&relay_b, &owner_keys, identifier, &[&relay_b.domain()]).await;
|
||||
println!("✓ Owner git data pushed to relay_b (announcement released from purgatory)");
|
||||
|
||||
// Step 3: Wait for sync and re-processing
|
||||
tokio::time::sleep(Duration::from_secs(3)).await;
|
||||
|
||||
@@ -333,8 +389,6 @@ async fn test_multiple_maintainers_all_reprocessed() {
|
||||
|
||||
println!("✅ All three maintainer announcements re-processed successfully");
|
||||
|
||||
client_a.disconnect().await;
|
||||
client_b.disconnect().await;
|
||||
relay_a.stop().await;
|
||||
relay_b.stop().await;
|
||||
}
|
||||
@@ -356,12 +410,8 @@ async fn test_invalid_maintainer_pubkey_handled_gracefully() {
|
||||
|
||||
let identifier = "invalid-maintainer-repo";
|
||||
|
||||
// Create client using TestClient helper
|
||||
let client = TestClient::new(relay.url(), owner_keys.clone())
|
||||
.await
|
||||
.expect("Failed to connect to relay");
|
||||
|
||||
// Step 1: Send maintainer announcement (will be rejected - doesn't list our relay)
|
||||
// This one uses example.com clone URL - it goes to purgatory on relay, never promoted
|
||||
let maintainer_announcement =
|
||||
EventBuilder::new(Kind::GitRepoAnnouncement, "Maintainer's repository")
|
||||
.tags(vec![
|
||||
@@ -378,17 +428,28 @@ async fn test_invalid_maintainer_pubkey_handled_gracefully() {
|
||||
.sign_with_keys(&maintainer_keys)
|
||||
.unwrap();
|
||||
|
||||
// Send maintainer announcement - expect it to be rejected
|
||||
let _ = client.send_event(&maintainer_announcement).await;
|
||||
// Send maintainer announcement - expect it to be rejected (purgatory / policy)
|
||||
send_to_relay(&relay, &maintainer_announcement).await.ok();
|
||||
tokio::time::sleep(Duration::from_millis(200)).await;
|
||||
|
||||
// Step 2: Send owner announcement with INVALID maintainer hex
|
||||
// Step 2: Set up owner announcement with INVALID maintainer hex and git data
|
||||
// Use HTTP clone URL to relay's git endpoint so it can be released from purgatory
|
||||
let owner_npub = owner_keys
|
||||
.public_key()
|
||||
.to_bech32()
|
||||
.expect("Failed to get npub");
|
||||
|
||||
let owner_announcement = EventBuilder::new(Kind::GitRepoAnnouncement, "Owner's repository")
|
||||
.tags(vec![
|
||||
Tag::identifier(identifier),
|
||||
Tag::custom(
|
||||
TagKind::custom("clone"),
|
||||
vec![format!("https://{}/{}.git", relay.domain(), identifier)],
|
||||
vec![format!(
|
||||
"http://{}/{}/{}.git",
|
||||
relay.domain(),
|
||||
owner_npub,
|
||||
identifier
|
||||
)],
|
||||
),
|
||||
Tag::custom(TagKind::custom("relays"), vec![relay.url().to_string()]),
|
||||
Tag::custom(
|
||||
@@ -399,7 +460,14 @@ async fn test_invalid_maintainer_pubkey_handled_gracefully() {
|
||||
.sign_with_keys(&owner_keys)
|
||||
.unwrap();
|
||||
|
||||
client.send_event(&owner_announcement).await.unwrap();
|
||||
send_to_relay(&relay, &owner_announcement).await.unwrap();
|
||||
|
||||
// Push git data to relay → releases owner announcement from purgatory
|
||||
let _git_dir =
|
||||
push_git_data_to_relay(&relay, &owner_keys, identifier, &[&relay.domain()]).await;
|
||||
println!("✓ Owner git data pushed to relay (announcement released from purgatory)");
|
||||
|
||||
// Wait for processing
|
||||
tokio::time::sleep(Duration::from_millis(500)).await;
|
||||
|
||||
// Step 3: Verify owner announcement accepted, maintainer not re-processed
|
||||
@@ -429,6 +497,5 @@ async fn test_invalid_maintainer_pubkey_handled_gracefully() {
|
||||
|
||||
println!("✅ Invalid maintainer pubkey handled gracefully without panic");
|
||||
|
||||
client.disconnect().await;
|
||||
relay.stop().await;
|
||||
}
|
||||
|
||||
+86
-53
@@ -16,8 +16,8 @@ use nostr_sdk::prelude::*;
|
||||
|
||||
use crate::common::{
|
||||
sync_helpers::{
|
||||
create_repo_announcement, fetch_metrics, wait_for_sync_connection, MetricsTestHarness,
|
||||
ParsedMetrics, TestClient,
|
||||
create_repo_announcement, fetch_metrics, setup_announcement_on_relay,
|
||||
wait_for_sync_connection, MetricsTestHarness, ParsedMetrics, TestClient,
|
||||
},
|
||||
TestRelay,
|
||||
};
|
||||
@@ -224,16 +224,17 @@ async fn test_startup_sync_event_count() {
|
||||
// 3. Create test keys
|
||||
let keys = Keys::generate();
|
||||
|
||||
// 4. Create an announcement that lists BOTH relays (required for discovery)
|
||||
let announcement = create_repo_announcement(
|
||||
&keys,
|
||||
&[&source_relay.domain(), &syncing_relay.domain()],
|
||||
"test-repo-metrics",
|
||||
);
|
||||
// 4. Set up announcement on SOURCE relay with git data
|
||||
// (purgatory requires git data before announcements are accepted)
|
||||
let repo_id = "test-repo-metrics";
|
||||
let domains = vec![source_relay.domain(), syncing_relay.domain()];
|
||||
let domain_refs: Vec<&str> = domains.iter().map(|s| s.as_str()).collect();
|
||||
|
||||
let (announcement, _git_dir_source) =
|
||||
setup_announcement_on_relay(&source_relay, &keys, &domain_refs, repo_id).await;
|
||||
println!(
|
||||
"Created announcement {} (kind {})",
|
||||
announcement.id,
|
||||
announcement.kind.as_u16()
|
||||
"Announcement {} set up on source relay with git data",
|
||||
announcement.id
|
||||
);
|
||||
|
||||
// 5. Build the repo coordinate for the 'a' tag in the patches
|
||||
@@ -241,7 +242,7 @@ async fn test_startup_sync_event_count() {
|
||||
"{}:{}:{}",
|
||||
Kind::GitRepoAnnouncement.as_u16(),
|
||||
keys.public_key().to_hex(),
|
||||
"test-repo-metrics"
|
||||
repo_id
|
||||
);
|
||||
|
||||
// 6. Create 3 patch events (Layer 2) that reference the announcement
|
||||
@@ -257,17 +258,11 @@ async fn test_startup_sync_event_count() {
|
||||
.collect();
|
||||
println!("Created {} patches", patches.len());
|
||||
|
||||
// 7. Send announcement + patches to SOURCE relay ONLY
|
||||
// 7. Send patches to SOURCE relay
|
||||
let source_client = TestClient::new(source_relay.url(), keys.clone())
|
||||
.await
|
||||
.expect("Failed to connect to source relay");
|
||||
|
||||
source_client
|
||||
.send_event(&announcement)
|
||||
.await
|
||||
.expect("Failed to send announcement to source");
|
||||
println!("Announcement sent to source relay");
|
||||
|
||||
for patch in &patches {
|
||||
source_client
|
||||
.send_event(patch)
|
||||
@@ -277,17 +272,10 @@ async fn test_startup_sync_event_count() {
|
||||
println!("Patches sent to source relay");
|
||||
source_client.disconnect().await;
|
||||
|
||||
// 8. Send announcement to SYNCING relay (triggers discovery of source relay)
|
||||
let syncing_client = TestClient::new(syncing_relay.url(), keys.clone())
|
||||
.await
|
||||
.expect("Failed to connect to syncing relay");
|
||||
|
||||
syncing_client
|
||||
.send_event(&announcement)
|
||||
.await
|
||||
.expect("Failed to send announcement to syncing relay");
|
||||
println!("Announcement sent to syncing relay (triggers discovery of source)");
|
||||
syncing_client.disconnect().await;
|
||||
// 8. Set up announcement on SYNCING relay (triggers discovery of source relay)
|
||||
let (_announcement_syncing, _git_dir_syncing) =
|
||||
setup_announcement_on_relay(&syncing_relay, &keys, &domain_refs, repo_id).await;
|
||||
println!("Announcement set up on syncing relay (triggers discovery of source)");
|
||||
|
||||
// 9. Wait for discovery + sync to complete
|
||||
println!("Waiting 5s for discovery and sync...");
|
||||
@@ -404,18 +392,35 @@ async fn test_connection_failure_increments_counter() {
|
||||
/// Test that live sync events are counted in metrics.
|
||||
///
|
||||
/// This test validates that events received via live subscription
|
||||
/// (after sync connection is established) are counted separately
|
||||
/// from startup/bootstrap events.
|
||||
/// (after sync connection is established) are counted in metrics.
|
||||
/// Uses Layer 2 patch events (not announcements) to avoid purgatory,
|
||||
/// since Layer 2 events are accepted directly to the DB.
|
||||
#[tokio::test]
|
||||
async fn test_live_sync_event_count() {
|
||||
let mut harness = MetricsTestHarness::with_sources(1).await;
|
||||
|
||||
// Pre-allocate syncing relay port to include in announcements
|
||||
let sync_port = TestRelay::find_free_port();
|
||||
let sync_domain = format!("127.0.0.1:{}", sync_port);
|
||||
|
||||
// Start source relay
|
||||
let source_relay = TestRelay::start().await;
|
||||
println!("Source relay started at {}", source_relay.url());
|
||||
|
||||
// Set up announcement on source relay BEFORE starting syncing relay
|
||||
// This allows discovery when syncing relay connects
|
||||
let keys = Keys::generate();
|
||||
let repo_id = "live-metrics-repo";
|
||||
let domains = vec![source_relay.domain(), sync_domain.clone()];
|
||||
let domain_refs: Vec<&str> = domains.iter().map(|s| s.as_str()).collect();
|
||||
|
||||
let (_announcement, _git_dir) =
|
||||
setup_announcement_on_relay(&source_relay, &keys, &domain_refs, repo_id).await;
|
||||
println!("Announcement set up on source relay with git data");
|
||||
|
||||
// Start syncing relay with pre-allocated port
|
||||
harness.start_syncing_relay_on_port(0, sync_port).await;
|
||||
let syncing_relay =
|
||||
TestRelay::start_on_port_with_options(sync_port, Some(source_relay.url().to_string()), false)
|
||||
.await;
|
||||
println!("Syncing relay started at {}", syncing_relay.url());
|
||||
|
||||
// Wait for sync connection to be fully established with EOSE received
|
||||
// This ensures we're in "live" mode before submitting test events
|
||||
@@ -424,33 +429,61 @@ async fn test_live_sync_event_count() {
|
||||
.await
|
||||
.expect("Sync connection should be established");
|
||||
|
||||
// Additional small delay to ensure EOSE has been processed
|
||||
tokio::time::sleep(Duration::from_millis(500)).await;
|
||||
// Additional delay to ensure purgatory promotion completes on syncing relay
|
||||
tokio::time::sleep(Duration::from_secs(4)).await;
|
||||
|
||||
// Now add events - these should be "live" not "startup"
|
||||
// Include BOTH domains so events are accepted by both relays
|
||||
let keys = Keys::generate();
|
||||
let events: Vec<_> = (0..2)
|
||||
.map(|i| {
|
||||
create_repo_announcement(
|
||||
&keys,
|
||||
&[&harness.source_domain(0), &sync_domain],
|
||||
&format!("live-{}", i),
|
||||
)
|
||||
})
|
||||
.collect();
|
||||
harness.submit_events(0, &events).await.unwrap();
|
||||
// Now add Layer 2 patch events (not announcements) - these are accepted immediately
|
||||
// (Layer 2 events are accepted directly to DB, no purgatory)
|
||||
let repo_coord_str = format!(
|
||||
"{}:{}:{}",
|
||||
Kind::GitRepoAnnouncement.as_u16(),
|
||||
keys.public_key().to_hex(),
|
||||
repo_id
|
||||
);
|
||||
|
||||
let patch1 = create_event_referencing_repo(
|
||||
&keys,
|
||||
&repo_coord_str,
|
||||
Kind::GitPatch.as_u16(),
|
||||
"Live test patch 1",
|
||||
);
|
||||
let patch2 = create_event_referencing_repo(
|
||||
&keys,
|
||||
&repo_coord_str,
|
||||
Kind::GitPatch.as_u16(),
|
||||
"Live test patch 2",
|
||||
);
|
||||
|
||||
// Send patches to source AFTER sync connection established (live mode)
|
||||
let client = TestClient::new(source_relay.url(), keys.clone())
|
||||
.await
|
||||
.expect("Failed to connect to source");
|
||||
client.send_event(&patch1).await.expect("Failed to send patch 1");
|
||||
client.send_event(&patch2).await.expect("Failed to send patch 2");
|
||||
client.disconnect().await;
|
||||
println!("Two patches sent to source relay (live mode)");
|
||||
|
||||
// Wait for live events to be processed and metrics updated
|
||||
tokio::time::sleep(Duration::from_secs(4)).await;
|
||||
let metrics = harness.get_metrics().await.unwrap();
|
||||
|
||||
// Fetch metrics from syncing relay
|
||||
let raw_metrics = fetch_metrics(&sync_url)
|
||||
.await
|
||||
.expect("Failed to fetch metrics");
|
||||
let metrics = ParsedMetrics::parse(&raw_metrics);
|
||||
|
||||
let synced_count = metrics.events_synced_total();
|
||||
println!("Events synced total: {:?}", synced_count);
|
||||
|
||||
assert_eq!(synced_count, Some(2), "Should have 2 synced events");
|
||||
// Cleanup
|
||||
syncing_relay.stop().await;
|
||||
source_relay.stop().await;
|
||||
|
||||
harness.stop_all().await;
|
||||
assert!(
|
||||
synced_count.is_some() && synced_count.unwrap() >= 2,
|
||||
"Should have synced at least 2 events, got {:?}",
|
||||
synced_count
|
||||
);
|
||||
}
|
||||
|
||||
/// Test that relay connected status is tracked in metrics.
|
||||
|
||||
+79
-165
@@ -55,30 +55,19 @@ async fn test_layer2_sync_with_lowercase_a_tag() {
|
||||
|
||||
let keys = Keys::generate();
|
||||
|
||||
// 2. Create and send repository announcement to both relays
|
||||
// 2. Create and send repository announcement to both relays with git data
|
||||
// (purgatory requires git data before announcements are accepted)
|
||||
let repo_id = "test-repo-tag-8a";
|
||||
let announcement =
|
||||
create_repo_announcement(&keys, &[&relay_a.domain(), &relay_b.domain()], repo_id);
|
||||
let domains = vec![relay_a.domain(), relay_b.domain()];
|
||||
let domain_refs: Vec<&str> = domains.iter().map(|s| s.as_str()).collect();
|
||||
|
||||
let client_a = TestClient::new(relay_a.url(), keys.clone())
|
||||
.await
|
||||
.expect("Failed to connect to relay_a");
|
||||
let (_announcement, _git_dir_a) =
|
||||
setup_announcement_on_relay(&relay_a, &keys, &domain_refs, repo_id).await;
|
||||
println!("Announcement set up on relay_a with git data");
|
||||
|
||||
let client_b = TestClient::new(relay_b.url(), keys.clone())
|
||||
.await
|
||||
.expect("Failed to connect to relay_b");
|
||||
|
||||
client_a
|
||||
.send_event(&announcement)
|
||||
.await
|
||||
.expect("Failed to send announcement to relay_a");
|
||||
println!("Announcement sent to relay_a");
|
||||
|
||||
client_b
|
||||
.send_event(&announcement)
|
||||
.await
|
||||
.expect("Failed to send announcement to relay_b");
|
||||
println!("Announcement sent to relay_b (triggers discovery)");
|
||||
let (_announcement_b, _git_dir_b) =
|
||||
setup_announcement_on_relay(&relay_b, &keys, &domain_refs, repo_id).await;
|
||||
println!("Announcement set up on relay_b with git data (triggers discovery)");
|
||||
|
||||
// 3. Wait for discovery
|
||||
tokio::time::sleep(Duration::from_secs(1)).await;
|
||||
@@ -95,9 +84,10 @@ async fn test_layer2_sync_with_lowercase_a_tag() {
|
||||
issue_id,
|
||||
issue.kind.as_u16()
|
||||
);
|
||||
for tag in issue.tags.iter() {
|
||||
println!(" Tag: {:?}", tag.as_slice());
|
||||
}
|
||||
|
||||
let client_a = TestClient::new(relay_a.url(), keys.clone())
|
||||
.await
|
||||
.expect("Failed to connect to relay_a");
|
||||
|
||||
client_a
|
||||
.send_event(&issue)
|
||||
@@ -106,7 +96,6 @@ async fn test_layer2_sync_with_lowercase_a_tag() {
|
||||
println!("Issue sent to relay_a");
|
||||
|
||||
client_a.disconnect().await;
|
||||
client_b.disconnect().await;
|
||||
|
||||
// 5. Wait and verify event syncs to relay_b
|
||||
let filter = Filter::new()
|
||||
@@ -154,30 +143,18 @@ async fn test_layer2_sync_with_uppercase_a_tag() {
|
||||
|
||||
let keys = Keys::generate();
|
||||
|
||||
// 2. Create and send repository announcement to both relays
|
||||
// 2. Create and send repository announcement to both relays with git data
|
||||
let repo_id = "test-repo-tag-8b";
|
||||
let announcement =
|
||||
create_repo_announcement(&keys, &[&relay_a.domain(), &relay_b.domain()], repo_id);
|
||||
let domains = vec![relay_a.domain(), relay_b.domain()];
|
||||
let domain_refs: Vec<&str> = domains.iter().map(|s| s.as_str()).collect();
|
||||
|
||||
let client_a = TestClient::new(relay_a.url(), keys.clone())
|
||||
.await
|
||||
.expect("Failed to connect to relay_a");
|
||||
let (_announcement, _git_dir_a) =
|
||||
setup_announcement_on_relay(&relay_a, &keys, &domain_refs, repo_id).await;
|
||||
println!("Announcement set up on relay_a with git data");
|
||||
|
||||
let client_b = TestClient::new(relay_b.url(), keys.clone())
|
||||
.await
|
||||
.expect("Failed to connect to relay_b");
|
||||
|
||||
client_a
|
||||
.send_event(&announcement)
|
||||
.await
|
||||
.expect("Failed to send announcement to relay_a");
|
||||
println!("Announcement sent to relay_a");
|
||||
|
||||
client_b
|
||||
.send_event(&announcement)
|
||||
.await
|
||||
.expect("Failed to send announcement to relay_b");
|
||||
println!("Announcement sent to relay_b (triggers discovery)");
|
||||
let (_announcement_b, _git_dir_b) =
|
||||
setup_announcement_on_relay(&relay_b, &keys, &domain_refs, repo_id).await;
|
||||
println!("Announcement set up on relay_b with git data (triggers discovery)");
|
||||
|
||||
// 3. Wait for discovery
|
||||
tokio::time::sleep(Duration::from_secs(1)).await;
|
||||
@@ -197,9 +174,10 @@ async fn test_layer2_sync_with_uppercase_a_tag() {
|
||||
issue_id,
|
||||
issue.kind.as_u16()
|
||||
);
|
||||
for tag in issue.tags.iter() {
|
||||
println!(" Tag: {:?}", tag.as_slice());
|
||||
}
|
||||
|
||||
let client_a = TestClient::new(relay_a.url(), keys.clone())
|
||||
.await
|
||||
.expect("Failed to connect to relay_a");
|
||||
|
||||
client_a
|
||||
.send_event(&issue)
|
||||
@@ -208,7 +186,6 @@ async fn test_layer2_sync_with_uppercase_a_tag() {
|
||||
println!("Issue sent to relay_a");
|
||||
|
||||
client_a.disconnect().await;
|
||||
client_b.disconnect().await;
|
||||
|
||||
// 5. Wait and verify event syncs to relay_b
|
||||
let filter = Filter::new()
|
||||
@@ -255,30 +232,18 @@ async fn test_layer2_sync_with_q_tag() {
|
||||
|
||||
let keys = Keys::generate();
|
||||
|
||||
// 2. Create and send repository announcement to both relays
|
||||
// 2. Create and send repository announcement to both relays with git data
|
||||
let repo_id = "test-repo-tag-8c";
|
||||
let announcement =
|
||||
create_repo_announcement(&keys, &[&relay_a.domain(), &relay_b.domain()], repo_id);
|
||||
let domains = vec![relay_a.domain(), relay_b.domain()];
|
||||
let domain_refs: Vec<&str> = domains.iter().map(|s| s.as_str()).collect();
|
||||
|
||||
let client_a = TestClient::new(relay_a.url(), keys.clone())
|
||||
.await
|
||||
.expect("Failed to connect to relay_a");
|
||||
let (_announcement, _git_dir_a) =
|
||||
setup_announcement_on_relay(&relay_a, &keys, &domain_refs, repo_id).await;
|
||||
println!("Announcement set up on relay_a with git data");
|
||||
|
||||
let client_b = TestClient::new(relay_b.url(), keys.clone())
|
||||
.await
|
||||
.expect("Failed to connect to relay_b");
|
||||
|
||||
client_a
|
||||
.send_event(&announcement)
|
||||
.await
|
||||
.expect("Failed to send announcement to relay_a");
|
||||
println!("Announcement sent to relay_a");
|
||||
|
||||
client_b
|
||||
.send_event(&announcement)
|
||||
.await
|
||||
.expect("Failed to send announcement to relay_b");
|
||||
println!("Announcement sent to relay_b (triggers discovery)");
|
||||
let (_announcement_b, _git_dir_b) =
|
||||
setup_announcement_on_relay(&relay_b, &keys, &domain_refs, repo_id).await;
|
||||
println!("Announcement set up on relay_b with git data (triggers discovery)");
|
||||
|
||||
// 3. Wait for discovery
|
||||
tokio::time::sleep(Duration::from_secs(1)).await;
|
||||
@@ -294,9 +259,10 @@ async fn test_layer2_sync_with_q_tag() {
|
||||
issue_id,
|
||||
issue.kind.as_u16()
|
||||
);
|
||||
for tag in issue.tags.iter() {
|
||||
println!(" Tag: {:?}", tag.as_slice());
|
||||
}
|
||||
|
||||
let client_a = TestClient::new(relay_a.url(), keys.clone())
|
||||
.await
|
||||
.expect("Failed to connect to relay_a");
|
||||
|
||||
client_a
|
||||
.send_event(&issue)
|
||||
@@ -305,7 +271,6 @@ async fn test_layer2_sync_with_q_tag() {
|
||||
println!("Issue sent to relay_a");
|
||||
|
||||
client_a.disconnect().await;
|
||||
client_b.disconnect().await;
|
||||
|
||||
// 5. Wait and verify event syncs to relay_b
|
||||
let filter = Filter::new()
|
||||
@@ -362,30 +327,18 @@ async fn test_layer3_sync_with_lowercase_e_tag() {
|
||||
|
||||
let keys = Keys::generate();
|
||||
|
||||
// 2. Create and send repository announcement to both relays
|
||||
// 2. Create and send repository announcement to both relays with git data
|
||||
let repo_id = "test-repo-tag-9a";
|
||||
let announcement =
|
||||
create_repo_announcement(&keys, &[&relay_a.domain(), &relay_b.domain()], repo_id);
|
||||
let domains = vec![relay_a.domain(), relay_b.domain()];
|
||||
let domain_refs: Vec<&str> = domains.iter().map(|s| s.as_str()).collect();
|
||||
|
||||
let client_a = TestClient::new(relay_a.url(), keys.clone())
|
||||
.await
|
||||
.expect("Failed to connect to relay_a");
|
||||
let (_announcement, _git_dir_a) =
|
||||
setup_announcement_on_relay(&relay_a, &keys, &domain_refs, repo_id).await;
|
||||
println!("Announcement set up on relay_a with git data");
|
||||
|
||||
let client_b = TestClient::new(relay_b.url(), keys.clone())
|
||||
.await
|
||||
.expect("Failed to connect to relay_b");
|
||||
|
||||
client_a
|
||||
.send_event(&announcement)
|
||||
.await
|
||||
.expect("Failed to send announcement to relay_a");
|
||||
println!("Announcement sent to relay_a");
|
||||
|
||||
client_b
|
||||
.send_event(&announcement)
|
||||
.await
|
||||
.expect("Failed to send announcement to relay_b");
|
||||
println!("Announcement sent to relay_b (triggers discovery)");
|
||||
let (_announcement_b, _git_dir_b) =
|
||||
setup_announcement_on_relay(&relay_b, &keys, &domain_refs, repo_id).await;
|
||||
println!("Announcement set up on relay_b with git data (triggers discovery)");
|
||||
|
||||
// 3. Wait for discovery
|
||||
tokio::time::sleep(Duration::from_secs(1)).await;
|
||||
@@ -396,6 +349,10 @@ async fn test_layer3_sync_with_lowercase_e_tag() {
|
||||
.expect("Failed to create issue");
|
||||
let issue_id = issue.id;
|
||||
|
||||
let client_a = TestClient::new(relay_a.url(), keys.clone())
|
||||
.await
|
||||
.expect("Failed to connect to relay_a");
|
||||
|
||||
client_a
|
||||
.send_event(&issue)
|
||||
.await
|
||||
@@ -410,11 +367,6 @@ async fn test_layer3_sync_with_lowercase_e_tag() {
|
||||
assert!(issue_synced, "Layer 2 issue should sync first");
|
||||
|
||||
// Wait for Layer 3 subscriptions to be established
|
||||
// After issue syncs, relay_b's SelfSubscriber needs time to:
|
||||
// 1. Receive the synced issue via notify_event broadcast
|
||||
// 2. Batch timer to tick (up to 200ms in tests)
|
||||
// 3. Process batch and create Layer 3 filters
|
||||
// 4. Subscribe to relay_a with Layer 3 filters
|
||||
tokio::time::sleep(Duration::from_millis(500)).await;
|
||||
|
||||
// 6. Create and send Layer 3 reply with lowercase 'e' tag (kind 1)
|
||||
@@ -427,9 +379,6 @@ async fn test_layer3_sync_with_lowercase_e_tag() {
|
||||
reply_id,
|
||||
reply.kind.as_u16()
|
||||
);
|
||||
for tag in reply.tags.iter() {
|
||||
println!(" Tag: {:?}", tag.as_slice());
|
||||
}
|
||||
|
||||
client_a
|
||||
.send_event(&reply)
|
||||
@@ -438,7 +387,6 @@ async fn test_layer3_sync_with_lowercase_e_tag() {
|
||||
println!("Layer 3 reply {} sent to relay_a", reply_id);
|
||||
|
||||
client_a.disconnect().await;
|
||||
client_b.disconnect().await;
|
||||
|
||||
// 7. Wait and verify reply syncs to relay_b
|
||||
let reply_filter = Filter::new()
|
||||
@@ -486,30 +434,18 @@ async fn test_layer3_sync_with_uppercase_e_tag() {
|
||||
|
||||
let keys = Keys::generate();
|
||||
|
||||
// 2. Create and send repository announcement to both relays
|
||||
// 2. Create and send repository announcement to both relays with git data
|
||||
let repo_id = "test-repo-tag-9b";
|
||||
let announcement =
|
||||
create_repo_announcement(&keys, &[&relay_a.domain(), &relay_b.domain()], repo_id);
|
||||
let domains = vec![relay_a.domain(), relay_b.domain()];
|
||||
let domain_refs: Vec<&str> = domains.iter().map(|s| s.as_str()).collect();
|
||||
|
||||
let client_a = TestClient::new(relay_a.url(), keys.clone())
|
||||
.await
|
||||
.expect("Failed to connect to relay_a");
|
||||
let (_announcement, _git_dir_a) =
|
||||
setup_announcement_on_relay(&relay_a, &keys, &domain_refs, repo_id).await;
|
||||
println!("Announcement set up on relay_a with git data");
|
||||
|
||||
let client_b = TestClient::new(relay_b.url(), keys.clone())
|
||||
.await
|
||||
.expect("Failed to connect to relay_b");
|
||||
|
||||
client_a
|
||||
.send_event(&announcement)
|
||||
.await
|
||||
.expect("Failed to send announcement to relay_a");
|
||||
println!("Announcement sent to relay_a");
|
||||
|
||||
client_b
|
||||
.send_event(&announcement)
|
||||
.await
|
||||
.expect("Failed to send announcement to relay_b");
|
||||
println!("Announcement sent to relay_b (triggers discovery)");
|
||||
let (_announcement_b, _git_dir_b) =
|
||||
setup_announcement_on_relay(&relay_b, &keys, &domain_refs, repo_id).await;
|
||||
println!("Announcement set up on relay_b with git data (triggers discovery)");
|
||||
|
||||
// 3. Wait for discovery
|
||||
tokio::time::sleep(Duration::from_secs(1)).await;
|
||||
@@ -520,6 +456,10 @@ async fn test_layer3_sync_with_uppercase_e_tag() {
|
||||
.expect("Failed to create issue");
|
||||
let issue_id = issue.id;
|
||||
|
||||
let client_a = TestClient::new(relay_a.url(), keys.clone())
|
||||
.await
|
||||
.expect("Failed to connect to relay_a");
|
||||
|
||||
client_a
|
||||
.send_event(&issue)
|
||||
.await
|
||||
@@ -534,11 +474,6 @@ async fn test_layer3_sync_with_uppercase_e_tag() {
|
||||
assert!(issue_synced, "Layer 2 issue should sync first");
|
||||
|
||||
// Wait for Layer 3 subscriptions to be established
|
||||
// After issue syncs, relay_b's SelfSubscriber needs time to:
|
||||
// 1. Receive the synced issue via notify_event broadcast
|
||||
// 2. Batch timer to tick (up to 200ms in tests)
|
||||
// 3. Process batch and create Layer 3 filters
|
||||
// 4. Subscribe to relay_a with Layer 3 filters
|
||||
tokio::time::sleep(Duration::from_millis(500)).await;
|
||||
|
||||
// 6. Create and send Layer 3 comment with uppercase 'E' tag (kind 1111)
|
||||
@@ -552,9 +487,6 @@ async fn test_layer3_sync_with_uppercase_e_tag() {
|
||||
comment_id,
|
||||
comment.kind.as_u16()
|
||||
);
|
||||
for tag in comment.tags.iter() {
|
||||
println!(" Tag: {:?}", tag.as_slice());
|
||||
}
|
||||
|
||||
client_a
|
||||
.send_event(&comment)
|
||||
@@ -563,7 +495,6 @@ async fn test_layer3_sync_with_uppercase_e_tag() {
|
||||
println!("Layer 3 comment {} sent to relay_a", comment_id);
|
||||
|
||||
client_a.disconnect().await;
|
||||
client_b.disconnect().await;
|
||||
|
||||
// 7. Wait and verify comment syncs to relay_b
|
||||
let comment_filter = Filter::new()
|
||||
@@ -614,30 +545,18 @@ async fn test_layer3_sync_with_q_tag() {
|
||||
|
||||
let keys = Keys::generate();
|
||||
|
||||
// 2. Create and send repository announcement to both relays
|
||||
// 2. Create and send repository announcement to both relays with git data
|
||||
let repo_id = "test-repo-tag-9c";
|
||||
let announcement =
|
||||
create_repo_announcement(&keys, &[&relay_a.domain(), &relay_b.domain()], repo_id);
|
||||
let domains = vec![relay_a.domain(), relay_b.domain()];
|
||||
let domain_refs: Vec<&str> = domains.iter().map(|s| s.as_str()).collect();
|
||||
|
||||
let client_a = TestClient::new(relay_a.url(), keys.clone())
|
||||
.await
|
||||
.expect("Failed to connect to relay_a");
|
||||
let (_announcement, _git_dir_a) =
|
||||
setup_announcement_on_relay(&relay_a, &keys, &domain_refs, repo_id).await;
|
||||
println!("Announcement set up on relay_a with git data");
|
||||
|
||||
let client_b = TestClient::new(relay_b.url(), keys.clone())
|
||||
.await
|
||||
.expect("Failed to connect to relay_b");
|
||||
|
||||
client_a
|
||||
.send_event(&announcement)
|
||||
.await
|
||||
.expect("Failed to send announcement to relay_a");
|
||||
println!("Announcement sent to relay_a");
|
||||
|
||||
client_b
|
||||
.send_event(&announcement)
|
||||
.await
|
||||
.expect("Failed to send announcement to relay_b");
|
||||
println!("Announcement sent to relay_b (triggers discovery)");
|
||||
let (_announcement_b, _git_dir_b) =
|
||||
setup_announcement_on_relay(&relay_b, &keys, &domain_refs, repo_id).await;
|
||||
println!("Announcement set up on relay_b with git data (triggers discovery)");
|
||||
|
||||
// 3. Wait for discovery
|
||||
tokio::time::sleep(Duration::from_secs(1)).await;
|
||||
@@ -648,6 +567,10 @@ async fn test_layer3_sync_with_q_tag() {
|
||||
.expect("Failed to create issue");
|
||||
let issue_id = issue.id;
|
||||
|
||||
let client_a = TestClient::new(relay_a.url(), keys.clone())
|
||||
.await
|
||||
.expect("Failed to connect to relay_a");
|
||||
|
||||
client_a
|
||||
.send_event(&issue)
|
||||
.await
|
||||
@@ -662,11 +585,6 @@ async fn test_layer3_sync_with_q_tag() {
|
||||
assert!(issue_synced, "Layer 2 issue should sync first");
|
||||
|
||||
// Wait for Layer 3 subscriptions to be established
|
||||
// After issue syncs, relay_b's SelfSubscriber needs time to:
|
||||
// 1. Receive the synced issue via notify_event broadcast
|
||||
// 2. Batch timer to tick (up to 200ms in tests)
|
||||
// 3. Process batch and create Layer 3 filters
|
||||
// 4. Subscribe to relay_a with Layer 3 filters
|
||||
tokio::time::sleep(Duration::from_millis(500)).await;
|
||||
|
||||
// 6. Create and send Layer 3 quote with 'q' tag (kind 1)
|
||||
@@ -679,9 +597,6 @@ async fn test_layer3_sync_with_q_tag() {
|
||||
quote_id,
|
||||
quote.kind.as_u16()
|
||||
);
|
||||
for tag in quote.tags.iter() {
|
||||
println!(" Tag: {:?}", tag.as_slice());
|
||||
}
|
||||
|
||||
client_a
|
||||
.send_event("e)
|
||||
@@ -690,7 +605,6 @@ async fn test_layer3_sync_with_q_tag() {
|
||||
println!("Layer 3 quote {} sent to relay_a", quote_id);
|
||||
|
||||
client_a.disconnect().await;
|
||||
client_b.disconnect().await;
|
||||
|
||||
// 7. Wait and verify quote syncs to relay_b
|
||||
let quote_filter = Filter::new()
|
||||
|
||||
Reference in New Issue
Block a user