View Javadoc
1   /*
2    *  Licensed to the Apache Software Foundation (ASF) under one
3    *  or more contributor license agreements.  See the NOTICE file
4    *  distributed with this work for additional information
5    *  regarding copyright ownership.  The ASF licenses this file
6    *  to you under the Apache License, Version 2.0 (the
7    *  "License"); you may not use this file except in compliance
8    *  with the License.  You may obtain a copy of the License at
9    *
10   *    http://www.apache.org/licenses/LICENSE-2.0
11   *
12   *  Unless required by applicable law or agreed to in writing,
13   *  software distributed under the License is distributed on an
14   *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15   *  KIND, either express or implied.  See the License for the
16   *  specific language governing permissions and limitations
17   *  under the License.
18   *
19   */
20  package org.apache.mina.handler;
21  
22  import static org.junit.Assert.assertEquals;
23  
24  import java.lang.reflect.Field;
25  import java.util.concurrent.TimeUnit;
26  import java.util.concurrent.atomic.AtomicInteger;
27  
28  import org.apache.mina.core.filterchain.IoFilterChain;
29  import org.apache.mina.core.service.IoHandlerAdapter;
30  import org.apache.mina.core.session.DummySession;
31  import org.apache.mina.core.session.IoSession;
32  import org.apache.mina.filter.executor.ExecutorFilter;
33  import org.apache.mina.filter.executor.OrderedThreadPoolExecutor;
34  import org.apache.mina.filter.executor.PriorityThreadPoolExecutor;
35  import org.apache.mina.filter.executor.UnorderedThreadPoolExecutor;
36  import org.junit.Test;
37  
38  /**
39   * Tests that reproduces a bug as described in issue DIRMINA-1156
40   *
41   * @author Guus der Kinderen, guus.der.kinderen@gmail.com
42   * @see <a href="https://issues.apache.org/jira/browse/DIRMINA-1156">DIRMINA-1156</a>
43   */
44  public class DIRMINA1156Test
45  {
46      /**
47       * Tests the state of {@link OrderedThreadPoolExecutor#idleWorkers} and {@link OrderedThreadPoolExecutor#workers}
48       * after an {@link Error} is thrown by a session's handler that was invoked through an OrderedThreadPoolExecutor.
49       * 
50       * @throws Exception exception
51       */
52      @Test
53      public void testOrderedThreadPoolExecutorSessionHandlerThrowingError() throws Exception
54      {
55          // Set up test fixture.
56          final boolean[] filterTriggered = {false}; // Used to verify the implementation of this test (to see if the Handler is invoked at all).
57          int corePoolSize = 1; // Prevent an idle worker from being cleaned up, which would skew the results of this test.
58          DummySession session = new DummySession();
59          IoFilterChain chain = session.getFilterChain();
60          OrderedThreadPoolExecutor executor = new OrderedThreadPoolExecutor(corePoolSize,1);
61          chain.addLast("executor", new ExecutorFilter(executor));
62          session.setHandler( new IoHandlerAdapter() {
63              @Override
64              public void messageReceived(IoSession session, Object message) throws Exception {
65                  filterTriggered[0] = true;
66                  throw new Error("An Error thrown during unit testing.");
67              }
68          });
69  
70          // Execute system under test.
71          try {
72              chain.fireMessageReceived("foo");
73  
74              // Shutting down and awaiting termination ensures that test execution blocks until Handler invocation has happened.
75              executor.shutdown();
76              executor.awaitTermination(10, TimeUnit.SECONDS);
77              if (!filterTriggered[0]) {
78                  throw new IllegalStateException("Bug in test implementation: the session handler was never invoked.");
79              }
80  
81              // Verify results.
82              final Field idleWorkersField = OrderedThreadPoolExecutor.class.getDeclaredField("idleWorkers"); // Using reflection as the field is not accessible. It might be nicer to make the field package-protected for testing.
83              idleWorkersField.setAccessible(true);
84              final AtomicInteger idleWorkers = (AtomicInteger) idleWorkersField.get(executor);
85              assertEquals("After all tasks have finished, the amount of workers that are idle should equal the amount of workers, but did not.", executor.getPoolSize(), idleWorkers.get());
86          } finally {
87              // Clean up test fixture.
88              if (!executor.isShutdown()) {
89                  executor.shutdownNow();
90              }
91          }
92      }
93  
94      /**
95       * Tests the state of {@link OrderedThreadPoolExecutor#idleWorkers} and {@link OrderedThreadPoolExecutor#workers}
96       * after a {@link RuntimeException} is thrown by a session's handler that was invoked through an
97       * OrderedThreadPoolExecutor.
98       * 
99       * @throws Exception exception
100      */
101     @Test
102     public void testOrderedThreadPoolExecutorSessionHandlerThrowingRuntimeException() throws Exception
103     {
104         // Set up test fixture.
105         final boolean[] filterTriggered = {false}; // Used to verify the implementation of this test (to see if the Handler is invoked at all).
106         int corePoolSize = 1; // Prevent an idle worker from being cleaned up, which would skew the results of this test.
107         DummySession session = new DummySession();
108         IoFilterChain chain = session.getFilterChain();
109         OrderedThreadPoolExecutor executor = new OrderedThreadPoolExecutor(corePoolSize,1);
110         chain.addLast("executor", new ExecutorFilter(executor));
111         session.setHandler( new IoHandlerAdapter() {
112             @Override
113             public void messageReceived(IoSession session, Object message) throws Exception {
114                 filterTriggered[0] = true;
115                 throw new RuntimeException("A RuntimeException thrown during unit testing.");
116             }
117         });
118 
119         // Execute system under test.
120         try {
121             chain.fireMessageReceived("foo");
122 
123             // Shutting down and awaiting termination ensures that test execution blocks until Handler invocation has happened.
124             executor.shutdown();
125             executor.awaitTermination(10, TimeUnit.SECONDS);
126             if (!filterTriggered[0]) {
127                 throw new IllegalStateException("Bug in test implementation: the session handler was never invoked.");
128             }
129 
130             // Verify results.
131             final Field idleWorkersField = OrderedThreadPoolExecutor.class.getDeclaredField("idleWorkers"); // Using reflection as the field is not accessible. It might be nicer to make the field package-protected for testing.
132             idleWorkersField.setAccessible(true);
133             final AtomicInteger idleWorkers = (AtomicInteger) idleWorkersField.get(executor);
134             assertEquals("After all tasks have finished, the amount of workers that are idle should equal the amount of workers, but did not.", executor.getPoolSize(), idleWorkers.get());
135         } finally {
136             // Clean up test fixture.
137             if (!executor.isShutdown()) {
138                 executor.shutdownNow();
139             }
140         }
141     }
142 
143     /**
144      * Tests the state of {@link OrderedThreadPoolExecutor#idleWorkers} and {@link OrderedThreadPoolExecutor#workers}
145      * after a (checked) {@link Exception} is thrown by a session's handler that was invoked through an
146      * OrderedThreadPoolExecutor.
147      * 
148      * @throws Exception exception
149      */
150     @Test
151     public void testOrderedThreadPoolExecutorSessionHandlerThrowingCheckedException() throws Exception
152     {
153         // Set up test fixture.
154         final boolean[] filterTriggered = {false}; // Used to verify the implementation of this test (to see if the Handler is invoked at all).
155         int corePoolSize = 1; // Prevent an idle worker from being cleaned up, which would skew the results of this test.
156         DummySession session = new DummySession();
157         IoFilterChain chain = session.getFilterChain();
158         OrderedThreadPoolExecutor executor = new OrderedThreadPoolExecutor(corePoolSize,1);
159         chain.addLast("executor", new ExecutorFilter(executor));
160         session.setHandler( new IoHandlerAdapter() {
161             @Override
162             public void messageReceived(IoSession session, Object message) throws Exception {
163                 filterTriggered[0] = true;
164                 throw new Exception("A (checked) Exception thrown during unit testing.");
165             }
166         });
167 
168         // Execute system under test.
169         try {
170             chain.fireMessageReceived("foo");
171 
172             // Shutting down and awaiting termination ensures that test execution blocks until Handler invocation has happened.
173             executor.shutdown();
174             executor.awaitTermination(10, TimeUnit.SECONDS);
175             if (!filterTriggered[0]) {
176                 throw new IllegalStateException("Bug in test implementation: the session handler was never invoked.");
177             }
178 
179             // Verify results.
180             final Field idleWorkersField = OrderedThreadPoolExecutor.class.getDeclaredField("idleWorkers"); // Using reflection as the field is not accessible. It might be nicer to make the field package-protected for testing.
181             idleWorkersField.setAccessible(true);
182             final AtomicInteger idleWorkers = (AtomicInteger) idleWorkersField.get(executor);
183             assertEquals("After all tasks have finished, the amount of workers that are idle should equal the amount of workers, but did not.", executor.getPoolSize(), idleWorkers.get());
184         } finally {
185             // Clean up test fixture.
186             if (!executor.isShutdown()) {
187                 executor.shutdownNow();
188             }
189         }
190     }
191 
192     /**
193      * Tests the state of {@link UnorderedThreadPoolExecutor#idleWorkers} and {@link UnorderedThreadPoolExecutor#workers}
194      * after an {@link Error} is thrown by a session's handler that was invoked through an UnorderedThreadPoolExecutor.
195      * 
196      * @throws Exception exception
197      */
198     @Test
199     public void testUnorderedThreadPoolExecutorSessionHandlerThrowingError() throws Exception
200     {
201         // Set up test fixture.
202         final boolean[] filterTriggered = {false}; // Used to verify the implementation of this test (to see if the Handler is invoked at all).
203         int corePoolSize = 1; // Prevent an idle worker from being cleaned up, which would skew the results of this test.
204         DummySession session = new DummySession();
205         IoFilterChain chain = session.getFilterChain();
206         UnorderedThreadPoolExecutor executor = new UnorderedThreadPoolExecutor(corePoolSize,1);
207         chain.addLast("executor", new ExecutorFilter(executor));
208         session.setHandler( new IoHandlerAdapter() {
209             @Override
210             public void messageReceived(IoSession session, Object message) throws Exception {
211                 filterTriggered[0] = true;
212                 throw new Error("An Error thrown during unit testing.");
213             }
214         });
215 
216         // Execute system under test.
217         try {
218             chain.fireMessageReceived("foo");
219 
220             // Shutting down and awaiting termination ensures that test execution blocks until Handler invocation has happened.
221             executor.shutdown();
222             executor.awaitTermination(10, TimeUnit.SECONDS);
223             if (!filterTriggered[0]) {
224                 throw new IllegalStateException("Bug in test implementation: the session handler was never invoked.");
225             }
226 
227             // Verify results.
228             final Field idleWorkersField = UnorderedThreadPoolExecutor.class.getDeclaredField("idleWorkers"); // Using reflection as the field is not accessible. It might be nicer to make the field package-protected for testing.
229             idleWorkersField.setAccessible(true);
230             final AtomicInteger idleWorkers = (AtomicInteger) idleWorkersField.get(executor);
231             assertEquals("After all tasks have finished, the amount of workers that are idle should equal the amount of workers, but did not.", executor.getPoolSize(), idleWorkers.get());
232         } finally {
233             // Clean up test fixture.
234             if (!executor.isShutdown()) {
235                 executor.shutdownNow();
236             }
237         }
238     }
239 
240     /**
241      * Tests the state of {@link UnorderedThreadPoolExecutor#idleWorkers} and {@link UnorderedThreadPoolExecutor#workers}
242      * after a {@link RuntimeException} is thrown by a session's handler that was invoked through an
243      * UnorderedThreadPoolExecutor.
244      * 
245      * @throws Exception exception
246      */
247     @Test
248     public void testUnorderedThreadPoolExecutorSessionHandlerThrowingRuntimeException() throws Exception
249     {
250         // Set up test fixture.
251         final boolean[] filterTriggered = {false}; // Used to verify the implementation of this test (to see if the Handler is invoked at all).
252         int corePoolSize = 1; // Prevent an idle worker from being cleaned up, which would skew the results of this test.
253         DummySession session = new DummySession();
254         IoFilterChain chain = session.getFilterChain();
255         UnorderedThreadPoolExecutor executor = new UnorderedThreadPoolExecutor(corePoolSize,1);
256         chain.addLast("executor", new ExecutorFilter(executor));
257         session.setHandler( new IoHandlerAdapter() {
258             @Override
259             public void messageReceived(IoSession session, Object message) throws Exception {
260                 filterTriggered[0] = true;
261                 throw new RuntimeException("A RuntimeException thrown during unit testing.");
262             }
263         });
264 
265         // Execute system under test.
266         try {
267             chain.fireMessageReceived("foo");
268 
269             // Shutting down and awaiting termination ensures that test execution blocks until Handler invocation has happened.
270             executor.shutdown();
271             executor.awaitTermination(10, TimeUnit.SECONDS);
272             if (!filterTriggered[0]) {
273                 throw new IllegalStateException("Bug in test implementation: the session handler was never invoked.");
274             }
275 
276             // Verify results.
277             final Field idleWorkersField = UnorderedThreadPoolExecutor.class.getDeclaredField("idleWorkers"); // Using reflection as the field is not accessible. It might be nicer to make the field package-protected for testing.
278             idleWorkersField.setAccessible(true);
279             final AtomicInteger idleWorkers = (AtomicInteger) idleWorkersField.get(executor);
280             assertEquals("After all tasks have finished, the amount of workers that are idle should equal the amount of workers, but did not.", executor.getPoolSize(), idleWorkers.get());
281         } finally {
282             // Clean up test fixture.
283             if (!executor.isShutdown()) {
284                 executor.shutdownNow();
285             }
286         }
287     }
288 
289     /**
290      * Tests the state of {@link UnorderedThreadPoolExecutor#idleWorkers} and {@link UnorderedThreadPoolExecutor#workers}
291      * after a (checked) {@link Exception} is thrown by a session's handler that was invoked through an
292      * UnorderedThreadPoolExecutor.
293      * 
294      * @throws Exception exception
295      */
296     @Test
297     public void testUnorderedThreadPoolExecutorSessionHandlerThrowingCheckedException() throws Exception
298     {
299         // Set up test fixture.
300         final boolean[] filterTriggered = {false}; // Used to verify the implementation of this test (to see if the Handler is invoked at all).
301         int corePoolSize = 1; // Prevent an idle worker from being cleaned up, which would skew the results of this test.
302         DummySession session = new DummySession();
303         IoFilterChain chain = session.getFilterChain();
304         UnorderedThreadPoolExecutor executor = new UnorderedThreadPoolExecutor(corePoolSize,1);
305         chain.addLast("executor", new ExecutorFilter(executor));
306         session.setHandler( new IoHandlerAdapter() {
307             @Override
308             public void messageReceived(IoSession session, Object message) throws Exception {
309                 filterTriggered[0] = true;
310                 throw new Exception("A (checked) Exception thrown during unit testing.");
311             }
312         });
313 
314         // Execute system under test.
315         try {
316             chain.fireMessageReceived("foo");
317 
318             // Shutting down and awaiting termination ensures that test execution blocks until Handler invocation has happened.
319             executor.shutdown();
320             executor.awaitTermination(10, TimeUnit.SECONDS);
321             if (!filterTriggered[0]) {
322                 throw new IllegalStateException("Bug in test implementation: the session handler was never invoked.");
323             }
324 
325             // Verify results.
326             final Field idleWorkersField = UnorderedThreadPoolExecutor.class.getDeclaredField("idleWorkers"); // Using reflection as the field is not accessible. It might be nicer to make the field package-protected for testing.
327             idleWorkersField.setAccessible(true);
328             final AtomicInteger idleWorkers = (AtomicInteger) idleWorkersField.get(executor);
329             assertEquals("After all tasks have finished, the amount of workers that are idle should equal the amount of workers, but did not.", executor.getPoolSize(), idleWorkers.get());
330         } finally {
331             // Clean up test fixture.
332             if (!executor.isShutdown()) {
333                 executor.shutdownNow();
334             }
335         }
336     }
337 
338     /**
339      * Tests the state of {@link PriorityThreadPoolExecutor#idleWorkers} and {@link PriorityThreadPoolExecutor#workers}
340      * after an {@link Error} is thrown by a session's handler that was invoked through an PriorityThreadPoolExecutor.
341      * 
342      * @throws Exception exception
343      */
344     @Test
345     public void testPriorityThreadPoolExecutorSessionHandlerThrowingError() throws Exception
346     {
347         // Set up test fixture.
348         final boolean[] filterTriggered = {false}; // Used to verify the implementation of this test (to see if the Handler is invoked at all).
349         int corePoolSize = 1; // Prevent an idle worker from being cleaned up, which would skew the results of this test.
350         DummySession session = new DummySession();
351         IoFilterChain chain = session.getFilterChain();
352         PriorityThreadPoolExecutor executor = new PriorityThreadPoolExecutor(corePoolSize,1);
353         chain.addLast("executor", new ExecutorFilter(executor));
354         session.setHandler( new IoHandlerAdapter() {
355             @Override
356             public void messageReceived(IoSession session, Object message) throws Exception {
357                 filterTriggered[0] = true;
358                 throw new Error("An Error thrown during unit testing.");
359             }
360         });
361 
362         // Execute system under test.
363         try {
364             chain.fireMessageReceived("foo");
365 
366             // Shutting down and awaiting termination ensures that test execution blocks until Handler invocation has happened.
367             executor.shutdown();
368             executor.awaitTermination(10, TimeUnit.SECONDS);
369             if (!filterTriggered[0]) {
370                 throw new IllegalStateException("Bug in test implementation: the session handler was never invoked.");
371             }
372 
373             // Verify results.
374             final Field idleWorkersField = PriorityThreadPoolExecutor.class.getDeclaredField("idleWorkers"); // Using reflection as the field is not accessible. It might be nicer to make the field package-protected for testing.
375             idleWorkersField.setAccessible(true);
376             final AtomicInteger idleWorkers = (AtomicInteger) idleWorkersField.get(executor);
377             assertEquals("After all tasks have finished, the amount of workers that are idle should equal the amount of workers, but did not.", executor.getPoolSize(), idleWorkers.get());
378         } finally {
379             // Clean up test fixture.
380             if (!executor.isShutdown()) {
381                 executor.shutdownNow();
382             }
383         }
384     }
385 
386     /**
387      * Tests the state of {@link PriorityThreadPoolExecutor#idleWorkers} and {@link PriorityThreadPoolExecutor#workers}
388      * after a {@link RuntimeException} is thrown by a session's handler that was invoked through an
389      * PriorityThreadPoolExecutor.
390      * 
391      * @throws Exception exception
392      */
393     @Test
394     public void testPriorityThreadPoolExecutorSessionHandlerThrowingRuntimeException() throws Exception
395     {
396         // Set up test fixture.
397         final boolean[] filterTriggered = {false}; // Used to verify the implementation of this test (to see if the Handler is invoked at all).
398         int corePoolSize = 1; // Prevent an idle worker from being cleaned up, which would skew the results of this test.
399         DummySession session = new DummySession();
400         IoFilterChain chain = session.getFilterChain();
401         PriorityThreadPoolExecutor executor = new PriorityThreadPoolExecutor(corePoolSize,1);
402         chain.addLast("executor", new ExecutorFilter(executor));
403         session.setHandler( new IoHandlerAdapter() {
404             @Override
405             public void messageReceived(IoSession session, Object message) throws Exception {
406                 filterTriggered[0] = true;
407                 throw new RuntimeException("A RuntimeException thrown during unit testing.");
408             }
409         });
410 
411         // Execute system under test.
412         try {
413             chain.fireMessageReceived("foo");
414 
415             // Shutting down and awaiting termination ensures that test execution blocks until Handler invocation has happened.
416             executor.shutdown();
417             executor.awaitTermination(10, TimeUnit.SECONDS);
418             if (!filterTriggered[0]) {
419                 throw new IllegalStateException("Bug in test implementation: the session handler was never invoked.");
420             }
421 
422             // Verify results.
423             final Field idleWorkersField = PriorityThreadPoolExecutor.class.getDeclaredField("idleWorkers"); // Using reflection as the field is not accessible. It might be nicer to make the field package-protected for testing.
424             idleWorkersField.setAccessible(true);
425             final AtomicInteger idleWorkers = (AtomicInteger) idleWorkersField.get(executor);
426             assertEquals("After all tasks have finished, the amount of workers that are idle should equal the amount of workers, but did not.", executor.getPoolSize(), idleWorkers.get());
427         } finally {
428             // Clean up test fixture.
429             if (!executor.isShutdown()) {
430                 executor.shutdownNow();
431             }
432         }
433     }
434 
435     /**
436      * Tests the state of {@link PriorityThreadPoolExecutor#idleWorkers} and {@link PriorityThreadPoolExecutor#workers}
437      * after a (checked) {@link Exception} is thrown by a session's handler that was invoked through an
438      * PriorityThreadPoolExecutor.
439      * 
440      * @throws Exception exception
441      */
442     @Test
443     public void testPriorityThreadPoolExecutorSessionHandlerThrowingCheckedException() throws Exception
444     {
445         // Set up test fixture.
446         final boolean[] filterTriggered = {false}; // Used to verify the implementation of this test (to see if the Handler is invoked at all).
447         int corePoolSize = 1; // Prevent an idle worker from being cleaned up, which would skew the results of this test.
448         DummySession session = new DummySession();
449         IoFilterChain chain = session.getFilterChain();
450         PriorityThreadPoolExecutor executor = new PriorityThreadPoolExecutor(corePoolSize,1);
451         chain.addLast("executor", new ExecutorFilter(executor));
452         session.setHandler( new IoHandlerAdapter() {
453             @Override
454             public void messageReceived(IoSession session, Object message) throws Exception {
455                 filterTriggered[0] = true;
456                 throw new Exception("A (checked) Exception thrown during unit testing.");
457             }
458         });
459 
460         // Execute system under test.
461         try {
462             chain.fireMessageReceived("foo");
463 
464             // Shutting down and awaiting termination ensures that test execution blocks until Handler invocation has happened.
465             executor.shutdown();
466             executor.awaitTermination(10, TimeUnit.SECONDS);
467             if (!filterTriggered[0]) {
468                 throw new IllegalStateException("Bug in test implementation: the session handler was never invoked.");
469             }
470 
471             // Verify results.
472             final Field idleWorkersField = PriorityThreadPoolExecutor.class.getDeclaredField("idleWorkers"); // Using reflection as the field is not accessible. It might be nicer to make the field package-protected for testing.
473             idleWorkersField.setAccessible(true);
474             final AtomicInteger idleWorkers = (AtomicInteger) idleWorkersField.get(executor);
475             assertEquals("After all tasks have finished, the amount of workers that are idle should equal the amount of workers, but did not.", executor.getPoolSize(), idleWorkers.get());
476         } finally {
477             // Clean up test fixture.
478             if (!executor.isShutdown()) {
479                 executor.shutdownNow();
480             }
481         }
482     }
483 }