mirror of
https://github.com/Termix-SSH/Termix.git
synced 2026-10-30 23:25:24 +00:00
feat: convert ssh tunnels into a plugin
This commit is contained in:
1 parent
c85c1fdb86
commit
1682861853
220 files changed
+36928
-11374
No files matched your search
@@ -0,0 +1,90 @@
|
||||
import { afterEach, describe, expect, it, vi } from "vitest";
|
||||
import { createFakeContext } from "@termix/plugin-sdk/testing";
|
||||
|
||||
vi.mock("../../../../src/backend/database/repositories/factory.js", () => ({
|
||||
createCurrentNotificationChannelRepository: vi.fn(),
|
||||
}));
|
||||
|
||||
const { setTunnelServices } = await import("../../src/backend/tunnels.js");
|
||||
const { executeStep } = await import("../../src/backend/actions/index.js");
|
||||
|
||||
afterEach(() => {
|
||||
setTunnelServices(null);
|
||||
});
|
||||
|
||||
function context(dryRun = false) {
|
||||
return {
|
||||
userId: "user-1",
|
||||
automationId: 1,
|
||||
runId: 1,
|
||||
dryRun,
|
||||
template: {},
|
||||
} as never;
|
||||
}
|
||||
|
||||
const step = (action: "connect" | "disconnect") =>
|
||||
({
|
||||
id: "s1",
|
||||
type: "tunnel",
|
||||
action,
|
||||
tunnelName: "7::0::web::8080::db::5432",
|
||||
}) as never;
|
||||
|
||||
describe("the tunnel step", () => {
|
||||
it("starts and stops the tunnel through tunnels.access as the automation's owner", async () => {
|
||||
const fake = createFakeContext({ pluginId: "automations" });
|
||||
const tunnels = {
|
||||
start: vi.fn(async () => undefined),
|
||||
stop: vi.fn(async () => undefined),
|
||||
};
|
||||
fake.ctx.services.provide("tunnels.access", tunnels);
|
||||
const get = vi.spyOn(fake.ctx.services, "get");
|
||||
setTunnelServices(fake.ctx.services);
|
||||
|
||||
const connected = await executeStep(step("connect"), context());
|
||||
expect(connected.success).toBe(true);
|
||||
expect(tunnels.start).toHaveBeenCalledWith("7::0::web::8080::db::5432");
|
||||
expect(get).toHaveBeenCalledWith("tunnels.access", { userId: "user-1" });
|
||||
|
||||
const stopped = await executeStep(step("disconnect"), context());
|
||||
expect(stopped.success).toBe(true);
|
||||
expect(tunnels.stop).toHaveBeenCalledWith("7::0::web::8080::db::5432");
|
||||
});
|
||||
|
||||
it("reports the tunnel plugin's own error", async () => {
|
||||
const fake = createFakeContext({ pluginId: "automations" });
|
||||
fake.ctx.services.provide("tunnels.access", {
|
||||
start: vi.fn(async () => {
|
||||
throw new Error('Tunnel "x" is not configured');
|
||||
}),
|
||||
stop: vi.fn(),
|
||||
});
|
||||
setTunnelServices(fake.ctx.services);
|
||||
|
||||
const result = await executeStep(step("connect"), context());
|
||||
expect(result.success).toBe(false);
|
||||
expect(result.error ?? result.output).toMatch(/not configured/);
|
||||
});
|
||||
|
||||
it("fails the step cleanly while the tunnels plugin is off", async () => {
|
||||
// No provider: the optional dependency is missing.
|
||||
setTunnelServices(
|
||||
createFakeContext({ pluginId: "automations" }).ctx.services,
|
||||
);
|
||||
const withoutProvider = await executeStep(step("connect"), context());
|
||||
expect(withoutProvider.success).toBe(false);
|
||||
expect(withoutProvider.error ?? withoutProvider.output).toMatch(
|
||||
/tunnels plugin is not available/,
|
||||
);
|
||||
|
||||
setTunnelServices(null);
|
||||
const inactive = await executeStep(step("disconnect"), context());
|
||||
expect(inactive.success).toBe(false);
|
||||
});
|
||||
|
||||
it("only describes what it would do on a dry run", async () => {
|
||||
const result = await executeStep(step("connect"), context(true));
|
||||
expect(result.success).toBe(true);
|
||||
expect(result.output).toMatch(/Would connect tunnel/);
|
||||
});
|
||||
});
|
||||
Reference in new issue
Block a user