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 static java.lang.Thread.currentThread; 201d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringertimport static java.util.concurrent.TimeUnit.SECONDS; 211d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert 227dd252788645e940eada959bdde927426e2531c9Paul Duffinimport com.google.common.collect.ImmutableList; 237dd252788645e940eada959bdde927426e2531c9Paul Duffinimport com.google.common.collect.Iterables; 247dd252788645e940eada959bdde927426e2531c9Paul Duffinimport com.google.common.collect.Lists; 257dd252788645e940eada959bdde927426e2531c9Paul Duffinimport com.google.common.util.concurrent.Service.Listener; 267dd252788645e940eada959bdde927426e2531c9Paul Duffinimport com.google.common.util.concurrent.Service.State; 271d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert 280888a09821a98ac0680fad765217302858e70fa4Paul Duffinimport junit.framework.TestCase; 290888a09821a98ac0680fad765217302858e70fa4Paul Duffin 301d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringertimport java.lang.Thread.UncaughtExceptionHandler; 317dd252788645e940eada959bdde927426e2531c9Paul Duffinimport java.util.List; 321d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringertimport java.util.concurrent.CountDownLatch; 337dd252788645e940eada959bdde927426e2531c9Paul Duffinimport java.util.concurrent.TimeUnit; 340888a09821a98ac0680fad765217302858e70fa4Paul Duffinimport java.util.concurrent.atomic.AtomicInteger; 350888a09821a98ac0680fad765217302858e70fa4Paul Duffinimport java.util.concurrent.atomic.AtomicReference; 367dd252788645e940eada959bdde927426e2531c9Paul Duffin 377dd252788645e940eada959bdde927426e2531c9Paul Duffinimport javax.annotation.concurrent.GuardedBy; 387dd252788645e940eada959bdde927426e2531c9Paul Duffin 391d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert/** 401d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * Unit test for {@link AbstractService}. 411d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * 421d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * @author Jesse Wilson 431d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert */ 441d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringertpublic class AbstractServiceTest extends TestCase { 451d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert 460888a09821a98ac0680fad765217302858e70fa4Paul Duffin private static final long LONG_TIMEOUT_MILLIS = 2500; 471d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert private Thread executionThread; 481d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert private Throwable thrownByExecutionThread; 491d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert 507dd252788645e940eada959bdde927426e2531c9Paul Duffin public void testNoOpServiceStartStop() throws Exception { 511d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert NoOpService service = new NoOpService(); 527dd252788645e940eada959bdde927426e2531c9Paul Duffin RecordingListener listener = RecordingListener.record(service); 537dd252788645e940eada959bdde927426e2531c9Paul Duffin 547dd252788645e940eada959bdde927426e2531c9Paul Duffin assertEquals(State.NEW, service.state()); 551d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert assertFalse(service.isRunning()); 561d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert assertFalse(service.running); 571d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert 580888a09821a98ac0680fad765217302858e70fa4Paul Duffin service.startAsync(); 597dd252788645e940eada959bdde927426e2531c9Paul Duffin assertEquals(State.RUNNING, service.state()); 601d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert assertTrue(service.isRunning()); 611d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert assertTrue(service.running); 621d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert 630888a09821a98ac0680fad765217302858e70fa4Paul Duffin service.stopAsync(); 647dd252788645e940eada959bdde927426e2531c9Paul Duffin assertEquals(State.TERMINATED, service.state()); 651d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert assertFalse(service.isRunning()); 661d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert assertFalse(service.running); 677dd252788645e940eada959bdde927426e2531c9Paul Duffin assertEquals( 687dd252788645e940eada959bdde927426e2531c9Paul Duffin ImmutableList.of( 697dd252788645e940eada959bdde927426e2531c9Paul Duffin State.STARTING, 707dd252788645e940eada959bdde927426e2531c9Paul Duffin State.RUNNING, 717dd252788645e940eada959bdde927426e2531c9Paul Duffin State.STOPPING, 727dd252788645e940eada959bdde927426e2531c9Paul Duffin State.TERMINATED), 737dd252788645e940eada959bdde927426e2531c9Paul Duffin listener.getStateHistory()); 741d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert } 751d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert 761d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert public void testNoOpServiceStartAndWaitStopAndWait() throws Exception { 771d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert NoOpService service = new NoOpService(); 781d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert 790888a09821a98ac0680fad765217302858e70fa4Paul Duffin service.startAsync().awaitRunning(); 807dd252788645e940eada959bdde927426e2531c9Paul Duffin assertEquals(State.RUNNING, service.state()); 811d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert 820888a09821a98ac0680fad765217302858e70fa4Paul Duffin service.stopAsync().awaitTerminated(); 837dd252788645e940eada959bdde927426e2531c9Paul Duffin assertEquals(State.TERMINATED, service.state()); 841d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert } 851d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert 860888a09821a98ac0680fad765217302858e70fa4Paul Duffin public void testNoOpServiceStartAsyncAndAwaitStopAsyncAndAwait() throws Exception { 870888a09821a98ac0680fad765217302858e70fa4Paul Duffin NoOpService service = new NoOpService(); 880888a09821a98ac0680fad765217302858e70fa4Paul Duffin 890888a09821a98ac0680fad765217302858e70fa4Paul Duffin service.startAsync().awaitRunning(); 900888a09821a98ac0680fad765217302858e70fa4Paul Duffin assertEquals(State.RUNNING, service.state()); 910888a09821a98ac0680fad765217302858e70fa4Paul Duffin 920888a09821a98ac0680fad765217302858e70fa4Paul Duffin service.stopAsync().awaitTerminated(); 930888a09821a98ac0680fad765217302858e70fa4Paul Duffin assertEquals(State.TERMINATED, service.state()); 940888a09821a98ac0680fad765217302858e70fa4Paul Duffin } 950888a09821a98ac0680fad765217302858e70fa4Paul Duffin 960888a09821a98ac0680fad765217302858e70fa4Paul Duffin public void testNoOpServiceStopIdempotence() throws Exception { 971d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert NoOpService service = new NoOpService(); 987dd252788645e940eada959bdde927426e2531c9Paul Duffin RecordingListener listener = RecordingListener.record(service); 990888a09821a98ac0680fad765217302858e70fa4Paul Duffin service.startAsync().awaitRunning(); 1007dd252788645e940eada959bdde927426e2531c9Paul Duffin assertEquals(State.RUNNING, service.state()); 1011d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert 1020888a09821a98ac0680fad765217302858e70fa4Paul Duffin service.stopAsync(); 1030888a09821a98ac0680fad765217302858e70fa4Paul Duffin service.stopAsync(); 1047dd252788645e940eada959bdde927426e2531c9Paul Duffin assertEquals(State.TERMINATED, service.state()); 1057dd252788645e940eada959bdde927426e2531c9Paul Duffin assertEquals( 1067dd252788645e940eada959bdde927426e2531c9Paul Duffin ImmutableList.of( 1077dd252788645e940eada959bdde927426e2531c9Paul Duffin State.STARTING, 1087dd252788645e940eada959bdde927426e2531c9Paul Duffin State.RUNNING, 1097dd252788645e940eada959bdde927426e2531c9Paul Duffin State.STOPPING, 1107dd252788645e940eada959bdde927426e2531c9Paul Duffin State.TERMINATED), 1117dd252788645e940eada959bdde927426e2531c9Paul Duffin listener.getStateHistory()); 1121d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert } 1131d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert 1140888a09821a98ac0680fad765217302858e70fa4Paul Duffin public void testNoOpServiceStopIdempotenceAfterWait() throws Exception { 1151d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert NoOpService service = new NoOpService(); 1161d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert 1170888a09821a98ac0680fad765217302858e70fa4Paul Duffin service.startAsync().awaitRunning(); 1181d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert 1190888a09821a98ac0680fad765217302858e70fa4Paul Duffin service.stopAsync().awaitTerminated(); 1200888a09821a98ac0680fad765217302858e70fa4Paul Duffin service.stopAsync(); 1217dd252788645e940eada959bdde927426e2531c9Paul Duffin assertEquals(State.TERMINATED, service.state()); 1221d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert } 1231d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert 1240888a09821a98ac0680fad765217302858e70fa4Paul Duffin public void testNoOpServiceStopIdempotenceDoubleWait() throws Exception { 1251d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert NoOpService service = new NoOpService(); 1261d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert 1270888a09821a98ac0680fad765217302858e70fa4Paul Duffin service.startAsync().awaitRunning(); 1287dd252788645e940eada959bdde927426e2531c9Paul Duffin assertEquals(State.RUNNING, service.state()); 1291d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert 1300888a09821a98ac0680fad765217302858e70fa4Paul Duffin service.stopAsync().awaitTerminated(); 1310888a09821a98ac0680fad765217302858e70fa4Paul Duffin service.stopAsync().awaitTerminated(); 1327dd252788645e940eada959bdde927426e2531c9Paul Duffin assertEquals(State.TERMINATED, service.state()); 1331d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert } 1341d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert 1351d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert public void testNoOpServiceStartStopAndWaitUninterruptible() 1361d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert throws Exception { 1371d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert NoOpService service = new NoOpService(); 1381d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert 1391d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert currentThread().interrupt(); 1401d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert try { 1410888a09821a98ac0680fad765217302858e70fa4Paul Duffin service.startAsync().awaitRunning(); 1427dd252788645e940eada959bdde927426e2531c9Paul Duffin assertEquals(State.RUNNING, service.state()); 1431d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert 1440888a09821a98ac0680fad765217302858e70fa4Paul Duffin service.stopAsync().awaitTerminated(); 1457dd252788645e940eada959bdde927426e2531c9Paul Duffin assertEquals(State.TERMINATED, service.state()); 1461d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert 1471d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert assertTrue(currentThread().isInterrupted()); 1481d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert } finally { 1491d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert Thread.interrupted(); // clear interrupt for future tests 1501d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert } 1511d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert } 1521d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert 1531d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert private static class NoOpService extends AbstractService { 1541d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert boolean running = false; 1551d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert 1561d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert @Override protected void doStart() { 1571d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert assertFalse(running); 1581d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert running = true; 1591d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert notifyStarted(); 1601d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert } 1611d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert 1621d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert @Override protected void doStop() { 1631d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert assertTrue(running); 1641d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert running = false; 1651d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert notifyStopped(); 1661d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert } 1671d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert } 1681d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert 1697dd252788645e940eada959bdde927426e2531c9Paul Duffin public void testManualServiceStartStop() throws Exception { 1701d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert ManualSwitchedService service = new ManualSwitchedService(); 1717dd252788645e940eada959bdde927426e2531c9Paul Duffin RecordingListener listener = RecordingListener.record(service); 1721d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert 1730888a09821a98ac0680fad765217302858e70fa4Paul Duffin service.startAsync(); 1747dd252788645e940eada959bdde927426e2531c9Paul Duffin assertEquals(State.STARTING, service.state()); 1751d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert assertFalse(service.isRunning()); 1761d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert assertTrue(service.doStartCalled); 1771d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert 1781d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert service.notifyStarted(); // usually this would be invoked by another thread 1797dd252788645e940eada959bdde927426e2531c9Paul Duffin assertEquals(State.RUNNING, service.state()); 1801d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert assertTrue(service.isRunning()); 1811d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert 1820888a09821a98ac0680fad765217302858e70fa4Paul Duffin service.stopAsync(); 1837dd252788645e940eada959bdde927426e2531c9Paul Duffin assertEquals(State.STOPPING, service.state()); 1841d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert assertFalse(service.isRunning()); 1851d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert assertTrue(service.doStopCalled); 1861d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert 1871d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert service.notifyStopped(); // usually this would be invoked by another thread 1887dd252788645e940eada959bdde927426e2531c9Paul Duffin assertEquals(State.TERMINATED, service.state()); 1891d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert assertFalse(service.isRunning()); 1907dd252788645e940eada959bdde927426e2531c9Paul Duffin assertEquals( 1917dd252788645e940eada959bdde927426e2531c9Paul Duffin ImmutableList.of( 1927dd252788645e940eada959bdde927426e2531c9Paul Duffin State.STARTING, 1937dd252788645e940eada959bdde927426e2531c9Paul Duffin State.RUNNING, 1947dd252788645e940eada959bdde927426e2531c9Paul Duffin State.STOPPING, 1957dd252788645e940eada959bdde927426e2531c9Paul Duffin State.TERMINATED), 1967dd252788645e940eada959bdde927426e2531c9Paul Duffin listener.getStateHistory()); 1977dd252788645e940eada959bdde927426e2531c9Paul Duffin 1981d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert } 1991d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert 2007dd252788645e940eada959bdde927426e2531c9Paul Duffin public void testManualServiceNotifyStoppedWhileRunning() throws Exception { 2011d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert ManualSwitchedService service = new ManualSwitchedService(); 2027dd252788645e940eada959bdde927426e2531c9Paul Duffin RecordingListener listener = RecordingListener.record(service); 2031d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert 2040888a09821a98ac0680fad765217302858e70fa4Paul Duffin service.startAsync(); 2057dd252788645e940eada959bdde927426e2531c9Paul Duffin service.notifyStarted(); 2067dd252788645e940eada959bdde927426e2531c9Paul Duffin service.notifyStopped(); 2077dd252788645e940eada959bdde927426e2531c9Paul Duffin assertEquals(State.TERMINATED, service.state()); 2087dd252788645e940eada959bdde927426e2531c9Paul Duffin assertFalse(service.isRunning()); 2097dd252788645e940eada959bdde927426e2531c9Paul Duffin assertFalse(service.doStopCalled); 2107dd252788645e940eada959bdde927426e2531c9Paul Duffin 2117dd252788645e940eada959bdde927426e2531c9Paul Duffin assertEquals( 2127dd252788645e940eada959bdde927426e2531c9Paul Duffin ImmutableList.of( 2137dd252788645e940eada959bdde927426e2531c9Paul Duffin State.STARTING, 2147dd252788645e940eada959bdde927426e2531c9Paul Duffin State.RUNNING, 2157dd252788645e940eada959bdde927426e2531c9Paul Duffin State.TERMINATED), 2167dd252788645e940eada959bdde927426e2531c9Paul Duffin listener.getStateHistory()); 2177dd252788645e940eada959bdde927426e2531c9Paul Duffin } 2187dd252788645e940eada959bdde927426e2531c9Paul Duffin 2197dd252788645e940eada959bdde927426e2531c9Paul Duffin public void testManualServiceStopWhileStarting() throws Exception { 2207dd252788645e940eada959bdde927426e2531c9Paul Duffin ManualSwitchedService service = new ManualSwitchedService(); 2217dd252788645e940eada959bdde927426e2531c9Paul Duffin RecordingListener listener = RecordingListener.record(service); 2227dd252788645e940eada959bdde927426e2531c9Paul Duffin 2230888a09821a98ac0680fad765217302858e70fa4Paul Duffin service.startAsync(); 2247dd252788645e940eada959bdde927426e2531c9Paul Duffin assertEquals(State.STARTING, service.state()); 2251d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert assertFalse(service.isRunning()); 2261d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert assertTrue(service.doStartCalled); 2271d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert 2280888a09821a98ac0680fad765217302858e70fa4Paul Duffin service.stopAsync(); 2297dd252788645e940eada959bdde927426e2531c9Paul Duffin assertEquals(State.STOPPING, service.state()); 2301d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert assertFalse(service.isRunning()); 2311d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert assertFalse(service.doStopCalled); 2321d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert 2331d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert service.notifyStarted(); 2347dd252788645e940eada959bdde927426e2531c9Paul Duffin assertEquals(State.STOPPING, service.state()); 2351d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert assertFalse(service.isRunning()); 2361d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert assertTrue(service.doStopCalled); 2371d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert 2381d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert service.notifyStopped(); 2397dd252788645e940eada959bdde927426e2531c9Paul Duffin assertEquals(State.TERMINATED, service.state()); 2407dd252788645e940eada959bdde927426e2531c9Paul Duffin assertFalse(service.isRunning()); 2417dd252788645e940eada959bdde927426e2531c9Paul Duffin assertEquals( 2427dd252788645e940eada959bdde927426e2531c9Paul Duffin ImmutableList.of( 2437dd252788645e940eada959bdde927426e2531c9Paul Duffin State.STARTING, 2447dd252788645e940eada959bdde927426e2531c9Paul Duffin State.STOPPING, 2457dd252788645e940eada959bdde927426e2531c9Paul Duffin State.TERMINATED), 2467dd252788645e940eada959bdde927426e2531c9Paul Duffin listener.getStateHistory()); 2477dd252788645e940eada959bdde927426e2531c9Paul Duffin } 2487dd252788645e940eada959bdde927426e2531c9Paul Duffin 2490888a09821a98ac0680fad765217302858e70fa4Paul Duffin /** 2500888a09821a98ac0680fad765217302858e70fa4Paul Duffin * This tests for a bug where if {@link Service#stopAsync()} was called while the service was 2510888a09821a98ac0680fad765217302858e70fa4Paul Duffin * {@link State#STARTING} more than once, the {@link Listener#stopping(State)} callback would get 2520888a09821a98ac0680fad765217302858e70fa4Paul Duffin * called multiple times. 2530888a09821a98ac0680fad765217302858e70fa4Paul Duffin */ 2540888a09821a98ac0680fad765217302858e70fa4Paul Duffin public void testManualServiceStopMultipleTimesWhileStarting() throws Exception { 2550888a09821a98ac0680fad765217302858e70fa4Paul Duffin ManualSwitchedService service = new ManualSwitchedService(); 2560888a09821a98ac0680fad765217302858e70fa4Paul Duffin final AtomicInteger stopppingCount = new AtomicInteger(); 2570888a09821a98ac0680fad765217302858e70fa4Paul Duffin service.addListener(new Listener() { 2580888a09821a98ac0680fad765217302858e70fa4Paul Duffin @Override public void stopping(State from) { 2590888a09821a98ac0680fad765217302858e70fa4Paul Duffin stopppingCount.incrementAndGet(); 2600888a09821a98ac0680fad765217302858e70fa4Paul Duffin } 2610888a09821a98ac0680fad765217302858e70fa4Paul Duffin }, MoreExecutors.sameThreadExecutor()); 2620888a09821a98ac0680fad765217302858e70fa4Paul Duffin 2630888a09821a98ac0680fad765217302858e70fa4Paul Duffin service.startAsync(); 2640888a09821a98ac0680fad765217302858e70fa4Paul Duffin service.stopAsync(); 2650888a09821a98ac0680fad765217302858e70fa4Paul Duffin assertEquals(1, stopppingCount.get()); 2660888a09821a98ac0680fad765217302858e70fa4Paul Duffin service.stopAsync(); 2670888a09821a98ac0680fad765217302858e70fa4Paul Duffin assertEquals(1, stopppingCount.get()); 2680888a09821a98ac0680fad765217302858e70fa4Paul Duffin } 2690888a09821a98ac0680fad765217302858e70fa4Paul Duffin 2707dd252788645e940eada959bdde927426e2531c9Paul Duffin public void testManualServiceStopWhileNew() throws Exception { 2717dd252788645e940eada959bdde927426e2531c9Paul Duffin ManualSwitchedService service = new ManualSwitchedService(); 2727dd252788645e940eada959bdde927426e2531c9Paul Duffin RecordingListener listener = RecordingListener.record(service); 2737dd252788645e940eada959bdde927426e2531c9Paul Duffin 2740888a09821a98ac0680fad765217302858e70fa4Paul Duffin service.stopAsync(); 2757dd252788645e940eada959bdde927426e2531c9Paul Duffin assertEquals(State.TERMINATED, service.state()); 2761d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert assertFalse(service.isRunning()); 2777dd252788645e940eada959bdde927426e2531c9Paul Duffin assertFalse(service.doStartCalled); 2787dd252788645e940eada959bdde927426e2531c9Paul Duffin assertFalse(service.doStopCalled); 2797dd252788645e940eada959bdde927426e2531c9Paul Duffin assertEquals(ImmutableList.of(State.TERMINATED), listener.getStateHistory()); 2807dd252788645e940eada959bdde927426e2531c9Paul Duffin } 2817dd252788645e940eada959bdde927426e2531c9Paul Duffin 2827dd252788645e940eada959bdde927426e2531c9Paul Duffin public void testManualServiceFailWhileStarting() throws Exception { 2837dd252788645e940eada959bdde927426e2531c9Paul Duffin ManualSwitchedService service = new ManualSwitchedService(); 2847dd252788645e940eada959bdde927426e2531c9Paul Duffin RecordingListener listener = RecordingListener.record(service); 2850888a09821a98ac0680fad765217302858e70fa4Paul Duffin service.startAsync(); 2867dd252788645e940eada959bdde927426e2531c9Paul Duffin service.notifyFailed(EXCEPTION); 2877dd252788645e940eada959bdde927426e2531c9Paul Duffin assertEquals(ImmutableList.of(State.STARTING, State.FAILED), listener.getStateHistory()); 2887dd252788645e940eada959bdde927426e2531c9Paul Duffin } 2897dd252788645e940eada959bdde927426e2531c9Paul Duffin 2907dd252788645e940eada959bdde927426e2531c9Paul Duffin public void testManualServiceFailWhileRunning() throws Exception { 2917dd252788645e940eada959bdde927426e2531c9Paul Duffin ManualSwitchedService service = new ManualSwitchedService(); 2927dd252788645e940eada959bdde927426e2531c9Paul Duffin RecordingListener listener = RecordingListener.record(service); 2930888a09821a98ac0680fad765217302858e70fa4Paul Duffin service.startAsync(); 2947dd252788645e940eada959bdde927426e2531c9Paul Duffin service.notifyStarted(); 2957dd252788645e940eada959bdde927426e2531c9Paul Duffin service.notifyFailed(EXCEPTION); 2967dd252788645e940eada959bdde927426e2531c9Paul Duffin assertEquals(ImmutableList.of(State.STARTING, State.RUNNING, State.FAILED), 2977dd252788645e940eada959bdde927426e2531c9Paul Duffin listener.getStateHistory()); 2987dd252788645e940eada959bdde927426e2531c9Paul Duffin } 2997dd252788645e940eada959bdde927426e2531c9Paul Duffin 3007dd252788645e940eada959bdde927426e2531c9Paul Duffin public void testManualServiceFailWhileStopping() throws Exception { 3017dd252788645e940eada959bdde927426e2531c9Paul Duffin ManualSwitchedService service = new ManualSwitchedService(); 3027dd252788645e940eada959bdde927426e2531c9Paul Duffin RecordingListener listener = RecordingListener.record(service); 3030888a09821a98ac0680fad765217302858e70fa4Paul Duffin service.startAsync(); 3047dd252788645e940eada959bdde927426e2531c9Paul Duffin service.notifyStarted(); 3050888a09821a98ac0680fad765217302858e70fa4Paul Duffin service.stopAsync(); 3067dd252788645e940eada959bdde927426e2531c9Paul Duffin service.notifyFailed(EXCEPTION); 3077dd252788645e940eada959bdde927426e2531c9Paul Duffin assertEquals(ImmutableList.of(State.STARTING, State.RUNNING, State.STOPPING, State.FAILED), 3087dd252788645e940eada959bdde927426e2531c9Paul Duffin listener.getStateHistory()); 3091d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert } 3101d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert 3111d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert public void testManualServiceUnrequestedStop() { 3121d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert ManualSwitchedService service = new ManualSwitchedService(); 3131d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert 3140888a09821a98ac0680fad765217302858e70fa4Paul Duffin service.startAsync(); 3151d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert 3161d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert service.notifyStarted(); 3177dd252788645e940eada959bdde927426e2531c9Paul Duffin assertEquals(State.RUNNING, service.state()); 3181d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert assertTrue(service.isRunning()); 3191d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert assertFalse(service.doStopCalled); 3201d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert 3211d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert service.notifyStopped(); 3227dd252788645e940eada959bdde927426e2531c9Paul Duffin assertEquals(State.TERMINATED, service.state()); 3231d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert assertFalse(service.isRunning()); 3241d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert assertFalse(service.doStopCalled); 3251d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert } 3261d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert 3271d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert /** 3281d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * The user of this service should call {@link #notifyStarted} and {@link 3290888a09821a98ac0680fad765217302858e70fa4Paul Duffin * #notifyStopped} after calling {@link #startAsync} and {@link #stopAsync}. 3301d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert */ 3311d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert private static class ManualSwitchedService extends AbstractService { 3321d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert boolean doStartCalled = false; 3331d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert boolean doStopCalled = false; 3341d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert 3351d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert @Override protected void doStart() { 3361d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert assertFalse(doStartCalled); 3371d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert doStartCalled = true; 3381d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert } 3391d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert 3401d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert @Override protected void doStop() { 3411d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert assertFalse(doStopCalled); 3421d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert doStopCalled = true; 3431d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert } 3441d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert } 3451d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert 3460888a09821a98ac0680fad765217302858e70fa4Paul Duffin public void testAwaitTerminated() throws Exception { 3470888a09821a98ac0680fad765217302858e70fa4Paul Duffin final NoOpService service = new NoOpService(); 3480888a09821a98ac0680fad765217302858e70fa4Paul Duffin Thread waiter = new Thread() { 3490888a09821a98ac0680fad765217302858e70fa4Paul Duffin @Override public void run() { 3500888a09821a98ac0680fad765217302858e70fa4Paul Duffin service.awaitTerminated(); 3510888a09821a98ac0680fad765217302858e70fa4Paul Duffin } 3520888a09821a98ac0680fad765217302858e70fa4Paul Duffin }; 3530888a09821a98ac0680fad765217302858e70fa4Paul Duffin waiter.start(); 3540888a09821a98ac0680fad765217302858e70fa4Paul Duffin service.startAsync().awaitRunning(); 3550888a09821a98ac0680fad765217302858e70fa4Paul Duffin assertEquals(State.RUNNING, service.state()); 3560888a09821a98ac0680fad765217302858e70fa4Paul Duffin service.stopAsync(); 3570888a09821a98ac0680fad765217302858e70fa4Paul Duffin waiter.join(LONG_TIMEOUT_MILLIS); // ensure that the await in the other thread is triggered 3580888a09821a98ac0680fad765217302858e70fa4Paul Duffin assertFalse(waiter.isAlive()); 3590888a09821a98ac0680fad765217302858e70fa4Paul Duffin } 3600888a09821a98ac0680fad765217302858e70fa4Paul Duffin 3610888a09821a98ac0680fad765217302858e70fa4Paul Duffin public void testAwaitTerminated_FailedService() throws Exception { 3620888a09821a98ac0680fad765217302858e70fa4Paul Duffin final ManualSwitchedService service = new ManualSwitchedService(); 3630888a09821a98ac0680fad765217302858e70fa4Paul Duffin final AtomicReference<Throwable> exception = Atomics.newReference(); 3640888a09821a98ac0680fad765217302858e70fa4Paul Duffin Thread waiter = new Thread() { 3650888a09821a98ac0680fad765217302858e70fa4Paul Duffin @Override public void run() { 3660888a09821a98ac0680fad765217302858e70fa4Paul Duffin try { 3670888a09821a98ac0680fad765217302858e70fa4Paul Duffin service.awaitTerminated(); 3680888a09821a98ac0680fad765217302858e70fa4Paul Duffin fail("Expected an IllegalStateException"); 3690888a09821a98ac0680fad765217302858e70fa4Paul Duffin } catch (Throwable t) { 3700888a09821a98ac0680fad765217302858e70fa4Paul Duffin exception.set(t); 3710888a09821a98ac0680fad765217302858e70fa4Paul Duffin } 3720888a09821a98ac0680fad765217302858e70fa4Paul Duffin } 3730888a09821a98ac0680fad765217302858e70fa4Paul Duffin }; 3740888a09821a98ac0680fad765217302858e70fa4Paul Duffin waiter.start(); 3750888a09821a98ac0680fad765217302858e70fa4Paul Duffin service.startAsync(); 3760888a09821a98ac0680fad765217302858e70fa4Paul Duffin service.notifyStarted(); 3770888a09821a98ac0680fad765217302858e70fa4Paul Duffin assertEquals(State.RUNNING, service.state()); 3780888a09821a98ac0680fad765217302858e70fa4Paul Duffin service.notifyFailed(EXCEPTION); 3790888a09821a98ac0680fad765217302858e70fa4Paul Duffin assertEquals(State.FAILED, service.state()); 3800888a09821a98ac0680fad765217302858e70fa4Paul Duffin waiter.join(LONG_TIMEOUT_MILLIS); 3810888a09821a98ac0680fad765217302858e70fa4Paul Duffin assertFalse(waiter.isAlive()); 3820888a09821a98ac0680fad765217302858e70fa4Paul Duffin assertTrue(exception.get() instanceof IllegalStateException); 3830888a09821a98ac0680fad765217302858e70fa4Paul Duffin assertEquals(EXCEPTION, exception.get().getCause()); 3840888a09821a98ac0680fad765217302858e70fa4Paul Duffin } 3850888a09821a98ac0680fad765217302858e70fa4Paul Duffin 3861d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert public void testThreadedServiceStartAndWaitStopAndWait() throws Throwable { 3871d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert ThreadedService service = new ThreadedService(); 3887dd252788645e940eada959bdde927426e2531c9Paul Duffin RecordingListener listener = RecordingListener.record(service); 3890888a09821a98ac0680fad765217302858e70fa4Paul Duffin service.startAsync().awaitRunning(); 3907dd252788645e940eada959bdde927426e2531c9Paul Duffin assertEquals(State.RUNNING, service.state()); 3911d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert 3921d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert service.awaitRunChecks(); 3931d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert 3940888a09821a98ac0680fad765217302858e70fa4Paul Duffin service.stopAsync().awaitTerminated(); 3957dd252788645e940eada959bdde927426e2531c9Paul Duffin assertEquals(State.TERMINATED, service.state()); 3961d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert 3971d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert throwIfSet(thrownByExecutionThread); 3987dd252788645e940eada959bdde927426e2531c9Paul Duffin assertEquals( 3997dd252788645e940eada959bdde927426e2531c9Paul Duffin ImmutableList.of( 4007dd252788645e940eada959bdde927426e2531c9Paul Duffin State.STARTING, 4017dd252788645e940eada959bdde927426e2531c9Paul Duffin State.RUNNING, 4027dd252788645e940eada959bdde927426e2531c9Paul Duffin State.STOPPING, 4037dd252788645e940eada959bdde927426e2531c9Paul Duffin State.TERMINATED), 4047dd252788645e940eada959bdde927426e2531c9Paul Duffin listener.getStateHistory()); 4051d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert } 4061d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert 4070888a09821a98ac0680fad765217302858e70fa4Paul Duffin public void testThreadedServiceStopIdempotence() throws Throwable { 4081d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert ThreadedService service = new ThreadedService(); 4091d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert 4100888a09821a98ac0680fad765217302858e70fa4Paul Duffin service.startAsync().awaitRunning(); 4117dd252788645e940eada959bdde927426e2531c9Paul Duffin assertEquals(State.RUNNING, service.state()); 4121d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert 4131d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert service.awaitRunChecks(); 4141d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert 4150888a09821a98ac0680fad765217302858e70fa4Paul Duffin service.stopAsync(); 4160888a09821a98ac0680fad765217302858e70fa4Paul Duffin service.stopAsync().awaitTerminated(); 4177dd252788645e940eada959bdde927426e2531c9Paul Duffin assertEquals(State.TERMINATED, service.state()); 4181d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert 4191d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert throwIfSet(thrownByExecutionThread); 4201d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert } 4211d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert 4220888a09821a98ac0680fad765217302858e70fa4Paul Duffin public void testThreadedServiceStopIdempotenceAfterWait() 4231d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert throws Throwable { 4241d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert ThreadedService service = new ThreadedService(); 4251d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert 4260888a09821a98ac0680fad765217302858e70fa4Paul Duffin service.startAsync().awaitRunning(); 4277dd252788645e940eada959bdde927426e2531c9Paul Duffin assertEquals(State.RUNNING, service.state()); 4281d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert 4291d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert service.awaitRunChecks(); 4301d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert 4310888a09821a98ac0680fad765217302858e70fa4Paul Duffin service.stopAsync().awaitTerminated(); 4320888a09821a98ac0680fad765217302858e70fa4Paul Duffin service.stopAsync(); 4337dd252788645e940eada959bdde927426e2531c9Paul Duffin assertEquals(State.TERMINATED, service.state()); 4341d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert 4351d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert executionThread.join(); 4361d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert 4371d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert throwIfSet(thrownByExecutionThread); 4381d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert } 4391d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert 4400888a09821a98ac0680fad765217302858e70fa4Paul Duffin public void testThreadedServiceStopIdempotenceDoubleWait() 4411d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert throws Throwable { 4421d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert ThreadedService service = new ThreadedService(); 4431d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert 4440888a09821a98ac0680fad765217302858e70fa4Paul Duffin service.startAsync().awaitRunning(); 4457dd252788645e940eada959bdde927426e2531c9Paul Duffin assertEquals(State.RUNNING, service.state()); 4461d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert 4471d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert service.awaitRunChecks(); 4481d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert 4490888a09821a98ac0680fad765217302858e70fa4Paul Duffin service.stopAsync().awaitTerminated(); 4500888a09821a98ac0680fad765217302858e70fa4Paul Duffin service.stopAsync().awaitTerminated(); 4517dd252788645e940eada959bdde927426e2531c9Paul Duffin assertEquals(State.TERMINATED, service.state()); 4521d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert 4531d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert throwIfSet(thrownByExecutionThread); 4541d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert } 4551d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert 4567dd252788645e940eada959bdde927426e2531c9Paul Duffin public void testManualServiceFailureIdempotence() { 4577dd252788645e940eada959bdde927426e2531c9Paul Duffin ManualSwitchedService service = new ManualSwitchedService(); 4587dd252788645e940eada959bdde927426e2531c9Paul Duffin RecordingListener.record(service); 4590888a09821a98ac0680fad765217302858e70fa4Paul Duffin service.startAsync(); 4607dd252788645e940eada959bdde927426e2531c9Paul Duffin service.notifyFailed(new Exception("1")); 4617dd252788645e940eada959bdde927426e2531c9Paul Duffin service.notifyFailed(new Exception("2")); 4620888a09821a98ac0680fad765217302858e70fa4Paul Duffin assertEquals("1", service.failureCause().getMessage()); 4637dd252788645e940eada959bdde927426e2531c9Paul Duffin try { 4640888a09821a98ac0680fad765217302858e70fa4Paul Duffin service.awaitRunning(); 4657dd252788645e940eada959bdde927426e2531c9Paul Duffin fail(); 4660888a09821a98ac0680fad765217302858e70fa4Paul Duffin } catch (IllegalStateException e) { 4677dd252788645e940eada959bdde927426e2531c9Paul Duffin assertEquals("1", e.getCause().getMessage()); 4687dd252788645e940eada959bdde927426e2531c9Paul Duffin } 4697dd252788645e940eada959bdde927426e2531c9Paul Duffin } 4707dd252788645e940eada959bdde927426e2531c9Paul Duffin 4711d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert private class ThreadedService extends AbstractService { 4721d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert final CountDownLatch hasConfirmedIsRunning = new CountDownLatch(1); 4731d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert 4741d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert /* 4751d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * The main test thread tries to stop() the service shortly after 4761d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * confirming that it is running. Meanwhile, the service itself is trying 4771d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * to confirm that it is running. If the main thread's stop() call happens 4781d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * before it has the chance, the test will fail. To avoid this, the main 4791d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * thread calls this method, which waits until the service has performed 4801d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * its own "running" check. 4811d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert */ 4821d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert void awaitRunChecks() throws InterruptedException { 4831d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert assertTrue("Service thread hasn't finished its checks. " 4841d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert + "Exception status (possibly stale): " + thrownByExecutionThread, 4851d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert hasConfirmedIsRunning.await(10, SECONDS)); 4861d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert } 4871d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert 4881d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert @Override protected void doStart() { 4891d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert assertEquals(State.STARTING, state()); 4901d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert invokeOnExecutionThreadForTest(new Runnable() { 4911d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert @Override public void run() { 4921d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert assertEquals(State.STARTING, state()); 4931d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert notifyStarted(); 4941d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert assertEquals(State.RUNNING, state()); 4951d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert hasConfirmedIsRunning.countDown(); 4961d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert } 4971d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert }); 4981d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert } 4991d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert 5001d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert @Override protected void doStop() { 5011d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert assertEquals(State.STOPPING, state()); 5021d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert invokeOnExecutionThreadForTest(new Runnable() { 5031d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert @Override public void run() { 5041d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert assertEquals(State.STOPPING, state()); 5051d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert notifyStopped(); 5061d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert assertEquals(State.TERMINATED, state()); 5071d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert } 5081d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert }); 5091d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert } 5101d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert } 5111d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert 5121d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert private void invokeOnExecutionThreadForTest(Runnable runnable) { 5131d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert executionThread = new Thread(runnable); 5141d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert executionThread.setUncaughtExceptionHandler(new UncaughtExceptionHandler() { 5151d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert @Override 5161d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert public void uncaughtException(Thread thread, Throwable e) { 5171d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert thrownByExecutionThread = e; 5181d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert } 5191d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert }); 5201d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert executionThread.start(); 5211d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert } 5221d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert 5231d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert private static void throwIfSet(Throwable t) throws Throwable { 5241d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert if (t != null) { 5251d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert throw t; 5261d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert } 5271d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert } 5281d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert 5291d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert public void testStopUnstartedService() throws Exception { 5301d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert NoOpService service = new NoOpService(); 5317dd252788645e940eada959bdde927426e2531c9Paul Duffin RecordingListener listener = RecordingListener.record(service); 5321d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert 5330888a09821a98ac0680fad765217302858e70fa4Paul Duffin service.stopAsync(); 5347dd252788645e940eada959bdde927426e2531c9Paul Duffin assertEquals(State.TERMINATED, service.state()); 5357dd252788645e940eada959bdde927426e2531c9Paul Duffin 5360888a09821a98ac0680fad765217302858e70fa4Paul Duffin try { 5370888a09821a98ac0680fad765217302858e70fa4Paul Duffin service.startAsync(); 5380888a09821a98ac0680fad765217302858e70fa4Paul Duffin fail(); 5390888a09821a98ac0680fad765217302858e70fa4Paul Duffin } catch (IllegalStateException expected) {} 5407dd252788645e940eada959bdde927426e2531c9Paul Duffin assertEquals(State.TERMINATED, Iterables.getOnlyElement(listener.getStateHistory())); 5417dd252788645e940eada959bdde927426e2531c9Paul Duffin } 5427dd252788645e940eada959bdde927426e2531c9Paul Duffin 5437dd252788645e940eada959bdde927426e2531c9Paul Duffin public void testFailingServiceStartAndWait() throws Exception { 5447dd252788645e940eada959bdde927426e2531c9Paul Duffin StartFailingService service = new StartFailingService(); 5457dd252788645e940eada959bdde927426e2531c9Paul Duffin RecordingListener listener = RecordingListener.record(service); 5467dd252788645e940eada959bdde927426e2531c9Paul Duffin 5477dd252788645e940eada959bdde927426e2531c9Paul Duffin try { 5480888a09821a98ac0680fad765217302858e70fa4Paul Duffin service.startAsync().awaitRunning(); 5497dd252788645e940eada959bdde927426e2531c9Paul Duffin fail(); 5500888a09821a98ac0680fad765217302858e70fa4Paul Duffin } catch (IllegalStateException e) { 5510888a09821a98ac0680fad765217302858e70fa4Paul Duffin assertEquals(EXCEPTION, service.failureCause()); 5527dd252788645e940eada959bdde927426e2531c9Paul Duffin assertEquals(EXCEPTION, e.getCause()); 5537dd252788645e940eada959bdde927426e2531c9Paul Duffin } 5547dd252788645e940eada959bdde927426e2531c9Paul Duffin assertEquals( 5557dd252788645e940eada959bdde927426e2531c9Paul Duffin ImmutableList.of( 5567dd252788645e940eada959bdde927426e2531c9Paul Duffin State.STARTING, 5577dd252788645e940eada959bdde927426e2531c9Paul Duffin State.FAILED), 5587dd252788645e940eada959bdde927426e2531c9Paul Duffin listener.getStateHistory()); 5597dd252788645e940eada959bdde927426e2531c9Paul Duffin } 5607dd252788645e940eada959bdde927426e2531c9Paul Duffin 5617dd252788645e940eada959bdde927426e2531c9Paul Duffin public void testFailingServiceStopAndWait_stopFailing() throws Exception { 5627dd252788645e940eada959bdde927426e2531c9Paul Duffin StopFailingService service = new StopFailingService(); 5637dd252788645e940eada959bdde927426e2531c9Paul Duffin RecordingListener listener = RecordingListener.record(service); 5647dd252788645e940eada959bdde927426e2531c9Paul Duffin 5650888a09821a98ac0680fad765217302858e70fa4Paul Duffin service.startAsync().awaitRunning(); 5667dd252788645e940eada959bdde927426e2531c9Paul Duffin try { 5670888a09821a98ac0680fad765217302858e70fa4Paul Duffin service.stopAsync().awaitTerminated(); 5687dd252788645e940eada959bdde927426e2531c9Paul Duffin fail(); 5690888a09821a98ac0680fad765217302858e70fa4Paul Duffin } catch (IllegalStateException e) { 5700888a09821a98ac0680fad765217302858e70fa4Paul Duffin assertEquals(EXCEPTION, service.failureCause()); 5717dd252788645e940eada959bdde927426e2531c9Paul Duffin assertEquals(EXCEPTION, e.getCause()); 5727dd252788645e940eada959bdde927426e2531c9Paul Duffin } 5737dd252788645e940eada959bdde927426e2531c9Paul Duffin assertEquals( 5747dd252788645e940eada959bdde927426e2531c9Paul Duffin ImmutableList.of( 5757dd252788645e940eada959bdde927426e2531c9Paul Duffin State.STARTING, 5767dd252788645e940eada959bdde927426e2531c9Paul Duffin State.RUNNING, 5777dd252788645e940eada959bdde927426e2531c9Paul Duffin State.STOPPING, 5787dd252788645e940eada959bdde927426e2531c9Paul Duffin State.FAILED), 5797dd252788645e940eada959bdde927426e2531c9Paul Duffin listener.getStateHistory()); 5807dd252788645e940eada959bdde927426e2531c9Paul Duffin } 5817dd252788645e940eada959bdde927426e2531c9Paul Duffin 5820888a09821a98ac0680fad765217302858e70fa4Paul Duffin public void testFailingServiceStopAndWait_runFailing() throws Exception { 5837dd252788645e940eada959bdde927426e2531c9Paul Duffin RunFailingService service = new RunFailingService(); 5847dd252788645e940eada959bdde927426e2531c9Paul Duffin RecordingListener listener = RecordingListener.record(service); 5857dd252788645e940eada959bdde927426e2531c9Paul Duffin 5860888a09821a98ac0680fad765217302858e70fa4Paul Duffin service.startAsync(); 5877dd252788645e940eada959bdde927426e2531c9Paul Duffin try { 5880888a09821a98ac0680fad765217302858e70fa4Paul Duffin service.awaitRunning(); 5897dd252788645e940eada959bdde927426e2531c9Paul Duffin fail(); 5900888a09821a98ac0680fad765217302858e70fa4Paul Duffin } catch (IllegalStateException e) { 5910888a09821a98ac0680fad765217302858e70fa4Paul Duffin assertEquals(EXCEPTION, service.failureCause()); 5920888a09821a98ac0680fad765217302858e70fa4Paul Duffin assertEquals(EXCEPTION, e.getCause()); 5937dd252788645e940eada959bdde927426e2531c9Paul Duffin } 5947dd252788645e940eada959bdde927426e2531c9Paul Duffin assertEquals( 5957dd252788645e940eada959bdde927426e2531c9Paul Duffin ImmutableList.of( 5967dd252788645e940eada959bdde927426e2531c9Paul Duffin State.STARTING, 5977dd252788645e940eada959bdde927426e2531c9Paul Duffin State.RUNNING, 5987dd252788645e940eada959bdde927426e2531c9Paul Duffin State.FAILED), 5997dd252788645e940eada959bdde927426e2531c9Paul Duffin listener.getStateHistory()); 6001d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert } 6011d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert 6021d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert public void testThrowingServiceStartAndWait() throws Exception { 6031d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert StartThrowingService service = new StartThrowingService(); 6047dd252788645e940eada959bdde927426e2531c9Paul Duffin RecordingListener listener = RecordingListener.record(service); 6051d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert 6061d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert try { 6070888a09821a98ac0680fad765217302858e70fa4Paul Duffin service.startAsync().awaitRunning(); 6081d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert fail(); 6090888a09821a98ac0680fad765217302858e70fa4Paul Duffin } catch (IllegalStateException e) { 6100888a09821a98ac0680fad765217302858e70fa4Paul Duffin assertEquals(service.exception, service.failureCause()); 6117dd252788645e940eada959bdde927426e2531c9Paul Duffin assertEquals(service.exception, e.getCause()); 6121d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert } 6137dd252788645e940eada959bdde927426e2531c9Paul Duffin assertEquals( 6147dd252788645e940eada959bdde927426e2531c9Paul Duffin ImmutableList.of( 6157dd252788645e940eada959bdde927426e2531c9Paul Duffin State.STARTING, 6167dd252788645e940eada959bdde927426e2531c9Paul Duffin State.FAILED), 6177dd252788645e940eada959bdde927426e2531c9Paul Duffin listener.getStateHistory()); 6181d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert } 6191d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert 6201d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert public void testThrowingServiceStopAndWait_stopThrowing() throws Exception { 6211d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert StopThrowingService service = new StopThrowingService(); 6227dd252788645e940eada959bdde927426e2531c9Paul Duffin RecordingListener listener = RecordingListener.record(service); 6231d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert 6240888a09821a98ac0680fad765217302858e70fa4Paul Duffin service.startAsync().awaitRunning(); 6251d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert try { 6260888a09821a98ac0680fad765217302858e70fa4Paul Duffin service.stopAsync().awaitTerminated(); 6271d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert fail(); 6280888a09821a98ac0680fad765217302858e70fa4Paul Duffin } catch (IllegalStateException e) { 6290888a09821a98ac0680fad765217302858e70fa4Paul Duffin assertEquals(service.exception, service.failureCause()); 6307dd252788645e940eada959bdde927426e2531c9Paul Duffin assertEquals(service.exception, e.getCause()); 6311d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert } 6327dd252788645e940eada959bdde927426e2531c9Paul Duffin assertEquals( 6337dd252788645e940eada959bdde927426e2531c9Paul Duffin ImmutableList.of( 6347dd252788645e940eada959bdde927426e2531c9Paul Duffin State.STARTING, 6357dd252788645e940eada959bdde927426e2531c9Paul Duffin State.RUNNING, 6367dd252788645e940eada959bdde927426e2531c9Paul Duffin State.STOPPING, 6377dd252788645e940eada959bdde927426e2531c9Paul Duffin State.FAILED), 6387dd252788645e940eada959bdde927426e2531c9Paul Duffin listener.getStateHistory()); 6391d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert } 6401d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert 6411d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert public void testThrowingServiceStopAndWait_runThrowing() throws Exception { 6421d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert RunThrowingService service = new RunThrowingService(); 6437dd252788645e940eada959bdde927426e2531c9Paul Duffin RecordingListener listener = RecordingListener.record(service); 6441d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert 6450888a09821a98ac0680fad765217302858e70fa4Paul Duffin service.startAsync(); 6463c77433663281544363151bf284b0240dfd22a42Paul Duffin try { 6470888a09821a98ac0680fad765217302858e70fa4Paul Duffin service.awaitTerminated(); 6483c77433663281544363151bf284b0240dfd22a42Paul Duffin fail(); 6490888a09821a98ac0680fad765217302858e70fa4Paul Duffin } catch (IllegalStateException e) { 6500888a09821a98ac0680fad765217302858e70fa4Paul Duffin assertEquals(service.exception, service.failureCause()); 6510888a09821a98ac0680fad765217302858e70fa4Paul Duffin assertEquals(service.exception, e.getCause()); 6521d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert } 6537dd252788645e940eada959bdde927426e2531c9Paul Duffin assertEquals( 6547dd252788645e940eada959bdde927426e2531c9Paul Duffin ImmutableList.of( 6557dd252788645e940eada959bdde927426e2531c9Paul Duffin State.STARTING, 6567dd252788645e940eada959bdde927426e2531c9Paul Duffin State.RUNNING, 6577dd252788645e940eada959bdde927426e2531c9Paul Duffin State.FAILED), 6587dd252788645e940eada959bdde927426e2531c9Paul Duffin listener.getStateHistory()); 6591d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert } 6601d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert 6617dd252788645e940eada959bdde927426e2531c9Paul Duffin public void testFailureCause_throwsIfNotFailed() { 6627dd252788645e940eada959bdde927426e2531c9Paul Duffin StopFailingService service = new StopFailingService(); 6637dd252788645e940eada959bdde927426e2531c9Paul Duffin try { 6647dd252788645e940eada959bdde927426e2531c9Paul Duffin service.failureCause(); 6657dd252788645e940eada959bdde927426e2531c9Paul Duffin fail(); 6667dd252788645e940eada959bdde927426e2531c9Paul Duffin } catch (IllegalStateException e) { 6677dd252788645e940eada959bdde927426e2531c9Paul Duffin // expected 6687dd252788645e940eada959bdde927426e2531c9Paul Duffin } 6690888a09821a98ac0680fad765217302858e70fa4Paul Duffin service.startAsync().awaitRunning(); 6707dd252788645e940eada959bdde927426e2531c9Paul Duffin try { 6717dd252788645e940eada959bdde927426e2531c9Paul Duffin service.failureCause(); 6727dd252788645e940eada959bdde927426e2531c9Paul Duffin fail(); 6737dd252788645e940eada959bdde927426e2531c9Paul Duffin } catch (IllegalStateException e) { 6747dd252788645e940eada959bdde927426e2531c9Paul Duffin // expected 6757dd252788645e940eada959bdde927426e2531c9Paul Duffin } 6767dd252788645e940eada959bdde927426e2531c9Paul Duffin try { 6770888a09821a98ac0680fad765217302858e70fa4Paul Duffin service.stopAsync().awaitTerminated(); 6787dd252788645e940eada959bdde927426e2531c9Paul Duffin fail(); 6790888a09821a98ac0680fad765217302858e70fa4Paul Duffin } catch (IllegalStateException e) { 6807dd252788645e940eada959bdde927426e2531c9Paul Duffin assertEquals(EXCEPTION, service.failureCause()); 6817dd252788645e940eada959bdde927426e2531c9Paul Duffin assertEquals(EXCEPTION, e.getCause()); 6827dd252788645e940eada959bdde927426e2531c9Paul Duffin } 6837dd252788645e940eada959bdde927426e2531c9Paul Duffin } 6847dd252788645e940eada959bdde927426e2531c9Paul Duffin 6857dd252788645e940eada959bdde927426e2531c9Paul Duffin public void testAddListenerAfterFailureDoesntCauseDeadlock() throws InterruptedException { 6867dd252788645e940eada959bdde927426e2531c9Paul Duffin final StartFailingService service = new StartFailingService(); 6870888a09821a98ac0680fad765217302858e70fa4Paul Duffin service.startAsync(); 6887dd252788645e940eada959bdde927426e2531c9Paul Duffin assertEquals(State.FAILED, service.state()); 6897dd252788645e940eada959bdde927426e2531c9Paul Duffin service.addListener(new RecordingListener(service), MoreExecutors.sameThreadExecutor()); 6907dd252788645e940eada959bdde927426e2531c9Paul Duffin Thread thread = new Thread() { 6917dd252788645e940eada959bdde927426e2531c9Paul Duffin @Override public void run() { 6920888a09821a98ac0680fad765217302858e70fa4Paul Duffin // Internally stopAsync() grabs a lock, this could be any such method on AbstractService. 6930888a09821a98ac0680fad765217302858e70fa4Paul Duffin service.stopAsync(); 6947dd252788645e940eada959bdde927426e2531c9Paul Duffin } 6957dd252788645e940eada959bdde927426e2531c9Paul Duffin }; 6967dd252788645e940eada959bdde927426e2531c9Paul Duffin thread.start(); 6970888a09821a98ac0680fad765217302858e70fa4Paul Duffin thread.join(LONG_TIMEOUT_MILLIS); 6987dd252788645e940eada959bdde927426e2531c9Paul Duffin assertFalse(thread + " is deadlocked", thread.isAlive()); 6997dd252788645e940eada959bdde927426e2531c9Paul Duffin } 7007dd252788645e940eada959bdde927426e2531c9Paul Duffin 7017dd252788645e940eada959bdde927426e2531c9Paul Duffin public void testListenerDoesntDeadlockOnStartAndWaitFromRunning() throws Exception { 7027dd252788645e940eada959bdde927426e2531c9Paul Duffin final NoOpThreadedService service = new NoOpThreadedService(); 7037dd252788645e940eada959bdde927426e2531c9Paul Duffin service.addListener(new Listener() { 7047dd252788645e940eada959bdde927426e2531c9Paul Duffin @Override public void running() { 7050888a09821a98ac0680fad765217302858e70fa4Paul Duffin service.awaitRunning(); 7067dd252788645e940eada959bdde927426e2531c9Paul Duffin } 7077dd252788645e940eada959bdde927426e2531c9Paul Duffin }, MoreExecutors.sameThreadExecutor()); 7080888a09821a98ac0680fad765217302858e70fa4Paul Duffin service.startAsync().awaitRunning(LONG_TIMEOUT_MILLIS, TimeUnit.MILLISECONDS); 7090888a09821a98ac0680fad765217302858e70fa4Paul Duffin service.stopAsync(); 7107dd252788645e940eada959bdde927426e2531c9Paul Duffin } 7117dd252788645e940eada959bdde927426e2531c9Paul Duffin 7127dd252788645e940eada959bdde927426e2531c9Paul Duffin public void testListenerDoesntDeadlockOnStopAndWaitFromTerminated() throws Exception { 7137dd252788645e940eada959bdde927426e2531c9Paul Duffin final NoOpThreadedService service = new NoOpThreadedService(); 7147dd252788645e940eada959bdde927426e2531c9Paul Duffin service.addListener(new Listener() { 7157dd252788645e940eada959bdde927426e2531c9Paul Duffin @Override public void terminated(State from) { 7160888a09821a98ac0680fad765217302858e70fa4Paul Duffin service.stopAsync().awaitTerminated(); 7177dd252788645e940eada959bdde927426e2531c9Paul Duffin } 7187dd252788645e940eada959bdde927426e2531c9Paul Duffin }, MoreExecutors.sameThreadExecutor()); 7190888a09821a98ac0680fad765217302858e70fa4Paul Duffin service.startAsync().awaitRunning(); 7207dd252788645e940eada959bdde927426e2531c9Paul Duffin 7217dd252788645e940eada959bdde927426e2531c9Paul Duffin Thread thread = new Thread() { 7227dd252788645e940eada959bdde927426e2531c9Paul Duffin @Override public void run() { 7230888a09821a98ac0680fad765217302858e70fa4Paul Duffin service.stopAsync().awaitTerminated(); 7247dd252788645e940eada959bdde927426e2531c9Paul Duffin } 7257dd252788645e940eada959bdde927426e2531c9Paul Duffin }; 7267dd252788645e940eada959bdde927426e2531c9Paul Duffin thread.start(); 7270888a09821a98ac0680fad765217302858e70fa4Paul Duffin thread.join(LONG_TIMEOUT_MILLIS); 7287dd252788645e940eada959bdde927426e2531c9Paul Duffin assertFalse(thread + " is deadlocked", thread.isAlive()); 7297dd252788645e940eada959bdde927426e2531c9Paul Duffin } 7307dd252788645e940eada959bdde927426e2531c9Paul Duffin 7317dd252788645e940eada959bdde927426e2531c9Paul Duffin private static class NoOpThreadedService extends AbstractExecutionThreadService { 7320888a09821a98ac0680fad765217302858e70fa4Paul Duffin final CountDownLatch latch = new CountDownLatch(1); 7330888a09821a98ac0680fad765217302858e70fa4Paul Duffin @Override protected void run() throws Exception { 7340888a09821a98ac0680fad765217302858e70fa4Paul Duffin latch.await(); 7350888a09821a98ac0680fad765217302858e70fa4Paul Duffin } 7360888a09821a98ac0680fad765217302858e70fa4Paul Duffin @Override protected void triggerShutdown() { 7370888a09821a98ac0680fad765217302858e70fa4Paul Duffin latch.countDown(); 7380888a09821a98ac0680fad765217302858e70fa4Paul Duffin } 7397dd252788645e940eada959bdde927426e2531c9Paul Duffin } 7407dd252788645e940eada959bdde927426e2531c9Paul Duffin 7417dd252788645e940eada959bdde927426e2531c9Paul Duffin private static class StartFailingService extends AbstractService { 7423c77433663281544363151bf284b0240dfd22a42Paul Duffin @Override protected void doStart() { 743dbd967a6e5c96cc1a97c5521f88dc1564ba2f81bPaul Duffin notifyFailed(EXCEPTION); 7443c77433663281544363151bf284b0240dfd22a42Paul Duffin } 7453c77433663281544363151bf284b0240dfd22a42Paul Duffin 7463c77433663281544363151bf284b0240dfd22a42Paul Duffin @Override protected void doStop() { 7473c77433663281544363151bf284b0240dfd22a42Paul Duffin fail(); 7483c77433663281544363151bf284b0240dfd22a42Paul Duffin } 7493c77433663281544363151bf284b0240dfd22a42Paul Duffin } 7503c77433663281544363151bf284b0240dfd22a42Paul Duffin 7517dd252788645e940eada959bdde927426e2531c9Paul Duffin private static class RunFailingService extends AbstractService { 7523c77433663281544363151bf284b0240dfd22a42Paul Duffin @Override protected void doStart() { 7533c77433663281544363151bf284b0240dfd22a42Paul Duffin notifyStarted(); 754dbd967a6e5c96cc1a97c5521f88dc1564ba2f81bPaul Duffin notifyFailed(EXCEPTION); 7553c77433663281544363151bf284b0240dfd22a42Paul Duffin } 7563c77433663281544363151bf284b0240dfd22a42Paul Duffin 7573c77433663281544363151bf284b0240dfd22a42Paul Duffin @Override protected void doStop() { 7583c77433663281544363151bf284b0240dfd22a42Paul Duffin fail(); 7593c77433663281544363151bf284b0240dfd22a42Paul Duffin } 7603c77433663281544363151bf284b0240dfd22a42Paul Duffin } 7613c77433663281544363151bf284b0240dfd22a42Paul Duffin 7627dd252788645e940eada959bdde927426e2531c9Paul Duffin private static class StopFailingService extends AbstractService { 7633c77433663281544363151bf284b0240dfd22a42Paul Duffin @Override protected void doStart() { 7643c77433663281544363151bf284b0240dfd22a42Paul Duffin notifyStarted(); 7653c77433663281544363151bf284b0240dfd22a42Paul Duffin } 7663c77433663281544363151bf284b0240dfd22a42Paul Duffin 7673c77433663281544363151bf284b0240dfd22a42Paul Duffin @Override protected void doStop() { 768dbd967a6e5c96cc1a97c5521f88dc1564ba2f81bPaul Duffin notifyFailed(EXCEPTION); 7693c77433663281544363151bf284b0240dfd22a42Paul Duffin } 7703c77433663281544363151bf284b0240dfd22a42Paul Duffin } 7713c77433663281544363151bf284b0240dfd22a42Paul Duffin 7727dd252788645e940eada959bdde927426e2531c9Paul Duffin private static class StartThrowingService extends AbstractService { 7737dd252788645e940eada959bdde927426e2531c9Paul Duffin 7747dd252788645e940eada959bdde927426e2531c9Paul Duffin final RuntimeException exception = new RuntimeException("deliberate"); 7757dd252788645e940eada959bdde927426e2531c9Paul Duffin 7767dd252788645e940eada959bdde927426e2531c9Paul Duffin @Override protected void doStart() { 7777dd252788645e940eada959bdde927426e2531c9Paul Duffin throw exception; 7787dd252788645e940eada959bdde927426e2531c9Paul Duffin } 7797dd252788645e940eada959bdde927426e2531c9Paul Duffin 7807dd252788645e940eada959bdde927426e2531c9Paul Duffin @Override protected void doStop() { 7817dd252788645e940eada959bdde927426e2531c9Paul Duffin fail(); 7827dd252788645e940eada959bdde927426e2531c9Paul Duffin } 7837dd252788645e940eada959bdde927426e2531c9Paul Duffin } 7847dd252788645e940eada959bdde927426e2531c9Paul Duffin 7857dd252788645e940eada959bdde927426e2531c9Paul Duffin private static class RunThrowingService extends AbstractService { 7867dd252788645e940eada959bdde927426e2531c9Paul Duffin 7877dd252788645e940eada959bdde927426e2531c9Paul Duffin final RuntimeException exception = new RuntimeException("deliberate"); 7887dd252788645e940eada959bdde927426e2531c9Paul Duffin 7897dd252788645e940eada959bdde927426e2531c9Paul Duffin @Override protected void doStart() { 7907dd252788645e940eada959bdde927426e2531c9Paul Duffin notifyStarted(); 7917dd252788645e940eada959bdde927426e2531c9Paul Duffin throw exception; 7927dd252788645e940eada959bdde927426e2531c9Paul Duffin } 7937dd252788645e940eada959bdde927426e2531c9Paul Duffin 7947dd252788645e940eada959bdde927426e2531c9Paul Duffin @Override protected void doStop() { 7957dd252788645e940eada959bdde927426e2531c9Paul Duffin fail(); 7967dd252788645e940eada959bdde927426e2531c9Paul Duffin } 7977dd252788645e940eada959bdde927426e2531c9Paul Duffin } 7987dd252788645e940eada959bdde927426e2531c9Paul Duffin 7997dd252788645e940eada959bdde927426e2531c9Paul Duffin private static class StopThrowingService extends AbstractService { 8007dd252788645e940eada959bdde927426e2531c9Paul Duffin 8017dd252788645e940eada959bdde927426e2531c9Paul Duffin final RuntimeException exception = new RuntimeException("deliberate"); 8027dd252788645e940eada959bdde927426e2531c9Paul Duffin 8037dd252788645e940eada959bdde927426e2531c9Paul Duffin @Override protected void doStart() { 8047dd252788645e940eada959bdde927426e2531c9Paul Duffin notifyStarted(); 8057dd252788645e940eada959bdde927426e2531c9Paul Duffin } 8067dd252788645e940eada959bdde927426e2531c9Paul Duffin 8077dd252788645e940eada959bdde927426e2531c9Paul Duffin @Override protected void doStop() { 8087dd252788645e940eada959bdde927426e2531c9Paul Duffin throw exception; 8097dd252788645e940eada959bdde927426e2531c9Paul Duffin } 8107dd252788645e940eada959bdde927426e2531c9Paul Duffin } 8117dd252788645e940eada959bdde927426e2531c9Paul Duffin 8120888a09821a98ac0680fad765217302858e70fa4Paul Duffin private static class RecordingListener extends Listener { 8137dd252788645e940eada959bdde927426e2531c9Paul Duffin static RecordingListener record(Service service) { 8147dd252788645e940eada959bdde927426e2531c9Paul Duffin RecordingListener listener = new RecordingListener(service); 8157dd252788645e940eada959bdde927426e2531c9Paul Duffin service.addListener(listener, MoreExecutors.sameThreadExecutor()); 8167dd252788645e940eada959bdde927426e2531c9Paul Duffin return listener; 8177dd252788645e940eada959bdde927426e2531c9Paul Duffin } 8187dd252788645e940eada959bdde927426e2531c9Paul Duffin 8197dd252788645e940eada959bdde927426e2531c9Paul Duffin final Service service; 8207dd252788645e940eada959bdde927426e2531c9Paul Duffin 8217dd252788645e940eada959bdde927426e2531c9Paul Duffin RecordingListener(Service service) { 8227dd252788645e940eada959bdde927426e2531c9Paul Duffin this.service = service; 8237dd252788645e940eada959bdde927426e2531c9Paul Duffin } 8247dd252788645e940eada959bdde927426e2531c9Paul Duffin 8257dd252788645e940eada959bdde927426e2531c9Paul Duffin @GuardedBy("this") 8267dd252788645e940eada959bdde927426e2531c9Paul Duffin final List<State> stateHistory = Lists.newArrayList(); 8277dd252788645e940eada959bdde927426e2531c9Paul Duffin final CountDownLatch completionLatch = new CountDownLatch(1); 8287dd252788645e940eada959bdde927426e2531c9Paul Duffin 8297dd252788645e940eada959bdde927426e2531c9Paul Duffin ImmutableList<State> getStateHistory() throws Exception { 8307dd252788645e940eada959bdde927426e2531c9Paul Duffin completionLatch.await(); 8317dd252788645e940eada959bdde927426e2531c9Paul Duffin synchronized (this) { 8327dd252788645e940eada959bdde927426e2531c9Paul Duffin return ImmutableList.copyOf(stateHistory); 8337dd252788645e940eada959bdde927426e2531c9Paul Duffin } 8347dd252788645e940eada959bdde927426e2531c9Paul Duffin } 8357dd252788645e940eada959bdde927426e2531c9Paul Duffin 8367dd252788645e940eada959bdde927426e2531c9Paul Duffin @Override public synchronized void starting() { 8377dd252788645e940eada959bdde927426e2531c9Paul Duffin assertTrue(stateHistory.isEmpty()); 8387dd252788645e940eada959bdde927426e2531c9Paul Duffin assertNotSame(State.NEW, service.state()); 8397dd252788645e940eada959bdde927426e2531c9Paul Duffin stateHistory.add(State.STARTING); 8407dd252788645e940eada959bdde927426e2531c9Paul Duffin } 8417dd252788645e940eada959bdde927426e2531c9Paul Duffin 8427dd252788645e940eada959bdde927426e2531c9Paul Duffin @Override public synchronized void running() { 8437dd252788645e940eada959bdde927426e2531c9Paul Duffin assertEquals(State.STARTING, Iterables.getOnlyElement(stateHistory)); 8447dd252788645e940eada959bdde927426e2531c9Paul Duffin stateHistory.add(State.RUNNING); 8450888a09821a98ac0680fad765217302858e70fa4Paul Duffin service.awaitRunning(); 8467dd252788645e940eada959bdde927426e2531c9Paul Duffin assertNotSame(State.STARTING, service.state()); 8477dd252788645e940eada959bdde927426e2531c9Paul Duffin } 8487dd252788645e940eada959bdde927426e2531c9Paul Duffin 8497dd252788645e940eada959bdde927426e2531c9Paul Duffin @Override public synchronized void stopping(State from) { 8507dd252788645e940eada959bdde927426e2531c9Paul Duffin assertEquals(from, Iterables.getLast(stateHistory)); 8517dd252788645e940eada959bdde927426e2531c9Paul Duffin stateHistory.add(State.STOPPING); 8527dd252788645e940eada959bdde927426e2531c9Paul Duffin if (from == State.STARTING) { 8530888a09821a98ac0680fad765217302858e70fa4Paul Duffin try { 8540888a09821a98ac0680fad765217302858e70fa4Paul Duffin service.awaitRunning(); 8550888a09821a98ac0680fad765217302858e70fa4Paul Duffin fail(); 8560888a09821a98ac0680fad765217302858e70fa4Paul Duffin } catch (IllegalStateException expected) { 8570888a09821a98ac0680fad765217302858e70fa4Paul Duffin assertNull(expected.getCause()); 8580888a09821a98ac0680fad765217302858e70fa4Paul Duffin assertTrue(expected.getMessage().equals( 8590888a09821a98ac0680fad765217302858e70fa4Paul Duffin "Expected the service to be RUNNING, but was STOPPING")); 8600888a09821a98ac0680fad765217302858e70fa4Paul Duffin } 8617dd252788645e940eada959bdde927426e2531c9Paul Duffin } 8627dd252788645e940eada959bdde927426e2531c9Paul Duffin assertNotSame(from, service.state()); 8637dd252788645e940eada959bdde927426e2531c9Paul Duffin } 8647dd252788645e940eada959bdde927426e2531c9Paul Duffin 8657dd252788645e940eada959bdde927426e2531c9Paul Duffin @Override public synchronized void terminated(State from) { 8667dd252788645e940eada959bdde927426e2531c9Paul Duffin assertEquals(from, Iterables.getLast(stateHistory, State.NEW)); 8677dd252788645e940eada959bdde927426e2531c9Paul Duffin stateHistory.add(State.TERMINATED); 8687dd252788645e940eada959bdde927426e2531c9Paul Duffin assertEquals(State.TERMINATED, service.state()); 8697dd252788645e940eada959bdde927426e2531c9Paul Duffin if (from == State.NEW) { 8700888a09821a98ac0680fad765217302858e70fa4Paul Duffin try { 8710888a09821a98ac0680fad765217302858e70fa4Paul Duffin service.awaitRunning(); 8720888a09821a98ac0680fad765217302858e70fa4Paul Duffin fail(); 8730888a09821a98ac0680fad765217302858e70fa4Paul Duffin } catch (IllegalStateException expected) { 8740888a09821a98ac0680fad765217302858e70fa4Paul Duffin assertNull(expected.getCause()); 8750888a09821a98ac0680fad765217302858e70fa4Paul Duffin assertTrue(expected.getMessage().equals( 8760888a09821a98ac0680fad765217302858e70fa4Paul Duffin "Expected the service to be RUNNING, but was TERMINATED")); 8770888a09821a98ac0680fad765217302858e70fa4Paul Duffin } 8787dd252788645e940eada959bdde927426e2531c9Paul Duffin } 8797dd252788645e940eada959bdde927426e2531c9Paul Duffin completionLatch.countDown(); 8807dd252788645e940eada959bdde927426e2531c9Paul Duffin } 8817dd252788645e940eada959bdde927426e2531c9Paul Duffin 8827dd252788645e940eada959bdde927426e2531c9Paul Duffin @Override public synchronized void failed(State from, Throwable failure) { 8837dd252788645e940eada959bdde927426e2531c9Paul Duffin assertEquals(from, Iterables.getLast(stateHistory)); 8847dd252788645e940eada959bdde927426e2531c9Paul Duffin stateHistory.add(State.FAILED); 8857dd252788645e940eada959bdde927426e2531c9Paul Duffin assertEquals(State.FAILED, service.state()); 8860888a09821a98ac0680fad765217302858e70fa4Paul Duffin assertEquals(failure, service.failureCause()); 8877dd252788645e940eada959bdde927426e2531c9Paul Duffin if (from == State.STARTING) { 8887dd252788645e940eada959bdde927426e2531c9Paul Duffin try { 8890888a09821a98ac0680fad765217302858e70fa4Paul Duffin service.awaitRunning(); 8907dd252788645e940eada959bdde927426e2531c9Paul Duffin fail(); 8910888a09821a98ac0680fad765217302858e70fa4Paul Duffin } catch (IllegalStateException e) { 8927dd252788645e940eada959bdde927426e2531c9Paul Duffin assertEquals(failure, e.getCause()); 8937dd252788645e940eada959bdde927426e2531c9Paul Duffin } 8947dd252788645e940eada959bdde927426e2531c9Paul Duffin } 8957dd252788645e940eada959bdde927426e2531c9Paul Duffin try { 8960888a09821a98ac0680fad765217302858e70fa4Paul Duffin service.awaitTerminated(); 8977dd252788645e940eada959bdde927426e2531c9Paul Duffin fail(); 8980888a09821a98ac0680fad765217302858e70fa4Paul Duffin } catch (IllegalStateException e) { 8990888a09821a98ac0680fad765217302858e70fa4Paul Duffin assertEquals(failure, e.getCause()); 9007dd252788645e940eada959bdde927426e2531c9Paul Duffin } 9017dd252788645e940eada959bdde927426e2531c9Paul Duffin completionLatch.countDown(); 9027dd252788645e940eada959bdde927426e2531c9Paul Duffin } 9037dd252788645e940eada959bdde927426e2531c9Paul Duffin } 9047dd252788645e940eada959bdde927426e2531c9Paul Duffin 9057dd252788645e940eada959bdde927426e2531c9Paul Duffin public void testNotifyStartedWhenNotStarting() { 9067dd252788645e940eada959bdde927426e2531c9Paul Duffin AbstractService service = new DefaultService(); 9077dd252788645e940eada959bdde927426e2531c9Paul Duffin try { 9087dd252788645e940eada959bdde927426e2531c9Paul Duffin service.notifyStarted(); 9097dd252788645e940eada959bdde927426e2531c9Paul Duffin fail(); 9107dd252788645e940eada959bdde927426e2531c9Paul Duffin } catch (IllegalStateException expected) {} 9117dd252788645e940eada959bdde927426e2531c9Paul Duffin } 9127dd252788645e940eada959bdde927426e2531c9Paul Duffin 9137dd252788645e940eada959bdde927426e2531c9Paul Duffin public void testNotifyStoppedWhenNotRunning() { 9147dd252788645e940eada959bdde927426e2531c9Paul Duffin AbstractService service = new DefaultService(); 9157dd252788645e940eada959bdde927426e2531c9Paul Duffin try { 9167dd252788645e940eada959bdde927426e2531c9Paul Duffin service.notifyStopped(); 9177dd252788645e940eada959bdde927426e2531c9Paul Duffin fail(); 9187dd252788645e940eada959bdde927426e2531c9Paul Duffin } catch (IllegalStateException expected) {} 9197dd252788645e940eada959bdde927426e2531c9Paul Duffin } 9207dd252788645e940eada959bdde927426e2531c9Paul Duffin 9217dd252788645e940eada959bdde927426e2531c9Paul Duffin public void testNotifyFailedWhenNotStarted() { 9227dd252788645e940eada959bdde927426e2531c9Paul Duffin AbstractService service = new DefaultService(); 9237dd252788645e940eada959bdde927426e2531c9Paul Duffin try { 9247dd252788645e940eada959bdde927426e2531c9Paul Duffin service.notifyFailed(new Exception()); 9257dd252788645e940eada959bdde927426e2531c9Paul Duffin fail(); 9267dd252788645e940eada959bdde927426e2531c9Paul Duffin } catch (IllegalStateException expected) {} 9277dd252788645e940eada959bdde927426e2531c9Paul Duffin } 9287dd252788645e940eada959bdde927426e2531c9Paul Duffin 9297dd252788645e940eada959bdde927426e2531c9Paul Duffin public void testNotifyFailedWhenTerminated() { 9307dd252788645e940eada959bdde927426e2531c9Paul Duffin NoOpService service = new NoOpService(); 9310888a09821a98ac0680fad765217302858e70fa4Paul Duffin service.startAsync().awaitRunning(); 9320888a09821a98ac0680fad765217302858e70fa4Paul Duffin service.stopAsync().awaitTerminated(); 9337dd252788645e940eada959bdde927426e2531c9Paul Duffin try { 9347dd252788645e940eada959bdde927426e2531c9Paul Duffin service.notifyFailed(new Exception()); 9357dd252788645e940eada959bdde927426e2531c9Paul Duffin fail(); 9367dd252788645e940eada959bdde927426e2531c9Paul Duffin } catch (IllegalStateException expected) {} 9377dd252788645e940eada959bdde927426e2531c9Paul Duffin } 9387dd252788645e940eada959bdde927426e2531c9Paul Duffin 9397dd252788645e940eada959bdde927426e2531c9Paul Duffin private static class DefaultService extends AbstractService { 9407dd252788645e940eada959bdde927426e2531c9Paul Duffin @Override protected void doStart() {} 9417dd252788645e940eada959bdde927426e2531c9Paul Duffin @Override protected void doStop() {} 9427dd252788645e940eada959bdde927426e2531c9Paul Duffin } 9437dd252788645e940eada959bdde927426e2531c9Paul Duffin 9441d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert private static final Exception EXCEPTION = new Exception(); 9451d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert} 946