Skip to content

Commit d444ceb

Browse files
committed
test: add and use tmpdir.hasTooLittleSpace()
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 hasTooLittleSpace() to the tmpdir module that uses statfsSync() to guess whether allocating a certain amount of space within the temporary directory will fail. This change also updates the most frequently failing tests to use the new function, in which case the relevant parts of the tests are skipped. Refs: nodejs/reliability#549
1 parent a75959b commit d444ceb

5 files changed

+52
-22
lines changed

test/common/README.md

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

1033+
### `hasTooLittleSpace(size)`
1034+
1035+
* `size` [\<number>][<number>] Required size, in bytes.
1036+
1037+
Returns `true` if the available blocks of the file system underlying `path`
1038+
might be insufficient to hold a single file of `size` bytes. This is useful for
1039+
skipping tests that require hundreds of megabytes or even gigabytes of temporary
1040+
files, but it is susceptible to race conditions.
1041+
10331042
## UDP pair helper
10341043

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

test/common/tmpdir.js

+6
Original file line numberDiff line numberDiff line change
@@ -69,7 +69,13 @@ function onexit(useSpawn) {
6969
}
7070
}
7171

72+
function hasTooLittleSpace(size) {
73+
const { bavail, bsize } = fs.statfsSync(tmpPath);
74+
return bavail < Math.ceil(size / bsize);
75+
}
76+
7277
module.exports = {
7378
path: tmpPath,
7479
refresh,
80+
hasTooLittleSpace,
7581
};

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.hasTooLittleSpace(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.hasTooLittleSpace(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.hasTooLittleSpace(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)