11d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert/*
21d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * Copyright (C) 2011 The Guava Authors
31d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert *
41d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * Licensed under the Apache License, Version 2.0 (the "License");
51d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * you may not use this file except in compliance with the License.
61d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * You may obtain a copy of the License at
71d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert *
81d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * http://www.apache.org/licenses/LICENSE-2.0
91d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert *
101d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * Unless required by applicable law or agreed to in writing, software
111d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * distributed under the License is distributed on an "AS IS" BASIS,
121d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
131d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * See the License for the specific language governing permissions and
141d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * limitations under the License.
151d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert */
161d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
171d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringertpackage com.google.common.util.concurrent;
181d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
191d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringertimport com.google.common.util.concurrent.AbstractScheduledService.Scheduler;
201d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringertimport com.google.common.util.concurrent.Service.State;
211d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
221d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringertimport junit.framework.TestCase;
231d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
241d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringertimport java.util.concurrent.CyclicBarrier;
251d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringertimport java.util.concurrent.ExecutionException;
261d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringertimport java.util.concurrent.Executors;
271d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringertimport java.util.concurrent.Future;
281d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringertimport java.util.concurrent.ScheduledExecutorService;
291d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringertimport java.util.concurrent.ScheduledFuture;
301d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringertimport java.util.concurrent.ScheduledThreadPoolExecutor;
311d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
321d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringertimport java.util.concurrent.TimeUnit;
331d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringertimport java.util.concurrent.atomic.AtomicBoolean;
341d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringertimport java.util.concurrent.atomic.AtomicInteger;
351d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
361d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert/**
371d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * Unit test for {@link AbstractScheduledService}.
381d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert *
391d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * @author Luke Sandberg
401d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert */
411d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
421d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringertpublic class AbstractScheduledServiceTest extends TestCase {
431d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
441d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert  volatile Scheduler configuration = Scheduler.newFixedDelaySchedule(0, 10, TimeUnit.MILLISECONDS);
451d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert  volatile ScheduledFuture<?> future = null;
461d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
471d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert  volatile boolean atFixedRateCalled = false;
481d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert  volatile boolean withFixedDelayCalled = false;
491d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert  volatile boolean scheduleCalled = false;
501d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
511d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert  final ScheduledExecutorService executor = new ScheduledThreadPoolExecutor(10) {
521d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    @Override
531d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    public ScheduledFuture<?> scheduleWithFixedDelay(Runnable command, long initialDelay,
541d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert        long delay, TimeUnit unit) {
551d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      return future = super.scheduleWithFixedDelay(command, initialDelay, delay, unit);
561d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    }
571d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert  };
581d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
591d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert  public void testServiceStartStop() throws Exception {
601d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    NullService service = new NullService();
611d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    service.startAndWait();
621d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    assertFalse(future.isDone());
631d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    service.stopAndWait();
641d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    assertTrue(future.isCancelled());
651d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert  }
661d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
671d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert  private class NullService extends AbstractScheduledService {
681d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    @Override protected void runOneIteration() throws Exception { }
691d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    @Override protected void startUp() throws Exception { }
701d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    @Override protected void shutDown() throws Exception { }
711d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    @Override protected Scheduler scheduler() { return configuration; }
721d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    @Override protected ScheduledExecutorService executor() { return executor; }
731d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert  }
741d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
751d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert  public void testFailOnExceptionFromRun() throws Exception {
761d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    TestService service = new TestService();
771d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    service.runException = new Exception();
781d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    service.startAndWait();
791d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    service.runFirstBarrier.await();
801d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    service.runSecondBarrier.await();
811d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    try {
821d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      future.get();
831d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      fail();
841d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    } catch (ExecutionException e) {
851d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      // An execution exception holds a runtime exception (from throwables.propogate) that holds our
861d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      // original exception.
871d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      assertEquals(service.runException, e.getCause().getCause());
881d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    }
891d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    assertEquals(service.state(), Service.State.FAILED);
901d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert  }
911d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
921d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert  public void testFailOnExceptionFromStartUp() {
931d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    TestService service = new TestService();
941d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    service.startUpException = new Exception();
951d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    try {
961d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      service.startAndWait();
971d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      fail();
981d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    } catch (UncheckedExecutionException e) {
991d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      assertEquals(service.startUpException, e.getCause());
1001d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    }
1011d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    assertEquals(0, service.numberOfTimesRunCalled.get());
1021d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    assertEquals(Service.State.FAILED, service.state());
1031d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert  }
1041d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
1051d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert  public void testFailOnExceptionFromShutDown() throws Exception {
1061d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    TestService service = new TestService();
1071d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    service.shutDownException = new Exception();
1081d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    service.startAndWait();
1091d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    service.runFirstBarrier.await();
1101d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    ListenableFuture<Service.State> stopHandle = service.stop();
1111d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    service.runSecondBarrier.await();
1121d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    try {
1131d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      stopHandle.get();
1141d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      fail();
1151d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    } catch (ExecutionException e) {
1161d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      assertEquals(service.shutDownException, e.getCause());
1171d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    }
1181d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    assertEquals(Service.State.FAILED, service.state());
1191d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert  }
1201d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
1211d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert  public void testRunOneIterationCalledMultipleTimes() throws Exception {
1221d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    TestService service = new TestService();
1231d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    service.startAndWait();
1241d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    for (int i = 1; i < 10; i++) {
1251d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      service.runFirstBarrier.await();
1261d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      assertEquals(i, service.numberOfTimesRunCalled.get());
1271d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      service.runSecondBarrier.await();
1281d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    }
1291d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    service.runFirstBarrier.await();
1301d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    service.stop();
1311d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    service.runSecondBarrier.await();
1321d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    service.stopAndWait();
1331d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert  }
1341d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
1351d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert  public void testExecutorOnlyCalledOnce() throws Exception {
1361d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    TestService service = new TestService();
1371d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    service.startAndWait();
1381d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    // It should be called once during startup.
1391d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    assertEquals(1, service.numberOfTimesExecutorCalled.get());
1401d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    for (int i = 1; i < 10; i++) {
1411d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      service.runFirstBarrier.await();
1421d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      assertEquals(i, service.numberOfTimesRunCalled.get());
1431d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      service.runSecondBarrier.await();
1441d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    }
1451d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    service.runFirstBarrier.await();
1461d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    service.stop();
1471d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    service.runSecondBarrier.await();
1481d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    service.stopAndWait();
1491d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    // Only called once overall.
1501d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    assertEquals(1, service.numberOfTimesExecutorCalled.get());
1511d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert  }
1521d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
1531d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert  public void testSchedulerOnlyCalledOnce() throws Exception {
1541d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    TestService service = new TestService();
1551d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    service.startAndWait();
1561d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    // It should be called once during startup.
1571d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    assertEquals(1, service.numberOfTimesSchedulerCalled.get());
1581d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    for (int i = 1; i < 10; i++) {
1591d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      service.runFirstBarrier.await();
1601d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      assertEquals(i, service.numberOfTimesRunCalled.get());
1611d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      service.runSecondBarrier.await();
1621d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    }
1631d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    service.runFirstBarrier.await();
1641d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    service.stop();
1651d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    service.runSecondBarrier.await();
1661d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    service.stopAndWait();
1671d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    // Only called once overall.
1681d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    assertEquals(1, service.numberOfTimesSchedulerCalled.get());
1691d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert  }
1701d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
1711d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert  private class TestService extends AbstractScheduledService {
1721d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    CyclicBarrier runFirstBarrier = new CyclicBarrier(2);
1731d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    CyclicBarrier runSecondBarrier = new CyclicBarrier(2);
1741d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
1751d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    volatile boolean startUpCalled = false;
1761d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    volatile boolean shutDownCalled = false;
1771d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    AtomicInteger numberOfTimesRunCalled = new AtomicInteger(0);
1781d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    AtomicInteger numberOfTimesExecutorCalled = new AtomicInteger(0);
1791d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    AtomicInteger numberOfTimesSchedulerCalled = new AtomicInteger(0);
1801d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    volatile Exception runException = null;
1811d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    volatile Exception startUpException = null;
1821d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    volatile Exception shutDownException = null;
1831d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
1841d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    @Override
1851d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    protected void runOneIteration() throws Exception {
1861d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      assertTrue(startUpCalled);
1871d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      assertFalse(shutDownCalled);
1881d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      numberOfTimesRunCalled.incrementAndGet();
1891d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      assertEquals(State.RUNNING, state());
1901d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      runFirstBarrier.await();
1911d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      runSecondBarrier.await();
1921d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      if (runException != null) {
1931d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert        throw runException;
1941d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      }
1951d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    }
1961d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
1971d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    @Override
1981d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    protected void startUp() throws Exception {
1991d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      assertFalse(startUpCalled);
2001d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      assertFalse(shutDownCalled);
2011d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      startUpCalled = true;
2021d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      assertEquals(State.STARTING, state());
2031d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      if (startUpException != null) {
2041d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert        throw startUpException;
2051d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      }
2061d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    }
2071d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
2081d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    @Override
2091d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    protected void shutDown() throws Exception {
2101d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      assertTrue(startUpCalled);
2111d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      assertFalse(shutDownCalled);
2121d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      shutDownCalled = true;
2131d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      if (shutDownException != null) {
2141d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert        throw shutDownException;
2151d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      }
2161d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    }
2171d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
2181d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    @Override
2191d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    protected ScheduledExecutorService executor() {
2201d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      numberOfTimesExecutorCalled.incrementAndGet();
2211d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      return executor;
2221d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    }
2231d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
2241d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    @Override
2251d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    protected Scheduler scheduler() {
2261d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      numberOfTimesSchedulerCalled.incrementAndGet();
2271d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      return configuration;
2281d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    }
2291d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert  }
2301d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
2311d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert  public static class SchedulerTest extends TestCase {
2321d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    // These constants are arbitrary and just used to make sure that the correct method is called
2331d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    // with the correct parameters.
2341d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    private static final int initialDelay = 10;
2351d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    private static final int delay = 20;
2361d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    private static final TimeUnit unit = TimeUnit.MILLISECONDS;
2371d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
2381d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    // Unique runnable object used for comparison.
2391d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    final Runnable testRunnable = new Runnable() {@Override public void run() {}};
2401d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    boolean called = false;
2411d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
2421d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    private void assertSingleCallWithCorrectParameters(Runnable command, long initialDelay,
2431d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert        long delay, TimeUnit unit) {
2441d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      assertFalse(called);  // only called once.
2451d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      called = true;
2461d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      assertEquals(SchedulerTest.initialDelay, initialDelay);
2471d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      assertEquals(SchedulerTest.delay, delay);
2481d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      assertEquals(SchedulerTest.unit, unit);
2491d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      assertEquals(testRunnable, command);
2501d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    }
2511d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
2521d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    public void testFixedRateSchedule() {
2531d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      Scheduler schedule = Scheduler.newFixedRateSchedule(initialDelay, delay, unit);
2541d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      schedule.schedule(null, new ScheduledThreadPoolExecutor(1) {
2551d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert        @Override
2561d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert        public ScheduledFuture<?> scheduleAtFixedRate(Runnable command, long initialDelay,
2571d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert            long period, TimeUnit unit) {
2581d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert          assertSingleCallWithCorrectParameters(command, initialDelay, delay, unit);
2591d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert          return null;
2601d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert        }
2611d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      }, testRunnable);
2621d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      assertTrue(called);
2631d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    }
2641d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
2651d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    public void testFixedDelaySchedule() {
2661d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      Scheduler schedule = Scheduler.newFixedDelaySchedule(initialDelay, delay, unit);
2671d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      schedule.schedule(null, new ScheduledThreadPoolExecutor(10) {
2681d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert        @Override
2691d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert        public ScheduledFuture<?> scheduleWithFixedDelay(Runnable command, long initialDelay,
2701d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert            long delay, TimeUnit unit) {
2711d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert          assertSingleCallWithCorrectParameters(command, initialDelay, delay, unit);
2721d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert          return null;
2731d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert        }
2741d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      }, testRunnable);
2751d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      assertTrue(called);
2761d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    }
2771d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
2781d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    private class TestCustomScheduler extends AbstractScheduledService.CustomScheduler {
2791d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      public AtomicInteger scheduleCounter = new AtomicInteger(0);
2801d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      @Override
2811d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      protected Schedule getNextSchedule() throws Exception {
2821d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert        scheduleCounter.incrementAndGet();
2831d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert        return new Schedule(0, TimeUnit.SECONDS);
2841d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      }
2851d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    }
2861d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
2871d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    public void testCustomSchedule_startStop() throws Exception {
2881d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      final CyclicBarrier firstBarrier = new CyclicBarrier(2);
2891d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      final CyclicBarrier secondBarrier = new CyclicBarrier(2);
2901d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      final AtomicBoolean shouldWait = new AtomicBoolean(true);
2911d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      Runnable task = new Runnable() {
2921d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert        @Override public void run() {
2931d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert          try {
2941d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert            if (shouldWait.get()) {
2951d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert              firstBarrier.await();
2961d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert              secondBarrier.await();
2971d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert            }
2981d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert          } catch (Exception e) {
2991d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert            throw new RuntimeException(e);
3001d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert          }
3011d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert        }
3021d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      };
3031d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      TestCustomScheduler scheduler = new TestCustomScheduler();
3041d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      Future<?> future = scheduler.schedule(null, Executors.newScheduledThreadPool(10), task);
3051d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      firstBarrier.await();
3061d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      assertEquals(1, scheduler.scheduleCounter.get());
3071d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      secondBarrier.await();
3081d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      firstBarrier.await();
3091d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      assertEquals(2, scheduler.scheduleCounter.get());
3101d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      shouldWait.set(false);
3111d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      secondBarrier.await();
3121d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      future.cancel(false);
3131d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    }
3141d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
3151d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    public void testCustomSchedulerServiceStop() throws Exception {
3161d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      TestAbstractScheduledCustomService service = new TestAbstractScheduledCustomService();
3171d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      service.startAndWait();
3181d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      service.firstBarrier.await();
3191d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      assertEquals(1, service.numIterations.get());
3201d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      service.stop();
3211d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      service.secondBarrier.await();
3221d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      service.stopAndWait();
3231d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      // Sleep for a while just to ensure that our task wasn't called again.
3241d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      Thread.sleep(unit.toMillis(3 * delay));
3251d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      assertEquals(1, service.numIterations.get());
3261d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    }
3271d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
3281d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    public void testBig() throws Exception {
3291d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      TestAbstractScheduledCustomService service = new TestAbstractScheduledCustomService() {
3301d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert        @Override protected Scheduler scheduler() {
3311d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert          return new AbstractScheduledService.CustomScheduler(){
3321d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert            @Override
3331d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert            protected Schedule getNextSchedule() throws Exception {
3341d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert              // Explicitly yield to increase the probability of a pathological scheduling.
3351d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert              Thread.yield();
3361d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert              return new Schedule(0, TimeUnit.SECONDS);
3371d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert            }
3381d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert          };
3391d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert        }
3401d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      };
3411d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      service.useBarriers = false;
3421d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      service.startAndWait();
3431d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      Thread.sleep(50);
3441d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      service.useBarriers = true;
3451d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      service.firstBarrier.await();
3461d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      int numIterations = service.numIterations.get();
3471d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      service.stop();
3481d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      service.secondBarrier.await();
3491d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      service.stopAndWait();
3501d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      assertEquals(numIterations, service.numIterations.get());
3511d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    }
3521d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
3531d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    private static class TestAbstractScheduledCustomService extends AbstractScheduledService {
3541d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      final AtomicInteger numIterations = new AtomicInteger(0);
3551d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      volatile boolean useBarriers = true;
3561d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      final CyclicBarrier firstBarrier = new CyclicBarrier(2);
3571d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      final CyclicBarrier secondBarrier = new CyclicBarrier(2);
3581d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
3591d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      @Override protected void runOneIteration() throws Exception {
3601d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert        numIterations.incrementAndGet();
3611d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert        if (useBarriers) {
3621d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert          firstBarrier.await();
3631d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert          secondBarrier.await();
3641d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert        }
3651d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      }
3661d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
3671d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      @Override protected ScheduledExecutorService executor() {
3681d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert        // use a bunch of threads so that weird overlapping schedules are more likely to happen.
3691d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert        return Executors.newScheduledThreadPool(10);
3701d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      }
3711d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
3721d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      @Override protected void startUp() throws Exception { }
3731d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
3741d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      @Override protected void shutDown() throws Exception { }
3751d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
3761d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      @Override protected Scheduler scheduler() {
3771d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert        return new CustomScheduler() {
3781d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert          @Override
3791d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert          protected Schedule getNextSchedule() throws Exception {
3801d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert            return new Schedule(delay, unit);
3811d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert          }};
3821d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      }
3831d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    }
3841d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
3851d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    public void testCustomSchedulerFailure() throws Exception {
3861d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      TestFailingCustomScheduledService service = new TestFailingCustomScheduledService();
3871d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      service.startAndWait();
3881d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      for (int i = 1; i < 4; i++) {
3891d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert        service.firstBarrier.await();
3901d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert        assertEquals(i, service.numIterations.get());
3911d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert        service.secondBarrier.await();
3921d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      }
3931d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      Thread.sleep(1000);
3941d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      try {
3951d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert        service.stop().get(100, TimeUnit.SECONDS);
3961d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert        fail();
3971d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      } catch (ExecutionException e) {
3981d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert        assertEquals(State.FAILED, service.state());
3991d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      }
4001d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    }
4011d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
4021d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    private static class TestFailingCustomScheduledService extends AbstractScheduledService {
4031d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      final AtomicInteger numIterations = new AtomicInteger(0);
4041d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      final CyclicBarrier firstBarrier = new CyclicBarrier(2);
4051d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      final CyclicBarrier secondBarrier = new CyclicBarrier(2);
4061d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
4071d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      @Override protected void runOneIteration() throws Exception {
4081d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert        numIterations.incrementAndGet();
4091d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert        firstBarrier.await();
4101d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert        secondBarrier.await();
4111d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      }
4121d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
4131d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      @Override protected ScheduledExecutorService executor() {
4141d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert        // use a bunch of threads so that weird overlapping schedules are more likely to happen.
4151d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert        return Executors.newScheduledThreadPool(10);
4161d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      }
4171d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
4181d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      @Override protected void startUp() throws Exception { }
4191d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
4201d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      @Override protected void shutDown() throws Exception { }
4211d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
4221d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      @Override protected Scheduler scheduler() {
4231d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert        return new CustomScheduler() {
4241d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert          @Override
4251d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert          protected Schedule getNextSchedule() throws Exception {
4261d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert            if (numIterations.get() > 2) {
4271d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert              throw new IllegalStateException("Failed");
4281d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert            }
4291d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert            return new Schedule(delay, unit);
4301d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert          }};
4311d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      }
4321d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    }
4331d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert  }
4341d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert}
435