mirror of
https://github.com/openclaw/openclaw.git
synced 2026-07-29 06:01:14 +00:00
* 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
139 lines
4.1 KiB
TypeScript
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);
|
|
});
|
|
});
|