Create REST endpoint to retrieve models 56/122156/2
authorandre.schmid <andre.schmid@est.tech>
Mon, 21 Jun 2021 21:25:28 +0000 (22:25 +0100)
committerChristophe Closset <christophe.closset@intl.att.com>
Mon, 5 Jul 2021 09:21:57 +0000 (09:21 +0000)
Change-Id: Ifca0095d84d5da4ab4b055942d893e9c6a259eb7
Issue-ID: SDC-3622
Signed-off-by: André Schmid <andre.schmid@est.tech>
catalog-be/src/main/java/org/openecomp/sdc/be/components/impl/ModelBusinessLogic.java
catalog-be/src/main/java/org/openecomp/sdc/be/servlets/ModelServlet.java
catalog-be/src/test/java/org/openecomp/sdc/be/components/impl/ModelBusinessLogicTest.java
catalog-be/src/test/java/org/openecomp/sdc/be/servlets/ModelServletTest.java
catalog-model/src/main/java/org/openecomp/sdc/be/model/jsonjanusgraph/operations/exception/ModelOperationExceptionSupplier.java
catalog-model/src/main/java/org/openecomp/sdc/be/model/operations/impl/ModelOperation.java
catalog-model/src/test/java/org/openecomp/sdc/be/model/operations/impl/ModelOperationTest.java

index 7f68a00..a048af4 100644 (file)
@@ -21,6 +21,7 @@ package org.openecomp.sdc.be.components.impl;
 import java.io.ByteArrayOutputStream;
 import java.io.IOException;
 import java.io.InputStream;
+import java.util.List;
 import java.util.Map;
 import java.util.Optional;
 import org.apache.commons.lang3.StringUtils;
@@ -56,6 +57,15 @@ public class ModelBusinessLogic {
         return modelOperation.findModelByName(modelName);
     }
 
+    /**
+     * Loads the list of models.
+     *
+     * @return the list of models
+     */
+    public List<Model> listModels() {
+        return modelOperation.findAllModels();
+    }
+
     public void createModelImports(final String modelName, final InputStream modelImportsZip) {
         if (StringUtils.isEmpty(modelName)) {
             throw ModelOperationExceptionSupplier.invalidModel(modelName).get();
index 0c5e4ae..337c641 100644 (file)
@@ -30,10 +30,12 @@ import io.swagger.v3.oas.annotations.servers.Server;
 import io.swagger.v3.oas.annotations.tags.Tag;
 import java.io.InputStream;
 import java.util.Arrays;
+import java.util.List;
 import javax.inject.Inject;
 import javax.validation.Valid;
 import javax.validation.constraints.NotNull;
 import javax.ws.rs.Consumes;
+import javax.ws.rs.GET;
 import javax.ws.rs.HeaderParam;
 import javax.ws.rs.POST;
 import javax.ws.rs.PUT;
@@ -121,6 +123,32 @@ public class ModelServlet extends AbstractValidationsServlet {
         }
     }
 
+    @GET
+    @Path("/model")
+    @Produces(MediaType.APPLICATION_JSON)
+    @PermissionAllowed(AafPermission.PermNames.INTERNAL_ALL_VALUE)
+    @Operation(method = "GET", summary = "List TOSCA models", description = "List all the existing TOSCA models",
+        responses = {
+            @ApiResponse(content = @Content(array = @ArraySchema(schema = @Schema(implementation = Model.class)))),
+            @ApiResponse(responseCode = "200", description = "Listing successful"),
+            @ApiResponse(responseCode = "403", description = "Restricted operation")
+        }
+    )
+    public Response listModels(@HeaderParam(value = Constants.USER_ID_HEADER) final String userId) {
+        validateUser(ValidationUtils.sanitizeInputString(userId));
+        try {
+            final List<Model> modelList = modelBusinessLogic.listModels();
+            return buildOkResponse(getComponentsUtils().getResponseFormat(ActionStatus.OK), RepresentationUtils.toRepresentation(modelList));
+        } catch (final BusinessException e) {
+            throw e;
+        } catch (final Exception e) {
+            var errorMsg = "Unexpected error while listing the models";
+            BeEcompErrorManager.getInstance().logBeRestApiGeneralError(errorMsg);
+            log.error(errorMsg, e);
+            return buildErrorResponse(getComponentsUtils().getResponseFormat(ActionStatus.GENERAL_ERROR));
+        }
+    }
+
     @PUT
     @Path("/model/imports")
     @Consumes(MediaType.MULTIPART_FORM_DATA)
index b88bdfb..ef334f5 100644 (file)
@@ -33,6 +33,8 @@ import java.io.ByteArrayInputStream;
 import java.io.IOException;
 import java.nio.file.Files;
 import java.nio.file.Path;
+import java.util.Collections;
+import java.util.List;
 import java.util.Map;
 import java.util.Optional;
 import org.junit.jupiter.api.BeforeEach;
@@ -190,4 +192,19 @@ class ModelBusinessLogicTest {
         actualModel = modelBusinessLogic.findModel(null);
         assertTrue(actualModel.isEmpty());
     }
+
+    @Test
+    void listModelsSuccessTest() {
+        final List<Model> expectedModelList = List.of(new Model());
+        when(modelOperation.findAllModels()).thenReturn(expectedModelList);
+        final List<Model> actualModelList = modelBusinessLogic.listModels();
+        assertEquals(expectedModelList, actualModelList, "The model list should be as expected");
+    }
+
+    @Test
+    void listModelsTest_emptyList() {
+        when(modelOperation.findAllModels()).thenReturn(Collections.emptyList());
+        final List<Model> actualModelList = modelBusinessLogic.listModels();
+        assertTrue(actualModelList.isEmpty(), "The model list should be empty");
+    }
 }
