|
24 | 24 | import static org.mockito.Mockito.mock;
|
25 | 25 | import static org.mockito.Mockito.times;
|
26 | 26 | import static org.mockito.Mockito.verify;
|
| 27 | +import static org.mockito.Mockito.verifyNoInteractions; |
27 | 28 | import static org.mockito.Mockito.when;
|
28 | 29 |
|
29 | 30 | import com.google.common.collect.ImmutableList;
|
|
46 | 47 | import io.grpc.LoadBalancer.SubchannelPicker;
|
47 | 48 | import io.grpc.LoadBalancer.SubchannelStateListener;
|
48 | 49 | import io.grpc.LoadBalancerProvider;
|
| 50 | +import io.grpc.Metadata; |
49 | 51 | import io.grpc.Status;
|
50 | 52 | import io.grpc.SynchronizationContext;
|
51 | 53 | import io.grpc.internal.FakeClock;
|
@@ -96,6 +98,10 @@ public class OutlierDetectionLoadBalancerTest {
|
96 | 98 | private Helper mockHelper;
|
97 | 99 | @Mock
|
98 | 100 | private SocketAddress mockSocketAddress;
|
| 101 | + @Mock |
| 102 | + private ClientStreamTracer.Factory mockStreamTracerFactory; |
| 103 | + @Mock |
| 104 | + private ClientStreamTracer mockStreamTracer; |
99 | 105 |
|
100 | 106 | @Captor
|
101 | 107 | private ArgumentCaptor<ConnectivityState> connectivityStateCaptor;
|
@@ -193,6 +199,9 @@ public Void answer(InvocationOnMock invocation) throws Throwable {
|
193 | 199 | }
|
194 | 200 | });
|
195 | 201 |
|
| 202 | + when(mockStreamTracerFactory.newClientStreamTracer(any(), |
| 203 | + any())).thenReturn(mockStreamTracer); |
| 204 | + |
196 | 205 | loadBalancer = new OutlierDetectionLoadBalancer(mockHelper, fakeClock.getTimeProvider());
|
197 | 206 | }
|
198 | 207 |
|
@@ -355,6 +364,72 @@ public void delegatePick() throws Exception {
|
355 | 364 | readySubchannel);
|
356 | 365 | }
|
357 | 366 |
|
| 367 | + /** |
| 368 | + * Any ClientStreamTracer.Factory set by the delegate picker should still get used. |
| 369 | + */ |
| 370 | + @Test |
| 371 | + public void delegatePickTracerFactoryPreserved() throws Exception { |
| 372 | + OutlierDetectionLoadBalancerConfig config = new OutlierDetectionLoadBalancerConfig.Builder() |
| 373 | + .setSuccessRateEjection(new SuccessRateEjection.Builder().build()) |
| 374 | + .setChildPolicy(new PolicySelection(fakeLbProvider, null)).build(); |
| 375 | + |
| 376 | + loadBalancer.acceptResolvedAddresses(buildResolvedAddress(config, servers.get(0))); |
| 377 | + |
| 378 | + // Make one of the subchannels READY. |
| 379 | + final Subchannel readySubchannel = subchannels.values().iterator().next(); |
| 380 | + deliverSubchannelState(readySubchannel, ConnectivityStateInfo.forNonError(READY)); |
| 381 | + |
| 382 | + verify(mockHelper, times(2)).updateBalancingState(stateCaptor.capture(), |
| 383 | + pickerCaptor.capture()); |
| 384 | + |
| 385 | + // Make sure that we can pick the single READY subchannel. |
| 386 | + SubchannelPicker picker = pickerCaptor.getAllValues().get(1); |
| 387 | + PickResult pickResult = picker.pickSubchannel(mock(PickSubchannelArgs.class)); |
| 388 | + |
| 389 | + // Calls to a stream tracer created with the factory in the result should make it to a stream |
| 390 | + // tracer the underlying LB/picker is using. |
| 391 | + ClientStreamTracer clientStreamTracer = pickResult.getStreamTracerFactory() |
| 392 | + .newClientStreamTracer(ClientStreamTracer.StreamInfo.newBuilder().build(), new Metadata()); |
| 393 | + clientStreamTracer.inboundHeaders(); |
| 394 | + // The underlying fake LB provider is configured with a factory that returns a mock stream |
| 395 | + // tracer. |
| 396 | + verify(mockStreamTracer).inboundHeaders(); |
| 397 | + } |
| 398 | + |
| 399 | + /** |
| 400 | + * Assure the tracer works even when the underlying LB does not have a tracer to delegate to. |
| 401 | + */ |
| 402 | + @Test |
| 403 | + public void delegatePickTracerFactoryNotSet() throws Exception { |
| 404 | + // We set the mock factory to null to indicate that the delegate does not have its own tracer. |
| 405 | + mockStreamTracerFactory = null; |
| 406 | + |
| 407 | + OutlierDetectionLoadBalancerConfig config = new OutlierDetectionLoadBalancerConfig.Builder() |
| 408 | + .setSuccessRateEjection(new SuccessRateEjection.Builder().build()) |
| 409 | + .setChildPolicy(new PolicySelection(fakeLbProvider, null)).build(); |
| 410 | + |
| 411 | + loadBalancer.acceptResolvedAddresses(buildResolvedAddress(config, servers.get(0))); |
| 412 | + |
| 413 | + // Make one of the subchannels READY. |
| 414 | + final Subchannel readySubchannel = subchannels.values().iterator().next(); |
| 415 | + deliverSubchannelState(readySubchannel, ConnectivityStateInfo.forNonError(READY)); |
| 416 | + |
| 417 | + verify(mockHelper, times(2)).updateBalancingState(stateCaptor.capture(), |
| 418 | + pickerCaptor.capture()); |
| 419 | + |
| 420 | + // Make sure that we can pick the single READY subchannel. |
| 421 | + SubchannelPicker picker = pickerCaptor.getAllValues().get(1); |
| 422 | + PickResult pickResult = picker.pickSubchannel(mock(PickSubchannelArgs.class)); |
| 423 | + |
| 424 | + // With no delegate tracers factory a call to the OD tracer should still work |
| 425 | + ClientStreamTracer clientStreamTracer = pickResult.getStreamTracerFactory() |
| 426 | + .newClientStreamTracer(ClientStreamTracer.StreamInfo.newBuilder().build(), new Metadata()); |
| 427 | + clientStreamTracer.inboundHeaders(); |
| 428 | + |
| 429 | + // Sanity check to make sure the delegate tracer does not get called. |
| 430 | + verifyNoInteractions(mockStreamTracer); |
| 431 | + } |
| 432 | + |
358 | 433 | /**
|
359 | 434 | * The success rate algorithm leaves a healthy set of addresses alone.
|
360 | 435 | */
|
@@ -1121,7 +1196,7 @@ void assertEjectedSubchannels(Set<SocketAddress> addresses) {
|
1121 | 1196 | }
|
1122 | 1197 |
|
1123 | 1198 | /** Round robin like fake load balancer. */
|
1124 |
| - private static final class FakeLoadBalancer extends LoadBalancer { |
| 1199 | + private final class FakeLoadBalancer extends LoadBalancer { |
1125 | 1200 | private final Helper helper;
|
1126 | 1201 |
|
1127 | 1202 | List<Subchannel> subchannelList;
|
@@ -1159,7 +1234,8 @@ public PickResult pickSubchannel(PickSubchannelArgs args) {
|
1159 | 1234 | if (lastPickIndex < 0 || lastPickIndex > subchannelList.size() - 1) {
|
1160 | 1235 | lastPickIndex = 0;
|
1161 | 1236 | }
|
1162 |
| - return PickResult.withSubchannel(subchannelList.get(lastPickIndex++)); |
| 1237 | + return PickResult.withSubchannel(subchannelList.get(lastPickIndex++), |
| 1238 | + mockStreamTracerFactory); |
1163 | 1239 | }
|
1164 | 1240 | };
|
1165 | 1241 | helper.updateBalancingState(state, picker);
|
|
0 commit comments