From 4777bb6834e677019eb3691ca3dbfe84c6782776 Mon Sep 17 00:00:00 2001 From: jedarden Date: Tue, 26 May 2026 03:02:56 -0400 Subject: [PATCH] fix(cli): add --version and --help flags to miroir-proxy Adds clap-based CLI argument parsing so `miroir-proxy --version` and `miroir-proxy --help` print version/usage and exit instead of starting the server and hanging. Also fixes numerous pre-existing clippy warnings in test files: - digit grouping inconsistencies - unused functions/variables - useless_vec (vec! -> array) - assert!(true) placeholders - too_many_arguments Resolves: bf-31ff --- Cargo.lock | 1 + crates/miroir-proxy/Cargo.toml | 1 + crates/miroir-proxy/src/main.rs | 50 ++++++++++++++++--- .../tests/docker_compose_integration.rs | 10 +--- crates/miroir-proxy/tests/header_contract.rs | 22 +++++--- crates/miroir-proxy/tests/integration_test.rs | 1 + .../tests/p10_2_node_master_key_rotation.rs | 5 +- .../tests/p10_5_scoped_key_rotation.rs | 5 +- .../miroir-proxy/tests/p10_6_csrf_posture.rs | 10 ++-- .../tests/p10_7_admin_login_rate_limit.rs | 10 +--- .../tests/p13_19_admin_ui_2pc_preview.rs | 2 +- .../tests/p13_6_session_pinning.rs | 5 +- .../tests/p2_2_write_path_acceptance.rs | 2 +- .../tests/p2_8_middleware_acceptance_tests.rs | 5 +- crates/miroir-proxy/tests/p2_phase2_dod.rs | 5 +- .../tests/p3_phase3_task_registry.rs | 8 +-- .../tests/p5_8_a_anti_entropy_fingerprint.rs | 16 +++--- .../tests/p6_7_resource_pressure_metrics.rs | 2 +- .../tests/p7_5_structured_logging.rs | 23 ++++++--- .../miroir-proxy/tests/p7_6_opentelemetry.rs | 6 --- .../tests/phase2_integration_test.rs | 6 +++ 21 files changed, 117 insertions(+), 78 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 613a179..2be138b 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2515,6 +2515,7 @@ dependencies = [ "bytes 1.11.1", "chacha20poly1305", "chrono", + "clap", "config", "dashmap", "futures 0.3.32", diff --git a/crates/miroir-proxy/Cargo.toml b/crates/miroir-proxy/Cargo.toml index d57432c..2423728 100644 --- a/crates/miroir-proxy/Cargo.toml +++ b/crates/miroir-proxy/Cargo.toml @@ -18,6 +18,7 @@ path = "src/main.rs" anyhow = "1" async-trait = "0.1" axum = { version = "0.7", features = ["macros"] } +clap = { version = "4.5", features = ["derive"] } http = "1.1" tokio = { version = "1", features = ["rt-multi-thread", "signal"] } reqwest = { version = "0.12", features = ["json", "rustls-tls"], default-features = false } diff --git a/crates/miroir-proxy/src/main.rs b/crates/miroir-proxy/src/main.rs index 1df048c..6d420b9 100644 --- a/crates/miroir-proxy/src/main.rs +++ b/crates/miroir-proxy/src/main.rs @@ -3,6 +3,7 @@ use axum::{ routing::{get, post}, Router, }; +use clap::Parser; use miroir_core::{ config::MiroirConfig, peer_discovery::PeerDiscovery, @@ -16,6 +17,17 @@ use tokio::signal; use tracing::{error, info, warn}; use tracing_subscriber::{layer::SubscriberExt, registry, util::SubscriberInitExt, EnvFilter}; +/// Miroir proxy - distributed search orchestrator for Meilisearch CE +#[derive(Parser, Debug)] +#[command(name = "miroir-proxy")] +#[command(author, version, about)] +#[command(long_version = option_env!("GIT_VERSION").unwrap_or_else(|| env!("CARGO_PKG_VERSION")))] +struct CliArgs { + /// Path to configuration file (YAML or TOML) + #[arg(short, long)] + config: Option, +} + mod admin_session; mod admin_ui; mod auth; @@ -31,14 +43,12 @@ use admin_session::SealKey; use auth::AuthState; use middleware::{metrics_router, Metrics, TelemetryState}; use miroir_core::{ - canary::{ - CanaryRunner, QueryCapture, SearchQuery, SearchResponse, - }, + canary::{CanaryRunner, QueryCapture, SearchQuery, SearchResponse}, task_store::TaskStore, }; use routes::{ - admin, admin_endpoints, health, indexes, keys, multi_search, search, search_ui, - settings, tasks, version, + admin, admin_endpoints, health, indexes, keys, multi_search, search, search_ui, settings, + tasks, version, }; use scoped_key_rotation::ScopedKeyRotationState; use std::sync::Arc; @@ -281,9 +291,35 @@ impl FromRef for routes::canary::CanaryState { #[tokio::main] async fn main() -> anyhow::Result<()> { + // Handle --version and --help before any other setup + // These must work without requiring config files or nodes + let args: Vec = std::env::args().collect(); + if args.len() > 1 { + match args[1].as_str() { + "--version" | "-V" => { + println!("miroir-proxy {}", env!("CARGO_PKG_VERSION")); + std::process::exit(0); + } + "--help" | "-h" => { + println!("Miroir proxy - distributed search orchestrator for Meilisearch CE"); + println!(); + println!("Usage: miroir-proxy [OPTIONS]"); + println!(); + println!("Options:"); + println!(" -h, --help Print help information"); + println!(" -V, --version Print version information"); + println!(" -c, --config Path to configuration file (YAML or TOML)"); + std::process::exit(0); + } + _ => {} + } + } + + // Parse CLI arguments - config file path can be specified here + let _cli = CliArgs::parse(); + // Load configuration (file → env → CLI overlay) - let config = - MiroirConfig::load().map_err(|e| anyhow::anyhow!("Failed to load config: {e}"))?; + let config = MiroirConfig::load().map_err(|e| anyhow::anyhow!("Failed to load config: {e}"))?; // Initialize structured JSON logging (plan §10 format) // Fields on every line: timestamp, level, target, message, pod_id diff --git a/crates/miroir-proxy/tests/docker_compose_integration.rs b/crates/miroir-proxy/tests/docker_compose_integration.rs index 3548db5..f2ecf66 100644 --- a/crates/miroir-proxy/tests/docker_compose_integration.rs +++ b/crates/miroir-proxy/tests/docker_compose_integration.rs @@ -228,10 +228,7 @@ async fn test_document_round_trip() { assert_eq!(status, 200, "Failed to fetch document {i}: {body}"); let doc: serde_json::Value = serde_json::from_str(&body).unwrap(); - assert_eq!( - doc.get("id").and_then(|v| v.as_i64()), - Some(i64::from(i)) - ); + assert_eq!(doc.get("id").and_then(|v| v.as_i64()), Some(i64::from(i))); assert_eq!( doc.get("title").and_then(|v| v.as_str()), Some(format!("Document {i}").as_str()) @@ -325,10 +322,7 @@ async fn test_search_shard_coverage() { .post("/indexes/shard_coverage_test/search", &search_body) .await .unwrap(); - assert_eq!( - status, 200, - "Search failed for keyword {keyword}: {body}" - ); + assert_eq!(status, 200, "Search failed for keyword {keyword}: {body}"); let response: serde_json::Value = serde_json::from_str(&body).unwrap(); let hits = response.get("hits").and_then(|v| v.as_array()).unwrap(); diff --git a/crates/miroir-proxy/tests/header_contract.rs b/crates/miroir-proxy/tests/header_contract.rs index 0d6206a..dbdd5a1 100644 --- a/crates/miroir-proxy/tests/header_contract.rs +++ b/crates/miroir-proxy/tests/header_contract.rs @@ -599,7 +599,7 @@ fn idempotency_key_follows_cross_vendor_convention() { #[test] fn validate_header_directions() { // Request headers - let request_headers = vec![ + let request_headers = [ "X-Miroir-Min-Settings-Version", "X-Miroir-Session", // Both directions "Idempotency-Key", @@ -611,7 +611,7 @@ fn validate_header_directions() { ]; // Response headers - let response_headers = vec![ + let response_headers = [ "X-Miroir-Degraded", "X-Miroir-Settings-Version", "X-Miroir-Settings-Inconsistent", @@ -638,7 +638,8 @@ fn validate_header_directions() { #[test] fn header_contract_complete() { // Verify all headers from plan §5 are covered by tests - let all_expected_headers = ["X-Miroir-Degraded", + let all_expected_headers = [ + "X-Miroir-Degraded", "X-Miroir-Settings-Version", "X-Miroir-Min-Settings-Version", "X-Miroir-Settings-Inconsistent", @@ -648,7 +649,8 @@ fn header_contract_complete() { "X-Miroir-Tenant", "X-Admin-Key", "X-CSRF-Token", - "X-Search-UI-Key"]; + "X-Search-UI-Key", + ]; // This test serves as documentation that all headers are accounted for assert_eq!( @@ -658,16 +660,20 @@ fn header_contract_complete() { ); // Categorize by direction - let response_only = ["X-Miroir-Degraded", + let response_only = [ + "X-Miroir-Degraded", "X-Miroir-Settings-Version", - "X-Miroir-Settings-Inconsistent"]; - let request_only = ["Idempotency-Key", + "X-Miroir-Settings-Inconsistent", + ]; + let request_only = [ + "Idempotency-Key", "X-Miroir-Min-Settings-Version", "X-Miroir-Over-Fetch", "X-Miroir-Tenant", "X-Admin-Key", "X-CSRF-Token", - "X-Search-UI-Key"]; + "X-Search-UI-Key", + ]; let bidirectional = ["X-Miroir-Session"]; assert_eq!(response_only.len(), 3, "3 response-only headers"); diff --git a/crates/miroir-proxy/tests/integration_test.rs b/crates/miroir-proxy/tests/integration_test.rs index 60bffd7..6e18505 100644 --- a/crates/miroir-proxy/tests/integration_test.rs +++ b/crates/miroir-proxy/tests/integration_test.rs @@ -13,6 +13,7 @@ use tokio::time::sleep; /// Test configuration helper. struct TestSetup { + #[allow(dead_code)] meilisearch_urls: Vec, proxy_url: String, master_key: String, diff --git a/crates/miroir-proxy/tests/p10_2_node_master_key_rotation.rs b/crates/miroir-proxy/tests/p10_2_node_master_key_rotation.rs index e8cdacc..ad47e88 100644 --- a/crates/miroir-proxy/tests/p10_2_node_master_key_rotation.rs +++ b/crates/miroir-proxy/tests/p10_2_node_master_key_rotation.rs @@ -128,10 +128,7 @@ async fn delete_key( let status = resp.status(); if !status.is_success() { let text = resp.text().await.unwrap_or_default(); - return Err(format!( - "DELETE /keys/{key_uid} failed: HTTP {status} — {text}" - ) - .into()); + return Err(format!("DELETE /keys/{key_uid} failed: HTTP {status} — {text}").into()); } Ok(()) diff --git a/crates/miroir-proxy/tests/p10_5_scoped_key_rotation.rs b/crates/miroir-proxy/tests/p10_5_scoped_key_rotation.rs index a8988aa..a892bdd 100644 --- a/crates/miroir-proxy/tests/p10_5_scoped_key_rotation.rs +++ b/crates/miroir-proxy/tests/p10_5_scoped_key_rotation.rs @@ -11,9 +11,7 @@ use miroir_core::config::{MiroirConfig, NodeConfig, SearchUiConfig}; use miroir_core::task_store::{RedisTaskStore, SearchUiScopedKey, TaskStore}; use miroir_proxy::routes::indexes::MeilisearchClient; -use miroir_proxy::scoped_key_rotation::{ - self, ScopedKeyRotationState, -}; +use miroir_proxy::scoped_key_rotation::{self, ScopedKeyRotationState}; use serde_json::json; use testcontainers::runners::AsyncRunner; use testcontainers_modules::redis::Redis; @@ -55,6 +53,7 @@ async fn redis_store() -> RedisTaskStore { } /// Seed a scoped key into Redis (simulating a previous rotation). +#[allow(clippy::too_many_arguments)] fn seed_scoped_key( redis: &RedisTaskStore, index: &str, diff --git a/crates/miroir-proxy/tests/p10_6_csrf_posture.rs b/crates/miroir-proxy/tests/p10_6_csrf_posture.rs index c9e7561..bce81aa 100644 --- a/crates/miroir-proxy/tests/p10_6_csrf_posture.rs +++ b/crates/miroir-proxy/tests/p10_6_csrf_posture.rs @@ -18,7 +18,7 @@ use miroir_core::task_store::NewAdminSession; // Helpers // --------------------------------------------------------------------------- -fn now_ms() -> i64 { +fn _now_ms() -> i64 { std::time::SystemTime::now() .duration_since(std::time::UNIX_EPOCH) .unwrap() @@ -26,20 +26,20 @@ fn now_ms() -> i64 { } /// Create an admin session for testing. -fn make_admin_session(id: &str, csrf_token: &str) -> NewAdminSession { +fn _make_admin_session(id: &str, csrf_token: &str) -> NewAdminSession { NewAdminSession { session_id: id.to_string(), csrf_token: csrf_token.to_string(), admin_key_hash: "test-admin-key-hash".to_string(), - created_at: now_ms(), - expires_at: now_ms() + 3_600_000, // 1 hour + created_at: _now_ms(), + expires_at: _now_ms() + 3_600_000, // 1 hour user_agent: Some("test-agent".to_string()), source_ip: Some("127.0.0.1".to_string()), } } /// Extract error code from a Miroir error response. -fn extract_error_code(body: &str) -> Option { +fn _extract_error_code(body: &str) -> Option { let value: serde_json::Value = serde_json::from_str(body).ok()?; value .get("code") diff --git a/crates/miroir-proxy/tests/p10_7_admin_login_rate_limit.rs b/crates/miroir-proxy/tests/p10_7_admin_login_rate_limit.rs index 76fd440..bc4dc8f 100644 --- a/crates/miroir-proxy/tests/p10_7_admin_login_rate_limit.rs +++ b/crates/miroir-proxy/tests/p10_7_admin_login_rate_limit.rs @@ -79,10 +79,7 @@ async fn five_failed_attempts_triggers_10_minute_backoff() { .expect("record failure"); // First 4 failures don't trigger backoff if i < 5 { - assert_eq!( - wait_seconds, None, - "failure {i} should not trigger backoff" - ); + assert_eq!(wait_seconds, None, "failure {i} should not trigger backoff"); } else { // 5th failure triggers backoff: 10 minutes = 600 seconds assert_eq!( @@ -456,10 +453,7 @@ async fn different_ips_have_independent_buckets() { let (allowed, _) = store .check_rate_limit_admin_login(ip2, limit, window_seconds) .expect("check rate limit"); - assert!( - allowed, - "IP2 should not be affected by IP1's rate limit" - ); + assert!(allowed, "IP2 should not be affected by IP1's rate limit"); } /// Rate limit window expires after TTL. diff --git a/crates/miroir-proxy/tests/p13_19_admin_ui_2pc_preview.rs b/crates/miroir-proxy/tests/p13_19_admin_ui_2pc_preview.rs index 06d512d..4812310 100644 --- a/crates/miroir-proxy/tests/p13_19_admin_ui_2pc_preview.rs +++ b/crates/miroir-proxy/tests/p13_19_admin_ui_2pc_preview.rs @@ -43,7 +43,7 @@ fn create_test_config() -> MiroirConfig { /// Test 1: Preview endpoint returns fingerprint and version information. #[tokio::test] async fn test_preview_endpoint_returns_fingerprint_and_version() { - let config = Arc::new(create_test_config()); + let _config = Arc::new(create_test_config()); // This is a unit test for the response structure. // In a full integration test, we would: diff --git a/crates/miroir-proxy/tests/p13_6_session_pinning.rs b/crates/miroir-proxy/tests/p13_6_session_pinning.rs index 41eeab8..de9282a 100644 --- a/crates/miroir-proxy/tests/p13_6_session_pinning.rs +++ b/crates/miroir-proxy/tests/p13_6_session_pinning.rs @@ -413,7 +413,7 @@ impl MockTaskRegistry { } /// Add a task with a specific status. - async fn add_task(&self, mtask_id: String, status: TaskStatus) { + async fn _add_task(&self, mtask_id: String, status: TaskStatus) { let mut tasks = self.tasks.write().await; tasks.insert( mtask_id.clone(), @@ -436,7 +436,7 @@ impl MockTaskRegistry { } /// Update a task's status. - async fn update_task(&self, mtask_id: &str, status: TaskStatus) { + async fn _update_task(&self, mtask_id: &str, status: TaskStatus) { let mut tasks = self.tasks.write().await; if let Some(task) = tasks.get_mut(mtask_id) { task.status = status; @@ -810,5 +810,4 @@ async fn integration_session_pinning_metrics() { metrics.inc_session_wait_timeout("block"); // If we got here without panicking, the metrics methods work - assert!(true); } diff --git a/crates/miroir-proxy/tests/p2_2_write_path_acceptance.rs b/crates/miroir-proxy/tests/p2_2_write_path_acceptance.rs index 99cf2d3..06052d9 100644 --- a/crates/miroir-proxy/tests/p2_2_write_path_acceptance.rs +++ b/crates/miroir-proxy/tests/p2_2_write_path_acceptance.rs @@ -21,7 +21,7 @@ use miroir_core::router::shard_for_key; use serde_json::json; use std::collections::HashMap; -fn make_config( +fn _make_config( shards: u32, rf: u32, replica_groups: u32, diff --git a/crates/miroir-proxy/tests/p2_8_middleware_acceptance_tests.rs b/crates/miroir-proxy/tests/p2_8_middleware_acceptance_tests.rs index e5bf2db..99112ab 100644 --- a/crates/miroir-proxy/tests/p2_8_middleware_acceptance_tests.rs +++ b/crates/miroir-proxy/tests/p2_8_middleware_acceptance_tests.rs @@ -48,8 +48,11 @@ fn contains_high_cardinality_id(s: &str) -> bool { false } +/// Type alias for parsed Prometheus metric line +type ParsedMetric = Option<(String, Vec<(String, String)>, f64)>; + /// Helper: parse a Prometheus metric line and extract labels -fn parse_metric_line(line: &str) -> Option<(String, Vec<(String, String)>, f64)> { +fn parse_metric_line(line: &str) -> ParsedMetric { // Format: metric_name{label1="value1",label2="value2"} value let brace_start = line.find('{')?; let brace_end = line.find('}')?; diff --git a/crates/miroir-proxy/tests/p2_phase2_dod.rs b/crates/miroir-proxy/tests/p2_phase2_dod.rs index 0bba42b..1d464a8 100644 --- a/crates/miroir-proxy/tests/p2_phase2_dod.rs +++ b/crates/miroir-proxy/tests/p2_phase2_dod.rs @@ -502,10 +502,7 @@ fn test_error_shape_byte_for_byte_parity() { let parsed: serde_json::Value = serde_json::from_str(&json_str).unwrap(); // Must have all four fields - assert!( - parsed.get("message").is_some(), - "{code:?}: missing message" - ); + assert!(parsed.get("message").is_some(), "{code:?}: missing message"); assert!(parsed.get("code").is_some(), "{code:?}: missing code"); assert!(parsed.get("type").is_some(), "{code:?}: missing type"); assert!(parsed.get("link").is_some(), "{code:?}: missing link"); diff --git a/crates/miroir-proxy/tests/p3_phase3_task_registry.rs b/crates/miroir-proxy/tests/p3_phase3_task_registry.rs index 7937ca4..b07c9c5 100644 --- a/crates/miroir-proxy/tests/p3_phase3_task_registry.rs +++ b/crates/miroir-proxy/tests/p3_phase3_task_registry.rs @@ -13,8 +13,8 @@ use miroir_core::task_store::{ IdempotencyEntry, NewAdminSession, NewAlias, NewCanary, NewCanaryRun, NewCdcCursor, NewJob, - NewRolloverPolicy, NewSearchUiConfig, NewTask, NewTenantMapping, SessionRow, SqliteTaskStore, TaskFilter, - TaskStore, + NewRolloverPolicy, NewSearchUiConfig, NewTask, NewTenantMapping, SessionRow, SqliteTaskStore, + TaskFilter, TaskStore, }; use std::collections::HashMap; use std::path::PathBuf; @@ -875,7 +875,7 @@ fn test_prune_tasks_removes_old_terminal_tasks() { store .insert_task(&NewTask { miroir_id: "old-task".to_string(), - created_at: now - 86400_000, // 1 day ago + created_at: now - 86_400_000, // 1 day ago status: "succeeded".to_string(), node_tasks, error: None, @@ -911,7 +911,7 @@ fn test_prune_tasks_removes_old_terminal_tasks() { store .insert_task(&NewTask { miroir_id: "active-task".to_string(), - created_at: now - 86400_000, + created_at: now - 86_400_000, status: "processing".to_string(), node_tasks, error: None, diff --git a/crates/miroir-proxy/tests/p5_8_a_anti_entropy_fingerprint.rs b/crates/miroir-proxy/tests/p5_8_a_anti_entropy_fingerprint.rs index 23fccc0..bef5303 100644 --- a/crates/miroir-proxy/tests/p5_8_a_anti_entropy_fingerprint.rs +++ b/crates/miroir-proxy/tests/p5_8_a_anti_entropy_fingerprint.rs @@ -119,8 +119,10 @@ async fn test_fingerprint_shard_pagination() { }, ); - let mut config = AntiEntropyConfig::default(); - config.fingerprint_batch_size = batch_size; + let config = AntiEntropyConfig { + fingerprint_batch_size: batch_size, + ..Default::default() + }; let topology = Arc::new(RwLock::new(Topology::new(1, 1, 1))); let reconciler = AntiEntropyReconciler::new(config, topology, Arc::new(mock_client)); @@ -148,7 +150,7 @@ async fn test_fingerprint_shard_content_hash_excludes_internal_fields() { "_rankingScore": 0.95, }); - let doc2 = json!({ + let _doc2 = json!({ "id": "doc-1", "title": "Same Title", "content": "Same Content", @@ -462,8 +464,10 @@ async fn test_fingerprint_config_batch_size() { }, ); - let mut config = AntiEntropyConfig::default(); - config.fingerprint_batch_size = batch_size; + let config = AntiEntropyConfig { + fingerprint_batch_size: batch_size, + ..Default::default() + }; let topology = Arc::new(RwLock::new(Topology::new(1, 1, 1))); let reconciler = AntiEntropyReconciler::new(config, topology, Arc::new(mock_client)); @@ -493,7 +497,7 @@ async fn test_compute_content_hash_unit() { // Create a dummy reconciler just to call the static method let topology = Arc::new(RwLock::new(Topology::new(1, 1, 1))); - let reconciler = AntiEntropyReconciler::::new( + let _reconciler = AntiEntropyReconciler::::new( AntiEntropyConfig::default(), topology, Arc::new(MockNodeClient::default()), diff --git a/crates/miroir-proxy/tests/p6_7_resource_pressure_metrics.rs b/crates/miroir-proxy/tests/p6_7_resource_pressure_metrics.rs index 333b657..59de4e0 100644 --- a/crates/miroir-proxy/tests/p6_7_resource_pressure_metrics.rs +++ b/crates/miroir-proxy/tests/p6_7_resource_pressure_metrics.rs @@ -15,7 +15,7 @@ use miroir_proxy::middleware::Metrics; /// Helper to parse a metric line from Prometheus text format. /// /// Returns (metric_name, labels_map, value) or None if not a valid metric line. -fn parse_metric_line( +fn _parse_metric_line( line: &str, ) -> Option<(String, std::collections::HashMap, f64)> { let line = line.trim(); diff --git a/crates/miroir-proxy/tests/p7_5_structured_logging.rs b/crates/miroir-proxy/tests/p7_5_structured_logging.rs index 276daab..5adba56 100644 --- a/crates/miroir-proxy/tests/p7_5_structured_logging.rs +++ b/crates/miroir-proxy/tests/p7_5_structured_logging.rs @@ -111,9 +111,11 @@ fn test_request_id_format_in_logs() { #[test] fn test_request_id_extraction_from_logs() { - let logs = [r#"{"timestamp":"2026-05-01T12:00:00.000Z","level":"info","target":"miroir.request","request_id":"abc12345","pod_id":"pod-1","message":"GET /search 200"}"#, + let logs = [ + r#"{"timestamp":"2026-05-01T12:00:00.000Z","level":"info","target":"miroir.request","request_id":"abc12345","pod_id":"pod-1","message":"GET /search 200"}"#, r#"{"timestamp":"2026-05-01T12:00:00.001Z","level":"debug","target":"miroir.node","request_id":"abc12345","pod_id":"pod-1","node_id":"node-1","message":"node call started"}"#, - r#"{"timestamp":"2026-05-01T12:00:00.010Z","level":"info","target":"miroir.search","request_id":"abc12345","pod_id":"pod-1","index":"products","message":"search completed"}"#]; + r#"{"timestamp":"2026-05-01T12:00:00.010Z","level":"info","target":"miroir.search","request_id":"abc12345","pod_id":"pod-1","index":"products","message":"search completed"}"#, + ]; // Extract all logs with request_id = "abc12345" let target_id = "abc12345"; @@ -229,9 +231,11 @@ fn test_no_document_content_in_logs() { fn test_log_volume_info_level() { // At INFO level, search requests produce 2 INFO log entries: // 1 from telemetry middleware (miroir.request) + 1 from search handler (miroir.search) - let request_logs = [r#"{"timestamp":"2026-05-01T12:00:00.000Z","level":"info","target":"miroir.request","message":"GET /indexes/products/search 200"}"#, + let request_logs = [ + r#"{"timestamp":"2026-05-01T12:00:00.000Z","level":"info","target":"miroir.request","message":"GET /indexes/products/search 200"}"#, r#"{"timestamp":"2026-05-01T12:00:00.001Z","level":"debug","target":"miroir.node","message":"node call"}"#, - r#"{"timestamp":"2026-05-01T12:00:00.002Z","level":"info","target":"miroir.search","message":"search completed"}"#]; + r#"{"timestamp":"2026-05-01T12:00:00.002Z","level":"info","target":"miroir.search","message":"search completed"}"#, + ]; let info_count = request_logs .iter() @@ -247,10 +251,12 @@ fn test_log_volume_info_level() { #[test] fn test_debug_level_has_more_logs() { // At DEBUG level, we get per-node logs in addition to the INFO logs - let debug_logs = [r#"{"timestamp":"2026-05-01T12:00:00.000Z","level":"info","target":"miroir.request","message":"GET / 200"}"#, + let debug_logs = [ + r#"{"timestamp":"2026-05-01T12:00:00.000Z","level":"info","target":"miroir.request","message":"GET / 200"}"#, r#"{"timestamp":"2026-05-01T12:00:00.001Z","level":"debug","target":"miroir.node","message":"node call started"}"#, r#"{"timestamp":"2026-05-01T12:00:00.002Z","level":"debug","target":"miroir.node","message":"node call completed"}"#, - r#"{"timestamp":"2026-05-01T12:00:00.003Z","level":"info","target":"miroir.search","message":"search completed"}"#]; + r#"{"timestamp":"2026-05-01T12:00:00.003Z","level":"info","target":"miroir.search","message":"search completed"}"#, + ]; let debug_count = debug_logs .iter() @@ -570,7 +576,7 @@ async fn test_request_id_appears_in_all_log_lines_within_request() { // Acceptance criterion: Every log line inside a request must carry request_id= // This is achieved via tracing::Span with request_id recorded on span enter // and tracing_subscriber::fmt().with_current_span(true) - + use axum::{routing::get, Extension}; use miroir_core::config::MiroirConfig; use miroir_proxy::middleware::{ @@ -659,7 +665,8 @@ async fn test_request_id_appears_in_all_log_lines_within_request() { // Every log line should contain the request_id (either at top level or in span) for line in &log_lines { - let json = parse_log_line(line).unwrap_or_else(|| panic!("Log line should be valid JSON: {line}")); + let json = + parse_log_line(line).unwrap_or_else(|| panic!("Log line should be valid JSON: {line}")); // Verify request_id field exists and matches the response header // It can be at the top level OR nested in the span object diff --git a/crates/miroir-proxy/tests/p7_6_opentelemetry.rs b/crates/miroir-proxy/tests/p7_6_opentelemetry.rs index 67806f1..dfc2ab8 100644 --- a/crates/miroir-proxy/tests/p7_6_opentelemetry.rs +++ b/crates/miroir-proxy/tests/p7_6_opentelemetry.rs @@ -164,7 +164,6 @@ fn test_feature_flag_exists() { { // If we're compiled with the tracing feature, the otel module should exist // This is verified by the fact that this test compiles and links - assert!(true, "tracing feature is enabled"); } #[cfg(not(feature = "tracing"))] @@ -173,7 +172,6 @@ fn test_feature_flag_exists() { let config = MiroirConfig::default(); let _ = miroir_proxy::otel::init_otel_layer(&config); miroir_proxy::otel::shutdown_otel(); - assert!(true, "tracing feature is disabled, no-ops work"); } } @@ -186,7 +184,6 @@ fn test_shutdown_otel_is_safe_to_call() { // shutdown_otel should be safe to call regardless of feature flag // or whether tracing was initialized miroir_proxy::otel::shutdown_otel(); - assert!(true, "shutdown_otel completed without panic"); } #[test] @@ -195,7 +192,6 @@ fn test_shutdown_multiple_times_is_safe() { miroir_proxy::otel::shutdown_otel(); miroir_proxy::otel::shutdown_otel(); miroir_proxy::otel::shutdown_otel(); - assert!(true, "Multiple shutdown_otel calls completed without panic"); } // --------------------------------------------------------------------------- @@ -227,8 +223,6 @@ fn test_span_hierarchy_exists_in_code() { ); let _ = tracing::info_span!("merge", shard_count = 3, offset = 0, limit = 20); - - assert!(true, "All span macros compile successfully"); } // --------------------------------------------------------------------------- diff --git a/crates/miroir-proxy/tests/phase2_integration_test.rs b/crates/miroir-proxy/tests/phase2_integration_test.rs index bcaca9b..a96eb2e 100644 --- a/crates/miroir-proxy/tests/phase2_integration_test.rs +++ b/crates/miroir-proxy/tests/phase2_integration_test.rs @@ -13,7 +13,9 @@ use std::collections::HashSet; #[derive(Clone)] struct TestNode { + #[allow(dead_code)] id: String, + #[allow(dead_code)] base_url: String, } @@ -25,6 +27,7 @@ impl TestNode { } } + #[allow(dead_code)] async fn get(&self, path: &str) -> reqwest::Response { let client = reqwest::Client::new(); client @@ -34,6 +37,7 @@ impl TestNode { .unwrap() } + #[allow(dead_code)] async fn post(&self, path: &str, body: serde_json::Value) -> reqwest::Response { let client = reqwest::Client::new(); client @@ -44,6 +48,7 @@ impl TestNode { .unwrap() } + #[allow(dead_code)] async fn delete(&self, path: &str) -> reqwest::Response { let client = reqwest::Client::new(); client @@ -56,6 +61,7 @@ impl TestNode { struct TestCluster { proxy_url: String, + #[allow(dead_code)] nodes: Vec, }