Merge "BUG-865: remove InstanceIdentifier.Builder.getIdentifier()"
[yangtools.git] / common / util / src / test / java / org / opendaylight / yangtools / util / concurrent / DeadlockDetectingListeningExecutorServiceTest.java
1 /*
2  * Copyright (c) 2014 Brocade Communications Systems, Inc. and others.  All rights reserved.
3  *
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
7  */
8
9 package org.opendaylight.yangtools.util.concurrent;
10
11 import static org.junit.Assert.*;
12
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;
19
20 import org.junit.Before;
21 import org.junit.Test;
22
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;
28
29 /**
30  * Unit tests for DeadlockDetectingListeningExecutorService.
31  *
32  * @author Thomas Pantelis
33  */
34 public class DeadlockDetectingListeningExecutorServiceTest {
35
36     interface Invoker {
37         ListenableFuture<?> invokeExecutor( ListeningExecutorService executor );
38     };
39
40     static final Invoker SUBMIT_CALLABLE = new Invoker() {
41         @Override
42         public ListenableFuture<?> invokeExecutor( ListeningExecutorService executor ) {
43             return executor.submit( new Callable<String>() {
44                 @Override
45                 public String call() throws Exception{
46                     return "foo";
47                 }
48             } );
49         }
50     };
51
52     static final Invoker SUBMIT_RUNNABLE =  new Invoker() {
53         @Override
54         public ListenableFuture<?> invokeExecutor( ListeningExecutorService executor ) {
55             return executor.submit( new Runnable() {
56                 @Override
57                 public void run(){
58                 }
59             } );
60         }
61     };
62
63     static final Invoker SUBMIT_RUNNABLE_WITH_RESULT = new Invoker() {
64         @Override
65         public ListenableFuture<?> invokeExecutor( ListeningExecutorService executor ) {
66             return executor.submit( new Runnable() {
67                 @Override
68                 public void run(){
69                 }
70             }, "foo" );
71         }
72     };
73
74     interface InitialInvoker {
75         void invokeExecutor( ListeningExecutorService executor, Runnable task );
76     };
77
78     static final InitialInvoker SUBMIT = new InitialInvoker() {
79         @Override
80         public void invokeExecutor( ListeningExecutorService executor, Runnable task ) {
81             executor.submit( task );
82         }
83     };
84
85     static final InitialInvoker EXECUTE = new InitialInvoker() {
86         @Override
87         public void invokeExecutor( ListeningExecutorService executor, Runnable task ) {
88             executor.execute( task );
89         }
90     };
91
92     @SuppressWarnings("serial")
93     public static class TestDeadlockException extends Exception {
94     }
95
96     public static Function<Void, Exception> DEADLOCK_EXECUTOR_FUNCTION = new Function<Void, Exception>() {
97         @Override
98         public Exception apply( Void notUsed ) {
99             return new TestDeadlockException();
100         }
101     };
102
103     DeadlockDetectingListeningExecutorService executor;
104
105     @Before
106     public void setup() {
107         executor = new DeadlockDetectingListeningExecutorService( Executors.newSingleThreadExecutor(),
108                                                                   DEADLOCK_EXECUTOR_FUNCTION );
109     }
110
111     @Test
112     public void testBlockingSubmitOffExecutor() throws Exception {
113
114         // Test submit with Callable.
115
116         ListenableFuture<String> future = executor.submit( new Callable<String>() {
117             @Override
118             public String call() throws Exception{
119                 return "foo";
120             }
121         } );
122
123         assertEquals( "Future result", "foo", future.get( 5, TimeUnit.SECONDS ) );
124
125         // Test submit with Runnable.
126
127         executor.submit( new Runnable() {
128             @Override
129             public void run(){
130             }
131         } ).get();
132
133         // Test submit with Runnable and value.
134
135         future = executor.submit( new Runnable() {
136             @Override
137             public void run(){
138             }
139         }, "foo" );
140
141         assertEquals( "Future result", "foo", future.get( 5, TimeUnit.SECONDS ) );
142     }
143
144     @Test
145     public void testNonBlockingSubmitOnExecutorThread() throws Throwable {
146
147         testNonBlockingSubmitOnExecutorThread( SUBMIT, SUBMIT_CALLABLE );
148         testNonBlockingSubmitOnExecutorThread( SUBMIT, SUBMIT_RUNNABLE );
149         testNonBlockingSubmitOnExecutorThread( SUBMIT, SUBMIT_RUNNABLE_WITH_RESULT );
150
151         testNonBlockingSubmitOnExecutorThread( EXECUTE, SUBMIT_CALLABLE );
152     }
153
154     void testNonBlockingSubmitOnExecutorThread( InitialInvoker initialInvoker,
155                                                 final Invoker invoker ) throws Throwable {
156
157         final AtomicReference<Throwable> caughtEx = new AtomicReference<>();
158         final CountDownLatch futureCompletedLatch = new CountDownLatch( 1 );
159
160         Runnable task = new Runnable() {
161             @SuppressWarnings({ "unchecked", "rawtypes" })
162             @Override
163             public void run() {
164
165                 Futures.addCallback( invoker.invokeExecutor( executor ), new FutureCallback() {
166                     @Override
167                     public void onSuccess( Object result ) {
168                         futureCompletedLatch.countDown();
169                     }
170
171                     @Override
172                     public void onFailure( Throwable t ) {
173                         caughtEx.set( t );
174                         futureCompletedLatch.countDown();
175                     }
176                 } );
177             }
178
179         };
180
181         initialInvoker.invokeExecutor( executor, task );
182
183         assertTrue( "Task did not complete - executor likely deadlocked",
184                     futureCompletedLatch.await( 5, TimeUnit.SECONDS ) );
185
186         if( caughtEx.get() != null ) {
187             throw caughtEx.get();
188         }
189     }
190
191     @Test
192     public void testBlockingSubmitOnExecutorThread() throws Exception {
193
194         testBlockingSubmitOnExecutorThread( SUBMIT, SUBMIT_CALLABLE );
195         testBlockingSubmitOnExecutorThread( SUBMIT, SUBMIT_RUNNABLE );
196         testBlockingSubmitOnExecutorThread( SUBMIT, SUBMIT_RUNNABLE_WITH_RESULT );
197
198         testBlockingSubmitOnExecutorThread( EXECUTE, SUBMIT_CALLABLE );
199     }
200
201     void testBlockingSubmitOnExecutorThread( InitialInvoker initialInvoker,
202                                              final Invoker invoker ) throws Exception {
203
204         final AtomicReference<Throwable> caughtEx = new AtomicReference<>();
205         final CountDownLatch latch = new CountDownLatch( 1 );
206
207         Runnable task = new Runnable() {
208             @Override
209             public void run() {
210
211                 try {
212                     invoker.invokeExecutor( executor ).get();
213                 } catch( ExecutionException e ) {
214                     caughtEx.set( e.getCause() );
215                 } catch( Throwable e ) {
216                     caughtEx.set( e );
217                 } finally {
218                     latch.countDown();
219                 }
220             }
221
222         };
223
224         initialInvoker.invokeExecutor( executor, task );
225
226         assertTrue( "Task did not complete - executor likely deadlocked",
227                     latch.await( 5, TimeUnit.SECONDS ) );
228
229         assertNotNull( "Expected exception thrown", caughtEx.get() );
230         assertEquals( "Caught exception type", TestDeadlockException.class, caughtEx.get().getClass() );
231     }
232 }