897a87193fa050547c646f060c332b2bc3dac82e
[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.EXPECT_EMPTY;
20 import static org.openecomp.sdc.logging.slf4j.ContextPropagationTestHelper.EXPECT_EXCEPTION_FROM_INNER;
21 import static org.openecomp.sdc.logging.slf4j.ContextPropagationTestHelper.EXPECT_INNER_RUN;
22 import static org.openecomp.sdc.logging.slf4j.ContextPropagationTestHelper.EXPECT_NOT_COPIED;
23 import static org.openecomp.sdc.logging.slf4j.ContextPropagationTestHelper.EXPECT_OUTER_RUN;
24 import static org.openecomp.sdc.logging.slf4j.ContextPropagationTestHelper.EXPECT_POPULATED;
25 import static org.openecomp.sdc.logging.slf4j.ContextPropagationTestHelper.EXPECT_PROPAGATED_TO_CHILD;
26 import static org.openecomp.sdc.logging.slf4j.ContextPropagationTestHelper.EXPECT_REMAIN_EMPTY;
27 import static org.openecomp.sdc.logging.slf4j.ContextPropagationTestHelper.EXPECT_REPLACED_WITH_STORED;
28 import static org.openecomp.sdc.logging.slf4j.ContextPropagationTestHelper.EXPECT_RETAINED_IN_CURRENT;
29 import static org.openecomp.sdc.logging.slf4j.ContextPropagationTestHelper.EXPECT_RETAINED_IN_PARENT;
30 import static org.openecomp.sdc.logging.slf4j.ContextPropagationTestHelper.EXPECT_REVERTED_ON_EXCEPTION;
31 import static org.openecomp.sdc.logging.slf4j.ContextPropagationTestHelper.IS_SUITABLE_LOGBACK_VERSION;
32 import static org.openecomp.sdc.logging.slf4j.ContextPropagationTestHelper.assertContextEmpty;
33 import static org.openecomp.sdc.logging.slf4j.ContextPropagationTestHelper.assertContextFields;
34 import static org.openecomp.sdc.logging.slf4j.ContextPropagationTestHelper.putUniqueValues;
35 import static org.testng.Assert.assertTrue;
36
37 import java.util.Map;
38 import java.util.concurrent.Callable;
39 import java.util.concurrent.ExecutorService;
40 import java.util.concurrent.Executors;
41 import java.util.concurrent.Future;
42 import java.util.concurrent.TimeUnit;
43 import java.util.concurrent.atomic.AtomicBoolean;
44 import org.openecomp.sdc.logging.spi.LoggingContextService;
45 import org.testng.annotations.Test;
46
47 /**
48  * Tests propagation of logging fields to Callable via the logging service.
49  * 
50  * @author evitaliy
51  * @since 08 Jan 18
52  */
53 @SuppressWarnings("DefaultAnnotationParam") // see the comment to ENABLED
54 public class CallableContextPropagationTest {
55
56     private final LoggingContextService ctxService = new SLF4JLoggingServiceProvider();
57
58     @Test(enabled = IS_SUITABLE_LOGBACK_VERSION)
59     public void testContextPropagated() throws Exception {
60
61         Map<ContextField, String> values = putUniqueValues();
62         AtomicBoolean complete = new AtomicBoolean(false);
63
64         // pass the callable to the context service first
65         execute(ctxService.copyToCallable(() -> {
66             assertContextFields(values, EXPECT_PROPAGATED_TO_CHILD);
67             complete.set(true);
68             return null;
69         }));
70
71         assertContextFields(values, EXPECT_RETAINED_IN_CURRENT);
72         assertTrue(complete.get(), EXPECT_INNER_RUN);
73     }
74
75     @Test(enabled = IS_SUITABLE_LOGBACK_VERSION)
76     public void testContextReplacement() throws Exception {
77
78         Map<ContextField, String> innerValues = putUniqueValues();
79         AtomicBoolean innerComplete = new AtomicBoolean(false);
80
81         // should run with the context of main thread
82         Callable inner = ctxService.copyToCallable(() -> {
83             assertContextFields(innerValues, EXPECT_PROPAGATED_TO_CHILD);
84             innerComplete.set(true);
85             return null;
86         });
87
88         // pushes its own context, but the inner must run with its own context
89         AtomicBoolean outerComplete = new AtomicBoolean(false);
90         execute(() -> {
91             Map<ContextField, String> outerValues = putUniqueValues();
92             inner.call();
93             assertContextFields(outerValues, EXPECT_REPLACED_WITH_STORED);
94             outerComplete.set(true);
95             return null;
96         });
97
98         assertContextFields(innerValues, EXPECT_RETAINED_IN_CURRENT);
99         assertTrue(outerComplete.get(), EXPECT_OUTER_RUN);
100         assertTrue(innerComplete.get(), EXPECT_INNER_RUN);
101     }
102
103     @Test(enabled = IS_SUITABLE_LOGBACK_VERSION)
104     public void testContextRemainsEmpty() throws Exception {
105
106         ctxService.clear();
107         assertContextEmpty(EXPECT_EMPTY);
108
109         final AtomicBoolean complete = new AtomicBoolean(false);
110         execute(ctxService.copyToCallable(() -> {
111             assertContextEmpty(EXPECT_EMPTY);
112             complete.set(true);
113             return null;
114         }));
115
116         assertContextEmpty(EXPECT_EMPTY);
117         assertTrue(complete.get(), EXPECT_INNER_RUN);
118     }
119
120     @Test(enabled = IS_SUITABLE_LOGBACK_VERSION)
121     public void testContextCleanedUp() throws Exception {
122
123         Map<ContextField, String> innerValues = putUniqueValues();
124
125         AtomicBoolean innerComplete = new AtomicBoolean(false);
126         // should run with the context of main thread
127         Callable inner = ctxService.copyToCallable((() -> {
128             assertContextFields(innerValues, EXPECT_PROPAGATED_TO_CHILD);
129             innerComplete.set(true);
130             return null;
131         }));
132
133         // pushes its own context, but runs the inner
134         AtomicBoolean outerComplete = new AtomicBoolean(false);
135         execute(() -> {
136             assertContextEmpty(EXPECT_NOT_COPIED);
137             inner.call();
138             assertContextEmpty(EXPECT_REMAIN_EMPTY);
139             outerComplete.set(true);
140             return null;
141         });
142
143         assertContextFields(innerValues, EXPECT_RETAINED_IN_PARENT);
144         assertTrue(outerComplete.get(), EXPECT_OUTER_RUN);
145         assertTrue(innerComplete.get(), EXPECT_INNER_RUN);
146     }
147
148     @Test(enabled = IS_SUITABLE_LOGBACK_VERSION)
149     public void testCleanupAfterError() throws Exception {
150
151         Map<ContextField, String> innerValues = putUniqueValues();
152
153         // should run with the context of main thread
154         AtomicBoolean innerComplete = new AtomicBoolean(false);
155         Callable inner = ctxService.copyToCallable(() -> {
156             assertContextFields(innerValues, EXPECT_PROPAGATED_TO_CHILD);
157             innerComplete.set(true);
158             throw new IllegalArgumentException();
159         });
160
161         // pushes its own context, but runs the inner callable
162         AtomicBoolean outerComplete = new AtomicBoolean(false);
163         AtomicBoolean exceptionThrown = new AtomicBoolean(false);
164         execute(() -> {
165
166             Map<ContextField, String> outerValues = putUniqueValues();
167             assertContextFields(outerValues, EXPECT_POPULATED);
168
169             try {
170                 inner.call();
171             } catch (IllegalArgumentException e) {
172                 exceptionThrown.set(true);
173             } finally {
174                 assertContextFields(outerValues, EXPECT_REVERTED_ON_EXCEPTION);
175                 outerComplete.set(true);
176             }
177
178             return null;
179         });
180
181         assertContextFields(innerValues, EXPECT_RETAINED_IN_PARENT);
182         assertTrue(outerComplete.get(), EXPECT_OUTER_RUN);
183         assertTrue(innerComplete.get(), EXPECT_INNER_RUN);
184         assertTrue(exceptionThrown.get(), EXPECT_EXCEPTION_FROM_INNER);
185     }
186
187     private void execute(Callable<Object> callable) throws Exception {
188
189         ExecutorService executor = Executors.newSingleThreadExecutor();
190
191         try {
192             Future<Object> future = executor.submit(callable);
193             future.get(10, TimeUnit.SECONDS);
194         } finally {
195             executor.shutdown();
196         }
197     }
198 }