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