Files
overleaf-cep/services/web/test/unit/src/ThirdPartyDataStore/TpdsUpdateSenderTests.js
T
Brian Gough 1d94ef5b54 Merge pull request #4003 from overleaf/bg-project-archiver-deletion
project archiver deletion of expired projects

GitOrigin-RevId: 7e010f4883e0bfeb593da6b728c8e4ac329824cd
2021-05-12 02:09:48 +00:00

376 lines
12 KiB
JavaScript

const { ObjectId } = require('mongodb')
const SandboxedModule = require('sandboxed-module')
const path = require('path')
const sinon = require('sinon')
const modulePath = path.join(
__dirname,
'../../../../app/src/Features/ThirdPartyDataStore/TpdsUpdateSender.js'
)
const projectId = 'project_id_here'
const userId = ObjectId()
const readOnlyRef = ObjectId()
const collaberatorRef = ObjectId()
const projectName = 'project_name_here'
const thirdPartyDataStoreApiUrl = 'http://third-party-json-store.herokuapp.com'
const httpUsername = 'user'
const httpPass = 'pass'
const siteUrl = 'http://www.localhost:3000'
const httpAuthSiteUrl = `http://${httpUsername}:${httpPass}@www.localhost:3000`
const filestoreUrl = 'filestore.sharelatex.com'
const projectArchiverUrl = 'project-archiver.overleaf.com'
describe('TpdsUpdateSender', function () {
beforeEach(function () {
this.fakeUser = {
_id: '12390i',
}
this.requestQueuer = function (queue, meth, opts, callback) {}
const memberIds = [userId, collaberatorRef, readOnlyRef]
this.CollaboratorsGetter = {
promises: {
getInvitedMemberIds: sinon.stub().resolves(memberIds),
},
}
this.docstoreUrl = 'docstore.sharelatex.env'
this.request = sinon.stub().resolves()
this.settings = {
siteUrl,
httpAuthSiteUrl,
apis: {
thirdPartyDataStore: { url: thirdPartyDataStoreApiUrl },
filestore: {
url: filestoreUrl,
},
docstore: {
pubUrl: this.docstoreUrl,
},
},
}
const getUsers = sinon.stub().resolves(
memberIds.slice(1).map(userId => {
return { _id: userId }
})
)
this.UserGetter = {
promises: { getUsers },
}
this.updateSender = SandboxedModule.require(modulePath, {
requires: {
mongodb: { ObjectId },
'settings-sharelatex': this.settings,
'request-promise-native': this.request,
'../Collaborators/CollaboratorsGetter': this.CollaboratorsGetter,
'../User/UserGetter.js': this.UserGetter,
'@overleaf/metrics': {
inc() {},
},
},
})
})
describe('enqueue', function () {
it('should not call request if there is no tpdsworker url', async function () {
await this.updateSender.promises.enqueue(null, null, null)
this.request.should.not.have.been.called
})
it('should post the message to the tpdsworker', async function () {
this.settings.apis.tpdsworker = { url: 'www.tpdsworker.env' }
const group0 = 'myproject'
const method0 = 'somemethod0'
const job0 = 'do something'
await this.updateSender.promises.enqueue(group0, method0, job0)
const args = this.request.firstCall.args[0]
args.json.group.should.equal(group0)
args.json.job.should.equal(job0)
args.json.method.should.equal(method0)
args.uri.should.equal(
'www.tpdsworker.env/enqueue/web_to_tpds_http_requests'
)
})
})
describe('sending updates', function () {
beforeEach(function () {
this.settings.apis.tpdsworker = { url: 'www.tpdsworker.env' }
})
it('queues a post the file with user and file id', async function () {
const fileId = '4545345'
const path = '/some/path/here.jpg'
await this.updateSender.promises.addFile({
project_id: projectId,
file_id: fileId,
path,
project_name: projectName,
})
const {
group: group0,
job: job0,
method: method0,
} = this.request.firstCall.args[0].json
group0.should.equal(userId)
method0.should.equal('pipeStreamFrom')
job0.method.should.equal('post')
job0.streamOrigin.should.equal(
`${filestoreUrl}/project/${projectId}/file/${fileId}`
)
const expectedUrl = `${thirdPartyDataStoreApiUrl}/user/${userId}/entity/${encodeURIComponent(
projectName
)}${encodeURIComponent(path)}`
job0.uri.should.equal(expectedUrl)
job0.headers.sl_all_user_ids.should.equal(JSON.stringify([userId]))
job0.headers.sl_project_owner_user_id.should.equal(userId)
const { group: group1, job: job1 } = this.request.secondCall.args[0].json
group1.should.equal(collaberatorRef)
job1.headers.sl_all_user_ids.should.equal(
JSON.stringify([collaberatorRef])
)
job1.headers.sl_project_owner_user_id.should.equal(userId)
const { group: group2, job: job2 } = this.request.thirdCall.args[0].json
group2.should.equal(readOnlyRef)
job2.headers.sl_all_user_ids.should.equal(JSON.stringify([readOnlyRef]))
job2.headers.sl_project_owner_user_id.should.equal(userId)
this.UserGetter.promises.getUsers.should.have.been.calledOnce.and.calledWith(
{
_id: {
$in: [collaberatorRef, readOnlyRef],
},
'dropbox.access_token.uid': { $ne: null },
},
{ _id: 1 }
)
})
it('post doc with stream origin of docstore', async function () {
const docId = '4545345'
const path = '/some/path/here.tex'
const lines = ['line1', 'line2', 'line3']
await this.updateSender.promises.addDoc({
project_id: projectId,
doc_id: docId,
path,
docLines: lines,
project_name: projectName,
})
const {
group: group0,
job: job0,
method: method0,
} = this.request.firstCall.args[0].json
group0.should.equal(userId)
method0.should.equal('pipeStreamFrom')
job0.method.should.equal('post')
const expectedUrl = `${thirdPartyDataStoreApiUrl}/user/${userId}/entity/${encodeURIComponent(
projectName
)}${encodeURIComponent(path)}`
job0.uri.should.equal(expectedUrl)
job0.streamOrigin.should.equal(
`${this.docstoreUrl}/project/${projectId}/doc/${docId}/raw`
)
job0.headers.sl_all_user_ids.should.eql(JSON.stringify([userId]))
const { group: group1, job: job1 } = this.request.secondCall.args[0].json
group1.should.equal(collaberatorRef)
job1.headers.sl_all_user_ids.should.equal(
JSON.stringify([collaberatorRef])
)
const { group: group2, job: job2 } = this.request.thirdCall.args[0].json
group2.should.equal(readOnlyRef)
job2.headers.sl_all_user_ids.should.equal(JSON.stringify([readOnlyRef]))
this.UserGetter.promises.getUsers.should.have.been.calledOnce.and.calledWith(
{
_id: {
$in: [collaberatorRef, readOnlyRef],
},
'dropbox.access_token.uid': { $ne: null },
},
{ _id: 1 }
)
})
it('deleting entity', async function () {
const path = '/path/here/t.tex'
await this.updateSender.promises.deleteEntity({
project_id: projectId,
path,
project_name: projectName,
})
const {
group: group0,
job: job0,
method: method0,
} = this.request.firstCall.args[0].json
group0.should.equal(userId)
method0.should.equal('standardHttpRequest')
job0.method.should.equal('delete')
const expectedUrl = `${thirdPartyDataStoreApiUrl}/user/${userId}/entity/${encodeURIComponent(
projectName
)}${encodeURIComponent(path)}`
job0.headers.sl_all_user_ids.should.eql(JSON.stringify([userId]))
job0.uri.should.equal(expectedUrl)
const { group: group1, job: job1 } = this.request.secondCall.args[0].json
group1.should.equal(collaberatorRef)
job1.headers.sl_all_user_ids.should.equal(
JSON.stringify([collaberatorRef])
)
const { group: group2, job: job2 } = this.request.thirdCall.args[0].json
group2.should.equal(readOnlyRef)
job2.headers.sl_all_user_ids.should.equal(JSON.stringify([readOnlyRef]))
this.UserGetter.promises.getUsers.should.have.been.calledOnce.and.calledWith(
{
_id: {
$in: [collaberatorRef, readOnlyRef],
},
'dropbox.access_token.uid': { $ne: null },
},
{ _id: 1 }
)
})
it('moving entity', async function () {
const startPath = 'staring/here/file.tex'
const endPath = 'ending/here/file.tex'
await this.updateSender.promises.moveEntity({
project_id: projectId,
startPath,
endPath,
project_name: projectName,
})
const {
group: group0,
job: job0,
method: method0,
} = this.request.firstCall.args[0].json
group0.should.equal(userId)
method0.should.equal('standardHttpRequest')
job0.method.should.equal('put')
job0.uri.should.equal(
`${thirdPartyDataStoreApiUrl}/user/${userId}/entity`
)
job0.json.startPath.should.equal(`/${projectName}/${startPath}`)
job0.json.endPath.should.equal(`/${projectName}/${endPath}`)
job0.headers.sl_all_user_ids.should.eql(JSON.stringify([userId]))
const { group: group1, job: job1 } = this.request.secondCall.args[0].json
group1.should.equal(collaberatorRef)
job1.headers.sl_all_user_ids.should.equal(
JSON.stringify([collaberatorRef])
)
const { group: group2, job: job2 } = this.request.thirdCall.args[0].json
group2.should.equal(readOnlyRef)
job2.headers.sl_all_user_ids.should.equal(JSON.stringify([readOnlyRef]))
this.UserGetter.promises.getUsers.should.have.been.calledOnce.and.calledWith(
{
_id: {
$in: [collaberatorRef, readOnlyRef],
},
'dropbox.access_token.uid': { $ne: null },
},
{ _id: 1 }
)
})
it('should be able to rename a project using the move entity func', async function () {
const oldProjectName = '/oldProjectName/'
const newProjectName = '/newProjectName/'
await this.updateSender.promises.moveEntity({
project_id: projectId,
project_name: oldProjectName,
newProjectName,
})
const {
group: group0,
job: job0,
method: method0,
} = this.request.firstCall.args[0].json
group0.should.equal(userId)
method0.should.equal('standardHttpRequest')
job0.method.should.equal('put')
job0.uri.should.equal(
`${thirdPartyDataStoreApiUrl}/user/${userId}/entity`
)
job0.json.startPath.should.equal(oldProjectName)
job0.json.endPath.should.equal(newProjectName)
job0.headers.sl_all_user_ids.should.eql(JSON.stringify([userId]))
const { group: group1, job: job1 } = this.request.secondCall.args[0].json
group1.should.equal(collaberatorRef)
job1.headers.sl_all_user_ids.should.equal(
JSON.stringify([collaberatorRef])
)
const { group: group2, job: job2 } = this.request.thirdCall.args[0].json
group2.should.equal(readOnlyRef)
job2.headers.sl_all_user_ids.should.equal(JSON.stringify([readOnlyRef]))
this.UserGetter.promises.getUsers.should.have.been.calledOnce.and.calledWith(
{
_id: {
$in: [collaberatorRef, readOnlyRef],
},
'dropbox.access_token.uid': { $ne: null },
},
{ _id: 1 }
)
})
it('pollDropboxForUser', async function () {
await this.updateSender.promises.pollDropboxForUser(userId)
const {
group: group0,
job: job0,
method: method0,
} = this.request.firstCall.args[0].json
group0.should.equal(`poll-dropbox:${userId}`)
method0.should.equal('standardHttpRequest')
job0.method.should.equal('post')
job0.uri.should.equal(`${thirdPartyDataStoreApiUrl}/user/poll`)
job0.json.user_ids[0].should.equal(userId)
})
})
describe('deleteProject', function () {
it('should not call request if there is no project archiver url', async function () {
await this.updateSender.promises.deleteProject({ project_id: projectId })
this.request.should.not.have.been.called
})
it('should make a delete request to project archiver', async function () {
this.settings.apis.project_archiver = { url: projectArchiverUrl }
await this.updateSender.promises.deleteProject({ project_id: projectId })
const { uri, method } = this.request.firstCall.args[0]
method.should.equal('delete')
uri.should.equal(`${projectArchiverUrl}/project/${projectId}`)
})
})
})