Add internal channel builder API to get target

This will be used for gRFC A66's OTel per-RPC metric label:

> `grpc.target` : Canonicalized target URI used when creating gRPC
> Channel, e.g. "dns:///pubsub.googleapis.com:443",
> "xds:///helloworld-gke:8000". Canonicalized target URI is the form
> with the scheme included if the user didn't mention the scheme
> (`scheme://[authority]/path`).

The majority of the changes are to move target computation from
ManagedChannelImpl into the builder. A small hack API was added to
ManagedChannelBuilder to get the target to create an interceptor.
This commit is contained in:
Eric Anderson 2024-05-05 10:47:16 -07:00
parent affa470252
commit 952ac022ee
10 changed files with 262 additions and 111 deletions

View File

@ -94,6 +94,12 @@ public abstract class ForwardingChannelBuilder2<T extends ManagedChannelBuilder<
return thisT();
}
@Override
protected T interceptWithTarget(InterceptorFactory factory) {
delegate().interceptWithTarget(factory);
return thisT();
}
@Override
public T addTransportFilter(ClientTransportFilter transportFilter) {
delegate().addTransportFilter(transportFilter);

View File

@ -0,0 +1,31 @@
/*
* Copyright 2024 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 accessors for {@link ManagedChannelBuilder}.
*/
public final class InternalManagedChannelBuilder {
private InternalManagedChannelBuilder() {}
public static <T extends ManagedChannelBuilder<T>> T interceptWithTarget(
ManagedChannelBuilder<T> builder, InternalInterceptorFactory factory) {
return builder.interceptWithTarget(factory);
}
public interface InternalInterceptorFactory extends ManagedChannelBuilder.InterceptorFactory {}
}

View File

@ -159,6 +159,21 @@ public abstract class ManagedChannelBuilder<T extends ManagedChannelBuilder<T>>
*/
public abstract T intercept(ClientInterceptor... interceptors);
/**
* Internal-only: Adds a factory that will construct an interceptor based on the channel's target.
* This can be used to work around nameResolverFactory() changing the target string.
*/
@Internal
protected T interceptWithTarget(InterceptorFactory factory) {
throw new UnsupportedOperationException();
}
/** Internal-only. */
@Internal
protected interface InterceptorFactory {
ClientInterceptor newInterceptor(String target);
}
/**
* Adds a {@link ClientTransportFilter}. The order of filters being added is the order they will
* be executed

View File

@ -93,9 +93,7 @@ import io.grpc.internal.ManagedChannelServiceConfig.ServiceConfigConvertedSelect
import io.grpc.internal.RetriableStream.ChannelBufferMeter;
import io.grpc.internal.RetriableStream.Throttle;
import io.grpc.internal.RetryingNameResolver.ResolutionResultListener;
import java.net.SocketAddress;
import java.net.URI;
import java.net.URISyntaxException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
@ -117,7 +115,6 @@ import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicReference;
import java.util.logging.Level;
import java.util.logging.Logger;
import java.util.regex.Pattern;
import javax.annotation.Nullable;
import javax.annotation.concurrent.GuardedBy;
import javax.annotation.concurrent.ThreadSafe;
@ -129,12 +126,6 @@ final class ManagedChannelImpl extends ManagedChannel implements
@VisibleForTesting
static final Logger logger = Logger.getLogger(ManagedChannelImpl.class.getName());
// Matching this pattern means the target string is a URI target or at least intended to be one.
// A URI target must be an absolute hierarchical URI.
// From RFC 2396: scheme = alpha *( alpha | digit | "+" | "-" | "." )
@VisibleForTesting
static final Pattern URI_PATTERN = Pattern.compile("[a-zA-Z][a-zA-Z0-9+.-]*:/.*");
static final long IDLE_TIMEOUT_MILLIS_DISABLE = -1;
static final long SUBCHANNEL_SHUTDOWN_DELAY_SECONDS = 5;
@ -595,6 +586,8 @@ final class ManagedChannelImpl extends ManagedChannel implements
ManagedChannelImpl(
ManagedChannelImplBuilder builder,
ClientTransportFactory clientTransportFactory,
URI targetUri,
NameResolverProvider nameResolverProvider,
BackoffPolicy.Provider backoffPolicyProvider,
ObjectPool<? extends Executor> balancerRpcExecutorPool,
Supplier<Stopwatch> stopwatchSupplier,
@ -625,10 +618,8 @@ final class ManagedChannelImpl extends ManagedChannel implements
this.retryEnabled = builder.retryEnabled;
this.loadBalancerFactory = new AutoConfiguredLoadBalancerFactory(builder.defaultLbPolicy);
this.nameResolverRegistry = builder.nameResolverRegistry;
ResolvedNameResolver resolvedResolver = getNameResolverProvider(
target, nameResolverRegistry, transportFactory.getSupportedSocketAddressTypes());
this.targetUri = resolvedResolver.targetUri;
this.nameResolverProvider = resolvedResolver.provider;
this.targetUri = checkNotNull(targetUri, "targetUri");
this.nameResolverProvider = checkNotNull(nameResolverProvider, "nameResolverProvider");
ScParser serviceConfigParser =
new ScParser(
retryEnabled,
@ -722,69 +713,6 @@ final class ManagedChannelImpl extends ManagedChannel implements
MetricInstrumentRegistry.getDefaultRegistry());
}
@VisibleForTesting
static class ResolvedNameResolver {
public final URI targetUri;
public final NameResolverProvider provider;
public ResolvedNameResolver(URI targetUri, NameResolverProvider provider) {
this.targetUri = checkNotNull(targetUri, "targetUri");
this.provider = checkNotNull(provider, "provider");
}
}
@VisibleForTesting
static ResolvedNameResolver getNameResolverProvider(
String target, NameResolverRegistry nameResolverRegistry,
Collection<Class<? extends SocketAddress>> channelTransportSocketAddressTypes) {
// Finding a NameResolver. Try using the target string as the URI. If that fails, try prepending
// "dns:///".
NameResolverProvider provider = null;
URI targetUri = null;
StringBuilder uriSyntaxErrors = new StringBuilder();
try {
targetUri = new URI(target);
} catch (URISyntaxException e) {
// Can happen with ip addresses like "[::1]:1234" or 127.0.0.1:1234.
uriSyntaxErrors.append(e.getMessage());
}
if (targetUri != null) {
// For "localhost:8080" this would likely cause provider to be null, because "localhost" is
// parsed as the scheme. Will hit the next case and try "dns:///localhost:8080".
provider = nameResolverRegistry.getProviderForScheme(targetUri.getScheme());
}
if (provider == null && !URI_PATTERN.matcher(target).matches()) {
// It doesn't look like a URI target. Maybe it's an authority string. Try with the default
// scheme from the registry.
try {
targetUri = new URI(nameResolverRegistry.getDefaultScheme(), "", "/" + target, null);
} catch (URISyntaxException e) {
// Should not be possible.
throw new IllegalArgumentException(e);
}
provider = nameResolverRegistry.getProviderForScheme(targetUri.getScheme());
}
if (provider == null) {
throw new IllegalArgumentException(String.format(
"Could not find a NameResolverProvider for %s%s",
target, uriSyntaxErrors.length() > 0 ? " (" + uriSyntaxErrors + ")" : ""));
}
if (channelTransportSocketAddressTypes != null) {
Collection<Class<? extends SocketAddress>> nameResolverSocketAddressTypes
= provider.getProducedSocketAddressTypes();
if (!channelTransportSocketAddressTypes.containsAll(nameResolverSocketAddressTypes)) {
throw new IllegalArgumentException(String.format(
"Address types of NameResolver '%s' for '%s' not supported by transport",
targetUri.getScheme(), target));
}
}
return new ResolvedNameResolver(targetUri, provider);
}
@VisibleForTesting
static NameResolver getNameResolver(
URI targetUri, @Nullable final String overrideAuthority,

View File

@ -26,7 +26,10 @@ import com.google.errorprone.annotations.DoNotCall;
import io.grpc.Attributes;
import io.grpc.BinaryLog;
import io.grpc.CallCredentials;
import io.grpc.CallOptions;
import io.grpc.Channel;
import io.grpc.ChannelCredentials;
import io.grpc.ClientCall;
import io.grpc.ClientInterceptor;
import io.grpc.ClientTransportFilter;
import io.grpc.CompressorRegistry;
@ -36,6 +39,7 @@ import io.grpc.InternalChannelz;
import io.grpc.InternalConfiguratorRegistry;
import io.grpc.ManagedChannel;
import io.grpc.ManagedChannelBuilder;
import io.grpc.MethodDescriptor;
import io.grpc.MetricSink;
import io.grpc.NameResolver;
import io.grpc.NameResolverProvider;
@ -57,6 +61,7 @@ import java.util.concurrent.Executor;
import java.util.concurrent.TimeUnit;
import java.util.logging.Level;
import java.util.logging.Logger;
import java.util.regex.Pattern;
import javax.annotation.Nullable;
/**
@ -109,6 +114,12 @@ public final class ManagedChannelImplBuilder
private static final long DEFAULT_RETRY_BUFFER_SIZE_IN_BYTES = 1L << 24; // 16M
private static final long DEFAULT_PER_RPC_BUFFER_LIMIT_IN_BYTES = 1L << 20; // 1M
// Matching this pattern means the target string is a URI target or at least intended to be one.
// A URI target must be an absolute hierarchical URI.
// From RFC 2396: scheme = alpha *( alpha | digit | "+" | "-" | "." )
@VisibleForTesting
static final Pattern URI_PATTERN = Pattern.compile("[a-zA-Z][a-zA-Z0-9+.-]*:/.*");
private static final Method GET_CLIENT_INTERCEPTOR_METHOD;
static {
@ -384,6 +395,14 @@ public final class ManagedChannelImplBuilder
return intercept(Arrays.asList(interceptors));
}
@Override
protected ManagedChannelImplBuilder interceptWithTarget(InterceptorFactory factory) {
// Add a placeholder instance to the interceptor list, and replace it with a real instance
// during build().
this.interceptors.add(new InterceptorFactoryWrapper(factory));
return this;
}
@Override
public ManagedChannelImplBuilder addTransportFilter(ClientTransportFilter hook) {
transportFilters.add(checkNotNull(hook, "transport filter"));
@ -675,13 +694,19 @@ public final class ManagedChannelImplBuilder
@Override
public ManagedChannel build() {
ClientTransportFactory clientTransportFactory =
clientTransportFactoryBuilder.buildClientTransportFactory();
ResolvedNameResolver resolvedResolver = getNameResolverProvider(
target, nameResolverRegistry, clientTransportFactory.getSupportedSocketAddressTypes());
return new ManagedChannelOrphanWrapper(new ManagedChannelImpl(
this,
clientTransportFactoryBuilder.buildClientTransportFactory(),
clientTransportFactory,
resolvedResolver.targetUri,
resolvedResolver.provider,
new ExponentialBackoffPolicy.Provider(),
SharedResourcePool.forResource(GrpcUtil.SHARED_CHANNEL_EXECUTOR),
GrpcUtil.STOPWATCH_SUPPLIER,
getEffectiveInterceptors(),
getEffectiveInterceptors(resolvedResolver.targetUri.toString()),
TimeProvider.SYSTEM_TIME_PROVIDER));
}
@ -689,12 +714,25 @@ public final class ManagedChannelImplBuilder
// what should be the desired behavior for retry + stats/tracing.
// TODO(zdapeng): FIX IT
@VisibleForTesting
List<ClientInterceptor> getEffectiveInterceptors() {
List<ClientInterceptor> getEffectiveInterceptors(String computedTarget) {
List<ClientInterceptor> effectiveInterceptors = new ArrayList<>(this.interceptors);
for (int i = 0; i < effectiveInterceptors.size(); i++) {
if (!(effectiveInterceptors.get(i) instanceof InterceptorFactoryWrapper)) {
continue;
}
InterceptorFactory factory =
((InterceptorFactoryWrapper) effectiveInterceptors.get(i)).factory;
ClientInterceptor interceptor = factory.newInterceptor(computedTarget);
if (interceptor == null) {
throw new NullPointerException("Factory returned null interceptor: " + factory);
}
effectiveInterceptors.set(i, interceptor);
}
boolean disableImplicitCensus = InternalConfiguratorRegistry.wasSetConfiguratorsCalled();
if (disableImplicitCensus) {
return this.interceptors;
return effectiveInterceptors;
}
List<ClientInterceptor> effectiveInterceptors = new ArrayList<>(this.interceptors);
if (statsEnabled) {
ClientInterceptor statsInterceptor = null;
@ -754,6 +792,69 @@ public final class ManagedChannelImplBuilder
return channelBuilderDefaultPortProvider.getDefaultPort();
}
@VisibleForTesting
static class ResolvedNameResolver {
public final URI targetUri;
public final NameResolverProvider provider;
public ResolvedNameResolver(URI targetUri, NameResolverProvider provider) {
this.targetUri = checkNotNull(targetUri, "targetUri");
this.provider = checkNotNull(provider, "provider");
}
}
@VisibleForTesting
static ResolvedNameResolver getNameResolverProvider(
String target, NameResolverRegistry nameResolverRegistry,
Collection<Class<? extends SocketAddress>> channelTransportSocketAddressTypes) {
// Finding a NameResolver. Try using the target string as the URI. If that fails, try prepending
// "dns:///".
NameResolverProvider provider = null;
URI targetUri = null;
StringBuilder uriSyntaxErrors = new StringBuilder();
try {
targetUri = new URI(target);
} catch (URISyntaxException e) {
// Can happen with ip addresses like "[::1]:1234" or 127.0.0.1:1234.
uriSyntaxErrors.append(e.getMessage());
}
if (targetUri != null) {
// For "localhost:8080" this would likely cause provider to be null, because "localhost" is
// parsed as the scheme. Will hit the next case and try "dns:///localhost:8080".
provider = nameResolverRegistry.getProviderForScheme(targetUri.getScheme());
}
if (provider == null && !URI_PATTERN.matcher(target).matches()) {
// It doesn't look like a URI target. Maybe it's an authority string. Try with the default
// scheme from the registry.
try {
targetUri = new URI(nameResolverRegistry.getDefaultScheme(), "", "/" + target, null);
} catch (URISyntaxException e) {
// Should not be possible.
throw new IllegalArgumentException(e);
}
provider = nameResolverRegistry.getProviderForScheme(targetUri.getScheme());
}
if (provider == null) {
throw new IllegalArgumentException(String.format(
"Could not find a NameResolverProvider for %s%s",
target, uriSyntaxErrors.length() > 0 ? " (" + uriSyntaxErrors + ")" : ""));
}
if (channelTransportSocketAddressTypes != null) {
Collection<Class<? extends SocketAddress>> nameResolverSocketAddressTypes
= provider.getProducedSocketAddressTypes();
if (!channelTransportSocketAddressTypes.containsAll(nameResolverSocketAddressTypes)) {
throw new IllegalArgumentException(String.format(
"Address types of NameResolver '%s' for '%s' not supported by transport",
targetUri.getScheme(), target));
}
}
return new ResolvedNameResolver(targetUri, provider);
}
private static class DirectAddressNameResolverProvider extends NameResolverProvider {
final SocketAddress address;
final String authority;
@ -809,6 +910,20 @@ public final class ManagedChannelImplBuilder
}
}
private static final class InterceptorFactoryWrapper implements ClientInterceptor {
final InterceptorFactory factory;
public InterceptorFactoryWrapper(InterceptorFactory factory) {
this.factory = checkNotNull(factory, "factory");
}
@Override
public <ReqT, RespT> ClientCall<ReqT, RespT> interceptCall(
MethodDescriptor<ReqT, RespT> method, CallOptions callOptions, Channel next) {
throw new AssertionError("Should have been replaced with real instance");
}
}
/**
* Returns the internal offload executor pool for offloading tasks.
*/

View File

@ -38,6 +38,7 @@ import io.grpc.CompressorRegistry;
import io.grpc.DecompressorRegistry;
import io.grpc.InternalConfigurator;
import io.grpc.InternalConfiguratorRegistry;
import io.grpc.InternalManagedChannelBuilder.InternalInterceptorFactory;
import io.grpc.ManagedChannel;
import io.grpc.ManagedChannelBuilder;
import io.grpc.MethodDescriptor;
@ -473,7 +474,7 @@ public class ManagedChannelImplBuilderTest {
@Test
public void getEffectiveInterceptors_default() {
builder.intercept(DUMMY_USER_INTERCEPTOR);
List<ClientInterceptor> effectiveInterceptors = builder.getEffectiveInterceptors();
List<ClientInterceptor> effectiveInterceptors = builder.getEffectiveInterceptors("unused:///");
assertEquals(3, effectiveInterceptors.size());
assertThat(effectiveInterceptors.get(0).getClass().getName())
.isEqualTo("io.grpc.census.CensusTracingModule$TracingClientInterceptor");
@ -486,7 +487,7 @@ public class ManagedChannelImplBuilderTest {
public void getEffectiveInterceptors_disableStats() {
builder.intercept(DUMMY_USER_INTERCEPTOR);
builder.setStatsEnabled(false);
List<ClientInterceptor> effectiveInterceptors = builder.getEffectiveInterceptors();
List<ClientInterceptor> effectiveInterceptors = builder.getEffectiveInterceptors("unused:///");
assertEquals(2, effectiveInterceptors.size());
assertThat(effectiveInterceptors.get(0).getClass().getName())
.isEqualTo("io.grpc.census.CensusTracingModule$TracingClientInterceptor");
@ -497,7 +498,7 @@ public class ManagedChannelImplBuilderTest {
public void getEffectiveInterceptors_disableTracing() {
builder.intercept(DUMMY_USER_INTERCEPTOR);
builder.setTracingEnabled(false);
List<ClientInterceptor> effectiveInterceptors = builder.getEffectiveInterceptors();
List<ClientInterceptor> effectiveInterceptors = builder.getEffectiveInterceptors("unused:///");
assertEquals(2, effectiveInterceptors.size());
assertThat(effectiveInterceptors.get(0).getClass().getName())
.isEqualTo("io.grpc.census.CensusStatsModule$StatsClientInterceptor");
@ -509,7 +510,7 @@ public class ManagedChannelImplBuilderTest {
builder.intercept(DUMMY_USER_INTERCEPTOR);
builder.setStatsEnabled(false);
builder.setTracingEnabled(false);
List<ClientInterceptor> effectiveInterceptors = builder.getEffectiveInterceptors();
List<ClientInterceptor> effectiveInterceptors = builder.getEffectiveInterceptors("unused:///");
assertThat(effectiveInterceptors).containsExactly(DUMMY_USER_INTERCEPTOR);
}
@ -529,7 +530,8 @@ public class ManagedChannelImplBuilderTest {
DUMMY_TARGET,
new UnsupportedClientTransportFactoryBuilder(),
new FixedPortProvider(DUMMY_PORT));
List<ClientInterceptor> effectiveInterceptors = builder.getEffectiveInterceptors();
List<ClientInterceptor> effectiveInterceptors =
builder.getEffectiveInterceptors("unused:///");
assertThat(effectiveInterceptors).hasSize(2);
try {
InternalConfiguratorRegistry.setConfigurators(Collections.emptyList());
@ -563,7 +565,8 @@ public class ManagedChannelImplBuilderTest {
DUMMY_TARGET,
new UnsupportedClientTransportFactoryBuilder(),
new FixedPortProvider(DUMMY_PORT));
List<ClientInterceptor> effectiveInterceptors = builder.getEffectiveInterceptors();
List<ClientInterceptor> effectiveInterceptors =
builder.getEffectiveInterceptors("unused:///");
assertThat(effectiveInterceptors)
.containsExactly(DUMMY_USER_INTERCEPTOR, DUMMY_USER_INTERCEPTOR1);
}
@ -587,11 +590,35 @@ public class ManagedChannelImplBuilderTest {
DUMMY_TARGET,
new UnsupportedClientTransportFactoryBuilder(),
new FixedPortProvider(DUMMY_PORT));
List<ClientInterceptor> effectiveInterceptors = builder.getEffectiveInterceptors();
List<ClientInterceptor> effectiveInterceptors =
builder.getEffectiveInterceptors("unused:///");
assertThat(effectiveInterceptors).isEmpty();
}
}
@Test
public void getEffectiveInterceptors_createsFromInterceptorFactories() throws Exception {
String target = "dns:///the-host";
builder.setStatsEnabled(false);
builder.setTracingEnabled(false);
builder.intercept(DUMMY_USER_INTERCEPTOR)
.interceptWithTarget(new InternalInterceptorFactory() {
@Override
public ClientInterceptor newInterceptor(String passedTarget) {
assertThat(passedTarget).isEqualTo(target);
return DUMMY_USER_INTERCEPTOR1;
}
})
.intercept(DUMMY_USER_INTERCEPTOR);
assertThat(builder.getEffectiveInterceptors(target))
.isEqualTo(Arrays.asList(
DUMMY_USER_INTERCEPTOR,
DUMMY_USER_INTERCEPTOR1,
DUMMY_USER_INTERCEPTOR));
}
@Test
public void idleTimeout() {
assertEquals(ManagedChannelImplBuilder.IDLE_MODE_DEFAULT_TIMEOUT_MILLIS,
@ -744,4 +771,15 @@ public class ManagedChannelImplBuilderTest {
assertThat(builder.metricSinks).contains(mocksink);
}
@Test
public void uriPattern() {
Pattern uriPattern = ManagedChannelImplBuilder.URI_PATTERN;
assertTrue(uriPattern.matcher("a:/").matches());
assertTrue(uriPattern.matcher("Z019+-.:/!@ #~ ").matches());
assertFalse(uriPattern.matcher("a/:").matches()); // "/:" not matched
assertFalse(uriPattern.matcher("0a:/").matches()); // '0' not matched
assertFalse(uriPattern.matcher("a,:/").matches()); // ',' not matched
assertFalse(uriPattern.matcher(" a:/").matches()); // space not matched
}
}

View File

@ -30,7 +30,7 @@ import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.JUnit4;
/** Unit tests for ManagedChannelImpl#getNameResolverProvider(). */
/** Unit tests for ManagedChannelImplBuilder#getNameResolverProvider(). */
@RunWith(JUnit4.class)
public class ManagedChannelImplGetNameResolverTest {
@Test
@ -95,7 +95,7 @@ public class ManagedChannelImplGetNameResolverTest {
public void validTargetNoProvider() {
NameResolverRegistry nameResolverRegistry = new NameResolverRegistry();
try {
ManagedChannelImpl.getNameResolverProvider(
ManagedChannelImplBuilder.getNameResolverProvider(
"foo.googleapis.com:8080", nameResolverRegistry,
Collections.singleton(InetSocketAddress.class));
fail("Should fail");
@ -108,7 +108,7 @@ public class ManagedChannelImplGetNameResolverTest {
public void validTargetProviderAddrTypesNotSupported() {
NameResolverRegistry nameResolverRegistry = getTestRegistry("testscheme");
try {
ManagedChannelImpl.getNameResolverProvider(
ManagedChannelImplBuilder.getNameResolverProvider(
"testscheme:///foo.googleapis.com:8080", nameResolverRegistry,
Collections.singleton(InProcessSocketAddress.class));
fail("Should fail");
@ -121,7 +121,8 @@ public class ManagedChannelImplGetNameResolverTest {
private void testValidTarget(String target, String expectedUriString, URI expectedUri) {
NameResolverRegistry nameResolverRegistry = getTestRegistry(expectedUri.getScheme());
ManagedChannelImpl.ResolvedNameResolver resolved = ManagedChannelImpl.getNameResolverProvider(
ManagedChannelImplBuilder.ResolvedNameResolver resolved =
ManagedChannelImplBuilder.getNameResolverProvider(
target, nameResolverRegistry, Collections.singleton(InetSocketAddress.class));
assertThat(resolved.provider).isInstanceOf(FakeNameResolverProvider.class);
assertThat(resolved.targetUri).isEqualTo(expectedUri);
@ -132,7 +133,8 @@ public class ManagedChannelImplGetNameResolverTest {
NameResolverRegistry nameResolverRegistry = getTestRegistry("dns");
try {
ManagedChannelImpl.ResolvedNameResolver resolved = ManagedChannelImpl.getNameResolverProvider(
ManagedChannelImplBuilder.ResolvedNameResolver resolved =
ManagedChannelImplBuilder.getNameResolverProvider(
target, nameResolverRegistry, Collections.singleton(InetSocketAddress.class));
FakeNameResolverProvider nameResolverProvider = (FakeNameResolverProvider) resolved.provider;
fail("Should have failed, but got resolver provider " + nameResolverProvider);

View File

@ -61,6 +61,7 @@ import io.grpc.MethodDescriptor;
import io.grpc.MethodDescriptor.MethodType;
import io.grpc.NameResolver;
import io.grpc.NameResolver.ResolutionResult;
import io.grpc.NameResolverProvider;
import io.grpc.Status;
import io.grpc.StringMarshaller;
import io.grpc.internal.FakeClock.ScheduledTask;
@ -169,7 +170,9 @@ public class ManagedChannelImplIdlenessTest {
when(mockTransportFactory.getSupportedSocketAddressTypes())
.thenReturn(Collections.singleton(InetSocketAddress.class));
ManagedChannelImplBuilder builder = new ManagedChannelImplBuilder("mockscheme:///target",
String target = "mockscheme:///target";
URI targetUri = URI.create(target);
ManagedChannelImplBuilder builder = new ManagedChannelImplBuilder(target,
new UnsupportedClientTransportFactoryBuilder(), null);
builder
@ -178,8 +181,11 @@ public class ManagedChannelImplIdlenessTest {
.idleTimeout(IDLE_TIMEOUT_SECONDS, TimeUnit.SECONDS)
.userAgent(USER_AGENT);
builder.executorPool = executorPool;
NameResolverProvider nameResolverProvider =
builder.nameResolverRegistry.getProviderForScheme(targetUri.getScheme());
channel = new ManagedChannelImpl(
builder, mockTransportFactory, new FakeBackoffPolicyProvider(),
builder, mockTransportFactory, targetUri, nameResolverProvider,
new FakeBackoffPolicyProvider(),
oobExecutorPool, timer.getStopwatchSupplier(),
Collections.<ClientInterceptor>emptyList(),
TimeProvider.SYSTEM_TIME_PROVIDER);

View File

@ -310,8 +310,11 @@ public class ManagedChannelImplTest {
when(mockTransportFactory.getSupportedSocketAddressTypes()).thenReturn(Collections.singleton(
InetSocketAddress.class));
NameResolverProvider nameResolverProvider =
channelBuilder.nameResolverRegistry.getProviderForScheme(expectedUri.getScheme());
channel = new ManagedChannelImpl(
channelBuilder, mockTransportFactory, new FakeBackoffPolicyProvider(),
channelBuilder, mockTransportFactory, expectedUri, nameResolverProvider,
new FakeBackoffPolicyProvider(),
balancerRpcExecutorPool, timer.getStopwatchSupplier(), Arrays.asList(interceptors),
timer.getTimeProvider());
@ -499,7 +502,8 @@ public class ManagedChannelImplTest {
when(mockTransportFactory.getSupportedSocketAddressTypes()).thenReturn(Collections.singleton(
InetSocketAddress.class));
channel = new ManagedChannelImpl(
channelBuilder, mockTransportFactory, new FakeBackoffPolicyProvider(),
channelBuilder, mockTransportFactory, expectedUri, nameResolverFactory,
new FakeBackoffPolicyProvider(),
balancerRpcExecutorPool, timer.getStopwatchSupplier(),
Collections.<ClientInterceptor>emptyList(), timer.getTimeProvider());
Map<String, Object> rawServiceConfig =
@ -563,7 +567,8 @@ public class ManagedChannelImplTest {
when(mockTransportFactory.getSupportedSocketAddressTypes()).thenReturn(Collections.singleton(
InetSocketAddress.class));
channel = new ManagedChannelImpl(
channelBuilder, mockTransportFactory, new FakeBackoffPolicyProvider(),
channelBuilder, mockTransportFactory, expectedUri, nameResolverFactory,
new FakeBackoffPolicyProvider(),
balancerRpcExecutorPool, timer.getStopwatchSupplier(),
Collections.<ClientInterceptor>emptyList(), timer.getTimeProvider());
nameResolverFactory.nextConfigOrError.set(
@ -2181,16 +2186,6 @@ public class ManagedChannelImplTest {
assertEquals(expectedRefreshCount, resolver.refreshCalled);
}
@Test
public void uriPattern() {
assertTrue(ManagedChannelImpl.URI_PATTERN.matcher("a:/").matches());
assertTrue(ManagedChannelImpl.URI_PATTERN.matcher("Z019+-.:/!@ #~ ").matches());
assertFalse(ManagedChannelImpl.URI_PATTERN.matcher("a/:").matches()); // "/:" not matched
assertFalse(ManagedChannelImpl.URI_PATTERN.matcher("0a:/").matches()); // '0' not matched
assertFalse(ManagedChannelImpl.URI_PATTERN.matcher("a,:/").matches()); // ',' not matched
assertFalse(ManagedChannelImpl.URI_PATTERN.matcher(" a:/").matches()); // space not matched
}
/**
* Test that information such as the Call's context, MethodDescriptor, authority, executor are
* propagated to newStream() and applyRequestMetadata().
@ -4429,7 +4424,7 @@ public class ManagedChannelImplTest {
}
}
private static final class FakeNameResolverFactory extends NameResolver.Factory {
private static final class FakeNameResolverFactory extends NameResolverProvider {
final List<URI> expectedUris;
final List<EquivalentAddressGroup> servers;
final boolean resolvedAtStart;
@ -4466,6 +4461,16 @@ public class ManagedChannelImplTest {
return "fake";
}
@Override
public int priority() {
return 9;
}
@Override
public boolean isAvailable() {
return true;
}
void allResolved() {
for (FakeNameResolverFactory.FakeNameResolver resolver : resolvers) {
resolver.resolved();

View File

@ -45,6 +45,7 @@ import io.grpc.LoadBalancerProvider;
import io.grpc.LoadBalancerRegistry;
import io.grpc.NameResolver;
import io.grpc.NameResolver.ConfigOrError;
import io.grpc.NameResolverProvider;
import io.grpc.Status;
import io.grpc.internal.ManagedChannelImplBuilder.FixedPortProvider;
import io.grpc.internal.ManagedChannelImplBuilder.UnsupportedClientTransportFactoryBuilder;
@ -161,10 +162,14 @@ public class ServiceConfigErrorHandlingTest {
when(mockTransportFactory.getSupportedSocketAddressTypes()).thenReturn(Collections.singleton(
InetSocketAddress.class));
NameResolverProvider nameResolverProvider =
channelBuilder.nameResolverRegistry.getProviderForScheme(expectedUri.getScheme());
channel =
new ManagedChannelImpl(
channelBuilder,
mockTransportFactory,
expectedUri,
nameResolverProvider,
new FakeBackoffPolicyProvider(),
balancerRpcExecutorPool,
timer.getStopwatchSupplier(),