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
17package com.android.server.wifi;
18
19import static org.hamcrest.core.IsEqual.equalTo;
20import static org.junit.Assert.assertEquals;
21import static org.junit.Assert.assertTrue;
22import static org.mockito.Matchers.any;
23import static org.mockito.Mockito.inOrder;
24import static org.mockito.Mockito.never;
25import static org.mockito.Mockito.spy;
26
27import android.os.Handler;
28import android.os.Looper;
29import android.os.Message;
30import android.test.suitebuilder.annotation.SmallTest;
31
32import org.junit.Before;
33import org.junit.Rule;
34import org.junit.Test;
35import org.junit.rules.ErrorCollector;
36import org.mockito.ArgumentCaptor;
37import org.mockito.InOrder;
38import org.mockito.MockitoAnnotations;
39
40/**
41 * Test MockLooperAbstractTime 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
47public class MockLooperTest {
48    private MockLooper mMockLooper;
49    private Handler mHandler;
50    private Handler mHandlerSpy;
51
52    @Rule
53    public ErrorCollector collector = new ErrorCollector();
54
55    @Before
56    public void setUp() throws Exception {
57        MockitoAnnotations.initMocks(this);
58
59        mMockLooper = new MockLooper();
60        mHandler = new Handler(mMockLooper.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
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        mMockLooper.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
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        mMockLooper.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
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        mMockLooper.moveTimeForward(5000);
142        mMockLooper.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
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        mMockLooper.moveTimeForward(4000);
173        mHandlerSpy.sendMessageDelayed(mHandler.obtainMessage(messageA), 1000);
174        mHandlerSpy.sendMessageDelayed(mHandler.obtainMessage(messageB), 2000);
175        mMockLooper.moveTimeForward(1000);
176        mMockLooper.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
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        mMockLooper.moveTimeForward(4000);
209        mHandlerSpy.sendMessageDelayed(mHandler.obtainMessage(messageA), 5000);
210        mHandlerSpy.sendMessageDelayed(mHandler.obtainMessage(messageB), 2000);
211        mMockLooper.moveTimeForward(3000);
212        mMockLooper.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
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        mMockLooper.moveTimeForward(4000);
245        mMockLooper.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        mMockLooper.moveTimeForward(3000);
255        mMockLooper.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
278    public void testAutoDispatchWithSingleMessage() {
279        final int mLoopSleepTimeMs = 5;
280
281        final int messageA = 1;
282
283        MockLooper mockLooper = new MockLooper();
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)
320    public void testRepeatedStartAutoDispatchThrowsException() {
321        mMockLooper.startAutoDispatch();
322        mMockLooper.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)
332    public void testStopAutoDispatchWithoutStartThrowsException() {
333        mMockLooper.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
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        mMockLooper.startAutoDispatch();
350        try {
351            mMockLooper.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, mMockLooper.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)
367    public void testAutoDispatchThrowsExceptionWhenNoMessagesDispatched() {
368        mMockLooper.startAutoDispatch();
369        mMockLooper.stopAutoDispatch();
370    }
371}
372