2019-05-29 05:21:06 -04:00
|
|
|
const SandboxedModule = require('sandboxed-module')
|
|
|
|
const sinon = require('sinon')
|
2022-09-07 06:28:42 -04:00
|
|
|
const { expect } = require('chai')
|
2023-06-01 07:38:45 -04:00
|
|
|
const { Writable } = require('stream')
|
2022-09-12 10:59:16 -04:00
|
|
|
const { ObjectId } = require('mongodb')
|
2019-05-29 05:21:06 -04:00
|
|
|
|
2022-09-07 06:28:42 -04:00
|
|
|
const MODULE_PATH =
|
|
|
|
'../../../../app/src/Features/ThirdPartyDataStore/UpdateMerger.js'
|
|
|
|
|
2021-04-14 09:17:21 -04:00
|
|
|
describe('UpdateMerger :', function () {
|
|
|
|
beforeEach(function () {
|
2022-09-07 06:28:42 -04:00
|
|
|
this.projectId = 'project_id_here'
|
|
|
|
this.userId = 'mock-user-id'
|
2023-08-02 09:01:36 -04:00
|
|
|
this.randomUUID = 'random-uuid'
|
|
|
|
this.dumpPath = '/dump'
|
2019-05-29 05:21:06 -04:00
|
|
|
|
|
|
|
this.docPath = this.newDocPath = '/folder/doc.tex'
|
|
|
|
this.filePath = this.newFilePath = '/folder/file.png'
|
|
|
|
|
|
|
|
this.existingDocPath = '/folder/other.tex'
|
|
|
|
this.existingFilePath = '/folder/fig1.pdf'
|
|
|
|
|
|
|
|
this.linkedFileData = { provider: 'url' }
|
|
|
|
|
|
|
|
this.existingDocs = [{ path: '/main.tex' }, { path: '/folder/other.tex' }]
|
|
|
|
this.existingFiles = [{ path: '/figure.pdf' }, { path: '/folder/fig1.pdf' }]
|
|
|
|
|
2023-08-02 09:01:36 -04:00
|
|
|
this.fsPath = `${this.dumpPath}/${this.projectId}_${this.randomUUID}`
|
2022-09-07 06:28:42 -04:00
|
|
|
this.fileContents = `\\documentclass{article}
|
|
|
|
\\usepackage[utf8]{inputenc}
|
|
|
|
|
|
|
|
\\title{42}
|
|
|
|
\\author{Jane Doe}
|
|
|
|
\\date{June 2011}`
|
|
|
|
this.docLines = this.fileContents.split('\n')
|
2019-05-29 05:21:06 -04:00
|
|
|
this.source = 'dropbox'
|
2023-06-01 07:38:45 -04:00
|
|
|
this.updateRequest = new Writable()
|
2023-08-02 09:01:36 -04:00
|
|
|
this.writeStream = new Writable()
|
2022-09-07 06:28:42 -04:00
|
|
|
|
|
|
|
this.fsPromises = {
|
|
|
|
unlink: sinon.stub().resolves(),
|
|
|
|
readFile: sinon.stub().withArgs(this.fsPath).resolves(this.fileContents),
|
2023-08-02 09:01:36 -04:00
|
|
|
mkdir: sinon.stub().resolves(),
|
|
|
|
}
|
|
|
|
|
|
|
|
this.fs = {
|
|
|
|
createWriteStream: sinon.stub().returns(this.writeStream),
|
2022-09-07 06:28:42 -04:00
|
|
|
}
|
|
|
|
|
2022-09-12 10:59:16 -04:00
|
|
|
this.doc = {
|
2023-12-18 05:54:01 -05:00
|
|
|
_id: new ObjectId(),
|
2022-09-12 10:59:16 -04:00
|
|
|
rev: 2,
|
|
|
|
}
|
|
|
|
|
|
|
|
this.file = {
|
2023-12-18 05:54:01 -05:00
|
|
|
_id: new ObjectId(),
|
2022-09-12 10:59:16 -04:00
|
|
|
rev: 6,
|
|
|
|
}
|
|
|
|
|
2022-09-21 08:00:40 -04:00
|
|
|
this.folder = {
|
2023-12-18 05:54:01 -05:00
|
|
|
_id: new ObjectId(),
|
2022-09-21 08:00:40 -04:00
|
|
|
}
|
|
|
|
|
2022-09-07 06:28:42 -04:00
|
|
|
this.EditorController = {
|
|
|
|
promises: {
|
|
|
|
deleteEntityWithPath: sinon.stub().resolves(),
|
2022-09-21 08:00:40 -04:00
|
|
|
upsertDocWithPath: sinon
|
|
|
|
.stub()
|
|
|
|
.resolves({ doc: this.doc, folder: this.folder }),
|
|
|
|
upsertFileWithPath: sinon
|
|
|
|
.stub()
|
|
|
|
.resolves({ file: this.file, folder: this.folder }),
|
2022-09-07 06:28:42 -04:00
|
|
|
},
|
|
|
|
}
|
|
|
|
|
|
|
|
this.FileTypeManager = {
|
|
|
|
promises: {
|
|
|
|
getType: sinon.stub(),
|
|
|
|
},
|
|
|
|
}
|
|
|
|
|
2023-08-02 09:01:36 -04:00
|
|
|
this.crypto = {
|
|
|
|
randomUUID: sinon.stub().returns(this.randomUUID),
|
2022-09-07 06:28:42 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
this.ProjectEntityHandler = {
|
|
|
|
promises: {
|
|
|
|
getAllEntities: sinon.stub().resolves({
|
|
|
|
docs: this.existingDocs,
|
|
|
|
files: this.existingFiles,
|
|
|
|
}),
|
|
|
|
},
|
|
|
|
}
|
|
|
|
|
2023-08-02 09:01:36 -04:00
|
|
|
this.Settings = { path: { dumpFolder: this.dumpPath } }
|
|
|
|
|
|
|
|
this.stream = { pipeline: sinon.stub().resolves() }
|
2022-09-07 06:28:42 -04:00
|
|
|
|
|
|
|
this.UpdateMerger = SandboxedModule.require(MODULE_PATH, {
|
|
|
|
requires: {
|
|
|
|
'fs/promises': this.fsPromises,
|
2023-08-02 09:01:36 -04:00
|
|
|
fs: this.fs,
|
2022-09-07 06:28:42 -04:00
|
|
|
'../Editor/EditorController': this.EditorController,
|
|
|
|
'../Uploads/FileTypeManager': this.FileTypeManager,
|
|
|
|
'../Project/ProjectEntityHandler': this.ProjectEntityHandler,
|
|
|
|
'@overleaf/settings': this.Settings,
|
2023-08-02 09:01:36 -04:00
|
|
|
'stream/promises': this.stream,
|
|
|
|
crypto: this.crypto,
|
2022-09-07 06:28:42 -04:00
|
|
|
},
|
|
|
|
})
|
2019-05-29 05:21:06 -04:00
|
|
|
})
|
|
|
|
|
2021-04-14 09:17:21 -04:00
|
|
|
describe('mergeUpdate', function () {
|
|
|
|
describe('doc updates for a new doc', function () {
|
2022-09-07 06:28:42 -04:00
|
|
|
beforeEach(async function () {
|
|
|
|
this.FileTypeManager.promises.getType.resolves({
|
|
|
|
binary: false,
|
|
|
|
encoding: 'utf-8',
|
|
|
|
})
|
|
|
|
await this.UpdateMerger.promises.mergeUpdate(
|
|
|
|
this.userId,
|
|
|
|
this.projectId,
|
2019-05-29 05:21:06 -04:00
|
|
|
this.docPath,
|
|
|
|
this.updateRequest,
|
2022-09-07 06:28:42 -04:00
|
|
|
this.source
|
2019-05-29 05:21:06 -04:00
|
|
|
)
|
|
|
|
})
|
|
|
|
|
2021-04-14 09:17:21 -04:00
|
|
|
it('should look at the file contents', function () {
|
2022-09-07 06:28:42 -04:00
|
|
|
expect(this.FileTypeManager.promises.getType).to.have.been.called
|
2019-05-29 05:21:06 -04:00
|
|
|
})
|
|
|
|
|
2021-04-14 09:17:21 -04:00
|
|
|
it('should process update as doc', function () {
|
2022-09-07 06:28:42 -04:00
|
|
|
expect(
|
|
|
|
this.EditorController.promises.upsertDocWithPath
|
|
|
|
).to.have.been.calledWith(
|
|
|
|
this.projectId,
|
|
|
|
this.docPath,
|
|
|
|
this.docLines,
|
|
|
|
this.source,
|
|
|
|
this.userId
|
|
|
|
)
|
2019-05-29 05:21:06 -04:00
|
|
|
})
|
|
|
|
|
2021-04-14 09:17:21 -04:00
|
|
|
it('removes the temp file from disk', function () {
|
2022-09-07 06:28:42 -04:00
|
|
|
expect(this.fsPromises.unlink).to.have.been.calledWith(this.fsPath)
|
2019-05-29 05:21:06 -04:00
|
|
|
})
|
|
|
|
})
|
|
|
|
|
2021-04-14 09:17:21 -04:00
|
|
|
describe('file updates for a new file ', function () {
|
2022-09-07 06:28:42 -04:00
|
|
|
beforeEach(async function () {
|
|
|
|
this.FileTypeManager.promises.getType.resolves({ binary: true })
|
|
|
|
await this.UpdateMerger.promises.mergeUpdate(
|
|
|
|
this.userId,
|
|
|
|
this.projectId,
|
2019-05-29 05:21:06 -04:00
|
|
|
this.filePath,
|
|
|
|
this.updateRequest,
|
2022-09-07 06:28:42 -04:00
|
|
|
this.source
|
2019-05-29 05:21:06 -04:00
|
|
|
)
|
|
|
|
})
|
|
|
|
|
2021-04-14 09:17:21 -04:00
|
|
|
it('should look at the file contents', function () {
|
2022-09-07 06:28:42 -04:00
|
|
|
expect(this.FileTypeManager.promises.getType).to.have.been.called
|
2019-05-29 05:21:06 -04:00
|
|
|
})
|
|
|
|
|
2021-04-14 09:17:21 -04:00
|
|
|
it('should process update as file', function () {
|
2022-09-07 06:28:42 -04:00
|
|
|
expect(
|
|
|
|
this.EditorController.promises.upsertFileWithPath
|
|
|
|
).to.have.been.calledWith(
|
|
|
|
this.projectId,
|
|
|
|
this.filePath,
|
|
|
|
this.fsPath,
|
|
|
|
null,
|
|
|
|
this.source,
|
|
|
|
this.userId
|
|
|
|
)
|
2019-05-29 05:21:06 -04:00
|
|
|
})
|
|
|
|
|
2021-04-14 09:17:21 -04:00
|
|
|
it('removes the temp file from disk', function () {
|
2022-09-07 06:28:42 -04:00
|
|
|
expect(this.fsPromises.unlink).to.have.been.calledWith(this.fsPath)
|
2019-05-29 05:21:06 -04:00
|
|
|
})
|
|
|
|
})
|
|
|
|
|
2021-04-14 09:17:21 -04:00
|
|
|
describe('doc updates for an existing doc', function () {
|
2022-09-07 06:28:42 -04:00
|
|
|
beforeEach(async function () {
|
|
|
|
this.FileTypeManager.promises.getType.resolves({
|
|
|
|
binary: false,
|
|
|
|
encoding: 'utf-8',
|
|
|
|
})
|
|
|
|
await this.UpdateMerger.promises.mergeUpdate(
|
|
|
|
this.userId,
|
|
|
|
this.projectId,
|
2019-05-29 05:21:06 -04:00
|
|
|
this.existingDocPath,
|
|
|
|
this.updateRequest,
|
2022-09-07 06:28:42 -04:00
|
|
|
this.source
|
2019-05-29 05:21:06 -04:00
|
|
|
)
|
|
|
|
})
|
|
|
|
|
2021-04-14 09:17:21 -04:00
|
|
|
it('should look at the file contents', function () {
|
2022-09-07 06:28:42 -04:00
|
|
|
expect(this.FileTypeManager.promises.getType).to.have.been.called
|
2019-05-29 05:21:06 -04:00
|
|
|
})
|
|
|
|
|
2021-04-14 09:17:21 -04:00
|
|
|
it('should process update as doc', function () {
|
2022-09-07 06:28:42 -04:00
|
|
|
expect(
|
|
|
|
this.EditorController.promises.upsertDocWithPath
|
|
|
|
).to.have.been.calledWith(
|
|
|
|
this.projectId,
|
|
|
|
this.existingDocPath,
|
|
|
|
this.docLines,
|
|
|
|
this.source,
|
|
|
|
this.userId
|
|
|
|
)
|
2019-05-29 05:21:06 -04:00
|
|
|
})
|
|
|
|
|
2021-04-14 09:17:21 -04:00
|
|
|
it('removes the temp file from disk', function () {
|
2022-09-07 06:28:42 -04:00
|
|
|
expect(this.fsPromises.unlink).to.have.been.calledWith(this.fsPath)
|
2019-05-29 05:21:06 -04:00
|
|
|
})
|
|
|
|
})
|
|
|
|
|
2021-04-14 09:17:21 -04:00
|
|
|
describe('file updates for an existing file', function () {
|
2022-09-07 06:28:42 -04:00
|
|
|
beforeEach(async function () {
|
|
|
|
this.FileTypeManager.promises.getType.resolves({ binary: true })
|
|
|
|
await this.UpdateMerger.promises.mergeUpdate(
|
|
|
|
this.userId,
|
|
|
|
this.projectId,
|
2019-05-29 05:21:06 -04:00
|
|
|
this.existingFilePath,
|
|
|
|
this.updateRequest,
|
2022-09-07 06:28:42 -04:00
|
|
|
this.source
|
2019-05-29 05:21:06 -04:00
|
|
|
)
|
|
|
|
})
|
|
|
|
|
2021-04-14 09:17:21 -04:00
|
|
|
it('should look at the file contents', function () {
|
2022-09-07 06:28:42 -04:00
|
|
|
expect(this.FileTypeManager.promises.getType).to.have.been.called
|
2019-05-29 05:21:06 -04:00
|
|
|
})
|
|
|
|
|
2021-04-14 09:17:21 -04:00
|
|
|
it('should process update as file', function () {
|
2022-09-07 06:28:42 -04:00
|
|
|
expect(
|
|
|
|
this.EditorController.promises.upsertFileWithPath
|
|
|
|
).to.have.been.calledWith(
|
|
|
|
this.projectId,
|
|
|
|
this.existingFilePath,
|
|
|
|
this.fsPath,
|
|
|
|
null,
|
|
|
|
this.source,
|
|
|
|
this.userId
|
|
|
|
)
|
2019-05-29 05:21:06 -04:00
|
|
|
})
|
|
|
|
|
2021-04-14 09:17:21 -04:00
|
|
|
it('removes the temp file from disk', function () {
|
2022-09-07 06:28:42 -04:00
|
|
|
expect(this.fsPromises.unlink).to.have.been.calledWith(this.fsPath)
|
2019-05-29 05:21:06 -04:00
|
|
|
})
|
|
|
|
})
|
|
|
|
})
|
|
|
|
|
2021-04-14 09:17:21 -04:00
|
|
|
describe('file updates for an existing doc', function () {
|
2022-09-07 06:28:42 -04:00
|
|
|
beforeEach(async function () {
|
|
|
|
this.FileTypeManager.promises.getType.resolves({ binary: true })
|
|
|
|
await this.UpdateMerger.promises.mergeUpdate(
|
|
|
|
this.userId,
|
|
|
|
this.projectId,
|
2019-08-06 08:21:05 -04:00
|
|
|
this.existingDocPath,
|
|
|
|
this.updateRequest,
|
2022-09-07 06:28:42 -04:00
|
|
|
this.source
|
2019-08-06 08:21:05 -04:00
|
|
|
)
|
|
|
|
})
|
|
|
|
|
2021-04-14 09:17:21 -04:00
|
|
|
it('should look at the file contents', function () {
|
2022-09-07 06:28:42 -04:00
|
|
|
expect(this.FileTypeManager.promises.getType).to.have.been.called
|
2019-08-06 08:21:05 -04:00
|
|
|
})
|
|
|
|
|
2021-04-14 09:17:21 -04:00
|
|
|
it('should process update as file', function () {
|
2022-09-07 06:28:42 -04:00
|
|
|
expect(
|
|
|
|
this.EditorController.promises.upsertFileWithPath
|
|
|
|
).to.have.been.calledWith(
|
|
|
|
this.projectId,
|
|
|
|
this.existingDocPath,
|
|
|
|
this.fsPath,
|
|
|
|
null,
|
|
|
|
this.source,
|
|
|
|
this.userId
|
|
|
|
)
|
2019-08-06 08:21:05 -04:00
|
|
|
})
|
|
|
|
|
2021-04-14 09:17:21 -04:00
|
|
|
it('removes the temp file from disk', function () {
|
2022-09-07 06:28:42 -04:00
|
|
|
expect(this.fsPromises.unlink).to.have.been.calledWith(this.fsPath)
|
2019-08-06 08:21:05 -04:00
|
|
|
})
|
|
|
|
})
|
|
|
|
|
2021-04-14 09:17:21 -04:00
|
|
|
describe('doc updates for an existing file', function () {
|
2022-09-07 06:28:42 -04:00
|
|
|
beforeEach(async function () {
|
|
|
|
this.FileTypeManager.promises.getType.resolves({ binary: true })
|
|
|
|
await this.UpdateMerger.promises.mergeUpdate(
|
|
|
|
this.userId,
|
|
|
|
this.projectId,
|
2019-08-06 08:21:05 -04:00
|
|
|
this.existingFilePath,
|
|
|
|
this.updateRequest,
|
2022-09-07 06:28:42 -04:00
|
|
|
this.source
|
2019-08-06 08:21:05 -04:00
|
|
|
)
|
|
|
|
})
|
|
|
|
|
2021-04-14 09:17:21 -04:00
|
|
|
it('should look at the file contents', function () {
|
2022-09-07 06:28:42 -04:00
|
|
|
expect(this.FileTypeManager.promises.getType).to.have.been.called
|
2019-08-06 08:21:05 -04:00
|
|
|
})
|
|
|
|
|
2021-04-14 09:17:21 -04:00
|
|
|
it('should not delete the existing file', function () {
|
2022-09-07 06:28:42 -04:00
|
|
|
expect(this.EditorController.promises.deleteEntityWithPath).to.not.have
|
|
|
|
.been.called
|
2019-08-06 08:21:05 -04:00
|
|
|
})
|
|
|
|
|
2021-04-14 09:17:21 -04:00
|
|
|
it('should process update as file', function () {
|
2022-09-07 06:28:42 -04:00
|
|
|
expect(
|
|
|
|
this.EditorController.promises.upsertFileWithPath
|
|
|
|
).to.have.been.calledWith(
|
|
|
|
this.projectId,
|
|
|
|
this.existingFilePath,
|
|
|
|
this.fsPath,
|
|
|
|
null,
|
|
|
|
this.source,
|
|
|
|
this.userId
|
|
|
|
)
|
2019-08-06 08:21:05 -04:00
|
|
|
})
|
|
|
|
|
2021-04-14 09:17:21 -04:00
|
|
|
it('removes the temp file from disk', function () {
|
2022-09-07 06:28:42 -04:00
|
|
|
expect(this.fsPromises.unlink).to.have.been.calledWith(this.fsPath)
|
2019-08-06 08:21:05 -04:00
|
|
|
})
|
|
|
|
})
|
|
|
|
|
2021-04-14 09:17:21 -04:00
|
|
|
describe('deleteUpdate', function () {
|
2022-09-07 06:28:42 -04:00
|
|
|
beforeEach(async function () {
|
|
|
|
await this.UpdateMerger.promises.deleteUpdate(
|
|
|
|
this.userId,
|
|
|
|
this.projectId,
|
2019-05-29 05:21:06 -04:00
|
|
|
this.docPath,
|
2022-09-07 06:28:42 -04:00
|
|
|
this.source
|
2019-05-29 05:21:06 -04:00
|
|
|
)
|
|
|
|
})
|
|
|
|
|
2021-04-14 09:17:21 -04:00
|
|
|
it('should delete the entity in the editor controller', function () {
|
2022-09-07 06:28:42 -04:00
|
|
|
expect(
|
|
|
|
this.EditorController.promises.deleteEntityWithPath
|
|
|
|
).to.have.been.calledWith(
|
|
|
|
this.projectId,
|
|
|
|
this.docPath,
|
|
|
|
this.source,
|
|
|
|
this.userId
|
|
|
|
)
|
2019-05-29 05:21:06 -04:00
|
|
|
})
|
|
|
|
})
|
|
|
|
})
|