mongodb-lock
Version:
Locks which uses MongoDB's atomic operations.
270 lines (210 loc) • 9.41 kB
JavaScript
// var async = require('async')
var test = require('tape')
var setup = require('./setup.js')
var mongoDbLock = require('../')
var codeRegexp = new RegExp(/^[0-9a-f]{32}$/)
setup(function(client, db) {
const col = db.collection('locks')
test("test ensureIndexes works fine", function(t) {
t.plan(3)
// the lock name in this case doesn't matter, since we're not going to acquire this one
var lock = mongoDbLock(col, 'whatever')
t.ok(lock, 'Lock object created ok')
lock.ensureIndexes(function(err, result) {
t.ok(!err, 'There was no error when ensuring the indexes')
t.ok(result.ok, 'Index creation was okay')
})
})
test("test that the lock can't be acquired twice", function(t) {
t.plan(5)
var lock = mongoDbLock(col, 'thisLock')
t.ok(lock, 'Lock object created ok')
lock.acquire(function(err, code) {
t.ok(!err, 'There was no error when acquring the lock')
t.ok(code.match(codeRegexp), 'The lock code returned matches the code regexp')
// see if we can get this lock again
lock.acquire(function(err, code) {
t.ok(!err, 'There was no error trying to lock again (even though it is already locked)')
t.ok(!code, 'However, no code was returned since the lock was not acquired')
})
})
})
test("test that the lock can't be acquired twice", function(t) {
t.plan(5)
var lock = mongoDbLock(col, 'another-lock')
t.ok(lock, 'Lock object created ok')
lock.acquire(function(err, code) {
t.ok(!err, 'There was no error when acquring the lock')
t.ok(code.match(codeRegexp), 'The lock code returned matches the code regexp')
// see if we can get this lock again
lock.acquire(function(err, code) {
t.ok(!err, 'There was no error trying to lock again (even though it is already locked)')
t.ok(!code, 'However, no code was returned since the lock was not acquired')
})
})
})
test("test that two locks are fine to acquire together", function(t) {
t.plan(4)
var lock1 = mongoDbLock(col, 'lock-1')
var lock2 = mongoDbLock(col, 'lock-2')
lock1.acquire(function(err, code) {
t.ok(!err, '1. There was no error when acquring the lock')
t.ok(code.match(codeRegexp), '1. The lock code returned matches the code regexp')
})
lock2.acquire(function(err, code) {
t.ok(!err, '2. There was no error when acquring the lock')
t.ok(code.match(codeRegexp), '2. The lock code returned matches the code regexp')
})
})
test("test that a 3s lock is released automatically", function(t) {
t.plan(5)
var threeSecs = 3 * 1000
var lock = mongoDbLock(col, 'three-secs', { timeout : threeSecs })
lock.acquire(function(err, code1) {
t.ok(!err, '1. There was no error when acquring the lock')
t.ok(code1.match(codeRegexp), '1. The lock code returned matches the code regexp')
setTimeout(function() {
lock.acquire(function(err, code2) {
t.ok(!err, '2. There was no error when acquring the lock')
t.ok(code2.match(codeRegexp), '2. The lock code returned matches the code regexp')
t.ok(code1 !== code2, '2. The 2nd code generated is different from the first')
})
}, threeSecs + 100)
})
})
test("test that a 3s lock can be released and then re-acquired", function(t) {
t.plan(7)
var threeSecs = 3 * 1000
var lock = mongoDbLock(col, 'release-me', { timeout : threeSecs })
lock.acquire(function(err, code1) {
t.ok(!err, '1. There was no error when acquring the lock')
t.ok(code1.match(codeRegexp), '1. The lock code returned matches the code regexp')
lock.release(code1, function(err, ok) {
t.ok(!err, 'No error when releasing this lock')
t.ok(ok, 'The lock was released correctly')
// re-acquire this lock since it has been released
lock.acquire(function(err, code2) {
t.ok(!err, '2. There was no error when acquring the lock')
t.ok(code2.match(codeRegexp), '2. The lock code returned matches the code regexp')
t.ok(code1 !== code2, '2. The 2nd code generated is different from the first')
})
})
})
})
test("test that a lock will fail a 2nd .release()", function(t) {
t.plan(6)
var lock = mongoDbLock(col, 'double-release')
lock.acquire(function(err, code) {
t.ok(!err, '1. There was no error when acquring the lock')
t.ok(code.match(codeRegexp), '1. The lock code returned matches the code regexp')
lock.release(code, function(err, ok) {
t.ok(!err, 'No error when releasing this lock')
t.ok(ok, 'The lock was released correctly')
lock.release(code, function(err, ok) {
t.ok(!err, 'No error when releasing this lock')
t.ok(!ok, "The lock was not released (since it wasn't actually acquired")
})
})
})
})
test("test that when a 3s is released automatically, the release fails properly", function(t) {
t.plan(4)
var threeSecs = 3 * 1000
var lock = mongoDbLock(col, 'bad-release', { timeout : threeSecs })
lock.acquire(function(err, code) {
t.ok(!err, 'There was no error when acquring the lock')
t.ok(code.match(codeRegexp), 'The lock code returned matches the code regexp')
setTimeout(function() {
lock.release(code, function(err, ok) {
t.ok(!err, 'There was no error releasing the expired lock, ie. the operation succeeded')
t.ok(!ok, 'The lock was not released (as expected)')
})
}, threeSecs + 100)
})
})
test("test that when removeExpired is false, released locks are not deleted from MongoDB", function(t) {
t.plan(6)
var lock = mongoDbLock(col, 'modify-expired-on-release')
lock.acquire(function(err, code) {
t.ok(!err, 'There was no error when acquring the lock')
t.ok(code.match(codeRegexp), 'The lock code returned matches the code regexp')
lock.release(code, function(err, ok) {
t.ok(!err, 'There was no error releasing the expired lock, ie. the operation succeeded')
t.ok(ok, 'The lock was released')
db.collection('locks').countDocuments({ code: code }, function(err, count) {
t.ok(!err, 'There was no error reading record count from MongoDB')
t.equal(count, 1, 'The record has not been removed after release')
})
})
})
})
test("test that when removeExpired is false, timed out locks are not removed", function(t) {
t.plan(5)
var lockTimeout = 3000;
var lockOptions = {
timeout: lockTimeout
}
var lock = mongoDbLock(col, 'modify-expired-on-release')
lock.acquire(function(err, code) {
t.ok(!err, 'There was no error when acquring the lock')
t.ok(code.match(codeRegexp), 'The lock code returned matches the code regexp')
setTimeout(function() {
lock.acquire(function(err, newCode) {
t.ok(!err, 'There was no error releasing the expired lock')
// Now check that the expired record has been removed
db.collection('locks').countDocuments({ code: code }, function(err, count) {
t.ok(!err, 'There was no error reading record count from MongoDB')
t.equal(count, 1, 'The record has not been removed after release')
})
})
}, lockTimeout + 100);
})
})
test("test that when removeExpired is true, released locks are deleted from MongoDB", function(t) {
t.plan(6)
var lockOptions = {
removeExpired: true
}
var lock = mongoDbLock(col, 'remove-expired-on-release', lockOptions)
lock.acquire(function(err, code) {
t.ok(!err, 'There was no error when acquring the lock')
t.ok(code.match(codeRegexp), 'The lock code returned matches the code regexp')
lock.release(code, function(err, ok) {
t.ok(!err, 'There was no error releasing the expired lock, ie. the operation succeeded')
t.ok(ok, 'The lock was released')
db.collection('locks').countDocuments({ code: code }, function(err, count) {
t.ok(!err, 'There was no error reading record count from MongoDB')
t.equal(count, 0, 'The record had been removed after release')
})
})
})
})
test("test that when removeExpired is true, timed out locks are deleted from MongoDB", function(t) {
t.plan(5)
var lockTimeout = 3000;
var lockOptions = {
removeExpired: true,
timeout: lockTimeout
}
var lock = mongoDbLock(col, 'remove-expired-on-timeout', lockOptions)
lock.acquire(function(err, code) {
t.ok(!err, 'There was no error when acquring the lock')
t.ok(code.match(codeRegexp), 'The lock code returned matches the code regexp')
setTimeout(function() {
lock.acquire(function(err, newCode) {
t.ok(!err, 'There was no error releasing the expired lock')
// Now check that the expired record has been removed
db.collection('locks').count({ code: code }, function(err, count) {
t.ok(!err, 'There was no error reading record count from MongoDB')
t.equal(count, 0, 'The record had been removed after release')
})
})
}, lockTimeout + 100);
})
})
test('client.close()', function(t) {
t.pass('client.close()')
client.close()
t.end()
})
})