Files
rootandClaude Opus 5.5 c9e8120fc6 test: server 测试共用建库与假引擎,sse-pg 归入串行组
- 新增 apps/server/test/support/{pg,engine}.ts:测试库地址、可用性探测、schema 咨询锁、
  建 schema + 加锁迁移 + 删除、可选去重的假引擎;6 份 harness 改用它(acquisition-organize 与
  file-manager 原先迁移不加锁,并行下有冲突隐患,一并修正)
- sse-pg 起子进程,并行下子进程启动超时,归入 serial
- 修正 b61335e 挪动 / 改名测试后遗留的 import 排序与格式(当时 lint 检查经管道被吞掉退出码)

Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-10-02 17:40:43 +08:00

80 lines
3.4 KiB
TypeScript

import { MOCK_CAMOFOX_IDENTITY } from "@umt/testkit";
import { afterAll, beforeAll, describe, expect, it } from "vitest";
import { egressProxy } from "../../src/modules/browser/service.ts";
import { sourcesIdentityModule } from "../../src/modules/sources-identity/index.ts";
import { readBrowserUserAgent } from "../../src/modules/sources-identity/service/user-agent.ts";
import { type BrowserHarness, createBrowserHarness, type Loose, ORIGIN, pgAvailable } from "./harness.ts";
// BR-4:打开会话前按站点下发出口(站点开代理 = 与 HTTP 同一代理,否则直连);浏览器固定身份写进 browser_provider.identity,
// 站点请求 UA 经钩子跟随它。
const up = await pgAvailable();
describe("egressProxy", () => {
it("URL → 上下文代理(口令拆出);非法为 null", () => {
expect(egressProxy("http://u:p%[email protected]:7891")).toEqual({
server: "http://172.17.0.1:7891",
username: "u",
password: "p@ss",
});
expect(egressProxy("socks5://127.0.0.1:1080")).toEqual({ server: "socks5://127.0.0.1:1080" });
expect(egressProxy("not a url")).toBeNull();
});
});
describe.skipIf(!up)("BR-4 浏览器身份与出口", () => {
let h: BrowserHarness;
const open = async () =>
(await h.req("/browser/sessions", { body: { siteId: h.siteId, accountId: null, url: `${ORIGIN}/torrents.php` } }))
.body.data as Loose;
const closeAll = async () => {
for (const s of (await h.req("/browser/sessions")).body.data.items as Loose[])
await h.req(`/browser/sessions/${s.id}`, { method: "DELETE" });
};
beforeAll(async () => {
h = await createBrowserHarness("br4id");
}, 120_000);
afterAll(async () => {
await h?.close();
});
it("站点不开代理:该 profile 直连;打开时读浏览器身份存库,站点请求 UA 跟随", async () => {
const s = await open();
expect(h.mock.egress.get(s.profileKey)).toBeNull();
const calls = h.mock.calls.map((c) => `${c.method} ${c.path}`);
expect(calls.indexOf(`PUT /umt/sessions/${encodeURIComponent(s.profileKey)}/proxy`)).toBeLessThan(
calls.lastIndexOf("POST /tabs"),
);
const row = await h.db
.selectFrom("browser_provider")
.select("identity")
.where("id", "=", h.providerId)
.executeTakeFirstOrThrow();
expect(row.identity).toMatchObject({ userAgent: MOCK_CAMOFOX_IDENTITY.userAgent, os: "windows" });
expect(await readBrowserUserAgent(h.ctx)).toBe(MOCK_CAMOFOX_IDENTITY.userAgent);
expect(await sourcesIdentityModule.runtime(h.ctx).defaultUserAgent()).toBe(MOCK_CAMOFOX_IDENTITY.userAgent);
await closeAll();
});
it("站点开代理且设了代理地址:该 profile 走同一代理(口令单独传)", async () => {
await h.db.updateTable("site").set({ proxy: true }).where("id", "=", h.siteId).execute();
await h.db
.insertInto("settings")
.values({ key: "sites", value: JSON.stringify({ proxyUrl: "http://user:[email protected]:7891" }) })
.onConflict((oc) =>
oc.column("key").doUpdateSet({ value: JSON.stringify({ proxyUrl: "http://user:[email protected]:7891" }) }),
)
.execute();
const s = await open();
expect(h.mock.egress.get(s.profileKey)).toEqual({
server: "http://172.17.0.1:7891",
username: "user",
password: "pw",
});
await closeAll();
await h.db.updateTable("site").set({ proxy: false }).where("id", "=", h.siteId).execute();
});
});