| package com.gemstone.gemfire.distributed; |
| |
| import static org.junit.Assert.assertTrue; |
| |
| import java.io.BufferedReader; |
| import java.io.File; |
| import java.io.FileReader; |
| import java.io.FileWriter; |
| import java.io.IOException; |
| import java.net.ServerSocket; |
| import java.util.List; |
| import java.util.Properties; |
| import java.util.concurrent.Callable; |
| import java.util.concurrent.atomic.AtomicBoolean; |
| |
| import org.apache.logging.log4j.Logger; |
| import org.junit.After; |
| import org.junit.Before; |
| import org.junit.Rule; |
| import org.junit.contrib.java.lang.system.RestoreSystemProperties; |
| import org.junit.rules.TestName; |
| |
| import com.gemstone.gemfire.distributed.internal.DistributionConfig; |
| import com.gemstone.gemfire.distributed.internal.InternalDistributedSystem; |
| import com.gemstone.gemfire.internal.FileUtil; |
| import com.gemstone.gemfire.internal.lang.StringUtils; |
| import com.gemstone.gemfire.internal.logging.LogService; |
| import com.gemstone.gemfire.internal.process.PidUnavailableException; |
| import com.gemstone.gemfire.internal.process.ProcessUtils; |
| import com.gemstone.gemfire.internal.process.ProcessStreamReader.InputListener; |
| import com.gemstone.gemfire.internal.util.IOUtils; |
| import com.gemstone.gemfire.internal.util.StopWatch; |
| |
| /** |
| * @author Kirk Lund |
| * @since 8.0 |
| */ |
| public abstract class AbstractLauncherJUnitTestCase { |
| private static final Logger logger = LogService.getLogger(); |
| |
| protected static final int WAIT_FOR_PROCESS_TO_DIE_TIMEOUT = 5 * 60 * 1000; // 5 minutes |
| protected static final int TIMEOUT_MILLISECONDS = WAIT_FOR_PROCESS_TO_DIE_TIMEOUT; |
| protected static final int WAIT_FOR_FILE_CREATION_TIMEOUT = 10*1000; |
| protected static final int WAIT_FOR_FILE_DELETION_TIMEOUT = 10*1000; |
| protected static final int WAIT_FOR_MBEAN_TIMEOUT = 10*1000; |
| protected static final int INTERVAL = 100; |
| protected static final int INTERVAL_MILLISECONDS = INTERVAL; |
| |
| private static final String EXPECTED_EXCEPTION_ADD = "<ExpectedException action=add>{}</ExpectedException>"; |
| private static final String EXPECTED_EXCEPTION_REMOVE = "<ExpectedException action=remove>{}</ExpectedException>"; |
| private static final String EXPECTED_EXCEPTION_MBEAN_NOT_REGISTERED = "MBean Not Registered In GemFire Domain"; |
| |
| protected volatile ServerSocket socket; |
| |
| protected volatile File pidFile; |
| protected volatile File stopRequestFile; |
| protected volatile File statusRequestFile; |
| protected volatile File statusFile; |
| |
| @Rule |
| public TestName testName= new TestName(); |
| |
| @Rule |
| public RestoreSystemProperties restoreSystemProperties = new RestoreSystemProperties(); |
| |
| @Before |
| public final void setUpLauncherTest() throws Exception { |
| System.setProperty("gemfire." + DistributionConfig.MCAST_PORT_NAME, Integer.toString(0)); |
| logger.info(EXPECTED_EXCEPTION_ADD, EXPECTED_EXCEPTION_MBEAN_NOT_REGISTERED); |
| } |
| |
| @After |
| public final void tearDownLauncherTest() throws Exception { |
| logger.info(EXPECTED_EXCEPTION_REMOVE, EXPECTED_EXCEPTION_MBEAN_NOT_REGISTERED); |
| if (this.socket != null) { |
| this.socket.close(); |
| this.socket = null; |
| } |
| delete(this.pidFile); this.pidFile = null; |
| delete(this.stopRequestFile); this.stopRequestFile = null; |
| delete(this.statusRequestFile); this.statusRequestFile = null; |
| delete(this.statusFile); this.statusFile = null; |
| } |
| |
| protected void delete(final File file) throws Exception { |
| assertEventuallyTrue("deleting " + file, new Callable<Boolean>() { |
| @Override |
| public Boolean call() throws Exception { |
| if (file == null) { |
| return true; |
| } |
| try { |
| FileUtil.delete(file); |
| } catch (IOException e) { |
| } |
| return !file.exists(); |
| } |
| }, WAIT_FOR_FILE_DELETION_TIMEOUT, INTERVAL); |
| } |
| |
| protected void waitForPidToStop(final int pid, boolean throwOnTimeout) throws Exception { |
| assertEventuallyFalse("Process never died", new Callable<Boolean>() { |
| @Override |
| public Boolean call() throws Exception { |
| return ProcessUtils.isProcessAlive(pid); |
| } |
| }, WAIT_FOR_PROCESS_TO_DIE_TIMEOUT, INTERVAL); |
| } |
| |
| protected void waitForPidToStop(final int pid) throws Exception { |
| waitForPidToStop(pid, true); |
| } |
| |
| protected void waitForFileToDelete(final File file, boolean throwOnTimeout) throws Exception { |
| if (file == null) { |
| return; |
| } |
| assertEventuallyTrue("waiting for file " + file + " to delete", new Callable<Boolean>() { |
| @Override |
| public Boolean call() throws Exception { |
| return !file.exists(); |
| } |
| }, WAIT_FOR_FILE_DELETION_TIMEOUT, INTERVAL); |
| } |
| |
| protected void waitForFileToDelete(final File file) throws Exception { |
| waitForFileToDelete(file, true); |
| } |
| |
| protected static int getPid() throws PidUnavailableException { |
| return ProcessUtils.identifyPid(); |
| } |
| |
| protected InputListener createLoggingListener(final String name, final String header) { |
| return new InputListener() { |
| @Override |
| public void notifyInputLine(String line) { |
| logger.info(new StringBuilder("[").append(header).append("]").append(line).toString()); |
| } |
| @Override |
| public String toString() { |
| return name; |
| } |
| }; |
| } |
| |
| protected InputListener createCollectionListener(final String name, final String header, final List<String> lines) { |
| return new InputListener() { |
| @Override |
| public void notifyInputLine(String line) { |
| lines.add(line); |
| } |
| @Override |
| public String toString() { |
| return name; |
| } |
| }; |
| } |
| |
| protected InputListener createExpectedListener(final String name, final String header, final String expected, final AtomicBoolean atomic) { |
| return new InputListener() { |
| @Override |
| public void notifyInputLine(String line) { |
| if (line.contains(expected)) { |
| atomic.set(true); |
| } |
| } |
| @Override |
| public String toString() { |
| return name; |
| } |
| }; |
| } |
| |
| protected void writeGemfireProperties(final Properties gemfireProperties, final File gemfirePropertiesFile) throws IOException { |
| if (!gemfirePropertiesFile.exists()) { |
| gemfireProperties.store(new FileWriter(gemfirePropertiesFile), "Configuration settings for the GemFire Server"); |
| } |
| } |
| |
| protected int readPid(final File pidFile) throws IOException { |
| BufferedReader reader = null; |
| try { |
| reader = new BufferedReader(new FileReader(pidFile)); |
| return Integer.parseInt(StringUtils.trim(reader.readLine())); |
| } |
| finally { |
| IOUtils.close(reader); |
| } |
| } |
| |
| protected void writePid(final File pidFile, final int pid) throws IOException { |
| FileWriter writer = new FileWriter(pidFile); |
| writer.write(String.valueOf(pid)); |
| writer.write("\n"); |
| writer.flush(); |
| writer.close(); |
| } |
| |
| protected void waitForFileToExist(final File file, boolean throwOnTimeout) throws Exception { |
| assertEventuallyTrue("waiting for file " + file + " to exist", new Callable<Boolean>() { |
| @Override |
| public Boolean call() throws Exception { |
| return file.exists(); |
| } |
| }, WAIT_FOR_FILE_CREATION_TIMEOUT, INTERVAL); |
| } |
| |
| protected void waitForFileToExist(final File file) throws Exception { |
| waitForFileToExist(file, true); |
| } |
| |
| protected String getUniqueName() { |
| return getClass().getSimpleName() + "_" + testName.getMethodName(); |
| } |
| |
| protected static void assertEventuallyTrue(final String message, final Callable<Boolean> callable, final int timeout, final int interval) throws Exception { |
| boolean done = false; |
| for (StopWatch time = new StopWatch(true); !done && time.elapsedTimeMillis() < timeout; done = (callable.call())) { |
| Thread.sleep(interval); |
| } |
| assertTrue(message, done); |
| } |
| |
| protected static void assertEventuallyFalse(final String message, final Callable<Boolean> callable, final int timeout, final int interval) throws Exception { |
| boolean done = false; |
| for (StopWatch time = new StopWatch(true); !done && time.elapsedTimeMillis() < timeout; done = (!callable.call())) { |
| Thread.sleep(interval); |
| } |
| assertTrue(message, done); |
| } |
| |
| protected static void disconnectFromDS() { |
| InternalDistributedSystem ids = InternalDistributedSystem.getConnectedInstance(); |
| if (ids != null) { |
| ids.disconnect(); |
| } |
| } |
| } |