This is an automated email from the ASF dual-hosted git repository. matthieu pushed a commit to branch master in repository https://gitbox.apache.org/repos/asf/james-project.git
commit 929e958a479fe7062240ffe0717b85afba08aeb2 Author: Rémi KOWALSKI <rkowal...@linagora.com> AuthorDate: Wed Dec 11 16:08:28 2019 +0100 JAMES-3009 convert event sourcing core tests to scala --- .../eventsourcing/DataCollectorSubscriber.java | 46 ---- .../eventsourcing/EventSourcingSystemTest.java | 259 --------------------- .../eventsourcing/EventSourcingSystemTest.scala | 167 +++++++++++++ 3 files changed, 167 insertions(+), 305 deletions(-) diff --git a/event-sourcing/event-sourcing-core/src/test/java/org/apache/james/eventsourcing/DataCollectorSubscriber.java b/event-sourcing/event-sourcing-core/src/test/java/org/apache/james/eventsourcing/DataCollectorSubscriber.java deleted file mode 100644 index 85fccd1..0000000 --- a/event-sourcing/event-sourcing-core/src/test/java/org/apache/james/eventsourcing/DataCollectorSubscriber.java +++ /dev/null @@ -1,46 +0,0 @@ -/**************************************************************** - * Licensed to the Apache Software Foundation (ASF) under one * - * or more contributor license agreements. See the NOTICE file * - * distributed with this work for additional information * - * regarding copyright ownership. The ASF licenses this file * - * to you under the Apache License, Version 2.0 (the * - * "License"); you may not use this file except in compliance * - * with the License. You may obtain a copy of the License at * - * * - * http://www.apache.org/licenses/LICENSE-2.0 * - * * - * Unless required by applicable law or agreed to in writing, * - * software distributed under the License is distributed on an * - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * - * KIND, either express or implied. See the License for the * - * specific language governing permissions and limitations * - * under the License. * - ****************************************************************/ - -package org.apache.james.eventsourcing; - -import java.util.ArrayList; -import java.util.List; - -import com.google.common.collect.ImmutableList; - -public class DataCollectorSubscriber implements Subscriber { - - private final List<String> data; - - public DataCollectorSubscriber() { - data = new ArrayList<>(); - } - - @Override - public void handle(Event event) { - if (event instanceof TestEvent) { - data.add(((TestEvent) event).getData()); - } - } - - - public List<String> getData() { - return ImmutableList.copyOf(data); - } -} diff --git a/event-sourcing/event-sourcing-core/src/test/java/org/apache/james/eventsourcing/EventSourcingSystemTest.java b/event-sourcing/event-sourcing-core/src/test/java/org/apache/james/eventsourcing/EventSourcingSystemTest.java deleted file mode 100644 index 5e431d6..0000000 --- a/event-sourcing/event-sourcing-core/src/test/java/org/apache/james/eventsourcing/EventSourcingSystemTest.java +++ /dev/null @@ -1,259 +0,0 @@ -/**************************************************************** - * Licensed to the Apache Software Foundation (ASF) under one * - * or more contributor license agreements. See the NOTICE file * - * distributed with this work for additional information * - * regarding copyright ownership. The ASF licenses this file * - * to you under the Apache License, Version 2.0 (the * - * "License"); you may not use this file except in compliance * - * with the License. You may obtain a copy of the License at * - * * - * http://www.apache.org/licenses/LICENSE-2.0 * - * * - * Unless required by applicable law or agreed to in writing, * - * software distributed under the License is distributed on an * - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * - * KIND, either express or implied. See the License for the * - * specific language governing permissions and limitations * - * under the License. * - ****************************************************************/ - -package org.apache.james.eventsourcing; - -import static org.assertj.core.api.Assertions.assertThat; -import static org.assertj.core.api.Assertions.assertThatThrownBy; -import static org.mockito.ArgumentMatchers.any; -import static org.mockito.Mockito.doThrow; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.when; - -import org.apache.james.eventsourcing.eventstore.EventStore; -import org.apache.james.eventsourcing.eventstore.History; -import org.junit.jupiter.api.Test; -import org.mockito.internal.matchers.InstanceOf; -import org.mockito.internal.progress.ThreadSafeMockingProgress; - -import com.github.steveash.guavate.Guavate; -import com.google.common.base.Splitter; -import com.google.common.collect.ImmutableList; -import com.google.common.collect.ImmutableSet; -import scala.collection.immutable.List; -import scala.jdk.javaapi.CollectionConverters; - -public interface EventSourcingSystemTest { - - String PAYLOAD_1 = "payload1"; - String PAYLOAD_2 = "payload2"; - TestAggregateId AGGREGATE_ID = TestAggregateId.apply(42); - - class MyCommand implements Command { - private final String payload; - - public MyCommand(String payload) { - this.payload = payload; - } - - public String getPayload() { - return payload; - } - } - - @Test - default void dispatchShouldApplyCommandHandlerThenCallSubscribers(EventStore eventStore) { - DataCollectorSubscriber subscriber = new DataCollectorSubscriber(); - EventSourcingSystem eventSourcingSystem = EventSourcingSystem.fromJava( - ImmutableSet.of(simpleDispatcher(eventStore)), - ImmutableSet.of(subscriber), - eventStore); - - eventSourcingSystem.dispatch(new MyCommand(PAYLOAD_1)); - - assertThat(subscriber.getData()).containsExactly(PAYLOAD_1); - } - - @Test - default void throwingSubscribersShouldNotAbortSubscriberChain(EventStore eventStore) { - DataCollectorSubscriber subscriber = new DataCollectorSubscriber(); - EventSourcingSystem eventSourcingSystem = EventSourcingSystem.fromJava( - ImmutableSet.of(simpleDispatcher(eventStore)), - ImmutableSet.of( - events -> { - throw new RuntimeException(); - }, - subscriber), - eventStore); - - eventSourcingSystem.dispatch(new MyCommand(PAYLOAD_1)); - - assertThat(subscriber.getData()).containsExactly(PAYLOAD_1); - } - - @Test - default void throwingStoreShouldNotLeadToPublishing() { - EventStore eventStore = mock(EventStore.class); - doThrow(new RuntimeException()).when(eventStore).appendAll(anyScalaList()); - when(eventStore.getEventsOfAggregate(any())).thenReturn(History.empty()); - - DataCollectorSubscriber subscriber = new DataCollectorSubscriber(); - EventSourcingSystem eventSourcingSystem = EventSourcingSystem.fromJava( - ImmutableSet.of(simpleDispatcher(eventStore)), - ImmutableSet.of( - events -> { - throw new RuntimeException(); - }, - subscriber), - eventStore); - - assertThatThrownBy(() -> eventSourcingSystem.dispatch(new MyCommand(PAYLOAD_1))) - .isInstanceOf(RuntimeException.class); - - assertThat(subscriber.getData()).isEmpty(); - } - - @Test - default void dispatchShouldApplyCommandHandlerThenStoreGeneratedEvents(EventStore eventStore) { - DataCollectorSubscriber subscriber = new DataCollectorSubscriber(); - EventSourcingSystem eventSourcingSystem = EventSourcingSystem.fromJava( - ImmutableSet.of(simpleDispatcher(eventStore)), - ImmutableSet.of(subscriber), - eventStore); - - eventSourcingSystem.dispatch(new MyCommand(PAYLOAD_1)); - - TestEvent expectedEvent = new TestEvent(EventId.first(), AGGREGATE_ID, PAYLOAD_1); - assertThat(CollectionConverters.asJava(eventStore.getEventsOfAggregate(AGGREGATE_ID).getEvents())) - .containsOnly(expectedEvent); - } - - @Test - default void dispatchShouldCallSubscriberForSubsequentCommands(EventStore eventStore) { - DataCollectorSubscriber subscriber = new DataCollectorSubscriber(); - EventSourcingSystem eventSourcingSystem = EventSourcingSystem.fromJava( - ImmutableSet.of(simpleDispatcher(eventStore)), - ImmutableSet.of(subscriber), - eventStore); - - eventSourcingSystem.dispatch(new MyCommand(PAYLOAD_1)); - eventSourcingSystem.dispatch(new MyCommand(PAYLOAD_2)); - - assertThat(subscriber.getData()).containsExactly(PAYLOAD_1, PAYLOAD_2); - } - - @Test - default void dispatchShouldStoreEventsForSubsequentCommands(EventStore eventStore) { - DataCollectorSubscriber subscriber = new DataCollectorSubscriber(); - EventSourcingSystem eventSourcingSystem = EventSourcingSystem.fromJava( - ImmutableSet.of(simpleDispatcher(eventStore)), - ImmutableSet.of(subscriber), - eventStore); - - eventSourcingSystem.dispatch(new MyCommand(PAYLOAD_1)); - eventSourcingSystem.dispatch(new MyCommand(PAYLOAD_2)); - - TestEvent expectedEvent1 = new TestEvent(EventId.first(), AGGREGATE_ID, PAYLOAD_1); - TestEvent expectedEvent2 = new TestEvent(expectedEvent1.eventId().next(), AGGREGATE_ID, PAYLOAD_2); - assertThat(CollectionConverters.asJava(eventStore.getEventsOfAggregate(AGGREGATE_ID).getEvents())) - .containsOnly(expectedEvent1, expectedEvent2); - } - - @Test - default void dispatcherShouldBeAbleToReturnSeveralEvents(EventStore eventStore) { - DataCollectorSubscriber subscriber = new DataCollectorSubscriber(); - EventSourcingSystem eventSourcingSystem = EventSourcingSystem.fromJava( - ImmutableSet.of(wordCuttingDispatcher(eventStore)), - ImmutableSet.of(subscriber), - eventStore); - - eventSourcingSystem.dispatch(new MyCommand("This is a test")); - - assertThat(subscriber.getData()).containsExactly("This", "is", "a", "test"); - } - - @Test - default void unknownCommandsShouldBeIgnored(EventStore eventStore) { - DataCollectorSubscriber subscriber = new DataCollectorSubscriber(); - EventSourcingSystem eventSourcingSystem = EventSourcingSystem.fromJava( - ImmutableSet.of(wordCuttingDispatcher(eventStore)), - ImmutableSet.of(subscriber), - eventStore); - - assertThatThrownBy(() -> eventSourcingSystem.dispatch(new Command() { - })) - .isInstanceOf(CommandDispatcher.UnknownCommandException.class); - } - - @Test - default void constructorShouldThrowWhenSeveralHandlersForTheSameCommand(EventStore eventStore) { - DataCollectorSubscriber subscriber = new DataCollectorSubscriber(); - - assertThatThrownBy(() -> - EventSourcingSystem.fromJava( - ImmutableSet.of(wordCuttingDispatcher(eventStore), - simpleDispatcher(eventStore)), - ImmutableSet.of(subscriber), - eventStore)) - .isInstanceOf(IllegalArgumentException.class); - } - - default CommandHandler<MyCommand> simpleDispatcher(EventStore eventStore) { - return new CommandHandler<MyCommand>() { - @Override - public Class<MyCommand> handledClass() { - return MyCommand.class; - } - - @Override - public scala.collection.immutable.List<? extends Event> handle(MyCommand myCommand) { - History history = eventStore.getEventsOfAggregate(AGGREGATE_ID); - - return CollectionConverters.asScala(ImmutableList.of(new TestEvent( - history.getNextEventId(), - AGGREGATE_ID, - myCommand.getPayload()))).toList(); - } - }; - } - - default CommandHandler<MyCommand> wordCuttingDispatcher(EventStore eventStore) { - return new CommandHandler<MyCommand>() { - @Override - public Class<MyCommand> handledClass() { - return MyCommand.class; - } - - @Override - public scala.collection.immutable.List<? extends Event> handle(MyCommand myCommand) { - History history = eventStore.getEventsOfAggregate(AGGREGATE_ID); - - EventIdIncrementer eventIdIncrementer = new EventIdIncrementer(history.getNextEventId()); - - return CollectionConverters.asScala(Splitter.on(" ") - .splitToList(myCommand.getPayload()) - .stream() - .map(word -> new TestEvent( - eventIdIncrementer.next(), - AGGREGATE_ID, - word)) - .collect(Guavate.toImmutableList())).toList(); - } - }; - } - - class EventIdIncrementer { - private EventId currentEventId; - - public EventIdIncrementer(EventId base) { - this.currentEventId = base; - } - - public EventId next() { - currentEventId = currentEventId.next(); - return currentEventId; - } - } - - static <T> List<T> anyScalaList() { - ThreadSafeMockingProgress.mockingProgress().getArgumentMatcherStorage().reportMatcher(new InstanceOf(scala.collection.immutable.List.class, "<any scala List>")); - return scala.collection.immutable.List.<T>newBuilder().result(); - } - -} \ No newline at end of file diff --git a/event-sourcing/event-sourcing-core/src/test/scala/org/apache/james/eventsourcing/EventSourcingSystemTest.scala b/event-sourcing/event-sourcing-core/src/test/scala/org/apache/james/eventsourcing/EventSourcingSystemTest.scala new file mode 100644 index 0000000..641d98a --- /dev/null +++ b/event-sourcing/event-sourcing-core/src/test/scala/org/apache/james/eventsourcing/EventSourcingSystemTest.scala @@ -0,0 +1,167 @@ + /*************************************************************** + * Licensed to the Apache Software Foundation (ASF) under one * + * or more contributor license agreements. See the NOTICE file * + * distributed with this work for additional information * + * regarding copyright ownership. The ASF licenses this file * + * to you under the Apache License, Version 2.0 (the * + * "License"); you may not use this file except in compliance * + * with the License. You may obtain a copy of the License at * + * * + * http://www.apache.org/licenses/LICENSE-2.0 * + * * + * Unless required by applicable law or agreed to in writing, * + * software distributed under the License is distributed on an * + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * + * KIND, either express or implied. See the License for the * + * specific language governing permissions and limitations * + * under the License. * + ****************************************************************/ +package org.apache.james.eventsourcing + +import com.google.common.base.Splitter +import org.apache.james.eventsourcing.eventstore.{EventStore, History} +import org.assertj.core.api.Assertions.{assertThat, assertThatThrownBy} +import org.junit.jupiter.api.Test +import org.mockito.ArgumentMatchers.any +import org.mockito.Mockito.{doThrow, mock, when} +import org.mockito.internal.matchers.InstanceOf +import org.mockito.internal.progress.ThreadSafeMockingProgress + +import scala.collection.immutable.List +import scala.jdk.CollectionConverters._ + +object EventSourcingSystemTest { + val PAYLOAD_1 = "payload1" + val PAYLOAD_2 = "payload2" + val AGGREGATE_ID = TestAggregateId(42) + + class MyCommand(val payload: String) extends Command { + def getPayload: String = payload + } + + class EventIdIncrementer(var currentEventId: EventId) { + def next: EventId = { + currentEventId = currentEventId.next + currentEventId + } + } + + def anyScalaList[T] : List[T] = { + ThreadSafeMockingProgress.mockingProgress + .getArgumentMatcherStorage + .reportMatcher(new InstanceOf(classOf[List[_]], "<any scala List>")) + scala.collection.immutable.List.newBuilder[T].result + } +} + +trait EventSourcingSystemTest { + @Test + def dispatchShouldApplyCommandHandlerThenCallSubscribers(eventStore: EventStore) : Unit = { + val subscriber = new DataCollectorSubscriber + val eventSourcingSystem = new EventSourcingSystem(Set(simpleDispatcher(eventStore)), Set(subscriber), eventStore) + eventSourcingSystem.dispatch(new EventSourcingSystemTest.MyCommand(EventSourcingSystemTest.PAYLOAD_1)) + assertThat(subscriber.getData.asJava).containsExactly(EventSourcingSystemTest.PAYLOAD_1) + } + + @Test + def throwingSubscribersShouldNotAbortSubscriberChain(eventStore: EventStore) : Unit = { + val subscriber = new DataCollectorSubscriber + val eventSourcingSystem = new EventSourcingSystem( + Set(simpleDispatcher(eventStore)), + Set((_: Event) => throw new RuntimeException, subscriber), + eventStore) + eventSourcingSystem.dispatch(new EventSourcingSystemTest.MyCommand(EventSourcingSystemTest.PAYLOAD_1)) + assertThat(subscriber.getData.asJava).containsExactly(EventSourcingSystemTest.PAYLOAD_1) + } + + @Test + def throwingStoreShouldNotLeadToPublishing() : Unit = { + val eventStore = mock(classOf[EventStore]) + doThrow(new RuntimeException).when(eventStore).appendAll(EventSourcingSystemTest.anyScalaList) + when(eventStore.getEventsOfAggregate(any)).thenReturn(History.empty) + val subscriber = new DataCollectorSubscriber + val eventSourcingSystem = new EventSourcingSystem( + Set(simpleDispatcher(eventStore)), + Set((_: Event) => throw new RuntimeException, subscriber), + eventStore) + assertThatThrownBy(() => eventSourcingSystem.dispatch(new EventSourcingSystemTest.MyCommand(EventSourcingSystemTest.PAYLOAD_1))) + .isInstanceOf(classOf[RuntimeException]) + assertThat(subscriber.getData.asJava).isEmpty() + } + + @Test + def dispatchShouldApplyCommandHandlerThenStoreGeneratedEvents(eventStore: EventStore) : Unit = { + val subscriber = new DataCollectorSubscriber + val eventSourcingSystem = new EventSourcingSystem(Set(simpleDispatcher(eventStore)), Set(subscriber), eventStore) + eventSourcingSystem.dispatch(new EventSourcingSystemTest.MyCommand(EventSourcingSystemTest.PAYLOAD_1)) + val expectedEvent = TestEvent(EventId.first, EventSourcingSystemTest.AGGREGATE_ID, EventSourcingSystemTest.PAYLOAD_1) + assertThat(eventStore.getEventsOfAggregate(EventSourcingSystemTest.AGGREGATE_ID).getEvents.asJava).containsOnly(expectedEvent) + } + + @Test + def dispatchShouldCallSubscriberForSubsequentCommands(eventStore: EventStore) : Unit = { + val subscriber = new DataCollectorSubscriber + val eventSourcingSystem = new EventSourcingSystem(Set(simpleDispatcher(eventStore)), Set(subscriber), eventStore) + eventSourcingSystem.dispatch(new EventSourcingSystemTest.MyCommand(EventSourcingSystemTest.PAYLOAD_1)) + eventSourcingSystem.dispatch(new EventSourcingSystemTest.MyCommand(EventSourcingSystemTest.PAYLOAD_2)) + assertThat(subscriber.getData.asJava).containsExactly(EventSourcingSystemTest.PAYLOAD_1, EventSourcingSystemTest.PAYLOAD_2) + } + + @Test + def dispatchShouldStoreEventsForSubsequentCommands(eventStore: EventStore) : Unit = { + val subscriber = new DataCollectorSubscriber + val eventSourcingSystem = new EventSourcingSystem(Set(simpleDispatcher(eventStore)), Set(subscriber), eventStore) + eventSourcingSystem.dispatch(new EventSourcingSystemTest.MyCommand(EventSourcingSystemTest.PAYLOAD_1)) + eventSourcingSystem.dispatch(new EventSourcingSystemTest.MyCommand(EventSourcingSystemTest.PAYLOAD_2)) + val expectedEvent1 = TestEvent(EventId.first, EventSourcingSystemTest.AGGREGATE_ID, EventSourcingSystemTest.PAYLOAD_1) + val expectedEvent2 = TestEvent(expectedEvent1.eventId.next, EventSourcingSystemTest.AGGREGATE_ID, EventSourcingSystemTest.PAYLOAD_2) + assertThat(eventStore.getEventsOfAggregate(EventSourcingSystemTest.AGGREGATE_ID).getEvents.asJava).containsOnly(expectedEvent1, expectedEvent2) + } + + @Test + def dispatcherShouldBeAbleToReturnSeveralEvents(eventStore: EventStore) : Unit = { + val subscriber = new DataCollectorSubscriber + val eventSourcingSystem = new EventSourcingSystem(Set(wordCuttingDispatcher(eventStore)), Set(subscriber), eventStore) + eventSourcingSystem.dispatch(new EventSourcingSystemTest.MyCommand("This is a test")) + assertThat(subscriber.getData.asJava).containsExactly("This", "is", "a", "test") + } + + @Test + def unknownCommandsShouldBeIgnored(eventStore: EventStore) : Unit = { + val subscriber = new DataCollectorSubscriber + val eventSourcingSystem = new EventSourcingSystem(Set(wordCuttingDispatcher(eventStore)), Set(subscriber), eventStore) + assertThatThrownBy(() => eventSourcingSystem.dispatch(new Command() {})) + .isInstanceOf(classOf[CommandDispatcher.UnknownCommandException]) + } + + @Test + def constructorShouldThrowWhenSeveralHandlersForTheSameCommand(eventStore: EventStore) : Unit = { + val subscriber = new DataCollectorSubscriber + assertThatThrownBy(() => new EventSourcingSystem( + Set(wordCuttingDispatcher(eventStore), simpleDispatcher(eventStore)), + Set(subscriber), eventStore)) + .isInstanceOf(classOf[IllegalArgumentException]) + } + + def simpleDispatcher(eventStore: EventStore) = new CommandHandler[EventSourcingSystemTest.MyCommand]() { + override def handledClass: Class[EventSourcingSystemTest.MyCommand] = classOf[EventSourcingSystemTest.MyCommand] + + override def handle(myCommand: EventSourcingSystemTest.MyCommand): List[TestEvent] = { + val history = eventStore.getEventsOfAggregate(EventSourcingSystemTest.AGGREGATE_ID) + List(TestEvent(history.getNextEventId, EventSourcingSystemTest.AGGREGATE_ID, myCommand.getPayload)) + } + } + + def wordCuttingDispatcher(eventStore: EventStore) = new CommandHandler[EventSourcingSystemTest.MyCommand]() { + override def handledClass: Class[EventSourcingSystemTest.MyCommand] = classOf[EventSourcingSystemTest.MyCommand] + + override def handle(myCommand: EventSourcingSystemTest.MyCommand): List[TestEvent] = { + val history = eventStore.getEventsOfAggregate(EventSourcingSystemTest.AGGREGATE_ID) + val eventIdIncrementer = new EventSourcingSystemTest.EventIdIncrementer(history.getNextEventId) + Splitter.on(" ").splitToList(myCommand.getPayload) + .asScala + .toList + .map((word: String) => TestEvent(eventIdIncrementer.next, EventSourcingSystemTest.AGGREGATE_ID, word)) + } + } +} \ No newline at end of file --------------------------------------------------------------------- To unsubscribe, e-mail: server-dev-unsubscr...@james.apache.org For additional commands, e-mail: server-dev-h...@james.apache.org