Skip to content

Commit

Permalink
DeterministicScheduler supports customizable tick precision
Browse files Browse the repository at this point in the history
This change adds a constructor which takes a TimeUnit for custom
precision, but does not modify the default constructor in order to
avoid breaking existing tests which could overflow a long using
very long periods of time.
  • Loading branch information
carterkozak committed Feb 28, 2020
1 parent 60addb0 commit 7e2c7a3
Show file tree
Hide file tree
Showing 2 changed files with 33 additions and 3 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

import java.util.Collection;
import java.util.List;
import java.util.Objects;
import java.util.concurrent.Callable;
import java.util.concurrent.Delayed;
import java.util.concurrent.ExecutionException;
Expand All @@ -27,7 +28,23 @@
*/
public class DeterministicScheduler implements ScheduledExecutorService {
private final DeltaQueue<ScheduledTask<?>> deltaQueue = new DeltaQueue<ScheduledTask<?>>();


private final TimeUnit tickTimeUnit;

public DeterministicScheduler() {
this(TimeUnit.MILLISECONDS);
}

/**
* A {@link TimeUnit} may be provided for custom tick precision. This can be helpful when operating
* with nanosecond or microsecond precision.
*
* @param tickTimeUnit Time unit to use for ticks.
*/
public DeterministicScheduler(TimeUnit tickTimeUnit) {
this.tickTimeUnit = Objects.requireNonNull(tickTimeUnit, "TimeUnit is required");
}

/**
* Runs time forwards by a given duration, executing any commands scheduled for
* execution during that time period, and any background tasks spawned by the
Expand Down Expand Up @@ -210,7 +227,7 @@ public boolean repeats() {
}

public long getDelay(TimeUnit unit) {
return unit.convert(deltaQueue.delay(this), TimeUnit.MILLISECONDS);
return unit.convert(deltaQueue.delay(this), tickTimeUnit);
}

public int compareTo(Delayed o) {
Expand Down Expand Up @@ -258,7 +275,7 @@ public void run() {
}

private long toTicks(long duration, TimeUnit timeUnit) {
return TimeUnit.MILLISECONDS.convert(duration, timeUnit);
return tickTimeUnit.convert(duration, timeUnit);
}

private UnsupportedSynchronousOperationException blockingOperationsNotSupported() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -135,6 +135,19 @@ public void testGetDelayWithManyScheduledTasks() throws Exception {
assertEquals(10, task3.getDelay(TimeUnit.SECONDS));
}

public void testGetDelayWithManyScheduledTasksWithMicrosecondPrecision() throws Exception {
DeterministicScheduler microsecondScheduler = new DeterministicScheduler(TimeUnit.MICROSECONDS);
ScheduledFuture<?> task1 = microsecondScheduler.schedule(commandA, 10, TimeUnit.MICROSECONDS);
ScheduledFuture<?> task2 = microsecondScheduler.schedule(commandA, 20, TimeUnit.MICROSECONDS);
ScheduledFuture<?> task3 = microsecondScheduler.schedule(commandA, 15, TimeUnit.MICROSECONDS);

microsecondScheduler.tick(5, TimeUnit.MICROSECONDS);

assertEquals(5, task1.getDelay(TimeUnit.MICROSECONDS));
assertEquals(15, task2.getDelay(TimeUnit.MICROSECONDS));
assertEquals(10, task3.getDelay(TimeUnit.MICROSECONDS));
}

public void testGetDelayOnPassedTasks() throws Exception {
final Throwable thrown = new IllegalStateException();

Expand Down

0 comments on commit 7e2c7a3

Please sign in to comment.