RealTimeRedisManagerTests.js 5.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171
  1. /* eslint-disable
  2. camelcase,
  3. no-return-assign,
  4. no-unused-vars,
  5. */
  6. // TODO: This file was created by bulk-decaffeinate.
  7. // Fix any style issues and re-enable lint.
  8. /*
  9. * decaffeinate suggestions:
  10. * DS102: Remove unnecessary code created because of implicit returns
  11. * Full docs: https://github.com/decaffeinate/decaffeinate/blob/master/docs/suggestions.md
  12. */
  13. const sinon = require('sinon')
  14. const chai = require('chai')
  15. const should = chai.should()
  16. const modulePath = '../../../../app/js/RealTimeRedisManager.js'
  17. const SandboxedModule = require('sandboxed-module')
  18. const Errors = require('../../../../app/js/Errors')
  19. describe('RealTimeRedisManager', function () {
  20. beforeEach(function () {
  21. this.rclient = {
  22. auth() {},
  23. exec: sinon.stub()
  24. }
  25. this.rclient.multi = () => this.rclient
  26. this.pubsubClient = { publish: sinon.stub() }
  27. this.RealTimeRedisManager = SandboxedModule.require(modulePath, {
  28. requires: {
  29. '@overleaf/redis-wrapper': {
  30. createClient: (config) =>
  31. config.name === 'pubsub' ? this.pubsubClient : this.rclient
  32. },
  33. 'settings-sharelatex': {
  34. redis: {
  35. documentupdater: (this.settings = {
  36. key_schema: {
  37. pendingUpdates({ doc_id }) {
  38. return `PendingUpdates:${doc_id}`
  39. }
  40. }
  41. }),
  42. pubsub: {
  43. name: 'pubsub'
  44. }
  45. }
  46. },
  47. 'logger-sharelatex': { log() {} },
  48. crypto: (this.crypto = {
  49. randomBytes: sinon
  50. .stub()
  51. .withArgs(4)
  52. .returns(Buffer.from([0x1, 0x2, 0x3, 0x4]))
  53. }),
  54. os: (this.os = { hostname: sinon.stub().returns('somehost') }),
  55. './Metrics': (this.metrics = { summary: sinon.stub() })
  56. }
  57. })
  58. this.doc_id = 'doc-id-123'
  59. this.project_id = 'project-id-123'
  60. return (this.callback = sinon.stub())
  61. })
  62. describe('getPendingUpdatesForDoc', function () {
  63. beforeEach(function () {
  64. this.rclient.lrange = sinon.stub()
  65. return (this.rclient.ltrim = sinon.stub())
  66. })
  67. describe('successfully', function () {
  68. beforeEach(function () {
  69. this.updates = [
  70. { op: [{ i: 'foo', p: 4 }] },
  71. { op: [{ i: 'foo', p: 4 }] }
  72. ]
  73. this.jsonUpdates = this.updates.map((update) => JSON.stringify(update))
  74. this.rclient.exec = sinon
  75. .stub()
  76. .callsArgWith(0, null, [this.jsonUpdates])
  77. return this.RealTimeRedisManager.getPendingUpdatesForDoc(
  78. this.doc_id,
  79. this.callback
  80. )
  81. })
  82. it('should get the pending updates', function () {
  83. return this.rclient.lrange
  84. .calledWith(`PendingUpdates:${this.doc_id}`, 0, 7)
  85. .should.equal(true)
  86. })
  87. it('should delete the pending updates', function () {
  88. return this.rclient.ltrim
  89. .calledWith(`PendingUpdates:${this.doc_id}`, 8, -1)
  90. .should.equal(true)
  91. })
  92. return it('should call the callback with the updates', function () {
  93. return this.callback.calledWith(null, this.updates).should.equal(true)
  94. })
  95. })
  96. return describe("when the JSON doesn't parse", function () {
  97. beforeEach(function () {
  98. this.jsonUpdates = [
  99. JSON.stringify({ op: [{ i: 'foo', p: 4 }] }),
  100. 'broken json'
  101. ]
  102. this.rclient.exec = sinon
  103. .stub()
  104. .callsArgWith(0, null, [this.jsonUpdates])
  105. return this.RealTimeRedisManager.getPendingUpdatesForDoc(
  106. this.doc_id,
  107. this.callback
  108. )
  109. })
  110. return it('should return an error to the callback', function () {
  111. return this.callback
  112. .calledWith(sinon.match.has('name', 'SyntaxError'))
  113. .should.equal(true)
  114. })
  115. })
  116. })
  117. describe('getUpdatesLength', function () {
  118. beforeEach(function () {
  119. this.rclient.llen = sinon.stub().yields(null, (this.length = 3))
  120. return this.RealTimeRedisManager.getUpdatesLength(
  121. this.doc_id,
  122. this.callback
  123. )
  124. })
  125. it('should look up the length', function () {
  126. return this.rclient.llen
  127. .calledWith(`PendingUpdates:${this.doc_id}`)
  128. .should.equal(true)
  129. })
  130. return it('should return the length', function () {
  131. return this.callback.calledWith(null, this.length).should.equal(true)
  132. })
  133. })
  134. return describe('sendData', function () {
  135. beforeEach(function () {
  136. this.message_id = 'doc:somehost:01020304-0'
  137. return this.RealTimeRedisManager.sendData({ op: 'thisop' })
  138. })
  139. it('should send the op with a message id', function () {
  140. return this.pubsubClient.publish
  141. .calledWith(
  142. 'applied-ops',
  143. JSON.stringify({ op: 'thisop', _id: this.message_id })
  144. )
  145. .should.equal(true)
  146. })
  147. return it('should track the payload size', function () {
  148. return this.metrics.summary
  149. .calledWith(
  150. 'redis.publish.applied-ops',
  151. JSON.stringify({ op: 'thisop', _id: this.message_id }).length
  152. )
  153. .should.equal(true)
  154. })
  155. })
  156. })