use of io.grpc.Context in project grpc-java by grpc.
the class ManagedChannelImplTest method informationPropagatedToNewStreamAndCallCredentials.
/**
* Test that information such as the Call's context, MethodDescriptor, authority, executor are
* propagated to newStream() and applyRequestMetadata().
*/
@Test
public void informationPropagatedToNewStreamAndCallCredentials() {
ResolvedServerInfoGroup serverInfoGroup = ResolvedServerInfoGroup.builder().add(server).build();
createChannel(new FakeNameResolverFactory(true), NO_INTERCEPTOR);
CallOptions callOptions = CallOptions.DEFAULT.withCallCredentials(creds);
final Context.Key<String> testKey = Context.key("testing");
Context ctx = Context.current().withValue(testKey, "testValue");
final LinkedList<Context> credsApplyContexts = new LinkedList<Context>();
final LinkedList<Context> newStreamContexts = new LinkedList<Context>();
doAnswer(new Answer<Void>() {
@Override
public Void answer(InvocationOnMock in) throws Throwable {
credsApplyContexts.add(Context.current());
return null;
}
}).when(creds).applyRequestMetadata(any(MethodDescriptor.class), any(Attributes.class), any(Executor.class), any(MetadataApplier.class));
// First call will be on delayed transport. Only newCall() is run within the expected context,
// so that we can verify that the context is explicitly attached before calling newStream() and
// applyRequestMetadata(), which happens after we detach the context from the thread.
Context origCtx = ctx.attach();
assertEquals("testValue", testKey.get());
ClientCall<String, Integer> call = channel.newCall(method, callOptions);
ctx.detach(origCtx);
assertNull(testKey.get());
call.start(mockCallListener, new Metadata());
// Simulate name resolution results
Subchannel subchannel = helper.createSubchannel(serverInfoGroup.toEquivalentAddressGroup(), Attributes.EMPTY);
subchannel.requestConnection();
verify(mockTransportFactory).newClientTransport(same(socketAddress), eq(authority), eq(userAgent));
MockClientTransportInfo transportInfo = transports.poll();
final ConnectionClientTransport transport = transportInfo.transport;
when(transport.getAttributes()).thenReturn(Attributes.EMPTY);
doAnswer(new Answer<ClientStream>() {
@Override
public ClientStream answer(InvocationOnMock in) throws Throwable {
newStreamContexts.add(Context.current());
return mock(ClientStream.class);
}
}).when(transport).newStream(any(MethodDescriptor.class), any(Metadata.class), any(CallOptions.class), any(StatsTraceContext.class));
verify(creds, never()).applyRequestMetadata(any(MethodDescriptor.class), any(Attributes.class), any(Executor.class), any(MetadataApplier.class));
// applyRequestMetadata() is called after the transport becomes ready.
transportInfo.listener.transportReady();
when(mockPicker.pickSubchannel(any(PickSubchannelArgs.class))).thenReturn(PickResult.withSubchannel(subchannel));
helper.updatePicker(mockPicker);
executor.runDueTasks();
ArgumentCaptor<Attributes> attrsCaptor = ArgumentCaptor.forClass(Attributes.class);
ArgumentCaptor<MetadataApplier> applierCaptor = ArgumentCaptor.forClass(MetadataApplier.class);
verify(creds).applyRequestMetadata(same(method), attrsCaptor.capture(), same(executor.getScheduledExecutorService()), applierCaptor.capture());
assertEquals("testValue", testKey.get(credsApplyContexts.poll()));
assertEquals(authority, attrsCaptor.getValue().get(CallCredentials.ATTR_AUTHORITY));
assertEquals(SecurityLevel.NONE, attrsCaptor.getValue().get(CallCredentials.ATTR_SECURITY_LEVEL));
verify(transport, never()).newStream(any(MethodDescriptor.class), any(Metadata.class), any(CallOptions.class), any(StatsTraceContext.class));
// newStream() is called after apply() is called
applierCaptor.getValue().apply(new Metadata());
verify(transport).newStream(same(method), any(Metadata.class), same(callOptions), any(StatsTraceContext.class));
assertEquals("testValue", testKey.get(newStreamContexts.poll()));
// The context should not live beyond the scope of newStream() and applyRequestMetadata()
assertNull(testKey.get());
// Second call will not be on delayed transport
origCtx = ctx.attach();
call = channel.newCall(method, callOptions);
ctx.detach(origCtx);
call.start(mockCallListener, new Metadata());
verify(creds, times(2)).applyRequestMetadata(same(method), attrsCaptor.capture(), same(executor.getScheduledExecutorService()), applierCaptor.capture());
assertEquals("testValue", testKey.get(credsApplyContexts.poll()));
assertEquals(authority, attrsCaptor.getValue().get(CallCredentials.ATTR_AUTHORITY));
assertEquals(SecurityLevel.NONE, attrsCaptor.getValue().get(CallCredentials.ATTR_SECURITY_LEVEL));
// This is from the first call
verify(transport).newStream(any(MethodDescriptor.class), any(Metadata.class), any(CallOptions.class), any(StatsTraceContext.class));
// Still, newStream() is called after apply() is called
applierCaptor.getValue().apply(new Metadata());
verify(transport, times(2)).newStream(same(method), any(Metadata.class), same(callOptions), any(StatsTraceContext.class));
assertEquals("testValue", testKey.get(newStreamContexts.poll()));
assertNull(testKey.get());
}
use of io.grpc.Context in project grpc-java by grpc.
the class ClientCallImplTest method contextAlreadyCancelledNotifiesImmediately.
@Test
public void contextAlreadyCancelledNotifiesImmediately() throws Exception {
// Attach the context which is recorded when the call is created
Context.CancellableContext cancellableContext = Context.current().withCancellation();
Throwable cause = new Throwable();
cancellableContext.cancel(cause);
Context previous = cancellableContext.attach();
ClientCallImpl<Void, Void> call = new ClientCallImpl<Void, Void>(method, new SerializingExecutor(Executors.newSingleThreadExecutor()), CallOptions.DEFAULT, statsTraceCtx, provider, deadlineCancellationExecutor).setDecompressorRegistry(decompressorRegistry);
previous.attach();
final SettableFuture<Status> statusFuture = SettableFuture.create();
call.start(new ClientCall.Listener<Void>() {
@Override
public void onClose(Status status, Metadata trailers) {
statusFuture.set(status);
}
}, new Metadata());
// Caller should receive onClose callback.
Status status = statusFuture.get(5, TimeUnit.SECONDS);
assertEquals(Status.Code.CANCELLED, status.getCode());
assertSame(cause, status.getCause());
assertStatusInStats(Status.Code.CANCELLED);
// Following operations should be no-op.
call.request(1);
call.sendMessage(null);
call.halfClose();
// Stream should never be created.
verifyZeroInteractions(transport);
try {
call.sendMessage(null);
fail("Call has been cancelled");
} catch (IllegalStateException ise) {
// expected
}
}
use of io.grpc.Context in project grpc-java by grpc.
the class ClientCallImplTest method callerContextPropagatedToListener.
@Test
public void callerContextPropagatedToListener() throws Exception {
// Attach the context which is recorded when the call is created
final Context.Key<String> testKey = Context.key("testing");
Context.current().withValue(testKey, "testValue").attach();
ClientCallImpl<Void, Void> call = new ClientCallImpl<Void, Void>(method, new SerializingExecutor(Executors.newSingleThreadExecutor()), CallOptions.DEFAULT, statsTraceCtx, provider, deadlineCancellationExecutor).setDecompressorRegistry(decompressorRegistry);
Context.ROOT.attach();
// Override the value after creating the call, this should not be seen by callbacks
Context.current().withValue(testKey, "badValue").attach();
final AtomicBoolean onHeadersCalled = new AtomicBoolean();
final AtomicBoolean onMessageCalled = new AtomicBoolean();
final AtomicBoolean onReadyCalled = new AtomicBoolean();
final AtomicBoolean observedIncorrectContext = new AtomicBoolean();
final CountDownLatch latch = new CountDownLatch(1);
call.start(new ClientCall.Listener<Void>() {
@Override
public void onHeaders(Metadata headers) {
onHeadersCalled.set(true);
checkContext();
}
@Override
public void onMessage(Void message) {
onMessageCalled.set(true);
checkContext();
}
@Override
public void onClose(Status status, Metadata trailers) {
checkContext();
latch.countDown();
}
@Override
public void onReady() {
onReadyCalled.set(true);
checkContext();
}
private void checkContext() {
if (!"testValue".equals(testKey.get())) {
observedIncorrectContext.set(true);
}
}
}, new Metadata());
verify(stream).start(listenerArgumentCaptor.capture());
ClientStreamListener listener = listenerArgumentCaptor.getValue();
listener.onReady();
listener.headersRead(new Metadata());
listener.messageRead(new ByteArrayInputStream(new byte[0]));
listener.messageRead(new ByteArrayInputStream(new byte[0]));
listener.closed(Status.OK, new Metadata());
assertTrue(latch.await(5, TimeUnit.SECONDS));
assertTrue(onHeadersCalled.get());
assertTrue(onMessageCalled.get());
assertTrue(onReadyCalled.get());
assertFalse(observedIncorrectContext.get());
}
use of io.grpc.Context in project grpc-java by grpc.
the class ClientCallImplTest method contextDeadlineShouldBePropagatedInMetadata.
@Test
public void contextDeadlineShouldBePropagatedInMetadata() {
long deadlineNanos = TimeUnit.SECONDS.toNanos(1);
Context context = Context.current().withDeadlineAfter(deadlineNanos, TimeUnit.NANOSECONDS, deadlineCancellationExecutor);
context.attach();
ClientCallImpl<Void, Void> call = new ClientCallImpl<Void, Void>(method, MoreExecutors.directExecutor(), CallOptions.DEFAULT, statsTraceCtx, provider, deadlineCancellationExecutor);
Metadata headers = new Metadata();
call.start(callListener, headers);
assertTrue(headers.containsKey(GrpcUtil.TIMEOUT_KEY));
Long timeout = headers.get(GrpcUtil.TIMEOUT_KEY);
assertNotNull(timeout);
long deltaNanos = TimeUnit.MILLISECONDS.toNanos(400);
assertTimeoutBetween(timeout, deadlineNanos - deltaNanos, deadlineNanos);
}
use of io.grpc.Context in project grpc-java by grpc.
the class ClientCallImplTest method contextCancellationCancelsStream.
@Test
public void contextCancellationCancelsStream() throws Exception {
// Attach the context which is recorded when the call is created
Context.CancellableContext cancellableContext = Context.current().withCancellation();
Context previous = cancellableContext.attach();
ClientCallImpl<Void, Void> call = new ClientCallImpl<Void, Void>(method, new SerializingExecutor(Executors.newSingleThreadExecutor()), CallOptions.DEFAULT, statsTraceCtx, provider, deadlineCancellationExecutor).setDecompressorRegistry(decompressorRegistry);
previous.attach();
call.start(callListener, new Metadata());
Throwable t = new Throwable();
cancellableContext.cancel(t);
verify(stream, times(1)).cancel(statusArgumentCaptor.capture());
verify(stream, times(1)).cancel(statusCaptor.capture());
assertEquals(Status.Code.CANCELLED, statusCaptor.getValue().getCode());
}
Aggregations