use std::process::Command;
use sonic_rs::{JsonContainerTrait, JsonValueTrait};
fn cargo_bin() -> String {
std::env::var("CARGO").unwrap_or_else(|_| "cargo".to_string())
}
fn run_basic_example() -> (String, i32) {
let output = Command::new(cargo_bin())
.args(["run", "--example", "basic", "--quiet"])
.output()
.expect("failed to spawn `cargo run --example basic`");
let stdout = String::from_utf8_lossy(&output.stdout).to_string();
let code = output.status.code().unwrap_or(-1);
(stdout, code)
}
fn first_json_line(stdout: &str) -> sonic_rs::Value {
for line in stdout.lines() {
let trimmed = line.trim();
if !trimmed.starts_with('{') {
continue;
}
if let Ok(parsed) = sonic_rs::from_str::<sonic_rs::Value>(trimmed) {
return parsed;
}
}
panic!("no JSON object line found in example stdout:\n{stdout}");
}
#[test]
fn default_emit_writes_bare_json_to_stdout() {
let (stdout, code) = run_basic_example();
assert_eq!(code, 0, "example exited non-zero; stdout:\n{stdout}");
let parsed = first_json_line(&stdout);
assert!(
parsed.is_object(),
"top-level stdout line is not a JSON object — looks like a tracing envelope:\n{stdout}"
);
assert_eq!(parsed["service"]["name"], "example-service");
assert_eq!(parsed["service"]["version"], "1.0.0");
assert_eq!(parsed["requests"], 1);
}
#[test]
fn default_emit_line_has_no_tracing_envelope_prefix() {
let (stdout, _) = run_basic_example();
let line = stdout
.lines()
.find(|l| l.trim_start().starts_with("{\"service\":"))
.expect("no line starting with `{\"service\":...` in stdout:\n{stdout}");
assert!(
!line.contains("event="),
"stdout line contains `event=` — looks like a tracing event, not a bare JSON line:\n{line}"
);
}
#[test]
fn default_emit_writes_log_entries_and_event_metadata() {
let (stdout, code) = run_basic_example();
assert_eq!(code, 0, "example exited non-zero; stdout:\n{stdout}");
let parsed = first_json_line(&stdout);
let log = parsed["log"].as_array().expect("log array missing");
assert_eq!(log.len(), 2, "expected 2 log entries, got {log:?}");
assert_eq!(log[0]["level"], "info");
assert_eq!(log[0]["message"], "request received");
assert_eq!(log[1]["level"], "warn");
assert_eq!(log[1]["message"], "upstream slow");
let timestamp = parsed["event"]["timestamp"].as_str().unwrap_or("");
assert!(!timestamp.is_empty(), "event.timestamp is empty");
assert!(
timestamp.contains('T'),
"timestamp not RFC 3339: {timestamp}"
);
let id = parsed["event"]["id"].as_str().unwrap_or("");
assert!(!id.is_empty(), "event.id is empty");
assert!(
parsed["duration"]["total_ms"].is_number(),
"duration.total_ms missing or not a number"
);
}
#[test]
fn dropped_events_counter_is_loadable() {
let _ = wide_log::stdout_emit::dropped_events();
}