fdeeb007611d438eece4bc2a6a701692a1a1dbb9
[vid.git] / vid-app-common / src / test / java / org / onap / vid / aai / AaiClientTest.java
1 /*-
2  * ============LICENSE_START=======================================================
3  * VID
4  * ================================================================================
5  * Copyright (C) 2017 - 2019 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 org.onap.vid.aai;
22
23 import com.fasterxml.jackson.core.JsonProcessingException;
24 import com.fasterxml.jackson.databind.ObjectMapper;
25 import com.google.common.collect.ImmutableList;
26 import org.apache.commons.lang3.builder.ReflectionToStringBuilder;
27 import org.apache.commons.lang3.builder.ToStringStyle;
28 import org.apache.commons.lang3.exception.ExceptionUtils;
29 import org.apache.commons.lang3.reflect.FieldUtils;
30 import org.apache.commons.lang3.tuple.Pair;
31 import org.apache.http.HttpStatus;
32 import org.mockito.Mockito;
33 import org.onap.portalsdk.core.logging.logic.EELFLoggerDelegate;
34 import org.onap.portalsdk.core.util.SystemProperties;
35 import org.onap.vid.aai.model.AaiGetNetworkCollectionDetails.RelatedToProperty;
36 import org.onap.vid.aai.model.AaiGetTenatns.GetTenantsResponse;
37 import org.onap.vid.aai.model.*;
38 import org.onap.vid.aai.util.*;
39 import org.onap.vid.controller.LocalWebConfig;
40 import org.onap.vid.exceptions.GenericUncheckedException;
41 import org.onap.vid.model.Subscriber;
42 import org.onap.vid.model.SubscriberList;
43 import org.onap.vid.model.probes.ExternalComponentStatus;
44 import org.onap.vid.model.probes.HttpRequestMetadata;
45 import org.onap.vid.model.probes.StatusMetadata;
46 import org.onap.vid.testUtils.TestUtils;
47 import org.onap.vid.utils.Unchecked;
48 import org.springframework.http.HttpMethod;
49 import org.springframework.test.context.ContextConfiguration;
50 import org.springframework.test.context.web.WebAppConfiguration;
51 import org.testng.Assert;
52 import org.testng.annotations.BeforeMethod;
53 import org.testng.annotations.DataProvider;
54 import org.testng.annotations.Test;
55 import sun.security.provider.certpath.SunCertPathBuilderException;
56 import sun.security.validator.ValidatorException;
57
58 import javax.crypto.BadPaddingException;
59 import javax.net.ssl.SSLHandshakeException;
60 import javax.servlet.ServletContext;
61 import javax.ws.rs.ProcessingException;
62 import javax.ws.rs.client.Client;
63 import javax.ws.rs.core.Response;
64 import java.io.FileNotFoundException;
65 import java.io.IOException;
66 import java.net.URI;
67 import java.security.cert.CertificateException;
68 import java.util.ArrayList;
69 import java.util.Map;
70 import java.util.function.BiConsumer;
71 import java.util.function.Function;
72 import java.util.stream.Collectors;
73 import java.util.stream.Stream;
74
75 import static org.apache.commons.lang3.StringUtils.equalsIgnoreCase;
76 import static org.hamcrest.MatcherAssert.assertThat;
77 import static org.hamcrest.Matchers.*;
78 import static org.mockito.ArgumentMatchers.nullable;
79 import static org.mockito.Matchers.any;
80 import static org.mockito.Matchers.anyBoolean;
81 import static org.mockito.Matchers.anyString;
82 import static org.mockito.Matchers.argThat;
83 import static org.mockito.Matchers.eq;
84 import static org.mockito.Matchers.isNull;
85 import static org.mockito.Mockito.*;
86 import static org.onap.vid.utils.Unchecked.toURI;
87 import static org.testng.Assert.*;
88
89 @ContextConfiguration(classes = {LocalWebConfig.class, SystemProperties.class})
90 @WebAppConfiguration
91 public class AaiClientTest {
92
93     private final String NO_LCP_REGION_AND_TENANTS_MSG = "A&AI has no LCP Region & Tenants associated to subscriber 'subscriberId' and service type 'serviceType'";
94     private AaiClient aaiClientMock;
95     private ServletContext servletContext;
96
97     @BeforeMethod
98     public void initMocks(){
99         aaiClientMock = mock(AaiClient.class);
100         aaiClientMock.logger = mock(EELFLoggerDelegate.class);
101         aaiClientMock.objectMapper = new ObjectMapper();
102         servletContext = mock(ServletContext.class);
103
104         when(servletContext.getRealPath(any(String.class))).thenReturn("");
105
106         when(aaiClientMock.doAaiGet(any(String.class),any(Boolean.class))).thenReturn(null);
107         when(aaiClientMock.doAaiGet(any(URI.class), anyBoolean(), anyBoolean())).thenReturn(null);
108     }
109
110     @DataProvider
111     public static Object[][] logicalLinkData() {
112         return new Object[][] {
113                 {"", "network/logical-links/logical-link/"},
114                 {"link", "network/logical-links/logical-link/link"}
115         };
116     }
117
118     @Test(dataProvider = "logicalLinkData")
119     public void getLogicalLink_Link_Is_Empty(String link, String expectedUrl) {
120
121         when(aaiClientMock.getLogicalLink(any(String.class))).thenCallRealMethod();
122         aaiClientMock.getLogicalLink(link);
123         verify(aaiClientMock).doAaiGet(argThat(s -> equalsIgnoreCase(s, expectedUrl)),any(Boolean.class));
124     }
125
126     @DataProvider
127     public static Object[][] subscribersResults() {
128         return new Object[][] {
129                 {new SubscriberList(new ArrayList<Subscriber>() {{ add(new Subscriber());  add(new Subscriber()); }}), true},
130                 {new SubscriberList(new ArrayList<Subscriber>() {{ add(new Subscriber()); }}), true},
131                 {new SubscriberList(new ArrayList<Subscriber>()), false}
132         };
133     }
134
135     @Test(dataProvider = "subscribersResults")
136     public void testProbeAaiGetAllSubscribers_returnsTwoToZeroSubscribers_ResultsAsExpected(SubscriberList subscribers, boolean isAvailable){
137         ExternalComponentStatus expectedStatus = new ExternalComponentStatus(ExternalComponentStatus.Component.AAI,isAvailable, new HttpRequestMetadata(
138                 HttpMethod.GET,
139                 200,
140                 "url",
141                 "rawData",
142                 isAvailable ? "OK" : "No subscriber received",
143                 0
144         ));
145         Mockito.when(aaiClientMock.getAllSubscribers(true)).thenReturn(
146                 new AaiResponseWithRequestInfo<>(
147                         HttpMethod.GET, "url", new AaiResponse<>(subscribers, null, 200),
148                         "rawData"));
149         Mockito.when(aaiClientMock.probeComponent()).thenCallRealMethod();
150         ExternalComponentStatus result  = aaiClientMock.probeComponent();
151         assertThat(statusDataReflected(result),is(statusDataReflected(expectedStatus)));
152         assertThat(requestMetadataReflected(result.getMetadata()),is(requestMetadataReflected(expectedStatus.getMetadata())));
153     }
154
155     @Test(expectedExceptions = Exception.class)
156     public void typedAaiGet_aaiRestInterfaceRestGetReturnsError_exceptionIsThrown() {
157         AAIRestInterface aaiRestInterface = mock(AAIRestInterface.class);
158         final ResponseWithRequestInfo responseWithRequestInfo = mockedResponseWithRequestInfo(Response.Status.INTERNAL_SERVER_ERROR, "entity");
159         mockForGetRequest(aaiRestInterface, responseWithRequestInfo);
160         final AaiClient aaiClient = new AaiClient(aaiRestInterface, null, null);
161
162         try {
163
164             aaiClient.typedAaiGet(toURI("/irrelevant/url"), RelatedToProperty.class);
165
166         } catch (Exception e) {
167             assertThat(ExceptionUtils.getStackTrace(e), e, instanceOf(ExceptionWithRequestInfo.class));
168             ExceptionWithRequestInfo e2 = ((ExceptionWithRequestInfo) e);
169             assertThat(e2.getHttpCode(), is(Response.Status.INTERNAL_SERVER_ERROR.getStatusCode()));
170             assertThat(e2.getRawData(), is("entity"));
171             assertThat(e2.getHttpMethod(), is(HttpMethod.GET));
172             assertThat(e2.getRequestedUrl(), is("/my/mocked/url"));
173
174             throw e;
175         }
176     }
177
178     @Test(expectedExceptions = Exception.class)
179     public void typedAaiGet_aaiRestInterfaceRestGetReturnsInparsableResponse_exceptionIsThrown() {
180         AAIRestInterface aaiRestInterface = mock(AAIRestInterface.class);
181         final ResponseWithRequestInfo responseWithRequestInfo = mockedResponseWithRequestInfo(Response.Status.OK, "entity");
182         mockForGetRequest(aaiRestInterface, responseWithRequestInfo);
183         final AaiClient aaiClient = new AaiClient(aaiRestInterface, null, null);
184
185         try {
186
187             aaiClient.typedAaiGet(toURI("/irrelevant/url"), RelatedToProperty.class);
188
189         } catch (Exception e) {
190             assertThat(ExceptionUtils.getStackTrace(e), e, instanceOf(ExceptionWithRequestInfo.class));
191             assertThat(e.getCause(),
192                     hasProperty("cause", is(instanceOf(com.fasterxml.jackson.core.JsonParseException.class)))
193             );
194             throw e;
195         }
196     }
197
198     @Test
199     public void typedAaiGet_aaiRestInterfaceRestGetReturns_objectIsFine() {
200         AAIRestInterface aaiRestInterface = mock(AAIRestInterface.class);
201         final ResponseWithRequestInfo responseWithRequestInfo = mockedResponseWithRequestInfo(Response.Status.OK,
202                 "{ \"property-key\": \"foo\", \"property-value\": \"bar\" }");
203         mockForGetRequest(aaiRestInterface, responseWithRequestInfo);
204
205         final AaiClient aaiClient = new AaiClient(aaiRestInterface, null, null);
206
207         final RelatedToProperty relatedToPropertyAaiResponse = aaiClient.typedAaiGet(toURI("/irrelevant/url"), RelatedToProperty.class);
208
209         assertThat(relatedToPropertyAaiResponse.getPropertyKey(), is("foo"));
210         assertThat(relatedToPropertyAaiResponse.getPropertyValue(), is("bar"));
211     }
212
213     private ResponseWithRequestInfo mockedResponseWithRequestInfo(Response.Status status, String entity) {
214         return mockedResponseWithRequestInfo(status, entity, "/my/mocked/url", HttpMethod.GET);
215     }
216
217     private ResponseWithRequestInfo mockedResponseWithRequestInfo(Response.Status status, String entity, String requestUrl, HttpMethod method) {
218         final Response mockResponse = mock(Response.class);
219         when(mockResponse.getStatus()).thenReturn(status.getStatusCode());
220         when(mockResponse.getStatusInfo()).thenReturn(status);
221         when(mockResponse.readEntity(String.class)).thenReturn(entity);
222         return new ResponseWithRequestInfo(mockResponse, requestUrl, method);
223     }
224
225     //serialize fields except of fields we cannot know ahead of time
226     private static String requestMetadataReflected(StatusMetadata metadata) {
227         return new ReflectionToStringBuilder(metadata, ToStringStyle.SHORT_PREFIX_STYLE)
228                 .setExcludeFieldNames("duration")
229                 .toString();
230     }
231
232     private static String statusDataReflected(ExternalComponentStatus status) {
233         return new ReflectionToStringBuilder(status, ToStringStyle.SHORT_PREFIX_STYLE)
234                 .setExcludeFieldNames("metadata")
235                 .toString();
236     }
237
238     @DataProvider
239     public static Object[][] rawData() {
240         return new Object[][]{
241                 {"errorMessage", }, {""}, {null}
242         };
243     }
244
245     @Test(dataProvider = "rawData")
246     public void testProbeAaiGetFullSubscribersWithNullResponse_returnsNotAvailableWithErrorRawData(String rawData){
247         Mockito.when(aaiClientMock.getAllSubscribers(true)).thenReturn(
248                 new AaiResponseWithRequestInfo<>(HttpMethod.GET, "url", null,
249                         rawData));
250         ExternalComponentStatus result = callProbeAaiGetAllSubscribersAndAssertNotAvailable();
251         assertThat(result.getMetadata(), instanceOf(HttpRequestMetadata.class));
252         assertEquals(((HttpRequestMetadata) result.getMetadata()).getRawData(), rawData);
253     }
254
255     @DataProvider
256     public static Object[][] exceptions() {
257         return new Object[][] {
258                 {"NullPointerException", "errorMessage",
259                         new ExceptionWithRequestInfo(HttpMethod.GET, "url",
260                                 "errorMessage", null, new NullPointerException())},
261                 {"RuntimeException", null,
262                         new ExceptionWithRequestInfo(HttpMethod.GET, "url",
263                                 null, null, new RuntimeException())},
264                 {"RuntimeException", null,
265                         new RuntimeException()},
266         };
267     }
268
269     @Test(dataProvider = "exceptions")
270     public void testProbeAaiGetFullSubscribersWithNullResponse_returnsNotAvailableWithErrorRawData(String description, String expectedRawData, Exception exception){
271         Mockito.when(aaiClientMock.getAllSubscribers(true)).thenThrow(exception);
272         ExternalComponentStatus result = callProbeAaiGetAllSubscribersAndAssertNotAvailable();
273         if (exception instanceof ExceptionWithRequestInfo) {
274             assertThat(result.getMetadata(), instanceOf(HttpRequestMetadata.class));
275             assertEquals(((HttpRequestMetadata) result.getMetadata()).getRawData(), expectedRawData);
276         }
277         assertThat(result.getMetadata().getDescription(), containsString(description));
278     }
279
280     private ExternalComponentStatus callProbeAaiGetAllSubscribersAndAssertNotAvailable() {
281         Mockito.when(aaiClientMock.probeComponent()).thenCallRealMethod();
282         ExternalComponentStatus result  = aaiClientMock.probeComponent();
283         assertFalse(result.isAvailable());
284         return result;
285     }
286
287
288     @Test
289     public void getTenants_Arguments_Are_Null_Or_Empty() {
290
291         when(aaiClientMock.getTenants(any(), any())).thenCallRealMethod();
292
293         AaiResponse response = aaiClientMock.getTenants("", "");
294
295         assertEquals(response.getErrorMessage(), "{\"statusText\":\" Failed to retrieve LCP Region & Tenants from A&AI, Subscriber ID or Service Type is missing.\"}");
296
297
298         response = aaiClientMock.getTenants(null, null);
299
300         assertEquals(response.getErrorMessage(), "{\"statusText\":\" Failed to retrieve LCP Region & Tenants from A&AI, Subscriber ID or Service Type is missing.\"}");
301     }
302
303     @Test(expectedExceptions = AaiClient.ParsingGetTenantsResponseFailure.class, expectedExceptionsMessageRegExp = NO_LCP_REGION_AND_TENANTS_MSG)
304     public void getTenants_Arguments_Are_Valid_But_Tenants_Not_Exist() {
305
306         when(aaiClientMock.getTenantsNonCached(any(String.class),any(String.class))).thenCallRealMethod();
307
308         Response generalEmptyResponse = mock(Response.class);
309         when(aaiClientMock.doAaiGet(any(String.class),any(Boolean.class))).thenReturn(generalEmptyResponse);
310
311         aaiClientMock.getTenantsNonCached("subscriberId", "serviceType");
312     }
313
314     @Test
315     public void whenCacheThrowException_thenGetTenantReturnAaiResponse() {
316         CacheProvider mockCacheProvider = mock(CacheProvider.class);
317         CacheProvider.Cache mockCache = mock(CacheProvider.Cache.class);
318         AaiClient aaiClientUnderTest = new AaiClient(null, null, mockCacheProvider);
319
320         when(mockCacheProvider.aaiClientCacheFor(any(), any())).thenReturn(mockCache);
321         when(mockCache.get(any())).thenThrow(new AaiClient.ParsingGetTenantsResponseFailure(NO_LCP_REGION_AND_TENANTS_MSG));
322         AaiResponse aaiResponse = aaiClientUnderTest.getTenants("subscriberId", "serviceType");
323         assertEquals(HttpStatus.SC_INTERNAL_SERVER_ERROR, aaiResponse.getHttpCode());
324         assertEquals("{\"statusText\":\""+NO_LCP_REGION_AND_TENANTS_MSG+"\"}", aaiResponse.getErrorMessage());
325     }
326
327     @Test
328     public void getTenants_Arguments_Are_Valid_Get_The_Tenanats() {
329
330         when(aaiClientMock.getTenantsNonCached(any(String.class),any(String.class))).thenCallRealMethod();
331
332
333         Response generalEmptyResponse = mock(Response.class);
334
335         when(generalEmptyResponse.readEntity(String.class)).thenReturn(tenantResponseRaw);
336         when(generalEmptyResponse.getStatus()).thenReturn(200);
337         when(generalEmptyResponse.getStatusInfo()).thenReturn(Response.Status.OK);
338
339
340         when(aaiClientMock.doAaiGet(any(String.class),any(Boolean.class))).thenReturn(generalEmptyResponse);
341
342         AaiResponse<GetTenantsResponse[]> response = aaiClientMock.getTenantsNonCached("subscriberId", "serviceType");
343
344         GetTenantsResponse[] tenants = response.getT();
345
346         Assert.assertTrue(response.t.length> 0);
347
348         Assert.assertEquals(tenants[0].cloudOwner,"att-aic-cloud-owner");
349     }
350
351     final String tenantResponseRaw ="" +
352             "{" +
353             "\"service-type\": \"VIRTUAL USP\"," +
354             "\"resource-version\": \"1494001841964\"," +
355             "\"relationship-list\": {" +
356             "\"relationship\": [{" +
357             "\"related-to\": \"tenant\"," +
358             "\"related-link\": \"/aai/v11/cloud-infrastructure/cloud-regions/cloud-region/att-aic/AAIAIC25/tenants/tenant/092eb9e8e4b7412e8787dd091bc58e86\"," +
359             "\"relationship-data\": [{" +
360             "\"relationship-key\": \"cloud-region.cloud-owner\"," +
361             "\"relationship-value\": \"att-aic-cloud-owner\"" +
362             "}," +
363             "{" +
364             "\"relationship-key\": \"cloud-region.cloud-region-id\"," +
365             "\"relationship-value\": \"AAIAIC25\"" +
366             "}," +
367             "{" +
368             "\"relationship-key\": \"tenant.tenant-id\"," +
369             "\"relationship-value\": \"092eb9e8e4b7412e8787dd091bc58e86\"" +
370             "}" +
371             "]," +
372             "\"related-to-property\": [{" +
373             "\"property-key\": \"tenant.tenant-name\"," +
374             "\"property-value\": \"USP-SIP-IC-24335-T-01\"" +
375             "}]" +
376             "}]" +
377             "}" +
378             "}";
379
380     final String vfModuleHomingResponseRaw ="{" +
381             "    \"vf-module-id\": \"ed02354a-3217-45ce-a1cd-e0b69b7a8cea\"," +
382             "    \"vf-module-name\": \"apndns_az_02_module_1\"," +
383             "    \"heat-stack-id\": \"apndns_az_02_module_1/97a319f3-b095-4fff-befa-c657508ecaf8\"," +
384             "    \"orchestration-status\": \"active\"," +
385             "    \"is-base-vf-module\": false," +
386             "    \"resource-version\": \"1530559380383\"," +
387             "    \"model-invariant-id\": \"74450b48-0aa0-4743-8314-9163e92b7862\"," +
388             "    \"model-version-id\": \"6bc01a2b-bc48-4991-b9fe-e22c2215d801\"," +
389             "    \"model-customization-id\": \"74f638c2-0368-4212-8f73-e961005af17c\"," +
390             "    \"module-index\": 0," +
391             "    \"relationship-list\": {" +
392             "        \"relationship\": [" +
393             "            {" +
394             "                \"related-to\": \"l3-network\"," +
395             "                \"relationship-label\": \"org.onap.relationships.inventory.DependsOn\"," +
396             "                \"related-link\": \"/aai/v12/network/l3-networks/l3-network/335e62be-73a3-41e8-930b-1a677bcafea5\"," +
397             "                \"relationship-data\": [" +
398             "                    {" +
399             "                        \"relationship-key\": \"l3-network.network-id\"," +
400             "                        \"relationship-value\": \"335e62be-73a3-41e8-930b-1a677bcafea5\"" +
401             "                    }" +
402             "                ]," +
403             "                \"related-to-property\": [" +
404             "                    {" +
405             "                        \"property-key\": \"l3-network.network-name\"," +
406             "                        \"property-value\": \"MNS-FN-25180-T-02Shared_oam_protected_net_1\"" +
407             "                    }" +
408             "                ]" +
409             "            }," +
410             "            {" +
411             "                \"related-to\": \"l3-network\"," +
412             "                \"relationship-label\": \"org.onap.relationships.inventory.DependsOn\"," +
413             "                \"related-link\": \"/aai/v12/network/l3-networks/l3-network/2db4ee3e-2ac7-4fc3-8739-ecf53416459e\"," +
414             "                \"relationship-data\": [" +
415             "                    {" +
416             "                        \"relationship-key\": \"l3-network.network-id\"," +
417             "                        \"relationship-value\": \"2db4ee3e-2ac7-4fc3-8739-ecf53416459e\"" +
418             "                    }" +
419             "                ]," +
420             "                \"related-to-property\": [" +
421             "                    {" +
422             "                        \"property-key\": \"l3-network.network-name\"," +
423             "                        \"property-value\": \"Mobisupport-FN-27099-T-02_int_apn_dns_net_1\"" +
424             "                    }" +
425             "                ]" +
426             "            }," +
427             "            {" +
428             "                \"related-to\": \"volume-group\"," +
429             "                \"relationship-label\": \"org.onap.relationships.inventory.Uses\"," +
430             "                \"related-link\": \"/aai/v12/cloud-infrastructure/cloud-regions/cloud-region/att-aic/rdm5b/volume-groups/volume-group/66013ebe-0c81-44b9-a24f-7c6acba73a39\"," +
431             "                \"relationship-data\": [" +
432             "                    {" +
433             "                        \"relationship-key\": \"cloud-region.cloud-owner\"," +
434             "                        \"relationship-value\": \"att-aic\"" +
435             "                    }," +
436             "                    {" +
437             "                        \"relationship-key\": \"cloud-region.cloud-region-id\"," +
438             "                        \"relationship-value\": \"rdm5b\"" +
439             "                    }," +
440             "                    {" +
441             "                        \"relationship-key\": \"volume-group.volume-group-id\"," +
442             "                        \"relationship-value\": \"66013ebe-0c81-44b9-a24f-7c6acba73a39\"" +
443             "                    }" +
444             "                ]" +
445             "            }," +
446             "            {" +
447             "                \"related-to\": \"vserver\"," +
448             "                \"relationship-label\": \"org.onap.relationships.inventory.Uses\"," +
449             "                \"related-link\": \"/aai/v12/cloud-infrastructure/cloud-regions/cloud-region/att-aic/rdm5b/tenants/tenant/db1818f7f2e34862b378bfb2cc520f91/vservers/vserver/5eef9f6d-9933-4bc6-9a1a-862d61309437\"," +
450             "                \"relationship-data\": [" +
451             "                    {" +
452             "                        \"relationship-key\": \"cloud-region.cloud-owner\"," +
453             "                        \"relationship-value\": \"att-aic\"" +
454             "                    }," +
455             "                    {" +
456             "                        \"relationship-key\": \"cloud-region.cloud-region-id\"," +
457             "                        \"relationship-value\": \"rdm5b\"" +
458             "                    }," +
459             "                    {" +
460             "                        \"relationship-key\": \"tenant.tenant-id\"," +
461             "                        \"relationship-value\": \"db1818f7f2e34862b378bfb2cc520f91\"" +
462             "                    }," +
463             "                    {" +
464             "                        \"relationship-key\": \"vserver.vserver-id\"," +
465             "                        \"relationship-value\": \"5eef9f6d-9933-4bc6-9a1a-862d61309437\"" +
466             "                    }" +
467             "                ]," +
468             "                \"related-to-property\": [" +
469             "                    {" +
470             "                        \"property-key\": \"vserver.vserver-name\"," +
471             "                        \"property-value\": \"zrdm5bfapn01dns002\"" +
472             "                    }" +
473             "                ]" +
474             "            }" +
475             "        ]" +
476             "    }" +
477             "}";
478     @Test
479     public void get_homingDataForVfModule() {
480         when(aaiClientMock.getHomingDataByVfModule(any(String.class), any(String.class))).thenCallRealMethod();
481
482         Response homingResponse = mock(Response.class);
483
484         when(homingResponse.readEntity(String.class)).thenReturn(vfModuleHomingResponseRaw);
485         when(homingResponse.getStatus()).thenReturn(200);
486         when(homingResponse.getStatusInfo()).thenReturn(Response.Status.OK);
487
488
489         when(aaiClientMock.doAaiGet(any(String.class), any(Boolean.class))).thenReturn(homingResponse);
490
491         GetTenantsResponse tenant = aaiClientMock.getHomingDataByVfModule("vnfInstanceId", "vfModuleId");
492
493         Assert.assertEquals(tenant.cloudOwner,"att-aic");
494         Assert.assertEquals(tenant.cloudRegionID,"rdm5b");
495         Assert.assertEquals(tenant.tenantID,"db1818f7f2e34862b378bfb2cc520f91");
496
497     }
498     @Test(expectedExceptions = GenericUncheckedException.class, expectedExceptionsMessageRegExp = "A&AI has no homing data associated to vfModule 'vfModuleId' of vnf 'vnfInstanceId'")
499     public void getVfMoudule_Homing_Arguments_Are_Valid_But_Not_Exists() {
500         when(aaiClientMock.getHomingDataByVfModule(any(String.class), any(String.class))).thenCallRealMethod();
501
502         Response generalEmptyResponse = mock(Response.class);
503         when(aaiClientMock.doAaiGet(any(String.class),any(Boolean.class))).thenReturn(generalEmptyResponse);
504
505         aaiClientMock.getHomingDataByVfModule("vnfInstanceId", "vfModuleId");
506     }
507
508     @DataProvider
509     public static Object[][] invalidDataId() {
510         return new String[][] {
511                 {""},
512                 {null}
513         };
514     }
515
516     @Test(dataProvider = "invalidDataId", expectedExceptions = GenericUncheckedException.class, expectedExceptionsMessageRegExp = "Failed to retrieve homing data associated to vfModule from A&AI, VNF InstanceId or VF Module Id is missing.")
517     public void getVfMoudule_Homing_Arguments_Are_Empty_Or_Null(String data) {
518         when(aaiClientMock.getHomingDataByVfModule(any(), any())).thenCallRealMethod();
519              aaiClientMock.getHomingDataByVfModule(data, data);
520     }
521
522     @DataProvider
523     public static Object[][] resourceTypesProvider() {
524         return new Object[][] {
525                 {"service-instance", ResourceType.SERVICE_INSTANCE},
526                 {"generic-vnf", ResourceType.GENERIC_VNF},
527                 {"vf-module", ResourceType.VF_MODULE}
528         };
529     }
530
531     @DataProvider
532     public static Object[][] nameAndResourceTypeProvider() {
533         return new Object[][] {
534                 {"SRIOV_SVC", ResourceType.SERVICE_INSTANCE, "nodes/service-instances?service-instance-name=SRIOV_SVC"},
535                 {"b1707vidnf", ResourceType.GENERIC_VNF, "nodes/generic-vnfs?vnf-name=b1707vidnf"},
536                 {"connectivity_test", ResourceType.VF_MODULE, "nodes/vf-modules?vf-module-name=connectivity_test"},
537                 {"ByronPace", ResourceType.INSTANCE_GROUP, "nodes/instance-groups?instance-group-name=ByronPace"},
538                 {"MjVg1234", ResourceType.VOLUME_GROUP, "nodes/volume-groups?volume-group-name=MjVg1234"}
539         };
540     }
541
542     @Test(dataProvider = "nameAndResourceTypeProvider")
543     public void whenSearchNodeTypeByName_callRightAaiPath(String name, ResourceType type, String expectedUrl) {
544         AAIRestInterface aaiRestInterface = mock(AAIRestInterface.class);
545         ResponseWithRequestInfo responseWithRequestInfo = mockedResponseWithRequestInfo(Response.Status.OK, "{}");
546
547         when(aaiRestInterface.RestGet(anyString(), anyString(), eq(toURI(expectedUrl)), anyBoolean(), anyBoolean()))
548                 .thenReturn(responseWithRequestInfo);
549
550         AaiClient aaiClient = new AaiClient(aaiRestInterface, null, null);
551
552         aaiClient.isNodeTypeExistsByName(name, type);
553     }
554
555     @DataProvider
556     public static Object[][] aaiClientInternalExceptions() {
557         return Stream.<Pair<Class<? extends Throwable>, UncheckedBiConsumer<HttpsAuthClient, Client>>>of(
558
559                 // Exception out of httpsAuthClientMock
560                 Pair.of(CertificateException.class, (httpsAuthClientMock, javaxClientMock) -> {
561                     final CertificateException e0 = new CertificateException("No X509TrustManager implementation available");
562                     SSLHandshakeException e = new SSLHandshakeException(e0.toString());
563                     e.initCause(e0);
564
565                     when(httpsAuthClientMock.getClient(any())).thenThrow(e);
566                 }),
567
568                 Pair.of(StringIndexOutOfBoundsException.class, mockExceptionOnClientProvider(new StringIndexOutOfBoundsException(4))),
569
570                 Pair.of(NullPointerException.class, mockExceptionOnClientProvider(new NullPointerException("null"))),
571
572                 Pair.of(FileNotFoundException.class, mockExceptionOnClientProvider(new FileNotFoundException("vid/WEB-INF/cert/aai-client-cert.p12"))),
573
574                 Pair.of(BadPaddingException.class, mockExceptionOnClientProvider(
575                         new IOException("keystore password was incorrect", new BadPaddingException("Given final block not properly padded")))
576                 ),
577                 Pair.of(GenericUncheckedException.class, mockExceptionOnClientProvider(new GenericUncheckedException("basa"))),
578
579                 Pair.of(NullPointerException.class, (httpsAuthClientMock, javaxClientMock) ->
580                         when(httpsAuthClientMock.getClient(any())).thenReturn(null)),
581
582
583                 // Exception out of javax's Client
584                 Pair.of(SSLHandshakeException.class, (httpsAuthClientMock, javaxClientMock) -> {
585                     when(javaxClientMock.target(nullable(String.class))).thenThrow(
586                             new ProcessingException(new SSLHandshakeException("Received fatal alert: certificate_expired"))
587                     );
588                 }),
589
590                 Pair.of(SunCertPathBuilderException.class, (httpsAuthClientMock, javaxClientMock) -> {
591                     SunCertPathBuilderException e0 = new SunCertPathBuilderException("unable to find valid certification path to requested target");
592                     when(javaxClientMock.target(nullable(String.class))).thenThrow(
593                             new ProcessingException(new ValidatorException("PKIX path building failed: " + e0.toString(), e0))
594                     );
595                 }),
596
597                 Pair.of(GenericUncheckedException.class, (httpsAuthClientMock, javaxClientMock) ->
598                         when(javaxClientMock.target(nullable(String.class))).thenThrow(new GenericUncheckedException("basa")))
599
600         ).flatMap(l -> Stream.of(
601                 // double each case to propagateExceptions = true/false, to verify that "don't propagate" really still work
602                 ImmutableList.of(l.getLeft(), l.getRight(), true).toArray(),
603                 ImmutableList.of(l.getLeft(), l.getRight(), false).toArray()
604         )).collect(Collectors.toList()).toArray(new Object[][]{});
605     }
606
607     private static UncheckedBiConsumer<HttpsAuthClient, Client> mockExceptionOnClientProvider(Exception e) {
608         return (httpsAuthClientMock, javaxClientMock) ->
609                 when(httpsAuthClientMock.getClient(any())).thenThrow(e);
610     }
611
612     @Test(dataProvider = "aaiClientInternalExceptions")
613     public void propagateExceptions_internalsThrowException_ExceptionRethrown(Class<? extends Throwable> expectedType, BiConsumer<HttpsAuthClient, Client> setupMocks, boolean propagateExceptions) throws Exception {
614         /*
615         Call chain is like:
616             this test -> AaiClient -> AAIRestInterface -> HttpsAuthClient -> javax's Client
617
618         In this test, *AaiClient* and *AAIRestInterface* are under test (actual
619         implementation is used), while HttpsAuthClient and the javax's Client are
620         mocked to return pseudo-responses or - better- throw exceptions.
621          */
622
623         // prepare mocks
624         HttpsAuthClient httpsAuthClientMock = mock(HttpsAuthClient.class);
625         TestUtils.JavaxRsClientMocks mocks = new TestUtils.JavaxRsClientMocks();
626         Client javaxClientMock = mocks.getFakeClient();
627         Response responseMock = mocks.getFakeResponse();
628
629         // prepare real AAIRestInterface and AaiClient, and wire mocks
630         AAIRestInterface aaiRestInterface = new AAIRestInterface(httpsAuthClientMock, mock(ServletRequestHelper.class), mock(SystemPropertyHelper.class));
631         final AaiClient aaiClient = new AaiClient(aaiRestInterface, null, null);
632         when(httpsAuthClientMock.getClient(any())).thenReturn(javaxClientMock);
633
634         // define atomic method under test, including reset of "aaiRestInterface.client"
635         final Function<Boolean, Response> doAaiGet = (propagateExceptions1) -> {
636             try {
637                 FieldUtils.writeField(aaiRestInterface, "client", null, true);
638                 return aaiClient.doAaiGet("uri", false, propagateExceptions1).getResponse();
639             } catch (IllegalAccessException e) {
640                 throw new RuntimeException(e);
641             }
642         };
643
644         // verify setup again
645         assertThat("mocks setup should make doAaiGet return our responseMock", doAaiGet.apply(true), is(sameInstance(responseMock)));
646
647
648         /// TEST:
649         setupMocks.accept(httpsAuthClientMock, javaxClientMock);
650
651         try {
652             final Response response = doAaiGet.apply(propagateExceptions);
653         } catch (Exception e) {
654             if (propagateExceptions) {
655                 assertThat("root cause incorrect for " + ExceptionUtils.getStackTrace(e), ExceptionUtils.getRootCause(e), instanceOf(expectedType));
656                 return; // ok, done
657             } else {
658                 // Verify that "don't propagate" really still work
659                 Assert.fail("calling doAaiGet when propagateExceptions is false must result with no exception", e);
660             }
661         }
662
663         // If no exception caught
664         // We're asserting that the legacy behaviour is still in place. Hopefully
665         // one day we will remove the non-propagateExceptions case
666         assertFalse(propagateExceptions, "calling doAaiGet when propagateExceptions is 'true' must result with an exception (in this test)");
667     }
668
669     @DataProvider
670     public static Object[][] aaiClientGetCloudOwnerByCloudRegionId() {
671
672         final String cloudRegion = "{" +
673                 "      \"cloud-owner\": \"mure-royo-ru22\"," +
674                 "      \"cloud-region-id\": \"ravitu\"," +
675                 "      \"cloud-type\": \"openstack\"," +
676                 "      \"resource-version\": \"1523631256125\"," +
677                 "      \"relationship-list\": {" +
678                 "        \"relationship\": [{" +
679                 "            \"related-to\": \"pserver\"" +
680                 "          }" +
681                 "        ]" +
682                 "      }" +
683                 "    }";
684
685         String bodyWith0 = "{  \"cloud-region\": [" + "  ]}";
686         String bodyWith1 = "{  \"cloud-region\": [" + cloudRegion + "  ]}";
687         String bodyWith2 = "{  \"cloud-region\": [" + cloudRegion + ", " + cloudRegion + "  ]}";
688         String bodyWithDifferent2 = "{  \"cloud-region\": [" + cloudRegion + ", " +
689                 cloudRegion.replace("mure-royo-ru22", "nolay-umaxo") +
690                 "]}";
691
692         return new Object[][] {
693                 { "regular single result", bodyWith1, false },
694                 { "exceptional empty result", bodyWith0, true },
695                 { "two same results", bodyWith2, false },
696                 { "two incoherent results", bodyWithDifferent2, true },
697         };
698     }
699
700     @Test(dataProvider = "aaiClientGetCloudOwnerByCloudRegionId")
701     public void getCloudOwnerByCloudRegionIdNonCached(String desc, String body, boolean expectingException) {
702         final String cloudRegion = "ravitu";
703         AAIRestInterface aaiRestInterface = mock(AAIRestInterface.class);
704         final ResponseWithRequestInfo responseWithRequestInfo = mockedResponseWithRequestInfo(Response.Status.OK, body);
705         when(aaiRestInterface.doRest(anyString(), anyString(), eq(Unchecked.toURI("cloud-infrastructure/cloud-regions?cloud-region-id=" + cloudRegion)),
706                 isNull(), eq(HttpMethod.GET), anyBoolean(), anyBoolean()))
707                 .thenReturn(responseWithRequestInfo);
708
709         final AaiClient aaiClient = new AaiClient(aaiRestInterface, null, null);
710
711         try {
712             final String result = aaiClient.getCloudOwnerByCloudRegionIdNonCached(cloudRegion);
713             if (expectingException) fail("expected failure on " + desc + ", got " + result);
714             else {
715                 assertThat(result, is("mure-royo-ru22"));
716             }
717         } catch (Exception e) {
718             if (!expectingException) throw e;
719             else {
720                 assertThat(e.toString(), either(
721                         containsString("No cloud-owner found for " + cloudRegion))
722                         .or(containsString("Conflicting cloud-owner found for " + cloudRegion)));
723             }
724         }
725     }
726
727     @DataProvider
728     public static Object[][]  cloudRegionAndTenantDataProvider() {
729         return new Object[][] {
730                 { "APPC-24595-T-IST-02C", "mtn23b" },
731                 { "APPC-24595-T-IST-02C", null },
732                 { null, "mtn23b" },
733                 { null, null },
734         };
735     }
736
737     @Test(dataProvider = "cloudRegionAndTenantDataProvider")
738     public void getCloudRegionAndTenantByVnfId(String tenantName, String cloudRegionId) throws JsonProcessingException {
739         SimpleResult tenant = new SimpleResult();
740         if (tenantName != null) {
741             tenant.setJsonNodeType("tenant");
742             Properties tenantProps = new Properties();
743             tenantProps.setTenantName(tenantName);
744             tenant.setJsonProperties(tenantProps);
745         }
746
747         SimpleResult cloudRegion = new SimpleResult();
748         if (cloudRegionId != null) {
749             cloudRegion.setJsonNodeType("cloud-region");
750             Properties cloudRegionProps = new Properties();
751             cloudRegionProps.setCloudRegionId(cloudRegionId);
752             cloudRegion.setJsonProperties(cloudRegionProps);
753         }
754
755         CustomQuerySimpleResult customQuerySimpleResult = new CustomQuerySimpleResult(ImmutableList.of(tenant, cloudRegion));
756         String mockedBody = new ObjectMapper().writeValueAsString(customQuerySimpleResult);
757
758         AAIRestInterface aaiRestInterface = mock(AAIRestInterface.class);
759         final ResponseWithRequestInfo responseWithRequestInfo = mockedResponseWithRequestInfo(Response.Status.OK, mockedBody, "query?format=simple", HttpMethod.PUT);
760         when(aaiRestInterface.doRest(anyString(), anyString(), eq(Unchecked.toURI("query?format=simple")),
761                 any(), eq(HttpMethod.PUT), anyBoolean(), anyBoolean()))
762                 .thenReturn(responseWithRequestInfo);
763
764         final AaiClient aaiClient = new AaiClient(aaiRestInterface, null, null);
765         Map<String, Properties> result = aaiClient.getCloudRegionAndTenantByVnfId("anyVnfId");
766         if (tenantName != null) {
767             assertEquals(result.get("tenant").getTenantName(), tenantName);
768         } else {
769             assertNull(result.get("tenant"));
770         }
771
772         if (cloudRegionId != null) {
773             assertEquals(result.get("cloud-region").getCloudRegionId(), cloudRegionId);
774         } else {
775             assertNull(result.get("cloud-region"));
776         }
777     }
778
779     protected void mockForGetRequest(AAIRestInterface aaiRestInterface, ResponseWithRequestInfo responseWithRequestInfo) {
780         when(aaiRestInterface.doRest(anyString(), anyString(), any(URI.class), isNull(), eq(HttpMethod.GET) ,anyBoolean(), anyBoolean()))
781                 .thenReturn(responseWithRequestInfo);
782     }
783
784     @Test
785     public void shouldProperlyReadResponseOnceWhenSubscribersAreNotPresent() {
786         AAIRestInterface restInterface = mock(AAIRestInterface.class);
787         PortDetailsTranslator portDetailsTranslator = mock(PortDetailsTranslator.class);
788         Response response = mock(Response.class);
789         when(response.getStatus()).thenReturn(404);
790         when(response.readEntity(String.class)).thenReturn("sampleEntity");
791         when(response.getStatusInfo()).thenReturn(Response.Status.NOT_FOUND);
792         ResponseWithRequestInfo responseWithRequestInfo = new ResponseWithRequestInfo(response, "test", HttpMethod.GET);
793         when(restInterface.RestGet(eq("VidAaiController"), any(String.class),
794                 eq(Unchecked.toURI("business/customers?subscriber-type=INFRA&depth=0")), eq(false), eq(true))).thenReturn(responseWithRequestInfo);
795         AaiClient aaiClient = new AaiClient(restInterface, portDetailsTranslator, null);
796
797
798         aaiClient.getAllSubscribers(true);
799
800         verify(response).readEntity(String.class);
801     }
802
803     @FunctionalInterface
804     public interface UncheckedBiConsumer<T, U> extends BiConsumer<T, U> {
805         @Override
806         default void accept(T t, U u) {
807             try {
808                 acceptThrows(t, u);
809             } catch (Exception e) {
810                 throw new RuntimeException(e);
811             }
812         }
813
814         void acceptThrows(T t, U u) throws Exception;
815     }
816
817 }