| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110 |
- sinon = require('sinon')
- chai = require('chai')
- should = chai.should()
- path = require('path')
- modulePath = path.join __dirname, '../../../../../app/js/infrastructure/LockManager.js'
- SandboxedModule = require('sandboxed-module')
- describe 'LockManager - getting the lock', ->
- beforeEach ->
- @LockManager = SandboxedModule.require modulePath, requires:
- "logger-sharelatex": log:->
- "./RedisWrapper":
- client: ()->
- auth:->
- "settings-sharelatex":{redis:{}}
- "metrics-sharelatex":
- inc:->
- gauge:->
- @callback = sinon.stub()
- @key = "lock:web:lockName:project-id}"
- @namespace = 'lockName'
- describe "when the lock is not set", ->
- beforeEach (done) ->
- @LockManager._tryLock = sinon.stub().yields(null, true)
- @LockManager._getLock @key, @namespace, (args...) =>
- @callback(args...)
- done()
- it "should try to get the lock", ->
- @LockManager._tryLock
- .calledWith(@key, @namespace)
- .should.equal true
- it "should only need to try once", ->
- @LockManager._tryLock.callCount.should.equal 1
- it "should return the callback", ->
- @callback.calledWith(null).should.equal true
- describe "when the lock is initially set", ->
- beforeEach (done) ->
- startTime = Date.now()
- tries = 0
- @LockManager.LOCK_TEST_INTERVAL = 5
- @LockManager._tryLock = (key, namespace, callback = (error, isFree) ->) ->
- if (Date.now() - startTime < 20) or (tries < 2)
- tries = tries + 1
- callback null, false
- else
- callback null, true
- sinon.spy @LockManager, "_tryLock"
- @LockManager._getLock @key, @namespace, (args...) =>
- @callback(args...)
- done()
- it "should call tryLock multiple times until free", ->
- (@LockManager._tryLock.callCount > 1).should.equal true
- it "should return the callback", ->
- @callback.calledWith(null).should.equal true
- describe "when the lock times out", ->
- beforeEach (done) ->
- time = Date.now()
- @LockManager.MAX_LOCK_WAIT_TIME = 5
- @LockManager._tryLock = sinon.stub().yields(null, false)
- @LockManager._getLock @key, @namespace, (args...) =>
- @callback(args...)
- done()
- it "should return the callback with an error", ->
- @callback.calledWith(new Error("timeout")).should.equal true
- describe "when there are multiple requests for the same lock", ->
- beforeEach (done) ->
- locked = false
- @results = []
- @LockManager.LOCK_TEST_INTERVAL = 1
- @LockManager._tryLock = (key, namespace, callback = (error, gotLock, lockValue) ->) ->
- if locked
- callback null, false
- else
- locked = true # simulate getting the lock
- callback null, true
- # Start ten lock requests in order at 1ms 2ms 3ms...
- # with them randomly holding the lock for 0-100ms.
- # Use predefined values for the random delay to make the test
- # deterministic.
- randomDelays = [52, 45, 41, 84, 60, 81, 31, 46, 9, 43 ]
- startTime = 0
- for randomDelay, i in randomDelays
- do (randomDelay, i) =>
- startTime += 1
- setTimeout () =>
- # changing the next line to the old method of LockManager._getLockByPolling
- # should give results in a random order and cause the test to fail.
- @LockManager._getLock @key, @namespace, (args...) =>
- setTimeout () ->
- locked = false # release the lock after a random amount of time
- , randomDelay
- @results.push i
- if @results.length is 10
- done()
- , startTime
- it "should process the requests in order", ->
- @results.should.deep.equal [0,1,2,3,4,5,6,7,8,9]
|