|
1 | 1 | import { it as _it, beforeAll, describe, expect, test } from "vitest"; |
2 | 2 | import { type DenoHTTPWorker, newDenoHTTPWorker } from "./index.js"; |
3 | 3 | import fs from "node:fs"; |
4 | | -import path from "node:path"; |
| 4 | +import os from "node:os"; |
| 5 | +import fsp from "node:fs/promises"; |
| 6 | +import path, { join } from "node:path"; |
5 | 7 | import { Worker } from "node:worker_threads"; |
6 | 8 | import { EarlyExitDenoHTTPWorkerError } from "./DenoHTTPWorker.js"; |
7 | 9 |
|
@@ -72,6 +74,68 @@ describe("DenoHTTPWorker", { timeout: 1000 }, () => { |
72 | 74 | await worker.terminate(); |
73 | 75 | }); |
74 | 76 |
|
| 77 | + it("crash on a corrupted lockfile", async () => { |
| 78 | + const tmpDir = await fsp.mkdtemp(join(os.tmpdir(), "vt-")); |
| 79 | + const lockfile = join(tmpDir, "deno.lock"); |
| 80 | + fs.writeFileSync(lockfile, "{"); |
| 81 | + await expect( |
| 82 | + newDenoHTTPWorker( |
| 83 | + ` |
| 84 | + export default { async fetch (req: Request): Promise<Response> { |
| 85 | + await Deno.removeSync(Deno.args[0]); |
| 86 | + return Response.json({ ok: req.url }) |
| 87 | + } } |
| 88 | + `, |
| 89 | + { printOutput: false, runFlags: [`--lock=${lockfile}`] } |
| 90 | + ) |
| 91 | + ).rejects.toMatchObject({ |
| 92 | + message: "Deno exited before being ready", |
| 93 | + stdout: undefined, |
| 94 | + stderr: expect.stringContaining("Lockfile may be corrupt"), |
| 95 | + }); |
| 96 | + }); |
| 97 | + |
| 98 | + // This test uses the network so it is disabled by default, but use |
| 99 | + // it for debugging lockfile errors |
| 100 | + it.skip("crash on an invalid lockfile", async () => { |
| 101 | + const tmpDir = await fsp.mkdtemp(join(os.tmpdir(), "vt-")); |
| 102 | + const lockfile = join(tmpDir, "deno.lock"); |
| 103 | + fs.writeFileSync(join(tmpDir, "deno.json"), "{}"); |
| 104 | + fs.writeFileSync( |
| 105 | + lockfile, |
| 106 | + JSON.stringify({ |
| 107 | + version: "5", |
| 108 | + specifiers: { |
| 109 | + "npm:is-number@*": "7.0.0", |
| 110 | + "npm:is-number@7.0.0": "7.0.0", |
| 111 | + }, |
| 112 | + npm: { |
| 113 | + "is-number@7.0.0": { |
| 114 | + integrity: |
| 115 | + "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0104MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", |
| 116 | + }, |
| 117 | + }, |
| 118 | + }) |
| 119 | + ); |
| 120 | + |
| 121 | + await expect( |
| 122 | + newDenoHTTPWorker( |
| 123 | + ` |
| 124 | + import isN from "npm:is-number@7.0.0"; |
| 125 | + export default { async fetch (req: Request): Promise<Response> { |
| 126 | + await Deno.removeSync(Deno.args[0]); |
| 127 | + return Response.json({ ok: isN('hi') }) |
| 128 | + } } |
| 129 | + `, |
| 130 | + { printOutput: false, runFlags: ["--reload", `--lock=${lockfile}`] } |
| 131 | + ) |
| 132 | + ).rejects.toMatchObject({ |
| 133 | + message: "Deno exited before being ready", |
| 134 | + stdout: undefined, |
| 135 | + stderr: expect.stringContaining("Tarball checksum"), |
| 136 | + }); |
| 137 | + }); |
| 138 | + |
75 | 139 | it("don't crash on socket removal", async () => { |
76 | 140 | const worker = await newDenoHTTPWorker( |
77 | 141 | ` |
@@ -187,9 +251,38 @@ describe("DenoHTTPWorker", { timeout: 1000 }, () => { |
187 | 251 | worker.addEventListener("exit", (code) => res(code)); |
188 | 252 | }); |
189 | 253 |
|
190 | | - jsonRequest(worker, "https://localhost/hello?isee=you", { |
191 | | - headers: { accept: "application/json" }, |
192 | | - }).catch(() => {}); |
| 254 | + await expect( |
| 255 | + jsonRequest(worker, "https://localhost/hello?isee=you", { |
| 256 | + headers: { accept: "application/json" }, |
| 257 | + }) |
| 258 | + ).resolves.toEqual(null); |
| 259 | + |
| 260 | + expect(await codePromise).toEqual(1); |
| 261 | + await worker.terminate(); |
| 262 | + }); |
| 263 | + |
| 264 | + it("intentional deno exits cause a socket error", async () => { |
| 265 | + const worker = await newDenoHTTPWorker( |
| 266 | + ` |
| 267 | + export default { async fetch (req: Request): Promise<Response> { |
| 268 | + Deno.exit(1); |
| 269 | + }} |
| 270 | + `, |
| 271 | + { printOutput: false } |
| 272 | + ); |
| 273 | + const codePromise = new Promise((res) => { |
| 274 | + worker.addEventListener("exit", (code) => { |
| 275 | + res(code); |
| 276 | + }); |
| 277 | + }); |
| 278 | + |
| 279 | + await expect( |
| 280 | + jsonRequest(worker, "https://localhost/hello?isee=you", { |
| 281 | + headers: { accept: "application/json" }, |
| 282 | + }) |
| 283 | + ).rejects.toMatchObject({ |
| 284 | + message: "other side closed", |
| 285 | + }); |
193 | 286 |
|
194 | 287 | expect(await codePromise).toEqual(1); |
195 | 288 | await worker.terminate(); |
|
0 commit comments