import type { OpencodeClient } from "@opencode-ai/sdk/v2";import { it as effectIt } from "@effect/vitest";import * as Effect from "effect/Effect";import * as Fiber from "effect/Fiber";import * as TestClock from "effect/testing/TestClock";import { describe, expect, it } from "vite-plus/test"; import { OpenCodeRuntimeError, resolveOpenCodeConfigContent, resolveOpenCodeServerPassword, verifyOpenCodeServerVersion,} from "./opencodeRuntime.ts"; describe("resolveOpenCodeConfigContent", () => { it("prefers the caller environment over the inherited environment", () => { expect( resolveOpenCodeConfigContent( { OPENCODE_CONFIG_CONTENT: '{"source":"caller"}' }, { OPENCODE_CONFIG_CONTENT: '{"source":"process"}' }, ), ).toBe('{"source":"caller"}'); }); it("falls back to the inherited environment and then an empty config", () => { expect( resolveOpenCodeConfigContent(undefined, { OPENCODE_CONFIG_CONTENT: '{"source":"process"}', }), ).toBe('{"source":"process"}'); expect(resolveOpenCodeConfigContent(undefined, {})).toBe("{}"); });}); describe("resolveOpenCodeServerPassword", () => { it("uses the local environment password when settings do not provide one", () => { expect( resolveOpenCodeServerPassword( { external: false, environment: { OPENCODE_SERVER_PASSWORD: " env password " } }, {}, ), ).toBe(" env password "); }); it("uses the settings password for a local server", () => { expect( resolveOpenCodeServerPassword({ external: false, serverPassword: " settings password " }, {}), ).toBe(" settings password "); }); it("uses the settings password when local settings and environment differ", () => { expect( resolveOpenCodeServerPassword( { external: false, serverPassword: "settings-password", environment: { OPENCODE_SERVER_PASSWORD: "environment-password" }, }, {}, ), ).toBe("settings-password"); }); it("does not send an inherited local password to an external server", () => { expect( resolveOpenCodeServerPassword( { external: true, environment: { OPENCODE_SERVER_PASSWORD: "local-secret" } }, { OPENCODE_SERVER_PASSWORD: "inherited-secret" }, ), ).toBeUndefined(); });}); function makeHealthClient( result: (options?: { readonly signal?: AbortSignal }) => Promise<unknown>,): OpencodeClient { return { global: { health: result, }, } as unknown as OpencodeClient;} describe("verifyOpenCodeServerVersion", () => { effectIt.effect("accepts a supported server version", () => Effect.gen(function* () { const version = yield* verifyOpenCodeServerVersion( makeHealthClient(() => Promise.resolve({ data: { healthy: true, version: "1.14.19" } })), ); expect(version).toBe("1.14.19"); }), ); effectIt.effect("rejects a server below the supported version", () => Effect.gen(function* () { const error = yield* verifyOpenCodeServerVersion( makeHealthClient(() => Promise.resolve({ data: { healthy: true, version: "1.14.18" } })), ).pipe(Effect.flip); expect(error).toBeInstanceOf(OpenCodeRuntimeError); expect(error.detail).toContain("v1.14.18 is too old"); }), ); for (const data of [ { healthy: true }, { healthy: true, version: "not-a-version" }, { healthy: false, version: "1.14.19" }, ]) { effectIt.effect(`rejects an invalid health response: ${JSON.stringify(data)}`, () => Effect.gen(function* () { const error = yield* verifyOpenCodeServerVersion( makeHealthClient(() => Promise.resolve({ data })), ).pipe(Effect.flip); expect(error).toBeInstanceOf(OpenCodeRuntimeError); expect(error.detail).toContain("requires OpenCode v1.14.19 or newer"); }), ); } effectIt.effect("preserves an unauthorized health error", () => Effect.gen(function* () { const error = yield* verifyOpenCodeServerVersion( makeHealthClient(() => Promise.reject({ response: { status: 401 }, error: { message: "Unauthorized" } }), ), ).pipe(Effect.flip); expect(error).toBeInstanceOf(OpenCodeRuntimeError); expect(error.detail).toContain("status=401"); expect(error.detail).toContain("Unauthorized"); }), ); effectIt.effect("aborts a health request when the version check times out", () => Effect.gen(function* () { let requestSignal: AbortSignal | undefined; const checkFiber = yield* verifyOpenCodeServerVersion( makeHealthClient((options) => { requestSignal = options?.signal; return new Promise(() => undefined); }), ).pipe(Effect.flip, Effect.forkChild); yield* Effect.yieldNow; expect(requestSignal).toBeDefined(); yield* TestClock.adjust("6 seconds"); const error = yield* Fiber.join(checkFiber); expect(error.detail).toBe("Timed out while checking the OpenCode server version."); expect(requestSignal?.aborted).toBe(true); }).pipe(Effect.provide(TestClock.layer())), );});
import type { OpencodeClient } from "@opencode-ai/sdk/v2";
import { it as effectIt } from "@effect/vitest";
import * as Effect from "effect/Effect";
import * as Fiber from "effect/Fiber";
import * as TestClock from "effect/testing/TestClock";
import { describe, expect, it } from "vite-plus/test";
import {
OpenCodeRuntimeError,
resolveOpenCodeConfigContent,
resolveOpenCodeServerPassword,
verifyOpenCodeServerVersion,
} from "./opencodeRuntime.ts";
describe("resolveOpenCodeConfigContent", () => {
it("prefers the caller environment over the inherited environment", () => {
expect(
resolveOpenCodeConfigContent(
{ OPENCODE_CONFIG_CONTENT: '{"source":"caller"}' },
{ OPENCODE_CONFIG_CONTENT: '{"source":"process"}' },
),
).toBe('{"source":"caller"}');
});
it("falls back to the inherited environment and then an empty config", () => {
expect(
resolveOpenCodeConfigContent(undefined, {
OPENCODE_CONFIG_CONTENT: '{"source":"process"}',
}),
).toBe('{"source":"process"}');
expect(resolveOpenCodeConfigContent(undefined, {})).toBe("{}");
});
});
describe("resolveOpenCodeServerPassword", () => {
it("uses the local environment password when settings do not provide one", () => {
expect(
resolveOpenCodeServerPassword(
{ external: false, environment: { OPENCODE_SERVER_PASSWORD: " env password " } },
{},
),
).toBe(" env password ");
});
it("uses the settings password for a local server", () => {
expect(
resolveOpenCodeServerPassword({ external: false, serverPassword: " settings password " }, {}),
).toBe(" settings password ");
});
it("uses the settings password when local settings and environment differ", () => {
expect(
resolveOpenCodeServerPassword(
{
external: false,
serverPassword: "settings-password",
environment: { OPENCODE_SERVER_PASSWORD: "environment-password" },
},
{},
),
).toBe("settings-password");
});
it("does not send an inherited local password to an external server", () => {
expect(
resolveOpenCodeServerPassword(
{ external: true, environment: { OPENCODE_SERVER_PASSWORD: "local-secret" } },
{ OPENCODE_SERVER_PASSWORD: "inherited-secret" },
),
).toBeUndefined();
});
});
function makeHealthClient(
result: (options?: { readonly signal?: AbortSignal }) => Promise<unknown>,
): OpencodeClient {
return {
global: {
health: result,
},
} as unknown as OpencodeClient;
}
describe("verifyOpenCodeServerVersion", () => {
effectIt.effect("accepts a supported server version", () =>
Effect.gen(function* () {
const version = yield* verifyOpenCodeServerVersion(
makeHealthClient(() => Promise.resolve({ data: { healthy: true, version: "1.14.19" } })),
);
expect(version).toBe("1.14.19");
}),
);
effectIt.effect("rejects a server below the supported version", () =>
Effect.gen(function* () {
const error = yield* verifyOpenCodeServerVersion(
makeHealthClient(() => Promise.resolve({ data: { healthy: true, version: "1.14.18" } })),
).pipe(Effect.flip);
expect(error).toBeInstanceOf(OpenCodeRuntimeError);
expect(error.detail).toContain("v1.14.18 is too old");
}),
);
for (const data of [
{ healthy: true },
{ healthy: true, version: "not-a-version" },
{ healthy: false, version: "1.14.19" },
]) {
effectIt.effect(`rejects an invalid health response: ${JSON.stringify(data)}`, () =>
Effect.gen(function* () {
const error = yield* verifyOpenCodeServerVersion(
makeHealthClient(() => Promise.resolve({ data })),
).pipe(Effect.flip);
expect(error).toBeInstanceOf(OpenCodeRuntimeError);
expect(error.detail).toContain("requires OpenCode v1.14.19 or newer");
}),
);
}
effectIt.effect("preserves an unauthorized health error", () =>
Effect.gen(function* () {
const error = yield* verifyOpenCodeServerVersion(
makeHealthClient(() =>
Promise.reject({ response: { status: 401 }, error: { message: "Unauthorized" } }),
),
).pipe(Effect.flip);
expect(error).toBeInstanceOf(OpenCodeRuntimeError);
expect(error.detail).toContain("status=401");
expect(error.detail).toContain("Unauthorized");
}),
);
effectIt.effect("aborts a health request when the version check times out", () =>
Effect.gen(function* () {
let requestSignal: AbortSignal | undefined;
const checkFiber = yield* verifyOpenCodeServerVersion(
makeHealthClient((options) => {
requestSignal = options?.signal;
return new Promise(() => undefined);
}),
).pipe(Effect.flip, Effect.forkChild);
yield* Effect.yieldNow;
expect(requestSignal).toBeDefined();
yield* TestClock.adjust("6 seconds");
const error = yield* Fiber.join(checkFiber);
expect(error.detail).toBe("Timed out while checking the OpenCode server version.");
expect(requestSignal?.aborted).toBe(true);
}).pipe(Effect.provide(TestClock.layer())),
);
});