feat/issue-751-journey-item-crud-api #791
@@ -2,6 +2,7 @@ package org.raddatz.familienarchiv.geschichte.journeyitem;
|
||||
|
||||
import jakarta.persistence.EntityManager;
|
||||
import jakarta.persistence.PersistenceContext;
|
||||
import org.junit.jupiter.api.AfterEach;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.raddatz.familienarchiv.PostgresContainerConfig;
|
||||
@@ -12,9 +13,15 @@ import org.raddatz.familienarchiv.geschichte.Geschichte;
|
||||
import org.raddatz.familienarchiv.geschichte.GeschichteRepository;
|
||||
import org.raddatz.familienarchiv.geschichte.GeschichteStatus;
|
||||
import org.raddatz.familienarchiv.geschichte.GeschichteType;
|
||||
import org.raddatz.familienarchiv.security.Permission;
|
||||
import org.raddatz.familienarchiv.user.AppUser;
|
||||
import org.raddatz.familienarchiv.user.AppUserRepository;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.boot.test.context.SpringBootTest;
|
||||
import org.springframework.context.annotation.Import;
|
||||
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
|
||||
import org.springframework.security.core.authority.SimpleGrantedAuthority;
|
||||
import org.springframework.security.core.context.SecurityContextHolder;
|
||||
import org.springframework.test.context.ActiveProfiles;
|
||||
import org.springframework.test.context.bean.override.mockito.MockitoBean;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
@@ -40,13 +47,20 @@ class JourneyItemIntegrationTest {
|
||||
|
||||
@Autowired GeschichteRepository geschichteRepository;
|
||||
@Autowired JourneyItemRepository journeyItemRepository;
|
||||
@Autowired JourneyItemService journeyItemService;
|
||||
@Autowired DocumentRepository documentRepository;
|
||||
@Autowired AppUserRepository appUserRepository;
|
||||
|
||||
Geschichte journey;
|
||||
Document doc;
|
||||
AppUser writer;
|
||||
|
||||
@BeforeEach
|
||||
void seed() {
|
||||
writer = appUserRepository.save(AppUser.builder()
|
||||
.email("journey-writer@test")
|
||||
.password("hash")
|
||||
.build());
|
||||
doc = documentRepository.save(Document.builder()
|
||||
.title("Testbrief")
|
||||
.originalFilename("testbrief.pdf")
|
||||
@@ -61,6 +75,19 @@ class JourneyItemIntegrationTest {
|
||||
em.clear();
|
||||
}
|
||||
|
||||
@AfterEach
|
||||
void clearSecurity() {
|
||||
SecurityContextHolder.clearContext();
|
||||
}
|
||||
|
||||
private void authenticateAs(AppUser user, Permission... permissions) {
|
||||
var authorities = java.util.Arrays.stream(permissions)
|
||||
.map(p -> new SimpleGrantedAuthority(p.name()))
|
||||
.toList();
|
||||
SecurityContextHolder.getContext().setAuthentication(
|
||||
new UsernamePasswordAuthenticationToken(user.getEmail(), null, authorities));
|
||||
}
|
||||
|
||||
// ─── @OrderBy ─────────────────────────────────────────────────────────────
|
||||
|
||||
@Test
|
||||
@@ -206,4 +233,62 @@ class JourneyItemIntegrationTest {
|
||||
journeyItemRepository.flush();
|
||||
}).isInstanceOf(Exception.class);
|
||||
}
|
||||
|
||||
// ─── JourneyItemService.append — end-to-end persistence ──────────────────
|
||||
|
||||
@Test
|
||||
void append_persists_item_at_position_10() {
|
||||
// Arrange: authenticate as a user with BLOG_WRITE
|
||||
authenticateAs(writer, Permission.BLOG_WRITE);
|
||||
|
||||
JourneyItemCreateDTO dto = new JourneyItemCreateDTO();
|
||||
dto.setNote("First stop");
|
||||
|
||||
// Act
|
||||
JourneyItemView view = journeyItemService.append(journey.getId(), dto);
|
||||
em.flush();
|
||||
em.clear();
|
||||
|
||||
// Assert: item exists in DB at position 10
|
||||
assertThat(view.position()).isEqualTo(10);
|
||||
assertThat(view.note()).isEqualTo("First stop");
|
||||
List<JourneyItem> persisted = journeyItemRepository.findByGeschichteIdOrderByPosition(journey.getId());
|
||||
assertThat(persisted).hasSize(1);
|
||||
assertThat(persisted.get(0).getPosition()).isEqualTo(10);
|
||||
assertThat(persisted.get(0).getNote()).isEqualTo("First stop");
|
||||
}
|
||||
|
||||
// ─── JourneyItemService.reorder — atomicity check ────────────────────────
|
||||
|
||||
@Test
|
||||
void reorder_swaps_positions_atomically() {
|
||||
// Arrange: append two items (pos 10, pos 20)
|
||||
authenticateAs(writer, Permission.BLOG_WRITE);
|
||||
|
||||
JourneyItemCreateDTO dto1 = new JourneyItemCreateDTO();
|
||||
dto1.setNote("Item one");
|
||||
JourneyItemView item1View = journeyItemService.append(journey.getId(), dto1);
|
||||
|
||||
JourneyItemCreateDTO dto2 = new JourneyItemCreateDTO();
|
||||
dto2.setNote("Item two");
|
||||
JourneyItemView item2View = journeyItemService.append(journey.getId(), dto2);
|
||||
|
||||
assertThat(item1View.position()).isEqualTo(10);
|
||||
assertThat(item2View.position()).isEqualTo(20);
|
||||
|
||||
// Act: reorder with [item2, item1]
|
||||
JourneyReorderDTO reorderDto = new JourneyReorderDTO();
|
||||
reorderDto.setItemIds(List.of(item2View.id(), item1View.id()));
|
||||
List<JourneyItemView> reordered = journeyItemService.reorder(journey.getId(), reorderDto);
|
||||
em.flush();
|
||||
em.clear();
|
||||
|
||||
// Assert: item2 is now at position 10, item1 is at position 20
|
||||
List<JourneyItem> persisted = journeyItemRepository.findByGeschichteIdOrderByPosition(journey.getId());
|
||||
assertThat(persisted).hasSize(2);
|
||||
assertThat(persisted.get(0).getId()).isEqualTo(item2View.id());
|
||||
assertThat(persisted.get(0).getPosition()).isEqualTo(10);
|
||||
assertThat(persisted.get(1).getId()).isEqualTo(item1View.id());
|
||||
assertThat(persisted.get(1).getPosition()).isEqualTo(20);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user