Merge from ECOMP's repository
[vid.git] / vid-app-common / src / test / java / org / onap / vid / aai / AaiClientTest.java
index 201ec09..2656532 100644 (file)
@@ -1,26 +1,6 @@
-/*-
- * ============LICENSE_START=======================================================
- * VID
- * ================================================================================
- * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved.
- * Modifications Copyright (C) 2018 Nokia. All rights reserved.
- * ================================================================================
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- * ============LICENSE_END=========================================================
- */
-
 package org.onap.vid.aai;
 
+import com.fasterxml.jackson.core.JsonProcessingException;
 import com.fasterxml.jackson.databind.ObjectMapper;
 import com.google.common.collect.ImmutableList;
 import org.apache.commons.lang3.builder.ReflectionToStringBuilder;
@@ -28,18 +8,15 @@ import org.apache.commons.lang3.builder.ToStringStyle;
 import org.apache.commons.lang3.exception.ExceptionUtils;
 import org.apache.commons.lang3.reflect.FieldUtils;
 import org.apache.commons.lang3.tuple.Pair;
+import org.apache.http.HttpStatus;
 import org.mockito.Mockito;
 import org.onap.portalsdk.core.logging.logic.EELFLoggerDelegate;
 import org.onap.portalsdk.core.util.SystemProperties;
+import org.onap.vid.aai.model.AaiGetNetworkCollectionDetails.RelatedToProperty;
 import org.onap.vid.aai.model.AaiGetTenatns.GetTenantsResponse;
-import org.onap.vid.aai.model.AaiNodeQueryResponse;
-import org.onap.vid.aai.model.PortDetailsTranslator;
-import org.onap.vid.aai.model.ResourceType;
-import org.onap.vid.aai.util.AAIRestInterface;
-import org.onap.vid.aai.util.HttpsAuthClient;
-import org.onap.vid.aai.util.ServletRequestHelper;
-import org.onap.vid.aai.util.SystemPropertyHelper;
-import org.onap.vid.controllers.LocalWebConfig;
+import org.onap.vid.aai.model.*;
+import org.onap.vid.aai.util.*;
+import org.onap.vid.controller.LocalWebConfig;
 import org.onap.vid.exceptions.GenericUncheckedException;
 import org.onap.vid.model.Subscriber;
 import org.onap.vid.model.SubscriberList;
@@ -47,6 +24,7 @@ import org.onap.vid.model.probes.ExternalComponentStatus;
 import org.onap.vid.model.probes.HttpRequestMetadata;
 import org.onap.vid.model.probes.StatusMetadata;
 import org.onap.vid.testUtils.TestUtils;
+import org.onap.vid.utils.Unchecked;
 import org.springframework.http.HttpMethod;
 import org.springframework.test.context.ContextConfiguration;
 import org.springframework.test.context.web.WebAppConfiguration;
@@ -65,42 +43,53 @@ import javax.ws.rs.client.Client;
 import javax.ws.rs.core.Response;
 import java.io.FileNotFoundException;
 import java.io.IOException;
+import java.net.URI;
 import java.security.cert.CertificateException;
 import java.util.ArrayList;
+import java.util.Map;
 import java.util.function.BiConsumer;
 import java.util.function.Function;
 import java.util.stream.Collectors;
 import java.util.stream.Stream;
 
 import static org.apache.commons.lang3.StringUtils.equalsIgnoreCase;
-import static org.hamcrest.CoreMatchers.*;
 import static org.hamcrest.MatcherAssert.assertThat;
-import static org.mockito.ArgumentMatchers.any;
-import static org.mockito.ArgumentMatchers.*;
+import static org.hamcrest.Matchers.*;
+import static org.mockito.ArgumentMatchers.nullable;
+import static org.mockito.Matchers.any;
+import static org.mockito.Matchers.anyBoolean;
+import static org.mockito.Matchers.anyString;
+import static org.mockito.Matchers.argThat;
+import static org.mockito.Matchers.eq;
+import static org.mockito.Matchers.isNull;
 import static org.mockito.Mockito.*;
