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

6
.gitignore vendored Normal file
View File

@@ -0,0 +1,6 @@
*.iml
*.ipr
*.iws
*.DS_Store
.idea/
target/

201
LICENSE Normal file
View File

@@ -0,0 +1,201 @@
Apache License
Version 2.0, January 2004
http://www.apache.org/licenses/
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
1. Definitions.
"License" shall mean the terms and conditions for use, reproduction,
and distribution as defined by Sections 1 through 9 of this document.
"Licensor" shall mean the copyright owner or entity authorized by
the copyright owner that is granting the License.
"Legal Entity" shall mean the union of the acting entity and all
other entities that control, are controlled by, or are under common
control with that entity. For the purposes of this definition,
"control" means (i) the power, direct or indirect, to cause the
direction or management of such entity, whether by contract or
otherwise, or (ii) ownership of fifty percent (50%) or more of the
outstanding shares, or (iii) beneficial ownership of such entity.
"You" (or "Your") shall mean an individual or Legal Entity
exercising permissions granted by this License.
"Source" form shall mean the preferred form for making modifications,
including but not limited to software source code, documentation
source, and configuration files.
"Object" form shall mean any form resulting from mechanical
transformation or translation of a Source form, including but
not limited to compiled object code, generated documentation,
and conversions to other media types.
"Work" shall mean the work of authorship, whether in Source or
Object form, made available under the License, as indicated by a
copyright notice that is included in or attached to the work
(an example is provided in the Appendix below).
"Derivative Works" shall mean any work, whether in Source or Object
form, that is based on (or derived from) the Work and for which the
editorial revisions, annotations, elaborations, or other modifications
represent, as a whole, an original work of authorship. For the purposes
of this License, Derivative Works shall not include works that remain
separable from, or merely link (or bind by name) to the interfaces of,
the Work and Derivative Works thereof.
"Contribution" shall mean any work of authorship, including
the original version of the Work and any modifications or additions
to that Work or Derivative Works thereof, that is intentionally
submitted to Licensor for inclusion in the Work by the copyright owner
or by an individual or Legal Entity authorized to submit on behalf of
the copyright owner. For the purposes of this definition, "submitted"
means any form of electronic, verbal, or written communication sent
to the Licensor or its representatives, including but not limited to
communication on electronic mailing lists, source code control systems,
and issue tracking systems that are managed by, or on behalf of, the
Licensor for the purpose of discussing and improving the Work, but
excluding communication that is conspicuously marked or otherwise
designated in writing by the copyright owner as "Not a Contribution."
"Contributor" shall mean Licensor and any individual or Legal Entity
on behalf of whom a Contribution has been received by Licensor and
subsequently incorporated within the Work.
2. Grant of Copyright License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
copyright license to reproduce, prepare Derivative Works of,
publicly display, publicly perform, sublicense, and distribute the
Work and such Derivative Works in Source or Object form.
3. Grant of Patent License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
(except as stated in this section) patent license to make, have made,
use, offer to sell, sell, import, and otherwise transfer the Work,
where such license applies only to those patent claims licensable
by such Contributor that are necessarily infringed by their
Contribution(s) alone or by combination of their Contribution(s)
with the Work to which such Contribution(s) was submitted. If You
institute patent litigation against any entity (including a
cross-claim or counterclaim in a lawsuit) alleging that the Work
or a Contribution incorporated within the Work constitutes direct
or contributory patent infringement, then any patent licenses
granted to You under this License for that Work shall terminate
as of the date such litigation is filed.
4. Redistribution. You may reproduce and distribute copies of the
Work or Derivative Works thereof in any medium, with or without
modifications, and in Source or Object form, provided that You
meet the following conditions:
(a) You must give any other recipients of the Work or
Derivative Works a copy of this License; and
(b) You must cause any modified files to carry prominent notices
stating that You changed the files; and
(c) You must retain, in the Source form of any Derivative Works
that You distribute, all copyright, patent, trademark, and
attribution notices from the Source form of the Work,
excluding those notices that do not pertain to any part of
the Derivative Works; and
(d) If the Work includes a "NOTICE" text file as part of its
distribution, then any Derivative Works that You distribute must
include a readable copy of the attribution notices contained
within such NOTICE file, excluding those notices that do not
pertain to any part of the Derivative Works, in at least one
of the following places: within a NOTICE text file distributed
as part of the Derivative Works; within the Source form or
documentation, if provided along with the Derivative Works; or,
within a display generated by the Derivative Works, if and
wherever such third-party notices normally appear. The contents
of the NOTICE file are for informational purposes only and
do not modify the License. You may add Your own attribution
notices within Derivative Works that You distribute, alongside
or as an addendum to the NOTICE text from the Work, provided
that such additional attribution notices cannot be construed
as modifying the License.
You may add Your own copyright statement to Your modifications and
may provide additional or different license terms and conditions
for use, reproduction, or distribution of Your modifications, or
for any such Derivative Works as a whole, provided Your use,
reproduction, and distribution of the Work otherwise complies with
the conditions stated in this License.
5. Submission of Contributions. Unless You explicitly state otherwise,
any Contribution intentionally submitted for inclusion in the Work
by You to the Licensor shall be under the terms and conditions of
this License, without any additional terms or conditions.
Notwithstanding the above, nothing herein shall supersede or modify
the terms of any separate license agreement you may have executed
with Licensor regarding such Contributions.
6. Trademarks. This License does not grant permission to use the trade
names, trademarks, service marks, or product names of the Licensor,
except as required for reasonable and customary use in describing the
origin of the Work and reproducing the content of the NOTICE file.
7. Disclaimer of Warranty. Unless required by applicable law or
agreed to in writing, Licensor provides the Work (and each
Contributor provides its Contributions) on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
implied, including, without limitation, any warranties or conditions
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
PARTICULAR PURPOSE. You are solely responsible for determining the
appropriateness of using or redistributing the Work and assume any
risks associated with Your exercise of permissions under this License.
8. Limitation of Liability. In no event and under no legal theory,
whether in tort (including negligence), contract, or otherwise,
unless required by applicable law (such as deliberate and grossly
negligent acts) or agreed to in writing, shall any Contributor be
liable to You for damages, including any direct, indirect, special,
incidental, or consequential damages of any character arising as a
result of this License or out of the use or inability to use the
Work (including but not limited to damages for loss of goodwill,
work stoppage, computer failure or malfunction, or any and all
other commercial damages or losses), even if such Contributor
has been advised of the possibility of such damages.
9. Accepting Warranty or Additional Liability. While redistributing
the Work or Derivative Works thereof, You may choose to offer,
and charge a fee for, acceptance of support, warranty, indemnity,
or other liability obligations and/or rights consistent with this
License. However, in accepting such obligations, You may act only
on Your own behalf and on Your sole responsibility, not on behalf
of any other Contributor, and only if You agree to indemnify,
defend, and hold each Contributor harmless for any liability
incurred by, or claims asserted against, such Contributor by reason
of your accepting any such warranty or additional liability.
END OF TERMS AND CONDITIONS
APPENDIX: How to apply the Apache License to your work.
To apply the Apache License to your work, attach the following
boilerplate notice, with the fields enclosed by brackets "[]"
replaced with your own identifying information. (Don't include
the brackets!) The text should be enclosed in the appropriate
comment syntax for the file format. We also recommend that a
file or class name and description of purpose be included on the
same "printed page" as the copyright notice for easier
identification within third-party archives.
Copyright [yyyy] [name of copyright owner]
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.

