@Test
  public void timesOutReadingFromEmptyFile() throws Exception {
    final File file = testFolder.newFile("my.pid");

    timeout.expect(TimeoutException.class);
    timeout.expectMessage("Invalid pid 'null' found");
    timeout.expectMinimumDuration(1000);
    timeout.expectMaximumDuration(10000);
    timeout.expectTimeUnit(TimeUnit.MILLISECONDS);

    new PidFile(file).readPid(1500, TimeUnit.MILLISECONDS);
  }
/**
 * Unit tests the PidFile class.
 *
 * @author Kirk Lund
 * @since 8.2
 */
@Category(UnitTest.class)
public class PidFileJUnitTest {

  @Rule public TemporaryFolder testFolder = new TemporaryFolder();

  @Rule public ExpectedException thrown = ExpectedException.none();

  @Rule public ExpectedTimeout timeout = ExpectedTimeout.none();

  protected Mockery mockContext;
  private ExecutorService futures;

  @Before
  public void before() {
    mockContext =
        new Mockery() {
          {
            setImposteriser(ClassImposteriser.INSTANCE);
          }
        };
    this.futures = Executors.newFixedThreadPool(2);
  }

  @After
  public void after() {
    mockContext.assertIsSatisfied();
    assertTrue(this.futures.shutdownNow().isEmpty());
  }

  @Test
  public void readsIntFromFile() throws Exception {
    final File file = testFolder.newFile("my.pid");
    final String value = "42";
    writeToFile(file, value);

    final int readValue = new PidFile(file).readPid();
    assertEquals(Integer.parseInt(value), readValue);
  }

  @Test
  public void readingEmptyFileThrowsIllegalArgumentException() throws Exception {
    final File file = testFolder.newFile("my.pid");

    thrown.expect(IllegalArgumentException.class);
    thrown.expectMessage("Invalid pid 'null' found");

    new PidFile(file).readPid();
  }

  @Test
  public void readingFileWithNonIntegerThrowsIllegalArgumentException() throws Exception {
    final File file = testFolder.newFile("my.pid");
    final String value = "fortytwo";
    writeToFile(file, value);

    thrown.expect(IllegalArgumentException.class);
    thrown.expectMessage("Invalid pid '" + value + "' found");

    new PidFile(file).readPid();
  }

  @Test
  public void readingFileWithNegativeIntegerThrowsIllegalArgumentException() throws Exception {
    final File file = testFolder.newFile("my.pid");
    final String value = "-42";
    writeToFile(file, value);

    thrown.expect(IllegalArgumentException.class);
    thrown.expectMessage("Invalid pid '" + value + "' found");

    new PidFile(file).readPid();
  }

  @Test
  public void readingNullFileThrowsNullPointerException() throws Exception {
    final File file = null;

    thrown.expect(NullPointerException.class);

    new PidFile(file).readPid();
  }

  @Test
  public void timesOutReadingFromEmptyFile() throws Exception {
    final File file = testFolder.newFile("my.pid");

    timeout.expect(TimeoutException.class);
    timeout.expectMessage("Invalid pid 'null' found");
    timeout.expectMinimumDuration(1000);
    timeout.expectMaximumDuration(10000);
    timeout.expectTimeUnit(TimeUnit.MILLISECONDS);

    new PidFile(file).readPid(1500, TimeUnit.MILLISECONDS);
  }

