22
33import static org .assertj .core .api .Assertions .assertThat ;
44
5+ import java .time .Duration ;
56import java .util .ArrayList ;
67import java .util .HashMap ;
78import java .util .List ;
1011import java .util .concurrent .CountDownLatch ;
1112import java .util .concurrent .Flow ;
1213import java .util .concurrent .TimeUnit ;
14+ import java .util .function .Consumer ;
1315import java .util .stream .Collectors ;
1416import java .util .stream .IntStream ;
1517
2224import org .junit .jupiter .api .Timeout ;
2325
2426import io .smallrye .mutiny .Multi ;
27+ import io .smallrye .mutiny .Uni ;
2528import io .smallrye .reactive .messaging .test .common .config .MapBasedConfig ;
2629import io .vertx .core .Vertx ;
30+ import io .vertx .proton .ProtonReceiver ;
2731
2832public class AmqpCreditTest extends AmqpTestBase {
2933
@@ -48,10 +52,36 @@ public void testCreditBasedFlowControl() throws Exception {
4852 CountDownLatch msgsReceived = new CountDownLatch (msgCount );
4953 List <Object > payloadsReceived = new ArrayList <>(msgCount );
5054
51- server = setupMockServer (msgCount , msgsReceived , payloadsReceived , executionHolder .vertx ().getDelegate ());
55+ server = setupMockServer (msgCount , msgsReceived , payloadsReceived , executionHolder .vertx ().getDelegate (),
56+ msgCount / 10 , r -> {
57+ });
58+
59+ Flow .Subscriber <? extends Message <?>> sink = createProviderAndSink (UUID .randomUUID ().toString (),
60+ server .actualPort ());
61+ //noinspection unchecked
62+ Multi .createFrom ().range (0 , msgCount )
63+ .map (Message ::of )
64+ .subscribe ((Flow .Subscriber <? super Message <Integer >>) sink );
65+
66+ assertThat (msgsReceived .await (20 , TimeUnit .SECONDS ))
67+ .withFailMessage ("Sent %s msgs but %s remain outstanding" , msgCount , msgsReceived .getCount ()).isTrue ();
68+ List <Integer > expectedPayloads = IntStream .range (0 , msgCount ).boxed ().collect (Collectors .toList ());
69+ assertThat (payloadsReceived ).containsAll (expectedPayloads );
70+ }
71+
72+ @ Test
73+ @ Timeout (30 )
74+ public void testNegativeCredit () throws Exception {
75+ int msgCount = 10 ;
76+ CountDownLatch msgsReceived = new CountDownLatch (msgCount );
77+ List <Object > payloadsReceived = new ArrayList <>(msgCount );
78+
79+ server = setupMockServer (msgCount , msgsReceived , payloadsReceived , executionHolder .vertx ().getDelegate (), -2 ,
80+ this ::updateCreditsEveryTwoSeconds );
5281
5382 Flow .Subscriber <? extends Message <?>> sink = createProviderAndSink (UUID .randomUUID ().toString (),
5483 server .actualPort ());
84+
5585 //noinspection unchecked
5686 Multi .createFrom ().range (0 , msgCount )
5787 .map (Message ::of )
@@ -78,8 +108,18 @@ private Flow.Subscriber<? extends Message<?>> createProviderAndSink(String topic
78108 return provider .getSubscriber (new MapBasedConfig (config ));
79109 }
80110
81- private MockServer setupMockServer (int msgCount , CountDownLatch latch , List <Object > payloads , Vertx vertx )
82- throws Exception {
111+ private void updateCreditsEveryTwoSeconds (ProtonReceiver serverReceiver ) {
112+ Multi .createFrom ().items (2 , 4 , 6 )
113+ .onItem ().transformToUniAndMerge (seconds -> {
114+ Duration delay = Duration .ofSeconds (seconds );
115+ return Uni .createFrom ().item (seconds )
116+ .onItem ().delayIt ().by (delay );
117+ })
118+ .subscribe ().with (item -> serverReceiver .flow (1 ));
119+ }
120+
121+ private MockServer setupMockServer (int msgCount , CountDownLatch latch , List <Object > payloads , Vertx vertx ,
122+ int initialCredits , Consumer <ProtonReceiver > receiverFunction ) throws Exception {
83123 assertThat (msgCount % 10 == 0 ).isTrue ();
84124 int creditBatch = msgCount / 10 ;
85125
@@ -114,9 +154,11 @@ private MockServer setupMockServer(int msgCount, CountDownLatch latch, List<Obje
114154 }
115155 });
116156
157+ receiverFunction .accept (serverReceiver );
158+
117159 serverReceiver .open ();
118160
119- serverReceiver .flow (creditBatch );
161+ serverReceiver .flow (initialCredits );
120162 });
121163 });
122164 }
0 commit comments