|
|
@@ -1,12 +1,28 @@
|
|
|
const { expect } = require('chai')
|
|
|
const sinon = require('sinon')
|
|
|
-const LockManager = require('../../../app/js/LockManager')
|
|
|
+const SandboxedModule = require('sandboxed-module')
|
|
|
+const modulePath = require('path').join(
|
|
|
+ __dirname,
|
|
|
+ '../../../app/js/LockManager'
|
|
|
+)
|
|
|
const Errors = require('../../../app/js/Errors')
|
|
|
|
|
|
describe('LockManager', function () {
|
|
|
beforeEach(function () {
|
|
|
this.key = '/local/compile/directory'
|
|
|
this.clock = sinon.useFakeTimers()
|
|
|
+ this.LockManager = SandboxedModule.require(modulePath, {
|
|
|
+ requires: {
|
|
|
+ '@overleaf/metrics': (this.Metrics = {
|
|
|
+ inc: sinon.stub(),
|
|
|
+ gauge: sinon.stub(),
|
|
|
+ }),
|
|
|
+ '@overleaf/settings': (this.Settings = {
|
|
|
+ compileConcurrencyLimit: 5,
|
|
|
+ }),
|
|
|
+ './Errors': (this.Erros = Errors),
|
|
|
+ },
|
|
|
+ })
|
|
|
})
|
|
|
|
|
|
afterEach(function () {
|
|
|
@@ -15,7 +31,7 @@ describe('LockManager', function () {
|
|
|
|
|
|
describe('when the lock is available', function () {
|
|
|
it('the lock can be acquired', function () {
|
|
|
- const lock = LockManager.acquire(this.key)
|
|
|
+ const lock = this.LockManager.acquire(this.key)
|
|
|
expect(lock).to.exist
|
|
|
lock.release()
|
|
|
})
|
|
|
@@ -23,7 +39,7 @@ describe('LockManager', function () {
|
|
|
|
|
|
describe('after the lock is acquired', function () {
|
|
|
beforeEach(function () {
|
|
|
- this.lock = LockManager.acquire(this.key)
|
|
|
+ this.lock = this.LockManager.acquire(this.key)
|
|
|
})
|
|
|
|
|
|
afterEach(function () {
|
|
|
@@ -33,13 +49,13 @@ describe('LockManager', function () {
|
|
|
})
|
|
|
|
|
|
it("the lock can't be acquired again", function () {
|
|
|
- expect(() => LockManager.acquire(this.key)).to.throw(
|
|
|
+ expect(() => this.LockManager.acquire(this.key)).to.throw(
|
|
|
Errors.AlreadyCompilingError
|
|
|
)
|
|
|
})
|
|
|
|
|
|
it('another lock can be acquired', function () {
|
|
|
- const lock = LockManager.acquire('another key')
|
|
|
+ const lock = this.LockManager.acquire('another key')
|
|
|
expect(lock).to.exist
|
|
|
lock.release()
|
|
|
})
|
|
|
@@ -47,14 +63,68 @@ describe('LockManager', function () {
|
|
|
it('the lock can be acquired again after an expiry period', function () {
|
|
|
// The expiry time is a little bit over 10 minutes. Let's wait 15 minutes.
|
|
|
this.clock.tick(15 * 60 * 1000)
|
|
|
- this.lock = LockManager.acquire(this.key)
|
|
|
+ this.lock = this.LockManager.acquire(this.key)
|
|
|
expect(this.lock).to.exist
|
|
|
})
|
|
|
|
|
|
it('the lock can be acquired again after it was released', function () {
|
|
|
this.lock.release()
|
|
|
- this.lock = LockManager.acquire(this.key)
|
|
|
+ this.lock = this.LockManager.acquire(this.key)
|
|
|
expect(this.lock).to.exist
|
|
|
})
|
|
|
})
|
|
|
+
|
|
|
+ describe('concurrency limit', function () {
|
|
|
+ it('dry run', function () {
|
|
|
+ for (let i = 0; i <= this.Settings.compileConcurrencyLimit; i++) {
|
|
|
+ this.LockManager.acquire('test_key' + i)
|
|
|
+ }
|
|
|
+ this.Metrics.inc
|
|
|
+ .calledWith('exceeded-compilier-concurrency-limit')
|
|
|
+ .should.equal(false)
|
|
|
+ this.LockManager.acquire(
|
|
|
+ 'test_key_' + (this.Settings.compileConcurrencyLimit + 1)
|
|
|
+ )
|
|
|
+ this.Metrics.inc
|
|
|
+ .calledWith('exceeded-compilier-concurrency-limit')
|
|
|
+ .should.equal(true)
|
|
|
+ })
|
|
|
+
|
|
|
+ it('exceeding the limit', function () {
|
|
|
+ for (let i = 0; i <= this.Settings.compileConcurrencyLimit; i++) {
|
|
|
+ this.LockManager.acquire('test_key' + i, false)
|
|
|
+ }
|
|
|
+ this.Metrics.inc
|
|
|
+ .calledWith('exceeded-compilier-concurrency-limit')
|
|
|
+ .should.equal(false)
|
|
|
+ expect(() =>
|
|
|
+ this.LockManager.acquire(
|
|
|
+ 'test_key_' + (this.Settings.compileConcurrencyLimit + 1),
|
|
|
+ false
|
|
|
+ )
|
|
|
+ ).to.throw(Errors.TooManyCompileRequestsError)
|
|
|
+
|
|
|
+ this.Metrics.inc
|
|
|
+ .calledWith('exceeded-compilier-concurrency-limit')
|
|
|
+ .should.equal(true)
|
|
|
+ })
|
|
|
+
|
|
|
+ it('within the limit', function () {
|
|
|
+ for (let i = 0; i <= this.Settings.compileConcurrencyLimit - 1; i++) {
|
|
|
+ this.LockManager.acquire('test_key' + i, false)
|
|
|
+ }
|
|
|
+ this.Metrics.inc
|
|
|
+ .calledWith('exceeded-compilier-concurrency-limit')
|
|
|
+ .should.equal(false)
|
|
|
+
|
|
|
+ const lock = this.LockManager.acquire(
|
|
|
+ 'test_key_' + this.Settings.compileConcurrencyLimit,
|
|
|
+ false
|
|
|
+ )
|
|
|
+
|
|
|
+ expect(lock.key).to.equal(
|
|
|
+ 'test_key_' + this.Settings.compileConcurrencyLimit
|
|
|
+ )
|
|
|
+ })
|
|
|
+ })
|
|
|
})
|