Files
Termix/plugins/tmux-monitor/tests/backend/routes.test.ts
T

91 lines
2.9 KiB
TypeScript

import { afterEach, describe, expect, it } from "vitest";
import { EventEmitter } from "node:events";
import { startServer, type TestServer } from "./helpers";
function fakeSshClient(outputs: Record<string, string>, exitCode = 0) {
const client = new EventEmitter() as EventEmitter & {
exec: (
command: string,
cb: (err: Error | null, stream: unknown) => void,
) => void;
};
client.exec = (command, cb) => {
const stream = new EventEmitter() as EventEmitter & {
stderr: EventEmitter;
};
stream.stderr = new EventEmitter();
const matchKey = Object.keys(outputs).find((k) => command.includes(k));
const output = matchKey ? outputs[matchKey] : "";
cb(null, stream);
setImmediate(() => {
if (output) stream.emit("data", Buffer.from(output));
stream.emit("close", exitCode);
});
};
return client;
}
let server: TestServer | null = null;
afterEach(async () => {
await server?.close();
server = null;
});
describe("GET /:hostId/overview", () => {
it("403s when the host does not exist or is not reachable", async () => {
server = await startServer({ hosts: [] });
const res = await server.request("GET", "/7/overview");
expect(res.status).toBe(403);
});
it("403s when the monitor is disabled for the host", async () => {
server = await startServer({ enabledHosts: [] });
const res = await server.request("GET", "/7/overview");
expect(res.status).toBe(403);
expect(res.body.error).toMatch(/not enabled/i);
});
it("403s without the tmux-monitor.use permission", async () => {
server = await startServer({ permissions: [] });
const res = await server.request("GET", "/7/overview");
expect(res.status).toBe(403);
});
it("reports tmux unavailable when the exec exits non-zero", async () => {
server = await startServer({ sshClient: fakeSshClient({}, 127) });
const res = await server.request("GET", "/7/overview");
expect(res.status).toBe(200);
expect(res.body).toEqual({ available: false, sessions: [] });
});
});
describe("PUT /:hostId/tags", () => {
it("saves tags for the acting user and session", async () => {
server = await startServer();
const res = await server.request("PUT", "/7/tags", {
body: { sessionName: "work", tags: ["a", "b", "b", " "] },
});
expect(res.status).toBe(200);
expect(res.body.tags.sort()).toEqual(["a", "b"]);
});
it("rejects a non-array tags field", async () => {
server = await startServer();
const res = await server.request("PUT", "/7/tags", {
body: { sessionName: "work", tags: "nope" },
});
expect(res.status).toBe(400);
});
});
describe("POST /:hostId/sessions", () => {
it("rejects an invalid session name", async () => {
server = await startServer();
const res = await server.request("POST", "/7/sessions", {
body: { name: "bad:name" },
});
expect(res.status).toBe(400);
});
});