From b070ee8df0b2e5cb842ab1512c1a8c1f63ee9107 Mon Sep 17 00:00:00 2001 From: Nitzan Uziely Date: Mon, 19 Apr 2021 01:07:06 +0300 Subject: [PATCH] fixup! fixup! fs: aggregate errors in fsPromises to avoid error swallowing --- ...s-promises-file-handle-aggregate-errors.js | 72 +++++++++++++++++++ 1 file changed, 72 insertions(+) create mode 100644 test/parallel/test-fs-promises-file-handle-aggregate-errors.js diff --git a/test/parallel/test-fs-promises-file-handle-aggregate-errors.js b/test/parallel/test-fs-promises-file-handle-aggregate-errors.js new file mode 100644 index 00000000000000..35c405cc3a90e8 --- /dev/null +++ b/test/parallel/test-fs-promises-file-handle-aggregate-errors.js @@ -0,0 +1,72 @@ +'use strict'; +// Flags: --expose-internals + +const common = require('../common'); +const tmpdir = require('../common/tmpdir'); + +// The following tests validate aggregate errors are thrown correctly +// when both an operation and close throw. + +const fs = require('fs'); +const path = require('path'); +const { + readFile, + writeFile, + truncate, + lchmod, +} = fs.promises; +const { + FileHandle, +} = require('internal/fs/promises'); + +const assert = require('assert'); +const originalFd = Object.getOwnPropertyDescriptor(FileHandle.prototype, 'fd'); + +let count = 0; +async function createFile() { + const filePath = path.join(tmpdir.path, `aggregate_errors_${++count}.txt`); + await writeFile(filePath, 'content'); + return filePath; +} + +async function checkAggregateError(op) { + try { + const filePath = await createFile(); + Object.defineProperty(FileHandle.prototype, 'fd', { + get: function() { + // Close is set by using a setter, + // so it needs to be set on the instance. + const originalClose = this.close; + this.close = async () => { + // close the file + await originalClose.call(this); + const closeError = new Error('CLOSE_ERROR'); + closeError.code = 456; + throw closeError; + }; + const opError = new Error('INTERNAL_ERROR'); + opError.code = 123; + throw opError; + } + }); + + await op(filePath).catch(common.mustCall((err) => { + assert.strictEqual(err.constructor.name, 'AggregateError'); + assert.strictEqual(err.code, 123); + assert.strictEqual(err.errors.length, 2); + assert.strictEqual(err.errors[0].message, 'INTERNAL_ERROR'); + assert.strictEqual(err.errors[1].message, 'CLOSE_ERROR'); + })); + } finally { + Object.defineProperty(FileHandle.prototype, 'fd', originalFd); + } +} +(async function() { + tmpdir.refresh(); + await checkAggregateError((filePath) => truncate(filePath)); + await checkAggregateError((filePath) => readFile(filePath)); + await checkAggregateError((filePath) => writeFile(filePath, '123')); + if (common.isOSX) { + await checkAggregateError((filePath) => lchmod(filePath, 0o777)); + } +})().then(common.mustCall());