  @Test
  public void readsIntBeforeTimeout() throws Exception {
    final int AWAIT_LATCH_TIMEOUT_MILLIS = 10 * 1000;
    final int OPEN_LATCH_DELAY_MILLIS = 2 * 1000;
    final int FUTURE_GET_TIMEOUT_MILLIS = 2 * 1000;
    final int READ_PID_TIMEOUT_MILLIS = 2 * OPEN_LATCH_DELAY_MILLIS;

    final File file = testFolder.newFile("my.pid");
    final FileWriter writer = new FileWriter(file);

    final CountDownLatch writePidLatch = new CountDownLatch(1);
    final String value = "42";

    // start Future to write the pid later but before timeout
    Future<Boolean> futureWritePid =
        this.futures.submit(
            new Callable<Boolean>() {
              @Override
              public Boolean call() throws Exception {
                writePidLatch.await(AWAIT_LATCH_TIMEOUT_MILLIS, TimeUnit.MILLISECONDS);
                writeToFile(file, value);
                return true;
              }
            });

    // start Future to sleep and release the delay
    Future<Boolean> futureOpenLatch =
        this.futures.submit(
            new Callable<Boolean>() {
              @Override
              public Boolean call() throws Exception {
                Thread.sleep(OPEN_LATCH_DELAY_MILLIS);
                writePidLatch.countDown();
                return true;
              }
            });

    StopWatch stopWatch = new StopWatch(true);
    final int readValue = new PidFile(file).readPid(READ_PID_TIMEOUT_MILLIS, TimeUnit.MILLISECONDS);
    assertEquals(Integer.parseInt(value), readValue);

    long duration = stopWatch.elapsedTimeMillis();
    assertTrue(duration > OPEN_LATCH_DELAY_MILLIS);
    assertTrue(duration < READ_PID_TIMEOUT_MILLIS);

    assertEquals(0, writePidLatch.getCount());
    assertTrue(futureOpenLatch.get(FUTURE_GET_TIMEOUT_MILLIS, TimeUnit.MILLISECONDS));
    assertTrue(futureWritePid.get(FUTURE_GET_TIMEOUT_MILLIS, TimeUnit.MILLISECONDS));
  }

  @Test
  public void findsCorrectFile() throws Exception {
    final File directory = testFolder.getRoot();

    final String fileNames[] = new String[] {"other.txt", "my.txt", "a.log", "b.log"};
    for (String fileName : fileNames) {
      testFolder.newFile(fileName);
    }

    final int pidValue = 42;
    final File file = testFolder.newFile("my.pid");
    writeToFile(file, String.valueOf(pidValue));

    final File other = testFolder.newFile("other.pid");
    writeToFile(other, "43");

    final File[] files = directory.listFiles();
    assertEquals(fileNames.length + 2, files.length);

    PidFile pidFile = new PidFile(directory, file.getName());
    assertEquals(file, pidFile.getFile());

    int value = pidFile.readPid();
    assertEquals(pidValue, value);
  }

  @Test
  public void missingFileInEmptyDirectoryThrowsFileNotFoundException() throws Exception {
    final File directory = testFolder.getRoot();

    final String pidFileName = "my.pid";

    thrown.expect(FileNotFoundException.class);
    thrown.expectMessage("Unable to find PID file '" + pidFileName + "' in directory " + directory);

    new PidFile(directory, pidFileName);
  }

  @Test
  public void missingFileThrowsFileNotFoundException() throws Exception {
    final String pidFileName = "my.pid";

    final File directory = testFolder.getRoot();
    final File file = new File(directory, pidFileName);

    thrown.expect(FileNotFoundException.class);
    thrown.expectMessage("Unable to find PID file '" + file + "'");

    new PidFile(file);
  }

  @Test
  public void missingFileInFullDirectoryThrowsFileNotFoundException() throws Exception {
    final File directory = testFolder.getRoot();

    final String fileNames[] = new String[] {"other.txt", "my.txt", "a.log", "b.log"};
    for (String fileName : fileNames) {
      testFolder.newFile(fileName);
    }

    final File other = testFolder.newFile("other.pid");
    writeToFile(other, "43");

    final File[] files = directory.listFiles();
    assertEquals(fileNames.length + 1, files.length);

    final String pidFileName = "my.pid";

    thrown.expect(FileNotFoundException.class);
    thrown.expectMessage("Unable to find PID file '" + pidFileName + "' in directory " + directory);

    new PidFile(directory, pidFileName);
  }

  private void writeToFile(final File file, String value) throws IOException {
    final FileWriter writer = new FileWriter(file);
    writer.write(value);
    writer.flush();
    writer.close();
  }
}