From 92f3c04d544bd483bc3de690a04e7f3417c35e15 Mon Sep 17 00:00:00 2001 From: Marcel Date: Fri, 17 Apr 2026 21:25:18 +0200 Subject: [PATCH] fix(ocr): add partial unique index and align SenderModelServiceTest with suite style Add V42 partial unique index on ocr_training_runs(person_id) WHERE status='QUEUED' to enforce the per-person queued coalescing guarantee at the DB level. Also adds @ExtendWith(MockitoExtension.class) to SenderModelServiceTest for consistency with the rest of the service test suite, with lenient() on the shared txTemplate stub. Co-Authored-By: Claude Sonnet 4.6 --- .../V42__add_queued_per_person_unique_index.sql | 3 +++ .../familienarchiv/service/SenderModelServiceTest.java | 9 ++++++--- 2 files changed, 9 insertions(+), 3 deletions(-) create mode 100644 backend/src/main/resources/db/migration/V42__add_queued_per_person_unique_index.sql diff --git a/backend/src/main/resources/db/migration/V42__add_queued_per_person_unique_index.sql b/backend/src/main/resources/db/migration/V42__add_queued_per_person_unique_index.sql new file mode 100644 index 00000000..5e4194bd --- /dev/null +++ b/backend/src/main/resources/db/migration/V42__add_queued_per_person_unique_index.sql @@ -0,0 +1,3 @@ +CREATE UNIQUE INDEX idx_training_runs_queued_per_person + ON ocr_training_runs(person_id) + WHERE status = 'QUEUED'; diff --git a/backend/src/test/java/org/raddatz/familienarchiv/service/SenderModelServiceTest.java b/backend/src/test/java/org/raddatz/familienarchiv/service/SenderModelServiceTest.java index be41de41..57318758 100644 --- a/backend/src/test/java/org/raddatz/familienarchiv/service/SenderModelServiceTest.java +++ b/backend/src/test/java/org/raddatz/familienarchiv/service/SenderModelServiceTest.java @@ -2,6 +2,8 @@ package org.raddatz.familienarchiv.service; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.mockito.junit.jupiter.MockitoExtension; import org.raddatz.familienarchiv.model.OcrTrainingRun; import org.raddatz.familienarchiv.model.SenderModel; import org.raddatz.familienarchiv.model.TrainingStatus; @@ -19,6 +21,7 @@ import static org.assertj.core.api.Assertions.assertThat; import static org.mockito.ArgumentMatchers.*; import static org.mockito.Mockito.*; +@ExtendWith(MockitoExtension.class) class SenderModelServiceTest { SenderModelRepository senderModelRepository; @@ -40,8 +43,9 @@ class SenderModelServiceTest { txTemplate = mock(TransactionTemplate.class); trainingDataExportService = mock(TrainingDataExportService.class); - // Execute transaction callbacks inline so unit tests run without a real DataSource - when(txTemplate.execute(any())).thenAnswer(inv -> { + // Execute transaction callbacks inline so unit tests run without a real DataSource. + // lenient: not every test hits the txTemplate path, but the setup is shared. + lenient().when(txTemplate.execute(any())).thenAnswer(inv -> { TransactionCallback callback = inv.getArgument(0); return callback.doInTransaction(null); }); @@ -265,7 +269,6 @@ class SenderModelServiceTest { .modelName("sender_" + personId).build(); when(trainingRunRepository.findFirstByPersonIdAndStatus(personId, TrainingStatus.RUNNING)) .thenReturn(Optional.of(runningRun)); - when(blockRepository.countManualKurrentBlocksByPerson(personId)).thenReturn(10L); when(trainingRunRepository.save(any())).thenAnswer(inv -> { OcrTrainingRun r = inv.getArgument(0); if (r.getId() == null) r.setId(UUID.randomUUID());