Skip to content

Commit

Permalink
test: clean tmpdir on process exit
Browse files Browse the repository at this point in the history
PR-URL: #28858
Reviewed-By: Rich Trott <[email protected]>
Reviewed-By: Colin Ihrig <[email protected]>
  • Loading branch information
joaocgreis authored and Trott committed Aug 11, 2019
1 parent 0376b5b commit 8ef68e6
Show file tree
Hide file tree
Showing 48 changed files with 212 additions and 66 deletions.
29 changes: 23 additions & 6 deletions test/addons/load-long-path/test.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,9 @@ if (common.isWindows && (process.env.PROCESSOR_ARCHITEW6432 !== undefined))
const fs = require('fs');
const path = require('path');
const assert = require('assert');
const { fork } = require('child_process');

const tmpdir = require('../../common/tmpdir');
tmpdir.refresh();

// Make a path that is more than 260 chars long.
// Any given folder cannot have a name longer than 260 characters,
Expand All @@ -17,7 +17,6 @@ let addonDestinationDir = path.resolve(tmpdir.path);

for (let i = 0; i < 10; i++) {
addonDestinationDir = path.join(addonDestinationDir, 'x'.repeat(30));
fs.mkdirSync(addonDestinationDir);
}

const addonPath = path.join(__dirname,
Expand All @@ -26,11 +25,29 @@ const addonPath = path.join(__dirname,
'binding.node');
const addonDestinationPath = path.join(addonDestinationDir, 'binding.node');

// Loading an addon keeps the file open until the process terminates. Load
// the addon in a child process so that when the parent terminates the file
// is already closed and the tmpdir can be cleaned up.

// Child
if (process.argv[2] === 'child') {
// Attempt to load at long path destination
const addon = require(addonDestinationPath);
assert.notStrictEqual(addon, null);
assert.strictEqual(addon.hello(), 'world');
return;
}

// Parent
tmpdir.refresh();

// Copy binary to long path destination
fs.mkdirSync(addonDestinationDir, { recursive: true });
const contents = fs.readFileSync(addonPath);
fs.writeFileSync(addonDestinationPath, contents);

// Attempt to load at long path destination
const addon = require(addonDestinationPath);
assert.notStrictEqual(addon, null);
assert.strictEqual(addon.hello(), 'world');
// Run test
const child = fork(__filename, ['child'], { stdio: 'inherit' });
child.on('exit', common.mustCall(function(code) {
assert.strictEqual(code, 0);
}));
7 changes: 7 additions & 0 deletions test/common/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -906,6 +906,13 @@ The realpath of the testing temporary directory.

Deletes and recreates the testing temporary directory.

The first time `refresh()` runs, it adds a listener to process `'exit'` that
cleans the temporary directory. Thus, every file under `tmpdir.path` needs to
be closed before the test completes. A good way to do this is to add a
listener to process `'beforeExit'`. If a file needs to be left open until
Node.js completes, use a child process and call `refresh()` only in the
parent.

## WPT Module

### harness
Expand Down
39 changes: 39 additions & 0 deletions test/common/tmpdir.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ const { execSync } = require('child_process');
const fs = require('fs');
const path = require('path');
const { debuglog } = require('util');
const { isMainThread } = require('worker_threads');

const debug = debuglog('test/tmpdir');

Expand Down Expand Up @@ -61,6 +62,9 @@ function rimrafSync(pathname, { spawn = true } = {}) {
}
rmdirSync(pathname, e);
}

if (fs.existsSync(pathname))
throw new Error(`Unable to rimraf ${pathname}`);
}

function rmdirSync(p, originalEr) {
Expand All @@ -80,7 +84,9 @@ function rmdirSync(p, originalEr) {
}
});
fs.rmdirSync(p);
return;
}
throw e;
}
}

Expand All @@ -93,9 +99,42 @@ 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(opts = {}) {
rimrafSync(this.path, opts);
fs.mkdirSync(this.path);

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', onexit);
}
}

function onexit() {
// Change directory to avoid possible EBUSY
if (isMainThread)
process.chdir(testRoot);

try {
rimrafSync(tmpPath, { spawn: false });
} 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;
}
}

