TSK-1236: removed links from classification definitions export

This commit is contained in:
Mustapha Zorgati 2020-12-04 20:49:49 +01:00
parent 727b3ba3b5
commit fff26d6a08
8 changed files with 323 additions and 177 deletions

View File

@ -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 {

View File

@ -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<ClassificationCollectionRepresentationModel> exportClassifications(
@RequestParam(required = false) String[] domain) {
public ResponseEntity<ClassificationDefinitionCollectionRepresentationModel>
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<ClassificationSummary> 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<ClassificationCollectionRepresentationModel> response =
ResponseEntity<ClassificationDefinitionCollectionRepresentationModel> 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<String, String> 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<ClassificationRepresentationModel> classificationList) {
Collection<ClassificationDefinitionRepresentationModel> definitionList) {
List<String> identifiers = new ArrayList<>();
Set<String> 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<Classification, String> mapChildrenToParentKeys(
Collection<ClassificationRepresentationModel> classificationRepresentationModels,
Collection<ClassificationDefinitionRepresentationModel> definitionList,
Map<String, String> systemIds) {
LOGGER.debug("Entry to mapChildrenToParentKeys()");
Map<Classification, String> childrenInFile = new HashMap<>();
Set<String> 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<ClassificationRepresentationModel> classificationRepresentationModels,
Collection<ClassificationDefinitionRepresentationModel> definitionList,
Map<String, String> 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()");
}

View File

@ -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<ClassificationDefinitionRepresentationModel> {
@ConstructorProperties("classifications")
public ClassificationDefinitionCollectionRepresentationModel(
Collection<ClassificationDefinitionRepresentationModel> content) {
super(content);
}
/**
* the embedded classification definitions.
*/
@JsonProperty("classifications")
@Override
public Collection<ClassificationDefinitionRepresentationModel> getContent() {
return super.getContent();
}
}

View File

@ -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<ClassificationDefinitionRepresentationModel> content) {
return new ClassificationDefinitionCollectionRepresentationModel(content);
}
public Classification toEntityModel(ClassificationDefinitionRepresentationModel repModel) {
return classificationAssembler.toEntityModel(repModel.getClassification());
}
}

View File

@ -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;
}

View File

@ -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<ClassificationDefinitionRepresentationModel> {
@JsonIgnoreProperties("_links")
@JsonUnwrapped
private final ClassificationRepresentationModel classification;
@JsonCreator
public ClassificationDefinitionRepresentationModel(
ClassificationRepresentationModel classification) {
this.classification = classification;
}
public ClassificationRepresentationModel getClassification() {
return classification;
}
}

View File

@ -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<ClassificationCollectionRepresentationModel>
CLASSIFICATION_PAGE_MODEL_TYPE =
new ParameterizedTypeReference<ClassificationCollectionRepresentationModel>() {};
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<ClassificationCollectionRepresentationModel> response =
void should_ExportAllClassifications_When_ExportIsRequested() {
ResponseEntity<ClassificationDefinitionCollectionRepresentationModel> 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<ClassificationCollectionRepresentationModel> response =
void should_NotContainAnyLinks_When_ExportIsRequested() {
ResponseEntity<ClassificationDefinitionCollectionRepresentationModel> 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<ClassificationDefinitionCollectionRepresentationModel> 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<Void> 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<Void> 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<Void> 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<Void> 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<Void> 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);
try (FileOutputStream out = new FileOutputStream(tmpFile);
OutputStreamWriter writer = new OutputStreamWriter(out, StandardCharsets.UTF_8);) {
mapper.writeValue(writer, clList);
MultiValueMap<String, Object> body = new LinkedMultiValueMap<>();
}
MultiValueMap<String, FileSystemResource> 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<MultiValueMap<String, Object>> 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);

View File

@ -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<WorkbasketDefinitionCollectionRepresentationModel> 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<WorkbasketDefinitionCollectionRepresentationModel> 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<WorkbasketDefinitionCollectionRepresentationModel>() {});
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<String, Object> body = new LinkedMultiValueMap<>();
HttpHeaders headers = restHelper.getHeadersBusinessAdmin();
headers.setContentType(MediaType.MULTIPART_FORM_DATA);
MultiValueMap<String, FileSystemResource> body = new LinkedMultiValueMap<>();
body.add("file", new FileSystemResource(tmpFile));
HttpEntity<MultiValueMap<String, Object>> 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<Void> responseImport =