overleaf/services/web/test/unit/src/ThirdPartyDataStore/TpdsUpdateSenderTests.js

369 lines
12 KiB
JavaScript
Raw Normal View History

const { ObjectId } = require('mongodb')
const SandboxedModule = require('sandboxed-module')
const chai = require('chai')
const path = require('path')
const sinon = require('sinon')
chai.should()
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'
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, {
globals: {
console: console
},
requires: {
mongodb: { ObjectId },
'settings-sharelatex': this.settings,
'logger-sharelatex': { log() {} },
'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)
})
})
})