From 877b1a198fe9fc01315727105a0331f09490c78d Mon Sep 17 00:00:00 2001 From: Eric Gribkoff Date: Mon, 23 Jul 2018 09:45:06 -0700 Subject: [PATCH] core: enterIdleMode() exits idle if still in use (#4630) --- .../io/grpc/internal/ManagedChannelImpl.java | 3 ++ .../grpc/internal/ManagedChannelImplTest.java | 44 +++++++++++++++++++ 2 files changed, 47 insertions(+) diff --git a/core/src/main/java/io/grpc/internal/ManagedChannelImpl.java b/core/src/main/java/io/grpc/internal/ManagedChannelImpl.java index 7b6fc9e015..1ee538a836 100644 --- a/core/src/main/java/io/grpc/internal/ManagedChannelImpl.java +++ b/core/src/main/java/io/grpc/internal/ManagedChannelImpl.java @@ -395,6 +395,9 @@ final class ManagedChannelImpl extends ManagedChannel implements Instrumented call = channel.newCall(method, CallOptions.DEFAULT); + call.start(mockCallListener, new Metadata()); + + // enterIdle() will shut down the name resolver and lb policy used to get a pick for the delayed + // call + channel.enterIdle(); + assertEquals(IDLE, channel.getState(false)); + + // enterIdle() will restart the delayed call by exiting idle. This creates a new helper. + ArgumentCaptor helperCaptor = ArgumentCaptor.forClass(Helper.class); + verify(mockLoadBalancerFactory, times(2)).newLoadBalancer(helperCaptor.capture()); + Helper helper2 = helperCaptor.getValue(); + + // Establish a connection + Subchannel subchannel = helper2.createSubchannel(addressGroup, Attributes.EMPTY); + subchannel.requestConnection(); + ClientStream mockStream = mock(ClientStream.class); + MockClientTransportInfo transportInfo = transports.poll(); + ConnectionClientTransport mockTransport = transportInfo.transport; + ManagedClientTransport.Listener transportListener = transportInfo.listener; + when(mockTransport.newStream(same(method), any(Metadata.class), any(CallOptions.class))) + .thenReturn(mockStream); + transportListener.transportReady(); + when(mockPicker.pickSubchannel(any(PickSubchannelArgs.class))) + .thenReturn(PickResult.withSubchannel(subchannel)); + helper2.updateBalancingState(READY, mockPicker); + assertEquals(READY, channel.getState(false)); + + // Verify the original call was drained + executor.runDueTasks(); + verify(mockTransport).newStream(same(method), any(Metadata.class), any(CallOptions.class)); + verify(mockStream).start(any(ClientStreamListener.class)); + } + @Test public void updateBalancingStateDoesUpdatePicker() { ClientStream mockStream = mock(ClientStream.class);