Пример #1
0
  @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>(
                DESCRIPTOR,
                new SerializingExecutor(Executors.newSingleThreadExecutor()),
                CallOptions.DEFAULT,
                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());
  }
Пример #2
0
  @Test
  public void contextDeadlineShouldNotOverrideSmallerMetadataTimeout() {
    long deadlineNanos = TimeUnit.SECONDS.toNanos(2);
    Context context =
        Context.current()
            .withDeadlineAfter(deadlineNanos, TimeUnit.NANOSECONDS, deadlineCancellationExecutor);
    context.attach();

    CallOptions callOpts = CallOptions.DEFAULT.withDeadlineAfter(1, TimeUnit.SECONDS);
    ClientCallImpl<Void, Void> call =
        new ClientCallImpl<Void, Void>(
            DESCRIPTOR,
            MoreExecutors.directExecutor(),
            callOpts,
            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 callOptsNanos = TimeUnit.SECONDS.toNanos(1);
    long deltaNanos = TimeUnit.MILLISECONDS.toNanos(400);
    assertTimeoutBetween(timeout, callOptsNanos - deltaNanos, callOptsNanos);
  }
Пример #3
0
  @Test
  public void cancelInOnMessageShouldInvokeStreamCancel() throws Exception {
    final ClientCallImpl<Void, Void> call =
        new ClientCallImpl<Void, Void>(
            DESCRIPTOR,
            MoreExecutors.directExecutor(),
            CallOptions.DEFAULT,
            provider,
            deadlineCancellationExecutor);
    final Exception cause = new Exception();
    ClientCall.Listener<Void> callListener =
        new ClientCall.Listener<Void>() {
          @Override
          public void onMessage(Void message) {
            call.cancel("foo", cause);
          }
        };

    call.start(callListener, new Metadata());
    call.halfClose();
    call.request(1);

    verify(stream).start(listenerArgumentCaptor.capture());
    ClientStreamListener streamListener = listenerArgumentCaptor.getValue();
    streamListener.onReady();
    streamListener.headersRead(new Metadata());
    streamListener.messageRead(new ByteArrayInputStream(new byte[0]));
    verify(stream).cancel(statusCaptor.capture());
    Status status = statusCaptor.getValue();
    assertEquals(Status.CANCELLED.getCode(), status.getCode());
    assertEquals("foo", status.getDescription());
    assertSame(cause, status.getCause());
  }
Пример #4
0
  @Test
  public void authorityPropagatedToStream() {
    ClientCallImpl<Void, Void> call =
        new ClientCallImpl<Void, Void>(
                method,
                MoreExecutors.directExecutor(),
                CallOptions.DEFAULT.withAuthority("overridden-authority"),
                provider,
                deadlineCancellationExecutor)
            .setDecompressorRegistry(decompressorRegistry);

    call.start(callListener, new Metadata());
    verify(stream).setAuthority("overridden-authority");
  }
Пример #5
0
  @Test
  public void authorityNotPropagatedToStream() {
    ClientCallImpl<Void, Void> call =
        new ClientCallImpl<Void, Void>(
                method,
                MoreExecutors.directExecutor(),
                // Don't provide an authority
                CallOptions.DEFAULT,
                provider,
                deadlineCancellationExecutor)
            .setDecompressorRegistry(decompressorRegistry);

    call.start(callListener, new Metadata());
    verify(stream, never()).setAuthority(any(String.class));
  }
Пример #6
0
  /** Without a context or call options deadline, a timeout should not be set in metadata. */
  @Test
  public void timeoutShouldNotBeSet() {
    ClientCallImpl<Void, Void> call =
        new ClientCallImpl<Void, Void>(
            DESCRIPTOR,
            MoreExecutors.directExecutor(),
            CallOptions.DEFAULT,
            provider,
            deadlineCancellationExecutor);

    Metadata headers = new Metadata();

    call.start(callListener, headers);

    assertFalse(headers.containsKey(GrpcUtil.TIMEOUT_KEY));
  }
Пример #7
0
  @Test
  public void prepareHeaders_ignoreIdentityEncoding() {
    Metadata m = new Metadata();
    ClientCallImpl.prepareHeaders(m, decompressorRegistry, Codec.Identity.NONE);

    assertNull(m.get(GrpcUtil.MESSAGE_ENCODING_KEY));
  }
Пример #8
0
  @Test
  public void prepareHeaders_userAgentAdded() {
    Metadata m = new Metadata();
    ClientCallImpl.prepareHeaders(
        m, CallOptions.DEFAULT, "user agent", DecompressorRegistry.getDefaultInstance());

    assertEquals(m.get(GrpcUtil.USER_AGENT_KEY), "user agent");
  }
Пример #9
0
  @Test
  public void callOptionsPropagatedToTransport() {
    final CallOptions callOptions = CallOptions.DEFAULT.withAuthority("dummy_value");
    final ClientCallImpl<Void, Void> call =
        new ClientCallImpl<Void, Void>(
                method,
                MoreExecutors.directExecutor(),
                callOptions,
                provider,
                deadlineCancellationExecutor)
            .setDecompressorRegistry(decompressorRegistry);
    final Metadata metadata = new Metadata();

    call.start(callListener, metadata);

    verify(transport).newStream(same(method), same(metadata), same(callOptions));
  }
Пример #10
0
  @Test
  public void prepareHeaders_messageEncodingAdded() {
    Metadata m = new Metadata();
    CallOptions callOptions = CallOptions.DEFAULT.withCompressor(new Codec.Gzip());
    ClientCallImpl.prepareHeaders(
        m, callOptions, "user agent", DecompressorRegistry.getDefaultInstance());

    assertEquals(m.get(GrpcUtil.MESSAGE_ENCODING_KEY), new Codec.Gzip().getMessageEncoding());
  }
Пример #11
0
  @Test
  public void prepareHeaders_ignoreIdentityEncoding() {
    Metadata m = new Metadata();
    CallOptions callOptions = CallOptions.DEFAULT.withCompressor(Codec.Identity.NONE);
    ClientCallImpl.prepareHeaders(
        m, callOptions, "user agent", DecompressorRegistry.getDefaultInstance());

    assertNull(m.get(GrpcUtil.MESSAGE_ENCODING_KEY));
  }
Пример #12
0
  @Test
  public void prepareHeaders_userAgentIgnored() {
    Metadata m = new Metadata();
    m.put(GrpcUtil.USER_AGENT_KEY, "batmobile");
    ClientCallImpl.prepareHeaders(m, decompressorRegistry, Codec.Identity.NONE);

    // User Agent is removed and set by the transport
    assertThat(m.get(GrpcUtil.USER_AGENT_KEY)).isNotNull();
  }
Пример #13
0
  @Test
  public void expiredDeadlineCancelsStream_CallOptions() {
    fakeClock.forwardTime(System.nanoTime(), TimeUnit.NANOSECONDS);
    ClientCallImpl<Void, Void> call =
        new ClientCallImpl<Void, Void>(
            DESCRIPTOR,
            MoreExecutors.directExecutor(),
            CallOptions.DEFAULT.withDeadline(Deadline.after(1000, TimeUnit.MILLISECONDS)),
            provider,
            deadlineCancellationExecutor);

    call.start(callListener, new Metadata());

    fakeClock.forwardMillis(1001);

    verify(stream, times(1)).cancel(statusCaptor.capture());
    assertEquals(Status.Code.DEADLINE_EXCEEDED, statusCaptor.getValue().getCode());
  }
Пример #14
0
  @Test
  public void prepareHeaders_authorityAdded() {
    Metadata m = new Metadata();
    CallOptions callOptions = CallOptions.DEFAULT.withAuthority("auth");
    ClientCallImpl.prepareHeaders(
        m, callOptions, "user agent", DecompressorRegistry.getDefaultInstance());

    assertEquals(m.get(GrpcUtil.AUTHORITY_KEY), "auth");
  }
Пример #15
0
 @Test
 public void deadlineExceededBeforeCallStarted() {
   CallOptions callOptions = CallOptions.DEFAULT.withDeadlineAfter(0, TimeUnit.SECONDS);
   fakeClock.forwardTime(System.nanoTime(), TimeUnit.NANOSECONDS);
   ClientCallImpl<Void, Void> call =
       new ClientCallImpl<Void, Void>(
               DESCRIPTOR,
               new SerializingExecutor(Executors.newSingleThreadExecutor()),
               callOptions,
               provider,
               deadlineCancellationExecutor)
           .setDecompressorRegistry(decompressorRegistry);
   call.start(callListener, new Metadata());
   verify(transport, times(0)).newStream(any(MethodDescriptor.class), any(Metadata.class));
   verify(callListener, timeout(1000)).onClose(statusCaptor.capture(), any(Metadata.class));
   assertEquals(Status.Code.DEADLINE_EXCEEDED, statusCaptor.getValue().getCode());
   verifyZeroInteractions(provider);
 }
Пример #16
0
  @Test
  public void prepareHeaders_removeReservedHeaders() {
    Metadata m = new Metadata();
    m.put(GrpcUtil.MESSAGE_ENCODING_KEY, "gzip");
    m.put(GrpcUtil.MESSAGE_ACCEPT_ENCODING_KEY, "gzip");

    ClientCallImpl.prepareHeaders(m, DecompressorRegistry.emptyInstance(), Codec.Identity.NONE);

    assertNull(m.get(GrpcUtil.MESSAGE_ENCODING_KEY));
    assertNull(m.get(GrpcUtil.MESSAGE_ACCEPT_ENCODING_KEY));
  }
Пример #17
0
  @Test
  public void prepareHeaders_acceptedEncodingsAdded() {
    Metadata m = new Metadata();
    DecompressorRegistry customRegistry =
        DecompressorRegistry.emptyInstance()
            .with(
                new Decompressor() {
                  @Override
                  public String getMessageEncoding() {
                    return "a";
                  }

                  @Override
                  public InputStream decompress(InputStream is) throws IOException {
                    return null;
                  }
                },
                true)
            .with(
                new Decompressor() {
                  @Override
                  public String getMessageEncoding() {
                    return "b";
                  }

                  @Override
                  public InputStream decompress(InputStream is) throws IOException {
                    return null;
                  }
                },
                true)
            .with(
                new Decompressor() {
                  @Override
                  public String getMessageEncoding() {
                    return "c";
                  }

                  @Override
                  public InputStream decompress(InputStream is) throws IOException {
                    return null;
                  }
                },
                false); // not advertised

    ClientCallImpl.prepareHeaders(m, customRegistry, Codec.Identity.NONE);

    Iterable<String> acceptedEncodings =
        ACCEPT_ENCODING_SPLITER.split(m.get(GrpcUtil.MESSAGE_ACCEPT_ENCODING_KEY));

    // Order may be different, since decoder priorities have not yet been implemented.
    assertEquals(ImmutableSet.of("b", "a"), ImmutableSet.copyOf(acceptedEncodings));
  }
Пример #18
0
  @Test
  public void streamCancelAbortsDeadlineTimer() {
    fakeClock.forwardTime(System.nanoTime(), TimeUnit.NANOSECONDS);

    ClientCallImpl<Void, Void> call =
        new ClientCallImpl<Void, Void>(
            DESCRIPTOR,
            MoreExecutors.directExecutor(),
            CallOptions.DEFAULT.withDeadline(Deadline.after(1000, TimeUnit.MILLISECONDS)),
            provider,
            deadlineCancellationExecutor);
    call.start(callListener, new Metadata());
    call.cancel("canceled", null);

    // Run the deadline timer, which should have been cancelled by the previous call to cancel()
    fakeClock.forwardMillis(1001);

    verify(stream, times(1)).cancel(statusCaptor.capture());

    assertEquals(Status.CANCELLED.getCode(), statusCaptor.getValue().getCode());
  }
Пример #19
0
  @Test
  public void advertisedEncodingsAreSent() {
    ClientCallImpl<Void, Void> call =
        new ClientCallImpl<Void, Void>(
                method,
                MoreExecutors.directExecutor(),
                CallOptions.DEFAULT,
                provider,
                deadlineCancellationExecutor)
            .setDecompressorRegistry(decompressorRegistry);

    call.start(callListener, new Metadata());

    ArgumentCaptor<Metadata> metadataCaptor = ArgumentCaptor.forClass(Metadata.class);
    verify(transport).newStream(eq(method), metadataCaptor.capture(), same(CallOptions.DEFAULT));
    Metadata actual = metadataCaptor.getValue();

    Set<String> acceptedEncodings =
        ImmutableSet.copyOf(actual.getAll(GrpcUtil.MESSAGE_ACCEPT_ENCODING_KEY));
    assertEquals(decompressorRegistry.getAdvertisedMessageEncodings(), acceptedEncodings);
  }
Пример #20
0
  @Test
  public void advertisedEncodingsAreSent() {
    MethodDescriptor<Void, Void> descriptor =
        MethodDescriptor.create(
            MethodType.UNARY,
            "service/method",
            new TestMarshaller<Void>(),
            new TestMarshaller<Void>());
    final ClientTransport transport = mock(ClientTransport.class);
    final ClientStream stream = mock(ClientStream.class);
    ClientTransportProvider provider =
        new ClientTransportProvider() {
          @Override
          public ListenableFuture<ClientTransport> get(CallOptions callOptions) {
            return Futures.immediateFuture(transport);
          }
        };
    when(transport.newStream(
            any(MethodDescriptor.class), any(Metadata.class), any(ClientStreamListener.class)))
        .thenReturn(stream);
    ClientCallImpl<Void, Void> call =
        new ClientCallImpl<Void, Void>(
                descriptor, executor, CallOptions.DEFAULT, provider, deadlineCancellationExecutor)
            .setDecompressorRegistry(decompressorRegistry);

    call.start(new TestClientCallListener<Void>(), new Metadata());

    ArgumentCaptor<Metadata> metadataCaptor = ArgumentCaptor.forClass(Metadata.class);
    verify(transport)
        .newStream(eq(descriptor), metadataCaptor.capture(), isA(ClientStreamListener.class));
    Metadata actual = metadataCaptor.getValue();

    Set<String> acceptedEncodings =
        ImmutableSet.copyOf(actual.getAll(GrpcUtil.MESSAGE_ACCEPT_ENCODING_KEY));
    assertEquals(decompressorRegistry.getAdvertisedMessageEncodings(), acceptedEncodings);
  }
Пример #21
0
  @Test
  public void prepareHeaders_removeReservedHeaders() {
    Metadata m = new Metadata();
    m.put(GrpcUtil.AUTHORITY_KEY, "auth");
    m.put(GrpcUtil.USER_AGENT_KEY, "user agent");
    m.put(GrpcUtil.MESSAGE_ENCODING_KEY, "gzip");
    m.put(GrpcUtil.MESSAGE_ACCEPT_ENCODING_KEY, "gzip");

    ClientCallImpl.prepareHeaders(
        m, CallOptions.DEFAULT, null, DecompressorRegistry.newEmptyInstance());

    assertNull(m.get(GrpcUtil.AUTHORITY_KEY));
    assertNull(m.get(GrpcUtil.USER_AGENT_KEY));
    assertNull(m.get(GrpcUtil.MESSAGE_ENCODING_KEY));
    assertNull(m.get(GrpcUtil.MESSAGE_ACCEPT_ENCODING_KEY));
  }
Пример #22
0
  @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>(
                DESCRIPTOR,
                new SerializingExecutor(Executors.newSingleThreadExecutor()),
                CallOptions.DEFAULT,
                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());

    // 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
    }
  }
Пример #23
0
  @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>(
                DESCRIPTOR,
                new SerializingExecutor(Executors.newSingleThreadExecutor()),
                CallOptions.DEFAULT,
                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());
  }