1
2
3
4
5
6
7
8
9
10
11
12
13
14 package ch.qos.logback.classic.util;
15
16 import ch.qos.logback.core.testUtil.RandomUtil;
17 import org.junit.jupiter.api.Assertions;
18 import org.junit.jupiter.api.Disabled;
19 import org.junit.jupiter.api.Test;
20
21 import java.util.HashMap;
22 import java.util.Map;
23 import java.util.concurrent.CountDownLatch;
24
25 public class LogbackMDCAdapterTest {
26
27 final static String A_SUFFIX = "A_SUFFIX";
28 final static String B_SUFFIX = "B_SUFFIX";
29
30 int diff = RandomUtil.getPositiveInt();
31
32 private final LogbackMDCAdapter mdcAdapter = new LogbackMDCAdapter();
33
34
35
36
37
38
39 @Test
40 public void LOGBACK_442() throws InterruptedException {
41 Map<String, String> parentHM = getMapFromMDCAdapter(mdcAdapter);
42 Assertions.assertNull(parentHM);
43
44 ChildThreadForMDCAdapter childThread = new ChildThreadForMDCAdapter(mdcAdapter);
45 childThread.start();
46 childThread.join();
47 Assertions.assertTrue(childThread.successul);
48 Assertions.assertNull(childThread.childHM);
49 }
50
51 @Test
52 public void removeForNullKeyTest() {
53 mdcAdapter.remove(null);
54 }
55
56 @Test
57 public void removeInexistentKey() {
58 mdcAdapter.remove("abcdlw0");
59 }
60
61 @Test
62 @Disabled
63 public void sequenceWithGet() {
64 mdcAdapter.put("k0", "v0");
65 Map<String, String> map0 = mdcAdapter.getPropertyMap();
66 mdcAdapter.get("k0");
67 mdcAdapter.put("k1", "v1");
68
69 Map<String, String> witness = new HashMap<>();
70 witness.put("k0", "v0");
71 witness.put("k1", "v1");
72
73 Assertions.assertEquals(witness, mdcAdapter.getPropertyMap());
74 }
75
76 @Test
77 public void sequenceWithGetPropertyMap() {
78 mdcAdapter.put("k0", "v0");
79 Map<String, String> map0 = mdcAdapter.getPropertyMap();
80 mdcAdapter.put("k0", "v1");
81
82 Assertions.assertEquals("v0", map0.get("k0"));
83 }
84
85 @Test
86 public void basicGetPropertyMap() {
87 mdcAdapter.put("k0", "v0");
88 mdcAdapter.put("k1", "v1");
89
90 Map<String, String> map0 = mdcAdapter.getPropertyMap();
91 mdcAdapter.put("k0", "v1");
92
93 Assertions.assertEquals("v0", map0.get("k0"));
94 Assertions.assertEquals("v1", map0.get("k1"));
95
96 }
97
98 @Test
99 @Disabled
100 public void sequenceWithCopyContextMap() {
101 mdcAdapter.put("k0", "v0");
102 Map<String, String> map0 = mdcAdapter.getPropertyMap();
103 mdcAdapter.getCopyOfContextMap();
104 mdcAdapter.put("k1", "v1");
105
106
107 Assertions.assertSame(map0, mdcAdapter.getPropertyMap());
108 }
109
110
111
112
113
114
115
116
117
118 @Test
119 public void noCopyOnInheritenceTest() throws InterruptedException {
120 CountDownLatch countDownLatch = new CountDownLatch(1);
121 String firstKey = "x" + diff;
122 String secondKey = "o" + diff;
123 mdcAdapter.put(firstKey, firstKey + A_SUFFIX);
124
125 ChildThread childThread = new ChildThread(mdcAdapter, firstKey, secondKey, countDownLatch);
126 childThread.start();
127 countDownLatch.await();
128 mdcAdapter.put(firstKey, firstKey + B_SUFFIX);
129 childThread.join();
130
131 Assertions.assertNull(mdcAdapter.get(secondKey));
132 Assertions.assertTrue(childThread.successful);
133
134 Map<String, String> parentHM = getMapFromMDCAdapter(mdcAdapter);
135 Assertions.assertTrue(parentHM != childThread.childHM);
136
137 HashMap<String, String> parentHMWitness = new HashMap<String, String>();
138 parentHMWitness.put(firstKey, firstKey + B_SUFFIX);
139 Assertions.assertEquals(parentHMWitness, parentHM);
140
141 HashMap<String, String> childHMWitness = new HashMap<String, String>();
142 childHMWitness.put(secondKey, secondKey + A_SUFFIX);
143 Assertions.assertEquals(childHMWitness, childThread.childHM);
144
145 }
146
147
148 @Test
149 public void clearOnChildThreadShouldNotAffectParent() throws InterruptedException {
150 String firstKey = "x" + diff;
151 String secondKey = "o" + diff;
152
153 mdcAdapter.put(firstKey, firstKey + A_SUFFIX);
154 Assertions.assertEquals(firstKey + A_SUFFIX, mdcAdapter.get(firstKey));
155
156 Thread clearer = new ChildThread(mdcAdapter, firstKey, secondKey) {
157 @Override
158 public void run() {
159 mdcAdapter.clear();
160 Assertions.assertNull(mdcAdapter.get(firstKey));
161 }
162 };
163
164 clearer.start();
165 clearer.join();
166
167 Assertions.assertEquals(firstKey + A_SUFFIX, mdcAdapter.get(firstKey));
168 }
169
170
171
172 @Test
173 public void nearSimultaneousPutsShouldNotCauseConcurrentModificationException() throws InterruptedException {
174
175
176
177
178
179
180
181 for (int i = 0; i < 2048; i++) {
182 mdcAdapter.put("k" + i, "v" + i);
183 }
184
185 ChildThread childThread = new ChildThread(mdcAdapter, null, null) {
186 @Override
187 public void run() {
188 for (int i = 0; i < 16; i++) {
189 mdcAdapter.put("ck" + i, "cv" + i);
190 Thread.yield();
191 }
192 successful = true;
193 }
194 };
195
196 childThread.start();
197 Thread.sleep(1);
198 for (int i = 0; i < 16; i++) {
199 mdcAdapter.put("K" + i, "V" + i);
200 }
201 childThread.join();
202 Assertions.assertTrue(childThread.successful);
203 }
204
205 Map<String, String> getMapFromMDCAdapter(LogbackMDCAdapter lma) {
206 ThreadLocal<Map<String, String>> tlMap = lma.readWriteThreadLocalMap;
207 return tlMap.get();
208 }
209
210
211 class ChildThreadForMDCAdapter extends Thread {
212
213 LogbackMDCAdapter logbackMDCAdapter;
214 boolean successul;
215 Map<String, String> childHM;
216
217 ChildThreadForMDCAdapter(LogbackMDCAdapter logbackMDCAdapter) {
218 this.logbackMDCAdapter = logbackMDCAdapter;
219 }
220
221 @Override
222 public void run() {
223 childHM = getMapFromMDCAdapter(logbackMDCAdapter);
224 logbackMDCAdapter.get("");
225 successul = true;
226 }
227 }
228
229 class ChildThread extends Thread {
230
231 LogbackMDCAdapter logbackMDCAdapter;
232 String firstKey;
233 String secondKey;
234 boolean successful;
235 Map<String, String> childHM;
236 CountDownLatch countDownLatch;
237
238 ChildThread(LogbackMDCAdapter logbackMDCAdapter) {
239 this(logbackMDCAdapter, null, null);
240 }
241
242 ChildThread(LogbackMDCAdapter logbackMDCAdapter, String firstKey, String secondKey) {
243 this(logbackMDCAdapter, firstKey, secondKey, null);
244 }
245
246 ChildThread(LogbackMDCAdapter logbackMDCAdapter, String firstKey, String secondKey,
247 CountDownLatch countDownLatch) {
248 super("chil");
249 this.logbackMDCAdapter = logbackMDCAdapter;
250 this.firstKey = firstKey;
251 this.secondKey = secondKey;
252 this.countDownLatch = countDownLatch;
253 }
254
255 @Override
256 public void run() {
257 logbackMDCAdapter.put(secondKey, secondKey + A_SUFFIX);
258 Assertions.assertNull(logbackMDCAdapter.get(firstKey));
259 if (countDownLatch != null)
260 countDownLatch.countDown();
261 Assertions.assertNotNull(logbackMDCAdapter.get(secondKey));
262 Assertions.assertEquals(secondKey + A_SUFFIX, logbackMDCAdapter.get(secondKey));
263
264 successful = true;
265 childHM = getMapFromMDCAdapter(logbackMDCAdapter);
266 }
267 }
268 }