153 lines
4.7 KiB
Rust
153 lines
4.7 KiB
Rust
#[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());
|
|
}
|