/* * COMSAT * Copyright (C) 2013-2016, Parallel Universe Software Co. All rights reserved. * * This program and the accompanying materials are dual-licensed under * either the terms of the Eclipse Public License v1.0 as published by * the Eclipse Foundation * * or (per the licensee's choosing) * * under the terms of the GNU Lesser General Public License version 3.0 * as published by the Free Software Foundation. */ package co.paralleluniverse.fibers.kafka; import co.paralleluniverse.fibers.Fiber; import co.paralleluniverse.fibers.SuspendExecution; import co.paralleluniverse.strands.SuspendableRunnable; import org.apache.kafka.clients.producer.Callback; import org.apache.kafka.clients.producer.MockProducer; import org.apache.kafka.clients.producer.ProducerRecord; import org.apache.kafka.clients.producer.RecordMetadata; import org.apache.kafka.common.serialization.ByteArraySerializer; import org.junit.Before; import org.junit.Test; import java.util.concurrent.ExecutionException; import java.util.concurrent.Future; import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeoutException; import java.util.concurrent.atomic.AtomicReference; import static org.junit.Assert.assertEquals; import static org.junit.Assert.fail; public class FiberKafkaProducerTest { private MockProducer<byte[], byte[]> mockProducer; private FiberKafkaProducer<byte[], byte[]> fiberProducer; private co.paralleluniverse.strands.concurrent.Phaser phaser; @Before public void setUp() { mockProducer = new MockProducer<>(false, new ByteArraySerializer(), new ByteArraySerializer()); fiberProducer = new FiberKafkaProducer<>(mockProducer); phaser = new co.paralleluniverse.strands.concurrent.Phaser(2); } @Test public void testSuccessfulSendWithoutCallback() throws InterruptedException, TimeoutException, ExecutionException { Fiber<Void> fiber = new Fiber<>(new SuspendableRunnable() { @Override public void run() throws SuspendExecution, InterruptedException { Future<RecordMetadata> f = fiberProducer.send(new ProducerRecord<>("Topic", "Key".getBytes(), "Value".getBytes())); Future<RecordMetadata> f2 = fiberProducer.send(new ProducerRecord<>("Topic", "Key".getBytes(), "Value".getBytes())); phaser.arrive(); try { RecordMetadata recordMetadata = f.get(); assertEquals("Topic", recordMetadata.topic()); assertEquals(0, recordMetadata.offset()); assertEquals(0, recordMetadata.partition()); RecordMetadata recordMetadata2 = f2.get(); assertEquals("Topic", recordMetadata2.topic()); assertEquals(1, recordMetadata2.offset()); assertEquals(0, recordMetadata2.partition()); } catch (ExecutionException e) { fail(); } } }); fiber.start(); phaser.arriveAndAwaitAdvance(); mockProducer.completeNext(); mockProducer.completeNext(); fiber.join(5000, TimeUnit.MILLISECONDS); } @Test public void testSuccessfulSendWithCallback() throws ExecutionException, InterruptedException, TimeoutException { Fiber<Void> fiber = new Fiber<>(new SuspendableRunnable() { @Override public void run() throws SuspendExecution, InterruptedException { final AtomicReference<RecordMetadata> callbackMetadata = new AtomicReference<>(null); final AtomicReference<RecordMetadata> callbackMetadata2 = new AtomicReference<>(null); Future<RecordMetadata> f = fiberProducer.send(new ProducerRecord<>("Topic", "Key".getBytes(), "Value".getBytes()), new Callback() { @Override public void onCompletion(RecordMetadata metadata, Exception exception) { callbackMetadata.set(metadata); } }); Future<RecordMetadata> f2 = fiberProducer.send(new ProducerRecord<>("Topic", "Key".getBytes(), "Value".getBytes()), new Callback() { @Override public void onCompletion(RecordMetadata metadata, Exception exception) { callbackMetadata2.set(metadata); } }); phaser.arriveAndAwaitAdvance(); try { RecordMetadata recordMetadata = f.get(); assertEquals("Topic", recordMetadata.topic()); assertEquals(0, recordMetadata.offset()); assertEquals(0, recordMetadata.partition()); RecordMetadata recordMetadata2 = f2.get(); assertEquals("Topic", recordMetadata2.topic()); assertEquals(1, recordMetadata2.offset()); assertEquals(0, recordMetadata2.partition()); } catch (ExecutionException e) { fail(); } phaser.arriveAndAwaitAdvance(); assertEquals("Topic", callbackMetadata.get().topic()); assertEquals(0, callbackMetadata.get().offset()); assertEquals(0, callbackMetadata.get().partition()); assertEquals("Topic", callbackMetadata2.get().topic()); assertEquals(1, callbackMetadata2.get().offset()); assertEquals(0, callbackMetadata2.get().partition()); } }); fiber.start(); phaser.arriveAndAwaitAdvance(); mockProducer.completeNext(); mockProducer.completeNext(); phaser.arrive(); fiber.join(5000, TimeUnit.MILLISECONDS); } @Test public void testErrorSendWithoutCallback() throws ExecutionException, InterruptedException, TimeoutException { final RuntimeException exception = new RuntimeException("Error"); Fiber<Void> fiber = new Fiber<>(new SuspendableRunnable() { @Override public void run() throws SuspendExecution, InterruptedException { Future<RecordMetadata> f = fiberProducer.send(new ProducerRecord<>("Topic", "Key".getBytes(), "Value".getBytes())); phaser.arrive(); try { f.get(); fail("Send should have failed."); } catch (ExecutionException e) { assertEquals(exception, e.getCause()); } } }); fiber.start(); phaser.arriveAndAwaitAdvance(); mockProducer.errorNext(exception); fiber.join(5000, TimeUnit.MILLISECONDS); } @Test public void testErrorSendWithCallback() throws ExecutionException, InterruptedException, TimeoutException { final RuntimeException exception = new RuntimeException("Error"); final AtomicReference<Exception> exceptionReference = new AtomicReference<>(null); Fiber<Void> fiber = new Fiber<>(new SuspendableRunnable() { @Override public void run() throws SuspendExecution, InterruptedException { Future<RecordMetadata> f = fiberProducer.send(new ProducerRecord<>("Topic", "Key".getBytes(), "Value".getBytes()), new Callback() { @Override public void onCompletion(RecordMetadata metadata, Exception exception) { exceptionReference.set(exception); } }); phaser.arriveAndAwaitAdvance(); try { f.get(); fail("Send should have failed."); } catch (ExecutionException e) { assertEquals(exception, e.getCause()); } phaser.arriveAndAwaitAdvance(); assertEquals(exception, exceptionReference.get()); } }); fiber.start(); phaser.arriveAndAwaitAdvance(); mockProducer.errorNext(exception); phaser.arrive(); fiber.join(5000, TimeUnit.MILLISECONDS); } }