Onboarding upload control 82/126482/12
authorandre.schmid <andre.schmid@est.tech>
Wed, 15 Dec 2021 19:44:06 +0000 (19:44 +0000)
committerMichael Morris <michael.morris@est.tech>
Fri, 21 Jan 2022 13:25:16 +0000 (13:25 +0000)
Brings the initial structure to control asynchronously a VSP package
upload during the onboarding.
Instead of blocking the UI, the upload and processing status will be
controlled by the backend, so the frontend can query it and control the
behaviour of the UI.
Updates the upload endpoint to obtain/verify an upload lock, and creates
a second endpoint to check for the upload status.

Change-Id: If1c43fb4f0b11e1d8a5627578bafc75f266393c2
Issue-ID: SDC-3826, SDC-3827
Signed-off-by: andre.schmid <andre.schmid@est.tech>
30 files changed:
common-app-api/src/main/java/org/openecomp/sdc/be/csar/storage/ArtifactInfo.java
common-be/src/main/java/org/openecomp/sdc/be/csar/storage/MinIoArtifactInfo.java
openecomp-be/api/openecomp-sdc-rest-webapp/onboarding-rest-war/src/main/webapp/WEB-INF/beans-services.xml
openecomp-be/api/openecomp-sdc-rest-webapp/openecomp-sdc-common-rest/src/main/java/org/openecomp/sdcrests/errors/DefaultExceptionMapper.java
openecomp-be/api/openecomp-sdc-rest-webapp/openecomp-sdc-common-rest/src/main/java/org/openecomp/sdcrests/mapping/MappingBase.java
openecomp-be/api/openecomp-sdc-rest-webapp/openecomp-sdc-common-rest/src/main/resources/errorCodesToResponseStatusMapping.json
openecomp-be/api/openecomp-sdc-rest-webapp/vendor-software-products-rest/vendor-software-products-rest-services/src/main/java/org/openecomp/sdcrests/vsp/rest/OrchestrationTemplateCandidateUploadManagerController.java [new file with mode: 0644]
openecomp-be/api/openecomp-sdc-rest-webapp/vendor-software-products-rest/vendor-software-products-rest-services/src/main/java/org/openecomp/sdcrests/vsp/rest/controllers/OrchestrationTemplateCandidateUploadManagerControllerImpl.java [new file with mode: 0644]
openecomp-be/api/openecomp-sdc-rest-webapp/vendor-software-products-rest/vendor-software-products-rest-services/src/main/java/org/openecomp/sdcrests/vsp/rest/exception/OrchestrationTemplateCandidateUploadManagerExceptionSupplier.java [new file with mode: 0644]
openecomp-be/api/openecomp-sdc-rest-webapp/vendor-software-products-rest/vendor-software-products-rest-services/src/main/java/org/openecomp/sdcrests/vsp/rest/mapping/VspUploadStatusRecordMapper.java [new file with mode: 0644]
openecomp-be/api/openecomp-sdc-rest-webapp/vendor-software-products-rest/vendor-software-products-rest-services/src/main/java/org/openecomp/sdcrests/vsp/rest/services/OrchestrationTemplateCandidateImpl.java
openecomp-be/api/openecomp-sdc-rest-webapp/vendor-software-products-rest/vendor-software-products-rest-services/src/main/java/org/openecomp/sdcrests/vsp/rest/services/OrchestrationTemplateCandidateUploadManager.java [new file with mode: 0644]
openecomp-be/api/openecomp-sdc-rest-webapp/vendor-software-products-rest/vendor-software-products-rest-services/src/main/java/org/openecomp/sdcrests/vsp/rest/services/OrchestrationTemplateCandidateUploadManagerImpl.java [new file with mode: 0644]
openecomp-be/api/openecomp-sdc-rest-webapp/vendor-software-products-rest/vendor-software-products-rest-services/src/test/java/org/openecomp/sdcrests/vsp/rest/controllers/OrchestrationTemplateCandidateUploadManagerControllerImplTest.java [new file with mode: 0644]
openecomp-be/api/openecomp-sdc-rest-webapp/vendor-software-products-rest/vendor-software-products-rest-services/src/test/java/org/openecomp/sdcrests/vsp/rest/mapping/VspUploadStatusRecordMapperTest.java [new file with mode: 0644]
openecomp-be/api/openecomp-sdc-rest-webapp/vendor-software-products-rest/vendor-software-products-rest-services/src/test/java/org/openecomp/sdcrests/vsp/rest/services/OrchestrationTemplateCandidateImplTest.java
openecomp-be/api/openecomp-sdc-rest-webapp/vendor-software-products-rest/vendor-software-products-rest-services/src/test/java/org/openecomp/sdcrests/vsp/rest/services/OrchestrationTemplateCandidateUploadManagerImplTest.java [new file with mode: 0644]
openecomp-be/api/openecomp-sdc-rest-webapp/vendor-software-products-rest/vendor-software-products-rest-types/src/main/java/org/openecomp/sdcrests/vendorsoftwareproducts/types/VspUploadStatusDto.java [new file with mode: 0644]
openecomp-be/lib/openecomp-common-lib/src/main/java/org/openecomp/sdc/common/errors/Messages.java
openecomp-be/lib/openecomp-sdc-vendor-software-product-lib/openecomp-sdc-vendor-software-product-api/src/main/java/org/openecomp/sdc/vendorsoftwareproduct/dao/VspUploadStatusRecordAccessor.java [new file with mode: 0644]
openecomp-be/lib/openecomp-sdc-vendor-software-product-lib/openecomp-sdc-vendor-software-product-api/src/main/java/org/openecomp/sdc/vendorsoftwareproduct/dao/VspUploadStatusRecordDao.java [new file with mode: 0644]
openecomp-be/lib/openecomp-sdc-vendor-software-product-lib/openecomp-sdc-vendor-software-product-api/src/main/java/org/openecomp/sdc/vendorsoftwareproduct/dao/type/VspUploadStatus.java [new file with mode: 0644]
openecomp-be/lib/openecomp-sdc-vendor-software-product-lib/openecomp-sdc-vendor-software-product-api/src/main/java/org/openecomp/sdc/vendorsoftwareproduct/dao/type/VspUploadStatusRecord.java [new file with mode: 0644]
openecomp-be/lib/openecomp-sdc-vendor-software-product-lib/openecomp-sdc-vendor-software-product-api/src/test/java/org/openecomp/sdc/vendorsoftwareproduct/dao/type/VspUploadStatusTest.java [new file with mode: 0644]
openecomp-be/lib/openecomp-sdc-vendor-software-product-lib/openecomp-sdc-vendor-software-product-core/src/main/java/org/openecomp/sdc/vendorsoftwareproduct/dao/errors/VendorSoftwareProductNotFoundErrorBuilder.java
openecomp-be/lib/openecomp-sdc-vendor-software-product-lib/openecomp-sdc-vendor-software-product-core/src/main/java/org/openecomp/sdc/vendorsoftwareproduct/dao/impl/VspUploadStatusRecordDaoIml.java [new file with mode: 0644]
openecomp-be/lib/openecomp-sdc-vendor-software-product-lib/openecomp-sdc-vendor-software-product-core/src/main/java/org/openecomp/sdc/vendorsoftwareproduct/errors/VendorSoftwareProductErrorCodes.java
openecomp-be/lib/openecomp-sdc-vendor-software-product-lib/openecomp-sdc-vendor-software-product-core/src/test/java/org/openecomp/sdc/vendorsoftwareproduct/dao/errors/VendorSoftwareProductNotFoundErrorBuilderTest.java
openecomp-be/lib/openecomp-sdc-vendor-software-product-lib/openecomp-sdc-vendor-software-product-core/src/test/java/org/openecomp/sdc/vendorsoftwareproduct/dao/impl/VspUploadStatusRecordDaoImlTest.java [new file with mode: 0644]
openecomp-be/tools/install/database/init_schemas.cql

index 9142653..54bf03b 100644 (file)
@@ -26,5 +26,7 @@ package org.openecomp.sdc.be.csar.storage;
 public interface ArtifactInfo {
 
     String getInfo();
+    byte[] getBytes();
+    void setBytes(byte[] bytes);
 
 }
index a193cdd..f5e26ab 100644 (file)
 
 package org.openecomp.sdc.be.csar.storage;
 
-import lombok.AllArgsConstructor;
 import lombok.Getter;
 
-@AllArgsConstructor
 @Getter
 public class MinIoArtifactInfo implements ArtifactInfo {
 
     private final String bucket;
     private final String objectName;
+    private byte[] artifactBytes;
+
+    public MinIoArtifactInfo(final String bucket, final String objectName) {
+        this.bucket = bucket;
+        this.objectName = objectName;
+    }
 
     @Override
     public String getInfo() {
         return String.format("bucket: %s\n"
             + "object: %s", bucket, objectName);
     }
+
+    @Override
+    public byte[] getBytes() {
+        return artifactBytes;
+    }
+
+    @Override
+    public void setBytes(final byte[] artifactBytes) {
+        this.artifactBytes = artifactBytes;
+    }
 }
index 62ae816..f4a84a0 100644 (file)
@@ -14,6 +14,7 @@
 
     <!-- CXF -->
     <context:component-scan base-package="org.openecomp.sdcrests"/>
+    <context:component-scan base-package="org.openecomp.sdc.vendorsoftwareproduct.dao"/>
     <!-- Needed for JSR-303 validations. May be removed when moving to JAX-RS 2.0 -->
     <bean id="validator" class="org.springframework.validation.beanvalidation.LocalValidatorFactoryBean"/>
 
@@ -60,6 +61,7 @@
             <ref bean="licenseKeyGroups"/>
             <ref bean="licenseKeyGroupLimits"/>
             <ref bean="vendorSoftwareProducts"/>
+            <ref bean="packageUploadManagerController"/>
             <ref bean="networks"/>
             <ref bean="components"/>
             <ref bean="nics"/>
@@ -72,9 +74,9 @@
             <ref bean="applicationConfiguration"/>
             <ref bean="componentMonitoringUploads"/>
             <ref bean="deploymentFlavors"/>
-               <ref bean="images"/>
+            <ref bean="images"/>
             <ref bean="orchestrationTemplateCandidate"/>
-           <ref bean="vnfPackageRepository"/>
+            <ref bean="vnfPackageRepository"/>
             <ref bean="componentDependencies"/>
             <ref bean="healthCheck"/>
             <ref bean="itemPermissions"/>
index 0546180..a256af7 100644 (file)
@@ -25,6 +25,7 @@ import javax.validation.ConstraintViolationException;
 import javax.validation.Path;
 import javax.ws.rs.core.MediaType;
 import javax.ws.rs.core.Response;
+import javax.ws.rs.core.Response.Status;
 import javax.ws.rs.ext.ExceptionMapper;
 import org.apache.commons.collections4.CollectionUtils;
 import org.hibernate.validator.internal.engine.path.PathImpl;
