3232import static com .google .api .gax .grpc .testing .FakeServiceGrpc .METHOD_RECOGNIZE ;
3333import static com .google .api .gax .grpc .testing .FakeServiceGrpc .METHOD_SERVER_STREAMING_RECOGNIZE ;
3434import static com .google .common .truth .Truth .assertThat ;
35+ import static org .junit .Assert .assertThrows ;
3536
3637import com .google .api .core .ApiFuture ;
3738import com .google .api .gax .core .FixedExecutorProvider ;
@@ -523,13 +524,57 @@ void channelCountShouldNotChangeWhenOutstandingRpcsAreWithinLimits() throws Exce
523524 assertThat (pool .entries .get ()).hasSize (2 );
524525 }
525526
527+ @ Test
528+ void customResizeDeltaIsRespected () throws Exception {
529+ ScheduledExecutorService executor = Mockito .mock (ScheduledExecutorService .class );
530+ FixedExecutorProvider provider = FixedExecutorProvider .create (executor );
531+
532+ List <ManagedChannel > channels = new ArrayList <>();
533+
534+ ChannelFactory channelFactory =
535+ () -> {
536+ ManagedChannel channel = Mockito .mock (ManagedChannel .class );
537+ Mockito .when (channel .newCall (Mockito .any (), Mockito .any ()))
538+ .thenAnswer (
539+ invocation -> {
540+ @ SuppressWarnings ("unchecked" )
541+ ClientCall <Object , Object > clientCall = Mockito .mock (ClientCall .class );
542+ return clientCall ;
543+ });
544+
545+ channels .add (channel );
546+ return channel ;
547+ };
548+
549+ pool =
550+ new ChannelPool (
551+ ChannelPoolSettings .builder ()
552+ .setInitialChannelCount (2 )
553+ .setMinRpcsPerChannel (1 )
554+ .setMaxRpcsPerChannel (2 )
555+ .setMaxResizeDelta (5 )
556+ .build (),
557+ channelFactory ,
558+ provider );
559+ assertThat (pool .entries .get ()).hasSize (2 );
560+
561+ // Add 20 RPCs to push expansion
562+ for (int i = 0 ; i < 20 ; i ++) {
563+ ClientCalls .futureUnaryCall (
564+ pool .newCall (METHOD_RECOGNIZE , CallOptions .DEFAULT ), Color .getDefaultInstance ());
565+ }
566+ pool .resize ();
567+ // delta is 15 - 2 = 13. Capped at maxResizeDelta = 5.
568+ // Expected size = 2 + 5 = 7.
569+ assertThat (pool .entries .get ()).hasSize (7 );
570+ }
571+
526572 @ Test
527573 void removedIdleChannelsAreShutdown () throws Exception {
528574 ScheduledExecutorService executor = Mockito .mock (ScheduledExecutorService .class );
529575 FixedExecutorProvider provider = FixedExecutorProvider .create (executor );
530576
531577 List <ManagedChannel > channels = new ArrayList <>();
532- List <ClientCall <Object , Object >> startedCalls = new ArrayList <>();
533578
534579 ChannelFactory channelFactory =
535580 () -> {
@@ -539,7 +584,6 @@ void removedIdleChannelsAreShutdown() throws Exception {
539584 invocation -> {
540585 @ SuppressWarnings ("unchecked" )
541586 ClientCall <Object , Object > clientCall = Mockito .mock (ClientCall .class );
542- startedCalls .add (clientCall );
543587 return clientCall ;
544588 });
545589
@@ -679,6 +723,109 @@ public void onComplete() {}
679723 assertThat (e .getMessage ()).isEqualTo ("Call is already cancelled" );
680724 }
681725
726+ @ Test
727+ void repeatedResizingLogsWarningOnExpand () throws Exception {
728+ ScheduledExecutorService executor = Mockito .mock (ScheduledExecutorService .class );
729+ FixedExecutorProvider provider = FixedExecutorProvider .create (executor );
730+
731+ ChannelFactory channelFactory =
732+ () -> {
733+ ManagedChannel channel = Mockito .mock (ManagedChannel .class );
734+ Mockito .when (channel .newCall (Mockito .any (), Mockito .any ()))
735+ .thenAnswer (
736+ invocation -> {
737+ @ SuppressWarnings ("unchecked" )
738+ ClientCall <Object , Object > clientCall = Mockito .mock (ClientCall .class );
739+ return clientCall ;
740+ });
741+ return channel ;
742+ };
743+
744+ pool =
745+ new ChannelPool (
746+ ChannelPoolSettings .builder ()
747+ .setInitialChannelCount (1 )
748+ .setMinRpcsPerChannel (1 )
749+ .setMaxRpcsPerChannel (2 )
750+ .setMaxResizeDelta (1 )
751+ .setMinChannelCount (1 )
752+ .setMaxChannelCount (10 )
753+ .build (),
754+ channelFactory ,
755+ provider );
756+ assertThat (pool .entries .get ()).hasSize (1 );
757+
758+ FakeLogHandler logHandler = new FakeLogHandler ();
759+ ChannelPool .LOG .addHandler (logHandler );
760+
761+ try {
762+ // Add 20 RPCs to push expansion
763+ for (int i = 0 ; i < 20 ; i ++) {
764+ ClientCalls .futureUnaryCall (
765+ pool .newCall (METHOD_RECOGNIZE , CallOptions .DEFAULT ), Color .getDefaultInstance ());
766+ }
767+
768+ // Resize 4 times, should not log warning yet
769+ for (int i = 0 ; i < 4 ; i ++) {
770+ pool .resize ();
771+ }
772+ assertThat (logHandler .getAllMessages ()).isEmpty ();
773+
774+ // 5th resize, should log warning
775+ pool .resize ();
776+ assertThat (logHandler .getAllMessages ()).hasSize (1 );
777+ assertThat (logHandler .getAllMessages ())
778+ .contains (ChannelPool .CHANNEL_POOL_CONSECUTIVE_RESIZING_WARNING );
779+
780+ // 6th resize, should not log again
781+ pool .resize ();
782+ assertThat (logHandler .getAllMessages ()).hasSize (1 );
783+ } finally {
784+ ChannelPool .LOG .removeHandler (logHandler );
785+ }
786+ }
787+
788+ @ Test
789+ void repeatedResizingLogsWarningOnShrink () throws Exception {
790+ ScheduledExecutorService executor = Mockito .mock (ScheduledExecutorService .class );
791+ FixedExecutorProvider provider = FixedExecutorProvider .create (executor );
792+
793+ ChannelFactory channelFactory = () -> Mockito .mock (ManagedChannel .class );
794+
795+ pool =
796+ new ChannelPool (
797+ ChannelPoolSettings .builder ()
798+ .setInitialChannelCount (10 )
799+ .setMinRpcsPerChannel (1 )
800+ .setMaxRpcsPerChannel (2 )
801+ .setMaxResizeDelta (1 )
802+ .setMinChannelCount (1 )
803+ .setMaxChannelCount (10 )
804+ .build (),
805+ channelFactory ,
806+ provider );
807+ assertThat (pool .entries .get ()).hasSize (10 );
808+
809+ FakeLogHandler logHandler = new FakeLogHandler ();
810+ ChannelPool .LOG .addHandler (logHandler );
811+
812+ try {
813+ // 0 RPCs, should shrink every cycle
814+ // Resize 4 times, should not log warning yet
815+ for (int i = 0 ; i < 4 ; i ++) {
816+ pool .resize ();
817+ }
818+ assertThat (logHandler .getAllMessages ()).isEmpty ();
819+
820+ // 5th resize, should log warning
821+ pool .resize ();
822+ assertThat (logHandler .getAllMessages ())
823+ .contains (ChannelPool .CHANNEL_POOL_CONSECUTIVE_RESIZING_WARNING );
824+ } finally {
825+ ChannelPool .LOG .removeHandler (logHandler );
826+ }
827+ }
828+
682829 @ Test
683830 void testDoubleRelease () throws Exception {
684831 FakeLogHandler logHandler = new FakeLogHandler ();
@@ -737,4 +884,11 @@ void testDoubleRelease() throws Exception {
737884 ChannelPool .LOG .removeHandler (logHandler );
738885 }
739886 }
887+
888+ @ Test
889+ void settingsValidationFailsWhenMaxResizeDeltaExceedsLimit () {
890+ ChannelPoolSettings .Builder builder =
891+ ChannelPoolSettings .builder ().setMaxResizeDelta (26 ).setMaxChannelCount (30 );
892+ assertThrows (IllegalStateException .class , builder ::build );
893+ }
740894}
0 commit comments