|
|
|
|
@@ -11,7 +11,6 @@ import org.raddatz.familienarchiv.model.Document;
|
|
|
|
|
import org.raddatz.familienarchiv.model.DocumentStatus;
|
|
|
|
|
import org.raddatz.familienarchiv.model.Person;
|
|
|
|
|
import org.raddatz.familienarchiv.model.Tag;
|
|
|
|
|
import org.raddatz.familienarchiv.repository.DocumentRepository;
|
|
|
|
|
import org.springframework.test.util.ReflectionTestUtils;
|
|
|
|
|
import software.amazon.awssdk.core.sync.RequestBody;
|
|
|
|
|
import software.amazon.awssdk.services.s3.S3Client;
|
|
|
|
|
@@ -35,7 +34,7 @@ import static org.mockito.Mockito.*;
|
|
|
|
|
@ExtendWith(MockitoExtension.class)
|
|
|
|
|
class MassImportServiceTest {
|
|
|
|
|
|
|
|
|
|
@Mock DocumentRepository documentRepository;
|
|
|
|
|
@Mock DocumentService documentService;
|
|
|
|
|
@Mock PersonService personService;
|
|
|
|
|
@Mock TagService tagService;
|
|
|
|
|
@Mock S3Client s3Client;
|
|
|
|
|
@@ -45,7 +44,7 @@ class MassImportServiceTest {
|
|
|
|
|
|
|
|
|
|
@BeforeEach
|
|
|
|
|
void setUp() {
|
|
|
|
|
service = new MassImportService(documentRepository, personService, tagService, s3Client, thumbnailAsyncRunner);
|
|
|
|
|
service = new MassImportService(documentService, personService, tagService, s3Client, thumbnailAsyncRunner);
|
|
|
|
|
ReflectionTestUtils.setField(service, "bucketName", "test-bucket");
|
|
|
|
|
ReflectionTestUtils.setField(service, "colIndex", 0);
|
|
|
|
|
ReflectionTestUtils.setField(service, "colBox", 1);
|
|
|
|
|
@@ -96,23 +95,23 @@ class MassImportServiceTest {
|
|
|
|
|
.originalFilename("doc001.pdf")
|
|
|
|
|
.status(DocumentStatus.UPLOADED)
|
|
|
|
|
.build();
|
|
|
|
|
when(documentRepository.findByOriginalFilename("doc001.pdf")).thenReturn(Optional.of(existing));
|
|
|
|
|
when(documentService.findByOriginalFilename("doc001.pdf")).thenReturn(Optional.of(existing));
|
|
|
|
|
|
|
|
|
|
service.importSingleDocument(minimalCells("doc001.pdf"), Optional.empty(), "doc001.pdf", "doc001");
|
|
|
|
|
|
|
|
|
|
verify(documentRepository, never()).save(any());
|
|
|
|
|
verify(documentService, never()).save(any());
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// ─── importSingleDocument — create new document (metadata only) ───────────
|
|
|
|
|
|
|
|
|
|
@Test
|
|
|
|
|
void importSingleDocument_createsNewDocument_whenNotExists() {
|
|
|
|
|
when(documentRepository.findByOriginalFilename("doc002.pdf")).thenReturn(Optional.empty());
|
|
|
|
|
when(documentRepository.save(any())).thenAnswer(inv -> inv.getArgument(0));
|
|
|
|
|
when(documentService.findByOriginalFilename("doc002.pdf")).thenReturn(Optional.empty());
|
|
|
|
|
when(documentService.save(any())).thenAnswer(inv -> inv.getArgument(0));
|
|
|
|
|
|
|
|
|
|
service.importSingleDocument(minimalCells("doc002.pdf"), Optional.empty(), "doc002.pdf", "doc002");
|
|
|
|
|
|
|
|
|
|
verify(documentRepository).save(argThat(d ->
|
|
|
|
|
verify(documentService).save(argThat(d ->
|
|
|
|
|
d.getOriginalFilename().equals("doc002.pdf")
|
|
|
|
|
&& d.getStatus() == DocumentStatus.PLACEHOLDER));
|
|
|
|
|
}
|
|
|
|
|
@@ -126,12 +125,12 @@ class MassImportServiceTest {
|
|
|
|
|
.originalFilename("existing.pdf")
|
|
|
|
|
.status(DocumentStatus.PLACEHOLDER)
|
|
|
|
|
.build();
|
|
|
|
|
when(documentRepository.findByOriginalFilename("existing.pdf")).thenReturn(Optional.of(placeholder));
|
|
|
|
|
when(documentRepository.save(any())).thenAnswer(inv -> inv.getArgument(0));
|
|
|
|
|
when(documentService.findByOriginalFilename("existing.pdf")).thenReturn(Optional.of(placeholder));
|
|
|
|
|
when(documentService.save(any())).thenAnswer(inv -> inv.getArgument(0));
|
|
|
|
|
|
|
|
|
|
service.importSingleDocument(minimalCells("existing.pdf"), Optional.empty(), "existing.pdf", "existing");
|
|
|
|
|
|
|
|
|
|
verify(documentRepository).save(same(placeholder));
|
|
|
|
|
verify(documentService).save(same(placeholder));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// ─── importSingleDocument — with file (S3 upload) ─────────────────────────
|
|
|
|
|
@@ -141,14 +140,14 @@ class MassImportServiceTest {
|
|
|
|
|
Path tempFile = tempDir.resolve("doc003.pdf");
|
|
|
|
|
Files.write(tempFile, "PDF content".getBytes());
|
|
|
|
|
|
|
|
|
|
when(documentRepository.findByOriginalFilename("doc003.pdf")).thenReturn(Optional.empty());
|
|
|
|
|
when(documentRepository.save(any())).thenAnswer(inv -> inv.getArgument(0));
|
|
|
|
|
when(documentService.findByOriginalFilename("doc003.pdf")).thenReturn(Optional.empty());
|
|
|
|
|
when(documentService.save(any())).thenAnswer(inv -> inv.getArgument(0));
|
|
|
|
|
|
|
|
|
|
service.importSingleDocument(
|
|
|
|
|
minimalCells("doc003.pdf"), Optional.of(tempFile.toFile()), "doc003.pdf", "doc003");
|
|
|
|
|
|
|
|
|
|
verify(s3Client).putObject(any(PutObjectRequest.class), any(RequestBody.class));
|
|
|
|
|
verify(documentRepository).save(argThat(d -> d.getStatus() == DocumentStatus.UPLOADED));
|
|
|
|
|
verify(documentService).save(argThat(d -> d.getStatus() == DocumentStatus.UPLOADED));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@Test
|
|
|
|
|
@@ -156,42 +155,42 @@ class MassImportServiceTest {
|
|
|
|
|
Path tempFile = tempDir.resolve("fail.pdf");
|
|
|
|
|
Files.write(tempFile, "data".getBytes());
|
|
|
|
|
|
|
|
|
|
when(documentRepository.findByOriginalFilename("fail.pdf")).thenReturn(Optional.empty());
|
|
|
|
|
when(documentService.findByOriginalFilename("fail.pdf")).thenReturn(Optional.empty());
|
|
|
|
|
doThrow(new RuntimeException("S3 error"))
|
|
|
|
|
.when(s3Client).putObject(any(PutObjectRequest.class), any(RequestBody.class));
|
|
|
|
|
|
|
|
|
|
service.importSingleDocument(
|
|
|
|
|
minimalCells("fail.pdf"), Optional.of(tempFile.toFile()), "fail.pdf", "fail");
|
|
|
|
|
|
|
|
|
|
verify(documentRepository, never()).save(any());
|
|
|
|
|
verify(documentService, never()).save(any());
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// ─── importSingleDocument — sender handling ───────────────────────────────
|
|
|
|
|
|
|
|
|
|
@Test
|
|
|
|
|
void importSingleDocument_setsNullSender_whenSenderCellIsBlank() {
|
|
|
|
|
when(documentRepository.findByOriginalFilename("nosender.pdf")).thenReturn(Optional.empty());
|
|
|
|
|
when(documentRepository.save(any())).thenAnswer(inv -> inv.getArgument(0));
|
|
|
|
|
when(documentService.findByOriginalFilename("nosender.pdf")).thenReturn(Optional.empty());
|
|
|
|
|
when(documentService.save(any())).thenAnswer(inv -> inv.getArgument(0));
|
|
|
|
|
|
|
|
|
|
List<String> cells = buildCells("nosender.pdf", "", "", "");
|
|
|
|
|
service.importSingleDocument(cells, Optional.empty(), "nosender.pdf", "nosender");
|
|
|
|
|
|
|
|
|
|
verify(documentRepository).save(argThat(d -> d.getSender() == null));
|
|
|
|
|
verify(documentService).save(argThat(d -> d.getSender() == null));
|
|
|
|
|
verify(personService, never()).findOrCreateByAlias(any());
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@Test
|
|
|
|
|
void importSingleDocument_createsSender_whenSenderCellIsNonBlank() {
|
|
|
|
|
Person sender = Person.builder().id(UUID.randomUUID()).firstName("Walter").lastName("Müller").build();
|
|
|
|
|
when(documentRepository.findByOriginalFilename("withsender.pdf")).thenReturn(Optional.empty());
|
|
|
|
|
when(documentRepository.save(any())).thenAnswer(inv -> inv.getArgument(0));
|
|
|
|
|
when(documentService.findByOriginalFilename("withsender.pdf")).thenReturn(Optional.empty());
|
|
|
|
|
when(documentService.save(any())).thenAnswer(inv -> inv.getArgument(0));
|
|
|
|
|
when(personService.findOrCreateByAlias("Walter Müller")).thenReturn(sender);
|
|
|
|
|
|
|
|
|
|
List<String> cells = buildCells("withsender.pdf", "Walter Müller", "", "");
|
|
|
|
|
service.importSingleDocument(cells, Optional.empty(), "withsender.pdf", "withsender");
|
|
|
|
|
|
|
|
|
|
verify(personService).findOrCreateByAlias("Walter Müller");
|
|
|
|
|
verify(documentRepository).save(argThat(d -> d.getSender() == sender));
|
|
|
|
|
verify(documentService).save(argThat(d -> d.getSender() == sender));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// ─── importSingleDocument — tag handling ─────────────────────────────────
|
|
|
|
|
@@ -199,8 +198,8 @@ class MassImportServiceTest {
|
|
|
|
|
@Test
|
|
|
|
|
void importSingleDocument_createsTag_whenTagCellIsNonBlank() {
|
|
|
|
|
Tag tag = Tag.builder().id(UUID.randomUUID()).name("Familie").build();
|
|
|
|
|
when(documentRepository.findByOriginalFilename("tagged.pdf")).thenReturn(Optional.empty());
|
|
|
|
|
when(documentRepository.save(any())).thenAnswer(inv -> inv.getArgument(0));
|
|
|
|
|
when(documentService.findByOriginalFilename("tagged.pdf")).thenReturn(Optional.empty());
|
|
|
|
|
when(documentService.save(any())).thenAnswer(inv -> inv.getArgument(0));
|
|
|
|
|
when(tagService.findOrCreate("Familie")).thenReturn(tag);
|
|
|
|
|
|
|
|
|
|
List<String> cells = buildCells("tagged.pdf", "", "", "Familie");
|
|
|
|
|
@@ -211,8 +210,8 @@ class MassImportServiceTest {
|
|
|
|
|
|
|
|
|
|
@Test
|
|
|
|
|
void importSingleDocument_doesNotCreateTag_whenTagCellIsBlank() {
|
|
|
|
|
when(documentRepository.findByOriginalFilename("notag.pdf")).thenReturn(Optional.empty());
|
|
|
|
|
when(documentRepository.save(any())).thenAnswer(inv -> inv.getArgument(0));
|
|
|
|
|
when(documentService.findByOriginalFilename("notag.pdf")).thenReturn(Optional.empty());
|
|
|
|
|
when(documentService.save(any())).thenAnswer(inv -> inv.getArgument(0));
|
|
|
|
|
|
|
|
|
|
List<String> cells = buildCells("notag.pdf", "", "", "");
|
|
|
|
|
service.importSingleDocument(cells, Optional.empty(), "notag.pdf", "notag");
|
|
|
|
|
@@ -225,38 +224,38 @@ class MassImportServiceTest {
|
|
|
|
|
@Test
|
|
|
|
|
void importSingleDocument_metadataComplete_whenSenderPresent() {
|
|
|
|
|
Person sender = Person.builder().id(UUID.randomUUID()).firstName("A").lastName("B").build();
|
|
|
|
|
when(documentRepository.findByOriginalFilename("meta.pdf")).thenReturn(Optional.empty());
|
|
|
|
|
when(documentRepository.save(any())).thenAnswer(inv -> inv.getArgument(0));
|
|
|
|
|
when(documentService.findByOriginalFilename("meta.pdf")).thenReturn(Optional.empty());
|
|
|
|
|
when(documentService.save(any())).thenAnswer(inv -> inv.getArgument(0));
|
|
|
|
|
when(personService.findOrCreateByAlias("A B")).thenReturn(sender);
|
|
|
|
|
|
|
|
|
|
List<String> cells = buildCells("meta.pdf", "A B", "", "");
|
|
|
|
|
service.importSingleDocument(cells, Optional.empty(), "meta.pdf", "meta");
|
|
|
|
|
|
|
|
|
|
verify(documentRepository).save(argThat(Document::isMetadataComplete));
|
|
|
|
|
verify(documentService).save(argThat(Document::isMetadataComplete));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@Test
|
|
|
|
|
void importSingleDocument_metadataIncomplete_whenNoKeyFieldsPresent() {
|
|
|
|
|
when(documentRepository.findByOriginalFilename("nometa.pdf")).thenReturn(Optional.empty());
|
|
|
|
|
when(documentRepository.save(any())).thenAnswer(inv -> inv.getArgument(0));
|
|
|
|
|
when(documentService.findByOriginalFilename("nometa.pdf")).thenReturn(Optional.empty());
|
|
|
|
|
when(documentService.save(any())).thenAnswer(inv -> inv.getArgument(0));
|
|
|
|
|
|
|
|
|
|
List<String> cells = buildCells("nometa.pdf", "", "", "");
|
|
|
|
|
service.importSingleDocument(cells, Optional.empty(), "nometa.pdf", "nometa");
|
|
|
|
|
|
|
|
|
|
verify(documentRepository).save(argThat(d -> !d.isMetadataComplete()));
|
|
|
|
|
verify(documentService).save(argThat(d -> !d.isMetadataComplete()));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// ─── importSingleDocument — blank fields set to null ─────────────────────
|
|
|
|
|
|
|
|
|
|
@Test
|
|
|
|
|
void importSingleDocument_setsBlankFieldsToNull() {
|
|
|
|
|
when(documentRepository.findByOriginalFilename("blank.pdf")).thenReturn(Optional.empty());
|
|
|
|
|
when(documentRepository.save(any())).thenAnswer(inv -> inv.getArgument(0));
|
|
|
|
|
when(documentService.findByOriginalFilename("blank.pdf")).thenReturn(Optional.empty());
|
|
|
|
|
when(documentService.save(any())).thenAnswer(inv -> inv.getArgument(0));
|
|
|
|
|
|
|
|
|
|
List<String> cells = buildCells("blank.pdf", "", "", "");
|
|
|
|
|
service.importSingleDocument(cells, Optional.empty(), "blank.pdf", "blank");
|
|
|
|
|
|
|
|
|
|
verify(documentRepository).save(argThat(d ->
|
|
|
|
|
verify(documentService).save(argThat(d ->
|
|
|
|
|
d.getLocation() == null &&
|
|
|
|
|
d.getSummary() == null &&
|
|
|
|
|
d.getTranscription() == null &&
|
|
|
|
|
@@ -281,13 +280,13 @@ class MassImportServiceTest {
|
|
|
|
|
);
|
|
|
|
|
Integer result = ReflectionTestUtils.invokeMethod(service, "processRows", rows);
|
|
|
|
|
assertThat(result).isEqualTo(0);
|
|
|
|
|
verify(documentRepository, never()).findByOriginalFilename(any());
|
|
|
|
|
verify(documentService, never()).findByOriginalFilename(any());
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@Test
|
|
|
|
|
void processRows_addsExtension_whenIndexHasNoDot() {
|
|
|
|
|
when(documentRepository.findByOriginalFilename("doc001.pdf")).thenReturn(Optional.empty());
|
|
|
|
|
when(documentRepository.save(any())).thenAnswer(inv -> inv.getArgument(0));
|
|
|
|
|
when(documentService.findByOriginalFilename("doc001.pdf")).thenReturn(Optional.empty());
|
|
|
|
|
when(documentService.save(any())).thenAnswer(inv -> inv.getArgument(0));
|
|
|
|
|
|
|
|
|
|
List<List<String>> rows = List.of(
|
|
|
|
|
List.of("header"),
|
|
|
|
|
@@ -296,13 +295,13 @@ class MassImportServiceTest {
|
|
|
|
|
Integer result = ReflectionTestUtils.invokeMethod(service, "processRows", rows);
|
|
|
|
|
|
|
|
|
|
assertThat(result).isEqualTo(1);
|
|
|
|
|
verify(documentRepository).findByOriginalFilename("doc001.pdf");
|
|
|
|
|
verify(documentService).findByOriginalFilename("doc001.pdf");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@Test
|
|
|
|
|
void processRows_usesFilenameAsIs_whenIndexHasDot() {
|
|
|
|
|
when(documentRepository.findByOriginalFilename("doc002.pdf")).thenReturn(Optional.empty());
|
|
|
|
|
when(documentRepository.save(any())).thenAnswer(inv -> inv.getArgument(0));
|
|
|
|
|
when(documentService.findByOriginalFilename("doc002.pdf")).thenReturn(Optional.empty());
|
|
|
|
|
when(documentService.save(any())).thenAnswer(inv -> inv.getArgument(0));
|
|
|
|
|
|
|
|
|
|
List<List<String>> rows = List.of(
|
|
|
|
|
List.of("header"),
|
|
|
|
|
@@ -311,15 +310,15 @@ class MassImportServiceTest {
|
|
|
|
|
Integer result = ReflectionTestUtils.invokeMethod(service, "processRows", rows);
|
|
|
|
|
|
|
|
|
|
assertThat(result).isEqualTo(1);
|
|
|
|
|
verify(documentRepository).findByOriginalFilename("doc002.pdf");
|
|
|
|
|
verify(documentService).findByOriginalFilename("doc002.pdf");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// ─── importSingleDocument — non-blank optional fields ────────────────────
|
|
|
|
|
|
|
|
|
|
@Test
|
|
|
|
|
void importSingleDocument_setsNonNullOptionalFields_whenPresent() {
|
|
|
|
|
when(documentRepository.findByOriginalFilename("rich.pdf")).thenReturn(Optional.empty());
|
|
|
|
|
when(documentRepository.save(any())).thenAnswer(inv -> inv.getArgument(0));
|
|
|
|
|
when(documentService.findByOriginalFilename("rich.pdf")).thenReturn(Optional.empty());
|
|
|
|
|
when(documentService.save(any())).thenAnswer(inv -> inv.getArgument(0));
|
|
|
|
|
|
|
|
|
|
// box=1, folder=2, location=9, summary=11, transcription=13
|
|
|
|
|
List<String> cells = List.of(
|
|
|
|
|
@@ -341,7 +340,7 @@ class MassImportServiceTest {
|
|
|
|
|
|
|
|
|
|
service.importSingleDocument(cells, Optional.empty(), "rich.pdf", "rich");
|
|
|
|
|
|
|
|
|
|
verify(documentRepository).save(argThat(d ->
|
|
|
|
|
verify(documentService).save(argThat(d ->
|
|
|
|
|
"Box A".equals(d.getArchiveBox()) &&
|
|
|
|
|
"Folder B".equals(d.getArchiveFolder()) &&
|
|
|
|
|
"Hamburg".equals(d.getLocation()) &&
|
|
|
|
|
@@ -352,27 +351,27 @@ class MassImportServiceTest {
|
|
|
|
|
@Test
|
|
|
|
|
void importSingleDocument_setsMetadataComplete_whenReceiversArePresent() {
|
|
|
|
|
Person receiver = Person.builder().id(UUID.randomUUID()).firstName("Walter").lastName("Müller").build();
|
|
|
|
|
when(documentRepository.findByOriginalFilename("rcv.pdf")).thenReturn(Optional.empty());
|
|
|
|
|
when(documentRepository.save(any())).thenAnswer(inv -> inv.getArgument(0));
|
|
|
|
|
when(documentService.findByOriginalFilename("rcv.pdf")).thenReturn(Optional.empty());
|
|
|
|
|
when(documentService.save(any())).thenAnswer(inv -> inv.getArgument(0));
|
|
|
|
|
when(personService.findOrCreateByAlias("Walter Müller")).thenReturn(receiver);
|
|
|
|
|
|
|
|
|
|
List<String> cells = List.of(
|
|
|
|
|
"rcv.pdf", "", "", "", "", "Walter Müller", "", "", "", "", "", "", "", "");
|
|
|
|
|
service.importSingleDocument(cells, Optional.empty(), "rcv.pdf", "rcv");
|
|
|
|
|
|
|
|
|
|
verify(documentRepository).save(argThat(Document::isMetadataComplete));
|
|
|
|
|
verify(documentService).save(argThat(Document::isMetadataComplete));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@Test
|
|
|
|
|
void importSingleDocument_setsMetadataComplete_whenDateIsPresent() {
|
|
|
|
|
when(documentRepository.findByOriginalFilename("dated.pdf")).thenReturn(Optional.empty());
|
|
|
|
|
when(documentRepository.save(any())).thenAnswer(inv -> inv.getArgument(0));
|
|
|
|
|
when(documentService.findByOriginalFilename("dated.pdf")).thenReturn(Optional.empty());
|
|
|
|
|
when(documentService.save(any())).thenAnswer(inv -> inv.getArgument(0));
|
|
|
|
|
|
|
|
|
|
List<String> cells = List.of(
|
|
|
|
|
"dated.pdf", "", "", "", "", "", "", "2024-03-15", "", "", "", "", "", "");
|
|
|
|
|
service.importSingleDocument(cells, Optional.empty(), "dated.pdf", "dated");
|
|
|
|
|
|
|
|
|
|
verify(documentRepository).save(argThat(Document::isMetadataComplete));
|
|
|
|
|
verify(documentService).save(argThat(Document::isMetadataComplete));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// ─── buildTitle — null location ───────────────────────────────────────────
|
|
|
|
|
|