158 lines · 6.6 KB · TypeScript
RawDownload
import { assert, describe, it } from "@effect/vitest";import * as Duration from "effect/Duration";import * as Effect from "effect/Effect";import * as FileSystem from "effect/FileSystem";import * as Layer from "effect/Layer";import * as Option from "effect/Option";import * as Ref from "effect/Ref";import * as Stream from "effect/Stream";import { HttpClient } from "effect/unstable/http";import { ChildProcessSpawner } from "effect/unstable/process"; import * as DesktopObservability from "../app/DesktopObservability.ts";import * as DesktopAppSettings from "../settings/DesktopAppSettings.ts";import * as DesktopTelemetryPublisher from "../telemetry/DesktopTelemetryPublisher.ts";import * as ElectronDialog from "../electron/ElectronDialog.ts";import * as DesktopWindow from "../window/DesktopWindow.ts";import * as DesktopWslEnvironment from "../wsl/DesktopWslEnvironment.ts";import * as DesktopBackendConfiguration from "./DesktopBackendConfiguration.ts";import * as DesktopBackendPool from "./DesktopBackendPool.ts";import type { DesktopBackendSnapshot, DesktopBackendStartConfig } from "./DesktopBackendManager.ts"; function makeStubInstance(  id: DesktopBackendPool.BackendInstanceId,  label: string,): DesktopBackendPool.DesktopBackendInstance {  const snapshot: DesktopBackendSnapshot = {    desiredRunning: false,    ready: false,    activePid: Option.none(),    restartAttempt: 0,    restartScheduled: false,  };  return {    id,    label: Effect.succeed(label),    start: Effect.void,    stop: () => Effect.void,    currentConfig: Effect.succeed(Option.none<DesktopBackendStartConfig>()),    snapshot: Effect.succeed(snapshot),    waitForReady: (_timeout: Duration.Duration) => Effect.succeed(false),  };} function makePoolLayer(  labelRef: Ref.Ref<string>,): Layer.Layer<DesktopBackendPool.DesktopBackendPool> {  return DesktopBackendPool.layer.pipe(    Layer.provideMerge(      Layer.mergeAll(        FileSystem.layerNoop({}),        Layer.succeed(          ChildProcessSpawner.ChildProcessSpawner,          ChildProcessSpawner.make(() => Effect.die("unexpected child process spawn")),        ),        Layer.succeed(          HttpClient.HttpClient,          HttpClient.make(() => Effect.die("unexpected HTTP request")),        ),        Layer.succeed(DesktopObservability.DesktopBackendOutputLogFactory, {          forInstance: () =>            Effect.succeed({              beginSession: () => Effect.void,              writeOutputChunk: () => Effect.void,              persistFailureSnapshot: () => Effect.void,              persistFailure: () => Effect.void,              discardSession: Effect.void,            } satisfies DesktopObservability.DesktopBackendOutputLogShape),        } satisfies DesktopObservability.DesktopBackendOutputLogFactory["Service"]),        Layer.succeed(DesktopTelemetryPublisher.DesktopTelemetryPublisher, {          latest: Effect.succeed(Option.none()),          changes: Stream.empty,          encoded: Stream.empty,          handleControl: () => Effect.void,          handleControlForSource: () => Effect.void,          removeControlSource: () => Effect.void,          publishUpdateReport: () => Effect.void,          updateRequests: Stream.empty,          updateCommits: Stream.empty,          updateCancellations: Stream.empty,        }),        Layer.succeed(DesktopBackendConfiguration.DesktopBackendConfiguration, {          resolvePrimary: Effect.die("unexpected primary config resolve"),          resolvePrimaryLabel: Ref.get(labelRef),          resolveWsl: () => Effect.die("unexpected WSL config resolve"),        } satisfies DesktopBackendConfiguration.DesktopBackendConfiguration["Service"]),        DesktopAppSettings.layerTest(),        DesktopWslEnvironment.layerTest(),        ElectronDialog.layer,        Layer.succeed(DesktopWindow.DesktopWindow, {          createMain: Effect.die("unexpected window create"),          ensureMain: Effect.die("unexpected window ensure"),          revealOrCreateMain: Effect.die("unexpected window reveal"),          activate: Effect.die("unexpected window activate"),          createMainIfBackendReady: Effect.die("unexpected window create"),          showConnectingSplash: Effect.void,          handleBackendReady: () => Effect.void,          handleBackendNotReady: Effect.void,          flushMainWindowBounds: Effect.void,          dispatchMenuAction: () => Effect.die("unexpected menu action"),          zoomMain: () => Effect.die("unexpected zoom"),          syncAppearance: Effect.void,        } satisfies DesktopWindow.DesktopWindow["Service"]),      ),    ),  );} describe("DesktopBackendPool", () => {  it.effect("layerTest exposes registered instances by id", () =>    Effect.gen(function* () {      const pool = yield* DesktopBackendPool.DesktopBackendPool;      const fetchedPrimary = yield* pool.get(DesktopBackendPool.PRIMARY_INSTANCE_ID);      const fetchedWsl = yield* pool.get(DesktopBackendPool.BackendInstanceId("wsl:ubuntu"));      const fetchedMissing = yield* pool.get(DesktopBackendPool.BackendInstanceId("missing"));      const all = yield* pool.list;      const resolvedPrimary = yield* pool.primary;       assert.equal(yield* Option.getOrThrow(fetchedPrimary).label, "Windows");      assert.equal(yield* Option.getOrThrow(fetchedWsl).label, "WSL (Ubuntu)");      assert.isTrue(Option.isNone(fetchedMissing));      assert.lengthOf(all, 2);      // First instance becomes primary in layerTest so single-instance      // stubs don't have to wire an explicit primary.      assert.equal(resolvedPrimary.id, DesktopBackendPool.PRIMARY_INSTANCE_ID);    }).pipe(      Effect.provide(        DesktopBackendPool.layerTest([          makeStubInstance(DesktopBackendPool.PRIMARY_INSTANCE_ID, "Windows"),          makeStubInstance(DesktopBackendPool.BackendInstanceId("wsl:ubuntu"), "WSL (Ubuntu)"),        ]),      ),    ),  );   it.effect("layerTest dies when no instances are supplied", () =>    Effect.exit(      Effect.gen(function* () {        yield* DesktopBackendPool.DesktopBackendPool;      }).pipe(Effect.provide(DesktopBackendPool.layerTest([]))),    ).pipe(Effect.map((exit) => assert.equal(exit._tag, "Failure"))),  );   it.effect("resolves the primary label lazily after pool layer construction", () =>    Effect.scoped(      Effect.gen(function* () {        const labelRef = yield* Ref.make("Windows");        const pool = yield* DesktopBackendPool.DesktopBackendPool.pipe(          Effect.provide(makePoolLayer(labelRef)),        );        const primary = yield* pool.primary;         yield* Ref.set(labelRef, "WSL (Ubuntu)");         assert.equal(yield* primary.label, "WSL (Ubuntu)");      }),    ),  );});