Initial spring-data-tests-4-gemfire project commit.
This commit is contained in:
6
.gitignore
vendored
Normal file
6
.gitignore
vendored
Normal file
@@ -0,0 +1,6 @@
|
||||
*.iml
|
||||
*.ipr
|
||||
*.iws
|
||||
*.DS_Store
|
||||
.idea/
|
||||
target/
|
||||
201
LICENSE
Normal file
201
LICENSE
Normal 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
208
pom.xml
Normal 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>
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -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;
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
|
||||
}
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
@@ -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 {
|
||||
|
||||
}
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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());
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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(" }");
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
|
||||
}
|
||||
@@ -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"));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user