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

test(opencode): simplify share layer wiring (#31811)

James Long 2 месяцев назад
Родитель
Сommit
20bf18ffb4
1 измененных файлов с 78 добавлено и 93 удалено
  1. 78 93
      packages/opencode/test/share/share-next.test.ts

+ 78 - 93
packages/opencode/test/share/share-next.test.ts

@@ -1,15 +1,14 @@
-import { NodeFileSystem } from "@effect/platform-node"
 import { beforeEach, describe, expect } from "bun:test"
 import { Effect, Exit, Layer, Option } from "effect"
 import { HttpClient, HttpClientRequest, HttpClientResponse } from "effect/unstable/http"
+import { LayerNode } from "@opencode-ai/core/effect/layer-node"
+import { httpClient } from "@opencode-ai/core/effect/layer-node-platform"
+import { CrossSpawnSpawner } from "@opencode-ai/core/cross-spawn-spawner"
+import { SessionProjector } from "@opencode-ai/core/session/projector"
 
 import { AccessToken, AccountID, OrgID, RefreshToken } from "../../src/account/schema"
-import { Account } from "../../src/account/account"
 import { AccountRepo } from "../../src/account/repo"
-import { CrossSpawnSpawner } from "@opencode-ai/core/cross-spawn-spawner"
 import { EventV2Bridge } from "../../src/event-v2-bridge"
-import { Config } from "@/config/config"
-import { Provider } from "@/provider/provider"
 import { Session } from "@/session/session"
 import type { SessionID } from "../../src/session/schema"
 import { ShareNext } from "@/share/share-next"
@@ -20,13 +19,7 @@ import { provideTmpdirInstance } from "../fixture/fixture"
 import { resetDatabase } from "../fixture/db"
 import { pollWithTimeout, testEffect } from "../lib/effect"
 
-const env = Layer.mergeAll(
-  Session.defaultLayer,
-  AccountRepo.defaultLayer,
-  Database.defaultLayer,
-  NodeFileSystem.layer,
-  CrossSpawnSpawner.defaultLayer,
-)
+const env = LayerNode.buildLayer(CrossSpawnSpawner.node)
 const it = testEffect(env)
 
 const json = (req: Parameters<typeof HttpClientResponse.fromWeb>[0], body: unknown, status = 200) =>
@@ -40,35 +33,28 @@ const json = (req: Parameters<typeof HttpClientResponse.fromWeb>[0], body: unkno
 
 const none = HttpClient.make(() => Effect.die("unexpected http call"))
 
-function live(client: HttpClient.HttpClient) {
-  const http = Layer.succeed(HttpClient.HttpClient, client)
-  return ShareNext.layer.pipe(
-    Layer.provide(EventV2Bridge.defaultLayer),
-    Layer.provide(Account.layer.pipe(Layer.provide(AccountRepo.defaultLayer), Layer.provide(http))),
-    Layer.provide(Config.defaultLayer),
-    Layer.provide(Database.defaultLayer),
-    Layer.provide(http),
-    Layer.provide(Provider.defaultLayer),
-    Layer.provide(Session.defaultLayer),
+function requestLayer(client: HttpClient.HttpClient) {
+  return LayerNode.buildLayer(
+    LayerNode.group([ShareNext.node, AccountRepo.node]),
+    {
+      replacements: [LayerNode.replace(httpClient, Layer.succeed(HttpClient.HttpClient, client))],
+    },
   )
 }
 
-function wired(client: HttpClient.HttpClient) {
-  const http = Layer.succeed(HttpClient.HttpClient, client)
-  return Layer.mergeAll(
-    EventV2Bridge.defaultLayer,
-    ShareNext.layer,
-    Session.defaultLayer,
-    AccountRepo.defaultLayer,
-    Database.defaultLayer,
-    NodeFileSystem.layer,
-    CrossSpawnSpawner.defaultLayer,
-  ).pipe(
-    Layer.provide(EventV2Bridge.defaultLayer),
-    Layer.provide(Account.layer.pipe(Layer.provide(AccountRepo.defaultLayer), Layer.provide(http))),
-    Layer.provide(Config.defaultLayer),
-    Layer.provide(http),
-    Layer.provide(Provider.defaultLayer),
+function integrationLayer(client: HttpClient.HttpClient) {
+  return LayerNode.buildLayer(
+    LayerNode.group([
+      ShareNext.node,
+      EventV2Bridge.node,
+      Session.node,
+      SessionProjector.node,
+      AccountRepo.node,
+      Database.node,
+    ]),
+    {
+      replacements: [LayerNode.replace(httpClient, Layer.succeed(HttpClient.HttpClient, client))],
+    },
   )
 }
 
@@ -115,7 +101,7 @@ describe("ShareNext", () => {
             expect(req.baseUrl).toBe("https://legacy-share.example.com")
             expect(req.headers).toEqual({})
           }),
-        ).pipe(Effect.provide(live(none))),
+        ).pipe(Effect.provide(requestLayer(none))),
       { config: { enterprise: { url: "https://legacy-share.example.com" } } },
     ),
   )
@@ -130,7 +116,7 @@ describe("ShareNext", () => {
           expect(req.api.create).toBe("/api/share")
           expect(req.headers).toEqual({})
         }),
-      ).pipe(Effect.provide(live(none))),
+      ).pipe(Effect.provide(requestLayer(none))),
     ),
   )
 
