@@ -21,6 +21,10 @@ function createHealthyDockerDeps(calls: string[]): QaDockerUpDeps {
|
21 | 21 | }; |
22 | 22 | } |
23 | 23 | |
| 24 | +function quoteForShell(value: string) { |
| 25 | +return `'${value.replaceAll("'", `'"'"'`)}'`; |
| 26 | +} |
| 27 | + |
24 | 28 | describe("runQaDockerUp", () => { |
25 | 29 | it("builds the QA UI, writes the harness, starts compose, and waits for health", async () => { |
26 | 30 | const calls: string[] = []; |
@@ -68,12 +72,39 @@ describe("runQaDockerUp", () => {
|
68 | 72 | expect(result.qaLabUrl).toBe("http://127.0.0.1:43124"); |
69 | 73 | expect(result.gatewayUrl).toBe("http://127.0.0.1:18889/"); |
70 | 74 | expect(result.composeFile).toBe(composeFile); |
71 | | -expect(result.stopCommand).toBe(`docker compose -f ${composeFile} down`); |
| 75 | +expect(result.stopCommand).toBe(`docker compose -f ${quoteForShell(composeFile)} down`); |
72 | 76 | } finally { |
73 | 77 | await rm(outputDir, { recursive: true, force: true }); |
74 | 78 | } |
75 | 79 | }); |
76 | 80 | |
| 81 | +it("quotes the printed stop command when the compose path is shell-sensitive", async () => { |
| 82 | +const calls: string[] = []; |
| 83 | +const tempRoot = await mkdtemp(path.join(os.tmpdir(), "qa-docker-up-")); |
| 84 | +const outputDir = path.join(tempRoot, "mac path's qa lab"); |
| 85 | +const repoRoot = path.resolve("/repo/openclaw"); |
| 86 | +const composeFile = path.join(outputDir, "docker-compose.qa.yml"); |
| 87 | + |
| 88 | +try { |
| 89 | +const result = await runQaDockerUp( |
| 90 | +{ |
| 91 | + repoRoot, |
| 92 | + outputDir, |
| 93 | +usePrebuiltImage: true, |
| 94 | +skipUiBuild: true, |
| 95 | +}, |
| 96 | +createHealthyDockerDeps(calls), |
| 97 | +); |
| 98 | + |
| 99 | +expect(result.stopCommand).toBe(`docker compose -f ${quoteForShell(composeFile)} down`); |
| 100 | +expect(calls).toContain( |
| 101 | +`docker compose -f ${composeFile} down --remove-orphans @${repoRoot}`, |
| 102 | +); |
| 103 | +} finally { |
| 104 | +await rm(tempRoot, { recursive: true, force: true }); |
| 105 | +} |
| 106 | +}); |
| 107 | + |
77 | 108 | it("skips UI build and compose --build for prebuilt images", async () => { |
78 | 109 | const calls: string[] = []; |
79 | 110 | const outputDir = await mkdtemp(path.join(os.tmpdir(), "qa-docker-up-")); |
|