diff --git a/services/track-changes/app/coffee/RedisManager.coffee b/services/track-changes/app/coffee/RedisManager.coffee new file mode 100644 index 0000000000..81a1375bf6 --- /dev/null +++ b/services/track-changes/app/coffee/RedisManager.coffee @@ -0,0 +1,21 @@ +Settings = require "settings-sharelatex" +redis = require('redis') +redisConf = Settings.redis?.web or {host: "localhost", port: 6379} +rclient = redis.createClient(redisConf.port, redisConf.host) +rclient.auth(redisConf.password) + +buildRawUpdatesKey = (doc_id) -> "UncompressedHistoryOps:#{doc_id}" + +module.exports = RedisManager = + getOldestRawUpdates: (doc_id, batchSize, callback = (error, rawUpdates) ->) -> + key = buildRawUpdatesKey(doc_id) + rclient.lrange key, 0, batchSize - 1, (error, jsonUpdates) -> + try + rawUpdates = ( JSON.parse(update) for update in jsonUpdates or [] ) + catch e + return callback(e) + callback null, rawUpdates + + deleteOldestRawUpdates: (doc_id, batchSize, callback = (error, rawUpdates) ->) -> + key = buildRawUpdatesKey(doc_id) + rclient.ltrim key, batchSize, -1, callback diff --git a/services/track-changes/test/unit/coffee/RedisManager/RedisManagerTests.coffee b/services/track-changes/test/unit/coffee/RedisManager/RedisManagerTests.coffee new file mode 100644 index 0000000000..669e64103d --- /dev/null +++ b/services/track-changes/test/unit/coffee/RedisManager/RedisManagerTests.coffee @@ -0,0 +1,45 @@ +sinon = require('sinon') +chai = require('chai') +should = chai.should() +expect = chai.expect +modulePath = "../../../../app/js/RedisManager.js" +SandboxedModule = require('sandboxed-module') + +describe "RedisManager", -> + beforeEach -> + @RedisManager = SandboxedModule.require modulePath, requires: + "redis" : + createClient: () => @rclient = + auth: sinon.stub() + "settings-sharelatex": {} + @doc_id = "doc-id-123" + @batchSize = 100 + @callback = sinon.stub() + + describe "getOldestRawUpdates", -> + beforeEach -> + @rawUpdates = [ {v: 42, op: "mock-op-42"}, { v: 45, op: "mock-op-45" }] + @jsonUpdates = (JSON.stringify(update) for update in @rawUpdates) + @rclient.lrange = sinon.stub().callsArgWith(3, null, @jsonUpdates) + @RedisManager.getOldestRawUpdates @doc_id, @batchSize, @callback + + it "should read the updates from redis", -> + @rclient.lrange + .calledWith("UncompressedHistoryOps:#{@doc_id}", 0, @batchSize - 1) + .should.equal true + + it "should call the callback with the parsed ops", -> + @callback.calledWith(null, @rawUpdates).should.equal true + + describe "deleteOldestRawUpdates", -> + beforeEach -> + @rclient.ltrim = sinon.stub().callsArg(3) + @RedisManager.deleteOldestRawUpdates @doc_id, @batchSize, @callback + + it "should delete the updates from redis", -> + @rclient.ltrim + .calledWith("UncompressedHistoryOps:#{@doc_id}", @batchSize, -1) + .should.equal true + + it "should call the callback", -> + @callback.called.should.equal true