Files
openclaw/packages/gateway-protocol/src/schema/environments.test.ts
Peter Steinberger 126b549a26 feat: run and reclaim cloud worker sessions from Control UI (#108398)
* feat(gateway): finish cloud worker session reclaim

* chore(gateway): refresh cloud worker artifacts

* fix(gateway): preserve recovery environment narrowing

* test(gateway): complete worker tunnel mock

* fix(gateway): harden cloud worker recovery

* fix(gateway): serialize forced worker teardown

* fix(gateway): handle replaced workspace directories

* fix(gateway): preserve forced destroy receiver

* test(ui): cover cloud worker reclaim flow

* fix(gateway): close final worker recovery races

* fix(ci): align cloud worker generated surfaces

* test(gateway): satisfy worker queue lint

* fix(gateway): recheck remote workspace after lease fence

* chore: move cloud worker release note to PR
2026-07-15 11:24:04 -07:00

139 lines
4.1 KiB
TypeScript

import { Value } from "typebox/value";
import { describe, expect, it } from "vitest";
import {
EnvironmentsCreateResultSchema,
EnvironmentsDestroyResultSchema,
EnvironmentsListResultSchema,
EnvironmentSummarySchema,
validateEnvironmentsCreateParams,
validateEnvironmentsDestroyParams,
WorkerEnvironmentStateSchema,
} from "../index.js";
const workerStates = [
"requested",
"provisioning",
"bootstrapping",
"ready",
"attached",
"idle",
"draining",
"destroying",
"destroyed",
"failed",
"orphaned",
] as const;
function workerSummary(
state: (typeof workerStates)[number],
status: "available" | "unavailable" | "starting" = "starting",
) {
return {
id: "environment-1",
type: "worker",
label: "Development worker",
status,
worker: {
providerId: "static-ssh",
state,
ageMs: 250,
attachedSessionIds: [],
tunnelStatus: "stopped",
},
};
}
describe("worker environment protocol schemas", () => {
it("accepts configured-profile create and environment-id destroy requests", () => {
expect(
validateEnvironmentsCreateParams({ profileId: "development", idempotencyKey: "request-1" }),
).toBe(true);
expect(validateEnvironmentsDestroyParams({ environmentId: "environment-1" })).toBe(true);
});
it("rejects missing, empty, and unknown lifecycle request fields", () => {
expect(validateEnvironmentsCreateParams({})).toBe(false);
expect(validateEnvironmentsCreateParams({ profileId: "", idempotencyKey: "request-1" })).toBe(
false,
);
expect(validateEnvironmentsCreateParams({ profileId: "development", idempotencyKey: "" })).toBe(
false,
);
expect(
validateEnvironmentsCreateParams({
profileId: "development",
idempotencyKey: "request-1",
providerId: "ssh",
}),
).toBe(false);
expect(validateEnvironmentsDestroyParams({ environmentId: "" })).toBe(false);
expect(validateEnvironmentsDestroyParams({ environmentId: "environment-1", force: true })).toBe(
true,
);
});
it("keeps the worker lifecycle state closed", () => {
for (const state of workerStates) {
expect(Value.Check(WorkerEnvironmentStateSchema, state)).toBe(true);
}
expect(Value.Check(WorkerEnvironmentStateSchema, "unknown")).toBe(false);
});
it("accepts worker metadata additively across summary and mutation results", () => {
const requested = workerSummary("requested");
const destroyedBase = workerSummary("destroyed", "unavailable");
const destroyed = {
...destroyedBase,
worker: {
...destroyedBase.worker,
leaseId: "lease-1",
idleMs: 50,
},
};
expect(Value.Check(EnvironmentSummarySchema, requested)).toBe(true);
expect(Value.Check(EnvironmentsCreateResultSchema, requested)).toBe(true);
expect(Value.Check(EnvironmentsDestroyResultSchema, destroyed)).toBe(true);
});
it("lists configured worker profiles without provider settings", () => {
expect(
Value.Check(EnvironmentsListResultSchema, {
environments: [],
profiles: [{ id: "aws", providerId: "crabbox" }],
}),
).toBe(true);
expect(
Value.Check(EnvironmentsListResultSchema, {
environments: [],
profiles: [{ id: "aws", providerId: "crabbox", settings: { token: "hidden" } }],
}),
).toBe(false);
});
it("preserves summaries without worker metadata and rejects malformed worker metadata", () => {
expect(
Value.Check(EnvironmentSummarySchema, {
id: "gateway",
type: "local",
status: "available",
}),
).toBe(true);
expect(
Value.Check(EnvironmentSummarySchema, {
...workerSummary("ready", "available"),
worker: { ...workerSummary("ready", "available").worker, ageMs: -1 },
}),
).toBe(false);
expect(
Value.Check(EnvironmentSummarySchema, {
...workerSummary("attached", "available"),
worker: {
...workerSummary("attached", "available").worker,
attachedSessionIds: [""],
},
}),
).toBe(false);
});
});