mirror of https://github.com/grpc/grpc-java.git
Enable Happy Eyeballs by default (#11022)
* Flip the flag * Fix test flakiness where IPv6 was not considered loopback
This commit is contained in:
parent
2c83ef0632
commit
51f811df86
|
@ -34,6 +34,7 @@ import io.grpc.EquivalentAddressGroup;
|
|||
import io.grpc.ExperimentalApi;
|
||||
import io.grpc.LoadBalancer;
|
||||
import io.grpc.Status;
|
||||
import io.grpc.SynchronizationContext;
|
||||
import io.grpc.SynchronizationContext.ScheduledHandle;
|
||||
import java.net.SocketAddress;
|
||||
import java.util.ArrayList;
|
||||
|
@ -72,7 +73,7 @@ final class PickFirstLeafLoadBalancer extends LoadBalancer {
|
|||
private ConnectivityState rawConnectivityState = IDLE;
|
||||
private ConnectivityState concludedState = IDLE;
|
||||
private final boolean enableHappyEyeballs =
|
||||
GrpcUtil.getFlag(GRPC_EXPERIMENTAL_XDS_DUALSTACK_ENDPOINTS, false);
|
||||
GrpcUtil.getFlag(GRPC_EXPERIMENTAL_XDS_DUALSTACK_ENDPOINTS, true);
|
||||
|
||||
PickFirstLeafLoadBalancer(Helper helper) {
|
||||
this.helper = checkNotNull(helper, "helper");
|
||||
|
@ -406,7 +407,16 @@ final class PickFirstLeafLoadBalancer extends LoadBalancer {
|
|||
}
|
||||
}
|
||||
|
||||
scheduleConnectionTask = helper.getSynchronizationContext().schedule(
|
||||
SynchronizationContext synchronizationContext = null;
|
||||
try {
|
||||
synchronizationContext = helper.getSynchronizationContext();
|
||||
} catch (NullPointerException e) {
|
||||
// All helpers should have a sync context, but if one doesn't (ex. user had a custom test)
|
||||
// we don't want to break previously working functionality.
|
||||
return;
|
||||
}
|
||||
|
||||
scheduleConnectionTask = synchronizationContext.schedule(
|
||||
new StartNextConnection(),
|
||||
CONNECTION_DELAY_INTERVAL_MS,
|
||||
TimeUnit.MILLISECONDS,
|
||||
|
|
|
@ -48,6 +48,7 @@ import io.grpc.LoadBalancerProvider;
|
|||
import io.grpc.LoadBalancerRegistry;
|
||||
import io.grpc.NameResolver.ConfigOrError;
|
||||
import io.grpc.Status;
|
||||
import io.grpc.SynchronizationContext;
|
||||
import io.grpc.internal.AutoConfiguredLoadBalancerFactory.AutoConfiguredLoadBalancer;
|
||||
import io.grpc.internal.PickFirstLeafLoadBalancer.PickFirstLeafLoadBalancerConfig;
|
||||
import io.grpc.internal.PickFirstLoadBalancer.PickFirstLoadBalancerConfig;
|
||||
|
@ -58,6 +59,7 @@ import java.net.SocketAddress;
|
|||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.ScheduledExecutorService;
|
||||
import java.util.concurrent.atomic.AtomicBoolean;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
import java.util.concurrent.atomic.AtomicReference;
|
||||
|
@ -691,6 +693,16 @@ public class AutoConfiguredLoadBalancerFactoryTest {
|
|||
}
|
||||
|
||||
private class TestHelper extends ForwardingLoadBalancerHelper {
|
||||
final SynchronizationContext syncContext = new SynchronizationContext(
|
||||
new Thread.UncaughtExceptionHandler() {
|
||||
@Override
|
||||
public void uncaughtException(Thread t, Throwable e) {
|
||||
throw new AssertionError(e);
|
||||
}
|
||||
});
|
||||
|
||||
final FakeClock fakeClock = new FakeClock();
|
||||
|
||||
@Override
|
||||
protected Helper delegate() {
|
||||
return null;
|
||||
|
@ -705,6 +717,16 @@ public class AutoConfiguredLoadBalancerFactoryTest {
|
|||
public void updateBalancingState(ConnectivityState newState, SubchannelPicker newPicker) {
|
||||
// noop
|
||||
}
|
||||
|
||||
@Override
|
||||
public SynchronizationContext getSynchronizationContext() {
|
||||
return syncContext;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ScheduledExecutorService getScheduledExecutorService() {
|
||||
return fakeClock.getScheduledExecutorService();
|
||||
}
|
||||
}
|
||||
|
||||
private static class TestSubchannel extends Subchannel {
|
||||
|
|
|
@ -18,6 +18,7 @@ package io.grpc.testing.integration;
|
|||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertNotEquals;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
|
||||
import io.grpc.ChannelCredentials;
|
||||
import io.grpc.ManagedChannelBuilder;
|
||||
|
@ -38,7 +39,6 @@ import io.grpc.okhttp.OkHttpServerBuilder;
|
|||
import io.grpc.stub.MetadataUtils;
|
||||
import io.grpc.testing.TlsTesting;
|
||||
import java.io.IOException;
|
||||
import java.net.InetAddress;
|
||||
import java.net.InetSocketAddress;
|
||||
import java.util.Arrays;
|
||||
import org.junit.Test;
|
||||
|
@ -139,7 +139,7 @@ public class Http2Test extends AbstractInteropTest {
|
|||
@Test
|
||||
public void remoteAddr() {
|
||||
InetSocketAddress isa = (InetSocketAddress) obtainRemoteClientAddr();
|
||||
assertEquals(InetAddress.getLoopbackAddress(), isa.getAddress());
|
||||
assertTrue(isa.getAddress().isLoopbackAddress());
|
||||
// It should not be the same as the server
|
||||
assertNotEquals(((InetSocketAddress) getListenAddress()).getPort(), isa.getPort());
|
||||
}
|
||||
|
@ -147,7 +147,7 @@ public class Http2Test extends AbstractInteropTest {
|
|||
@Test
|
||||
public void localAddr() throws Exception {
|
||||
InetSocketAddress isa = (InetSocketAddress) obtainLocalServerAddr();
|
||||
assertEquals(InetAddress.getLoopbackAddress(), isa.getAddress());
|
||||
assertTrue(isa.getAddress().isLoopbackAddress());
|
||||
assertEquals(((InetSocketAddress) getListenAddress()).getPort(), isa.getPort());
|
||||
}
|
||||
|
||||
|
|
|
@ -217,6 +217,8 @@ public class RlsLoadBalancerTest {
|
|||
inOrder.verify(helper).createSubchannel(any(CreateSubchannelArgs.class));
|
||||
inOrder.verify(helper, atLeast(0))
|
||||
.updateBalancingState(eq(ConnectivityState.CONNECTING), any(SubchannelPicker.class));
|
||||
inOrder.verify(helper, atLeast(0)).getSynchronizationContext();
|
||||
inOrder.verify(helper, atLeast(0)).getScheduledExecutorService();
|
||||
inOrder.verifyNoMoreInteractions();
|
||||
assertThat(res.getStatus().isOk()).isTrue();
|
||||
assertThat(subchannels).hasSize(1);
|
||||
|
@ -325,6 +327,8 @@ public class RlsLoadBalancerTest {
|
|||
inOrder.verify(helper).createSubchannel(any(CreateSubchannelArgs.class));
|
||||
inOrder.verify(helper, atLeast(0))
|
||||
.updateBalancingState(eq(ConnectivityState.CONNECTING), any(SubchannelPicker.class));
|
||||
inOrder.verify(helper, atLeast(0)).getSynchronizationContext();
|
||||
inOrder.verify(helper, atLeast(0)).getScheduledExecutorService();
|
||||
inOrder.verifyNoMoreInteractions();
|
||||
assertThat(res.getStatus().isOk()).isTrue();
|
||||
|
||||
|
|
|
@ -32,7 +32,6 @@ import static org.mockito.Mockito.mock;
|
|||
import static org.mockito.Mockito.never;
|
||||
import static org.mockito.Mockito.times;
|
||||
import static org.mockito.Mockito.verify;
|
||||
import static org.mockito.Mockito.verifyNoMoreInteractions;
|
||||
|
||||
import com.google.common.collect.Lists;
|
||||
import io.grpc.Attributes;
|
||||
|
@ -128,7 +127,7 @@ public class MultiChildLoadBalancerTest {
|
|||
(TestLb.TestSubchannelPicker) pickerCaptor.getValue();
|
||||
assertThat(subchannelPicker.getReadySubchannels()).containsExactly(readySubchannel);
|
||||
|
||||
verifyNoMoreInteractions(mockHelper);
|
||||
AbstractTestHelper.verifyNoMoreMeaningfulInteractions(mockHelper);
|
||||
}
|
||||
|
||||
@Test
|
||||
|
@ -192,7 +191,7 @@ public class MultiChildLoadBalancerTest {
|
|||
verify(mockHelper, times(3)).createSubchannel(any(LoadBalancer.CreateSubchannelArgs.class));
|
||||
inOrder.verify(mockHelper, times(2)).updateBalancingState(eq(READY), pickerCaptor.capture());
|
||||
|
||||
verifyNoMoreInteractions(mockHelper);
|
||||
AbstractTestHelper.verifyNoMoreMeaningfulInteractions(mockHelper);
|
||||
}
|
||||
|
||||
@Test
|
||||
|
|
|
@ -153,7 +153,7 @@ public class RoundRobinLoadBalancerTest {
|
|||
assertEquals(READY, stateCaptor.getAllValues().get(1));
|
||||
assertThat(getList(pickerCaptor.getValue())).containsExactly(readySubchannel);
|
||||
|
||||
verifyNoMoreInteractions(mockHelper);
|
||||
AbstractTestHelper.verifyNoMoreMeaningfulInteractions(mockHelper);
|
||||
}
|
||||
|
||||
@Test
|
||||
|
@ -234,7 +234,7 @@ public class RoundRobinLoadBalancerTest {
|
|||
picker = pickerCaptor.getValue();
|
||||
assertThat(getList(picker)).containsExactly(oldSubchannel, newSubchannel);
|
||||
|
||||
verifyNoMoreInteractions(mockHelper);
|
||||
AbstractTestHelper.verifyNoMoreMeaningfulInteractions(mockHelper);
|
||||
}
|
||||
|
||||
@Test
|
||||
|
@ -269,7 +269,7 @@ public class RoundRobinLoadBalancerTest {
|
|||
|
||||
verify(subchannel, atLeastOnce()).requestConnection();
|
||||
verify(mockHelper, times(3)).createSubchannel(any(CreateSubchannelArgs.class));
|
||||
verifyNoMoreInteractions(mockHelper);
|
||||
AbstractTestHelper.verifyNoMoreMeaningfulInteractions(mockHelper);
|
||||
}
|
||||
|
||||
@Test
|
||||
|
@ -355,7 +355,7 @@ public class RoundRobinLoadBalancerTest {
|
|||
inOrder.verify(mockHelper).updateBalancingState(eq(CONNECTING), isA(EmptyPicker.class));
|
||||
}
|
||||
|
||||
verifyNoMoreInteractions(mockHelper);
|
||||
AbstractTestHelper.verifyNoMoreMeaningfulInteractions(mockHelper);
|
||||
}
|
||||
|
||||
@Test
|
||||
|
@ -432,7 +432,7 @@ public class RoundRobinLoadBalancerTest {
|
|||
|
||||
LoadBalancer.PickResult pickResult2 = pickerCaptor.getValue().pickSubchannel(mockArgs);
|
||||
assertEquals(readySubchannel, pickResult2.getSubchannel());
|
||||
verifyNoMoreInteractions(mockHelper);
|
||||
AbstractTestHelper.verifyNoMoreMeaningfulInteractions(mockHelper);
|
||||
}
|
||||
|
||||
@Test
|
||||
|
|
|
@ -18,7 +18,10 @@ package io.grpc.util;
|
|||
|
||||
import static org.mockito.AdditionalAnswers.delegatesTo;
|
||||
import static org.mockito.ArgumentMatchers.eq;
|
||||
import static org.mockito.Mockito.atLeast;
|
||||
import static org.mockito.Mockito.mock;
|
||||
import static org.mockito.Mockito.verify;
|
||||
import static org.mockito.Mockito.verifyNoMoreInteractions;
|
||||
|
||||
import com.google.common.collect.Maps;
|
||||
import io.grpc.Attributes;
|
||||
|
@ -32,12 +35,15 @@ import io.grpc.LoadBalancer.Helper;
|
|||
import io.grpc.LoadBalancer.Subchannel;
|
||||
import io.grpc.LoadBalancer.SubchannelPicker;
|
||||
import io.grpc.LoadBalancer.SubchannelStateListener;
|
||||
import io.grpc.SynchronizationContext;
|
||||
import io.grpc.internal.FakeClock;
|
||||
import io.grpc.internal.PickFirstLoadBalancerProvider;
|
||||
import java.net.SocketAddress;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.ScheduledExecutorService;
|
||||
import org.mockito.ArgumentCaptor;
|
||||
import org.mockito.InOrder;
|
||||
|
||||
|
@ -60,9 +66,26 @@ public abstract class AbstractTestHelper extends ForwardingLoadBalancerHelper {
|
|||
protected final Map<Subchannel, Subchannel> realToMockSubChannelMap = new HashMap<>();
|
||||
private final Map<Subchannel, SubchannelStateListener> subchannelStateListeners =
|
||||
Maps.newLinkedHashMap();
|
||||
private final FakeClock fakeClock;
|
||||
private final SynchronizationContext syncContext;
|
||||
|
||||
public abstract Map<List<EquivalentAddressGroup>, Subchannel> getSubchannelMap();
|
||||
|
||||
public AbstractTestHelper() {
|
||||
this(new FakeClock(), new SynchronizationContext(new Thread.UncaughtExceptionHandler() {
|
||||
@Override
|
||||
public void uncaughtException(Thread t, Throwable e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}));
|
||||
}
|
||||
|
||||
public AbstractTestHelper(FakeClock fakeClock, SynchronizationContext syncContext) {
|
||||
super();
|
||||
this.fakeClock = fakeClock;
|
||||
this.syncContext = syncContext;
|
||||
}
|
||||
|
||||
public Map<Subchannel, Subchannel> getMockToRealSubChannelMap() {
|
||||
return mockToRealSubChannelMap;
|
||||
}
|
||||
|
@ -79,6 +102,18 @@ public abstract class AbstractTestHelper extends ForwardingLoadBalancerHelper {
|
|||
return subchannelStateListeners;
|
||||
}
|
||||
|
||||
public static final FakeClock.TaskFilter NOT_START_NEXT_CONNECTION =
|
||||
new FakeClock.TaskFilter() {
|
||||
@Override
|
||||
public boolean shouldAccept(Runnable command) {
|
||||
return !command.toString().contains("StartNextConnection");
|
||||
}
|
||||
};
|
||||
|
||||
public static int getNumFilteredPendingTasks(FakeClock fakeClock) {
|
||||
return fakeClock.getPendingTasks(NOT_START_NEXT_CONNECTION).size();
|
||||
}
|
||||
|
||||
public void deliverSubchannelState(Subchannel subchannel, ConnectivityStateInfo newState) {
|
||||
Subchannel realSc = getMockToRealSubChannelMap().get(subchannel);
|
||||
if (realSc == null) {
|
||||
|
@ -128,6 +163,16 @@ public abstract class AbstractTestHelper extends ForwardingLoadBalancerHelper {
|
|||
((TestSubchannel)subchannel).channel = channel;
|
||||
}
|
||||
|
||||
@Override
|
||||
public SynchronizationContext getSynchronizationContext() {
|
||||
return syncContext;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ScheduledExecutorService getScheduledExecutorService() {
|
||||
return fakeClock.getScheduledExecutorService();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "Test Helper";
|
||||
|
@ -148,6 +193,17 @@ public abstract class AbstractTestHelper extends ForwardingLoadBalancerHelper {
|
|||
}
|
||||
}
|
||||
|
||||
public static void verifyNoMoreMeaningfulInteractions(Helper helper) {
|
||||
verify(helper, atLeast(0)).getSynchronizationContext();
|
||||
verify(helper, atLeast(0)).getScheduledExecutorService();
|
||||
verifyNoMoreInteractions(helper);
|
||||
}
|
||||
|
||||
public static void verifyNoMoreMeaningfulInteractions(Helper helper, InOrder inOrder) {
|
||||
inOrder.verify(helper, atLeast(0)).getSynchronizationContext();
|
||||
inOrder.verify(helper, atLeast(0)).getScheduledExecutorService();
|
||||
inOrder.verifyNoMoreInteractions();
|
||||
}
|
||||
|
||||
protected class TestSubchannel extends ForwardingSubchannel {
|
||||
CreateSubchannelArgs args;
|
||||
|
|
|
@ -101,7 +101,7 @@ class XdsEndpointResource extends XdsResourceType<EdsUpdate> {
|
|||
}
|
||||
|
||||
private static boolean isEnabledXdsDualStack() {
|
||||
return GrpcUtil.getFlag(GRPC_EXPERIMENTAL_XDS_DUALSTACK_ENDPOINTS, false);
|
||||
return GrpcUtil.getFlag(GRPC_EXPERIMENTAL_XDS_DUALSTACK_ENDPOINTS, true);
|
||||
}
|
||||
|
||||
private static EdsUpdate processClusterLoadAssignment(ClusterLoadAssignment assignment)
|
||||
|
|
|
@ -159,7 +159,7 @@ public class LeastRequestLoadBalancerTest {
|
|||
assertEquals(READY, stateCaptor.getAllValues().get(1));
|
||||
assertThat(getList(pickerCaptor.getValue())).containsExactly(readySubchannel);
|
||||
|
||||
verifyNoMoreInteractions(helper);
|
||||
AbstractTestHelper.verifyNoMoreMeaningfulInteractions(helper);
|
||||
}
|
||||
|
||||
@Test
|
||||
|
@ -226,7 +226,7 @@ public class LeastRequestLoadBalancerTest {
|
|||
|
||||
assertThat(getList(pickerCaptor.getValue())).containsExactly(oldSubchannel, newSubchannel);
|
||||
|
||||
verifyNoMoreInteractions(helper);
|
||||
AbstractTestHelper.verifyNoMoreMeaningfulInteractions(helper);
|
||||
}
|
||||
|
||||
private Subchannel getSubchannel(EquivalentAddressGroup removedEag) {
|
||||
|
@ -288,7 +288,7 @@ public class LeastRequestLoadBalancerTest {
|
|||
int expectedCount = PickFirstLoadBalancerProvider.isEnabledNewPickFirst() ? 1 : 2;
|
||||
verify(subchannel, times(expectedCount)).requestConnection();
|
||||
verify(helper, times(3)).createSubchannel(any(CreateSubchannelArgs.class));
|
||||
verifyNoMoreInteractions(helper);
|
||||
AbstractTestHelper.verifyNoMoreMeaningfulInteractions(helper);
|
||||
}
|
||||
|
||||
@Test
|
||||
|
@ -319,7 +319,7 @@ public class LeastRequestLoadBalancerTest {
|
|||
// At this point it should use a ReadyPicker with newConfig
|
||||
pickerCaptor.getValue().pickSubchannel(mockArgs);
|
||||
verify(mockRandom, times(oldConfig.choiceCount + newConfig.choiceCount)).nextInt(1);
|
||||
verifyNoMoreInteractions(helper);
|
||||
AbstractTestHelper.verifyNoMoreMeaningfulInteractions(helper);
|
||||
}
|
||||
|
||||
@Test
|
||||
|
@ -375,7 +375,7 @@ public class LeastRequestLoadBalancerTest {
|
|||
inOrder.verify(helper).updateBalancingState(eq(READY), isA(ReadyPicker.class));
|
||||
|
||||
verify(helper, times(3)).createSubchannel(any(CreateSubchannelArgs.class));
|
||||
verifyNoMoreInteractions(helper);
|
||||
AbstractTestHelper.verifyNoMoreMeaningfulInteractions(helper);
|
||||
}
|
||||
|
||||
private String getStatusString(SubchannelPicker picker) {
|
||||
|
@ -426,7 +426,7 @@ public class LeastRequestLoadBalancerTest {
|
|||
inOrder.verify(helper).updateBalancingState(eq(CONNECTING), isA(EmptyPicker.class));
|
||||
}
|
||||
|
||||
verifyNoMoreInteractions(helper);
|
||||
AbstractTestHelper.verifyNoMoreMeaningfulInteractions(helper);
|
||||
}
|
||||
|
||||
@Test
|
||||
|
@ -548,7 +548,7 @@ public class LeastRequestLoadBalancerTest {
|
|||
LoadBalancer.PickResult pickResult2 = pickerCaptor.getValue().pickSubchannel(mockArgs);
|
||||
verify(mockRandom, times(choiceCount * 2)).nextInt(1);
|
||||
assertEquals(readySubchannel, pickResult2.getSubchannel());
|
||||
verifyNoMoreInteractions(helper);
|
||||
AbstractTestHelper.verifyNoMoreMeaningfulInteractions(helper);
|
||||
}
|
||||
|
||||
@Test
|
||||
|
|
|
@ -59,6 +59,7 @@ import io.grpc.Metadata;
|
|||
import io.grpc.Status;
|
||||
import io.grpc.Status.Code;
|
||||
import io.grpc.SynchronizationContext;
|
||||
import io.grpc.internal.FakeClock;
|
||||
import io.grpc.internal.PickFirstLoadBalancerProvider;
|
||||
import io.grpc.internal.PickSubchannelArgsImpl;
|
||||
import io.grpc.testing.TestMethodDescriptors;
|
||||
|
@ -161,7 +162,7 @@ public class RingHashLoadBalancerTest {
|
|||
verify(helper).updateBalancingState(eq(READY), pickerCaptor.capture());
|
||||
result = pickerCaptor.getValue().pickSubchannel(args);
|
||||
assertThat(result.getSubchannel()).isSameInstanceAs(subchannel);
|
||||
verifyNoMoreInteractions(helper);
|
||||
AbstractTestHelper.verifyNoMoreMeaningfulInteractions(helper);
|
||||
}
|
||||
|
||||
@Test
|
||||
|
@ -1055,6 +1056,9 @@ public class RingHashLoadBalancerTest {
|
|||
}
|
||||
|
||||
private class TestHelper extends AbstractTestHelper {
|
||||
public TestHelper() {
|
||||
super(new FakeClock(), syncContext);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<List<EquivalentAddressGroup>, Subchannel> getSubchannelMap() {
|
||||
|
@ -1066,11 +1070,6 @@ public class RingHashLoadBalancerTest {
|
|||
return AUTHORITY;
|
||||
}
|
||||
|
||||
@Override
|
||||
public SynchronizationContext getSynchronizationContext() {
|
||||
return syncContext;
|
||||
}
|
||||
|
||||
private Subchannel getMockSubchannel(Subchannel realSubchannel) {
|
||||
return realToMockSubChannelMap.get(realSubchannel);
|
||||
}
|
||||
|
|
|
@ -22,6 +22,8 @@ import static org.mockito.AdditionalAnswers.delegatesTo;
|
|||
import static org.mockito.Mockito.any;
|
||||
import static org.mockito.Mockito.eq;
|
||||
import static org.mockito.Mockito.mock;
|
||||
import static org.mockito.Mockito.never;
|
||||
import static org.mockito.Mockito.reset;
|
||||
import static org.mockito.Mockito.times;
|
||||
import static org.mockito.Mockito.verify;
|
||||
import static org.mockito.Mockito.verifyNoMoreInteractions;
|
||||
|
@ -50,6 +52,7 @@ import io.grpc.LoadBalancer.SubchannelStateListener;
|
|||
import io.grpc.Status;
|
||||
import io.grpc.SynchronizationContext;
|
||||
import io.grpc.internal.FakeClock;
|
||||
import io.grpc.internal.GrpcUtil;
|
||||
import io.grpc.internal.TestUtils;
|
||||
import io.grpc.services.InternalCallMetricRecorder;
|
||||
import io.grpc.services.MetricReport;
|
||||
|
@ -71,7 +74,6 @@ import java.util.Random;
|
|||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.concurrent.ConcurrentLinkedQueue;
|
||||
import java.util.concurrent.CyclicBarrier;
|
||||
import java.util.concurrent.ScheduledExecutorService;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
import org.junit.Before;
|
||||
|
@ -94,8 +96,8 @@ public class WeightedRoundRobinLoadBalancerTest {
|
|||
@Rule
|
||||
public final MockitoRule mockito = MockitoJUnit.rule();
|
||||
|
||||
private final TestHelper testHelperInstance = new TestHelper();
|
||||
private Helper helper = mock(Helper.class, delegatesTo(testHelperInstance));
|
||||
private final TestHelper testHelperInstance;
|
||||
private final Helper helper;
|
||||
|
||||
@Mock
|
||||
private LoadBalancer.PickSubchannelArgs mockArgs;
|
||||
|
@ -134,6 +136,11 @@ public class WeightedRoundRobinLoadBalancerTest {
|
|||
}
|
||||
});
|
||||
|
||||
public WeightedRoundRobinLoadBalancerTest() {
|
||||
testHelperInstance = new TestHelper();
|
||||
helper = mock(Helper.class, delegatesTo(testHelperInstance));
|
||||
}
|
||||
|
||||
@Before
|
||||
public void setup() {
|
||||
for (int i = 0; i < 3; i++) {
|
||||
|
@ -161,6 +168,7 @@ public class WeightedRoundRobinLoadBalancerTest {
|
|||
new FakeRandom(0));
|
||||
|
||||
verify(helper, times(3)).createSubchannel(any(CreateSubchannelArgs.class));
|
||||
reset(helper);
|
||||
}
|
||||
|
||||
@Test
|
||||
|
@ -184,9 +192,9 @@ public class WeightedRoundRobinLoadBalancerTest {
|
|||
syncContext.execute(() -> wrr.acceptResolvedAddresses(ResolvedAddresses.newBuilder()
|
||||
.setAddresses(servers).setLoadBalancingPolicyConfig(weightedConfig)
|
||||
.setAttributes(affinity).build()));
|
||||
verify(helper, times(6)).createSubchannel(
|
||||
verify(helper, times(3)).createSubchannel(
|
||||
any(CreateSubchannelArgs.class));
|
||||
assertThat(fakeClock.getPendingTasks().size()).isEqualTo(1);
|
||||
assertThat(getNumFilteredPendingTasks()).isEqualTo(1);
|
||||
|
||||
Iterator<Subchannel> it = subchannels.values().iterator();
|
||||
Subchannel readySubchannel1 = it.next();
|
||||
|
@ -219,7 +227,8 @@ public class WeightedRoundRobinLoadBalancerTest {
|
|||
weightedChild2.new OrcaReportListener(weightedConfig.errorUtilizationPenalty).onLoadReport(
|
||||
InternalCallMetricRecorder.createMetricReport(
|
||||
0.2, 0, 0.1, 1, 0, new HashMap<>(), new HashMap<>(), new HashMap<>()));
|
||||
assertThat(fakeClock.forwardTime(11, TimeUnit.SECONDS)).isEqualTo(1);
|
||||
int expectedTasks = isEnabledHappyEyeballs() ? 2 : 1;
|
||||
assertThat(fakeClock.forwardTime(11, TimeUnit.SECONDS)).isEqualTo(expectedTasks);
|
||||
|
||||
assertThat(getAddressesFromPick(weightedPicker)).isEqualTo(weightedChild1.getEag());
|
||||
assertThat(fakeClock.getPendingTasks().size()).isEqualTo(1);
|
||||
|
@ -229,13 +238,13 @@ public class WeightedRoundRobinLoadBalancerTest {
|
|||
syncContext.execute(() -> wrr.acceptResolvedAddresses(ResolvedAddresses.newBuilder()
|
||||
.setAddresses(servers).setLoadBalancingPolicyConfig(weightedConfig)
|
||||
.setAttributes(affinity).build()));
|
||||
assertThat(fakeClock.getPendingTasks().size()).isEqualTo(1);
|
||||
assertThat(getNumFilteredPendingTasks()).isEqualTo(1);
|
||||
|
||||
syncContext.execute(() -> wrr.shutdown());
|
||||
for (Subchannel subchannel: subchannels.values()) {
|
||||
verify(subchannel).shutdown();
|
||||
}
|
||||
assertThat(fakeClock.getPendingTasks().size()).isEqualTo(0);
|
||||
assertThat(getNumFilteredPendingTasks()).isEqualTo(0);
|
||||
verifyNoMoreInteractions(mockArgs);
|
||||
}
|
||||
|
||||
|
@ -252,7 +261,7 @@ public class WeightedRoundRobinLoadBalancerTest {
|
|||
syncContext.execute(() -> wrr.acceptResolvedAddresses(ResolvedAddresses.newBuilder()
|
||||
.setAddresses(servers).setLoadBalancingPolicyConfig(weightedConfig)
|
||||
.setAttributes(affinity).build()));
|
||||
verify(helper, times(6)).createSubchannel(
|
||||
verify(helper, times(3)).createSubchannel(
|
||||
any(CreateSubchannelArgs.class));
|
||||
Iterator<Subchannel> it = subchannels.values().iterator();
|
||||
Subchannel readySubchannel1 = it.next();
|
||||
|
@ -273,7 +282,8 @@ public class WeightedRoundRobinLoadBalancerTest {
|
|||
weightedChild2.new OrcaReportListener(weightedConfig.errorUtilizationPenalty).onLoadReport(
|
||||
InternalCallMetricRecorder.createMetricReport(
|
||||
0.9, 0, 0.1, 1, 0, new HashMap<>(), new HashMap<>(), new HashMap<>()));
|
||||
assertThat(fakeClock.forwardTime(11, TimeUnit.SECONDS)).isEqualTo(1);
|
||||
int expectedTasks = isEnabledHappyEyeballs() ? 2 : 1;
|
||||
assertThat(fakeClock.forwardTime(11, TimeUnit.SECONDS)).isEqualTo(expectedTasks);
|
||||
PickResult pickResult = weightedPicker.pickSubchannel(mockArgs);
|
||||
assertThat(getAddresses(pickResult))
|
||||
.isEqualTo(weightedChild1.getEag());
|
||||
|
@ -306,9 +316,9 @@ public class WeightedRoundRobinLoadBalancerTest {
|
|||
syncContext.execute(() -> wrr.acceptResolvedAddresses(ResolvedAddresses.newBuilder()
|
||||
.setAddresses(servers).setLoadBalancingPolicyConfig(weightedConfig)
|
||||
.setAttributes(affinity).build()));
|
||||
verify(helper, times(6)).createSubchannel(
|
||||
verify(helper, times(3)).createSubchannel(
|
||||
any(CreateSubchannelArgs.class));
|
||||
assertThat(fakeClock.getPendingTasks().size()).isEqualTo(1);
|
||||
assertThat(getNumFilteredPendingTasks()).isEqualTo(1);
|
||||
|
||||
Iterator<Subchannel> it = subchannels.values().iterator();
|
||||
Subchannel readySubchannel1 = it.next();
|
||||
|
@ -489,19 +499,20 @@ public class WeightedRoundRobinLoadBalancerTest {
|
|||
assertThat(wrr.acceptResolvedAddresses(ResolvedAddresses.newBuilder()
|
||||
.setAddresses(servers).setLoadBalancingPolicyConfig(null)
|
||||
.setAttributes(affinity).build()).isOk()).isFalse();
|
||||
verify(helper, times(3)).createSubchannel(any(CreateSubchannelArgs.class));
|
||||
verify(helper, never()).createSubchannel(any(CreateSubchannelArgs.class));
|
||||
verify(helper).updateBalancingState(eq(ConnectivityState.TRANSIENT_FAILURE), any());
|
||||
assertThat(fakeClock.getPendingTasks()).isEmpty();
|
||||
|
||||
syncContext.execute(() -> wrr.acceptResolvedAddresses(ResolvedAddresses.newBuilder()
|
||||
.setAddresses(servers).setLoadBalancingPolicyConfig(weightedConfig)
|
||||
.setAttributes(affinity).build()));
|
||||
verify(helper, times(6)).createSubchannel(
|
||||
verify(helper, times(3)).createSubchannel(
|
||||
any(CreateSubchannelArgs.class));
|
||||
verify(helper).updateBalancingState(eq(CONNECTING), pickerCaptor.capture());
|
||||
assertThat(pickerCaptor.getValue().getClass().getName())
|
||||
.isEqualTo("io.grpc.util.RoundRobinLoadBalancer$EmptyPicker");
|
||||
assertThat(fakeClock.forwardTime(11, TimeUnit.SECONDS)).isEqualTo(1);
|
||||
int expectedCount = isEnabledHappyEyeballs() ? servers.size() + 1 : 1;
|
||||
assertThat(fakeClock.forwardTime(11, TimeUnit.SECONDS)).isEqualTo( expectedCount);
|
||||
}
|
||||
|
||||
@Test
|
||||
|
@ -509,9 +520,8 @@ public class WeightedRoundRobinLoadBalancerTest {
|
|||
syncContext.execute(() -> wrr.acceptResolvedAddresses(ResolvedAddresses.newBuilder()
|
||||
.setAddresses(servers).setLoadBalancingPolicyConfig(weightedConfig)
|
||||
.setAttributes(affinity).build()));
|
||||
verify(helper, times(6)).createSubchannel(
|
||||
any(CreateSubchannelArgs.class));
|
||||
assertThat(fakeClock.getPendingTasks().size()).isEqualTo(1);
|
||||
verify(helper, times(3)).createSubchannel(any(CreateSubchannelArgs.class));
|
||||
assertThat(getNumFilteredPendingTasks()).isEqualTo(1);
|
||||
|
||||
Iterator<Subchannel> it = subchannels.values().iterator();
|
||||
Subchannel readySubchannel1 = it.next();
|
||||
|
@ -532,7 +542,8 @@ public class WeightedRoundRobinLoadBalancerTest {
|
|||
weightedChild2.new OrcaReportListener(weightedConfig.errorUtilizationPenalty).onLoadReport(
|
||||
InternalCallMetricRecorder.createMetricReport(
|
||||
0.2, 0, 0.1, 1, 0, new HashMap<>(), new HashMap<>(), new HashMap<>()));
|
||||
assertThat(fakeClock.forwardTime(5, TimeUnit.SECONDS)).isEqualTo(1);
|
||||
int expectedCount = isEnabledHappyEyeballs() ? 2 : 1;
|
||||
assertThat(fakeClock.forwardTime(5, TimeUnit.SECONDS)).isEqualTo(expectedCount);
|
||||
Map<EquivalentAddressGroup, Integer> pickCount = new HashMap<>();
|
||||
for (int i = 0; i < 10000; i++) {
|
||||
EquivalentAddressGroup result = getAddressesFromPick(weightedPicker);
|
||||
|
@ -557,14 +568,18 @@ public class WeightedRoundRobinLoadBalancerTest {
|
|||
.isLessThan(0.002);
|
||||
}
|
||||
|
||||
private boolean isEnabledHappyEyeballs() {
|
||||
return GrpcUtil.getFlag("GRPC_EXPERIMENTAL_XDS_DUALSTACK_ENDPOINTS", true);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void updateWeightTimer() {
|
||||
syncContext.execute(() -> wrr.acceptResolvedAddresses(ResolvedAddresses.newBuilder()
|
||||
.setAddresses(servers).setLoadBalancingPolicyConfig(weightedConfig)
|
||||
.setAttributes(affinity).build()));
|
||||
verify(helper, times(6)).createSubchannel(
|
||||
verify(helper, times(3)).createSubchannel(
|
||||
any(CreateSubchannelArgs.class));
|
||||
assertThat(fakeClock.getPendingTasks().size()).isEqualTo(1);
|
||||
assertThat(getNumFilteredPendingTasks()).isEqualTo(1);
|
||||
|
||||
Iterator<Subchannel> it = subchannels.values().iterator();
|
||||
Subchannel readySubchannel1 = it.next();
|
||||
|
@ -592,17 +607,18 @@ public class WeightedRoundRobinLoadBalancerTest {
|
|||
weightedChild2.new OrcaReportListener(weightedConfig.errorUtilizationPenalty).onLoadReport(
|
||||
InternalCallMetricRecorder.createMetricReport(
|
||||
0.2, 0, 0.1, 1, 0, new HashMap<>(), new HashMap<>(), new HashMap<>()));
|
||||
assertThat(fakeClock.forwardTime(11, TimeUnit.SECONDS)).isEqualTo(1);
|
||||
int expectedTasks = isEnabledHappyEyeballs() ? 2 : 1;
|
||||
assertThat(fakeClock.forwardTime(11, TimeUnit.SECONDS)).isEqualTo(expectedTasks);
|
||||
assertThat(getAddressesFromPick(weightedPicker))
|
||||
.isEqualTo(weightedChild1.getEag());
|
||||
assertThat(fakeClock.getPendingTasks().size()).isEqualTo(1);
|
||||
assertThat(getNumFilteredPendingTasks()).isEqualTo(1);
|
||||
weightedConfig = WeightedRoundRobinLoadBalancerConfig.newBuilder()
|
||||
.setWeightUpdatePeriodNanos(500_000_000L) //.5s
|
||||
.build();
|
||||
syncContext.execute(() -> wrr.acceptResolvedAddresses(ResolvedAddresses.newBuilder()
|
||||
.setAddresses(servers).setLoadBalancingPolicyConfig(weightedConfig)
|
||||
.setAttributes(affinity).build()));
|
||||
assertThat(fakeClock.getPendingTasks().size()).isEqualTo(1);
|
||||
assertThat(getNumFilteredPendingTasks()).isEqualTo(1);
|
||||
weightedChild1.new OrcaReportListener(weightedConfig.errorUtilizationPenalty).onLoadReport(
|
||||
InternalCallMetricRecorder.createMetricReport(
|
||||
0.2, 0, 0.1, 1, 0, new HashMap<>(), new HashMap<>(), new HashMap<>()));
|
||||
|
@ -610,7 +626,8 @@ public class WeightedRoundRobinLoadBalancerTest {
|
|||
InternalCallMetricRecorder.createMetricReport(
|
||||
0.1, 0, 0.1, 1, 0, new HashMap<>(), new HashMap<>(), new HashMap<>()));
|
||||
//timer fires, new weight updated
|
||||
assertThat(fakeClock.forwardTime(500, TimeUnit.MILLISECONDS)).isEqualTo(1);
|
||||
expectedTasks = isEnabledHappyEyeballs() ? 2 : 1;
|
||||
assertThat(fakeClock.forwardTime(500, TimeUnit.MILLISECONDS)).isEqualTo(expectedTasks);
|
||||
assertThat(getAddressesFromPick(weightedPicker))
|
||||
.isEqualTo(weightedChild2.getEag());
|
||||
assertThat(getAddressesFromPick(weightedPicker))
|
||||
|
@ -622,9 +639,9 @@ public class WeightedRoundRobinLoadBalancerTest {
|
|||
syncContext.execute(() -> wrr.acceptResolvedAddresses(ResolvedAddresses.newBuilder()
|
||||
.setAddresses(servers).setLoadBalancingPolicyConfig(weightedConfig)
|
||||
.setAttributes(affinity).build()));
|
||||
verify(helper, times(6)).createSubchannel(
|
||||
verify(helper, times(3)).createSubchannel(
|
||||
any(CreateSubchannelArgs.class));
|
||||
assertThat(fakeClock.getPendingTasks().size()).isEqualTo(1);
|
||||
assertThat(getNumFilteredPendingTasks()).isEqualTo(1);
|
||||
|
||||
Iterator<Subchannel> it = subchannels.values().iterator();
|
||||
Subchannel readySubchannel1 = it.next();
|
||||
|
@ -645,7 +662,8 @@ public class WeightedRoundRobinLoadBalancerTest {
|
|||
weightedChild2.new OrcaReportListener(weightedConfig.errorUtilizationPenalty).onLoadReport(
|
||||
InternalCallMetricRecorder.createMetricReport(
|
||||
0.2, 0, 0.1, 1, 0, new HashMap<>(), new HashMap<>(), new HashMap<>()));
|
||||
assertThat(fakeClock.forwardTime(10, TimeUnit.SECONDS)).isEqualTo(1);
|
||||
int expectedTasks = isEnabledHappyEyeballs() ? 2 : 1;
|
||||
assertThat(fakeClock.forwardTime(10, TimeUnit.SECONDS)).isEqualTo(expectedTasks);
|
||||
Map<EquivalentAddressGroup, Integer> pickCount = new HashMap<>();
|
||||
for (int i = 0; i < 1000; i++) {
|
||||
EquivalentAddressGroup result = getAddressesFromPick(weightedPicker);
|
||||
|
@ -676,9 +694,9 @@ public class WeightedRoundRobinLoadBalancerTest {
|
|||
syncContext.execute(() -> wrr.acceptResolvedAddresses(ResolvedAddresses.newBuilder()
|
||||
.setAddresses(servers).setLoadBalancingPolicyConfig(weightedConfig)
|
||||
.setAttributes(affinity).build()));
|
||||
verify(helper, times(6)).createSubchannel(
|
||||
verify(helper, times(3)).createSubchannel(
|
||||
any(CreateSubchannelArgs.class));
|
||||
assertThat(fakeClock.getPendingTasks().size()).isEqualTo(1);
|
||||
assertThat(getNumFilteredPendingTasks()).isEqualTo(1);
|
||||
|
||||
Iterator<Subchannel> it = subchannels.values().iterator();
|
||||
Subchannel readySubchannel1 = it.next();
|
||||
|
@ -691,7 +709,8 @@ public class WeightedRoundRobinLoadBalancerTest {
|
|||
eq(ConnectivityState.READY), pickerCaptor.capture());
|
||||
WeightedRoundRobinPicker weightedPicker =
|
||||
(WeightedRoundRobinPicker) pickerCaptor.getAllValues().get(1);
|
||||
assertThat(fakeClock.forwardTime(10, TimeUnit.SECONDS)).isEqualTo(1);
|
||||
int expectedTasks = isEnabledHappyEyeballs() ? 2 : 1;
|
||||
assertThat(fakeClock.forwardTime(10, TimeUnit.SECONDS)).isEqualTo(expectedTasks);
|
||||
WeightedChildLbState weightedChild1 = (WeightedChildLbState) getChild(weightedPicker, 0);
|
||||
WeightedChildLbState weightedChild2 = (WeightedChildLbState) getChild(weightedPicker, 1);
|
||||
Map<EquivalentAddressGroup, Integer> qpsByChannel = ImmutableMap.of(weightedChild1.getEag(), 2,
|
||||
|
@ -743,9 +762,9 @@ public class WeightedRoundRobinLoadBalancerTest {
|
|||
syncContext.execute(() -> wrr.acceptResolvedAddresses(ResolvedAddresses.newBuilder()
|
||||
.setAddresses(servers).setLoadBalancingPolicyConfig(weightedConfig)
|
||||
.setAttributes(affinity).build()));
|
||||
verify(helper, times(6)).createSubchannel(
|
||||
verify(helper, times(3)).createSubchannel(
|
||||
any(CreateSubchannelArgs.class)); // 3 from setup plus 3 from the execute
|
||||
assertThat(fakeClock.getPendingTasks().size()).isEqualTo(1);
|
||||
assertThat(getNumFilteredPendingTasks()).isEqualTo(1);
|
||||
|
||||
Iterator<Subchannel> it = subchannels.values().iterator();
|
||||
Subchannel readySubchannel1 = it.next();
|
||||
|
@ -791,9 +810,9 @@ public class WeightedRoundRobinLoadBalancerTest {
|
|||
syncContext.execute(() -> wrr.acceptResolvedAddresses(ResolvedAddresses.newBuilder()
|
||||
.setAddresses(servers).setLoadBalancingPolicyConfig(weightedConfig)
|
||||
.setAttributes(affinity).build()));
|
||||
verify(helper, times(6)).createSubchannel(
|
||||
verify(helper, times(3)).createSubchannel(
|
||||
any(CreateSubchannelArgs.class));
|
||||
assertThat(fakeClock.getPendingTasks().size()).isEqualTo(1);
|
||||
assertThat(getNumFilteredPendingTasks()).isEqualTo(1);
|
||||
|
||||
Iterator<Subchannel> it = subchannels.values().iterator();
|
||||
Subchannel readySubchannel1 = it.next();
|
||||
|
@ -834,7 +853,8 @@ public class WeightedRoundRobinLoadBalancerTest {
|
|||
}
|
||||
}
|
||||
}).start();
|
||||
assertThat(fakeClock.forwardTime(10, TimeUnit.SECONDS)).isEqualTo(1);
|
||||
int expectedTasks = isEnabledHappyEyeballs() ? 2 : 1;
|
||||
assertThat(fakeClock.forwardTime(10, TimeUnit.SECONDS)).isEqualTo(expectedTasks);
|
||||
barrier.await();
|
||||
for (int i = 0; i < 1000; i++) {
|
||||
EquivalentAddressGroup result = getAddresses(weightedPicker.pickSubchannel(mockArgs));
|
||||
|
@ -1101,6 +1121,9 @@ public class WeightedRoundRobinLoadBalancerTest {
|
|||
inOrder.verify(subchannel2).shutdown();
|
||||
}
|
||||
|
||||
private int getNumFilteredPendingTasks() {
|
||||
return AbstractTestHelper.getNumFilteredPendingTasks(fakeClock);
|
||||
}
|
||||
|
||||
private static final class VerifyingScheduler {
|
||||
private final StaticStrideScheduler delegate;
|
||||
|
@ -1148,6 +1171,9 @@ public class WeightedRoundRobinLoadBalancerTest {
|
|||
}
|
||||
|
||||
private class TestHelper extends AbstractTestHelper {
|
||||
public TestHelper() {
|
||||
super(fakeClock, syncContext);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<List<EquivalentAddressGroup>, Subchannel> getSubchannelMap() {
|
||||
|
@ -1163,17 +1189,5 @@ public class WeightedRoundRobinLoadBalancerTest {
|
|||
public Map<Subchannel, SubchannelStateListener> getSubchannelStateListeners() {
|
||||
return subchannelStateListeners;
|
||||
}
|
||||
|
||||
@Override
|
||||
public SynchronizationContext getSynchronizationContext() {
|
||||
return syncContext;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ScheduledExecutorService getScheduledExecutorService() {
|
||||
return fakeClock.getScheduledExecutorService();
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue