2 * Copyright (c) 2014 Brocade Communications Systems, Inc. and others. All rights reserved.
4 * This program and the accompanying materials are made available under the
5 * terms of the Eclipse Public License v1.0 which accompanies this distribution,
6 * and is available at http://www.eclipse.org/legal/epl-v10.html
9 package org.opendaylight.yangtools.util.concurrent;
11 import static org.junit.Assert.*;
13 import java.util.concurrent.Callable;
14 import java.util.concurrent.CountDownLatch;
15 import java.util.concurrent.ExecutionException;
16 import java.util.concurrent.Executors;
17 import java.util.concurrent.TimeUnit;
18 import java.util.concurrent.atomic.AtomicReference;
20 import org.junit.Before;
21 import org.junit.Test;
23 import com.google.common.base.Function;
24 import com.google.common.util.concurrent.FutureCallback;
25 import com.google.common.util.concurrent.Futures;
26 import com.google.common.util.concurrent.ListenableFuture;
27 import com.google.common.util.concurrent.ListeningExecutorService;
30 * Unit tests for DeadlockDetectingListeningExecutorService.
32 * @author Thomas Pantelis
34 public class DeadlockDetectingListeningExecutorServiceTest {
37 ListenableFuture<?> invokeExecutor( ListeningExecutorService executor );
40 static final Invoker SUBMIT_CALLABLE = new Invoker() {
42 public ListenableFuture<?> invokeExecutor( ListeningExecutorService executor ) {
43 return executor.submit( new Callable<String>() {
45 public String call() throws Exception{
52 static final Invoker SUBMIT_RUNNABLE = new Invoker() {
54 public ListenableFuture<?> invokeExecutor( ListeningExecutorService executor ) {
55 return executor.submit( new Runnable() {
63 static final Invoker SUBMIT_RUNNABLE_WITH_RESULT = new Invoker() {
65 public ListenableFuture<?> invokeExecutor( ListeningExecutorService executor ) {
66 return executor.submit( new Runnable() {
74 interface InitialInvoker {
75 void invokeExecutor( ListeningExecutorService executor, Runnable task );
78 static final InitialInvoker SUBMIT = new InitialInvoker() {
80 public void invokeExecutor( ListeningExecutorService executor, Runnable task ) {
81 executor.submit( task );
85 static final InitialInvoker EXECUTE = new InitialInvoker() {
87 public void invokeExecutor( ListeningExecutorService executor, Runnable task ) {
88 executor.execute( task );
92 @SuppressWarnings("serial")
93 public static class TestDeadlockException extends Exception {
96 public static Function<Void, Exception> DEADLOCK_EXECUTOR_FUNCTION = new Function<Void, Exception>() {
98 public Exception apply( Void notUsed ) {
99 return new TestDeadlockException();
103 DeadlockDetectingListeningExecutorService executor;
106 public void setup() {
107 executor = new DeadlockDetectingListeningExecutorService( Executors.newSingleThreadExecutor(),
108 DEADLOCK_EXECUTOR_FUNCTION );
112 public void testBlockingSubmitOffExecutor() throws Exception {
114 // Test submit with Callable.
116 ListenableFuture<String> future = executor.submit( new Callable<String>() {
118 public String call() throws Exception{
123 assertEquals( "Future result", "foo", future.get( 5, TimeUnit.SECONDS ) );
125 // Test submit with Runnable.
127 executor.submit( new Runnable() {
133 // Test submit with Runnable and value.
135 future = executor.submit( new Runnable() {
141 assertEquals( "Future result", "foo", future.get( 5, TimeUnit.SECONDS ) );
145 public void testNonBlockingSubmitOnExecutorThread() throws Throwable {
147 testNonBlockingSubmitOnExecutorThread( SUBMIT, SUBMIT_CALLABLE );
148 testNonBlockingSubmitOnExecutorThread( SUBMIT, SUBMIT_RUNNABLE );
149 testNonBlockingSubmitOnExecutorThread( SUBMIT, SUBMIT_RUNNABLE_WITH_RESULT );
151 testNonBlockingSubmitOnExecutorThread( EXECUTE, SUBMIT_CALLABLE );
154 void testNonBlockingSubmitOnExecutorThread( InitialInvoker initialInvoker,
155 final Invoker invoker ) throws Throwable {
157 final AtomicReference<Throwable> caughtEx = new AtomicReference<>();
158 final CountDownLatch futureCompletedLatch = new CountDownLatch( 1 );
160 Runnable task = new Runnable() {
161 @SuppressWarnings({ "unchecked", "rawtypes" })
165 Futures.addCallback( invoker.invokeExecutor( executor ), new FutureCallback() {
167 public void onSuccess( Object result ) {
168 futureCompletedLatch.countDown();
172 public void onFailure( Throwable t ) {
174 futureCompletedLatch.countDown();
181 initialInvoker.invokeExecutor( executor, task );
183 assertTrue( "Task did not complete - executor likely deadlocked",
184 futureCompletedLatch.await( 5, TimeUnit.SECONDS ) );
186 if( caughtEx.get() != null ) {
187 throw caughtEx.get();
192 public void testBlockingSubmitOnExecutorThread() throws Exception {
194 testBlockingSubmitOnExecutorThread( SUBMIT, SUBMIT_CALLABLE );
195 testBlockingSubmitOnExecutorThread( SUBMIT, SUBMIT_RUNNABLE );
196 testBlockingSubmitOnExecutorThread( SUBMIT, SUBMIT_RUNNABLE_WITH_RESULT );
198 testBlockingSubmitOnExecutorThread( EXECUTE, SUBMIT_CALLABLE );
201 void testBlockingSubmitOnExecutorThread( InitialInvoker initialInvoker,
202 final Invoker invoker ) throws Exception {
204 final AtomicReference<Throwable> caughtEx = new AtomicReference<>();
205 final CountDownLatch latch = new CountDownLatch( 1 );
207 Runnable task = new Runnable() {
212 invoker.invokeExecutor( executor ).get();
213 } catch( ExecutionException e ) {
214 caughtEx.set( e.getCause() );
215 } catch( Throwable e ) {
224 initialInvoker.invokeExecutor( executor, task );
226 assertTrue( "Task did not complete - executor likely deadlocked",
227 latch.await( 5, TimeUnit.SECONDS ) );
229 assertNotNull( "Expected exception thrown", caughtEx.get() );
230 assertEquals( "Caught exception type", TestDeadlockException.class, caughtEx.get().getClass() );