From 61d4796d84960ec9f25392635afceea3a3bd0916 Mon Sep 17 00:00:00 2001 From: DanConwayDev Date: Thu, 11 Dec 2025 08:47:08 +0000 Subject: refactor: move metrics tests to tests/sync/ structure (Phase 7) --- tests/proactive_sync_metrics.rs | 364 ---------------------------------------- 1 file changed, 364 deletions(-) delete mode 100644 tests/proactive_sync_metrics.rs (limited to 'tests/proactive_sync_metrics.rs') 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 @@ -//! GRASP-02 Phase 6: Proactive Sync Metrics Integration Tests -//! -//! Tests the Prometheus metrics integration for proactive sync: -//! - All sync metrics exposed at `/metrics` endpoint -//! - Connection metrics update correctly -//! - Health state metrics reflect actual state -//! - Gap events tracked correctly -//! - Load test with 3+ relays -//! -//! # Running Tests -//! -//! ```bash -//! cargo test --test proactive_sync_metrics -//! cargo test --test proactive_sync_metrics -- --nocapture -//! ``` - -mod common; - -use std::time::Duration; - -use common::TestRelay; -use nostr_sdk::prelude::*; - -/// Kind 30617 - Repository State (NIP-34) -const KIND_REPOSITORY_STATE: u16 = 30617; - -/// Create a valid repository announcement event for testing -fn create_valid_repo_announcement(keys: &Keys, domain: &str, identifier: &str) -> Event { - let tags = vec![ - Tag::identifier(identifier), - Tag::custom( - TagKind::custom("clone"), - vec![format!("http://{}/{}", domain, identifier)], - ), - Tag::custom(TagKind::custom("relays"), vec![format!("ws://{}", domain)]), - ]; - - EventBuilder::new(Kind::Custom(KIND_REPOSITORY_STATE), "Repository state") - .tags(tags) - .sign_with_keys(keys) - .expect("Failed to sign event") -} - -/// Helper to fetch metrics from a relay's HTTP endpoint -async fn fetch_metrics(relay: &TestRelay) -> Result { - // Extract host:port from ws:// URL - let ws_url = relay.url(); - let http_url = ws_url.replace("ws://", "http://").replace("/", "") + "/metrics"; - - reqwest::get(&http_url).await?.text().await -} - -/// Test that sync metrics are exposed at /metrics endpoint -#[tokio::test] -async fn test_sync_metrics_exposed() { - let relay = TestRelay::start().await; - - // Give time for relay to start - tokio::time::sleep(Duration::from_millis(500)).await; - - // Fetch metrics - let metrics_result = fetch_metrics(&relay).await; - - relay.stop().await; - - // Check that we got metrics (even if sync isn't configured) - let metrics = metrics_result.expect("Failed to fetch metrics"); - - // Verify basic metrics structure exists - assert!( - metrics.contains("ngit_") || metrics.contains("# HELP"), - "Metrics endpoint should return Prometheus metrics" - ); -} - -/// Test that sync metrics include expected metric names -#[tokio::test] -async fn test_sync_metric_names_present() { - // Start a relay with sync configured - let source_relay = TestRelay::start().await; - let sync_relay = TestRelay::start_with_sync(Some(source_relay.url().into())).await; - - // Give time for sync connection to attempt - tokio::time::sleep(Duration::from_secs(2)).await; - - // Fetch metrics from the syncing relay - let metrics = fetch_metrics(&sync_relay) - .await - .expect("Failed to fetch metrics"); - - sync_relay.stop().await; - source_relay.stop().await; - - // Check for expected sync metric names (they may have zero values) - // At minimum, the ngit_ prefix metrics should be present - assert!( - metrics.contains("ngit_"), - "Metrics should include ngit_ prefixed metrics" - ); -} - -/// Test connection metrics update correctly on successful connection -#[tokio::test] -async fn test_connection_metrics_on_success() { - // Start source relay - let source_relay = TestRelay::start().await; - tokio::time::sleep(Duration::from_millis(200)).await; - - // Start syncing relay - let sync_relay = TestRelay::start_with_sync(Some(source_relay.url().into())).await; - - // Wait for connection to establish - tokio::time::sleep(Duration::from_secs(2)).await; - - // Fetch metrics - we can verify the relay started and metrics endpoint works - let metrics = fetch_metrics(&sync_relay) - .await - .expect("Failed to fetch metrics"); - - sync_relay.stop().await; - source_relay.stop().await; - - // Verify metrics endpoint returned data - assert!(!metrics.is_empty(), "Metrics endpoint should return data"); -} - -/// Test that events syncing updates metrics -#[tokio::test] -async fn test_event_sync_metrics() { - // Start source relay - let source_relay = TestRelay::start().await; - tokio::time::sleep(Duration::from_millis(200)).await; - - // Start syncing relay - let sync_relay = TestRelay::start_with_sync(Some(source_relay.url().into())).await; - - // Wait for connection - tokio::time::sleep(Duration::from_secs(1)).await; - - // Create and submit an event to source relay - let keys = Keys::generate(); - let event = create_valid_repo_announcement(&keys, &source_relay.domain(), "metrics-test-repo"); - - let client = Client::default(); - client - .add_relay(source_relay.url()) - .await - .expect("Failed to add relay"); - client.connect().await; - - let _ = client.send_event(&event).await; - - // Wait for sync to occur - tokio::time::sleep(Duration::from_secs(2)).await; - - // Fetch metrics from sync relay - let metrics = fetch_metrics(&sync_relay) - .await - .expect("Failed to fetch metrics"); - - client.disconnect().await; - sync_relay.stop().await; - source_relay.stop().await; - - // Verify metrics endpoint returned data after sync activity - assert!( - !metrics.is_empty(), - "Metrics should be present after sync activity" - ); -} - -/// Test health state tracking in metrics -#[tokio::test] -async fn test_health_state_metrics() { - // Start a syncing relay pointing to a non-existent source - // This will result in connection failures and health state changes - let sync_relay = TestRelay::start_with_sync(Some("ws://127.0.0.1:19999".into())).await; - - // Wait for some connection attempts - tokio::time::sleep(Duration::from_secs(3)).await; - - // Fetch metrics - let metrics = fetch_metrics(&sync_relay) - .await - .expect("Failed to fetch metrics"); - - sync_relay.stop().await; - - // The relay should still be operational even with failed sync - assert!( - !metrics.is_empty(), - "Metrics should be present even with sync failures" - ); -} - -/// Test gap event tracking (events received during catchup) -#[tokio::test] -async fn test_gap_event_tracking() { - // Start source relay and add some events first - let source_relay = TestRelay::start().await; - tokio::time::sleep(Duration::from_millis(200)).await; - - let keys = Keys::generate(); - - // Submit event before sync relay starts - let event = create_valid_repo_announcement(&keys, &source_relay.domain(), "pre-existing-repo"); - - let client = Client::default(); - client - .add_relay(source_relay.url()) - .await - .expect("Failed to add relay"); - client.connect().await; - let _ = client.send_event(&event).await; - - // Now start syncing relay - it should catch up on existing events - let sync_relay = TestRelay::start_with_sync(Some(source_relay.url().into())).await; - - // Wait for catchup - tokio::time::sleep(Duration::from_secs(3)).await; - - // Fetch metrics - let metrics = fetch_metrics(&sync_relay) - .await - .expect("Failed to fetch metrics"); - - client.disconnect().await; - sync_relay.stop().await; - source_relay.stop().await; - - // Verify metrics exist after gap sync scenario - assert!( - !metrics.is_empty(), - "Metrics should track gap sync activity" - ); -} - -/// Load test with 3+ relays configured for sync -#[tokio::test] -async fn test_multi_relay_load() { - // Start 3 source relays - let source_relay_1 = TestRelay::start().await; - let source_relay_2 = TestRelay::start().await; - let source_relay_3 = TestRelay::start().await; - - tokio::time::sleep(Duration::from_millis(500)).await; - - // Start a syncing relay pointing to first source - // Note: The current implementation only supports single sync relay URL - // but the test demonstrates the system handles multiple relay scenarios - let sync_relay = TestRelay::start_with_sync(Some(source_relay_1.url().into())).await; - - // Wait for connections - tokio::time::sleep(Duration::from_secs(2)).await; - - // Submit events to all source relays - let keys = Keys::generate(); - - let event1 = create_valid_repo_announcement(&keys, &source_relay_1.domain(), "repo-1"); - let event2 = create_valid_repo_announcement(&keys, &source_relay_2.domain(), "repo-2"); - let event3 = create_valid_repo_announcement(&keys, &source_relay_3.domain(), "repo-3"); - - // Submit events - let client1 = Client::default(); - client1 - .add_relay(source_relay_1.url()) - .await - .expect("Failed to add relay"); - client1.connect().await; - let _ = client1.send_event(&event1).await; - - let client2 = Client::default(); - client2 - .add_relay(source_relay_2.url()) - .await - .expect("Failed to add relay"); - client2.connect().await; - let _ = client2.send_event(&event2).await; - - let client3 = Client::default(); - client3 - .add_relay(source_relay_3.url()) - .await - .expect("Failed to add relay"); - client3.connect().await; - let _ = client3.send_event(&event3).await; - - // Wait for sync - tokio::time::sleep(Duration::from_secs(3)).await; - - // Fetch metrics from sync relay - let metrics = fetch_metrics(&sync_relay) - .await - .expect("Failed to fetch metrics"); - - // Cleanup - client1.disconnect().await; - client2.disconnect().await; - client3.disconnect().await; - sync_relay.stop().await; - source_relay_1.stop().await; - source_relay_2.stop().await; - source_relay_3.stop().await; - - // Verify metrics system handled load - assert!( - !metrics.is_empty(), - "Metrics should be available under multi-relay load" - ); -} - -/// Test that Prometheus text format is valid -#[tokio::test] -async fn test_prometheus_format_valid() { - let relay = TestRelay::start().await; - tokio::time::sleep(Duration::from_millis(500)).await; - - let metrics = fetch_metrics(&relay) - .await - .expect("Failed to fetch metrics"); - - relay.stop().await; - - // Check for valid Prometheus format markers - // - Lines starting with # are comments (HELP, TYPE) - // - Metric lines have format: metric_name{labels} value - let lines: Vec<&str> = metrics.lines().collect(); - - // Should have some content - assert!(!lines.is_empty(), "Metrics should have content"); - - // Check for at least some standard Prometheus patterns - let has_help = lines.iter().any(|l| l.starts_with("# HELP")); - let has_type = lines.iter().any(|l| l.starts_with("# TYPE")); - - // At minimum we expect help/type comments for any registered metrics - assert!( - has_help || has_type || lines.iter().any(|l| l.contains("ngit_")), - "Metrics should contain Prometheus format elements" - ); -} - -/// Test metrics endpoint availability during sync operations -#[tokio::test] -async fn test_metrics_availability_during_sync() { - let source_relay = TestRelay::start().await; - let sync_relay = TestRelay::start_with_sync(Some(source_relay.url().into())).await; - - tokio::time::sleep(Duration::from_millis(500)).await; - - // Make multiple metrics requests while sync is active - for i in 0..3 { - let metrics = fetch_metrics(&sync_relay).await; - assert!( - metrics.is_ok(), - "Metrics request {} should succeed during sync", - i + 1 - ); - tokio::time::sleep(Duration::from_millis(200)).await; - } - - sync_relay.stop().await; - source_relay.stop().await; -} -- cgit v1.2.3