diff options
Diffstat (limited to 'tests/sync/discovery.rs')
| -rw-r--r-- | tests/sync/discovery.rs | 259 |
1 files changed, 32 insertions, 227 deletions
diff --git a/tests/sync/discovery.rs b/tests/sync/discovery.rs index 8ed80b5..d45a290 100644 --- a/tests/sync/discovery.rs +++ b/tests/sync/discovery.rs | |||
| @@ -3,10 +3,6 @@ | |||
| 3 | //! Tests for relay discovery from announcement events. | 3 | //! Tests for relay discovery from announcement events. |
| 4 | //! When a relay receives an announcement listing another relay, | 4 | //! When a relay receives an announcement listing another relay, |
| 5 | //! it should discover and connect to that relay to sync events. | 5 | //! it should discover and connect to that relay to sync events. |
| 6 | //! | ||
| 7 | //! # Tests | ||
| 8 | //! - Test 2: Direct Layer 3 discovery from Layer 2 | ||
| 9 | //! - Test 3: Recursive multi-hop Layer 3 discovery | ||
| 10 | 6 | ||
| 11 | use std::time::Duration; | 7 | use std::time::Duration; |
| 12 | 8 | ||
| @@ -62,29 +58,26 @@ async fn test_discovers_layer3_via_layer2() { | |||
| 62 | // 3. Create test keys | 58 | // 3. Create test keys |
| 63 | let keys = Keys::generate(); | 59 | let keys = Keys::generate(); |
| 64 | 60 | ||
| 65 | // 4. Create a repository announcement that lists BOTH relays | 61 | // 4. Set up repository announcement on relay_a with git data |
| 66 | let announcement = create_repo_announcement( | 62 | // (purgatory requires git data before announcements are accepted) |
| 67 | &keys, | 63 | let repo_id = "test-repo-discovery"; |
| 68 | &[&relay_a.domain(), &relay_b.domain()], | 64 | let domains = vec![relay_a.domain(), relay_b.domain()]; |
| 69 | "test-repo-discovery", | 65 | let domain_refs: Vec<&str> = domains.iter().map(|s| s.as_str()).collect(); |
| 70 | ); | ||
| 71 | let announcement_id = announcement.id; | ||
| 72 | 66 | ||
| 67 | let (announcement, _git_dir_a) = | ||
| 68 | setup_announcement_on_relay(&relay_a, &keys, &domain_refs, repo_id).await; | ||
| 69 | let announcement_id = announcement.id; | ||
| 73 | println!( | 70 | println!( |
| 74 | "Created announcement {} (kind {})", | 71 | "Announcement {} set up on relay_a with git data", |
| 75 | announcement_id, | 72 | announcement_id |
| 76 | announcement.kind.as_u16() | ||
| 77 | ); | 73 | ); |
| 78 | for tag in announcement.tags.iter() { | ||
| 79 | println!(" Tag: {:?}", tag.as_slice()); | ||
| 80 | } | ||
| 81 | 74 | ||
| 82 | // 5. Build the repo coordinate for the 'a' tag in the patch | 75 | // 5. Build the repo coordinate for the 'a' tag in the patch |
| 83 | let repo_coord = format!( | 76 | let repo_coord = format!( |
| 84 | "{}:{}:{}", | 77 | "{}:{}:{}", |
| 85 | Kind::GitRepoAnnouncement.as_u16(), | 78 | Kind::GitRepoAnnouncement.as_u16(), |
| 86 | keys.public_key().to_hex(), | 79 | keys.public_key().to_hex(), |
| 87 | "test-repo-discovery" | 80 | repo_id |
| 88 | ); | 81 | ); |
| 89 | 82 | ||
| 90 | // 6. Create a patch event (Layer 2) that references the announcement | 83 | // 6. Create a patch event (Layer 2) that references the announcement |
| @@ -97,22 +90,13 @@ async fn test_discovers_layer3_via_layer2() { | |||
| 97 | let patch_id = patch.id; | 90 | let patch_id = patch.id; |
| 98 | 91 | ||
| 99 | println!("Created patch {} (kind {})", patch_id, patch.kind.as_u16()); | 92 | println!("Created patch {} (kind {})", patch_id, patch.kind.as_u16()); |
| 100 | for tag in patch.tags.iter() { | ||
| 101 | println!(" Tag: {:?}", tag.as_slice()); | ||
| 102 | } | ||
| 103 | 93 | ||
| 104 | // 7. Send announcement and patch to relay_a ONLY | 94 | // 7. Send patch to relay_a |
| 105 | let client_a = TestClient::new(relay_a.url(), keys.clone()) | 95 | let client_a = TestClient::new(relay_a.url(), keys.clone()) |
| 106 | .await | 96 | .await |
| 107 | .expect("Failed to connect to relay_a"); | 97 | .expect("Failed to connect to relay_a"); |
| 108 | 98 | ||
| 109 | client_a | 99 | client_a |
| 110 | .send_event(&announcement) | ||
| 111 | .await | ||
| 112 | .expect("Failed to send announcement to relay_a"); | ||
| 113 | println!("Announcement sent to relay_a"); | ||
| 114 | |||
| 115 | client_a | ||
| 116 | .send_event(&patch) | 100 | .send_event(&patch) |
| 117 | .await | 101 | .await |
| 118 | .expect("Failed to send patch to relay_a"); | 102 | .expect("Failed to send patch to relay_a"); |
| @@ -120,18 +104,10 @@ async fn test_discovers_layer3_via_layer2() { | |||
| 120 | 104 | ||
| 121 | client_a.disconnect().await; | 105 | client_a.disconnect().await; |
| 122 | 106 | ||
| 123 | // 8. Send announcement to relay_b directly (triggers discovery of relay_a) | 107 | // 8. Set up announcement on relay_b (triggers discovery of relay_a) |
| 124 | let client_b = TestClient::new(relay_b.url(), keys.clone()) | 108 | let (_announcement_b, _git_dir_b) = |
| 125 | .await | 109 | setup_announcement_on_relay(&relay_b, &keys, &domain_refs, repo_id).await; |
| 126 | .expect("Failed to connect to relay_b"); | 110 | println!("Announcement set up on relay_b (should trigger discovery of relay_a)"); |
| 127 | |||
| 128 | client_b | ||
| 129 | .send_event(&announcement) | ||
| 130 | .await | ||
| 131 | .expect("Failed to send announcement to relay_b"); | ||
| 132 | println!("Announcement sent to relay_b (should trigger discovery of relay_a)"); | ||
| 133 | |||
| 134 | client_b.disconnect().await; | ||
| 135 | 111 | ||
| 136 | // 9. Wait for relay_b to discover relay_a and sync the patch | 112 | // 9. Wait for relay_b to discover relay_a and sync the patch |
| 137 | println!("Waiting 3s for relay_b to discover relay_a and sync patch..."); | 113 | println!("Waiting 3s for relay_b to discover relay_a and sync patch..."); |
| @@ -197,19 +173,20 @@ async fn test_relay_discovery_via_announcements_with_historic_sync() { | |||
| 197 | // 3. Create test keys | 173 | // 3. Create test keys |
| 198 | let keys = Keys::generate(); | 174 | let keys = Keys::generate(); |
| 199 | 175 | ||
| 200 | // 4. Create the event chain on relay_a: | 176 | // 4. Set up repository on relay_a with git data and a Layer 2 issue |
| 201 | 177 | ||
| 202 | // Layer 1: Repository announcement | 178 | // Layer 1: Set up announcement with git data |
| 203 | let announcement = create_repo_announcement( | 179 | let domains = vec![relay_a.domain(), relay_b.domain()]; |
| 204 | &keys, | 180 | let domain_refs: Vec<&str> = domains.iter().map(|s| s.as_str()).collect(); |
| 205 | &[&relay_a.domain(), &relay_b.domain()], | 181 | let repo_id = "test-repo-chain"; |
| 206 | "test-repo-chain", | 182 | |
| 207 | ); | 183 | let (announcement, _git_dir_a) = |
| 184 | setup_announcement_on_relay(&relay_a, &keys, &domain_refs, repo_id).await; | ||
| 208 | let announcement_id = announcement.id; | 185 | let announcement_id = announcement.id; |
| 209 | println!("Created announcement {} (Layer 1)", announcement_id); | 186 | println!("Announcement {} set up on relay_a with git data (Layer 1)", announcement_id); |
| 210 | 187 | ||
| 211 | // Build repo coordinate for Layer 2 reference | 188 | // Build repo coordinate for Layer 2 reference |
| 212 | let repo_coord = repo_coord(&keys, "test-repo-chain"); | 189 | let repo_coord = repo_coord(&keys, repo_id); |
| 213 | 190 | ||
| 214 | // Layer 2: Issue referencing the repo | 191 | // Layer 2: Issue referencing the repo |
| 215 | let issue = build_layer2_issue_event(&keys, &repo_coord, "Test issue for chain discovery") | 192 | let issue = build_layer2_issue_event(&keys, &repo_coord, "Test issue for chain discovery") |
| @@ -217,35 +194,23 @@ async fn test_relay_discovery_via_announcements_with_historic_sync() { | |||
| 217 | let issue_id = issue.id; | 194 | let issue_id = issue.id; |
| 218 | println!("Created issue {} (Layer 2)", issue_id); | 195 | println!("Created issue {} (Layer 2)", issue_id); |
| 219 | 196 | ||
| 220 | // 5. Send all events to relay_a | 197 | // 5. Send issue to relay_a |
| 221 | let client_a = TestClient::new(relay_a.url(), keys.clone()) | 198 | let client_a = TestClient::new(relay_a.url(), keys.clone()) |
| 222 | .await | 199 | .await |
| 223 | .expect("Failed to connect to relay_a"); | 200 | .expect("Failed to connect to relay_a"); |
| 224 | 201 | ||
| 225 | client_a | 202 | client_a |
| 226 | .send_event(&announcement) | ||
| 227 | .await | ||
| 228 | .expect("Failed to send announcement"); | ||
| 229 | client_a | ||
| 230 | .send_event(&issue) | 203 | .send_event(&issue) |
| 231 | .await | 204 | .await |
| 232 | .expect("Failed to send issue"); | 205 | .expect("Failed to send issue"); |
| 233 | 206 | ||
| 234 | println!("Events sent to relay_a"); | 207 | println!("Issue sent to relay_a"); |
| 235 | client_a.disconnect().await; | 208 | client_a.disconnect().await; |
| 236 | 209 | ||
| 237 | // 6. Send only the announcement to relay_b (triggers discovery) | 210 | // 6. Set up announcement on relay_b (triggers discovery of relay_a) |
| 238 | let client_b = TestClient::new(relay_b.url(), keys.clone()) | 211 | let (_announcement_b, _git_dir_b) = |
| 239 | .await | 212 | setup_announcement_on_relay(&relay_b, &keys, &domain_refs, repo_id).await; |
| 240 | .expect("Failed to connect to relay_b"); | 213 | println!("Announcement set up on relay_b (should trigger discovery of relay_a)"); |
| 241 | |||
| 242 | client_b | ||
| 243 | .send_event(&announcement) | ||
| 244 | .await | ||
| 245 | .expect("Failed to send announcement to relay_b"); | ||
| 246 | println!("Announcement sent to relay_b (should trigger discovery)"); | ||
| 247 | |||
| 248 | client_b.disconnect().await; | ||
| 249 | 214 | ||
| 250 | // 7. Wait for sync | 215 | // 7. Wait for sync |
| 251 | println!("Waiting 3s for Layer 2 sync..."); | 216 | println!("Waiting 3s for Layer 2 sync..."); |
| @@ -271,163 +236,3 @@ async fn test_relay_discovery_via_announcements_with_historic_sync() { | |||
| 271 | ); | 236 | ); |
| 272 | } | 237 | } |
| 273 | 238 | ||
| 274 | /// Test 3: 3-relay recursive discovery - relay discovers third relay through bootstrap | ||
| 275 | /// | ||
| 276 | /// Scenario: | ||
| 277 | /// ```text | ||
| 278 | /// relay_a (SUT) relay_b (bootstrap) relay_c (discovered) | ||
| 279 | /// │ │ │ | ||
| 280 | /// │ │ has announcement_x │ has announcement_y | ||
| 281 | /// │ │ listing A+B+C │ listing A+C | ||
| 282 | /// │ │ │ | ||
| 283 | /// ├────connect──────────► │ | ||
| 284 | /// │◄───sync announcement_x─────────────────────── | ||
| 285 | /// │ │ | ||
| 286 | /// │ discovers relay_c from announcement_x │ | ||
| 287 | /// │ │ | ||
| 288 | /// ├─────────────connect─────────────────────────► | ||
| 289 | /// │◄────────────sync announcement_y─────────────┘ | ||
| 290 | /// ``` | ||
| 291 | /// | ||
| 292 | /// This tests that relay_a: | ||
| 293 | /// 1. Connects to relay_b (configured as bootstrap) | ||
| 294 | /// 2. Receives announcement_x which lists relay_c | ||
| 295 | /// 3. Discovers and connects to relay_c | ||
| 296 | /// 4. Syncs announcement_y from relay_c | ||
| 297 | /// | ||
| 298 | #[tokio::test] | ||
| 299 | async fn test_recursive_relay_discovery_via_announcements_with_historic_sync() { | ||
| 300 | // 1. Start all three relays | ||
| 301 | |||
| 302 | // relay_b - will be the bootstrap relay, has announcement_x | ||
| 303 | let relay_b = TestRelay::start().await; | ||
| 304 | println!( | ||
| 305 | "relay_b (bootstrap) started at {} (domain: {})", | ||
| 306 | relay_b.url(), | ||
| 307 | relay_b.domain() | ||
| 308 | ); | ||
| 309 | |||
| 310 | // relay_c - will be discovered via announcement_x, has announcement_y | ||
| 311 | let relay_c = TestRelay::start().await; | ||
| 312 | println!( | ||
| 313 | "relay_c (to be discovered) started at {} (domain: {})", | ||
| 314 | relay_c.url(), | ||
| 315 | relay_c.domain() | ||
| 316 | ); | ||
| 317 | |||
| 318 | // relay_a - SUT, starts with relay_b as bootstrap | ||
| 319 | let relay_a = TestRelay::start_with_sync(Some(relay_b.url().to_string())).await; | ||
| 320 | println!( | ||
| 321 | "relay_a (SUT) started at {} (domain: {})", | ||
| 322 | relay_a.url(), | ||
| 323 | relay_a.domain() | ||
| 324 | ); | ||
| 325 | |||
| 326 | // 2. Create test keys (one for each announcement) | ||
| 327 | let keys_x = Keys::generate(); | ||
| 328 | let keys_y = Keys::generate(); | ||
| 329 | |||
| 330 | // 3. Create announcement_x on relay_b (lists all three relays: A+B+C) | ||
| 331 | let announcement_x = create_repo_announcement( | ||
| 332 | &keys_x, | ||
| 333 | &[&relay_a.domain(), &relay_b.domain(), &relay_c.domain()], | ||
| 334 | "repo-x-all-relays", | ||
| 335 | ); | ||
| 336 | let announcement_x_id = announcement_x.id; | ||
| 337 | println!("Created announcement_x {} listing A+B+C", announcement_x_id); | ||
| 338 | for tag in announcement_x.tags.iter() { | ||
| 339 | println!(" Tag: {:?}", tag.as_slice()); | ||
| 340 | } | ||
| 341 | |||
| 342 | // 4. Create announcement_y on relay_c (lists only A+C, NOT B) | ||
| 343 | let announcement_y = create_repo_announcement( | ||
| 344 | &keys_y, | ||
| 345 | &[&relay_a.domain(), &relay_c.domain()], | ||
| 346 | "repo-y-ac-only", | ||
| 347 | ); | ||
| 348 | let announcement_y_id = announcement_y.id; | ||
| 349 | println!( | ||
| 350 | "Created announcement_y {} listing A+C only", | ||
| 351 | announcement_y_id | ||
| 352 | ); | ||
| 353 | for tag in announcement_y.tags.iter() { | ||
| 354 | println!(" Tag: {:?}", tag.as_slice()); | ||
| 355 | } | ||
| 356 | |||
| 357 | // 5. Send announcement_x to relay_b only | ||
| 358 | let client_b = TestClient::new(relay_b.url(), keys_x.clone()) | ||
| 359 | .await | ||
| 360 | .expect("Failed to connect to relay_b"); | ||
| 361 | |||
| 362 | client_b | ||
| 363 | .send_event(&announcement_x) | ||
| 364 | .await | ||
| 365 | .expect("Failed to send announcement_x to relay_b"); | ||
| 366 | println!("announcement_x sent to relay_b"); | ||
| 367 | |||
| 368 | client_b.disconnect().await; | ||
| 369 | |||
| 370 | // 6. Send announcement_y to relay_c only | ||
| 371 | let client_c = TestClient::new(relay_c.url(), keys_y.clone()) | ||
| 372 | .await | ||
| 373 | .expect("Failed to connect to relay_c"); | ||
| 374 | |||
| 375 | client_c | ||
| 376 | .send_event(&announcement_y) | ||
| 377 | .await | ||
| 378 | .expect("Failed to send announcement_y to relay_c"); | ||
| 379 | println!("announcement_y sent to relay_c"); | ||
| 380 | |||
| 381 | client_c.disconnect().await; | ||
| 382 | |||
| 383 | // 7. Wait for relay_a to: | ||
| 384 | // - Sync from bootstrap relay_b (gets announcement_x) | ||
| 385 | // - Discover relay_c from announcement_x's relays tag | ||
| 386 | // - Connect to relay_c and sync announcement_y | ||
| 387 | println!("Waiting 5s for recursive relay discovery..."); | ||
| 388 | tokio::time::sleep(Duration::from_secs(5)).await; | ||
| 389 | |||
| 390 | // 8. Verify announcement_x was synced to relay_a (from bootstrap relay_b) | ||
| 391 | let filter_x = Filter::new() | ||
| 392 | .kind(Kind::GitRepoAnnouncement) | ||
| 393 | .author(keys_x.public_key()); | ||
| 394 | |||
| 395 | let announcement_x_synced = | ||
| 396 | wait_for_event_on_relay(relay_a.url(), filter_x, Duration::from_secs(5)).await; | ||
| 397 | |||
| 398 | println!( | ||
| 399 | "announcement_x {} synced to relay_a: {}", | ||
| 400 | announcement_x_id, announcement_x_synced | ||
| 401 | ); | ||
| 402 | |||
| 403 | // 9. Verify announcement_y was synced to relay_a (from discovered relay_c) | ||
| 404 | let filter_y = Filter::new() | ||
| 405 | .kind(Kind::GitRepoAnnouncement) | ||
| 406 | .author(keys_y.public_key()); | ||
| 407 | |||
| 408 | let announcement_y_synced = | ||
| 409 | wait_for_event_on_relay(relay_a.url(), filter_y, Duration::from_secs(5)).await; | ||
| 410 | |||
| 411 | println!( | ||
| 412 | "announcement_y {} synced to relay_a: {}", | ||
| 413 | announcement_y_id, announcement_y_synced | ||
| 414 | ); | ||
| 415 | |||
| 416 | // 10. Cleanup | ||
| 417 | relay_a.stop().await; | ||
| 418 | relay_b.stop().await; | ||
| 419 | relay_c.stop().await; | ||
| 420 | |||
| 421 | // 11. Assertions | ||
| 422 | assert!( | ||
| 423 | announcement_x_synced, | ||
| 424 | "announcement_x {} should have synced from bootstrap relay_b to relay_a", | ||
| 425 | announcement_x_id | ||
| 426 | ); | ||
| 427 | |||
| 428 | assert!( | ||
| 429 | announcement_y_synced, | ||
| 430 | "announcement_y {} should have synced from discovered relay_c to relay_a (recursive discovery)", | ||
| 431 | announcement_y_id | ||
| 432 | ); | ||
| 433 | } | ||