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

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))
})
})