Search in sources :

Example 1 with Context

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());
}
Also used : Attributes(io.grpc.Attributes) Metadata(io.grpc.Metadata) ResolvedServerInfoGroup(io.grpc.ResolvedServerInfoGroup) CallOptions(io.grpc.CallOptions) Matchers.anyString(org.mockito.Matchers.anyString) Executor(java.util.concurrent.Executor) PickSubchannelArgs(io.grpc.LoadBalancer.PickSubchannelArgs) Context(io.grpc.Context) MetadataApplier(io.grpc.CallCredentials.MetadataApplier) MockClientTransportInfo(io.grpc.internal.TestUtils.MockClientTransportInfo) MethodDescriptor(io.grpc.MethodDescriptor) LinkedList(java.util.LinkedList) InvocationOnMock(org.mockito.invocation.InvocationOnMock) Subchannel(io.grpc.LoadBalancer.Subchannel) Test(org.junit.Test)

Example 2 with Context

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
    }
}
Also used : Context(io.grpc.Context) StatsContext(com.google.instrumentation.stats.StatsContext) Status(io.grpc.Status) Metadata(io.grpc.Metadata) ClientCall(io.grpc.ClientCall) Test(org.junit.Test)

Example 3 with Context

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());
}
Also used : Context(io.grpc.Context) StatsContext(com.google.instrumentation.stats.StatsContext) Status(io.grpc.Status) Metadata(io.grpc.Metadata) CountDownLatch(java.util.concurrent.CountDownLatch) AtomicBoolean(java.util.concurrent.atomic.AtomicBoolean) ByteArrayInputStream(java.io.ByteArrayInputStream) ClientCall(io.grpc.ClientCall) Test(org.junit.Test)

Example 4 with Context

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);
}
Also used : Context(io.grpc.Context) StatsContext(com.google.instrumentation.stats.StatsContext) Metadata(io.grpc.Metadata) Test(org.junit.Test)

Example 5 with Context

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());
}
Also used : Context(io.grpc.Context) StatsContext(com.google.instrumentation.stats.StatsContext) Metadata(io.grpc.Metadata) Test(org.junit.Test)

Aggregations

Context (io.grpc.Context)20 Test (org.junit.Test)15 Metadata (io.grpc.Metadata)10 StatsContext (com.google.instrumentation.stats.StatsContext)8 CallOptions (io.grpc.CallOptions)4 Status (io.grpc.Status)4 CountDownLatch (java.util.concurrent.CountDownLatch)3 ScheduledExecutorService (java.util.concurrent.ScheduledExecutorService)3 AtomicBoolean (java.util.concurrent.atomic.AtomicBoolean)3 IntegrationTest (com.google.cloud.spanner.IntegrationTest)2 SpannerException (com.google.cloud.spanner.SpannerException)2 SpannerMatchers.isSpannerException (com.google.cloud.spanner.SpannerMatchers.isSpannerException)2 ClientCall (io.grpc.ClientCall)2 ServerCall (io.grpc.ServerCall)2 ServiceDescriptor (io.grpc.ServiceDescriptor)2 JumpToApplicationThreadServerStreamListener (io.grpc.internal.ServerImpl.JumpToApplicationThreadServerStreamListener)2 ByteArrayInputStream (java.io.ByteArrayInputStream)2 ExecutionException (java.util.concurrent.ExecutionException)2 AtomicInteger (java.util.concurrent.atomic.AtomicInteger)2 ExponentialBackOff (com.google.api.client.util.ExponentialBackOff)1