summaryrefslogtreecommitdiffhomepage
path: root/packages/opencode/test/effect/instance-state.test.ts
diff options
context:
space:
mode:
Diffstat (limited to 'packages/opencode/test/effect/instance-state.test.ts')
-rw-r--r--packages/opencode/test/effect/instance-state.test.ts100
1 files changed, 99 insertions, 1 deletions
diff --git a/packages/opencode/test/effect/instance-state.test.ts b/packages/opencode/test/effect/instance-state.test.ts
index 2d527482b..914753312 100644
--- a/packages/opencode/test/effect/instance-state.test.ts
+++ b/packages/opencode/test/effect/instance-state.test.ts
@@ -1,6 +1,7 @@
import { afterEach, expect, test } from "bun:test"
-import { Duration, Effect, Layer, ManagedRuntime, ServiceMap } from "effect"
+import { Cause, Deferred, Duration, Effect, Exit, Fiber, Layer, ManagedRuntime, ServiceMap } from "effect"
import { InstanceState } from "../../src/effect/instance-state"
+import { InstanceRef } from "../../src/effect/instance-ref"
import { Instance } from "../../src/project/instance"
import { tmpdir } from "../fixture/fixture"
@@ -382,3 +383,100 @@ test("InstanceState dedupes concurrent lookups", async () => {
),
)
})
+
+test("InstanceState survives deferred resume from the same instance context", async () => {
+ await using tmp = await tmpdir({ git: true })
+
+ interface Api {
+ readonly get: (gate: Deferred.Deferred<void>) => Effect.Effect<string>
+ }
+
+ class Test extends ServiceMap.Service<Test, Api>()("@test/DeferredResume") {
+ static readonly layer = Layer.effect(
+ Test,
+ Effect.gen(function* () {
+ const state = yield* InstanceState.make((ctx) => Effect.sync(() => ctx.directory))
+
+ return Test.of({
+ get: Effect.fn("Test.get")(function* (gate: Deferred.Deferred<void>) {
+ yield* Deferred.await(gate)
+ return yield* InstanceState.get(state)
+ }),
+ })
+ }),
+ )
+ }
+
+ const rt = ManagedRuntime.make(Test.layer)
+
+ try {
+ const gate = await Effect.runPromise(Deferred.make<void>())
+ const fiber = await Instance.provide({
+ directory: tmp.path,
+ fn: () => Promise.resolve(rt.runFork(Test.use((svc) => svc.get(gate)))),
+ })
+
+ await Instance.provide({
+ directory: tmp.path,
+ fn: () => Effect.runPromise(Deferred.succeed(gate, void 0)),
+ })
+ const exit = await Effect.runPromise(Fiber.await(fiber))
+
+ expect(Exit.isSuccess(exit)).toBe(true)
+ if (Exit.isSuccess(exit)) {
+ expect(exit.value).toBe(tmp.path)
+ }
+ } finally {
+ await rt.dispose()
+ }
+})
+
+test("InstanceState survives deferred resume outside ALS when InstanceRef is set", async () => {
+ await using tmp = await tmpdir({ git: true })
+
+ interface Api {
+ readonly get: (gate: Deferred.Deferred<void>) => Effect.Effect<string>
+ }
+
+ class Test extends ServiceMap.Service<Test, Api>()("@test/DeferredResumeOutside") {
+ static readonly layer = Layer.effect(
+ Test,
+ Effect.gen(function* () {
+ const state = yield* InstanceState.make((ctx) => Effect.sync(() => ctx.directory))
+
+ return Test.of({
+ get: Effect.fn("Test.get")(function* (gate: Deferred.Deferred<void>) {
+ yield* Deferred.await(gate)
+ return yield* InstanceState.get(state)
+ }),
+ })
+ }),
+ )
+ }
+
+ const rt = ManagedRuntime.make(Test.layer)
+
+ try {
+ const gate = await Effect.runPromise(Deferred.make<void>())
+ // Provide InstanceRef so the fiber carries the context even when
+ // the deferred is resolved from outside Instance.provide ALS.
+ const fiber = await Instance.provide({
+ directory: tmp.path,
+ fn: () =>
+ Promise.resolve(
+ rt.runFork(Test.use((svc) => svc.get(gate)).pipe(Effect.provideService(InstanceRef, Instance.current))),
+ ),
+ })
+
+ // Resume from outside any Instance.provide — ALS is NOT set here
+ await Effect.runPromise(Deferred.succeed(gate, void 0))
+ const exit = await Effect.runPromise(Fiber.await(fiber))
+
+ expect(Exit.isSuccess(exit)).toBe(true)
+ if (Exit.isSuccess(exit)) {
+ expect(exit.value).toBe(tmp.path)
+ }
+ } finally {
+ await rt.dispose()
+ }
+})