Repository: james-project
Updated Branches:
  refs/heads/master eeafbf4b5 -> bd195b983


MAILBOX-364 Propose a contract for EventBus API


Project: http://git-wip-us.apache.org/repos/asf/james-project/repo
Commit: http://git-wip-us.apache.org/repos/asf/james-project/commit/cad536c9
Tree: http://git-wip-us.apache.org/repos/asf/james-project/tree/cad536c9
Diff: http://git-wip-us.apache.org/repos/asf/james-project/diff/cad536c9

Branch: refs/heads/master
Commit: cad536c9c93693a2d2004c7bf5dfeaa1f7116555
Parents: 421bd1f
Author: Benoit Tellier <[email protected]>
Authored: Wed Dec 12 14:47:39 2018 +0700
Committer: Benoit Tellier <[email protected]>
Committed: Tue Dec 18 09:09:57 2018 +0700

----------------------------------------------------------------------
 .../james/mailbox/events/EventBusContract.java  | 336 +++++++++++++++++++
 1 file changed, 336 insertions(+)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/james-project/blob/cad536c9/mailbox/api/src/test/java/org/apache/james/mailbox/events/EventBusContract.java
----------------------------------------------------------------------
diff --git 
a/mailbox/api/src/test/java/org/apache/james/mailbox/events/EventBusContract.java
 
