Skip to content

Commit e7a38ab

Browse files
committed
test,bench: add tests/bench for fs.realpath() fix
The test/benchmarks included also work for the previous JS implementation of fs.realpath(). In case the new implementation of realpath() needs to be reverted, we want these changes to stick around.
1 parent bf8827b commit e7a38ab

File tree

3 files changed

+158
-2
lines changed

3 files changed

+158
-2
lines changed

benchmark/fs/bench-realpath.js

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
'use strict';
2+
3+
const common = require('../common');
4+
const fs = require('fs');
5+
const path = require('path');
6+
const resolved_path = path.resolve(__dirname, '../../lib/');
7+
const relative_path = path.relative(__dirname, '../../lib/');
8+
9+
const bench = common.createBenchmark(main, {
10+
n: [1e4],
11+
type: ['relative', 'resolved'],
12+
});
13+
14+
15+
function main(conf) {
16+
const n = conf.n >>> 0;
17+
const type = conf.type;
18+
19+
bench.start();
20+
if (type === 'relative')
21+
relativePath(n);
22+
else if (type === 'resolved')
23+
resolvedPath(n);
24+
else
25+
throw new Error('unknown "type": ' + type);
26+
}
27+
28+
function relativePath(n) {
29+
(function r(cntr) {
30+
if (--cntr <= 0)
31+
return bench.end(n);
32+
fs.realpath(relative_path, function() {
33+
r(cntr);
34+
});
35+
}(n));
36+
}
37+
38+
function resolvedPath(n) {
39+
(function r(cntr) {
40+
if (--cntr <= 0)
41+
return bench.end(n);
42+
fs.realpath(resolved_path, function() {
43+
r(cntr);
44+
});
45+
}(n));
46+
}

benchmark/fs/bench-realpathSync.js

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
'use strict';
2+
3+
const common = require('../common');
4+
const fs = require('fs');
5+
const path = require('path');
6+
const resolved_path = path.resolve(__dirname, '../../lib/');
7+
const relative_path = path.relative(__dirname, '../../lib/');
8+
9+
const bench = common.createBenchmark(main, {
10+
n: [1e4],
11+
type: ['relative', 'resolved'],
12+
});
13+
14+
15+
function main(conf) {
16+
const n = conf.n >>> 0;
17+
const type = conf.type;
18+
19+
bench.start();
20+
if (type === 'relative')
21+
relativePath(n);
22+
else if (type === 'resolved')
23+
resolvedPath(n);
24+
else
25+
throw new Error('unknown "type": ' + type);
26+
bench.end(n);
27+
}
28+
29+
function relativePath(n) {
30+
for (var i = 0; i < n; i++) {
31+
fs.realpathSync(relative_path);
32+
}
33+
}
34+
35+
function resolvedPath(n) {
36+
for (var i = 0; i < n; i++) {
37+
fs.realpathSync(resolved_path);
38+
}
39+
}

test/parallel/test-fs-realpath.js

Lines changed: 73 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -204,7 +204,7 @@ function test_cyclic_link_protection(callback) {
204204
fs.symlinkSync(t[1], t[0], 'dir');
205205
unlink.push(t[0]);
206206
});
207-
assert.throws(function() { fs.realpathSync(entry); });
207+
assert.throws(function() { fs.realpathSync(entry); }, /ELOOP/);
208208
asynctest(fs.realpath, [entry], callback, function(err, result) {
209209
assert.ok(err && true);
210210
return true;
@@ -461,6 +461,76 @@ function test_abs_with_kids(cb) {
461461
});
462462
}
463463

464+
function test_deep_symlink_eloop(callback) {
465+
console.log('test_deep_symlink_eloop');
466+
if (skipSymlinks) {
467+
common.skip('symlink test (no privs)');
468+
return runNextTest();
469+
}
470+
471+
const deepsymPath = path.join(targetsAbsDir, 'deep-symlink');
472+
const aPath = path.join(deepsymPath, 'a');
473+
const bSympath = path.join(aPath, 'b');
474+
const cleanupPaths = [bSympath];
475+
const pRepeat = 33;
476+
477+
function cleanup() {
478+
while (cleanupPaths.length > 0) {
479+
try {fs.unlinkSync(cleanupPaths.pop());} catch (e) {}
480+
}
481+
}
482+
483+
fs.mkdirSync(deepsymPath);
484+
fs.mkdirSync(aPath);
485+
fs.mkdirSync(path.join(targetsAbsDir, 'deep-symlink', 'c'));
486+
try {fs.unlinkSync(bSympath);} catch (e) {}
487+
fs.symlinkSync(deepsymPath, bSympath);
488+
489+
// First test sync calls.
490+
491+
const testPath = aPath + '/b/a'.repeat(pRepeat) + '/b/c';
492+
const resolvedPath = fs.realpathSync(testPath);
493+
assert.equal(path.relative(deepsymPath, resolvedPath), 'c');
494+
495+
var reallyBigSymPath = deepsymPath;
496+
var prev = null;
497+
498+
// Make massively deep set of symlinks
499+
for (var i = 97; i < 105; i++) {
500+
for (var j = 97; j < 101; j++) {
501+
const link = String.fromCharCode(i) + String.fromCharCode(j);
502+
const link_path = path.join(deepsymPath, link);
503+
cleanupPaths.push(link_path);
504+
try {fs.unlinkSync(link_path);} catch (e) {}
505+
if (prev)
506+
fs.symlinkSync(link_path, prev);
507+
reallyBigSymPath += '/' + link;
508+
prev = link_path;
509+
}
510+
}
511+
fs.symlinkSync(deepsymPath, prev);
512+
reallyBigSymPath += '/' + path.basename(prev);
513+
514+
assert.throws(() => fs.realpathSync(reallyBigSymPath), /ELOOP/);
515+
516+
// Now test async calls.
517+
518+
fs.realpath(testPath, (err, resolvedPath) => {
519+
if (err) throw err;
520+
assert.equal(path.relative(deepsymPath, resolvedPath), 'c');
521+
checkAsyncReallyBigSymPath();
522+
});
523+
524+
function checkAsyncReallyBigSymPath() {
525+
fs.realpath(reallyBigSymPath, (err, path) => {
526+
assert.ok(err);
527+
assert.ok(/ELOOP/.test(err.message));
528+
cleanup();
529+
runNextTest();
530+
});
531+
}
532+
}
533+
464534
// ----------------------------------------------------------------------------
465535

466536
var tests = [
@@ -476,7 +546,8 @@ var tests = [
476546
test_non_symlinks,
477547
test_escape_cwd,
478548
test_abs_with_kids,
479-
test_up_multiple
549+
test_up_multiple,
550+
test_deep_symlink_eloop,
480551
];
481552
var numtests = tests.length;
482553
var testsRun = 0;

0 commit comments

Comments
 (0)