mirror of
https://github.com/block/buzz.git
synced 2026-10-28 21:11:48 +00:00
test(desktop): exercise lifecycle refusal through configuration catalog
Hold the inherited-oversized agent_discovery.rs at the desktop file-size ratchet base by importing the storage module and qualifying its save sites; no behavior, ceiling, or gate change, so the PR CI paths job stops failing before any native lane starts. desktop-stop.spec.ts still selected the retired "Destination Desktop" combobox, so the smoke case timed out on the configuration-driven UI. Drive the same observable refusal through the current contract: wait for the eligible remote catalog entry, select the exact runtime configuration, assert the destination Start refusal copy, and re-send the identical signed request via Retry same request. Fixture requests are identified by signed event id so launch accounting stays scoped to the start action while status, catalog, and preflight actions share the lifecycle IPC. Signed-off-by: Logan Johnson <loganj@squareup.com>
This commit is contained in:
@@ -505,9 +505,8 @@ async fn restart_single_agent_after_install(
|
||||
managed_agents::{
|
||||
agent_readiness, current_instance_id, find_managed_agent_mut, known_acp_runtime,
|
||||
load_global_agent_config, load_managed_agents, load_personas, record_agent_command,
|
||||
resolve_effective_agent_env, stop_managed_agent_process,
|
||||
storage::save_runtime_metadata_batch, sync_managed_agent_processes, AgentReadiness,
|
||||
BackendKind,
|
||||
resolve_effective_agent_env, stop_managed_agent_process, storage,
|
||||
sync_managed_agent_processes, AgentReadiness, BackendKind,
|
||||
},
|
||||
};
|
||||
use tauri::Manager;
|
||||
@@ -537,7 +536,7 @@ async fn restart_single_agent_after_install(
|
||||
¤t_instance_id(&app_for_stop),
|
||||
);
|
||||
if sync_changed {
|
||||
save_runtime_metadata_batch(&app_for_stop, &records)?;
|
||||
storage::save_runtime_metadata_batch(&app_for_stop, &records)?;
|
||||
}
|
||||
|
||||
// Re-verify eligibility under lock.
|
||||
@@ -591,7 +590,7 @@ async fn restart_single_agent_after_install(
|
||||
// Stop the process.
|
||||
let record_mut = find_managed_agent_mut(&mut records, &pubkey_owned)?;
|
||||
stop_managed_agent_process(&app_for_stop, record_mut, &mut runtimes)?;
|
||||
save_runtime_metadata_batch(&app_for_stop, &records)?;
|
||||
storage::save_runtime_metadata_batch(&app_for_stop, &records)?;
|
||||
|
||||
Ok(runtime_keys)
|
||||
})
|
||||
@@ -645,9 +644,7 @@ fn persist_last_error_on_install(
|
||||
) -> Result<(), String> {
|
||||
use crate::{
|
||||
app_state::AppState,
|
||||
managed_agents::{
|
||||
find_managed_agent_mut, load_managed_agents, storage::save_runtime_metadata_batch,
|
||||
},
|
||||
managed_agents::{find_managed_agent_mut, load_managed_agents, storage},
|
||||
};
|
||||
use tauri::Manager;
|
||||
let state = app.state::<AppState>();
|
||||
@@ -659,7 +656,7 @@ fn persist_last_error_on_install(
|
||||
let record = find_managed_agent_mut(&mut records, pubkey)?;
|
||||
record.last_error = Some(error.to_string());
|
||||
record.updated_at = crate::util::now_iso();
|
||||
save_runtime_metadata_batch(app, &records)
|
||||
storage::save_runtime_metadata_batch(app, &records)
|
||||
}
|
||||
|
||||
/// Build the `-l -c` argument list for the install shell.
|
||||
|
||||
@@ -9,6 +9,8 @@ test("remote Stop distinguishes delivery, uncertainty, and confirmed result", as
|
||||
}) => {
|
||||
test.setTimeout(60_000);
|
||||
const agent = "a7".repeat(32);
|
||||
const remoteDesktop = "22222222-2222-4222-8222-222222222222";
|
||||
const standardRuntime = { id: "standard-runtime", revision: "3" };
|
||||
await installMockBridge(page, {
|
||||
managedAgents: [],
|
||||
relayAgents: [
|
||||
@@ -25,7 +27,7 @@ test("remote Stop distinguishes delivery, uncertainty, and confirmed result", as
|
||||
});
|
||||
await page.goto("/");
|
||||
await expect(page.getByTestId("open-agents-view")).toBeVisible();
|
||||
await page.evaluate(() => {
|
||||
await page.evaluate((configuration: { id: string; revision: string }) => {
|
||||
const w = window as typeof window & {
|
||||
__STOP_FIXTURE__: {
|
||||
confirmed: boolean;
|
||||
@@ -49,6 +51,22 @@ test("remote Stop distinguishes delivery, uncertainty, and confirmed result", as
|
||||
const now = Math.floor(Date.now() / 1000);
|
||||
const local = "11111111-1111-4111-8111-111111111111";
|
||||
const remote = "22222222-2222-4222-8222-222222222222";
|
||||
// The mounted control issues status and catalog actions over the same
|
||||
// lifecycle IPC before any launch. Identify each signed request by its
|
||||
// event id so launch accounting stays scoped to the destination Start.
|
||||
const lifecycleRequests = new Map<
|
||||
string,
|
||||
{ action: string; desktop: string }
|
||||
>();
|
||||
const eligibleCatalogEntry = {
|
||||
configuration,
|
||||
name: "Standard runtime",
|
||||
host: remote,
|
||||
runtime: "acp",
|
||||
model: "claude-opus-4-6",
|
||||
provider: null,
|
||||
eligible: true,
|
||||
};
|
||||
const sign = async (kind: number, tags: string[][] = []) =>
|
||||
JSON.parse(
|
||||
await original("sign_event", {
|
||||
@@ -87,14 +105,44 @@ test("remote Stop distinguishes delivery, uncertainty, and confirmed result", as
|
||||
case "read_desktop_placement":
|
||||
case "receive_desktop_lifecycle":
|
||||
return null;
|
||||
case "prepare_desktop_lifecycle":
|
||||
w.__STOP_FIXTURE__.lifecyclePrepared++;
|
||||
return sign(50182, [
|
||||
case "prepare_desktop_lifecycle": {
|
||||
const request = await sign(50182, [
|
||||
["p", payload.owner],
|
||||
["d", payload.desktop],
|
||||
]);
|
||||
case "read_desktop_lifecycle_results":
|
||||
return "provisioning_unavailable";
|
||||
lifecycleRequests.set(request.id, {
|
||||
action: payload.action,
|
||||
desktop: payload.desktop,
|
||||
});
|
||||
if (payload.action === "start")
|
||||
w.__STOP_FIXTURE__.lifecyclePrepared++;
|
||||
return request;
|
||||
}
|
||||
case "read_desktop_lifecycle_results": {
|
||||
const request = lifecycleRequests.get(payload.request.id);
|
||||
if (request?.action === "preflight")
|
||||
return {
|
||||
outcome: "ready",
|
||||
observation: {
|
||||
valid_until: now + 600,
|
||||
running_configuration: null,
|
||||
catalog: null,
|
||||
},
|
||||
};
|
||||
if (request?.action !== "catalog")
|
||||
return { outcome: "provisioning_unavailable" };
|
||||
return {
|
||||
outcome: "ready",
|
||||
observation: {
|
||||
valid_until: now + 600,
|
||||
running_configuration: null,
|
||||
catalog: {
|
||||
entry: request.desktop === remote ? eligibleCatalogEntry : null,
|
||||
next: null,
|
||||
},
|
||||
},
|
||||
};
|
||||
}
|
||||
case "prepare_desktop_stop":
|
||||
w.__STOP_FIXTURE__.prepared++;
|
||||
return sign(50180, [
|
||||
@@ -109,14 +157,18 @@ test("remote Stop distinguishes delivery, uncertainty, and confirmed result", as
|
||||
const wire = JSON.parse(payload.message.data);
|
||||
if (wire[0] === "EVENT" && wire[1]?.kind === 50180)
|
||||
w.__STOP_FIXTURE__.sends.push(JSON.stringify(wire[1]));
|
||||
if (wire[0] === "EVENT" && wire[1]?.kind === 50182)
|
||||
if (
|
||||
wire[0] === "EVENT" &&
|
||||
wire[1]?.kind === 50182 &&
|
||||
lifecycleRequests.get(wire[1].id)?.action === "start"
|
||||
)
|
||||
w.__STOP_FIXTURE__.lifecycleSends.push(JSON.stringify(wire[1]));
|
||||
break;
|
||||
}
|
||||
}
|
||||
return original(command, payload, options);
|
||||
};
|
||||
});
|
||||
}, standardRuntime);
|
||||
await page.getByTestId("open-agents-view").click();
|
||||
const desktops = page.getByRole("region", { name: "Known Desktops" });
|
||||
await desktops.getByRole("button", { name: "Refresh", exact: true }).click();
|
||||
@@ -184,22 +236,32 @@ test("remote Stop distinguishes delivery, uncertainty, and confirmed result", as
|
||||
path: "test-results/desktop-stop/04-confirmed.png",
|
||||
});
|
||||
|
||||
// The mounted lifecycle selector shares host labels with the Stop rows.
|
||||
// The mounted lifecycle controls share host labels with the Stop rows.
|
||||
// IPC explicitly refuses launch; no native process is created by this fixture.
|
||||
const controls = desktops.getByRole("region", {
|
||||
name: "Agent placement controls",
|
||||
});
|
||||
// Operation outcomes are announced in the unnamed status region; its
|
||||
// labeled sibling reports the observed running configuration.
|
||||
const outcome = controls
|
||||
.getByRole("status")
|
||||
.and(controls.locator("p:not([aria-label])"));
|
||||
await controls
|
||||
.getByRole("combobox", { name: "Agent to place" })
|
||||
.selectOption(agent);
|
||||
await expect(outcome).toHaveText(
|
||||
"Choose a configuration for the next Start. This does not change an existing process.",
|
||||
);
|
||||
await controls
|
||||
.getByRole("combobox", { name: "Destination Desktop" })
|
||||
.selectOption("22222222-2222-4222-8222-222222222222");
|
||||
.getByRole("combobox", { name: "Runtime configuration" })
|
||||
.selectOption(
|
||||
`${remoteDesktop}:${standardRuntime.id}:${standardRuntime.revision}`,
|
||||
);
|
||||
await controls
|
||||
.getByRole("button", { name: "Start on destination", exact: true })
|
||||
.click();
|
||||
await expect(controls.getByRole("status")).toHaveText(
|
||||
"Destination keyless launch provisioning is unavailable. No new process was started.",
|
||||
await expect(outcome).toHaveText(
|
||||
"Destination cannot launch this agent. No new process was started.",
|
||||
);
|
||||
await waitForAnimations(page);
|
||||
await desktops.screenshot({
|
||||
@@ -208,8 +270,8 @@ test("remote Stop distinguishes delivery, uncertainty, and confirmed result", as
|
||||
await controls
|
||||
.getByRole("button", { name: "Retry same request", exact: true })
|
||||
.click();
|
||||
await expect(controls.getByRole("status")).toHaveText(
|
||||
"Destination keyless launch provisioning is unavailable. No new process was started.",
|
||||
await expect(outcome).toHaveText(
|
||||
"Destination cannot launch this agent. No new process was started.",
|
||||
);
|
||||
const lifecycle = await page.evaluate(
|
||||
() =>
|
||||
|
||||
Reference in New Issue
Block a user