xds: wire up re-resolution requests from LB policies for DNS clusters and bypass requests from LB policies for EDS clusters (#7769)

This change wires up the refreshNameResolution() API for triggering DNS re-resolution in ClusterResolverLoadBalancer, which provides a way for downstream LB policies to request a resolution refresh and only re-resolution requests from LB policies for the DNS cluster should trigger the DNS refresh.
This commit is contained in:
Chengyuan Zhang 2021-01-08 01:08:13 -08:00 committed by GitHub
parent 2755afeaa5
commit 18772e2470
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
8 changed files with 298 additions and 104 deletions

View File

@ -38,6 +38,7 @@ import io.grpc.internal.BackoffPolicy;
import io.grpc.internal.ExponentialBackoffPolicy;
import io.grpc.internal.ObjectPool;
import io.grpc.internal.ServiceConfigUtil.PolicySelection;
import io.grpc.util.ForwardingLoadBalancerHelper;
import io.grpc.util.GracefulSwitchLoadBalancer;
import io.grpc.xds.ClusterImplLoadBalancerProvider.ClusterImplConfig;
import io.grpc.xds.ClusterResolverLoadBalancerProvider.ClusterResolverConfig;
@ -49,6 +50,7 @@ import io.grpc.xds.EnvoyProtoData.LocalityLbEndpoints;
import io.grpc.xds.EnvoyServerProtoData.UpstreamTlsContext;
import io.grpc.xds.LrsLoadBalancerProvider.LrsConfig;
import io.grpc.xds.PriorityLoadBalancerProvider.PriorityLbConfig;
import io.grpc.xds.PriorityLoadBalancerProvider.PriorityLbConfig.PriorityChildConfig;
import io.grpc.xds.WeightedTargetLoadBalancerProvider.WeightedPolicySelection;
import io.grpc.xds.WeightedTargetLoadBalancerProvider.WeightedTargetConfig;
import io.grpc.xds.XdsClient.EdsResourceWatcher;
@ -166,7 +168,7 @@ final class ClusterResolverLoadBalancer extends LoadBalancer {
private LoadBalancer childLb;
ClusterResolverLbState(Helper helper) {
this.helper = checkNotNull(helper, "helper");
this.helper = new RefreshableHelper(checkNotNull(helper, "helper"));
logger.log(XdsLogLevel.DEBUG, "New ClusterResolverLbState");
}
@ -214,7 +216,7 @@ final class ClusterResolverLoadBalancer extends LoadBalancer {
private void handleEndpointResourceUpdate() {
List<EquivalentAddressGroup> addresses = new ArrayList<>();
Map<String, PolicySelection> priorityLbPolicies = new HashMap<>();
Map<String, PriorityChildConfig> priorityChildConfigs = new HashMap<>();
List<String> priorities = new ArrayList<>(); // totally ordered priority list
boolean allResolved = true;
for (String cluster : clusters) {
@ -225,7 +227,7 @@ final class ClusterResolverLoadBalancer extends LoadBalancer {
}
if (state.result != null) {
addresses.addAll(state.result.addresses);
priorityLbPolicies.putAll(state.result.priorityLbPolicies);
priorityChildConfigs.putAll(state.result.priorityChildConfigs);
priorities.addAll(state.result.priorities);
}
}
@ -243,7 +245,7 @@ final class ClusterResolverLoadBalancer extends LoadBalancer {
return;
}
PriorityLbConfig childConfig =
new PriorityLbConfig(Collections.unmodifiableMap(priorityLbPolicies),
new PriorityLbConfig(Collections.unmodifiableMap(priorityChildConfigs),
Collections.unmodifiableList(priorities));
if (childLb == null) {
childLb = lbRegistry.getProvider(PRIORITY_POLICY_NAME).newLoadBalancer(helper);
@ -273,6 +275,31 @@ final class ClusterResolverLoadBalancer extends LoadBalancer {
}
}
/**
* Wires re-resolution requests from downstream LB policies with DNS resolver.
*/
private final class RefreshableHelper extends ForwardingLoadBalancerHelper {
private final Helper delegate;
private RefreshableHelper(Helper delegate) {
this.delegate = checkNotNull(delegate, "delegate");
}
@Override
public void refreshNameResolution() {
for (ClusterState state : clusterStates.values()) {
if (state instanceof LogicalDnsClusterState) {
((LogicalDnsClusterState) state).refresh();
}
}
}
@Override
protected Helper delegate() {
return delegate;
}
}
/**
* Resolution state of an underlying cluster.
*/
@ -390,13 +417,13 @@ final class ClusterResolverLoadBalancer extends LoadBalancer {
}
List<String> priorities = new ArrayList<>(prioritizedLocalityWeights.keySet());
Collections.sort(priorities);
Map<String, PolicySelection> priorityLbPolicies =
generateClusterPriorityLbPolicies(name, edsServiceName, lrsServerName,
maxConcurrentRequests, tlsContext, localityPickingPolicy,
endpointPickingPolicy, lbRegistry, prioritizedLocalityWeights, dropOverloads);
Map<String, PriorityChildConfig> priorityChildConfigs = generatePriorityChildConfigs(
name, edsServiceName, lrsServerName, maxConcurrentRequests, tlsContext,
localityPickingPolicy, endpointPickingPolicy, true, lbRegistry,
prioritizedLocalityWeights, dropOverloads);
status = Status.OK;
resolved = true;
result = new ClusterResolutionResult(addresses, priorityLbPolicies, priorities);
result = new ClusterResolutionResult(addresses, priorityChildConfigs, priorities);
handleEndpointResourceUpdate();
}
}
@ -463,12 +490,23 @@ final class ClusterResolverLoadBalancer extends LoadBalancer {
resolver.start(new NameResolverListener());
}
void refresh() {
cancelBackoff();
resolver.refresh();
}
@Override
void shutdown() {
super.shutdown();
resolver.shutdown();
cancelBackoff();
}
private void cancelBackoff() {
if (scheduledRefresh != null) {
scheduledRefresh.cancel();
scheduledRefresh = null;
backoffPolicy = null;
}
}
@ -505,13 +543,13 @@ final class ClusterResolverLoadBalancer extends LoadBalancer {
lbRegistry.getProvider("pick_first");
PolicySelection endpointPickingPolicy =
new PolicySelection(endpointPickingLbProvider, null);
PolicySelection priorityLbPolicy =
generateClusterPriorityLbPolicy(name, edsServiceName, lrsServerName,
maxConcurrentRequests, tlsContext, endpointPickingPolicy, lbRegistry,
LOGICAL_DNS_CLUSTER_LOCALITY, Collections.<DropOverload>emptyList());
PriorityChildConfig priorityChildConfig = generatePriorityChildConfig(
name, edsServiceName, lrsServerName, maxConcurrentRequests, tlsContext,
endpointPickingPolicy, false, lbRegistry, LOGICAL_DNS_CLUSTER_LOCALITY,
Collections.<DropOverload>emptyList());
status = Status.OK;
resolved = true;
result = new ClusterResolutionResult(addresses, priorityName, priorityLbPolicy);
result = new ClusterResolutionResult(addresses, priorityName, priorityChildConfig);
handleEndpointResourceUpdate();
}
}
@ -555,35 +593,35 @@ final class ClusterResolverLoadBalancer extends LoadBalancer {
private static class ClusterResolutionResult {
// Endpoint addresses.
private final List<EquivalentAddressGroup> addresses;
// Load balancing policy (with config) for each priority in the cluster.
private final Map<String, PolicySelection> priorityLbPolicies;
// Config (include load balancing policy/config) for each priority in the cluster.
private final Map<String, PriorityChildConfig> priorityChildConfigs;
// List of priority names ordered in descending priorities.
private final List<String> priorities;
ClusterResolutionResult(List<EquivalentAddressGroup> addresses, String priority,
PolicySelection priorityLbPolicy) {
this(addresses, Collections.singletonMap(priority, priorityLbPolicy),
PriorityChildConfig config) {
this(addresses, Collections.singletonMap(priority, config),
Collections.singletonList(priority));
}
ClusterResolutionResult(List<EquivalentAddressGroup> addresses,
Map<String, PolicySelection> priorityLbPolicies, List<String> priorities) {
Map<String, PriorityChildConfig> configs, List<String> priorities) {
this.addresses = addresses;
this.priorityLbPolicies = priorityLbPolicies;
this.priorityChildConfigs = configs;
this.priorities = priorities;
}
}
/**
* Generates the intra-priority LB policy for a single priority with the single given locality.
* Generates the config to be used in the priority LB policy for a single priority.
*
* <p>priority LB -> cluster_impl LB -> (lrs LB) -> pick_first
*/
private PolicySelection generateClusterPriorityLbPolicy(
private static PriorityChildConfig generatePriorityChildConfig(
String cluster, @Nullable String edsServiceName, @Nullable String lrsServerName,
@Nullable Long maxConcurrentRequests, @Nullable UpstreamTlsContext tlsContext,
PolicySelection endpointPickingPolicy, LoadBalancerRegistry lbRegistry,
Locality locality, List<DropOverload> dropOverloads) {
PolicySelection endpointPickingPolicy, boolean ignoreReresolution,
LoadBalancerRegistry lbRegistry, Locality locality, List<DropOverload> dropOverloads) {
PolicySelection localityLbPolicy =
generateLocalityLbConfig(locality, cluster, edsServiceName, lrsServerName,
endpointPickingPolicy, lbRegistry);
@ -592,23 +630,25 @@ final class ClusterResolverLoadBalancer extends LoadBalancer {
dropOverloads, localityLbPolicy, tlsContext);
LoadBalancerProvider clusterImplLbProvider =
lbRegistry.getProvider(XdsLbPolicies.CLUSTER_IMPL_POLICY_NAME);
return new PolicySelection(clusterImplLbProvider, clusterImplConfig);
PolicySelection clusterImplPolicy =
new PolicySelection(clusterImplLbProvider, clusterImplConfig);
return new PriorityChildConfig(clusterImplPolicy, ignoreReresolution);
}
/**
* Generates intra-priority LB policies (with config) for priorities in the cluster.
* Generates configs to be used in the priority LB policy for priorities in the cluster.
*
* <p>priority LB -> cluster_impl LB (one per priority) -> weighted_target LB
* -> (lrs LB (one per locality)) -> round_robin
*/
private static Map<String, PolicySelection> generateClusterPriorityLbPolicies(
private static Map<String, PriorityChildConfig> generatePriorityChildConfigs(
String cluster, @Nullable String edsServiceName, @Nullable String lrsServerName,
@Nullable Long maxConcurrentRequests, @Nullable UpstreamTlsContext tlsContext,
PolicySelection localityPickingPolicy, PolicySelection endpointPickingPolicy,
LoadBalancerRegistry lbRegistry,
boolean ignoreReresolution, LoadBalancerRegistry lbRegistry,
Map<String, Map<Locality, Integer>> prioritizedLocalityWeights,
List<DropOverload> dropOverloads) {
Map<String, PolicySelection> policies = new HashMap<>();
Map<String, PriorityChildConfig> configs = new HashMap<>();
for (String priority : prioritizedLocalityWeights.keySet()) {
WeightedTargetConfig localityPickingLbConfig =
generateLocalityPickingLbConfig(cluster, edsServiceName, lrsServerName,
@ -622,9 +662,9 @@ final class ClusterResolverLoadBalancer extends LoadBalancer {
lbRegistry.getProvider(XdsLbPolicies.CLUSTER_IMPL_POLICY_NAME);
PolicySelection clusterImplPolicy =
new PolicySelection(clusterImplLbProvider, clusterImplConfig);
policies.put(priority, clusterImplPolicy);
configs.put(priority, new PriorityChildConfig(clusterImplPolicy, ignoreReresolution));
}
return policies;
return configs;
}
private static WeightedTargetConfig generateLocalityPickingLbConfig(

View File

@ -40,6 +40,7 @@ import io.grpc.xds.EnvoyProtoData.Locality;
import io.grpc.xds.EnvoyProtoData.LocalityLbEndpoints;
import io.grpc.xds.LrsLoadBalancerProvider.LrsConfig;
import io.grpc.xds.PriorityLoadBalancerProvider.PriorityLbConfig;
import io.grpc.xds.PriorityLoadBalancerProvider.PriorityLbConfig.PriorityChildConfig;
import io.grpc.xds.WeightedTargetLoadBalancerProvider.WeightedPolicySelection;
import io.grpc.xds.WeightedTargetLoadBalancerProvider.WeightedTargetConfig;
import io.grpc.xds.XdsClient.EdsResourceWatcher;
@ -293,8 +294,8 @@ final class EdsLoadBalancer2 extends LoadBalancer {
private void handleResourceUpdate() {
// Populate configurations used by downstream LB policies from the freshest result.
EdsConfig config = (EdsConfig) resolvedAddresses.getLoadBalancingPolicyConfig();
// Load balancing policy for each priority.
Map<String, PolicySelection> priorityChildPolicies = new HashMap<>();
// Config for each priority.
Map<String, PriorityChildConfig> priorityChildConfigs = new HashMap<>();
List<String> priorities = new ArrayList<>();
for (Integer priority : prioritizedLocalityWeights.keySet()) {
WeightedTargetConfig weightedTargetConfig =
@ -312,12 +313,12 @@ final class EdsLoadBalancer2 extends LoadBalancer {
PolicySelection clusterImplPolicy =
new PolicySelection(clusterImplLbProvider, clusterImplConfig);
String priorityName = priorityName(priority);
priorityChildPolicies.put(priorityName, clusterImplPolicy);
priorityChildConfigs.put(priorityName, new PriorityChildConfig(clusterImplPolicy, true));
priorities.add(priorityName);
}
Collections.sort(priorities);
PriorityLbConfig priorityLbConfig =
new PriorityLbConfig(Collections.unmodifiableMap(priorityChildPolicies),
new PriorityLbConfig(Collections.unmodifiableMap(priorityChildConfigs),
Collections.unmodifiableList(priorities));
lb.handleResolvedAddresses(
resolvedAddresses.toBuilder()

View File

@ -34,17 +34,22 @@ import io.grpc.internal.ServiceConfigUtil.PolicySelection;
import io.grpc.util.ForwardingLoadBalancerHelper;
import io.grpc.util.GracefulSwitchLoadBalancer;
import io.grpc.xds.PriorityLoadBalancerProvider.PriorityLbConfig;
import io.grpc.xds.PriorityLoadBalancerProvider.PriorityLbConfig.PriorityChildConfig;
import io.grpc.xds.XdsLogger.XdsLogLevel;
import io.grpc.xds.XdsSubchannelPickers.ErrorPicker;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
import javax.annotation.Nullable;
/** Load balancer for priority policy. */
/**
* Load balancer for priority policy. A <em>priority</em> represents a logical entity within a
* cluster for load balancing purposes.
*/
final class PriorityLoadBalancer extends LoadBalancer {
private final Helper helper;
private final SynchronizationContext syncContext;
@ -57,8 +62,10 @@ final class PriorityLoadBalancer extends LoadBalancer {
// Following fields are only null initially.
private ResolvedAddresses resolvedAddresses;
// List of priority names in order.
private List<String> priorityNames;
private Map<String, Integer> priorityNameToIndex;
// Config for each priority.
private Map<String, PriorityChildConfig> priorityConfigs;
private ConnectivityState currentConnectivityState;
private SubchannelPicker currentPicker;
@ -78,13 +85,10 @@ final class PriorityLoadBalancer extends LoadBalancer {
PriorityLbConfig config = (PriorityLbConfig) resolvedAddresses.getLoadBalancingPolicyConfig();
checkNotNull(config, "missing priority lb config");
priorityNames = config.priorities;
Map<String, Integer> pToI = new HashMap<>();
for (int i = 0; i < priorityNames.size(); i++) {
pToI.put(priorityNames.get(i), i);
}
priorityNameToIndex = Collections.unmodifiableMap(pToI);
priorityConfigs = config.childConfigs;
Set<String> prioritySet = new HashSet<>(config.priorities);
for (String priority : children.keySet()) {
if (!priorityNameToIndex.containsKey(priority)) {
if (!prioritySet.contains(priority)) {
children.get(priority).deactivate();
}
}
@ -125,7 +129,8 @@ final class PriorityLoadBalancer extends LoadBalancer {
for (int i = 0; i < priorityNames.size(); i++) {
String priority = priorityNames.get(i);
if (!children.containsKey(priority)) {
ChildLbState child = new ChildLbState(priority);
ChildLbState child =
new ChildLbState(priority, priorityConfigs.get(priority).ignoreReresolution);
children.put(priority, child);
child.updateResolvedAddresses();
updateOverallState(CONNECTING, BUFFER_PICKER);
@ -180,9 +185,9 @@ final class PriorityLoadBalancer extends LoadBalancer {
ConnectivityState connectivityState = CONNECTING;
SubchannelPicker picker = BUFFER_PICKER;
ChildLbState(final String priority) {
ChildLbState(final String priority, boolean ignoreReresolution) {
this.priority = priority;
childHelper = new ChildHelper();
childHelper = new ChildHelper(ignoreReresolution);
lb = new GracefulSwitchLoadBalancer(childHelper);
class FailOverTask implements Runnable {
@ -253,7 +258,7 @@ final class PriorityLoadBalancer extends LoadBalancer {
void updateResolvedAddresses() {
PriorityLbConfig config =
(PriorityLbConfig) resolvedAddresses.getLoadBalancingPolicyConfig();
PolicySelection childPolicySelection = config.childConfigs.get(priority);
PolicySelection childPolicySelection = config.childConfigs.get(priority).policySelection;
LoadBalancerProvider lbProvider = childPolicySelection.getProvider();
String newPolicy = lbProvider.getPolicyName();
if (!newPolicy.equals(policy)) {
@ -268,6 +273,19 @@ final class PriorityLoadBalancer extends LoadBalancer {
}
final class ChildHelper extends ForwardingLoadBalancerHelper {
private final boolean ignoreReresolution;
ChildHelper(boolean ignoreReresolution) {
this.ignoreReresolution = ignoreReresolution;
}
@Override
public void refreshNameResolution() {
if (!ignoreReresolution) {
delegate().refreshNameResolution();
}
}
@Override
public void updateBalancingState(final ConnectivityState newState,
final SubchannelPicker newPicker) {

View File

@ -61,10 +61,10 @@ public final class PriorityLoadBalancerProvider extends LoadBalancerProvider {
}
static final class PriorityLbConfig {
final Map<String, PolicySelection> childConfigs;
final Map<String, PriorityChildConfig> childConfigs;
final List<String> priorities;
PriorityLbConfig(Map<String, PolicySelection> childConfigs, List<String> priorities) {
PriorityLbConfig(Map<String, PriorityChildConfig> childConfigs, List<String> priorities) {
this.childConfigs = Collections.unmodifiableMap(checkNotNull(childConfigs, "childConfigs"));
this.priorities = Collections.unmodifiableList(checkNotNull(priorities, "priorities"));
checkArgument(!priorities.isEmpty(), "priority list is empty");
@ -86,5 +86,15 @@ public final class PriorityLoadBalancerProvider extends LoadBalancerProvider {
.add("priorities", priorities)
.toString();
}
static final class PriorityChildConfig {
final PolicySelection policySelection;
final boolean ignoreReresolution;
PriorityChildConfig(PolicySelection policySelection, boolean ignoreReresolution) {
this.policySelection = checkNotNull(policySelection, "policySelection");
this.ignoreReresolution = ignoreReresolution;
}
}
}
}

View File

@ -53,6 +53,7 @@ import io.grpc.Status.Code;
import io.grpc.SynchronizationContext;
import io.grpc.internal.BackoffPolicy;
import io.grpc.internal.FakeClock;
import io.grpc.internal.FakeClock.ScheduledTask;
import io.grpc.internal.GrpcUtil;
import io.grpc.internal.ObjectPool;
import io.grpc.internal.ServiceConfigUtil.PolicySelection;
@ -66,6 +67,7 @@ import io.grpc.xds.EnvoyProtoData.LocalityLbEndpoints;
import io.grpc.xds.EnvoyServerProtoData.UpstreamTlsContext;
import io.grpc.xds.LrsLoadBalancerProvider.LrsConfig;
import io.grpc.xds.PriorityLoadBalancerProvider.PriorityLbConfig;
import io.grpc.xds.PriorityLoadBalancerProvider.PriorityLbConfig.PriorityChildConfig;
import io.grpc.xds.WeightedTargetLoadBalancerProvider.WeightedPolicySelection;
import io.grpc.xds.WeightedTargetLoadBalancerProvider.WeightedTargetConfig;
import io.grpc.xds.internal.sds.CommonTlsContextTestsUtil;
@ -151,7 +153,9 @@ public class ClusterResolverLoadBalancerTest {
@Mock
private BackoffPolicy.Provider backoffPolicyProvider;
@Mock
private BackoffPolicy backoffPolicy;
private BackoffPolicy backoffPolicy1;
@Mock
private BackoffPolicy backoffPolicy2;
@Captor
private ArgumentCaptor<SubchannelPicker> pickerCaptor;
private int xdsClientRefs;
@ -181,9 +185,11 @@ public class ClusterResolverLoadBalancerTest {
when(helper.getSynchronizationContext()).thenReturn(syncContext);
when(helper.getScheduledExecutorService()).thenReturn(fakeClock.getScheduledExecutorService());
when(helper.getAuthority()).thenReturn(AUTHORITY);
when(backoffPolicyProvider.get()).thenReturn(backoffPolicy);
when(backoffPolicy.nextBackoffNanos())
when(backoffPolicyProvider.get()).thenReturn(backoffPolicy1, backoffPolicy2);
when(backoffPolicy1.nextBackoffNanos())
.thenReturn(TimeUnit.SECONDS.toNanos(1L), TimeUnit.SECONDS.toNanos(10L));
when(backoffPolicy2.nextBackoffNanos())
.thenReturn(TimeUnit.SECONDS.toNanos(5L), TimeUnit.SECONDS.toNanos(50L));
loadBalancer = new ClusterResolverLoadBalancer(helper, lbRegistry, backoffPolicyProvider);
}
@ -193,6 +199,7 @@ public class ClusterResolverLoadBalancerTest {
assertThat(resolvers).isEmpty();
assertThat(xdsClient.watchers).isEmpty();
assertThat(xdsClientRefs).isEqualTo(0);
assertThat(fakeClock.getPendingTasks()).isEmpty();
}
@Test
@ -224,10 +231,12 @@ public class ClusterResolverLoadBalancerTest {
assertThat(childBalancer.name).isEqualTo(PRIORITY_POLICY_NAME);
PriorityLbConfig priorityLbConfig = (PriorityLbConfig) childBalancer.config;
assertThat(priorityLbConfig.priorities).containsExactly(priority1, priority2).inOrder();
PolicySelection priorityChildPolicy = priorityLbConfig.childConfigs.get(priority1);
assertThat(priorityChildPolicy.getProvider().getPolicyName())
PriorityChildConfig priorityChildConfig = priorityLbConfig.childConfigs.get(priority1);
assertThat(priorityChildConfig.ignoreReresolution).isTrue();
assertThat(priorityChildConfig.policySelection.getProvider().getPolicyName())
.isEqualTo(CLUSTER_IMPL_POLICY_NAME);
ClusterImplConfig clusterImplConfig = (ClusterImplConfig) priorityChildPolicy.getConfig();
ClusterImplConfig clusterImplConfig =
(ClusterImplConfig) priorityChildConfig.policySelection.getConfig();
assertClusterImplConfig(clusterImplConfig, CLUSTER2, EDS_SERVICE_NAME2, LRS_SERVER_NAME, 200L,
tlsContext, Collections.<DropOverload>emptyList(), WEIGHTED_TARGET_POLICY_NAME);
WeightedTargetConfig weightedTargetConfig =
@ -239,10 +248,11 @@ public class ClusterResolverLoadBalancerTest {
assertLrsConfig((LrsConfig) target.policySelection.getConfig(), CLUSTER2, EDS_SERVICE_NAME2,
LRS_SERVER_NAME, locality1, "round_robin");
priorityChildPolicy = priorityLbConfig.childConfigs.get(priority2);
assertThat(priorityChildPolicy.getProvider().getPolicyName())
priorityChildConfig = priorityLbConfig.childConfigs.get(priority2);
assertThat(priorityChildConfig.ignoreReresolution).isTrue();
assertThat(priorityChildConfig.policySelection.getProvider().getPolicyName())
.isEqualTo(CLUSTER_IMPL_POLICY_NAME);
clusterImplConfig = (ClusterImplConfig) priorityChildPolicy.getConfig();
clusterImplConfig = (ClusterImplConfig) priorityChildConfig.policySelection.getConfig();
assertClusterImplConfig(clusterImplConfig, CLUSTER2, EDS_SERVICE_NAME2, LRS_SERVER_NAME, 200L,
tlsContext, Collections.<DropOverload>emptyList(), WEIGHTED_TARGET_POLICY_NAME);
weightedTargetConfig = (WeightedTargetConfig) clusterImplConfig.childPolicy.getConfig();
@ -269,10 +279,11 @@ public class ClusterResolverLoadBalancerTest {
assertThat(priorityLbConfig.priorities)
.containsExactly(priority3, priority1, priority2).inOrder();
priorityChildPolicy = priorityLbConfig.childConfigs.get(priority3);
assertThat(priorityChildPolicy.getProvider().getPolicyName())
priorityChildConfig = priorityLbConfig.childConfigs.get(priority3);
assertThat(priorityChildConfig.ignoreReresolution).isTrue();
assertThat(priorityChildConfig.policySelection.getProvider().getPolicyName())
.isEqualTo(CLUSTER_IMPL_POLICY_NAME);
clusterImplConfig = (ClusterImplConfig) priorityChildPolicy.getConfig();
clusterImplConfig = (ClusterImplConfig) priorityChildConfig.policySelection.getConfig();
assertClusterImplConfig(clusterImplConfig, CLUSTER1, EDS_SERVICE_NAME1, LRS_SERVER_NAME, 100L,
tlsContext, Collections.<DropOverload>emptyList(), WEIGHTED_TARGET_POLICY_NAME);
weightedTargetConfig = (WeightedTargetConfig) clusterImplConfig.childPolicy.getConfig();
@ -374,8 +385,9 @@ public class ClusterResolverLoadBalancerTest {
FakeLoadBalancer childBalancer = Iterables.getOnlyElement(childBalancers);
PriorityLbConfig priorityLbConfig = (PriorityLbConfig) childBalancer.config;
PolicySelection priorityChildPolicy = priorityLbConfig.childConfigs.get(priority);
ClusterImplConfig clusterImplConfig = (ClusterImplConfig) priorityChildPolicy.getConfig();
PriorityChildConfig priorityChildConfig = priorityLbConfig.childConfigs.get(priority);
ClusterImplConfig clusterImplConfig =
(ClusterImplConfig) priorityChildConfig.policySelection.getConfig();
WeightedTargetConfig weightedTargetConfig =
(WeightedTargetConfig) clusterImplConfig.childPolicy.getConfig();
assertThat(weightedTargetConfig.targets.keySet()).containsExactly(locality2.toString());
@ -439,10 +451,12 @@ public class ClusterResolverLoadBalancerTest {
assertThat(childBalancer.name).isEqualTo(PRIORITY_POLICY_NAME);
PriorityLbConfig priorityLbConfig = (PriorityLbConfig) childBalancer.config;
String priority = Iterables.getOnlyElement(priorityLbConfig.priorities);
PolicySelection priorityChildPolicy = priorityLbConfig.childConfigs.get(priority);
assertThat(priorityChildPolicy.getProvider().getPolicyName())
PriorityChildConfig priorityChildConfig = priorityLbConfig.childConfigs.get(priority);
assertThat(priorityChildConfig.ignoreReresolution).isFalse();
assertThat(priorityChildConfig.policySelection.getProvider().getPolicyName())
.isEqualTo(CLUSTER_IMPL_POLICY_NAME);
ClusterImplConfig clusterImplConfig = (ClusterImplConfig) priorityChildPolicy.getConfig();
ClusterImplConfig clusterImplConfig =
(ClusterImplConfig) priorityChildConfig.policySelection.getConfig();
assertClusterImplConfig(clusterImplConfig, CLUSTER_DNS, null, LRS_SERVER_NAME, 100L, null,
Collections.<DropOverload>emptyList(), LRS_POLICY_NAME);
LrsConfig lrsConfig = (LrsConfig) clusterImplConfig.childPolicy.getConfig();
@ -451,9 +465,23 @@ public class ClusterResolverLoadBalancerTest {
assertAddressesEqual(Arrays.asList(endpoint1, endpoint2), childBalancer.addresses);
}
@Test
public void onlyLogicalDnsCluster_handleRefreshNameResolution() {
deliverConfigWithSingleLogicalDnsCluster();
EquivalentAddressGroup endpoint1 = makeAddress("endpoint-addr-1");
EquivalentAddressGroup endpoint2 = makeAddress("endpoint-addr-2");
FakeNameResolver resolver = Iterables.getOnlyElement(resolvers);
resolver.deliverEndpointAddresses(Arrays.asList(endpoint1, endpoint2));
assertThat(resolver.refreshCount).isEqualTo(0);
FakeLoadBalancer childBalancer = Iterables.getOnlyElement(childBalancers);
childBalancer.helper.refreshNameResolution();
assertThat(resolver.refreshCount).isEqualTo(1);
}
@Test
public void onlyLogicalDnsCluster_resolutionError_backoffAndRefresh() {
InOrder inOrder = Mockito.inOrder(helper, backoffPolicyProvider, backoffPolicy);
InOrder inOrder = Mockito.inOrder(helper, backoffPolicyProvider,
backoffPolicy1, backoffPolicy2);
deliverConfigWithSingleLogicalDnsCluster();
FakeNameResolver resolver = Iterables.getOnlyElement(resolvers);
Status error = Status.UNAVAILABLE.withDescription("cannot reach DNS server");
@ -463,7 +491,7 @@ public class ClusterResolverLoadBalancerTest {
assertPicker(pickerCaptor.getValue(), error, null);
assertThat(resolver.refreshCount).isEqualTo(0);
inOrder.verify(backoffPolicyProvider).get();
inOrder.verify(backoffPolicy).nextBackoffNanos();
inOrder.verify(backoffPolicy1).nextBackoffNanos();
assertThat(fakeClock.getPendingTasks()).hasSize(1);
assertThat(Iterables.getOnlyElement(fakeClock.getPendingTasks()).getDelay(TimeUnit.SECONDS))
.isEqualTo(1L);
@ -474,7 +502,7 @@ public class ClusterResolverLoadBalancerTest {
resolver.deliverError(error);
inOrder.verify(helper).updateBalancingState(
eq(ConnectivityState.TRANSIENT_FAILURE), pickerCaptor.capture());
inOrder.verify(backoffPolicy).nextBackoffNanos();
inOrder.verify(backoffPolicy1).nextBackoffNanos();
assertPicker(pickerCaptor.getValue(), error, null);
assertThat(fakeClock.getPendingTasks()).hasSize(1);
assertThat(Iterables.getOnlyElement(fakeClock.getPendingTasks()).getDelay(TimeUnit.SECONDS))
@ -494,6 +522,42 @@ public class ClusterResolverLoadBalancerTest {
inOrder.verifyNoMoreInteractions();
}
@Test
public void onlyLogicalDnsCluster_refreshNameResolutionRaceWithResolutionError() {
InOrder inOrder = Mockito.inOrder(backoffPolicyProvider, backoffPolicy1, backoffPolicy2);
deliverConfigWithSingleLogicalDnsCluster();
EquivalentAddressGroup endpoint = makeAddress("endpoint-addr");
FakeNameResolver resolver = Iterables.getOnlyElement(resolvers);
resolver.deliverEndpointAddresses(Collections.singletonList(endpoint));
FakeLoadBalancer childBalancer = Iterables.getOnlyElement(childBalancers);
assertAddressesEqual(Collections.singletonList(endpoint), childBalancer.addresses);
assertThat(resolver.refreshCount).isEqualTo(0);
childBalancer.helper.refreshNameResolution();
assertThat(resolver.refreshCount).isEqualTo(1);
resolver.deliverError(Status.UNAVAILABLE.withDescription("I am lost"));
inOrder.verify(backoffPolicyProvider).get();
inOrder.verify(backoffPolicy1).nextBackoffNanos();
assertThat(fakeClock.getPendingTasks()).hasSize(1);
ScheduledTask task = Iterables.getOnlyElement(fakeClock.getPendingTasks());
assertThat(task.getDelay(TimeUnit.SECONDS)).isEqualTo(1L);
fakeClock.forwardTime( 100L, TimeUnit.MILLISECONDS);
childBalancer.helper.refreshNameResolution();
assertThat(resolver.refreshCount).isEqualTo(2);
assertThat(task.isCancelled()).isTrue();
assertThat(fakeClock.getPendingTasks()).isEmpty();
resolver.deliverError(Status.UNAVAILABLE.withDescription("I am still lost"));
inOrder.verify(backoffPolicyProvider).get(); // active refresh resets backoff sequence
inOrder.verify(backoffPolicy2).nextBackoffNanos();
task = Iterables.getOnlyElement(fakeClock.getPendingTasks());
assertThat(task.getDelay(TimeUnit.SECONDS)).isEqualTo(5L);
fakeClock.forwardTime(5L, TimeUnit.SECONDS);
assertThat(resolver.refreshCount).isEqualTo(3);
inOrder.verifyNoMoreInteractions();
}
private void deliverConfigWithSingleLogicalDnsCluster() {
DiscoveryMechanism instance =
DiscoveryMechanism.forLogicalDns(CLUSTER_DNS, LRS_SERVER_NAME, 100L, null);

View File

@ -55,6 +55,7 @@ import io.grpc.xds.EnvoyProtoData.LocalityLbEndpoints;
import io.grpc.xds.EnvoyServerProtoData.UpstreamTlsContext;
import io.grpc.xds.LrsLoadBalancerProvider.LrsConfig;
import io.grpc.xds.PriorityLoadBalancerProvider.PriorityLbConfig;
import io.grpc.xds.PriorityLoadBalancerProvider.PriorityLbConfig.PriorityChildConfig;
import io.grpc.xds.WeightedTargetLoadBalancerProvider.WeightedPolicySelection;
import io.grpc.xds.WeightedTargetLoadBalancerProvider.WeightedTargetConfig;
import io.grpc.xds.internal.sds.CommonTlsContextTestsUtil;
@ -170,9 +171,12 @@ public class EdsLoadBalancer2Test {
assertThat(childBalancer.name).isEqualTo(PRIORITY_POLICY_NAME);
PriorityLbConfig config = (PriorityLbConfig) childBalancer.config;
assertThat(config.priorities).containsExactly("priority1", "priority2");
PolicySelection priorityChild1 = config.childConfigs.get("priority1");
assertThat(priorityChild1.getProvider().getPolicyName()).isEqualTo(CLUSTER_IMPL_POLICY_NAME);
ClusterImplConfig clusterImplConfig1 = (ClusterImplConfig) priorityChild1.getConfig();
PriorityChildConfig priorityChild1 = config.childConfigs.get("priority1");
assertThat(priorityChild1.ignoreReresolution).isTrue();
assertThat(priorityChild1.policySelection.getProvider().getPolicyName())
.isEqualTo(CLUSTER_IMPL_POLICY_NAME);
ClusterImplConfig clusterImplConfig1 =
(ClusterImplConfig) priorityChild1.policySelection.getConfig();
assertClusterImplConfig(clusterImplConfig1, CLUSTER, EDS_SERVICE_NAME, LRS_SERVER_NAME,
null, Collections.<DropOverload>emptyList(), WEIGHTED_TARGET_POLICY_NAME);
PolicySelection weightedTargetPolicy1 = clusterImplConfig1.childPolicy;
@ -193,9 +197,12 @@ public class EdsLoadBalancer2Test {
assertLrsConfig((LrsConfig) target2.policySelection.getConfig(), CLUSTER, EDS_SERVICE_NAME,
LRS_SERVER_NAME, locality2, "round_robin");
PolicySelection priorityChild2 = config.childConfigs.get("priority2");
assertThat(priorityChild2.getProvider().getPolicyName()).isEqualTo(CLUSTER_IMPL_POLICY_NAME);
ClusterImplConfig clusterImplConfig2 = (ClusterImplConfig) priorityChild2.getConfig();
PriorityChildConfig priorityChild2 = config.childConfigs.get("priority2");
assertThat(priorityChild2.ignoreReresolution).isTrue();
assertThat(priorityChild2.policySelection.getProvider().getPolicyName())
.isEqualTo(CLUSTER_IMPL_POLICY_NAME);
ClusterImplConfig clusterImplConfig2 =
(ClusterImplConfig) priorityChild2.policySelection.getConfig();
assertClusterImplConfig(clusterImplConfig2, CLUSTER, EDS_SERVICE_NAME, LRS_SERVER_NAME,
null, Collections.<DropOverload>emptyList(), WEIGHTED_TARGET_POLICY_NAME);
PolicySelection weightedTargetPolicy2 = clusterImplConfig2.childPolicy;
@ -244,9 +251,12 @@ public class EdsLoadBalancer2Test {
assertThat(childBalancer.name).isEqualTo(PRIORITY_POLICY_NAME);
PriorityLbConfig config = (PriorityLbConfig) childBalancer.config;
assertThat(config.priorities).containsExactly("priority1");
PolicySelection priorityChild = config.childConfigs.get("priority1");
assertThat(priorityChild.getProvider().getPolicyName()).isEqualTo(CLUSTER_IMPL_POLICY_NAME);
ClusterImplConfig clusterImplConfig = (ClusterImplConfig) priorityChild.getConfig();
PriorityChildConfig priorityChild = config.childConfigs.get("priority1");
assertThat(priorityChild.ignoreReresolution).isTrue();
assertThat(priorityChild.policySelection.getProvider().getPolicyName())
.isEqualTo(CLUSTER_IMPL_POLICY_NAME);
ClusterImplConfig clusterImplConfig =
(ClusterImplConfig) priorityChild.policySelection.getConfig();
PolicySelection weightedTargetPolicy = clusterImplConfig.childPolicy;
assertThat(weightedTargetPolicy.getProvider().getPolicyName())
.isEqualTo(WEIGHTED_TARGET_POLICY_NAME);
@ -276,8 +286,10 @@ public class EdsLoadBalancer2Test {
config = (PriorityLbConfig) childBalancer.config;
assertThat(config.priorities).containsExactly("priority1");
priorityChild = config.childConfigs.get("priority1");
assertThat(priorityChild.getProvider().getPolicyName()).isEqualTo(CLUSTER_IMPL_POLICY_NAME);
clusterImplConfig = (ClusterImplConfig) priorityChild.getConfig();
assertThat(priorityChild.ignoreReresolution).isTrue();
assertThat(priorityChild.policySelection.getProvider().getPolicyName())
.isEqualTo(CLUSTER_IMPL_POLICY_NAME);
clusterImplConfig = (ClusterImplConfig) priorityChild.policySelection.getConfig();
weightedTargetPolicy = clusterImplConfig.childPolicy;
assertThat(weightedTargetPolicy.getProvider().getPolicyName())
.isEqualTo(WEIGHTED_TARGET_POLICY_NAME);
@ -355,8 +367,9 @@ public class EdsLoadBalancer2Test {
FakeLoadBalancer childBalancer = Iterables.getOnlyElement(childBalancers);
PriorityLbConfig config = (PriorityLbConfig) childBalancer.config;
PolicySelection priorityChildPolicy = config.childConfigs.get("priority1");
ClusterImplConfig clusterImplConfig = (ClusterImplConfig) priorityChildPolicy.getConfig();
PriorityChildConfig priorityChildConfig = config.childConfigs.get("priority1");
ClusterImplConfig clusterImplConfig =
(ClusterImplConfig) priorityChildConfig.policySelection.getConfig();
WeightedTargetConfig weightedTargetConfig =
(WeightedTargetConfig) clusterImplConfig.childPolicy.getConfig();
assertThat(weightedTargetConfig.targets.keySet()).containsExactly(locality2.toString());
@ -484,7 +497,7 @@ public class EdsLoadBalancer2Test {
}
private Long populateMaxConcurrentRequests(PriorityLbConfig config, String priority) {
PolicySelection priorityChildConfig = config.childConfigs.get(priority);
PolicySelection priorityChildConfig = config.childConfigs.get(priority).policySelection;
ClusterImplConfig clusterImplConfig = (ClusterImplConfig) priorityChildConfig.getConfig();
return clusterImplConfig.maxConcurrentRequests;
}
@ -510,7 +523,7 @@ public class EdsLoadBalancer2Test {
}
private UpstreamTlsContext populateTlsContext(PriorityLbConfig config, String priority) {
PolicySelection priorityChildConfig = config.childConfigs.get(priority);
PolicySelection priorityChildConfig = config.childConfigs.get(priority).policySelection;
ClusterImplConfig clusterImplConfig = (ClusterImplConfig) priorityChildConfig.getConfig();
return clusterImplConfig.tlsContext;
}

View File

@ -23,6 +23,7 @@ import com.google.common.collect.ImmutableMap;
import io.grpc.LoadBalancerProvider;
import io.grpc.internal.ServiceConfigUtil.PolicySelection;
import io.grpc.xds.PriorityLoadBalancerProvider.PriorityLbConfig;
import io.grpc.xds.PriorityLoadBalancerProvider.PriorityLbConfig.PriorityChildConfig;
import java.util.List;
import java.util.Map;
import org.junit.Rule;
@ -40,8 +41,11 @@ public class PriorityLoadBalancerProviderTest {
@SuppressWarnings("ExpectedExceptionChecker")
@Test
public void priorityLbConfig_emptyPriorities() {
Map<String, PolicySelection> childConfigs =
ImmutableMap.of("p0", new PolicySelection(mock(LoadBalancerProvider.class), null));
Map<String, PriorityChildConfig> childConfigs =
ImmutableMap.of(
"p0",
new PriorityChildConfig(
new PolicySelection(mock(LoadBalancerProvider.class), null), true));
List<String> priorities = ImmutableList.of();
thrown.expect(IllegalArgumentException.class);
@ -51,8 +55,11 @@ public class PriorityLoadBalancerProviderTest {
@SuppressWarnings("ExpectedExceptionChecker")
@Test
public void priorityLbConfig_missingChildConfig() {
Map<String, PolicySelection> childConfigs =
ImmutableMap.of("p1", new PolicySelection(mock(LoadBalancerProvider.class), null));
Map<String, PriorityChildConfig> childConfigs =
ImmutableMap.of(
"p1",
new PriorityChildConfig(
new PolicySelection(mock(LoadBalancerProvider.class), null), true));
List<String> priorities = ImmutableList.of("p0", "p1");
thrown.expect(IllegalArgumentException.class);

View File

@ -47,6 +47,7 @@ import io.grpc.internal.FakeClock;
import io.grpc.internal.ServiceConfigUtil.PolicySelection;
import io.grpc.internal.TestUtils.StandardLoadBalancerProvider;
import io.grpc.xds.PriorityLoadBalancerProvider.PriorityLbConfig;
import io.grpc.xds.PriorityLoadBalancerProvider.PriorityLbConfig.PriorityChildConfig;
import io.grpc.xds.XdsSubchannelPickers.ErrorPicker;
import java.net.InetSocketAddress;
import java.net.SocketAddress;
@ -137,14 +138,18 @@ public class PriorityLoadBalancerTest {
Attributes attributes =
Attributes.newBuilder().set(Attributes.Key.create("fakeKey"), "fakeValue").build();
Object fooConfig0 = new Object();
PolicySelection fooPolicy0 = new PolicySelection(fooLbProvider, fooConfig0);
PriorityChildConfig priorityChildConfig0 =
new PriorityChildConfig(new PolicySelection(fooLbProvider, fooConfig0), true);
Object barConfig0 = new Object();
PolicySelection barPolicy0 = new PolicySelection(barLbProvider, barConfig0);
PriorityChildConfig priorityChildConfig1 =
new PriorityChildConfig(new PolicySelection(barLbProvider, barConfig0), true);
Object fooConfig1 = new Object();
PolicySelection fooPolicy1 = new PolicySelection(fooLbProvider, fooConfig1);
PriorityChildConfig priorityChildConfig2 =
new PriorityChildConfig(new PolicySelection(fooLbProvider, fooConfig1), true);
PriorityLbConfig priorityLbConfig =
new PriorityLbConfig(
ImmutableMap.of("p0", fooPolicy0, "p1", barPolicy0, "p2", fooPolicy1),
ImmutableMap.of("p0", priorityChildConfig0, "p1", priorityChildConfig1,
"p2", priorityChildConfig2),
ImmutableList.of("p0", "p1", "p2"));
priorityLb.handleResolvedAddresses(
ResolvedAddresses.newBuilder()
@ -190,9 +195,11 @@ public class PriorityLoadBalancerTest {
newEag = AddressFilter.setPathFilter(newEag, ImmutableList.of("p1"));
List<EquivalentAddressGroup> newAddresses = ImmutableList.of(newEag);
Object newBarConfig = new Object();
PolicySelection newBarPolicy = new PolicySelection(barLbProvider, newBarConfig);
PriorityLbConfig newPriorityLbConfig =
new PriorityLbConfig(ImmutableMap.of("p1", newBarPolicy), ImmutableList.of("p1"));
new PriorityLbConfig(
ImmutableMap.of("p1",
new PriorityChildConfig(new PolicySelection(barLbProvider, newBarConfig), true)),
ImmutableList.of("p1"));
priorityLb.handleResolvedAddresses(
ResolvedAddresses.newBuilder()
.setAddresses(newAddresses)
@ -217,12 +224,14 @@ public class PriorityLoadBalancerTest {
@Test
public void handleNameResolutionError() {
Object fooConfig0 = new Object();
PolicySelection fooPolicy0 = new PolicySelection(fooLbProvider, fooConfig0);
PriorityChildConfig priorityChildConfig0 =
new PriorityChildConfig(new PolicySelection(fooLbProvider, fooConfig0), true);
Object fooConfig1 = new Object();
PolicySelection fooPolicy1 = new PolicySelection(fooLbProvider, fooConfig1);
PriorityChildConfig priorityChildConfig1 =
new PriorityChildConfig(new PolicySelection(fooLbProvider, fooConfig1), true);
PriorityLbConfig priorityLbConfig =
new PriorityLbConfig(ImmutableMap.of("p0", fooPolicy0), ImmutableList.of("p0"));
new PriorityLbConfig(ImmutableMap.of("p0", priorityChildConfig0), ImmutableList.of("p0"));
priorityLb.handleResolvedAddresses(
ResolvedAddresses.newBuilder()
.setAddresses(ImmutableList.<EquivalentAddressGroup>of())
@ -234,7 +243,7 @@ public class PriorityLoadBalancerTest {
verify(fooLb0).handleNameResolutionError(status);
priorityLbConfig =
new PriorityLbConfig(ImmutableMap.of("p1", fooPolicy1), ImmutableList.of("p1"));
new PriorityLbConfig(ImmutableMap.of("p1", priorityChildConfig1), ImmutableList.of("p1"));
priorityLb.handleResolvedAddresses(
ResolvedAddresses.newBuilder()
.setAddresses(ImmutableList.<EquivalentAddressGroup>of())
@ -253,13 +262,18 @@ public class PriorityLoadBalancerTest {
@Test
public void typicalPriorityFailOverFlow() {
PolicySelection policy0 = new PolicySelection(fooLbProvider, new Object());
PolicySelection policy1 = new PolicySelection(fooLbProvider, new Object());
PolicySelection policy2 = new PolicySelection(fooLbProvider, new Object());
PolicySelection policy3 = new PolicySelection(fooLbProvider, new Object());
PriorityChildConfig priorityChildConfig0 =
new PriorityChildConfig(new PolicySelection(fooLbProvider, new Object()), true);
PriorityChildConfig priorityChildConfig1 =
new PriorityChildConfig(new PolicySelection(fooLbProvider, new Object()), true);
PriorityChildConfig priorityChildConfig2 =
new PriorityChildConfig(new PolicySelection(fooLbProvider, new Object()), true);
PriorityChildConfig priorityChildConfig3 =
new PriorityChildConfig(new PolicySelection(fooLbProvider, new Object()), true);
PriorityLbConfig priorityLbConfig =
new PriorityLbConfig(
ImmutableMap.of("p0", policy0, "p1", policy1, "p2", policy2, "p3", policy3),
ImmutableMap.of("p0", priorityChildConfig0, "p1", priorityChildConfig1,
"p2", priorityChildConfig2, "p3", priorityChildConfig3),
ImmutableList.of("p0", "p1", "p2", "p3"));
priorityLb.handleResolvedAddresses(
ResolvedAddresses.newBuilder()
@ -379,6 +393,33 @@ public class PriorityLoadBalancerTest {
verify(balancer3).shutdown();
}
@Test
public void bypassReresolutionRequestsIfConfiged() {
PriorityChildConfig priorityChildConfig0 =
new PriorityChildConfig(new PolicySelection(fooLbProvider, new Object()), true);
PriorityChildConfig priorityChildConfig1 =
new PriorityChildConfig(new PolicySelection(fooLbProvider, new Object()), false);
PriorityLbConfig priorityLbConfig =
new PriorityLbConfig(
ImmutableMap.of("p0", priorityChildConfig0, "p1", priorityChildConfig1),
ImmutableList.of("p0", "p1"));
priorityLb.handleResolvedAddresses(
ResolvedAddresses.newBuilder()
.setAddresses(ImmutableList.<EquivalentAddressGroup>of())
.setLoadBalancingPolicyConfig(priorityLbConfig)
.build());
Helper priorityHelper0 = Iterables.getOnlyElement(fooHelpers); // priority p0
priorityHelper0.refreshNameResolution();
verify(helper, never()).refreshNameResolution();
// Simulate fallback to priority p1.
priorityHelper0.updateBalancingState(TRANSIENT_FAILURE, new ErrorPicker(Status.UNAVAILABLE));
assertThat(fooHelpers).hasSize(2);
Helper priorityHelper1 = Iterables.getLast(fooHelpers);
priorityHelper1.refreshNameResolution();
verify(helper).refreshNameResolution();
}
private void assertLatestConnectivityState(ConnectivityState expectedState) {
verify(helper, atLeastOnce())
.updateBalancingState(connectivityStateCaptor.capture(), pickerCaptor.capture());