11d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert/*
21d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * Copyright (C) 2009 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.base.Throwables;
201d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
211d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringertimport junit.framework.TestCase;
221d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
231d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringertimport java.lang.Thread.UncaughtExceptionHandler;
241d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringertimport java.util.concurrent.CountDownLatch;
251d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringertimport java.util.concurrent.ExecutionException;
261d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringertimport java.util.concurrent.Executor;
271d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringertimport java.util.concurrent.Future;
281d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringertimport java.util.concurrent.TimeUnit;
291d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringertimport java.util.concurrent.TimeoutException;
301d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
311d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert/**
321d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * Unit test for {@link AbstractExecutionThreadService}.
331d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert *
341d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * @author Jesse Wilson
351d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert */
361d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringertpublic class AbstractExecutionThreadServiceTest extends TestCase {
371d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
381d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert  private final CountDownLatch enterRun = new CountDownLatch(1);
391d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert  private final CountDownLatch exitRun = new CountDownLatch(1);
401d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
411d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert  private Thread executionThread;
421d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert  private Throwable thrownByExecutionThread;
431d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert  private final Executor executor = new Executor() {
441d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    @Override
451d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    public void execute(Runnable command) {
461d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      executionThread = new Thread(command);
471d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      executionThread.setUncaughtExceptionHandler(new UncaughtExceptionHandler() {
481d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert        @Override
491d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert        public void uncaughtException(Thread thread, Throwable e) {
501d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert          thrownByExecutionThread = e;
511d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert        }
521d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      });
531d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      executionThread.start();
541d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    }
551d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert  };
561d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
571d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert  public void testServiceStartStop() throws Exception {
581d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    WaitOnRunService service = new WaitOnRunService();
591d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    assertFalse(service.startUpCalled);
601d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
611d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    service.start().get();
621d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    assertTrue(service.startUpCalled);
631d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    assertEquals(Service.State.RUNNING, service.state());
641d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
651d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    enterRun.await(); // to avoid stopping the service until run() is invoked
661d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
671d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    service.stop().get();
681d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    assertTrue(service.shutDownCalled);
691d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    assertEquals(Service.State.TERMINATED, service.state());
701d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    executionThread.join();
711d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    assertNull(thrownByExecutionThread);
721d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert  }
731d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
741d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert  public void testServiceStartStopIdempotence() throws Exception {
751d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    WaitOnRunService service = new WaitOnRunService();
761d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
771d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    service.start();
781d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    service.start();
791d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    service.startAndWait();
801d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    assertEquals(Service.State.RUNNING, service.state());
811d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    service.startAndWait();
821d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    assertEquals(Service.State.RUNNING, service.state());
831d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
841d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    enterRun.await(); // to avoid stopping the service until run() is invoked
851d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
861d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    service.stop();
871d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    service.stop();
881d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    service.stopAndWait();
891d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    assertEquals(Service.State.TERMINATED, service.state());
901d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    service.stopAndWait();
911d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    assertEquals(Service.State.TERMINATED, service.state());
921d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
931d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    assertEquals(Service.State.RUNNING, service.start().get());
941d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    assertEquals(Service.State.RUNNING, service.startAndWait());
951d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    assertEquals(Service.State.TERMINATED, service.stop().get());
961d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    assertEquals(Service.State.TERMINATED, service.stopAndWait());
971d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
981d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    executionThread.join();
991d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    assertNull(thrownByExecutionThread);
1001d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert  }
1011d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
1021d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert  public void testServiceExitingOnItsOwn() throws Exception {
1031d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    WaitOnRunService service = new WaitOnRunService();
1041d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    service.expectedShutdownState = Service.State.RUNNING;
1051d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
1061d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    service.start().get();
1071d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    assertTrue(service.startUpCalled);
1081d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    assertEquals(Service.State.RUNNING, service.state());
1091d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
1101d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    exitRun.countDown(); // the service will exit voluntarily
1111d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    executionThread.join();
1121d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
1131d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    assertTrue(service.shutDownCalled);
1141d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    assertEquals(Service.State.TERMINATED, service.state());
1151d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    assertNull(thrownByExecutionThread);
1161d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
1171d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    service.stop().get(); // no-op
1181d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    assertEquals(Service.State.TERMINATED, service.state());
1191d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    assertTrue(service.shutDownCalled);
1201d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert  }
1211d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
1221d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert  private class WaitOnRunService extends AbstractExecutionThreadService {
1231d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    private boolean startUpCalled = false;
1241d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    private boolean runCalled = false;
1251d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    private boolean shutDownCalled = false;
1261d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    private State expectedShutdownState = State.STOPPING;
1271d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
1281d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    @Override protected void startUp() {
1291d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      assertFalse(startUpCalled);
1301d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      assertFalse(runCalled);
1311d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      assertFalse(shutDownCalled);
1321d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      startUpCalled = true;
1331d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      assertEquals(State.STARTING, state());
1341d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    }
1351d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
1361d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    @Override protected void run() {
1371d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      assertTrue(startUpCalled);
1381d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      assertFalse(runCalled);
1391d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      assertFalse(shutDownCalled);
1401d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      runCalled = true;
1411d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      assertEquals(State.RUNNING, state());
1421d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
1431d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      enterRun.countDown();
1441d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      try {
1451d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert        exitRun.await();
1461d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      } catch (InterruptedException e) {
1471d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert        throw Throwables.propagate(e);
1481d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      }
1491d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    }
1501d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
1511d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    @Override protected void shutDown() {
1521d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      assertTrue(startUpCalled);
1531d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      assertTrue(runCalled);
1541d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      assertFalse(shutDownCalled);
1551d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      shutDownCalled = true;
1561d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      assertEquals(expectedShutdownState, state());
1571d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    }
1581d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
1591d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    @Override protected void triggerShutdown() {
1601d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      exitRun.countDown();
1611d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    }
1621d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
1631d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    @Override protected Executor executor() {
1641d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      return executor;
1651d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    }
1661d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert  }
1671d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
1681d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert  public void testServiceThrowOnStartUp() throws Exception {
1691d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    ThrowOnStartUpService service = new ThrowOnStartUpService();
1701d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    assertFalse(service.startUpCalled);
1711d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
1721d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    Future<Service.State> startupFuture = service.start();
1731d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    try {
1741d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      startupFuture.get();
1751d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      fail();
1761d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    } catch (ExecutionException expected) {
1771d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      assertEquals("kaboom!", expected.getCause().getMessage());
1781d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    }
1791d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    executionThread.join();
1801d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
1811d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    assertTrue(service.startUpCalled);
1821d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    assertEquals(Service.State.FAILED, service.state());
1831d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    assertTrue(thrownByExecutionThread.getMessage().equals("kaboom!"));
1841d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert  }
1851d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
1861d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert  private class ThrowOnStartUpService extends AbstractExecutionThreadService {
1871d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    private boolean startUpCalled = false;
1881d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
1891d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    @Override protected void startUp() {
1901d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      startUpCalled = true;
1911d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      throw new UnsupportedOperationException("kaboom!");
1921d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    }
1931d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
1941d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    @Override protected void run() {
1951d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      throw new AssertionError("run() should not be called");
1961d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    }
1971d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
1981d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    @Override protected Executor executor() {
1991d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      return executor;
2001d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    }
2011d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert  }
2021d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
2031d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert  public void testServiceThrowOnRun() throws Exception {
2041d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    ThrowOnRunService service = new ThrowOnRunService();
2051d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
2061d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    service.start().get();
2071d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
2081d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    executionThread.join();
2091d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    assertTrue(service.shutDownCalled);
2101d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    assertEquals(Service.State.FAILED, service.state());
2111d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    assertEquals("kaboom!", thrownByExecutionThread.getMessage());
2121d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert  }
2131d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
2141d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert  public void testServiceThrowOnRunAndThenAgainOnShutDown() throws Exception {
2151d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    ThrowOnRunService service = new ThrowOnRunService();
2161d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    service.throwOnShutDown = true;
2171d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
2181d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    service.start().get();
2191d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    executionThread.join();
2201d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
2211d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    assertTrue(service.shutDownCalled);
2221d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    assertEquals(Service.State.FAILED, service.state());
2231d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    assertEquals("kaboom!", thrownByExecutionThread.getMessage());
2241d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert  }
2251d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
2261d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert  private class ThrowOnRunService extends AbstractExecutionThreadService {
2271d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    private boolean shutDownCalled = false;
2281d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    private boolean throwOnShutDown = false;
2291d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
2301d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    @Override protected void run() {
2311d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      throw new UnsupportedOperationException("kaboom!");
2321d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    }
2331d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
2341d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    @Override protected void shutDown() {
2351d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      shutDownCalled = true;
2361d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      if (throwOnShutDown) {
2371d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert        throw new UnsupportedOperationException("double kaboom!");
2381d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      }
2391d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    }
2401d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
2411d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    @Override protected Executor executor() {
2421d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      return executor;
2431d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    }
2441d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert  }
2451d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
2461d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert  public void testServiceThrowOnShutDown() throws Exception {
2471d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    ThrowOnShutDown service = new ThrowOnShutDown();
2481d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
2491d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    service.start().get();
2501d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    assertEquals(Service.State.RUNNING, service.state());
2511d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
2521d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    service.stop();
2531d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    enterRun.countDown();
2541d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    executionThread.join();
2551d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
2561d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    assertEquals(Service.State.FAILED, service.state());
2571d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    assertEquals("kaboom!", thrownByExecutionThread.getMessage());
2581d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert  }
2591d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
2601d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert  private class ThrowOnShutDown extends AbstractExecutionThreadService {
2611d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    @Override protected void run() {
2621d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      try {
2631d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert        enterRun.await();
2641d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      } catch (InterruptedException e) {
2651d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert        throw Throwables.propagate(e);
2661d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      }
2671d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    }
2681d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
2691d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    @Override protected void shutDown() {
2701d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      throw new UnsupportedOperationException("kaboom!");
2711d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    }
2721d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
2731d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    @Override protected Executor executor() {
2741d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      return executor;
2751d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    }
2761d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert  }
2771d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
2781d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert  public void testServiceTimeoutOnStartUp() throws Exception {
2791d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    TimeoutOnStartUp service = new TimeoutOnStartUp();
2801d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
2811d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    try {
2821d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      service.start().get(1, TimeUnit.MILLISECONDS);
2831d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      fail();
2841d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    } catch (TimeoutException e) {
2851d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      assertTrue(e.getMessage().contains(Service.State.STARTING.toString()));
2861d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    }
2871d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert  }
2881d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
2891d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert  private class TimeoutOnStartUp extends AbstractExecutionThreadService {
2901d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    @Override protected Executor executor() {
2911d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      return new Executor() {
2921d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert        @Override public void execute(Runnable command) {
2931d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert        }
2941d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      };
2951d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    }
2961d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
2971d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    @Override
2981d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    protected void run() throws Exception {
2991d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    }
3001d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert  }
3011d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
3021d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert}
303