use of io.grpc.LoadBalancer.Subchannel in project grpc-java by grpc.
the class HealthCheckingLoadBalancerFactoryTest method serviceConfigChangesServiceNameWhenRpcInactive.
@Test
public void serviceConfigChangesServiceNameWhenRpcInactive() {
Attributes resolutionAttrs = attrsWithHealthCheckService("TeeService");
ResolvedAddresses result1 = ResolvedAddresses.newBuilder().setAddresses(resolvedAddressList).setAttributes(resolutionAttrs).build();
hcLbEventDelivery.handleResolvedAddresses(result1);
verify(origLb).handleResolvedAddresses(result1);
verifyNoMoreInteractions(origLb);
Subchannel subchannel = createSubchannel(0, Attributes.EMPTY);
SubchannelStateListener mockListener = mockStateListeners[0];
assertThat(unwrap(subchannel)).isSameInstanceAs(subchannels[0]);
InOrder inOrder = inOrder(origLb, mockListener);
HealthImpl healthImpl = healthImpls[0];
// Underlying subchannel is not READY initially
ConnectivityStateInfo underlyingErrorState = ConnectivityStateInfo.forTransientFailure(Status.UNAVAILABLE.withDescription("connection refused"));
deliverSubchannelState(0, underlyingErrorState);
inOrder.verify(mockListener).onSubchannelState(same(underlyingErrorState));
inOrder.verifyNoMoreInteractions();
// Service config returns with the same health check name.
hcLbEventDelivery.handleResolvedAddresses(result1);
// It's delivered to origLb, but nothing else happens
inOrder.verify(origLb).handleResolvedAddresses(result1);
assertThat(healthImpl.calls).isEmpty();
verifyNoMoreInteractions(origLb);
// Service config returns a different health check name.
resolutionAttrs = attrsWithHealthCheckService("FooService");
ResolvedAddresses result2 = ResolvedAddresses.newBuilder().setAddresses(resolvedAddressList).setAttributes(resolutionAttrs).build();
hcLbEventDelivery.handleResolvedAddresses(result2);
inOrder.verify(origLb).handleResolvedAddresses(result2);
// Underlying subchannel is now ready
deliverSubchannelState(0, ConnectivityStateInfo.forNonError(READY));
// Concluded CONNECTING state
inOrder.verify(mockListener).onSubchannelState(eq(ConnectivityStateInfo.forNonError(CONNECTING)));
// Health check RPC is started
assertThat(healthImpl.calls).hasSize(1);
// with the new service name
assertThat(healthImpl.calls.poll().request).isEqualTo(makeRequest("FooService"));
verifyNoMoreInteractions(origLb, mockListener);
}
use of io.grpc.LoadBalancer.Subchannel in project grpc-java by grpc.
the class HealthCheckingLoadBalancerFactoryTest method serviceConfigDisablesHealthCheckWhenRpcInactive.
@Test
public void serviceConfigDisablesHealthCheckWhenRpcInactive() {
Attributes resolutionAttrs = attrsWithHealthCheckService("TeeService");
ResolvedAddresses result1 = ResolvedAddresses.newBuilder().setAddresses(resolvedAddressList).setAttributes(resolutionAttrs).build();
hcLbEventDelivery.handleResolvedAddresses(result1);
verify(origLb).handleResolvedAddresses(result1);
verifyNoMoreInteractions(origLb);
Subchannel subchannel = createSubchannel(0, Attributes.EMPTY);
assertThat(unwrap(subchannel)).isSameInstanceAs(subchannels[0]);
InOrder inOrder = inOrder(origLb, mockStateListeners[0]);
// Underlying subchannel is not READY initially
ConnectivityStateInfo underlyingErrorState = ConnectivityStateInfo.forTransientFailure(Status.UNAVAILABLE.withDescription("connection refused"));
deliverSubchannelState(0, underlyingErrorState);
inOrder.verify(mockStateListeners[0]).onSubchannelState(same(underlyingErrorState));
inOrder.verifyNoMoreInteractions();
// NameResolver gives an update without service config, thus health check will be disabled
ResolvedAddresses result2 = ResolvedAddresses.newBuilder().setAddresses(resolvedAddressList).setAttributes(Attributes.EMPTY).build();
hcLbEventDelivery.handleResolvedAddresses(result2);
inOrder.verify(origLb).handleResolvedAddresses(result2);
// Underlying subchannel is now ready
deliverSubchannelState(0, ConnectivityStateInfo.forNonError(READY));
// Since health check is disabled, READY state is propagated directly.
inOrder.verify(mockStateListeners[0]).onSubchannelState(eq(ConnectivityStateInfo.forNonError(READY)));
// and there is no health check activity.
assertThat(healthImpls[0].calls).isEmpty();
verifyNoMoreInteractions(origLb, mockStateListeners[0]);
}
use of io.grpc.LoadBalancer.Subchannel in project grpc-java by grpc.
the class HealthCheckingLoadBalancerFactoryTest method balancerShutdown.
@Test
public void balancerShutdown() {
Attributes resolutionAttrs = attrsWithHealthCheckService("TeeService");
ResolvedAddresses result = ResolvedAddresses.newBuilder().setAddresses(resolvedAddressList).setAttributes(resolutionAttrs).build();
hcLbEventDelivery.handleResolvedAddresses(result);
verify(origLb).handleResolvedAddresses(result);
verifyNoMoreInteractions(origLb);
ServerSideCall[] serverCalls = new ServerSideCall[NUM_SUBCHANNELS];
final Subchannel[] wrappedSubchannels = new Subchannel[NUM_SUBCHANNELS];
for (int i = 0; i < NUM_SUBCHANNELS; i++) {
Subchannel subchannel = createSubchannel(i, Attributes.EMPTY);
wrappedSubchannels[i] = subchannel;
SubchannelStateListener mockListener = mockStateListeners[i];
assertThat(unwrap(subchannel)).isSameInstanceAs(subchannels[i]);
// Trigger the health check
deliverSubchannelState(i, ConnectivityStateInfo.forNonError(READY));
HealthImpl healthImpl = healthImpls[i];
assertThat(healthImpl.calls).hasSize(1);
serverCalls[i] = healthImpl.calls.poll();
assertThat(serverCalls[i].cancelled).isFalse();
verify(mockListener).onSubchannelState(eq(ConnectivityStateInfo.forNonError(CONNECTING)));
}
doAnswer(new Answer<Void>() {
@Override
public Void answer(InvocationOnMock invocation) {
for (int i = 0; i < NUM_SUBCHANNELS; i++) {
wrappedSubchannels[i].shutdown();
}
return null;
}
}).when(origLb).shutdown();
// Shut down the balancer
hcLbEventDelivery.shutdown();
verify(origLb).shutdown();
// Health check stream should be cancelled
for (int i = 0; i < NUM_SUBCHANNELS; i++) {
assertThat(serverCalls[i].cancelled).isTrue();
verifyNoMoreInteractions(origLb);
verify(mockStateListeners[i]).onSubchannelState(ConnectivityStateInfo.forNonError(SHUTDOWN));
// No more health check call is made or scheduled
assertThat(healthImpls[i].calls).isEmpty();
}
assertThat(clock.getPendingTasks()).isEmpty();
}
use of io.grpc.LoadBalancer.Subchannel in project grpc-java by grpc.
the class HealthCheckingLoadBalancerFactoryTest method serviceConfigDisablesHealthCheckWhenRetryPending.
@Test
public void serviceConfigDisablesHealthCheckWhenRetryPending() {
Attributes resolutionAttrs = attrsWithHealthCheckService("TeeService");
ResolvedAddresses result = ResolvedAddresses.newBuilder().setAddresses(resolvedAddressList).setAttributes(resolutionAttrs).build();
hcLbEventDelivery.handleResolvedAddresses(result);
verify(origLb).handleResolvedAddresses(result);
verifyNoMoreInteractions(origLb);
Subchannel subchannel = createSubchannel(0, Attributes.EMPTY);
assertThat(unwrap(subchannel)).isSameInstanceAs(subchannels[0]);
InOrder inOrder = inOrder(origLb, mockStateListeners[0]);
deliverSubchannelState(0, ConnectivityStateInfo.forNonError(READY));
inOrder.verify(mockStateListeners[0]).onSubchannelState(eq(ConnectivityStateInfo.forNonError(CONNECTING)));
inOrder.verifyNoMoreInteractions();
HealthImpl healthImpl = healthImpls[0];
assertThat(healthImpl.calls).hasSize(1);
// Server closes the stream without responding. Client in retry backoff
assertThat(clock.getPendingTasks()).isEmpty();
healthImpl.calls.poll().responseObserver.onCompleted();
assertThat(clock.getPendingTasks()).hasSize(1);
inOrder.verify(mockStateListeners[0]).onSubchannelState(unavailableStateWithMsg("Health-check stream unexpectedly closed with " + Status.OK + " for 'TeeService'"));
// NameResolver gives an update without service config, thus health check will be disabled
ResolvedAddresses result2 = ResolvedAddresses.newBuilder().setAddresses(resolvedAddressList).setAttributes(Attributes.EMPTY).build();
hcLbEventDelivery.handleResolvedAddresses(result2);
// Retry timer is cancelled
assertThat(clock.getPendingTasks()).isEmpty();
// No retry was attempted
assertThat(healthImpl.calls).isEmpty();
// Subchannel uses original state
inOrder.verify(mockStateListeners[0]).onSubchannelState(eq(ConnectivityStateInfo.forNonError(READY)));
inOrder.verify(origLb).handleResolvedAddresses(result2);
verifyNoMoreInteractions(origLb, mockStateListeners[0]);
}
use of io.grpc.LoadBalancer.Subchannel in project grpc-java by grpc.
the class ManagedChannelImplTest method newCallWithConfigSelector.
@Test
public void newCallWithConfigSelector() {
FakeNameResolverFactory nameResolverFactory = new FakeNameResolverFactory.Builder(expectedUri).setServers(ImmutableList.of(addressGroup)).build();
channelBuilder.nameResolverFactory(nameResolverFactory);
channel = new ManagedChannelImpl(channelBuilder, mockTransportFactory, new FakeBackoffPolicyProvider(), balancerRpcExecutorPool, timer.getStopwatchSupplier(), Collections.<ClientInterceptor>emptyList(), timer.getTimeProvider());
nameResolverFactory.nextConfigOrError.set(ConfigOrError.fromConfig(ManagedChannelServiceConfig.empty()));
final Metadata.Key<String> metadataKey = Metadata.Key.of("test", Metadata.ASCII_STRING_MARSHALLER);
final CallOptions.Key<String> callOptionsKey = CallOptions.Key.create("test");
InternalConfigSelector configSelector = new InternalConfigSelector() {
@Override
public Result selectConfig(final PickSubchannelArgs args) {
return Result.newBuilder().setConfig(ManagedChannelServiceConfig.empty()).setInterceptor(// An interceptor that mutates CallOptions based on headers value.
new ClientInterceptor() {
String value = args.getHeaders().get(metadataKey);
@Override
public <ReqT, RespT> ClientCall<ReqT, RespT> interceptCall(MethodDescriptor<ReqT, RespT> method, CallOptions callOptions, Channel next) {
callOptions = callOptions.withOption(callOptionsKey, value);
return next.newCall(method, callOptions);
}
}).build();
}
};
nameResolverFactory.nextAttributes.set(Attributes.newBuilder().set(InternalConfigSelector.KEY, configSelector).build());
channel.getState(true);
Metadata headers = new Metadata();
headers.put(metadataKey, "fooValue");
ClientStream mockStream = mock(ClientStream.class);
ClientCall<String, Integer> call = channel.newCall(method, CallOptions.DEFAULT);
call.start(mockCallListener, headers);
ArgumentCaptor<Helper> helperCaptor = ArgumentCaptor.forClass(null);
verify(mockLoadBalancerProvider).newLoadBalancer(helperCaptor.capture());
helper = helperCaptor.getValue();
// Make the transport available
Subchannel subchannel = createSubchannelSafely(helper, addressGroup, Attributes.EMPTY, subchannelStateListener);
requestConnectionSafely(helper, subchannel);
verify(mockTransportFactory).newClientTransport(any(SocketAddress.class), any(ClientTransportOptions.class), any(ChannelLogger.class));
MockClientTransportInfo transportInfo = transports.poll();
ConnectionClientTransport mockTransport = transportInfo.transport;
ManagedClientTransport.Listener transportListener = transportInfo.listener;
when(mockTransport.newStream(same(method), same(headers), any(CallOptions.class), ArgumentMatchers.<ClientStreamTracer[]>any())).thenReturn(mockStream);
transportListener.transportReady();
when(mockPicker.pickSubchannel(any(PickSubchannelArgs.class))).thenReturn(PickResult.withSubchannel(subchannel));
updateBalancingStateSafely(helper, READY, mockPicker);
executor.runDueTasks();
ArgumentCaptor<CallOptions> callOptionsCaptor = ArgumentCaptor.forClass(null);
verify(mockTransport).newStream(same(method), same(headers), callOptionsCaptor.capture(), ArgumentMatchers.<ClientStreamTracer[]>any());
assertThat(callOptionsCaptor.getValue().getOption(callOptionsKey)).isEqualTo("fooValue");
verify(mockStream).start(streamListenerCaptor.capture());
// Clean up as much as possible to allow the channel to terminate.
shutdownSafely(helper, subchannel);
timer.forwardNanos(TimeUnit.SECONDS.toNanos(ManagedChannelImpl.SUBCHANNEL_SHUTDOWN_DELAY_SECONDS));
}
Aggregations