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