This commit is contained in:
Mateusz Gruszczyński committed 2026-10-04 11:15:58 +02:00
1 parent 87e571c170
commit fa7abc9e53
308 files changed
+49746 -50237

No files matched your search

+159
View File
@@ -0,0 +1,159 @@
mod tests {
use super::*;
fn entry() -> LogEntry {
LogEntry {
vhost: Some("app".into()),
route: Some("root".into()),
cache_effective_enabled: Some(true),
transform_effective_enabled: Some(false),
backend: Some("origin".into()),
id: 7,
time_ms: 1_700_000_000_000,
method: "GET".into(),
host: "app.example".into(),
path: "/health".into(),
http_version: "3",
transport: "h3",
websocket_bootstrap: Some("h3_extended_connect"),
websocket_phase: Some("tunnel_closed"),
websocket_error: None,
h3_reset_code: None,
upstream_status: Some(101),
upstream_error: None,
client_ip: Some("192.0.2.10".into()),
user_agent: Some("RustProxy-Test/1.0".into()),
country: Some("PL".into()),
status: 200,
duration_ms: 12,
request_bytes: 10,
response_bytes: 42,
outcome: "ok",
cache: "HIT",
cache_reason: "cache_hit",
}
}
#[test]
fn json_format_can_map_and_add_static_fields() {
let mut format = JsonFormat::default();
format.fields.insert("http_status".into(), "status".into());
format.fields.insert("site".into(), "vhost".into());
format.fields.insert("route".into(), "route".into());
format.fields.insert("ua".into(), "user_agent".into());
format.fields.insert("geo_country".into(), "country".into());
format
.fields
.insert("cache_enabled".into(), "cache_effective_enabled".into());
format.fields.insert(
"transform_enabled".into(),
"transform_effective_enabled".into(),
);
format.static_fields.insert("service".into(), "edge".into());
let mut settings = Settings::default();
settings.format = format.clone();
settings.validate().unwrap();
let value = format_entry(&entry(), &format);
assert_eq!(value["http_status"], 200);
assert_eq!(value["site"], "app");
assert_eq!(value["route"], "root");
assert_eq!(value["ua"], "RustProxy-Test/1.0");
assert_eq!(value["geo_country"], "PL");
assert_eq!(value["cache_enabled"], true);
assert_eq!(value["transform_enabled"], false);
assert_eq!(value["service"], "edge");
assert!(value.get("method").is_none());
}
#[test]
fn logging_validation_rejects_credentials_unknown_fields_and_bad_endpoints() {
let mut settings = Settings::default();
settings.loki.enabled = true;
settings.loki.url = "https://user:secret@example.invalid/loki/api/v1/push".into();
assert!(settings.validate().is_err());
let mut settings = Settings::default();
settings.logstash.enabled = true;
settings.logstash.address = "missing-port.example".into();
assert!(settings.validate().is_err());
let mut settings = Settings::default();
settings
.format
.fields
.insert("status".into(), "does_not_exist".into());
assert!(settings.validate().is_err());
}
#[test]
fn per_vhost_file_mode_has_safe_names_and_requires_directory() {
assert_eq!(vhost_log_name(Some("app-1")), "app-1");
assert_eq!(vhost_log_name(None), "_unmatched");
assert_eq!(vhost_log_name(Some("bad/name")), "bad_name");
let mut settings = Settings::default();
settings.file.enabled = true;
settings.file.per_vhost = true;
settings.file.directory.clear();
assert!(settings.validate().is_err());
}
#[test]
fn capture_defaults_keep_geoip_off_request_path() {
let settings = Settings::default();
assert!(settings.capture_user_agent);
assert!(!settings.capture_country);
}
#[test]
fn default_json_format_keeps_standard_entry() {
let value = format_entry(&entry(), &JsonFormat::default());
assert_eq!(value["method"], "GET");
assert_eq!(value["cache"], "HIT");
assert_eq!(value["response_bytes"], 42);
}
#[test]
fn error_log_defaults_off_and_redacts_common_secret_shapes() {
let settings = ErrorLogSettings::default();
assert!(!settings.enabled);
assert_eq!(settings.format, ErrorLogFormat::Json);
let text = redact_text(
r#"Authorization: Bearer topsecret url=https://x.invalid/?api_token=abc password=hunter2 {\"private_key\":\"pem-data\"}"#,
);
assert!(!text.contains("topsecret"));
assert!(!text.contains("api_token=abc"));
assert!(!text.contains("hunter2"));
assert!(!text.contains("pem-data"));
}
#[test]
fn error_json_is_one_record_and_reserved_fields_cannot_be_overwritten() {
let event = ErrorEvent {
timestamp: "2026-10-03T12:34:56.123Z".into(),
target: "rust_proxy::http".into(),
message: "upstream failed\nsecond line".into(),
fields: BTreeMap::from([
("message".into(), "attacker override".into()),
("request_id".into(), "abc".into()),
]),
};
let line = format_error_event(&event, ErrorLogFormat::Json);
assert_eq!(line.iter().filter(|byte| **byte == b'\n').count(), 1);
let value: Value = serde_json::from_slice(&line).unwrap();
assert_eq!(value["message"], "upstream failed\nsecond line");
assert_eq!(value["request_id"], "abc");
}
#[test]
fn retained_history_is_larger_than_the_live_snapshot_but_still_bounded() {
let logs = Logs::default();
for id in 0..(LIVE_WINDOW + 80) {
let mut item = entry();
item.id = id as u64;
logs.push(item);
}
assert_eq!(logs.recent_limit(LIVE_WINDOW).len(), LIVE_WINDOW);
assert_eq!(logs.recent().len(), LIVE_WINDOW + 80);
assert_eq!(logs.recent_limit(HISTORY_CAPACITY + 1).len(), LIVE_WINDOW + 80);
}
}