1
1
using System . Collections . Generic ;
2
+ using System . Linq ;
2
3
using System . Threading ;
3
4
using System . Threading . Tasks ;
4
5
using RabbitMQ . AMQP . Client ;
@@ -146,7 +147,7 @@ await publisher.Publish(new AmqpMessage($"message_{i}"),
146
147
await connection . CloseAsync ( ) ;
147
148
}
148
149
149
-
150
+
150
151
/// <summary>
151
152
/// Test the consumer for a stream queue with offset
152
153
/// The test is not deterministic because we don't know how many messages will be consumed
@@ -185,6 +186,104 @@ public async Task ConsumerForStreamQueueWithOffset(StreamOffsetSpecification off
185
186
await connection . CloseAsync ( ) ;
186
187
}
187
188
189
+
190
+ /// <summary>
191
+ /// Test for stream filtering
192
+ /// There are two consumers:
193
+ /// - one with a filter that should receive only the messages with the filter
194
+ /// - one without filter that should receive all messages
195
+ /// </summary>
196
+ /// <param name="filter"></param>
197
+ /// <param name="expected"></param>
198
+ [ Theory ]
199
+ [ InlineData ( "pizza,beer,pasta,wine" , 4 ) ]
200
+ [ InlineData ( "pizza,beer" , 2 ) ]
201
+ [ InlineData ( "pizza" , 1 ) ]
202
+ public async Task ConsumerWithStreamFilterShouldReceiveOnlyPartOfTheMessages ( string filter , int expected )
203
+ {
204
+ string [ ] filters = filter . Split ( "," ) ;
205
+
206
+ IConnection connection = await AmqpConnection . CreateAsync ( ConnectionSettingBuilder . Create ( ) . Build ( ) ) ;
207
+ IManagement management = connection . Management ( ) ;
208
+ string queueName = $ "ConsumerWithStreamFilterShouldReceiveOnlyPartOfTheMessages_{ filter } ";
209
+ await management . Queue ( ) . Name ( queueName ) . Type ( QueueType . STREAM ) . Declare ( ) ;
210
+ foreach ( string se in filters )
211
+ {
212
+ await Publish ( connection , queueName , 1 , se ) ;
213
+ }
214
+
215
+ // wait for the messages to be published and the chunks to be created
216
+ await Task . Delay ( 1000 ) ;
217
+ // publish extra messages without filter and these messages should be always excluded
218
+ // by the consumer with the filter
219
+ await Publish ( connection , queueName , 10 ) ;
220
+
221
+ List < IMessage > receivedMessages = [ ] ;
222
+ IConsumer consumer = connection . ConsumerBuilder ( ) . Queue ( queueName ) . InitialCredits ( 100 )
223
+ . MessageHandler ( ( context , message ) =>
224
+ {
225
+ receivedMessages . Add ( message ) ;
226
+ context . Accept ( ) ;
227
+ } ) . Stream ( ) . FilterValues ( filters ) . FilterMatchUnfiltered ( false )
228
+ . Offset ( StreamOffsetSpecification . First ) . Builder ( )
229
+ . Build ( ) ;
230
+
231
+ int receivedWithoutFilters = 0 ;
232
+ IConsumer consumerWithoutFilters = connection . ConsumerBuilder ( ) . Queue ( queueName ) . InitialCredits ( 100 )
233
+ . MessageHandler ( ( context , message ) =>
234
+ {
235
+ Interlocked . Increment ( ref receivedWithoutFilters ) ;
236
+ context . Accept ( ) ;
237
+ } ) . Stream ( )
238
+ . Offset ( StreamOffsetSpecification . First ) . Builder ( )
239
+ . Build ( ) ;
240
+
241
+ // wait for the consumer to consume all messages
242
+ await Task . Delay ( 500 ) ;
243
+ Assert . Equal ( expected , receivedMessages . Count ) ;
244
+ Assert . Equal ( filters . Length + 10 , receivedWithoutFilters ) ;
245
+
246
+ await consumer . CloseAsync ( ) ;
247
+ await consumerWithoutFilters . CloseAsync ( ) ;
248
+ await management . QueueDeletion ( ) . Delete ( queueName ) ;
249
+ await connection . CloseAsync ( ) ;
250
+ }
251
+
252
+
253
+ /// <summary>
254
+ /// Test the offset value for the stream queue
255
+ /// </summary>
256
+ /// <param name="offsetStart"></param>
257
+ /// <param name="numberOfMessagesExpected"></param>
258
+
259
+ [ Theory ]
260
+ [ InlineData ( 0 , 100 ) ]
261
+ [ InlineData ( 50 , 50 ) ]
262
+ [ InlineData ( 99 , 1 ) ]
263
+ public async Task ConsumerForStreamQueueWithOffsetValue ( int offsetStart , int numberOfMessagesExpected )
264
+ {
265
+ IConnection connection = await AmqpConnection . CreateAsync ( ConnectionSettingBuilder . Create ( ) . Build ( ) ) ;
266
+ IManagement management = connection . Management ( ) ;
267
+ string queueName = $ "ConsumerForStreamQueueWithOffsetValue_{ offsetStart } ";
268
+ await management . Queue ( ) . Name ( queueName ) . Type ( QueueType . STREAM ) . Declare ( ) ;
269
+ await Publish ( connection , queueName , 100 ) ;
270
+ int consumed = 0 ;
271
+ IConsumer consumer = connection . ConsumerBuilder ( ) . Queue ( queueName ) . InitialCredits ( 100 )
272
+ . MessageHandler ( ( context , message ) => { Interlocked . Increment ( ref consumed ) ; } ) . Stream ( ) . Offset ( offsetStart )
273
+ . Builder ( ) . Build ( ) ;
274
+
275
+ // wait for the consumer to consume all messages
276
+ // we can't use the TaskCompletionSource here because we don't know how many messages will be consumed
277
+ // In two seconds, the consumer should consume all messages
278
+ await Task . Delay ( 2000 ) ;
279
+
280
+ Assert . Equal ( consumed , numberOfMessagesExpected ) ;
281
+ await consumer . CloseAsync ( ) ;
282
+ await management . QueueDeletion ( ) . Delete ( queueName ) ;
283
+ await connection . CloseAsync ( ) ;
284
+ }
285
+
286
+
188
287
private static async Task Publish ( IConnection connection , string queue , int numberOfMessages ,
189
288
string filter = null )
190
289
{
@@ -197,7 +296,7 @@ private static async Task Publish(IConnection connection, string queue, int numb
197
296
message . Annotation ( "x-stream-filter-value" , filter ) ;
198
297
}
199
298
200
- await publisher . Publish ( new AmqpMessage ( $ "message_ { i } " ) ,
299
+ await publisher . Publish ( message ,
201
300
( _ , descriptor ) => { Assert . Equal ( OutcomeState . Accepted , descriptor . State ) ; } ) ;
202
301
}
203
302
}
0 commit comments