blob: a36e628fcff20bfb10f8c623ebbce5b5d25aed21 [file] [log] [blame]
/*
* Copyright 2017 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 androidx.work.impl.background.systemjob;
import static androidx.work.NetworkType.CONNECTED;
import static androidx.work.NetworkType.METERED;
import static androidx.work.NetworkType.NOT_REQUIRED;
import static androidx.work.NetworkType.NOT_ROAMING;
import static androidx.work.NetworkType.UNMETERED;
import static org.hamcrest.CoreMatchers.is;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.arrayContaining;
import static org.hamcrest.Matchers.greaterThanOrEqualTo;
import android.app.job.JobInfo;
import android.net.Uri;
import android.os.Build;
import androidx.test.core.app.ApplicationProvider;
import androidx.test.ext.junit.runners.AndroidJUnit4;
import androidx.test.filters.SdkSuppress;
import androidx.test.filters.SmallTest;
import androidx.work.BackoffPolicy;
import androidx.work.Constraints;
import androidx.work.NetworkType;
import androidx.work.OneTimeWorkRequest;
import androidx.work.PeriodicWorkRequest;
import androidx.work.WorkManagerTest;
import androidx.work.impl.WorkManagerImpl;
import androidx.work.impl.model.WorkSpec;
import androidx.work.worker.TestWorker;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import java.util.concurrent.TimeUnit;
@RunWith(AndroidJUnit4.class)
@SdkSuppress(minSdkVersion = WorkManagerImpl.MIN_JOB_SCHEDULER_API_LEVEL)
public class SystemJobInfoConverterTest extends WorkManagerTest {
private static final long TEST_INTERVAL_DURATION =
PeriodicWorkRequest.MIN_PERIODIC_INTERVAL_MILLIS + 1232L;
private static final long TEST_FLEX_DURATION =
PeriodicWorkRequest.MIN_PERIODIC_FLEX_MILLIS + 112L;
private static final int JOB_ID = 101;
private SystemJobInfoConverter mConverter;
@Before
public void setUp() {
mConverter = new SystemJobInfoConverter(
ApplicationProvider.getApplicationContext());
}
@Test
@SmallTest
public void testConvert_ids() {
final String expectedWorkSpecId = "026e3422-9cd1-11e7-abc4-cec278b6b50a";
WorkSpec workSpec = new WorkSpec(expectedWorkSpecId, TestWorker.class.getName());
JobInfo jobInfo = mConverter.convert(workSpec, JOB_ID);
String actualWorkSpecId = jobInfo.getExtras().getString(
SystemJobInfoConverter.EXTRA_WORK_SPEC_ID);
assertThat(actualWorkSpecId, is(expectedWorkSpecId));
assertThat(jobInfo.getId(), is(JOB_ID));
}
@Test
@SmallTest
public void testConvert_setPersistedByDefault() {
JobInfo jobInfo = mConverter.convert(
new WorkSpec("id", TestWorker.class.getName()), JOB_ID);
assertThat(jobInfo.isPersisted(), is(false));
}
/**
* Due to b/6771687, calling {@link JobInfo.Builder#build} with no constraints throws an
* {@link IllegalArgumentException}. This is testing that {@link SystemJobInfoConverter#convert}
* sets some dummy constraint to toggle some internal boolean flags in {@link JobInfo.Builder}
* to allow {@link OneTimeWorkRequest} with no constraints to be converted without affecting its
* runtime, e.g. calling builder.setMinLatencyMillis(0L).
*/
@Test
@SmallTest
public void testConvert_noConstraints_doesNotThrowException() {
mConverter.convert(new WorkSpec("id", TestWorker.class.getName()), JOB_ID);
}
@Test
@SmallTest
public void testConvert_retryPolicy() {
long expectedBackoffDelayDuration = 50000;
WorkSpec workSpec = new WorkSpec("id", TestWorker.class.getName());
workSpec.setBackoffDelayDuration(expectedBackoffDelayDuration);
workSpec.backoffPolicy = BackoffPolicy.LINEAR;
JobInfo jobInfo = mConverter.convert(workSpec, JOB_ID);
assertThat(jobInfo.getInitialBackoffMillis(), is(expectedBackoffDelayDuration));
assertThat(jobInfo.getBackoffPolicy(), is(JobInfo.BACKOFF_POLICY_LINEAR));
}
@Test
@SmallTest
public void testConvert_initialDelay() {
final long expectedInitialDelay = 12123L;
WorkSpec workSpec = new WorkSpec("id", TestWorker.class.getName());
workSpec.initialDelay = expectedInitialDelay;
JobInfo jobInfo = mConverter.convert(workSpec, JOB_ID);
assertCloseValues(jobInfo.getMinLatencyMillis(), expectedInitialDelay);
}
@Test
@SmallTest
public void testConvert_periodicWithNoFlex() {
WorkSpec workSpec = new WorkSpec("id", TestWorker.class.getName());
workSpec.setPeriodic(TEST_INTERVAL_DURATION);
JobInfo jobInfo = mConverter.convert(workSpec, JOB_ID);
assertThat(jobInfo.getMinLatencyMillis(), is(0L));
}
@Test
@SmallTest
public void testConvert_periodicWithFlex() {
WorkSpec workSpec = new WorkSpec("id", TestWorker.class.getName());
workSpec.setPeriodic(TEST_INTERVAL_DURATION, TEST_FLEX_DURATION);
JobInfo jobInfo = mConverter.convert(workSpec, JOB_ID);
assertCloseValues(jobInfo.getMinLatencyMillis(),
TEST_INTERVAL_DURATION - TEST_FLEX_DURATION);
}
@Test
@SmallTest
public void testConvert_requireCharging() {
final boolean expectedRequireCharging = true;
WorkSpec workSpec = getTestWorkSpecWithConstraints(new Constraints.Builder()
.setRequiresCharging(expectedRequireCharging).build());
JobInfo jobInfo = mConverter.convert(workSpec, JOB_ID);
assertThat(jobInfo.isRequireCharging(), is(expectedRequireCharging));
}
@Test
@SmallTest
@SdkSuppress(minSdkVersion = 24)
public void testConvert_requireContentUriTrigger() {
final Uri expectedUri = Uri.parse("TEST_URI");
final JobInfo.TriggerContentUri expectedTriggerContentUri =
new JobInfo.TriggerContentUri(
expectedUri, JobInfo.TriggerContentUri.FLAG_NOTIFY_FOR_DESCENDANTS);
WorkSpec workSpec = getTestWorkSpecWithConstraints(new Constraints.Builder()
.addContentUriTrigger(expectedUri, true)
.setTriggerContentUpdateDelay(5, TimeUnit.SECONDS)
.setTriggerContentMaxDelay(10, TimeUnit.SECONDS)
.build());
JobInfo jobInfo = mConverter.convert(workSpec, JOB_ID);
JobInfo.TriggerContentUri[] triggerContentUris = jobInfo.getTriggerContentUris();
assertThat(triggerContentUris, is(arrayContaining(expectedTriggerContentUri)));
assertThat(jobInfo.getTriggerContentUpdateDelay(), is(TimeUnit.SECONDS.toMillis(5)));
assertThat(jobInfo.getTriggerContentMaxDelay(), is(TimeUnit.SECONDS.toMillis(10)));
}
@Test
@SmallTest
public void testConvert_requireDeviceIdle() {
final boolean expectedRequireDeviceIdle = true;
WorkSpec workSpec = getTestWorkSpecWithConstraints(new Constraints.Builder()
.setRequiresDeviceIdle(expectedRequireDeviceIdle).build());
JobInfo jobInfo = mConverter.convert(workSpec, JOB_ID);
assertThat(jobInfo.isRequireDeviceIdle(), is(expectedRequireDeviceIdle));
}
@Test
@SmallTest
@SdkSuppress(minSdkVersion = 26)
public void testConvert_requireBatteryNotLow() {
final boolean expectedRequireBatteryNotLow = true;
WorkSpec workSpec = getTestWorkSpecWithConstraints(new Constraints.Builder()
.setRequiresBatteryNotLow(expectedRequireBatteryNotLow).build());
JobInfo jobInfo = mConverter.convert(workSpec, JOB_ID);
assertThat(jobInfo.isRequireBatteryNotLow(), is(expectedRequireBatteryNotLow));
}
@Test
@SmallTest
@SdkSuppress(minSdkVersion = 26)
public void testConvert_requireStorageNotLow() {
final boolean expectedRequireStorageNotLow = true;
WorkSpec workSpec = getTestWorkSpecWithConstraints(new Constraints.Builder()
.setRequiresStorageNotLow(expectedRequireStorageNotLow).build());
JobInfo jobInfo = mConverter.convert(workSpec, JOB_ID);
assertThat(jobInfo.isRequireStorageNotLow(), is(expectedRequireStorageNotLow));
}
@Test
@SmallTest
public void testConvert_networkTypeNotRoamingRequiresApi24() {
convertWithRequiredNetworkType(NOT_ROAMING, JobInfo.NETWORK_TYPE_NOT_ROAMING, 24);
}
@Test
@SmallTest
public void testConvert_networkTypeMeteredRequiresApi26() {
convertWithRequiredNetworkType(METERED, JobInfo.NETWORK_TYPE_METERED, 26);
}
@Test
@SmallTest
@SdkSuppress(minSdkVersion = 29)
public void testConvert_setImportantWhileForeground() {
WorkSpec workSpec = getTestWorkSpecWithConstraints(new Constraints.Builder().build());
JobInfo jobInfo = mConverter.convert(workSpec, JOB_ID);
assertThat(jobInfo.isImportantWhileForeground(), is(true));
}
@Test
@SmallTest
@SdkSuppress(minSdkVersion = 29)
public void testConvert_setImportantWhileForeground_withTimingConstraints() {
WorkSpec workSpec = new WorkSpec("id", TestWorker.class.getName());
workSpec.setPeriodic(TEST_INTERVAL_DURATION, TEST_FLEX_DURATION);
JobInfo jobInfo = mConverter.convert(workSpec, JOB_ID);
assertThat(jobInfo.isImportantWhileForeground(), is(false));
}
private void convertWithRequiredNetworkType(NetworkType networkType,
int jobInfoNetworkType,
int minSdkVersion) {
WorkSpec workSpec = getTestWorkSpecWithConstraints(new Constraints.Builder()
.setRequiredNetworkType(networkType).build());
JobInfo jobInfo = mConverter.convert(workSpec, JOB_ID);
if (Build.VERSION.SDK_INT >= minSdkVersion) {
assertThat(jobInfo.getNetworkType(), is(jobInfoNetworkType));
} else {
assertThat(jobInfo.getNetworkType(), is(JobInfo.NETWORK_TYPE_ANY));
}
}
@Test
@SmallTest
public void testConvertNetworkType_none() {
assertThat(SystemJobInfoConverter.convertNetworkType(NOT_REQUIRED),
is(JobInfo.NETWORK_TYPE_NONE));
}
@Test
@SmallTest
public void testConvertNetworkType_any() {
assertThat(SystemJobInfoConverter.convertNetworkType(CONNECTED),
is(JobInfo.NETWORK_TYPE_ANY));
}
@Test
@SmallTest
public void testConvertNetworkType_unmetered() {
assertThat(SystemJobInfoConverter.convertNetworkType(UNMETERED),
is(JobInfo.NETWORK_TYPE_UNMETERED));
}
@Test
@SmallTest
@SdkSuppress(minSdkVersion = 23, maxSdkVersion = 23)
public void testConvertNetworkType_notRoaming_returnAnyBeforeApi24() {
assertThat(SystemJobInfoConverter.convertNetworkType(NOT_ROAMING),
is(JobInfo.NETWORK_TYPE_ANY));
}
@Test
@SmallTest
@SdkSuppress(minSdkVersion = 24)
public void testConvertNetworkType_notRoaming_returnsNotRoamingAtOrAfterApi24() {
assertThat(SystemJobInfoConverter.convertNetworkType(NOT_ROAMING),
is(JobInfo.NETWORK_TYPE_NOT_ROAMING));
}
@Test
@SmallTest
@SdkSuppress(minSdkVersion = WorkManagerImpl.MIN_JOB_SCHEDULER_API_LEVEL, maxSdkVersion = 25)
public void testConvertNetworkType_metered_returnsAnyBeforeApi26() {
assertThat(SystemJobInfoConverter.convertNetworkType(METERED),
is(JobInfo.NETWORK_TYPE_ANY));
}
@Test
@SmallTest
@SdkSuppress(minSdkVersion = 26)
public void testConvertNetworkType_metered_returnsMeteredAtOrAfterApi26() {
assertThat(SystemJobInfoConverter.convertNetworkType(METERED),
is(JobInfo.NETWORK_TYPE_METERED));
}
private WorkSpec getTestWorkSpecWithConstraints(Constraints constraints) {
return getWorkSpec(new OneTimeWorkRequest.Builder(TestWorker.class)
.setConstraints(constraints)
.build());
}
private void assertCloseValues(long value, long target) {
double min = Math.min(value, target);
double max = Math.max(value, target);
double ratio = min / max;
assertThat(ratio, greaterThanOrEqualTo(0.999d));
}
}