2 * ============LICENSE_START=======================================================
4 * ================================================================================
5 * Copyright (C) 2018 AT&T Intellectual Property. All rights reserved.
6 * ================================================================================
7 * Licensed under the Apache License, Version 2.0 (the "License");
8 * you may not use this file except in compliance with the License.
9 * You may obtain a copy of the License at
11 * http://www.apache.org/licenses/LICENSE-2.0
13 * Unless required by applicable law or agreed to in writing, software
14 * distributed under the License is distributed on an "AS IS" BASIS,
15 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16 * See the License for the specific language governing permissions and
17 * limitations under the License.
18 * ============LICENSE_END=========================================================
21 package com.woorea.openstack.connector;
23 import static org.junit.Assert.assertTrue;
24 import static org.mockito.Matchers.any;
25 import static org.mockito.Mockito.doCallRealMethod;
26 import static org.mockito.Mockito.mock;
27 import static org.mockito.Mockito.when;
29 import java.io.ByteArrayInputStream;
30 import java.io.IOException;
31 import java.io.OutputStream;
32 import java.lang.reflect.Method;
34 import java.util.Arrays;
35 import java.util.HashMap;
36 import java.util.List;
37 import java.util.logging.ConsoleHandler;
38 import java.util.logging.Level;
39 import java.util.logging.LogRecord;
40 import java.util.logging.Logger;
41 import java.util.logging.SimpleFormatter;
43 import javax.ws.rs.core.MultivaluedMap;
45 import org.junit.Before;
46 import org.junit.BeforeClass;
47 import org.junit.Test;
48 import org.mockito.invocation.InvocationOnMock;
49 import org.mockito.stubbing.Answer;
51 import com.sun.jersey.api.client.ClientHandler;
52 import com.sun.jersey.api.client.ClientRequest;
53 import com.sun.jersey.api.client.ClientRequestAdapter;
54 import com.sun.jersey.api.client.ClientResponse;
55 import com.sun.jersey.api.client.filter.ClientFilter;
57 public class JerseyLoggingFilterTest {
59 private static Logger logger;
60 private static LogFormatter logFormatter;
63 public static void setUpClass() throws Exception {
64 logger = Logger.getLogger(JerseyLoggingFilterTest.class.getSimpleName());
65 logger.setLevel(Level.ALL);
66 logger.setUseParentHandlers(false);
68 ConsoleHandler handler = new ConsoleHandler();
69 logFormatter = new LogFormatter();
70 handler.setFormatter(logFormatter);
71 handler.setLevel(Level.ALL);
72 logger.addHandler(handler);
76 public void setUpTest() {
77 logFormatter.clearLog();
81 * Tests a scenario with no request content (GET).
82 * @throws Exception for unexpected errors
85 public void testGET() throws Exception {
86 String responseContent = "<response>Hello, I am Eliza.</response>";
87 execute("GET", "http://www.onap.org/eliza", null, responseContent);
91 * Tests a scenario with request content (POST).
92 * @throws Exception for unexpected errors
95 public void testPOST() throws Exception {
96 String requestContent = "<request>I feel sad.</request>";
97 String responseContent = "<response>Do you often feel sad?</response>";
98 execute("POST", "http://www.onap.org/eliza", requestContent, responseContent);
102 * Runs a single test.
103 * @param httpMethod any HTTP method (POST, GET, ...)
105 * @param requestContent mock request content, possibly null
106 * @param responseContent mock response content, never null
107 * @throws Exception for unexpected errors
109 private void execute(String httpMethod, String url, String requestContent, String responseContent)
111 JerseyLoggingFilter loggingFilter = new JerseyLoggingFilter(logger);
113 // Mock multi-valued and single valued request headers
115 HashMap<String, List<Object>> requestHeaderMap = new HashMap<>();
116 requestHeaderMap.put("Accept", Arrays.asList(new Object[]{"application/xml","application/json"}));
118 if (requestContent != null) {
119 requestHeaderMap.put("Content-Type", Arrays.asList(new Object[]{"application/xml"}));
120 requestHeaderMap.put("Content-Length", Arrays.asList(new Object[]{String.valueOf(requestContent.length())}));
123 @SuppressWarnings("unchecked")
124 MultivaluedMap<String, Object> requestHeaders = mock(MultivaluedMap.class);
125 when(requestHeaders.entrySet()).thenReturn(requestHeaderMap.entrySet());
127 // Mock the request object
129 ClientRequest request = mock(TestClientRequest.class);
130 when(request.getURI()).thenReturn(new URI(url));
131 when(request.getMethod()).thenReturn(httpMethod);
132 when(request.getHeaders()).thenReturn(requestHeaders);
134 if (requestContent != null) {
135 when(request.getEntity()).thenReturn(requestContent.getBytes("UTF-8"));
138 doCallRealMethod().when(request).setAdapter(any(ClientRequestAdapter.class));
139 when(request.getAdapter()).thenCallRealMethod();
140 request.setAdapter(new DefaultClientRequestAdapter());
142 // Mock multi-valued and single valued response headers
144 HashMap<String, List<String>> responseHeaderMap = new HashMap<>();
145 responseHeaderMap.put("Cache-Control", Arrays.asList(new String[]{"no-cache","no-store"}));
146 responseHeaderMap.put("Content-Type", Arrays.asList(new String[]{"application/xml"}));
147 responseHeaderMap.put("Content-Length", Arrays.asList(new String[]{String.valueOf(responseContent.length())}));
148 @SuppressWarnings("unchecked")
149 MultivaluedMap<String, String> responseHeaders = mock(MultivaluedMap.class);
150 when(responseHeaders.entrySet()).thenReturn(responseHeaderMap.entrySet());
152 // Mock the response object
154 ClientResponse response = mock(ClientResponse.class);
155 when(response.getStatus()).thenReturn(200);
156 when(response.getHeaders()).thenReturn(responseHeaders);
157 when(response.getEntityInputStream()).thenReturn(
158 new ByteArrayInputStream(responseContent.getBytes("UTF-8")));
160 // Mock a handler that returns the response object and set
161 // it to be the next filter after the logging filter.
163 ClientFilter handler = mock(ClientFilter.class);
164 when(handler.handle(request)).then(produceResponse(response));
165 Method setNext = ClientFilter.class.getDeclaredMethod("setNext", new Class<?>[]{ClientHandler.class});
166 setNext.setAccessible(true);
167 setNext.invoke(loggingFilter, new Object[]{handler});
169 // Run the request into the logging filter
171 loggingFilter.handle(request);
173 // Validate resulting the log content
175 String log = logFormatter.getLog();
177 assertContains(log, "* Client out-bound request");
178 assertContains(log, "> " + httpMethod + " " + url);
180 for (String header : requestHeaderMap.keySet()) {
181 assertContains(log, "> " + header + ": ");
184 if (requestContent != null) {
185 assertContains(log, requestContent);
188 assertContains(log, "* Client in-bound response");
189 assertContains(log, "< 200");
191 for (String header : responseHeaderMap.keySet()) {
192 assertContains(log, "< " + header + ": ");
195 assertContains(log, responseContent);
198 private void assertContains(String log, String expect) {
199 assertTrue("Log does not contain '" + expect + "'", log.contains(expect));
202 private class DefaultClientRequestAdapter implements ClientRequestAdapter {
204 public OutputStream adapt(ClientRequest request, OutputStream out) throws IOException {
209 private abstract class TestClientRequest extends ClientRequest {
210 private ClientRequestAdapter adapter;
213 public ClientRequestAdapter getAdapter() {
218 public void setAdapter(ClientRequestAdapter adapter) {
219 this.adapter = adapter;
223 private Answer<ClientResponse> produceResponse(final ClientResponse response) {
224 return new Answer<ClientResponse>() {
225 public ClientResponse answer(InvocationOnMock invocation) throws IOException {
226 ClientRequest request = (ClientRequest) invocation.getArguments()[0];
227 byte[] entity = (byte[]) request.getEntity();
229 if (entity != null) {
230 ClientRequestAdapter adapter = request.getAdapter();
232 OutputStream nullOutputStream = new OutputStream() {
234 public void write(int b) {
239 OutputStream outputStream = adapter.adapt(request, nullOutputStream);
240 outputStream.write(entity);
241 outputStream.close();
249 private static class LogFormatter extends SimpleFormatter {
250 StringBuilder buffer = new StringBuilder();
252 public synchronized String getLog() {
253 return buffer.toString();
256 public synchronized void clearLog() {
261 public synchronized String format(LogRecord record) {
262 String logData = super.format(record);
263 buffer.append(logData);