Change MDC datetime formatter to Zulu time
[logging-analytics.git] / reference / logging-slf4j / src / test / java / org / onap / logging / ref / slf4j / ONAPLogAdapterTest.java
1 /**
2  * ============LICENSE_START=======================================================
3  * org.onap.logging
4  * ================================================================================
5  * Copyright © 2018 Amdocs
6  * All rights reserved.
7  * ================================================================================
8  * Licensed under the Apache License, Version 2.0 (the "License");
9  * you may not use this file except in compliance with the License.
10  * You may obtain a copy of the License at
11  *
12  *    http://www.apache.org/licenses/LICENSE-2.0
13  *
14  * Unless required by applicable law or agreed to in writing, software
15  * distributed under the License is distributed on an "AS IS" BASIS,
16  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17  * See the License for the specific language governing permissions and
18  * limitations under the License.
19  * ============LICENSE_END=========================================================
20  */
21
22 package org.onap.logging.ref.slf4j;
23
24 import java.util.HashMap;
25 import java.util.Map;
26 import java.util.UUID;
27
28 import javax.xml.bind.DatatypeConverter;
29
30 import org.slf4j.Logger;
31 import org.slf4j.LoggerFactory;
32 import org.slf4j.MDC;
33 import org.slf4j.event.Level;
34 import org.springframework.mock.web.MockHttpServletRequest;
35 import org.testng.Assert;
36 import org.testng.annotations.AfterMethod;
37 import org.testng.annotations.Test;
38 import static org.hamcrest.MatcherAssert.assertThat;
39 import static org.hamcrest.core.Is.is;
40 import static org.hamcrest.core.IsEqual.equalTo;
41 import static org.hamcrest.core.IsNot.not;
42 import static org.hamcrest.core.IsSame.sameInstance;
43 import static org.hamcrest.core.StringContains.containsString;
44 import static org.hamcrest.core.StringEndsWith.endsWith;
45 import static org.hamcrest.core.Every.everyItem;
46 import static org.hamcrest.core.IsInstanceOf.instanceOf;
47 import static org.hamcrest.core.IsNull.notNullValue;
48 import static org.hamcrest.core.IsNull.nullValue;
49 import static org.hamcrest.core.StringStartsWith.startsWith;
50 import static org.hamcrest.beans.HasProperty.hasProperty;
51 import static org.hamcrest.number.IsCloseTo.closeTo;
52 import static org.hamcrest.number.OrderingComparison.greaterThan;
53 import static org.hamcrest.number.OrderingComparison.greaterThanOrEqualTo;
54 import static org.hamcrest.number.OrderingComparison.lessThan;
55 import static org.hamcrest.number.OrderingComparison.lessThanOrEqualTo;
56 import static org.hamcrest.collection.IsArray.array;
57 import static org.hamcrest.collection.IsArrayContaining.hasItemInArray;
58 import static org.hamcrest.collection.IsArrayContainingInAnyOrder.arrayContainingInAnyOrder;
59 import static org.hamcrest.collection.IsIn.isIn;
60 import static org.hamcrest.collection.IsIn.isOneOf;
61 import static org.hamcrest.collection.IsMapContaining.hasKey;
62 import static org.hamcrest.collection.IsMapContaining.hasEntry;
63 import static org.hamcrest.collection.IsMapContaining.hasValue;
64 import static org.hamcrest.text.IsEqualIgnoringWhiteSpace.equalToIgnoringWhiteSpace;
65 import static org.hamcrest.text.IsEqualIgnoringCase.equalToIgnoringCase;
66 import static org.hamcrest.text.IsEmptyString.isEmptyOrNullString;
67 import static org.hamcrest.text.IsEmptyString.isEmptyString;
68 import static org.hamcrest.text.StringContainsInOrder.stringContainsInOrder;
69 import static org.hamcrest.xml.HasXPath.hasXPath;
70
71 import org.testng.Assert;
72 import org.testng.annotations.Test;
73
74 import static org.hamcrest.MatcherAssert.assertThat;
75 import static org.hamcrest.core.Is.is;
76 import static org.hamcrest.core.IsNot.not;
77 import static org.hamcrest.core.IsNull.notNullValue;
78 import static org.hamcrest.core.IsNull.nullValue;
79 import static org.hamcrest.core.IsSame.sameInstance;
80
81 /**
82  * Tests for {@link ONAPLogAdapter}.
83  */
84 public class ONAPLogAdapterTest {
85
86     /**
87      * Ensure that MDCs are cleared after each testcase.
88      */
89     @AfterMethod
90     public void resetMDCs() {
91         MDC.clear();
92     }
93
94     /**
95      * Test nullcheck.
96      */
97     @Test
98     public void testCheckNotNull() {
99
100         ONAPLogAdapter.checkNotNull("");
101
102         try {
103             ONAPLogAdapter.checkNotNull(null);
104             Assert.fail("Should throw NullPointerException");
105         }
106         catch (final NullPointerException e) {
107
108         }
109     }
110
111     /**
112      * Test defaulting of nulls.
113      */
114     @Test
115     public void testDefaultToEmpty() {
116         assertThat(ONAPLogAdapter.defaultToEmpty("123"), is("123"));
117         assertThat(ONAPLogAdapter.defaultToEmpty(Integer.valueOf(1984)), is("1984"));
118         assertThat(ONAPLogAdapter.defaultToEmpty(null), is(""));
119     }
120
121     /**
122      * Test defaulting of nulls.
123      */
124     @Test
125     public void testDefaultToUUID() {
126         assertThat(ONAPLogAdapter.defaultToUUID("123"), is("123"));
127         UUID.fromString(ONAPLogAdapter.defaultToUUID(null));
128     }
129
130     /**
131      * Test ENTERING.
132      */
133     @Test
134     public void testEntering() {
135
136         final Logger logger = LoggerFactory.getLogger(this.getClass());
137         final ONAPLogAdapter adapter = new ONAPLogAdapter(logger);
138         final MockHttpServletRequest http = new MockHttpServletRequest();
139         http.setRequestURI("uri123");
140         http.setServerName("local123");
141         http.setRemoteAddr("remote123");
142         http.addHeader("X-ONAP-RequestID", "request123");
143         http.addHeader("X-ONAP-InvocationID", "invocation123");
144         http.addHeader("X-ONAP-PartnerName", "partner123");
145
146         try {
147             adapter.getServiceDescriptor().setServiceName("uri123");
148             adapter.entering(http);
149             final Map<String, String> mdcs = MDC.getCopyOfContextMap();
150             assertThat(mdcs.get("RequestID"), is("request123"));
151             assertThat(mdcs.get("InvocationID"), is("invocation123"));
152             assertThat(mdcs.get("PartnerName"), is("partner123"));
153             assertThat(mdcs.get("ServiceName"), is("uri123"));
154             assertThat(mdcs.get("ServerFQDN"), is("local123"));
155             assertThat(mdcs.get("ClientIPAddress"), is("remote123"));
156
157             // Timestamp format and value:
158
159             final String invokeTimestampString = mdcs.get("InvokeTimestamp");
160             assertThat(invokeTimestampString, notNullValue());
161             assertThat(invokeTimestampString, endsWith("Z"));
162             final long invokeTimestamp = DatatypeConverter.parseDateTime(invokeTimestampString).getTimeInMillis();
163             assertThat(Math.abs(System.currentTimeMillis() - invokeTimestamp), lessThan(5000L));
164         }
165         finally {
166             MDC.clear();
167         }
168     }
169
170     @Test
171     public void testSetServiceDescriptor() {
172         final ONAPLogAdapter.ServiceDescriptor override = new ONAPLogAdapter.ServiceDescriptor();
173         final Logger logger = LoggerFactory.getLogger(this.getClass());
174         final ONAPLogAdapter adapter = new ONAPLogAdapter(logger);
175         final ONAPLogAdapter.ServiceDescriptor before = adapter.getServiceDescriptor();
176         adapter.setServiceDescriptor(override);
177         final ONAPLogAdapter.ServiceDescriptor after = adapter.getServiceDescriptor();
178         assertThat(after, not(sameInstance(before)));
179         assertThat(after, is(override));
180     }
181
182     @Test
183     public void testSetResponseDescriptor() {
184         final ONAPLogAdapter.ResponseDescriptor override = new ONAPLogAdapter.ResponseDescriptor();
185         final Logger logger = LoggerFactory.getLogger(this.getClass());
186         final ONAPLogAdapter adapter = new ONAPLogAdapter(logger);
187         final ONAPLogAdapter.ResponseDescriptor before = adapter.getResponseDescriptor();
188         adapter.setResponseDescriptor(override);
189         final ONAPLogAdapter.ResponseDescriptor after = adapter.getResponseDescriptor();
190         assertThat(after, not(sameInstance(before)));
191         assertThat(after, is(override));
192     }
193
194     @Test
195     public void testUnwrap() {
196         final Logger logger = LoggerFactory.getLogger(this.getClass());
197         final ONAPLogAdapter adapter = new ONAPLogAdapter(logger);
198         assertThat(adapter.unwrap(), is(logger));
199     }
200
201     /**
202      * Test EXITING.
203      */
204     @Test
205     public void testExiting() {
206
207         final Logger logger = LoggerFactory.getLogger(this.getClass());
208         final ONAPLogAdapter adapter = new ONAPLogAdapter(logger);
209
210         try {
211             MDC.put("somekey", "somevalue");
212             assertThat(MDC.get("somekey"), is("somevalue"));
213             adapter.exiting();
214             assertThat(MDC.get("somekey"), nullValue());
215         }
216         finally {
217             MDC.clear();
218         }
219     }
220
221     /**
222      * Test INVOKE.
223      */
224     @Test
225     public void testInvokeSyncAsyncNull() {
226
227         final Logger logger = LoggerFactory.getLogger(this.getClass());
228         final ONAPLogAdapter adapter = new ONAPLogAdapter(logger);
229
230         final UUID syncUUID = adapter.invoke(ONAPLogConstants.InvocationMode.SYNCHRONOUS);
231         assertThat(syncUUID, notNullValue());
232
233         final UUID asyncUUID = adapter.invoke(ONAPLogConstants.InvocationMode.SYNCHRONOUS);
234         assertThat(asyncUUID, notNullValue());
235
236         final UUID agnosticUUID = adapter.invoke((ONAPLogConstants.InvocationMode)null);
237         assertThat(agnosticUUID, notNullValue());
238
239     }
240
241     /**
242      * Test INVOKE, with RequestAdapter.
243      */
244     @Test
245     public void testInvokeWithAdapter() throws Exception {
246
247         final Logger logger = LoggerFactory.getLogger(this.getClass());
248         final ONAPLogAdapter adapter = new ONAPLogAdapter(logger);
249
250         final Map<String, String> headers = new HashMap<>();
251         final ONAPLogAdapter.RequestBuilder builder = new ONAPLogAdapter.RequestBuilder<ONAPLogAdapter.RequestBuilder>() {
252             @Override
253             public ONAPLogAdapter.RequestBuilder setHeader(final String name, final String value) {
254                 headers.put(name, value);
255                 return this;
256             }
257         };
258
259         try {
260             final UUID uuid = adapter.invoke(builder, ONAPLogConstants.InvocationMode.SYNCHRONOUS);
261             assertThat(uuid, notNullValue());
262             assertThat(headers.get(ONAPLogConstants.Headers.INVOCATION_ID), is(uuid.toString()));
263             assertThat(headers.containsKey(ONAPLogConstants.Headers.PARTNER_NAME), is(true));
264             assertThat(headers.containsKey(ONAPLogConstants.Headers.REQUEST_ID), is(true));
265         }
266         finally {
267             MDC.clear();
268         }
269     }
270
271     /**
272      * Test INVOKE, with RequestAdapter.
273      */
274     @Test
275     public void testInvokeWithAdapterAndNull() throws Exception {
276
277         final Logger logger = LoggerFactory.getLogger(this.getClass());
278         final ONAPLogAdapter adapter = new ONAPLogAdapter(logger);
279
280         final Map<String, String> headers = new HashMap<>();
281         final ONAPLogAdapter.RequestBuilder builder = new ONAPLogAdapter.RequestBuilder<ONAPLogAdapter.RequestBuilder>() {
282             @Override
283             public ONAPLogAdapter.RequestBuilder setHeader(final String name, final String value) {
284                 headers.put(name, value);
285                 return this;
286             }
287         };
288
289         try {
290             final UUID uuid = adapter.invoke(builder);
291             assertThat(uuid, notNullValue());
292             assertThat(headers.get(ONAPLogConstants.Headers.INVOCATION_ID), is(uuid.toString()));
293             assertThat(headers.containsKey(ONAPLogConstants.Headers.PARTNER_NAME), is(true));
294             assertThat(headers.containsKey(ONAPLogConstants.Headers.REQUEST_ID), is(true));
295         }
296         finally {
297             MDC.clear();
298         }
299     }
300
301     @Test
302     public void testHttpServletRequestAdapter() {
303
304         final UUID uuid = UUID.randomUUID();
305         final MockHttpServletRequest request = new MockHttpServletRequest();
306         request.addHeader("uuid", uuid.toString());
307         request.setRequestURI("/ctx0");
308         request.setServerName("srv0");
309
310         final ONAPLogAdapter.HttpServletRequestAdapter adapter
311                 = new ONAPLogAdapter.HttpServletRequestAdapter(request);
312         assertThat(adapter.getHeader("uuid"), is(uuid.toString()));
313         assertThat(adapter.getRequestURI(), is("/ctx0"));
314         assertThat(adapter.getServerAddress(), is("srv0"));
315     }
316
317     @Test
318     public void testServiceDescriptor() {
319         final String uuid = UUID.randomUUID().toString();
320
321         final ONAPLogAdapter.ServiceDescriptor adapter
322                 = new ONAPLogAdapter.ServiceDescriptor();
323         adapter.setServiceUUID(uuid);
324         adapter.setServiceName("name0");
325
326         assertThat(MDC.get(ONAPLogConstants.MDCs.SERVICE_NAME), nullValue());
327         assertThat(MDC.get(ONAPLogConstants.MDCs.INSTANCE_UUID), nullValue());
328
329         adapter.setMDCs();
330
331         assertThat(MDC.get(ONAPLogConstants.MDCs.SERVICE_NAME), is("name0"));
332         assertThat(MDC.get(ONAPLogConstants.MDCs.INSTANCE_UUID), is(uuid));
333     }
334
335     @Test
336     public void testResponseDescriptor() {
337         final String uuid = UUID.randomUUID().toString();
338
339         final ONAPLogAdapter.ResponseDescriptor adapter
340                 = new ONAPLogAdapter.ResponseDescriptor();
341         adapter.setResponseCode("code0");
342         adapter.setResponseDescription("desc0");
343         adapter.setResponseSeverity(Level.INFO);
344         adapter.setResponseStatus(ONAPLogConstants.ResponseStatus.COMPLETED);
345
346         assertThat(MDC.get(ONAPLogConstants.MDCs.RESPONSE_CODE), nullValue());
347         assertThat(MDC.get(ONAPLogConstants.MDCs.RESPONSE_DESCRIPTION), nullValue());
348         assertThat(MDC.get(ONAPLogConstants.MDCs.RESPONSE_SEVERITY), nullValue());
349         assertThat(MDC.get(ONAPLogConstants.MDCs.RESPONSE_STATUS_CODE), nullValue());
350
351         adapter.setMDCs();
352
353         assertThat(MDC.get(ONAPLogConstants.MDCs.RESPONSE_CODE), is("code0"));
354         assertThat(MDC.get(ONAPLogConstants.MDCs.RESPONSE_DESCRIPTION), is("desc0"));
355         assertThat(MDC.get(ONAPLogConstants.MDCs.RESPONSE_SEVERITY), is("INFO"));
356         assertThat(MDC.get(ONAPLogConstants.MDCs.RESPONSE_STATUS_CODE), is("COMPLETED"));
357     }
358
359     /**
360      * Exercise the contract, for a caller that's happy to have their
361      * service name automatically derived. (This validates nothing
362      * and achieves nothing; it's just to provide an example of minimal usage).
363      */
364     @Test
365     public void testContract() {
366
367         // Note no wrapper around HttpServletRequest, which will work for
368         // most invocations (since they come via HTTP), but otherwise
369         // can implement your own RequestAdapter.
370
371         final Logger logger = LoggerFactory.getLogger(this.getClass());
372         final ONAPLogAdapter adapter = new ONAPLogAdapter(logger);
373         final MockHttpServletRequest http = new MockHttpServletRequest();
374
375         // Immediately log ENTERING marker, with global MDCs.
376
377         adapter.entering(http);
378         try {
379
380             // Generate (and log) an invocationID, then use it to
381             // invoke another component.
382
383             final RESTClient client = new RESTClient();             // implements ONAPLogAdapter.RequestBuilder<RESTClient>.
384             adapter.invoke(client, ONAPLogConstants.InvocationMode.SYNCHRONOUS);
385             final RESTRequest request = null;                       // TODO: build real request.
386             final RESTResponse response = client.execute(request);  // TODO: handle real response.
387
388             // Set response details prior to #exiting.
389             // (Obviously there'd be errorhandling, etc. IRL).
390
391             adapter.getResponseDescriptor()
392                     .setResponseCode((String)null)
393                     .setResponseSeverity(Level.INFO)
394                     .setResponseStatus(ONAPLogConstants.ResponseStatus.COMPLETED);
395         }
396         finally {
397
398             // Return, logging EXIT marker, with response MDCs.
399
400             adapter.exiting();
401         }
402     }
403
404     /**
405      * Dummy class, for example code.
406      */
407     static class RESTClient implements ONAPLogAdapter.RequestBuilder<RESTClient> {
408
409         @Override
410         public RESTClient setHeader(final String name, final String value) {
411             return null;
412         }
413
414         RESTResponse execute(RESTRequest request) {
415             return null;
416         }
417     }
418
419     /**
420      * Dummy class, for example code.
421      */
422     static class RESTRequest {
423
424     }
425
426     /**
427      * Dummy class, for example code.
428      */
429     static class RESTResponse {
430
431     }
432 }