2  * Copyright © 2016-2018 European Support Limited
 
   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
 
   8  *      http://www.apache.org/licenses/LICENSE-2.0
 
  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.
 
  17 package org.openecomp.sdc.logging.slf4j;
 
  19 import static org.openecomp.sdc.logging.slf4j.SLF4JLoggerWrapper.BEGIN_TIMESTAMP;
 
  20 import static org.openecomp.sdc.logging.slf4j.SLF4JLoggerWrapper.CLIENT_IP_ADDRESS;
 
  21 import static org.openecomp.sdc.logging.slf4j.SLF4JLoggerWrapper.ELAPSED_TIME;
 
  22 import static org.openecomp.sdc.logging.slf4j.SLF4JLoggerWrapper.END_TIMESTAMP;
 
  23 import static org.openecomp.sdc.logging.slf4j.SLF4JLoggerWrapper.RESPONSE_CODE;
 
  24 import static org.openecomp.sdc.logging.slf4j.SLF4JLoggerWrapper.RESPONSE_DESCRIPTION;
 
  25 import static org.openecomp.sdc.logging.slf4j.SLF4JLoggerWrapper.STATUS_CODE;
 
  26 import static org.testng.Assert.assertEquals;
 
  27 import static org.testng.Assert.assertNotNull;
 
  28 import static org.testng.Assert.assertNull;
 
  30 import java.lang.reflect.InvocationHandler;
 
  31 import java.lang.reflect.Method;
 
  32 import java.lang.reflect.Proxy;
 
  33 import java.util.Arrays;
 
  35 import org.openecomp.sdc.logging.api.AuditData;
 
  36 import org.openecomp.sdc.logging.api.StatusCode;
 
  37 import org.slf4j.Logger;
 
  39 import org.testng.annotations.Test;
 
  45 public class SLF4JLoggerWrapperTest {
 
  48     public void auditDoesNotFailWhenInputNull() {
 
  49         new SLF4JLoggerWrapper(this.getClass()).audit(null);
 
  53     public void beginTimeAvailableWhenPassed() {
 
  54         SpyLogger spy = createSpy();
 
  55         long start = System.currentTimeMillis();
 
  56         new SLF4JLoggerWrapper(spy).audit(AuditData.builder().startTime(start).build());
 
  57         assertNotNull(spy.mdc().get(BEGIN_TIMESTAMP));
 
  61     public void entTimeAvailableWhenPassed() {
 
  62         SpyLogger spy = createSpy();
 
  63         long end = System.currentTimeMillis();
 
  64         new SLF4JLoggerWrapper(spy).audit(AuditData.builder().endTime(end).build());
 
  65         assertNotNull(spy.mdc().get(END_TIMESTAMP));
 
  69     public void elapsedTimeAvailableWhenPassed() {
 
  70         SpyLogger spy = createSpy();
 
  71         long start = System.currentTimeMillis();
 
  72         new SLF4JLoggerWrapper(spy).audit(AuditData.builder()
 
  73             .startTime(start).endTime(start).build());
 
  74         assertNotNull(spy.mdc().get(ELAPSED_TIME));
 
  78     public void statusCodeAvailableWhenPassed() {
 
  79         SpyLogger spy = createSpy();
 
  80         new SLF4JLoggerWrapper(spy).audit(AuditData.builder().statusCode(StatusCode.COMPLETE).build());
 
  81         assertEquals(spy.mdc().get(STATUS_CODE), StatusCode.COMPLETE.name());
 
  85     public void statusCodeEmptyWhenNotPassed() {
 
  86         SpyLogger spy = createSpy();
 
  87         new SLF4JLoggerWrapper(spy).audit(AuditData.builder().build());
 
  88         assertNull(spy.mdc().get(STATUS_CODE));
 
  92     public void responseCodeAvailableWhenPassed() {
 
  93         final String responseCode = "SpyResponse";
 
  94         SpyLogger spy = createSpy();
 
  95         new SLF4JLoggerWrapper(spy).audit(AuditData.builder().responseCode(responseCode).build());
 
  96         assertEquals(spy.mdc().get(RESPONSE_CODE), responseCode);
 
 100     public void responseCodeEmptyWhenNotPassed() {
 
 101         SpyLogger spy = createSpy();
 
 102         new SLF4JLoggerWrapper(spy).audit(AuditData.builder().build());
 
 103         assertNull(spy.mdc().get(RESPONSE_CODE));
 
 107     public void responseDescriptionAvailableWhenPassed() {
 
 108         final String responseDescription = "SpyDescription";
 
 109         SpyLogger spy = createSpy();
 
 110         new SLF4JLoggerWrapper(spy).audit(AuditData.builder().responseDescription(responseDescription).build());
 
 111         assertEquals(spy.mdc().get(RESPONSE_DESCRIPTION), responseDescription);
 
 115     public void responseDescriptionEmptyWhenNotPassed() {
 
 116         SpyLogger spy = createSpy();
 
 117         new SLF4JLoggerWrapper(spy).audit(AuditData.builder().build());
 
 118         assertNull(spy.mdc().get(RESPONSE_DESCRIPTION));
 
 122     public void clientIpAddressAvailableWhenPassed() {
 
 123         final String ipAddress = "10.56.20.20";
 
 124         SpyLogger spy = createSpy();
 
 125         new SLF4JLoggerWrapper(spy).audit(AuditData.builder().clientIpAddress(ipAddress).build());
 
 126         assertEquals(spy.mdc().get(CLIENT_IP_ADDRESS), ipAddress);
 
 130     public void clientIpAddressEmptyWhenNotPassed() {
 
 131         SpyLogger spy = createSpy();
 
 132         new SLF4JLoggerWrapper(spy).audit(AuditData.builder().build());
 
 133         assertNull(spy.mdc().get(CLIENT_IP_ADDRESS));
 
 137     public void elapsedTimeEqualsDifferenceBetweenStartAndEnd() {
 
 138         SpyLogger spy = createSpy();
 
 139         final long diff = 1024;
 
 140         long start = System.currentTimeMillis();
 
 141         long end = start + diff;
 
 142         new SLF4JLoggerWrapper(spy).audit(AuditData.builder().startTime(start).endTime(end).build());
 
 143         assertEquals(spy.mdc().get(ELAPSED_TIME), Long.toString(diff));
 
 146     interface SpyLogger extends Logger {
 
 148         Map<String, String> mdc();
 
 152      * Creates a in instance of Logger that can be used to track MDC changes as part of an invocation of
 
 155      * @return object that implements {@link SpyLogger}
 
 157     private static SpyLogger createSpy() {
 
 159         // build a dynamic proxy to avoid implementing the long list of Logger methods
 
 160         // when we actually need just Logger.info() with the audit marker
 
 161         ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
 
 162         return SpyLogger.class.cast(
 
 163                 Proxy.newProxyInstance(classLoader, new Class<?>[]{SpyLogger.class}, new SpyingInvocationHandler()));
 
 166     private static class SpyingInvocationHandler implements InvocationHandler {
 
 168         private Map<String, String> mdc;
 
 171         public Object invoke(Object proxy, Method method, Object[] args) {
 
 173             // return the remembered MDC for spying
 
 174             if (method.getName().equals("mdc")) {
 
 178             // filter out everything that's not related to audit
 
 179             if (!method.getName().equals("info") || args.length == 0 || !args[0].equals(Markers.AUDIT)) {
 
 180                 throw new UnsupportedOperationException("Method " + method.getName() + " with arguments " +
 
 181                     Arrays.toString(args) + " wasn't supposed to be called");
 
 184             // remember the MDC that was active during the invocation
 
 185             mdc = MDC.getCopyOfContextMap();