Initial spring-data-tests-4-gemfire project commit.

This commit is contained in:
John Blum
2017-12-02 21:26:41 -08:00
commit 750ecc57b2
30 changed files with 5260 additions and 0 deletions

View File

@@ -0,0 +1,328 @@
/*
* Copyright 2016 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
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;
import java.io.File;
import java.io.IOException;
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.tests.util.ThreadUtils;
import org.springframework.data.gemfire.util.CollectionUtils;
/**
* The {@link ClientServerIntegrationTestsSupport} class is a abstract base class encapsulating common functionality
* to support the implementation of GemFire client/server tests.
*
* @author John Blum
* @see java.io.File
* @see java.net.ServerSocket
* @see java.net.Socket
* @see java.time.LocalDateTime
* @see org.apache.geode.cache.server.CacheServer
* @see org.springframework.context.annotation.AnnotationConfigApplicationContext
* @see org.springframework.data.gemfire.tests.process.ProcessExecutor
* @see org.springframework.data.gemfire.tests.process.ProcessWrapper
* @see SocketUtils
* @see ThreadUtils
* @since 0.0.1
*/
@SuppressWarnings("unused")
public class ClientServerIntegrationTestsSupport {
protected static final long DEFAULT_WAIT_DURATION = TimeUnit.SECONDS.toMillis(30);
protected static final long DEFAULT_WAIT_INTERVAL = 500L; // milliseconds
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 DEFAULT_HOSTNAME = "localhost";
protected static final String DIRECTORY_DELETE_ON_EXIT_PROPERTY = "spring.data.gemfire.directory.delete-on-exit";
protected static final String GEMFIRE_CACHE_SERVER_PORT_PROPERTY = "spring.data.gemfire.cache.server.port";
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 = "warning";
protected static final String GEMFIRE_LOG_LEVEL_PROPERTY = "spring.data.gemfire.log.level";
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 final String TEST_GEMFIRE_LOG_LEVEL = "warning";
/* (non-Javadoc) */
protected static String asApplicationName(Class<?> type) {
return type.getSimpleName();
}
/* (non-Javadoc) */
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")));
}
/* (non-Javadoc) */
protected static File createDirectory(String pathname) {
return createDirectory(new File(pathname));
}
/* (non-Javadoc) */
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;
}
/* (non-Javadoc) */
protected static int findAvailablePort() throws IOException {
ServerSocket serverSocket = null;
try {
serverSocket = new ServerSocket(0);
return serverSocket.getLocalPort();
}
finally {
SocketUtils.close(serverSocket);
}
}
/* (non-Javadoc) */
protected static String getClassNameAsPath(Class type) {
return type.getName().replaceAll("\\.", "/");
}
/* (non-Javadoc) */
protected static String getClassNameAsPath(Object obj) {
return getClassNameAsPath(obj.getClass());
}
/* (non-Javadoc) */
protected static String getPackageNameAsPath(Class type) {
return type.getPackage().getName().replaceAll("\\.", "/");
}
/* (non-Javadoc) */
protected static String getPackageNameAsPath(Object obj) {
return getPackageNameAsPath(obj.getClass());
}
/* (non-Javadoc) */
protected static String getContextXmlFileLocation(Class type) {
return getClassNameAsPath(type).concat("-context.xml");
}
/* (non-Javadoc) */
protected static String getServerContextXmlFileLocation(Class type) {
return getClassNameAsPath(type).concat("-server-context.xml");
}
/* (non-Javadoc) */
protected static boolean isDeleteDirectoryOnExit() {
return Boolean.valueOf(System.getProperty(DIRECTORY_DELETE_ON_EXIT_PROPERTY, Boolean.TRUE.toString()));
}
/* (non-Javadoc) */
protected static int intValue(Number number) {
return (number != null ? number.intValue() : 0);
}
/* (non-Javadoc) */
protected static String logFile() {
return logFile(GEMFIRE_LOG_FILE);
}
/* (non-Javadoc) */
protected static String logFile(String defaultLogFilePathname) {
return System.getProperty(GEMFIRE_LOG_FILE_PROPERTY, defaultLogFilePathname);
}
/* (non-Javadoc) */
protected static String logLevel() {
return logLevel(GEMFIRE_LOG_LEVEL);
}
/* (non-Javadoc) */
protected static String logLevel(String defaultLogLevel) {
return System.getProperty(GEMFIRE_LOG_LEVEL_PROPERTY, defaultLogLevel);
}
/* (non-Javadoc) */
protected static void logSystemProperties() throws IOException {
FileUtils.write(new File(SYSTEM_PROPERTIES_LOG_FILE),
String.format("%s", CollectionUtils.toString(System.getProperties())));
}
/* (non-Javadoc) */
protected static ProcessWrapper run(Class<?> type, String... arguments) throws IOException {
return run(createDirectory(asDirectoryName(type)), type, arguments);
}
/* (non-Javadoc) */
protected static ProcessWrapper run(File workingDirectory, Class<?> type, String... arguments) throws IOException {
return (isProcessRunAuto() ? launch(createDirectory(workingDirectory), type, arguments) : null);
}
/* (non-Javadoc) */
protected static ProcessWrapper run(String classpath, Class<?> type, String... arguments) throws IOException {
return run(createDirectory(asDirectoryName(type)), classpath, type, arguments);
}
/* (non-Javadoc) */
protected static ProcessWrapper run(File workingDirectory, String classpath, Class<?> type, String... arguments)
throws IOException {
return (isProcessRunAuto() ? launch(createDirectory(workingDirectory), classpath, type, arguments) : null);
}
/* (non-Javadoc) */
protected static boolean isProcessRunAuto() {
return !isProcessRunManual();
}
/* (non-Javadoc) */
protected static boolean isProcessRunManual() {
return Boolean.getBoolean(PROCESS_RUN_MANUAL_PROPERTY);
}
/* (non-Javadoc) */
protected static AnnotationConfigApplicationContext runSpringApplication(Class<?> annotatedClass, String... args) {
return runSpringApplication(asArray(annotatedClass), args);
}
/* (non-Javadoc) */
protected static AnnotationConfigApplicationContext runSpringApplication(Class<?>[] annotatedClasses,
String... args) {
AnnotationConfigApplicationContext applicationContext =
new AnnotationConfigApplicationContext(annotatedClasses);
applicationContext.registerShutdownHook();
return applicationContext;
}
/* (non-Javadoc) */
protected static boolean stop(ProcessWrapper process) {
return stop(process, DEFAULT_WAIT_DURATION);
}
/* (non-Javadoc) */
protected static boolean stop(ProcessWrapper process, long duration) {
return Optional.ofNullable(process)
.map(it -> {
it.stop(duration);
if (it.isNotRunning() && isDeleteDirectoryOnExit()) {
FileSystemUtils.deleteRecursive(it.getWorkingDirectory());
}
return it.isRunning();
})
.orElse(true);
}
/* (non-Javadoc) */
protected static boolean waitForCacheServerToStart(CacheServer cacheServer) {
return waitForServerToStart(cacheServer.getBindAddress(), cacheServer.getPort(), DEFAULT_WAIT_DURATION);
}
/* (non-Javadoc) */
protected static boolean waitForCacheServerToStart(CacheServer cacheServer, long duration) {
return waitForServerToStart(cacheServer.getBindAddress(), cacheServer.getPort(), duration);
}
/* (non-Javadoc) */
protected static boolean waitForServerToStart(String host, int port) {
return waitForServerToStart(host, port, DEFAULT_WAIT_DURATION);
}
/* (non-Javadoc) */
protected static boolean waitForServerToStart(final String host, final int port, long duration) {
return ThreadUtils.timedWait(duration, DEFAULT_WAIT_INTERVAL, new ThreadUtils.WaitCondition() {
AtomicBoolean connected = new AtomicBoolean(false);
public boolean waiting() {
Socket socket = null;
try {
if (!connected.get()) {
socket = new Socket(host, port);
connected.set(true);
}
}
catch (IOException ignore) {
}
finally {
SocketUtils.close(socket);
}
return !connected.get();
}
});
}
protected static boolean waitOn(Condition condition) {
return waitOn(condition, DEFAULT_WAIT_DURATION);
}
@SuppressWarnings("all")
protected static boolean waitOn(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();
}
protected interface Condition {
boolean evaluate();
}
}

View File

