228 lines
6.0 KiB
TypeScript
228 lines
6.0 KiB
TypeScript
import { assertEquals } from "@std/assert";
|
|
import { executeOperations } from "./executor.ts";
|
|
import type { Operation } from "./operations.ts";
|
|
import type { ActualState } from "../state/actual.ts";
|
|
|
|
function emptyActual(): ActualState {
|
|
return {
|
|
groups: [],
|
|
groupsByName: new Map(),
|
|
groupsById: new Map(),
|
|
setupKeys: [],
|
|
setupKeysByName: new Map(),
|
|
peers: [],
|
|
peersByName: new Map(),
|
|
peersById: new Map(),
|
|
policies: [],
|
|
policiesByName: new Map(),
|
|
routes: [],
|
|
routesByNetworkId: new Map(),
|
|
dns: [],
|
|
dnsByName: new Map(),
|
|
};
|
|
}
|
|
|
|
Deno.test("executor calls createGroup for create_group op", async () => {
|
|
const calls: string[] = [];
|
|
const mockClient = {
|
|
createGroup: (data: { name: string }) => {
|
|
calls.push(`createGroup:${data.name}`);
|
|
return Promise.resolve({
|
|
id: "new-g1",
|
|
name: data.name,
|
|
peers_count: 0,
|
|
peers: [],
|
|
issued: "api" as const,
|
|
});
|
|
},
|
|
};
|
|
const ops: Operation[] = [
|
|
{ type: "create_group", name: "pilots" },
|
|
];
|
|
const { results } = await executeOperations(
|
|
ops,
|
|
mockClient as never,
|
|
emptyActual(),
|
|
);
|
|
assertEquals(calls, ["createGroup:pilots"]);
|
|
assertEquals(results[0].status, "success");
|
|
});
|
|
|
|
Deno.test("executor aborts on first failure", async () => {
|
|
const mockClient = {
|
|
createGroup: () => Promise.reject(new Error("API down")),
|
|
createSetupKey: () => Promise.resolve({ id: 1, key: "k", name: "key1" }),
|
|
};
|
|
const ops: Operation[] = [
|
|
{ type: "create_group", name: "pilots" },
|
|
{ type: "create_setup_key", name: "key1" },
|
|
];
|
|
const { results } = await executeOperations(
|
|
ops,
|
|
mockClient as never,
|
|
emptyActual(),
|
|
);
|
|
assertEquals(results[0].status, "failed");
|
|
assertEquals(results.length, 1); // second op never executed
|
|
});
|
|
|
|
Deno.test("executor tracks created group IDs for setup key auto_groups", async () => {
|
|
const calls: Array<{ method: string; data: unknown }> = [];
|
|
const mockClient = {
|
|
createGroup: (data: { name: string }) => {
|
|
calls.push({ method: "createGroup", data });
|
|
return Promise.resolve({
|
|
id: "new-g1",
|
|
name: data.name,
|
|
peers_count: 0,
|
|
peers: [],
|
|
issued: "api" as const,
|
|
});
|
|
},
|
|
createSetupKey: (data: Record<string, unknown>) => {
|
|
calls.push({ method: "createSetupKey", data });
|
|
return Promise.resolve({
|
|
id: 1,
|
|
name: data.name,
|
|
key: "raw-key-123",
|
|
type: data.type,
|
|
expires: "2026-04-01T00:00:00Z",
|
|
valid: true,
|
|
revoked: false,
|
|
used_times: 0,
|
|
state: "valid" as const,
|
|
auto_groups: data.auto_groups,
|
|
usage_limit: data.usage_limit,
|
|
});
|
|
},
|
|
};
|
|
const ops: Operation[] = [
|
|
{ type: "create_group", name: "pilots" },
|
|
{
|
|
type: "create_setup_key",
|
|
name: "key1",
|
|
details: {
|
|
type: "one-off",
|
|
auto_groups: ["pilots"],
|
|
usage_limit: 1,
|
|
expires_in: 604800,
|
|
},
|
|
},
|
|
];
|
|
const { results, createdKeys } = await executeOperations(
|
|
ops,
|
|
mockClient as never,
|
|
emptyActual(),
|
|
);
|
|
assertEquals(results.length, 2);
|
|
assertEquals(results[0].status, "success");
|
|
assertEquals(results[1].status, "success");
|
|
// The setup key call should have resolved "pilots" -> "new-g1"
|
|
const setupKeyCall = calls.find((c) => c.method === "createSetupKey");
|
|
assertEquals(
|
|
(setupKeyCall?.data as Record<string, unknown>).auto_groups,
|
|
["new-g1"],
|
|
);
|
|
// Created keys map stores the raw key
|
|
assertEquals(createdKeys.get("key1"), "raw-key-123");
|
|
});
|
|
|
|
Deno.test("executor resolves group IDs from actual state", async () => {
|
|
const calls: Array<{ method: string; data: unknown }> = [];
|
|
const actual = emptyActual();
|
|
actual.groupsByName.set("pilots", {
|
|
id: "existing-g1",
|
|
name: "pilots",
|
|
peers_count: 0,
|
|
peers: [],
|
|
issued: "api",
|
|
});
|
|
|
|
const mockClient = {
|
|
createSetupKey: (data: Record<string, unknown>) => {
|
|
calls.push({ method: "createSetupKey", data });
|
|
return Promise.resolve({
|
|
id: 1,
|
|
name: data.name,
|
|
key: "raw-key-456",
|
|
type: data.type,
|
|
expires: "2026-04-01T00:00:00Z",
|
|
valid: true,
|
|
revoked: false,
|
|
used_times: 0,
|
|
state: "valid" as const,
|
|
auto_groups: data.auto_groups,
|
|
usage_limit: data.usage_limit,
|
|
});
|
|
},
|
|
};
|
|
const ops: Operation[] = [
|
|
{
|
|
type: "create_setup_key",
|
|
name: "key1",
|
|
details: {
|
|
type: "one-off",
|
|
auto_groups: ["pilots"],
|
|
usage_limit: 1,
|
|
expires_in: 604800,
|
|
},
|
|
},
|
|
];
|
|
const { results } = await executeOperations(
|
|
ops,
|
|
mockClient as never,
|
|
actual,
|
|
);
|
|
assertEquals(results[0].status, "success");
|
|
const setupKeyCall = calls.find((c) => c.method === "createSetupKey");
|
|
assertEquals(
|
|
(setupKeyCall?.data as Record<string, unknown>).auto_groups,
|
|
["existing-g1"],
|
|
);
|
|
});
|
|
|
|
Deno.test("executor deletes group by resolving ID from actual", async () => {
|
|
const calls: string[] = [];
|
|
const actual = emptyActual();
|
|
actual.groupsByName.set("stale-group", {
|
|
id: "g-old",
|
|
name: "stale-group",
|
|
peers_count: 0,
|
|
peers: [],
|
|
issued: "api",
|
|
});
|
|
|
|
const mockClient = {
|
|
deleteGroup: (id: string) => {
|
|
calls.push(`deleteGroup:${id}`);
|
|
return Promise.resolve();
|
|
},
|
|
};
|
|
const ops: Operation[] = [
|
|
{ type: "delete_group", name: "stale-group" },
|
|
];
|
|
const { results } = await executeOperations(
|
|
ops,
|
|
mockClient as never,
|
|
actual,
|
|
);
|
|
assertEquals(calls, ["deleteGroup:g-old"]);
|
|
assertEquals(results[0].status, "success");
|
|
});
|
|
|
|
Deno.test("executor stores error message on failure", async () => {
|
|
const mockClient = {
|
|
createGroup: () => Promise.reject(new Error("rate limited")),
|
|
};
|
|
const ops: Operation[] = [
|
|
{ type: "create_group", name: "pilots" },
|
|
];
|
|
const { results } = await executeOperations(
|
|
ops,
|
|
mockClient as never,
|
|
emptyActual(),
|
|
);
|
|
assertEquals(results[0].status, "failed");
|
|
assertEquals(results[0].error, "rate limited");
|
|
});
|