2c5233f9c9406236b2743d5066a180360a8aa0a8
[sdc.git] /
1 /*
2  * Copyright © 2016-2018 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.SLF4JLoggerWrapper.AuditField.BEGIN_TIMESTAMP;
20 import static org.openecomp.sdc.logging.slf4j.SLF4JLoggerWrapper.AuditField.CLIENT_IP_ADDRESS;
21 import static org.openecomp.sdc.logging.slf4j.SLF4JLoggerWrapper.AuditField.ELAPSED_TIME;
22 import static org.openecomp.sdc.logging.slf4j.SLF4JLoggerWrapper.AuditField.END_TIMESTAMP;
23 import static org.openecomp.sdc.logging.slf4j.SLF4JLoggerWrapper.AuditField.RESPONSE_CODE;
24 import static org.openecomp.sdc.logging.slf4j.SLF4JLoggerWrapper.AuditField.RESPONSE_DESCRIPTION;
25 import static org.openecomp.sdc.logging.slf4j.SLF4JLoggerWrapper.AuditField.STATUS_CODE;
26 import static org.testng.Assert.assertEquals;
27 import static org.testng.Assert.assertNotNull;
28 import static org.testng.Assert.assertNull;
29
30 import java.lang.reflect.InvocationHandler;
31 import java.lang.reflect.Method;
32 import java.lang.reflect.Proxy;
33 import java.util.Arrays;
34 import java.util.Map;
35 import org.openecomp.sdc.logging.api.AuditData;
36 import org.openecomp.sdc.logging.api.StatusCode;
37 import org.slf4j.Logger;
38 import org.slf4j.MDC;
39 import org.testng.annotations.Test;
40
41 /**
42  * Unit-test of SLF4J implementation of Logger.
43  *
44  * @author evitaliy
45  * @since 05 Mar 18
46  */
47 @SuppressWarnings("CheckStyle")
48 public class SLF4JLoggerWrapperTest {
49
50     @Test
51     public void auditDoesNotFailWhenInputNull() {
52         new SLF4JLoggerWrapper(this.getClass()).audit(null);
53     }
54
55     @Test
56     public void beginTimeAvailableWhenPassed() {
57         SpyLogger spy = createSpy();
58         long start = System.currentTimeMillis();
59         new SLF4JLoggerWrapper(spy).audit(AuditData.builder().startTime(start).build());
60         assertNotNull(spy.mdc().get(BEGIN_TIMESTAMP.asKey()));
61     }
62
63     @Test
64     public void entTimeAvailableWhenPassed() {
65         SpyLogger spy = createSpy();
66         long end = System.currentTimeMillis();
67         new SLF4JLoggerWrapper(spy).audit(AuditData.builder().endTime(end).build());
68         assertNotNull(spy.mdc().get(END_TIMESTAMP.asKey()));
69     }
70
71     @Test
72     public void elapsedTimeAvailableWhenPassed() {
73         SpyLogger spy = createSpy();
74         long start = System.currentTimeMillis();
75         new SLF4JLoggerWrapper(spy).audit(AuditData.builder()
76             .startTime(start).endTime(start).build());
77         assertNotNull(spy.mdc().get(ELAPSED_TIME.asKey()));
78     }
79
80     @Test
81     public void statusCodeAvailableWhenPassed() {
82         SpyLogger spy = createSpy();
83         new SLF4JLoggerWrapper(spy).audit(AuditData.builder().statusCode(StatusCode.COMPLETE).build());
84         assertEquals(spy.mdc().get(STATUS_CODE.asKey()), StatusCode.COMPLETE.name());
85     }
86
87     @Test
88     public void statusCodeEmptyWhenNotPassed() {
89         SpyLogger spy = createSpy();
90         new SLF4JLoggerWrapper(spy).audit(AuditData.builder().build());
91         assertNull(spy.mdc().get(STATUS_CODE.asKey()));
92     }
93
94     @Test
95     public void responseCodeAvailableWhenPassed() {
96         final String responseCode = "SpyResponse";
97         SpyLogger spy = createSpy();
98         new SLF4JLoggerWrapper(spy).audit(AuditData.builder().responseCode(responseCode).build());
99         assertEquals(spy.mdc().get(RESPONSE_CODE.asKey()), responseCode);
100     }
101
102     @Test
103     public void responseCodeEmptyWhenNotPassed() {
104         SpyLogger spy = createSpy();
105         new SLF4JLoggerWrapper(spy).audit(AuditData.builder().build());
106         assertNull(spy.mdc().get(RESPONSE_CODE.asKey()));
107     }
108
109     @Test
110     public void responseDescriptionAvailableWhenPassed() {
111         final String responseDescription = "SpyDescription";
112         SpyLogger spy = createSpy();
113         new SLF4JLoggerWrapper(spy).audit(AuditData.builder().responseDescription(responseDescription).build());
114         assertEquals(spy.mdc().get(RESPONSE_DESCRIPTION.asKey()), responseDescription);
115     }
116
117     @Test
118     public void responseDescriptionEmptyWhenNotPassed() {
119         SpyLogger spy = createSpy();
120         new SLF4JLoggerWrapper(spy).audit(AuditData.builder().build());
121         assertNull(spy.mdc().get(RESPONSE_DESCRIPTION.asKey()));
122     }
123
124     @Test
125     public void clientIpAddressAvailableWhenPassed() {
126         final String ipAddress = "10.56.20.20";
127         SpyLogger spy = createSpy();
128         new SLF4JLoggerWrapper(spy).audit(AuditData.builder().clientIpAddress(ipAddress).build());
129         assertEquals(spy.mdc().get(CLIENT_IP_ADDRESS.asKey()), ipAddress);
130     }
131
132     @Test
133     public void clientIpAddressEmptyWhenNotPassed() {
134         SpyLogger spy = createSpy();
135         new SLF4JLoggerWrapper(spy).audit(AuditData.builder().build());
136         assertNull(spy.mdc().get(CLIENT_IP_ADDRESS.asKey()));
137     }
138
139     @Test
140     public void elapsedTimeEqualsDifferenceBetweenStartAndEnd() {
141         SpyLogger spy = createSpy();
142         final long diff = 1024;
143         long start = System.currentTimeMillis();
144         long end = start + diff;
145         new SLF4JLoggerWrapper(spy).audit(AuditData.builder().startTime(start).endTime(end).build());
146         assertEquals(spy.mdc().get(ELAPSED_TIME.asKey()), Long.toString(diff));
147     }
148
149     interface SpyLogger extends Logger {
150
151         Map<String, String> mdc();
152     }
153
154     /**
155      * Creates a in instance of Logger that can be used to track MDC changes as part of an invocation of
156      * Logger.audit().
157      *
158      * @return object that implements {@link SpyLogger}
159      */
160     private static SpyLogger createSpy() {
161
162         // build a dynamic proxy to avoid implementing the long list of Logger methods
163         // when we actually need just Logger.info() with the audit marker
164         ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
165         return SpyLogger.class.cast(
166                 Proxy.newProxyInstance(classLoader, new Class<?>[]{SpyLogger.class}, new SpyingInvocationHandler()));
167     }
168
169     private static class SpyingInvocationHandler implements InvocationHandler {
170
171         private Map<String, String> mdc;
172
173         @Override
174         public Object invoke(Object proxy, Method method, Object[] args) {
175
176             if (isReturnMdcMethod(method)) {
177                 return mdc;
178             }
179
180             if (!isAuditMethod(method, args)) {
181                 throw new UnsupportedOperationException("Method " + method.getName() + " with arguments "
182                         + Arrays.toString(args) + " wasn't supposed to be called");
183             }
184
185             storeEffectiveMdc();
186             return null;
187         }
188
189         private boolean isAuditMethod(Method method, Object[] args) {
190             return (method.getName().equals("info") && args.length > 0 && args[0].equals(Markers.AUDIT));
191         }
192
193         private void storeEffectiveMdc() {
194             mdc = MDC.getCopyOfContextMap();
195         }
196
197         private boolean isReturnMdcMethod(Method method) {
198             return method.equals(SpyLogger.class.getDeclaredMethods()[0]);
199         }
200     }
201 }