mirror of
https://github.com/tdurieux/anonymous_github.git
synced 2026-11-14 08:17:26 +01:00
97 lines
4.6 KiB
JavaScript
97 lines
4.6 KiB
JavaScript
const { expect } = require("chai");
|
|
const { setImmediate, setTimeout } = require("timers");
|
|
const { once } = require("events");
|
|
const { Writable } = require("stream");
|
|
const archiver = require("archiver");
|
|
const fs = require("fs");
|
|
const os = require("os");
|
|
const { execFileSync } = require("child_process");
|
|
require("ts-node/register/transpile-only");
|
|
const { boundedZip } = require("../src/core/bounded-zip");
|
|
|
|
async function bytes(archive, entries) {
|
|
const chunks = [];
|
|
archive.on("data", chunk => chunks.push(chunk));
|
|
const end = once(archive, "end");
|
|
for (const entry of entries) archive.append(entry.body, { date: new Date("2020-01-01T00:00:00Z"), ...entry.options });
|
|
await archive.finalize(); await end;
|
|
return Buffer.concat(chunks);
|
|
}
|
|
|
|
describe("bounded ZIP central directory", function () {
|
|
this.timeout(20000);
|
|
it("preserves archive bytes, compression, Unicode names, modes, and empty files", async () => {
|
|
const entries = [
|
|
{ body: "private text\n".repeat(100), options: { name: "folder/é中.txt", mode: 0o100755 } },
|
|
{ body: Buffer.from([0, 1, 255]), options: { name: "binary.dat", store: true } },
|
|
{ body: "", options: { name: "empty.txt" } },
|
|
];
|
|
expect(await bytes(boundedZip(), entries)).to.deep.equal(await bytes(archiver("zip"), entries));
|
|
expect(await bytes(boundedZip(), [])).to.deep.equal(await bytes(archiver("zip"), []));
|
|
});
|
|
|
|
it("preserves ZIP64 size and offset encoding beyond 4 GiB", async () => {
|
|
const Entry = require("compress-commons/lib/archivers/zip/zip-archive-entry");
|
|
async function directory(archive) {
|
|
const entry = new Entry("large.bin");
|
|
entry.setMethod(0); entry.setTime(new Date("2020-01-01"));
|
|
entry.setSize(2 ** 32 + 123); entry.setCompressedSize(2 ** 32 + 123);
|
|
entry._offsets = { file: 2 ** 32 + 456 };
|
|
archive._module.engine._entries.push(entry);
|
|
archive._module.engine.offset = 2 ** 33;
|
|
return bytes(archive, []);
|
|
}
|
|
expect(await directory(boundedZip())).to.deep.equal(await directory(archiver("zip")));
|
|
});
|
|
|
|
it("preserves ZIP64 counts and drains 180,636 records under a 128 MiB heap", function () {
|
|
this.timeout(60000);
|
|
const output = execFileSync(process.execPath, ["--max-old-space-size=128", "test/fixtures/zip-directory-memory.js"],
|
|
{ cwd: process.cwd(), timeout: 55000, encoding: "utf8" });
|
|
const result = JSON.parse(output.trim().split("\n").pop());
|
|
expect(result.entries).to.equal(180636);
|
|
expect(result.zip64Count).to.equal(180636);
|
|
expect(result.centralRecords).to.equal(180636);
|
|
expect(result.heapMiB).to.be.lessThan(128);
|
|
});
|
|
|
|
it("reports spool write failures through the stream error handler", () => {
|
|
const archive = boundedZip();
|
|
let failure;
|
|
archive.on("error", error => { failure = error; });
|
|
const Entry = require("compress-commons/lib/archivers/zip/zip-archive-entry");
|
|
const entry = new Entry("file.txt"); entry.setMethod(0); entry.setTime(new Date()); entry._offsets = { file: 0 };
|
|
const write = fs.writeSync;
|
|
try {
|
|
fs.writeSync = () => { throw Object.assign(new Error("disk full"), { code: "ENOSPC" }); };
|
|
expect(() => archive._module.engine._entries.push(entry)).not.to.throw();
|
|
expect(failure?.code).to.equal("ENOSPC");
|
|
} finally { fs.writeSync = write; archive.abort(); }
|
|
});
|
|
|
|
it("removes its spool when aborted while waiting for a slow consumer", async () => {
|
|
const existing = new Set(fs.readdirSync(os.tmpdir()));
|
|
const archive = boundedZip();
|
|
archive.on("error", () => {});
|
|
const sink = new Writable({ highWaterMark: 1, write(_chunk, _encoding, _callback) {} });
|
|
archive.pipe(sink);
|
|
archive.append("small file", { name: "test.txt" });
|
|
await once(archive, "entry");
|
|
const created = fs.readdirSync(os.tmpdir()).filter(n => n.startsWith("anonymous-zip-directory-") && !existing.has(n));
|
|
expect(created).to.have.length(1);
|
|
const engine = archive._module.engine;
|
|
const Entry = require("compress-commons/lib/archivers/zip/zip-archive-entry");
|
|
for (let i = 0; i < 50000; i++) {
|
|
const entry = new Entry(`${"directory/".repeat(32)}file-${i}.txt`); entry.setMethod(0); entry.setTime(new Date()); entry._offsets = { file: 0 };
|
|
engine._entries.push(entry);
|
|
}
|
|
try {
|
|
void archive.finalize().catch(() => {});
|
|
await new Promise(resolve => setTimeout(resolve, 50));
|
|
expect(engine._archive.finished).to.equal(false);
|
|
} finally { archive.abort(); sink.destroy(); }
|
|
await new Promise(resolve => setImmediate(resolve));
|
|
expect(fs.existsSync(`${os.tmpdir()}/${created[0]}`)).to.equal(false);
|
|
});
|
|
});
|