@@ -0,0 +1,189 @@
/*
* Copyright 2017 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.data.gemfire.tests.mock;
import java.util.Collection;
import java.util.Map;
import java.util.Optional;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.atomic.AtomicLong;
import java.util.concurrent.atomic.AtomicReference;
import java.util.function.Consumer;
import java.util.function.Function;
import java.util.function.Supplier;
import org.mockito.invocation.InvocationOnMock;
import org.mockito.stubbing.Answer;
import org.springframework.util.StringUtils;
/**
* The {@link MockObjectsSupport} class is an abstract base class encapsulating common operations and utilities
* used in mocking using Mockito.
*
* @author John Blum
* @see org.mockito.invocation.InvocationOnMock
* @see org.mockito.stubbing.Answer
* @since 2.0.0
*/
@SuppressWarnings("unused")
public abstract class MockObjectsSupport {
private static final AtomicLong mockObjectIdentifier = new AtomicLong(0L);
private static final String DEFAULT_MOCK_OBJECT_NAME = "MockObject";
public static String mockObjectIdentifier() {
return mockObjectIdentifier(DEFAULT_MOCK_OBJECT_NAME);
}
public static String mockObjectIdentifier(String mockObjectName) {
return String.format("%s%d", Optional.ofNullable(mockObjectName).filter(StringUtils::hasText)
.orElse(DEFAULT_MOCK_OBJECT_NAME), mockObjectIdentifier.incrementAndGet());
}
/* (non-Javadoc) */
protected static Answer<Boolean> newGetter(AtomicBoolean returnValue) {
return invocation -> returnValue.get();
}
/* (non-Javadoc) */
protected static Answer<Integer> newGetter(AtomicInteger returnValue) {
return invocation -> returnValue.get();
}
/* (non-Javadoc) */
protected static Answer<Long> newGetter(AtomicLong returnValue) {
return invocation -> returnValue.get();
}
/* (non-Javadoc) */
protected static <R> Answer<R> newGetter(AtomicReference<R> returnValue) {
return invocation -> returnValue.get();
}
/* (non-Javadoc) */
protected static <R, S> Answer<S> newGetter(AtomicReference<R> returnValue, Function<R, S> converter) {
return invocation -> converter.apply(returnValue.get());
}
/* (non-Javadoc) */
protected static <R> Answer<R> newGetter(Supplier<R> returnValue) {
return invocation -> returnValue.get();
}
/* (non-Javadoc) */
protected static <R, S> Answer<S> newGetter(Supplier<R> returnValue, Function<R, S> converter) {
return invocation -> converter.apply(returnValue.get());
}
/* (non-Javadoc) */
protected static <E, C extends Collection<E>, R> Answer<R> newAdder(C collection, R returnValue) {
return invocation -> {
collection.add(invocation.getArgument(0));
return returnValue;
};
}
/* (non-Javadoc) */
protected static <R> Answer<R> newSetter(AtomicBoolean argument, R returnValue) {
return invocation -> {
argument.set(invocation.getArgument(0));
return returnValue;
};
}
/* (non-Javadoc) */
protected static <R> Answer<R> newSetter(AtomicBoolean argument, Boolean value, R returnValue) {
return invocation -> {
argument.set(value);
return returnValue;
};
}
/* (non-Javadoc) */
protected static <R> Answer<R> newSetter(AtomicInteger argument, R returnValue) {
return invocation -> {
argument.set(invocation.getArgument(0));
return returnValue;
};
}
/* (non-Javadoc) */
protected static <R> Answer<R> newSetter(AtomicInteger argument, Integer value, R returnValue) {
return invocation -> {
argument.set(value);
return returnValue;
};
}
/* (non-Javadoc) */
protected static <R> Answer<R> newSetter(AtomicLong argument, R returnValue) {
return invocation -> {
argument.set(invocation.getArgument(0));
return returnValue;
};
}
/* (non-Javadoc) */
protected static <R> Answer<R> newSetter(AtomicLong argument, Long value, R returnValue) {
return invocation -> {
argument.set(value);
return returnValue;
};
}
/* (non-Javadoc) */
protected static <T, R> Answer<R> newSetter(AtomicReference<T> argument, R returnValue) {
return invocation -> {
argument.set(invocation.getArgument(0));
return returnValue;
};
}
/* (non-Javadoc) */
protected static <T, R> Answer<R> newSetter(AtomicReference<T> argument, T value, R returnValue) {
return invocation -> {
argument.set(value);
return returnValue;
};
}
/* (non-Javadoc) */
protected static <T, R> Answer<R> newSetter(AtomicReference<T> argument, Function<?, T> converter, R returnValue) {
return invocation -> {
argument.set(converter.apply(invocation.getArgument(0)));
return returnValue;
};
}
/* (non-Javadoc) */
protected static <K, V, R> Answer<R> newSetter(Map<K, V> argument, R returnValue) {
return invocation -> {
argument.put(invocation.getArgument(0), invocation.getArgument(1));
return returnValue;
};
}
/* (non-Javadoc) */
protected static <T> Answer<Void> newVoidAnswer(Consumer<InvocationOnMock> methodInvocation) {
return invocation -> {
methodInvocation.accept(invocation);
return null;
};
}
}

View File

@@ -0,0 +1,58 @@
/*
* Copyright 2017 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.data.gemfire.tests.mock.annotation;
import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Inherited;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import org.apache.geode.cache.GemFireCache;
import org.springframework.context.annotation.Import;
/**
* The {@link EnableGemFireMockObjects} annotation enables mocking of GemFire Objects in Unit Tests.
*
* @author John Blum
* @see Documented
* @see Inherited
* @see Retention
* @see Target
* @see org.apache.geode.cache.GemFireCache
* @see org.springframework.context.annotation.Import
* @since 2.0.0
*/
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Inherited
@Documented
@Import(GemFireMockObjectsConfiguration.class)
@SuppressWarnings("unused")
public @interface EnableGemFireMockObjects {
/**
* Determines whether the mock {@link GemFireCache} created for Unit Tests is a Singleton.
*
* Defaults to {@literal false}.
*
* @return a boolean value indicating whether the mock {@link GemFireCache} created for Unit Tests is a Singleton.
*/
boolean useSingletonCache() default false;
}

View File

@@ -0,0 +1,97 @@
/*
* Copyright 2017 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.data.gemfire.tests.mock.annotation;
import java.lang.annotation.Annotation;
import org.springframework.beans.factory.config.BeanPostProcessor;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.ImportAware;
import org.springframework.context.event.ContextClosedEvent;
import org.springframework.context.event.EventListener;
import org.springframework.core.annotation.AnnotationAttributes;
import org.springframework.core.type.AnnotationMetadata;
import org.springframework.data.gemfire.tests.mock.MockGemFireObjectsSupport;
import org.springframework.data.gemfire.tests.mock.config.MockGemFireObjectsBeanPostProcessor;
/**
* The {@link GemFireMockObjectsConfiguration} class is a Spring {@link Configuration @Configuration} class
* containing bean definitions to configure GemFire Object mocking.
*
* @author John Blum
* @see Annotation
* @see org.springframework.beans.factory.config.BeanPostProcessor
* @see org.springframework.context.annotation.Bean
* @see org.springframework.context.annotation.Configuration
* @see org.springframework.context.annotation.ImportAware
* @see org.springframework.core.annotation.AnnotationAttributes
* @see org.springframework.core.type.AnnotationMetadata
* @see org.springframework.data.gemfire.test.mock.config.MockGemFireObjectsBeanPostProcessor
* @since 2.0.0
*/
@SuppressWarnings("unused")
@Configuration
public class GemFireMockObjectsConfiguration implements ImportAware {
private boolean useSingletonCache = false;
@Override
public void setImportMetadata(AnnotationMetadata importingClassMetadata) {
if (isAnnotationPresent(importingClassMetadata)) {
AnnotationAttributes enableGemFireMockingAttributes = getAnnotationAttributes(importingClassMetadata);
this.useSingletonCache = enableGemFireMockingAttributes.getBoolean("useSingletonCache");
}
}
private Class<? extends Annotation> getAnnotationType() {
return EnableGemFireMockObjects.class;
}
private boolean isAnnotationPresent(AnnotationMetadata importingClassMetadata) {
return isAnnotationPresent(importingClassMetadata, getAnnotationType());
}
private boolean isAnnotationPresent(AnnotationMetadata importingClassMetadata,
Class<? extends Annotation> annotationType) {
return importingClassMetadata.hasAnnotation(annotationType.getName());
}
private AnnotationAttributes getAnnotationAttributes(AnnotationMetadata importingClassMetadata) {
return getAnnotationAttributes(importingClassMetadata, getAnnotationType());
}
private AnnotationAttributes getAnnotationAttributes(AnnotationMetadata importingClassMetadata,
Class<? extends Annotation> annotationType) {
return AnnotationAttributes.fromMap(importingClassMetadata.getAnnotationAttributes(annotationType.getName()));
}
@Bean
public BeanPostProcessor mockGemFireObjectsBeanPostProcessor() {
return MockGemFireObjectsBeanPostProcessor.newInstance(this.useSingletonCache);
}
@EventListener
public void releaseMockResources(ContextClosedEvent event) {
MockGemFireObjectsSupport.destroy();
}
}

View File

