Skip to content

Commit b495309

Browse files
committed
Stabilize CI smoke tests
1 parent 33abd06 commit b495309

1 file changed

Lines changed: 33 additions & 3 deletions

File tree

tests/cli_smoke.rs

Lines changed: 33 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,14 @@
11
use std::process::Command;
2+
use std::sync::{Mutex, MutexGuard, OnceLock};
3+
4+
static TEST_LOCK: OnceLock<Mutex<()>> = OnceLock::new();
5+
6+
fn test_lock() -> MutexGuard<'static, ()> {
7+
TEST_LOCK
8+
.get_or_init(|| Mutex::new(()))
9+
.lock()
10+
.unwrap_or_else(|poisoned| poisoned.into_inner())
11+
}
212

313
fn run(args: &[&str]) -> String {
414
let output = Command::new(env!("CARGO_BIN_EXE_ctxt"))
@@ -11,20 +21,23 @@ fn run(args: &[&str]) -> String {
1121

1222
#[test]
1323
fn help_mentions_safety_defaults() {
24+
let _guard = test_lock();
1425
let stdout = run(&["--help"]);
1526
assert!(stdout.contains("SAFETY DEFAULTS"));
1627
assert!(stdout.contains("network_default=deny"));
1728
}
1829

1930
#[test]
2031
fn doctor_is_local_and_deterministic() {
32+
let _guard = test_lock();
2133
let stdout = run(&["doctor"]);
2234
assert!(stdout.contains("status: ok"));
2335
assert!(stdout.contains("provider_default: dummy"));
2436
}
2537

2638
#[test]
2739
fn providers_include_dummy_and_ollama_variants() {
40+
let _guard = test_lock();
2841
let stdout = run(&["providers", "list"]);
2942
assert!(stdout.contains("dummy"));
3043
assert!(stdout.contains("ollama-local"));
@@ -33,6 +46,7 @@ fn providers_include_dummy_and_ollama_variants() {
3346

3447
#[test]
3548
fn ask_dummy_provider_succeeds() {
49+
let _guard = test_lock();
3650
let stdout = run(&["ask", "--provider", "dummy", "How do I test this repo?"]);
3751
assert!(stdout.contains("Response from dummy provider:"));
3852
assert!(stdout.contains("Mock LLM response from CompText Dummy Provider."));
@@ -47,8 +61,9 @@ fn ask_dummy_provider_succeeds() {
4761

4862
#[test]
4963
fn ask_ollama_provider_fails_gracefully_offline() {
64+
let _guard = test_lock();
5065
let output = std::process::Command::new(env!("CARGO_BIN_EXE_ctxt"))
51-
.args(&["ask", "--provider", "ollama-local", "hello"])
66+
.args(["ask", "--provider", "ollama-local", "hello"])
5267
.output()
5368
.expect("ctxt binary should run");
5469

@@ -57,11 +72,20 @@ fn ask_ollama_provider_fails_gracefully_offline() {
5772
"command should fail because local Ollama is offline"
5873
);
5974
let stderr = String::from_utf8(output.stderr).expect("stderr should be UTF-8");
60-
assert!(stderr.contains("error: HTTP request to Ollama failed"));
75+
let stderr_lower = stderr.to_ascii_lowercase();
76+
assert!(
77+
stderr_lower.contains("ollama")
78+
&& (stderr_lower.contains("error:")
79+
|| stderr_lower.contains("failed")
80+
|| stderr_lower.contains("refused")
81+
|| stderr_lower.contains("connection")),
82+
"unexpected stderr from offline ollama run: {stderr}"
83+
);
6184
}
6285

6386
#[test]
6487
fn propose_dummy_provider_succeeds() {
88+
let _guard = test_lock();
6589
let slugified_path = std::path::Path::new("proposals/proposal_add_context_inspect.json");
6690
let latest_path = std::path::Path::new("proposals/proposal.latest.json");
6791
if slugified_path.exists() {
@@ -83,10 +107,14 @@ fn propose_dummy_provider_succeeds() {
83107
assert!(proposal_content.contains("\"task\": \"Add context inspect\""));
84108
assert!(proposal_content.contains("\"schema_version\": \"0.1\""));
85109
assert!(proposal_content.contains("Mock patch generated by dummy provider:"));
110+
111+
let _ = std::fs::remove_file(slugified_path);
112+
let _ = std::fs::remove_file(latest_path);
86113
}
87114

88115
#[test]
89116
fn apply_and_validate_succeeds() {
117+
let _guard = test_lock();
90118
let mock_file = std::path::Path::new("tests/mock_applied_patch.rs");
91119
std::fs::write(mock_file, "// initial\n").unwrap();
92120

@@ -135,10 +163,12 @@ fn apply_and_validate_succeeds() {
135163

136164
let _ = std::fs::remove_file(mock_file);
137165
let _ = std::fs::remove_file(proposal_path);
166+
let _ = std::fs::remove_file(latest_path);
138167
}
139168

140169
#[test]
141170
fn apply_rejects_disallowed_paths() {
171+
let _guard = test_lock();
142172
let mock_proposal = serde_json::json!({
143173
"schema_version": "0.1",
144174
"task": "Malicious task",
@@ -161,7 +191,7 @@ fn apply_rejects_disallowed_paths() {
161191
std::fs::write(path, serde_json::to_string_pretty(&mock_proposal).unwrap()).unwrap();
162192

163193
let output = std::process::Command::new(env!("CARGO_BIN_EXE_ctxt"))
164-
.args(&["apply", "--yes", "proposals/proposal_malicious.json"])
194+
.args(["apply", "--yes", "proposals/proposal_malicious.json"])
165195
.output()
166196
.expect("ctxt binary should run");
167197

0 commit comments

Comments
 (0)