From 221a6af83804851ed849c25f4a73633143c2199c Mon Sep 17 00:00:00 2001 From: Marcel Date: Tue, 28 Apr 2026 20:58:55 +0200 Subject: [PATCH] test(transcription): rename propagation across 200 blocks must stay under 2 seconds MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Latency floor (Sara): a merge-blocking regression check, not a benchmark. Seeds 200 blocks each with one mention of the same person, fires the rename, and asserts the listener completes the entire find/mutate/saveAllAndFlush cycle in less than two seconds against the Testcontainers Postgres. Confirms the partial reload (one Auguste → Augusta) actually persisted so the timing isn't measuring an empty path. Refs #362 Co-Authored-By: Claude Opus 4.7 --- .../PersonMentionPropagationListenerTest.java | 32 +++++++++++++++++++ 1 file changed, 32 insertions(+) diff --git a/backend/src/test/java/org/raddatz/familienarchiv/service/PersonMentionPropagationListenerTest.java b/backend/src/test/java/org/raddatz/familienarchiv/service/PersonMentionPropagationListenerTest.java index 3cd98ea2..33bd0830 100644 --- a/backend/src/test/java/org/raddatz/familienarchiv/service/PersonMentionPropagationListenerTest.java +++ b/backend/src/test/java/org/raddatz/familienarchiv/service/PersonMentionPropagationListenerTest.java @@ -21,6 +21,7 @@ import org.springframework.boot.jdbc.test.autoconfigure.AutoConfigureTestDatabas import org.springframework.boot.data.jpa.test.autoconfigure.DataJpaTest; import org.springframework.context.annotation.Import; +import java.util.ArrayList; import java.util.List; import java.util.UUID; @@ -165,6 +166,37 @@ class PersonMentionPropagationListenerTest { .containsExactly("Ghost Name"); } + @Test + void propagatesAcross200Blocks_inUnderTwoSeconds_latencyFloor() { + UUID personId = savedPersonId("Auguste", "Raddatz"); + List blockIds = new ArrayList<>(); + for (int i = 0; i < 200; i++) { + TranscriptionBlock saved = blockRepository.save(TranscriptionBlock.builder() + .annotationId(annotationId).documentId(documentId) + .text("Block " + i + " mentions @Auguste Raddatz here.") + .sortOrder(i) + .mentionedPersons(List.of(new PersonMention(personId, "Auguste Raddatz"))) + .build()); + blockIds.add(saved.getId()); + } + blockRepository.flush(); + em.clear(); + + long start = System.nanoTime(); + listener.onPersonDisplayNameChanged( + new PersonDisplayNameChangedEvent(personId, "Auguste Raddatz", "Augusta Raddatz")); + blockRepository.flush(); + long elapsedMs = (System.nanoTime() - start) / 1_000_000; + + assertThat(elapsedMs) + .as("Propagation across 200 blocks must stay under 2s — merge-blocking regression floor") + .isLessThan(2000L); + + em.clear(); + TranscriptionBlock first = blockRepository.findById(blockIds.get(0)).orElseThrow(); + assertThat(first.getText()).contains("@Augusta Raddatz"); + } + @Test void leavesUnrelatedBlockUntouched_whenNoSidecarReferencesPerson() { UUID personId = savedPersonId("Auguste", "Raddatz");