/** * Coverage extras — 补上 architect review 指出的关键覆盖缺口: * - drug.adapter 无 filter throw * - internal-experience 默认排除调用方自己 * - literature 空响应不入缓存 * - telemetry 异步非阻塞:adapter 结果优先,即使 telemetry 慢也立刻返 * * internal-experience 用 telemetry hook 验 sourceMetadata.excludedSelf=true * (不需要真 PG),但路径会真打 db.select() 所以本测试 skip 当无 DATABASE_URL。 */ import test from "node:test"; import assert from "node:assert/strict"; import { drugAdapter } from "../drug.adapter.ts"; import { literatureAdapter, _clearLiteratureCache } from "../literature.adapter.ts"; import { _setTelemetryTestHook, _resetBudgetCounters, } from "../index.ts"; import { _setTelemetryTestHook as _setHookFn, type TelemetryRecord, } from "../telemetry.ts"; void _setHookFn; // re-export sanity test.beforeEach(() => { _resetBudgetCounters(); _clearLiteratureCache(); _setTelemetryTestHook(null); }); test("drug.adapter — 无任何 filter 抛错(防全表扫)", async () => { await assert.rejects( () => drugAdapter.query({ kind: "drug_network", capabilityId: "cap_drug_test", params: {}, // 全空 — 必须 throw }), /requires at least one of drug_id/, ); }); test("literature — 空响应 *不* 入缓存(下次仍 cache-miss)", async () => { const calls: TelemetryRecord[] = []; _setTelemetryTestHook((r) => calls.push(r)); const realFetch = globalThis.fetch; let bridgeCalls = 0; let epmcCalls = 0; globalThis.fetch = (async (url: string | URL, _init?: RequestInit) => { const u = typeof url === "string" ? url : url.toString(); if (u.includes("/internal/tools/inspect_target")) { bridgeCalls += 1; return new Response( JSON.stringify({ tool: "inspect_target", result: { status: "ok", buckets: [] }, }), { status: 200, headers: { "Content-Type": "application/json" } }, ); } if (u.includes("europepmc")) { epmcCalls += 1; return new Response(JSON.stringify({ resultList: { result: [] }, hitCount: 0 }), { status: 200, headers: { "Content-Type": "application/json" }, }); } return realFetch(url, _init); }) as typeof fetch; process.env["DOATLAS_BRIDGE_SECRET"] = "test-secret"; try { const r1 = await literatureAdapter.query({ kind: "literature", capabilityId: "cap_empty", params: { q: "no_results_at_all_xyzzy" }, }); assert.equal(r1.items.length, 0); assert.equal(bridgeCalls, 1); assert.equal(epmcCalls, 1); const r2 = await literatureAdapter.query({ kind: "literature", capabilityId: "cap_empty", params: { q: "no_results_at_all_xyzzy" }, }); assert.equal(r2.items.length, 0); // 关键断言:第二次仍真打了 bridge + epmc(因为空响应没有缓存) assert.equal(bridgeCalls, 2, "空响应不应被缓存,第二次必须重打 bridge"); assert.equal(epmcCalls, 2, "空响应不应被缓存,第二次必须重打 EPMC"); // telemetry:两次都标 cacheHit='miss' — 没有 'hit' 出现 const cacheHits = calls.filter((c) => c.cacheHit === "hit"); assert.equal(cacheHits.length, 0, "空响应路径上不应出现 cacheHit='hit'"); } finally { globalThis.fetch = realFetch; } }); test("telemetry — adapter 结果立刻返,不等待 telemetry 完成", async () => { // 让 telemetry hook 真去等 200ms — 验证 adapter 不会被它阻塞。 let telemetryDone = false; _setTelemetryTestHook((_r) => { setTimeout(() => { telemetryDone = true; }, 200); }); const t0 = Date.now(); await assert.rejects(() => drugAdapter.query({ kind: "drug_network", capabilityId: "cap_telem", params: {}, // throw 路径(同样 fire-and-forget telemetry) }), ); const elapsed = Date.now() - t0; assert.ok( elapsed < 100, `adapter 必须立即返回(<100ms),不能等 telemetry;实际 ${elapsed}ms`, ); // telemetryDone 这时应该还是 false(timer 200ms 后才置 true) assert.equal(telemetryDone, false, "adapter 返回时 telemetry hook 还在 timer 中"); });