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