208
pom.xml Normal file
View File

@@ -0,0 +1,208 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.data.build</groupId>
<artifactId>spring-data-parent</artifactId>
<version>2.0.3.BUILD-SNAPSHOT</version>
</parent>
<groupId>org.springframework.data</groupId>
<artifactId>spring-data-tests-4-gemfire</artifactId>
<version>0.1.0.BUILD-SNAPSHOT</version>
<packaging>jar</packaging>
<name>Spring Data Test Context Framework for Spring Data GemFire/Geode</name>
<description>
This project is a new Spring Data module building on Spring's TestContext Framework for writing Unit
and Integration Tests for both Spring Data for Pivotal GemFire as well as Spring Data for Apache Geode.
</description>
<url>https://github.com/jxblum/spring-data-tests-4-gemfire</url>
<licenses>
<license>
<name>Apache License, Version 2.0</name>
<url>http://www.apache.org/licenses/LICENSE-2.0</url>
<comments>
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.
</comments>
</license>
</licenses>
<organization>
<name>Pivotal Software, Inc.</name>
<url>http://www.pivotal.io</url>
</organization>
<developers>
<developer>
<id>jblum</id>
<name>John Blum</name>
<email>jblum at pivotal dot io</email>
<organization>Pivotal Software, Inc.</organization>
<organizationUrl>http://www.spring.io</organizationUrl>
<roles>
<role>Spring Data Team</role>
<role>Spring Data Cassandra Project Lead (Committer)</role>
<role>Spring Data GemFire Project Lead (Committer)</role>
<role>Spring Data Geode Project Lead (Committer)</role>
<role>Spring Session Data GemFire Project Lead (Committer)</role>
<role>Spring Session Data Geode Project Lead (Committer)</role>
<role>Spring Boot Data GemFire Project Lead (Committer)</role>
<role>Spring Boot Data Geode Project Lead (Committer)</role>
<role>Apache Geode Committer</role>
</roles>
</developer>
</developers>
<properties>
<java.version>1.8</java.version>
<maven-compiler-plugin.version>3.3</maven-compiler-plugin.version>
<maven-surefire-plugin.version>2.19.1</maven-surefire-plugin.version>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<assertj.version>3.8.0</assertj.version>
<junit.version>4.12</junit.version>
<mockito.version>2.12.0</mockito.version>
<multithreadedtc.version>1.01</multithreadedtc.version>
<spring-data-gemfire.version>${project.parent.version}</spring-data-gemfire.version>
<spring-data-geode.version>${project.parent.version}</spring-data-geode.version>
<spring-shell.version>1.2.0.RELEASE</spring-shell.version>
</properties>
<repositories>
<repository>
<id>spring-libs-snapshot</id>
<url>https://repo.spring.io/libs-snapshot</url>
</repository>
</repositories>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.assertj</groupId>
<artifactId>assertj-core</artifactId>
<version>${assertj.version}</version>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>${junit.version}</version>
</dependency>
<dependency>
<groupId>org.mockito</groupId>
<artifactId>mockito-core</artifactId>
<version>${mockito.version}</version>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>${lombok}</version>
</dependency>
<dependency>
<groupId>edu.umd.cs.mtc</groupId>
<artifactId>multithreadedtc</artifactId>
<version>${multithreadedtc.version}</version>
</dependency>
<dependency>
<groupId>org.springframework.data</groupId>
<artifactId>spring-data-gemfire</artifactId>
<version>${spring-data-gemfire.version}</version>
</dependency>
<dependency>
<groupId>org.springframework.data</groupId>
<artifactId>spring-data-geode</artifactId>
<version>${spring-data-geode.version}</version>
</dependency>
</dependencies>
</dependencyManagement>
<dependencies>
<dependency>
<groupId>org.assertj</groupId>
<artifactId>assertj-core</artifactId>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
</dependency>
<dependency>
<groupId>org.mockito</groupId>
<artifactId>mockito-core</artifactId>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</dependency>
<dependency>
<groupId>edu.umd.cs.mtc</groupId>
<artifactId>multithreadedtc</artifactId>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-test</artifactId>
<version>${spring}</version>
</dependency>
<dependency>
<groupId>org.springframework.data</groupId>
<artifactId>spring-data-geode</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.shell</groupId>
<artifactId>spring-shell</artifactId>
<version>${spring-shell.version}</version>
<optional>true</optional>
<scope>runtime</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>${maven-compiler-plugin.version}</version>
<configuration>
<compilerArgs>
<arg>-Xlint:unchecked</arg>
<!-- <classpath>${java.home}/lib/tools.jar</classpath> -->
</compilerArgs>
<source>${java.version}</source>
<target>${java.version}</target>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<version>${maven-surefire-plugin.version}</version>
<configuration>
<argLine>
-Dgemfire.log-level=warning
</argLine>
<includes>
<include>**/*Test.java</include>
<include>**/*Tests.java</include>
</includes>
<reuseForks>false</reuseForks>
</configuration>
</plugin>
</plugins>
</build>
</project>

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);
}
}
}
}
}