diff --git a/api/src/main/java/io/grpc/ForwardingChannelBuilder2.java b/api/src/main/java/io/grpc/ForwardingChannelBuilder2.java index cc001ae244..a34dea3645 100644 --- a/api/src/main/java/io/grpc/ForwardingChannelBuilder2.java +++ b/api/src/main/java/io/grpc/ForwardingChannelBuilder2.java @@ -94,6 +94,12 @@ public abstract class ForwardingChannelBuilder2> T interceptWithTarget( + ManagedChannelBuilder builder, InternalInterceptorFactory factory) { + return builder.interceptWithTarget(factory); + } + + public interface InternalInterceptorFactory extends ManagedChannelBuilder.InterceptorFactory {} +} diff --git a/api/src/main/java/io/grpc/ManagedChannelBuilder.java b/api/src/main/java/io/grpc/ManagedChannelBuilder.java index caaf4dcfdc..9f8e5479ad 100644 --- a/api/src/main/java/io/grpc/ManagedChannelBuilder.java +++ b/api/src/main/java/io/grpc/ManagedChannelBuilder.java @@ -159,6 +159,21 @@ public abstract class ManagedChannelBuilder> */ 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 diff --git a/core/src/main/java/io/grpc/internal/ManagedChannelImpl.java b/core/src/main/java/io/grpc/internal/ManagedChannelImpl.java index eeb769291d..d908e6bd80 100644 --- a/core/src/main/java/io/grpc/internal/ManagedChannelImpl.java +++ b/core/src/main/java/io/grpc/internal/ManagedChannelImpl.java @@ -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 balancerRpcExecutorPool, Supplier 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> 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> 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, diff --git a/core/src/main/java/io/grpc/internal/ManagedChannelImplBuilder.java b/core/src/main/java/io/grpc/internal/ManagedChannelImplBuilder.java index b787d76643..b12fd43d36 100644 --- a/core/src/main/java/io/grpc/internal/ManagedChannelImplBuilder.java +++ b/core/src/main/java/io/grpc/internal/ManagedChannelImplBuilder.java @@ -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 getEffectiveInterceptors() { + List getEffectiveInterceptors(String computedTarget) { + List 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 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> 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> 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 ClientCall interceptCall( + MethodDescriptor method, CallOptions callOptions, Channel next) { + throw new AssertionError("Should have been replaced with real instance"); + } + } + /** * Returns the internal offload executor pool for offloading tasks. */ diff --git a/core/src/test/java/io/grpc/internal/ManagedChannelImplBuilderTest.java b/core/src/test/java/io/grpc/internal/ManagedChannelImplBuilderTest.java index bebf5e3d23..d6ae0a532b 100644 --- a/core/src/test/java/io/grpc/internal/ManagedChannelImplBuilderTest.java +++ b/core/src/test/java/io/grpc/internal/ManagedChannelImplBuilderTest.java @@ -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 effectiveInterceptors = builder.getEffectiveInterceptors(); + List 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 effectiveInterceptors = builder.getEffectiveInterceptors(); + List 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 effectiveInterceptors = builder.getEffectiveInterceptors(); + List 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 effectiveInterceptors = builder.getEffectiveInterceptors(); + List 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 effectiveInterceptors = builder.getEffectiveInterceptors(); + List 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 effectiveInterceptors = builder.getEffectiveInterceptors(); + List 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 effectiveInterceptors = builder.getEffectiveInterceptors(); + List 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 + } } diff --git a/core/src/test/java/io/grpc/internal/ManagedChannelImplGetNameResolverTest.java b/core/src/test/java/io/grpc/internal/ManagedChannelImplGetNameResolverTest.java index d930045a13..98300bc82f 100644 --- a/core/src/test/java/io/grpc/internal/ManagedChannelImplGetNameResolverTest.java +++ b/core/src/test/java/io/grpc/internal/ManagedChannelImplGetNameResolverTest.java @@ -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,8 +121,9 @@ public class ManagedChannelImplGetNameResolverTest { private void testValidTarget(String target, String expectedUriString, URI expectedUri) { NameResolverRegistry nameResolverRegistry = getTestRegistry(expectedUri.getScheme()); - ManagedChannelImpl.ResolvedNameResolver resolved = ManagedChannelImpl.getNameResolverProvider( - target, nameResolverRegistry, Collections.singleton(InetSocketAddress.class)); + ManagedChannelImplBuilder.ResolvedNameResolver resolved = + ManagedChannelImplBuilder.getNameResolverProvider( + target, nameResolverRegistry, Collections.singleton(InetSocketAddress.class)); assertThat(resolved.provider).isInstanceOf(FakeNameResolverProvider.class); assertThat(resolved.targetUri).isEqualTo(expectedUri); assertThat(resolved.targetUri.toString()).isEqualTo(expectedUriString); @@ -132,8 +133,9 @@ public class ManagedChannelImplGetNameResolverTest { NameResolverRegistry nameResolverRegistry = getTestRegistry("dns"); try { - ManagedChannelImpl.ResolvedNameResolver resolved = ManagedChannelImpl.getNameResolverProvider( - target, nameResolverRegistry, Collections.singleton(InetSocketAddress.class)); + 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); } catch (IllegalArgumentException e) { diff --git a/core/src/test/java/io/grpc/internal/ManagedChannelImplIdlenessTest.java b/core/src/test/java/io/grpc/internal/ManagedChannelImplIdlenessTest.java index e50eeaf768..90008c1be3 100644 --- a/core/src/test/java/io/grpc/internal/ManagedChannelImplIdlenessTest.java +++ b/core/src/test/java/io/grpc/internal/ManagedChannelImplIdlenessTest.java @@ -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.emptyList(), TimeProvider.SYSTEM_TIME_PROVIDER); diff --git a/core/src/test/java/io/grpc/internal/ManagedChannelImplTest.java b/core/src/test/java/io/grpc/internal/ManagedChannelImplTest.java index 6cd88001f8..2b598db1cf 100644 --- a/core/src/test/java/io/grpc/internal/ManagedChannelImplTest.java +++ b/core/src/test/java/io/grpc/internal/ManagedChannelImplTest.java @@ -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.emptyList(), timer.getTimeProvider()); Map 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.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 expectedUris; final List 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(); diff --git a/core/src/test/java/io/grpc/internal/ServiceConfigErrorHandlingTest.java b/core/src/test/java/io/grpc/internal/ServiceConfigErrorHandlingTest.java index 697b55c902..6f255763d3 100644 --- a/core/src/test/java/io/grpc/internal/ServiceConfigErrorHandlingTest.java +++ b/core/src/test/java/io/grpc/internal/ServiceConfigErrorHandlingTest.java @@ -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(),