@@ -0,0 +1,58 @@
/*
* Copyright 2017 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.data.gemfire.tests.mock.annotation;
import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Inherited;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import org.junit.runner.RunWith;
import org.springframework.data.gemfire.tests.mock.context.MockGemFireObjectsApplicationContextInitializer;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringRunner;
/**
* The {@link GemFireUnitTest} annotation marks a test class as a GemFire Unit Test
* with GemFire Object mocking enabled.
*
* Additionally, this annotation enables Spring's {@link SpringRunner} JUnit Runner implementation
* using JUnit's {@link RunWith} annotation.
*
* @author John Blum
* @see Documented
* @see Inherited
* @see Retention
* @see Target
* @see org.junit.runner.RunWith
* @see org.springframework.data.gemfire.test.mock.context.MockGemFireObjectsApplicationContextInitializer
* @see org.springframework.test.context.ContextConfiguration
* @see org.springframework.test.context.junit4.SpringRunner
* @since 2.0.0
*/
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Inherited
@Documented
@RunWith(SpringRunner.class)
@ContextConfiguration(initializers = MockGemFireObjectsApplicationContextInitializer.class)
@SuppressWarnings("unused")
public @interface GemFireUnitTest {
}

View File

@@ -0,0 +1,173 @@
/*
* Copyright 2017 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.data.gemfire.tests.mock.config;
import static org.mockito.Mockito.when;
import java.util.Properties;
import java.util.concurrent.atomic.AtomicReference;
import org.apache.geode.cache.CacheFactory;
import org.apache.geode.cache.GemFireCache;
import org.apache.geode.cache.client.ClientCacheFactory;
import org.apache.geode.cache.client.PoolFactory;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.BeanPostProcessor;
import org.springframework.data.gemfire.CacheFactoryBean;
import org.springframework.data.gemfire.client.ClientCacheFactoryBean;
import org.springframework.data.gemfire.client.PoolFactoryBean;
import org.springframework.data.gemfire.tests.mock.MockGemFireObjectsSupport;
import org.springframework.lang.Nullable;
/**
* The {@link MockGemFireObjectsBeanPostProcessor} class is a Spring {@link BeanPostProcessor} that applies
* mocks and spies to Spring Data GemFire / Spring Data Geode and Pivotal GemFire / Apache Geode objects
* and components.
*
* @author John Blum
* @see org.apache.geode.cache.CacheFactory
* @see org.apache.geode.cache.client.ClientCacheFactory
* @see org.apache.geode.cache.client.PoolFactory
* @see org.springframework.beans.factory.config.BeanPostProcessor
* @see org.springframework.data.gemfire.CacheFactoryBean
* @see org.springframework.data.gemfire.client.ClientCacheFactoryBean
* @see org.springframework.data.gemfire.client.PoolFactoryBean
* @see org.springframework.data.gemfire.test.mock.MockGemFireObjectsSupport
* @since 2.0.0
*/
public class MockGemFireObjectsBeanPostProcessor implements BeanPostProcessor {
private static final boolean DEFAULT_USE_SINGLETON_CACHE = false;
private static final String GEMFIRE_PROPERTIES_BEAN_NAME = "gemfireProperties";
private volatile boolean useSingletonCache;
private final AtomicReference<Properties> gemfireProperties = new AtomicReference<>(new Properties());
public static MockGemFireObjectsBeanPostProcessor newInstance() {
return newInstance(DEFAULT_USE_SINGLETON_CACHE);
}
public static MockGemFireObjectsBeanPostProcessor newInstance(boolean useSingletonCache) {
MockGemFireObjectsBeanPostProcessor beanPostProcessor = new MockGemFireObjectsBeanPostProcessor();
beanPostProcessor.useSingletonCache = useSingletonCache;
return beanPostProcessor;
}
@Nullable @Override
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
return (isGemFireProperties(bean, beanName) ? set((Properties) bean)
: (bean instanceof CacheFactoryBean ? spyOnCacheFactoryBean((CacheFactoryBean) bean, this.useSingletonCache)
: (bean instanceof PoolFactoryBean ? mockThePoolFactoryBean((PoolFactoryBean) bean)
: bean)));
}
@Nullable @Override
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
if (bean instanceof GemFireCache) {
GemFireCache gemfireCache = (GemFireCache) bean;
when(gemfireCache.getDistributedSystem().getProperties()).thenReturn(this.gemfireProperties.get());
}
return bean;
}
private boolean isGemFireProperties(Object bean, String beanName) {
return (bean instanceof Properties && GEMFIRE_PROPERTIES_BEAN_NAME.equals(beanName));
}
private Object set(Properties gemfireProperties) {
this.gemfireProperties.set(gemfireProperties);
return gemfireProperties;
}
private Object spyOnCacheFactoryBean(CacheFactoryBean bean, boolean useSingletonCache) {
return (bean instanceof ClientCacheFactoryBean
? SpyingClientCacheFactoryInitializer.spyOn((ClientCacheFactoryBean) bean, useSingletonCache)
: SpyingCacheFactoryInitializer.spyOn(bean, useSingletonCache));
}
private Object mockThePoolFactoryBean(PoolFactoryBean bean) {
return MockingPoolFactoryInitializer.mock(bean);
}
protected static class SpyingCacheFactoryInitializer
implements CacheFactoryBean.CacheFactoryInitializer<CacheFactory> {
public static CacheFactoryBean spyOn(CacheFactoryBean cacheFactoryBean, boolean useSingletonCache) {
cacheFactoryBean.setCacheFactoryInitializer(new SpyingCacheFactoryInitializer(useSingletonCache));
return cacheFactoryBean;
}
private final boolean useSingletonCache;
protected SpyingCacheFactoryInitializer(boolean useSingletonCache) {
this.useSingletonCache = useSingletonCache;
}
@Override
public CacheFactory initialize(CacheFactory cacheFactory) {
return MockGemFireObjectsSupport.spyOn(cacheFactory, useSingletonCache);
}
}
protected static class SpyingClientCacheFactoryInitializer
implements CacheFactoryBean.CacheFactoryInitializer<ClientCacheFactory> {
public static ClientCacheFactoryBean spyOn(ClientCacheFactoryBean clientCacheFactoryBean,
boolean useSingletonCache) {
clientCacheFactoryBean.setCacheFactoryInitializer(
new SpyingClientCacheFactoryInitializer(useSingletonCache));
return clientCacheFactoryBean;
}
private final boolean useSingletonCache;
protected SpyingClientCacheFactoryInitializer(boolean useSingletonCache) {
this.useSingletonCache = useSingletonCache;
}
@Override
public ClientCacheFactory initialize(ClientCacheFactory clientCacheFactory) {
return MockGemFireObjectsSupport.spyOn(clientCacheFactory, this.useSingletonCache);
}
}
protected static class MockingPoolFactoryInitializer implements PoolFactoryBean.PoolFactoryInitializer {
public static PoolFactoryBean mock(PoolFactoryBean poolFactoryBean) {
poolFactoryBean.setPoolFactoryInitializer(new MockingPoolFactoryInitializer());
return poolFactoryBean;
}
@Override
public PoolFactory initialize(PoolFactory poolFactory) {
return MockGemFireObjectsSupport.mockPoolFactory();
}
}
}

View File

@@ -0,0 +1,41 @@
/*
* Copyright 2017 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.data.gemfire.tests.mock.context;
import org.springframework.context.ApplicationContextInitializer;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.data.gemfire.tests.mock.config.MockGemFireObjectsBeanPostProcessor;
/**
* The {@link MockGemFireObjectsApplicationContextInitializer} class is a Spring {@link ApplicationContextInitializer}
* used to initialize the Spring {@link ConfigurableApplicationContext} with GemFire Object mocking.
*
* @author John Blum
* @see org.springframework.context.ApplicationContextInitializer
* @see org.springframework.context.ConfigurableApplicationContext
* @see org.springframework.data.gemfire.test.mock.config.MockGemFireObjectsBeanPostProcessor
* @since 2.0.0
*/
public class MockGemFireObjectsApplicationContextInitializer
implements ApplicationContextInitializer<ConfigurableApplicationContext> {
@Override
@SuppressWarnings("all")
public void initialize(ConfigurableApplicationContext applicationContext) {
applicationContext.getBeanFactory().addBeanPostProcessor(MockGemFireObjectsBeanPostProcessor.newInstance());
}
}

View File

@@ -0,0 +1,73 @@
/*
* Copyright 2017 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.data.gemfire.tests.mock.support;
import java.lang.reflect.Method;
/**
* The {@link MockObjectInvocationException} class is an extension of {@link MockObjectsException} to categorize
* problems with {@link Method method} invocations on {@link Object Mock Objects}.
*
* @author John Blum
* @see org.springframework.data.gemfire.test.mock.support.MockObjectsException
* @since 2.0.1
*/
@SuppressWarnings("unused")
public class MockObjectInvocationException extends MockObjectsException {
/**
* Constructs a new instance of the {@link MockObjectInvocationException} class with no message or underlying cause.
*/
public MockObjectInvocationException() {
}
/**
* Constructs a new instance of the {@link MockObjectInvocationException} class initialized with
* the given {@link String message} describing the problem.
*
* @param message {@link String} describing the problem.
* @see String
*/
public MockObjectInvocationException(String message) {
super(message);
}
/**
* Constructs a new instance of the {@link MockObjectInvocationException} class initialized with
* the given {@link Throwable cause} of the underlying problem.
*
* @param cause {@link Throwable} object containing the cause of this exception.
* @see Throwable
*/
public MockObjectInvocationException(Throwable cause) {
super(cause);
}
/**
* Constructs a new instance of the {@link MockObjectInvocationException} class initialized with
* the given {@link String message} describing the underlying problem as well as the {@link Throwable cause}
* of the underlying problem.
*
* @param message {@link String} describing the problem.
* @param cause {@link Throwable} object containing the cause of this exception.
* @see Throwable
* @see String
*/
public MockObjectInvocationException(String message, Throwable cause) {
super(message, cause);
}
}

