Support deletion of archived services in SDC BE 66/128166/14
authorJvD_Ericsson <jeff.van.dam@est.tech>
Tue, 29 Mar 2022 12:41:35 +0000 (13:41 +0100)
committerVasyl Razinkov <vasyl.razinkov@est.tech>
Mon, 25 Apr 2022 21:55:34 +0000 (21:55 +0000)
Issue-ID: SDC-3936
Change-Id: I75201007c9cf6b71b035f14864e380d78aace12b
Signed-off-by: JvD_Ericsson <jeff.van.dam@est.tech>
13 files changed:
catalog-be/src/main/docker/backend/chef-repo/cookbooks/sdc-catalog-be/files/default/error-configuration.yaml
catalog-be/src/main/java/org/openecomp/sdc/be/components/impl/ServiceBusinessLogic.java
catalog-be/src/main/java/org/openecomp/sdc/be/servlets/ServiceServlet.java
catalog-be/src/test/java/org/openecomp/sdc/be/components/BaseServiceBusinessLogicTest.java
catalog-be/src/test/java/org/openecomp/sdc/be/components/ServiceDistributionBLTest.java
catalog-be/src/test/java/org/openecomp/sdc/be/components/impl/ServiceBusinessLogicBaseTestSetup.java
catalog-be/src/test/java/org/openecomp/sdc/be/components/impl/ServiceBusinessLogicTest.java
catalog-dao/src/main/java/org/openecomp/sdc/be/dao/api/ActionStatus.java
catalog-model/src/main/java/org/openecomp/sdc/be/model/jsonjanusgraph/operations/ToscaElementOperation.java
catalog-model/src/main/java/org/openecomp/sdc/be/model/jsonjanusgraph/operations/ToscaOperationFacade.java
catalog-model/src/main/java/org/openecomp/sdc/be/model/jsonjanusgraph/operations/exception/ToscaOperationExceptionSupplier.java [new file with mode: 0644]
catalog-model/src/main/java/org/openecomp/sdc/be/model/operations/api/StorageOperationStatus.java
catalog-model/src/test/java/org/openecomp/sdc/be/model/jsonjanusgraph/operations/ToscaOperationFacadeTest.java

index 10cc6f6..9e7939d 100644 (file)
@@ -2635,6 +2635,21 @@ errors:
         messageId: "SVC4163"
     }
 
+    #---------SVC4164-----------------------------
+    # %1 - Component name
+    COMPONENT_NOT_ARCHIVED: {
+        code: 403,
+        message: "Component '%1' is not archived",
+        messageId: "SVC4692"
+    }
+
+    #---------SVC4165-----------------------------
+    # %1 - List of services
+    COMPONENT_IN_USE_BY_ANOTHER_COMPONENT: {
+        code: 403,
+        message: "Component is in use by '%1'",
+        messageId: "SVC4693"
+    }
     #---------SVC4164-----------------------------
     # %1 - componentType
     # %2 - component name
index aa011e9..8dac6ff 100644 (file)
@@ -102,6 +102,7 @@ import org.openecomp.sdc.be.datatypes.enums.ComponentTypeEnum;
 import org.openecomp.sdc.be.datatypes.enums.JsonPresentationFields;
 import org.openecomp.sdc.be.datatypes.enums.NodeTypeEnum;
 import org.openecomp.sdc.be.datatypes.enums.OriginTypeEnum;
+import org.openecomp.sdc.be.datatypes.enums.ModelTypeEnum;
 import org.openecomp.sdc.be.externalapi.servlet.representation.ServiceDistributionReqInfo;
 import org.openecomp.sdc.be.impl.ForwardingPathUtils;
 import org.openecomp.sdc.be.impl.WebAppContextWrapper;
@@ -123,6 +124,7 @@ import org.openecomp.sdc.be.model.PropertyDefinition;
 import org.openecomp.sdc.be.model.Resource;
 import org.openecomp.sdc.be.model.Service;
 import org.openecomp.sdc.be.model.User;
+import org.openecomp.sdc.be.model.Model;
 import org.openecomp.sdc.be.model.category.CategoryDefinition;
 import org.openecomp.sdc.be.model.jsonjanusgraph.operations.ArtifactsOperations;
 import org.openecomp.sdc.be.model.jsonjanusgraph.operations.ForwardingPathOperation;
@@ -133,6 +135,7 @@ import org.openecomp.sdc.be.model.operations.api.IGroupOperation;
 import org.openecomp.sdc.be.model.operations.api.IGroupTypeOperation;
 import org.openecomp.sdc.be.model.operations.api.StorageOperationStatus;
 import org.openecomp.sdc.be.model.operations.impl.InterfaceLifecycleOperation;
+import org.openecomp.sdc.be.model.operations.impl.ModelOperation;
 import org.openecomp.sdc.be.model.operations.impl.UniqueIdBuilder;
 import org.openecomp.sdc.be.model.operations.utils.ComponentValidationUtils;
 import org.openecomp.sdc.be.plugins.ServiceCreationPlugin;
