test(tool): migrate edit concurrency test (#26983)
This commit is contained in:
parent
04aafe2bfc
commit
257fcafc83
1 changed files with 47 additions and 71 deletions
|
|
@ -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")
|
|
||||||
},
|
|
||||||
})
|
|
||||||
})
|
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue