@Override public Mono<Void> handle(Event event) { return eventDeadLetters.store(group, event); } }
@Test default void failedEventsByGroupShouldReturnEmptyWhenNonMatch() { EventDeadLetters eventDeadLetters = eventDeadLetters(); eventDeadLetters.store(GROUP_A, EVENT_1).block(); eventDeadLetters.store(GROUP_A, EVENT_2).block(); eventDeadLetters.store(GROUP_A, EVENT_3).block(); assertThat(eventDeadLetters.failedEventIds(GROUP_B).toStream()) .isEmpty(); }
@Test default void storeShouldIgnoreStoreDuplicatedEventsPerGroup() { EventDeadLetters eventDeadLetters = eventDeadLetters(); eventDeadLetters.store(GROUP_A, EVENT_1).block(); eventDeadLetters.store(GROUP_A, EVENT_1).block(); eventDeadLetters.store(GROUP_A, EVENT_1).block(); assertThat(eventDeadLetters.failedEventIds(GROUP_A).toStream()) .containsExactly(EVENT_ID_1); }
@Test default void failedEventsByGroupShouldReturnAllEventsCorrespondingToGivenGroup() { EventDeadLetters eventDeadLetters = eventDeadLetters(); eventDeadLetters.store(GROUP_A, EVENT_1).block(); eventDeadLetters.store(GROUP_A, EVENT_2).block(); eventDeadLetters.store(GROUP_B, EVENT_3).block(); assertThat(eventDeadLetters.failedEventIds(GROUP_A).toStream()) .containsOnly(EVENT_ID_1, EVENT_ID_2); }
@Test default void storeShouldThrowWhenNullGroup() { EventDeadLetters eventDeadLetters = eventDeadLetters(); assertThatThrownBy(() -> eventDeadLetters.store(NULL_GROUP, EVENT_1)) .isInstanceOf(IllegalArgumentException.class); }
@Test default void storeShouldThrowWhenBothGroupAndEventAreNull() { EventDeadLetters eventDeadLetters = eventDeadLetters(); assertThatThrownBy(() -> eventDeadLetters.store(NULL_GROUP, NULL_EVENT)) .isInstanceOf(IllegalArgumentException.class); }
@Test default void failedEventShouldReturnEventWhenContains() { EventDeadLetters eventDeadLetters = eventDeadLetters(); eventDeadLetters.store(GROUP_A, EVENT_1).block(); eventDeadLetters.store(GROUP_A, EVENT_2).block(); assertThat(eventDeadLetters.failedEvent(GROUP_A, EVENT_1.getEventId()).block()) .isEqualTo(EVENT_1); }
@Test default void storeShouldThrowWhenNullEvent() { EventDeadLetters eventDeadLetters = eventDeadLetters(); assertThatThrownBy(() -> eventDeadLetters.store(GROUP_A, NULL_EVENT)) .isInstanceOf(IllegalArgumentException.class); }
@Test default void failedEventShouldReturnEmptyWhenNotFound() { EventDeadLetters eventDeadLetters = eventDeadLetters(); eventDeadLetters.store(GROUP_A, EVENT_1).block(); eventDeadLetters.store(GROUP_A, EVENT_2).block(); assertThat(eventDeadLetters.failedEvent(GROUP_A, EVENT_ID_3).block()) .isNull(); }
@Test default void failedEventShouldNotRemoveEvent() { EventDeadLetters eventDeadLetters = eventDeadLetters(); eventDeadLetters.store(GROUP_A, EVENT_1).block(); eventDeadLetters.store(GROUP_A, EVENT_2).block(); eventDeadLetters.store(GROUP_A, EVENT_3).block(); eventDeadLetters.failedEvent(GROUP_A, EVENT_1.getEventId()).block(); assertThat(allEventIds()) .containsOnly(EVENT_ID_1, EVENT_ID_2, EVENT_ID_3); } }
@Test default void failedEventsByGroupShouldNotRemoveEvents() { EventDeadLetters eventDeadLetters = eventDeadLetters(); eventDeadLetters.store(GROUP_A, EVENT_1).block(); eventDeadLetters.store(GROUP_A, EVENT_2).block(); eventDeadLetters.store(GROUP_B, EVENT_3).block(); eventDeadLetters.failedEventIds(GROUP_A).toStream(); assertThat(allEventIds()) .containsOnly(EVENT_ID_1, EVENT_ID_2, EVENT_ID_3); } }
@Test default void removeShouldKeepNonMatched() { EventDeadLetters eventDeadLetters = eventDeadLetters(); eventDeadLetters.store(GROUP_A, EVENT_1).block(); eventDeadLetters.store(GROUP_A, EVENT_2).block(); eventDeadLetters.store(GROUP_A, EVENT_3).block(); eventDeadLetters.remove(GROUP_A, EVENT_1.getEventId()).block(); assertThat(eventDeadLetters.failedEventIds(GROUP_A).toStream()) .containsOnly(EVENT_ID_2, EVENT_ID_3); }
@Test default void storeShouldStoreGroupWithCorrespondingEvent() { EventDeadLetters eventDeadLetters = eventDeadLetters(); eventDeadLetters.store(GROUP_A, EVENT_1).block(); assertThat(eventDeadLetters.failedEvent(GROUP_A, EVENT_1.getEventId()).block()) .isEqualTo(EVENT_1); }
@Test default void groupsWithFailedEventsShouldReturnAllStoredGroups() { EventDeadLetters eventDeadLetters = eventDeadLetters(); eventDeadLetters.store(GROUP_A, EVENT_1).block(); eventDeadLetters.store(GROUP_B, EVENT_1).block(); assertThat(eventDeadLetters.groupsWithFailedEvents().toStream()) .containsOnly(GROUP_A, GROUP_B); }
@Test default void removeShouldRemoveMatched() { EventDeadLetters eventDeadLetters = eventDeadLetters(); eventDeadLetters.store(GROUP_A, EVENT_1).block(); eventDeadLetters.store(GROUP_A, EVENT_2).block(); eventDeadLetters.remove(GROUP_A, EVENT_1.getEventId()).block(); assertThat(eventDeadLetters.failedEvent(GROUP_A, EVENT_1.getEventId()).block()) .isNull(); }
@Test default void removeShouldNotThrowWhenNoMatched() { EventDeadLetters eventDeadLetters = eventDeadLetters(); eventDeadLetters.store(GROUP_A, EVENT_1).block(); assertThatCode(() -> eventDeadLetters.remove(GROUP_A, EVENT_2.getEventId()).block()) .doesNotThrowAnyException(); }
@Test default void storeShouldKeepConsistencyWhenConcurrentStore() throws Exception { EventDeadLetters eventDeadLetters = eventDeadLetters(); ImmutableMap<Integer, Group> groups = concurrentGroups(); Multimap<Integer, Event.EventId> storedEventIds = Multimaps.synchronizedSetMultimap(HashMultimap.create()); ConcurrentTestRunner.builder() .operation((threadNumber, step) -> { Event.EventId eventId = Event.EventId.random(); storedEventIds.put(threadNumber, eventId); eventDeadLetters.store(groups.get(threadNumber), event(eventId)); }) .threadCount(THREAD_COUNT) .operationCount(OPERATION_COUNT) .runSuccessfullyWithin(RUN_SUCCESSFULLY_IN); groups.forEach((groupId, group) -> { Group storedGroup = groups.get(groupId); assertThat(eventDeadLetters.failedEventIds(storedGroup).toStream()) .hasSameElementsAs(storedEventIds.get(groupId)); }); } }
@Test default void removeShouldKeepConsistencyWhenConcurrentRemove() throws Exception { EventDeadLetters eventDeadLetters = eventDeadLetters(); ImmutableMap<Integer, Group> groups = concurrentGroups(); ConcurrentHashMap<Integer, Event.EventId> storedEventIds = new ConcurrentHashMap<>(); ConcurrentTestRunner.builder() .operation((threadNumber, step) -> { int operationIndex = threadNumber * OPERATION_COUNT + step; Event.EventId eventId = Event.EventId.random(); storedEventIds.put(operationIndex, eventId); eventDeadLetters.store(groups.get(threadNumber), event(eventId)).subscribe(); }) .threadCount(THREAD_COUNT) .operationCount(OPERATION_COUNT) .runSuccessfullyWithin(RUN_SUCCESSFULLY_IN); ConcurrentTestRunner.builder() .operation((threadNumber, step) -> { int operationIndex = threadNumber * OPERATION_COUNT + step; eventDeadLetters.remove(groups.get(threadNumber), storedEventIds.get(operationIndex)); }) .threadCount(THREAD_COUNT) .operationCount(OPERATION_COUNT) .runSuccessfullyWithin(RUN_SUCCESSFULLY_IN); assertThat(allEventIds()) .isEmpty(); } }