public void testThreadedServiceStartAndWaitStopAndWait() throws Throwable { ThreadedService service = new ThreadedService(); RecordingListener listener = RecordingListener.record(service); service.startAsync().awaitRunning(); assertEquals(State.RUNNING, service.state()); service.awaitRunChecks(); service.stopAsync().awaitTerminated(); assertEquals(State.TERMINATED, service.state()); throwIfSet(thrownByExecutionThread); assertEquals( ImmutableList.of( State.STARTING, State.RUNNING, State.STOPPING, State.TERMINATED), listener.getStateHistory()); }
@Test public void testRun_writesMetrics() throws Exception { Optional<ImmutableList<MetricPoint<?>>> threeBatch = Optional.of(ImmutableList.of(point, point, point)); exporter.startAsync(); insertAndAssert(threeBatch); // Insert another batch in order to block until the exporter has processed the last one insertAndAssert(threeBatch); // Force the exporter to finish so that the verify counts below are deterministic insertAndAssert(poisonPill); try { exporter.awaitTerminated(500, TimeUnit.MILLISECONDS); } catch (TimeoutException timeout) { fail("MetricExporter did not reach the TERMINATED state after receiving a poison pill"); } assertThat(exporter.state()).isNotEqualTo(State.FAILED); verify(writer, times(6)).write(point); verify(writer, times(2)).flush(); }
/** * Implementing classes should invoke this method once their service has stopped. It will cause * the service to transition from {@link State#STOPPING} to {@link State#TERMINATED}. * * @throws IllegalStateException if the service is neither {@link State#STOPPING} nor {@link * State#RUNNING}. */ protected final void notifyStopped() { monitor.enter(); try { // We check the internal state of the snapshot instead of state() directly so we don't allow // notifyStopped() to be called while STARTING, even if stop() has already been called. State previous = snapshot.state; if (previous != STOPPING && previous != RUNNING) { IllegalStateException failure = new IllegalStateException("Cannot notifyStopped() when the service is " + previous); notifyFailed(failure); throw failure; } snapshot = new StateSnapshot(TERMINATED); enqueueTerminatedEvent(previous); } finally { monitor.leave(); dispatchListenerEvents(); } }
public void testNoOpServiceStartStopAndWaitUninterruptible() throws Exception { NoOpService service = new NoOpService(); currentThread().interrupt(); try { service.startAsync().awaitRunning(); assertEquals(State.RUNNING, service.state()); service.stopAsync().awaitTerminated(); assertEquals(State.TERMINATED, service.state()); assertTrue(currentThread().isInterrupted()); } finally { Thread.interrupted(); // clear interrupt for future tests } }
private void enqueueTerminatedEvent(final State from) { switch (from) { case NEW: listeners.enqueue(TERMINATED_FROM_NEW_EVENT); break; case RUNNING: listeners.enqueue(TERMINATED_FROM_RUNNING_EVENT); break; case STOPPING: listeners.enqueue(TERMINATED_FROM_STOPPING_EVENT); break; case STARTING: case TERMINATED: case FAILED: default: throw new AssertionError(); } }
StateSnapshot( State internalState, boolean shutdownWhenStartupFinishes, @Nullable Throwable failure) { checkArgument( !shutdownWhenStartupFinishes || internalState == STARTING, "shudownWhenStartupFinishes can only be set if state is STARTING. Got %s instead.", internalState); checkArgument( !(failure != null ^ internalState == FAILED), "A failure cause should be set if and only if the state is failed. Got %s and %s " + "instead.", internalState, failure); this.state = internalState; this.shutdownWhenStartupFinishes = shutdownWhenStartupFinishes; this.failure = failure; }
public void testNoOpServiceStartStop() throws Exception { NoOpService service = new NoOpService(); RecordingListener listener = RecordingListener.record(service); assertEquals(State.NEW, service.state()); assertFalse(service.isRunning()); assertFalse(service.running); service.startAsync(); assertEquals(State.RUNNING, service.state()); assertTrue(service.isRunning()); assertTrue(service.running); service.stopAsync(); assertEquals(State.TERMINATED, service.state()); assertFalse(service.isRunning()); assertFalse(service.running); assertEquals( ImmutableList.of( State.STARTING, State.RUNNING, State.STOPPING, State.TERMINATED), listener.getStateHistory()); }
public void testServiceStartStop() { Service a = new NoOpService(); Service b = new NoOpService(); ServiceManager manager = new ServiceManager(asList(a, b)); RecordingListener listener = new RecordingListener(); manager.addListener(listener); assertState(manager, Service.State.NEW, a, b); assertFalse(manager.isHealthy()); manager.startAsync().awaitHealthy(); assertState(manager, Service.State.RUNNING, a, b); assertTrue(manager.isHealthy()); assertTrue(listener.healthyCalled); assertFalse(listener.stoppedCalled); assertTrue(listener.failedServices.isEmpty()); manager.stopAsync().awaitStopped(); assertState(manager, Service.State.TERMINATED, a, b); assertFalse(manager.isHealthy()); assertTrue(listener.stoppedCalled); assertTrue(listener.failedServices.isEmpty()); }
/** * This tests for a bug where if {@link Service#stopAsync()} was called while the service was * {@link State#STARTING} more than once, the {@link Listener#stopping(State)} callback would get * called multiple times. */ public void testManualServiceStopMultipleTimesWhileStarting() throws Exception { ManualSwitchedService service = new ManualSwitchedService(); final AtomicInteger stopppingCount = new AtomicInteger(); service.addListener(new Listener() { @Override public void stopping(State from) { stopppingCount.incrementAndGet(); } }, directExecutor()); service.startAsync(); service.stopAsync(); assertEquals(1, stopppingCount.get()); service.stopAsync(); assertEquals(1, stopppingCount.get()); }
public void testFailingServiceStopAndWait_runFailing() throws Exception { RunFailingService service = new RunFailingService(); RecordingListener listener = RecordingListener.record(service); service.startAsync(); try { service.awaitRunning(); fail(); } catch (IllegalStateException e) { assertEquals(EXCEPTION, service.failureCause()); assertEquals(EXCEPTION, e.getCause()); } assertEquals( ImmutableList.of( State.STARTING, State.RUNNING, State.FAILED), listener.getStateHistory()); }
public void testThreadedServiceStopIdempotenceAfterWait() throws Throwable { ThreadedService service = new ThreadedService(); service.startAsync().awaitRunning(); assertEquals(State.RUNNING, service.state()); service.awaitRunChecks(); service.stopAsync().awaitTerminated(); service.stopAsync(); assertEquals(State.TERMINATED, service.state()); executionThread.join(); throwIfSet(thrownByExecutionThread); }
public void testFailingServiceStartAndWait() throws Exception { StartFailingService service = new StartFailingService(); RecordingListener listener = RecordingListener.record(service); try { service.startAsync().awaitRunning(); fail(); } catch (IllegalStateException e) { assertEquals(EXCEPTION, service.failureCause()); assertEquals(EXCEPTION, e.getCause()); } assertEquals( ImmutableList.of( State.STARTING, State.FAILED), listener.getStateHistory()); }
public void testFailingServiceStopAndWait_stopFailing() throws Exception { StopFailingService service = new StopFailingService(); RecordingListener listener = RecordingListener.record(service); service.startAsync().awaitRunning(); try { service.stopAsync().awaitTerminated(); fail(); } catch (IllegalStateException e) { assertEquals(EXCEPTION, service.failureCause()); assertEquals(EXCEPTION, e.getCause()); } assertEquals( ImmutableList.of( State.STARTING, State.RUNNING, State.STOPPING, State.FAILED), listener.getStateHistory()); }
public void testThrowingServiceStopAndWait_runThrowing() throws Exception { RunThrowingService service = new RunThrowingService(); RecordingListener listener = RecordingListener.record(service); service.startAsync(); try { service.awaitTerminated(); fail(); } catch (IllegalStateException e) { assertEquals(service.exception, service.failureCause()); assertEquals(service.exception, e.getCause()); } assertEquals( ImmutableList.of( State.STARTING, State.RUNNING, State.FAILED), listener.getStateHistory()); }
public void testFailOnErrorFromStartUpListener() throws InterruptedException { final Error error = new Error(); final CountDownLatch latch = new CountDownLatch(1); TestService service = new TestService(); service.addListener(new Service.Listener() { @Override public void running() { throw error; } @Override public void failed(State from, Throwable failure) { assertEquals(State.RUNNING, from); assertEquals(error, failure); latch.countDown(); } }, directExecutor()); service.startAsync(); latch.await(); assertEquals(0, service.numberOfTimesRunCalled.get()); assertEquals(Service.State.FAILED, service.state()); }
public void testCustomSchedulerFailure() throws Exception { TestFailingCustomScheduledService service = new TestFailingCustomScheduledService(); service.startAsync().awaitRunning(); for (int i = 1; i < 4; i++) { service.firstBarrier.await(); assertEquals(i, service.numIterations.get()); service.secondBarrier.await(); } Thread.sleep(1000); try { service.stopAsync().awaitTerminated(100, TimeUnit.SECONDS); fail(); } catch (IllegalStateException e) { assertEquals(State.FAILED, service.state()); } }
public void testCustomScheduler_deadlock() throws InterruptedException, BrokenBarrierException { final CyclicBarrier inGetNextSchedule = new CyclicBarrier(2); // This will flakily deadlock, so run it multiple times to increase the flake likelihood for (int i = 0; i < 1000; i++) { Service service = new AbstractScheduledService() { @Override protected void runOneIteration() {} @Override protected Scheduler scheduler() { return new CustomScheduler() { @Override protected Schedule getNextSchedule() throws Exception { if (state() != State.STARTING) { inGetNextSchedule.await(); Thread.yield(); throw new RuntimeException("boom"); } return new Schedule(0, TimeUnit.NANOSECONDS); } }; } }; service.startAsync().awaitRunning(); inGetNextSchedule.await(); service.stopAsync(); } }
public void testFailStart() throws Exception { Service a = new NoOpService(); Service b = new FailStartService(); Service c = new NoOpService(); Service d = new FailStartService(); Service e = new NoOpService(); ServiceManager manager = new ServiceManager(asList(a, b, c, d, e)); RecordingListener listener = new RecordingListener(); manager.addListener(listener); assertState(manager, Service.State.NEW, a, b, c, d, e); try { manager.startAsync().awaitHealthy(); fail(); } catch (IllegalStateException expected) { } assertFalse(listener.healthyCalled); assertState(manager, Service.State.RUNNING, a, c, e); assertEquals(ImmutableSet.of(b, d), listener.failedServices); assertState(manager, Service.State.FAILED, b, d); assertFalse(manager.isHealthy()); manager.stopAsync().awaitStopped(); assertFalse(manager.isHealthy()); assertFalse(listener.healthyCalled); assertTrue(listener.stoppedCalled); }
public void testFailStop() throws Exception { Service a = new NoOpService(); Service b = new FailStopService(); Service c = new NoOpService(); ServiceManager manager = new ServiceManager(asList(a, b, c)); RecordingListener listener = new RecordingListener(); manager.addListener(listener); manager.startAsync().awaitHealthy(); assertTrue(listener.healthyCalled); assertFalse(listener.stoppedCalled); manager.stopAsync().awaitStopped(); assertTrue(listener.stoppedCalled); assertEquals(ImmutableSet.of(b), listener.failedServices); assertState(manager, Service.State.FAILED, b); assertState(manager, Service.State.TERMINATED, a, c); }
public void testFailRun() throws Exception { Service a = new NoOpService(); Service b = new FailRunService(); ServiceManager manager = new ServiceManager(asList(a, b)); RecordingListener listener = new RecordingListener(); manager.addListener(listener); assertState(manager, Service.State.NEW, a, b); try { manager.startAsync().awaitHealthy(); fail(); } catch (IllegalStateException expected) { } assertTrue(listener.healthyCalled); assertEquals(ImmutableSet.of(b), listener.failedServices); manager.stopAsync().awaitStopped(); assertState(manager, Service.State.FAILED, b); assertState(manager, Service.State.TERMINATED, a); assertTrue(listener.stoppedCalled); }
@Override public synchronized void terminated(State from) { assertEquals(from, Iterables.getLast(stateHistory, State.NEW)); stateHistory.add(State.TERMINATED); assertEquals(State.TERMINATED, service.state()); if (from == State.NEW) { try { service.awaitRunning(); fail(); } catch (IllegalStateException expected) { assertNull(expected.getCause()); assertTrue(expected.getMessage().equals( "Expected the service " + service + " to be RUNNING, but was TERMINATED")); } } completionLatch.countDown(); }
/** * Implementing classes should invoke this method once their service has stopped. It will cause * the service to transition from {@link State#STOPPING} to {@link State#TERMINATED}. * * @throws IllegalStateException if the service is neither {@link State#STOPPING} nor {@link * State#RUNNING}. */ protected final void notifyStopped() { monitor.enter(); try { // We check the internal state of the snapshot instead of state() directly so we don't allow // notifyStopped() to be called while STARTING, even if stop() has already been called. State previous = snapshot.state; if (previous != STOPPING && previous != RUNNING) { IllegalStateException failure = new IllegalStateException("Cannot notifyStopped() when the service is " + previous); notifyFailed(failure); throw failure; } snapshot = new StateSnapshot(TERMINATED); terminated(previous); } finally { monitor.leave(); executeListeners(); } }
public void testFailOnExceptionFromRun() throws Exception { TestService service = new TestService(); service.runException = new Exception(); service.startAsync().awaitRunning(); service.runFirstBarrier.await(); service.runSecondBarrier.await(); try { future.get(); fail(); } catch (CancellationException expected) { } // An execution exception holds a runtime exception (from throwables.propogate) that holds our // original exception. assertEquals(service.runException, service.failureCause()); assertEquals(service.state(), Service.State.FAILED); }
@Test public void testRun_takesFromQueue_whileRunning() throws Exception { exporter.startAsync().awaitRunning(); insertAndAssert(emptyBatch); // Insert more batches to verify that the exporter hasn't gotten stuck insertAndAssert(emptyBatch); insertAndAssert(emptyBatch); assertThat(exporter.state()).isEqualTo(State.RUNNING); }
@Test public void testRun_staysRunning_afterIOException() throws Exception { Optional<ImmutableList<MetricPoint<?>>> threeBatch = Optional.of(ImmutableList.of(point, point, point)); doThrow(new IOException()).when(writer).write(Matchers.<MetricPoint<?>>any()); exporter.startAsync(); insertAndAssert(threeBatch); // Insert another batch in order to block until the exporter has processed the last one insertAndAssert(threeBatch); // Insert another to make sure the exporter hasn't gotten stuck insertAndAssert(threeBatch); assertThat(exporter.state()).isNotEqualTo(State.FAILED); }
public void shutdown() { GuiceDI.getInstance(ServerRegistry.class).stopAsync(); GuiceDI.getInstance(RemotingNettyServer.class).stopAsync().addListener(new Listener() { @Override public void terminated(State from) { super.terminated(from); logger.info("zk registry stopped"); } }, MoreExecutors.directExecutor()); }
private static ListenerCallQueue.Event<Listener> terminatedEvent(final State from) { return new ListenerCallQueue.Event<Listener>() { @Override public void call(Listener listener) { listener.terminated(from); } @Override public String toString() { return "terminated({from = " + from + "})"; } }; }
private static ListenerCallQueue.Event<Listener> stoppingEvent(final State from) { return new ListenerCallQueue.Event<Listener>() { @Override public void call(Listener listener) { listener.stopping(from); } @Override public String toString() { return "stopping({from = " + from + "})"; } }; }
public void testNoOpServiceStopIdempotenceDoubleWait() throws Exception { NoOpService service = new NoOpService(); service.startAsync().awaitRunning(); assertEquals(State.RUNNING, service.state()); service.stopAsync().awaitTerminated(); service.stopAsync().awaitTerminated(); assertEquals(State.TERMINATED, service.state()); }
/** Checks that the current state is equal to the expected state. */ @GuardedBy("monitor") private void checkCurrentState(State expected) { State actual = state(); if (actual != expected) { if (actual == FAILED) { // Handle this specially so that we can include the failureCause, if there is one. throw new IllegalStateException( "Expected the service " + this + " to be " + expected + ", but the service has FAILED", failureCause()); } throw new IllegalStateException( "Expected the service " + this + " to be " + expected + ", but was " + actual); } }
private void enqueueStoppingEvent(final State from) { if (from == State.STARTING) { listeners.enqueue(STOPPING_FROM_STARTING_EVENT); } else if (from == State.RUNNING) { listeners.enqueue(STOPPING_FROM_RUNNING_EVENT); } else { throw new AssertionError(); } }