@Test
public void testObserverErrorCancelsCall() throws Throwable {

  final RuntimeException expectedCause = new RuntimeException("some error");
  final SettableApiFuture<Throwable> actualErrorF = SettableApiFuture.create();
  ResponseObserver<Money> moneyObserver =
      new StateCheckingResponseObserver<Money>() {
        @Override
        protected void onStartImpl(StreamController controller) {}
        @Override
        protected void onResponseImpl(Money response) {
          throw expectedCause;
        }
        @Override
        protected void onErrorImpl(Throwable t) {
          actualErrorF.set(t);
        }
        @Override
        protected void onCompleteImpl() {
          actualErrorF.set(null);
        }
      };
  streamingCallable.call(DEFAULT_REQUEST, moneyObserver);
  Throwable actualError = actualErrorF.get(500, TimeUnit.MILLISECONDS);
  Truth.assertThat(actualError).isInstanceOf(ApiException.class);
  Truth.assertThat(((ApiException) actualError).getStatusCode().getCode())
      .isEqualTo(StatusCode.Code.CANCELLED);
  // grpc is responsible for the immediate cancellation
  Truth.assertThat(actualError.getCause()).isInstanceOf(StatusRuntimeException.class);
  // and the client error is cause for grpc to cancel it
  Truth.assertThat(actualError.getCause().getCause()).isSameInstanceAs(expectedCause);
}