179 lines
6.1 KiB
JavaScript
179 lines
6.1 KiB
JavaScript
// @vitest-environment jsdom
|
|
import { readFileSync } from "node:fs";
|
|
import { join } from "node:path";
|
|
import { beforeEach, describe, expect, it, vi } from "vitest";
|
|
|
|
const authenticatedRequestMock = vi.hoisted(() => vi.fn());
|
|
|
|
vi.mock("@/components/session/authenticatedRequest.vue", () => ({
|
|
authenticatedRequest: authenticatedRequestMock,
|
|
}));
|
|
|
|
import {
|
|
EDGE_GATEWAY_WORKSPACE_CACHE_KEY,
|
|
EDGE_GATEWAY_WORKSPACE_CACHE_TTL_MS,
|
|
clearEdgeGatewayWorkspaceCache,
|
|
getEdgeGateway,
|
|
getEdgeGatewayInstallTokenStatus,
|
|
listEdgeGateways,
|
|
peekCachedEdgeGateway,
|
|
peekCachedEdgeGatewayList,
|
|
getEdgeGatewayModuleConfig,
|
|
setEdgeGatewayModuleConfig,
|
|
} from "@/services/edgeGateways.js";
|
|
|
|
describe("edge gateway service", () => {
|
|
beforeEach(() => {
|
|
authenticatedRequestMock.mockReset();
|
|
localStorage.clear();
|
|
sessionStorage.clear();
|
|
clearEdgeGatewayWorkspaceCache();
|
|
});
|
|
|
|
it("loads module config entries and derives a keyed config object", async () => {
|
|
authenticatedRequestMock.mockResolvedValue({
|
|
data: {
|
|
data: [
|
|
{ variable: "enabled", value: true },
|
|
{ variable: "default_release_channel", value: "canary" },
|
|
],
|
|
},
|
|
});
|
|
|
|
const response = await getEdgeGatewayModuleConfig();
|
|
|
|
expect(authenticatedRequestMock).toHaveBeenCalledWith("/edgegateway/config", "GET", {});
|
|
expect(response.data.config).toEqual({
|
|
enabled: true,
|
|
default_release_channel: "canary",
|
|
});
|
|
});
|
|
|
|
it("persists module config updates as a single payload", async () => {
|
|
authenticatedRequestMock.mockResolvedValue({
|
|
data: {
|
|
data: [],
|
|
},
|
|
});
|
|
|
|
await setEdgeGatewayModuleConfig({
|
|
enabled: false,
|
|
default_release_channel: "canary",
|
|
default_update_window: "03:00-05:00",
|
|
});
|
|
|
|
expect(authenticatedRequestMock).toHaveBeenCalledTimes(1);
|
|
expect(authenticatedRequestMock).toHaveBeenCalledWith("/edgegateway/config", "POST", {
|
|
enabled: false,
|
|
default_release_channel: "canary",
|
|
default_update_window: "03:00-05:00",
|
|
});
|
|
});
|
|
|
|
it("passes through installer session status requests unchanged", async () => {
|
|
authenticatedRequestMock.mockResolvedValue({
|
|
data: {
|
|
data: {
|
|
claim_token_id: 9001,
|
|
status: "RUNNING",
|
|
},
|
|
},
|
|
});
|
|
|
|
await getEdgeGatewayInstallTokenStatus(9001);
|
|
|
|
expect(authenticatedRequestMock).toHaveBeenCalledTimes(1);
|
|
expect(authenticatedRequestMock).toHaveBeenCalledWith("/edge-gateways/install-token/9001/status", "GET", {});
|
|
});
|
|
|
|
it("scopes workspace snapshots to the active session principal", async () => {
|
|
window.localStorage.setItem("token", "user-one-token");
|
|
authenticatedRequestMock.mockResolvedValueOnce({
|
|
data: {
|
|
data: { id: 101, label: "User One Gateway" },
|
|
},
|
|
});
|
|
|
|
await getEdgeGateway(101);
|
|
expect(peekCachedEdgeGateway(101)?.label).toBe("User One Gateway");
|
|
|
|
window.localStorage.setItem("token", "user-two-token");
|
|
expect(peekCachedEdgeGateway(101)).toBeNull();
|
|
expect(window.localStorage.getItem(EDGE_GATEWAY_WORKSPACE_CACHE_KEY)).toBeNull();
|
|
});
|
|
|
|
it("uses a stable browser cache namespace for session-scoped workspace snapshots", () => {
|
|
const source = readFileSync(join(process.cwd(), "src/services/edgeGateways.js"), "utf8");
|
|
|
|
expect(EDGE_GATEWAY_WORKSPACE_CACHE_KEY).toBe("truckwash.edgeGatewayWorkspace.cache.v1");
|
|
expect(source).toContain("sessionStorage");
|
|
expect(source).toContain("EDGE_GATEWAY_WORKSPACE_CACHE_KEY");
|
|
});
|
|
|
|
it("stores workspace cache entries in session storage scoped to the active token", async () => {
|
|
localStorage.setItem("token", "operator-a-token");
|
|
authenticatedRequestMock.mockResolvedValueOnce({
|
|
data: {
|
|
data: [
|
|
{
|
|
id: 101,
|
|
department_id: 55,
|
|
name: "Privileged gateway",
|
|
metadata: { agent_token: "secret-agent-token", health: "ok" },
|
|
bindings: [{ relay_id: 7, credential_secret: "binding-secret" }],
|
|
},
|
|
],
|
|
meta: { fleet_usage: { total: 1 }, api_key: "fleet-api-key" },
|
|
},
|
|
});
|
|
|
|
await listEdgeGateways({ departmentId: 55, view: "summary" });
|
|
|
|
expect(localStorage.getItem(EDGE_GATEWAY_WORKSPACE_CACHE_KEY)).toBeNull();
|
|
const persisted = JSON.parse(sessionStorage.getItem(EDGE_GATEWAY_WORKSPACE_CACHE_KEY));
|
|
expect(persisted.scope).toEqual(expect.any(String));
|
|
expect(persisted.scope).not.toContain("operator-a-token");
|
|
expect(persisted.lists).toBeTruthy();
|
|
expect(JSON.stringify(persisted)).not.toContain("secret-agent-token");
|
|
expect(JSON.stringify(persisted)).not.toContain("binding-secret");
|
|
expect(JSON.stringify(persisted)).not.toContain("fleet-api-key");
|
|
expect(peekCachedEdgeGateway(101)?.metadata?.health).toBe("ok");
|
|
|
|
localStorage.setItem("token", "operator-b-token");
|
|
|
|
expect(peekCachedEdgeGatewayList({ departmentId: 55, view: "summary" })).toBeNull();
|
|
expect(peekCachedEdgeGateway(101)).toBeNull();
|
|
});
|
|
|
|
it("expires stale workspace cache entries", async () => {
|
|
localStorage.setItem("token", "operator-a-token");
|
|
authenticatedRequestMock.mockResolvedValueOnce({
|
|
data: {
|
|
data: [{ id: 202, department_id: 55, name: "Stale gateway" }],
|
|
meta: {},
|
|
},
|
|
});
|
|
|
|
await listEdgeGateways({ departmentId: 55, view: "summary" });
|
|
|
|
const persisted = JSON.parse(sessionStorage.getItem(EDGE_GATEWAY_WORKSPACE_CACHE_KEY));
|
|
persisted.cachedAt = Date.now() - EDGE_GATEWAY_WORKSPACE_CACHE_TTL_MS - 1;
|
|
Object.values(persisted.lists).forEach((entry) => {
|
|
entry.cachedAt = persisted.cachedAt;
|
|
});
|
|
Object.values(persisted.details).forEach((entry) => {
|
|
entry.cachedAt = persisted.cachedAt;
|
|
});
|
|
sessionStorage.setItem(EDGE_GATEWAY_WORKSPACE_CACHE_KEY, JSON.stringify(persisted));
|
|
vi.resetModules();
|
|
|
|
const { peekCachedEdgeGateway: peekGateway, peekCachedEdgeGatewayList: peekList } = await import(
|
|
"@/services/edgeGateways.js"
|
|
);
|
|
|
|
expect(peekList({ departmentId: 55, view: "summary" })).toBeNull();
|
|
expect(peekGateway(202)).toBeNull();
|
|
expect(sessionStorage.getItem(EDGE_GATEWAY_WORKSPACE_CACHE_KEY)).toBeNull();
|
|
});
|
|
});
|