mirror of
https://github.com/yu-i-i/overleaf-cep.git
synced 2026-05-23 09:09:36 +02:00
125 lines
3.3 KiB
JavaScript
125 lines
3.3 KiB
JavaScript
import { vi, expect, describe, beforeEach, afterEach, it } from 'vitest'
|
|
import sinon from 'sinon'
|
|
import * as Errors from '../../../app/js/Errors.js'
|
|
import path from 'node:path'
|
|
|
|
const modulePath = path.join(import.meta.dirname, '../../../app/js/LockManager')
|
|
|
|
describe('LockManager', () => {
|
|
beforeEach(async ctx => {
|
|
ctx.key = '/local/compile/directory'
|
|
ctx.clock = sinon.useFakeTimers()
|
|
|
|
vi.doMock('@overleaf/metrics', () => ({
|
|
default: (ctx.Metrics = {
|
|
inc: sinon.stub(),
|
|
gauge: sinon.stub(),
|
|
}),
|
|
}))
|
|
|
|
vi.doMock('@overleaf/settings', () => ({
|
|
default: (ctx.Settings = {
|
|
compileConcurrencyLimit: 5,
|
|
}),
|
|
}))
|
|
|
|
vi.doMock('../../../app/js/Errors', () => ({
|
|
default: (ctx.Erros = Errors),
|
|
}))
|
|
|
|
vi.doMock('../../../app/js/RequestParser', () => ({
|
|
default: { MAX_TIMEOUT: 600 },
|
|
}))
|
|
|
|
ctx.LockManager = (await import(modulePath)).default
|
|
})
|
|
|
|
afterEach(ctx => {
|
|
ctx.clock.restore()
|
|
})
|
|
|
|
describe('when the lock is available', () => {
|
|
it('the lock can be acquired', ctx => {
|
|
const lock = ctx.LockManager.acquire(ctx.key)
|
|
expect(lock).to.exist
|
|
lock.release()
|
|
})
|
|
})
|
|
|
|
describe('after the lock is acquired', () => {
|
|
beforeEach(ctx => {
|
|
ctx.lock = ctx.LockManager.acquire(ctx.key)
|
|
})
|
|
|
|
afterEach(ctx => {
|
|
if (ctx.lock != null) {
|
|
ctx.lock.release()
|
|
}
|
|
})
|
|
|
|
it("the lock can't be acquired again", ctx => {
|
|
expect(() => ctx.LockManager.acquire(ctx.key)).to.throw(
|
|
Errors.AlreadyCompilingError
|
|
)
|
|
})
|
|
|
|
it('another lock can be acquired', ctx => {
|
|
const lock = ctx.LockManager.acquire('another key')
|
|
expect(lock).to.exist
|
|
lock.release()
|
|
})
|
|
|
|
it('the lock can be acquired again after an expiry period', ctx => {
|
|
// The expiry time is a little bit over 10 minutes. Let's wait 15 minutes.
|
|
ctx.clock.tick(15 * 60 * 1000)
|
|
ctx.lock = ctx.LockManager.acquire(ctx.key)
|
|
expect(ctx.lock).to.exist
|
|
})
|
|
|
|
it('the lock can be acquired again after it was released', ctx => {
|
|
ctx.lock.release()
|
|
ctx.lock = ctx.LockManager.acquire(ctx.key)
|
|
expect(ctx.lock).to.exist
|
|
})
|
|
})
|
|
|
|
describe('concurrency limit', () => {
|
|
it('exceeding the limit', ctx => {
|
|
for (let i = 0; i <= ctx.Settings.compileConcurrencyLimit; i++) {
|
|
ctx.LockManager.acquire('test_key' + i)
|
|
}
|
|
ctx.Metrics.inc
|
|
.calledWith('exceeded-compilier-concurrency-limit')
|
|
.should.equal(false)
|
|
expect(() =>
|
|
ctx.LockManager.acquire(
|
|
'test_key_' + (ctx.Settings.compileConcurrencyLimit + 1),
|
|
false
|
|
)
|
|
).to.throw(Errors.TooManyCompileRequestsError)
|
|
|
|
ctx.Metrics.inc
|
|
.calledWith('exceeded-compilier-concurrency-limit')
|
|
.should.equal(true)
|
|
})
|
|
|
|
it('within the limit', ctx => {
|
|
for (let i = 0; i <= ctx.Settings.compileConcurrencyLimit - 1; i++) {
|
|
ctx.LockManager.acquire('test_key' + i)
|
|
}
|
|
ctx.Metrics.inc
|
|
.calledWith('exceeded-compilier-concurrency-limit')
|
|
.should.equal(false)
|
|
|
|
const lock = ctx.LockManager.acquire(
|
|
'test_key_' + ctx.Settings.compileConcurrencyLimit,
|
|
false
|
|
)
|
|
|
|
expect(lock.key).to.equal(
|
|
'test_key_' + ctx.Settings.compileConcurrencyLimit
|
|
)
|
|
})
|
|
})
|
|
})
|