Skip to content

Commit 11a2d1c

Browse files
tniessenMoLow
authored andcommitted
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: nodejs/reliability#549 PR-URL: nodejs#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>
1 parent 72443bc commit 11a2d1c

5 files changed

+52
-22
lines changed

test/common/README.md

+9
Original file line numberDiff line numberDiff line change
@@ -1027,6 +1027,15 @@ Avoid calling it more than once in an asynchronous context as one call
10271027
might refresh the temporary directory of a different context, causing
10281028
the test to fail somewhat mysteriously.
10291029

1030+
### `hasEnoughSpace(size)`
1031+
1032+
* `size` [\<number>][<number>] Required size, in bytes.
1033+
1034+
Returns `true` if the available blocks of the file system underlying `path`
1035+
are likely sufficient to hold a single file of `size` bytes. This is useful for
1036+
skipping tests that require hundreds of megabytes or even gigabytes of temporary
1037+
files, but it is inaccurate and susceptible to race conditions.
1038+
10301039
## UDP pair helper
10311040

10321041
The `common/udppair` module exports a function `makeUDPPair` and a class

test/common/tmpdir.js

+6
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,13 @@ function onexit() {
5555
}
5656
}
5757

58+
function hasEnoughSpace(size) {
59+
const { bavail, bsize } = fs.statfsSync(tmpPath);
60+
return bavail >= Math.ceil(size / bsize);
61+
}
62+
5863
module.exports = {
5964
path: tmpPath,
6065
refresh,
66+
hasEnoughSpace,
6167
};

test/parallel/test-fs-promises-file-handle-readFile.js

+16-11
Original file line numberDiff line numberDiff line change
@@ -106,17 +106,22 @@ async function doReadAndCancel() {
106106
// Variable taken from https://github.com/nodejs/node/blob/1377163f3351/lib/internal/fs/promises.js#L5
107107
const kIoMaxLength = 2 ** 31 - 1;
108108

109-
const newFile = path.resolve(tmpDir, 'dogs-running3.txt');
110-
await writeFile(newFile, Buffer.from('0'));
111-
await truncate(newFile, kIoMaxLength + 1);
112-
113-
const fileHandle = await open(newFile, 'r');
114-
115-
await assert.rejects(fileHandle.readFile(), {
116-
name: 'RangeError',
117-
code: 'ERR_FS_FILE_TOO_LARGE'
118-
});
119-
await fileHandle.close();
109+
if (!tmpdir.hasEnoughSpace(kIoMaxLength)) {
110+
// truncate() will fail with ENOSPC if there is not enough space.
111+
common.printSkipMessage(`Not enough space in ${tmpDir}`);
112+
} else {
113+
const newFile = path.resolve(tmpDir, 'dogs-running3.txt');
114+
await writeFile(newFile, Buffer.from('0'));
115+
await truncate(newFile, kIoMaxLength + 1);
116+
117+
const fileHandle = await open(newFile, 'r');
118+
119+
await assert.rejects(fileHandle.readFile(), {
120+
name: 'RangeError',
121+
code: 'ERR_FS_FILE_TOO_LARGE'
122+
});
123+
await fileHandle.close();
124+
}
120125
}
121126
}
122127

test/parallel/test-fs-readfile.js

+17-11
Original file line numberDiff line numberDiff line change
@@ -52,21 +52,27 @@ for (const e of fileInfo) {
5252
assert.deepStrictEqual(buf, e.contents);
5353
}));
5454
}
55-
// Test readFile size too large
55+
56+
// readFile() and readFileSync() should fail if the file is too big.
5657
{
5758
const kIoMaxLength = 2 ** 31 - 1;
5859

59-
const file = path.join(tmpdir.path, `${prefix}-too-large.txt`);
60-
fs.writeFileSync(file, Buffer.from('0'));
61-
fs.truncateSync(file, kIoMaxLength + 1);
60+
if (!tmpdir.hasEnoughSpace(kIoMaxLength)) {
61+
// truncateSync() will fail with ENOSPC if there is not enough space.
62+
common.printSkipMessage(`Not enough space in ${tmpdir.path}`);
63+
} else {
64+
const file = path.join(tmpdir.path, `${prefix}-too-large.txt`);
65+
fs.writeFileSync(file, Buffer.from('0'));
66+
fs.truncateSync(file, kIoMaxLength + 1);
6267

63-
fs.readFile(file, common.expectsError({
64-
code: 'ERR_FS_FILE_TOO_LARGE',
65-
name: 'RangeError',
66-
}));
67-
assert.throws(() => {
68-
fs.readFileSync(file);
69-
}, { code: 'ERR_FS_FILE_TOO_LARGE', name: 'RangeError' });
68+
fs.readFile(file, common.expectsError({
69+
code: 'ERR_FS_FILE_TOO_LARGE',
70+
name: 'RangeError',
71+
}));
72+
assert.throws(() => {
73+
fs.readFileSync(file);
74+
}, { code: 'ERR_FS_FILE_TOO_LARGE', name: 'RangeError' });
75+
}
7076
}
7177

7278
{

test/pummel/test-fs-readfile-tostring-fail.js

+4
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,10 @@ if (common.isAIX && (Number(cp.execSync('ulimit -f')) * 512) < kStringMaxLength)
1616
const tmpdir = require('../common/tmpdir');
1717
tmpdir.refresh();
1818

19+
if (!tmpdir.hasEnoughSpace(kStringMaxLength)) {
20+
common.skip(`Not enough space in ${tmpdir.path}`);
21+
}
22+
1923
const file = path.join(tmpdir.path, 'toobig.txt');
2024
const stream = fs.createWriteStream(file, {
2125
flags: 'a',

0 commit comments

Comments
 (0)