b/mailbox/api/src/test/java/org/apache/james/mailbox/events/EventBusContract.java
new file mode 100644
index 0000000..bef6ec3
--- /dev/null
+++ 
b/mailbox/api/src/test/java/org/apache/james/mailbox/events/EventBusContract.java
@@ -0,0 +1,336 @@
+/****************************************************************
+ * 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.mailbox.events;
+
+import static org.assertj.core.api.Assertions.assertThatCode;
+import static org.assertj.core.api.Assertions.assertThatThrownBy;
+import static org.junit.jupiter.api.Assertions.assertTimeout;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.Mockito.doAnswer;
+import static org.mockito.Mockito.doThrow;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.verifyZeroInteractions;
+import static org.mockito.Mockito.when;
+
+import java.time.Duration;
+import java.util.concurrent.CountDownLatch;
+
+import org.apache.james.mailbox.MailboxListener;
+import org.apache.james.mailbox.model.MailboxId;
+import org.apache.james.mailbox.model.TestId;
+import org.junit.jupiter.api.Test;
+
+import com.google.common.collect.ImmutableSet;
+
+public interface EventBusContract {
+    MailboxListener.MailboxEvent event = 
mock(MailboxListener.MailboxEvent.class);
+
+    class GroupA extends Group {}
+    class GroupB extends Group {}
+
+    MailboxId ID_1 = TestId.of(18);
+    MailboxId ID_2 = TestId.of(24);
+    ImmutableSet<RegistrationKey> NO_KEYS = ImmutableSet.of();
+    MailboxIdRegistrationKey KEY_1 = new MailboxIdRegistrationKey(ID_1);
+    MailboxIdRegistrationKey KEY_2 = new MailboxIdRegistrationKey(ID_2);
+
+    EventBus eventBus();
+
+    default MailboxListener newListener() {
+        MailboxListener listener = mock(MailboxListener.class);
+        
when(listener.getExecutionMode()).thenReturn(MailboxListener.ExecutionMode.SYNCHRONOUS);
+        return listener;
+    }
+
+    @Test
+    default void listenerGroupShouldReceiveEvents() {
+        MailboxListener listener = newListener();
+
+        eventBus().register(listener, new GroupA());
+
+        eventBus().dispatch(event, NO_KEYS).block();
+
+        verify(listener, times(1)).event(any());
+    }
+
+    @Test
+    default void dispatchShouldNotThrowWhenAGroupListenerFails() {
+        MailboxListener listener = newListener();
+        doThrow(new RuntimeException()).when(listener).event(any());
+
+        eventBus().register(listener, new GroupA());
+
+        assertThatCode(() -> eventBus().dispatch(event, NO_KEYS).block())
+            .doesNotThrowAnyException();
+    }
+
+    @Test
+    default void dispatchShouldNotThrowWhenARegisteredListenerFails() {
+        MailboxListener listener = newListener();
+        doThrow(new RuntimeException()).when(listener).event(any());
+
+        eventBus().register(listener, KEY_1);
+
+        assertThatCode(() -> eventBus().dispatch(event, NO_KEYS).block())
+            .doesNotThrowAnyException();
+    }
+
+    @Test
+    default void eachListenerGroupShouldReceiveEvents() {
+        MailboxListener listener = newListener();
+        MailboxListener listener2 = newListener();
+        eventBus().register(listener, new GroupA());
+        eventBus().register(listener2, new GroupB());
+
+        eventBus().dispatch(event, NO_KEYS).block();
+
+        verify(listener, times(1)).event(any());
+        verify(listener2, times(1)).event(any());
+    }
+
+    @Test
+    default void unregisteredGroupListenerShouldNotReceiveEvents() {
+        MailboxListener listener = newListener();
+        Registration registration = eventBus().register(listener, new 
GroupA());
+
+        registration.unregister();
+
+        eventBus().dispatch(event, NO_KEYS).block();
+        verifyZeroInteractions(listener);
+    }
+
+    @Test
+    default void registerShouldThrowWhenAGroupIsAlreadyUsed() {
+        MailboxListener listener = newListener();
+        MailboxListener listener2 = newListener();
+
+        eventBus().register(listener, new GroupA());
+
+        assertThatThrownBy(() -> eventBus().register(listener2, new GroupA()))
+            .isInstanceOf(GroupAlreadyRegistered.class);
+    }
+
+    @Test
+    default void registerShouldNotThrowOnAnUnregisteredGroup() {
+        MailboxListener listener = newListener();
+        MailboxListener listener2 = newListener();
+
+        eventBus().register(listener, new GroupA()).unregister();
+
+        assertThatCode(() -> eventBus().register(listener2, new GroupA()))
+            .doesNotThrowAnyException();
+    }
+
+    @Test
+    default void unregisterShouldBeIdempotentForGroups() {
+        MailboxListener listener = newListener();
+
+        Registration registration = eventBus().register(listener, new 
GroupA());
+        registration.unregister();
+
+        assertThatCode(registration::unregister)
+            .doesNotThrowAnyException();
+    }
+
+    @Test
+    default void registerShouldAcceptAlreadyUnregisteredGroups() {
+        MailboxListener listener = newListener();
+
+        eventBus().register(listener, new GroupA()).unregister();
+        eventBus().register(listener, new GroupA());
+
+        eventBus().dispatch(event, NO_KEYS).block();
+
+        verify(listener, times(1)).event(any());
+    }
+
+    @Test
+    default void dispatchShouldNotNotifyRegisteredListenerWhenEmptyKeySet() {
+        MailboxListener listener = newListener();
+        eventBus().register(listener, KEY_1);
+
+        eventBus().dispatch(event, NO_KEYS).block();
+
+        verifyZeroInteractions(listener);
+    }
+
+    @Test
+    default void dispatchShouldNotNotifyListenerRegisteredOnOtherKeys() {
+        MailboxListener listener = newListener();
+        eventBus().register(listener, KEY_1);
+
+        eventBus().dispatch(event, ImmutableSet.of(KEY_2)).block();
+
+        verifyZeroInteractions(listener);
+    }
+
+    @Test
+    default void dispatchShouldNotifyRegisteredListeners() {
+        MailboxListener listener = newListener();
+        eventBus().register(listener, KEY_1);
+
+        eventBus().dispatch(event, ImmutableSet.of(KEY_1)).block();
+
+        verify(listener, times(1)).event(any());
+    }
+
+    @Test
+    default void dispatchShouldNotifyOnlyRegisteredListener() {
+        MailboxListener listener = newListener();
+        MailboxListener listener2 = newListener();
+        eventBus().register(listener, KEY_1);
+        eventBus().register(listener2, KEY_2);
+
+        eventBus().dispatch(event, ImmutableSet.of(KEY_1)).block();
+
+        verify(listener, times(1)).event(any());
+        verifyZeroInteractions(listener2);
+    }
+
+    @Test
+    default void dispatchShouldNotifyAllListenersRegisteredOnAKey() {
+        MailboxListener listener = newListener();
+        MailboxListener listener2 = newListener();
+        eventBus().register(listener, KEY_1);
+        eventBus().register(listener2, KEY_1);
+
+        eventBus().dispatch(event, ImmutableSet.of(KEY_1)).block();
+
+        verify(listener, times(1)).event(any());
+        verify(listener2, times(1)).event(any());
+    }
+
+    @Test
+    default void registerShouldAllowDuplicatedRegistration() {
+        MailboxListener listener = newListener();
+        eventBus().register(listener, KEY_1);
+        eventBus().register(listener, KEY_1);
+
+        eventBus().dispatch(event, ImmutableSet.of(KEY_1)).block();
+
+        verify(listener, times(1)).event(any());
+    }
+
+    @Test
+    default void unregisterShouldRemoveDoubleRegisteredListener() {
+        MailboxListener listener = newListener();
+        eventBus().register(listener, KEY_1);
+        eventBus().register(listener, KEY_1).unregister();
+
+        eventBus().dispatch(event, ImmutableSet.of(KEY_1)).block();
+
+        verifyZeroInteractions(listener);
+    }
+
+    @Test
+    default void callingAllUnregisterMethodShouldUnregisterTheListener() {
+        MailboxListener listener = newListener();
+        Registration registration = eventBus().register(listener, KEY_1);
+        eventBus().register(listener, KEY_1).unregister();
+        registration.unregister();
+
+        eventBus().dispatch(event, ImmutableSet.of(KEY_1)).block();
+
+        verifyZeroInteractions(listener);
+    }
+
+    @Test
+    default void unregisterShouldHaveNotNotifyWhenCalledOnDifferentKeys() {
+        MailboxListener listener = newListener();
+        eventBus().register(listener, KEY_1);
+        eventBus().register(listener, KEY_2).unregister();
+
+        eventBus().dispatch(event, ImmutableSet.of(KEY_1)).block();
+
+        verify(listener, times(1)).event(any());
+    }
+
+    @Test
+    default void unregisterShouldBeIdempotentForKeyRegistrations() {
+        MailboxListener listener = newListener();
+
+        Registration registration = eventBus().register(listener, KEY_1);
+        registration.unregister();
+
+        assertThatCode(registration::unregister)
+            .doesNotThrowAnyException();
+    }
+
+    @Test
+    default void dispatchShouldAcceptSeveralKeys() {
+        MailboxListener listener = newListener();
+        eventBus().register(listener, KEY_1);
+
+        eventBus().dispatch(event, ImmutableSet.of(KEY_1, KEY_2)).block();
+
+        verify(listener, times(1)).event(any());
+    }
+
+    @Test
+    default void dispatchShouldCallListenerOnceWhenSeveralKeysMatching() {
+        MailboxListener listener = newListener();
+        eventBus().register(listener, KEY_1);
+        eventBus().register(listener, KEY_2);
+
+        eventBus().dispatch(event, ImmutableSet.of(KEY_1, KEY_2)).block();
+
+        verify(listener, times(1)).event(any());
+    }
+
+    @Test
+    default void dispatchShouldNotNotifyUnregisteredListener() {
+        MailboxListener listener = newListener();
+        eventBus().register(listener, KEY_1).unregister();
+
+        eventBus().dispatch(event, ImmutableSet.of(KEY_1)).block();
+
+        verifyZeroInteractions(listener);
+    }
+
+    @Test
+    default void dispatchShouldCallSynchronousListener() {
+        MailboxListener listener = newListener();
+
+        eventBus().register(listener, new GroupA());
+
+        eventBus().dispatch(event, NO_KEYS).block();
+
+        verify(listener, times(1)).event(any());
+    }
+
+    @Test
+    default void dispatchShouldNotBlockAsynchronousListener() {
+        MailboxListener listener = newListener();
+        
when(listener.getExecutionMode()).thenReturn(MailboxListener.ExecutionMode.ASYNCHRONOUS);
+        CountDownLatch latch = new CountDownLatch(1);
+        doAnswer(invocation -> {
+            latch.await();
+            return null;
+        }).when(listener).event(event);
+
+        assertTimeout(Duration.ofSeconds(2),
+            () -> {
+                eventBus().dispatch(event, NO_KEYS).block();
+                latch.countDown();
+            });
+    }
+}


---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to