blob: e62e07d6858f9086b47b6346df1543fdb2e20919 [file] [log] [blame]
/*
* Copyright (C) 2018 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.server.job;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
import static org.junit.Assume.assumeFalse;
import static org.mockito.ArgumentMatchers.anyString;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
import android.app.job.JobInfo;
import android.content.ComponentName;
import android.content.Context;
import android.content.pm.PackageManagerInternal;
import android.os.Build;
import android.os.UserHandle;
import android.util.ArraySet;
import android.util.Log;
import android.util.SparseArray;
import androidx.test.InstrumentationRegistry;
import androidx.test.filters.SmallTest;
import androidx.test.runner.AndroidJUnit4;
import com.android.server.LocalServices;
import com.android.server.job.controllers.JobStatus;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
@RunWith(AndroidJUnit4.class)
@SmallTest
public class JobSetTest {
private static final String TAG = JobSetTest.class.getSimpleName();
private static final int SECONDARY_USER_ID_1 = 12;
private static final int SECONDARY_USER_ID_2 = 13;
private Context mContext;
private ComponentName mComponent;
private JobStore.JobSet mJobSet;
@Before
public void setUp() throws Exception {
mContext = InstrumentationRegistry.getTargetContext();
mComponent = new ComponentName(mContext, JobStoreTest.class);
mJobSet = new JobStore.JobSet();
final PackageManagerInternal pm = mock(PackageManagerInternal.class);
when(pm.getPackageTargetSdkVersion(anyString()))
.thenReturn(Build.VERSION_CODES.CUR_DEVELOPMENT);
LocalServices.addService(PackageManagerInternal.class, pm);
assumeFalse("Test cannot run in user " + mContext.getUserId(),
mContext.getUserId() == SECONDARY_USER_ID_1
|| mContext.getUserId() == SECONDARY_USER_ID_2);
}
private JobStatus getJobStatusWithCallinUid(int jobId, int callingUid) {
final JobInfo jobInfo = new JobInfo.Builder(jobId, mComponent)
.setPeriodic(10)
.setRequiresCharging(true)
.build();
return JobStatus.createFromJobInfo(jobInfo, callingUid, mContext.getPackageName(),
mContext.getUserId(), "Test");
}
@Test
public void testBothMapsHaveSameJobs() {
final int callingUid1 = UserHandle.getUid(SECONDARY_USER_ID_1, 1);
final int callingUid2 = UserHandle.getUid(SECONDARY_USER_ID_2, 1);
final JobStatus testJob1 = getJobStatusWithCallinUid(1, callingUid1);
final JobStatus testJob2 = getJobStatusWithCallinUid(2, callingUid2);
mJobSet.add(testJob1);
mJobSet.add(testJob2);
for (int i = 11; i <= 20; i++) {
mJobSet.add(getJobStatusWithCallinUid(i, (i%2 == 0) ? callingUid2 : callingUid1));
}
assertHaveSameJobs(mJobSet.mJobsPerSourceUid, mJobSet.mJobs);
mJobSet.remove(testJob1);
mJobSet.remove(testJob2);
assertHaveSameJobs(mJobSet.mJobsPerSourceUid, mJobSet.mJobs);
mJobSet.removeJobsOfNonUsers(new int[] {mContext.getUserId(), SECONDARY_USER_ID_1});
assertHaveSameJobs(mJobSet.mJobsPerSourceUid, mJobSet.mJobs);
mJobSet.removeJobsOfNonUsers(new int[] {mContext.getUserId()});
assertTrue("mJobs should be empty", mJobSet.mJobs.size() == 0);
assertTrue("mJobsPerSourceUid should be empty", mJobSet.mJobsPerSourceUid.size() == 0);
}
private static void assertHaveSameJobs(SparseArray<ArraySet<JobStatus>> map1,
SparseArray<ArraySet<JobStatus>> map2) {
final ArraySet<JobStatus> set1 = new ArraySet<>();
final ArraySet<JobStatus> set2 = new ArraySet<>();
int size1 = 0;
for (int i = 0; i < map1.size(); i++) {
final ArraySet<JobStatus> jobs = map1.valueAt(i);
if (jobs == null) return;
size1 += jobs.size();
set1.addAll(jobs);
}
for (int i = 0; i < map2.size(); i++) {
final ArraySet<JobStatus> jobs = map2.valueAt(i);
if (jobs == null) return;
size1 -= jobs.size();
set2.addAll(jobs);
}
if (size1 != 0 || !set1.equals(set2)) {
dump("map1", map1);
dump("map2", map2);
fail("Both maps have different sets of jobs");
}
}
private static void dump(String prefix, SparseArray<ArraySet<JobStatus>> jobMap) {
final StringBuilder str = new StringBuilder();
for (int i = 0; i < jobMap.size(); i++) {
final ArraySet<JobStatus> jobs = jobMap.valueAt(i);
if (jobs == null) return;
str.append("[Key: " + jobMap.keyAt(i) + ", Value: {");
for (int j = 0; j < jobs.size(); j++) {
final JobStatus job = jobs.valueAt(j);
str.append("(s=" + job.getSourceUid() + ", c=" + job.getUid() + "), ");
}
str.append("}], ");
}
Log.d(TAG, prefix + ": " + str.toString());
}
@After
public void tearDown() throws Exception {
LocalServices.removeServiceForTest(PackageManagerInternal.class);
}
}