@Test
  public void testStartStop() throws Exception {
    expectConfigure();
    expectStart(Collections.EMPTY_LIST);
    expectStop();

    PowerMock.replayAll();

    store.configure(DEFAULT_PROPS);
    assertEquals(TOPIC, capturedTopic.getValue());
    assertEquals(
        "org.apache.kafka.common.serialization.ByteArraySerializer",
        capturedProducerProps.getValue().get(ProducerConfig.KEY_SERIALIZER_CLASS_CONFIG));
    assertEquals(
        "org.apache.kafka.common.serialization.ByteArraySerializer",
        capturedProducerProps.getValue().get(ProducerConfig.VALUE_SERIALIZER_CLASS_CONFIG));
    assertEquals(
        "org.apache.kafka.common.serialization.ByteArrayDeserializer",
        capturedConsumerProps.getValue().get(ConsumerConfig.KEY_DESERIALIZER_CLASS_CONFIG));
    assertEquals(
        "org.apache.kafka.common.serialization.ByteArrayDeserializer",
        capturedConsumerProps.getValue().get(ConsumerConfig.VALUE_DESERIALIZER_CLASS_CONFIG));

    store.start();
    store.stop();

    PowerMock.verifyAll();
  }
  @Test
  public void testReloadOnStart() throws Exception {
    expectConfigure();
    expectStart(
        Arrays.asList(
            new ConsumerRecord<>(TOPIC, 0, 0, TP0_KEY.array(), TP0_VALUE.array()),
            new ConsumerRecord<>(TOPIC, 1, 0, TP1_KEY.array(), TP1_VALUE.array()),
            new ConsumerRecord<>(TOPIC, 0, 1, TP0_KEY.array(), TP0_VALUE_NEW.array()),
            new ConsumerRecord<>(TOPIC, 1, 1, TP1_KEY.array(), TP1_VALUE_NEW.array())));
    expectStop();

    PowerMock.replayAll();

    store.configure(DEFAULT_PROPS);
    store.start();
    HashMap<ByteBuffer, ByteBuffer> data = Whitebox.getInternalState(store, "data");
    assertEquals(TP0_VALUE_NEW, data.get(TP0_KEY));
    assertEquals(TP1_VALUE_NEW, data.get(TP1_KEY));

    store.stop();

    PowerMock.verifyAll();
  }
 @Test(expected = ConnectException.class)
 public void testMissingTopic() {
   store = new KafkaOffsetBackingStore();
   store.configure(Collections.<String, Object>emptyMap());
 }
  @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();
  }