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 193ecfa412eddc4b084663f38d562537b86b9734d5Paul Duffinimport static com.google.common.util.concurrent.MoreExecutors.directExecutor; 201d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringertimport static java.lang.Thread.currentThread; 211d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringertimport static java.util.concurrent.TimeUnit.SECONDS; 221d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert 237dd252788645e940eada959bdde927426e2531c9Paul Duffinimport com.google.common.collect.ImmutableList; 247dd252788645e940eada959bdde927426e2531c9Paul Duffinimport com.google.common.collect.Iterables; 257dd252788645e940eada959bdde927426e2531c9Paul Duffinimport com.google.common.collect.Lists; 267dd252788645e940eada959bdde927426e2531c9Paul Duffinimport com.google.common.util.concurrent.Service.Listener; 277dd252788645e940eada959bdde927426e2531c9Paul Duffinimport com.google.common.util.concurrent.Service.State; 281d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert 290888a09821a98ac0680fad765217302858e70fa4Paul Duffinimport junit.framework.TestCase; 300888a09821a98ac0680fad765217302858e70fa4Paul Duffin 311d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringertimport java.lang.Thread.UncaughtExceptionHandler; 327dd252788645e940eada959bdde927426e2531c9Paul Duffinimport java.util.List; 331d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringertimport java.util.concurrent.CountDownLatch; 347dd252788645e940eada959bdde927426e2531c9Paul Duffinimport java.util.concurrent.TimeUnit; 350888a09821a98ac0680fad765217302858e70fa4Paul Duffinimport java.util.concurrent.atomic.AtomicInteger; 360888a09821a98ac0680fad765217302858e70fa4Paul Duffinimport java.util.concurrent.atomic.AtomicReference; 377dd252788645e940eada959bdde927426e2531c9Paul Duffin 387dd252788645e940eada959bdde927426e2531c9Paul Duffinimport javax.annotation.concurrent.GuardedBy; 397dd252788645e940eada959bdde927426e2531c9Paul Duffin 401d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert/** 411d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * Unit test for {@link AbstractService}. 421d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * 431d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * @author Jesse Wilson 441d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert */ 451d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringertpublic class AbstractServiceTest extends TestCase { 461d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert 470888a09821a98ac0680fad765217302858e70fa4Paul Duffin private static final long LONG_TIMEOUT_MILLIS = 2500; 481d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert private Thread executionThread; 491d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert private Throwable thrownByExecutionThread; 501d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert 517dd252788645e940eada959bdde927426e2531c9Paul Duffin public void testNoOpServiceStartStop() throws Exception { 521d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert NoOpService service = new NoOpService(); 537dd252788645e940eada959bdde927426e2531c9Paul Duffin RecordingListener listener = RecordingListener.record(service); 547dd252788645e940eada959bdde927426e2531c9Paul Duffin 557dd252788645e940eada959bdde927426e2531c9Paul Duffin assertEquals(State.NEW, service.state()); 561d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert assertFalse(service.isRunning()); 571d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert assertFalse(service.running); 581d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert 590888a09821a98ac0680fad765217302858e70fa4Paul Duffin service.startAsync(); 607dd252788645e940eada959bdde927426e2531c9Paul Duffin assertEquals(State.RUNNING, service.state()); 611d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert assertTrue(service.isRunning()); 621d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert assertTrue(service.running); 631d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert 640888a09821a98ac0680fad765217302858e70fa4Paul Duffin service.stopAsync(); 657dd252788645e940eada959bdde927426e2531c9Paul Duffin assertEquals(State.TERMINATED, service.state()); 661d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert assertFalse(service.isRunning()); 671d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert assertFalse(service.running); 687dd252788645e940eada959bdde927426e2531c9Paul Duffin assertEquals( 697dd252788645e940eada959bdde927426e2531c9Paul Duffin ImmutableList.of( 707dd252788645e940eada959bdde927426e2531c9Paul Duffin State.STARTING, 717dd252788645e940eada959bdde927426e2531c9Paul Duffin State.RUNNING, 727dd252788645e940eada959bdde927426e2531c9Paul Duffin State.STOPPING, 737dd252788645e940eada959bdde927426e2531c9Paul Duffin State.TERMINATED), 747dd252788645e940eada959bdde927426e2531c9Paul Duffin listener.getStateHistory()); 751d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert } 761d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert 771d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert public void testNoOpServiceStartAndWaitStopAndWait() throws Exception { 781d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert NoOpService service = new NoOpService(); 791d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert 800888a09821a98ac0680fad765217302858e70fa4Paul Duffin service.startAsync().awaitRunning(); 817dd252788645e940eada959bdde927426e2531c9Paul Duffin assertEquals(State.RUNNING, service.state()); 821d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert 830888a09821a98ac0680fad765217302858e70fa4Paul Duffin service.stopAsync().awaitTerminated(); 847dd252788645e940eada959bdde927426e2531c9Paul Duffin assertEquals(State.TERMINATED, service.state()); 851d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert } 861d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert 870888a09821a98ac0680fad765217302858e70fa4Paul Duffin public void testNoOpServiceStartAsyncAndAwaitStopAsyncAndAwait() throws Exception { 880888a09821a98ac0680fad765217302858e70fa4Paul Duffin NoOpService service = new NoOpService(); 890888a09821a98ac0680fad765217302858e70fa4Paul Duffin 900888a09821a98ac0680fad765217302858e70fa4Paul Duffin service.startAsync().awaitRunning(); 910888a09821a98ac0680fad765217302858e70fa4Paul Duffin assertEquals(State.RUNNING, service.state()); 920888a09821a98ac0680fad765217302858e70fa4Paul Duffin 930888a09821a98ac0680fad765217302858e70fa4Paul Duffin service.stopAsync().awaitTerminated(); 940888a09821a98ac0680fad765217302858e70fa4Paul Duffin assertEquals(State.TERMINATED, service.state()); 950888a09821a98ac0680fad765217302858e70fa4Paul Duffin } 960888a09821a98ac0680fad765217302858e70fa4Paul Duffin 970888a09821a98ac0680fad765217302858e70fa4Paul Duffin public void testNoOpServiceStopIdempotence() throws Exception { 981d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert NoOpService service = new NoOpService(); 997dd252788645e940eada959bdde927426e2531c9Paul Duffin RecordingListener listener = RecordingListener.record(service); 1000888a09821a98ac0680fad765217302858e70fa4Paul Duffin service.startAsync().awaitRunning(); 1017dd252788645e940eada959bdde927426e2531c9Paul Duffin assertEquals(State.RUNNING, service.state()); 1021d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert 1030888a09821a98ac0680fad765217302858e70fa4Paul Duffin service.stopAsync(); 1040888a09821a98ac0680fad765217302858e70fa4Paul Duffin service.stopAsync(); 1057dd252788645e940eada959bdde927426e2531c9Paul Duffin assertEquals(State.TERMINATED, service.state()); 1067dd252788645e940eada959bdde927426e2531c9Paul Duffin assertEquals( 1077dd252788645e940eada959bdde927426e2531c9Paul Duffin ImmutableList.of( 1087dd252788645e940eada959bdde927426e2531c9Paul Duffin State.STARTING, 1097dd252788645e940eada959bdde927426e2531c9Paul Duffin State.RUNNING, 1107dd252788645e940eada959bdde927426e2531c9Paul Duffin State.STOPPING, 1117dd252788645e940eada959bdde927426e2531c9Paul Duffin State.TERMINATED), 1127dd252788645e940eada959bdde927426e2531c9Paul Duffin listener.getStateHistory()); 1131d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert } 1141d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert 1150888a09821a98ac0680fad765217302858e70fa4Paul Duffin public void testNoOpServiceStopIdempotenceAfterWait() throws Exception { 1161d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert NoOpService service = new NoOpService(); 1171d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert 1180888a09821a98ac0680fad765217302858e70fa4Paul Duffin service.startAsync().awaitRunning(); 1191d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert 1200888a09821a98ac0680fad765217302858e70fa4Paul Duffin service.stopAsync().awaitTerminated(); 1210888a09821a98ac0680fad765217302858e70fa4Paul Duffin service.stopAsync(); 1227dd252788645e940eada959bdde927426e2531c9Paul Duffin assertEquals(State.TERMINATED, service.state()); 1231d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert } 1241d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert 1250888a09821a98ac0680fad765217302858e70fa4Paul Duffin public void testNoOpServiceStopIdempotenceDoubleWait() throws Exception { 1261d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert NoOpService service = new NoOpService(); 1271d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert 1280888a09821a98ac0680fad765217302858e70fa4Paul Duffin service.startAsync().awaitRunning(); 1297dd252788645e940eada959bdde927426e2531c9Paul Duffin assertEquals(State.RUNNING, service.state()); 1301d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert 1310888a09821a98ac0680fad765217302858e70fa4Paul Duffin service.stopAsync().awaitTerminated(); 1320888a09821a98ac0680fad765217302858e70fa4Paul Duffin service.stopAsync().awaitTerminated(); 1337dd252788645e940eada959bdde927426e2531c9Paul Duffin assertEquals(State.TERMINATED, service.state()); 1341d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert } 1351d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert 1361d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert public void testNoOpServiceStartStopAndWaitUninterruptible() 1371d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert throws Exception { 1381d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert NoOpService service = new NoOpService(); 1391d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert 1401d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert currentThread().interrupt(); 1411d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert try { 1420888a09821a98ac0680fad765217302858e70fa4Paul Duffin service.startAsync().awaitRunning(); 1437dd252788645e940eada959bdde927426e2531c9Paul Duffin assertEquals(State.RUNNING, service.state()); 1441d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert 1450888a09821a98ac0680fad765217302858e70fa4Paul Duffin service.stopAsync().awaitTerminated(); 1467dd252788645e940eada959bdde927426e2531c9Paul Duffin assertEquals(State.TERMINATED, service.state()); 1471d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert 1481d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert assertTrue(currentThread().isInterrupted()); 1491d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert } finally { 1501d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert Thread.interrupted(); // clear interrupt for future tests 1511d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert } 1521d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert } 1531d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert 1541d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert private static class NoOpService extends AbstractService { 1551d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert boolean running = false; 1561d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert 1571d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert @Override protected void doStart() { 1581d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert assertFalse(running); 1591d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert running = true; 1601d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert notifyStarted(); 1611d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert } 1621d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert 1631d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert @Override protected void doStop() { 1641d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert assertTrue(running); 1651d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert running = false; 1661d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert notifyStopped(); 1671d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert } 1681d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert } 1691d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert 1707dd252788645e940eada959bdde927426e2531c9Paul Duffin public void testManualServiceStartStop() throws Exception { 1711d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert ManualSwitchedService service = new ManualSwitchedService(); 1727dd252788645e940eada959bdde927426e2531c9Paul Duffin RecordingListener listener = RecordingListener.record(service); 1731d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert 1740888a09821a98ac0680fad765217302858e70fa4Paul Duffin service.startAsync(); 1757dd252788645e940eada959bdde927426e2531c9Paul Duffin assertEquals(State.STARTING, service.state()); 1761d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert assertFalse(service.isRunning()); 1771d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert assertTrue(service.doStartCalled); 1781d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert 1791d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert service.notifyStarted(); // usually this would be invoked by another thread 1807dd252788645e940eada959bdde927426e2531c9Paul Duffin assertEquals(State.RUNNING, service.state()); 1811d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert assertTrue(service.isRunning()); 1821d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert 1830888a09821a98ac0680fad765217302858e70fa4Paul Duffin service.stopAsync(); 1847dd252788645e940eada959bdde927426e2531c9Paul Duffin assertEquals(State.STOPPING, service.state()); 1851d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert assertFalse(service.isRunning()); 1861d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert assertTrue(service.doStopCalled); 1871d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert 1881d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert service.notifyStopped(); // usually this would be invoked by another thread 1897dd252788645e940eada959bdde927426e2531c9Paul Duffin assertEquals(State.TERMINATED, service.state()); 1901d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert assertFalse(service.isRunning()); 1917dd252788645e940eada959bdde927426e2531c9Paul Duffin assertEquals( 1927dd252788645e940eada959bdde927426e2531c9Paul Duffin ImmutableList.of( 1937dd252788645e940eada959bdde927426e2531c9Paul Duffin State.STARTING, 1947dd252788645e940eada959bdde927426e2531c9Paul Duffin State.RUNNING, 1957dd252788645e940eada959bdde927426e2531c9Paul Duffin State.STOPPING, 1967dd252788645e940eada959bdde927426e2531c9Paul Duffin State.TERMINATED), 1977dd252788645e940eada959bdde927426e2531c9Paul Duffin listener.getStateHistory()); 1987dd252788645e940eada959bdde927426e2531c9Paul Duffin 1991d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert } 2001d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert 2017dd252788645e940eada959bdde927426e2531c9Paul Duffin public void testManualServiceNotifyStoppedWhileRunning() throws Exception { 2021d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert ManualSwitchedService service = new ManualSwitchedService(); 2037dd252788645e940eada959bdde927426e2531c9Paul Duffin RecordingListener listener = RecordingListener.record(service); 2041d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert 2050888a09821a98ac0680fad765217302858e70fa4Paul Duffin service.startAsync(); 2067dd252788645e940eada959bdde927426e2531c9Paul Duffin service.notifyStarted(); 2077dd252788645e940eada959bdde927426e2531c9Paul Duffin service.notifyStopped(); 2087dd252788645e940eada959bdde927426e2531c9Paul Duffin assertEquals(State.TERMINATED, service.state()); 2097dd252788645e940eada959bdde927426e2531c9Paul Duffin assertFalse(service.isRunning()); 2107dd252788645e940eada959bdde927426e2531c9Paul Duffin assertFalse(service.doStopCalled); 2117dd252788645e940eada959bdde927426e2531c9Paul Duffin 2127dd252788645e940eada959bdde927426e2531c9Paul Duffin assertEquals( 2137dd252788645e940eada959bdde927426e2531c9Paul Duffin ImmutableList.of( 2147dd252788645e940eada959bdde927426e2531c9Paul Duffin State.STARTING, 2157dd252788645e940eada959bdde927426e2531c9Paul Duffin State.RUNNING, 2167dd252788645e940eada959bdde927426e2531c9Paul Duffin State.TERMINATED), 2177dd252788645e940eada959bdde927426e2531c9Paul Duffin listener.getStateHistory()); 2187dd252788645e940eada959bdde927426e2531c9Paul Duffin } 2197dd252788645e940eada959bdde927426e2531c9Paul Duffin 2207dd252788645e940eada959bdde927426e2531c9Paul Duffin public void testManualServiceStopWhileStarting() throws Exception { 2217dd252788645e940eada959bdde927426e2531c9Paul Duffin ManualSwitchedService service = new ManualSwitchedService(); 2227dd252788645e940eada959bdde927426e2531c9Paul Duffin RecordingListener listener = RecordingListener.record(service); 2237dd252788645e940eada959bdde927426e2531c9Paul Duffin 2240888a09821a98ac0680fad765217302858e70fa4Paul Duffin service.startAsync(); 2257dd252788645e940eada959bdde927426e2531c9Paul Duffin assertEquals(State.STARTING, service.state()); 2261d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert assertFalse(service.isRunning()); 2271d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert assertTrue(service.doStartCalled); 2281d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert 2290888a09821a98ac0680fad765217302858e70fa4Paul Duffin service.stopAsync(); 2307dd252788645e940eada959bdde927426e2531c9Paul Duffin assertEquals(State.STOPPING, service.state()); 2311d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert assertFalse(service.isRunning()); 2321d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert assertFalse(service.doStopCalled); 2331d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert 2341d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert service.notifyStarted(); 2357dd252788645e940eada959bdde927426e2531c9Paul Duffin assertEquals(State.STOPPING, service.state()); 2361d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert assertFalse(service.isRunning()); 2371d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert assertTrue(service.doStopCalled); 2381d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert 2391d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert service.notifyStopped(); 2407dd252788645e940eada959bdde927426e2531c9Paul Duffin assertEquals(State.TERMINATED, service.state()); 2417dd252788645e940eada959bdde927426e2531c9Paul Duffin assertFalse(service.isRunning()); 2427dd252788645e940eada959bdde927426e2531c9Paul Duffin assertEquals( 2437dd252788645e940eada959bdde927426e2531c9Paul Duffin ImmutableList.of( 2447dd252788645e940eada959bdde927426e2531c9Paul Duffin State.STARTING, 2457dd252788645e940eada959bdde927426e2531c9Paul Duffin State.STOPPING, 2467dd252788645e940eada959bdde927426e2531c9Paul Duffin State.TERMINATED), 2477dd252788645e940eada959bdde927426e2531c9Paul Duffin listener.getStateHistory()); 2487dd252788645e940eada959bdde927426e2531c9Paul Duffin } 2497dd252788645e940eada959bdde927426e2531c9Paul Duffin 2500888a09821a98ac0680fad765217302858e70fa4Paul Duffin /** 2510888a09821a98ac0680fad765217302858e70fa4Paul Duffin * This tests for a bug where if {@link Service#stopAsync()} was called while the service was 2520888a09821a98ac0680fad765217302858e70fa4Paul Duffin * {@link State#STARTING} more than once, the {@link Listener#stopping(State)} callback would get 2530888a09821a98ac0680fad765217302858e70fa4Paul Duffin * called multiple times. 2540888a09821a98ac0680fad765217302858e70fa4Paul Duffin */ 2550888a09821a98ac0680fad765217302858e70fa4Paul Duffin public void testManualServiceStopMultipleTimesWhileStarting() throws Exception { 2560888a09821a98ac0680fad765217302858e70fa4Paul Duffin ManualSwitchedService service = new ManualSwitchedService(); 2570888a09821a98ac0680fad765217302858e70fa4Paul Duffin final AtomicInteger stopppingCount = new AtomicInteger(); 2580888a09821a98ac0680fad765217302858e70fa4Paul Duffin service.addListener(new Listener() { 2590888a09821a98ac0680fad765217302858e70fa4Paul Duffin @Override public void stopping(State from) { 2600888a09821a98ac0680fad765217302858e70fa4Paul Duffin stopppingCount.incrementAndGet(); 2610888a09821a98ac0680fad765217302858e70fa4Paul Duffin } 2623ecfa412eddc4b084663f38d562537b86b9734d5Paul Duffin }, directExecutor()); 2630888a09821a98ac0680fad765217302858e70fa4Paul Duffin 2640888a09821a98ac0680fad765217302858e70fa4Paul Duffin service.startAsync(); 2650888a09821a98ac0680fad765217302858e70fa4Paul Duffin service.stopAsync(); 2660888a09821a98ac0680fad765217302858e70fa4Paul Duffin assertEquals(1, stopppingCount.get()); 2670888a09821a98ac0680fad765217302858e70fa4Paul Duffin service.stopAsync(); 2680888a09821a98ac0680fad765217302858e70fa4Paul Duffin assertEquals(1, stopppingCount.get()); 2690888a09821a98ac0680fad765217302858e70fa4Paul Duffin } 2700888a09821a98ac0680fad765217302858e70fa4Paul Duffin 2717dd252788645e940eada959bdde927426e2531c9Paul Duffin public void testManualServiceStopWhileNew() throws Exception { 2727dd252788645e940eada959bdde927426e2531c9Paul Duffin ManualSwitchedService service = new ManualSwitchedService(); 2737dd252788645e940eada959bdde927426e2531c9Paul Duffin RecordingListener listener = RecordingListener.record(service); 2747dd252788645e940eada959bdde927426e2531c9Paul Duffin 2750888a09821a98ac0680fad765217302858e70fa4Paul Duffin service.stopAsync(); 2767dd252788645e940eada959bdde927426e2531c9Paul Duffin assertEquals(State.TERMINATED, service.state()); 2771d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert assertFalse(service.isRunning()); 2787dd252788645e940eada959bdde927426e2531c9Paul Duffin assertFalse(service.doStartCalled); 2797dd252788645e940eada959bdde927426e2531c9Paul Duffin assertFalse(service.doStopCalled); 2807dd252788645e940eada959bdde927426e2531c9Paul Duffin assertEquals(ImmutableList.of(State.TERMINATED), listener.getStateHistory()); 2817dd252788645e940eada959bdde927426e2531c9Paul Duffin } 2827dd252788645e940eada959bdde927426e2531c9Paul Duffin 2837dd252788645e940eada959bdde927426e2531c9Paul Duffin public void testManualServiceFailWhileStarting() throws Exception { 2847dd252788645e940eada959bdde927426e2531c9Paul Duffin ManualSwitchedService service = new ManualSwitchedService(); 2857dd252788645e940eada959bdde927426e2531c9Paul Duffin RecordingListener listener = RecordingListener.record(service); 2860888a09821a98ac0680fad765217302858e70fa4Paul Duffin service.startAsync(); 2877dd252788645e940eada959bdde927426e2531c9Paul Duffin service.notifyFailed(EXCEPTION); 2887dd252788645e940eada959bdde927426e2531c9Paul Duffin assertEquals(ImmutableList.of(State.STARTING, State.FAILED), listener.getStateHistory()); 2897dd252788645e940eada959bdde927426e2531c9Paul Duffin } 2907dd252788645e940eada959bdde927426e2531c9Paul Duffin 2917dd252788645e940eada959bdde927426e2531c9Paul Duffin public void testManualServiceFailWhileRunning() throws Exception { 2927dd252788645e940eada959bdde927426e2531c9Paul Duffin ManualSwitchedService service = new ManualSwitchedService(); 2937dd252788645e940eada959bdde927426e2531c9Paul Duffin RecordingListener listener = RecordingListener.record(service); 2940888a09821a98ac0680fad765217302858e70fa4Paul Duffin service.startAsync(); 2957dd252788645e940eada959bdde927426e2531c9Paul Duffin service.notifyStarted(); 2967dd252788645e940eada959bdde927426e2531c9Paul Duffin service.notifyFailed(EXCEPTION); 2977dd252788645e940eada959bdde927426e2531c9Paul Duffin assertEquals(ImmutableList.of(State.STARTING, State.RUNNING, State.FAILED), 2987dd252788645e940eada959bdde927426e2531c9Paul Duffin listener.getStateHistory()); 2997dd252788645e940eada959bdde927426e2531c9Paul Duffin } 3007dd252788645e940eada959bdde927426e2531c9Paul Duffin 3017dd252788645e940eada959bdde927426e2531c9Paul Duffin public void testManualServiceFailWhileStopping() throws Exception { 3027dd252788645e940eada959bdde927426e2531c9Paul Duffin ManualSwitchedService service = new ManualSwitchedService(); 3037dd252788645e940eada959bdde927426e2531c9Paul Duffin RecordingListener listener = RecordingListener.record(service); 3040888a09821a98ac0680fad765217302858e70fa4Paul Duffin service.startAsync(); 3057dd252788645e940eada959bdde927426e2531c9Paul Duffin service.notifyStarted(); 3060888a09821a98ac0680fad765217302858e70fa4Paul Duffin service.stopAsync(); 3077dd252788645e940eada959bdde927426e2531c9Paul Duffin service.notifyFailed(EXCEPTION); 3087dd252788645e940eada959bdde927426e2531c9Paul Duffin assertEquals(ImmutableList.of(State.STARTING, State.RUNNING, State.STOPPING, State.FAILED), 3097dd252788645e940eada959bdde927426e2531c9Paul Duffin listener.getStateHistory()); 3101d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert } 3111d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert 3121d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert public void testManualServiceUnrequestedStop() { 3131d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert ManualSwitchedService service = new ManualSwitchedService(); 3141d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert 3150888a09821a98ac0680fad765217302858e70fa4Paul Duffin service.startAsync(); 3161d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert 3171d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert service.notifyStarted(); 3187dd252788645e940eada959bdde927426e2531c9Paul Duffin assertEquals(State.RUNNING, service.state()); 3191d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert assertTrue(service.isRunning()); 3201d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert assertFalse(service.doStopCalled); 3211d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert 3221d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert service.notifyStopped(); 3237dd252788645e940eada959bdde927426e2531c9Paul Duffin assertEquals(State.TERMINATED, service.state()); 3241d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert assertFalse(service.isRunning()); 3251d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert assertFalse(service.doStopCalled); 3261d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert } 3271d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert 3281d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert /** 3291d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * The user of this service should call {@link #notifyStarted} and {@link 3300888a09821a98ac0680fad765217302858e70fa4Paul Duffin * #notifyStopped} after calling {@link #startAsync} and {@link #stopAsync}. 3311d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert */ 3321d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert private static class ManualSwitchedService extends AbstractService { 3331d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert boolean doStartCalled = false; 3341d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert boolean doStopCalled = false; 3351d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert 3361d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert @Override protected void doStart() { 3371d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert assertFalse(doStartCalled); 3381d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert doStartCalled = true; 3391d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert } 3401d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert 3411d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert @Override protected void doStop() { 3421d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert assertFalse(doStopCalled); 3431d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert doStopCalled = true; 3441d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert } 3451d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert } 3461d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert 3470888a09821a98ac0680fad765217302858e70fa4Paul Duffin public void testAwaitTerminated() throws Exception { 3480888a09821a98ac0680fad765217302858e70fa4Paul Duffin final NoOpService service = new NoOpService(); 3490888a09821a98ac0680fad765217302858e70fa4Paul Duffin Thread waiter = new Thread() { 3500888a09821a98ac0680fad765217302858e70fa4Paul Duffin @Override public void run() { 3510888a09821a98ac0680fad765217302858e70fa4Paul Duffin service.awaitTerminated(); 3520888a09821a98ac0680fad765217302858e70fa4Paul Duffin } 3530888a09821a98ac0680fad765217302858e70fa4Paul Duffin }; 3540888a09821a98ac0680fad765217302858e70fa4Paul Duffin waiter.start(); 3550888a09821a98ac0680fad765217302858e70fa4Paul Duffin service.startAsync().awaitRunning(); 3560888a09821a98ac0680fad765217302858e70fa4Paul Duffin assertEquals(State.RUNNING, service.state()); 3570888a09821a98ac0680fad765217302858e70fa4Paul Duffin service.stopAsync(); 3580888a09821a98ac0680fad765217302858e70fa4Paul Duffin waiter.join(LONG_TIMEOUT_MILLIS); // ensure that the await in the other thread is triggered 3590888a09821a98ac0680fad765217302858e70fa4Paul Duffin assertFalse(waiter.isAlive()); 3600888a09821a98ac0680fad765217302858e70fa4Paul Duffin } 3610888a09821a98ac0680fad765217302858e70fa4Paul Duffin 3620888a09821a98ac0680fad765217302858e70fa4Paul Duffin public void testAwaitTerminated_FailedService() throws Exception { 3630888a09821a98ac0680fad765217302858e70fa4Paul Duffin final ManualSwitchedService service = new ManualSwitchedService(); 3640888a09821a98ac0680fad765217302858e70fa4Paul Duffin final AtomicReference<Throwable> exception = Atomics.newReference(); 3650888a09821a98ac0680fad765217302858e70fa4Paul Duffin Thread waiter = new Thread() { 3660888a09821a98ac0680fad765217302858e70fa4Paul Duffin @Override public void run() { 3670888a09821a98ac0680fad765217302858e70fa4Paul Duffin try { 3680888a09821a98ac0680fad765217302858e70fa4Paul Duffin service.awaitTerminated(); 3690888a09821a98ac0680fad765217302858e70fa4Paul Duffin fail("Expected an IllegalStateException"); 3700888a09821a98ac0680fad765217302858e70fa4Paul Duffin } catch (Throwable t) { 3710888a09821a98ac0680fad765217302858e70fa4Paul Duffin exception.set(t); 3720888a09821a98ac0680fad765217302858e70fa4Paul Duffin } 3730888a09821a98ac0680fad765217302858e70fa4Paul Duffin } 3740888a09821a98ac0680fad765217302858e70fa4Paul Duffin }; 3750888a09821a98ac0680fad765217302858e70fa4Paul Duffin waiter.start(); 3760888a09821a98ac0680fad765217302858e70fa4Paul Duffin service.startAsync(); 3770888a09821a98ac0680fad765217302858e70fa4Paul Duffin service.notifyStarted(); 3780888a09821a98ac0680fad765217302858e70fa4Paul Duffin assertEquals(State.RUNNING, service.state()); 3790888a09821a98ac0680fad765217302858e70fa4Paul Duffin service.notifyFailed(EXCEPTION); 3800888a09821a98ac0680fad765217302858e70fa4Paul Duffin assertEquals(State.FAILED, service.state()); 3810888a09821a98ac0680fad765217302858e70fa4Paul Duffin waiter.join(LONG_TIMEOUT_MILLIS); 3820888a09821a98ac0680fad765217302858e70fa4Paul Duffin assertFalse(waiter.isAlive()); 3830888a09821a98ac0680fad765217302858e70fa4Paul Duffin assertTrue(exception.get() instanceof IllegalStateException); 3840888a09821a98ac0680fad765217302858e70fa4Paul Duffin assertEquals(EXCEPTION, exception.get().getCause()); 3850888a09821a98ac0680fad765217302858e70fa4Paul Duffin } 3860888a09821a98ac0680fad765217302858e70fa4Paul Duffin 3871d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert public void testThreadedServiceStartAndWaitStopAndWait() throws Throwable { 3881d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert ThreadedService service = new ThreadedService(); 3897dd252788645e940eada959bdde927426e2531c9Paul Duffin RecordingListener listener = RecordingListener.record(service); 3900888a09821a98ac0680fad765217302858e70fa4Paul Duffin service.startAsync().awaitRunning(); 3917dd252788645e940eada959bdde927426e2531c9Paul Duffin assertEquals(State.RUNNING, service.state()); 3921d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert 3931d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert service.awaitRunChecks(); 3941d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert 3950888a09821a98ac0680fad765217302858e70fa4Paul Duffin service.stopAsync().awaitTerminated(); 3967dd252788645e940eada959bdde927426e2531c9Paul Duffin assertEquals(State.TERMINATED, service.state()); 3971d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert 3981d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert throwIfSet(thrownByExecutionThread); 3997dd252788645e940eada959bdde927426e2531c9Paul Duffin assertEquals( 4007dd252788645e940eada959bdde927426e2531c9Paul Duffin ImmutableList.of( 4017dd252788645e940eada959bdde927426e2531c9Paul Duffin State.STARTING, 4027dd252788645e940eada959bdde927426e2531c9Paul Duffin State.RUNNING, 4037dd252788645e940eada959bdde927426e2531c9Paul Duffin State.STOPPING, 4047dd252788645e940eada959bdde927426e2531c9Paul Duffin State.TERMINATED), 4057dd252788645e940eada959bdde927426e2531c9Paul Duffin listener.getStateHistory()); 4061d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert } 4071d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert 4080888a09821a98ac0680fad765217302858e70fa4Paul Duffin public void testThreadedServiceStopIdempotence() throws Throwable { 4091d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert ThreadedService service = new ThreadedService(); 4101d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert 4110888a09821a98ac0680fad765217302858e70fa4Paul Duffin service.startAsync().awaitRunning(); 4127dd252788645e940eada959bdde927426e2531c9Paul Duffin assertEquals(State.RUNNING, service.state()); 4131d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert 4141d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert service.awaitRunChecks(); 4151d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert 4160888a09821a98ac0680fad765217302858e70fa4Paul Duffin service.stopAsync(); 4170888a09821a98ac0680fad765217302858e70fa4Paul Duffin service.stopAsync().awaitTerminated(); 4187dd252788645e940eada959bdde927426e2531c9Paul Duffin assertEquals(State.TERMINATED, service.state()); 4191d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert 4201d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert throwIfSet(thrownByExecutionThread); 4211d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert } 4221d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert 4230888a09821a98ac0680fad765217302858e70fa4Paul Duffin public void testThreadedServiceStopIdempotenceAfterWait() 4241d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert throws Throwable { 4251d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert ThreadedService service = new ThreadedService(); 4261d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert 4270888a09821a98ac0680fad765217302858e70fa4Paul Duffin service.startAsync().awaitRunning(); 4287dd252788645e940eada959bdde927426e2531c9Paul Duffin assertEquals(State.RUNNING, service.state()); 4291d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert 4301d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert service.awaitRunChecks(); 4311d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert 4320888a09821a98ac0680fad765217302858e70fa4Paul Duffin service.stopAsync().awaitTerminated(); 4330888a09821a98ac0680fad765217302858e70fa4Paul Duffin service.stopAsync(); 4347dd252788645e940eada959bdde927426e2531c9Paul Duffin assertEquals(State.TERMINATED, service.state()); 4351d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert 4361d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert executionThread.join(); 4371d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert 4381d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert throwIfSet(thrownByExecutionThread); 4391d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert } 4401d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert 4410888a09821a98ac0680fad765217302858e70fa4Paul Duffin public void testThreadedServiceStopIdempotenceDoubleWait() 4421d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert throws Throwable { 4431d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert ThreadedService service = new ThreadedService(); 4441d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert 4450888a09821a98ac0680fad765217302858e70fa4Paul Duffin service.startAsync().awaitRunning(); 4467dd252788645e940eada959bdde927426e2531c9Paul Duffin assertEquals(State.RUNNING, service.state()); 4471d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert 4481d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert service.awaitRunChecks(); 4491d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert 4500888a09821a98ac0680fad765217302858e70fa4Paul Duffin service.stopAsync().awaitTerminated(); 4510888a09821a98ac0680fad765217302858e70fa4Paul Duffin service.stopAsync().awaitTerminated(); 4527dd252788645e940eada959bdde927426e2531c9Paul Duffin assertEquals(State.TERMINATED, service.state()); 4531d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert 4541d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert throwIfSet(thrownByExecutionThread); 4551d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert } 4561d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert 4577dd252788645e940eada959bdde927426e2531c9Paul Duffin public void testManualServiceFailureIdempotence() { 4587dd252788645e940eada959bdde927426e2531c9Paul Duffin ManualSwitchedService service = new ManualSwitchedService(); 4597dd252788645e940eada959bdde927426e2531c9Paul Duffin RecordingListener.record(service); 4600888a09821a98ac0680fad765217302858e70fa4Paul Duffin service.startAsync(); 4617dd252788645e940eada959bdde927426e2531c9Paul Duffin service.notifyFailed(new Exception("1")); 4627dd252788645e940eada959bdde927426e2531c9Paul Duffin service.notifyFailed(new Exception("2")); 4630888a09821a98ac0680fad765217302858e70fa4Paul Duffin assertEquals("1", service.failureCause().getMessage()); 4647dd252788645e940eada959bdde927426e2531c9Paul Duffin try { 4650888a09821a98ac0680fad765217302858e70fa4Paul Duffin service.awaitRunning(); 4667dd252788645e940eada959bdde927426e2531c9Paul Duffin fail(); 4670888a09821a98ac0680fad765217302858e70fa4Paul Duffin } catch (IllegalStateException e) { 4687dd252788645e940eada959bdde927426e2531c9Paul Duffin assertEquals("1", e.getCause().getMessage()); 4697dd252788645e940eada959bdde927426e2531c9Paul Duffin } 4707dd252788645e940eada959bdde927426e2531c9Paul Duffin } 4717dd252788645e940eada959bdde927426e2531c9Paul Duffin 4721d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert private class ThreadedService extends AbstractService { 4731d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert final CountDownLatch hasConfirmedIsRunning = new CountDownLatch(1); 4741d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert 4751d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert /* 4761d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * The main test thread tries to stop() the service shortly after 4771d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * confirming that it is running. Meanwhile, the service itself is trying 4781d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * to confirm that it is running. If the main thread's stop() call happens 4791d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * before it has the chance, the test will fail. To avoid this, the main 4801d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * thread calls this method, which waits until the service has performed 4811d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * its own "running" check. 4821d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert */ 4831d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert void awaitRunChecks() throws InterruptedException { 4841d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert assertTrue("Service thread hasn't finished its checks. " 4851d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert + "Exception status (possibly stale): " + thrownByExecutionThread, 4861d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert hasConfirmedIsRunning.await(10, SECONDS)); 4871d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert } 4881d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert 4891d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert @Override protected void doStart() { 4901d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert assertEquals(State.STARTING, state()); 4911d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert invokeOnExecutionThreadForTest(new Runnable() { 4921d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert @Override public void run() { 4931d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert assertEquals(State.STARTING, state()); 4941d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert notifyStarted(); 4951d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert assertEquals(State.RUNNING, state()); 4961d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert hasConfirmedIsRunning.countDown(); 4971d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert } 4981d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert }); 4991d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert } 5001d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert 5011d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert @Override protected void doStop() { 5021d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert assertEquals(State.STOPPING, state()); 5031d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert invokeOnExecutionThreadForTest(new Runnable() { 5041d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert @Override public void run() { 5051d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert assertEquals(State.STOPPING, state()); 5061d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert notifyStopped(); 5071d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert assertEquals(State.TERMINATED, state()); 5081d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert } 5091d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert }); 5101d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert } 5111d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert } 5121d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert 5131d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert private void invokeOnExecutionThreadForTest(Runnable runnable) { 5141d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert executionThread = new Thread(runnable); 5151d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert executionThread.setUncaughtExceptionHandler(new UncaughtExceptionHandler() { 5161d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert @Override 5171d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert public void uncaughtException(Thread thread, Throwable e) { 5181d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert thrownByExecutionThread = e; 5191d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert } 5201d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert }); 5211d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert executionThread.start(); 5221d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert } 5231d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert 5241d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert private static void throwIfSet(Throwable t) throws Throwable { 5251d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert if (t != null) { 5261d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert throw t; 5271d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert } 5281d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert } 5291d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert 5301d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert public void testStopUnstartedService() throws Exception { 5311d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert NoOpService service = new NoOpService(); 5327dd252788645e940eada959bdde927426e2531c9Paul Duffin RecordingListener listener = RecordingListener.record(service); 5331d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert 5340888a09821a98ac0680fad765217302858e70fa4Paul Duffin service.stopAsync(); 5357dd252788645e940eada959bdde927426e2531c9Paul Duffin assertEquals(State.TERMINATED, service.state()); 5367dd252788645e940eada959bdde927426e2531c9Paul Duffin 5370888a09821a98ac0680fad765217302858e70fa4Paul Duffin try { 5380888a09821a98ac0680fad765217302858e70fa4Paul Duffin service.startAsync(); 5390888a09821a98ac0680fad765217302858e70fa4Paul Duffin fail(); 5400888a09821a98ac0680fad765217302858e70fa4Paul Duffin } catch (IllegalStateException expected) {} 5417dd252788645e940eada959bdde927426e2531c9Paul Duffin assertEquals(State.TERMINATED, Iterables.getOnlyElement(listener.getStateHistory())); 5427dd252788645e940eada959bdde927426e2531c9Paul Duffin } 5437dd252788645e940eada959bdde927426e2531c9Paul Duffin 5447dd252788645e940eada959bdde927426e2531c9Paul Duffin public void testFailingServiceStartAndWait() throws Exception { 5457dd252788645e940eada959bdde927426e2531c9Paul Duffin StartFailingService service = new StartFailingService(); 5467dd252788645e940eada959bdde927426e2531c9Paul Duffin RecordingListener listener = RecordingListener.record(service); 5477dd252788645e940eada959bdde927426e2531c9Paul Duffin 5487dd252788645e940eada959bdde927426e2531c9Paul Duffin try { 5490888a09821a98ac0680fad765217302858e70fa4Paul Duffin service.startAsync().awaitRunning(); 5507dd252788645e940eada959bdde927426e2531c9Paul Duffin fail(); 5510888a09821a98ac0680fad765217302858e70fa4Paul Duffin } catch (IllegalStateException e) { 5520888a09821a98ac0680fad765217302858e70fa4Paul Duffin assertEquals(EXCEPTION, service.failureCause()); 5537dd252788645e940eada959bdde927426e2531c9Paul Duffin assertEquals(EXCEPTION, e.getCause()); 5547dd252788645e940eada959bdde927426e2531c9Paul Duffin } 5557dd252788645e940eada959bdde927426e2531c9Paul Duffin assertEquals( 5567dd252788645e940eada959bdde927426e2531c9Paul Duffin ImmutableList.of( 5577dd252788645e940eada959bdde927426e2531c9Paul Duffin State.STARTING, 5587dd252788645e940eada959bdde927426e2531c9Paul Duffin State.FAILED), 5597dd252788645e940eada959bdde927426e2531c9Paul Duffin listener.getStateHistory()); 5607dd252788645e940eada959bdde927426e2531c9Paul Duffin } 5617dd252788645e940eada959bdde927426e2531c9Paul Duffin 5627dd252788645e940eada959bdde927426e2531c9Paul Duffin public void testFailingServiceStopAndWait_stopFailing() throws Exception { 5637dd252788645e940eada959bdde927426e2531c9Paul Duffin StopFailingService service = new StopFailingService(); 5647dd252788645e940eada959bdde927426e2531c9Paul Duffin RecordingListener listener = RecordingListener.record(service); 5657dd252788645e940eada959bdde927426e2531c9Paul Duffin 5660888a09821a98ac0680fad765217302858e70fa4Paul Duffin service.startAsync().awaitRunning(); 5677dd252788645e940eada959bdde927426e2531c9Paul Duffin try { 5680888a09821a98ac0680fad765217302858e70fa4Paul Duffin service.stopAsync().awaitTerminated(); 5697dd252788645e940eada959bdde927426e2531c9Paul Duffin fail(); 5700888a09821a98ac0680fad765217302858e70fa4Paul Duffin } catch (IllegalStateException e) { 5710888a09821a98ac0680fad765217302858e70fa4Paul Duffin assertEquals(EXCEPTION, service.failureCause()); 5727dd252788645e940eada959bdde927426e2531c9Paul Duffin assertEquals(EXCEPTION, e.getCause()); 5737dd252788645e940eada959bdde927426e2531c9Paul Duffin } 5747dd252788645e940eada959bdde927426e2531c9Paul Duffin assertEquals( 5757dd252788645e940eada959bdde927426e2531c9Paul Duffin ImmutableList.of( 5767dd252788645e940eada959bdde927426e2531c9Paul Duffin State.STARTING, 5777dd252788645e940eada959bdde927426e2531c9Paul Duffin State.RUNNING, 5787dd252788645e940eada959bdde927426e2531c9Paul Duffin State.STOPPING, 5797dd252788645e940eada959bdde927426e2531c9Paul Duffin State.FAILED), 5807dd252788645e940eada959bdde927426e2531c9Paul Duffin listener.getStateHistory()); 5817dd252788645e940eada959bdde927426e2531c9Paul Duffin } 5827dd252788645e940eada959bdde927426e2531c9Paul Duffin 5830888a09821a98ac0680fad765217302858e70fa4Paul Duffin public void testFailingServiceStopAndWait_runFailing() throws Exception { 5847dd252788645e940eada959bdde927426e2531c9Paul Duffin RunFailingService service = new RunFailingService(); 5857dd252788645e940eada959bdde927426e2531c9Paul Duffin RecordingListener listener = RecordingListener.record(service); 5867dd252788645e940eada959bdde927426e2531c9Paul Duffin 5870888a09821a98ac0680fad765217302858e70fa4Paul Duffin service.startAsync(); 5887dd252788645e940eada959bdde927426e2531c9Paul Duffin try { 5890888a09821a98ac0680fad765217302858e70fa4Paul Duffin service.awaitRunning(); 5907dd252788645e940eada959bdde927426e2531c9Paul Duffin fail(); 5910888a09821a98ac0680fad765217302858e70fa4Paul Duffin } catch (IllegalStateException e) { 5920888a09821a98ac0680fad765217302858e70fa4Paul Duffin assertEquals(EXCEPTION, service.failureCause()); 5930888a09821a98ac0680fad765217302858e70fa4Paul Duffin assertEquals(EXCEPTION, e.getCause()); 5947dd252788645e940eada959bdde927426e2531c9Paul Duffin } 5957dd252788645e940eada959bdde927426e2531c9Paul Duffin assertEquals( 5967dd252788645e940eada959bdde927426e2531c9Paul Duffin ImmutableList.of( 5977dd252788645e940eada959bdde927426e2531c9Paul Duffin State.STARTING, 5987dd252788645e940eada959bdde927426e2531c9Paul Duffin State.RUNNING, 5997dd252788645e940eada959bdde927426e2531c9Paul Duffin State.FAILED), 6007dd252788645e940eada959bdde927426e2531c9Paul Duffin listener.getStateHistory()); 6011d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert } 6021d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert 6031d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert public void testThrowingServiceStartAndWait() throws Exception { 6041d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert StartThrowingService service = new StartThrowingService(); 6057dd252788645e940eada959bdde927426e2531c9Paul Duffin RecordingListener listener = RecordingListener.record(service); 6061d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert 6071d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert try { 6080888a09821a98ac0680fad765217302858e70fa4Paul Duffin service.startAsync().awaitRunning(); 6091d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert fail(); 6100888a09821a98ac0680fad765217302858e70fa4Paul Duffin } catch (IllegalStateException e) { 6110888a09821a98ac0680fad765217302858e70fa4Paul Duffin assertEquals(service.exception, service.failureCause()); 6127dd252788645e940eada959bdde927426e2531c9Paul Duffin assertEquals(service.exception, e.getCause()); 6131d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert } 6147dd252788645e940eada959bdde927426e2531c9Paul Duffin assertEquals( 6157dd252788645e940eada959bdde927426e2531c9Paul Duffin ImmutableList.of( 6167dd252788645e940eada959bdde927426e2531c9Paul Duffin State.STARTING, 6177dd252788645e940eada959bdde927426e2531c9Paul Duffin State.FAILED), 6187dd252788645e940eada959bdde927426e2531c9Paul Duffin listener.getStateHistory()); 6191d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert } 6201d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert 6211d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert public void testThrowingServiceStopAndWait_stopThrowing() throws Exception { 6221d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert StopThrowingService service = new StopThrowingService(); 6237dd252788645e940eada959bdde927426e2531c9Paul Duffin RecordingListener listener = RecordingListener.record(service); 6241d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert 6250888a09821a98ac0680fad765217302858e70fa4Paul Duffin service.startAsync().awaitRunning(); 6261d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert try { 6270888a09821a98ac0680fad765217302858e70fa4Paul Duffin service.stopAsync().awaitTerminated(); 6281d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert fail(); 6290888a09821a98ac0680fad765217302858e70fa4Paul Duffin } catch (IllegalStateException e) { 6300888a09821a98ac0680fad765217302858e70fa4Paul Duffin assertEquals(service.exception, service.failureCause()); 6317dd252788645e940eada959bdde927426e2531c9Paul Duffin assertEquals(service.exception, e.getCause()); 6321d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert } 6337dd252788645e940eada959bdde927426e2531c9Paul Duffin assertEquals( 6347dd252788645e940eada959bdde927426e2531c9Paul Duffin ImmutableList.of( 6357dd252788645e940eada959bdde927426e2531c9Paul Duffin State.STARTING, 6367dd252788645e940eada959bdde927426e2531c9Paul Duffin State.RUNNING, 6377dd252788645e940eada959bdde927426e2531c9Paul Duffin State.STOPPING, 6387dd252788645e940eada959bdde927426e2531c9Paul Duffin State.FAILED), 6397dd252788645e940eada959bdde927426e2531c9Paul Duffin listener.getStateHistory()); 6401d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert } 6411d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert 6421d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert public void testThrowingServiceStopAndWait_runThrowing() throws Exception { 6431d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert RunThrowingService service = new RunThrowingService(); 6447dd252788645e940eada959bdde927426e2531c9Paul Duffin RecordingListener listener = RecordingListener.record(service); 6451d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert 6460888a09821a98ac0680fad765217302858e70fa4Paul Duffin service.startAsync(); 6473c77433663281544363151bf284b0240dfd22a42Paul Duffin try { 6480888a09821a98ac0680fad765217302858e70fa4Paul Duffin service.awaitTerminated(); 6493c77433663281544363151bf284b0240dfd22a42Paul Duffin fail(); 6500888a09821a98ac0680fad765217302858e70fa4Paul Duffin } catch (IllegalStateException e) { 6510888a09821a98ac0680fad765217302858e70fa4Paul Duffin assertEquals(service.exception, service.failureCause()); 6520888a09821a98ac0680fad765217302858e70fa4Paul Duffin assertEquals(service.exception, e.getCause()); 6531d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert } 6547dd252788645e940eada959bdde927426e2531c9Paul Duffin assertEquals( 6557dd252788645e940eada959bdde927426e2531c9Paul Duffin ImmutableList.of( 6567dd252788645e940eada959bdde927426e2531c9Paul Duffin State.STARTING, 6577dd252788645e940eada959bdde927426e2531c9Paul Duffin State.RUNNING, 6587dd252788645e940eada959bdde927426e2531c9Paul Duffin State.FAILED), 6597dd252788645e940eada959bdde927426e2531c9Paul Duffin listener.getStateHistory()); 6601d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert } 6611d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert 6627dd252788645e940eada959bdde927426e2531c9Paul Duffin public void testFailureCause_throwsIfNotFailed() { 6637dd252788645e940eada959bdde927426e2531c9Paul Duffin StopFailingService service = new StopFailingService(); 6647dd252788645e940eada959bdde927426e2531c9Paul Duffin try { 6657dd252788645e940eada959bdde927426e2531c9Paul Duffin service.failureCause(); 6667dd252788645e940eada959bdde927426e2531c9Paul Duffin fail(); 6677dd252788645e940eada959bdde927426e2531c9Paul Duffin } catch (IllegalStateException e) { 6687dd252788645e940eada959bdde927426e2531c9Paul Duffin // expected 6697dd252788645e940eada959bdde927426e2531c9Paul Duffin } 6700888a09821a98ac0680fad765217302858e70fa4Paul Duffin service.startAsync().awaitRunning(); 6717dd252788645e940eada959bdde927426e2531c9Paul Duffin try { 6727dd252788645e940eada959bdde927426e2531c9Paul Duffin service.failureCause(); 6737dd252788645e940eada959bdde927426e2531c9Paul Duffin fail(); 6747dd252788645e940eada959bdde927426e2531c9Paul Duffin } catch (IllegalStateException e) { 6757dd252788645e940eada959bdde927426e2531c9Paul Duffin // expected 6767dd252788645e940eada959bdde927426e2531c9Paul Duffin } 6777dd252788645e940eada959bdde927426e2531c9Paul Duffin try { 6780888a09821a98ac0680fad765217302858e70fa4Paul Duffin service.stopAsync().awaitTerminated(); 6797dd252788645e940eada959bdde927426e2531c9Paul Duffin fail(); 6800888a09821a98ac0680fad765217302858e70fa4Paul Duffin } catch (IllegalStateException e) { 6817dd252788645e940eada959bdde927426e2531c9Paul Duffin assertEquals(EXCEPTION, service.failureCause()); 6827dd252788645e940eada959bdde927426e2531c9Paul Duffin assertEquals(EXCEPTION, e.getCause()); 6837dd252788645e940eada959bdde927426e2531c9Paul Duffin } 6847dd252788645e940eada959bdde927426e2531c9Paul Duffin } 6857dd252788645e940eada959bdde927426e2531c9Paul Duffin 6867dd252788645e940eada959bdde927426e2531c9Paul Duffin public void testAddListenerAfterFailureDoesntCauseDeadlock() throws InterruptedException { 6877dd252788645e940eada959bdde927426e2531c9Paul Duffin final StartFailingService service = new StartFailingService(); 6880888a09821a98ac0680fad765217302858e70fa4Paul Duffin service.startAsync(); 6897dd252788645e940eada959bdde927426e2531c9Paul Duffin assertEquals(State.FAILED, service.state()); 6903ecfa412eddc4b084663f38d562537b86b9734d5Paul Duffin service.addListener(new RecordingListener(service), directExecutor()); 6917dd252788645e940eada959bdde927426e2531c9Paul Duffin Thread thread = new Thread() { 6927dd252788645e940eada959bdde927426e2531c9Paul Duffin @Override public void run() { 6930888a09821a98ac0680fad765217302858e70fa4Paul Duffin // Internally stopAsync() grabs a lock, this could be any such method on AbstractService. 6940888a09821a98ac0680fad765217302858e70fa4Paul Duffin service.stopAsync(); 6957dd252788645e940eada959bdde927426e2531c9Paul Duffin } 6967dd252788645e940eada959bdde927426e2531c9Paul Duffin }; 6977dd252788645e940eada959bdde927426e2531c9Paul Duffin thread.start(); 6980888a09821a98ac0680fad765217302858e70fa4Paul Duffin thread.join(LONG_TIMEOUT_MILLIS); 6997dd252788645e940eada959bdde927426e2531c9Paul Duffin assertFalse(thread + " is deadlocked", thread.isAlive()); 7007dd252788645e940eada959bdde927426e2531c9Paul Duffin } 7017dd252788645e940eada959bdde927426e2531c9Paul Duffin 7027dd252788645e940eada959bdde927426e2531c9Paul Duffin public void testListenerDoesntDeadlockOnStartAndWaitFromRunning() throws Exception { 7037dd252788645e940eada959bdde927426e2531c9Paul Duffin final NoOpThreadedService service = new NoOpThreadedService(); 7047dd252788645e940eada959bdde927426e2531c9Paul Duffin service.addListener(new Listener() { 7057dd252788645e940eada959bdde927426e2531c9Paul Duffin @Override public void running() { 7060888a09821a98ac0680fad765217302858e70fa4Paul Duffin service.awaitRunning(); 7077dd252788645e940eada959bdde927426e2531c9Paul Duffin } 7083ecfa412eddc4b084663f38d562537b86b9734d5Paul Duffin }, directExecutor()); 7090888a09821a98ac0680fad765217302858e70fa4Paul Duffin service.startAsync().awaitRunning(LONG_TIMEOUT_MILLIS, TimeUnit.MILLISECONDS); 7100888a09821a98ac0680fad765217302858e70fa4Paul Duffin service.stopAsync(); 7117dd252788645e940eada959bdde927426e2531c9Paul Duffin } 7127dd252788645e940eada959bdde927426e2531c9Paul Duffin 7137dd252788645e940eada959bdde927426e2531c9Paul Duffin public void testListenerDoesntDeadlockOnStopAndWaitFromTerminated() throws Exception { 7147dd252788645e940eada959bdde927426e2531c9Paul Duffin final NoOpThreadedService service = new NoOpThreadedService(); 7157dd252788645e940eada959bdde927426e2531c9Paul Duffin service.addListener(new Listener() { 7167dd252788645e940eada959bdde927426e2531c9Paul Duffin @Override public void terminated(State from) { 7170888a09821a98ac0680fad765217302858e70fa4Paul Duffin service.stopAsync().awaitTerminated(); 7187dd252788645e940eada959bdde927426e2531c9Paul Duffin } 7193ecfa412eddc4b084663f38d562537b86b9734d5Paul Duffin }, directExecutor()); 7200888a09821a98ac0680fad765217302858e70fa4Paul Duffin service.startAsync().awaitRunning(); 7217dd252788645e940eada959bdde927426e2531c9Paul Duffin 7227dd252788645e940eada959bdde927426e2531c9Paul Duffin Thread thread = new Thread() { 7237dd252788645e940eada959bdde927426e2531c9Paul Duffin @Override public void run() { 7240888a09821a98ac0680fad765217302858e70fa4Paul Duffin service.stopAsync().awaitTerminated(); 7257dd252788645e940eada959bdde927426e2531c9Paul Duffin } 7267dd252788645e940eada959bdde927426e2531c9Paul Duffin }; 7277dd252788645e940eada959bdde927426e2531c9Paul Duffin thread.start(); 7280888a09821a98ac0680fad765217302858e70fa4Paul Duffin thread.join(LONG_TIMEOUT_MILLIS); 7297dd252788645e940eada959bdde927426e2531c9Paul Duffin assertFalse(thread + " is deadlocked", thread.isAlive()); 7307dd252788645e940eada959bdde927426e2531c9Paul Duffin } 7317dd252788645e940eada959bdde927426e2531c9Paul Duffin 7327dd252788645e940eada959bdde927426e2531c9Paul Duffin private static class NoOpThreadedService extends AbstractExecutionThreadService { 7330888a09821a98ac0680fad765217302858e70fa4Paul Duffin final CountDownLatch latch = new CountDownLatch(1); 7340888a09821a98ac0680fad765217302858e70fa4Paul Duffin @Override protected void run() throws Exception { 7350888a09821a98ac0680fad765217302858e70fa4Paul Duffin latch.await(); 7360888a09821a98ac0680fad765217302858e70fa4Paul Duffin } 7370888a09821a98ac0680fad765217302858e70fa4Paul Duffin @Override protected void triggerShutdown() { 7380888a09821a98ac0680fad765217302858e70fa4Paul Duffin latch.countDown(); 7390888a09821a98ac0680fad765217302858e70fa4Paul Duffin } 7407dd252788645e940eada959bdde927426e2531c9Paul Duffin } 7417dd252788645e940eada959bdde927426e2531c9Paul Duffin 7427dd252788645e940eada959bdde927426e2531c9Paul Duffin private static class StartFailingService extends AbstractService { 7433c77433663281544363151bf284b0240dfd22a42Paul Duffin @Override protected void doStart() { 744dbd967a6e5c96cc1a97c5521f88dc1564ba2f81bPaul Duffin notifyFailed(EXCEPTION); 7453c77433663281544363151bf284b0240dfd22a42Paul Duffin } 7463c77433663281544363151bf284b0240dfd22a42Paul Duffin 7473c77433663281544363151bf284b0240dfd22a42Paul Duffin @Override protected void doStop() { 7483c77433663281544363151bf284b0240dfd22a42Paul Duffin fail(); 7493c77433663281544363151bf284b0240dfd22a42Paul Duffin } 7503c77433663281544363151bf284b0240dfd22a42Paul Duffin } 7513c77433663281544363151bf284b0240dfd22a42Paul Duffin 7527dd252788645e940eada959bdde927426e2531c9Paul Duffin private static class RunFailingService extends AbstractService { 7533c77433663281544363151bf284b0240dfd22a42Paul Duffin @Override protected void doStart() { 7543c77433663281544363151bf284b0240dfd22a42Paul Duffin notifyStarted(); 755dbd967a6e5c96cc1a97c5521f88dc1564ba2f81bPaul Duffin notifyFailed(EXCEPTION); 7563c77433663281544363151bf284b0240dfd22a42Paul Duffin } 7573c77433663281544363151bf284b0240dfd22a42Paul Duffin 7583c77433663281544363151bf284b0240dfd22a42Paul Duffin @Override protected void doStop() { 7593c77433663281544363151bf284b0240dfd22a42Paul Duffin fail(); 7603c77433663281544363151bf284b0240dfd22a42Paul Duffin } 7613c77433663281544363151bf284b0240dfd22a42Paul Duffin } 7623c77433663281544363151bf284b0240dfd22a42Paul Duffin 7637dd252788645e940eada959bdde927426e2531c9Paul Duffin private static class StopFailingService extends AbstractService { 7643c77433663281544363151bf284b0240dfd22a42Paul Duffin @Override protected void doStart() { 7653c77433663281544363151bf284b0240dfd22a42Paul Duffin notifyStarted(); 7663c77433663281544363151bf284b0240dfd22a42Paul Duffin } 7673c77433663281544363151bf284b0240dfd22a42Paul Duffin 7683c77433663281544363151bf284b0240dfd22a42Paul Duffin @Override protected void doStop() { 769dbd967a6e5c96cc1a97c5521f88dc1564ba2f81bPaul Duffin notifyFailed(EXCEPTION); 7703c77433663281544363151bf284b0240dfd22a42Paul Duffin } 7713c77433663281544363151bf284b0240dfd22a42Paul Duffin } 7723c77433663281544363151bf284b0240dfd22a42Paul Duffin 7737dd252788645e940eada959bdde927426e2531c9Paul Duffin private static class StartThrowingService extends AbstractService { 7747dd252788645e940eada959bdde927426e2531c9Paul Duffin 7757dd252788645e940eada959bdde927426e2531c9Paul Duffin final RuntimeException exception = new RuntimeException("deliberate"); 7767dd252788645e940eada959bdde927426e2531c9Paul Duffin 7777dd252788645e940eada959bdde927426e2531c9Paul Duffin @Override protected void doStart() { 7787dd252788645e940eada959bdde927426e2531c9Paul Duffin throw exception; 7797dd252788645e940eada959bdde927426e2531c9Paul Duffin } 7807dd252788645e940eada959bdde927426e2531c9Paul Duffin 7817dd252788645e940eada959bdde927426e2531c9Paul Duffin @Override protected void doStop() { 7827dd252788645e940eada959bdde927426e2531c9Paul Duffin fail(); 7837dd252788645e940eada959bdde927426e2531c9Paul Duffin } 7847dd252788645e940eada959bdde927426e2531c9Paul Duffin } 7857dd252788645e940eada959bdde927426e2531c9Paul Duffin 7867dd252788645e940eada959bdde927426e2531c9Paul Duffin private static class RunThrowingService extends AbstractService { 7877dd252788645e940eada959bdde927426e2531c9Paul Duffin 7887dd252788645e940eada959bdde927426e2531c9Paul Duffin final RuntimeException exception = new RuntimeException("deliberate"); 7897dd252788645e940eada959bdde927426e2531c9Paul Duffin 7907dd252788645e940eada959bdde927426e2531c9Paul Duffin @Override protected void doStart() { 7917dd252788645e940eada959bdde927426e2531c9Paul Duffin notifyStarted(); 7927dd252788645e940eada959bdde927426e2531c9Paul Duffin throw exception; 7937dd252788645e940eada959bdde927426e2531c9Paul Duffin } 7947dd252788645e940eada959bdde927426e2531c9Paul Duffin 7957dd252788645e940eada959bdde927426e2531c9Paul Duffin @Override protected void doStop() { 7967dd252788645e940eada959bdde927426e2531c9Paul Duffin fail(); 7977dd252788645e940eada959bdde927426e2531c9Paul Duffin } 7987dd252788645e940eada959bdde927426e2531c9Paul Duffin } 7997dd252788645e940eada959bdde927426e2531c9Paul Duffin 8007dd252788645e940eada959bdde927426e2531c9Paul Duffin private static class StopThrowingService extends AbstractService { 8017dd252788645e940eada959bdde927426e2531c9Paul Duffin 8027dd252788645e940eada959bdde927426e2531c9Paul Duffin final RuntimeException exception = new RuntimeException("deliberate"); 8037dd252788645e940eada959bdde927426e2531c9Paul Duffin 8047dd252788645e940eada959bdde927426e2531c9Paul Duffin @Override protected void doStart() { 8057dd252788645e940eada959bdde927426e2531c9Paul Duffin notifyStarted(); 8067dd252788645e940eada959bdde927426e2531c9Paul Duffin } 8077dd252788645e940eada959bdde927426e2531c9Paul Duffin 8087dd252788645e940eada959bdde927426e2531c9Paul Duffin @Override protected void doStop() { 8097dd252788645e940eada959bdde927426e2531c9Paul Duffin throw exception; 8107dd252788645e940eada959bdde927426e2531c9Paul Duffin } 8117dd252788645e940eada959bdde927426e2531c9Paul Duffin } 8127dd252788645e940eada959bdde927426e2531c9Paul Duffin 8130888a09821a98ac0680fad765217302858e70fa4Paul Duffin private static class RecordingListener extends Listener { 8147dd252788645e940eada959bdde927426e2531c9Paul Duffin static RecordingListener record(Service service) { 8157dd252788645e940eada959bdde927426e2531c9Paul Duffin RecordingListener listener = new RecordingListener(service); 8163ecfa412eddc4b084663f38d562537b86b9734d5Paul Duffin service.addListener(listener, directExecutor()); 8177dd252788645e940eada959bdde927426e2531c9Paul Duffin return listener; 8187dd252788645e940eada959bdde927426e2531c9Paul Duffin } 8197dd252788645e940eada959bdde927426e2531c9Paul Duffin 8207dd252788645e940eada959bdde927426e2531c9Paul Duffin final Service service; 8217dd252788645e940eada959bdde927426e2531c9Paul Duffin 8227dd252788645e940eada959bdde927426e2531c9Paul Duffin RecordingListener(Service service) { 8237dd252788645e940eada959bdde927426e2531c9Paul Duffin this.service = service; 8247dd252788645e940eada959bdde927426e2531c9Paul Duffin } 8257dd252788645e940eada959bdde927426e2531c9Paul Duffin 8267dd252788645e940eada959bdde927426e2531c9Paul Duffin @GuardedBy("this") 8277dd252788645e940eada959bdde927426e2531c9Paul Duffin final List<State> stateHistory = Lists.newArrayList(); 8287dd252788645e940eada959bdde927426e2531c9Paul Duffin final CountDownLatch completionLatch = new CountDownLatch(1); 8297dd252788645e940eada959bdde927426e2531c9Paul Duffin 8307dd252788645e940eada959bdde927426e2531c9Paul Duffin ImmutableList<State> getStateHistory() throws Exception { 8317dd252788645e940eada959bdde927426e2531c9Paul Duffin completionLatch.await(); 8327dd252788645e940eada959bdde927426e2531c9Paul Duffin synchronized (this) { 8337dd252788645e940eada959bdde927426e2531c9Paul Duffin return ImmutableList.copyOf(stateHistory); 8347dd252788645e940eada959bdde927426e2531c9Paul Duffin } 8357dd252788645e940eada959bdde927426e2531c9Paul Duffin } 8367dd252788645e940eada959bdde927426e2531c9Paul Duffin 8377dd252788645e940eada959bdde927426e2531c9Paul Duffin @Override public synchronized void starting() { 8387dd252788645e940eada959bdde927426e2531c9Paul Duffin assertTrue(stateHistory.isEmpty()); 8397dd252788645e940eada959bdde927426e2531c9Paul Duffin assertNotSame(State.NEW, service.state()); 8407dd252788645e940eada959bdde927426e2531c9Paul Duffin stateHistory.add(State.STARTING); 8417dd252788645e940eada959bdde927426e2531c9Paul Duffin } 8427dd252788645e940eada959bdde927426e2531c9Paul Duffin 8437dd252788645e940eada959bdde927426e2531c9Paul Duffin @Override public synchronized void running() { 8447dd252788645e940eada959bdde927426e2531c9Paul Duffin assertEquals(State.STARTING, Iterables.getOnlyElement(stateHistory)); 8457dd252788645e940eada959bdde927426e2531c9Paul Duffin stateHistory.add(State.RUNNING); 8460888a09821a98ac0680fad765217302858e70fa4Paul Duffin service.awaitRunning(); 8477dd252788645e940eada959bdde927426e2531c9Paul Duffin assertNotSame(State.STARTING, service.state()); 8487dd252788645e940eada959bdde927426e2531c9Paul Duffin } 8497dd252788645e940eada959bdde927426e2531c9Paul Duffin 8507dd252788645e940eada959bdde927426e2531c9Paul Duffin @Override public synchronized void stopping(State from) { 8517dd252788645e940eada959bdde927426e2531c9Paul Duffin assertEquals(from, Iterables.getLast(stateHistory)); 8527dd252788645e940eada959bdde927426e2531c9Paul Duffin stateHistory.add(State.STOPPING); 8537dd252788645e940eada959bdde927426e2531c9Paul Duffin if (from == State.STARTING) { 8540888a09821a98ac0680fad765217302858e70fa4Paul Duffin try { 8550888a09821a98ac0680fad765217302858e70fa4Paul Duffin service.awaitRunning(); 8560888a09821a98ac0680fad765217302858e70fa4Paul Duffin fail(); 8570888a09821a98ac0680fad765217302858e70fa4Paul Duffin } catch (IllegalStateException expected) { 8580888a09821a98ac0680fad765217302858e70fa4Paul Duffin assertNull(expected.getCause()); 8590888a09821a98ac0680fad765217302858e70fa4Paul Duffin assertTrue(expected.getMessage().equals( 8600888a09821a98ac0680fad765217302858e70fa4Paul Duffin "Expected the service to be RUNNING, but was STOPPING")); 8610888a09821a98ac0680fad765217302858e70fa4Paul Duffin } 8627dd252788645e940eada959bdde927426e2531c9Paul Duffin } 8637dd252788645e940eada959bdde927426e2531c9Paul Duffin assertNotSame(from, service.state()); 8647dd252788645e940eada959bdde927426e2531c9Paul Duffin } 8657dd252788645e940eada959bdde927426e2531c9Paul Duffin 8667dd252788645e940eada959bdde927426e2531c9Paul Duffin @Override public synchronized void terminated(State from) { 8677dd252788645e940eada959bdde927426e2531c9Paul Duffin assertEquals(from, Iterables.getLast(stateHistory, State.NEW)); 8687dd252788645e940eada959bdde927426e2531c9Paul Duffin stateHistory.add(State.TERMINATED); 8697dd252788645e940eada959bdde927426e2531c9Paul Duffin assertEquals(State.TERMINATED, service.state()); 8707dd252788645e940eada959bdde927426e2531c9Paul Duffin if (from == State.NEW) { 8710888a09821a98ac0680fad765217302858e70fa4Paul Duffin try { 8720888a09821a98ac0680fad765217302858e70fa4Paul Duffin service.awaitRunning(); 8730888a09821a98ac0680fad765217302858e70fa4Paul Duffin fail(); 8740888a09821a98ac0680fad765217302858e70fa4Paul Duffin } catch (IllegalStateException expected) { 8750888a09821a98ac0680fad765217302858e70fa4Paul Duffin assertNull(expected.getCause()); 8760888a09821a98ac0680fad765217302858e70fa4Paul Duffin assertTrue(expected.getMessage().equals( 8770888a09821a98ac0680fad765217302858e70fa4Paul Duffin "Expected the service to be RUNNING, but was TERMINATED")); 8780888a09821a98ac0680fad765217302858e70fa4Paul Duffin } 8797dd252788645e940eada959bdde927426e2531c9Paul Duffin } 8807dd252788645e940eada959bdde927426e2531c9Paul Duffin completionLatch.countDown(); 8817dd252788645e940eada959bdde927426e2531c9Paul Duffin } 8827dd252788645e940eada959bdde927426e2531c9Paul Duffin 8837dd252788645e940eada959bdde927426e2531c9Paul Duffin @Override public synchronized void failed(State from, Throwable failure) { 8847dd252788645e940eada959bdde927426e2531c9Paul Duffin assertEquals(from, Iterables.getLast(stateHistory)); 8857dd252788645e940eada959bdde927426e2531c9Paul Duffin stateHistory.add(State.FAILED); 8867dd252788645e940eada959bdde927426e2531c9Paul Duffin assertEquals(State.FAILED, service.state()); 8870888a09821a98ac0680fad765217302858e70fa4Paul Duffin assertEquals(failure, service.failureCause()); 8887dd252788645e940eada959bdde927426e2531c9Paul Duffin if (from == State.STARTING) { 8897dd252788645e940eada959bdde927426e2531c9Paul Duffin try { 8900888a09821a98ac0680fad765217302858e70fa4Paul Duffin service.awaitRunning(); 8917dd252788645e940eada959bdde927426e2531c9Paul Duffin fail(); 8920888a09821a98ac0680fad765217302858e70fa4Paul Duffin } catch (IllegalStateException e) { 8937dd252788645e940eada959bdde927426e2531c9Paul Duffin assertEquals(failure, e.getCause()); 8947dd252788645e940eada959bdde927426e2531c9Paul Duffin } 8957dd252788645e940eada959bdde927426e2531c9Paul Duffin } 8967dd252788645e940eada959bdde927426e2531c9Paul Duffin try { 8970888a09821a98ac0680fad765217302858e70fa4Paul Duffin service.awaitTerminated(); 8987dd252788645e940eada959bdde927426e2531c9Paul Duffin fail(); 8990888a09821a98ac0680fad765217302858e70fa4Paul Duffin } catch (IllegalStateException e) { 9000888a09821a98ac0680fad765217302858e70fa4Paul Duffin assertEquals(failure, e.getCause()); 9017dd252788645e940eada959bdde927426e2531c9Paul Duffin } 9027dd252788645e940eada959bdde927426e2531c9Paul Duffin completionLatch.countDown(); 9037dd252788645e940eada959bdde927426e2531c9Paul Duffin } 9047dd252788645e940eada959bdde927426e2531c9Paul Duffin } 9057dd252788645e940eada959bdde927426e2531c9Paul Duffin 9067dd252788645e940eada959bdde927426e2531c9Paul Duffin public void testNotifyStartedWhenNotStarting() { 9077dd252788645e940eada959bdde927426e2531c9Paul Duffin AbstractService service = new DefaultService(); 9087dd252788645e940eada959bdde927426e2531c9Paul Duffin try { 9097dd252788645e940eada959bdde927426e2531c9Paul Duffin service.notifyStarted(); 9107dd252788645e940eada959bdde927426e2531c9Paul Duffin fail(); 9117dd252788645e940eada959bdde927426e2531c9Paul Duffin } catch (IllegalStateException expected) {} 9127dd252788645e940eada959bdde927426e2531c9Paul Duffin } 9137dd252788645e940eada959bdde927426e2531c9Paul Duffin 9147dd252788645e940eada959bdde927426e2531c9Paul Duffin public void testNotifyStoppedWhenNotRunning() { 9157dd252788645e940eada959bdde927426e2531c9Paul Duffin AbstractService service = new DefaultService(); 9167dd252788645e940eada959bdde927426e2531c9Paul Duffin try { 9177dd252788645e940eada959bdde927426e2531c9Paul Duffin service.notifyStopped(); 9187dd252788645e940eada959bdde927426e2531c9Paul Duffin fail(); 9197dd252788645e940eada959bdde927426e2531c9Paul Duffin } catch (IllegalStateException expected) {} 9207dd252788645e940eada959bdde927426e2531c9Paul Duffin } 9217dd252788645e940eada959bdde927426e2531c9Paul Duffin 9227dd252788645e940eada959bdde927426e2531c9Paul Duffin public void testNotifyFailedWhenNotStarted() { 9237dd252788645e940eada959bdde927426e2531c9Paul Duffin AbstractService service = new DefaultService(); 9247dd252788645e940eada959bdde927426e2531c9Paul Duffin try { 9257dd252788645e940eada959bdde927426e2531c9Paul Duffin service.notifyFailed(new Exception()); 9267dd252788645e940eada959bdde927426e2531c9Paul Duffin fail(); 9277dd252788645e940eada959bdde927426e2531c9Paul Duffin } catch (IllegalStateException expected) {} 9287dd252788645e940eada959bdde927426e2531c9Paul Duffin } 9297dd252788645e940eada959bdde927426e2531c9Paul Duffin 9307dd252788645e940eada959bdde927426e2531c9Paul Duffin public void testNotifyFailedWhenTerminated() { 9317dd252788645e940eada959bdde927426e2531c9Paul Duffin NoOpService service = new NoOpService(); 9320888a09821a98ac0680fad765217302858e70fa4Paul Duffin service.startAsync().awaitRunning(); 9330888a09821a98ac0680fad765217302858e70fa4Paul Duffin service.stopAsync().awaitTerminated(); 9347dd252788645e940eada959bdde927426e2531c9Paul Duffin try { 9357dd252788645e940eada959bdde927426e2531c9Paul Duffin service.notifyFailed(new Exception()); 9367dd252788645e940eada959bdde927426e2531c9Paul Duffin fail(); 9377dd252788645e940eada959bdde927426e2531c9Paul Duffin } catch (IllegalStateException expected) {} 9387dd252788645e940eada959bdde927426e2531c9Paul Duffin } 9397dd252788645e940eada959bdde927426e2531c9Paul Duffin 9407dd252788645e940eada959bdde927426e2531c9Paul Duffin private static class DefaultService extends AbstractService { 9417dd252788645e940eada959bdde927426e2531c9Paul Duffin @Override protected void doStart() {} 9427dd252788645e940eada959bdde927426e2531c9Paul Duffin @Override protected void doStop() {} 9437dd252788645e940eada959bdde927426e2531c9Paul Duffin } 9447dd252788645e940eada959bdde927426e2531c9Paul Duffin 9451d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert private static final Exception EXCEPTION = new Exception(); 9461d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert} 947