refactor(ocr): move repository access from OcrController into OcrService

OcrController was injecting OcrJobRepository and OcrJobDocumentRepository
directly, violating the Controller → Service → Repository layering rule.
Moved getJob() and getDocumentOcrStatus() logic into OcrService.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
Marcel
2026-04-13 12:26:14 +02:00
parent 410ef88e1a
commit 2d43f09172
4 changed files with 105 additions and 41 deletions

View File

@@ -4,12 +4,11 @@ import tools.jackson.databind.ObjectMapper;
import org.junit.jupiter.api.Test;
import org.raddatz.familienarchiv.config.SecurityConfig;
import org.raddatz.familienarchiv.dto.BatchOcrDTO;
import org.raddatz.familienarchiv.dto.OcrStatusDTO;
import org.raddatz.familienarchiv.dto.TriggerOcrDTO;
import org.raddatz.familienarchiv.exception.DomainException;
import org.raddatz.familienarchiv.exception.ErrorCode;
import org.raddatz.familienarchiv.model.*;
import org.raddatz.familienarchiv.repository.OcrJobDocumentRepository;
import org.raddatz.familienarchiv.repository.OcrJobRepository;
import org.raddatz.familienarchiv.security.PermissionAspect;
import org.raddatz.familienarchiv.service.*;
import org.springframework.beans.factory.annotation.Autowired;
@@ -22,7 +21,6 @@ import org.springframework.test.context.bean.override.mockito.MockitoBean;
import org.springframework.test.web.servlet.MockMvc;
import java.util.List;
import java.util.Optional;
import java.util.UUID;
import static org.mockito.ArgumentMatchers.any;
@@ -43,8 +41,6 @@ class OcrControllerTest {
@MockitoBean OcrService ocrService;
@MockitoBean OcrBatchService ocrBatchService;
@MockitoBean OcrProgressService ocrProgressService;
@MockitoBean OcrJobRepository ocrJobRepository;
@MockitoBean OcrJobDocumentRepository ocrJobDocumentRepository;
@MockitoBean UserService userService;
@MockitoBean CustomUserDetailsService customUserDetailsService;
@@ -81,7 +77,8 @@ class OcrControllerTest {
@WithMockUser(authorities = "READ_ALL")
void getJobStatus_returns404_whenJobNotFound() throws Exception {
UUID jobId = UUID.randomUUID();
when(ocrJobRepository.findById(jobId)).thenReturn(Optional.empty());
when(ocrService.getJob(jobId))
.thenThrow(DomainException.notFound(ErrorCode.OCR_JOB_NOT_FOUND, "OCR job not found"));
mockMvc.perform(get("/api/ocr/jobs/{jobId}", jobId))
.andExpect(status().isNotFound());
@@ -99,7 +96,7 @@ class OcrControllerTest {
.errorCount(1)
.skippedCount(0)
.build();
when(ocrJobRepository.findById(jobId)).thenReturn(Optional.of(job));
when(ocrService.getJob(jobId)).thenReturn(job);
mockMvc.perform(get("/api/ocr/jobs/{jobId}", jobId))
.andExpect(status().isOk())
@@ -128,8 +125,8 @@ class OcrControllerTest {
@WithMockUser(authorities = "READ_ALL")
void getDocumentOcrStatus_returnsNone_whenNoOcrJobExists() throws Exception {
UUID docId = UUID.randomUUID();
when(ocrJobDocumentRepository.findFirstByDocumentIdAndStatusIn(eq(docId), any()))
.thenReturn(Optional.empty());
when(ocrService.getDocumentOcrStatus(docId))
.thenReturn(OcrStatusDTO.builder().status("NONE").build());
mockMvc.perform(get("/api/documents/{id}/ocr-status", docId))
.andExpect(status().isOk())

View File

@@ -5,12 +5,14 @@ import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.junit.jupiter.MockitoExtension;
import org.raddatz.familienarchiv.dto.OcrStatusDTO;
import org.raddatz.familienarchiv.exception.DomainException;
import org.raddatz.familienarchiv.exception.ErrorCode;
import org.raddatz.familienarchiv.model.*;
import org.raddatz.familienarchiv.repository.OcrJobDocumentRepository;
import org.raddatz.familienarchiv.repository.OcrJobRepository;
import java.util.Optional;
import java.util.UUID;
import static org.assertj.core.api.Assertions.assertThat;
@@ -30,6 +32,69 @@ class OcrServiceTest {
@InjectMocks OcrService ocrService;
// ─── getJob ──────────────────────────────────────────────────────────────────
@Test
void getJob_returnsJob_whenFound() {
UUID jobId = UUID.randomUUID();
OcrJob job = OcrJob.builder().id(jobId).status(OcrJobStatus.RUNNING).build();
when(ocrJobRepository.findById(jobId)).thenReturn(Optional.of(job));
OcrJob result = ocrService.getJob(jobId);
assertThat(result).isEqualTo(job);
}
@Test
void getJob_throwsNotFound_whenJobDoesNotExist() {
UUID jobId = UUID.randomUUID();
when(ocrJobRepository.findById(jobId)).thenReturn(Optional.empty());
assertThatThrownBy(() -> ocrService.getJob(jobId))
.isInstanceOf(DomainException.class)
.satisfies(e -> {
DomainException de = (DomainException) e;
assertThat(de.getStatus()).isEqualTo(NOT_FOUND);
assertThat(de.getCode()).isEqualTo(ErrorCode.OCR_JOB_NOT_FOUND);
});
}
// ─── getDocumentOcrStatus ───────────────────────────────────────────────────
@Test
void getDocumentOcrStatus_returnsNone_whenNoActiveJob() {
UUID docId = UUID.randomUUID();
when(ocrJobDocumentRepository.findFirstByDocumentIdAndStatusIn(any(), any()))
.thenReturn(Optional.empty());
OcrStatusDTO result = ocrService.getDocumentOcrStatus(docId);
assertThat(result.getStatus()).isEqualTo("NONE");
assertThat(result.getJobId()).isNull();
}
@Test
void getDocumentOcrStatus_returnsActiveStatus_whenJobExists() {
UUID docId = UUID.randomUUID();
UUID jobId = UUID.randomUUID();
OcrJobDocument jobDoc = OcrJobDocument.builder()
.jobId(jobId).documentId(docId)
.status(OcrDocumentStatus.RUNNING)
.currentPage(2).totalPages(5)
.build();
when(ocrJobDocumentRepository.findFirstByDocumentIdAndStatusIn(any(), any()))
.thenReturn(Optional.of(jobDoc));
OcrStatusDTO result = ocrService.getDocumentOcrStatus(docId);
assertThat(result.getStatus()).isEqualTo("RUNNING");
assertThat(result.getJobId()).isEqualTo(jobId);
assertThat(result.getCurrentPage()).isEqualTo(2);
assertThat(result.getTotalPages()).isEqualTo(5);
}
// ─── startOcr ───────────────────────────────────────────────────────────────
@Test
void startOcr_throwsBadRequest_whenDocumentIsPlaceholder() {
UUID docId = UUID.randomUUID();