use super::*;
fn profile_trace_from_stderr(stderr: &str) -> Value {
let lines = stderr.lines().collect::<Vec<_>>();
assert_eq!(
lines.len(),
1,
"jsonl profiling should emit exactly one stderr line: {stderr}"
);
serde_json::from_str(lines[0]).expect("profile stderr line should be parseable JSON")
}
fn profile_phase_names(trace: &Value) -> Vec<&str> {
trace["phases"]
.as_array()
.expect("trace should include phases")
.iter()
.map(|phase| {
phase["name"]
.as_str()
.expect("phase should include a string name")
})
.collect()
}
fn assert_profile_trace_is_sanitized(stderr: &str, temp: &TempDir) {
let temp_path = temp.path().display().to_string();
for sensitive in [
temp_path.as_str(),
"sensitive-profile-input.txt",
"HEDDLE_PROFILE",
"jsonl",
"--output",
] {
assert!(
!stderr.contains(sensitive),
"profile trace should not include sensitive input `{sensitive}`: {stderr}"
);
}
}
fn setup_profile_repo_with_sensitive_input() -> TempDir {
let temp = TempDir::new().unwrap();
heddle(&["init"], Some(temp.path())).unwrap();
std::fs::write(temp.path().join("sensitive-profile-input.txt"), "secret").unwrap();
temp
}
fn seed_stale_monitor_endpoint(temp: &TempDir) {
let endpoint = temp.path().join(".heddle/state/monitor-helper.json");
std::fs::create_dir_all(endpoint.parent().expect("monitor state parent")).unwrap();
std::fs::write(
endpoint,
r#"{"version":1,"host":"127.0.0.1","port":9,"pid":null}"#,
)
.unwrap();
}
#[test]
fn perf_trace_jsonl_status_keeps_stdout_json_and_stderr_parseable() {
let temp = setup_profile_repo_with_sensitive_input();
let output = heddle_output_with_env(
&["--output", "json", "status"],
Some(temp.path()),
&[("HEDDLE_PROFILE", "jsonl")],
)
.expect("status should run");
let stdout = std::str::from_utf8(&output.stdout).unwrap();
let stderr = std::str::from_utf8(&output.stderr).unwrap();
assert!(
output.status.success(),
"profiled status should succeed; stdout={stdout} stderr={stderr}"
);
serde_json::from_str::<Value>(stdout).expect("status stdout should remain valid JSON");
let trace = profile_trace_from_stderr(stderr);
assert_eq!(trace["schema"], "heddle-cli-profile/v1");
assert_eq!(trace["command"], "status");
assert_eq!(trace["exit_status"], "ok");
let phases = profile_phase_names(&trace);
for expected in [
"status repo open",
"status current state",
"status worktree status",
"status thread summary",
"status build total",
"status render",
] {
assert!(
phases.contains(&expected),
"trace should include status phase `{expected}`: {trace}"
);
}
assert!(
!phases.contains(&"status phases"),
"jsonl profile should split the old grouped status phase: {trace}"
);
assert_eq!(trace["totals"]["command_body_ms"]["unit"], "milliseconds");
assert_eq!(trace["totals"]["total_ms"]["unit"], "milliseconds");
assert!(
stderr.contains("\"phases\"") && !stderr.contains("heddle profile:"),
"jsonl mode should not emit human profile text: {stderr}"
);
assert_profile_trace_is_sanitized(stderr, &temp);
}
#[test]
fn perf_trace_jsonl_status_reports_structural_counters() {
let temp = setup_profile_repo_with_sensitive_input();
let output = heddle_output_with_env(
&["--output", "json", "status"],
Some(temp.path()),
&[("HEDDLE_PROFILE", "jsonl")],
)
.expect("status should run");
let stderr = std::str::from_utf8(&output.stderr).unwrap();
assert!(
output.status.success(),
"profiled status should succeed: {stderr}"
);
let trace = profile_trace_from_stderr(stderr);
let structural = trace["phases"]
.as_array()
.unwrap()
.iter()
.find(|phase| phase["name"] == "structural counters")
.unwrap_or_else(|| panic!("trace should include structural counters: {trace}"));
let metrics = structural["metrics"].as_object().unwrap();
for name in [
"directories_scanned",
"directories_skipped",
"files_hashed",
"monitor_changed_paths",
"object_decodes",
"ref_reads",
"oplog_reads",
"repository_opens",
"ancestors_visited",
"history_objects_decoded",
] {
assert!(metrics.contains_key(name), "missing `{name}` in {trace}");
}
assert_eq!(
metrics["network_client_initialized"]["value"],
Value::Bool(false),
"local status must report an actual false boolean: {trace}"
);
}
#[test]
fn perf_trace_jsonl_version_reports_startup_totals() {
let temp = TempDir::new().unwrap();
let output = heddle_output_with_env(
&["--version"],
Some(temp.path()),
&[("HEDDLE_PROFILE", "jsonl")],
)
.expect("version should run");
let stderr = std::str::from_utf8(&output.stderr).unwrap();
assert!(
output.status.success(),
"profiled version should succeed: {stderr}"
);
let trace = profile_trace_from_stderr(stderr);
assert_eq!(trace["command"], "version");
assert_eq!(trace["totals"]["total_ms"]["unit"], "milliseconds");
assert_eq!(
trace["phases"]
.as_array()
.unwrap()
.iter()
.find(|phase| phase["name"] == "structural counters")
.unwrap()["metrics"]["network_client_initialized"]["value"],
Value::Bool(false)
);
}
#[test]
fn perf_trace_jsonl_thread_list_uses_named_phase_records() {
let temp = setup_profile_repo_with_sensitive_input();
seed_stale_monitor_endpoint(&temp);
let output = heddle_output_with_env(
&["--output", "json", "thread", "list"],
Some(temp.path()),
&[("HEDDLE_PROFILE", "jsonl")],
)
.expect("thread list should run");
let stdout = std::str::from_utf8(&output.stdout).unwrap();
let stderr = std::str::from_utf8(&output.stderr).unwrap();
assert!(
output.status.success(),
"profiled thread list should succeed; stdout={stdout} stderr={stderr}"
);
serde_json::from_str::<Value>(stdout).expect("thread list stdout should remain valid JSON");
let trace = profile_trace_from_stderr(stderr);
assert_eq!(trace["schema"], "heddle-cli-profile/v1");
assert_eq!(trace["command"], "thread list");
assert_eq!(trace["exit_status"], "ok");
let phases = profile_phase_names(&trace);
for expected in [
"thread list collect summaries",
"thread list verification",
"thread list command body",
] {
assert!(
phases.contains(&expected),
"trace should include thread list phase `{expected}`: {trace}"
);
}
assert!(
!phases.contains(&"thread list phases"),
"jsonl profile should split the old grouped thread list phase: {trace}"
);
assert_profile_trace_is_sanitized(stderr, &temp);
}
#[test]
fn perf_trace_jsonl_verify_uses_named_phase_records() {
let temp = setup_profile_repo_with_sensitive_input();
heddle(&["capture", "-m", "profile input"], Some(temp.path())).unwrap();
seed_stale_monitor_endpoint(&temp);
let output = heddle_output_with_env(
&["--output", "json", "verify"],
Some(temp.path()),
&[("HEDDLE_PROFILE", "jsonl")],
)
.expect("verify should run");
let stdout = std::str::from_utf8(&output.stdout).unwrap();
let stderr = std::str::from_utf8(&output.stderr).unwrap();
assert!(
output.status.success(),
"profiled verify should succeed; stdout={stdout} stderr={stderr}"
);
serde_json::from_str::<Value>(stdout).expect("verify stdout should remain valid JSON");
let trace = profile_trace_from_stderr(stderr);
assert_eq!(trace["schema"], "heddle-cli-profile/v1");
assert_eq!(trace["command"], "verify");
assert_eq!(trace["exit_status"], "ok");
let phases = profile_phase_names(&trace);
for expected in [
"verify plain git probe",
"verify repo open",
"verify repository checks",
"verify command body",
] {
assert!(
phases.contains(&expected),
"trace should include verify phase `{expected}`: {trace}"
);
}
assert!(
!phases.contains(&"verify phases"),
"jsonl profile should split the old grouped verify phase: {trace}"
);
assert_profile_trace_is_sanitized(stderr, &temp);
}
#[test]
fn perf_trace_jsonl_git_overlay_clone_separates_copy_and_state_store_write() {
let temp = TempDir::new().unwrap();
let source = temp.path().join("source");
let destination = temp.path().join("clone");
let git = SleyRepository::init(&source).unwrap();
let tree = git_empty_tree_oid(&git);
git_commit_with_tree(&git, Some("refs/heads/main"), tree, "seed", &[]);
let source_arg = source.to_str().unwrap();
let destination_arg = destination.to_str().unwrap();
let output = heddle_output_with_env(
&["--output", "json", "clone", source_arg, destination_arg],
Some(temp.path()),
&[("HEDDLE_PROFILE", "jsonl")],
)
.expect("profiled Git-overlay clone should run");
let stderr = std::str::from_utf8(&output.stderr).unwrap();
assert!(output.status.success(), "clone should succeed: {stderr}");
let trace = profile_trace_from_stderr(stderr);
let phase = trace["phases"]
.as_array()
.unwrap()
.iter()
.find(|phase| phase["name"] == "git overlay clone phases")
.unwrap_or_else(|| panic!("trace should separate Git copy from Heddle ingest: {trace}"));
let metrics = phase["metrics"].as_object().unwrap();
for name in [
"sley_mirror_copy_ms",
"heddle_ingest_ms",
"state_store_write_ms",
] {
assert!(metrics.contains_key(name), "missing `{name}` in {trace}");
assert_eq!(metrics[name]["unit"], "milliseconds");
}
}
#[test]
fn perf_trace_human_mode_still_writes_profile_text() {
let temp = TempDir::new().unwrap();
heddle(&["init"], Some(temp.path())).unwrap();
let output = heddle_output_with_env(
&["--output", "json", "status"],
Some(temp.path()),
&[("HEDDLE_PROFILE", "1")],
)
.expect("status should run");
let stdout = std::str::from_utf8(&output.stdout).unwrap();
let stderr = std::str::from_utf8(&output.stderr).unwrap();
assert!(
output.status.success(),
"human-profiled status should succeed; stdout={stdout} stderr={stderr}"
);
serde_json::from_str::<Value>(stdout).expect("status stdout should remain valid JSON");
assert!(
stderr.contains("heddle profile:")
&& stderr.contains("command: status phases")
&& stderr.contains("command_body_ms:"),
"human profile output should be preserved on stderr: {stderr}"
);
}