From 762850dfe54da2eead25f8d5a4610ed9e715a4d5 Mon Sep 17 00:00:00 2001 From: Kit Langton Date: Mon, 18 May 2026 13:22:59 -0400 Subject: [PATCH] Migrate provider config tests to instance fixtures Convert the first provider env/config/filtering tests to Effect-aware instance fixtures while keeping behavior unchanged and documenting neutral timing. --- .../opencode/test/provider/provider.test.ts | 235 +++++++----------- perf/test-suite.md | 1 + 2 files changed, 91 insertions(+), 145 deletions(-) diff --git a/packages/opencode/test/provider/provider.test.ts b/packages/opencode/test/provider/provider.test.ts index c109284070..fb18b4457f 100644 --- a/packages/opencode/test/provider/provider.test.ts +++ b/packages/opencode/test/provider/provider.test.ts @@ -29,6 +29,12 @@ function rememberEnv(k: string) { if (!originalEnv.has(k)) originalEnv.set(k, process.env[k]) } +const setProcessEnv = (k: string, v: string) => + Effect.sync(() => { + rememberEnv(k) + process.env[k] = v + }) + const set = (ctx: InstanceContext, k: string, v: string) => { rememberEnv(k) process.env[k] = v @@ -128,160 +134,99 @@ const alphaProviderConfig = { }, } -test("provider loaded from env variable", async () => { - await using tmp = await tmpdir({ - init: async (dir) => { - await Bun.write( - path.join(dir, "opencode.json"), - JSON.stringify({ - $schema: "https://opencode.ai/config.json", - }), - ) - }, - }) - await withTestInstance({ - directory: tmp.path, - fn: async (ctx) => { - await set(ctx, "ANTHROPIC_API_KEY", "test-api-key") - const providers = await list(ctx) - expect(providers[ProviderID.anthropic]).toBeDefined() - // Provider should retain its connection source even if custom loaders - // merge additional options. - expect(providers[ProviderID.anthropic].source).toBe("env") - expect(providers[ProviderID.anthropic].options.headers["anthropic-beta"]).toBeDefined() - }, - }) -}) +it.instance("provider loaded from env variable", () => + Effect.gen(function* () { + yield* setProcessEnv("ANTHROPIC_API_KEY", "test-api-key") + const providers = yield* Provider.Service.use((provider) => provider.list()) + expect(providers[ProviderID.anthropic]).toBeDefined() + // Provider should retain its connection source even if custom loaders + // merge additional options. + expect(providers[ProviderID.anthropic].source).toBe("env") + expect(providers[ProviderID.anthropic].options.headers["anthropic-beta"]).toBeDefined() + }), +) -test("provider loaded from config with apiKey option", async () => { - await using tmp = await tmpdir({ - init: async (dir) => { - await Bun.write( - path.join(dir, "opencode.json"), - JSON.stringify({ - $schema: "https://opencode.ai/config.json", - provider: { - anthropic: { - options: { - apiKey: "config-api-key", - }, - }, +it.instance( + "provider loaded from config with apiKey option", + Effect.gen(function* () { + const providers = yield* Provider.Service.use((provider) => provider.list()) + expect(providers[ProviderID.anthropic]).toBeDefined() + }), + { + config: { + provider: { + anthropic: { + options: { + apiKey: "config-api-key", }, - }), - ) + }, + }, }, - }) - await withTestInstance({ - directory: tmp.path, - fn: async (ctx) => { - const providers = await list(ctx) - expect(providers[ProviderID.anthropic]).toBeDefined() - }, - }) -}) + }, +) -test("disabled_providers excludes provider", async () => { - await using tmp = await tmpdir({ - init: async (dir) => { - await Bun.write( - path.join(dir, "opencode.json"), - JSON.stringify({ - $schema: "https://opencode.ai/config.json", - disabled_providers: ["anthropic"], - }), - ) - }, - }) - await withTestInstance({ - directory: tmp.path, - fn: async (ctx) => { - await set(ctx, "ANTHROPIC_API_KEY", "test-api-key") - const providers = await list(ctx) - expect(providers[ProviderID.anthropic]).toBeUndefined() - }, - }) -}) +it.instance( + "disabled_providers excludes provider", + Effect.gen(function* () { + yield* setProcessEnv("ANTHROPIC_API_KEY", "test-api-key") + const providers = yield* Provider.Service.use((provider) => provider.list()) + expect(providers[ProviderID.anthropic]).toBeUndefined() + }), + { config: { disabled_providers: ["anthropic"] } }, +) -test("enabled_providers restricts to only listed providers", async () => { - await using tmp = await tmpdir({ - init: async (dir) => { - await Bun.write( - path.join(dir, "opencode.json"), - JSON.stringify({ - $schema: "https://opencode.ai/config.json", - enabled_providers: ["anthropic"], - }), - ) - }, - }) - await withTestInstance({ - directory: tmp.path, - fn: async (ctx) => { - await set(ctx, "ANTHROPIC_API_KEY", "test-api-key") - await set(ctx, "OPENAI_API_KEY", "test-openai-key") - const providers = await list(ctx) - expect(providers[ProviderID.anthropic]).toBeDefined() - expect(providers[ProviderID.openai]).toBeUndefined() - }, - }) -}) +it.instance( + "enabled_providers restricts to only listed providers", + Effect.gen(function* () { + yield* setProcessEnv("ANTHROPIC_API_KEY", "test-api-key") + yield* setProcessEnv("OPENAI_API_KEY", "test-openai-key") + const providers = yield* Provider.Service.use((provider) => provider.list()) + expect(providers[ProviderID.anthropic]).toBeDefined() + expect(providers[ProviderID.openai]).toBeUndefined() + }), + { config: { enabled_providers: ["anthropic"] } }, +) -test("model whitelist filters models for provider", async () => { - await using tmp = await tmpdir({ - init: async (dir) => { - await Bun.write( - path.join(dir, "opencode.json"), - JSON.stringify({ - $schema: "https://opencode.ai/config.json", - provider: { - anthropic: { - whitelist: ["claude-sonnet-4-20250514"], - }, - }, - }), - ) +it.instance( + "model whitelist filters models for provider", + Effect.gen(function* () { + yield* setProcessEnv("ANTHROPIC_API_KEY", "test-api-key") + const providers = yield* Provider.Service.use((provider) => provider.list()) + expect(providers[ProviderID.anthropic]).toBeDefined() + const models = Object.keys(providers[ProviderID.anthropic].models) + expect(models).toContain("claude-sonnet-4-20250514") + expect(models.length).toBe(1) + }), + { + config: { + provider: { + anthropic: { + whitelist: ["claude-sonnet-4-20250514"], + }, + }, }, - }) - await withTestInstance({ - directory: tmp.path, - fn: async (ctx) => { - await set(ctx, "ANTHROPIC_API_KEY", "test-api-key") - const providers = await list(ctx) - expect(providers[ProviderID.anthropic]).toBeDefined() - const models = Object.keys(providers[ProviderID.anthropic].models) - expect(models).toContain("claude-sonnet-4-20250514") - expect(models.length).toBe(1) - }, - }) -}) + }, +) -test("model blacklist excludes specific models", async () => { - await using tmp = await tmpdir({ - init: async (dir) => { - await Bun.write( - path.join(dir, "opencode.json"), - JSON.stringify({ - $schema: "https://opencode.ai/config.json", - provider: { - anthropic: { - blacklist: ["claude-sonnet-4-20250514"], - }, - }, - }), - ) +it.instance( + "model blacklist excludes specific models", + Effect.gen(function* () { + yield* setProcessEnv("ANTHROPIC_API_KEY", "test-api-key") + const providers = yield* Provider.Service.use((provider) => provider.list()) + expect(providers[ProviderID.anthropic]).toBeDefined() + const models = Object.keys(providers[ProviderID.anthropic].models) + expect(models).not.toContain("claude-sonnet-4-20250514") + }), + { + config: { + provider: { + anthropic: { + blacklist: ["claude-sonnet-4-20250514"], + }, + }, }, - }) - await withTestInstance({ - directory: tmp.path, - fn: async (ctx) => { - await set(ctx, "ANTHROPIC_API_KEY", "test-api-key") - const providers = await list(ctx) - expect(providers[ProviderID.anthropic]).toBeDefined() - const models = Object.keys(providers[ProviderID.anthropic].models) - expect(models).not.toContain("claude-sonnet-4-20250514") - }, - }) -}) + }, +) test("custom model alias via config", async () => { await using tmp = await tmpdir({ diff --git a/perf/test-suite.md b/perf/test-suite.md index f01e11505a..4be7d6ba6f 100644 --- a/perf/test-suite.md +++ b/perf/test-suite.md @@ -68,6 +68,7 @@ Repeated setup work, long sleeps/timeouts, serial integration tests, filesystem/ | Session processor effect tests do not require repository state | Removed git setup from all processor-effect temp server fixtures | 12.500s | 9.230s | keep | Two targeted reruns passed after the change: 9.61s, 9.23s. | | HTTP listen PTY ticket tests restart the same listener topology twice | Folded directory-scoped ticket regression into the broader unsafe-ticket test | 7.051s | 6.170s | keep | Two targeted reruns passed after the change: 6.76s, 6.17s; still covers mint failure and successful same-directory upgrade. | | File watcher readiness can write before async native subscriptions are active | Retried short readiness writes and accepted symlink-realpath HEAD events | failed | 4.62s | keep | Three sequential focused watcher runs passed: 4.62s, 4.57s, 4.64s; full suite no longer failed in `watcher.test.ts`. | +| First provider config/env/filtering block can use Effect-aware instance fixtures | Migrated six `tmpdir` + `withTestInstance` cases to `it.instance` | 6.06s | 6.07s | keep | Neutral timing, but removes manual config file writes and instance plumbing; use as the pattern for later provider slices. | ## Profiling Results