summaryrefslogtreecommitdiffstats
path: root/catalog-be
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 /catalog-be
parente3de4c9d214983d38a7d66e89dae5d4bba170ca3 (diff)
Support for selection of capabilities
Change-Id: Ib1a3e3e1a59fc84c62620932c408e231acf77024 Issue-ID: SDC-3580 Signed-off-by: André Schmid <andre.schmid@est.tech>
Diffstat (limited to 'catalog-be')
-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
14 files changed, 858 insertions, 8 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