1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18 package org.apache.commons.lang3.concurrent;
19
20 import static org.junit.jupiter.api.Assertions.assertEquals;
21 import static org.junit.jupiter.api.Assertions.assertNull;
22 import static org.junit.jupiter.api.Assertions.assertThrows;
23
24 import java.io.IOException;
25 import java.nio.file.FileSystemException;
26 import java.util.concurrent.TimeUnit;
27 import java.util.concurrent.atomic.AtomicBoolean;
28 import java.util.concurrent.atomic.AtomicInteger;
29
30 import org.apache.commons.lang3.exception.ExceptionUtils;
31 import org.junit.jupiter.api.BeforeEach;
32 import org.junit.jupiter.api.Test;
33 import org.junit.jupiter.api.Timeout;
34 import org.junit.jupiter.api.Timeout.ThreadMode;
35 import org.junit.jupiter.params.ParameterizedTest;
36 import org.junit.jupiter.params.provider.ValueSource;
37
38
39
40
41 class AtomicSafeInitializerTest extends AbstractConcurrentInitializerTest<Object> {
42
43
44
45
46
47
48
49 private static final class AtomicSafeInitializerTestImpl extends AtomicSafeInitializer<Object> {
50
51
52 final AtomicInteger initCounter = new AtomicInteger();
53
54 @Override
55 protected Object initialize() {
56 initCounter.incrementAndGet();
57 return new Object();
58 }
59 }
60
61
62 private AtomicSafeInitializerTestImpl initializer;
63
64
65
66
67
68
69 @Override
70 protected ConcurrentInitializer<Object> createInitializer() {
71 return initializer;
72 }
73
74 @BeforeEach
75 public void setUp() {
76 initializer = new AtomicSafeInitializerTestImpl();
77 }
78
79 @Test
80 void testGetThatReturnsNullFirstTime() throws ConcurrentException {
81 final AtomicSafeInitializer<Object> initializer = new AtomicSafeInitializer<Object>() {
82
83 final AtomicBoolean firstRun = new AtomicBoolean(true);
84
85 @Override
86 protected Object initialize() {
87 if (firstRun.getAndSet(false)) {
88 return null;
89 }
90 return new Object();
91 }
92 };
93 assertNull(initializer.get());
94 assertNull(initializer.get());
95 }
96
97 @ParameterizedTest
98 @ValueSource(classes = { IOException.class, Exception.class, FileSystemException.class, ReflectiveOperationException.class, ConcurrentException.class })
99 @Timeout(value = 5, unit = TimeUnit.SECONDS, threadMode = ThreadMode.SAME_THREAD)
100 void testInitializerThrowsChecked(final Class<Exception> throwableClass) throws ConcurrentException {
101 final String message = "Initializing";
102 final AtomicSafeInitializer<Object> asi = AtomicSafeInitializer.builder().setInitializer(() -> {
103 throw throwableClass.getConstructor(String.class).newInstance(message);
104 }).get();
105 final String expected = throwableClass.getSimpleName() + ": " + message;
106 assertEquals(expected, ExceptionUtils.getRootCauseMessage(assertThrows(ConcurrentException.class, asi::get)));
107 assertEquals(expected, ExceptionUtils.getRootCauseMessage(assertThrows(ConcurrentException.class, asi::get)));
108 }
109
110 @ParameterizedTest
111 @ValueSource(classes = { IllegalStateException.class, IllegalArgumentException.class, NullPointerException.class, RuntimeException.class })
112 @Timeout(value = 5, unit = TimeUnit.SECONDS, threadMode = ThreadMode.SAME_THREAD)
113 void testInitializerThrowsUnchecked(final Class<Exception> throwableClass) throws ConcurrentException {
114 final String message = "Initializing";
115 final AtomicSafeInitializer<Object> asi = AtomicSafeInitializer.builder().setInitializer(() -> {
116 throw throwableClass.getConstructor(String.class).newInstance(message);
117 }).get();
118 assertEquals(message, assertThrows(throwableClass, asi::get).getMessage());
119 assertEquals(message, assertThrows(throwableClass, asi::get).getMessage());
120 }
121
122
123
124
125
126
127
128 @Test
129 void testNumberOfInitializeInvocations() throws ConcurrentException, InterruptedException {
130 testGetConcurrent();
131 assertEquals(1, initializer.initCounter.get(), "Wrong number of invocations");
132 }
133 }