WebsocketLoadBalancerTests.coffee 3.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107
  1. SandboxedModule = require('sandboxed-module')
  2. sinon = require('sinon')
  3. require('chai').should()
  4. modulePath = require('path').join __dirname, '../../../app/js/WebsocketLoadBalancer'
  5. describe "WebsocketLoadBalancer", ->
  6. beforeEach ->
  7. @rclient = {}
  8. @WebsocketLoadBalancer = SandboxedModule.require modulePath, requires:
  9. "redis-sharelatex":
  10. createClient: () => @rclient
  11. "logger-sharelatex": @logger = { log: sinon.stub(), error: sinon.stub() }
  12. "./SafeJsonParse": @SafeJsonParse =
  13. parse: (data, cb) => cb null, JSON.parse(data)
  14. "./EventLogger": {checkEventOrder: sinon.stub()}
  15. @io = {}
  16. @WebsocketLoadBalancer.rclientPub = publish: sinon.stub()
  17. @WebsocketLoadBalancer.rclientSub =
  18. subscribe: sinon.stub()
  19. on: sinon.stub()
  20. @room_id = "room-id"
  21. @message = "message-to-editor"
  22. @payload = ["argument one", 42]
  23. describe "emitToRoom", ->
  24. beforeEach ->
  25. @WebsocketLoadBalancer.emitToRoom(@room_id, @message, @payload...)
  26. it "should publish the message to redis", ->
  27. @WebsocketLoadBalancer.rclientPub.publish
  28. .calledWith("editor-events", JSON.stringify(
  29. room_id: @room_id,
  30. message: @message
  31. payload: @payload
  32. ))
  33. .should.equal true
  34. describe "emitToAll", ->
  35. beforeEach ->
  36. @WebsocketLoadBalancer.emitToRoom = sinon.stub()
  37. @WebsocketLoadBalancer.emitToAll @message, @payload...
  38. it "should emit to the room 'all'", ->
  39. @WebsocketLoadBalancer.emitToRoom
  40. .calledWith("all", @message, @payload...)
  41. .should.equal true
  42. describe "listenForEditorEvents", ->
  43. beforeEach ->
  44. @WebsocketLoadBalancer._processEditorEvent = sinon.stub()
  45. @WebsocketLoadBalancer.listenForEditorEvents()
  46. it "should subscribe to the editor-events channel", ->
  47. @WebsocketLoadBalancer.rclientSub.subscribe
  48. .calledWith("editor-events")
  49. .should.equal true
  50. it "should process the events with _processEditorEvent", ->
  51. @WebsocketLoadBalancer.rclientSub.on
  52. .calledWith("message", sinon.match.func)
  53. .should.equal true
  54. describe "_processEditorEvent", ->
  55. describe "with bad JSON", ->
  56. beforeEach ->
  57. @SafeJsonParse.parse = sinon.stub().callsArgWith 1, new Error("oops")
  58. @WebsocketLoadBalancer._processEditorEvent(@io, "editor-events", "blah")
  59. it "should log an error", ->
  60. @logger.error.called.should.equal true
  61. describe "with a designated room", ->
  62. beforeEach ->
  63. @io.sockets =
  64. clients: sinon.stub().returns([
  65. {id: 'client-id-1', emit: @emit1 = sinon.stub()}
  66. {id: 'client-id-2', emit: @emit2 = sinon.stub()}
  67. {id: 'client-id-1', emit: @emit3 = sinon.stub()} # duplicate client
  68. ])
  69. data = JSON.stringify
  70. room_id: @room_id
  71. message: @message
  72. payload: @payload
  73. @WebsocketLoadBalancer._processEditorEvent(@io, "editor-events", data)
  74. it "should send the message to all (unique) clients in the room", ->
  75. @io.sockets.clients
  76. .calledWith(@room_id)
  77. .should.equal true
  78. @emit1.calledWith(@message, @payload...).should.equal true
  79. @emit2.calledWith(@message, @payload...).should.equal true
  80. @emit3.called.should.equal false # duplicate client should be ignored
  81. describe "when emitting to all", ->
  82. beforeEach ->
  83. @io.sockets =
  84. emit: @emit = sinon.stub()
  85. data = JSON.stringify
  86. room_id: "all"
  87. message: @message
  88. payload: @payload
  89. @WebsocketLoadBalancer._processEditorEvent(@io, "editor-events", data)
  90. it "should send the message to all clients", ->
  91. @emit.calledWith(@message, @payload...).should.equal true