Skip to content

Commit

Permalink
Fix faulty and random failing IJobManagerTest.testOrder eclipse-platf…
Browse files Browse the repository at this point in the history
…orm#628

The test case IJobManagerTest.testOrder is randomly failing. It is
supposed to validate that Jobs are execute in the order in which they
are scheduled. To this end, it asserts that the run methods of the Jobs
are executed in the order in which the have been scheduled. There is,
however, no guarantee for an execution order of the run methods but only
for the order in which the Jobs are picked by a Worker to be executed.

This change rewrites the test case to only validate that whenever a
Job's run method is executed the previously scheduled jobs have started
running or have already finished as well, i.e., are either in the state
RUNNING or NONE.

Fixes eclipse-platform#628
  • Loading branch information
HeikoKlare authored and fedejeanne committed Sep 13, 2023
1 parent 8da9b50 commit 08ecfca
Showing 1 changed file with 25 additions and 21 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -13,17 +13,18 @@
*******************************************************************************/
package org.eclipse.core.tests.runtime.jobs;

import static java.util.Collections.synchronizedList;
import static org.hamcrest.CoreMatchers.is;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.collection.IsEmptyCollection.empty;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.Queue;
import java.util.Set;
import java.util.concurrent.ConcurrentLinkedQueue;
import java.util.concurrent.Semaphore;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.atomic.AtomicIntegerArray;
Expand Down Expand Up @@ -1743,34 +1744,37 @@ public void testMutexRule() {
jobs[JOB_COUNT - 1].cancel();
}

public void testOrder() {
//ensure jobs are run in order from lowest to highest sleep time.
final Queue<Job> done = new ConcurrentLinkedQueue<>();
int[] sleepTimes = new int[] { 5, 200, 400, 600 };
Job[] jobs = new Job[sleepTimes.length];
for (int i = 0; i < sleepTimes.length; i++) {
jobs[i] = new Job("testOrder(" + i + ")") {
public void testOrder() throws Exception {
// ensure jobs are run in order from lowest to highest sleep time.
int[] sleepTimes = new int[] { 0, 1, 2, 5, 10, 15, 25, 50 };
final LinkedList<Job> allJobs = new LinkedList<>();
final List<Job> jobsRunningBeforePrevious = synchronizedList(new ArrayList<>());

for (int sleepTime : sleepTimes) {
final Job previouslyScheduledJob = allJobs.isEmpty() ? null : allJobs.getLast();
Job currentJob = new Job("testOrder job to be run with sleep time " + sleepTime) {
@Override
protected IStatus run(IProgressMonitor monitor) {
done.add(this);
if (!hasPreviousJobStartedRunning()) {
jobsRunningBeforePrevious.add(this);
}
return Status.OK_STATUS;
}

private boolean hasPreviousJobStartedRunning() {
return previouslyScheduledJob == null || previouslyScheduledJob.getState() == Job.RUNNING
|| previouslyScheduledJob.getState() == Job.NONE;
}
};
currentJob.schedule(sleepTime);
allJobs.add(currentJob);
}
for (int i = 0; i < sleepTimes.length; i++) {
jobs[i].schedule(sleepTimes[i]);
}
// make sure listener has had a chance to process the finished job
while (done.size() != jobs.length) {
Thread.yield();
}
Job[] doneOrder = done.toArray(new Job[done.size()]);
assertEquals("1.0", jobs.length, doneOrder.length);
for (int i = 0; i < doneOrder.length; i++) {
assertEquals("1.1." + i, jobs[i], doneOrder[i]);
for (Job job : allJobs) {
job.join();
}

assertThat("there have jobs started running before a previously scheduled one", jobsRunningBeforePrevious,
empty());
}

public void testReverseOrder() throws InterruptedException {
Expand Down

0 comments on commit 08ecfca

Please sign in to comment.