/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.kafka.clients.consumer.internals; import org.junit.Test; import java.util.concurrent.atomic.AtomicInteger; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNull; import static org.junit.Assert.assertTrue; public class RequestFutureTest { @Test public void testBasicCompletion() { RequestFuture<String> future = new RequestFuture<>(); String value = "foo"; future.complete(value); assertTrue(future.isDone()); assertEquals(value, future.value()); } @Test public void testBasicFailure() { RequestFuture<String> future = new RequestFuture<>(); RuntimeException exception = new RuntimeException(); future.raise(exception); assertTrue(future.isDone()); assertEquals(exception, future.exception()); } @Test public void testVoidFuture() { RequestFuture<Void> future = new RequestFuture<>(); future.complete(null); assertTrue(future.isDone()); assertNull(future.value()); } @Test(expected = IllegalArgumentException.class) public void testRuntimeExceptionInComplete() { RequestFuture<Exception> future = new RequestFuture<>(); future.complete(new RuntimeException()); } @Test(expected = IllegalStateException.class) public void invokeCompleteAfterAlreadyComplete() { RequestFuture<Void> future = new RequestFuture<>(); future.complete(null); future.complete(null); } @Test(expected = IllegalStateException.class) public void invokeCompleteAfterAlreadyFailed() { RequestFuture<Void> future = new RequestFuture<>(); future.raise(new RuntimeException()); future.complete(null); } @Test(expected = IllegalStateException.class) public void invokeRaiseAfterAlreadyFailed() { RequestFuture<Void> future = new RequestFuture<>(); future.raise(new RuntimeException()); future.raise(new RuntimeException()); } @Test(expected = IllegalStateException.class) public void invokeRaiseAfterAlreadyCompleted() { RequestFuture<Void> future = new RequestFuture<>(); future.complete(null); future.raise(new RuntimeException()); } @Test(expected = IllegalStateException.class) public void invokeExceptionAfterSuccess() { RequestFuture<Void> future = new RequestFuture<>(); future.complete(null); future.exception(); } @Test(expected = IllegalStateException.class) public void invokeValueAfterFailure() { RequestFuture<Void> future = new RequestFuture<>(); future.raise(new RuntimeException()); future.value(); } @Test public void listenerInvokedIfAddedBeforeFutureCompletion() { RequestFuture<Void> future = new RequestFuture<>(); MockRequestFutureListener<Void> listener = new MockRequestFutureListener<>(); future.addListener(listener); future.complete(null); assertOnSuccessInvoked(listener); } @Test public void listenerInvokedIfAddedBeforeFutureFailure() { RequestFuture<Void> future = new RequestFuture<>(); MockRequestFutureListener<Void> listener = new MockRequestFutureListener<>(); future.addListener(listener); future.raise(new RuntimeException()); assertOnFailureInvoked(listener); } @Test public void listenerInvokedIfAddedAfterFutureCompletion() { RequestFuture<Void> future = new RequestFuture<>(); future.complete(null); MockRequestFutureListener<Void> listener = new MockRequestFutureListener<>(); future.addListener(listener); assertOnSuccessInvoked(listener); } @Test public void listenerInvokedIfAddedAfterFutureFailure() { RequestFuture<Void> future = new RequestFuture<>(); future.raise(new RuntimeException()); MockRequestFutureListener<Void> listener = new MockRequestFutureListener<>(); future.addListener(listener); assertOnFailureInvoked(listener); } @Test public void listenersInvokedIfAddedBeforeAndAfterFailure() { RequestFuture<Void> future = new RequestFuture<>(); MockRequestFutureListener<Void> beforeListener = new MockRequestFutureListener<>(); future.addListener(beforeListener); future.raise(new RuntimeException()); MockRequestFutureListener<Void> afterListener = new MockRequestFutureListener<>(); future.addListener(afterListener); assertOnFailureInvoked(beforeListener); assertOnFailureInvoked(afterListener); } @Test public void listenersInvokedIfAddedBeforeAndAfterCompletion() { RequestFuture<Void> future = new RequestFuture<>(); MockRequestFutureListener<Void> beforeListener = new MockRequestFutureListener<>(); future.addListener(beforeListener); future.complete(null); MockRequestFutureListener<Void> afterListener = new MockRequestFutureListener<>(); future.addListener(afterListener); assertOnSuccessInvoked(beforeListener); assertOnSuccessInvoked(afterListener); } @Test public void testComposeSuccessCase() { RequestFuture<String> future = new RequestFuture<>(); RequestFuture<Integer> composed = future.compose(new RequestFutureAdapter<String, Integer>() { @Override public void onSuccess(String value, RequestFuture<Integer> future) { future.complete(value.length()); } }); future.complete("hello"); assertTrue(composed.isDone()); assertTrue(composed.succeeded()); assertEquals(5, (int) composed.value()); } @Test public void testComposeFailureCase() { RequestFuture<String> future = new RequestFuture<>(); RequestFuture<Integer> composed = future.compose(new RequestFutureAdapter<String, Integer>() { @Override public void onSuccess(String value, RequestFuture<Integer> future) { future.complete(value.length()); } }); RuntimeException e = new RuntimeException(); future.raise(e); assertTrue(composed.isDone()); assertTrue(composed.failed()); assertEquals(e, composed.exception()); } private static <T> void assertOnSuccessInvoked(MockRequestFutureListener<T> listener) { assertEquals(1, listener.numOnSuccessCalls.get()); assertEquals(0, listener.numOnFailureCalls.get()); } private static <T> void assertOnFailureInvoked(MockRequestFutureListener<T> listener) { assertEquals(0, listener.numOnSuccessCalls.get()); assertEquals(1, listener.numOnFailureCalls.get()); } private static class MockRequestFutureListener<T> implements RequestFutureListener<T> { private final AtomicInteger numOnSuccessCalls = new AtomicInteger(0); private final AtomicInteger numOnFailureCalls = new AtomicInteger(0); @Override public void onSuccess(T value) { numOnSuccessCalls.incrementAndGet(); } @Override public void onFailure(RuntimeException e) { numOnFailureCalls.incrementAndGet(); } } }