diff options
author | Kun Zhang <zhangkun83@users.noreply.github.com> | 2018-10-06 12:36:35 -0700 |
---|---|---|
committer | GitHub <noreply@github.com> | 2018-10-06 12:36:35 -0700 |
commit | cc5e3c19df185913d2f9255e815430b7c3f2b331 (patch) | |
tree | 4888aedcc4525a41e4a50502ab8905889049fb0b /core | |
parent | 0b7043d31ac3f7aa7156b91350d8eb06eed6e3ff (diff) | |
download | grpc-grpc-java-cc5e3c19df185913d2f9255e815430b7c3f2b331.tar.gz |
core: ForwardingLoadBalancerHelper (#4911)
This will be used by LoadBalancer plugins that delegates to another,
which is what the new request routing (go/grpc-request-routing-design)
requires. This will also be used to wrap LoadBalancers to add
client-side health-checking functionality.
Diffstat (limited to 'core')
3 files changed, 210 insertions, 4 deletions
diff --git a/core/src/main/java/io/grpc/util/ForwardingLoadBalancerHelper.java b/core/src/main/java/io/grpc/util/ForwardingLoadBalancerHelper.java new file mode 100644 index 000000000..e2a9720d4 --- /dev/null +++ b/core/src/main/java/io/grpc/util/ForwardingLoadBalancerHelper.java @@ -0,0 +1,95 @@ +/* + * 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.util; + +import com.google.common.base.MoreObjects; +import io.grpc.Attributes; +import io.grpc.ConnectivityState; +import io.grpc.EquivalentAddressGroup; +import io.grpc.ExperimentalApi; +import io.grpc.LoadBalancer.Subchannel; +import io.grpc.LoadBalancer.SubchannelPicker; +import io.grpc.LoadBalancer; +import io.grpc.ManagedChannel; +import io.grpc.NameResolver; +import java.util.List; + +@ExperimentalApi("https://github.com/grpc/grpc-java/issues/1771") +public abstract class ForwardingLoadBalancerHelper extends LoadBalancer.Helper { + /** + * Returns the underlying helper. + */ + protected abstract LoadBalancer.Helper delegate(); + + @Override + public Subchannel createSubchannel(EquivalentAddressGroup addrs, Attributes attrs) { + return delegate().createSubchannel(addrs, attrs); + } + + @Override + public Subchannel createSubchannel(List<EquivalentAddressGroup> addrs, Attributes attrs) { + return delegate().createSubchannel(addrs, attrs); + } + + @Override + public void updateSubchannelAddresses( + Subchannel subchannel, EquivalentAddressGroup addrs) { + delegate().updateSubchannelAddresses(subchannel, addrs); + } + + @Override + public void updateSubchannelAddresses( + Subchannel subchannel, List<EquivalentAddressGroup> addrs) { + delegate().updateSubchannelAddresses(subchannel, addrs); + } + + @Override + public ManagedChannel createOobChannel(EquivalentAddressGroup eag, String authority) { + return delegate().createOobChannel(eag, authority); + } + + @Override + public void updateOobChannelAddresses(ManagedChannel channel, EquivalentAddressGroup eag) { + delegate().updateOobChannelAddresses(channel, eag); + } + + @Override + public void updateBalancingState( + ConnectivityState newState, SubchannelPicker newPicker) { + delegate().updateBalancingState(newState, newPicker); + } + + @Override + public void runSerialized(Runnable task) { + delegate().runSerialized(task); + } + + @Override + public NameResolver.Factory getNameResolverFactory() { + return delegate().getNameResolverFactory(); + } + + @Override + public String getAuthority() { + return delegate().getAuthority(); + } + + @Override + public String toString() { + return MoreObjects.toStringHelper(this).add("delegate", delegate()).toString(); + } +} diff --git a/core/src/test/java/io/grpc/ForwardingTestUtil.java b/core/src/test/java/io/grpc/ForwardingTestUtil.java index ce9ca5eb7..e9f1c5b23 100644 --- a/core/src/test/java/io/grpc/ForwardingTestUtil.java +++ b/core/src/test/java/io/grpc/ForwardingTestUtil.java @@ -28,6 +28,7 @@ import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.lang.reflect.Modifier; import java.util.Collection; +import javax.annotation.Nullable; /** * A util class to help test forwarding classes. @@ -35,9 +36,8 @@ import java.util.Collection; public final class ForwardingTestUtil { /** * Use reflection to perform a basic sanity test. The forwarding class should forward all public - * methods to the delegate, except for those in skippedMethods. - * This does NOT verify that arguments or return values are forwarded properly. It only alerts - * the developer if a forward method is missing. + * methods to the delegate, except for those in skippedMethods. This does NOT verify that + * arguments or return values are forwarded properly. * * @param delegateClass The class whose methods should be forwarded. * @param mockDelegate The mockito mock of the delegate class. @@ -49,6 +49,34 @@ public final class ForwardingTestUtil { T mockDelegate, T forwarder, Collection<Method> skippedMethods) throws Exception { + testMethodsForwarded( + delegateClass, mockDelegate, forwarder, skippedMethods, + new ArgumentProvider() { + @Override + public Object get(Class<?> clazz) { + return null; + } + }); + } + + /** + * Use reflection to perform a basic sanity test. The forwarding class should forward all public + * methods to the delegate, except for those in skippedMethods. This does NOT verify that return + * values are forwarded properly, and can only verify the propagation of arguments for which + * {@code argProvider} returns distinctive non-null values. + * + * @param delegateClass The class whose methods should be forwarded. + * @param mockDelegate The mockito mock of the delegate class. + * @param forwarder The forwarder object that forwards to the mockDelegate. + * @param skippedMethods A collection of methods that are skipped by the test. + * @param argProvider provides argument to be passed to tested forwarding methods. + */ + public static <T> void testMethodsForwarded( + Class<T> delegateClass, + T mockDelegate, + T forwarder, + Collection<Method> skippedMethods, + ArgumentProvider argProvider) throws Exception { assertTrue(mockingDetails(mockDelegate).isMock()); assertFalse(mockingDetails(forwarder).isMock()); @@ -61,7 +89,9 @@ public final class ForwardingTestUtil { Class<?>[] argTypes = method.getParameterTypes(); Object[] args = new Object[argTypes.length]; for (int i = 0; i < argTypes.length; i++) { - args[i] = Defaults.defaultValue(argTypes[i]); + if ((args[i] = argProvider.get(argTypes[i])) == null) { + args[i] = Defaults.defaultValue(argTypes[i]); + } } method.invoke(forwarder, args); try { @@ -85,4 +115,20 @@ public final class ForwardingTestUtil { assertEquals("Method toString() was not forwarded properly", expected, actual); } } + + /** + * Provides arguments for forwarded methods tested in {@link #testMethodsForwarded}. + */ + public interface ArgumentProvider { + /** + * Return an instance of the given class to be used as an argument passed to one method call. + * If one method has multiple arguments with the same type, each occurrence will call this + * method once. It is recommended that each invocation returns a distinctive object for the + * same type, in order to verify that arguments are passed by the tested class correctly. + * + * @return a value to be passed as an argument. If {@code null}, {@link Default#defaultValue} + * will be used. + */ + @Nullable Object get(Class<?> clazz); + } } diff --git a/core/src/test/java/io/grpc/util/ForwardingLoadBalancerHelperTest.java b/core/src/test/java/io/grpc/util/ForwardingLoadBalancerHelperTest.java new file mode 100644 index 000000000..ebc883b9a --- /dev/null +++ b/core/src/test/java/io/grpc/util/ForwardingLoadBalancerHelperTest.java @@ -0,0 +1,65 @@ +/* + * 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.util; + +import static org.mockito.Mockito.mock; + +import io.grpc.EquivalentAddressGroup; +import io.grpc.ForwardingTestUtil; +import io.grpc.LoadBalancer; +import java.lang.reflect.Method; +import java.net.SocketAddress; +import java.util.Arrays; +import java.util.Collections; +import java.util.List; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.junit.runners.JUnit4; + +/** Unit tests for {@link ForwardingLoadBalancerHelper}. */ +@RunWith(JUnit4.class) +public class ForwardingLoadBalancerHelperTest { + private final LoadBalancer.Helper mockDelegate = mock(LoadBalancer.Helper.class); + + private final class TestHelper extends ForwardingLoadBalancerHelper { + @Override + protected LoadBalancer.Helper delegate() { + return mockDelegate; + } + } + + @Test + public void allMethodsForwarded() throws Exception { + final SocketAddress mockAddr = mock(SocketAddress.class); + ForwardingTestUtil.testMethodsForwarded( + LoadBalancer.Helper.class, + mockDelegate, + new TestHelper(), + Collections.<Method>emptyList(), + new ForwardingTestUtil.ArgumentProvider() { + @Override + public Object get(Class<?> clazz) { + if (clazz.equals(EquivalentAddressGroup.class)) { + return new EquivalentAddressGroup(Arrays.asList(mockAddr)); + } else if (clazz.equals(List.class)) { + return Collections.<Object>emptyList(); + } + return null; + } + }); + } +} |