From 52670a9e0b450074dfbe0d151925d0133bc8442a Mon Sep 17 00:00:00 2001 From: Ittay Stern Date: Sun, 2 Feb 2020 20:04:18 +0200 Subject: Respect owning-entity-id when searching instances by Subscriber Issue-ID: VID-758 Change-Id: Ife6d8679b3ea00d4bb9efb24810b5a50652f5d76 Signed-off-by: Ittay Stern --- .../src/main/java/org/onap/vid/aai/AaiClient.java | 6 +- .../java/org/onap/vid/aai/AaiClientInterface.java | 2 +- .../java/org/onap/vid/aai/ServiceInstance.java | 4 ++ .../vid/model/ServiceInstanceSearchResult.java | 20 ++++++- .../java/org/onap/vid/services/AaiServiceImpl.java | 52 ++++++++++++++++-- .../java/org/onap/vid/services/AaiServiceTest.java | 64 ++++++++++++++++++++-- .../src/test/java/org/onap/vid/api/AaiApiTest.java | 3 +- 7 files changed, 135 insertions(+), 16 deletions(-) diff --git a/vid-app-common/src/main/java/org/onap/vid/aai/AaiClient.java b/vid-app-common/src/main/java/org/onap/vid/aai/AaiClient.java index 159401009..be77e2bc0 100644 --- a/vid-app-common/src/main/java/org/onap/vid/aai/AaiClient.java +++ b/vid-app-common/src/main/java/org/onap/vid/aai/AaiClient.java @@ -528,9 +528,9 @@ public class AaiClient implements AaiClientInterface { } @Override - public AaiResponse getSubscriberData(String subscriberId, boolean omitServiceInstances) { + public AaiResponse getSubscriberData(String subscriberId, boolean omitServiceInstances) { String depth = omitServiceInstances ? "1" : "2"; - AaiResponse subscriberDataResponse; + AaiResponse subscriberDataResponse; Response resp = doAaiGet(BUSINESS_CUSTOMERS_CUSTOMER + subscriberId + "?depth=" + depth, false); subscriberDataResponse = processAaiResponse(resp, Services.class, null); return subscriberDataResponse; @@ -617,7 +617,7 @@ public class AaiClient implements AaiClientInterface { } } - private AaiResponse processAaiResponse(Response resp, Class classType, String responseBody) { + private AaiResponse processAaiResponse(Response resp, Class classType, String responseBody) { return processAaiResponse(resp, classType, responseBody, VidObjectMapperType.CODEHAUS); } diff --git a/vid-app-common/src/main/java/org/onap/vid/aai/AaiClientInterface.java b/vid-app-common/src/main/java/org/onap/vid/aai/AaiClientInterface.java index 2a879e295..5b36828c6 100644 --- a/vid-app-common/src/main/java/org/onap/vid/aai/AaiClientInterface.java +++ b/vid-app-common/src/main/java/org/onap/vid/aai/AaiClientInterface.java @@ -49,7 +49,7 @@ public interface AaiClientInterface extends ProbeInterface { AaiResponse getAllSubscribers(); - AaiResponse getSubscriberData(String subscriberId, boolean omitServiceInstances); + AaiResponse getSubscriberData(String subscriberId, boolean omitServiceInstances); AaiResponse getServices(); diff --git a/vid-app-common/src/main/java/org/onap/vid/aai/ServiceInstance.java b/vid-app-common/src/main/java/org/onap/vid/aai/ServiceInstance.java index bd1a3acf7..a4e7de00c 100644 --- a/vid-app-common/src/main/java/org/onap/vid/aai/ServiceInstance.java +++ b/vid-app-common/src/main/java/org/onap/vid/aai/ServiceInstance.java @@ -22,6 +22,7 @@ package org.onap.vid.aai; import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import com.fasterxml.jackson.annotation.JsonProperty; +import org.onap.vid.aai.model.RelationshipList; @JsonIgnoreProperties(ignoreUnknown = true) public class ServiceInstance { @@ -50,4 +51,7 @@ public class ServiceInstance { @JsonProperty("model-version-id") public String modelVersionId; + @JsonProperty("relationship-list") + public RelationshipList relationshipList; + } diff --git a/vid-app-common/src/main/java/org/onap/vid/model/ServiceInstanceSearchResult.java b/vid-app-common/src/main/java/org/onap/vid/model/ServiceInstanceSearchResult.java index 2665313d7..f75027994 100644 --- a/vid-app-common/src/main/java/org/onap/vid/model/ServiceInstanceSearchResult.java +++ b/vid-app-common/src/main/java/org/onap/vid/model/ServiceInstanceSearchResult.java @@ -22,9 +22,11 @@ package org.onap.vid.model; import com.fasterxml.jackson.annotation.JsonProperty; import org.apache.commons.lang3.StringUtils; +import org.onap.vid.roles.WithPermissionPropertiesOwningEntity; import org.onap.vid.roles.WithPermissionPropertiesSubscriberAndServiceType; -public class ServiceInstanceSearchResult implements WithPermissionPropertiesSubscriberAndServiceType { +public class ServiceInstanceSearchResult + implements WithPermissionPropertiesSubscriberAndServiceType, WithPermissionPropertiesOwningEntity { private final String SUBSCRIBER_ID_FRONTEND_ALIAS = "globalCustomerId"; @@ -42,14 +44,16 @@ public class ServiceInstanceSearchResult implements WithPermissionPropertiesSubs private String aaiModelVersionId; + private String owningEntityId; + private boolean isPermitted; public ServiceInstanceSearchResult(){ } public ServiceInstanceSearchResult(String serviceInstanceId, String subscriberId, String serviceType, - String serviceInstanceName, String subscriberName, String aaiModelInvariantId, - String aaiModelVersionId, boolean isPermitted) { + String serviceInstanceName, String subscriberName, String aaiModelInvariantId, + String aaiModelVersionId, String owningEntityId, boolean isPermitted) { this.serviceInstanceId = serviceInstanceId; this.subscriberId = subscriberId; this.serviceType = serviceType; @@ -57,6 +61,7 @@ public class ServiceInstanceSearchResult implements WithPermissionPropertiesSubs this.subscriberName = subscriberName; this.aaiModelInvariantId = aaiModelInvariantId; this.aaiModelVersionId = aaiModelVersionId; + this.owningEntityId = owningEntityId; this.isPermitted = isPermitted; } @@ -119,6 +124,15 @@ public class ServiceInstanceSearchResult implements WithPermissionPropertiesSubs this.aaiModelVersionId = aaiModelVersionId; } + @Override + public String getOwningEntityId() { + return owningEntityId; + } + + public void setOwningEntityId(String owningEntityId) { + this.owningEntityId = owningEntityId; + } + public boolean getIsPermitted() { return isPermitted; } diff --git a/vid-app-common/src/main/java/org/onap/vid/services/AaiServiceImpl.java b/vid-app-common/src/main/java/org/onap/vid/services/AaiServiceImpl.java index 696aca5ea..9db8233a7 100644 --- a/vid-app-common/src/main/java/org/onap/vid/services/AaiServiceImpl.java +++ b/vid-app-common/src/main/java/org/onap/vid/services/AaiServiceImpl.java @@ -21,6 +21,8 @@ package org.onap.vid.services; +import static java.util.Collections.emptyList; +import static org.apache.commons.collections4.ListUtils.emptyIfNull; import static org.onap.vid.aai.AaiClient.QUERY_FORMAT_RESOURCE; import static org.onap.vid.utils.KotlinUtilsKt.JACKSON_OBJECT_MAPPER; @@ -33,8 +35,10 @@ import java.util.Collections; import java.util.List; import java.util.Map; import java.util.Objects; +import java.util.Optional; import java.util.concurrent.ExecutorService; import java.util.stream.Collectors; +import java.util.stream.Stream; import javax.validation.constraints.NotNull; import javax.ws.rs.core.Response; import org.apache.commons.lang3.StringUtils; @@ -98,6 +102,7 @@ public class AaiServiceImpl implements AaiService { private static final String SERVICE_INSTANCE_ID = "service-instance.service-instance-id"; private static final String SERVICE_TYPE = "service-subscription.service-type"; private static final String CUSTOMER_ID = "customer.global-customer-id"; + private static final String OWNING_ENTITY_ID = "owning-entity.owning-entity-id"; private static final String SERVICE_INSTANCE_NAME = "service-instance.service-instance-name"; private static final String TENANT_NODE_TYPE = "tenant"; private static final String CLOUD_REGION_NODE_TYPE = "cloud-region"; @@ -330,9 +335,11 @@ public class AaiServiceImpl implements AaiService { if (serviceSubscription.serviceInstances != null) { for (ServiceInstance serviceInstance : serviceSubscription.serviceInstances.serviceInstance) { + ServiceInstanceSearchResult serviceInstanceSearchResult = - new ServiceInstanceSearchResult(serviceInstance.serviceInstanceId, subscriberId, serviceType, serviceInstance.serviceInstanceName, - subscriberName, serviceInstance.modelInvariantId, serviceInstance.modelVersionId, false); + new ServiceInstanceSearchResult(serviceInstance.serviceInstanceId, subscriberId, serviceType, + serviceInstance.serviceInstanceName, subscriberName, serviceInstance.modelInvariantId, + serviceInstance.modelVersionId, relatedOwningEntityId(serviceInstance), false); serviceInstanceSearchResult.setIsPermitted(roleValidator.isServicePermitted(serviceInstanceSearchResult)); @@ -345,6 +352,43 @@ public class AaiServiceImpl implements AaiService { return results; } + protected String relatedOwningEntityId(ServiceInstance serviceInstance) { + /* + For reference, consider the service-instance structure below. Method will null-safely extract the + `relationship-value` where `relationship-key` == `owning-entity.owning-entity-id`. + + { + "service-instance-id": "5d521981-33be-4bb5-bb20-5616a9c52a5a", + ... + "relationship-list": { + "relationship": [ + { + "related-to": "owning-entity", + "related-link": "/aai/v11/business/owning-entities/owning-entity/4d4ecf59-41f1-40d4-818d-885234680a42", + "relationship-data": [ + { + "relationship-key": "owning-entity.owning-entity-id", + "relationship-value": "4d4ecf59-41f1-40d4-818d-885234680a42" + } + ] + } + ] + } + } + */ + + Stream allRelationships = + Optional.ofNullable(serviceInstance.relationshipList) + .map(it -> it.getRelationship()) + .map(it -> it.stream().flatMap(r -> emptyIfNull(r.getRelationDataList()).stream())) + .orElse(Stream.empty()); + + return allRelationships + .filter(r -> StringUtils.equals(r.getRelationshipKey(), OWNING_ENTITY_ID)) + .map(it -> it.getRelationshipValue()) + .findAny().orElse(null); + } + private boolean serviceInstanceMatchesIdentifier(String instanceIdentifier, ServiceInstance serviceInstance) { return instanceIdentifier.equals(serviceInstance.serviceInstanceId) || instanceIdentifier.equals(serviceInstance.serviceInstanceName); } @@ -672,7 +716,7 @@ public class AaiServiceImpl implements AaiService { return aaiTree.stream().map(VpnBindingKt::from).collect(Collectors.toList()); } catch (ExceptionWithRequestInfo exception) { if (Objects.equals(404, exception.getHttpCode())) { - return Collections.emptyList(); + return emptyList(); } throw exception; } @@ -688,7 +732,7 @@ public class AaiServiceImpl implements AaiService { return aaiTree.stream().map(Network::from).collect(Collectors.toList()); } catch (ExceptionWithRequestInfo exception) { if (Objects.equals(404, exception.getHttpCode())) { - return Collections.emptyList(); + return emptyList(); } throw exception; } diff --git a/vid-app-common/src/test/java/org/onap/vid/services/AaiServiceTest.java b/vid-app-common/src/test/java/org/onap/vid/services/AaiServiceTest.java index 338657b51..12774f431 100644 --- a/vid-app-common/src/test/java/org/onap/vid/services/AaiServiceTest.java +++ b/vid-app-common/src/test/java/org/onap/vid/services/AaiServiceTest.java @@ -20,22 +20,23 @@ package org.onap.vid.services; +import static org.hamcrest.CoreMatchers.is; import static org.hamcrest.MatcherAssert.assertThat; import static org.hamcrest.Matchers.arrayWithSize; import static org.hamcrest.Matchers.equalTo; -import static org.mockito.ArgumentMatchers.any; +import static org.hamcrest.Matchers.nullValue; import static org.mockito.ArgumentMatchers.anyString; import static org.mockito.ArgumentMatchers.eq; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.when; -import static org.mockito.Mockito.withSettings; import static org.testng.Assert.assertEquals; import static org.testng.Assert.assertNotNull; +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.databind.ObjectMapper; import com.google.common.collect.ImmutableMap; import java.util.ArrayList; import java.util.Arrays; -import java.util.Collections; import java.util.List; import java.util.Map; import org.mockito.InjectMocks; @@ -44,6 +45,7 @@ import org.mockito.Mockito; import org.mockito.MockitoAnnotations; import org.onap.vid.aai.AaiClientInterface; import org.onap.vid.aai.AaiResponse; +import org.onap.vid.aai.ServiceInstance; import org.onap.vid.aai.model.AaiGetPnfResponse; import org.onap.vid.aai.model.AaiGetPnfs.Pnf; import org.onap.vid.aai.model.AaiGetTenatns.GetTenantsResponse; @@ -53,7 +55,6 @@ import org.onap.vid.aai.model.RelationshipData; import org.onap.vid.aai.model.RelationshipList; import org.onap.vid.aai.model.ServiceRelationships; import org.onap.vid.model.aaiTree.AAITreeNode; -import org.onap.vid.roles.Role; import org.onap.vid.roles.RoleValidator; import org.onap.vid.roles.RoleValidatorFactory; import org.testng.annotations.BeforeMethod; @@ -220,4 +221,59 @@ public class AaiServiceTest { assertThat(anyMatch, equalTo(expectedMatch)); } + @DataProvider + public static Object[][] dataToDestroy() { + return new Object[][]{ + {"nothing"}, {"relationship-list"}, {"relationship"}, {"relationship-data"} ,{"owning-entity-id"} + }; + } + + + @Test(dataProvider = "dataToDestroy") + public void relatedOwningEntityId_givenInstanceAndOptionalError_extractCorrectlyOrReturnNull(String dataToDestroy) throws JsonProcessingException { + ServiceInstance serviceInstance = new ObjectMapper().readValue(("" + + "{ " + + " \"service-instance-id\": \"5d521981-33be-4bb5-bb20-5616a9c52a5a\", " + + " \"service-instance-name\": \"dfgh\", " + + " \"service-type\": \"\", " + + " \"service-role\": \"\", " + + " \"environment-context\": \"null\", " + + " \"workload-context\": \"null\", " + + " \"model-invariant-id\": \"331a194d-9248-4533-88bc-62c812ccb5c1\", " + + " \"model-version-id\": \"171b3887-e73e-479d-8ef8-2690bf74f2aa\", " + + " \"resource-version\": \"1508832105498\", " + + " \"orchestration-status\": \"Active\", " + + " \"relationship-list\": { " + + " \"relationship\": [ " + + " { " + + " \"related-to\": \"project\", " + + " \"related-link\": \"/aai/v11/business/projects/project/Kennedy\", " + + " \"relationship-data\": [ " + + " { " + + " \"relationship-key\": \"project.project-name\", " + + " \"relationship-value\": \"Kennedy\" " + + " } " + + " ] " + + " }, " + + " { " + + " \"related-to\": \"owning-entity\", " + + " \"related-link\": \"/aai/v11/business/owning-entities/owning-entity/4d4ecf59-41f1-40d4-818d-885234680a42\", " + + " \"relationship-data\": [ " + + " { " + + " \"relationship-key\": \"owning-entity.owning-entity-id\", " + + " \"relationship-value\": \"4d4ecf59-41f1-40d4-818d-885234680a42\" " + + " } " + + " ] " + + " } " + + " ] " + + " } " + + "}").replace(dataToDestroy, "omitted"), ServiceInstance.class); + + if (dataToDestroy.equals("nothing")) { + assertThat(aaiService.relatedOwningEntityId(serviceInstance), is("4d4ecf59-41f1-40d4-818d-885234680a42")); + } else { + assertThat(aaiService.relatedOwningEntityId(serviceInstance), is(nullValue())); + } + } + } diff --git a/vid-automation/src/test/java/org/onap/vid/api/AaiApiTest.java b/vid-automation/src/test/java/org/onap/vid/api/AaiApiTest.java index e170c450f..ca09d796b 100644 --- a/vid-automation/src/test/java/org/onap/vid/api/AaiApiTest.java +++ b/vid-automation/src/test/java/org/onap/vid/api/AaiApiTest.java @@ -903,7 +903,7 @@ public class AaiApiTest extends BaseApiAaiTest { } @Test - public void searchServiceInstances_serviceInstanceOfAnotherSubscriber_authIsFollwingFeatureToggle() { + public void searchServiceInstances_serviceInstanceOfAnotherSubscriber_authIsFollowingFeatureToggle() { String craigRobertsSubscriberId = "31739f3e-526b-11e6-beb8-9e71128cae77"; String aServiceInstanceId = "4ea864f2-b946-473a-b51c-51a7c10b8391"; String aServiceOwningEntityId = "f160c875-ddd1-4ef5-84d8-d098784daa3a"; @@ -913,6 +913,7 @@ public class AaiApiTest extends BaseApiAaiTest { SimulatorApi.registerExpectation(GET_SUBSCRIBERS_FOR_CUSTOMER_CRAIG_ROBERTS, ImmutableMap.of(aServiceOwningEntityId, currentUserAuthorizedOwningEntityId), CLEAR_THEN_SET); + SimulatorApi.registerExpectationFromPreset(new PresetAAIGetSubscribersGet(), APPEND); JsonNode serviceInstancesResult = restTemplate .getForObject(uri + "/search_service_instances?subscriberId=" + craigRobertsSubscriberId, JsonNode.class); -- cgit 1.2.3-korg