chai = require('chai') chai.should() sinon = require("sinon") Errors = require "../../../../app/js/Features/Errors/Errors" modulePath = "../../../../app/js/Features/History/HistoryController" SandboxedModule = require('sandboxed-module') describe "HistoryController", -> beforeEach -> @callback = sinon.stub() @user_id = "user-id-123" @AuthenticationController = getLoggedInUserId: sinon.stub().returns(@user_id) @HistoryController = SandboxedModule.require modulePath, requires: "request" : @request = sinon.stub() "settings-sharelatex": @settings = {} "logger-sharelatex": @logger = {log: sinon.stub(), error: sinon.stub()} "../Authentication/AuthenticationController": @AuthenticationController "../Errors/Errors": Errors "./HistoryManager": @HistoryManager = {} "../Project/ProjectDetailsHandler": @ProjectDetailsHandler = {} "../Project/ProjectEntityUpdateHandler": @ProjectEntityUpdateHandler = {} @settings.apis = trackchanges: enabled: false url: "http://trackchanges.example.com" project_history: url: "http://project_history.example.com" describe "selectHistoryApi", -> beforeEach -> @req = { url: "/mock/url", method: "POST" } @res = "mock-res" @next = sinon.stub() describe "for a project with project history", -> beforeEach -> @ProjectDetailsHandler.getDetails = sinon.stub().callsArgWith(1, null, {overleaf:{history:{id: 42, display:true}}}) @HistoryController.selectHistoryApi @req, @res, @next it "should set the flag for project history to true", -> @req.useProjectHistory.should.equal true describe "for any other project ", -> beforeEach -> @ProjectDetailsHandler.getDetails = sinon.stub().callsArgWith(1, null, {}) @HistoryController.selectHistoryApi @req, @res, @next it "should not set the flag for project history to false", -> @req.useProjectHistory.should.equal false describe "proxyToHistoryApi", -> beforeEach -> @req = { url: "/mock/url", method: "POST" } @res = "mock-res" @next = sinon.stub() @proxy = events: {} pipe: sinon.stub() on: (event, handler) -> @events[event] = handler @request.returns @proxy describe "for a project with the project history flag", -> beforeEach -> @req.useProjectHistory = true @HistoryController.proxyToHistoryApi @req, @res, @next it "should get the user id", -> @AuthenticationController.getLoggedInUserId .calledWith(@req) .should.equal true it "should call the project history api", -> @request .calledWith({ url: "#{@settings.apis.project_history.url}#{@req.url}" method: @req.method headers: "X-User-Id": @user_id }) .should.equal true it "should pipe the response to the client", -> @proxy.pipe .calledWith(@res) .should.equal true describe "for a project without the project history flag", -> beforeEach -> @req.useProjectHistory = false @HistoryController.proxyToHistoryApi @req, @res, @next it "should get the user id", -> @AuthenticationController.getLoggedInUserId .calledWith(@req) .should.equal true it "should call the track changes api", -> @request .calledWith({ url: "#{@settings.apis.trackchanges.url}#{@req.url}" method: @req.method headers: "X-User-Id": @user_id }) .should.equal true it "should pipe the response to the client", -> @proxy.pipe .calledWith(@res) .should.equal true describe "with an error", -> beforeEach -> @HistoryController.proxyToHistoryApi @req, @res, @next @proxy.events["error"].call(@proxy, @error = new Error("oops")) it "should pass the error up the call chain", -> @next.calledWith(@error).should.equal true describe "proxyToHistoryApiAndInjectUserDetails", -> beforeEach -> @req = { url: "/mock/url", method: "POST" } @res = json: sinon.stub() @next = sinon.stub() @request.yields(null, {statusCode: 200}, @data = "mock-data") @HistoryManager.injectUserDetails = sinon.stub().yields(null, @data_with_users = "mock-injected-data") describe "for a project with the project history flag", -> beforeEach -> @req.useProjectHistory = true @HistoryController.proxyToHistoryApiAndInjectUserDetails @req, @res, @next it "should get the user id", -> @AuthenticationController.getLoggedInUserId .calledWith(@req) .should.equal true it "should call the project history api", -> @request .calledWith({ url: "#{@settings.apis.project_history.url}#{@req.url}" method: @req.method json: true headers: "X-User-Id": @user_id }) .should.equal true it "should inject the user data", -> @HistoryManager.injectUserDetails .calledWith(@data) .should.equal true it "should return the data with users to the client", -> @res.json.calledWith(@data_with_users).should.equal true describe "for a project without the project history flag", -> beforeEach -> @req.useProjectHistory = false @HistoryController.proxyToHistoryApiAndInjectUserDetails @req, @res, @next it "should get the user id", -> @AuthenticationController.getLoggedInUserId .calledWith(@req) .should.equal true it "should call the track changes api", -> @request .calledWith({ url: "#{@settings.apis.trackchanges.url}#{@req.url}" method: @req.method json: true headers: "X-User-Id": @user_id }) .should.equal true it "should inject the user data", -> @HistoryManager.injectUserDetails .calledWith(@data) .should.equal true it "should return the data with users to the client", -> @res.json.calledWith(@data_with_users).should.equal true describe "proxyToHistoryApiAndInjectUserDetails (with the history API failing)", -> beforeEach -> @req = { url: "/mock/url", method: "POST", useProjectHistory: true } @res = { json: sinon.stub() } @next = sinon.stub() @request.yields(null, {statusCode: 500}, @data = "mock-data") @HistoryManager.injectUserDetails = sinon.stub().yields(null, @data_with_users = "mock-injected-data") @HistoryController.proxyToHistoryApiAndInjectUserDetails @req, @res, @next it "should not inject the user data", -> @HistoryManager.injectUserDetails .calledWith(@data) .should.equal false it "should not return the data with users to the client", -> @res.json.calledWith(@data_with_users).should.equal false describe "resyncProjectHistory", -> describe "for a project without project-history enabled", -> beforeEach -> @project_id = 'mock-project-id' @req = params: Project_id: @project_id @res = sendStatus: sinon.stub() @next = sinon.stub() @error = new Errors.ProjectHistoryDisabledError() @ProjectEntityUpdateHandler.resyncProjectHistory = sinon.stub().yields(@error) @HistoryController.resyncProjectHistory @req, @res, @next it "response with a 404", -> @res.sendStatus .calledWith(404) .should.equal true describe "for a project with project-history enabled", -> beforeEach -> @project_id = 'mock-project-id' @req = params: Project_id: @project_id @res = sendStatus: sinon.stub() @next = sinon.stub() @ProjectEntityUpdateHandler.resyncProjectHistory = sinon.stub().yields() @HistoryController.resyncProjectHistory @req, @res, @next it "resyncs the project", -> @ProjectEntityUpdateHandler.resyncProjectHistory .calledWith(@project_id) .should.equal true it "responds with a 204", -> @res.sendStatus .calledWith(204) .should.equal true