mirror of
https://github.com/zebrajr/node.git
synced 2026-01-15 12:15:26 +00:00
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>
82 lines
2.2 KiB
JavaScript
82 lines
2.2 KiB
JavaScript
'use strict';
|
|
|
|
const { spawnSync } = require('child_process');
|
|
const fs = require('fs');
|
|
const path = require('path');
|
|
const { isMainThread } = require('worker_threads');
|
|
|
|
function rmSync(pathname, useSpawn) {
|
|
if (useSpawn) {
|
|
const escapedPath = pathname.replaceAll('\\', '\\\\');
|
|
spawnSync(
|
|
process.execPath,
|
|
[
|
|
'-e',
|
|
`require("fs").rmSync("${escapedPath}", { maxRetries: 3, recursive: true, force: true });`,
|
|
],
|
|
);
|
|
} else {
|
|
fs.rmSync(pathname, { maxRetries: 3, recursive: true, force: true });
|
|
}
|
|
}
|
|
|
|
const testRoot = process.env.NODE_TEST_DIR ?
|
|
fs.realpathSync(process.env.NODE_TEST_DIR) : path.resolve(__dirname, '..');
|
|
|
|
// Using a `.` prefixed name, which is the convention for "hidden" on POSIX,
|
|
// gets tools to ignore it by default or by simple rules, especially eslint.
|
|
const tmpdirName = '.tmp.' +
|
|
(process.env.TEST_SERIAL_ID || process.env.TEST_THREAD_ID || '0');
|
|
const tmpPath = path.join(testRoot, tmpdirName);
|
|
|
|
let firstRefresh = true;
|
|
function refresh(useSpawn = false) {
|
|
rmSync(tmpPath, useSpawn);
|
|
fs.mkdirSync(tmpPath);
|
|
|
|
if (firstRefresh) {
|
|
firstRefresh = false;
|
|
// Clean only when a test uses refresh. This allows for child processes to
|
|
// use the tmpdir and only the parent will clean on exit.
|
|
process.on('exit', () => {
|
|
return onexit(useSpawn);
|
|
});
|
|
}
|
|
}
|
|
|
|
function onexit(useSpawn) {
|
|
// Change directory to avoid possible EBUSY
|
|
if (isMainThread)
|
|
process.chdir(testRoot);
|
|
|
|
try {
|
|
rmSync(tmpPath, useSpawn);
|
|
} catch (e) {
|
|
console.error('Can\'t clean tmpdir:', tmpPath);
|
|
|
|
const files = fs.readdirSync(tmpPath);
|
|
console.error('Files blocking:', files);
|
|
|
|
if (files.some((f) => f.startsWith('.nfs'))) {
|
|
// Warn about NFS "silly rename"
|
|
console.error('Note: ".nfs*" might be files that were open and ' +
|
|
'unlinked but not closed.');
|
|
console.error('See http://nfs.sourceforge.net/#faq_d2 for details.');
|
|
}
|
|
|
|
console.error();
|
|
throw e;
|
|
}
|
|
}
|
|
|
|
function hasEnoughSpace(size) {
|
|
const { bavail, bsize } = fs.statfsSync(tmpPath);
|
|
return bavail >= Math.ceil(size / bsize);
|
|
}
|
|
|
|
module.exports = {
|
|
path: tmpPath,
|
|
refresh,
|
|
hasEnoughSpace,
|
|
};
|