/* * Copyright (C) 2016 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.android.internal.util; import static org.junit.Assert.*; import static org.mockito.Mockito.*; import android.app.AlarmManager; import android.content.Context; import android.os.Handler; import android.os.Looper; import android.os.Message; import android.test.suitebuilder.annotation.SmallTest; import org.junit.After; import org.junit.Before; import org.junit.Test; import org.mockito.ArgumentCaptor; import org.mockito.Mock; import org.mockito.MockitoAnnotations; import org.mockito.Spy; import org.mockito.invocation.InvocationOnMock; import org.mockito.stubbing.Answer; /** * Unit tests for {@link com.android.internal.util.WakeupMessage}. */ @SmallTest public class WakeupMessageTest { private static final String TEST_CMD_NAME = "TEST cmd Name"; private static final int TEST_CMD = 18; private static final int TEST_ARG1 = 33; private static final int TEST_ARG2 = 182; private static final Object TEST_OBJ = "hello"; @Mock AlarmManager mAlarmManager; WakeupMessage mMessage; // Make a spy so that we can verify calls to it @Spy MessageCapturingHandler mHandler = new MessageCapturingHandler(); ArgumentCaptor<AlarmManager.OnAlarmListener> mListenerCaptor = ArgumentCaptor.forClass(AlarmManager.OnAlarmListener.class); /** * A Handler that will capture the most recent message sent to it. * * This handler is setup on the main Looper */ public static class MessageCapturingHandler extends Handler { private Message mLastMessage; public MessageCapturingHandler() { super(Looper.getMainLooper(), /* Nothing is actually dispatched on this Looper */ null, false); } @Override public void handleMessage(Message m) { // need to copy since it will be recycled after this method returns mLastMessage = Message.obtain(m); } public Message getLastMessage() { return mLastMessage; } } /** * Sets up the test. */ @Before public void setUp() { MockitoAnnotations.initMocks(this); Context context = mock(Context.class); when(context.getSystemService(Context.ALARM_SERVICE)).thenReturn(mAlarmManager); // capture the listener for each AlarmManager.setExact call doNothing().when(mAlarmManager).setExact(anyInt(), anyLong(), any(String.class), mListenerCaptor.capture(), any(Handler.class)); mMessage = new WakeupMessage(context, mHandler, TEST_CMD_NAME, TEST_CMD, TEST_ARG1, TEST_ARG2, TEST_OBJ); } /** * Ensure the test is cleaned up and ready for the next test. */ @After public void cleanup() { validateMockitoUsage(); } private void scheduleAndVerifyAlarm(long when) { mMessage.schedule(when); verify(mAlarmManager).setExact(eq(AlarmManager.ELAPSED_REALTIME_WAKEUP), eq(when), eq(TEST_CMD_NAME), any(AlarmManager.OnAlarmListener.class), eq(mHandler)); } private void verifyMessageDispatchedOnce() { verify(mHandler, times(1)).handleMessage(any(Message.class)); assertEquals("what", TEST_CMD, mHandler.getLastMessage().what); assertEquals("arg1", TEST_ARG1, mHandler.getLastMessage().arg1); assertEquals("arg2", TEST_ARG2, mHandler.getLastMessage().arg2); assertEquals("obj", TEST_OBJ, mHandler.getLastMessage().obj); } /** * Schedule and deliver a single message */ @Test public void scheduleAndDeliverMessage() { final long when = 1001; scheduleAndVerifyAlarm(when); verify(mHandler, never()).handleMessage(any(Message.class)); mListenerCaptor.getValue().onAlarm(); verifyMessageDispatchedOnce(); } /** * Check that the message is not delivered if cancel is called it after its alarm fires but * before onAlarm is called. * * This ensures that if cancel is called on the handler thread, any previously-scheduled message * is guaranteed not to be delivered. */ @Test public void scheduleAndCancelMessage() { final long when = 1010; scheduleAndVerifyAlarm(when); mMessage.cancel(); mListenerCaptor.getValue().onAlarm(); verify(mHandler, never()).handleMessage(any(Message.class)); } /** * Verify nothing happens when cancel is called without a schedule */ @Test public void cancelWithoutSchedule() { mMessage.cancel(); } /** * Verify that the message is silently rescheduled if schedule is called twice without the * message being dispatched first. */ @Test public void scheduleTwiceWithoutMessageDispatched() { final long when1 = 1011; final long when2 = 1012; scheduleAndVerifyAlarm(when1); scheduleAndVerifyAlarm(when2); mListenerCaptor.getValue().onAlarm(); verifyMessageDispatchedOnce(); } }