import { assert, describe, it } from "@effect/vitest"; import * as NodeServices from "@effect/platform-node/NodeServices"; import { Duration, Effect, Fiber, Layer, Result, Sink, Stream } from "effect"; import { TestClock } from "effect/testing"; import { ChildProcessSpawner } from "effect/unstable/process"; import { baseSshArgs, getLastNonEmptyOutputLine, parseSshResolveOutput, resolveRemoteT3CliPackageSpec, runSshCommand, } from "./command.ts"; const makeNeverFinishingProcess = () => { let finish: ((exitCode: ChildProcessSpawner.ExitCode) => void) | null = null; return ChildProcessSpawner.makeHandle({ pid: ChildProcessSpawner.ProcessId(123), stdout: Stream.empty, stderr: Stream.empty, all: Stream.empty, exitCode: Effect.callback((resume) => { finish = (exitCode) => resume(Effect.succeed(exitCode)); return Effect.sync(() => { finish = null; }); }), isRunning: Effect.succeed(true), kill: () => Effect.sync(() => { finish?.(ChildProcessSpawner.ExitCode(143)); }), stdin: Sink.drain, getInputFd: () => Sink.drain, getOutputFd: () => Stream.empty, unref: Effect.succeed(Effect.void), }); }; describe("ssh command", () => { it.effect("parses resolved ssh config output into a target", () => Effect.sync(() => { assert.deepEqual( parseSshResolveOutput( "devbox", ["hostname devbox.example.com", "user julius", "port 2222", ""].join("\n"), ), { alias: "devbox", hostname: "devbox.example.com", username: "julius", port: 2222, }, ); }), ); it.effect("builds interactive ssh args without forcing batch mode", () => Effect.sync(() => { assert.deepEqual( baseSshArgs( { alias: "devbox", hostname: "devbox.example.com", username: "julius", port: 2222, }, { batchMode: "no" }, ), ["-o", "BatchMode=no", "-o", "ConnectTimeout=10", "-p", "2222"], ); }), ); it.effect("resolves the remote t3 package spec from the desktop release channel", () => Effect.sync(() => { assert.equal( resolveRemoteT3CliPackageSpec({ appVersion: "0.0.17", updateChannel: "latest", }), "t3@0.0.17", ); assert.equal( resolveRemoteT3CliPackageSpec({ appVersion: "0.0.17-nightly.20260415.44", updateChannel: "nightly", }), "t3@0.0.17-nightly.20260415.44", ); assert.equal( resolveRemoteT3CliPackageSpec({ appVersion: "0.0.0-dev", updateChannel: "nightly", isDevelopment: true, }), "t3@nightly", ); assert.equal( resolveRemoteT3CliPackageSpec({ appVersion: "0.0.0-dev", updateChannel: "latest", isDevelopment: true, }), "t3@nightly", ); }), ); it.effect("reads the last non-empty ssh output line", () => Effect.sync(() => { assert.equal( getLastNonEmptyOutputLine( ["Welcome to the host", "", '{"credential":"pairing-token"}', ""].join("\n"), ), '{"credential":"pairing-token"}', ); }), ); it.effect("fails commands that never finish", () => { const spawner = ChildProcessSpawner.make(() => Effect.succeed(makeNeverFinishingProcess())); const spawnerLayer = Layer.succeed(ChildProcessSpawner.ChildProcessSpawner, spawner); const processLayer = Layer.mergeAll(NodeServices.layer, spawnerLayer, TestClock.layer()); return Effect.gen(function* () { const fiber = yield* Effect.forkChild( Effect.result( runSshCommand( { alias: "devbox", hostname: "devbox.example.com", username: "julius", port: 2222, }, { timeoutMs: 1 }, ), ), ); yield* Effect.yieldNow; yield* TestClock.adjust(Duration.millis(1)); const result = yield* Fiber.join(fiber); assert.isTrue(Result.isFailure(result)); if (Result.isFailure(result)) { assert.include(result.failure.message, "SSH command timed out after 1ms."); } }).pipe(Effect.provide(processLayer)); }); });