module.exports = {
Expand Down
21 changes: 19 additions & 2 deletions test/parallel/test-child-process-server-close.js
Original file line number Diff line number Diff line change
@@ -1,12 +1,29 @@
'use strict';

const common = require('../common');
const { spawn } = require('child_process');
const assert = require('assert');
const { fork, spawn } = require('child_process');
const net = require('net');

const tmpdir = require('../common/tmpdir');
tmpdir.refresh();

// Run in a child process because the PIPE file descriptor stays open until
// Node.js completes, blocking the tmpdir and preventing cleanup.

if (process.argv[2] !== 'child') {
// Parent
tmpdir.refresh();

// Run test
const child = fork(__filename, ['child'], { stdio: 'inherit' });
child.on('exit', common.mustCall(function(code) {
assert.strictEqual(code, 0);
}));

return;
}

// Child
const server = net.createServer((conn) => {
spawn(process.execPath, ['-v'], {
stdio: ['ignore', conn, 'ignore']
Expand Down
10 changes: 0 additions & 10 deletions test/parallel/test-fs-append-file-sync.js
Original file line number Diff line number Diff line change
Expand Up @@ -99,13 +99,3 @@ const fileData5 = fs.readFileSync(filename5);

assert.strictEqual(Buffer.byteLength(data) + currentFileData.length,
fileData5.length);

// Exit logic for cleanup.

process.on('exit', function() {
fs.unlinkSync(filename);
fs.unlinkSync(filename2);
fs.unlinkSync(filename3);
fs.unlinkSync(filename4);
fs.unlinkSync(filename5);
});
1 change: 1 addition & 0 deletions test/parallel/test-fs-buffertype-writesync.js
Original file line number Diff line number Diff line change
Expand Up @@ -19,4 +19,5 @@ v.forEach((value) => {
const fd = fs.openSync(filePath, 'w');
fs.writeSync(fd, value);
assert.strictEqual(fs.readFileSync(filePath).toString(), String(value));
fs.closeSync(fd);
});
1 change: 1 addition & 0 deletions test/parallel/test-fs-fsync.js
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@ fs.open(fileTemp, 'a', 0o777, common.mustCall(function(err, fd) {
assert.ifError(err);
fs.fsync(fd, common.mustCall(function(err) {
assert.ifError(err);
fs.closeSync(fd);
}));
}));
}));
Expand Down
4 changes: 0 additions & 4 deletions test/parallel/test-fs-long-path.js
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,3 @@ fs.writeFile(fullPath, 'ok', common.mustCall(function(err) {
assert.ifError(err);
}));
}));

process.on('exit', function() {
fs.unlinkSync(fullPath);
});
5 changes: 4 additions & 1 deletion test/parallel/test-fs-open-flags.js
Original file line number Diff line number Diff line change
Expand Up @@ -94,5 +94,8 @@ if (common.isLinux || common.isOSX) {
tmpdir.refresh();
const file = path.join(tmpdir.path, 'a.js');
fs.copyFileSync(fixtures.path('a.js'), file);
fs.open(file, O_DSYNC, common.mustCall(assert.ifError));
fs.open(file, O_DSYNC, common.mustCall((err, fd) => {
assert.ifError(err);
fs.closeSync(fd);
}));
}
4 changes: 2 additions & 2 deletions test/parallel/test-fs-options-immutable.js
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,6 @@ if (common.canCreateSymLink()) {
{
const fileName = path.resolve(tmpdir.path, 'streams');
fs.WriteStream(fileName, options).once('open', common.mustCall(() => {
fs.ReadStream(fileName, options);
}));
fs.ReadStream(fileName, options).destroy();
})).end();
}
4 changes: 4 additions & 0 deletions test/parallel/test-fs-promises-file-handle-append-file.js
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,8 @@ async function validateAppendBuffer() {
await fileHandle.appendFile(buffer);
const appendedFileData = fs.readFileSync(filePath);
assert.deepStrictEqual(appendedFileData, buffer);

await fileHandle.close();
}

