From 15bcbb1d7aa63fe18a4c02f90f9f57a57977c4b3 Mon Sep 17 00:00:00 2001 From: James Long Date: Mon, 29 Jun 2026 16:22:50 -0400 Subject: [PATCH] refactor(opencode): migrate session tests to layer nodes (#34494) --- packages/opencode/test/mcp/auth.test.ts | 17 +++++----- .../opencode/test/permission/next.test.ts | 14 ++++----- .../opencode/test/session/instruction.test.ts | 31 +++++++++++-------- .../opencode/test/session/session.test.ts | 26 +++++++--------- 4 files changed, 43 insertions(+), 45 deletions(-) diff --git a/packages/opencode/test/mcp/auth.test.ts b/packages/opencode/test/mcp/auth.test.ts index 7ad8c4826c..5aa099983a 100644 --- a/packages/opencode/test/mcp/auth.test.ts +++ b/packages/opencode/test/mcp/auth.test.ts @@ -1,9 +1,8 @@ import { expect, test } from "bun:test" import { setTimeout as sleep } from "node:timers/promises" -import { LayerNode } from "@opencode-ai/core/effect/layer-node" +import { AppNodeBuilder } from "@opencode-ai/core/effect/app-node-builder" import { Effect, Layer } from "effect" import { FSUtil } from "@opencode-ai/core/fs-util" -import { EffectFlock } from "@opencode-ai/core/util/effect-flock" import { McpAuth } from "../../src/mcp/auth" function authFile() { @@ -11,7 +10,7 @@ function authFile() { let activeWrites = 0 let sawOverlap = false - const layer = Layer.effect( + const fsLayer = Layer.effect( FSUtil.Service, Effect.gen(function* () { const fs = yield* FSUtil.Service @@ -42,14 +41,14 @@ function authFile() { : fs.writeJson(file, value, mode), }) }), - ).pipe(Layer.provide(LayerNode.compile(FSUtil.node))) + ).pipe(Layer.provide(AppNodeBuilder.build(FSUtil.node))) - return { layer, raw: () => raw } + return { fsLayer, raw: () => raw } } -function authService(layer: Layer.Layer) { +function authService(fsLayer: Layer.Layer) { return McpAuth.Service.use((auth) => Effect.succeed(auth)).pipe( - Effect.provide(LayerNode.compile(McpAuth.node, [[FSUtil.node, layer]])), + Effect.provide(AppNodeBuilder.build(McpAuth.node, [[FSUtil.node, fsLayer]])), ) } @@ -58,8 +57,8 @@ test("serializes concurrent auth file updates across service instances", async ( await Effect.runPromise( Effect.gen(function* () { - const first = yield* authService(file.layer) - const second = yield* authService(file.layer) + const first = yield* authService(file.fsLayer) + const second = yield* authService(file.fsLayer) yield* Effect.all( [ diff --git a/packages/opencode/test/permission/next.test.ts b/packages/opencode/test/permission/next.test.ts index e784350055..ec2a641667 100644 --- a/packages/opencode/test/permission/next.test.ts +++ b/packages/opencode/test/permission/next.test.ts @@ -4,21 +4,19 @@ import os from "os" import { Cause, Deferred, Effect, Exit, Fiber, Layer } from "effect" import { EventV2Bridge } from "../../src/event-v2-bridge" import { CrossSpawnSpawner } from "@opencode-ai/core/cross-spawn-spawner" -import { Database } from "@opencode-ai/core/database/database" import { Permission } from "../../src/permission" -import { InstanceBootstrap } from "../../src/project/bootstrap-service" +import { InstanceBootstrap } from "../../src/project/bootstrap" import { InstanceStore } from "../../src/project/instance-store" import { TestInstance, tmpdirScoped } from "../fixture/fixture" import { testEffect } from "../lib/effect" import { MessageID, SessionID } from "../../src/session/schema" +import { AppNodeBuilder } from "@opencode-ai/core/effect/app-node-builder" +import { LayerNode } from "@opencode-ai/core/effect/layer-node" -const events = EventV2Bridge.defaultLayer const noopBootstrap = Layer.succeed(InstanceBootstrap.Service, InstanceBootstrap.Service.of({ run: Effect.void })) -const env = Layer.mergeAll( - Permission.layer.pipe(Layer.provide(Database.defaultLayer), Layer.provide(events)), - events, - CrossSpawnSpawner.defaultLayer, - InstanceStore.defaultLayer.pipe(Layer.provide(noopBootstrap)), +const env = AppNodeBuilder.build( + LayerNode.group([Permission.node, EventV2Bridge.node, CrossSpawnSpawner.node, InstanceStore.node]), + [[InstanceBootstrap.node, noopBootstrap]], ) const it = testEffect(env) diff --git a/packages/opencode/test/session/instruction.test.ts b/packages/opencode/test/session/instruction.test.ts index 53ccf06e12..f2ec95c618 100644 --- a/packages/opencode/test/session/instruction.test.ts +++ b/packages/opencode/test/session/instruction.test.ts @@ -2,34 +2,39 @@ import { describe, expect, test } from "bun:test" import { SessionV1 } from "@opencode-ai/core/v1/session" import path from "path" import { Effect, FileSystem, Layer } from "effect" -import { FetchHttpClient } from "effect/unstable/http" -import { NodeFileSystem } from "@effect/platform-node" import { CrossSpawnSpawner } from "@opencode-ai/core/cross-spawn-spawner" -import { FSUtil } from "@opencode-ai/core/fs-util" import { Instruction } from "../../src/session/instruction" import type { MessageV2 } from "../../src/session/message-v2" import { MessageID, PartID, SessionID } from "../../src/session/schema" import { Global } from "@opencode-ai/core/global" import { RuntimeFlags } from "../../src/effect/runtime-flags" -import { provideInstance, provideTmpdirInstance, testInstanceStoreLayer, tmpdirScoped } from "../fixture/fixture" +import { provideInstance, provideTmpdirInstance, tmpdirScoped } from "../fixture/fixture" import { testEffect } from "../lib/effect" import { TestConfig } from "../fixture/config" import { ProviderV2 } from "@opencode-ai/core/provider" import { ModelV2 } from "@opencode-ai/core/model" +import { AppNodeBuilder } from "@opencode-ai/core/effect/app-node-builder" +import { LayerNode } from "@opencode-ai/core/effect/layer-node" +import { LayerNodePlatform } from "@opencode-ai/core/effect/app-node-platform" +import { InstanceStore } from "@/project/instance-store" +import { InstanceBootstrap } from "@/project/bootstrap" +import { Config } from "@/config/config" -const it = testEffect(Layer.mergeAll(CrossSpawnSpawner.defaultLayer, NodeFileSystem.layer, testInstanceStoreLayer)) +const it = testEffect( + AppNodeBuilder.build(LayerNode.group([CrossSpawnSpawner.node, LayerNodePlatform.filesystem, InstanceStore.node]), [ + [InstanceBootstrap.node, Layer.succeed(InstanceBootstrap.Service, InstanceBootstrap.Service.of({ run: Effect.void }))], + ]), +) -const configLayer = TestConfig.layer() +const configLayer = Layer.succeed(Config.Service, TestConfig.make()) const instructionLayer = (global: Partial, flags: Partial = {}) => - Instruction.layer.pipe( - Layer.provide(configLayer), - Layer.provide(FSUtil.defaultLayer), - Layer.provide(FetchHttpClient.layer), - Layer.provide(Global.layerWith(global)), - Layer.provide(RuntimeFlags.layer(flags)), - ) + AppNodeBuilder.build(Instruction.node, [ + [Config.node, configLayer], + [Global.node, Global.layerWith(global)], + [RuntimeFlags.node, RuntimeFlags.layer(flags)], + ]) const provideInstruction = (global: Partial, flags?: Partial) => diff --git a/packages/opencode/test/session/session.test.ts b/packages/opencode/test/session/session.test.ts index c82f713d2b..a839e6da30 100644 --- a/packages/opencode/test/session/session.test.ts +++ b/packages/opencode/test/session/session.test.ts @@ -1,6 +1,5 @@ import { describe, expect } from "bun:test" import { SessionV1 } from "@opencode-ai/core/v1/session" -import { Database } from "@opencode-ai/core/database/database" import { EventV2 } from "@opencode-ai/core/event" import { SessionProjector } from "@opencode-ai/core/session/projector" import { Deferred, Effect, Exit, Layer } from "effect" @@ -8,26 +7,23 @@ import { Session as SessionNs } from "@/session/session" 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, testInstanceStoreLayer, tmpdirScoped } from "../fixture/fixture" +import { provideInstance, tmpdirScoped } from "../fixture/fixture" import { testEffect } from "../lib/effect" -import { Storage } from "@/storage/storage" import { RuntimeFlags } from "@/effect/runtime-flags" -import { BackgroundJob } from "@/background/job" import { EventV2Bridge } from "@/event-v2-bridge" import { GlobalBus } from "@/bus/global" +import { AppNodeBuilder } from "@opencode-ai/core/effect/app-node-builder" +import { LayerNode } from "@opencode-ai/core/effect/layer-node" +import { InstanceStore } from "@/project/instance-store" +import { InstanceBootstrap } from "@/project/bootstrap" const it = testEffect( - Layer.mergeAll( - SessionNs.layer.pipe( - Layer.provide(Storage.defaultLayer), - Layer.provide(Database.defaultLayer), - Layer.provideMerge(EventV2Bridge.defaultLayer), - Layer.provide(SessionProjector.defaultLayer), - Layer.provide(RuntimeFlags.layer({ experimentalWorkspaces: false })), - Layer.provide(BackgroundJob.defaultLayer), - ), - CrossSpawnSpawner.defaultLayer, - testInstanceStoreLayer, + AppNodeBuilder.build( + LayerNode.group([SessionNs.node, EventV2Bridge.node, SessionProjector.node, CrossSpawnSpawner.node, InstanceStore.node]), + [ + [RuntimeFlags.node, RuntimeFlags.layer({ experimentalWorkspaces: false })], + [InstanceBootstrap.node, Layer.succeed(InstanceBootstrap.Service, InstanceBootstrap.Service.of({ run: Effect.void }))], + ], ), )