upleb.uk

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

summaryrefslogtreecommitdiff
path: root/docs
diff options
context:
space:
mode:
Diffstat (limited to 'docs')
-rw-r--r--docs/archive/2025-12-18-sync-test-refactor.md481
1 files changed, 481 insertions, 0 deletions
diff --git a/docs/archive/2025-12-18-sync-test-refactor.md b/docs/archive/2025-12-18-sync-test-refactor.md
new file mode 100644
index 0000000..cf22956
--- /dev/null
+++ b/docs/archive/2025-12-18-sync-test-refactor.md
@@ -0,0 +1,481 @@
1# Sync Test Refactor Options
2
3## Summary of Requirements
4
5From your feedback:
6
7- **Tag variations**: Test with ONE sync mode (live OR historic), but make it clear which
8- **Discovery**: Needs both live AND historic examples (mechanism differs)
9- **Duplication**: Compare approaches before deciding
10
11---
12
13## Chosen Approach: Unified Helper with Event Slices
14
15A single helper function that handles both sync modes based on which event slices have content:
16
17````rust
18/// Result from sync test scenario
19pub struct SyncTestResult {
20 pub source: TestRelay,
21 pub syncing: TestRelay,
22 pub keys: Keys,
23 pub repo_coord: String,
24}
25
26/// Run a sync test scenario with historic and/or live events.
27///
28/// # Arguments
29/// - `historic_events` - Events loaded on source BEFORE syncing relay connects
30/// - `live_events` - Events fed to source AFTER syncing relay connects
31///
32/// # Mode Detection
33/// - If only `historic_events` has content → Historic sync test
34/// - If only `live_events` has content → Live sync test
35/// - Both can have content for mixed scenarios
36///
37/// # Example - Historic Sync
38/// ```rust
39/// let (result, events) = run_sync_test(&[announcement, issue], &[]).await;
40/// // Source had events before syncing relay started
41/// // Verify events synced to result.syncing
42/// ```
43///
44/// # Example - Live Sync
45/// ```rust
46/// let (result, events) = run_sync_test(&[], &[issue, patch]).await;
47/// // Events were added after connection established
48/// // Verify events synced to result.syncing
49/// ```
50pub async fn run_sync_test(
51 historic_events: &[Event],
52 live_events: &[Event],
53) -> SyncTestResult {
54 // 1. Pre-allocate syncing relay port for announcement tags
55 let syncing_port = TestRelay::find_free_port();
56 let syncing_domain = format!("127.0.0.1:{}", syncing_port);
57
58 // 2. Start source relay
59 let source = TestRelay::start().await;
60
61 // 3. Create keys and announcement listing both relays
62 let keys = Keys::generate();
63 let announcement = create_repo_announcement(
64 &keys,
65 &[&source.domain(), &syncing_domain],
66 "test-repo",
67 );
68
69 // 4. Send announcement + historic events to source BEFORE syncing relay starts
70 send_to_relay(&source, &announcement).await;
71 for event in historic_events {
72 send_to_relay(&source, event).await;
73 }
74
75 // 5. Start syncing relay (connects to source)
76 let syncing = TestRelay::start_on_port_with_options(
77 syncing_port,
78 Some(source.url().into()),
79 false,
80 ).await;
81
82 // 6. Wait for sync connection to establish
83 wait_for_sync_connection(syncing.url(), 1, Duration::from_secs(5)).await.ok();
84
85 // 7. Send live events AFTER connection established
86 for event in live_events {
87 send_to_relay(&source, event).await;
88 }
89
90 // 8. Allow sync to complete
91 tokio::time::sleep(Duration::from_secs(2)).await;
92
93 SyncTestResult {
94 source,
95 syncing,
96 keys,
97 repo_coord: repo_coord(&keys, "test-repo"),
98 }
99}
100````
101
102### Test Usage Examples
103
104```rust
105// Historic sync - events existed before connection
106#[tokio::test]
107async fn test_historic_layer2_issue_syncs() {
108 let keys = Keys::generate();
109 let repo_coord = repo_coord(&keys, "test-repo");
110 let issue = build_layer2_issue_event(&keys, &repo_coord, "Historic Issue")?;
111
112 let result = run_sync_test(&[issue.clone()], &[]).await;
113
114 assert!(
115 wait_for_event_on_relay(result.syncing.url(), issue.id).await,
116 "Historic issue should sync"
117 );
118}
119
120// Live sync - events arrive after connection
121#[tokio::test]
122async fn test_live_layer2_issue_syncs() {
123 let keys = Keys::generate();
124 let repo_coord = repo_coord(&keys, "test-repo");
125 let issue = build_layer2_issue_event(&keys, &repo_coord, "Live Issue")?;
126
127 let result = run_sync_test(&[], &[issue.clone()]).await;
128
129 assert!(
130 wait_for_event_on_relay(result.syncing.url(), issue.id).await,
131 "Live issue should sync"
132 );
133}
134
135// Discovery test - historic
136#[tokio::test]
137async fn test_discovery_historic_syncs_layer2() {
138 let keys = Keys::generate();
139 let repo_coord = repo_coord(&keys, "test-repo");
140 let issue = build_layer2_issue_event(&keys, &repo_coord, "Discovered Issue")?;
141
142 // Source has the issue before discovery
143 let result = run_sync_test(&[issue.clone()], &[]).await;
144
145 assert!(wait_for_event_on_relay(result.syncing.url(), issue.id).await);
146}
147
148// Discovery test - live
149#[tokio::test]
150async fn test_discovery_live_syncs_layer2() {
151 // ... setup similar, events in second slice
152}
153```
154
155### Why This Approach
156
1571. **Single function, both modes** - No duplication of setup logic
1582. **Clear distinction** - Function signature makes it obvious which is historic vs live
1593. **No new dependencies** - Plain Rust
1604. **Readable tests** - Test body just creates events and calls helper
1615. **Flexible** - Can test mixed scenarios if needed
162
163---
164
165## Proposed Test File Structure
166
167```
168tests/sync/
169├── mod.rs # Module declarations + overview doc
170├── historic_sync.rs # NEW: Historic sync tests (events exist before connection)
171├── live_sync.rs # REFACTORED: Live sync tests (events arrive after connection)
172├── discovery.rs # REFACTORED: Relay discovery (both modes)
173├── tag_variations.rs # REFACTORED: Tag type coverage (live sync only)
174├── metrics.rs # UNCHANGED: Prometheus metrics tests
175└── catchup.rs # UNCHANGED: Documentation only
176```
177
178### `tests/sync/historic_sync.rs` (NEW - renamed from bootstrap.rs)
179
180```rust
181//! Historic Sync Tests
182//!
183//! Tests for syncing events that exist on source relay BEFORE the syncing relay connects.
184//! This is the bootstrap/startup sync path.
185
186/// Historic sync: Layer 1 announcements sync on startup
187/// run_sync_test with historic_events: [announcement]
188#[tokio::test]
189async fn test_historic_layer1_announcement_syncs() { ... }
190
191/// Historic sync: Layer 2 issues sync on startup
192/// run_sync_test with historic_events: [issue]
193#[tokio::test]
194async fn test_historic_layer2_issue_syncs() { ... }
195
196/// Historic sync: Layer 3 comments sync after Layer 2 syncs
197/// run_sync_test with historic_events: [issue, comment]
198#[tokio::test]
199async fn test_historic_layer3_comment_syncs() { ... }
200
201/// Historic sync: Events not listing relay domain are rejected
202/// run_sync_test with historic_events: [announcement_missing_domain]
203/// Verify NOT synced
204#[tokio::test]
205async fn test_historic_rejects_events_not_listing_relay() { ... }
206
207/// Historic sync works without NIP-77 negentropy (REQ+EOSE fallback)
208/// run_sync_test with historic_events, negentropy disabled
209#[tokio::test]
210async fn test_historic_sync_without_negentropy() { ... }
211```
212
213### `tests/sync/live_sync.rs` (REFACTORED)
214
215```rust
216//! Live Sync Tests
217//!
218//! Tests for syncing events that arrive on source relay AFTER the syncing relay connects.
219//! This is the real-time/subscription-based sync path.
220
221/// Live sync: Layer 2 issues sync in real-time
222/// run_sync_test with live_events: [issue]
223#[tokio::test]
224async fn test_live_layer2_issue_syncs() { ... }
225
226/// Live sync: Layer 3 comments sync after Layer 2 syncs
227/// run_sync_test with live_events: [issue, comment]
228#[tokio::test]
229async fn test_live_layer3_comment_syncs() { ... }
230
231/// Live sync: Events arrive in chronological order
232/// run_sync_test with live_events: [issue1, issue2, issue3]
233#[tokio::test]
234async fn test_live_sync_event_ordering() { ... }
235```
236
237### `tests/sync/discovery.rs` (REFACTORED)
238
239```rust
240//! Relay Discovery Tests
241//!
242//! Tests for discovering other relays from announcement events.
243//! Discovery can happen via historic sync or live sync paths.
244
245// === HISTORIC DISCOVERY ===
246// Relay discovers another relay from an announcement that existed before connection
247
248/// Historic discovery: Discovers relay from announcement, syncs Layer 2
249/// 1. relay_a has announcement + issue
250/// 2. relay_b starts with sync from relay_a
251/// 3. relay_b syncs announcement, discovers other relays listed, syncs issue
252#[tokio::test]
253async fn test_historic_discovery_syncs_layer2() { ... }
254
255/// Historic discovery: 3-relay recursive discovery chain
256/// 1. relay_b has announcement listing relay_c
257/// 2. relay_c has separate announcement
258/// 3. relay_a starts syncing from relay_b
259/// 4. relay_a gets announcement, discovers relay_c, syncs from relay_c
260#[tokio::test]
261async fn test_historic_recursive_discovery() { ... }
262
263// === LIVE DISCOVERY ===
264// Relay discovers another relay from an announcement that arrives after connection
265
266/// Live discovery: Discovers relay from new announcement, syncs Layer 2
267/// 1. Both relays running
268/// 2. Announcement submitted to relay_a
269/// 3. relay_b discovers relay_a from announcement, syncs Layer 2 events
270#[tokio::test]
271async fn test_live_discovery_syncs_layer2() { ... }
272
273/// Live discovery: Multi-hop discovery with layer chain
274/// Similar to recursive but with live submission of announcement
275#[tokio::test]
276async fn test_live_recursive_discovery() { ... }
277```
278
279### `tests/sync/tag_variations.rs` (REFACTORED - Live sync only)
280
281```rust
282//! Tag Variation Tests (Live Sync Mode)
283//!
284//! Tests that all valid tag types are correctly processed during sync.
285//! Uses LIVE sync mode - tag parsing is mode-independent, so testing one mode is sufficient.
286
287// === LAYER 2 TAG VARIATIONS ===
288
289/// Layer 2 with lowercase 'a' tag (standard NIP-01)
290#[tokio::test]
291async fn test_layer2_lowercase_a_tag() { ... }
292
293/// Layer 2 with uppercase 'A' tag (NIP-33 style)
294#[tokio::test]
295async fn test_layer2_uppercase_a_tag() { ... }
296
297/// Layer 2 with 'q' quote tag (NIP-18 style)
298#[tokio::test]
299async fn test_layer2_q_tag() { ... }
300
301// === LAYER 3 TAG VARIATIONS ===
302
303/// Layer 3 with lowercase 'e' tag (standard NIP-01)
304#[tokio::test]
305async fn test_layer3_lowercase_e_tag() { ... }
306
307/// Layer 3 with uppercase 'E' tag (NIP-22 comment)
308#[tokio::test]
309async fn test_layer3_uppercase_e_tag() { ... }
310
311/// Layer 3 with 'q' quote tag (NIP-18 style)
312#[tokio::test]
313async fn test_layer3_q_tag() { ... }
314```
315
316### `tests/sync/mod.rs` (UPDATED)
317
318```rust
319//! Sync Integration Tests
320//!
321//! Tests for ngit-grasp's proactive sync functionality, organized by sync mode:
322//!
323//! ## Sync Modes
324//!
325//! - **Historic Sync** (`historic_sync.rs`): Events exist BEFORE syncing relay connects
326//! - Also called bootstrap/startup sync
327//! - Tests the REQ+EOSE or negentropy-based initial sync
328//!
329//! - **Live Sync** (`live_sync.rs`): Events arrive AFTER syncing relay connects
330//! - Also called real-time/subscription-based sync
331//! - Tests the event forwarding via active subscriptions
332//!
333//! ## Other Test Categories
334//!
335//! - **Discovery** (`discovery.rs`): Relay discovers other relays from announcements
336//! - Has both historic and live variants
337//!
338//! - **Tag Variations** (`tag_variations.rs`): All valid tag types work correctly
339//! - Uses live sync (tag parsing is mode-independent)
340//!
341//! - **Metrics** (`metrics.rs`): Prometheus metrics for sync operations
342//!
343//! - **Catchup** (`catchup.rs`): Documentation only (not integration-testable)
344
345pub mod catchup;
346pub mod discovery;
347pub mod historic_sync; // Renamed from bootstrap
348pub mod live_sync;
349pub mod metrics;
350pub mod tag_variations;
351```
352
353---
354
355## Test Count Summary
356
357| File | Before | After | Notes |
358| --------------------------------- | ------ | ------ | ------------------------ |
359| `historic_sync.rs` (bootstrap.rs) | 4 | 5 | Renamed, minor additions |
360| `live_sync.rs` | 3 | 3 | Simplified using helper |
361| `discovery.rs` | 3 | 4 | Split into historic/live |
362| `tag_variations.rs` | 6 | 6 | Simplified using helper |
363| `metrics.rs` | 9 | 9 | Unchanged |
364| `catchup.rs` | 0 | 0 | Documentation only |
365| **Total** | **25** | **27** | +2 discovery tests |
366
367---
368
369## Implementation Plan
370
371### Context
372
373- Two metrics tests are currently failing: `test_live_sync_event_count` and `test_multi_source_aggregate_counts`
374- This may indicate implementation bugs in sync functionality
375- Plan must account for distinguishing test bugs from implementation bugs
376
377### Phase 1: Establish Baseline
378
379**Goal:** Understand current state before making changes
380
3811. Run `cargo test --test sync` and capture full output
3822. Identify all passing vs failing tests
3833. For each failing test, investigate whether:
384 - Test logic is incorrect (test bug)
385 - Implementation is broken (impl bug)
386 - Test was never working (aspirational test)
3874. Document findings in Known Issues section below
388
389### Phase 2: Add Test Infrastructure
390
391**Goal:** Add new helpers without breaking existing tests
392
3931. Add `SyncTestResult` struct to sync_helpers.rs:
394
395 ```rust
396 pub struct SyncTestResult {
397 pub source: TestRelay,
398 pub syncing: TestRelay,
399 pub keys: Keys,
400 pub repo_coord: String,
401 }
402 ```
403
4042. Add `run_sync_test(historic_events, live_events)` helper function
405
4063. Add unit tests for the helper itself:
407
408 - `test_run_sync_test_historic_mode` - verify events sent before connection
409 - `test_run_sync_test_live_mode` - verify events sent after connection
410
4114. Run `cargo test` to confirm no regressions
412
413### Phase 3: Refactor Historic Sync Tests
414
415**Goal:** Migrate bootstrap.rs → historic_sync.rs incrementally
416
4171. Rename file: `bootstrap.rs` → `historic_sync.rs`
4182. Update `mod.rs` to reference new module name
4193. Refactor tests one at a time:
420 - `test_bootstrap_syncs_existing_layer2_events` → `test_historic_layer2_issue_syncs`
421 - `test_relay_replays_events_after_restart` → keep or remove (tests restart, not sync mode)
422 - `test_announcement_not_listing_relay_is_not_synced` → `test_historic_rejects_unlisted_relay`
423 - `test_history_sync_without_negentropy` → `test_historic_sync_without_negentropy`
4244. Test after each refactor: `cargo test --test sync historic_sync`
425
426### Phase 4: Refactor Live Sync Tests
427
428**Goal:** Simplify live_sync.rs using run_sync_test helper
429
4301. Refactor tests one at a time:
431 - `test_live_sync_layer2_events` → use `run_sync_test(&[], &[issue])`
432 - `test_live_sync_layer3_events` → use `run_sync_test(&[], &[issue, comment])`
433 - `test_live_sync_event_ordering` → may need custom setup for ordering test
4342. Test after each refactor: `cargo test --test sync live_sync`
435
436### Phase 5: Refactor Discovery Tests
437
438**Goal:** Split discovery.rs into historic and live sections
439
4401. Add section comment: `// === HISTORIC DISCOVERY ===`
4412. Refactor existing tests to use run_sync_test
4423. Add new tests:
443 - `test_historic_discovery_syncs_layer2`
444 - `test_live_discovery_syncs_layer2`
4454. Test after each change: `cargo test --test sync discovery`
446
447### Phase 6: Refactor Tag Variations Tests
448
449**Goal:** Simplify tag_variations.rs using run_sync_test (live mode)
450
4511. Add header doc comment explaining live sync mode choice
4522. Refactor each test to use `run_sync_test(&[], &[event])`
4533. Test after all changes: `cargo test --test sync tag_variations`
454
455### Phase 7: Final Verification and Cleanup
456
4571. Update `mod.rs` documentation
4582. Run full test suite: `cargo test --test sync`
4593. Compare results to Phase 1 baseline:
460 - New failures = regressions from refactor (must fix)
461 - Same failures as baseline = pre-existing issues (document)
4624. Delete `work/sync-test-refactor-options.md`
463
464---
465
466## Known Issues
467
468_To be filled in during Phase 1_
469
470### Failing Tests Before Refactor
471
472| Test | Status | Root Cause | Action |
473| --------------------------------------------- | ---------- | ---------- | ------ |
474| `metrics::test_live_sync_event_count` | ❌ Failing | TBD | TBD |
475| `metrics::test_multi_source_aggregate_counts` | ❌ Failing | TBD | TBD |
476
477### Implementation Notes
478
479_Any discoveries about how sync actually works vs how tests expect it to work_
480
481---