\ No newline at end of file
index 5992be4..12f803f 100644 (file)
@@ -26,12 +26,15 @@ import static org.mockito.Mockito.when;
 
 import com.fasterxml.jackson.core.JsonProcessingException;
 import com.fasterxml.jackson.databind.ObjectMapper;
+import java.io.IOException;
 import java.io.InputStream;
 import java.nio.file.Path;
+import java.util.List;
 import javax.servlet.ServletContext;
 import javax.servlet.http.HttpServletRequest;
 import javax.servlet.http.HttpSession;
 import javax.ws.rs.client.Entity;
+import javax.ws.rs.core.HttpHeaders;
 import javax.ws.rs.core.MediaType;
 import javax.ws.rs.core.Response.Status;
 import org.apache.commons.lang3.StringUtils;
@@ -44,11 +47,8 @@ import org.glassfish.jersey.server.ResourceConfig;
 import org.glassfish.jersey.test.JerseyTest;
 import org.glassfish.jersey.test.TestProperties;
 import org.junit.jupiter.api.AfterEach;
-import org.junit.jupiter.api.BeforeAll;
 import org.junit.jupiter.api.BeforeEach;
 import org.junit.jupiter.api.Test;
-import org.junit.jupiter.api.TestInstance;
-import org.junit.jupiter.api.TestInstance.Lifecycle;
 import org.mockito.InjectMocks;
 import org.mockito.Mock;
 import org.mockito.MockitoAnnotations;
@@ -79,7 +79,6 @@ import org.springframework.context.ApplicationContext;
 import org.springframework.context.annotation.AnnotationConfigApplicationContext;
 import org.springframework.web.context.WebApplicationContext;
 
