a617abd69c4447de2bd6b59555399136fc6e9e06
[sdc.git] /
1 /*
2  * Copyright © 2016-2017 European Support Limited
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16
17 package org.openecomp.sdc.logging.slf4j;
18
19 import org.openecomp.sdc.logging.provider.LoggingContextService;
20 import org.testng.annotations.Test;
21
22 import java.util.UUID;
23 import java.util.concurrent.atomic.AtomicBoolean;
24
25 import static org.testng.Assert.assertEquals;
26 import static org.testng.Assert.assertNull;
27 import static org.testng.Assert.assertTrue;
28
29 /**
30  * @author EVITALIY
31  * @since 08 Jan 18
32  */
33 public class RunnableContextPropagationTest extends BaseContextPropagationTest {
34
35     @Test(enabled = ENABLED, dataProvider = PROVIDER)
36     public void contextNotCopiedToChildThreadByDefault(LoggingContextService ctx)
37             throws InterruptedException {
38
39         String random = UUID.randomUUID().toString();
40         ctx.put(KEY, random);
41
42         AtomicBoolean complete = new AtomicBoolean(false);
43
44         // create thread right away without copying context
45         Thread thread = new Thread(() -> {
46             assertNull(ctx.get(KEY), "Data unexpectedly copied to a child thread. " +
47                     "Are you using an old version of SLF4J diagnostic context implementation (e.g. logback)?");
48             complete.set(true);
49         });
50
51         thread.start();
52         thread.join();
53
54         assertEquals(ctx.get(KEY), random, EXPECT_RETAINED_IN_CURRENT);
55         assertTrue(complete.get(), EXPECT_INNER_RUN);
56     }
57
58     @Test(enabled = ENABLED, dataProvider = PROVIDER)
59     public void contextCopiedWhenToRunnableCalled(LoggingContextService ctx)
60             throws InterruptedException {
61
62         String uuid = UUID.randomUUID().toString();
63         ctx.put(KEY, uuid);
64
65         AtomicBoolean complete = new AtomicBoolean(false);
66
67         // pass the runnable to the context service first
68         Thread thread = new Thread(ctx.toRunnable(() -> {
69             assertEquals(ctx.get(KEY), uuid, EXPECT_PROPAGATED_TO_CHILD);
70             complete.set(true);
71         }));
72
73         thread.start();
74         thread.join();
75
76         assertEquals(ctx.get(KEY), uuid, EXPECT_RETAINED_IN_CURRENT);
77         assertTrue(complete.get(), EXPECT_INNER_RUN);
78     }
79
80     @Test(enabled = ENABLED, dataProvider = PROVIDER)
81     public void copiedContextRetainedEvenWhenAnotherPushed(LoggingContextService ctx)
82             throws InterruptedException {
83
84         String innerRandom = UUID.randomUUID().toString();
85         ctx.put(KEY, innerRandom);
86
87         AtomicBoolean innerComplete = new AtomicBoolean(false);
88
89         // should run with the context of main thread
90         Runnable inner = ctx.toRunnable(() -> {
91             assertEquals(ctx.get(KEY), innerRandom, EXPECT_PROPAGATED_TO_CHILD);
92             innerComplete.set(true);
93         });
94
95         // pushes its context, but the inner must run with its own context
96         AtomicBoolean outerComplete = new AtomicBoolean(false);
97         Thread outer = new Thread(() -> {
98             String outerUuid = UUID.randomUUID().toString();
99             ctx.put(KEY, outerUuid);
100             inner.run();
101             assertEquals(ctx.get(KEY), outerUuid, EXPECT_REPLACED_WITH_STORED);
102             outerComplete.set(true);
103         });
104
105         outer.start();
106         outer.join();
107
108         assertEquals(ctx.get(KEY), innerRandom, EXPECT_RETAINED_IN_CURRENT);
109         assertTrue(outerComplete.get(), EXPECT_OUTER_RUN);
110         assertTrue(innerComplete.get(), EXPECT_INNER_RUN);
111     }
112
113     @Test(enabled = ENABLED, dataProvider = PROVIDER)
114     public void contextRemainsEmptyWhenParentWasEmpty(LoggingContextService ctx)
115             throws InterruptedException {
116
117         ctx.remove(KEY);
118         assertNull(ctx.get(KEY), EXPECT_EMPTY);
119
120         final AtomicBoolean complete = new AtomicBoolean(false);
121         Runnable runnable = ctx.toRunnable(() -> {
122             assertNull(ctx.get(KEY), EXPECT_EMPTY);
123             complete.set(true);
124         });
125
126         Thread thread = new Thread(runnable);
127         thread.start();
128         thread.join();
129
130         assertNull(ctx.get(KEY), EXPECT_EMPTY);
131         assertTrue(complete.get(), EXPECT_INNER_RUN);
132     }
133
134     @Test(enabled = ENABLED, dataProvider = PROVIDER)
135     public void childThreadCleanedUpAfterRunnableRuns(LoggingContextService ctx)
136             throws Exception {
137
138         String innerRandom = UUID.randomUUID().toString();
139         ctx.put(KEY, innerRandom);
140
141         AtomicBoolean innerComplete = new AtomicBoolean(false);
142         // should run with the context of main thread
143         Runnable inner = ctx.toRunnable(() -> {
144             assertEquals(ctx.get(KEY), innerRandom, EXPECT_PROPAGATED_TO_CHILD);
145             innerComplete.set(true);
146         });
147
148         // pushes its own context, but runs the inner
149         AtomicBoolean outerComplete = new AtomicBoolean(false);
150         Thread outer = new Thread(() -> {
151             assertNull(ctx.get(KEY), EXPECT_NOT_COPIED);
152             inner.run();
153             assertNull(ctx.get(KEY), EXPECT_REMAIN_EMPTY);
154             outerComplete.set(true);
155         });
156
157         outer.start();
158         outer.join();
159
160         assertEquals(ctx.get(KEY), innerRandom, EXPECT_RETAINED_IN_PARENT);
161         assertTrue(outerComplete.get(), EXPECT_OUTER_RUN);
162         assertTrue(innerComplete.get(), EXPECT_INNER_RUN);
163     }
164
165     @Test(enabled = ENABLED, dataProvider = PROVIDER)
166     public void childThreadCleanedUpAfterException(LoggingContextService ctx)
167             throws Exception {
168
169         String innerRandom = UUID.randomUUID().toString();
170         ctx.put(KEY, innerRandom);
171
172         // should run with the context of main thread
173         AtomicBoolean innerComplete = new AtomicBoolean(false);
174         Runnable inner = ctx.toRunnable(() -> {
175             assertEquals(ctx.get(KEY), innerRandom, EXPECT_PROPAGATED_TO_CHILD);
176             innerComplete.set(true);
177             throw new IllegalArgumentException();
178         });
179
180         // pushes its own context, but runs the inner runnable
181         AtomicBoolean outerComplete = new AtomicBoolean(false);
182         AtomicBoolean exceptionThrown = new AtomicBoolean(false);
183         Thread outer = new Thread(() -> {
184
185             String outerUuid = UUID.randomUUID().toString();
186             ctx.put(KEY, outerUuid);
187             assertEquals(ctx.get(KEY), outerUuid, EXPECT_POPULATED);
188
189             try {
190                 inner.run();
191             } catch (IllegalArgumentException e) {
192                 exceptionThrown.set(true);
193             } finally {
194                 assertEquals(ctx.get(KEY), outerUuid, EXPECT_REVERTED_ON_EXCEPTION);
195                 outerComplete.set(true);
196             }
197         });
198
199         outer.start();
200         outer.join();
201
202         assertEquals(ctx.get(KEY), innerRandom, EXPECT_RETAINED_IN_PARENT);
203         assertTrue(outerComplete.get(), EXPECT_OUTER_RUN);
204         assertTrue(innerComplete.get(), EXPECT_INNER_RUN);
205         assertTrue(exceptionThrown.get(), EXPECT_EXCEPTION_FROM_INNER);
206     }
207
208
209 }