@@ -52,11 +53,11 @@ public class DefaultExceptionMapper implements ExceptionMapper<Exception> {
     public Response toResponse(Exception exception) {
         Response response;
         if (exception instanceof CoreException) {
-            response = transform(CoreException.class.cast(exception));
+            response = transform((CoreException) exception);
         } else if (exception instanceof ConstraintViolationException) {
-            response = transform(ConstraintViolationException.class.cast(exception));
+            response = transform((ConstraintViolationException) exception);
         } else if (exception instanceof JsonMappingException) {
-            response = transform(JsonMappingException.class.cast(exception));
+            response = transform((JsonMappingException) exception);
         } else {
             response = transform(exception);
         }
@@ -66,22 +67,21 @@ public class DefaultExceptionMapper implements ExceptionMapper<Exception> {
         return response;
     }
 
-    private Response transform(CoreException coreException) {
-        Response response;
-        ErrorCode code = coreException.code();
+    private Response transform(final CoreException coreException) {
+        final ErrorCode code = coreException.code();
         LOGGER.error(code.message(), coreException);
         if (coreException.code().category().equals(ErrorCategory.APPLICATION)) {
-            if (Response.Status.NOT_FOUND.name().equals(ERROR_CODE_TO_RESPONSE_STATUS.get(code.id()))) {
-                response = Response.status(Response.Status.NOT_FOUND).entity(toEntity(Response.Status.NOT_FOUND, code)).build();
-            } else if (Response.Status.BAD_REQUEST.name().equals(ERROR_CODE_TO_RESPONSE_STATUS.get(code.id()))) {
-                response = Response.status(Response.Status.BAD_REQUEST).entity(toEntity(Response.Status.BAD_REQUEST, code)).build();
-            } else {
-                response = Response.status(Response.Status.EXPECTATION_FAILED).entity(toEntity(Response.Status.EXPECTATION_FAILED, code)).build();
+            final Status errorStatus = Status.valueOf(ERROR_CODE_TO_RESPONSE_STATUS.get(code.id()));
+            if (List.of(Status.BAD_REQUEST, Status.FORBIDDEN, Status.NOT_FOUND, Status.INTERNAL_SERVER_ERROR).contains(errorStatus)) {
+                return buildResponse(errorStatus, code);
             }
-        } else {
-            response = Response.status(Response.Status.INTERNAL_SERVER_ERROR).entity(toEntity(Response.Status.INTERNAL_SERVER_ERROR, code)).build();
+            return buildResponse(Status.EXPECTATION_FAILED, code);
         }
-        return response;
+        return buildResponse(Status.INTERNAL_SERVER_ERROR, code);
+    }
+
+    private Response buildResponse(Status notFound, ErrorCode code) {
+        return Response.status(notFound).entity(toEntity(notFound, code)).build();
     }
 
     private Response transform(ConstraintViolationException validationException) {
@@ -98,28 +98,26 @@ public class DefaultExceptionMapper implements ExceptionMapper<Exception> {
         }
         ErrorCode validationErrorCode = new ValidationErrorBuilder(message, fieldName).build();
         LOGGER.error(validationErrorCode.message(), validationException);
-        return Response.status(Response.Status.EXPECTATION_FAILED) //error 417
-            .entity(toEntity(Response.Status.EXPECTATION_FAILED, validationErrorCode)).build();
+        return buildResponse(Status.EXPECTATION_FAILED, validationErrorCode);
     }
 
     private Response transform(JsonMappingException jsonMappingException) {
         ErrorCode jsonMappingErrorCode = new JsonMappingErrorBuilder().build();
         LOGGER.error(jsonMappingErrorCode.message(), jsonMappingException);
-        return Response.status(Response.Status.EXPECTATION_FAILED) //error 417
-            .entity(toEntity(Response.Status.EXPECTATION_FAILED, jsonMappingErrorCode)).build();
+        return buildResponse(Status.EXPECTATION_FAILED, jsonMappingErrorCode);
     }
 
     private Response transform(Exception exception) {
         ErrorCode errorCode = new GeneralErrorBuilder().build();
         LOGGER.error(errorCode.message(), exception);
-        return Response.status(Response.Status.INTERNAL_SERVER_ERROR).entity(toEntity(Response.Status.INTERNAL_SERVER_ERROR, errorCode)).build();
+        return buildResponse(Status.INTERNAL_SERVER_ERROR, errorCode);
     }
 
     private String getFieldName(Path propertyPath) {
         return ((PathImpl) propertyPath).getLeafNode().toString();
     }
 
-    private Object toEntity(Response.Status status, ErrorCode code) {
+    private Object toEntity(final Status status, final ErrorCode code) {
         return new ErrorCodeAndMessage(status, code);
     }
 }
index 68a16e8..133f2e4 100644 (file)
@@ -37,7 +37,7 @@ public abstract class MappingBase<S, T> {
      */
     public final T applyMapping(final S source, Class<T> clazz) {
         T target = (T) instantiateTarget(clazz);
-        if (source != null && target != null) {
+        if (source != null) {
             preMapping(source, target);
             doMapping(source, target);
             postMapping(source, target);
index 979b6c6..95b2c07 100644 (file)
@@ -1,6 +1,12 @@
 {
   "VSP_NOT_FOUND": "NOT_FOUND",
   "VSP_INVALID": "BAD_REQUEST",
+  "VSP_PROCESSING_IN_PROGRESS": "FORBIDDEN",
+  "VSP_CREATE_UPLOAD_LOCK_ERROR": "INTERNAL_SERVER_ERROR",
+  "VSP_UPDATE_UPLOAD_LOCK_ERROR": "INTERNAL_SERVER_ERROR",
+  "VSP_UPLOAD_LOCK_NOT_FOUND_ERROR": "NOT_FOUND",
+  "VSP_UPLOAD_ALREADY_FINISHED_ERROR": "INTERNAL_SERVER_ERROR",
+  "ORCHESTRATION_NOT_FOUND": "NOT_FOUND",
   "UPLOAD_INVALID" : "PRECONDITION_FAILED",
   "PACKAGE_NOT_FOUND": "NOT_FOUND",
   "PACKAGE_INVALID": "BAD_REQUEST",
diff --git a/openecomp-be/api/openecomp-sdc-rest-webapp/vendor-software-products-rest/vendor-software-products-rest-services/src/main/java/org/openecomp/sdcrests/vsp/rest/OrchestrationTemplateCandidateUploadManagerController.java b/openecomp-be/api/openecomp-sdc-rest-webapp/vendor-software-products-rest/vendor-software-products-rest-services/src/main/java/org/openecomp/sdcrests/vsp/rest/OrchestrationTemplateCandidateUploadManagerController.java
new file mode 100644 (file)
index 0000000..971a1c4
--- /dev/null
@@ -0,0 +1,65 @@
+/*
+ * -
+ *  ============LICENSE_START=======================================================
+ *  Copyright (C) 2022 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.sdcrests.vsp.rest;
+
+import static org.openecomp.sdcrests.common.RestConstants.USER_ID_HEADER_PARAM;
+import static org.openecomp.sdcrests.common.RestConstants.USER_MISSING_ERROR_MSG;
+import static org.openecomp.sdcrests.vsp.rest.OrchestrationTemplateCandidateUploadManagerController.URL;
+
+import io.swagger.v3.oas.annotations.Parameter;
+import io.swagger.v3.oas.annotations.tags.Tag;
+import javax.validation.constraints.NotNull;
+import javax.ws.rs.Consumes;
+import javax.ws.rs.GET;
+import javax.ws.rs.HeaderParam;
+import javax.ws.rs.Path;
+import javax.ws.rs.PathParam;
+import javax.ws.rs.Produces;
+import javax.ws.rs.core.MediaType;
+import javax.ws.rs.core.Response;
+import org.springframework.validation.annotation.Validated;
+
+@Path(URL)
+@Produces(MediaType.APPLICATION_JSON)
+@Consumes(MediaType.APPLICATION_JSON)
+@Tag(name = "SDCE-1 APIs")
+@Tag(name = "Package Upload Manager")
+@Validated
+public interface OrchestrationTemplateCandidateUploadManagerController extends VspEntities {
+
+    String URL = "/v1.0/vendor-software-products/{vspId}/versions/{versionId}/orchestration-template-candidate/upload";
+
+    /**
+     * Gets the latest package upload status for a Vendor Software Product version.
+     *
+     * @param vspId     the vsp id
+     * @param versionId the vsp version id
+     * @param user      the username accessing the API
+     * @return if successful, an OK response with the latest VspUploadStatus information
+     */
+    @GET
+    @Path("/")
+    Response getLatestStatus(@Parameter(description = "Vendor Software Product id") @PathParam("vspId") String vspId,
+                             @Parameter(description = "Vendor Software Product version id") @PathParam("versionId") String versionId,
+                             @NotNull(message = USER_MISSING_ERROR_MSG) @HeaderParam(USER_ID_HEADER_PARAM) String user);
+
+}
diff --git a/openecomp-be/api/openecomp-sdc-rest-webapp/vendor-software-products-rest/vendor-software-products-rest-services/src/main/java/org/openecomp/sdcrests/vsp/rest/controllers/OrchestrationTemplateCandidateUploadManagerControllerImpl.java b/openecomp-be/api/openecomp-sdc-rest-webapp/vendor-software-products-rest/vendor-software-products-rest-services/src/main/java/org/openecomp/sdcrests/vsp/rest/controllers/OrchestrationTemplateCandidateUploadManagerControllerImpl.java
new file mode 100644 (file)
index 0000000..f96522a
--- /dev/null
@@ -0,0 +1,71 @@
+/*
+ * -
+ *  ============LICENSE_START=======================================================
+ *  Copyright (C) 2022 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.sdcrests.vsp.rest.controllers;
+
+import java.util.Optional;
+import javax.ws.rs.core.Response;
+import javax.ws.rs.core.Response.Status;
+import org.openecomp.sdc.common.util.ValidationUtils;
+import org.openecomp.sdcrests.vendorsoftwareproducts.types.VspUploadStatusDto;
+import org.openecomp.sdcrests.vsp.rest.OrchestrationTemplateCandidateUploadManagerController;
+import org.openecomp.sdcrests.vsp.rest.services.OrchestrationTemplateCandidateUploadManager;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Controller;
+
+@Controller("packageUploadManagerController")
+public class OrchestrationTemplateCandidateUploadManagerControllerImpl implements OrchestrationTemplateCandidateUploadManagerController {
+
+    private final OrchestrationTemplateCandidateUploadManager orchestrationTemplateCandidateUploadManager;
+
+    @Autowired
+    public OrchestrationTemplateCandidateUploadManagerControllerImpl(final OrchestrationTemplateCandidateUploadManager orchestrationTemplateCandidateUploadManager) {
+        this.orchestrationTemplateCandidateUploadManager = orchestrationTemplateCandidateUploadManager;
+    }
+
+    @Override
+    public Response getLatestStatus(String vspId, String versionId, String user) {
+        vspId = ValidationUtils.sanitizeInputString(vspId);
+        versionId = ValidationUtils.sanitizeInputString(versionId);
+        user = ValidationUtils.sanitizeInputString(user);
+
+        final Optional<VspUploadStatusDto> vspUploadStatus = orchestrationTemplateCandidateUploadManager.findLatestStatus(vspId, versionId, user);
+        if (vspUploadStatus.isEmpty()) {
+            return Response.status(Status.NOT_FOUND).build();
+        }
+
+        return Response.ok(vspUploadStatus.get()).build();
+    }
+
+    /**
+     * Builds the string representing the get API url.
+     *
+     * @param vspId the vsp id
+     * @param vspVersionId the vsp version id
+     * @return the string representing the get API url
+     */
+    public static String buildGetUrl(final String vspId, final String vspVersionId) {
+        return OrchestrationTemplateCandidateUploadManagerController.URL
+            .replace("{vspId}", vspId)
+            .replace("{versionId}", vspVersionId);
+    }
+
+}
diff --git a/openecomp-be/api/openecomp-sdc-rest-webapp/vendor-software-products-rest/vendor-software-products-rest-services/src/main/java/org/openecomp/sdcrests/vsp/rest/exception/OrchestrationTemplateCandidateUploadManagerExceptionSupplier.java b/openecomp-be/api/openecomp-sdc-rest-webapp/vendor-software-products-rest/vendor-software-products-rest-services/src/main/java/org/openecomp/sdcrests/vsp/rest/exception/OrchestrationTemplateCandidateUploadManagerExceptionSupplier.java
new file mode 100644 (file)
index 0000000..2eb0261
--- /dev/null
@@ -0,0 +1,84 @@
+/*
+ * -
+ *  ============LICENSE_START=======================================================
+ *  Copyright (C) 2022 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.sdcrests.vsp.rest.exception;
+
+import static org.openecomp.sdc.vendorsoftwareproduct.errors.VendorSoftwareProductErrorCodes.VSP_CREATE_UPLOAD_LOCK_ERROR;
+import static org.openecomp.sdc.vendorsoftwareproduct.errors.VendorSoftwareProductErrorCodes.VSP_PROCESSING_IN_PROGRESS;
+import static org.openecomp.sdc.vendorsoftwareproduct.errors.VendorSoftwareProductErrorCodes.VSP_UPDATE_UPLOAD_LOCK_ERROR;
+import static org.openecomp.sdc.vendorsoftwareproduct.errors.VendorSoftwareProductErrorCodes.VSP_UPLOAD_ALREADY_FINISHED_ERROR;
+import static org.openecomp.sdc.vendorsoftwareproduct.errors.VendorSoftwareProductErrorCodes.VSP_UPLOAD_LOCK_NOT_FOUND_ERROR;
+
+import java.util.UUID;
+import java.util.function.Supplier;
+import java.util.stream.Collectors;
+import org.openecomp.sdc.common.errors.CoreException;
+import org.openecomp.sdc.common.errors.ErrorCode;
+import org.openecomp.sdc.common.errors.ErrorCode.ErrorCodeBuilder;
+import org.openecomp.sdc.vendorsoftwareproduct.dao.errors.VendorSoftwareProductNotFoundErrorBuilder;
+import org.openecomp.sdc.vendorsoftwareproduct.dao.type.VspUploadStatus;
+
+public class OrchestrationTemplateCandidateUploadManagerExceptionSupplier {
+
+    private OrchestrationTemplateCandidateUploadManagerExceptionSupplier() {
+    }
+
+    public static Supplier<CoreException> vspUploadAlreadyInProgress(final String vspId, final String vspVersionId) {
+        final String errorMsg = String.format("There is a processing in progress for the VSP %s, version %s", vspId, vspVersionId);
+        return () -> new CoreException(new ErrorCodeBuilder().withId(VSP_PROCESSING_IN_PROGRESS).withMessage(errorMsg).build());
+    }
+
+    public static Supplier<CoreException> couldNotCreateLock(final String vspId, final String vspVersionId, final Exception exception) {
+        final String errorMsg = String.format("Could not create a lock for the VSP %s, version %s", vspId, vspVersionId);
+        final ErrorCode errorCode = new ErrorCodeBuilder().withId(VSP_CREATE_UPLOAD_LOCK_ERROR).withMessage(errorMsg).build();
+        return () -> new CoreException(errorCode, exception);
+    }
+
+    public static Supplier<CoreException> couldNotUpdateLock(final UUID lockId, final String vspId, final String vspVersionId, final Exception exception) {
+        final String errorMsg = String.format("Could not update the lock %s for the VSP %s, version %s", lockId, vspId, vspVersionId);
+        final ErrorCode errorCode = new ErrorCodeBuilder().withId(VSP_UPDATE_UPLOAD_LOCK_ERROR).withMessage(errorMsg).build();
+        return () -> new CoreException(errorCode, exception);
+    }
+
+    public static Supplier<CoreException> couldNotFindLock(final UUID lockId, final String vspId, final String vspVersionId) {
+        final String errorMsg = String.format("Could not find lock '%s' for the VSP %s, version %s", lockId, vspId, vspVersionId);
+        final ErrorCode errorCode = new ErrorCodeBuilder().withId(VSP_UPLOAD_LOCK_NOT_FOUND_ERROR).withMessage(errorMsg).build();
+        return () -> new CoreException(errorCode);
+    }
+
+    public static Supplier<CoreException> uploadAlreadyFinished(final UUID lockId, final String vspId, final String vspVersionId) {
+        final String errorMsg = String.format("The upload was already finished for lock '%s', VSP '%s', version '%s'", lockId, vspId, vspVersionId);
+        final ErrorCode errorCode = new ErrorCodeBuilder().withId(VSP_UPLOAD_ALREADY_FINISHED_ERROR).withMessage(errorMsg).build();
+        return () -> new CoreException(errorCode);
+    }
+
+    public static Supplier<CoreException> vspNotFound(final String vspId, final String vspVersionId) {
+        return () -> new CoreException(new VendorSoftwareProductNotFoundErrorBuilder(vspId, vspVersionId).build());
+    }
+
+    public static Supplier<IllegalArgumentException> invalidCompleteStatus(final VspUploadStatus status) {
+        String errorMsg = String.format("Invalid complete status '%s'. Expecting one of: %s",
+            status,
+            VspUploadStatus.getCompleteStatus().stream().map(Enum::name).collect(Collectors.joining(", "))
+        );
+        return () -> new IllegalArgumentException(errorMsg);
+    }
+}
diff --git a/openecomp-be/api/openecomp-sdc-rest-webapp/vendor-software-products-rest/vendor-software-products-rest-services/src/main/java/org/openecomp/sdcrests/vsp/rest/mapping/VspUploadStatusRecordMapper.java b/openecomp-be/api/openecomp-sdc-rest-webapp/vendor-software-products-rest/vendor-software-products-rest-services/src/main/java/org/openecomp/sdcrests/vsp/rest/mapping/VspUploadStatusRecordMapper.java
new file mode 100644 (file)
index 0000000..9cc3b59
--- /dev/null
@@ -0,0 +1,40 @@
+/*
+ * -
+ *  ============LICENSE_START=======================================================
+ *  Copyright (C) 2022 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.sdcrests.vsp.rest.mapping;
+
+import org.openecomp.sdc.vendorsoftwareproduct.dao.type.VspUploadStatusRecord;
+import org.openecomp.sdcrests.mapping.MappingBase;
+import org.openecomp.sdcrests.vendorsoftwareproducts.types.VspUploadStatusDto;
+
+public class VspUploadStatusRecordMapper extends MappingBase<VspUploadStatusRecord, VspUploadStatusDto> {
+
+    @Override
+    public void doMapping(final VspUploadStatusRecord source, final VspUploadStatusDto target) {
+        target.setVspId(source.getVspId());
+        target.setVspVersionId(source.getVspVersionId());
+        target.setStatus(source.getStatus());
+        target.setLockId(source.getLockId());
+        target.setComplete(source.getIsComplete());
+        target.setCreated(source.getCreated());
+        target.setUpdated(source.getUpdated());
+    }
+}
index e8ee6b3..1477ce1 100644 (file)
@@ -22,7 +22,6 @@
 package org.openecomp.sdcrests.vsp.rest.services;
 
 import static javax.ws.rs.core.Response.Status.EXPECTATION_FAILED;
-import static javax.ws.rs.core.Response.Status.INTERNAL_SERVER_ERROR;
 import static javax.ws.rs.core.Response.Status.NOT_ACCEPTABLE;
 import static javax.ws.rs.core.Response.Status.NOT_FOUND;
 import static org.openecomp.core.validation.errors.ErrorMessagesFormatBuilder.getErrorWithParameters;
@@ -59,6 +58,7 @@ import org.openecomp.sdc.be.csar.storage.ArtifactStorageConfig;
 import org.openecomp.sdc.be.csar.storage.ArtifactStorageManager;
 import org.openecomp.sdc.be.csar.storage.PackageSizeReducer;
 import org.openecomp.sdc.be.csar.storage.StorageFactory;
+import org.openecomp.sdc.be.csar.storage.exception.ArtifactStorageException;
 import org.openecomp.sdc.common.util.ValidationUtils;
 import org.openecomp.sdc.common.utils.SdcCommon;
 import org.openecomp.sdc.datatypes.error.ErrorLevel;
@@ -70,6 +70,7 @@ import org.openecomp.sdc.vendorsoftwareproduct.OrchestrationTemplateCandidateMan
 import org.openecomp.sdc.vendorsoftwareproduct.VendorSoftwareProductManager;
 import org.openecomp.sdc.vendorsoftwareproduct.VspManagerFactory;
 import org.openecomp.sdc.vendorsoftwareproduct.dao.type.VspDetails;
+import org.openecomp.sdc.vendorsoftwareproduct.dao.type.VspUploadStatus;
 import org.openecomp.sdc.vendorsoftwareproduct.impl.onboarding.OnboardingPackageProcessor;
 import org.openecomp.sdc.vendorsoftwareproduct.impl.onboarding.validation.CnfPackageValidator;
 import org.openecomp.sdc.vendorsoftwareproduct.types.OnboardPackageInfo;
@@ -82,10 +83,12 @@ import org.openecomp.sdcrests.vendorsoftwareproducts.types.FileDataStructureDto;
 import org.openecomp.sdcrests.vendorsoftwareproducts.types.OrchestrationTemplateActionResponseDto;
 import org.openecomp.sdcrests.vendorsoftwareproducts.types.UploadFileResponseDto;
 import org.openecomp.sdcrests.vendorsoftwareproducts.types.ValidationResponseDto;
+import org.openecomp.sdcrests.vendorsoftwareproducts.types.VspUploadStatusDto;
 import org.openecomp.sdcrests.vsp.rest.OrchestrationTemplateCandidate;
 import org.openecomp.sdcrests.vsp.rest.mapping.MapFilesDataStructureToDto;
 import org.openecomp.sdcrests.vsp.rest.mapping.MapUploadFileResponseToUploadFileResponseDto;
 import org.openecomp.sdcrests.vsp.rest.mapping.MapValidationResponseToDto;
+import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.context.annotation.Scope;
 import org.springframework.stereotype.Service;
 
@@ -100,8 +103,10 @@ public class OrchestrationTemplateCandidateImpl implements OrchestrationTemplate
     private final ActivityLogManager activityLogManager;
     private final ArtifactStorageManager artifactStorageManager;
     private final PackageSizeReducer packageSizeReducer;
+    private final OrchestrationTemplateCandidateUploadManager orchestrationTemplateCandidateUploadManager;
 
-    public OrchestrationTemplateCandidateImpl() {
+    @Autowired
+    public OrchestrationTemplateCandidateImpl(final OrchestrationTemplateCandidateUploadManager orchestrationTemplateCandidateUploadManager) {
         this.candidateManager = OrchestrationTemplateCandidateManagerFactory.getInstance().createInterface();
         this.vendorSoftwareProductManager = VspManagerFactory.getInstance().createInterface();
         this.activityLogManager = ActivityLogManagerFactory.getInstance().createInterface();
@@ -110,6 +115,7 @@ public class OrchestrationTemplateCandidateImpl implements OrchestrationTemplate
         this.artifactStorageManager = storageFactory.createArtifactStorageManager();
         LOGGER.info("Instantiating packageSizeReducer");
         this.packageSizeReducer = storageFactory.createPackageSizeReducer().orElse(null);
+        this.orchestrationTemplateCandidateUploadManager = orchestrationTemplateCandidateUploadManager;
     }
 
     // Constructor used in test to avoid mock static
@@ -117,81 +123,101 @@ public class OrchestrationTemplateCandidateImpl implements OrchestrationTemplate
                                               final VendorSoftwareProductManager vendorSoftwareProductManager,
                                               final ActivityLogManager activityLogManager,
                                               final ArtifactStorageManager artifactStorageManager,
-                                              final PackageSizeReducer packageSizeReducer) {
+                                              final PackageSizeReducer packageSizeReducer,
+                                              final OrchestrationTemplateCandidateUploadManager orchestrationTemplateCandidateUploadManager) {
         this.candidateManager = candidateManager;
         this.vendorSoftwareProductManager = vendorSoftwareProductManager;
         this.activityLogManager = activityLogManager;
         this.artifactStorageManager = artifactStorageManager;
         this.packageSizeReducer = packageSizeReducer;
+        this.orchestrationTemplateCandidateUploadManager = orchestrationTemplateCandidateUploadManager;
     }
 
     @Override
     public Response upload(String vspId, String versionId, final Attachment fileToUpload, final String user) {
         vspId = ValidationUtils.sanitizeInputString(vspId);
         versionId = ValidationUtils.sanitizeInputString(versionId);
-        final byte[] fileToUploadBytes;
-        final DataHandler dataHandler = fileToUpload.getDataHandler();
-        final var filename = ValidationUtils.sanitizeInputString(dataHandler.getName());
-        ArtifactInfo artifactInfo = null;
-        if (artifactStorageManager.isEnabled()) {
-            final Path tempArtifactPath;
-            try {
-                final ArtifactStorageConfig storageConfiguration = artifactStorageManager.getStorageConfiguration();
+        final Response response;
+        VspUploadStatusDto vspUploadStatus = null;
+        try {
+            vspUploadStatus = orchestrationTemplateCandidateUploadManager.putUploadInProgress(vspId, versionId, user);
+            final byte[] fileToUploadBytes;
+            final DataHandler dataHandler = fileToUpload.getDataHandler();
+            final var filename = ValidationUtils.sanitizeInputString(dataHandler.getName());
+            ArtifactInfo artifactInfo = null;
+            if (artifactStorageManager.isEnabled()) {
+                artifactInfo = handleArtifactStorage(vspId, versionId, filename, dataHandler);
+                fileToUploadBytes = artifactInfo.getBytes();
+            } else {
+                fileToUploadBytes = fileToUpload.getObject(byte[].class);
+            }
 
-                final Path folder = Path.of(storageConfiguration.getTempPath()).resolve(vspId).resolve(versionId);
-                tempArtifactPath = folder.resolve(UUID.randomUUID().toString());
-                Files.createDirectories(folder);
-                try (final InputStream packageInputStream = dataHandler.getInputStream();
-                    final var fileOutputStream = new FileOutputStream(tempArtifactPath.toFile())) {
-                    packageInputStream.transferTo(fileOutputStream);
-                }
-            } catch (final Exception e) {
-                return Response.status(INTERNAL_SERVER_ERROR).entity(buildUploadResponseWithError(
-                    new ErrorMessage(ErrorLevel.ERROR, UNEXPECTED_PROBLEM_HAPPENED_WHILE_GETTING.formatMessage(filename)))).build();
+            final var onboardingPackageProcessor =
+                new OnboardingPackageProcessor(filename, fileToUploadBytes, new CnfPackageValidator(), artifactInfo);
+            final ErrorMessage[] errorMessages = onboardingPackageProcessor.getErrorMessages().toArray(new ErrorMessage[0]);
+            if (onboardingPackageProcessor.hasErrors()) {
+                return Response.status(NOT_ACCEPTABLE).entity(buildUploadResponseWithError(errorMessages)).build();
             }
-            try (final InputStream inputStream = Files.newInputStream(tempArtifactPath)) {
-                artifactInfo = artifactStorageManager.upload(vspId, versionId, inputStream);
-            } catch (final Exception e) {
-                LOGGER.error("Package Size Reducer not configured", e);
-                return Response.status(INTERNAL_SERVER_ERROR).entity(buildUploadResponseWithError(
-                    new ErrorMessage(ErrorLevel.ERROR, ERROR_HAS_OCCURRED_WHILE_PERSISTING_THE_ARTIFACT.formatMessage(filename)))).build();
+            final var onboardPackageInfo = onboardingPackageProcessor.getOnboardPackageInfo().orElse(null);
+            if (onboardPackageInfo == null) {
+                final UploadFileResponseDto uploadFileResponseDto = buildUploadResponseWithError(
+                    new ErrorMessage(ErrorLevel.ERROR, PACKAGE_PROCESS_ERROR.formatMessage(filename)));
+                return Response.ok(uploadFileResponseDto).build();
             }
-            try {
-                fileToUploadBytes = packageSizeReducer.reduce(tempArtifactPath);
-                Files.delete(tempArtifactPath);
-            } catch (final Exception e) {
-                LOGGER.error("Package Size Reducer not configured", e);
-                return Response.status(INTERNAL_SERVER_ERROR).entity(buildUploadResponseWithError(
-                    new ErrorMessage(ErrorLevel.ERROR,
-                        ERROR_HAS_OCCURRED_WHILE_REDUCING_THE_ARTIFACT_SIZE.formatMessage(tempArtifactPath.toString())))).build();
+            final var version = new Version(versionId);
+            final var vspDetails = vendorSoftwareProductManager.getVsp(vspId, version);
+            response = processOnboardPackage(onboardPackageInfo, vspDetails, errorMessages);
+            final UploadFileResponseDto entity = (UploadFileResponseDto) response.getEntity();
+            if (artifactStorageManager.isEnabled()) {
+                if (!entity.getErrors().isEmpty()) {
+                    artifactStorageManager.delete(artifactInfo);
+                } else {
+                    artifactStorageManager.put(vspId, versionId + ".reduced", new ByteArrayInputStream(fileToUploadBytes));
+                }
             }
-        } else {
-            fileToUploadBytes = fileToUpload.getObject(byte[].class);
+            orchestrationTemplateCandidateUploadManager
+                .putUploadAsFinished(vspId, versionId, vspUploadStatus.getLockId(), VspUploadStatus.SUCCESS, user);
+        } catch (final Exception ex) {
+            if (vspUploadStatus != null) {
+                orchestrationTemplateCandidateUploadManager
+                    .putUploadAsFinished(vspId, versionId, vspUploadStatus.getLockId(), VspUploadStatus.ERROR, user);
+            }
+            throw ex;
         }
+        return response;
+    }
+
+    private ArtifactInfo handleArtifactStorage(final String vspId, final String versionId, final String filename,
+                                               final DataHandler artifactDataHandler) {
+        final Path tempArtifactPath;
+        try {
+            final ArtifactStorageConfig storageConfiguration = artifactStorageManager.getStorageConfiguration();
 
-        final var onboardingPackageProcessor = new OnboardingPackageProcessor(filename, fileToUploadBytes, new CnfPackageValidator(), artifactInfo);
-        final ErrorMessage[] errorMessages = onboardingPackageProcessor.getErrorMessages().toArray(new ErrorMessage[0]);
-        if (onboardingPackageProcessor.hasErrors()) {
-            return Response.status(NOT_ACCEPTABLE).entity(buildUploadResponseWithError(errorMessages)).build();
+            final Path folder = Path.of(storageConfiguration.getTempPath()).resolve(vspId).resolve(versionId);
+            tempArtifactPath = folder.resolve(UUID.randomUUID().toString());
+            Files.createDirectories(folder);
+            try (final InputStream packageInputStream = artifactDataHandler.getInputStream();
+                final var fileOutputStream = new FileOutputStream(tempArtifactPath.toFile())) {
+                packageInputStream.transferTo(fileOutputStream);
+            }
+        } catch (final Exception e) {
+            throw new ArtifactStorageException(UNEXPECTED_PROBLEM_HAPPENED_WHILE_GETTING.formatMessage(filename));
         }
-        final var onboardPackageInfo = onboardingPackageProcessor.getOnboardPackageInfo().orElse(null);
-        if (onboardPackageInfo == null) {
-            final UploadFileResponseDto uploadFileResponseDto = buildUploadResponseWithError(
-                new ErrorMessage(ErrorLevel.ERROR, PACKAGE_PROCESS_ERROR.formatMessage(filename)));
-            return Response.ok(uploadFileResponseDto).build();
+        final ArtifactInfo artifactInfo;
+        try (final InputStream inputStream = Files.newInputStream(tempArtifactPath)) {
+            artifactInfo = artifactStorageManager.upload(vspId, versionId, inputStream);
+        } catch (final Exception e) {
+            LOGGER.error("Package Size Reducer not configured", e);
+            throw new ArtifactStorageException(ERROR_HAS_OCCURRED_WHILE_PERSISTING_THE_ARTIFACT.formatMessage(filename));
         }
-        final var version = new Version(versionId);
-        final var vspDetails = vendorSoftwareProductManager.getVsp(vspId, version);
-        final Response response = processOnboardPackage(onboardPackageInfo, vspDetails, errorMessages);
-        final UploadFileResponseDto entity = (UploadFileResponseDto) response.getEntity();
-        if (artifactStorageManager.isEnabled()) {
-            if (!entity.getErrors().isEmpty()) {
-                artifactStorageManager.delete(artifactInfo);
-            } else {
-                artifactStorageManager.put(vspId, versionId + ".reduced", new ByteArrayInputStream(fileToUploadBytes));
-            }
+        try {
+            artifactInfo.setBytes(packageSizeReducer.reduce(tempArtifactPath));
+            Files.delete(tempArtifactPath);
+        } catch (final Exception e) {
+            LOGGER.error("Package Size Reducer not configured", e);
+            throw new ArtifactStorageException(ERROR_HAS_OCCURRED_WHILE_REDUCING_THE_ARTIFACT_SIZE.formatMessage(filename));
         }
-        return response;
+        return artifactInfo;
     }
 
     private Response processOnboardPackage(final OnboardPackageInfo onboardPackageInfo, final VspDetails vspDetails,
@@ -227,7 +253,7 @@ public class OrchestrationTemplateCandidateImpl implements OrchestrationTemplate
             fileName = "Candidate." + zipFile.get().getLeft();
         } else {
             zipFile = vendorSoftwareProductManager.get(vspId, new Version((versionId)));
-            if (!zipFile.isPresent()) {
+            if (zipFile.isEmpty()) {
                 ErrorMessage errorMessage = new ErrorMessage(ErrorLevel.ERROR,
                     getErrorWithParameters(NO_FILE_WAS_UPLOADED_OR_FILE_NOT_EXIST.getErrorMessage(), ""));
                 LOGGER.error(errorMessage.getMessage());
@@ -270,7 +296,7 @@ public class OrchestrationTemplateCandidateImpl implements OrchestrationTemplate
     @Override
     public Response getFilesDataStructure(String vspId, String versionId, String user) {
         Optional<FilesDataStructure> filesDataStructure = candidateManager.getFilesDataStructure(vspId, new Version(versionId));
-        if (!filesDataStructure.isPresent()) {
+        if (filesDataStructure.isEmpty()) {
             filesDataStructure = vendorSoftwareProductManager.getOrchestrationTemplateStructure(vspId, new Version(versionId));
         }
         FileDataStructureDto fileDataStructureDto = filesDataStructure
diff --git a/openecomp-be/api/openecomp-sdc-rest-webapp/vendor-software-products-rest/vendor-software-products-rest-services/src/main/java/org/openecomp/sdcrests/vsp/rest/services/OrchestrationTemplateCandidateUploadManager.java b/openecomp-be/api/openecomp-sdc-rest-webapp/vendor-software-products-rest/vendor-software-products-rest-services/src/main/java/org/openecomp/sdcrests/vsp/rest/services/OrchestrationTemplateCandidateUploadManager.java
new file mode 100644 (file)
index 0000000..0f33580
--- /dev/null
@@ -0,0 +1,63 @@
+/*
+ * -
+ *  ============LICENSE_START=======================================================
+ *  Copyright (C) 2022 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.sdcrests.vsp.rest.services;
+
+import java.util.Optional;
+import java.util.UUID;
+import org.openecomp.sdc.vendorsoftwareproduct.dao.type.VspUploadStatus;
+import org.openecomp.sdcrests.vendorsoftwareproducts.types.VspUploadStatusDto;
+
+public interface OrchestrationTemplateCandidateUploadManager {
+
+    /**
+     * Creates a lock to start uploading a package.
+     *
+     * @param vspId        the Vendor Software Product id
+     * @param vspVersionId the Vendor Software Product version id
+     * @param user         the current user
+     * @return a new upload status containing the lock
+     */
+    VspUploadStatusDto putUploadInProgress(String vspId, String vspVersionId, String user);
+
+    /**
+     * Finishes the upload process, applying the given VspUploadStatusType completion status.
+     *
+     * @param vspId            the Vendor Software Product id
+     * @param vspVersionId     the Vendor Software Product version id
+     * @param lockId           the upload lock id
+     * @param completionStatus any status that represents a completion
+     * @param user             the current user
+     * @return the updated status
+     */
+    VspUploadStatusDto putUploadAsFinished(final String vspId, final String vspVersionId, final UUID lockId, final VspUploadStatus completionStatus,
+                                           final String user);
+
+    /**
+     * Finds the latest upload status for a given Vendor Software Product version.
+     *
+     * @param vspId        the Vendor Software Product id
+     * @param vspVersionId the Vendor Software Product version id
+     * @param user         the current user
+     * @return the latest upload status for the requested Vendor Software Product version
+     */
+    Optional<VspUploadStatusDto> findLatestStatus(String vspId, String vspVersionId, String user);
+}
diff --git a/openecomp-be/api/openecomp-sdc-rest-webapp/vendor-software-products-rest/vendor-software-products-rest-services/src/main/java/org/openecomp/sdcrests/vsp/rest/services/OrchestrationTemplateCandidateUploadManagerImpl.java b/openecomp-be/api/openecomp-sdc-rest-webapp/vendor-software-products-rest/vendor-software-products-rest-services/src/main/java/org/openecomp/sdcrests/vsp/rest/services/OrchestrationTemplateCandidateUploadManagerImpl.java
new file mode 100644 (file)
index 0000000..d7cfe04
--- /dev/null
@@ -0,0 +1,171 @@
+/*
+ * -
+ *  ============LICENSE_START=======================================================
+ *  Copyright (C) 2022 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.sdcrests.vsp.rest.services;
+
+import static org.openecomp.sdcrests.vsp.rest.exception.OrchestrationTemplateCandidateUploadManagerExceptionSupplier.couldNotCreateLock;
+import static org.openecomp.sdcrests.vsp.rest.exception.OrchestrationTemplateCandidateUploadManagerExceptionSupplier.couldNotFindLock;
+import static org.openecomp.sdcrests.vsp.rest.exception.OrchestrationTemplateCandidateUploadManagerExceptionSupplier.couldNotUpdateLock;
+import static org.openecomp.sdcrests.vsp.rest.exception.OrchestrationTemplateCandidateUploadManagerExceptionSupplier.uploadAlreadyFinished;
+import static org.openecomp.sdcrests.vsp.rest.exception.OrchestrationTemplateCandidateUploadManagerExceptionSupplier.vspUploadAlreadyInProgress;
+
+import java.util.Date;
+import java.util.List;
+import java.util.Optional;
+import java.util.UUID;
+import java.util.concurrent.locks.Lock;
+import java.util.concurrent.locks.ReentrantLock;
+import org.openecomp.sdc.common.errors.CoreException;
+import org.openecomp.sdc.vendorsoftwareproduct.VendorSoftwareProductManager;
+import org.openecomp.sdc.vendorsoftwareproduct.VspManagerFactory;
+import org.openecomp.sdc.vendorsoftwareproduct.dao.VspUploadStatusRecordDao;
+import org.openecomp.sdc.vendorsoftwareproduct.dao.type.VspDetails;
+import org.openecomp.sdc.vendorsoftwareproduct.dao.type.VspUploadStatus;
+import org.openecomp.sdc.vendorsoftwareproduct.dao.type.VspUploadStatusRecord;
+import org.openecomp.sdc.versioning.dao.types.Version;
+import org.openecomp.sdcrests.vendorsoftwareproducts.types.VspUploadStatusDto;
+import org.openecomp.sdcrests.vsp.rest.exception.OrchestrationTemplateCandidateUploadManagerExceptionSupplier;
+import org.openecomp.sdcrests.vsp.rest.mapping.VspUploadStatusRecordMapper;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.beans.factory.annotation.Qualifier;
+import org.springframework.stereotype.Service;
+
+/**
+ * Manages the package upload process status.
+ */
+@Service
+public class OrchestrationTemplateCandidateUploadManagerImpl implements OrchestrationTemplateCandidateUploadManager {
+
+    private static final Logger LOGGER = LoggerFactory.getLogger(OrchestrationTemplateCandidateUploadManagerImpl.class);
+
+    private final VspUploadStatusRecordDao uploadManagerDao;
+    private final VspUploadStatusRecordMapper vspUploadStatusRecordMapper;
+    private final VendorSoftwareProductManager vendorSoftwareProductManager;
+    private final Lock startUploadLock;
+
+    @Autowired
+    public OrchestrationTemplateCandidateUploadManagerImpl(
+        @Qualifier("vsp-upload-status-record-dao-impl") final VspUploadStatusRecordDao uploadManagerDao) {
+
+        this.uploadManagerDao = uploadManagerDao;
+        this.vendorSoftwareProductManager = VspManagerFactory.getInstance().createInterface();
+        this.vspUploadStatusRecordMapper = new VspUploadStatusRecordMapper();
+        startUploadLock = new ReentrantLock();
+    }
+
+    //for tests purpose
+    OrchestrationTemplateCandidateUploadManagerImpl(final VspUploadStatusRecordDao uploadManagerDao,
+                                                    final VendorSoftwareProductManager vendorSoftwareProductManager) {
+        this.uploadManagerDao = uploadManagerDao;
+        this.vendorSoftwareProductManager = vendorSoftwareProductManager;
+        this.vspUploadStatusRecordMapper = new VspUploadStatusRecordMapper();
+        startUploadLock = new ReentrantLock();
+    }
+
+    @Override
+    public VspUploadStatusDto putUploadInProgress(final String vspId, final String vspVersionId, final String user) {
+        checkVspExists(vspId, vspVersionId);
+        LOGGER.debug("Start uploading for VSP id '{}', version '{}', triggered by user '{}'", vspId, vspVersionId, user);
+
+        final VspUploadStatusRecord vspUploadStatusRecord;
+        startUploadLock.lock();
+        try {
+            final List<VspUploadStatusRecord> uploadInProgressList = uploadManagerDao.findAllInProgress(vspId, vspVersionId);
+            if (!uploadInProgressList.isEmpty()) {
+                throw vspUploadAlreadyInProgress(vspId, vspVersionId).get();
+            }
+
+            vspUploadStatusRecord = new VspUploadStatusRecord();
+            vspUploadStatusRecord.setStatus(VspUploadStatus.UPLOADING);
+            vspUploadStatusRecord.setVspId(vspId);
+            vspUploadStatusRecord.setVspVersionId(vspVersionId);
+            vspUploadStatusRecord.setLockId(UUID.randomUUID());
+            vspUploadStatusRecord.setCreated(new Date());
+
+            uploadManagerDao.create(vspUploadStatusRecord);
+            LOGGER.debug("Upload lock '{}' created for VSP id '{}', version '{}'", vspUploadStatusRecord.getLockId(), vspId, vspVersionId);
+        } catch (final CoreException e) {
+            throw e;
+        } catch (final Exception e) {
+            throw couldNotCreateLock(vspId, vspVersionId, e).get();
+        } finally {
+            startUploadLock.unlock();
+        }
+
+        return vspUploadStatusRecordMapper.applyMapping(vspUploadStatusRecord, VspUploadStatusDto.class);
+    }
+
+    @Override
+    public VspUploadStatusDto putUploadAsFinished(final String vspId, final String vspVersionId, final UUID lockId, final VspUploadStatus completionStatus,
+                                                  final String user) {
+
+        if (!completionStatus.isCompleteStatus()) {
+            throw OrchestrationTemplateCandidateUploadManagerExceptionSupplier.invalidCompleteStatus(completionStatus).get();
+        }
+        final Optional<VspUploadStatusRecord> vspUploadStatusOptional =
+            uploadManagerDao.findByVspIdAndVersionIdAndLockId(vspId, vspVersionId, lockId);
+        if (vspUploadStatusOptional.isEmpty()) {
+            throw couldNotFindLock(lockId, vspId, vspVersionId).get();
+        }
+        final VspUploadStatusRecord vspUploadStatusRecord = vspUploadStatusOptional.get();
+        if (vspUploadStatusRecord.getIsComplete()) {
+            throw uploadAlreadyFinished(lockId, vspId, vspVersionId).get();
+        }
+        LOGGER.debug("Finishing the upload for VSP id '{}', version '{}', lock '{}', triggered by user '{}'",
+            vspUploadStatusRecord.getVspId(), vspUploadStatusRecord.getVspVersionId(), vspUploadStatusRecord.getLockId(), user);
+        vspUploadStatusRecord.setStatus(completionStatus);
+        vspUploadStatusRecord.setUpdated(new Date());
+        vspUploadStatusRecord.setIsComplete(true);
+
+        try {
+            uploadManagerDao.update(vspUploadStatusRecord);
+            LOGGER.debug("Upload complete for VSP '{}', version '{}', lock '{}'",
+                vspUploadStatusRecord.getLockId(), vspUploadStatusRecord.getVspId(), vspUploadStatusRecord.getVspVersionId());
+        } catch (final Exception e) {
+            throw couldNotUpdateLock(vspUploadStatusRecord.getLockId(), vspUploadStatusRecord.getVspId(), vspUploadStatusRecord.getVspVersionId(), e)
+                .get();
+        }
+
+        return vspUploadStatusRecordMapper.applyMapping(vspUploadStatusRecord, VspUploadStatusDto.class);
+    }
+
+    private void checkVspExists(final String vspId, final String vspVersionId) {
+        final VspDetails vspDetails = vendorSoftwareProductManager.getVsp(vspId, new Version(vspVersionId));
+        if (vspDetails == null) {
+            throw OrchestrationTemplateCandidateUploadManagerExceptionSupplier.vspNotFound(vspId, vspVersionId).get();
+        }
+    }
+
+    @Override
+    public Optional<VspUploadStatusDto> findLatestStatus(final String vspId, final String vspVersionId, final String user) {
+        checkVspExists(vspId, vspVersionId);
+
+        final Optional<VspUploadStatusRecord> vspUploadStatus = uploadManagerDao.findLatest(vspId, vspVersionId);
+        if (vspUploadStatus.isEmpty()) {
+            return Optional.empty();
+        }
+
+        return Optional.of(vspUploadStatusRecordMapper.applyMapping(vspUploadStatus.get(), VspUploadStatusDto.class));
+    }
+
+}
diff --git a/openecomp-be/api/openecomp-sdc-rest-webapp/vendor-software-products-rest/vendor-software-products-rest-services/src/test/java/org/openecomp/sdcrests/vsp/rest/controllers/OrchestrationTemplateCandidateUploadManagerControllerImplTest.java b/openecomp-be/api/openecomp-sdc-rest-webapp/vendor-software-products-rest/vendor-software-products-rest-services/src/test/java/org/openecomp/sdcrests/vsp/rest/controllers/OrchestrationTemplateCandidateUploadManagerControllerImplTest.java
new file mode 100644 (file)
index 0000000..db66f91
--- /dev/null
@@ -0,0 +1,92 @@
+/*
+ * -
+ *  ============LICENSE_START=======================================================
+ *  Copyright (C) 2022 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.sdcrests.vsp.rest.controllers;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+import static org.mockito.Mockito.when;
+
+import java.util.Date;
+import java.util.Optional;
+import java.util.UUID;
+import javax.ws.rs.core.Response;
+import org.apache.http.HttpStatus;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+import org.mockito.InjectMocks;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+import org.openecomp.sdc.vendorsoftwareproduct.dao.type.VspUploadStatus;
+import org.openecomp.sdcrests.vendorsoftwareproducts.types.VspUploadStatusDto;
+import org.openecomp.sdcrests.vsp.rest.services.OrchestrationTemplateCandidateUploadManager;
+
+class OrchestrationTemplateCandidateUploadManagerControllerImplTest {
+
+    @Mock
+    private OrchestrationTemplateCandidateUploadManager orchestrationTemplateCandidateUploadManager;
+
+    @InjectMocks
+    private OrchestrationTemplateCandidateUploadManagerControllerImpl packageUploadManagerControllerImpl;
+
+    @BeforeEach
+    void setUp() {
+        MockitoAnnotations.openMocks(this);
+    }
+
+    @Test
+    void getLatestSuccessTest() {
+        //given
+        final String vspId = "vspId";
+        final String vspVersionId = "vspVersionId";
+        final String username = "username";
+        final VspUploadStatusDto vspUploadStatusDto = buildDefaultVspUploadStatus(vspId, vspVersionId);
+        //when
+        when(orchestrationTemplateCandidateUploadManager.findLatestStatus(vspId, vspVersionId, username)).thenReturn(Optional.of(vspUploadStatusDto));
+
+        final Response response = packageUploadManagerControllerImpl.getLatestStatus(vspId, vspVersionId, username);
+        //then
+        assertEquals(HttpStatus.SC_OK, response.getStatus());
+        final Object actualEntity = response.getEntity();
+        assertTrue(actualEntity instanceof VspUploadStatusDto);
+        assertEquals(vspUploadStatusDto, actualEntity);
+    }
+
+    private VspUploadStatusDto buildDefaultVspUploadStatus(final String vspId, final String vspVersionId) {
+        final var vspUploadStatusDto = new VspUploadStatusDto();
+        vspUploadStatusDto.setStatus(VspUploadStatus.UPLOADING);
+        vspUploadStatusDto.setLockId(UUID.randomUUID());
+        vspUploadStatusDto.setVspId(vspId);
+        vspUploadStatusDto.setVspVersionId(vspVersionId);
+        vspUploadStatusDto.setCreated(new Date());
+        vspUploadStatusDto.setComplete(false);
+        return vspUploadStatusDto;
+    }
+
+    @Test
+    void buildGetUrlSuccessTest() {
+        final String vspId = "vspId";
+        final String vspVersionId = "vspVersionId";
+        final String actualGetUrl = OrchestrationTemplateCandidateUploadManagerControllerImpl.buildGetUrl(vspId, vspVersionId);
+        assertEquals("/v1.0/vendor-software-products/vspId/versions/vspVersionId/orchestration-template-candidate/upload", actualGetUrl);
+    }
+
+}
\ No newline at end of file
diff --git a/openecomp-be/api/openecomp-sdc-rest-webapp/vendor-software-products-rest/vendor-software-products-rest-services/src/test/java/org/openecomp/sdcrests/vsp/rest/mapping/VspUploadStatusRecordMapperTest.java b/openecomp-be/api/openecomp-sdc-rest-webapp/vendor-software-products-rest/vendor-software-products-rest-services/src/test/java/org/openecomp/sdcrests/vsp/rest/mapping/VspUploadStatusRecordMapperTest.java
new file mode 100644 (file)
index 0000000..9bba87b
--- /dev/null
@@ -0,0 +1,59 @@
+/*
+ * -
+ *  ============LICENSE_START=======================================================
+ *  Copyright (C) 2022 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.sdcrests.vsp.rest.mapping;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+
+import java.util.Date;
+import java.util.UUID;
+import org.junit.jupiter.api.Test;
+import org.openecomp.sdc.vendorsoftwareproduct.dao.type.VspUploadStatusRecord;
+import org.openecomp.sdc.vendorsoftwareproduct.dao.type.VspUploadStatus;
+import org.openecomp.sdcrests.vendorsoftwareproducts.types.VspUploadStatusDto;
+
+class VspUploadStatusRecordMapperTest {
+
+    @Test
+    void fullMappingTest() {
+        //given
+        final VspUploadStatusRecordMapper vspUploadStatusRecordMapper = new VspUploadStatusRecordMapper();
+        final var vspUploadStatus = new VspUploadStatusRecord();
+        vspUploadStatus.setVspId("vspId");
+        vspUploadStatus.setVspVersionId("vspVersionId");
+        vspUploadStatus.setStatus(VspUploadStatus.UPLOADING);
+        vspUploadStatus.setLockId(UUID.randomUUID());
+        vspUploadStatus.setIsComplete(true);
+        vspUploadStatus.setCreated(new Date());
+        vspUploadStatus.setUpdated(new Date());
+        final var vspUploadStatusDto = new VspUploadStatusDto();
+        //when
+        vspUploadStatusRecordMapper.doMapping(vspUploadStatus, vspUploadStatusDto);
+        //then
+        assertEquals(vspUploadStatus.getVspId(), vspUploadStatusDto.getVspId());
+        assertEquals(vspUploadStatus.getVspVersionId(), vspUploadStatusDto.getVspVersionId());
+        assertEquals(vspUploadStatus.getStatus(), vspUploadStatusDto.getStatus());
+        assertEquals(vspUploadStatus.getLockId(), vspUploadStatusDto.getLockId());
+        assertEquals(vspUploadStatus.getIsComplete(), vspUploadStatusDto.isComplete());
+        assertEquals(vspUploadStatus.getCreated(), vspUploadStatusDto.getCreated());
+        assertEquals(vspUploadStatus.getUpdated(), vspUploadStatusDto.getUpdated());
+    }
+}
\ No newline at end of file
index 2d2c308..6e0231a 100644 (file)
@@ -28,7 +28,7 @@ import static org.junit.jupiter.api.Assertions.assertNull;
 import static org.junit.jupiter.api.Assertions.assertTrue;
 import static org.junit.jupiter.api.Assertions.fail;
 import static org.mockito.ArgumentMatchers.any;
-import static org.mockito.ArgumentMatchers.anyString;
+import static org.mockito.ArgumentMatchers.eq;
 import static org.mockito.Mockito.when;
 
 import java.io.IOException;
@@ -76,6 +76,7 @@ import org.openecomp.sdc.vendorsoftwareproduct.types.candidateheat.Module;
 import org.openecomp.sdcrests.vendorsoftwareproducts.types.FileDataStructureDto;
 import org.openecomp.sdcrests.vendorsoftwareproducts.types.OrchestrationTemplateActionResponseDto;
 import org.openecomp.sdcrests.vendorsoftwareproducts.types.UploadFileResponseDto;
+import org.openecomp.sdcrests.vendorsoftwareproducts.types.VspUploadStatusDto;
 
 class OrchestrationTemplateCandidateImplTest {
 
@@ -94,6 +95,8 @@ class OrchestrationTemplateCandidateImplTest {
     private ArtifactStorageManager artifactStorageManager;
     @Mock
     private PackageSizeReducer packageSizeReducer;
+    @Mock
+    private OrchestrationTemplateCandidateUploadManager orchestrationTemplateCandidateUploadManager;
     @InjectMocks
     private OrchestrationTemplateCandidateImpl orchestrationTemplateCandidate;
 
@@ -146,15 +149,21 @@ class OrchestrationTemplateCandidateImplTest {
 
     @Test
     void uploadSignedTest() throws IOException {
+        final String vspId = "vspId";
+        final String versionId = "versionId";
+        when(orchestrationTemplateCandidateUploadManager.putUploadInProgress(vspId, versionId, user)).thenReturn(new VspUploadStatusDto());
         Response response = orchestrationTemplateCandidate
-            .upload("1", "1", mockAttachment("filename.zip", this.getClass().getResource("/files/sample-signed.zip")), user);
+            .upload(vspId, versionId, mockAttachment("filename.zip", this.getClass().getResource("/files/sample-signed.zip")), user);
         assertEquals(Status.OK.getStatusCode(), response.getStatus());
         assertTrue(((UploadFileResponseDto) response.getEntity()).getErrors().isEmpty());
     }
 
     @Test
     void uploadNotSignedTest() throws IOException {
-        Response response = orchestrationTemplateCandidate.upload("1", "1",
+        final String vspId = "vspId";
+        final String versionId = "versionId";
+        when(orchestrationTemplateCandidateUploadManager.putUploadInProgress(vspId, versionId, user)).thenReturn(new VspUploadStatusDto());
+        Response response = orchestrationTemplateCandidate.upload(vspId, versionId,
             mockAttachment("filename.csar", this.getClass().getResource("/files/sample-not-signed.csar")), user);
         assertEquals(Status.OK.getStatusCode(), response.getStatus());
         assertTrue(((UploadFileResponseDto) response.getEntity()).getErrors().isEmpty());
@@ -167,11 +176,15 @@ class OrchestrationTemplateCandidateImplTest {
             new MinIoStorageArtifactStorageConfig(true, new EndPoint("host", 9000, false), new Credentials("accessKey", "secretKey"), "tempPath"));
 
         final Path path = Path.of("src/test/resources/files/sample-not-signed.csar");
-        when(artifactStorageManager.upload(anyString(), anyString(), any())).thenReturn(new MinIoArtifactInfo("vspId", "name"));
+        final String vspId = "vspId";
+        final String versionId = "versionId";
+        when(artifactStorageManager.upload(eq(vspId), eq(versionId), any())).thenReturn(new MinIoArtifactInfo("vspId", "name"));
         final byte[] bytes = Files.readAllBytes(path);
         when(packageSizeReducer.reduce(any())).thenReturn(bytes);
 
-        Response response = orchestrationTemplateCandidate.upload("1", "1",
+        when(orchestrationTemplateCandidateUploadManager.putUploadInProgress(vspId, versionId, user)).thenReturn(new VspUploadStatusDto());
+
+        Response response = orchestrationTemplateCandidate.upload(vspId, versionId,
             mockAttachment("filename.csar", this.getClass().getResource("/files/sample-not-signed.csar")), user);
         assertEquals(Status.OK.getStatusCode(), response.getStatus());
         assertTrue(((UploadFileResponseDto) response.getEntity()).getErrors().isEmpty());
diff --git a/openecomp-be/api/openecomp-sdc-rest-webapp/vendor-software-products-rest/vendor-software-products-rest-services/src/test/java/org/openecomp/sdcrests/vsp/rest/services/OrchestrationTemplateCandidateUploadManagerImplTest.java b/openecomp-be/api/openecomp-sdc-rest-webapp/vendor-software-products-rest/vendor-software-products-rest-services/src/test/java/org/openecomp/sdcrests/vsp/rest/services/OrchestrationTemplateCandidateUploadManagerImplTest.java
new file mode 100644 (file)
index 0000000..9a7629f
--- /dev/null
@@ -0,0 +1,312 @@
+/*
+ * -
+ *  ============LICENSE_START=======================================================
+ *  Copyright (C) 2022 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.sdcrests.vsp.rest.services;
+
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertFalse;
+import static org.junit.jupiter.api.Assertions.assertNotNull;
+import static org.junit.jupiter.api.Assertions.assertThrows;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.Mockito.doThrow;
+import static org.mockito.Mockito.when;
+
+import java.util.Date;
+import java.util.List;
+import java.util.Optional;
+import java.util.UUID;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+import org.mockito.InjectMocks;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+import org.openecomp.sdc.common.errors.CoreException;
+import org.openecomp.sdc.vendorsoftwareproduct.VendorSoftwareProductManager;
+import org.openecomp.sdc.vendorsoftwareproduct.dao.VspUploadStatusRecordDao;
+import org.openecomp.sdc.vendorsoftwareproduct.dao.type.VspDetails;
+import org.openecomp.sdc.vendorsoftwareproduct.dao.type.VspUploadStatus;
+import org.openecomp.sdc.vendorsoftwareproduct.dao.type.VspUploadStatusRecord;
+import org.openecomp.sdc.versioning.dao.types.Version;
+import org.openecomp.sdcrests.vendorsoftwareproducts.types.VspUploadStatusDto;
+import org.openecomp.sdcrests.vsp.rest.exception.OrchestrationTemplateCandidateUploadManagerExceptionSupplier;
+
+class OrchestrationTemplateCandidateUploadManagerImplTest {
+
+    @Mock
+    private VspUploadStatusRecordDao vspUploadStatusRecordDao;
+    @Mock
+    private VendorSoftwareProductManager vendorSoftwareProductManager;
+    @InjectMocks
+    private OrchestrationTemplateCandidateUploadManagerImpl packageUploadManagerImpl;
+
+    @BeforeEach
+    void setUp() {
+        MockitoAnnotations.openMocks(this);
+    }
+
+    @Test
+    void startUploadSuccessTest() {
+        //given
+        final String vspId = "vspId";
+        final String vspVersionId = "vspVersionId";
+        final String username = "username";
+        when(vendorSoftwareProductManager.getVsp(vspId, new Version(vspVersionId))).thenReturn(new VspDetails());
+        //when
+        final VspUploadStatusDto vspUploadStatusDto = packageUploadManagerImpl.putUploadInProgress(vspId, vspVersionId, username);
+        //then
+        assertEquals(vspId, vspUploadStatusDto.getVspId());
+        assertEquals(vspVersionId, vspUploadStatusDto.getVspVersionId());
+        assertEquals(VspUploadStatus.UPLOADING, vspUploadStatusDto.getStatus());
+        assertFalse(vspUploadStatusDto.isComplete());
+        assertNotNull(vspUploadStatusDto.getLockId());
+        assertNotNull(vspUploadStatusDto.getCreated());
+    }
+
+    @Test
+    void startUpload_uploadAlreadyInProgressTest() {
+        //given
+        final String vspId = "vspId";
+        final String vspVersionId = "vspVersionId";
+        final String username = "username";
+        when(vspUploadStatusRecordDao.findAllInProgress(vspId, vspVersionId)).thenReturn(List.of(new VspUploadStatusRecord()));
+        when(vendorSoftwareProductManager.getVsp(vspId, new Version(vspVersionId))).thenReturn(new VspDetails());
+        //when/then
+        final CoreException actualCoreException =
+            assertThrows(CoreException.class, () -> packageUploadManagerImpl.putUploadInProgress(vspId, vspVersionId, username));
+        final CoreException expectedCoreException = OrchestrationTemplateCandidateUploadManagerExceptionSupplier.vspUploadAlreadyInProgress(vspId,
+            vspVersionId).get();
+        assertEquals(expectedCoreException.code().id(), actualCoreException.code().id());
+        assertEquals(expectedCoreException.code().message(), actualCoreException.code().message());
+    }
+
+    @Test
+    void startUpload_vspNotFoundTest() {
+        //given
+        final String vspId = "vspId";
+        final String vspVersionId = "vspVersionId";
+        final String username = "username";
+        //when/then
+        final CoreException actualCoreException =
+            assertThrows(CoreException.class, () -> packageUploadManagerImpl.putUploadInProgress(vspId, vspVersionId, username));
+        final CoreException expectedCoreException = OrchestrationTemplateCandidateUploadManagerExceptionSupplier.vspNotFound(vspId, vspVersionId)
+            .get();
+        assertEquals(expectedCoreException.code().id(), actualCoreException.code().id());
+        assertEquals(expectedCoreException.code().message(), actualCoreException.code().message());
+    }
+
+    @Test
+    void startUpload_createLockErrorTest() {
+        //given
+        final String vspId = "vspId";
+        final String vspVersionId = "vspVersionId";
+        final String username = "username";
+        //when/then
+        when(vendorSoftwareProductManager.getVsp(vspId, new Version(vspVersionId))).thenReturn(new VspDetails());
+        doThrow(new RuntimeException()).when(vspUploadStatusRecordDao).create(any(VspUploadStatusRecord.class));
+        final CoreException actualCoreException =
+            assertThrows(CoreException.class, () -> packageUploadManagerImpl.putUploadInProgress(vspId, vspVersionId, username));
+        final CoreException expectedCoreException =
+            OrchestrationTemplateCandidateUploadManagerExceptionSupplier.couldNotCreateLock(vspId, vspVersionId, new RuntimeException()).get();
+        assertEquals(expectedCoreException.code().id(), actualCoreException.code().id());
+        assertEquals(expectedCoreException.code().message(), actualCoreException.code().message());
+    }
+
+    @Test
+    void finishUploadSuccessTest() {
+        //given
+        final String vspId = "vspId";
+        final String vspVersionId = "vspVersionId";
+        final UUID lockId = UUID.randomUUID();
+        final String username = "username";
+        final VspUploadStatusRecord vspUploadStatusRecord = new VspUploadStatusRecord();
+        vspUploadStatusRecord.setVspId(vspId);
+        vspUploadStatusRecord.setVspVersionId(vspVersionId);
+        vspUploadStatusRecord.setLockId(lockId);
+        vspUploadStatusRecord.setStatus(VspUploadStatus.UPLOADING);
+        vspUploadStatusRecord.setCreated(new Date());
+        when(vspUploadStatusRecordDao.findByVspIdAndVersionIdAndLockId(vspId, vspVersionId, lockId))
+            .thenReturn(Optional.of(vspUploadStatusRecord));
+        //when
+        final VspUploadStatusDto actualVspUploadStatus = packageUploadManagerImpl
+            .putUploadAsFinished(vspId, vspVersionId, lockId, VspUploadStatus.SUCCESS, username);
+        //then
+        assertEquals(vspId, actualVspUploadStatus.getVspId());
+        assertEquals(vspVersionId, actualVspUploadStatus.getVspVersionId());
+        assertEquals(VspUploadStatus.SUCCESS, actualVspUploadStatus.getStatus());
+        assertEquals(vspUploadStatusRecord.getLockId(), actualVspUploadStatus.getLockId());
+        assertEquals(vspUploadStatusRecord.getCreated(), actualVspUploadStatus.getCreated());
+        assertNotNull(actualVspUploadStatus.getUpdated());
+        assertTrue(actualVspUploadStatus.isComplete());
+    }
+
+    @Test
+    void finishUploadIllegalStatusTest() {
+        final UUID lockId = UUID.randomUUID();
+        IllegalArgumentException actualException = assertThrows(IllegalArgumentException.class,
+            () -> packageUploadManagerImpl.putUploadAsFinished("vspId", "vspVersionId", lockId, VspUploadStatus.UPLOADING, "username"));
+        IllegalArgumentException expectedException = OrchestrationTemplateCandidateUploadManagerExceptionSupplier.invalidCompleteStatus(
+            VspUploadStatus.UPLOADING).get();
+        assertEquals(expectedException.getMessage(), actualException.getMessage());
+
+        actualException = assertThrows(IllegalArgumentException.class,
+            () -> packageUploadManagerImpl
+                .putUploadAsFinished("vspId", "vspVersionId", lockId, VspUploadStatus.PROCESSING, "username")
+        );
+        expectedException = OrchestrationTemplateCandidateUploadManagerExceptionSupplier.invalidCompleteStatus(
+            VspUploadStatus.PROCESSING).get();
+        assertEquals(expectedException.getMessage(), actualException.getMessage());
+    }
+
+    @Test
+    void finishUploadCouldNotFindLockTest() {
+        //given
+        final String vspId = "vspId";
+        final String vspVersionId = "vspVersionId";
+        final UUID lockId = UUID.randomUUID();
+        final String username = "username";
+        final VspUploadStatusRecord vspUploadStatusRecord = new VspUploadStatusRecord();
+        vspUploadStatusRecord.setVspId(vspId);
+        vspUploadStatusRecord.setVspVersionId(vspVersionId);
+        vspUploadStatusRecord.setLockId(lockId);
+        vspUploadStatusRecord.setStatus(VspUploadStatus.UPLOADING);
+        vspUploadStatusRecord.setCreated(new Date());
+        when(vspUploadStatusRecordDao.findByVspIdAndVersionIdAndLockId(vspId, vspVersionId, lockId))
+            .thenReturn(Optional.empty());
+        //when/then
+        final CoreException actualException = assertThrows(CoreException.class,
+            () -> packageUploadManagerImpl.putUploadAsFinished(vspId, vspVersionId, lockId, VspUploadStatus.SUCCESS, username));
+
+        final CoreException expectedException =
+            OrchestrationTemplateCandidateUploadManagerExceptionSupplier.couldNotFindLock(lockId, vspId, vspVersionId).get();
+        assertEquals(expectedException.getMessage(), actualException.getMessage());
+    }
+
+    @Test
+    void finishUpload_uploadAlreadyFinishedTest() {
+        //given
+        final String vspId = "vspId";
+        final String vspVersionId = "vspVersionId";
+        final UUID lockId = UUID.randomUUID();
+        final String username = "username";
+        final VspUploadStatusRecord vspUploadStatusRecord = new VspUploadStatusRecord();
+        vspUploadStatusRecord.setVspId(vspId);
+        vspUploadStatusRecord.setVspVersionId(vspVersionId);
+        vspUploadStatusRecord.setLockId(lockId);
+        vspUploadStatusRecord.setIsComplete(true);
+        when(vspUploadStatusRecordDao.findByVspIdAndVersionIdAndLockId(vspId, vspVersionId, lockId))
+            .thenReturn(Optional.of(vspUploadStatusRecord));
+        //when/then
+        final CoreException actualException = assertThrows(CoreException.class, () -> packageUploadManagerImpl
+            .putUploadAsFinished(vspId, vspVersionId, lockId, VspUploadStatus.SUCCESS, username));
+
+        final CoreException expectedException =
+            OrchestrationTemplateCandidateUploadManagerExceptionSupplier.uploadAlreadyFinished(lockId, vspId, vspVersionId).get();
+        assertEquals(expectedException.getMessage(), actualException.getMessage());
+    }
+
+    @Test
+    void finishUploadCouldNotUpdateLockTest() {
+        //given
+        final String vspId = "vspId";
+        final String vspVersionId = "vspVersionId";
+        final UUID lockId = UUID.randomUUID();
+        final String username = "username";
+        final VspUploadStatusRecord vspUploadStatusRecord = new VspUploadStatusRecord();
+        vspUploadStatusRecord.setVspId(vspId);
+        vspUploadStatusRecord.setVspVersionId(vspVersionId);
+        vspUploadStatusRecord.setLockId(lockId);
+        vspUploadStatusRecord.setStatus(VspUploadStatus.UPLOADING);
+        vspUploadStatusRecord.setCreated(new Date());
+        when(vspUploadStatusRecordDao.findByVspIdAndVersionIdAndLockId(vspId, vspVersionId, lockId))
+            .thenReturn(Optional.of(vspUploadStatusRecord));
+        doThrow(new RuntimeException()).when(vspUploadStatusRecordDao).update(vspUploadStatusRecord);
+        //when/then
+        final CoreException actualException = assertThrows(CoreException.class, () -> packageUploadManagerImpl
+            .putUploadAsFinished(vspId, vspVersionId, lockId, VspUploadStatus.SUCCESS, username));
+
+        final CoreException expectedException =
+            OrchestrationTemplateCandidateUploadManagerExceptionSupplier
+                .couldNotUpdateLock(lockId, vspId, vspVersionId, new RuntimeException()).get();
+        assertEquals(expectedException.getMessage(), actualException.getMessage());
+    }
+
+    @Test
+    void findLatestSuccessTest() {
+        //given
+        final String vspId = "vspId";
+        final String vspVersionId = "vspVersionId";
+        final String username = "username";
+        when(vendorSoftwareProductManager.getVsp(vspId, new Version(vspVersionId))).thenReturn(new VspDetails());
+        final var expectedVspUploadStatus = new VspUploadStatusRecord();
+        expectedVspUploadStatus.setStatus(VspUploadStatus.UPLOADING);
+        expectedVspUploadStatus.setLockId(UUID.randomUUID());
+        expectedVspUploadStatus.setVspId(vspId);
+        expectedVspUploadStatus.setVspVersionId(vspVersionId);
+        expectedVspUploadStatus.setCreated(new Date());
+        expectedVspUploadStatus.setUpdated(new Date());
+        expectedVspUploadStatus.setIsComplete(true);
+        when(vspUploadStatusRecordDao.findLatest(vspId, vspVersionId)).thenReturn(Optional.of(expectedVspUploadStatus));
+        //when
+        final Optional<VspUploadStatusDto> actualVspUploadStatusDtoOpt = packageUploadManagerImpl.findLatestStatus(vspId, vspVersionId, username);
+        //then
+        assertTrue(actualVspUploadStatusDtoOpt.isPresent());
+        final VspUploadStatusDto actualVspUploadStatusDto = actualVspUploadStatusDtoOpt.get();
+        assertEquals(expectedVspUploadStatus.getVspId(), actualVspUploadStatusDto.getVspId());
+        assertEquals(expectedVspUploadStatus.getVspVersionId(), actualVspUploadStatusDto.getVspVersionId());
+        assertEquals(expectedVspUploadStatus.getLockId(), actualVspUploadStatusDto.getLockId());
+        assertEquals(expectedVspUploadStatus.getIsComplete(), actualVspUploadStatusDto.isComplete());
+        assertEquals(expectedVspUploadStatus.getCreated(), actualVspUploadStatusDto.getCreated());
+        assertEquals(expectedVspUploadStatus.getUpdated(), actualVspUploadStatusDto.getUpdated());
+        assertEquals(expectedVspUploadStatus.getStatus(), actualVspUploadStatusDto.getStatus());
+    }
+
+    @Test
+    void findLatest_noStatusFoundTest() {
+        //given
+        final String vspId = "vspId";
+        final String vspVersionId = "vspVersionId";
+        final String username = "username";
+        when(vendorSoftwareProductManager.getVsp(vspId, new Version(vspVersionId))).thenReturn(new VspDetails());
+        when(vspUploadStatusRecordDao.findLatest(vspId, vspVersionId)).thenReturn(Optional.empty());
+        //when
+        final Optional<VspUploadStatusDto> actualVspUploadStatusDtoOpt = packageUploadManagerImpl.findLatestStatus(vspId, vspVersionId, username);
+        //then
+        assertTrue(actualVspUploadStatusDtoOpt.isEmpty());
+    }
+
+    @Test
+    void findLatest_vspNotFoundTest() {
+        //given
+        final String vspId = "vspId";
+        final String vspVersionId = "vspVersionId";
+        final String username = "username";
+        //when/then
+        final CoreException actualCoreException =
+            assertThrows(CoreException.class, () -> packageUploadManagerImpl.findLatestStatus(vspId, vspVersionId, username));
+        final CoreException expectedCoreException = OrchestrationTemplateCandidateUploadManagerExceptionSupplier.vspNotFound(vspId, vspVersionId)
+            .get();
+        assertEquals(expectedCoreException.code().id(), actualCoreException.code().id());
+        assertEquals(expectedCoreException.code().message(), actualCoreException.code().message());
+    }
+
+}
\ No newline at end of file
diff --git a/openecomp-be/api/openecomp-sdc-rest-webapp/vendor-software-products-rest/vendor-software-products-rest-types/src/main/java/org/openecomp/sdcrests/vendorsoftwareproducts/types/VspUploadStatusDto.java b/openecomp-be/api/openecomp-sdc-rest-webapp/vendor-software-products-rest/vendor-software-products-rest-types/src/main/java/org/openecomp/sdcrests/vendorsoftwareproducts/types/VspUploadStatusDto.java
new file mode 100644 (file)
index 0000000..7ff46e7
--- /dev/null
@@ -0,0 +1,44 @@
+/*
+ * -
+ *  ============LICENSE_START=======================================================
+ *  Copyright (C) 2022 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.sdcrests.vendorsoftwareproducts.types;
+
+import java.util.Date;
+import java.util.UUID;
+import lombok.Data;
+import org.openecomp.sdc.vendorsoftwareproduct.dao.type.VspUploadStatusRecord;
+import org.openecomp.sdc.vendorsoftwareproduct.dao.type.VspUploadStatus;
+
+/**
+ * DTO for class {@link VspUploadStatusRecord}
+ */
+@Data
+public class VspUploadStatusDto {
+
+    private String vspId;
+    private String vspVersionId;
+    private UUID lockId;
+    private boolean isComplete;
+    private VspUploadStatus status;
+    private Date created;
+    private Date updated;
+
+}
index 21ad7a6..9310042 100644 (file)
@@ -208,7 +208,7 @@ public enum Messages {
     UNEXPECTED_PROBLEM_HAPPENED_WHILE_GETTING("An unexpected problem happened while getting '%s'");
     // @formatter:on
 
-    private String errorMessage;
+    private final String errorMessage;
 
     /**
      * Formats the message with the given parameters.
diff --git a/openecomp-be/lib/openecomp-sdc-vendor-software-product-lib/openecomp-sdc-vendor-software-product-api/src/main/java/org/openecomp/sdc/vendorsoftwareproduct/dao/VspUploadStatusRecordAccessor.java b/openecomp-be/lib/openecomp-sdc-vendor-software-product-lib/openecomp-sdc-vendor-software-product-api/src/main/java/org/openecomp/sdc/vendorsoftwareproduct/dao/VspUploadStatusRecordAccessor.java
new file mode 100644 (file)
index 0000000..84ffde6
--- /dev/null
@@ -0,0 +1,44 @@
+/*
+ * -
+ *  ============LICENSE_START=======================================================
+ *  Copyright (C) 2022 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.vendorsoftwareproduct.dao;
+
+import com.datastax.driver.mapping.Result;
+import com.datastax.driver.mapping.annotations.Accessor;
+import com.datastax.driver.mapping.annotations.Query;
+import java.util.UUID;
+import org.openecomp.sdc.vendorsoftwareproduct.dao.type.VspUploadStatusRecord;
+
+/**
+ * Cassandra accessor for the {@link VspUploadStatusRecord}
+ */
+@Accessor
+public interface VspUploadStatusRecordAccessor {
+
+    @Query("SELECT * FROM vsp_upload_status WHERE vsp_id = ? AND vsp_version_id = ?")
+    Result<VspUploadStatusRecord> findAllByVspIdAndVspVersionId(final String vspId, final String vspVersionId);
+
+    @Query("SELECT * FROM vsp_upload_status WHERE vsp_id = ? AND vsp_version_id = ? AND is_complete = FALSE")
+    Result<VspUploadStatusRecord> findAllIncomplete(final String vspId, final String vspVersionId);
+
+    @Query("SELECT * FROM vsp_upload_status WHERE vsp_id = ? AND vsp_version_id = ? AND lock_id = ?")
+    Result<VspUploadStatusRecord> findByVspIdAndVersionIdAndLockId(final String vspId, final String vspVersionId, final UUID lockId);
+}
diff --git a/openecomp-be/lib/openecomp-sdc-vendor-software-product-lib/openecomp-sdc-vendor-software-product-api/src/main/java/org/openecomp/sdc/vendorsoftwareproduct/dao/VspUploadStatusRecordDao.java b/openecomp-be/lib/openecomp-sdc-vendor-software-product-lib/openecomp-sdc-vendor-software-product-api/src/main/java/org/openecomp/sdc/vendorsoftwareproduct/dao/VspUploadStatusRecordDao.java
new file mode 100644 (file)
index 0000000..3329eb1
--- /dev/null
@@ -0,0 +1,84 @@
+/*
+ * -
+ *  ============LICENSE_START=======================================================
+ *  Copyright (C) 2022 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.vendorsoftwareproduct.dao;
+
+import java.util.List;
+import java.util.Optional;
+import java.util.UUID;
+import org.openecomp.sdc.vendorsoftwareproduct.dao.type.VspUploadStatusRecord;
+
+/**
+ * Data Access Object for the package upload process status record.
+ */
+public interface VspUploadStatusRecordDao {
+
+    /**
+     * Creates an upload status record.
+     *
+     * @param vspUploadStatusRecord the upload status record to create
+     */
+    void create(final VspUploadStatusRecord vspUploadStatusRecord);
+
+    /**
+     * Updates an upload status record.
+     *
+     * @param vspUploadStatusRecord the upload status record to update
+     */
+    void update(final VspUploadStatusRecord vspUploadStatusRecord);
+
+    /**
+     * Finds all upload status record by Vendor Software Product id and its version id.
+     *
+     * @param vspId        the Vendor Software Product id
+     * @param vspVersionId the Vendor Software Product version id
+     * @return a list with all the status record found that matches the criteria
+     */
+    List<VspUploadStatusRecord> findAllByVspIdAndVersionId(final String vspId, final String vspVersionId);
+
+    /**
+     * Finds all upload status record by Vendor Software Product id and its version id.
+     *
+     * @param vspId        the Vendor Software Product id
+     * @param vspVersionId the Vendor Software Product version id
+     * @return a list with all the status record found that matches the criteria
+     */
+    Optional<VspUploadStatusRecord> findByVspIdAndVersionIdAndLockId(final String vspId, final String vspVersionId, final UUID lockId);
+
+    /**
+     * Finds all uploads in progress by Vendor Software Product id and its version id.
+     *
+     * @param vspId        the Vendor Software Product id
+     * @param vspVersionId the Vendor Software Product version id
+     * @return a list with all the status record found that matches the criteria
+     */
+    List<VspUploadStatusRecord> findAllInProgress(final String vspId, final String vspVersionId);
+
+    /**
+     * Finds the latest upload status record for the Vendor Software Product id and its version id.
+     *
+     * @param vspId        the Vendor Software Product id
+     * @param vspVersionId the Vendor Software Product version id
+     * @return the latest upload status record that matches the criteria
+     */
+    Optional<VspUploadStatusRecord> findLatest(final String vspId, final String vspVersionId);
+
+}
diff --git a/openecomp-be/lib/openecomp-sdc-vendor-software-product-lib/openecomp-sdc-vendor-software-product-api/src/main/java/org/openecomp/sdc/vendorsoftwareproduct/dao/type/VspUploadStatus.java b/openecomp-be/lib/openecomp-sdc-vendor-software-product-lib/openecomp-sdc-vendor-software-product-api/src/main/java/org/openecomp/sdc/vendorsoftwareproduct/dao/type/VspUploadStatus.java
new file mode 100644 (file)
index 0000000..f5d9de3
--- /dev/null
@@ -0,0 +1,42 @@
+/*
+ * -
+ *  ============LICENSE_START=======================================================
+ *  Copyright (C) 2022 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.vendorsoftwareproduct.dao.type;
+
+import java.util.List;
+
+/**
+ * Represents the status of a Vendor Software Product package upload.
+ */
+public enum VspUploadStatus {
+    UPLOADING,
+    PROCESSING,
+    SUCCESS,
+    ERROR;
+
+    public boolean isCompleteStatus() {
+        return getCompleteStatus().contains(this);
+    }
+
+    public static List<VspUploadStatus> getCompleteStatus() {
+        return List.of(SUCCESS, ERROR);
+    }
+}
diff --git a/openecomp-be/lib/openecomp-sdc-vendor-software-product-lib/openecomp-sdc-vendor-software-product-api/src/main/java/org/openecomp/sdc/vendorsoftwareproduct/dao/type/VspUploadStatusRecord.java b/openecomp-be/lib/openecomp-sdc-vendor-software-product-lib/openecomp-sdc-vendor-software-product-api/src/main/java/org/openecomp/sdc/vendorsoftwareproduct/dao/type/VspUploadStatusRecord.java
new file mode 100644 (file)
index 0000000..d0ce91c
--- /dev/null
@@ -0,0 +1,75 @@
+/*
+ * -
+ *  ============LICENSE_START=======================================================
+ *  Copyright (C) 2022 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.vendorsoftwareproduct.dao.type;
+
+import com.datastax.driver.mapping.annotations.ClusteringColumn;
+import com.datastax.driver.mapping.annotations.Column;
+import com.datastax.driver.mapping.annotations.PartitionKey;
+import com.datastax.driver.mapping.annotations.Table;
+import java.util.Date;
+import java.util.UUID;
+import lombok.AccessLevel;
+import lombok.Data;
+import lombok.Getter;
+import lombok.NoArgsConstructor;
+import lombok.Setter;
+
+@Data
+@NoArgsConstructor
+@Table(keyspace = "dox", name = "vsp_upload_status")
+public class VspUploadStatusRecord {
+
+    @PartitionKey
+    @Column(name = "vsp_id")
+    private String vspId;
+
+    @PartitionKey(value = 1)
+    @Column(name = "vsp_version_id")
+    private String vspVersionId;
+
+    @ClusteringColumn
+    @Column(name = "lock_id")
+    private UUID lockId;
+
+    @Column(name = "is_complete")
+    @Getter(AccessLevel.NONE)
+    @Setter(AccessLevel.NONE)
+    private boolean isComplete;
+
+    @Column(name = "status")
+    private VspUploadStatus status;
+
+    @ClusteringColumn(value = 1)
+    @Column(name = "created")
+    private Date created;
+
+    @Column(name = "updated")
+    private Date updated;
+
+    public boolean getIsComplete() {
+        return isComplete;
+    }
+
+    public void setIsComplete(boolean complete) {
+        isComplete = complete;
+    }
+}
\ No newline at end of file
diff --git a/openecomp-be/lib/openecomp-sdc-vendor-software-product-lib/openecomp-sdc-vendor-software-product-api/src/test/java/org/openecomp/sdc/vendorsoftwareproduct/dao/type/VspUploadStatusTest.java b/openecomp-be/lib/openecomp-sdc-vendor-software-product-lib/openecomp-sdc-vendor-software-product-api/src/test/java/org/openecomp/sdc/vendorsoftwareproduct/dao/type/VspUploadStatusTest.java
new file mode 100644 (file)
index 0000000..83618e7
--- /dev/null
@@ -0,0 +1,48 @@
+/*
+ * -
+ *  ============LICENSE_START=======================================================
+ *  Copyright (C) 2022 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.vendorsoftwareproduct.dao.type;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertFalse;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+
+import java.util.List;
+import org.junit.jupiter.api.Test;
+
+class VspUploadStatusTest {
+
+    @Test
+    void isCompleteStatus() {
+        assertTrue(VspUploadStatus.SUCCESS.isCompleteStatus());
+        assertTrue(VspUploadStatus.ERROR.isCompleteStatus());
+        assertFalse(VspUploadStatus.UPLOADING.isCompleteStatus());
+        assertFalse(VspUploadStatus.PROCESSING.isCompleteStatus());
+    }
+
+    @Test
+    void getCompleteStatusTest() {
+        final List<VspUploadStatus> completeStatus = VspUploadStatus.getCompleteStatus();
+        assertEquals(2, completeStatus.size());
+        assertTrue(completeStatus.contains(VspUploadStatus.SUCCESS));
+        assertTrue(completeStatus.contains(VspUploadStatus.ERROR));
+    }
+}
\ No newline at end of file
index 8cb2d72..5b0933d 100644 (file)
@@ -27,6 +27,7 @@ import org.openecomp.sdc.common.errors.ErrorCode;
 public class VendorSoftwareProductNotFoundErrorBuilder {
 
     private static final String VSP_FOUND_MSG = "Vendor software product with Id %s not found.";
+    private static final String VSP_ID_AND_VERSION_ID_NOT_FOUND_MSG = "Vendor Software Product with id '%s' and version id '%s' not found.";
     private final ErrorCode.ErrorCodeBuilder builder = new ErrorCode.ErrorCodeBuilder();
 
     /**
@@ -40,6 +41,12 @@ public class VendorSoftwareProductNotFoundErrorBuilder {
         builder.withMessage(String.format(VSP_FOUND_MSG, vendorSoftwareProductId));
     }
 
+    public VendorSoftwareProductNotFoundErrorBuilder(final String vendorSoftwareProductId, final String vendorSoftwareProductVersionId) {
+        builder.withId(VSP_NOT_FOUND);
+        builder.withCategory(ErrorCategory.APPLICATION);
+        builder.withMessage(String.format(VSP_ID_AND_VERSION_ID_NOT_FOUND_MSG, vendorSoftwareProductId, vendorSoftwareProductVersionId));
+    }
+
     public ErrorCode build() {
         return builder.build();
     }
diff --git a/openecomp-be/lib/openecomp-sdc-vendor-software-product-lib/openecomp-sdc-vendor-software-product-core/src/main/java/org/openecomp/sdc/vendorsoftwareproduct/dao/impl/VspUploadStatusRecordDaoIml.java b/openecomp-be/lib/openecomp-sdc-vendor-software-product-lib/openecomp-sdc-vendor-software-product-core/src/main/java/org/openecomp/sdc/vendorsoftwareproduct/dao/impl/VspUploadStatusRecordDaoIml.java
new file mode 100644 (file)
index 0000000..558016c
--- /dev/null
@@ -0,0 +1,97 @@
+/*
+ * -
+ *  ============LICENSE_START=======================================================
+ *  Copyright (C) 2022 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.vendorsoftwareproduct.dao.impl;
+
+import com.datastax.driver.extras.codecs.enums.EnumNameCodec;
+import com.datastax.driver.mapping.Mapper;
+import com.datastax.driver.mapping.MappingManager;
+import com.datastax.driver.mapping.Result;
+import java.util.Comparator;
+import java.util.List;
+import java.util.Optional;
+import java.util.UUID;
+import org.openecomp.core.nosqldb.factory.NoSqlDbFactory;
+import org.openecomp.sdc.vendorsoftwareproduct.dao.VspUploadStatusRecordAccessor;
+import org.openecomp.sdc.vendorsoftwareproduct.dao.VspUploadStatusRecordDao;
+import org.openecomp.sdc.vendorsoftwareproduct.dao.type.VspUploadStatusRecord;
+import org.openecomp.sdc.vendorsoftwareproduct.dao.type.VspUploadStatus;
+import org.springframework.stereotype.Component;
+
+/**
+ * Data access object for the package upload process status.
+ */
+@Component("vsp-upload-status-record-dao-impl")
+public class VspUploadStatusRecordDaoIml implements VspUploadStatusRecordDao {
+
+    private final Mapper<VspUploadStatusRecord> mapper;
+    private final VspUploadStatusRecordAccessor accessor;
+
+    public VspUploadStatusRecordDaoIml() {
+        final MappingManager mappingManager = NoSqlDbFactory.getInstance().createInterface().getMappingManager();
+        mapper = mappingManager.mapper(VspUploadStatusRecord.class);
+        accessor = mappingManager.createAccessor(VspUploadStatusRecordAccessor.class);
+        mappingManager.getSession().getCluster().getConfiguration().getCodecRegistry().register(new EnumNameCodec<>(VspUploadStatus.class));
+    }
+
+    //for tests purpose
+    VspUploadStatusRecordDaoIml(final VspUploadStatusRecordAccessor accessor) {
+        this.accessor = accessor;
+        mapper = null;
+    }
+
+    @Override
+    public void create(final VspUploadStatusRecord vspUploadStatusRecord) {
+        mapper.save(vspUploadStatusRecord);
+    }
+
+    @Override
+    public void update(final VspUploadStatusRecord vspUploadStatusRecord) {
+        mapper.save(vspUploadStatusRecord);
+    }
+
+    @Override
+    public List<VspUploadStatusRecord> findAllByVspIdAndVersionId(final String vspId, final String vspVersionId) {
+        final Result<VspUploadStatusRecord> allByVspIdAndVspVersionId = accessor.findAllByVspIdAndVspVersionId(vspId, vspVersionId);
+        return allByVspIdAndVspVersionId.all();
+    }
+
+    @Override
+    public Optional<VspUploadStatusRecord> findByVspIdAndVersionIdAndLockId(final String vspId, final String vspVersionId, final UUID lockId) {
+        final Result<VspUploadStatusRecord> vspUploadStatusRecordResult = accessor.findByVspIdAndVersionIdAndLockId(vspId, vspVersionId, lockId);
+        final VspUploadStatusRecord vspUploadStatusRecord = vspUploadStatusRecordResult.one();
+        return Optional.ofNullable(vspUploadStatusRecord);
+    }
+
+    @Override
+    public List<VspUploadStatusRecord> findAllInProgress(final String vspId, final String vspVersionId) {
+        final Result<VspUploadStatusRecord> incompleteUploadList = accessor.findAllIncomplete(vspId, vspVersionId);
+        return incompleteUploadList.all();
+    }
+
+    @Override
+    public Optional<VspUploadStatusRecord> findLatest(final String vspId, final String vspVersionId) {
+        final List<VspUploadStatusRecord> vspUploadStatusRecordList = accessor.findAllByVspIdAndVspVersionId(vspId, vspVersionId).all();
+        vspUploadStatusRecordList.sort(Comparator.comparing(VspUploadStatusRecord::getCreated).reversed());
+        return Optional.ofNullable(vspUploadStatusRecordList.get(0));
+    }
+
+}
index 13ade27..353dd2d 100644 (file)
@@ -77,6 +77,11 @@ public class VendorSoftwareProductErrorCodes {
     public static final String UPDATE_IMAGE_NOT_ALLOWED = "UPDATE_IMAGE_NOT_ALLOWED";
     public static final String INVALID_EXTENSION = "INVALID_EXTENSION";
     public static final String VSP_ONBOARD_METHOD_UPDATE_NOT_ALLOWED = "VSP_ONBOARD_METHOD_UPDATE_NOT_ALLOWED";
+    public static final String VSP_PROCESSING_IN_PROGRESS = "VSP_PROCESSING_IN_PROGRESS";
+    public static final String VSP_CREATE_UPLOAD_LOCK_ERROR = "VSP_CREATE_UPLOAD_LOCK_ERROR";
+    public static final String VSP_UPDATE_UPLOAD_LOCK_ERROR = "VSP_UPDATE_UPLOAD_LOCK_ERROR";
+    public static final String VSP_UPLOAD_LOCK_NOT_FOUND_ERROR = "VSP_UPLOAD_LOCK_NOT_FOUND_ERROR";
+    public static final String VSP_UPLOAD_ALREADY_FINISHED_ERROR = "VSP_UPLOAD_ALREADY_FINISHED_ERROR";
 
     private VendorSoftwareProductErrorCodes() {
     }
index 9268178..71b77b1 100644 (file)
  */
 package org.openecomp.sdc.vendorsoftwareproduct.dao.errors;
 
+import static org.junit.jupiter.api.Assertions.assertEquals;
 import static org.openecomp.sdc.vendorsoftwareproduct.errors.VendorSoftwareProductErrorCodes.VSP_NOT_FOUND;
 
-import org.junit.Assert;
-import org.junit.Test;
+import org.junit.jupiter.api.Test;
 import org.openecomp.sdc.common.errors.ErrorCategory;
 import org.openecomp.sdc.common.errors.ErrorCode;
 
-public class VendorSoftwareProductNotFoundErrorBuilderTest {
+class VendorSoftwareProductNotFoundErrorBuilderTest {
 
     @Test
-    public void shouldReturnVspNotFoundErrorCode() {
-        VendorSoftwareProductNotFoundErrorBuilder vendorSoftwareProductNotFoundErrorBuilder =
-                new VendorSoftwareProductNotFoundErrorBuilder("testVsp1");
+    void shouldReturnVspNotFoundErrorCode() {
+        final var vendorSoftwareProductNotFoundErrorBuilder = new VendorSoftwareProductNotFoundErrorBuilder("testVsp1");
         ErrorCode actual = vendorSoftwareProductNotFoundErrorBuilder.build();
-        Assert.assertEquals(ErrorCategory.APPLICATION, actual.category());
-        Assert.assertEquals(VSP_NOT_FOUND, actual.id());
+        assertEquals(ErrorCategory.APPLICATION, actual.category());
+        assertEquals(VSP_NOT_FOUND, actual.id());
+    }
+
+    @Test
+    void vspIdAndVspVersionIdConstructorTest() {
+        var vspId = "vspId";
+        var vspVersionId = "vspVersionId";
+        final var errorBuilder = new VendorSoftwareProductNotFoundErrorBuilder(vspId, vspVersionId);
+        final ErrorCode actualErrorCode = errorBuilder.build();
+        assertEquals(ErrorCategory.APPLICATION, actualErrorCode.category());
+        assertEquals(VSP_NOT_FOUND, actualErrorCode.id());
+        final String expectedMsg = String.format("Vendor Software Product with id '%s' and version id '%s' not found.", vspId, vspVersionId);
+        assertEquals(expectedMsg, actualErrorCode.message());
     }
 }
diff --git a/openecomp-be/lib/openecomp-sdc-vendor-software-product-lib/openecomp-sdc-vendor-software-product-core/src/test/java/org/openecomp/sdc/vendorsoftwareproduct/dao/impl/VspUploadStatusRecordDaoImlTest.java b/openecomp-be/lib/openecomp-sdc-vendor-software-product-lib/openecomp-sdc-vendor-software-product-core/src/test/java/org/openecomp/sdc/vendorsoftwareproduct/dao/impl/VspUploadStatusRecordDaoImlTest.java
new file mode 100644 (file)
index 0000000..cd0bc1c
--- /dev/null
@@ -0,0 +1,133 @@
+/*
+ * -
+ *  ============LICENSE_START=======================================================
+ *  Copyright (C) 2022 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.vendorsoftwareproduct.dao.impl;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+
+import com.datastax.driver.mapping.Result;
+import java.util.ArrayList;
+import java.util.Calendar;
+import java.util.List;
+import java.util.Optional;
+import java.util.UUID;
+import java.util.stream.IntStream;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+import org.openecomp.sdc.vendorsoftwareproduct.dao.VspUploadStatusRecordAccessor;
+import org.openecomp.sdc.vendorsoftwareproduct.dao.type.VspUploadStatusRecord;
+
+class VspUploadStatusRecordDaoImlTest {
+
+    @Mock
+    private VspUploadStatusRecordAccessor accessor;
+
+    private VspUploadStatusRecordDaoIml packageUploadManagerDaoIml;
+
+    @BeforeEach
+    void setUp() {
+        MockitoAnnotations.openMocks(this);
+        packageUploadManagerDaoIml = new VspUploadStatusRecordDaoIml(accessor);
+    }
+
+    @Test
+    void findAllByVspIdAndVersionIdSuccessTest() {
+        //given
+        final String vspId = "vspId";
+        final String vspVersionId = "vspVersionId";
+        final List<VspUploadStatusRecord> expectedVspUploadStatusRecordList = List.of(new VspUploadStatusRecord(), new VspUploadStatusRecord());
+        final Result<VspUploadStatusRecord> resultMock = mock(Result.class);
+        when(resultMock.all()).thenReturn(expectedVspUploadStatusRecordList);
+        when(accessor.findAllByVspIdAndVspVersionId(vspId, vspVersionId)).thenReturn(resultMock);
+        //when
+        final List<VspUploadStatusRecord> actualVspUploadStatusRecordList =
+            packageUploadManagerDaoIml.findAllByVspIdAndVersionId(vspId, vspVersionId);
+        //then
+        assertEquals(expectedVspUploadStatusRecordList, actualVspUploadStatusRecordList);
+    }
+
+    @Test
+    void findByVspIdAndVersionIdAndLockIdSuccessTest() {
+        //given
+        final String vspId = "vspId";
+        final String vspVersionId = "vspVersionId";
+        final UUID lockId = UUID.randomUUID();
+        final var expectedVspUploadStatus = new VspUploadStatusRecord();
+        final Result<VspUploadStatusRecord> resultMock = mock(Result.class);
+        when(resultMock.one()).thenReturn(expectedVspUploadStatus);
+        when(accessor.findByVspIdAndVersionIdAndLockId(vspId, vspVersionId, lockId)).thenReturn(resultMock);
+        //when
+        final Optional<VspUploadStatusRecord> vspUploadStatusOptional =
+            packageUploadManagerDaoIml.findByVspIdAndVersionIdAndLockId(vspId, vspVersionId, lockId);
+        //then
+        assertTrue(vspUploadStatusOptional.isPresent());
+        assertEquals(expectedVspUploadStatus, vspUploadStatusOptional.get());
+    }
+
+    @Test
+    void findAllNotCompleteSuccessTest() {
+        //given
+        final String vspId = "vspId";
+        final String vspVersionId = "vspVersionId";
+        final List<VspUploadStatusRecord> expectedVspUploadStatusRecordList = List.of(new VspUploadStatusRecord(), new VspUploadStatusRecord());
+        final Result<VspUploadStatusRecord> resultMock = mock(Result.class);
+        when(resultMock.all()).thenReturn(expectedVspUploadStatusRecordList);
+        when(accessor.findAllIncomplete(vspId, vspVersionId)).thenReturn(resultMock);
+        //when
+        final List<VspUploadStatusRecord> actualVspUploadStatusRecordList = packageUploadManagerDaoIml.findAllInProgress(vspId, vspVersionId);
+        //then
+        assertEquals(expectedVspUploadStatusRecordList, actualVspUploadStatusRecordList);
+    }
+
+    @Test
+    void findLatestSuccessTest() {
+        //given
+        final String vspId = "vspId";
+        final String vspVersionId = "vspVersionId";
+        final List<VspUploadStatusRecord> expectedVspUploadStatusRecordList = new ArrayList<>();
+        IntStream.rangeClosed(1, 31)
+            .mapToObj(day -> {
+                final VspUploadStatusRecord vspUploadStatusRecord = new VspUploadStatusRecord();
+                final Calendar calendar = Calendar.getInstance();
+                calendar.set(2022, Calendar.JANUARY, day);
+                vspUploadStatusRecord.setCreated(calendar.getTime());
+                return vspUploadStatusRecord;
+            })
+            .forEach(expectedVspUploadStatusRecordList::add);
+        final Result<VspUploadStatusRecord> resultMock = mock(Result.class);
+        when(resultMock.all()).thenReturn(expectedVspUploadStatusRecordList);
+
+        final VspUploadStatusRecord mostRecentVspUploadStatus = expectedVspUploadStatusRecordList.get(expectedVspUploadStatusRecordList.size() - 1);
+
+        when(accessor.findAllByVspIdAndVspVersionId(vspId, vspVersionId)).thenReturn(resultMock);
+        //when
+        final Optional<VspUploadStatusRecord> vspUploadStatusOptional = packageUploadManagerDaoIml.findLatest(vspId, vspVersionId);
+        //then
+        assertTrue(vspUploadStatusOptional.isPresent());
+        assertEquals(mostRecentVspUploadStatus, vspUploadStatusOptional.get());
+    }
+
+}
\ No newline at end of file
index 7e3bc0a..a5c9777 100644 (file)
@@ -44,6 +44,20 @@ CREATE TABLE IF NOT EXISTS NOTIFICATION_SUBSCRIBERS (entity_id text PRIMARY KEY,
 CREATE TABLE IF NOT EXISTS last_notification (owner_id text PRIMARY KEY, event_id timeuuid);
 CREATE TABLE IF NOT EXISTS notifications (owner_id text, event_id timeuuid, read boolean, originator_id text, event_type text, event_attributes text, PRIMARY KEY (owner_id, event_id)) WITH CLUSTERING ORDER BY (event_id DESC);
 CREATE TABLE IF NOT EXISTS vsp_merge_hint (space text, item_id text, version_id text, model_id text, model_resolution text, PRIMARY KEY ((space, item_id, version_id)));
+CREATE TABLE IF NOT EXISTS dox.vsp_upload_status
+(
+    vsp_id         text,
+    vsp_version_id text,
+    created        timestamp,
+    is_complete    boolean,
+    lock_id        uuid,
+    status         text,
+    updated        timestamp,
+    primary key ( (vsp_id, vsp_version_id), lock_id, created)
+) WITH CLUSTERING ORDER BY (lock_id ASC, created DESC);
+CREATE INDEX IF NOT EXISTS vsp_upload_status_is_complete_index on dox.vsp_upload_status (is_complete);
+CREATE INDEX IF NOT EXISTS vsp_upload_status_status_index on dox.vsp_upload_status (status);
+
 INSERT INTO application_config (namespace,key,value) VALUES ('vsp.schemaTemplates', 'composition.component', '{ "$schema": "http://json-schema.org/draft-04/schema#",  "type": "object",  "properties": {    "name": { "type": "string"<#if !manual>, "enum": [   "${component.name}" ], "default": "${component.name}"</#if>    },    "displayName": { "type": "string"<#if !manual && component.displayName??>, "enum": [   "${component.displayName}" ], "default": "${component.displayName}"</#if>},"description": {"type": "string"}},"additionalProperties": false,"required": ["name"<#if !manual && component.displayName??>,"displayName"</#if>]}');
 INSERT INTO application_config (namespace,key,value) VALUES ('vsp.schemaTemplates', 'composition.compute', '{ "$schema": "http://json-schema.org/draft-04/schema#", "type": "object", "properties": { "name": { "type": "string" <#if !manual>, "enum": [ "${compute.name}" ], "default": "${compute.name}"</#if> }, "description": { "type": "string", "maxLength": 300 } } }');
 INSERT INTO application_config (namespace,key,value) VALUES ('vsp.schemaTemplates', 'composition.deployment', '{ "$schema": "http://json-schema.org/draft-04/schema#", "type": "object", "properties": { "model": { "type": "string", "maxLength": 30 }, "description": { "type": "string", "maxLength": 300 }, "featureGroupId":{ "type": "string", "enum": [<#if featureGroupIds??> <#list featureGroupIds as featureGroupId> "${featureGroupId}"<#sep>,</#list> </#if> ] }, "componentComputeAssociations": { "type": "array", "properties": { "vfcid": { "type": "string" }, "computeFlavorid": { "type": "string" } }, "additionalProperties": false } }, "additionalProperties": false, "required": [ "model" ] }');