1 // Copyright 2019 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 package org.chromium.chrome.browser.notifications;
6 
7 import static org.junit.Assert.assertEquals;
8 import static org.junit.Assert.assertFalse;
9 import static org.junit.Assert.assertTrue;
10 import static org.mockito.Mockito.any;
11 import static org.mockito.Mockito.anyBoolean;
12 import static org.mockito.Mockito.doReturn;
13 import static org.mockito.Mockito.eq;
14 import static org.mockito.Mockito.never;
15 import static org.mockito.Mockito.verify;
16 
17 import android.os.Bundle;
18 
19 import org.junit.After;
20 import org.junit.Before;
21 import org.junit.Test;
22 import org.junit.runner.RunWith;
23 import org.mockito.ArgumentCaptor;
24 import org.mockito.Mock;
25 import org.mockito.MockitoAnnotations;
26 import org.robolectric.RuntimeEnvironment;
27 import org.robolectric.annotation.Config;
28 
29 import org.chromium.base.SysUtils;
30 import org.chromium.base.test.BaseRobolectricTestRunner;
31 import org.chromium.chrome.browser.background_task_scheduler.ChromeBackgroundTaskFactory;
32 import org.chromium.components.background_task_scheduler.BackgroundTask;
33 import org.chromium.components.background_task_scheduler.BackgroundTaskScheduler;
34 import org.chromium.components.background_task_scheduler.BackgroundTaskSchedulerFactory;
35 import org.chromium.components.background_task_scheduler.NativeBackgroundTask;
36 import org.chromium.components.background_task_scheduler.TaskIds;
37 import org.chromium.components.background_task_scheduler.TaskInfo;
38 import org.chromium.components.background_task_scheduler.TaskParameters;
39 
40 /**
41  * Unit tests for NotificationTriggerBackgroundTask.
42  */
43 @RunWith(BaseRobolectricTestRunner.class)
44 @Config(manifest = Config.NONE)
45 public class NotificationTriggerBackgroundTaskTest {
46     @Mock
47     private BackgroundTaskScheduler mTaskScheduler;
48     @Mock
49     private NotificationTriggerScheduler mTriggerScheduler;
50     @Mock
51     private BackgroundTask.TaskFinishedCallback mTaskFinishedCallback;
52 
53     @Before
setUp()54     public void setUp() {
55         MockitoAnnotations.initMocks(this);
56         BackgroundTaskSchedulerFactory.setSchedulerForTesting(mTaskScheduler);
57         ChromeBackgroundTaskFactory.setAsDefault();
58         NotificationTriggerScheduler.setInstanceForTests(mTriggerScheduler);
59     }
60 
61     @After
tearDown()62     public void tearDown() {
63         SysUtils.resetForTesting();
64     }
65 
createTaskParameters(long timestamp)66     private static TaskParameters createTaskParameters(long timestamp) {
67         Bundle extras = new Bundle();
68         extras.putLong(NotificationTriggerBackgroundTask.KEY_TIMESTAMP, timestamp);
69         return TaskParameters.create(TaskIds.NOTIFICATION_TRIGGER_JOB_ID).addExtras(extras).build();
70     }
71 
72     @Test
testScheduleInitializesOneOffTask()73     public void testScheduleInitializesOneOffTask() {
74         long delay = 1000;
75         long timestamp = System.currentTimeMillis() + delay;
76         ArgumentCaptor<TaskInfo> taskInfoCaptor = ArgumentCaptor.forClass(TaskInfo.class);
77         NotificationTriggerBackgroundTask.schedule(timestamp, delay);
78         verify(mTaskScheduler).schedule(any(), taskInfoCaptor.capture());
79         TaskInfo taskInfo = taskInfoCaptor.getValue();
80 
81         assertEquals(TaskIds.NOTIFICATION_TRIGGER_JOB_ID, taskInfo.getTaskId());
82         assertTrue(taskInfo.isPersisted());
83         assertTrue(taskInfo.shouldUpdateCurrent());
84         assertEquals(TaskInfo.NetworkType.NONE, taskInfo.getRequiredNetworkType());
85         assertEquals(timestamp,
86                 taskInfo.getExtras().getLong(NotificationTriggerBackgroundTask.KEY_TIMESTAMP));
87         TaskInfo.TimingInfo timingInfo = taskInfo.getTimingInfo();
88         assertTrue(timingInfo instanceof TaskInfo.ExactInfo);
89         TaskInfo.ExactInfo exactTimingInfo = (TaskInfo.ExactInfo) timingInfo;
90         assertEquals(timestamp, exactTimingInfo.getTriggerAtMs());
91     }
92 
93     @Test
testCancelCancelsTask()94     public void testCancelCancelsTask() {
95         NotificationTriggerBackgroundTask.cancel();
96         verify(mTaskScheduler).cancel(any(), eq(TaskIds.NOTIFICATION_TRIGGER_JOB_ID));
97     }
98 
99     @Test
testRescheduleCallsScheduler()100     public void testRescheduleCallsScheduler() {
101         new NotificationTriggerBackgroundTask().reschedule(RuntimeEnvironment.application);
102         verify(mTriggerScheduler).reschedule();
103     }
104 
105     @Test
testStartBeforeNative_ValidTrigger()106     public void testStartBeforeNative_ValidTrigger() {
107         long timestamp = System.currentTimeMillis() + 1000;
108         doReturn(true).when(mTriggerScheduler).checkAndResetTrigger(eq(timestamp));
109 
110         int result = new NotificationTriggerBackgroundTask().onStartTaskBeforeNativeLoaded(
111                 RuntimeEnvironment.application, createTaskParameters(timestamp),
112                 mTaskFinishedCallback);
113 
114         assertEquals(NativeBackgroundTask.StartBeforeNativeResult.LOAD_NATIVE, result);
115         verify(mTriggerScheduler).checkAndResetTrigger(eq(timestamp));
116         verify(mTaskFinishedCallback, never()).taskFinished(anyBoolean());
117     }
118 
119     @Test
testStartBeforeNative_InvalidTrigger()120     public void testStartBeforeNative_InvalidTrigger() {
121         long timestamp = System.currentTimeMillis() + 1000;
122         doReturn(false).when(mTriggerScheduler).checkAndResetTrigger(eq(timestamp));
123 
124         int result = new NotificationTriggerBackgroundTask().onStartTaskBeforeNativeLoaded(
125                 RuntimeEnvironment.application, createTaskParameters(timestamp),
126                 mTaskFinishedCallback);
127 
128         assertEquals(NativeBackgroundTask.StartBeforeNativeResult.DONE, result);
129         verify(mTriggerScheduler).checkAndResetTrigger(eq(timestamp));
130         verify(mTaskFinishedCallback, never()).taskFinished(anyBoolean());
131     }
132 
133     @Test
testStartWithNativeCallsTriggerNotifications()134     public void testStartWithNativeCallsTriggerNotifications() {
135         long timestamp = System.currentTimeMillis() + 1000;
136         new NotificationTriggerBackgroundTask().onStartTaskWithNative(
137                 RuntimeEnvironment.application, createTaskParameters(timestamp),
138                 mTaskFinishedCallback);
139 
140         verify(mTriggerScheduler).triggerNotifications();
141         verify(mTaskFinishedCallback).taskFinished(eq(false));
142     }
143 
144     @Test
testReschedule_BeforeNative()145     public void testReschedule_BeforeNative() {
146         long timestamp = System.currentTimeMillis() + 1000;
147         boolean shouldReschedule =
148                 new NotificationTriggerBackgroundTask().onStopTaskBeforeNativeLoaded(
149                         RuntimeEnvironment.application, createTaskParameters(timestamp));
150         assertTrue(shouldReschedule);
151     }
152 
153     @Test
testReschedule_WithNative()154     public void testReschedule_WithNative() {
155         long timestamp = System.currentTimeMillis() + 1000;
156         boolean shouldReschedule = new NotificationTriggerBackgroundTask().onStopTaskWithNative(
157                 RuntimeEnvironment.application, createTaskParameters(timestamp));
158         assertTrue(shouldReschedule);
159     }
160 
161     @Test
testReschedule_AfterTriggerBeforeNative()162     public void testReschedule_AfterTriggerBeforeNative() {
163         long timestamp = System.currentTimeMillis() + 1000;
164 
165         NotificationTriggerBackgroundTask task = new NotificationTriggerBackgroundTask();
166         TaskParameters params = createTaskParameters(timestamp);
167         task.onStartTaskWithNative(RuntimeEnvironment.application, params, mTaskFinishedCallback);
168         boolean shouldReschedule =
169                 task.onStopTaskBeforeNativeLoaded(RuntimeEnvironment.application, params);
170 
171         assertFalse(shouldReschedule);
172     }
173 
174     @Test
testReschedule_AfterTriggerWithNative()175     public void testReschedule_AfterTriggerWithNative() {
176         long timestamp = System.currentTimeMillis() + 1000;
177 
178         NotificationTriggerBackgroundTask task = new NotificationTriggerBackgroundTask();
179         TaskParameters params = createTaskParameters(timestamp);
180         task.onStartTaskWithNative(RuntimeEnvironment.application, params, mTaskFinishedCallback);
181         boolean shouldReschedule =
182                 task.onStopTaskWithNative(RuntimeEnvironment.application, params);
183 
184         assertFalse(shouldReschedule);
185     }
186 
187     @Test
testReschedule_ValidTriggerBeforeNative()188     public void testReschedule_ValidTriggerBeforeNative() {
189         long timestamp = System.currentTimeMillis() + 1000;
190         doReturn(true).when(mTriggerScheduler).checkAndResetTrigger(eq(timestamp));
191 
192         NotificationTriggerBackgroundTask task = new NotificationTriggerBackgroundTask();
193         TaskParameters params = createTaskParameters(timestamp);
194         task.onStartTaskBeforeNativeLoaded(
195                 RuntimeEnvironment.application, params, mTaskFinishedCallback);
196         boolean shouldReschedule =
197                 task.onStopTaskBeforeNativeLoaded(RuntimeEnvironment.application, params);
198 
199         assertTrue(shouldReschedule);
200     }
201 
202     @Test
testReschedule_ValidTriggerWithNative()203     public void testReschedule_ValidTriggerWithNative() {
204         long timestamp = System.currentTimeMillis() + 1000;
205         doReturn(true).when(mTriggerScheduler).checkAndResetTrigger(eq(timestamp));
206 
207         NotificationTriggerBackgroundTask task = new NotificationTriggerBackgroundTask();
208         TaskParameters params = createTaskParameters(timestamp);
209         task.onStartTaskBeforeNativeLoaded(
210                 RuntimeEnvironment.application, params, mTaskFinishedCallback);
211         boolean shouldReschedule =
212                 task.onStopTaskWithNative(RuntimeEnvironment.application, params);
213 
214         assertTrue(shouldReschedule);
215     }
216 
217     @Test
testReschedule_InvalidTriggerBeforeNative()218     public void testReschedule_InvalidTriggerBeforeNative() {
219         long timestamp = System.currentTimeMillis() + 1000;
220         doReturn(false).when(mTriggerScheduler).checkAndResetTrigger(eq(timestamp));
221 
222         NotificationTriggerBackgroundTask task = new NotificationTriggerBackgroundTask();
223         TaskParameters params = createTaskParameters(timestamp);
224         task.onStartTaskBeforeNativeLoaded(
225                 RuntimeEnvironment.application, params, mTaskFinishedCallback);
226         boolean shouldReschedule =
227                 task.onStopTaskBeforeNativeLoaded(RuntimeEnvironment.application, params);
228 
229         assertFalse(shouldReschedule);
230     }
231 
232     @Test
testReschedule_InvalidTriggerWithNative()233     public void testReschedule_InvalidTriggerWithNative() {
234         long timestamp = System.currentTimeMillis() + 1000;
235         doReturn(false).when(mTriggerScheduler).checkAndResetTrigger(eq(timestamp));
236 
237         NotificationTriggerBackgroundTask task = new NotificationTriggerBackgroundTask();
238         TaskParameters params = createTaskParameters(timestamp);
239         task.onStartTaskBeforeNativeLoaded(
240                 RuntimeEnvironment.application, params, mTaskFinishedCallback);
241         boolean shouldReschedule =
242                 task.onStopTaskWithNative(RuntimeEnvironment.application, params);
243 
244         assertFalse(shouldReschedule);
245     }
246 }
247