17
17
18
18
package com .rabbitmq .client .amqp .impl ;
19
19
20
+ import static com .rabbitmq .client .amqp .Management .QueueType .QUORUM ;
20
21
import static com .rabbitmq .client .amqp .Management .QueueType .STREAM ;
21
- import static com .rabbitmq .client .amqp .Resource .State .OPEN ;
22
- import static com .rabbitmq .client .amqp .Resource .State .RECOVERING ;
22
+ import static com .rabbitmq .client .amqp .Resource .State .*;
23
23
import static com .rabbitmq .client .amqp .impl .Assertions .*;
24
24
import static com .rabbitmq .client .amqp .impl .Cli .closeConnection ;
25
- import static com .rabbitmq .client .amqp .impl .TestUtils .name ;
26
- import static com .rabbitmq .client .amqp .impl .TestUtils .sync ;
25
+ import static com .rabbitmq .client .amqp .impl .TestUtils .*;
27
26
import static org .assertj .core .api .Assertions .*;
28
27
29
28
import com .rabbitmq .client .amqp .*;
41
40
@ ExtendWith (AmqpTestInfrastructureExtension .class )
42
41
public class AmqpConsumerTest {
43
42
43
+ // used by the test extension
44
44
BackOffDelayPolicy backOffDelayPolicy = BackOffDelayPolicy .fixed (Duration .ofMillis (100 ));
45
45
Environment environment ;
46
46
Connection connection ;
@@ -50,7 +50,6 @@ public class AmqpConsumerTest {
50
50
@ BeforeEach
51
51
void init (TestInfo info ) {
52
52
this .q = name (info );
53
- connection .management ().queue (this .q ).type (STREAM ).declare ();
54
53
this .connectionName = ((AmqpConnection ) connection ).name ();
55
54
}
56
55
@@ -61,6 +60,7 @@ void tearDown() {
61
60
62
61
@ Test
63
62
void subscriptionListenerShouldBeCalledOnRecovery () {
63
+ connection .management ().queue (this .q ).type (STREAM ).declare ();
64
64
Sync subscriptionSync = sync ();
65
65
Sync recoveredSync = sync ();
66
66
connection
@@ -81,6 +81,7 @@ void subscriptionListenerShouldBeCalledOnRecovery() {
81
81
82
82
@ Test
83
83
void streamConsumerRestartsWhereItLeftOff () {
84
+ connection .management ().queue (this .q ).type (STREAM ).declare ();
84
85
Connection publisherConnection = environment .connectionBuilder ().build ();
85
86
Publisher publisher = publisherConnection .publisherBuilder ().queue (this .q ).build ();
86
87
int messageCount = 100 ;
@@ -159,6 +160,57 @@ void streamConsumerRestartsWhereItLeftOff() {
159
160
assertThat (lastOffsetProcessed ).hasValueGreaterThan (offsetAfterClosing );
160
161
}
161
162
163
+ @ Test
164
+ void unsettledMessageShouldGoBackToQueueIfConnectionIsClosed (TestInfo testInfo ) {
165
+ String cName = name (testInfo );
166
+ connection .management ().queue (this .q ).type (QUORUM ).declare ();
167
+ Sync connectionRecoveredSync = sync ();
168
+ Connection c =
169
+ ((AmqpConnectionBuilder ) environment .connectionBuilder ())
170
+ .name (cName )
171
+ .recovery ()
172
+ .backOffDelayPolicy (backOffDelayPolicy )
173
+ .connectionBuilder ()
174
+ .listeners (recoveredListener (connectionRecoveredSync ))
175
+ .build ();
176
+ Publisher publisher = c .publisherBuilder ().queue (this .q ).build ();
177
+
178
+ Sync deliveredSync = sync (2 );
179
+ Sync consumerClosedSync = sync ();
180
+ AtomicInteger deliveryCount = new AtomicInteger ();
181
+ c .consumerBuilder ()
182
+ .listeners (
183
+ ctx -> {
184
+ if (ctx .currentState () == CLOSED ) {
185
+ consumerClosedSync .down ();
186
+ }
187
+ })
188
+ .queue (this .q )
189
+ .messageHandler (
190
+ (ctx , msg ) -> {
191
+ if (deliveryCount .incrementAndGet () == 1 ) {
192
+ closeConnection (cName );
193
+ }
194
+ deliveredSync .down ();
195
+ })
196
+ .build ();
197
+
198
+ publisher .publish (publisher .message (), ctx -> {});
199
+
200
+ assertThat (deliveredSync ).completes ();
201
+ assertThat (deliveryCount ).hasValue (2 );
202
+ assertThat (connectionRecoveredSync ).completes ();
203
+ assertThat (consumerClosedSync ).hasNotCompleted ();
204
+ c .close ();
205
+ assertThat (consumerClosedSync ).completes ();
206
+
207
+ waitAtMost (
208
+ () -> {
209
+ Management .QueueInfo info = connection .management ().queueInfo (this .q );
210
+ return info .messageCount () == 1 && info .consumerCount () == 0 ;
211
+ });
212
+ }
213
+
162
214
private static Resource .StateListener recoveredListener (Sync sync ) {
163
215
return context -> {
164
216
if (context .previousState () == RECOVERING && context .currentState () == OPEN ) {
0 commit comments