1- import { RabbitMqTransport } from './rabbitmq-transport'
2- import { TestContainer , TestEvent , TestCommand , TestCommandHandler } from '../test'
1+ import { RabbitMqTransport , DEFAULT_MAX_RETRIES } from './rabbitmq-transport'
2+ import {
3+ TestContainer ,
4+ TestEvent ,
5+ TestCommand ,
6+ TestCommandHandler ,
7+ TestPoisonedMessageHandler ,
8+ TestPoisonedMessage ,
9+ HANDLE_CHECKER ,
10+ HandleChecker
11+ } from '../test'
312import { BUS_RABBITMQ_INTERNAL_SYMBOLS , BUS_RABBITMQ_SYMBOLS } from './bus-rabbitmq-symbols'
413import { Connection , Channel , Message as RabbitMqMessage } from 'amqplib'
514import { TransportMessage , BUS_SYMBOLS , ApplicationBootstrap , Bus } from '@node-ts/bus-core'
@@ -8,14 +17,16 @@ import * as faker from 'faker'
817import { MessageAttributes } from '@node-ts/bus-messages'
918import { TestSystemMessage } from '../test/test-system-message'
1019import { TestSystemMessageHandler } from '../test/test-system-message-handler'
20+ import { Mock , IMock , It , Times } from 'typemoq'
1121
1222export async function sleep ( timeoutMs : number ) : Promise < void > {
1323 return new Promise ( resolve => setTimeout ( resolve , timeoutMs ) )
1424}
1525
1626const configuration : RabbitMqTransportConfiguration = {
1727 queueName : 'node-ts/bus-rabbitmq-test' ,
18- connectionString : 'amqp://guest:guest@0.0.0.0'
28+ connectionString : 'amqp://guest:guest@0.0.0.0' ,
29+ maxRetries : 3
1930}
2031
2132describe ( 'RabbitMqTransport' , ( ) => {
@@ -25,16 +36,20 @@ describe('RabbitMqTransport', () => {
2536 let channel : Channel
2637 let container : TestContainer
2738 let bootstrap : ApplicationBootstrap
39+ let handleChecker : IMock < HandleChecker >
2840
2941 beforeAll ( async ( ) => {
42+ handleChecker = Mock . ofType < HandleChecker > ( )
3043 container = new TestContainer ( )
44+ container . bind ( HANDLE_CHECKER ) . toConstantValue ( handleChecker . object )
3145 container . bind ( BUS_RABBITMQ_SYMBOLS . TransportConfiguration ) . toConstantValue ( configuration )
3246 bus = container . get ( BUS_SYMBOLS . Bus )
3347 sut = container . get ( BUS_SYMBOLS . Transport )
3448
3549 bootstrap = container . get < ApplicationBootstrap > ( BUS_SYMBOLS . ApplicationBootstrap )
3650 bootstrap . registerHandler ( TestCommandHandler )
3751 bootstrap . registerHandler ( TestSystemMessageHandler )
52+ bootstrap . registerHandler ( TestPoisonedMessageHandler )
3853
3954 const connectionFactory = container . get < ( ) => Promise < Connection > > ( BUS_RABBITMQ_INTERNAL_SYMBOLS . AmqpFactory )
4055 connection = await connectionFactory ( )
@@ -71,6 +86,35 @@ describe('RabbitMqTransport', () => {
7186 } )
7287 } )
7388
89+ describe ( 'when retrying a poisoned message' , ( ) => {
90+ const poisonedMessage = new TestPoisonedMessage ( faker . random . uuid ( ) )
91+ beforeAll ( async ( ) => {
92+ jest . setTimeout ( 10000 )
93+ await bus . publish ( poisonedMessage )
94+ await new Promise < void > ( resolve => {
95+ channel . consume ( 'dead-letter' , msg => {
96+ if ( ! msg ) {
97+ return
98+ }
99+
100+ channel . ack ( msg )
101+
102+ const message = JSON . parse ( msg . content . toString ( ) ) as TestPoisonedMessage
103+ if ( message . id === poisonedMessage . id ) {
104+ resolve ( )
105+ }
106+ } )
107+ } )
108+ } )
109+
110+ it ( `it should fail after configuration.maxRetries attempts` , ( ) => {
111+ handleChecker . verify (
112+ h => h . check ( It . is < TestPoisonedMessage > ( m => m . id === poisonedMessage . id ) , It . isAny ( ) ) ,
113+ Times . exactly ( configuration . maxRetries ! )
114+ )
115+ } )
116+ } )
117+
74118 describe ( 'when sending a command' , ( ) => {
75119 const command = new TestCommand ( )
76120 beforeEach ( async ( ) => {
@@ -91,23 +135,21 @@ describe('RabbitMqTransport', () => {
91135 const command = new TestSystemMessage ( )
92136 const channelName = command . name
93137
94- beforeEach ( async ( ) => {
95- await channel . assertExchange ( command . name , 'fanout' )
96- await channel . bindQueue ( configuration . queueName , command . name , '' )
138+ beforeAll ( async ( ) => {
139+ jest . setTimeout ( 10000 )
140+ channel . publish ( channelName , '' , Buffer . from ( JSON . stringify ( command ) ) )
141+ await sleep ( 5000 )
97142 } )
98143
99- afterEach ( async ( ) => {
144+ afterAll ( async ( ) => {
100145 await channel . deleteExchange ( command . name )
101146 } )
102147
103148 it ( 'should handle system messages' , async ( ) => {
104- channel . publish ( channelName , '' , Buffer . from ( JSON . stringify ( command ) ) )
105- jest . setTimeout ( 10000 )
106- await sleep ( 5000 )
107- const message = await sut . readNextMessage ( )
108-
109- expect ( message ) . toBeDefined ( )
110- expect ( message ! . domainMessage ) . toMatchObject ( command )
149+ handleChecker . verify (
150+ h => h . check ( It . is < TestSystemMessage > ( m => m . name === command . name ) , It . isAny ( ) ) ,
151+ Times . once ( )
152+ )
111153 } )
112154 } )
113155
0 commit comments