RealTimeRedisManagerTests.js 5.0 KB

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