Files
anomalyco_opencode/packages/server/test/handler-policy.test.ts
T
2026-08-21 19:37:19 +00:00

62 lines
2.6 KiB
TypeScript

import { Session } from "@opencode-ai/core/session"
import { SessionMessage } from "@opencode-ai/core/session/message"
import { PluginSupervisor } from "@opencode-ai/core/plugin/supervisor"
import { SessionNotFoundError, ServiceUnavailableError, UnknownError } from "@opencode-ai/protocol/errors"
import { expect, test } from "bun:test"
import { Effect, Layer, Logger, References } from "effect"
import { pluginReadiness } from "../src/handlers/plugin-readiness"
import { failedMessageDecode, missingSession } from "../src/handlers/session-error"
test("yieldable session errors preserve the handler failure policy", async () => {
const sessionID = Session.ID.create()
const error = await Effect.runPromise(
Effect.fail(new Session.NotFoundError({ sessionID })).pipe(
Effect.catchTag("Session.NotFoundError", missingSession),
Effect.flip,
),
)
expect(error).toBeInstanceOf(SessionNotFoundError)
expect(error).toMatchObject({ sessionID, message: `Session not found: ${sessionID}` })
})
test("message decode policy preserves its reference and log annotations", async () => {
const sessionID = Session.ID.create()
const messageID = SessionMessage.ID.create()
const messages: unknown[] = []
const annotations: Array<Record<string, unknown>> = []
const logger = Logger.make<unknown, void>((options) => {
messages.push(options.message)
annotations.push({ ...options.fiber.getRef(References.CurrentLogAnnotations) })
})
const error = await Effect.runPromise(
Effect.fail(new Session.MessageDecodeError({ sessionID, messageID })).pipe(
Effect.catchTag("Session.MessageDecodeError", failedMessageDecode),
Effect.flip,
Effect.provide(Logger.layer([logger], { mergeWithExisting: false })),
),
)
expect(error).toBeInstanceOf(UnknownError)
expect(error.message).toBe("Unexpected server error. Check server logs for details.")
expect(error.ref).toMatch(/^err_[0-9a-f]{8}$/)
expect(messages).toEqual([["failed to decode session message"]])
expect(annotations).toEqual([{ ref: error.ref, sessionID, messageID }])
})
test("plugin readiness stays lazy and resolves the supervisor for every execution", async () => {
let flushes = 0
const readiness = pluginReadiness(
() => new ServiceUnavailableError({ message: "initialization timed out", service: "test" }),
)
const layer = Layer.succeed(PluginSupervisor.Service, {
flush: Effect.sync(() => {
flushes++
}),
})
expect(flushes).toBe(0)
await Effect.runPromise(Effect.all([readiness, readiness], { concurrency: 1 }).pipe(Effect.provide(layer)))
expect(flushes).toBe(2)
})