private void expectStart(final List<ConsumerRecord<byte[], byte[]>> preexistingRecords)
     throws Exception {
   storeLog.start();
   PowerMock.expectLastCall()
       .andAnswer(
           new IAnswer<Object>() {
             @Override
             public Object answer() throws Throwable {
               for (ConsumerRecord<byte[], byte[]> rec : preexistingRecords)
                 capturedConsumedCallback.getValue().onCompletion(null, rec);
               return null;
             }
           });
 }
 private void expectStop() {
   storeLog.stop();
   PowerMock.expectLastCall();
 }
  @Test
  public void testSetFailure() throws Exception {
    expectConfigure();
    expectStart(Collections.EMPTY_LIST);
    expectStop();

    // Set offsets
    Capture<org.apache.kafka.clients.producer.Callback> callback0 = EasyMock.newCapture();
    storeLog.send(
        EasyMock.aryEq(TP0_KEY.array()),
        EasyMock.aryEq(TP0_VALUE.array()),
        EasyMock.capture(callback0));
    PowerMock.expectLastCall();
    Capture<org.apache.kafka.clients.producer.Callback> callback1 = EasyMock.newCapture();
    storeLog.send(
        EasyMock.aryEq(TP1_KEY.array()),
        EasyMock.aryEq(TP1_VALUE.array()),
        EasyMock.capture(callback1));
    PowerMock.expectLastCall();
    Capture<org.apache.kafka.clients.producer.Callback> callback2 = EasyMock.newCapture();
    storeLog.send(
        EasyMock.aryEq(TP2_KEY.array()),
        EasyMock.aryEq(TP2_VALUE.array()),
        EasyMock.capture(callback2));
    PowerMock.expectLastCall();

    PowerMock.replayAll();

    store.configure(DEFAULT_PROPS);
    store.start();

    // Set some offsets
    Map<ByteBuffer, ByteBuffer> toSet = new HashMap<>();
    toSet.put(TP0_KEY, TP0_VALUE);
    toSet.put(TP1_KEY, TP1_VALUE);
    toSet.put(TP2_KEY, TP2_VALUE);
    final AtomicBoolean invoked = new AtomicBoolean(false);
    final AtomicBoolean invokedFailure = new AtomicBoolean(false);
    Future<Void> setFuture =
        store.set(
            toSet,
            new Callback<Void>() {
              @Override
              public void onCompletion(Throwable error, Void result) {
                invoked.set(true);
                if (error != null) invokedFailure.set(true);
              }
            });
    assertFalse(setFuture.isDone());
    // Out of order callbacks shouldn't matter, should still require all to be invoked before
    // invoking the callback
    // for the store's set callback
    callback1.getValue().onCompletion(null, null);
    assertFalse(invoked.get());
    callback2.getValue().onCompletion(null, new KafkaException("bogus error"));
    assertTrue(invoked.get());
    assertTrue(invokedFailure.get());
    callback0.getValue().onCompletion(null, null);
    try {
      setFuture.get(10000, TimeUnit.MILLISECONDS);
      fail(
          "Should have seen KafkaException thrown when waiting on KafkaOffsetBackingStore.set() future");
    } catch (ExecutionException e) {
      // expected
      assertNotNull(e.getCause());
      assertTrue(e.getCause() instanceof KafkaException);
    }

    store.stop();

    PowerMock.verifyAll();
  }
  @Test
  public void testGetSet() throws Exception {
    expectConfigure();
    expectStart(Collections.EMPTY_LIST);
    expectStop();

    // First get() against an empty store
    final Capture<Callback<Void>> firstGetReadToEndCallback = EasyMock.newCapture();
    storeLog.readToEnd(EasyMock.capture(firstGetReadToEndCallback));
    PowerMock.expectLastCall()
        .andAnswer(
            new IAnswer<Object>() {
              @Override
              public Object answer() throws Throwable {
                firstGetReadToEndCallback.getValue().onCompletion(null, null);
                return null;
              }
            });

    // Set offsets
    Capture<org.apache.kafka.clients.producer.Callback> callback0 = EasyMock.newCapture();
    storeLog.send(
        EasyMock.aryEq(TP0_KEY.array()),
        EasyMock.aryEq(TP0_VALUE.array()),
        EasyMock.capture(callback0));
    PowerMock.expectLastCall();
    Capture<org.apache.kafka.clients.producer.Callback> callback1 = EasyMock.newCapture();
    storeLog.send(
        EasyMock.aryEq(TP1_KEY.array()),
        EasyMock.aryEq(TP1_VALUE.array()),
        EasyMock.capture(callback1));
    PowerMock.expectLastCall();

    // Second get() should get the produced data and return the new values
    final Capture<Callback<Void>> secondGetReadToEndCallback = EasyMock.newCapture();
    storeLog.readToEnd(EasyMock.capture(secondGetReadToEndCallback));
    PowerMock.expectLastCall()
        .andAnswer(
            new IAnswer<Object>() {
              @Override
              public Object answer() throws Throwable {
                capturedConsumedCallback
                    .getValue()
                    .onCompletion(
                        null,
                        new ConsumerRecord<>(TOPIC, 0, 0, TP0_KEY.array(), TP0_VALUE.array()));
                capturedConsumedCallback
                    .getValue()
                    .onCompletion(
                        null,
                        new ConsumerRecord<>(TOPIC, 1, 0, TP1_KEY.array(), TP1_VALUE.array()));
                secondGetReadToEndCallback.getValue().onCompletion(null, null);
                return null;
              }
            });

    // Third get() should pick up data produced by someone else and return those values
    final Capture<Callback<Void>> thirdGetReadToEndCallback = EasyMock.newCapture();
    storeLog.readToEnd(EasyMock.capture(thirdGetReadToEndCallback));
    PowerMock.expectLastCall()
        .andAnswer(
            new IAnswer<Object>() {
              @Override
              public Object answer() throws Throwable {
                capturedConsumedCallback
                    .getValue()
                    .onCompletion(
                        null,
                        new ConsumerRecord<>(TOPIC, 0, 1, TP0_KEY.array(), TP0_VALUE_NEW.array()));
                capturedConsumedCallback
                    .getValue()
                    .onCompletion(
                        null,
                        new ConsumerRecord<>(TOPIC, 1, 1, TP1_KEY.array(), TP1_VALUE_NEW.array()));
                thirdGetReadToEndCallback.getValue().onCompletion(null, null);
                return null;
              }
            });

    PowerMock.replayAll();

    store.configure(DEFAULT_PROPS);
    store.start();

    // Getting from empty store should return nulls
    final AtomicBoolean getInvokedAndPassed = new AtomicBoolean(false);
    store
        .get(
            Arrays.asList(TP0_KEY, TP1_KEY),
            new Callback<Map<ByteBuffer, ByteBuffer>>() {
              @Override
              public void onCompletion(Throwable error, Map<ByteBuffer, ByteBuffer> result) {
                // Since we didn't read them yet, these will be null
                assertEquals(null, result.get(TP0_KEY));
                assertEquals(null, result.get(TP1_KEY));
                getInvokedAndPassed.set(true);
              }
            })
        .get(10000, TimeUnit.MILLISECONDS);
    assertTrue(getInvokedAndPassed.get());

    // Set some offsets
    Map<ByteBuffer, ByteBuffer> toSet = new HashMap<>();
    toSet.put(TP0_KEY, TP0_VALUE);
    toSet.put(TP1_KEY, TP1_VALUE);
    final AtomicBoolean invoked = new AtomicBoolean(false);
    Future<Void> setFuture =
        store.set(
            toSet,
            new Callback<Void>() {
              @Override
              public void onCompletion(Throwable error, Void result) {
                invoked.set(true);
              }
            });
    assertFalse(setFuture.isDone());
    // Out of order callbacks shouldn't matter, should still require all to be invoked before
    // invoking the callback
    // for the store's set callback
    callback1.getValue().onCompletion(null, null);
    assertFalse(invoked.get());
    callback0.getValue().onCompletion(null, null);
    setFuture.get(10000, TimeUnit.MILLISECONDS);
    assertTrue(invoked.get());

    // Getting data should read to end of our published data and return it
    final AtomicBoolean secondGetInvokedAndPassed = new AtomicBoolean(false);
    store
        .get(
            Arrays.asList(TP0_KEY, TP1_KEY),
            new Callback<Map<ByteBuffer, ByteBuffer>>() {
              @Override
              public void onCompletion(Throwable error, Map<ByteBuffer, ByteBuffer> result) {
                assertEquals(TP0_VALUE, result.get(TP0_KEY));
                assertEquals(TP1_VALUE, result.get(TP1_KEY));
                secondGetInvokedAndPassed.set(true);
              }
            })
        .get(10000, TimeUnit.MILLISECONDS);
    assertTrue(secondGetInvokedAndPassed.get());

    // Getting data should read to end of our published data and return it
    final AtomicBoolean thirdGetInvokedAndPassed = new AtomicBoolean(false);
    store
        .get(
            Arrays.asList(TP0_KEY, TP1_KEY),
            new Callback<Map<ByteBuffer, ByteBuffer>>() {
              @Override
              public void onCompletion(Throwable error, Map<ByteBuffer, ByteBuffer> result) {
                assertEquals(TP0_VALUE_NEW, result.get(TP0_KEY));
                assertEquals(TP1_VALUE_NEW, result.get(TP1_KEY));
                thirdGetInvokedAndPassed.set(true);
              }
            })
        .get(10000, TimeUnit.MILLISECONDS);
    assertTrue(thirdGetInvokedAndPassed.get());

    store.stop();

    PowerMock.verifyAll();
  }