Commit 8ae4c981 authored by Mugdha Lakhani's avatar Mugdha Lakhani Committed by Commit Bot

[Background Sync] Verify network conditions when woken up.

This adds logic to verify that the background task that wakes up Chrome
is called with network connectivity.
Unit tests are also added to verify the same.

Follow-up CLs will add more unit tests to verify the behavior of
BackgroundSyncBackgroundTask.

Bug: 924490
Change-Id: I1950e00704054c120b6668ebabcb99c32ec9f5c3
Reviewed-on: https://chromium-review.googlesource.com/c/1482462Reviewed-by: default avatarTommy Nyquist <nyquist@chromium.org>
Commit-Queue: Mugdha Lakhani <nator@chromium.org>
Cr-Commit-Position: refs/heads/master@{#636749}
parent 1d6b5052
......@@ -29,12 +29,12 @@ public class DeviceConditions {
private boolean mPowerSaveOn;
// Network related variables.
private int mNetConnectionType = ConnectionType.CONNECTION_NONE;
private @ConnectionType int mNetConnectionType = ConnectionType.CONNECTION_UNKNOWN;
private boolean mActiveNetworkMetered;
// If true, getCurrentNetConnectionType() will always return CONNECTION_NONE.
@VisibleForTesting
public static boolean mForceNoConnectionForTesting;
public static boolean sForceNoConnectionForTesting;
/**
* Creates a DeviceConditions instance that stores a snapshot of the current set of device
......@@ -122,7 +122,7 @@ public class DeviceConditions {
*/
public static int getCurrentNetConnectionType(Context context) {
int connectionType = ConnectionType.CONNECTION_NONE;
if (mForceNoConnectionForTesting) {
if (sForceNoConnectionForTesting) {
return connectionType;
}
......@@ -203,6 +203,14 @@ public class DeviceConditions {
return mNetConnectionType;
}
/**
* Sets the network connection type.
*/
@VisibleForTesting
void setNetworkConnectionType(@ConnectionType int netConnectionType) {
mNetConnectionType = netConnectionType;
}
/** Returns whether network connection is metered. */
public boolean isActiveNetworkMetered() {
return mActiveNetworkMetered;
......
......@@ -8,10 +8,12 @@ import android.content.Context;
import org.chromium.base.annotations.NativeMethods;
import org.chromium.base.metrics.RecordHistogram;
import org.chromium.chrome.browser.DeviceConditions;
import org.chromium.chrome.browser.background_task_scheduler.NativeBackgroundTask;
import org.chromium.components.background_task_scheduler.BackgroundTask.TaskFinishedCallback;
import org.chromium.components.background_task_scheduler.TaskIds;
import org.chromium.components.background_task_scheduler.TaskParameters;
import org.chromium.net.ConnectionType;
/**
* Handles servicing of Background Sync background tasks coming via
......@@ -23,6 +25,14 @@ public class BackgroundSyncBackgroundTask extends NativeBackgroundTask {
Context context, TaskParameters taskParameters, TaskFinishedCallback callback) {
assert taskParameters.getTaskId() == TaskIds.BACKGROUND_SYNC_ONE_SHOT_JOB_ID;
// Check that we're called with network connectivity.
@ConnectionType
int current_network_type = DeviceConditions.getCurrentNetConnectionType(context);
if (current_network_type == ConnectionType.CONNECTION_NONE
|| current_network_type == ConnectionType.CONNECTION_UNKNOWN) {
return StartBeforeNativeResult.RESCHEDULE;
}
return StartBeforeNativeResult.LOAD_NATIVE;
}
......
......@@ -2400,6 +2400,7 @@ chrome_junit_test_java_sources = [
"junit/src/org/chromium/chrome/browser/autofill/keyboard_accessory/ManualFillingControllerTest.java",
"junit/src/org/chromium/chrome/browser/autofill/keyboard_accessory/PasswordAccessorySheetControllerTest.java",
"junit/src/org/chromium/chrome/browser/background_sync/BackgroundSyncBackgroundTaskSchedulerTest.java",
"junit/src/org/chromium/chrome/browser/background_sync/BackgroundSyncBackgroundTaskTest.java",
"junit/src/org/chromium/chrome/browser/background_task_scheduler/NativeBackgroundTaskTest.java",
"junit/src/org/chromium/chrome/browser/browseractions/BrowserActionsIntentTest.java",
"junit/src/org/chromium/chrome/browser/browserservices/ClearDataDialogResultRecorderTest.java",
......
......@@ -408,7 +408,7 @@ public class OfflinePageAutoFetchTest {
private void forceConnectivityState(boolean connected) {
ThreadUtils.runOnUiThreadBlocking(() -> {
NetworkChangeNotifier.forceConnectivityState(connected);
DeviceConditions.mForceNoConnectionForTesting = !connected;
DeviceConditions.sForceNoConnectionForTesting = !connected;
});
OfflineTestUtil.waitForConnectivityState(connected);
}
......
......@@ -9,6 +9,8 @@ import android.content.Context;
import org.robolectric.annotation.Implementation;
import org.robolectric.annotation.Implements;
import org.chromium.net.ConnectionType;
/** Custom shadow for the OfflinePageUtils. */
@Implements(DeviceConditions.class)
public class ShadowDeviceConditions {
......@@ -20,6 +22,14 @@ public class ShadowDeviceConditions {
sDeviceConditions = deviceConditions;
}
/**
* Sets current connection type for the device conditions that will be
* used for tests.
*/
public static void setCurrentNetworkConnectionType(@ConnectionType int connectionType) {
sDeviceConditions.setNetworkConnectionType(connectionType);
}
@Implementation
public static DeviceConditions getCurrent(Context context) {
return sDeviceConditions;
......
// Copyright 2019 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
package org.chromium.chrome.browser.background_sync;
import static org.junit.Assert.assertEquals;
import static org.mockito.Mockito.any;
import static org.mockito.Mockito.anyBoolean;
import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.eq;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import android.content.Context;
import android.os.Bundle;
import org.junit.After;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.ArgumentCaptor;
import org.mockito.Captor;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
import org.robolectric.RuntimeEnvironment;
import org.robolectric.annotation.Config;
import org.chromium.base.BaseSwitches;
import org.chromium.base.Callback;
import org.chromium.base.CommandLine;
import org.chromium.base.SysUtils;
import org.chromium.base.test.BaseRobolectricTestRunner;
import org.chromium.base.test.util.Feature;
import org.chromium.base.test.util.JniMocker;
import org.chromium.chrome.browser.ChromeFeatureList;
import org.chromium.chrome.browser.ShadowDeviceConditions;
import org.chromium.chrome.browser.background_task_scheduler.NativeBackgroundTask;
import org.chromium.chrome.test.support.DisableHistogramsRule;
import org.chromium.components.background_task_scheduler.BackgroundTask;
import org.chromium.components.background_task_scheduler.BackgroundTaskScheduler;
import org.chromium.components.background_task_scheduler.BackgroundTaskSchedulerFactory;
import org.chromium.components.background_task_scheduler.TaskIds;
import org.chromium.components.background_task_scheduler.TaskInfo;
import org.chromium.components.background_task_scheduler.TaskParameters;
import org.chromium.net.ConnectionType;
import java.util.HashMap;
/**
* Unit tests for BackgroundSyncBackgroundTask.
*/
@RunWith(BaseRobolectricTestRunner.class)
@Config(manifest = Config.NONE, shadows = {ShadowDeviceConditions.class})
public class BackgroundSyncBackgroundTaskTest {
private static final String IS_LOW_END_DEVICE_SWITCH =
"--" + BaseSwitches.ENABLE_LOW_END_DEVICE_MODE;
@Rule
public DisableHistogramsRule mDisableHistogramsRule = new DisableHistogramsRule();
@Rule
public JniMocker mocker = new JniMocker();
private Bundle mTaskExtras;
private long mTaskTime;
@Mock
private BackgroundSyncBackgroundTask.Natives mNativeMock;
@Mock
private BackgroundTaskScheduler mTaskScheduler;
@Mock
private BackgroundTask.TaskFinishedCallback mTaskFinishedCallback;
@Mock
private Callback<Boolean> mInternalBooleanCallback;
@Captor
private ArgumentCaptor<TaskInfo> mTaskInfo;
@Before
public void setUp() throws Exception {
MockitoAnnotations.initMocks(this);
BackgroundTaskSchedulerFactory.setSchedulerForTesting(mTaskScheduler);
HashMap<String, Boolean> features = new HashMap<>();
features.put(ChromeFeatureList.BACKGROUND_TASK_SCHEDULER_FOR_BACKGROUND_SYNC, true);
ChromeFeatureList.setTestFeatures(features);
mTaskExtras = new Bundle();
doReturn(true)
.when(mTaskScheduler)
.schedule(eq(RuntimeEnvironment.application), mTaskInfo.capture());
ShadowDeviceConditions.setCurrentNetworkConnectionType(ConnectionType.CONNECTION_NONE);
// Run tests as a low-end device.
CommandLine.init(new String[] {"testcommand", IS_LOW_END_DEVICE_SWITCH});
mocker.mock(BackgroundSyncBackgroundTaskJni.TEST_HOOKS, mNativeMock);
}
@After
public void tearDown() throws Exception {
// Clean up static state for subsequent Robolectric tests.
CommandLine.reset();
SysUtils.resetForTesting();
}
@Test
@Feature("BackgroundSync")
public void testNetworkConditions_NoNetwork() {
// The test has been set up with no network by default.
TaskParameters params = TaskParameters.create(TaskIds.BACKGROUND_SYNC_ONE_SHOT_JOB_ID)
.addExtras(mTaskExtras)
.build();
int result = new BackgroundSyncBackgroundTask().onStartTaskBeforeNativeLoaded(
RuntimeEnvironment.application, params, mTaskFinishedCallback);
assertEquals(NativeBackgroundTask.StartBeforeNativeResult.RESCHEDULE, result);
// TaskFinishedCallback callback is only called once native code has
// finished processing pending Background Sync registrations.
verify(mTaskFinishedCallback, times(0)).taskFinished(anyBoolean());
}
@Test
@Feature("BackgroundSync")
public void testNetworkConditions_Wifi() {
ShadowDeviceConditions.setCurrentNetworkConnectionType(ConnectionType.CONNECTION_WIFI);
TaskParameters params = TaskParameters.create(TaskIds.BACKGROUND_SYNC_ONE_SHOT_JOB_ID)
.addExtras(mTaskExtras)
.build();
int result = new BackgroundSyncBackgroundTask().onStartTaskBeforeNativeLoaded(
RuntimeEnvironment.application, params, mTaskFinishedCallback);
assertEquals(NativeBackgroundTask.StartBeforeNativeResult.LOAD_NATIVE, result);
// TaskFinishedCallback callback is only called once native code has
// finished processing pending Background Sync registrations.
verify(mTaskFinishedCallback, times(0)).taskFinished(anyBoolean());
}
@Test
@Feature("BackgroundSync")
public void testOnStartTaskWithNative() {
TaskParameters params = TaskParameters.create(TaskIds.BACKGROUND_SYNC_ONE_SHOT_JOB_ID)
.addExtras(mTaskExtras)
.build();
new BackgroundSyncBackgroundTask().onStartTaskWithNative(
RuntimeEnvironment.application, params, mTaskFinishedCallback);
verify(mNativeMock).fireBackgroundSyncEvents(any(Runnable.class));
verify(mTaskFinishedCallback, times(0)).taskFinished(anyBoolean());
verify(mTaskScheduler, times(0)).schedule(any(Context.class), any(TaskInfo.class));
}
}
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment