aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAvi Gaffa <avi.gaffa@amdocs.com>2018-07-18 11:35:02 +0000
committerGerrit Code Review <gerrit@onap.org>2018-07-18 11:35:02 +0000
commit65aace9081f4fafde2554704ead8d0ce0c285d5e (patch)
treee4fadf7d3da8ba9b6dc325b2107b1339965d06c0
parentcf576292b7c646854da61a383748bb839dfda233 (diff)
parent90c62fa8ff77bdea92d817a54b17c65820db6f21 (diff)
Merge "Pagination of workflow list API"
-rw-r--r--workflow/workflow-designer-be/src/main/java/org/onap/sdc/workflow/api/RestConstants.java6
-rw-r--r--workflow/workflow-designer-be/src/main/java/org/onap/sdc/workflow/api/WorkflowController.java37
-rw-r--r--workflow/workflow-designer-be/src/main/java/org/onap/sdc/workflow/api/exceptionshandlers/CustomizedResponseEntityExceptionHandler.java20
-rw-r--r--workflow/workflow-designer-be/src/main/java/org/onap/sdc/workflow/api/types/CollectionWrapper.java12
-rw-r--r--workflow/workflow-designer-be/src/main/java/org/onap/sdc/workflow/services/WorkflowManager.java3
-rw-r--r--workflow/workflow-designer-be/src/main/java/org/onap/sdc/workflow/services/WorkflowNameComparator.java16
-rw-r--r--workflow/workflow-designer-be/src/main/java/org/onap/sdc/workflow/services/exceptions/InvalidPaginationParameterException.java8
-rw-r--r--workflow/workflow-designer-be/src/main/java/org/onap/sdc/workflow/services/impl/WorkflowManagerImpl.java52
-rw-r--r--workflow/workflow-designer-be/src/test/java/org/onap/sdc/workflow/RestPath.java36
-rw-r--r--workflow/workflow-designer-be/src/test/java/org/onap/sdc/workflow/api/WorkflowControllerTest.java154
-rw-r--r--workflow/workflow-designer-be/src/test/java/org/onap/sdc/workflow/services/impl/WorkflowManagerImplTest.java100
11 files changed, 431 insertions, 13 deletions
diff --git a/workflow/workflow-designer-be/src/main/java/org/onap/sdc/workflow/api/RestConstants.java b/workflow/workflow-designer-be/src/main/java/org/onap/sdc/workflow/api/RestConstants.java
index 8f02be0f..47a757e2 100644
--- a/workflow/workflow-designer-be/src/main/java/org/onap/sdc/workflow/api/RestConstants.java
+++ b/workflow/workflow-designer-be/src/main/java/org/onap/sdc/workflow/api/RestConstants.java
@@ -6,4 +6,10 @@ public class RestConstants {
}
public static final String USER_ID_HEADER_PARAM = "USER_ID";
+ public static final String LIMIT_PARAM = "size";
+ public static final String OFFSET_PARAM = "page";
+ public static final String SORT_PARAM = "sort";
+ public static final String SORT_FIELD_NAME = "name";
+ public static final int LIMIT_DEFAULT = 20;
+ public static final int OFFSET_DEFAULT = 0;
}
diff --git a/workflow/workflow-designer-be/src/main/java/org/onap/sdc/workflow/api/WorkflowController.java b/workflow/workflow-designer-be/src/main/java/org/onap/sdc/workflow/api/WorkflowController.java
index b224e84b..de35320d 100644
--- a/workflow/workflow-designer-be/src/main/java/org/onap/sdc/workflow/api/WorkflowController.java
+++ b/workflow/workflow-designer-be/src/main/java/org/onap/sdc/workflow/api/WorkflowController.java
@@ -1,14 +1,28 @@
package org.onap.sdc.workflow.api;
+import static org.onap.sdc.workflow.api.RestConstants.LIMIT_DEFAULT;
+import static org.onap.sdc.workflow.api.RestConstants.SORT_FIELD_NAME;
+import static org.onap.sdc.workflow.api.RestConstants.SORT_PARAM;
import static org.onap.sdc.workflow.api.RestConstants.USER_ID_HEADER_PARAM;
+import com.google.common.collect.ImmutableSet;
+
+import java.util.Arrays;
+import java.util.Set;
+
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import org.onap.sdc.workflow.api.types.CollectionWrapper;
import org.onap.sdc.workflow.persistence.types.Workflow;
import org.onap.sdc.workflow.services.WorkflowManager;
+import org.onap.sdc.workflow.services.exceptions.InvalidPaginationParameterException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
+import org.springframework.data.domain.PageRequest;
+import org.springframework.data.domain.Pageable;
+import org.springframework.data.domain.Sort;
+import org.springframework.data.web.PageableDefault;
+import org.springframework.data.web.SortDefault;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
@@ -35,8 +49,14 @@ public class WorkflowController {
@GetMapping(produces = MediaType.APPLICATION_JSON_VALUE)
@ApiOperation("List workflows")
- public CollectionWrapper<Workflow> list(@RequestHeader(USER_ID_HEADER_PARAM) String user) {
- return new CollectionWrapper<>(workflowManager.list());
+ public CollectionWrapper<Workflow> list(@RequestHeader(USER_ID_HEADER_PARAM) String user,
+ @PageableDefault(size = LIMIT_DEFAULT)
+ @SortDefault.SortDefaults({
+ @SortDefault(sort = SORT_FIELD_NAME, direction = Sort.Direction.ASC)
+ }) Pageable pageable) {
+ PageRequest pageRequest = createPageRequest(pageable);
+ return new CollectionWrapper<>(pageRequest.getPageSize(), pageRequest.getPageNumber(),
+ workflowManager.list(pageRequest));
}
@PostMapping(consumes = MediaType.APPLICATION_JSON_VALUE)
@@ -63,4 +83,17 @@ public class WorkflowController {
workflowManager.update(workflow);
return workflow;
}
+
+ private PageRequest createPageRequest(Pageable pageable) {
+ Set<String> validSortFields = ImmutableSet.of(SORT_FIELD_NAME);
+ Sort sort = pageable.getSort();
+ for (Sort.Order order : sort) {
+ String sortFieldName = order.getProperty();
+ if (!sortFieldName.equalsIgnoreCase(SORT_FIELD_NAME)) {
+ throw new InvalidPaginationParameterException(SORT_PARAM, sortFieldName,
+ "is not supported. Supported values are: " + Arrays.toString(validSortFields.toArray()));
+ }
+ }
+ return PageRequest.of(pageable.getPageNumber(), pageable.getPageSize(), sort);
+ }
}
diff --git a/workflow/workflow-designer-be/src/main/java/org/onap/sdc/workflow/api/exceptionshandlers/CustomizedResponseEntityExceptionHandler.java b/workflow/workflow-designer-be/src/main/java/org/onap/sdc/workflow/api/exceptionshandlers/CustomizedResponseEntityExceptionHandler.java
index 68fd41a5..bcc28d6d 100644
--- a/workflow/workflow-designer-be/src/main/java/org/onap/sdc/workflow/api/exceptionshandlers/CustomizedResponseEntityExceptionHandler.java
+++ b/workflow/workflow-designer-be/src/main/java/org/onap/sdc/workflow/api/exceptionshandlers/CustomizedResponseEntityExceptionHandler.java
@@ -1,19 +1,25 @@
package org.onap.sdc.workflow.api.exceptionshandlers;
+import static org.springframework.http.HttpStatus.BAD_REQUEST;
import static org.springframework.http.HttpStatus.FORBIDDEN;
import static org.springframework.http.HttpStatus.NOT_FOUND;
import static org.springframework.http.HttpStatus.UNPROCESSABLE_ENTITY;
import org.onap.sdc.workflow.services.exceptions.EntityNotFoundException;
import org.onap.sdc.workflow.services.exceptions.InvalidArtifactException;
+import org.onap.sdc.workflow.services.exceptions.InvalidPaginationParameterException;
import org.onap.sdc.workflow.services.exceptions.UniqueValueViolationException;
import org.onap.sdc.workflow.services.exceptions.VersionCreationException;
import org.onap.sdc.workflow.services.exceptions.VersionModificationException;
import org.onap.sdc.workflow.services.exceptions.VersionStateModificationException;
+import org.springframework.http.HttpHeaders;
+import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
+import org.springframework.web.bind.ServletRequestBindingException;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestController;
+import org.springframework.web.context.request.WebRequest;
import org.springframework.web.servlet.mvc.method.annotation.ResponseEntityExceptionHandler;
@ControllerAdvice
@@ -32,6 +38,20 @@ public class CustomizedResponseEntityExceptionHandler extends ResponseEntityExce
return new ResponseEntity<>(exception.getMessage(), NOT_FOUND);
}
+ @ExceptionHandler({InvalidPaginationParameterException.class})
+ public final ResponseEntity<String> handlePaginationException(InvalidPaginationParameterException exception) {
+ return new ResponseEntity<>(exception.getMessage(), BAD_REQUEST);
+ }
+
+ //For missing header exceptions
+ @Override
+ public ResponseEntity<Object> handleServletRequestBindingException(ServletRequestBindingException ex,
+ HttpHeaders headers, HttpStatus status,
+ WebRequest request) {
+ return new ResponseEntity<>(ex.getMessage(), BAD_REQUEST);
+ }
+
+
@ExceptionHandler({InvalidArtifactException.class, VersionModificationException.class,
VersionStateModificationException.class})
public final ResponseEntity<String> handleInvalidArtifactException(
diff --git a/workflow/workflow-designer-be/src/main/java/org/onap/sdc/workflow/api/types/CollectionWrapper.java b/workflow/workflow-designer-be/src/main/java/org/onap/sdc/workflow/api/types/CollectionWrapper.java
index 653b0dcf..1d583dd9 100644
--- a/workflow/workflow-designer-be/src/main/java/org/onap/sdc/workflow/api/types/CollectionWrapper.java
+++ b/workflow/workflow-designer-be/src/main/java/org/onap/sdc/workflow/api/types/CollectionWrapper.java
@@ -11,6 +11,18 @@ public class CollectionWrapper<T> {
private int offset;
private Collection<T> results;
+
+ public CollectionWrapper() {
+ //Default constructor for object mappers
+ }
+
+ public CollectionWrapper(int limit, int offset, Collection<T> results) {
+ this.results = results;
+ this.limit = limit;
+ this.offset = offset;
+ this.total = results.size();
+ }
+
public CollectionWrapper(Collection<T> results) {
this.results = results;
this.total = results.size();
diff --git a/workflow/workflow-designer-be/src/main/java/org/onap/sdc/workflow/services/WorkflowManager.java b/workflow/workflow-designer-be/src/main/java/org/onap/sdc/workflow/services/WorkflowManager.java
index 01c0b053..e2572b78 100644
--- a/workflow/workflow-designer-be/src/main/java/org/onap/sdc/workflow/services/WorkflowManager.java
+++ b/workflow/workflow-designer-be/src/main/java/org/onap/sdc/workflow/services/WorkflowManager.java
@@ -2,10 +2,11 @@ package org.onap.sdc.workflow.services;
import java.util.Collection;
import org.onap.sdc.workflow.persistence.types.Workflow;
+import org.springframework.data.domain.Pageable;
public interface WorkflowManager {
- Collection<Workflow> list();
+ Collection<Workflow> list(Pageable pageable);
Workflow get(Workflow workflow);
diff --git a/workflow/workflow-designer-be/src/main/java/org/onap/sdc/workflow/services/WorkflowNameComparator.java b/workflow/workflow-designer-be/src/main/java/org/onap/sdc/workflow/services/WorkflowNameComparator.java
new file mode 100644
index 00000000..1ba4dcda
--- /dev/null
+++ b/workflow/workflow-designer-be/src/main/java/org/onap/sdc/workflow/services/WorkflowNameComparator.java
@@ -0,0 +1,16 @@
+package org.onap.sdc.workflow.services;
+
+import java.util.Comparator;
+
+import org.onap.sdc.workflow.persistence.types.Workflow;
+
+public class WorkflowNameComparator implements Comparator<Workflow>{
+
+ @Override
+ public int compare(Workflow workflow1, Workflow workflow2) {
+ String workflowName1 = workflow1.getName().toLowerCase();
+ String workflowName2 = workflow2.getName().toLowerCase();
+ //ascending order
+ return workflowName1.compareTo(workflowName2);
+ }
+}
diff --git a/workflow/workflow-designer-be/src/main/java/org/onap/sdc/workflow/services/exceptions/InvalidPaginationParameterException.java b/workflow/workflow-designer-be/src/main/java/org/onap/sdc/workflow/services/exceptions/InvalidPaginationParameterException.java
new file mode 100644
index 00000000..fde8fd97
--- /dev/null
+++ b/workflow/workflow-designer-be/src/main/java/org/onap/sdc/workflow/services/exceptions/InvalidPaginationParameterException.java
@@ -0,0 +1,8 @@
+package org.onap.sdc.workflow.services.exceptions;
+
+public class InvalidPaginationParameterException extends RuntimeException {
+
+ public InvalidPaginationParameterException(String parameterName, String parameterValue, String message) {
+ super(String.format("Requested %s: %s %s", parameterName, parameterValue, message));
+ }
+} \ No newline at end of file
diff --git a/workflow/workflow-designer-be/src/main/java/org/onap/sdc/workflow/services/impl/WorkflowManagerImpl.java b/workflow/workflow-designer-be/src/main/java/org/onap/sdc/workflow/services/impl/WorkflowManagerImpl.java
index 8ac5025a..2cb897fe 100644
--- a/workflow/workflow-designer-be/src/main/java/org/onap/sdc/workflow/services/impl/WorkflowManagerImpl.java
+++ b/workflow/workflow-designer-be/src/main/java/org/onap/sdc/workflow/services/impl/WorkflowManagerImpl.java
@@ -1,11 +1,18 @@
package org.onap.sdc.workflow.services.impl;
+import static org.onap.sdc.workflow.api.RestConstants.SORT_FIELD_NAME;
+
+import java.util.ArrayList;
import java.util.Collection;
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.List;
import java.util.function.Predicate;
import java.util.stream.Collectors;
import org.onap.sdc.workflow.persistence.types.Workflow;
import org.onap.sdc.workflow.services.UniqueValueService;
import org.onap.sdc.workflow.services.WorkflowManager;
+import org.onap.sdc.workflow.services.WorkflowNameComparator;
import org.onap.sdc.workflow.services.exceptions.EntityNotFoundException;
import org.onap.sdc.workflow.services.impl.mappers.WorkflowMapper;
import org.openecomp.sdc.versioning.ItemManager;
@@ -13,6 +20,8 @@ import org.openecomp.sdc.versioning.types.Item;
import org.openecomp.sdc.versioning.types.ItemStatus;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
+import org.springframework.data.domain.Pageable;
+import org.springframework.data.domain.Sort;
import org.springframework.stereotype.Service;
@Service("workflowManager")
@@ -36,9 +45,11 @@ public class WorkflowManagerImpl implements WorkflowManager {
}
@Override
- public Collection<Workflow> list() {
- return itemManager.list(ITEM_PREDICATE).stream().map(workflowMapper::itemToWorkflow)
- .collect(Collectors.toList());
+ public Collection<Workflow> list(Pageable pageRequest) {
+ List<Workflow> workflowList = itemManager.list(ITEM_PREDICATE).stream()
+ .map( workflowMapper::itemToWorkflow).collect(Collectors.toList());
+ sortWorkflowList(workflowList, pageRequest);
+ return applyLimitAndOffset(workflowList, pageRequest);
}
@Override
@@ -76,4 +87,39 @@ public class WorkflowManagerImpl implements WorkflowManager {
item.setVersionStatusCounters(retrievedItem.getVersionStatusCounters());
itemManager.update(item);
}
+
+ private List<Workflow> applyLimitAndOffset(List<Workflow> workflowList, Pageable pageRequest) {
+ int limit = pageRequest.getPageSize();
+ int offset = pageRequest.getPageNumber();
+ int totalNumOfWorkflows = workflowList.size();
+ List<Workflow> selectedWorkflows;
+ try {
+ if (limit > totalNumOfWorkflows) {
+ limit = totalNumOfWorkflows;
+ }
+ int startIndex = offset * limit;
+ int endIndex = startIndex + limit;
+ if (endIndex > totalNumOfWorkflows) {
+ endIndex = totalNumOfWorkflows;
+ }
+ selectedWorkflows = workflowList.subList(startIndex, endIndex);
+ } catch (IndexOutOfBoundsException | IllegalArgumentException ex) {
+ selectedWorkflows = new ArrayList<>();
+ }
+ return selectedWorkflows;
+ }
+
+ private void sortWorkflowList(List<Workflow> workflowList, Pageable pageRequest) {
+ Comparator<Workflow> comparator = getWorkflowListComparator();
+ if (pageRequest.getSort().getOrderFor(SORT_FIELD_NAME).getDirection() == Sort.Direction.ASC) {
+ workflowList.sort(comparator);
+ } else {
+ workflowList.sort(Collections.reverseOrder(comparator));
+ }
+ }
+
+ private Comparator<Workflow> getWorkflowListComparator() {
+ //More comparators can be added if required based on sort field name
+ return new WorkflowNameComparator();
+ }
}
diff --git a/workflow/workflow-designer-be/src/test/java/org/onap/sdc/workflow/RestPath.java b/workflow/workflow-designer-be/src/test/java/org/onap/sdc/workflow/RestPath.java
index 266ca91b..ba99996a 100644
--- a/workflow/workflow-designer-be/src/test/java/org/onap/sdc/workflow/RestPath.java
+++ b/workflow/workflow-designer-be/src/test/java/org/onap/sdc/workflow/RestPath.java
@@ -1,10 +1,46 @@
package org.onap.sdc.workflow;
+import static org.onap.sdc.workflow.api.RestConstants.LIMIT_PARAM;
+import static org.onap.sdc.workflow.api.RestConstants.OFFSET_PARAM;
+import static org.onap.sdc.workflow.api.RestConstants.SORT_PARAM;
+
public class RestPath {
+ private RestPath() {
+ //Hiding implicit constructor
+ }
+
private static final String WORKFLOWS_URL = "/workflows";
private static final String WORKFLOW_URL_FORMATTER = WORKFLOWS_URL + "/%s";
private static final String VERSIONS_URL_FORMATTER = WORKFLOWS_URL + "/%s/versions";
private static final String VERSION_URL_FORMATTER = WORKFLOWS_URL + "/%s/versions/%s";
+ private static final String SORT_QUERY_STRING_FORMATTER = SORT_PARAM + "=%s";
+ private static final String LIMIT_QUERY_STRING_FORMATTER = LIMIT_PARAM + "=%s";
+ private static final String OFFSET_QUERY_STRING_FORMATTER = OFFSET_PARAM + "=%s";
+ private static final String WORKFLOW_URL_FORMATTER_QUERY_PARAMS_ALL =
+ WORKFLOWS_URL + "?" + SORT_QUERY_STRING_FORMATTER+ "&" + LIMIT_QUERY_STRING_FORMATTER + "&" +
+ OFFSET_QUERY_STRING_FORMATTER;
+ private static final String WORKFLOW_URL_FORMATTER_QUERY_PARAMS_NO_SORT =
+ WORKFLOWS_URL + "?" + LIMIT_QUERY_STRING_FORMATTER + "&" + OFFSET_QUERY_STRING_FORMATTER;
+ private static final String WORKFLOW_URL_FORMATTER_QUERY_PARAMS_NO_SORT_AND_LIMIT =
+ WORKFLOWS_URL + "?" + OFFSET_QUERY_STRING_FORMATTER;
+ private static final String WORKFLOW_URL_FORMATTER_QUERY_PARAMS_NO_SORT_AND_OFFSET =
+ WORKFLOWS_URL + "?" + LIMIT_QUERY_STRING_FORMATTER;
+
+ public static String getWorkflowsPathAllQueryParams(String sort, String limit, String offset){
+ return String.format(WORKFLOW_URL_FORMATTER_QUERY_PARAMS_ALL, sort, limit, offset);
+ }
+
+ public static String getWorkflowsPathNoSort(String limit, String offset){
+ return String.format(WORKFLOW_URL_FORMATTER_QUERY_PARAMS_NO_SORT, limit, offset);
+ }
+
+ public static String getWorkflowsPathNoSortAndLimit(String offset){
+ return String.format(WORKFLOW_URL_FORMATTER_QUERY_PARAMS_NO_SORT_AND_LIMIT, offset);
+ }
+
+ public static String getWorkflowsPathNoSortAndOffset(String limit){
+ return String.format(WORKFLOW_URL_FORMATTER_QUERY_PARAMS_NO_SORT_AND_OFFSET, limit);
+ }
public static String getWorkflowsPath(){
return WORKFLOWS_URL;
diff --git a/workflow/workflow-designer-be/src/test/java/org/onap/sdc/workflow/api/WorkflowControllerTest.java b/workflow/workflow-designer-be/src/test/java/org/onap/sdc/workflow/api/WorkflowControllerTest.java
index 454a5d38..1f36759d 100644
--- a/workflow/workflow-designer-be/src/test/java/org/onap/sdc/workflow/api/WorkflowControllerTest.java
+++ b/workflow/workflow-designer-be/src/test/java/org/onap/sdc/workflow/api/WorkflowControllerTest.java
@@ -8,6 +8,10 @@ import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.onap.sdc.workflow.TestUtil.createWorkflow;
+import static org.onap.sdc.workflow.api.RestConstants.LIMIT_DEFAULT;
+import static org.onap.sdc.workflow.api.RestConstants.OFFSET_DEFAULT;
+import static org.onap.sdc.workflow.api.RestConstants.SORT_FIELD_NAME;
+import static org.onap.sdc.workflow.api.RestConstants.SORT_PARAM;
import static org.onap.sdc.workflow.api.RestConstants.USER_ID_HEADER_PARAM;
import static org.springframework.http.MediaType.APPLICATION_JSON;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
@@ -16,9 +20,14 @@ import static org.springframework.test.web.servlet.result.MockMvcResultHandlers.
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import com.google.common.collect.ImmutableSet;
import com.google.gson.Gson;
+
import java.util.ArrayList;
import java.util.List;
+import java.util.Set;
+
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -26,9 +35,12 @@ import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.junit.MockitoJUnitRunner;
import org.onap.sdc.workflow.RestPath;
+import org.onap.sdc.workflow.api.exceptionshandlers.CustomizedResponseEntityExceptionHandler;
+import org.onap.sdc.workflow.api.types.CollectionWrapper;
import org.onap.sdc.workflow.persistence.types.Workflow;
import org.onap.sdc.workflow.services.WorkflowManager;
import org.openecomp.sdc.versioning.types.Item;
+import org.springframework.data.web.PageableHandlerMethodArgumentResolver;
import org.springframework.http.MediaType;
import org.springframework.mock.web.MockHttpServletResponse;
import org.springframework.test.web.servlet.MockMvc;
@@ -42,6 +54,11 @@ public class WorkflowControllerTest {
"Missing request header '%s' for method parameter of type String";
private static final String USER_ID = "userId";
private static final Gson GSON = new Gson();
+ private static final String USER_ID_HEADER = "USER_ID";
+ private static final String INVALID_PAGINATION_PARAMETER_FORMAT = "Requested %s: %s %s";
+ private static final String PAGINATION_PARAMETER_INVALID_SORT_FIELD_SUFFIX =
+ "is not supported. Supported values are: ";
+ private static final String DEFAULT_SORT_VALUE = "name,asc";
private MockMvc mockMvc;
@@ -55,6 +72,10 @@ public class WorkflowControllerTest {
@Before
public void setUp() {
mockMvc = MockMvcBuilders.standaloneSetup(workflowController).build();
+ mockMvc = MockMvcBuilders.standaloneSetup(workflowController)
+ .setCustomArgumentResolvers(new PageableHandlerMethodArgumentResolver())
+ .setControllerAdvice(new CustomizedResponseEntityExceptionHandler())
+ .build();
}
@Test
@@ -64,7 +85,7 @@ public class WorkflowControllerTest {
mockMvc.perform(get(RestPath.getWorkflowPath(workflowMock.getId())).contentType(APPLICATION_JSON))
.andDo(print()).andExpect(status().isBadRequest()).andExpect(status().is(400)).andReturn()
.getResponse();
- assertEquals(String.format(MISSING_REQUEST_HEADER_ERRROR_FORMAT, "USER_ID"), response.getErrorMessage());
+ assertEquals(String.format(MISSING_REQUEST_HEADER_ERRROR_FORMAT, USER_ID_HEADER), response.getContentAsString());
}
@Test
@@ -83,19 +104,129 @@ public class WorkflowControllerTest {
MockHttpServletResponse response =
mockMvc.perform(get(RestPath.getWorkflowsPath()).contentType(APPLICATION_JSON)).andDo(print())
.andExpect(status().isBadRequest()).andExpect(status().is(400)).andReturn().getResponse();
- assertEquals(String.format(MISSING_REQUEST_HEADER_ERRROR_FORMAT, USER_ID_HEADER_PARAM), response.getErrorMessage());
+ assertEquals(String.format(MISSING_REQUEST_HEADER_ERRROR_FORMAT, USER_ID_HEADER_PARAM), response.getContentAsString());
}
@Test
public void shouldReturn5WorkflowWhen5WorkflowsExists() throws Exception {
int numOfWorkflows = 5;
List<Workflow> workflowMocks = createWorkflows(numOfWorkflows);
- doReturn(workflowMocks).when(workflowManagerMock).list();
+ doReturn(workflowMocks).when(workflowManagerMock).list(any());
mockMvc.perform(
get(RestPath.getWorkflowsPath()).header(USER_ID_HEADER_PARAM, USER_ID).contentType(APPLICATION_JSON))
.andDo(print()).andExpect(status().isOk()).andExpect(jsonPath("$.results", hasSize(numOfWorkflows)));
}
+ @Test
+ public void shouldReturnSortedLimitOffsetAppliedWorkflows() throws Exception {
+ List<Workflow> workflowMocks = createLimit2AndOffset1For5WorkflowList();
+ doReturn(workflowMocks).when(workflowManagerMock).list(any());
+ mockMvc.perform(
+ get(RestPath.getWorkflowsPathAllQueryParams(DEFAULT_SORT_VALUE, "2", "1"))
+ .header(RestConstants.USER_ID_HEADER_PARAM, USER_ID).contentType(APPLICATION_JSON))
+ .andDo(print()).andExpect(status().isOk()).andExpect(jsonPath("$.results", hasSize(2)));
+ }
+
+ @Test
+ public void shouldReturnResultsWithDefaultWhenLimitIsNegative() throws Exception {
+ List<Workflow> workflowMocks = createLimit2AndOffset1For5WorkflowList();
+ doReturn(workflowMocks).when(workflowManagerMock).list(any());
+ MockHttpServletResponse response = mockMvc.perform(
+ get(RestPath.getWorkflowsPathAllQueryParams(DEFAULT_SORT_VALUE, "-2", "1"))
+ .header(RestConstants.USER_ID_HEADER_PARAM, USER_ID).contentType(APPLICATION_JSON))
+ .andDo(print()).andExpect(status().isOk()).andExpect(status().is(200)).andReturn()
+ .getResponse();
+ CollectionWrapper workflowListResponse =
+ new ObjectMapper().readValue(response.getContentAsString(), CollectionWrapper.class);
+ assertEquals(LIMIT_DEFAULT, workflowListResponse.getLimit());
+ assertEquals(1, workflowListResponse.getOffset());
+ assertEquals(2, workflowListResponse.getTotal());
+ }
+
+ @Test
+ public void shouldFallbackOnDefaultOffsetWhenOffsetIsNegative() throws Exception {
+ MockHttpServletResponse response = mockMvc.perform(
+ get(RestPath.getWorkflowsPathAllQueryParams(DEFAULT_SORT_VALUE, "2", "-1"))
+ .header(RestConstants.USER_ID_HEADER_PARAM, USER_ID).contentType(APPLICATION_JSON))
+ .andDo(print()).andExpect(status().isOk()).andExpect(status().is(200)).andReturn()
+ .getResponse();
+ CollectionWrapper workflowListResponse =
+ new ObjectMapper().readValue(response.getContentAsString(), CollectionWrapper.class);
+ assertEquals(2, workflowListResponse.getLimit());
+ assertEquals(OFFSET_DEFAULT, workflowListResponse.getOffset());
+ assertEquals(0, workflowListResponse.getTotal());
+ }
+
+ @Test
+ public void shouldFallbackOnDefaultLimitWhenLimitIsNotAnInteger() throws Exception {
+ MockHttpServletResponse response = mockMvc.perform(
+ get(RestPath.getWorkflowsPathAllQueryParams(DEFAULT_SORT_VALUE, "abc", "0"))
+ .header(RestConstants.USER_ID_HEADER_PARAM, USER_ID).contentType(APPLICATION_JSON))
+ .andDo(print()).andExpect(status().isOk()).andExpect(status().is(200)).andReturn()
+ .getResponse();
+ CollectionWrapper workflowListResponse =
+ new ObjectMapper().readValue(response.getContentAsString(), CollectionWrapper.class);
+ assertEquals(LIMIT_DEFAULT, workflowListResponse.getLimit());
+ assertEquals(0, workflowListResponse.getOffset());
+ assertEquals(0, workflowListResponse.getTotal());
+ }
+
+ @Test
+ public void shouldFallbackOnDefaultOffsetWhenOffsetIsNotAnInteger() throws Exception {
+ MockHttpServletResponse response = mockMvc.perform(
+ get(RestPath.getWorkflowsPathAllQueryParams(DEFAULT_SORT_VALUE, "2", "abc"))
+ .header(RestConstants.USER_ID_HEADER_PARAM, USER_ID).contentType(APPLICATION_JSON))
+ .andDo(print()).andExpect(status().isOk()).andExpect(status().is(200)).andReturn()
+ .getResponse();
+ CollectionWrapper workflowListResponse =
+ new ObjectMapper().readValue(response.getContentAsString(), CollectionWrapper.class);
+ assertEquals(2, workflowListResponse.getLimit());
+ assertEquals(OFFSET_DEFAULT, workflowListResponse.getOffset());
+ assertEquals(0, workflowListResponse.getTotal());
+ }
+
+ @Test
+ public void shouldThrowExceptionWhenSortFieldIsInvalid() throws Exception {
+ MockHttpServletResponse response = mockMvc.perform(
+ get(RestPath.getWorkflowsPathAllQueryParams("invalidSortField,asc", "2", "1"))
+ .header(RestConstants.USER_ID_HEADER_PARAM, USER_ID).contentType(APPLICATION_JSON))
+ .andDo(print()).andExpect(status().isBadRequest()).andExpect(status().is(400)).andReturn()
+ .getResponse();
+ assertEquals(String.format(INVALID_PAGINATION_PARAMETER_FORMAT, SORT_PARAM, "invalidSortField",
+ PAGINATION_PARAMETER_INVALID_SORT_FIELD_SUFFIX + getSupportedSortFields()),
+ response.getContentAsString());
+ }
+
+ @Test
+ public void shouldReturnAscSortedLimitOffsetAppliedWorkflowsWhenSortIsNotSpecified() throws Exception {
+ List<Workflow> workflowMocks = createLimit2AndOffset1For5WorkflowList();
+ doReturn(workflowMocks).when(workflowManagerMock).list(any());
+ mockMvc.perform(
+ get(RestPath.getWorkflowsPathNoSort("2", "1"))
+ .header(RestConstants.USER_ID_HEADER_PARAM, USER_ID).contentType(APPLICATION_JSON))
+ .andDo(print()).andExpect(status().isOk()).andExpect(jsonPath("$.results", hasSize(2)));
+ }
+
+ @Test
+ public void shouldReturnDefaultLimitOffsetAppliedWorkflowsWhenLimitIsNotSpecified() throws Exception {
+ List<Workflow> workflowMocks = createLimit2AndOffset1For5WorkflowList();
+ doReturn(workflowMocks).when(workflowManagerMock).list(any());
+ mockMvc.perform(
+ get(RestPath.getWorkflowsPathNoSortAndLimit("1"))
+ .header(RestConstants.USER_ID_HEADER_PARAM, USER_ID).contentType(APPLICATION_JSON))
+ .andDo(print()).andExpect(status().isOk()).andExpect(jsonPath("$.results", hasSize(2)));
+ }
+
+ @Test
+ public void shouldReturnDefaultOffsetAppliedWorkflowsWhenOffsetIsNotSpecified() throws Exception {
+ List<Workflow> workflowMocks = createLimit1WorkflowList();
+ doReturn(workflowMocks).when(workflowManagerMock).list(any());
+ mockMvc.perform(
+ get(RestPath.getWorkflowsPathNoSortAndOffset("1"))
+ .header(RestConstants.USER_ID_HEADER_PARAM, USER_ID).contentType(APPLICATION_JSON))
+ .andDo(print()).andExpect(status().isOk()).andExpect(jsonPath("$.results", hasSize(1)));
+ }
+
/* @Test
public void shouldCreateWorkflowWhenCallingPostRESTRequest() throws Exception {
Item item = new Item();
@@ -117,5 +248,22 @@ public class WorkflowControllerTest {
return workflowList;
}
+ private List<Workflow> createLimit2AndOffset1For5WorkflowList() {
+ List<Workflow> workflowList = new ArrayList<>();
+ workflowList.add(createWorkflow(2, true));
+ workflowList.add(createWorkflow(3, true));
+ return workflowList;
+ }
+
+ private List<Workflow> createLimit1WorkflowList() {
+ List<Workflow> workflowList = new ArrayList<>();
+ workflowList.add(createWorkflow(0, true));
+ return workflowList;
+ }
+
+
+ private Set<String> getSupportedSortFields() {
+ return ImmutableSet.of(SORT_FIELD_NAME);
+ }
} \ No newline at end of file
diff --git a/workflow/workflow-designer-be/src/test/java/org/onap/sdc/workflow/services/impl/WorkflowManagerImplTest.java b/workflow/workflow-designer-be/src/test/java/org/onap/sdc/workflow/services/impl/WorkflowManagerImplTest.java
index 17037d9b..500011b4 100644
--- a/workflow/workflow-designer-be/src/test/java/org/onap/sdc/workflow/services/impl/WorkflowManagerImplTest.java
+++ b/workflow/workflow-designer-be/src/test/java/org/onap/sdc/workflow/services/impl/WorkflowManagerImplTest.java
@@ -6,9 +6,14 @@ import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.onap.sdc.workflow.TestUtil.createItem;
import static org.onap.sdc.workflow.TestUtil.createWorkflow;
+import static org.onap.sdc.workflow.api.RestConstants.SORT_FIELD_NAME;
import java.util.Arrays;
+import java.util.Collection;
+import java.util.Iterator;
import java.util.List;
+
+import org.junit.Assert;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -21,6 +26,8 @@ import org.onap.sdc.workflow.services.impl.mappers.WorkflowMapper;
import org.openecomp.sdc.versioning.ItemManager;
import org.openecomp.sdc.versioning.types.Item;
import org.openecomp.sdc.versioning.types.ItemStatus;
+import org.springframework.data.domain.PageRequest;
+import org.springframework.data.domain.Sort;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
@RunWith(SpringJUnit4ClassRunner.class)
@@ -30,6 +37,7 @@ public class WorkflowManagerImplTest {
private static final String WORKFLOW_TYPE = "WORKFLOW";
private static final String WORKFLOW_NAME_UNIQUE_TYPE = "WORKFLOW_NAME";
private List<Item> itemList;
+ private List<Workflow> workflowList;
@Mock
private WorkflowMapper workflowMapperMock;
@@ -46,16 +54,21 @@ public class WorkflowManagerImplTest {
@Before
public void setUp() {
- itemList = Arrays.asList(createItem(1, true, true), createItem(2, true, true), createItem(3, true, true));
-
+ itemList = Arrays.asList(createItem(1, true, true), createItem(2, true, true), createItem(3, true, true),
+ createItem(4, true, true), createItem(5, true, true));
+ workflowList = Arrays.asList(createWorkflow(1, true), createWorkflow(2, true), createWorkflow(3, true),
+ createWorkflow(4, true), createWorkflow(5, true));
}
@Test
public void shouldReturnWorkflowVersionList() {
-
+ PageRequest pageRequest = createPageRequest(2, 1, Sort.Direction.DESC, SORT_FIELD_NAME);
doReturn(itemList).when(itemManagerMock).list(WorkflowManagerImpl.ITEM_PREDICATE);
- workflowManager.list();
+ for (int i=0; i<itemList.size(); i++) {
+ doReturn(workflowList.get(i)).when(workflowMapperMock).itemToWorkflow(itemList.get(i));
+ }
+ workflowManager.list(pageRequest);
verify(itemManagerMock).list(WorkflowManagerImpl.ITEM_PREDICATE);
}
@@ -116,4 +129,83 @@ public class WorkflowManagerImplTest {
workflowManager.update(createWorkflow(1, true));
}
+ @Test
+ public void shouldListAllWorkflowsWhenLimitAndOffsetAreValid() {
+ PageRequest pageRequest = createPageRequest(5, 0, Sort.Direction.ASC, SORT_FIELD_NAME);
+ doReturn(itemList).when(itemManagerMock).list(WorkflowManagerImpl.ITEM_PREDICATE);
+ for (int i=0; i<itemList.size(); i++) {
+ doReturn(workflowList.get(i)).when(workflowMapperMock).itemToWorkflow(itemList.get(i));
+ }
+ Assert.assertEquals(5, workflowManager.list(pageRequest).size());
+ }
+
+ @Test
+ public void shouldListLimitFilteredWorkflowsInFirstOffsetRange() {
+ PageRequest pageRequest = createPageRequest(3, 0, Sort.Direction.ASC, SORT_FIELD_NAME);
+ doReturn(itemList).when(itemManagerMock).list(WorkflowManagerImpl.ITEM_PREDICATE);
+ for (int i=0; i<itemList.size(); i++) {
+ doReturn(workflowList.get(i)).when(workflowMapperMock).itemToWorkflow(itemList.get(i));
+ }
+ Assert.assertEquals(3, workflowManager.list(pageRequest).size());
+ }
+
+ @Test
+ public void shouldListLimitFilteredWorkflowsInSecondOffsetRange() {
+ PageRequest pageRequest = createPageRequest(3, 1, Sort.Direction.ASC, SORT_FIELD_NAME);
+ doReturn(itemList).when(itemManagerMock).list(WorkflowManagerImpl.ITEM_PREDICATE);
+ for (int i=0; i<itemList.size(); i++) {
+ doReturn(workflowList.get(i)).when(workflowMapperMock).itemToWorkflow(itemList.get(i));
+ }
+ Assert.assertEquals(2, workflowManager.list(pageRequest).size());
+ }
+
+ @Test
+ public void shouldListAllWorkflowsWhenLimitGreaterThanTotalRecordsAndOffsetInRange() {
+ PageRequest pageRequest = createPageRequest(10, 0, Sort.Direction.ASC, SORT_FIELD_NAME);
+ doReturn(itemList).when(itemManagerMock).list(WorkflowManagerImpl.ITEM_PREDICATE);
+ for (int i=0; i<itemList.size(); i++) {
+ doReturn(workflowList.get(i)).when(workflowMapperMock).itemToWorkflow(itemList.get(i));
+ }
+ Assert.assertEquals(5, workflowManager.list(pageRequest).size());
+ }
+
+ @Test
+ public void shouldNotListWorkflowsIfOffsetGreaterThanTotalRecords() {
+ PageRequest pageRequest = createPageRequest(3, 6, Sort.Direction.ASC, SORT_FIELD_NAME);
+ doReturn(itemList).when(itemManagerMock).list(WorkflowManagerImpl.ITEM_PREDICATE);
+ for (int i=0; i<itemList.size(); i++) {
+ doReturn(workflowList.get(i)).when(workflowMapperMock).itemToWorkflow(itemList.get(i));
+ }
+ Assert.assertEquals(0, workflowManager.list(pageRequest).size());
+ }
+
+ @Test
+ public void shouldNotListWorkflowsBothLimitAndOffsetGreaterThanTotalRecords() {
+ PageRequest pageRequest = createPageRequest(10, 10, Sort.Direction.ASC, SORT_FIELD_NAME);
+ doReturn(itemList).when(itemManagerMock).list(WorkflowManagerImpl.ITEM_PREDICATE);
+ for (int i=0; i<itemList.size(); i++) {
+ doReturn(workflowList.get(i)).when(workflowMapperMock).itemToWorkflow(itemList.get(i));
+ }
+ Assert.assertEquals(0, workflowManager.list(pageRequest).size());
+ }
+
+ @Test
+ public void shouldListLimitOffsetAppliedWorkflowsSortedInDescOrder() {
+ PageRequest pageRequest = createPageRequest(2, 1, Sort.Direction.DESC, SORT_FIELD_NAME);
+ doReturn(itemList).when(itemManagerMock).list(WorkflowManagerImpl.ITEM_PREDICATE);
+ for (int i=0; i<itemList.size(); i++) {
+ doReturn(workflowList.get(i)).when(workflowMapperMock).itemToWorkflow(itemList.get(i));
+ }
+ Collection<Workflow> workflows = workflowManager.list(pageRequest);
+ Assert.assertEquals(2, workflows.size());
+ Iterator<Workflow> workflowIterator = workflows.iterator();
+ Assert.assertEquals("workflowName3", workflowIterator.next().getName());
+ Assert.assertEquals("workflowName2", workflowIterator.next().getName());
+ }
+
+ private PageRequest createPageRequest(int limit, int offset,
+ Sort.Direction sortOrder, String sortField) {
+ return PageRequest.of(offset, limit, sortOrder, sortField);
+ }
+
} \ No newline at end of file