core: add default implementation of managed channel builder

This commit is contained in:
Sergii Tkachenko 2020-09-01 19:05:25 -04:00 committed by Sergii Tkachenko
parent fa103b9d7a
commit c7f876d016
7 changed files with 418 additions and 81 deletions

View File

@ -20,6 +20,7 @@ import static io.grpc.benchmarks.Utils.pickUnusedPort;
import com.google.protobuf.ByteString;
import io.grpc.ManagedChannel;
import io.grpc.ManagedChannelBuilder;
import io.grpc.Server;
import io.grpc.Status;
import io.grpc.StatusRuntimeException;
@ -30,7 +31,6 @@ import io.grpc.benchmarks.proto.Messages.SimpleResponse;
import io.grpc.benchmarks.qps.AsyncServer;
import io.grpc.inprocess.InProcessChannelBuilder;
import io.grpc.inprocess.InProcessServerBuilder;
import io.grpc.internal.AbstractManagedChannelImplBuilder;
import io.grpc.internal.AbstractServerImplBuilder;
import io.grpc.netty.NegotiationType;
import io.grpc.netty.NettyChannelBuilder;
@ -81,7 +81,7 @@ public class TransportBenchmark {
@Setup
public void setUp() throws Exception {
AbstractServerImplBuilder<?> serverBuilder;
AbstractManagedChannelImplBuilder<?> channelBuilder;
ManagedChannelBuilder<?> channelBuilder;
switch (transport) {
case INPROCESS:
{

View File

@ -51,7 +51,7 @@ import java.util.logging.Logger;
import javax.annotation.Nullable;
/**
* The base class for channel builders.
* Abstract base class for channel builders.
*
* @param <T> The concrete type of this builder.
*/

View File

@ -0,0 +1,198 @@
/*
* Copyright 2020 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 com.google.common.base.Preconditions;
import io.grpc.ManagedChannelBuilder;
import java.net.SocketAddress;
import java.util.concurrent.Executor;
import javax.annotation.Nullable;
/**
* Default managed channel builder, for usage in Transport implementations.
*/
public final class ManagedChannelImplBuilder
extends AbstractManagedChannelImplBuilder<ManagedChannelImplBuilder> {
private boolean authorityCheckerDisabled;
@Deprecated
@Nullable
private OverrideAuthorityChecker authorityChecker;
/**
* An interface for Transport implementors to provide the {@link ClientTransportFactory}
* appropriate for the channel.
*/
public interface ClientTransportFactoryBuilder {
ClientTransportFactory buildClientTransportFactory();
}
/**
* An interface for Transport implementors to provide a default port to {@link
* io.grpc.NameResolver} for use in cases where the target string doesn't include a port. The
* default implementation returns {@link GrpcUtil#DEFAULT_PORT_SSL}.
*/
public interface ChannelBuilderDefaultPortProvider {
int getDefaultPort();
}
/**
* Default implementation of {@link ChannelBuilderDefaultPortProvider} that returns a fixed port.
*/
public static final class FixedPortProvider implements ChannelBuilderDefaultPortProvider {
private final int port;
public FixedPortProvider(int port) {
this.port = port;
}
@Override
public int getDefaultPort() {
return port;
}
}
private final class ManagedChannelDefaultPortProvider implements
ChannelBuilderDefaultPortProvider {
@Override
public int getDefaultPort() {
return ManagedChannelImplBuilder.super.getDefaultPort();
}
}
private final ClientTransportFactoryBuilder clientTransportFactoryBuilder;
private final ChannelBuilderDefaultPortProvider channelBuilderDefaultPortProvider;
/**
* Creates a new managed channel builder with a target string, which can be either a valid {@link
* io.grpc.NameResolver}-compliant URI, or an authority string. Transport implementors must
* provide client transport factory builder, and may set custom channel default port provider.
*/
public ManagedChannelImplBuilder(String target,
ClientTransportFactoryBuilder clientTransportFactoryBuilder,
@Nullable ChannelBuilderDefaultPortProvider channelBuilderDefaultPortProvider) {
super(target);
this.clientTransportFactoryBuilder = Preconditions
.checkNotNull(clientTransportFactoryBuilder, "clientTransportFactoryBuilder");
if (channelBuilderDefaultPortProvider != null) {
this.channelBuilderDefaultPortProvider = channelBuilderDefaultPortProvider;
} else {
this.channelBuilderDefaultPortProvider = new ManagedChannelDefaultPortProvider();
}
}
/**
* Creates a new managed channel builder with the given server address, authority string of the
* channel. Transport implementors must provide client transport factory builder, and may set
* custom channel default port provider.
*/
public ManagedChannelImplBuilder(SocketAddress directServerAddress, String authority,
ClientTransportFactoryBuilder clientTransportFactoryBuilder,
@Nullable ChannelBuilderDefaultPortProvider channelBuilderDefaultPortProvider) {
super(directServerAddress, authority);
this.clientTransportFactoryBuilder = Preconditions
.checkNotNull(clientTransportFactoryBuilder, "clientTransportFactoryBuilder");
if (channelBuilderDefaultPortProvider != null) {
this.channelBuilderDefaultPortProvider = channelBuilderDefaultPortProvider;
} else {
this.channelBuilderDefaultPortProvider = new ManagedChannelDefaultPortProvider();
}
}
@Override
protected ClientTransportFactory buildTransportFactory() {
return clientTransportFactoryBuilder.buildClientTransportFactory();
}
@Override
protected int getDefaultPort() {
return channelBuilderDefaultPortProvider.getDefaultPort();
}
/** Disable the check whether the authority is valid. */
public ManagedChannelImplBuilder disableCheckAuthority() {
authorityCheckerDisabled = true;
return this;
}
/** Enable previously disabled authority check. */
public ManagedChannelImplBuilder enableCheckAuthority() {
authorityCheckerDisabled = false;
return this;
}
@Deprecated
public interface OverrideAuthorityChecker {
String checkAuthority(String authority);
}
@Deprecated
public void overrideAuthorityChecker(@Nullable OverrideAuthorityChecker authorityChecker) {
this.authorityChecker = authorityChecker;
}
@Override
protected String checkAuthority(String authority) {
if (authorityCheckerDisabled) {
return authority;
}
if (authorityChecker != null) {
return authorityChecker.checkAuthority(authority);
}
return super.checkAuthority(authority);
}
@Override
public void setStatsEnabled(boolean value) {
super.setStatsEnabled(value);
}
@Override
public void setStatsRecordStartedRpcs(boolean value) {
super.setStatsRecordStartedRpcs(value);
}
@Override
public void setStatsRecordFinishedRpcs(boolean value) {
super.setStatsRecordFinishedRpcs(value);
}
@Override
public void setStatsRecordRealTimeMetrics(boolean value) {
super.setStatsRecordRealTimeMetrics(value);
}
@Override
public void setTracingEnabled(boolean value) {
super.setTracingEnabled(value);
}
@Override
public ObjectPool<? extends Executor> getOffloadExecutorPool() {
return super.getOffloadExecutorPool();
}
public static ManagedChannelBuilder<?> forAddress(String name, int port) {
throw new UnsupportedOperationException("ClientTransportFactoryBuilder is required");
}
public static ManagedChannelBuilder<?> forTarget(String target) {
throw new UnsupportedOperationException("ClientTransportFactoryBuilder is required");
}
}

View File

@ -0,0 +1,162 @@
/*
* Copyright 2020 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 org.junit.Assert.assertEquals;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import io.grpc.internal.ManagedChannelImplBuilder.ChannelBuilderDefaultPortProvider;
import io.grpc.internal.ManagedChannelImplBuilder.ClientTransportFactoryBuilder;
import io.grpc.internal.ManagedChannelImplBuilder.FixedPortProvider;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.ExpectedException;
import org.junit.runner.RunWith;
import org.junit.runners.JUnit4;
import org.mockito.Mock;
import org.mockito.junit.MockitoJUnit;
import org.mockito.junit.MockitoRule;
/** Unit tests for {@link ManagedChannelImplBuilder}. */
@RunWith(JUnit4.class)
public class ManagedChannelImplBuilderTest {
private static final int DUMMY_PORT = 42;
private static final String DUMMY_TARGET = "fake-target";
private static final String DUMMY_AUTHORITY_VALID = "valid:1234";
private static final String DUMMY_AUTHORITY_INVALID = "[ : : 1]";
@Rule public final MockitoRule mocks = MockitoJUnit.rule();
@Rule public final ExpectedException thrown = ExpectedException.none();
@Mock private ClientTransportFactoryBuilder mockClientTransportFactoryBuilder;
@Mock private ChannelBuilderDefaultPortProvider mockChannelBuilderDefaultPortProvider;
private ManagedChannelImplBuilder builder;
@Before
public void setUp() throws Exception {
builder = new ManagedChannelImplBuilder(
DUMMY_TARGET,
mockClientTransportFactoryBuilder,
mockChannelBuilderDefaultPortProvider);
}
/** Ensure buildTransportFactory() delegates to the custom implementation. */
@Test
public void buildTransportFactory() {
final ClientTransportFactory clientTransportFactory = mock(ClientTransportFactory.class);
when(mockClientTransportFactoryBuilder.buildClientTransportFactory())
.thenReturn(clientTransportFactory);
assertEquals(clientTransportFactory, builder.buildTransportFactory());
verify(mockClientTransportFactoryBuilder).buildClientTransportFactory();
}
/** Ensure getDefaultPort() returns default port when no custom implementation provided. */
@Test
public void getDefaultPort_default() {
final ManagedChannelImplBuilder builderNoPortProvider = new ManagedChannelImplBuilder(
DUMMY_TARGET, mockClientTransportFactoryBuilder, null);
assertEquals(GrpcUtil.DEFAULT_PORT_SSL, builderNoPortProvider.getDefaultPort());
}
/** Ensure getDefaultPort() delegates to the custom implementation. */
@Test
public void getDefaultPort_custom() {
when(mockChannelBuilderDefaultPortProvider.getDefaultPort()).thenReturn(DUMMY_PORT);
assertEquals(DUMMY_PORT, builder.getDefaultPort());
verify(mockChannelBuilderDefaultPortProvider).getDefaultPort();
}
/** Test FixedPortProvider(int port). */
@Test
public void getDefaultPort_fixedPortProvider() {
final ManagedChannelImplBuilder builderFixedPortProvider = new ManagedChannelImplBuilder(
DUMMY_TARGET,
mockClientTransportFactoryBuilder,
new FixedPortProvider(DUMMY_PORT));
assertEquals(DUMMY_PORT, builderFixedPortProvider.getDefaultPort());
}
@Test
public void checkAuthority_validAuthorityAllowed() {
assertEquals(DUMMY_AUTHORITY_VALID, builder.checkAuthority(DUMMY_AUTHORITY_VALID));
}
@Test
public void checkAuthority_invalidAuthorityFailed() {
thrown.expect(IllegalArgumentException.class);
thrown.expectMessage("Invalid authority");
builder.checkAuthority(DUMMY_AUTHORITY_INVALID);
}
@Test
public void disableCheckAuthority_validAuthorityAllowed() {
builder.disableCheckAuthority();
assertEquals(DUMMY_AUTHORITY_VALID, builder.checkAuthority(DUMMY_AUTHORITY_VALID));
}
@Test
public void disableCheckAuthority_invalidAuthorityAllowed() {
builder.disableCheckAuthority();
assertEquals(DUMMY_AUTHORITY_INVALID, builder.checkAuthority(DUMMY_AUTHORITY_INVALID));
}
@Test
public void enableCheckAuthority_validAuthorityAllowed() {
builder.disableCheckAuthority().enableCheckAuthority();
assertEquals(DUMMY_AUTHORITY_VALID, builder.checkAuthority(DUMMY_AUTHORITY_VALID));
}
@Test
public void disableCheckAuthority_invalidAuthorityFailed() {
thrown.expect(IllegalArgumentException.class);
thrown.expectMessage("Invalid authority");
builder.disableCheckAuthority().enableCheckAuthority();
builder.checkAuthority(DUMMY_AUTHORITY_INVALID);
}
/** Ensure authority check can disabled with custom authority check implementation. */
@Test
@SuppressWarnings("deprecation")
public void overrideAuthorityChecker_default() {
builder.overrideAuthorityChecker(
new io.grpc.internal.ManagedChannelImplBuilder.OverrideAuthorityChecker() {
@Override public String checkAuthority(String authority) {
return authority;
}
});
assertEquals(DUMMY_AUTHORITY_INVALID, builder.checkAuthority(DUMMY_AUTHORITY_INVALID));
}
/** Ensure custom authority is ignored after disableCheckAuthority(). */
@Test
@SuppressWarnings("deprecation")
public void overrideAuthorityChecker_ignored() {
builder.overrideAuthorityChecker(
new io.grpc.internal.ManagedChannelImplBuilder.OverrideAuthorityChecker() {
@Override public String checkAuthority(String authority) {
throw new IllegalArgumentException();
}
});
builder.disableCheckAuthority();
assertEquals(DUMMY_AUTHORITY_INVALID, builder.checkAuthority(DUMMY_AUTHORITY_INVALID));
}
}

View File

@ -62,6 +62,7 @@ import io.grpc.NameResolver.ResolutionResult;
import io.grpc.Status;
import io.grpc.StringMarshaller;
import io.grpc.internal.FakeClock.ScheduledTask;
import io.grpc.internal.ManagedChannelImplBuilder.ClientTransportFactoryBuilder;
import io.grpc.internal.TestUtils.MockClientTransportInfo;
import java.net.SocketAddress;
import java.net.URI;
@ -159,21 +160,15 @@ public class ManagedChannelImplIdlenessTest {
when(mockTransportFactory.getScheduledExecutorService())
.thenReturn(timer.getScheduledExecutorService());
class Builder extends AbstractManagedChannelImplBuilder<Builder> {
Builder(String target) {
super(target);
}
@Override protected ClientTransportFactory buildTransportFactory() {
ManagedChannelImplBuilder builder = new ManagedChannelImplBuilder("fake://target",
new ClientTransportFactoryBuilder() {
@Override public ClientTransportFactory buildClientTransportFactory() {
throw new UnsupportedOperationException();
}
},
null);
@Override public Builder usePlaintext() {
throw new UnsupportedOperationException();
}
}
Builder builder = new Builder("fake://target")
builder
.nameResolverFactory(mockNameResolverFactory)
.defaultLoadBalancingPolicy(MOCK_POLICY_NAME)
.idleTimeout(IDLE_TIMEOUT_SECONDS, TimeUnit.SECONDS)

View File

@ -107,6 +107,8 @@ import io.grpc.StringMarshaller;
import io.grpc.internal.ClientTransportFactory.ClientTransportOptions;
import io.grpc.internal.InternalSubchannel.TransportLogger;
import io.grpc.internal.ManagedChannelImpl.ScParser;
import io.grpc.internal.ManagedChannelImplBuilder.ClientTransportFactoryBuilder;
import io.grpc.internal.ManagedChannelImplBuilder.FixedPortProvider;
import io.grpc.internal.ServiceConfigUtil.PolicySelection;
import io.grpc.internal.TestUtils.MockClientTransportInfo;
import io.grpc.stub.ClientCalls;
@ -269,7 +271,7 @@ public class ManagedChannelImplTest {
private CallCredentials creds;
@Mock
private Executor offloadExecutor;
private ChannelBuilder channelBuilder;
private ManagedChannelImplBuilder channelBuilder;
private boolean requestConnection = true;
private BlockingQueue<MockClientTransportInfo> transports;
private boolean panicExpected;
@ -325,13 +327,19 @@ public class ManagedChannelImplTest {
when(balancerRpcExecutorPool.getObject())
.thenReturn(balancerRpcExecutor.getScheduledExecutorService());
channelBuilder =
new ChannelBuilder()
channelBuilder = new ManagedChannelImplBuilder(TARGET,
new ClientTransportFactoryBuilder() {
@Override
public ClientTransportFactory buildClientTransportFactory() {
throw new UnsupportedOperationException();
}
},
new FixedPortProvider(DEFAULT_PORT));
channelBuilder
.nameResolverFactory(new FakeNameResolverFactory.Builder(expectedUri).build())
.defaultLoadBalancingPolicy(MOCK_POLICY_NAME)
.userAgent(USER_AGENT)
.idleTimeout(
AbstractManagedChannelImplBuilder.IDLE_MODE_MAX_TIMEOUT_DAYS, TimeUnit.DAYS)
.idleTimeout(ManagedChannelImplBuilder.IDLE_MODE_MAX_TIMEOUT_DAYS, TimeUnit.DAYS)
.offloadExecutor(offloadExecutor);
channelBuilder.executorPool = executorPool;
channelBuilder.binlog = null;
@ -3466,21 +3474,18 @@ public class ManagedChannelImplTest {
}
FakeNameResolverFactory2 factory = new FakeNameResolverFactory2();
final class CustomBuilder extends AbstractManagedChannelImplBuilder<CustomBuilder> {
CustomBuilder() {
super(TARGET);
this.executorPool = ManagedChannelImplTest.this.executorPool;
this.channelz = ManagedChannelImplTest.this.channelz;
}
ManagedChannelImplBuilder customBuilder = new ManagedChannelImplBuilder(TARGET,
new ClientTransportFactoryBuilder() {
@Override
protected ClientTransportFactory buildTransportFactory() {
public ClientTransportFactory buildClientTransportFactory() {
return mockTransportFactory;
}
}
ManagedChannel mychannel = new CustomBuilder().nameResolverFactory(factory).build();
},
null);
customBuilder.executorPool = executorPool;
customBuilder.channelz = channelz;
ManagedChannel mychannel = customBuilder.nameResolverFactory(factory).build();
ClientCall<Void, Void> call1 =
mychannel.newCall(TestMethodDescriptors.voidMethod(), CallOptions.DEFAULT);
@ -4025,22 +4030,6 @@ public class ManagedChannelImplTest {
}
}
private static final class ChannelBuilder
extends AbstractManagedChannelImplBuilder<ChannelBuilder> {
ChannelBuilder() {
super(TARGET);
}
@Override protected ClientTransportFactory buildTransportFactory() {
throw new UnsupportedOperationException();
}
@Override protected int getDefaultPort() {
return DEFAULT_PORT;
}
}
private static final class FakeBackoffPolicyProvider implements BackoffPolicy.Provider {
@Override
public BackoffPolicy get() {

View File

@ -46,6 +46,8 @@ import io.grpc.LoadBalancerRegistry;
import io.grpc.NameResolver;
import io.grpc.NameResolver.ConfigOrError;
import io.grpc.Status;
import io.grpc.internal.ManagedChannelImplBuilder.ClientTransportFactoryBuilder;
import io.grpc.internal.ManagedChannelImplBuilder.FixedPortProvider;
import java.net.SocketAddress;
import java.net.URI;
import java.util.ArrayList;
@ -151,7 +153,7 @@ public class ServiceConfigErrorHandlingTest {
private ObjectPool<Executor> balancerRpcExecutorPool;
@Mock
private Executor blockingExecutor;
private ChannelBuilder channelBuilder;
private ManagedChannelImplBuilder channelBuilder;
private void createChannel(ClientInterceptor... interceptors) {
checkState(channel == null);
@ -197,13 +199,20 @@ public class ServiceConfigErrorHandlingTest {
.thenReturn(timer.getScheduledExecutorService());
when(executorPool.getObject()).thenReturn(executor.getScheduledExecutorService());
channelBuilder =
new ChannelBuilder()
channelBuilder = new ManagedChannelImplBuilder(TARGET,
new ClientTransportFactoryBuilder() {
@Override
public ClientTransportFactory buildClientTransportFactory() {
throw new UnsupportedOperationException();
}
},
new FixedPortProvider(DEFAULT_PORT));
channelBuilder
.nameResolverFactory(new FakeNameResolverFactory.Builder(expectedUri).build())
.defaultLoadBalancingPolicy(MOCK_POLICY_NAME)
.userAgent(USER_AGENT)
.idleTimeout(
AbstractManagedChannelImplBuilder.IDLE_MODE_MAX_TIMEOUT_DAYS, TimeUnit.DAYS)
.idleTimeout(ManagedChannelImplBuilder.IDLE_MODE_MAX_TIMEOUT_DAYS, TimeUnit.DAYS)
.offloadExecutor(blockingExecutor);
channelBuilder.executorPool = executorPool;
channelBuilder.binlog = null;
@ -527,22 +536,6 @@ public class ServiceConfigErrorHandlingTest {
verify(mockLoadBalancer, never()).handleNameResolutionError(any(Status.class));
}
private static final class ChannelBuilder
extends AbstractManagedChannelImplBuilder<ChannelBuilder> {
ChannelBuilder() {
super(TARGET);
}
@Override protected ClientTransportFactory buildTransportFactory() {
throw new UnsupportedOperationException();
}
@Override protected int getDefaultPort() {
return DEFAULT_PORT;
}
}
private static final class FakeBackoffPolicyProvider implements BackoffPolicy.Provider {
@Override
public BackoffPolicy get() {