fix(qa): avoid self-check report clobbering · openclaw/openclaw@33b8b72
vincentkoc
·
2026-06-23
·
via Recent Commits to openclaw:main
| Original file line number | Diff line number | Diff line change |
|---|
@@ -657,7 +657,8 @@ describe("qa-lab server", () => {
|
657 | 657 | }); |
658 | 658 | |
659 | 659 | const result = await lab.runSelfCheck(); |
660 | | -expect(result.outputPath).toBe(path.join(repoRoot, ".artifacts", "qa-e2e", "self-check.md")); |
| 660 | +expect(path.dirname(result.outputPath)).toBe(path.join(repoRoot, ".artifacts", "qa-e2e")); |
| 661 | +expect(path.basename(result.outputPath)).toMatch(/^self-check-[a-z0-9]+-[a-f0-9]{8}\.md$/u); |
661 | 662 | expect(await readFile(result.outputPath, "utf8")).toContain("Synthetic Slack-class roundtrip"); |
662 | 663 | }); |
663 | 664 | |
|
| Original file line number | Diff line number | Diff line change |
|---|
@@ -53,10 +53,13 @@ describe("resolveQaSelfCheckOutputPath", () => {
|
53 | 53 | ).toBe("/tmp/custom/self-check.md"); |
54 | 54 | }); |
55 | 55 | |
56 | | -it("anchors default self-check reports under the provided repo root", () => { |
| 56 | +it("anchors default self-check reports under unique files in the provided repo root", () => { |
57 | 57 | const repoRoot = path.resolve("/tmp/openclaw-repo"); |
58 | | -expect(resolveQaSelfCheckOutputPath({ repoRoot })).toBe( |
59 | | -path.join(repoRoot, ".artifacts", "qa-e2e", "self-check.md"), |
60 | | -); |
| 58 | +const firstPath = resolveQaSelfCheckOutputPath({ repoRoot }); |
| 59 | +const secondPath = resolveQaSelfCheckOutputPath({ repoRoot }); |
| 60 | + |
| 61 | +expect(path.dirname(firstPath)).toBe(path.join(repoRoot, ".artifacts", "qa-e2e")); |
| 62 | +expect(path.basename(firstPath)).toMatch(/^self-check-[a-z0-9]+-[a-f0-9]{8}\.md$/u); |
| 63 | +expect(secondPath).not.toBe(firstPath); |
61 | 64 | }); |
62 | 65 | }); |
| Original file line number | Diff line number | Diff line change |
|---|
|
1 | 1 | // Qa Lab plugin module implements self check behavior. |
| 2 | +import { randomUUID } from "node:crypto"; |
2 | 3 | import fs from "node:fs/promises"; |
3 | 4 | import path from "node:path"; |
4 | 5 | import type { OpenClawConfig } from "openclaw/plugin-sdk/config-contracts"; |
@@ -27,7 +28,8 @@ export function resolveQaSelfCheckOutputPath(params?: { outputPath?: string; rep
|
27 | 28 | return params.outputPath; |
28 | 29 | } |
29 | 30 | const repoRoot = path.resolve(params?.repoRoot ?? process.cwd()); |
30 | | -return path.join(repoRoot, ".artifacts", "qa-e2e", "self-check.md"); |
| 31 | +const runId = `${Date.now().toString(36)}-${randomUUID().slice(0, 8)}`; |
| 32 | +return path.join(repoRoot, ".artifacts", "qa-e2e", `self-check-${runId}.md`); |
31 | 33 | } |
32 | 34 | |
33 | 35 | export async function runQaSelfCheckAgainstState(params: { |
|
| Original file line number | Diff line number | Diff line change |
|---|
@@ -14,7 +14,7 @@ type QaE2eDeps = {
|
14 | 14 | |
15 | 15 | type QaE2eArgs = { |
16 | 16 | help: boolean; |
17 | | -outputPath: string; |
| 17 | +outputPath?: string; |
18 | 18 | }; |
19 | 19 | |
20 | 20 | async function loadQaE2eRuntime(): Promise<QaE2eRuntime> { |
@@ -58,7 +58,7 @@ export function parseQaE2eArgs(argv: readonly string[]): QaE2eArgs {
|
58 | 58 | continue; |
59 | 59 | } |
60 | 60 | if (arg === "--help" || arg === "-h") { |
61 | | -return { help: true, outputPath: ".artifacts/qa-e2e/self-check.md" }; |
| 61 | +return { help: true }; |
62 | 62 | } |
63 | 63 | const inlineOutput = arg.startsWith("--output=") ? arg.slice("--output=".length).trim() : null; |
64 | 64 | if (inlineOutput !== null) { |
@@ -85,7 +85,7 @@ export function parseQaE2eArgs(argv: readonly string[]): QaE2eArgs {
|
85 | 85 | } |
86 | 86 | outputPath = arg.trim(); |
87 | 87 | } |
88 | | -return { help: false, outputPath: outputPath || ".artifacts/qa-e2e/self-check.md" }; |
| 88 | +return outputPath ? { help: false, outputPath } : { help: false }; |
89 | 89 | } |
90 | 90 | |
91 | 91 | export async function main( |
@@ -101,7 +101,9 @@ export async function main(
|
101 | 101 | const { isQaSelfCheckSuccessful, runQaE2eSelfCheck } = await ( |
102 | 102 | deps.loadRuntime ?? loadQaE2eRuntime |
103 | 103 | )(); |
104 | | -const result = await runQaE2eSelfCheck({ outputPath: args.outputPath }); |
| 104 | +const result = args.outputPath |
| 105 | + ? await runQaE2eSelfCheck({ outputPath: args.outputPath }) |
| 106 | + : await runQaE2eSelfCheck(); |
105 | 107 | (deps.writeStdout ?? ((text: string) => process.stdout.write(text)))( |
106 | 108 | `QA self-check report: ${result.outputPath}\n`, |
107 | 109 | ); |
|
| Original file line number | Diff line number | Diff line change |
|---|
@@ -47,7 +47,7 @@ describe("qa-e2e script", () => {
|
47 | 47 | }); |
48 | 48 | |
49 | 49 | it("resolves the default self-check report path", () => { |
50 | | -expect(resolveQaE2eOutputPath([])).toBe(".artifacts/qa-e2e/self-check.md"); |
| 50 | +expect(resolveQaE2eOutputPath([])).toBeUndefined(); |
51 | 51 | expect(resolveQaE2eOutputPath([".artifacts/custom.md"])).toBe(".artifacts/custom.md"); |
52 | 52 | expect(resolveQaE2eOutputPath(["--output", ".artifacts/custom.md"])).toBe( |
53 | 53 | ".artifacts/custom.md", |
@@ -121,4 +121,22 @@ describe("qa-e2e script", () => {
|
121 | 121 | expect(writeStdout).toHaveBeenCalledWith("QA self-check report: /tmp/qa-self-check.md\n"); |
122 | 122 | expect(env.OPENCLAW_BUILD_PRIVATE_QA).toBe("1"); |
123 | 123 | }); |
| 124 | + |
| 125 | +it("lets QA Lab choose the default self-check output path", async () => { |
| 126 | +const result = makeSelfCheckResult("pass"); |
| 127 | +const runQaE2eSelfCheck = vi.fn(async () => result); |
| 128 | +const env: NodeJS.ProcessEnv = {}; |
| 129 | + |
| 130 | +await expect( |
| 131 | +main([], { |
| 132 | + env, |
| 133 | +loadRuntime: async () => ({ |
| 134 | +isQaSelfCheckSuccessful: () => true, |
| 135 | + runQaE2eSelfCheck, |
| 136 | +}), |
| 137 | +}), |
| 138 | +).resolves.toBe(0); |
| 139 | + |
| 140 | +expect(runQaE2eSelfCheck.mock.calls[0]).toEqual([]); |
| 141 | +}); |
124 | 142 | }); |
此内容由惯性聚合(RSS阅读器)自动聚合整理,仅供阅读参考。 原文来自 — 版权归原作者所有。