2022-07-07 12:27:20 +00:00
|
|
|
const { expect } = require('chai')
|
2020-02-19 11:15:37 +00:00
|
|
|
const sinon = require('sinon')
|
2022-07-07 12:27:20 +00:00
|
|
|
const mockFs = require('mock-fs')
|
|
|
|
const OError = require('@overleaf/o-error')
|
|
|
|
const LockManager = require('../../../app/js/LockManager')
|
2020-02-19 11:15:37 +00:00
|
|
|
const Errors = require('../../../app/js/Errors')
|
2020-02-19 11:15:08 +00:00
|
|
|
|
2022-07-07 12:27:20 +00:00
|
|
|
describe('LockManager', function () {
|
2020-08-10 16:01:11 +00:00
|
|
|
beforeEach(function () {
|
2022-07-07 12:27:20 +00:00
|
|
|
this.lockFile = '/local/compile/directory/.project-lock'
|
|
|
|
mockFs({
|
|
|
|
'/local/compile/directory': {},
|
2020-02-19 11:15:37 +00:00
|
|
|
})
|
2022-07-07 12:27:20 +00:00
|
|
|
this.clock = sinon.useFakeTimers()
|
2020-02-19 11:15:37 +00:00
|
|
|
})
|
2020-02-19 11:15:08 +00:00
|
|
|
|
2022-07-07 12:27:20 +00:00
|
|
|
afterEach(function () {
|
|
|
|
mockFs.restore()
|
|
|
|
this.clock.restore()
|
|
|
|
})
|
2020-02-19 11:15:08 +00:00
|
|
|
|
2022-07-07 12:27:20 +00:00
|
|
|
describe('when the lock is available', function () {
|
|
|
|
it('the lock can be acquired', async function () {
|
|
|
|
await LockManager.acquire(this.lockFile)
|
|
|
|
})
|
2020-02-19 11:15:08 +00:00
|
|
|
|
2022-07-07 12:27:20 +00:00
|
|
|
it('acquiring a lock in a nonexistent directory throws an error with debug info', async function () {
|
|
|
|
const err = await expect(
|
|
|
|
LockManager.acquire('/invalid/path/.project-lock')
|
|
|
|
).to.be.rejected
|
|
|
|
const info = OError.getFullInfo(err)
|
|
|
|
expect(info).to.have.keys(['statLock', 'statDir', 'readdirDir'])
|
|
|
|
expect(info.statLock.code).to.equal('ENOENT')
|
|
|
|
expect(info.statDir.code).to.equal('ENOENT')
|
|
|
|
expect(info.readdirDir.code).to.equal('ENOENT')
|
|
|
|
})
|
|
|
|
})
|
2017-09-22 15:19:33 +00:00
|
|
|
|
2022-07-07 12:27:20 +00:00
|
|
|
describe('after the lock is acquired', function () {
|
|
|
|
beforeEach(async function () {
|
|
|
|
this.lock = await LockManager.acquire(this.lockFile)
|
2020-02-19 11:15:37 +00:00
|
|
|
})
|
2020-02-19 11:15:08 +00:00
|
|
|
|
2022-07-07 12:27:20 +00:00
|
|
|
it("the lock can't be acquired again", function (done) {
|
|
|
|
const promise = LockManager.acquire(this.lockFile)
|
|
|
|
// runAllAsync() will advance through time until there are no pending
|
|
|
|
// timers or promises. It interferes with Mocha's promise interface, so
|
|
|
|
// we use Mocha's callback interface for this test.
|
|
|
|
this.clock.runAllAsync()
|
|
|
|
expect(promise)
|
|
|
|
.to.be.rejectedWith(Errors.AlreadyCompilingError)
|
|
|
|
.then(() => {
|
|
|
|
done()
|
|
|
|
})
|
|
|
|
.catch(err => {
|
|
|
|
done(err)
|
|
|
|
})
|
|
|
|
})
|
2020-02-19 11:15:08 +00:00
|
|
|
|
2022-07-07 12:27:20 +00:00
|
|
|
it('the lock can be acquired again after an expiry period', async function () {
|
|
|
|
// The expiry time is 5 minutes. Let's wait 10 minutes.
|
|
|
|
this.clock.tick(10 * 60 * 1000)
|
|
|
|
await LockManager.acquire(this.lockFile)
|
|
|
|
})
|
2017-09-22 15:19:33 +00:00
|
|
|
|
2022-07-07 12:27:20 +00:00
|
|
|
it('the lock can be acquired again after it was released', async function () {
|
|
|
|
this.lock.release()
|
|
|
|
await LockManager.acquire(this.lockFile)
|
2020-02-19 11:15:37 +00:00
|
|
|
})
|
|
|
|
})
|
|
|
|
})
|