node/test/parallel/test-fs-promises-file-handle-readFile.js
Tobias Nießen 609d2b0ff2
test: add and use tmpdir.hasEnoughSpace()
In general, we assume that the tmpdir will provide sufficient space for
most tests. Some tests, however, require hundreds of megabytes or even
gigabytes of space, which often causes them to fail, especially on our
macOS infrastructure. The most recent reliability report contains more
than 20 related CI failures.

This change adds a new function hasEnoughSpace() to the tmpdir module
that uses statfsSync() to guess whether allocating a certain amount of
space within the temporary directory will succeed.

This change also updates the most frequently failing tests to use the
new function such that the relevant parts of the tests are skipped if
tmpdir has insufficient space.

Refs: https://github.com/nodejs/reliability/issues/549
PR-URL: https://github.com/nodejs/node/pull/47767
Reviewed-By: James M Snell <jasnell@gmail.com>
Reviewed-By: Colin Ihrig <cjihrig@gmail.com>
Reviewed-By: Yagiz Nizipli <yagiz@nizipli.com>
Reviewed-By: Moshe Atlow <moshe@atlow.co.il>
Reviewed-By: Richard Lau <rlau@redhat.com>
2023-05-01 15:23:49 +00:00

132 lines
4.0 KiB
JavaScript

'use strict';
const common = require('../common');
// The following tests validate base functionality for the fs.promises
// FileHandle.readFile method.
const fs = require('fs');
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;
tmpdir.refresh();
async function validateReadFile() {
const filePath = path.resolve(tmpDir, 'tmp-read-file.txt');
const fileHandle = await open(filePath, 'w+');
const buffer = Buffer.from('Hello world'.repeat(100), 'utf8');
const fd = fs.openSync(filePath, 'w+');
fs.writeSync(fd, buffer, 0, buffer.length);
fs.closeSync(fd);
const readFileData = await fileHandle.readFile();
assert.deepStrictEqual(buffer, readFileData);
await fileHandle.close();
}
async function validateReadFileProc() {
// Test to make sure reading a file under the /proc directory works. Adapted
// from test-fs-read-file-sync-hostname.js.
// Refs:
// - https://groups.google.com/forum/#!topic/nodejs-dev/rxZ_RoH1Gn0
// - https://github.com/nodejs/node/issues/21331
// Test is Linux-specific.
if (!common.isLinux)
return;
const fileHandle = await open('/proc/sys/kernel/hostname', 'r');
const hostname = await fileHandle.readFile();
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+');
try {
const buffer = Buffer.from('Dogs running'.repeat(10000), 'utf8');
fs.writeFileSync(filePathForHandle, buffer);
const signal = AbortSignal.abort();
await assert.rejects(readFile(fileHandle, common.mustNotMutateObjectDeep({ signal })), {
name: 'AbortError'
});
} finally {
await fileHandle.close();
}
}
// 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;
process.nextTick(() => controller.abort());
await assert.rejects(readFile(fileHandle, common.mustNotMutateObjectDeep({ signal })), {
name: 'AbortError'
}, 'tick-0');
await fileHandle.close();
}
// 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(1, () => controller.abort());
await assert.rejects(fileHandle.readFile(common.mustNotMutateObjectDeep({ signal, encoding: 'utf8' })), {
name: 'AbortError'
}, 'tick-1');
await fileHandle.close();
}
// Validate file size is within range for reading
{
// Variable taken from https://github.com/nodejs/node/blob/1377163f3351/lib/internal/fs/promises.js#L5
const kIoMaxLength = 2 ** 31 - 1;
if (!tmpdir.hasEnoughSpace(kIoMaxLength)) {
// truncate() will fail with ENOSPC if there is not enough space.
common.printSkipMessage(`Not enough space in ${tmpDir}`);
} else {
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'
});
await fileHandle.close();
}
}
}
validateReadFile()
.then(validateReadFileProc)
.then(doReadAndCancel)
.then(common.mustCall());