From 0cf825a213838147c2c4462e3d0475b924a142cd Mon Sep 17 00:00:00 2001 From: Alex Mikhalev Date: Mon, 13 Apr 2026 19:19:16 +0200 Subject: [PATCH] fix(tests): make CI tests shallow-clone and server-mode stable Two remaining CI Main Branch failures after #801: 1. orchestrator_tests: git_diff_baseline() fell back to HEAD~1 for the diff baseline, but shallow CI checkouts lack history before HEAD. Now uses git's empty-tree SHA as stable fallback when root commit lookup returns nothing, making test_orchestrator_compound_review_integration, test_git_diff_matching_changes_spawns, and test_spawn_agent_proceeds_with_git_diff_findings reliable across shallow/fetch-depth=0 CI environments. 2. integration_tests: test_end_to_end_server_workflow was selecting the already-active role (* marker) which fails with exit 1. Now selects a different role (non-current) so the switch is always exercised meaningfully. Refs: #801 --- .../tests/integration_tests.rs | 21 ++++++++++++++- .../tests/orchestrator_tests.rs | 27 ++++++++++++------- 2 files changed, 38 insertions(+), 10 deletions(-) diff --git a/crates/terraphim_agent/tests/integration_tests.rs b/crates/terraphim_agent/tests/integration_tests.rs index ab1248310..76aeee5c4 100644 --- a/crates/terraphim_agent/tests/integration_tests.rs +++ b/crates/terraphim_agent/tests/integration_tests.rs @@ -325,7 +325,7 @@ async fn test_end_to_end_server_workflow() -> Result<()> { "Server should have roles available" ); - let selected_role = server_roles + let current_role = server_roles .iter() .find_map(|line| { let trimmed = line.trim(); @@ -342,6 +342,25 @@ async fn test_end_to_end_server_workflow() -> Result<()> { }) .unwrap_or_else(|| "Terraphim Engineer".to_string()); + let selected_role = server_roles + .iter() + .find_map(|line| { + let trimmed = line.trim(); + if trimmed.starts_with('*') { + return None; + } + let role = trimmed + .trim_start_matches('*') + .trim() + .split_once(" (") + .map(|(name, _)| name) + .unwrap_or(trimmed) + .trim() + .to_string(); + (role != current_role).then_some(role) + }) + .unwrap_or_else(|| current_role.clone()); + // 3. Test search with server (may fail in CI due to missing KG data or slow indexing) let (search_stdout, search_stderr, search_code) = run_server_command(&server_url, &["search", "integration test", "--limit", "3"])?; diff --git a/crates/terraphim_orchestrator/tests/orchestrator_tests.rs b/crates/terraphim_orchestrator/tests/orchestrator_tests.rs index c032f7710..b46ca9339 100644 --- a/crates/terraphim_orchestrator/tests/orchestrator_tests.rs +++ b/crates/terraphim_orchestrator/tests/orchestrator_tests.rs @@ -9,15 +9,24 @@ use terraphim_orchestrator::{ }; use uuid::Uuid; -/// Return a deterministic baseline commit for git-diff tests. -/// Uses the repository root commit so tests work in any clone. -fn baseline_commit() -> String { +/// Return a deterministic baseline for git-diff tests. +/// Prefer the repository root commit, but fall back to the empty tree when the +/// checkout is shallow and history before HEAD is unavailable. +fn git_diff_baseline() -> String { let output = std::process::Command::new("git") .args(["rev-list", "--max-parents=0", "HEAD"]) .output() .expect("git rev-list failed"); let commits = String::from_utf8_lossy(&output.stdout); - commits.lines().next().unwrap_or("").trim().to_string() + let baseline = commits.lines().next().unwrap_or("").trim(); + + if baseline.is_empty() { + // Git's well-known empty tree object works as a stable diff baseline + // even when CI checks out a shallow clone without HEAD~1 available. + "4b825dc642cb6eb9a060e54bf8d69288fbee4904".to_string() + } else { + baseline.to_string() + } } fn test_config() -> OrchestratorConfig { @@ -181,7 +190,7 @@ async fn test_orchestrator_compound_review_integration() { }; let workflow = CompoundReviewWorkflow::new(swarm_config); - let result = workflow.run("HEAD", "HEAD~1").await.unwrap(); + let result = workflow.run("HEAD", &git_diff_baseline()).await.unwrap(); assert!( !result.correlation_id.is_nil(), @@ -462,7 +471,7 @@ async fn test_git_diff_matching_changes_spawns() { let mut orch = AgentOrchestrator::new(config).unwrap(); // Seed with initial commit so there ARE changes - let baseline_commit = baseline_commit(); + let baseline_commit = git_diff_baseline(); orch.set_last_run_commit("sentinel", &baseline_commit); let result = orch.spawn_agent_for_test("sentinel").await; @@ -481,7 +490,7 @@ async fn test_git_diff_non_matching_changes_skips() { let mut orch = AgentOrchestrator::new(config).unwrap(); // Seed with initial commit so there ARE changes, but none match the watch path - let baseline_commit = baseline_commit(); + let baseline_commit = git_diff_baseline(); orch.set_last_run_commit("sentinel", &baseline_commit); let result = orch.spawn_agent_for_test("sentinel").await; @@ -608,7 +617,7 @@ async fn test_spawn_agent_skipped_by_git_diff_no_matching() { let mut orch = AgentOrchestrator::new(config).unwrap(); // Seed with initial commit so there are diff results - let baseline_commit = baseline_commit(); + let baseline_commit = git_diff_baseline(); orch.set_last_run_commit("sentinel", &baseline_commit); let result = orch.spawn_agent_for_test("sentinel").await; @@ -628,7 +637,7 @@ async fn test_spawn_agent_proceeds_with_git_diff_findings() { let mut orch = AgentOrchestrator::new(config).unwrap(); // Use initial commit as baseline -> every file is a change - let baseline_commit = baseline_commit(); + let baseline_commit = git_diff_baseline(); orch.set_last_run_commit("sentinel", &baseline_commit); let result = orch.spawn_agent_for_test("sentinel").await;