diff --git a/lib/taskana-core/src/main/java/pro/taskana/task/api/TaskService.java b/lib/taskana-core/src/main/java/pro/taskana/task/api/TaskService.java index 6e357fdf2..463c3a583 100644 --- a/lib/taskana-core/src/main/java/pro/taskana/task/api/TaskService.java +++ b/lib/taskana-core/src/main/java/pro/taskana/task/api/TaskService.java @@ -169,9 +169,9 @@ public interface TaskService { * @param taskId the {@linkplain Task#getId() id} of the {@linkplain Task} to be claimed * @return the claimed {@linkplain Task} * @throws TaskNotFoundException if the {@linkplain Task} with taskId was not found - * @throws InvalidStateException if the {@linkplain Task#getState() state} of the {@linkplain - * Task} with taskId isn't {@linkplain TaskState#READY} - * @throws InvalidOwnerException if the {@linkplain Task} with taskId is claimed by someone else + * @throws InvalidStateException if the state of Task with taskId is in {@linkplain + * TaskState#END_STATES} + * @throws InvalidOwnerException cannot be thrown * @throws NotAuthorizedException if the current user has no {@linkplain * WorkbasketPermission#READ} for the {@linkplain Workbasket} the {@linkplain Task} is in */ @@ -216,8 +216,7 @@ public interface TaskService { * @throws TaskNotFoundException if the {@linkplain Task} with taskId was not found * @throws InvalidStateException if the {@linkplain Task} is already in one of the {@linkplain * TaskState#END_STATES} - * @throws InvalidOwnerException if forceCancel is false and the {@linkplain Task} is claimed by - * another user + * @throws InvalidOwnerException cannot be thrown * @throws NotAuthorizedException if the current user has no {@linkplain * WorkbasketPermission#READ} for the {@linkplain Workbasket} the {@linkplain Task} is in */ @@ -326,7 +325,9 @@ public interface TaskService { * @param taskId the {@linkplain Task#getId() id} of the {@linkplain Task} which should be * completed * @return the updated {@linkplain Task} after completion - * @throws InvalidStateException if the {@linkplain Task} with taskId wasn't claimed before + * @throws InvalidStateException if the {@linkplain Task#getState() state} of the {@linkplain + * Task} with taskId is with taskId is {@linkplain TaskState#TERMINATED} or {@linkplain + * TaskState#CANCELLED} * @throws TaskNotFoundException if the {@linkplain Task} with taskId wasn't found * @throws InvalidOwnerException if current user isn't the {@linkplain Task#getOwner() owner} of * the {@linkplain Task} or {@linkplain TaskanaRole#ADMIN} @@ -389,13 +390,13 @@ public interface TaskService { * *

This is typically done by administration to correct any technical issue. * - * @param taskId the {@linkplain Task#getId() id} of the {@linkplain Task} to cancel + * @param taskId the {@linkplain Task#getId() id} of the {@linkplain Task} to terminate * @return the updated {@linkplain Task} * @throws TaskNotFoundException if the {@linkplain Task} with taskId wasn't found * @throws InvalidStateException if the {@linkplain Task} isn't in {@linkplain TaskState#READY} or * {@linkplain TaskState#CLAIMED} * @throws NotAuthorizedException if the current user isn't member of {@linkplain - * TaskanaRole#ADMIN} or {@linkplain TaskanaRole#BUSINESS_ADMIN} + * TaskanaRole#ADMIN} or {@linkplain TaskanaRole#TASK_ADMIN} */ Task terminateTask(String taskId) throws TaskNotFoundException, InvalidStateException, NotAuthorizedException; @@ -710,8 +711,9 @@ public interface TaskService { * @throws TaskNotFoundException if the given {@linkplain Task#getId() id} doesn't refer to an * existing {@linkplain Task} * @throws InvalidStateException if the {@linkplain Task#getState() state} of the referenced - * {@linkplain Task} isn't one of the {@linkplain TaskState#END_STATES} and forceDelete is - * false + * {@linkplain Task} isn't {@linkplain TaskState#TERMINATED} or {@linkplain + * TaskState#CANCELLED} and the Callback State of the Task is {@linkplain + * CallbackState#CALLBACK_PROCESSING_REQUIRED} * @throws NotAuthorizedException if the current user isn't member of {@linkplain * TaskanaRole#ADMIN} */ diff --git a/rest/taskana-rest-spring/src/docs/asciidoc/rest-api.adoc b/rest/taskana-rest-spring/src/docs/asciidoc/rest-api.adoc index 50bacd5af..7b66589e9 100644 --- a/rest/taskana-rest-spring/src/docs/asciidoc/rest-api.adoc +++ b/rest/taskana-rest-spring/src/docs/asciidoc/rest-api.adoc @@ -8,8 +8,7 @@ This is the REST documentation for http://taskana.pro)[TASKANA] - the world's fi Whenever a parameter is an array type, several values can be passed by declaring that parameter multiple times. Whenever a parameter is a complex type, the attributes of the value-object can be passed as a json. -For example, a complex parameter with the name "complex-query-param" and attributes "attribute1" and "attribute2" -would be specified in the following way: + +For example, a complex parameter with the name "complex-query-param" and attributes "attribute1" and "attribute2" would be specified in the following way: + complex-query-param={"attribute1":"value1","attribute2":"value2"} === Hypermedia Support @@ -101,6 +100,7 @@ include::{snippets}/TaskControllerRestDocTest/getSpecificTaskDocTest/auto-sectio include::{snippets}/TaskControllerRestDocTest/getAllTasksDocTest/auto-section.adoc[] include::{snippets}/TaskControllerRestDocTest/updateTaskDocTest/auto-section.adoc[] include::{snippets}/TaskControllerRestDocTest/claimTaskDocTest/auto-section.adoc[] +include::{snippets}/TaskControllerRestDocTest/forceClaimTaskDocTest/auto-section.adoc[] include::{snippets}/TaskControllerRestDocTest/selectAndClaimTaskDocTest/auto-section.adoc[] include::{snippets}/TaskControllerRestDocTest/cancelClaimTaskDocTest/auto-section.adoc[] include::{snippets}/TaskControllerRestDocTest/forceCancelClaimTaskDocTest/auto-section.adoc[] @@ -109,9 +109,13 @@ include::{snippets}/TaskControllerRestDocTest/forceRequestReviewTaskDocTest/auto include::{snippets}/TaskControllerRestDocTest/requestChangesTaskDocTest/auto-section.adoc[] include::{snippets}/TaskControllerRestDocTest/forceRequestChangesTaskDocTest/auto-section.adoc[] include::{snippets}/TaskControllerRestDocTest/completeTaskDocTest/auto-section.adoc[] +include::{snippets}/TaskControllerRestDocTest/forceCompleteTaskDocTest/auto-section.adoc[] include::{snippets}/TaskControllerRestDocTest/cancelTaskDocTest/auto-section.adoc[] +include::{snippets}/TaskControllerRestDocTest/terminateTaskDocTest/auto-section.adoc[] include::{snippets}/TaskControllerRestDocTest/transferTaskDocTest/auto-section.adoc[] +include::{snippets}/TaskControllerRestDocTest/setTaskReadDocTest/auto-section.adoc[] include::{snippets}/TaskControllerRestDocTest/deleteTaskDocTest/auto-section.adoc[] +include::{snippets}/TaskControllerRestDocTest/forceDeleteTaskDocTest/auto-section.adoc[] include::{snippets}/TaskControllerRestDocTest/deleteTasksDocTest/auto-section.adoc[] == Task Comment Resource diff --git a/rest/taskana-rest-spring/src/main/java/pro/taskana/common/rest/RestEndpoints.java b/rest/taskana-rest-spring/src/main/java/pro/taskana/common/rest/RestEndpoints.java index 1245cd418..5b7f13135 100644 --- a/rest/taskana-rest-spring/src/main/java/pro/taskana/common/rest/RestEndpoints.java +++ b/rest/taskana-rest-spring/src/main/java/pro/taskana/common/rest/RestEndpoints.java @@ -43,6 +43,7 @@ public final class RestEndpoints { // task endpoints public static final String URL_TASKS = API_V1 + "tasks"; public static final String URL_TASKS_ID = API_V1 + "tasks/{taskId}"; + public static final String URL_TASKS_ID_FORCE = API_V1 + "tasks/{taskId}/force"; public static final String URL_TASKS_ID_CLAIM = API_V1 + "tasks/{taskId}/claim"; public static final String URL_TASKS_ID_CLAIM_FORCE = API_V1 + "tasks/{taskId}/claim/force"; public static final String URL_TASKS_ID_SELECT_AND_CLAIM = API_V1 + "tasks/select-and-claim"; @@ -54,9 +55,12 @@ public final class RestEndpoints { public static final String URL_TASKS_ID_REQUEST_CHANGES_FORCE = API_V1 + "tasks/{taskId}/request-changes/force"; public static final String URL_TASKS_ID_COMPLETE = API_V1 + "tasks/{taskId}/complete"; + public static final String URL_TASKS_ID_COMPLETE_FORCE = API_V1 + "tasks/{taskId}/complete/force"; public static final String URL_TASKS_ID_CANCEL = API_V1 + "tasks/{taskId}/cancel"; + public static final String URL_TASKS_ID_TERMINATE = API_V1 + "tasks/{taskId}/terminate"; public static final String URL_TASKS_ID_TRANSFER_WORKBASKET_ID = API_V1 + "tasks/{taskId}/transfer/{workbasketId}"; + public static final String URL_TASKS_ID_SET_READ = API_V1 + "tasks/{taskId}/set-read"; // task comment endpoints public static final String URL_TASK_COMMENTS = API_V1 + "tasks/{taskId}/comments"; diff --git a/rest/taskana-rest-spring/src/main/java/pro/taskana/task/rest/TaskController.java b/rest/taskana-rest-spring/src/main/java/pro/taskana/task/rest/TaskController.java index 9e3bf85e1..d5da13b20 100644 --- a/rest/taskana-rest-spring/src/main/java/pro/taskana/task/rest/TaskController.java +++ b/rest/taskana-rest-spring/src/main/java/pro/taskana/task/rest/TaskController.java @@ -49,6 +49,7 @@ import pro.taskana.task.api.models.Task; import pro.taskana.task.api.models.TaskSummary; import pro.taskana.task.rest.assembler.TaskRepresentationModelAssembler; import pro.taskana.task.rest.assembler.TaskSummaryRepresentationModelAssembler; +import pro.taskana.task.rest.models.IsReadRepresentationModel; import pro.taskana.task.rest.models.TaskRepresentationModel; import pro.taskana.task.rest.models.TaskSummaryCollectionRepresentationModel; import pro.taskana.task.rest.models.TaskSummaryPagedRepresentationModel; @@ -73,6 +74,43 @@ public class TaskController { this.taskSummaryRepresentationModelAssembler = taskSummaryRepresentationModelAssembler; } + // region CREATE + + /** + * This endpoint creates a persistent Task. + * + * @param taskRepresentationModel the Task which should be created. + * @return the created Task + * @throws WorkbasketNotFoundException if the referenced Workbasket does not exist + * @throws ClassificationNotFoundException if the referenced Classification does not exist + * @throws NotAuthorizedException if the current user is not authorized to append a Task to the + * referenced Workbasket + * @throws TaskAlreadyExistException if the requested Task already exists. + * @throws InvalidArgumentException if any input is semantically wrong. + * @throws AttachmentPersistenceException if an Attachment with ID will be added multiple times + * without using the task-methods + * @throws ObjectReferencePersistenceException if an ObjectReference with ID will be added + * multiple times without using the task-methods + * @title Create a new Task + */ + @PostMapping(path = RestEndpoints.URL_TASKS) + @Transactional(rollbackFor = Exception.class) + public ResponseEntity createTask( + @RequestBody TaskRepresentationModel taskRepresentationModel) + throws WorkbasketNotFoundException, ClassificationNotFoundException, NotAuthorizedException, + TaskAlreadyExistException, InvalidArgumentException, AttachmentPersistenceException, + ObjectReferencePersistenceException { + Task fromResource = taskRepresentationModelAssembler.toEntityModel(taskRepresentationModel); + Task createdTask = taskService.createTask(fromResource); + + return ResponseEntity.status(HttpStatus.CREATED) + .body(taskRepresentationModelAssembler.toModel(createdTask)); + } + + // endregion + + // region READ + /** * This endpoint retrieves a list of existing Tasks. Filters can be applied. * @@ -116,50 +154,6 @@ public class TaskController { return ResponseEntity.ok(pagedModels); } - /** - * This endpoint deletes an aggregation of Tasks and returns the deleted Tasks. Filters can be - * applied. - * - * @title Delete multiple Tasks - * @param filterParameter the filter parameters - * @param filterCustomFields the filter parameters regarding TaskCustomFields - * @param filterCustomIntFields the filter parameters regarding TaskCustomIntFields - * @return the deleted task summaries - * @throws InvalidArgumentException TODO: this is never thrown - * @throws NotAuthorizedException if the current user is not authorized to delete the requested - * Tasks. - */ - @DeleteMapping(path = RestEndpoints.URL_TASKS) - @Transactional(readOnly = true, rollbackFor = Exception.class) - public ResponseEntity deleteTasks( - TaskQueryFilterParameter filterParameter, - TaskQueryFilterCustomFields filterCustomFields, - TaskQueryFilterCustomIntFields filterCustomIntFields) - throws InvalidArgumentException, NotAuthorizedException { - TaskQuery query = taskService.createTaskQuery(); - filterParameter.apply(query); - filterCustomFields.apply(query); - filterCustomIntFields.apply(query); - - List taskSummaries = query.list(); - - List taskIdsToDelete = - taskSummaries.stream().map(TaskSummary::getId).collect(Collectors.toList()); - - BulkOperationResults result = - taskService.deleteTasks(taskIdsToDelete); - - Set failedIds = new HashSet<>(result.getFailedIds()); - List successfullyDeletedTaskSummaries = - taskSummaries.stream() - .filter(not(summary -> failedIds.contains(summary.getId()))) - .collect(Collectors.toList()); - - return ResponseEntity.ok( - taskSummaryRepresentationModelAssembler.toTaskanaCollectionModel( - successfullyDeletedTaskSummaries)); - } - /** * This endpoint retrieves a specific Task. * @@ -178,6 +172,10 @@ public class TaskController { return ResponseEntity.ok(taskRepresentationModelAssembler.toModel(task)); } + // endregion + + // region UPDATE + /** * This endpoint claims a Task if possible. * @@ -198,8 +196,108 @@ public class TaskController { throws TaskNotFoundException, InvalidStateException, InvalidOwnerException, NotAuthorizedException { // TODO verify user - taskService.claim(taskId); - Task updatedTask = taskService.getTask(taskId); + Task updatedTask = taskService.claim(taskId); + return ResponseEntity.ok(taskRepresentationModelAssembler.toModel(updatedTask)); + } + + /** + * This endpoint force claims a Task if possible even if it is already claimed by someone else. + * + * @param taskId the Id of the Task which should be force claimed + * @param userName TODO: this is currently not used + * @return the force claimed Task + * @throws TaskNotFoundException if the requested Task does not exist. + * @throws InvalidStateException if the state of Task with taskId is in an END_STATE. + * @throws InvalidOwnerException cannot be thrown. + * @throws NotAuthorizedException if the current user has no read permissions for the requested + * Task. + * @title Force claim a Task + */ + @PostMapping(path = RestEndpoints.URL_TASKS_ID_CLAIM_FORCE) + @Transactional(rollbackFor = Exception.class) + public ResponseEntity forceClaimTask( + @PathVariable String taskId, @RequestBody(required = false) String userName) + throws TaskNotFoundException, InvalidStateException, InvalidOwnerException, + NotAuthorizedException { + // TODO verify user + Task updatedTask = taskService.forceClaim(taskId); + return ResponseEntity.ok(taskRepresentationModelAssembler.toModel(updatedTask)); + } + + /** + * This endpoint selects the first Task returned by the Task Query and claims it. + * + * @param filterParameter the filter parameters + * @param filterCustomFields the filter parameters regarding TaskCustomFields + * @param filterCustomIntFields the filter parameters regarding TaskCustomIntFields + * @param sortParameter the sort parameters + * @return the claimed Task + * @throws InvalidOwnerException if the Task is already claimed by someone else + * @throws NotAuthorizedException if the current user has no read permission for the Workbasket + * the Task is in + * @title Select and claim a Task + */ + @PostMapping(path = RestEndpoints.URL_TASKS_ID_SELECT_AND_CLAIM) + @Transactional(rollbackFor = Exception.class) + public ResponseEntity selectAndClaimTask( + TaskQueryFilterParameter filterParameter, + TaskQueryFilterCustomFields filterCustomFields, + TaskQueryFilterCustomIntFields filterCustomIntFields, + TaskQuerySortParameter sortParameter) + throws InvalidOwnerException, NotAuthorizedException { + TaskQuery query = taskService.createTaskQuery(); + + filterParameter.apply(query); + filterCustomFields.apply(query); + filterCustomIntFields.apply(query); + sortParameter.apply(query); + + Task selectedAndClaimedTask = taskService.selectAndClaim(query); + + return ResponseEntity.ok(taskRepresentationModelAssembler.toModel(selectedAndClaimedTask)); + } + + /** + * This endpoint cancels the claim of an existing Task if it was claimed by the current user + * before. + * + * @param taskId the Id of the requested Task. + * @return the unclaimed Task. + * @throws TaskNotFoundException if the requested Task does not exist. + * @throws InvalidStateException if the Task is already in an end state. + * @throws InvalidOwnerException if the Task is claimed by a different user. + * @throws NotAuthorizedException if the current user has no read permission for the Workbasket + * the Task is in + * @title Cancel a claimed Task + */ + @DeleteMapping(path = RestEndpoints.URL_TASKS_ID_CLAIM) + @Transactional(rollbackFor = Exception.class) + public ResponseEntity cancelClaimTask(@PathVariable String taskId) + throws TaskNotFoundException, InvalidStateException, InvalidOwnerException, + NotAuthorizedException { + Task updatedTask = taskService.cancelClaim(taskId); + + return ResponseEntity.ok(taskRepresentationModelAssembler.toModel(updatedTask)); + } + + /** + * This endpoint force cancels the claim of an existing Task. + * + * @param taskId the Id of the requested Task. + * @return the unclaimed Task. + * @throws TaskNotFoundException if the requested Task does not exist. + * @throws InvalidStateException if the Task is already in an end state. + * @throws InvalidOwnerException if the Task is claimed by a different user. + * @throws NotAuthorizedException if the current user has no read permission for the Workbasket + * the Task is in + * @title Force cancel a claimed Task + */ + @DeleteMapping(path = RestEndpoints.URL_TASKS_ID_CLAIM_FORCE) + @Transactional(rollbackFor = Exception.class) + public ResponseEntity forceCancelClaimTask(@PathVariable String taskId) + throws TaskNotFoundException, InvalidStateException, InvalidOwnerException, + NotAuthorizedException { + Task updatedTask = taskService.forceCancelClaim(taskId); return ResponseEntity.ok(taskRepresentationModelAssembler.toModel(updatedTask)); } @@ -287,83 +385,6 @@ public class TaskController { return ResponseEntity.ok(taskRepresentationModelAssembler.toModel(task)); } - /** - * This endpoint selects the first Task returned by the Task Query and claims it. - * - * @param filterParameter the filter parameters - * @param filterCustomFields the filter parameters regarding TaskCustomFields - * @param filterCustomIntFields the filter parameters regarding TaskCustomIntFields - * @param sortParameter the sort parameters - * @return the claimed Task - * @throws InvalidOwnerException if the Task is already claimed by someone else - * @throws NotAuthorizedException if the current user has no read permission for the Workbasket - * the Task is in - * @title Select and claim a Task - */ - @PostMapping(path = RestEndpoints.URL_TASKS_ID_SELECT_AND_CLAIM) - @Transactional(rollbackFor = Exception.class) - public ResponseEntity selectAndClaimTask( - TaskQueryFilterParameter filterParameter, - TaskQueryFilterCustomFields filterCustomFields, - TaskQueryFilterCustomIntFields filterCustomIntFields, - TaskQuerySortParameter sortParameter) - throws InvalidOwnerException, NotAuthorizedException { - TaskQuery query = taskService.createTaskQuery(); - - filterParameter.apply(query); - filterCustomFields.apply(query); - filterCustomIntFields.apply(query); - sortParameter.apply(query); - - Task selectedAndClaimedTask = taskService.selectAndClaim(query); - - return ResponseEntity.ok(taskRepresentationModelAssembler.toModel(selectedAndClaimedTask)); - } - - /** - * This endpoint cancels the claim of an existing Task if it was claimed by the current user - * before. - * - * @param taskId the Id of the requested Task. - * @return the unclaimed Task. - * @throws TaskNotFoundException if the requested Task does not exist. - * @throws InvalidStateException if the Task is already in an end state. - * @throws InvalidOwnerException if the Task is claimed by a different user. - * @throws NotAuthorizedException if the current user has no read permission for the Workbasket - * the Task is in - * @title Cancel a claimed Task - */ - @DeleteMapping(path = RestEndpoints.URL_TASKS_ID_CLAIM) - @Transactional(rollbackFor = Exception.class) - public ResponseEntity cancelClaimTask(@PathVariable String taskId) - throws TaskNotFoundException, InvalidStateException, InvalidOwnerException, - NotAuthorizedException { - Task updatedTask = taskService.cancelClaim(taskId); - - return ResponseEntity.ok(taskRepresentationModelAssembler.toModel(updatedTask)); - } - - /** - * This endpoint force cancels the claim of an existing Task. - * - * @param taskId the Id of the requested Task. - * @return the unclaimed Task. - * @throws TaskNotFoundException if the requested Task does not exist. - * @throws InvalidStateException if the Task is already in an end state. - * @throws InvalidOwnerException if the Task is claimed by a different user. - * @throws NotAuthorizedException if the current user has no read permission for the Workbasket - * the Task is in - * @title Force cancel a claimed Task - */ - @DeleteMapping(path = RestEndpoints.URL_TASKS_ID_CLAIM_FORCE) - @Transactional(rollbackFor = Exception.class) - public ResponseEntity forceCancelClaimTask(@PathVariable String taskId) - throws TaskNotFoundException, InvalidStateException, InvalidOwnerException, - NotAuthorizedException { - Task updatedTask = taskService.forceCancelClaim(taskId); - return ResponseEntity.ok(taskRepresentationModelAssembler.toModel(updatedTask)); - } - /** * This endpoint completes a Task. * @@ -382,29 +403,32 @@ public class TaskController { throws TaskNotFoundException, InvalidOwnerException, InvalidStateException, NotAuthorizedException { - Task updatedTask = taskService.forceCompleteTask(taskId); + Task updatedTask = taskService.completeTask(taskId); return ResponseEntity.ok(taskRepresentationModelAssembler.toModel(updatedTask)); } /** - * This endpoint deletes a Task. + * This endpoint force completes a Task. * - * @title Delete a Task - * @param taskId the Id of the Task which should be deleted. - * @return the deleted Task. + * @param taskId Id of the requested Task to force complete. + * @return the force completed Task * @throws TaskNotFoundException if the requested Task does not exist. - * @throws InvalidStateException TODO: this is never thrown - * @throws NotAuthorizedException if the current user is not authorized to delete the requested - * Task. + * @throws InvalidOwnerException cannot be thrown. + * @throws InvalidStateException if the state of the Task with taskId is TERMINATED or CANCELED + * @throws NotAuthorizedException if the current user has no read permission for the Workbasket + * the Task is in + * @title Force complete a Task */ - @DeleteMapping(path = RestEndpoints.URL_TASKS_ID) + @PostMapping(path = RestEndpoints.URL_TASKS_ID_COMPLETE_FORCE) @Transactional(rollbackFor = Exception.class) - public ResponseEntity deleteTask(@PathVariable String taskId) - throws TaskNotFoundException, InvalidStateException, NotAuthorizedException { - taskService.forceDeleteTask(taskId); + public ResponseEntity forceCompleteTask(@PathVariable String taskId) + throws TaskNotFoundException, InvalidOwnerException, InvalidStateException, + NotAuthorizedException { - return ResponseEntity.noContent().build(); + Task updatedTask = taskService.forceCompleteTask(taskId); + + return ResponseEntity.ok(taskRepresentationModelAssembler.toModel(updatedTask)); } /** @@ -430,34 +454,23 @@ public class TaskController { } /** - * This endpoint creates a persistent Task. + * This endpoint terminates a Task. Termination is an administrative action to complete a Task. * - * @param taskRepresentationModel the Task which should be created. - * @return the created Task - * @throws WorkbasketNotFoundException if the referenced Workbasket does not exist - * @throws ClassificationNotFoundException if the referenced Classification does not exist - * @throws NotAuthorizedException if the current user is not authorized to append a Task to the - * referenced Workbasket - * @throws TaskAlreadyExistException if the requested Task already exists. - * @throws InvalidArgumentException if any input is semantically wrong. - * @throws AttachmentPersistenceException if an Attachment with ID will be added multiple times - * without using the task-methods - * @throws ObjectReferencePersistenceException if an ObjectReference with ID will be added - * multiple times without using the task-methods - * @title Create a new Task + * @param taskId Id of the requested Task to terminate. + * @return the terminated Task + * @throws TaskNotFoundException if the requested Task does not exist. + * @throws InvalidStateException if the task is not in state READY or CLAIMED + * @throws NotAuthorizedException if the current user isn't an administrator (ADMIN/TASKADMIN) + * @title Terminate a Task */ - @PostMapping(path = RestEndpoints.URL_TASKS) + @PostMapping(path = RestEndpoints.URL_TASKS_ID_TERMINATE) @Transactional(rollbackFor = Exception.class) - public ResponseEntity createTask( - @RequestBody TaskRepresentationModel taskRepresentationModel) - throws WorkbasketNotFoundException, ClassificationNotFoundException, NotAuthorizedException, - TaskAlreadyExistException, InvalidArgumentException, AttachmentPersistenceException, - ObjectReferencePersistenceException { - Task fromResource = taskRepresentationModelAssembler.toEntityModel(taskRepresentationModel); - Task createdTask = taskService.createTask(fromResource); + public ResponseEntity terminateTask(@PathVariable String taskId) + throws TaskNotFoundException, NotAuthorizedException, InvalidStateException { - return ResponseEntity.status(HttpStatus.CREATED) - .body(taskRepresentationModelAssembler.toModel(createdTask)); + Task terminatedTask = taskService.terminateTask(taskId); + + return ResponseEntity.ok(taskRepresentationModelAssembler.toModel(terminatedTask)); } /** @@ -527,6 +540,119 @@ public class TaskController { return ResponseEntity.ok(taskRepresentationModelAssembler.toModel(task)); } + /** + * This endpoint sets the 'isRead' property of a Task. + * + * @param taskId Id of the requested Task to set read or unread. + * @param isRead if true, the Task property isRead is set to true, else it's set to false + * @return the updated Task + * @throws TaskNotFoundException if the requested Task does not exist. + * @throws NotAuthorizedException if the current user has no read permission for the Workbasket + * the Task is in + * @title Set a Task read or unread + */ + @PostMapping(path = RestEndpoints.URL_TASKS_ID_SET_READ) + @Transactional(rollbackFor = Exception.class) + public ResponseEntity setTaskRead( + @PathVariable String taskId, @RequestBody IsReadRepresentationModel isRead) + throws TaskNotFoundException, NotAuthorizedException { + + Task updatedTask = taskService.setTaskRead(taskId, isRead.getIsRead()); + + return ResponseEntity.ok(taskRepresentationModelAssembler.toModel(updatedTask)); + } + + // endregion + + // region DELETE + + /** + * This endpoint deletes a Task. + * + * @title Delete a Task + * @param taskId the Id of the Task which should be deleted. + * @return the deleted Task. + * @throws TaskNotFoundException if the requested Task does not exist. + * @throws InvalidStateException If the Task is not in an END_STATE + * @throws NotAuthorizedException if the current user isn't an administrator (ADMIN) + */ + @DeleteMapping(path = RestEndpoints.URL_TASKS_ID) + @Transactional(rollbackFor = Exception.class) + public ResponseEntity deleteTask(@PathVariable String taskId) + throws TaskNotFoundException, InvalidStateException, NotAuthorizedException { + taskService.deleteTask(taskId); + + return ResponseEntity.noContent().build(); + } + + /** + * This endpoint force deletes a Task even if it's not completed. + * + * @title Force delete a Task + * @param taskId the Id of the Task which should be force deleted. + * @return the force deleted Task. + * @throws TaskNotFoundException if the requested Task does not exist. + * @throws InvalidStateException If the Task is not TERMINATED or CANCELLED and the Callback state + * of the Task is CALLBACK_PROCESSING_REQUIRED + * @throws NotAuthorizedException if the current user isn't an administrator (ADMIN) Task. + */ + @DeleteMapping(path = RestEndpoints.URL_TASKS_ID_FORCE) + @Transactional(rollbackFor = Exception.class) + public ResponseEntity forceDeleteTask(@PathVariable String taskId) + throws TaskNotFoundException, InvalidStateException, NotAuthorizedException { + taskService.forceDeleteTask(taskId); + + return ResponseEntity.noContent().build(); + } + + /** + * This endpoint deletes an aggregation of Tasks and returns the deleted Tasks. Filters can be + * applied. + * + * @title Delete multiple Tasks + * @param filterParameter the filter parameters + * @param filterCustomFields the filter parameters regarding TaskCustomFields + * @param filterCustomIntFields the filter parameters regarding TaskCustomIntFields + * @return the deleted task summaries + * @throws InvalidArgumentException TODO: this is never thrown + * @throws NotAuthorizedException if the current user is not authorized to delete the requested + * Tasks. + */ + @DeleteMapping(path = RestEndpoints.URL_TASKS) + @Transactional(readOnly = true, rollbackFor = Exception.class) + public ResponseEntity deleteTasks( + TaskQueryFilterParameter filterParameter, + TaskQueryFilterCustomFields filterCustomFields, + TaskQueryFilterCustomIntFields filterCustomIntFields) + throws InvalidArgumentException, NotAuthorizedException { + TaskQuery query = taskService.createTaskQuery(); + filterParameter.apply(query); + filterCustomFields.apply(query); + filterCustomIntFields.apply(query); + + List taskSummaries = query.list(); + + List taskIdsToDelete = + taskSummaries.stream().map(TaskSummary::getId).collect(Collectors.toList()); + + BulkOperationResults result = + taskService.deleteTasks(taskIdsToDelete); + + Set failedIds = new HashSet<>(result.getFailedIds()); + List successfullyDeletedTaskSummaries = + taskSummaries.stream() + .filter(not(summary -> failedIds.contains(summary.getId()))) + .collect(Collectors.toList()); + + return ResponseEntity.ok( + taskSummaryRepresentationModelAssembler.toTaskanaCollectionModel( + successfullyDeletedTaskSummaries)); + } + + // endregion + + // region TaskQuery + public enum TaskQuerySortBy implements QuerySortBy { CLASSIFICATION_KEY(TaskQuery::orderByClassificationKey), CLASSIFICATION_NAME(TaskQuery::orderByClassificationName), @@ -608,4 +734,7 @@ public class TaskController { return super.getSortBy(); } } + + // endregion + } diff --git a/rest/taskana-rest-spring/src/main/java/pro/taskana/task/rest/models/IsReadRepresentationModel.java b/rest/taskana-rest-spring/src/main/java/pro/taskana/task/rest/models/IsReadRepresentationModel.java new file mode 100644 index 000000000..168c0b6fb --- /dev/null +++ b/rest/taskana-rest-spring/src/main/java/pro/taskana/task/rest/models/IsReadRepresentationModel.java @@ -0,0 +1,20 @@ +package pro.taskana.task.rest.models; + +import com.fasterxml.jackson.annotation.JsonProperty; +import java.beans.ConstructorProperties; + +public class IsReadRepresentationModel { + + /** The value to set the Task property isRead. */ + @JsonProperty("is-read") + private final boolean isRead; + + @ConstructorProperties({"is-read"}) + public IsReadRepresentationModel(boolean isRead) { + this.isRead = isRead; + } + + public boolean getIsRead() { + return isRead; + } +} diff --git a/rest/taskana-rest-spring/src/test/java/pro/taskana/task/rest/TaskControllerIntTest.java b/rest/taskana-rest-spring/src/test/java/pro/taskana/task/rest/TaskControllerIntTest.java index fd27aee1c..7932690f0 100644 --- a/rest/taskana-rest-spring/src/test/java/pro/taskana/task/rest/TaskControllerIntTest.java +++ b/rest/taskana-rest-spring/src/test/java/pro/taskana/task/rest/TaskControllerIntTest.java @@ -19,8 +19,11 @@ import java.util.stream.Stream; import javax.sql.DataSource; import org.assertj.core.api.ThrowableAssert.ThrowingCallable; import org.junit.jupiter.api.DynamicTest; +import org.junit.jupiter.api.Nested; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.TestFactory; +import org.junit.jupiter.api.TestInstance; +import org.junit.jupiter.api.TestInstance.Lifecycle; import org.junit.jupiter.api.function.ThrowingConsumer; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Value; @@ -38,6 +41,7 @@ import pro.taskana.common.test.rest.RestHelper; import pro.taskana.common.test.rest.TaskanaSpringBootTest; import pro.taskana.sampledata.SampleDataGenerator; import pro.taskana.task.api.TaskState; +import pro.taskana.task.rest.models.IsReadRepresentationModel; import pro.taskana.task.rest.models.ObjectReferenceRepresentationModel; import pro.taskana.task.rest.models.TaskRepresentationModel; import pro.taskana.task.rest.models.TaskRepresentationModel.CustomAttribute; @@ -80,1595 +84,6 @@ class TaskControllerIntTest { sampleDataGenerator.generateSampleData(); } - @Test - void should_GetAllTasks() { - String url = restHelper.toUrl(RestEndpoints.URL_TASKS); - HttpEntity auth = new HttpEntity<>(RestHelper.generateHeadersForUser("teamlead-1")); - - ResponseEntity response = - TEMPLATE.exchange(url, HttpMethod.GET, auth, TASK_SUMMARY_PAGE_MODEL_TYPE); - - assertThat(response.getBody()).isNotNull(); - assertThat((response.getBody()).getLink(IanaLinkRelations.SELF)).isNotNull(); - assertThat(response.getBody().getContent()).hasSize(60); - } - - @Test - void should_GetAllTasks_For_SpecifiedWorkbasketId() { - String url = - restHelper.toUrl(RestEndpoints.URL_TASKS) - + "?workbasket-id=WBI:100000000000000000000000000000000001"; - HttpEntity auth = new HttpEntity<>(RestHelper.generateHeadersForUser("teamlead-1")); - - ResponseEntity response = - TEMPLATE.exchange(url, HttpMethod.GET, auth, TASK_SUMMARY_PAGE_MODEL_TYPE); - - assertThat(response.getBody()).isNotNull(); - assertThat((response.getBody()).getLink(IanaLinkRelations.SELF)).isNotNull(); - assertThat(response.getBody().getContent()).hasSize(22); - } - - @Test - void should_GetAllTasks_For_SpecifiedWorkbasketIdWithinMultiplePlannedTimeIntervals() { - Instant firstInstant = Instant.now().minus(7, ChronoUnit.DAYS); - Instant secondInstant = Instant.now().minus(10, ChronoUnit.DAYS); - Instant thirdInstant = Instant.now().minus(10, ChronoUnit.DAYS); - Instant fourthInstant = Instant.now().minus(11, ChronoUnit.DAYS); - String url = - restHelper.toUrl(RestEndpoints.URL_TASKS) - + String.format( - "?workbasket-id=WBI:100000000000000000000000000000000001" - + "&planned=%s&planned=" - + "&planned=%s&planned=%s" - + "&planned=&planned=%s" - + "&sort-by=PLANNED", - firstInstant, secondInstant, thirdInstant, fourthInstant); - HttpEntity auth = new HttpEntity<>(RestHelper.generateHeadersForUser("teamlead-1")); - - ResponseEntity response = - TEMPLATE.exchange(url, HttpMethod.GET, auth, TASK_SUMMARY_PAGE_MODEL_TYPE); - - assertThat(response.getBody()).isNotNull(); - assertThat((response.getBody()).getLink(IanaLinkRelations.SELF)).isNotNull(); - assertThat(response.getBody().getContent()).hasSize(6); - } - - @Test - void should_GetCustomIntCorrectly_When_GettingTaskWithCustomIntValues() { - String url = - restHelper.toUrl(RestEndpoints.URL_TASKS_ID, "TKI:000000000000000000000000000000000025"); - HttpEntity auth = new HttpEntity<>(RestHelper.generateHeadersForUser("user-1-2")); - - ResponseEntity response = - TEMPLATE.exchange(url, HttpMethod.GET, auth, TASK_MODEL_TYPE); - - TaskRepresentationModel repModel = response.getBody(); - assertThat(repModel).isNotNull(); - assertThat(repModel.getCustomInt1()).isEqualTo(1); - assertThat(repModel.getCustomInt2()).isEqualTo(2); - assertThat(repModel.getCustomInt3()).isEqualTo(3); - assertThat(repModel.getCustomInt4()).isEqualTo(4); - assertThat(repModel.getCustomInt5()).isEqualTo(5); - assertThat(repModel.getCustomInt6()).isEqualTo(6); - assertThat(repModel.getCustomInt7()).isEqualTo(7); - assertThat(repModel.getCustomInt8()).isEqualTo(8); - } - - @TestFactory - Stream should_GetAllTasks_For_SpecifiedWorkbasketIdAndCustomIntFieldIn() { - List customIntValues = List.of(1, 2, 3, 4, 5, 6, 7, 8); - ThrowingConsumer test = - i -> { - String url = - restHelper.toUrl(RestEndpoints.URL_TASKS) - + String.format( - "?workbasket-id=WBI:100000000000000000000000000000000001" - + "&custom-int-%s=%s", - i, i); - HttpEntity auth = - new HttpEntity<>(RestHelper.generateHeadersForUser("teamlead-1")); - - ResponseEntity response = - TEMPLATE.exchange(url, HttpMethod.GET, auth, TASK_SUMMARY_PAGE_MODEL_TYPE); - - assertThat(response.getBody()).isNotNull(); - assertThat((response.getBody()).getLink(IanaLinkRelations.SELF)).isNotNull(); - assertThat(response.getBody().getContent()).hasSize(22); - }; - - return DynamicTest.stream(customIntValues.iterator(), c -> "customInt" + c, test); - } - - @TestFactory - Stream should_GetAllTasks_For_SpecifiedWorkbasketIdAndCustomIntFieldFrom() { - List customIntValues = List.of(1, 2, 3, 4, 5, 6, 7, 8); - ThrowingConsumer test = - i -> { - String url = - restHelper.toUrl(RestEndpoints.URL_TASKS) - + String.format( - "?workbasket-id=WBI:100000000000000000000000000000000001" - + "&custom-int-%s-from=%s", - i, i); - HttpEntity auth = - new HttpEntity<>(RestHelper.generateHeadersForUser("teamlead-1")); - - ResponseEntity response = - TEMPLATE.exchange(url, HttpMethod.GET, auth, TASK_SUMMARY_PAGE_MODEL_TYPE); - - assertThat(response.getBody()).isNotNull(); - assertThat((response.getBody()).getLink(IanaLinkRelations.SELF)).isNotNull(); - assertThat(response.getBody().getContent()).hasSize(22); - }; - - return DynamicTest.stream(customIntValues.iterator(), c -> "customInt" + c, test); - } - - @TestFactory - Stream should_GetAllTasks_For_SpecifiedWorkbasketIdAndCustomIntFieldFromAndTo() { - List customIntValues = List.of(1, 2, 3, 4, 5, 6, 7, 8); - ThrowingConsumer test = - i -> { - String url = - restHelper.toUrl(RestEndpoints.URL_TASKS) - + String.format( - "?workbasket-id=WBI:100000000000000000000000000000000001" - + "&custom-int-%s-from=-1&custom-int-%s-to=123", - i, i); - HttpEntity auth = - new HttpEntity<>(RestHelper.generateHeadersForUser("teamlead-1")); - - ResponseEntity response = - TEMPLATE.exchange(url, HttpMethod.GET, auth, TASK_SUMMARY_PAGE_MODEL_TYPE); - - assertThat(response.getBody()).isNotNull(); - assertThat((response.getBody()).getLink(IanaLinkRelations.SELF)).isNotNull(); - assertThat(response.getBody().getContent()).hasSize(22); - }; - - return DynamicTest.stream(customIntValues.iterator(), c -> "customInt" + c, test); - } - - @TestFactory - Stream should_GetAllTasks_For_SpecifiedWorkbasketIdAndCustomIntFieldTo() { - List customIntValues = List.of(1, 2, 3, 4, 5, 6, 7, 8); - ThrowingConsumer test = - i -> { - String url = - restHelper.toUrl(RestEndpoints.URL_TASKS) - + String.format( - "?workbasket-id=WBI:100000000000000000000000000000000001" - + "&custom-int-%s-to=%s", - i, i); - HttpEntity auth = - new HttpEntity<>(RestHelper.generateHeadersForUser("teamlead-1")); - - ResponseEntity response = - TEMPLATE.exchange(url, HttpMethod.GET, auth, TASK_SUMMARY_PAGE_MODEL_TYPE); - - assertThat(response.getBody()).isNotNull(); - assertThat((response.getBody()).getLink(IanaLinkRelations.SELF)).isNotNull(); - assertThat(response.getBody().getContent()).hasSize(22); - }; - - return DynamicTest.stream(customIntValues.iterator(), c -> "customInt" + c, test); - } - - @TestFactory - Stream should_GetAllTasks_For_SpecifiedWorkbasketIdAndCustomIntFieldNotIn() { - List customIntValues = List.of(1, 2, 3, 4, 5, 6, 7, 8); - ThrowingConsumer test = - i -> { - String url = - restHelper.toUrl(RestEndpoints.URL_TASKS) - + String.format( - "?workbasket-id=WBI:100000000000000000000000000000000001" - + "&custom-int-%s-not=25", - i); - HttpEntity auth = - new HttpEntity<>(RestHelper.generateHeadersForUser("teamlead-1")); - - ResponseEntity response = - TEMPLATE.exchange(url, HttpMethod.GET, auth, TASK_SUMMARY_PAGE_MODEL_TYPE); - - assertThat(response.getBody()).isNotNull(); - assertThat((response.getBody()).getLink(IanaLinkRelations.SELF)).isNotNull(); - assertThat(response.getBody().getContent()).hasSize(22); - }; - - return DynamicTest.stream(customIntValues.iterator(), c -> "customInt" + c, test); - } - - @TestFactory - Stream - should_ThrowException_For_SpecifiedWorkbasketIdAndCustomIntFieldWithinIncorrectInterval() { - List customIntValues = List.of(1, 2, 3, 4, 5, 6, 7, 8); - ThrowingConsumer test = - i -> { - String url = - restHelper.toUrl(RestEndpoints.URL_TASKS) - + String.format( - "?workbasket-id=WBI:100000000000000000000000000000000001" - + "&custom-int-%s-within=%s" - + "&custom-int-%s-within=23" - + "&custom-int-%s-within=15", - i, i, i, i); - HttpEntity auth = - new HttpEntity<>(RestHelper.generateHeadersForUser("teamlead-1")); - - ThrowingCallable httpCall = - () -> TEMPLATE.exchange(url, HttpMethod.GET, auth, TASK_SUMMARY_PAGE_MODEL_TYPE); - - assertThatThrownBy(httpCall) - .isInstanceOf(HttpStatusCodeException.class) - .hasMessageContaining( - String.format( - "provided length of the property 'custom-int-%s-within' is not dividable by" - + " 2", - i)) - .extracting(HttpStatusCodeException.class::cast) - .extracting(HttpStatusCodeException::getStatusCode) - .isEqualTo(HttpStatus.BAD_REQUEST); - }; - - return DynamicTest.stream(customIntValues.iterator(), c -> "customInt" + c, test); - } - - @TestFactory - Stream - should_ThrowException_For_SpecifiedWorkbasketIdAndCustomIntFieldWithinNullInterval() { - List customIntValues = List.of(1, 2, 3, 4, 5, 6, 7, 8); - ThrowingConsumer test = - i -> { - String url = - restHelper.toUrl(RestEndpoints.URL_TASKS) - + String.format( - "?workbasket-id=WBI:100000000000000000000000000000000001" - + "&custom-int-%s-within=" - + "&custom-int-%s-within=", - i, i, i); - HttpEntity auth = - new HttpEntity<>(RestHelper.generateHeadersForUser("teamlead-1")); - - ThrowingCallable httpCall = - () -> TEMPLATE.exchange(url, HttpMethod.GET, auth, TASK_SUMMARY_PAGE_MODEL_TYPE); - - assertThatThrownBy(httpCall) - .isInstanceOf(HttpStatusCodeException.class) - .hasMessageContaining( - String.format( - "Each interval in 'custom-int-" - + i - + "-within' shouldn't consist of two 'null' values", - i)) - .extracting(HttpStatusCodeException.class::cast) - .extracting(HttpStatusCodeException::getStatusCode) - .isEqualTo(HttpStatus.BAD_REQUEST); - }; - - return DynamicTest.stream(customIntValues.iterator(), c -> "customInt" + c, test); - } - - @TestFactory - Stream should_GetAllTasks_For_SpecifiedWorkbasketIdAndCustomIntFieldWithin() { - List customIntValues = List.of(1, 2, 3, 4, 5, 6, 7, 8); - ThrowingConsumer test = - i -> { - String url = - restHelper.toUrl(RestEndpoints.URL_TASKS) - + String.format( - "?workbasket-id=WBI:100000000000000000000000000000000001" - + "&custom-int-%s-within=%s" - + "&custom-int-%s-within=15", - i, i, i); - HttpEntity auth = - new HttpEntity<>(RestHelper.generateHeadersForUser("teamlead-1")); - - ResponseEntity response = - TEMPLATE.exchange(url, HttpMethod.GET, auth, TASK_SUMMARY_PAGE_MODEL_TYPE); - - assertThat(response.getBody()).isNotNull(); - assertThat((response.getBody()).getLink(IanaLinkRelations.SELF)).isNotNull(); - assertThat(response.getBody().getContent()).hasSize(22); - }; - - return DynamicTest.stream(customIntValues.iterator(), c -> "customInt" + c, test); - } - - @TestFactory - Stream - should_GetAllTasks_For_SpecifiedWorkbasketIdAndCustomIntFieldWithinOpenLowerBound() { - List customIntValues = List.of(1, 2, 3, 4, 5, 6, 7, 8); - ThrowingConsumer test = - i -> { - String url = - restHelper.toUrl(RestEndpoints.URL_TASKS) - + String.format( - "?workbasket-id=WBI:100000000000000000000000000000000001" - + "&custom-int-%s-within=" - + "&custom-int-%s-within=%s", - i, i, i); - HttpEntity auth = - new HttpEntity<>(RestHelper.generateHeadersForUser("teamlead-1")); - - ResponseEntity response = - TEMPLATE.exchange(url, HttpMethod.GET, auth, TASK_SUMMARY_PAGE_MODEL_TYPE); - - assertThat(response.getBody()).isNotNull(); - assertThat((response.getBody()).getLink(IanaLinkRelations.SELF)).isNotNull(); - assertThat(response.getBody().getContent()).hasSize(22); - }; - - return DynamicTest.stream(customIntValues.iterator(), c -> "customInt" + c, test); - } - - @TestFactory - Stream - should_GetAllTasks_For_SpecifiedWorkbasketIdAndCustomIntFieldNotWithinOpenUpperBound() { - List customIntValues = List.of(1, 2, 3, 4, 5, 6, 7, 8); - ThrowingConsumer test = - i -> { - String url = - restHelper.toUrl(RestEndpoints.URL_TASKS) - + String.format( - "?workbasket-id=WBI:100000000000000000000000000000000001" - + "&custom-int-%s-not-within=%s" - + "&custom-int-%s-not-within=", - i, i, i); - HttpEntity auth = - new HttpEntity<>(RestHelper.generateHeadersForUser("teamlead-1")); - - ResponseEntity response = - TEMPLATE.exchange(url, HttpMethod.GET, auth, TASK_SUMMARY_PAGE_MODEL_TYPE); - - assertThat(response.getBody()).isNotNull(); - assertThat((response.getBody()).getLink(IanaLinkRelations.SELF)).isNotNull(); - assertThat(response.getBody().getContent()).isEmpty(); - }; - - return DynamicTest.stream(customIntValues.iterator(), c -> "customInt" + c, test); - } - - @Test - void should_GetAllTasks_For_SpecifiesWorkbasketIdWithinSinglePlannedTimeInterval() { - Instant plannedFromInstant = Instant.now().minus(6, ChronoUnit.DAYS); - Instant plannedToInstant = Instant.now().minus(3, ChronoUnit.DAYS); - String url = - restHelper.toUrl(RestEndpoints.URL_TASKS) - + "?workbasket-id=WBI:100000000000000000000000000000000001" - + "&planned-from=" - + plannedFromInstant - + "&planned-until=" - + plannedToInstant - + "&sort-by=PLANNED"; - HttpEntity auth = new HttpEntity<>(RestHelper.generateHeadersForUser("teamlead-1")); - - ResponseEntity response = - TEMPLATE.exchange(url, HttpMethod.GET, auth, TASK_SUMMARY_PAGE_MODEL_TYPE); - - assertThat(response.getBody()).isNotNull(); - assertThat((response.getBody()).getLink(IanaLinkRelations.SELF)).isNotNull(); - assertThat(response.getBody().getContent()).hasSize(3); - } - - @Test - void should_GetAllTasks_For_SpecifiedWorkbasketIdWithinSingleIndefinitePlannedTimeInterval() { - Instant plannedFromInstant = Instant.now().minus(6, ChronoUnit.DAYS); - String url = - restHelper.toUrl(RestEndpoints.URL_TASKS) - + "?workbasket-id=WBI:100000000000000000000000000000000001" - + "&planned-from=" - + plannedFromInstant - + "&sort-by=PLANNED"; - HttpEntity auth = new HttpEntity<>(RestHelper.generateHeadersForUser("teamlead-1")); - - ResponseEntity response = - TEMPLATE.exchange(url, HttpMethod.GET, auth, TASK_SUMMARY_PAGE_MODEL_TYPE); - - assertThat(response.getBody()).isNotNull(); - assertThat((response.getBody()).getLink(IanaLinkRelations.SELF)).isNotNull(); - assertThat(response.getBody().getContent()).hasSize(4); - } - - @Test - void should_ThrowException_When_GettingTasksByWorkbasketIdWithInvalidPlannedParamsCombination() { - String url = - restHelper.toUrl(RestEndpoints.URL_TASKS) - + "?workbasket-id=WBI:100000000000000000000000000000000001" - + "&planned=2020-01-22T09:44:47.453Z,," - + "2020-01-19T07:44:47.453Z,2020-01-19T19:44:47.453Z," - + ",2020-01-18T09:44:47.453Z" - + "&planned-from=2020-01-19T07:44:47.453Z" - + "&sort-by=planned"; - HttpEntity auth = new HttpEntity<>(RestHelper.generateHeadersForUser("teamlead-1")); - - ThrowingCallable httpCall = - () -> TEMPLATE.exchange(url, HttpMethod.GET, auth, TASK_SUMMARY_PAGE_MODEL_TYPE); - - assertThatThrownBy(httpCall) - .isInstanceOf(HttpStatusCodeException.class) - .extracting(HttpStatusCodeException.class::cast) - .extracting(HttpStatusCodeException::getStatusCode) - .isEqualTo(HttpStatus.BAD_REQUEST); - } - - @Test - void should_GetAllTasks_For_SpecifiedWorkbasketIdWithinMultipleDueTimeIntervals() { - Instant firstInstant = Instant.now().minus(7, ChronoUnit.DAYS); - Instant secondInstant = Instant.now().minus(10, ChronoUnit.DAYS); - Instant thirdInstant = Instant.now().minus(10, ChronoUnit.DAYS); - Instant fourthInstant = Instant.now().minus(11, ChronoUnit.DAYS); - String url = - restHelper.toUrl(RestEndpoints.URL_TASKS) - + String.format( - "?workbasket-id=WBI:100000000000000000000000000000000001" - + "&due=%s&due=" - + "&due=%s&due=%s" - + "&due=&due=%s" - + "&sort-by=DUE", - firstInstant, secondInstant, thirdInstant, fourthInstant); - HttpEntity auth = new HttpEntity<>(RestHelper.generateHeadersForUser("teamlead-1")); - - ResponseEntity response = - TEMPLATE.exchange(url, HttpMethod.GET, auth, TASK_SUMMARY_PAGE_MODEL_TYPE); - - assertThat(response.getBody()).isNotNull(); - assertThat((response.getBody()).getLink(IanaLinkRelations.SELF)).isNotNull(); - assertThat(response.getBody().getContent()).hasSize(22); - } - - @Test - void should_ReturnAllTasks_For_ProvidedPrimaryObjectReference() throws Exception { - String url = - restHelper.toUrl(RestEndpoints.URL_TASKS) - + "?por=" - + URLEncoder.encode("{\"systemInstance\":\"MyInstance1\",\"type\":\"MyType1\"}", UTF_8); - HttpEntity auth = new HttpEntity<>(RestHelper.generateHeadersForUser("teamlead-1")); - ResponseEntity response = - TEMPLATE.exchange(url, HttpMethod.GET, auth, TASK_SUMMARY_PAGE_MODEL_TYPE); - assertThat(response.getBody()).isNotNull(); - assertThat(response.getStatusCode()).isEqualTo(HttpStatus.OK); - assertThat((response.getBody()).getLink(IanaLinkRelations.SELF)).isNotNull(); - assertThat(response.getBody().getContent()).hasSize(4); - } - - @Test - void should_ReturnAllTasks_For_ProvidedSecondaryObjectReferenceByTypeAndValue() throws Exception { - String url = - restHelper.toUrl(RestEndpoints.URL_TASKS) - + "?sor=" - + URLEncoder.encode("{\"type\":\"Type2\",\"value\":\"Value2\"}", UTF_8); - HttpEntity auth = new HttpEntity<>(RestHelper.generateHeadersForUser("teamlead-1")); - ResponseEntity response = - TEMPLATE.exchange(url, HttpMethod.GET, auth, TASK_SUMMARY_PAGE_MODEL_TYPE); - assertThat(response.getBody()).isNotNull(); - assertThat(response.getStatusCode()).isEqualTo(HttpStatus.OK); - assertThat((response.getBody()).getLink(IanaLinkRelations.SELF)).isNotNull(); - assertThat(response.getBody().getContent()).hasSize(2); - } - - @Test - void should_ReturnAllTasks_For_ProvidedSecondaryObjectReferenceByCompany() throws Exception { - String url = - restHelper.toUrl(RestEndpoints.URL_TASKS) - + "?sor=" - + URLEncoder.encode("{\"company\":\"Company3\"}", UTF_8); - HttpEntity auth = new HttpEntity<>(RestHelper.generateHeadersForUser("teamlead-1")); - ResponseEntity response = - TEMPLATE.exchange(url, HttpMethod.GET, auth, TASK_SUMMARY_PAGE_MODEL_TYPE); - assertThat(response.getBody()).isNotNull(); - assertThat(response.getStatusCode()).isEqualTo(HttpStatus.OK); - assertThat((response.getBody()).getLink(IanaLinkRelations.SELF)).isNotNull(); - assertThat(response.getBody().getContent()).hasSize(1); - } - - @Test - void should_ReturnNoTasks_For_ProvidedNonexistentSecondaryObjectReference() throws Exception { - String url = - restHelper.toUrl(RestEndpoints.URL_TASKS) - + "?sor=" - + URLEncoder.encode("{\"type\":\"Type2\",\"value\":\"Quatsch\"}", UTF_8); - HttpEntity auth = new HttpEntity<>(RestHelper.generateHeadersForUser("teamlead-1")); - ResponseEntity response = - TEMPLATE.exchange(url, HttpMethod.GET, auth, TASK_SUMMARY_PAGE_MODEL_TYPE); - assertThat(response.getBody()).isNotNull(); - assertThat(response.getStatusCode()).isEqualTo(HttpStatus.OK); - assertThat((response.getBody()).getLink(IanaLinkRelations.SELF)).isNotNull(); - assertThat(response.getBody().getContent()).isEmpty(); - } - - @Test - void should_ReturnAllTasksByWildcardSearch_For_ProvidedSearchValue() { - String url = - restHelper.toUrl(RestEndpoints.URL_TASKS) - + "?wildcard-search-value=99" - + "&wildcard-search-fields=NAME" - + "&wildcard-search-fields=CUSTOM_3" - + "&wildcard-search-fields=CUSTOM_4"; - HttpEntity auth = new HttpEntity<>(RestHelper.generateHeadersForUser("admin")); - - ResponseEntity response = - TEMPLATE.exchange(url, HttpMethod.GET, auth, TASK_SUMMARY_PAGE_MODEL_TYPE); - - assertThat(response.getBody()).isNotNull(); - assertThat((response.getBody()).getLink(IanaLinkRelations.SELF)).isNotNull(); - assertThat(response.getBody().getContent()).hasSize(4); - } - - @TestFactory - Stream should_ThrowException_When_ProvidingInvalidFormatForCustomAttributes() { - Iterator iterator = - Arrays.asList( - CustomAttribute.of(null, "value"), - CustomAttribute.of("", "value"), - CustomAttribute.of("key", null)) - .iterator(); - - ThrowingConsumer test = - customAttribute -> { - TaskRepresentationModel taskRepresentationModel = getTaskResourceSample(); - taskRepresentationModel.setCustomAttributes(List.of(customAttribute)); - String url = restHelper.toUrl(RestEndpoints.URL_TASKS); - HttpEntity auth = - new HttpEntity<>( - taskRepresentationModel, RestHelper.generateHeadersForUser("teamlead-1")); - - ThrowingCallable httpCall = - () -> TEMPLATE.exchange(url, HttpMethod.POST, auth, TASK_MODEL_TYPE); - assertThatThrownBy(httpCall) - .isInstanceOf(HttpStatusCodeException.class) - .hasMessageContaining("Format of custom attributes is not valid") - .extracting(HttpStatusCodeException.class::cast) - .extracting(HttpStatusCodeException::getStatusCode) - .isEqualTo(HttpStatus.BAD_REQUEST); - }; - - return DynamicTest.stream(iterator, c -> "customAttribute: '" + c.getKey() + "'", test); - } - - @Test - void should_DeleteAllTasks_For_ProvidedParams() { - String url = - restHelper.toUrl(RestEndpoints.URL_TASKS) - + "?task-id=TKI:000000000000000000000000000000000036" - + "&task-id=TKI:000000000000000000000000000000000037" - + "&task-id=TKI:000000000000000000000000000000000038" - + "&custom14=abc"; - HttpEntity auth = new HttpEntity<>(RestHelper.generateHeadersForUser("admin")); - - ResponseEntity response = - TEMPLATE.exchange(url, HttpMethod.DELETE, auth, TASK_SUMMARY_COLLECTION_MODEL_TYPE); - - assertThat(response.getBody()).isNotNull(); - assertThat((response.getBody()).getLink(IanaLinkRelations.SELF)).isNotNull(); - assertThat(response.getBody().getContent()).hasSize(3); - } - - @Test - void should_ThrowException_When_ProvidingInvalidWildcardSearchParameters() { - String url = restHelper.toUrl(RestEndpoints.URL_TASKS) + "?wildcard-search-value=%rt%"; - HttpEntity auth = new HttpEntity<>(RestHelper.generateHeadersForUser("teamlead-1")); - - ThrowingCallable httpCall = - () -> TEMPLATE.exchange(url, HttpMethod.GET, auth, TASK_SUMMARY_PAGE_MODEL_TYPE); - - assertThatThrownBy(httpCall) - .isInstanceOf(HttpStatusCodeException.class) - .extracting(HttpStatusCodeException.class::cast) - .extracting(HttpStatusCodeException::getStatusCode) - .isEqualTo(HttpStatus.BAD_REQUEST); - - String url2 = - restHelper.toUrl(RestEndpoints.URL_TASKS) - + "?wildcard-search-fields=NAME,CUSTOM_3,CUSTOM_4"; - ThrowingCallable httpCall2 = - () -> TEMPLATE.exchange(url2, HttpMethod.GET, auth, TASK_SUMMARY_PAGE_MODEL_TYPE); - - assertThatThrownBy(httpCall2) - .isInstanceOf(HttpStatusCodeException.class) - .extracting(HttpStatusCodeException.class::cast) - .extracting(HttpStatusCodeException::getStatusCode) - .isEqualTo(HttpStatus.BAD_REQUEST); - } - - @Test - void should_GetAllTasks_For_SpecifiedWorkbasketIdWithinSingleDueTimeInterval() { - Instant dueFromInstant = Instant.now().minus(8, ChronoUnit.DAYS); - Instant dueToInstant = Instant.now().minus(3, ChronoUnit.DAYS); - String url = - restHelper.toUrl(RestEndpoints.URL_TASKS) - + "?workbasket-id=WBI:100000000000000000000000000000000001" - + "&due-from=" - + dueFromInstant - + "&due-until=" - + dueToInstant - + "&sort-by=DUE"; - HttpEntity auth = new HttpEntity<>(RestHelper.generateHeadersForUser("teamlead-1")); - - ResponseEntity response = - TEMPLATE.exchange(url, HttpMethod.GET, auth, TASK_SUMMARY_PAGE_MODEL_TYPE); - - assertThat(response.getBody()).isNotNull(); - assertThat((response.getBody()).getLink(IanaLinkRelations.SELF)).isNotNull(); - assertThat(response.getBody().getContent()).hasSize(1); - } - - @Test - void should_GetAllTasks_For_SpecifiedWorkbasketIdWithinSingleIndefiniteDueTimeInterval() { - Instant dueToInstant = Instant.now().minus(1, ChronoUnit.DAYS); - String url = - restHelper.toUrl(RestEndpoints.URL_TASKS) - + "?workbasket-id=WBI:100000000000000000000000000000000001" - + "&due-until=" - + dueToInstant - + "&sort-by=DUE"; - HttpEntity auth = new HttpEntity<>(RestHelper.generateHeadersForUser("teamlead-1")); - - ResponseEntity response = - TEMPLATE.exchange(url, HttpMethod.GET, auth, TASK_SUMMARY_PAGE_MODEL_TYPE); - - assertThat(response.getBody()).isNotNull(); - assertThat((response.getBody()).getLink(IanaLinkRelations.SELF)).isNotNull(); - assertThat(response.getBody().getContent()).hasSize(6); - } - - @Test - void should_GetAllTasks_For_WorkbasketIdWithInvalidDueParamsCombination() { - String url = - restHelper.toUrl(RestEndpoints.URL_TASKS) - + "?workbasket-id=WBI:100000000000000000000000000000000001" - + "&due=2020-01-22T09:44:47.453Z,," - + "2020-01-19T07:44:47.453Z,2020-01-19T19:44:47.453Z," - + ",2020-01-18T09:44:47.453Z" - + "&due-from=2020-01-19T07:44:47.453Z" - + "&sort-by=planned"; - HttpEntity auth = new HttpEntity<>(RestHelper.generateHeadersForUser("teamlead-1")); - - ThrowingCallable httpCall = - () -> { - TEMPLATE.exchange(url, HttpMethod.GET, auth, TASK_SUMMARY_PAGE_MODEL_TYPE); - }; - - assertThatThrownBy(httpCall) - .isInstanceOf(HttpStatusCodeException.class) - .extracting(HttpStatusCodeException.class::cast) - .extracting(HttpStatusCodeException::getStatusCode) - .isEqualTo(HttpStatus.BAD_REQUEST); - } - - @Test - void should_GetAllTasks_For_SpecifiedWorkbasketKeyAndDomain() { - String url = - restHelper.toUrl(RestEndpoints.URL_TASKS) + "?workbasket-key=USER-1-2&domain=DOMAIN_A"; - HttpEntity auth = new HttpEntity<>(RestHelper.generateHeadersForUser("user-1-2")); - - ResponseEntity response = - TEMPLATE.exchange(url, HttpMethod.GET, auth, TASK_SUMMARY_PAGE_MODEL_TYPE); - - assertThat(response.getBody()).isNotNull(); - assertThat((response.getBody()).getLink(IanaLinkRelations.SELF)).isNotNull(); - assertThat(response.getBody().getContent()).hasSize(21); - } - - @Test - void should_GetAllTasks_For_SpecifiedExternalId() { - String url = - restHelper.toUrl(RestEndpoints.URL_TASKS) - + "?external-id=ETI:000000000000000000000000000000000003" - + "&external-id=ETI:000000000000000000000000000000000004"; - HttpEntity auth = new HttpEntity<>(RestHelper.generateHeadersForUser("teamlead-1")); - - ResponseEntity response = - TEMPLATE.exchange(url, HttpMethod.GET, auth, TASK_SUMMARY_PAGE_MODEL_TYPE); - - assertThat(response.getBody()).isNotNull(); - assertThat((response.getBody()).getLink(IanaLinkRelations.SELF)).isNotNull(); - assertThat(response.getBody().getContent()).hasSize(2); - } - - @Test - void should_ThrowException_When_KeyIsSetButDomainIsMissing() { - String url = restHelper.toUrl(RestEndpoints.URL_TASKS) + "?workbasket-key=USER-1-2"; - HttpEntity auth = new HttpEntity<>(RestHelper.generateHeadersForUser("user-1-2")); - - ThrowingCallable httpCall = - () -> TEMPLATE.exchange(url, HttpMethod.GET, auth, TASK_SUMMARY_PAGE_MODEL_TYPE); - - assertThatThrownBy(httpCall) - .isInstanceOf(HttpStatusCodeException.class) - .extracting(HttpStatusCodeException.class::cast) - .extracting(HttpStatusCodeException::getStatusCode) - .isEqualTo(HttpStatus.BAD_REQUEST); - } - - @Test - void should_GetAllTasksWithAdminRole() { - String url = restHelper.toUrl(RestEndpoints.URL_TASKS); - HttpEntity auth = new HttpEntity<>(RestHelper.generateHeadersForUser("admin")); - - ResponseEntity response = - TEMPLATE.exchange(url, HttpMethod.GET, auth, TASK_SUMMARY_PAGE_MODEL_TYPE); - - assertThat(response.getBody()).isNotNull(); - assertThat((response.getBody()).getLink(IanaLinkRelations.SELF)).isNotNull(); - assertThat(response.getBody().getContent()).hasSize(91); - } - - @Test - void should_KeepFiltersInTheLinkOfTheResponse_When_GettingTasks() { - String url = - restHelper.toUrl(RestEndpoints.URL_TASKS) - + "?por-type=VNR&por-value=22334455&sort-by=POR_VALUE&order=DESCENDING"; - HttpEntity auth = new HttpEntity<>(RestHelper.generateHeadersForUser("teamlead-1")); - - ResponseEntity response = - TEMPLATE.exchange(url, HttpMethod.GET, auth, TASK_SUMMARY_PAGE_MODEL_TYPE); - - assertThat(response.getBody()).isNotNull(); - assertThat((response.getBody()).getLink(IanaLinkRelations.SELF)).isNotNull(); - assertThat(response.getBody().getRequiredLink(IanaLinkRelations.SELF).getHref()) - .endsWith( - "/api/v1/tasks?por-type=VNR&por-value=22334455" - + "&sort-by=POR_VALUE&order=DESCENDING"); - } - - @Test - void should_GetAllTasks_For_GettingLastTaskSummaryPageSortedByPorValue() { - String url = - restHelper.toUrl(RestEndpoints.URL_TASKS) - + "?state=READY&state=CLAIMED&sort-by=POR_VALUE" - + "&order=DESCENDING&page-size=5&page=16"; - HttpEntity auth = new HttpEntity<>(RestHelper.generateHeadersForUser("admin")); - - ResponseEntity response = - TEMPLATE.exchange(url, HttpMethod.GET, auth, TASK_SUMMARY_PAGE_MODEL_TYPE); - - assertThat(response.getBody()).isNotNull(); - assertThat((response.getBody()).getContent()).hasSize(5); - assertThat(response.getBody().getRequiredLink(IanaLinkRelations.LAST).getHref()) - .contains("page=16"); - assertThat(response.getBody().getContent().iterator().next().getTaskId()) - .isEqualTo("TKI:000000000000000000000000000000000064"); - assertThat(response.getBody().getLink(IanaLinkRelations.SELF)).isNotNull(); - assertThat(response.getBody().getRequiredLink(IanaLinkRelations.SELF).getHref()) - .endsWith( - "/api/v1/tasks?state=READY&state=CLAIMED" - + "&sort-by=POR_VALUE&order=DESCENDING&page-size=5&page=16"); - assertThat(response.getBody().getLink(IanaLinkRelations.FIRST)).isNotNull(); - assertThat(response.getBody().getLink(IanaLinkRelations.LAST)).isNotNull(); - assertThat(response.getBody().getLink(IanaLinkRelations.PREV)).isNotNull(); - } - - @Test - void should_SortByOwnerLongName() { - String url = - restHelper.toUrl(RestEndpoints.URL_TASKS) - + "?sort-by=OWNER_LONG_NAME" - + "&order=DESCENDING"; - HttpEntity auth = new HttpEntity<>(RestHelper.generateHeadersForUser("admin")); - - ResponseEntity response = - TEMPLATE.exchange(url, HttpMethod.GET, auth, TASK_SUMMARY_PAGE_MODEL_TYPE); - - assertThat(response.getBody()).isNotNull(); - assertThat((response.getBody()).getLink(IanaLinkRelations.SELF)).isNotNull(); - } - - @Test - void testGetLastPageSortedByDueWithHiddenTasksRemovedFromResult() { - resetDb(); - // required because - // ClassificationControllerIntTest.testGetQueryByPorSecondPageSortedByType changes - // tasks and this test depends on the tasks as they are in sampledata - String url = restHelper.toUrl(RestEndpoints.URL_TASKS) + "?sort-by=DUE&order=DESCENDING"; - HttpEntity auth = new HttpEntity<>(RestHelper.generateHeadersForUser("teamlead-1")); - - ResponseEntity response = - TEMPLATE.exchange(url, HttpMethod.GET, auth, TASK_SUMMARY_PAGE_MODEL_TYPE); - - assertThat(response.getBody()).isNotNull(); - assertThat((response.getBody()).getContent()).hasSize(60); - - String url2 = - restHelper.toUrl(RestEndpoints.URL_TASKS) - + "?sort-by=DUE&order=DESCENDING&page-size=5&page=5"; - response = TEMPLATE.exchange(url2, HttpMethod.GET, auth, TASK_SUMMARY_PAGE_MODEL_TYPE); - - assertThat(response.getBody()).isNotNull(); - assertThat((response.getBody()).getContent()).hasSize(5); - assertThat(response.getBody().getRequiredLink(IanaLinkRelations.LAST).getHref()) - .contains("page=12"); - assertThat(response.getBody().getContent().iterator().next().getTaskId()) - .isEqualTo("TKI:000000000000000000000000000000000073"); - assertThat(response.getBody().getLink(IanaLinkRelations.SELF)).isNotNull(); - assertThat(response.getBody().getRequiredLink(IanaLinkRelations.SELF).getHref()) - .endsWith("/api/v1/tasks?sort-by=DUE&order=DESCENDING&page-size=5&page=5"); - assertThat(response.getBody().getLink(IanaLinkRelations.FIRST)).isNotNull(); - assertThat(response.getBody().getLink(IanaLinkRelations.LAST)).isNotNull(); - assertThat(response.getBody().getLink(IanaLinkRelations.PREV)).isNotNull(); - } - - @Test - void should_GetAllTasks_For_GettingSecondPageFilteredByPorAttributesSortedByType() { - resetDb(); // required because - // ClassificationControllerIntTest.testGetQueryByPorSecondPageSortedByType changes - // tasks and this test depends on the tasks as they are in sampledata - String url = - restHelper.toUrl(RestEndpoints.URL_TASKS) - + "?por-company=00&por-system=PASystem&por-instance=00&" - + "por-type=VNR&por-value=22334455&sort-by=POR_TYPE&" - + "order=ASCENDING&page-size=5&page=2"; - HttpEntity auth = new HttpEntity<>(RestHelper.generateHeadersForUser("teamlead-1")); - - ResponseEntity response = - TEMPLATE.exchange(url, HttpMethod.GET, auth, TASK_SUMMARY_PAGE_MODEL_TYPE); - - assertThat(response.getBody()).isNotNull(); - assertThat(response.getBody().getContent()) - .extracting(TaskSummaryRepresentationModel::getTaskId) - .containsExactlyInAnyOrder("TKI:000000000000000000000000000000000013"); - assertThat(response.getBody().getLink(IanaLinkRelations.SELF)).isNotNull(); - assertThat(response.getBody().getRequiredLink(IanaLinkRelations.SELF).getHref()) - .endsWith( - "/api/v1/tasks?por-company=00&por-system=PASystem&por-instance=00&" - + "por-type=VNR&por-value=22334455&sort-by=POR_TYPE&order=ASCENDING&" - + "page-size=5&page=2"); - assertThat(response.getBody().getLink(IanaLinkRelations.FIRST)).isNotNull(); - assertThat(response.getBody().getLink(IanaLinkRelations.LAST)).isNotNull(); - assertThat(response.getBody().getLink(IanaLinkRelations.PREV)).isNotNull(); - } - - @Test - void should_NotGetEmptyAttachmentList_When_GettingTaskWithAttachment() { - String url = - restHelper.toUrl(RestEndpoints.URL_TASKS_ID, "TKI:000000000000000000000000000000000002"); - HttpEntity auth = new HttpEntity<>(RestHelper.generateHeadersForUser("admin")); - - ResponseEntity response = - TEMPLATE.exchange(url, HttpMethod.GET, auth, TASK_MODEL_TYPE); - - TaskRepresentationModel repModel = response.getBody(); - assertThat(repModel).isNotNull(); - assertThat(repModel.getAttachments()).isNotEmpty(); - } - - @Test - void should_ReturnFilteredTasks_When_GettingTaskWithoutAttachments() { - String url = restHelper.toUrl(RestEndpoints.URL_TASKS) + "?without-attachment=true"; - HttpEntity auth = new HttpEntity<>(RestHelper.generateHeadersForUser("admin")); - - ResponseEntity response = - TEMPLATE.exchange(url, HttpMethod.GET, auth, TASK_SUMMARY_PAGE_MODEL_TYPE); - - assertThat(response.getBody()).isNotNull(); - assertThat((response.getBody()).getLink(IanaLinkRelations.SELF)).isNotNull(); - assertThat(response.getBody().getContent()).hasSize(84); - } - - @Test - void should_ThrowException_When_WithoutAttachmentsIsSetToFalse() { - String url = restHelper.toUrl(RestEndpoints.URL_TASKS) + "?without-attachment=false"; - HttpEntity auth = new HttpEntity<>(RestHelper.generateHeadersForUser("admin")); - - assertThatThrownBy( - () -> TEMPLATE.exchange(url, HttpMethod.GET, auth, TASK_SUMMARY_PAGE_MODEL_TYPE)) - .isInstanceOf(HttpStatusCodeException.class) - .hasMessageContaining("provided value of the property 'without-attachment' must be 'true'"); - } - - @Test - void should_NotGetEmptyObjectReferencesList_When_GettingTaskWithObjectReferences() { - String url = - restHelper.toUrl(RestEndpoints.URL_TASKS_ID, "TKI:000000000000000000000000000000000001"); - HttpEntity auth = new HttpEntity<>(RestHelper.generateHeadersForUser("admin")); - - ResponseEntity response = - TEMPLATE.exchange(url, HttpMethod.GET, auth, TASK_MODEL_TYPE); - - TaskRepresentationModel repModel = response.getBody(); - assertThat(repModel).isNotNull(); - assertThat(repModel.getSecondaryObjectReferences()).isNotEmpty(); - } - - @Test - void should_ReturnFilteredTasks_When_GettingTasksBySecondaryObjectReferenceValue() { - String url = restHelper.toUrl(RestEndpoints.URL_TASKS) + "?sor-value=Value2"; - HttpEntity auth = new HttpEntity<>(RestHelper.generateHeadersForUser("teamlead-1")); - - ResponseEntity response = - TEMPLATE.exchange(url, HttpMethod.GET, auth, TASK_SUMMARY_PAGE_MODEL_TYPE); - - assertThat(response.getBody()).isNotNull(); - assertThat((response.getBody()).getLink(IanaLinkRelations.SELF)).isNotNull(); - assertThat(response.getBody().getContent()).hasSize(3); - } - - @Test - void should_ReturnFilteredTasks_When_GettingTasksBySecondaryObjectReferenceTypeLike() { - String url = restHelper.toUrl(RestEndpoints.URL_TASKS) + "?sor-type-like=Type"; - HttpEntity auth = new HttpEntity<>(RestHelper.generateHeadersForUser("teamlead-1")); - - ResponseEntity response = - TEMPLATE.exchange(url, HttpMethod.GET, auth, TASK_SUMMARY_PAGE_MODEL_TYPE); - - assertThat(response.getBody()).isNotNull(); - assertThat((response.getBody()).getLink(IanaLinkRelations.SELF)).isNotNull(); - assertThat(response.getBody().getContent()).hasSize(3); - } - - @Test - void should_ReturnFilteredTasks_When_GettingTasksBySecondaryObjectReferenceValueAndCompany() { - String url = - restHelper.toUrl(RestEndpoints.URL_TASKS) + "?sor-value=Value2&&sor-company=Company1"; - HttpEntity auth = new HttpEntity<>(RestHelper.generateHeadersForUser("teamlead-1")); - - ResponseEntity response = - TEMPLATE.exchange(url, HttpMethod.GET, auth, TASK_SUMMARY_PAGE_MODEL_TYPE); - - assertThat(response.getBody()).isNotNull(); - assertThat((response.getBody()).getLink(IanaLinkRelations.SELF)).isNotNull(); - assertThat(response.getBody().getContent()).hasSize(1); - } - - @Test - void should_CreateAndDeleteTaskWithSecondaryObjectReferences_When_SpecifyingObjectReferences() { - TaskRepresentationModel taskRepresentationModel = getTaskResourceSample(); - ObjectReferenceRepresentationModel obj0 = getSampleSecondaryObjectReference("0"); - obj0.setTaskId(taskRepresentationModel.getTaskId()); - ObjectReferenceRepresentationModel obj1 = getSampleSecondaryObjectReference("1"); - obj1.setTaskId(taskRepresentationModel.getTaskId()); - List secondaryObjectReferences = List.of(obj0, obj1); - taskRepresentationModel.setSecondaryObjectReferences(secondaryObjectReferences); - - String url = restHelper.toUrl(RestEndpoints.URL_TASKS); - HttpEntity auth = - new HttpEntity<>(taskRepresentationModel, RestHelper.generateHeadersForUser("teamlead-1")); - - ResponseEntity responseCreate = - TEMPLATE.exchange(url, HttpMethod.POST, auth, TASK_MODEL_TYPE); - assertThat(responseCreate.getStatusCode()).isEqualTo(HttpStatus.CREATED); - assertThat(responseCreate.getBody()).isNotNull(); - String taskIdOfCreatedTask = responseCreate.getBody().getTaskId(); - - String url2 = restHelper.toUrl(RestEndpoints.URL_TASKS_ID, taskIdOfCreatedTask); - HttpEntity auth2 = new HttpEntity<>(RestHelper.generateHeadersForUser("admin")); - - ResponseEntity responseDeleted = - TEMPLATE.exchange( - url2, HttpMethod.DELETE, auth2, ParameterizedTypeReference.forType(Void.class)); - assertThat(responseDeleted.getStatusCode()).isEqualTo(HttpStatus.NO_CONTENT); - } - - @Test - void should_CreateAndDeleteTaskWithManualPriority_When_SpecifyingManualPriority() { - TaskRepresentationModel taskRepresentationModel = getTaskResourceSample(); - taskRepresentationModel.setManualPriority(7); - - String url = restHelper.toUrl(RestEndpoints.URL_TASKS); - HttpEntity auth = - new HttpEntity<>(taskRepresentationModel, RestHelper.generateHeadersForUser("teamlead-1")); - - ResponseEntity responseCreate = - TEMPLATE.exchange(url, HttpMethod.POST, auth, TASK_MODEL_TYPE); - assertThat(responseCreate.getStatusCode()).isEqualTo(HttpStatus.CREATED); - assertThat(responseCreate.getBody()).isNotNull(); - assertThat(responseCreate.getBody().getPriority()) - .isEqualTo((responseCreate.getBody().getManualPriority())) - .isEqualTo(7); - - String taskIdOfCreatedTask = responseCreate.getBody().getTaskId(); - String url2 = restHelper.toUrl(RestEndpoints.URL_TASKS_ID, taskIdOfCreatedTask); - HttpEntity auth2 = new HttpEntity<>(RestHelper.generateHeadersForUser("admin")); - - ResponseEntity responseDeleted = - TEMPLATE.exchange( - url2, HttpMethod.DELETE, auth2, ParameterizedTypeReference.forType(Void.class)); - assertThat(responseDeleted.getStatusCode()).isEqualTo(HttpStatus.NO_CONTENT); - } - - @Test - void should_CreateTaskWithCorrectPriorityAndThenDeleteIt_When_NotSpecifyingManualPriority() { - TaskRepresentationModel taskRepresentationModel = getTaskResourceSample(); - - String url = restHelper.toUrl(RestEndpoints.URL_TASKS); - HttpEntity auth = - new HttpEntity<>(taskRepresentationModel, RestHelper.generateHeadersForUser("teamlead-1")); - - ResponseEntity responseCreate = - TEMPLATE.exchange(url, HttpMethod.POST, auth, TASK_MODEL_TYPE); - assertThat(responseCreate.getStatusCode()).isEqualTo(HttpStatus.CREATED); - assertThat(responseCreate.getBody()).isNotNull(); - // The classification of taskRepresentationModel with the key "L11010" has priority=1 - assertThat(responseCreate.getBody().getPriority()).isEqualTo(1); - assertThat(responseCreate.getBody().getManualPriority()).isEqualTo(-1); - - String taskIdOfCreatedTask = responseCreate.getBody().getTaskId(); - String url2 = restHelper.toUrl(RestEndpoints.URL_TASKS_ID, taskIdOfCreatedTask); - HttpEntity auth2 = new HttpEntity<>(RestHelper.generateHeadersForUser("admin")); - - ResponseEntity responseDeleted = - TEMPLATE.exchange( - url2, HttpMethod.DELETE, auth2, ParameterizedTypeReference.forType(Void.class)); - assertThat(responseDeleted.getStatusCode()).isEqualTo(HttpStatus.NO_CONTENT); - } - - @Test - void should_GetPriorityCorrectly_When_GettingTaskWithManualPriority() { - String url = - restHelper.toUrl(RestEndpoints.URL_TASKS_ID, "TKI:000000000000000000070000000000000079"); - HttpEntity auth = new HttpEntity<>(RestHelper.generateHeadersForUser("teamlead-1")); - - ResponseEntity response = - TEMPLATE.exchange(url, HttpMethod.GET, auth, TASK_MODEL_TYPE); - - assertThat(response.getBody()).isNotNull(); - assertThat(response.getBody().getPriority()) - .isEqualTo((response.getBody().getManualPriority())) - .isEqualTo(56); - } - - @Test - void should_ReturnReceivedDate_When_GettingTask() { - String url = - restHelper.toUrl(RestEndpoints.URL_TASKS_ID, "TKI:000000000000000000000000000000000024"); - HttpEntity auth = new HttpEntity<>(RestHelper.generateHeadersForUser("admin")); - - ResponseEntity response = - TEMPLATE.exchange(url, HttpMethod.GET, auth, TASK_MODEL_TYPE); - - assertThat(response.getBody()) - .isNotNull() - .extracting(TaskSummaryRepresentationModel::getReceived) - .isNotNull(); - } - - @Test - void should_ChangeValueOfReceived_When_UpdatingTask() { - String url = - restHelper.toUrl(RestEndpoints.URL_TASKS_ID, "TKI:100000000000000000000000000000000000"); - HttpEntity httpEntityWithoutBody = - new HttpEntity<>(RestHelper.generateHeadersForUser("teamlead-1")); - - ResponseEntity responseGet = - TEMPLATE.exchange(url, HttpMethod.GET, httpEntityWithoutBody, TASK_MODEL_TYPE); - - final TaskRepresentationModel originalTask = responseGet.getBody(); - Instant expectedReceived = Instant.parse("2019-09-13T08:44:17.588Z"); - originalTask.setReceived(expectedReceived); - HttpEntity httpEntity = - new HttpEntity<>(originalTask, RestHelper.generateHeadersForUser("teamlead-1")); - - ResponseEntity responseUpdate = - TEMPLATE.exchange(url, HttpMethod.PUT, httpEntity, TASK_MODEL_TYPE); - - TaskRepresentationModel updatedTask = responseUpdate.getBody(); - assertThat(updatedTask).isNotNull(); - assertThat(updatedTask.getReceived()).isEqualTo(expectedReceived); - } - - @Test - void should_ChangeValueOfModified_When_UpdatingTask() { - String url = - restHelper.toUrl(RestEndpoints.URL_TASKS_ID, "TKI:100000000000000000000000000000000000"); - HttpEntity auth = new HttpEntity<>(RestHelper.generateHeadersForUser("teamlead-1")); - - ResponseEntity responseGet = - TEMPLATE.exchange(url, HttpMethod.GET, auth, TASK_MODEL_TYPE); - - final TaskRepresentationModel originalTask = responseGet.getBody(); - HttpEntity auth2 = - new HttpEntity<>(originalTask, RestHelper.generateHeadersForUser("teamlead-1")); - - ResponseEntity responseUpdate = - TEMPLATE.exchange(url, HttpMethod.PUT, auth2, TASK_MODEL_TYPE); - - TaskRepresentationModel updatedTask = responseUpdate.getBody(); - assertThat(originalTask).isNotNull(); - assertThat(updatedTask).isNotNull(); - assertThat(originalTask.getModified()).isBefore(updatedTask.getModified()); - } - - @Test - void should_CreateAndDeleteTask() { - TaskRepresentationModel taskRepresentationModel = getTaskResourceSample(); - String url = restHelper.toUrl(RestEndpoints.URL_TASKS); - HttpEntity auth = - new HttpEntity<>(taskRepresentationModel, RestHelper.generateHeadersForUser("teamlead-1")); - - ResponseEntity responseCreate = - TEMPLATE.exchange(url, HttpMethod.POST, auth, TASK_MODEL_TYPE); - assertThat(responseCreate.getStatusCode()).isEqualTo(HttpStatus.CREATED); - assertThat(responseCreate.getBody()).isNotNull(); - - String taskIdOfCreatedTask = responseCreate.getBody().getTaskId(); - assertThat(taskIdOfCreatedTask).startsWith("TKI:"); - - String url2 = restHelper.toUrl(RestEndpoints.URL_TASKS_ID, taskIdOfCreatedTask); - HttpEntity auth2 = new HttpEntity<>(RestHelper.generateHeadersForUser("admin")); - - ResponseEntity responseDeleted = - TEMPLATE.exchange( - url2, HttpMethod.DELETE, auth2, ParameterizedTypeReference.forType(Void.class)); - assertThat(responseDeleted.getStatusCode()).isEqualTo(HttpStatus.NO_CONTENT); - } - - /** - * TSK-926: If Planned and Due Date is provided to create a task and not matching to service level - * throw an exception One is calculated by other other date +- service level. - */ - @Test - void should_ThrowException_When_CreatingTaskWithPlannedAndDueDateNotMatchingServiceLevel() { - TaskRepresentationModel taskRepresentationModel = getTaskResourceSample(); - Instant plannedTime = Instant.parse("2019-09-13T08:44:17.588Z"); - taskRepresentationModel.setPlanned(plannedTime); - taskRepresentationModel.setDue(plannedTime); - String url = restHelper.toUrl(RestEndpoints.URL_TASKS); - HttpEntity auth = - new HttpEntity<>(taskRepresentationModel, RestHelper.generateHeadersForUser("user-1-1")); - - ThrowingCallable httpCall = - () -> { - TEMPLATE.exchange(url, HttpMethod.POST, auth, TASK_MODEL_TYPE); - }; - - assertThatThrownBy(httpCall).isInstanceOf(HttpStatusCodeException.class); - } - - @Test - void should_RouteCreatedTask_When_CreatingTaskWithoutWorkbasketInformation() { - TaskRepresentationModel taskRepresentationModel = getTaskResourceSample(); - taskRepresentationModel.setWorkbasketSummary(null); - - String url = restHelper.toUrl(RestEndpoints.URL_TASKS); - HttpEntity auth = - new HttpEntity<>(taskRepresentationModel, RestHelper.generateHeadersForUser("user-1-1")); - ResponseEntity responseCreate = - TEMPLATE.exchange(url, HttpMethod.POST, auth, TASK_MODEL_TYPE); - - assertThat(responseCreate.getBody().getWorkbasketSummary().getWorkbasketId()) - .isEqualTo(IntegrationTestTaskRouter.DEFAULT_ROUTING_TARGET); - - String url2 = - restHelper.toUrl(RestEndpoints.URL_TASKS_ID, responseCreate.getBody().getTaskId()); - HttpEntity auth2 = new HttpEntity<>(RestHelper.generateHeadersForUser("admin")); - - ResponseEntity responseDeleted = - TEMPLATE.exchange( - url2, HttpMethod.DELETE, auth2, ParameterizedTypeReference.forType(Void.class)); - assertThat(responseDeleted.getStatusCode()).isEqualTo(HttpStatus.NO_CONTENT); - } - - @Test - void should_ThrowException_When_CreatingTaskWithInvalidParameter() throws Exception { - final String taskToCreateJson = - "{\"classificationKey\":\"L11010\"," - + "\"workbasketSummaryResource\":" - + "{\"workbasketId\":\"WBI:100000000000000000000000000000000004\"}," - + "\"primaryObjRef\":{\"company\":\"MyCompany1\",\"system\":\"MySystem1\"," - + "\"systemInstance\":\"MyInstance1\",\"type\":\"MyType1\",\"value\":\"00000001\"}}"; - - URL url = new URL(restHelper.toUrl(RestEndpoints.URL_TASKS)); - HttpURLConnection con = (HttpURLConnection) url.openConnection(); - con.setRequestMethod("POST"); - con.setDoOutput(true); - con.setRequestProperty("Authorization", RestHelper.encodeUserAndPasswordAsBasicAuth("admin")); - con.setRequestProperty("Content-Type", "application/json"); - BufferedWriter out = new BufferedWriter(new OutputStreamWriter(con.getOutputStream(), UTF_8)); - out.write(taskToCreateJson); - out.flush(); - out.close(); - assertThat(con.getResponseCode()).isEqualTo(400); - - con.disconnect(); - final String taskToCreateJson2 = - "{\"classificationSummaryResource\":" - + "{\"classificationId\":\"CLI:100000000000000000000000000000000004\"}," - + "\"workbasketSummaryResource\":{\"workbasketId\":\"\"}," - + "\"primaryObjRef\":{\"company\":\"MyCompany1\",\"system\":\"MySystem1\"," - + "\"systemInstance\":\"MyInstance1\",\"type\":\"MyType1\",\"value\":\"00000001\"}}"; - - url = new URL(restHelper.toUrl(RestEndpoints.URL_TASKS)); - con = (HttpURLConnection) url.openConnection(); - con.setRequestMethod("POST"); - con.setDoOutput(true); - con.setRequestProperty("Authorization", RestHelper.encodeUserAndPasswordAsBasicAuth("admin")); - con.setRequestProperty("Content-Type", "application/json"); - out = new BufferedWriter(new OutputStreamWriter(con.getOutputStream(), UTF_8)); - out.write(taskToCreateJson2); - out.flush(); - out.close(); - assertThat(con.getResponseCode()).isEqualTo(400); - - con.disconnect(); - } - - @Test - void should_CancelTask_when_CallingCancelEndpoint() { - String url = - restHelper.toUrl(RestEndpoints.URL_TASKS_ID, "TKI:000000000000000000000000000000000103"); - HttpEntity auth = new HttpEntity<>(RestHelper.generateHeadersForUser("user-1-2")); - - // retrieve task from Rest Api - ResponseEntity responseGet = - TEMPLATE.exchange(url, HttpMethod.GET, auth, TASK_MODEL_TYPE); - - assertThat(responseGet.getBody()).isNotNull(); - TaskRepresentationModel theTaskRepresentationModel = responseGet.getBody(); - assertThat(theTaskRepresentationModel.getState()).isEqualTo(TaskState.CLAIMED); - - // cancel the task - String url2 = - restHelper.toUrl( - RestEndpoints.URL_TASKS_ID_CANCEL, "TKI:000000000000000000000000000000000103"); - responseGet = TEMPLATE.exchange(url2, HttpMethod.POST, auth, TASK_MODEL_TYPE); - - assertThat(responseGet.getBody()).isNotNull(); - assertThat(responseGet.getBody().getState()).isEqualTo(TaskState.CANCELLED); - } - - @Test - void should_CancelClaimTask() { - String url = - restHelper.toUrl(RestEndpoints.URL_TASKS_ID, "TKI:000000000000000000000000000000000032"); - HttpEntity auth = new HttpEntity<>(RestHelper.generateHeadersForUser("user-1-2")); - - // retrieve task from Rest Api - ResponseEntity getTaskResponse = - TEMPLATE.exchange(url, HttpMethod.GET, auth, TASK_MODEL_TYPE); - assertThat(getTaskResponse.getBody()).isNotNull(); - TaskRepresentationModel claimedTaskRepresentationModel = getTaskResponse.getBody(); - assertThat(claimedTaskRepresentationModel.getState()).isEqualTo(TaskState.CLAIMED); - assertThat(claimedTaskRepresentationModel.getOwner()).isEqualTo("user-1-2"); - - // cancel claim - String url2 = - restHelper.toUrl( - RestEndpoints.URL_TASKS_ID_CLAIM, "TKI:000000000000000000000000000000000032"); - ResponseEntity cancelClaimResponse = - TEMPLATE.exchange(url2, HttpMethod.DELETE, auth, TASK_MODEL_TYPE); - - assertThat(cancelClaimResponse.getBody()).isNotNull(); - assertThat(cancelClaimResponse.getStatusCode().is2xxSuccessful()).isTrue(); - TaskRepresentationModel cancelClaimedtaskRepresentationModel = cancelClaimResponse.getBody(); - assertThat(cancelClaimedtaskRepresentationModel.getOwner()).isNull(); - assertThat(cancelClaimedtaskRepresentationModel.getClaimed()).isNull(); - assertThat(cancelClaimedtaskRepresentationModel.getState()).isEqualTo(TaskState.READY); - } - - @Test - void should_ForceCancelClaim_When_TaskIsClaimedByDifferentOwner() { - String url = - restHelper.toUrl(RestEndpoints.URL_TASKS_ID, "TKI:000000000000000000000000000000000027"); - HttpEntity auth = new HttpEntity<>(RestHelper.generateHeadersForUser("user-1-1")); - - // retrieve task from Rest Api - ResponseEntity getTaskResponse = - TEMPLATE.exchange(url, HttpMethod.GET, auth, TASK_MODEL_TYPE); - assertThat(getTaskResponse.getBody()).isNotNull(); - TaskRepresentationModel claimedTaskRepresentationModel = getTaskResponse.getBody(); - assertThat(claimedTaskRepresentationModel.getState()).isEqualTo(TaskState.CLAIMED); - assertThat(claimedTaskRepresentationModel.getOwner()).isEqualTo("user-1-2"); - - // force cancel claim - String url2 = - restHelper.toUrl( - RestEndpoints.URL_TASKS_ID_CLAIM_FORCE, "TKI:000000000000000000000000000000000027"); - ResponseEntity cancelClaimResponse = - TEMPLATE.exchange(url2, HttpMethod.DELETE, auth, TASK_MODEL_TYPE); - - assertThat(cancelClaimResponse.getBody()).isNotNull(); - assertThat(cancelClaimResponse.getStatusCode().is2xxSuccessful()).isTrue(); - TaskRepresentationModel cancelClaimedtaskRepresentationModel = cancelClaimResponse.getBody(); - assertThat(cancelClaimedtaskRepresentationModel.getOwner()).isNull(); - assertThat(cancelClaimedtaskRepresentationModel.getClaimed()).isNull(); - assertThat(cancelClaimedtaskRepresentationModel.getState()).isEqualTo(TaskState.READY); - } - - @Test - void should_ThrowException_When_CancelClaimingOfClaimedTaskByAnotherUser() { - String url = - restHelper.toUrl(RestEndpoints.URL_TASKS_ID, "TKI:000000000000000000000000000000000026"); - HttpEntity auth = new HttpEntity<>(RestHelper.generateHeadersForUser("user-1-2")); - - // retrieve task from Rest Api - ResponseEntity responseGet = - TEMPLATE.exchange(url, HttpMethod.GET, auth, TASK_MODEL_TYPE); - - assertThat(responseGet.getBody()).isNotNull(); - TaskRepresentationModel theTaskRepresentationModel = responseGet.getBody(); - assertThat(theTaskRepresentationModel.getState()).isEqualTo(TaskState.CLAIMED); - assertThat(theTaskRepresentationModel.getOwner()).isEqualTo("user-1-1"); - - // try to cancel claim - String url2 = - restHelper.toUrl( - RestEndpoints.URL_TASKS_ID_CLAIM, "TKI:000000000000000000000000000000000026"); - ThrowingCallable httpCall = - () -> TEMPLATE.exchange(url2, HttpMethod.DELETE, auth, TASK_MODEL_TYPE); - - assertThatThrownBy(httpCall) - .extracting(HttpStatusCodeException.class::cast) - .extracting(HttpStatusCodeException::getStatusCode) - .isEqualTo(HttpStatus.BAD_REQUEST); - } - - @Test - void should_RequestReviewOnATask() { - String url = - restHelper.toUrl(RestEndpoints.URL_TASKS_ID, "TKI:000000000000000000000000000000000035"); - HttpEntity auth = new HttpEntity<>(RestHelper.generateHeadersForUser("user-1-1")); - - // retrieve task from Rest Api - ResponseEntity getTaskResponse = - TEMPLATE.exchange(url, HttpMethod.GET, auth, TASK_MODEL_TYPE); - assertThat(getTaskResponse.getBody()).isNotNull(); - TaskRepresentationModel repModel = getTaskResponse.getBody(); - assertThat(repModel.getState()).isEqualTo(TaskState.CLAIMED); - assertThat(repModel.getOwner()).isEqualTo("user-1-1"); - - // request review - String url2 = - restHelper.toUrl( - RestEndpoints.URL_TASKS_ID_REQUEST_REVIEW, "TKI:000000000000000000000000000000000035"); - ResponseEntity requestReviewResponse = - TEMPLATE.exchange(url2, HttpMethod.POST, auth, TASK_MODEL_TYPE); - - assertThat(requestReviewResponse.getBody()).isNotNull(); - assertThat(requestReviewResponse.getStatusCode()).isEqualTo(HttpStatus.OK); - repModel = requestReviewResponse.getBody(); - assertThat(repModel.getOwner()).isNull(); - assertThat(repModel.getState()).isEqualTo(TaskState.READY_FOR_REVIEW); - } - - @Test - void should_ForceRequestReview_When_CurrentUserIsNotTheOwner() { - String url = - restHelper.toUrl(RestEndpoints.URL_TASKS_ID, "TKI:000000000000000000000000000000000101"); - HttpEntity auth = new HttpEntity<>(RestHelper.generateHeadersForUser("user-1-1")); - - // retrieve task from Rest Api - ResponseEntity getTaskResponse = - TEMPLATE.exchange(url, HttpMethod.GET, auth, TASK_MODEL_TYPE); - assertThat(getTaskResponse.getBody()).isNotNull(); - TaskRepresentationModel repModel = getTaskResponse.getBody(); - assertThat(repModel.getState()).isEqualTo(TaskState.CLAIMED); - assertThat(repModel.getOwner()).isEqualTo("user-1-2"); - - // request review - String url2 = - restHelper.toUrl( - RestEndpoints.URL_TASKS_ID_REQUEST_REVIEW_FORCE, - "TKI:000000000000000000000000000000000101"); - ResponseEntity requestReviewResponse = - TEMPLATE.exchange(url2, HttpMethod.POST, auth, TASK_MODEL_TYPE); - - assertThat(requestReviewResponse.getBody()).isNotNull(); - assertThat(requestReviewResponse.getStatusCode()).isEqualTo(HttpStatus.OK); - repModel = requestReviewResponse.getBody(); - assertThat(repModel.getOwner()).isNull(); - assertThat(repModel.getState()).isEqualTo(TaskState.READY_FOR_REVIEW); - } - - @Test - void should_RequestChangesOnATask() { - String url = - restHelper.toUrl(RestEndpoints.URL_TASKS_ID, "TKI:000000000000000000000000000000000136"); - HttpEntity auth = new HttpEntity<>(RestHelper.generateHeadersForUser("user-1-1")); - - // retrieve task from Rest Api - ResponseEntity getTaskResponse = - TEMPLATE.exchange(url, HttpMethod.GET, auth, TASK_MODEL_TYPE); - assertThat(getTaskResponse.getBody()).isNotNull(); - TaskRepresentationModel repModel = getTaskResponse.getBody(); - assertThat(repModel.getState()).isEqualTo(TaskState.IN_REVIEW); - assertThat(repModel.getOwner()).isEqualTo("user-1-1"); - - // request changes - String url2 = - restHelper.toUrl( - RestEndpoints.URL_TASKS_ID_REQUEST_CHANGES, "TKI:000000000000000000000000000000000136"); - ResponseEntity requestedChangesResponse = - TEMPLATE.exchange(url2, HttpMethod.POST, auth, TASK_MODEL_TYPE); - - assertThat(requestedChangesResponse.getBody()).isNotNull(); - assertThat(requestedChangesResponse.getStatusCode()).isEqualTo(HttpStatus.OK); - repModel = requestedChangesResponse.getBody(); - assertThat(repModel.getOwner()).isNull(); - assertThat(repModel.getState()).isEqualTo(TaskState.READY); - } - - @Test - void should_ForceRequestChanges_When_CurrentUserIsNotTheOwner() { - String url = - restHelper.toUrl(RestEndpoints.URL_TASKS_ID, "TKI:000000000000000000000000000000000100"); - HttpEntity auth = new HttpEntity<>(RestHelper.generateHeadersForUser("user-1-1")); - - // retrieve task from Rest Api - ResponseEntity getTaskResponse = - TEMPLATE.exchange(url, HttpMethod.GET, auth, TASK_MODEL_TYPE); - assertThat(getTaskResponse.getBody()).isNotNull(); - TaskRepresentationModel repModel = getTaskResponse.getBody(); - assertThat(repModel.getState()).isEqualTo(TaskState.CLAIMED); - assertThat(repModel.getOwner()).isEqualTo("user-1-2"); - - // request changes - String url2 = - restHelper.toUrl( - RestEndpoints.URL_TASKS_ID_REQUEST_CHANGES_FORCE, - "TKI:000000000000000000000000000000000100"); - ResponseEntity requestedChangesResponse = - TEMPLATE.exchange(url2, HttpMethod.POST, auth, TASK_MODEL_TYPE); - - assertThat(requestedChangesResponse.getBody()).isNotNull(); - assertThat(requestedChangesResponse.getStatusCode()).isEqualTo(HttpStatus.OK); - repModel = requestedChangesResponse.getBody(); - assertThat(repModel.getOwner()).isNull(); - assertThat(repModel.getState()).isEqualTo(TaskState.READY); - } - - @Test - void should_UpdateTaskOwnerOfReadyTask() { - final String url = restHelper.toUrl("/api/v1/tasks/TKI:000000000000000000000000000000000025"); - HttpEntity auth = new HttpEntity<>(RestHelper.generateHeadersForUser("user-1-2")); - - // retrieve task from Rest Api - ResponseEntity responseGet = - TEMPLATE.exchange(url, HttpMethod.GET, auth, TASK_MODEL_TYPE); - - assertThat(responseGet.getBody()).isNotNull(); - TaskRepresentationModel theTaskRepresentationModel = responseGet.getBody(); - assertThat(theTaskRepresentationModel.getState()).isEqualTo(TaskState.READY); - assertThat(theTaskRepresentationModel.getOwner()).isNull(); - - // set Owner and update Task - theTaskRepresentationModel.setOwner("dummyUser"); - HttpEntity auth2 = - new HttpEntity<>(theTaskRepresentationModel, RestHelper.generateHeadersForUser("user-1-2")); - - ResponseEntity responseUpdate = - TEMPLATE.exchange(url, HttpMethod.PUT, auth2, TASK_MODEL_TYPE); - - assertThat(responseUpdate.getBody()).isNotNull(); - TaskRepresentationModel theUpdatedTaskRepresentationModel = responseUpdate.getBody(); - assertThat(theUpdatedTaskRepresentationModel.getState()).isEqualTo(TaskState.READY); - assertThat(theUpdatedTaskRepresentationModel.getOwner()).isEqualTo("dummyUser"); - } - - @Test - void should_ThrowException_When_UpdatingTaskOwnerOfClaimedTask() { - final String url = restHelper.toUrl("/api/v1/tasks/TKI:000000000000000000000000000000000026"); - HttpEntity auth = new HttpEntity<>(RestHelper.generateHeadersForUser("user-1-2")); - - // retrieve task from Rest Api - ResponseEntity responseGet = - TEMPLATE.exchange(url, HttpMethod.GET, auth, TASK_MODEL_TYPE); - - assertThat(responseGet.getBody()).isNotNull(); - TaskRepresentationModel theTaskRepresentationModel = responseGet.getBody(); - assertThat(theTaskRepresentationModel.getState()).isEqualTo(TaskState.CLAIMED); - assertThat(theTaskRepresentationModel.getOwner()).isEqualTo("user-1-1"); - - // set Owner and update Task - theTaskRepresentationModel.setOwner("dummyuser"); - HttpEntity auth2 = - new HttpEntity<>(theTaskRepresentationModel, RestHelper.generateHeadersForUser("user-1-2")); - - ThrowingCallable httpCall = - () -> { - TEMPLATE.exchange(url, HttpMethod.PUT, auth2, TASK_MODEL_TYPE); - }; - - assertThatThrownBy(httpCall) - .isInstanceOf(HttpStatusCodeException.class) - .hasMessageContaining("400"); - } - - @Test - void should_ThrowNotAuthorized_When_UserHasNoAuthorizationOnTask() { - String url = - restHelper.toUrl(RestEndpoints.URL_TASKS_ID, "TKI:000000000000000000000000000000000000"); - HttpEntity auth = new HttpEntity<>(RestHelper.generateHeadersForUser("user-b-1")); - - ThrowingCallable httpCall = - () -> { - TEMPLATE.exchange( - url, - HttpMethod.GET, - auth, - ParameterizedTypeReference.forType(TaskRepresentationModel.class)); - }; - - assertThatThrownBy(httpCall) - .extracting(HttpStatusCodeException.class::cast) - .extracting(HttpStatusCodeException::getStatusCode) - .isEqualTo(HttpStatus.FORBIDDEN); - } - - @Test - void should_ThrowException_When_ProvidingInvalidFilterParams() { - String url = - restHelper.toUrl(RestEndpoints.URL_TASKS) - + "?workbasket-id=WBI:100000000000000000000000000000000001" - + "&illegalParam=illegal" - + "&anotherIllegalParam=stillIllegal" - + "&sort-by=NAME&order=DESCENDING&page-size=5&page=2"; - HttpEntity auth = new HttpEntity<>(RestHelper.generateHeadersForUser("teamlead-1")); - - ThrowingCallable httpCall = - () -> TEMPLATE.exchange(url, HttpMethod.GET, auth, TASK_SUMMARY_PAGE_MODEL_TYPE); - - assertThatThrownBy(httpCall) - .isInstanceOf(HttpStatusCodeException.class) - .hasMessageContaining( - "Unknown request parameters found: [anotherIllegalParam, illegalParam]") - .extracting(HttpStatusCodeException.class::cast) - .extracting(HttpStatusCodeException::getStatusCode) - .isEqualTo(HttpStatus.BAD_REQUEST); - } - - @Test - void should_ThrowException_When_ProvidingInvalidOrder() { - String url = - restHelper.toUrl(RestEndpoints.URL_TASKS) - + "?workbasket-id=WBI:100000000000000000000000000000000001" - + "&sort-by=NAME&order=WRONG"; - HttpEntity auth = new HttpEntity<>(RestHelper.generateHeadersForUser("teamlead-1")); - - ThrowingCallable httpCall = - () -> TEMPLATE.exchange(url, HttpMethod.GET, auth, TASK_SUMMARY_PAGE_MODEL_TYPE); - - assertThatThrownBy(httpCall) - .isInstanceOf(HttpStatusCodeException.class) - .hasMessageContaining("\"expectedValues\":[\"ASCENDING\",\"DESCENDING\"]") - .extracting(HttpStatusCodeException.class::cast) - .extracting(HttpStatusCodeException::getStatusCode) - .isEqualTo(HttpStatus.BAD_REQUEST); - } - - @TestFactory - Stream should_SetTransferFlagDependentOnRequestBody_When_TransferringTask() { - Iterator iterator = Arrays.asList(true, false).iterator(); - String url = - restHelper.toUrl( - RestEndpoints.URL_TASKS_ID_TRANSFER_WORKBASKET_ID, - "TKI:000000000000000000000000000000000003", - "WBI:100000000000000000000000000000000006"); - - ThrowingConsumer test = - setTransferFlag -> { - HttpEntity auth = - new HttpEntity<>( - setTransferFlag.toString(), RestHelper.generateHeadersForUser("admin")); - ResponseEntity response = - TEMPLATE.exchange(url, HttpMethod.POST, auth, TASK_MODEL_TYPE); - - assertThat(response.getBody()).isNotNull(); - assertThat(response.getBody().getWorkbasketSummary().getWorkbasketId()) - .isEqualTo("WBI:100000000000000000000000000000000006"); - assertThat(response.getBody().isTransferred()).isEqualTo(setTransferFlag); - }; - - return DynamicTest.stream(iterator, c -> "for setTransferFlag: " + c, test); - } - - @Test - void should_SetTransferFlagToTrue_When_TransferringWithoutRequestBody() { - String url = - restHelper.toUrl( - RestEndpoints.URL_TASKS_ID_TRANSFER_WORKBASKET_ID, - "TKI:000000000000000000000000000000000003", - "WBI:100000000000000000000000000000000006"); - HttpEntity auth = new HttpEntity<>(RestHelper.generateHeadersForUser("admin")); - - ResponseEntity response = - TEMPLATE.exchange(url, HttpMethod.POST, auth, TASK_MODEL_TYPE); - - assertThat(response.getBody()).isNotNull(); - assertThat(response.getBody().getWorkbasketSummary().getWorkbasketId()) - .isEqualTo("WBI:100000000000000000000000000000000006"); - assertThat(response.getBody().isTransferred()).isTrue(); - } - private TaskRepresentationModel getTaskResourceSample() { ClassificationSummaryRepresentationModel classificationResource = new ClassificationSummaryRepresentationModel(); @@ -1700,4 +115,1916 @@ class TaskControllerIntTest { objectReference.setValue("0000000" + suffix); return objectReference; } + + @Nested + @TestInstance(Lifecycle.PER_CLASS) + class GetTasks { + + @Test + void should_GetAllTasks() { + String url = restHelper.toUrl(RestEndpoints.URL_TASKS); + HttpEntity auth = new HttpEntity<>(RestHelper.generateHeadersForUser("teamlead-1")); + + ResponseEntity response = + TEMPLATE.exchange(url, HttpMethod.GET, auth, TASK_SUMMARY_PAGE_MODEL_TYPE); + + assertThat(response.getBody()).isNotNull(); + assertThat((response.getBody()).getLink(IanaLinkRelations.SELF)).isNotNull(); + assertThat(response.getBody().getContent()).hasSize(60); + } + + @Test + void should_GetAllTasks_For_SpecifiedWorkbasketId() { + String url = + restHelper.toUrl(RestEndpoints.URL_TASKS) + + "?workbasket-id=WBI:100000000000000000000000000000000001"; + HttpEntity auth = new HttpEntity<>(RestHelper.generateHeadersForUser("teamlead-1")); + + ResponseEntity response = + TEMPLATE.exchange(url, HttpMethod.GET, auth, TASK_SUMMARY_PAGE_MODEL_TYPE); + + assertThat(response.getBody()).isNotNull(); + assertThat((response.getBody()).getLink(IanaLinkRelations.SELF)).isNotNull(); + assertThat(response.getBody().getContent()).hasSize(22); + } + + @Test + void should_GetAllTasks_For_SpecifiedWorkbasketIdWithinMultiplePlannedTimeIntervals() { + Instant firstInstant = Instant.now().minus(7, ChronoUnit.DAYS); + Instant secondInstant = Instant.now().minus(10, ChronoUnit.DAYS); + Instant thirdInstant = Instant.now().minus(10, ChronoUnit.DAYS); + Instant fourthInstant = Instant.now().minus(11, ChronoUnit.DAYS); + String url = + restHelper.toUrl(RestEndpoints.URL_TASKS) + + String.format( + "?workbasket-id=WBI:100000000000000000000000000000000001" + + "&planned=%s&planned=" + + "&planned=%s&planned=%s" + + "&planned=&planned=%s" + + "&sort-by=PLANNED", + firstInstant, secondInstant, thirdInstant, fourthInstant); + HttpEntity auth = new HttpEntity<>(RestHelper.generateHeadersForUser("teamlead-1")); + + ResponseEntity response = + TEMPLATE.exchange(url, HttpMethod.GET, auth, TASK_SUMMARY_PAGE_MODEL_TYPE); + + assertThat(response.getBody()).isNotNull(); + assertThat((response.getBody()).getLink(IanaLinkRelations.SELF)).isNotNull(); + assertThat(response.getBody().getContent()).hasSize(6); + } + + @Test + void should_GetCustomIntCorrectly_When_GettingTaskWithCustomIntValues() { + String url = + restHelper.toUrl(RestEndpoints.URL_TASKS_ID, "TKI:000000000000000000000000000000000025"); + HttpEntity auth = new HttpEntity<>(RestHelper.generateHeadersForUser("user-1-2")); + + ResponseEntity response = + TEMPLATE.exchange(url, HttpMethod.GET, auth, TASK_MODEL_TYPE); + + TaskRepresentationModel repModel = response.getBody(); + assertThat(repModel).isNotNull(); + assertThat(repModel.getCustomInt1()).isEqualTo(1); + assertThat(repModel.getCustomInt2()).isEqualTo(2); + assertThat(repModel.getCustomInt3()).isEqualTo(3); + assertThat(repModel.getCustomInt4()).isEqualTo(4); + assertThat(repModel.getCustomInt5()).isEqualTo(5); + assertThat(repModel.getCustomInt6()).isEqualTo(6); + assertThat(repModel.getCustomInt7()).isEqualTo(7); + assertThat(repModel.getCustomInt8()).isEqualTo(8); + } + + @TestFactory + Stream should_GetAllTasks_For_SpecifiedWorkbasketIdAndCustomIntFieldIn() { + List customIntValues = List.of(1, 2, 3, 4, 5, 6, 7, 8); + ThrowingConsumer test = + i -> { + String url = + restHelper.toUrl(RestEndpoints.URL_TASKS) + + String.format( + "?workbasket-id=WBI:100000000000000000000000000000000001" + + "&custom-int-%s=%s", + i, i); + HttpEntity auth = + new HttpEntity<>(RestHelper.generateHeadersForUser("teamlead-1")); + + ResponseEntity response = + TEMPLATE.exchange(url, HttpMethod.GET, auth, TASK_SUMMARY_PAGE_MODEL_TYPE); + + assertThat(response.getBody()).isNotNull(); + assertThat((response.getBody()).getLink(IanaLinkRelations.SELF)).isNotNull(); + assertThat(response.getBody().getContent()).hasSize(22); + }; + + return DynamicTest.stream(customIntValues.iterator(), c -> "customInt" + c, test); + } + + @TestFactory + Stream should_GetAllTasks_For_SpecifiedWorkbasketIdAndCustomIntFieldFrom() { + List customIntValues = List.of(1, 2, 3, 4, 5, 6, 7, 8); + ThrowingConsumer test = + i -> { + String url = + restHelper.toUrl(RestEndpoints.URL_TASKS) + + String.format( + "?workbasket-id=WBI:100000000000000000000000000000000001" + + "&custom-int-%s-from=%s", + i, i); + HttpEntity auth = + new HttpEntity<>(RestHelper.generateHeadersForUser("teamlead-1")); + + ResponseEntity response = + TEMPLATE.exchange(url, HttpMethod.GET, auth, TASK_SUMMARY_PAGE_MODEL_TYPE); + + assertThat(response.getBody()).isNotNull(); + assertThat((response.getBody()).getLink(IanaLinkRelations.SELF)).isNotNull(); + assertThat(response.getBody().getContent()).hasSize(22); + }; + + return DynamicTest.stream(customIntValues.iterator(), c -> "customInt" + c, test); + } + + @TestFactory + Stream should_GetAllTasks_For_SpecifiedWorkbasketIdAndCustomIntFieldFromAndTo() { + List customIntValues = List.of(1, 2, 3, 4, 5, 6, 7, 8); + ThrowingConsumer test = + i -> { + String url = + restHelper.toUrl(RestEndpoints.URL_TASKS) + + String.format( + "?workbasket-id=WBI:100000000000000000000000000000000001" + + "&custom-int-%s-from=-1&custom-int-%s-to=123", + i, i); + HttpEntity auth = + new HttpEntity<>(RestHelper.generateHeadersForUser("teamlead-1")); + + ResponseEntity response = + TEMPLATE.exchange(url, HttpMethod.GET, auth, TASK_SUMMARY_PAGE_MODEL_TYPE); + + assertThat(response.getBody()).isNotNull(); + assertThat((response.getBody()).getLink(IanaLinkRelations.SELF)).isNotNull(); + assertThat(response.getBody().getContent()).hasSize(22); + }; + + return DynamicTest.stream(customIntValues.iterator(), c -> "customInt" + c, test); + } + + @TestFactory + Stream should_GetAllTasks_For_SpecifiedWorkbasketIdAndCustomIntFieldTo() { + List customIntValues = List.of(1, 2, 3, 4, 5, 6, 7, 8); + ThrowingConsumer test = + i -> { + String url = + restHelper.toUrl(RestEndpoints.URL_TASKS) + + String.format( + "?workbasket-id=WBI:100000000000000000000000000000000001" + + "&custom-int-%s-to=%s", + i, i); + HttpEntity auth = + new HttpEntity<>(RestHelper.generateHeadersForUser("teamlead-1")); + + ResponseEntity response = + TEMPLATE.exchange(url, HttpMethod.GET, auth, TASK_SUMMARY_PAGE_MODEL_TYPE); + + assertThat(response.getBody()).isNotNull(); + assertThat((response.getBody()).getLink(IanaLinkRelations.SELF)).isNotNull(); + assertThat(response.getBody().getContent()).hasSize(22); + }; + + return DynamicTest.stream(customIntValues.iterator(), c -> "customInt" + c, test); + } + + @TestFactory + Stream should_GetAllTasks_For_SpecifiedWorkbasketIdAndCustomIntFieldNotIn() { + List customIntValues = List.of(1, 2, 3, 4, 5, 6, 7, 8); + ThrowingConsumer test = + i -> { + String url = + restHelper.toUrl(RestEndpoints.URL_TASKS) + + String.format( + "?workbasket-id=WBI:100000000000000000000000000000000001" + + "&custom-int-%s-not=25", + i); + HttpEntity auth = + new HttpEntity<>(RestHelper.generateHeadersForUser("teamlead-1")); + + ResponseEntity response = + TEMPLATE.exchange(url, HttpMethod.GET, auth, TASK_SUMMARY_PAGE_MODEL_TYPE); + + assertThat(response.getBody()).isNotNull(); + assertThat((response.getBody()).getLink(IanaLinkRelations.SELF)).isNotNull(); + assertThat(response.getBody().getContent()).hasSize(22); + }; + + return DynamicTest.stream(customIntValues.iterator(), c -> "customInt" + c, test); + } + + @TestFactory + Stream + should_ThrowException_For_SpecifiedWorkbasketIdAndCustomIntFieldWithinIncorrectInterval() { + List customIntValues = List.of(1, 2, 3, 4, 5, 6, 7, 8); + ThrowingConsumer test = + i -> { + String url = + restHelper.toUrl(RestEndpoints.URL_TASKS) + + String.format( + "?workbasket-id=WBI:100000000000000000000000000000000001" + + "&custom-int-%s-within=%s" + + "&custom-int-%s-within=23" + + "&custom-int-%s-within=15", + i, i, i, i); + HttpEntity auth = + new HttpEntity<>(RestHelper.generateHeadersForUser("teamlead-1")); + + ThrowingCallable httpCall = + () -> TEMPLATE.exchange(url, HttpMethod.GET, auth, TASK_SUMMARY_PAGE_MODEL_TYPE); + + assertThatThrownBy(httpCall) + .isInstanceOf(HttpStatusCodeException.class) + .hasMessageContaining( + String.format( + "provided length of the property 'custom-int-%s-within' is not dividable by" + + " 2", + i)) + .extracting(HttpStatusCodeException.class::cast) + .extracting(HttpStatusCodeException::getStatusCode) + .isEqualTo(HttpStatus.BAD_REQUEST); + }; + + return DynamicTest.stream(customIntValues.iterator(), c -> "customInt" + c, test); + } + + @TestFactory + Stream + should_ThrowException_For_SpecifiedWorkbasketIdAndCustomIntFieldWithinNullInterval() { + List customIntValues = List.of(1, 2, 3, 4, 5, 6, 7, 8); + ThrowingConsumer test = + i -> { + String url = + restHelper.toUrl(RestEndpoints.URL_TASKS) + + String.format( + "?workbasket-id=WBI:100000000000000000000000000000000001" + + "&custom-int-%s-within=" + + "&custom-int-%s-within=", + i, i, i); + HttpEntity auth = + new HttpEntity<>(RestHelper.generateHeadersForUser("teamlead-1")); + + ThrowingCallable httpCall = + () -> TEMPLATE.exchange(url, HttpMethod.GET, auth, TASK_SUMMARY_PAGE_MODEL_TYPE); + + assertThatThrownBy(httpCall) + .isInstanceOf(HttpStatusCodeException.class) + .hasMessageContaining( + String.format( + "Each interval in 'custom-int-" + + i + + "-within' shouldn't consist of two 'null' values", + i)) + .extracting(HttpStatusCodeException.class::cast) + .extracting(HttpStatusCodeException::getStatusCode) + .isEqualTo(HttpStatus.BAD_REQUEST); + }; + + return DynamicTest.stream(customIntValues.iterator(), c -> "customInt" + c, test); + } + + @TestFactory + Stream should_GetAllTasks_For_SpecifiedWorkbasketIdAndCustomIntFieldWithin() { + List customIntValues = List.of(1, 2, 3, 4, 5, 6, 7, 8); + ThrowingConsumer test = + i -> { + String url = + restHelper.toUrl(RestEndpoints.URL_TASKS) + + String.format( + "?workbasket-id=WBI:100000000000000000000000000000000001" + + "&custom-int-%s-within=%s" + + "&custom-int-%s-within=15", + i, i, i); + HttpEntity auth = + new HttpEntity<>(RestHelper.generateHeadersForUser("teamlead-1")); + + ResponseEntity response = + TEMPLATE.exchange(url, HttpMethod.GET, auth, TASK_SUMMARY_PAGE_MODEL_TYPE); + + assertThat(response.getBody()).isNotNull(); + assertThat((response.getBody()).getLink(IanaLinkRelations.SELF)).isNotNull(); + assertThat(response.getBody().getContent()).hasSize(22); + }; + + return DynamicTest.stream(customIntValues.iterator(), c -> "customInt" + c, test); + } + + @TestFactory + Stream + should_GetAllTasks_For_SpecifiedWorkbasketIdAndCustomIntFieldWithinOpenLowerBound() { + List customIntValues = List.of(1, 2, 3, 4, 5, 6, 7, 8); + ThrowingConsumer test = + i -> { + String url = + restHelper.toUrl(RestEndpoints.URL_TASKS) + + String.format( + "?workbasket-id=WBI:100000000000000000000000000000000001" + + "&custom-int-%s-within=" + + "&custom-int-%s-within=%s", + i, i, i); + HttpEntity auth = + new HttpEntity<>(RestHelper.generateHeadersForUser("teamlead-1")); + + ResponseEntity response = + TEMPLATE.exchange(url, HttpMethod.GET, auth, TASK_SUMMARY_PAGE_MODEL_TYPE); + + assertThat(response.getBody()).isNotNull(); + assertThat((response.getBody()).getLink(IanaLinkRelations.SELF)).isNotNull(); + assertThat(response.getBody().getContent()).hasSize(22); + }; + + return DynamicTest.stream(customIntValues.iterator(), c -> "customInt" + c, test); + } + + @TestFactory + Stream + should_GetAllTasks_For_SpecifiedWorkbasketIdAndCustomIntFieldNotWithinOpenUpperBound() { + List customIntValues = List.of(1, 2, 3, 4, 5, 6, 7, 8); + ThrowingConsumer test = + i -> { + String url = + restHelper.toUrl(RestEndpoints.URL_TASKS) + + String.format( + "?workbasket-id=WBI:100000000000000000000000000000000001" + + "&custom-int-%s-not-within=%s" + + "&custom-int-%s-not-within=", + i, i, i); + HttpEntity auth = + new HttpEntity<>(RestHelper.generateHeadersForUser("teamlead-1")); + + ResponseEntity response = + TEMPLATE.exchange(url, HttpMethod.GET, auth, TASK_SUMMARY_PAGE_MODEL_TYPE); + + assertThat(response.getBody()).isNotNull(); + assertThat((response.getBody()).getLink(IanaLinkRelations.SELF)).isNotNull(); + assertThat(response.getBody().getContent()).isEmpty(); + }; + + return DynamicTest.stream(customIntValues.iterator(), c -> "customInt" + c, test); + } + + @Test + void should_GetAllTasks_For_SpecifiesWorkbasketIdWithinSinglePlannedTimeInterval() { + Instant plannedFromInstant = Instant.now().minus(6, ChronoUnit.DAYS); + Instant plannedToInstant = Instant.now().minus(3, ChronoUnit.DAYS); + String url = + restHelper.toUrl(RestEndpoints.URL_TASKS) + + "?workbasket-id=WBI:100000000000000000000000000000000001" + + "&planned-from=" + + plannedFromInstant + + "&planned-until=" + + plannedToInstant + + "&sort-by=PLANNED"; + HttpEntity auth = new HttpEntity<>(RestHelper.generateHeadersForUser("teamlead-1")); + + ResponseEntity response = + TEMPLATE.exchange(url, HttpMethod.GET, auth, TASK_SUMMARY_PAGE_MODEL_TYPE); + + assertThat(response.getBody()).isNotNull(); + assertThat((response.getBody()).getLink(IanaLinkRelations.SELF)).isNotNull(); + assertThat(response.getBody().getContent()).hasSize(3); + } + + @Test + void should_GetAllTasks_For_SpecifiedWorkbasketIdWithinSingleIndefinitePlannedTimeInterval() { + Instant plannedFromInstant = Instant.now().minus(6, ChronoUnit.DAYS); + String url = + restHelper.toUrl(RestEndpoints.URL_TASKS) + + "?workbasket-id=WBI:100000000000000000000000000000000001" + + "&planned-from=" + + plannedFromInstant + + "&sort-by=PLANNED"; + HttpEntity auth = new HttpEntity<>(RestHelper.generateHeadersForUser("teamlead-1")); + + ResponseEntity response = + TEMPLATE.exchange(url, HttpMethod.GET, auth, TASK_SUMMARY_PAGE_MODEL_TYPE); + + assertThat(response.getBody()).isNotNull(); + assertThat((response.getBody()).getLink(IanaLinkRelations.SELF)).isNotNull(); + assertThat(response.getBody().getContent()).hasSize(4); + } + + @Test + void + should_ThrowException_When_GettingTasksByWorkbasketIdWithInvalidPlannedParamsCombination() { + String url = + restHelper.toUrl(RestEndpoints.URL_TASKS) + + "?workbasket-id=WBI:100000000000000000000000000000000001" + + "&planned=2020-01-22T09:44:47.453Z,," + + "2020-01-19T07:44:47.453Z,2020-01-19T19:44:47.453Z," + + ",2020-01-18T09:44:47.453Z" + + "&planned-from=2020-01-19T07:44:47.453Z" + + "&sort-by=planned"; + HttpEntity auth = new HttpEntity<>(RestHelper.generateHeadersForUser("teamlead-1")); + + ThrowingCallable httpCall = + () -> TEMPLATE.exchange(url, HttpMethod.GET, auth, TASK_SUMMARY_PAGE_MODEL_TYPE); + + assertThatThrownBy(httpCall) + .isInstanceOf(HttpStatusCodeException.class) + .extracting(HttpStatusCodeException.class::cast) + .extracting(HttpStatusCodeException::getStatusCode) + .isEqualTo(HttpStatus.BAD_REQUEST); + } + + @Test + void should_GetAllTasks_For_SpecifiedWorkbasketIdWithinMultipleDueTimeIntervals() { + Instant firstInstant = Instant.now().minus(7, ChronoUnit.DAYS); + Instant secondInstant = Instant.now().minus(10, ChronoUnit.DAYS); + Instant thirdInstant = Instant.now().minus(10, ChronoUnit.DAYS); + Instant fourthInstant = Instant.now().minus(11, ChronoUnit.DAYS); + String url = + restHelper.toUrl(RestEndpoints.URL_TASKS) + + String.format( + "?workbasket-id=WBI:100000000000000000000000000000000001" + + "&due=%s&due=" + + "&due=%s&due=%s" + + "&due=&due=%s" + + "&sort-by=DUE", + firstInstant, secondInstant, thirdInstant, fourthInstant); + HttpEntity auth = new HttpEntity<>(RestHelper.generateHeadersForUser("teamlead-1")); + + ResponseEntity response = + TEMPLATE.exchange(url, HttpMethod.GET, auth, TASK_SUMMARY_PAGE_MODEL_TYPE); + + assertThat(response.getBody()).isNotNull(); + assertThat((response.getBody()).getLink(IanaLinkRelations.SELF)).isNotNull(); + assertThat(response.getBody().getContent()).hasSize(22); + } + + @Test + void should_ReturnAllTasks_For_ProvidedPrimaryObjectReference() { + String url = + restHelper.toUrl(RestEndpoints.URL_TASKS) + + "?por=" + + URLEncoder.encode( + "{\"systemInstance\":\"MyInstance1\",\"type\":\"MyType1\"}", UTF_8); + HttpEntity auth = new HttpEntity<>(RestHelper.generateHeadersForUser("teamlead-1")); + ResponseEntity response = + TEMPLATE.exchange(url, HttpMethod.GET, auth, TASK_SUMMARY_PAGE_MODEL_TYPE); + assertThat(response.getBody()).isNotNull(); + assertThat(response.getStatusCode()).isEqualTo(HttpStatus.OK); + assertThat((response.getBody()).getLink(IanaLinkRelations.SELF)).isNotNull(); + assertThat(response.getBody().getContent()).hasSize(4); + } + + @Test + void should_ReturnAllTasks_For_ProvidedSecondaryObjectReferenceByTypeAndValue() { + String url = + restHelper.toUrl(RestEndpoints.URL_TASKS) + + "?sor=" + + URLEncoder.encode("{\"type\":\"Type2\",\"value\":\"Value2\"}", UTF_8); + HttpEntity auth = new HttpEntity<>(RestHelper.generateHeadersForUser("teamlead-1")); + ResponseEntity response = + TEMPLATE.exchange(url, HttpMethod.GET, auth, TASK_SUMMARY_PAGE_MODEL_TYPE); + assertThat(response.getBody()).isNotNull(); + assertThat(response.getStatusCode()).isEqualTo(HttpStatus.OK); + assertThat((response.getBody()).getLink(IanaLinkRelations.SELF)).isNotNull(); + assertThat(response.getBody().getContent()).hasSize(2); + } + + @Test + void should_ReturnAllTasks_For_ProvidedSecondaryObjectReferenceByCompany() { + String url = + restHelper.toUrl(RestEndpoints.URL_TASKS) + + "?sor=" + + URLEncoder.encode("{\"company\":\"Company3\"}", UTF_8); + HttpEntity auth = new HttpEntity<>(RestHelper.generateHeadersForUser("teamlead-1")); + ResponseEntity response = + TEMPLATE.exchange(url, HttpMethod.GET, auth, TASK_SUMMARY_PAGE_MODEL_TYPE); + assertThat(response.getBody()).isNotNull(); + assertThat(response.getStatusCode()).isEqualTo(HttpStatus.OK); + assertThat((response.getBody()).getLink(IanaLinkRelations.SELF)).isNotNull(); + assertThat(response.getBody().getContent()).hasSize(1); + } + + @Test + void should_ReturnNoTasks_For_ProvidedNonexistentSecondaryObjectReference() { + String url = + restHelper.toUrl(RestEndpoints.URL_TASKS) + + "?sor=" + + URLEncoder.encode("{\"type\":\"Type2\",\"value\":\"Quatsch\"}", UTF_8); + HttpEntity auth = new HttpEntity<>(RestHelper.generateHeadersForUser("teamlead-1")); + ResponseEntity response = + TEMPLATE.exchange(url, HttpMethod.GET, auth, TASK_SUMMARY_PAGE_MODEL_TYPE); + assertThat(response.getBody()).isNotNull(); + assertThat(response.getStatusCode()).isEqualTo(HttpStatus.OK); + assertThat((response.getBody()).getLink(IanaLinkRelations.SELF)).isNotNull(); + assertThat(response.getBody().getContent()).isEmpty(); + } + + @Test + void should_ReturnAllTasksByWildcardSearch_For_ProvidedSearchValue() { + String url = + restHelper.toUrl(RestEndpoints.URL_TASKS) + + "?wildcard-search-value=99" + + "&wildcard-search-fields=NAME" + + "&wildcard-search-fields=CUSTOM_3" + + "&wildcard-search-fields=CUSTOM_4"; + HttpEntity auth = new HttpEntity<>(RestHelper.generateHeadersForUser("admin")); + + ResponseEntity response = + TEMPLATE.exchange(url, HttpMethod.GET, auth, TASK_SUMMARY_PAGE_MODEL_TYPE); + + assertThat(response.getBody()).isNotNull(); + assertThat((response.getBody()).getLink(IanaLinkRelations.SELF)).isNotNull(); + assertThat(response.getBody().getContent()).hasSize(4); + } + + @TestFactory + Stream should_ThrowException_When_ProvidingInvalidFormatForCustomAttributes() { + Iterator iterator = + Arrays.asList( + CustomAttribute.of(null, "value"), + CustomAttribute.of("", "value"), + CustomAttribute.of("key", null)) + .iterator(); + + ThrowingConsumer test = + customAttribute -> { + TaskRepresentationModel taskRepresentationModel = getTaskResourceSample(); + taskRepresentationModel.setCustomAttributes(List.of(customAttribute)); + String url = restHelper.toUrl(RestEndpoints.URL_TASKS); + HttpEntity auth = + new HttpEntity<>( + taskRepresentationModel, RestHelper.generateHeadersForUser("teamlead-1")); + + ThrowingCallable httpCall = + () -> TEMPLATE.exchange(url, HttpMethod.POST, auth, TASK_MODEL_TYPE); + assertThatThrownBy(httpCall) + .isInstanceOf(HttpStatusCodeException.class) + .hasMessageContaining("Format of custom attributes is not valid") + .extracting(HttpStatusCodeException.class::cast) + .extracting(HttpStatusCodeException::getStatusCode) + .isEqualTo(HttpStatus.BAD_REQUEST); + }; + + return DynamicTest.stream(iterator, c -> "customAttribute: '" + c.getKey() + "'", test); + } + + @Test + void should_ThrowException_When_ProvidingInvalidFilterParams() { + String url = + restHelper.toUrl(RestEndpoints.URL_TASKS) + + "?workbasket-id=WBI:100000000000000000000000000000000001" + + "&illegalParam=illegal" + + "&anotherIllegalParam=stillIllegal" + + "&sort-by=NAME&order=DESCENDING&page-size=5&page=2"; + HttpEntity auth = new HttpEntity<>(RestHelper.generateHeadersForUser("teamlead-1")); + + ThrowingCallable httpCall = + () -> TEMPLATE.exchange(url, HttpMethod.GET, auth, TASK_SUMMARY_PAGE_MODEL_TYPE); + + assertThatThrownBy(httpCall) + .isInstanceOf(HttpStatusCodeException.class) + .hasMessageContaining( + "Unknown request parameters found: [anotherIllegalParam, illegalParam]") + .extracting(HttpStatusCodeException.class::cast) + .extracting(HttpStatusCodeException::getStatusCode) + .isEqualTo(HttpStatus.BAD_REQUEST); + } + + @Test + void should_ThrowException_When_ProvidingInvalidOrder() { + String url = + restHelper.toUrl(RestEndpoints.URL_TASKS) + + "?workbasket-id=WBI:100000000000000000000000000000000001" + + "&sort-by=NAME&order=WRONG"; + HttpEntity auth = new HttpEntity<>(RestHelper.generateHeadersForUser("teamlead-1")); + + ThrowingCallable httpCall = + () -> TEMPLATE.exchange(url, HttpMethod.GET, auth, TASK_SUMMARY_PAGE_MODEL_TYPE); + + assertThatThrownBy(httpCall) + .isInstanceOf(HttpStatusCodeException.class) + .hasMessageContaining("\"expectedValues\":[\"ASCENDING\",\"DESCENDING\"]") + .extracting(HttpStatusCodeException.class::cast) + .extracting(HttpStatusCodeException::getStatusCode) + .isEqualTo(HttpStatus.BAD_REQUEST); + } + + @Test + void should_ThrowNotAuthorized_When_UserHasNoAuthorizationOnTask() { + String url = + restHelper.toUrl(RestEndpoints.URL_TASKS_ID, "TKI:000000000000000000000000000000000000"); + HttpEntity auth = new HttpEntity<>(RestHelper.generateHeadersForUser("user-b-1")); + + ThrowingCallable httpCall = + () -> + TEMPLATE.exchange( + url, + HttpMethod.GET, + auth, + ParameterizedTypeReference.forType(TaskRepresentationModel.class)); + + assertThatThrownBy(httpCall) + .extracting(HttpStatusCodeException.class::cast) + .extracting(HttpStatusCodeException::getStatusCode) + .isEqualTo(HttpStatus.FORBIDDEN); + } + + @Test + void should_ThrowException_When_ProvidingInvalidWildcardSearchParameters() { + String url = restHelper.toUrl(RestEndpoints.URL_TASKS) + "?wildcard-search-value=%rt%"; + HttpEntity auth = new HttpEntity<>(RestHelper.generateHeadersForUser("teamlead-1")); + + ThrowingCallable httpCall = + () -> TEMPLATE.exchange(url, HttpMethod.GET, auth, TASK_SUMMARY_PAGE_MODEL_TYPE); + + assertThatThrownBy(httpCall) + .isInstanceOf(HttpStatusCodeException.class) + .extracting(HttpStatusCodeException.class::cast) + .extracting(HttpStatusCodeException::getStatusCode) + .isEqualTo(HttpStatus.BAD_REQUEST); + + String url2 = + restHelper.toUrl(RestEndpoints.URL_TASKS) + + "?wildcard-search-fields=NAME,CUSTOM_3,CUSTOM_4"; + ThrowingCallable httpCall2 = + () -> TEMPLATE.exchange(url2, HttpMethod.GET, auth, TASK_SUMMARY_PAGE_MODEL_TYPE); + + assertThatThrownBy(httpCall2) + .isInstanceOf(HttpStatusCodeException.class) + .extracting(HttpStatusCodeException.class::cast) + .extracting(HttpStatusCodeException::getStatusCode) + .isEqualTo(HttpStatus.BAD_REQUEST); + } + + @Test + void should_GetAllTasks_For_SpecifiedWorkbasketIdWithinSingleDueTimeInterval() { + Instant dueFromInstant = Instant.now().minus(8, ChronoUnit.DAYS); + Instant dueToInstant = Instant.now().minus(3, ChronoUnit.DAYS); + String url = + restHelper.toUrl(RestEndpoints.URL_TASKS) + + "?workbasket-id=WBI:100000000000000000000000000000000001" + + "&due-from=" + + dueFromInstant + + "&due-until=" + + dueToInstant + + "&sort-by=DUE"; + HttpEntity auth = new HttpEntity<>(RestHelper.generateHeadersForUser("teamlead-1")); + + ResponseEntity response = + TEMPLATE.exchange(url, HttpMethod.GET, auth, TASK_SUMMARY_PAGE_MODEL_TYPE); + + assertThat(response.getBody()).isNotNull(); + assertThat((response.getBody()).getLink(IanaLinkRelations.SELF)).isNotNull(); + assertThat(response.getBody().getContent()).hasSize(1); + } + + @Test + void should_GetAllTasks_For_SpecifiedWorkbasketIdWithinSingleIndefiniteDueTimeInterval() { + Instant dueToInstant = Instant.now().minus(1, ChronoUnit.DAYS); + String url = + restHelper.toUrl(RestEndpoints.URL_TASKS) + + "?workbasket-id=WBI:100000000000000000000000000000000001" + + "&due-until=" + + dueToInstant + + "&sort-by=DUE"; + HttpEntity auth = new HttpEntity<>(RestHelper.generateHeadersForUser("teamlead-1")); + + ResponseEntity response = + TEMPLATE.exchange(url, HttpMethod.GET, auth, TASK_SUMMARY_PAGE_MODEL_TYPE); + + assertThat(response.getBody()).isNotNull(); + assertThat((response.getBody()).getLink(IanaLinkRelations.SELF)).isNotNull(); + assertThat(response.getBody().getContent()).hasSize(6); + } + + @Test + void should_GetAllTasks_For_WorkbasketIdWithInvalidDueParamsCombination() { + String url = + restHelper.toUrl(RestEndpoints.URL_TASKS) + + "?workbasket-id=WBI:100000000000000000000000000000000001" + + "&due=2020-01-22T09:44:47.453Z,," + + "2020-01-19T07:44:47.453Z,2020-01-19T19:44:47.453Z," + + ",2020-01-18T09:44:47.453Z" + + "&due-from=2020-01-19T07:44:47.453Z" + + "&sort-by=planned"; + HttpEntity auth = new HttpEntity<>(RestHelper.generateHeadersForUser("teamlead-1")); + + ThrowingCallable httpCall = + () -> TEMPLATE.exchange(url, HttpMethod.GET, auth, TASK_SUMMARY_PAGE_MODEL_TYPE); + + assertThatThrownBy(httpCall) + .isInstanceOf(HttpStatusCodeException.class) + .extracting(HttpStatusCodeException.class::cast) + .extracting(HttpStatusCodeException::getStatusCode) + .isEqualTo(HttpStatus.BAD_REQUEST); + } + + @Test + void should_GetAllTasks_For_SpecifiedWorkbasketKeyAndDomain() { + String url = + restHelper.toUrl(RestEndpoints.URL_TASKS) + "?workbasket-key=USER-1-2&domain=DOMAIN_A"; + HttpEntity auth = new HttpEntity<>(RestHelper.generateHeadersForUser("user-1-2")); + + ResponseEntity response = + TEMPLATE.exchange(url, HttpMethod.GET, auth, TASK_SUMMARY_PAGE_MODEL_TYPE); + + assertThat(response.getBody()).isNotNull(); + assertThat((response.getBody()).getLink(IanaLinkRelations.SELF)).isNotNull(); + assertThat(response.getBody().getContent()).hasSize(21); + } + + @Test + void should_GetAllTasks_For_SpecifiedExternalId() { + String url = + restHelper.toUrl(RestEndpoints.URL_TASKS) + + "?external-id=ETI:000000000000000000000000000000000003" + + "&external-id=ETI:000000000000000000000000000000000004"; + HttpEntity auth = new HttpEntity<>(RestHelper.generateHeadersForUser("teamlead-1")); + + ResponseEntity response = + TEMPLATE.exchange(url, HttpMethod.GET, auth, TASK_SUMMARY_PAGE_MODEL_TYPE); + + assertThat(response.getBody()).isNotNull(); + assertThat((response.getBody()).getLink(IanaLinkRelations.SELF)).isNotNull(); + assertThat(response.getBody().getContent()).hasSize(2); + } + + @Test + void should_ThrowException_When_KeyIsSetButDomainIsMissing() { + String url = restHelper.toUrl(RestEndpoints.URL_TASKS) + "?workbasket-key=USER-1-2"; + HttpEntity auth = new HttpEntity<>(RestHelper.generateHeadersForUser("user-1-2")); + + ThrowingCallable httpCall = + () -> TEMPLATE.exchange(url, HttpMethod.GET, auth, TASK_SUMMARY_PAGE_MODEL_TYPE); + + assertThatThrownBy(httpCall) + .isInstanceOf(HttpStatusCodeException.class) + .extracting(HttpStatusCodeException.class::cast) + .extracting(HttpStatusCodeException::getStatusCode) + .isEqualTo(HttpStatus.BAD_REQUEST); + } + + @Test + void should_GetAllTasksWithAdminRole() { + String url = restHelper.toUrl(RestEndpoints.URL_TASKS); + HttpEntity auth = new HttpEntity<>(RestHelper.generateHeadersForUser("admin")); + + ResponseEntity response = + TEMPLATE.exchange(url, HttpMethod.GET, auth, TASK_SUMMARY_PAGE_MODEL_TYPE); + + assertThat(response.getBody()).isNotNull(); + assertThat((response.getBody()).getLink(IanaLinkRelations.SELF)).isNotNull(); + assertThat(response.getBody().getContent()).hasSize(91); + } + + @Test + void should_KeepFiltersInTheLinkOfTheResponse_When_GettingTasks() { + String url = + restHelper.toUrl(RestEndpoints.URL_TASKS) + + "?por-type=VNR&por-value=22334455&sort-by=POR_VALUE&order=DESCENDING"; + HttpEntity auth = new HttpEntity<>(RestHelper.generateHeadersForUser("teamlead-1")); + + ResponseEntity response = + TEMPLATE.exchange(url, HttpMethod.GET, auth, TASK_SUMMARY_PAGE_MODEL_TYPE); + + assertThat(response.getBody()).isNotNull(); + assertThat((response.getBody()).getLink(IanaLinkRelations.SELF)).isNotNull(); + assertThat(response.getBody().getRequiredLink(IanaLinkRelations.SELF).getHref()) + .endsWith( + "/api/v1/tasks?por-type=VNR&por-value=22334455" + + "&sort-by=POR_VALUE&order=DESCENDING"); + } + + @Test + void should_GetAllTasks_For_GettingLastTaskSummaryPageSortedByPorValue() { + String url = + restHelper.toUrl(RestEndpoints.URL_TASKS) + + "?state=READY&state=CLAIMED&sort-by=POR_VALUE" + + "&order=DESCENDING&page-size=5&page=16"; + HttpEntity auth = new HttpEntity<>(RestHelper.generateHeadersForUser("admin")); + + ResponseEntity response = + TEMPLATE.exchange(url, HttpMethod.GET, auth, TASK_SUMMARY_PAGE_MODEL_TYPE); + + assertThat(response.getBody()).isNotNull(); + assertThat((response.getBody()).getContent()).hasSize(5); + assertThat(response.getBody().getRequiredLink(IanaLinkRelations.LAST).getHref()) + .contains("page=16"); + assertThat(response.getBody().getContent().iterator().next().getTaskId()) + .isEqualTo("TKI:000000000000000000000000000000000064"); + assertThat(response.getBody().getLink(IanaLinkRelations.SELF)).isNotNull(); + assertThat(response.getBody().getRequiredLink(IanaLinkRelations.SELF).getHref()) + .endsWith( + "/api/v1/tasks?state=READY&state=CLAIMED" + + "&sort-by=POR_VALUE&order=DESCENDING&page-size=5&page=16"); + assertThat(response.getBody().getLink(IanaLinkRelations.FIRST)).isNotNull(); + assertThat(response.getBody().getLink(IanaLinkRelations.LAST)).isNotNull(); + assertThat(response.getBody().getLink(IanaLinkRelations.PREV)).isNotNull(); + } + + @Test + void should_SortByOwnerLongName() { + String url = + restHelper.toUrl(RestEndpoints.URL_TASKS) + + "?sort-by=OWNER_LONG_NAME" + + "&order=DESCENDING"; + HttpEntity auth = new HttpEntity<>(RestHelper.generateHeadersForUser("admin")); + + ResponseEntity response = + TEMPLATE.exchange(url, HttpMethod.GET, auth, TASK_SUMMARY_PAGE_MODEL_TYPE); + + assertThat(response.getBody()).isNotNull(); + assertThat((response.getBody()).getLink(IanaLinkRelations.SELF)).isNotNull(); + } + + @Test + void testGetLastPageSortedByDueWithHiddenTasksRemovedFromResult() { + resetDb(); + // required because + // ClassificationControllerIntTest.testGetQueryByPorSecondPageSortedByType changes + // tasks and this test depends on the tasks as they are in sampledata + String url = restHelper.toUrl(RestEndpoints.URL_TASKS) + "?sort-by=DUE&order=DESCENDING"; + HttpEntity auth = new HttpEntity<>(RestHelper.generateHeadersForUser("teamlead-1")); + + ResponseEntity response = + TEMPLATE.exchange(url, HttpMethod.GET, auth, TASK_SUMMARY_PAGE_MODEL_TYPE); + + assertThat(response.getBody()).isNotNull(); + assertThat((response.getBody()).getContent()).hasSize(60); + + String url2 = + restHelper.toUrl(RestEndpoints.URL_TASKS) + + "?sort-by=DUE&order=DESCENDING&page-size=5&page=5"; + response = TEMPLATE.exchange(url2, HttpMethod.GET, auth, TASK_SUMMARY_PAGE_MODEL_TYPE); + + assertThat(response.getBody()).isNotNull(); + assertThat((response.getBody()).getContent()).hasSize(5); + assertThat(response.getBody().getRequiredLink(IanaLinkRelations.LAST).getHref()) + .contains("page=12"); + assertThat(response.getBody().getContent().iterator().next().getTaskId()) + .isEqualTo("TKI:000000000000000000000000000000000073"); + assertThat(response.getBody().getLink(IanaLinkRelations.SELF)).isNotNull(); + assertThat(response.getBody().getRequiredLink(IanaLinkRelations.SELF).getHref()) + .endsWith("/api/v1/tasks?sort-by=DUE&order=DESCENDING&page-size=5&page=5"); + assertThat(response.getBody().getLink(IanaLinkRelations.FIRST)).isNotNull(); + assertThat(response.getBody().getLink(IanaLinkRelations.LAST)).isNotNull(); + assertThat(response.getBody().getLink(IanaLinkRelations.PREV)).isNotNull(); + } + + @Test + void should_GetAllTasks_For_GettingSecondPageFilteredByPorAttributesSortedByType() { + resetDb(); // required because + // ClassificationControllerIntTest.testGetQueryByPorSecondPageSortedByType changes + // tasks and this test depends on the tasks as they are in sampledata + String url = + restHelper.toUrl(RestEndpoints.URL_TASKS) + + "?por-company=00&por-system=PASystem&por-instance=00&" + + "por-type=VNR&por-value=22334455&sort-by=POR_TYPE&" + + "order=ASCENDING&page-size=5&page=2"; + HttpEntity auth = new HttpEntity<>(RestHelper.generateHeadersForUser("teamlead-1")); + + ResponseEntity response = + TEMPLATE.exchange(url, HttpMethod.GET, auth, TASK_SUMMARY_PAGE_MODEL_TYPE); + + assertThat(response.getBody()).isNotNull(); + assertThat(response.getBody().getContent()) + .extracting(TaskSummaryRepresentationModel::getTaskId) + .containsExactlyInAnyOrder("TKI:000000000000000000000000000000000013"); + assertThat(response.getBody().getLink(IanaLinkRelations.SELF)).isNotNull(); + assertThat(response.getBody().getRequiredLink(IanaLinkRelations.SELF).getHref()) + .endsWith( + "/api/v1/tasks?por-company=00&por-system=PASystem&por-instance=00&" + + "por-type=VNR&por-value=22334455&sort-by=POR_TYPE&order=ASCENDING&" + + "page-size=5&page=2"); + assertThat(response.getBody().getLink(IanaLinkRelations.FIRST)).isNotNull(); + assertThat(response.getBody().getLink(IanaLinkRelations.LAST)).isNotNull(); + assertThat(response.getBody().getLink(IanaLinkRelations.PREV)).isNotNull(); + } + + @Test + void should_NotGetEmptyAttachmentList_When_GettingTaskWithAttachment() { + String url = + restHelper.toUrl(RestEndpoints.URL_TASKS_ID, "TKI:000000000000000000000000000000000002"); + HttpEntity auth = new HttpEntity<>(RestHelper.generateHeadersForUser("admin")); + + ResponseEntity response = + TEMPLATE.exchange(url, HttpMethod.GET, auth, TASK_MODEL_TYPE); + + TaskRepresentationModel repModel = response.getBody(); + assertThat(repModel).isNotNull(); + assertThat(repModel.getAttachments()).isNotEmpty(); + } + + @Test + void should_ReturnFilteredTasks_When_GettingTaskWithoutAttachments() { + String url = restHelper.toUrl(RestEndpoints.URL_TASKS) + "?without-attachment=true"; + HttpEntity auth = new HttpEntity<>(RestHelper.generateHeadersForUser("admin")); + + ResponseEntity response = + TEMPLATE.exchange(url, HttpMethod.GET, auth, TASK_SUMMARY_PAGE_MODEL_TYPE); + + assertThat(response.getBody()).isNotNull(); + assertThat((response.getBody()).getLink(IanaLinkRelations.SELF)).isNotNull(); + assertThat(response.getBody().getContent()).hasSize(84); + } + + @Test + void should_ThrowException_When_WithoutAttachmentsIsSetToFalse() { + String url = restHelper.toUrl(RestEndpoints.URL_TASKS) + "?without-attachment=false"; + HttpEntity auth = new HttpEntity<>(RestHelper.generateHeadersForUser("admin")); + + assertThatThrownBy( + () -> TEMPLATE.exchange(url, HttpMethod.GET, auth, TASK_SUMMARY_PAGE_MODEL_TYPE)) + .isInstanceOf(HttpStatusCodeException.class) + .hasMessageContaining( + "provided value of the property 'without-attachment' must be 'true'"); + } + + @Test + void should_NotGetEmptyObjectReferencesList_When_GettingTaskWithObjectReferences() { + String url = + restHelper.toUrl(RestEndpoints.URL_TASKS_ID, "TKI:000000000000000000000000000000000001"); + HttpEntity auth = new HttpEntity<>(RestHelper.generateHeadersForUser("admin")); + + ResponseEntity response = + TEMPLATE.exchange(url, HttpMethod.GET, auth, TASK_MODEL_TYPE); + + TaskRepresentationModel repModel = response.getBody(); + assertThat(repModel).isNotNull(); + assertThat(repModel.getSecondaryObjectReferences()).isNotEmpty(); + } + + @Test + void should_ReturnFilteredTasks_When_GettingTasksBySecondaryObjectReferenceValue() { + String url = restHelper.toUrl(RestEndpoints.URL_TASKS) + "?sor-value=Value2"; + HttpEntity auth = new HttpEntity<>(RestHelper.generateHeadersForUser("teamlead-1")); + + ResponseEntity response = + TEMPLATE.exchange(url, HttpMethod.GET, auth, TASK_SUMMARY_PAGE_MODEL_TYPE); + + assertThat(response.getBody()).isNotNull(); + assertThat((response.getBody()).getLink(IanaLinkRelations.SELF)).isNotNull(); + assertThat(response.getBody().getContent()).hasSize(3); + } + + @Test + void should_ReturnFilteredTasks_When_GettingTasksBySecondaryObjectReferenceTypeLike() { + String url = restHelper.toUrl(RestEndpoints.URL_TASKS) + "?sor-type-like=Type"; + HttpEntity auth = new HttpEntity<>(RestHelper.generateHeadersForUser("teamlead-1")); + + ResponseEntity response = + TEMPLATE.exchange(url, HttpMethod.GET, auth, TASK_SUMMARY_PAGE_MODEL_TYPE); + + assertThat(response.getBody()).isNotNull(); + assertThat((response.getBody()).getLink(IanaLinkRelations.SELF)).isNotNull(); + assertThat(response.getBody().getContent()).hasSize(3); + } + + @Test + void should_ReturnFilteredTasks_When_GettingTasksBySecondaryObjectReferenceValueAndCompany() { + String url = + restHelper.toUrl(RestEndpoints.URL_TASKS) + "?sor-value=Value2&&sor-company=Company1"; + HttpEntity auth = new HttpEntity<>(RestHelper.generateHeadersForUser("teamlead-1")); + + ResponseEntity response = + TEMPLATE.exchange(url, HttpMethod.GET, auth, TASK_SUMMARY_PAGE_MODEL_TYPE); + + assertThat(response.getBody()).isNotNull(); + assertThat((response.getBody()).getLink(IanaLinkRelations.SELF)).isNotNull(); + assertThat(response.getBody().getContent()).hasSize(1); + } + + @Test + void should_GetPriorityCorrectly_When_GettingTaskWithManualPriority() { + String url = + restHelper.toUrl(RestEndpoints.URL_TASKS_ID, "TKI:000000000000000000070000000000000079"); + HttpEntity auth = new HttpEntity<>(RestHelper.generateHeadersForUser("teamlead-1")); + + ResponseEntity response = + TEMPLATE.exchange(url, HttpMethod.GET, auth, TASK_MODEL_TYPE); + + assertThat(response.getBody()).isNotNull(); + assertThat(response.getBody().getPriority()) + .isEqualTo((response.getBody().getManualPriority())) + .isEqualTo(56); + } + + @Test + void should_ReturnReceivedDate_When_GettingTask() { + String url = + restHelper.toUrl(RestEndpoints.URL_TASKS_ID, "TKI:000000000000000000000000000000000024"); + HttpEntity auth = new HttpEntity<>(RestHelper.generateHeadersForUser("admin")); + + ResponseEntity response = + TEMPLATE.exchange(url, HttpMethod.GET, auth, TASK_MODEL_TYPE); + + assertThat(response.getBody()) + .isNotNull() + .extracting(TaskSummaryRepresentationModel::getReceived) + .isNotNull(); + } + } + + @Nested + @TestInstance(Lifecycle.PER_CLASS) + class CreateTasks { + + @Test + void should_CreateAndDeleteTask() { + TaskRepresentationModel taskRepresentationModel = getTaskResourceSample(); + String url = restHelper.toUrl(RestEndpoints.URL_TASKS); + HttpEntity auth = + new HttpEntity<>( + taskRepresentationModel, RestHelper.generateHeadersForUser("teamlead-1")); + + ResponseEntity responseCreate = + TEMPLATE.exchange(url, HttpMethod.POST, auth, TASK_MODEL_TYPE); + assertThat(responseCreate.getStatusCode()).isEqualTo(HttpStatus.CREATED); + assertThat(responseCreate.getBody()).isNotNull(); + + String taskIdOfCreatedTask = responseCreate.getBody().getTaskId(); + assertThat(taskIdOfCreatedTask).startsWith("TKI:"); + + String url2 = restHelper.toUrl(RestEndpoints.URL_TASKS_ID_FORCE, taskIdOfCreatedTask); + HttpEntity auth2 = new HttpEntity<>(RestHelper.generateHeadersForUser("admin")); + + ResponseEntity responseDeleted = + TEMPLATE.exchange( + url2, HttpMethod.DELETE, auth2, ParameterizedTypeReference.forType(Void.class)); + assertThat(responseDeleted.getStatusCode()).isEqualTo(HttpStatus.NO_CONTENT); + } + + @Test + void should_CreateAndDeleteTaskWithSecondaryObjectReferences_When_SpecifyingObjectReferences() { + TaskRepresentationModel taskRepresentationModel = getTaskResourceSample(); + ObjectReferenceRepresentationModel obj0 = getSampleSecondaryObjectReference("0"); + obj0.setTaskId(taskRepresentationModel.getTaskId()); + ObjectReferenceRepresentationModel obj1 = getSampleSecondaryObjectReference("1"); + obj1.setTaskId(taskRepresentationModel.getTaskId()); + List secondaryObjectReferences = List.of(obj0, obj1); + taskRepresentationModel.setSecondaryObjectReferences(secondaryObjectReferences); + + String url = restHelper.toUrl(RestEndpoints.URL_TASKS); + HttpEntity auth = + new HttpEntity<>( + taskRepresentationModel, RestHelper.generateHeadersForUser("teamlead-1")); + + ResponseEntity responseCreate = + TEMPLATE.exchange(url, HttpMethod.POST, auth, TASK_MODEL_TYPE); + assertThat(responseCreate.getStatusCode()).isEqualTo(HttpStatus.CREATED); + assertThat(responseCreate.getBody()).isNotNull(); + String taskIdOfCreatedTask = responseCreate.getBody().getTaskId(); + + String url2 = restHelper.toUrl(RestEndpoints.URL_TASKS_ID_FORCE, taskIdOfCreatedTask); + HttpEntity auth2 = new HttpEntity<>(RestHelper.generateHeadersForUser("admin")); + + ResponseEntity responseDeleted = + TEMPLATE.exchange( + url2, HttpMethod.DELETE, auth2, ParameterizedTypeReference.forType(Void.class)); + assertThat(responseDeleted.getStatusCode()).isEqualTo(HttpStatus.NO_CONTENT); + } + + @Test + void should_CreateAndDeleteTaskWithManualPriority_When_SpecifyingManualPriority() { + TaskRepresentationModel taskRepresentationModel = getTaskResourceSample(); + taskRepresentationModel.setManualPriority(7); + + String url = restHelper.toUrl(RestEndpoints.URL_TASKS); + HttpEntity auth = + new HttpEntity<>( + taskRepresentationModel, RestHelper.generateHeadersForUser("teamlead-1")); + + ResponseEntity responseCreate = + TEMPLATE.exchange(url, HttpMethod.POST, auth, TASK_MODEL_TYPE); + assertThat(responseCreate.getStatusCode()).isEqualTo(HttpStatus.CREATED); + assertThat(responseCreate.getBody()).isNotNull(); + assertThat(responseCreate.getBody().getPriority()) + .isEqualTo((responseCreate.getBody().getManualPriority())) + .isEqualTo(7); + + String taskIdOfCreatedTask = responseCreate.getBody().getTaskId(); + String url2 = restHelper.toUrl(RestEndpoints.URL_TASKS_ID_FORCE, taskIdOfCreatedTask); + HttpEntity auth2 = new HttpEntity<>(RestHelper.generateHeadersForUser("admin")); + + ResponseEntity responseDeleted = + TEMPLATE.exchange( + url2, HttpMethod.DELETE, auth2, ParameterizedTypeReference.forType(Void.class)); + assertThat(responseDeleted.getStatusCode()).isEqualTo(HttpStatus.NO_CONTENT); + } + + @Test + void should_CreateTaskWithCorrectPriorityAndThenDeleteIt_When_NotSpecifyingManualPriority() { + TaskRepresentationModel taskRepresentationModel = getTaskResourceSample(); + + String url = restHelper.toUrl(RestEndpoints.URL_TASKS); + HttpEntity auth = + new HttpEntity<>( + taskRepresentationModel, RestHelper.generateHeadersForUser("teamlead-1")); + + ResponseEntity responseCreate = + TEMPLATE.exchange(url, HttpMethod.POST, auth, TASK_MODEL_TYPE); + assertThat(responseCreate.getStatusCode()).isEqualTo(HttpStatus.CREATED); + assertThat(responseCreate.getBody()).isNotNull(); + // The classification of taskRepresentationModel with the key "L11010" has priority=1 + assertThat(responseCreate.getBody().getPriority()).isEqualTo(1); + assertThat(responseCreate.getBody().getManualPriority()).isEqualTo(-1); + + String taskIdOfCreatedTask = responseCreate.getBody().getTaskId(); + String url2 = restHelper.toUrl(RestEndpoints.URL_TASKS_ID_FORCE, taskIdOfCreatedTask); + HttpEntity auth2 = new HttpEntity<>(RestHelper.generateHeadersForUser("admin")); + + ResponseEntity responseDeleted = + TEMPLATE.exchange( + url2, HttpMethod.DELETE, auth2, ParameterizedTypeReference.forType(Void.class)); + assertThat(responseDeleted.getStatusCode()).isEqualTo(HttpStatus.NO_CONTENT); + } + + /** + * TSK-926: If Planned and Due Date is provided to create a task and not matching to service + * level throw an exception One is calculated by other other date +- service level. + */ + @Test + void should_ThrowException_When_CreatingTaskWithPlannedAndDueDateNotMatchingServiceLevel() { + TaskRepresentationModel taskRepresentationModel = getTaskResourceSample(); + Instant plannedTime = Instant.parse("2019-09-13T08:44:17.588Z"); + taskRepresentationModel.setPlanned(plannedTime); + taskRepresentationModel.setDue(plannedTime); + String url = restHelper.toUrl(RestEndpoints.URL_TASKS); + HttpEntity auth = + new HttpEntity<>(taskRepresentationModel, RestHelper.generateHeadersForUser("user-1-1")); + + ThrowingCallable httpCall = + () -> TEMPLATE.exchange(url, HttpMethod.POST, auth, TASK_MODEL_TYPE); + + assertThatThrownBy(httpCall).isInstanceOf(HttpStatusCodeException.class); + } + + @Test + void should_RouteCreatedTask_When_CreatingTaskWithoutWorkbasketInformation() { + TaskRepresentationModel taskRepresentationModel = getTaskResourceSample(); + taskRepresentationModel.setWorkbasketSummary(null); + + String url = restHelper.toUrl(RestEndpoints.URL_TASKS); + HttpEntity auth = + new HttpEntity<>(taskRepresentationModel, RestHelper.generateHeadersForUser("user-1-1")); + ResponseEntity responseCreate = + TEMPLATE.exchange(url, HttpMethod.POST, auth, TASK_MODEL_TYPE); + + assertThat(responseCreate.getBody().getWorkbasketSummary().getWorkbasketId()) + .isEqualTo(IntegrationTestTaskRouter.DEFAULT_ROUTING_TARGET); + + String url2 = + restHelper.toUrl(RestEndpoints.URL_TASKS_ID_FORCE, responseCreate.getBody().getTaskId()); + HttpEntity auth2 = new HttpEntity<>(RestHelper.generateHeadersForUser("admin")); + + ResponseEntity responseDeleted = + TEMPLATE.exchange( + url2, HttpMethod.DELETE, auth2, ParameterizedTypeReference.forType(Void.class)); + assertThat(responseDeleted.getStatusCode()).isEqualTo(HttpStatus.NO_CONTENT); + } + + @Test + void should_ThrowException_When_CreatingTaskWithInvalidParameter() throws Exception { + final String taskToCreateJson = + "{\"classificationKey\":\"L11010\"," + + "\"workbasketSummaryResource\":" + + "{\"workbasketId\":\"WBI:100000000000000000000000000000000004\"}," + + "\"primaryObjRef\":{\"company\":\"MyCompany1\",\"system\":\"MySystem1\"," + + "\"systemInstance\":\"MyInstance1\",\"type\":\"MyType1\",\"value\":\"00000001\"}}"; + + URL url = new URL(restHelper.toUrl(RestEndpoints.URL_TASKS)); + HttpURLConnection con = (HttpURLConnection) url.openConnection(); + con.setRequestMethod("POST"); + con.setDoOutput(true); + con.setRequestProperty("Authorization", RestHelper.encodeUserAndPasswordAsBasicAuth("admin")); + con.setRequestProperty("Content-Type", "application/json"); + BufferedWriter out = new BufferedWriter(new OutputStreamWriter(con.getOutputStream(), UTF_8)); + out.write(taskToCreateJson); + out.flush(); + out.close(); + assertThat(con.getResponseCode()).isEqualTo(400); + + con.disconnect(); + final String taskToCreateJson2 = + "{\"classificationSummaryResource\":" + + "{\"classificationId\":\"CLI:100000000000000000000000000000000004\"}," + + "\"workbasketSummaryResource\":{\"workbasketId\":\"\"}," + + "\"primaryObjRef\":{\"company\":\"MyCompany1\",\"system\":\"MySystem1\"," + + "\"systemInstance\":\"MyInstance1\",\"type\":\"MyType1\",\"value\":\"00000001\"}}"; + + url = new URL(restHelper.toUrl(RestEndpoints.URL_TASKS)); + con = (HttpURLConnection) url.openConnection(); + con.setRequestMethod("POST"); + con.setDoOutput(true); + con.setRequestProperty("Authorization", RestHelper.encodeUserAndPasswordAsBasicAuth("admin")); + con.setRequestProperty("Content-Type", "application/json"); + out = new BufferedWriter(new OutputStreamWriter(con.getOutputStream(), UTF_8)); + out.write(taskToCreateJson2); + out.flush(); + out.close(); + assertThat(con.getResponseCode()).isEqualTo(400); + + con.disconnect(); + } + } + + @Nested + @TestInstance(Lifecycle.PER_CLASS) + class UpdateTasks { + + @Test + void should_ChangeValueOfReceived_When_UpdatingTask() { + String url = + restHelper.toUrl(RestEndpoints.URL_TASKS_ID, "TKI:100000000000000000000000000000000000"); + HttpEntity httpEntityWithoutBody = + new HttpEntity<>(RestHelper.generateHeadersForUser("teamlead-1")); + + ResponseEntity responseGet = + TEMPLATE.exchange(url, HttpMethod.GET, httpEntityWithoutBody, TASK_MODEL_TYPE); + + final TaskRepresentationModel originalTask = responseGet.getBody(); + Instant expectedReceived = Instant.parse("2019-09-13T08:44:17.588Z"); + originalTask.setReceived(expectedReceived); + HttpEntity httpEntity = + new HttpEntity<>(originalTask, RestHelper.generateHeadersForUser("teamlead-1")); + + ResponseEntity responseUpdate = + TEMPLATE.exchange(url, HttpMethod.PUT, httpEntity, TASK_MODEL_TYPE); + + TaskRepresentationModel updatedTask = responseUpdate.getBody(); + assertThat(updatedTask).isNotNull(); + assertThat(updatedTask.getReceived()).isEqualTo(expectedReceived); + } + + @Test + void should_ChangeValueOfModified_When_UpdatingTask() { + String url = + restHelper.toUrl(RestEndpoints.URL_TASKS_ID, "TKI:100000000000000000000000000000000000"); + HttpEntity auth = new HttpEntity<>(RestHelper.generateHeadersForUser("teamlead-1")); + + ResponseEntity responseGet = + TEMPLATE.exchange(url, HttpMethod.GET, auth, TASK_MODEL_TYPE); + + final TaskRepresentationModel originalTask = responseGet.getBody(); + HttpEntity auth2 = + new HttpEntity<>(originalTask, RestHelper.generateHeadersForUser("teamlead-1")); + + ResponseEntity responseUpdate = + TEMPLATE.exchange(url, HttpMethod.PUT, auth2, TASK_MODEL_TYPE); + + TaskRepresentationModel updatedTask = responseUpdate.getBody(); + assertThat(originalTask).isNotNull(); + assertThat(updatedTask).isNotNull(); + assertThat(originalTask.getModified()).isBefore(updatedTask.getModified()); + } + } + + @Nested + @TestInstance(Lifecycle.PER_CLASS) + class DeleteTasks { + + @Test + void should_DeleteTask() { + String url = + restHelper.toUrl(RestEndpoints.URL_TASKS_ID, "TKI:000000000000000000000000000000000039"); + HttpEntity auth = new HttpEntity<>(RestHelper.generateHeadersForUser("admin")); + + ResponseEntity responseGet = + TEMPLATE.exchange(url, HttpMethod.GET, auth, TASK_MODEL_TYPE); + assertThat(responseGet.getBody()).isNotNull(); + assertThat(responseGet.getBody().getState()).isEqualTo(TaskState.COMPLETED); + + ResponseEntity responseDelete = + TEMPLATE.exchange(url, HttpMethod.DELETE, auth, TASK_MODEL_TYPE); + + assertThat(responseDelete.getStatusCode()).isEqualTo(HttpStatus.NO_CONTENT); + + ThrowingCallable httpCall = + () -> TEMPLATE.exchange(url, HttpMethod.GET, auth, TASK_MODEL_TYPE); + + assertThatThrownBy(httpCall) + .isInstanceOf(HttpStatusCodeException.class) + .hasMessageContaining( + "Task with id 'TKI:000000000000000000000000000000000039' was not found.") + .extracting(HttpStatusCodeException.class::cast) + .extracting(HttpStatusCodeException::getStatusCode) + .isEqualTo(HttpStatus.NOT_FOUND); + } + + @Test + void should_ForceDeleteTask() { + String url = + restHelper.toUrl(RestEndpoints.URL_TASKS_ID, "TKI:000000000000000000000000000000000026"); + String urlForce = + restHelper.toUrl( + RestEndpoints.URL_TASKS_ID_FORCE, "TKI:000000000000000000000000000000000026"); + HttpEntity auth = new HttpEntity<>(RestHelper.generateHeadersForUser("admin")); + + ResponseEntity responseGet = + TEMPLATE.exchange(url, HttpMethod.GET, auth, TASK_MODEL_TYPE); + assertThat(responseGet.getBody()).isNotNull(); + assertThat(responseGet.getBody().getState()).isEqualTo(TaskState.CLAIMED); + + ResponseEntity responseDelete = + TEMPLATE.exchange(urlForce, HttpMethod.DELETE, auth, TASK_MODEL_TYPE); + + assertThat(responseDelete.getStatusCode()).isEqualTo(HttpStatus.NO_CONTENT); + + ThrowingCallable httpCall = + () -> TEMPLATE.exchange(url, HttpMethod.GET, auth, TASK_MODEL_TYPE); + + assertThatThrownBy(httpCall) + .isInstanceOf(HttpStatusCodeException.class) + .hasMessageContaining( + "Task with id 'TKI:000000000000000000000000000000000026' was not found.") + .extracting(HttpStatusCodeException.class::cast) + .extracting(HttpStatusCodeException::getStatusCode) + .isEqualTo(HttpStatus.NOT_FOUND); + } + + @Test + void should_DeleteAllTasks_For_ProvidedParams() { + String url = + restHelper.toUrl(RestEndpoints.URL_TASKS) + + "?task-id=TKI:000000000000000000000000000000000036" + + "&task-id=TKI:000000000000000000000000000000000037" + + "&task-id=TKI:000000000000000000000000000000000038" + + "&custom14=abc"; + HttpEntity auth = new HttpEntity<>(RestHelper.generateHeadersForUser("admin")); + + ResponseEntity response = + TEMPLATE.exchange(url, HttpMethod.DELETE, auth, TASK_SUMMARY_COLLECTION_MODEL_TYPE); + + assertThat(response.getBody()).isNotNull(); + assertThat((response.getBody()).getLink(IanaLinkRelations.SELF)).isNotNull(); + assertThat(response.getBody().getContent()).hasSize(3); + } + } + + @Nested + @TestInstance(Lifecycle.PER_CLASS) + class UpdateTaskOwnerOfTasks { + + @Test + void should_UpdateTaskOwnerOfReadyTask() { + final String url = restHelper.toUrl("/api/v1/tasks/TKI:000000000000000000000000000000000025"); + HttpEntity auth = new HttpEntity<>(RestHelper.generateHeadersForUser("user-1-2")); + + // retrieve task from Rest Api + ResponseEntity responseGet = + TEMPLATE.exchange(url, HttpMethod.GET, auth, TASK_MODEL_TYPE); + + assertThat(responseGet.getBody()).isNotNull(); + TaskRepresentationModel taskRepresentationModel = responseGet.getBody(); + assertThat(taskRepresentationModel.getState()).isEqualTo(TaskState.READY); + assertThat(taskRepresentationModel.getOwner()).isNull(); + + // set Owner and update Task + taskRepresentationModel.setOwner("dummyUser"); + HttpEntity auth2 = + new HttpEntity<>(taskRepresentationModel, RestHelper.generateHeadersForUser("user-1-2")); + + ResponseEntity responseUpdate = + TEMPLATE.exchange(url, HttpMethod.PUT, auth2, TASK_MODEL_TYPE); + + assertThat(responseUpdate.getBody()).isNotNull(); + TaskRepresentationModel theUpdatedTaskRepresentationModel = responseUpdate.getBody(); + assertThat(theUpdatedTaskRepresentationModel.getState()).isEqualTo(TaskState.READY); + assertThat(theUpdatedTaskRepresentationModel.getOwner()).isEqualTo("dummyUser"); + } + + @Test + void should_ThrowException_When_UpdatingTaskOwnerOfClaimedTask() { + final String url = restHelper.toUrl("/api/v1/tasks/TKI:000000000000000000000000000000000026"); + HttpEntity auth = new HttpEntity<>(RestHelper.generateHeadersForUser("user-1-2")); + + // retrieve task from Rest Api + ResponseEntity responseGet = + TEMPLATE.exchange(url, HttpMethod.GET, auth, TASK_MODEL_TYPE); + + assertThat(responseGet.getBody()).isNotNull(); + TaskRepresentationModel taskRepresentationModel = responseGet.getBody(); + assertThat(taskRepresentationModel.getState()).isEqualTo(TaskState.CLAIMED); + assertThat(taskRepresentationModel.getOwner()).isEqualTo("user-1-1"); + + // set Owner and update Task + taskRepresentationModel.setOwner("dummyuser"); + HttpEntity auth2 = + new HttpEntity<>(taskRepresentationModel, RestHelper.generateHeadersForUser("user-1-2")); + + ThrowingCallable httpCall = + () -> TEMPLATE.exchange(url, HttpMethod.PUT, auth2, TASK_MODEL_TYPE); + + assertThatThrownBy(httpCall) + .isInstanceOf(HttpStatusCodeException.class) + .hasMessageContaining("400"); + } + } + + @Nested + @TestInstance(Lifecycle.PER_CLASS) + class TransferTasks { + @TestFactory + Stream should_SetTransferFlagDependentOnRequestBody_When_TransferringTask() { + Iterator iterator = Arrays.asList(true, false).iterator(); + String url = + restHelper.toUrl( + RestEndpoints.URL_TASKS_ID_TRANSFER_WORKBASKET_ID, + "TKI:000000000000000000000000000000000003", + "WBI:100000000000000000000000000000000006"); + + ThrowingConsumer test = + setTransferFlag -> { + HttpEntity auth = + new HttpEntity<>( + setTransferFlag.toString(), RestHelper.generateHeadersForUser("admin")); + ResponseEntity response = + TEMPLATE.exchange(url, HttpMethod.POST, auth, TASK_MODEL_TYPE); + + assertThat(response.getBody()).isNotNull(); + assertThat(response.getBody().getWorkbasketSummary().getWorkbasketId()) + .isEqualTo("WBI:100000000000000000000000000000000006"); + assertThat(response.getBody().isTransferred()).isEqualTo(setTransferFlag); + }; + + return DynamicTest.stream(iterator, c -> "for setTransferFlag: " + c, test); + } + + @Test + void should_SetTransferFlagToTrue_When_TransferringWithoutRequestBody() { + String url = + restHelper.toUrl( + RestEndpoints.URL_TASKS_ID_TRANSFER_WORKBASKET_ID, + "TKI:000000000000000000000000000000000003", + "WBI:100000000000000000000000000000000006"); + HttpEntity auth = new HttpEntity<>(RestHelper.generateHeadersForUser("admin")); + + ResponseEntity response = + TEMPLATE.exchange(url, HttpMethod.POST, auth, TASK_MODEL_TYPE); + + assertThat(response.getBody()).isNotNull(); + assertThat(response.getBody().getWorkbasketSummary().getWorkbasketId()) + .isEqualTo("WBI:100000000000000000000000000000000006"); + assertThat(response.getBody().isTransferred()).isTrue(); + } + } + + @Nested + @TestInstance(Lifecycle.PER_CLASS) + class RequestChangesOnTasks { + + @Test + void should_RequestChangesOnATask() { + String url = + restHelper.toUrl(RestEndpoints.URL_TASKS_ID, "TKI:000000000000000000000000000000000136"); + HttpEntity auth = new HttpEntity<>(RestHelper.generateHeadersForUser("user-1-1")); + + // retrieve task from Rest Api + ResponseEntity getTaskResponse = + TEMPLATE.exchange(url, HttpMethod.GET, auth, TASK_MODEL_TYPE); + assertThat(getTaskResponse.getBody()).isNotNull(); + TaskRepresentationModel repModel = getTaskResponse.getBody(); + assertThat(repModel.getState()).isEqualTo(TaskState.IN_REVIEW); + assertThat(repModel.getOwner()).isEqualTo("user-1-1"); + + // request changes + String url2 = + restHelper.toUrl( + RestEndpoints.URL_TASKS_ID_REQUEST_CHANGES, + "TKI:000000000000000000000000000000000136"); + ResponseEntity requestedChangesResponse = + TEMPLATE.exchange(url2, HttpMethod.POST, auth, TASK_MODEL_TYPE); + + assertThat(requestedChangesResponse.getBody()).isNotNull(); + assertThat(requestedChangesResponse.getStatusCode()).isEqualTo(HttpStatus.OK); + repModel = requestedChangesResponse.getBody(); + assertThat(repModel.getOwner()).isNull(); + assertThat(repModel.getState()).isEqualTo(TaskState.READY); + } + + @Test + void should_ForceRequestChanges_When_CurrentUserIsNotTheOwner() { + String url = + restHelper.toUrl(RestEndpoints.URL_TASKS_ID, "TKI:000000000000000000000000000000000100"); + HttpEntity auth = new HttpEntity<>(RestHelper.generateHeadersForUser("user-1-1")); + + // retrieve task from Rest Api + ResponseEntity getTaskResponse = + TEMPLATE.exchange(url, HttpMethod.GET, auth, TASK_MODEL_TYPE); + assertThat(getTaskResponse.getBody()).isNotNull(); + TaskRepresentationModel repModel = getTaskResponse.getBody(); + assertThat(repModel.getState()).isEqualTo(TaskState.CLAIMED); + assertThat(repModel.getOwner()).isEqualTo("user-1-2"); + + // request changes + String url2 = + restHelper.toUrl( + RestEndpoints.URL_TASKS_ID_REQUEST_CHANGES_FORCE, + "TKI:000000000000000000000000000000000100"); + ResponseEntity requestedChangesResponse = + TEMPLATE.exchange(url2, HttpMethod.POST, auth, TASK_MODEL_TYPE); + + assertThat(requestedChangesResponse.getBody()).isNotNull(); + assertThat(requestedChangesResponse.getStatusCode()).isEqualTo(HttpStatus.OK); + repModel = requestedChangesResponse.getBody(); + assertThat(repModel.getOwner()).isNull(); + assertThat(repModel.getState()).isEqualTo(TaskState.READY); + } + } + + @Nested + @TestInstance(Lifecycle.PER_CLASS) + class RequestReviewOnTasks { + + @Test + void should_RequestReviewOnATask() { + String url = + restHelper.toUrl(RestEndpoints.URL_TASKS_ID, "TKI:000000000000000000000000000000000035"); + HttpEntity auth = new HttpEntity<>(RestHelper.generateHeadersForUser("user-1-1")); + + // retrieve task from Rest Api + ResponseEntity getTaskResponse = + TEMPLATE.exchange(url, HttpMethod.GET, auth, TASK_MODEL_TYPE); + assertThat(getTaskResponse.getBody()).isNotNull(); + TaskRepresentationModel repModel = getTaskResponse.getBody(); + assertThat(repModel.getState()).isEqualTo(TaskState.CLAIMED); + assertThat(repModel.getOwner()).isEqualTo("user-1-1"); + + // request review + String url2 = + restHelper.toUrl( + RestEndpoints.URL_TASKS_ID_REQUEST_REVIEW, + "TKI:000000000000000000000000000000000035"); + ResponseEntity requestReviewResponse = + TEMPLATE.exchange(url2, HttpMethod.POST, auth, TASK_MODEL_TYPE); + + assertThat(requestReviewResponse.getBody()).isNotNull(); + assertThat(requestReviewResponse.getStatusCode()).isEqualTo(HttpStatus.OK); + repModel = requestReviewResponse.getBody(); + assertThat(repModel.getOwner()).isNull(); + assertThat(repModel.getState()).isEqualTo(TaskState.READY_FOR_REVIEW); + } + + @Test + void should_ForceRequestReview_When_CurrentUserIsNotTheOwner() { + String url = + restHelper.toUrl(RestEndpoints.URL_TASKS_ID, "TKI:000000000000000000000000000000000101"); + HttpEntity auth = new HttpEntity<>(RestHelper.generateHeadersForUser("user-1-1")); + + // retrieve task from Rest Api + ResponseEntity getTaskResponse = + TEMPLATE.exchange(url, HttpMethod.GET, auth, TASK_MODEL_TYPE); + assertThat(getTaskResponse.getBody()).isNotNull(); + TaskRepresentationModel repModel = getTaskResponse.getBody(); + assertThat(repModel.getState()).isEqualTo(TaskState.CLAIMED); + assertThat(repModel.getOwner()).isEqualTo("user-1-2"); + + // request review + String url2 = + restHelper.toUrl( + RestEndpoints.URL_TASKS_ID_REQUEST_REVIEW_FORCE, + "TKI:000000000000000000000000000000000101"); + ResponseEntity requestReviewResponse = + TEMPLATE.exchange(url2, HttpMethod.POST, auth, TASK_MODEL_TYPE); + + assertThat(requestReviewResponse.getBody()).isNotNull(); + assertThat(requestReviewResponse.getStatusCode()).isEqualTo(HttpStatus.OK); + repModel = requestReviewResponse.getBody(); + assertThat(repModel.getOwner()).isNull(); + assertThat(repModel.getState()).isEqualTo(TaskState.READY_FOR_REVIEW); + } + } + + @Nested + @TestInstance(Lifecycle.PER_CLASS) + class CompleteTasks { + @Test + void should_CompleteTask() { + String url = + restHelper.toUrl(RestEndpoints.URL_TASKS_ID, "TKI:000000000000000000000000000000000102"); + HttpEntity auth = new HttpEntity<>(RestHelper.generateHeadersForUser("user-1-2")); + + // retrieve task from Rest Api + ResponseEntity getTaskResponse = + TEMPLATE.exchange(url, HttpMethod.GET, auth, TASK_MODEL_TYPE); + assertThat(getTaskResponse.getBody()).isNotNull(); + TaskRepresentationModel repModel = getTaskResponse.getBody(); + assertThat(repModel.getState()).isEqualTo(TaskState.CLAIMED); + assertThat(repModel.getOwner()).isEqualTo("user-1-2"); + + // complete Task + String url2 = + restHelper.toUrl( + RestEndpoints.URL_TASKS_ID_COMPLETE, "TKI:000000000000000000000000000000000102"); + ResponseEntity completeResponse = + TEMPLATE.exchange(url2, HttpMethod.POST, auth, TASK_MODEL_TYPE); + + assertThat(completeResponse.getBody()).isNotNull(); + assertThat(completeResponse.getStatusCode()).isEqualTo(HttpStatus.OK); + repModel = completeResponse.getBody(); + assertThat(repModel.getOwner()).isEqualTo("user-1-2"); + assertThat(repModel.getState()).isEqualTo(TaskState.COMPLETED); + } + + @Test + void should_ForceCompleteTask_When_CurrentUserIsNotTheOwner() { + String url = + restHelper.toUrl(RestEndpoints.URL_TASKS_ID, "TKI:000000000000000000000000000000000028"); + HttpEntity auth = new HttpEntity<>(RestHelper.generateHeadersForUser("user-1-2")); + + // retrieve task from Rest Api + ResponseEntity getTaskResponse = + TEMPLATE.exchange(url, HttpMethod.GET, auth, TASK_MODEL_TYPE); + assertThat(getTaskResponse.getBody()).isNotNull(); + TaskRepresentationModel repModel = getTaskResponse.getBody(); + assertThat(repModel.getState()).isEqualTo(TaskState.CLAIMED); + assertThat(repModel.getOwner()).isEqualTo("user-1-1"); + + // force complete task + String url2 = + restHelper.toUrl( + RestEndpoints.URL_TASKS_ID_COMPLETE_FORCE, + "TKI:000000000000000000000000000000000028"); + ResponseEntity forceCompleteResponse = + TEMPLATE.exchange(url2, HttpMethod.POST, auth, TASK_MODEL_TYPE); + + assertThat(forceCompleteResponse.getBody()).isNotNull(); + assertThat(forceCompleteResponse.getStatusCode()).isEqualTo(HttpStatus.OK); + repModel = forceCompleteResponse.getBody(); + assertThat(repModel.getOwner()).isEqualTo("user-1-2"); + assertThat(repModel.getState()).isEqualTo(TaskState.COMPLETED); + } + } + + @Nested + @TestInstance(Lifecycle.PER_CLASS) + class CancelTasks { + + @Test + void should_CancelTask() { + String url = + restHelper.toUrl(RestEndpoints.URL_TASKS_ID, "TKI:000000000000000000000000000000000103"); + HttpEntity auth = new HttpEntity<>(RestHelper.generateHeadersForUser("user-1-2")); + + // retrieve task from Rest Api + ResponseEntity responseGet = + TEMPLATE.exchange(url, HttpMethod.GET, auth, TASK_MODEL_TYPE); + + assertThat(responseGet.getBody()).isNotNull(); + TaskRepresentationModel taskRepresentationModel = responseGet.getBody(); + assertThat(taskRepresentationModel.getState()).isEqualTo(TaskState.CLAIMED); + + // cancel the task + String url2 = + restHelper.toUrl( + RestEndpoints.URL_TASKS_ID_CANCEL, "TKI:000000000000000000000000000000000103"); + ResponseEntity cancelResponse = + TEMPLATE.exchange(url2, HttpMethod.POST, auth, TASK_MODEL_TYPE); + + assertThat(cancelResponse.getBody()).isNotNull(); + assertThat(cancelResponse.getBody().getState()).isEqualTo(TaskState.CANCELLED); + } + } + + @Nested + @TestInstance(Lifecycle.PER_CLASS) + class TerminateTasks { + @Test + void should_TerminateTask() { + String url = + restHelper.toUrl(RestEndpoints.URL_TASKS_ID, "TKI:100000000000000000000000000000000000"); + HttpEntity auth = new HttpEntity<>(RestHelper.generateHeadersForUser("admin")); + + // retrieve task from Rest Api + ResponseEntity responseGet = + TEMPLATE.exchange(url, HttpMethod.GET, auth, TASK_MODEL_TYPE); + + assertThat(responseGet.getBody()).isNotNull(); + TaskRepresentationModel taskRepresentationModel = responseGet.getBody(); + assertThat(taskRepresentationModel.getState()).isEqualTo(TaskState.CLAIMED); + + // terminate the task + String url2 = + restHelper.toUrl( + RestEndpoints.URL_TASKS_ID_TERMINATE, "TKI:000000000000000000000000000000000103"); + ResponseEntity terminateResponse = + TEMPLATE.exchange(url2, HttpMethod.POST, auth, TASK_MODEL_TYPE); + + assertThat(terminateResponse.getBody()).isNotNull(); + assertThat(terminateResponse.getBody().getState()).isEqualTo(TaskState.TERMINATED); + } + } + + @Nested + @TestInstance(Lifecycle.PER_CLASS) + class ClaimTasks { + + @Test + void should_ClaimTask() { + String url = + restHelper.toUrl(RestEndpoints.URL_TASKS_ID, "TKI:000000000000000000000000000000000033"); + HttpEntity auth = new HttpEntity<>(RestHelper.generateHeadersForUser("user-1-2")); + + // retrieve task from Rest Api + ResponseEntity getTaskResponse = + TEMPLATE.exchange(url, HttpMethod.GET, auth, TASK_MODEL_TYPE); + assertThat(getTaskResponse.getBody()).isNotNull(); + TaskRepresentationModel readyTaskRepresentationModel = getTaskResponse.getBody(); + assertThat(readyTaskRepresentationModel.getState()).isEqualTo(TaskState.READY); + assertThat(readyTaskRepresentationModel.getOwner()).isEqualTo("user-1-2"); + + // claim + String url2 = + restHelper.toUrl( + RestEndpoints.URL_TASKS_ID_CLAIM, "TKI:000000000000000000000000000000000033"); + ResponseEntity claimResponse = + TEMPLATE.exchange(url2, HttpMethod.POST, auth, TASK_MODEL_TYPE); + + assertThat(claimResponse.getBody()).isNotNull(); + assertThat(claimResponse.getStatusCode()).isEqualTo(HttpStatus.OK); + TaskRepresentationModel claimedTaskRepresentationModel = claimResponse.getBody(); + assertThat(claimedTaskRepresentationModel.getOwner()).isEqualTo("user-1-2"); + assertThat(claimedTaskRepresentationModel.getState()).isEqualTo(TaskState.CLAIMED); + } + + @Test + void should_ForceClaim_When_TaskIsClaimedByDifferentOwner() { + String url = + restHelper.toUrl(RestEndpoints.URL_TASKS_ID, "TKI:000000000000000000000000000000000029"); + HttpEntity auth = new HttpEntity<>(RestHelper.generateHeadersForUser("user-1-1")); + + // retrieve task from Rest Api + ResponseEntity getTaskResponse = + TEMPLATE.exchange(url, HttpMethod.GET, auth, TASK_MODEL_TYPE); + assertThat(getTaskResponse.getBody()).isNotNull(); + TaskRepresentationModel readyTaskRepresentationModel = getTaskResponse.getBody(); + assertThat(readyTaskRepresentationModel.getState()).isEqualTo(TaskState.CLAIMED); + assertThat(readyTaskRepresentationModel.getOwner()).isEqualTo("user-1-2"); + + // claim + String url2 = + restHelper.toUrl( + RestEndpoints.URL_TASKS_ID_CLAIM_FORCE, "TKI:000000000000000000000000000000000029"); + ResponseEntity claimResponse = + TEMPLATE.exchange(url2, HttpMethod.POST, auth, TASK_MODEL_TYPE); + + assertThat(claimResponse.getBody()).isNotNull(); + assertThat(claimResponse.getStatusCode()).isEqualTo(HttpStatus.OK); + TaskRepresentationModel claimedTaskRepresentationModel = claimResponse.getBody(); + assertThat(claimedTaskRepresentationModel.getOwner()).isEqualTo("user-1-1"); + assertThat(claimedTaskRepresentationModel.getState()).isEqualTo(TaskState.CLAIMED); + } + } + + @Nested + @TestInstance(Lifecycle.PER_CLASS) + class CancelClaimTasks { + @Test + void should_CancelClaimTask() { + String url = + restHelper.toUrl(RestEndpoints.URL_TASKS_ID, "TKI:000000000000000000000000000000000032"); + HttpEntity auth = new HttpEntity<>(RestHelper.generateHeadersForUser("user-1-2")); + + // retrieve task from Rest Api + ResponseEntity getTaskResponse = + TEMPLATE.exchange(url, HttpMethod.GET, auth, TASK_MODEL_TYPE); + assertThat(getTaskResponse.getBody()).isNotNull(); + TaskRepresentationModel taskRepresentationModel = getTaskResponse.getBody(); + assertThat(taskRepresentationModel.getState()).isEqualTo(TaskState.CLAIMED); + assertThat(taskRepresentationModel.getOwner()).isEqualTo("user-1-2"); + + // cancel claim + String url2 = + restHelper.toUrl( + RestEndpoints.URL_TASKS_ID_CLAIM, "TKI:000000000000000000000000000000000032"); + ResponseEntity cancelClaimResponse = + TEMPLATE.exchange(url2, HttpMethod.DELETE, auth, TASK_MODEL_TYPE); + + assertThat(cancelClaimResponse.getBody()).isNotNull(); + assertThat(cancelClaimResponse.getStatusCode()).isEqualTo(HttpStatus.OK); + TaskRepresentationModel cancelClaimedtaskRepresentationModel = cancelClaimResponse.getBody(); + assertThat(cancelClaimedtaskRepresentationModel.getOwner()).isNull(); + assertThat(cancelClaimedtaskRepresentationModel.getClaimed()).isNull(); + assertThat(cancelClaimedtaskRepresentationModel.getState()).isEqualTo(TaskState.READY); + } + + @Test + void should_ForceCancelClaim_When_TaskIsClaimedByDifferentOwner() { + String url = + restHelper.toUrl(RestEndpoints.URL_TASKS_ID, "TKI:000000000000000000000000000000000027"); + HttpEntity auth = new HttpEntity<>(RestHelper.generateHeadersForUser("user-1-1")); + + // retrieve task from Rest Api + ResponseEntity getTaskResponse = + TEMPLATE.exchange(url, HttpMethod.GET, auth, TASK_MODEL_TYPE); + assertThat(getTaskResponse.getBody()).isNotNull(); + TaskRepresentationModel taskRepresentationModel = getTaskResponse.getBody(); + assertThat(taskRepresentationModel.getState()).isEqualTo(TaskState.CLAIMED); + assertThat(taskRepresentationModel.getOwner()).isEqualTo("user-1-2"); + + // force cancel claim + String url2 = + restHelper.toUrl( + RestEndpoints.URL_TASKS_ID_CLAIM_FORCE, "TKI:000000000000000000000000000000000027"); + ResponseEntity cancelClaimResponse = + TEMPLATE.exchange(url2, HttpMethod.DELETE, auth, TASK_MODEL_TYPE); + + assertThat(cancelClaimResponse.getBody()).isNotNull(); + assertThat(cancelClaimResponse.getStatusCode()).isEqualTo(HttpStatus.OK); + TaskRepresentationModel cancelClaimedtaskRepresentationModel = cancelClaimResponse.getBody(); + assertThat(cancelClaimedtaskRepresentationModel.getOwner()).isNull(); + assertThat(cancelClaimedtaskRepresentationModel.getClaimed()).isNull(); + assertThat(cancelClaimedtaskRepresentationModel.getState()).isEqualTo(TaskState.READY); + } + + @Test + void should_ThrowException_When_CancelClaimingOfClaimedTaskByAnotherUser() { + String url = + restHelper.toUrl(RestEndpoints.URL_TASKS_ID, "TKI:000000000000000000000000000000000026"); + HttpEntity auth = new HttpEntity<>(RestHelper.generateHeadersForUser("user-1-2")); + + // retrieve task from Rest Api + ResponseEntity responseGet = + TEMPLATE.exchange(url, HttpMethod.GET, auth, TASK_MODEL_TYPE); + + assertThat(responseGet.getBody()).isNotNull(); + TaskRepresentationModel taskRepresentationModel = responseGet.getBody(); + assertThat(taskRepresentationModel.getState()).isEqualTo(TaskState.CLAIMED); + assertThat(taskRepresentationModel.getOwner()).isEqualTo("user-1-1"); + + // try to cancel claim + String url2 = + restHelper.toUrl( + RestEndpoints.URL_TASKS_ID_CLAIM, "TKI:000000000000000000000000000000000026"); + ThrowingCallable httpCall = + () -> TEMPLATE.exchange(url2, HttpMethod.DELETE, auth, TASK_MODEL_TYPE); + + assertThatThrownBy(httpCall) + .extracting(HttpStatusCodeException.class::cast) + .extracting(HttpStatusCodeException::getStatusCode) + .isEqualTo(HttpStatus.BAD_REQUEST); + } + } + + @Nested + @TestInstance(Lifecycle.PER_CLASS) + class SetTasksRead { + @Test + void should_setTaskRead() { + String url = + restHelper.toUrl(RestEndpoints.URL_TASKS_ID, "TKI:000000000000000000000000000000000025"); + HttpEntity auth = new HttpEntity<>(RestHelper.generateHeadersForUser("user-1-2")); + + // retrieve task from Rest Api + ResponseEntity getTaskResponse = + TEMPLATE.exchange(url, HttpMethod.GET, auth, TASK_MODEL_TYPE); + assertThat(getTaskResponse.getBody()).isNotNull(); + TaskRepresentationModel taskRepresentationModel = getTaskResponse.getBody(); + assertThat(taskRepresentationModel.isRead()).isFalse(); + + // set Task read + HttpEntity httpEntity = + new HttpEntity<>( + new IsReadRepresentationModel(true), RestHelper.generateHeadersForUser("user-1-2")); + String url2 = + restHelper.toUrl( + RestEndpoints.URL_TASKS_ID_SET_READ, "TKI:000000000000000000000000000000000025"); + ResponseEntity setReadResponse = + TEMPLATE.exchange(url2, HttpMethod.POST, httpEntity, TASK_MODEL_TYPE); + + assertThat(setReadResponse.getBody()).isNotNull(); + assertThat(setReadResponse.getStatusCode()).isEqualTo(HttpStatus.OK); + TaskRepresentationModel setReadTaskRepresentationModel = setReadResponse.getBody(); + assertThat(setReadTaskRepresentationModel.isRead()).isTrue(); + } + + @Test + void should_setTaskUnread() { + String url = + restHelper.toUrl(RestEndpoints.URL_TASKS_ID, "TKI:000000000000000000000000000000000027"); + HttpEntity auth = new HttpEntity<>(RestHelper.generateHeadersForUser("user-1-2")); + + // retrieve task from Rest Api + ResponseEntity getTaskResponse = + TEMPLATE.exchange(url, HttpMethod.GET, auth, TASK_MODEL_TYPE); + assertThat(getTaskResponse.getBody()).isNotNull(); + TaskRepresentationModel taskRepresentationModel = getTaskResponse.getBody(); + assertThat(taskRepresentationModel.isRead()).isTrue(); + + // set Task unread + HttpEntity httpEntity = + new HttpEntity<>( + new IsReadRepresentationModel(false), RestHelper.generateHeadersForUser("user-1-2")); + String url2 = + restHelper.toUrl( + RestEndpoints.URL_TASKS_ID_SET_READ, "TKI:000000000000000000000000000000000027"); + ResponseEntity setUnreadResponse = + TEMPLATE.exchange(url2, HttpMethod.POST, httpEntity, TASK_MODEL_TYPE); + + assertThat(setUnreadResponse.getBody()).isNotNull(); + assertThat(setUnreadResponse.getStatusCode()).isEqualTo(HttpStatus.OK); + TaskRepresentationModel setReadTaskRepresentationModel = setUnreadResponse.getBody(); + assertThat(setReadTaskRepresentationModel.isRead()).isFalse(); + } + } } diff --git a/rest/taskana-rest-spring/src/test/java/pro/taskana/task/rest/TaskControllerRestDocTest.java b/rest/taskana-rest-spring/src/test/java/pro/taskana/task/rest/TaskControllerRestDocTest.java index dee27db4a..1cc39e835 100644 --- a/rest/taskana-rest-spring/src/test/java/pro/taskana/task/rest/TaskControllerRestDocTest.java +++ b/rest/taskana-rest-spring/src/test/java/pro/taskana/task/rest/TaskControllerRestDocTest.java @@ -19,6 +19,7 @@ import pro.taskana.task.api.TaskService; import pro.taskana.task.api.models.Task; import pro.taskana.task.internal.models.ObjectReferenceImpl; import pro.taskana.task.rest.assembler.TaskRepresentationModelAssembler; +import pro.taskana.task.rest.models.IsReadRepresentationModel; import pro.taskana.task.rest.models.TaskRepresentationModel; @ExtendWith(JaasExtension.class) @@ -34,6 +35,21 @@ class TaskControllerRestDocTest extends BaseRestDocTest { .andExpect(MockMvcResultMatchers.status().isOk()); } + @Test + void deleteTaskDocTest() throws Exception { + mockMvc + .perform(delete(RestEndpoints.URL_TASKS_ID, "TKI:000000000000000000000000000000000039")) + .andExpect(MockMvcResultMatchers.status().isNoContent()); + } + + @Test + void forceDeleteTaskDocTest() throws Exception { + mockMvc + .perform( + delete(RestEndpoints.URL_TASKS_ID_FORCE, "TKI:000000000000000000000000000000000005")) + .andExpect(MockMvcResultMatchers.status().isNoContent()); + } + @Test void deleteTasksDocTest() throws Exception { mockMvc @@ -60,6 +76,15 @@ class TaskControllerRestDocTest extends BaseRestDocTest { .andExpect(MockMvcResultMatchers.status().isOk()); } + @Test + void forceClaimTaskDocTest() throws Exception { + mockMvc + .perform( + post( + RestEndpoints.URL_TASKS_ID_CLAIM_FORCE, "TKI:000000000000000000000000000000000003")) + .andExpect(MockMvcResultMatchers.status().isOk()); + } + @Test void cancelClaimTaskDocTest() throws Exception { mockMvc @@ -139,6 +164,16 @@ class TaskControllerRestDocTest extends BaseRestDocTest { .andExpect(MockMvcResultMatchers.status().isOk()); } + @Test + void forceCompleteTaskDocTest() throws Exception { + mockMvc + .perform( + post( + RestEndpoints.URL_TASKS_ID_COMPLETE_FORCE, + "TKI:000000000000000000000000000000000003")) + .andExpect(MockMvcResultMatchers.status().isOk()); + } + @Test void cancelTaskDocTest() throws Exception { mockMvc @@ -147,6 +182,26 @@ class TaskControllerRestDocTest extends BaseRestDocTest { .andExpect(MockMvcResultMatchers.status().isOk()); } + @Test + void terminateTaskDocTest() throws Exception { + mockMvc + .perform( + post(RestEndpoints.URL_TASKS_ID_TERMINATE, "TKI:000000000000000000000000000000000000")) + .andExpect(MockMvcResultMatchers.status().isOk()); + } + + @Test + void setTaskReadDocTest() throws Exception { + + IsReadRepresentationModel isRead = new IsReadRepresentationModel(true); + + mockMvc + .perform( + post(RestEndpoints.URL_TASKS_ID_SET_READ, "TKI:000000000000000000000000000000000025") + .content(objectMapper.writeValueAsString(isRead))) + .andExpect(MockMvcResultMatchers.status().isOk()); + } + @Test void createTaskDocTest() throws Exception { final Task task = taskService.newTask("WBI:100000000000000000000000000000000004"); @@ -165,13 +220,6 @@ class TaskControllerRestDocTest extends BaseRestDocTest { .andExpect(MockMvcResultMatchers.status().isCreated()); } - @Test - void deleteTaskDocTest() throws Exception { - mockMvc - .perform(delete(RestEndpoints.URL_TASKS_ID, "TKI:000000000000000000000000000000000001")) - .andExpect(MockMvcResultMatchers.status().isNoContent()); - } - @Test void transferTaskDocTest() throws Exception { mockMvc