#[test] fn stored_log_inventory_keeps_existing_files_visible_when_writer_is_disabled() { use std::io::Write; let dir = tempfile::tempdir().unwrap(); let path = dir.path().join("access.jsonl"); let mut file = std::fs::File::create(&path).unwrap(); writeln!(file, r#"{{"event":"request","status":200}}"#).unwrap(); let mut config = Config::default(); config.logging.file.enabled = false; config.logging.file.per_vhost = false; config.logging.file.path = path.to_string_lossy().into_owned(); let sources = configured_file_log_sources(&config); let access = sources.iter().find(|source| source.id == "access").unwrap(); assert!(!access.enabled); assert!(access.exists); assert!(access.size > 0); assert_eq!(access.path, path); } #[test] fn stored_log_tail_enforces_line_budget() { use std::io::Write; let dir = tempfile::tempdir().unwrap(); let path = dir.path().join("access.jsonl"); let mut file = std::fs::File::create(&path).unwrap(); for id in 0..10 { writeln!(file, r#"{{"time_ms":{id},"event":"request"}}"#).unwrap(); } drop(file); let source = source_from_path( "access".into(), "Access log".into(), "access", path, false, "JSONL", ); let (lines, _bytes, truncated) = read_tail(&source, 1024 * 1024, 3).unwrap(); assert_eq!(lines.len(), 3); assert!(lines[0].contains(r#""time_ms":9"#)); assert!(lines[2].contains(r#""time_ms":7"#)); assert!(truncated); } #[test] fn stored_log_query_rejects_oversized_source_identifier() { let query = FileLogQuery { source: Some("x".repeat(193)), ..FileLogQuery::default() }; assert!(validate_file_log_query(&query).is_err()); } #[test] fn stored_log_normalizes_mapped_client_ip_and_searches_diagnostics() { let dir = tempfile::tempdir().unwrap(); let source = source_from_path( "vhost:app".into(), "app.jsonl".into(), "access", dir.path().join("app.jsonl"), true, "JSONL", ); let mut format = crate::logging::JsonFormat::default(); format.fields.remove("client_ip"); format .fields .insert("remote_addr".into(), "client_ip".into()); let record = normalized_record( &source, r#"{"event":"protocol_error","remote_addr":"192.0.2.10","reason":"tls_handshake_error","error":"HTTP parser error","sni":"app.example.test","matched_by":"sni","vhost":"app"}"#, &format, ); assert_eq!(record["client_ip"], "192.0.2.10"); assert_eq!(record["sni"], "app.example.test"); let query = FileLogQuery::default(); assert!(record_matches( &record, &query, &parse_file_log_search("error").unwrap() )); assert!(record_matches( &record, &query, &parse_file_log_search(r#"error:"HTTP parser""#).unwrap() )); assert!(record_matches( &record, &query, &parse_file_log_search("sni:app.example.test AND !country:Poland").unwrap() )); assert!(!record_matches( &record, &query, &parse_file_log_search("sni:missing").unwrap() )); } #[test] fn stored_log_search_supports_field_aliases_negation_and_numeric_filters() { let record = json!({ "method":"GET", "country":"Germany", "status":503, "path":"/api/users" }); assert!(record_matches_search( &record, &parse_file_log_search("req: GET AND !country: Poland AND status:>=500").unwrap() )); assert!(record_matches_search( &record, &parse_file_log_search("status:5xx path:/api/*").unwrap() )); assert!(!record_matches_search( &record, &parse_file_log_search("country:Poland").unwrap() )); } #[test] fn stored_log_raw_error_parser_extracts_basic_fields() { let record = parse_raw_error_record( "2026-10-05T19:00:00.000Z ERROR rust_proxy::http upstream failed client_ip=192.0.2.10 status=502 error=connection reset", ); assert_eq!(record["timestamp"], "2026-10-05T19:00:00.000Z"); assert_eq!(record["level"], "ERROR"); assert_eq!(record["target"], "rust_proxy::http"); assert_eq!(record["message"], "upstream failed"); assert_eq!(record["client_ip"], "192.0.2.10"); assert_eq!(record["status"], "502"); assert_eq!(record["error"], "connection reset"); } #[cfg(unix)] #[test] fn stored_log_reader_refuses_symlink_targets() { use std::os::unix::fs::symlink; let dir = tempfile::tempdir().unwrap(); let real = dir.path().join("real.jsonl"); let link = dir.path().join("link.jsonl"); std::fs::write(&real, b"{}\n").unwrap(); symlink(&real, &link).unwrap(); assert!(open_file_log(&link).is_err()); }