@inst/vscode-bin-darwin
Version:
BINARY ONLY - VSCode binary deployment for macOS
573 lines (526 loc) • 18.6 kB
JavaScript
;
var nsfw = require('../src/');
var path = require('path');
var promisify = require('promisify-node');
var fse = promisify(require('fs-extra'));
var exec = promisify(function (command, options, callback) {
return require('child_process').exec(command, options, callback);
});
jasmine.DEFAULT_TIMEOUT_INTERVAL = 120000;
var DEBOUNCE = 1000;
var TIMEOUT_PER_STEP = 3000;
describe('Node Sentinel File Watcher', function () {
var workDir = path.resolve('./mockfs');
beforeEach(function (done) {
function makeDir(identifier) {
return fse.mkdir(path.join(workDir, 'test' + identifier)).then(function () {
return fse.mkdir(path.join(workDir, 'test' + identifier, 'folder' + identifier));
}).then(function () {
return fse.open(path.join(workDir, 'test' + identifier, 'testing' + identifier + '.file'), 'w');
}).then(function (fd) {
return fse.write(fd, 'testing').then(function () {
return fd;
});
}).then(function (fd) {
return fse.close(fd);
});
}
// create a file System
return fse.stat(workDir).then(function () {
return fse.remove(workDir);
}, function () {}).then(function () {
return fse.mkdir(workDir);
}).then(function () {
var promises = [];
for (var i = 0; i < 5; ++i) {
promises.push(makeDir(i));
}
return Promise.all(promises);
}).then(done);
});
afterEach(function (done) {
return fse.remove(workDir).then(done);
});
describe('Basic', function () {
it('can watch a single file', function (done) {
var file = 'testing1.file';
var inPath = path.resolve(workDir, 'test1');
var filePath = path.join(inPath, file);
var changeEvents = 0;
var createEvents = 0;
var deleteEvents = 0;
function findEvents(element) {
if (element.action === nsfw.actions.MODIFIED && element.directory === path.resolve(inPath) && element.file === file) {
changeEvents++;
} else if (element.action === nsfw.actions.CREATED && element.directory === path.resolve(inPath) && element.file === file) {
createEvents++;
} else if (element.action === nsfw.actions.DELETED && element.directory === path.resolve(inPath) && element.file === file) {
deleteEvents++;
}
}
var watch = void 0;
return nsfw(filePath, function (events) {
return events.forEach(findEvents);
}, { debounceMS: 100 }).then(function (_w) {
watch = _w;
return watch.start();
}).then(function () {
return new Promise(function (resolve) {
setTimeout(resolve, TIMEOUT_PER_STEP);
});
}).then(function () {
var fd = fse.openSync(filePath, 'w');
fse.writeSync(fd, 'Bean bag video games at noon.');
return fse.close(fd);
}).then(function () {
return new Promise(function (resolve) {
setTimeout(resolve, TIMEOUT_PER_STEP);
});
}).then(function () {
return fse.remove(filePath);
}).then(function () {
return new Promise(function (resolve) {
setTimeout(resolve, TIMEOUT_PER_STEP);
});
}).then(function () {
var fd = fse.openSync(filePath, 'w');
fse.writeSync(fd, 'His watch has ended.');
return fse.close(fd);
}).then(function () {
return new Promise(function (resolve) {
setTimeout(resolve, TIMEOUT_PER_STEP);
});
}).then(function () {
return watch.stop();
}).then(function () {
expect(changeEvents).toBeGreaterThan(0);
expect(createEvents).toBe(1);
expect(deleteEvents).toBe(1);
}).then(done, function () {
return watch.stop().then(function (err) {
return done.fail(err);
});
});
});
it('can listen for a create event', function (done) {
var file = 'another_test.file';
var inPath = path.resolve(workDir, 'test2', 'folder2');
var eventFound = false;
function findEvent(element) {
if (element.action === nsfw.actions.CREATED && element.directory === path.resolve(inPath) && element.file === file) {
eventFound = true;
}
}
var watch = void 0;
return nsfw(workDir, function (events) {
return events.forEach(findEvent);
}, { debounceMS: DEBOUNCE }).then(function (_w) {
watch = _w;
return watch.start();
}).then(function () {
return new Promise(function (resolve) {
setTimeout(resolve, TIMEOUT_PER_STEP);
});
}).then(function () {
return fse.open(path.join(inPath, file), 'w');
}).then(function (fd) {
return fse.write(fd, 'Peanuts, on occasion, rain from the skies.').then(function () {
return fd;
});
}).then(function (fd) {
return fse.close(fd);
}).then(function () {
return new Promise(function (resolve) {
setTimeout(resolve, TIMEOUT_PER_STEP);
});
}).then(function () {
expect(eventFound).toBe(true);
return watch.stop();
}).then(done, function () {
return watch.stop().then(function (err) {
return done.fail(err);
});
});
});
it('can listen for a delete event', function (done) {
var file = 'testing3.file';
var inPath = path.resolve(workDir, 'test3');
var eventFound = false;
function findEvent(element) {
if (element.action === nsfw.actions.DELETED && element.directory === path.resolve(inPath) && element.file === file) {
eventFound = true;
}
}
var watch = void 0;
return nsfw(workDir, function (events) {
return events.forEach(findEvent);
}, { debounceMS: DEBOUNCE }).then(function (_w) {
watch = _w;
return watch.start();
}).then(function () {
return new Promise(function (resolve) {
setTimeout(resolve, TIMEOUT_PER_STEP);
});
}).then(function () {
return fse.remove(path.join(inPath, file));
}).then(function () {
return new Promise(function (resolve) {
setTimeout(resolve, TIMEOUT_PER_STEP);
});
}).then(function () {
expect(eventFound).toBe(true);
return watch.stop();
}).then(done, function () {
return watch.stop().then(function (err) {
return done.fail(err);
});
});
});
it('can listen for a modify event', function (done) {
var file = 'testing0.file';
var inPath = path.resolve(workDir, 'test0');
var eventFound = false;
function findEvent(element) {
if (element.action === nsfw.actions.MODIFIED && element.directory === path.resolve(inPath) && element.file === file) {
eventFound = true;
}
}
var watch = void 0;
return nsfw(workDir, function (events) {
return events.forEach(findEvent);
}, { debounceMS: DEBOUNCE }).then(function (_w) {
watch = _w;
return watch.start();
}).then(function () {
return new Promise(function (resolve) {
setTimeout(resolve, TIMEOUT_PER_STEP);
});
}).then(function () {
return fse.open(path.join(inPath, file), 'w');
}).then(function (fd) {
return fse.write(fd, 'At times, sunflower seeds are all that is life.').then(function () {
return fd;
});
}).then(function (fd) {
return fse.close(fd);
}).then(function () {
return new Promise(function (resolve) {
setTimeout(resolve, TIMEOUT_PER_STEP);
});
}).then(function () {
expect(eventFound).toBe(true);
return watch.stop();
}).then(done, function () {
return watch.stop().then(function (err) {
return done.fail(err);
});
});
});
it('can run multiple watchers at once', function (done) {
var dirA = path.resolve(workDir, 'test0');
var fileA = 'testing1.file';
var dirB = path.resolve(workDir, 'test1');
var fileB = 'testing0.file';
var events = 0;
function findEvent(element) {
if (element.action === nsfw.actions.CREATED) {
if (element.directory === dirA && element.file === fileA) {
events++;
} else if (element.directory === dirB && element.file === fileB) {
events++;
}
}
}
var watchA = void 0;
var watchB = void 0;
return nsfw(dirA, function (events) {
return events.forEach(findEvent);
}, { debounceMS: DEBOUNCE }).then(function (_w) {
watchA = _w;
return watchA.start();
}).then(function () {
return nsfw(dirB, function (events) {
return events.forEach(findEvent);
}, { debounceMS: DEBOUNCE }).then(function (_w) {
watchB = _w;
return watchB.start();
});
}).then(function () {
return new Promise(function (resolve) {
setTimeout(resolve, TIMEOUT_PER_STEP);
});
}).then(function () {
return fse.open(path.join(dirA, fileA), 'w');
}).then(function (fd) {
return new Promise(function (resolve) {
setTimeout(function () {
return resolve(fd);
}, TIMEOUT_PER_STEP);
});
}).then(function (fd) {
return fse.write(fd, 'At times, sunflower seeds are all that is life.').then(function () {
return fd;
});
}).then(function (fd) {
return fse.close(fd);
}).then(function () {
return fse.open(path.join(dirB, fileB), 'w');
}).then(function (fd) {
return new Promise(function (resolve) {
setTimeout(function () {
return resolve(fd);
}, TIMEOUT_PER_STEP);
});
}).then(function (fd) {
return fse.write(fd, 'At times, sunflower seeds are all that is life.').then(function () {
return fd;
});
}).then(function (fd) {
return fse.close(fd);
}).then(function () {
return new Promise(function (resolve) {
setTimeout(resolve, TIMEOUT_PER_STEP);
});
}).then(function () {
expect(events).toBe(2);
return watchA.stop();
}).then(function () {
return watchB.stop();
}).then(done, function () {
return watchA.stop().then(function () {
return watchB.stop();
}).then(function (err) {
return done.fail(err);
});
});
});
});
describe('Recursive', function () {
it('can listen for the creation of a deeply nested file', function (done) {
var paths = ['d', 'e', 'e', 'p', 'f', 'o', 'l', 'd', 'e', 'r'];
var file = 'a_file.txt';
var foundFileCreateEvent = false;
function findEvent(element) {
if (element.action === nsfw.actions.CREATED && element.directory === path.join.apply(path, [workDir].concat(paths)) && element.file === file) {
foundFileCreateEvent = true;
}
}
var watch = void 0;
var directory = workDir;
return nsfw(workDir, function (events) {
return events.forEach(findEvent);
}, { debounceMS: DEBOUNCE }).then(function (_w) {
watch = _w;
return watch.start();
}).then(function () {
return new Promise(function (resolve) {
setTimeout(resolve, TIMEOUT_PER_STEP);
});
}).then(function () {
return paths.reduce(function (chain, dir) {
directory = path.join(directory, dir);
var nextDirectory = directory;
return chain.then(function () {
return fse.mkdir(nextDirectory);
});
}, Promise.resolve());
}).then(function () {
return fse.open(path.join(directory, file), 'w');
}).then(function (fd) {
return fse.close(fd);
}).then(function () {
return new Promise(function (resolve) {
setTimeout(resolve, TIMEOUT_PER_STEP);
});
}).then(function () {
expect(foundFileCreateEvent).toBe(true);
return watch.stop();
}).then(done, function () {
return watch.stop().then(function (err) {
return done.fail(err);
});
});
});
it('can listen for the destruction of a directory and its subtree', function (done) {
var inPath = path.resolve(workDir, 'test4');
var deletionCount = 0;
function findEvent(element) {
if (element.action === nsfw.actions.DELETED) {
if (element.directory === path.resolve(inPath) && (element.file === 'testing4.file' || element.file === 'folder4')) {
deletionCount++;
} else if (element.directory === workDir && element.file === 'test4') {
deletionCount++;
}
}
}
var watch = void 0;
return nsfw(workDir, function (events) {
return events.forEach(findEvent);
}, { debounceMS: DEBOUNCE }).then(function (_w) {
watch = _w;
return watch.start();
}).then(function () {
return new Promise(function (resolve) {
setTimeout(resolve, TIMEOUT_PER_STEP);
});
}).then(function () {
return fse.remove(inPath);
}).then(function () {
return new Promise(function (resolve) {
setTimeout(resolve, TIMEOUT_PER_STEP);
});
}).then(function () {
expect(deletionCount).toBeGreaterThan(2);
return watch.stop();
}).then(done, function () {
return watch.stop().then(function (err) {
return done.fail(err);
});
});
});
});
describe('Errors', function () {
it('can gracefully recover when the watch folder is deleted', function (done) {
var inPath = path.join(workDir, 'test4');
var erroredOut = false;
var watch = void 0;
return nsfw(inPath, function () {}, { debounceMS: DEBOUNCE, errorCallback: function errorCallback() {
erroredOut = true;
}
}).then(function (_w) {
watch = _w;
return watch.start();
}).then(function () {
return new Promise(function (resolve) {
setTimeout(resolve, TIMEOUT_PER_STEP);
});
}).then(function () {
return fse.remove(inPath);
}).then(function () {
return new Promise(function (resolve) {
setTimeout(resolve, TIMEOUT_PER_STEP);
});
}).then(function () {
expect(erroredOut).toBe(true);
return watch.stop();
}).then(done, function () {
return watch.stop().then(function (err) {
return done.fail(err);
});
});
});
});
describe('Stress', function () {
var stressRepoPath = path.resolve('nsfw-stress-test');
beforeEach(function (done) {
return exec('git clone https://github.com/implausible/nsfw-stress-test').then(done);
});
it('does not segfault under stress', function (done) {
var count = 0;
var watch = void 0;
var errorRestart = Promise.resolve();
return nsfw(stressRepoPath, function () {
count++;
}, {
errorCallback: function errorCallback() {
errorRestart = watch.stop().then(watch.start);
}
}).then(function (_w) {
watch = _w;
return watch.start();
}).then(function () {
return fse.remove(path.join(stressRepoPath, 'folder'));
}).then(function () {
return errorRestart;
}).then(function () {
expect(count).toBeGreaterThan(0);
return watch.stop();
}).then(function () {
return fse.remove(stressRepoPath);
}).then(function () {
return fse.mkdir(stressRepoPath);
}).then(function () {
return nsfw(stressRepoPath, function () {
count++;
}, {
errorCallback: function errorCallback() {
errorRestart = watch.stop().then(watch.start);
}
});
}).then(function (_w) {
watch = _w;
count = 0;
errorRestart = Promise.resolve();
return watch.start();
}).then(function () {
return new Promise(function (resolve) {
return setTimeout(resolve, TIMEOUT_PER_STEP);
});
}).then(function () {
return exec('git clone https://github.com/implausible/nsfw-stress-test ' + path.join('nsfw-stress-test', 'test'));
}).then(function () {
return fse.stat(path.join(stressRepoPath, 'test'));
}).then(function () {
return fse.remove(path.join(stressRepoPath, 'test'));
}).then(function () {
return errorRestart;
}).then(function () {
expect(count).toBeGreaterThan(0);
count = 0;
return watch.stop();
}).then(done, function () {
return watch.stop().then(function (err) {
return done.fail(err);
});
});
});
afterEach(function (done) {
return fse.remove(stressRepoPath).then(done);
});
});
describe('Unicode support', function () {
var watchPath = path.join(workDir, 'は');
beforeEach(function (done) {
return fse.mkdir(watchPath).then(done);
});
it('supports watching unicode directories', function (done) {
var file = 'unicoded_right_in_the.talker';
var eventFound = false;
function findEvent(element) {
if (element.action === nsfw.actions.CREATED && element.directory === watchPath && element.file === file) {
eventFound = true;
}
}
var watch = void 0;
return nsfw(workDir, function (events) {
return events.forEach(findEvent);
}, { debounceMS: DEBOUNCE }).then(function (_w) {
watch = _w;
return watch.start();
}).then(function () {
return new Promise(function (resolve) {
setTimeout(resolve, TIMEOUT_PER_STEP);
});
}).then(function () {
return fse.open(path.join(watchPath, file), 'w');
}).then(function (fd) {
return fse.write(fd, 'Unicode though.').then(function () {
return fd;
});
}).then(function (fd) {
return fse.close(fd);
}).then(function () {
return new Promise(function (resolve) {
setTimeout(resolve, TIMEOUT_PER_STEP);
});
}).then(function () {
expect(eventFound).toBe(true);
return watch.stop();
}).then(done, function () {
return watch.stop().then(function (err) {
return done.fail(err);
});
});
});
});
});