Просмотр исходного кода

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

Kit Langton 3 месяцев назад
Родитель
Сommit
257fcafc83
1 измененных файлов с 47 добавлено и 71 удалено
  1. 47 71
      packages/opencode/test/tool/edit.test.ts

+ 47 - 71
packages/opencode/test/tool/edit.test.ts

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