Template Upload
This commit is contained in:
292
node_modules/lockfile/test/basic.js
generated
vendored
Normal file
292
node_modules/lockfile/test/basic.js
generated
vendored
Normal file
@ -0,0 +1,292 @@
|
||||
var test = require('tap').test
|
||||
var lockFile = require('../lockfile.js')
|
||||
var path = require('path')
|
||||
var fs = require('fs')
|
||||
var touch = require('touch')
|
||||
|
||||
// On Unix systems, it uses ctime by default for staleness checks, since it's
|
||||
// the most reliable. However, because this test artificially sets some locks
|
||||
// to an earlier time to simulate staleness, we use mtime here.
|
||||
lockFile.filetime = 'mtime'
|
||||
|
||||
test('setup', function (t) {
|
||||
try { lockFile.unlockSync('basic-lock') } catch (er) {}
|
||||
try { lockFile.unlockSync('sync-lock') } catch (er) {}
|
||||
try { lockFile.unlockSync('never-forget') } catch (er) {}
|
||||
try { lockFile.unlockSync('stale-lock') } catch (er) {}
|
||||
try { lockFile.unlockSync('watch-lock') } catch (er) {}
|
||||
try { lockFile.unlockSync('retry-lock') } catch (er) {}
|
||||
try { lockFile.unlockSync('contentious-lock') } catch (er) {}
|
||||
try { lockFile.unlockSync('stale-wait-lock') } catch (er) {}
|
||||
try { lockFile.unlockSync('stale-windows-lock') } catch (er) {}
|
||||
t.end()
|
||||
})
|
||||
|
||||
test('lock contention', function (t) {
|
||||
var gotlocks = 0;
|
||||
var N = 200
|
||||
var delay = 10
|
||||
// allow for some time for each lock acquisition and release.
|
||||
// note that raising N higher will mean that the overhead
|
||||
// increases, because we're creating more and more watchers.
|
||||
// irl, you should never have several hundred contenders for a
|
||||
// single lock, so this situation is somewhat pathological.
|
||||
var overhead = 200
|
||||
var wait = N * overhead + delay
|
||||
|
||||
// first make it locked, so that everyone has to wait
|
||||
lockFile.lock('contentious-lock', function(er, lock) {
|
||||
t.ifError(er, 'acquiring starter')
|
||||
if (er) throw er;
|
||||
t.pass('acquired starter lock')
|
||||
setTimeout(function() {
|
||||
lockFile.unlock('contentious-lock', function (er) {
|
||||
t.ifError(er, 'unlocking starter')
|
||||
if (er) throw er
|
||||
t.pass('unlocked starter')
|
||||
})
|
||||
}, delay)
|
||||
})
|
||||
|
||||
for (var i=0; i < N; i++)
|
||||
lockFile.lock('contentious-lock', { wait: wait }, function(er, lock) {
|
||||
if (er) throw er;
|
||||
lockFile.unlock('contentious-lock', function(er) {
|
||||
if (er) throw er
|
||||
gotlocks++
|
||||
t.pass('locked and unlocked #' + gotlocks)
|
||||
if (gotlocks === N) {
|
||||
t.pass('got all locks')
|
||||
t.end()
|
||||
}
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
test('basic test', function (t) {
|
||||
lockFile.check('basic-lock', function (er, locked) {
|
||||
if (er) throw er
|
||||
t.notOk(locked)
|
||||
lockFile.lock('basic-lock', function (er) {
|
||||
if (er) throw er
|
||||
lockFile.lock('basic-lock', function (er) {
|
||||
t.ok(er)
|
||||
lockFile.check('basic-lock', function (er, locked) {
|
||||
if (er) throw er
|
||||
t.ok(locked)
|
||||
lockFile.unlock('basic-lock', function (er) {
|
||||
if (er) throw er
|
||||
lockFile.check('basic-lock', function (er, locked) {
|
||||
if (er) throw er
|
||||
t.notOk(locked)
|
||||
t.end()
|
||||
})
|
||||
})
|
||||
})
|
||||
})
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
test('sync test', function (t) {
|
||||
var locked
|
||||
locked = lockFile.checkSync('sync-lock')
|
||||
t.notOk(locked)
|
||||
lockFile.lockSync('sync-lock')
|
||||
locked = lockFile.checkSync('sync-lock')
|
||||
t.ok(locked)
|
||||
lockFile.unlockSync('sync-lock')
|
||||
locked = lockFile.checkSync('sync-lock')
|
||||
t.notOk(locked)
|
||||
t.end()
|
||||
})
|
||||
|
||||
test('exit cleanup test', function (t) {
|
||||
var child = require.resolve('./fixtures/child.js')
|
||||
var node = process.execPath
|
||||
var spawn = require('child_process').spawn
|
||||
spawn(node, [child]).on('exit', function () {
|
||||
setTimeout(function () {
|
||||
var locked = lockFile.checkSync('never-forget')
|
||||
t.notOk(locked)
|
||||
t.end()
|
||||
}, 100)
|
||||
})
|
||||
})
|
||||
|
||||
test('error exit cleanup test', function (t) {
|
||||
var child = require.resolve('./fixtures/bad-child.js')
|
||||
var node = process.execPath
|
||||
var spawn = require('child_process').spawn
|
||||
spawn(node, [child]).on('exit', function () {
|
||||
setTimeout(function () {
|
||||
var locked = lockFile.checkSync('never-forget')
|
||||
t.notOk(locked)
|
||||
t.end()
|
||||
}, 100)
|
||||
})
|
||||
})
|
||||
|
||||
|
||||
test('staleness test', function (t) {
|
||||
lockFile.lock('stale-lock', function (er) {
|
||||
if (er) throw er
|
||||
|
||||
// simulate 2s old
|
||||
touch.sync('stale-lock', { time: new Date(Date.now() - 2000) })
|
||||
|
||||
var opts = { stale: 1 }
|
||||
lockFile.check('stale-lock', opts, function (er, locked) {
|
||||
if (er) throw er
|
||||
t.notOk(locked)
|
||||
lockFile.lock('stale-lock', opts, function (er) {
|
||||
if (er) throw er
|
||||
lockFile.unlock('stale-lock', function (er) {
|
||||
if (er) throw er
|
||||
t.end()
|
||||
})
|
||||
})
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
test('staleness sync test', function (t) {
|
||||
var opts = { stale: 1 }
|
||||
lockFile.lockSync('stale-lock')
|
||||
// simulate 2s old
|
||||
touch.sync('stale-lock', { time: new Date(Date.now() - 2000) })
|
||||
var locked
|
||||
locked = lockFile.checkSync('stale-lock', opts)
|
||||
t.notOk(locked)
|
||||
lockFile.lockSync('stale-lock', opts)
|
||||
lockFile.unlockSync('stale-lock')
|
||||
t.end()
|
||||
})
|
||||
|
||||
test('retries', function (t) {
|
||||
// next 5 opens will fail.
|
||||
var opens = 5
|
||||
fs._open = fs.open
|
||||
fs.open = function (path, mode, cb) {
|
||||
if (--opens === 0) {
|
||||
fs.open = fs._open
|
||||
return fs.open(path, mode, cb)
|
||||
}
|
||||
var er = new Error('bogus')
|
||||
// to be, or not to be, that is the question.
|
||||
er.code = opens % 2 ? 'EEXIST' : 'ENOENT'
|
||||
process.nextTick(cb.bind(null, er))
|
||||
}
|
||||
|
||||
lockFile.lock('retry-lock', { retries: opens }, function (er) {
|
||||
if (er) throw er
|
||||
t.equal(opens, 0)
|
||||
lockFile.unlockSync('retry-lock')
|
||||
t.end()
|
||||
})
|
||||
})
|
||||
|
||||
test('retryWait', function (t) {
|
||||
// next 5 opens will fail.
|
||||
var opens = 5
|
||||
fs._open = fs.open
|
||||
fs.open = function (path, mode, cb) {
|
||||
if (--opens === 0) {
|
||||
fs.open = fs._open
|
||||
return fs.open(path, mode, cb)
|
||||
}
|
||||
var er = new Error('bogus')
|
||||
// to be, or not to be, that is the question.
|
||||
er.code = opens % 2 ? 'EEXIST' : 'ENOENT'
|
||||
process.nextTick(cb.bind(null, er))
|
||||
}
|
||||
|
||||
var opts = { retries: opens, retryWait: 100 }
|
||||
lockFile.lock('retry-lock', opts, function (er) {
|
||||
if (er) throw er
|
||||
t.equal(opens, 0)
|
||||
lockFile.unlockSync('retry-lock')
|
||||
t.end()
|
||||
})
|
||||
})
|
||||
|
||||
test('retry sync', function (t) {
|
||||
// next 5 opens will fail.
|
||||
var opens = 5
|
||||
fs._openSync = fs.openSync
|
||||
fs.openSync = function (path, mode) {
|
||||
if (--opens === 0) {
|
||||
fs.openSync = fs._openSync
|
||||
return fs.openSync(path, mode)
|
||||
}
|
||||
var er = new Error('bogus')
|
||||
// to be, or not to be, that is the question.
|
||||
er.code = opens % 2 ? 'EEXIST' : 'ENOENT'
|
||||
throw er
|
||||
}
|
||||
|
||||
var opts = { retries: opens }
|
||||
lockFile.lockSync('retry-lock', opts)
|
||||
t.equal(opens, 0)
|
||||
lockFile.unlockSync('retry-lock')
|
||||
t.end()
|
||||
})
|
||||
|
||||
test('wait and stale together', function (t) {
|
||||
// first locker.
|
||||
var interval
|
||||
lockFile.lock('stale-wait-lock', function(er) {
|
||||
// keep refreshing the lock, so we keep it forever
|
||||
interval = setInterval(function() {
|
||||
touch.sync('stale-wait-lock')
|
||||
}, 10)
|
||||
|
||||
// try to get another lock. this must fail!
|
||||
var opt = { stale: 1000, wait: 2000, pollInterval: 1000 }
|
||||
lockFile.lock('stale-wait-lock', opt, function (er) {
|
||||
if (!er)
|
||||
t.fail('got second lock? that unpossible!')
|
||||
else
|
||||
t.pass('second lock failed, as i have foreseen it')
|
||||
clearInterval(interval)
|
||||
t.end()
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
|
||||
test('stale windows file tunneling test', function (t) {
|
||||
// for windows only
|
||||
// nt file system tunneling feature will make file creation time not updated
|
||||
var opts = { stale: 1000 }
|
||||
lockFile.lockSync('stale-windows-lock')
|
||||
touch.sync('stale-windows-lock', { time: new Date(Date.now() - 3000) })
|
||||
|
||||
var locked
|
||||
lockFile.unlockSync('stale-windows-lock')
|
||||
lockFile.lockSync('stale-windows-lock', opts)
|
||||
locked = lockFile.checkSync('stale-windows-lock', opts)
|
||||
t.ok(locked, "should be locked and not stale")
|
||||
lockFile.lock('stale-windows-lock', opts, function (er) {
|
||||
if (!er)
|
||||
t.fail('got second lock? impossible, windows file tunneling problem!')
|
||||
else
|
||||
t.pass('second lock failed, windows file tunneling problem fixed')
|
||||
t.end()
|
||||
})
|
||||
})
|
||||
|
||||
|
||||
test('cleanup', function (t) {
|
||||
try { lockFile.unlockSync('basic-lock') } catch (er) {}
|
||||
try { lockFile.unlockSync('sync-lock') } catch (er) {}
|
||||
try { lockFile.unlockSync('never-forget') } catch (er) {}
|
||||
try { lockFile.unlockSync('stale-lock') } catch (er) {}
|
||||
try { lockFile.unlockSync('watch-lock') } catch (er) {}
|
||||
try { lockFile.unlockSync('retry-lock') } catch (er) {}
|
||||
try { lockFile.unlockSync('contentious-lock') } catch (er) {}
|
||||
try { lockFile.unlockSync('stale-wait-lock') } catch (er) {}
|
||||
try { lockFile.unlockSync('stale-windows-lock') } catch (er) {}
|
||||
t.end()
|
||||
})
|
||||
|
5
node_modules/lockfile/test/fixtures/bad-child.js
generated
vendored
Normal file
5
node_modules/lockfile/test/fixtures/bad-child.js
generated
vendored
Normal file
@ -0,0 +1,5 @@
|
||||
var lockFile = require('../../lockfile.js')
|
||||
|
||||
lockFile.lockSync('never-forget')
|
||||
|
||||
throw new Error('waaaaaaaaa')
|
3
node_modules/lockfile/test/fixtures/child.js
generated
vendored
Normal file
3
node_modules/lockfile/test/fixtures/child.js
generated
vendored
Normal file
@ -0,0 +1,3 @@
|
||||
var lockFile = require('../../lockfile.js')
|
||||
|
||||
lockFile.lock('never-forget', function () {})
|
68
node_modules/lockfile/test/retry-time.js
generated
vendored
Normal file
68
node_modules/lockfile/test/retry-time.js
generated
vendored
Normal file
@ -0,0 +1,68 @@
|
||||
// In these tests, we do the following:
|
||||
// try for 200ms (rt=2)
|
||||
// wait for 300ms
|
||||
// try for 200ms (rt=1)
|
||||
// wait for 300ms
|
||||
// try for 200ms (rt=0)
|
||||
// fail after 1200
|
||||
// Actual time will be more like 1220-ish for setTimeout irregularity
|
||||
// But it should NOT be as slow as 2000.
|
||||
|
||||
var lockFile = require('../')
|
||||
var touch = require('touch')
|
||||
var test = require('tap').test
|
||||
var fs = require('fs')
|
||||
|
||||
var RETRYWAIT = 100
|
||||
var WAIT = 100
|
||||
var RETRIES = 2
|
||||
var EXPECTTIME = (RETRYWAIT * RETRIES) + (WAIT * (RETRIES + 1))
|
||||
var TOOLONG = EXPECTTIME * 1.5
|
||||
|
||||
test('setup', function (t) {
|
||||
touch.sync('file.lock')
|
||||
t.end()
|
||||
})
|
||||
|
||||
var pollPeriods = [10, 100, 10000]
|
||||
pollPeriods.forEach(function (pp) {
|
||||
test('retry+wait, poll=' + pp, function (t) {
|
||||
var ended = false
|
||||
var timer = setTimeout(function() {
|
||||
t.fail('taking too long!')
|
||||
ended = true
|
||||
t.end()
|
||||
}, 2000)
|
||||
|
||||
if (timer.unref)
|
||||
timer.unref()
|
||||
|
||||
var start = Date.now()
|
||||
lockFile.lock('file.lock', {
|
||||
wait: WAIT,
|
||||
retries: RETRIES,
|
||||
retryWait: RETRYWAIT,
|
||||
pollPeriod: pp
|
||||
}, function (er) {
|
||||
if (ended) return
|
||||
var time = Date.now() - start
|
||||
console.error('t=%d', time)
|
||||
t.ok(time >= EXPECTTIME, 'should take at least ' + EXPECTTIME)
|
||||
t.ok(time < TOOLONG, 'should take less than ' + TOOLONG)
|
||||
clearTimeout(timer)
|
||||
t.end()
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
test('cleanup', function (t) {
|
||||
fs.unlinkSync('file.lock')
|
||||
t.end()
|
||||
var timer = setTimeout(function() {
|
||||
process.exit(1)
|
||||
}, 500)
|
||||
if (timer.unref)
|
||||
timer.unref()
|
||||
else
|
||||
clearTimeout(timer)
|
||||
})
|
85
node_modules/lockfile/test/stale-contention.js
generated
vendored
Normal file
85
node_modules/lockfile/test/stale-contention.js
generated
vendored
Normal file
@ -0,0 +1,85 @@
|
||||
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()
|
||||
})
|
10
node_modules/lockfile/test/unlock-no-cb.js
generated
vendored
Normal file
10
node_modules/lockfile/test/unlock-no-cb.js
generated
vendored
Normal file
@ -0,0 +1,10 @@
|
||||
var t = require('tap')
|
||||
if (/0\.(10|8)/.test(process.version)) {
|
||||
t.pass('just a dummy test, no beforeExit in this node version')
|
||||
} else {
|
||||
process.on('beforeExit', function (code) {
|
||||
t.equal(code, 0, 'did not throw')
|
||||
})
|
||||
}
|
||||
var lf = require('lockfile')
|
||||
lf.unlock('no-file-no-cb')
|
Reference in New Issue
Block a user