Skip to content
Snippets Groups Projects
Commit 3541499e authored by Jan Zickermann's avatar Jan Zickermann
Browse files

Merge branch 'OZG-8070-Map-primaryFormData' into 'main'

Ozg 8070 map primary form data

See merge request !6
parents 34a73cc3 814bb341
Branches
Tags
1 merge request!6Ozg 8070 map primary form data
Pipeline #2442 passed
......@@ -23,95 +23,51 @@
*/
package de.ozgcloud.eingang.intelliform;
import static java.util.stream.Collectors.*;
import java.io.IOException;
import java.time.ZonedDateTime;
import java.util.Collection;
import java.util.GregorianCalendar;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.Set;
import java.util.UUID;
import java.util.stream.Collectors;
import java.util.stream.IntStream;
import java.util.stream.Stream;
import javax.xml.datatype.XMLGregorianCalendar;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import org.springframework.stereotype.Component;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.NodeList;
import org.xml.sax.SAXException;
import de.ozgcloud.common.binaryfile.TempFileUtils;
import de.ozgcloud.eingang.common.errorhandling.TechnicalException;
import de.ozgcloud.eingang.common.formdata.FormData;
import de.ozgcloud.eingang.common.formdata.FormData.FormDataControl;
import de.ozgcloud.eingang.common.formdata.IncomingFile;
import de.ozgcloud.eingang.common.formdata.IncomingFileGroup;
import lombok.RequiredArgsConstructor;
@Component
@RequiredArgsConstructor
class DepositDataMapper {
// TODO Resolve code duplication (xta-adapter:
// de.ozgcloud.eingang.xdomea.XMLHelper)
private static final DocumentBuilder DOCUMENT_BUILDER = createDocumentBuilder();
private static DocumentBuilder createDocumentBuilder() {
var documentBuilderFactory = DocumentBuilderFactory.newInstance();
try {
documentBuilderFactory.setFeature("http://apache.org/xml/features/disallow-doctype-decl", true);
return documentBuilderFactory.newDocumentBuilder();
} catch (ParserConfigurationException e) {
throw new TechnicalException("Failed to configure document builder", e);
}
}
public FormData mapToFormData(DepositData depositData) {
var incomingFileMap = mapDepositAttachmentsToSortedIncomingFiles(depositData);
var document = parsePrimaryXmlRepresentation(depositData, incomingFileMap);
var attachmentGroups = findAttachmentGroups(document);
var formData = mapToFormDataWithRepresentationsAndAttachments(
getRepresentations(incomingFileMap, getAttachmentFileIds(attachmentGroups)),
getAttachmentFileGroups(attachmentGroups, incomingFileMap));
var classification = mapDepositIncomingFiles(depositData)
.classifyFiles();
return formData.toBuilder()
.control(FormDataControl.builder().metaData(Optional.of(buildMetaData(depositData))).build())
.build();
}
private List<String> getAttachmentFileIds(Map<String, List<String>> attachmentGroups) {
return attachmentGroups.values().stream()
.flatMap(Collection::stream)
.toList();
}
var attachments = classification.getAttachmentIncomingFileGroups();
var representations = classification.getRepresentationIncomingFiles();
private FormData mapToFormDataWithRepresentationsAndAttachments(
List<IncomingFile> representations,
List<IncomingFileGroup> attachments) {
return FormData.builder()
.attachments(attachments)
.numberOfAttachments(attachments.size())
.representations(representations)
.numberOfRepresentations(representations.size())
.control(FormDataControl.builder()
.metaData(Optional.of(buildMetaData(depositData)))
.representations(Optional.of(buildControlRepresentations(classification)))
.build())
.build();
}
Map<String, IncomingFile> mapDepositAttachmentsToSortedIncomingFiles(DepositData depositData) {
var incomingFilesMap = mapDepositAttachmentsToIncomingFiles(depositData);
var primaryId = depositData.getPrimaryDataAttachmentId();
incomingFilesMap.putFirst(primaryId, getIncomingFileById(primaryId, incomingFilesMap));
return incomingFilesMap;
DepositIncomingFiles mapDepositIncomingFiles(DepositData depositData) {
return DepositIncomingFiles.builder()
.primaryFormDataFileVendorId(depositData.getPrimaryDataAttachmentId())
.incomingFileMap(mapDepositAttachmentsToIncomingFiles(depositData))
.build();
}
private LinkedHashMap<String, IncomingFile> mapDepositAttachmentsToIncomingFiles(DepositData depositData) {
......@@ -136,62 +92,6 @@ class DepositDataMapper {
.build();
}
private Document parsePrimaryXmlRepresentation(DepositData depositData, Map<String, IncomingFile> incomingFileMap) {
// Expect that the <primaryDataAttachmentId> refers to the XML file
return parseDocument(
getIncomingFileById(depositData.getPrimaryDataAttachmentId(), incomingFileMap));
}
private static Document parseDocument(IncomingFile incomingFile) {
try (var inputStream = incomingFile.getContentStream()) {
return DOCUMENT_BUILDER.parse(inputStream);
} catch (SAXException | IOException e) {
throw new TechnicalException("Failed to parse xml document!", e);
}
}
Map<String, List<String>> findAttachmentGroups(Document document) {
return streamElements(document.getElementsByTagName("file"))
.collect(groupingBy(
element -> element.getParentNode().getNodeName(),
mapping(
element -> element.getAttribute("id"),
toList())));
}
private List<IncomingFileGroup> getAttachmentFileGroups(Map<String, List<String>> attachmentGroups, Map<String, IncomingFile> incomingFileMap) {
return attachmentGroups.entrySet().stream()
.map(entry -> IncomingFileGroup.builder()
.name(entry.getKey())
.files(entry.getValue().stream().map(id -> getIncomingFileById(id, incomingFileMap)).toList())
.build())
.toList();
}
private List<IncomingFile> getRepresentations(Map<String, IncomingFile> incomingFileMap, List<String> attachmentFileIds) {
return getNamesWithout(incomingFileMap.keySet(), attachmentFileIds).stream()
.map(id -> getIncomingFileById(id, incomingFileMap))
.toList();
}
private IncomingFile getIncomingFileById(String id, Map<String, IncomingFile> incomingFileMap) {
if (!incomingFileMap.containsKey(id)) {
throw new TechnicalException("Failed to find <file> attachment ID '%s' in deposit data!".formatted(id));
}
return incomingFileMap.get(id);
}
private List<String> getNamesWithout(Collection<String> names, Collection<String> excludedStrings) {
var excludedStringsSet = Set.copyOf(excludedStrings);
return names.stream().filter(name -> !excludedStringsSet.contains(name)).toList();
}
private Stream<Element> streamElements(NodeList nodeList) {
return IntStream.range(0, nodeList.getLength())
.mapToObj(nodeList::item)
.map(Element.class::cast);
}
IntelliFormMetaData buildMetaData(DepositData depositData) {
var builder = IntelliFormMetaData.builder();
getOrigin(depositData).ifPresent(builder::origin);
......@@ -203,7 +103,16 @@ class DepositDataMapper {
}
Optional<ZonedDateTime> getOrigin(DepositData depositData) {
return Optional.ofNullable(depositData.getTimestamp()).map(XMLGregorianCalendar::toGregorianCalendar).map(GregorianCalendar::toZonedDateTime);
return Optional.ofNullable(depositData.getTimestamp())
.map(XMLGregorianCalendar::toGregorianCalendar)
.map(GregorianCalendar::toZonedDateTime);
}
FormData.Representations buildControlRepresentations(DepositIncomingFilesClassification classification) {
return FormData.Representations.builder()
.primaryFormDataRepresentation(classification.primaryFormDataFileName())
.primaryFormDataPdfRepresentation(classification.primaryFormDataPdfFileName())
.build();
}
}
package de.ozgcloud.eingang.intelliform;
import static java.util.stream.Collectors.*;
import java.io.IOException;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.IntStream;
import java.util.stream.Stream;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.NodeList;
import org.xml.sax.SAXException;
import de.ozgcloud.eingang.common.errorhandling.TechnicalException;
import de.ozgcloud.eingang.common.formdata.IncomingFile;
import lombok.Builder;
@Builder
record DepositIncomingFiles(
String primaryFormDataFileVendorId,
LinkedHashMap<String, IncomingFile> incomingFileMap
) {
private static final DocumentBuilder DOCUMENT_BUILDER = createDocumentBuilder();
public IncomingFile getIncomingFileByVendorId(String vendorId) {
if (!incomingFileMap.containsKey(vendorId)) {
throw new TechnicalException("Failed to find <file> attachment ID '%s' in deposit data!".formatted(vendorId));
}
return incomingFileMap.get(vendorId);
}
public DepositIncomingFilesClassification classifyFiles() {
return DepositIncomingFilesClassification.builder()
.attachmentGroups(findAttachmentGroups(parsePrimaryXmlRepresentation()))
.incomingFiles(this)
.build();
}
private Map<String, List<String>> findAttachmentGroups(Document document) {
return streamElements(document.getElementsByTagName("file"))
.collect(groupingBy(
element -> element.getParentNode().getNodeName(),
mapping(
element -> element.getAttribute("id"),
toList())));
}
private Stream<Element> streamElements(NodeList nodeList) {
return IntStream.range(0, nodeList.getLength())
.mapToObj(nodeList::item)
.map(Element.class::cast);
}
private Document parsePrimaryXmlRepresentation() {
return parseDocument(getIncomingFileByVendorId(primaryFormDataFileVendorId));
}
private static DocumentBuilder createDocumentBuilder() {
var documentBuilderFactory = DocumentBuilderFactory.newInstance();
try {
documentBuilderFactory.setFeature("http://apache.org/xml/features/disallow-doctype-decl", true);
return documentBuilderFactory.newDocumentBuilder();
} catch (ParserConfigurationException e) {
throw new TechnicalException("Failed to configure document builder", e);
}
}
private static Document parseDocument(IncomingFile incomingFile) {
try (var inputStream = incomingFile.getContentStream()) {
return DOCUMENT_BUILDER.parse(inputStream);
} catch (SAXException | IOException e) {
throw new TechnicalException("Failed to parse xml document!", e);
}
}
}
package de.ozgcloud.eingang.intelliform;
import java.util.Collection;
import java.util.List;
import java.util.Map;
import java.util.Set;
import de.ozgcloud.eingang.common.formdata.IncomingFile;
import de.ozgcloud.eingang.common.formdata.IncomingFileGroup;
import lombok.Builder;
@Builder
record DepositIncomingFilesClassification(
Map<String, List<String>> attachmentGroups,
DepositIncomingFiles incomingFiles
) {
public String primaryFormDataPdfFileName() {
return getRepresentationIncomingFiles().stream()
.map(IncomingFile::getName)
.filter(name -> name.endsWith(".pdf"))
.findFirst()
.orElse("");
}
public String primaryFormDataFileName() {
return incomingFiles.getIncomingFileByVendorId(incomingFiles.primaryFormDataFileVendorId()).getName();
}
public List<IncomingFileGroup> getAttachmentIncomingFileGroups() {
return attachmentGroups.entrySet().stream()
.map(entry -> IncomingFileGroup.builder()
.name(entry.getKey())
.files(entry.getValue().stream()
.map(incomingFiles::getIncomingFileByVendorId)
.toList())
.build())
.toList();
}
public List<IncomingFile> getRepresentationIncomingFiles() {
return getNamesWithout(incomingFiles.incomingFileMap().keySet(), getAttachmentFileIds()).stream()
.map(incomingFiles::getIncomingFileByVendorId)
.toList();
}
private List<String> getAttachmentFileIds() {
return attachmentGroups.values().stream()
.flatMap(Collection::stream)
.toList();
}
private List<String> getNamesWithout(Collection<String> names, Collection<String> excludedStrings) {
var excludedStringsSet = Set.copyOf(excludedStrings);
return names.stream()
.filter(name -> !excludedStringsSet.contains(name))
.toList();
}
}
......@@ -25,21 +25,15 @@ package de.ozgcloud.eingang.intelliform;
import static de.ozgcloud.eingang.intelliform.AttachmentTestFactory.*;
import static de.ozgcloud.eingang.intelliform.DepositDataTestFactory.*;
import static java.util.Collections.*;
import static org.assertj.core.api.Assertions.*;
import static org.mockito.ArgumentMatchers.*;
import static org.mockito.Mockito.*;
import java.io.IOException;
import java.io.StringReader;
import java.nio.charset.Charset;
import java.time.ZonedDateTime;
import java.time.temporal.ChronoUnit;
import java.util.List;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import org.apache.commons.io.FileUtils;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.DisplayName;
......@@ -47,16 +41,12 @@ import org.junit.jupiter.api.Nested;
import org.junit.jupiter.api.Test;
import org.mockito.ArgumentCaptor;
import org.mockito.Captor;
import org.mockito.Mock;
import org.mockito.Spy;
import org.w3c.dom.Document;
import org.xml.sax.InputSource;
import org.xml.sax.SAXException;
import de.ozgcloud.eingang.common.errorhandling.TechnicalException;
import de.ozgcloud.eingang.common.formdata.FormData;
import de.ozgcloud.eingang.common.formdata.IncomingFile;
import de.ozgcloud.eingang.common.formdata.IncomingFileGroup;
import de.ozgcloud.eingang.intelliform.AttachmentTestFactory.MetaAttachment;
import lombok.SneakyThrows;
class DepositDataMapperTest {
......@@ -68,266 +58,177 @@ class DepositDataMapperTest {
@Nested
class TestMapToFormData {
@Captor
private ArgumentCaptor<Attachment> attachmentArgumentCaptor;
private final DepositData depositData = DepositDataTestFactory.create();
private DepositData depositData;
@Mock
private IntelliFormMetaData intelliFormMetaData;
@Mock
private FormData.Representations controlRepresentations;
@Mock
private DepositIncomingFiles depositIncomingFiles;
@Mock
private DepositIncomingFilesClassification classification;
@Mock
private IncomingFileGroup attachmentIncomingFileGroup;
@Mock
private IncomingFile represenationIncomingFile;
@DisplayName("with normal attachments")
@Nested
class TestWithNormalAttachments {
@BeforeEach
void mock() {
depositData = DepositDataTestFactory.create(ATTACHMENTS);
doReturn(depositIncomingFiles).when(mapper).mapDepositIncomingFiles(any());
when(depositIncomingFiles.classifyFiles()).thenReturn(classification);
when(classification.getAttachmentIncomingFileGroups()).thenReturn(List.of(attachmentIncomingFileGroup));
when(classification.getRepresentationIncomingFiles()).thenReturn(List.of(represenationIncomingFile));
doReturn(intelliFormMetaData).when(mapper).buildMetaData(any());
doReturn(controlRepresentations).when(mapper).buildControlRepresentations(any());
}
@DisplayName("should throw technical exception if primary xml link is incorrect")
@DisplayName("should call mapDepositIncomingFiles")
@Test
void shouldThrowTechnicalExceptionIfPrimaryXmlLinkIsIncorrect() {
depositData.setPrimaryDataAttachmentId("incorrect");
void shouldCallMapDepositIncomingFiles() {
doMapping();
assertThatThrownBy(TestMapToFormData.this::doMapping)
.isInstanceOf(TechnicalException.class);
verify(mapper).mapDepositIncomingFiles(depositData);
}
@DisplayName("should use map to incoming file method")
@DisplayName("should call classifyFiles")
@Test
void shouldUseMapToIncomingFileMethod() {
void shouldCallClassifyFiles() {
doMapping();
verify(mapper, times(ATTACHMENTS.size())).mapAttachmentToIncomingFile(attachmentArgumentCaptor.capture());
assertThat(attachmentArgumentCaptor.getAllValues()).isEqualTo(ATTACHMENTS);
verify(depositIncomingFiles).classifyFiles();
}
@DisplayName("should return with representations")
@DisplayName("should call getAttachmentIncomingFileGroups")
@Test
void shouldReturnWithRepresentations() {
var formData = doMapping();
void shouldCallGetAttachmentIncomingFileGroups() {
doMapping();
var incomingFileIds = formData.getRepresentations().stream().map(IncomingFile::getVendorId).toList();
assertThat(incomingFileIds).containsExactly(XML_ATTACHMENT_ID, PDF_ATTACHMENT_ID);
verify(classification).getAttachmentIncomingFileGroups();
}
@DisplayName("should return with one attachment")
@DisplayName("should call getRepresentationIncomingFiles")
@Test
void shouldReturnWithOneAttachment() {
var formData = doMapping();
void shouldCallGetRepresentationIncomingFiles() {
doMapping();
var incomingFileIds = formData.getAttachments().stream()
.flatMap(group -> group.getFiles().stream())
.map(IncomingFile::getVendorId)
.toList();
assertThat(incomingFileIds).containsExactly(PNG_ATTACHMENT_ID);
verify(classification).getRepresentationIncomingFiles();
}
@DisplayName("should return with attachment group name")
@DisplayName("should map representations")
@Test
void shouldReturnWithAttachmentGroupName() {
void shouldMapRepresentations() {
var formData = doMapping();
var incomingFileIds = formData.getAttachments().stream()
.map(IncomingFileGroup::getName)
.toList();
assertThat(incomingFileIds).containsExactly("Upload1");
assertThat(formData.getRepresentations()).containsExactly(represenationIncomingFile);
}
@DisplayName("should return with number of representations")
@DisplayName("should map numberOfRepresentations")
@Test
void shouldReturnWithNumberOfRepresentations() {
void shouldMapNumberOfRepresentations() {
var formData = doMapping();
assertThat(formData.getNumberOfRepresentations()).isEqualTo(2);
}
assertThat(formData.getNumberOfRepresentations()).isEqualTo(1);
}
@DisplayName("with duplicate keys")
@Nested
class TestWithDuplicateKeys {
@BeforeEach
void mock() {
depositData = DepositDataTestFactory.create(List.of(
withEmptyName(createXmlDaten()),
createXmlDaten(),
withEmptyName(createPdf()),
createPdf(),
withEmptyName(createPng()),
createPng()));
}
@DisplayName("should call buildMetaData")
@Test
void shouldCallBuildMetaData() {
doMapping();
private Attachment withEmptyName(Attachment attachment) {
attachment.setName("");
return attachment;
verify(mapper).buildMetaData(depositData);
}
@DisplayName("should keep last entry for representations")
@DisplayName("should map control metadata")
@Test
void shouldKeepLastEntryForRepresentations() {
void shouldMapControlMetadata() {
var formData = doMapping();
var representationFiles = formData.getRepresentations();
assertThat(getAttachmentVendorIds(representationFiles)).containsExactly(XML_ATTACHMENT_ID, PDF_ATTACHMENT_ID);
assertThat(getAttachmentFileNames(representationFiles)).containsExactly(XML_NAME, PDF_ATTACHMENT_NAME);
assertThat(formData.getControl().getMetaData()).contains(intelliFormMetaData);
}
@DisplayName("should keep last entry for attachments")
@DisplayName("should call buildControlRepresentations")
@Test
void shouldKeepLastEntryForAttachments() {
var formData = doMapping();
void shouldCallBuildControlRepresentations() {
doMapping();
var attachmentFiles = formData.getAttachments().stream()
.map(IncomingFileGroup::getFiles)
.flatMap(List::stream)
.toList();
assertThat(getAttachmentVendorIds(attachmentFiles)).containsExactly(PNG_ATTACHMENT_ID);
assertThat(getAttachmentFileNames(attachmentFiles)).containsExactly(PNG_ATTACHMENT_NAME);
verify(mapper).buildControlRepresentations(classification);
}
private List<String> getAttachmentFileNames(List<IncomingFile> incomingFileList) {
return incomingFileList.stream()
.map(IncomingFile::getName)
.toList();
}
@DisplayName("should map control representations")
@Test
void shouldMapControlRepresentations() {
var formData = doMapping();
private List<String> getAttachmentVendorIds(List<IncomingFile> incomingFileList) {
return incomingFileList.stream()
.map(IncomingFile::getVendorId)
.toList();
}
assertThat(formData.getControl().getRepresentations()).contains(controlRepresentations);
}
@DisplayName("with many attachments")
@Nested
class TestWithManyAttachments {
@BeforeEach
void mock() {
depositData = DepositDataTestFactory.create(MANY_ATTACHMENTS);
private FormData doMapping() {
return mapper.mapToFormData(depositData);
}
@DisplayName("should return with representations")
@Test
void shouldReturnWithRepresentations() {
var formData = doMapping();
var incomingFileIds = formData.getRepresentations().stream()
.map(IncomingFile::getVendorId)
.toList();
assertThat(incomingFileIds).containsExactly(
XML_ATTACHMENT_ID,
XML_ROHFORM_ATTACHMENT_ID,
XML_ORIGINALFORM_ATTACHMENT_ID);
}
@DisplayName("should return with attachment groups")
@Test
void shouldReturnWithAttachmentGroups() {
var formData = doMapping();
var incomingFileIds = formData.getAttachments().stream()
.flatMap(group -> group.getFiles().stream())
.map(IncomingFile::getVendorId)
.toList();
assertThat(incomingFileIds).containsExactlyInAnyOrder(
DOCX1_ATTACHMENT_ID,
PDF_ATTACHMENT_ID,
DOCX2_ATTACHMENT_ID,
DOCX3_ATTACHMENT_ID,
DOCX4_ATTACHMENT_ID,
DOCX5_ATTACHMENT_ID,
DOCX6_ATTACHMENT_ID,
DOCX7_ATTACHMENT_ID,
DOCX8_ATTACHMENT_ID,
PDF2_ATTACHMENT_ID,
ODT_ATTACHMENT_ID,
JPG_ATTACHMENT_ID,
PNG_ATTACHMENT_ID);
}
}
@DisplayName("with empty attachments")
@DisplayName("map DepositIncomingFiles")
@Nested
class TestWithEmptyAttachments {
@DisplayName("should throw technical exception")
@Test
void shouldThrowTechnicalException() {
depositData = DepositDataTestFactory.create(emptyList());
class TestMapDepositIncomingFiles {
private final DepositData depositData = DepositDataTestFactory.create(ATTACHMENTS);
assertThatThrownBy(TestMapToFormData.this::doMapping)
.isInstanceOf(TechnicalException.class);
}
}
@Mock
private IncomingFile incomingFile1;
@Test
void shouldAddMetaData() {
depositData = DepositDataTestFactory.create();
@Mock
private IncomingFile incomingFile2;
doMapping();
@Mock
private IncomingFile incomingFile3;
verify(mapper).buildMetaData(any());
}
@Captor
private ArgumentCaptor<Attachment> attachmentArgumentCaptor;
private FormData doMapping() {
return mapper.mapToFormData(depositData);
@BeforeEach
void mock() {
doReturn(incomingFile1, incomingFile2, incomingFile3).when(mapper).mapAttachmentToIncomingFile(any());
}
}
@DisplayName("should call mapAttachmentToIncomingFile")
@Test
void shouldCallMapAttachmentToIncomingFile() {
mapper.mapDepositIncomingFiles(depositData);
@DisplayName("map deposit attachments to sorted incoming files")
@Nested
class TestMapDepositAttachmentsToSortedIncomingFiles {
verify(mapper, times(ATTACHMENTS.size())).mapAttachmentToIncomingFile(attachmentArgumentCaptor.capture());
assertThat(attachmentArgumentCaptor.getAllValues())
.extracting(Attachment::getId)
.containsExactly(XML_ATTACHMENT_ID, PDF_ATTACHMENT_ID, PNG_ATTACHMENT_ID);
}
@DisplayName("should fail without primaryDataAttachmentId attachment")
@DisplayName("should map to attachment groups")
@Test
void shouldFailWithoutPrimaryDataAttachmentIdAttachment() {
var depositData = DepositDataTestFactory.create(emptyList());
void shouldMapToAttachmentGroups() {
var result = mapper.mapDepositIncomingFiles(depositData);
assertThatThrownBy(() -> mapper.mapDepositAttachmentsToSortedIncomingFiles(depositData))
.isInstanceOf(TechnicalException.class);
assertThat(result.primaryFormDataFileVendorId()).isEqualTo(XML_ATTACHMENT_ID);
}
@DisplayName("should keep entry order")
@DisplayName("should map vendorId keys")
@Test
void shouldKeepEntryOrder() {
var depositData = DepositDataTestFactory.create(ATTACHMENTS);
var incomingFileMap = mapper.mapDepositAttachmentsToSortedIncomingFiles(depositData);
void shouldMapVendorIdKeys() {
var result = mapper.mapDepositIncomingFiles(depositData);
var keys = incomingFileMap.keySet().stream().toList();
assertThat(keys).containsExactly(XML_ATTACHMENT_ID, PDF_ATTACHMENT_ID, PNG_ATTACHMENT_ID);
assertThat(result.incomingFileMap()).containsOnlyKeys(XML_ATTACHMENT_ID, PDF_ATTACHMENT_ID, PNG_ATTACHMENT_ID);
}
@DisplayName("should move primary attachment id to first position")
@Test
void shouldMovePrimaryAttachmentIdToFirstPosition() {
var rohformId = "XML-daten-rohform";
var depositData = DepositDataTestFactory.create(List.of(
AttachmentTestFactory.createAttachment(MetaAttachment.builder()
.id(rohformId)
.name("XML-Daten (Rohform).xml")
.contentType(XML_CONTENT_TYPE)
.content("abc")
.build()),
AttachmentTestFactory.createPdf(),
AttachmentTestFactory.createXmlDaten(),
AttachmentTestFactory.createPng()));
var incomingFileMap = mapper.mapDepositAttachmentsToSortedIncomingFiles(depositData);
var keys = incomingFileMap.keySet().stream().toList();
assertThat(keys).containsExactly(XML_ATTACHMENT_ID, rohformId, PDF_ATTACHMENT_ID, PNG_ATTACHMENT_ID);
}
@DisplayName("should keep last entry for duplicate key")
@DisplayName("should map incoming file values")
@Test
void shouldKeepLastEntryForDuplicateKey() {
var depositData = DepositDataTestFactory.create(List.of(
AttachmentTestFactory.createXmlDaten(),
AttachmentTestFactory.createPdf(),
AttachmentTestFactory.createXmlDaten()));
void shouldMapIncomingFileValues() {
var result = mapper.mapDepositIncomingFiles(depositData);
var incomingFileMap = mapper.mapDepositAttachmentsToSortedIncomingFiles(depositData);
var keys = incomingFileMap.keySet().stream().toList();
assertThat(keys).containsExactly(XML_ATTACHMENT_ID, PDF_ATTACHMENT_ID);
assertThat(result.incomingFileMap()).containsValues(incomingFile1, incomingFile2, incomingFile3);
}
}
......@@ -396,62 +297,6 @@ class DepositDataMapperTest {
}
}
@DisplayName("find attachment groups")
@Nested
class TestFindAttachmentGroups {
private Document document;
@BeforeEach
void mock() {
document = buildXMLDocument("""
<myForm t:client-id="land">
<Upload1>
<file content-type="image/png" description="" id="VendorId3333" length="155251">Image.png</file>
</Upload1>
<Upload2>
<file id="VendorId1111">name1.txt</file>
<file id="VendorId2222">name2.txt</file>
</Upload2>
<file id="VendorIdxxxx">namex.txt</file>
</myForm>""");
}
@DisplayName("should have groups with parent element name")
@Test
void shouldHaveGroupsWithParentElementName() {
var attachmentGroups = mapper.findAttachmentGroups(document);
assertThat(attachmentGroups).containsOnlyKeys("Upload1", "Upload2", "myForm");
}
@DisplayName("should have Upload1 group with fileId")
@Test
void shouldHaveUpload1GroupWithFileId() {
var attachmentGroups = mapper.findAttachmentGroups(document);
assertThat(attachmentGroups.get("Upload1")).containsExactly("VendorId3333");
}
@DisplayName("should have two fileIds in Upload2 group")
@Test
void shouldHaveTwoFileIdsInUpload2Group() {
var attachmentGroups = mapper.findAttachmentGroups(document);
assertThat(attachmentGroups.get("Upload2")).containsExactly("VendorId1111", "VendorId2222");
}
}
private Document buildXMLDocument(String xmlString) {
try {
return DocumentBuilderFactory.newInstance()
.newDocumentBuilder()
.parse(new InputSource(new StringReader(xmlString)));
} catch (ParserConfigurationException | IOException | SAXException e) {
throw new RuntimeException(e);
}
}
@Nested
class TestBuildMetaData {
......@@ -487,4 +332,37 @@ class DepositDataMapperTest {
}
}
@DisplayName("build control representations")
@Nested
class TestBuildControlRepresentations {
@Mock
private DepositIncomingFilesClassification classification;
private final String primaryFormDataFileName = "primaryFormDataFile.xml";
private final String primaryFormDataPdfFileName = "primaryFormDataPdfFile.pdf";
@BeforeEach
void mock() {
when(classification.primaryFormDataFileName()).thenReturn(primaryFormDataFileName);
when(classification.primaryFormDataPdfFileName()).thenReturn(primaryFormDataPdfFileName);
}
@DisplayName("should map primaryFormDataRepresentation")
@Test
void shouldMapPrimaryFormDataRepresentation() {
var representations = mapper.buildControlRepresentations(classification);
assertThat(representations.getPrimaryFormDataRepresentation()).isEqualTo(primaryFormDataFileName);
}
@DisplayName("should map primaryFormDataPdfRepresentation")
@Test
void shouldMapPrimaryFormDataPdfRepresentation() {
var representations = mapper.buildControlRepresentations(classification);
assertThat(representations.getPrimaryFormDataPdfRepresentation()).isEqualTo(primaryFormDataPdfFileName);
}
}
}
package de.ozgcloud.eingang.intelliform;
import static de.ozgcloud.eingang.intelliform.AttachmentTestFactory.*;
import static de.ozgcloud.eingang.intelliform.DepositIncomingFilesTestFactory.*;
import static org.assertj.core.api.Assertions.*;
import java.util.List;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Nested;
import org.junit.jupiter.api.Test;
import de.ozgcloud.eingang.common.formdata.IncomingFile;
import de.ozgcloud.eingang.common.formdata.IncomingFileGroup;
class DepositIncomingFilesClassificationTest {
private final DepositIncomingFilesClassification classification = DepositIncomingFilesTestFactory.create()
.classifyFiles();
@DisplayName("get attachment incoming file groups")
@Nested
class TestGetAttachmentIncomingFileGroups {
@DisplayName("should map to three groups")
@Test
void shouldMapAttachmentGroupsToIncomingFileGroups() {
var result = getAttachmentIncomingFileGroups();
assertThat(result)
.extracting(IncomingFileGroup::getName).containsOnly("Upload1", "Upload2", "myForm");
}
@DisplayName("should map incoming files")
@Test
void shouldMapIncomingFiles() {
var result = getAttachmentIncomingFileGroups();
assertThat(result)
.flatExtracting(IncomingFileGroup::getFiles)
.extracting(IncomingFile::getId)
.containsOnly(PNG_FILE_ID, DOCX1_FILE_ID, DOCX2_FILE_ID, DOCX3_FILE_ID);
}
private List<IncomingFileGroup> getAttachmentIncomingFileGroups() {
return classification.getAttachmentIncomingFileGroups();
}
}
@DisplayName("get representation incoming files")
@Nested
class TestGetRepresentationIncomingFiles {
@DisplayName("should map to two files")
@Test
void shouldMapToTwoFiles() {
var result = getRepresentationIncomingFiles();
assertThat(result)
.extracting(IncomingFile::getId)
.containsOnly(XML_FILE_ID, PDF_FILE_ID);
}
private List<IncomingFile> getRepresentationIncomingFiles() {
return classification.getRepresentationIncomingFiles();
}
}
@DisplayName("primaryFormDataFileName")
@Nested
class TestPrimaryFormDataFileName {
@DisplayName("should return")
@Test
void shouldReturn() {
var result = classification.primaryFormDataFileName();
assertThat(result).isEqualTo(XML_FILE_NAME);
}
}
@DisplayName("primaryFormDataPdfFileName")
@Nested
class TestPrimaryFormDataPdfFileName {
@DisplayName("should return")
@Test
void shouldReturn() {
var result = classification.primaryFormDataPdfFileName();
assertThat(result).isEqualTo(PDF_ATTACHMENT_NAME);
}
@DisplayName("should return empty string if no PDF file is found")
@Test
void shouldReturnEmptyStringIfNoPdfFileIsFound() {
var incomingFilesMap = DepositIncomingFilesTestFactory.create().incomingFileMap();
incomingFilesMap.remove(PDF_ATTACHMENT_ID);
var faultyDepositIncomingFiles = DepositIncomingFilesTestFactory.createBuilder()
.incomingFileMap(incomingFilesMap)
.build()
.classifyFiles();
var result = faultyDepositIncomingFiles.primaryFormDataPdfFileName();
assertThat(result).isEmpty();
}
}
}
\ No newline at end of file
package de.ozgcloud.eingang.intelliform;
import static de.ozgcloud.eingang.intelliform.AttachmentTestFactory.*;
import static de.ozgcloud.eingang.intelliform.DepositIncomingFilesTestFactory.*;
import static org.assertj.core.api.Assertions.*;
import java.util.LinkedHashMap;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Nested;
import org.junit.jupiter.api.Test;
import de.ozgcloud.eingang.common.errorhandling.TechnicalException;
import de.ozgcloud.eingang.common.formdata.IncomingFile;
class DepositIncomingFilesTest {
private final DepositIncomingFiles depositIncomingFiles = DepositIncomingFilesTestFactory.create();
@DisplayName("classify files")
@Nested
class TestClassifyFiles {
@DisplayName("should have groups with parent element name")
@Test
void shouldHaveGroupsWithParentElementName() {
var result = classifyFiles();
assertThat(result.attachmentGroups()).containsOnlyKeys("Upload1", "Upload2", "myForm");
}
@DisplayName("should map one file to Upload1 group")
@Test
void shouldMapOneFileToUpload1Group() {
var result = classifyFiles();
assertThat(result.attachmentGroups().get("Upload1")).containsExactly(PNG_ATTACHMENT_ID);
}
@DisplayName("should map two files to Upload2 group")
@Test
void shouldMapTwoFilesToUpload2Group() {
var result = classifyFiles();
assertThat(result.attachmentGroups().get("Upload2")).containsExactly(DOCX1_ATTACHMENT_ID, DOCX2_ATTACHMENT_ID);
}
@DisplayName("should map one file to myForm group")
@Test
void shouldMapOneFileToMyFormGroup() {
var result = classifyFiles();
assertThat(result.attachmentGroups().get("myForm")).containsExactly(DOCX3_ATTACHMENT_ID);
}
@DisplayName("should have incoming files")
@Test
void shouldHaveIncomingFiles() {
var result = classifyFiles();
assertThat(result.incomingFiles()).isEqualTo(depositIncomingFiles);
}
@DisplayName("should throw technical exception with empty attachments")
@Test
void shouldThrowTechnicalExceptionWithEmptyAttachments() {
var faultyDepositIncomingFiles = DepositIncomingFilesTestFactory.createBuilder()
.incomingFileMap(new LinkedHashMap<>())
.build();
assertThatThrownBy(faultyDepositIncomingFiles::classifyFiles)
.isInstanceOf(TechnicalException.class);
}
@DisplayName("should throw technical exception if primary xml link is incorrect")
@Test
void shouldThrowTechnicalExceptionIfPrimaryXmlLinkIsIncorrect() {
var faultyDepositData = DepositIncomingFilesTestFactory.createBuilder()
.primaryFormDataFileVendorId("incorrect")
.build();
assertThatThrownBy(faultyDepositData::classifyFiles)
.isInstanceOf(TechnicalException.class);
}
private DepositIncomingFilesClassification classifyFiles() {
return depositIncomingFiles.classifyFiles();
}
}
@DisplayName("get incoming file by vendorId")
@Nested
class TestGetIncomingFileByVendorId {
@DisplayName("should return")
@Test
void shouldReturn() {
var result = depositIncomingFiles.getIncomingFileByVendorId(XML_ATTACHMENT_ID);
assertThat(result)
.extracting(IncomingFile::getId)
.isEqualTo(XML_FILE_ID);
}
@DisplayName("should throw technical exception if vendor ID is not found")
@Test
void shouldThrowTechnicalExceptionIfVendorIdIsNotFound() {
assertThatThrownBy(() -> depositIncomingFiles.getIncomingFileByVendorId("incorrect"))
.isInstanceOf(TechnicalException.class);
}
}
}
\ No newline at end of file
package de.ozgcloud.eingang.intelliform;
import static de.ozgcloud.eingang.intelliform.AttachmentTestFactory.*;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.UUID;
import de.ozgcloud.common.binaryfile.TempFileUtils;
import de.ozgcloud.eingang.common.formdata.IncomingFileTestFactory;
class DepositIncomingFilesTestFactory {
static final String XML_FILE_ID = UUID.randomUUID().toString();
static final String PDF_FILE_ID = UUID.randomUUID().toString();
static final String PNG_FILE_ID = UUID.randomUUID().toString();
static final String DOCX1_FILE_ID = UUID.randomUUID().toString();
static final String DOCX2_FILE_ID = UUID.randomUUID().toString();
static final String DOCX3_FILE_ID = UUID.randomUUID().toString();
static final String XML_MY_FORM_CONTENT = """
<myForm t:client-id="land">
<Upload1>
<file content-type="image/png" description="" id="%s" length="155251">Image.png</file>
</Upload1>
<Upload2>
<file id="%s">name1.txt</file>
<file id="%s">name2.txt</file>
</Upload2>
<file id="%s">namex.txt</file>
</myForm>""".formatted(
PNG_ATTACHMENT_ID,
DOCX1_ATTACHMENT_ID,
DOCX2_ATTACHMENT_ID,
DOCX3_ATTACHMENT_ID
);
static DepositIncomingFiles create() {
return createBuilder().build();
}
static DepositIncomingFiles.DepositIncomingFilesBuilder createBuilder() {
return DepositIncomingFiles.builder()
.primaryFormDataFileVendorId(XML_ATTACHMENT_ID)
.incomingFileMap(new LinkedHashMap<>(Map.of(
XML_ATTACHMENT_ID, IncomingFileTestFactory.createBuilder()
.id(XML_FILE_ID)
.vendorId(XML_ATTACHMENT_ID)
.name(XML_FILE_NAME)
.file(TempFileUtils.writeTmpFile(XML_MY_FORM_CONTENT))
.build(),
PDF_ATTACHMENT_ID, IncomingFileTestFactory.createBuilder()
.id(PDF_FILE_ID)
.vendorId(PDF_ATTACHMENT_ID)
.name(PDF_ATTACHMENT_NAME)
.build(),
PNG_ATTACHMENT_ID, IncomingFileTestFactory.createBuilder()
.id(PNG_FILE_ID)
.name(PNG_ATTACHMENT_NAME)
.vendorId(PNG_ATTACHMENT_ID)
.build(),
DOCX1_ATTACHMENT_ID, IncomingFileTestFactory.createBuilder()
.id(DOCX1_FILE_ID)
.vendorId(DOCX1_ATTACHMENT_ID)
.build(),
DOCX2_ATTACHMENT_ID, IncomingFileTestFactory.createBuilder()
.id(DOCX2_FILE_ID)
.vendorId(DOCX2_ATTACHMENT_ID)
.build(),
DOCX3_ATTACHMENT_ID, IncomingFileTestFactory.createBuilder()
.id(DOCX3_FILE_ID)
.vendorId(DOCX3_ATTACHMENT_ID)
.build()
)));
}
}
......@@ -177,7 +177,7 @@ class FormDataEndpointITCase {
var representationVendorIds = eingang.getRepresentationsList().stream()
.map(GrpcIncomingFile::getVendorId)
.toList();
assertThat(representationVendorIds).containsExactly(
assertThat(representationVendorIds).containsExactlyInAnyOrder(
XML_ATTACHMENT_ID,
XML_ROHFORM_ATTACHMENT_ID,
XML_ORIGINALFORM_ATTACHMENT_ID);
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment