blob: e1ad29b5a4d620f639914464da3ee9e116ae2079 [file] [log] [blame]
package com.gemstone.gemfire.internal.process;
import static org.junit.Assert.*;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileWriter;
import java.io.IOException;
import java.util.concurrent.Callable;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
import org.jmock.Mockery;
import org.jmock.lib.legacy.ClassImposteriser;
import org.junit.After;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.experimental.categories.Category;
import org.junit.rules.ExpectedException;
import org.junit.rules.TemporaryFolder;
import com.gemstone.gemfire.internal.util.StopWatch;
import com.gemstone.gemfire.test.junit.categories.UnitTest;
import com.gemstone.gemfire.test.junit.rules.ExpectedTimeout;
/**
* 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(2000);
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();
}
}