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