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 com.android.internal.util;
18 
19 import static org.junit.Assert.*;
20 import static org.mockito.Mockito.*;
21 
22 import android.app.AlarmManager;
23 import android.content.Context;
24 import android.os.Handler;
25 import android.os.Looper;
26 import android.os.Message;
27 import android.test.suitebuilder.annotation.SmallTest;
28 
29 import org.junit.After;
30 import org.junit.Before;
31 import org.junit.Test;
32 import org.mockito.ArgumentCaptor;
33 import org.mockito.Mock;
34 import org.mockito.MockitoAnnotations;
35 import org.mockito.Spy;
36 import org.mockito.invocation.InvocationOnMock;
37 import org.mockito.stubbing.Answer;
38 
39 /**
40  * Unit tests for {@link com.android.internal.util.WakeupMessage}.
41  */
42 @SmallTest
43 public class WakeupMessageTest {
44     private static final String TEST_CMD_NAME = "TEST cmd Name";
45     private static final int TEST_CMD = 18;
46     private static final int TEST_ARG1 = 33;
47     private static final int TEST_ARG2 = 182;
48     private static final Object TEST_OBJ = "hello";
49 
50     @Mock Context mContext;
51     @Mock AlarmManager mAlarmManager;
52     WakeupMessage mMessage;
53     // Make a spy so that we can verify calls to it
54     @Spy MessageCapturingHandler mHandler = new MessageCapturingHandler();
55 
56     ArgumentCaptor<AlarmManager.OnAlarmListener> mListenerCaptor =
57             ArgumentCaptor.forClass(AlarmManager.OnAlarmListener.class);
58 
59     /**
60      * A Handler that will capture the most recent message sent to it.
61      *
62      * This handler is setup on the main Looper
63      */
64     public static class MessageCapturingHandler extends Handler {
65         private Message mLastMessage;
66 
MessageCapturingHandler()67         public MessageCapturingHandler() {
68             super(Looper.getMainLooper(), /* Nothing is actually dispatched on this Looper */
69                     null, false);
70         }
71 
72         @Override
handleMessage(Message m)73         public void handleMessage(Message m) {
74             // need to copy since it will be recycled after this method returns
75             mLastMessage = Message.obtain(m);
76         }
77 
getLastMessage()78         public Message getLastMessage() {
79             return mLastMessage;
80         }
81     }
82 
83     /**
84      * Sets up the test.
85      */
86     @Before
setUp()87     public void setUp() {
88         MockitoAnnotations.initMocks(this);
89 
90         when(mContext.getSystemService(Context.ALARM_SERVICE)).thenReturn(mAlarmManager);
91         // capture the listener for each AlarmManager.setExact call
92         doNothing().when(mAlarmManager).setExact(anyInt(), anyLong(), any(String.class),
93                 mListenerCaptor.capture(), any(Handler.class));
94 
95         mMessage = new WakeupMessage(mContext, mHandler, TEST_CMD_NAME, TEST_CMD, TEST_ARG1,
96                 TEST_ARG2, TEST_OBJ);
97     }
98 
99     /**
100      * Ensure the test is cleaned up and ready for the next test.
101      */
102     @After
cleanup()103     public void cleanup() {
104         validateMockitoUsage();
105     }
106 
scheduleAndVerifyAlarm(long when)107     private void scheduleAndVerifyAlarm(long when) {
108         mMessage.schedule(when);
109         verify(mAlarmManager).setExact(eq(AlarmManager.ELAPSED_REALTIME_WAKEUP), eq(when),
110                 eq(TEST_CMD_NAME), any(AlarmManager.OnAlarmListener.class), eq(mHandler));
111     }
112 
verifyMessageDispatchedOnce()113     private void verifyMessageDispatchedOnce() {
114         verify(mHandler, times(1)).handleMessage(any(Message.class));
115         assertEquals("what", TEST_CMD, mHandler.getLastMessage().what);
116         assertEquals("arg1", TEST_ARG1, mHandler.getLastMessage().arg1);
117         assertEquals("arg2", TEST_ARG2, mHandler.getLastMessage().arg2);
118         assertEquals("obj", TEST_OBJ, mHandler.getLastMessage().obj);
119     }
120 
121     /**
122      * Schedule and deliver a single message
123      */
124     @Test
scheduleAndDeliverMessage()125     public void scheduleAndDeliverMessage() {
126         final long when = 1001;
127         scheduleAndVerifyAlarm(when);
128         verify(mHandler, never()).handleMessage(any(Message.class));
129         mListenerCaptor.getValue().onAlarm();
130         verifyMessageDispatchedOnce();
131     }
132 
133     /**
134      * Check that the message is not delivered if cancel is called it after its alarm fires but
135      * before onAlarm is called.
136      *
137      * This ensures that if cancel is called on the handler thread, any previously-scheduled message
138      * is guaranteed not to be delivered.
139      */
140     @Test
scheduleAndCancelMessage()141     public void scheduleAndCancelMessage() {
142         final long when = 1010;
143         scheduleAndVerifyAlarm(when);
144         mMessage.cancel();
145         mListenerCaptor.getValue().onAlarm();
146         verify(mHandler, never()).handleMessage(any(Message.class));
147     }
148 
149     /**
150      * Verify nothing happens when cancel is called without a schedule
151      */
152     @Test
cancelWithoutSchedule()153     public void cancelWithoutSchedule() {
154         mMessage.cancel();
155     }
156 
157     /**
158      * Verify that the message is silently rescheduled if schedule is called twice without the
159      * message being dispatched first.
160      */
161     @Test
scheduleTwiceWithoutMessageDispatched()162     public void scheduleTwiceWithoutMessageDispatched() {
163         final long when1 = 1011;
164         final long when2 = 1012;
165         scheduleAndVerifyAlarm(when1);
166         scheduleAndVerifyAlarm(when2);
167         mListenerCaptor.getValue().onAlarm();
168         verifyMessageDispatchedOnce();
169     }
170 
171     /**
172      * Verify that a Runnable is scheduled and dispatched.
173      */
174     @Test
scheduleRunnable()175     public void scheduleRunnable() {
176         final long when = 1011;
177         final Runnable runnable = mock(Runnable.class);
178         WakeupMessage dut = new WakeupMessage(mContext, mHandler, TEST_CMD_NAME, runnable);
179         dut.schedule(when);
180         verify(mAlarmManager).setExact(eq(AlarmManager.ELAPSED_REALTIME_WAKEUP), eq(when),
181                 eq(TEST_CMD_NAME), any(AlarmManager.OnAlarmListener.class), eq(mHandler));
182         mListenerCaptor.getValue().onAlarm();
183         verify(runnable, times(1)).run();
184     }
185 
186 }
187