View Javadoc
1   /*
2    * Licensed to the Apache Software Foundation (ASF) under one or more
3    * contributor license agreements.  See the NOTICE file distributed with
4    * this work for additional information regarding copyright ownership.
5    * The ASF licenses this file to You under the Apache License, Version 2.0
6    * (the "License"); you may not use this file except in compliance with
7    * the License.  You may obtain a copy of the License at
8    *
9    *      https://www.apache.org/licenses/LICENSE-2.0
10   *
11   * Unless required by applicable law or agreed to in writing, software
12   * distributed under the License is distributed on an "AS IS" BASIS,
13   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14   * See the License for the specific language governing permissions and
15   * limitations under the License.
16   */
17  package org.apache.commons.lang3.concurrent;
18  
19  import static org.apache.commons.lang3.LangAssertions.assertIllegalArgumentException;
20  import static org.junit.jupiter.api.Assertions.assertEquals;
21  import static org.junit.jupiter.api.Assertions.assertFalse;
22  import static org.junit.jupiter.api.Assertions.assertNotNull;
23  import static org.junit.jupiter.api.Assertions.assertNull;
24  import static org.junit.jupiter.api.Assertions.assertSame;
25  import static org.junit.jupiter.api.Assertions.assertThrows;
26  import static org.junit.jupiter.api.Assertions.assertTrue;
27  
28  import java.util.concurrent.ConcurrentHashMap;
29  import java.util.concurrent.ConcurrentMap;
30  import java.util.concurrent.ExecutionException;
31  import java.util.concurrent.Future;
32  import java.util.concurrent.TimeUnit;
33  
34  import org.apache.commons.lang3.AbstractLangTest;
35  import org.easymock.EasyMock;
36  import org.junit.jupiter.api.Test;
37  
38  /**
39   * Test class for {@link ConcurrentUtils}.
40   */
41  class ConcurrentUtilsTest extends AbstractLangTest {
42      /**
43       * Tests creating a ConcurrentException with an error as cause.
44       */
45      @Test
46      void testConcurrentExceptionCauseError() {
47          assertIllegalArgumentException(() -> new ConcurrentException("An error", new Error()));
48      }
49  
50      /**
51       * Tests creating a ConcurrentException with null as cause.
52       */
53      @Test
54      void testConcurrentExceptionCauseNull() {
55          assertIllegalArgumentException(() -> new ConcurrentException(null));
56      }
57  
58      /**
59       * Tests creating a ConcurrentException with a runtime exception as cause.
60       */
61      @Test
62      void testConcurrentExceptionCauseUnchecked() {
63          assertIllegalArgumentException(() -> new ConcurrentException(new RuntimeException()));
64      }
65  
66      /**
67       * Tries to create a ConcurrentRuntimeException with an error as cause.
68       */
69      @Test
70      void testConcurrentRuntimeExceptionCauseError() {
71          assertIllegalArgumentException(() -> new ConcurrentRuntimeException("An error", new Error()));
72      }
73  
74      /**
75       * Tries to create a ConcurrentRuntimeException with null as cause.
76       */
77      @Test
78      void testConcurrentRuntimeExceptionCauseNull() {
79          assertIllegalArgumentException(() -> new ConcurrentRuntimeException(null));
80      }
81  
82      /**
83       * Tries to create a ConcurrentRuntimeException with a runtime as cause.
84       */
85      @Test
86      void testConcurrentRuntimeExceptionCauseUnchecked() {
87          assertIllegalArgumentException(() -> new ConcurrentRuntimeException(new RuntimeException()));
88      }
89  
90      /**
91       * Tests constant future.
92       *
93       * @throws Exception so we don't have to catch it
94       */
95      @Test
96      void testConstantFuture_Integer() throws Exception {
97          final Integer value = Integer.valueOf(5);
98          final Future<Integer> test = ConcurrentUtils.constantFuture(value);
99          assertTrue(test.isDone());
100         assertSame(value, test.get());
101         assertSame(value, test.get(1000, TimeUnit.SECONDS));
102         assertSame(value, test.get(1000, null));
103         assertFalse(test.isCancelled());
104         assertFalse(test.cancel(true));
105         assertFalse(test.cancel(false));
106     }
107 
108     /**
109      * Tests constant future.
110      *
111      * @throws Exception so we don't have to catch it
112      */
113     @Test
114     void testConstantFuture_null() throws Exception {
115         final Integer value = null;
116         final Future<Integer> test = ConcurrentUtils.constantFuture(value);
117         assertTrue(test.isDone());
118         assertSame(value, test.get());
119         assertSame(value, test.get(1000, TimeUnit.SECONDS));
120         assertSame(value, test.get(1000, null));
121         assertFalse(test.isCancelled());
122         assertFalse(test.cancel(true));
123         assertFalse(test.cancel(false));
124     }
125 
126     /**
127      * Tests createIfAbsent() if the map does not contain the key in question.
128      *
129      * @throws org.apache.commons.lang3.concurrent.ConcurrentException so we don't have to catch it
130      */
131     @Test
132     void testCreateIfAbsentKeyNotPresent() throws ConcurrentException {
133         final ConcurrentInitializer<Integer> init = EasyMock.createMock(ConcurrentInitializer.class);
134         final String key = "testKey";
135         final Integer value = 42;
136         EasyMock.expect(init.get()).andReturn(value);
137         EasyMock.replay(init);
138         final ConcurrentMap<String, Integer> map = new ConcurrentHashMap<>();
139         assertEquals(value, ConcurrentUtils.createIfAbsent(map, key, init), "Wrong result");
140         assertEquals(value, map.get(key), "Wrong value in map");
141         EasyMock.verify(init);
142     }
143 
144     /**
145      * Tests createIfAbsent() if the key is found in the map.
146      *
147      * @throws org.apache.commons.lang3.concurrent.ConcurrentException so we don't have to catch it
148      */
149     @Test
150     void testCreateIfAbsentKeyPresent() throws ConcurrentException {
151         final ConcurrentInitializer<Integer> init = EasyMock.createMock(ConcurrentInitializer.class);
152         EasyMock.replay(init);
153         final String key = "testKey";
154         final Integer value = 42;
155         final ConcurrentMap<String, Integer> map = new ConcurrentHashMap<>();
156         map.put(key, value);
157         assertEquals(value, ConcurrentUtils.createIfAbsent(map, key, init), "Wrong result");
158         assertEquals(value, map.get(key), "Wrong value in map");
159         EasyMock.verify(init);
160     }
161 
162     /**
163      * Tests createIfAbsent() if a null initializer is passed in.
164      *
165      * @throws org.apache.commons.lang3.concurrent.ConcurrentException so we don't have to catch it
166      */
167     @Test
168     void testCreateIfAbsentNullInit() throws ConcurrentException {
169         final ConcurrentMap<String, Integer> map = new ConcurrentHashMap<>();
170         final String key = "testKey";
171         final Integer value = 42;
172         map.put(key, value);
173         assertNull(ConcurrentUtils.createIfAbsent(map, key, null), "Wrong result");
174         assertEquals(value, map.get(key), "Map was changed");
175     }
176 
177     /**
178      * Tests createIfAbsent() if a null map is passed in.
179      *
180      * @throws org.apache.commons.lang3.concurrent.ConcurrentException so we don't have to catch it
181      */
182     @Test
183     void testCreateIfAbsentNullMap() throws ConcurrentException {
184         final ConcurrentInitializer<Integer> init = EasyMock.createMock(ConcurrentInitializer.class);
185         EasyMock.replay(init);
186         assertNull(ConcurrentUtils.createIfAbsent(null, "test", init), "Wrong result");
187         EasyMock.verify(init);
188     }
189 
190     /**
191      * Tests createIfAbsentUnchecked() if an exception is thrown.
192      *
193      * @throws org.apache.commons.lang3.concurrent.ConcurrentException so we don't have to catch it
194      */
195     @Test
196     void testCreateIfAbsentUncheckedException() throws ConcurrentException {
197         final ConcurrentInitializer<Integer> init = EasyMock.createMock(ConcurrentInitializer.class);
198         final Exception ex = new Exception();
199         EasyMock.expect(init.get()).andThrow(new ConcurrentException(ex));
200         EasyMock.replay(init);
201         final ConcurrentRuntimeException crex = assertThrows(ConcurrentRuntimeException.class,
202             () -> ConcurrentUtils.createIfAbsentUnchecked(new ConcurrentHashMap<>(), "test", init));
203         assertEquals(ex, crex.getCause(), "Wrong cause");
204         EasyMock.verify(init);
205     }
206 
207     /**
208      * Tests createIfAbsentUnchecked() if no exception is thrown.
209      */
210     @Test
211     void testCreateIfAbsentUncheckedSuccess() {
212         final String key = "testKey";
213         final Integer value = 42;
214         final ConcurrentMap<String, Integer> map = new ConcurrentHashMap<>();
215         assertEquals(value, ConcurrentUtils.createIfAbsentUnchecked(map, key, new ConstantInitializer<>(value)), "Wrong result");
216         assertEquals(value, map.get(key), "Wrong value in map");
217     }
218 
219     /**
220      * Tests extractCause() if the cause is a checked exception.
221      */
222     @Test
223     void testExtractCauseChecked() {
224         final Exception ex = new Exception("Test");
225         final ConcurrentException cex = ConcurrentUtils.extractCause(new ExecutionException(ex));
226         assertSame(ex, cex.getCause(), "Wrong cause");
227     }
228 
229     /**
230      * Tests extractCause() if the cause is an error.
231      */
232     @Test
233     void testExtractCauseError() {
234         final Error err = new AssertionError("Test");
235         final AssertionError e = assertThrows(AssertionError.class, () -> ConcurrentUtils.extractCause(new ExecutionException(err)));
236         assertEquals(err, e, "Wrong error");
237     }
238 
239     /**
240      * Tests extractCause() for a null exception.
241      */
242     @Test
243     void testExtractCauseNull() {
244         assertNull(ConcurrentUtils.extractCause(null), "Non null result");
245     }
246 
247     /**
248      * Tests extractCause() if the cause of the passed in exception is null.
249      */
250     @Test
251     void testExtractCauseNullCause() {
252         assertNull(ConcurrentUtils.extractCause(new ExecutionException("Test", null)), "Non null result");
253     }
254 
255     /**
256      * Tests extractCauseUnchecked() if the cause is a checked exception.
257      */
258     @Test
259     void testExtractCauseUncheckedChecked() {
260         final Exception ex = new Exception("Test");
261         final ConcurrentRuntimeException cex = ConcurrentUtils.extractCauseUnchecked(new ExecutionException(ex));
262         assertSame(ex, cex.getCause(), "Wrong cause");
263     }
264 
265     /**
266      * Tests extractCauseUnchecked() if the cause is an error.
267      */
268     @Test
269     void testExtractCauseUncheckedError() {
270         final Error err = new AssertionError("Test");
271         final Error e = assertThrows(Error.class, () -> ConcurrentUtils.extractCauseUnchecked(new ExecutionException(err)));
272         assertEquals(err, e, "Wrong error");
273     }
274 
275     /**
276      * Tests extractCause() if the cause is an unchecked exception.
277      */
278     @Test
279     void testExtractCauseUncheckedException() {
280         final RuntimeException rex = new RuntimeException("Test");
281         assertThrows(RuntimeException.class, () -> ConcurrentUtils.extractCause(new ExecutionException(rex)));
282     }
283 
284     /**
285      * Tests extractCauseUnchecked() for a null exception.
286      */
287     @Test
288     void testExtractCauseUncheckedNull() {
289         assertNull(ConcurrentUtils.extractCauseUnchecked(null), "Non null result");
290     }
291 
292     /**
293      * Tests extractCauseUnchecked() if the cause of the passed in exception is null.
294      */
295     @Test
296     void testExtractCauseUncheckedNullCause() {
297         assertNull(ConcurrentUtils.extractCauseUnchecked(new ExecutionException("Test", null)), "Non null result");
298     }
299 
300     /**
301      * Tests extractCauseUnchecked() if the cause is an unchecked exception.
302      */
303     @Test
304     void testExtractCauseUncheckedUncheckedException() {
305         final RuntimeException rex = new RuntimeException("Test");
306         final RuntimeException r = assertThrows(RuntimeException.class, () -> ConcurrentUtils.extractCauseUnchecked(new ExecutionException(rex)));
307         assertEquals(rex, r, "Wrong exception");
308     }
309 
310     /**
311      * Tests handleCause() if the cause is a checked exception.
312      */
313     @Test
314     void testHandleCauseChecked() {
315         final Exception ex = new Exception("Test");
316         final ConcurrentException cex = assertThrows(ConcurrentException.class, () -> ConcurrentUtils.handleCause(new ExecutionException(ex)));
317         assertEquals(ex, cex.getCause(), "Wrong cause");
318     }
319 
320     /**
321      * Tests handleCause() if the cause is an error.
322      */
323     @Test
324     void testHandleCauseError() {
325         final Error err = new AssertionError("Test");
326         final Error e = assertThrows(Error.class, () -> ConcurrentUtils.handleCause(new ExecutionException(err)));
327         assertEquals(err, e, "Wrong error");
328     }
329 
330     /**
331      * Tests handleCause() for a null parameter or a null cause. In this case the method should do nothing. We can only test
332      * that no exception is thrown.
333      *
334      * @throws org.apache.commons.lang3.concurrent.ConcurrentException so we don't have to catch it
335      */
336     @Test
337     void testHandleCauseNull() throws ConcurrentException {
338         ConcurrentUtils.handleCause(null);
339         ConcurrentUtils.handleCause(new ExecutionException("Test", null));
340     }
341 
342     /**
343      * Tests handleCauseUnchecked() if the cause is a checked exception.
344      */
345     @Test
346     void testHandleCauseUncheckedChecked() {
347         final Exception ex = new Exception("Test");
348         final ConcurrentRuntimeException crex = assertThrows(ConcurrentRuntimeException.class,
349             () -> ConcurrentUtils.handleCauseUnchecked(new ExecutionException(ex)));
350         assertEquals(ex, crex.getCause(), "Wrong cause");
351     }
352 
353     /**
354      * Tests handleCauseUnchecked() if the cause is an error.
355      */
356     @Test
357     void testHandleCauseUncheckedError() {
358         final Error err = new AssertionError("Test");
359         final Error e = assertThrows(Error.class, () -> ConcurrentUtils.handleCauseUnchecked(new ExecutionException(err)));
360         assertEquals(err, e, "Wrong error");
361     }
362 
363     /**
364      * Tests handleCause() if the cause is an unchecked exception.
365      */
366     @Test
367     void testHandleCauseUncheckedException() {
368         final RuntimeException rex = new RuntimeException("Test");
369         final RuntimeException r = assertThrows(RuntimeException.class, () -> ConcurrentUtils.handleCause(new ExecutionException(rex)));
370         assertEquals(rex, r, "Wrong exception");
371     }
372 
373     /**
374      * Tests handleCauseUnchecked() for a null parameter or a null cause. In this case the method should do nothing. We can
375      * only test that no exception is thrown.
376      */
377     @Test
378     void testHandleCauseUncheckedNull() {
379         ConcurrentUtils.handleCauseUnchecked(null);
380         ConcurrentUtils.handleCauseUnchecked(new ExecutionException("Test", null));
381     }
382 
383     /**
384      * Tests handleCauseUnchecked() if the cause is an unchecked exception.
385      */
386     @Test
387     void testHandleCauseUncheckedUncheckedException() {
388         final RuntimeException rex = new RuntimeException("Test");
389         final RuntimeException r = assertThrows(RuntimeException.class, () -> ConcurrentUtils.handleCauseUnchecked(new ExecutionException(rex)));
390         assertEquals(rex, r, "Wrong exception");
391     }
392 
393     /**
394      * Tests a successful initialize() operation.
395      *
396      * @throws org.apache.commons.lang3.concurrent.ConcurrentException so we don't have to catch it
397      */
398     @Test
399     void testInitialize() throws ConcurrentException {
400         final ConcurrentInitializer<Object> init = EasyMock.createMock(ConcurrentInitializer.class);
401         final Object result = new Object();
402         EasyMock.expect(init.get()).andReturn(result);
403         EasyMock.replay(init);
404         assertSame(result, ConcurrentUtils.initialize(init), "Wrong result object");
405         EasyMock.verify(init);
406     }
407 
408     /**
409      * Tests initialize() for a null argument.
410      *
411      * @throws org.apache.commons.lang3.concurrent.ConcurrentException so we don't have to catch it
412      */
413     @Test
414     void testInitializeNull() throws ConcurrentException {
415         assertNull(ConcurrentUtils.initialize(null), "Got a result");
416     }
417 
418     /**
419      * Tests a successful initializeUnchecked() operation.
420      *
421      * @throws org.apache.commons.lang3.concurrent.ConcurrentException so we don't have to catch it
422      */
423     @Test
424     void testInitializeUnchecked() throws ConcurrentException {
425         final ConcurrentInitializer<Object> init = EasyMock.createMock(ConcurrentInitializer.class);
426         final Object result = new Object();
427         EasyMock.expect(init.get()).andReturn(result);
428         EasyMock.replay(init);
429         assertSame(result, ConcurrentUtils.initializeUnchecked(init), "Wrong result object");
430         EasyMock.verify(init);
431     }
432 
433     /**
434      * Tests whether exceptions are correctly handled by initializeUnchecked().
435      *
436      * @throws org.apache.commons.lang3.concurrent.ConcurrentException so we don't have to catch it
437      */
438     @Test
439     void testInitializeUncheckedEx() throws ConcurrentException {
440         final ConcurrentInitializer<Object> init = EasyMock.createMock(ConcurrentInitializer.class);
441         final Exception cause = new Exception();
442         EasyMock.expect(init.get()).andThrow(new ConcurrentException(cause));
443         EasyMock.replay(init);
444         final ConcurrentRuntimeException crex = assertThrows(ConcurrentRuntimeException.class, () -> ConcurrentUtils.initializeUnchecked(init));
445         assertSame(cause, crex.getCause(), "Wrong cause");
446         EasyMock.verify(init);
447     }
448 
449     /**
450      * Tests initializeUnchecked() for a null argument.
451      */
452     @Test
453     void testInitializeUncheckedNull() {
454         assertNull(ConcurrentUtils.initializeUnchecked(null), "Got a result");
455     }
456 
457     /**
458      * Tests putIfAbsent() if the map does not contain the key in question.
459      */
460     @Test
461     void testPutIfAbsentKeyNotPresent() {
462         final String key = "testKey";
463         final Integer value = 42;
464         final ConcurrentMap<String, Integer> map = new ConcurrentHashMap<>();
465         assertEquals(value, ConcurrentUtils.putIfAbsent(map, key, value), "Wrong result");
466         assertEquals(value, map.get(key), "Wrong value in map");
467     }
468 
469     /**
470      * Tests putIfAbsent() if the map contains the key in question.
471      */
472     @Test
473     void testPutIfAbsentKeyPresent() {
474         final String key = "testKey";
475         final Integer value = 42;
476         final ConcurrentMap<String, Integer> map = new ConcurrentHashMap<>();
477         map.put(key, value);
478         assertEquals(value, ConcurrentUtils.putIfAbsent(map, key, 0), "Wrong result");
479         assertEquals(value, map.get(key), "Wrong value in map");
480     }
481 
482     /**
483      * Tests putIfAbsent() if a null map is passed in.
484      */
485     @Test
486     void testPutIfAbsentNullMap() {
487         assertNull(ConcurrentUtils.putIfAbsent(null, "test", 100), "Wrong result");
488     }
489 
490     /**
491      * Tests creating ConcurrentRuntimeException with no arguments.
492      */
493     @Test
494     void testUninitializedConcurrentRuntimeException() {
495         assertNotNull(new ConcurrentRuntimeException(), "Error creating empty ConcurrentRuntimeException");
496     }
497 }