Example #1
0
 /**
  * Cancel this context and detach it as the current context from the thread.
  *
  * @param toAttach context to make current.
  * @param cause of cancellation, can be {@code null}.
  */
 public void detachAndCancel(Context toAttach, @Nullable Throwable cause) {
   try {
     detach(toAttach);
   } finally {
     cancel(cause);
   }
 }
  @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());
  }
Example #3
0
 @Test
 public void statusFromCancelled_returnCancelledIfCauseIsNull() {
   Context.CancellableContext cancellableContext = Context.current().withCancellation();
   cancellableContext.cancel(null);
   assertTrue(cancellableContext.isCancelled());
   Status status = statusFromCancelled(cancellableContext);
   assertNotNull(status);
   assertEquals(Status.Code.CANCELLED, status.getCode());
 }
Example #4
0
 @Test
 public void statusFromCancelled_returnStatusAsSetOnCtx() {
   Context.CancellableContext cancellableContext = Context.current().withCancellation();
   cancellableContext.cancel(Status.DEADLINE_EXCEEDED.withDescription("foo bar").asException());
   Status status = statusFromCancelled(cancellableContext);
   assertNotNull(status);
   assertEquals(Status.Code.DEADLINE_EXCEEDED, status.getCode());
   assertEquals("foo bar", status.getDescription());
 }
Example #5
0
 @Test
 public void statusFromCancelled_shouldReturnStatusWithCauseAttached() {
   Context.CancellableContext cancellableContext = Context.current().withCancellation();
   Throwable t = new Throwable();
   cancellableContext.cancel(t);
   Status status = statusFromCancelled(cancellableContext);
   assertNotNull(status);
   assertEquals(Status.Code.CANCELLED, status.getCode());
   assertSame(t, status.getCause());
 }
Example #6
0
  /** This is a whitebox test, to verify a special case of the implementation. */
  @Test
  public void statusFromCancelled_StatusUnknownShouldWork() {
    Context.CancellableContext cancellableContext = Context.current().withCancellation();
    Exception e = Status.UNKNOWN.asException();
    cancellableContext.cancel(e);
    assertTrue(cancellableContext.isCancelled());

    Status status = statusFromCancelled(cancellableContext);
    assertNotNull(status);
    assertEquals(Status.Code.UNKNOWN, status.getCode());
    assertSame(e, status.getCause());
  }
  @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
    }
  }
Example #8
0
 @Override
 public boolean isCancelled() {
   synchronized (this) {
     if (cancelled) {
       return true;
     }
   }
   // Detect cancellation of parent in the case where we have no listeners and
   // record it.
   if (super.isCancelled()) {
     cancel(super.cancellationCause());
     return true;
   }
   return false;
 }
Example #9
0
 /** Create a cancellable context that has a deadline. */
 private CancellableContext(
     Context parent, Deadline deadline, ScheduledExecutorService scheduler) {
   super(parent, deriveDeadline(parent, deadline), true);
   if (DEADLINE_KEY.get(this) == deadline) {
     final TimeoutException cause = new TimeoutException("context timed out");
     if (!deadline.isExpired()) {
       // The parent deadline was after the new deadline so we need to install a listener
       // on the new earlier deadline to trigger expiration for this context.
       pendingDeadline =
           deadline.runOnExpiration(
               new Runnable() {
                 @Override
                 public void run() {
                   cancel(cause);
                 }
               },
               scheduler);
     } else {
       // Cancel immediately if the deadline is already expired.
       cancel(cause);
     }
   }
   uncancellableSurrogate = new Context(this, EMPTY_ENTRIES);
 }