diff --git a/spring-data-geode-test/src/main/java/org/springframework/data/gemfire/tests/integration/ClientServerIntegrationTestsSupport.java b/spring-data-geode-test/src/main/java/org/springframework/data/gemfire/tests/integration/ClientServerIntegrationTestsSupport.java index 54ec72b..a0880c7 100644 --- a/spring-data-geode-test/src/main/java/org/springframework/data/gemfire/tests/integration/ClientServerIntegrationTestsSupport.java +++ b/spring-data-geode-test/src/main/java/org/springframework/data/gemfire/tests/integration/ClientServerIntegrationTestsSupport.java @@ -16,7 +16,6 @@ package org.springframework.data.gemfire.tests.integration; -import static org.assertj.core.api.Assertions.assertThat; import static org.springframework.data.gemfire.tests.process.ProcessExecutor.launch; import static org.springframework.data.gemfire.util.ArrayUtils.asArray; @@ -25,18 +24,15 @@ import java.io.IOException; import java.net.InetSocketAddress; import java.net.ServerSocket; import java.net.Socket; -import java.time.LocalDateTime; -import java.time.format.DateTimeFormatter; import java.util.Optional; +import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicBoolean; import org.apache.geode.cache.server.CacheServer; import org.springframework.context.annotation.AnnotationConfigApplicationContext; import org.springframework.data.gemfire.tests.process.ProcessWrapper; import org.springframework.data.gemfire.tests.util.FileSystemUtils; -import org.springframework.data.gemfire.tests.util.FileUtils; import org.springframework.data.gemfire.tests.util.SocketUtils; -import org.springframework.data.gemfire.util.CollectionUtils; /** * The {@link ClientServerIntegrationTestsSupport} class is a abstract base class encapsulating common functionality @@ -44,9 +40,12 @@ import org.springframework.data.gemfire.util.CollectionUtils; * * @author John Blum * @see java.io.File + * @see java.lang.Process + * @see java.net.InetSocketAddress * @see java.net.ServerSocket * @see java.net.Socket * @see java.time.LocalDateTime + * @see java.util.concurrent.TimeUnit * @see org.apache.geode.cache.server.CacheServer * @see org.springframework.context.ApplicationContext * @see org.springframework.context.annotation.AnnotationConfigApplicationContext @@ -63,34 +62,7 @@ public abstract class ClientServerIntegrationTestsSupport extends IntegrationTes protected static final String DEBUG_ENDPOINT = "-agentlib:jdwp=transport=dt_socket,server=y,suspend=y,address=5005"; protected static final String DEBUGGING_ENABLED_PROPERTY = "spring.data.gemfire.debugging.enabled"; - protected static final String DIRECTORY_DELETE_ON_EXIT_PROPERTY = "spring.data.gemfire.directory.delete-on-exit"; protected static final String PROCESS_RUN_MANUAL_PROPERTY = "spring.data.gemfire.process.run-manual"; - protected static final String SYSTEM_PROPERTIES_LOG_FILE = "system-properties.log"; - - protected static String asApplicationName(Class type) { - return type.getSimpleName(); - } - - protected static String asDirectoryName(Class type) { - return String.format("%1$s-%2$s", asApplicationName(type), - LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd-hh-mm-ss"))); - } - - protected static File createDirectory(String pathname) { - return createDirectory(new File(pathname)); - } - - protected static File createDirectory(File directory) { - - assertThat(directory.isDirectory() || directory.mkdirs()) - .as(String.format("Failed to create directory [%s]", directory)).isTrue(); - - if (isDeleteDirectoryOnExit()) { - directory.deleteOnExit(); - } - - return directory; - } protected static int findAvailablePort() throws IOException { @@ -108,57 +80,16 @@ public abstract class ClientServerIntegrationTestsSupport extends IntegrationTes } } - protected static String getClassNameAsPath(Class type) { - return type.getName().replaceAll("\\.", "/"); - } - - protected static String getClassNameAsPath(Object obj) { - return getClassNameAsPath(obj.getClass()); - } - - protected static String getPackageNameAsPath(Class type) { - return type.getPackage().getName().replaceAll("\\.", "/"); - } - - protected static String getPackageNameAsPath(Object obj) { - return getPackageNameAsPath(obj.getClass()); - } - - protected static String getContextXmlFileLocation(Class type) { - return getClassNameAsPath(type).concat("-context.xml"); - } - - protected static String getServerContextXmlFileLocation(Class type) { - return getClassNameAsPath(type).concat("-server-context.xml"); - } - - protected static boolean isDeleteDirectoryOnExit() { - return Boolean.valueOf(System.getProperty(DIRECTORY_DELETE_ON_EXIT_PROPERTY, Boolean.TRUE.toString())); - } - protected static int intValue(Number number) { return number != null ? number.intValue() : 0; } - protected static String logFile() { - return logFile(GEMFIRE_LOG_FILE); + protected static boolean isProcessRunAuto() { + return !isProcessRunManual(); } - protected static String logFile(String defaultLogFilePathname) { - return System.getProperty(GEMFIRE_LOG_FILE_PROPERTY, defaultLogFilePathname); - } - - protected static String logLevel() { - return logLevel(GEMFIRE_LOG_LEVEL); - } - - protected static String logLevel(String defaultLogLevel) { - return System.getProperty(GEMFIRE_LOG_LEVEL_PROPERTY, defaultLogLevel); - } - - protected static void logSystemProperties() throws IOException { - FileUtils.write(new File(SYSTEM_PROPERTIES_LOG_FILE), - String.format("%s", CollectionUtils.toString(System.getProperties()))); + protected static boolean isProcessRunManual() { + return Boolean.getBoolean(PROCESS_RUN_MANUAL_PROPERTY); } protected static ProcessWrapper run(Class type, String... arguments) throws IOException { @@ -179,14 +110,6 @@ public abstract class ClientServerIntegrationTestsSupport extends IntegrationTes return isProcessRunAuto() ? launch(createDirectory(workingDirectory), classpath, type, arguments) : null; } - protected static boolean isProcessRunAuto() { - return !isProcessRunManual(); - } - - protected static boolean isProcessRunManual() { - return Boolean.getBoolean(PROCESS_RUN_MANUAL_PROPERTY); - } - protected static AnnotationConfigApplicationContext runSpringApplication(Class annotatedClass, String... args) { return runSpringApplication(asArray(annotatedClass), args); } @@ -231,6 +154,7 @@ public abstract class ClientServerIntegrationTestsSupport extends IntegrationTes return waitForServerToStart(cacheServer.getBindAddress(), cacheServer.getPort(), duration); } + @SuppressWarnings("all") protected static boolean waitForServerToStart(String host, int port) { return waitForServerToStart(host, port, DEFAULT_WAIT_DURATION); } @@ -258,4 +182,26 @@ public abstract class ClientServerIntegrationTestsSupport extends IntegrationTes }, duration); } + + protected static int waitForProcessToStop(Process process, File directory) { + return waitForProcessToStop(process, directory, DEFAULT_WAIT_DURATION); + } + + protected static int waitForProcessToStop(Process process, File directory, long duration) { + + long timeout = System.currentTimeMillis() + duration; + + try { + while (process.isAlive() && System.currentTimeMillis() < timeout) { + if (process.waitFor(DEFAULT_WAIT_INTERVAL, TimeUnit.MILLISECONDS)) { + return process.exitValue(); + } + } + } + catch (InterruptedException ignore) { + Thread.currentThread().interrupt(); + } + + return process.isAlive() ? -1 : process.exitValue(); + } } diff --git a/spring-data-geode-test/src/main/java/org/springframework/data/gemfire/tests/integration/IntegrationTestsSupport.java b/spring-data-geode-test/src/main/java/org/springframework/data/gemfire/tests/integration/IntegrationTestsSupport.java index 7e3cc7c..38c3793 100644 --- a/spring-data-geode-test/src/main/java/org/springframework/data/gemfire/tests/integration/IntegrationTestsSupport.java +++ b/spring-data-geode-test/src/main/java/org/springframework/data/gemfire/tests/integration/IntegrationTestsSupport.java @@ -16,6 +16,14 @@ package org.springframework.data.gemfire.tests.integration; +import static java.util.Arrays.stream; +import static org.assertj.core.api.Assertions.assertThat; +import static org.springframework.data.gemfire.util.ArrayUtils.nullSafeArray; + +import java.io.File; +import java.io.IOException; +import java.time.LocalDateTime; +import java.time.format.DateTimeFormatter; import java.util.List; import java.util.Optional; import java.util.concurrent.TimeUnit; @@ -23,32 +31,48 @@ import java.util.concurrent.atomic.AtomicBoolean; import java.util.function.Predicate; import java.util.stream.Collectors; +import org.apache.geode.DataSerializer; import org.apache.geode.cache.CacheClosedException; import org.apache.geode.cache.GemFireCache; +import org.apache.geode.internal.InternalDataSerializer; import org.apache.geode.internal.net.SocketCreatorFactory; import org.junit.AfterClass; +import org.junit.Before; import org.junit.BeforeClass; import org.springframework.data.gemfire.GemfireUtils; import org.springframework.data.gemfire.tests.mock.GemFireMockObjectsSupport; +import org.springframework.data.gemfire.tests.util.FileUtils; +import org.springframework.data.gemfire.util.CollectionUtils; /** * The {@link IntegrationTestsSupport} class is an abstract base class supporting integration tests * with either Apache Geode or Pivotal GemFire in a Spring context. * * @author John Blum + * @see java.io.File + * @see java.time.LocalDateTime + * @see java.util.concurrent.TimeUnit * @see org.apache.geode.cache.GemFireCache + * @see org.springframework.data.gemfire.tests.mock.GemFireMockObjectsSupport * @since 1.0.0 */ @SuppressWarnings("unused") public abstract class IntegrationTestsSupport { + protected static final boolean DEFAULT_DEBUG_GEMFIRE_QUERIES = false; + + protected static final boolean DEBUG_GEMFIRE_QUERIES = Boolean.getBoolean("spring.data.gemfire.query.debug"); + protected static final long DEFAULT_WAIT_DURATION = TimeUnit.SECONDS.toMillis(30); protected static final long DEFAULT_WAIT_INTERVAL = 500L; // milliseconds + protected static final String DIRECTORY_DELETE_ON_EXIT_PROPERTY = "spring.data.gemfire.directory.delete-on-exit"; protected static final String GEMFIRE_LOG_FILE = "gemfire-server.log"; protected static final String GEMFIRE_LOG_FILE_PROPERTY = "spring.data.gemfire.log.file"; protected static final String GEMFIRE_LOG_LEVEL = "error"; protected static final String GEMFIRE_LOG_LEVEL_PROPERTY = "spring.data.gemfire.log.level"; + protected static final String GEMFIRE_QUERY_VERBOSE_PROPERTY = "gemfire.Query.VERBOSE"; + protected static final String SYSTEM_PROPERTIES_LOG_FILE = "system-properties.log"; protected static final String TEST_GEMFIRE_LOG_LEVEL = "error"; private static final Predicate GEMFIRE_DOT_SYSTEM_PROPERTY_NAME_PREDICATE = @@ -86,11 +110,27 @@ public abstract class IntegrationTestsSupport { //SSLConfigurationFactory.close(); } + @Before + public void configureQueryDebugging() { + + if (isQueryDebuggingEnabled()) { + System.setProperty(GEMFIRE_QUERY_VERBOSE_PROPERTY, Boolean.TRUE.toString()); + } + } + @AfterClass public static void destroyAllGemFireMockObjects() { GemFireMockObjectsSupport.destroy(); } + @AfterClass + public static void unregisterAllDataSerializers() { + + stream(nullSafeArray(InternalDataSerializer.getSerializers(), DataSerializer.class)) + .map(DataSerializer::getId) + .forEach(InternalDataSerializer::unregister); + } + public static void closeGemFireCacheWaitOnCloseEvent() { closeGemFireCacheWaitOnCloseEvent(DEFAULT_WAIT_DURATION); } @@ -124,6 +164,84 @@ public abstract class IntegrationTestsSupport { }).orElse(cache); } + protected static String asApplicationName(Class type) { + return type.getSimpleName(); + } + + protected static String asDirectoryName(Class type) { + return String.format("%1$s-%2$s", asApplicationName(type), + LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd-hh-mm-ss"))); + } + + protected static File createDirectory(String pathname) { + return createDirectory(new File(pathname)); + } + + protected static File createDirectory(File directory) { + + assertThat(directory.isDirectory() || directory.mkdirs()) + .as(String.format("Failed to create directory [%s]", directory)).isTrue(); + + if (isDeleteDirectoryOnExit()) { + directory.deleteOnExit(); + } + + return directory; + } + + protected static boolean isDeleteDirectoryOnExit() { + return Boolean.valueOf(System.getProperty(DIRECTORY_DELETE_ON_EXIT_PROPERTY, Boolean.TRUE.toString())); + } + + protected boolean isQueryDebuggingEnabled() { + return DEBUG_GEMFIRE_QUERIES || withQueryDebugging(); + } + + protected static String getClassNameAsPath(Class type) { + return type.getName().replaceAll("\\.", "/"); + } + + protected static String getClassNameAsPath(Object obj) { + return getClassNameAsPath(obj.getClass()); + } + + protected static String getPackageNameAsPath(Class type) { + return type.getPackage().getName().replaceAll("\\.", "/"); + } + + protected static String getPackageNameAsPath(Object obj) { + return getPackageNameAsPath(obj.getClass()); + } + + protected static String getContextXmlFileLocation(Class type) { + return getClassNameAsPath(type).concat("-context.xml"); + } + + protected static String getServerContextXmlFileLocation(Class type) { + return getClassNameAsPath(type).concat("-server-context.xml"); + } + + protected static String logFile() { + return logFile(GEMFIRE_LOG_FILE); + } + + protected static String logFile(String defaultLogFilePathname) { + return System.getProperty(GEMFIRE_LOG_FILE_PROPERTY, defaultLogFilePathname); + } + + protected static String logLevel() { + return logLevel(GEMFIRE_LOG_LEVEL); + } + + protected static String logLevel(String defaultLogLevel) { + return System.getProperty(GEMFIRE_LOG_LEVEL_PROPERTY, defaultLogLevel); + } + + protected static void logSystemProperties() throws IOException { + FileUtils.write(new File(SYSTEM_PROPERTIES_LOG_FILE), + String.format("%s", CollectionUtils.toString(System.getProperties()))); + } + protected static boolean waitOn(Condition condition) { return waitOn(condition, DEFAULT_WAIT_DURATION); } @@ -152,6 +270,10 @@ public abstract class IntegrationTestsSupport { return condition.evaluate(); } + protected boolean withQueryDebugging() { + return DEFAULT_DEBUG_GEMFIRE_QUERIES; + } + @FunctionalInterface protected interface Condition { boolean evaluate();