• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2014 The Guava Authors
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package com.google.common.eventbus;
18 
19 import static com.google.common.truth.Truth.assertThat;
20 
21 import com.google.common.collect.ImmutableList;
22 import com.google.common.collect.Queues;
23 import com.google.common.util.concurrent.Uninterruptibles;
24 import java.util.concurrent.ConcurrentLinkedQueue;
25 import java.util.concurrent.CountDownLatch;
26 import java.util.concurrent.CyclicBarrier;
27 import junit.framework.TestCase;
28 
29 /**
30  * Tests for {@link Dispatcher} implementations.
31  *
32  * @author Colin Decker
33  */
34 public class DispatcherTest extends TestCase {
35 
36   private final EventBus bus = new EventBus();
37 
38   private final IntegerSubscriber i1 = new IntegerSubscriber("i1");
39   private final IntegerSubscriber i2 = new IntegerSubscriber("i2");
40   private final IntegerSubscriber i3 = new IntegerSubscriber("i3");
41   private final ImmutableList<Subscriber> integerSubscribers =
42       ImmutableList.of(
43           subscriber(bus, i1, "handleInteger", Integer.class),
44           subscriber(bus, i2, "handleInteger", Integer.class),
45           subscriber(bus, i3, "handleInteger", Integer.class));
46 
47   private final StringSubscriber s1 = new StringSubscriber("s1");
48   private final StringSubscriber s2 = new StringSubscriber("s2");
49   private final ImmutableList<Subscriber> stringSubscribers =
50       ImmutableList.of(
51           subscriber(bus, s1, "handleString", String.class),
52           subscriber(bus, s2, "handleString", String.class));
53 
54   private final ConcurrentLinkedQueue<Object> dispatchedSubscribers =
55       Queues.newConcurrentLinkedQueue();
56 
57   private Dispatcher dispatcher;
58 
testPerThreadQueuedDispatcher()59   public void testPerThreadQueuedDispatcher() {
60     dispatcher = Dispatcher.perThreadDispatchQueue();
61     dispatcher.dispatch(1, integerSubscribers.iterator());
62 
63     assertThat(dispatchedSubscribers)
64         .containsExactly(
65             i1,
66             i2,
67             i3, // Integer subscribers are dispatched to first.
68             s1,
69             s2, // Though each integer subscriber dispatches to all string subscribers,
70             s1,
71             s2, // those string subscribers aren't actually dispatched to until all integer
72             s1,
73             s2 // subscribers have finished.
74             )
75         .inOrder();
76   }
77 
testLegacyAsyncDispatcher()78   public void testLegacyAsyncDispatcher() {
79     dispatcher = Dispatcher.legacyAsync();
80 
81     final CyclicBarrier barrier = new CyclicBarrier(2);
82     final CountDownLatch latch = new CountDownLatch(2);
83 
84     new Thread(
85             new Runnable() {
86               @Override
87               public void run() {
88                 try {
89                   barrier.await();
90                 } catch (Exception e) {
91                   throw new AssertionError(e);
92                 }
93 
94                 dispatcher.dispatch(2, integerSubscribers.iterator());
95                 latch.countDown();
96               }
97             })
98         .start();
99 
100     new Thread(
101             new Runnable() {
102               @Override
103               public void run() {
104                 try {
105                   barrier.await();
106                 } catch (Exception e) {
107                   throw new AssertionError(e);
108                 }
109 
110                 dispatcher.dispatch("foo", stringSubscribers.iterator());
111                 latch.countDown();
112               }
113             })
114         .start();
115 
116     Uninterruptibles.awaitUninterruptibly(latch);
117 
118     // See Dispatcher.LegacyAsyncDispatcher for an explanation of why there aren't really any
119     // useful testable guarantees about the behavior of that dispatcher in a multithreaded
120     // environment. Here we simply test that all the expected dispatches happened in some order.
121     assertThat(dispatchedSubscribers).containsExactly(i1, i2, i3, s1, s1, s1, s1, s2, s2, s2, s2);
122   }
123 
testImmediateDispatcher()124   public void testImmediateDispatcher() {
125     dispatcher = Dispatcher.immediate();
126     dispatcher.dispatch(1, integerSubscribers.iterator());
127 
128     assertThat(dispatchedSubscribers)
129         .containsExactly(
130             i1, s1, s2, // Each integer subscriber immediately dispatches to 2 string subscribers.
131             i2, s1, s2, i3, s1, s2)
132         .inOrder();
133   }
134 
subscriber( EventBus bus, Object target, String methodName, Class<?> eventType)135   private static Subscriber subscriber(
136       EventBus bus, Object target, String methodName, Class<?> eventType) {
137     try {
138       return Subscriber.create(bus, target, target.getClass().getMethod(methodName, eventType));
139     } catch (NoSuchMethodException e) {
140       throw new AssertionError(e);
141     }
142   }
143 
144   public final class IntegerSubscriber {
145     private final String name;
146 
IntegerSubscriber(String name)147     public IntegerSubscriber(String name) {
148       this.name = name;
149     }
150 
151     @Subscribe
handleInteger(Integer integer)152     public void handleInteger(Integer integer) {
153       dispatchedSubscribers.add(this);
154       dispatcher.dispatch("hello", stringSubscribers.iterator());
155     }
156 
157     @Override
toString()158     public String toString() {
159       return name;
160     }
161   }
162 
163   public final class StringSubscriber {
164     private final String name;
165 
StringSubscriber(String name)166     public StringSubscriber(String name) {
167       this.name = name;
168     }
169 
170     @Subscribe
handleString(String string)171     public void handleString(String string) {
172       dispatchedSubscribers.add(this);
173     }
174 
175     @Override
toString()176     public String toString() {
177       return name;
178     }
179   }
180 }
181