test(api): 补齐天猫恢复审计与指标回归
This commit is contained in:
parent
f8085888c1
commit
8c4d057202
6
TODO.md
6
TODO.md
@ -73,7 +73,7 @@
|
|||||||
- [ ] `S3-03` 阻塞恢复与 `L3 Browser Recovery` 落地(进行中)
|
- [ ] `S3-03` 阻塞恢复与 `L3 Browser Recovery` 落地(进行中)
|
||||||
- [ ] `S3-04` 双平台候选确认与执行控制台落地(进行中:页面与状态展示已具备,真实并发执行待补)
|
- [ ] `S3-04` 双平台候选确认与执行控制台落地(进行中:页面与状态展示已具备,真实并发执行待补)
|
||||||
- [x] `S3-05` `PartialCompleted`、`Blocked`、`Failed` 汇总规则落地
|
- [x] `S3-05` `PartialCompleted`、`Blocked`、`Failed` 汇总规则落地
|
||||||
- [ ] `S3-06` 双平台主回归包落地(进行中:已新增 JD + 天猫 live 搜索、确认、执行、报告的主链 API 回归,并覆盖 `tmall SearchBlocked + jd Completed`、`tmall NoResult + jd Completed`、`tmall Blocked + jd Completed`、`tmall Blocked -> retry success -> report v2`、`tmall Blocked -> retry blocked -> report unchanged`,以及 `tmall SearchBlocked` 恢复后二次确认仅补跑新恢复平台的回归,待继续补更多失败/恢复组合)
|
- [ ] `S3-06` 双平台主回归包落地(进行中:已新增 JD + 天猫 live 搜索、确认、执行、报告的主链 API 回归,并覆盖 `tmall SearchBlocked + jd Completed`、`tmall NoResult + jd Completed`、`tmall Blocked + jd Completed`、`tmall Blocked -> retry success -> report v2`、`tmall Blocked -> retry blocked -> report unchanged`、`tmall SearchBlocked -> retry success -> audit/metrics`,以及 `tmall SearchBlocked` 恢复后二次确认仅补跑新恢复平台的回归,待继续补更多失败/恢复组合)
|
||||||
|
|
||||||
## `S4`
|
## `S4`
|
||||||
|
|
||||||
@ -86,7 +86,7 @@
|
|||||||
|
|
||||||
## `S5`
|
## `S5`
|
||||||
|
|
||||||
- [ ] `S5-01` 平台级定向重试稳定化(进行中)
|
- [ ] `S5-01` 平台级定向重试稳定化(进行中:已补天猫 `SearchBlocked` 恢复后的审计与 `retryCount/recoveryCount` 回归,待继续扩展更多失败来源与版本差异检测)
|
||||||
- [ ] `S5-02` 性能与成本优化(未开始)
|
- [ ] `S5-02` 性能与成本优化(未开始)
|
||||||
- [ ] `S5-03` UAT 与试运行任务集执行(未开始)
|
- [ ] `S5-03` UAT 与试运行任务集执行(未开始)
|
||||||
- [ ] `S5-04` 部署、值守、排障与热修手册落地(未开始)
|
- [ ] `S5-04` 部署、值守、排障与热修手册落地(未开始)
|
||||||
@ -96,6 +96,6 @@
|
|||||||
|
|
||||||
- [ ] `X-01` 上下游文档变更同步(进行中)
|
- [ ] `X-01` 上下游文档变更同步(进行中)
|
||||||
- [ ] `X-02` 安全与合规检查(未开始)
|
- [ ] `X-02` 安全与合规检查(未开始)
|
||||||
- [ ] `X-03` 测试资产维护(进行中:已补天猫搜索解析/服务回归,以及双平台 live 主链、`SearchBlocked`、`NoResult`、`Blocked`、`Blocked -> retry success`、`Blocked -> retry blocked -> report unchanged` 与 `SearchBlocked` 恢复后二次确认不重复执行已完成平台的回归,真实 fixture/HAR 待补)
|
- [ ] `X-03` 测试资产维护(进行中:已补天猫搜索解析/服务回归,以及双平台 live 主链、`SearchBlocked`、`NoResult`、`Blocked`、`Blocked -> retry success`、`Blocked -> retry blocked -> report unchanged`、`SearchBlocked -> retry success -> audit/metrics` 与 `SearchBlocked` 恢复后二次确认不重复执行已完成平台的回归,真实 fixture/HAR 待补)
|
||||||
- [ ] `X-04` 设计一致性与可访问性检查(进行中)
|
- [ ] `X-04` 设计一致性与可访问性检查(进行中)
|
||||||
- [ ] `X-05` 观测指标复盘(未开始)
|
- [ ] `X-05` 观测指标复盘(未开始)
|
||||||
|
|||||||
@ -903,6 +903,115 @@ describe("Dual-platform live loop", () => {
|
|||||||
await app.close();
|
await app.close();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it("records recovery audit entries and retry metrics when a SearchBlocked Tmall platform recovers", async () => {
|
||||||
|
let allowTmallSearch = false;
|
||||||
|
const tmallLiveService = createTmallLiveServiceStub({
|
||||||
|
async previewSearch(query) {
|
||||||
|
if (!allowTmallSearch) {
|
||||||
|
const error = new Error("Tmall search session appears invalid.") as Error & {
|
||||||
|
statusCode: number;
|
||||||
|
};
|
||||||
|
error.statusCode = 409;
|
||||||
|
throw error;
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
query,
|
||||||
|
source: "html",
|
||||||
|
candidateCount: 1,
|
||||||
|
candidates: [
|
||||||
|
{
|
||||||
|
candidateId: "tmall-934454505228",
|
||||||
|
platform: "tmall",
|
||||||
|
title: "Apple iPhone 15",
|
||||||
|
price: 4399,
|
||||||
|
priceLabel: "CNY 4399",
|
||||||
|
storeName: "Apple 官方旗舰店",
|
||||||
|
productUrl: "https://detail.tmall.com/item.htm?id=934454505228",
|
||||||
|
imageUrl: "https://img.alicdn.com/example.jpg",
|
||||||
|
salesHint: "已售 70万+",
|
||||||
|
specLabel: "128GB",
|
||||||
|
highlights: ["天猫", "官方旗舰店"]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
};
|
||||||
|
}
|
||||||
|
});
|
||||||
|
const app = createServer({
|
||||||
|
jdLiveService: createJdLiveServiceStub(),
|
||||||
|
tmallLiveService
|
||||||
|
});
|
||||||
|
await app.ready();
|
||||||
|
await importDualLiveSessions(app);
|
||||||
|
|
||||||
|
const createdTask = await createTask(app, "iPhone 15");
|
||||||
|
expect(
|
||||||
|
createdTask.platformRuns.find((run: { platform: string }) => run.platform === "tmall")
|
||||||
|
).toMatchObject({
|
||||||
|
platform: "tmall",
|
||||||
|
status: "SearchBlocked"
|
||||||
|
});
|
||||||
|
|
||||||
|
allowTmallSearch = true;
|
||||||
|
|
||||||
|
const retryResponse = await app.inject({
|
||||||
|
method: "POST",
|
||||||
|
url: `/api/tasks/${createdTask.taskId}/platforms/tmall/retry`
|
||||||
|
});
|
||||||
|
|
||||||
|
expect(retryResponse.statusCode).toBe(200);
|
||||||
|
expect(
|
||||||
|
retryResponse
|
||||||
|
.json()
|
||||||
|
.task.platformRuns.find((run: { platform: string }) => run.platform === "tmall")
|
||||||
|
).toMatchObject({
|
||||||
|
platform: "tmall",
|
||||||
|
status: "AwaitingSelection"
|
||||||
|
});
|
||||||
|
|
||||||
|
const auditResponse = await app.inject({
|
||||||
|
method: "GET",
|
||||||
|
url: `/api/tasks/${createdTask.taskId}/audit`
|
||||||
|
});
|
||||||
|
|
||||||
|
expect(auditResponse.statusCode).toBe(200);
|
||||||
|
expect(auditResponse.json().audit).toEqual(
|
||||||
|
expect.arrayContaining([
|
||||||
|
expect.objectContaining({
|
||||||
|
action: "platform.retry_started",
|
||||||
|
platform: "tmall"
|
||||||
|
}),
|
||||||
|
expect.objectContaining({
|
||||||
|
action: "task.recovery_completed",
|
||||||
|
platform: "tmall"
|
||||||
|
}),
|
||||||
|
expect.objectContaining({
|
||||||
|
action: "platform.retry_completed",
|
||||||
|
platform: "tmall"
|
||||||
|
})
|
||||||
|
])
|
||||||
|
);
|
||||||
|
|
||||||
|
const overviewResponse = await app.inject({
|
||||||
|
method: "GET",
|
||||||
|
url: "/api/observability/overview"
|
||||||
|
});
|
||||||
|
|
||||||
|
expect(overviewResponse.statusCode).toBe(200);
|
||||||
|
expect(
|
||||||
|
overviewResponse
|
||||||
|
.json()
|
||||||
|
.overview.platformRuns.find((metric: { platform: string }) => metric.platform === "tmall")
|
||||||
|
).toMatchObject({
|
||||||
|
platform: "tmall",
|
||||||
|
retryCount: 1,
|
||||||
|
recoveryCount: 1
|
||||||
|
});
|
||||||
|
expect(overviewResponse.json().overview.audits.recoveryActions).toBe(3);
|
||||||
|
|
||||||
|
await app.close();
|
||||||
|
});
|
||||||
|
|
||||||
it("keeps the current report version when a blocked Tmall retry does not recover", async () => {
|
it("keeps the current report version when a blocked Tmall retry does not recover", async () => {
|
||||||
const tmallLiveService = createTmallLiveServiceStub({
|
const tmallLiveService = createTmallLiveServiceStub({
|
||||||
async previewProduct() {
|
async previewProduct() {
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user