You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
200 lines
6.0 KiB
200 lines
6.0 KiB
var tap = require('tap') |
|
, sinon = require('sinon') |
|
, fs = require('fs') |
|
, path = require('path') |
|
, mkfiletree = require('mkfiletree') |
|
, FDManager = require('./') |
|
|
|
tap.test('open / close', function (t) { |
|
var fsMock = sinon.mock(fs) |
|
, fdman = FDManager() |
|
|
|
fsMock.expects('open').once().withArgs('/foo/bar/baz.txt', 'r').callsArgWith(2, null, 101) |
|
fsMock.expects('close').once().withArgs(101) |
|
|
|
fdman.open('/foo/bar/baz.txt', function (err, fd) { |
|
t.notOk(err) |
|
t.equal(fd, 101) |
|
fdman.close('/foo/bar/baz.txt', 101) |
|
process.nextTick(function () { |
|
fsMock.verify() |
|
t.equal(0, FDManager._totalOpenFds) |
|
t.end() |
|
}) |
|
}) |
|
}) |
|
|
|
tap.test('open / checkout / close', function (t) { |
|
var fsMock = sinon.mock(fs) |
|
, fdman = FDManager() |
|
, closeSpy |
|
|
|
fsMock.expects('open').once().withArgs('/foo/bar/baz.txt', 'r').callsArgWith(2, null, 101) |
|
closeSpy = fsMock.expects('close').once().withArgs(101) |
|
|
|
// open a file |
|
fdman.open('/foo/bar/baz.txt', function (err, fd) { |
|
t.notOk(err) |
|
t.equal(fd, 101) |
|
|
|
// check it out |
|
fdman.checkout('/foo/bar/baz.txt', 101) |
|
|
|
// close it |
|
fdman.close('/foo/bar/baz.txt', fd) |
|
|
|
process.nextTick(function () { |
|
// file should NOT be closed |
|
t.equal(closeSpy.callCount, 0) |
|
|
|
// check it in |
|
fdman.checkin('/foo/bar/baz.txt', 101) |
|
process.nextTick(function () { |
|
// file should now be closed |
|
fsMock.verify() |
|
t.equal(0, FDManager._totalOpenFds) |
|
t.end() |
|
}) |
|
}) |
|
}) |
|
}) |
|
|
|
tap.test('open / checkout / close with checkinfn', function (t) { |
|
var fsMock = sinon.mock(fs) |
|
, fdman = FDManager() |
|
, closeSpy |
|
|
|
fsMock.expects('open').once().withArgs('/foo/bar/baz.txt', 'r').callsArgWith(2, null, 101) |
|
closeSpy = fsMock.expects('close').once().withArgs(101) |
|
|
|
// open a file |
|
fdman.open('/foo/bar/baz.txt', function (err, fd) { |
|
t.notOk(err) |
|
t.equal(fd, 101) |
|
|
|
// check it out |
|
fdman.checkout('/foo/bar/baz.txt', 101) |
|
var checkin = fdman.checkinfn('/foo/bar/baz.txt', 101) |
|
|
|
// close it |
|
fdman.close('/foo/bar/baz.txt', fd) |
|
|
|
process.nextTick(function () { |
|
// file should NOT be closed |
|
t.equal(closeSpy.callCount, 0) |
|
|
|
// check it in |
|
checkin('/foo/bar/baz.txt', 101) |
|
process.nextTick(function () { |
|
// file should now be closed |
|
fsMock.verify() |
|
t.equal(0, FDManager._totalOpenFds) |
|
t.end() |
|
}) |
|
}) |
|
}) |
|
}) |
|
|
|
tap.test('many open files', function (t) { |
|
var filetree = {} |
|
, fdman = FDManager() |
|
, i = 200 |
|
, maxopen = 0 |
|
, tasks = 0 |
|
, end = function () { |
|
process.nextTick(function () { |
|
// after all that, we shouldn't have anything left open |
|
t.equal(0, FDManager._totalOpenFds) |
|
console.error('Max open fds: ' + maxopen) |
|
mkfiletree.cleanUp(t.end.bind(t)) |
|
}) |
|
} |
|
// a simple async tasks queue, once we start putting jobs into this |
|
// we watch them complete and when tasks in = tasks complete then |
|
// end() |
|
, async = function (task) { |
|
tasks++ |
|
process.nextTick(task.bind(null, function (err) { |
|
// watch the fd-open count |
|
if (FDManager._totalOpenFds > maxopen) maxopen = FDManager._totalOpenFds |
|
t.notOk(err) |
|
if (--tasks === 0) |
|
end() |
|
})) |
|
} |
|
|
|
// make a big directory full of guff |
|
while (i--) |
|
filetree['derp' + i] = 'DERPTASTIC! ' + i |
|
|
|
// HAHAHAHAHAHAHAHAHAHAHAHAH! |
|
// good luck figuring this out buddy |
|
// it made sense when it was coming out of my fingers at least |
|
mkfiletree.makeTemp('fd', filetree, function (err, dir) { |
|
|
|
// called for each of the 200 files |
|
function runner (i) { |
|
var f = path.join(dir, 'derp' + i) |
|
return function (callback) { |
|
setTimeout(function () { // stagger opens |
|
// open the file |
|
fdman.open(f, function (err, fd) { |
|
t.equal(err, null, 'no err') |
|
t.ok(fd > 0, 'fd > 0 [' + fd + ']: ' + f) |
|
// for each file, do this next stuff up to `i` times |
|
for (var j = 0; j < i; j++) { |
|
(function (j) { |
|
async(function (callback) { |
|
setTimeout(function () { |
|
// checkout the file, `j` ms later |
|
fdman.checkout(f, fd) |
|
if (j === i - 1) { |
|
// on the last checkout, read from the fd to make sure it's |
|
// what we expect |
|
var buf = new Buffer(20) |
|
fs.read(fd, buf, 0, 20, 0, function (err, len) { |
|
t.notOk(err) |
|
t.equal(buf.toString('utf8', 0, len), 'DERPTASTIC! ' + i) |
|
// console.error('READ',i,buf.toString('utf8', 0, len)) |
|
callback() |
|
}) |
|
} else |
|
callback() |
|
}, j) |
|
|
|
async(function (callback) { |
|
setTimeout(function () { |
|
// a matching checkin for each checkout, delayed from the |
|
// checkin by up to 10ms |
|
// (this could be moved up into the checkout block to make sure |
|
// the read doesn't cause problems) |
|
fdman.checkin(f, fd) |
|
callback() |
|
}, j + (Math.random() * 10)) |
|
}) |
|
}) |
|
}(j)) |
|
} |
|
|
|
async(function (callback) { |
|
setTimeout(function () { |
|
// close the file at some point after we've opened it, by this |
|
// time there will be checkouts in process so it shouldn't be |
|
// closeable |
|
fdman.close(f, fd) |
|
callback() |
|
}, Math.floor(10 + Math.random() * i)) |
|
}) |
|
callback() |
|
}) |
|
}, i) |
|
} |
|
} |
|
|
|
console.error('DIR',dir) |
|
t.notOk(err, 'no err') |
|
|
|
for (i = 0; i < 200; i++) |
|
async(runner(i)) |
|
}) |
|
}) |