View File

@@ -0,0 +1,71 @@
/*
* Copyright 2017 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.data.gemfire.tests.mock.support;
/**
* The {@link MockObjectsException} class is a {@link RuntimeException} indicating a general problem
* with the Mock Objects infrastructure.
*
* @author John Blum
* @see RuntimeException
* @since 2.0.1
*/
@SuppressWarnings("unused")
public class MockObjectsException extends RuntimeException {
/**
* Constructs a new instance of the {@link MockObjectsException} class with no message or underlying cause.
*/
public MockObjectsException() {
}
/**
* Constructs a new instance of the {@link MockObjectsException} class initialized with
* the given {@link String message} describing the problem.
*
* @param message {@link String} describing the problem.
* @see String
*/
public MockObjectsException(String message) {
super(message);
}
/**
* Constructs a new instance of the {@link MockObjectsException} class initialized with
* the given {@link Throwable cause} of the underlying problem.
*
* @param cause {@link Throwable} object containing the cause of this exception.
* @see Throwable
*/
public MockObjectsException(Throwable cause) {
super(cause);
}
/**
* Constructs a new instance of the {@link MockObjectsException} class initialized with
* the given {@link String message} describing the underlying problem as well as the {@link Throwable cause}
* of the underlying problem.
*
* @param message {@link String} describing the problem.
* @param cause {@link Throwable} object containing the cause of this exception.
* @see Throwable
* @see String
*/
public MockObjectsException(String message, Throwable cause) {
super(message, cause);
}
}

View File

@@ -0,0 +1,45 @@
/*
* Copyright 2010-2013 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.data.gemfire.tests.process;
/**
* The PidUnavailableException class is a RuntimeException indicating that the process ID (PID) is unobtainable for
* the current process.
*
* @author John Blum
* @see RuntimeException
* @since 1.5.0
*/
@SuppressWarnings("unused")
public class PidUnavailableException extends RuntimeException {
public PidUnavailableException() {
}
public PidUnavailableException(final String message) {
super(message);
}
public PidUnavailableException(final Throwable cause) {
super(cause);
}
public PidUnavailableException(final String message, final Throwable cause) {
super(message, cause);
}
}

View File

@@ -0,0 +1,102 @@
/*
* Copyright 2010-2013 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.data.gemfire.tests.process;
import java.io.File;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.springframework.data.gemfire.tests.util.FileSystemUtils;
import org.springframework.util.Assert;
import org.springframework.util.StringUtils;
/**
* The {@link ProcessConfiguration} class is a container encapsulating configuration and context meta-data
* for a running process.
*
* @author John Blum
* @see ProcessBuilder
* @see org.springframework.data.gemfire.process.ProcessExecutor
* @since 1.5.0
*/
@SuppressWarnings("unused")
public class ProcessConfiguration {
private final boolean redirectingErrorStream;
private final File workingDirectory;
private final List<String> command;
private final Map<String, String> environment;
public static ProcessConfiguration create(ProcessBuilder processBuilder) {
Assert.notNull(processBuilder, "The ProcessBuilder used to configure and start the Process must not be null");
return new ProcessConfiguration(processBuilder.command(), processBuilder.directory(),
processBuilder.environment(), processBuilder.redirectErrorStream());
}
public ProcessConfiguration(List<String> command, File workingDirectory, Map<String, String> environment,
boolean redirectErrorStream) {
Assert.notEmpty(command, "Process command must be specified");
Assert.isTrue(FileSystemUtils.isDirectory(workingDirectory), String.format(
"Process working directory [%s] is not valid", workingDirectory));
this.command = new ArrayList<String>(command);
this.workingDirectory = workingDirectory;
this.redirectingErrorStream = redirectErrorStream;
this.environment = (environment != null
? Collections.unmodifiableMap(new HashMap<String, String>(environment))
: Collections.<String, String>emptyMap());
}
public List<String> getCommand() {
return Collections.unmodifiableList(command);
}
public String getCommandString() {
return StringUtils.arrayToDelimitedString(getCommand().toArray(), " ");
}
public Map<String, String> getEnvironment() {
return environment;
}
public boolean isRedirectingErrorStream() {
return redirectingErrorStream;
}
public File getWorkingDirectory() {
return workingDirectory;
}
@Override
public String toString() {
return "{ command = ".concat(getCommandString())
.concat(", workingDirectory = ".concat(getWorkingDirectory().getAbsolutePath()))
.concat(", environment = ".concat(String.valueOf(getEnvironment())))
.concat(", redirectingErrorStream = ".concat(String.valueOf(isRedirectingErrorStream())))
.concat(" }");
}
}

View File

@@ -0,0 +1,125 @@
/*
* Copyright 2010-2013 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.data.gemfire.tests.process;
import static org.springframework.data.gemfire.util.ArrayUtils.nullSafeArray;
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.stream.Collectors;
import org.springframework.data.gemfire.tests.util.FileSystemUtils;
import org.springframework.util.Assert;
import org.springframework.util.StringUtils;
/**
* The {@link ProcessExecutor} class is a utility class for launching and running Java processes.
*
* @author John Blum
* @see java.io.File
* @see java.lang.Process
* @see java.lang.ProcessBuilder
* @see java.lang.System
* @see org.springframework.data.gemfire.tests.process.ProcessConfiguration
* @see org.springframework.data.gemfire.tests.process.ProcessWrapper
* @since 1.5.0
*/
@SuppressWarnings("unused")
public abstract class ProcessExecutor {
public static final File JAVA_EXE = new File(new File(FileSystemUtils.JAVA_HOME, "bin"), "java");
public static final String JAVA_CLASSPATH = System.getProperty("java.class.path");
protected static final String SPRING_GEMFIRE_SYSTEM_PROPERTY_PREFIX = "spring.gemfire.";
protected static final String SPRING_DATA_GEMFIRE_SYSTEM_PROPERTY_PREFIX = "spring.data.gemfire.";
public static ProcessWrapper launch(Class<?> type, String... args) throws IOException {
return launch(FileSystemUtils.WORKING_DIRECTORY, type, args);
}
public static ProcessWrapper launch(File workingDirectory, Class<?> type, String... args) throws IOException {
return launch(workingDirectory, JAVA_CLASSPATH, type, args);
}
public static ProcessWrapper launch(File workingDirectory, String classpath, Class<?> type, String... args)
throws IOException {
ProcessBuilder processBuilder = new ProcessBuilder()
.command(buildCommand(classpath, type, args))
.directory(validateDirectory(workingDirectory))
.redirectErrorStream(true);
Process process = processBuilder.start();
ProcessWrapper processWrapper = new ProcessWrapper(process, ProcessConfiguration.create(processBuilder));
processWrapper.register((input) -> System.err.printf("[FORK] - %s%n", input));
return processWrapper;
}
protected static String[] buildCommand(String classpath, Class<?> type, String... args) {
Assert.notNull(type, "The main Java class to launch must not be null");
List<String> command = new ArrayList<>();
List<String> programArguments = new ArrayList<>(args.length);
command.add(JAVA_EXE.getAbsolutePath());
command.add("-server");
command.add("-ea");
command.add("-classpath");
command.add(StringUtils.hasText(classpath) ? classpath : JAVA_CLASSPATH);
command.addAll(getSpringGemFireSystemProperties());
for (String arg : nullSafeArray(args, String.class)) {
if (isJvmOption(arg)) {
command.add(arg);
}
else if (!StringUtils.isEmpty(arg)) {
programArguments.add(arg);
}
}
command.add(type.getName());
command.addAll(programArguments);
return command.toArray(new String[command.size()]);
}
protected static Collection<? extends String> getSpringGemFireSystemProperties() {
return System.getProperties().stringPropertyNames().stream()
.filter(property -> property.startsWith(SPRING_DATA_GEMFIRE_SYSTEM_PROPERTY_PREFIX)
|| property.startsWith(SPRING_GEMFIRE_SYSTEM_PROPERTY_PREFIX))
.map(property -> String.format("-D%1$s=%2$s", property, System.getProperty(property)))
.collect(Collectors.toList());
}
protected static boolean isJvmOption(String option) {
return (StringUtils.hasText(option) && (option.startsWith("-D") || option.startsWith("-X")));
}
protected static File validateDirectory(File workingDirectory) {
Assert.isTrue(workingDirectory != null && (workingDirectory.isDirectory() || workingDirectory.mkdirs()),
String.format("Failed to create working directory [%s]", workingDirectory));
return workingDirectory;
}
}

View File

