Merge pull request #2614 from overleaf/sk-monolithify-tags

Move 'tags' into web

GitOrigin-RevId: a248d1b2471f0bfa05589df9b7357b4d85793a79
This commit is contained in:
Shane Kilkelly
2020-03-25 04:16:44 +00:00
committed by Copybot
parent bffb9f3bce
commit b51e3c01e4
11 changed files with 755 additions and 592 deletions
@@ -21,8 +21,8 @@ const modulePath = require('path').join(
)
describe('TagsController', function() {
const user_id = '123nd3ijdks'
const project_id = '123njdskj9jlk'
const userId = '123nd3ijdks'
const projectId = '123njdskj9jlk'
const tag = 'some_class101'
beforeEach(function() {
@@ -54,11 +54,11 @@ describe('TagsController', function() {
})
this.req = {
params: {
project_id
projectId
},
session: {
user: {
_id: user_id
_id: userId
}
}
}
@@ -76,7 +76,7 @@ describe('TagsController', function() {
return this.controller.getAllTags(this.req, {
json: body => {
body.should.equal(allTags)
this.handler.getAllTags.calledWith(user_id).should.equal(true)
this.handler.getAllTags.calledWith(userId).should.equal(true)
return done()
}
})
@@ -86,14 +86,14 @@ describe('TagsController', function() {
describe('createTag', function() {
beforeEach(function() {
this.handler.createTag.callsArgWith(2, null, (this.tag = { mock: 'tag' }))
this.req.session.user._id = this.user_id = 'user-id-123'
this.req.session.user._id = this.userId = 'user-id-123'
this.req.body = { name: (this.name = 'tag-name') }
return this.controller.createTag(this.req, this.res)
})
it('should create the tag in the backend', function() {
return this.handler.createTag
.calledWith(this.user_id, this.name)
.calledWith(this.userId, this.name)
.should.equal(true)
})
@@ -104,14 +104,14 @@ describe('TagsController', function() {
describe('deleteTag', function() {
beforeEach(function() {
this.req.params.tag_id = this.tag_id = 'tag-id-123'
this.req.session.user._id = this.user_id = 'user-id-123'
this.req.params.tagId = this.tagId = 'tag-id-123'
this.req.session.user._id = this.userId = 'user-id-123'
return this.controller.deleteTag(this.req, this.res)
})
it('should delete the tag in the backend', function() {
return this.handler.deleteTag
.calledWith(this.user_id, this.tag_id)
.calledWith(this.userId, this.tagId)
.should.equal(true)
})
@@ -123,8 +123,8 @@ describe('TagsController', function() {
describe('renameTag', function() {
beforeEach(function() {
this.req.params.tag_id = this.tag_id = 'tag-id-123'
return (this.req.session.user._id = this.user_id = 'user-id-123')
this.req.params.tagId = this.tagId = 'tag-id-123'
return (this.req.session.user._id = this.userId = 'user-id-123')
})
describe('with a name', function() {
@@ -135,7 +135,7 @@ describe('TagsController', function() {
it('should delete the tag in the backend', function() {
return this.handler.renameTag
.calledWith(this.user_id, this.tag_id, this.name)
.calledWith(this.userId, this.tagId, this.name)
.should.equal(true)
})
@@ -163,15 +163,15 @@ describe('TagsController', function() {
describe('addProjectToTag', function() {
beforeEach(function() {
this.req.params.tag_id = this.tag_id = 'tag-id-123'
this.req.params.project_id = this.project_id = 'project-id-123'
this.req.session.user._id = this.user_id = 'user-id-123'
this.req.params.tagId = this.tagId = 'tag-id-123'
this.req.params.projectId = this.projectId = 'project-id-123'
this.req.session.user._id = this.userId = 'user-id-123'
return this.controller.addProjectToTag(this.req, this.res)
})
it('should add the tag to the project in the backend', function() {
return this.handler.addProjectToTag
.calledWith(this.user_id, this.tag_id, this.project_id)
.calledWith(this.userId, this.tagId, this.projectId)
.should.equal(true)
})
@@ -183,15 +183,15 @@ describe('TagsController', function() {
describe('removeProjectFromTag', function() {
beforeEach(function() {
this.req.params.tag_id = this.tag_id = 'tag-id-123'
this.req.params.project_id = this.project_id = 'project-id-123'
this.req.session.user._id = this.user_id = 'user-id-123'
this.req.params.tagId = this.tagId = 'tag-id-123'
this.req.params.projectId = this.projectId = 'project-id-123'
this.req.session.user._id = this.userId = 'user-id-123'
return this.controller.removeProjectFromTag(this.req, this.res)
})
it('should remove the tag from the project in the backend', function() {
return this.handler.removeProjectFromTag
.calledWith(this.user_id, this.tag_id, this.project_id)
.calledWith(this.userId, this.tagId, this.projectId)
.should.equal(true)
})
@@ -1,425 +1,260 @@
const SandboxedModule = require('sandboxed-module')
const { assert } = require('chai')
const { expect } = require('chai')
require('chai').should()
const sinon = require('sinon')
const { Tag } = require('../helpers/models/Tag')
const { ObjectId } = require('mongojs')
const modulePath = require('path').join(
__dirname,
'../../../../app/src/Features/Tags/TagsHandler.js'
)
describe('TagsHandler', function() {
const userId = 'user-id-123'
const tagId = 'tag-id-123'
const projectId = 'project-id-123'
const tagsUrl = 'tags.sharelatex.testing'
const tag = 'tag_name'
describe('TagsHandler', function() {
beforeEach(function() {
this.request = {
post: sinon.stub().callsArgWith(1),
del: sinon.stub().callsArgWith(1),
get: sinon.stub()
}
this.userId = ObjectId().toString()
this.callback = sinon.stub()
this.handler = SandboxedModule.require(modulePath, {
globals: {
console: console
},
this.tag = { user_id: this.userId, name: 'some name' }
this.tagId = ObjectId().toString()
this.projectId = ObjectId().toString()
this.mongojs = { ObjectId: ObjectId }
this.TagMock = sinon.mock(Tag)
this.TagsHandler = SandboxedModule.require(modulePath, {
requires: {
'settings-sharelatex': {
apis: { tags: { url: tagsUrl } }
},
request: this.request,
'logger-sharelatex': {
log() {},
warn() {},
err() {}
}
'../../infrastructure/mongojs': this.mongojs,
'../../models/Tag': { Tag: Tag }
}
})
})
describe('removeProjectFromAllTags', function() {
it('should tell the tags api to remove the project_id from all the users tags', function(done) {
this.handler.removeProjectFromAllTags(userId, projectId, () => {
this.request.del
.calledWith({
url: `${tagsUrl}/user/${userId}/project/${projectId}`,
timeout: 10000
})
.should.equal(true)
done()
})
})
})
describe('getAllTags', function() {
it('should get all tags', function(done) {
const stubbedAllTags = [
{ name: 'tag', project_ids: ['123423', '423423'] }
]
this.request.get.callsArgWith(
1,
null,
{ statusCode: 200 },
stubbedAllTags
)
this.handler.getAllTags(userId, (err, allTags) => {
assert.notExists(err)
stubbedAllTags.should.deep.equal(allTags)
const getOpts = {
url: `${tagsUrl}/user/${userId}/tag`,
json: true,
timeout: 10000
}
this.request.get.calledWith(getOpts).should.equal(true)
done()
})
})
it('should callback with an empty array on error', function(done) {
this.request.get.callsArgWith(
1,
{ something: 'wrong' },
{ statusCode: 200 },
[]
)
this.handler.getAllTags(userId, (err, allTags) => {
allTags.length.should.equal(0)
assert.isDefined(err)
done()
})
})
it('should callback with an empty array if there are no tags', function(done) {
this.request.get.callsArgWith(
1,
{ something: 'wrong' },
{ statusCode: 200 },
undefined
)
this.handler.getAllTags(userId, (err, allTags) => {
allTags.length.should.equal(0)
assert.isDefined(err)
done()
})
})
it('should callback with an empty array on a non 200 response', function(done) {
this.request.get.callsArgWith(1, null, { statusCode: 201 }, [])
this.handler.getAllTags(userId, (err, allTags) => {
allTags.length.should.equal(0)
assert.isDefined(err)
done()
})
})
it('should callback with an empty array on no body and no response', function(done) {
this.request.get.callsArgWith(
1,
{ something: 'wrong' },
undefined,
undefined
)
this.handler.getAllTags(userId, (err, allTags) => {
allTags.length.should.equal(0)
assert.isDefined(err)
describe('finding users tags', function() {
it('should find all the documents with that user id', function(done) {
const stubbedTags = [{ name: 'tag1' }, { name: 'tag2' }, { name: 'tag3' }]
this.TagMock.expects('find')
.once()
.withArgs({ user_id: this.userId })
.yields(null, stubbedTags)
this.TagsHandler.getAllTags(this.userId, (err, result) => {
expect(err).to.not.exist
this.TagMock.verify()
expect(result).to.deep.equal(stubbedTags)
done()
})
})
})
describe('createTag', function() {
beforeEach(function() {
this.request.post = sinon
.stub()
.callsArgWith(1, null, { statusCode: 204 }, '')
this.handler.createTag(userId, (this.name = 'tag_name'), this.callback)
})
it('should send a request to the tag backend', function() {
this.request.post
.calledWith({
url: `${tagsUrl}/user/${userId}/tag`,
json: {
name: this.name
},
timeout: 10000
})
.should.equal(true)
})
it('should call the callback with no error', function() {
this.callback.calledWith(null).should.equal(true)
})
})
describe('deleteTag', function() {
describe('successfully', function() {
beforeEach(function() {
this.request.del = sinon
.stub()
.callsArgWith(1, null, { statusCode: 204 }, '')
this.handler.deleteTag(userId, tagId, this.callback)
})
it('should send a request to the tag backend', function() {
this.request.del
.calledWith({
url: `${tagsUrl}/user/${userId}/tag/${tagId}`,
timeout: 10000
})
.should.equal(true)
})
it('should call the callback with no error', function() {
this.callback.calledWith(null).should.equal(true)
})
})
describe('with error', function() {
beforeEach(function() {
this.request.del = sinon
.stub()
.callsArgWith(1, null, { statusCode: 500 }, '')
this.handler.deleteTag(userId, tagId, this.callback)
})
it('should call the callback with an Error', function() {
this.callback
.calledWith(sinon.match.instanceOf(Error))
.should.equal(true)
})
})
})
describe('renameTag', function() {
describe('successfully', function() {
beforeEach(function() {
this.request.post = sinon
.stub()
.callsArgWith(1, null, { statusCode: 204 }, '')
this.handler.renameTag(
userId,
tagId,
(this.name = 'new-name'),
this.callback
describe('when insert succeeds', function() {
it('should call insert in mongo', function(done) {
this.TagMock.expects('create')
.withArgs(this.tag)
.once()
.yields(null, this.tag)
this.TagsHandler.createTag(
this.tag.user_id,
this.tag.name,
(err, resultTag) => {
expect(err).to.not.exist
this.TagMock.verify()
expect(resultTag.user_id).to.equal(this.tag.user_id)
expect(resultTag.name).to.equal(this.tag.name)
done()
}
)
})
it('should send a request to the tag backend', function() {
this.request.post
.calledWith({
url: `${tagsUrl}/user/${userId}/tag/${tagId}/rename`,
json: {
name: this.name
},
timeout: 10000
})
.should.equal(true)
})
it('should call the callback with no error', function() {
this.callback.calledWith(null).should.equal(true)
})
})
describe('with error', function() {
describe('when insert has duplicate key error error', function() {
beforeEach(function() {
this.request.post = sinon
.stub()
.callsArgWith(1, null, { statusCode: 500 }, '')
this.handler.renameTag(userId, tagId, 'name', this.callback)
this.duplicateKeyError = new Error('Duplicate')
this.duplicateKeyError.code = 11000
})
it('should call the callback with an Error', function() {
this.callback
.calledWith(sinon.match.instanceOf(Error))
.should.equal(true)
})
})
})
describe('removeProjectFromTag', function() {
describe('successfully', function() {
beforeEach(function() {
this.request.del = sinon
.stub()
.callsArgWith(1, null, { statusCode: 204 }, '')
this.handler.removeProjectFromTag(
userId,
tagId,
projectId,
this.callback
it('should get tag with findOne and return that tag', function(done) {
this.TagMock.expects('create')
.withArgs(this.tag)
.once()
.yields(this.duplicateKeyError)
this.TagMock.expects('findOne')
.withArgs({ user_id: this.tag.user_id, name: this.tag.name })
.once()
.yields(null, this.tag)
this.TagsHandler.createTag(
this.tag.user_id,
this.tag.name,
(err, resultTag) => {
expect(err).to.not.exist
this.TagMock.verify()
expect(resultTag.user_id).to.equal(this.tag.user_id)
expect(resultTag.name).to.equal(this.tag.name)
done()
}
)
})
it('should send a request to the tag backend', function() {
this.request.del
.calledWith({
url: `${tagsUrl}/user/${userId}/tag/${tagId}/project/${projectId}`,
timeout: 10000
})
.should.equal(true)
})
it('should call the callback with no error', function() {
this.callback.calledWith(null).should.equal(true)
})
})
describe('with error', function() {
beforeEach(function() {
this.request.del = sinon
.stub()
.callsArgWith(1, null, { statusCode: 500 }, '')
this.handler.removeProjectFromTag(
userId,
tagId,
projectId,
this.callback
)
})
it('should call the callback with an Error', function() {
this.callback
.calledWith(sinon.match.instanceOf(Error))
.should.equal(true)
})
})
})
describe('addProjectToTag', function() {
describe('successfully', function() {
beforeEach(function() {
this.request.post = sinon
.stub()
.callsArgWith(1, null, { statusCode: 204 }, '')
this.handler.addProjectToTag(userId, tagId, projectId, this.callback)
})
describe('with a valid tag_id', function() {
beforeEach(function() {})
it('should send a request to the tag backend', function() {
this.request.post
.calledWith({
url: `${tagsUrl}/user/${userId}/tag/${tagId}/project/${projectId}`,
timeout: 10000
})
.should.equal(true)
})
it('should call the callback with no error', function() {
this.callback.calledWith(null).should.equal(true)
})
})
describe('with error', function() {
beforeEach(function() {
this.request.post = sinon
.stub()
.callsArgWith(1, null, { statusCode: 500 }, '')
this.handler.addProjectToTag(userId, tagId, projectId, this.callback)
})
it('should call the callback with an Error', function() {
this.callback
.calledWith(sinon.match.instanceOf(Error))
.should.equal(true)
it('should call update in mongo', function(done) {
this.TagMock.expects('findOneAndUpdate')
.once()
.withArgs(
{ _id: this.tagId, user_id: this.userId },
{ $addToSet: { project_ids: this.projectId } }
)
.yields()
this.TagsHandler.addProjectToTag(
this.userId,
this.tagId,
this.projectId,
err => {
expect(err).to.not.exist
this.TagMock.verify()
done()
}
)
})
})
})
describe('addProjectToTagName', function() {
describe('successfully', function() {
beforeEach(function() {
this.request.post = sinon
.stub()
.callsArgWith(1, null, { statusCode: 204 }, '')
this.handler.addProjectToTagName(userId, tag, projectId, this.callback)
})
it('should send a request to the tag backend', function() {
this.request.post
.calledWith({
json: {
name: tag
},
url: `${tagsUrl}/user/${userId}/tag/project/${projectId}`,
timeout: 10000
})
.should.equal(true)
})
it('should call the callback with no error', function() {
this.callback.calledWith(null).should.equal(true)
})
})
describe('with error', function() {
beforeEach(function() {
this.request.post = sinon
.stub()
.callsArgWith(1, null, { statusCode: 500 }, '')
this.handler.addProjectToTagName(
userId,
tagId,
projectId,
this.callback
it('should call update in mongo', function(done) {
this.TagMock.expects('update')
.once()
.withArgs(
{ name: this.tag.name, user_id: this.tag.userId },
{ $addToSet: { project_ids: this.projectId } },
{ upsert: true }
)
})
it('should call the callback with an Error', function() {
this.callback
.calledWith(sinon.match.instanceOf(Error))
.should.equal(true)
})
.yields()
this.TagsHandler.addProjectToTagName(
this.tag.userId,
this.tag.name,
this.projectId,
err => {
expect(err).to.not.exist
this.TagMock.verify()
done()
}
)
})
})
describe('updateTagUserIds', function() {
describe('successfully', function() {
beforeEach(function() {
this.request.put = sinon
.stub()
.callsArgWith(1, null, { statusCode: 204 }, '')
this.handler.updateTagUserIds(
'old-user-id',
'new-user-id',
this.callback
it('should call update in mongo', function(done) {
this.newUserId = ObjectId().toString()
this.TagMock.expects('update')
.once()
.withArgs(
{ user_id: this.userId },
{ $set: { user_id: this.newUserId } },
{ multi: true }
)
})
it('should send a request to the tag backend', function() {
this.request.put
.calledWith({
json: {
user_id: 'new-user-id'
},
url: `${tagsUrl}/user/old-user-id/tag`,
timeout: 10000
})
.should.equal(true)
})
it('should call the callback with no error', function() {
this.callback.calledWith(null).should.equal(true)
.yields()
this.TagsHandler.updateTagUserIds(this.userId, this.newUserId, err => {
expect(err).to.not.exist
this.TagMock.verify()
done()
})
})
})
describe('with error', function() {
beforeEach(function() {
this.request.put = sinon
.stub()
.callsArgWith(1, null, { statusCode: 500 }, '')
this.handler.updateTagUserIds(
'old-user-id',
'new-user-id',
this.callback
describe('removeProjectFromTag', function() {
describe('with a valid tag_id', function() {
it('should call update in mongo', function(done) {
this.TagMock.expects('update')
.once()
.withArgs(
{
_id: this.tagId,
user_id: this.userId
},
{
$pull: { project_ids: this.projectId }
}
)
.yields()
this.TagsHandler.removeProjectFromTag(
this.userId,
this.tagId,
this.projectId,
err => {
expect(err).to.not.exist
this.TagMock.verify()
done()
}
)
})
})
})
it('should call the callback with an Error', function() {
this.callback
.calledWith(sinon.match.instanceOf(Error))
.should.equal(true)
describe('removeProjectFromAllTags', function() {
it('should pull the project id from the tag', function(done) {
this.TagMock.expects('update')
.once()
.withArgs(
{
user_id: this.userId
},
{
$pull: { project_ids: this.projectId }
}
)
.yields()
this.TagsHandler.removeProjectFromAllTags(
this.userId,
this.projectId,
err => {
expect(err).to.not.exist
this.TagMock.verify()
done()
}
)
})
})
describe('deleteTag', function() {
describe('with a valid tag_id', function() {
it('should call remove in mongo', function(done) {
this.TagMock.expects('remove')
.once()
.withArgs({ _id: this.tagId, user_id: this.userId })
.yields()
this.TagsHandler.deleteTag(this.userId, this.tagId, err => {
expect(err).to.not.exist
this.TagMock.verify()
done()
})
})
})
})
describe('renameTag', function() {
describe('with a valid tag_id', function() {
it('should call remove in mongo', function(done) {
this.newName = 'new name'
this.TagMock.expects('update')
.once()
.withArgs(
{ _id: this.tagId, user_id: this.userId },
{ $set: { name: this.newName } }
)
.yields()
this.TagsHandler.renameTag(
this.userId,
this.tagId,
this.newName,
err => {
expect(err).to.not.exist
this.TagMock.verify()
done()
}
)
})
})
})
@@ -0,0 +1,3 @@
const mockModel = require('../MockModel')
module.exports = mockModel('Tag')