| /* |
| * Copyright 2018 The gRPC Authors |
| * |
| * Licensed under the Apache License, Version 2.0 (the "License"); |
| * you may not use this file except in compliance with the License. |
| * You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| |
| package io.grpc.internal; |
| |
| import static com.google.common.truth.Truth.assertThat; |
| import static io.grpc.LoadBalancer.ATTR_LOAD_BALANCING_CONFIG; |
| import static org.junit.Assert.assertTrue; |
| import static org.junit.Assert.fail; |
| import static org.mockito.AdditionalAnswers.delegatesTo; |
| import static org.mockito.Matchers.any; |
| import static org.mockito.Matchers.eq; |
| import static org.mockito.Matchers.same; |
| import static org.mockito.Matchers.startsWith; |
| import static org.mockito.Mockito.RETURNS_DEEP_STUBS; |
| import static org.mockito.Mockito.mock; |
| import static org.mockito.Mockito.times; |
| import static org.mockito.Mockito.verify; |
| import static org.mockito.Mockito.verifyNoMoreInteractions; |
| import static org.mockito.Mockito.verifyZeroInteractions; |
| |
| import io.grpc.Attributes; |
| import io.grpc.ChannelLogger; |
| import io.grpc.ChannelLogger.ChannelLogLevel; |
| import io.grpc.ConnectivityState; |
| import io.grpc.ConnectivityStateInfo; |
| import io.grpc.EquivalentAddressGroup; |
| import io.grpc.LoadBalancer; |
| import io.grpc.LoadBalancer.Helper; |
| import io.grpc.LoadBalancer.Subchannel; |
| import io.grpc.LoadBalancer.SubchannelPicker; |
| import io.grpc.LoadBalancerProvider; |
| import io.grpc.LoadBalancerRegistry; |
| import io.grpc.ManagedChannel; |
| import io.grpc.Status; |
| import io.grpc.SynchronizationContext; |
| import io.grpc.grpclb.GrpclbLoadBalancerProvider; |
| import io.grpc.internal.AutoConfiguredLoadBalancerFactory.AutoConfiguredLoadBalancer; |
| import io.grpc.internal.AutoConfiguredLoadBalancerFactory.PolicyException; |
| import io.grpc.internal.AutoConfiguredLoadBalancerFactory.PolicySelection; |
| import io.grpc.util.ForwardingLoadBalancerHelper; |
| import java.net.SocketAddress; |
| import java.util.Arrays; |
| import java.util.Collections; |
| import java.util.HashMap; |
| import java.util.LinkedHashSet; |
| 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 org.junit.After; |
| import org.junit.Before; |
| import org.junit.Test; |
| import org.junit.runner.RunWith; |
| import org.junit.runners.JUnit4; |
| import org.mockito.ArgumentCaptor; |
| |
| /** |
| * Unit tests for {@link AutoConfiguredLoadBalancerFactory}. |
| */ |
| @RunWith(JUnit4.class) |
| public class AutoConfiguredLoadBalancerFactoryTest { |
| private final AutoConfiguredLoadBalancerFactory lbf = new AutoConfiguredLoadBalancerFactory(); |
| |
| private final ChannelLogger channelLogger = mock(ChannelLogger.class); |
| private final LoadBalancer testLbBalancer = mock(LoadBalancer.class); |
| private final LoadBalancerProvider testLbBalancerProvider = |
| mock(LoadBalancerProvider.class, delegatesTo(new TestLbLoadBalancerProvider())); |
| |
| @Before |
| public void setUp() { |
| LoadBalancerRegistry.getDefaultRegistry().register(testLbBalancerProvider); |
| } |
| |
| @After |
| public void tearDown() { |
| LoadBalancerRegistry.getDefaultRegistry().deregister(testLbBalancerProvider); |
| } |
| |
| @Test |
| public void newLoadBalancer_isAuto() { |
| LoadBalancer lb = lbf.newLoadBalancer(new TestHelper()); |
| |
| assertThat(lb).isInstanceOf(AutoConfiguredLoadBalancer.class); |
| } |
| |
| @Test |
| public void defaultIsPickFirst() { |
| AutoConfiguredLoadBalancer lb = |
| (AutoConfiguredLoadBalancer) lbf.newLoadBalancer(new TestHelper()); |
| |
| assertThat(lb.getDelegateProvider()).isInstanceOf(PickFirstLoadBalancerProvider.class); |
| assertThat(lb.getDelegate().getClass().getName()).contains("PickFirst"); |
| } |
| |
| @Test |
| public void forwardsCalls() { |
| AutoConfiguredLoadBalancer lb = |
| (AutoConfiguredLoadBalancer) lbf.newLoadBalancer(new TestHelper()); |
| |
| final AtomicInteger calls = new AtomicInteger(); |
| TestLoadBalancer testlb = new TestLoadBalancer() { |
| |
| @Override |
| public void handleNameResolutionError(Status error) { |
| calls.getAndSet(1); |
| } |
| |
| @Override |
| public void handleSubchannelState(Subchannel subchannel, ConnectivityStateInfo stateInfo) { |
| calls.getAndSet(2); |
| } |
| |
| @Override |
| public void shutdown() { |
| calls.getAndSet(3); |
| } |
| }; |
| |
| lb.setDelegate(testlb); |
| |
| lb.handleNameResolutionError(Status.RESOURCE_EXHAUSTED); |
| assertThat(calls.getAndSet(0)).isEqualTo(1); |
| |
| lb.handleSubchannelState(null, null); |
| assertThat(calls.getAndSet(0)).isEqualTo(2); |
| |
| lb.shutdown(); |
| assertThat(calls.getAndSet(0)).isEqualTo(3); |
| } |
| |
| @Test |
| public void handleResolvedAddressGroups_keepOldBalancer() { |
| final List<EquivalentAddressGroup> servers = |
| Collections.singletonList(new EquivalentAddressGroup(new SocketAddress(){})); |
| Helper helper = new TestHelper() { |
| @Override |
| public Subchannel createSubchannel(List<EquivalentAddressGroup> addrs, Attributes attrs) { |
| assertThat(addrs).isEqualTo(servers); |
| return new TestSubchannel(addrs, attrs); |
| } |
| |
| @Override |
| public void updateBalancingState(ConnectivityState newState, SubchannelPicker newPicker) { |
| // noop |
| } |
| }; |
| AutoConfiguredLoadBalancer lb = |
| (AutoConfiguredLoadBalancer) lbf.newLoadBalancer(helper); |
| LoadBalancer oldDelegate = lb.getDelegate(); |
| |
| lb.handleResolvedAddressGroups(servers, Attributes.EMPTY); |
| |
| assertThat(lb.getDelegate()).isSameAs(oldDelegate); |
| } |
| |
| @Test |
| public void handleResolvedAddressGroups_shutsDownOldBalancer() { |
| Map<String, Object> serviceConfig = new HashMap<String, Object>(); |
| serviceConfig.put("loadBalancingPolicy", "round_robin"); |
| Attributes serviceConfigAttrs = |
| Attributes.newBuilder() |
| .set(GrpcAttributes.NAME_RESOLVER_SERVICE_CONFIG, serviceConfig) |
| .build(); |
| final List<EquivalentAddressGroup> servers = |
| Collections.singletonList(new EquivalentAddressGroup(new SocketAddress(){})); |
| Helper helper = new TestHelper() { |
| @Override |
| public Subchannel createSubchannel(List<EquivalentAddressGroup> addrs, Attributes attrs) { |
| assertThat(addrs).isEqualTo(servers); |
| return new TestSubchannel(addrs, attrs); |
| } |
| |
| @Override |
| public void updateBalancingState(ConnectivityState newState, SubchannelPicker newPicker) { |
| // noop |
| } |
| }; |
| AutoConfiguredLoadBalancer lb = |
| (AutoConfiguredLoadBalancer) lbf.newLoadBalancer(helper); |
| final AtomicBoolean shutdown = new AtomicBoolean(); |
| TestLoadBalancer testlb = new TestLoadBalancer() { |
| |
| @Override |
| public void handleNameResolutionError(Status error) { |
| // noop |
| } |
| |
| @Override |
| public void handleSubchannelState(Subchannel subchannel, ConnectivityStateInfo stateInfo) { |
| // noop |
| } |
| |
| @Override |
| public void shutdown() { |
| shutdown.set(true); |
| } |
| }; |
| lb.setDelegate(testlb); |
| |
| lb.handleResolvedAddressGroups(servers, serviceConfigAttrs); |
| |
| assertThat(lb.getDelegateProvider().getClass().getName()).isEqualTo( |
| "io.grpc.util.SecretRoundRobinLoadBalancerProvider$Provider"); |
| assertTrue(shutdown.get()); |
| } |
| |
| @Test |
| public void handleResolvedAddressGroups_propagateLbConfigToDelegate() throws Exception { |
| Map<String, Object> serviceConfig = |
| parseConfig("{\"loadBalancingConfig\": [ {\"test_lb\": { \"setting1\": \"high\" } } ] }"); |
| Attributes serviceConfigAttrs = |
| Attributes.newBuilder() |
| .set(GrpcAttributes.NAME_RESOLVER_SERVICE_CONFIG, serviceConfig) |
| .build(); |
| final List<EquivalentAddressGroup> servers = |
| Collections.singletonList(new EquivalentAddressGroup(new SocketAddress(){})); |
| Helper helper = new TestHelper() { |
| @Override |
| public void updateBalancingState(ConnectivityState newState, SubchannelPicker newPicker) { |
| // noop |
| } |
| }; |
| AutoConfiguredLoadBalancer lb = |
| (AutoConfiguredLoadBalancer) lbf.newLoadBalancer(helper); |
| |
| lb.handleResolvedAddressGroups(servers, serviceConfigAttrs); |
| |
| verify(testLbBalancerProvider).newLoadBalancer(same(helper)); |
| assertThat(lb.getDelegate()).isSameAs(testLbBalancer); |
| ArgumentCaptor<Attributes> attrsCaptor = ArgumentCaptor.forClass(null); |
| verify(testLbBalancer).handleResolvedAddressGroups(eq(servers), attrsCaptor.capture()); |
| assertThat(attrsCaptor.getValue().get(ATTR_LOAD_BALANCING_CONFIG)) |
| .isEqualTo(Collections.singletonMap("setting1", "high")); |
| verifyNoMoreInteractions(testLbBalancer); |
| |
| serviceConfig = |
| parseConfig("{\"loadBalancingConfig\": [ {\"test_lb\": { \"setting1\": \"low\" } } ] }"); |
| serviceConfigAttrs = |
| Attributes.newBuilder() |
| .set(GrpcAttributes.NAME_RESOLVER_SERVICE_CONFIG, serviceConfig) |
| .build(); |
| lb.handleResolvedAddressGroups(servers, serviceConfigAttrs); |
| |
| verify(testLbBalancer, times(2)) |
| .handleResolvedAddressGroups(eq(servers), attrsCaptor.capture()); |
| // But the balancer config is changed. |
| assertThat(attrsCaptor.getValue().get(ATTR_LOAD_BALANCING_CONFIG)) |
| .isEqualTo(Collections.singletonMap("setting1", "low")); |
| // Service config didn't change policy, thus the delegateLb is not swapped |
| verifyNoMoreInteractions(testLbBalancer); |
| verify(testLbBalancerProvider).newLoadBalancer(any(Helper.class)); |
| } |
| |
| @Test |
| public void handleResolvedAddressGroups_propagateOnlyBackendAddrsToDelegate() throws Exception { |
| // This case only happens when grpclb is missing. We will use a local registry |
| LoadBalancerRegistry registry = new LoadBalancerRegistry(); |
| registry.register(new PickFirstLoadBalancerProvider()); |
| registry.register(new FakeRoundRobinLoadBalancerProvider()); |
| |
| final List<EquivalentAddressGroup> servers = |
| Arrays.asList( |
| new EquivalentAddressGroup(new SocketAddress(){}), |
| new EquivalentAddressGroup( |
| new SocketAddress(){}, |
| Attributes.newBuilder().set(GrpcAttributes.ATTR_LB_ADDR_AUTHORITY, "ok").build())); |
| Helper helper = new TestHelper() { |
| @Override |
| public void updateBalancingState(ConnectivityState newState, SubchannelPicker newPicker) { |
| // noop |
| } |
| }; |
| AutoConfiguredLoadBalancer lb = |
| (AutoConfiguredLoadBalancer) new AutoConfiguredLoadBalancerFactory(registry) |
| .newLoadBalancer(helper); |
| |
| lb.handleResolvedAddressGroups(servers, Attributes.EMPTY); |
| |
| assertThat(lb.getDelegate()).isSameAs(testLbBalancer); |
| verify(testLbBalancer).handleResolvedAddressGroups( |
| eq(Collections.singletonList(servers.get(0))), any(Attributes.class)); |
| } |
| |
| @Test |
| public void decideLoadBalancerProvider_noBalancerAddresses_noServiceConfig_pickFirst() |
| throws Exception { |
| AutoConfiguredLoadBalancer lb = |
| (AutoConfiguredLoadBalancer) lbf.newLoadBalancer(new TestHelper()); |
| Map<String, Object> serviceConfig = null; |
| List<EquivalentAddressGroup> servers = |
| Collections.singletonList(new EquivalentAddressGroup(new SocketAddress(){})); |
| PolicySelection selection = lb.decideLoadBalancerProvider(servers, serviceConfig); |
| |
| assertThat(selection.provider).isInstanceOf(PickFirstLoadBalancerProvider.class); |
| assertThat(selection.serverList).isEqualTo(servers); |
| assertThat(selection.config).isNull(); |
| verifyZeroInteractions(channelLogger); |
| } |
| |
| @Test |
| public void decideLoadBalancerProvider_oneBalancer_noServiceConfig_grpclb() throws Exception { |
| AutoConfiguredLoadBalancer lb = |
| (AutoConfiguredLoadBalancer) lbf.newLoadBalancer(new TestHelper()); |
| Map<String, Object> serviceConfig = null; |
| List<EquivalentAddressGroup> servers = |
| Collections.singletonList( |
| new EquivalentAddressGroup( |
| new SocketAddress(){}, |
| Attributes.newBuilder().set(GrpcAttributes.ATTR_LB_ADDR_AUTHORITY, "ok").build())); |
| PolicySelection selection = lb.decideLoadBalancerProvider(servers, serviceConfig); |
| |
| assertThat(selection.provider).isInstanceOf(GrpclbLoadBalancerProvider.class); |
| assertThat(selection.serverList).isEqualTo(servers); |
| assertThat(selection.config).isNull(); |
| verifyZeroInteractions(channelLogger); |
| } |
| |
| @Test |
| public void decideLoadBalancerProvider_grpclbOverridesServiceConfigLbPolicy() throws Exception { |
| AutoConfiguredLoadBalancer lb = |
| (AutoConfiguredLoadBalancer) lbf.newLoadBalancer(new TestHelper()); |
| Map<String, Object> serviceConfig = new HashMap<String, Object>(); |
| serviceConfig.put("loadBalancingPolicy", "round_robin"); |
| List<EquivalentAddressGroup> servers = |
| Collections.singletonList( |
| new EquivalentAddressGroup( |
| new SocketAddress(){}, |
| Attributes.newBuilder().set(GrpcAttributes.ATTR_LB_ADDR_AUTHORITY, "ok").build())); |
| PolicySelection selection = lb.decideLoadBalancerProvider(servers, serviceConfig); |
| |
| assertThat(selection.provider).isInstanceOf(GrpclbLoadBalancerProvider.class); |
| assertThat(selection.serverList).isEqualTo(servers); |
| assertThat(selection.config).isNull(); |
| verifyZeroInteractions(channelLogger); |
| } |
| |
| @SuppressWarnings("unchecked") |
| @Test |
| public void decideLoadBalancerProvider_grpclbOverridesServiceConfigLbConfig() throws Exception { |
| AutoConfiguredLoadBalancer lb = |
| (AutoConfiguredLoadBalancer) lbf.newLoadBalancer(new TestHelper()); |
| Map<String, Object> serviceConfig = |
| parseConfig("{\"loadBalancingConfig\": [ {\"round_robin\": {} } ] }"); |
| List<EquivalentAddressGroup> servers = |
| Collections.singletonList( |
| new EquivalentAddressGroup( |
| new SocketAddress(){}, |
| Attributes.newBuilder().set(GrpcAttributes.ATTR_LB_ADDR_AUTHORITY, "ok").build())); |
| PolicySelection selection = lb.decideLoadBalancerProvider(servers, serviceConfig); |
| |
| assertThat(selection.provider).isInstanceOf(GrpclbLoadBalancerProvider.class); |
| assertThat(selection.serverList).isEqualTo(servers); |
| assertThat(selection.config).isNull(); |
| verifyZeroInteractions(channelLogger); |
| } |
| |
| @Test |
| public void decideLoadBalancerProvider_grpclbProviderNotFound_fallbackToRoundRobin() |
| throws Exception { |
| LoadBalancerRegistry registry = new LoadBalancerRegistry(); |
| registry.register(new PickFirstLoadBalancerProvider()); |
| registry.register(new FakeRoundRobinLoadBalancerProvider()); |
| AutoConfiguredLoadBalancer lb = |
| (AutoConfiguredLoadBalancer) new AutoConfiguredLoadBalancerFactory(registry) |
| .newLoadBalancer(new TestHelper()); |
| Map<String, Object> serviceConfig = |
| parseConfig("{\"loadBalancingConfig\": [ {\"round_robin\": {} } ] }"); |
| List<EquivalentAddressGroup> servers = |
| Arrays.asList( |
| new EquivalentAddressGroup( |
| new SocketAddress(){}, |
| Attributes.newBuilder().set(GrpcAttributes.ATTR_LB_ADDR_AUTHORITY, "ok").build()), |
| new EquivalentAddressGroup(new SocketAddress(){})); |
| PolicySelection selection = lb.decideLoadBalancerProvider(servers, serviceConfig); |
| |
| assertThat(selection.provider).isInstanceOf(FakeRoundRobinLoadBalancerProvider.class); |
| assertThat(selection.config).isNull(); |
| verify(channelLogger).log( |
| eq(ChannelLogLevel.ERROR), |
| startsWith("Found balancer addresses but grpclb runtime is missing")); |
| |
| // Called for the second time, the warning is only logged once |
| selection = lb.decideLoadBalancerProvider(servers, serviceConfig); |
| |
| assertThat(selection.provider).isInstanceOf(FakeRoundRobinLoadBalancerProvider.class); |
| // Balancer addresses are filtered out in the server list passed to round_robin |
| assertThat(selection.serverList).isEqualTo(Collections.singletonList(servers.get(1))); |
| assertThat(selection.config).isNull(); |
| verifyNoMoreInteractions(channelLogger); |
| } |
| |
| @Test |
| public void decideLoadBalancerProvider_grpclbProviderNotFound_noBackendAddress() |
| throws Exception { |
| LoadBalancerRegistry registry = new LoadBalancerRegistry(); |
| registry.register(new PickFirstLoadBalancerProvider()); |
| registry.register(new FakeRoundRobinLoadBalancerProvider()); |
| AutoConfiguredLoadBalancer lb = |
| (AutoConfiguredLoadBalancer) new AutoConfiguredLoadBalancerFactory(registry) |
| .newLoadBalancer(new TestHelper()); |
| Map<String, Object> serviceConfig = |
| parseConfig("{\"loadBalancingConfig\": [ {\"round_robin\": {} } ] }"); |
| List<EquivalentAddressGroup> servers = |
| Collections.singletonList( |
| new EquivalentAddressGroup( |
| new SocketAddress(){}, |
| Attributes.newBuilder().set(GrpcAttributes.ATTR_LB_ADDR_AUTHORITY, "ok").build())); |
| try { |
| lb.decideLoadBalancerProvider(servers, serviceConfig); |
| fail("Should throw"); |
| } catch (PolicyException e) { |
| assertThat(e.getMessage()) |
| .isEqualTo("Received ONLY balancer addresses but grpclb runtime is missing"); |
| } |
| } |
| |
| @Test |
| public void decideLoadBalancerProvider_serviceConfigLbPolicyOverridesDefault() throws Exception { |
| AutoConfiguredLoadBalancer lb = |
| (AutoConfiguredLoadBalancer) lbf.newLoadBalancer(new TestHelper()); |
| Map<String, Object> serviceConfig = new HashMap<String, Object>(); |
| serviceConfig.put("loadBalancingPolicy", "round_robin"); |
| List<EquivalentAddressGroup> servers = |
| Collections.singletonList(new EquivalentAddressGroup(new SocketAddress(){})); |
| PolicySelection selection = lb.decideLoadBalancerProvider(servers, serviceConfig); |
| |
| assertThat(selection.provider.getClass().getName()).isEqualTo( |
| "io.grpc.util.SecretRoundRobinLoadBalancerProvider$Provider"); |
| assertThat(selection.config).isEqualTo(Collections.emptyMap()); |
| verifyZeroInteractions(channelLogger); |
| } |
| |
| @Test |
| public void decideLoadBalancerProvider_serviceConfigLbConfigOverridesDefault() throws Exception { |
| AutoConfiguredLoadBalancer lb = |
| (AutoConfiguredLoadBalancer) lbf.newLoadBalancer(new TestHelper()); |
| Map<String, Object> serviceConfig = |
| parseConfig("{\"loadBalancingConfig\": [ {\"round_robin\": {\"setting1\": \"high\"} } ] }"); |
| List<EquivalentAddressGroup> servers = |
| Collections.singletonList(new EquivalentAddressGroup(new SocketAddress(){})); |
| PolicySelection selection = lb.decideLoadBalancerProvider(servers, serviceConfig); |
| |
| assertThat(selection.provider.getClass().getName()).isEqualTo( |
| "io.grpc.util.SecretRoundRobinLoadBalancerProvider$Provider"); |
| assertThat(selection.serverList).isEqualTo(servers); |
| assertThat(selection.config).isEqualTo(Collections.singletonMap("setting1", "high")); |
| verifyZeroInteractions(channelLogger); |
| } |
| |
| @Test |
| public void decideLoadBalancerProvider_serviceConfigLbPolicyFailsOnUnknown() { |
| AutoConfiguredLoadBalancer lb = |
| (AutoConfiguredLoadBalancer) lbf.newLoadBalancer(new TestHelper()); |
| Map<String, Object> serviceConfig = new HashMap<String, Object>(); |
| serviceConfig.put("loadBalancingPolicy", "MAGIC_BALANCER"); |
| List<EquivalentAddressGroup> servers = |
| Collections.singletonList(new EquivalentAddressGroup(new SocketAddress(){})); |
| try { |
| lb.decideLoadBalancerProvider(servers, serviceConfig); |
| fail(); |
| } catch (PolicyException e) { |
| assertThat(e.getMessage()).isEqualTo( |
| "None of [magic_balancer] specified by Service Config are available."); |
| } |
| } |
| |
| @Test |
| public void decideLoadBalancerProvider_serviceConfigLbConfigFailsOnUnknown() throws Exception { |
| AutoConfiguredLoadBalancer lb = |
| (AutoConfiguredLoadBalancer) lbf.newLoadBalancer(new TestHelper()); |
| Map<String, Object> serviceConfig = |
| parseConfig("{\"loadBalancingConfig\": [ {\"magic_balancer\": {} } ] }"); |
| List<EquivalentAddressGroup> servers = |
| Collections.singletonList(new EquivalentAddressGroup(new SocketAddress(){})); |
| try { |
| lb.decideLoadBalancerProvider(servers, serviceConfig); |
| fail(); |
| } catch (PolicyException e) { |
| assertThat(e.getMessage()).isEqualTo( |
| "None of [magic_balancer] specified by Service Config are available."); |
| } |
| } |
| |
| @Test |
| public void decideLoadBalancerProvider_serviceConfigLbConfigSkipUnknown() throws Exception { |
| AutoConfiguredLoadBalancer lb = |
| (AutoConfiguredLoadBalancer) lbf.newLoadBalancer(new TestHelper()); |
| Map<String, Object> serviceConfig = |
| parseConfig( |
| "{\"loadBalancingConfig\": [ {\"magic_balancer\": {} }, {\"round_robin\": {} } ] }"); |
| List<EquivalentAddressGroup> servers = |
| Collections.singletonList(new EquivalentAddressGroup(new SocketAddress(){})); |
| PolicySelection selection = lb.decideLoadBalancerProvider(servers, serviceConfig); |
| |
| assertThat(selection.provider.getClass().getName()).isEqualTo( |
| "io.grpc.util.SecretRoundRobinLoadBalancerProvider$Provider"); |
| assertThat(selection.serverList).isEqualTo(servers); |
| assertThat(selection.config).isEqualTo(Collections.emptyMap()); |
| verify(channelLogger).log( |
| eq(ChannelLogLevel.DEBUG), |
| eq("{0} specified by Service Config are not available"), |
| eq(new LinkedHashSet<String>(Arrays.asList("magic_balancer")))); |
| } |
| |
| @Test |
| public void decideLoadBalancerProvider_serviceConfigHasZeroLbConfig() throws Exception { |
| AutoConfiguredLoadBalancer lb = |
| (AutoConfiguredLoadBalancer) lbf.newLoadBalancer(new TestHelper()); |
| List<EquivalentAddressGroup> servers = |
| Collections.singletonList(new EquivalentAddressGroup(new SocketAddress(){})); |
| PolicySelection selection = lb.decideLoadBalancerProvider( |
| servers, Collections.<String, Object>emptyMap()); |
| |
| assertThat(selection.provider).isInstanceOf(PickFirstLoadBalancerProvider.class); |
| assertThat(selection.serverList).isEqualTo(servers); |
| assertThat(selection.config).isNull(); |
| verifyZeroInteractions(channelLogger); |
| } |
| |
| @Test |
| public void channelTracing_lbPolicyChanged() { |
| final FakeClock clock = new FakeClock(); |
| List<EquivalentAddressGroup> servers = |
| Collections.singletonList(new EquivalentAddressGroup(new SocketAddress(){})); |
| Helper helper = new TestHelper() { |
| @Override |
| public Subchannel createSubchannel(List<EquivalentAddressGroup> addrs, Attributes attrs) { |
| return new TestSubchannel(addrs, attrs); |
| } |
| |
| @Override |
| public ManagedChannel createOobChannel(EquivalentAddressGroup eag, String authority) { |
| return mock(ManagedChannel.class, RETURNS_DEEP_STUBS); |
| } |
| |
| @Override |
| public String getAuthority() { |
| return "fake_authority"; |
| } |
| |
| @Override |
| public void updateBalancingState(ConnectivityState newState, SubchannelPicker newPicker) { |
| // noop |
| } |
| |
| @Override |
| public SynchronizationContext getSynchronizationContext() { |
| return new SynchronizationContext( |
| new Thread.UncaughtExceptionHandler() { |
| @Override |
| public void uncaughtException(Thread t, Throwable e) { |
| throw new AssertionError(e); |
| } |
| }); |
| } |
| |
| @Override |
| public ScheduledExecutorService getScheduledExecutorService() { |
| return clock.getScheduledExecutorService(); |
| } |
| }; |
| |
| LoadBalancer lb = new AutoConfiguredLoadBalancerFactory().newLoadBalancer(helper); |
| lb.handleResolvedAddressGroups(servers, Attributes.EMPTY); |
| |
| verifyNoMoreInteractions(channelLogger); |
| |
| Map<String, Object> serviceConfig = new HashMap<String, Object>(); |
| serviceConfig.put("loadBalancingPolicy", "round_robin"); |
| lb.handleResolvedAddressGroups(servers, |
| Attributes.newBuilder() |
| .set(GrpcAttributes.NAME_RESOLVER_SERVICE_CONFIG, serviceConfig).build()); |
| |
| verify(channelLogger).log( |
| eq(ChannelLogLevel.INFO), |
| eq("Load balancer changed from {0} to {1}"), |
| eq("PickFirstLoadBalancer"), eq("RoundRobinLoadBalancer")); |
| verify(channelLogger).log( |
| eq(ChannelLogLevel.DEBUG), |
| eq("Load-balancing config: {0}"), |
| eq(Collections.emptyMap())); |
| verifyNoMoreInteractions(channelLogger); |
| |
| serviceConfig.put("loadBalancingPolicy", "round_robin"); |
| lb.handleResolvedAddressGroups(servers, |
| Attributes.newBuilder() |
| .set(GrpcAttributes.NAME_RESOLVER_SERVICE_CONFIG, serviceConfig).build()); |
| verify(channelLogger, times(2)).log( |
| eq(ChannelLogLevel.DEBUG), |
| eq("Load-balancing config: {0}"), |
| eq(Collections.emptyMap())); |
| verifyNoMoreInteractions(channelLogger); |
| |
| servers = Collections.singletonList(new EquivalentAddressGroup( |
| new SocketAddress(){}, |
| Attributes.newBuilder().set(GrpcAttributes.ATTR_LB_ADDR_AUTHORITY, "ok").build())); |
| lb.handleResolvedAddressGroups(servers, Attributes.EMPTY); |
| |
| verify(channelLogger).log( |
| eq(ChannelLogLevel.INFO), |
| eq("Load balancer changed from {0} to {1}"), |
| eq("RoundRobinLoadBalancer"), eq("GrpclbLoadBalancer")); |
| |
| verifyNoMoreInteractions(channelLogger); |
| } |
| |
| public static class ForwardingLoadBalancer extends LoadBalancer { |
| private final LoadBalancer delegate; |
| |
| public ForwardingLoadBalancer(LoadBalancer delegate) { |
| this.delegate = delegate; |
| } |
| |
| protected LoadBalancer delegate() { |
| return delegate; |
| } |
| |
| @Override |
| public void handleResolvedAddressGroups( |
| List<EquivalentAddressGroup> servers, Attributes attributes) { |
| delegate().handleResolvedAddressGroups(servers, attributes); |
| } |
| |
| @Override |
| public void handleNameResolutionError(Status error) { |
| delegate().handleNameResolutionError(error); |
| } |
| |
| @Override |
| public void handleSubchannelState(Subchannel subchannel, ConnectivityStateInfo stateInfo) { |
| delegate().handleSubchannelState(subchannel, stateInfo); |
| } |
| |
| @Override |
| public void shutdown() { |
| delegate().shutdown(); |
| } |
| } |
| |
| @SuppressWarnings("unchecked") |
| private static Map<String, Object> parseConfig(String json) throws Exception { |
| return (Map<String, Object>) JsonParser.parse(json); |
| } |
| |
| private static class TestLoadBalancer extends ForwardingLoadBalancer { |
| TestLoadBalancer() { |
| super(null); |
| } |
| } |
| |
| private class TestHelper extends ForwardingLoadBalancerHelper { |
| @Override |
| protected Helper delegate() { |
| return null; |
| } |
| |
| @Override |
| public ChannelLogger getChannelLogger() { |
| return channelLogger; |
| } |
| } |
| |
| private static class TestSubchannel extends Subchannel { |
| TestSubchannel(List<EquivalentAddressGroup> addrs, Attributes attrs) { |
| this.addrs = addrs; |
| this.attrs = attrs; |
| } |
| |
| final List<EquivalentAddressGroup> addrs; |
| final Attributes attrs; |
| |
| @Override |
| public void shutdown() { |
| } |
| |
| @Override |
| public void requestConnection() { |
| } |
| |
| @Override |
| public List<EquivalentAddressGroup> getAllAddresses() { |
| return addrs; |
| } |
| |
| @Override |
| public Attributes getAttributes() { |
| return attrs; |
| } |
| } |
| |
| private final class TestLbLoadBalancerProvider extends LoadBalancerProvider { |
| static final String POLICY_NAME = "test_lb"; |
| |
| @Override |
| public boolean isAvailable() { |
| return true; |
| } |
| |
| @Override |
| public int getPriority() { |
| return 5; |
| } |
| |
| @Override |
| public String getPolicyName() { |
| return POLICY_NAME; |
| } |
| |
| @Override |
| public LoadBalancer newLoadBalancer(Helper helper) { |
| return testLbBalancer; |
| } |
| } |
| |
| private final class FakeRoundRobinLoadBalancerProvider extends LoadBalancerProvider { |
| static final String POLICY_NAME = "round_robin"; |
| |
| @Override |
| public boolean isAvailable() { |
| return true; |
| } |
| |
| @Override |
| public int getPriority() { |
| return 5; |
| } |
| |
| @Override |
| public String getPolicyName() { |
| return POLICY_NAME; |
| } |
| |
| @Override |
| public LoadBalancer newLoadBalancer(Helper helper) { |
| return testLbBalancer; |
| } |
| } |
| } |