async function validateAppendString() {
Expand All @@ -33,6 +35,8 @@ async function validateAppendString() {
const stringAsBuffer = Buffer.from(string, 'utf8');
const appendedFileData = fs.readFileSync(filePath);
assert.deepStrictEqual(appendedFileData, stringAsBuffer);

await fileHandle.close();
}

validateAppendBuffer()
Expand Down
2 changes: 2 additions & 0 deletions test/parallel/test-fs-promises-file-handle-chmod.js
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,8 @@ async function validateFilePermission() {
await fileHandle.chmod(newPermissions);
const statsAfterMod = fs.statSync(filePath);
assert.deepStrictEqual(statsAfterMod.mode & expectedAccess, expectedAccess);

await fileHandle.close();
}

validateFilePermission().then(common.mustCall());
4 changes: 4 additions & 0 deletions test/parallel/test-fs-promises-file-handle-read.js
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,8 @@ async function validateRead() {
const readAsyncHandle = await fileHandle.read(Buffer.alloc(11), 0, 11, 0);
assert.deepStrictEqual(buffer.length, readAsyncHandle.bytesRead);
assert.deepStrictEqual(buffer, readAsyncHandle.buffer);

await fileHandle.close();
}

async function validateEmptyRead() {
Expand All @@ -38,6 +40,8 @@ async function validateEmptyRead() {
fs.closeSync(fd);
const readAsyncHandle = await fileHandle.read(Buffer.alloc(11), 0, 11, 0);
assert.deepStrictEqual(buffer.length, readAsyncHandle.bytesRead);

await fileHandle.close();
}

async function validateLargeRead() {
Expand Down
2 changes: 2 additions & 0 deletions test/parallel/test-fs-promises-file-handle-readFile.js
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,8 @@ async function validateReadFile() {

const readFileData = await fileHandle.readFile();
assert.deepStrictEqual(buffer, readFileData);

await fileHandle.close();
}

async function validateReadFileProc() {
Expand Down
1 change: 1 addition & 0 deletions test/parallel/test-fs-promises-file-handle-stat.js
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ async function validateStat() {
const fileHandle = await open(filePath, 'w+');
const stats = await fileHandle.stat();
assert.ok(stats.mtime instanceof Date);
await fileHandle.close();
}

validateStat()
Expand Down
1 change: 1 addition & 0 deletions test/parallel/test-fs-promises-file-handle-sync.js
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ async function validateSync() {
const ret = await handle.read(Buffer.alloc(11), 0, 11, 0);
assert.strictEqual(ret.bytesRead, 11);
assert.deepStrictEqual(ret.buffer, buf);
await handle.close();
}

validateSync();
2 changes: 2 additions & 0 deletions test/parallel/test-fs-promises-file-handle-truncate.js
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,8 @@ async function validateTruncate() {

await fileHandle.truncate(5);
assert.deepStrictEqual((await readFile(filename)).toString(), 'Hello');

await fileHandle.close();
}

validateTruncate().then(common.mustCall());
8 changes: 8 additions & 0 deletions test/parallel/test-fs-promises-file-handle-write.js
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,8 @@ async function validateWrite() {
await fileHandle.write(buffer, 0, buffer.length);
const readFileData = fs.readFileSync(filePathForHandle);
assert.deepStrictEqual(buffer, readFileData);

await fileHandle.close();
}

async function validateEmptyWrite() {
Expand All @@ -32,6 +34,8 @@ async function validateEmptyWrite() {
await fileHandle.write(buffer, 0, buffer.length);
const readFileData = fs.readFileSync(filePathForHandle);
assert.deepStrictEqual(buffer, readFileData);

await fileHandle.close();
}

async function validateNonUint8ArrayWrite() {
Expand All @@ -42,6 +46,8 @@ async function validateNonUint8ArrayWrite() {
await fileHandle.write(buffer, 0, buffer.length);
const readFileData = fs.readFileSync(filePathForHandle);
assert.deepStrictEqual(Buffer.from(buffer, 'utf8'), readFileData);

await fileHandle.close();
}

async function validateNonStringValuesWrite() {
Expand All @@ -55,6 +61,8 @@ async function validateNonStringValuesWrite() {
const readFileData = fs.readFileSync(filePathForHandle);
const expected = ['123', '[object Object]', '[object Map]'].join('');
assert.deepStrictEqual(Buffer.from(expected, 'utf8'), readFileData);

await fileHandle.close();
}

Promise.all([
Expand Down
2 changes: 2 additions & 0 deletions test/parallel/test-fs-promises-file-handle-writeFile.js
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,8 @@ async function validateWriteFile() {
await fileHandle.writeFile(buffer);
const readFileData = fs.readFileSync(filePathForHandle);
assert.deepStrictEqual(buffer, readFileData);

await fileHandle.close();
}

validateWriteFile()
Expand Down
2 changes: 2 additions & 0 deletions test/parallel/test-fs-promises-readfile-with-fd.js
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,8 @@ async function readFileTest() {

/* readFile() should read from position five, instead of zero. */
assert.deepStrictEqual((await handle.readFile()).toString(), ' World');

await handle.close();
}


Expand Down
2 changes: 2 additions & 0 deletions test/parallel/test-fs-promises-writefile-with-fd.js
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,8 @@ async function writeFileTest() {

/* New content should be written at position five, instead of zero. */
assert.deepStrictEqual(readFileSync(fn).toString(), 'HelloWorld');

await handle.close();
}


Expand Down
Loading

0 comments on commit 8ef68e6

Please sign in to comment.