- M1-M2: 数据层与核心API(DuckDB, entries/tags/comments/search服务) - M3: SSR页面(EJS模板,接真实数据) - M4: 管理后台(登录/用户/内容源/AI ingest) - M5: 采集层(scheduler+rss/html/eryajf适配器) - M6: MCP只读接口(Streamable HTTP, 4工具) - M7: Docker部署(Dockerfile+docker-compose) - 测试: 10个用例全部通过 - 修复: DuckDB连接参数绑定、状态机迁移、标签树操作
58 lines
1.8 KiB
JavaScript
58 lines
1.8 KiB
JavaScript
import test from "node:test";
|
|
import assert from "node:assert/strict";
|
|
import { withApp } from "./helpers.js";
|
|
import { registerAdapter } from "../src/ingest/adapters/index.js";
|
|
import { runSource } from "../src/ingest/pipeline.js";
|
|
|
|
test("feed pipeline dedupes by url and records runs", async () => {
|
|
await withApp(async ({ api, loginAdmin }) => {
|
|
registerAdapter("test-fake", {
|
|
async fetch() {
|
|
return [
|
|
{
|
|
title: "ripgrep",
|
|
url: "https://github.com/BurntSushi/ripgrep?utm_source=x",
|
|
description: "dup",
|
|
},
|
|
{
|
|
title: "brand-new-tool",
|
|
url: "https://github.com/fake/brand-new-tool",
|
|
description: "new item from fake source",
|
|
},
|
|
{ title: "", url: "https://example.com/invalid", description: "" },
|
|
];
|
|
},
|
|
});
|
|
|
|
const cookie = await loginAdmin();
|
|
const created = await api("/api/admin/sources", {
|
|
method: "POST",
|
|
body: {
|
|
name: "fake 源",
|
|
url: "mem://fake",
|
|
adapter: "test-fake",
|
|
cron_expr: "0 9 * * 1",
|
|
},
|
|
cookie,
|
|
});
|
|
assert.equal(created.status, 201);
|
|
const sourceId = created.json.data.id;
|
|
|
|
const stats = await runSource(sourceId);
|
|
assert.equal(stats.found, 3);
|
|
assert.equal(stats.created, 1);
|
|
assert.equal(stats.skipped, 2);
|
|
|
|
const runs = await api(`/api/admin/sources/${sourceId}/runs`, {}, cookie ? {} : {});
|
|
void runs;
|
|
|
|
const pending = await api("/api/entries?q=brand-new-tool&status=all");
|
|
assert.equal(pending.json.data.total, 1);
|
|
assert.equal(pending.json.data.items[0].status, "pending");
|
|
|
|
const manual = await api(`/api/admin/sources/${sourceId}/run`, { method: "POST", cookie });
|
|
assert.equal(manual.json.data.created, 0);
|
|
assert.equal(manual.json.data.skipped, 3);
|
|
});
|
|
});
|