overleaf/services/web/test/unit/src/ThirdPartyDataStore/TpdsProjectFlusherTests.js
Alf Eaton 1be43911b4 Merge pull request #3942 from overleaf/prettier-trailing-comma
Set Prettier's "trailingComma" setting to "es5"

GitOrigin-RevId: 9f14150511929a855b27467ad17be6ab262fe5d5
2021-04-28 02:10:01 +00:00

238 lines
7.1 KiB
JavaScript

const { expect } = require('chai')
const sinon = require('sinon')
const SandboxedModule = require('sandboxed-module')
const { ObjectId } = require('mongodb')
const { Project } = require('../helpers/models/Project')
const MODULE_PATH =
'../../../../app/src/Features/ThirdPartyDataStore/TpdsProjectFlusher'
describe('TpdsProjectFlusher', function () {
beforeEach(function () {
this.project = { _id: ObjectId() }
this.docs = {
'/doc/one': { _id: 'mock-doc-1', lines: ['one'], rev: 5 },
'/doc/two': { _id: 'mock-doc-2', lines: ['two'], rev: 6 },
}
this.files = {
'/file/one': { _id: 'mock-file-1', rev: 7 },
'/file/two': { _id: 'mock-file-2', rev: 8 },
}
this.DocumentUpdaterHandler = {
promises: {
flushProjectToMongo: sinon.stub().resolves(),
},
}
this.ProjectGetter = {
promises: {
getProject: sinon.stub().resolves(this.project),
},
}
this.ProjectEntityHandler = {
promises: {
getAllDocs: sinon.stub().withArgs(this.project._id).resolves(this.docs),
getAllFiles: sinon
.stub()
.withArgs(this.project._id)
.resolves(this.files),
},
}
this.TpdsUpdateSender = {
promises: {
addDoc: sinon.stub().resolves(),
addFile: sinon.stub().resolves(),
},
}
this.ProjectMock = sinon.mock(Project)
this.TpdsProjectFlusher = SandboxedModule.require(MODULE_PATH, {
requires: {
'../DocumentUpdater/DocumentUpdaterHandler': this
.DocumentUpdaterHandler,
'../Project/ProjectGetter': this.ProjectGetter,
'../Project/ProjectEntityHandler': this.ProjectEntityHandler,
'../../models/Project': { Project },
'./TpdsUpdateSender': this.TpdsUpdateSender,
},
})
})
afterEach(function () {
this.ProjectMock.restore()
})
describe('flushProjectToTpds', function () {
describe('usually', function () {
beforeEach(async function () {
await this.TpdsProjectFlusher.promises.flushProjectToTpds(
this.project._id
)
})
it('should flush the project from the doc updater', function () {
expect(
this.DocumentUpdaterHandler.promises.flushProjectToMongo
).to.have.been.calledWith(this.project._id)
})
it('should flush each doc to the TPDS', function () {
for (const [path, doc] of Object.entries(this.docs)) {
expect(this.TpdsUpdateSender.promises.addDoc).to.have.been.calledWith(
{
project_id: this.project._id,
doc_id: doc._id,
project_name: this.project.name,
rev: doc.rev,
path,
}
)
}
})
it('should flush each file to the TPDS', function () {
for (const [path, file] of Object.entries(this.files)) {
expect(
this.TpdsUpdateSender.promises.addFile
).to.have.been.calledWith({
project_id: this.project._id,
file_id: file._id,
project_name: this.project.name,
rev: file.rev,
path,
})
}
})
})
describe('when a TPDS flush is pending', function () {
beforeEach(async function () {
this.project.deferredTpdsFlushCounter = 2
this.ProjectMock.expects('updateOne')
.withArgs(
{
_id: this.project._id,
deferredTpdsFlushCounter: { $lte: 2 },
},
{ $set: { deferredTpdsFlushCounter: 0 } }
)
.chain('exec')
.resolves()
await this.TpdsProjectFlusher.promises.flushProjectToTpds(
this.project._id
)
})
it('resets the deferred flush counter', function () {
this.ProjectMock.verify()
})
})
})
describe('deferProjectFlushToTpds', function () {
beforeEach(async function () {
this.ProjectMock.expects('updateOne')
.withArgs(
{
_id: this.project._id,
},
{ $inc: { deferredTpdsFlushCounter: 1 } }
)
.chain('exec')
.resolves()
await this.TpdsProjectFlusher.promises.deferProjectFlushToTpds(
this.project._id
)
})
it('increments the deferred flush counter', function () {
this.ProjectMock.verify()
})
})
describe('flushProjectToTpdsIfNeeded', function () {
let cases = [0, undefined]
cases.forEach(counterValue => {
describe(`when the deferred flush counter is ${counterValue}`, function () {
beforeEach(async function () {
this.project.deferredTpdsFlushCounter = counterValue
await this.TpdsProjectFlusher.promises.flushProjectToTpdsIfNeeded(
this.project._id
)
})
it("doesn't flush the project from the doc updater", function () {
expect(this.DocumentUpdaterHandler.promises.flushProjectToMongo).not
.to.have.been.called
})
it("doesn't flush any doc", function () {
expect(this.TpdsUpdateSender.promises.addDoc).not.to.have.been.called
})
it("doesn't flush any file", function () {
expect(this.TpdsUpdateSender.promises.addFile).not.to.have.been.called
})
})
})
cases = [1, 2]
cases.forEach(counterValue => {
describe(`when the deferred flush counter is ${counterValue}`, function () {
beforeEach(async function () {
this.project.deferredTpdsFlushCounter = counterValue
this.ProjectMock.expects('updateOne')
.withArgs(
{
_id: this.project._id,
deferredTpdsFlushCounter: { $lte: counterValue },
},
{ $set: { deferredTpdsFlushCounter: 0 } }
)
.chain('exec')
.resolves()
await this.TpdsProjectFlusher.promises.flushProjectToTpdsIfNeeded(
this.project._id
)
})
it('flushes the project from the doc updater', function () {
expect(
this.DocumentUpdaterHandler.promises.flushProjectToMongo
).to.have.been.calledWith(this.project._id)
})
it('flushes each doc to the TPDS', function () {
for (const [path, doc] of Object.entries(this.docs)) {
expect(
this.TpdsUpdateSender.promises.addDoc
).to.have.been.calledWith({
project_id: this.project._id,
doc_id: doc._id,
project_name: this.project.name,
rev: doc.rev,
path,
})
}
})
it('flushes each file to the TPDS', function () {
for (const [path, file] of Object.entries(this.files)) {
expect(
this.TpdsUpdateSender.promises.addFile
).to.have.been.calledWith({
project_id: this.project._id,
file_id: file._id,
project_name: this.project.name,
rev: file.rev,
path,
})
}
})
it('resets the deferred flush counter', function () {
this.ProjectMock.verify()
})
})
})
})
})