/* * Copyright (c) 2014 Brocade Communications Systems, Inc. and others. All rights reserved. * * This program and the accompanying materials are made available under the * terms of the Eclipse Public License v1.0 which accompanies this distribution, * and is available at http://www.eclipse.org/legal/epl-v10.html */ package org.opendaylight.yangtools.util.concurrent; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertNull; import static org.junit.Assert.assertSame; import static org.junit.Assert.fail; import com.google.common.util.concurrent.CheckedFuture; import com.google.common.util.concurrent.SettableFuture; import java.util.concurrent.CancellationException; import java.util.concurrent.CountDownLatch; import java.util.concurrent.ExecutionException; import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicReference; import org.junit.Test; /** * Unit tests for MappingCheckedFuture. * * @author Thomas Pantelis */ public class MappingCheckedFutureTest { interface FutureInvoker { void invokeGet( CheckedFuture<?,?> future ) throws Exception; Throwable extractWrappedTestEx( Exception from ); } @SuppressWarnings("serial") static class TestException extends Exception { TestException( final String message, final Throwable cause ) { super( message, cause ); } } static final ExceptionMapper<TestException> MAPPER = new ExceptionMapper<TestException>( "Test", TestException.class ) { @Override protected TestException newWithCause( final String message, final Throwable cause ) { return new TestException( message, cause ); } }; static final FutureInvoker GET = new FutureInvoker() { @Override public void invokeGet( final CheckedFuture<?,?> future ) throws Exception { future.get(); } @Override public Throwable extractWrappedTestEx( final Exception from ) { if (from instanceof ExecutionException ) { return from.getCause(); } return from; } }; static final FutureInvoker TIMED_GET = new FutureInvoker() { @Override public void invokeGet( final CheckedFuture<?,?> future ) throws Exception { future.get( 1, TimeUnit.HOURS ); } @Override public Throwable extractWrappedTestEx( final Exception from ) { if (from instanceof ExecutionException ) { return from.getCause(); } return from; } }; static final FutureInvoker CHECKED_GET = new FutureInvoker() { @Override public void invokeGet( final CheckedFuture<?,?> future ) throws Exception { future.checkedGet(); } @Override public Throwable extractWrappedTestEx( final Exception from ) { return from; } }; static final FutureInvoker TIMED_CHECKED_GET = new FutureInvoker() { @Override public void invokeGet( final CheckedFuture<?,?> future ) throws Exception { future.checkedGet( 50, TimeUnit.MILLISECONDS ); } @Override public Throwable extractWrappedTestEx( final Exception from ) { return from; } }; @Test public void testGet() throws Exception { SettableFuture<String> delegate = SettableFuture.create(); MappingCheckedFuture<String,TestException> future = MappingCheckedFuture.create( delegate, MAPPER ); delegate.set( "test" ); assertEquals( "get", "test", future.get() ); } @Test public void testGetWithExceptions() throws Exception { testExecutionException( GET, new RuntimeException() ); testExecutionException( GET, new TestException( "mock", null ) ); testCancellationException( GET ); testInterruptedException( GET ); } @Test public void testTimedGet() throws Exception { SettableFuture<String> delegate = SettableFuture.create(); MappingCheckedFuture<String,TestException> future = MappingCheckedFuture.create( delegate, MAPPER ); delegate.set( "test" ); assertEquals( "get", "test", future.get( 50, TimeUnit.MILLISECONDS ) ); } @Test public void testTimedGetWithExceptions() throws Exception { testExecutionException( TIMED_GET, new RuntimeException() ); testCancellationException( TIMED_GET ); testInterruptedException( TIMED_GET ); } @Test public void testCheckedGetWithExceptions() throws Exception { testExecutionException( CHECKED_GET, new RuntimeException() ); testCancellationException( CHECKED_GET ); testInterruptedException( CHECKED_GET ); } @Test public void testTimedCheckedWithExceptions() throws Exception { testExecutionException( TIMED_CHECKED_GET, new RuntimeException() ); testCancellationException( TIMED_CHECKED_GET ); testInterruptedException( TIMED_CHECKED_GET ); } private static void testExecutionException( final FutureInvoker invoker, final Throwable cause ) { SettableFuture<String> delegate = SettableFuture.create(); MappingCheckedFuture<String,TestException> mappingFuture = MappingCheckedFuture.create( delegate, MAPPER ); delegate.setException( cause ); try { invoker.invokeGet( mappingFuture ); fail( "Expected exception thrown" ); } catch( Exception e ) { Throwable expectedTestEx = invoker.extractWrappedTestEx( e ); assertNotNull( "Expected returned exception is null", expectedTestEx ); assertEquals( "Exception type", TestException.class, expectedTestEx.getClass() ); if (cause instanceof TestException ) { assertNull( "Expected null cause", expectedTestEx.getCause() ); } else { assertSame( "TestException cause", cause, expectedTestEx.getCause() ); } } } private static void testCancellationException( final FutureInvoker invoker ) { SettableFuture<String> delegate = SettableFuture.create(); MappingCheckedFuture<String,TestException> mappingFuture = MappingCheckedFuture.create( delegate, MAPPER ); mappingFuture.cancel( false ); try { invoker.invokeGet( mappingFuture ); fail( "Expected exception thrown" ); } catch( Exception e ) { Throwable expectedTestEx = invoker.extractWrappedTestEx( e ); assertNotNull( "Expected returned exception is null", expectedTestEx ); assertEquals( "Exception type", TestException.class, expectedTestEx.getClass() ); assertEquals( "TestException cause type", CancellationException.class, expectedTestEx.getCause().getClass() ); } } private static void testInterruptedException( final FutureInvoker invoker ) throws Exception { SettableFuture<String> delegate = SettableFuture.create(); final MappingCheckedFuture<String,TestException> mappingFuture = MappingCheckedFuture.create( delegate, MAPPER ); final AtomicReference<AssertionError> assertError = new AtomicReference<>(); final CountDownLatch doneLatch = new CountDownLatch( 1 ); Thread thread = new Thread() { @Override public void run() { try { doInvoke(); } catch( AssertionError e ) { assertError.set( e ); } finally { doneLatch.countDown(); } } void doInvoke() { try { invoker.invokeGet( mappingFuture ); fail( "Expected exception thrown" ); } catch( Exception e ) { Throwable expectedTestEx = invoker.extractWrappedTestEx( e ); assertNotNull( "Expected returned exception is null", expectedTestEx ); assertEquals( "Exception type", TestException.class, expectedTestEx.getClass() ); assertEquals( "TestException cause type", InterruptedException.class, expectedTestEx.getCause().getClass() ); } } }; thread.start(); thread.interrupt(); assertEquals( "get call completed", true, doneLatch.await( 5, TimeUnit.SECONDS ) ); if (assertError.get() != null ) { throw assertError.get(); } } }