mirror of https://github.com/grpc/grpc-java.git
core: Don't reuse channels in PickFirstLeafLB test
PickFirstLeafLB uses channel reference equality to see if it has re-created subchannels. The tests reusing channels breaks the expected invariant.
This commit is contained in:
parent
c29763d886
commit
e567b4427a
|
|
@ -123,16 +123,14 @@ public class PickFirstLeafLoadBalancerTest {
|
|||
private ArgumentCaptor<CreateSubchannelArgs> createArgsCaptor;
|
||||
@Captor
|
||||
private ArgumentCaptor<SubchannelStateListener> stateListenerCaptor;
|
||||
private final Helper mockHelper = mock(Helper.class, delegatesTo(new MockHelperImpl()));
|
||||
@Mock
|
||||
private Helper mockHelper;
|
||||
private FakeSubchannel mockSubchannel1;
|
||||
@Mock
|
||||
private FakeSubchannel mockSubchannel1n2;
|
||||
private FakeSubchannel mockSubchannel2;
|
||||
@Mock
|
||||
private FakeSubchannel mockSubchannel2n2;
|
||||
private FakeSubchannel mockSubchannel3;
|
||||
@Mock
|
||||
private FakeSubchannel mockSubchannel3n2;
|
||||
private FakeSubchannel mockSubchannel4;
|
||||
@Mock
|
||||
private FakeSubchannel mockSubchannel5;
|
||||
@Mock // This LoadBalancer doesn't use any of the arg fields, as verified in tearDown().
|
||||
private PickSubchannelArgs mockArgs;
|
||||
|
|
@ -150,23 +148,28 @@ public class PickFirstLeafLoadBalancerTest {
|
|||
SocketAddress addr = new FakeSocketAddress("server" + i);
|
||||
servers.add(new EquivalentAddressGroup(addr));
|
||||
}
|
||||
mockSubchannel1 = mock(FakeSubchannel.class);
|
||||
mockSubchannel2 = mock(FakeSubchannel.class);
|
||||
mockSubchannel3 = mock(FakeSubchannel.class);
|
||||
mockSubchannel4 = mock(FakeSubchannel.class);
|
||||
mockSubchannel5 = mock(FakeSubchannel.class);
|
||||
when(mockSubchannel1.getAttributes()).thenReturn(Attributes.EMPTY);
|
||||
when(mockSubchannel2.getAttributes()).thenReturn(Attributes.EMPTY);
|
||||
when(mockSubchannel3.getAttributes()).thenReturn(Attributes.EMPTY);
|
||||
when(mockSubchannel4.getAttributes()).thenReturn(Attributes.EMPTY);
|
||||
when(mockSubchannel5.getAttributes()).thenReturn(Attributes.EMPTY);
|
||||
|
||||
when(mockSubchannel1.getAllAddresses()).thenReturn(Lists.newArrayList(servers.get(0)));
|
||||
when(mockSubchannel2.getAllAddresses()).thenReturn(Lists.newArrayList(servers.get(1)));
|
||||
when(mockSubchannel3.getAllAddresses()).thenReturn(Lists.newArrayList(servers.get(2)));
|
||||
when(mockSubchannel4.getAllAddresses()).thenReturn(Lists.newArrayList(servers.get(3)));
|
||||
when(mockSubchannel5.getAllAddresses()).thenReturn(Lists.newArrayList(servers.get(4)));
|
||||
mockSubchannel1 = mock(FakeSubchannel.class, delegatesTo(
|
||||
new FakeSubchannel(Arrays.asList(servers.get(0)), Attributes.EMPTY)));
|
||||
mockSubchannel1n2 = mock(FakeSubchannel.class, delegatesTo(
|
||||
new FakeSubchannel(Arrays.asList(servers.get(0)), Attributes.EMPTY)));
|
||||
mockSubchannel2 = mock(FakeSubchannel.class, delegatesTo(
|
||||
new FakeSubchannel(Arrays.asList(servers.get(1)), Attributes.EMPTY)));
|
||||
mockSubchannel2n2 = mock(FakeSubchannel.class, delegatesTo(
|
||||
new FakeSubchannel(Arrays.asList(servers.get(1)), Attributes.EMPTY)));
|
||||
mockSubchannel3 = mock(FakeSubchannel.class, delegatesTo(
|
||||
new FakeSubchannel(Arrays.asList(servers.get(2)), Attributes.EMPTY)));
|
||||
mockSubchannel3n2 = mock(FakeSubchannel.class, delegatesTo(
|
||||
new FakeSubchannel(Arrays.asList(servers.get(2)), Attributes.EMPTY)));
|
||||
mockSubchannel4 = mock(FakeSubchannel.class, delegatesTo(
|
||||
new FakeSubchannel(Arrays.asList(servers.get(3)), Attributes.EMPTY)));
|
||||
mockSubchannel5 = mock(FakeSubchannel.class, delegatesTo(
|
||||
new FakeSubchannel(Arrays.asList(servers.get(4)), Attributes.EMPTY)));
|
||||
|
||||
mockHelper = mock(Helper.class, delegatesTo(new MockHelperImpl(Arrays.asList(
|
||||
mockSubchannel1, mockSubchannel1n2,
|
||||
mockSubchannel2, mockSubchannel2n2,
|
||||
mockSubchannel3, mockSubchannel3n2,
|
||||
mockSubchannel4, mockSubchannel5))));
|
||||
loadBalancer = new PickFirstLeafLoadBalancer(mockHelper);
|
||||
}
|
||||
|
||||
|
|
@ -251,14 +254,14 @@ public class PickFirstLeafLoadBalancerTest {
|
|||
PickResult pick2 = pickerCaptor.getValue().pickSubchannel(mockArgs);
|
||||
assertEquals(pick1, pick2);
|
||||
verifyNoMoreInteractions(mockHelper);
|
||||
assertThat(pick1.toString()).contains("subchannel=null");
|
||||
assertThat(pick1.getSubchannel()).isNull();
|
||||
|
||||
stateListener2.onSubchannelState(ConnectivityStateInfo.forNonError(READY));
|
||||
verify(mockHelper).updateBalancingState(eq(READY), pickerCaptor.capture());
|
||||
PickResult pick3 = pickerCaptor.getValue().pickSubchannel(mockArgs);
|
||||
PickResult pick4 = pickerCaptor.getValue().pickSubchannel(mockArgs);
|
||||
assertEquals(pick3, pick4);
|
||||
assertThat(pick3.toString()).contains("subchannel=Mock");
|
||||
assertThat(pick3.getSubchannel()).isEqualTo(mockSubchannel2);
|
||||
}
|
||||
|
||||
@Test
|
||||
|
|
@ -569,7 +572,7 @@ public class PickFirstLeafLoadBalancerTest {
|
|||
InOrder inOrder = inOrder(mockHelper);
|
||||
SocketAddress socketAddress = servers.get(0).getAddresses().get(0);
|
||||
EquivalentAddressGroup badEag = new EquivalentAddressGroup(
|
||||
Lists.newArrayList(socketAddress, socketAddress), affinity);
|
||||
Lists.newArrayList(socketAddress, socketAddress));
|
||||
List<EquivalentAddressGroup> newServers = Lists.newArrayList(badEag);
|
||||
|
||||
loadBalancer.acceptResolvedAddresses(
|
||||
|
|
@ -727,7 +730,7 @@ public class PickFirstLeafLoadBalancerTest {
|
|||
@Test
|
||||
public void nameResolutionTemporaryError() {
|
||||
List<EquivalentAddressGroup> newServers = Lists.newArrayList(servers.get(0));
|
||||
InOrder inOrder = inOrder(mockHelper, mockSubchannel1);
|
||||
InOrder inOrder = inOrder(mockHelper, mockSubchannel1, mockSubchannel1n2);
|
||||
loadBalancer.acceptResolvedAddresses(
|
||||
ResolvedAddresses.newBuilder().setAddresses(newServers).setAttributes(affinity).build());
|
||||
inOrder.verify(mockSubchannel1).start(stateListenerCaptor.capture());
|
||||
|
|
@ -744,14 +747,15 @@ public class PickFirstLeafLoadBalancerTest {
|
|||
loadBalancer.acceptResolvedAddresses(
|
||||
ResolvedAddresses.newBuilder().setAddresses(servers).setAttributes(affinity).build());
|
||||
inOrder.verify(mockHelper).updateBalancingState(eq(CONNECTING), pickerCaptor.capture());
|
||||
inOrder.verify(mockSubchannel1).start(stateListenerCaptor.capture());
|
||||
inOrder.verify(mockSubchannel1n2).start(stateListenerCaptor.capture());
|
||||
SubchannelStateListener stateListener2 = stateListenerCaptor.getValue();
|
||||
|
||||
assertNull(pickerCaptor.getValue().pickSubchannel(mockArgs).getSubchannel());
|
||||
|
||||
stateListener2.onSubchannelState(ConnectivityStateInfo.forNonError(READY));
|
||||
inOrder.verify(mockHelper).updateBalancingState(eq(READY), pickerCaptor.capture());
|
||||
assertEquals(mockSubchannel1, pickerCaptor.getValue().pickSubchannel(mockArgs).getSubchannel());
|
||||
assertEquals(mockSubchannel1n2,
|
||||
pickerCaptor.getValue().pickSubchannel(mockArgs).getSubchannel());
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -1027,7 +1031,7 @@ public class PickFirstLeafLoadBalancerTest {
|
|||
@Test
|
||||
public void updateAddresses_disjoint_ready_twice() {
|
||||
InOrder inOrder = inOrder(mockHelper, mockSubchannel1, mockSubchannel2,
|
||||
mockSubchannel3, mockSubchannel4);
|
||||
mockSubchannel3, mockSubchannel4, mockSubchannel1n2, mockSubchannel2n2);
|
||||
// Creating first set of endpoints/addresses
|
||||
List<EquivalentAddressGroup> oldServers = Lists.newArrayList(servers.get(0), servers.get(1));
|
||||
SubchannelStateListener stateListener2 = null;
|
||||
|
|
@ -1126,7 +1130,7 @@ public class PickFirstLeafLoadBalancerTest {
|
|||
ResolvedAddresses.newBuilder().setAddresses(newestServers).setAttributes(affinity).build());
|
||||
inOrder.verify(mockSubchannel3).shutdown();
|
||||
inOrder.verify(mockHelper).updateBalancingState(eq(CONNECTING), pickerCaptor.capture());
|
||||
inOrder.verify(mockSubchannel1).start(stateListenerCaptor.capture());
|
||||
inOrder.verify(mockSubchannel1n2).start(stateListenerCaptor.capture());
|
||||
stateListener = stateListenerCaptor.getValue();
|
||||
assertEquals(CONNECTING, loadBalancer.getConcludedConnectivityState());
|
||||
picker = pickerCaptor.getValue();
|
||||
|
|
@ -1135,7 +1139,7 @@ public class PickFirstLeafLoadBalancerTest {
|
|||
assertEquals(picker.pickSubchannel(mockArgs), picker.pickSubchannel(mockArgs));
|
||||
|
||||
// But the picker calls requestConnection() only once
|
||||
inOrder.verify(mockSubchannel1).requestConnection();
|
||||
inOrder.verify(mockSubchannel1n2).requestConnection();
|
||||
assertEquals(PickResult.withNoResult(), pickerCaptor.getValue().pickSubchannel(mockArgs));
|
||||
assertEquals(CONNECTING, loadBalancer.getConcludedConnectivityState());
|
||||
|
||||
|
|
@ -1150,23 +1154,24 @@ public class PickFirstLeafLoadBalancerTest {
|
|||
stateListener.onSubchannelState(ConnectivityStateInfo.forTransientFailure(CONNECTION_ERROR));
|
||||
|
||||
// Starting connection attempt to address 2
|
||||
if (!enableHappyEyeballs) {
|
||||
inOrder.verify(mockSubchannel2).start(stateListenerCaptor.capture());
|
||||
stateListener2 = stateListenerCaptor.getValue();
|
||||
}
|
||||
inOrder.verify(mockSubchannel2).requestConnection();
|
||||
FakeSubchannel mockSubchannel2Attempt =
|
||||
enableHappyEyeballs ? mockSubchannel2n2 : mockSubchannel2;
|
||||
inOrder.verify(mockSubchannel2Attempt).start(stateListenerCaptor.capture());
|
||||
stateListener2 = stateListenerCaptor.getValue();
|
||||
inOrder.verify(mockSubchannel2Attempt).requestConnection();
|
||||
|
||||
// Connection attempt to address 2 is successful
|
||||
stateListener2.onSubchannelState(ConnectivityStateInfo.forNonError(READY));
|
||||
assertEquals(READY, loadBalancer.getConcludedConnectivityState());
|
||||
inOrder.verify(mockSubchannel1).shutdown();
|
||||
inOrder.verify(mockSubchannel1n2).shutdown();
|
||||
|
||||
// Successful connection shuts down other subchannel
|
||||
inOrder.verify(mockHelper).updateBalancingState(eq(READY), pickerCaptor.capture());
|
||||
picker = pickerCaptor.getValue();
|
||||
|
||||
// Verify that picker still returns correct subchannel
|
||||
assertEquals(PickResult.withSubchannel(mockSubchannel2), picker.pickSubchannel(mockArgs));
|
||||
assertEquals(
|
||||
PickResult.withSubchannel(mockSubchannel2Attempt), picker.pickSubchannel(mockArgs));
|
||||
}
|
||||
|
||||
@Test
|
||||
|
|
@ -2048,7 +2053,7 @@ public class PickFirstLeafLoadBalancerTest {
|
|||
|
||||
// Starting first connection attempt
|
||||
InOrder inOrder = inOrder(mockHelper, mockSubchannel1, mockSubchannel2,
|
||||
mockSubchannel3, mockSubchannel4); // captor: captures
|
||||
mockSubchannel3, mockSubchannel4, mockSubchannel1n2); // captor: captures
|
||||
|
||||
// Creating first set of endpoints/addresses
|
||||
List<EquivalentAddressGroup> addrs =
|
||||
|
|
@ -2084,9 +2089,9 @@ public class PickFirstLeafLoadBalancerTest {
|
|||
|
||||
// Calling pickSubchannel() requests a connection.
|
||||
assertEquals(picker.pickSubchannel(mockArgs), picker.pickSubchannel(mockArgs));
|
||||
inOrder.verify(mockSubchannel1).start(stateListenerCaptor.capture());
|
||||
inOrder.verify(mockSubchannel1n2).start(stateListenerCaptor.capture());
|
||||
SubchannelStateListener stateListener3 = stateListenerCaptor.getValue();
|
||||
inOrder.verify(mockSubchannel1).requestConnection();
|
||||
inOrder.verify(mockSubchannel1n2).requestConnection();
|
||||
when(mockSubchannel1.getAllAddresses()).thenReturn(Lists.newArrayList(servers.get(0)));
|
||||
|
||||
// gives the same result when called twice
|
||||
|
|
@ -2101,7 +2106,7 @@ public class PickFirstLeafLoadBalancerTest {
|
|||
// second subchannel connection attempt succeeds
|
||||
inOrder.verify(mockSubchannel2).requestConnection();
|
||||
stateListener2.onSubchannelState(ConnectivityStateInfo.forNonError(READY));
|
||||
inOrder.verify(mockSubchannel1).shutdown();
|
||||
inOrder.verify(mockSubchannel1n2).shutdown();
|
||||
inOrder.verify(mockHelper).updateBalancingState(eq(READY), pickerCaptor.capture());
|
||||
assertEquals(READY, loadBalancer.getConcludedConnectivityState());
|
||||
|
||||
|
|
@ -2146,7 +2151,7 @@ public class PickFirstLeafLoadBalancerTest {
|
|||
public void ready_then_transient_failure_again() {
|
||||
// Starting first connection attempt
|
||||
InOrder inOrder = inOrder(mockHelper, mockSubchannel1, mockSubchannel2,
|
||||
mockSubchannel3, mockSubchannel4); // captor: captures
|
||||
mockSubchannel3, mockSubchannel4, mockSubchannel1n2); // captor: captures
|
||||
|
||||
// Creating first set of endpoints/addresses
|
||||
List<EquivalentAddressGroup> addrs =
|
||||
|
|
@ -2183,9 +2188,9 @@ public class PickFirstLeafLoadBalancerTest {
|
|||
|
||||
// Calling pickSubchannel() requests a connection, gives the same result when called twice.
|
||||
assertEquals(picker.pickSubchannel(mockArgs), picker.pickSubchannel(mockArgs));
|
||||
inOrder.verify(mockSubchannel1).start(stateListenerCaptor.capture());
|
||||
inOrder.verify(mockSubchannel1n2).start(stateListenerCaptor.capture());
|
||||
SubchannelStateListener stateListener3 = stateListenerCaptor.getValue();
|
||||
inOrder.verify(mockSubchannel1).requestConnection();
|
||||
inOrder.verify(mockSubchannel1n2).requestConnection();
|
||||
when(mockSubchannel3.getAllAddresses()).thenReturn(Lists.newArrayList(servers.get(0)));
|
||||
stateListener3.onSubchannelState(ConnectivityStateInfo.forNonError(CONNECTING));
|
||||
inOrder.verify(mockHelper).updateBalancingState(eq(CONNECTING), pickerCaptor.capture());
|
||||
|
|
@ -2201,7 +2206,7 @@ public class PickFirstLeafLoadBalancerTest {
|
|||
assertEquals(READY, loadBalancer.getConcludedConnectivityState());
|
||||
|
||||
// verify that picker returns correct subchannel
|
||||
inOrder.verify(mockSubchannel1).shutdown();
|
||||
inOrder.verify(mockSubchannel1n2).shutdown();
|
||||
inOrder.verify(mockHelper).updateBalancingState(eq(READY), pickerCaptor.capture());
|
||||
picker = pickerCaptor.getValue();
|
||||
assertEquals(PickResult.withSubchannel(mockSubchannel2), picker.pickSubchannel(mockArgs));
|
||||
|
|
@ -2309,7 +2314,8 @@ public class PickFirstLeafLoadBalancerTest {
|
|||
public void happy_eyeballs_pick_pushes_index_over_end() {
|
||||
Assume.assumeTrue(enableHappyEyeballs); // This test is only for happy eyeballs
|
||||
|
||||
InOrder inOrder = inOrder(mockHelper, mockSubchannel1, mockSubchannel2, mockSubchannel3);
|
||||
InOrder inOrder = inOrder(mockHelper, mockSubchannel1, mockSubchannel2, mockSubchannel3,
|
||||
mockSubchannel2n2, mockSubchannel3n2);
|
||||
Status error = Status.UNAUTHENTICATED.withDescription("simulated failure");
|
||||
|
||||
List<EquivalentAddressGroup> addrs =
|
||||
|
|
@ -2359,9 +2365,9 @@ public class PickFirstLeafLoadBalancerTest {
|
|||
|
||||
// Try pushing after end with just picks
|
||||
listeners[0].onSubchannelState(ConnectivityStateInfo.forNonError(READY));
|
||||
for (SubchannelStateListener listener : listeners) {
|
||||
listener.onSubchannelState(ConnectivityStateInfo.forNonError(IDLE));
|
||||
}
|
||||
verify(mockSubchannel2).shutdown();
|
||||
verify(mockSubchannel3).shutdown();
|
||||
listeners[0].onSubchannelState(ConnectivityStateInfo.forNonError(IDLE));
|
||||
loadBalancer.acceptResolvedAddresses(
|
||||
ResolvedAddresses.newBuilder().setAddresses(addrs).setAttributes(affinity).build());
|
||||
inOrder.verify(mockHelper).updateBalancingState(eq(IDLE), pickerCaptor.capture());
|
||||
|
|
@ -2372,11 +2378,14 @@ public class PickFirstLeafLoadBalancerTest {
|
|||
}
|
||||
assertEquals(IDLE, loadBalancer.getConcludedConnectivityState());
|
||||
|
||||
for (SubchannelStateListener listener : listeners) {
|
||||
listener.onSubchannelState(ConnectivityStateInfo.forTransientFailure(error));
|
||||
}
|
||||
listeners[0].onSubchannelState(ConnectivityStateInfo.forTransientFailure(error));
|
||||
inOrder.verify(mockSubchannel2n2).start(stateListenerCaptor.capture());
|
||||
stateListenerCaptor.getValue().onSubchannelState(
|
||||
ConnectivityStateInfo.forTransientFailure(error));
|
||||
inOrder.verify(mockSubchannel3n2).start(stateListenerCaptor.capture());
|
||||
stateListenerCaptor.getValue().onSubchannelState(
|
||||
ConnectivityStateInfo.forTransientFailure(error));
|
||||
assertEquals(TRANSIENT_FAILURE, loadBalancer.getConcludedConnectivityState());
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
|
|
@ -2571,9 +2580,22 @@ public class PickFirstLeafLoadBalancerTest {
|
|||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "FakeSocketAddress-" + name;
|
||||
return "FakeSocketAddress(" + name + ")";
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (!(o instanceof FakeSocketAddress)) {
|
||||
return false;
|
||||
}
|
||||
FakeSocketAddress that = (FakeSocketAddress) o;
|
||||
return this.name.equals(that.name);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return name.hashCode();
|
||||
}
|
||||
}
|
||||
|
||||
private void forwardTimeByConnectionDelay() {
|
||||
|
|
@ -2631,15 +2653,26 @@ public class PickFirstLeafLoadBalancerTest {
|
|||
|
||||
@Override
|
||||
public void shutdown() {
|
||||
listener.onSubchannelState(ConnectivityStateInfo.forNonError(SHUTDOWN));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void requestConnection() {
|
||||
listener.onSubchannelState(ConnectivityStateInfo.forNonError(CONNECTING));
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "FakeSubchannel@" + hashCode() + "(" + eags + ")";
|
||||
}
|
||||
}
|
||||
|
||||
private class MockHelperImpl extends LoadBalancer.Helper {
|
||||
private final List<Subchannel> subchannels;
|
||||
|
||||
public MockHelperImpl(List<? extends Subchannel> subchannels) {
|
||||
this.subchannels = new ArrayList<Subchannel>(subchannels);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ManagedChannel createOobChannel(EquivalentAddressGroup eag, String authority) {
|
||||
return null;
|
||||
|
|
@ -2672,16 +2705,17 @@ public class PickFirstLeafLoadBalancerTest {
|
|||
|
||||
@Override
|
||||
public Subchannel createSubchannel(CreateSubchannelArgs args) {
|
||||
SocketAddress addr = args.getAddresses().get(0).getAddresses().get(0);
|
||||
List<FakeSubchannel> fakeSubchannels =
|
||||
Arrays.asList(mockSubchannel1, mockSubchannel2, mockSubchannel3, mockSubchannel4,
|
||||
mockSubchannel5);
|
||||
for (int i = 1; i <= 5; i++) {
|
||||
if (addr.toString().equals(new FakeSocketAddress("server" + i).toString())) {
|
||||
return fakeSubchannels.get(i - 1);
|
||||
for (int i = 0; i < subchannels.size(); i++) {
|
||||
Subchannel subchannel = subchannels.get(i);
|
||||
List<EquivalentAddressGroup> addrs = subchannel.getAllAddresses();
|
||||
verify(subchannel, atLeast(1)).getAllAddresses(); // ignore the interaction
|
||||
if (!args.getAddresses().equals(addrs)) {
|
||||
continue;
|
||||
}
|
||||
subchannels.remove(i);
|
||||
return subchannel;
|
||||
}
|
||||
throw new IllegalArgumentException("Unexpected address: " + addr);
|
||||
throw new IllegalArgumentException("Unexpected addresses: " + args.getAddresses());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue