- Convert Event and Rsvp from mutable POJOs to Java records - Move all 8 exception classes to application.service.exception sub-package - Add ArchUnit rule enforcing domain models must be records Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
147 lines
4.6 KiB
Java
147 lines
4.6 KiB
Java
package de.fete.application.service;
|
|
|
|
import static org.assertj.core.api.Assertions.assertThat;
|
|
import static org.mockito.ArgumentMatchers.any;
|
|
import static org.mockito.Mockito.times;
|
|
import static org.mockito.Mockito.verify;
|
|
import static org.mockito.Mockito.when;
|
|
|
|
import de.fete.domain.model.CreateEventCommand;
|
|
import de.fete.domain.model.Event;
|
|
import de.fete.domain.model.EventToken;
|
|
import de.fete.domain.port.out.EventRepository;
|
|
import java.time.Clock;
|
|
import java.time.Instant;
|
|
import java.time.LocalDate;
|
|
import java.time.OffsetDateTime;
|
|
import java.time.ZoneId;
|
|
import java.util.Optional;
|
|
import org.junit.jupiter.api.BeforeEach;
|
|
import org.junit.jupiter.api.Test;
|
|
import org.junit.jupiter.api.extension.ExtendWith;
|
|
import org.mockito.ArgumentCaptor;
|
|
import org.mockito.Mock;
|
|
import org.mockito.junit.jupiter.MockitoExtension;
|
|
|
|
@ExtendWith(MockitoExtension.class)
|
|
class EventServiceTest {
|
|
|
|
private static final ZoneId ZONE = ZoneId.of("Europe/Berlin");
|
|
private static final Instant FIXED_INSTANT =
|
|
LocalDate.of(2026, 3, 5).atStartOfDay(ZONE).toInstant();
|
|
private static final Clock FIXED_CLOCK = Clock.fixed(FIXED_INSTANT, ZONE);
|
|
private static final LocalDate TODAY = LocalDate.ofInstant(FIXED_INSTANT, ZONE);
|
|
|
|
@Mock
|
|
private EventRepository eventRepository;
|
|
|
|
private EventService eventService;
|
|
|
|
@BeforeEach
|
|
void setUp() {
|
|
eventService = new EventService(eventRepository, FIXED_CLOCK);
|
|
}
|
|
|
|
@Test
|
|
void createEventWithValidCommand() {
|
|
when(eventRepository.save(any(Event.class)))
|
|
.thenAnswer(invocation -> invocation.getArgument(0));
|
|
|
|
var command = new CreateEventCommand(
|
|
"Birthday Party",
|
|
"Come celebrate!",
|
|
TODAY.plusDays(90).atStartOfDay(ZONE).toOffsetDateTime(),
|
|
ZONE,
|
|
"Berlin"
|
|
);
|
|
|
|
Event result = eventService.createEvent(command);
|
|
|
|
assertThat(result.title()).isEqualTo("Birthday Party");
|
|
assertThat(result.description()).isEqualTo("Come celebrate!");
|
|
assertThat(result.timezone()).isEqualTo(ZONE);
|
|
assertThat(result.location()).isEqualTo("Berlin");
|
|
assertThat(result.eventToken()).isNotNull();
|
|
assertThat(result.organizerToken()).isNotNull();
|
|
assertThat(result.createdAt()).isEqualTo(OffsetDateTime.ofInstant(FIXED_INSTANT, ZONE));
|
|
}
|
|
|
|
@Test
|
|
void repositorySaveCalledExactlyOnce() {
|
|
when(eventRepository.save(any(Event.class)))
|
|
.thenAnswer(invocation -> invocation.getArgument(0));
|
|
|
|
var command = new CreateEventCommand(
|
|
"Test", null,
|
|
TODAY.plusDays(10).atStartOfDay(ZONE).toOffsetDateTime(), ZONE, null
|
|
);
|
|
|
|
eventService.createEvent(command);
|
|
|
|
ArgumentCaptor<Event> captor = ArgumentCaptor.forClass(Event.class);
|
|
verify(eventRepository, times(1)).save(captor.capture());
|
|
assertThat(captor.getValue().title()).isEqualTo("Test");
|
|
}
|
|
|
|
@Test
|
|
void expiryDateIsEventDatePlusSevenDays() {
|
|
when(eventRepository.save(any(Event.class)))
|
|
.thenAnswer(invocation -> invocation.getArgument(0));
|
|
|
|
var eventDate = TODAY.plusDays(10);
|
|
var command = new CreateEventCommand(
|
|
"Test", null,
|
|
eventDate.atStartOfDay(ZONE).toOffsetDateTime(), ZONE, null
|
|
);
|
|
|
|
Event result = eventService.createEvent(command);
|
|
|
|
assertThat(result.expiryDate()).isEqualTo(eventDate.plusDays(7));
|
|
}
|
|
|
|
// --- GetEventUseCase tests (T004) ---
|
|
|
|
@Test
|
|
void getByEventTokenReturnsEvent() {
|
|
EventToken token = EventToken.generate();
|
|
var event = new Event(null, token, null, "Found Event", null, null, null, null, null, null,
|
|
false, null);
|
|
when(eventRepository.findByEventToken(token))
|
|
.thenReturn(Optional.of(event));
|
|
|
|
Optional<Event> result = eventService.getByEventToken(token);
|
|
|
|
assertThat(result).isPresent();
|
|
assertThat(result.get().title()).isEqualTo("Found Event");
|
|
}
|
|
|
|
@Test
|
|
void getByEventTokenReturnsEmptyForUnknownToken() {
|
|
EventToken token = EventToken.generate();
|
|
when(eventRepository.findByEventToken(token))
|
|
.thenReturn(Optional.empty());
|
|
|
|
Optional<Event> result = eventService.getByEventToken(token);
|
|
|
|
assertThat(result).isEmpty();
|
|
}
|
|
|
|
// --- Timezone validation tests (T006) ---
|
|
|
|
@Test
|
|
void createEventWithValidTimezoneSucceeds() {
|
|
when(eventRepository.save(any(Event.class)))
|
|
.thenAnswer(invocation -> invocation.getArgument(0));
|
|
|
|
var command = new CreateEventCommand(
|
|
"Test", null,
|
|
TODAY.plusDays(10).atStartOfDay(ZONE).toOffsetDateTime(),
|
|
ZoneId.of("America/New_York"), null
|
|
);
|
|
|
|
Event result = eventService.createEvent(command);
|
|
|
|
assertThat(result.timezone()).isEqualTo(ZoneId.of("America/New_York"));
|
|
}
|
|
}
|