From fff26d6a08dd7556afc309ad65f210e183932d73 Mon Sep 17 00:00:00 2001 From: Mustapha Zorgati <15628173+mustaphazorgati@users.noreply.github.com> Date: Fri, 4 Dec 2020 20:49:49 +0100 Subject: [PATCH] TSK-1236: removed links from classification definitions export --- .../api/models/ClassificationSummary.java | 2 +- .../ClassificationDefinitionController.java | 134 +++++++----- ...finitionCollectionRepresentationModel.java | 27 +++ ...efinitionRepresentationModelAssembler.java | 49 +++++ ...ificationRepresentationModelAssembler.java | 23 +- ...ficationDefinitionRepresentationModel.java | 25 +++ ...sificationDefinitionControllerIntTest.java | 204 +++++++++--------- ...WorkbasketDefinitionControllerIntTest.java | 36 +++- 8 files changed, 323 insertions(+), 177 deletions(-) create mode 100644 rest/taskana-rest-spring/src/main/java/pro/taskana/classification/rest/assembler/ClassificationDefinitionCollectionRepresentationModel.java create mode 100644 rest/taskana-rest-spring/src/main/java/pro/taskana/classification/rest/assembler/ClassificationDefinitionRepresentationModelAssembler.java create mode 100644 rest/taskana-rest-spring/src/main/java/pro/taskana/classification/rest/models/ClassificationDefinitionRepresentationModel.java diff --git a/lib/taskana-core/src/main/java/pro/taskana/classification/api/models/ClassificationSummary.java b/lib/taskana-core/src/main/java/pro/taskana/classification/api/models/ClassificationSummary.java index b8f77f6a9..21370790d 100644 --- a/lib/taskana-core/src/main/java/pro/taskana/classification/api/models/ClassificationSummary.java +++ b/lib/taskana-core/src/main/java/pro/taskana/classification/api/models/ClassificationSummary.java @@ -4,7 +4,7 @@ import pro.taskana.classification.api.ClassificationCustomField; /** * Interface for ClassificationSummaries. This is a specific short model-object which only requieres - * the most important informations. Specific ones can be load afterwards via ID. + * the most important information. Specific ones can be load afterwards via ID. */ public interface ClassificationSummary { diff --git a/rest/taskana-rest-spring/src/main/java/pro/taskana/classification/rest/ClassificationDefinitionController.java b/rest/taskana-rest-spring/src/main/java/pro/taskana/classification/rest/ClassificationDefinitionController.java index 2f3002473..209c8c6df 100644 --- a/rest/taskana-rest-spring/src/main/java/pro/taskana/classification/rest/ClassificationDefinitionController.java +++ b/rest/taskana-rest-spring/src/main/java/pro/taskana/classification/rest/ClassificationDefinitionController.java @@ -33,8 +33,9 @@ import pro.taskana.classification.api.exceptions.ClassificationAlreadyExistExcep import pro.taskana.classification.api.exceptions.ClassificationNotFoundException; import pro.taskana.classification.api.models.Classification; import pro.taskana.classification.api.models.ClassificationSummary; -import pro.taskana.classification.rest.assembler.ClassificationRepresentationModelAssembler; -import pro.taskana.classification.rest.models.ClassificationCollectionRepresentationModel; +import pro.taskana.classification.rest.assembler.ClassificationDefinitionCollectionRepresentationModel; +import pro.taskana.classification.rest.assembler.ClassificationDefinitionRepresentationModelAssembler; +import pro.taskana.classification.rest.models.ClassificationDefinitionRepresentationModel; import pro.taskana.classification.rest.models.ClassificationRepresentationModel; import pro.taskana.common.api.exceptions.ConcurrencyException; import pro.taskana.common.api.exceptions.DomainNotFoundException; @@ -52,30 +53,29 @@ public class ClassificationDefinitionController { private final ObjectMapper mapper; private final ClassificationService classificationService; - private final ClassificationRepresentationModelAssembler - classificationRepresentationModelAssembler; + private final ClassificationDefinitionRepresentationModelAssembler assembler; @Autowired ClassificationDefinitionController( ObjectMapper mapper, ClassificationService classificationService, - ClassificationRepresentationModelAssembler classificationRepresentationModelAssembler) { + ClassificationDefinitionRepresentationModelAssembler assembler) { this.mapper = mapper; this.classificationService = classificationService; - this.classificationRepresentationModelAssembler = classificationRepresentationModelAssembler; + this.assembler = assembler; } /** * This endpoint exports all configured Classifications. * - * @title Export Classifications * @param domain Filter the export by domain * @return the configured Classifications. + * @title Export Classifications */ @GetMapping(path = RestEndpoints.URL_CLASSIFICATION_DEFINITIONS) @Transactional(readOnly = true, rollbackFor = Exception.class) - public ResponseEntity exportClassifications( - @RequestParam(required = false) String[] domain) { + public ResponseEntity + exportClassifications(@RequestParam(required = false) String[] domain) { if (LOGGER.isDebugEnabled()) { LOGGER.debug("Entry to exportClassifications(domain= {})", Arrays.toString(domain)); } @@ -84,16 +84,15 @@ public class ClassificationDefinitionController { List summaries = domain != null ? query.domainIn(domain).list() : query.list(); - ClassificationCollectionRepresentationModel collectionModel = + ClassificationDefinitionCollectionRepresentationModel collectionModel = summaries.stream() .map(ClassificationSummary::getId) .map(wrap(classificationService::getClassification)) .collect( Collectors.collectingAndThen( - Collectors.toList(), - classificationRepresentationModelAssembler::toTaskanaCollectionModel)); + Collectors.toList(), assembler::toTaskanaCollectionModel)); - ResponseEntity response = + ResponseEntity response = ResponseEntity.ok(collectionModel); if (LOGGER.isDebugEnabled()) { LOGGER.debug("Exit from exportClassifications(), returning {}", response); @@ -125,7 +124,7 @@ public class ClassificationDefinitionController { DomainNotFoundException, IOException { LOGGER.debug("Entry to importClassifications()"); Map systemIds = getSystemIds(); - ClassificationCollectionRepresentationModel collection = + ClassificationDefinitionCollectionRepresentationModel collection = extractClassificationResourcesFromFile(file); checkForDuplicates(collection.getContent()); @@ -144,17 +143,18 @@ public class ClassificationDefinitionController { Collectors.toMap(i -> i.getKey() + "|" + i.getDomain(), ClassificationSummary::getId)); } - private ClassificationCollectionRepresentationModel extractClassificationResourcesFromFile( - MultipartFile file) throws IOException { + private ClassificationDefinitionCollectionRepresentationModel + extractClassificationResourcesFromFile(MultipartFile file) throws IOException { return mapper.readValue( - file.getInputStream(), ClassificationCollectionRepresentationModel.class); + file.getInputStream(), ClassificationDefinitionCollectionRepresentationModel.class); } private void checkForDuplicates( - Collection classificationList) { + Collection definitionList) { List identifiers = new ArrayList<>(); Set duplicates = new HashSet<>(); - for (ClassificationRepresentationModel classification : classificationList) { + for (ClassificationDefinitionRepresentationModel definition : definitionList) { + ClassificationRepresentationModel classification = definition.getClassification(); String identifier = classification.getKey() + "|" + classification.getDomain(); if (identifiers.contains(identifier)) { duplicates.add(identifier); @@ -169,20 +169,23 @@ public class ClassificationDefinitionController { } private Map mapChildrenToParentKeys( - Collection classificationRepresentationModels, + Collection definitionList, Map systemIds) { LOGGER.debug("Entry to mapChildrenToParentKeys()"); Map childrenInFile = new HashMap<>(); Set newKeysWithDomain = new HashSet<>(); - classificationRepresentationModels.forEach( - cl -> newKeysWithDomain.add(cl.getKey() + "|" + cl.getDomain())); + definitionList.stream() + .map(ClassificationDefinitionRepresentationModel::getClassification) + .forEach(cl -> newKeysWithDomain.add(cl.getKey() + "|" + cl.getDomain())); - for (ClassificationRepresentationModel cl : classificationRepresentationModels) { + for (ClassificationDefinitionRepresentationModel def : definitionList) { + ClassificationRepresentationModel cl = def.getClassification(); cl.setParentId(cl.getParentId() == null ? "" : cl.getParentId()); cl.setParentKey(cl.getParentKey() == null ? "" : cl.getParentKey()); if (!cl.getParentId().equals("") && cl.getParentKey().equals("")) { - for (ClassificationRepresentationModel parent : classificationRepresentationModels) { + for (ClassificationDefinitionRepresentationModel parentDef : definitionList) { + ClassificationRepresentationModel parent = parentDef.getClassification(); if (cl.getParentId().equals(parent.getClassificationId())) { cl.setParentKey(parent.getKey()); } @@ -194,8 +197,7 @@ public class ClassificationDefinitionController { && !cl.getParentKey().equals("") && (newKeysWithDomain.contains(parentKeyAndDomain) || systemIds.containsKey(parentKeyAndDomain)))) { - childrenInFile.put( - classificationRepresentationModelAssembler.toEntityModel(cl), cl.getParentKey()); + childrenInFile.put(assembler.toEntityModel(def), cl.getParentKey()); } } if (LOGGER.isDebugEnabled()) { @@ -206,29 +208,26 @@ public class ClassificationDefinitionController { } private void insertOrUpdateClassificationsWithoutParent( - Collection classificationRepresentationModels, + Collection definitionList, Map systemIds) throws ClassificationNotFoundException, NotAuthorizedException, InvalidArgumentException, ClassificationAlreadyExistException, DomainNotFoundException, ConcurrencyException { LOGGER.debug("Entry to insertOrUpdateClassificationsWithoutParent()"); - for (ClassificationRepresentationModel classificationRepresentationModel : - classificationRepresentationModels) { - classificationRepresentationModel.setParentKey(null); - classificationRepresentationModel.setParentId(null); - classificationRepresentationModel.setClassificationId(null); + for (ClassificationDefinitionRepresentationModel definition : definitionList) { + ClassificationRepresentationModel classificationRepModel = definition.getClassification(); + classificationRepModel.setParentKey(null); + classificationRepModel.setParentId(null); + classificationRepModel.setClassificationId(null); + + Classification newClassification = assembler.toEntityModel(definition); String systemId = - systemIds.get( - classificationRepresentationModel.getKey() - + "|" - + classificationRepresentationModel.getDomain()); + systemIds.get(classificationRepModel.getKey() + "|" + classificationRepModel.getDomain()); if (systemId != null) { - updateExistingClassification(classificationRepresentationModel, systemId); + updateExistingClassification(newClassification, systemId); } else { - classificationService.createClassification( - classificationRepresentationModelAssembler.toEntityModel( - classificationRepresentationModel)); + classificationService.createClassification(newClassification); } } LOGGER.debug("Exit from insertOrUpdateClassificationsWithoutParent()"); @@ -260,31 +259,48 @@ public class ClassificationDefinitionController { LOGGER.debug("Exit from updateParentChildrenRelations()"); } - private void updateExistingClassification(ClassificationRepresentationModel cl, String systemId) + private void updateExistingClassification(Classification newClassification, String systemId) throws ClassificationNotFoundException, NotAuthorizedException, ConcurrencyException, InvalidArgumentException { LOGGER.debug("Entry to updateExistingClassification()"); Classification currentClassification = classificationService.getClassification(systemId); - if (cl.getType() != null && !cl.getType().equals(currentClassification.getType())) { + if (newClassification.getType() != null + && !newClassification.getType().equals(currentClassification.getType())) { throw new InvalidArgumentException("Can not change the type of a classification."); } - currentClassification.setCategory(cl.getCategory()); - currentClassification.setIsValidInDomain(cl.getIsValidInDomain()); - currentClassification.setName(cl.getName()); - currentClassification.setParentId(cl.getParentId()); - currentClassification.setParentKey(cl.getParentKey()); - currentClassification.setDescription(cl.getDescription()); - currentClassification.setPriority(cl.getPriority()); - currentClassification.setServiceLevel(cl.getServiceLevel()); - currentClassification.setApplicationEntryPoint(cl.getApplicationEntryPoint()); - currentClassification.setCustomAttribute(ClassificationCustomField.CUSTOM_1, cl.getCustom1()); - currentClassification.setCustomAttribute(ClassificationCustomField.CUSTOM_2, cl.getCustom2()); - currentClassification.setCustomAttribute(ClassificationCustomField.CUSTOM_3, cl.getCustom3()); - currentClassification.setCustomAttribute(ClassificationCustomField.CUSTOM_4, cl.getCustom4()); - currentClassification.setCustomAttribute(ClassificationCustomField.CUSTOM_5, cl.getCustom5()); - currentClassification.setCustomAttribute(ClassificationCustomField.CUSTOM_6, cl.getCustom6()); - currentClassification.setCustomAttribute(ClassificationCustomField.CUSTOM_7, cl.getCustom7()); - currentClassification.setCustomAttribute(ClassificationCustomField.CUSTOM_8, cl.getCustom8()); + currentClassification.setCategory(newClassification.getCategory()); + currentClassification.setIsValidInDomain(newClassification.getIsValidInDomain()); + currentClassification.setName(newClassification.getName()); + currentClassification.setParentId(newClassification.getParentId()); + currentClassification.setParentKey(newClassification.getParentKey()); + currentClassification.setDescription(newClassification.getDescription()); + currentClassification.setPriority(newClassification.getPriority()); + currentClassification.setServiceLevel(newClassification.getServiceLevel()); + currentClassification.setApplicationEntryPoint(newClassification.getApplicationEntryPoint()); + currentClassification.setCustomAttribute( + ClassificationCustomField.CUSTOM_1, + newClassification.getCustomAttribute(ClassificationCustomField.CUSTOM_1)); + currentClassification.setCustomAttribute( + ClassificationCustomField.CUSTOM_2, + newClassification.getCustomAttribute(ClassificationCustomField.CUSTOM_2)); + currentClassification.setCustomAttribute( + ClassificationCustomField.CUSTOM_3, + newClassification.getCustomAttribute(ClassificationCustomField.CUSTOM_3)); + currentClassification.setCustomAttribute( + ClassificationCustomField.CUSTOM_4, + newClassification.getCustomAttribute(ClassificationCustomField.CUSTOM_4)); + currentClassification.setCustomAttribute( + ClassificationCustomField.CUSTOM_5, + newClassification.getCustomAttribute(ClassificationCustomField.CUSTOM_5)); + currentClassification.setCustomAttribute( + ClassificationCustomField.CUSTOM_6, + newClassification.getCustomAttribute(ClassificationCustomField.CUSTOM_6)); + currentClassification.setCustomAttribute( + ClassificationCustomField.CUSTOM_7, + newClassification.getCustomAttribute(ClassificationCustomField.CUSTOM_7)); + currentClassification.setCustomAttribute( + ClassificationCustomField.CUSTOM_8, + newClassification.getCustomAttribute(ClassificationCustomField.CUSTOM_8)); classificationService.updateClassification(currentClassification); LOGGER.debug("Exit from updateExistingClassification()"); } diff --git a/rest/taskana-rest-spring/src/main/java/pro/taskana/classification/rest/assembler/ClassificationDefinitionCollectionRepresentationModel.java b/rest/taskana-rest-spring/src/main/java/pro/taskana/classification/rest/assembler/ClassificationDefinitionCollectionRepresentationModel.java new file mode 100644 index 000000000..3530136a9 --- /dev/null +++ b/rest/taskana-rest-spring/src/main/java/pro/taskana/classification/rest/assembler/ClassificationDefinitionCollectionRepresentationModel.java @@ -0,0 +1,27 @@ +package pro.taskana.classification.rest.assembler; + +import com.fasterxml.jackson.annotation.JsonProperty; +import java.beans.ConstructorProperties; +import java.util.Collection; + +import pro.taskana.classification.rest.models.ClassificationDefinitionRepresentationModel; +import pro.taskana.common.rest.models.CollectionRepresentationModel; + +public class ClassificationDefinitionCollectionRepresentationModel extends + CollectionRepresentationModel { + + @ConstructorProperties("classifications") + public ClassificationDefinitionCollectionRepresentationModel( + Collection content) { + super(content); + } + + /** + * the embedded classification definitions. + */ + @JsonProperty("classifications") + @Override + public Collection getContent() { + return super.getContent(); + } +} diff --git a/rest/taskana-rest-spring/src/main/java/pro/taskana/classification/rest/assembler/ClassificationDefinitionRepresentationModelAssembler.java b/rest/taskana-rest-spring/src/main/java/pro/taskana/classification/rest/assembler/ClassificationDefinitionRepresentationModelAssembler.java new file mode 100644 index 000000000..e3a22059d --- /dev/null +++ b/rest/taskana-rest-spring/src/main/java/pro/taskana/classification/rest/assembler/ClassificationDefinitionRepresentationModelAssembler.java @@ -0,0 +1,49 @@ +package pro.taskana.classification.rest.assembler; + +import java.util.List; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.hateoas.server.RepresentationModelAssembler; +import org.springframework.lang.NonNull; +import org.springframework.stereotype.Component; + +import pro.taskana.classification.api.models.Classification; +import pro.taskana.classification.rest.models.ClassificationDefinitionRepresentationModel; +import pro.taskana.classification.rest.models.ClassificationRepresentationModel; +import pro.taskana.common.rest.assembler.CollectionRepresentationModelAssembler; + +@Component +public class ClassificationDefinitionRepresentationModelAssembler + implements RepresentationModelAssembler< + Classification, ClassificationDefinitionRepresentationModel>, + CollectionRepresentationModelAssembler< + Classification, + ClassificationDefinitionRepresentationModel, + ClassificationDefinitionCollectionRepresentationModel> { + + private final ClassificationRepresentationModelAssembler classificationAssembler; + + @Autowired + public ClassificationDefinitionRepresentationModelAssembler( + ClassificationRepresentationModelAssembler classificationAssembler) { + this.classificationAssembler = classificationAssembler; + } + + @Override + @NonNull + public ClassificationDefinitionRepresentationModel toModel( + @NonNull Classification classification) { + ClassificationRepresentationModel classificationRepModel = + classificationAssembler.toModel(classification); + return new ClassificationDefinitionRepresentationModel(classificationRepModel); + } + + @Override + public ClassificationDefinitionCollectionRepresentationModel buildCollectionEntity( + List content) { + return new ClassificationDefinitionCollectionRepresentationModel(content); + } + + public Classification toEntityModel(ClassificationDefinitionRepresentationModel repModel) { + return classificationAssembler.toEntityModel(repModel.getClassification()); + } +} diff --git a/rest/taskana-rest-spring/src/main/java/pro/taskana/classification/rest/assembler/ClassificationRepresentationModelAssembler.java b/rest/taskana-rest-spring/src/main/java/pro/taskana/classification/rest/assembler/ClassificationRepresentationModelAssembler.java index 14a3affaf..765ad9090 100644 --- a/rest/taskana-rest-spring/src/main/java/pro/taskana/classification/rest/assembler/ClassificationRepresentationModelAssembler.java +++ b/rest/taskana-rest-spring/src/main/java/pro/taskana/classification/rest/assembler/ClassificationRepresentationModelAssembler.java @@ -40,6 +40,20 @@ public class ClassificationRepresentationModelAssembler @NonNull @Override public ClassificationRepresentationModel toModel(@NonNull Classification classification) { + ClassificationRepresentationModel repModel = toModelWithoutLinks(classification); + try { + repModel.add( + WebMvcLinkBuilder.linkTo( + methodOn(ClassificationController.class) + .getClassification(classification.getId())) + .withSelfRel()); + } catch (ClassificationNotFoundException e) { + throw new SystemException("caught unexpected Exception.", e.getCause()); + } + return repModel; + } + + public ClassificationRepresentationModel toModelWithoutLinks(Classification classification) { ClassificationRepresentationModel repModel = new ClassificationRepresentationModel(); repModel.setClassificationId(classification.getId()); repModel.setApplicationEntryPoint(classification.getApplicationEntryPoint()); @@ -64,15 +78,6 @@ public class ClassificationRepresentationModelAssembler repModel.setCreated(classification.getCreated()); repModel.setModified(classification.getModified()); repModel.setDescription(classification.getDescription()); - try { - repModel.add( - WebMvcLinkBuilder.linkTo( - methodOn(ClassificationController.class) - .getClassification(classification.getId())) - .withSelfRel()); - } catch (ClassificationNotFoundException e) { - throw new SystemException("caught unexpected Exception.", e.getCause()); - } return repModel; } diff --git a/rest/taskana-rest-spring/src/main/java/pro/taskana/classification/rest/models/ClassificationDefinitionRepresentationModel.java b/rest/taskana-rest-spring/src/main/java/pro/taskana/classification/rest/models/ClassificationDefinitionRepresentationModel.java new file mode 100644 index 000000000..b2e8ed5e9 --- /dev/null +++ b/rest/taskana-rest-spring/src/main/java/pro/taskana/classification/rest/models/ClassificationDefinitionRepresentationModel.java @@ -0,0 +1,25 @@ +package pro.taskana.classification.rest.models; + +import com.fasterxml.jackson.annotation.JsonCreator; +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonUnwrapped; +import org.springframework.hateoas.RepresentationModel; + + +public class ClassificationDefinitionRepresentationModel extends + RepresentationModel { + + @JsonIgnoreProperties("_links") + @JsonUnwrapped + private final ClassificationRepresentationModel classification; + + @JsonCreator + public ClassificationDefinitionRepresentationModel( + ClassificationRepresentationModel classification) { + this.classification = classification; + } + + public ClassificationRepresentationModel getClassification() { + return classification; + } +} diff --git a/rest/taskana-rest-spring/src/test/java/pro/taskana/classification/rest/ClassificationDefinitionControllerIntTest.java b/rest/taskana-rest-spring/src/test/java/pro/taskana/classification/rest/ClassificationDefinitionControllerIntTest.java index ebe17205f..694ca975d 100644 --- a/rest/taskana-rest-spring/src/test/java/pro/taskana/classification/rest/ClassificationDefinitionControllerIntTest.java +++ b/rest/taskana-rest-spring/src/test/java/pro/taskana/classification/rest/ClassificationDefinitionControllerIntTest.java @@ -1,6 +1,7 @@ package pro.taskana.classification.rest; import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatCode; import static org.assertj.core.api.Assertions.assertThatThrownBy; import static pro.taskana.common.test.rest.RestHelper.TEMPLATE; @@ -20,6 +21,7 @@ import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.core.ParameterizedTypeReference; import org.springframework.core.io.FileSystemResource; +import org.springframework.hateoas.Links; import org.springframework.http.HttpEntity; import org.springframework.http.HttpHeaders; import org.springframework.http.HttpMethod; @@ -32,10 +34,12 @@ import org.springframework.web.client.HttpClientErrorException; import org.springframework.web.client.HttpStatusCodeException; import pro.taskana.classification.api.ClassificationService; +import pro.taskana.classification.api.exceptions.ClassificationNotFoundException; +import pro.taskana.classification.rest.assembler.ClassificationDefinitionCollectionRepresentationModel; import pro.taskana.classification.rest.assembler.ClassificationRepresentationModelAssembler; import pro.taskana.classification.rest.models.ClassificationCollectionRepresentationModel; +import pro.taskana.classification.rest.models.ClassificationDefinitionRepresentationModel; import pro.taskana.classification.rest.models.ClassificationRepresentationModel; -import pro.taskana.classification.rest.models.ClassificationSummaryRepresentationModel; import pro.taskana.common.rest.RestEndpoints; import pro.taskana.common.test.rest.RestHelper; import pro.taskana.common.test.rest.TaskanaSpringBootTest; @@ -45,9 +49,6 @@ import pro.taskana.common.test.rest.TaskanaSpringBootTest; @TestMethodOrder(OrderAnnotation.class) class ClassificationDefinitionControllerIntTest { - private static final ParameterizedTypeReference - CLASSIFICATION_PAGE_MODEL_TYPE = - new ParameterizedTypeReference() {}; private static final Logger LOGGER = LoggerFactory.getLogger(ClassificationController.class); private final RestHelper restHelper; @@ -69,16 +70,18 @@ class ClassificationDefinitionControllerIntTest { @Test @Order(1) // since the import tests adds Classifications this has to be tested first. - void testExportClassifications() { - ResponseEntity response = + void should_ExportAllClassifications_When_ExportIsRequested() { + ResponseEntity response = TEMPLATE.exchange( restHelper.toUrl(RestEndpoints.URL_CLASSIFICATION_DEFINITIONS) + "?domain=DOMAIN_B", HttpMethod.GET, restHelper.defaultRequest(), - CLASSIFICATION_PAGE_MODEL_TYPE); + ParameterizedTypeReference + .forType(ClassificationDefinitionCollectionRepresentationModel.class)); assertThat(response.getStatusCode()).isEqualTo(HttpStatus.OK); assertThat(response.getBody()).isNotNull(); assertThat(response.getBody().getContent()) + .extracting(ClassificationDefinitionRepresentationModel::getClassification) .extracting(ClassificationRepresentationModel::getClassificationId) .containsExactlyInAnyOrder( "CLI:200000000000000000000000000000000015", @@ -89,27 +92,52 @@ class ClassificationDefinitionControllerIntTest { } @Test - void testExportClassificationsFromWrongDomain() { - ResponseEntity response = + void should_NotContainAnyLinks_When_ExportIsRequested() { + ResponseEntity response = + TEMPLATE.exchange( + restHelper.toUrl(RestEndpoints.URL_CLASSIFICATION_DEFINITIONS) + "?domain=DOMAIN_B", + HttpMethod.GET, + restHelper.defaultRequest(), + ParameterizedTypeReference.forType( + ClassificationDefinitionCollectionRepresentationModel.class)); + assertThat(response.getStatusCode()).isEqualTo(HttpStatus.OK); + assertThat(response.getBody()).isNotNull(); + assertThat(response.getBody().getLinks()).isEmpty(); + assertThat(response.getBody().getContent()) + .extracting(ClassificationDefinitionRepresentationModel::getClassification) + .extracting(ClassificationRepresentationModel::getLinks) + .extracting(Links::isEmpty) + .containsOnly(true); + } + + @Test + void should_ExportNothing_When_DomainIsUnknown() { + ResponseEntity response = TEMPLATE.exchange( restHelper.toUrl(RestEndpoints.URL_CLASSIFICATION_DEFINITIONS) + "?domain=ADdfe", HttpMethod.GET, restHelper.defaultRequest(), - CLASSIFICATION_PAGE_MODEL_TYPE); + ParameterizedTypeReference + .forType(ClassificationDefinitionCollectionRepresentationModel.class)); assertThat(response.getBody()).isNotNull(); assertThat(response.getBody().getContent()).isEmpty(); } @Test - void testImportFilledClassification() throws Exception { + void should_CreateNewClassification_When_ImportContainsUnknownClassification() throws Exception { + String key = "key drelf"; + String domain = "DOMAIN_A"; + assertThatThrownBy(() -> classificationService.getClassification(key, domain)) + .isInstanceOf(ClassificationNotFoundException.class); + ClassificationRepresentationModel classification = new ClassificationRepresentationModel(); classification.setClassificationId("classificationId_"); - classification.setKey("key drelf"); + classification.setKey(key); + classification.setDomain(domain); classification.setParentId("CLI:100000000000000000000000000000000016"); classification.setParentKey("T2000"); classification.setCategory("MANUAL"); classification.setType("TASK"); - classification.setDomain("DOMAIN_A"); classification.setIsValidInDomain(true); classification.setCreated(Instant.parse("2016-05-12T10:12:12.12Z")); classification.setModified(Instant.parse("2018-05-12T10:12:12.12Z")); @@ -132,10 +160,13 @@ class ClassificationDefinitionControllerIntTest { ResponseEntity response = importRequest(clList); assertThat(response.getStatusCode()).isEqualTo(HttpStatus.NO_CONTENT); + + assertThatCode(() -> classificationService.getClassification(key, domain)) + .doesNotThrowAnyException(); } @Test - void testFailureWhenKeyIsMissing() { + void should_ThrowError_When_KeyIsMissingForNewClassification() { ClassificationRepresentationModel classification = new ClassificationRepresentationModel(); classification.setDomain("DOMAIN_A"); ClassificationCollectionRepresentationModel clList = @@ -149,7 +180,7 @@ class ClassificationDefinitionControllerIntTest { } @Test - void testFailureWhenDomainIsMissing() throws Exception { + void should_ThrowError_When_DomainIsMissingForNewClassification() { ClassificationRepresentationModel classification = new ClassificationRepresentationModel(); classification.setKey("one"); ClassificationCollectionRepresentationModel clList = @@ -163,7 +194,7 @@ class ClassificationDefinitionControllerIntTest { } @Test - void testFailureWhenUpdatingTypeOfExistingClassification() throws Exception { + void should_ThrowError_When_ImportModifiesTypeOfExistingClassification() throws Exception { ClassificationRepresentationModel classification = getClassificationWithKeyAndDomain("T6310", ""); classification.setType("DOCUMENT"); @@ -178,7 +209,34 @@ class ClassificationDefinitionControllerIntTest { } @Test - void testImportMultipleClassifications() throws Exception { + void should_ThrowError_When_ImportContainsDuplicateClassification() { + ClassificationRepresentationModel classification1 = new ClassificationRepresentationModel(); + classification1.setClassificationId("id1"); + classification1.setKey("ImportKey3"); + classification1.setDomain("DOMAIN_A"); + + ClassificationCollectionRepresentationModel clList = + new ClassificationCollectionRepresentationModel(List.of(classification1, classification1)); + + assertThatThrownBy(() -> importRequest(clList)) + .isInstanceOf(HttpClientErrorException.class) + .extracting(e -> (HttpClientErrorException) e) + .extracting(HttpStatusCodeException::getStatusCode) + .isEqualTo(HttpStatus.CONFLICT); + } + + @Test + void should_CreateMultipleClassifications_When_ImportContainsMultipleClassifications() + throws Exception { + String key1 = "ImportKey1"; + String key2 = "ImportKey2"; + String domain = "DOMAIN_A"; + + assertThatThrownBy(() -> classificationService.getClassification(key1, domain)) + .isInstanceOf(ClassificationNotFoundException.class); + assertThatThrownBy(() -> classificationService.getClassification(key2, domain)) + .isInstanceOf(ClassificationNotFoundException.class); + ClassificationRepresentationModel classification1 = this.createClassification("id1", "ImportKey1", "DOMAIN_A", null, null); @@ -201,27 +259,15 @@ class ClassificationDefinitionControllerIntTest { ResponseEntity response = importRequest(clList); assertThat(response.getStatusCode()).isEqualTo(HttpStatus.NO_CONTENT); + + assertThatCode(() -> classificationService.getClassification(key1, domain)) + .doesNotThrowAnyException(); + assertThatCode(() -> classificationService.getClassification(key2, domain)) + .doesNotThrowAnyException(); } @Test - void testImportDuplicateClassification() { - ClassificationRepresentationModel classification1 = new ClassificationRepresentationModel(); - classification1.setClassificationId("id1"); - classification1.setKey("ImportKey3"); - classification1.setDomain("DOMAIN_A"); - - ClassificationCollectionRepresentationModel clList = - new ClassificationCollectionRepresentationModel(List.of(classification1, classification1)); - - assertThatThrownBy(() -> importRequest(clList)) - .isInstanceOf(HttpClientErrorException.class) - .extracting(e -> (HttpClientErrorException) e) - .extracting(HttpStatusCodeException::getStatusCode) - .isEqualTo(HttpStatus.CONFLICT); - } - - @Test - void testInsertExistingClassificationWithOlderTimestamp() throws Exception { + void should_IgnoreModifiedTimestamp_When_ImportingClassification() throws Exception { ClassificationRepresentationModel existingClassification = getClassificationWithKeyAndDomain("L110107", "DOMAIN_A"); existingClassification.setName("first new Name"); @@ -229,12 +275,15 @@ class ClassificationDefinitionControllerIntTest { ClassificationCollectionRepresentationModel clList = new ClassificationCollectionRepresentationModel(List.of(existingClassification)); + // first request. Everything normal here ResponseEntity response = importRequest(clList); assertThat(response.getStatusCode()).isEqualTo(HttpStatus.NO_CONTENT); existingClassification.setName("second new Name"); clList = new ClassificationCollectionRepresentationModel(List.of(existingClassification)); + // second request. NOTE: we did not update the modified timestamp of the classification + // we want to import -> import should still work response = importRequest(clList); assertThat(response.getStatusCode()).isEqualTo(HttpStatus.NO_CONTENT); @@ -244,57 +293,27 @@ class ClassificationDefinitionControllerIntTest { } @Test - void testHookExistingChildToNewParent() throws Exception { - final ClassificationRepresentationModel newClassification = - createClassification("new Classification", "newClass", "DOMAIN_A", null, "L11010"); - ClassificationRepresentationModel existingClassification = - getClassificationWithKeyAndDomain("L110102", "DOMAIN_A"); - existingClassification.setParentId("new Classification"); - existingClassification.setParentKey("newClass"); - - ClassificationCollectionRepresentationModel clList = - new ClassificationCollectionRepresentationModel( - List.of(existingClassification, newClassification)); - - ResponseEntity response = importRequest(clList); - assertThat(response.getStatusCode()).isEqualTo(HttpStatus.NO_CONTENT); - - ClassificationSummaryRepresentationModel parentCl = - getClassificationWithKeyAndDomain("L11010", "DOMAIN_A"); - ClassificationSummaryRepresentationModel testNewCl = - getClassificationWithKeyAndDomain("newClass", "DOMAIN_A"); - ClassificationSummaryRepresentationModel testExistingCl = - getClassificationWithKeyAndDomain("L110102", "DOMAIN_A"); - - assertThat(parentCl).isNotNull(); - assertThat(testNewCl).isNotNull(); - assertThat(testExistingCl).isNotNull(); - assertThat(testExistingCl.getParentId()).isEqualTo(testNewCl.getClassificationId()); - assertThat(testNewCl.getParentId()).isEqualTo(parentCl.getClassificationId()); - } - - @Test - void testImportParentAndChildClassification() throws Exception { - ClassificationRepresentationModel classification1 = + void should_KeepParentLink_When_ImportingClassificationsWhichWereLinked() throws Exception { + ClassificationRepresentationModel parent = this.createClassification("parentId", "ImportKey6", "DOMAIN_A", null, null); - ClassificationRepresentationModel classification2 = + ClassificationRepresentationModel child1 = this.createClassification("childId1", "ImportKey7", "DOMAIN_A", null, "ImportKey6"); - ClassificationRepresentationModel classification3 = + ClassificationRepresentationModel child2 = this.createClassification("childId2", "ImportKey8", "DOMAIN_A", "parentId", null); - ClassificationRepresentationModel classification4 = + ClassificationRepresentationModel grandChild1 = this.createClassification( "grandchildId1", "ImportKey9", "DOMAIN_A", "childId1", "ImportKey7"); - ClassificationRepresentationModel classification5 = + ClassificationRepresentationModel grandChild2 = this.createClassification("grandchild2", "ImportKey10", "DOMAIN_A", null, "ImportKey7"); ClassificationCollectionRepresentationModel clList = new ClassificationCollectionRepresentationModel( List.of( - classification1, - classification2, - classification3, - classification4, - classification5)); + parent, + child1, + child2, + grandChild1, + grandChild2)); ResponseEntity response = importRequest(clList); assertThat(response.getStatusCode()).isEqualTo(HttpStatus.NO_CONTENT); @@ -314,7 +333,7 @@ class ClassificationDefinitionControllerIntTest { } @Test - void testImportParentAndChildClassificationWithKey() throws Exception { + void should_LinkParentClassification_When_OnlyParentKeyIsDefinedInImport() throws Exception { ClassificationRepresentationModel parent = createClassification("parent", "ImportKey11", "DOMAIN_A", null, null); parent.setCustom1("parent is correct"); @@ -344,7 +363,8 @@ class ClassificationDefinitionControllerIntTest { } @Test - void testChangeParentByImportingExistingClassification() throws Exception { + void should_OverrideExistingParentLinks_When_ImportLinksExistingClassificationsDifferently() + throws Exception { ClassificationRepresentationModel child1 = this.getClassificationWithKeyAndDomain("L110105", "DOMAIN_A"); assertThat(child1.getParentKey()).isEqualTo("L11010"); @@ -375,20 +395,6 @@ class ClassificationDefinitionControllerIntTest { assertThat(childWithoutParent.getParentKey()).isEqualTo(child2.getParentKey()); } - @Test - void testFailOnImportDuplicates() throws Exception { - ClassificationRepresentationModel classification = - this.getClassificationWithKeyAndDomain("L110105", "DOMAIN_A"); - - ClassificationCollectionRepresentationModel clList = - new ClassificationCollectionRepresentationModel(List.of(classification, classification)); - - assertThatThrownBy(() -> importRequest(clList)) - .isInstanceOf(HttpClientErrorException.class) - .extracting(ex -> ((HttpClientErrorException) ex).getStatusCode()) - .isEqualTo(HttpStatus.CONFLICT); - } - private ClassificationRepresentationModel createClassification( String id, String key, String domain, String parentId, String parentKey) { ClassificationRepresentationModel classificationRepresentationModel = @@ -411,17 +417,17 @@ class ClassificationDefinitionControllerIntTest { throws Exception { LOGGER.debug("Start Import"); File tmpFile = File.createTempFile("test", ".tmp"); - OutputStreamWriter writer = - new OutputStreamWriter(new FileOutputStream(tmpFile), StandardCharsets.UTF_8); - mapper.writeValue(writer, clList); - - MultiValueMap body = new LinkedMultiValueMap<>(); + try (FileOutputStream out = new FileOutputStream(tmpFile); + OutputStreamWriter writer = new OutputStreamWriter(out, StandardCharsets.UTF_8);) { + mapper.writeValue(writer, clList); + } + MultiValueMap body = new LinkedMultiValueMap<>(); + body.add("file", new FileSystemResource(tmpFile)); HttpHeaders headers = restHelper.getHeadersBusinessAdmin(); headers.setContentType(MediaType.MULTIPART_FORM_DATA); - body.add("file", new FileSystemResource(tmpFile)); - HttpEntity> requestEntity = new HttpEntity<>(body, headers); + HttpEntity requestEntity = new HttpEntity<>(body, headers); String serverUrl = restHelper.toUrl(RestEndpoints.URL_CLASSIFICATION_DEFINITIONS); return TEMPLATE.postForEntity(serverUrl, requestEntity, Void.class); diff --git a/rest/taskana-rest-spring/src/test/java/pro/taskana/workbasket/rest/WorkbasketDefinitionControllerIntTest.java b/rest/taskana-rest-spring/src/test/java/pro/taskana/workbasket/rest/WorkbasketDefinitionControllerIntTest.java index fa55001f0..cea2e94dc 100644 --- a/rest/taskana-rest-spring/src/test/java/pro/taskana/workbasket/rest/WorkbasketDefinitionControllerIntTest.java +++ b/rest/taskana-rest-spring/src/test/java/pro/taskana/workbasket/rest/WorkbasketDefinitionControllerIntTest.java @@ -22,6 +22,7 @@ import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Value; import org.springframework.core.ParameterizedTypeReference; import org.springframework.core.io.FileSystemResource; +import org.springframework.hateoas.Links; import org.springframework.http.HttpEntity; import org.springframework.http.HttpHeaders; import org.springframework.http.HttpMethod; @@ -39,6 +40,7 @@ import pro.taskana.common.test.rest.TaskanaSpringBootTest; import pro.taskana.sampledata.SampleDataGenerator; import pro.taskana.workbasket.rest.models.WorkbasketDefinitionCollectionRepresentationModel; import pro.taskana.workbasket.rest.models.WorkbasketDefinitionRepresentationModel; +import pro.taskana.workbasket.rest.models.WorkbasketRepresentationModel; /** Integration tests for WorkbasketDefinitionController. */ @TaskanaSpringBootTest @@ -94,6 +96,20 @@ class WorkbasketDefinitionControllerIntTest { assertThat(allAuthorizationsAreEmpty).isFalse(); } + @Test + void should_NotContainAnyLinks_When_ExportIsRequested() { + ResponseEntity response = + executeExportRequestForDomain("DOMAIN_A"); + assertThat(response.getStatusCode()).isEqualTo(HttpStatus.OK); + assertThat(response.getBody()).isNotNull(); + assertThat(response.getBody().getLinks()).isEmpty(); + assertThat(response.getBody().getContent()) + .extracting(WorkbasketDefinitionRepresentationModel::getWorkbasket) + .extracting(WorkbasketRepresentationModel::getLinks) + .extracting(Links::isEmpty) + .containsOnly(true); + } + @Test void testExportWorkbasketsFromWrongDomain() { ResponseEntity response = @@ -236,9 +252,7 @@ class WorkbasketDefinitionControllerIntTest { WorkbasketDefinitionRepresentationModel w = pagedModel.getContent().iterator().next(); ThrowingCallable httpCall = - () -> { - expectStatusWhenExecutingImportRequestOfWorkbaskets(HttpStatus.CONFLICT, w, w); - }; + () -> expectStatusWhenExecutingImportRequestOfWorkbaskets(HttpStatus.CONFLICT, w, w); assertThatThrownBy(httpCall).isInstanceOf(HttpClientErrorException.class); } @@ -260,7 +274,8 @@ class WorkbasketDefinitionControllerIntTest { restHelper.toUrl(RestEndpoints.URL_WORKBASKET_DEFINITIONS) + "?domain=" + domain, HttpMethod.GET, restHelper.defaultRequest(), - new ParameterizedTypeReference() {}); + ParameterizedTypeReference.forType( + WorkbasketDefinitionCollectionRepresentationModel.class)); } private void expectStatusWhenExecutingImportRequestOfWorkbaskets( @@ -275,15 +290,18 @@ class WorkbasketDefinitionControllerIntTest { HttpStatus expectedStatus, WorkbasketDefinitionCollectionRepresentationModel pageModel) throws Exception { File tmpFile = File.createTempFile("test", ".tmp"); - try (OutputStreamWriter writer = new OutputStreamWriter(new FileOutputStream(tmpFile), UTF_8)) { + try (FileOutputStream out = new FileOutputStream(tmpFile); + OutputStreamWriter writer = new OutputStreamWriter(out, UTF_8)) { objMapper.writeValue(writer, pageModel); } - MultiValueMap body = new LinkedMultiValueMap<>(); - HttpHeaders headers = restHelper.getHeadersBusinessAdmin(); - headers.setContentType(MediaType.MULTIPART_FORM_DATA); + + MultiValueMap body = new LinkedMultiValueMap<>(); body.add("file", new FileSystemResource(tmpFile)); - HttpEntity> requestEntity = new HttpEntity<>(body, headers); + HttpHeaders headers = restHelper.getHeadersBusinessAdmin(); + headers.setContentType(MediaType.MULTIPART_FORM_DATA); + + HttpEntity requestEntity = new HttpEntity<>(body, headers); String serverUrl = restHelper.toUrl(RestEndpoints.URL_WORKBASKET_DEFINITIONS); ResponseEntity responseImport =