From 8a8a1b83be4fafe4ab385b959bc08b257a272ec5 Mon Sep 17 00:00:00 2001 From: yigit Date: Tue, 14 Jan 2014 11:02:39 -0800 Subject: [PATCH 01/41] inc version code in readme --- README.md | 4 ++-- jobqueue/AndroidManifest.xml | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index 034376c..1ab186f 100644 --- a/README.md +++ b/README.md @@ -128,7 +128,7 @@ At Path, we use [greenrobot's EventBus](https://github.com/greenrobot/EventBus); ### Getting Started We distribute artifacts through maven central repository. -Gradle: `compile 'com.path:android-priority-jobqueue:0.9.9'` +Gradle: `compile 'com.path:android-priority-jobqueue:1.0'` Maven: @@ -136,7 +136,7 @@ Maven: com.path android-priority-jobqueue - 0.9.9 + 1.0 ``` diff --git a/jobqueue/AndroidManifest.xml b/jobqueue/AndroidManifest.xml index 4912d66..88078b1 100644 --- a/jobqueue/AndroidManifest.xml +++ b/jobqueue/AndroidManifest.xml @@ -1,8 +1,8 @@ + android:versionCode="2" + android:versionName="1.0"> From 9bf72e89252ce9b7608c66ad8992e17ef8bd4a34 Mon Sep 17 00:00:00 2001 From: yigit Date: Tue, 14 Jan 2014 11:13:01 -0800 Subject: [PATCH 02/41] add version history to wiki --- README.md | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/README.md b/README.md index 1ab186f..ef75d7c 100644 --- a/README.md +++ b/README.md @@ -14,6 +14,7 @@ It is written primarily with [flexibility][10] & [functionality][11] in mind. Th - [What's happening under the hood?](#under-the-hood) - [Advantages](#advantages) - [Getting Started](#getting-started) + - [Version History](#version-history) - [Building](#building) - [Running Tests](#running-tests) - [wiki][9] @@ -148,6 +149,15 @@ We highly recommend checking how you can configure job manager and individual jo * [Review sample app][6] * [Review sample configuration][7] +### Version History + + - 1.0 (Jan 14, 2014): + - Added [parameterized][12] constructor for Job for more readable code. + - Deprecated `BaseJob` in favor of a more complete `Job` class. + - 0.9.9 (Dec 16, 2013): + - First public release. + + ### [Wiki][9] ### Dependencies From c4ce282879850ca0845b58d5b322f3ee2a89c18e Mon Sep 17 00:00:00 2001 From: yigit Date: Tue, 14 Jan 2014 11:15:28 -0800 Subject: [PATCH 03/41] add missing link --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index ef75d7c..a8027b0 100644 --- a/README.md +++ b/README.md @@ -228,3 +228,4 @@ THE SOFTWARE. [9]: https://github.com/path/android-priority-jobqueue/wiki [10]: https://github.com/path/android-priority-jobqueue/wiki/Job-Manager-Configuration [11]: https://github.com/path/android-priority-jobqueue/wiki/Job-Configuration +[12]: https://github.com/path/android-priority-jobqueue/blob/master/jobqueue/src/com/path/android/jobqueue/Params.java From c4d1c228f0cbff8ceed70f4ca8b48b2d3da7cf5a Mon Sep 17 00:00:00 2001 From: yigit Date: Tue, 21 Jan 2014 13:18:18 -0800 Subject: [PATCH 04/41] failing unit test for #21 --- jobqueue/AndroidManifest.xml | 2 +- .../test/jobqueue/JobQueueTestBase.java | 7 ++-- .../jobqueue/NonPersistentJobQueueTest.java | 36 ++++++++++++++++++- 3 files changed, 41 insertions(+), 4 deletions(-) diff --git a/jobqueue/AndroidManifest.xml b/jobqueue/AndroidManifest.xml index 88078b1..29eff0d 100644 --- a/jobqueue/AndroidManifest.xml +++ b/jobqueue/AndroidManifest.xml @@ -2,7 +2,7 @@ + android:versionName="1.1"> diff --git a/jobqueue/test/com/path/android/jobqueue/test/jobqueue/JobQueueTestBase.java b/jobqueue/test/com/path/android/jobqueue/test/jobqueue/JobQueueTestBase.java index 9c3c188..9b19689 100644 --- a/jobqueue/test/com/path/android/jobqueue/test/jobqueue/JobQueueTestBase.java +++ b/jobqueue/test/com/path/android/jobqueue/test/jobqueue/JobQueueTestBase.java @@ -75,6 +75,7 @@ public void testPriority() throws Exception { MatcherAssert.assertThat(jobQueue.nextJobAndIncRunCount(true, null), nullValue()); } + @Test public void testDelayUntilWithPriority() throws Exception { JobQueue jobQueue = createNewJobQueue(); @@ -437,7 +438,9 @@ protected JobHolder createNewJobHolder() { } protected JobHolder createNewJobHolder(Params params) { - return new JobHolder(null, getPriorityField(params).get(), getGroupIdField(params).get(), 0, new DummyJob(params), System.nanoTime(), Long.MIN_VALUE, JobManager.NOT_RUNNING_SESSION_ID); + long delay = getDelayMsField(params).get(); + return new JobHolder(null, getPriorityField(params).get(), getGroupIdField(params).get(), 0, new DummyJob(params), System.nanoTime(), + delay > 0 ? System.nanoTime() + delay * JobManager.NS_PER_MS : JobManager.NOT_DELAYED_JOB_DELAY, JobManager.NOT_RUNNING_SESSION_ID); } private JobHolder createNewJobHolderWithDelayUntil(Params params, long delayUntil) { @@ -446,7 +449,7 @@ private JobHolder createNewJobHolderWithDelayUntil(Params params, long delayUnti return jobHolder; } - private JobQueue createNewJobQueue() { + protected JobQueue createNewJobQueue() { return createNewJobQueueWithSessionId(System.nanoTime()); } diff --git a/jobqueue/test/com/path/android/jobqueue/test/jobqueue/NonPersistentJobQueueTest.java b/jobqueue/test/com/path/android/jobqueue/test/jobqueue/NonPersistentJobQueueTest.java index 32ca824..aec3924 100644 --- a/jobqueue/test/com/path/android/jobqueue/test/jobqueue/NonPersistentJobQueueTest.java +++ b/jobqueue/test/com/path/android/jobqueue/test/jobqueue/NonPersistentJobQueueTest.java @@ -1,10 +1,16 @@ package com.path.android.jobqueue.test.jobqueue; +import com.path.android.jobqueue.JobHolder; +import com.path.android.jobqueue.JobManager; import com.path.android.jobqueue.JobQueue; +import com.path.android.jobqueue.Params; import com.path.android.jobqueue.nonPersistentQueue.NonPersistentPriorityQueue; import com.path.android.jobqueue.test.util.JobQueueFactory; +import static org.hamcrest.CoreMatchers.*; +import org.hamcrest.*; +import org.junit.Test; import org.junit.runner.RunWith; -import org.robolectric.RobolectricTestRunner; +import org.robolectric.*; @RunWith(RobolectricTestRunner.class) public class NonPersistentJobQueueTest extends JobQueueTestBase { @@ -16,4 +22,32 @@ public JobQueue createNew(long sessionId, String id) { } }); } + + /** + * issue #21 https://github.com/path/android-priority-jobqueue/issues/21 + */ + @Test + public void testTooManyQueueChanges() throws InterruptedException { + JobQueue jobQueue = createNewJobQueue(); + int limit = 10000; + long delayMs = 2000; + long then = System.nanoTime() + delayMs * JobManager.NS_PER_MS; + for(int i = 0; i < limit; i++) { + jobQueue.insert(createNewJobHolder(new Params(0).requireNetwork().delayInMs(delayMs))); + } + + MatcherAssert.assertThat("all jobs require network, should return null", jobQueue.nextJobAndIncRunCount(false, null), nullValue()); + long sleep = then - System.nanoTime(); + sleep += JobManager.NS_PER_MS * 1000; + if (sleep > 0) { + Thread.sleep(sleep / JobManager.NS_PER_MS); + } + //should be able to get it w/o an overflow + for(int i = 0; i < limit; i++) { + JobHolder holder = jobQueue.nextJobAndIncRunCount(true, null); + MatcherAssert.assertThat("should get a next job", holder, notNullValue()); + jobQueue.remove(holder); + } + + } } From 703e57306e41ae5be2c9f585ab0330232306a2f9 Mon Sep 17 00:00:00 2001 From: yigit Date: Tue, 21 Jan 2014 13:34:05 -0800 Subject: [PATCH 05/41] avoid recursive calls in Merged Queue fixes: #21 --- .../nonPersistentQueue/MergedQueue.java | 48 ++++++++++--------- 1 file changed, 25 insertions(+), 23 deletions(-) diff --git a/jobqueue/src/com/path/android/jobqueue/nonPersistentQueue/MergedQueue.java b/jobqueue/src/com/path/android/jobqueue/nonPersistentQueue/MergedQueue.java index f845afd..4df0fef 100644 --- a/jobqueue/src/com/path/android/jobqueue/nonPersistentQueue/MergedQueue.java +++ b/jobqueue/src/com/path/android/jobqueue/nonPersistentQueue/MergedQueue.java @@ -110,31 +110,33 @@ public JobHolder poll(Collection excludeGroupIds) { */ @Override public JobHolder peek(Collection excludeGroupIds) { - JobHolder delayed = queue0.peek(excludeGroupIds); - //if queue for this job has changed, re-add it and try peek from scratch - if(delayed != null && decideQueue(delayed) != SetId.S0) { - queue1.offer(delayed); - queue0.remove(delayed); - return peek(excludeGroupIds); - } - JobHolder nonDelayed = queue1.peek(excludeGroupIds); - //if queue for this job has changed, re-add it and try peek from scratch - if(nonDelayed != null && decideQueue(nonDelayed) != SetId.S1) { - queue0.offer(nonDelayed); - queue1.remove(nonDelayed); - return peek(excludeGroupIds); - } - if(delayed == null) { + while (true) { + JobHolder delayed = queue0.peek(excludeGroupIds); + //if queue for this job has changed, re-add it and try peek from scratch + if(delayed != null && decideQueue(delayed) != SetId.S0) { + queue1.offer(delayed); + queue0.remove(delayed); + continue;//retry + } + JobHolder nonDelayed = queue1.peek(excludeGroupIds); + //if queue for this job has changed, re-add it and try peek from scratch + if(nonDelayed != null && decideQueue(nonDelayed) != SetId.S1) { + queue0.offer(nonDelayed); + queue1.remove(nonDelayed); + continue;//retry + } + if(delayed == null) { + return nonDelayed; + } + if(nonDelayed == null) { + return delayed; + } + int cmp = retrieveComparator.compare(delayed, nonDelayed); + if(cmp == -1) { + return delayed; + } return nonDelayed; } - if(nonDelayed == null) { - return delayed; - } - int cmp = retrieveComparator.compare(delayed, nonDelayed); - if(cmp == -1) { - return delayed; - } - return nonDelayed; } From 039f3692605c98b8519cc0cf18c0a219a289d8ca Mon Sep 17 00:00:00 2001 From: yigit Date: Tue, 21 Jan 2014 10:21:03 -0800 Subject: [PATCH 06/41] job status functionality. WIP #18 --- .../android/jobqueue/AsyncAddCallback.java | 12 +++++++ .../com/path/android/jobqueue/JobManager.java | 25 ++++++++++++++- .../com/path/android/jobqueue/JobQueue.java | 7 +++++ .../com/path/android/jobqueue/JobStatus.java | 31 +++++++++++++++++++ 4 files changed, 74 insertions(+), 1 deletion(-) create mode 100644 jobqueue/src/com/path/android/jobqueue/AsyncAddCallback.java create mode 100644 jobqueue/src/com/path/android/jobqueue/JobStatus.java diff --git a/jobqueue/src/com/path/android/jobqueue/AsyncAddCallback.java b/jobqueue/src/com/path/android/jobqueue/AsyncAddCallback.java new file mode 100644 index 0000000..2b464e6 --- /dev/null +++ b/jobqueue/src/com/path/android/jobqueue/AsyncAddCallback.java @@ -0,0 +1,12 @@ +package com.path.android.jobqueue; + +import android.app.Activity; + +/** + * If you are adding the job via the async adder, you can provide a callback method to receive the ID. + * Please keep in mind that job manager will keep a strong reference to this callback. So if the callback is an + * anonymous class inside an {@link Activity} context, it may leak the activity until the job is added. + */ +public interface AsyncAddCallback { + public void onAdded(long jobId); +} diff --git a/jobqueue/src/com/path/android/jobqueue/JobManager.java b/jobqueue/src/com/path/android/jobqueue/JobManager.java index 8c18ea7..0c64f06 100644 --- a/jobqueue/src/com/path/android/jobqueue/JobManager.java +++ b/jobqueue/src/com/path/android/jobqueue/JobManager.java @@ -156,6 +156,10 @@ public void addJobInBackground(Job job) { addJobInBackground(job.getPriority(), job.getDelayInMs(), job); } + public void addJobInBackground(Job job, /*nullable*/ AsyncAddCallback callback) { + addJobInBackground(job.getPriority(), job.getDelayInMs(), job, callback); + } + //need to sync on related job queue before calling this private void addOnAddedLock(ConcurrentHashMap lockMap, long id) { lockMap.put(id, new CountDownLatch(1)); @@ -299,6 +303,17 @@ private void reAddJob(JobHolder jobHolder) { } } + /** + * returns the current status of a {@link Job} + * @param id the ID, returned by the addJob method + * @param isPersistent Jobs are added to different queues depending on if they are persistent or not. This is necessary + * because each queue has independent id sets. + * @return + */ + public JobStatus getJobStatus(long id, boolean isPersistent) { + return null; + } + private void removeJob(JobHolder jobHolder) { if (jobHolder.getBaseJob().isPersistent()) { synchronized (persistentJobQueue) { @@ -497,12 +512,20 @@ public void run() { */ @Deprecated public void addJobInBackground(final int priority, final long delay, final BaseJob baseJob) { + addJobInBackground(priority, delay, baseJob, null); + } + + protected void addJobInBackground(final int priority, final long delay, final BaseJob baseJob, + /*nullable*/final AsyncAddCallback callback) { final long callTime = System.nanoTime(); timedExecutor.execute(new Runnable() { @Override public void run() { final long runDelay = (System.nanoTime() - callTime) / NS_PER_MS; - addJob(priority, Math.max(0, delay - runDelay), baseJob); + long id = addJob(priority, Math.max(0, delay - runDelay), baseJob); + if(callback != null) { + callback.onAdded(id); + } } }); } diff --git a/jobqueue/src/com/path/android/jobqueue/JobQueue.java b/jobqueue/src/com/path/android/jobqueue/JobQueue.java index 0755505..bec4ce4 100644 --- a/jobqueue/src/com/path/android/jobqueue/JobQueue.java +++ b/jobqueue/src/com/path/android/jobqueue/JobQueue.java @@ -72,4 +72,11 @@ public interface JobQueue { */ void clear(); + /** + * returns the current status of a job + * @param id job id, returned by the {@link JobManager#addJob(Job)} method. + * @return + */ + JobStatus getJobStatus(long id); + } diff --git a/jobqueue/src/com/path/android/jobqueue/JobStatus.java b/jobqueue/src/com/path/android/jobqueue/JobStatus.java new file mode 100644 index 0000000..8199db2 --- /dev/null +++ b/jobqueue/src/com/path/android/jobqueue/JobStatus.java @@ -0,0 +1,31 @@ +package com.path.android.jobqueue; + +/** + * Identifies the current status of a job if it is in the queue + */ +public enum JobStatus { + /** + * Job is in the queue but requires network connection to be run and there is no network available right now + */ + WAITING_FOR_NETWORK, + /** + * Job is in the queue, ready to be run. Waiting for an available consumer + */ + WAITING, + /** + * Job is executed by one of the runners + */ + RUNNING, + /** + * Job is not know by job queue. + *

This can be: + *

    + *
  • Invalid ID
  • + *
  • Job has been completed
  • + *
  • Job has failed
  • + *
  • Job has just been added, about to be delivered into a queue
  • + *
+ *

+ */ + DOES_NOT_EXISTS +} From 7234c05065af5f77640d67820bdacebea38768d9 Mon Sep 17 00:00:00 2001 From: yigit Date: Wed, 22 Jan 2014 12:23:40 -0800 Subject: [PATCH 07/41] failing unit tests for find job by id for queues. #18 --- .../com/path/android/jobqueue/JobQueue.java | 8 +- .../com/path/android/jobqueue/JobStatus.java | 16 +- .../jobqueue/cachedQueue/CachedJobQueue.java | 5 + .../NonPersistentPriorityQueue.java | 11 + .../sqlite/SqliteJobQueue.java | 11 + .../test/jobqueue/JobQueueTestBase.java | 194 +++++++++++------- 6 files changed, 161 insertions(+), 84 deletions(-) diff --git a/jobqueue/src/com/path/android/jobqueue/JobQueue.java b/jobqueue/src/com/path/android/jobqueue/JobQueue.java index bec4ce4..a149a00 100644 --- a/jobqueue/src/com/path/android/jobqueue/JobQueue.java +++ b/jobqueue/src/com/path/android/jobqueue/JobQueue.java @@ -73,10 +73,10 @@ public interface JobQueue { void clear(); /** - * returns the current status of a job - * @param id job id, returned by the {@link JobManager#addJob(Job)} method. - * @return + * returns the job with the given id if it exists in the queue + * @param id id of the job, returned by insert method + * @return JobHolder with the given id or null if it does not exists */ - JobStatus getJobStatus(long id); + JobHolder findJobById(long id); } diff --git a/jobqueue/src/com/path/android/jobqueue/JobStatus.java b/jobqueue/src/com/path/android/jobqueue/JobStatus.java index 8199db2..42cdd72 100644 --- a/jobqueue/src/com/path/android/jobqueue/JobStatus.java +++ b/jobqueue/src/com/path/android/jobqueue/JobStatus.java @@ -5,20 +5,24 @@ */ public enum JobStatus { /** - * Job is in the queue but requires network connection to be run and there is no network available right now + * Job is in the queue but cannot run yet. + * As of v 1.1, this might be: + *
    + *
  • Job requires network but there is no available network connection
  • + *