@@ -194,6 +197,7 @@ public class ServiceBusinessLogic extends ComponentBusinessLogic {
     private ServiceCategoryValidator serviceCategoryValidator;
     @Autowired
     private ServiceValidator serviceValidator;
+    private final ModelOperation modelOperation;
 
     @Autowired
     public ServiceBusinessLogic(IElementOperation elementDao, IGroupOperation groupOperation, IGroupInstanceOperation groupInstanceOperation,
@@ -205,7 +209,7 @@ public class ServiceBusinessLogic extends ComponentBusinessLogic {
                                 ComponentContactIdValidator componentContactIdValidator, ComponentNameValidator componentNameValidator,
                                 ComponentTagsValidator componentTagsValidator, ComponentValidator componentValidator,
                                 ComponentIconValidator componentIconValidator, ComponentProjectCodeValidator componentProjectCodeValidator,
-                                ComponentDescriptionValidator componentDescriptionValidator) {
+                                ComponentDescriptionValidator componentDescriptionValidator, ModelOperation modelOperation) {
         super(elementDao, groupOperation, groupInstanceOperation, groupTypeOperation, groupBusinessLogic, interfaceOperation,
             interfaceLifecycleTypeOperation, artifactsBusinessLogic, artifactToscaOperation, componentContactIdValidator, componentNameValidator,
             componentTagsValidator, componentValidator, componentIconValidator, componentProjectCodeValidator, componentDescriptionValidator);
@@ -214,6 +218,7 @@ public class ServiceBusinessLogic extends ComponentBusinessLogic {
         this.serviceDistributionValidation = serviceDistributionValidation;
         this.forwardingPathValidator = forwardingPathValidator;
         this.uiComponentDataConverter = uiComponentDataConverter;
+        this.modelOperation = modelOperation;
     }
 
     @Autowired
@@ -1301,7 +1306,39 @@ public class ServiceBusinessLogic extends ComponentBusinessLogic {
         return Either.left(serviceRelations);
     }
 
-    public ResponseFormat deleteService(String serviceId, User user) {
+    public void deleteServiceAllVersions(String serviceId, User user) {
+        validateUserExists(user);
+        Either<Service, StorageOperationStatus> serviceStatus = toscaOperationFacade.getToscaElement(serviceId);
+        if (serviceStatus.isRight()) {
+            log.debug("Failed to get service {}", serviceId);
+            componentException(serviceStatus.right().value());
+        }
+        Service service = serviceStatus.left().value();
+        if (Boolean.FALSE.equals(service.isArchived())) {
+            log.debug("The service, {}, requested for delete has not been archived.", serviceId);
+            throw new ComponentException(ActionStatus.COMPONENT_NOT_ARCHIVED, serviceId);
+        }
+        List<String> deletedServiceList = new ArrayList<>();
+        try {
+            String model = service.getModel();
+            final Optional<Model> modelOptional = modelOperation.findModelByName(model);
+            deletedServiceList = toscaOperationFacade.deleteService(service.getInvariantUUID(), true);
+            if (log.isDebugEnabled()) {
+                deletedServiceList.forEach(deletedS -> log.debug("Component {} was deleted.", deletedS));
+            }
+            if (modelOptional.isPresent() && modelOptional.get().getModelType() == ModelTypeEnum.NORMATIVE_EXTENSION) {
+                modelOperation.deleteModel(modelOptional.get(), false);
+            }
+            toscaOperationFacade.commitAndCheck(service.getUniqueId());
+            updateCatalog(service, ChangeTypeEnum.DELETE);
+        } catch (ComponentException exception) {
+            log.debug("Failed to delete service, {}, in ServiceServlet", serviceId);
+            janusGraphDao.rollback();
+            throw exception;
+        }
+    }
+
+    public ResponseFormat markServiceForDeletion(String serviceId, User user) {
         ResponseFormat responseFormat;
         validateUserExists(user);
         Either<Service, StorageOperationStatus> serviceStatus = toscaOperationFacade.getToscaElement(serviceId);
index bf171c2..bcedc60 100644 (file)
@@ -52,6 +52,7 @@ import javax.ws.rs.POST;
 import javax.ws.rs.PUT;
 import javax.ws.rs.Path;
 import javax.ws.rs.PathParam;
+import javax.ws.rs.QueryParam;
 import javax.ws.rs.Produces;
 import javax.ws.rs.core.Context;
 import javax.ws.rs.core.MediaType;
@@ -109,6 +110,8 @@ public class ServiceServlet extends AbstractValidationsServlet {
     private final ElementBusinessLogic elementBusinessLogic;
     private final ServiceBusinessLogic serviceBusinessLogic;
 
+    public enum Action {DELETE, MARK_AS_DELETE}
+
     @Inject
     public ServiceServlet(UserBusinessLogic userBusinessLogic, ComponentInstanceBusinessLogic componentInstanceBL, ComponentsUtils componentsUtils,
                           ServletUtils servletUtils, ResourceImportManager resourceImportManager, ServiceBusinessLogic serviceBusinessLogic,
@@ -269,7 +272,12 @@ public class ServiceServlet extends AbstractValidationsServlet {
         @ApiResponse(responseCode = "400", description = "Invalid content / Missing content"),
         @ApiResponse(responseCode = "404", description = "Service not found")})
     @PermissionAllowed(AafPermission.PermNames.INTERNAL_ALL_VALUE)
-    public Response deleteService(@PathParam("serviceId") final String serviceId, @Context final HttpServletRequest request) {
+    public Response deleteService(@PathParam("serviceId") final String serviceId,
+                                  @Parameter(description = "Optional parameter to determine the delete action: " +
+                                          "DELETE, which will permanently delete theService from the system or " +
+                                          "MARK_AS_DELETE, which will logically mark the service as deleted. Default action is to MARK_AS_DELETE")
+                                  @QueryParam("deleteAction") final Action deleteAction,
+                                  @Context final HttpServletRequest request) {
         ServletContext context = request.getSession().getServletContext();
         String url = request.getMethod() + " " + request.getRequestURI();
         log.debug(START_HANDLE_REQUEST_OF, url);
@@ -284,7 +292,13 @@ public class ServiceServlet extends AbstractValidationsServlet {
                 .log(LoggerSupportabilityActions.DELETE_SERVICE, StatusCode.STARTED, "Starting to delete service {} by user {} ", serviceIdLower,
                     userId);
             ServiceBusinessLogic businessLogic = getServiceBL(context);
-            ResponseFormat actionResponse = businessLogic.deleteService(serviceIdLower, modifier);
+            ResponseFormat actionResponse;
+            if (Action.DELETE.equals(deleteAction)) {
+                businessLogic.deleteServiceAllVersions(serviceIdLower, modifier);
+                actionResponse = componentsUtils.getResponseFormat(ActionStatus.NO_CONTENT);
+            } else {
+                actionResponse = businessLogic.markServiceForDeletion(serviceIdLower, modifier);
+            }
             if (actionResponse.getStatus() != HttpStatus.SC_NO_CONTENT) {
                 log.debug("failed to delete service");
                 return buildErrorResponse(actionResponse);
index ee37ea1..692e8cc 100644 (file)
@@ -67,6 +67,7 @@ import org.openecomp.sdc.be.model.jsonjanusgraph.operations.ToscaOperationFacade
 import org.openecomp.sdc.be.model.operations.api.IElementOperation;
 import org.openecomp.sdc.be.model.operations.api.StorageOperationStatus;
 import org.openecomp.sdc.be.model.operations.impl.GraphLockOperation;
+import org.openecomp.sdc.be.model.operations.impl.ModelOperation;
 import org.openecomp.sdc.be.resources.data.auditing.ResourceAdminEvent;
 import org.openecomp.sdc.be.user.Role;
 import org.openecomp.sdc.be.user.UserBusinessLogic;
@@ -98,6 +99,7 @@ public abstract class BaseServiceBusinessLogicTest extends ComponentBusinessLogi
     private ToscaOperationFacade toscaOperationFacade = Mockito.mock(ToscaOperationFacade.class);
     private GenericTypeBusinessLogic genericTypeBusinessLogic = Mockito.mock(GenericTypeBusinessLogic.class);
     private ForwardingPathOperation forwardingPathOperation  = Mockito.mock(ForwardingPathOperation.class);
+    private final ModelOperation modelOperation = Mockito.mock(ModelOperation.class);
 
     User user = null;
     Service serviceResponse = null;
@@ -165,7 +167,8 @@ public abstract class BaseServiceBusinessLogicTest extends ComponentBusinessLogi
             artifactsBusinessLogic, distributionEngine, componentInstanceBusinessLogic,
             serviceDistributionValidation, forwardingPathValidator, uiComponentDataConverter,
             artifactToscaOperation, componentContactIdValidator, componentNameValidator,
-            componentTagsValidator, componentValidator, componentIconValidator, componentProjectCodeValidator, componentDescriptionValidator);
+            componentTagsValidator, componentValidator, componentIconValidator, componentProjectCodeValidator, componentDescriptionValidator,
+            modelOperation);
         bl.setUserAdmin(mockUserAdmin);
         bl.setGraphLockOperation(graphLockOperation);
         bl.setJanusGraphDao(mockJanusGraphDao);
index 72cb516..0b3973e 100644 (file)
@@ -53,6 +53,7 @@ import org.openecomp.sdc.be.model.DistributionStatusEnum;
 import org.openecomp.sdc.be.model.Service;
 import org.openecomp.sdc.be.model.User;
 import org.openecomp.sdc.be.model.jsonjanusgraph.operations.ToscaOperationFacade;
+import org.openecomp.sdc.be.model.operations.impl.ModelOperation;
 import org.openecomp.sdc.common.impl.ExternalConfiguration;
 import org.openecomp.sdc.common.util.ThreadLocalsHolder;
 import org.openecomp.sdc.exception.ResponseFormat;
@@ -66,6 +67,7 @@ class ServiceDistributionBLTest extends ComponentBusinessLogicMock {
     private final ComponentInstanceBusinessLogic componentInstanceBusinessLogic = Mockito.mock(ComponentInstanceBusinessLogic.class);
     private final ForwardingPathValidator forwardingPathValidator = Mockito.mock(ForwardingPathValidator.class);
     private final UiComponentDataConverter uiComponentDataConverter = Mockito.mock(UiComponentDataConverter.class);
+    private final ModelOperation modelOperation = Mockito.mock(ModelOperation.class);
 
     @InjectMocks
     private final ServiceBusinessLogic bl = new ServiceBusinessLogic(elementDao, groupOperation, groupInstanceOperation,
@@ -74,7 +76,7 @@ class ServiceDistributionBLTest extends ComponentBusinessLogicMock {
         serviceDistributionValidation, forwardingPathValidator, uiComponentDataConverter,
         artifactToscaOperation, componentContactIdValidator,
         componentNameValidator, componentTagsValidator, componentValidator, componentIconValidator,
-        componentProjectCodeValidator, componentDescriptionValidator);
+        componentProjectCodeValidator, componentDescriptionValidator, modelOperation);
 
     private Service serviceToActivate;
     private ActivationRequestInformation activationRequestInformation;
index 44daa34..5b45851 100644 (file)
@@ -78,6 +78,7 @@ import org.openecomp.sdc.be.model.jsonjanusgraph.operations.ToscaOperationFacade
 import org.openecomp.sdc.be.model.operations.api.IElementOperation;
 import org.openecomp.sdc.be.model.operations.api.StorageOperationStatus;
 import org.openecomp.sdc.be.model.operations.impl.GraphLockOperation;
+import org.openecomp.sdc.be.model.operations.impl.ModelOperation;
 import org.openecomp.sdc.be.resources.data.auditing.DistributionDeployEvent;
 import org.openecomp.sdc.be.resources.data.auditing.DistributionNotificationEvent;
 import org.openecomp.sdc.be.resources.data.auditing.ResourceAdminEvent;
@@ -110,6 +111,7 @@ class ServiceBusinessLogicBaseTestSetup extends BaseBusinessLogicMock {
     protected CatalogOperation catalogOperation = Mockito.mock(CatalogOperation.class);
     protected ResourceAdminEvent auditArchive2 = Mockito.mock(ResourceAdminEvent.class);
     protected ResourceAdminEvent auditRestore = Mockito.mock(ResourceAdminEvent.class);
+    protected ModelOperation modelOperation = Mockito.mock(ModelOperation.class);
     IElementOperation mockElementDao = new ElementOperationMock();
     DistributionEngine distributionEngine =  Mockito.mock(DistributionEngine.class);
     ServiceDistributionValidation serviceDistributionValidation = Mockito.mock(ServiceDistributionValidation.class);
@@ -209,7 +211,7 @@ class ServiceBusinessLogicBaseTestSetup extends BaseBusinessLogicMock {
                 serviceDistributionValidation, forwardingPathValidator, uiComponentDataConverter,
                 artifactToscaOperation, componentContactIdValidator,
                 componentNameValidator, componentTagsValidator, componentValidator,
-                componentIconValidator, componentProjectCodeValidator, componentDescriptionValidator);
+                componentIconValidator, componentProjectCodeValidator, componentDescriptionValidator, modelOperation);
         bl.setComponentContactIdValidator(componentContactIdValidator);
         bl.setComponentIconValidator(componentIconValidator);
         bl.setComponentTagsValidator(componentTagsValidator);
index 5c074b0..69938cd 100644 (file)
@@ -28,6 +28,7 @@ import static org.junit.jupiter.api.Assertions.assertEquals;
 import static org.junit.jupiter.api.Assertions.assertFalse;
 import static org.junit.jupiter.api.Assertions.assertNotNull;
 import static org.junit.jupiter.api.Assertions.assertNull;
+import static org.junit.jupiter.api.Assertions.assertThrows;
 import static org.junit.jupiter.api.Assertions.assertTrue;
 import static org.junit.jupiter.api.Assertions.fail;
 import static org.mockito.Mockito.when;
@@ -41,7 +42,9 @@ import java.util.Arrays;
 import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
+import java.util.Optional;
 import java.util.UUID;
+
 import org.apache.commons.lang3.tuple.ImmutablePair;
 import org.junit.jupiter.api.Test;
 import org.mockito.Mockito;
@@ -51,16 +54,20 @@ import org.openecomp.sdc.be.datatypes.elements.ArtifactDataDefinition;
 import org.openecomp.sdc.be.datatypes.elements.InterfaceInstanceDataDefinition;
 import org.openecomp.sdc.be.datatypes.elements.ListDataDefinition;
 import org.openecomp.sdc.be.datatypes.enums.ComponentTypeEnum;
+import org.openecomp.sdc.be.datatypes.enums.ModelTypeEnum;
 import org.openecomp.sdc.be.model.ArtifactDefinition;
 import org.openecomp.sdc.be.model.Component;
 import org.openecomp.sdc.be.model.ComponentInstance;
 import org.openecomp.sdc.be.model.ComponentInstanceInterface;
 import org.openecomp.sdc.be.model.GroupInstance;
+import org.openecomp.sdc.be.model.Model;
 import org.openecomp.sdc.be.model.Operation;
 import org.openecomp.sdc.be.model.PropertyDefinition;
 import org.openecomp.sdc.be.model.Resource;
 import org.openecomp.sdc.be.model.Service;
 import org.openecomp.sdc.be.model.category.CategoryDefinition;
+import org.openecomp.sdc.be.model.jsonjanusgraph.operations.exception.ToscaOperationException;
+import org.openecomp.sdc.be.model.operations.StorageException;
 import org.openecomp.sdc.be.model.operations.api.StorageOperationStatus;
 import org.openecomp.sdc.be.plugins.ServiceCreationPlugin;
 import org.openecomp.sdc.be.resources.data.auditing.AuditingActionEnum;
@@ -659,6 +666,39 @@ class ServiceBusinessLogicTest extends ServiceBusinessLogicBaseTestSetup {
         assertFalse(resourceIdList.contains(resourceInUse));
     }
 
+    @Test
+    void testDeleteArchivedService_NotFound() {
+        Mockito.when(toscaOperationFacade.getToscaElement(Mockito.anyString())).thenReturn(Either.right(StorageOperationStatus.NOT_FOUND));
+        assertThrows(StorageException.class, () -> bl.deleteServiceAllVersions("1", user));
+    }
+
+    @Test
+    void testDeleteArchivedService_NotArchived() {
+        String serviceId = "12345";
+        Either<Component, StorageOperationStatus> eitherService = Either.left(createNewService());
+        eitherService.left().value().setArchived(false);
+        Mockito.when(toscaOperationFacade.getToscaElement(Mockito.anyString())).thenReturn(eitherService);
+        final ComponentException actualException = assertThrows(ComponentException.class, () -> bl.deleteServiceAllVersions(serviceId, user));
+        assertEquals(actualException.getActionStatus(), ActionStatus.COMPONENT_NOT_ARCHIVED);
+        assertEquals(actualException.getParams()[0], serviceId);
+    }
+
+    @Test
+    void testDeleteArchivedService_DeleteServiceSpecificModel() throws ToscaOperationException {
+        String serviceId = "12345";
+        String model = "serviceSpecificModel";
+        List<String> deletedServcies= new ArrayList<>();
+        deletedServcies.add("54321");
+        Model normativeExtensionModel = new Model("normativeExtensionModel", ModelTypeEnum.NORMATIVE_EXTENSION);
+        Either<Component, StorageOperationStatus> eitherService = Either.left(createNewService());
+        eitherService.left().value().setArchived(true);
+        eitherService.left().value().setModel(model);
+        Mockito.when(toscaOperationFacade.getToscaElement(Mockito.anyString())).thenReturn(eitherService);
+        Mockito.when(toscaOperationFacade.deleteService(Mockito.anyString(), Mockito.eq(true))).thenReturn(deletedServcies);
+        Mockito.when(modelOperation.findModelByName(model)).thenReturn(Optional.of(normativeExtensionModel));
+        bl.deleteServiceAllVersions(serviceId, user);
+        Mockito.verify(modelOperation, Mockito.times(1)).deleteModel(normativeExtensionModel, false);
+    }
 
     @SuppressWarnings({ "unchecked", "rawtypes" })
     @Test
index 922853e..3b5c995 100644 (file)
@@ -62,7 +62,7 @@ public enum ActionStatus {
     // Attribute related
     ATTRIBUTE_ALREADY_EXIST, ATTRIBUTE_NOT_FOUND, INVALID_ATTRIBUTE,
     // State related
-    INVALID_SERVICE_STATE, COMPONENT_IN_CHECKOUT_STATE, ILLEGAL_COMPONENT_STATE, COMPONENT_IN_CERT_IN_PROGRESS_STATE, COMPONENT_SENT_FOR_CERTIFICATION, COMPONENT_VERSION_ALREADY_EXIST, COMPONENT_ALREADY_CHECKED_IN, COMPONENT_CHECKOUT_BY_ANOTHER_USER, COMPONENT_IN_USE, COMPONENT_HAS_NEWER_VERSION, COMPONENT_ALREADY_CERTIFIED, COMPONENT_NOT_READY_FOR_CERTIFICATION, COMPONENT_ARTIFACT_NOT_FOUND, COMPONENT_INSTANCE_NOT_FOUND, COMPONENT_INSTANCE_NOT_FOUND_ON_CONTAINER, SERVICE_NOT_FOUND, SERVICE_CATEGORY_CANNOT_BE_CHANGED, SERVICE_NAME_CANNOT_BE_CHANGED, SERVICE_ICON_CANNOT_BE_CHANGED, COMPONENT_TOO_MUCH_CATEGORIES, SERVICE_CANNOT_CONTAIN_SUBCATEGORY, RESOURCE_CATEGORY_CANNOT_BE_CHANGED, RESOURCE_NAME_CANNOT_BE_CHANGED, RESOURCE_ICON_CANNOT_BE_CHANGED, RESOURCE_VENDOR_NAME_CANNOT_BE_CHANGED, RESOURCE_TOO_MUCH_SUBCATEGORIES, SERVICE_ICON_EXCEEDS_LIMIT, RESOURCE_INSTANCE_NOT_FOUND, RESOURCE_INSTANCE_BAD_REQUEST, RESOURCE_INSTANCE_MATCH_NOT_FOUND, RESOURCE_INSTANCE_ALREADY_EXIST, RESOURCE_INSTANCE_RELATION_NOT_FOUND, COMPONENT_MISSING_SUBCATEGORY, COMPONENT_INVALID_SUBCATEGORY, ARTIFACT_TYPE_NOT_SUPPORTED, MISSING_ARTIFACT_TYPE, ARTIFACT_LOGICAL_NAME_CANNOT_BE_CHANGED, ARTIFACT_EXIST, ARTIFACT_NOT_FOUND, ARTIFACT_INVALID_MD5, MISSING_ARTIFACT_NAME, MISSING_PROJECT_CODE, INVALID_PROJECT_CODE, COMPONENT_MISSING_MANDATORY_ARTIFACTS, LIFECYCLE_TYPE_ALREADY_EXIST, SERVICE_NOT_AVAILABLE_FOR_DISTRIBUTION, MISSING_LIFECYCLE_TYPE, RESOURCE_VFCMT_LIFECYCLE_STATE_NOT_VALID,
+    INVALID_SERVICE_STATE, COMPONENT_IN_CHECKOUT_STATE, ILLEGAL_COMPONENT_STATE, COMPONENT_IN_CERT_IN_PROGRESS_STATE, COMPONENT_SENT_FOR_CERTIFICATION, COMPONENT_VERSION_ALREADY_EXIST, COMPONENT_ALREADY_CHECKED_IN, COMPONENT_CHECKOUT_BY_ANOTHER_USER, COMPONENT_IN_USE, COMPONENT_IN_USE_BY_ANOTHER_COMPONENT, COMPONENT_HAS_NEWER_VERSION, COMPONENT_ALREADY_CERTIFIED, COMPONENT_NOT_READY_FOR_CERTIFICATION, COMPONENT_ARTIFACT_NOT_FOUND, COMPONENT_INSTANCE_NOT_FOUND, COMPONENT_INSTANCE_NOT_FOUND_ON_CONTAINER, SERVICE_NOT_FOUND, SERVICE_CATEGORY_CANNOT_BE_CHANGED, SERVICE_NAME_CANNOT_BE_CHANGED, SERVICE_ICON_CANNOT_BE_CHANGED, COMPONENT_TOO_MUCH_CATEGORIES, SERVICE_CANNOT_CONTAIN_SUBCATEGORY, RESOURCE_CATEGORY_CANNOT_BE_CHANGED, RESOURCE_NAME_CANNOT_BE_CHANGED, RESOURCE_ICON_CANNOT_BE_CHANGED, RESOURCE_VENDOR_NAME_CANNOT_BE_CHANGED, RESOURCE_TOO_MUCH_SUBCATEGORIES, SERVICE_ICON_EXCEEDS_LIMIT, RESOURCE_INSTANCE_NOT_FOUND, RESOURCE_INSTANCE_BAD_REQUEST, RESOURCE_INSTANCE_MATCH_NOT_FOUND, RESOURCE_INSTANCE_ALREADY_EXIST, RESOURCE_INSTANCE_RELATION_NOT_FOUND, COMPONENT_MISSING_SUBCATEGORY, COMPONENT_INVALID_SUBCATEGORY, ARTIFACT_TYPE_NOT_SUPPORTED, MISSING_ARTIFACT_TYPE, ARTIFACT_LOGICAL_NAME_CANNOT_BE_CHANGED, ARTIFACT_EXIST, ARTIFACT_NOT_FOUND, ARTIFACT_INVALID_MD5, MISSING_ARTIFACT_NAME, MISSING_PROJECT_CODE, INVALID_PROJECT_CODE, COMPONENT_MISSING_MANDATORY_ARTIFACTS, LIFECYCLE_TYPE_ALREADY_EXIST, SERVICE_NOT_AVAILABLE_FOR_DISTRIBUTION, MISSING_LIFECYCLE_TYPE, RESOURCE_VFCMT_LIFECYCLE_STATE_NOT_VALID,
     // Distribution
     BAD_REQUEST_MISSING_RESOURCE, MISSING_USER_ID, MISSING_X_ECOMP_INSTANCE_ID, MISSING_PUBLIC_KEY, MISSING_ENV_NAME, DISTRIBUTION_ENV_DOES_NOT_EXIST, MISSING_BODY, ECOMP_RESEND_WITH_BASIC_AUTHENTICATION_CREDENTIALS, ECOMP_COMPONENT_NOT_AUTHORIZED, METHOD_NOT_ALLOWED_TO_DOWNLOAD_ARTIFACT, REGISTRATION_FAILED, DISTRIBUTION_ENVIRONMENT_NOT_AVAILABLE, DISTRIBUTION_ENVIRONMENT_NOT_FOUND, DISTRIBUTION_ENVIRONMENT_INVALID, DISTRIBUTION_REQUESTED_NOT_FOUND, DISTRIBUTION_REQUESTED_FAILED, DISTRIBUTION_NOT_FOUND, ADDITIONAL_INFORMATION_ALREADY_EXISTS, COMPONENT_VERSION_NOT_FOUND, ADDITIONAL_INFORMATION_MAX_NUMBER_REACHED, ADDITIONAL_INFORMATION_EMPTY_STRING_NOT_ALLOWED, ADDITIONAL_INFORMATION_EXCEEDS_LIMIT, ADDITIONAL_INFORMATION_KEY_NOT_ALLOWED_CHARACTERS, ADDITIONAL_INFORMATION_VALUE_NOT_ALLOWED_CHARACTERS, ADDITIONAL_INFORMATION_NOT_FOUND, ASDC_VERSION_NOT_FOUND, MISSING_DATA, EXCEEDS_LIMIT, UNSUPPORTED_ERROR, ARTIFACT_INVALID_TIMEOUT, SERVICE_IS_VNF_CANNOT_BE_CHANGED, RESOURCE_INSTANCE_NOT_FOUND_ON_SERVICE, WRONG_ARTIFACT_FILE_EXTENSION, INVALID_YAML, INVALID_XML, INVALID_JSON, INVALID_DEPLOYMENT_ARTIFACT_HEAT, INVALID_HEAT_PARAMETER_TYPE, INVALID_HEAT_PARAMETER_VALUE, DEPLOYMENT_ARTIFACT_OF_TYPE_ALREADY_EXISTS, DEPLOYMENT_ARTIFACT_NAME_ALREADY_EXISTS, MISSING_HEAT, MISMATCH_HEAT_VS_HEAT_ENV, CORRUPTED_FORMAT, MISMATCH_BETWEEN_ARTIFACT_TYPE_AND_COMPONENT_TYPE, INVALID_PARAMS_IN_HEAT_ENV_FILE, API_RESOURCE_NOT_FOUND,
     //UEB
@@ -100,7 +100,7 @@ public enum ActionStatus {
     //policies
     RESOURCE_CANNOT_CONTAIN_POLICIES, POLICY_NOT_FOUND_ON_CONTAINER, INVALID_POLICY_NAME, POLICY_NAME_ALREADY_EXIST, EXCLUDED_POLICY_TYPE, POLICY_MISSING_POLICY_TYPE, POLICY_TYPE_IS_INVALID,
     //External References Statuses
-    EXT_REF_ALREADY_EXIST, EXT_REF_NOT_FOUND, POLICY_TARGET_DOES_NOT_EXIST, POLICY_TARGET_TYPE_DOES_NOT_EXIST, INPUTS_NOT_FOUND, RESOURCE_LIFECYCLE_STATE_NOT_VALID, COMPONENT_IS_ARCHIVED,
+    EXT_REF_ALREADY_EXIST, EXT_REF_NOT_FOUND, POLICY_TARGET_DOES_NOT_EXIST, POLICY_TARGET_TYPE_DOES_NOT_EXIST, INPUTS_NOT_FOUND, RESOURCE_LIFECYCLE_STATE_NOT_VALID, COMPONENT_IS_ARCHIVED, COMPONENT_NOT_ARCHIVED,
     //Automated upgrade
     COMPONENT_IS_NOT_HIHGEST_CERTIFIED, NO_INSTANCES_TO_UPGRADE, ARCHIVED_ORIGINS_FOUND, UPDATE_CATALOG_FAILED,
     //Interface
index 9e9b944..caedbee 100644 (file)
@@ -150,6 +150,17 @@ public abstract class ToscaElementOperation extends BaseOperation {
         return Either.left(vertexG);
     }
 
+    protected GraphVertex getHighestVersionFrom(GraphVertex v) {
+        Either<GraphVertex, JanusGraphOperationStatus> childVertexE = janusGraphDao
+                .getChildVertex(v, EdgeLabelEnum.VERSION, JsonParseFlagEnum.NoParse);
+        GraphVertex highestVersionVertex = v;
+        while (childVertexE.isLeft()) {
+            highestVersionVertex = childVertexE.left().value();
+            childVertexE = janusGraphDao.getChildVertex(highestVersionVertex, EdgeLabelEnum.VERSION, JsonParseFlagEnum.NoParse);
+        }
+        return highestVersionVertex;
+    }
+
     public Either<ToscaElement, StorageOperationStatus> getToscaElement(String uniqueId) {
         return getToscaElement(uniqueId, new ComponentParametersView());
     }
index 496fd0f..0546a91 100644 (file)
@@ -31,6 +31,7 @@ import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.Collection;
 import java.util.Collections;
+import java.util.Comparator;
 import java.util.EnumMap;
 import java.util.HashMap;
 import java.util.HashSet;
@@ -42,6 +43,7 @@ import java.util.Map.Entry;
 import java.util.Objects;
 import java.util.Optional;
 import java.util.Set;
+import java.util.TreeSet;
 import java.util.function.BiPredicate;
 import java.util.stream.Collectors;
 import org.apache.commons.collections.CollectionUtils;
@@ -79,6 +81,7 @@ import org.openecomp.sdc.be.datatypes.elements.RequirementDataDefinition;
 import org.openecomp.sdc.be.datatypes.enums.ComponentTypeEnum;
 import org.openecomp.sdc.be.datatypes.enums.GraphPropertyEnum;
 import org.openecomp.sdc.be.datatypes.enums.JsonPresentationFields;
+import org.openecomp.sdc.be.datatypes.enums.NodeTypeEnum;
 import org.openecomp.sdc.be.datatypes.enums.OriginTypeEnum;
 import org.openecomp.sdc.be.datatypes.enums.PromoteVersionEnum;
 import org.openecomp.sdc.be.datatypes.enums.ResourceTypeEnum;
@@ -114,8 +117,11 @@ import org.openecomp.sdc.be.model.catalog.CatalogComponent;
 import org.openecomp.sdc.be.model.jsonjanusgraph.config.ContainerInstanceTypesData;
 import org.openecomp.sdc.be.model.jsonjanusgraph.datamodel.TopologyTemplate;
 import org.openecomp.sdc.be.model.jsonjanusgraph.datamodel.ToscaElement;
+import org.openecomp.sdc.be.model.jsonjanusgraph.datamodel.ToscaElementTypeEnum;
+import org.openecomp.sdc.be.model.jsonjanusgraph.operations.exception.ToscaOperationExceptionSupplier;
 import org.openecomp.sdc.be.model.jsonjanusgraph.utils.ModelConverter;
 import org.openecomp.sdc.be.model.operations.StorageException;
+import org.openecomp.sdc.be.model.operations.api.IGraphLockOperation;
 import org.openecomp.sdc.be.model.operations.api.StorageOperationStatus;
 import org.openecomp.sdc.be.model.operations.impl.DaoStatusConverter;
 import org.openecomp.sdc.be.model.operations.impl.UniqueIdBuilder;
@@ -144,6 +150,8 @@ public class ToscaOperationFacade {
     private static final String COULDNT_FETCH_COMPONENT_WITH_AND_UNIQUE_ID_ERROR = "Couldn't fetch component with and unique id {}, error: {}";
     private static final Logger log = Logger.getLogger(ToscaOperationFacade.class.getName());
     @Autowired
+    private IGraphLockOperation graphLockOperation;
+    @Autowired
     private NodeTypeOperation nodeTypeOperation;
     @Autowired
     private TopologyTemplateOperation topologyTemplateOperation;
@@ -992,21 +1000,122 @@ public class ToscaOperationFacade {
         return Either.left(checkIfInUseAndDelete(allMarked));
     }
 
-    private List<String> checkIfInUseAndDelete(List<GraphVertex> allMarked) {
+    public List<String> deleteService(String invariantUUID, final boolean inTransaction) {
+        List<GraphVertex> allServiceVerticesToDelete = getVerticesForAllVersions(invariantUUID, ToscaElementTypeEnum.TOPOLOGY_TEMPLATE);
+        List<String> affectedComponentIds = new ArrayList<>();
+        try {
+            checkNotUsed( allServiceVerticesToDelete);
+            lockAllVerticesByNodeType(allServiceVerticesToDelete, NodeTypeEnum.Service);
+            for (GraphVertex elementV : allServiceVerticesToDelete) {
+                Either<ToscaElement, StorageOperationStatus> deleteToscaElement = deleteToscaElement(elementV);
+                if (deleteToscaElement.isRight()) {
+                    log.debug("Failed to delete element UniqueID {}, Name {}, error {}", elementV.getUniqueId(),
+                        elementV.getMetadataProperties().get(GraphPropertyEnum.NAME), deleteToscaElement.right().value());
+                    throwStorageException(deleteToscaElement.right().value());
+                }
+                affectedComponentIds.add(elementV.getUniqueId());
+            }
+            if (!inTransaction) {
+                janusGraphDao.commit();
+            }
+        } catch (Exception exception) {
+            if (!inTransaction) {
+                janusGraphDao.rollback();
+            }
+            throw exception;
+        } finally {
+            unlockAllVerticesByNodeType(allServiceVerticesToDelete, NodeTypeEnum.Service);
+        }
+        return affectedComponentIds;
+    }
+
+    private void checkNotUsed(List<GraphVertex> vertices) {
+        boolean isInUse = isAnyComponentInUse(vertices);
+        if (isInUse) {
+            Set<GraphVertex> listOfVertices =  getComponentsUsingComponents(vertices);
+            List<String> listOfStringComponents = new ArrayList<>();
+            for (GraphVertex componentVertex : listOfVertices) {
+                listOfStringComponents.add(
+                        componentVertex.getMetadataJson().get(GraphPropertyEnum.COMPONENT_TYPE.getProperty()) + " "
+                                + componentVertex.getMetadataJson().get(GraphPropertyEnum.NAME.getProperty())
+                );
+            }
+            String stringOfComponents = String.join(", ", listOfStringComponents);
+            throw ToscaOperationExceptionSupplier.componentInUse(stringOfComponents).get();
+        }
+    }
+
+    private List<GraphVertex> getVerticesForAllVersions(String invariantUUID, ToscaElementTypeEnum componentType){
+        Either<List<Component>, StorageOperationStatus> allComponents =
+                getComponentListByInvariantUuid(invariantUUID, null);
+        if (allComponents.isRight()) {
+            throwStorageException(allComponents.right().value());
+        }
+        List<GraphVertex> allComponentVertices = new ArrayList<>();
+        for (Component component : allComponents.left().value()) {
+            Either<GraphVertex, StorageOperationStatus> componentGraphVertex = topologyTemplateOperation
+                    .getComponentByLabelAndId(component.getUniqueId(), componentType, JsonParseFlagEnum.ParseAll);
+            if (componentGraphVertex.isRight()) {
+                throwStorageException(componentGraphVertex.right().value());
+            }
+            allComponentVertices.add(componentGraphVertex.left().value());
+        }
+        return allComponentVertices;
+    }
+
+    public void commitAndCheck(String componentId) {
+        JanusGraphOperationStatus status = janusGraphDao.commit();
+        if (!status.equals(JanusGraphOperationStatus.OK)) {
+            log.debug("error occurred when trying to DELETE {}. Return code is: {}", componentId, status);
+            throwStorageException(DaoStatusConverter.convertJanusGraphStatusToStorageStatus(status));
+        }
+    }
+
+    private Set<GraphVertex> getComponentsUsingComponents(List<GraphVertex> componentVertices) {
+        Set<GraphVertex> inUseBy = new TreeSet<>(Comparator.comparing(GraphVertex::getUniqueId));
+        for (final GraphVertex elementV : componentVertices) {
+            List<GraphVertex> inUseByVertex = isInUse(elementV);
+            if (!inUseByVertex.isEmpty()) {
+                inUseBy.addAll(inUseByVertex);
+            }
+        }
+        return inUseBy;
+    }
+
+    private boolean isAnyComponentInUse(List<GraphVertex> componentVertices) {
+        boolean isComponentInUse = false;
+        if (log.isDebugEnabled()) {
+            for (final GraphVertex graphVertex : componentVertices) {
+                if (!isInUse(graphVertex).isEmpty()) {
+                    isComponentInUse = true;
+                }
+            }
+        } else {
+            isComponentInUse = componentVertices.stream().anyMatch(vertex -> !isInUse(vertex).isEmpty());
+        }
+        return isComponentInUse;
+    }
+
+    private List<GraphVertex> isInUse(GraphVertex elementV) {
         final List<EdgeLabelEnum> forbiddenEdgeLabelEnums = Arrays
-            .asList(EdgeLabelEnum.INSTANCE_OF, EdgeLabelEnum.PROXY_OF, EdgeLabelEnum.ALLOTTED_OF);
-        List<String> deleted = new ArrayList<>();
-        for (GraphVertex elementV : allMarked) {
-            boolean isAllowedToDelete = true;
-            for (EdgeLabelEnum edgeLabelEnum : forbiddenEdgeLabelEnums) {
-                Either<Edge, JanusGraphOperationStatus> belongingEdgeByCriteria = janusGraphDao
-                    .getBelongingEdgeByCriteria(elementV, edgeLabelEnum, null);
-                if (belongingEdgeByCriteria.isLeft()) {
-                    log.debug("Marked element {} in use. don't delete it", elementV.getUniqueId());
-                    isAllowedToDelete = false;
-                    break;
+                .asList(EdgeLabelEnum.INSTANCE_OF, EdgeLabelEnum.PROXY_OF, EdgeLabelEnum.ALLOTTED_OF);
+        for (EdgeLabelEnum edgeLabelEnum : forbiddenEdgeLabelEnums) {
+            Either<List<GraphVertex>, JanusGraphOperationStatus> inUseBy =
+                    janusGraphDao.getParentVertices(elementV, edgeLabelEnum, JsonParseFlagEnum.ParseAll);
+            if (inUseBy.isLeft()) {
+                if (log.isDebugEnabled()) {
+                    log.debug("Element {} in use.", elementV.getUniqueId());
                 }
+                return inUseBy.left().value();
             }
+        }
+        return Collections.emptyList();
+    }
+
+    private List<String> checkIfInUseAndDelete(List<GraphVertex> allMarked) {
+        List<String> deleted = new ArrayList<>();
+        for (GraphVertex elementV : allMarked) {
+            boolean isAllowedToDelete = !isInUse(elementV).isEmpty();
             if (isAllowedToDelete) {
                 Either<ToscaElement, StorageOperationStatus> deleteToscaElement = deleteToscaElement(elementV);
                 if (deleteToscaElement.isRight()) {
@@ -1020,6 +1129,21 @@ public class ToscaOperationFacade {
         return deleted;
     }
 
+    private void lockAllVerticesByNodeType(List<GraphVertex> allVerticesToLock, NodeTypeEnum nodeType) {
+        for (GraphVertex graphVertex : allVerticesToLock) {
+            StorageOperationStatus storageOperationStatus = graphLockOperation.lockComponent(graphVertex.getUniqueId(), nodeType);
+            if (!storageOperationStatus.equals(StorageOperationStatus.OK)) {
+                throwStorageException(storageOperationStatus);
+            }
+        }
+    }
+
+    private void unlockAllVerticesByNodeType(List<GraphVertex> allVerticesToUnlock, NodeTypeEnum nodeType) {
+        for (GraphVertex graphVertex : allVerticesToUnlock) {
+            graphLockOperation.unlockComponent(graphVertex.getUniqueId(), nodeType);
+        }
+    }
+
     public Either<List<String>, StorageOperationStatus> getAllComponentsMarkedForDeletion(ComponentTypeEnum componentType) {
         Either<List<GraphVertex>, StorageOperationStatus> allComponentsMarkedForDeletion;
         switch (componentType) {
diff --git a/catalog-model/src/main/java/org/openecomp/sdc/be/model/jsonjanusgraph/operations/exception/ToscaOperationExceptionSupplier.java b/catalog-model/src/main/java/org/openecomp/sdc/be/model/jsonjanusgraph/operations/exception/ToscaOperationExceptionSupplier.java
new file mode 100644 (file)
index 0000000..62d7e29
--- /dev/null
@@ -0,0 +1,37 @@
+/*
+ * ============LICENSE_START=======================================================
+ *  Copyright (C) 2021 Nordix Foundation
+ *  ================================================================================
+ *  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.
+ *
+ *  SPDX-License-Identifier: Apache-2.0
+ *  ============LICENSE_END=========================================================
+ */
+
+package org.openecomp.sdc.be.model.jsonjanusgraph.operations.exception;
+
+import java.util.function.Supplier;
+import org.openecomp.sdc.be.dao.api.ActionStatus;
+import org.openecomp.sdc.be.dao.janusgraph.JanusGraphOperationStatus;
+import org.openecomp.sdc.be.model.operations.api.StorageOperationStatus;
+
+public class ToscaOperationExceptionSupplier {
+
+    private ToscaOperationExceptionSupplier() {
+
+    }
+
+    public static Supplier<OperationException> componentInUse(final String stringOfServices) {
+        return () -> new OperationException(ActionStatus.COMPONENT_IN_USE_BY_ANOTHER_COMPONENT, stringOfServices);
+    }
+
+}
index 4fbb5fb..4916030 100644 (file)
@@ -64,6 +64,8 @@ public enum StorageOperationStatus {
     PROPERTY_NAME_ALREADY_EXISTS,
     INVALID_PROPERTY,
     COMPONENT_IS_ARCHIVED,
+    COMPONENT_NOT_ARCHIVED,
+    COMPONENT_IN_USE_BY_ANOTHER_COMPONENT,
     DECLARED_INPUT_USED_BY_OPERATION;
     // @formatter:on
 
index c0c417a..625ec39 100644 (file)
@@ -36,6 +36,7 @@ import static org.junit.Assert.assertNotNull;
 import static org.junit.Assert.assertNull;
 import static org.junit.Assert.assertSame;
 import static org.junit.Assert.assertTrue;
+import static org.junit.jupiter.api.Assertions.assertThrows;
 import static org.mockito.ArgumentMatchers.any;
 import static org.mockito.ArgumentMatchers.anyInt;
 import static org.mockito.ArgumentMatchers.anyMap;
@@ -70,6 +71,8 @@ import org.mockito.Mock;
 import org.mockito.Mockito;
 import org.mockito.MockitoAnnotations;
 import org.mockito.junit.MockitoJUnitRunner;
+import org.openecomp.sdc.be.config.ComponentType;
+import org.openecomp.sdc.be.dao.api.ActionStatus;
 import org.openecomp.sdc.be.dao.janusgraph.JanusGraphOperationStatus;
 import org.openecomp.sdc.be.dao.jsongraph.GraphVertex;
 import org.openecomp.sdc.be.dao.janusgraph.HealingJanusGraphDao;
@@ -84,6 +87,7 @@ import org.openecomp.sdc.be.datatypes.elements.RequirementDataDefinition;
 import org.openecomp.sdc.be.datatypes.enums.ComponentTypeEnum;
 import org.openecomp.sdc.be.datatypes.enums.GraphPropertyEnum;
 import org.openecomp.sdc.be.datatypes.enums.JsonPresentationFields;
+import org.openecomp.sdc.be.datatypes.enums.NodeTypeEnum;
 import org.openecomp.sdc.be.datatypes.enums.OriginTypeEnum;
 import org.openecomp.sdc.be.datatypes.enums.PromoteVersionEnum;
 import org.openecomp.sdc.be.datatypes.enums.ResourceTypeEnum;
@@ -106,7 +110,10 @@ import org.openecomp.sdc.be.model.jsonjanusgraph.datamodel.NodeType;
 import org.openecomp.sdc.be.model.jsonjanusgraph.datamodel.TopologyTemplate;
 import org.openecomp.sdc.be.model.jsonjanusgraph.datamodel.ToscaElement;
 import org.openecomp.sdc.be.model.jsonjanusgraph.datamodel.ToscaElementTypeEnum;
+import org.openecomp.sdc.be.model.jsonjanusgraph.operations.exception.OperationException;
 import org.openecomp.sdc.be.model.jsonjanusgraph.utils.ModelConverter;
+import org.openecomp.sdc.be.model.operations.StorageException;
+import org.openecomp.sdc.be.model.operations.api.IGraphLockOperation;
 import org.openecomp.sdc.be.model.operations.api.StorageOperationStatus;
 
 @RunWith(MockitoJUnitRunner.class)
@@ -137,6 +144,9 @@ public class ToscaOperationFacadeTest {
     @Mock
     private NodeTemplateOperation nodeTemplateOperationMock;
 
+    @Mock
+    private IGraphLockOperation graphLockOperationMock;
+
     @Before
     public void setUp() throws Exception {
         testInstance = new ToscaOperationFacade();
@@ -407,6 +417,153 @@ public class ToscaOperationFacadeTest {
         assertTrue(result.isLeft());
     }
 
+    @Test
+    public void testDeleteService_ServiceInUse() {
+        String invariantUUID = "12345";
+        String serviceUid = "1";
+        GraphVertex service1 = getTopologyTemplateVertex();
+        service1.setUniqueId(serviceUid);
+        List<GraphVertex> allResourcesToDelete = new ArrayList<>();
+        allResourcesToDelete.add(service1);
+        Map<GraphPropertyEnum, Object> propertiesToMatch = new EnumMap<>(GraphPropertyEnum.class);
+        propertiesToMatch.put(GraphPropertyEnum.INVARIANT_UUID, invariantUUID);
+        ToscaElement toscaElement = getToscaElementForTest();
+        toscaElement.setUniqueId(serviceUid);
+        String service2Name = "service2Name";
+        Map<String, Object> service2MetadataJson = new HashMap<>();
+        service2MetadataJson.put(GraphPropertyEnum.COMPONENT_TYPE.getProperty(), ComponentType.SERVICE);
+        service2MetadataJson.put(GraphPropertyEnum.NAME.getProperty(), service2Name);
+        String service2Uid = "2";
+        GraphVertex usingService = getTopologyTemplateVertex();
+        usingService.setUniqueId(service2Uid);
+        usingService.setMetadataJson(service2MetadataJson);
+        List<GraphVertex> inUseBy = new ArrayList<>();
+        inUseBy.add(usingService);
+
+        when(janusGraphDaoMock.getByCriteria(null, propertiesToMatch, JsonParseFlagEnum.ParseMetadata)).
+                thenReturn(Either.left(allResourcesToDelete));
+        doReturn(Either.left(toscaElement)).when(topologyTemplateOperationMock).getToscaElement(eq(service1), any(ComponentParametersView.class));
+        when(topologyTemplateOperationMock.
+                getComponentByLabelAndId(serviceUid, ToscaElementTypeEnum.TOPOLOGY_TEMPLATE, JsonParseFlagEnum.ParseAll)).
+                thenReturn(Either.left(service1));
+        when(janusGraphDaoMock.getParentVertices(any(GraphVertex.class), any(), eq(JsonParseFlagEnum.ParseAll))).
+                thenReturn(Either.left(inUseBy)).thenReturn(Either.left(inUseBy));
+        final OperationException actualException = assertThrows(OperationException.class, () -> testInstance.deleteService(invariantUUID, true));
+        assertEquals(actualException.getActionStatus(), ActionStatus.COMPONENT_IN_USE_BY_ANOTHER_COMPONENT);
+        assertEquals(actualException.getParams()[0], ComponentType.SERVICE +  " " + service2Name);
+    }
+
+    @Test
+    public void testDeleteService_WithOneVersion() {
+        String invariantUUID = "12345";
+        String serviceUid = "1";
+        Map<GraphPropertyEnum, Object> propertiesToMatch = new EnumMap<>(GraphPropertyEnum.class);
+        propertiesToMatch.put(GraphPropertyEnum.INVARIANT_UUID, invariantUUID);
+        GraphVertex service1 = getTopologyTemplateVertex();
+        service1.setUniqueId(serviceUid);
+        List<GraphVertex> allResourcesToDelete = new ArrayList<>();
+        allResourcesToDelete.add(service1);
+        ToscaElement toscaElement = getToscaElementForTest();
+        toscaElement.setUniqueId(serviceUid);
+        List<String> affectedComponentIds = new ArrayList<>();
+        affectedComponentIds.add(service1.getUniqueId());
+
+        when(janusGraphDaoMock.getByCriteria(null, propertiesToMatch, JsonParseFlagEnum.ParseMetadata)).
+                thenReturn(Either.left(allResourcesToDelete));
+        doReturn(Either.left(toscaElement)).when(topologyTemplateOperationMock).getToscaElement(eq(service1), any(ComponentParametersView.class));
+        when(topologyTemplateOperationMock.
+                getComponentByLabelAndId(serviceUid, ToscaElementTypeEnum.TOPOLOGY_TEMPLATE, JsonParseFlagEnum.ParseAll)).
+                thenReturn(Either.left(service1));
+        when(janusGraphDaoMock.getParentVertices(eq(service1), any(), eq(JsonParseFlagEnum.ParseAll))).
+                thenReturn(Either.right(JanusGraphOperationStatus.OK));
+        when(graphLockOperationMock.lockComponent(service1.getUniqueId(), NodeTypeEnum.Service)).
+                thenReturn(StorageOperationStatus.OK);
+        when(topologyTemplateOperationMock.deleteToscaElement(service1)).thenReturn(Either.left(toscaElement));
+        assertEquals(affectedComponentIds, testInstance.deleteService(invariantUUID, true));
+    }
+
+    @Test
+    public void testDeleteService_WithTwoVersions() {
+        String invariantUUID = "12345";
+        String serviceUid = "1";
+        String service2Uid = "2";
+        GraphVertex service = getTopologyTemplateVertex();
+        service.setUniqueId(serviceUid);
+        GraphVertex serviceV2 = getTopologyTemplateVertex();
+        serviceV2.setUniqueId(service2Uid);
+        ToscaElement toscaElement = getToscaElementForTest();
+        toscaElement.setUniqueId(serviceUid);
+        ToscaElement toscaElement2 = getToscaElementForTest();
+        toscaElement2.setUniqueId(service2Uid);
+        List<String> affectedComponentIds = new ArrayList<>();
+        affectedComponentIds.add(service.getUniqueId());
+        affectedComponentIds.add(serviceV2.getUniqueId());
+        List<GraphVertex> allResourcesToDelete = new ArrayList<>();
+        allResourcesToDelete.add(service);
+        allResourcesToDelete.add(serviceV2);
+        Map<GraphPropertyEnum, Object> propertiesToMatch = new EnumMap<>(GraphPropertyEnum.class);
+        propertiesToMatch.put(GraphPropertyEnum.INVARIANT_UUID, invariantUUID);
+
+        when(janusGraphDaoMock.getByCriteria(null, propertiesToMatch, JsonParseFlagEnum.ParseMetadata)).
+                thenReturn(Either.left(allResourcesToDelete));
+        doReturn(Either.left(toscaElement)).when(topologyTemplateOperationMock).
+                getToscaElement(eq(service), any(ComponentParametersView.class));
+        doReturn(Either.left(toscaElement2)).when(topologyTemplateOperationMock).
+                getToscaElement(eq(serviceV2), any(ComponentParametersView.class));
+        when(topologyTemplateOperationMock.
+                getComponentByLabelAndId(serviceUid, ToscaElementTypeEnum.TOPOLOGY_TEMPLATE, JsonParseFlagEnum.ParseAll)).
+                thenReturn(Either.left(service));
+        when(topologyTemplateOperationMock.
+                getComponentByLabelAndId(service2Uid, ToscaElementTypeEnum.TOPOLOGY_TEMPLATE, JsonParseFlagEnum.ParseAll)).
+                thenReturn(Either.left(serviceV2));
+        when(janusGraphDaoMock.getParentVertices(any(GraphVertex.class), any(), eq(JsonParseFlagEnum.ParseAll))).
+                thenReturn(Either.right(JanusGraphOperationStatus.OK));
+        when(graphLockOperationMock.lockComponent(service.getUniqueId(), NodeTypeEnum.Service)).
+            thenReturn(StorageOperationStatus.OK);
+        when(graphLockOperationMock.lockComponent(serviceV2.getUniqueId(), NodeTypeEnum.Service)).
+                thenReturn(StorageOperationStatus.OK);
+        when(topologyTemplateOperationMock.deleteToscaElement(service)).thenReturn(Either.left(toscaElement));
+        when(topologyTemplateOperationMock.deleteToscaElement(serviceV2)).thenReturn(Either.left(toscaElement));
+        assertEquals(affectedComponentIds, testInstance.deleteService(invariantUUID, true));
+    }
+
+    @Test
+    public void testDeleteService_FailDelete() {
+        String invariantUUID = "12345";
+        String serviceUid = "1";
+        GraphVertex service = getTopologyTemplateVertex();
+        service.setUniqueId(serviceUid);
+        ToscaElement toscaElement = getToscaElementForTest();
+        toscaElement.setUniqueId(serviceUid);
+        List<GraphVertex> allResourcesToDelete = new ArrayList<>();
+        allResourcesToDelete.add(service);
+        Map<GraphPropertyEnum, Object> propertiesToMatch = new EnumMap<>(GraphPropertyEnum.class);
+        propertiesToMatch.put(GraphPropertyEnum.INVARIANT_UUID, invariantUUID);
+
+        when(janusGraphDaoMock.getByCriteria(null, propertiesToMatch, JsonParseFlagEnum.ParseMetadata)).
+                thenReturn(Either.left(allResourcesToDelete));
+        doReturn(Either.left(toscaElement)).when(topologyTemplateOperationMock).getToscaElement(eq(service), any(ComponentParametersView.class));
+        when(topologyTemplateOperationMock.getComponentByLabelAndId(serviceUid, ToscaElementTypeEnum.TOPOLOGY_TEMPLATE, JsonParseFlagEnum.ParseAll)).
+                thenReturn(Either.left(service));
+        when(janusGraphDaoMock.getParentVertices(eq(service), any(), eq(JsonParseFlagEnum.ParseAll))).
+                thenReturn(Either.right(JanusGraphOperationStatus.OK));
+        when(graphLockOperationMock.lockComponent(service.getUniqueId(), NodeTypeEnum.Service)).
+                thenReturn(StorageOperationStatus.OK);
+        when(topologyTemplateOperationMock.deleteToscaElement(service))
+                .thenReturn(Either.right(StorageOperationStatus.NOT_FOUND));
+        assertThrows(StorageException.class, () -> testInstance.deleteService(invariantUUID, true));
+    }
+
+    @Test
+    public void testDeleteService_NotFound() {
+        String invariantUUID = "12345";
+        Map<GraphPropertyEnum, Object> propertiesToMatch = new EnumMap<>(GraphPropertyEnum.class);
+        propertiesToMatch.put(GraphPropertyEnum.INVARIANT_UUID, invariantUUID);
+        when(janusGraphDaoMock.getByCriteria(null, propertiesToMatch, JsonParseFlagEnum.ParseMetadata)).
+                thenReturn(Either.right(JanusGraphOperationStatus.NOT_FOUND));
+        assertThrows(StorageException.class, () -> testInstance.deleteService(invariantUUID, true));
+    }
+
     @Test
     public void testMarkComponentToDelete() {
         StorageOperationStatus result;