node/test/parallel/test-fs-rmdir-recursive.js
Maria Paktiti 27507ca108 test: add more recursive fs.rmdir() tests
Update tests to create more nested folders and files, like rimraf
package tests do. Each test will create 28 nested directories and
210 files. It will also create different types of files, like
symlinks.

PR-URL: https://github.com/nodejs/node/pull/29815
Reviewed-By: Ben Coe <bencoe@gmail.com>
2019-10-12 20:50:54 -07:00

215 lines
5.7 KiB
JavaScript

// Flags: --expose-internals
'use strict';
const common = require('../common');
const tmpdir = require('../common/tmpdir');
const assert = require('assert');
const fs = require('fs');
const path = require('path');
const { validateRmdirOptions } = require('internal/fs/utils');
let count = 0;
tmpdir.refresh();
function makeNonEmptyDirectory(depth, files, folders, dirname, createSymLinks) {
fs.mkdirSync(dirname, { recursive: true });
fs.writeFileSync(path.join(dirname, 'text.txt'), 'hello', 'utf8');
const options = { flag: 'wx' };
for (let f = files; f > 0; f--) {
fs.writeFileSync(path.join(dirname, `f-${depth}-${f}`), '', options);
}
if (createSymLinks) {
// Valid symlink
fs.symlinkSync(
`f-${depth}-1`,
path.join(dirname, `link-${depth}-good`),
'file'
);
// Invalid symlink
fs.symlinkSync(
'does-not-exist',
path.join(dirname, `link-${depth}-bad`),
'file'
);
}
// File with a name that looks like a glob
fs.writeFileSync(path.join(dirname, '[a-z0-9].txt'), '', options);
depth--;
if (depth <= 0) {
return;
}
for (let f = folders; f > 0; f--) {
fs.mkdirSync(
path.join(dirname, `folder-${depth}-${f}`),
{ recursive: true }
);
makeNonEmptyDirectory(
depth,
files,
folders,
path.join(dirname, `d-${depth}-${f}`),
createSymLinks
);
}
}
function removeAsync(dir) {
// Removal should fail without the recursive option.
fs.rmdir(dir, common.mustCall((err) => {
assert.strictEqual(err.syscall, 'rmdir');
// Removal should fail without the recursive option set to true.
fs.rmdir(dir, { recursive: false }, common.mustCall((err) => {
assert.strictEqual(err.syscall, 'rmdir');
// Recursive removal should succeed.
fs.rmdir(dir, { recursive: true }, common.mustCall((err) => {
assert.ifError(err);
// No error should occur if recursive and the directory does not exist.
fs.rmdir(dir, { recursive: true }, common.mustCall((err) => {
assert.ifError(err);
// Attempted removal should fail now because the directory is gone.
fs.rmdir(dir, common.mustCall((err) => {
assert.strictEqual(err.syscall, 'rmdir');
}));
}));
}));
}));
}));
}
// Test the asynchronous version
{
// Create a 4-level folder hierarchy including symlinks
let dir = `rmdir-recursive-${count}`;
makeNonEmptyDirectory(4, 10, 2, dir, true);
removeAsync(dir);
// Create a 2-level folder hierarchy without symlinks
count++;
dir = `rmdir-recursive-${count}`;
makeNonEmptyDirectory(2, 10, 2, dir, false);
removeAsync(dir);
// Create a flat folder including symlinks
count++;
dir = `rmdir-recursive-${count}`;
makeNonEmptyDirectory(1, 10, 2, dir, true);
removeAsync(dir);
}
// Test the synchronous version.
{
count++;
const dir = `rmdir-recursive-${count}`;
makeNonEmptyDirectory(4, 10, 2, dir, true);
// Removal should fail without the recursive option set to true.
common.expectsError(() => {
fs.rmdirSync(dir);
}, { syscall: 'rmdir' });
common.expectsError(() => {
fs.rmdirSync(dir, { recursive: false });
}, { syscall: 'rmdir' });
// Recursive removal should succeed.
fs.rmdirSync(dir, { recursive: true });
// No error should occur if recursive and the directory does not exist.
fs.rmdirSync(dir, { recursive: true });
// Attempted removal should fail now because the directory is gone.
common.expectsError(() => fs.rmdirSync(dir), { syscall: 'rmdir' });
}
// Test the Promises based version.
(async () => {
count++;
const dir = `rmdir-recursive-${count}`;
makeNonEmptyDirectory(4, 10, 2, dir, true);
// Removal should fail without the recursive option set to true.
assert.rejects(fs.promises.rmdir(dir), { syscall: 'rmdir' });
assert.rejects(fs.promises.rmdir(dir, { recursive: false }), {
syscall: 'rmdir'
});
// Recursive removal should succeed.
await fs.promises.rmdir(dir, { recursive: true });
// No error should occur if recursive and the directory does not exist.
await fs.promises.rmdir(dir, { recursive: true });
// Attempted removal should fail now because the directory is gone.
assert.rejects(fs.promises.rmdir(dir), { syscall: 'rmdir' });
})();
// Test input validation.
{
const defaults = {
emfileWait: 1000,
maxBusyTries: 3,
recursive: false
};
const modified = {
emfileWait: 953,
maxBusyTries: 5,
recursive: true
};
assert.deepStrictEqual(validateRmdirOptions(), defaults);
assert.deepStrictEqual(validateRmdirOptions({}), defaults);
assert.deepStrictEqual(validateRmdirOptions(modified), modified);
assert.deepStrictEqual(validateRmdirOptions({
maxBusyTries: 99
}), {
emfileWait: 1000,
maxBusyTries: 99,
recursive: false
});
[null, 'foo', 5, NaN].forEach((bad) => {
common.expectsError(() => {
validateRmdirOptions(bad);
}, {
code: 'ERR_INVALID_ARG_TYPE',
type: TypeError,
message: /^The "options" argument must be of type object\./
});
});
[undefined, null, 'foo', Infinity, function() {}].forEach((bad) => {
common.expectsError(() => {
validateRmdirOptions({ recursive: bad });
}, {
code: 'ERR_INVALID_ARG_TYPE',
type: TypeError,
message: /^The "recursive" argument must be of type boolean\./
});
});
common.expectsError(() => {
validateRmdirOptions({ emfileWait: -1 });
}, {
code: 'ERR_OUT_OF_RANGE',
type: RangeError,
message: /^The value of "emfileWait" is out of range\./
});
common.expectsError(() => {
validateRmdirOptions({ maxBusyTries: -1 });
}, {
code: 'ERR_OUT_OF_RANGE',
type: RangeError,
message: /^The value of "maxBusyTries" is out of range\./
});
}