diff options
| author | DanConwayDev <DanConwayDev@protonmail.com> | 2026-02-18 23:17:08 +0000 |
|---|---|---|
| committer | DanConwayDev <DanConwayDev@protonmail.com> | 2026-02-23 12:05:05 +0000 |
| commit | 49b9405dfcbb872686acdd7abc12dc9c94adc2ab (patch) | |
| tree | 2bd54765aad3853dddd68119c9143626ba3bfdaa /tests/sync/maintainer_reprocessing.rs | |
| parent | 63865548b07e44d69321af3b03ca2c29aa60d74d (diff) | |
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.
Diffstat (limited to 'tests/sync/maintainer_reprocessing.rs')
| -rw-r--r-- | tests/sync/maintainer_reprocessing.rs | 153 |
1 files changed, 110 insertions, 43 deletions
diff --git a/tests/sync/maintainer_reprocessing.rs b/tests/sync/maintainer_reprocessing.rs index df1bf78..266a437 100644 --- a/tests/sync/maintainer_reprocessing.rs +++ b/tests/sync/maintainer_reprocessing.rs | |||
| @@ -7,7 +7,10 @@ use std::time::Duration; | |||
| 7 | 7 | ||
| 8 | use nostr_sdk::prelude::*; | 8 | use nostr_sdk::prelude::*; |
| 9 | 9 | ||
| 10 | use crate::common::{sync_helpers::*, TestRelay}; | 10 | use crate::common::{ |
| 11 | sync_helpers::*, | ||
| 12 | TestRelay, | ||
| 13 | }; | ||
| 11 | 14 | ||
| 12 | /// Test that maintainer announcements are re-processed immediately when owner announcement accepted | 15 | /// Test that maintainer announcements are re-processed immediately when owner announcement accepted |
| 13 | /// | 16 | /// |
| @@ -37,10 +40,12 @@ async fn test_maintainer_announcement_reprocessed_immediately() { | |||
| 37 | 40 | ||
| 38 | let start = std::time::Instant::now(); | 41 | let start = std::time::Instant::now(); |
| 39 | 42 | ||
| 40 | // Step 1: Send maintainer announcement to relay_a (will be rejected - doesn't list relay_b) | 43 | // Step 1: Send maintainer announcement to relay_a (will be rejected by relay_b - doesn't list relay_b) |
| 41 | let client_a = TestClient::new(relay_a.url(), maintainer_keys.clone()) | 44 | // Use HTTP clone URL pointing to relay_a's git endpoint so it can be released from purgatory |
| 42 | .await | 45 | let maintainer_npub = maintainer_keys |
| 43 | .expect("Failed to connect to relay_a"); | 46 | .public_key() |
| 47 | .to_bech32() | ||
| 48 | .expect("Failed to get npub"); | ||
| 44 | 49 | ||
| 45 | let maintainer_announcement = | 50 | let maintainer_announcement = |
| 46 | EventBuilder::new(Kind::GitRepoAnnouncement, "Maintainer's repository") | 51 | EventBuilder::new(Kind::GitRepoAnnouncement, "Maintainer's repository") |
| @@ -48,27 +53,50 @@ async fn test_maintainer_announcement_reprocessed_immediately() { | |||
| 48 | Tag::identifier(identifier), | 53 | Tag::identifier(identifier), |
| 49 | Tag::custom( | 54 | Tag::custom( |
| 50 | TagKind::custom("clone"), | 55 | TagKind::custom("clone"), |
| 51 | vec![format!("https://{}/{}.git", relay_a.domain(), identifier)], | 56 | vec![format!( |
| 57 | "http://{}/{}/{}.git", | ||
| 58 | relay_a.domain(), | ||
| 59 | maintainer_npub, | ||
| 60 | identifier | ||
| 61 | )], | ||
| 52 | ), | 62 | ), |
| 53 | Tag::custom(TagKind::custom("relays"), vec![relay_a.url().to_string()]), | 63 | Tag::custom(TagKind::custom("relays"), vec![relay_a.url().to_string()]), |
| 54 | ]) | 64 | ]) |
| 55 | .sign_with_keys(&maintainer_keys) | 65 | .sign_with_keys(&maintainer_keys) |
| 56 | .unwrap(); | 66 | .unwrap(); |
| 57 | 67 | ||
| 58 | client_a.send_event(&maintainer_announcement).await.unwrap(); | 68 | send_to_relay(&relay_a, &maintainer_announcement) |
| 69 | .await | ||
| 70 | .unwrap(); | ||
| 59 | println!("✓ Maintainer announcement sent to relay_a"); | 71 | println!("✓ Maintainer announcement sent to relay_a"); |
| 60 | 72 | ||
| 61 | // Step 2: Send owner announcement to relay_b (lists relay_a + maintainer) | 73 | // Push git data for maintainer's repo to relay_a → releases maintainer announcement from purgatory |
| 62 | let client_b = TestClient::new(relay_b.url(), owner_keys.clone()) | 74 | let _git_dir_maintainer = push_git_data_to_relay( |
| 63 | .await | 75 | &relay_a, |
| 64 | .expect("Failed to connect to relay_b"); | 76 | &maintainer_keys, |
| 77 | identifier, | ||
| 78 | &[&relay_a.domain()], | ||
| 79 | ) | ||
| 80 | .await; | ||
| 81 | println!("✓ Maintainer git data pushed to relay_a (announcement released from purgatory)"); | ||
| 82 | |||
| 83 | // Step 2: Set up owner announcement on relay_b (lists relay_a + maintainer) with git data | ||
| 84 | let owner_npub = owner_keys | ||
| 85 | .public_key() | ||
| 86 | .to_bech32() | ||
| 87 | .expect("Failed to get npub"); | ||
| 65 | 88 | ||
| 66 | let owner_announcement = EventBuilder::new(Kind::GitRepoAnnouncement, "Owner's repository") | 89 | let owner_announcement = EventBuilder::new(Kind::GitRepoAnnouncement, "Owner's repository") |
| 67 | .tags(vec![ | 90 | .tags(vec![ |
| 68 | Tag::identifier(identifier), | 91 | Tag::identifier(identifier), |
| 69 | Tag::custom( | 92 | Tag::custom( |
| 70 | TagKind::custom("clone"), | 93 | TagKind::custom("clone"), |
| 71 | vec![format!("https://{}/{}.git", relay_b.domain(), identifier)], | 94 | vec![format!( |
| 95 | "http://{}/{}/{}.git", | ||
| 96 | relay_b.domain(), | ||
| 97 | owner_npub, | ||
| 98 | identifier | ||
| 99 | )], | ||
| 72 | ), | 100 | ), |
| 73 | Tag::custom( | 101 | Tag::custom( |
| 74 | TagKind::custom("relays"), | 102 | TagKind::custom("relays"), |
| @@ -82,9 +110,14 @@ async fn test_maintainer_announcement_reprocessed_immediately() { | |||
| 82 | .sign_with_keys(&owner_keys) | 110 | .sign_with_keys(&owner_keys) |
| 83 | .unwrap(); | 111 | .unwrap(); |
| 84 | 112 | ||
| 85 | client_b.send_event(&owner_announcement).await.unwrap(); | 113 | send_to_relay(&relay_b, &owner_announcement).await.unwrap(); |
| 86 | println!("✓ Owner announcement sent to relay_b"); | 114 | println!("✓ Owner announcement sent to relay_b"); |
| 87 | 115 | ||
| 116 | // Push git data for owner's repo to relay_b → releases owner announcement from purgatory | ||
| 117 | let _git_dir_owner = | ||
| 118 | push_git_data_to_relay(&relay_b, &owner_keys, identifier, &[&relay_b.domain()]).await; | ||
| 119 | println!("✓ Owner git data pushed to relay_b (announcement released from purgatory)"); | ||
| 120 | |||
| 88 | // Step 3: Wait for sync and re-processing (relay_b discovers relay_a, syncs, re-processes) | 121 | // Step 3: Wait for sync and re-processing (relay_b discovers relay_a, syncs, re-processes) |
| 89 | tokio::time::sleep(Duration::from_secs(3)).await; | 122 | tokio::time::sleep(Duration::from_secs(3)).await; |
| 90 | 123 | ||
| @@ -114,15 +147,13 @@ async fn test_maintainer_announcement_reprocessed_immediately() { | |||
| 114 | 147 | ||
| 115 | // Step 5: Verify it happened quickly (not 24 hours!) | 148 | // Step 5: Verify it happened quickly (not 24 hours!) |
| 116 | assert!( | 149 | assert!( |
| 117 | elapsed.as_secs() < 10, | 150 | elapsed.as_secs() < 15, |
| 118 | "Re-processing should happen in <10 seconds, took {:?}", | 151 | "Re-processing should happen in <15 seconds, took {:?}", |
| 119 | elapsed | 152 | elapsed |
| 120 | ); | 153 | ); |
| 121 | 154 | ||
| 122 | println!("✅ Maintainer announcement re-processed in {:?}", elapsed); | 155 | println!("✅ Maintainer announcement re-processed in {:?}", elapsed); |
| 123 | 156 | ||
| 124 | client_a.disconnect().await; | ||
| 125 | client_b.disconnect().await; | ||
| 126 | relay_a.stop().await; | 157 | relay_a.stop().await; |
| 127 | relay_b.stop().await; | 158 | relay_b.stop().await; |
| 128 | } | 159 | } |
| @@ -253,15 +284,18 @@ async fn test_multiple_maintainers_all_reprocessed() { | |||
| 253 | 284 | ||
| 254 | let identifier = "multi-maintainer-repo"; | 285 | let identifier = "multi-maintainer-repo"; |
| 255 | 286 | ||
| 256 | // Step 1: Send three maintainer announcements to relay_a | 287 | // Step 1: Send three maintainer announcements to relay_a with git data |
| 257 | let client_a = TestClient::new(relay_a.url(), maintainer1_keys.clone()) | 288 | // (purgatory requires git data before announcements are accepted) |
| 258 | .await | 289 | let mut git_dirs_maintainers = Vec::new(); |
| 259 | .expect("Failed to connect to relay_a"); | ||
| 260 | |||
| 261 | for (idx, maintainer_keys) in [&maintainer1_keys, &maintainer2_keys, &maintainer3_keys] | 290 | for (idx, maintainer_keys) in [&maintainer1_keys, &maintainer2_keys, &maintainer3_keys] |
| 262 | .iter() | 291 | .iter() |
| 263 | .enumerate() | 292 | .enumerate() |
| 264 | { | 293 | { |
| 294 | let m_npub = maintainer_keys | ||
| 295 | .public_key() | ||
| 296 | .to_bech32() | ||
| 297 | .expect("Failed to get npub"); | ||
| 298 | |||
| 265 | let announcement = EventBuilder::new( | 299 | let announcement = EventBuilder::new( |
| 266 | Kind::GitRepoAnnouncement, | 300 | Kind::GitRepoAnnouncement, |
| 267 | format!("Maintainer {} repository", idx + 1), | 301 | format!("Maintainer {} repository", idx + 1), |
| @@ -270,28 +304,45 @@ async fn test_multiple_maintainers_all_reprocessed() { | |||
| 270 | Tag::identifier(identifier), | 304 | Tag::identifier(identifier), |
| 271 | Tag::custom( | 305 | Tag::custom( |
| 272 | TagKind::custom("clone"), | 306 | TagKind::custom("clone"), |
| 273 | vec![format!("https://{}/{}.git", relay_a.domain(), identifier)], | 307 | vec![format!( |
| 308 | "http://{}/{}/{}.git", | ||
| 309 | relay_a.domain(), | ||
| 310 | m_npub, | ||
| 311 | identifier | ||
| 312 | )], | ||
| 274 | ), | 313 | ), |
| 275 | Tag::custom(TagKind::custom("relays"), vec![relay_a.url().to_string()]), | 314 | Tag::custom(TagKind::custom("relays"), vec![relay_a.url().to_string()]), |
| 276 | ]) | 315 | ]) |
| 277 | .sign_with_keys(maintainer_keys) | 316 | .sign_with_keys(maintainer_keys) |
| 278 | .unwrap(); | 317 | .unwrap(); |
| 279 | 318 | ||
| 280 | client_a.send_event(&announcement).await.unwrap(); | 319 | send_to_relay(&relay_a, &announcement).await.unwrap(); |
| 320 | |||
| 321 | // Push git data to release each maintainer's announcement from purgatory | ||
| 322 | let git_dir = | ||
| 323 | push_git_data_to_relay(&relay_a, maintainer_keys, identifier, &[&relay_a.domain()]) | ||
| 324 | .await; | ||
| 325 | git_dirs_maintainers.push(git_dir); | ||
| 281 | } | 326 | } |
| 282 | println!("✓ Three maintainer announcements sent to relay_a"); | 327 | println!("✓ Three maintainer announcements sent to relay_a with git data"); |
| 283 | 328 | ||
| 284 | // Step 2: Send owner announcement to relay_b (lists relay_a + all three maintainers) | 329 | // Step 2: Send owner announcement to relay_b (lists relay_a + all three maintainers) |
| 285 | let client_b = TestClient::new(relay_b.url(), owner_keys.clone()) | 330 | let owner_npub = owner_keys |
| 286 | .await | 331 | .public_key() |
| 287 | .expect("Failed to connect to relay_b"); | 332 | .to_bech32() |
| 333 | .expect("Failed to get npub"); | ||
| 288 | 334 | ||
| 289 | let owner_announcement = EventBuilder::new(Kind::GitRepoAnnouncement, "Owner's repository") | 335 | let owner_announcement = EventBuilder::new(Kind::GitRepoAnnouncement, "Owner's repository") |
| 290 | .tags(vec![ | 336 | .tags(vec![ |
| 291 | Tag::identifier(identifier), | 337 | Tag::identifier(identifier), |
| 292 | Tag::custom( | 338 | Tag::custom( |
| 293 | TagKind::custom("clone"), | 339 | TagKind::custom("clone"), |
| 294 | vec![format!("https://{}/{}.git", relay_b.domain(), identifier)], | 340 | vec![format!( |
| 341 | "http://{}/{}/{}.git", | ||
| 342 | relay_b.domain(), | ||
| 343 | owner_npub, | ||
| 344 | identifier | ||
| 345 | )], | ||
| 295 | ), | 346 | ), |
| 296 | Tag::custom( | 347 | Tag::custom( |
| 297 | TagKind::custom("relays"), | 348 | TagKind::custom("relays"), |
| @@ -309,9 +360,14 @@ async fn test_multiple_maintainers_all_reprocessed() { | |||
| 309 | .sign_with_keys(&owner_keys) | 360 | .sign_with_keys(&owner_keys) |
| 310 | .unwrap(); | 361 | .unwrap(); |
| 311 | 362 | ||
| 312 | client_b.send_event(&owner_announcement).await.unwrap(); | 363 | send_to_relay(&relay_b, &owner_announcement).await.unwrap(); |
| 313 | println!("✓ Owner announcement sent to relay_b"); | 364 | println!("✓ Owner announcement sent to relay_b"); |
| 314 | 365 | ||
| 366 | // Push git data for owner to relay_b → releases owner announcement from purgatory | ||
| 367 | let _git_dir_owner = | ||
| 368 | push_git_data_to_relay(&relay_b, &owner_keys, identifier, &[&relay_b.domain()]).await; | ||
| 369 | println!("✓ Owner git data pushed to relay_b (announcement released from purgatory)"); | ||
| 370 | |||
| 315 | // Step 3: Wait for sync and re-processing | 371 | // Step 3: Wait for sync and re-processing |
| 316 | tokio::time::sleep(Duration::from_secs(3)).await; | 372 | tokio::time::sleep(Duration::from_secs(3)).await; |
| 317 | 373 | ||
| @@ -333,8 +389,6 @@ async fn test_multiple_maintainers_all_reprocessed() { | |||
| 333 | 389 | ||
| 334 | println!("✅ All three maintainer announcements re-processed successfully"); | 390 | println!("✅ All three maintainer announcements re-processed successfully"); |
| 335 | 391 | ||
| 336 | client_a.disconnect().await; | ||
| 337 | client_b.disconnect().await; | ||
| 338 | relay_a.stop().await; | 392 | relay_a.stop().await; |
| 339 | relay_b.stop().await; | 393 | relay_b.stop().await; |
| 340 | } | 394 | } |
| @@ -356,12 +410,8 @@ async fn test_invalid_maintainer_pubkey_handled_gracefully() { | |||
| 356 | 410 | ||
| 357 | let identifier = "invalid-maintainer-repo"; | 411 | let identifier = "invalid-maintainer-repo"; |
| 358 | 412 | ||
| 359 | // Create client using TestClient helper | ||
| 360 | let client = TestClient::new(relay.url(), owner_keys.clone()) | ||
| 361 | .await | ||
| 362 | .expect("Failed to connect to relay"); | ||
| 363 | |||
| 364 | // Step 1: Send maintainer announcement (will be rejected - doesn't list our relay) | 413 | // Step 1: Send maintainer announcement (will be rejected - doesn't list our relay) |
| 414 | // This one uses example.com clone URL - it goes to purgatory on relay, never promoted | ||
| 365 | let maintainer_announcement = | 415 | let maintainer_announcement = |
| 366 | EventBuilder::new(Kind::GitRepoAnnouncement, "Maintainer's repository") | 416 | EventBuilder::new(Kind::GitRepoAnnouncement, "Maintainer's repository") |
| 367 | .tags(vec![ | 417 | .tags(vec![ |
| @@ -378,17 +428,28 @@ async fn test_invalid_maintainer_pubkey_handled_gracefully() { | |||
| 378 | .sign_with_keys(&maintainer_keys) | 428 | .sign_with_keys(&maintainer_keys) |
| 379 | .unwrap(); | 429 | .unwrap(); |
| 380 | 430 | ||
| 381 | // Send maintainer announcement - expect it to be rejected | 431 | // Send maintainer announcement - expect it to be rejected (purgatory / policy) |
| 382 | let _ = client.send_event(&maintainer_announcement).await; | 432 | send_to_relay(&relay, &maintainer_announcement).await.ok(); |
| 383 | tokio::time::sleep(Duration::from_millis(200)).await; | 433 | tokio::time::sleep(Duration::from_millis(200)).await; |
| 384 | 434 | ||
| 385 | // Step 2: Send owner announcement with INVALID maintainer hex | 435 | // Step 2: Set up owner announcement with INVALID maintainer hex and git data |
| 436 | // Use HTTP clone URL to relay's git endpoint so it can be released from purgatory | ||
| 437 | let owner_npub = owner_keys | ||
| 438 | .public_key() | ||
| 439 | .to_bech32() | ||
| 440 | .expect("Failed to get npub"); | ||
| 441 | |||
| 386 | let owner_announcement = EventBuilder::new(Kind::GitRepoAnnouncement, "Owner's repository") | 442 | let owner_announcement = EventBuilder::new(Kind::GitRepoAnnouncement, "Owner's repository") |
| 387 | .tags(vec![ | 443 | .tags(vec![ |
| 388 | Tag::identifier(identifier), | 444 | Tag::identifier(identifier), |
| 389 | Tag::custom( | 445 | Tag::custom( |
| 390 | TagKind::custom("clone"), | 446 | TagKind::custom("clone"), |
| 391 | vec![format!("https://{}/{}.git", relay.domain(), identifier)], | 447 | vec![format!( |
| 448 | "http://{}/{}/{}.git", | ||
| 449 | relay.domain(), | ||
| 450 | owner_npub, | ||
| 451 | identifier | ||
| 452 | )], | ||
| 392 | ), | 453 | ), |
| 393 | Tag::custom(TagKind::custom("relays"), vec![relay.url().to_string()]), | 454 | Tag::custom(TagKind::custom("relays"), vec![relay.url().to_string()]), |
| 394 | Tag::custom( | 455 | Tag::custom( |
| @@ -399,7 +460,14 @@ async fn test_invalid_maintainer_pubkey_handled_gracefully() { | |||
| 399 | .sign_with_keys(&owner_keys) | 460 | .sign_with_keys(&owner_keys) |
| 400 | .unwrap(); | 461 | .unwrap(); |
| 401 | 462 | ||
| 402 | client.send_event(&owner_announcement).await.unwrap(); | 463 | send_to_relay(&relay, &owner_announcement).await.unwrap(); |
| 464 | |||
| 465 | // Push git data to relay → releases owner announcement from purgatory | ||
| 466 | let _git_dir = | ||
| 467 | push_git_data_to_relay(&relay, &owner_keys, identifier, &[&relay.domain()]).await; | ||
| 468 | println!("✓ Owner git data pushed to relay (announcement released from purgatory)"); | ||
| 469 | |||
| 470 | // Wait for processing | ||
| 403 | tokio::time::sleep(Duration::from_millis(500)).await; | 471 | tokio::time::sleep(Duration::from_millis(500)).await; |
| 404 | 472 | ||
| 405 | // Step 3: Verify owner announcement accepted, maintainer not re-processed | 473 | // Step 3: Verify owner announcement accepted, maintainer not re-processed |
| @@ -429,6 +497,5 @@ async fn test_invalid_maintainer_pubkey_handled_gracefully() { | |||
| 429 | 497 | ||
| 430 | println!("✅ Invalid maintainer pubkey handled gracefully without panic"); | 498 | println!("✅ Invalid maintainer pubkey handled gracefully without panic"); |
| 431 | 499 | ||
| 432 | client.disconnect().await; | ||
| 433 | relay.stop().await; | 500 | relay.stop().await; |
| 434 | } | 501 | } |