package com.path.android.jobqueue.test.jobmanager; import com.path.android.jobqueue.JobHolder; import com.path.android.jobqueue.JobManager; import com.path.android.jobqueue.Params; import com.path.android.jobqueue.config.Configuration; import com.path.android.jobqueue.test.jobs.DummyJob; import org.fest.reflect.method.*; import static org.hamcrest.CoreMatchers.*; import org.hamcrest.*; import org.junit.Test; import org.junit.runner.RunWith; import org.robolectric.*; import java.util.concurrent.CountDownLatch; import java.util.concurrent.atomic.AtomicInteger; @RunWith(RobolectricTestRunner.class) public class GroupingTest extends JobManagerTestBase { @Test public void testGrouping() throws Exception { JobManager jobManager = createJobManager(); jobManager.stop(); Invoker<JobHolder> nextJobMethod = getNextJobMethod(jobManager); Invoker<Void> removeJobMethod = getRemoveJobMethod(jobManager); long jobId1 = jobManager.addJob(new DummyJob(new Params(0).groupBy("group1"))); long jobId2 = jobManager.addJob(new DummyJob(new Params(0).groupBy("group1"))); long jobId3 = jobManager.addJob(new DummyJob(new Params(0).persist().groupBy("group2"))); long jobId4 = jobManager.addJob(new DummyJob(new Params(0).persist().groupBy("group1"))); JobHolder nextJob = nextJobMethod.invoke(); MatcherAssert.assertThat("next job should be the first job from group1", nextJob.getId(), equalTo(jobId1)); JobHolder group2Job = nextJobMethod.invoke(); MatcherAssert.assertThat("since group 1 is running now, next job should be from group 2", group2Job.getId(), equalTo(jobId3)); removeJobMethod.invoke(nextJob); JobHolder group1NextJob =nextJobMethod.invoke(); MatcherAssert.assertThat("after removing job from group 1, another job from group1 should be returned", group1NextJob.getId(), equalTo(jobId2)); MatcherAssert.assertThat("when jobs from both groups are running, no job should be returned from next job", nextJobMethod.invoke(), is(nullValue())); removeJobMethod.invoke(group2Job); MatcherAssert.assertThat("even after group2 job is complete, no jobs should be returned since we only have group1 jobs left", nextJobMethod.invoke(), is(nullValue())); } @Test public void testGroupingRaceCondition() throws Exception { DummyNetworkUtilWithConnectivityEventSupport dummyNetworkUtil = new DummyNetworkUtilWithConnectivityEventSupport(); JobManager jobManager = createJobManager(new Configuration.Builder(Robolectric.application) .minConsumerCount(5).maxConsumerCount(10) .networkUtil(dummyNetworkUtil)); dummyNetworkUtil.setHasNetwork(false, true); //add a bunch of network requring jobs final String GROUP_ID = "shared_group_id"; final int AFTER_ADDED_JOBS_COUNT = 5; final int NOT_SET_JOB_ID = -1; final AtomicInteger firstRunJob = new AtomicInteger(NOT_SET_JOB_ID); final int FIRST_JOB_ID = -10; final CountDownLatch onAddedCalled = new CountDownLatch(1); final CountDownLatch remainingJobsOnAddedCalled = new CountDownLatch(AFTER_ADDED_JOBS_COUNT); jobManager.addJobInBackground(new DummyJob(new Params(10).requireNetwork().groupBy(GROUP_ID)) { @Override public void onAdded() { super.onAdded(); onAddedCalled.countDown(); try { //wait until all other jobs are added remainingJobsOnAddedCalled.await(); //wait a bit after all are added, Thread.sleep(1000); } catch (InterruptedException e) { } } @Override public void onRun() throws Throwable { super.onRun(); firstRunJob.compareAndSet(NOT_SET_JOB_ID, FIRST_JOB_ID); } }); //ensure first jobs on added is called onAddedCalled.await(); for(int i = 0; i < AFTER_ADDED_JOBS_COUNT; i ++) { final int finalI = i; jobManager.addJob(new DummyJob(new Params(5).groupBy(GROUP_ID).requireNetwork()) { final int id = finalI + 1; @Override public void onAdded() { super.onAdded(); remainingJobsOnAddedCalled.countDown(); } @Override public void onRun() throws Throwable { super.onRun(); firstRunJob.compareAndSet(NOT_SET_JOB_ID, id); } }); } dummyNetworkUtil.setHasNetwork(true, true); //wait until all jobs are completed while(firstRunJob.get() == NOT_SET_JOB_ID) { Thread.sleep(100); } MatcherAssert.assertThat("highest priority job should run if it is added before others", firstRunJob.get(), is(FIRST_JOB_ID)); } }