Просмотр исходного кода

add acceptance tests for RedisMigrationManager

Brian Gough 6 лет назад
Родитель
Сommit
c2714f9ae9

+ 320 - 0
services/document-updater/test/acceptance/coffee/RedisMigrationManagerTests.coffee

@@ -0,0 +1,320 @@
+sinon = require "sinon"
+chai = require("chai")
+chai.should()
+expect = chai.expect
+async = require "async"
+Settings = require('settings-sharelatex')
+rclient_old = require("redis-sharelatex").createClient(Settings.redis.project_history)
+rclient_new = require("redis-sharelatex").createClient(Settings.redis.new_project_history)
+rclient_du = require("redis-sharelatex").createClient(Settings.redis.documentupdater)
+Keys = Settings.redis.documentupdater.key_schema
+HistoryKeys = Settings.redis.history.key_schema
+ProjectHistoryKeys = Settings.redis.project_history.key_schema
+NewProjectHistoryKeys = Settings.redis.new_project_history.key_schema
+
+MockTrackChangesApi = require "./helpers/MockTrackChangesApi"
+MockWebApi = require "./helpers/MockWebApi"
+DocUpdaterClient = require "./helpers/DocUpdaterClient"
+DocUpdaterApp = require "./helpers/DocUpdaterApp"
+
+describe "RedisMigrationManager", ->
+	before (done) ->
+		@lines = ["one", "two", "three"]
+		@version = 42
+		@update =
+			doc: @doc_id
+			op: [{
+				i: "one and a half\n"
+				p: 4
+			}]
+			v: @version
+		DocUpdaterApp.ensureRunning(done)
+
+	describe "when the migration phase is 'prepare' (default)", ->
+
+		describe "when there is no migration flag", ->
+			before (done) ->
+				[@project_id, @doc_id] = [DocUpdaterClient.randomId(), DocUpdaterClient.randomId()]
+
+				MockWebApi.insertDoc @project_id, @doc_id, {lines: @lines, version: @version}
+				DocUpdaterClient.preloadDoc @project_id, @doc_id, (error) =>
+					throw error if error?
+					sinon.spy MockWebApi, "getDocument"
+					DocUpdaterClient.sendUpdate @project_id, @doc_id, @update, (error) ->
+						throw error if error?
+						setTimeout done, 200
+				return null
+
+			after ->
+				MockWebApi.getDocument.restore()
+
+			it "should push the applied updates to old redis", (done) ->
+				rclient_old.lrange ProjectHistoryKeys.projectHistoryOps({@project_id}), 0, -1, (error, updates) =>
+					JSON.parse(updates[0]).op.should.deep.equal @update.op
+					done()
+				return null
+
+			it "should not push the applied updates to the new redis", (done) ->
+				rclient_new.exists ProjectHistoryKeys.projectHistoryOps({@project_id}), (error, result) =>
+					result.should.equal 0
+					done()
+				return null
+
+			it "should not set the migration flag for the project", (done) ->
+				rclient_new.exists NewProjectHistoryKeys.projectHistoryMigrationKey({@project_id}), (error, result) =>
+					result.should.equal 0
+					done()
+				return null
+
+		describe "when the migration flag is set for the project", ->
+			before (done) ->
+				[@project_id, @doc_id] = [DocUpdaterClient.randomId(), DocUpdaterClient.randomId()]
+
+				rclient_new.set NewProjectHistoryKeys.projectHistoryMigrationKey({@project_id}), '1', (error) =>
+					throw error if error?
+					MockWebApi.insertDoc @project_id, @doc_id, {lines: @lines, version: @version}
+					DocUpdaterClient.preloadDoc @project_id, @doc_id, (error) =>
+						throw error if error?
+						sinon.spy MockWebApi, "getDocument"
+						DocUpdaterClient.sendUpdate @project_id, @doc_id, @update, (error) ->
+							throw error if error?
+							setTimeout done, 200
+				return null
+
+			after (done) ->
+				MockWebApi.getDocument.restore()
+				rclient_new.del NewProjectHistoryKeys.projectHistoryMigrationKey({@project_id}), done
+				return null
+
+			it "should push the applied updates to the new redis", (done) ->
+				rclient_new.lrange ProjectHistoryKeys.projectHistoryOps({@project_id}), 0, -1, (error, updates) =>
+					JSON.parse(updates[0]).op.should.deep.equal @update.op
+					done()
+				return null
+
+			it "should not push the applied updates to the old redis", (done) ->
+				rclient_old.exists ProjectHistoryKeys.projectHistoryOps({@project_id}), (error, result) =>
+					result.should.equal 0
+					done()
+				return null
+
+			it "should keep the migration flag for the project", (done) ->
+				rclient_new.exists NewProjectHistoryKeys.projectHistoryMigrationKey({@project_id}), (error, result) =>
+					result.should.equal 1
+					done()
+				return null
+
+	describe "when the migration phase is 'switch'", ->
+		before ->
+			Settings.redis.new_project_history.migration_phase = 'switch'
+
+		describe "when the old queue is empty", ->
+			before (done) ->
+				[@project_id, @doc_id] = [DocUpdaterClient.randomId(), DocUpdaterClient.randomId()]
+
+				MockWebApi.insertDoc @project_id, @doc_id, {lines: @lines, version: @version}
+				DocUpdaterClient.preloadDoc @project_id, @doc_id, (error) =>
+					throw error if error?
+					sinon.spy MockWebApi, "getDocument"
+					DocUpdaterClient.sendUpdate @project_id, @doc_id, @update, (error) ->
+						throw error if error?
+						setTimeout done, 200
+				return null
+
+			after ->
+				MockWebApi.getDocument.restore()
+
+			it "should push the applied updates to the new redis", (done) ->
+				rclient_new.lrange ProjectHistoryKeys.projectHistoryOps({@project_id}), 0, -1, (error, updates) =>
+					JSON.parse(updates[0]).op.should.deep.equal @update.op
+					done()
+				return null
+
+			it "should not push the applied updates to the old redis", (done) ->
+				rclient_old.exists ProjectHistoryKeys.projectHistoryOps({@project_id}), (error, result) =>
+					result.should.equal 0
+					done()
+				return null
+
+			it "should set the migration flag for the project", (done) ->
+				rclient_new.get NewProjectHistoryKeys.projectHistoryMigrationKey({@project_id}), (error, result) =>
+					result.should.equal "NEW"
+					done()
+				return null
+
+		describe "when the old queue is not empty", ->
+			before (done) ->
+				[@project_id, @doc_id] = [DocUpdaterClient.randomId(), DocUpdaterClient.randomId()]
+
+				MockWebApi.insertDoc @project_id, @doc_id, {lines: @lines, version: @version}
+				DocUpdaterClient.preloadDoc @project_id, @doc_id, (error) =>
+					throw error if error?
+					sinon.spy MockWebApi, "getDocument"
+					rclient_old.rpush ProjectHistoryKeys.projectHistoryOps({@project_id}), JSON.stringify({op: "dummy-op"}), (error) =>
+						throw error if error?
+						DocUpdaterClient.sendUpdate @project_id, @doc_id, @update, (error) ->
+							throw error if error?
+							setTimeout done, 200
+				return null
+
+			after ->
+				MockWebApi.getDocument.restore()
+
+			it "should push the applied updates to the old redis", (done) ->
+				rclient_old.lrange ProjectHistoryKeys.projectHistoryOps({@project_id}), 0, -1, (error, updates) =>
+					JSON.parse(updates[0]).op.should.deep.equal "dummy-op"
+					JSON.parse(updates[1]).op.should.deep.equal @update.op
+					done()
+				return null
+
+			it "should not push the applied updates to the new redis", (done) ->
+				rclient_new.exists ProjectHistoryKeys.projectHistoryOps({@project_id}), (error, result) =>
+					result.should.equal 0
+					done()
+				return null
+
+			it "should not set the migration flag for the project", (done) ->
+				rclient_new.exists NewProjectHistoryKeys.projectHistoryMigrationKey({@project_id}), (error, result) =>
+					result.should.equal 0
+					done()
+				return null
+
+		describe "when the migration flag is set for the project", ->
+			before (done) ->
+				[@project_id, @doc_id] = [DocUpdaterClient.randomId(), DocUpdaterClient.randomId()]
+
+				rclient_new.set NewProjectHistoryKeys.projectHistoryMigrationKey({@project_id}), '1', (error) =>
+					throw error if error?
+					MockWebApi.insertDoc @project_id, @doc_id, {lines: @lines, version: @version}
+					DocUpdaterClient.preloadDoc @project_id, @doc_id, (error) =>
+						throw error if error?
+						sinon.spy MockWebApi, "getDocument"
+						DocUpdaterClient.sendUpdate @project_id, @doc_id, @update, (error) ->
+							throw error if error?
+							setTimeout done, 200
+				return null
+
+			after (done) ->
+				MockWebApi.getDocument.restore()
+				rclient_new.del NewProjectHistoryKeys.projectHistoryMigrationKey({@project_id}), done
+				return null
+
+			it "should push the applied updates to the new redis", (done) ->
+				rclient_new.lrange ProjectHistoryKeys.projectHistoryOps({@project_id}), 0, -1, (error, updates) =>
+					JSON.parse(updates[0]).op.should.deep.equal @update.op
+					done()
+				return null
+
+			it "should not push the applied updates to the old redis", (done) ->
+				rclient_old.exists ProjectHistoryKeys.projectHistoryOps({@project_id}), (error, result) =>
+					result.should.equal 0
+					done()
+				return null
+
+			it "should keep the migration flag for the project", (done) ->
+				rclient_new.exists NewProjectHistoryKeys.projectHistoryMigrationKey({@project_id}), (error, result) =>
+					result.should.equal 1
+					done()
+				return null
+
+	describe "when the migration phase is 'rollback'", ->
+		before ->
+			Settings.redis.new_project_history.migration_phase = 'rollback'
+
+		describe "when the old queue is empty", ->
+			before (done) ->
+				[@project_id, @doc_id] = [DocUpdaterClient.randomId(), DocUpdaterClient.randomId()]
+
+				MockWebApi.insertDoc @project_id, @doc_id, {lines: @lines, version: @version}
+				DocUpdaterClient.preloadDoc @project_id, @doc_id, (error) =>
+					throw error if error?
+					sinon.spy MockWebApi, "getDocument"
+					DocUpdaterClient.sendUpdate @project_id, @doc_id, @update, (error) ->
+						throw error if error?
+						setTimeout done, 200
+				return null
+
+			after ->
+				MockWebApi.getDocument.restore()
+
+			it "should push the applied updates to the old redis", (done) ->
+				rclient_old.lrange ProjectHistoryKeys.projectHistoryOps({@project_id}), 0, -1, (error, updates) =>
+					JSON.parse(updates[0]).op.should.deep.equal @update.op
+					done()
+				return null
+
+			it "should not push the applied updates to the new redis", (done) ->
+				rclient_new.exists ProjectHistoryKeys.projectHistoryOps({@project_id}), (error, result) =>
+					result.should.equal 0
+					done()
+				return null
+
+		describe "when the new queue is not empty", ->
+			before (done) ->
+				[@project_id, @doc_id] = [DocUpdaterClient.randomId(), DocUpdaterClient.randomId()]
+
+				MockWebApi.insertDoc @project_id, @doc_id, {lines: @lines, version: @version}
+				DocUpdaterClient.preloadDoc @project_id, @doc_id, (error) =>
+					throw error if error?
+					sinon.spy MockWebApi, "getDocument"
+					rclient_new.rpush ProjectHistoryKeys.projectHistoryOps({@project_id}), JSON.stringify({op: "dummy-op"}), (error) =>
+						throw error if error?
+						DocUpdaterClient.sendUpdate @project_id, @doc_id, @update, (error) ->
+							throw error if error?
+							setTimeout done, 200
+				return null
+
+			after ->
+				MockWebApi.getDocument.restore()
+
+			it "should push the applied updates to the old redis", (done) ->
+				rclient_old.lrange ProjectHistoryKeys.projectHistoryOps({@project_id}), 0, -1, (error, updates) =>
+					JSON.parse(updates[0]).op.should.deep.equal @update.op
+					done()
+				return null
+
+			it "should not push the applied updates to the new redis", (done) ->
+				rclient_new.lrange ProjectHistoryKeys.projectHistoryOps({@project_id}), 0, -1, (error, updates) =>
+					JSON.parse(updates[0]).op.should.deep.equal "dummy-op"
+					updates.length.should.equal 1
+					done()
+				return null
+
+		describe "when the migration flag is set for the project", ->
+			before (done) ->
+				[@project_id, @doc_id] = [DocUpdaterClient.randomId(), DocUpdaterClient.randomId()]
+
+				rclient_new.set NewProjectHistoryKeys.projectHistoryMigrationKey({@project_id}), '1', (error) =>
+					throw error if error?
+					MockWebApi.insertDoc @project_id, @doc_id, {lines: @lines, version: @version}
+					DocUpdaterClient.preloadDoc @project_id, @doc_id, (error) =>
+						throw error if error?
+						sinon.spy MockWebApi, "getDocument"
+						DocUpdaterClient.sendUpdate @project_id, @doc_id, @update, (error) ->
+							throw error if error?
+							setTimeout done, 200
+				return null
+
+			after (done) ->
+				MockWebApi.getDocument.restore()
+				rclient_new.del NewProjectHistoryKeys.projectHistoryMigrationKey({@project_id}), done
+				return null
+
+			it "should push the applied updates to the old redis", (done) ->
+				rclient_old.lrange ProjectHistoryKeys.projectHistoryOps({@project_id}), 0, -1, (error, updates) =>
+					JSON.parse(updates[0]).op.should.deep.equal @update.op
+					done()
+				return null
+
+			it "should not push the applied updates to the new redis", (done) ->
+				rclient_new.exists ProjectHistoryKeys.projectHistoryOps({@project_id}), (error, result) =>
+					result.should.equal 0
+					done()
+				return null
+
+			it "should delete the migration flag for the project", (done) ->
+				rclient_new.exists NewProjectHistoryKeys.projectHistoryMigrationKey({@project_id}), (error, result) =>
+					result.should.equal 0
+					done()
+				return null
+