EditorUpdatesControllerTests.coffee 6.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175
  1. SandboxedModule = require('sandboxed-module')
  2. sinon = require('sinon')
  3. require('chai').should()
  4. modulePath = require('path').join __dirname, '../../../../app/js/Features/Editor/EditorUpdatesController'
  5. MockClient = require "../helpers/MockClient"
  6. assert = require('assert')
  7. describe "EditorUpdatesController", ->
  8. beforeEach ->
  9. @project_id = "project-id-123"
  10. @doc_id = "doc-id-123"
  11. @client = new MockClient()
  12. @callback = sinon.stub()
  13. @EditorUpdatesController = SandboxedModule.require modulePath, requires:
  14. "logger-sharelatex": @logger = { error: sinon.stub(), log: sinon.stub() }
  15. "./EditorRealTimeController" : @EditorRealTimeController = {}
  16. "../DocumentUpdater/DocumentUpdaterHandler" : @DocumentUpdaterHandler = {}
  17. "../Versioning/AutomaticSnapshotManager" : @AutomaticSnapshotManager = {}
  18. "../../infrastructure/Metrics" : @metrics = { set: sinon.stub(), inc: sinon.stub() }
  19. "../../infrastructure/Server" : io: @io = {}
  20. "redis" :
  21. createClient: ()=>
  22. @rclient = {auth:->}
  23. describe "_applyUpdate", ->
  24. beforeEach ->
  25. @update = {op: {p: 12, t: "foo"}}
  26. @client.set("user_id", @user_id = "user-id-123")
  27. @DocumentUpdaterHandler.queueChange = sinon.stub().callsArg(3)
  28. describe "succesfully", ->
  29. beforeEach ->
  30. @EditorUpdatesController._applyUpdate @client, @project_id, @doc_id, @update, @callback
  31. it "should queue the update", ->
  32. @DocumentUpdaterHandler.queueChange
  33. .calledWith(@project_id, @doc_id, @update)
  34. .should.equal true
  35. it "should call the callback", ->
  36. @callback.called.should.equal true
  37. it "should update the active users metric", ->
  38. @metrics.set.calledWith("editor.active-users", @user_id).should.equal true
  39. it "should update the active projects metric", ->
  40. @metrics.set.calledWith("editor.active-projects", @project_id).should.equal true
  41. it "should increment the doc updates", ->
  42. @metrics.inc.calledWith("editor.doc-update").should.equal true
  43. describe "unsuccessfully", ->
  44. beforeEach ->
  45. @client.disconnect = sinon.stub()
  46. @DocumentUpdaterHandler.queueChange = sinon.stub().callsArgWith(3, new Error("Something went wrong"))
  47. @EditorUpdatesController._applyUpdate @client, @project_id, @doc_id, @update, @callback
  48. it "should disconnect the client", ->
  49. @client.disconnect.called.should.equal true
  50. it "should log an error", ->
  51. @logger.error.called.should.equal true
  52. describe "when client.take_snapshot is true", ->
  53. beforeEach ->
  54. @client.set("take_snapshots", true)
  55. @AutomaticSnapshotManager.markProjectAsUpdated = sinon.stub()
  56. @EditorUpdatesController._applyUpdate(@client, @project_id, @doc_id, @update)
  57. it "should call AutomaticSnapshotManager.markProjectAsUpdated", ->
  58. @AutomaticSnapshotManager.markProjectAsUpdated.calledWith(@project_id)
  59. .should.equal true
  60. describe "applyOtUpdate", ->
  61. beforeEach ->
  62. @client.id = "client-id"
  63. @client.set("user_id", @user_id = "user-id-123")
  64. @update = {op: {p: 12, t: "foo"}}
  65. @EditorUpdatesController._applyUpdate = sinon.stub()
  66. @EditorUpdatesController.applyOtUpdate @client, @project_id, @doc_id, @update
  67. it "should set the source of the update to the client id", ->
  68. @update.meta.source.should.equal @client.id
  69. it "should set the user_id of the update to the user id", ->
  70. @update.meta.user_id.should.equal @user_id
  71. it "should apply the update", ->
  72. @EditorUpdatesController._applyUpdate
  73. .calledWith(@client, @project_id, @doc_id, @update)
  74. .should.equal true
  75. describe "listenForUpdatesFromDocumentUpdater", ->
  76. beforeEach ->
  77. @rclient.subscribe = sinon.stub()
  78. @rclient.on = sinon.stub()
  79. @EditorUpdatesController.listenForUpdatesFromDocumentUpdater()
  80. it "should subscribe to the doc-updater stream", ->
  81. @rclient.subscribe.calledWith("applied-ops").should.equal true
  82. it "should register a callback to handle updates", ->
  83. @rclient.on.calledWith("message").should.equal true
  84. describe "_processMessageFromDocumentUpdater", ->
  85. describe "with update", ->
  86. beforeEach ->
  87. @message =
  88. doc_id: @doc_id
  89. op: {t: "foo", p: 12}
  90. @EditorUpdatesController._applyUpdateFromDocumentUpdater = sinon.stub()
  91. @EditorUpdatesController._processMessageFromDocumentUpdater "applied-ops", JSON.stringify(@message)
  92. it "should apply the update", ->
  93. @EditorUpdatesController._applyUpdateFromDocumentUpdater
  94. .calledWith(@doc_id, @message.op)
  95. .should.equal true
  96. describe "with error", ->
  97. beforeEach ->
  98. @message =
  99. doc_id: @doc_id
  100. error: "Something went wrong"
  101. @EditorUpdatesController._processErrorFromDocumentUpdater = sinon.stub()
  102. @EditorUpdatesController._processMessageFromDocumentUpdater "applied-ops", JSON.stringify(@message)
  103. it "should process the error", ->
  104. @EditorUpdatesController._processErrorFromDocumentUpdater
  105. .calledWith(@doc_id, @message.error)
  106. .should.equal true
  107. describe "_applyUpdateFromDocumentUpdater", ->
  108. beforeEach ->
  109. @sourceClient = new MockClient()
  110. @otherClients = [new MockClient(), new MockClient()]
  111. @update =
  112. op: [ t: "foo", p: 12 ]
  113. meta: source: @sourceClient.id
  114. v: @version = 42
  115. doc: @doc_id
  116. @io.sockets =
  117. clients: sinon.stub().returns([@sourceClient, @otherClients...])
  118. @EditorUpdatesController._applyUpdateFromDocumentUpdater @doc_id, @update
  119. it "should send a version bump to the source client", ->
  120. @sourceClient.emit
  121. .calledWith("otUpdateApplied", v: @version, doc: @doc_id)
  122. .should.equal true
  123. it "should get the clients connected to the document", ->
  124. @io.sockets.clients
  125. .calledWith(@doc_id)
  126. .should.equal true
  127. it "should send the full update to the other clients", ->
  128. for client in @otherClients
  129. client.emit
  130. .calledWith("otUpdateApplied", @update)
  131. .should.equal true
  132. describe "_processErrorFromDocumentUpdater", ->
  133. beforeEach ->
  134. @clients = [new MockClient(), new MockClient()]
  135. @io.sockets =
  136. clients: sinon.stub().returns(@clients)
  137. @EditorUpdatesController._processErrorFromDocumentUpdater @doc_id, "Something went wrong"
  138. it "should log out an error", ->
  139. @logger.error.called.should.equal true
  140. it "should disconnect all clients in that document", ->
  141. @io.sockets.clients.calledWith(@doc_id).should.equal true
  142. for client in @clients
  143. client.disconnect.called.should.equal true