fcd1a562523d2c978e0e56f7263d39b81945d69c
[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 static org.openecomp.sdc.logging.slf4j.ContextPropagationTestHelper.assertContextEmpty;
20 import static org.openecomp.sdc.logging.slf4j.ContextPropagationTestHelper.assertContextFields;
21 import static org.openecomp.sdc.logging.slf4j.ContextPropagationTestHelper.putUniqueValues;
22 import static org.testng.Assert.assertTrue;
23
24 import java.util.Map;
25 import java.util.concurrent.atomic.AtomicBoolean;
26 import org.openecomp.sdc.logging.slf4j.SLF4JLoggingServiceProvider.ContextField;
27 import org.openecomp.sdc.logging.spi.LoggingContextService;
28 import org.testng.annotations.Test;
29
30 /**
31  * @author evitaliy
32  * @since 08 Jan 18
33  */
34 public class RunnableContextPropagationTest extends BaseContextPropagationTest {
35
36     @Test(enabled = ENABLED, dataProvider = PROVIDER)
37     public void contextNotCopiedToChildThreadByDefault(LoggingContextService ctx)
38             throws InterruptedException {
39
40         Map<ContextField, String> values = putUniqueValues(ctx);
41         AtomicBoolean complete = new AtomicBoolean(false);
42
43         // create thread right away without copying context
44         Thread thread = new Thread(() -> {
45             assertContextEmpty("Data unexpectedly copied to a child thread. " +
46                     "Are you using an old version of SLF4J diagnostic context implementation (e.g. logback)?");
47             complete.set(true);
48         });
49
50         thread.start();
51         thread.join();
52
53         assertContextFields(values, EXPECT_RETAINED_IN_CURRENT);
54         assertTrue(complete.get(), EXPECT_INNER_RUN);
55     }
56
57     @Test(enabled = ENABLED, dataProvider = PROVIDER)
58     public void contextCopiedWhenToRunnableCalled(LoggingContextService ctx)
59             throws InterruptedException {
60
61         Map<ContextField, String> values = putUniqueValues(ctx);
62         AtomicBoolean complete = new AtomicBoolean(false);
63
64         // pass the runnable to the context service first
65         Thread thread = new Thread(ctx.copyToRunnable(() -> {
66             assertContextFields(values, EXPECT_PROPAGATED_TO_CHILD);
67             complete.set(true);
68         }));
69
70         thread.start();
71         thread.join();
72
73         assertContextFields(values, EXPECT_RETAINED_IN_CURRENT);
74         assertTrue(complete.get(), EXPECT_INNER_RUN);
75     }
76
77     @Test(enabled = ENABLED, dataProvider = PROVIDER)
78     public void copiedContextRetainedEvenWhenAnotherPushed(LoggingContextService ctx)
79             throws InterruptedException {
80
81         Map<ContextField, String> innerValues = putUniqueValues(ctx);
82         AtomicBoolean innerComplete = new AtomicBoolean(false);
83
84         // should run with the context of main thread
85         Runnable inner = ctx.copyToRunnable(() -> {
86             assertContextFields(innerValues, EXPECT_PROPAGATED_TO_CHILD);
87             innerComplete.set(true);
88         });
89
90         // pushes its context, but the inner must run with its own context
91         AtomicBoolean outerComplete = new AtomicBoolean(false);
92         Thread outer = new Thread(() -> {
93             Map<ContextField, String> outerValues = putUniqueValues(ctx);
94             inner.run();
95             assertContextFields(outerValues, EXPECT_REPLACED_WITH_STORED);
96             outerComplete.set(true);
97         });
98
99         outer.start();
100         outer.join();
101
102         assertContextFields(innerValues, EXPECT_RETAINED_IN_CURRENT);
103         assertTrue(outerComplete.get(), EXPECT_OUTER_RUN);
104         assertTrue(innerComplete.get(), EXPECT_INNER_RUN);
105     }
106
107     @Test(enabled = ENABLED, dataProvider = PROVIDER)
108     public void contextRemainsEmptyWhenParentWasEmpty(LoggingContextService ctx)
109             throws InterruptedException {
110
111         ctx.clear();
112         assertContextEmpty(EXPECT_EMPTY);
113
114         final AtomicBoolean complete = new AtomicBoolean(false);
115         Runnable runnable = ctx.copyToRunnable(() -> {
116             assertContextEmpty(EXPECT_EMPTY);
117             complete.set(true);
118         });
119
120         Thread thread = new Thread(runnable);
121         thread.start();
122         thread.join();
123
124         assertContextEmpty(EXPECT_EMPTY);
125         assertTrue(complete.get(), EXPECT_INNER_RUN);
126     }
127
128     @Test(enabled = ENABLED, dataProvider = PROVIDER)
129     public void childThreadCleanedUpAfterRunnableRuns(LoggingContextService ctx)
130             throws Exception {
131
132         Map<ContextField, String> innerValues = putUniqueValues(ctx);
133         AtomicBoolean innerComplete = new AtomicBoolean(false);
134         // should run with the context of main thread
135         Runnable inner = ctx.copyToRunnable(() -> {
136             assertContextFields(innerValues, EXPECT_PROPAGATED_TO_CHILD);
137             innerComplete.set(true);
138         });
139
140         // pushes its own context, but runs the inner
141         AtomicBoolean outerComplete = new AtomicBoolean(false);
142         Thread outer = new Thread(() -> {
143             assertContextEmpty(EXPECT_NOT_COPIED);
144             inner.run();
145             assertContextEmpty(EXPECT_REMAIN_EMPTY);
146             outerComplete.set(true);
147         });
148
149         outer.start();
150         outer.join();
151
152         assertContextFields(innerValues, EXPECT_RETAINED_IN_PARENT);
153         assertTrue(outerComplete.get(), EXPECT_OUTER_RUN);
154         assertTrue(innerComplete.get(), EXPECT_INNER_RUN);
155     }
156
157     @Test(enabled = ENABLED, dataProvider = PROVIDER)
158     public void childThreadCleanedUpAfterException(LoggingContextService ctx)
159             throws Exception {
160
161         Map<ContextField, String> innerValues = putUniqueValues(ctx);
162
163         // should run with the context of main thread
164         AtomicBoolean innerComplete = new AtomicBoolean(false);
165         Runnable inner = ctx.copyToRunnable(() -> {
166             assertContextFields(innerValues, EXPECT_PROPAGATED_TO_CHILD);
167             innerComplete.set(true);
168             throw new IllegalArgumentException();
169         });
170
171         // pushes its own context, but runs the inner runnable
172         AtomicBoolean outerComplete = new AtomicBoolean(false);
173         AtomicBoolean exceptionThrown = new AtomicBoolean(false);
174         Thread outer = new Thread(() -> {
175
176             Map<ContextField, String> outerValues = putUniqueValues(ctx);
177             assertContextFields(outerValues, EXPECT_POPULATED);
178
179             try {
180                 inner.run();
181             } catch (IllegalArgumentException e) {
182                 exceptionThrown.set(true);
183             } finally {
184                 assertContextFields(outerValues, EXPECT_REVERTED_ON_EXCEPTION);
185                 outerComplete.set(true);
186             }
187         });
188
189         outer.start();
190         outer.join();
191
192         assertContextFields(innerValues, EXPECT_RETAINED_IN_PARENT);
193         assertTrue(outerComplete.get(), EXPECT_OUTER_RUN);
194         assertTrue(innerComplete.get(), EXPECT_INNER_RUN);
195         assertTrue(exceptionThrown.get(), EXPECT_EXCEPTION_FROM_INNER);
196     }
197
198
199 }