test(#240): add Testcontainers integration tests for native SQL queue queries
6 new tests covering findSegmentationQueue (excludes PLACEHOLDER, excludes annotated docs), findTranscriptionQueue (below-90%-reviewed docs, zero-block case), findReadyToReadQueue (>=90% reviewed), and findWeeklyStats (zeros on empty DB). Runs against real PostgreSQL 16 via Testcontainers. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -4,8 +4,10 @@ import org.junit.jupiter.api.Test;
|
||||
import org.raddatz.familienarchiv.PostgresContainerConfig;
|
||||
import org.raddatz.familienarchiv.config.FlywayConfig;
|
||||
import org.raddatz.familienarchiv.model.Document;
|
||||
import org.raddatz.familienarchiv.model.DocumentAnnotation;
|
||||
import org.raddatz.familienarchiv.model.DocumentStatus;
|
||||
import org.raddatz.familienarchiv.model.Person;
|
||||
import org.raddatz.familienarchiv.model.TranscriptionBlock;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.boot.jdbc.test.autoconfigure.AutoConfigureTestDatabase;
|
||||
import org.springframework.boot.data.jpa.test.autoconfigure.DataJpaTest;
|
||||
@@ -20,6 +22,7 @@ import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
import java.util.Set;
|
||||
import java.util.UUID;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
@@ -34,6 +37,12 @@ class DocumentRepositoryTest {
|
||||
@Autowired
|
||||
private PersonRepository personRepository;
|
||||
|
||||
@Autowired
|
||||
private AnnotationRepository annotationRepository;
|
||||
|
||||
@Autowired
|
||||
private TranscriptionBlockRepository transcriptionBlockRepository;
|
||||
|
||||
// ─── save and findById ────────────────────────────────────────────────────
|
||||
|
||||
@Test
|
||||
@@ -253,4 +262,116 @@ class DocumentRepositoryTest {
|
||||
|
||||
assertThat(results).hasSize(1);
|
||||
}
|
||||
|
||||
// ─── findSegmentationQueue ────────────────────────────────────────────────
|
||||
|
||||
@Test
|
||||
void findSegmentationQueue_excludes_PLACEHOLDER_documents() {
|
||||
documentRepository.save(uploaded("Hochgeladener Brief"));
|
||||
documentRepository.save(Document.builder()
|
||||
.title("Platzhalter").originalFilename("placeholder.pdf")
|
||||
.status(DocumentStatus.PLACEHOLDER).build());
|
||||
|
||||
List<TranscriptionQueueProjection> result = documentRepository.findSegmentationQueue(10);
|
||||
|
||||
assertThat(result).extracting(TranscriptionQueueProjection::getTitle)
|
||||
.containsExactly("Hochgeladener Brief")
|
||||
.doesNotContain("Platzhalter");
|
||||
}
|
||||
|
||||
@Test
|
||||
void findSegmentationQueue_excludes_documents_that_already_have_annotations() {
|
||||
Document withAnnotation = documentRepository.save(uploaded("Mit Annotation"));
|
||||
documentRepository.save(uploaded("Ohne Annotation"));
|
||||
annotationRepository.save(annotation(withAnnotation.getId()));
|
||||
|
||||
List<TranscriptionQueueProjection> result = documentRepository.findSegmentationQueue(10);
|
||||
|
||||
assertThat(result).extracting(TranscriptionQueueProjection::getTitle)
|
||||
.containsExactly("Ohne Annotation")
|
||||
.doesNotContain("Mit Annotation");
|
||||
}
|
||||
|
||||
// ─── findTranscriptionQueue ───────────────────────────────────────────────
|
||||
|
||||
@Test
|
||||
void findTranscriptionQueue_returns_documents_with_annotations_below_90pct_reviewed() {
|
||||
Document doc = documentRepository.save(uploaded("Tagebuch"));
|
||||
DocumentAnnotation ann = annotationRepository.save(annotation(doc.getId()));
|
||||
// One block, not reviewed → 0 / 1 = 0% < 90%
|
||||
transcriptionBlockRepository.save(block(doc.getId(), ann.getId(), "Text", false));
|
||||
|
||||
List<TranscriptionQueueProjection> result = documentRepository.findTranscriptionQueue(10);
|
||||
|
||||
assertThat(result).extracting(TranscriptionQueueProjection::getTitle)
|
||||
.contains("Tagebuch");
|
||||
}
|
||||
|
||||
@Test
|
||||
void findTranscriptionQueue_returns_zero_textedBlockCount_when_no_transcription_blocks() {
|
||||
Document doc = documentRepository.save(uploaded("Nur Annotation"));
|
||||
annotationRepository.save(annotation(doc.getId()));
|
||||
// No transcription blocks at all — annotationCount=1, textedBlockCount=0
|
||||
|
||||
List<TranscriptionQueueProjection> result = documentRepository.findTranscriptionQueue(10);
|
||||
|
||||
assertThat(result).hasSize(1);
|
||||
assertThat(result.get(0).getTextedBlockCount()).isEqualTo(0);
|
||||
assertThat(result.get(0).getAnnotationCount()).isEqualTo(1);
|
||||
}
|
||||
|
||||
// ─── findReadyToReadQueue ─────────────────────────────────────────────────
|
||||
|
||||
@Test
|
||||
void findReadyToReadQueue_returns_documents_with_at_least_90pct_reviewed() {
|
||||
Document doc = documentRepository.save(uploaded("Urkunde"));
|
||||
DocumentAnnotation ann = annotationRepository.save(annotation(doc.getId()));
|
||||
// One block, reviewed → 1 / 1 = 100% >= 90%
|
||||
transcriptionBlockRepository.save(block(doc.getId(), ann.getId(), "Text", true));
|
||||
|
||||
List<TranscriptionQueueProjection> result = documentRepository.findReadyToReadQueue(10);
|
||||
|
||||
assertThat(result).extracting(TranscriptionQueueProjection::getTitle)
|
||||
.contains("Urkunde");
|
||||
}
|
||||
|
||||
// ─── findWeeklyStats ──────────────────────────────────────────────────────
|
||||
|
||||
@Test
|
||||
void findWeeklyStats_returns_zeros_when_database_is_empty() {
|
||||
TranscriptionWeeklyStatsProjection stats = documentRepository.findWeeklyStats();
|
||||
|
||||
assertThat(stats.getSegmentationCount()).isEqualTo(0L);
|
||||
assertThat(stats.getTranscriptionCount()).isEqualTo(0L);
|
||||
assertThat(stats.getReadyCount()).isEqualTo(0L);
|
||||
}
|
||||
|
||||
// ─── seeding helpers ─────────────────────────────────────────────────────
|
||||
|
||||
private Document uploaded(String title) {
|
||||
return Document.builder()
|
||||
.title(title)
|
||||
.originalFilename(title.toLowerCase().replace(" ", "_") + ".pdf")
|
||||
.status(DocumentStatus.UPLOADED)
|
||||
.build();
|
||||
}
|
||||
|
||||
private DocumentAnnotation annotation(UUID documentId) {
|
||||
return DocumentAnnotation.builder()
|
||||
.documentId(documentId)
|
||||
.pageNumber(1)
|
||||
.x(0.1).y(0.1).width(0.5).height(0.3)
|
||||
.color("#ff0000")
|
||||
.build();
|
||||
}
|
||||
|
||||
private TranscriptionBlock block(UUID documentId, UUID annotationId, String text, boolean reviewed) {
|
||||
return TranscriptionBlock.builder()
|
||||
.documentId(documentId)
|
||||
.annotationId(annotationId)
|
||||
.text(text)
|
||||
.sortOrder(0)
|
||||
.reviewed(reviewed)
|
||||
.build();
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user