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(); }