tests(warm_pool): seed a real agent so upsert actually writes the row
ci / gates (push) Successful in 7s
ci / frontend (push) Successful in 24s
ci / publish (push) Successful in 2m20s
ci / rust (push) Successful in 3m41s
ci / e2e (push) Failing after 15s

Root cause of the "reuse must not drain the pool" flake: the test called
`manager.exec(AgentId::new(), ...)` with a random UUID that had no agents
row. `agent_containers::upsert` uses `INSERT ... FROM agents WHERE a.id = $1`,
which silently inserts zero rows when no agent matches — so the "assigned"
sandbox never persisted to the DB. The next exec's reuse lookup returned
None, fell through to the provision branch, and popped from the warm pool
instead of reusing the assigned sandbox. When the warmer hadn't refilled by
the time we asserted, pool_size == 1 instead of 2.

Seed a workspace + owner + agent up front (mirrors soak.rs's setup). Now
upsert commits a real row, the second exec hits the reuse branch, and the
pool stays whole — the test asserts what its name claims.

The tolerant-health-check change in cm-runtime (15cffba) stays as a
defensive improvement for prod under docker daemon load, but the real fix
for the test is here.
This commit is contained in:
Omar Sobh
2026-07-05 19:12:13 -07:00
parent 04f8302871
commit 696d8237fe
+45 -2
View File
@@ -6,9 +6,12 @@ use std::process::Command;
use std::sync::Arc; use std::sync::Arc;
use std::time::Duration; use std::time::Duration;
use cm_domain::AgentId; use cm_domain::{
AccessPolicy, Agent, AgentId, AgentStatus, Role, User, UserId, Workspace, WorkspaceId,
};
use cm_runtime::SandboxManager; use cm_runtime::SandboxManager;
use cm_sandbox::DockerDriver; use cm_sandbox::DockerDriver;
use sqlx::PgPool;
const IMAGE: &str = "clawmates/agent-base:dev"; const IMAGE: &str = "clawmates/agent-base:dev";
@@ -49,19 +52,59 @@ async fn pool_reaches(manager: &SandboxManager, target: usize) {
); );
} }
/// Inserts a workspace + owner user + agent so that
/// `agent_containers::upsert(agent, ...)` (which uses INSERT ... FROM agents
/// WHERE a.id = $1) actually persists a row. Without this seeding the upsert
/// silently inserts zero rows, the next exec's reuse lookup returns None,
/// and the "assigned" sandbox is re-provisioned from the warm pool —
/// draining it and racing the warmer's refill (this test's classic flake).
async fn seed_agent(pool: &PgPool) -> AgentId {
let ws = Workspace {
id: WorkspaceId::new(),
name: "WarmPool".into(),
plan: "team".into(),
};
cm_db::repo::workspaces::insert(pool, &ws).await.unwrap();
let owner = User {
id: UserId::new(),
workspace_id: ws.id,
email: format!("{}@warmpool.test", UserId::new()),
role: Role::Owner,
display_name: "Owner".into(),
created_at: time::OffsetDateTime::UNIX_EPOCH,
};
cm_db::repo::users::insert(pool, &owner).await.unwrap();
let agent = Agent {
id: AgentId::new(),
workspace_id: ws.id,
name: "Warm".into(),
job_title: "Analyst".into(),
system_prompt: String::new(),
avatar: String::new(),
accent: String::new(),
wallpaper: String::new(),
managed_by: owner.id,
status: AgentStatus::Online,
};
cm_db::repo::agents::insert(pool, &agent, &AccessPolicy::default())
.await
.unwrap();
agent.id
}
#[tokio::test] #[tokio::test]
async fn the_pool_prefills_assigns_and_refills() { async fn the_pool_prefills_assigns_and_refills() {
ensure_image(); ensure_image();
let driver: Arc<dyn cm_sandbox::SandboxDriver> = let driver: Arc<dyn cm_sandbox::SandboxDriver> =
Arc::new(DockerDriver::connect().expect("docker reachable")); Arc::new(DockerDriver::connect().expect("docker reachable"));
let pool = cm_testkit::test_pool().await; let pool = cm_testkit::test_pool().await;
let agent = seed_agent(&pool).await;
let manager = Arc::new(SandboxManager::new(driver, pool, "local", IMAGE)).warm(2); let manager = Arc::new(SandboxManager::new(driver, pool, "local", IMAGE)).warm(2);
// The warmer fills the pool without any exec happening. // The warmer fills the pool without any exec happening.
pool_reaches(&manager, 2).await; pool_reaches(&manager, 2).await;
// An exec is served from the pool — and works. // An exec is served from the pool — and works.
let agent = AgentId::new();
let result = manager.exec(agent, "id -u").await.unwrap(); let result = manager.exec(agent, "id -u").await.unwrap();
assert_eq!(result.stdout.trim(), "10001"); assert_eq!(result.stdout.trim(), "10001");