189 lines
6.4 KiB
TypeScript
189 lines
6.4 KiB
TypeScript
|
|
import test from "node:test";
|
||
|
|
import assert from "node:assert/strict";
|
||
|
|
|
||
|
|
import {
|
||
|
|
applyDualPaneSftpOpen,
|
||
|
|
canOpenDualPaneSftp,
|
||
|
|
dualPaneTabFromPane,
|
||
|
|
planDualPaneSftpOpen,
|
||
|
|
type DualPaneSftpTab,
|
||
|
|
} from "./sftpDualPaneOpen.ts";
|
||
|
|
|
||
|
|
const tab = (
|
||
|
|
id: string,
|
||
|
|
options: Partial<DualPaneSftpTab> = {},
|
||
|
|
): DualPaneSftpTab => ({
|
||
|
|
id,
|
||
|
|
isLocal: false,
|
||
|
|
hostId: null,
|
||
|
|
endpointKey: "endpoint-1",
|
||
|
|
hasConnection: true,
|
||
|
|
...options,
|
||
|
|
});
|
||
|
|
|
||
|
|
test("canOpenDualPaneSftp matches the SFTP host picker: not serial, not plugin", () => {
|
||
|
|
assert.equal(canOpenDualPaneSftp({}), true);
|
||
|
|
assert.equal(canOpenDualPaneSftp({ protocol: "ssh" }), true);
|
||
|
|
assert.equal(canOpenDualPaneSftp({ protocol: "mosh" }), true);
|
||
|
|
assert.equal(canOpenDualPaneSftp({ protocol: "telnet" }), true);
|
||
|
|
assert.equal(canOpenDualPaneSftp({ protocol: "serial" }), false);
|
||
|
|
assert.equal(canOpenDualPaneSftp({ protocol: "plugin:example.provider.ssh" }), false);
|
||
|
|
});
|
||
|
|
|
||
|
|
test("planDualPaneSftpOpen connects local left and host right on empty panes", () => {
|
||
|
|
assert.deepEqual(
|
||
|
|
planDualPaneSftpOpen({ leftTabs: [], rightTabs: [], hostId: "host-1", hostEndpointKey: "endpoint-1" }),
|
||
|
|
{
|
||
|
|
selectLeftTabId: null,
|
||
|
|
connectLeftLocal: true,
|
||
|
|
addLeftTab: false,
|
||
|
|
selectRightTabId: null,
|
||
|
|
connectRightHost: true,
|
||
|
|
addRightTab: false,
|
||
|
|
},
|
||
|
|
);
|
||
|
|
});
|
||
|
|
|
||
|
|
test("planDualPaneSftpOpen reuses an existing local left tab and matching right host", () => {
|
||
|
|
const plan = planDualPaneSftpOpen({
|
||
|
|
leftTabs: [tab("left-remote", { hostId: "other" }), tab("left-local", { isLocal: true, hostId: "local" })],
|
||
|
|
rightTabs: [tab("right-host", { hostId: "host-1" })],
|
||
|
|
hostId: "host-1",
|
||
|
|
hostEndpointKey: "endpoint-1",
|
||
|
|
});
|
||
|
|
assert.deepEqual(plan, {
|
||
|
|
selectLeftTabId: "left-local",
|
||
|
|
connectLeftLocal: false,
|
||
|
|
addLeftTab: false,
|
||
|
|
selectRightTabId: "right-host",
|
||
|
|
connectRightHost: false,
|
||
|
|
addRightTab: false,
|
||
|
|
});
|
||
|
|
});
|
||
|
|
|
||
|
|
test("planDualPaneSftpOpen uses idle panes instead of adding tabs", () => {
|
||
|
|
const plan = planDualPaneSftpOpen({
|
||
|
|
leftTabs: [tab("left-idle", { hasConnection: false })],
|
||
|
|
rightTabs: [tab("right-idle", { hasConnection: false })],
|
||
|
|
hostId: "host-1",
|
||
|
|
hostEndpointKey: "endpoint-1",
|
||
|
|
});
|
||
|
|
assert.equal(plan.selectLeftTabId, "left-idle");
|
||
|
|
assert.equal(plan.connectLeftLocal, true);
|
||
|
|
assert.equal(plan.addLeftTab, false);
|
||
|
|
assert.equal(plan.selectRightTabId, "right-idle");
|
||
|
|
assert.equal(plan.connectRightHost, true);
|
||
|
|
assert.equal(plan.addRightTab, false);
|
||
|
|
});
|
||
|
|
|
||
|
|
test("applyDualPaneSftpOpen selects existing tabs without reconnecting", () => {
|
||
|
|
const calls: string[] = [];
|
||
|
|
const plan = applyDualPaneSftpOpen(
|
||
|
|
{
|
||
|
|
leftTabs: [tab("left-local", { isLocal: true, hostId: "local" })],
|
||
|
|
rightTabs: [tab("right-host", { hostId: "host-1" })],
|
||
|
|
selectTab: (side, tabId) => calls.push(`select:${side}:${tabId}`),
|
||
|
|
connect: (side, host, options) => {
|
||
|
|
const target = host === "local" ? "local" : host.id;
|
||
|
|
const mode = options?.forceNewTab ? "new" : (options?.tabId ? `tab:${options.tabId}` : "reuse");
|
||
|
|
calls.push(`connect:${side}:${target}:${mode}`);
|
||
|
|
},
|
||
|
|
},
|
||
|
|
{ id: "host-1" },
|
||
|
|
"endpoint-1",
|
||
|
|
);
|
||
|
|
assert.equal(plan.connectLeftLocal, false);
|
||
|
|
assert.equal(plan.connectRightHost, false);
|
||
|
|
assert.deepEqual(calls, ["select:left:left-local", "select:right:right-host"]);
|
||
|
|
});
|
||
|
|
|
||
|
|
test("dualPaneTabFromPane treats error and disconnected tabs as idle", () => {
|
||
|
|
assert.deepEqual(
|
||
|
|
dualPaneTabFromPane({
|
||
|
|
id: "right-dead",
|
||
|
|
connection: { isLocal: false, hostId: "host-1", status: "error" },
|
||
|
|
}),
|
||
|
|
{ id: "right-dead", isLocal: false, hostId: "host-1", endpointKey: null, hasConnection: false },
|
||
|
|
);
|
||
|
|
assert.deepEqual(
|
||
|
|
dualPaneTabFromPane({
|
||
|
|
id: "right-live",
|
||
|
|
connection: { isLocal: false, hostId: "host-1", status: "connected" },
|
||
|
|
}),
|
||
|
|
{ id: "right-live", isLocal: false, hostId: "host-1", endpointKey: null, hasConnection: true },
|
||
|
|
);
|
||
|
|
});
|
||
|
|
|
||
|
|
test("planDualPaneSftpOpen prefers a matching dead host tab over an earlier idle tab", () => {
|
||
|
|
const idle = tab("right-idle", { hasConnection: false });
|
||
|
|
const dead = dualPaneTabFromPane({
|
||
|
|
id: "right-dead",
|
||
|
|
connection: { isLocal: false, hostId: "host-1", status: "error" },
|
||
|
|
});
|
||
|
|
const plan = planDualPaneSftpOpen({
|
||
|
|
leftTabs: [tab("left-local", { isLocal: true, hostId: "local" })],
|
||
|
|
rightTabs: [idle, dead],
|
||
|
|
hostId: "host-1",
|
||
|
|
hostEndpointKey: "endpoint-1",
|
||
|
|
});
|
||
|
|
assert.equal(plan.selectRightTabId, "right-dead");
|
||
|
|
assert.equal(plan.connectRightHost, true);
|
||
|
|
assert.equal(plan.addRightTab, false);
|
||
|
|
});
|
||
|
|
|
||
|
|
test("planDualPaneSftpOpen reconnects a matching host tab that is no longer live", () => {
|
||
|
|
const dead = dualPaneTabFromPane({
|
||
|
|
id: "right-dead",
|
||
|
|
connection: { isLocal: false, hostId: "host-1", status: "error" },
|
||
|
|
});
|
||
|
|
const plan = planDualPaneSftpOpen({
|
||
|
|
leftTabs: [tab("left-local", { isLocal: true, hostId: "local" })],
|
||
|
|
rightTabs: [dead],
|
||
|
|
hostId: "host-1",
|
||
|
|
hostEndpointKey: "endpoint-1",
|
||
|
|
});
|
||
|
|
assert.deepEqual(plan, {
|
||
|
|
selectLeftTabId: "left-local",
|
||
|
|
connectLeftLocal: false,
|
||
|
|
addLeftTab: false,
|
||
|
|
selectRightTabId: "right-dead",
|
||
|
|
connectRightHost: true,
|
||
|
|
addRightTab: false,
|
||
|
|
});
|
||
|
|
});
|
||
|
|
|
||
|
|
test("applyDualPaneSftpOpen adds tabs when both sides are occupied by other hosts", () => {
|
||
|
|
const calls: string[] = [];
|
||
|
|
applyDualPaneSftpOpen(
|
||
|
|
{
|
||
|
|
leftTabs: [tab("left-remote", { hostId: "other" })],
|
||
|
|
rightTabs: [tab("right-other", { hostId: "other" })],
|
||
|
|
selectTab: (side, tabId) => calls.push(`select:${side}:${tabId}`),
|
||
|
|
connect: (side, host, options) => {
|
||
|
|
const target = host === "local" ? "local" : host.id;
|
||
|
|
const mode = options?.forceNewTab ? "new" : (options?.tabId ? `tab:${options.tabId}` : "reuse");
|
||
|
|
calls.push(`connect:${side}:${target}:${mode}`);
|
||
|
|
},
|
||
|
|
},
|
||
|
|
{ id: "host-1" },
|
||
|
|
"endpoint-1",
|
||
|
|
);
|
||
|
|
assert.deepEqual(calls, [
|
||
|
|
"connect:left:local:new",
|
||
|
|
"connect:right:host-1:new",
|
||
|
|
]);
|
||
|
|
});
|
||
|
|
|
||
|
|
test("planDualPaneSftpOpen does not reuse a live tab after the saved endpoint changes", () => {
|
||
|
|
const plan = planDualPaneSftpOpen({
|
||
|
|
leftTabs: [tab("left-local", { isLocal: true, hostId: "local" })],
|
||
|
|
rightTabs: [tab("right-stale", { hostId: "host-1", endpointKey: "old-endpoint" })],
|
||
|
|
hostId: "host-1",
|
||
|
|
hostEndpointKey: "new-endpoint",
|
||
|
|
});
|
||
|
|
|
||
|
|
assert.equal(plan.selectRightTabId, null);
|
||
|
|
assert.equal(plan.connectRightHost, true);
|
||
|
|
assert.equal(plan.addRightTab, true);
|
||
|
|
});
|