Test case and fix for deferred jobs.

Closes #2033
This commit is contained in:
agrajaghh 2014-10-24 03:29:29 +02:00 committed by Moxie Marlinspike
parent e7b6a852c5
commit 306da92031
5 changed files with 140 additions and 16 deletions

View File

@ -3,6 +3,7 @@ package org.whispersystems.jobqueue;
import android.test.AndroidTestCase; import android.test.AndroidTestCase;
import org.whispersystems.jobqueue.jobs.PersistentTestJob; import org.whispersystems.jobqueue.jobs.PersistentTestJob;
import org.whispersystems.jobqueue.jobs.RequirementDeferringTestJob;
import org.whispersystems.jobqueue.jobs.RequirementTestJob; import org.whispersystems.jobqueue.jobs.RequirementTestJob;
import org.whispersystems.jobqueue.jobs.TestJob; import org.whispersystems.jobqueue.jobs.TestJob;
import org.whispersystems.jobqueue.persistence.JavaJobSerializer; import org.whispersystems.jobqueue.persistence.JavaJobSerializer;
@ -11,6 +12,9 @@ import org.whispersystems.jobqueue.util.MockRequirementProvider;
import org.whispersystems.jobqueue.util.PersistentMockRequirement; import org.whispersystems.jobqueue.util.PersistentMockRequirement;
import org.whispersystems.jobqueue.util.PersistentRequirement; import org.whispersystems.jobqueue.util.PersistentRequirement;
import org.whispersystems.jobqueue.util.PersistentResult; import org.whispersystems.jobqueue.util.PersistentResult;
import org.whispersystems.jobqueue.util.RunnableThrowable;
import java.io.IOException;
public class JobManagerTest extends AndroidTestCase { public class JobManagerTest extends AndroidTestCase {
@ -28,7 +32,8 @@ public class JobManagerTest extends AndroidTestCase {
MockRequirementProvider provider = new MockRequirementProvider(); MockRequirementProvider provider = new MockRequirementProvider();
MockRequirement requirement = new MockRequirement(false); MockRequirement requirement = new MockRequirement(false);
TestJob testJob = new RequirementTestJob(requirement); TestJob testJob = new RequirementTestJob(requirement);
JobManager jobManager = new JobManager(getContext(), "transient-requirement-test", provider, null, 1); JobManager jobManager = new JobManager(getContext(), "transient-requirement-test",
provider, null, 1);
jobManager.add(testJob); jobManager.add(testJob);
@ -39,13 +44,70 @@ public class JobManagerTest extends AndroidTestCase {
provider.fireChange(); provider.fireChange();
assertTrue(testJob.isRan()); 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 { public void testPersistentJobExecuton() throws InterruptedException {
PersistentMockRequirement requirement = new PersistentMockRequirement(); PersistentMockRequirement requirement = new PersistentMockRequirement();
PersistentTestJob testJob = new PersistentTestJob(requirement); 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(); PersistentResult.getInstance().reset();
PersistentRequirement.getInstance().setPresent(false); PersistentRequirement.getInstance().setPresent(false);
@ -56,7 +118,8 @@ public class JobManagerTest extends AndroidTestCase {
assertTrue(!PersistentResult.getInstance().isRan()); assertTrue(!PersistentResult.getInstance().isRan());
PersistentRequirement.getInstance().setPresent(true); 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()); assertTrue(PersistentResult.getInstance().isRan());
} }
@ -65,7 +128,8 @@ public class JobManagerTest extends AndroidTestCase {
EncryptionKeys keys = new EncryptionKeys(new byte[30]); EncryptionKeys keys = new EncryptionKeys(new byte[30]);
PersistentMockRequirement requirement = new PersistentMockRequirement(); PersistentMockRequirement requirement = new PersistentMockRequirement();
PersistentTestJob testJob = new PersistentTestJob(requirement, keys); 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); jobManager.setEncryptionKeys(keys);
PersistentResult.getInstance().reset(); PersistentResult.getInstance().reset();
@ -126,5 +190,4 @@ public class JobManagerTest extends AndroidTestCase {
assertTrue(testJobTwo.isRan()); assertTrue(testJobTwo.isRan());
} }
} }

View File

@ -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;
}
}
}

View File

@ -6,11 +6,11 @@ import org.whispersystems.jobqueue.JobParameters;
public class TestJob extends Job { public class TestJob extends Job {
private final Object ADDED_LOCK = new Object(); private final Object ADDED_LOCK = new Object();
private final Object RAN_LOCK = new Object(); protected final Object RAN_LOCK = new Object();
private final Object CANCELED_LOCK = new Object(); private final Object CANCELED_LOCK = new Object();
private boolean added = false; private boolean added = false;
private boolean ran = false; protected boolean ran = false;
private boolean canceled = false; private boolean canceled = false;
private Runnable runnable; private Runnable runnable;

View File

@ -0,0 +1,8 @@
package org.whispersystems.jobqueue.util;
public interface RunnableThrowable {
public void run() throws Throwable;
public void shouldThrow(Boolean value);
}

View File

@ -50,6 +50,8 @@ public class JobConsumer extends Thread {
if (job.isPersistent()) { if (job.isPersistent()) {
persistentStorage.remove(job.getPersistentId()); persistentStorage.remove(job.getPersistentId());
} }
} else {
jobQueue.add(job);
} }
if (job.getGroupId() != null) { if (job.getGroupId() != null) {