test(tool): migrate edit concurrency test (#26983)

This commit is contained in:
Kit Langton 2026-05-12 11:52:31 -04:00 committed by GitHub
commit 257fcafc83
No known key found for this signature in database
GPG key ID: B5690EEEBB952194

View file

@ -1,10 +1,9 @@
import { afterAll, afterEach, describe, test, expect } from "bun:test" import { afterEach, describe, expect } from "bun:test"
import path from "path" import path from "path"
import fs from "fs/promises" import fs from "fs/promises"
import { Cause, Deferred, Effect, Exit, Layer, ManagedRuntime } from "effect" import { Cause, Deferred, Effect, Exit, Fiber, Layer } from "effect"
import { EditTool } from "../../src/tool/edit" import { EditTool } from "../../src/tool/edit"
import { WithInstance } from "../../src/project/with-instance" import { disposeAllInstances, TestInstance } from "../fixture/fixture"
import { disposeAllInstances, TestInstance, tmpdir } from "../fixture/fixture"
import { LSP } from "@/lsp/lsp" import { LSP } from "@/lsp/lsp"
import { AppFileSystem } from "@opencode-ai/core/filesystem" import { AppFileSystem } from "@opencode-ai/core/filesystem"
import { Format } from "../../src/format" import { Format } from "../../src/format"
@ -42,20 +41,6 @@ const layer = Layer.mergeAll(
const it = testEffect(layer) const it = testEffect(layer)
const runtime = ManagedRuntime.make(layer)
afterAll(async () => {
await runtime.dispose()
})
const resolve = () =>
runtime.runPromise(
Effect.gen(function* () {
const info = yield* EditTool
return yield* info.init()
}),
)
const init = Effect.fn("EditToolTest.init")(function* () { const init = Effect.fn("EditToolTest.init")(function* () {
const info = yield* EditTool const info = yield* EditTool
return yield* info.init() return yield* info.init()
@ -500,58 +485,49 @@ describe("tool.edit", () => {
}) })
describe("concurrent editing", () => { describe("concurrent editing", () => {
test("preserves concurrent edits to different sections of the same file", async () => { it.instance("preserves concurrent edits to different sections of the same file", () =>
await using tmp = await tmpdir() Effect.gen(function* () {
const filepath = path.join(tmp.path, "file.txt") const test = yield* TestInstance
await fs.writeFile(filepath, "top = 0\nmiddle = keep\nbottom = 0\n", "utf-8") const filepath = path.join(test.directory, "file.txt")
yield* put(filepath, "top = 0\nmiddle = keep\nbottom = 0\n")
await WithInstance.provide({ const firstAsk = yield* Deferred.make<void>()
directory: tmp.path, let asks = 0
fn: async () => { const delayedCtx = {
const edit = await resolve() ...ctx,
let asks = 0 ask: () =>
const firstAsk = Promise.withResolvers<void>() Effect.gen(function* () {
const delayedCtx = { asks++
...ctx, if (asks !== 1) return
ask: () => yield* Deferred.succeed(firstAsk, undefined)
Effect.gen(function* () { yield* Effect.promise(() => Bun.sleep(50))
asks++ }),
if (asks !== 1) return }
firstAsk.resolve()
yield* Effect.promise(() => Bun.sleep(50))
}),
}
const promise1 = Effect.runPromise( const first = yield* run(
edit.execute( {
{ filePath: filepath,
filePath: filepath, oldString: "top = 0",
oldString: "top = 0", newString: "top = 1",
newString: "top = 1", },
}, delayedCtx,
delayedCtx, ).pipe(Effect.forkScoped)
),
)
await firstAsk.promise yield* Deferred.await(firstAsk)
yield* Effect.all([
Fiber.join(first),
run(
{
filePath: filepath,
oldString: "bottom = 0",
newString: "bottom = 2",
},
delayedCtx,
),
])
const promise2 = Effect.runPromise( expect(yield* load(filepath)).toBe("top = 1\nmiddle = keep\nbottom = 2\n")
edit.execute( }),
{ )
filePath: filepath,
oldString: "bottom = 0",
newString: "bottom = 2",
},
delayedCtx,
),
)
const results = await Promise.allSettled([promise1, promise2])
expect(results[0]?.status).toBe("fulfilled")
expect(results[1]?.status).toBe("fulfilled")
expect(await fs.readFile(filepath, "utf-8")).toBe("top = 1\nmiddle = keep\nbottom = 2\n")
},
})
})
}) })
}) })