OLD | NEW |
(Empty) | |
| 1 // Copyright 2016 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.offlinepages; |
| 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.times; |
| 15 import static org.mockito.Mockito.verify; |
| 16 |
| 17 import android.app.Activity; |
| 18 import android.content.Context; |
| 19 import android.os.Bundle; |
| 20 |
| 21 import org.junit.After; |
| 22 import org.junit.Before; |
| 23 import org.junit.Rule; |
| 24 import org.junit.Test; |
| 25 import org.junit.runner.RunWith; |
| 26 import org.mockito.ArgumentCaptor; |
| 27 import org.mockito.ArgumentMatchers; |
| 28 import org.mockito.Captor; |
| 29 import org.mockito.Mock; |
| 30 import org.mockito.MockitoAnnotations; |
| 31 import org.robolectric.RuntimeEnvironment; |
| 32 import org.robolectric.annotation.Config; |
| 33 |
| 34 import org.chromium.base.ActivityState; |
| 35 import org.chromium.base.ApplicationStatus; |
| 36 import org.chromium.base.BaseSwitches; |
| 37 import org.chromium.base.Callback; |
| 38 import org.chromium.base.CommandLine; |
| 39 import org.chromium.base.ContextUtils; |
| 40 import org.chromium.base.SysUtils; |
| 41 import org.chromium.base.test.util.Feature; |
| 42 import org.chromium.chrome.browser.DisableHistogramsRule; |
| 43 import org.chromium.chrome.browser.background_task_scheduler.NativeBackgroundTas
k; |
| 44 import org.chromium.components.background_task_scheduler.BackgroundTask; |
| 45 import org.chromium.components.background_task_scheduler.BackgroundTaskScheduler
; |
| 46 import org.chromium.components.background_task_scheduler.BackgroundTaskScheduler
Factory; |
| 47 import org.chromium.components.background_task_scheduler.TaskIds; |
| 48 import org.chromium.components.background_task_scheduler.TaskInfo; |
| 49 import org.chromium.components.background_task_scheduler.TaskParameters; |
| 50 import org.chromium.net.ConnectionType; |
| 51 import org.chromium.testing.local.LocalRobolectricTestRunner; |
| 52 |
| 53 /** |
| 54 * Unit tests for OfflineBackgroundTask. |
| 55 */ |
| 56 @RunWith(LocalRobolectricTestRunner.class) |
| 57 @Config(manifest = Config.NONE, shadows = {ShadowDeviceConditions.class}) |
| 58 public class OfflineBackgroundTaskTest { |
| 59 private static final boolean REQUIRE_POWER = true; |
| 60 private static final boolean REQUIRE_UNMETERED = true; |
| 61 private static final boolean POWER_CONNECTED = true; |
| 62 private static final int MINIMUM_BATTERY_LEVEL = 33; |
| 63 private static final String IS_LOW_END_DEVICE_SWITCH = |
| 64 "--" + BaseSwitches.ENABLE_LOW_END_DEVICE_MODE; |
| 65 |
| 66 @Rule |
| 67 public DisableHistogramsRule mDisableHistogramsRule = new DisableHistogramsR
ule(); |
| 68 |
| 69 private Bundle mTaskExtras; |
| 70 private long mTestTime; |
| 71 private TriggerConditions mTriggerConditions = |
| 72 new TriggerConditions(!REQUIRE_POWER, MINIMUM_BATTERY_LEVEL, REQUIRE
_UNMETERED); |
| 73 private DeviceConditions mDeviceConditions = new DeviceConditions( |
| 74 !POWER_CONNECTED, MINIMUM_BATTERY_LEVEL + 5, ConnectionType.CONNECTI
ON_3G); |
| 75 private Activity mTestActivity; |
| 76 |
| 77 @Mock |
| 78 private BackgroundSchedulerProcessor mBackgroundSchedulerProcessor; |
| 79 |
| 80 @Mock |
| 81 private BackgroundTaskScheduler mTaskScheduler; |
| 82 @Mock |
| 83 private BackgroundTask.TaskFinishedCallback mTaskFinishedCallback; |
| 84 @Mock |
| 85 private Callback<Boolean> mInternalBooleanCallback; |
| 86 @Captor |
| 87 private ArgumentCaptor<TaskInfo> mTaskInfo; |
| 88 |
| 89 @Before |
| 90 public void setUp() throws Exception { |
| 91 MockitoAnnotations.initMocks(this); |
| 92 ContextUtils.initApplicationContextForTests(RuntimeEnvironment.applicati
on); |
| 93 BackgroundTaskSchedulerFactory.setSchedulerForTesting(mTaskScheduler); |
| 94 doReturn(true) |
| 95 .when(mTaskScheduler) |
| 96 .schedule(eq(RuntimeEnvironment.application), mTaskInfo.capture(
)); |
| 97 |
| 98 ShadowDeviceConditions.setCurrentConditions(mDeviceConditions); |
| 99 |
| 100 // Set up background scheduler processor mock. |
| 101 BackgroundSchedulerProcessor.setInstanceForTesting(mBackgroundSchedulerP
rocessor); |
| 102 |
| 103 // Build a bundle with trigger conditions. |
| 104 mTaskExtras = new Bundle(); |
| 105 TaskExtrasPacker.packTimeInBundle(mTaskExtras); |
| 106 TaskExtrasPacker.packTriggerConditionsInBundle(mTaskExtras, mTriggerCond
itions); |
| 107 |
| 108 // Run tests as a low-end device. |
| 109 CommandLine.init(new String[] {"testcommand", IS_LOW_END_DEVICE_SWITCH})
; |
| 110 |
| 111 // Set up single, stopped Activity. |
| 112 ApplicationStatus.destroyForJUnitTests(); |
| 113 mTestActivity = new Activity(); |
| 114 ApplicationStatus.onStateChangeForTesting(mTestActivity, ActivityState.C
REATED); |
| 115 ApplicationStatus.onStateChangeForTesting(mTestActivity, ActivityState.S
TOPPED); |
| 116 } |
| 117 |
| 118 @After |
| 119 public void tearDown() throws Exception { |
| 120 // Clean up static state for subsequent Robolectric tests. |
| 121 CommandLine.reset(); |
| 122 SysUtils.reset(); |
| 123 ApplicationStatus.destroyForJUnitTests(); |
| 124 } |
| 125 |
| 126 private void setupScheduledProcessingWithResult(boolean result) { |
| 127 doReturn(result) |
| 128 .when(mBackgroundSchedulerProcessor) |
| 129 .startScheduledProcessing( |
| 130 any(DeviceConditions.class), ArgumentMatchers.<Callback<
Boolean>>any()); |
| 131 } |
| 132 |
| 133 @Test |
| 134 @Feature({"OfflinePages"}) |
| 135 public void testCheckConditions_BatteryConditions_LowBattery_NoPower() { |
| 136 // Setup low battery conditions with no power connected. |
| 137 DeviceConditions deviceConditionsLowBattery = new DeviceConditions( |
| 138 !POWER_CONNECTED, MINIMUM_BATTERY_LEVEL - 1, ConnectionType.CONN
ECTION_WIFI); |
| 139 ShadowDeviceConditions.setCurrentConditions(deviceConditionsLowBattery); |
| 140 |
| 141 // Verify that conditions for processing are not met. |
| 142 assertFalse( |
| 143 OfflineBackgroundTask.checkConditions(RuntimeEnvironment.applica
tion, mTaskExtras)); |
| 144 |
| 145 // Check impact on starting before native loaded. |
| 146 TaskParameters params = TaskParameters.create(TaskIds.OFFLINE_PAGES_BACK
GROUND_JOB_ID) |
| 147 .addExtras(mTaskExtras) |
| 148 .build(); |
| 149 |
| 150 int result = new OfflineBackgroundTask().onStartTaskBeforeNativeLoaded( |
| 151 RuntimeEnvironment.application, params, mTaskFinishedCallback); |
| 152 assertEquals(NativeBackgroundTask.RESCHEDULE, result); |
| 153 // Task finished can only gets called from the native part, when async p
rocessing starts. |
| 154 verify(mTaskFinishedCallback, times(0)).taskFinished(anyBoolean()); |
| 155 } |
| 156 |
| 157 @Test |
| 158 @Feature({"OfflinePages"}) |
| 159 public void testCheckConditions_BatteryConditions_LowBattery_WithPower() { |
| 160 // Set battery percentage below minimum level, but connect power. |
| 161 DeviceConditions deviceConditionsPowerConnected = new DeviceConditions( |
| 162 POWER_CONNECTED, MINIMUM_BATTERY_LEVEL - 1, ConnectionType.CONNE
CTION_WIFI); |
| 163 ShadowDeviceConditions.setCurrentConditions(deviceConditionsPowerConnect
ed); |
| 164 |
| 165 // Now verify that same battery level, with power connected, will pass t
he conditions. |
| 166 assertTrue( |
| 167 OfflineBackgroundTask.checkConditions(RuntimeEnvironment.applica
tion, mTaskExtras)); |
| 168 |
| 169 // Check impact on starting before native loaded. |
| 170 TaskParameters params = TaskParameters.create(TaskIds.OFFLINE_PAGES_BACK
GROUND_JOB_ID) |
| 171 .addExtras(mTaskExtras) |
| 172 .build(); |
| 173 |
| 174 int result = new OfflineBackgroundTask().onStartTaskBeforeNativeLoaded( |
| 175 RuntimeEnvironment.application, params, mTaskFinishedCallback); |
| 176 assertEquals(NativeBackgroundTask.LOAD_NATIVE, result); |
| 177 // Task finished can only gets called from the native part, when async p
rocessing starts. |
| 178 verify(mTaskFinishedCallback, times(0)).taskFinished(anyBoolean()); |
| 179 } |
| 180 |
| 181 @Test |
| 182 @Feature({"OfflinePages"}) |
| 183 public void testCheckConditions_OnLowEndDevice_ActivityStarted() { |
| 184 // Transition the test Activity to a running state. |
| 185 ApplicationStatus.onStateChangeForTesting(mTestActivity, ActivityState.S
TARTED); |
| 186 |
| 187 // Verify that conditions for processing are not met. |
| 188 assertFalse( |
| 189 OfflineBackgroundTask.checkConditions(RuntimeEnvironment.applica
tion, mTaskExtras)); |
| 190 |
| 191 // Check impact on starting before native loaded. |
| 192 TaskParameters params = TaskParameters.create(TaskIds.OFFLINE_PAGES_BACK
GROUND_JOB_ID) |
| 193 .addExtras(mTaskExtras) |
| 194 .build(); |
| 195 |
| 196 int result = new OfflineBackgroundTask().onStartTaskBeforeNativeLoaded( |
| 197 RuntimeEnvironment.application, params, mTaskFinishedCallback); |
| 198 assertEquals(NativeBackgroundTask.RESCHEDULE, result); |
| 199 // Task finished can only gets called from the native part, when async p
rocessing starts. |
| 200 verify(mTaskFinishedCallback, times(0)).taskFinished(anyBoolean()); |
| 201 } |
| 202 |
| 203 @Test |
| 204 @Feature({"OfflinePages"}) |
| 205 public void testCheckConditions_OnLowEndDevice_ActivityStopped() { |
| 206 // Switch activity state to stopped. |
| 207 ApplicationStatus.onStateChangeForTesting(mTestActivity, ActivityState.S
TOPPED); |
| 208 |
| 209 // Now verify that condition check passes when Activity is stopped. |
| 210 assertTrue( |
| 211 OfflineBackgroundTask.checkConditions(RuntimeEnvironment.applica
tion, mTaskExtras)); |
| 212 |
| 213 // Check impact on starting before native loaded. |
| 214 TaskParameters params = TaskParameters.create(TaskIds.OFFLINE_PAGES_BACK
GROUND_JOB_ID) |
| 215 .addExtras(mTaskExtras) |
| 216 .build(); |
| 217 |
| 218 int result = new OfflineBackgroundTask().onStartTaskBeforeNativeLoaded( |
| 219 RuntimeEnvironment.application, params, mTaskFinishedCallback); |
| 220 assertEquals(NativeBackgroundTask.LOAD_NATIVE, result); |
| 221 // Task finished can only gets called from the native part, when async p
rocessing starts. |
| 222 verify(mTaskFinishedCallback, times(0)).taskFinished(anyBoolean()); |
| 223 } |
| 224 |
| 225 @Test |
| 226 @Feature({"OfflinePages"}) |
| 227 public void testOnStartTaskWithNative_BackupScheduleIfExecutingTask() { |
| 228 setupScheduledProcessingWithResult(true); |
| 229 |
| 230 TaskParameters params = TaskParameters.create(TaskIds.OFFLINE_PAGES_BACK
GROUND_JOB_ID) |
| 231 .addExtras(mTaskExtras) |
| 232 .build(); |
| 233 |
| 234 new OfflineBackgroundTask().onStartTaskWithNative( |
| 235 RuntimeEnvironment.application, params, mTaskFinishedCallback); |
| 236 |
| 237 verify(mTaskScheduler, times(1)) |
| 238 .schedule(eq(RuntimeEnvironment.application), any(TaskInfo.class
)); |
| 239 // Task is running at this point, hence no callback issued. |
| 240 verify(mTaskFinishedCallback, times(0)).taskFinished(anyBoolean()); |
| 241 } |
| 242 |
| 243 @Test |
| 244 @Feature({"OfflinePages"}) |
| 245 public void testOnStartTaskWithNative_RescheduleThroughCallbackWhenRunning()
{ |
| 246 setupScheduledProcessingWithResult(false); |
| 247 |
| 248 TaskParameters params = TaskParameters.create(TaskIds.OFFLINE_PAGES_BACK
GROUND_JOB_ID) |
| 249 .addExtras(mTaskExtras) |
| 250 .build(); |
| 251 |
| 252 new OfflineBackgroundTask().onStartTaskWithNative( |
| 253 RuntimeEnvironment.application, params, mTaskFinishedCallback); |
| 254 |
| 255 verify(mTaskScheduler, times(0)).schedule(any(Context.class), any(TaskIn
fo.class)); |
| 256 // Task started async processing after native load, but processing refus
ed to progress, |
| 257 // hence task finished called with reschedule request. |
| 258 verify(mTaskFinishedCallback, times(1)).taskFinished(eq(true)); |
| 259 } |
| 260 |
| 261 @Test |
| 262 @Feature({"OfflinePages"}) |
| 263 public void testStartBackgroundRequests() { |
| 264 setupScheduledProcessingWithResult(true); |
| 265 |
| 266 assertTrue(OfflineBackgroundTask.startScheduledProcessing(mBackgroundSch
edulerProcessor, |
| 267 RuntimeEnvironment.application, mTaskExtras, mInternalBooleanCal
lback)); |
| 268 |
| 269 // Check with BackgroundSchedulerProcessor that processing started. |
| 270 verify(mBackgroundSchedulerProcessor, times(1)) |
| 271 .startScheduledProcessing(eq(mDeviceConditions), eq(mInternalBoo
leanCallback)); |
| 272 } |
| 273 |
| 274 @Test |
| 275 @Feature({"OfflinePages"}) |
| 276 public void testStartBackgroundRequestsNotStarted() { |
| 277 // Processing will not be started here. |
| 278 setupScheduledProcessingWithResult(false); |
| 279 |
| 280 assertFalse(OfflineBackgroundTask.startScheduledProcessing(mBackgroundSc
hedulerProcessor, |
| 281 RuntimeEnvironment.application, mTaskExtras, mInternalBooleanCal
lback)); |
| 282 |
| 283 // Check with BackgroundSchedulerProcessor that it did not start. |
| 284 verify(mBackgroundSchedulerProcessor, times(1)) |
| 285 .startScheduledProcessing(eq(mDeviceConditions), eq(mInternalBoo
leanCallback)); |
| 286 } |
| 287 } |
OLD | NEW |