use std::path::PathBuf;
use std::time::Duration;
use tempfile::NamedTempFile;
use terraphim_spawner::{AgentSpawner, SpawnContext, SpawnRequest};
use terraphim_types::capability::{Capability, Provider, ProviderType};
fn bash_provider(working_dir: PathBuf) -> Provider {
Provider::new(
"@bash-fixture",
"Bash Fixture",
ProviderType::Agent {
agent_id: "@bash-fixture".to_string(),
cli_command: "/bin/bash".to_string(),
working_dir,
},
vec![Capability::CodeGeneration],
)
}
fn fixture_script_path() -> PathBuf {
PathBuf::from(env!("CARGO_MANIFEST_DIR")).join("tests/fixtures/echo_args_env.sh")
}
async fn wait_for_record(path: &std::path::Path) -> String {
let start = std::time::Instant::now();
loop {
if let Ok(contents) = tokio::fs::read_to_string(path).await {
if !contents.is_empty() {
return contents;
}
}
if start.elapsed() > Duration::from_secs(2) {
panic!(
"fixture record file at {} did not become non-empty within 2s",
path.display()
);
}
tokio::time::sleep(Duration::from_millis(20)).await;
}
}
#[tokio::test]
async fn bash_provider_runs_multi_line_task_via_dash_c() {
let record = NamedTempFile::new().expect("create temp record file");
let record_path = record.path().to_path_buf();
let fixture = fixture_script_path();
assert!(
fixture.exists(),
"fixture script missing at {}",
fixture.display()
);
let task_body = format!("set -e\nbash '{}' first second\n", fixture.display(),);
let provider = bash_provider(PathBuf::from("/tmp"));
let request = SpawnRequest::new(provider, &task_body);
let ctx = SpawnContext::global()
.with_env("RECORD_FILE", record_path.to_string_lossy().to_string())
.with_env("ADF_TASK_SUMMARY", "informational summary line")
.with_env("ADF_FIXTURE_MARKER", "marker-value");
let spawner = AgentSpawner::new();
let _handle = spawner
.spawn_with_fallback(&request, ctx)
.await
.expect("spawn must succeed");
let contents = wait_for_record(&record_path).await;
assert!(
contents.contains("argc=2"),
"expected argc=2 (fixture must execute), got: {contents}"
);
assert!(
contents.contains("argv[1]=first"),
"missing first argv: {contents}"
);
assert!(
contents.contains("argv[2]=second"),
"missing second argv: {contents}"
);
}
#[tokio::test]
async fn env_overrides_reach_child_process() {
let record = NamedTempFile::new().expect("create temp record file");
let record_path = record.path().to_path_buf();
let fixture = fixture_script_path();
let task_body = format!("set -e\nbash '{}' no-args\n", fixture.display(),);
let provider = bash_provider(PathBuf::from("/tmp"));
let request = SpawnRequest::new(provider, &task_body);
let ctx = SpawnContext::global()
.with_env("RECORD_FILE", record_path.to_string_lossy().to_string())
.with_env("ADF_TASK_SUMMARY", "Build/test verdict for PR #999")
.with_env("ADF_FIXTURE_MARKER", "marker-value");
let spawner = AgentSpawner::new();
let _handle = spawner
.spawn_with_fallback(&request, ctx)
.await
.expect("spawn must succeed");
let contents = wait_for_record(&record_path).await;
assert!(
contents.contains("ADF_TASK_SUMMARY=Build/test verdict for PR #999"),
"ADF_TASK_SUMMARY env not visible to child, got: {contents}"
);
assert!(
contents.contains("ADF_FIXTURE_MARKER=marker-value"),
"ADF_FIXTURE_MARKER env not visible to child, got: {contents}"
);
}