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 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,3 @@
|
|||||||
|
CREATE UNIQUE INDEX idx_training_runs_queued_per_person
|
||||||
|
ON ocr_training_runs(person_id)
|
||||||
|
WHERE status = 'QUEUED';
|
||||||
@@ -2,6 +2,8 @@ package org.raddatz.familienarchiv.service;
|
|||||||
|
|
||||||
import org.junit.jupiter.api.BeforeEach;
|
import org.junit.jupiter.api.BeforeEach;
|
||||||
import org.junit.jupiter.api.Test;
|
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.OcrTrainingRun;
|
||||||
import org.raddatz.familienarchiv.model.SenderModel;
|
import org.raddatz.familienarchiv.model.SenderModel;
|
||||||
import org.raddatz.familienarchiv.model.TrainingStatus;
|
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.ArgumentMatchers.*;
|
||||||
import static org.mockito.Mockito.*;
|
import static org.mockito.Mockito.*;
|
||||||
|
|
||||||
|
@ExtendWith(MockitoExtension.class)
|
||||||
class SenderModelServiceTest {
|
class SenderModelServiceTest {
|
||||||
|
|
||||||
SenderModelRepository senderModelRepository;
|
SenderModelRepository senderModelRepository;
|
||||||
@@ -40,8 +43,9 @@ class SenderModelServiceTest {
|
|||||||
txTemplate = mock(TransactionTemplate.class);
|
txTemplate = mock(TransactionTemplate.class);
|
||||||
trainingDataExportService = mock(TrainingDataExportService.class);
|
trainingDataExportService = mock(TrainingDataExportService.class);
|
||||||
|
|
||||||
// Execute transaction callbacks inline so unit tests run without a real DataSource
|
// Execute transaction callbacks inline so unit tests run without a real DataSource.
|
||||||
when(txTemplate.execute(any())).thenAnswer(inv -> {
|
// 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);
|
TransactionCallback<?> callback = inv.getArgument(0);
|
||||||
return callback.doInTransaction(null);
|
return callback.doInTransaction(null);
|
||||||
});
|
});
|
||||||
@@ -265,7 +269,6 @@ class SenderModelServiceTest {
|
|||||||
.modelName("sender_" + personId).build();
|
.modelName("sender_" + personId).build();
|
||||||
when(trainingRunRepository.findFirstByPersonIdAndStatus(personId, TrainingStatus.RUNNING))
|
when(trainingRunRepository.findFirstByPersonIdAndStatus(personId, TrainingStatus.RUNNING))
|
||||||
.thenReturn(Optional.of(runningRun));
|
.thenReturn(Optional.of(runningRun));
|
||||||
when(blockRepository.countManualKurrentBlocksByPerson(personId)).thenReturn(10L);
|
|
||||||
when(trainingRunRepository.save(any())).thenAnswer(inv -> {
|
when(trainingRunRepository.save(any())).thenAnswer(inv -> {
|
||||||
OcrTrainingRun r = inv.getArgument(0);
|
OcrTrainingRun r = inv.getArgument(0);
|
||||||
if (r.getId() == null) r.setId(UUID.randomUUID());
|
if (r.getId() == null) r.setId(UUID.randomUUID());
|
||||||
|
|||||||
Reference in New Issue
Block a user