openAgent
gitlabThe open source UNIVERSAL agent.
clone
https://gitlab.com/bitzzdev/openAgent.gitAIagentautomationopen-sourceuniversal-agent
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/app-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 { AccountRepo } from "../../src/account/repo"import { EventV2Bridge } from "../../src/event-v2-bridge"import { Session } from "@/session/session"import type { SessionID } from "../../src/session/schema"import { ShareNext } from "@/share/share-next"import { SessionShareTable } from "@opencode-ai/core/share/sql"import { Database } from "@opencode-ai/core/database/database"import { eq } from "drizzle-orm"import { provideTmpdirInstance } from "../fixture/fixture"import { resetDatabase } from "../fixture/db"import { pollWithTimeout, testEffect } from "../lib/effect"const env = LayerNode.compile(LayerNode.group([CrossSpawnSpawner.node]))const it = testEffect(env)const json = (req: Parameters<typeof HttpClientResponse.fromWeb>[0], body: unknown, status = 200) =>HttpClientResponse.fromWeb(req,new Response(JSON.stringify(body), {status,headers: { "content-type": "application/json" },}),)const none = HttpClient.make(() => Effect.die("unexpected http call"))function requestLayer(client: HttpClient.HttpClient) {const replacement = [httpClient, Layer.succeed(HttpClient.HttpClient, client)] as constreturn LayerNode.compile(LayerNode.group([ShareNext.node, AccountRepo.node]), [replacement])}function integrationLayer(client: HttpClient.HttpClient) {const replacement = [httpClient, Layer.succeed(HttpClient.HttpClient, client)] as constreturn LayerNode.compile(LayerNode.group([ShareNext.node,EventV2Bridge.node,Session.node,SessionProjector.node,AccountRepo.node,Database.node,]),[replacement],)}const share = (id: SessionID) =>Effect.gen(function* () {const { db } = yield* Database.Servicereturn yield* db.select().from(SessionShareTable).where(eq(SessionShareTable.session_id, id)).get().pipe(Effect.orDie)})const seed = (url: string, org?: string) =>AccountRepo.Service.use((repo) =>repo.persistAccount({id: AccountID.make("account-1"),email: "user@example.com",url,accessToken: AccessToken.make("st_test_token"),refreshToken: RefreshToken.make("rt_test_token"),expiry: Date.now() + 10 * 60_000,orgID: org ? Option.some(OrgID.make(org)) : Option.none(),}),)beforeEach(async () => {await resetDatabase()})describe("ShareNext", () => {it.live("request uses legacy share API without active org account", () =>provideTmpdirInstance(() =>ShareNext.Service.use((svc) =>Effect.gen(function* () {const req = yield* svc.request()expect(req.api.create).toBe("/api/share")expect(req.api.sync("shr_123")).toBe("/api/share/shr_123/sync")expect(req.api.remove("shr_123")).toBe("/api/share/shr_123")expect(req.api.data("shr_123")).toBe("/api/share/shr_123/data")expect(req.baseUrl).toBe("https://legacy-share.example.com")expect(req.headers).toEqual({})}),).pipe(Effect.provide(requestLayer(none))),{ config: { enterprise: { url: "https://legacy-share.example.com" } } },),)it.live("request uses default URL when no enterprise config", () =>provideTmpdirInstance(() =>ShareNext.Service.use((svc) =>Effect.gen(function* () {const req = yield* svc.request()expect(req.baseUrl).toBe("https://opncd.ai")expect(req.api.create).toBe("/api/share")expect(req.headers).toEqual({})}),).pipe(Effect.provide(requestLayer(none))),),)it.live("request uses org share API with auth headers when account is active", () =>provideTmpdirInstance(() =>Effect.gen(function* () {yield* seed("https://control.example.com", "org-1")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")expect(req.api.remove("shr_123")).toBe("/api/shares/shr_123")expect(req.api.data("shr_123")).toBe("/api/shares/shr_123/data")expect(req.baseUrl).toBe("https://control.example.com")expect(req.headers).toEqual({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(() => {const createRequests: HttpClientRequest.HttpClientRequest[] = []const client = HttpClient.make((req) => {if (req.url.endsWith("/api/share")) {createRequests.push(req)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* (yield* ShareNext.Service).create(session.id)expect(result.id).toBe("shr_abc")expect(result.url).toBe("https://legacy-share.example.com/share/abc")expect(result.secret).toBe("sec_123")const row = yield* share(session.id)expect(row?.id).toBe("shr_abc")expect(row?.url).toBe("https://legacy-share.example.com/share/abc")expect(row?.secret).toBe("sec_123")expect(createRequests).toHaveLength(1)expect(createRequests[0].method).toBe("POST")expect(createRequests[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(() => {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.Serviceyield* 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(() => {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)))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", () =>provideTmpdirInstance(() => {const seen: Array<{ url: string; body: string }> = []const client = HttpClient.make((req) => {if (req.url.endsWith("/sync") && req.body._tag === "Uint8Array") {seen.push({ url: req.url, body: new TextDecoder().decode(req.body.body) })}return Effect.succeed(json(req, { ok: true }))})return Effect.gen(function* () {const events = yield* EventV2Bridge.Serviceconst share = yield* ShareNext.Serviceconst session = yield* Session.Serviceconst info = yield* session.create({ title: "first" })yield* share.init()yield* Effect.sleep(50)const { db } = yield* Database.Serviceyield* db.insert(SessionShareTable).values({session_id: info.id,id: "shr_abc",url: "https://legacy-share.example.com/share/abc",secret: "sec_123",}).run().pipe(Effect.orDie)yield* events.publish(Session.Event.Diff, {sessionID: info.id,diff: [{file: "a.ts",patch:"Index: a.ts\n===================================================================\n--- a.ts\t\n+++ a.ts\t\n@@ -1,1 +1,1 @@\n-one\n\\ No newline at end of file\n+two\n\\ No newline at end of file\n",additions: 1,deletions: 1,status: "modified",},],})yield* events.publish(Session.Event.Diff, {sessionID: info.id,diff: [{file: "b.ts",patch:"Index: b.ts\n===================================================================\n--- b.ts\t\n+++ b.ts\t\n@@ -1,1 +1,1 @@\n-old\n\\ No newline at end of file\n+new\n\\ No newline at end of file\n",additions: 2,deletions: 0,status: "modified",},],})yield* pollWithTimeout(Effect.sync(() => (seen.length === 1 ? true : undefined)),"timed out waiting for share sync","5 seconds",)expect(seen).toHaveLength(1)expect(seen[0].url).toBe("https://legacy-share.example.com/api/share/shr_abc/sync")const body = JSON.parse(seen[0].body) as {secret: stringdata: Array<{type: stringdata: Array<{file: stringpatch: stringadditions: numberdeletions: numberstatus?: string}>}>}expect(body.secret).toBe("sec_123")expect(body.data).toHaveLength(1)expect(body.data[0].type).toBe("session_diff")expect(body.data[0].data).toEqual([{file: "b.ts",patch:"Index: b.ts\n===================================================================\n--- b.ts\t\n+++ b.ts\t\n@@ -1,1 +1,1 @@\n-old\n\\ No newline at end of file\n+new\n\\ No newline at end of file\n",additions: 2,deletions: 0,status: "modified",},])}).pipe(Effect.provide(integrationLayer(client)))},{ config: { enterprise: { url: "https://legacy-share.example.com" } } },),)})