test(timeline): add integration tests for TimelineService + findByGeneration
Verifies PersonRepository.findByGeneration handles match, no-match (empty list not NPE), and null-generation persons (excluded). Also confirms TimelineService.assemble() returns a persisted curated event in the correct year band against real Postgres via Testcontainers. Refs #777 Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,105 @@
|
||||
package org.raddatz.familienarchiv.timeline;
|
||||
|
||||
import jakarta.persistence.EntityManager;
|
||||
import jakarta.persistence.PersistenceContext;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.raddatz.familienarchiv.PostgresContainerConfig;
|
||||
import org.raddatz.familienarchiv.document.DatePrecision;
|
||||
import org.raddatz.familienarchiv.person.Person;
|
||||
import org.raddatz.familienarchiv.person.PersonRepository;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.boot.test.context.SpringBootTest;
|
||||
import org.springframework.context.annotation.Import;
|
||||
import org.springframework.test.context.ActiveProfiles;
|
||||
import org.springframework.test.context.bean.override.mockito.MockitoBean;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
import software.amazon.awssdk.services.s3.S3Client;
|
||||
|
||||
import java.time.LocalDate;
|
||||
import java.util.List;
|
||||
import java.util.UUID;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
/**
|
||||
* Integration tests for {@link TimelineService} and {@link PersonRepository#findByGeneration}
|
||||
* against real Postgres. Verifies that assembled output reflects persisted curated events and
|
||||
* that the generation query handles null-generation rows correctly.
|
||||
*/
|
||||
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.NONE)
|
||||
@ActiveProfiles("test")
|
||||
@Import(PostgresContainerConfig.class)
|
||||
@Transactional
|
||||
class TimelineServiceIntegrationTest {
|
||||
|
||||
@MockitoBean S3Client s3Client;
|
||||
|
||||
@Autowired TimelineService timelineService;
|
||||
@Autowired TimelineEventRepository timelineEventRepository;
|
||||
@Autowired PersonRepository personRepository;
|
||||
|
||||
@PersistenceContext EntityManager em;
|
||||
|
||||
// ─── PersonRepository.findByGeneration ────────────────────────────────────
|
||||
|
||||
@Test
|
||||
void findByGeneration_returns_matching_persons() {
|
||||
personRepository.save(Person.builder().lastName("Gen2A").generation(2).build());
|
||||
personRepository.save(Person.builder().lastName("Gen2B").generation(2).build());
|
||||
personRepository.save(Person.builder().lastName("Gen3").generation(3).build());
|
||||
em.flush();
|
||||
|
||||
List<Person> result = personRepository.findByGeneration(2);
|
||||
|
||||
assertThat(result).extracting(Person::getLastName)
|
||||
.containsExactlyInAnyOrder("Gen2A", "Gen2B");
|
||||
}
|
||||
|
||||
@Test
|
||||
void findByGeneration_returns_empty_list_not_npe_when_no_match() {
|
||||
personRepository.save(Person.builder().lastName("Gen1").generation(1).build());
|
||||
em.flush();
|
||||
|
||||
List<Person> result = personRepository.findByGeneration(99);
|
||||
|
||||
assertThat(result).isNotNull().isEmpty();
|
||||
}
|
||||
|
||||
@Test
|
||||
void findByGeneration_does_not_return_null_generation_persons() {
|
||||
personRepository.save(Person.builder().lastName("NullGen").build()); // generation stays null
|
||||
em.flush();
|
||||
|
||||
List<Person> result = personRepository.findByGeneration(1);
|
||||
|
||||
assertThat(result).extracting(Person::getLastName).doesNotContain("NullGen");
|
||||
}
|
||||
|
||||
// ─── TimelineService.assemble end-to-end ─────────────────────────────────
|
||||
|
||||
@Test
|
||||
void assemble_includes_persisted_curated_event_in_correct_year_band() {
|
||||
UUID actorId = UUID.randomUUID();
|
||||
TimelineEvent event = timelineEventRepository.save(TimelineEvent.builder()
|
||||
.title("Sarajevo")
|
||||
.type(EventType.HISTORICAL)
|
||||
.eventDate(LocalDate.of(1914, 6, 28))
|
||||
.precision(DatePrecision.DAY)
|
||||
.createdBy(actorId)
|
||||
.updatedBy(actorId)
|
||||
.build());
|
||||
em.flush();
|
||||
em.clear();
|
||||
|
||||
TimelineDTO result = timelineService.assemble(new TimelineFilter(null, null, null, null, null));
|
||||
|
||||
assertThat(result.years()).anySatisfy(y -> {
|
||||
assertThat(y.year()).isEqualTo(1914);
|
||||
assertThat(y.entries()).anySatisfy(e -> {
|
||||
assertThat(e.title()).isEqualTo("Sarajevo");
|
||||
assertThat(e.kind()).isEqualTo(Kind.EVENT);
|
||||
assertThat(e.eventId()).isEqualTo(event.getId());
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user