UNPKG

@tawk.to/nestjs-google-pubsub-microservice

Version:
563 lines 25.4 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); const chai_1 = require("chai"); const sinon = require("sinon"); const gc_pubsub_constants_1 = require("./gc-pubsub.constants"); const gc_pubsub_client_1 = require("./gc-pubsub.client"); const gc_message_builder_1 = require("./gc-message.builder"); const common_1 = require("@nestjs/common"); describe('GCPubSubClient', () => { let client; let pubsub; let topicMock; let subscriptionMock; let createClient; let sandbox; let clock; beforeEach(() => { sandbox = sinon.createSandbox(); Object.defineProperty(global, 'performance', { writable: true, }); clock = sandbox.useFakeTimers(); }); afterEach(() => { sandbox.restore(); }); describe('connect', () => { describe('when is not connected', () => { describe('when check existence is true', () => { beforeEach(async () => { client = getInstance({ replyTopic: 'replyTopic', replySubscription: 'replySubcription', }); try { client['client'] = null; await client.connect(); } catch (_a) { } }); it('should call "createClient" once', async () => { (0, chai_1.expect)(createClient.called).to.be.true; }); it('should call "client.topic" once', async () => { (0, chai_1.expect)(pubsub.topic.called).to.be.true; }); it('should call "topic.exists" once', async () => { (0, chai_1.expect)(topicMock.exists.called).to.be.true; }); it('should call "topic.create" once', async () => { (0, chai_1.expect)(topicMock.create.called).to.be.true; }); it('should call "topic.subscription" once', async () => { (0, chai_1.expect)(topicMock.subscription.called).to.be.true; }); it('should call "subscription.create" once', async () => { (0, chai_1.expect)(subscriptionMock.create.called).to.be.true; }); it('should call "subscription.on" twice', async () => { (0, chai_1.expect)(subscriptionMock.on.callCount).to.eq(2); }); }); describe('when createSubscriptionOptions is provided', () => { const mockCreateSubscriptionOptions = { messageRetentionDuration: { seconds: 604800, }, pushEndpoint: 'https://example.com/push', oidcToken: { serviceAccountEmail: 'example@example.com', audience: 'https://example.com', }, topic: 'projects/my-project/topics/my-topic', pushConfig: { pushEndpoint: 'https://example.com/push', }, ackDeadlineSeconds: 60, retainAckedMessages: true, labels: { env: 'dev', version: '1.0.0', }, enableMessageOrdering: false, expirationPolicy: { ttl: { seconds: 86400, }, }, filter: 'attribute.type = "order"', deadLetterPolicy: { deadLetterTopic: 'projects/my-project/topics/my-dead-letter-topic', maxDeliveryAttempts: 5, }, retryPolicy: { minimumBackoff: { seconds: 10, }, maximumBackoff: { seconds: 300, }, }, detached: false, enableExactlyOnceDelivery: true, topicMessageRetentionDuration: { seconds: 2592000, }, state: 'ACTIVE', }; beforeEach(async () => { client = getInstance({ createSubscriptionOptions: mockCreateSubscriptionOptions, replySubscription: 'testSubscription', replyTopic: 'testTopic', checkExistence: true, init: true, }); await client.connect(); }); it('should call "subscription.create" with argument', async () => { (0, chai_1.expect)(subscriptionMock.create.calledOnce).to.be.true; (0, chai_1.expect)(subscriptionMock.create.calledWith(mockCreateSubscriptionOptions)).to.be.true; }); }); describe('when clientIdFilter is turned on', () => { const mockCreateSubscriptionOptions = { messageRetentionDuration: { seconds: 604800, }, pushEndpoint: 'https://example.com/push', oidcToken: { serviceAccountEmail: 'example@example.com', audience: 'https://example.com', }, topic: 'projects/my-project/topics/my-topic', pushConfig: { pushEndpoint: 'https://example.com/push', }, ackDeadlineSeconds: 60, retainAckedMessages: true, labels: { env: 'dev', version: '1.0.0', }, enableMessageOrdering: false, expirationPolicy: { ttl: { seconds: 86400, }, }, filter: 'attribute.type = "order"', deadLetterPolicy: { deadLetterTopic: 'projects/my-project/topics/my-dead-letter-topic', maxDeliveryAttempts: 5, }, retryPolicy: { minimumBackoff: { seconds: 10, }, maximumBackoff: { seconds: 300, }, }, detached: false, enableExactlyOnceDelivery: true, topicMessageRetentionDuration: { seconds: 2592000, }, state: 'ACTIVE', }; beforeEach(async () => { client = getInstance({ createSubscriptionOptions: mockCreateSubscriptionOptions, replySubscription: 'testSubscription', replyTopic: 'testTopic', checkExistence: true, init: true, clientIdFilter: true, }); await client.connect(); }); it('should call subscription.create with client id filter', async () => { const expectedArgs = Object.assign(Object.assign({}, mockCreateSubscriptionOptions), { filter: `attributes._clientId = "${client.clientId}" AND (${mockCreateSubscriptionOptions.filter})` }); (0, chai_1.expect)(subscriptionMock.create.calledOnce).to.be.true; (0, chai_1.expect)(subscriptionMock.create.calledWith(expectedArgs)).to.be.true; }); it('should call subscription.create with client id filter with empty filter', async () => { client = getInstance({ replySubscription: 'testSubscription', replyTopic: 'testTopic', checkExistence: true, init: true, clientIdFilter: true, }); await client.connect(); const expectedArgs = { filter: `attributes._clientId = "${client.clientId}"`, }; (0, chai_1.expect)(subscriptionMock.create.calledOnce).to.be.true; (0, chai_1.expect)(subscriptionMock.create.calledWith(expectedArgs)).to.be.true; }); it('should call not subscription.create with client id when clientIdFilter is off', async () => { client = getInstance({ replySubscription: 'testSubscription', replyTopic: 'testTopic', checkExistence: true, init: true, }); await client.connect(); (0, chai_1.expect)(subscriptionMock.create.calledOnce).to.be.true; (0, chai_1.expect)(subscriptionMock.create.calledWith()).to.be.true; }); }); describe('when check existence is false', () => { beforeEach(async () => { client = getInstance({ replyTopic: 'replyTopic', replySubscription: 'replySubscription', init: false, checkExistence: false, }); try { client['client'] = null; await client.connect(); } catch (_a) { } }); it('should call "createClient" once', () => { (0, chai_1.expect)(createClient.called).to.be.true; }); it('should call "client.topic" once', () => { (0, chai_1.expect)(pubsub.topic.called).to.be.true; }); it('should not call "topic.exists" once', () => { (0, chai_1.expect)(topicMock.exists.called).to.be.false; }); it('should not call "topic.create" once', () => { (0, chai_1.expect)(topicMock.create.called).to.be.false; }); it('should call "topic.subscription" once', () => { (0, chai_1.expect)(topicMock.subscription.called).to.be.true; }); it('should not call "subscription.exists" once', () => { (0, chai_1.expect)(subscriptionMock.exists.called).to.be.false; }); it('should call "subscription.on" twice', () => { (0, chai_1.expect)(subscriptionMock.on.callCount).to.eq(2); }); }); }); describe('when is connected', () => { beforeEach(async () => { client = getInstance({ replyTopic: 'replyTopic', replySubscription: 'replySubscription', appendClientIdToSubscription: true, appendClientIdToReplyTopic: true, }); try { client['client'] = pubsub; await client.connect(); } catch (_a) { } }); it('should not call "createClient"', async () => { (0, chai_1.expect)(createClient.called).to.be.false; }); it('should not call "client.topic"', async () => { (0, chai_1.expect)(pubsub.topic.called).to.be.false; }); it('should not call "topic.create"', async () => { (0, chai_1.expect)(topicMock.create.called).to.be.false; }); it('should not call "topic.subscription"', async () => { (0, chai_1.expect)(topicMock.subscription.called).to.be.false; }); it('should not call "subscription.create"', async () => { (0, chai_1.expect)(subscriptionMock.create.called).to.be.false; }); it('should not call "subscription.on"', async () => { (0, chai_1.expect)(subscriptionMock.on.callCount).to.eq(0); }); describe('when appendClientIdToSubscription is true', () => { it('should append clientId to subscription name', () => { (0, chai_1.expect)(client['replySubscriptionName']).to.equal(`replySubscription-${client.clientId}`); }); }); describe('when appendClientIdToReplyTopic is true', () => { it('should append clientId to reply topic name', () => { (0, chai_1.expect)(client['replyTopicName']).to.equal(`replyTopic-${client.clientId}`); }); }); }); }); describe('publish', () => { let callback; beforeEach(() => { callback = sandbox.spy(); client = getInstance({ replyTopic: 'replyTopic', replySubscription: 'replySubcription', autoResume: true, }); client.topic = topicMock; sinon.spy(client['serializer'], 'serialize'); }); const pattern = 'test'; const msg = { pattern, data: 'data' }; it('should send message to a proper topic', (done) => { topicMock.publishMessage = sinon.stub().callsFake(async () => { const message = topicMock.publishMessage.getCall(0).args[0]; (0, chai_1.expect)(topicMock.publishMessage.called).to.be.true; (0, chai_1.expect)(message.data).to.be.eql(client['serializer'].serialize.getCall(0) .returnValue.data); done(); }); client['publish'](msg, () => { }); }); it('should remove listener from routing map on dispose', () => { client['publish'](msg, () => ({}))(); (0, chai_1.expect)(client['routingMap'].size).to.be.eq(0); }); it('should call callback on error', () => { const callback = sandbox.spy(); sinon.stub(client, 'assignPacketId').callsFake(() => { throw new Error(); }); client['publish'](msg, callback); (0, chai_1.expect)(callback.called).to.be.true; (0, chai_1.expect)(callback.getCall(0).args[0].err).to.be.instanceof(Error); }); it('should call resumePublishing on error with ordering key', (done) => { topicMock.publishMessage = sinon.stub().rejects(); const message = { data: new gc_message_builder_1.GCPubSubMessageBuilder('data').setOrderingKey('asdf').build(), pattern: 'test', }; client['publish'](message, () => { (0, chai_1.expect)(topicMock.resumePublishing.called).to.be.true; done(); }); }); it('should send message to a proper topic', (done) => { topicMock.publishMessage = sinon.stub().callsFake(async () => { const message = topicMock.publishMessage.getCall(0).args[0]; (0, chai_1.expect)(topicMock.publishMessage.called).to.be.true; (0, chai_1.expect)(message.data).to.be.eql(client['serializer'].serialize.getCall(0) .returnValue.data); (0, chai_1.expect)(message.attributes._pattern).to.be.eql(JSON.stringify(pattern)); (0, chai_1.expect)(message.attributes._id).to.be.not.empty; done(); }); client['publish'](msg, () => { }); }); it('should setTimeout to call callback with timeout error when timeout is provided', (done) => { const message = { data: new gc_message_builder_1.GCPubSubMessageBuilder('data') .setOrderingKey('asdf') .setTimeout(500) .build(), pattern: 'test', }; Promise.resolve(client['publish'](message, callback)).then(() => { clock.tick(510); (0, chai_1.expect)(callback.called).to.be.true; const error = callback.getCall(0).args[0].err; (0, chai_1.expect)(error).to.be.instanceof(common_1.RequestTimeoutException); done(); }); }); }); describe('handleResponse', () => { let callback; const id = '1'; beforeEach(() => { callback = sandbox.spy(); }); describe('when disposed', () => { beforeEach(() => { client['routingMap'].set(id, callback); client.handleResponse({ data: Buffer.from(JSON.stringify({ id, isDisposed: true })), attributes: {}, }); }); it('should emit disposed callback', () => { (0, chai_1.expect)(callback.called).to.be.true; (0, chai_1.expect)(callback.calledWith({ err: undefined, response: undefined, isDisposed: true, })).to.be.true; }); }); describe('when not disposed', () => { let buffer; beforeEach(() => { buffer = { id, err: undefined, response: 'res' }; client['routingMap'].set(id, callback); client.handleResponse({ data: Buffer.from(JSON.stringify(buffer)), attributes: {}, }); }); it('should not close server', () => { (0, chai_1.expect)(pubsub.close.called).to.be.false; }); it('should call callback with error and response data', () => { (0, chai_1.expect)(callback.called).to.be.true; (0, chai_1.expect)(callback.calledWith({ err: buffer.err, response: buffer.response, })).to.be.true; }); }); }); describe('close', () => { describe('default', () => { beforeEach(async () => { client = getInstance({ replyTopic: 'replyTopic', replySubscription: 'replySubcription', }); await client.connect(); await client.close(); }); it('should call "replySubscription.close"', function () { (0, chai_1.expect)(subscriptionMock.close.called).to.be.true; }); it('should close() pubsub', () => { (0, chai_1.expect)(pubsub.close.called).to.be.true; }); it('should set "client" to null', () => { (0, chai_1.expect)(client.client).to.be.null; }); it('should set "topic" to null', () => { (0, chai_1.expect)(client.topic).to.be.null; }); it('should set "replySubscription" to null', () => { (0, chai_1.expect)(client.replySubscription).to.be.null; }); it('should not delete topic', () => { (0, chai_1.expect)(topicMock.delete.called).to.be.false; }); it('should not delete subscription', () => { (0, chai_1.expect)(subscriptionMock.delete.called).to.be.false; }); }); describe('autoDeleteSubscriptionOnClose is true', () => { beforeEach(async () => { client = getInstance({ autoDeleteSubscriptionOnShutdown: true, replyTopic: 'replyTopic', replySubscription: 'replySubcription', }); await client.connect(); await client.close(); }); it('should delete subscription on close', () => { (0, chai_1.expect)(subscriptionMock.delete.calledOnce).to.be.true; }); }); describe('autoDeleteReplyTopicOnShutdown is true', () => { beforeEach(async () => { client = getInstance({ autoDeleteReplyTopicOnShutdown: true, replyTopic: 'replyTopic', replySubscription: 'replySubcription', }); await client.connect(); await client.close(); }); it('should delete subscription on close', () => { (0, chai_1.expect)(pubsub.topic.getCall(1).args[0]).to.eql(client['replyTopicName']); const topic = pubsub.topic.getCall(1).returnValue; (0, chai_1.expect)(topic.delete.calledOnce).to.be.true; }); }); }); describe('dispatchEvent', () => { const msg = { pattern: 'pattern', data: 'data' }; beforeEach(() => { client = getInstance({ replyTopic: 'replyTopic', replySubscription: 'replySubcription', }); client.topic = topicMock; sinon.spy(client['serializer'], 'serialize'); }); it('should publish packet', async () => { await client['dispatchEvent'](msg); (0, chai_1.expect)(topicMock.publishMessage.called).to.be.true; }); it('should publish packet with proper data', async () => { await client['dispatchEvent'](msg); (0, chai_1.expect)(topicMock.publishMessage.getCall(0).args[0].data).to.be.eql(client['serializer'].serialize.getCall(0) .returnValue.data); }); it('should throw error', async () => { topicMock.publishMessage.callsFake((a, b, c, d) => d(new Error())); client['dispatchEvent'](msg).catch((err) => (0, chai_1.expect)(err).to.be.instanceOf(Error)); }); it('should publish packet', async () => { await client['dispatchEvent'](msg); (0, chai_1.expect)(topicMock.publishMessage.called).to.be.true; }); it('should publish packet with proper data', async () => { await client['dispatchEvent'](msg); const message = topicMock.publishMessage.getCall(0).args[0]; (0, chai_1.expect)(message.data).to.be.eql(client['serializer'].serialize.getCall(0) .returnValue.data); (0, chai_1.expect)(message.attributes._pattern).to.be.eql(msg.pattern); }); it('should throw error', async () => { topicMock.publishMessage.callsFake((a, b, c, d) => d(new Error())); client['dispatchEvent'](msg).catch((err) => (0, chai_1.expect)(err).to.be.instanceOf(Error)); }); }); describe('createIfNotExists', () => { it('should throw error', async () => { const create = sandbox.stub().rejects({ code: 7 }); try { await client['createIfNotExists'](create); } catch (error) { (0, chai_1.expect)(error).to.include({ code: 7 }); } (0, chai_1.expect)(create.called).to.be.true; }); it('should skip error', async () => { const create = sandbox.stub().rejects({ code: gc_pubsub_constants_1.ALREADY_EXISTS }); await client['createIfNotExists'](create); (0, chai_1.expect)(create.called).to.be.true; }); }); function getInstance(options) { const client = new gc_pubsub_client_1.GCPubSubClient(options); subscriptionMock = { create: sandbox.stub().resolves(), close: sandbox.stub().callsFake((callback) => callback()), on: sandbox.stub().returnsThis(), exists: sandbox.stub().resolves([true]), delete: sandbox.stub().resolves(), }; topicMock = { create: sandbox.stub().resolves(), flush: sandbox.stub().callsFake((callback) => callback()), publishMessage: sandbox.stub().resolves(), exists: sandbox.stub().resolves([true]), subscription: sandbox.stub().returns(subscriptionMock), resumePublishing: sandbox.stub().resolves(), delete: sandbox.stub().resolves(), }; pubsub = { topic: sandbox.stub().callsFake(() => topicMock), close: sandbox.stub().callsFake((callback) => callback()), }; createClient = sandbox.stub(client, 'createClient').callsFake(() => { return pubsub; }); return client; } }); //# sourceMappingURL=gc-pubsub.client.spec.js.map