• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1var fs = require('fs')
2var lockFile = require('../')
3var test = require('tap').test
4var path = require('path')
5var lock = path.resolve(__dirname, 'stale.lock')
6var touch = require('touch')
7var spawn = require('child_process').spawn
8var node = process.execPath
9
10// We're using a lockfile with an artificially old date,
11// so make it use that instead of ctime.
12// Probably you should never do this in production!
13lockFile.filetime = 'mtime'
14
15if (process.argv[2] === 'child') {
16  return child()
17}
18
19function child () {
20  // Make fs.stat take 100ms to return its data
21  // This is important because, in a test scenario where
22  // we're statting the same exact file rapid-fire like this,
23  // it'll end up being cached by the FS, and never trigger
24  // the race condition we're trying to expose.
25  fs.stat = function (stat) { return function () {
26    var args = [].slice.call(arguments)
27    var cb = args.pop()
28    stat.apply(fs, args.concat(function(er, st) {
29      setTimeout(function () {
30        cb(er, st)
31      }, 100)
32    }))
33  }}(fs.stat)
34
35  lockFile.lock(lock, { stale: 100000 }, function (er) {
36    if (er && er.code !== 'EEXIST')
37      throw er
38    else if (er)
39      process.exit(17)
40    else
41      setTimeout(function(){}, 500)
42  })
43}
44
45test('create stale file', function (t) {
46  try { fs.unlinkSync(lock) } catch (er) {}
47  touch.sync(lock, { time: '1979-07-01T19:10:00.000Z' })
48  t.end()
49})
50
51test('contenders', function (t) {
52  var n = 10
53  var fails = 0
54  var wins = 0
55  var args = [ __filename, 'child' ]
56  var opt = { stdio: [0, "pipe", 2] }
57  for (var i = 0; i < n; i++) {
58    spawn(node, args, opt).on('close', then)
59  }
60
61  function then (code) {
62    if (code === 17) {
63      fails ++
64    } else if (code) {
65      t.fail("unexpected failure", code)
66      fails ++
67    } else {
68      wins ++
69    }
70    if (fails + wins === n) {
71      done()
72    }
73  }
74
75  function done () {
76    t.equal(wins, 1, "should have 1 lock winner")
77    t.equal(fails, n - 1, "all others should lose")
78    t.end()
79  }
80})
81
82test('remove stale file', function (t) {
83  try { fs.unlinkSync(lock) } catch (er) {}
84  t.end()
85})
86