#![allow(unused_imports)]
use super::helpers::AftProcess;
use serde_json::Value;
use std::time::{Duration, Instant};
#[test]
#[cfg(target_os = "windows")]
fn windows_bash_echo_completes_quickly() {
let mut aft = AftProcess::spawn();
let started = Instant::now();
let frames = aft.send_until(
r#"{"id":"win-bash-1","method":"bash","params":{"command":"Write-Output hello"}}"#,
|value| value["id"] == "win-bash-1",
);
let elapsed = started.elapsed();
let response = frames
.iter()
.find(|frame| frame["id"] == "win-bash-1")
.expect("expected response for win-bash-1");
assert_eq!(response["success"], true, "bash command should succeed");
assert!(
elapsed < Duration::from_secs(15),
"trivial echo took {}ms — investigate Windows bash spawn overhead",
elapsed.as_millis()
);
}
#[test]
#[cfg(target_os = "windows")]
fn windows_bash_handles_powershell_pipe() {
let mut aft = AftProcess::spawn();
let frames = aft.send_until(
r#"{"id":"win-pipe","method":"bash","params":{"command":"Write-Output hello | Select-String hello"}}"#,
|value| value["id"] == "win-pipe",
);
let response = frames
.iter()
.find(|frame| frame["id"] == "win-pipe")
.expect("expected response for win-pipe");
assert_eq!(response["success"], true);
let output = response["data"]["output"].as_str().unwrap_or_default();
assert!(
output.contains("hello"),
"expected pipe output to contain 'hello', got: {output}"
);
}
#[test]
#[ignore]
#[cfg(target_os = "windows")]
fn windows_bash_30s_sleep_completes_under_transport_budget() {
let mut aft = AftProcess::spawn();
let started = Instant::now();
let frames = aft.send_until(
r#"{"id":"win-sleep-30","method":"bash","params":{"command":"Start-Sleep -Seconds 30; Write-Output done","timeout":60000}}"#,
|value| value["id"] == "win-sleep-30",
);
let elapsed = started.elapsed();
let response = frames
.iter()
.find(|frame| frame["id"] == "win-sleep-30")
.expect("expected response for win-sleep-30");
assert_eq!(
response["success"], true,
"30s sleep with 60s user-timeout must complete (transport budget = 65s)"
);
assert!(
elapsed < Duration::from_secs(50),
"30s sleep took {}s round-trip — Windows spawn overhead is dangerous",
elapsed.as_secs()
);
}
#[test]
#[cfg(target_os = "windows")]
fn windows_bash_blocks_path_env_case_insensitively() {
let mut aft = AftProcess::spawn();
let frames = aft.send_until(
r#"{"id":"win-env-block","method":"bash","params":{"command":"Write-Output ok","env":{"path":"C:\\evil"}}}"#,
|value| value["id"] == "win-env-block",
);
let response = frames
.iter()
.find(|frame| frame["id"] == "win-env-block")
.expect("expected response for win-env-block");
if response["success"] == true {
let stringified = response.to_string();
assert!(
stringified.to_lowercase().contains("path")
|| stringified.to_lowercase().contains("blocked"),
"expected blocked env var to surface in response: {stringified}"
);
} else {
let message = response["message"].as_str().unwrap_or_default();
assert!(
message.to_lowercase().contains("path") || message.to_lowercase().contains("blocked"),
"expected error message to mention blocked env var, got: {message}"
);
}
}
#[test]
#[cfg(not(target_os = "windows"))]
fn windows_bash_tests_skipped_on_non_windows() {
}