package org.erlide.runtime; import java.util.List; import org.erlide.runtime.service.AlwaysRestartPolicy; import org.erlide.runtime.service.CooldownRestartPolicy; import org.erlide.runtime.service.NeverRestartPolicy; import org.erlide.runtime.service.RestartableService; import org.erlide.util.services.Provider; import org.hamcrest.Matchers; import org.junit.After; import org.junit.Assert; import org.junit.Test; import com.google.common.collect.Lists; import com.google.common.util.concurrent.AbstractExecutionThreadService; import com.google.common.util.concurrent.MoreExecutors; import com.google.common.util.concurrent.Service; import com.google.common.util.concurrent.Service.Listener; import com.google.common.util.concurrent.Service.State; public class RestartableServiceTest { static class DummyService extends AbstractExecutionThreadService { private boolean running = false; private boolean crashed = false; @Override protected void run() throws Exception { while (running) { Thread.sleep(30); if (crashed) { throw new RuntimeException("#hello#"); } } } @Override protected void startUp() throws Exception { running = true; } @Override protected void triggerShutdown() { running = false; } public void triggerCrash() { crashed = true; } } private RestartableService service; private final Provider<Service> dummyFactory = new Provider<Service>() { @Override public Service get() { return new DummyService(); } }; @After public void cleanup() { if (service.state() != State.FAILED) { service.stopAsync().awaitTerminated(); } service = null; } @Test public void shouldNotCrashAfterInterval_always() throws InterruptedException { service = new RestartableService(dummyFactory, new CooldownRestartPolicy(1000)); service.startAsync().awaitRunning(); final DummyService dummy = (DummyService) service.getDelegate(); Thread.sleep(1100); dummy.triggerCrash(); Thread.sleep(100); Assert.assertThat(dummy.state(), Matchers.is(State.FAILED)); Assert.assertThat(service.state(), Matchers.is(State.RUNNING)); } @Test public void shouldCrashBeforeInterval_always() throws InterruptedException { service = new RestartableService(dummyFactory, new CooldownRestartPolicy()); service.startAsync().awaitRunning(); final DummyService dummy = (DummyService) service.getDelegate(); dummy.triggerCrash(); Thread.sleep(100); Assert.assertThat(dummy.state(), Matchers.is(State.FAILED)); Assert.assertThat(service.state(), Matchers.is(State.FAILED)); } @Test public void shouldCrashBeforeInterval_secondTime() throws InterruptedException { service = new RestartableService(dummyFactory, new CooldownRestartPolicy(1000)); service.startAsync().awaitRunning(); final DummyService dummy = (DummyService) service.getDelegate(); Thread.sleep(1100); dummy.triggerCrash(); Thread.sleep(100); Assert.assertThat(dummy.state(), Matchers.is(State.FAILED)); Assert.assertThat(service.state(), Matchers.is(State.RUNNING)); final DummyService dummy2 = (DummyService) service.getDelegate(); Assert.assertThat(dummy2, Matchers.is(Matchers.not(dummy))); dummy2.triggerCrash(); Thread.sleep(100); Assert.assertThat(dummy2.state(), Matchers.is(State.FAILED)); Assert.assertThat(service.state(), Matchers.is(State.FAILED)); } @Test public void shouldNotCrashBeforeInterval_secondTime() throws InterruptedException { service = new RestartableService(dummyFactory, new CooldownRestartPolicy(1000)); service.startAsync().awaitRunning(); final DummyService dummy = (DummyService) service.getDelegate(); Thread.sleep(1100); dummy.triggerCrash(); Thread.sleep(100); Assert.assertThat(dummy.state(), Matchers.is(State.FAILED)); Assert.assertThat(service.state(), Matchers.is(State.RUNNING)); final DummyService dummy2 = (DummyService) service.getDelegate(); Assert.assertThat(dummy2, Matchers.is(Matchers.not(dummy))); Thread.sleep(1100); dummy2.triggerCrash(); Thread.sleep(100); Assert.assertThat(dummy2.state(), Matchers.is(State.FAILED)); Assert.assertThat(service.state(), Matchers.is(State.RUNNING)); } @Test public void shouldShutdown_always() throws InterruptedException { service = new RestartableService(dummyFactory, new AlwaysRestartPolicy()); service.startAsync().awaitRunning(); final DummyService dummy = (DummyService) service.getDelegate(); dummy.triggerShutdown(); Thread.sleep(100); Assert.assertThat(dummy.state(), Matchers.is(State.TERMINATED)); Assert.assertThat(service.state(), Matchers.is(State.TERMINATED)); } @Test public void shouldCrash_never() throws InterruptedException { service = new RestartableService(dummyFactory, new NeverRestartPolicy()); service.startAsync().awaitRunning(); final DummyService dummy = (DummyService) service.getDelegate(); dummy.triggerCrash(); Thread.sleep(100); Assert.assertThat(dummy.state(), Matchers.is(State.FAILED)); Assert.assertThat(service.state(), Matchers.is(State.FAILED)); } @Test public void shouldShutdown_never() throws InterruptedException { service = new RestartableService(dummyFactory, new NeverRestartPolicy()); service.startAsync().awaitRunning(); final DummyService dummy = (DummyService) service.getDelegate(); dummy.triggerShutdown(); Thread.sleep(100); Assert.assertThat(dummy.state(), Matchers.is(State.TERMINATED)); Assert.assertThat(service.state(), Matchers.is(State.TERMINATED)); } @Test public void shouldPostNotifications() throws InterruptedException { final List<String> events = Lists.newArrayList(); service = new RestartableService(dummyFactory, new AlwaysRestartPolicy()); service.addListener(new Listener() { @Override public void starting() { events.add("starting"); } @Override public void running() { events.add("running"); } @Override public void stopping(final State from) { events.add("stopping " + from); } @Override public void terminated(final State from) { events.add("terminated " + from); } @Override public void failed(final State from, final Throwable failure) { events.add("failed " + from); } }, MoreExecutors.sameThreadExecutor()); service.startAsync().awaitRunning(); Thread.sleep(100); DummyService dummy = (DummyService) service.getDelegate(); dummy.triggerCrash(); Thread.sleep(100); dummy = (DummyService) service.getDelegate(); dummy.triggerCrash(); Thread.sleep(100); service.stopAsync().awaitTerminated(); Thread.sleep(100); System.out.println(events); Assert.assertThat(events, Matchers.contains("starting", "running", "starting", "running", "starting", "running", "stopping RUNNING", "terminated STOPPING")); } }