2 * ============LICENSE_START=======================================================
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
11 * http://www.apache.org/licenses/LICENSE-2.0
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=========================================================
21 package org.onap.vid.aai;
23 import static java.util.stream.Collectors.toList;
24 import static org.apache.commons.lang3.StringUtils.equalsIgnoreCase;
25 import static org.hamcrest.MatcherAssert.assertThat;
26 import static org.hamcrest.Matchers.contains;
27 import static org.hamcrest.Matchers.containsInAnyOrder;
28 import static org.hamcrest.Matchers.containsString;
29 import static org.hamcrest.Matchers.either;
30 import static org.hamcrest.Matchers.hasProperty;
31 import static org.hamcrest.Matchers.instanceOf;
32 import static org.hamcrest.Matchers.is;
33 import static org.hamcrest.Matchers.sameInstance;
34 import static org.mockito.ArgumentMatchers.any;
35 import static org.mockito.ArgumentMatchers.anyBoolean;
36 import static org.mockito.ArgumentMatchers.anyString;
37 import static org.mockito.ArgumentMatchers.argThat;
38 import static org.mockito.ArgumentMatchers.eq;
39 import static org.mockito.ArgumentMatchers.isNull;
40 import static org.mockito.ArgumentMatchers.nullable;
41 import static org.mockito.Mockito.mock;
42 import static org.mockito.Mockito.verify;
43 import static org.mockito.Mockito.when;
44 import static org.onap.vid.utils.KotlinUtilsKt.JACKSON_OBJECT_MAPPER;
45 import static org.onap.vid.utils.Unchecked.toURI;
46 import static org.testng.Assert.assertEquals;
47 import static org.testng.Assert.assertFalse;
48 import static org.testng.Assert.assertNull;
49 import static org.testng.Assert.fail;
51 import com.fasterxml.jackson.core.JsonProcessingException;
52 import com.fasterxml.jackson.databind.ObjectMapper;
53 import com.google.common.collect.ImmutableList;
54 import java.io.FileNotFoundException;
55 import java.io.IOException;
57 import java.security.cert.CertificateException;
58 import java.util.ArrayList;
60 import java.util.function.BiConsumer;
61 import java.util.function.Function;
62 import java.util.stream.Stream;
63 import javax.crypto.BadPaddingException;
64 import javax.net.ssl.SSLHandshakeException;
65 import javax.servlet.ServletContext;
66 import javax.ws.rs.ProcessingException;
67 import javax.ws.rs.client.Client;
68 import javax.ws.rs.core.Response;
69 import org.apache.commons.lang3.builder.ReflectionToStringBuilder;
70 import org.apache.commons.lang3.builder.ToStringStyle;
71 import org.apache.commons.lang3.exception.ExceptionUtils;
72 import org.apache.commons.lang3.reflect.FieldUtils;
73 import org.apache.commons.lang3.tuple.Pair;
74 import org.apache.http.HttpStatus;
75 import org.hamcrest.Matcher;
76 import org.mockito.Mockito;
77 import org.onap.portalsdk.core.logging.logic.EELFLoggerDelegate;
78 import org.onap.portalsdk.core.util.SystemProperties;
79 import org.onap.vid.aai.model.AaiGetTenatns.GetTenantsResponse;
80 import org.onap.vid.aai.model.CustomQuerySimpleResult;
81 import org.onap.vid.aai.model.ModelVer;
82 import org.onap.vid.aai.model.ModelVersions;
83 import org.onap.vid.aai.model.PortDetailsTranslator;
84 import org.onap.vid.aai.model.Properties;
85 import org.onap.vid.aai.model.RelatedToProperty;
86 import org.onap.vid.aai.model.ResourceType;
87 import org.onap.vid.aai.model.SimpleResult;
88 import org.onap.vid.aai.util.AAIRestInterface;
89 import org.onap.vid.aai.util.CacheProvider;
90 import org.onap.vid.aai.util.HttpsAuthClient;
91 import org.onap.vid.aai.util.ServletRequestHelper;
92 import org.onap.vid.aai.util.SystemPropertyHelper;
93 import org.onap.vid.controller.LocalWebConfig;
94 import org.onap.vid.exceptions.GenericUncheckedException;
95 import org.onap.vid.model.Subscriber;
96 import org.onap.vid.model.SubscriberList;
97 import org.onap.vid.model.probes.ExternalComponentStatus;
98 import org.onap.vid.model.probes.HttpRequestMetadata;
99 import org.onap.vid.model.probes.StatusMetadata;
100 import org.onap.vid.testUtils.TestUtils;
101 import org.onap.vid.utils.Logging;
102 import org.onap.vid.utils.Unchecked;
103 import org.springframework.http.HttpMethod;
104 import org.springframework.test.context.ContextConfiguration;
105 import org.springframework.test.context.web.WebAppConfiguration;
106 import org.testng.Assert;
107 import org.testng.annotations.BeforeMethod;
108 import org.testng.annotations.DataProvider;
109 import org.testng.annotations.Test;
110 import sun.security.provider.certpath.SunCertPathBuilderException;
111 import sun.security.validator.ValidatorException;
113 @ContextConfiguration(classes = {LocalWebConfig.class, SystemProperties.class})
115 public class AaiClientTest {
117 private final String NO_LCP_REGION_AND_TENANTS_MSG = "A&AI has no LCP Region & Tenants associated to subscriber 'subscriberId' and service type 'serviceType'";
118 private AaiClient aaiClientMock;
119 private ServletContext servletContext;
122 public void initMocks(){
123 aaiClientMock = mock(AaiClient.class);
124 aaiClientMock.logger = mock(EELFLoggerDelegate.class);
125 aaiClientMock.objectMapper = new ObjectMapper();
126 servletContext = mock(ServletContext.class);
128 when(servletContext.getRealPath(any(String.class))).thenReturn("");
130 when(aaiClientMock.doAaiGet(any(String.class),any(Boolean.class))).thenReturn(null);
131 when(aaiClientMock.doAaiGet(any(URI.class), anyBoolean(), anyBoolean())).thenReturn(null);
135 public static Object[][] logicalLinkData() {
136 return new Object[][] {
137 {"", "network/logical-links/logical-link/"},
138 {"link", "network/logical-links/logical-link/link"}
142 private static String nfRoleOnly = "{\"start\":[\"/business/customers/customer/globalCustomerId1-360-as988q/service-subscriptions/service-subscription/TEST1-360/service-instances\"],\"query\":\"query/vnfs-fromServiceInstance-filter?nfRole=test360\"}";
143 private static String nfRoleAndCloudRegion = "{\"start\":[\"/business/customers/customer/globalCustomerId1-360-as988q/service-subscriptions/service-subscription/TEST1-360/service-instances\"],\"query\":\"query/vnfs-fromServiceInstance-filterByCloudRegion?nfRole=test360&cloudRegionID=cloudRegion-1\"}";
144 private static String cloudRegionOnly = "{\"start\":[\"/business/customers/customer/globalCustomerId1-360-as988q/service-subscriptions/service-subscription/TEST1-360/service-instances\"],\"query\":\"query/vnfs-fromServiceInstance-filterByCloudRegion?cloudRegionID=cloudRegion-1\"}";
145 private static String withoutNfroleAndCloudRegion = "{\"start\":[\"/business/customers/customer/globalCustomerId1-360-as988q/service-subscriptions/service-subscription/TEST1-360/service-instances\"],\"query\":\"query/vnfs-fromServiceInstance-filter\"}";
146 private static String withoutNfroleAndCloudRegionWithSpace = "{\"start\":[\"/business/customers/customer/globalCustomerId1with%20space%20360-as988q/service-subscriptions/service-subscription/TEST1%20360/service-instances\"],\"query\":\"query/vnfs-fromServiceInstance-filter\"}";
148 private static String responseJsonNfRole = "/payload_jsons/changeManagement/vnfs-fromServiceInstance-filterNfRole.json";
149 private static String responseJsonCloudRegion ="/payload_jsons/changeManagement/vnfs-fromServiceInstance-filterByCloudRegion.json";
153 public static Object[][] aaiPutCustomQueryData() {
154 return new Object[][] {
155 {"globalCustomerId1-360-as988q", "TEST1-360", "test360", null, nfRoleOnly, responseJsonNfRole, "908419144", 200},
156 {"globalCustomerId1-360-as988q", "TEST1-360", null, "cloudRegion-1", cloudRegionOnly, responseJsonCloudRegion, "1165906024", 200},
157 {"globalCustomerId1-360-as988q", "TEST1-360", "test360", "cloudRegion-1", nfRoleAndCloudRegion,
158 responseJsonCloudRegion, "1165906024", 200},
159 {"globalCustomerId1with space 360-as988q", "TEST1 360", null, null, withoutNfroleAndCloudRegionWithSpace, responseJsonNfRole, "908419144", 200},
160 {"globalCustomerId1-360-as988q", "TEST1-360", null, null, withoutNfroleAndCloudRegion, responseJsonNfRole, "908419144", 200},
164 @Test(dataProvider = "aaiPutCustomQueryData")
165 public void testAaiPutCustomQueryByParams(String globalCustomerId, String serviceType, String nfRole, String cloudRegion, String expectedPayload, String responseBody, String expectedId, int responseHttpCode) {
166 String queryFormat = "query?format=simple";
167 final ResponseWithRequestInfo mockedResponseWithRequestInfo = mockedResponseWithRequestInfo(Response.Status.OK,
168 TestUtils.readFileAsString(responseBody),
169 "query?format=simple&Mock=True",
171 when(aaiClientMock.doAaiPut(eq(queryFormat), anyString(), anyBoolean(), anyBoolean())).thenReturn(mockedResponseWithRequestInfo);
172 when(aaiClientMock.getVnfsByParamsForChangeManagement(anyString(), anyString(), nullable(String.class), nullable(String.class))).thenCallRealMethod();
173 AaiResponse<AaiGetVnfResponse> response = aaiClientMock.getVnfsByParamsForChangeManagement(globalCustomerId, serviceType, nfRole, cloudRegion);
174 verify(aaiClientMock).doAaiPut(eq(queryFormat), eq(expectedPayload), eq(false), eq(false));
175 assertEquals(response.getHttpCode(), responseHttpCode);
176 assertEquals(response.getT().getResults().get(0).id, expectedId);
179 @Test(dataProvider = "logicalLinkData")
180 public void getLogicalLink_Link_Is_Empty(String link, String expectedUrl) {
182 when(aaiClientMock.getLogicalLink(any(String.class))).thenCallRealMethod();
183 aaiClientMock.getLogicalLink(link);
184 verify(aaiClientMock).doAaiGet(argThat(s -> equalsIgnoreCase(s, expectedUrl)),any(Boolean.class));
188 public static Object[][] subscribersResults() {
189 return new Object[][] {
190 {new SubscriberList(new ArrayList<Subscriber>() {{ add(new Subscriber()); add(new Subscriber()); }}), true},
191 {new SubscriberList(new ArrayList<Subscriber>() {{ add(new Subscriber()); }}), true},
192 {new SubscriberList(new ArrayList<Subscriber>()), false}
196 @Test(dataProvider = "subscribersResults")
197 public void testProbeAaiGetAllSubscribers_returnsTwoToZeroSubscribers_ResultsAsExpected(SubscriberList subscribers, boolean isAvailable){
198 ExternalComponentStatus expectedStatus = new ExternalComponentStatus(ExternalComponentStatus.Component.AAI,isAvailable, new HttpRequestMetadata(
203 isAvailable ? "OK" : "No subscriber received",
206 Mockito.when(aaiClientMock.getAllSubscribers(true)).thenReturn(
207 new AaiResponseWithRequestInfo<>(
208 HttpMethod.GET, "url", new AaiResponse<>(subscribers, null, 200),
210 Mockito.when(aaiClientMock.probeComponent()).thenCallRealMethod();
211 ExternalComponentStatus result = aaiClientMock.probeComponent();
212 assertThat(statusDataReflected(result),is(statusDataReflected(expectedStatus)));
213 assertThat(requestMetadataReflected(result.getMetadata()),is(requestMetadataReflected(expectedStatus.getMetadata())));
216 @Test(expectedExceptions = Exception.class)
217 public void typedAaiGet_aaiRestInterfaceRestGetReturnsError_exceptionIsThrown() {
218 AAIRestInterface aaiRestInterface = mock(AAIRestInterface.class);
219 final ResponseWithRequestInfo responseWithRequestInfo = mockedResponseWithRequestInfo(Response.Status.INTERNAL_SERVER_ERROR, "entity");
220 mockForGetRequest(aaiRestInterface, responseWithRequestInfo);
221 final AaiClient aaiClient = new AaiClient(aaiRestInterface, null, null);
225 aaiClient.typedAaiGet(toURI("/irrelevant/url"), RelatedToProperty.class);
227 } catch (Exception e) {
228 assertThat(ExceptionUtils.getStackTrace(e), e, instanceOf(ExceptionWithRequestInfo.class));
229 ExceptionWithRequestInfo e2 = ((ExceptionWithRequestInfo) e);
230 assertThat(e2.getHttpCode(), is(Response.Status.INTERNAL_SERVER_ERROR.getStatusCode()));
231 assertThat(e2.getRawData(), is("entity"));
232 assertThat(e2.getHttpMethod(), is(HttpMethod.GET));
233 assertThat(e2.getRequestedUrl(), is("/my/mocked/url"));
239 @Test(expectedExceptions = Exception.class)
240 public void typedAaiGet_aaiRestInterfaceRestGetReturnsInparsableResponse_exceptionIsThrown() {
241 AAIRestInterface aaiRestInterface = mock(AAIRestInterface.class);
242 final ResponseWithRequestInfo responseWithRequestInfo = mockedResponseWithRequestInfo(Response.Status.OK, "entity");
243 mockForGetRequest(aaiRestInterface, responseWithRequestInfo);
244 final AaiClient aaiClient = new AaiClient(aaiRestInterface, null, null);
248 aaiClient.typedAaiGet(toURI("/irrelevant/url"), RelatedToProperty.class);
250 } catch (Exception e) {
251 assertThat(ExceptionUtils.getStackTrace(e), e, instanceOf(ExceptionWithRequestInfo.class));
252 assertThat(e.getCause(),
253 hasProperty("cause", is(instanceOf(com.fasterxml.jackson.core.JsonParseException.class)))
260 public void typedAaiGet_aaiRestInterfaceRestGetReturns_objectIsFine() {
261 AAIRestInterface aaiRestInterface = mock(AAIRestInterface.class);
262 final ResponseWithRequestInfo responseWithRequestInfo = mockedResponseWithRequestInfo(Response.Status.OK,
263 "{ \"property-key\": \"foo\", \"property-value\": \"bar\" }");
264 mockForGetRequest(aaiRestInterface, responseWithRequestInfo);
266 final AaiClient aaiClient = new AaiClient(aaiRestInterface, null, null);
268 final RelatedToProperty relatedToPropertyAaiResponse = aaiClient.typedAaiGet(toURI("/irrelevant/url"), RelatedToProperty.class);
270 assertThat(relatedToPropertyAaiResponse.getPropertyKey(), is("foo"));
271 assertThat(relatedToPropertyAaiResponse.getPropertyValue(), is("bar"));
274 private ResponseWithRequestInfo mockedResponseWithRequestInfo(Response.Status status, String entity) {
275 return mockedResponseWithRequestInfo(status, entity, "/my/mocked/url", HttpMethod.GET);
278 private ResponseWithRequestInfo mockedResponseWithRequestInfo(Response.Status status, String entity, String requestUrl, HttpMethod method) {
279 final Response mockResponse = mock(Response.class);
280 when(mockResponse.getStatus()).thenReturn(status.getStatusCode());
281 when(mockResponse.getStatusInfo()).thenReturn(status);
282 when(mockResponse.readEntity(String.class)).thenReturn(entity);
283 return new ResponseWithRequestInfo(mockResponse, requestUrl, method);
286 //serialize fields except of fields we cannot know ahead of time
287 private static String requestMetadataReflected(StatusMetadata metadata) {
288 return new ReflectionToStringBuilder(metadata, ToStringStyle.SHORT_PREFIX_STYLE)
289 .setExcludeFieldNames("duration")
293 private static String statusDataReflected(ExternalComponentStatus status) {
294 return new ReflectionToStringBuilder(status, ToStringStyle.SHORT_PREFIX_STYLE)
295 .setExcludeFieldNames("metadata")
300 public static Object[][] rawData() {
301 return new Object[][]{
302 {"errorMessage", }, {""}, {null}
306 @Test(dataProvider = "rawData")
307 public void testProbeAaiGetFullSubscribersWithNullResponse_returnsNotAvailableWithErrorRawData(String rawData){
308 Mockito.when(aaiClientMock.getAllSubscribers(true)).thenReturn(
309 new AaiResponseWithRequestInfo<>(HttpMethod.GET, "url", null,
311 ExternalComponentStatus result = callProbeAaiGetAllSubscribersAndAssertNotAvailable();
312 assertThat(result.getMetadata(), instanceOf(HttpRequestMetadata.class));
313 assertEquals(((HttpRequestMetadata) result.getMetadata()).getRawData(), rawData);
317 public static Object[][] exceptions() {
318 return new Object[][] {
319 {"NullPointerException", "errorMessage",
320 new ExceptionWithRequestInfo(HttpMethod.GET, "url",
321 "errorMessage", null, new NullPointerException())},
322 {"RuntimeException", null,
323 new ExceptionWithRequestInfo(HttpMethod.GET, "url",
324 null, null, new RuntimeException())},
325 {"RuntimeException", null,
326 new RuntimeException()},
330 @Test(dataProvider = "exceptions")
331 public void testProbeAaiGetFullSubscribersWithNullResponse_returnsNotAvailableWithErrorRawData(String description, String expectedRawData, Exception exception){
332 Mockito.when(aaiClientMock.getAllSubscribers(true)).thenThrow(exception);
333 ExternalComponentStatus result = callProbeAaiGetAllSubscribersAndAssertNotAvailable();
334 if (exception instanceof ExceptionWithRequestInfo) {
335 assertThat(result.getMetadata(), instanceOf(HttpRequestMetadata.class));
336 assertEquals(((HttpRequestMetadata) result.getMetadata()).getRawData(), expectedRawData);
338 assertThat(result.getMetadata().getDescription(), containsString(description));
341 private ExternalComponentStatus callProbeAaiGetAllSubscribersAndAssertNotAvailable() {
342 Mockito.when(aaiClientMock.probeComponent()).thenCallRealMethod();
343 ExternalComponentStatus result = aaiClientMock.probeComponent();
344 assertFalse(result.isAvailable());
350 public void getTenants_Arguments_Are_Null_Or_Empty() {
352 when(aaiClientMock.getTenants(any(), any())).thenCallRealMethod();
354 AaiResponse response = aaiClientMock.getTenants("", "");
356 assertEquals(response.getErrorMessage(), "{\"statusText\":\" Failed to retrieve LCP Region & Tenants from A&AI, Subscriber ID or Service Type is missing.\"}");
359 response = aaiClientMock.getTenants(null, null);
361 assertEquals(response.getErrorMessage(), "{\"statusText\":\" Failed to retrieve LCP Region & Tenants from A&AI, Subscriber ID or Service Type is missing.\"}");
364 @Test(expectedExceptions = AaiClient.ParsingGetTenantsResponseFailure.class, expectedExceptionsMessageRegExp = NO_LCP_REGION_AND_TENANTS_MSG)
365 public void getTenants_Arguments_Are_Valid_But_Tenants_Not_Exist() {
367 when(aaiClientMock.getTenantsNonCached(any(String.class),any(String.class))).thenCallRealMethod();
369 Response generalEmptyResponse = mock(Response.class);
370 when(aaiClientMock.doAaiGet(any(String.class),any(Boolean.class))).thenReturn(generalEmptyResponse);
372 aaiClientMock.getTenantsNonCached("subscriberId", "serviceType");
376 public void whenCacheThrowException_thenGetTenantReturnAaiResponse() {
377 CacheProvider mockCacheProvider = mock(CacheProvider.class);
378 CacheProvider.Cache mockCache = mock(CacheProvider.Cache.class);
379 AaiClient aaiClientUnderTest = new AaiClient(null, null, mockCacheProvider);
381 when(mockCacheProvider.aaiClientCacheFor(any(), any())).thenReturn(mockCache);
382 when(mockCache.get(any())).thenThrow(new AaiClient.ParsingGetTenantsResponseFailure(NO_LCP_REGION_AND_TENANTS_MSG));
383 AaiResponse aaiResponse = aaiClientUnderTest.getTenants("subscriberId", "serviceType");
384 assertEquals(HttpStatus.SC_INTERNAL_SERVER_ERROR, aaiResponse.getHttpCode());
385 assertEquals("{\"statusText\":\""+NO_LCP_REGION_AND_TENANTS_MSG+"\"}", aaiResponse.getErrorMessage());
389 public void getTenants_Arguments_Are_Valid_Get_The_Tenanats() {
391 when(aaiClientMock.getTenantsNonCached(any(String.class),any(String.class))).thenCallRealMethod();
394 Response generalEmptyResponse = mock(Response.class);
396 when(generalEmptyResponse.readEntity(String.class)).thenReturn(tenantResponseRaw);
397 when(generalEmptyResponse.getStatus()).thenReturn(200);
398 when(generalEmptyResponse.getStatusInfo()).thenReturn(Response.Status.OK);
401 when(aaiClientMock.doAaiGet(any(String.class),any(Boolean.class))).thenReturn(generalEmptyResponse);
403 AaiResponse<GetTenantsResponse[]> response = aaiClientMock.getTenantsNonCached("subscriberId", "serviceType");
405 GetTenantsResponse[] tenants = response.getT();
407 Assert.assertTrue(response.t.length> 0);
409 Assert.assertEquals(tenants[0].cloudOwner,"irma-aic-cloud-owner");
412 final String tenantResponseRaw ="" +
414 "\"service-type\": \"VIRTUAL USP\"," +
415 "\"resource-version\": \"1494001841964\"," +
416 "\"relationship-list\": {" +
417 "\"relationship\": [{" +
418 "\"related-to\": \"tenant\"," +
419 "\"related-link\": \"/aai/v11/cloud-infrastructure/cloud-regions/cloud-region/irma-aic/AAIAIC25/tenants/tenant/092eb9e8e4b7412e8787dd091bc58e86\"," +
420 "\"relationship-data\": [{" +
421 "\"relationship-key\": \"cloud-region.cloud-owner\"," +
422 "\"relationship-value\": \"irma-aic-cloud-owner\"" +
425 "\"relationship-key\": \"cloud-region.cloud-region-id\"," +
426 "\"relationship-value\": \"AAIAIC25\"" +
429 "\"relationship-key\": \"tenant.tenant-id\"," +
430 "\"relationship-value\": \"092eb9e8e4b7412e8787dd091bc58e86\"" +
433 "\"related-to-property\": [{" +
434 "\"property-key\": \"tenant.tenant-name\"," +
435 "\"property-value\": \"USP-SIP-IC-24335-T-01\"" +
441 final String vfModuleHomingResponseRaw ="{" +
442 " \"vf-module-id\": \"ed02354a-3217-45ce-a1cd-e0b69b7a8cea\"," +
443 " \"vf-module-name\": \"apndns_az_02_module_1\"," +
444 " \"heat-stack-id\": \"apndns_az_02_module_1/97a319f3-b095-4fff-befa-c657508ecaf8\"," +
445 " \"orchestration-status\": \"active\"," +
446 " \"is-base-vf-module\": false," +
447 " \"resource-version\": \"1530559380383\"," +
448 " \"model-invariant-id\": \"74450b48-0aa0-4743-8314-9163e92b7862\"," +
449 " \"model-version-id\": \"6bc01a2b-bc48-4991-b9fe-e22c2215d801\"," +
450 " \"model-customization-id\": \"74f638c2-0368-4212-8f73-e961005af17c\"," +
451 " \"module-index\": 0," +
452 " \"relationship-list\": {" +
453 " \"relationship\": [" +
455 " \"related-to\": \"l3-network\"," +
456 " \"relationship-label\": \"org.onap.relationships.inventory.DependsOn\"," +
457 " \"related-link\": \"/aai/v12/network/l3-networks/l3-network/335e62be-73a3-41e8-930b-1a677bcafea5\"," +
458 " \"relationship-data\": [" +
460 " \"relationship-key\": \"l3-network.network-id\"," +
461 " \"relationship-value\": \"335e62be-73a3-41e8-930b-1a677bcafea5\"" +
464 " \"related-to-property\": [" +
466 " \"property-key\": \"l3-network.network-name\"," +
467 " \"property-value\": \"MNS-FN-25180-T-02Shared_oam_protected_net_1\"" +
472 " \"related-to\": \"l3-network\"," +
473 " \"relationship-label\": \"org.onap.relationships.inventory.DependsOn\"," +
474 " \"related-link\": \"/aai/v12/network/l3-networks/l3-network/2db4ee3e-2ac7-4fc3-8739-ecf53416459e\"," +
475 " \"relationship-data\": [" +
477 " \"relationship-key\": \"l3-network.network-id\"," +
478 " \"relationship-value\": \"2db4ee3e-2ac7-4fc3-8739-ecf53416459e\"" +
481 " \"related-to-property\": [" +
483 " \"property-key\": \"l3-network.network-name\"," +
484 " \"property-value\": \"Mobisupport-FN-27099-T-02_int_apn_dns_net_1\"" +
489 " \"related-to\": \"volume-group\"," +
490 " \"relationship-label\": \"org.onap.relationships.inventory.Uses\"," +
491 " \"related-link\": \"/aai/v12/cloud-infrastructure/cloud-regions/cloud-region/irma-aic/rdm5b/volume-groups/volume-group/66013ebe-0c81-44b9-a24f-7c6acba73a39\"," +
492 " \"relationship-data\": [" +
494 " \"relationship-key\": \"cloud-region.cloud-owner\"," +
495 " \"relationship-value\": \"irma-aic\"" +
498 " \"relationship-key\": \"cloud-region.cloud-region-id\"," +
499 " \"relationship-value\": \"rdm5b\"" +
502 " \"relationship-key\": \"volume-group.volume-group-id\"," +
503 " \"relationship-value\": \"66013ebe-0c81-44b9-a24f-7c6acba73a39\"" +
508 " \"related-to\": \"vserver\"," +
509 " \"relationship-label\": \"org.onap.relationships.inventory.Uses\"," +
510 " \"related-link\": \"/aai/v12/cloud-infrastructure/cloud-regions/cloud-region/irma-aic/rdm5b/tenants/tenant/db1818f7f2e34862b378bfb2cc520f91/vservers/vserver/5eef9f6d-9933-4bc6-9a1a-862d61309437\"," +
511 " \"relationship-data\": [" +
513 " \"relationship-key\": \"cloud-region.cloud-owner\"," +
514 " \"relationship-value\": \"irma-aic\"" +
517 " \"relationship-key\": \"cloud-region.cloud-region-id\"," +
518 " \"relationship-value\": \"rdm5b\"" +
521 " \"relationship-key\": \"tenant.tenant-id\"," +
522 " \"relationship-value\": \"db1818f7f2e34862b378bfb2cc520f91\"" +
525 " \"relationship-key\": \"vserver.vserver-id\"," +
526 " \"relationship-value\": \"5eef9f6d-9933-4bc6-9a1a-862d61309437\"" +
529 " \"related-to-property\": [" +
531 " \"property-key\": \"vserver.vserver-name\"," +
532 " \"property-value\": \"zrdm5bfapn01dns002\"" +
540 public void get_homingDataForVfModule() {
541 when(aaiClientMock.getHomingDataByVfModule(any(String.class), any(String.class))).thenCallRealMethod();
543 Response homingResponse = mock(Response.class);
545 when(homingResponse.readEntity(String.class)).thenReturn(vfModuleHomingResponseRaw);
546 when(homingResponse.getStatus()).thenReturn(200);
547 when(homingResponse.getStatusInfo()).thenReturn(Response.Status.OK);
550 when(aaiClientMock.doAaiGet(any(String.class), any(Boolean.class))).thenReturn(homingResponse);
552 GetTenantsResponse tenant = aaiClientMock.getHomingDataByVfModule("vnfInstanceId", "vfModuleId");
554 Assert.assertEquals(tenant.cloudOwner,"irma-aic" );
555 Assert.assertEquals(tenant.cloudRegionID,"rdm5b");
556 Assert.assertEquals(tenant.tenantID,"db1818f7f2e34862b378bfb2cc520f91");
559 @Test(expectedExceptions = GenericUncheckedException.class, expectedExceptionsMessageRegExp = "A&AI has no homing data associated to vfModule 'vfModuleId' of vnf 'vnfInstanceId'")
560 public void getVfModule_Homing_Arguments_Are_Valid_But_Not_Exists() {
561 when(aaiClientMock.getHomingDataByVfModule(any(String.class), any(String.class))).thenCallRealMethod();
563 Response generalEmptyResponse = mock(Response.class);
564 when(aaiClientMock.doAaiGet(any(String.class),any(Boolean.class))).thenReturn(generalEmptyResponse);
566 aaiClientMock.getHomingDataByVfModule("vnfInstanceId", "vfModuleId");
570 public static Object[][] invalidDataId() {
571 return new String[][] {
577 @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.")
578 public void getVfModule_Homing_Arguments_Are_Empty_Or_Null(String data) {
579 when(aaiClientMock.getHomingDataByVfModule(any(), any())).thenCallRealMethod();
580 aaiClientMock.getHomingDataByVfModule(data, data);
584 public static Object[][] resourceTypesProvider() {
585 return new Object[][] {
586 {"service-instance", ResourceType.SERVICE_INSTANCE},
587 {"generic-vnf", ResourceType.GENERIC_VNF},
588 {"vf-module", ResourceType.VF_MODULE}
593 public static Object[][] nameAndResourceTypeProvider() {
594 return new Object[][] {
595 {"SRIOV_SVC", ResourceType.SERVICE_INSTANCE, "nodes/service-instances?service-instance-name=SRIOV_SVC"},
596 {"b1707vidnf", ResourceType.GENERIC_VNF, "nodes/generic-vnfs?vnf-name=b1707vidnf"},
597 {"connectivity_test", ResourceType.VF_MODULE, "nodes/vf-modules?vf-module-name=connectivity_test"},
598 {"ByronPace", ResourceType.INSTANCE_GROUP, "nodes/instance-groups?instance-group-name=ByronPace"},
599 {"MjVg1234", ResourceType.VOLUME_GROUP, "nodes/volume-groups?volume-group-name=MjVg1234"}
603 @Test(dataProvider = "nameAndResourceTypeProvider")
604 public void whenSearchNodeTypeByName_callRightAaiPath(String name, ResourceType type, String expectedUrl) {
605 AAIRestInterface aaiRestInterface = mock(AAIRestInterface.class);
606 ResponseWithRequestInfo responseWithRequestInfo = mockedResponseWithRequestInfo(Response.Status.OK, "{}");
608 when(aaiRestInterface.RestGet(anyString(), anyString(), eq(toURI(expectedUrl)), anyBoolean(), anyBoolean()))
609 .thenReturn(responseWithRequestInfo);
611 AaiClient aaiClient = new AaiClient(aaiRestInterface, null, null);
613 aaiClient.isNodeTypeExistsByName(name, type);
617 public static Object[][] aaiClientInternalExceptions() {
618 return Stream.<Pair<Class<? extends Throwable>, UncheckedBiConsumer<HttpsAuthClient, Client>>>of(
620 // Exception out of httpsAuthClientMock
621 Pair.of(CertificateException.class, (httpsAuthClientMock, javaxClientMock) -> {
622 final CertificateException e0 = new CertificateException("No X509TrustManager implementation available");
623 SSLHandshakeException e = new SSLHandshakeException(e0.toString());
626 when(httpsAuthClientMock.getClient(any())).thenThrow(e);
629 Pair.of(StringIndexOutOfBoundsException.class, mockExceptionOnClientProvider(new StringIndexOutOfBoundsException(4))),
631 Pair.of(NullPointerException.class, mockExceptionOnClientProvider(new NullPointerException("null"))),
633 Pair.of(FileNotFoundException.class, mockExceptionOnClientProvider(new FileNotFoundException("vid/WEB-INF/cert/aai-client-cert.p12"))),
635 Pair.of(BadPaddingException.class, mockExceptionOnClientProvider(
636 new IOException("keystore password was incorrect", new BadPaddingException("Given final block not properly padded")))
638 Pair.of(GenericUncheckedException.class, mockExceptionOnClientProvider(new GenericUncheckedException("basa"))),
640 Pair.of(NullPointerException.class, (httpsAuthClientMock, javaxClientMock) ->
641 when(httpsAuthClientMock.getClient(any())).thenReturn(null)),
644 // Exception out of javax's Client
645 Pair.of(SSLHandshakeException.class, (httpsAuthClientMock, javaxClientMock) -> {
646 when(javaxClientMock.target(nullable(String.class))).thenThrow(
647 new ProcessingException(new SSLHandshakeException("Received fatal alert: certificate_expired"))
651 Pair.of(SunCertPathBuilderException.class, (httpsAuthClientMock, javaxClientMock) -> {
652 SunCertPathBuilderException e0 = new SunCertPathBuilderException("unable to find valid certification path to requested target");
653 when(javaxClientMock.target(nullable(String.class))).thenThrow(
654 new ProcessingException(new ValidatorException("PKIX path building failed: " + e0.toString(), e0))
658 Pair.of(GenericUncheckedException.class, (httpsAuthClientMock, javaxClientMock) ->
659 when(javaxClientMock.target(nullable(String.class))).thenThrow(new GenericUncheckedException("basa")))
661 ).flatMap(l -> Stream.of(
662 // double each case to propagateExceptions = true/false, to verify that "don't propagate" really still work
663 ImmutableList.of(l.getLeft(), l.getRight(), true).toArray(),
664 ImmutableList.of(l.getLeft(), l.getRight(), false).toArray()
665 )).collect(toList()).toArray(new Object[][]{});
668 private static UncheckedBiConsumer<HttpsAuthClient, Client> mockExceptionOnClientProvider(Exception e) {
669 return (httpsAuthClientMock, javaxClientMock) ->
670 when(httpsAuthClientMock.getClient(any())).thenThrow(e);
673 @Test(dataProvider = "aaiClientInternalExceptions")
674 public void propagateExceptions_internalsThrowException_ExceptionRethrown(Class<? extends Throwable> expectedType, BiConsumer<HttpsAuthClient, Client> setupMocks, boolean propagateExceptions) throws Exception {
677 this test -> AaiClient -> AAIRestInterface -> HttpsAuthClient -> javax's Client
679 In this test, *AaiClient* and *AAIRestInterface* are under test (actual
680 implementation is used), while HttpsAuthClient and the javax's Client are
681 mocked to return pseudo-responses or - better- throw exceptions.
685 HttpsAuthClient httpsAuthClientMock = mock(HttpsAuthClient.class);
686 TestUtils.JavaxRsClientMocks mocks = new TestUtils.JavaxRsClientMocks();
687 Client javaxClientMock = mocks.getFakeClient();
688 Response responseMock = mocks.getFakeResponse();
690 // prepare real AAIRestInterface and AaiClient, and wire mocks
691 AAIRestInterface aaiRestInterface = new AAIRestInterface(httpsAuthClientMock,
692 mock(ServletRequestHelper.class),
693 mock(SystemPropertyHelper.class),
694 mock(Logging.class));
695 final AaiClient aaiClient = new AaiClient(aaiRestInterface, null, null);
696 when(httpsAuthClientMock.getClient(any())).thenReturn(javaxClientMock);
698 // define atomic method under test, including reset of "aaiRestInterface.client"
699 final Function<Boolean, Response> doAaiGet = (propagateExceptions1) -> {
701 FieldUtils.writeField(aaiRestInterface, "client", null, true);
702 return aaiClient.doAaiGet("uri", false, propagateExceptions1).getResponse();
703 } catch (IllegalAccessException e) {
704 throw new RuntimeException(e);
708 // verify setup again
709 assertThat("mocks setup should make doAaiGet return our responseMock", doAaiGet.apply(true), is(sameInstance(responseMock)));
713 setupMocks.accept(httpsAuthClientMock, javaxClientMock);
716 final Response response = doAaiGet.apply(propagateExceptions);
717 } catch (Exception e) {
718 if (propagateExceptions) {
719 assertThat("root cause incorrect for " + ExceptionUtils.getStackTrace(e), ExceptionUtils.getRootCause(e), instanceOf(expectedType));
722 // Verify that "don't propagate" really still work
723 Assert.fail("calling doAaiGet when propagateExceptions is false must result with no exception", e);
727 // If no exception caught
728 // We're asserting that the legacy behaviour is still in place. Hopefully
729 // one day we will remove the non-propagateExceptions case
730 assertFalse(propagateExceptions, "calling doAaiGet when propagateExceptions is 'true' must result with an exception (in this test)");
734 public static Object[][] aaiClientGetCloudOwnerByCloudRegionId() {
736 final String cloudRegion = "{" +
737 " \"cloud-owner\": \"mure-royo-ru22\"," +
738 " \"cloud-region-id\": \"ravitu\"," +
739 " \"cloud-type\": \"openstack\"," +
740 " \"resource-version\": \"1523631256125\"," +
741 " \"relationship-list\": {" +
742 " \"relationship\": [{" +
743 " \"related-to\": \"pserver\"" +
749 String bodyWith0 = "{ \"cloud-region\": [" + " ]}";
750 String bodyWith1 = "{ \"cloud-region\": [" + cloudRegion + " ]}";
751 String bodyWith2 = "{ \"cloud-region\": [" + cloudRegion + ", " + cloudRegion + " ]}";
752 String bodyWithDifferent2 = "{ \"cloud-region\": [" + cloudRegion + ", " +
753 cloudRegion.replace("mure-royo-ru22", "nolay-umaxo") +
756 return new Object[][] {
757 { "regular single result", bodyWith1, false },
758 { "exceptional empty result", bodyWith0, true },
759 { "two same results", bodyWith2, false },
760 { "two incoherent results", bodyWithDifferent2, true },
764 @Test(dataProvider = "aaiClientGetCloudOwnerByCloudRegionId")
765 public void getCloudOwnerByCloudRegionIdNonCached(String desc, String body, boolean expectingException) {
766 final String cloudRegion = "ravitu";
767 AAIRestInterface aaiRestInterface = mock(AAIRestInterface.class);
768 final ResponseWithRequestInfo responseWithRequestInfo = mockedResponseWithRequestInfo(Response.Status.OK, body);
769 when(aaiRestInterface.doRest(anyString(), anyString(), eq(Unchecked.toURI("cloud-infrastructure/cloud-regions?cloud-region-id=" + cloudRegion)),
770 isNull(), eq(HttpMethod.GET), anyBoolean(), anyBoolean()))
771 .thenReturn(responseWithRequestInfo);
773 final AaiClient aaiClient = new AaiClient(aaiRestInterface, null, null);
776 final String result = aaiClient.getCloudOwnerByCloudRegionIdNonCached(cloudRegion);
777 if (expectingException) fail("expected failure on " + desc + ", got " + result);
779 assertThat(result, is("mure-royo-ru22"));
781 } catch (Exception e) {
782 if (!expectingException) throw e;
784 assertThat(e.toString(), either(
785 containsString("No cloud-owner found for " + cloudRegion))
786 .or(containsString("Conflicting cloud-owner found for " + cloudRegion)));
792 public static Object[][] cloudRegionAndTenantDataProvider() {
793 return new Object[][] {
794 { "APPC-24595-T-IST-02C", "mtn23b" },
795 { "APPC-24595-T-IST-02C", null },
802 public static Object[][] versionsDataProvider() {
803 return new Object[][] {
804 { Stream.of("20","10","30"), Stream.of("30","20","10"), "30" },
805 { Stream.of("10","20","20"), Stream.of("20","20","10"), "20" },
806 { Stream.of("c","b","a"), Stream.of("c","b","a"), "c" },
807 { Stream.of("1.0","2.0","1.8"), Stream.of("2.0","1.8","1.0"), "2.0" },
808 { Stream.of("1.0.7","2.0.9","2.0.2"), Stream.of("2.0.9","2.0.2","1.0.7"), "2.0.9" },
809 { Stream.of("0","0","0"), Stream.of("0","0","0"), "0" },
810 { Stream.of("","10"), Stream.of("10",""), "10" },
814 @Test(dataProvider = "versionsDataProvider")
815 public void sortedModelVer(Stream<String> input, Stream<String> expectedSorted, String expectedMax) {
816 Stream<ModelVer> modelVerStream = input.map(version -> {
817 ModelVer mv = new ModelVer();
818 mv.setModelVersion(version);
822 final AaiClient aaiClient = new AaiClient(null, null, null);
824 assertThat(aaiClient.sortedModelVer(modelVerStream),
826 expectedSorted.map(it -> hasProperty("modelVersion", is(it))).toArray(Matcher[]::new)
830 @Test(dataProvider = "versionsDataProvider")
831 public void maxModelVer(Stream<String> input, Stream<String> expectedSorted, String expectedMax) {
832 Stream<ModelVer> modelVerStream = input.map(version -> {
833 ModelVer mv = new ModelVer();
834 mv.setModelVersion(version);
838 final AaiClient aaiClient = new AaiClient(null, null, null);
840 assertThat(aaiClient.maxModelVer(modelVerStream), hasProperty("modelVersion", is(expectedMax)));
843 @Test(expectedExceptions = GenericUncheckedException.class)
844 public void maxModelVerException() {
845 final AaiClient aaiClient = new AaiClient(null, null, null);
846 aaiClient.maxModelVer(Stream.of(new ModelVer()));
848 @Test(dataProvider = "cloudRegionAndTenantDataProvider")
849 public void getCloudRegionAndTenantByVnfId(String tenantName, String cloudRegionId) throws JsonProcessingException {
850 SimpleResult tenant = new SimpleResult();
851 if (tenantName != null) {
852 tenant.setJsonNodeType("tenant");
853 Properties tenantProps = new Properties();
854 tenantProps.setTenantName(tenantName);
855 tenant.setJsonProperties(tenantProps);
858 SimpleResult cloudRegion = new SimpleResult();
859 if (cloudRegionId != null) {
860 cloudRegion.setJsonNodeType("cloud-region");
861 Properties cloudRegionProps = new Properties();
862 cloudRegionProps.setCloudRegionId(cloudRegionId);
863 cloudRegion.setJsonProperties(cloudRegionProps);
866 CustomQuerySimpleResult customQuerySimpleResult = new CustomQuerySimpleResult(ImmutableList.of(tenant, cloudRegion));
867 String mockedBody = new ObjectMapper().writeValueAsString(customQuerySimpleResult);
869 AAIRestInterface aaiRestInterface = mock(AAIRestInterface.class);
870 final ResponseWithRequestInfo responseWithRequestInfo = mockedResponseWithRequestInfo(Response.Status.OK, mockedBody, "query?format=simple", HttpMethod.PUT);
871 when(aaiRestInterface.doRest(anyString(), anyString(), eq(Unchecked.toURI("query?format=simple")),
872 any(), eq(HttpMethod.PUT), anyBoolean(), anyBoolean()))
873 .thenReturn(responseWithRequestInfo);
875 final AaiClient aaiClient = new AaiClient(aaiRestInterface, null, null);
876 Map<String, Properties> result = aaiClient.getCloudRegionAndTenantByVnfId("anyVnfId");
877 if (tenantName != null) {
878 assertEquals(result.get("tenant").getTenantName(), tenantName);
880 assertNull(result.get("tenant"));
883 if (cloudRegionId != null) {
884 assertEquals(result.get("cloud-region").getCloudRegionId(), cloudRegionId);
886 assertNull(result.get("cloud-region"));
890 protected void mockForGetRequest(AAIRestInterface aaiRestInterface, ResponseWithRequestInfo responseWithRequestInfo) {
891 when(aaiRestInterface.doRest(anyString(), anyString(), any(URI.class), isNull(), eq(HttpMethod.GET) ,anyBoolean(), anyBoolean()))
892 .thenReturn(responseWithRequestInfo);
896 public void shouldProperlyReadResponseOnceWhenSubscribersAreNotPresent() {
897 AAIRestInterface restInterface = mock(AAIRestInterface.class);
898 PortDetailsTranslator portDetailsTranslator = mock(PortDetailsTranslator.class);
899 Response response = mock(Response.class);
900 when(response.getStatus()).thenReturn(404);
901 when(response.readEntity(String.class)).thenReturn("sampleEntity");
902 when(response.getStatusInfo()).thenReturn(Response.Status.NOT_FOUND);
903 ResponseWithRequestInfo responseWithRequestInfo = new ResponseWithRequestInfo(response, "test", HttpMethod.GET);
904 when(restInterface.RestGet(eq("VidAaiController"), any(String.class),
905 eq(Unchecked.toURI("business/customers?subscriber-type=INFRA&depth=0")), eq(false), eq(true))).thenReturn(responseWithRequestInfo);
906 AaiClient aaiClient = new AaiClient(restInterface, portDetailsTranslator, null);
909 aaiClient.getAllSubscribers(true);
911 verify(response).readEntity(String.class);
915 public interface UncheckedBiConsumer<T, U> extends BiConsumer<T, U> {
917 default void accept(T t, U u) {
920 } catch (Exception e) {
921 throw new RuntimeException(e);
925 void acceptThrows(T t, U u) throws Exception;
929 public void getLatestVersionByInvariantId_verifyCallingExpectedApi(){
931 when(aaiClientMock.getLatestVersionByInvariantId(anyString())).thenCallRealMethod();
933 aaiClientMock.getLatestVersionByInvariantId("model-invariant-id");
935 Mockito.verify(aaiClientMock).doAaiPut(argThat(url -> url.endsWith("query?format=resource&depth=0")),argThat(payload -> payload.contains("service-design-and-creation/models/model/model-invariant-id")),anyBoolean());
940 public static Object[][] getSubscriberDataDataProvider() {
941 return new Object[][] {
943 { "another id 123", false },
947 @Test(dataProvider = "getSubscriberDataDataProvider")
948 public void getSubscriberDataParams(String subscriberId, boolean omitServiceInstances) {
949 String depth = omitServiceInstances ? "1" : "2";
950 when(aaiClientMock.getSubscriberData(anyString(),anyBoolean())).thenCallRealMethod();
951 aaiClientMock.getSubscriberData(subscriberId, omitServiceInstances);
952 Mockito.verify(aaiClientMock).doAaiGet(argThat(s -> s.contains("customer/" + subscriberId + "?") && s.contains("depth=" + depth)),any(Boolean.class));
956 public void testToModelVerStream() throws IOException {
958 ModelVersions modelVersions = JACKSON_OBJECT_MAPPER.readValue("" +
960 " \"results\": [\n" +
963 " \"model-invariant-id\": \"f6342be5-d66b-4d03-a1aa-c82c3094c4ea\",\n" +
964 " \"model-type\": \"service\",\n" +
965 " \"resource-version\": \"1534274421300\"\n" +
969 " \"model-ver\": {\n" +
970 " \"model-version-id\": \"a92f899d-a3ec-465b-baed-1663b0a5aee1\",\n" +
971 " \"model-name\": \"NCM_VLAN_SVC_ym161f\",\n" +
972 " \"model-version\": \"bbb\",\n" +
973 " \"distribution-status\": \"DISTRIBUTION_COMPLETE_OK\",\n" +
974 " \"model-description\": \"Network Collection service for vLAN tagging\",\n" +
975 " \"resource-version\": \"1534788756086\"\n" +
979 " \"model-ver\": {\n" +
980 " \"model-version-id\": \"d2fda667-e92e-4cfa-9620-5da5de01a319\",\n" +
981 " \"model-name\": \"NCM_VLAN_SVC_ym161f\",\n" +
982 " \"model-version\": \"aaa\",\n" +
983 " \"distribution-status\": \"DISTRIBUTION_COMPLETE_OK\",\n" +
984 " \"model-description\": \"Network Collection service for vLAN tagging\",\n" +
985 " \"resource-version\": \"1534444087221\"\n" +
987 " }]}", ModelVersions.class);
990 final AaiClient aaiClient = new AaiClient(null, null, null);
992 assertThat(aaiClient.toModelVerStream(modelVersions).collect(toList()),
994 hasProperty("modelVersionId", is("a92f899d-a3ec-465b-baed-1663b0a5aee1")),
995 hasProperty("modelVersionId", is("d2fda667-e92e-4cfa-9620-5da5de01a319"))