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