upleb.uk

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

summaryrefslogtreecommitdiff
path: root/tests/proactive_sync_metrics.rs
diff options
context:
space:
mode:
authorDanConwayDev <DanConwayDev@protonmail.com>2025-12-11 08:47:08 +0000
committerDanConwayDev <DanConwayDev@protonmail.com>2025-12-11 08:47:08 +0000
commit61d4796d84960ec9f25392635afceea3a3bd0916 (patch)
tree98bd7c10d34decc2f7c96f50ddead8e8dc63f473 /tests/proactive_sync_metrics.rs
parentffcf8a7bc679f0aff9135063d343be3161b3b439 (diff)
refactor: move metrics tests to tests/sync/ structure (Phase 7)
Diffstat (limited to 'tests/proactive_sync_metrics.rs')
-rw-r--r--tests/proactive_sync_metrics.rs364
1 files changed, 0 insertions, 364 deletions
diff --git a/tests/proactive_sync_metrics.rs b/tests/proactive_sync_metrics.rs
deleted file mode 100644
index 32abe74..0000000
--- a/tests/proactive_sync_metrics.rs
+++ /dev/null
@@ -1,364 +0,0 @@
1//! GRASP-02 Phase 6: Proactive Sync Metrics Integration Tests
2//!
3//! Tests the Prometheus metrics integration for proactive sync:
4//! - All sync metrics exposed at `/metrics` endpoint
5//! - Connection metrics update correctly
6//! - Health state metrics reflect actual state
7//! - Gap events tracked correctly
8//! - Load test with 3+ relays
9//!
10//! # Running Tests
11//!
12//! ```bash
13//! cargo test --test proactive_sync_metrics
14//! cargo test --test proactive_sync_metrics -- --nocapture
15//! ```
16
17mod common;
18
19use std::time::Duration;
20
21use common::TestRelay;
22use nostr_sdk::prelude::*;
23
24/// Kind 30617 - Repository State (NIP-34)
25const KIND_REPOSITORY_STATE: u16 = 30617;
26
27/// Create a valid repository announcement event for testing
28fn create_valid_repo_announcement(keys: &Keys, domain: &str, identifier: &str) -> Event {
29 let tags = vec![
30 Tag::identifier(identifier),
31 Tag::custom(
32 TagKind::custom("clone"),
33 vec![format!("http://{}/{}", domain, identifier)],
34 ),
35 Tag::custom(TagKind::custom("relays"), vec![format!("ws://{}", domain)]),
36 ];
37
38 EventBuilder::new(Kind::Custom(KIND_REPOSITORY_STATE), "Repository state")
39 .tags(tags)
40 .sign_with_keys(keys)
41 .expect("Failed to sign event")
42}
43
44/// Helper to fetch metrics from a relay's HTTP endpoint
45async fn fetch_metrics(relay: &TestRelay) -> Result<String, reqwest::Error> {
46 // Extract host:port from ws:// URL
47 let ws_url = relay.url();
48 let http_url = ws_url.replace("ws://", "http://").replace("/", "") + "/metrics";
49
50 reqwest::get(&http_url).await?.text().await
51}
52
53/// Test that sync metrics are exposed at /metrics endpoint
54#[tokio::test]
55async fn test_sync_metrics_exposed() {
56 let relay = TestRelay::start().await;
57
58 // Give time for relay to start
59 tokio::time::sleep(Duration::from_millis(500)).await;
60
61 // Fetch metrics
62 let metrics_result = fetch_metrics(&relay).await;
63
64 relay.stop().await;
65
66 // Check that we got metrics (even if sync isn't configured)
67 let metrics = metrics_result.expect("Failed to fetch metrics");
68
69 // Verify basic metrics structure exists
70 assert!(
71 metrics.contains("ngit_") || metrics.contains("# HELP"),
72 "Metrics endpoint should return Prometheus metrics"
73 );
74}
75
76/// Test that sync metrics include expected metric names
77#[tokio::test]
78async fn test_sync_metric_names_present() {
79 // Start a relay with sync configured
80 let source_relay = TestRelay::start().await;
81 let sync_relay = TestRelay::start_with_sync(Some(source_relay.url().into())).await;
82
83 // Give time for sync connection to attempt
84 tokio::time::sleep(Duration::from_secs(2)).await;
85
86 // Fetch metrics from the syncing relay
87 let metrics = fetch_metrics(&sync_relay)
88 .await
89 .expect("Failed to fetch metrics");
90
91 sync_relay.stop().await;
92 source_relay.stop().await;
93
94 // Check for expected sync metric names (they may have zero values)
95 // At minimum, the ngit_ prefix metrics should be present
96 assert!(
97 metrics.contains("ngit_"),
98 "Metrics should include ngit_ prefixed metrics"
99 );
100}
101
102/// Test connection metrics update correctly on successful connection
103#[tokio::test]
104async fn test_connection_metrics_on_success() {
105 // Start source relay
106 let source_relay = TestRelay::start().await;
107 tokio::time::sleep(Duration::from_millis(200)).await;
108
109 // Start syncing relay
110 let sync_relay = TestRelay::start_with_sync(Some(source_relay.url().into())).await;
111
112 // Wait for connection to establish
113 tokio::time::sleep(Duration::from_secs(2)).await;
114
115 // Fetch metrics - we can verify the relay started and metrics endpoint works
116 let metrics = fetch_metrics(&sync_relay)
117 .await
118 .expect("Failed to fetch metrics");
119
120 sync_relay.stop().await;
121 source_relay.stop().await;
122
123 // Verify metrics endpoint returned data
124 assert!(!metrics.is_empty(), "Metrics endpoint should return data");
125}
126
127/// Test that events syncing updates metrics
128#[tokio::test]
129async fn test_event_sync_metrics() {
130 // Start source relay
131 let source_relay = TestRelay::start().await;
132 tokio::time::sleep(Duration::from_millis(200)).await;
133
134 // Start syncing relay
135 let sync_relay = TestRelay::start_with_sync(Some(source_relay.url().into())).await;
136
137 // Wait for connection
138 tokio::time::sleep(Duration::from_secs(1)).await;
139
140 // Create and submit an event to source relay
141 let keys = Keys::generate();
142 let event = create_valid_repo_announcement(&keys, &source_relay.domain(), "metrics-test-repo");
143
144 let client = Client::default();
145 client
146 .add_relay(source_relay.url())
147 .await
148 .expect("Failed to add relay");
149 client.connect().await;
150
151 let _ = client.send_event(&event).await;
152
153 // Wait for sync to occur
154 tokio::time::sleep(Duration::from_secs(2)).await;
155
156 // Fetch metrics from sync relay
157 let metrics = fetch_metrics(&sync_relay)
158 .await
159 .expect("Failed to fetch metrics");
160
161 client.disconnect().await;
162 sync_relay.stop().await;
163 source_relay.stop().await;
164
165 // Verify metrics endpoint returned data after sync activity
166 assert!(
167 !metrics.is_empty(),
168 "Metrics should be present after sync activity"
169 );
170}
171
172/// Test health state tracking in metrics
173#[tokio::test]
174async fn test_health_state_metrics() {
175 // Start a syncing relay pointing to a non-existent source
176 // This will result in connection failures and health state changes
177 let sync_relay = TestRelay::start_with_sync(Some("ws://127.0.0.1:19999".into())).await;
178
179 // Wait for some connection attempts
180 tokio::time::sleep(Duration::from_secs(3)).await;
181
182 // Fetch metrics
183 let metrics = fetch_metrics(&sync_relay)
184 .await
185 .expect("Failed to fetch metrics");
186
187 sync_relay.stop().await;
188
189 // The relay should still be operational even with failed sync
190 assert!(
191 !metrics.is_empty(),
192 "Metrics should be present even with sync failures"
193 );
194}
195
196/// Test gap event tracking (events received during catchup)
197#[tokio::test]
198async fn test_gap_event_tracking() {
199 // Start source relay and add some events first
200 let source_relay = TestRelay::start().await;
201 tokio::time::sleep(Duration::from_millis(200)).await;
202
203 let keys = Keys::generate();
204
205 // Submit event before sync relay starts
206 let event = create_valid_repo_announcement(&keys, &source_relay.domain(), "pre-existing-repo");
207
208 let client = Client::default();
209 client
210 .add_relay(source_relay.url())
211 .await
212 .expect("Failed to add relay");
213 client.connect().await;
214 let _ = client.send_event(&event).await;
215
216 // Now start syncing relay - it should catch up on existing events
217 let sync_relay = TestRelay::start_with_sync(Some(source_relay.url().into())).await;
218
219 // Wait for catchup
220 tokio::time::sleep(Duration::from_secs(3)).await;
221
222 // Fetch metrics
223 let metrics = fetch_metrics(&sync_relay)
224 .await
225 .expect("Failed to fetch metrics");
226
227 client.disconnect().await;
228 sync_relay.stop().await;
229 source_relay.stop().await;
230
231 // Verify metrics exist after gap sync scenario
232 assert!(
233 !metrics.is_empty(),
234 "Metrics should track gap sync activity"
235 );
236}
237
238/// Load test with 3+ relays configured for sync
239#[tokio::test]
240async fn test_multi_relay_load() {
241 // Start 3 source relays
242 let source_relay_1 = TestRelay::start().await;
243 let source_relay_2 = TestRelay::start().await;
244 let source_relay_3 = TestRelay::start().await;
245
246 tokio::time::sleep(Duration::from_millis(500)).await;
247
248 // Start a syncing relay pointing to first source
249 // Note: The current implementation only supports single sync relay URL
250 // but the test demonstrates the system handles multiple relay scenarios
251 let sync_relay = TestRelay::start_with_sync(Some(source_relay_1.url().into())).await;
252
253 // Wait for connections
254 tokio::time::sleep(Duration::from_secs(2)).await;
255
256 // Submit events to all source relays
257 let keys = Keys::generate();
258
259 let event1 = create_valid_repo_announcement(&keys, &source_relay_1.domain(), "repo-1");
260 let event2 = create_valid_repo_announcement(&keys, &source_relay_2.domain(), "repo-2");
261 let event3 = create_valid_repo_announcement(&keys, &source_relay_3.domain(), "repo-3");
262
263 // Submit events
264 let client1 = Client::default();
265 client1
266 .add_relay(source_relay_1.url())
267 .await
268 .expect("Failed to add relay");
269 client1.connect().await;
270 let _ = client1.send_event(&event1).await;
271
272 let client2 = Client::default();
273 client2
274 .add_relay(source_relay_2.url())
275 .await
276 .expect("Failed to add relay");
277 client2.connect().await;
278 let _ = client2.send_event(&event2).await;
279
280 let client3 = Client::default();
281 client3
282 .add_relay(source_relay_3.url())
283 .await
284 .expect("Failed to add relay");
285 client3.connect().await;
286 let _ = client3.send_event(&event3).await;
287
288 // Wait for sync
289 tokio::time::sleep(Duration::from_secs(3)).await;
290
291 // Fetch metrics from sync relay
292 let metrics = fetch_metrics(&sync_relay)
293 .await
294 .expect("Failed to fetch metrics");
295
296 // Cleanup
297 client1.disconnect().await;
298 client2.disconnect().await;
299 client3.disconnect().await;
300 sync_relay.stop().await;
301 source_relay_1.stop().await;
302 source_relay_2.stop().await;
303 source_relay_3.stop().await;
304
305 // Verify metrics system handled load
306 assert!(
307 !metrics.is_empty(),
308 "Metrics should be available under multi-relay load"
309 );
310}
311
312/// Test that Prometheus text format is valid
313#[tokio::test]
314async fn test_prometheus_format_valid() {
315 let relay = TestRelay::start().await;
316 tokio::time::sleep(Duration::from_millis(500)).await;
317
318 let metrics = fetch_metrics(&relay)
319 .await
320 .expect("Failed to fetch metrics");
321
322 relay.stop().await;
323
324 // Check for valid Prometheus format markers
325 // - Lines starting with # are comments (HELP, TYPE)
326 // - Metric lines have format: metric_name{labels} value
327 let lines: Vec<&str> = metrics.lines().collect();
328
329 // Should have some content
330 assert!(!lines.is_empty(), "Metrics should have content");
331
332 // Check for at least some standard Prometheus patterns
333 let has_help = lines.iter().any(|l| l.starts_with("# HELP"));
334 let has_type = lines.iter().any(|l| l.starts_with("# TYPE"));
335
336 // At minimum we expect help/type comments for any registered metrics
337 assert!(
338 has_help || has_type || lines.iter().any(|l| l.contains("ngit_")),
339 "Metrics should contain Prometheus format elements"
340 );
341}
342
343/// Test metrics endpoint availability during sync operations
344#[tokio::test]
345async fn test_metrics_availability_during_sync() {
346 let source_relay = TestRelay::start().await;
347 let sync_relay = TestRelay::start_with_sync(Some(source_relay.url().into())).await;
348
349 tokio::time::sleep(Duration::from_millis(500)).await;
350
351 // Make multiple metrics requests while sync is active
352 for i in 0..3 {
353 let metrics = fetch_metrics(&sync_relay).await;
354 assert!(
355 metrics.is_ok(),
356 "Metrics request {} should succeed during sync",
357 i + 1
358 );
359 tokio::time::sleep(Duration::from_millis(200)).await;
360 }
361
362 sync_relay.stop().await;
363 source_relay.stop().await;
364}