2014-02-26 10:56:52 -05:00
|
|
|
SandboxedModule = require('sandboxed-module')
|
|
|
|
sinon = require('sinon')
|
|
|
|
require('chai').should()
|
2016-12-01 11:50:55 -05:00
|
|
|
modulePath = require('path').join __dirname, '../../../../app/js/HistoryManager'
|
2014-02-26 10:56:52 -05:00
|
|
|
|
2016-12-01 11:50:55 -05:00
|
|
|
describe "HistoryManager", ->
|
2014-02-26 10:56:52 -05:00
|
|
|
beforeEach ->
|
2016-12-01 11:50:55 -05:00
|
|
|
@HistoryManager = SandboxedModule.require modulePath, requires:
|
2014-02-26 10:56:52 -05:00
|
|
|
"request": @request = {}
|
2017-10-05 08:45:29 -04:00
|
|
|
"settings-sharelatex": @Settings = {
|
|
|
|
apis:
|
|
|
|
project_history:
|
|
|
|
enabled: true
|
|
|
|
url: "http://project_history.example.com"
|
|
|
|
trackchanges:
|
|
|
|
url: "http://trackchanges.example.com"
|
|
|
|
}
|
2019-11-15 11:53:16 -05:00
|
|
|
"logger-sharelatex": @logger = { log: sinon.stub(), error: sinon.stub(), debug: sinon.stub() }
|
2018-03-07 08:29:53 -05:00
|
|
|
"./DocumentManager": @DocumentManager = {}
|
2017-04-13 12:00:42 -04:00
|
|
|
"./HistoryRedisManager": @HistoryRedisManager = {}
|
2018-03-07 08:29:53 -05:00
|
|
|
"./RedisManager": @RedisManager = {}
|
2018-03-09 09:14:14 -05:00
|
|
|
"./ProjectHistoryRedisManager": @ProjectHistoryRedisManager = {}
|
2019-11-22 04:14:32 -05:00
|
|
|
"./Metrics": @metrics = {inc: sinon.stub()}
|
2014-03-19 11:56:44 -04:00
|
|
|
@project_id = "mock-project-id"
|
2014-02-26 10:56:52 -05:00
|
|
|
@doc_id = "mock-doc-id"
|
|
|
|
@callback = sinon.stub()
|
|
|
|
|
2018-02-22 05:16:41 -05:00
|
|
|
describe "flushDocChangesAsync", ->
|
2017-10-05 08:45:29 -04:00
|
|
|
beforeEach ->
|
|
|
|
@request.post = sinon.stub().callsArgWith(1, null, statusCode: 204)
|
|
|
|
|
2019-11-15 11:53:16 -05:00
|
|
|
describe "when the project uses track changes", ->
|
|
|
|
beforeEach ->
|
|
|
|
@RedisManager.getHistoryType = sinon.stub().yields(null, 'track-changes')
|
|
|
|
@HistoryManager.flushDocChangesAsync @project_id, @doc_id
|
2014-02-26 10:56:52 -05:00
|
|
|
|
2019-11-15 11:53:16 -05:00
|
|
|
it "should send a request to the track changes api", ->
|
|
|
|
@request.post
|
|
|
|
.calledWith("#{@Settings.apis.trackchanges.url}/project/#{@project_id}/doc/#{@doc_id}/flush")
|
|
|
|
.should.equal true
|
|
|
|
|
|
|
|
describe "when the project uses project history", ->
|
|
|
|
beforeEach ->
|
|
|
|
@RedisManager.getHistoryType = sinon.stub().yields(null, 'project-history')
|
|
|
|
@HistoryManager.flushDocChangesAsync @project_id, @doc_id
|
|
|
|
|
|
|
|
it "should not send a request to the track changes api", ->
|
|
|
|
@request.post
|
|
|
|
.called
|
|
|
|
.should.equal false
|
2017-10-05 08:45:29 -04:00
|
|
|
|
2018-01-24 06:37:28 -05:00
|
|
|
describe "flushProjectChangesAsync", ->
|
2017-10-05 08:45:29 -04:00
|
|
|
beforeEach ->
|
|
|
|
@request.post = sinon.stub().callsArgWith(1, null, statusCode: 204)
|
|
|
|
|
2018-01-24 06:37:28 -05:00
|
|
|
@HistoryManager.flushProjectChangesAsync @project_id
|
2017-10-05 08:45:29 -04:00
|
|
|
|
|
|
|
it "should send a request to the project history api", ->
|
|
|
|
@request.post
|
2019-06-03 05:01:10 -04:00
|
|
|
.calledWith({url: "#{@Settings.apis.project_history.url}/project/#{@project_id}/flush", qs:{background:true}})
|
2017-10-05 08:45:29 -04:00
|
|
|
.should.equal true
|
2014-02-28 13:29:05 -05:00
|
|
|
|
2019-08-15 05:54:12 -04:00
|
|
|
describe "flushProjectChanges", ->
|
|
|
|
|
|
|
|
describe "in the normal case", ->
|
|
|
|
beforeEach ->
|
|
|
|
@request.post = sinon.stub().callsArgWith(1, null, statusCode: 204)
|
|
|
|
@HistoryManager.flushProjectChanges @project_id, {background:true}
|
|
|
|
|
|
|
|
it "should send a request to the project history api", ->
|
|
|
|
@request.post
|
|
|
|
.calledWith({url: "#{@Settings.apis.project_history.url}/project/#{@project_id}/flush", qs:{background:true}})
|
|
|
|
.should.equal true
|
|
|
|
|
|
|
|
describe "with the skip_history_flush option", ->
|
|
|
|
beforeEach ->
|
|
|
|
@request.post = sinon.stub()
|
|
|
|
@HistoryManager.flushProjectChanges @project_id, {skip_history_flush:true}
|
|
|
|
|
|
|
|
it "should not send a request to the project history api", ->
|
|
|
|
@request.post
|
|
|
|
.called
|
|
|
|
.should.equal false
|
|
|
|
|
2017-05-09 07:02:27 -04:00
|
|
|
describe "recordAndFlushHistoryOps", ->
|
2014-02-28 13:29:05 -05:00
|
|
|
beforeEach ->
|
2017-10-05 08:45:29 -04:00
|
|
|
@ops = [ 'mock-ops' ]
|
|
|
|
@project_ops_length = 10
|
|
|
|
@doc_ops_length = 5
|
2014-02-28 13:29:05 -05:00
|
|
|
|
2018-01-24 06:37:28 -05:00
|
|
|
@HistoryManager.flushProjectChangesAsync = sinon.stub()
|
2017-10-05 08:45:29 -04:00
|
|
|
@HistoryRedisManager.recordDocHasHistoryOps = sinon.stub().callsArg(3)
|
2018-02-22 05:16:41 -05:00
|
|
|
@HistoryManager.flushDocChangesAsync = sinon.stub()
|
2017-10-05 08:45:29 -04:00
|
|
|
|
|
|
|
describe "with no ops", ->
|
2014-02-28 13:29:05 -05:00
|
|
|
beforeEach ->
|
2017-10-05 08:45:29 -04:00
|
|
|
@HistoryManager.recordAndFlushHistoryOps(
|
|
|
|
@project_id, @doc_id, [], @doc_ops_length, @project_ops_length, @callback
|
|
|
|
)
|
2014-02-28 13:29:05 -05:00
|
|
|
|
2017-10-05 08:45:29 -04:00
|
|
|
it "should not flush project changes", ->
|
2018-01-24 06:37:28 -05:00
|
|
|
@HistoryManager.flushProjectChangesAsync.called.should.equal false
|
2017-10-05 08:45:29 -04:00
|
|
|
|
|
|
|
it "should not record doc has history ops", ->
|
|
|
|
@HistoryRedisManager.recordDocHasHistoryOps.called.should.equal false
|
|
|
|
|
|
|
|
it "should not flush doc changes", ->
|
2018-02-22 05:16:41 -05:00
|
|
|
@HistoryManager.flushDocChangesAsync.called.should.equal false
|
2014-03-21 08:41:05 -04:00
|
|
|
|
|
|
|
it "should call the callback", ->
|
|
|
|
@callback.called.should.equal true
|
2014-02-28 13:29:05 -05:00
|
|
|
|
2017-10-05 08:45:29 -04:00
|
|
|
describe "with enough ops to flush project changes", ->
|
2014-03-21 08:41:05 -04:00
|
|
|
beforeEach ->
|
2018-01-31 06:27:40 -05:00
|
|
|
@HistoryManager.shouldFlushHistoryOps = sinon.stub()
|
|
|
|
@HistoryManager.shouldFlushHistoryOps.withArgs(@project_ops_length).returns(true)
|
|
|
|
@HistoryManager.shouldFlushHistoryOps.withArgs(@doc_ops_length).returns(false)
|
2016-08-23 11:00:46 -04:00
|
|
|
|
2017-10-05 08:45:29 -04:00
|
|
|
@HistoryManager.recordAndFlushHistoryOps(
|
|
|
|
@project_id, @doc_id, @ops, @doc_ops_length, @project_ops_length, @callback
|
|
|
|
)
|
|
|
|
|
|
|
|
it "should flush project changes", ->
|
2018-01-24 06:37:28 -05:00
|
|
|
@HistoryManager.flushProjectChangesAsync
|
2017-10-05 08:45:29 -04:00
|
|
|
.calledWith(@project_id)
|
2016-08-23 11:00:46 -04:00
|
|
|
.should.equal true
|
|
|
|
|
2017-10-05 08:45:29 -04:00
|
|
|
it "should record doc has history ops", ->
|
|
|
|
@HistoryRedisManager.recordDocHasHistoryOps
|
|
|
|
.calledWith(@project_id, @doc_id, @ops)
|
|
|
|
|
|
|
|
it "should not flush doc changes", ->
|
2018-02-22 05:16:41 -05:00
|
|
|
@HistoryManager.flushDocChangesAsync.called.should.equal false
|
2017-10-05 08:45:29 -04:00
|
|
|
|
|
|
|
it "should call the callback", ->
|
|
|
|
@callback.called.should.equal true
|
|
|
|
|
|
|
|
describe "with enough ops to flush doc changes", ->
|
2016-08-23 11:00:46 -04:00
|
|
|
beforeEach ->
|
2018-01-31 06:27:40 -05:00
|
|
|
@HistoryManager.shouldFlushHistoryOps = sinon.stub()
|
|
|
|
@HistoryManager.shouldFlushHistoryOps.withArgs(@project_ops_length).returns(false)
|
|
|
|
@HistoryManager.shouldFlushHistoryOps.withArgs(@doc_ops_length).returns(true)
|
2017-10-05 08:45:29 -04:00
|
|
|
|
|
|
|
@HistoryManager.recordAndFlushHistoryOps(
|
|
|
|
@project_id, @doc_id, @ops, @doc_ops_length, @project_ops_length, @callback
|
|
|
|
)
|
2014-03-21 08:41:05 -04:00
|
|
|
|
2017-10-05 08:45:29 -04:00
|
|
|
it "should not flush project changes", ->
|
2018-01-24 06:37:28 -05:00
|
|
|
@HistoryManager.flushProjectChangesAsync.called.should.equal false
|
2017-10-05 08:45:29 -04:00
|
|
|
|
|
|
|
it "should record doc has history ops", ->
|
|
|
|
@HistoryRedisManager.recordDocHasHistoryOps
|
|
|
|
.calledWith(@project_id, @doc_id, @ops)
|
|
|
|
|
|
|
|
it "should flush doc changes", ->
|
2018-02-22 05:16:41 -05:00
|
|
|
@HistoryManager.flushDocChangesAsync
|
2014-03-21 08:41:05 -04:00
|
|
|
.calledWith(@project_id, @doc_id)
|
|
|
|
.should.equal true
|
|
|
|
|
2017-10-05 08:45:29 -04:00
|
|
|
it "should call the callback", ->
|
|
|
|
@callback.called.should.equal true
|
|
|
|
|
|
|
|
describe "when recording doc has history ops errors", ->
|
2014-03-21 08:41:05 -04:00
|
|
|
beforeEach ->
|
2017-10-05 08:45:29 -04:00
|
|
|
@error = new Error("error")
|
2017-05-09 04:32:56 -04:00
|
|
|
@HistoryRedisManager.recordDocHasHistoryOps =
|
2017-10-05 08:45:29 -04:00
|
|
|
sinon.stub().callsArgWith(3, @error)
|
|
|
|
|
|
|
|
@HistoryManager.recordAndFlushHistoryOps(
|
|
|
|
@project_id, @doc_id, @ops, @doc_ops_length, @project_ops_length, @callback
|
|
|
|
)
|
|
|
|
|
|
|
|
it "should not flush doc changes", ->
|
2018-02-22 05:16:41 -05:00
|
|
|
@HistoryManager.flushDocChangesAsync.called.should.equal false
|
2017-10-05 08:45:29 -04:00
|
|
|
|
|
|
|
it "should call the callback with the error", ->
|
|
|
|
@callback.calledWith(@error).should.equal true
|
|
|
|
|
2018-01-31 06:27:40 -05:00
|
|
|
describe "shouldFlushHistoryOps", ->
|
2017-10-05 08:45:29 -04:00
|
|
|
it "should return false if the number of ops is not known", ->
|
2018-01-31 06:27:40 -05:00
|
|
|
@HistoryManager.shouldFlushHistoryOps(null, ['a', 'b', 'c'].length, 1).should.equal false
|
2017-10-05 08:45:29 -04:00
|
|
|
|
|
|
|
it "should return false if the updates didn't take us past the threshold", ->
|
|
|
|
# Currently there are 14 ops
|
|
|
|
# Previously we were on 11 ops
|
|
|
|
# We didn't pass over a multiple of 5
|
2018-01-31 06:27:40 -05:00
|
|
|
@HistoryManager.shouldFlushHistoryOps(14, ['a', 'b', 'c'].length, 5).should.equal false
|
2017-10-05 08:45:29 -04:00
|
|
|
|
|
|
|
it "should return true if the updates took to the threshold", ->
|
|
|
|
# Currently there are 15 ops
|
|
|
|
# Previously we were on 12 ops
|
|
|
|
# We've reached a new multiple of 5
|
2018-01-31 06:27:40 -05:00
|
|
|
@HistoryManager.shouldFlushHistoryOps(15, ['a', 'b', 'c'].length, 5).should.equal true
|
2017-10-05 08:45:29 -04:00
|
|
|
|
|
|
|
it "should return true if the updates took past the threshold", ->
|
|
|
|
# Currently there are 19 ops
|
|
|
|
# Previously we were on 16 ops
|
|
|
|
# We didn't pass over a multiple of 5
|
2018-01-31 06:27:40 -05:00
|
|
|
@HistoryManager.shouldFlushHistoryOps(17, ['a', 'b', 'c'].length, 5).should.equal true
|
2018-03-07 08:29:53 -05:00
|
|
|
|
|
|
|
describe "resyncProjectHistory", ->
|
|
|
|
beforeEach ->
|
2018-04-23 07:08:04 -04:00
|
|
|
@projectHistoryId = 'history-id-1234'
|
2018-03-07 08:29:53 -05:00
|
|
|
@docs = [
|
|
|
|
doc: @doc_id
|
|
|
|
path: 'main.tex'
|
|
|
|
]
|
|
|
|
@files = [
|
|
|
|
file: 'mock-file-id'
|
|
|
|
path: 'universe.png'
|
|
|
|
url: "www.filestore.test/#{@project_id}/mock-file-id"
|
|
|
|
]
|
2018-03-09 09:14:14 -05:00
|
|
|
@ProjectHistoryRedisManager.queueResyncProjectStructure = sinon.stub().yields()
|
2018-03-07 08:29:53 -05:00
|
|
|
@DocumentManager.resyncDocContentsWithLock = sinon.stub().yields()
|
2018-04-23 07:08:04 -04:00
|
|
|
@HistoryManager.resyncProjectHistory @project_id, @projectHistoryId, @docs, @files, @callback
|
2018-03-07 08:29:53 -05:00
|
|
|
|
|
|
|
it "should queue a project structure reync", ->
|
2018-03-09 09:14:14 -05:00
|
|
|
@ProjectHistoryRedisManager.queueResyncProjectStructure
|
2018-04-23 07:08:04 -04:00
|
|
|
.calledWith(@project_id, @projectHistoryId, @docs, @files)
|
2018-03-07 08:29:53 -05:00
|
|
|
.should.equal true
|
|
|
|
|
|
|
|
it "should queue doc content reyncs", ->
|
|
|
|
@DocumentManager
|
|
|
|
.resyncDocContentsWithLock
|
|
|
|
.calledWith(@project_id, @doc_id)
|
|
|
|
.should.equal true
|
|
|
|
|
|
|
|
it "should call the callback", ->
|
|
|
|
@callback.called.should.equal true
|