@@ -0,0 +1,41 @@
/*
* Copyright 2010-2013 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.data.gemfire.tests.process;
import java.util.EventListener;
/**
* The {@link ProcessInputStreamListener} is a callback interface that gets called when input arrives from either a
* {@link Process process's} standard output steam or standard error stream.
*
* @author John Blum
* @see EventListener
* @since 1.5.0
*/
public interface ProcessInputStreamListener extends EventListener {
/**
* Callback method that gets called when the {@link Process} sends output from either its standard out
* or standard error streams.
*
* @param input {@link String} containing output from the {@link Process} that this listener is listening to.
* @see Process#getErrorStream()
* @see Process#getInputStream()
*/
void onInput(String input);
}

View File

@@ -0,0 +1,233 @@
/*
* Copyright 2010-2013 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.data.gemfire.tests.process;
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileFilter;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.io.OutputStream;
import java.io.PrintWriter;
import java.lang.management.ManagementFactory;
import java.lang.management.RuntimeMXBean;
import java.util.Scanner;
import java.util.logging.Logger;
import org.springframework.data.gemfire.tests.util.FileSystemUtils;
import org.springframework.data.gemfire.tests.util.IOUtils;
import org.springframework.util.Assert;
import org.springframework.util.StringUtils;
/**
* The {@link ProcessUtils} class is a utility class for working with Operating System (OS) {@link Process processes}.
*
* @author John Blum
* @see File
* @see Process
* @since 1.5.0
*/
@SuppressWarnings("unused")
public abstract class ProcessUtils {
protected static final Logger log = Logger.getLogger(ProcessUtils.class.getName());
protected static final String TERM_TOKEN = "<TERM/>";
/* (non-Javadoc) */
public static int currentPid() {
RuntimeMXBean runtimeMXBean = ManagementFactory.getRuntimeMXBean();
String runtimeMXBeanName = runtimeMXBean.getName();
Exception cause = null;
if (StringUtils.hasText(runtimeMXBeanName)) {
int atSignIndex = runtimeMXBeanName.indexOf('@');
if (atSignIndex > 0) {
try {
return Integer.parseInt(runtimeMXBeanName.substring(0, atSignIndex));
}
catch (NumberFormatException e) {
cause = e;
}
}
}
throw new PidUnavailableException(String.format("Process ID (PID) not available [%s]", runtimeMXBeanName),
cause);
}
/* (non-Javadoc) */
public static boolean isAlive(Process process) {
return (process != null && process.isAlive());
}
/* (non-Javadoc) */
public static boolean isRunning(int processId) {
/*
for (VirtualMachineDescriptor vmDescriptor : VirtualMachine.list()) {
if (String.valueOf(processId).equals(vmDescriptor.id())) {
return true;
}
}
return false;
*/
throw new UnsupportedOperationException("operation not supported");
}
/* (non-Javadoc) */
public static boolean isRunning(Process process) {
try {
process.exitValue();
return false;
}
catch (IllegalThreadStateException ignore) {
return true;
}
}
/* (non-Javadoc) */
public static void signalStop(Process process) throws IOException {
if (isRunning(process)) {
OutputStream processOutputStream = process.getOutputStream();
processOutputStream.write(TERM_TOKEN.concat("\n").getBytes());
processOutputStream.flush();
}
}
/* (non-Javadoc) */
@SuppressWarnings("all")
public static void waitForStopSignal() {
Scanner in = new Scanner(System.in);
while (!TERM_TOKEN.equals(in.next()));
}
/* (non-Javadoc) */
public static int findAndReadPid(File workingDirectory) {
File pidFile = findPidFile(workingDirectory);
if (pidFile == null) {
throw new PidUnavailableException(String.format(
"No PID file was found in working directory [%s] or any of it's sub-directories",
workingDirectory));
}
return readPid(pidFile);
}
/* (non-Javadoc) */
@SuppressWarnings("all")
protected static File findPidFile(File workingDirectory) {
Assert.isTrue(FileSystemUtils.isDirectory(workingDirectory), String.format(
"File [%s] is not a valid directory", workingDirectory));
for (File file : workingDirectory.listFiles(DirectoryPidFileFilter.INSTANCE)) {
if (file.isDirectory()) {
file = findPidFile(file);
}
if (PidFileFilter.INSTANCE.accept(file)) {
return file;
}
}
return null;
}
/* (non-Javadoc) */
@SuppressWarnings("all")
public static int readPid(File pidFile) {
Assert.isTrue(pidFile != null && pidFile.isFile(), String.format(
"File [%s] is not a valid file", pidFile));
BufferedReader fileReader = null;
String pidValue = null;
try {
fileReader = new BufferedReader(new FileReader(pidFile));
pidValue = String.valueOf(fileReader.readLine()).trim();
return Integer.parseInt(pidValue);
}
catch (FileNotFoundException e) {
throw new PidUnavailableException(String.format("PID file [%s] not found", pidFile), e);
}
catch (IOException e) {
throw new PidUnavailableException(String.format("failed to read PID from file [%s]", pidFile), e);
}
catch (NumberFormatException e) {
throw new PidUnavailableException(String.format(
"value [%1$s] from PID file [%2$s] was not a valid numerical PID", pidValue, pidFile), e);
}
finally {
IOUtils.close(fileReader);
}
}
/* (non-Javadoc) */
@SuppressWarnings("all")
public static void writePid(File pidFile, int pid) throws IOException {
Assert.isTrue(pidFile != null && (pidFile.isFile() || pidFile.createNewFile()), String.format(
"File [%s] is not a valid file", pidFile));
Assert.isTrue(pid > 0, String.format("PID [%d] must greater than 0", pid));
PrintWriter fileWriter = new PrintWriter(new BufferedWriter(new FileWriter(pidFile, false), 16), true);
try {
fileWriter.println(pid);
}
finally {
pidFile.deleteOnExit();
FileSystemUtils.close(fileWriter);
}
}
/* (non-Javadoc) */
protected static class DirectoryPidFileFilter extends PidFileFilter {
protected static final DirectoryPidFileFilter INSTANCE = new DirectoryPidFileFilter();
/**
* @inheritDoc
*/
@Override
public boolean accept(File path) {
return (path != null && (path.isDirectory() || super.accept(path)));
}
}
/* (non-Javadoc) */
protected static class PidFileFilter implements FileFilter {
protected static final PidFileFilter INSTANCE = new PidFileFilter();
/**
* @inheritDoc
*/
@Override
public boolean accept(File path) {
return (path != null && path.isFile() && path.getName().toLowerCase().endsWith(".pid"));
}
}
}

View File

