overleaf/services/web/test/unit/coffee/Project/ProjectDetailsHandlerTests.coffee
2018-09-28 09:48:15 +01:00

297 lines
10 KiB
CoffeeScript

should = require('chai').should()
modulePath = "../../../../app/js/Features/Project/ProjectDetailsHandler"
Errors = require "../../../../app/js/Features/Errors/Errors"
SandboxedModule = require('sandboxed-module')
sinon = require('sinon')
assert = require("chai").assert
expect = require("chai").expect
require('chai').should()
describe 'ProjectDetailsHandler', ->
beforeEach ->
@project_id = "321l3j1kjkjl"
@user_id = "user-id-123"
@project =
name: "project"
description: "this is a great project"
something:"should not exist"
compiler: "latexxxxxx"
owner_ref: @user_id
@user =
features: "mock-features"
@ProjectGetter =
getProjectWithoutDocLines: sinon.stub().callsArgWith(1, null, @project)
getProject: sinon.stub().callsArgWith(2, null, @project)
@ProjectModel =
update: sinon.stub()
findOne: sinon.stub()
@UserGetter =
getUser: sinon.stub().callsArgWith(1, null, @user)
@tpdsUpdateSender =
moveEntity:sinon.stub().callsArgWith 1
@handler = SandboxedModule.require modulePath, requires:
"./ProjectGetter":@ProjectGetter
'../../models/Project': Project:@ProjectModel
"../User/UserGetter": @UserGetter
'../ThirdPartyDataStore/TpdsUpdateSender':@tpdsUpdateSender
'logger-sharelatex':
log:->
err:->
'./ProjectTokenGenerator': @ProjectTokenGenerator = {}
describe "getDetails", ->
it "should find the project and owner", (done)->
@handler.getDetails @project_id, (err, details)=>
details.name.should.equal @project.name
details.description.should.equal @project.description
details.compiler.should.equal @project.compiler
details.features.should.equal @user.features
assert.equal(details.something, undefined)
done()
it "should find overleaf metadata if it exists", (done)->
@project.overleaf = { id: 'id' }
@handler.getDetails @project_id, (err, details)=>
details.overleaf.should.equal @project.overleaf
assert.equal(details.something, undefined)
done()
it "should return an error for a non-existent project", (done)->
@ProjectGetter.getProject.callsArg(2, null, null)
err = new Errors.NotFoundError("project not found")
@handler.getDetails "0123456789012345678901234", (error, details) =>
err.should.eql error
done()
it "should return the error", (done)->
error = "some error"
@ProjectGetter.getProject.callsArgWith(2, error)
@handler.getDetails @project_id, (err)=>
err.should.equal error
done()
describe "getProjectDescription", ->
it "should make a call to mongo just for the description", (done)->
@ProjectGetter.getProject.callsArgWith(2)
@handler.getProjectDescription @project_id, (err, description)=>
@ProjectGetter.getProject
.calledWith(@project_id, description: true)
.should.equal true
done()
it "should return what the mongo call returns", (done)->
err = "error"
description = "cool project"
@ProjectGetter.getProject.callsArgWith(2, err, {description:description})
@handler.getProjectDescription @project_id, (returnedErr, returnedDescription)=>
err.should.equal returnedErr
description.should.equal returnedDescription
done()
describe "setProjectDescription", ->
beforeEach ->
@description = "updated teh description"
it "should update the project detials", (done)->
@ProjectModel.update.callsArgWith(2)
@handler.setProjectDescription @project_id, @description, =>
@ProjectModel.update.calledWith({_id:@project_id}, {description:@description}).should.equal true
done()
describe "renameProject", ->
beforeEach ->
@handler.validateProjectName = sinon.stub().yields()
@ProjectModel.update.callsArgWith(2)
@newName = "new name here"
it "should update the project with the new name", (done)->
newName = "new name here"
@handler.renameProject @project_id, @newName, =>
@ProjectModel.update.calledWith({_id: @project_id}, {name: @newName}).should.equal true
done()
it "should tell the tpdsUpdateSender", (done)->
@handler.renameProject @project_id, @newName, =>
@tpdsUpdateSender.moveEntity.calledWith({project_id:@project_id, project_name:@project.name, newProjectName:@newName}).should.equal true
done()
it "should not do anything with an invalid name", (done) ->
@handler.validateProjectName = sinon.stub().yields(new Error("invalid name"))
@handler.renameProject @project_id, @newName, =>
@tpdsUpdateSender.moveEntity.called.should.equal false
@ProjectModel.update.called.should.equal false
done()
describe "validateProjectName", ->
it "should reject undefined names", (done) ->
@handler.validateProjectName undefined, (error) ->
expect(error).to.exist
done()
it "should reject empty names", (done) ->
@handler.validateProjectName "", (error) ->
expect(error).to.exist
done()
it "should reject empty names with /s", (done) ->
@handler.validateProjectName "foo/bar", (error) ->
expect(error).to.exist
done()
it "should reject long names", (done) ->
@handler.validateProjectName new Array(1000).join("a"), (error) ->
expect(error).to.exist
done()
it "should accept normal names", (done) ->
@handler.validateProjectName "foobar", (error) ->
expect(error).to.not.exist
done()
describe "ensureProjectNameIsUnique", ->
beforeEach ->
@result = {
owned: ["name", "name1", "name11"]
readAndWrite: ["name2", "name22"]
readOnly: ["name3", "name33"]
tokenReadAndWrite: ["name4", "name44"]
tokenReadOnly: ["name5", "name55", "x".repeat(15)]
}
@ProjectGetter.findAllUsersProjects = sinon.stub().callsArgWith(2, null, @result)
it "should leave a unique name unchanged", (done) ->
@handler.ensureProjectNameIsUnique @user_id, "unique-name", ["-test-suffix"], (error, name, changed) ->
expect(name).to.equal "unique-name"
expect(changed).to.equal false
done()
it "should append a suffix to an existing name", (done) ->
@handler.ensureProjectNameIsUnique @user_id, "name1", ["-test-suffix"], (error, name, changed) ->
expect(name).to.equal "name1-test-suffix"
expect(changed).to.equal true
done()
it "should fallback to a second suffix when needed", (done) ->
@handler.ensureProjectNameIsUnique @user_id, "name1", ["1", "-test-suffix"], (error, name, changed) ->
expect(name).to.equal "name1-test-suffix"
expect(changed).to.equal true
done()
it "should truncate the name when append a suffix if the result is too long", (done) ->
@handler.MAX_PROJECT_NAME_LENGTH = 20
@handler.ensureProjectNameIsUnique @user_id, "x".repeat(15), ["-test-suffix"], (error, name, changed) ->
expect(name).to.equal "x".repeat(8) + "-test-suffix"
expect(changed).to.equal true
done()
it "should return an error if the name cannot be made unique", (done) ->
@handler.ensureProjectNameIsUnique @user_id, "name", ["1", "5", "55"], (error, name, changed) ->
expect(error).to.eql new Errors.InvalidNameError("Project name could not be made unique")
done()
describe "setPublicAccessLevel", ->
beforeEach ->
@ProjectModel.update.callsArgWith(2)
@accessLevel = "readOnly"
it "should update the project with the new level", (done)->
@handler.setPublicAccessLevel @project_id, @accessLevel, =>
@ProjectModel.update.calledWith({_id: @project_id}, {publicAccesLevel: @accessLevel}).should.equal true
done()
it 'should not produce an error', (done) ->
@handler.setPublicAccessLevel @project_id, @accessLevel, (err) =>
expect(err).to.not.exist
done()
describe 'when update produces an error', ->
beforeEach ->
@ProjectModel.update.callsArgWith(2, new Error('woops'))
it 'should produce an error', (done) ->
@handler.setPublicAccessLevel @project_id, @accessLevel, (err) =>
expect(err).to.exist
expect(err).to.be.instanceof Error
done()
describe "ensureTokensArePresent", ->
beforeEach ->
describe 'when the project has tokens', ->
beforeEach ->
@project =
_id: @project_id
tokens:
readOnly: 'aaa'
readAndWrite: '42bbb'
@ProjectGetter.getProject = sinon.stub()
.callsArgWith(2, null, @project)
@ProjectModel.update = sinon.stub()
it 'should get the project', (done) ->
@handler.ensureTokensArePresent @project_id, (err, tokens) =>
expect(@ProjectGetter.getProject.callCount).to.equal 1
expect(@ProjectGetter.getProject.calledWith(@project_id, {tokens: 1}))
.to.equal true
done()
it 'should not update the project with new tokens', (done) ->
@handler.ensureTokensArePresent @project_id, (err, tokens) =>
expect(@ProjectModel.update.callCount).to.equal 0
done()
it 'should produce the tokens without error', (done) ->
@handler.ensureTokensArePresent @project_id, (err, tokens) =>
expect(err).to.not.exist
expect(tokens).to.deep.equal @project.tokens
done()
describe 'when tokens are missing', ->
beforeEach ->
@project =
_id: @project_id
@ProjectGetter.getProject = sinon.stub()
.callsArgWith(2, null, @project)
@readOnlyToken = 'abc'
@readAndWriteToken = '42def'
@ProjectTokenGenerator.readOnlyToken = sinon.stub().returns(@readOnlyToken)
@ProjectTokenGenerator.readAndWriteToken = sinon.stub().returns(@readAndWriteToken)
@ProjectModel.update = sinon.stub()
.callsArgWith(2, null)
it 'should get the project', (done) ->
@handler.ensureTokensArePresent @project_id, (err, tokens) =>
expect(@ProjectGetter.getProject.callCount).to.equal 1
expect(@ProjectGetter.getProject.calledWith(@project_id, {tokens: 1}))
.to.equal true
done()
it 'should update the project with new tokens', (done) ->
@handler.ensureTokensArePresent @project_id, (err, tokens) =>
expect(@ProjectTokenGenerator.readOnlyToken.callCount)
.to.equal 1
expect(@ProjectTokenGenerator.readAndWriteToken.callCount)
.to.equal 1
expect(@ProjectModel.update.callCount).to.equal 1
expect(@ProjectModel.update.calledWith(
{_id: @project_id},
{$set: {tokens: {readOnly: @readOnlyToken, readAndWrite: @readAndWriteToken}}}
)).to.equal true
done()
it 'should produce the tokens without error', (done) ->
@handler.ensureTokensArePresent @project_id, (err, tokens) =>
expect(err).to.not.exist
expect(tokens).to.deep.equal {
readOnly: @readOnlyToken,
readAndWrite: @readAndWriteToken
}
done()