From 5452d0e8544f7650bf092e1ef7d4b8f949efc15a Mon Sep 17 00:00:00 2001 From: Emil Sivervik Date: Wed, 6 Jan 2021 13:59:12 +0100 Subject: [PATCH] test: increase fs promise coverage 1. Signal aborted while writing file Refs: https://coverage.nodejs.org/coverage-0b6d3070a176d437/lib/internal/fs/promises.js.html#L278 2. Signal aborted on first tick Refs: https://coverage.nodejs.org/coverage-0b6d3070a176d437/lib/internal/fs/promises.js.html#L301 3. Validate file size is withing range for reading Refs: https://coverage.nodejs.org/coverage-0b6d3070a176d437/lib/internal/fs/promises.js.html#L312 4. Signal aborted right before buffer read Refs: https://coverage.nodejs.org/coverage-0b6d3070a176d437/lib/internal/fs/promises.js.html#L321 5. Use fallback buffer allocation when input not buffer Refs: https://coverage.nodejs.org/coverage-0b6d3070a176d437/lib/internal/fs/promises.js.html#L374 6. Specify symlink type Refs: https://coverage.nodejs.org/coverage-0b6d3070a176d437/lib/internal/fs/promises.js.html#L539 7. Set modification times with lutimes Refs: https://coverage.nodejs.org/coverage-0b6d3070a176d437/lib/internal/fs/promises.js.html#L635 8. Use fallback encoding when input is null Refs: https://coverage.nodejs.org/coverage-0b6d3070a176d437/lib/internal/fs/promises.js.html#L665 9. Use fallback flag when input is null Refs: https://coverage.nodejs.org/coverage-0b6d3070a176d437/lib/internal/fs/promises.js.html#L681 PR-URL: https://github.com/nodejs/node/pull/36813 Reviewed-By: Antoine du Hamel Reviewed-By: Darshan Sen Reviewed-By: James M Snell --- .../test-fs-promises-file-handle-readFile.js | 75 ++++++++++++++++++- .../test-fs-promises-file-handle-writeFile.js | 19 ++++- test/parallel/test-fs-promises-writefile.js | 2 +- test/parallel/test-fs-promises.js | 38 ++++++++++ 4 files changed, 129 insertions(+), 5 deletions(-) diff --git a/test/parallel/test-fs-promises-file-handle-readFile.js b/test/parallel/test-fs-promises-file-handle-readFile.js index 4416744bf5189a..367391244eace9 100644 --- a/test/parallel/test-fs-promises-file-handle-readFile.js +++ b/test/parallel/test-fs-promises-file-handle-readFile.js @@ -1,3 +1,4 @@ +// Flags: --experimental-abortcontroller 'use strict'; const common = require('../common'); @@ -6,9 +7,15 @@ const common = require('../common'); // FileHandle.readFile method. const fs = require('fs'); -const { open } = fs.promises; +const { + open, + readFile, + writeFile, + truncate +} = fs.promises; const path = require('path'); const tmpdir = require('../common/tmpdir'); +const tick = require('../common/tick'); const assert = require('assert'); const tmpDir = tmpdir.path; @@ -45,6 +52,70 @@ async function validateReadFileProc() { assert.ok(hostname.length > 0); } +async function doReadAndCancel() { + // Signal aborted from the start + { + const filePathForHandle = path.resolve(tmpDir, 'dogs-running.txt'); + const fileHandle = await open(filePathForHandle, 'w+'); + const buffer = Buffer.from('Dogs running'.repeat(10000), 'utf8'); + fs.writeFileSync(filePathForHandle, buffer); + const controller = new AbortController(); + const { signal } = controller; + controller.abort(); + await assert.rejects(readFile(fileHandle, { signal }), { + name: 'AbortError' + }); + } + + // Signal aborted on first tick + { + const filePathForHandle = path.resolve(tmpDir, 'dogs-running1.txt'); + const fileHandle = await open(filePathForHandle, 'w+'); + const buffer = Buffer.from('Dogs running'.repeat(10000), 'utf8'); + fs.writeFileSync(filePathForHandle, buffer); + const controller = new AbortController(); + const { signal } = controller; + tick(1, () => controller.abort()); + await assert.rejects(readFile(fileHandle, { signal }), { + name: 'AbortError' + }); + } + + // Signal aborted right before buffer read + { + const newFile = path.resolve(tmpDir, 'dogs-running2.txt'); + const buffer = Buffer.from('Dogs running'.repeat(1000), 'utf8'); + fs.writeFileSync(newFile, buffer); + + const fileHandle = await open(newFile, 'r'); + + const controller = new AbortController(); + const { signal } = controller; + tick(2, () => controller.abort()); + await assert.rejects(fileHandle.readFile({ signal, encoding: 'utf8' }), { + name: 'AbortError' + }); + } + + // Validate file size is within range for reading + { + // Variable taken from https://github.com/nodejs/node/blob/master/lib/internal/fs/promises.js#L5 + const kIoMaxLength = 2 ** 31 - 1; + + const newFile = path.resolve(tmpDir, 'dogs-running3.txt'); + await writeFile(newFile, Buffer.from('0')); + await truncate(newFile, kIoMaxLength + 1); + + const fileHandle = await open(newFile, 'r'); + + await assert.rejects(fileHandle.readFile(), { + name: 'RangeError', + code: 'ERR_FS_FILE_TOO_LARGE' + }); + } +} + validateReadFile() - .then(() => validateReadFileProc()) + .then(validateReadFileProc) + .then(doReadAndCancel) .then(common.mustCall()); diff --git a/test/parallel/test-fs-promises-file-handle-writeFile.js b/test/parallel/test-fs-promises-file-handle-writeFile.js index 25b767a0abcf62..a4ae7fd054b53d 100644 --- a/test/parallel/test-fs-promises-file-handle-writeFile.js +++ b/test/parallel/test-fs-promises-file-handle-writeFile.js @@ -1,12 +1,13 @@ +// Flags: --experimental-abortcontroller 'use strict'; const common = require('../common'); // The following tests validate base functionality for the fs.promises -// FileHandle.readFile method. +// FileHandle.writeFile method. const fs = require('fs'); -const { open } = fs.promises; +const { open, writeFile } = fs.promises; const path = require('path'); const tmpdir = require('../common/tmpdir'); const assert = require('assert'); @@ -26,5 +27,19 @@ async function validateWriteFile() { await fileHandle.close(); } +// Signal aborted while writing file +async function doWriteAndCancel() { + const filePathForHandle = path.resolve(tmpDir, 'dogs-running.txt'); + const fileHandle = await open(filePathForHandle, 'w+'); + const buffer = Buffer.from('dogs running'.repeat(10000), 'utf8'); + const controller = new AbortController(); + const { signal } = controller; + process.nextTick(() => controller.abort()); + await assert.rejects(writeFile(fileHandle, buffer, { signal }), { + name: 'AbortError' + }); +} + validateWriteFile() + .then(doWriteAndCancel) .then(common.mustCall()); diff --git a/test/parallel/test-fs-promises-writefile.js b/test/parallel/test-fs-promises-writefile.js index de58395774ba0d..f5f3e8dad38469 100644 --- a/test/parallel/test-fs-promises-writefile.js +++ b/test/parallel/test-fs-promises-writefile.js @@ -32,7 +32,7 @@ async function doWriteWithCancel() { } async function doAppend() { - await fsPromises.appendFile(dest, buffer2); + await fsPromises.appendFile(dest, buffer2, { flag: null }); const data = fs.readFileSync(dest); const buf = Buffer.concat([buffer, buffer2]); assert.deepStrictEqual(buf, data); diff --git a/test/parallel/test-fs-promises.js b/test/parallel/test-fs-promises.js index b6d4260a6484d0..bb9a3257e11fae 100644 --- a/test/parallel/test-fs-promises.js +++ b/test/parallel/test-fs-promises.js @@ -16,6 +16,7 @@ const { link, lchmod, lstat, + lutimes, mkdir, mkdtemp, open, @@ -140,6 +141,13 @@ async function getHandle(dest) { await handle.close(); } + // Use fallback buffer allocation when input not buffer + { + const handle = await getHandle(dest); + const ret = await handle.read(0, 0, 0, 0); + assert.strictEqual(ret.buffer.length, 16384); + } + // Bytes written to file match buffer { const handle = await getHandle(dest); @@ -226,6 +234,19 @@ async function getHandle(dest) { await handle.close(); } + // Set modification times with lutimes + { + const a_time = new Date(); + a_time.setMinutes(a_time.getMinutes() - 1); + const m_time = new Date(); + m_time.setHours(m_time.getHours() - 1); + await lutimes(dest, a_time, m_time); + const stats = await stat(dest); + + assert.strictEqual(a_time.toString(), stats.atime.toString()); + assert.strictEqual(m_time.toString(), stats.mtime.toString()); + } + // create symlink { const newPath = path.resolve(tmpDir, 'baz2.js'); @@ -270,6 +291,15 @@ async function getHandle(dest) { } } + // specify symlink type + { + const dir = path.join(tmpDir, nextdir()); + await symlink(tmpDir, dir, 'dir'); + const stats = await lstat(dir); + assert.strictEqual(stats.isSymbolicLink(), true); + await unlink(dir); + } + // create hard link { const newPath = path.resolve(tmpDir, 'baz2.js'); @@ -296,6 +326,14 @@ async function getHandle(dest) { await unlink(newFile); } + // Use fallback encoding when input is null + { + const newFile = path.resolve(tmpDir, 'dogs_running.js'); + await writeFile(newFile, 'dogs running', { encoding: null }); + const fileExists = fs.existsSync(newFile); + assert.strictEqual(fileExists, true); + } + // `mkdir` when options is number. { const dir = path.join(tmpDir, nextdir());