@@ -0,0 +1,347 @@
/*
* Copyright 2010-2013 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.data.gemfire.tests.process;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.util.List;
import java.util.Map;
import java.util.concurrent.CopyOnWriteArrayList;
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 java.util.concurrent.atomic.AtomicBoolean;
import java.util.logging.Level;
import java.util.logging.Logger;
import org.springframework.data.gemfire.tests.util.FileSystemUtils;
import org.springframework.data.gemfire.tests.util.FileUtils;
import org.springframework.data.gemfire.tests.util.IOUtils;
import org.springframework.data.gemfire.tests.util.ThreadUtils;
import org.springframework.data.gemfire.tests.util.ThrowableUtils;
import org.springframework.util.Assert;
/**
* The ProcessWrapper class is a wrapper for a Process object representing an OS process and the ProcessBuilder used
* to construct and start the process.
*
* @author John Blum
* @see Process
* @see ProcessBuilder
* @since 1.5.0
*/
@SuppressWarnings("unused")
public class ProcessWrapper {
protected static final boolean DEFAULT_DAEMON_THREAD = true;
protected static final long DEFAULT_WAIT_TIME_MILLISECONDS = TimeUnit.SECONDS.toMillis(15);
private final List<ProcessInputStreamListener> listeners = new CopyOnWriteArrayList<>();
protected final Logger log = Logger.getLogger(getClass().getName());
private final Process process;
private final ProcessConfiguration processConfiguration;
/* (non-Javadoc) */
public ProcessWrapper(Process process, ProcessConfiguration processConfiguration) {
Assert.notNull(process, "Process must not be null");
Assert.notNull(processConfiguration, "The context and configuration meta-data providing details"
+ " about the environment in which the process is running and how the process was configured and executed"
+ " must not be null");
this.process = process;
this.processConfiguration = processConfiguration;
init();
}
/* (non-Javadoc) */
private void init() {
newThread("Process OUT Stream Reader Thread",
newProcessInputStreamReaderRunnable(process.getInputStream())).start();
if (!isRedirectingErrorStream()) {
newThread("Process ERR Stream Reader Thread",
newProcessInputStreamReaderRunnable(process.getErrorStream())).start();
}
}
/* (non-Javadoc) */
protected Runnable newProcessInputStreamReaderRunnable(InputStream in) {
return () -> {
if (isRunning()) {
BufferedReader inputReader = new BufferedReader(new InputStreamReader(in));
try {
for (String input = inputReader.readLine(); input != null; input = inputReader.readLine()) {
for (ProcessInputStreamListener listener : listeners) {
listener.onInput(input);
}
}
}
catch (IOException ignore) {
// Ignore IO error and just stop reading from the process input stream
// An IO error occurred most likely because the process was terminated
}
finally {
IOUtils.close(inputReader);
}
}
};
}
/* (non-Javadoc) */
protected Thread newThread(String name, Runnable task) {
Assert.hasText(name, "Thread name must be specified");
Assert.notNull(task, "Thread task must not be null");
Thread thread = new Thread(task, name);
thread.setDaemon(DEFAULT_DAEMON_THREAD);
thread.setPriority(Thread.NORM_PRIORITY);
return thread;
}
/* (non-Javadoc) */
public boolean isAlive() {
return ProcessUtils.isAlive(process);
}
/* (non-Javadoc) */
public boolean isNotAlive() {
return !isAlive();
}
/* (non-Javadoc) */
public List<String> getCommand() {
return processConfiguration.getCommand();
}
/* (non-Javadoc) */
public String getCommandString() {
return processConfiguration.getCommandString();
}
/* (non-Javadoc) */
public Map<String, String> getEnvironment() {
return processConfiguration.getEnvironment();
}
/* (non-Javadoc) */
public int getPid() {
return ProcessUtils.findAndReadPid(getWorkingDirectory());
}
/* (non-Javadoc) */
public int safeGetPid() {
try {
return getPid();
}
catch (PidUnavailableException ignore) {
return -1;
}
}
/* (non-Javadoc) */
public boolean isRedirectingErrorStream() {
return processConfiguration.isRedirectingErrorStream();
}
/* (non-Javadoc) */
public boolean isNotRunning() {
return !isRunning();
}
/* (non-Javadoc) */
public boolean isRunning() {
return ProcessUtils.isRunning(process);
}
/* (non-Javadoc) */
public File getWorkingDirectory() {
return processConfiguration.getWorkingDirectory();
}
/* (non-Javadoc) */
public int exitValue() {
return process.exitValue();
}
/* (non-Javadoc) */
public int safeExitValue() {
try {
return exitValue();
}
catch (IllegalThreadStateException ignore) {
return -1;
}
}
/* (non-Javadoc) */
public String readLogFile() throws IOException {
File[] logFiles = FileSystemUtils.listFiles(getWorkingDirectory(),
(path) -> (path != null && (path.isDirectory() || path.getAbsolutePath().endsWith(".log"))));
if (logFiles.length > 0) {
return readLogFile(logFiles[0]);
}
else {
throw new FileNotFoundException(String.format(
"No log files found in process's [%d] working directory [%s]",
safeGetPid(), getWorkingDirectory()));
}
}
/* (non-Javadoc) */
public String readLogFile(File log) throws IOException {
return FileUtils.read(log);
}
/* (non-Javadoc) */
public boolean register(ProcessInputStreamListener listener) {
return (listener != null && listeners.add(listener));
}
/* (non-Javadoc) */
public void registerShutdownHook() {
Runtime.getRuntime().addShutdownHook(new Thread(this::shutdown));
}
/* (non-Javadoc) */
public void signal() {
try {
OutputStream outputStream = process.getOutputStream();
outputStream.write("\n".getBytes());
outputStream.flush();
}
catch (IOException e) {
log.warning("Failed to signal process");
if (log.isLoggable(Level.FINE)) {
log.fine(ThrowableUtils.toString(e));
}
}
}
/* (non-Javadoc) */
public void signalStop() {
try {
ProcessUtils.signalStop(process);
}
catch (IOException e) {
log.warning("Failed to signal the process to stop");
if (log.isLoggable(Level.FINE)) {
log.fine(ThrowableUtils.toString(e));
}
}
}
/* (non-Javadoc) */
public int stop() {
return stop(DEFAULT_WAIT_TIME_MILLISECONDS);
}
/* (non-Javadoc) */
public int stop(long milliseconds) {
if (isRunning()) {
boolean interrupted = false;
int exitValue = -1;
int pid = safeGetPid();
long timeout = (System.currentTimeMillis() + milliseconds);
AtomicBoolean exited = new AtomicBoolean(false);
ExecutorService executorService = Executors.newSingleThreadExecutor();
try {
Future<Integer> futureExitValue = executorService.submit(() -> {
process.destroy();
int localExitValue = process.waitFor();
exited.set(true);
return localExitValue;
});
while (!exited.get() && System.currentTimeMillis() < timeout) {
try {
exitValue = futureExitValue.get(milliseconds, TimeUnit.MILLISECONDS);
log.info(String.format("Process [%s] has stopped%n", pid));
}
catch (InterruptedException ignore) {
interrupted = true;
}
}
}
catch (TimeoutException e) {
exitValue = -1;
log.warning(String.format("Process [%1$d] did not stop within the allotted timeout of %2$d seconds%n",
pid, TimeUnit.MILLISECONDS.toSeconds(milliseconds)));
}
catch (Exception ignore) {
// handles CancellationException, ExecutionException
}
finally {
executorService.shutdownNow();
if (interrupted) {
Thread.currentThread().interrupt();
}
}
return exitValue;
}
else {
return exitValue();
}
}
/* (non-Javadoc) */
public int shutdown() {
if (isRunning()) {
log.info(String.format("Stopping process [%d]...%n", safeGetPid()));
signalStop();
waitFor();
}
return stop();
}
/* (non-Javadoc) */
public boolean unregister(ProcessInputStreamListener listener) {
return listeners.remove(listener);
}
/* (non-Javadoc) */
public void waitFor() {
waitFor(DEFAULT_WAIT_TIME_MILLISECONDS);
}
/* (non-Javadoc) */
public void waitFor(long milliseconds) {
ThreadUtils.timedWait(milliseconds, 500, this::isRunning);
}
}

View File

@@ -0,0 +1,84 @@
/*
* Copyright 2010-2013 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.data.gemfire.tests.support;
import java.io.PrintWriter;
import java.sql.Connection;
import java.sql.SQLException;
import java.sql.SQLFeatureNotSupportedException;
import java.util.logging.Logger;
import javax.sql.DataSource;
/**
* The DataSourceAdapter class is an implementation of the DataSource interface with unsupported operations by default.
*
* @author John Blum
* @see Connection
* @see DataSource
* @since 1.3.4
*/
@SuppressWarnings("unused")
public abstract class DataSourceAdapter implements DataSource {
private static final String UNSUPPORTED_OPERATION_EXCEPTION_MESSAGE = "Not Implemented";
@Override
public Connection getConnection() throws SQLException {
throw new UnsupportedOperationException(UNSUPPORTED_OPERATION_EXCEPTION_MESSAGE);
}
@Override
public Connection getConnection(final String username, final String password) throws SQLException {
throw new UnsupportedOperationException(UNSUPPORTED_OPERATION_EXCEPTION_MESSAGE);
}
@Override
public PrintWriter getLogWriter() throws SQLException {
throw new UnsupportedOperationException(UNSUPPORTED_OPERATION_EXCEPTION_MESSAGE);
}
@Override
public void setLogWriter(final PrintWriter out) throws SQLException {
throw new UnsupportedOperationException(UNSUPPORTED_OPERATION_EXCEPTION_MESSAGE);
}
@Override
public int getLoginTimeout() throws SQLException {
throw new UnsupportedOperationException(UNSUPPORTED_OPERATION_EXCEPTION_MESSAGE);
}
@Override
public void setLoginTimeout(final int seconds) throws SQLException {
throw new UnsupportedOperationException(UNSUPPORTED_OPERATION_EXCEPTION_MESSAGE);
}
//@Override
public Logger getParentLogger() throws SQLFeatureNotSupportedException {
throw new UnsupportedOperationException(UNSUPPORTED_OPERATION_EXCEPTION_MESSAGE);
}
@Override
public boolean isWrapperFor(final Class<?> iface) throws SQLException {
throw new UnsupportedOperationException(UNSUPPORTED_OPERATION_EXCEPTION_MESSAGE);
}
@Override
public <T> T unwrap(final Class<T> iface) throws SQLException {
throw new UnsupportedOperationException(UNSUPPORTED_OPERATION_EXCEPTION_MESSAGE);
}
}

View File

@@ -0,0 +1,38 @@
/*
* Copyright 2010-2013 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.data.gemfire.tests.support;
import java.util.concurrent.atomic.AtomicLong;
/**
* The IdentifierSequence class is an Identifier (ID) generator generating unique IDs in sequence.
*
* @author John Blum
* @see System#currentTimeMillis()
* @see AtomicLong
* @since 1.5.3
*/
@SuppressWarnings("unused")
public abstract class IdentifierSequence {
private static final AtomicLong ID_SEQUENCE = new AtomicLong(System.currentTimeMillis());
public static long nextId() {
return ID_SEQUENCE.incrementAndGet();
}
}

View File