+import static org.onap.vid.utils.Unchecked.toURI;
 import static org.testng.Assert.*;
 
 @ContextConfiguration(classes = {LocalWebConfig.class, SystemProperties.class})
 @WebAppConfiguration
 public class AaiClientTest {
 
+    private final String NO_LCP_REGION_AND_TENANTS_MSG = "A&AI has no LCP Region & Tenants associated to subscriber 'subscriberId' and service type 'serviceType'";
     private AaiClient aaiClientMock;
     private ServletContext servletContext;
 
     @BeforeMethod
-    public void initMocks() {
+    public void initMocks(){
         aaiClientMock = mock(AaiClient.class);
         aaiClientMock.logger = mock(EELFLoggerDelegate.class);
+        aaiClientMock.objectMapper = new ObjectMapper();
         servletContext = mock(ServletContext.class);
 
         when(servletContext.getRealPath(any(String.class))).thenReturn("");
 
-        when(aaiClientMock.doAaiGet(any(String.class), any(Boolean.class))).thenReturn(null);
+        when(aaiClientMock.doAaiGet(any(String.class),any(Boolean.class))).thenReturn(null);
+        when(aaiClientMock.doAaiGet(any(URI.class), anyBoolean(), anyBoolean())).thenReturn(null);
     }
 
     @DataProvider
     public static Object[][] logicalLinkData() {
-        return new Object[][]{
+        return new Object[][] {
                 {"", "network/logical-links/logical-link/"},
                 {"link", "network/logical-links/logical-link/link"}
         };
@@ -111,26 +100,21 @@ public class AaiClientTest {
 
         when(aaiClientMock.getLogicalLink(any(String.class))).thenCallRealMethod();
         aaiClientMock.getLogicalLink(link);
-        Mockito.verify(aaiClientMock).doAaiGet(argThat(s -> equalsIgnoreCase(s, expectedUrl)), any(Boolean.class));
+        verify(aaiClientMock).doAaiGet(argThat(s -> equalsIgnoreCase(s, expectedUrl)),any(Boolean.class));
     }
 
     @DataProvider
     public static Object[][] subscribersResults() {
-        return new Object[][]{
-                {new SubscriberList(new ArrayList<Subscriber>() {{
-                    add(new Subscriber());
-                    add(new Subscriber());
-                }}), true},
-                {new SubscriberList(new ArrayList<Subscriber>() {{
-                    add(new Subscriber());
-                }}), true},
+        return new Object[][] {
+                {new SubscriberList(new ArrayList<Subscriber>() {{ add(new Subscriber());  add(new Subscriber()); }}), true},
+                {new SubscriberList(new ArrayList<Subscriber>() {{ add(new Subscriber()); }}), true},
                 {new SubscriberList(new ArrayList<Subscriber>()), false}
         };
     }
 
     @Test(dataProvider = "subscribersResults")
-    public void testProbeAaiGetAllSubscribers_returnsTwoToZeroSubscribers_ResultsAsExpected(SubscriberList subscribers, boolean isAvailable) {
-        ExternalComponentStatus expectedStatus = new ExternalComponentStatus(ExternalComponentStatus.Component.AAI, isAvailable, new HttpRequestMetadata(
+    public void testProbeAaiGetAllSubscribers_returnsTwoToZeroSubscribers_ResultsAsExpected(SubscriberList subscribers, boolean isAvailable){
+        ExternalComponentStatus expectedStatus = new ExternalComponentStatus(ExternalComponentStatus.Component.AAI,isAvailable, new HttpRequestMetadata(
                 HttpMethod.GET,
                 200,
                 "url",
@@ -143,9 +127,79 @@ public class AaiClientTest {
                         HttpMethod.GET, "url", new AaiResponse<>(subscribers, null, 200),
                         "rawData"));
         Mockito.when(aaiClientMock.probeAaiGetAllSubscribers()).thenCallRealMethod();
-        ExternalComponentStatus result = aaiClientMock.probeAaiGetAllSubscribers();
-        assertThat(statusDataReflected(result), is(statusDataReflected(expectedStatus)));
-        assertThat(requestMetadataReflected(result.getMetadata()), is(requestMetadataReflected(expectedStatus.getMetadata())));
+        ExternalComponentStatus result  = aaiClientMock.probeAaiGetAllSubscribers();
+        assertThat(statusDataReflected(result),is(statusDataReflected(expectedStatus)));
+        assertThat(requestMetadataReflected(result.getMetadata()),is(requestMetadataReflected(expectedStatus.getMetadata())));
+    }
+
+    @Test(expectedExceptions = Exception.class)
+    public void typedAaiGet_aaiRestInterfaceRestGetReturnsError_exceptionIsThrown() {
+        AAIRestInterface aaiRestInterface = mock(AAIRestInterface.class);
+        final ResponseWithRequestInfo responseWithRequestInfo = mockedResponseWithRequestInfo(Response.Status.INTERNAL_SERVER_ERROR, "entity");
+        mockForGetRequest(aaiRestInterface, responseWithRequestInfo);
+        final AaiClient aaiClient = new AaiClient(aaiRestInterface, null, null);
+
+        try {
+
+            aaiClient.typedAaiGet(toURI("/irrelevant/url"), RelatedToProperty.class);
+
+        } catch (Exception e) {
+            assertThat(ExceptionUtils.getStackTrace(e), e, instanceOf(ExceptionWithRequestInfo.class));
+            ExceptionWithRequestInfo e2 = ((ExceptionWithRequestInfo) e);
+            assertThat(e2.getHttpCode(), is(Response.Status.INTERNAL_SERVER_ERROR.getStatusCode()));
+            assertThat(e2.getRawData(), is("entity"));
+            assertThat(e2.getHttpMethod(), is(HttpMethod.GET));
+            assertThat(e2.getRequestedUrl(), is("/my/mocked/url"));
+
+            throw e;
+        }
+    }
+
+    @Test(expectedExceptions = Exception.class)
+    public void typedAaiGet_aaiRestInterfaceRestGetReturnsInparsableResponse_exceptionIsThrown() {
+        AAIRestInterface aaiRestInterface = mock(AAIRestInterface.class);
+        final ResponseWithRequestInfo responseWithRequestInfo = mockedResponseWithRequestInfo(Response.Status.OK, "entity");
+        mockForGetRequest(aaiRestInterface, responseWithRequestInfo);
+        final AaiClient aaiClient = new AaiClient(aaiRestInterface, null, null);
+
+        try {
+
+            aaiClient.typedAaiGet(toURI("/irrelevant/url"), RelatedToProperty.class);
+
+        } catch (Exception e) {
+            assertThat(ExceptionUtils.getStackTrace(e), e, instanceOf(ExceptionWithRequestInfo.class));
+            assertThat(e.getCause(),
+                    hasProperty("cause", is(instanceOf(com.fasterxml.jackson.core.JsonParseException.class)))
+            );
+            throw e;
+        }
+    }
+
+    @Test
+    public void typedAaiGet_aaiRestInterfaceRestGetReturns_objectIsFine() {
+        AAIRestInterface aaiRestInterface = mock(AAIRestInterface.class);
+        final ResponseWithRequestInfo responseWithRequestInfo = mockedResponseWithRequestInfo(Response.Status.OK,
+                "{ \"property-key\": \"foo\", \"property-value\": \"bar\" }");
+        mockForGetRequest(aaiRestInterface, responseWithRequestInfo);
+
+        final AaiClient aaiClient = new AaiClient(aaiRestInterface, null, null);
+
+        final RelatedToProperty relatedToPropertyAaiResponse = aaiClient.typedAaiGet(toURI("/irrelevant/url"), RelatedToProperty.class);
+
+        assertThat(relatedToPropertyAaiResponse.getPropertyKey(), is("foo"));
+        assertThat(relatedToPropertyAaiResponse.getPropertyValue(), is("bar"));
+    }
+
+    private ResponseWithRequestInfo mockedResponseWithRequestInfo(Response.Status status, String entity) {
+        return mockedResponseWithRequestInfo(status, entity, "/my/mocked/url", HttpMethod.GET);
+    }
+
+    private ResponseWithRequestInfo mockedResponseWithRequestInfo(Response.Status status, String entity, String requestUrl, HttpMethod method) {
+        final Response mockResponse = mock(Response.class);
+        when(mockResponse.getStatus()).thenReturn(status.getStatusCode());
+        when(mockResponse.getStatusInfo()).thenReturn(status);
+        when(mockResponse.readEntity(String.class)).thenReturn(entity);
+        return new ResponseWithRequestInfo(mockResponse, requestUrl, method);
     }
 
     //serialize fields except of fields we cannot know ahead of time
@@ -164,12 +218,12 @@ public class AaiClientTest {
     @DataProvider
     public static Object[][] rawData() {
         return new Object[][]{
-                {"errorMessage",}, {""}, {null}
+                {"errorMessage", }, {""}, {null}
         };
     }
 
     @Test(dataProvider = "rawData")
-    public void testProbeAaiGetFullSubscribersWithNullResponse_returnsNotAvailableWithErrorRawData(String rawData) {
+    public void testProbeAaiGetFullSubscribersWithNullResponse_returnsNotAvailableWithErrorRawData(String rawData){
         Mockito.when(aaiClientMock.getAllSubscribers(true)).thenReturn(
                 new AaiResponseWithRequestInfo<>(HttpMethod.GET, "url", null,
                         rawData));
@@ -180,7 +234,7 @@ public class AaiClientTest {
 
     @DataProvider
     public static Object[][] exceptions() {
-        return new Object[][]{
+        return new Object[][] {
                 {"NullPointerException", "errorMessage",
                         new ExceptionWithRequestInfo(HttpMethod.GET, "url",
                                 "errorMessage", null, new NullPointerException())},
@@ -193,7 +247,7 @@ public class AaiClientTest {
     }
 
     @Test(dataProvider = "exceptions")
-    public void testProbeAaiGetFullSubscribersWithNullResponse_returnsNotAvailableWithErrorRawData(String description, String expectedRawData, Exception exception) {
+    public void testProbeAaiGetFullSubscribersWithNullResponse_returnsNotAvailableWithErrorRawData(String description, String expectedRawData, Exception exception){
         Mockito.when(aaiClientMock.getAllSubscribers(true)).thenThrow(exception);
         ExternalComponentStatus result = callProbeAaiGetAllSubscribersAndAssertNotAvailable();
         if (exception instanceof ExceptionWithRequestInfo) {
@@ -205,7 +259,7 @@ public class AaiClientTest {
 
     private ExternalComponentStatus callProbeAaiGetAllSubscribersAndAssertNotAvailable() {
         Mockito.when(aaiClientMock.probeAaiGetAllSubscribers()).thenCallRealMethod();
-        ExternalComponentStatus result = aaiClientMock.probeAaiGetAllSubscribers();
+        ExternalComponentStatus result  = aaiClientMock.probeAaiGetAllSubscribers();
         assertFalse(result.isAvailable());
         return result;
     }
@@ -226,56 +280,55 @@ public class AaiClientTest {
         assertEquals(response.getErrorMessage(), "{\"statusText\":\" Failed to retrieve LCP Region & Tenants from A&AI, Subscriber ID or Service Type is missing.\"}");
     }
 
-    @Test
+    @Test(expectedExceptions = AaiClient.ParsingGetTenantsResponseFailure.class, expectedExceptionsMessageRegExp = NO_LCP_REGION_AND_TENANTS_MSG)
     public void getTenants_Arguments_Are_Valid_But_Tenants_Not_Exist() {
 
-        when(aaiClientMock.getTenants(any(String.class), any(String.class))).thenCallRealMethod();
+        when(aaiClientMock.getTenantsNonCached(any(String.class),any(String.class))).thenCallRealMethod();
 
         Response generalEmptyResponse = mock(Response.class);
-        when(aaiClientMock.doAaiGet(any(String.class), any(Boolean.class))).thenReturn(generalEmptyResponse);
+        when(aaiClientMock.doAaiGet(any(String.class),any(Boolean.class))).thenReturn(generalEmptyResponse);
 
-        AaiResponse response = aaiClientMock.getTenants("subscriberId", "serviceType");
-
-        assertEquals(response.getErrorMessage(), "{\"statusText\":\" A&AI has no LCP Region & Tenants associated to subscriber 'subscriberId' and service type 'serviceType'\"}");
+        aaiClientMock.getTenantsNonCached("subscriberId", "serviceType");
+    }
 
+    @Test
+    public void whenCacheThrowException_thenGetTenantReturnAaiResponse() {
+        CacheProvider mockCacheProvider = mock(CacheProvider.class);
+        CacheProvider.Cache mockCache = mock(CacheProvider.Cache.class);
+        AaiClient aaiClientUnderTest = new AaiClient(null, null, mockCacheProvider);
+
+        when(mockCacheProvider.aaiClientCacheFor(any(), any())).thenReturn(mockCache);
+        when(mockCache.get(any())).thenThrow(new AaiClient.ParsingGetTenantsResponseFailure(NO_LCP_REGION_AND_TENANTS_MSG));
+        AaiResponse aaiResponse = aaiClientUnderTest.getTenants("subscriberId", "serviceType");
+        assertEquals(HttpStatus.SC_INTERNAL_SERVER_ERROR, aaiResponse.getHttpCode());
+        assertEquals("{\"statusText\":\""+NO_LCP_REGION_AND_TENANTS_MSG+"\"}", aaiResponse.getErrorMessage());
     }
 
     @Test
     public void getTenants_Arguments_Are_Valid_Get_The_Tenanats() {
 
-        when(aaiClientMock.getTenants(any(String.class), any(String.class))).thenCallRealMethod();
+        when(aaiClientMock.getTenantsNonCached(any(String.class),any(String.class))).thenCallRealMethod();
 
 
         Response generalEmptyResponse = mock(Response.class);
 
         when(generalEmptyResponse.readEntity(String.class)).thenReturn(tenantResponseRaw);
         when(generalEmptyResponse.getStatus()).thenReturn(200);
-        when(generalEmptyResponse.getStatusInfo()).thenReturn(new Response.StatusType() {
-            @Override
-            public int getStatusCode() {
-                return 200;
-            }
+        when(generalEmptyResponse.getStatusInfo()).thenReturn(Response.Status.OK);
 
-            @Override
-            public Response.Status.Family getFamily() {
-                return Response.Status.Family.SUCCESSFUL;
-            }
 
-            @Override
-            public String getReasonPhrase() {
-                return null;
-            }
-        });
+        when(aaiClientMock.doAaiGet(any(String.class),any(Boolean.class))).thenReturn(generalEmptyResponse);
 
+        AaiResponse<GetTenantsResponse[]> response = aaiClientMock.getTenantsNonCached("subscriberId", "serviceType");
 
-        when(aaiClientMock.doAaiGet(any(String.class), any(Boolean.class))).thenReturn(generalEmptyResponse);
+        GetTenantsResponse[] tenants = response.getT();
 
-        AaiResponse<GetTenantsResponse[]> response = aaiClientMock.getTenants("subscriberId", "serviceType");
+        Assert.assertTrue(response.t.length> 0);
 
-        Assert.assertTrue(response.t.length > 0);
+        Assert.assertEquals(tenants[0].cloudOwner,"att-aic-cloud-owner");
     }
 
-    final String tenantResponseRaw = "" +
+    final String tenantResponseRaw ="" +
             "{" +
             "\"service-type\": \"VIRTUAL USP\"," +
             "\"resource-version\": \"1494001841964\"," +
@@ -285,7 +338,7 @@ public class AaiClientTest {
             "\"related-link\": \"/aai/v11/cloud-infrastructure/cloud-regions/cloud-region/att-aic/AAIAIC25/tenants/tenant/092eb9e8e4b7412e8787dd091bc58e86\"," +
             "\"relationship-data\": [{" +
             "\"relationship-key\": \"cloud-region.cloud-owner\"," +
-            "\"relationship-value\": \"att-aic\"" +
+            "\"relationship-value\": \"att-aic-cloud-owner\"" +
             "}," +
             "{" +
             "\"relationship-key\": \"cloud-region.cloud-region-id\"," +
@@ -304,51 +357,179 @@ public class AaiClientTest {
             "}" +
             "}";
 
+    final String vfModuleHomingResponseRaw ="{" +
+            "    \"vf-module-id\": \"ed02354a-3217-45ce-a1cd-e0b69b7a8cea\"," +
+            "    \"vf-module-name\": \"apndns_az_02_module_1\"," +
+            "    \"heat-stack-id\": \"apndns_az_02_module_1/97a319f3-b095-4fff-befa-c657508ecaf8\"," +
+            "    \"orchestration-status\": \"active\"," +
+            "    \"is-base-vf-module\": false," +
+            "    \"resource-version\": \"1530559380383\"," +
+            "    \"model-invariant-id\": \"74450b48-0aa0-4743-8314-9163e92b7862\"," +
+            "    \"model-version-id\": \"6bc01a2b-bc48-4991-b9fe-e22c2215d801\"," +
+            "    \"model-customization-id\": \"74f638c2-0368-4212-8f73-e961005af17c\"," +
+            "    \"module-index\": 0," +
+            "    \"relationship-list\": {" +
+            "        \"relationship\": [" +
+            "            {" +
+            "                \"related-to\": \"l3-network\"," +
+            "                \"relationship-label\": \"org.onap.relationships.inventory.DependsOn\"," +
+            "                \"related-link\": \"/aai/v12/network/l3-networks/l3-network/335e62be-73a3-41e8-930b-1a677bcafea5\"," +
+            "                \"relationship-data\": [" +
+            "                    {" +
+            "                        \"relationship-key\": \"l3-network.network-id\"," +
+            "                        \"relationship-value\": \"335e62be-73a3-41e8-930b-1a677bcafea5\"" +
+            "                    }" +
+            "                ]," +
+            "                \"related-to-property\": [" +
+            "                    {" +
+            "                        \"property-key\": \"l3-network.network-name\"," +
+            "                        \"property-value\": \"MNS-FN-25180-T-02Shared_oam_protected_net_1\"" +
+            "                    }" +
+            "                ]" +
+            "            }," +
+            "            {" +
+            "                \"related-to\": \"l3-network\"," +
+            "                \"relationship-label\": \"org.onap.relationships.inventory.DependsOn\"," +
+            "                \"related-link\": \"/aai/v12/network/l3-networks/l3-network/2db4ee3e-2ac7-4fc3-8739-ecf53416459e\"," +
+            "                \"relationship-data\": [" +
+            "                    {" +
+            "                        \"relationship-key\": \"l3-network.network-id\"," +
+            "                        \"relationship-value\": \"2db4ee3e-2ac7-4fc3-8739-ecf53416459e\"" +
+            "                    }" +
+            "                ]," +
+            "                \"related-to-property\": [" +
+            "                    {" +
+            "                        \"property-key\": \"l3-network.network-name\"," +
+            "                        \"property-value\": \"Mobisupport-FN-27099-T-02_int_apn_dns_net_1\"" +
+            "                    }" +
+            "                ]" +
+            "            }," +
+            "            {" +
+            "                \"related-to\": \"volume-group\"," +
+            "                \"relationship-label\": \"org.onap.relationships.inventory.Uses\"," +
+            "                \"related-link\": \"/aai/v12/cloud-infrastructure/cloud-regions/cloud-region/att-aic/rdm5b/volume-groups/volume-group/66013ebe-0c81-44b9-a24f-7c6acba73a39\"," +
+            "                \"relationship-data\": [" +
+            "                    {" +
+            "                        \"relationship-key\": \"cloud-region.cloud-owner\"," +
+            "                        \"relationship-value\": \"att-aic\"" +
+            "                    }," +
+            "                    {" +
+            "                        \"relationship-key\": \"cloud-region.cloud-region-id\"," +
+            "                        \"relationship-value\": \"rdm5b\"" +
+            "                    }," +
+            "                    {" +
+            "                        \"relationship-key\": \"volume-group.volume-group-id\"," +
+            "                        \"relationship-value\": \"66013ebe-0c81-44b9-a24f-7c6acba73a39\"" +
+            "                    }" +
+            "                ]" +
+            "            }," +
+            "            {" +
+            "                \"related-to\": \"vserver\"," +
+            "                \"relationship-label\": \"org.onap.relationships.inventory.Uses\"," +
+            "                \"related-link\": \"/aai/v12/cloud-infrastructure/cloud-regions/cloud-region/att-aic/rdm5b/tenants/tenant/db1818f7f2e34862b378bfb2cc520f91/vservers/vserver/5eef9f6d-9933-4bc6-9a1a-862d61309437\"," +
+            "                \"relationship-data\": [" +
+            "                    {" +
+            "                        \"relationship-key\": \"cloud-region.cloud-owner\"," +
+            "                        \"relationship-value\": \"att-aic\"" +
+            "                    }," +
+            "                    {" +
+            "                        \"relationship-key\": \"cloud-region.cloud-region-id\"," +
+            "                        \"relationship-value\": \"rdm5b\"" +
+            "                    }," +
+            "                    {" +
+            "                        \"relationship-key\": \"tenant.tenant-id\"," +
+            "                        \"relationship-value\": \"db1818f7f2e34862b378bfb2cc520f91\"" +
+            "                    }," +
+            "                    {" +
+            "                        \"relationship-key\": \"vserver.vserver-id\"," +
+            "                        \"relationship-value\": \"5eef9f6d-9933-4bc6-9a1a-862d61309437\"" +
+            "                    }" +
+            "                ]," +
+            "                \"related-to-property\": [" +
+            "                    {" +
+            "                        \"property-key\": \"vserver.vserver-name\"," +
+            "                        \"property-value\": \"zrdm5bfapn01dns002\"" +
+            "                    }" +
+            "                ]" +
+            "            }" +
+            "        ]" +
+            "    }" +
+            "}";
+    @Test
+    public void get_homingDataForVfModule() {
+        when(aaiClientMock.getHomingDataByVfModule(any(String.class), any(String.class))).thenCallRealMethod();
+
+        Response homingResponse = mock(Response.class);
+
+        when(homingResponse.readEntity(String.class)).thenReturn(vfModuleHomingResponseRaw);
+        when(homingResponse.getStatus()).thenReturn(200);
+        when(homingResponse.getStatusInfo()).thenReturn(Response.Status.OK);
+
+
+        when(aaiClientMock.doAaiGet(any(String.class), any(Boolean.class))).thenReturn(homingResponse);
+
+        GetTenantsResponse tenant = aaiClientMock.getHomingDataByVfModule("vnfInstanceId", "vfModuleId");
+
+        Assert.assertEquals(tenant.cloudOwner,"att-aic");
+        Assert.assertEquals(tenant.cloudRegionID,"rdm5b");
+        Assert.assertEquals(tenant.tenantID,"db1818f7f2e34862b378bfb2cc520f91");
+
+    }
+    @Test(expectedExceptions = GenericUncheckedException.class, expectedExceptionsMessageRegExp = "A&AI has no homing data associated to vfModule 'vfModuleId' of vnf 'vnfInstanceId'")
+    public void getVfMoudule_Homing_Arguments_Are_Valid_But_Not_Exists() {
+        when(aaiClientMock.getHomingDataByVfModule(any(String.class), any(String.class))).thenCallRealMethod();
+
+        Response generalEmptyResponse = mock(Response.class);
+        when(aaiClientMock.doAaiGet(any(String.class),any(Boolean.class))).thenReturn(generalEmptyResponse);
+
+        aaiClientMock.getHomingDataByVfModule("vnfInstanceId", "vfModuleId");
+    }
+
     @DataProvider
-    public static Object[][] resourceTypesProvider() {
-        return new Object[][]{
-                {"service-instance", ResourceType.SERVICE_INSTANCE},
-                {"generic-vnf", ResourceType.GENERIC_VNF},
-                {"vf-module", ResourceType.VF_MODULE}
+    public static Object[][] invalidDataId() {
+        return new String[][] {
+                {""},
+                {null}
         };
     }
 
-    @Test(dataProvider = "resourceTypesProvider")
-    public void aaiNodeQueryResponseDeserializationTest(String resourceType, ResourceType expectedResourceType) throws IOException {
-        String link = "/aai/v12/business/customers/customer/a9a77d5a-123e-4ca2-9eb9-0b015d2ee0fb/service-subscriptions/service-subscription/Nimbus/service-instances/service-instance/7131d483-b450-406f-8e30-0c650645fc67";
-        String json =
-                "{\"result-data\": [{" +
-                        "\"resource-type\": \"" + resourceType + "\"," +
-                        "\"resource-link\": \"" + link + "\"" +
-                        "}]}";
-
-        AaiNodeQueryResponse nodeQueryResponse = new ObjectMapper().readValue(json, AaiNodeQueryResponse.class);
-        assertThat(nodeQueryResponse.resultData.get(0).resourceLink, equalTo(link));
-        assertThat(nodeQueryResponse.resultData.get(0).resourceType, is(expectedResourceType));
+    @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.")
+    public void getVfMoudule_Homing_Arguments_Are_Empty_Or_Null(String data) {
+        when(aaiClientMock.getHomingDataByVfModule(any(), any())).thenCallRealMethod();
+             aaiClientMock.getHomingDataByVfModule(data, data);
     }
 
-    @Test
-    public void aaiNodeQueryEmptyResponseDeserializationTest() throws IOException {
-        String json = "{}";
-        AaiNodeQueryResponse nodeQueryResponse = new ObjectMapper().readValue(json, AaiNodeQueryResponse.class);
-        assertNull(nodeQueryResponse.resultData);
+    @DataProvider
+    public static Object[][] resourceTypesProvider() {
+        return new Object[][] {
+                {"service-instance", ResourceType.SERVICE_INSTANCE},
+                {"generic-vnf", ResourceType.GENERIC_VNF},
+                {"vf-module", ResourceType.VF_MODULE}
+        };
     }
 
     @DataProvider
     public static Object[][] nameAndResourceTypeProvider() {
-        return new Object[][]{
-                {"SRIOV_SVC", ResourceType.SERVICE_INSTANCE, "search/nodes-query?search-node-type=service-instance&filter=service-instance-name:EQUALS:SRIOV_SVC"},
-                {"b1707vidnf", ResourceType.GENERIC_VNF, "search/nodes-query?search-node-type=generic-vnf&filter=vnf-name:EQUALS:b1707vidnf"},
-                {"connectivity_test", ResourceType.VF_MODULE, "search/nodes-query?search-node-type=vf-module&filter=vf-module-name:EQUALS:connectivity_test"},
-                {"MjVg1234", ResourceType.VOLUME_GROUP, "search/nodes-query?search-node-type=volume-group&filter=volume-group-name:EQUALS:MjVg1234"}
+        return new Object[][] {
+                {"SRIOV_SVC", ResourceType.SERVICE_INSTANCE, "nodes/service-instances?service-instance-name=SRIOV_SVC"},
+                {"b1707vidnf", ResourceType.GENERIC_VNF, "nodes/generic-vnfs?vnf-name=b1707vidnf"},
+                {"connectivity_test", ResourceType.VF_MODULE, "nodes/vf-modules?vf-module-name=connectivity_test"},
+                {"ByronPace", ResourceType.INSTANCE_GROUP, "nodes/instance-groups?instance-group-name=ByronPace"},
+                {"MjVg1234", ResourceType.VOLUME_GROUP, "nodes/volume-groups?volume-group-name=MjVg1234"}
         };
     }
 
     @Test(dataProvider = "nameAndResourceTypeProvider")
     public void whenSearchNodeTypeByName_callRightAaiPath(String name, ResourceType type, String expectedUrl) {
-        when(aaiClientMock.searchNodeTypeByName(any(String.class), any(ResourceType.class))).thenCallRealMethod();
-        aaiClientMock.searchNodeTypeByName(name, type);
-        Mockito.verify(aaiClientMock).doAaiGet(eq(expectedUrl), eq(false));
+        AAIRestInterface aaiRestInterface = mock(AAIRestInterface.class);
+        ResponseWithRequestInfo responseWithRequestInfo = mockedResponseWithRequestInfo(Response.Status.OK, "{}");
+
+        when(aaiRestInterface.RestGet(anyString(), anyString(), eq(toURI(expectedUrl)), anyBoolean(), anyBoolean()))
+                .thenReturn(responseWithRequestInfo);
+
+        AaiClient aaiClient = new AaiClient(aaiRestInterface, null, null);
+
+        aaiClient.isNodeTypeExistsByName(name, type);
     }
 
     @DataProvider
@@ -381,20 +562,20 @@ public class AaiClientTest {
 
                 // Exception out of javax's Client
                 Pair.of(SSLHandshakeException.class, (httpsAuthClientMock, javaxClientMock) -> {
-                    when(javaxClientMock.target(anyString())).thenThrow(
+                    when(javaxClientMock.target(nullable(String.class))).thenThrow(
                             new ProcessingException(new SSLHandshakeException("Received fatal alert: certificate_expired"))
                     );
                 }),
 
                 Pair.of(SunCertPathBuilderException.class, (httpsAuthClientMock, javaxClientMock) -> {
                     SunCertPathBuilderException e0 = new SunCertPathBuilderException("unable to find valid certification path to requested target");
-                    when(javaxClientMock.target(anyString())).thenThrow(
+                    when(javaxClientMock.target(nullable(String.class))).thenThrow(
                             new ProcessingException(new ValidatorException("PKIX path building failed: " + e0.toString(), e0))
                     );
                 }),
 
                 Pair.of(GenericUncheckedException.class, (httpsAuthClientMock, javaxClientMock) ->
-                        when(javaxClientMock.target(anyString())).thenThrow(new GenericUncheckedException("basa")))
+                        when(javaxClientMock.target(nullable(String.class))).thenThrow(new GenericUncheckedException("basa")))
 
         ).flatMap(l -> Stream.of(
                 // double each case to propagateExceptions = true/false, to verify that "don't propagate" really still work
@@ -426,8 +607,8 @@ public class AaiClientTest {
         Response responseMock = mocks.getFakeResponse();
 
         // prepare real AAIRestInterface and AaiClient, and wire mocks
-        AAIRestInterface aaiRestInterface = new AAIRestInterface(httpsAuthClientMock, new ServletRequestHelper(), new SystemPropertyHelper());
-        final AaiClient aaiClient = new AaiClient(aaiRestInterface, null);
+        AAIRestInterface aaiRestInterface = new AAIRestInterface(httpsAuthClientMock, mock(ServletRequestHelper.class), mock(SystemPropertyHelper.class));
+        final AaiClient aaiClient = new AaiClient(aaiRestInterface, null, null);
         when(httpsAuthClientMock.getClient(any())).thenReturn(javaxClientMock);
 
         // define atomic method under test, including reset of "aaiRestInterface.client"
@@ -465,6 +646,121 @@ public class AaiClientTest {
         assertFalse(propagateExceptions, "calling doAaiGet when propagateExceptions is 'true' must result with an exception (in this test)");
     }
 
+    @DataProvider
+    public static Object[][] aaiClientGetCloudOwnerByCloudRegionId() {
+
+        final String cloudRegion = "{" +
+                "      \"cloud-owner\": \"mure-royo-ru22\"," +
+                "      \"cloud-region-id\": \"ravitu\"," +
+                "      \"cloud-type\": \"openstack\"," +
+                "      \"resource-version\": \"1523631256125\"," +
+                "      \"relationship-list\": {" +
+                "        \"relationship\": [{" +
+                "            \"related-to\": \"pserver\"" +
+                "          }" +
+                "        ]" +
+                "      }" +
+                "    }";
+
+        String bodyWith0 = "{  \"cloud-region\": [" + "  ]}";
+        String bodyWith1 = "{  \"cloud-region\": [" + cloudRegion + "  ]}";
+        String bodyWith2 = "{  \"cloud-region\": [" + cloudRegion + ", " + cloudRegion + "  ]}";
+        String bodyWithDifferent2 = "{  \"cloud-region\": [" + cloudRegion + ", " +
+                cloudRegion.replace("mure-royo-ru22", "nolay-umaxo") +
+                "]}";
+
+        return new Object[][] {
+                { "regular single result", bodyWith1, false },
+                { "exceptional empty result", bodyWith0, true },
+                { "two same results", bodyWith2, false },
+                { "two incoherent results", bodyWithDifferent2, true },
+        };
+    }
+
+    @Test(dataProvider = "aaiClientGetCloudOwnerByCloudRegionId")
+    public void getCloudOwnerByCloudRegionIdNonCached(String desc, String body, boolean expectingException) {
+        final String cloudRegion = "ravitu";
+        AAIRestInterface aaiRestInterface = mock(AAIRestInterface.class);
+        final ResponseWithRequestInfo responseWithRequestInfo = mockedResponseWithRequestInfo(Response.Status.OK, body);
+        when(aaiRestInterface.doRest(anyString(), anyString(), eq(Unchecked.toURI("cloud-infrastructure/cloud-regions?cloud-region-id=" + cloudRegion)),
+                isNull(), eq(HttpMethod.GET), anyBoolean(), anyBoolean()))
+                .thenReturn(responseWithRequestInfo);
+
+        final AaiClient aaiClient = new AaiClient(aaiRestInterface, null, null);
+
+        try {
+            final String result = aaiClient.getCloudOwnerByCloudRegionIdNonCached(cloudRegion);
+            if (expectingException) fail("expected failure on " + desc + ", got " + result);
+            else {
+                assertThat(result, is("mure-royo-ru22"));
+            }
+        } catch (Exception e) {
+            if (!expectingException) throw e;
+            else {
+                assertThat(e.toString(), either(
+                        containsString("No cloud-owner found for " + cloudRegion))
+                        .or(containsString("Conflicting cloud-owner found for " + cloudRegion)));
+            }
+        }
+    }
+
+    @DataProvider
+    public static Object[][]  cloudRegionAndTenantDataProvider() {
+        return new Object[][] {
+                { "APPC-24595-T-IST-02C", "mtn23b" },
+                { "APPC-24595-T-IST-02C", null },
+                { null, "mtn23b" },
+                { null, null },
+        };
+    }
+
+    @Test(dataProvider = "cloudRegionAndTenantDataProvider")
+    public void getCloudRegionAndTenantByVnfId(String tenantName, String cloudRegionId) throws JsonProcessingException {
+        SimpleResult tenant = new SimpleResult();
+        if (tenantName != null) {
+            tenant.setJsonNodeType("tenant");
+            Properties tenantProps = new Properties();
+            tenantProps.setTenantName(tenantName);
+            tenant.setJsonProperties(tenantProps);
+        }
+
+        SimpleResult cloudRegion = new SimpleResult();
+        if (cloudRegionId != null) {
+            cloudRegion.setJsonNodeType("cloud-region");
+            Properties cloudRegionProps = new Properties();
+            cloudRegionProps.setCloudRegionId(cloudRegionId);
+            cloudRegion.setJsonProperties(cloudRegionProps);
+        }
+
+        CustomQuerySimpleResult customQuerySimpleResult = new CustomQuerySimpleResult(ImmutableList.of(tenant, cloudRegion));
+        String mockedBody = new ObjectMapper().writeValueAsString(customQuerySimpleResult);
+
+        AAIRestInterface aaiRestInterface = mock(AAIRestInterface.class);
+        final ResponseWithRequestInfo responseWithRequestInfo = mockedResponseWithRequestInfo(Response.Status.OK, mockedBody, "query?format=simple", HttpMethod.PUT);
+        when(aaiRestInterface.doRest(anyString(), anyString(), eq(Unchecked.toURI("query?format=simple")),
+                any(), eq(HttpMethod.PUT), anyBoolean(), anyBoolean()))
+                .thenReturn(responseWithRequestInfo);
+
+        final AaiClient aaiClient = new AaiClient(aaiRestInterface, null, null);
+        Map<String, Properties> result = aaiClient.getCloudRegionAndTenantByVnfId("anyVnfId");
+        if (tenantName != null) {
+            assertEquals(result.get("tenant").getTenantName(), tenantName);
+        } else {
+            assertNull(result.get("tenant"));
+        }
+
+        if (cloudRegionId != null) {
+            assertEquals(result.get("cloud-region").getCloudRegionId(), cloudRegionId);
+        } else {
+            assertNull(result.get("cloud-region"));
+        }
+    }
+
+    protected void mockForGetRequest(AAIRestInterface aaiRestInterface, ResponseWithRequestInfo responseWithRequestInfo) {
+        when(aaiRestInterface.doRest(anyString(), anyString(), any(URI.class), isNull(), eq(HttpMethod.GET) ,anyBoolean(), anyBoolean()))
+                .thenReturn(responseWithRequestInfo);
+    }
+
     @Test
     public void shouldProperlyReadResponseOnceWhenSubscribersAreNotPresent() {
         AAIRestInterface restInterface = mock(AAIRestInterface.class);
@@ -475,8 +771,8 @@ public class AaiClientTest {
         when(response.getStatusInfo()).thenReturn(Response.Status.NOT_FOUND);
         ResponseWithRequestInfo responseWithRequestInfo = new ResponseWithRequestInfo(response, "test", HttpMethod.GET);
         when(restInterface.RestGet(eq("VidAaiController"), any(String.class),
-                eq("business/customers?subscriber-type=INFRA&depth=0"), eq(false), eq(true))).thenReturn(responseWithRequestInfo);
-        AaiClient aaiClient = new AaiClient(restInterface, portDetailsTranslator);
+                eq(Unchecked.toURI("business/customers?subscriber-type=INFRA&depth=0")), eq(false), eq(true))).thenReturn(responseWithRequestInfo);
+        AaiClient aaiClient = new AaiClient(restInterface, portDetailsTranslator, null);
 
 
         aaiClient.getAllSubscribers(true);
@@ -497,4 +793,5 @@ public class AaiClientTest {
 
         void acceptThrows(T t, U u) throws Exception;
     }
+
 }