blob: e0be115f5278754cd5db8b3de7fe9ebb11c22940 [file] [log] [blame]
package com.google.enterprise.adaptor;
import static org.junit.Assert.*;
import org.junit.*;
import org.junit.rules.ExpectedException;
import java.util.TimeZone;
import java.util.concurrent.*;
import java.util.concurrent.atomic.*;
/** Test cases for {@link CronScheduler}. */
public class CronSchedulerTest {
private ScheduledExecutorService executor
= Executors.newSingleThreadScheduledExecutor();
private Runnable noopRunnable = new Runnable() {
@Override
public void run() {}
};
@Rule
public ExpectedException thrown = ExpectedException.none();
@After
public void tearDown() {
executor.shutdownNow();
}
@Test
public void testNullExecutor() {
thrown.expect(NullPointerException.class);
new CronScheduler(null);
}
@Test
public void testWrongFutureReschedule() {
CronScheduler scheduler = new CronScheduler(executor);
Future<?> future = new FutureTask<Object>(noopRunnable, null);
thrown.expect(IllegalArgumentException.class);
scheduler.reschedule(future, "* * * * *");
}
@Test
public void testParsing() {
CronScheduler scheduler = new CronScheduler(executor);
assertEquals("CronFuture([{0}, {0}, {0}, {0}, {0}])",
scheduler.schedule("0 0 1 1 0", noopRunnable).toString());
assertEquals("CronFuture([{59}, {23}, {30}, {11}, {6}])",
scheduler.schedule("59 23 31 12 6", noopRunnable).toString());
assertEquals("CronFuture([{0}, {0}, {0}, {0}, {0, 1, 3, 5}])",
scheduler.schedule("0 0 1 1 1-7/2", noopRunnable).toString());
assertEquals("CronFuture([{0}, {0}, {1, 3, 5, 7, 9, 11}, {0}, {0}])",
scheduler.schedule("0 0 2-13/2 1 0", noopRunnable).toString());
assertEquals("CronFuture([{0}, {0}, {0}, {0}, {0, 1, 2, 3, 4, 5, 6}])",
scheduler.schedule("0 0 1 1 *", noopRunnable).toString());
}
@Test
public void testWrongNumberOfFields() {
CronScheduler scheduler = new CronScheduler(executor);
thrown.expect(IllegalArgumentException.class);
scheduler.schedule("0 0 1 1 0 0", noopRunnable);
}
@Test
public void testValueNotInRange() {
CronScheduler scheduler = new CronScheduler(executor);
thrown.expect(IllegalArgumentException.class);
scheduler.schedule("0 0 1 0 0", noopRunnable);
}
@Test
public void testValueNotInRange2() {
CronScheduler scheduler = new CronScheduler(executor);
thrown.expect(IllegalArgumentException.class);
scheduler.schedule("0 0 1 1000 0", noopRunnable);
}
@Test
public void testNotANumber() {
CronScheduler scheduler = new CronScheduler(executor);
thrown.expect(IllegalArgumentException.class);
scheduler.schedule("0 0 1 wat 0", noopRunnable);
}
@Test
public void testCatchesException() {
executor.shutdownNow();
final AtomicReference<Runnable> atomicCommand
= new AtomicReference<Runnable>();
executor = new ScheduledThreadPoolExecutor(1) {
@Override
public ScheduledFuture<?> scheduleAtFixedRate(Runnable command,
long initialDelay, long period, TimeUnit unit) {
atomicCommand.set(command);
// Set high delay, because we don't want it to actually run.
return super.scheduleAtFixedRate(command, 100000, period, unit);
}
};
MockTimeProvider timeProvider = new MockTimeProvider();
timeProvider.autoIncrement = false;
TimeZone timeZone = TimeZone.getTimeZone("America/Los_Angeles");
CronScheduler scheduler
= new CronScheduler(executor, timeProvider, timeZone);
Runnable runnable = new Runnable() {
@Override
public void run() {
throw new RuntimeException("This should be caught");
}
};
// Capture internally-used runnable.
Future<?> future = scheduler.schedule("* * * * *", runnable);
// Should not throw an exception.
atomicCommand.get().run();
}
@Test
public void testRunning() throws Exception {
executor.shutdownNow();
final AtomicReference<Runnable> atomicCommand
= new AtomicReference<Runnable>();
executor = new ScheduledThreadPoolExecutor(1) {
@Override
public ScheduledFuture<?> scheduleAtFixedRate(Runnable command,
long initialDelay, long period, TimeUnit unit) {
atomicCommand.set(command);
assertEquals((60 * 1000) - (10 * 1000) + 1000, initialDelay);
assertEquals(60 * 1000, period);
assertEquals(TimeUnit.MILLISECONDS, unit);
// Set high delay, because we don't want it to actually run.
return super.scheduleAtFixedRate(command, 100000, period, unit);
}
};
MockTimeProvider timeProvider = new MockTimeProvider();
timeProvider.autoIncrement = false;
TimeZone timeZone = TimeZone.getTimeZone("America/Los_Angeles");
CronScheduler scheduler
= new CronScheduler(executor, timeProvider, timeZone);
final AtomicLong counter = new AtomicLong();
Runnable runnable = new Runnable() {
@Override
public void run() {
counter.incrementAndGet();
}
};
// 1970-01-01T00:00:10Z
timeProvider.time = 10 * 1000;
// Capture internally-used runnable.
Future<?> future = scheduler.schedule("2 2 2 2 1", runnable);
counter.set(0);
// 1970-02-02T10:02:01Z, which is a Monday. That is 02:02:01 in PST.
timeProvider.time = 2800921L * 1000;
atomicCommand.get().run();
Thread.sleep(10);
assertEquals(1, counter.get());
// Wrong minute.
// 1970-02-02T10:01:01Z, which is a Monday. That is 02:01:01 in PST.
timeProvider.time = 2800861L * 1000;
atomicCommand.get().run();
Thread.sleep(10);
assertEquals(1, counter.get());
// Wrong hour.
// 1970-02-02T09:02:01Z, which is a Monday. That is 01:02:01 in PST.
timeProvider.time = 2797321L * 1000;
atomicCommand.get().run();
Thread.sleep(10);
assertEquals(1, counter.get());
// Wrong day of month.
// 1970-02-02T10:02:01Z, which is a Monday. That is 02:02:01 in PST.
timeProvider.time = 2800921L * 1000;
scheduler.reschedule(future, "2 2 1 2 2");
atomicCommand.get().run();
Thread.sleep(10);
assertEquals(1, counter.get());
// Wrong month.
// 1970-02-02T10:02:01Z, which is a Monday. That is 02:02:01 in PST.
timeProvider.time = 2800921L * 1000;
scheduler.reschedule(future, "2 2 2 1 2");
atomicCommand.get().run();
Thread.sleep(10);
assertEquals(1, counter.get());
// Wrong day of week.
// 1970-02-02T10:02:01Z, which is a Monday. That is 02:02:01 in PST.
timeProvider.time = 2800921L * 1000;
scheduler.reschedule(future, "2 2 2 2 2");
atomicCommand.get().run();
Thread.sleep(10);
assertEquals(1, counter.get());
}
@Test
public void testRunsTwice() throws Exception {
executor.shutdownNow();
executor = new ScheduledThreadPoolExecutor(1) {
@Override
public ScheduledFuture<?> scheduleAtFixedRate(Runnable command,
long initialDelay, long period, TimeUnit unit) {
assertEquals((60 * 1000) - (10 * 1000) + 1000, initialDelay);
assertEquals(60 * 1000, period);
assertEquals(TimeUnit.MILLISECONDS, unit);
// Set low delay, because we want it to run soon.
return super.scheduleAtFixedRate(command, 1, 10, unit);
}
};
final MockTimeProvider timeProvider = new MockTimeProvider();
timeProvider.autoIncrement = false;
TimeZone timeZone = TimeZone.getTimeZone("America/Los_Angeles");
CronScheduler scheduler
= new CronScheduler(executor, timeProvider, timeZone);
final LinkedBlockingQueue<Object> queue = new LinkedBlockingQueue<Object>();
Runnable runnable = new Runnable() {
@Override
public void run() {
assertTrue(queue.offer(new Object()));
timeProvider.time += 60 * 1000;
}
};
// 1970-01-01T00:00:10Z
timeProvider.time = 10 * 1000;
// Capture internally-used runnable.
Future<?> future = scheduler.schedule("* * * * *", runnable);
assertNotNull(queue.poll(100, TimeUnit.MILLISECONDS));
assertNotNull(queue.poll(100, TimeUnit.MILLISECONDS));
future.cancel(false);
}
}