@@ -0,0 +1,50 @@
/*
* Copyright 2017 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.data.gemfire.tests.support;
import java.util.HashMap;
import java.util.Map;
/**
* The {@link MapBuilder} class employs the Builder Software Design Pattern to build a {@link Map}.
*
* @author John Blum
* @see Map
* @since 2.0.0
*/
public class MapBuilder<KEY, VALUE> {
public static <KEY, VALUE> MapBuilder<KEY, VALUE> newMapBuilder() {
return new MapBuilder<>();
}
private final Map<KEY, VALUE> map = new HashMap<>();
public MapBuilder<KEY, VALUE> put(KEY key, VALUE value) {
this.map.put(key, value);
return this;
}
public MapBuilder<KEY, VALUE> remove(KEY key) {
this.map.remove(key);
return this;
}
public Map<KEY, VALUE> build() {
return this.map;
}
}

View File

@@ -0,0 +1,249 @@
/*
* Copyright 2010-2013 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.data.gemfire.tests.util;
import static org.springframework.data.gemfire.util.ArrayUtils.nullSafeArray;
import static org.springframework.data.gemfire.util.CollectionUtils.nullSafeIterable;
import java.io.File;
import java.io.FileFilter;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import org.springframework.util.Assert;
/**
* The {@link FileSystemUtils} class is a utility class encapsulating functionality to process
* file system directories and files collectively.
*
* @author John Blum
* @see File
* @see FileFilter
* @see org.springframework.data.gemfire.test.support.FileUtils
* @see org.springframework.data.gemfire.test.support.IOUtils
* @since 1.5.0
*/
@SuppressWarnings("unused")
public abstract class FileSystemUtils extends FileUtils {
public static final File JAVA_HOME = new File(System.getProperty("java.home"));
public static final File JAVA_EXE = new File(new File(JAVA_HOME, "bin"), "java");
public static final File TEMPORARY_DIRECTORY = new File(System.getProperty("java.io.tmpdir"));
public static final File USER_HOME = new File(System.getProperty("user.home"));
public static final File WORKING_DIRECTORY = new File(System.getProperty("user.dir"));
public static final File[] NO_FILES = new File[0];
/* (non-Javadoc) */
public static boolean deleteRecursive(File path) {
return deleteRecursive(path, AllFilesFilter.INSTANCE);
}
/* (non-Javadoc) */
public static boolean deleteRecursive(File path, FileFilter fileFilter) {
boolean success = true;
if (isDirectory(path)) {
for (File file : safeListFiles(path, fileFilter)) {
success &= deleteRecursive(file);
}
}
return ((!exists(path) || path.delete()) && success);
}
public static boolean exists(File path) {
return (path != null && path.exists());
}
// returns sub-directory just below working directory
public static File getRootRelativeToWorkingDirectoryOrPath(File path) {
File localPath = path;
if (isDirectory(localPath)) {
while (localPath != null && !WORKING_DIRECTORY.equals(localPath.getParentFile())) {
localPath = localPath.getParentFile();
}
}
return (localPath != null ? localPath : path);
}
/* (non-Javadoc) */
public static File[] listFiles(File directory, FileFilter fileFilter) {
Assert.isTrue(isDirectory(directory), String.format(
"File [%s] does not refer to a valid directory", directory));
List<File> results = new ArrayList<File>();
for (File file : safeListFiles(directory, fileFilter)) {
if (isDirectory(file)) {
results.addAll(Arrays.asList(listFiles(file, fileFilter)));
}
else {
results.add(file);
}
}
return results.toArray(new File[results.size()]);
}
/* (non-Javadoc) */
public static File[] safeListFiles(File directory) {
return safeListFiles(directory, AllFilesFilter.INSTANCE);
}
/* (non-Javadoc) */
public static File[] safeListFiles(File directory, FileFilter fileFilter) {
FileFilter resolvedFileFilter = (fileFilter != null ? fileFilter : AllFilesFilter.INSTANCE);
File[] files = (isDirectory(directory) ? directory.listFiles(resolvedFileFilter) : null);
return (files != null ? files : NO_FILES);
}
public static class AllFilesFilter implements FileFilter {
public static final AllFilesFilter INSTANCE = new AllFilesFilter();
@Override
public boolean accept(File pathname) {
return true;
}
}
public static class CompositeFileFilter implements FileFilter {
private final FileFilter fileFilterOne;
private final FileFilter fileFilterTwo;
private final LogicalOperator logicalOperator;
private CompositeFileFilter(FileFilter fileFilterOne, LogicalOperator operator, FileFilter fileFilterTwo) {
this.fileFilterOne = fileFilterOne;
this.logicalOperator = operator;
this.fileFilterTwo = fileFilterTwo;
}
protected static FileFilter compose(FileFilter fileFilterOne, LogicalOperator operator, FileFilter fileFilterTwo) {
return (fileFilterOne == null ? fileFilterTwo : (fileFilterTwo == null ? fileFilterOne
: new CompositeFileFilter(fileFilterOne, operator, fileFilterTwo)));
}
public static FileFilter and(FileFilter... fileFilters) {
return and(Arrays.asList(nullSafeArray(fileFilters, FileFilter.class)));
}
public static FileFilter and(Iterable<FileFilter> fileFilters) {
FileFilter current = null;
for (FileFilter fileFilter : nullSafeIterable(fileFilters)) {
current = compose(current, LogicalOperator.AND, fileFilter);
}
return current;
}
public static FileFilter or(FileFilter... fileFilters) {
return or(Arrays.asList(nullSafeArray(fileFilters, FileFilter.class)));
}
public static FileFilter or(Iterable<FileFilter> fileFilters) {
FileFilter current = null;
for (FileFilter fileFilter : nullSafeIterable(fileFilters)) {
current = compose(current, LogicalOperator.OR, fileFilter);
}
return current;
}
@Override
public boolean accept(File pathname) {
switch (this.logicalOperator) {
case AND:
return (fileFilterOne.accept(pathname) && fileFilterTwo.accept(pathname));
case OR:
return (fileFilterOne.accept(pathname) || fileFilterTwo.accept(pathname));
default:
throw new UnsupportedOperationException(String.format(
"Logical operator [%s] is unsupported", this.logicalOperator));
}
}
enum LogicalOperator {
AND, OR;
}
}
public static class DirectoryOnlyFilter implements FileFilter {
public static final DirectoryOnlyFilter INSTANCE = new DirectoryOnlyFilter();
@Override
public boolean accept(File pathname) {
return isDirectory(pathname);
}
}
public static final class FileExtensionFilter extends FileOnlyFilter {
private final String fileExtension;
public static FileExtensionFilter newFileExtensionFilter(String fileExtension) {
return new FileExtensionFilter(fileExtension);
}
public FileExtensionFilter(String fileExtension) {
Assert.hasText(fileExtension, String.format("File extension [%s] must be specified", fileExtension));
this.fileExtension = fileExtension;
}
@Override
public boolean accept(File pathname) {
return (super.accept(pathname) && pathname.getAbsolutePath().toLowerCase().endsWith(this.fileExtension));
}
}
public static class FileOnlyFilter implements FileFilter {
public static final FileOnlyFilter INSTANCE = new FileOnlyFilter();
@Override
public boolean accept(File pathname) {
return isFile(pathname);
}
}
public static class NegatingFileFilter implements FileFilter {
private final FileFilter delegate;
public static NegatingFileFilter newNegatingFileFilter(FileFilter delegate) {
return new NegatingFileFilter(delegate);
}
public NegatingFileFilter(FileFilter delegate) {
Assert.notNull(delegate, "FileFilter must not be null");
this.delegate = delegate;
}
@Override
public boolean accept(File pathname) {
return !this.delegate.accept(pathname);
}
}
}

View File

@@ -0,0 +1,106 @@
/*
* Copyright 2010-2017 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.data.gemfire.tests.util;
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import org.springframework.util.Assert;
import org.springframework.util.StringUtils;
/**
* The {@link FileUtils} class is an abstract utility class for processing file system files
* by working with {@link File} objects.
*
* @author John Blum
* @see File
* @see FileReader
* @see FileWriter
* @see org.springframework.data.gemfire.test.support.IOUtils
* @since 1.5.0
*/
@SuppressWarnings("unused")
public abstract class FileUtils extends IOUtils {
public static final String FILE_SEPARATOR = System.getProperty("file.separator");
public static final String LINE_SEPARATOR = System.getProperty("line.separator");
/* (non-Javadoc) */
public static boolean isDirectory(File path) {
return (path != null && path.isDirectory());
}
/* (non-Javadoc) */
public static boolean isFile(File path) {
return (path != null && path.isFile());
}
/* (non-Javadoc) */
public static File newFile(String pathname) {
return new File(pathname);
}
/* (non-Javadoc) */
public static File newFile(File parent, String pathname) {
return new File(parent, pathname);
}
/* (non-Javadoc) */
@SuppressWarnings("all")
public static String read(File file) throws IOException {
Assert.isTrue(isFile(file), String.format("The file [%s] to read the contents from is not a valid file", file));
BufferedReader fileReader = new BufferedReader(new FileReader(file));
try {
StringBuilder buffer = new StringBuilder();
for (String line = fileReader.readLine(); line != null; line = fileReader.readLine()) {
buffer.append(line);
buffer.append(LINE_SEPARATOR);
}
return buffer.toString().trim();
}
finally {
close(fileReader);
}
}
/* (non-Javadoc) */
public static void write(File file, String contents) throws IOException {
Assert.notNull(file, "File must not be null");
Assert.isTrue(StringUtils.hasText(contents), String.format(
"The contents for File [%1$s] cannot be null or empty", file));
BufferedWriter fileWriter = null;
try {
fileWriter = new BufferedWriter(new FileWriter(file));
fileWriter.write(contents);
fileWriter.flush();
}
finally {
IOUtils.close(fileWriter);
}
}
}

