Skip to content

Commit

Permalink
core: add concrete implementation of managed channel builder
Browse files Browse the repository at this point in the history
  • Loading branch information
sergiitk committed Aug 25, 2020
1 parent 292f3b9 commit e7afdb3
Show file tree
Hide file tree
Showing 3 changed files with 333 additions and 1 deletion.
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@
import javax.annotation.Nullable;

/**
* The base class for channel builders.
* Abstract base class for channel builders.
*
* @param <T> The concrete type of this builder.
*/
Expand Down
181 changes: 181 additions & 0 deletions core/src/main/java/io/grpc/internal/ManagedChannelImplBuilder.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,181 @@
/*
* 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();
}

private 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 cannot be null");

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 cannot be null");

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");
}
}
151 changes: 151 additions & 0 deletions core/src/test/java/io/grpc/internal/ManagedChannelImplBuilderTest.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,151 @@
/*
* 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 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
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));
}
}

0 comments on commit e7afdb3

Please sign in to comment.