test(provider): migrate DigitalOcean provider test to Effect runner (#27232)

This commit is contained in:
Kit Langton
2026-05-12 22:51:11 -04:00
committed by GitHub
parent e3684f36f9
commit 03cf833236

View File

@@ -1,132 +1,122 @@
import { test, expect, afterEach } from "bun:test" import { expect } from "bun:test"
import path from "path"
import { tmpdir } from "../fixture/fixture"
import { WithInstance } from "../../src/project/with-instance"
import { Provider } from "../../src/provider/provider" import { Provider } from "../../src/provider/provider"
import { ProviderID } from "../../src/provider/schema" import { ProviderID } from "../../src/provider/schema"
import { Env } from "../../src/env"
import { Effect } from "effect" import { Effect } from "effect"
import { AppRuntime } from "../../src/effect/app-runtime" import { testEffect } from "../lib/effect"
import { makeRuntime } from "../../src/effect/run-service"
const envRuntime = makeRuntime(Env.Service, Env.defaultLayer)
const set = (k: string, v: string) => envRuntime.runSync((svc) => svc.set(k, v))
async function list() {
return AppRuntime.runPromise(
Effect.gen(function* () {
const provider = yield* Provider.Service
return yield* provider.list()
}),
)
}
const DIGITALOCEAN = ProviderID.make("digitalocean") const DIGITALOCEAN = ProviderID.make("digitalocean")
const it = testEffect(Provider.defaultLayer)
const originalAuthContent = process.env.OPENCODE_AUTH_CONTENT const withEnv = <A, E, R>(values: Record<string, string>, effect: Effect.Effect<A, E, R>) =>
afterEach(() => { Effect.acquireUseRelease(
if (originalAuthContent === undefined) delete process.env.OPENCODE_AUTH_CONTENT Effect.sync(() => {
else process.env.OPENCODE_AUTH_CONTENT = originalAuthContent const previous = Object.fromEntries(Object.keys(values).map((key) => [key, process.env[key]] as const))
}) Object.assign(process.env, values)
return previous
}),
() => effect,
(previous) =>
Effect.sync(() => {
for (const [key, value] of Object.entries(previous)) {
if (value === undefined) delete process.env[key]
else process.env[key] = value
}
}),
)
function injectAuth(metadata: Record<string, string> | undefined) { const withAuth = <A, E, R>(metadata: Record<string, string> | undefined, effect: Effect.Effect<A, E, R>) =>
process.env.OPENCODE_AUTH_CONTENT = JSON.stringify({ withEnv(
digitalocean: { {
type: "api", OPENCODE_AUTH_CONTENT: JSON.stringify({
key: "sk_do_test", digitalocean: {
...(metadata ? { metadata } : {}), type: "api",
key: "sk_do_test",
...(metadata ? { metadata } : {}),
},
}),
}, },
}) effect,
} )
test("digitalocean provider autoloads from DIGITALOCEAN_ACCESS_TOKEN", async () => { it.instance(
await using tmp = await tmpdir({ "digitalocean provider autoloads from DIGITALOCEAN_ACCESS_TOKEN",
init: async (dir) => { () =>
await Bun.write(path.join(dir, "opencode.json"), JSON.stringify({ $schema: "https://opencode.ai/config.json" })) withEnv(
}, { DIGITALOCEAN_ACCESS_TOKEN: "test-token" },
}) Effect.gen(function* () {
await WithInstance.provide({ const provider = yield* Provider.Service
directory: tmp.path, const providers = yield* provider.list()
fn: async () => { expect(providers[DIGITALOCEAN]).toBeDefined()
set("DIGITALOCEAN_ACCESS_TOKEN", "test-token") expect(providers[DIGITALOCEAN].source).toBe("env")
const providers = await list() const baseModel = Object.values(providers[DIGITALOCEAN].models)[0]
expect(providers[DIGITALOCEAN]).toBeDefined() expect(baseModel.api.url).toBe("https://inference.do-ai.run/v1")
expect(providers[DIGITALOCEAN].source).toBe("env") expect(baseModel.api.npm).toBe("@ai-sdk/openai-compatible")
const baseModel = Object.values(providers[DIGITALOCEAN].models)[0] const routerEntries = Object.keys(providers[DIGITALOCEAN].models).filter((id) => id.startsWith("router:"))
expect(baseModel.api.url).toBe("https://inference.do-ai.run/v1") expect(routerEntries.length).toBe(0)
expect(baseModel.api.npm).toBe("@ai-sdk/openai-compatible") }),
const routerEntries = Object.keys(providers[DIGITALOCEAN].models).filter((id) => id.startsWith("router:")) ),
expect(routerEntries.length).toBe(0) { config: {} },
}, )
})
})
test("digitalocean provider.models surfaces cached routers from auth metadata", async () => { it.instance(
await using tmp = await tmpdir({ "digitalocean provider.models surfaces cached routers from auth metadata",
init: async (dir) => { () =>
await Bun.write(path.join(dir, "opencode.json"), JSON.stringify({ $schema: "https://opencode.ai/config.json" })) withAuth(
}, {
}) routers: JSON.stringify([
injectAuth({ { name: "my-router", uuid: "11f1499a-aaaa-bbbb-cccc-4e013e2ddde4" },
routers: JSON.stringify([ { name: "other-router", uuid: "22f1499a-aaaa-bbbb-cccc-4e013e2ddde4" },
{ name: "my-router", uuid: "11f1499a-aaaa-bbbb-cccc-4e013e2ddde4" }, ]),
{ name: "other-router", uuid: "22f1499a-aaaa-bbbb-cccc-4e013e2ddde4" }, routers_fetched_at: String(Date.now()),
]), oauth_access: "doo_v1_test",
routers_fetched_at: String(Date.now()), oauth_expires: String(Date.now() + 60 * 60 * 1000),
oauth_access: "doo_v1_test", },
oauth_expires: String(Date.now() + 60 * 60 * 1000), Effect.gen(function* () {
}) const provider = yield* Provider.Service
await WithInstance.provide({ const providers = yield* provider.list()
directory: tmp.path, const models = providers[DIGITALOCEAN].models
fn: async () => { expect(models["router:my-router"]).toBeDefined()
const providers = await list() expect(models["router:my-router"].api.id).toBe("router:my-router")
const models = providers[DIGITALOCEAN].models expect(models["router:my-router"].api.url).toBe("https://inference.do-ai.run/v1")
expect(models["router:my-router"]).toBeDefined() expect(models["router:my-router"].api.npm).toBe("@ai-sdk/openai-compatible")
expect(models["router:my-router"].api.id).toBe("router:my-router") expect(models["router:other-router"]).toBeDefined()
expect(models["router:my-router"].api.url).toBe("https://inference.do-ai.run/v1") }),
expect(models["router:my-router"].api.npm).toBe("@ai-sdk/openai-compatible") ),
expect(models["router:other-router"]).toBeDefined() { config: {} },
}, )
})
})
test("digitalocean provider.models skips refresh when oauth bearer is expired", async () => { it.instance(
await using tmp = await tmpdir({ "digitalocean provider.models skips refresh when oauth bearer is expired",
init: async (dir) => { () =>
await Bun.write(path.join(dir, "opencode.json"), JSON.stringify({ $schema: "https://opencode.ai/config.json" })) withAuth(
}, {
}) routers: JSON.stringify([{ name: "stale-router", uuid: "stale" }]),
injectAuth({ routers_fetched_at: "0",
routers: JSON.stringify([{ name: "stale-router", uuid: "stale" }]), oauth_access: "doo_v1_expired",
routers_fetched_at: "0", oauth_expires: "1",
oauth_access: "doo_v1_expired", },
oauth_expires: "1", Effect.gen(function* () {
}) const provider = yield* Provider.Service
await WithInstance.provide({ const providers = yield* provider.list()
directory: tmp.path, const models = providers[DIGITALOCEAN].models
fn: async () => { expect(models["router:stale-router"]).toBeDefined()
const providers = await list() }),
const models = providers[DIGITALOCEAN].models ),
expect(models["router:stale-router"]).toBeDefined() { config: {} },
}, )
})
})
test("digitalocean provider.models passes through base models when no auth metadata", async () => { it.instance(
await using tmp = await tmpdir({ "digitalocean provider.models passes through base models when no auth metadata",
init: async (dir) => { () =>
await Bun.write(path.join(dir, "opencode.json"), JSON.stringify({ $schema: "https://opencode.ai/config.json" })) withEnv(
}, { DIGITALOCEAN_ACCESS_TOKEN: "test-token" },
}) Effect.gen(function* () {
await WithInstance.provide({ const provider = yield* Provider.Service
directory: tmp.path, const providers = yield* provider.list()
fn: async () => { const models = providers[DIGITALOCEAN].models
set("DIGITALOCEAN_ACCESS_TOKEN", "test-token") expect(Object.keys(models).length).toBeGreaterThan(0)
const providers = await list() expect(Object.keys(models).filter((id) => id.startsWith("router:")).length).toBe(0)
const models = providers[DIGITALOCEAN].models }),
expect(Object.keys(models).length).toBeGreaterThan(0) ),
expect(Object.keys(models).filter((id) => id.startsWith("router:")).length).toBe(0) { config: {} },
}, )
})
})