@@ -139,7 +125,7 @@ describe("ShareNext", () => {
       Effect.gen(function* () {
         yield* seed("https://control.example.com", "org-1")
 
-        const req = yield* ShareNext.use.request().pipe(Effect.provide(live(none)))
+        const req = yield* ShareNext.use.request()
 
         expect(req.api.create).toBe("/api/shares")
         expect(req.api.sync("shr_123")).toBe("/api/shares/shr_123/sync")
@@ -150,31 +136,31 @@ describe("ShareNext", () => {
           authorization: "Bearer st_test_token",
           "x-org-id": "org-1",
         })
-      }),
+      }).pipe(Effect.provide(requestLayer(none))),
     ),
   )
 
   it.live("create posts share, persists it, and returns the result", () =>
     provideTmpdirInstance(
-      () =>
-        Effect.gen(function* () {
-          const session = yield* Session.use.create({ title: "test" })
-          const seen: HttpClientRequest.HttpClientRequest[] = []
-          const client = HttpClient.make((req) => {
-            seen.push(req)
-            if (req.url.endsWith("/api/share")) {
-              return Effect.succeed(
-                json(req, {
-                  id: "shr_abc",
-                  url: "https://legacy-share.example.com/share/abc",
-                  secret: "sec_123",
-                }),
-              )
-            }
-            return Effect.succeed(json(req, { ok: true }))
-          })
+      () => {
+        const seen: HttpClientRequest.HttpClientRequest[] = []
+        const client = HttpClient.make((req) => {
+          seen.push(req)
+          if (req.url.endsWith("/api/share")) {
+            return Effect.succeed(
+              json(req, {
+                id: "shr_abc",
+                url: "https://legacy-share.example.com/share/abc",
+                secret: "sec_123",
+              }),
+            )
+          }
+          return Effect.succeed(json(req, { ok: true }))
+        })
+        return Effect.gen(function* () {
+          const session = yield* (yield* Session.Service).create({ title: "test" })
 
-          const result = yield* ShareNext.use.create(session.id).pipe(Effect.provide(live(client)))
+          const result = yield* (yield* ShareNext.Service).create(session.id)
 
           expect(result.id).toBe("shr_abc")
           expect(result.url).toBe("https://legacy-share.example.com/share/abc")
@@ -188,60 +174,59 @@ describe("ShareNext", () => {
           expect(seen).toHaveLength(1)
           expect(seen[0].method).toBe("POST")
           expect(seen[0].url).toBe("https://legacy-share.example.com/api/share")
-        }),
+        }).pipe(Effect.provide(integrationLayer(client)))
+      },
       { config: { enterprise: { url: "https://legacy-share.example.com" } } },
     ),
   )
 
   it.live("remove deletes the persisted share and calls the delete endpoint", () =>
     provideTmpdirInstance(
-      () =>
-        Effect.gen(function* () {
-          const session = yield* Session.use.create({ title: "test" })
-          const seen: HttpClientRequest.HttpClientRequest[] = []
-          const client = HttpClient.make((req) => {
-            seen.push(req)
-            if (req.method === "POST") {
-              return Effect.succeed(
-                json(req, {
-                  id: "shr_abc",
-                  url: "https://legacy-share.example.com/share/abc",
-                  secret: "sec_123",
-                }),
-              )
-            }
-            return Effect.succeed(HttpClientResponse.fromWeb(req, new Response(null, { status: 200 })))
-          })
+      () => {
+        const seen: HttpClientRequest.HttpClientRequest[] = []
+        const client = HttpClient.make((req) => {
+          seen.push(req)
+          if (req.method === "POST") {
+            return Effect.succeed(
+              json(req, {
+                id: "shr_abc",
+                url: "https://legacy-share.example.com/share/abc",
+                secret: "sec_123",
+              }),
+            )
+          }
+          return Effect.succeed(HttpClientResponse.fromWeb(req, new Response(null, { status: 200 })))
+        })
+        return Effect.gen(function* () {
+          const session = yield* (yield* Session.Service).create({ title: "test" })
+          const service = yield* ShareNext.Service
 
-          yield* Effect.gen(function* () {
-            yield* ShareNext.use.create(session.id)
-            yield* ShareNext.use.remove(session.id)
-          }).pipe(Effect.provide(live(client)))
+          yield* service.create(session.id)
+          yield* service.remove(session.id)
 
           expect(yield* share(session.id)).toBeUndefined()
           expect(seen.map((req) => [req.method, req.url])).toEqual([
             ["POST", "https://legacy-share.example.com/api/share"],
             ["DELETE", "https://legacy-share.example.com/api/share/shr_abc"],
           ])
-        }),
+        }).pipe(Effect.provide(integrationLayer(client)))
+      },
       { config: { enterprise: { url: "https://legacy-share.example.com" } } },
     ),
   )
 
   it.live("create fails on a non-ok response and does not persist a share", () =>
-    provideTmpdirInstance(() =>
-      Effect.gen(function* () {
-        const session = yield* Session.use.create({ title: "test" })
-        const client = HttpClient.make((req) => Effect.succeed(json(req, { error: "bad" }, 500)))
+    provideTmpdirInstance(() => {
+      const client = HttpClient.make((req) => Effect.succeed(json(req, { error: "bad" }, 500)))
+      return Effect.gen(function* () {
+        const session = yield* (yield* Session.Service).create({ title: "test" })
 
-        const exit = yield* ShareNext.Service.use((svc) => Effect.exit(svc.create(session.id))).pipe(
-          Effect.provide(live(client)),
-        )
+        const exit = yield* ShareNext.Service.use((svc) => Effect.exit(svc.create(session.id)))
 
         expect(Exit.isFailure(exit)).toBe(true)
         expect(yield* share(session.id)).toBeUndefined()
-      }),
-    ),
+      }).pipe(Effect.provide(integrationLayer(client)))
+    }),
   )
 
   it.live("ShareNext coalesces rapid diff events into one delayed sync with latest data", () =>
@@ -336,7 +321,7 @@ describe("ShareNext", () => {
               status: "modified",
             },
           ])
-        }).pipe(Effect.provide(wired(client)))
+        }).pipe(Effect.provide(integrationLayer(client)))
       },
       { config: { enterprise: { url: "https://legacy-share.example.com" } } },
     ),