import { mkdtempSync, rmSync } from "node:fs"; import { mkdir, readFile, rm, writeFile } from "node:fs/promises"; import { tmpdir } from "node:os"; import { join } from "node:path"; import { describe, expect, it } from "@effect/vitest"; import { Effect, FileSystem, Layer, Path, PlatformError } from "effect"; import { acquireDaemonStartLock, canonicalDaemonHost, currentDaemonScopeId, isPidAlive, readDaemonPointer, readDaemonRecord, releaseDaemonStartLock, removeDaemonPointer, removeDaemonRecord, writeDaemonPointer, writeDaemonRecord, } from "../apps/cli/src/daemon-state"; const fileSystemError = (method: string, cause: unknown) => PlatformError.systemError({ _tag: "Unknown", module: "FileSystem", method, description: "FileSystem operation failed", cause, }); const fileSystemLayer = FileSystem.layerNoop({ makeDirectory: (path, options) => Effect.tryPromise({ try: () => mkdir(path, { recursive: options?.recursive, mode: options?.mode }), catch: (cause) => fileSystemError("makeDirectory", cause), }), writeFileString: (path, data, options) => Effect.tryPromise({ try: () => writeFile(path, data, { encoding: "utf8", flag: options?.flag }), catch: (cause) => fileSystemError("writeFileString", cause), }), readFileString: (path, encoding = "utf8") => Effect.tryPromise({ try: () => readFile(path, { encoding: encoding as BufferEncoding }), catch: (cause) => fileSystemError("readFileString", cause), }), remove: (path, options) => Effect.tryPromise({ try: () => rm(path, { recursive: options?.recursive ?? false, force: options?.force ?? false }), catch: (cause) => fileSystemError("remove", cause), }), }); const daemonStateLayer = Layer.merge(fileSystemLayer, Path.layer); const withDaemonDataDir = (effect: Effect.Effect) => Effect.acquireUseRelease( Effect.sync(() => { const prev = process.env.EXECUTOR_DATA_DIR; const dir = mkdtempSync(join(tmpdir(), "executor-daemon-state-test-")); process.env.EXECUTOR_DATA_DIR = dir; return { dir, prev }; }), () => effect, ({ dir, prev }) => Effect.sync(() => { if (prev === undefined) { delete process.env.EXECUTOR_DATA_DIR; } else { process.env.EXECUTOR_DATA_DIR = prev; } rmSync(dir, { recursive: true, force: true }); }), ).pipe(Effect.provide(daemonStateLayer)); describe("daemon state", () => { it("normalizes local host aliases", () => { expect(canonicalDaemonHost("localhost")).toBe("localhost"); expect(canonicalDaemonHost("127.0.0.1")).toBe("localhost"); expect(canonicalDaemonHost("::1")).toBe("localhost"); expect(canonicalDaemonHost("0.0.0.0")).toBe("localhost"); expect(canonicalDaemonHost("api.example.com")).toBe("api.example.com"); }); it.effect("writes, reads, and removes daemon records", () => withDaemonDataDir( Effect.gen(function* () { yield* writeDaemonRecord({ hostname: "127.0.0.1", port: 4788, pid: 12345, scopeDir: "/tmp/scope", }); const stored = yield* readDaemonRecord({ hostname: "localhost", port: 4788 }); expect(stored).toEqual({ version: 1, hostname: "localhost", port: 4788, pid: 12345, startedAt: expect.any(String), scopeDir: "/tmp/scope", }); yield* removeDaemonRecord({ hostname: "localhost", port: 4788 }); const after = yield* readDaemonRecord({ hostname: "localhost", port: 4788 }); expect(after).toBeNull(); }), ), ); it.effect("writes, reads, and removes daemon pointers", () => withDaemonDataDir( Effect.gen(function* () { yield* writeDaemonPointer({ hostname: "127.0.0.1", port: 5799, pid: 24680, scopeId: "scope:/tmp/project", scopeDir: "/tmp/project", token: "tok_123", }); const stored = yield* readDaemonPointer({ hostname: "localhost", scopeId: "scope:/tmp/project", }); expect(stored).toEqual({ version: 1, hostname: "localhost", port: 5799, pid: 24680, startedAt: expect.any(String), scopeId: "scope:/tmp/project", scopeDir: "/tmp/project", token: "tok_123", }); yield* removeDaemonPointer({ hostname: "localhost", scopeId: "scope:/tmp/project", }); const after = yield* readDaemonPointer({ hostname: "localhost", scopeId: "scope:/tmp/project", }); expect(after).toBeNull(); }), ), ); it.effect("serializes daemon startup with lock files", () => withDaemonDataDir( Effect.gen(function* () { const lock = yield* acquireDaemonStartLock({ hostname: "localhost", scopeId: "scope:/tmp/project", }); const second = yield* acquireDaemonStartLock({ hostname: "localhost", scopeId: "scope:/tmp/project", }).pipe(Effect.flip); expect(second.message).toContain("already in progress"); yield* releaseDaemonStartLock(lock); const third = yield* acquireDaemonStartLock({ hostname: "localhost", scopeId: "scope:/tmp/project", }); yield* releaseDaemonStartLock(third); }), ), ); it("derives scope id from EXECUTOR_SCOPE_DIR or cwd", () => { const prev = process.env.EXECUTOR_SCOPE_DIR; process.env.EXECUTOR_SCOPE_DIR = "/tmp/explicit-scope"; expect(currentDaemonScopeId()).toBe("scope:/tmp/explicit-scope"); if (prev === undefined) { delete process.env.EXECUTOR_SCOPE_DIR; } else { process.env.EXECUTOR_SCOPE_DIR = prev; } expect(currentDaemonScopeId()).toContain("cwd:"); }); it("detects live and invalid pids", () => { expect(isPidAlive(process.pid)).toBe(true); expect(isPidAlive(-1)).toBe(false); }); });