| /* |
| * Copyright (C) 2014 The Guava Authors |
| * |
| * Licensed 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 com.google.common.eventbus; |
| |
| import static com.google.common.truth.Truth.assertThat; |
| |
| import com.google.common.collect.ImmutableList; |
| import com.google.common.collect.Queues; |
| import com.google.common.util.concurrent.Uninterruptibles; |
| |
| import junit.framework.TestCase; |
| |
| import java.util.concurrent.ConcurrentLinkedQueue; |
| import java.util.concurrent.CountDownLatch; |
| import java.util.concurrent.CyclicBarrier; |
| |
| /** |
| * Tests for {@link Dispatcher} implementations. |
| * |
| * @author Colin Decker |
| */ |
| |
| public class DispatcherTest extends TestCase { |
| |
| private final EventBus bus = new EventBus(); |
| |
| private final IntegerSubscriber i1 = new IntegerSubscriber("i1"); |
| private final IntegerSubscriber i2 = new IntegerSubscriber("i2"); |
| private final IntegerSubscriber i3 = new IntegerSubscriber("i3"); |
| private final ImmutableList<Subscriber> integerSubscribers = ImmutableList.of( |
| subscriber(bus, i1, "handleInteger", Integer.class), |
| subscriber(bus, i2, "handleInteger", Integer.class), |
| subscriber(bus, i3, "handleInteger", Integer.class)); |
| |
| private final StringSubscriber s1 = new StringSubscriber("s1"); |
| private final StringSubscriber s2 = new StringSubscriber("s2"); |
| private final ImmutableList<Subscriber> stringSubscribers = ImmutableList.of( |
| subscriber(bus, s1, "handleString", String.class), |
| subscriber(bus, s2, "handleString", String.class)); |
| |
| private final ConcurrentLinkedQueue<Object> dispatchedSubscribers |
| = Queues.newConcurrentLinkedQueue(); |
| |
| private Dispatcher dispatcher; |
| |
| public void testPerThreadQueuedDispatcher() { |
| dispatcher = Dispatcher.perThreadDispatchQueue(); |
| dispatcher.dispatch(1, integerSubscribers.iterator()); |
| |
| assertThat(dispatchedSubscribers) |
| .has().exactly( |
| i1, i2, i3, // Integer subscribers are dispatched to first. |
| s1, s2, // Though each integer subscriber dispatches to all string subscribers, |
| s1, s2, // those string subscribers aren't actually dispatched to until all integer |
| s1, s2 // subscribers have finished. |
| ).inOrder(); |
| } |
| |
| public void testLegacyAsyncDispatcher() { |
| dispatcher = Dispatcher.legacyAsync(); |
| |
| final CyclicBarrier barrier = new CyclicBarrier(2); |
| final CountDownLatch latch = new CountDownLatch(2); |
| |
| new Thread(new Runnable() { |
| @Override |
| public void run() { |
| try { |
| barrier.await(); |
| } catch (Exception e) { |
| throw new AssertionError(e); |
| } |
| |
| dispatcher.dispatch(2, integerSubscribers.iterator()); |
| latch.countDown(); |
| } |
| }).start(); |
| |
| new Thread(new Runnable() { |
| @Override |
| public void run() { |
| try { |
| barrier.await(); |
| } catch (Exception e) { |
| throw new AssertionError(e); |
| } |
| |
| dispatcher.dispatch("foo", stringSubscribers.iterator()); |
| latch.countDown(); |
| } |
| }).start(); |
| |
| Uninterruptibles.awaitUninterruptibly(latch); |
| |
| // See Dispatcher.LegacyAsyncDispatcher for an explanation of why there aren't really any |
| // useful testable guarantees about the behavior of that dispatcher in a multithreaded |
| // environment. Here we simply test that all the expected dispatches happened in some order. |
| assertThat(dispatchedSubscribers) |
| .has().exactly( |
| i1, i2, i3, |
| s1, s1, s1, s1, |
| s2, s2, s2, s2); |
| } |
| |
| public void testImmediateDispatcher() { |
| dispatcher = Dispatcher.immediate(); |
| dispatcher.dispatch(1, integerSubscribers.iterator()); |
| |
| assertThat(dispatchedSubscribers) |
| .has().exactly( |
| i1, s1, s2, // Each integer subscriber immediately dispatches to 2 string subscribers. |
| i2, s1, s2, |
| i3, s1, s2 |
| ).inOrder(); |
| } |
| |
| private static Subscriber subscriber( |
| EventBus bus, Object target, |
| String methodName, Class<?> eventType) { |
| try { |
| return Subscriber.create(bus, target, target.getClass().getMethod(methodName, eventType)); |
| } catch (NoSuchMethodException e) { |
| throw new AssertionError(e); |
| } |
| } |
| |
| public final class IntegerSubscriber { |
| private final String name; |
| |
| public IntegerSubscriber(String name) { |
| this.name = name; |
| } |
| |
| @Subscribe |
| public void handleInteger(Integer integer) { |
| dispatchedSubscribers.add(this); |
| dispatcher.dispatch("hello", stringSubscribers.iterator()); |
| } |
| |
| @Override |
| public String toString() { |
| return name; |
| } |
| } |
| |
| public final class StringSubscriber { |
| private final String name; |
| |
| public StringSubscriber(String name) { |
| this.name = name; |
| } |
| |
| @Subscribe |
| public void handleString(String string) { |
| dispatchedSubscribers.add(this); |
| } |
| |
| @Override |
| public String toString() { |
| return name; |
| } |
| } |
| } |