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