3ebad7c4ada6fb4fbc1b513c7073e0ded74ea550
[so/libs.git] /
1 /*-
2  * ============LICENSE_START=======================================================
3  * ONAP - SO
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
10  *
11  *      http://www.apache.org/licenses/LICENSE-2.0
12  *
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=========================================================
19  */
20
21 package com.woorea.openstack.connector;
22
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;
28
29 import java.io.ByteArrayInputStream;
30 import java.io.IOException;
31 import java.io.OutputStream;
32 import java.lang.reflect.Method;
33 import java.net.URI;
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;
42
43 import javax.ws.rs.core.MultivaluedMap;
44
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;
50
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;
56
57 public class JerseyLoggingFilterTest {
58
59     private static Logger logger;
60     private static LogFormatter logFormatter;
61     
62     @BeforeClass
63     public static void setUpClass() throws Exception {
64         logger = Logger.getLogger(JerseyLoggingFilterTest.class.getSimpleName());
65         logger.setLevel(Level.ALL);
66         logger.setUseParentHandlers(false);
67
68         ConsoleHandler handler = new ConsoleHandler();
69         logFormatter = new LogFormatter();
70         handler.setFormatter(logFormatter);
71         handler.setLevel(Level.ALL);
72         logger.addHandler(handler);
73     }
74
75     @Before
76     public void setUpTest() {
77         logFormatter.clearLog();
78     }
79     
80     /**
81      * Tests a scenario with no request content (GET).
82      * @throws Exception for unexpected errors
83      */
84     @Test
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);
88     }
89     
90     /**
91      * Tests a scenario with request content (POST).
92      * @throws Exception for unexpected errors
93      */
94     @Test
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);
99     }
100
101     /**
102      * Runs a single test.
103      * @param httpMethod any HTTP method (POST, GET, ...)
104      * @param url any URL
105      * @param requestContent mock request content, possibly null
106      * @param responseContent mock response content, never null
107      * @throws Exception for unexpected errors
108      */
109     private void execute(String httpMethod, String url, String requestContent, String responseContent)
110             throws Exception {
111         JerseyLoggingFilter loggingFilter = new JerseyLoggingFilter(logger);
112
113         // Mock multi-valued and single valued request headers
114
115         HashMap<String, List<Object>> requestHeaderMap = new HashMap<>();
116         requestHeaderMap.put("Accept", Arrays.asList(new Object[]{"application/xml","application/json"}));
117
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())}));
121         }
122
123         @SuppressWarnings("unchecked")
124         MultivaluedMap<String, Object> requestHeaders = mock(MultivaluedMap.class);
125         when(requestHeaders.entrySet()).thenReturn(requestHeaderMap.entrySet());
126
127         // Mock the request object
128
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);
133
134         if (requestContent != null) {
135             when(request.getEntity()).thenReturn(requestContent.getBytes("UTF-8"));
136         }
137
138         doCallRealMethod().when(request).setAdapter(any(ClientRequestAdapter.class));
139         when(request.getAdapter()).thenCallRealMethod();
140         request.setAdapter(new DefaultClientRequestAdapter());
141
142         // Mock multi-valued and single valued response headers
143
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());
151
152         // Mock the response object
153
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")));
159
160         // Mock a handler that returns the response object and set
161         // it to be the next filter after the logging filter.
162
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});
168
169         // Run the request into the logging filter
170
171         loggingFilter.handle(request);
172
173         // Validate resulting the log content
174
175         String log = logFormatter.getLog();
176
177         assertContains(log, "* Client out-bound request");
178         assertContains(log, "> " + httpMethod + " " + url);
179
180         for (String header : requestHeaderMap.keySet()) {
181             assertContains(log, "> " + header + ": ");
182         }
183
184         if (requestContent != null) {
185             assertContains(log, requestContent);
186         }
187
188         assertContains(log, "* Client in-bound response");
189         assertContains(log, "< 200");
190
191         for (String header : responseHeaderMap.keySet()) {
192             assertContains(log, "< " + header + ": ");
193         }
194
195         assertContains(log, responseContent);
196     }
197     
198     private void assertContains(String log, String expect) {
199         assertTrue("Log does not contain '" + expect + "'", log.contains(expect));
200     }
201
202     private class DefaultClientRequestAdapter implements ClientRequestAdapter {
203         @Override
204         public OutputStream adapt(ClientRequest request, OutputStream out) throws IOException {
205             return out;
206         }
207     }
208
209     private abstract class TestClientRequest extends ClientRequest {
210         private ClientRequestAdapter adapter;
211
212         @Override
213         public ClientRequestAdapter getAdapter() {
214             return adapter;
215         }
216
217         @Override
218         public void setAdapter(ClientRequestAdapter adapter) {
219             this.adapter = adapter;
220         }
221     }
222     
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();
228
229                 if (entity != null) {
230                     ClientRequestAdapter adapter = request.getAdapter();
231     
232                     OutputStream nullOutputStream = new OutputStream() {
233                         @Override
234                         public void write(int b) {
235                             // Discard
236                         }
237                     };
238
239                     OutputStream outputStream = adapter.adapt(request, nullOutputStream);
240                     outputStream.write(entity);
241                     outputStream.close();
242                 }
243
244                 return response;
245             }
246         };
247     }
248
249     private static class LogFormatter extends SimpleFormatter {
250         StringBuilder buffer = new StringBuilder();
251
252         public synchronized String getLog() {
253             return buffer.toString();
254         }
255
256         public synchronized void clearLog() {
257             buffer.setLength(0);
258         }
259
260         @Override
261         public synchronized String format(LogRecord record) {
262             String logData = super.format(record);
263             buffer.append(logData);
264             return logData;
265         }
266     }
267 }