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.servlet.jaxrs;
19 import static org.easymock.EasyMock.anyObject;
20 import static org.easymock.EasyMock.anyString;
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;
50 * Unit testing JAX-RS response filter.
55 @RunWith(PowerMockRunner.class)
56 public class LoggingResponseFilterTest {
58 private static final Class RESOURCE_TYPE = Resource.class;
59 private static final Method RESOURCE_METHOD = Resource.class.getDeclaredMethods()[0];
62 public TestName testName = new TestName();
65 public void prepareLoggingContext() {
70 * Verify all mocks after each test.
73 public void verifyMocks() {
76 PowerMock.verifyAll();
77 } catch (AssertionError e) {
78 throw new AssertionError("Expectations failed in " + testName.getMethodName() + "()", e);
83 @PrepareForTest({LoggingContext.class, LoggerFactory.class})
84 public void noAuditWhenNoMatchingResource() {
86 PowerMock.mockStatic(LoggerFactory.class);
87 mockFilterLogger(logger -> {
88 logger.debug(anyString());
89 EasyMock.expectLastCall();
91 PowerMock.replay(LoggerFactory.class);
93 LoggingResponseFilter responseFilter = new LoggingResponseFilter();
94 responseFilter.filter(mockDisabledRequestContext(), mockDisabledResponseContext());
98 @PrepareForTest({LoggingContext.class, LoggerFactory.class})
99 public void noAuditWhenNullResource() {
101 PowerMock.mockStatic(LoggerFactory.class);
102 mockFilterLogger(logger -> {
103 logger.debug(anyString());
104 EasyMock.expectLastCall();
106 PowerMock.replay(LoggerFactory.class);
108 LoggingResponseFilter responseFilter = new LoggingResponseFilter();
109 responseFilter.setResource(null);
110 responseFilter.filter(mockDisabledRequestContext(), mockDisabledResponseContext());
114 @PrepareForTest({LoggingContext.class, LoggerFactory.class})
115 public void noAuditWhenAuditDisabled() {
117 PowerMock.mockStatic(LoggerFactory.class);
119 mockResourceLogger(false, AuditData.builder().build());
120 PowerMock.replay(LoggerFactory.class);
122 LoggingResponseFilter responseFilter = new LoggingResponseFilter();
123 responseFilter.setResource(mockResource());
124 responseFilter.filter(mockDisabledRequestContext(), mockDisabledResponseContext());
128 @PrepareForTest({LoggingContext.class, LoggerFactory.class})
129 public void startTimeReadWhenPresentInRequestContext() {
131 final String clientIp = "IP1";
132 final long startTime = 12345L;
133 final Response.Status ok = Response.Status.OK;
135 PowerMock.mockStatic(LoggerFactory.class);
136 mockResourceLogger(true, buildAuditData(startTime, clientIp, ok, StatusCode.COMPLETE));
138 PowerMock.replay(LoggerFactory.class);
140 LoggingResponseFilter filter = new LoggingResponseFilter();
141 filter.setResource(mockResource());
142 filter.setHttpRequest(mockHttpRequest(clientIp));
144 filter.filter(mockRequestContext(startTime), mockResponseContext(ok));
148 @PrepareForTest({LoggingContext.class, LoggerFactory.class})
149 public void startTimeZeroWhenNotPresentInRequestContext() {
151 final String clientIp = "IP2";
152 final Response.Status ok = Response.Status.OK;
154 AuditData expectedAuditData = buildAuditData(0, clientIp, ok, StatusCode.COMPLETE);
156 PowerMock.mockStatic(LoggerFactory.class);
157 mockResourceLogger(true, expectedAuditData);
158 mockFilterLogger(logger -> {
159 logger.error(anyString(), anyObject(Object[].class));
160 EasyMock.expectLastCall();
162 PowerMock.replay(LoggerFactory.class);
164 LoggingResponseFilter filter = new LoggingResponseFilter();
165 filter.setResource(mockResource());
166 filter.setHttpRequest(mockHttpRequest(clientIp));
168 filter.filter(mockRequestContext(null), mockResponseContext(ok));
172 @PrepareForTest({LoggingContext.class, LoggerFactory.class})
173 public void startTimeZeroWhenIncorrectObjectType() {
175 final String clientIp = "IP3";
176 final Response.Status accepted = Response.Status.ACCEPTED;
178 AuditData expectedAuditData = buildAuditData(0, clientIp, accepted, StatusCode.COMPLETE);
180 PowerMock.mockStatic(LoggerFactory.class);
181 mockFilterLogger(logger -> {
182 logger.error(anyString(), anyString(), anyString(), anyObject());
183 EasyMock.expectLastCall();
185 mockResourceLogger(true, expectedAuditData);
186 PowerMock.replay(LoggerFactory.class);
188 LoggingResponseFilter filter = new LoggingResponseFilter();
189 filter.setResource(mockResource());
190 filter.setHttpRequest(mockHttpRequest(clientIp));
192 filter.filter(mockRequestContext("string object"), mockResponseContext(accepted));
196 @PrepareForTest({LoggingContext.class, LoggerFactory.class})
197 public void statusErrorWhenHttpResponseGreaterThan399() {
199 final Response.Status error = Response.Status.BAD_REQUEST;
200 final String clientIp = "IP13";
201 final long startTime = 88668603L;
203 AuditData expectedAuditData = buildAuditData(startTime, clientIp, error, StatusCode.ERROR);
205 PowerMock.mockStatic(LoggerFactory.class);
206 mockResourceLogger(true, expectedAuditData);
208 PowerMock.replay(LoggerFactory.class);
210 LoggingResponseFilter filter = new LoggingResponseFilter();
211 filter.setResource(mockResource());
212 filter.setHttpRequest(mockHttpRequest(clientIp));
214 filter.filter(mockRequestContext(startTime), mockResponseContext(error));
217 private AuditData buildAuditData(long startTime, String clientIp, Response.Status responseStatus,
219 return AuditData.builder().startTime(startTime).responseCode(Integer.toString(responseStatus.getStatusCode()))
220 .responseDescription(responseStatus.getReasonPhrase()).clientIpAddress(clientIp)
221 .statusCode(status).build();
224 private void mockResourceLogger(boolean enabled, AuditData auditData) {
226 Logger resourceLogger = EasyMock.mock(Logger.class);
228 EasyMock.expect(resourceLogger.isAuditEnabled()).andReturn(enabled).atLeastOnce();
231 resourceLogger.audit(EasyMock.cmp(auditData, new AuditDataComparator(), LogicalOperator.EQUAL));
232 EasyMock.expectLastCall();
235 EasyMock.replay(resourceLogger);
237 LoggerFactory.getLogger(RESOURCE_TYPE);
238 PowerMock.expectLastCall().andReturn(resourceLogger);
242 private final void mockFilterLogger(Consumer<Logger>... expectations) {
244 Logger filterLogger = EasyMock.mock(Logger.class);
246 for (Consumer<Logger> expect : expectations) {
247 expect.accept(filterLogger);
250 EasyMock.replay(filterLogger);
252 LoggerFactory.getLogger(LoggingResponseFilter.class);
253 PowerMock.expectLastCall().andReturn(filterLogger);
256 private void mockLoggingContext() {
257 PowerMock.mockStatic(LoggingContext.class);
258 LoggingContext.clear();
259 EasyMock.expectLastCall();
260 PowerMock.replay(LoggingContext.class);
263 private ContainerRequestContext mockDisabledRequestContext() {
264 ContainerRequestContext requestContext = EasyMock.mock(ContainerRequestContext.class);
265 EasyMock.replay(requestContext);
266 return requestContext;
269 private ContainerResponseContext mockDisabledResponseContext() {
270 ContainerResponseContext responseContext = EasyMock.mock(ContainerResponseContext.class);
271 EasyMock.replay(responseContext);
272 return responseContext;
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;
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;
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;
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);
305 private static class AuditDataComparator implements Comparator<AuditData> {
308 public int compare(AuditData one, AuditData two) {
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())) {
325 @SuppressWarnings("unused")