mirror of
https://github.com/Termix-SSH/Termix.git
synced 2026-10-28 14:15:24 +00:00
107 lines
3.4 KiB
TypeScript
107 lines
3.4 KiB
TypeScript
import { afterEach, describe, expect, it, vi } from "vitest";
|
|
import { RemoteSessions } from "../../src/backend/sessions.js";
|
|
import { createLiveSessions } from "../../src/backend/live-sessions.js";
|
|
import { GuacamoleTokenService } from "../../src/backend/token-service.js";
|
|
|
|
const meta = {
|
|
termixConnectId: "c1",
|
|
hostId: 7,
|
|
hostName: "Win box",
|
|
ownerUserId: "user-1",
|
|
protocol: "rdp" as const,
|
|
tabInstanceId: "tab-1",
|
|
};
|
|
|
|
afterEach(() => {
|
|
vi.useRealTimers();
|
|
});
|
|
|
|
describe("RemoteSessions", () => {
|
|
it("moves parked resources onto the session and releases them on close", () => {
|
|
const sessions = new RemoteSessions();
|
|
const tunnel = vi.fn();
|
|
const tracking = vi.fn();
|
|
sessions.park("c1", [tunnel]);
|
|
sessions.opened(meta, "g1", [tracking]);
|
|
|
|
expect(sessions.byConnect("c1")?.guacamoleConnectionId).toBe("g1");
|
|
expect(sessions.byGuacamole("g1")?.hostName).toBe("Win box");
|
|
expect(tunnel).not.toHaveBeenCalled();
|
|
|
|
sessions.closed("c1");
|
|
expect(tunnel).toHaveBeenCalledOnce();
|
|
expect(tracking).toHaveBeenCalledOnce();
|
|
expect(sessions.byGuacamole("g1")).toBeNull();
|
|
});
|
|
|
|
it("releases a tunnel guacd never used", () => {
|
|
vi.useFakeTimers();
|
|
const sessions = new RemoteSessions(1000);
|
|
const tunnel = vi.fn();
|
|
sessions.park("c1", [tunnel]);
|
|
vi.advanceTimersByTime(1000);
|
|
expect(tunnel).toHaveBeenCalledOnce();
|
|
});
|
|
|
|
it("releases everything on clear, and one failing close does not stop the rest", () => {
|
|
const sessions = new RemoteSessions();
|
|
const failing = vi.fn(() => {
|
|
throw new Error("already closed");
|
|
});
|
|
const pending = vi.fn();
|
|
const open = vi.fn();
|
|
sessions.park("c2", [failing, pending]);
|
|
sessions.park("c1", [open]);
|
|
sessions.opened(meta, "g1");
|
|
sessions.clear();
|
|
expect(pending).toHaveBeenCalledOnce();
|
|
expect(open).toHaveBeenCalledOnce();
|
|
});
|
|
});
|
|
|
|
describe("sessions.live providers", () => {
|
|
const tokens = new GuacamoleTokenService();
|
|
|
|
it("describes a live session of its own protocol only", () => {
|
|
const sessions = new RemoteSessions();
|
|
sessions.opened(meta, "g1");
|
|
const deps = { sessions, tokens, endSession: vi.fn(() => true) };
|
|
const rdp = createLiveSessions("rdp", deps);
|
|
const vnc = createLiveSessions("vnc", deps);
|
|
|
|
expect(rdp.getSession("g1")).toMatchObject({
|
|
id: "g1",
|
|
userId: "user-1",
|
|
hostId: 7,
|
|
hostName: "Win box",
|
|
isConnected: true,
|
|
tabInstanceId: "tab-1",
|
|
});
|
|
expect(vnc.getSession("g1")).toBeNull();
|
|
});
|
|
|
|
it("mints a join token for a viewer and refuses an unknown session", () => {
|
|
const sessions = new RemoteSessions();
|
|
sessions.opened(meta, "g1");
|
|
const rdp = createLiveSessions("rdp", {
|
|
sessions,
|
|
tokens,
|
|
endSession: vi.fn(() => true),
|
|
});
|
|
|
|
const token = tokens.decryptToken(rdp.createViewerToken("g1", true));
|
|
expect(token?.connection).toMatchObject({ join: "g1", readOnly: true });
|
|
expect(token?.recording).toBeUndefined();
|
|
expect(() => rdp.createViewerToken("nope", false)).toThrow();
|
|
});
|
|
|
|
it("ends the session for its owner", () => {
|
|
const sessions = new RemoteSessions();
|
|
sessions.opened(meta, "g1");
|
|
const endSession = vi.fn(() => true);
|
|
const rdp = createLiveSessions("rdp", { sessions, tokens, endSession });
|
|
rdp.ownerEndSession("g1", "owner ended");
|
|
expect(endSession).toHaveBeenCalledWith("g1");
|
|
});
|
|
});
|