aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorandre.schmid <andre.schmid@est.tech>2021-05-05 15:31:04 +0100
committerChristophe Closset <christophe.closset@intl.att.com>2021-05-15 06:21:13 +0000
commit2152a9a43767cdd486fd8c93894f66a05083f53c (patch)
treecbb64fc5680ba724bc317e27f6a20802d5b38502
parente3de4c9d214983d38a7d66e89dae5d4bba170ca3 (diff)
Support for selection of capabilities
Change-Id: Ib1a3e3e1a59fc84c62620932c408e231acf77024 Issue-ID: SDC-3580 Signed-off-by: André Schmid <andre.schmid@est.tech>
-rw-r--r--catalog-be/src/main/docker/backend/chef-repo/cookbooks/sdc-catalog-be/files/default/error-configuration.yaml28
-rw-r--r--catalog-be/src/main/java/org/openecomp/sdc/be/components/impl/ComponentInstanceBusinessLogic.java69
-rw-r--r--catalog-be/src/main/java/org/openecomp/sdc/be/components/impl/exceptions/ComponentException.java3
-rw-r--r--catalog-be/src/main/java/org/openecomp/sdc/be/servlets/ComponentInstanceCapabilityServlet.java144
-rw-r--r--catalog-be/src/main/java/org/openecomp/sdc/be/servlets/ComponentInstanceServlet.java2
-rw-r--r--catalog-be/src/main/java/org/openecomp/sdc/be/servlets/builder/ServletResponseBuilder.java72
-rw-r--r--catalog-be/src/main/java/org/openecomp/sdc/be/servlets/exception/OperationExceptionMapper.java50
-rw-r--r--catalog-be/src/main/java/org/openecomp/sdc/be/tosca/CapabilityRequirementConverter.java8
-rw-r--r--catalog-be/src/main/java/org/openecomp/sdc/config/CatalogBESpringConfig.java3
-rw-r--r--catalog-be/src/test/java/org/openecomp/sdc/be/components/impl/ComponentInstanceBusinessLogicTest.java217
-rw-r--r--catalog-be/src/test/java/org/openecomp/sdc/be/servlets/ComponentInstanceCapabilityServletTest.java240
-rw-r--r--catalog-be/src/test/java/org/openecomp/sdc/be/servlets/JerseySpringBaseTest.java1
-rw-r--r--catalog-be/src/test/java/org/openecomp/sdc/be/tosca/CapabilityRequirementConverterTest.java1
-rw-r--r--catalog-be/src/test/resources/config/catalog-be/error-configuration.yaml28
-rw-r--r--catalog-dao/src/main/java/org/openecomp/sdc/be/dao/api/ActionStatus.java5
-rw-r--r--catalog-model/src/main/java/org/openecomp/sdc/be/model/jsonjanusgraph/operations/NodeTemplateOperation.java124
-rw-r--r--catalog-model/src/main/java/org/openecomp/sdc/be/model/jsonjanusgraph/operations/ToscaOperationFacade.java7
-rw-r--r--catalog-model/src/main/java/org/openecomp/sdc/be/model/jsonjanusgraph/operations/exception/OperationException.java42
-rw-r--r--catalog-model/src/main/java/org/openecomp/sdc/be/ui/mapper/CapabilityMapper.java40
-rw-r--r--catalog-model/src/main/java/org/openecomp/sdc/be/ui/model/ComponentInstanceCapabilityUpdateModel.java50
-rw-r--r--catalog-model/src/test/java/org/openecomp/sdc/be/model/jsonjanusgraph/operations/NodeTemplateOperationTest.java197
-rw-r--r--catalog-model/src/test/java/org/openecomp/sdc/be/ui/mapper/CapabilityMapperTest.java60
-rw-r--r--catalog-ui/src/app/models/capability.ts2
-rw-r--r--catalog-ui/src/app/ng2/pages/composition/graph/composition-graph.component.ts11
-rw-r--r--catalog-ui/src/app/ng2/pages/composition/panel/panel-tabs/req-capabilities-tab/req-capabilities-tab.component.html28
-rw-r--r--catalog-ui/src/app/ng2/pages/composition/panel/panel-tabs/req-capabilities-tab/req-capabilities-tab.component.ts42
-rw-r--r--catalog-ui/src/app/ng2/pages/composition/panel/panel-tabs/req-capabilities-tab/requirement-list/requirement-list.component.html2
-rw-r--r--catalog-ui/src/app/ng2/services/component-instance-services/component-instance.service.spec.ts80
-rw-r--r--catalog-ui/src/app/ng2/services/component-instance-services/component-instance.service.ts36
-rw-r--r--catalog-ui/src/app/utils/constants.ts1
-rw-r--r--common-app-api/src/main/java/org/openecomp/sdc/exception/ResponseFormat.java10
-rw-r--r--common-app-logging/src/main/java/org/openecomp/sdc/common/log/enums/LoggerSupportabilityActions.java1
-rw-r--r--common-be/src/main/java/org/openecomp/sdc/be/datatypes/elements/CapabilityDataDefinition.java21
-rw-r--r--common-be/src/main/java/org/openecomp/sdc/be/exception/BusinessException.java34
-rw-r--r--integration-tests/src/test/java/org/onap/sdc/frontend/ci/tests/pages/component/workspace/CompositionRequirementsCapabilitiesTab.java7
35 files changed, 1573 insertions, 93 deletions
diff --git a/catalog-be/src/main/docker/backend/chef-repo/cookbooks/sdc-catalog-be/files/default/error-configuration.yaml b/catalog-be/src/main/docker/backend/chef-repo/cookbooks/sdc-catalog-be/files/default/error-configuration.yaml
index 3e1b16d82f..b49c111c79 100644
--- a/catalog-be/src/main/docker/backend/chef-repo/cookbooks/sdc-catalog-be/files/default/error-configuration.yaml
+++ b/catalog-be/src/main/docker/backend/chef-repo/cookbooks/sdc-catalog-be/files/default/error-configuration.yaml
@@ -2437,3 +2437,31 @@ errors:
message: '%1 is not yet supported',
messageId: "SVC4139"
}
+ #---------SVC4140------------------------------
+ # %1 - Component uid
+ COMPONENT_FIND_ERROR: {
+ code: 500,
+ message: "An unexpected error occurred while retrieving the component '%1'.",
+ messageId: "SVC4140"
+ }
+ #---------SVC4141------------------------------
+ # %1 - Component uid
+ COMPONENT_CAPABILITIES_FIND_ERROR: {
+ code: 500,
+ message: "An unexpected error occurred while retrieving the component '%1' capabilities.",
+ messageId: "SVC4141"
+ }
+ #---------SVC4142------------------------------
+ # %1 - Component uid or name
+ COMPONENT_NOT_FOUND: {
+ code: 404,
+ message: "Component '%1' was not found.",
+ messageId: "SVC4142"
+ }
+ #---------SVC4143------------------------------
+ # %1 - Capability name
+ COMPONENT_INSTANCE_CAPABILITY_UPDATE_ERROR: {
+ code: 500,
+ message: "An unexpected error occurred while updating the capability '%1'.",
+ messageId: "SVC4143"
+ } \ No newline at end of file
diff --git a/catalog-be/src/main/java/org/openecomp/sdc/be/components/impl/ComponentInstanceBusinessLogic.java b/catalog-be/src/main/java/org/openecomp/sdc/be/components/impl/ComponentInstanceBusinessLogic.java
index b602072354..b8fabc307f 100644
--- a/catalog-be/src/main/java/org/openecomp/sdc/be/components/impl/ComponentInstanceBusinessLogic.java
+++ b/catalog-be/src/main/java/org/openecomp/sdc/be/components/impl/ComponentInstanceBusinessLogic.java
@@ -74,6 +74,7 @@ import org.openecomp.sdc.be.datatypes.enums.NodeTypeEnum;
import org.openecomp.sdc.be.datatypes.enums.OriginTypeEnum;
import org.openecomp.sdc.be.datatypes.enums.ResourceTypeEnum;
import org.openecomp.sdc.be.datatypes.tosca.ToscaGetFunctionType;
+import org.openecomp.sdc.be.exception.BusinessException;
import org.openecomp.sdc.be.impl.ComponentsUtils;
import org.openecomp.sdc.be.impl.ForwardingPathUtils;
import org.openecomp.sdc.be.impl.ServiceFilterUtils;
@@ -108,6 +109,7 @@ import org.openecomp.sdc.be.model.jsonjanusgraph.operations.ArtifactsOperations;
import org.openecomp.sdc.be.model.jsonjanusgraph.operations.ForwardingPathOperation;
import org.openecomp.sdc.be.model.jsonjanusgraph.operations.InterfaceOperation;
import org.openecomp.sdc.be.model.jsonjanusgraph.operations.NodeFilterOperation;
+import org.openecomp.sdc.be.model.jsonjanusgraph.operations.NodeTemplateOperation;
import org.openecomp.sdc.be.model.jsonjanusgraph.operations.ToscaOperationFacade;
import org.openecomp.sdc.be.model.jsonjanusgraph.utils.ModelConverter;
import org.openecomp.sdc.be.model.operations.StorageException;
@@ -130,6 +132,8 @@ import org.openecomp.sdc.common.api.Constants;
import org.openecomp.sdc.common.datastructure.Wrapper;
import org.openecomp.sdc.common.jsongraph.util.CommonUtility;
import org.openecomp.sdc.common.jsongraph.util.CommonUtility.LogLevelEnum;
+import org.openecomp.sdc.common.log.elements.ErrorLogOptionalData;
+import org.openecomp.sdc.common.log.enums.EcompLoggerErrorCode;
import org.openecomp.sdc.common.log.wrappers.Logger;
import org.openecomp.sdc.common.util.ValidationUtils;
import org.openecomp.sdc.exception.ResponseFormat;
@@ -153,6 +157,8 @@ public class ComponentInstanceBusinessLogic extends BaseBusinessLogic {
private static final String FAILED_TO_COPY_COMP_INSTANCE_TO_CANVAS = "Failed to copy the component instance to the canvas";
private static final String COPY_COMPONENT_INSTANCE_OK = "Copy component instance OK";
private static final String CANNOT_ATTACH_RESOURCE_INSTANCES_TO_CONTAINER_RESOURCE_OF_TYPE = "Cannot attach resource instances to container resource of type {}";
+ private static final String FAILED_TO_UPDATE_COMPONENT_INSTANCE_CAPABILITY = "Failed to update component instance capability on instance {} in "
+ + "container {}";
private static final String SERVICE_PROXY = "serviceProxy";
private static final String ASSOCIATE_RI_TO_RI = "associateRIToRI";
private ComponentInstanceOperation componentInstanceOperation;
@@ -3238,6 +3244,69 @@ public class ComponentInstanceBusinessLogic extends BaseBusinessLogic {
}
}
+ public Either<CapabilityDefinition, ResponseFormat> updateInstanceCapability(final ComponentTypeEnum containerComponentType,
+ final String containerComponentId,
+ final String componentInstanceUniqueId,
+ final CapabilityDefinition capabilityDefinition,
+ final String userId) {
+ if (containerComponentType == null) {
+ BeEcompErrorManager.getInstance().logInvalidInputError("updateInstanceCapability", INVALID_COMPONENT_TYPE, ErrorSeverity.INFO);
+ return Either.right(componentsUtils.getResponseFormat(ActionStatus.NOT_ALLOWED));
+ }
+ validateUserExists(userId);
+ final Either<Component, StorageOperationStatus> getResourceResult = toscaOperationFacade.getToscaFullElement(containerComponentId);
+ if (getResourceResult.isRight()) {
+ log.debug(FAILED_TO_RETRIEVE_COMPONENT_COMPONENT_ID, containerComponentId);
+ return Either.right(componentsUtils.getResponseFormat(ActionStatus.COMPONENT_NOT_FOUND, containerComponentId));
+ }
+ final Component containerComponent = getResourceResult.left().value();
+ if (!ComponentValidationUtils.canWorkOnComponent(containerComponent, userId)) {
+ log.info("Restricted operation for user: {} on component {}", userId, containerComponentId);
+ return Either.right(componentsUtils.getResponseFormat(ActionStatus.RESTRICTED_OPERATION));
+ }
+ final Either<ComponentInstance, StorageOperationStatus> resourceInstanceStatus =
+ getResourceInstanceById(containerComponent, componentInstanceUniqueId);
+ if (resourceInstanceStatus.isRight()) {
+ return Either.right(componentsUtils
+ .getResponseFormat(ActionStatus.RESOURCE_INSTANCE_NOT_FOUND_ON_SERVICE, componentInstanceUniqueId, containerComponentId));
+ }
+ // lock resource
+ final StorageOperationStatus lockStatus = graphLockOperation.lockComponent(containerComponentId, containerComponentType.getNodeType());
+ if (lockStatus != StorageOperationStatus.OK) {
+ log.debug("Failed to lock component {}", containerComponentId);
+ return Either.right(componentsUtils.getResponseFormat(componentsUtils.convertFromStorageResponse(lockStatus)));
+ }
+ var success = false;
+ try {
+ final CapabilityDataDefinition updatedCapabilityDefinition = toscaOperationFacade
+ .updateComponentInstanceCapability(containerComponentId, componentInstanceUniqueId, capabilityDefinition);
+ final Either<Component, StorageOperationStatus> updateContainerEither = toscaOperationFacade
+ .updateComponentInstanceMetadataOfTopologyTemplate(containerComponent);
+ if (updateContainerEither.isRight()) {
+ var actionStatus = componentsUtils.convertFromStorageResponse(updateContainerEither.right().value(), containerComponentType);
+ return Either.right(componentsUtils.getResponseFormat(actionStatus));
+ }
+ success = true;
+ return Either.left(new CapabilityDefinition(updatedCapabilityDefinition));
+ } catch (final BusinessException e) {
+ log.error(EcompLoggerErrorCode.BUSINESS_PROCESS_ERROR, NodeTemplateOperation.class.getName(), (ErrorLogOptionalData) null,
+ FAILED_TO_UPDATE_COMPONENT_INSTANCE_CAPABILITY, componentInstanceUniqueId, containerComponentId);
+ throw e;
+ } catch (final Exception e) {
+ log.error(EcompLoggerErrorCode.BUSINESS_PROCESS_ERROR, NodeTemplateOperation.class.getName(), (ErrorLogOptionalData) null,
+ FAILED_TO_UPDATE_COMPONENT_INSTANCE_CAPABILITY, componentInstanceUniqueId, containerComponentId);
+ throw new ByResponseFormatComponentException(componentsUtils.getResponseFormat(ActionStatus.GENERAL_ERROR));
+ } finally {
+ if (success) {
+ janusGraphDao.commit();
+ } else {
+ janusGraphDao.rollback();
+ }
+ // unlock resource
+ graphLockOperation.unlockComponent(containerComponentId, containerComponentType.getNodeType());
+ }
+ }
+
public Either<List<ComponentInstanceProperty>, ResponseFormat> updateInstanceCapabilityProperties(ComponentTypeEnum componentTypeEnum,
String containerComponentId,
String componentInstanceUniqueId,
diff --git a/catalog-be/src/main/java/org/openecomp/sdc/be/components/impl/exceptions/ComponentException.java b/catalog-be/src/main/java/org/openecomp/sdc/be/components/impl/exceptions/ComponentException.java
index 351d279875..7410e888f0 100644
--- a/catalog-be/src/main/java/org/openecomp/sdc/be/components/impl/exceptions/ComponentException.java
+++ b/catalog-be/src/main/java/org/openecomp/sdc/be/components/impl/exceptions/ComponentException.java
@@ -22,10 +22,11 @@ package org.openecomp.sdc.be.components.impl.exceptions;
import javax.annotation.Nullable;
import org.openecomp.sdc.be.components.impl.ResponseFormatManager;
import org.openecomp.sdc.be.dao.api.ActionStatus;
+import org.openecomp.sdc.be.exception.BusinessException;
import org.openecomp.sdc.be.model.Resource;
import org.openecomp.sdc.exception.ResponseFormat;
-public class ComponentException extends RuntimeException {
+public class ComponentException extends BusinessException {
/**
* This class will be initialized either by action status and params or by ResponseFormat
diff --git a/catalog-be/src/main/java/org/openecomp/sdc/be/servlets/ComponentInstanceCapabilityServlet.java b/catalog-be/src/main/java/org/openecomp/sdc/be/servlets/ComponentInstanceCapabilityServlet.java
new file mode 100644
index 0000000000..f83f83df2b
--- /dev/null
+++ b/catalog-be/src/main/java/org/openecomp/sdc/be/servlets/ComponentInstanceCapabilityServlet.java
@@ -0,0 +1,144 @@
+/*
+ * ============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.servlets;
+
+import com.jcabi.aspects.Loggable;
+import fj.data.Either;
+import io.swagger.v3.oas.annotations.Operation;
+import io.swagger.v3.oas.annotations.Parameter;
+import io.swagger.v3.oas.annotations.media.ArraySchema;
+import io.swagger.v3.oas.annotations.media.Content;
+import io.swagger.v3.oas.annotations.media.Schema;
+import io.swagger.v3.oas.annotations.responses.ApiResponse;
+import io.swagger.v3.oas.annotations.servers.Server;
+import io.swagger.v3.oas.annotations.tags.Tag;
+import javax.servlet.http.HttpServletRequest;
+import javax.validation.Valid;
+import javax.validation.constraints.NotNull;
+import javax.ws.rs.Consumes;
+import javax.ws.rs.HeaderParam;
+import javax.ws.rs.PUT;
+import javax.ws.rs.Path;
+import javax.ws.rs.PathParam;
+import javax.ws.rs.Produces;
+import javax.ws.rs.core.Context;
+import javax.ws.rs.core.MediaType;
+import javax.ws.rs.core.Response;
+import org.openecomp.sdc.be.components.impl.ComponentInstanceBusinessLogic;
+import org.openecomp.sdc.be.components.impl.ResponseFormatManager;
+import org.openecomp.sdc.be.components.impl.aaf.AafPermission;
+import org.openecomp.sdc.be.components.impl.aaf.PermissionAllowed;
+import org.openecomp.sdc.be.config.BeEcompErrorManager;
+import org.openecomp.sdc.be.dao.api.ActionStatus;
+import org.openecomp.sdc.be.datatypes.enums.ComponentTypeEnum;
+import org.openecomp.sdc.be.exception.BusinessException;
+import org.openecomp.sdc.be.model.CapabilityDefinition;
+import org.openecomp.sdc.be.servlets.builder.ServletResponseBuilder;
+import org.openecomp.sdc.be.ui.mapper.CapabilityMapper;
+import org.openecomp.sdc.be.ui.model.ComponentInstanceCapabilityUpdateModel;
+import org.openecomp.sdc.common.api.Constants;
+import org.openecomp.sdc.common.log.elements.LoggerSupportability;
+import org.openecomp.sdc.common.log.enums.LoggerSupportabilityActions;
+import org.openecomp.sdc.common.log.enums.StatusCode;
+import org.openecomp.sdc.common.log.wrappers.Logger;
+import org.openecomp.sdc.exception.ResponseFormat;
+import org.springframework.stereotype.Controller;
+import org.springframework.web.bind.annotation.RequestBody;
+
+/**
+ * Handles component instance capabilities operations
+ */
+@Loggable(prepend = true, value = Loggable.DEBUG, trim = false)
+@Path("/v1/catalog")
+@Tag(name = "SDCE-2 APIs")
+@Server(url = "/sdc2/rest")
+@Controller
+public class ComponentInstanceCapabilityServlet {
+
+ private static final Logger LOGGER = Logger.getLogger(ComponentInstanceCapabilityServlet.class);
+ private static final LoggerSupportability LOGGER_SUPPORTABILITY = LoggerSupportability.getLogger(ComponentInstanceCapabilityServlet.class);
+
+ private final ResponseFormatManager responseFormatManager;
+ private final ComponentInstanceBusinessLogic componentInstanceBusinessLogic;
+ private final CapabilityMapper capabilityMapper;
+ private final ServletResponseBuilder servletResponseBuilder;
+
+ public ComponentInstanceCapabilityServlet(final ComponentInstanceBusinessLogic componentInstanceBusinessLogic,
+ final CapabilityMapper capabilityMapper, final ServletResponseBuilder servletResponseBuilder) {
+ this.capabilityMapper = capabilityMapper;
+ this.servletResponseBuilder = servletResponseBuilder;
+ this.responseFormatManager = ResponseFormatManager.getInstance();
+ this.componentInstanceBusinessLogic = componentInstanceBusinessLogic;
+ }
+
+ @PUT
+ @Path("/{containerComponentType}/{containerComponentId}/componentInstances/{componentInstanceUniqueId}/capability/")
+ @Consumes(MediaType.APPLICATION_JSON)
+ @Produces(MediaType.APPLICATION_JSON)
+ @Operation(description = "Update Component Instance Capability", method = "PUT", summary = "Returns updated Component Instance Capability",
+ responses = {
+ @ApiResponse(content = @Content(array = @ArraySchema(schema = @Schema(implementation = Response.class)))),
+ @ApiResponse(responseCode = "200", description = "Resource instance capability successfully updated"),
+ @ApiResponse(responseCode = "403", description = "Restricted operation"),
+ @ApiResponse(responseCode = "400", description = "Invalid content / Missing content"),
+ @ApiResponse(responseCode = "404", description = "Component/Component Instance/Capability not found")})
+ @PermissionAllowed(AafPermission.PermNames.INTERNAL_ALL_VALUE)
+ public Response updateInstanceRequirement(@PathParam("containerComponentType") final String containerComponentType,
+ @PathParam("containerComponentId") final String containerComponentId,
+ @PathParam("componentInstanceUniqueId") final String componentInstanceUniqueId,
+ @Parameter(description = "Component instance capability to update", required = true)
+ @Valid @RequestBody @NotNull final ComponentInstanceCapabilityUpdateModel capabilityUpdateModel,
+ @Context final HttpServletRequest request,
+ @HeaderParam(value = Constants.USER_ID_HEADER) final String userId) {
+ if (LOGGER.isDebugEnabled()) {
+ final var url = request.getMethod() + " " + request.getRequestURI();
+ LOGGER.debug("Start handle request of {}", url);
+ }
+ try {
+ var componentTypeEnum = ComponentTypeEnum.findByParamName(containerComponentType);
+ if (componentTypeEnum == null) {
+ LOGGER.debug("Unsupported component type {}", containerComponentType);
+ return servletResponseBuilder
+ .buildErrorResponse(responseFormatManager.getResponseFormat(ActionStatus.UNSUPPORTED_ERROR, containerComponentType));
+ }
+ final var capabilityDefinition = capabilityMapper.mapToCapabilityDefinition(capabilityUpdateModel);
+ LOGGER_SUPPORTABILITY.log(LoggerSupportabilityActions.UPDATE_INSTANCE_CAPABILITY, StatusCode.STARTED,
+ "Starting to update capability '{}' in component instance '{}' by '{}'",
+ capabilityDefinition.getName(), componentInstanceUniqueId, userId);
+ final Either<CapabilityDefinition, ResponseFormat> response = componentInstanceBusinessLogic
+ .updateInstanceCapability(componentTypeEnum, containerComponentId, componentInstanceUniqueId, capabilityDefinition, userId);
+ if (response.isRight()) {
+ return servletResponseBuilder.buildErrorResponse(response.right().value());
+ }
+ return servletResponseBuilder.buildOkResponse(responseFormatManager.getResponseFormat(ActionStatus.OK), response.left().value());
+ } catch (final BusinessException e) {
+ //leave to the handlers deal with it
+ throw e;
+ } catch (final Exception e) {
+ var errorMsg = String
+ .format("Unexpected error while updating component '%s' of type '%s' instance '%s'. Payload '%s'",
+ containerComponentId, containerComponentType, componentInstanceUniqueId, capabilityUpdateModel);
+ BeEcompErrorManager.getInstance().logBeRestApiGeneralError(errorMsg);
+ LOGGER.debug(errorMsg, e);
+ return servletResponseBuilder.buildErrorResponse(responseFormatManager.getResponseFormat(ActionStatus.GENERAL_ERROR));
+ }
+ }
+
+}
diff --git a/catalog-be/src/main/java/org/openecomp/sdc/be/servlets/ComponentInstanceServlet.java b/catalog-be/src/main/java/org/openecomp/sdc/be/servlets/ComponentInstanceServlet.java
index 7816d3d0be..d44c26ee6a 100644
--- a/catalog-be/src/main/java/org/openecomp/sdc/be/servlets/ComponentInstanceServlet.java
+++ b/catalog-be/src/main/java/org/openecomp/sdc/be/servlets/ComponentInstanceServlet.java
@@ -1046,7 +1046,7 @@ public class ComponentInstanceServlet extends AbstractValidationsServlet {
try {
log.debug(START_HANDLE_REQUEST_OF, url);
ComponentTypeEnum componentTypeEnum = ComponentTypeEnum.findByParamName(containerComponentType);
- if (componentInstanceBusinessLogic == null) {
+ if (componentTypeEnum == null) {
log.debug(UNSUPPORTED_COMPONENT_TYPE, containerComponentType);
return buildErrorResponse(getComponentsUtils().getResponseFormat(ActionStatus.UNSUPPORTED_ERROR, containerComponentType));
}
diff --git a/catalog-be/src/main/java/org/openecomp/sdc/be/servlets/builder/ServletResponseBuilder.java b/catalog-be/src/main/java/org/openecomp/sdc/be/servlets/builder/ServletResponseBuilder.java
new file mode 100644
index 0000000000..a36ccf5133
--- /dev/null
+++ b/catalog-be/src/main/java/org/openecomp/sdc/be/servlets/builder/ServletResponseBuilder.java
@@ -0,0 +1,72 @@
+/*
+ * ============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.servlets.builder;
+
+import com.google.gson.Gson;
+import com.google.gson.GsonBuilder;
+import java.util.Map;
+import java.util.Map.Entry;
+import javax.ws.rs.core.Response;
+import org.apache.commons.collections.MapUtils;
+import org.openecomp.sdc.common.log.wrappers.Logger;
+import org.openecomp.sdc.exception.ResponseFormat;
+import org.springframework.stereotype.Service;
+
+@Service
+public class ServletResponseBuilder {
+
+ private final Gson gson;
+
+ public ServletResponseBuilder() {
+ gson = new GsonBuilder().setPrettyPrinting().create();
+ }
+
+ private static final Logger log = Logger.getLogger(ServletResponseBuilder.class);
+
+ public Response buildErrorResponse(final ResponseFormat requestErrorWrapper) {
+ return Response.status(requestErrorWrapper.getStatus()).entity(gson.toJson(requestErrorWrapper.getRequestError())).build();
+ }
+
+ public Response buildOkResponse(final ResponseFormat errorResponseWrapper, final Object entity) {
+ return buildOkResponse(errorResponseWrapper, entity, null);
+ }
+
+ public Response buildOkResponse(final ResponseFormat errorResponseWrapper, final Object entity,
+ final Map<String, String> additionalHeaders) {
+ final int status = errorResponseWrapper.getStatus();
+ var responseBuilder = Response.status(status);
+ if (entity != null) {
+ if (log.isTraceEnabled()) {
+ log.trace("returned entity is {}", entity.toString());
+ }
+ responseBuilder = responseBuilder.entity(entity);
+ }
+ if (MapUtils.isNotEmpty(additionalHeaders)) {
+ for (final Entry<String, String> additionalHeader : additionalHeaders.entrySet()) {
+ final String headerName = additionalHeader.getKey();
+ final String headerValue = additionalHeader.getValue();
+ log.trace("Adding header {} with value {} to the response", headerName, headerValue);
+ responseBuilder = responseBuilder.header(headerName, headerValue);
+ }
+ }
+ return responseBuilder.build();
+ }
+
+}
diff --git a/catalog-be/src/main/java/org/openecomp/sdc/be/servlets/exception/OperationExceptionMapper.java b/catalog-be/src/main/java/org/openecomp/sdc/be/servlets/exception/OperationExceptionMapper.java
new file mode 100644
index 0000000000..7c25f8aef8
--- /dev/null
+++ b/catalog-be/src/main/java/org/openecomp/sdc/be/servlets/exception/OperationExceptionMapper.java
@@ -0,0 +1,50 @@
+/*
+ * ============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.servlets.exception;
+
+import javax.ws.rs.core.Response;
+import javax.ws.rs.ext.ExceptionMapper;
+import javax.ws.rs.ext.Provider;
+import org.openecomp.sdc.be.components.impl.ResponseFormatManager;
+import org.openecomp.sdc.be.model.jsonjanusgraph.operations.exception.OperationException;
+import org.openecomp.sdc.be.servlets.builder.ServletResponseBuilder;
+import org.openecomp.sdc.common.log.wrappers.Logger;
+import org.springframework.stereotype.Component;
+
+@Component
+@Provider
+public class OperationExceptionMapper implements ExceptionMapper<OperationException> {
+
+ private final ServletResponseBuilder servletResponseBuilder;
+ private final ResponseFormatManager responseFormatManager;
+
+ private static final Logger log = Logger.getLogger(OperationExceptionMapper.class);
+
+ public OperationExceptionMapper(final ServletResponseBuilder servletResponseBuilder) {
+ this.servletResponseBuilder = servletResponseBuilder;
+ this.responseFormatManager = ResponseFormatManager.getInstance();
+ }
+
+ @Override
+ public Response toResponse(final OperationException exception) {
+ log.debug("Handling OperationException response", exception);
+ return servletResponseBuilder.buildErrorResponse(responseFormatManager.getResponseFormat(exception.getActionStatus(), exception.getParams()));
+ }
+}
diff --git a/catalog-be/src/main/java/org/openecomp/sdc/be/tosca/CapabilityRequirementConverter.java b/catalog-be/src/main/java/org/openecomp/sdc/be/tosca/CapabilityRequirementConverter.java
index ac4f8bf6c8..88f3666305 100644
--- a/catalog-be/src/main/java/org/openecomp/sdc/be/tosca/CapabilityRequirementConverter.java
+++ b/catalog-be/src/main/java/org/openecomp/sdc/be/tosca/CapabilityRequirementConverter.java
@@ -323,9 +323,11 @@ public class CapabilityRequirementConverter {
Map<String, String[]> toscaCapabilities = new HashMap<>();
Either<Map<String, String[]>, ToscaError> result = null;
for (Map.Entry<String, List<CapabilityDefinition>> entry : capabilities.entrySet()) {
- Optional<CapabilityDefinition> failedToAddRequirement = entry.getValue().stream().filter(
- c -> !addEntry(componentsCache, toscaCapabilities, component, new SubstitutionEntry(c.getName(), c.getParentName(), ""),
- c.getPreviousName(), c.getOwnerId(), c.getPath())).findAny();
+ Optional<CapabilityDefinition> failedToAddRequirement = entry.getValue().stream()
+ .filter(CapabilityDataDefinition::isExternal)
+ .filter( c -> !addEntry(componentsCache, toscaCapabilities, component, new SubstitutionEntry(c.getName(), c.getParentName(), "")
+ , c.getPreviousName(), c.getOwnerId(), c.getPath()))
+ .findAny();
if (failedToAddRequirement.isPresent()) {
logger.debug("Failed to convert capability {} for substitution mappings section of a tosca template of the component {}. ",
failedToAddRequirement.get().getName(), component.getName());
diff --git a/catalog-be/src/main/java/org/openecomp/sdc/config/CatalogBESpringConfig.java b/catalog-be/src/main/java/org/openecomp/sdc/config/CatalogBESpringConfig.java
index 570cabee5f..0c78b1fdef 100644
--- a/catalog-be/src/main/java/org/openecomp/sdc/config/CatalogBESpringConfig.java
+++ b/catalog-be/src/main/java/org/openecomp/sdc/config/CatalogBESpringConfig.java
@@ -65,7 +65,8 @@ import org.springframework.core.annotation.Order;
"org.openecomp.sdc.be.servlets",
"org.openecomp.sdc.be.filters",
"org.openecomp.sdc.be.plugins",
- "org.openecomp.sdc.be.togglz"})
+ "org.openecomp.sdc.be.togglz",
+ "org.openecomp.sdc.be.ui.mapper"})
// @formatter:on
public class CatalogBESpringConfig {
diff --git a/catalog-be/src/test/java/org/openecomp/sdc/be/components/impl/ComponentInstanceBusinessLogicTest.java b/catalog-be/src/test/java/org/openecomp/sdc/be/components/impl/ComponentInstanceBusinessLogicTest.java
index 07fff19f0b..5c8b6ce6d2 100644
--- a/catalog-be/src/test/java/org/openecomp/sdc/be/components/impl/ComponentInstanceBusinessLogicTest.java
+++ b/catalog-be/src/test/java/org/openecomp/sdc/be/components/impl/ComponentInstanceBusinessLogicTest.java
@@ -23,10 +23,12 @@ package org.openecomp.sdc.be.components.impl;
import static org.assertj.core.api.Assertions.assertThat;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertFalse;
+import static org.junit.jupiter.api.Assertions.assertNotEquals;
import static org.junit.jupiter.api.Assertions.assertNotNull;
import static org.junit.jupiter.api.Assertions.assertNull;
import static org.junit.jupiter.api.Assertions.assertSame;
import static org.junit.jupiter.api.Assertions.assertThrows;
+import static org.junit.jupiter.api.Assertions.assertTrue;
import static org.junit.jupiter.api.DynamicTest.dynamicTest;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anySet;
@@ -79,12 +81,12 @@ import org.openecomp.sdc.be.datatypes.elements.GetInputValueDataDefinition;
import org.openecomp.sdc.be.datatypes.elements.GetPolicyValueDataDefinition;
import org.openecomp.sdc.be.datatypes.elements.ListDataDefinition;
import org.openecomp.sdc.be.datatypes.elements.RequirementDataDefinition;
-import org.openecomp.sdc.be.datatypes.elements.SchemaDefinition;
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.ResourceTypeEnum;
+import org.openecomp.sdc.be.exception.BusinessException;
import org.openecomp.sdc.be.impl.ComponentsUtils;
import org.openecomp.sdc.be.model.ArtifactDefinition;
import org.openecomp.sdc.be.model.CapabilityDefinition;
@@ -111,6 +113,7 @@ import org.openecomp.sdc.be.model.cache.ApplicationDataTypeCache;
import org.openecomp.sdc.be.model.jsonjanusgraph.config.ContainerInstanceTypesData;
import org.openecomp.sdc.be.model.jsonjanusgraph.operations.ForwardingPathOperation;
import org.openecomp.sdc.be.model.jsonjanusgraph.operations.ToscaOperationFacade;
+import org.openecomp.sdc.be.model.jsonjanusgraph.operations.exception.OperationException;
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.PropertyOperation;
@@ -201,7 +204,7 @@ class ComponentInstanceBusinessLogicTest {
@BeforeEach
void init() {
- MockitoAnnotations.initMocks(this);
+ MockitoAnnotations.openMocks(this);
stubMethods();
createComponents();
}
@@ -1950,6 +1953,216 @@ class ComponentInstanceBusinessLogicTest {
}
+ @Test
+ void updateInstanceCapabilitySuccessTest() {
+ var containerComponentId = "containerComponentId";
+ var componentInstanceUniqueId = "componentInstanceUniqueId";
+ var capabilityDefinition = new CapabilityDefinition();
+ capabilityDefinition.setUniqueId("uniqueId");
+
+ final Component component = new Service();
+ component.setUniqueId(containerComponentId);
+ component.setLastUpdaterUserId(USER_ID);
+ component.setLifecycleState(LifecycleStateEnum.NOT_CERTIFIED_CHECKOUT);
+
+ var componentInstance = new ComponentInstance();
+ componentInstance.setUniqueId(componentInstanceUniqueId);
+ component.setComponentInstances(Collections.singletonList(componentInstance));
+
+ when(toscaOperationFacade.getToscaFullElement(containerComponentId))
+ .thenReturn(Either.left(component));
+ when(toscaOperationFacade.updateComponentInstanceCapability(containerComponentId, componentInstanceUniqueId, capabilityDefinition))
+ .thenReturn(capabilityDefinition);
+ when(toscaOperationFacade.updateComponentInstanceMetadataOfTopologyTemplate(component))
+ .thenReturn(Either.left(component));
+ when(graphLockOperation.lockComponent(containerComponentId, NodeTypeEnum.Service))
+ .thenReturn(StorageOperationStatus.OK);
+
+ final Either<CapabilityDefinition, ResponseFormat> resultEither = componentInstanceBusinessLogic
+ .updateInstanceCapability(ComponentTypeEnum.SERVICE, containerComponentId, componentInstanceUniqueId, capabilityDefinition, USER_ID);
+ assertTrue(resultEither.isLeft());
+ final CapabilityDefinition actualCapabilityDefinition = resultEither.left().value();
+ assertNotEquals(capabilityDefinition, actualCapabilityDefinition);
+ assertEquals(capabilityDefinition.getUniqueId(), actualCapabilityDefinition.getUniqueId());
+ }
+
+ @Test
+ void updateInstanceCapabilityNoContainerComponentTypeTest() {
+ var responseFormat = new ResponseFormat();
+ when(componentsUtils.getResponseFormat(ActionStatus.NOT_ALLOWED)).thenReturn(responseFormat);
+ final Either<CapabilityDefinition, ResponseFormat> resultEither = componentInstanceBusinessLogic
+ .updateInstanceCapability(null, "containerComponentId", "componentInstanceUniqueId", new CapabilityDefinition(), USER_ID);
+ assertTrue(resultEither.isRight(), "Either return should be right");
+ final ResponseFormat actualResponseFormat = resultEither.right().value();
+ assertEquals(responseFormat, actualResponseFormat);
+ }
+
+ @Test
+ void updateInstanceCapabilityContainerComponentNotFoundTest() {
+ var containerComponentId = "containerComponentId";
+ when(toscaOperationFacade.getToscaFullElement(containerComponentId)).thenReturn(Either.right(null));
+ var responseFormat = new ResponseFormat();
+ when(componentsUtils.getResponseFormat(ActionStatus.COMPONENT_NOT_FOUND, containerComponentId)).thenReturn(responseFormat);
+ final Either<CapabilityDefinition, ResponseFormat> resultEither = componentInstanceBusinessLogic
+ .updateInstanceCapability(ComponentTypeEnum.SERVICE, "containerComponentId", "componentInstanceUniqueId", new CapabilityDefinition(), USER_ID);
+ assertTrue(resultEither.isRight(), "Either return should be right");
+ final ResponseFormat actualResponseFormat = resultEither.right().value();
+ assertEquals(responseFormat, actualResponseFormat);
+ }
+
+ @Test
+ void updateInstanceCapabilityCannotWorkOnComponentTest() {
+ var containerComponentId = "containerComponentId";
+ var componentInstanceUniqueId = "componentInstanceUniqueId";
+
+ final Component component = new Service();
+ component.setUniqueId(containerComponentId);
+ component.setLastUpdaterUserId("anotherUse");
+ component.setLifecycleState(LifecycleStateEnum.NOT_CERTIFIED_CHECKOUT);
+
+ var expectedResponseFormat = new ResponseFormat();
+
+ when(toscaOperationFacade.getToscaFullElement(containerComponentId))
+ .thenReturn(Either.left(component));
+ when(componentsUtils.getResponseFormat(ActionStatus.RESTRICTED_OPERATION))
+ .thenReturn(expectedResponseFormat);
+
+ final Either<CapabilityDefinition, ResponseFormat> resultEither = componentInstanceBusinessLogic
+ .updateInstanceCapability(ComponentTypeEnum.SERVICE, containerComponentId, componentInstanceUniqueId, new CapabilityDefinition(), USER_ID);
+ assertTrue(resultEither.isRight(), "Either return should be right");
+ final ResponseFormat actualResponseFormat = resultEither.right().value();
+ assertEquals(expectedResponseFormat, actualResponseFormat);
+ }
+
+ @Test
+ void updateInstanceCapabilityResourceInstanceNotFoundTest() {
+ var containerComponentId = "containerComponentId";
+ var componentInstanceUniqueId = "componentInstanceUniqueId";
+
+ final Component component = new Service();
+ component.setUniqueId(containerComponentId);
+ component.setLastUpdaterUserId(USER_ID);
+ component.setLifecycleState(LifecycleStateEnum.NOT_CERTIFIED_CHECKOUT);
+
+ var expectedResponseFormat = new ResponseFormat();
+
+ when(toscaOperationFacade.getToscaFullElement(containerComponentId))
+ .thenReturn(Either.left(component));
+ when(componentsUtils.getResponseFormat(ActionStatus.RESOURCE_INSTANCE_NOT_FOUND_ON_SERVICE, componentInstanceUniqueId, containerComponentId))
+ .thenReturn(expectedResponseFormat);
+
+ final Either<CapabilityDefinition, ResponseFormat> resultEither = componentInstanceBusinessLogic
+ .updateInstanceCapability(ComponentTypeEnum.SERVICE, containerComponentId, componentInstanceUniqueId, new CapabilityDefinition(), USER_ID);
+ assertTrue(resultEither.isRight(), "Either return should be right");
+ final ResponseFormat actualResponseFormat = resultEither.right().value();
+ assertEquals(expectedResponseFormat, actualResponseFormat);
+ }
+
+ @Test
+ void updateInstanceCapabilityUpdateMetadataFailTest() {
+ var containerComponentId = "containerComponentId";
+ var componentInstanceUniqueId = "componentInstanceUniqueId";
+ var capabilityDefinition = new CapabilityDefinition();
+ capabilityDefinition.setUniqueId("uniqueId");
+
+ final Component component = new Service();
+ component.setUniqueId(containerComponentId);
+ component.setLastUpdaterUserId(USER_ID);
+ component.setLifecycleState(LifecycleStateEnum.NOT_CERTIFIED_CHECKOUT);
+
+ var componentInstance = new ComponentInstance();
+ componentInstance.setUniqueId(componentInstanceUniqueId);
+ component.setComponentInstances(Collections.singletonList(componentInstance));
+
+ var expectedResponseFormat = new ResponseFormat();
+
+ when(toscaOperationFacade.getToscaFullElement(containerComponentId))
+ .thenReturn(Either.left(component));
+ when(graphLockOperation.lockComponent(containerComponentId, NodeTypeEnum.Service))
+ .thenReturn(StorageOperationStatus.OK);
+ when(toscaOperationFacade.updateComponentInstanceCapability(containerComponentId, componentInstanceUniqueId, capabilityDefinition))
+ .thenReturn(capabilityDefinition);
+ when(toscaOperationFacade.updateComponentInstanceMetadataOfTopologyTemplate(component))
+ .thenReturn(Either.right(StorageOperationStatus.GENERAL_ERROR));
+ when(componentsUtils.convertFromStorageResponse(StorageOperationStatus.GENERAL_ERROR, ComponentTypeEnum.SERVICE))
+ .thenReturn(ActionStatus.GENERAL_ERROR);
+ when(componentsUtils.getResponseFormat(ActionStatus.GENERAL_ERROR))
+ .thenReturn(expectedResponseFormat);
+
+ final Either<CapabilityDefinition, ResponseFormat> resultEither = componentInstanceBusinessLogic
+ .updateInstanceCapability(ComponentTypeEnum.SERVICE, containerComponentId, componentInstanceUniqueId, capabilityDefinition, USER_ID);
+ assertTrue(resultEither.isRight(), "Either return should be right");
+ final ResponseFormat actualResponseFormat = resultEither.right().value();
+ assertEquals(expectedResponseFormat, actualResponseFormat);
+ }
+
+ @Test
+ void updateInstanceCapabilityBusinessExceptionHandlingTest() {
+ var containerComponentId = "containerComponentId";
+ var componentInstanceUniqueId = "componentInstanceUniqueId";
+ var capabilityDefinition = new CapabilityDefinition();
+ capabilityDefinition.setUniqueId("uniqueId");
+
+ final Component component = new Service();
+ component.setUniqueId(containerComponentId);
+ component.setLastUpdaterUserId(USER_ID);
+ component.setLifecycleState(LifecycleStateEnum.NOT_CERTIFIED_CHECKOUT);
+
+ var componentInstance = new ComponentInstance();
+ componentInstance.setUniqueId(componentInstanceUniqueId);
+ component.setComponentInstances(Collections.singletonList(componentInstance));
+
+
+ when(toscaOperationFacade.getToscaFullElement(containerComponentId))
+ .thenReturn(Either.left(component));
+ when(graphLockOperation.lockComponent(containerComponentId, NodeTypeEnum.Service))
+ .thenReturn(StorageOperationStatus.OK);
+ when(toscaOperationFacade.updateComponentInstanceCapability(containerComponentId, componentInstanceUniqueId, capabilityDefinition))
+ .thenThrow(new OperationException(ActionStatus.GENERAL_ERROR));
+
+ final BusinessException businessException = assertThrows(BusinessException.class, () -> {
+ componentInstanceBusinessLogic
+ .updateInstanceCapability(ComponentTypeEnum.SERVICE, containerComponentId, componentInstanceUniqueId, capabilityDefinition, USER_ID);
+ });
+ assertTrue(businessException instanceof OperationException);
+ assertEquals(ActionStatus.GENERAL_ERROR, ((OperationException) businessException).getActionStatus());
+ }
+
+ @Test
+ void updateInstanceCapabilityUnknownExceptionHandlingTest() {
+ var containerComponentId = "containerComponentId";
+ var componentInstanceUniqueId = "componentInstanceUniqueId";
+ var capabilityDefinition = new CapabilityDefinition();
+ capabilityDefinition.setUniqueId("uniqueId");
+
+ final Component component = new Service();
+ component.setUniqueId(containerComponentId);
+ component.setLastUpdaterUserId(USER_ID);
+ component.setLifecycleState(LifecycleStateEnum.NOT_CERTIFIED_CHECKOUT);
+
+ var componentInstance = new ComponentInstance();
+ componentInstance.setUniqueId(componentInstanceUniqueId);
+ component.setComponentInstances(Collections.singletonList(componentInstance));
+
+ var expectedResponseFormat = new ResponseFormat();
+
+ when(toscaOperationFacade.getToscaFullElement(containerComponentId))
+ .thenReturn(Either.left(component));
+ when(graphLockOperation.lockComponent(containerComponentId, NodeTypeEnum.Service))
+ .thenReturn(StorageOperationStatus.OK);
+ when(toscaOperationFacade.updateComponentInstanceCapability(containerComponentId, componentInstanceUniqueId, capabilityDefinition))
+ .thenThrow(new RuntimeException());
+ when(componentsUtils.getResponseFormat(ActionStatus.GENERAL_ERROR))
+ .thenReturn(expectedResponseFormat);
+
+ final Exception exception = assertThrows(BusinessException.class, () ->
+ componentInstanceBusinessLogic
+ .updateInstanceCapability(ComponentTypeEnum.SERVICE, containerComponentId, componentInstanceUniqueId, capabilityDefinition, USER_ID));
+ assertTrue(exception instanceof ByResponseFormatComponentException);
+ final ByResponseFormatComponentException actualException = (ByResponseFormatComponentException) exception;
+ assertEquals(expectedResponseFormat, actualException.getResponseFormat());
+ }
+
private ComponentInstance createServiceSubstitutionComponentInstance() {
final ComponentInstance instanceToBeCreated = new ComponentInstance();
instanceToBeCreated.setName(COMPONENT_INSTANCE_NAME);
diff --git a/catalog-be/src/test/java/org/openecomp/sdc/be/servlets/ComponentInstanceCapabilityServletTest.java b/catalog-be/src/test/java/org/openecomp/sdc/be/servlets/ComponentInstanceCapabilityServletTest.java
new file mode 100644
index 0000000000..8155f22d65
--- /dev/null
+++ b/catalog-be/src/test/java/org/openecomp/sdc/be/servlets/ComponentInstanceCapabilityServletTest.java
@@ -0,0 +1,240 @@
+/*
+ * ============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.servlets;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertNotNull;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+
+import com.fasterxml.jackson.core.JsonProcessingException;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import fj.data.Either;
+import javax.ws.rs.client.Entity;
+import javax.ws.rs.core.MediaType;
+import javax.ws.rs.core.Response;
+import org.glassfish.jersey.server.ResourceConfig;
+import org.junit.jupiter.api.AfterEach;
+import org.junit.jupiter.api.BeforeAll;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+import org.openecomp.sdc.be.components.impl.ComponentInstanceBusinessLogic;
+import org.openecomp.sdc.be.config.ConfigurationManager;
+import org.openecomp.sdc.be.config.ErrorInfo;
+import org.openecomp.sdc.be.dao.api.ActionStatus;
+import org.openecomp.sdc.be.datatypes.enums.ComponentTypeEnum;
+import org.openecomp.sdc.be.model.CapabilityDefinition;
+import org.openecomp.sdc.be.model.jsonjanusgraph.operations.exception.OperationException;
+import org.openecomp.sdc.be.servlets.builder.ServletResponseBuilder;
+import org.openecomp.sdc.be.servlets.exception.OperationExceptionMapper;
+import org.openecomp.sdc.be.ui.mapper.CapabilityMapper;
+import org.openecomp.sdc.be.ui.model.ComponentInstanceCapabilityUpdateModel;
+import org.openecomp.sdc.common.api.ConfigurationSource;
+import org.openecomp.sdc.common.api.Constants;
+import org.openecomp.sdc.common.impl.ExternalConfiguration;
+import org.openecomp.sdc.common.impl.FSConfigurationSource;
+import org.openecomp.sdc.exception.ResponseFormat;
+import org.openecomp.sdc.exception.ServiceException;
+
+class ComponentInstanceCapabilityServletTest extends JerseySpringBaseTest {
+
+ private static final String UPDATE_INSTANCE_REQUIREMENT_PATH_FORMAT = "/v1/catalog/%s/%s/componentInstances/%s/capability";
+ private static ConfigurationManager configurationManager;
+
+ private final String componentId = "componentId";
+ private final String componentInstanceId = "componentInstanceId";
+ private final String userId = "userId";
+
+ private CapabilityMapper capabilityMapper;
+ private ComponentInstanceBusinessLogic componentInstanceBusinessLogicMock;
+
+ @Override
+ protected ResourceConfig configure() {
+ componentInstanceBusinessLogicMock = mock(ComponentInstanceBusinessLogic.class);
+ capabilityMapper = new CapabilityMapper();
+ var servletResponseBuilder = new ServletResponseBuilder();
+ var componentInstanceCapabilityServlet =
+ new ComponentInstanceCapabilityServlet(componentInstanceBusinessLogicMock, capabilityMapper, servletResponseBuilder);
+ return super.configure().register(componentInstanceCapabilityServlet)
+ .register(new OperationExceptionMapper(servletResponseBuilder));
+ }
+
+ @BeforeAll
+ static void beforeAll() {
+ setupConfiguration();
+ }
+
+ private static void setupConfiguration() {
+ final ConfigurationSource configurationSource =
+ new FSConfigurationSource(ExternalConfiguration.getChangeListener(), "src/test/resources/config/catalog-be");
+ configurationManager = new ConfigurationManager(configurationSource);
+ }
+
+ //workaround for JerseyTest + Junit5
+ @BeforeEach
+ void beforeEach() throws Exception {
+ super.setUp();
+ }
+
+ //workaround for JerseyTest + Junit5
+ @AfterEach
+ void afterEach() throws Exception {
+ super.tearDown();
+ }
+
+ @Test
+ void updateInstanceRequirementSuccessTest() throws JsonProcessingException {
+ final var updateModel = createDefaultUpdateMode();
+ var expectedCapabilityDefinition = capabilityMapper.mapToCapabilityDefinition(updateModel);
+
+ when(componentInstanceBusinessLogicMock
+ .updateInstanceCapability(eq(ComponentTypeEnum.SERVICE), eq(componentId), eq(componentInstanceId), any(CapabilityDefinition.class), eq(userId)))
+ .thenReturn(Either.left(expectedCapabilityDefinition));
+ final var url =
+ String.format(UPDATE_INSTANCE_REQUIREMENT_PATH_FORMAT, ComponentTypeEnum.SERVICE_PARAM_NAME, componentId, componentInstanceId);
+
+ final Response response = target()
+ .path(url)
+ .request(MediaType.APPLICATION_JSON)
+ .header(Constants.USER_ID_HEADER, userId)
+ .put(Entity.entity(parseToJson(updateModel), MediaType.APPLICATION_JSON));
+ var actualCapabilityDefinition = response.readEntity(CapabilityDefinition.class);
+ assertEquals(200, response.getStatus(), "The update status should be as expected");
+ assertEquals(MediaType.valueOf(MediaType.APPLICATION_JSON), response.getMediaType(), "The content type should be application/json");
+ assertCapabilityDefinition(actualCapabilityDefinition, expectedCapabilityDefinition);
+ }
+
+ @Test
+ void updateInstanceRequirementFailTest() throws JsonProcessingException {
+ final var expectedResponseFormat = new ResponseFormat(404);
+ final var requestErrorWrapper = expectedResponseFormat.new RequestErrorWrapper();
+ final var serviceException = new ServiceException("anErrorCode", "anErrorText", new String[2]);
+ requestErrorWrapper.setServiceException(serviceException);
+ expectedResponseFormat.setRequestError(requestErrorWrapper);
+
+ when(componentInstanceBusinessLogicMock
+ .updateInstanceCapability(eq(ComponentTypeEnum.SERVICE), eq(componentId), eq(componentInstanceId), any(CapabilityDefinition.class), eq(userId)))
+ .thenReturn(Either.right(expectedResponseFormat));
+
+ final var url =
+ String.format(UPDATE_INSTANCE_REQUIREMENT_PATH_FORMAT, ComponentTypeEnum.SERVICE_PARAM_NAME, componentId, componentInstanceId);
+ final Response response = target()
+ .path(url)
+ .request(MediaType.APPLICATION_JSON)
+ .header(Constants.USER_ID_HEADER, userId)
+ .put(Entity.entity(parseToJson(createDefaultUpdateMode()), MediaType.APPLICATION_JSON));
+ var actualResponseFormat = response.readEntity(ResponseFormat.class);
+
+ assertEquals(expectedResponseFormat.getStatus(), response.getStatus(), "The update status should be as expected");
+ assertNotNull(actualResponseFormat.getRequestError());
+ assertNotNull(actualResponseFormat.getRequestError().getRequestError());
+ assertEquals(expectedResponseFormat.getMessageId(), actualResponseFormat.getMessageId());
+ assertEquals(expectedResponseFormat.getVariables().length, actualResponseFormat.getVariables().length);
+ }
+
+ @Test
+ void updateInstanceRequirementKnownErrorTest() throws JsonProcessingException {
+ when(componentInstanceBusinessLogicMock
+ .updateInstanceCapability(eq(ComponentTypeEnum.SERVICE), eq(componentId), eq(componentInstanceId), any(CapabilityDefinition.class), eq(userId)))
+ .thenThrow(new OperationException(ActionStatus.COMPONENT_NOT_FOUND, componentId));
+ final var url =
+ String.format(UPDATE_INSTANCE_REQUIREMENT_PATH_FORMAT, ComponentTypeEnum.SERVICE_PARAM_NAME, componentId, componentInstanceId);
+ final Response response = target()
+ .path(url)
+ .request(MediaType.APPLICATION_JSON)
+ .header(Constants.USER_ID_HEADER, userId)
+ .put(Entity.entity(parseToJson(createDefaultUpdateMode()), MediaType.APPLICATION_JSON));
+ var responseFormat = response.readEntity(ResponseFormat.class);
+
+ final ErrorInfo errorInfo = configurationManager.getErrorConfiguration().getErrorInfo(ActionStatus.COMPONENT_NOT_FOUND.name());
+ assertNotNull(errorInfo);
+ assertEquals(errorInfo.getCode(), response.getStatus(), "The update status should be as expected");
+ assertEquals(errorInfo.getMessageId(), responseFormat.getMessageId());
+ assertEquals(errorInfo.getMessage(), responseFormat.getText());
+ }
+
+ @Test
+ void updateInstanceRequirementUnknownErrorTest() throws JsonProcessingException {
+ when(componentInstanceBusinessLogicMock
+ .updateInstanceCapability(eq(ComponentTypeEnum.SERVICE), eq(componentId), eq(componentInstanceId), any(CapabilityDefinition.class), eq(userId)))
+ .thenThrow(new RuntimeException());
+ final var url =
+ String.format(UPDATE_INSTANCE_REQUIREMENT_PATH_FORMAT, ComponentTypeEnum.SERVICE_PARAM_NAME, componentId, componentInstanceId);
+ final Response response = target()
+ .path(url)
+ .request(MediaType.APPLICATION_JSON)
+ .header(Constants.USER_ID_HEADER, userId)
+ .put(Entity.entity(parseToJson(createDefaultUpdateMode()), MediaType.APPLICATION_JSON));
+ var responseFormat = response.readEntity(ResponseFormat.class);
+
+ final ErrorInfo errorInfo = configurationManager.getErrorConfiguration().getErrorInfo(ActionStatus.GENERAL_ERROR.name());
+ assertNotNull(errorInfo);
+ assertEquals(errorInfo.getCode(), response.getStatus(), "The update status should be as expected");
+ assertEquals(errorInfo.getMessageId(), responseFormat.getMessageId());
+ assertEquals(errorInfo.getMessage(), responseFormat.getText());
+ }
+
+ @Test
+ void updateInstanceRequirementIncorrectComponentTypeTest() throws JsonProcessingException {
+ final var url =
+ String.format(UPDATE_INSTANCE_REQUIREMENT_PATH_FORMAT, "wrongType", componentId, componentInstanceId);
+ final Response response = target()
+ .path(url)
+ .request(MediaType.APPLICATION_JSON)
+ .header(Constants.USER_ID_HEADER, userId)
+ .put(Entity.entity(parseToJson(createDefaultUpdateMode()), MediaType.APPLICATION_JSON));
+ var responseFormat = response.readEntity(ResponseFormat.class);
+
+ final ErrorInfo errorInfo = configurationManager.getErrorConfiguration().getErrorInfo(ActionStatus.UNSUPPORTED_ERROR.name());
+ assertNotNull(errorInfo);
+ assertEquals(errorInfo.getCode(), response.getStatus(), "The update status should be as expected");
+ assertEquals(errorInfo.getMessageId(), responseFormat.getMessageId());
+ assertEquals(errorInfo.getMessage(), responseFormat.getText());
+ }
+
+ private ComponentInstanceCapabilityUpdateModel createDefaultUpdateMode() {
+ var capabilityUpdateModel = new ComponentInstanceCapabilityUpdateModel();
+ capabilityUpdateModel.setName("name");
+ capabilityUpdateModel.setExternal(true);
+ capabilityUpdateModel.setOwnerId("ownerId");
+ capabilityUpdateModel.setType("type");
+ capabilityUpdateModel.setOwnerName("ownerName");
+ capabilityUpdateModel.setUniqueId("uniqueId");
+ return capabilityUpdateModel;
+ }
+
+ private void assertCapabilityDefinition(final CapabilityDefinition actualCapabilityDefinition,
+ final CapabilityDefinition expectedCapabilityDefinition) {
+ assertEquals(expectedCapabilityDefinition.getUniqueId(), actualCapabilityDefinition.getUniqueId());
+ assertEquals(expectedCapabilityDefinition.getName(), actualCapabilityDefinition.getName());
+ assertEquals(expectedCapabilityDefinition.getOwnerId(), actualCapabilityDefinition.getOwnerId());
+ assertEquals(expectedCapabilityDefinition.getOwnerName(), actualCapabilityDefinition.getOwnerName());
+ assertEquals(expectedCapabilityDefinition.getType(), actualCapabilityDefinition.getType());
+ assertEquals(expectedCapabilityDefinition.isExternal(), actualCapabilityDefinition.isExternal());
+ }
+
+ private <T> String parseToJson(final T object) throws JsonProcessingException {
+ return new ObjectMapper().writeValueAsString(object);
+ }
+
+}
+
diff --git a/catalog-be/src/test/java/org/openecomp/sdc/be/servlets/JerseySpringBaseTest.java b/catalog-be/src/test/java/org/openecomp/sdc/be/servlets/JerseySpringBaseTest.java
index e755de12f0..7fda4edd4f 100644
--- a/catalog-be/src/test/java/org/openecomp/sdc/be/servlets/JerseySpringBaseTest.java
+++ b/catalog-be/src/test/java/org/openecomp/sdc/be/servlets/JerseySpringBaseTest.java
@@ -77,6 +77,7 @@ public abstract class JerseySpringBaseTest extends JerseyTest {
.register(jacksonJsonProvider);
}
+ @Override
protected ResourceConfig configure() {
forceSet(TestProperties.CONTAINER_PORT, "0");
return configure(BaseTestConfig.class);
diff --git a/catalog-be/src/test/java/org/openecomp/sdc/be/tosca/CapabilityRequirementConverterTest.java b/catalog-be/src/test/java/org/openecomp/sdc/be/tosca/CapabilityRequirementConverterTest.java
index 49920c3c45..5f1b62d1d4 100644
--- a/catalog-be/src/test/java/org/openecomp/sdc/be/tosca/CapabilityRequirementConverterTest.java
+++ b/catalog-be/src/test/java/org/openecomp/sdc/be/tosca/CapabilityRequirementConverterTest.java
@@ -307,6 +307,7 @@ public class CapabilityRequirementConverterTest {
CapabilityDefinition capabilityDefinition = new CapabilityDefinition();
capabilityDefinition.setName(capabilityName);
capabilityDefinition.setType("att.Node");
+ capabilityDefinition.setExternal(true);
List<ComponentInstanceProperty> properties = new ArrayList<>();
ComponentInstanceProperty prop = new ComponentInstanceProperty();
prop.setName(PROPERTY_NAME);
diff --git a/catalog-be/src/test/resources/config/catalog-be/error-configuration.yaml b/catalog-be/src/test/resources/config/catalog-be/error-configuration.yaml
index 50906d2624..b363bacd73 100644
--- a/catalog-be/src/test/resources/config/catalog-be/error-configuration.yaml
+++ b/catalog-be/src/test/resources/config/catalog-be/error-configuration.yaml
@@ -2266,3 +2266,31 @@ errors:
message: "Error: Invalid content. Type name is not defined for policy %1",
messageId: "SVC4802"
}
+ #---------SVC4140------------------------------
+ # %1 - Component uid
+ COMPONENT_FIND_ERROR: {
+ code: 500,
+ message: "An unexpected error occurred while retrieving the component '%1'.",
+ messageId: "SVC4140"
+ }
+ #---------SVC4141------------------------------
+ # %1 - Component uid
+ COMPONENT_CAPABILITIES_FIND_ERROR: {
+ code: 500,
+ message: "An unexpected error occurred while retrieving the component '%1' capabilities.",
+ messageId: "SVC4141"
+ }
+ #---------SVC4142------------------------------
+ # %1 - Component uid or name
+ COMPONENT_NOT_FOUND: {
+ code: 404,
+ message: "Component '%1' was not found.",
+ messageId: "SVC4142"
+ }
+ #---------SVC4143------------------------------
+ # %1 - Capability name
+ COMPONENT_INSTANCE_CAPABILITY_UPDATE_ERROR: {
+ code: 500,
+ message: "An unexpected error occurred while updating the capability '%1'.",
+ messageId: "SVC4143"
+ } \ No newline at end of file
diff --git a/catalog-dao/src/main/java/org/openecomp/sdc/be/dao/api/ActionStatus.java b/catalog-dao/src/main/java/org/openecomp/sdc/be/dao/api/ActionStatus.java
index a8f94e8eb5..619f88263c 100644
--- a/catalog-dao/src/main/java/org/openecomp/sdc/be/dao/api/ActionStatus.java
+++ b/catalog-dao/src/main/java/org/openecomp/sdc/be/dao/api/ActionStatus.java
@@ -31,6 +31,10 @@ public enum ActionStatus {
RESOURCE_NOT_FOUND, MISSING_DERIVED_FROM_TEMPLATE, PARENT_RESOURCE_NOT_FOUND, PARENT_RESOURCE_DOES_NOT_EXTEND, INVALID_DEFAULT_VALUE, INVALID_COMPLEX_DEFAULT_VALUE, MULTIPLE_PARENT_RESOURCE_FOUND, INVALID_RESOURCE_PAYLOAD, INVALID_TOSCA_FILE_EXTENSION, INVALID_YAML_FILE, INVALID_TOSCA_TEMPLATE, NOT_RESOURCE_TOSCA_TEMPLATE, NOT_SINGLE_RESOURCE, INVALID_RESOURCE_NAMESPACE, RESOURCE_ALREADY_EXISTS, INVALID_RESOURCE_CHECKSUM, RESOURCE_CANNOT_CONTAIN_RESOURCE_INSTANCES, NO_ASSETS_FOUND, GENERIC_TYPE_NOT_FOUND, INVALID_RESOURCE_TYPE, TOSCA_PARSE_ERROR, INVALID_PM_DICTIONARY_FILE,
// Service related
SERVICE_TYPE_EXCEEDS_LIMIT, INVALID_SERVICE_TYPE, SERVICE_ROLE_EXCEEDS_LIMIT, INVALID_SERVICE_ROLE, INVALID_INSTANTIATION_TYPE, NOT_SERVICE_TOSCA_TEMPLATE, NOT_SINGLE_SERVICE, INVALID_SERVICE_CHECKSUM, INVALID_SERVICE_PAYLOAD, INVALID_SERVICE_NAMESPACE, SERVICE_ALREADY_EXISTS, UNSUPPORTED_DISTRIBUTION_STATUS, INVALID_NAMING_POLICY, INVALID_ENVIRONMENT_CONTEXT, NAMING_POLICY_EXCEEDS_LIMIT, MISSING_ECOMP_GENERATED_NAMING, PROPERTY_EXCEEDS_LIMIT, INVALID_PROPERY,
+ // Component related
+ COMPONENT_FIND_ERROR,
+ COMPONENT_CAPABILITIES_FIND_ERROR,
+ COMPONENT_INSTANCE_CAPABILITY_UPDATE_ERROR,
// Component name related
COMPONENT_NAME_ALREADY_EXIST, COMPONENT_NAME_EXCEEDS_LIMIT, MISSING_COMPONENT_NAME, INVALID_COMPONENT_NAME,
// Component description related
@@ -109,6 +113,7 @@ public enum ActionStatus {
CONTAINER_CANNOT_CONTAIN_COMPONENT_IN_STATE, CONTAINER_CANNOT_CONTAIN_INSTANCE, MISSING_MANDATORY_PROPERTY, MANDATORY_PROPERTY_MISSING_VALUE,
//Capability related
CAPABILITY_NOT_FOUND, CAPABILITY_NAME_MANDATORY, CAPABILITY_TYPE_MANDATORY, CAPABILITY_NAME_ALREADY_IN_USE, MAX_OCCURRENCES_SHOULD_BE_GREATER_THAN_MIN_OCCURRENCES, CAPABILITY_DELETION_NOT_ALLOWED_USED_IN_COMPOSITION, CAPABILITY_UPDATE_NOT_ALLOWED_USED_IN_COMPOSITION, INVALID_CAPABILITY_NAME, FAILED_TO_CREATE_OR_UPDATE_CAPABILITY_PROPERTIES, CAPABILITY_PROPERTIES_NOT_FOUND, RELATIONSHIP_TYPE_ALREADY_EXIST, MISSING_RELATIONSHIP_TYPE, CAPABILITY_TYPE_CANNOT_BE_EMPTY,
+ COMPONENT_CAPABILITY_UPDATE_NOT_FOUND_ERROR,
//Requirement related
REQUIREMENT_NOT_FOUND, REQUIREMENT_NAME_MANDATORY, REQUIREMENT_CAPABILITY_MANDATORY, REQUIREMENT_NAME_ALREADY_IN_USE, REQUIREMENT_DELETION_NOT_ALLOWED_USED_IN_COMPOSITION, REQUIREMENT_UPDATE_NOT_ALLOWED_USED_IN_COMPOSITION, INVALID_REQUIREMENT_NAME,
//Abstract template related
diff --git a/catalog-model/src/main/java/org/openecomp/sdc/be/model/jsonjanusgraph/operations/NodeTemplateOperation.java b/catalog-model/src/main/java/org/openecomp/sdc/be/model/jsonjanusgraph/operations/NodeTemplateOperation.java
index f9e9a46698..416c701582 100644
--- a/catalog-model/src/main/java/org/openecomp/sdc/be/model/jsonjanusgraph/operations/NodeTemplateOperation.java
+++ b/catalog-model/src/main/java/org/openecomp/sdc/be/model/jsonjanusgraph/operations/NodeTemplateOperation.java
@@ -45,6 +45,7 @@ import org.apache.tinkerpop.gremlin.structure.Edge;
import org.janusgraph.core.JanusGraphVertex;
import org.openecomp.sdc.be.config.BeEcompErrorManager;
import org.openecomp.sdc.be.config.ConfigurationManager;
+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.jsongraph.types.EdgeLabelEnum;
@@ -105,6 +106,7 @@ 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.enums.JsonConstantKeysEnum;
+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.StorageOperationStatus;
@@ -115,7 +117,9 @@ import org.openecomp.sdc.common.api.ArtifactGroupTypeEnum;
import org.openecomp.sdc.common.api.ArtifactTypeEnum;
import org.openecomp.sdc.common.jsongraph.util.CommonUtility;
import org.openecomp.sdc.common.jsongraph.util.CommonUtility.LogLevelEnum;
+import org.openecomp.sdc.common.log.elements.ErrorLogOptionalData;
import org.openecomp.sdc.common.log.elements.LoggerSupportability;
+import org.openecomp.sdc.common.log.enums.EcompLoggerErrorCode;
import org.openecomp.sdc.common.log.enums.LogLevel;
import org.openecomp.sdc.common.log.enums.LoggerSupportabilityActions;
import org.openecomp.sdc.common.log.enums.StatusCode;
@@ -957,11 +961,13 @@ public class NodeTemplateOperation extends BaseOperation {
MapListCapabilityDataDefinition allCalculatedCap = new MapListCapabilityDataDefinition();
if (calculatedCapabilities != null) {
calculatedCapabilities.forEach((key1, value1) -> {
- Map<String, ListCapabilityDataDefinition> mapByType = value1.getMapToscaDataDefinition();
- mapByType.forEach((key, value) -> value.getListToscaDataDefinition().forEach(cap -> {
- cap.addToPath(componentInstance.getUniqueId());
- allCalculatedCap.add(key, cap);
- }));
+ final Map<String, ListCapabilityDataDefinition> mapByType = value1.getMapToscaDataDefinition();
+ mapByType.forEach((key, value) -> value.getListToscaDataDefinition().stream()
+ .filter(CapabilityDataDefinition::isExternal)
+ .forEach(cap -> {
+ cap.addToPath(componentInstance.getUniqueId());
+ allCalculatedCap.add(key, cap);
+ }));
});
}
MapListCapabilityDataDefinition allCaps;
@@ -1068,6 +1074,93 @@ public class NodeTemplateOperation extends BaseOperation {
return StorageOperationStatus.OK;
}
+ public CapabilityDataDefinition updateComponentInstanceCapabilities(final String componentId, final String componentInstanceUniqueId,
+ final CapabilityDataDefinition capabilityDataDefinition) {
+
+ final GraphVertex containerVertex = findComponentVertex(componentId).orElse(null);
+ if (containerVertex == null) {
+ throw new OperationException(ActionStatus.COMPONENT_NOT_FOUND, componentId);
+ }
+
+ final Pair<GraphVertex, Map<String, MapListCapabilityDataDefinition>> capabilityVertexAndDataPair =
+ findCapabilityVertex(containerVertex).orElse(null);
+ if (capabilityVertexAndDataPair == null) {
+ throw new OperationException(ActionStatus.CAPABILITY_OF_INSTANCE_NOT_FOUND_ON_CONTAINER, capabilityDataDefinition.getName(),
+ capabilityDataDefinition.getOwnerName(), componentId);
+ }
+ final GraphVertex capabilitiesVertex = capabilityVertexAndDataPair.getLeft();
+ final Map<String, MapListCapabilityDataDefinition> capabilityDataMap = capabilityVertexAndDataPair.getRight();
+
+ final CapabilityDataDefinition actualCapabilityDataDefinition =
+ findCapability(capabilityDataMap, componentInstanceUniqueId, capabilityDataDefinition.getType(), capabilityDataDefinition.getUniqueId())
+ .orElse(null);
+ if (actualCapabilityDataDefinition == null) {
+ throw new OperationException(ActionStatus.CAPABILITY_OF_INSTANCE_NOT_FOUND_ON_CONTAINER, capabilityDataDefinition.getName(),
+ capabilityDataDefinition.getOwnerName(), componentId);
+ }
+ bindCapabilityDefinition(capabilityDataDefinition, actualCapabilityDataDefinition);
+
+ var storageOperationStatus = updateCapabilityVertex(containerVertex, capabilitiesVertex);
+ if (storageOperationStatus != StorageOperationStatus.OK) {
+ throw new OperationException(ActionStatus.COMPONENT_INSTANCE_CAPABILITY_UPDATE_ERROR, capabilityDataDefinition.getName());
+ }
+ return new CapabilityDataDefinition(actualCapabilityDataDefinition);
+ }
+
+ private void bindCapabilityDefinition(final CapabilityDataDefinition fromCapabilityDefinition,
+ final CapabilityDataDefinition capabilityDefinitionToUpdate) {
+ capabilityDefinitionToUpdate.setExternal(fromCapabilityDefinition.isExternal());
+ }
+
+ private Optional<GraphVertex> findComponentVertex(final String componentId) {
+ final Either<GraphVertex, JanusGraphOperationStatus> componentEither = janusGraphDao.getVertexById(componentId, JsonParseFlagEnum.ParseAll);
+ if (componentEither.isRight()) {
+ final JanusGraphOperationStatus error = componentEither.right().value();
+ CommonUtility.addRecordToLog(log, LogLevelEnum.DEBUG, FAILED_TO_FETCH_CONTAINER_VERTEX_ERROR, componentId, error);
+ if (error == JanusGraphOperationStatus.NOT_FOUND) {
+ return Optional.empty();
+ }
+ log.error(EcompLoggerErrorCode.BUSINESS_PROCESS_ERROR, NodeTemplateOperation.class.getName(), (ErrorLogOptionalData) null,
+ FAILED_TO_FETCH_CONTAINER_VERTEX_ERROR, componentId, error);
+ throw new OperationException(ActionStatus.COMPONENT_FIND_ERROR, componentId);
+ }
+ return Optional.ofNullable(componentEither.left().value());
+ }
+
+ private Optional<Pair<GraphVertex, Map<String, MapListCapabilityDataDefinition>>> findCapabilityVertex(final GraphVertex containerVertex) {
+
+ final Either<Pair<GraphVertex, Map<String, MapListCapabilityDataDefinition>>, StorageOperationStatus> capabilitiesEither =
+ fetchContainerCalculatedCapability(containerVertex, EdgeLabelEnum.CALCULATED_CAPABILITIES);
+ if (capabilitiesEither.isRight()) {
+ final StorageOperationStatus error = capabilitiesEither.right().value();
+ if (error == StorageOperationStatus.NOT_FOUND) {
+ return Optional.empty();
+ }
+ log.error(EcompLoggerErrorCode.BUSINESS_PROCESS_ERROR, NodeTemplateOperation.class.getName(), (ErrorLogOptionalData) null,
+ FAILED_TO_FETCH_CONTAINER_VERTEX_ERROR, containerVertex.getUniqueId(), error);
+ throw new OperationException(ActionStatus.COMPONENT_CAPABILITIES_FIND_ERROR, containerVertex.getUniqueId());
+ }
+ return Optional.ofNullable(capabilitiesEither.left().value());
+ }
+
+ private Optional<CapabilityDataDefinition> findCapability(final Map<String, MapListCapabilityDataDefinition> capabilityMap,
+ final String componentInstanceUniqueId,
+ final String capabilityType,
+ final String capabilityUniqueId) {
+ var componentInstanceCapabilitiesMap = capabilityMap.get(componentInstanceUniqueId);
+ if (componentInstanceCapabilitiesMap == null || componentInstanceCapabilitiesMap.isEmpty()) {
+ return Optional.empty();
+ }
+ var listCapabilityDataDefinition = componentInstanceCapabilitiesMap.getMapToscaDataDefinition().get(capabilityType);
+ if (listCapabilityDataDefinition == null || listCapabilityDataDefinition.isEmpty()) {
+ return Optional.empty();
+ }
+
+ return listCapabilityDataDefinition.getListToscaDataDefinition().stream()
+ .filter(e -> e.getUniqueId().equals(capabilityUniqueId))
+ .findFirst();
+ }
+
public StorageOperationStatus updateComponentInstanceRequirement(String componentId, String componentInstanceUniqueId,
RequirementDataDefinition requirementDataDefinition) {
Either<GraphVertex, JanusGraphOperationStatus> containerVEither = janusGraphDao
@@ -1143,6 +1236,27 @@ public class NodeTemplateOperation extends BaseOperation {
return StorageOperationStatus.OK;
}
+ private StorageOperationStatus updateCapabilityVertex(final GraphVertex containerVertex, final GraphVertex capabilitiesVertex) {
+ containerVertex.setJsonMetadataField(JsonPresentationFields.LAST_UPDATE_DATE, System.currentTimeMillis());
+ final Either<GraphVertex, JanusGraphOperationStatus> updateElement = janusGraphDao.updateVertex(containerVertex);
+ if (updateElement.isRight()) {
+ CommonUtility.addRecordToLog(log, LogLevelEnum.DEBUG, "Failed to update topology template '{}' with new capabilities. Error '{}'.",
+ containerVertex.getUniqueId(), updateElement.right().value());
+ return DaoStatusConverter.convertJanusGraphStatusToStorageStatus(updateElement.right().value());
+ }
+
+ final Either<GraphVertex, JanusGraphOperationStatus> statusEither =
+ updateOrCopyOnUpdate(capabilitiesVertex, containerVertex, EdgeLabelEnum.CALCULATED_CAPABILITIES);
+ if (statusEither.isRight()) {
+ JanusGraphOperationStatus error = statusEither.right().value();
+ CommonUtility.addRecordToLog(log, LogLevelEnum.DEBUG,
+ "Failed to update calculated capability for container {} error {}", containerVertex.getUniqueId(), error);
+ return DaoStatusConverter.convertJanusGraphStatusToStorageStatus(error);
+ }
+ CommonUtility.addRecordToLog(log, LogLevelEnum.DEBUG, "Updated calculated capability for container '{}'", containerVertex.getUniqueId());
+ return StorageOperationStatus.OK;
+ }
+
private StorageOperationStatus addComponentInstanceToscaDataToNodeTypeContainer(NodeType originNodeType,
ComponentInstanceDataDefinition componentInstance,
GraphVertex updatedContainerVertex) {
diff --git a/catalog-model/src/main/java/org/openecomp/sdc/be/model/jsonjanusgraph/operations/ToscaOperationFacade.java b/catalog-model/src/main/java/org/openecomp/sdc/be/model/jsonjanusgraph/operations/ToscaOperationFacade.java
index 06e23f04ea..205a48e9b2 100644
--- a/catalog-model/src/main/java/org/openecomp/sdc/be/model/jsonjanusgraph/operations/ToscaOperationFacade.java
+++ b/catalog-model/src/main/java/org/openecomp/sdc/be/model/jsonjanusgraph/operations/ToscaOperationFacade.java
@@ -112,6 +112,7 @@ 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.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.StorageOperationStatus;
@@ -2963,6 +2964,12 @@ public class ToscaOperationFacade {
return nodeTemplateOperation.updateComponentInstanceRequirement(containerComponentId, componentInstanceUniqueId, requirementDataDefinition);
}
+ public CapabilityDataDefinition updateComponentInstanceCapability(final String containerComponentId, final String componentInstanceUniqueId,
+ final CapabilityDataDefinition capabilityDataDefinition) {
+
+ return nodeTemplateOperation.updateComponentInstanceCapabilities(containerComponentId, componentInstanceUniqueId, capabilityDataDefinition);
+ }
+
public StorageOperationStatus updateComponentInstanceInterfaces(Component containerComponent, String componentInstanceUniqueId) {
MapInterfaceDataDefinition mapInterfaceDataDefinition = convertComponentInstanceInterfaces(containerComponent, componentInstanceUniqueId);
return topologyTemplateOperation.updateComponentInstanceInterfaces(containerComponent, componentInstanceUniqueId, mapInterfaceDataDefinition);
diff --git a/catalog-model/src/main/java/org/openecomp/sdc/be/model/jsonjanusgraph/operations/exception/OperationException.java b/catalog-model/src/main/java/org/openecomp/sdc/be/model/jsonjanusgraph/operations/exception/OperationException.java
new file mode 100644
index 0000000000..30323af521
--- /dev/null
+++ b/catalog-model/src/main/java/org/openecomp/sdc/be/model/jsonjanusgraph/operations/exception/OperationException.java
@@ -0,0 +1,42 @@
+/*
+ * ============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 lombok.Getter;
+import org.openecomp.sdc.be.dao.api.ActionStatus;
+import org.openecomp.sdc.be.exception.BusinessException;
+
+@Getter
+public class OperationException extends BusinessException {
+
+ private final ActionStatus actionStatus;
+ private final String[] params;
+
+ public OperationException(final String message) {
+ super(message);
+ actionStatus = ActionStatus.GENERAL_ERROR;
+ params = new String[0];
+ }
+
+ public OperationException(final ActionStatus actionStatus, String... params) {
+ this.actionStatus = actionStatus;
+ this.params = params;
+ }
+}
diff --git a/catalog-model/src/main/java/org/openecomp/sdc/be/ui/mapper/CapabilityMapper.java b/catalog-model/src/main/java/org/openecomp/sdc/be/ui/mapper/CapabilityMapper.java
new file mode 100644
index 0000000000..4df93829fa
--- /dev/null
+++ b/catalog-model/src/main/java/org/openecomp/sdc/be/ui/mapper/CapabilityMapper.java
@@ -0,0 +1,40 @@
+/*
+ * ============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.ui.mapper;
+
+import org.openecomp.sdc.be.model.CapabilityDefinition;
+import org.openecomp.sdc.be.ui.model.ComponentInstanceCapabilityUpdateModel;
+import org.springframework.stereotype.Service;
+
+@Service
+public class CapabilityMapper {
+
+ public CapabilityDefinition mapToCapabilityDefinition(final ComponentInstanceCapabilityUpdateModel capabilityUpdateModel) {
+ var capabilityDefinition = new CapabilityDefinition();
+ capabilityDefinition.setUniqueId(capabilityUpdateModel.getUniqueId());
+ capabilityDefinition.setType(capabilityUpdateModel.getType());
+ capabilityDefinition.setOwnerId(capabilityUpdateModel.getOwnerId());
+ capabilityDefinition.setOwnerName(capabilityUpdateModel.getOwnerName());
+ capabilityDefinition.setName(capabilityUpdateModel.getName());
+ capabilityDefinition.setExternal(capabilityUpdateModel.getExternal());
+ return capabilityDefinition;
+ }
+
+}
diff --git a/catalog-model/src/main/java/org/openecomp/sdc/be/ui/model/ComponentInstanceCapabilityUpdateModel.java b/catalog-model/src/main/java/org/openecomp/sdc/be/ui/model/ComponentInstanceCapabilityUpdateModel.java
new file mode 100644
index 0000000000..3fd74cd9e2
--- /dev/null
+++ b/catalog-model/src/main/java/org/openecomp/sdc/be/ui/model/ComponentInstanceCapabilityUpdateModel.java
@@ -0,0 +1,50 @@
+/*
+ * ============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.ui.model;
+
+import javax.validation.constraints.NotNull;
+import javax.validation.constraints.Size;
+import lombok.Data;
+
+/**
+ * Model for the component instance capability update request
+ */
+@Data
+public class ComponentInstanceCapabilityUpdateModel {
+
+ @NotNull
+ @Size(min=1)
+ private String type;
+ @NotNull
+ @Size(min=1)
+ private String name;
+ @NotNull
+ @Size(min=1)
+ private String ownerId;
+ @NotNull
+ @Size(min=1)
+ private String ownerName;
+ @NotNull
+ @Size(min=1)
+ private String uniqueId;
+ @NotNull
+ private Boolean external;
+
+}
diff --git a/catalog-model/src/test/java/org/openecomp/sdc/be/model/jsonjanusgraph/operations/NodeTemplateOperationTest.java b/catalog-model/src/test/java/org/openecomp/sdc/be/model/jsonjanusgraph/operations/NodeTemplateOperationTest.java
index cf4d6b22bf..5a02c5752f 100644
--- a/catalog-model/src/test/java/org/openecomp/sdc/be/model/jsonjanusgraph/operations/NodeTemplateOperationTest.java
+++ b/catalog-model/src/test/java/org/openecomp/sdc/be/model/jsonjanusgraph/operations/NodeTemplateOperationTest.java
@@ -29,12 +29,29 @@
*/
package org.openecomp.sdc.be.model.jsonjanusgraph.operations;
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertNotNull;
+import static org.junit.jupiter.api.Assertions.assertSame;
+import static org.junit.jupiter.api.Assertions.assertThrows;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+import static org.mockito.ArgumentMatchers.anyString;
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.spy;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
import com.google.common.collect.Lists;
import fj.data.Either;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
import org.apache.commons.lang3.tuple.ImmutablePair;
import org.apache.tinkerpop.gremlin.structure.Direction;
import org.apache.tinkerpop.gremlin.structure.Edge;
-import org.apache.tinkerpop.gremlin.structure.Vertex;
import org.janusgraph.core.JanusGraphVertex;
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.Test;
@@ -43,46 +60,48 @@ import org.junit.jupiter.api.TestInstance.Lifecycle;
import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.ArgumentMatchers;
import org.mockito.InjectMocks;
-import org.mockito.Mock;
import org.mockito.Mockito;
-import org.mockito.junit.MockitoJUnitRunner;
import org.mockito.junit.jupiter.MockitoExtension;
+import org.openecomp.sdc.be.config.ConfigurationManager;
+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.jsongraph.JanusGraphDao;
import org.openecomp.sdc.be.dao.jsongraph.types.EdgeLabelEnum;
import org.openecomp.sdc.be.dao.jsongraph.types.JsonParseFlagEnum;
import org.openecomp.sdc.be.dao.jsongraph.types.VertexTypeEnum;
-import org.openecomp.sdc.be.datatypes.elements.*;
+import org.openecomp.sdc.be.datatypes.elements.ArtifactDataDefinition;
+import org.openecomp.sdc.be.datatypes.elements.CapabilityDataDefinition;
+import org.openecomp.sdc.be.datatypes.elements.ComponentInstanceDataDefinition;
+import org.openecomp.sdc.be.datatypes.elements.ListCapabilityDataDefinition;
+import org.openecomp.sdc.be.datatypes.elements.ListRequirementDataDefinition;
+import org.openecomp.sdc.be.datatypes.elements.MapArtifactDataDefinition;
+import org.openecomp.sdc.be.datatypes.elements.MapListCapabilityDataDefinition;
+import org.openecomp.sdc.be.datatypes.elements.MapListRequirementDataDefinition;
+import org.openecomp.sdc.be.datatypes.elements.RequirementDataDefinition;
import org.openecomp.sdc.be.datatypes.enums.GraphPropertyEnum;
import org.openecomp.sdc.be.datatypes.enums.JsonPresentationFields;
import org.openecomp.sdc.be.datatypes.enums.ResourceTypeEnum;
-import org.openecomp.sdc.be.datatypes.tosca.ToscaDataDefinition;
-import org.openecomp.sdc.be.model.*;
+import org.openecomp.sdc.be.model.ArtifactDefinition;
+import org.openecomp.sdc.be.model.CapabilityDefinition;
+import org.openecomp.sdc.be.model.CapabilityRequirementRelationship;
+import org.openecomp.sdc.be.model.Component;
+import org.openecomp.sdc.be.model.ComponentInstance;
+import org.openecomp.sdc.be.model.ComponentInstanceAttribute;
+import org.openecomp.sdc.be.model.ComponentInstanceOutput;
+import org.openecomp.sdc.be.model.GroupDefinition;
+import org.openecomp.sdc.be.model.ModelTestBase;
+import org.openecomp.sdc.be.model.RelationshipImpl;
+import org.openecomp.sdc.be.model.RelationshipInfo;
+import org.openecomp.sdc.be.model.RequirementCapabilityRelDef;
+import org.openecomp.sdc.be.model.Resource;
+import org.openecomp.sdc.be.model.User;
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.operations.exception.OperationException;
import org.openecomp.sdc.be.model.operations.api.StorageOperationStatus;
import org.openecomp.sdc.common.api.ArtifactGroupTypeEnum;
-import java.util.ArrayList;
-import java.util.HashMap;
-import java.util.Iterator;
-import java.util.List;
-import java.util.Map;
-
-import static org.codehaus.groovy.runtime.DefaultGroovyMethods.any;
-import static org.junit.jupiter.api.Assertions.assertEquals;
-import static org.junit.jupiter.api.Assertions.assertNotNull;
-import static org.junit.jupiter.api.Assertions.assertSame;
-import static org.junit.jupiter.api.Assertions.assertTrue;
-import static org.mockito.ArgumentMatchers.anyList;
-import static org.mockito.ArgumentMatchers.anyString;
-import static org.mockito.ArgumentMatchers.eq;
-import static org.mockito.Mockito.doReturn;
-import static org.mockito.Mockito.times;
-import static org.mockito.Mockito.verify;
-import static org.mockito.Mockito.when;
-
@ExtendWith(MockitoExtension.class)
@TestInstance(Lifecycle.PER_CLASS)
class NodeTemplateOperationTest extends ModelTestBase {
@@ -205,10 +224,8 @@ class NodeTemplateOperationTest extends ModelTestBase {
@Test
void testGetDefaultHeatTimeout() {
- Integer result;
-
- // default test
- result = NodeTemplateOperation.getDefaultHeatTimeout();
+ assertEquals(ConfigurationManager.getConfigurationManager().getConfiguration().getHeatArtifactDeploymentTimeout().getDefaultMinutes(),
+ NodeTemplateOperation.getDefaultHeatTimeout());
}
@Test
@@ -234,13 +251,8 @@ class NodeTemplateOperationTest extends ModelTestBase {
}
@Test
- void testCreateCapPropertyKey() throws Exception {
- String key = "";
- String instanceId = "";
- String result;
-
- // default test
- result = NodeTemplateOperation.createCapPropertyKey(key, instanceId);
+ void testCreateCapPropertyKey() {
+ assertEquals("instanceId#instanceId#key", NodeTemplateOperation.createCapPropertyKey("key", "instanceId"));
}
@Test
@@ -438,6 +450,119 @@ class NodeTemplateOperationTest extends ModelTestBase {
eq(componentInstanceOutputList), ArgumentMatchers.anyList(), eq(JsonPresentationFields.NAME));
}
+ @Test
+ void updateComponentInstanceCapabilitiesSuccessTest() {
+ final var capabilityUniqueId = "capabilityUniqueId";
+ final var capabilityType = "capabilityType";
+ final var componentInstanceId = "componentInstanceId";
+
+ final var nodeTemplateOperation = spy(operation);
+ final var capabilityDefinitionDatabase = new CapabilityDataDefinition();
+ capabilityDefinitionDatabase.setUniqueId(capabilityUniqueId);
+ capabilityDefinitionDatabase.setType(capabilityType);
+ capabilityDefinitionDatabase.setExternal(false);
+ final var capabilityDefinitionToUpdate = new CapabilityDataDefinition();
+ capabilityDefinitionToUpdate.setUniqueId(capabilityUniqueId);
+ capabilityDefinitionToUpdate.setType(capabilityType);
+ capabilityDefinitionToUpdate.setExternal(true);
+ final Map<String, MapListCapabilityDataDefinition> capabilityByInstanceMap = new HashMap<>();
+ var mapListCapabilityDataDefinition = new MapListCapabilityDataDefinition();
+ mapListCapabilityDataDefinition.add(capabilityDefinitionDatabase.getType(), capabilityDefinitionDatabase);
+ capabilityByInstanceMap.put(componentInstanceId, mapListCapabilityDataDefinition);
+
+ final GraphVertex componentVertex = Mockito.mock(GraphVertex.class);
+ final GraphVertex capabilitiesVertex = Mockito.mock(GraphVertex.class);
+ doReturn(capabilityByInstanceMap).when(capabilitiesVertex).getJson();
+ when(janusGraphDao.getVertexById(COMPONENT_ID, JsonParseFlagEnum.ParseAll)).thenReturn(Either.left(componentVertex));
+ when(janusGraphDao.getChildVertex(componentVertex, EdgeLabelEnum.CALCULATED_CAPABILITIES, JsonParseFlagEnum.ParseJson))
+ .thenReturn(Either.left(capabilitiesVertex));
+ when(janusGraphDao.updateVertex(componentVertex)).thenReturn(Either.left(componentVertex));
+ doReturn(Either.left(capabilitiesVertex))
+ .when(nodeTemplateOperation).updateOrCopyOnUpdate(capabilitiesVertex, componentVertex, EdgeLabelEnum.CALCULATED_CAPABILITIES);
+ final CapabilityDataDefinition actualCapabilityDataDefinition = nodeTemplateOperation
+ .updateComponentInstanceCapabilities(COMPONENT_ID, componentInstanceId, capabilityDefinitionToUpdate);
+ assertTrue(actualCapabilityDataDefinition.isExternal());
+ }
+
+ @Test
+ void updateComponentInstanceCapabilitiesTest_capabilityNotFound() {
+ final var componentInstanceId = "componentInstanceId";
+ var capabilityDataDefinition = new CapabilityDataDefinition();
+ capabilityDataDefinition.setType("aCapabilityType");
+ final GraphVertex componentVertex = Mockito.mock(GraphVertex.class);
+ final GraphVertex calculatedCapabilityVertex = Mockito.mock(GraphVertex.class);
+ //no capabilities found
+ when(janusGraphDao.getVertexById(COMPONENT_ID, JsonParseFlagEnum.ParseAll)).thenReturn(Either.left(componentVertex));
+ when(janusGraphDao.getChildVertex(componentVertex, EdgeLabelEnum.CALCULATED_CAPABILITIES, JsonParseFlagEnum.ParseJson))
+ .thenReturn(Either.right(JanusGraphOperationStatus.NOT_FOUND));
+ OperationException actualException = assertThrows(OperationException.class, () ->
+ operation.updateComponentInstanceCapabilities(COMPONENT_ID, componentInstanceId, capabilityDataDefinition));
+ assertEquals(ActionStatus.CAPABILITY_OF_INSTANCE_NOT_FOUND_ON_CONTAINER, actualException.getActionStatus());
+ assertEquals(actualException.getParams().length, 3);
+ assertEquals(capabilityDataDefinition.getName(), actualException.getParams()[0]);
+ assertEquals(capabilityDataDefinition.getOwnerName(), actualException.getParams()[1]);
+ assertEquals(COMPONENT_ID, actualException.getParams()[2]);
+
+ //found capabilities, but not for the provided instance id
+ when(janusGraphDao.getChildVertex(componentVertex, EdgeLabelEnum.CALCULATED_CAPABILITIES, JsonParseFlagEnum.ParseJson))
+ .thenReturn(Either.left(calculatedCapabilityVertex));
+ actualException = assertThrows(OperationException.class, () ->
+ operation.updateComponentInstanceCapabilities(COMPONENT_ID, "componentInstanceId", capabilityDataDefinition));
+ assertEquals(ActionStatus.CAPABILITY_OF_INSTANCE_NOT_FOUND_ON_CONTAINER, actualException.getActionStatus());
+ assertEquals(actualException.getParams().length, 3);
+ assertEquals(capabilityDataDefinition.getName(), actualException.getParams()[0]);
+ assertEquals(capabilityDataDefinition.getOwnerName(), actualException.getParams()[1]);
+ assertEquals(COMPONENT_ID, actualException.getParams()[2]);
+
+ //found capabilities for the instance id, but not with the provided capability type
+ final Map<String, MapListCapabilityDataDefinition> capabilityByInstanceMap = new HashMap<>();
+ var mapListCapabilityDataDefinition = new MapListCapabilityDataDefinition();
+ mapListCapabilityDataDefinition.add("anotherCapabilityType", new CapabilityDataDefinition());
+ capabilityByInstanceMap.put(componentInstanceId, mapListCapabilityDataDefinition);
+ doReturn(capabilityByInstanceMap).when(calculatedCapabilityVertex).getJson();
+ actualException = assertThrows(OperationException.class, () ->
+ operation.updateComponentInstanceCapabilities(COMPONENT_ID, "componentInstanceId", capabilityDataDefinition));
+ assertEquals(ActionStatus.CAPABILITY_OF_INSTANCE_NOT_FOUND_ON_CONTAINER, actualException.getActionStatus());
+ assertEquals(actualException.getParams().length, 3);
+ assertEquals(capabilityDataDefinition.getName(), actualException.getParams()[0]);
+ assertEquals(capabilityDataDefinition.getOwnerName(), actualException.getParams()[1]);
+ assertEquals(COMPONENT_ID, actualException.getParams()[2]);
+ }
+
+ @Test
+ void updateComponentInstanceCapabilitiesTest_capabilityFindError() {
+ final GraphVertex componentVertex = Mockito.mock(GraphVertex.class);
+ when(componentVertex.getUniqueId()).thenReturn(COMPONENT_ID);
+ when(janusGraphDao.getVertexById(COMPONENT_ID, JsonParseFlagEnum.ParseAll)).thenReturn(Either.left(componentVertex));
+ when(janusGraphDao.getChildVertex(componentVertex, EdgeLabelEnum.CALCULATED_CAPABILITIES, JsonParseFlagEnum.ParseJson))
+ .thenReturn(Either.right(JanusGraphOperationStatus.GENERAL_ERROR));
+ final OperationException actualException = assertThrows(OperationException.class, () ->
+ operation.updateComponentInstanceCapabilities(COMPONENT_ID, "componentInstanceId", new CapabilityDataDefinition()));
+ assertEquals(ActionStatus.COMPONENT_CAPABILITIES_FIND_ERROR, actualException.getActionStatus());
+ assertEquals(actualException.getParams().length, 1);
+ assertEquals(COMPONENT_ID, actualException.getParams()[0]);
+ }
+
+ @Test
+ void updateComponentInstanceCapabilitiesTest_componentNotFound() {
+ when(janusGraphDao.getVertexById(COMPONENT_ID, JsonParseFlagEnum.ParseAll)).thenReturn(Either.right(JanusGraphOperationStatus.NOT_FOUND));
+ final OperationException actualException = assertThrows(OperationException.class, () ->
+ operation.updateComponentInstanceCapabilities(COMPONENT_ID, "componentInstanceId", new CapabilityDataDefinition()));
+ assertEquals(ActionStatus.COMPONENT_NOT_FOUND, actualException.getActionStatus());
+ assertEquals(actualException.getParams().length, 1);
+ assertEquals(COMPONENT_ID, actualException.getParams()[0]);
+ }
+
+ @Test
+ void updateComponentInstanceCapabilitiesTest_componentFindError() {
+ when(janusGraphDao.getVertexById(COMPONENT_ID, JsonParseFlagEnum.ParseAll)).thenReturn(Either.right(JanusGraphOperationStatus.GENERAL_ERROR));
+ final OperationException actualException = assertThrows(OperationException.class, () ->
+ operation.updateComponentInstanceCapabilities(COMPONENT_ID, "componentInstanceId", new CapabilityDataDefinition()));
+ assertEquals(ActionStatus.COMPONENT_FIND_ERROR, actualException.getActionStatus());
+ assertEquals(actualException.getParams().length, 1);
+ assertEquals(COMPONENT_ID, actualException.getParams()[0]);
+ }
+
private ComponentInstance createCompInstance() {
ComponentInstance componentInstance = new ComponentInstance();
String id = "id";
diff --git a/catalog-model/src/test/java/org/openecomp/sdc/be/ui/mapper/CapabilityMapperTest.java b/catalog-model/src/test/java/org/openecomp/sdc/be/ui/mapper/CapabilityMapperTest.java
new file mode 100644
index 0000000000..6e147281b8
--- /dev/null
+++ b/catalog-model/src/test/java/org/openecomp/sdc/be/ui/mapper/CapabilityMapperTest.java
@@ -0,0 +1,60 @@
+/*
+ * ============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.ui.mapper;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+import org.openecomp.sdc.be.model.CapabilityDefinition;
+import org.openecomp.sdc.be.ui.model.ComponentInstanceCapabilityUpdateModel;
+
+class CapabilityMapperTest {
+
+ private CapabilityMapper capabilityMapper;
+
+ @BeforeEach
+ void beforeEach() {
+ capabilityMapper = new CapabilityMapper();
+ }
+
+ @Test
+ void mapToCapabilityDefinitionTest() {
+ final ComponentInstanceCapabilityUpdateModel capabilityUpdateModel = new ComponentInstanceCapabilityUpdateModel();
+ capabilityUpdateModel.setUniqueId("uniqueId");
+ capabilityUpdateModel.setName("name");
+ capabilityUpdateModel.setExternal(true);
+ capabilityUpdateModel.setOwnerId("ownerId");
+ capabilityUpdateModel.setType("type");
+ capabilityUpdateModel.setOwnerName("ownerName");
+ final CapabilityDefinition capabilityDefinition = capabilityMapper.mapToCapabilityDefinition(capabilityUpdateModel);
+ assertCapabilityDefinition(capabilityDefinition, capabilityUpdateModel);
+ }
+
+ private void assertCapabilityDefinition(final CapabilityDefinition actualCapabilityDefinition,
+ final ComponentInstanceCapabilityUpdateModel expectedCapabilityDefinition) {
+ assertEquals(expectedCapabilityDefinition.getUniqueId(), actualCapabilityDefinition.getUniqueId());
+ assertEquals(expectedCapabilityDefinition.getName(), actualCapabilityDefinition.getName());
+ assertEquals(expectedCapabilityDefinition.getOwnerId(), actualCapabilityDefinition.getOwnerId());
+ assertEquals(expectedCapabilityDefinition.getOwnerName(), actualCapabilityDefinition.getOwnerName());
+ assertEquals(expectedCapabilityDefinition.getType(), actualCapabilityDefinition.getType());
+ assertEquals(expectedCapabilityDefinition.getExternal(), actualCapabilityDefinition.isExternal());
+ }
+} \ No newline at end of file
diff --git a/catalog-ui/src/app/models/capability.ts b/catalog-ui/src/app/models/capability.ts
index f365dc4940..b377ed9edd 100644
--- a/catalog-ui/src/app/models/capability.ts
+++ b/catalog-ui/src/app/models/capability.ts
@@ -62,6 +62,7 @@ export class Capability implements RequirementCapabilityModel {
description: string;
validSourceTypes: string[];
properties: PropertyModel[];
+ external: boolean;
// custom
selected: boolean;
@@ -84,6 +85,7 @@ export class Capability implements RequirementCapabilityModel {
this.description = capability.description;
this.validSourceTypes = capability.validSourceTypes;
this.selected = capability.selected;
+ this.external = capability.external;
this.initFilterTerm();
}
diff --git a/catalog-ui/src/app/ng2/pages/composition/graph/composition-graph.component.ts b/catalog-ui/src/app/ng2/pages/composition/graph/composition-graph.component.ts
index 3cab4b300f..8d2357d6ad 100644
--- a/catalog-ui/src/app/ng2/pages/composition/graph/composition-graph.component.ts
+++ b/catalog-ui/src/app/ng2/pages/composition/graph/composition-graph.component.ts
@@ -25,7 +25,8 @@ import {
ZoneInstanceAssignmentType,
ZoneInstanceMode,
ZoneInstanceType,
- Requirement
+ Requirement,
+ Capability
} from 'app/models';
import { ForwardingPath } from 'app/models/forwarding-path';
import { CompositionCiServicePathLink } from 'app/models/graph/graph-links/composition-graph-links/composition-ci-service-path-link';
@@ -649,6 +650,14 @@ export class CompositionGraphComponent implements AfterViewInit {
.find(r => r.uniqueId === requirement.uniqueId).external = requirement.external;
});
+ this.eventListenerService.registerObserverCallback(GRAPH_EVENTS.ON_COMPONENT_INSTANCE_CAPABILITY_EXTERNAL_CHANGED,
+ (uniqueId: string, capability: Capability) => {
+ const graphCapability = this._cy.getElementById(uniqueId).data()
+ .componentInstance.capabilities[capability.type].find(cap => cap.uniqueId === capability.uniqueId);
+ graphCapability.external = capability.external;
+ }
+ );
+
this.eventListenerService.registerObserverCallback(GRAPH_EVENTS.ON_DELETE_COMPONENT_INSTANCE, (componentInstanceId: string) => {
const nodeToDelete = this._cy.getElementById(componentInstanceId);
this.nodesGraphUtils.deleteNode(this._cy, this.topologyTemplate, nodeToDelete);
diff --git a/catalog-ui/src/app/ng2/pages/composition/panel/panel-tabs/req-capabilities-tab/req-capabilities-tab.component.html b/catalog-ui/src/app/ng2/pages/composition/panel/panel-tabs/req-capabilities-tab/req-capabilities-tab.component.html
index c73f69734f..ad25aabefd 100644
--- a/catalog-ui/src/app/ng2/pages/composition/panel/panel-tabs/req-capabilities-tab/req-capabilities-tab.component.html
+++ b/catalog-ui/src/app/ng2/pages/composition/panel/panel-tabs/req-capabilities-tab/req-capabilities-tab.component.html
@@ -5,6 +5,16 @@
<div *ngFor="let capability of capabilities" class="relations-details-container">
<div class="relations-name">{{capability.name}}&nbsp;</div>
<div class="relations-desc"> {{capability.type}} </div>
+ <div class="checkbox-label-mark-as-external" *ngIf="isComponentInstanceSelected">
+ <checkbox
+ class="checkbox-label"
+ [attr.data-tests-id]="'checkbox-external-cap-' + capability.name"
+ [label]="'External'"
+ (checkedChange)="onMarkCapabilityAsExternal(capability)"
+ [(checked)]="capability.external"
+ [disabled]="isViewOnly">
+ </checkbox>
+ </div>
</div>
</sdc-accordion>
</div>
@@ -19,10 +29,20 @@
<ng-template #complexComponentTemplate>
<sdc-accordion *ngIf="capabilitiesInstancesMap" [title]="'Capabilities'" [arrow-direction]="'right'" [testId]="'Capabilities-accordion'">
<sdc-accordion *ngFor="let key of objectKeys(capabilitiesInstancesMap); let i = index" [title]="key">
- <div *ngFor="let capability of capabilitiesInstancesMap[key]" class="relations-details-container">
- <div class="relations-name">{{capability.name}}&nbsp;</div>
- <div class="relations-desc"> {{capability.type}} </div>
- </div>
+ <div *ngFor="let capability of capabilitiesInstancesMap[key]" class="relations-details-container">
+ <div class="relations-name">{{capability.name}}&nbsp;</div>
+ <div class="relations-desc"> {{capability.type}} </div>
+ <div class="checkbox-label-mark-as-external" *ngIf="isComponentInstanceSelected">
+ <checkbox
+ class="checkbox-label"
+ [attr.data-tests-id]="'checkbox-external-cap-' + capability.name"
+ [label]="'External'"
+ (checkedChange)="onMarkCapabilityAsExternal(capability)"
+ [(checked)]="capability.external"
+ [disabled]="isViewOnly">
+ </checkbox>
+ </div>
+ </div>
</sdc-accordion>
</sdc-accordion>
diff --git a/catalog-ui/src/app/ng2/pages/composition/panel/panel-tabs/req-capabilities-tab/req-capabilities-tab.component.ts b/catalog-ui/src/app/ng2/pages/composition/panel/panel-tabs/req-capabilities-tab/req-capabilities-tab.component.ts
index 7c91cbc4b8..7bb88c7f59 100644
--- a/catalog-ui/src/app/ng2/pages/composition/panel/panel-tabs/req-capabilities-tab/req-capabilities-tab.component.ts
+++ b/catalog-ui/src/app/ng2/pages/composition/panel/panel-tabs/req-capabilities-tab/req-capabilities-tab.component.ts
@@ -1,5 +1,5 @@
import { Component, OnInit, Input, OnDestroy } from '@angular/core';
-import { Component as TopologyTemplate, Capability, Requirement, CapabilitiesGroup, RequirementsGroup, ComponentInstance, FullComponentInstance } from "app/models";
+import { Component as TopologyTemplate, Capability, Requirement, CapabilitiesGroup, RequirementsGroup, FullComponentInstance } from "app/models";
import { Store } from "@ngxs/store";
import { GRAPH_EVENTS } from "app/utils";
import { ComponentGenericResponse } from "app/ng2/services/responses/component-generic-response";
@@ -8,6 +8,7 @@ import { EventListenerService } from "app/services";
import { WorkspaceService } from "app/ng2/pages/workspace/workspace.service";
import { CompositionService } from "app/ng2/pages/composition/composition.service";
import {SelectedComponentType, TogglePanelLoadingAction} from "../../../common/store/graph.actions";
+import {ComponentInstanceServiceNg2} from "../../../../../services/component-instance-services/component-instance.service";
export class InstanceCapabilitiesMap {
@@ -42,7 +43,8 @@ export class ReqAndCapabilitiesTabComponent implements OnInit, OnDestroy {
private topologyTemplateService:TopologyTemplateService,
private workspaceService: WorkspaceService,
private compositionService: CompositionService,
- private eventListenerService:EventListenerService) { }
+ private eventListenerService:EventListenerService,
+ private componentInstanceService: ComponentInstanceServiceNg2) { }
ngOnInit(): void {
@@ -112,13 +114,19 @@ export class ReqAndCapabilitiesTabComponent implements OnInit, OnDestroy {
private initInstancesMap = ():void => {
this.capabilitiesInstancesMap = new InstanceCapabilitiesMap();
- _.forEach(this.capabilities, (capability:Capability) => {
- if (this.capabilitiesInstancesMap[capability.ownerName]) {
- this.capabilitiesInstancesMap[capability.ownerName] = this.capabilitiesInstancesMap[capability.ownerName].concat(capability);
- } else {
- this.capabilitiesInstancesMap[capability.ownerName] = new Array<Capability>(capability);
+ let capabilityList: Array<Capability> = this.capabilities;
+ if (capabilityList) {
+ if (!this.isComponentInstanceSelected) {
+ capabilityList = capabilityList.filter(value => value.external);
}
- });
+ capabilityList.forEach(capability => {
+ if (this.capabilitiesInstancesMap[capability.ownerName]) {
+ this.capabilitiesInstancesMap[capability.ownerName] = this.capabilitiesInstancesMap[capability.ownerName].concat(capability);
+ } else {
+ this.capabilitiesInstancesMap[capability.ownerName] = new Array<Capability>(capability);
+ }
+ });
+ }
this.requirementsInstancesMap = new InstanceRequirementsMap();
_.forEach(this.requirements, (requirement:Requirement) => {
@@ -161,7 +169,21 @@ export class ReqAndCapabilitiesTabComponent implements OnInit, OnDestroy {
}
-
-
+ onMarkCapabilityAsExternal(capability: Capability) {
+ this.store.dispatch(new TogglePanelLoadingAction({isLoading: true}));
+ capability.external = !capability.external;
+ const componentId = this.workspaceService.metadata.uniqueId;
+ const componentInstanceId = this.component.uniqueId;
+ this.componentInstanceService
+ .updateInstanceCapability(this.workspaceService.metadata.getTypeUrl(), componentId, componentInstanceId, capability)
+ .subscribe(() => {
+ this.eventListenerService.notifyObservers(GRAPH_EVENTS.ON_COMPONENT_INSTANCE_CAPABILITY_EXTERNAL_CHANGED, componentInstanceId, capability);
+ this.store.dispatch(new TogglePanelLoadingAction({isLoading: false}));
+ } , (error) => {
+ console.error("An error has occurred while setting capability '" + capability.name + "' external", error);
+ capability.external = !capability.external;
+ this.store.dispatch(new TogglePanelLoadingAction({isLoading: false}));
+ });
+ }
}
diff --git a/catalog-ui/src/app/ng2/pages/composition/panel/panel-tabs/req-capabilities-tab/requirement-list/requirement-list.component.html b/catalog-ui/src/app/ng2/pages/composition/panel/panel-tabs/req-capabilities-tab/requirement-list/requirement-list.component.html
index ebaed0441a..ee8277971b 100644
--- a/catalog-ui/src/app/ng2/pages/composition/panel/panel-tabs/req-capabilities-tab/requirement-list/requirement-list.component.html
+++ b/catalog-ui/src/app/ng2/pages/composition/panel/panel-tabs/req-capabilities-tab/requirement-list/requirement-list.component.html
@@ -17,7 +17,7 @@
*ngIf="isInstanceSelected">
<checkbox
class="checkbox-label"
- [attr.data-tests-id]="'checkbox-mark-as-external-' + requirement.name"
+ [attr.data-tests-id]="'checkbox-external-req-' + requirement.name"
[label]="'External'"
(checkedChange)="onMarkAsExternal(requirement)"
[(checked)]="requirement.external"
diff --git a/catalog-ui/src/app/ng2/services/component-instance-services/component-instance.service.spec.ts b/catalog-ui/src/app/ng2/services/component-instance-services/component-instance.service.spec.ts
new file mode 100644
index 0000000000..4de556cdd5
--- /dev/null
+++ b/catalog-ui/src/app/ng2/services/component-instance-services/component-instance.service.spec.ts
@@ -0,0 +1,80 @@
+/*
+ * ============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=========================================================
+ */
+
+import {TestBed} from '@angular/core/testing';
+import {ISdcConfig, SdcConfigToken} from "../../config/sdc-config.config";
+import {ComponentInstanceServiceNg2} from "./component-instance.service";
+import {Capability} from "../../../models/capability";
+import {HttpClientTestingModule, HttpTestingController} from "@angular/common/http/testing";
+
+describe('ComponentInstanceServiceNg2', () => {
+ let httpTestingController: HttpTestingController;
+ let componentInstanceService: ComponentInstanceServiceNg2;
+ let rootApi: string = 'http://localhost/'
+ let componentApiRoot: string = 'catalog/'
+ beforeEach(() => {
+ const sdcConfigToken: Partial<ISdcConfig> = {
+ 'api': {
+ 'root': rootApi,
+ 'component_api_root': componentApiRoot,
+ }
+ };
+ TestBed.configureTestingModule({
+ providers: [ComponentInstanceServiceNg2,
+ {provide: SdcConfigToken, useValue: sdcConfigToken}
+ ],
+ imports: [HttpClientTestingModule]
+ });
+ httpTestingController = TestBed.get(HttpTestingController);
+ componentInstanceService = TestBed.get(ComponentInstanceServiceNg2);
+ });
+
+ it('should be created', () => {
+ expect(componentInstanceService).toBeTruthy();
+ });
+
+ it('updateInstanceCapability call should return the expected data', () => {
+ const capabilityToUpdate = new Capability();
+ capabilityToUpdate.type = "tosca.capabilities.Scalable";
+ capabilityToUpdate.name = "capScalable";
+ capabilityToUpdate.ownerId = "191f8a83-d362-4db4-af30-75d71a55c959.a822dd1c-3560-47ea-b8a2-f557fed5e186.vfcapreq10";
+ capabilityToUpdate.uniqueId = "2047eb3c-de31-4413-a358-8710a3dd2670";
+ capabilityToUpdate.external = true;
+
+ const componentTypeUrl = "services/";
+ let actualCapability: Capability;
+ componentInstanceService.updateInstanceCapability(componentTypeUrl, "componentId", "componentInstanceId", capabilityToUpdate)
+ .subscribe(capability => {
+ actualCapability = capability;
+ });
+
+ const request =
+ httpTestingController.expectOne(`${rootApi}${componentApiRoot}${componentTypeUrl}componentId/componentInstances/componentInstanceId/capability/`);
+
+ expect(request.request.method).toEqual('PUT');
+
+ request.flush(capabilityToUpdate);
+ expect(actualCapability.name).toEqual(capabilityToUpdate.name);
+ expect(actualCapability.type).toEqual(capabilityToUpdate.type);
+ expect(actualCapability.ownerId).toEqual(capabilityToUpdate.ownerId);
+ expect(actualCapability.uniqueId).toEqual(capabilityToUpdate.uniqueId);
+ expect(actualCapability.external).toEqual(capabilityToUpdate.external);
+ });
+
+});
diff --git a/catalog-ui/src/app/ng2/services/component-instance-services/component-instance.service.ts b/catalog-ui/src/app/ng2/services/component-instance-services/component-instance.service.ts
index 5ae2918805..1e4ddda9c0 100644
--- a/catalog-ui/src/app/ng2/services/component-instance-services/component-instance.service.ts
+++ b/catalog-ui/src/app/ng2/services/component-instance-services/component-instance.service.ts
@@ -18,15 +18,25 @@
* ============LICENSE_END=========================================================
*/
-import {Injectable, Inject} from '@angular/core';
-import { Observable } from 'rxjs/Observable';
-import {PropertyFEModel, PropertyBEModel, Requirement} from "app/models";
-import {CommonUtils, ComponentType, ServerTypeUrl, ComponentInstanceFactory} from "app/utils";
-import {Component, ComponentInstance, Capability, PropertyModel, ArtifactGroupModel, ArtifactModel, AttributeModel, IFileDownload} from "app/models";
-import {SdcConfigToken, ISdcConfig} from "../../config/sdc-config.config";
-import { HttpClient, HttpHeaders } from '@angular/common/http';
-import { InputBEModel } from '../../../models/properties-inputs/input-be-model';
-import { HttpHelperService } from '../http-hepler.service';
+import {Inject, Injectable} from '@angular/core';
+import {Observable} from 'rxjs/Observable';
+import {
+ ArtifactGroupModel,
+ ArtifactModel,
+ AttributeModel,
+ Capability,
+ Component,
+ ComponentInstance,
+ IFileDownload,
+ PropertyBEModel,
+ PropertyModel,
+ Requirement
+} from "app/models";
+import {CommonUtils, ComponentInstanceFactory, ComponentType, ServerTypeUrl} from "app/utils";
+import {ISdcConfig, SdcConfigToken} from "../../config/sdc-config.config";
+import {HttpClient, HttpHeaders} from '@angular/common/http';
+import {InputBEModel} from '../../../models/properties-inputs/input-be-model';
+import {HttpHelperService} from '../http-hepler.service';
import {AttributeBEModel} from "../../../models/attributes-outputs/attribute-be-model";
import {OutputBEModel} from "../../../models/attributes-outputs/output-be-model";
@@ -158,6 +168,11 @@ export class ComponentInstanceServiceNg2 {
'/requirementName/' + requirement.name, requirement);
}
+ updateInstanceCapability(componentTypeUrl: string, componentId: string, componentInstanceId: string, capability: Capability): Observable<Capability> {
+ const url = `${this.baseUrl}${componentTypeUrl}${componentId}/componentInstances/${componentInstanceId}/capability/`;
+ return this.http.put<Capability>(url, capability);
+ }
+
updateInstanceInputs(component: Component, componentInstanceId: string, inputs: PropertyBEModel[]): Observable<PropertyBEModel[]> {
return this.http.post<Array<PropertyModel>>(this.baseUrl + component.getTypeUrl() + component.uniqueId + '/resourceInstance/' + componentInstanceId + '/inputs', inputs)
@@ -203,7 +218,6 @@ export class ComponentInstanceServiceNg2 {
}
addInstanceArtifact = (componentType:string, componentId:string, instanceId:string, artifact:ArtifactModel):Observable<ArtifactModel> => {
- // let deferred = this.$q.defer<ArtifactModel>();
let headerObj = new HttpHeaders();
if (artifact.payloadData) {
headerObj = headerObj.set('Content-MD5', HttpHelperService.getHeaderMd5(artifact));
@@ -217,7 +231,7 @@ export class ComponentInstanceServiceNg2 {
updateInstanceArtifact = (componentType:string, componentId:string, instanceId:string, artifact:ArtifactModel):Observable<ArtifactModel> => {
return this.http.post<ArtifactModel>(this.baseUrl + this.getServerTypeUrl(componentType) + componentId + '/resourceInstance/' + instanceId + '/artifacts/' + artifact.uniqueId, artifact).map((res) => {
return new ArtifactModel(res);
- });;
+ });
};
deleteInstanceArtifact = (componentId:string, componentType:string, instanceId:string, artifactId:string, artifactLabel:string):Observable<ArtifactModel> => {
diff --git a/catalog-ui/src/app/utils/constants.ts b/catalog-ui/src/app/utils/constants.ts
index 3e86ec9e96..f7cbf8d7b0 100644
--- a/catalog-ui/src/app/utils/constants.ts
+++ b/catalog-ui/src/app/utils/constants.ts
@@ -349,6 +349,7 @@ export class GRAPH_EVENTS {
static ON_PALETTE_COMPONENT_HIDE_POPUP_PANEL = 'onPaletteComponentHidePopupPanel';
static ON_COMPONENT_INSTANCE_NAME_CHANGED = 'onComponentInstanceNameChanged';
static ON_COMPONENT_INSTANCE_REQUIREMENT_EXTERNAL_CHANGED = 'onComponentInstanceRequirementExternalChanged'
+ static ON_COMPONENT_INSTANCE_CAPABILITY_EXTERNAL_CHANGED = 'onComponentInstanceCapabilityExternalChanged'
static ON_ZONE_INSTANCE_NAME_CHANGED = 'onZoneInstanceNameChanged';
static ON_DELETE_COMPONENT_INSTANCE = 'onDeleteComponentInstance';
static ON_DELETE_ZONE_INSTANCE = 'onDeleteZoneInstance';
diff --git a/common-app-api/src/main/java/org/openecomp/sdc/exception/ResponseFormat.java b/common-app-api/src/main/java/org/openecomp/sdc/exception/ResponseFormat.java
index b0467425ec..2840ccd3b4 100644
--- a/common-app-api/src/main/java/org/openecomp/sdc/exception/ResponseFormat.java
+++ b/common-app-api/src/main/java/org/openecomp/sdc/exception/ResponseFormat.java
@@ -19,6 +19,8 @@
*/
package org.openecomp.sdc.exception;
+import lombok.Setter;
+
/**
* Nested POJOs to express required JSON format of the error
* <p>
@@ -28,6 +30,7 @@ package org.openecomp.sdc.exception;
*/
public class ResponseFormat {
+ @Setter
private int status;
private RequestErrorWrapper requestErrorWrapper;
@@ -40,10 +43,6 @@ public class ResponseFormat {
this.status = status;
}
- public void setStatus(int status) {
- this.status = status;
- }
-
public Integer getStatus() {
return status;
}
@@ -153,9 +152,6 @@ public class ResponseFormat {
@SuppressWarnings("unused")
private OkResponseInfo okResponseInfo;
- public RequestError() {
- }
-
public PolicyException getPolicyException() {
return policyException;
}
diff --git a/common-app-logging/src/main/java/org/openecomp/sdc/common/log/enums/LoggerSupportabilityActions.java b/common-app-logging/src/main/java/org/openecomp/sdc/common/log/enums/LoggerSupportabilityActions.java
index 88b6dbfb6a..253a41f8cb 100644
--- a/common-app-logging/src/main/java/org/openecomp/sdc/common/log/enums/LoggerSupportabilityActions.java
+++ b/common-app-logging/src/main/java/org/openecomp/sdc/common/log/enums/LoggerSupportabilityActions.java
@@ -79,6 +79,7 @@ public enum LoggerSupportabilityActions {
UPDATE_GROUP_MEMBERS("UPDATE GROUP MEMBERS"),
UPDATE_INSTANCE_CAPABILITY_PROPERTY("UPDATE INSTANCE CAPABILITY PROPERTY"),
UPDATE_INSTANCE_REQUIREMENT("UPDATE INSTANCE REQUIREMENT"),
+ UPDATE_INSTANCE_CAPABILITY("UPDATE INSTANCE CAPABILITY"),
UPDATE_POLICY_TARGET("UPDATE POLICY TARGET"),
UPDATE_POLICIES_PROPERTIES("UPDATE POLICIES PROPERTIES");
// @formatter:on
diff --git a/common-be/src/main/java/org/openecomp/sdc/be/datatypes/elements/CapabilityDataDefinition.java b/common-be/src/main/java/org/openecomp/sdc/be/datatypes/elements/CapabilityDataDefinition.java
index 78bfe50d5c..3345c95946 100644
--- a/common-be/src/main/java/org/openecomp/sdc/be/datatypes/elements/CapabilityDataDefinition.java
+++ b/common-be/src/main/java/org/openecomp/sdc/be/datatypes/elements/CapabilityDataDefinition.java
@@ -21,6 +21,8 @@
package org.openecomp.sdc.be.datatypes.elements;
import com.google.common.collect.Lists;
+import lombok.Getter;
+import lombok.Setter;
import org.openecomp.sdc.be.datatypes.enums.JsonPresentationFields;
import org.openecomp.sdc.be.datatypes.tosca.ToscaDataDefinition;
@@ -35,6 +37,10 @@ public class CapabilityDataDefinition extends ToscaDataDefinition {
public static final String MIN_OCCURRENCES = "0";
public static final String MAX_OCCURRENCES = "UNBOUNDED";
+ @Getter
+ @Setter
+ private boolean external = false;
+
/**
* The default constructor initializing limits of the occurrences
*/
@@ -45,11 +51,11 @@ public class CapabilityDataDefinition extends ToscaDataDefinition {
}
/**
- * Deep copy constructor
+ * Deep copy constructor.
*
- * @param other
+ * @param other the capability data definition to copy
*/
- public CapabilityDataDefinition(CapabilityDataDefinition other) {
+ public CapabilityDataDefinition(final CapabilityDataDefinition other) {
this.setUniqueId(other.getUniqueId());
this.setType(other.getType());
this.setDescription(other.getDescription());
@@ -84,6 +90,7 @@ public class CapabilityDataDefinition extends ToscaDataDefinition {
this.setSource(other.getSource());
this.setOwnerType(other.getOwnerType());
+ this.setExternal(other.isExternal());
}
public CapabilityDataDefinition(CapabilityTypeDataDefinition other) {
@@ -422,11 +429,11 @@ public class CapabilityDataDefinition extends ToscaDataDefinition {
String maxOccurrences = this.getMaxOccurrences();
String source = this.getSource();
-
return "CapabilityDefinition [uniqueId=" + uniqueId + ", description=" + description + ", name=" + name
- + ", type=" + type + ", validSourceTypes=" + validSourceTypes + ", capabilitySources="
- + capabilitySources + ", ownerId=" + ownerId + ", ownerName=" + ownerName
- + ", minOccurrences=" + minOccurrences + ", maxOccurrences=" + maxOccurrences + ", path=" + path + ", source=" + source + "]";
+ + ", type=" + type + ", validSourceTypes=" + validSourceTypes + ", capabilitySources="
+ + capabilitySources + ", ownerId=" + ownerId + ", ownerName=" + ownerName
+ + ", minOccurrences=" + minOccurrences + ", maxOccurrences=" + maxOccurrences + ", path=" + path + ", source=" + source
+ + ", external=" + external + "]";
}
public enum OwnerType {
diff --git a/common-be/src/main/java/org/openecomp/sdc/be/exception/BusinessException.java b/common-be/src/main/java/org/openecomp/sdc/be/exception/BusinessException.java
new file mode 100644
index 0000000000..69fb00f3b5
--- /dev/null
+++ b/common-be/src/main/java/org/openecomp/sdc/be/exception/BusinessException.java
@@ -0,0 +1,34 @@
+/*
+ * ============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.exception;
+
+public abstract class BusinessException extends RuntimeException {
+
+ protected BusinessException() {
+ }
+
+ protected BusinessException(final String message) {
+ super(message);
+ }
+
+ protected BusinessException(final String message, final Throwable cause) {
+ super(message, cause);
+ }
+}
diff --git a/integration-tests/src/test/java/org/onap/sdc/frontend/ci/tests/pages/component/workspace/CompositionRequirementsCapabilitiesTab.java b/integration-tests/src/test/java/org/onap/sdc/frontend/ci/tests/pages/component/workspace/CompositionRequirementsCapabilitiesTab.java
index bee2d3a339..2ea7437416 100644
--- a/integration-tests/src/test/java/org/onap/sdc/frontend/ci/tests/pages/component/workspace/CompositionRequirementsCapabilitiesTab.java
+++ b/integration-tests/src/test/java/org/onap/sdc/frontend/ci/tests/pages/component/workspace/CompositionRequirementsCapabilitiesTab.java
@@ -67,11 +67,11 @@ public class CompositionRequirementsCapabilitiesTab extends AbstractPageObject {
}
private void loadRequirements() {
- final List<WebElement> webElements = waitForAllElementsVisibility(By.xpath("//checkbox[@data-tests-id]"));
+ final List<WebElement> webElements = waitForAllElementsVisibility(By.xpath(XpathSelector.REQUIREMENT_EXTERNAL_CHECKBOX.getXPath()));
checkboxExternalRequirementMap = new HashMap<>();
webElements.forEach(webElement -> {
final String dataTestsId = webElement.getAttribute("data-tests-id");
- checkboxExternalRequirementMap.put(dataTestsId.substring("checkbox-mark-as-external-".length()), webElement);
+ checkboxExternalRequirementMap.put(dataTestsId.substring("checkbox-external-req-".length()), webElement);
});
}
@@ -94,7 +94,8 @@ public class CompositionRequirementsCapabilitiesTab extends AbstractPageObject {
private enum XpathSelector {
REQ_CAPABILITIES_TAB("//req-capabilities-tab"),
CAPABILITIES_ACCORDION("//div[@data-tests-id='Capabilities-accordion']"),
- REQUIREMENTS_ACCORDION("//div[@data-tests-id='Requirements-accordion']");
+ REQUIREMENTS_ACCORDION("//div[@data-tests-id='Requirements-accordion']"),
+ REQUIREMENT_EXTERNAL_CHECKBOX("//checkbox[starts-with(@data-tests-id, 'checkbox-external-req-')]");
private final String xPath;