From 306da92031aaa0c635ea2e7afdff641d74d64444 Mon Sep 17 00:00:00 2001 From: agrajaghh Date: Fri, 24 Oct 2014 03:29:29 +0200 Subject: [PATCH] Test case and fix for deferred jobs. Closes #2033 --- .../jobqueue/JobManagerTest.java | 83 ++++++++++++++++--- .../jobs/RequirementDeferringTestJob.java | 51 ++++++++++++ .../whispersystems/jobqueue/jobs/TestJob.java | 12 +-- .../jobqueue/util/RunnableThrowable.java | 8 ++ .../whispersystems/jobqueue/JobConsumer.java | 2 + 5 files changed, 140 insertions(+), 16 deletions(-) create mode 100644 jobqueue/src/androidTest/java/org/whispersystems/jobqueue/jobs/RequirementDeferringTestJob.java create mode 100644 jobqueue/src/androidTest/java/org/whispersystems/jobqueue/util/RunnableThrowable.java diff --git a/jobqueue/src/androidTest/java/org/whispersystems/jobqueue/JobManagerTest.java b/jobqueue/src/androidTest/java/org/whispersystems/jobqueue/JobManagerTest.java index 448cfb4fa9..db8bdb9906 100644 --- a/jobqueue/src/androidTest/java/org/whispersystems/jobqueue/JobManagerTest.java +++ b/jobqueue/src/androidTest/java/org/whispersystems/jobqueue/JobManagerTest.java @@ -3,6 +3,7 @@ package org.whispersystems.jobqueue; import android.test.AndroidTestCase; import org.whispersystems.jobqueue.jobs.PersistentTestJob; +import org.whispersystems.jobqueue.jobs.RequirementDeferringTestJob; import org.whispersystems.jobqueue.jobs.RequirementTestJob; import org.whispersystems.jobqueue.jobs.TestJob; import org.whispersystems.jobqueue.persistence.JavaJobSerializer; @@ -11,12 +12,15 @@ import org.whispersystems.jobqueue.util.MockRequirementProvider; import org.whispersystems.jobqueue.util.PersistentMockRequirement; import org.whispersystems.jobqueue.util.PersistentRequirement; import org.whispersystems.jobqueue.util.PersistentResult; +import org.whispersystems.jobqueue.util.RunnableThrowable; + +import java.io.IOException; public class JobManagerTest extends AndroidTestCase { public void testTransientJobExecution() throws InterruptedException { - TestJob testJob = new TestJob(); - JobManager jobManager = new JobManager(getContext(), "transient-test", null, null, 1); + TestJob testJob = new TestJob(); + JobManager jobManager = new JobManager(getContext(), "transient-test", null, null, 1); jobManager.add(testJob); @@ -25,10 +29,11 @@ public class JobManagerTest extends AndroidTestCase { } public void testTransientRequirementJobExecution() throws InterruptedException { - MockRequirementProvider provider = new MockRequirementProvider(); - MockRequirement requirement = new MockRequirement(false); - TestJob testJob = new RequirementTestJob(requirement); - JobManager jobManager = new JobManager(getContext(), "transient-requirement-test", provider, null, 1); + MockRequirementProvider provider = new MockRequirementProvider(); + MockRequirement requirement = new MockRequirement(false); + TestJob testJob = new RequirementTestJob(requirement); + JobManager jobManager = new JobManager(getContext(), "transient-requirement-test", + provider, null, 1); jobManager.add(testJob); @@ -39,13 +44,70 @@ public class JobManagerTest extends AndroidTestCase { provider.fireChange(); assertTrue(testJob.isRan()); + } + public void testTransientRequirementDeferringJobExecution() throws InterruptedException { + final Object lock = new Object(); + + RunnableThrowable waitRunnable = new RunnableThrowable() { + public Boolean shouldThrow = false; + + @Override + public void run() throws Exception { + try { + synchronized (lock) { + lock.wait(); + + if (shouldThrow) { + throw new Exception(); + } + } + } catch (InterruptedException e) { + throw new AssertionError(e); + } + } + @Override + public void shouldThrow(Boolean value) { + shouldThrow = value; + } + }; + + MockRequirementProvider provider = new MockRequirementProvider(); + MockRequirement requirement = new MockRequirement(false); + RequirementDeferringTestJob testJob = new RequirementDeferringTestJob(requirement, 5, waitRunnable); + JobManager jobManager = new JobManager(getContext(), "transient-requirement-test", + provider, null, 1); + + jobManager.add(testJob); + + waitRunnable.shouldThrow(true); + requirement.setPresent(true); + provider.fireChange(); + + assertTrue(testJob.isRan()); + assertTrue(!testJob.isFinished()); + synchronized (lock) { lock.notifyAll(); } + assertTrue(!testJob.isFinished()); + + requirement.setPresent(false); + provider.fireChange(); + assertTrue(!testJob.isFinished()); + synchronized (lock) { lock.notifyAll(); } + assertTrue(!testJob.isFinished()); + + waitRunnable.shouldThrow(false); + requirement.setPresent(true); + provider.fireChange(); + assertTrue(!testJob.isFinished()); + synchronized (lock) { lock.notifyAll(); } + assertTrue(testJob.isFinished()); } public void testPersistentJobExecuton() throws InterruptedException { PersistentMockRequirement requirement = new PersistentMockRequirement(); PersistentTestJob testJob = new PersistentTestJob(requirement); - JobManager jobManager = new JobManager(getContext(), "persistent-requirement-test3", null, new JavaJobSerializer(getContext()), 1); + JobManager jobManager = new JobManager(getContext(), "persistent-requirement-test3", + null, new JavaJobSerializer(getContext()), 1); PersistentResult.getInstance().reset(); PersistentRequirement.getInstance().setPresent(false); @@ -56,7 +118,8 @@ public class JobManagerTest extends AndroidTestCase { assertTrue(!PersistentResult.getInstance().isRan()); PersistentRequirement.getInstance().setPresent(true); - jobManager = new JobManager(getContext(), "persistent-requirement-test3", null, new JavaJobSerializer(getContext()), 1); + jobManager = new JobManager(getContext(), "persistent-requirement-test3", null, + new JavaJobSerializer(getContext()), 1); assertTrue(PersistentResult.getInstance().isRan()); } @@ -65,7 +128,8 @@ public class JobManagerTest extends AndroidTestCase { EncryptionKeys keys = new EncryptionKeys(new byte[30]); PersistentMockRequirement requirement = new PersistentMockRequirement(); PersistentTestJob testJob = new PersistentTestJob(requirement, keys); - JobManager jobManager = new JobManager(getContext(), "persistent-requirement-test4", null, new JavaJobSerializer(getContext()), 1); + JobManager jobManager = new JobManager(getContext(), "persistent-requirement-test4", + null, new JavaJobSerializer(getContext()), 1); jobManager.setEncryptionKeys(keys); PersistentResult.getInstance().reset(); @@ -126,5 +190,4 @@ public class JobManagerTest extends AndroidTestCase { assertTrue(testJobTwo.isRan()); } - } diff --git a/jobqueue/src/androidTest/java/org/whispersystems/jobqueue/jobs/RequirementDeferringTestJob.java b/jobqueue/src/androidTest/java/org/whispersystems/jobqueue/jobs/RequirementDeferringTestJob.java new file mode 100644 index 0000000000..e64b7a3661 --- /dev/null +++ b/jobqueue/src/androidTest/java/org/whispersystems/jobqueue/jobs/RequirementDeferringTestJob.java @@ -0,0 +1,51 @@ +package org.whispersystems.jobqueue.jobs; + + import org.whispersystems.jobqueue.JobParameters; + import org.whispersystems.jobqueue.requirements.Requirement; + import org.whispersystems.jobqueue.util.RunnableThrowable; + + import java.io.IOException; + +public class RequirementDeferringTestJob extends TestJob { + + private final Object FINISHED_LOCK = new Object(); + + private boolean finished = false; + + private RunnableThrowable runnable; + + public RequirementDeferringTestJob(Requirement requirement, int retryCount, RunnableThrowable runnable) { + super(JobParameters.newBuilder().withRequirement(requirement).withRetryCount(retryCount).create()); + this.runnable = runnable; + } + + @Override + public void onRun() throws Throwable { + synchronized (RAN_LOCK) { + this.ran = true; + } + + if (runnable != null) + runnable.run(); + + synchronized (FINISHED_LOCK) { + this.finished = true; + } + } + + @Override + public boolean onShouldRetry(Throwable throwable) { + if (throwable instanceof Exception) { + return true; + } + return false; + } + + public boolean isFinished() throws InterruptedException { + synchronized (FINISHED_LOCK) { + if (!finished) FINISHED_LOCK.wait(1000); + return finished; + } + } + +} \ No newline at end of file diff --git a/jobqueue/src/androidTest/java/org/whispersystems/jobqueue/jobs/TestJob.java b/jobqueue/src/androidTest/java/org/whispersystems/jobqueue/jobs/TestJob.java index 9b9d6fa855..b99ae2347b 100644 --- a/jobqueue/src/androidTest/java/org/whispersystems/jobqueue/jobs/TestJob.java +++ b/jobqueue/src/androidTest/java/org/whispersystems/jobqueue/jobs/TestJob.java @@ -5,13 +5,13 @@ import org.whispersystems.jobqueue.JobParameters; public class TestJob extends Job { - private final Object ADDED_LOCK = new Object(); - private final Object RAN_LOCK = new Object(); - private final Object CANCELED_LOCK = new Object(); + private final Object ADDED_LOCK = new Object(); + protected final Object RAN_LOCK = new Object(); + private final Object CANCELED_LOCK = new Object(); - private boolean added = false; - private boolean ran = false; - private boolean canceled = false; + private boolean added = false; + protected boolean ran = false; + private boolean canceled = false; private Runnable runnable; diff --git a/jobqueue/src/androidTest/java/org/whispersystems/jobqueue/util/RunnableThrowable.java b/jobqueue/src/androidTest/java/org/whispersystems/jobqueue/util/RunnableThrowable.java new file mode 100644 index 0000000000..abbdf97de1 --- /dev/null +++ b/jobqueue/src/androidTest/java/org/whispersystems/jobqueue/util/RunnableThrowable.java @@ -0,0 +1,8 @@ +package org.whispersystems.jobqueue.util; + +public interface RunnableThrowable { + + public void run() throws Throwable; + + public void shouldThrow(Boolean value); +} diff --git a/jobqueue/src/main/java/org/whispersystems/jobqueue/JobConsumer.java b/jobqueue/src/main/java/org/whispersystems/jobqueue/JobConsumer.java index 4419dc62e3..648027dfec 100644 --- a/jobqueue/src/main/java/org/whispersystems/jobqueue/JobConsumer.java +++ b/jobqueue/src/main/java/org/whispersystems/jobqueue/JobConsumer.java @@ -50,6 +50,8 @@ public class JobConsumer extends Thread { if (job.isPersistent()) { persistentStorage.remove(job.getPersistentId()); } + } else { + jobQueue.add(job); } if (job.getGroupId() != null) {