/* eslint-disable no-return-assign, */ // TODO: This file was created by bulk-decaffeinate. // Fix any style issues and re-enable lint. /* * decaffeinate suggestions: * DS101: Remove unnecessary use of Array.from * DS102: Remove unnecessary code created because of implicit returns * Full docs: https://github.com/decaffeinate/decaffeinate/blob/master/docs/suggestions.md */ const SandboxedModule = require('sandboxed-module') const sinon = require('sinon') const modulePath = require('path').join( __dirname, '../../../app/js/WebsocketLoadBalancer' ) describe('WebsocketLoadBalancer', function () { beforeEach(function () { this.rclient = {} this.RoomEvents = { on: sinon.stub() } this.WebsocketLoadBalancer = SandboxedModule.require(modulePath, { requires: { './RedisClientManager': { createClientList: () => [], }, './SafeJsonParse': (this.SafeJsonParse = { parse: (data, cb) => cb(null, JSON.parse(data)), }), './EventLogger': { checkEventOrder: sinon.stub() }, './HealthCheckManager': { check: sinon.stub() }, './RoomManager': (this.RoomManager = { eventSource: sinon.stub().returns(this.RoomEvents), }), './ChannelManager': (this.ChannelManager = { publish: sinon.stub() }), './ConnectedUsersManager': (this.ConnectedUsersManager = { refreshClient: sinon.stub(), }), }, }) this.io = {} this.WebsocketLoadBalancer.rclientPubList = [{ publish: sinon.stub() }] this.WebsocketLoadBalancer.rclientSubList = [ { subscribe: sinon.stub(), on: sinon.stub(), }, ] this.room_id = 'room-id' this.message = 'otUpdateApplied' return (this.payload = ['argument one', 42]) }) describe('emitToRoom', function () { beforeEach(function () { return this.WebsocketLoadBalancer.emitToRoom( this.room_id, this.message, ...Array.from(this.payload) ) }) return it('should publish the message to redis', function () { return this.ChannelManager.publish .calledWith( this.WebsocketLoadBalancer.rclientPubList[0], 'editor-events', this.room_id, JSON.stringify({ room_id: this.room_id, message: this.message, payload: this.payload, }) ) .should.equal(true) }) }) describe('emitToAll', function () { beforeEach(function () { this.WebsocketLoadBalancer.emitToRoom = sinon.stub() return this.WebsocketLoadBalancer.emitToAll( this.message, ...Array.from(this.payload) ) }) return it("should emit to the room 'all'", function () { return this.WebsocketLoadBalancer.emitToRoom .calledWith('all', this.message, ...Array.from(this.payload)) .should.equal(true) }) }) describe('listenForEditorEvents', function () { beforeEach(function () { this.WebsocketLoadBalancer._processEditorEvent = sinon.stub() return this.WebsocketLoadBalancer.listenForEditorEvents() }) it('should subscribe to the editor-events channel', function () { return this.WebsocketLoadBalancer.rclientSubList[0].subscribe .calledWith('editor-events') .should.equal(true) }) return it('should process the events with _processEditorEvent', function () { return this.WebsocketLoadBalancer.rclientSubList[0].on .calledWith('message', sinon.match.func) .should.equal(true) }) }) return describe('_processEditorEvent', function () { describe('with bad JSON', function () { beforeEach(function () { this.isRestrictedUser = false this.SafeJsonParse.parse = sinon .stub() .callsArgWith(1, new Error('oops')) return this.WebsocketLoadBalancer._processEditorEvent( this.io, 'editor-events', 'blah' ) }) return it('should log an error', function () { return this.logger.error.called.should.equal(true) }) }) describe('with a designated room', function () { beforeEach(function () { this.io.sockets = { clients: sinon.stub().returns([ { id: 'client-id-1', emit: (this.emit1 = sinon.stub()), ol_context: {}, }, { id: 'client-id-2', emit: (this.emit2 = sinon.stub()), ol_context: {}, }, { id: 'client-id-1', emit: (this.emit3 = sinon.stub()), ol_context: {}, }, // duplicate client ]), } const data = JSON.stringify({ room_id: this.room_id, message: this.message, payload: this.payload, }) return this.WebsocketLoadBalancer._processEditorEvent( this.io, 'editor-events', data ) }) return it('should send the message to all (unique) clients in the room', function () { this.io.sockets.clients.calledWith(this.room_id).should.equal(true) this.emit1 .calledWith(this.message, ...Array.from(this.payload)) .should.equal(true) this.emit2 .calledWith(this.message, ...Array.from(this.payload)) .should.equal(true) return this.emit3.called.should.equal(false) }) }) // duplicate client should be ignored describe('with a designated room, and restricted clients, not restricted message', function () { beforeEach(function () { this.io.sockets = { clients: sinon.stub().returns([ { id: 'client-id-1', emit: (this.emit1 = sinon.stub()), ol_context: {}, }, { id: 'client-id-2', emit: (this.emit2 = sinon.stub()), ol_context: {}, }, { id: 'client-id-1', emit: (this.emit3 = sinon.stub()), ol_context: {}, }, // duplicate client { id: 'client-id-4', emit: (this.emit4 = sinon.stub()), ol_context: { is_restricted_user: true }, }, ]), } const data = JSON.stringify({ room_id: this.room_id, message: this.message, payload: this.payload, }) return this.WebsocketLoadBalancer._processEditorEvent( this.io, 'editor-events', data ) }) return it('should send the message to all (unique) clients in the room', function () { this.io.sockets.clients.calledWith(this.room_id).should.equal(true) this.emit1 .calledWith(this.message, ...Array.from(this.payload)) .should.equal(true) this.emit2 .calledWith(this.message, ...Array.from(this.payload)) .should.equal(true) this.emit3.called.should.equal(false) // duplicate client should be ignored return this.emit4.called.should.equal(true) }) }) // restricted client, but should be called describe('with a designated room, and restricted clients, restricted message', function () { beforeEach(function () { this.io.sockets = { clients: sinon.stub().returns([ { id: 'client-id-1', emit: (this.emit1 = sinon.stub()), ol_context: {}, }, { id: 'client-id-2', emit: (this.emit2 = sinon.stub()), ol_context: {}, }, { id: 'client-id-1', emit: (this.emit3 = sinon.stub()), ol_context: {}, }, // duplicate client { id: 'client-id-4', emit: (this.emit4 = sinon.stub()), ol_context: { is_restricted_user: true }, }, ]), } const data = JSON.stringify({ room_id: this.room_id, message: (this.restrictedMessage = 'new-comment'), payload: this.payload, }) return this.WebsocketLoadBalancer._processEditorEvent( this.io, 'editor-events', data ) }) return it('should send the message to all (unique) clients in the room, who are not restricted', function () { this.io.sockets.clients.calledWith(this.room_id).should.equal(true) this.emit1 .calledWith(this.restrictedMessage, ...Array.from(this.payload)) .should.equal(true) this.emit2 .calledWith(this.restrictedMessage, ...Array.from(this.payload)) .should.equal(true) this.emit3.called.should.equal(false) // duplicate client should be ignored return this.emit4.called.should.equal(false) }) }) // restricted client, should not be called return describe('when emitting to all', function () { beforeEach(function () { this.io.sockets = { emit: (this.emit = sinon.stub()) } const data = JSON.stringify({ room_id: 'all', message: this.message, payload: this.payload, }) return this.WebsocketLoadBalancer._processEditorEvent( this.io, 'editor-events', data ) }) return it('should send the message to all clients', function () { return this.emit .calledWith(this.message, ...Array.from(this.payload)) .should.equal(true) }) }) }) })