mirror of
https://github.com/anomalyco/opencode.git
synced 2026-09-06 13:14:31 +00:00
106 lines
4.2 KiB
TypeScript
106 lines
4.2 KiB
TypeScript
import { expect } from "bun:test"
|
|
import { SdkPlugins } from "@opencode-ai/core/plugin/sdk"
|
|
import { Plugin } from "@opencode-ai/plugin/effect"
|
|
import { Context, Deferred, Effect, Fiber, Layer } from "effect"
|
|
import { HttpEffect, HttpRouter, HttpServer } from "effect/unstable/http"
|
|
import { tmpdirScoped } from "../../core/test/fixture/tmpdir"
|
|
import { it } from "../../core/test/lib/effect"
|
|
import { createRoutes } from "../src/routes"
|
|
|
|
it.live(
|
|
"lists and gets providers without blocking on plugin initialization",
|
|
() =>
|
|
Effect.gen(function* () {
|
|
const tmp = yield* tmpdirScoped("opencode-provider-endpoints-")
|
|
const started = yield* Deferred.make<void>()
|
|
const release = yield* Deferred.make<void>()
|
|
const context = yield* Layer.build(
|
|
createRoutes({
|
|
password: "secret",
|
|
database: { path: ":memory:" },
|
|
models: { fetch: false },
|
|
fs: { filewatcher: false },
|
|
config: {
|
|
directory: tmp.path,
|
|
project: false,
|
|
content: JSON.stringify({
|
|
providers: {
|
|
custom: {
|
|
name: "Configured Custom Provider",
|
|
package: "@opencode-ai/ai/providers/openai-compatible",
|
|
settings: { apiKey: "secret" },
|
|
models: { chat: {} },
|
|
},
|
|
},
|
|
}),
|
|
},
|
|
}).pipe(Layer.provide(HttpServer.layerServices)),
|
|
)
|
|
const sdk = Context.get(context, SdkPlugins.Service)
|
|
yield* sdk.register(
|
|
Plugin.define({
|
|
id: "slow-plugin",
|
|
effect: () =>
|
|
Effect.gen(function* () {
|
|
yield* Deferred.succeed(started, undefined)
|
|
yield* Deferred.await(release)
|
|
}),
|
|
}),
|
|
)
|
|
const handler = Context.get(context, HttpRouter.HttpRouter)
|
|
.asHttpEffect()
|
|
.pipe(HttpEffect.toWebHandlerWith(context))
|
|
const request = (method: "GET" | "POST", route: string) =>
|
|
Effect.promise((signal) => {
|
|
const url = new URL(route, "http://opencode.local")
|
|
url.searchParams.set("location[directory]", tmp.path)
|
|
return handler(
|
|
new Request(url, {
|
|
method,
|
|
headers: { authorization: `Basic ${btoa("opencode:secret")}` },
|
|
signal,
|
|
}),
|
|
)
|
|
})
|
|
const pending = yield* request("POST", "/api/plugin/await-activation").pipe(Effect.forkScoped)
|
|
yield* Deferred.await(started)
|
|
|
|
// Config providers activate after SDK plugins; reads must return the current snapshot without waiting.
|
|
const list = yield* request("GET", "/api/provider").pipe(Effect.timeout("2 seconds"))
|
|
expect(list.status).toBe(200)
|
|
expect(yield* Effect.promise(() => list.json())).toMatchObject({
|
|
location: { directory: tmp.path },
|
|
data: expect.not.arrayContaining([expect.objectContaining({ id: "custom" })]),
|
|
})
|
|
const get = yield* request("GET", "/api/provider/custom").pipe(Effect.timeout("2 seconds"))
|
|
expect(get.status).toBe(404)
|
|
expect(yield* Effect.promise(() => get.json())).toMatchObject({
|
|
_tag: "ProviderNotFoundError",
|
|
providerID: "custom",
|
|
})
|
|
expect(pending.pollUnsafe()).toBeUndefined()
|
|
|
|
yield* Deferred.succeed(release, undefined)
|
|
expect((yield* Fiber.join(pending)).status).toBe(204)
|
|
const provider = {
|
|
id: "custom",
|
|
name: "Configured Custom Provider",
|
|
activation: "enabled",
|
|
package: "@opencode-ai/ai/providers/openai-compatible",
|
|
settings: { apiKey: "secret" },
|
|
}
|
|
const configuredList = yield* request("GET", "/api/provider").pipe(Effect.timeout("2 seconds"))
|
|
expect(configuredList.status).toBe(200)
|
|
expect(yield* Effect.promise(() => configuredList.json())).toMatchObject({
|
|
location: { directory: tmp.path },
|
|
data: expect.arrayContaining([expect.objectContaining(provider)]),
|
|
})
|
|
const configuredGet = yield* request("GET", "/api/provider/custom").pipe(Effect.timeout("2 seconds"))
|
|
expect(configuredGet.status).toBe(200)
|
|
expect(yield* Effect.promise(() => configuredGet.json())).toMatchObject({
|
|
location: { directory: tmp.path },
|
|
data: provider,
|
|
})
|
|
}),
|
|
15_000,
|
|
)
|