-@TestInstance(Lifecycle.PER_CLASS)
 class ModelServletTest extends JerseyTest {
 
     private static final String USER_ID = "cs0008";
@@ -121,8 +120,20 @@ class ModelServletTest extends JerseyTest {
     private final Path rootPath = Path.of("/v1/catalog/model");
     private final Path importsPath = rootPath.resolve("imports");
 
-    @BeforeAll
-    public void initClass() {
+    @BeforeEach
+    void resetMock() throws Exception {
+        super.setUp();
+        initMocks();
+        initConfig();
+        initTestData();
+    }
+
+    @AfterEach
+    void after() throws Exception {
+        super.tearDown();
+    }
+
+    private void initMocks() {
         when(request.getSession()).thenReturn(session);
         when(session.getServletContext()).thenReturn(servletContext);
         when(servletContext.getAttribute(Constants.WEB_APPLICATION_CONTEXT_WRAPPER_ATTR))
@@ -132,6 +143,9 @@ class ModelServletTest extends JerseyTest {
         when(request.getHeader(Constants.USER_ID_HEADER)).thenReturn(USER_ID);
         when(webApplicationContext.getBean(ServletUtils.class)).thenReturn(servletUtils);
         when(servletUtils.getComponentsUtils()).thenReturn(componentsUtils);
+    }
+
+    private void initConfig() {
         final String appConfigDir = "src/test/resources/config/catalog-be";
         final ConfigurationSource configurationSource = new FSConfigurationSource(ExternalConfiguration.getChangeListener(), appConfigDir);
         final ConfigurationManager configurationManager = new ConfigurationManager(configurationSource);
@@ -141,17 +155,6 @@ class ModelServletTest extends JerseyTest {
         ExternalConfiguration.setAppName("catalog-be");
     }
 
-    @BeforeEach
-    void resetMock() throws Exception {
-        super.setUp();
-        initTestData();
-    }
-
-    @AfterEach
-    void after() throws Exception {
-        super.tearDown();
-    }
-
     private void initTestData() {
         final String modelName = "MY-INTEGRATION-TEST-MODEL";
         model = new Model(modelName);
@@ -287,6 +290,40 @@ class ModelServletTest extends JerseyTest {
         assertEquals(Status.INTERNAL_SERVER_ERROR.getStatusCode(), response.getStatus());
     }
 
+    @Test
+    void listModelSuccessTest() throws IOException {
+        var model1 = new Model("model1");
+        var model2 = new Model("model2");
+        var model3 = new Model("model3");
+        final List<Model> modelList = List.of(model1, model2, model3);
+        when(responseFormat.getStatus()).thenReturn(HttpStatus.OK_200);
+        when(componentsUtils.getResponseFormat(ActionStatus.OK)).thenReturn(responseFormat);
+        when(modelBusinessLogic.listModels()).thenReturn(modelList);
+
+        final var response = target(rootPath.toString()).request(MediaType.APPLICATION_JSON)
+            .header(Constants.USER_ID_HEADER, USER_ID)
+            .get();
+
+        assertEquals(Status.OK.getStatusCode(), response.getStatus());
+        assertEquals(MediaType.APPLICATION_JSON, response.getHeaderString(HttpHeaders.CONTENT_TYPE));
+        final String responseBody = response.readEntity(String.class);
+        final String toRepresentation = (String) RepresentationUtils.toRepresentation(modelList);
+        assertEquals(toRepresentation, responseBody);
+    }
+
+    @Test
+    void listModelErrorTest() {
+        when(responseFormat.getStatus()).thenReturn(HttpStatus.INTERNAL_SERVER_ERROR_500);
+        when(componentsUtils.getResponseFormat(ActionStatus.GENERAL_ERROR)).thenReturn(responseFormat);
+        doThrow(new RuntimeException()).when(modelBusinessLogic).listModels();
+
+        final var response = target(rootPath.toString()).request(MediaType.APPLICATION_JSON)
+            .header(Constants.USER_ID_HEADER, USER_ID)
+            .get();
+
+        assertEquals(Status.INTERNAL_SERVER_ERROR.getStatusCode(), response.getStatus());
+    }
+
     private FormDataMultiPart buildUpdateFormDataMultiPart(final String modelName, final byte[] importFilesZip) {
         return new FormDataMultiPart()
             .field("modelName", modelName)
index c2ad071..6622bf5 100644 (file)
@@ -21,6 +21,7 @@ package org.openecomp.sdc.be.model.jsonjanusgraph.operations.exception;
 
 import java.util.function.Supplier;
 import org.openecomp.sdc.be.dao.api.ActionStatus;
+import org.openecomp.sdc.be.dao.janusgraph.JanusGraphOperationStatus;
 
 /**
  * Supplies operation exception needed by the the Model logic
@@ -47,4 +48,9 @@ public class ModelOperationExceptionSupplier {
         return () -> new OperationException(ActionStatus.MODEL_ALREADY_EXISTS, modelName);
     }
 
+    public static Supplier<OperationException> failedToRetrieveModels(final JanusGraphOperationStatus janusGraphOperationStatus) {
+        var errorMsg = String.format("Failed to retrieve models. Status '%s'", janusGraphOperationStatus);
+        return () -> new OperationException(ActionStatus.GENERAL_ERROR, errorMsg);
+    }
+
 }
index ccc18e5..ddc0367 100644 (file)
@@ -20,6 +20,7 @@ package org.openecomp.sdc.be.model.operations.impl;
 
 import fj.data.Either;
 import java.nio.charset.StandardCharsets;
+import java.util.Collections;
 import java.util.EnumMap;
 import java.util.List;
 import java.util.Map;
@@ -99,18 +100,11 @@ public class ModelOperation {
         final Map<GraphPropertyEnum, Object> props = new EnumMap<>(GraphPropertyEnum.class);
         props.put(GraphPropertyEnum.NAME, name);
         props.put(GraphPropertyEnum.UNIQUE_ID, UniqueIdBuilder.buildModelUid(name));
-        final Either<List<GraphVertex>, JanusGraphOperationStatus> result = janusGraphDao.getByCriteria(VertexTypeEnum.MODEL, props);
-        if (result.isRight()) {
-            final JanusGraphOperationStatus janusGraphOperationStatus = result.right().value();
-            if (janusGraphOperationStatus == JanusGraphOperationStatus.NOT_FOUND) {
-                return Optional.empty();
-            }
-            log.error(EcompLoggerErrorCode.DATA_ERROR, this.getClass().getName(),
-                String.format("Problem while getting model %s. reason %s", name, janusGraphOperationStatus));
-            throw new OperationException(ActionStatus.GENERAL_ERROR,
-                String.format("Failed to get model %s on JanusGraph with %s error", name, janusGraphOperationStatus));
+        final List<GraphVertex> modelVerticesList = findModelVerticesByCriteria(props);
+        if (modelVerticesList.isEmpty()) {
+            return Optional.empty();
         }
-        return Optional.ofNullable(result.left().value().get(0));
+        return Optional.ofNullable(modelVerticesList.get(0));
     }
 
     public Optional<Model> findModelByName(final String name) {
@@ -123,8 +117,7 @@ public class ModelOperation {
         }
 
         final GraphVertex graphVertex = modelVertexOpt.get();
-        final var model = new Model((String) graphVertex.getMetadataProperty(GraphPropertyEnum.NAME));
-        return Optional.of(model);
+        return Optional.of(convertToModel(graphVertex));
     }
 
     public void createModelImports(final String modelId, final Map<String, byte[]> zipContent) {
@@ -144,6 +137,42 @@ public class ModelOperation {
             }).collect(Collectors.toList());
         toscaModelImportCassandraDao.importAll(modelId, toscaImportByModelList);
     }
+
+    /**
+     * Finds all the models.
+     *
+     * @return the list of models
+     */
+    public List<Model> findAllModels() {
+        return findModelsByCriteria(Collections.emptyMap());
+    }
+
+    private List<Model> findModelsByCriteria(final Map<GraphPropertyEnum, Object> propertyCriteria) {
+        final List<GraphVertex> modelVerticesByCriteria = findModelVerticesByCriteria(propertyCriteria);
+        if (modelVerticesByCriteria.isEmpty()) {
+            return Collections.emptyList();
+        }
+
+        return modelVerticesByCriteria.stream().map(this::convertToModel).collect(Collectors.toList());
+    }
+
+    private List<GraphVertex> findModelVerticesByCriteria(final Map<GraphPropertyEnum, Object> propertyCriteria) {
+        final Either<List<GraphVertex>, JanusGraphOperationStatus> result = janusGraphDao.getByCriteria(VertexTypeEnum.MODEL, propertyCriteria);
+        if (result.isRight()) {
+            final var janusGraphOperationStatus = result.right().value();
+            if (janusGraphOperationStatus == JanusGraphOperationStatus.NOT_FOUND) {
+                return Collections.emptyList();
+            }
+            final var operationException = ModelOperationExceptionSupplier.failedToRetrieveModels(janusGraphOperationStatus).get();
+            log.error(EcompLoggerErrorCode.DATA_ERROR, this.getClass().getName(), operationException.getMessage());
+            throw operationException;
+        }
+        return result.left().value();
+    }
+
+    private Model convertToModel(final GraphVertex modelGraphVertex) {
+        return new Model((String) modelGraphVertex.getMetadataProperty(GraphPropertyEnum.NAME));
+    }
 }
 
 
index 620c7f7..c48a152 100644 (file)
@@ -20,6 +20,7 @@ package org.openecomp.sdc.be.model.operations.impl;
 
 import static org.assertj.core.api.Assertions.assertThat;
 import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertFalse;
 import static org.junit.jupiter.api.Assertions.assertThrows;
 import static org.junit.jupiter.api.Assertions.assertTrue;
 import static org.mockito.ArgumentMatchers.any;
@@ -55,6 +56,7 @@ import org.openecomp.sdc.be.data.model.ToscaImportByModel;
 import org.openecomp.sdc.be.datatypes.enums.GraphPropertyEnum;
 import org.openecomp.sdc.be.model.Model;
 import org.openecomp.sdc.be.model.ModelTestBase;
+import org.openecomp.sdc.be.model.jsonjanusgraph.operations.exception.ModelOperationExceptionSupplier;
 import org.openecomp.sdc.be.model.jsonjanusgraph.operations.exception.OperationException;
 import org.openecomp.sdc.be.resources.data.ModelData;
 import org.springframework.test.context.ContextConfiguration;
@@ -225,4 +227,38 @@ class ModelOperationTest extends ModelTestBase {
         assertTrue(modelOperation.findModelByName(null).isEmpty());
     }
 
+    @Test
+    void findAllModelsSuccessTest() {
+        final GraphVertex expectedVertex = mock(GraphVertex.class);
+        when(expectedVertex.getMetadataProperty(GraphPropertyEnum.NAME)).thenReturn(modelName);
+        when(janusGraphDao.getByCriteria(VertexTypeEnum.MODEL, Collections.emptyMap())).thenReturn(Either.left(List.of(expectedVertex)));
+        final List<Model> actualModelList = modelOperation.findAllModels();
+        assertFalse(actualModelList.isEmpty());
+        assertEquals(1, actualModelList.size());
+        assertEquals(modelName, actualModelList.get(0).getName());
+    }
+
+    @Test
+    void findAllModelsTest_noModelsFound() {
+        when(janusGraphDao.getByCriteria(VertexTypeEnum.MODEL, Collections.emptyMap())).thenReturn(Either.left(Collections.emptyList()));
+        final List<Model> actualModelList = modelOperation.findAllModels();
+        assertTrue(actualModelList.isEmpty());
+    }
+
+    @Test
+    void findAllModelsTest_janusGraphNotFound() {
+        when(janusGraphDao.getByCriteria(VertexTypeEnum.MODEL, Collections.emptyMap()))
+            .thenReturn(Either.right(JanusGraphOperationStatus.NOT_FOUND));
+        final List<Model> actualModelList = modelOperation.findAllModels();
+        assertTrue(actualModelList.isEmpty());
+    }
+
+    @Test
+    void findAllModelsTest_janusGraphError() {
+        when(janusGraphDao.getByCriteria(VertexTypeEnum.MODEL, Collections.emptyMap()))
+            .thenReturn(Either.right(JanusGraphOperationStatus.GENERAL_ERROR));
+        final var actualException = assertThrows(OperationException.class, () -> modelOperation.findAllModels());
+        final var expectedException = ModelOperationExceptionSupplier.failedToRetrieveModels(JanusGraphOperationStatus.GENERAL_ERROR).get();
+        assertEquals(expectedException.getMessage(), actualException.getMessage());
+    }
 }