mirror of
https://github.com/fabro-sh/fabro.git
synced 2026-09-12 23:02:41 +00:00
Fix slow unit tests (>5s) by removing unnecessary production delays
- doctor_no_color test: add --dry-run flag to skip live network probes (11s -> <1s) - retry tests: set retry_policy=linear for 500ms delay instead of 5s default backoff - cli_backend tests: make poll_interval configurable on AgentCliBackend, use 10ms in tests - doctor TOML fixtures: remove status.code=1 now that dry-run doctor exits 0 Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
1b3d3d900b
commit
cb21dc8096
6 changed files with 49 additions and 20 deletions
|
|
@ -352,7 +352,7 @@ fn serve_help() {
|
|||
#[test]
|
||||
fn doctor_no_color_when_no_color_set() {
|
||||
arc()
|
||||
.args(["doctor"])
|
||||
.args(["doctor", "--dry-run"])
|
||||
.env_clear()
|
||||
.env("NO_COLOR", "1")
|
||||
.assert()
|
||||
|
|
|
|||
|
|
@ -1,6 +1,5 @@
|
|||
bin.name = "fabro"
|
||||
args = ["doctor", "--dry-run"]
|
||||
status.code = 1
|
||||
|
||||
[env]
|
||||
inherit = false
|
||||
|
|
|
|||
|
|
@ -1,6 +1,5 @@
|
|||
bin.name = "fabro"
|
||||
args = ["doctor"]
|
||||
status.code = 1
|
||||
|
||||
[env]
|
||||
inherit = false
|
||||
|
|
|
|||
|
|
@ -1,6 +1,5 @@
|
|||
bin.name = "fabro"
|
||||
args = ["doctor", "-v"]
|
||||
status.code = 1
|
||||
|
||||
[env]
|
||||
inherit = false
|
||||
|
|
|
|||
|
|
@ -364,6 +364,7 @@ pub struct AgentCliBackend {
|
|||
model: String,
|
||||
provider: Provider,
|
||||
env: HashMap<String, String>,
|
||||
poll_interval: std::time::Duration,
|
||||
}
|
||||
|
||||
impl AgentCliBackend {
|
||||
|
|
@ -373,6 +374,7 @@ impl AgentCliBackend {
|
|||
model,
|
||||
provider,
|
||||
env: HashMap::new(),
|
||||
poll_interval: std::time::Duration::from_secs(5),
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -382,6 +384,12 @@ impl AgentCliBackend {
|
|||
self
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
pub fn with_poll_interval(mut self, interval: std::time::Duration) -> Self {
|
||||
self.poll_interval = interval;
|
||||
self
|
||||
}
|
||||
|
||||
/// Detect changed files by comparing git state before and after the CLI run.
|
||||
async fn detect_changed_files(&self, sandbox: &Arc<dyn Sandbox>) -> Vec<String> {
|
||||
// Get unstaged changes
|
||||
|
|
@ -568,7 +576,7 @@ impl CodergenBackend for AgentCliBackend {
|
|||
// 3c. Poll for completion
|
||||
let poll_command =
|
||||
format!("[ -f {exit_code_path} ] && cat {exit_code_path} || echo running");
|
||||
let poll_interval = std::time::Duration::from_secs(5);
|
||||
let poll_interval = self.poll_interval;
|
||||
let exit_code: i32 = loop {
|
||||
tokio::time::sleep(poll_interval).await;
|
||||
emitter.touch(); // keep the stall watchdog alive while polling
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
use std::collections::VecDeque;
|
||||
use std::path::Path;
|
||||
use std::sync::Arc;
|
||||
use std::time::Duration;
|
||||
|
||||
use fabro_llm::provider::Provider;
|
||||
use fabro_workflows::checkpoint::Checkpoint;
|
||||
|
|
@ -1002,6 +1003,10 @@ async fn retry_on_failure_then_succeed() {
|
|||
retry_node
|
||||
.attrs
|
||||
.insert("max_retries".to_string(), AttrValue::Integer(3));
|
||||
retry_node.attrs.insert(
|
||||
"retry_policy".to_string(),
|
||||
AttrValue::String("linear".to_string()),
|
||||
);
|
||||
graph.nodes.insert("work".to_string(), retry_node);
|
||||
|
||||
graph.edges.push(Edge::new("start", "work"));
|
||||
|
|
@ -2537,6 +2542,10 @@ async fn scenario_node_retries_on_retry_status() {
|
|||
flaky
|
||||
.attrs
|
||||
.insert("max_retries".to_string(), AttrValue::Integer(2));
|
||||
flaky.attrs.insert(
|
||||
"retry_policy".to_string(),
|
||||
AttrValue::String("linear".to_string()),
|
||||
);
|
||||
graph.nodes.insert("flaky".to_string(), flaky);
|
||||
graph.edges.push(Edge::new("start", "flaky"));
|
||||
graph.edges.push(Edge::new("flaky", "exit"));
|
||||
|
|
@ -9557,7 +9566,8 @@ async fn cli_backend_run_writes_prompt_and_calls_exec() {
|
|||
let claude_output = r#"{"type":"result","result":"I fixed the bug.","usage":{"input_tokens":500,"output_tokens":200}}"#;
|
||||
let test_env = Arc::new(CliTestEnv::new(claude_output));
|
||||
let env: Arc<dyn fabro_agent::Sandbox> = test_env.clone();
|
||||
let backend = AgentCliBackend::new("claude-opus-4-6".into(), Provider::Anthropic);
|
||||
let backend = AgentCliBackend::new("claude-opus-4-6".into(), Provider::Anthropic)
|
||||
.with_poll_interval(Duration::from_millis(10));
|
||||
|
||||
let node = Node::new("fix_code");
|
||||
let context = Context::new();
|
||||
|
|
@ -9630,7 +9640,8 @@ async fn cli_backend_run_detects_changed_files() {
|
|||
let claude_output = r#"{"type":"result","result":"Created new file.","usage":{"input_tokens":100,"output_tokens":50}}"#;
|
||||
let env: Arc<dyn fabro_agent::Sandbox> =
|
||||
Arc::new(CliTestEnv::new(claude_output).with_git_diff_after("src/main.rs\nsrc/lib.rs\n"));
|
||||
let backend = AgentCliBackend::new("claude-opus-4-6".into(), Provider::Anthropic);
|
||||
let backend = AgentCliBackend::new("claude-opus-4-6".into(), Provider::Anthropic)
|
||||
.with_poll_interval(Duration::from_millis(10));
|
||||
|
||||
let node = Node::new("implement");
|
||||
let context = Context::new();
|
||||
|
|
@ -9664,7 +9675,8 @@ async fn cli_backend_run_with_codex_provider() {
|
|||
let codex_output = "{\"type\":\"item.completed\",\"item\":{\"id\":\"item_0\",\"type\":\"agent_message\",\"text\":\"Implemented the feature.\"}}\n{\"type\":\"turn.completed\",\"usage\":{\"input_tokens\":300,\"output_tokens\":150}}";
|
||||
let test_env = Arc::new(CliTestEnv::new(codex_output));
|
||||
let env: Arc<dyn fabro_agent::Sandbox> = test_env.clone();
|
||||
let backend = AgentCliBackend::new("gpt-5.3-codex".into(), Provider::OpenAi);
|
||||
let backend = AgentCliBackend::new("gpt-5.3-codex".into(), Provider::OpenAi)
|
||||
.with_poll_interval(Duration::from_millis(10));
|
||||
|
||||
let node = Node::new("implement");
|
||||
let context = Context::new();
|
||||
|
|
@ -9830,7 +9842,8 @@ async fn cli_backend_run_fails_on_nonzero_exit() {
|
|||
}
|
||||
|
||||
let failing_env: Arc<dyn fabro_agent::Sandbox> = Arc::new(FailingCliEnv);
|
||||
let backend = AgentCliBackend::new("claude-opus-4-6".into(), Provider::Anthropic);
|
||||
let backend = AgentCliBackend::new("claude-opus-4-6".into(), Provider::Anthropic)
|
||||
.with_poll_interval(Duration::from_millis(10));
|
||||
let node = Node::new("step");
|
||||
let context = Context::new();
|
||||
let emitter = Arc::new(EventEmitter::new());
|
||||
|
|
@ -9869,7 +9882,8 @@ async fn cli_backend_run_fails_on_nonzero_exit() {
|
|||
#[tokio::test]
|
||||
async fn cli_backend_run_fails_on_unparseable_output() {
|
||||
let env: Arc<dyn fabro_agent::Sandbox> = Arc::new(CliTestEnv::new("this is not json at all"));
|
||||
let backend = AgentCliBackend::new("claude-opus-4-6".into(), Provider::Anthropic);
|
||||
let backend = AgentCliBackend::new("claude-opus-4-6".into(), Provider::Anthropic)
|
||||
.with_poll_interval(Duration::from_millis(10));
|
||||
|
||||
let node = Node::new("step");
|
||||
let context = Context::new();
|
||||
|
|
@ -9906,7 +9920,8 @@ async fn cli_backend_run_uses_node_model_override() {
|
|||
r#"{"type":"result","result":"ok","usage":{"input_tokens":10,"output_tokens":5}}"#;
|
||||
let test_env = Arc::new(CliTestEnv::new(claude_output));
|
||||
let env: Arc<dyn fabro_agent::Sandbox> = test_env.clone();
|
||||
let backend = AgentCliBackend::new("default-model".into(), Provider::Anthropic);
|
||||
let backend = AgentCliBackend::new("default-model".into(), Provider::Anthropic)
|
||||
.with_poll_interval(Duration::from_millis(10));
|
||||
|
||||
let mut node = Node::new("step");
|
||||
node.attrs.insert(
|
||||
|
|
@ -9952,7 +9967,8 @@ async fn cli_backend_run_uses_node_provider_override() {
|
|||
let codex_output = "{\"type\":\"item.completed\",\"item\":{\"id\":\"item_0\",\"type\":\"agent_message\",\"text\":\"ok\"}}\n{\"type\":\"turn.completed\",\"usage\":{\"input_tokens\":10,\"output_tokens\":5}}";
|
||||
let test_env = Arc::new(CliTestEnv::new(codex_output));
|
||||
let env: Arc<dyn fabro_agent::Sandbox> = test_env.clone();
|
||||
let backend = AgentCliBackend::new("default-model".into(), Provider::Anthropic);
|
||||
let backend = AgentCliBackend::new("default-model".into(), Provider::Anthropic)
|
||||
.with_poll_interval(Duration::from_millis(10));
|
||||
|
||||
let mut node = Node::new("step");
|
||||
node.attrs.insert(
|
||||
|
|
@ -9995,7 +10011,8 @@ async fn cli_backend_run_writes_provider_used_json() {
|
|||
let claude_output =
|
||||
r#"{"type":"result","result":"done","usage":{"input_tokens":10,"output_tokens":5}}"#;
|
||||
let env: Arc<dyn fabro_agent::Sandbox> = Arc::new(CliTestEnv::new(claude_output));
|
||||
let backend = AgentCliBackend::new("claude-opus-4-6".into(), Provider::Anthropic);
|
||||
let backend = AgentCliBackend::new("claude-opus-4-6".into(), Provider::Anthropic)
|
||||
.with_poll_interval(Duration::from_millis(10));
|
||||
|
||||
let node = Node::new("step");
|
||||
let context = Context::new();
|
||||
|
|
@ -10037,7 +10054,8 @@ async fn backend_router_delegates_to_cli_for_cli_node() {
|
|||
let env: Arc<dyn fabro_agent::Sandbox> = Arc::new(CliTestEnv::new(claude_output));
|
||||
|
||||
let api_backend = Box::new(MockCodergenBackend); // would return "Response for ..."
|
||||
let cli = AgentCliBackend::new("claude-opus-4-6".into(), Provider::Anthropic);
|
||||
let cli = AgentCliBackend::new("claude-opus-4-6".into(), Provider::Anthropic)
|
||||
.with_poll_interval(Duration::from_millis(10));
|
||||
let router = BackendRouter::new(api_backend, cli);
|
||||
|
||||
let mut node = Node::new("cli_step");
|
||||
|
|
@ -10082,7 +10100,8 @@ async fn backend_router_delegates_to_api_for_normal_node() {
|
|||
let env = local_env();
|
||||
|
||||
let api_backend = Box::new(MockCodergenBackend);
|
||||
let cli = AgentCliBackend::new("claude-opus-4-6".into(), Provider::Anthropic);
|
||||
let cli = AgentCliBackend::new("claude-opus-4-6".into(), Provider::Anthropic)
|
||||
.with_poll_interval(Duration::from_millis(10));
|
||||
let router = BackendRouter::new(api_backend, cli);
|
||||
|
||||
let mut node = Node::new("api_step");
|
||||
|
|
@ -10126,7 +10145,8 @@ async fn backend_router_delegates_to_cli_for_backend_attr() {
|
|||
let env: Arc<dyn fabro_agent::Sandbox> = Arc::new(CliTestEnv::new(codex_output));
|
||||
|
||||
let api_backend = Box::new(MockCodergenBackend);
|
||||
let cli = AgentCliBackend::new("gpt-5.3-codex".into(), Provider::OpenAi);
|
||||
let cli = AgentCliBackend::new("gpt-5.3-codex".into(), Provider::OpenAi)
|
||||
.with_poll_interval(Duration::from_millis(10));
|
||||
let router = BackendRouter::new(api_backend, cli);
|
||||
|
||||
let mut node = Node::new("codex_step");
|
||||
|
|
@ -10220,7 +10240,8 @@ async fn full_pipeline_with_cli_backend_node() {
|
|||
|
||||
// Build engine with BackendRouter
|
||||
let api = MockCodergenBackend;
|
||||
let cli = AgentCliBackend::new("claude-opus-4-6".into(), Provider::Anthropic);
|
||||
let cli = AgentCliBackend::new("claude-opus-4-6".into(), Provider::Anthropic)
|
||||
.with_poll_interval(Duration::from_millis(10));
|
||||
let router = BackendRouter::new(Box::new(api), cli);
|
||||
let codergen_handler = AgentHandler::new(Some(Box::new(router)));
|
||||
|
||||
|
|
@ -10232,7 +10253,8 @@ async fn full_pipeline_with_cli_backend_node() {
|
|||
Box::new(AgentHandler::new(Some(Box::new({
|
||||
// Second BackendRouter for the "agent" handler
|
||||
let api2 = MockCodergenBackend;
|
||||
let cli2 = AgentCliBackend::new("claude-opus-4-6".into(), Provider::Anthropic);
|
||||
let cli2 = AgentCliBackend::new("claude-opus-4-6".into(), Provider::Anthropic)
|
||||
.with_poll_interval(Duration::from_millis(10));
|
||||
BackendRouter::new(Box::new(api2), cli2)
|
||||
})))),
|
||||
);
|
||||
|
|
@ -10358,14 +10380,16 @@ async fn stylesheet_backend_property_routes_to_cli() {
|
|||
|
||||
// Run the pipeline
|
||||
let api = MockCodergenBackend;
|
||||
let cli = AgentCliBackend::new("claude-opus-4-6".into(), Provider::Anthropic);
|
||||
let cli = AgentCliBackend::new("claude-opus-4-6".into(), Provider::Anthropic)
|
||||
.with_poll_interval(Duration::from_millis(10));
|
||||
let router = BackendRouter::new(Box::new(api), cli);
|
||||
|
||||
let mut registry = HandlerRegistry::new(Box::new(AgentHandler::new(Some(Box::new(router)))));
|
||||
registry.register("start", Box::new(StartHandler));
|
||||
registry.register("exit", Box::new(ExitHandler));
|
||||
let api2 = MockCodergenBackend;
|
||||
let cli2 = AgentCliBackend::new("claude-opus-4-6".into(), Provider::Anthropic);
|
||||
let cli2 = AgentCliBackend::new("claude-opus-4-6".into(), Provider::Anthropic)
|
||||
.with_poll_interval(Duration::from_millis(10));
|
||||
let router2 = BackendRouter::new(Box::new(api2), cli2);
|
||||
registry.register(
|
||||
"agent",
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue