linagora-rse
Version:
385 lines (306 loc) • 14.8 kB
JavaScript
const sinon = require('sinon');
const mockery = require('mockery');
const { expect } = require('chai');
describe('The point to point messaging channel manager', function() {
let logger, PointToPointMessagingChannelManager, message, pointToPointChannelManager, channelName1, channelName2;
beforeEach(function() {
logger = {
debug: sinon.spy(),
warn: sinon.spy(),
error: sinon.spy()
};
channelName1 = 'foo:bar';
channelName2 = 'bar:baz';
message = { id: 1, content: 'My message content' };
mockery.registerMock('../../../core/logger', logger);
PointToPointMessagingChannelManager = this.helpers.requireBackend('core/messaging/point-to-point/manager');
pointToPointChannelManager = new PointToPointMessagingChannelManager();
});
describe('The channel function', function() {
it('should return a valid object', function() {
const channel1 = pointToPointChannelManager.get(channelName1);
expect(channel1).to.have.property('send').that.is.a('function');
expect(channel1).to.have.property('receive').that.is.a('function');
expect(channel1).to.have.property('unsubscribe').that.is.a('function');
});
it('should create as many channels as needed', function() {
const channel1 = pointToPointChannelManager.get(channelName1);
const channel2 = pointToPointChannelManager.get(channelName2);
expect(channel1).to.not.equal(channel2);
});
it('should not create new channel if it already exists', function() {
const channel1 = pointToPointChannelManager.get(channelName1);
const channel2 = pointToPointChannelManager.get(channelName1);
expect(channel1).to.equal(channel2);
});
describe('The channel#send function', function() {
describe('When client is not set', function() {
it('should cache message as publication', function() {
expect(pointToPointChannelManager._sendBuffer).to.be.empty;
pointToPointChannelManager.get(channelName1).send(message);
expect(pointToPointChannelManager._sendBuffer).to.deep.equal([
{
channel: channelName1,
message: message
}
]);
});
});
describe('When client is set', function() {
it('should publish message on client', function() {
const client = {
publish: sinon.spy()
};
expect(pointToPointChannelManager._sendBuffer).to.be.empty;
pointToPointChannelManager.client = client;
pointToPointChannelManager.get(channelName1).send(message);
expect(pointToPointChannelManager._sendBuffer).to.be.empty;
expect(client.publish).to.have.been.calledOnce;
expect(client.publish).to.have.been.calledWith(channelName1, message);
});
});
});
describe('The channel#receive function', function() {
describe('When client is not set', function() {
it('should cache receiver', function() {
const receiver = () => {};
expect(pointToPointChannelManager._receiversPromisesBuffer).to.be.empty;
expect(pointToPointChannelManager._receiversCache).to.be.empty;
const promise = pointToPointChannelManager.get(channelName1).receive(receiver);
expect(promise).to.be.an.instanceof(Promise);
expect(pointToPointChannelManager._receiversPromisesBuffer.length).to.equal(1);
});
it('should resolve when client is set', function(done) {
const receiver = () => {};
const client = {
subscribeToDurableQueue: sinon.stub().returns(Promise.resolve())
};
const promise = pointToPointChannelManager.get(channelName1).receive(receiver);
promise.then(function() {
expect(client.subscribeToDurableQueue).to.have.been.calledOnce;
done();
});
pointToPointChannelManager.setClient(client);
});
});
describe('When client is set', function() {
it('should subscribe to the client', function() {
const receiver = () => {};
const client = {
subscribeToDurableQueue: sinon.stub().returns(Promise.resolve())
};
expect(pointToPointChannelManager._receiversPromisesBuffer).to.be.empty;
expect(pointToPointChannelManager._receiversCache).to.be.empty;
pointToPointChannelManager.client = client;
pointToPointChannelManager.get(channelName1).receive(receiver);
expect(pointToPointChannelManager._receiversPromisesBuffer).to.be.empty;
expect(pointToPointChannelManager._receiversCache.length).to.equal(1);
expect(client.subscribeToDurableQueue).to.have.been.calledOnce;
expect(client.subscribeToDurableQueue).to.have.been.calledWith(channelName1, channelName1, sinon.match.func);
});
it('should wrap the receiver', function() {
const receiver = () => {};
const client = {
subscribeToDurableQueue: sinon.stub().returns(Promise.resolve())
};
pointToPointChannelManager.client = client;
pointToPointChannelManager.get(channelName1).receive(receiver);
expect(client.subscribeToDurableQueue.firstCall.args[2]).to.be.a('function');
expect(client.subscribeToDurableQueue.firstCall.args[2]).to.not.equal(receiver);
});
it('should wrap receiver and provide context to ack message', function() {
const originalMessage = { text: 'The original message' };
const receiver = sinon.spy();
const client = {
subscribeToDurableQueue: sinon.stub().returns(Promise.resolve()),
ack: sinon.spy()
};
pointToPointChannelManager.client = client;
pointToPointChannelManager.get(channelName1).receive(receiver);
const wrappedReceiver = client.subscribeToDurableQueue.firstCall.args[2];
wrappedReceiver(message, originalMessage);
expect(receiver).to.have.been.calledWith(message, sinon.match(function(value) {
expect(value.ack).to.be.a('function');
value.ack();
expect(client.ack).to.have.been.calledWith(originalMessage);
return true;
}));
});
});
});
describe('The channel#unsubscribe function', function() {
it('should not fail when receiver is undefined', function() {
pointToPointChannelManager._receiversCache.push({ channel: channelName1, receiver: function() {} });
expect(pointToPointChannelManager._receiversCache.length).to.equal(1);
pointToPointChannelManager.get(channelName1).unsubscribe();
expect(pointToPointChannelManager._receiversCache.length).to.equal(1);
});
it('should not fail when receiver is not registered', function() {
const receiver1 = () => {};
const receiver2 = () => {};
pointToPointChannelManager._receiversCache.push({ channel: channelName1, receiver: receiver1 });
expect(pointToPointChannelManager._receiversCache.length).to.equal(1);
pointToPointChannelManager.get(channelName1).unsubscribe(receiver2);
expect(pointToPointChannelManager._receiversCache.length).to.equal(1);
});
it('should remove receiver from cache when it exists', function() {
const receiver = () => {};
pointToPointChannelManager._receiversCache.push({ channel: channelName1, receiver });
expect(pointToPointChannelManager._receiversCache.length).to.equal(1);
pointToPointChannelManager.get(channelName1).unsubscribe(receiver);
expect(pointToPointChannelManager._receiversCache).to.be.empty;
});
describe('When client is set', function() {
it('should unsubscribe from client', function() {
const receiver = () => {};
const client = {
unsubscribe: sinon.spy()
};
pointToPointChannelManager.client = client;
pointToPointChannelManager.get(channelName1).unsubscribe(receiver);
expect(client.unsubscribe).to.have.been.calledWith(channelName1, receiver);
});
});
});
describe('The setClient function', function() {
it('should reject when client is undefined', function(done) {
pointToPointChannelManager.setClient()
.then(function() {
done(new Error('Should not occur'));
})
.catch(function(error) {
expect(error.message).to.match(/PointToPointMessagingManager: Client is undefined/);
done();
});
});
it('should subscribe with all the receivers which were added', function(done) {
const client = {
subscribeToDurableQueue: sinon.stub().returns(Promise.resolve())
};
const receiver1 = () => {};
const receiver2 = () => {};
const receiver3 = () => {};
const messaging1 = pointToPointChannelManager.get(channelName1);
const messaging2 = pointToPointChannelManager.get(channelName2);
messaging1.receive(receiver1);
messaging1.receive(receiver2);
messaging2.receive(receiver3);
expect(pointToPointChannelManager._receiversPromisesBuffer.length).to.equal(3);
pointToPointChannelManager.setClient(client).then(function() {
expect(client.subscribeToDurableQueue).to.have.been.calledThrice;
expect(pointToPointChannelManager._receiversPromisesBuffer).to.be.empty;
done();
}, done);
});
it('should send all messages which were sent while client was not defined', function(done) {
const client = {
publish: sinon.stub().returns(Promise.resolve())
};
const message1 = 'Message 1';
const message2 = 'Message 2';
const message3 = 'Message 3';
const messaging1 = pointToPointChannelManager.get(channelName1);
const messaging2 = pointToPointChannelManager.get(channelName2);
expect(pointToPointChannelManager._sendBuffer).to.be.empty;
messaging1.send(message1);
messaging1.send(message2);
messaging2.send(message3);
expect(pointToPointChannelManager._sendBuffer.length).to.equal(3);
pointToPointChannelManager.setClient(client).then(function() {
expect(client.publish).to.have.been.calledThrice;
expect(client.publish).to.have.been.calledWith(channelName1, message1);
expect(client.publish).to.have.been.calledWith(channelName1, message2);
expect(client.publish).to.have.been.calledWith(channelName2, message3);
expect(pointToPointChannelManager._sendBuffer).to.be.empty;
done();
}, done);
});
});
describe('The unsetClient function', function() {
it('should call dispose on client if client was set and call the callback', function() {
const callback = sinon.spy();
const client = {
dispose: sinon.spy(function(cb) {
cb();
})
};
pointToPointChannelManager.client = client;
pointToPointChannelManager.unsetClient(callback);
expect(client.dispose).to.have.been.calledOnce;
expect(client.dispose).to.have.been.calledWith(callback);
expect(callback).to.have.been.calledOnce;
});
it('should only call the callback if client was not set', function() {
const callback = sinon.spy();
pointToPointChannelManager.unsetClient(callback);
expect(callback).to.have.been.calledOnce;
});
});
describe('Integration tests', function() {
it('should be able to subscribe to receivers which were registered before even if client is set, unset and set again', function(done) {
const client1 = {
dispose: sinon.spy(function(cb) {
cb();
}),
subscribeToDurableQueue: sinon.spy()
};
const client2 = {
dispose: sinon.spy(function(cb) {
cb();
}),
subscribeToDurableQueue: sinon.spy()
};
const receiver1 = () => {};
const receiver2 = () => {};
pointToPointChannelManager.get(channelName1).receive(receiver1);
pointToPointChannelManager.get(channelName1).receive(receiver2);
pointToPointChannelManager.setClient(client1)
.then(function() { testClient(channelName1, client1); })
.then(function() { pointToPointChannelManager.unsetClient(); })
.then(function() { pointToPointChannelManager.setClient(client2); })
.then(function() { testClient(channelName1, client2); })
.then(done)
.catch(done);
function testClient(channel, client) {
expect(client.subscribeToDurableQueue).to.have.been.calledWith(channel, channel, sinon.match.func);
expect(client.subscribeToDurableQueue).to.have.been.calledTwice;
}
});
it('should be able to unsubscribe by giving the subscribe result', function(done) {
const client = {
subscribeToDurableQueue: sinon.stub().returns(Promise.resolve()),
unsubscribe: sinon.spy()
};
const receiver = () => {};
pointToPointChannelManager.setClient(client)
.then(function() { return pointToPointChannelManager.get(channelName1).receive(receiver); })
.then(function(handler) { return pointToPointChannelManager.get(channelName1).unsubscribe(handler); })
.then(function() {
expect(client.subscribeToDurableQueue).to.have.been.calledOnce;
expect(client.unsubscribe).to.have.been.calledOnce;
expect(pointToPointChannelManager._receiversCache).to.be.empty;
})
.then(done)
.catch(done);
});
it('should be able to unsubscribe by giving the subscribe result from resolved promise after client is set', function(done) {
const client = {
subscribeToDurableQueue: sinon.stub().returns(Promise.resolve()),
unsubscribe: sinon.spy()
};
const receiver = () => {};
const channel = pointToPointChannelManager.get(channelName1);
const promise = channel.receive(receiver);
promise.then(function(handler) { channel.unsubscribe(handler); })
.then(function() {
expect(client.subscribeToDurableQueue).to.have.been.calledOnce;
expect(client.unsubscribe).to.have.been.calledOnce;
expect(pointToPointChannelManager._receiversCache).to.be.empty;
})
.then(done)
.catch(done);
pointToPointChannelManager.setClient(client).catch(done);
});
});
});
});