remove ability to disable cert chain validation
[aai/rest-client.git] / src / test / java / org / onap / aai / restclient / client / RestfulClientTest.java
1 /*
2  * ============LICENSE_START===========================================================================================
3  * Copyright (c) 2017 AT&T Intellectual Property.
4  * Copyright (c) 2017 Amdocs 
5  * Modification Copyright (c) 2018 IBM. 
6  * All rights reserved.
7  * =====================================================================================================================
8  * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with
9  * the License. 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 distributed under the License is distributed on
14  * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the
15  * specific language governing permissions and limitations under the License.
16  * ============LICENSE_END================================================== ===========================================
17  * 
18  * ECOMP and OpenECOMP are trademarks and service marks of AT&T Intellectual Property.
19  */
20 package org.onap.aai.restclient.client;
21
22 import static org.junit.Assert.assertEquals;
23 import static org.junit.Assert.assertNotNull;
24 import static org.junit.Assert.assertNull;
25 import static org.junit.Assert.assertTrue;
26
27 import javax.ws.rs.core.MediaType;
28 import javax.ws.rs.core.Response;
29 import javax.ws.rs.core.Response.Status;
30
31 import org.junit.Before;
32 import org.junit.Test;
33 import org.mockito.ArgumentCaptor;
34 import org.mockito.Mockito;
35 import org.onap.aai.restclient.client.OperationResult;
36 import org.onap.aai.restclient.client.RestClient;
37 import org.onap.aai.restclient.enums.RestAuthenticationMode;
38 import org.onap.aai.restclient.rest.RestClientBuilder;
39
40 import com.sun.jersey.api.client.Client;
41 import com.sun.jersey.api.client.ClientResponse;
42 import com.sun.jersey.api.client.UniformInterfaceException;
43 import com.sun.jersey.api.client.WebResource;
44 import com.sun.jersey.api.client.WebResource.Builder;
45 import com.sun.jersey.core.util.MultivaluedMapImpl;
46
47 public class RestfulClientTest {
48
49     private static final String TEST_URL = "http://localhost:9000/aai/v7";
50
51     private final MultivaluedMapImpl emptyMap = new MultivaluedMapImpl();
52
53     private RestClientBuilder mockClientBuilder;
54     private Client mockedClient;
55     private WebResource mockedWebResource;
56     private Builder mockedBuilder;
57     private ClientResponse mockedClientResponse;
58
59     /**
60      * Test case initialization
61      * 
62      * @throws Exception the exception
63      */
64     @SuppressWarnings("unchecked")
65     @Before
66     public void init() throws Exception {
67         mockedClientResponse = Mockito.mock(ClientResponse.class);
68         setResponseStatus(Response.Status.OK);
69         Mockito.when(mockedClientResponse.getHeaders()).thenReturn(emptyMap);
70         Mockito.when(mockedClientResponse.getEntity(String.class)).thenReturn("hello");
71
72         mockedBuilder = Mockito.mock(Builder.class);
73         Mockito.when(mockedBuilder.get(Mockito.any(Class.class))).thenReturn(mockedClientResponse);
74         Mockito.when(mockedBuilder.post(Mockito.any(Class.class))).thenReturn(mockedClientResponse);
75         Mockito.when(mockedBuilder.put(Mockito.any(Class.class))).thenReturn(mockedClientResponse);
76         Mockito.when(mockedBuilder.delete(Mockito.any(Class.class))).thenReturn(mockedClientResponse);
77         Mockito.when(mockedBuilder.head()).thenReturn(mockedClientResponse);
78
79         mockedWebResource = Mockito.mock(WebResource.class);
80         Mockito.when(mockedWebResource.accept(Mockito.<MediaType>anyVararg())).thenReturn(mockedBuilder);
81
82         mockedClient = Mockito.mock(Client.class);
83         Mockito.when(mockedClient.resource(Mockito.anyString())).thenReturn(mockedWebResource);
84
85         mockClientBuilder = Mockito.mock(RestClientBuilder.class);
86         Mockito.when(mockClientBuilder.getClient()).thenReturn(mockedClient);
87     }
88
89     @Test
90     public void validateConstructors() {
91         RestClient restClient = new RestClient();
92         assertNotNull(restClient);
93         restClient = new RestClient(mockClientBuilder);
94         assertNotNull(restClient);
95     }
96
97     @Test
98     public void validateBasicClientConstruction() throws Exception {
99         Client client = new RestClient(mockClientBuilder).authenticationMode(RestAuthenticationMode.HTTP_NOAUTH)
100                 .connectTimeoutMs(1000).readTimeoutMs(500).getClient();
101         assertNotNull(client);
102     }
103
104     @Test
105     public void validateClientWithSslBasicAuthConstruction() throws Exception {
106         Client client = new RestClient(mockClientBuilder).authenticationMode(RestAuthenticationMode.SSL_BASIC)
107                 .connectTimeoutMs(1000).readTimeoutMs(500).basicAuthPassword("password").basicAuthUsername("username")
108                 .getClient();
109         assertNotNull(client);
110     }
111
112     @Test
113     public void validateClientWithSslCertConstruction() throws Exception {
114         // This test covers the standard SSL settings, i.e. no validation
115         assertNotNull(buildClient());
116
117         RestClient restClient = new RestClient(mockClientBuilder);
118
119         // Test with validation enabled
120         Client client = restClient.authenticationMode(RestAuthenticationMode.SSL_CERT).connectTimeoutMs(1000)
121                 .readTimeoutMs(500).clientCertFile("cert").clientCertPassword("password").validateServerCertChain(true)
122                 .validateServerHostname(true).getClient();
123         assertNotNull(client);
124
125         // Test with a trust store
126         client = restClient.authenticationMode(RestAuthenticationMode.SSL_CERT).connectTimeoutMs(1000)
127                 .readTimeoutMs(500).clientCertFile("cert").clientCertPassword("password").trustStore("truststore")
128                 .getClient();
129         assertNotNull(client);
130     }
131
132     @Test
133     public void validateSuccessfulPut() throws Exception {
134         RestClient restClient = buildClient();
135
136         OperationResult result = restClient.put(TEST_URL, "", emptyMap, MediaType.APPLICATION_JSON_TYPE,
137                 MediaType.APPLICATION_JSON_TYPE);
138
139         assertEquals(Response.Status.OK.getStatusCode(), result.getResultCode());
140         assertNotNull(result.getResult());
141         assertNull(result.getFailureCause());
142
143         // Repeat the PUT operation, this time with a return code of 204
144         setResponseToNoContent();
145         result = restClient.put(TEST_URL, "", emptyMap, MediaType.APPLICATION_JSON_TYPE,
146                 MediaType.APPLICATION_JSON_TYPE);
147
148         assertEquals(Response.Status.NO_CONTENT.getStatusCode(), result.getResultCode());
149         assertNull(result.getResult());
150         assertNull(result.getFailureCause());
151     }
152
153     @Test
154     public void validateSuccessfulPost() throws Exception {
155         RestClient restClient = buildClient();
156
157         OperationResult result = restClient.post(TEST_URL, "", emptyMap, MediaType.APPLICATION_JSON_TYPE,
158                 MediaType.APPLICATION_JSON_TYPE);
159
160         assertEquals(Response.Status.OK.getStatusCode(), result.getResultCode());
161         assertNotNull(result.getResult());
162         assertNull(result.getFailureCause());
163
164         // Repeat the POST operation, this time with a return code of 204
165         setResponseToNoContent();
166         result = restClient.post(TEST_URL, "", emptyMap, MediaType.APPLICATION_JSON_TYPE,
167                 MediaType.APPLICATION_JSON_TYPE);
168
169         assertEquals(Response.Status.NO_CONTENT.getStatusCode(), result.getResultCode());
170         assertNull(result.getResult());
171         assertNull(result.getFailureCause());
172     }
173     
174     @Test
175     public void validateSuccessfulPost_withMultivaluedHeader() throws Exception {
176         RestClient restClient = buildClient();
177
178         MultivaluedMapImpl headerMap = new MultivaluedMapImpl();
179         
180         headerMap.add("txnId", "123");
181         headerMap.add("txnId", "456");
182         headerMap.add("txnId", "789");
183
184         OperationResult result = restClient.post(TEST_URL, "", headerMap, MediaType.APPLICATION_JSON_TYPE,
185             MediaType.APPLICATION_JSON_TYPE);
186
187         // capture the txnId header from the outgoing request  
188         ArgumentCaptor<String> txnIdHeaderName = ArgumentCaptor.forClass(String.class);
189         ArgumentCaptor<String> txnIdHeaderValue = ArgumentCaptor.forClass(String.class);
190         
191         Mockito.verify(mockedBuilder, Mockito.atLeast(1)).header(txnIdHeaderName.capture(), txnIdHeaderValue.capture());
192         assertEquals("123;456;789", txnIdHeaderValue.getValue());
193
194         assertEquals(Response.Status.OK.getStatusCode(), result.getResultCode());
195         assertNotNull(result.getResult());
196         assertNull(result.getFailureCause());
197     }
198
199     @Test
200     public void validateSuccessfulGet() throws Exception {
201         OperationResult result = buildClient().get(TEST_URL, emptyMap, MediaType.APPLICATION_JSON_TYPE);
202
203         assertEquals(Response.Status.OK.getStatusCode(), result.getResultCode());
204         assertNotNull(result.getResult());
205         assertNull(result.getFailureCause());
206     }
207
208     @Test
209     public void validateSuccessfulGetWithBasicAuth() throws Exception {
210         RestClient restClient = new RestClient(mockClientBuilder).authenticationMode(RestAuthenticationMode.SSL_BASIC)
211                 .connectTimeoutMs(1000).readTimeoutMs(500).basicAuthUsername("username").basicAuthUsername("password");
212
213         OperationResult result = restClient.get(TEST_URL, emptyMap, MediaType.APPLICATION_JSON_TYPE);
214
215         assertEquals(Response.Status.OK.getStatusCode(), result.getResultCode());
216         assertNotNull(result.getResult());
217         assertNull(result.getFailureCause());
218     }
219
220     @Test
221     public void validateResourceNotFoundGet() throws Exception {
222         setResponseStatus(Response.Status.NOT_FOUND);
223         Mockito.when(mockedClientResponse.getEntity(String.class)).thenReturn("RNF");
224
225         OperationResult result = buildClient().get(TEST_URL, emptyMap, MediaType.APPLICATION_JSON_TYPE);
226
227         assertEquals(Response.Status.NOT_FOUND.getStatusCode(), result.getResultCode());
228         assertNull(result.getResult());
229         assertNotNull(result.getFailureCause());
230     }
231
232     @Test
233     public void validateHealthCheck() throws Exception {
234         boolean targetServiceHealthy =
235                 buildClient().healthCheck("http://localhost:9000/aai/util/echo", "startSerice", "targetService");
236
237         assertEquals(true, targetServiceHealthy);
238     }
239
240     @Test
241     public void validateHealthCheckFailureWith403() throws Exception {
242         Mockito.when(mockedClientResponse.getStatus()).thenReturn(Response.Status.FORBIDDEN.getStatusCode());
243
244         boolean targetServiceHealthy =
245                 buildClient().healthCheck("http://localhost:9000/aai/util/echo", "startSerice", "targetService");
246
247         assertEquals(false, targetServiceHealthy);
248     }
249
250     @Test
251     public void validateHealthCheckFailureWithThrownException() throws Exception {
252         Mockito.when(mockedBuilder.get(Mockito.any(Class.class))).thenThrow(new IllegalArgumentException("error"));
253
254         boolean targetServiceHealthy =
255                 buildClient().healthCheck("http://localhost:9000/aai/util/echo", "startSerice", "targetService");
256
257         assertEquals(false, targetServiceHealthy);
258     }
259
260     @Test
261     public void validateSuccessfulGetWithRetries() throws Exception {
262         Mockito.when(mockedClientResponse.getStatus()).thenReturn(408).thenReturn(Response.Status.OK.getStatusCode());
263         Mockito.when(mockedClientResponse.getEntity(String.class)).thenReturn("error").thenReturn("ok");
264
265         OperationResult result = buildClient().get(TEST_URL, emptyMap, MediaType.APPLICATION_JSON_TYPE, 3);
266
267         assertEquals(Response.Status.OK.getStatusCode(), result.getResultCode());
268         assertNotNull(result.getResult());
269         assertNull(result.getFailureCause());
270
271     }
272
273     @Test
274     public void validateFailedGetWithRetriesCausedByResourceNotFound() throws Exception {
275         setResponseStatus(Response.Status.NOT_FOUND);
276         Mockito.when(mockedClientResponse.getEntity(String.class)).thenReturn("error").thenReturn("ok");
277
278         OperationResult result = buildClient().get(TEST_URL, emptyMap, MediaType.APPLICATION_JSON_TYPE, 3);
279
280         assertEquals(Response.Status.NOT_FOUND.getStatusCode(), result.getResultCode());
281         assertNull(result.getResult());
282         assertNotNull(result.getFailureCause());
283
284     }
285
286     @Test
287     public void validateFailedGetAfterMaxRetries() throws Exception {
288         setResponseStatus(Response.Status.INTERNAL_SERVER_ERROR);
289         Mockito.when(mockedClientResponse.getEntity(String.class)).thenReturn("error");
290
291         OperationResult result = buildClient().get(TEST_URL, emptyMap, MediaType.APPLICATION_JSON_TYPE, 3);
292
293         assertEquals(504, result.getResultCode());
294         assertNull(result.getResult());
295         assertNotNull(result.getFailureCause());
296
297     }
298
299     @Test
300     public void validateSuccessfulDelete() throws Exception {
301         RestClient restClient = buildClient();
302
303         OperationResult result = restClient.delete(TEST_URL, emptyMap, MediaType.APPLICATION_JSON_TYPE);
304
305         assertEquals(Response.Status.OK.getStatusCode(), result.getResultCode());
306         assertNotNull(result.getResult());
307         assertNull(result.getFailureCause());
308
309         // Repeat the DELETE operation, this time with a return code of 204
310         setResponseToNoContent();
311         result = restClient.delete(TEST_URL, emptyMap, MediaType.APPLICATION_JSON_TYPE);
312
313         assertEquals(Response.Status.NO_CONTENT.getStatusCode(), result.getResultCode());
314         assertNull(result.getResult());
315         assertNull(result.getFailureCause());
316     }
317
318
319     @Test
320     public void validateSuccessfulHead() throws Exception {
321         OperationResult result = buildClient().head(TEST_URL, emptyMap, MediaType.APPLICATION_JSON_TYPE);
322
323         assertEquals(Response.Status.OK.getStatusCode(), result.getResultCode());
324         assertNotNull(result.getResult());
325         assertNull(result.getFailureCause());
326
327     }
328
329     @Test
330     public void validateSuccessfulPatch() throws Exception {
331         Mockito.when(mockedBuilder.header("X-HTTP-Method-Override", "PATCH")).thenReturn(mockedBuilder);
332         OperationResult result = buildClient().patch(TEST_URL, "", emptyMap, MediaType.APPLICATION_JSON_TYPE,
333                 MediaType.APPLICATION_JSON_TYPE);
334
335         assertEquals(Response.Status.OK.getStatusCode(), result.getResultCode());
336         assertNotNull(result.getResult());
337         assertNull(result.getFailureCause());
338
339     }
340
341     @Test
342     public void testGetClient() throws Exception {
343         RestClientBuilder restClientBuilder= new RestClientBuilder();
344         restClientBuilder.setAuthenticationMode(RestAuthenticationMode.SSL_BASIC);
345         restClientBuilder.setTruststoreFilename("truststore");
346         assertTrue(restClientBuilder.getClient() instanceof Client);
347     }
348
349     /**
350      * Specify the status code of the response object returned by the mocked client
351      * 
352      * @param status object storing the status code to mock in the ClientResponse
353      */
354     private void setResponseStatus(Status status) {
355         Mockito.when(mockedClientResponse.getStatus()).thenReturn(status.getStatusCode());
356     }
357
358     /**
359      * Set the mocked client to return a response of "204 No Content"
360      */
361     private void setResponseToNoContent() {
362         setResponseStatus(Response.Status.NO_CONTENT);
363         // The Jersey client throws an exception when getEntity() is called following a 204 response
364         UniformInterfaceException uniformInterfaceException = new UniformInterfaceException(mockedClientResponse);
365         Mockito.when(mockedClientResponse.getEntity(String.class)).thenThrow(uniformInterfaceException);
366     }
367
368     /**
369      * @return a mocked Rest Client object using standard SSL settings
370      */
371     private RestClient buildClient() {
372         return new RestClient(mockClientBuilder).authenticationMode(RestAuthenticationMode.SSL_CERT)
373                 .connectTimeoutMs(1000).readTimeoutMs(500).clientCertFile("cert").clientCertPassword("password");
374     }
375 }