Add MappingCheckedFuture
[controller.git] / opendaylight / md-sal / sal-common-api / src / test / java / org / opendaylight / controller / md / sal / common / api / MappingCheckedFutureTest.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 package org.opendaylight.controller.md.sal.common.api;
9
10 import static org.junit.Assert.assertEquals;
11 import static org.junit.Assert.assertNotNull;
12 import static org.junit.Assert.assertNull;
13 import static org.junit.Assert.assertSame;
14 import static org.junit.Assert.assertTrue;
15 import static org.junit.Assert.fail;
16
17 import com.google.common.util.concurrent.CheckedFuture;
18 import com.google.common.util.concurrent.SettableFuture;
19 import java.util.concurrent.CancellationException;
20 import java.util.concurrent.CountDownLatch;
21 import java.util.concurrent.ExecutionException;
22 import java.util.concurrent.TimeUnit;
23 import java.util.concurrent.atomic.AtomicReference;
24 import org.junit.Test;
25 import org.opendaylight.yangtools.util.concurrent.ExceptionMapper;
26
27 /**
28  * Unit tests for MappingCheckedFuture.
29  *
30  * @author Thomas Pantelis
31  */
32 public class MappingCheckedFutureTest {
33
34     interface FutureInvoker {
35         void invokeGet(CheckedFuture<?,?> future) throws Exception;
36
37         Throwable extractWrappedTestEx(Exception from);
38     }
39
40     static class TestException extends Exception {
41         private static final long serialVersionUID = 1L;
42
43         TestException(final String message, final Throwable cause) {
44             super(message, cause);
45         }
46     }
47
48     static final ExceptionMapper<TestException> MAPPER = new ExceptionMapper<TestException>(
49                                                                       "Test", TestException.class) {
50
51         @Override
52         protected TestException newWithCause(final String message, final Throwable cause) {
53             return new TestException(message, cause);
54         }
55     };
56
57     static final FutureInvoker GET = new FutureInvoker() {
58         @Override
59         public void invokeGet(final CheckedFuture<?, ?> future) throws Exception {
60             future.get();
61         }
62
63         @Override
64         public Throwable extractWrappedTestEx(final Exception from) {
65             if (from instanceof ExecutionException) {
66                 return from.getCause();
67             }
68
69             return from;
70         }
71     };
72
73     static final FutureInvoker TIMED_GET = new FutureInvoker() {
74         @Override
75         public void invokeGet(final CheckedFuture<?, ?> future) throws Exception {
76             future.get(1, TimeUnit.HOURS);
77         }
78
79         @Override
80         public Throwable extractWrappedTestEx(final Exception from) {
81             if (from instanceof ExecutionException) {
82                 return from.getCause();
83             }
84
85             return from;
86         }
87     };
88
89     static final FutureInvoker CHECKED_GET = new FutureInvoker() {
90         @Override
91         public void invokeGet(final CheckedFuture<?,?> future) throws Exception {
92             future.checkedGet();
93         }
94
95         @Override
96         public Throwable extractWrappedTestEx(final Exception from) {
97             return from;
98         }
99     };
100
101     static final FutureInvoker TIMED_CHECKED_GET = new FutureInvoker() {
102         @Override
103         public void invokeGet(final CheckedFuture<?,?> future) throws Exception {
104             future.checkedGet(50, TimeUnit.MILLISECONDS);
105         }
106
107         @Override
108         public Throwable extractWrappedTestEx(final Exception from) {
109             return from;
110         }
111     };
112
113     @Test
114     public void testGet() throws Exception {
115         SettableFuture<String> delegate = SettableFuture.create();
116         MappingCheckedFuture<String,TestException> future = MappingCheckedFuture.create(delegate, MAPPER);
117         delegate.set("test");
118         assertEquals("get", "test", future.get());
119     }
120
121     @Test
122     public void testGetWithExceptions() throws Exception {
123         testExecutionException(GET, new RuntimeException());
124         testExecutionException(GET, new TestException("mock", null));
125         testCancellationException(GET);
126         testInterruptedException(GET);
127     }
128
129     @Test
130     public void testTimedGet() throws Exception {
131         SettableFuture<String> delegate = SettableFuture.create();
132         MappingCheckedFuture<String,TestException> future = MappingCheckedFuture.create(delegate, MAPPER);
133         delegate.set("test");
134         assertEquals("get", "test", future.get(50, TimeUnit.MILLISECONDS));
135     }
136
137     @Test
138     public void testTimedGetWithExceptions() throws Exception {
139         testExecutionException(TIMED_GET, new RuntimeException());
140         testCancellationException(TIMED_GET);
141         testInterruptedException(TIMED_GET);
142     }
143
144     @Test
145     public void testCheckedGetWithExceptions() throws Exception {
146         testExecutionException(CHECKED_GET, new RuntimeException());
147         testCancellationException(CHECKED_GET);
148         testInterruptedException(CHECKED_GET);
149     }
150
151     @Test
152     public void testTimedCheckedWithExceptions() throws Exception {
153         testExecutionException(TIMED_CHECKED_GET, new RuntimeException());
154         testCancellationException(TIMED_CHECKED_GET);
155         testInterruptedException(TIMED_CHECKED_GET);
156     }
157
158     @SuppressWarnings("checkstyle:illegalCatch")
159     private static void testExecutionException(final FutureInvoker invoker, final Throwable cause) {
160         SettableFuture<String> delegate = SettableFuture.create();
161         MappingCheckedFuture<String, TestException> mappingFuture = MappingCheckedFuture.create(delegate, MAPPER);
162
163         delegate.setException(cause);
164
165         try {
166             invoker.invokeGet(mappingFuture);
167             fail("Expected exception thrown");
168         } catch (Exception e) {
169             Throwable expectedTestEx = invoker.extractWrappedTestEx(e);
170             assertNotNull("Expected returned exception is null", expectedTestEx);
171             assertEquals("Exception type", TestException.class, expectedTestEx.getClass());
172
173             if (cause instanceof TestException) {
174                 assertNull("Expected null cause", expectedTestEx.getCause());
175             } else {
176                 assertSame("TestException cause", cause, expectedTestEx.getCause());
177             }
178         }
179     }
180
181     @SuppressWarnings("checkstyle:illegalCatch")
182     private static void testCancellationException(final FutureInvoker invoker) {
183         SettableFuture<String> delegate = SettableFuture.create();
184         MappingCheckedFuture<String, TestException> mappingFuture = MappingCheckedFuture.create(delegate, MAPPER);
185
186         mappingFuture.cancel(false);
187
188         try {
189             invoker.invokeGet(mappingFuture);
190             fail("Expected exception thrown");
191         } catch (Exception e) {
192             Throwable expectedTestEx = invoker.extractWrappedTestEx(e);
193             assertNotNull("Expected returned exception is null", expectedTestEx);
194             assertEquals("Exception type", TestException.class, expectedTestEx.getClass());
195             assertEquals("TestException cause type", CancellationException.class, expectedTestEx.getCause().getClass());
196         }
197     }
198
199     @SuppressWarnings("checkstyle:illegalCatch")
200     private static void testInterruptedException(final FutureInvoker invoker) throws Exception {
201         SettableFuture<String> delegate = SettableFuture.create();
202         final MappingCheckedFuture<String, TestException> mappingFuture = MappingCheckedFuture.create(delegate, MAPPER);
203
204         final AtomicReference<AssertionError> assertError = new AtomicReference<>();
205         final CountDownLatch doneLatch = new CountDownLatch(1);
206         Thread thread = new Thread() {
207             @Override
208             public void run() {
209                 try {
210                     doInvoke();
211                 } catch (AssertionError e) {
212                     assertError.set(e);
213                 } finally {
214                     doneLatch.countDown();
215                 }
216             }
217
218             void doInvoke() {
219                 try {
220                     invoker.invokeGet(mappingFuture);
221                     fail("Expected exception thrown");
222                 } catch (Exception e) {
223                     Throwable expectedTestEx = invoker.extractWrappedTestEx(e);
224                     assertNotNull("Expected returned exception is null", expectedTestEx);
225                     assertEquals("Exception type", TestException.class, expectedTestEx.getClass());
226                     assertEquals("TestException cause type", InterruptedException.class,
227                                   expectedTestEx.getCause().getClass());
228                 }
229             }
230         };
231         thread.start();
232
233         thread.interrupt();
234         assertTrue("get call completed", doneLatch.await(5, TimeUnit.SECONDS));
235
236         if (assertError.get() != null) {
237             throw assertError.get();
238         }
239     }
240 }