//! Integration tests for the `runprobe` command. use std::fs; use assert_cmd::Command; use predicates::prelude::*; use tempfile::TempDir; fn cargo_command() -> Command { Command::cargo_bin("runprobe").expect("binary") } #[cfg(windows)] fn pwsh_success_args() -> Vec<&'static str> { vec!["Write-Output", "done"] } #[test] fn help_mentions_shell_tail_and_log_dir_flags() { let mut command = cargo_command(); command .arg("--help") .assert() .success() .stdout(predicate::str::contains("--shell ")) .stdout(predicate::str::contains("--tail-bytes ")) .stdout(predicate::str::contains("--log-dir ")); } #[cfg(windows)] #[test] fn json_output_reports_shell_run_and_cwd() { let temp = TempDir::new().expect("temp dir"); let mut command = cargo_command(); command .arg("--json") .arg("--shell") .arg("pwsh") .arg("--cwd") .arg(temp.path()) .arg("--") .args(pwsh_success_args()) .assert() .success() .stdout(predicate::str::contains("\"ok\":true")) .stdout(predicate::str::contains("\"exit_code\":0")) .stdout(predicate::str::contains("\"timed_out\":false")) .stdout(predicate::str::contains("\"stdout_tail\":\"done")) .stdout(predicate::str::contains(format!( "\"cwd\":\"{}\"", temp.path().display().to_string().replace('\\', "\\\\") ))); } #[cfg(windows)] #[test] fn failure_text_includes_stdout_and_stderr_tails() { let temp = TempDir::new().expect("temp dir"); let script = temp.path().join("fail.ps1"); fs::write(&script, "Write-Error 'boom'\nWrite-Output 'out'\nexit 9\n").expect("script"); let mut command = cargo_command(); command .arg("--shell") .arg("pwsh") .arg("--tail-bytes") .arg("32") .arg("--") .arg(script) .assert() .success() .stdout(predicate::str::contains("fail exit_code=9")) .stdout(predicate::str::contains("stderr_tail:")) .stdout(predicate::str::contains("boom")) .stdout(predicate::str::contains("stdout_tail:")) .stdout(predicate::str::contains("out")); } #[cfg(windows)] #[test] fn timeout_json_reports_log_path_when_requested() { let log_dir = TempDir::new().expect("log dir"); let script_dir = TempDir::new().expect("script dir"); let script = script_dir.path().join("slow.ps1"); fs::write( &script, "Start-Sleep -Milliseconds 500\nWrite-Output 'late'\n", ) .expect("script"); let mut command = cargo_command(); let assert = command .arg("--json") .arg("--shell") .arg("pwsh") .arg("--timeout") .arg("100ms") .arg("--log-dir") .arg(log_dir.path()) .arg("--") .arg(script) .assert() .success() .stdout(predicate::str::contains("\"timed_out\":true")) .stdout(predicate::str::contains("\"log_path\":\"")); let output = String::from_utf8(assert.get_output().stdout.clone()).expect("utf8 stdout"); let json: serde_json::Value = serde_json::from_str(&output).expect("json"); let log_path = json["log_path"].as_str().expect("log path"); let log_body = fs::read_to_string(log_path).expect("log body"); assert!(log_body.contains("[stdout]")); assert!(log_body.contains("[stderr]")); } #[cfg(windows)] #[test] fn raw_shell_runs_native_command_directly() { let mut command = cargo_command(); command .arg("--json") .arg("--") .arg("pwsh") .arg("-NoProfile") .arg("-Command") .arg("Write-Output raw-ok") .assert() .success() .stdout(predicate::str::contains("\"ok\":true")) .stdout(predicate::str::contains("\"stdout_tail\":\"raw-ok")); } #[cfg(windows)] #[test] fn cmd_shell_runs_command_through_wrapper() { let mut command = cargo_command(); command .arg("--json") .arg("--shell") .arg("cmd") .arg("--") .arg("cmd") .arg("/d") .arg("/s") .arg("/c") .arg("echo cmd-ok") .assert() .success() .stdout(predicate::str::contains("\"ok\":true")) .stdout(predicate::str::contains("\"stdout_tail\":\"cmd-ok")); }