diff options
| author | DanConwayDev <DanConwayDev@protonmail.com> | 2025-12-18 16:57:10 +0000 |
|---|---|---|
| committer | DanConwayDev <DanConwayDev@protonmail.com> | 2025-12-18 16:57:10 +0000 |
| commit | 33530da5864245cc44e96c7a168ad806fdab6d98 (patch) | |
| tree | 62ac26b00f49610f18aaa69b296ec247656042d2 /tests/common | |
| parent | 203aae5e3fca0f6a2b4788c0941412367c162d42 (diff) | |
test: add unified run_sync_test() helper infrastructure
Add SyncTestResult struct and run_sync_test() helper function to
sync_helpers.rs for unified test setup. The helper automatically
determines sync mode (historic vs live) based on which event slice
has content.
Features:
- SyncTestResult: holds test fixtures (relays, keys, repo_coord)
- run_sync_test(): unified setup for both historic and live sync tests
- Panic guards for invalid usage (both slices or neither)
- Unit tests for panic conditions
Test results: 40 tests total, 38 passing (same as baseline)
- 2 pre-existing metric test failures (unchanged from baseline)
- All new panic condition tests passing
- No regressions introduced
Diffstat (limited to 'tests/common')
| -rw-r--r-- | tests/common/sync_helpers.rs | 165 |
1 files changed, 165 insertions, 0 deletions
diff --git a/tests/common/sync_helpers.rs b/tests/common/sync_helpers.rs index e07ad1f..67dec3c 100644 --- a/tests/common/sync_helpers.rs +++ b/tests/common/sync_helpers.rs | |||
| @@ -1060,4 +1060,169 @@ mod tests { | |||
| 1060 | let metrics = ParsedMetrics::parse(text); | 1060 | let metrics = ParsedMetrics::parse(text); |
| 1061 | assert_eq!(metrics.relay_connected("ws://127.0.0.1:12345"), Some(true)); | 1061 | assert_eq!(metrics.relay_connected("ws://127.0.0.1:12345"), Some(true)); |
| 1062 | } | 1062 | } |
| 1063 | |||
| 1064 | // ============================================================================ | ||
| 1065 | // Unified Sync Test Helper | ||
| 1066 | // ============================================================================ | ||
| 1067 | |||
| 1068 | /// Result from running a sync test setup | ||
| 1069 | /// | ||
| 1070 | /// Holds all fixtures needed for making assertions in sync tests. | ||
| 1071 | /// Returned by [`run_sync_test`] after setting up the test environment. | ||
| 1072 | pub struct SyncTestResult { | ||
| 1073 | pub source_relay: TestRelay, | ||
| 1074 | pub syncing_relay: TestRelay, | ||
| 1075 | pub maintainer_keys: Keys, | ||
| 1076 | pub repo_coord: String, | ||
| 1077 | } | ||
| 1078 | |||
| 1079 | /// Helper to send an event to a relay | ||
| 1080 | /// | ||
| 1081 | /// Creates a temporary client, sends the event, and disconnects. | ||
| 1082 | async fn send_to_relay(relay: &TestRelay, event: &Event) -> Result<(), String> { | ||
| 1083 | let temp_keys = Keys::generate(); | ||
| 1084 | let client = TestClient::new(relay.url(), temp_keys).await?; | ||
| 1085 | client.send_event(event).await?; | ||
| 1086 | client.disconnect().await; | ||
| 1087 | Ok(()) | ||
| 1088 | } | ||
| 1089 | |||
| 1090 | /// Unified sync test helper that automatically determines sync mode. | ||
| 1091 | /// | ||
| 1092 | /// This function sets up a complete sync test environment by determining whether | ||
| 1093 | /// to test historic sync (events sent before syncing relay connects) or live sync | ||
| 1094 | /// (events sent after syncing relay connects) based on which event slice has content. | ||
| 1095 | /// | ||
| 1096 | /// # Sync Mode Detection | ||
| 1097 | /// | ||
| 1098 | /// - **Historic sync**: If `historic_events` has content and `live_events` is empty | ||
| 1099 | /// - **Live sync**: If `live_events` has content and `historic_events` is empty | ||
| 1100 | /// - **Panics**: If both slices have content or both are empty (invalid usage) | ||
| 1101 | /// | ||
| 1102 | /// # Arguments | ||
| 1103 | /// | ||
| 1104 | /// * `historic_events` - Events to send BEFORE syncing relay connects (for historic sync tests) | ||
| 1105 | /// * `live_events` - Events to send AFTER syncing relay connects (for live sync tests) | ||
| 1106 | /// | ||
| 1107 | /// # Returns | ||
| 1108 | /// | ||
| 1109 | /// [`SyncTestResult`] containing test fixtures for assertions | ||
| 1110 | /// | ||
| 1111 | /// # Example | ||
| 1112 | /// | ||
| 1113 | /// ```ignore | ||
| 1114 | /// // Historic sync test | ||
| 1115 | /// let issue = build_layer2_issue_event(&keys, &repo_coord, "Historic Issue")?; | ||
| 1116 | /// let result = run_sync_test(&[issue], &[]).await; | ||
| 1117 | /// // Assert issue synced to result.syncing_relay | ||
| 1118 | /// | ||
| 1119 | /// // Live sync test | ||
| 1120 | /// let comment = build_layer3_comment_event(&keys, &issue.id, "Live Comment", Kind::Custom(1111))?; | ||
| 1121 | /// let result = run_sync_test(&[], &[comment]).await; | ||
| 1122 | /// // Assert comment synced to result.syncing_relay | ||
| 1123 | /// ``` | ||
| 1124 | pub async fn run_sync_test( | ||
| 1125 | historic_events: &[Event], | ||
| 1126 | live_events: &[Event], | ||
| 1127 | ) -> SyncTestResult { | ||
| 1128 | // Validate usage - exactly one slice must have content | ||
| 1129 | let historic_mode = !historic_events.is_empty(); | ||
| 1130 | let live_mode = !live_events.is_empty(); | ||
| 1131 | |||
| 1132 | if historic_mode && live_mode { | ||
| 1133 | panic!("Invalid usage: both historic_events and live_events provided. Use one or the other."); | ||
| 1134 | } | ||
| 1135 | if !historic_mode && !live_mode { | ||
| 1136 | panic!("Invalid usage: both historic_events and live_events are empty. Provide at least one."); | ||
| 1137 | } | ||
| 1138 | |||
| 1139 | // 1. Pre-allocate syncing relay port for announcement tags | ||
| 1140 | let syncing_port = TestRelay::find_free_port(); | ||
| 1141 | let syncing_domain = format!("127.0.0.1:{}", syncing_port); | ||
| 1142 | |||
| 1143 | // 2. Start source relay | ||
| 1144 | let source = TestRelay::start().await; | ||
| 1145 | |||
| 1146 | // 3. Create keys and announcement listing both relays | ||
| 1147 | let keys = Keys::generate(); | ||
| 1148 | let announcement = create_repo_announcement( | ||
| 1149 | &keys, | ||
| 1150 | &[&source.domain(), &syncing_domain], | ||
| 1151 | "test-repo", | ||
| 1152 | ); | ||
| 1153 | |||
| 1154 | // 4. Send announcement + historic events to source BEFORE syncing relay starts | ||
| 1155 | send_to_relay(&source, &announcement) | ||
| 1156 | .await | ||
| 1157 | .expect("Failed to send announcement"); | ||
| 1158 | for event in historic_events { | ||
| 1159 | send_to_relay(&source, event) | ||
| 1160 | .await | ||
| 1161 | .expect("Failed to send historic event"); | ||
| 1162 | } | ||
| 1163 | |||
| 1164 | // 5. Start syncing relay (connects to source) | ||
| 1165 | let syncing = TestRelay::start_on_port_with_options( | ||
| 1166 | syncing_port, | ||
| 1167 | Some(source.url().into()), | ||
| 1168 | false, | ||
| 1169 | ) | ||
| 1170 | .await; | ||
| 1171 | |||
| 1172 | // 6. Wait for sync connection to establish | ||
| 1173 | let _ = wait_for_sync_connection(syncing.url(), 1, Duration::from_secs(5)).await; | ||
| 1174 | |||
| 1175 | // 7. Send live events AFTER connection established | ||
| 1176 | for event in live_events { | ||
| 1177 | send_to_relay(&source, event) | ||
| 1178 | .await | ||
| 1179 | .expect("Failed to send live event"); | ||
| 1180 | } | ||
| 1181 | |||
| 1182 | // 8. Allow sync to complete | ||
| 1183 | tokio::time::sleep(Duration::from_millis(100)).await; | ||
| 1184 | |||
| 1185 | // 9. Compute repo coordinate before moving keys | ||
| 1186 | let coordinate = repo_coord(&keys, "test-repo"); | ||
| 1187 | |||
| 1188 | SyncTestResult { | ||
| 1189 | source_relay: source, | ||
| 1190 | syncing_relay: syncing, | ||
| 1191 | maintainer_keys: keys, | ||
| 1192 | repo_coord: coordinate, | ||
| 1193 | } | ||
| 1194 | } | ||
| 1195 | |||
| 1196 | // ============================================================================ | ||
| 1197 | // Tests for Unified Sync Test Helper | ||
| 1198 | // ============================================================================ | ||
| 1199 | |||
| 1200 | #[cfg(test)] | ||
| 1201 | mod sync_helper_tests { | ||
| 1202 | use super::*; | ||
| 1203 | |||
| 1204 | // Note: Full integration tests of run_sync_test are in the actual sync test modules. | ||
| 1205 | // These unit tests only verify the panic conditions for invalid usage. | ||
| 1206 | |||
| 1207 | #[tokio::test] | ||
| 1208 | #[should_panic(expected = "both historic_events and live_events provided")] | ||
| 1209 | async fn test_run_sync_test_panics_with_both_slices() { | ||
| 1210 | let keys = Keys::generate(); | ||
| 1211 | let coord = repo_coord(&keys, "test"); | ||
| 1212 | let historic = build_layer2_issue_event(&keys, &coord, "Historic") | ||
| 1213 | .expect("Should create event"); | ||
| 1214 | let live = build_layer3_reply_with_e_tag(&keys, &EventId::all_zeros(), "Live") | ||
| 1215 | .expect("Should create event"); | ||
| 1216 | |||
| 1217 | // Should panic - both slices provided | ||
| 1218 | let _result = run_sync_test(&[historic], &[live]).await; | ||
| 1219 | } | ||
| 1220 | |||
| 1221 | #[tokio::test] | ||
| 1222 | #[should_panic(expected = "both historic_events and live_events are empty")] | ||
| 1223 | async fn test_run_sync_test_panics_with_empty_slices() { | ||
| 1224 | // Should panic - both slices empty | ||
| 1225 | let _result = run_sync_test(&[], &[]).await; | ||
| 1226 | } | ||
| 1227 | } | ||
| 1063 | } | 1228 | } |