Bones/node_modules/lockfile/test/stale-contention.js

86 lines
2.1 KiB
JavaScript
Raw Normal View History

2017-05-17 13:45:25 -04:00
var fs = require('fs')
var lockFile = require('../')
var test = require('tap').test
var path = require('path')
var lock = path.resolve(__dirname, 'stale.lock')
var touch = require('touch')
var spawn = require('child_process').spawn
var node = process.execPath
// We're using a lockfile with an artificially old date,
// so make it use that instead of ctime.
// Probably you should never do this in production!
lockFile.filetime = 'mtime'
if (process.argv[2] === 'child') {
return child()
}
function child () {
// Make fs.stat take 100ms to return its data
// This is important because, in a test scenario where
// we're statting the same exact file rapid-fire like this,
// it'll end up being cached by the FS, and never trigger
// the race condition we're trying to expose.
fs.stat = function (stat) { return function () {
var args = [].slice.call(arguments)
var cb = args.pop()
stat.apply(fs, args.concat(function(er, st) {
setTimeout(function () {
cb(er, st)
}, 100)
}))
}}(fs.stat)
lockFile.lock(lock, { stale: 100000 }, function (er) {
if (er && er.code !== 'EEXIST')
throw er
else if (er)
process.exit(17)
else
setTimeout(function(){}, 500)
})
}
test('create stale file', function (t) {
try { fs.unlinkSync(lock) } catch (er) {}
touch.sync(lock, { time: '1979-07-01T19:10:00.000Z' })
t.end()
})
test('contenders', function (t) {
var n = 10
var fails = 0
var wins = 0
var args = [ __filename, 'child' ]
var opt = { stdio: [0, "pipe", 2] }
for (var i = 0; i < n; i++) {
spawn(node, args, opt).on('close', then)
}
function then (code) {
if (code === 17) {
fails ++
} else if (code) {
t.fail("unexpected failure", code)
fails ++
} else {
wins ++
}
if (fails + wins === n) {
done()
}
}
function done () {
t.equal(wins, 1, "should have 1 lock winner")
t.equal(fails, n - 1, "all others should lose")
t.end()
}
})
test('remove stale file', function (t) {
try { fs.unlinkSync(lock) } catch (er) {}
t.end()
})