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);
});
});