From 4256a6bfed97ae70102a0d1e418548d1a481b53d Mon Sep 17 00:00:00 2001 From: Jesse Carter Date: Mon, 7 Dec 2020 19:31:52 -0500 Subject: [PATCH] feat(rabbitmq): execution context check utility convenience function to check whether the current handler in an execution context is related to RabbitMQ re #204 --- .../e2e/execution-context.e2e-spec.ts | 84 +++++++++++++++++++ packages/rabbitmq/src/index.ts | 1 + packages/rabbitmq/src/rabbitmq.helpers.ts | 7 ++ 3 files changed, 92 insertions(+) create mode 100644 integration/rabbitmq/e2e/execution-context.e2e-spec.ts create mode 100644 packages/rabbitmq/src/rabbitmq.helpers.ts diff --git a/integration/rabbitmq/e2e/execution-context.e2e-spec.ts b/integration/rabbitmq/e2e/execution-context.e2e-spec.ts new file mode 100644 index 000000000..6a1cfe0cc --- /dev/null +++ b/integration/rabbitmq/e2e/execution-context.e2e-spec.ts @@ -0,0 +1,84 @@ +import { + AmqpConnection, + isRabbitContext, + RabbitMQModule, + RabbitSubscribe, +} from '@golevelup/nestjs-rabbitmq'; +import { CallHandler, ExecutionContext, NestInterceptor } from '@nestjs/common'; +import { INestApplication, Injectable } from '@nestjs/common'; +import { Test } from '@nestjs/testing'; + +const interceptorHandler = jest.fn(); + +const exchange = 'contextExchange'; +const queue = 'contextQueue'; + +@Injectable() +class TestInterceptor implements NestInterceptor { + intercept(context: ExecutionContext, next: CallHandler) { + const shouldSkip = isRabbitContext(context); + if (shouldSkip) { + return next.handle(); + } + + interceptorHandler('invoked'); + return next.handle(); + } +} + +@Injectable() +class SubscribeService { + @RabbitSubscribe({ + exchange, + routingKey: '#', + queue, + }) + handleSubscribe(message: object) { + console.log(`RECEIVED MESSAGE: ${message}`); + } +} + +describe('Rabbit Subscribe Without Register Handlers', () => { + let app: INestApplication; + let amqpConnection: AmqpConnection; + + const rabbitHost = process.env.NODE_ENV === 'ci' ? 'rabbit' : 'localhost'; + const uri = `amqp://rabbitmq:rabbitmq@${rabbitHost}:5672`; + + beforeAll(async () => { + const moduleFixture = await Test.createTestingModule({ + providers: [SubscribeService, TestInterceptor], + imports: [ + RabbitMQModule.forRoot(RabbitMQModule, { + exchanges: [ + { + name: exchange, + type: 'topic', + }, + ], + uri, + connectionInitOptions: { wait: true, reject: true, timeout: 3000 }, + }), + ], + }).compile(); + + app = moduleFixture.createNestApplication(); + amqpConnection = app.get(AmqpConnection); + app.useGlobalInterceptors(new TestInterceptor()); + await app.init(); + }); + + afterAll(async () => { + await app.close(); + }); + + it('should recognize a rabbit handler execution context and allow for interceptors to be skipped', async (done) => { + await amqpConnection.publish(exchange, 'x', `test-message`); + expect.assertions(1); + + setTimeout(() => { + expect(interceptorHandler).not.toHaveBeenCalled(); + done(); + }, 100); + }); +}); diff --git a/packages/rabbitmq/src/index.ts b/packages/rabbitmq/src/index.ts index 1efa69e0b..90a107120 100644 --- a/packages/rabbitmq/src/index.ts +++ b/packages/rabbitmq/src/index.ts @@ -5,3 +5,4 @@ export * from './rabbitmq.constants'; export * from './rabbitmq.decorators'; export * from './rabbitmq.interfaces'; export * from './rabbitmq.module'; +export * from './rabbitmq.helpers'; diff --git a/packages/rabbitmq/src/rabbitmq.helpers.ts b/packages/rabbitmq/src/rabbitmq.helpers.ts new file mode 100644 index 000000000..9ec7de8f8 --- /dev/null +++ b/packages/rabbitmq/src/rabbitmq.helpers.ts @@ -0,0 +1,7 @@ +import { ExecutionContext } from '@nestjs/common'; +import { RABBIT_HANDLER } from './rabbitmq.constants'; + +export const isRabbitContext = (executionContext: ExecutionContext) => { + const handler = executionContext.getHandler(); + return Reflect.getMetadataKeys(handler).includes(RABBIT_HANDLER); +};