151 lines · 4.3 KB · TypeScript
RawDownload
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<ChildProcessSpawner.ExitCode>((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));  });});