2020import static com .rabbitmq .client .amqp .ConnectionSettings .Affinity .Operation .CONSUME ;
2121import static com .rabbitmq .client .amqp .ConnectionSettings .Affinity .Operation .PUBLISH ;
2222import static com .rabbitmq .client .amqp .impl .Assertions .assertThat ;
23+ import static com .rabbitmq .client .amqp .impl .ExceptionUtils .noRunningStreamMemberOnNode ;
2324import static com .rabbitmq .client .amqp .impl .TestUtils .*;
2425import static java .time .Duration .ofMillis ;
2526import static java .time .Duration .ofSeconds ;
27+ import static java .util .Arrays .stream ;
2628import static java .util .stream .Collectors .toList ;
2729import static java .util .stream .IntStream .range ;
2830import static org .assertj .core .api .Assertions .assertThat ;
31+ import static org .assertj .core .api .Assertions .assertThatThrownBy ;
2932
3033import com .rabbitmq .client .amqp .*;
34+ import com .rabbitmq .client .amqp .AmqpException .AmqpResourceClosedException ;
3135import com .rabbitmq .client .amqp .impl .TestUtils .Sync ;
32- import java .util .Arrays ;
3336import java .util .List ;
3437import java .util .Set ;
3538import java .util .concurrent .ConcurrentHashMap ;
3639import java .util .concurrent .atomic .AtomicInteger ;
3740import java .util .function .Consumer ;
3841import java .util .stream .Collectors ;
42+ import org .assertj .core .api .Condition ;
3943import org .junit .jupiter .api .*;
4044import org .junit .jupiter .params .ParameterizedTest ;
4145import org .junit .jupiter .params .provider .EnumSource ;
@@ -440,7 +444,7 @@ void connectionShouldBeOnOwningNodeWhenAffinityIsActivatedForClassicQueues(TestI
440444 List <String > names = range (0 , URIS .length ).mapToObj (ignored -> name (info )).collect (toList ());
441445 try {
442446 List <Connection > connections =
443- Arrays . stream (URIS )
447+ stream (URIS )
444448 .map (
445449 uri ->
446450 connection (
@@ -479,6 +483,57 @@ void connectionShouldBeOnOwningNodeWhenAffinityIsActivatedForClassicQueues(TestI
479483 }
480484 }
481485
486+ @ Test
487+ void consumerOnNodeWithoutStreamMemberShouldThrow () {
488+ List <AmqpConnection > connections = List .of ();
489+ try {
490+ int memberCount = URIS .length - 1 ;
491+ this .management .queue (this .name ).stream ().initialMemberCount (memberCount ).queue ().declare ();
492+ waitAtMost (() -> this .management .queueInfo (this .name ).members ().size () == memberCount );
493+
494+ List <String > members = this .management .queueInfo (this .name ).members ();
495+
496+ connections =
497+ stream (URIS )
498+ .map (uri -> (AmqpConnection ) this .environment .connectionBuilder ().uri (uri ).build ())
499+ .collect (toList ());
500+
501+ Connection cWithMember =
502+ connections .stream ()
503+ .filter (c -> members .contains (c .connectionNodename ()))
504+ .findAny ()
505+ .get ();
506+ cWithMember
507+ .consumerBuilder ()
508+ .queue (this .name )
509+ .messageHandler ((ctx , msg ) -> ctx .accept ())
510+ .build ();
511+
512+ Connection cWithNoMember =
513+ connections .stream ()
514+ .filter (c -> !members .contains (c .connectionNodename ()))
515+ .findAny ()
516+ .get ();
517+
518+ assertThatThrownBy (
519+ () ->
520+ cWithNoMember
521+ .consumerBuilder ()
522+ .queue (this .name )
523+ .messageHandler ((ctx , msg ) -> ctx .accept ())
524+ .build ())
525+ .isInstanceOf (AmqpResourceClosedException .class )
526+ .is (
527+ new Condition <>(
528+ e -> noRunningStreamMemberOnNode ((AmqpException ) e ),
529+ "detected as a no-running-stream-member-on-connection-node exception" ));
530+
531+ } finally {
532+ this .connection .management ().queueDeletion ().delete (this .name );
533+ connections .forEach (Connection ::close );
534+ }
535+ }
536+
482537 String moveQqLeader () {
483538 String initialLeader = deleteQqLeader ();
484539 addQqMember (initialLeader );
@@ -491,10 +546,6 @@ String deleteQqLeader() {
491546 return deleteLeader (this ::deleteQqMember );
492547 }
493548
494- String deleteStreamLeader () {
495- return deleteLeader (leader -> Cli .deleteStreamMember (q , leader ));
496- }
497-
498549 String deleteLeader (Consumer <String > deleteMemberOperation ) {
499550 Management .QueueInfo info = queueInfo ();
500551 String initialLeader = info .leader ();
0 commit comments