3434import static org .junit .jupiter .api .Assertions .assertThrows ;
3535import static org .junit .jupiter .api .Assertions .assertTrue ;
3636import static org .mockito .ArgumentMatchers .any ;
37- import static org .mockito .ArgumentMatchers .anyLong ;
3837import static org .mockito .Mockito .mock ;
39- import static org .mockito .Mockito .never ;
4038import static org .mockito .Mockito .verify ;
41- import static org .mockito .Mockito .when ;
4239
4340import java .util .ArrayList ;
4441import java .util .List ;
5148import org .mockito .ArgumentCaptor ;
5249
5350class RefreshingHttpJsonChannelTest {
51+ private static class FakeManagedHttpJsonChannel extends ManagedHttpJsonChannel {
52+ private volatile boolean isShutdown = false ;
53+ private volatile boolean isTerminated = false ;
54+ private HttpJsonClientCall <?, ?> nextCall = null ;
55+
56+ @ Override
57+ public void shutdown () {
58+ isShutdown = true ;
59+ }
60+
61+ @ Override
62+ public void shutdownNow () {
63+ isShutdown = true ;
64+ isTerminated = true ;
65+ }
66+
67+ @ Override
68+ public boolean isShutdown () {
69+ return isShutdown ;
70+ }
71+
72+ @ Override
73+ public boolean isTerminated () {
74+ return isTerminated ;
75+ }
76+
77+ @ Override
78+ public boolean awaitTermination (long duration , TimeUnit unit ) {
79+ return isTerminated ;
80+ }
81+
82+ @ Override
83+ @ SuppressWarnings ("unchecked" )
84+ public <RequestT , ResponseT > HttpJsonClientCall <RequestT , ResponseT > newCall (
85+ ApiMethodDescriptor <RequestT , ResponseT > methodDescriptor ,
86+ HttpJsonCallOptions callOptions ) {
87+ if (nextCall != null ) {
88+ return (HttpJsonClientCall <RequestT , ResponseT >) nextCall ;
89+ }
90+ return mock (HttpJsonClientCall .class );
91+ }
92+ }
93+
5494 private AtomicInteger channelFactoryCount ;
55- private ManagedHttpJsonChannel lastCreatedChannel ;
95+ private FakeManagedHttpJsonChannel lastCreatedChannel ;
5696 private String testCertPath = "/fake/path" ;
5797 private String testFingerprint = "fingerprint1" ;
5898 private boolean shouldThrowOnFactory = false ;
@@ -64,7 +104,7 @@ class RefreshingHttpJsonChannelTest {
64104 throw new RuntimeException ("Simulated factory failure" );
65105 }
66106 channelFactoryCount .incrementAndGet ();
67- lastCreatedChannel = mock ( ManagedHttpJsonChannel . class );
107+ lastCreatedChannel = new FakeManagedHttpJsonChannel ( );
68108 return lastCreatedChannel ;
69109 };
70110
@@ -131,7 +171,7 @@ void testShouldRefreshTrueWhenChanged() throws InterruptedException {
131171 @ Test
132172 void testRefreshSwapsChannel () throws InterruptedException {
133173 RefreshingHttpJsonChannel channel = createTestChannel ();
134- ManagedHttpJsonChannel firstChannel = lastCreatedChannel ;
174+ FakeManagedHttpJsonChannel firstChannel = lastCreatedChannel ;
135175 assertEquals (1 , channelFactoryCount .get ());
136176
137177 Thread .sleep (1001 ); // Invalidate 1-second cache
@@ -144,22 +184,22 @@ void testRefreshSwapsChannel() throws InterruptedException {
144184
145185 // Verify a new channel was created and the old one retired
146186 assertEquals (2 , channelFactoryCount .get ());
147- ManagedHttpJsonChannel secondChannel = lastCreatedChannel ;
187+ FakeManagedHttpJsonChannel secondChannel = lastCreatedChannel ;
148188
149189 // The old channel should receive a shutdown request immediately since there are no active calls
150- verify (firstChannel ). shutdown ( );
151- verify (secondChannel , never ()). shutdown ( );
190+ assertTrue (firstChannel . isShutdown () );
191+ assertFalse (secondChannel . isShutdown () );
152192 }
153193
154194 @ Test
155195 void testRefreshKeepsInFlightChannelsAlive () throws InterruptedException {
156196 RefreshingHttpJsonChannel channel = createTestChannel ();
157- ManagedHttpJsonChannel firstChannel = lastCreatedChannel ;
197+ FakeManagedHttpJsonChannel firstChannel = lastCreatedChannel ;
158198
159199 // Simulate an in-flight API call
160200 @ SuppressWarnings ("unchecked" )
161201 HttpJsonClientCall <Object , Object > mockCall = mock (HttpJsonClientCall .class );
162- when ( firstChannel .newCall ( any (), any ())). thenReturn ( mockCall ) ;
202+ firstChannel .nextCall = mockCall ;
163203
164204 HttpJsonClientCall <Object , Object > activeCall = channel .newCall (null , null );
165205
@@ -174,7 +214,7 @@ void testRefreshKeepsInFlightChannelsAlive() throws InterruptedException {
174214 assertEquals (2 , channelFactoryCount .get ());
175215
176216 // IMPORTANT: The first channel should NOT be shut down yet because of the active call!
177- verify (firstChannel , never ()). shutdown ( );
217+ assertFalse (firstChannel . isShutdown () );
178218
179219 // Now complete the call successfully
180220 @ SuppressWarnings ("unchecked" )
@@ -192,19 +232,18 @@ void testRefreshKeepsInFlightChannelsAlive() throws InterruptedException {
192232 listenerCaptor .getValue ().onClose (0 , null );
193233
194234 // FIRST CHANNEL SHOULD BE SHUT DOWN NOW!
195- verify (firstChannel ). shutdown ( );
235+ assertTrue (firstChannel . isShutdown () );
196236 }
197237
198238 @ Test
199239 void testRefreshDoesNotSpawnChannelWhenShutdown () throws InterruptedException {
200240 RefreshingHttpJsonChannel channel = createTestChannel ();
201- ManagedHttpJsonChannel firstChannel = lastCreatedChannel ;
241+ FakeManagedHttpJsonChannel firstChannel = lastCreatedChannel ;
202242 assertEquals (1 , channelFactoryCount .get ());
203243
204- // By default, Mockito returns false for boolean.
205- // Let's simulate that the channel pool is shut down.
244+ // Simulate that the channel pool is shut down.
206245 channel .shutdown ();
207- when ( firstChannel .isShutdown ()). thenReturn ( true );
246+ firstChannel .shutdown ( );
208247
209248 Thread .sleep (1001 ); // Invalidate 1-second cache
210249
@@ -252,9 +291,8 @@ void testShutdownNowSetsIsShutdown() {
252291 @ Test
253292 void testAwaitTerminationZeroTimeoutOnTerminatedChannelReturnsTrue () throws InterruptedException {
254293 RefreshingHttpJsonChannel channel = createTestChannel ();
255- ManagedHttpJsonChannel firstChannel = lastCreatedChannel ;
256- when (firstChannel .isTerminated ()).thenReturn (true );
257- when (firstChannel .awaitTermination (anyLong (), any ())).thenReturn (true );
294+ FakeManagedHttpJsonChannel firstChannel = lastCreatedChannel ;
295+ firstChannel .isTerminated = true ;
258296
259297 channel .shutdown ();
260298 assertTrue (channel .awaitTermination (0 , TimeUnit .MILLISECONDS ));
0 commit comments