View File

@@ -0,0 +1,96 @@
/*
* Copyright 2010-2017 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.data.gemfire.tests.util;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.Closeable;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.Serializable;
import java.util.logging.Level;
import java.util.logging.Logger;
/**
* The {@link IOUtils} class is an abstract utility class for working with IO operations.
*
* @author John Blum
* @see Closeable
* @since 1.5.0
*/
@SuppressWarnings("unused")
public abstract class IOUtils {
protected static final Logger log = Logger.getLogger(IOUtils.class.getName());
/* (non-Javadoc) */
public static boolean close(Closeable closeable) {
if (closeable != null) {
try {
closeable.close();
return true;
}
catch (IOException cause) {
if (log.isLoggable(Level.FINE)) {
log.fine(String.format("Failed to close the Closeable object (%1$s) due to an I/O error:%n%2$s",
closeable, ThrowableUtils.toString(cause)));
}
}
}
return false;
}
/* (non-Javadoc) */
@SuppressWarnings("unchecked")
public static <T> T deserializeObject(byte[] objectBytes) throws IOException, ClassNotFoundException {
ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(objectBytes);
ObjectInputStream objectInputStream = null;
try {
objectInputStream = new ObjectInputStream(byteArrayInputStream);
return (T) objectInputStream.readObject();
}
finally {
IOUtils.close(objectInputStream);
}
}
/* (non-Javadoc) */
public static byte[] serializeObject(Serializable obj) throws IOException {
ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
ObjectOutputStream objectOutputStream = null;
try {
objectOutputStream = new ObjectOutputStream(byteArrayOutputStream);
objectOutputStream.writeObject(obj);
objectOutputStream.flush();
return byteArrayOutputStream.toByteArray();
}
finally {
IOUtils.close(objectOutputStream);
}
}
}

View File

@@ -0,0 +1,69 @@
/*
* Copyright 2016 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
package org.springframework.data.gemfire.tests.util;
import java.io.IOException;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.logging.Logger;
/**
* {@link SocketUtils} is a utility class for managing {@link Socket} and {@link ServerSocket} objects.
*
* @author John Blum
* @see ServerSocket
* @see Socket
* @since 1.9.0
*/
@SuppressWarnings("unused")
public abstract class SocketUtils {
private static final Logger log = Logger.getLogger(SocketUtils.class.getName());
/* (non-Javadoc) */
public static boolean close(Socket socket) {
try {
if (socket != null) {
socket.close();
return true;
}
}
catch (IOException ignore) {
log.warning(String.format("Failed to close Socket [%s]", socket));
log.warning(ThrowableUtils.toString(ignore));
}
return false;
}
/* (non-Javadoc) */
public static boolean close(ServerSocket serverSocket) {
try {
if (serverSocket != null) {
serverSocket.close();
return true;
}
}
catch (IOException ignore) {
log.warning(String.format("Failed to close ServerSocket [%s]", serverSocket));
log.warning(ThrowableUtils.toString(ignore));
}
return false;
}
}

View File

@@ -0,0 +1,79 @@
/*
* Copyright 2010-2013 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.data.gemfire.tests.util;
/**
* The StackTraceUtils class is a utility class for working with stack trace frames (elements) of the current Thread.
*
* @author John Blum
* @see StackTraceElement
* @see Thread
* @see org.springframework.data.gemfire.test.support.ThreadUtils
* @since 1.5.3
*/
@SuppressWarnings("unused")
public abstract class StackTraceUtils extends ThreadUtils {
public static StackTraceElement getCaller() {
return getCaller(Thread.currentThread());
}
public static StackTraceElement getCaller(final Thread thread) {
return thread.getStackTrace()[2];
}
public static String getCallerName(final StackTraceElement element) {
return String.format("%1$%s.%2$s", element.getClass().getName(), element.getMethodName());
}
public static String getCallerSimpleName(final StackTraceElement element) {
return String.format("%1$%s.%2$s", element.getClass().getSimpleName(), element.getMethodName());
}
public static StackTraceElement getTestCaller() {
return getTestCaller(Thread.currentThread());
}
public static StackTraceElement getTestCaller(final Thread thread) {
for (StackTraceElement stackTraceElement : thread.getStackTrace()) {
if (isTestSuiteClass(stackTraceElement) && isTestCaseMethod(stackTraceElement)) {
return stackTraceElement;
}
}
return null;
}
private static boolean isTestCaseMethod(final StackTraceElement element) {
boolean result = element.getMethodName().toLowerCase().startsWith("test");
try {
result |= element.getClass().getMethod(element.getMethodName()).isAnnotationPresent(org.junit.Test.class);
}
catch (NoSuchMethodException ignore) {
}
return result;
}
private static boolean isTestSuiteClass(final StackTraceElement element) {
boolean result = element.getClass().getSimpleName().toLowerCase().endsWith("test");
result |= element.getClass().isAssignableFrom(junit.framework.TestCase.class);
return result;
}
}

View File

@@ -0,0 +1,79 @@
/*
* Copyright 2010-2013 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.data.gemfire.tests.util;
import java.util.concurrent.TimeUnit;
/**
* {@link ThreadUtils} is an abstract utility class for managing Java {@link Thread Threads}.
*
* @author John Blum
* @see Thread
* @since 1.5.0
*/
@SuppressWarnings("unused")
public abstract class ThreadUtils {
/* (non-Javadoc) */
public static boolean sleep(long milliseconds) {
try {
Thread.sleep(milliseconds);
return true;
}
catch (InterruptedException ignore) {
Thread.currentThread().interrupt();
return false;
}
}
public static boolean timedWait(long duration) {
return timedWait(duration, duration);
}
public static boolean timedWait(long duration, long interval) {
return timedWait(duration, interval, new WaitCondition() {
@Override public boolean waiting() {
return true;
}
});
}
@SuppressWarnings("all")
public static boolean timedWait(long duration, long interval, WaitCondition waitCondition) {
final long timeout = (System.currentTimeMillis() + duration);
interval = Math.min(interval, duration);
try {
while (waitCondition.waiting() && (System.currentTimeMillis() < timeout)) {
synchronized (waitCondition) {
TimeUnit.MILLISECONDS.timedWait(waitCondition, interval);
}
}
}
catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
return !waitCondition.waiting();
}
// TODO rename interface to Condition and waiting() method to evaluate()
public interface WaitCondition {
boolean waiting();
}
}

View File

@@ -0,0 +1,40 @@
/*
* Copyright 2010-2013 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.data.gemfire.tests.util;
import java.io.PrintWriter;
import java.io.StringWriter;
/**
* The ThrowableUtils class is a utility class for working with Throwable, Exception and Error objects.
*
* @author John Blum
* @see Error
* @see Exception
* @see Throwable
* @since 1.5.0
*/
@SuppressWarnings("unused")
public abstract class ThrowableUtils {
public static String toString(final Throwable t) {
StringWriter writer = new StringWriter();
t.printStackTrace(new PrintWriter(writer));
return writer.toString();
}
}

View File

@@ -0,0 +1,70 @@
/*
* Copyright 2010-2013 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.data.gemfire.tests.util;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.zip.ZipEntry;
import java.util.zip.ZipFile;
import org.springframework.core.io.Resource;
import org.springframework.data.gemfire.util.CollectionUtils;
import org.springframework.util.Assert;
import org.springframework.util.FileCopyUtils;
/**
* The ZipUtils class is an abstract utility class for working with JAR and ZIP archives.
*
* @author John Blum
* @see File
* @see ZipFile
* @since 1.5.0
*/
public abstract class ZipUtils {
public static void unzip(final Resource zipResource, final File directory) throws IOException {
Assert.notNull(zipResource, "The ZIP Resource must not be null!");
Assert.isTrue(directory != null && directory.isDirectory(), String.format(
"The file system pathname (%1$s) is not a valid directory!", directory));
ZipFile zipFile = new ZipFile(zipResource.getFile(), ZipFile.OPEN_READ);
for (ZipEntry entry : CollectionUtils.iterable(zipFile.entries())) {
if (entry.isDirectory()) {
new File(directory, entry.getName()).mkdirs();
}
else {
DataInputStream entryInputStream = new DataInputStream(zipFile.getInputStream(entry));
DataOutputStream entryOutputStream = new DataOutputStream(new FileOutputStream(
new File(directory, entry.getName())));
try {
FileCopyUtils.copy(entryInputStream, entryOutputStream);
}
finally {
IOUtils.close(entryInputStream);
IOUtils.close(entryOutputStream);
}
}
}
}
}