@Test void callbackExceptionDoesntThrow() throws Exception {
    consumer = (input) -> new Call.Base<Void>() {
      @Override protected Void doExecute() {
        throw new AssertionError();
      }

      @Override protected void doEnqueue(Callback<Void> callback) {
        callback.onError(new NullPointerException());
      }

      @Override public Call<Void> clone() {
        throw new AssertionError();
      }
    };

    ScribeSpanConsumer scribe = newScribeSpanConsumer("zipkin", consumer);

    LogEntry entry = new LogEntry();
    entry.category = "zipkin";
    entry.message = encodedSpan;

    expectSuccess(scribe, entry);

    // Storage finishes after callback so wait for it.
    await().untilAsserted(() -> assertThat(scribeMetrics.messages()).isEqualTo(1));
    assertThat(scribeMetrics.messagesDropped()).isZero();
    assertThat(scribeMetrics.bytes()).isEqualTo(bytes.length);
    assertThat(scribeMetrics.spans()).isEqualTo(1);
    assertThat(scribeMetrics.spansDropped()).isEqualTo(1);
  }
Callbacks are performed asynchronously. If they throw, it hints that we are chaining futures
when we shouldn't
zipkin-collector/scribe/src/test/java/zipkin2/collector/scribe/ScribeSpanConsumerTest.java