*/ - WAITING_FOR_NETWORK, + WAITING_NOT_READY, /** - * Job is in the queue, ready to be run. Waiting for an available consumer + * Job is in the queue, ready to be run. Waiting for an available consumer. */ - WAITING, + WAITING_READY, /** - * Job is executed by one of the runners + * Job is being executed by one of the runners. */ RUNNING, /** * Job is not know by job queue. - *

This can be: + *

This might be: *

    *
  • Invalid ID
  • *
  • Job has been completed
  • diff --git a/jobqueue/src/com/path/android/jobqueue/cachedQueue/CachedJobQueue.java b/jobqueue/src/com/path/android/jobqueue/cachedQueue/CachedJobQueue.java index be3279a..c373c99 100644 --- a/jobqueue/src/com/path/android/jobqueue/cachedQueue/CachedJobQueue.java +++ b/jobqueue/src/com/path/android/jobqueue/cachedQueue/CachedJobQueue.java @@ -93,6 +93,11 @@ public void clear() { delegate.clear(); } + @Override + public JobHolder findJobById(long id) { + return delegate.findJobById(id); + } + private static class Cache { Integer count; DelayUntil delayUntil; diff --git a/jobqueue/src/com/path/android/jobqueue/nonPersistentQueue/NonPersistentPriorityQueue.java b/jobqueue/src/com/path/android/jobqueue/nonPersistentQueue/NonPersistentPriorityQueue.java index 618d4da..503101b 100644 --- a/jobqueue/src/com/path/android/jobqueue/nonPersistentQueue/NonPersistentPriorityQueue.java +++ b/jobqueue/src/com/path/android/jobqueue/nonPersistentQueue/NonPersistentPriorityQueue.java @@ -91,11 +91,22 @@ public Long getNextJobDelayUntilNs(boolean hasNetwork) { return next == null ? null : next.getDelayUntilNs(); } + /** + * {@inheritDoc} + */ @Override public void clear() { jobs.clear(); } + /** + * {@inheritDoc} + */ + @Override + public JobHolder findJobById(long id) { + return null; + } + public final Comparator jobComparator = new Comparator() { @Override public int compare(JobHolder holder1, JobHolder holder2) { diff --git a/jobqueue/src/com/path/android/jobqueue/persistentQueue/sqlite/SqliteJobQueue.java b/jobqueue/src/com/path/android/jobqueue/persistentQueue/sqlite/SqliteJobQueue.java index 5f290e5..af6153e 100644 --- a/jobqueue/src/com/path/android/jobqueue/persistentQueue/sqlite/SqliteJobQueue.java +++ b/jobqueue/src/com/path/android/jobqueue/persistentQueue/sqlite/SqliteJobQueue.java @@ -246,6 +246,9 @@ public Long getNextJobDelayUntilNs(boolean hasNetwork) { } } + /** + * {@inheritDoc} + */ @Override public void clear() { sqlHelper.truncate(); @@ -253,6 +256,14 @@ public void clear() { nextJobsQueryCache.clear(); } + /** + * {@inheritDoc} + */ + @Override + public JobHolder findJobById(long id) { + return null; + } + private void onJobFetchedForRunning(JobHolder jobHolder) { SQLiteStatement stmt = sqlHelper.getOnJobFetchedForRunningStatement(); jobHolder.setRunCount(jobHolder.getRunCount() + 1); diff --git a/jobqueue/test/com/path/android/jobqueue/test/jobqueue/JobQueueTestBase.java b/jobqueue/test/com/path/android/jobqueue/test/jobqueue/JobQueueTestBase.java index 9b19689..73797d3 100644 --- a/jobqueue/test/com/path/android/jobqueue/test/jobqueue/JobQueueTestBase.java +++ b/jobqueue/test/com/path/android/jobqueue/test/jobqueue/JobQueueTestBase.java @@ -9,7 +9,7 @@ import com.path.android.jobqueue.test.util.JobQueueFactory; import org.fest.reflect.core.*; import static org.hamcrest.CoreMatchers.*; -import org.hamcrest.*; +import static org.hamcrest.MatcherAssert.*; import org.junit.Ignore; import org.junit.Test; @@ -28,34 +28,34 @@ public JobQueueTestBase(JobQueueFactory factory) { public void testBasicAddRemoveCount() throws Exception { final int ADD_COUNT = 6; JobQueue jobQueue = createNewJobQueue(); - MatcherAssert.assertThat((int) jobQueue.count(), equalTo(0)); - MatcherAssert.assertThat(jobQueue.nextJobAndIncRunCount(true, null), nullValue()); + assertThat((int) jobQueue.count(), equalTo(0)); + assertThat(jobQueue.nextJobAndIncRunCount(true, null), nullValue()); for (int i = 0; i < ADD_COUNT; i++) { JobHolder holder = createNewJobHolder(); jobQueue.insert(holder); - MatcherAssert.assertThat((int) jobQueue.count(), equalTo(i + 1)); - MatcherAssert.assertThat(holder.getId(), notNullValue()); + assertThat((int) jobQueue.count(), equalTo(i + 1)); + assertThat(holder.getId(), notNullValue()); jobQueue.insertOrReplace(holder); - MatcherAssert.assertThat((int) jobQueue.count(), equalTo(i + 1)); + assertThat((int) jobQueue.count(), equalTo(i + 1)); } JobHolder firstHolder = jobQueue.nextJobAndIncRunCount(true, null); - MatcherAssert.assertThat(firstHolder.getRunCount(), equalTo(1)); + assertThat(firstHolder.getRunCount(), equalTo(1)); //size should be down 1 - MatcherAssert.assertThat((int) jobQueue.count(), equalTo(ADD_COUNT - 1)); + assertThat((int) jobQueue.count(), equalTo(ADD_COUNT - 1)); //should return another job JobHolder secondHolder = jobQueue.nextJobAndIncRunCount(true, null); - MatcherAssert.assertThat(secondHolder.getRunCount(), equalTo(1)); + assertThat(secondHolder.getRunCount(), equalTo(1)); //size should be down 2 - MatcherAssert.assertThat((int) jobQueue.count(), equalTo(ADD_COUNT - 2)); + assertThat((int) jobQueue.count(), equalTo(ADD_COUNT - 2)); //second holder and first holder should have different ids - MatcherAssert.assertThat(firstHolder.getId(), not(secondHolder.getId())); + assertThat(firstHolder.getId(), not(secondHolder.getId())); jobQueue.remove(secondHolder); - MatcherAssert.assertThat((int) jobQueue.count(), equalTo(ADD_COUNT - 2)); + assertThat((int) jobQueue.count(), equalTo(ADD_COUNT - 2)); jobQueue.remove(secondHolder); //non existed job removed, count should be the same - MatcherAssert.assertThat((int) jobQueue.count(), equalTo(ADD_COUNT - 2)); + assertThat((int) jobQueue.count(), equalTo(ADD_COUNT - 2)); jobQueue.remove(firstHolder); - MatcherAssert.assertThat((int) jobQueue.count(), equalTo(ADD_COUNT - 2)); + assertThat((int) jobQueue.count(), equalTo(ADD_COUNT - 2)); } @Test @@ -70,9 +70,9 @@ public void testPriority() throws Exception { int minPriority = Integer.MAX_VALUE; for (int i = 0; i < JOB_LIMIT; i++) { JobHolder holder = jobQueue.nextJobAndIncRunCount(true, null); - MatcherAssert.assertThat(holder.getPriority() <= minPriority, is(true)); + assertThat(holder.getPriority() <= minPriority, is(true)); } - MatcherAssert.assertThat(jobQueue.nextJobAndIncRunCount(true, null), nullValue()); + assertThat(jobQueue.nextJobAndIncRunCount(true, null), nullValue()); } @@ -84,7 +84,7 @@ public void testDelayUntilWithPriority() throws Exception { JobHolder highPriorityHolder = createNewJobHolderWithDelayUntil(new Params(10), now + 20000 * JobManager.NS_PER_MS); jobQueue.insert(lowPriorityHolder); jobQueue.insert(highPriorityHolder); - MatcherAssert.assertThat("when asked, if lower priority job has less delay until, we should return it", + assertThat("when asked, if lower priority job has less delay until, we should return it", jobQueue.getNextJobDelayUntilNs(true), equalTo(lowPriorityHolder.getDelayUntilNs())); } @@ -98,20 +98,20 @@ public void testGroupId() throws Exception { long jobId4 = jobQueue.insert(createNewJobHolder(new Params(0).groupBy("group2"))); long jobId5 = jobQueue.insert(createNewJobHolder(new Params(0).groupBy("group1"))); JobHolder holder1 = jobQueue.nextJobAndIncRunCount(true, Arrays.asList(new String[]{"group2"})); - MatcherAssert.assertThat("first jobs should be from group group2 if group1 is excluded", + assertThat("first jobs should be from group group2 if group1 is excluded", holder1.getBaseJob().getRunGroupId(), equalTo("group1")); - MatcherAssert.assertThat("correct job should be returned if groupId is provided", + assertThat("correct job should be returned if groupId is provided", holder1.getId(), equalTo(jobId1)); - MatcherAssert.assertThat("no jobs should be returned if all groups are excluded", + assertThat("no jobs should be returned if all groups are excluded", jobQueue.nextJobAndIncRunCount(true, Arrays.asList(new String[]{"group1", "group2"})), is(nullValue())); long jobId6 = jobQueue.insert(createNewJobHolder(new Params(0))); - MatcherAssert.assertThat("both groups are disabled, null group job should be returned", + assertThat("both groups are disabled, null group job should be returned", jobQueue.nextJobAndIncRunCount(true, Arrays.asList(new String[]{"group1", "group2"})).getId(), is(jobId6)); - MatcherAssert.assertThat("if group1 is excluded, next job should be from group2", + assertThat("if group1 is excluded, next job should be from group2", jobQueue.nextJobAndIncRunCount(true, Arrays.asList(new String[]{"group1"})).getBaseJob().getRunGroupId() , equalTo("group2")); @@ -119,12 +119,12 @@ public void testGroupId() throws Exception { jobQueue.insertOrReplace(holder1); //ask for it again, should return the same holder because it is grouped JobHolder holder2 = jobQueue.nextJobAndIncRunCount(true, null); - MatcherAssert.assertThat("for grouped jobs, re-fetching job should work fine", + assertThat("for grouped jobs, re-fetching job should work fine", holder2.getId(), equalTo(holder1.getId())); JobHolder holder3 = jobQueue.nextJobAndIncRunCount(true, Arrays.asList(new String[]{"group1"})); - MatcherAssert.assertThat("if a group it excluded, next available from another group should be returned", + assertThat("if a group it excluded, next available from another group should be returned", holder3.getId(), equalTo(jobId4)); //add two more non-grouped jobs @@ -132,12 +132,12 @@ public void testGroupId() throws Exception { long jobId8 = jobQueue.insert(createNewJobHolder(new Params(0))); JobHolder holder4 = jobQueue.nextJobAndIncRunCount(true, Arrays.asList(new String[]{"group1", "group2"})); - MatcherAssert.assertThat("if all grouped jobs are excluded, non-grouped jobs should be returned", + assertThat("if all grouped jobs are excluded, non-grouped jobs should be returned", holder4.getId(), equalTo(jobId7)); jobQueue.insertOrReplace(holder4); //for non-grouped jobs, run counts should be respected - MatcherAssert.assertThat("if all grouped jobs are excluded, re-inserted highest priority job should still be returned", + assertThat("if all grouped jobs are excluded, re-inserted highest priority job should still be returned", jobQueue.nextJobAndIncRunCount(true, Arrays.asList(new String[]{"group1", "group2"})).getId(), equalTo(jobId7)); @@ -154,13 +154,13 @@ public void testDueDelayUntilWithPriority() throws Exception { long soonJobDelay = 2000; JobHolder highestPriorityDelayedJob = createNewJobHolderWithDelayUntil(new Params(12), now + soonJobDelay * JobManager.NS_PER_MS); long highestPriorityDelayedJobId = jobQueue.insert(highestPriorityDelayedJob); - MatcherAssert.assertThat("when asked, if job's due has passed, highest priority jobs's delay until should be " + + assertThat("when asked, if job's due has passed, highest priority jobs's delay until should be " + "returned", jobQueue.getNextJobDelayUntilNs(true), equalTo(highPriorityHolder.getDelayUntilNs())); //make sure soon job is valid now Thread.sleep(soonJobDelay); - MatcherAssert.assertThat("when a job's time come, it should be returned", + assertThat("when a job's time come, it should be returned", jobQueue.nextJobAndIncRunCount(true, null).getId(), equalTo(highestPriorityDelayedJobId)); } @@ -175,16 +175,16 @@ public void testDelayUntil() throws Exception { jobQueue.insert(networkJobHolder); jobQueue.insert(noNetworkJobHolder); - MatcherAssert.assertThat("if there is no network, delay until should be provided for no network job", + assertThat("if there is no network, delay until should be provided for no network job", jobQueue.getNextJobDelayUntilNs(false), equalTo(noNetworkJobHolder.getDelayUntilNs())); - MatcherAssert.assertThat("if there is network, delay until should be provided for network job because it is " + + assertThat("if there is network, delay until should be provided for network job because it is " + "sooner", jobQueue.getNextJobDelayUntilNs(true), equalTo(networkJobHolder.getDelayUntilNs())); JobHolder noNetworkJobHolder2 = createNewJobHolderWithDelayUntil(new Params(0), now + 100000 * JobManager.NS_PER_MS); jobQueue.insert(noNetworkJobHolder2); - MatcherAssert.assertThat("if there is network, any job's delay until should be returned", + assertThat("if there is network, any job's delay until should be returned", jobQueue.getNextJobDelayUntilNs(true), equalTo(noNetworkJobHolder2.getDelayUntilNs())); } @@ -195,13 +195,13 @@ public void testTruncate() throws Exception { for(int i = 0; i < LIMIT; i ++) { jobQueue.insert(createNewJobHolder()); } - MatcherAssert.assertThat("queue should have all jobs", jobQueue.count(), equalTo(LIMIT)); + assertThat("queue should have all jobs", jobQueue.count(), equalTo(LIMIT)); jobQueue.clear(); - MatcherAssert.assertThat("after clear, queue should be empty", jobQueue.count(), equalTo(0)); + assertThat("after clear, queue should be empty", jobQueue.count(), equalTo(0)); for(int i = 0; i < LIMIT; i ++) { jobQueue.insert(createNewJobHolder()); } - MatcherAssert.assertThat("if we add jobs again, count should match", jobQueue.count(), equalTo(LIMIT)); + assertThat("if we add jobs again, count should match", jobQueue.count(), equalTo(LIMIT)); } @Test @@ -231,8 +231,8 @@ public void testPriorityWithDelayedJobs() throws Exception { int lastPriority = Integer.MAX_VALUE; for(int i = 0; i < 5; i++) { JobHolder next = jobQueue.nextJobAndIncRunCount(true, null); - MatcherAssert.assertThat("next job should not be null", next, notNullValue()); - MatcherAssert.assertThat("next job's priority should be lower then previous for job " + i, next.getPriority() <= lastPriority, is(true)); + assertThat("next job should not be null", next, notNullValue()); + assertThat("next job's priority should be lower then previous for job " + i, next.getPriority() <= lastPriority, is(true)); lastPriority = next.getPriority(); } @@ -261,7 +261,7 @@ public void testSessionId() throws Exception { JobHolder jobHolder = createNewJobHolder(); jobQueue.insert(jobHolder); jobHolder = jobQueue.nextJobAndIncRunCount(true, null); - MatcherAssert.assertThat("session id should be attached to next job", + assertThat("session id should be attached to next job", jobHolder.getRunningSessionId(), equalTo(sessionId)); } @@ -277,10 +277,10 @@ public void testPriorityWithReAdd() throws Exception { int minPriority = Integer.MAX_VALUE; for (int i = 0; i < JOB_LIMIT; i++) { JobHolder holder = jobQueue.nextJobAndIncRunCount(true, null); - MatcherAssert.assertThat(holder.getPriority() <= minPriority, is(true)); + assertThat(holder.getPriority() <= minPriority, is(true)); jobQueue.insertOrReplace(holder); } - MatcherAssert.assertThat(jobQueue.nextJobAndIncRunCount(true, null), notNullValue()); + assertThat(jobQueue.nextJobAndIncRunCount(true, null), notNullValue()); } @Test @@ -289,10 +289,10 @@ public void testRemove() throws Exception { JobHolder holder = createNewJobHolder(); jobQueue.insert(holder); Long jobId = holder.getId(); - MatcherAssert.assertThat(jobQueue.nextJobAndIncRunCount(true, null).getId(), equalTo(jobId)); - MatcherAssert.assertThat(jobQueue.nextJobAndIncRunCount(true, null), is(nullValue())); + assertThat(jobQueue.nextJobAndIncRunCount(true, null).getId(), equalTo(jobId)); + assertThat(jobQueue.nextJobAndIncRunCount(true, null), is(nullValue())); jobQueue.remove(holder); - MatcherAssert.assertThat(jobQueue.nextJobAndIncRunCount(true, null), is(nullValue())); + assertThat(jobQueue.nextJobAndIncRunCount(true, null), is(nullValue())); } @Test @@ -300,15 +300,15 @@ public void testNetwork() throws Exception { JobQueue jobQueue = createNewJobQueue(); JobHolder jobHolder = createNewJobHolder(new Params(0)); jobQueue.insert(jobHolder); - MatcherAssert.assertThat("no network job should be returned even if there is no netowrk", + assertThat("no network job should be returned even if there is no netowrk", jobQueue.nextJobAndIncRunCount(false, null), notNullValue()); jobQueue.remove(jobHolder); jobHolder = createNewJobHolder(new Params(0).requireNetwork()); - MatcherAssert.assertThat("if there isn't any network, job with network requirement should not return", + assertThat("if there isn't any network, job with network requirement should not return", jobQueue.nextJobAndIncRunCount(false, null), nullValue()); - MatcherAssert.assertThat("if there is network, job with network requirement should be returned", + assertThat("if there is network, job with network requirement should be returned", jobQueue.nextJobAndIncRunCount(true, null), nullValue()); jobQueue.remove(jobHolder); @@ -318,17 +318,17 @@ public void testNetwork() throws Exception { long firstJobId = jobQueue.insert(jobHolder); long secondJobId = jobQueue.insert(jobHolder2); JobHolder retrieved = jobQueue.nextJobAndIncRunCount(false, null); - MatcherAssert.assertThat("one job should be returned w/o network", retrieved, notNullValue()); + assertThat("one job should be returned w/o network", retrieved, notNullValue()); if(retrieved != null) { - MatcherAssert.assertThat("no network job should be returned although it has lower priority", retrieved.getId(), equalTo(firstJobId)); + assertThat("no network job should be returned although it has lower priority", retrieved.getId(), equalTo(firstJobId)); } - MatcherAssert.assertThat("no other job should be returned w/o network", jobQueue.nextJobAndIncRunCount(false, null), nullValue()); + assertThat("no other job should be returned w/o network", jobQueue.nextJobAndIncRunCount(false, null), nullValue()); retrieved = jobQueue.nextJobAndIncRunCount(true, null); - MatcherAssert.assertThat("if network is back, network requiring job should be returned", retrieved, notNullValue()); + assertThat("if network is back, network requiring job should be returned", retrieved, notNullValue()); if(retrieved != null) { - MatcherAssert.assertThat("when there is network, network job should be returned", retrieved.getId(), equalTo(secondJobId)); + assertThat("when there is network, network job should be returned", retrieved.getId(), equalTo(secondJobId)); } //add first job back jobQueue.insertOrReplace(jobHolder); @@ -336,18 +336,18 @@ public void testNetwork() throws Exception { jobQueue.insertOrReplace(jobHolder2); retrieved = jobQueue.nextJobAndIncRunCount(true, null); - MatcherAssert.assertThat("if network is back, job w/ higher priority should be returned", retrieved, notNullValue()); + assertThat("if network is back, job w/ higher priority should be returned", retrieved, notNullValue()); if(retrieved != null) { - MatcherAssert.assertThat("if network is back, job w/ higher priority should be returned", retrieved.getId(), equalTo(secondJobId)); + assertThat("if network is back, job w/ higher priority should be returned", retrieved.getId(), equalTo(secondJobId)); } jobQueue.insertOrReplace(jobHolder2); JobHolder highestPriorityJob = createNewJobHolder(new Params(10)); long highestPriorityJobId = jobQueue.insert(highestPriorityJob); retrieved = jobQueue.nextJobAndIncRunCount(true, null); - MatcherAssert.assertThat("w/ or w/o network, highest priority should be returned", retrieved, notNullValue()); + assertThat("w/ or w/o network, highest priority should be returned", retrieved, notNullValue()); if(retrieved != null) { - MatcherAssert.assertThat("w/ or w/o network, highest priority should be returned", retrieved.getId(), equalTo(highestPriorityJobId)); + assertThat("w/ or w/o network, highest priority should be returned", retrieved.getId(), equalTo(highestPriorityJobId)); } //TODO test delay until @@ -356,40 +356,40 @@ public void testNetwork() throws Exception { @Test public void testCountReadyJobs() throws Exception { JobQueue jobQueue = createNewJobQueue(); - MatcherAssert.assertThat("initial count should be 0 for ready jobs", jobQueue.countReadyJobs(true, null), equalTo(0)); + assertThat("initial count should be 0 for ready jobs", jobQueue.countReadyJobs(true, null), equalTo(0)); //add some jobs jobQueue.insert(createNewJobHolder()); jobQueue.insert(createNewJobHolder(new Params(0).requireNetwork())); long now = System.nanoTime(); long delay = 1000; jobQueue.insert(createNewJobHolderWithDelayUntil(new Params(0), now + TimeUnit.MILLISECONDS.toNanos(delay))); - MatcherAssert.assertThat("ready count should be 1 if there is no network", jobQueue.countReadyJobs(false, null), equalTo(1)); - MatcherAssert.assertThat("ready count should be 2 if there is network", jobQueue.countReadyJobs(true, null), equalTo(2)); + assertThat("ready count should be 1 if there is no network", jobQueue.countReadyJobs(false, null), equalTo(1)); + assertThat("ready count should be 2 if there is network", jobQueue.countReadyJobs(true, null), equalTo(2)); Thread.sleep(delay); - MatcherAssert.assertThat("when needed delay time passes, ready count should be 3", jobQueue.countReadyJobs(true, null), equalTo(3)); - MatcherAssert.assertThat("when needed delay time passes but no network, ready count should be 2", jobQueue.countReadyJobs(false, null), equalTo(2)); + assertThat("when needed delay time passes, ready count should be 3", jobQueue.countReadyJobs(true, null), equalTo(3)); + assertThat("when needed delay time passes but no network, ready count should be 2", jobQueue.countReadyJobs(false, null), equalTo(2)); jobQueue.insert(createNewJobHolder(new Params(5).groupBy("group1"))); jobQueue.insert(createNewJobHolder(new Params(5).groupBy("group1"))); - MatcherAssert.assertThat("when more than 1 job from same group is created, ready jobs should increment only by 1", + assertThat("when more than 1 job from same group is created, ready jobs should increment only by 1", jobQueue.countReadyJobs(true, null), equalTo(4)); - MatcherAssert.assertThat("excluding groups should work", + assertThat("excluding groups should work", jobQueue.countReadyJobs(true, Arrays.asList(new String[]{"group1"})), equalTo(3)); - MatcherAssert.assertThat("giving a non-existing group should not fool the count", + assertThat("giving a non-existing group should not fool the count", jobQueue.countReadyJobs(true, Arrays.asList(new String[]{"group3423"})), equalTo(4)); jobQueue.insert(createNewJobHolder(new Params(3).groupBy("group2"))); - MatcherAssert.assertThat("when a job from another group is added, ready job count should inc", + assertThat("when a job from another group is added, ready job count should inc", jobQueue.countReadyJobs(true, null), equalTo(5)); now = System.nanoTime(); jobQueue.insert(createNewJobHolderWithDelayUntil(new Params(3).groupBy("group3"), now + TimeUnit.MILLISECONDS.toNanos(delay))); - MatcherAssert.assertThat("when a delayed job from another group is added, ready count should not change", + assertThat("when a delayed job from another group is added, ready count should not change", jobQueue.countReadyJobs(true, null), equalTo(5)); jobQueue.insert(createNewJobHolder(new Params(3).groupBy("group3"))); - MatcherAssert.assertThat("when another job from delayed group is added, ready job count should inc", + assertThat("when another job from delayed group is added, ready job count should inc", jobQueue.countReadyJobs(true, null), equalTo(6)); Thread.sleep(delay); - MatcherAssert.assertThat("when delay passes and a job from existing group becomes available, ready job count should not change", + assertThat("when delay passes and a job from existing group becomes available, ready job count should not change", jobQueue.countReadyJobs(true, null), equalTo(6)); - MatcherAssert.assertThat("when some groups are excluded, count should be correct", + assertThat("when some groups are excluded, count should be correct", jobQueue.countReadyJobs(true, Arrays.asList(new String[]{"group1", "group3"})), equalTo(4)); //jobs w/ same group id but with different persistence constraints should not fool the count @@ -398,11 +398,11 @@ public void testCountReadyJobs() throws Exception { jobQueue.insert(createNewJobHolderWithDelayUntil(new Params(0).groupBy("group10"), now + 1000)); jobQueue.insert(createNewJobHolderWithDelayUntil(new Params(0).persist().groupBy("group10"), now - 1000)); jobQueue.insert(createNewJobHolderWithDelayUntil(new Params(0).groupBy("group10"), now - 1000)); - MatcherAssert.assertThat("when many jobs are added w/ different constraints but same group id, ready count should not be fooled", + assertThat("when many jobs are added w/ different constraints but same group id, ready count should not be fooled", jobQueue.countReadyJobs(true, Arrays.asList(new String[]{"group1", "group3"})), equalTo(5)); - MatcherAssert.assertThat("when many jobs are added w/ different constraints but same group id, ready count should not be fooled", + assertThat("when many jobs are added w/ different constraints but same group id, ready count should not be fooled", jobQueue.countReadyJobs(true, null), equalTo(7)); - MatcherAssert.assertThat("when many jobs are added w/ different constraints but same group id, ready count should not be fooled", + assertThat("when many jobs are added w/ different constraints but same group id, ready count should not be fooled", jobQueue.countReadyJobs(false, Arrays.asList(new String[]{"group1", "group3"})), equalTo(4)); } @@ -425,14 +425,60 @@ public void testJobFields() throws Exception { for (int i = 0; i < 2; i++) { JobHolder received = jobQueue.nextJobAndIncRunCount(true, null); - MatcherAssert.assertThat("job id should be preserved", received.getId(), equalTo(id)); - MatcherAssert.assertThat("job priority should be preserved", received.getPriority(), equalTo(priority)); - MatcherAssert.assertThat("job session id should be assigned", received.getRunningSessionId(), equalTo(sessionId)); - MatcherAssert.assertThat("job run count should be incremented", received.getRunCount(), equalTo(runCount + i + 1)); + assertThat("job id should be preserved", received.getId(), equalTo(id)); + assertThat("job priority should be preserved", received.getPriority(), equalTo(priority)); + assertThat("job session id should be assigned", received.getRunningSessionId(), equalTo(sessionId)); + assertThat("job run count should be incremented", received.getRunCount(), equalTo(runCount + i + 1)); jobQueue.insertOrReplace(received); } } + private void assertJob(JobQueue jobQueue, String msg, long id, /*nullable*/ JobHolder holder) { + if(holder == null) { + assertThat(msg, jobQueue.findJobById(id), nullValue()); + return; + } + assertThat(msg + "(existence check)", jobQueue.findJobById(id), notNullValue()); + assertThat(msg + "(id check)", jobQueue.findJobById(id).getId(), is(holder.getId())); + } + + @Test + public void testFindJobHolderById() { + JobQueue jobQueue = createNewJobQueue(); + assertJob(jobQueue, "non existing job (negative id)", -4, null); + assertJob(jobQueue, "non existing job (positive id)", +4, null); + final int LIMIT = 10; + JobHolder[] holders = new JobHolder[LIMIT]; + long[] ids = new long[LIMIT]; + for(int i = 0; i < LIMIT; i++) { + holders[i] = createNewJobHolder(new Params((int) (Math.random() * 50)).setPersistent(Math.random() < .5).setRequiresNetwork(Math.random() < .5)); + ids[i] = jobQueue.insert(holders[i]); + assertJob(jobQueue, "job by id should work for inserted job", ids[i], holders[i]); + } + final int REMOVE_CNT = LIMIT / 2; + for(int i = 0; i < REMOVE_CNT; i++) { + int ind = (int) (Math.random() * LIMIT); + if(holders[ind] == null) { + continue; + } + //remove some randomly, up to half + jobQueue.remove(holders[ind]); + holders[ind] = null; + } + //re-query all, ensure we can still find non-removed jobs and not find removed jobs + for(int i = 0; i < LIMIT; i++) { + if(holders[i] != null) { + assertJob(jobQueue, "if job is still in the Q, it should be returned", ids[i], holders[i]); + //re add job + jobQueue.insertOrReplace(holders[i]); + //re-test after re-add + assertJob(jobQueue, "after re-insert, if job is still in the Q, it should be returned", ids[i], holders[i]); + } else { + assertJob(jobQueue, "removed job should not be returned in id query", ids[i], null); + } + } + } + protected JobHolder createNewJobHolder() { return createNewJobHolder(new Params(0)); } From 50b5c7a0324a88c108aff095519da696c2de86ad Mon Sep 17 00:00:00 2001 From: yigit Date: Wed, 22 Jan 2014 13:47:58 -0800 Subject: [PATCH 08/41] find by id implementation for sqlite queue and non-persistent queue --- .../jobqueue/nonPersistentQueue/JobSet.java | 1 + .../nonPersistentQueue/MergedQueue.java | 13 +++++++ .../NonPersistentJobSet.java | 35 +++++++++++++++---- .../NonPersistentPriorityQueue.java | 2 +- .../persistentQueue/sqlite/SqlHelper.java | 5 +++ .../sqlite/SqliteJobQueue.java | 27 +++++++++----- .../test/jobqueue/JobQueueTestBase.java | 6 +++- 7 files changed, 72 insertions(+), 17 deletions(-) diff --git a/jobqueue/src/com/path/android/jobqueue/nonPersistentQueue/JobSet.java b/jobqueue/src/com/path/android/jobqueue/nonPersistentQueue/JobSet.java index 2613245..b084a0e 100644 --- a/jobqueue/src/com/path/android/jobqueue/nonPersistentQueue/JobSet.java +++ b/jobqueue/src/com/path/android/jobqueue/nonPersistentQueue/JobSet.java @@ -11,6 +11,7 @@ public interface JobSet { public JobHolder peek(Collection excludeGroupIds); public JobHolder poll(Collection excludeGroupIds); + public JobHolder findById(long id); public boolean offer(JobHolder holder); public boolean remove(JobHolder holder); public void clear(); diff --git a/jobqueue/src/com/path/android/jobqueue/nonPersistentQueue/MergedQueue.java b/jobqueue/src/com/path/android/jobqueue/nonPersistentQueue/MergedQueue.java index 4df0fef..f32fd7c 100644 --- a/jobqueue/src/com/path/android/jobqueue/nonPersistentQueue/MergedQueue.java +++ b/jobqueue/src/com/path/android/jobqueue/nonPersistentQueue/MergedQueue.java @@ -201,6 +201,19 @@ public CountWithGroupIdsResult countReadyJobs(SetId setId, Collection ex } } + + + /** + * Returns the JobHolder that has the given id + * @param id id job the job + * @return + */ + @Override + public JobHolder findById(long id) { + JobHolder q0 = queue0.findById(id); + return q0 == null ? queue1.findById(id) : q0; + } + /** * simple enum to identify queues */ diff --git a/jobqueue/src/com/path/android/jobqueue/nonPersistentQueue/NonPersistentJobSet.java b/jobqueue/src/com/path/android/jobqueue/nonPersistentQueue/NonPersistentJobSet.java index c178453..aec9272 100644 --- a/jobqueue/src/com/path/android/jobqueue/nonPersistentQueue/NonPersistentJobSet.java +++ b/jobqueue/src/com/path/android/jobqueue/nonPersistentQueue/NonPersistentJobSet.java @@ -3,7 +3,13 @@ import com.path.android.jobqueue.JobHolder; import com.path.android.jobqueue.log.JqLog; -import java.util.*; +import java.util.Collection; +import java.util.Comparator; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Map; +import java.util.Set; +import java.util.TreeSet; /** * This is the default implementation of JobSet. @@ -11,13 +17,15 @@ * version */ public class NonPersistentJobSet implements JobSet { - TreeSet set; + private final TreeSet set; //groupId -> # of jobs in that group - Map existingGroups; + private final Map existingGroups; + private final Map idCache; public NonPersistentJobSet(Comparator comparator) { this.set = new TreeSet(comparator); this.existingGroups = new HashMap(); + this.idCache = new HashMap(); } private JobHolder safeFirst() { @@ -62,6 +70,11 @@ public JobHolder poll(Collection excludeGroupIds) { return peek; } + @Override + public JobHolder findById(long id) { + return idCache.get(id); + } + @Override public boolean offer(JobHolder holder) { if(holder.getId() == null) { @@ -73,9 +86,13 @@ public boolean offer(JobHolder holder) { remove(holder); result = set.add(holder); } - if(result && holder.getGroupId() != null) { - incGroupCount(holder.getGroupId()); + if(result) { + idCache.put(holder.getId(), holder); + if(holder.getGroupId() != null) { + incGroupCount(holder.getGroupId()); + } } + return result; } @@ -103,8 +120,11 @@ private void decGroupCount(String groupId) { @Override public boolean remove(JobHolder holder) { boolean removed = set.remove(holder); - if(removed && holder.getGroupId() != null) { - decGroupCount(holder.getGroupId()); + if(removed) { + idCache.remove(holder.getId()); + if(holder.getGroupId() != null) { + decGroupCount(holder.getGroupId()); + } } return removed; } @@ -115,6 +135,7 @@ public boolean remove(JobHolder holder) { public void clear() { set.clear(); existingGroups.clear(); + idCache.clear(); } @Override diff --git a/jobqueue/src/com/path/android/jobqueue/nonPersistentQueue/NonPersistentPriorityQueue.java b/jobqueue/src/com/path/android/jobqueue/nonPersistentQueue/NonPersistentPriorityQueue.java index 503101b..627d09b 100644 --- a/jobqueue/src/com/path/android/jobqueue/nonPersistentQueue/NonPersistentPriorityQueue.java +++ b/jobqueue/src/com/path/android/jobqueue/nonPersistentQueue/NonPersistentPriorityQueue.java @@ -104,7 +104,7 @@ public void clear() { */ @Override public JobHolder findJobById(long id) { - return null; + return jobs.findById(id); } public final Comparator jobComparator = new Comparator() { diff --git a/jobqueue/src/com/path/android/jobqueue/persistentQueue/sqlite/SqlHelper.java b/jobqueue/src/com/path/android/jobqueue/persistentQueue/sqlite/SqlHelper.java index ad5d689..50e3ad7 100644 --- a/jobqueue/src/com/path/android/jobqueue/persistentQueue/sqlite/SqlHelper.java +++ b/jobqueue/src/com/path/android/jobqueue/persistentQueue/sqlite/SqlHelper.java @@ -8,6 +8,9 @@ * Helper class for {@link SqliteJobQueue} to generate sql queries and statements. */ public class SqlHelper { + + /**package**/ String FIND_BY_ID_QUERY; + private SQLiteStatement insertStatement; private SQLiteStatement insertOrReplaceStatement; private SQLiteStatement deleteStatement; @@ -16,6 +19,7 @@ public class SqlHelper { private SQLiteStatement nextJobDelayedUntilWithNetworkStatement; private SQLiteStatement nextJobDelayedUntilWithoutNetworkStatement; + final SQLiteDatabase db; final String tableName; final String primaryKeyColumnName; @@ -28,6 +32,7 @@ public SqlHelper(SQLiteDatabase db, String tableName, String primaryKeyColumnNam this.columnCount = columnCount; this.primaryKeyColumnName = primaryKeyColumnName; this.sessionId = sessionId; + FIND_BY_ID_QUERY = "SELECT * FROM " + tableName + " WHERE " + DbOpenHelper.ID_COLUMN.columnName + " = ?"; } public static String create(String tableName, Property primaryKey, Property... properties) { diff --git a/jobqueue/src/com/path/android/jobqueue/persistentQueue/sqlite/SqliteJobQueue.java b/jobqueue/src/com/path/android/jobqueue/persistentQueue/sqlite/SqliteJobQueue.java index af6153e..eefc667 100644 --- a/jobqueue/src/com/path/android/jobqueue/persistentQueue/sqlite/SqliteJobQueue.java +++ b/jobqueue/src/com/path/android/jobqueue/persistentQueue/sqlite/SqliteJobQueue.java @@ -159,6 +159,25 @@ public int countReadyJobs(boolean hasNetwork, Collection excludeGroups) } } + /** + * {@inheritDoc} + */ + @Override + public JobHolder findJobById(long id) { + Cursor cursor = db.rawQuery(sqlHelper.FIND_BY_ID_QUERY, new String[]{Long.toString(id)}); + try { + if(!cursor.moveToFirst()) { + return null; + } + return createJobHolderFromCursor(cursor); + } catch (InvalidBaseJobException e) { + JqLog.e(e, "invalid job on findJobById"); + return null; + } finally { + cursor.close(); + } + } + /** * {@inheritDoc} */ @@ -256,14 +275,6 @@ public void clear() { nextJobsQueryCache.clear(); } - /** - * {@inheritDoc} - */ - @Override - public JobHolder findJobById(long id) { - return null; - } - private void onJobFetchedForRunning(JobHolder jobHolder) { SQLiteStatement stmt = sqlHelper.getOnJobFetchedForRunningStatement(); jobHolder.setRunCount(jobHolder.getRunCount() + 1); diff --git a/jobqueue/test/com/path/android/jobqueue/test/jobqueue/JobQueueTestBase.java b/jobqueue/test/com/path/android/jobqueue/test/jobqueue/JobQueueTestBase.java index 73797d3..2805e54 100644 --- a/jobqueue/test/com/path/android/jobqueue/test/jobqueue/JobQueueTestBase.java +++ b/jobqueue/test/com/path/android/jobqueue/test/jobqueue/JobQueueTestBase.java @@ -447,7 +447,7 @@ public void testFindJobHolderById() { JobQueue jobQueue = createNewJobQueue(); assertJob(jobQueue, "non existing job (negative id)", -4, null); assertJob(jobQueue, "non existing job (positive id)", +4, null); - final int LIMIT = 10; + final int LIMIT = 100; JobHolder[] holders = new JobHolder[LIMIT]; long[] ids = new long[LIMIT]; for(int i = 0; i < LIMIT; i++) { @@ -477,6 +477,10 @@ public void testFindJobHolderById() { assertJob(jobQueue, "removed job should not be returned in id query", ids[i], null); } } + jobQueue.clear(); + for(int i = 0; i < LIMIT; i++) { + assertJob(jobQueue, "after clear, find by id should return null", ids[i], null); + } } protected JobHolder createNewJobHolder() { From a9567ff591ed015b831c2febb83303d9456db7a9 Mon Sep 17 00:00:00 2001 From: yigit Date: Wed, 22 Jan 2014 14:32:47 -0800 Subject: [PATCH 09/41] job status failing test case #18 --- .../com/path/android/jobqueue/JobStatus.java | 2 +- .../test/jobmanager/JobManagerTestBase.java | 29 ++++++ .../test/jobmanager/JobStatusTest.java | 95 +++++++++++++++++++ 3 files changed, 125 insertions(+), 1 deletion(-) create mode 100644 jobqueue/test/com/path/android/jobqueue/test/jobmanager/JobStatusTest.java diff --git a/jobqueue/src/com/path/android/jobqueue/JobStatus.java b/jobqueue/src/com/path/android/jobqueue/JobStatus.java index 42cdd72..26c6063 100644 --- a/jobqueue/src/com/path/android/jobqueue/JobStatus.java +++ b/jobqueue/src/com/path/android/jobqueue/JobStatus.java @@ -31,5 +31,5 @@ public enum JobStatus { *
*

*/ - DOES_NOT_EXISTS + UNKNOWN } diff --git a/jobqueue/test/com/path/android/jobqueue/test/jobmanager/JobManagerTestBase.java b/jobqueue/test/com/path/android/jobqueue/test/jobmanager/JobManagerTestBase.java index b44fc39..d416b76 100644 --- a/jobqueue/test/com/path/android/jobqueue/test/jobmanager/JobManagerTestBase.java +++ b/jobqueue/test/com/path/android/jobqueue/test/jobmanager/JobManagerTestBase.java @@ -32,6 +32,31 @@ protected JobManager createJobManager(Configuration.Builder configurationBuilder + protected static class DummyTwoLatchJob extends DummyJob { + private final CountDownLatch waitFor; + private final CountDownLatch trigger; + private final CountDownLatch onRunLatch; + + protected DummyTwoLatchJob(Params params, CountDownLatch waitFor, CountDownLatch trigger) { + super(params); + this.waitFor = waitFor; + this.trigger = trigger; + onRunLatch = new CountDownLatch(1); + } + + public void waitTillOnRun() throws InterruptedException { + onRunLatch.await(); + } + + @Override + public void onRun() throws Throwable { + onRunLatch.countDown(); + waitFor.await(); + super.onRun(); + trigger.countDown(); + } + } + protected static class DummyLatchJob extends DummyJob { private final CountDownLatch latch; @@ -108,6 +133,10 @@ public boolean isConnected(Context context) { public void setListener(Listener listener) { this.listener = listener; } + + public boolean isConnected() { + return hasNetwork; + } } protected static class ObjectReference { diff --git a/jobqueue/test/com/path/android/jobqueue/test/jobmanager/JobStatusTest.java b/jobqueue/test/com/path/android/jobqueue/test/jobmanager/JobStatusTest.java new file mode 100644 index 0000000..819ed4b --- /dev/null +++ b/jobqueue/test/com/path/android/jobqueue/test/jobmanager/JobStatusTest.java @@ -0,0 +1,95 @@ +package com.path.android.jobqueue.test.jobmanager; + +import com.path.android.jobqueue.Job; +import com.path.android.jobqueue.JobManager; +import com.path.android.jobqueue.JobStatus; +import com.path.android.jobqueue.Params; +import com.path.android.jobqueue.config.Configuration; +import com.path.android.jobqueue.test.jobs.DummyJob; +import static org.hamcrest.CoreMatchers.*; +import static org.hamcrest.MatcherAssert.*; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.robolectric.*; + +import java.util.ArrayList; +import java.util.List; +import java.util.concurrent.CountDownLatch; + +@RunWith(RobolectricTestRunner.class) +public class JobStatusTest extends JobManagerTestBase { + @Test + public void testJobStatus() throws InterruptedException { + DummyNetworkUtilWithConnectivityEventSupport networkUtil = new DummyNetworkUtilWithConnectivityEventSupport(); + networkUtil.setHasNetwork(false, true); + JobManager jobManager = createJobManager(new Configuration.Builder(Robolectric.application).networkUtil(networkUtil)); + jobManager.stop(); + List networkRequiringJobIndices = new ArrayList(); + Job[] jobs = new Job[] { + new DummyJob(new Params(0)), + new DummyJob(new Params(0).persist()), + new DummyJob(new Params(0).persist().requireNetwork()) + }; + long[] ids = new long[jobs.length]; + for(int i = 0; i < jobs.length; i ++) { + ids[i] = jobManager.addJob(jobs[i]); + if(jobs[i].requiresNetwork()) { + networkRequiringJobIndices.add(i); + } + JobStatus expectedStatus = (networkUtil.isConnected() || jobs[i].requiresNetwork() == false) ? JobStatus.WAITING_READY : + JobStatus.WAITING_NOT_READY; + assertThat("job should have correct status after being added", + jobManager.getJobStatus(ids[i], jobs[i].isPersistent()), is(expectedStatus)); + } + + //create an unknown id, ensure status for that + + boolean exists; + long unknownId; + do { + unknownId = (long) (Math.random() * 10000 - 5000); + exists = false; + for(long id : ids) { + if(id == unknownId) { + exists = true; + continue; + } + } + } while (exists); + for(boolean persistent : new boolean[]{true, false}) { + assertThat("job with unknown id should return as expected", jobManager.getJobStatus(unknownId, persistent), is(JobStatus.UNKNOWN)); + } + + CountDownLatch startLatch = new CountDownLatch(1), endLatch = new CountDownLatch(1); + DummyTwoLatchJob twoLatchJob = new DummyTwoLatchJob(new Params(0), startLatch, endLatch); + jobManager.start(); + long jobId = jobManager.addJob(twoLatchJob); + twoLatchJob.waitTillOnRun(); + assertThat("job should be in running state", jobManager.getJobStatus(jobId, false), is(JobStatus.RUNNING)); + startLatch.countDown();//let it run + endLatch.await();//wait till it finishes + Thread.sleep(500);//give some time to job manager to clear the job + assertThat("finished job should go to unknown state", jobManager.getJobStatus(jobId, false), is(JobStatus.UNKNOWN)); + + //network requiring job should not be ready + for(Integer i : networkRequiringJobIndices) { + assertThat("network requiring job should still be not-ready", jobManager.getJobStatus(ids[i], jobs[i].isPersistent()), is(JobStatus.WAITING_NOT_READY)); + } + jobManager.stop(); + networkUtil.setHasNetwork(true, true); + for(Integer i : networkRequiringJobIndices) { + assertThat("network requiring job should still be ready after network is there", jobManager.getJobStatus(ids[i], jobs[i].isPersistent()), is(JobStatus.WAITING_READY)); + } + + jobManager.start(); + int limit = 10; + while (jobManager.count() > 0 && limit-- > 0) { + Thread.sleep(1000); + } + assertThat("jobs should finish", jobManager.count(), is(0)); + for(int i = 0; i < jobs.length; i ++) { + //after all jobs finish, state should be unknown + assertThat("all jobs finished, states should be unknown", jobManager.getJobStatus(ids[i], jobs[i].isPersistent()), is(JobStatus.UNKNOWN)); + } + } +} From eb09552d34fe8287ee965b623d084a43bd13f681 Mon Sep 17 00:00:00 2001 From: yigit Date: Wed, 22 Jan 2014 16:36:24 -0800 Subject: [PATCH 10/41] job status implementation #18 --- .../com/path/android/jobqueue/JobManager.java | 31 ++++++++++++++- .../com/path/android/jobqueue/JobStatus.java | 1 + .../executor/JobConsumerExecutor.java | 39 ++++++++++++++++--- .../test/jobmanager/JobStatusTest.java | 24 ++++++++++++ 4 files changed, 88 insertions(+), 7 deletions(-) diff --git a/jobqueue/src/com/path/android/jobqueue/JobManager.java b/jobqueue/src/com/path/android/jobqueue/JobManager.java index 0c64f06..ad1ae8b 100644 --- a/jobqueue/src/com/path/android/jobqueue/JobManager.java +++ b/jobqueue/src/com/path/android/jobqueue/JobManager.java @@ -304,14 +304,41 @@ private void reAddJob(JobHolder jobHolder) { } /** - * returns the current status of a {@link Job} + * Returns the current status of a {@link Job}. + *

+ * You should not call this method on UI thread because it may make a db request. + *

* @param id the ID, returned by the addJob method * @param isPersistent Jobs are added to different queues depending on if they are persistent or not. This is necessary * because each queue has independent id sets. * @return */ public JobStatus getJobStatus(long id, boolean isPersistent) { - return null; + if(jobConsumerExecutor.isRunning(id, isPersistent)) { + return JobStatus.RUNNING; + } + JobHolder holder; + if(isPersistent) { + synchronized (persistentJobQueue) { + holder = persistentJobQueue.findJobById(id); + } + } else { + synchronized (nonPersistentJobQueue) { + holder = nonPersistentJobQueue.findJobById(id); + } + } + if(holder == null) { + return JobStatus.UNKNOWN; + } + boolean network = hasNetwork(); + if(holder.requiresNetwork() && !network) { + return JobStatus.WAITING_NOT_READY; + } + if(holder.getDelayUntilNs() > System.nanoTime()) { + return JobStatus.WAITING_NOT_READY; + } + + return JobStatus.WAITING_READY; } private void removeJob(JobHolder jobHolder) { diff --git a/jobqueue/src/com/path/android/jobqueue/JobStatus.java b/jobqueue/src/com/path/android/jobqueue/JobStatus.java index 26c6063..4864411 100644 --- a/jobqueue/src/com/path/android/jobqueue/JobStatus.java +++ b/jobqueue/src/com/path/android/jobqueue/JobStatus.java @@ -9,6 +9,7 @@ public enum JobStatus { * As of v 1.1, this might be: *
    *
  • Job requires network but there is no available network connection
  • + *
  • Job is delayed. We are waiting for the time to pass
  • *
*/ WAITING_NOT_READY, diff --git a/jobqueue/src/com/path/android/jobqueue/executor/JobConsumerExecutor.java b/jobqueue/src/com/path/android/jobqueue/executor/JobConsumerExecutor.java index 2334f62..0d080a0 100644 --- a/jobqueue/src/com/path/android/jobqueue/executor/JobConsumerExecutor.java +++ b/jobqueue/src/com/path/android/jobqueue/executor/JobConsumerExecutor.java @@ -6,6 +6,7 @@ import com.path.android.jobqueue.config.Configuration; import com.path.android.jobqueue.log.JqLog; +import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicInteger; @@ -21,7 +22,8 @@ public class JobConsumerExecutor { private final Contract contract; private final int keepAliveSeconds; private final AtomicInteger activeConsumerCount = new AtomicInteger(0); - private final AtomicInteger runningJobCount = new AtomicInteger(0); + // key : id + (isPersistent) + private final ConcurrentHashMap runningJobHolders; public JobConsumerExecutor(Configuration config, Contract contract) { @@ -31,6 +33,7 @@ public JobConsumerExecutor(Configuration config, Contract contract) { this.keepAliveSeconds = config.getConsumerKeepAlive(); this.contract = contract; threadGroup = new ThreadGroup("JobConsumers"); + runningJobHolders = new ConcurrentHashMap(); } /** @@ -92,17 +95,43 @@ private boolean isAboveLoadFactor(boolean inConsumerThread) { int consumerCnt = activeConsumerCount.intValue() - (inConsumerThread ? 1 : 0); boolean res = consumerCnt < minConsumerSize || - consumerCnt * loadFactor < contract.countRemainingReadyJobs() + runningJobCount.get(); + consumerCnt * loadFactor < contract.countRemainingReadyJobs() + runningJobHolders.size(); if(JqLog.isDebugEnabled()) { JqLog.d("%s: load factor check. %s = (%d < %d)|| (%d * %d < %d + %d). consumer thread: %s", Thread.currentThread().getName(), res, consumerCnt, minConsumerSize, - consumerCnt, loadFactor, contract.countRemainingReadyJobs(), runningJobCount.get(), inConsumerThread); + consumerCnt, loadFactor, contract.countRemainingReadyJobs(), runningJobHolders.size(), inConsumerThread); } return res; } } + private void onBeforeRun(JobHolder jobHolder) { + runningJobHolders.put(createrunningJobHolderKey(jobHolder), jobHolder); + } + + private void onAfterRun(JobHolder jobHolder) { + runningJobHolders.remove(createrunningJobHolderKey(jobHolder)); + } + + private String createrunningJobHolderKey(JobHolder jobHolder) { + return createrunningJobHolderKey(jobHolder.getId(), jobHolder.getBaseJob().isPersistent()); + } + + private String createrunningJobHolderKey(long id, boolean isPersistent) { + return id + "_" + (isPersistent ? "t" : "f"); + } + + /** + * returns true if job is currently handled by one of the executor threads + * @param id id of the job + * @param persistent boolean flag to distinguish id conflicts + * @return true if job is currently handled here + */ + public boolean isRunning(long id, boolean persistent) { + return runningJobHolders.containsKey(createrunningJobHolderKey(id, persistent)); + } + /** * contract between the {@link JobManager} and {@link JobConsumerExecutor} */ @@ -168,13 +197,13 @@ public void run() { do { nextJob = contract.isRunning() ? contract.getNextJob(executor.keepAliveSeconds, TimeUnit.SECONDS) : null; if (nextJob != null) { - executor.runningJobCount.incrementAndGet(); + executor.onBeforeRun(nextJob); if (nextJob.safeRun(nextJob.getRunCount())) { contract.removeJob(nextJob); } else { contract.insertOrReplace(nextJob); } - executor.runningJobCount.decrementAndGet(); + executor.onAfterRun(nextJob); } } while (nextJob != null); } finally { diff --git a/jobqueue/test/com/path/android/jobqueue/test/jobmanager/JobStatusTest.java b/jobqueue/test/com/path/android/jobqueue/test/jobmanager/JobStatusTest.java index 819ed4b..28656ba 100644 --- a/jobqueue/test/com/path/android/jobqueue/test/jobmanager/JobStatusTest.java +++ b/jobqueue/test/com/path/android/jobqueue/test/jobmanager/JobStatusTest.java @@ -91,5 +91,29 @@ public void testJobStatus() throws InterruptedException { //after all jobs finish, state should be unknown assertThat("all jobs finished, states should be unknown", jobManager.getJobStatus(ids[i], jobs[i].isPersistent()), is(JobStatus.UNKNOWN)); } + final long SHORT_SLEEP = 1000; + Job[] delayedJobs = new Job[]{ + new DummyJob(new Params(0).delayInMs(SHORT_SLEEP)), + new DummyJob(new Params(0).delayInMs(SHORT_SLEEP).persist()), + new DummyJob(new Params(0).delayInMs(SHORT_SLEEP * 10)), + new DummyJob(new Params(0).delayInMs(SHORT_SLEEP * 10).persist())}; + long[] delayedIds = new long[delayedJobs.length]; + for(int i = 0; i < delayedJobs.length; i ++) { + delayedIds[i] = jobManager.addJob(delayedJobs[i]); + } + + for(int i = 0; i < delayedJobs.length; i ++) { + assertThat("delayed job(" + i + ") should receive not ready status", jobManager.getJobStatus(delayedIds[i], delayedJobs[i].isPersistent()), is(JobStatus.WAITING_NOT_READY)); + } + jobManager.stop(); + //sleep + Thread.sleep(SHORT_SLEEP * 2); + for(int i = 0; i < delayedJobs.length; i ++) { + if(delayedJobs[i].getDelayInMs() == SHORT_SLEEP) { + assertThat("when enough time passes, delayed jobs should move to ready state", jobManager.getJobStatus(delayedIds[i], delayedJobs[i].isPersistent()), is(JobStatus.WAITING_READY)); + } else { + assertThat("delayed job should receive not ready status until their time comes", jobManager.getJobStatus(delayedIds[i], delayedJobs[i].isPersistent()), is(JobStatus.WAITING_NOT_READY)); + } + } } } From 52a9bab971319b0c539651b6f702d71de1550e08 Mon Sep 17 00:00:00 2001 From: yigit Date: Wed, 22 Jan 2014 18:22:05 -0800 Subject: [PATCH 11/41] query interface test for delayed jobs. #18 --- .../com/path/android/jobqueue/JobManager.java | 4 ++ .../test/jobmanager/AddInBackgroundTest.java | 50 ++++++++++++++++--- 2 files changed, 46 insertions(+), 8 deletions(-) diff --git a/jobqueue/src/com/path/android/jobqueue/JobManager.java b/jobqueue/src/com/path/android/jobqueue/JobManager.java index ad1ae8b..d70182c 100644 --- a/jobqueue/src/com/path/android/jobqueue/JobManager.java +++ b/jobqueue/src/com/path/android/jobqueue/JobManager.java @@ -308,6 +308,10 @@ private void reAddJob(JobHolder jobHolder) { *

* You should not call this method on UI thread because it may make a db request. *

+ *

+ * This is not a very fast call so try not to make it unless necessary. Consider using events if you need to be + * informed about a job's lifecycle. + *

* @param id the ID, returned by the addJob method * @param isPersistent Jobs are added to different queues depending on if they are persistent or not. This is necessary * because each queue has independent id sets. diff --git a/jobqueue/test/com/path/android/jobqueue/test/jobmanager/AddInBackgroundTest.java b/jobqueue/test/com/path/android/jobqueue/test/jobmanager/AddInBackgroundTest.java index 20be3a3..454d3c5 100644 --- a/jobqueue/test/com/path/android/jobqueue/test/jobmanager/AddInBackgroundTest.java +++ b/jobqueue/test/com/path/android/jobqueue/test/jobmanager/AddInBackgroundTest.java @@ -1,8 +1,14 @@ package com.path.android.jobqueue.test.jobmanager; +import com.path.android.jobqueue.AsyncAddCallback; +import com.path.android.jobqueue.BaseJob; import com.path.android.jobqueue.Job; +import com.path.android.jobqueue.JobHolder; +import com.path.android.jobqueue.JobManager; +import com.path.android.jobqueue.JobQueue; import com.path.android.jobqueue.Params; import com.path.android.jobqueue.test.jobs.DummyJob; +import org.fest.reflect.core.*; import org.hamcrest.*; import org.junit.Test; import org.junit.runner.RunWith; @@ -14,15 +20,19 @@ @RunWith(RobolectricTestRunner.class) public class AddInBackgroundTest extends JobManagerTestBase { @Test - public void testAddInBackground() { - addInBackground(false); - addInBackground(true); - + public void testAddInBackground() throws InterruptedException { + for(boolean delay : new boolean[]{true, false}) { + for(boolean useCallback : new boolean[]{true, false}) { + addInBackground(delay, useCallback); + } + } } - public void addInBackground(boolean delayed) { + + public void addInBackground(boolean delayed, boolean useCallback) throws InterruptedException { long currentThreadId = Thread.currentThread().getId(); final AtomicLong onAddedThreadId = new AtomicLong(); final CountDownLatch addedLatch = new CountDownLatch(2); + Job dummyJob = new DummyJob(new Params(1).setDelayMs(delayed ? 1000 : 0)) { @Override public void onAdded() { @@ -31,9 +41,33 @@ public void onAdded() { addedLatch.countDown(); } }; - createJobManager().addJobInBackground(dummyJob); - - addedLatch.countDown(); + JobManager jobManager = createJobManager(); + jobManager.stop(); + final AtomicLong jobId = new AtomicLong(0); + if(useCallback) { + jobManager.addJobInBackground(dummyJob, new AsyncAddCallback() { + @Override + public void onAdded(long id) { + jobId.set(id); + addedLatch.countDown(); + } + }); + } else { + addedLatch.countDown(); + jobManager.addJobInBackground(dummyJob); + } + addedLatch.await(); MatcherAssert.assertThat("thread ids should be different. delayed:" + delayed, currentThreadId, CoreMatchers.not(onAddedThreadId.get())); + if(useCallback) { + JobQueue queue = getNonPersistentQueue(jobManager); + JobHolder holder = queue.findJobById(jobId.longValue()); + MatcherAssert.assertThat("there should be a job in the holder. id:" + jobId.longValue() +", delayed:" + delayed + ", use cb:" + useCallback + , holder, CoreMatchers.notNullValue()); + MatcherAssert.assertThat("id callback should have the proper id:", holder.getBaseJob(), CoreMatchers.is((BaseJob) dummyJob)); + } + } + + protected JobQueue getNonPersistentQueue(JobManager jobManager) { + return Reflection.field("nonPersistentJobQueue").ofType(JobQueue.class).in(jobManager).get(); } } From bd0d0740d76201042031d5ec25df60743d70dc5a Mon Sep 17 00:00:00 2001 From: yigit Date: Tue, 28 Jan 2014 13:52:06 -0800 Subject: [PATCH 12/41] review changes --- examples/twitter/TwitterClient/build.gradle | 2 +- jobqueue/AndroidManifest.xml | 2 +- .../src/com/path/android/jobqueue/JobManager.java | 2 +- .../src/com/path/android/jobqueue/JobStatus.java | 2 +- .../jobqueue/executor/JobConsumerExecutor.java | 12 ++++++------ 5 files changed, 10 insertions(+), 10 deletions(-) diff --git a/examples/twitter/TwitterClient/build.gradle b/examples/twitter/TwitterClient/build.gradle index defa741..d5d7bad 100644 --- a/examples/twitter/TwitterClient/build.gradle +++ b/examples/twitter/TwitterClient/build.gradle @@ -54,7 +54,7 @@ android { dependencies { compile 'de.greenrobot:eventbus:2.1.0-beta-1' compile 'org.twitter4j:twitter4j-core:3.0.3' - compile 'com.path:android-priority-jobqueue:1.0-SNAPSHOT' + compile 'com.path:android-priority-jobqueue:1.1-SNAPSHOT' compile files('external-libs/greenDAO.jar') } diff --git a/jobqueue/AndroidManifest.xml b/jobqueue/AndroidManifest.xml index 29eff0d..604d7e6 100644 --- a/jobqueue/AndroidManifest.xml +++ b/jobqueue/AndroidManifest.xml @@ -2,7 +2,7 @@ + android:versionName="1.1-SNAPSHOT"> diff --git a/jobqueue/src/com/path/android/jobqueue/JobManager.java b/jobqueue/src/com/path/android/jobqueue/JobManager.java index d70182c..4c795a9 100644 --- a/jobqueue/src/com/path/android/jobqueue/JobManager.java +++ b/jobqueue/src/com/path/android/jobqueue/JobManager.java @@ -306,7 +306,7 @@ private void reAddJob(JobHolder jobHolder) { /** * Returns the current status of a {@link Job}. *

- * You should not call this method on UI thread because it may make a db request. + * You should not call this method on the UI thread because it may make a db request. *

*

* This is not a very fast call so try not to make it unless necessary. Consider using events if you need to be diff --git a/jobqueue/src/com/path/android/jobqueue/JobStatus.java b/jobqueue/src/com/path/android/jobqueue/JobStatus.java index 4864411..b687cc3 100644 --- a/jobqueue/src/com/path/android/jobqueue/JobStatus.java +++ b/jobqueue/src/com/path/android/jobqueue/JobStatus.java @@ -22,7 +22,7 @@ public enum JobStatus { */ RUNNING, /** - * Job is not know by job queue. + * Job is not known by job queue. *

This might be: *