mirror of
https://gitee.com/zhangsken/opencode.git
synced 2026-10-16 10:30:01 +08:00
test(ci): register omitted V2 unit suites (#45970)
This commit is contained in:
@@ -2,3 +2,4 @@ packages/core/migration/**/snapshot.json linguist-generated
|
||||
packages/core/src/database/migration.gen.ts linguist-generated
|
||||
packages/core/src/models-dev/snapshot.txt linguist-generated
|
||||
packages/core/src/**/*.txt text eol=lf
|
||||
packages/httpapi-codegen/test/generated/*.ts text eol=lf
|
||||
|
||||
@@ -2,6 +2,7 @@ import { describe, expect, test } from "bun:test"
|
||||
import { mkdtemp, rm } from "node:fs/promises"
|
||||
import { tmpdir } from "node:os"
|
||||
import { join } from "node:path"
|
||||
import { fileURLToPath } from "node:url"
|
||||
import { Effect, FileSystem, Schema, SchemaAST, SchemaGetter } from "effect"
|
||||
import {
|
||||
HttpApi,
|
||||
@@ -1096,7 +1097,7 @@ describe("HttpApiCodegen.generate", () => {
|
||||
Effect.gen(function* () {
|
||||
const output = compile(FixtureApi)
|
||||
const actual = yield* Effect.promise(() =>
|
||||
Array.fromAsync(new Bun.Glob("*.ts").scan(new URL("generated", import.meta.url).pathname)),
|
||||
Array.fromAsync(new Bun.Glob("*.ts").scan(fileURLToPath(new URL("generated", import.meta.url)))),
|
||||
)
|
||||
expect(actual.sort((a, b) => a.localeCompare(b))).toEqual(
|
||||
output.files.map((file) => file.path).sort((a, b) => a.localeCompare(b)),
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import { describe, expect } from "bun:test"
|
||||
import { join } from "node:path"
|
||||
import { Effect, FileSystem, Option } from "effect"
|
||||
import { write, type Output } from "../src"
|
||||
import { it } from "./effect"
|
||||
@@ -15,8 +16,8 @@ describe("HttpApiCodegen.write", () => {
|
||||
yield* write(output, "/generated")
|
||||
|
||||
expect(writes).toEqual([
|
||||
{ path: "/generated/session.ts", content: "export const session = {}\n" },
|
||||
{ path: "/generated/.httpapi-codegen.json", content: '["session.ts"]\n' },
|
||||
{ path: join("/generated", "session.ts"), content: "export const session = {}\n" },
|
||||
{ path: join("/generated", ".httpapi-codegen.json"), content: '["session.ts"]\n' },
|
||||
])
|
||||
}).pipe(
|
||||
Effect.provideService(
|
||||
@@ -55,7 +56,7 @@ describe("HttpApiCodegen.write", () => {
|
||||
writeFileString: () => Effect.void,
|
||||
}),
|
||||
),
|
||||
Effect.tap(() => Effect.sync(() => expect(removed).toEqual(["/generated/old.ts"]))),
|
||||
Effect.tap(() => Effect.sync(() => expect(removed).toEqual([join("/generated", "old.ts")]))),
|
||||
)
|
||||
})
|
||||
|
||||
|
||||
@@ -11,6 +11,7 @@ import { ServerFetch } from "../src/fetch"
|
||||
const options = {
|
||||
app: { version: "test-version" },
|
||||
database: { path: ":memory:" },
|
||||
config: { project: false },
|
||||
models: { fetch: false },
|
||||
fs: { filewatcher: false },
|
||||
} as const
|
||||
@@ -26,15 +27,20 @@ function occupy(port: number, cancel = false) {
|
||||
server: createServer((request, response) => {
|
||||
requests.push(request.url ?? "")
|
||||
response.end(cancel ? "cancelled" : "still running", () => {
|
||||
if (cancel) servers.forEach((item) => item.server.close())
|
||||
if (cancel)
|
||||
servers.forEach((item) => {
|
||||
// Bun clears its native handle in close(), so force-close connections first.
|
||||
item.server.closeAllConnections()
|
||||
item.server.close()
|
||||
})
|
||||
})
|
||||
}),
|
||||
}))
|
||||
yield* Effect.addFinalizer(() =>
|
||||
Effect.forEach(servers, (item) =>
|
||||
Effect.callback<void>((resume) => {
|
||||
item.server.close(() => resume(Effect.void))
|
||||
item.server.closeAllConnections()
|
||||
item.server.close(() => resume(Effect.void))
|
||||
}),
|
||||
),
|
||||
)
|
||||
@@ -154,22 +160,26 @@ it.live("falls back to port 1457 when OpenAI OAuth port 1455 remains busy", () =
|
||||
}),
|
||||
)
|
||||
|
||||
it.live("explains how to recover when both OpenAI OAuth callback ports are busy", () =>
|
||||
Effect.gen(function* () {
|
||||
yield* occupy(1455)
|
||||
yield* occupy(1457)
|
||||
const handler = yield* ServerFetch.make(options)
|
||||
yield* ready(handler)
|
||||
const response = yield* connectOpenAI(handler)
|
||||
it.live(
|
||||
"explains how to recover when both OpenAI OAuth callback ports are busy",
|
||||
() =>
|
||||
Effect.gen(function* () {
|
||||
yield* occupy(1455)
|
||||
yield* occupy(1457)
|
||||
const handler = yield* ServerFetch.make(options)
|
||||
yield* ready(handler)
|
||||
const response = yield* connectOpenAI(handler)
|
||||
|
||||
expect(response.status).toBe(400)
|
||||
expect(yield* Effect.promise(() => response.json())).toEqual({
|
||||
_tag: "InvalidRequestError",
|
||||
message:
|
||||
"OpenAI browser login needs local port 1455 or 1457, but both are already in use. Stop the processes using those ports or choose ChatGPT Pro/Plus (headless), then try again.",
|
||||
kind: "integration_authorization",
|
||||
})
|
||||
}),
|
||||
expect(response.status).toBe(400)
|
||||
expect(yield* Effect.promise(() => response.json())).toEqual({
|
||||
_tag: "InvalidRequestError",
|
||||
message:
|
||||
"OpenAI browser login needs local port 1455 or 1457, but both are already in use. Stop the processes using those ports or choose ChatGPT Pro/Plus (headless), then try again.",
|
||||
kind: "integration_authorization",
|
||||
})
|
||||
}),
|
||||
// Real retries wait 18 * 200 ms; startup and scoped cleanup also count toward the deadline.
|
||||
{ timeout: 10_000 },
|
||||
)
|
||||
|
||||
it.live("treats destroying a missing workspace as success", () =>
|
||||
|
||||
@@ -1,19 +1,12 @@
|
||||
import { describe, expect, test } from "bun:test"
|
||||
import { Effect } from "effect"
|
||||
|
||||
const forbidden = /["']@opencode-ai\/(?:core|sdk|server)(?:\/[^"']*)?["']/
|
||||
const oldSession = /(?:SessionV1|session-v1|legacy-message|legacy-message-values)/
|
||||
|
||||
describe("Session UI package boundaries", () => {
|
||||
test("does not import server runtime packages", async () => {
|
||||
const files = new Bun.Glob("**/*.{ts,tsx}")
|
||||
const violations: string[] = []
|
||||
|
||||
for await (const path of files.scan({ cwd: import.meta.dir, absolute: true })) {
|
||||
if (path === import.meta.path) continue
|
||||
if (forbidden.test(await Bun.file(path).text())) violations.push(path.slice(import.meta.dir.length + 1))
|
||||
}
|
||||
|
||||
expect(violations).toEqual([])
|
||||
expect(await findViolations(forbidden)).toEqual([])
|
||||
})
|
||||
|
||||
test("does not declare server runtime dependencies", async () => {
|
||||
@@ -26,15 +19,7 @@ describe("Session UI package boundaries", () => {
|
||||
})
|
||||
|
||||
test("does not contain old Session message boundaries", async () => {
|
||||
const files = new Bun.Glob("**/*.{ts,tsx}")
|
||||
const violations: string[] = []
|
||||
|
||||
for await (const path of files.scan({ cwd: import.meta.dir, absolute: true })) {
|
||||
if (path === import.meta.path) continue
|
||||
if (oldSession.test(await Bun.file(path).text())) violations.push(path.slice(import.meta.dir.length + 1))
|
||||
}
|
||||
|
||||
expect(violations).toEqual([])
|
||||
expect(await findViolations(oldSession)).toEqual([])
|
||||
})
|
||||
|
||||
test("exports the current Session document surface", async () => {
|
||||
@@ -49,3 +34,18 @@ describe("Session UI package boundaries", () => {
|
||||
expect(exports["./timeline/projection"]).toBe("./src/timeline/projection.ts")
|
||||
})
|
||||
})
|
||||
|
||||
async function findViolations(pattern: RegExp) {
|
||||
const files = await Array.fromAsync(new Bun.Glob("**/*.{ts,tsx}").scan({ cwd: import.meta.dir, absolute: true }))
|
||||
const matches = await Effect.runPromise(
|
||||
Effect.forEach(
|
||||
files.filter((path) => path !== import.meta.path),
|
||||
(path) =>
|
||||
Effect.promise(async () =>
|
||||
pattern.test(await Bun.file(path).text()) ? path.slice(import.meta.dir.length + 1) : undefined,
|
||||
),
|
||||
{ concurrency: 8 },
|
||||
),
|
||||
)
|
||||
return matches.filter((path) => path !== undefined)
|
||||
}
|
||||
|
||||
+11
@@ -34,6 +34,10 @@
|
||||
"dependsOn": [],
|
||||
"outputs": ["dist/**"]
|
||||
},
|
||||
"@opencode-ai/ai#test": {
|
||||
"dependsOn": ["^build"],
|
||||
"outputs": []
|
||||
},
|
||||
"@opencode-ai/codemode#test": {
|
||||
"dependsOn": ["^build"],
|
||||
"outputs": []
|
||||
@@ -45,6 +49,13 @@
|
||||
"@opencode-ai/function#test": {
|
||||
"outputs": []
|
||||
},
|
||||
"@opencode-ai/httpapi-codegen#test": {
|
||||
"outputs": []
|
||||
},
|
||||
"@opencode-ai/server#test": {
|
||||
"dependsOn": ["^build"],
|
||||
"outputs": []
|
||||
},
|
||||
"@opencode-ai/cli#test": {
|
||||
"dependsOn": ["^build"],
|
||||
"outputs": []
|
||||
|
||||
Reference in New Issue
Block a user