@Test
  public void start_then_stop_gracefully() throws Exception {
    underTest = newDefaultMonitor(tempDir);
    HttpProcessClient client = new HttpProcessClient(tempDir, "test");
    // blocks until started
    underTest.start(singletonList(client.newCommand()));

    assertThat(client).isReady().wasStartedBefore(System.currentTimeMillis());

    // blocks until stopped
    underTest.stop();
    assertThat(client).isNotReady().wasGracefullyTerminated();
    assertThat(underTest.getState()).isEqualTo(State.STOPPED);
    verify(fileSystem).reset();
  }
  @Test
  public void watchForHardStop_adds_a_hardStopWatcher_thread_and_starts_it() throws Exception {
    underTest = newDefaultMonitor(tempDir, true);
    assertThat(underTest.hardStopWatcher).isNull();

    HttpProcessClient p1 = new HttpProcessClient(tempDir, "p1");
    underTest.start(singletonList(p1.newCommand()));

    assertThat(underTest.hardStopWatcher).isNotNull();
    assertThat(underTest.hardStopWatcher.isAlive()).isTrue();

    p1.kill();
    underTest.awaitTermination();

    assertThat(underTest.hardStopWatcher.isAlive()).isFalse();
  }
 @Test
 public void stop_all_processes_if_one_fails_to_start() throws Exception {
   underTest = newDefaultMonitor(tempDir);
   HttpProcessClient p1 = new HttpProcessClient(tempDir, "p1");
   HttpProcessClient p2 = new HttpProcessClient(tempDir, "p2", -1);
   try {
     underTest.start(Arrays.asList(p1.newCommand(), p2.newCommand()));
     fail();
   } catch (Exception expected) {
     assertThat(p1).hasBeenReady().wasGracefullyTerminated();
     assertThat(p2)
         .hasNotBeenReady()
         // self "gracefully terminated", even if startup went bad
         .wasGracefullyTerminated();
   }
 }
  @Test
  public void stop_all_processes_if_monitor_shutdowns() throws Exception {
    underTest = newDefaultMonitor(tempDir);
    HttpProcessClient p1 = new HttpProcessClient(tempDir, "p1");
    HttpProcessClient p2 = new HttpProcessClient(tempDir, "p2");
    underTest.start(Arrays.asList(p1.newCommand(), p2.newCommand()));
    assertThat(p1).isReady();
    assertThat(p2).isReady();

    // emulate CTRL-C
    underTest.getShutdownHook().run();
    underTest.getShutdownHook().join();

    assertThat(p1).wasGracefullyTerminated();
    assertThat(p2).wasGracefullyTerminated();

    verify(fileSystem).reset();
  }
  @Test
  public void start_then_stop_sequence_of_commands() throws Exception {
    underTest = newDefaultMonitor(tempDir);
    HttpProcessClient p1 = new HttpProcessClient(tempDir, "p1");
    HttpProcessClient p2 = new HttpProcessClient(tempDir, "p2");
    underTest.start(Arrays.asList(p1.newCommand(), p2.newCommand()));

    // start p2 when p1 is fully started (ready)
    assertThat(p1).isReady().wasStartedBefore(p2);
    assertThat(p2).isReady();

    underTest.stop();

    // stop in inverse order
    assertThat(p1).isNotReady().wasGracefullyTerminated();
    assertThat(p2).isNotReady().wasGracefullyTerminatedBefore(p1);
    verify(fileSystem).reset();
  }
    public HttpProcessClientAssert wasStartedBefore(HttpProcessClient client) {
      isNotNull();

      List<Long> startingAt = actual.wasStartingAt();
      longs.assertEqual(info, startingAt.size(), 1);
      longs.assertLessThanOrEqualTo(
          info, startingAt.iterator().next(), client.wasStartingAt().iterator().next());

      return this;
    }
    public HttpProcessClientAssert wasGracefullyTerminatedBefore(HttpProcessClient p1) {
      isNotNull();

      List<Long> wasGracefullyTerminatedAt = actual.wasGracefullyTerminatedAt();
      longs.assertEqual(info, wasGracefullyTerminatedAt.size(), 1);
      longs.assertLessThanOrEqualTo(
          info,
          wasGracefullyTerminatedAt.iterator().next(),
          p1.wasGracefullyTerminatedAt().iterator().next());

      return this;
    }
  @Test
  public void restart_all_processes_if_one_asks_for_restart() throws Exception {
    underTest = newDefaultMonitor(tempDir);
    HttpProcessClient p1 = new HttpProcessClient(tempDir, "p1");
    HttpProcessClient p2 = new HttpProcessClient(tempDir, "p2");
    underTest.start(Arrays.asList(p1.newCommand(), p2.newCommand()));

    assertThat(p1).isReady();
    assertThat(p2).isReady();

    p2.restart();

    assertThat(underTest.waitForOneRestart()).isTrue();

    assertThat(p1).wasStarted(2).wasGracefullyTerminated(1);
    assertThat(p2).wasStarted(2).wasGracefullyTerminated(1);

    underTest.stop();

    assertThat(p1).wasStarted(2).wasGracefullyTerminated(2);
    assertThat(p2).wasStarted(2).wasGracefullyTerminated(2);

    verify(fileSystem, times(2)).reset();
  }
  @Test
  public void stop_all_processes_if_one_shutdowns() throws Exception {
    underTest = newDefaultMonitor(tempDir);
    HttpProcessClient p1 = new HttpProcessClient(tempDir, "p1");
    HttpProcessClient p2 = new HttpProcessClient(tempDir, "p2");
    underTest.start(Arrays.asList(p1.newCommand(), p2.newCommand()));
    assertThat(p1.isReady()).isTrue();
    assertThat(p2.isReady()).isTrue();

    // kill p1 -> waiting for detection by monitor than termination of p2
    p1.kill();
    underTest.awaitTermination();

    assertThat(p1).isNotReady().wasNotGracefullyTerminated();
    assertThat(p2).isNotReady().wasGracefullyTerminated();

    verify(fileSystem).reset();
  }