tschaub / mock-fs

Configurable mock for the fs module
https://npmjs.org/package/mock-fs
Other
906 stars 86 forks source link

Strange behaviour with fs-extra, archiver and mock-fs combination #349

Open patrickdawson opened 2 years ago

patrickdawson commented 2 years ago

Hey there,

I have a strange problem with fs-extra, archiver and mock-fs in combination. I am running on node 16.13.2 but it seems to be broken on all nodejs 16 and 17 versions.

Here is the code example

const fs = require("fs-extra");
const { promisify } = require("util");
const { pipeline } = require("stream/promises");
const { setImmediate } = require("timers/promises");
const pEvent = require("p-event");
const archiver = require("archiver");
const StreamZip = require("node-stream-zip");
const mockfs = require("mock-fs");

async function unzip(filePath, targetDir) {
    const zip = new StreamZip({
        file: filePath,
        storeEntries: true,
    });
    const extract = promisify(zip.extract).bind(zip);

    await pEvent(zip, "ready");
    const count = await extract(null, targetDir);
    zip.close();
    return count;
}

async function main() {
    mockfs({
        "someFile.txt": "Content 1",
    });

    await setImmediate(); // without setImmediate no problem

    fileReadStream = fs.createReadStream("someFile.txt", { encoding: "utf-8" });
    const output = fs.createWriteStream("foo.zip");

    const archive = archiver("zip", {
        zlib: { level: 0 },
    });
    const pipelinePromise = pipeline(archive, output);
    const entryEvent = pEvent(archive, "entry");
    archive.append(fileReadStream, { name: "someFile.txt" });

    await entryEvent;
    await archive.finalize();
    await pipelinePromise;

    await unzip("foo.zip", ".");
};

main().catch(e => console.log(e));

With this code sample I get the following error: Invalid local header.

The error does NOT occur:

Does anyone know what is going on here?

package.json

{
  "name": "archiver-and-mockfs",
  "version": "1.0.0",
  "description": "",
  "main": "index.js",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1"
  },
  "keywords": [],
  "author": "",
  "license": "ISC",
  "dependencies": {
    "archiver": "5.3.0",
    "fs-extra": "10.0.0",
    "lodash": "4.17.21",
    "mock-fs": "5.1.2",
    "node-stream-zip": "1.15.0",
    "p-event": "4.2.0",
    "p-map": "4.0.0"
  }
}
3cp commented 2 years ago

If nodejs v14 has no issue, it's related to the readstream timing breaking change in nodejs v16. We don't fully understand some side effect. I am particularly puzzled by the effect of await setImmediate();.

338