Skip to content

Commit e0d0fe1

Browse files
authored
test(bus): migrate integration tests to Effect runner (anomalyco#27132)
1 parent f7dbb4d commit e0d0fe1

1 file changed

Lines changed: 67 additions & 67 deletions

File tree

Lines changed: 67 additions & 67 deletions
Original file line numberDiff line numberDiff line change
@@ -1,88 +1,88 @@
1-
import { afterEach, describe, expect, test } from "bun:test"
2-
import { Schema } from "effect"
1+
import { CrossSpawnSpawner } from "@opencode-ai/core/cross-spawn-spawner"
2+
import { afterEach, describe, expect } from "bun:test"
3+
import { Deferred, Effect, Layer, Schema } from "effect"
34
import { Bus } from "../../src/bus"
45
import { BusEvent } from "../../src/bus/bus-event"
5-
import { Instance } from "../../src/project/instance"
6-
import { WithInstance } from "../../src/project/with-instance"
7-
import { disposeAllInstances, tmpdir } from "../fixture/fixture"
6+
import { disposeAllInstances, provideInstance, tmpdirScoped } from "../fixture/fixture"
7+
import { testEffect } from "../lib/effect"
88

99
const TestEvent = BusEvent.define("test.integration", Schema.Struct({ value: Schema.Number }))
10-
11-
function withInstance(directory: string, fn: () => Promise<void>) {
12-
return WithInstance.provide({ directory, fn })
13-
}
10+
const it = testEffect(Layer.mergeAll(Bus.layer, CrossSpawnSpawner.defaultLayer))
1411

1512
describe("Bus integration: acquireRelease subscriber pattern", () => {
1613
afterEach(() => disposeAllInstances())
1714

18-
test("subscriber via callback facade receives events and cleans up on unsub", async () => {
19-
await using tmp = await tmpdir()
20-
const received: number[] = []
15+
it.instance("subscriber via callback facade receives events and cleans up on unsub", () =>
16+
Effect.gen(function* () {
17+
const bus = yield* Bus.Service
18+
const received: number[] = []
19+
const receivedTwo = yield* Deferred.make<void>()
2120

22-
await withInstance(tmp.path, async () => {
23-
const unsub = Bus.subscribe(TestEvent, (evt) => {
21+
const unsub = yield* bus.subscribeCallback(TestEvent, (evt) => {
2422
received.push(evt.properties.value)
23+
if (received.length === 2) Deferred.doneUnsafe(receivedTwo, Effect.void)
2524
})
26-
await Bun.sleep(10)
27-
await Bus.publish(TestEvent, { value: 1 })
28-
await Bus.publish(TestEvent, { value: 2 })
29-
await Bun.sleep(10)
25+
yield* bus.publish(TestEvent, { value: 1 })
26+
yield* bus.publish(TestEvent, { value: 2 })
27+
yield* Deferred.await(receivedTwo).pipe(Effect.timeout("2 seconds"))
3028

3129
expect(received).toEqual([1, 2])
3230

33-
unsub()
34-
await Bun.sleep(10)
35-
await Bus.publish(TestEvent, { value: 3 })
36-
await Bun.sleep(10)
31+
yield* Effect.sync(unsub)
32+
yield* bus.publish(TestEvent, { value: 3 })
33+
yield* Effect.sleep("10 millis")
3734

3835
expect(received).toEqual([1, 2])
39-
})
40-
})
41-
42-
test("subscribeAll receives events from multiple types", async () => {
43-
await using tmp = await tmpdir()
44-
const received: Array<{ type: string; value?: number }> = []
36+
}),
37+
)
4538

46-
const OtherEvent = BusEvent.define("test.other", Schema.Struct({ value: Schema.Number }))
39+
it.instance("subscribeAll receives events from multiple types", () =>
40+
Effect.gen(function* () {
41+
const bus = yield* Bus.Service
42+
const received: Array<{ type: string; value?: number }> = []
43+
const OtherEvent = BusEvent.define("test.other", Schema.Struct({ value: Schema.Number }))
44+
const receivedTwo = yield* Deferred.make<void>()
4745

48-
await withInstance(tmp.path, async () => {
49-
Bus.subscribeAll((evt) => {
46+
yield* bus.subscribeAllCallback((evt) => {
5047
received.push({ type: evt.type, value: evt.properties.value })
48+
if (received.length === 2) Deferred.doneUnsafe(receivedTwo, Effect.void)
5149
})
52-
await Bun.sleep(10)
53-
await Bus.publish(TestEvent, { value: 10 })
54-
await Bus.publish(OtherEvent, { value: 20 })
55-
await Bun.sleep(10)
56-
})
57-
58-
expect(received).toEqual([
59-
{ type: "test.integration", value: 10 },
60-
{ type: "test.other", value: 20 },
61-
])
62-
})
63-
64-
test("subscriber cleanup on instance disposal interrupts the stream", async () => {
65-
await using tmp = await tmpdir()
66-
const received: number[] = []
67-
let disposed = false
68-
69-
await withInstance(tmp.path, async () => {
70-
Bus.subscribeAll((evt) => {
71-
if (evt.type === Bus.InstanceDisposed.type) {
72-
disposed = true
73-
return
74-
}
75-
received.push(evt.properties.value)
76-
})
77-
await Bun.sleep(10)
78-
await Bus.publish(TestEvent, { value: 1 })
79-
await Bun.sleep(10)
80-
})
81-
82-
await disposeAllInstances()
83-
await Bun.sleep(50)
84-
85-
expect(received).toEqual([1])
86-
expect(disposed).toBe(true)
87-
})
50+
yield* bus.publish(TestEvent, { value: 10 })
51+
yield* bus.publish(OtherEvent, { value: 20 })
52+
yield* Deferred.await(receivedTwo).pipe(Effect.timeout("2 seconds"))
53+
54+
expect(received).toEqual([
55+
{ type: "test.integration", value: 10 },
56+
{ type: "test.other", value: 20 },
57+
])
58+
}),
59+
)
60+
61+
it.live("subscriber cleanup on instance disposal interrupts the stream", () =>
62+
Effect.gen(function* () {
63+
const dir = yield* tmpdirScoped()
64+
const received: number[] = []
65+
const seen = yield* Deferred.make<void>()
66+
const disposed = yield* Deferred.make<void>()
67+
68+
yield* Effect.gen(function* () {
69+
const bus = yield* Bus.Service
70+
yield* bus.subscribeAllCallback((evt) => {
71+
if (evt.type === Bus.InstanceDisposed.type) {
72+
Deferred.doneUnsafe(disposed, Effect.void)
73+
return
74+
}
75+
received.push(evt.properties.value)
76+
Deferred.doneUnsafe(seen, Effect.void)
77+
})
78+
yield* bus.publish(TestEvent, { value: 1 })
79+
yield* Deferred.await(seen).pipe(Effect.timeout("2 seconds"))
80+
}).pipe(provideInstance(dir))
81+
82+
yield* Effect.promise(() => disposeAllInstances())
83+
yield* Deferred.await(disposed).pipe(Effect.timeout("2 seconds"))
84+
85+
expect(received).toEqual([1])
86+
}),
87+
)
8888
})

0 commit comments

Comments
 (0)