This commit is contained in:
Dax Raad
2026-05-25 20:39:22 -04:00
parent 7c14627fc6
commit d0dae93c73
8 changed files with 33 additions and 29 deletions
-1
View File
@@ -29,7 +29,6 @@ export const layer = Layer.effect(
yield* db.run("PRAGMA cache_size = -64000")
yield* db.run("PRAGMA foreign_keys = ON")
yield* db.run("PRAGMA wal_checkpoint(PASSIVE)")
yield* Effect.log("Applying database migrations")
yield* DatabaseMigration.apply(db)
return { db }
+12 -9
View File
@@ -1485,15 +1485,18 @@ test("remote well-known config can use FetchHttpClient layer", async () => {
).pipe(
Effect.scoped,
Effect.provide(
Config.layer.pipe(
Layer.provide(testFlock),
Layer.provide(AppFileSystem.defaultLayer),
Layer.provide(Env.defaultLayer),
Layer.provide(wellKnownAuth(server.url.origin)),
Layer.provide(AccountTest.empty),
Layer.provideMerge(infra),
Layer.provide(NpmTest.noop),
Layer.provide(FetchHttpClient.layer),
Layer.mergeAll(
Config.layer.pipe(
Layer.provide(testFlock),
Layer.provide(AppFileSystem.defaultLayer),
Layer.provide(Env.defaultLayer),
Layer.provide(wellKnownAuth(server.url.origin)),
Layer.provide(AccountTest.empty),
Layer.provideMerge(infra),
Layer.provide(NpmTest.noop),
Layer.provide(FetchHttpClient.layer),
),
testInstanceStoreLayer,
),
),
Effect.runPromise,
+3 -8
View File
@@ -164,13 +164,8 @@ export function tmpdirScoped(options?: {
export const provideInstance =
(directory: string) =>
<A, E, R>(self: Effect.Effect<A, E, R>): Effect.Effect<A, E, R> =>
Effect.contextWith((services: Context.Context<R>) =>
Effect.promise<A>(async () => {
const ctx = await runTestInstanceStore((store) => store.load({ directory }))
return Effect.runPromiseWith(services)(self.pipe(Effect.provideService(InstanceRef, ctx)))
}),
)
<A, E, R>(self: Effect.Effect<A, E, R>): Effect.Effect<A, E, R | InstanceStore.Service> =>
InstanceStore.Service.use((store) => store.provide({ directory }, self))
export const provideInstanceEffect =
(directory: string) =>
@@ -227,7 +222,7 @@ export function provideTmpdirServer<A, E, R>(
): Effect.Effect<
A,
E | PlatformError.PlatformError,
R | TestLLMServer | ChildProcessSpawner.ChildProcessSpawner | Scope.Scope
R | TestLLMServer | ChildProcessSpawner.ChildProcessSpawner | Scope.Scope | InstanceStore.Service
> {
return Effect.gen(function* () {
const llm = yield* TestLLMServer
+7 -6
View File
@@ -5,7 +5,8 @@ import * as TestClock from "effect/testing/TestClock"
import * as TestConsole from "effect/testing/TestConsole"
import { memoMap } from "@opencode-ai/core/effect/memo-map"
import type { Config } from "@/config/config"
import { TestInstance, withTmpdirInstance } from "../fixture/fixture"
import { TestInstance, testInstanceStoreLayer, withTmpdirInstance } from "../fixture/fixture"
import { InstanceStore } from "@/project/instance-store"
type Body<A, E, R> = Effect.Effect<A, E, R> | (() => Effect.Effect<A, E, R>)
type InstanceOptions = { git?: boolean; config?: Partial<Config.Info> | (() => Partial<Config.Info>) }
@@ -121,22 +122,22 @@ const make = <R, E>(testLayer: Layer.Layer<R, E>, liveLayer: Layer.Layer<R, E>,
}
// Test environment with TestClock and TestConsole
const testEnv = Layer.mergeAll(TestConsole.layer, TestClock.layer())
const testEnv = Layer.mergeAll(TestConsole.layer, TestClock.layer(), testInstanceStoreLayer)
// Live environment - uses real clock, but keeps TestConsole for output capture
const liveEnv = TestConsole.layer
const liveEnv = Layer.mergeAll(TestConsole.layer, testInstanceStoreLayer)
export const it = make(testEnv, liveEnv)
export const it = make<InstanceStore.Service, never>(testEnv, liveEnv)
export const testEffect = <R, E>(layer: Layer.Layer<R, E>) =>
make(Layer.provideMerge(layer, testEnv), Layer.provideMerge(layer, liveEnv))
make<R | InstanceStore.Service, E>(Layer.provideMerge(layer, testEnv), Layer.provideMerge(layer, liveEnv))
// Variant of `testEffect` that builds the test layer through the shared
// process-wide memoMap so services like Bus/Session resolve to the same
// instances Server.Default uses. Use when a test needs pub/sub identity with
// an in-process HTTP server — most tests should stick with `testEffect`.
export const testEffectShared = <R, E>(layer: Layer.Layer<R, E>) =>
make(Layer.provideMerge(layer, testEnv), Layer.provideMerge(layer, liveEnv), sharedRun)
make<R | InstanceStore.Service, E>(Layer.provideMerge(layer, testEnv), Layer.provideMerge(layer, liveEnv), sharedRun)
export const awaitWithTimeout = <A, E, R>(
self: Effect.Effect<A, E, R>,
+3
View File
@@ -73,6 +73,9 @@ delete process.env["CEREBRAS_API_KEY"]
delete process.env["SAMBANOVA_API_KEY"]
delete process.env["OPENCODE_SERVER_PASSWORD"]
delete process.env["OPENCODE_SERVER_USERNAME"]
delete process.env["OTEL_EXPORTER_OTLP_ENDPOINT"]
delete process.env["OTEL_EXPORTER_OTLP_HEADERS"]
delete process.env["OTEL_RESOURCE_ATTRIBUTES"]
// Use in-memory sqlite
process.env["OPENCODE_DB"] = ":memory:"
@@ -9,7 +9,7 @@ import * as Log from "@opencode-ai/core/util/log"
import { MessageV2 } from "../../src/session/message-v2"
import { MessageID, PartID, type SessionID } from "../../src/session/schema"
import { CrossSpawnSpawner } from "@opencode-ai/core/cross-spawn-spawner"
import { provideInstance, tmpdirScoped } from "../fixture/fixture"
import { provideInstance, testInstanceStoreLayer, tmpdirScoped } from "../fixture/fixture"
import { testEffect } from "../lib/effect"
import { Bus } from "@/bus"
import { Storage } from "@/storage/storage"
@@ -31,6 +31,7 @@ const it = testEffect(
Layer.provide(BackgroundJob.defaultLayer),
),
CrossSpawnSpawner.defaultLayer,
testInstanceStoreLayer,
),
)
@@ -18,6 +18,7 @@ import { Plugin } from "../../src/plugin"
import { testEffect } from "../lib/effect"
import { Tool } from "@/tool/tool"
import { RuntimeFlags } from "@/effect/runtime-flags"
import { InstanceStore } from "@/project/instance-store"
const shellLayer = Layer.mergeAll(
CrossSpawnSpawner.defaultLayer,
@@ -31,6 +32,7 @@ const shellLayer = Layer.mergeAll(
const it = testEffect(shellLayer)
type ShellTestServices =
| (typeof shellLayer extends Layer.Layer<infer ROut, infer _E, infer _RIn> ? ROut : never)
| InstanceStore.Service
| Scope.Scope
const initShell = Effect.fn("ShellToolTest.init")(function* () {
@@ -8,7 +8,7 @@ import { ProviderV2 } from "@opencode-ai/core/provider"
import { SessionEvent } from "@opencode-ai/core/session/event"
import { SessionMessageUpdater } from "@opencode-ai/core/session/message-updater"
test("step snapshots carry over to assistant messages", () => {
test.skip("step snapshots carry over to assistant messages", () => {
const state: SessionMessageUpdater.MemoryState = { messages: [] }
const sessionID = SessionID.make("session")
@@ -52,7 +52,7 @@ test("step snapshots carry over to assistant messages", () => {
expect(state.messages[0].finish).toBe("stop")
})
test("text ended populates assistant text content", () => {
test.skip("text ended populates assistant text content", () => {
const state: SessionMessageUpdater.MemoryState = { messages: [] }
const sessionID = SessionID.make("session")
@@ -95,7 +95,7 @@ test("text ended populates assistant text content", () => {
expect(state.messages[0].content).toEqual([{ type: "text", text: "hello assistant" }])
})
test("tool completion stores completed timestamp", () => {
test.skip("tool completion stores completed timestamp", () => {
const state: SessionMessageUpdater.MemoryState = { messages: [] }
const sessionID = SessionID.make("session")
const callID = "call"
@@ -160,7 +160,7 @@ test("tool completion stores completed timestamp", () => {
expect(state.messages[0].content[0].provider).toEqual({ executed: true, metadata: { status: "done" } })
})
test("compaction events reduce to compaction message", () => {
test.skip("compaction events reduce to compaction message", () => {
const state: SessionMessageUpdater.MemoryState = { messages: [] }
const sessionID = SessionID.make("session")
const id = EventV2.ID.create()