1 /*
2  * Copyright (C) 2016 The Android Open Source Project
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 android.os.test;
18 
19 import static org.hamcrest.core.IsEqual.equalTo;
20 import static org.junit.Assert.assertEquals;
21 import static org.junit.Assert.assertTrue;
22 import static org.mockito.Matchers.any;
23 import static org.mockito.Mockito.inOrder;
24 import static org.mockito.Mockito.mock;
25 import static org.mockito.Mockito.never;
26 import static org.mockito.Mockito.spy;
27 
28 import android.os.Handler;
29 import android.os.Looper;
30 import android.os.Message;
31 import android.test.suitebuilder.annotation.SmallTest;
32 
33 import org.junit.Before;
34 import org.junit.Rule;
35 import org.junit.Test;
36 import org.junit.rules.ErrorCollector;
37 import org.mockito.ArgumentCaptor;
38 import org.mockito.InOrder;
39 import org.mockito.MockitoAnnotations;
40 
41 import java.util.concurrent.Executor;
42 
43 /**
44  * Test TestLooperAbstractTime which provides control over "time". Note that
45  * real-time is being used as well. Therefore small time increments are NOT
46  * reliable. All tests are in "K" units (i.e. *1000).
47  */
48 
49 @SmallTest
50 public class TestLooperTest {
51     private TestLooper mTestLooper;
52     private Handler mHandler;
53     private Handler mHandlerSpy;
54     private Executor mExecutor;
55 
56     @Rule
57     public ErrorCollector collector = new ErrorCollector();
58 
59     @Before
setUp()60     public void setUp() throws Exception {
61         MockitoAnnotations.initMocks(this);
62 
63         mTestLooper = new TestLooper();
64         mHandler = new Handler(mTestLooper.getLooper());
65         mHandlerSpy = spy(mHandler);
66         mExecutor = mTestLooper.getNewExecutor();
67     }
68 
69     /**
70      * Basic test with no time stamps: dispatch 4 messages, check that all 4
71      * delivered (in correct order).
72      */
73     @Test
testNoTimeMovement()74     public void testNoTimeMovement() {
75         final int messageA = 1;
76         final int messageB = 2;
77         final int messageC = 3;
78 
79         InOrder inOrder = inOrder(mHandlerSpy);
80         ArgumentCaptor<Message> messageCaptor = ArgumentCaptor.forClass(Message.class);
81 
82         mHandlerSpy.sendMessage(mHandler.obtainMessage(messageA));
83         mHandlerSpy.sendMessage(mHandler.obtainMessage(messageA));
84         mHandlerSpy.sendMessage(mHandler.obtainMessage(messageB));
85         mHandlerSpy.sendMessage(mHandler.obtainMessage(messageC));
86         mTestLooper.dispatchAll();
87 
88         inOrder.verify(mHandlerSpy).handleMessage(messageCaptor.capture());
89         collector.checkThat("1: messageA", messageA, equalTo(messageCaptor.getValue().what));
90         inOrder.verify(mHandlerSpy).handleMessage(messageCaptor.capture());
91         collector.checkThat("2: messageA", messageA, equalTo(messageCaptor.getValue().what));
92         inOrder.verify(mHandlerSpy).handleMessage(messageCaptor.capture());
93         collector.checkThat("3: messageB", messageB, equalTo(messageCaptor.getValue().what));
94         inOrder.verify(mHandlerSpy).handleMessage(messageCaptor.capture());
95         collector.checkThat("4: messageC", messageC, equalTo(messageCaptor.getValue().what));
96 
97         inOrder.verify(mHandlerSpy, never()).handleMessage(any(Message.class));
98     }
99 
100     /**
101      * Basic test of the Executor with no time stamps: dispatch 4 executables, check that all 4
102      * executed in correct order.
103      */
104     @Test
testNoTimeMovementExecutor()105     public void testNoTimeMovementExecutor() {
106         final Runnable runnableA = mock(Runnable.class);
107         final Runnable runnableB = mock(Runnable.class);
108         final Runnable runnableC = mock(Runnable.class);
109 
110         InOrder inOrder = inOrder(runnableA, runnableB, runnableC);
111 
112         mExecutor.execute(runnableA);
113         mExecutor.execute(runnableB);
114         mExecutor.execute(runnableA);
115         mExecutor.execute(runnableC);
116         mTestLooper.dispatchAll();
117 
118         inOrder.verify(runnableA).run();
119         inOrder.verify(runnableB).run();
120         inOrder.verify(runnableA).run();
121         inOrder.verify(runnableC).run();
122 
123         inOrder.verifyNoMoreInteractions();
124     }
125 
126     /**
127      * Test message sequence: A, B, C@5K, A@10K. Don't move time.
128      * <p>
129      * Expected: only get A, B
130      */
131     @Test
testDelayedDispatchNoTimeMove()132     public void testDelayedDispatchNoTimeMove() {
133         final int messageA = 1;
134         final int messageB = 2;
135         final int messageC = 3;
136 
137         InOrder inOrder = inOrder(mHandlerSpy);
138         ArgumentCaptor<Message> messageCaptor = ArgumentCaptor.forClass(Message.class);
139 
140         mHandlerSpy.sendMessage(mHandler.obtainMessage(messageA));
141         mHandlerSpy.sendMessage(mHandler.obtainMessage(messageB));
142         mHandlerSpy.sendMessageDelayed(mHandler.obtainMessage(messageC), 5000);
143         mHandlerSpy.sendMessageDelayed(mHandler.obtainMessage(messageA), 10000);
144         mTestLooper.dispatchAll();
145 
146         inOrder.verify(mHandlerSpy).handleMessage(messageCaptor.capture());
147         collector.checkThat("1: messageA", messageA, equalTo(messageCaptor.getValue().what));
148         inOrder.verify(mHandlerSpy).handleMessage(messageCaptor.capture());
149         collector.checkThat("2: messageB", messageB, equalTo(messageCaptor.getValue().what));
150 
151         inOrder.verify(mHandlerSpy, never()).handleMessage(any(Message.class));
152     }
153 
154     /**
155      * Test message sequence: A, B, C@5K, A@10K, Advance time by 5K.
156      * <p>
157      * Expected: only get A, B, C
158      */
159     @Test
testDelayedDispatchAdvanceTimeOnce()160     public void testDelayedDispatchAdvanceTimeOnce() {
161         final int messageA = 1;
162         final int messageB = 2;
163         final int messageC = 3;
164 
165         InOrder inOrder = inOrder(mHandlerSpy);
166         ArgumentCaptor<Message> messageCaptor = ArgumentCaptor.forClass(Message.class);
167 
168         mHandlerSpy.sendMessage(mHandler.obtainMessage(messageA));
169         mHandlerSpy.sendMessage(mHandler.obtainMessage(messageB));
170         mHandlerSpy.sendMessageDelayed(mHandler.obtainMessage(messageC), 5000);
171         mHandlerSpy.sendMessageDelayed(mHandler.obtainMessage(messageA), 10000);
172         mTestLooper.moveTimeForward(5000);
173         mTestLooper.dispatchAll();
174 
175         inOrder.verify(mHandlerSpy).handleMessage(messageCaptor.capture());
176         collector.checkThat("1: messageA", messageA, equalTo(messageCaptor.getValue().what));
177         inOrder.verify(mHandlerSpy).handleMessage(messageCaptor.capture());
178         collector.checkThat("2: messageB", messageB, equalTo(messageCaptor.getValue().what));
179         inOrder.verify(mHandlerSpy).handleMessage(messageCaptor.capture());
180         collector.checkThat("3: messageC", messageC, equalTo(messageCaptor.getValue().what));
181 
182         inOrder.verify(mHandlerSpy, never()).handleMessage(any(Message.class));
183     }
184 
185     /**
186      * Test message sequence: A, B, C@5K, Advance time by 4K, A@1K, B@2K Advance
187      * time by 1K.
188      * <p>
189      * Expected: get A, B, C, A
190      */
191     @Test
testDelayedDispatchAdvanceTimeTwice()192     public void testDelayedDispatchAdvanceTimeTwice() {
193         final int messageA = 1;
194         final int messageB = 2;
195         final int messageC = 3;
196 
197         InOrder inOrder = inOrder(mHandlerSpy);
198         ArgumentCaptor<Message> messageCaptor = ArgumentCaptor.forClass(Message.class);
199 
200         mHandlerSpy.sendMessage(mHandler.obtainMessage(messageA));
201         mHandlerSpy.sendMessage(mHandler.obtainMessage(messageB));
202         mHandlerSpy.sendMessageDelayed(mHandler.obtainMessage(messageC), 5000);
203         mTestLooper.moveTimeForward(4000);
204         mHandlerSpy.sendMessageDelayed(mHandler.obtainMessage(messageA), 1000);
205         mHandlerSpy.sendMessageDelayed(mHandler.obtainMessage(messageB), 2000);
206         mTestLooper.moveTimeForward(1000);
207         mTestLooper.dispatchAll();
208 
209         inOrder.verify(mHandlerSpy).handleMessage(messageCaptor.capture());
210         collector.checkThat("1: messageA", messageA, equalTo(messageCaptor.getValue().what));
211         inOrder.verify(mHandlerSpy).handleMessage(messageCaptor.capture());
212         collector.checkThat("2: messageB", messageB, equalTo(messageCaptor.getValue().what));
213         inOrder.verify(mHandlerSpy).handleMessage(messageCaptor.capture());
214         collector.checkThat("3: messageC", messageC, equalTo(messageCaptor.getValue().what));
215         inOrder.verify(mHandlerSpy).handleMessage(messageCaptor.capture());
216         collector.checkThat("4: messageA", messageA, equalTo(messageCaptor.getValue().what));
217 
218         inOrder.verify(mHandlerSpy, never()).handleMessage(any(Message.class));
219     }
220 
221     /**
222      * Test message sequence: A, B, C@5K, Advance time by 4K, A@5K, B@2K Advance
223      * time by 3K.
224      * <p>
225      * Expected: get A, B, C, B
226      */
227     @Test
testDelayedDispatchReverseOrder()228     public void testDelayedDispatchReverseOrder() {
229         final int messageA = 1;
230         final int messageB = 2;
231         final int messageC = 3;
232 
233         InOrder inOrder = inOrder(mHandlerSpy);
234         ArgumentCaptor<Message> messageCaptor = ArgumentCaptor.forClass(Message.class);
235 
236         mHandlerSpy.sendMessage(mHandler.obtainMessage(messageA));
237         mHandlerSpy.sendMessage(mHandler.obtainMessage(messageB));
238         mHandlerSpy.sendMessageDelayed(mHandler.obtainMessage(messageC), 5000);
239         mTestLooper.moveTimeForward(4000);
240         mHandlerSpy.sendMessageDelayed(mHandler.obtainMessage(messageA), 5000);
241         mHandlerSpy.sendMessageDelayed(mHandler.obtainMessage(messageB), 2000);
242         mTestLooper.moveTimeForward(3000);
243         mTestLooper.dispatchAll();
244 
245         inOrder.verify(mHandlerSpy).handleMessage(messageCaptor.capture());
246         collector.checkThat("1: messageA", messageA, equalTo(messageCaptor.getValue().what));
247         inOrder.verify(mHandlerSpy).handleMessage(messageCaptor.capture());
248         collector.checkThat("2: messageB", messageB, equalTo(messageCaptor.getValue().what));
249         inOrder.verify(mHandlerSpy).handleMessage(messageCaptor.capture());
250         collector.checkThat("3: messageC", messageC, equalTo(messageCaptor.getValue().what));
251         inOrder.verify(mHandlerSpy).handleMessage(messageCaptor.capture());
252         collector.checkThat("4: messageB", messageB, equalTo(messageCaptor.getValue().what));
253 
254         inOrder.verify(mHandlerSpy, never()).handleMessage(any(Message.class));
255     }
256 
257     /**
258      * Test message sequence: A, B, C@5K, Advance time by 4K, dispatch all,
259      * A@5K, B@2K Advance time by 3K, dispatch all.
260      * <p>
261      * Expected: get A, B after first dispatch; then C, B after second dispatch
262      */
263     @Test
testDelayedDispatchAllMultipleTimes()264     public void testDelayedDispatchAllMultipleTimes() {
265         final int messageA = 1;
266         final int messageB = 2;
267         final int messageC = 3;
268 
269         InOrder inOrder = inOrder(mHandlerSpy);
270         ArgumentCaptor<Message> messageCaptor = ArgumentCaptor.forClass(Message.class);
271 
272         mHandlerSpy.sendMessage(mHandler.obtainMessage(messageA));
273         mHandlerSpy.sendMessage(mHandler.obtainMessage(messageB));
274         mHandlerSpy.sendMessageDelayed(mHandler.obtainMessage(messageC), 5000);
275         mTestLooper.moveTimeForward(4000);
276         mTestLooper.dispatchAll();
277 
278         inOrder.verify(mHandlerSpy).handleMessage(messageCaptor.capture());
279         collector.checkThat("1: messageA", messageA, equalTo(messageCaptor.getValue().what));
280         inOrder.verify(mHandlerSpy).handleMessage(messageCaptor.capture());
281         collector.checkThat("2: messageB", messageB, equalTo(messageCaptor.getValue().what));
282 
283         mHandlerSpy.sendMessageDelayed(mHandler.obtainMessage(messageA), 5000);
284         mHandlerSpy.sendMessageDelayed(mHandler.obtainMessage(messageB), 2000);
285         mTestLooper.moveTimeForward(3000);
286         mTestLooper.dispatchAll();
287 
288         inOrder.verify(mHandlerSpy).handleMessage(messageCaptor.capture());
289         collector.checkThat("3: messageC", messageC, equalTo(messageCaptor.getValue().what));
290         inOrder.verify(mHandlerSpy).handleMessage(messageCaptor.capture());
291         collector.checkThat("4: messageB", messageB, equalTo(messageCaptor.getValue().what));
292 
293         inOrder.verify(mHandlerSpy, never()).handleMessage(any(Message.class));
294     }
295 
296     /**
297      * Test AutoDispatch for a single message.
298      * This test would ideally use the Channel sendMessageSynchronously.  At this time, the setup to
299      * get a working test channel is cumbersome.  Until this is fixed, we substitute with a
300      * sendMessage followed by a blocking call.  The main test thread blocks until the test handler
301      * receives the test message (messageA) and sets a boolean true.  Once the boolean is true, the
302      * main thread will exit the busy wait loop, stop autoDispatch and check the assert.
303      *
304      * Enable AutoDispatch, add message, block on message being handled and stop AutoDispatch.
305      * <p>
306      * Expected: handleMessage is called for messageA and stopAutoDispatch is called.
307      */
308     @Test
testAutoDispatchWithSingleMessage()309     public void testAutoDispatchWithSingleMessage() {
310         final int mLoopSleepTimeMs = 5;
311 
312         final int messageA = 1;
313 
314         TestLooper mockLooper = new TestLooper();
315         class TestHandler extends Handler {
316             public volatile boolean handledMessage = false;
317             TestHandler(Looper looper) {
318                 super(looper);
319             }
320 
321             @Override
322             public void handleMessage(Message msg) {
323                 if (msg.what == messageA) {
324                     handledMessage = true;
325                 }
326             }
327         }
328 
329         TestHandler testHandler = new TestHandler(mockLooper.getLooper());
330         mockLooper.startAutoDispatch();
331         testHandler.sendMessage(testHandler.obtainMessage(messageA));
332         while (!testHandler.handledMessage) {
333             // Block until message is handled
334             try {
335                 Thread.sleep(mLoopSleepTimeMs);
336             } catch (InterruptedException e) {
337                 // Interrupted while sleeping.
338             }
339         }
340         mockLooper.stopAutoDispatch();
341         assertTrue("TestHandler should have received messageA", testHandler.handledMessage);
342     }
343 
344     /**
345      * Test starting AutoDispatch while already running throws IllegalStateException
346      * Enable AutoDispatch two times in a row.
347      * <p>
348      * Expected: catch IllegalStateException on second call.
349      */
350     @Test(expected = IllegalStateException.class)
testRepeatedStartAutoDispatchThrowsException()351     public void testRepeatedStartAutoDispatchThrowsException() {
352         mTestLooper.startAutoDispatch();
353         mTestLooper.startAutoDispatch();
354     }
355 
356     /**
357      * Test stopping AutoDispatch without previously starting throws IllegalStateException
358      * Stop AutoDispatch
359      * <p>
360      * Expected: catch IllegalStateException on second call.
361      */
362     @Test(expected = IllegalStateException.class)
testStopAutoDispatchWithoutStartThrowsException()363     public void testStopAutoDispatchWithoutStartThrowsException() {
364         mTestLooper.stopAutoDispatch();
365     }
366 
367     /**
368      * Test AutoDispatch exits and does not dispatch a later message.
369      * Start and stop AutoDispatch then add a message.
370      * <p>
371      * Expected: After AutoDispatch is stopped, dispatchAll will return 1.
372      */
373     @Test
testAutoDispatchStopsCleanlyWithoutDispatchingAMessage()374     public void testAutoDispatchStopsCleanlyWithoutDispatchingAMessage() {
375         final int messageA = 1;
376 
377         InOrder inOrder = inOrder(mHandlerSpy);
378         ArgumentCaptor<Message> messageCaptor = ArgumentCaptor.forClass(Message.class);
379 
380         mTestLooper.startAutoDispatch();
381         try {
382             mTestLooper.stopAutoDispatch();
383         } catch (IllegalStateException e) {
384             //  Stopping without a dispatch will throw an exception.
385         }
386 
387         mHandlerSpy.sendMessage(mHandler.obtainMessage(messageA));
388         assertEquals("One message should be dispatched", 1, mTestLooper.dispatchAll());
389     }
390 
391     /**
392      * Test AutoDispatch throws an exception when no messages are dispatched.
393      * Start and stop AutoDispatch
394      * <p>
395      * Expected: Exception is thrown with the stopAutoDispatch call.
396      */
397     @Test(expected = IllegalStateException.class)
testAutoDispatchThrowsExceptionWhenNoMessagesDispatched()398     public void testAutoDispatchThrowsExceptionWhenNoMessagesDispatched() {
399         mTestLooper.startAutoDispatch();
400         mTestLooper.stopAutoDispatch();
401     }
402 }
403