test(document): add @SpringBootTest smoke tests for lazy-loading correctness
All checks were successful
CI / Unit & Component Tests (pull_request) Successful in 3m2s
CI / OCR Service Tests (pull_request) Successful in 19s
CI / Backend Unit Tests (pull_request) Successful in 3m6s
CI / fail2ban Regex (pull_request) Successful in 42s
CI / Semgrep Security Scan (pull_request) Successful in 19s
CI / Compose Bucket Idempotency (pull_request) Successful in 1m0s

Five integration tests verify that DocumentService and DashboardService
do not throw LazyInitializationException after the EAGER→LAZY migration:
getDocumentById, getRecentActivity, searchDocuments (receiver/sender sort),
and dashboardService.getResume.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
Marcel
2026-05-18 16:55:23 +02:00
parent b8505e0de5
commit e13b37d585

View File

@@ -0,0 +1,158 @@
package org.raddatz.familienarchiv.document;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.Test;
import org.raddatz.familienarchiv.PostgresContainerConfig;
import org.raddatz.familienarchiv.audit.AuditLogQueryService;
import org.raddatz.familienarchiv.dashboard.DashboardService;
import org.raddatz.familienarchiv.person.Person;
import org.raddatz.familienarchiv.person.PersonRepository;
import org.raddatz.familienarchiv.tag.Tag;
import org.raddatz.familienarchiv.tag.TagRepository;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.context.annotation.Import;
import org.springframework.data.domain.PageRequest;
import org.springframework.test.context.ActiveProfiles;
import org.springframework.test.context.bean.override.mockito.MockitoBean;
import software.amazon.awssdk.services.s3.S3Client;
import java.util.HashSet;
import java.util.Optional;
import java.util.Set;
import java.util.UUID;
import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.assertThatCode;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.when;
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.NONE)
@ActiveProfiles("test")
@Import(PostgresContainerConfig.class)
class DocumentLazyLoadingTest {
@MockitoBean
S3Client s3Client;
@Autowired
DocumentRepository documentRepository;
@Autowired
PersonRepository personRepository;
@Autowired
TagRepository tagRepository;
@Autowired
DocumentService documentService;
@Autowired
DashboardService dashboardService;
@MockitoBean
AuditLogQueryService auditLogQueryService;
@AfterEach
void cleanup() {
documentRepository.deleteAll();
tagRepository.deleteAll();
personRepository.deleteAll();
}
@Test
void getDocumentById_tagsAndReceiversAccessible_afterReturnFromService() {
Person sender = personRepository.save(Person.builder().firstName("Max").lastName("LzSender").build());
Person receiver = personRepository.save(Person.builder().firstName("Anna").lastName("LzReceiver").build());
Tag tag = tagRepository.save(Tag.builder().name("LzTag").build());
Document doc = documentRepository.save(Document.builder()
.title("LazyTest").originalFilename("lazy_test.pdf")
.status(DocumentStatus.UPLOADED)
.sender(sender)
.receivers(new HashSet<>(Set.of(receiver)))
.tags(new HashSet<>(Set.of(tag)))
.build());
Document result = documentService.getDocumentById(doc.getId());
assertThatCode(() -> {
assertThat(result.getTags()).isNotEmpty();
result.getTags().forEach(t -> assertThat(t.getName()).isNotNull());
assertThat(result.getReceivers()).isNotEmpty();
result.getReceivers().forEach(r -> assertThat(r.getLastName()).isNotNull());
}).doesNotThrowAnyException();
}
@Test
void getRecentActivity_doesNotThrowLazyInitializationException() {
Person sender = personRepository.save(Person.builder().firstName("Hans").lastName("RaSender").build());
Tag tag = tagRepository.save(Tag.builder().name("RaTag").build());
for (int i = 0; i < 3; i++) {
documentRepository.save(Document.builder()
.title("RaDoc " + i).originalFilename("ra_doc" + i + ".pdf")
.status(DocumentStatus.UPLOADED)
.sender(sender)
.tags(new HashSet<>(Set.of(tag)))
.build());
}
assertThatCode(() -> documentService.getRecentActivity(3))
.doesNotThrowAnyException();
}
@Test
void searchDocuments_receiverSort_doesNotThrowLazyInitializationException() {
Person sender = personRepository.save(Person.builder().firstName("Hans").lastName("SrSender").build());
Person receiver = personRepository.save(Person.builder().firstName("Anna").lastName("SrReceiver").build());
Tag tag = tagRepository.save(Tag.builder().name("SrTag").build());
documentRepository.save(Document.builder()
.title("SrDoc").originalFilename("sr_doc.pdf")
.status(DocumentStatus.UPLOADED)
.sender(sender)
.receivers(new HashSet<>(Set.of(receiver)))
.tags(new HashSet<>(Set.of(tag)))
.build());
assertThatCode(() -> documentService.searchDocuments(
null, null, null, null, null, null, null, null,
DocumentSort.RECEIVER, "asc", null,
PageRequest.of(0, 20)))
.doesNotThrowAnyException();
}
@Test
void searchDocuments_senderSort_doesNotThrowLazyInitializationException() {
Person sender = personRepository.save(Person.builder().firstName("Hans").lastName("SsSender").build());
Tag tag = tagRepository.save(Tag.builder().name("SsTag").build());
documentRepository.save(Document.builder()
.title("SsDoc").originalFilename("ss_doc.pdf")
.status(DocumentStatus.UPLOADED)
.sender(sender)
.tags(new HashSet<>(Set.of(tag)))
.build());
assertThatCode(() -> documentService.searchDocuments(
null, null, null, null, null, null, null, null,
DocumentSort.SENDER, "asc", null,
PageRequest.of(0, 20)))
.doesNotThrowAnyException();
}
@Test
void dashboardService_getResume_accessesReceiversViaGetDocumentById_withoutException() {
Person sender = personRepository.save(Person.builder().firstName("Max").lastName("DsSender").build());
Person receiver = personRepository.save(Person.builder().firstName("Anna").lastName("DsReceiver").build());
Document doc = documentRepository.save(Document.builder()
.title("DashboardTest").originalFilename("dashboard_test.pdf")
.status(DocumentStatus.UPLOADED)
.sender(sender)
.receivers(new HashSet<>(Set.of(receiver)))
.build());
UUID fakeUserId = UUID.randomUUID();
when(auditLogQueryService.findMostRecentDocumentForUser(any())).thenReturn(Optional.of(doc.getId()));
when(auditLogQueryService.findRecentContributorsPerDocument(any())).thenReturn(java.util.Map.of());
assertThatCode(() -> dashboardService.getResume(fakeUserId))
.doesNotThrowAnyException();
}
}