From 75676b534faa49422c788056a4a44495f47b0732 Mon Sep 17 00:00:00 2001 From: John Blum Date: Tue, 6 Nov 2018 11:57:50 -0800 Subject: [PATCH] Extend the o.s.data.gemfire.tests.integration.ForkingClientServerIntegrationTestsSupport class from STDG. Delegate query debugging configuration to the ForkingClientServerIntegrationTestsSupport class. Remove all waitFor.. methods, preferring the ForkingClientServerIntegrationTestsSupport class variants. Remove all test resource clean up (e.g. cleaning up DataSerializer registration) and rely on ForkingClientServerIntegrationTestsSupport class test resource clean up. --- .../AbstractGemFireIntegrationTests.java | 274 +++++------------- 1 file changed, 78 insertions(+), 196 deletions(-) diff --git a/spring-session-data-geode/src/integration-test/java/org/springframework/session/data/gemfire/AbstractGemFireIntegrationTests.java b/spring-session-data-geode/src/integration-test/java/org/springframework/session/data/gemfire/AbstractGemFireIntegrationTests.java index e22bbce..1e5337c 100644 --- a/spring-session-data-geode/src/integration-test/java/org/springframework/session/data/gemfire/AbstractGemFireIntegrationTests.java +++ b/spring-session-data-geode/src/integration-test/java/org/springframework/session/data/gemfire/AbstractGemFireIntegrationTests.java @@ -22,78 +22,68 @@ import static org.springframework.data.gemfire.util.ArrayUtils.nullSafeArray; import java.io.File; import java.io.IOException; -import java.net.Socket; import java.net.URISyntaxException; import java.net.URL; import java.time.Instant; import java.util.ArrayList; import java.util.List; import java.util.Optional; -import java.util.concurrent.TimeUnit; -import java.util.concurrent.atomic.AtomicBoolean; import java.util.stream.Collectors; import org.junit.Before; import org.mockito.Mockito; -import org.apache.geode.DataSerializer; -import org.apache.geode.cache.CacheClosedException; import org.apache.geode.cache.DataPolicy; import org.apache.geode.cache.ExpirationAction; import org.apache.geode.cache.ExpirationAttributes; import org.apache.geode.cache.GemFireCache; import org.apache.geode.cache.Region; -import org.apache.geode.cache.client.ClientCache; -import org.apache.geode.cache.client.ClientCacheFactory; import org.apache.geode.cache.query.Index; -import org.apache.geode.cache.server.CacheServer; -import org.apache.geode.internal.InternalDataSerializer; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.ApplicationListener; +import org.springframework.data.gemfire.tests.integration.ForkingClientServerIntegrationTestsSupport; import org.springframework.session.Session; +import org.springframework.session.SessionRepository; import org.springframework.session.data.gemfire.support.GemFireUtils; import org.springframework.session.events.AbstractSessionEvent; import org.springframework.util.StringUtils; /** * {@link AbstractGemFireIntegrationTests} is an abstract base class encapsulating common functionality - * for writing Spring Session Data Pivotal GemFire & Apache Geode integration tests. + * for writing Spring Session for Apache Geode & Pivotal GemFire integration tests. * * @author John Blum - * @since 1.1.0 - * @see org.apache.geode.DataSerializer + * @see java.io.File + * @see java.net.URL + * @see java.time.Instant * @see org.apache.geode.cache.DataPolicy * @see org.apache.geode.cache.ExpirationAttributes * @see org.apache.geode.cache.GemFireCache * @see org.apache.geode.cache.Region - * @see org.apache.geode.cache.client.ClientCache * @see org.apache.geode.cache.query.Index - * @see org.apache.geode.cache.server.CacheServer - * @see org.apache.geode.internal.InternalDataSerializer + * @see org.springframework.data.gemfire.tests.integration.ForkingClientServerIntegrationTestsSupport * @see org.springframework.session.Session + * @see org.springframework.session.SessionRepository + * @see org.springframework.session.events.AbstractSessionEvent + * @since 1.1.0 */ -@SuppressWarnings("unused") -public abstract class AbstractGemFireIntegrationTests { +public abstract class AbstractGemFireIntegrationTests extends ForkingClientServerIntegrationTestsSupport { protected static final boolean DEFAULT_ENABLE_QUERY_DEBUGGING = false; - protected static final boolean GEMFIRE_QUERY_DEBUG = Boolean.getBoolean("spring.session.data.gemfire.query.debug"); - - protected static final int DEFAULT_GEMFIRE_SERVER_PORT = CacheServer.DEFAULT_PORT; - - protected static final long DEFAULT_WAIT_DURATION = TimeUnit.SECONDS.toMillis(20); - protected static final long DEFAULT_WAIT_INTERVAL = 500L; + protected static final boolean GEMFIRE_QUERY_DEBUG = + Boolean.getBoolean("spring.session.data.gemfire.query.debug"); protected static final File WORKING_DIRECTORY = new File(System.getProperty("user.dir")); protected static final String DEFAULT_PROCESS_CONTROL_FILENAME = "process.ctl"; protected static final String GEMFIRE_LOG_FILE_NAME = - System.getProperty("spring.session.data.gemfire.log-file", "gemfire-server.log"); + System.getProperty("spring.session.data.gemfire.log.file", "gemfire-server.log"); protected static final String GEMFIRE_LOG_LEVEL = - System.getProperty("spring.session.data.gemfire.log-level", "error"); + System.getProperty("spring.session.data.gemfire.log.level", "error"); @Autowired(required = false) protected GemFireCache gemfireCache; @@ -101,11 +91,11 @@ public abstract class AbstractGemFireIntegrationTests { @Autowired(required = false) protected GemFireOperationsSessionRepository gemfireSessionRepository; + @Autowired(required = false) + protected SessionRepository sessionRepository; + @Before public void setup() { -<<<<<<< HEAD - System.setProperty("gemfire.Query.VERBOSE", String.valueOf(isQueryDebuggingEnabled())); -======= this.sessionRepository = this.gemfireSessionRepository != null ? this.gemfireSessionRepository @@ -114,22 +104,24 @@ public abstract class AbstractGemFireIntegrationTests { this.sessionRepository = Optional.ofNullable(this.sessionRepository) .map(Mockito::spy) .orElse(null); ->>>>>>> 9f810ed... Add support to prevent SessionRepository.save(:Session) invocations for non-dirty Sessions. } protected static String buildClassPathContainingJarFiles(String... jarFilenames) { StringBuilder classpath = new StringBuilder(); - stream(nullSafeArray(jarFilenames, String.class)).map(AbstractGemFireIntegrationTests::findJarInClasspath) - .forEach(classpathEntry -> classpathEntry.filter(StringUtils::hasText).ifPresent(it -> { + stream(nullSafeArray(jarFilenames, String.class)) + .map(AbstractGemFireIntegrationTests::findJarInClassPath) + .forEach(classpathEntry -> classpathEntry + .filter(StringUtils::hasText) + .ifPresent(it -> { - if (classpath.length() > 0) { - classpath.append(File.pathSeparator); - } + if (classpath.length() > 0) { + classpath.append(File.pathSeparator); + } - classpath.append(it); - })); + classpath.append(it); + })); return classpath.toString(); } @@ -137,16 +129,20 @@ public abstract class AbstractGemFireIntegrationTests { private static Optional findClassInFileSystem(Class type) { return Optional.ofNullable(type) - .map(AbstractGemFireIntegrationTests::getResourceName) + .map(AbstractGemFireIntegrationTests::toResourceName) .map(resourceName -> type.getClassLoader().getResource(resourceName)); } - private static Optional findJarInClasspath(String jarFilename) { - return stream(nullSafeArray(System.getProperty("java.class.path").split(File.pathSeparator), String.class)) - .filter(element -> element.contains(jarFilename)).findFirst(); + private static Optional findJarInClassPath(String jarFilename) { + + String[] javaClassPath = System.getProperty("java.class.path").split(File.pathSeparator); + + return stream(nullSafeArray(javaClassPath, String.class)) + .filter(element -> element.contains(jarFilename)) + .findFirst(); } - private static String getResourceName(Class type) { + private static String toResourceName(Class type) { return type.getName().replaceAll("\\.", "/").concat(".class"); } @@ -155,7 +151,8 @@ public abstract class AbstractGemFireIntegrationTests { File directory = new File(WORKING_DIRECTORY, pathname); assertThat(directory.isDirectory() || directory.mkdirs()) - .as(String.format("Failed to create directory [%s]", directory)).isTrue(); + .as(String.format("Failed to create directory [%s]", directory)) + .isTrue(); directory.deleteOnExit(); @@ -185,17 +182,23 @@ public abstract class AbstractGemFireIntegrationTests { commandLine.add(type.getName()); commandLine.addAll(extractProgramArguments(args)); - //System.err.printf("Java process command-line is [%s]%n", commandLine); + //System.err.printf("Java process command-line is [%s]%n", commandLine); return commandLine; } private static List extractJvmArguments(String... args) { - return stream(args).filter(arg -> arg.startsWith("-")).collect(Collectors.toList()); + + return stream(args) + .filter(arg -> arg.startsWith("-")) + .collect(Collectors.toList()); } private static List extractProgramArguments(String... args) { - return stream(args).filter(arg -> !arg.startsWith("-")).collect(Collectors.toList()); + + return stream(args) + .filter(arg -> !arg.startsWith("-")) + .collect(Collectors.toList()); } // Run Java Class in Directory with Arguments @@ -216,10 +219,10 @@ public abstract class AbstractGemFireIntegrationTests { .map(File::getAbsolutePath) .map(pathname -> { - int indexOfTypeName = pathname.indexOf(getResourceName(type)); + int indexOfTypeName = pathname.indexOf(toResourceName(type)); - pathname = (indexOfTypeName > -1 ? pathname.substring(0, indexOfTypeName) : pathname); - pathname = (pathname.endsWith(File.separator) ? pathname.substring(0, pathname.length() - 1) : pathname); + pathname = indexOfTypeName > -1 ? pathname.substring(0, indexOfTypeName) : pathname; + pathname = pathname.endsWith(File.separator) ? pathname.substring(0, pathname.length() - 1) : pathname; return pathname; }) @@ -238,138 +241,13 @@ public abstract class AbstractGemFireIntegrationTests { } private static Process run(List command, File directory) throws IOException { - return new ProcessBuilder().command(command).directory(directory).inheritIO().redirectErrorStream(true).start(); - } - protected static void unregisterAllDataSerializers() { - stream(nullSafeArray(InternalDataSerializer.getSerializers(), DataSerializer.class)) - .map(DataSerializer::getId).forEach(InternalDataSerializer::unregister); - } - - protected static boolean waitForCacheServerToStart(CacheServer cacheServer) { - return waitForCacheServerToStart(cacheServer, DEFAULT_WAIT_DURATION); - } - - protected static boolean waitForCacheServerToStart(CacheServer cacheServer, long duration) { - return waitForCacheServerToStart(cacheServer.getBindAddress(), cacheServer.getPort(), duration); - } - - protected static boolean waitForCacheServerToStart(String host, int port) { - return waitForCacheServerToStart(host, port, DEFAULT_WAIT_DURATION); - } - - protected static boolean waitForCacheServerToStart(final String host, final int port, long duration) { - - return waitOnCondition(new Condition() { - - AtomicBoolean connected = new AtomicBoolean(false); - - public boolean evaluate() { - - Socket socket = null; - - try { - if (!this.connected.get()) { - socket = new Socket(host, port); - this.connected.set(true); - } - } - catch (IOException ignore) { - } - finally { - GemFireUtils.close(socket); - } - - return connected.get(); - } - }, duration); - } - - // NOTE this method would not be necessary except Spring Sessions' build does not fork - // the test JVM - // for every test class. - protected static boolean waitForClientCacheToClose() { - return waitForClientCacheToClose(DEFAULT_WAIT_DURATION); - } - - protected static boolean waitForClientCacheToClose(long duration) { - - try { - - ClientCache clientCache = ClientCacheFactory.getAnyInstance(); - - clientCache.close(); - waitOnCondition(clientCache::isClosed, duration); - - return clientCache.isClosed(); - } - catch (CacheClosedException ignore) { - return true; - } - - } - - protected static boolean waitForProcessToStart(Process process, File directory) { - return waitForProcessToStart(process, directory, DEFAULT_WAIT_DURATION); - } - - @SuppressWarnings("all") - protected static boolean waitForProcessToStart(Process process, File directory, long duration) { - - File processControl = new File(directory, DEFAULT_PROCESS_CONTROL_FILENAME); - - waitOnCondition(new Condition() { - public boolean evaluate() { - return processControl.isFile(); - } - }, duration); - - return process.isAlive(); - } - - 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 e) { - Thread.currentThread().interrupt(); - } - - return (process.isAlive() ? -1 : process.exitValue()); - } - - protected static boolean waitOnCondition(Condition condition) { - return waitOnCondition(condition, DEFAULT_WAIT_DURATION); - } - - @SuppressWarnings("all") - protected static boolean waitOnCondition(Condition condition, long duration) { - - long timeout = (System.currentTimeMillis() + duration); - - try { - while (!condition.evaluate() && System.currentTimeMillis() < timeout) { - synchronized (condition) { - TimeUnit.MILLISECONDS.timedWait(condition, DEFAULT_WAIT_INTERVAL); - } - } - } - catch (InterruptedException e) { - Thread.currentThread().interrupt(); - } - - return condition.evaluate(); + return new ProcessBuilder() + .command(command) + .directory(directory) + .inheritIO() + .redirectErrorStream(true) + .start(); } @SuppressWarnings("all") @@ -387,12 +265,14 @@ public abstract class AbstractGemFireIntegrationTests { } protected void assertValidSession(Session session) { + assertThat(session).isNotNull(); assertThat(session.getId()).isNotEmpty(); assertThat(session.isExpired()).isFalse(); } protected void assertRegion(Region actualRegion, String expectedName, DataPolicy expectedDataPolicy) { + assertThat(actualRegion).isNotNull(); assertThat(actualRegion.getName()).isEqualTo(expectedName); assertThat(actualRegion.getFullPath()).isEqualTo(GemFireUtils.toRegionPath(expectedName)); @@ -401,6 +281,7 @@ public abstract class AbstractGemFireIntegrationTests { } protected void assertIndex(Index index, String expectedExpression, String expectedFromClause) { + assertThat(index).isNotNull(); assertThat(index.getIndexedExpression()).isEqualTo(expectedExpression); assertThat(index.getFromClause()).isEqualTo(expectedFromClause); @@ -411,7 +292,7 @@ public abstract class AbstractGemFireIntegrationTests { } protected void assertEntryIdleTimeout(ExpirationAttributes actualExpirationAttributes, - ExpirationAction expectedAction, int expectedTimeout) { + ExpirationAction expectedAction, int expectedTimeout) { assertThat(actualExpirationAttributes).isNotNull(); assertThat(actualExpirationAttributes.getAction()).isEqualTo(expectedAction); @@ -422,18 +303,27 @@ public abstract class AbstractGemFireIntegrationTests { return DEFAULT_ENABLE_QUERY_DEBUGGING; } - protected boolean isQueryDebuggingEnabled() { - return (GEMFIRE_QUERY_DEBUG || enableQueryDebugging()); + protected SessionRepository getSessionRepository() { + return this.sessionRepository; } + @SuppressWarnings("unused") protected List listRegions(GemFireCache gemfireCache) { - return gemfireCache.rootRegions().stream().map(Region::getFullPath).collect(Collectors.toList()); + + return gemfireCache.rootRegions().stream() + .map(Region::getFullPath) + .collect(Collectors.toList()); + } + + @Override + protected boolean withQueryDebugging() { + return enableQueryDebugging(); } @SuppressWarnings("unchecked") protected T createSession() { - T session = (T) this.gemfireSessionRepository.createSession(); + T session = (T) getSessionRepository().createSession(); assertThat(session).isNotNull(); @@ -452,7 +342,7 @@ public abstract class AbstractGemFireIntegrationTests { @SuppressWarnings("all") protected T delete(T session) { - this.gemfireSessionRepository.delete(session); + getSessionRepository().deleteById(session.getId()); return session; } @@ -463,11 +353,11 @@ public abstract class AbstractGemFireIntegrationTests { @SuppressWarnings("unchecked") protected T get(String sessionId) { - return (T) this.gemfireSessionRepository.findById(sessionId); + return (T) getSessionRepository().findById(sessionId); } protected T save(T session) { - this.gemfireSessionRepository.save(session); + getSessionRepository().save(session); return session; } @@ -503,17 +393,9 @@ public abstract class AbstractGemFireIntegrationTests { public T waitForSessionEvent(long duration) { - waitOnCondition(() -> (SessionEventListener.this.sessionEvent != null), duration); + waitOn(() -> SessionEventListener.this.sessionEvent != null, duration); return getSessionEvent(); } } - - /** - * The Condition interface defines a logical condition that must be satisfied before - * it is safe to proceed. - */ - protected interface Condition { - boolean evaluate(); - } }