710cf12b7e3ff94472954306dfb92dce798e843c
[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.servlet.jaxrs;
18
19 import static org.easymock.EasyMock.anyObject;
20 import static org.easymock.EasyMock.anyString;
21
22 import java.lang.reflect.Method;
23 import java.util.Comparator;
24 import java.util.Objects;
25 import java.util.function.Consumer;
26 import javax.servlet.http.HttpServletRequest;
27 import javax.ws.rs.container.ContainerRequestContext;
28 import javax.ws.rs.container.ContainerResponseContext;
29 import javax.ws.rs.container.ResourceInfo;
30 import javax.ws.rs.core.Response;
31 import org.easymock.EasyMock;
32 import org.easymock.LogicalOperator;
33 import org.junit.After;
34 import org.junit.Before;
35 import org.junit.Rule;
36 import org.junit.Test;
37 import org.junit.rules.TestName;
38 import org.junit.runner.RunWith;
39 import org.openecomp.sdc.logging.api.AuditData;
40 import org.openecomp.sdc.logging.api.Logger;
41 import org.openecomp.sdc.logging.api.LoggerFactory;
42 import org.openecomp.sdc.logging.api.LoggingContext;
43 import org.openecomp.sdc.logging.api.StatusCode;
44 import org.powermock.api.easymock.PowerMock;
45 import org.powermock.core.classloader.annotations.PrepareForTest;
46 import org.powermock.modules.junit4.PowerMockRunner;
47
48
49 /**
50  * Unit testing JAX-RS response filter.
51  *
52  * @author evitaliy
53  * @since 19 Mar 2018
54  */
55 @RunWith(PowerMockRunner.class)
56 public class LoggingResponseFilterTest {
57
58     private static final Class RESOURCE_TYPE = Resource.class;
59     private static final Method RESOURCE_METHOD = Resource.class.getDeclaredMethods()[0];
60
61     @Rule
62     public TestName testName = new TestName();
63
64     @Before
65     public void prepareLoggingContext() {
66         mockLoggingContext();
67     }
68
69     /**
70      * Verify all mocks after each test.
71      */
72     @After
73     public void verifyMocks() {
74
75         try {
76             PowerMock.verifyAll();
77         } catch (AssertionError e) {
78             throw new AssertionError("Expectations failed in " + testName.getMethodName() + "()", e);
79         }
80     }
81
82     @Test
83     @PrepareForTest({LoggingContext.class, LoggerFactory.class})
84     public void noAuditWhenNoMatchingResource() {
85
86         PowerMock.mockStatic(LoggerFactory.class);
87         mockFilterLogger(logger -> {
88             logger.debug(anyString());
89             EasyMock.expectLastCall();
90         });
91         PowerMock.replay(LoggerFactory.class);
92
93         LoggingResponseFilter responseFilter = new LoggingResponseFilter();
94         responseFilter.filter(mockDisabledRequestContext(), mockDisabledResponseContext());
95     }
96
97     @Test
98     @PrepareForTest({LoggingContext.class, LoggerFactory.class})
99     public void noAuditWhenNullResource() {
100
101         PowerMock.mockStatic(LoggerFactory.class);
102         mockFilterLogger(logger -> {
103             logger.debug(anyString());
104             EasyMock.expectLastCall();
105         });
106         PowerMock.replay(LoggerFactory.class);
107
108         LoggingResponseFilter responseFilter = new LoggingResponseFilter();
109         responseFilter.setResource(null);
110         responseFilter.filter(mockDisabledRequestContext(), mockDisabledResponseContext());
111     }
112
113     @Test
114     @PrepareForTest({LoggingContext.class, LoggerFactory.class})
115     public void noAuditWhenAuditDisabled() {
116
117         PowerMock.mockStatic(LoggerFactory.class);
118         mockFilterLogger();
119         mockResourceLogger(false, AuditData.builder().build());
120         PowerMock.replay(LoggerFactory.class);
121
122         LoggingResponseFilter responseFilter = new LoggingResponseFilter();
123         responseFilter.setResource(mockResource());
124         responseFilter.filter(mockDisabledRequestContext(), mockDisabledResponseContext());
125     }
126
127     @Test
128     @PrepareForTest({LoggingContext.class, LoggerFactory.class})
129     public void startTimeReadWhenPresentInRequestContext() {
130
131         final String clientIp = "IP1";
132         final long startTime = 12345L;
133         final Response.Status ok = Response.Status.OK;
134
135         PowerMock.mockStatic(LoggerFactory.class);
136         mockResourceLogger(true, buildAuditData(startTime, clientIp, ok, StatusCode.COMPLETE));
137         mockFilterLogger();
138         PowerMock.replay(LoggerFactory.class);
139
140         LoggingResponseFilter filter = new LoggingResponseFilter();
141         filter.setResource(mockResource());
142         filter.setHttpRequest(mockHttpRequest(clientIp));
143
144         filter.filter(mockRequestContext(startTime), mockResponseContext(ok));
145     }
146
147     @Test
148     @PrepareForTest({LoggingContext.class, LoggerFactory.class})
149     public void startTimeZeroWhenNotPresentInRequestContext() {
150
151         final String clientIp = "IP2";
152         final Response.Status ok = Response.Status.OK;
153
154         AuditData expectedAuditData = buildAuditData(0, clientIp, ok, StatusCode.COMPLETE);
155
156         PowerMock.mockStatic(LoggerFactory.class);
157         mockResourceLogger(true, expectedAuditData);
158         mockFilterLogger(logger -> {
159             logger.error(anyString(), anyObject(Object[].class));
160             EasyMock.expectLastCall();
161         });
162         PowerMock.replay(LoggerFactory.class);
163
164         LoggingResponseFilter filter = new LoggingResponseFilter();
165         filter.setResource(mockResource());
166         filter.setHttpRequest(mockHttpRequest(clientIp));
167
168         filter.filter(mockRequestContext(null), mockResponseContext(ok));
169     }
170
171     @Test
172     @PrepareForTest({LoggingContext.class, LoggerFactory.class})
173     public void startTimeZeroWhenIncorrectObjectType() {
174
175         final String clientIp = "IP3";
176         final Response.Status accepted = Response.Status.ACCEPTED;
177
178         AuditData expectedAuditData = buildAuditData(0, clientIp, accepted, StatusCode.COMPLETE);
179
180         PowerMock.mockStatic(LoggerFactory.class);
181         mockFilterLogger(logger -> {
182             logger.error(anyString(), anyString(), anyString(), anyObject());
183             EasyMock.expectLastCall();
184         });
185         mockResourceLogger(true, expectedAuditData);
186         PowerMock.replay(LoggerFactory.class);
187
188         LoggingResponseFilter filter = new LoggingResponseFilter();
189         filter.setResource(mockResource());
190         filter.setHttpRequest(mockHttpRequest(clientIp));
191
192         filter.filter(mockRequestContext("string object"), mockResponseContext(accepted));
193     }
194
195     @Test
196     @PrepareForTest({LoggingContext.class, LoggerFactory.class})
197     public void statusErrorWhenHttpResponseGreaterThan399() {
198
199         final Response.Status error = Response.Status.BAD_REQUEST;
200         final String clientIp = "IP13";
201         final long startTime = 88668603L;
202
203         AuditData expectedAuditData = buildAuditData(startTime, clientIp, error, StatusCode.ERROR);
204
205         PowerMock.mockStatic(LoggerFactory.class);
206         mockResourceLogger(true, expectedAuditData);
207         mockFilterLogger();
208         PowerMock.replay(LoggerFactory.class);
209
210         LoggingResponseFilter filter = new LoggingResponseFilter();
211         filter.setResource(mockResource());
212         filter.setHttpRequest(mockHttpRequest(clientIp));
213
214         filter.filter(mockRequestContext(startTime), mockResponseContext(error));
215     }
216
217     private AuditData buildAuditData(long startTime, String clientIp, Response.Status responseStatus,
218             StatusCode status) {
219         return AuditData.builder().startTime(startTime).responseCode(Integer.toString(responseStatus.getStatusCode()))
220                         .responseDescription(responseStatus.getReasonPhrase()).clientIpAddress(clientIp)
221                         .statusCode(status).build();
222     }
223
224     private void mockResourceLogger(boolean enabled, AuditData auditData) {
225
226         Logger resourceLogger = EasyMock.mock(Logger.class);
227
228         EasyMock.expect(resourceLogger.isAuditEnabled()).andReturn(enabled).atLeastOnce();
229
230         if (enabled) {
231             resourceLogger.audit(EasyMock.cmp(auditData, new AuditDataComparator(), LogicalOperator.EQUAL));
232             EasyMock.expectLastCall();
233         }
234
235         EasyMock.replay(resourceLogger);
236
237         LoggerFactory.getLogger(RESOURCE_TYPE);
238         PowerMock.expectLastCall().andReturn(resourceLogger);
239     }
240
241     @SafeVarargs
242     private final void mockFilterLogger(Consumer<Logger>... expectations) {
243
244         Logger filterLogger = EasyMock.mock(Logger.class);
245
246         for (Consumer<Logger> expect : expectations) {
247             expect.accept(filterLogger);
248         }
249
250         EasyMock.replay(filterLogger);
251
252         LoggerFactory.getLogger(LoggingResponseFilter.class);
253         PowerMock.expectLastCall().andReturn(filterLogger);
254     }
255
256     private void mockLoggingContext() {
257         PowerMock.mockStatic(LoggingContext.class);
258         LoggingContext.clear();
259         EasyMock.expectLastCall();
260         PowerMock.replay(LoggingContext.class);
261     }
262
263     private ContainerRequestContext mockDisabledRequestContext() {
264         ContainerRequestContext requestContext = EasyMock.mock(ContainerRequestContext.class);
265         EasyMock.replay(requestContext);
266         return requestContext;
267     }
268
269     private ContainerResponseContext mockDisabledResponseContext() {
270         ContainerResponseContext responseContext = EasyMock.mock(ContainerResponseContext.class);
271         EasyMock.replay(responseContext);
272         return responseContext;
273     }
274
275     private HttpServletRequest mockHttpRequest(String clientIp) {
276         HttpServletRequest servletRequest = EasyMock.mock(HttpServletRequest.class);
277         EasyMock.expect(servletRequest.getRemoteAddr()).andReturn(clientIp);
278         EasyMock.replay(servletRequest);
279         return servletRequest;
280     }
281
282     private ContainerRequestContext mockRequestContext(Object startTime) {
283         ContainerRequestContext requestContext = EasyMock.mock(ContainerRequestContext.class);
284         EasyMock.expect(requestContext.getProperty(LoggingRequestFilter.START_TIME_KEY)).andReturn(startTime);
285         EasyMock.replay(requestContext);
286         return requestContext;
287     }
288
289     private ContainerResponseContext mockResponseContext(Response.StatusType statusInfo) {
290         ContainerResponseContext responseContext = EasyMock.mock(ContainerResponseContext.class);
291         EasyMock.expect(responseContext.getStatusInfo()).andReturn(statusInfo);
292         EasyMock.replay(responseContext);
293         return responseContext;
294     }
295
296     private ResourceInfo mockResource() {
297         ResourceInfo resource = EasyMock.mock(ResourceInfo.class);
298         //noinspection unchecked
299         EasyMock.expect(resource.getResourceClass()).andReturn(RESOURCE_TYPE).anyTimes();
300         EasyMock.expect(resource.getResourceMethod()).andReturn(RESOURCE_METHOD).anyTimes();
301         EasyMock.replay(resource);
302         return resource;
303     }
304
305     private static class AuditDataComparator implements Comparator<AuditData> {
306
307         @Override
308         public int compare(AuditData one, AuditData two) {
309
310             // don't compare end time as it changes
311             if (Objects.equals(one.getClientIpAddress(), two.getClientIpAddress())
312                         && Objects.equals(one.getResponseCode(), two.getResponseCode())
313                         && Objects.equals(one.getResponseDescription(), two.getResponseDescription())
314                         && one.getStartTime() == two.getStartTime()
315                         && Objects.equals(one.getStatusCode(), two.getStatusCode())) {
316
317                 return 0;
318             }
319
320             return -1;
321         }
322     }
323
324     interface Resource {
325         @SuppressWarnings("unused")
326         void method();
327     }
328 }