package com.path.android.jobqueue.test.jobmanager; import com.path.android.jobqueue.Params; import com.path.android.jobqueue.config.Configuration; import com.path.android.jobqueue.executor.JobConsumerExecutor; import com.path.android.jobqueue.log.CustomLogger; import com.path.android.jobqueue.test.jobs.DummyJob; import static org.hamcrest.CoreMatchers.*; import org.hamcrest.*; import org.junit.Test; import org.junit.runner.RunWith; import org.robolectric.*; import java.util.ArrayList; import java.util.List; import java.util.concurrent.Semaphore; import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicInteger; @RunWith(RobolectricTestRunner.class) public class LoadFactorTest extends JobManagerTestBase { @Test public void testLoadFactor() throws Exception { //test adding zillions of jobs from the same group and ensure no more than 1 thread is created int maxConsumerCount = 5; int minConsumerCount = 2; int loadFactor = 5; com.path.android.jobqueue.JobManager jobManager = createJobManager(new Configuration.Builder(Robolectric.application) .maxConsumerCount(maxConsumerCount) .minConsumerCount(minConsumerCount) .customLogger(new CustomLogger() { public boolean isDebugEnabled() {return true;} public void d(String text, Object... args) {System.out.println(String.format(text, args));} public void e(Throwable t, String text, Object... args) {t.printStackTrace(); System.out.println(String.format(text, args));} public void e(String text, Object... args) {System.out.println(String.format(text, args));} }) .loadFactor(loadFactor)); JobConsumerExecutor consumerExecutor = getConsumerExecutor(jobManager); org.fest.reflect.field.Invoker<AtomicInteger> activeConsumerCnt = getActiveConsumerCount(consumerExecutor); Object runLock = new Object(); Semaphore semaphore = new Semaphore(maxConsumerCount); int totalJobCount = loadFactor * maxConsumerCount * 5; List<DummyJob> runningJobs = new ArrayList<DummyJob>(totalJobCount); for(int i = 0; i < totalJobCount; i ++) { DummyJob job = new NeverEndingDummyJob(new Params((int)(Math.random() * 3)), runLock, semaphore); runningJobs.add(job); jobManager.addJob(job); int expectedConsumerCount = Math.min(maxConsumerCount, (int)Math.ceil((float)(i+1) / loadFactor)); if(i >= minConsumerCount) { expectedConsumerCount = Math.max(minConsumerCount, expectedConsumerCount); } //wait till enough jobs start long now = System.nanoTime(); long waitTill = now + TimeUnit.SECONDS.toNanos(10); while(System.nanoTime() < waitTill) { if(semaphore.availablePermits() == maxConsumerCount - expectedConsumerCount) { //enough # of jobs started break; } } if(i < loadFactor) { //make sure there is only min job running MatcherAssert.assertThat("while below load factor, active consumer count should be = min", activeConsumerCnt.get().get(), equalTo(Math.min(i + 1, minConsumerCount))); } if(i > loadFactor) { //make sure there is only 1 job running MatcherAssert.assertThat("while above load factor. there should be more job consumers. i=" + i, activeConsumerCnt.get().get(), equalTo(expectedConsumerCount)); } } //finish all jobs long now = System.nanoTime(); long waitTill = now + TimeUnit.SECONDS.toNanos(10); while(System.nanoTime() < waitTill) { synchronized (runLock) { runLock.notifyAll(); } long totalRunningCount = 0; for(DummyJob job : runningJobs) { totalRunningCount += job.getOnRunCnt(); } if(totalJobCount == totalRunningCount) { //cool! break; } } MatcherAssert.assertThat("no jobs should remain", jobManager.count(), equalTo(0)); } }