aboutsummaryrefslogtreecommitdiff
path: root/core
diff options
context:
space:
mode:
authorKun Zhang <zhangkun83@users.noreply.github.com>2018-10-10 21:45:56 -0700
committerGitHub <noreply@github.com>2018-10-10 21:45:56 -0700
commit861f9147ed13e3956fe27b2a86288063558c2e94 (patch)
tree1b58b07fce7815db541aafa335a12dfc246c0691 /core
parent4ce9c0492d0d03731d7ab8023f95ea562ee0d5e2 (diff)
downloadgrpc-grpc-java-861f9147ed13e3956fe27b2a86288063558c2e94.tar.gz
core: add CallCredentials2 and deprecate CallCredentials' old interface (#4902)
This is the first step of smoothly changing the CallCredentials API. Security level and authority are parameters required to be passed to applyRequestMetadata(). This change wraps them, along with MethodDescriptor and the transport attributes to RequestInfo, which is more clear to the implementers. ATTR_SECURITY_LEVEL is moved to the internal GrpcAttributes and annotated as TransportAttr, because transports are required to set it, but no user is actually reading them from {Client,Server}Call.getAttributes(). ATTR_AUTHORITY is removed, because no transport is overriding it. All involved interfaces are changed to abstract classes, as this will make further API changes smoother. The CallCredentials name is stabilized, thus we first introduce CallCredentials2, ask CallCredentials implementations to migrate to it, while GRPC accepting both at the same time, then replace CallCredentials with CallCredentials2.
Diffstat (limited to 'core')
-rw-r--r--core/src/main/java/io/grpc/CallCredentials.java43
-rw-r--r--core/src/main/java/io/grpc/CallCredentials2.java84
-rw-r--r--core/src/main/java/io/grpc/inprocess/InProcessTransport.java4
-rw-r--r--core/src/main/java/io/grpc/internal/CallCredentialsApplyingTransportFactory.java1
-rw-r--r--core/src/main/java/io/grpc/internal/GrpcAttributes.java11
-rw-r--r--core/src/main/java/io/grpc/internal/MetadataApplierImpl.java2
-rw-r--r--core/src/test/java/io/grpc/internal/CallCredentials2ApplyingTest.java291
-rw-r--r--core/src/test/java/io/grpc/internal/CallCredentialsApplyingTest.java1
-rw-r--r--core/src/test/java/io/grpc/internal/ManagedChannelImplTest.java3
9 files changed, 432 insertions, 8 deletions
diff --git a/core/src/main/java/io/grpc/CallCredentials.java b/core/src/main/java/io/grpc/CallCredentials.java
index 0d87bb610..2bc4b2876 100644
--- a/core/src/main/java/io/grpc/CallCredentials.java
+++ b/core/src/main/java/io/grpc/CallCredentials.java
@@ -40,11 +40,15 @@ public interface CallCredentials {
* The security level of the transport. It is guaranteed to be present in the {@code attrs} passed
* to {@link #applyRequestMetadata}. It is by default {@link SecurityLevel#NONE} but can be
* overridden by the transport.
+ *
+ * @deprecated transport implementations should use {@code
+ * io.grpc.internal.GrpcAttributes.ATTR_SECURITY_LEVEL} instead.
*/
@ExperimentalApi("https://github.com/grpc/grpc-java/issues/1914")
@Grpc.TransportAttr
+ @Deprecated
public static final Key<SecurityLevel> ATTR_SECURITY_LEVEL =
- Key.create("io.grpc.CallCredentials.securityLevel");
+ Key.create("io.grpc.internal.GrpcAttributes.securityLevel");
/**
* The authority string used to authenticate the server. Usually it's the server's host name. It
@@ -54,6 +58,7 @@ public interface CallCredentials {
*/
@ExperimentalApi("https://github.com/grpc/grpc-java/issues/1914")
@Grpc.TransportAttr
+ @Deprecated
public static final Key<String> ATTR_AUTHORITY = Key.create("io.grpc.CallCredentials.authority");
/**
@@ -73,8 +78,11 @@ public interface CallCredentials {
* needs to perform blocking operations.
* @param applier The outlet of the produced headers. It can be called either before or after this
* method returns.
+ *
+ * @deprecated implement {@link CallCredentials2} instead.
*/
@ExperimentalApi("https://github.com/grpc/grpc-java/issues/1914")
+ @Deprecated
void applyRequestMetadata(
MethodDescriptor<?, ?> method, Attributes attrs,
Executor appExecutor, MetadataApplier applier);
@@ -92,16 +100,43 @@ public interface CallCredentials {
* <p>Exactly one of its methods must be called to make the RPC proceed.
*/
@ExperimentalApi("https://github.com/grpc/grpc-java/issues/1914")
- public interface MetadataApplier {
+ public abstract static class MetadataApplier {
/**
* Called when headers are successfully generated. They will be merged into the original
* headers.
*/
- void apply(Metadata headers);
+ public abstract void apply(Metadata headers);
/**
* Called when there has been an error when preparing the headers. This will fail the RPC.
*/
- void fail(Status status);
+ public abstract void fail(Status status);
+ }
+
+ /**
+ * The request-related information passed to {@code CallCredentials2.applyRequestMetadata()}.
+ */
+ @ExperimentalApi("https://github.com/grpc/grpc-java/issues/1914")
+ public abstract static class RequestInfo {
+ /**
+ * The method descriptor of this RPC.
+ */
+ public abstract MethodDescriptor<?, ?> getMethodDescriptor();
+
+ /**
+ * The security level on the transport.
+ */
+ public abstract SecurityLevel getSecurityLevel();
+
+ /**
+ * Returns the authority string used to authenticate the server for this call.
+ */
+ public abstract String getAuthority();
+
+ /**
+ * Returns the transport attributes.
+ */
+ @Grpc.TransportAttr
+ public abstract Attributes getTransportAttrs();
}
}
diff --git a/core/src/main/java/io/grpc/CallCredentials2.java b/core/src/main/java/io/grpc/CallCredentials2.java
new file mode 100644
index 000000000..458a04c9f
--- /dev/null
+++ b/core/src/main/java/io/grpc/CallCredentials2.java
@@ -0,0 +1,84 @@
+/*
+ * Copyright 2016 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;
+
+import static com.google.common.base.MoreObjects.firstNonNull;
+import static com.google.common.base.Preconditions.checkNotNull;
+
+import java.util.concurrent.Executor;
+
+/**
+ * The new interface for {@link CallCredentials}.
+ *
+ * <p>THIS CLASS NAME IS TEMPORARY and is part of a migration. This class will BE DELETED as it
+ * replaces {@link CallCredentials} in short-term. THIS CLASS SHOULD ONLY BE REFERENCED BY
+ * IMPLEMENTIONS. All consumers should still reference {@link CallCredentials}.
+ */
+@ExperimentalApi("https://github.com/grpc/grpc-java/issues/4901")
+public abstract class CallCredentials2 implements CallCredentials {
+ /**
+ * Pass the credential data to the given {@link CallCredentials.MetadataApplier}, which will
+ * propagate it to the request metadata.
+ *
+ * <p>It is called for each individual RPC, within the {@link Context} of the call, before the
+ * stream is about to be created on a transport. Implementations should not block in this
+ * method. If metadata is not immediately available, e.g., needs to be fetched from network, the
+ * implementation may give the {@code applier} to an asynchronous task which will eventually call
+ * the {@code applier}. The RPC proceeds only after the {@code applier} is called.
+ *
+ * @param requestInfo request-related information
+ * @param appExecutor The application thread-pool. It is provided to the implementation in case it
+ * needs to perform blocking operations.
+ * @param applier The outlet of the produced headers. It can be called either before or after this
+ * method returns.
+ */
+ @ExperimentalApi("https://github.com/grpc/grpc-java/issues/1914")
+ public abstract void applyRequestMetadata(
+ RequestInfo requestInfo, Executor appExecutor, MetadataApplier applier);
+
+ @Override
+ @SuppressWarnings("deprecation")
+ public final void applyRequestMetadata(
+ final MethodDescriptor<?, ?> method, final Attributes attrs,
+ Executor appExecutor, CallCredentials.MetadataApplier applier) {
+ final String authority = checkNotNull(attrs.get(ATTR_AUTHORITY), "authority");
+ final SecurityLevel securityLevel =
+ firstNonNull(attrs.get(ATTR_SECURITY_LEVEL), SecurityLevel.NONE);
+ RequestInfo requestInfo = new RequestInfo() {
+ @Override
+ public MethodDescriptor<?, ?> getMethodDescriptor() {
+ return method;
+ }
+
+ @Override
+ public SecurityLevel getSecurityLevel() {
+ return securityLevel;
+ }
+
+ @Override
+ public String getAuthority() {
+ return authority;
+ }
+
+ @Override
+ public Attributes getTransportAttrs() {
+ return attrs;
+ }
+ };
+ applyRequestMetadata(requestInfo, appExecutor, applier);
+ }
+}
diff --git a/core/src/main/java/io/grpc/inprocess/InProcessTransport.java b/core/src/main/java/io/grpc/inprocess/InProcessTransport.java
index b10a46a25..03e2e1a19 100644
--- a/core/src/main/java/io/grpc/inprocess/InProcessTransport.java
+++ b/core/src/main/java/io/grpc/inprocess/InProcessTransport.java
@@ -24,7 +24,6 @@ import com.google.common.base.MoreObjects;
import com.google.common.util.concurrent.ListenableFuture;
import com.google.common.util.concurrent.SettableFuture;
import io.grpc.Attributes;
-import io.grpc.CallCredentials;
import io.grpc.CallOptions;
import io.grpc.Compressor;
import io.grpc.Deadline;
@@ -41,6 +40,7 @@ import io.grpc.Status;
import io.grpc.internal.ClientStream;
import io.grpc.internal.ClientStreamListener;
import io.grpc.internal.ConnectionClientTransport;
+import io.grpc.internal.GrpcAttributes;
import io.grpc.internal.GrpcUtil;
import io.grpc.internal.ManagedClientTransport;
import io.grpc.internal.NoopClientStream;
@@ -91,7 +91,7 @@ final class InProcessTransport implements ServerTransport, ConnectionClientTrans
@GuardedBy("this")
private List<ServerStreamTracer.Factory> serverStreamTracerFactories;
private final Attributes attributes = Attributes.newBuilder()
- .set(CallCredentials.ATTR_SECURITY_LEVEL, SecurityLevel.PRIVACY_AND_INTEGRITY)
+ .set(GrpcAttributes.ATTR_SECURITY_LEVEL, SecurityLevel.PRIVACY_AND_INTEGRITY)
.build();
public InProcessTransport(String name, String authority, String userAgent) {
diff --git a/core/src/main/java/io/grpc/internal/CallCredentialsApplyingTransportFactory.java b/core/src/main/java/io/grpc/internal/CallCredentialsApplyingTransportFactory.java
index df2e0a0bd..e5141cf1e 100644
--- a/core/src/main/java/io/grpc/internal/CallCredentialsApplyingTransportFactory.java
+++ b/core/src/main/java/io/grpc/internal/CallCredentialsApplyingTransportFactory.java
@@ -72,6 +72,7 @@ final class CallCredentialsApplyingTransportFactory implements ClientTransportFa
}
@Override
+ @SuppressWarnings("deprecation")
public ClientStream newStream(
MethodDescriptor<?, ?> method, Metadata headers, CallOptions callOptions) {
CallCredentials creds = callOptions.getCredentials();
diff --git a/core/src/main/java/io/grpc/internal/GrpcAttributes.java b/core/src/main/java/io/grpc/internal/GrpcAttributes.java
index e620bb6d7..6a63864f6 100644
--- a/core/src/main/java/io/grpc/internal/GrpcAttributes.java
+++ b/core/src/main/java/io/grpc/internal/GrpcAttributes.java
@@ -18,7 +18,9 @@ package io.grpc.internal;
import io.grpc.Attributes;
import io.grpc.EquivalentAddressGroup;
+import io.grpc.Grpc;
import io.grpc.NameResolver;
+import io.grpc.SecurityLevel;
import java.util.Map;
/**
@@ -48,5 +50,14 @@ public final class GrpcAttributes {
public static final Attributes.Key<Boolean> ATTR_LB_PROVIDED_BACKEND =
Attributes.Key.create("io.grpc.grpclb.lbProvidedBackend");
+ /**
+ * The security level of the transport. If it's not present, {@link SecurityLevel#NONE} should be
+ * assumed.
+ */
+ @SuppressWarnings("deprecation")
+ @Grpc.TransportAttr
+ public static final Attributes.Key<SecurityLevel> ATTR_SECURITY_LEVEL =
+ io.grpc.CallCredentials.ATTR_SECURITY_LEVEL;
+
private GrpcAttributes() {}
}
diff --git a/core/src/main/java/io/grpc/internal/MetadataApplierImpl.java b/core/src/main/java/io/grpc/internal/MetadataApplierImpl.java
index 48e00665c..c3196ddd1 100644
--- a/core/src/main/java/io/grpc/internal/MetadataApplierImpl.java
+++ b/core/src/main/java/io/grpc/internal/MetadataApplierImpl.java
@@ -29,7 +29,7 @@ import io.grpc.Status;
import javax.annotation.Nullable;
import javax.annotation.concurrent.GuardedBy;
-final class MetadataApplierImpl implements MetadataApplier {
+final class MetadataApplierImpl extends MetadataApplier {
private final ClientTransport transport;
private final MethodDescriptor<?, ?> method;
private final Metadata origHeaders;
diff --git a/core/src/test/java/io/grpc/internal/CallCredentials2ApplyingTest.java b/core/src/test/java/io/grpc/internal/CallCredentials2ApplyingTest.java
new file mode 100644
index 000000000..f87e22810
--- /dev/null
+++ b/core/src/test/java/io/grpc/internal/CallCredentials2ApplyingTest.java
@@ -0,0 +1,291 @@
+/*
+ * Copyright 2016 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.junit.Assert.assertNull;
+import static org.junit.Assert.assertSame;
+import static org.mockito.Matchers.any;
+import static org.mockito.Matchers.same;
+import static org.mockito.Mockito.doAnswer;
+import static org.mockito.Mockito.doThrow;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import io.grpc.Attributes;
+import io.grpc.CallCredentials.MetadataApplier;
+import io.grpc.CallCredentials.RequestInfo;
+import io.grpc.CallCredentials2;
+import io.grpc.CallOptions;
+import io.grpc.IntegerMarshaller;
+import io.grpc.Metadata;
+import io.grpc.MethodDescriptor;
+import io.grpc.SecurityLevel;
+import io.grpc.Status;
+import io.grpc.StringMarshaller;
+import java.net.SocketAddress;
+import java.util.concurrent.Executor;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+import org.mockito.ArgumentCaptor;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+import org.mockito.invocation.InvocationOnMock;
+import org.mockito.stubbing.Answer;
+
+/**
+ * Unit test for {@link CallCredentials2} applying functionality implemented by {@link
+ * CallCredentialsApplyingTransportFactory} and {@link MetadataApplierImpl}.
+ */
+@RunWith(JUnit4.class)
+public class CallCredentials2ApplyingTest {
+ @Mock
+ private ClientTransportFactory mockTransportFactory;
+
+ @Mock
+ private ConnectionClientTransport mockTransport;
+
+ @Mock
+ private ClientStream mockStream;
+
+ @Mock
+ private CallCredentials2 mockCreds;
+
+ @Mock
+ private Executor mockExecutor;
+
+ @Mock
+ private SocketAddress address;
+
+ private static final String AUTHORITY = "testauthority";
+ private static final String USER_AGENT = "testuseragent";
+ private static final Attributes.Key<String> ATTR_KEY = Attributes.Key.create("somekey");
+ private static final String ATTR_VALUE = "somevalue";
+ private static final MethodDescriptor<String, Integer> method =
+ MethodDescriptor.<String, Integer>newBuilder()
+ .setType(MethodDescriptor.MethodType.UNKNOWN)
+ .setFullMethodName("service/method")
+ .setRequestMarshaller(new StringMarshaller())
+ .setResponseMarshaller(new IntegerMarshaller())
+ .build();
+ private static final Metadata.Key<String> ORIG_HEADER_KEY =
+ Metadata.Key.of("header1", Metadata.ASCII_STRING_MARSHALLER);
+ private static final String ORIG_HEADER_VALUE = "some original header value";
+ private static final Metadata.Key<String> CREDS_KEY =
+ Metadata.Key.of("test-creds", Metadata.ASCII_STRING_MARSHALLER);
+ private static final String CREDS_VALUE = "some credentials";
+
+ private final Metadata origHeaders = new Metadata();
+ private ForwardingConnectionClientTransport transport;
+ private CallOptions callOptions;
+
+ @Before
+ public void setUp() {
+ ClientTransportFactory.ClientTransportOptions clientTransportOptions =
+ new ClientTransportFactory.ClientTransportOptions()
+ .setAuthority(AUTHORITY)
+ .setUserAgent(USER_AGENT);
+
+ MockitoAnnotations.initMocks(this);
+ origHeaders.put(ORIG_HEADER_KEY, ORIG_HEADER_VALUE);
+ when(mockTransportFactory.newClientTransport(address, clientTransportOptions))
+ .thenReturn(mockTransport);
+ when(mockTransport.newStream(same(method), any(Metadata.class), any(CallOptions.class)))
+ .thenReturn(mockStream);
+ ClientTransportFactory transportFactory = new CallCredentialsApplyingTransportFactory(
+ mockTransportFactory, mockExecutor);
+ transport = (ForwardingConnectionClientTransport)
+ transportFactory.newClientTransport(address, clientTransportOptions);
+ callOptions = CallOptions.DEFAULT.withCallCredentials(mockCreds);
+ verify(mockTransportFactory).newClientTransport(address, clientTransportOptions);
+ assertSame(mockTransport, transport.delegate());
+ }
+
+ @Test
+ public void parameterPropagation_base() {
+ Attributes transportAttrs = Attributes.newBuilder().set(ATTR_KEY, ATTR_VALUE).build();
+ when(mockTransport.getAttributes()).thenReturn(transportAttrs);
+
+ transport.newStream(method, origHeaders, callOptions);
+
+ ArgumentCaptor<RequestInfo> infoCaptor = ArgumentCaptor.forClass(null);
+ verify(mockCreds).applyRequestMetadata(
+ infoCaptor.capture(), same(mockExecutor), any(MetadataApplier.class));
+ RequestInfo info = infoCaptor.getValue();
+ assertSame(method, info.getMethodDescriptor());
+ Attributes attrs = info.getTransportAttrs();
+ assertSame(ATTR_VALUE, info.getTransportAttrs().get(ATTR_KEY));
+ assertSame(AUTHORITY, info.getAuthority());
+ assertSame(SecurityLevel.NONE, info.getSecurityLevel());
+ }
+
+ @Test
+ public void parameterPropagation_transportSetSecurityLevel() {
+ Attributes transportAttrs = Attributes.newBuilder()
+ .set(ATTR_KEY, ATTR_VALUE)
+ .set(GrpcAttributes.ATTR_SECURITY_LEVEL, SecurityLevel.INTEGRITY)
+ .build();
+ when(mockTransport.getAttributes()).thenReturn(transportAttrs);
+
+ transport.newStream(method, origHeaders, callOptions);
+
+ ArgumentCaptor<RequestInfo> infoCaptor = ArgumentCaptor.forClass(null);
+ verify(mockCreds).applyRequestMetadata(
+ infoCaptor.capture(), same(mockExecutor), any(MetadataApplier.class));
+ RequestInfo info = infoCaptor.getValue();
+ assertSame(method, info.getMethodDescriptor());
+ assertSame(ATTR_VALUE, info.getTransportAttrs().get(ATTR_KEY));
+ assertSame(AUTHORITY, info.getAuthority());
+ assertSame(SecurityLevel.INTEGRITY, info.getSecurityLevel());
+ }
+
+ @Test
+ public void parameterPropagation_callOptionsSetAuthority() {
+ Attributes transportAttrs = Attributes.newBuilder()
+ .set(ATTR_KEY, ATTR_VALUE)
+ .build();
+ when(mockTransport.getAttributes()).thenReturn(transportAttrs);
+ Executor anotherExecutor = mock(Executor.class);
+
+ transport.newStream(method, origHeaders,
+ callOptions.withAuthority("calloptions-authority").withExecutor(anotherExecutor));
+
+ ArgumentCaptor<RequestInfo> infoCaptor = ArgumentCaptor.forClass(null);
+ verify(mockCreds).applyRequestMetadata(
+ infoCaptor.capture(), same(anotherExecutor), any(MetadataApplier.class));
+ RequestInfo info = infoCaptor.getValue();
+ assertSame(method, info.getMethodDescriptor());
+ assertSame(ATTR_VALUE, info.getTransportAttrs().get(ATTR_KEY));
+ assertEquals("calloptions-authority", info.getAuthority());
+ assertSame(SecurityLevel.NONE, info.getSecurityLevel());
+ }
+
+ @Test
+ public void credentialThrows() {
+ final RuntimeException ex = new RuntimeException();
+ when(mockTransport.getAttributes()).thenReturn(Attributes.EMPTY);
+ doThrow(ex).when(mockCreds).applyRequestMetadata(
+ any(RequestInfo.class), same(mockExecutor), any(MetadataApplier.class));
+
+ FailingClientStream stream =
+ (FailingClientStream) transport.newStream(method, origHeaders, callOptions);
+
+ verify(mockTransport, never()).newStream(method, origHeaders, callOptions);
+ assertEquals(Status.Code.UNAUTHENTICATED, stream.getError().getCode());
+ assertSame(ex, stream.getError().getCause());
+ }
+
+ @Test
+ public void applyMetadata_inline() {
+ when(mockTransport.getAttributes()).thenReturn(Attributes.EMPTY);
+ doAnswer(new Answer<Void>() {
+ @Override
+ public Void answer(InvocationOnMock invocation) throws Throwable {
+ MetadataApplier applier = (MetadataApplier) invocation.getArguments()[2];
+ Metadata headers = new Metadata();
+ headers.put(CREDS_KEY, CREDS_VALUE);
+ applier.apply(headers);
+ return null;
+ }
+ }).when(mockCreds).applyRequestMetadata(
+ any(RequestInfo.class), same(mockExecutor), any(MetadataApplier.class));
+
+ ClientStream stream = transport.newStream(method, origHeaders, callOptions);
+
+ verify(mockTransport).newStream(method, origHeaders, callOptions);
+ assertSame(mockStream, stream);
+ assertEquals(CREDS_VALUE, origHeaders.get(CREDS_KEY));
+ assertEquals(ORIG_HEADER_VALUE, origHeaders.get(ORIG_HEADER_KEY));
+ }
+
+ @Test
+ public void fail_inline() {
+ final Status error = Status.FAILED_PRECONDITION.withDescription("channel not secure for creds");
+ when(mockTransport.getAttributes()).thenReturn(Attributes.EMPTY);
+ doAnswer(new Answer<Void>() {
+ @Override
+ public Void answer(InvocationOnMock invocation) throws Throwable {
+ MetadataApplier applier = (MetadataApplier) invocation.getArguments()[2];
+ applier.fail(error);
+ return null;
+ }
+ }).when(mockCreds).applyRequestMetadata(
+ any(RequestInfo.class), same(mockExecutor), any(MetadataApplier.class));
+
+ FailingClientStream stream =
+ (FailingClientStream) transport.newStream(method, origHeaders, callOptions);
+
+ verify(mockTransport, never()).newStream(method, origHeaders, callOptions);
+ assertSame(error, stream.getError());
+ }
+
+ @Test
+ public void applyMetadata_delayed() {
+ when(mockTransport.getAttributes()).thenReturn(Attributes.EMPTY);
+
+ // Will call applyRequestMetadata(), which is no-op.
+ DelayedStream stream = (DelayedStream) transport.newStream(method, origHeaders, callOptions);
+
+ ArgumentCaptor<MetadataApplier> applierCaptor = ArgumentCaptor.forClass(null);
+ verify(mockCreds).applyRequestMetadata(
+ any(RequestInfo.class), same(mockExecutor), applierCaptor.capture());
+ verify(mockTransport, never()).newStream(method, origHeaders, callOptions);
+
+ Metadata headers = new Metadata();
+ headers.put(CREDS_KEY, CREDS_VALUE);
+ applierCaptor.getValue().apply(headers);
+
+ verify(mockTransport).newStream(method, origHeaders, callOptions);
+ assertSame(mockStream, stream.getRealStream());
+ assertEquals(CREDS_VALUE, origHeaders.get(CREDS_KEY));
+ assertEquals(ORIG_HEADER_VALUE, origHeaders.get(ORIG_HEADER_KEY));
+ }
+
+ @Test
+ public void fail_delayed() {
+ when(mockTransport.getAttributes()).thenReturn(Attributes.EMPTY);
+
+ // Will call applyRequestMetadata(), which is no-op.
+ DelayedStream stream = (DelayedStream) transport.newStream(method, origHeaders, callOptions);
+
+ ArgumentCaptor<MetadataApplier> applierCaptor = ArgumentCaptor.forClass(null);
+ verify(mockCreds).applyRequestMetadata(
+ any(RequestInfo.class), same(mockExecutor), applierCaptor.capture());
+
+ Status error = Status.FAILED_PRECONDITION.withDescription("channel not secure for creds");
+ applierCaptor.getValue().fail(error);
+
+ verify(mockTransport, never()).newStream(method, origHeaders, callOptions);
+ FailingClientStream failingStream = (FailingClientStream) stream.getRealStream();
+ assertSame(error, failingStream.getError());
+ }
+
+ @Test
+ public void noCreds() {
+ callOptions = callOptions.withCallCredentials(null);
+ ClientStream stream = transport.newStream(method, origHeaders, callOptions);
+
+ verify(mockTransport).newStream(method, origHeaders, callOptions);
+ assertSame(mockStream, stream);
+ assertNull(origHeaders.get(CREDS_KEY));
+ assertEquals(ORIG_HEADER_VALUE, origHeaders.get(ORIG_HEADER_KEY));
+ }
+}
diff --git a/core/src/test/java/io/grpc/internal/CallCredentialsApplyingTest.java b/core/src/test/java/io/grpc/internal/CallCredentialsApplyingTest.java
index c6a9bfb43..51df406b5 100644
--- a/core/src/test/java/io/grpc/internal/CallCredentialsApplyingTest.java
+++ b/core/src/test/java/io/grpc/internal/CallCredentialsApplyingTest.java
@@ -55,6 +55,7 @@ import org.mockito.stubbing.Answer;
* CallCredentialsApplyingTransportFactory} and {@link MetadataApplierImpl}.
*/
@RunWith(JUnit4.class)
+@Deprecated
public class CallCredentialsApplyingTest {
@Mock
private ClientTransportFactory mockTransportFactory;
diff --git a/core/src/test/java/io/grpc/internal/ManagedChannelImplTest.java b/core/src/test/java/io/grpc/internal/ManagedChannelImplTest.java
index 248eb66f0..863834a0f 100644
--- a/core/src/test/java/io/grpc/internal/ManagedChannelImplTest.java
+++ b/core/src/test/java/io/grpc/internal/ManagedChannelImplTest.java
@@ -1388,6 +1388,7 @@ public class ManagedChannelImplTest {
* propagated to newStream() and applyRequestMetadata().
*/
@Test
+ @SuppressWarnings("deprecation")
public void informationPropagatedToNewStreamAndCallCredentials() {
createChannel();
CallOptions callOptions = CallOptions.DEFAULT.withCallCredentials(creds);
@@ -1401,7 +1402,7 @@ public class ManagedChannelImplTest {
credsApplyContexts.add(Context.current());
return null;
}
- }).when(creds).applyRequestMetadata(
+ }).when(creds).applyRequestMetadata( // TODO(zhangkun83): remove suppression of deprecations
any(MethodDescriptor.class), any(Attributes.class), any(Executor.class),
any(MetadataApplier.class));