add another 100 tests (thank you claude for making these I ain't coming up with this much shit to test)

This commit is contained in:
KingKDot
2026-04-08 21:49:59 -05:00
parent 6a058930aa
commit 66393d5ba4
8 changed files with 1248 additions and 0 deletions
+220
View File
@@ -0,0 +1,220 @@
import { describe, expect, test, beforeEach } from "bun:test";
import { metrics } from "./metrics";
beforeEach(() => {
metrics.reset();
});
describe("MetricsCollector", () => {
describe("connection tracking", () => {
test("records connections and disconnections", () => {
metrics.recordConnection();
metrics.recordConnection();
metrics.recordDisconnection();
const snap = metrics.getSnapshot();
expect(snap.connections.totalConnections).toBe(2);
expect(snap.connections.totalDisconnections).toBe(1);
expect(snap.connections.activeConnections).toBe(1);
});
test("active connections can go to zero", () => {
const before = metrics.getSnapshot();
const baseConns = before.connections.totalConnections;
const baseDisconns = before.connections.totalDisconnections;
metrics.recordConnection();
metrics.recordDisconnection();
const snap = metrics.getSnapshot();
expect(snap.connections.totalConnections).toBe(baseConns + 1);
expect(snap.connections.totalDisconnections).toBe(baseDisconns + 1);
expect(snap.connections.activeConnections).toBe(before.connections.activeConnections);
});
});
describe("command tracking", () => {
test("records command count and type breakdown", () => {
metrics.recordCommand("console");
metrics.recordCommand("console");
metrics.recordCommand("desktop_start");
const snap = metrics.getSnapshot();
expect(snap.commands.total).toBe(3);
expect(snap.commands.byType["console"]).toBe(2);
expect(snap.commands.byType["desktop_start"]).toBe(1);
});
test("commands within last minute are counted", () => {
metrics.recordCommand("test");
const snap = metrics.getSnapshot();
expect(snap.commands.lastMinute).toBeGreaterThanOrEqual(1);
expect(snap.commands.lastHour).toBeGreaterThanOrEqual(1);
});
});
describe("bandwidth tracking", () => {
test("records bytes sent and received", () => {
metrics.recordBytesSent(1024);
metrics.recordBytesSent(2048);
metrics.recordBytesReceived(512);
const snap = metrics.getSnapshot();
expect(snap.bandwidth.sent).toBe(3072);
expect(snap.bandwidth.received).toBe(512);
});
});
describe("ping tracking", () => {
test("returns null stats when no pings recorded", () => {
const snap = metrics.getSnapshot();
expect(snap.ping.min).toBeNull();
expect(snap.ping.max).toBeNull();
expect(snap.ping.avg).toBeNull();
expect(snap.ping.count).toBe(0);
});
test("computes min/max/avg correctly", () => {
metrics.recordPing(10);
metrics.recordPing(20);
metrics.recordPing(30);
const snap = metrics.getSnapshot();
expect(snap.ping.min).toBe(10);
expect(snap.ping.max).toBe(30);
expect(snap.ping.avg).toBe(20);
expect(snap.ping.count).toBe(3);
});
test("single ping has same min/max/avg", () => {
metrics.recordPing(42);
const snap = metrics.getSnapshot();
expect(snap.ping.min).toBe(42);
expect(snap.ping.max).toBe(42);
expect(snap.ping.avg).toBe(42);
expect(snap.ping.count).toBe(1);
});
});
describe("HTTP request tracking", () => {
test("records total HTTP requests", () => {
metrics.recordHttpRequest(10, 200);
metrics.recordHttpRequest(20, 200);
metrics.recordHttpRequest(5, 404);
const snap = metrics.getSnapshot();
expect(snap.http.total).toBe(3);
});
test("tracks error responses in last minute", () => {
metrics.recordHttpRequest(10, 200);
metrics.recordHttpRequest(20, 500);
metrics.recordHttpRequest(5, 404);
const snap = metrics.getSnapshot();
expect(snap.http.lastMinuteErrors).toBeGreaterThanOrEqual(2);
});
test("computes latency avg and p95", () => {
for (let i = 1; i <= 100; i++) {
metrics.recordHttpRequest(i, 200);
}
const snap = metrics.getSnapshot();
expect(snap.http.latencyAvg).toBeCloseTo(50.5, 0);
expect(snap.http.latencyP95).toBeGreaterThanOrEqual(90);
});
});
describe("snapshot structure", () => {
test("returns expected top-level keys", () => {
const snap = metrics.getSnapshot();
expect(snap).toHaveProperty("timestamp");
expect(snap).toHaveProperty("clients");
expect(snap).toHaveProperty("connections");
expect(snap).toHaveProperty("commands");
expect(snap).toHaveProperty("sessions");
expect(snap).toHaveProperty("bandwidth");
expect(snap).toHaveProperty("server");
expect(snap).toHaveProperty("ping");
expect(snap).toHaveProperty("http");
expect(snap).toHaveProperty("eventLoop");
});
test("server uptime is positive", () => {
const snap = metrics.getSnapshot();
expect(snap.server.uptime).toBeGreaterThanOrEqual(0);
expect(snap.server.startTime).toBeGreaterThan(0);
});
test("system memory values are reasonable", () => {
const snap = metrics.getSnapshot();
expect(snap.server.systemMemory.total).toBeGreaterThan(0);
expect(snap.server.systemMemory.free).toBeGreaterThanOrEqual(0);
expect(snap.server.systemMemory.usedPercent).toBeGreaterThanOrEqual(0);
expect(snap.server.systemMemory.usedPercent).toBeLessThanOrEqual(100);
});
test("cpu cores is positive", () => {
const snap = metrics.getSnapshot();
expect(snap.server.cpu.cores).toBeGreaterThan(0);
});
});
describe("history", () => {
test("starts empty", () => {
expect(metrics.getHistory()).toEqual([]);
});
test("recordHistoryEntry adds to history", () => {
const snap = metrics.getSnapshot();
metrics.recordHistoryEntry(snap);
const history = metrics.getHistory();
expect(history).toHaveLength(1);
expect(history[0].timestamp).toBe(snap.timestamp);
});
test("history is capped at maxHistoryPoints", () => {
for (let i = 0; i < 100; i++) {
const snap = metrics.getSnapshot();
metrics.recordHistoryEntry(snap);
}
const history = metrics.getHistory();
expect(history.length).toBeLessThanOrEqual(60);
});
test("getHistory returns a copy", () => {
const snap = metrics.getSnapshot();
metrics.recordHistoryEntry(snap);
const h1 = metrics.getHistory();
const h2 = metrics.getHistory();
expect(h1).not.toBe(h2);
expect(h1).toEqual(h2);
});
});
describe("reset", () => {
test("clears resettable counters", () => {
metrics.recordCommand("test");
metrics.recordBytesSent(100);
metrics.recordBytesReceived(200);
metrics.recordPing(50);
metrics.recordHttpRequest(10, 200);
metrics.reset();
const snap = metrics.getSnapshot();
// Note: connection counters are cumulative and not cleared by reset()
expect(snap.commands.total).toBe(0);
expect(snap.bandwidth.sent).toBe(0);
expect(snap.bandwidth.received).toBe(0);
expect(snap.ping.count).toBe(0);
expect(snap.http.total).toBe(0);
});
});
});
+209
View File
@@ -0,0 +1,209 @@
import { describe, expect, test } from "bun:test";
import {
checkPermission,
checkAnyPermission,
checkAllPermissions,
requireAuth,
requirePermission,
requireAnyPermission,
getPermissionDescription,
getRoleDescription,
type Permission,
} from "./rbac";
import type { AuthenticatedUser } from "./auth";
function makeUser(overrides: Partial<AuthenticatedUser> = {}): AuthenticatedUser {
return {
userId: 1,
username: "testuser",
role: "admin",
...overrides,
};
}
describe("checkPermission", () => {
test("returns false for null user", () => {
expect(checkPermission(null, "users:manage")).toBe(false);
});
test("admin has users:manage", () => {
expect(checkPermission(makeUser({ role: "admin" }), "users:manage")).toBe(true);
});
test("operator does not have users:manage", () => {
expect(checkPermission(makeUser({ role: "operator" }), "users:manage")).toBe(false);
});
test("viewer does not have users:manage", () => {
expect(checkPermission(makeUser({ role: "viewer" }), "users:manage")).toBe(false);
});
test("admin has clients:control", () => {
expect(checkPermission(makeUser({ role: "admin" }), "clients:control")).toBe(true);
});
test("operator has clients:control", () => {
expect(checkPermission(makeUser({ role: "operator" }), "clients:control")).toBe(true);
});
test("viewer does not have clients:control", () => {
expect(checkPermission(makeUser({ role: "viewer" }), "clients:control")).toBe(false);
});
test("admin has audit:view", () => {
expect(checkPermission(makeUser({ role: "admin" }), "audit:view")).toBe(true);
});
test("operator does not have audit:view", () => {
expect(checkPermission(makeUser({ role: "operator" }), "audit:view")).toBe(false);
});
});
describe("checkAnyPermission", () => {
test("returns false for null user", () => {
expect(checkAnyPermission(null, ["users:manage", "clients:control"])).toBe(false);
});
test("returns true if user has at least one permission", () => {
const user = makeUser({ role: "operator" });
expect(checkAnyPermission(user, ["users:manage", "clients:control"])).toBe(true);
});
test("returns false if user has none of the permissions", () => {
const user = makeUser({ role: "viewer" });
expect(checkAnyPermission(user, ["users:manage", "clients:control"])).toBe(false);
});
test("returns true for empty permissions array (vacuously)", () => {
const user = makeUser({ role: "viewer" });
// Array.some on empty returns false
expect(checkAnyPermission(user, [])).toBe(false);
});
});
describe("checkAllPermissions", () => {
test("returns false for null user", () => {
expect(checkAllPermissions(null, ["users:manage"])).toBe(false);
});
test("admin has all permissions", () => {
const user = makeUser({ role: "admin" });
expect(
checkAllPermissions(user, ["users:manage", "clients:control", "audit:view"]),
).toBe(true);
});
test("operator lacks users:manage so fails all check", () => {
const user = makeUser({ role: "operator" });
expect(
checkAllPermissions(user, ["users:manage", "clients:control"]),
).toBe(false);
});
test("returns true for empty permissions array (vacuously)", () => {
const user = makeUser({ role: "viewer" });
expect(checkAllPermissions(user, [])).toBe(true);
});
});
describe("requireAuth", () => {
test("returns user when provided", () => {
const user = makeUser();
expect(requireAuth(user)).toBe(user);
});
test("throws 401 Response for null user", () => {
expect(() => requireAuth(null)).toThrow();
try {
requireAuth(null);
} catch (e) {
expect(e).toBeInstanceOf(Response);
expect((e as Response).status).toBe(401);
}
});
});
describe("requirePermission", () => {
test("returns user when permission is satisfied", () => {
const user = makeUser({ role: "admin" });
expect(requirePermission(user, "users:manage")).toBe(user);
});
test("throws 401 for null user", () => {
try {
requirePermission(null, "users:manage");
} catch (e) {
expect(e).toBeInstanceOf(Response);
expect((e as Response).status).toBe(401);
}
});
test("throws 403 when permission is not satisfied", () => {
const user = makeUser({ role: "viewer" });
try {
requirePermission(user, "users:manage");
} catch (e) {
expect(e).toBeInstanceOf(Response);
expect((e as Response).status).toBe(403);
}
});
});
describe("requireAnyPermission", () => {
test("returns user when at least one permission is satisfied", () => {
const user = makeUser({ role: "operator" });
expect(requireAnyPermission(user, ["users:manage", "clients:control"])).toBe(user);
});
test("throws 403 when none satisfied", () => {
const user = makeUser({ role: "viewer" });
try {
requireAnyPermission(user, ["users:manage", "clients:control"]);
} catch (e) {
expect(e).toBeInstanceOf(Response);
expect((e as Response).status).toBe(403);
}
});
});
describe("getPermissionDescription", () => {
const cases: [Permission, string][] = [
["users:manage", "Manage users and roles"],
["clients:control", "Control clients (execute commands, desktop, console, files)"],
["clients:view", "View connected clients"],
["clients:build", "Build client binaries"],
["audit:view", "View audit logs"],
];
for (const [perm, desc] of cases) {
test(`${perm} → "${desc}"`, () => {
expect(getPermissionDescription(perm)).toBe(desc);
});
}
test("unknown permission returns fallback", () => {
expect(getPermissionDescription("bogus:perm" as Permission)).toBe("Unknown permission");
});
});
describe("getRoleDescription", () => {
test("admin description", () => {
expect(getRoleDescription("admin")).toBe(
"Full access - can manage users and control all clients",
);
});
test("operator description", () => {
expect(getRoleDescription("operator")).toBe(
"Can control clients but cannot manage users",
);
});
test("viewer description", () => {
expect(getRoleDescription("viewer")).toBe("Read-only access to view clients");
});
test("unknown role returns fallback", () => {
expect(getRoleDescription("unknown" as any)).toBe("Unknown role");
});
});
@@ -0,0 +1,271 @@
import { describe, expect, test, beforeEach } from "bun:test";
import {
addConsoleSession,
getConsoleSession,
deleteConsoleSession,
getConsoleSessionsByClient,
getConsoleSessionCount,
addRdSession,
getRdSession,
deleteRdSession,
getRdSessionsByClient,
getRdSessionCount,
hasRdSessionsForClient,
addHvncSession,
getHvncSession,
deleteHvncSession,
getHvncSessionsByClient,
hasHvncSessionsForClient,
getHvncSessionCount,
addFileBrowserSession,
getFileBrowserSession,
deleteFileBrowserSession,
getFileBrowserSessionsByClient,
getFileBrowserSessionCount,
addProcessSession,
getProcessSession,
deleteProcessSession,
getProcessSessionsByClient,
getProcessSessionCount,
addKeyloggerSession,
getKeyloggerSession,
deleteKeyloggerSession,
getKeyloggerSessionsByClient,
addVoiceSession,
getVoiceSession,
deleteVoiceSession,
getVoiceSessionsByClient,
addNotificationSession,
deleteNotificationSession,
getNotificationSessionCount,
addDashboardSession,
deleteDashboardSession,
getDashboardSessionCount,
safeSendViewerFrame,
getAllConsoleSessions,
getAllRdSessions,
} from "./sessionManager";
import type { ServerWebSocket } from "bun";
import type { SocketData } from "./types";
// Minimal mock ws that records sends
function mockWs(): ServerWebSocket<SocketData> {
const sent: any[] = [];
return {
send: (data: any) => { sent.push(data); return data.length || 0; },
close: () => {},
data: { role: "console_viewer" as any, clientId: "c1" },
_sent: sent,
} as any;
}
// We need to clear sessions between tests. The session manager uses module-level Maps,
// so we just delete sessions we create.
function cleanupConsoleSessions(ids: string[]) {
for (const id of ids) deleteConsoleSession(id);
}
describe("sessionManager - console sessions", () => {
const ids: string[] = [];
test("add and get a console session", () => {
const ws = mockWs();
const session = { id: "cs-1", clientId: "client-a", viewer: ws, createdAt: Date.now() };
ids.push("cs-1");
addConsoleSession(session);
const retrieved = getConsoleSession("cs-1");
expect(retrieved).toBeDefined();
expect(retrieved!.clientId).toBe("client-a");
});
test("get nonexistent session returns undefined", () => {
expect(getConsoleSession("nonexistent")).toBeUndefined();
});
test("delete returns true for existing session", () => {
const ws = mockWs();
addConsoleSession({ id: "cs-del", clientId: "client-b", viewer: ws, createdAt: Date.now() });
expect(deleteConsoleSession("cs-del")).toBe(true);
});
test("delete returns false for nonexistent session", () => {
expect(deleteConsoleSession("no-such-id")).toBe(false);
});
test("getConsoleSessionsByClient returns sessions for that client", () => {
const ws = mockWs();
addConsoleSession({ id: "cs-c1", clientId: "multi-client", viewer: ws, createdAt: Date.now() });
addConsoleSession({ id: "cs-c2", clientId: "multi-client", viewer: ws, createdAt: Date.now() });
addConsoleSession({ id: "cs-c3", clientId: "other-client", viewer: ws, createdAt: Date.now() });
ids.push("cs-c1", "cs-c2", "cs-c3");
const sessions = getConsoleSessionsByClient("multi-client");
expect(sessions.length).toBe(2);
expect(sessions.map(s => s.id).sort()).toEqual(["cs-c1", "cs-c2"]);
});
test("getConsoleSessionsByClient returns empty for unknown client", () => {
expect(getConsoleSessionsByClient("unknown-client")).toEqual([]);
});
// Clean up all created sessions
test("cleanup", () => {
cleanupConsoleSessions(ids);
});
});
describe("sessionManager - remote desktop sessions", () => {
test("add, get, and delete RD session", () => {
const ws = mockWs();
addRdSession({ id: "rd-1", clientId: "c-rd", viewer: ws, createdAt: Date.now() });
expect(getRdSession("rd-1")).toBeDefined();
expect(hasRdSessionsForClient("c-rd")).toBe(true);
expect(getRdSessionsByClient("c-rd").length).toBe(1);
expect(deleteRdSession("rd-1")).toBe(true);
expect(getRdSession("rd-1")).toBeUndefined();
expect(hasRdSessionsForClient("c-rd")).toBe(false);
});
test("delete nonexistent RD session returns false", () => {
expect(deleteRdSession("no-rd")).toBe(false);
});
});
describe("sessionManager - HVNC sessions", () => {
test("add, get, and delete HVNC session", () => {
const ws = mockWs();
addHvncSession({ id: "hvnc-1", clientId: "c-hvnc", viewer: ws, createdAt: Date.now() });
expect(getHvncSession("hvnc-1")).toBeDefined();
expect(hasHvncSessionsForClient("c-hvnc")).toBe(true);
expect(getHvncSessionsByClient("c-hvnc").length).toBe(1);
expect(getHvncSessionCount()).toBeGreaterThanOrEqual(1);
expect(deleteHvncSession("hvnc-1")).toBe(true);
expect(getHvncSession("hvnc-1")).toBeUndefined();
});
});
describe("sessionManager - file browser sessions", () => {
test("add, get, and delete file browser session", () => {
const ws = mockWs();
addFileBrowserSession({ id: "fb-1", clientId: "c-fb", viewer: ws, createdAt: Date.now() });
expect(getFileBrowserSession("fb-1")).toBeDefined();
expect(getFileBrowserSessionsByClient("c-fb").length).toBe(1);
expect(deleteFileBrowserSession("fb-1")).toBe(true);
expect(getFileBrowserSession("fb-1")).toBeUndefined();
});
});
describe("sessionManager - process sessions", () => {
test("add, get, and delete process session", () => {
const ws = mockWs();
addProcessSession({ id: "ps-1", clientId: "c-ps", viewer: ws, createdAt: Date.now() });
expect(getProcessSession("ps-1")).toBeDefined();
expect(getProcessSessionsByClient("c-ps").length).toBe(1);
expect(deleteProcessSession("ps-1")).toBe(true);
expect(getProcessSession("ps-1")).toBeUndefined();
});
});
describe("sessionManager - keylogger sessions", () => {
test("add, get, and delete keylogger session", () => {
const ws = mockWs();
addKeyloggerSession({ id: "kl-1", clientId: "c-kl", viewer: ws, createdAt: Date.now() });
expect(getKeyloggerSession("kl-1")).toBeDefined();
expect(getKeyloggerSessionsByClient("c-kl").length).toBe(1);
expect(deleteKeyloggerSession("kl-1")).toBe(true);
expect(getKeyloggerSession("kl-1")).toBeUndefined();
});
});
describe("sessionManager - voice sessions", () => {
test("add, get, and delete voice session", () => {
const ws = mockWs();
addVoiceSession({ id: "vc-1", clientId: "c-vc", viewer: ws, createdAt: Date.now() });
expect(getVoiceSession("vc-1")).toBeDefined();
expect(getVoiceSessionsByClient("c-vc").length).toBe(1);
expect(deleteVoiceSession("vc-1")).toBe(true);
expect(getVoiceSession("vc-1")).toBeUndefined();
});
});
describe("sessionManager - notification sessions", () => {
test("add and delete notification session", () => {
const ws = mockWs();
addNotificationSession({ id: "ns-1", viewer: ws, createdAt: Date.now() });
expect(getNotificationSessionCount()).toBeGreaterThanOrEqual(1);
expect(deleteNotificationSession("ns-1")).toBe(true);
});
});
describe("sessionManager - dashboard sessions", () => {
test("add and delete dashboard session", () => {
const ws = mockWs();
addDashboardSession({ id: "ds-1", viewer: ws, createdAt: Date.now() });
expect(getDashboardSessionCount()).toBeGreaterThanOrEqual(1);
expect(deleteDashboardSession("ds-1")).toBe(true);
});
});
describe("safeSendViewerFrame", () => {
test("constructs correct binary frame with header", () => {
const sent: any[] = [];
const ws = {
send: (data: any) => { sent.push(data); },
} as any;
const payload = new Uint8Array([1, 2, 3, 4]);
const header = { type: "frame", display: 0 };
const bytesSent = safeSendViewerFrame(ws, payload, header);
expect(bytesSent).toBeGreaterThan(0);
expect(sent.length).toBe(1);
// Verify the frame structure: 4-byte length + meta + payload
const frame = sent[0] as Uint8Array;
const metaLen = new DataView(frame.buffer, frame.byteOffset, 4).getUint32(0, false);
expect(metaLen).toBeGreaterThan(0);
const metaBytes = frame.slice(4, 4 + metaLen);
const meta = JSON.parse(new TextDecoder().decode(metaBytes));
expect(meta.type).toBe("frame");
expect(meta.display).toBe(0);
const payloadBytes = frame.slice(4 + metaLen);
expect(payloadBytes).toEqual(payload);
});
test("returns 0 when send throws", () => {
const ws = {
send: () => { throw new Error("closed"); },
} as any;
const result = safeSendViewerFrame(ws, new Uint8Array([1]), {});
expect(result).toBe(0);
});
test("handles empty payload", () => {
const sent: any[] = [];
const ws = {
send: (data: any) => { sent.push(data); },
} as any;
const bytesSent = safeSendViewerFrame(ws, new Uint8Array(0), { type: "empty" });
expect(bytesSent).toBeGreaterThan(0);
});
});