Switch to new class loader filter runner
This commit is contained in:
@@ -13,6 +13,10 @@
|
||||
<packaging>jar</packaging>
|
||||
<name>Spring Cloud Commons</name>
|
||||
<description>Spring Cloud Commons</description>
|
||||
<properties>
|
||||
<aether.version>1.0.2.v20150114</aether.version>
|
||||
<maven.version>3.3.9</maven.version>
|
||||
</properties>
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
@@ -35,7 +39,7 @@
|
||||
</plugins>
|
||||
<pluginManagement>
|
||||
<plugins>
|
||||
<!--This plugin's configuration is used to store Eclipse m2e settings only. It has no influence on the Maven build itself.-->
|
||||
<!--This plugin's configuration is used to store Eclipse m2e settings only. It has no influence on the Maven build itself. -->
|
||||
<plugin>
|
||||
<groupId>org.eclipse.m2e</groupId>
|
||||
<artifactId>lifecycle-mapping</artifactId>
|
||||
@@ -135,5 +139,53 @@
|
||||
<artifactId>spring-boot-starter-test</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.eclipse.aether</groupId>
|
||||
<artifactId>aether-api</artifactId>
|
||||
<version>${aether.version}</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.eclipse.aether</groupId>
|
||||
<artifactId>aether-connector-basic</artifactId>
|
||||
<version>${aether.version}</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.eclipse.aether</groupId>
|
||||
<artifactId>aether-impl</artifactId>
|
||||
<version>${aether.version}</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.eclipse.aether</groupId>
|
||||
<artifactId>aether-spi</artifactId>
|
||||
<version>${aether.version}</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.eclipse.aether</groupId>
|
||||
<artifactId>aether-transport-file</artifactId>
|
||||
<version>${aether.version}</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.eclipse.aether</groupId>
|
||||
<artifactId>aether-transport-http</artifactId>
|
||||
<version>${aether.version}</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.eclipse.aether</groupId>
|
||||
<artifactId>aether-util</artifactId>
|
||||
<version>${aether.version}</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.apache.maven</groupId>
|
||||
<artifactId>maven-core</artifactId>
|
||||
<version>${maven.version}</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
</project>
|
||||
|
||||
@@ -0,0 +1,42 @@
|
||||
/*
|
||||
* Copyright 2012-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.cloud;
|
||||
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
/**
|
||||
* Annotation used in combination with {@link ModifiedClassPathRunner} to override entries
|
||||
* on the classpath.
|
||||
*
|
||||
* @author Andy Wilkinson
|
||||
*/
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Target(ElementType.TYPE)
|
||||
public @interface ClassPathOverrides {
|
||||
|
||||
/**
|
||||
* One or more sets of Maven coordinates ({@code groupId:artifactId:version}) to be
|
||||
* added to the classpath. The additions will take precedence over any existing
|
||||
* classes on the classpath.
|
||||
* @return the coordinates
|
||||
*/
|
||||
String[] value();
|
||||
|
||||
}
|
||||
@@ -1,220 +0,0 @@
|
||||
package org.springframework.cloud;
|
||||
|
||||
import java.io.File;
|
||||
import java.lang.annotation.Annotation;
|
||||
import java.lang.reflect.Method;
|
||||
import java.net.URL;
|
||||
import java.net.URLClassLoader;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.jar.Attributes;
|
||||
import java.util.jar.JarFile;
|
||||
|
||||
import org.junit.runners.BlockJUnit4ClassRunner;
|
||||
import org.junit.runners.model.FrameworkMethod;
|
||||
import org.junit.runners.model.InitializationError;
|
||||
import org.junit.runners.model.TestClass;
|
||||
|
||||
import org.springframework.core.annotation.AnnotationUtils;
|
||||
import org.springframework.util.AntPathMatcher;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
/**
|
||||
* Taken from Spring Boot test utils.
|
||||
* https://github.com/spring-projects/spring-boot/blob/1.4.x/spring-boot/src/test/java/org/springframework/boot/testutil/FilteredClassPathRunner.java
|
||||
* @author Ryan Baxter
|
||||
*/
|
||||
public class FilteredClassPathRunner extends BlockJUnit4ClassRunner {
|
||||
public FilteredClassPathRunner(Class<?> testClass) throws InitializationError {
|
||||
super(testClass);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected TestClass createTestClass(Class<?> testClass) {
|
||||
try {
|
||||
ClassLoader classLoader = createTestClassLoader(testClass);
|
||||
return new FilteredTestClass(classLoader, testClass.getName());
|
||||
}
|
||||
catch (Exception ex) {
|
||||
throw new IllegalStateException(ex);
|
||||
}
|
||||
}
|
||||
|
||||
private URLClassLoader createTestClassLoader(Class<?> testClass) throws Exception {
|
||||
URLClassLoader classLoader = (URLClassLoader) this.getClass().getClassLoader();
|
||||
return new FilteredClassLoader(filterUrls(extractUrls(classLoader), testClass),
|
||||
classLoader.getParent(), classLoader);
|
||||
}
|
||||
|
||||
private URL[] extractUrls(URLClassLoader classLoader) throws Exception {
|
||||
List<URL> extractedUrls = new ArrayList<URL>();
|
||||
for (URL url : classLoader.getURLs()) {
|
||||
if (isSurefireBooterJar(url)) {
|
||||
extractedUrls.addAll(extractUrlsFromManifestClassPath(url));
|
||||
}
|
||||
else {
|
||||
extractedUrls.add(url);
|
||||
}
|
||||
}
|
||||
return extractedUrls.toArray(new URL[extractedUrls.size()]);
|
||||
}
|
||||
|
||||
private boolean isSurefireBooterJar(URL url) {
|
||||
return url.getPath().contains("surefirebooter");
|
||||
}
|
||||
|
||||
private List<URL> extractUrlsFromManifestClassPath(URL booterJar) throws Exception {
|
||||
List<URL> urls = new ArrayList<URL>();
|
||||
for (String entry : getClassPath(booterJar)) {
|
||||
urls.add(new URL(entry));
|
||||
}
|
||||
return urls;
|
||||
}
|
||||
|
||||
private String[] getClassPath(URL booterJar) throws Exception {
|
||||
JarFile jarFile = new JarFile(new File(booterJar.toURI()));
|
||||
try {
|
||||
return StringUtils.delimitedListToStringArray(jarFile.getManifest()
|
||||
.getMainAttributes().getValue(Attributes.Name.CLASS_PATH), " ");
|
||||
}
|
||||
finally {
|
||||
jarFile.close();
|
||||
}
|
||||
}
|
||||
|
||||
private URL[] filterUrls(URL[] urls, Class<?> testClass) throws Exception {
|
||||
ClassPathEntryFilter filter = new ClassPathEntryFilter(testClass);
|
||||
List<URL> filteredUrls = new ArrayList<URL>();
|
||||
for (URL url : urls) {
|
||||
if (!filter.isExcluded(url)) {
|
||||
filteredUrls.add(url);
|
||||
}
|
||||
}
|
||||
return filteredUrls.toArray(new URL[filteredUrls.size()]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Filter for class path entries.
|
||||
*/
|
||||
private static final class ClassPathEntryFilter {
|
||||
|
||||
private final List<String> exclusions;
|
||||
|
||||
private final AntPathMatcher matcher = new AntPathMatcher();
|
||||
|
||||
private ClassPathEntryFilter(Class<?> testClass) throws Exception {
|
||||
ClassPathExclusions exclusions = AnnotationUtils.findAnnotation(testClass,
|
||||
ClassPathExclusions.class);
|
||||
this.exclusions = exclusions == null ? Collections.<String>emptyList()
|
||||
: Arrays.asList(exclusions.value());
|
||||
}
|
||||
|
||||
private boolean isExcluded(URL url) throws Exception {
|
||||
if (!"file".equals(url.getProtocol())) {
|
||||
return false;
|
||||
}
|
||||
String name = new File(url.toURI()).getName();
|
||||
for (String exclusion : this.exclusions) {
|
||||
if (this.matcher.match(exclusion, name)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Filtered version of JUnit's {@link TestClass}.
|
||||
*/
|
||||
private static final class FilteredTestClass extends TestClass {
|
||||
|
||||
private final ClassLoader classLoader;
|
||||
|
||||
FilteredTestClass(ClassLoader classLoader, String testClassName)
|
||||
throws ClassNotFoundException {
|
||||
super(classLoader.loadClass(testClassName));
|
||||
this.classLoader = classLoader;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<FrameworkMethod> getAnnotatedMethods(
|
||||
Class<? extends Annotation> annotationClass) {
|
||||
try {
|
||||
return getAnnotatedMethods(annotationClass.getName());
|
||||
}
|
||||
catch (ClassNotFoundException ex) {
|
||||
throw new RuntimeException(ex);
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
private List<FrameworkMethod> getAnnotatedMethods(String annotationClassName)
|
||||
throws ClassNotFoundException {
|
||||
Class<? extends Annotation> annotationClass = (Class<? extends Annotation>) this.classLoader
|
||||
.loadClass(annotationClassName);
|
||||
List<FrameworkMethod> methods = super.getAnnotatedMethods(annotationClass);
|
||||
return wrapFrameworkMethods(methods);
|
||||
}
|
||||
|
||||
private List<FrameworkMethod> wrapFrameworkMethods(
|
||||
List<FrameworkMethod> methods) {
|
||||
List<FrameworkMethod> wrapped = new ArrayList<FrameworkMethod>(
|
||||
methods.size());
|
||||
for (FrameworkMethod frameworkMethod : methods) {
|
||||
wrapped.add(new FilteredFrameworkMethod(this.classLoader,
|
||||
frameworkMethod.getMethod()));
|
||||
}
|
||||
return wrapped;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Filtered version of JUnit's {@link FrameworkMethod}.
|
||||
*/
|
||||
private static final class FilteredFrameworkMethod extends FrameworkMethod {
|
||||
|
||||
private final ClassLoader classLoader;
|
||||
|
||||
private FilteredFrameworkMethod(ClassLoader classLoader, Method method) {
|
||||
super(method);
|
||||
this.classLoader = classLoader;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object invokeExplosively(Object target, Object... params)
|
||||
throws Throwable {
|
||||
ClassLoader originalClassLoader = Thread.currentThread()
|
||||
.getContextClassLoader();
|
||||
Thread.currentThread().setContextClassLoader(this.classLoader);
|
||||
try {
|
||||
return super.invokeExplosively(target, params);
|
||||
}
|
||||
finally {
|
||||
Thread.currentThread().setContextClassLoader(originalClassLoader);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private static final class FilteredClassLoader extends URLClassLoader {
|
||||
|
||||
private final ClassLoader junitLoader;
|
||||
|
||||
FilteredClassLoader(URL[] urls, ClassLoader parent, ClassLoader junitLoader) {
|
||||
super(urls, parent);
|
||||
this.junitLoader = junitLoader;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Class<?> loadClass(String name) throws ClassNotFoundException {
|
||||
if (name.startsWith("org.junit")) {
|
||||
return this.junitLoader.loadClass(name);
|
||||
}
|
||||
return super.loadClass(name);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,345 @@
|
||||
/*
|
||||
* Copyright 2012-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.cloud;
|
||||
|
||||
import java.io.File;
|
||||
import java.lang.annotation.Annotation;
|
||||
import java.lang.reflect.Method;
|
||||
import java.net.URL;
|
||||
import java.net.URLClassLoader;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.jar.Attributes;
|
||||
import java.util.jar.JarFile;
|
||||
|
||||
import org.apache.maven.repository.internal.MavenRepositorySystemUtils;
|
||||
import org.eclipse.aether.DefaultRepositorySystemSession;
|
||||
import org.eclipse.aether.RepositorySystem;
|
||||
import org.eclipse.aether.artifact.DefaultArtifact;
|
||||
import org.eclipse.aether.collection.CollectRequest;
|
||||
import org.eclipse.aether.connector.basic.BasicRepositoryConnectorFactory;
|
||||
import org.eclipse.aether.graph.Dependency;
|
||||
import org.eclipse.aether.impl.DefaultServiceLocator;
|
||||
import org.eclipse.aether.repository.LocalRepository;
|
||||
import org.eclipse.aether.repository.RemoteRepository;
|
||||
import org.eclipse.aether.resolution.ArtifactResult;
|
||||
import org.eclipse.aether.resolution.DependencyRequest;
|
||||
import org.eclipse.aether.resolution.DependencyResult;
|
||||
import org.eclipse.aether.spi.connector.RepositoryConnectorFactory;
|
||||
import org.eclipse.aether.spi.connector.transport.TransporterFactory;
|
||||
import org.eclipse.aether.transport.http.HttpTransporterFactory;
|
||||
import org.junit.runners.BlockJUnit4ClassRunner;
|
||||
import org.junit.runners.model.FrameworkMethod;
|
||||
import org.junit.runners.model.InitializationError;
|
||||
import org.junit.runners.model.TestClass;
|
||||
|
||||
import org.springframework.core.annotation.AnnotationUtils;
|
||||
import org.springframework.util.AntPathMatcher;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
/**
|
||||
* A custom {@link BlockJUnit4ClassRunner} that runs tests using a modified class path.
|
||||
* Entries are excluded from the class path using {@link ClassPathExclusions} and
|
||||
* overridden using {@link ClassPathOverrides} on the test class. A class loader is
|
||||
* created with the customized class path and is used both to load the test class and as
|
||||
* the thread context class loader while the test is being run.
|
||||
*
|
||||
* @author Andy Wilkinson
|
||||
*/
|
||||
public class ModifiedClassPathRunner extends BlockJUnit4ClassRunner {
|
||||
|
||||
public ModifiedClassPathRunner(Class<?> testClass) throws InitializationError {
|
||||
super(testClass);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected TestClass createTestClass(Class<?> testClass) {
|
||||
try {
|
||||
ClassLoader classLoader = createTestClassLoader(testClass);
|
||||
return new ModifiedClassPathTestClass(classLoader, testClass.getName());
|
||||
}
|
||||
catch (Exception ex) {
|
||||
throw new IllegalStateException(ex);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Object createTest() throws Exception {
|
||||
ModifiedClassPathTestClass testClass = (ModifiedClassPathTestClass) getTestClass();
|
||||
return testClass.doWithModifiedClassPathThreadContextClassLoader(
|
||||
new ModifiedClassPathTestClass.ModifiedClassPathTcclAction<Object, Exception>() {
|
||||
|
||||
@Override
|
||||
public Object perform() throws Exception {
|
||||
return ModifiedClassPathRunner.super.createTest();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private URLClassLoader createTestClassLoader(Class<?> testClass) throws Exception {
|
||||
URLClassLoader classLoader = (URLClassLoader) this.getClass().getClassLoader();
|
||||
return new ModifiedClassPathClassLoader(
|
||||
processUrls(extractUrls(classLoader), testClass), classLoader.getParent(),
|
||||
classLoader);
|
||||
}
|
||||
|
||||
private URL[] extractUrls(URLClassLoader classLoader) throws Exception {
|
||||
List<URL> extractedUrls = new ArrayList<URL>();
|
||||
for (URL url : classLoader.getURLs()) {
|
||||
if (isSurefireBooterJar(url)) {
|
||||
extractedUrls.addAll(extractUrlsFromManifestClassPath(url));
|
||||
}
|
||||
else {
|
||||
extractedUrls.add(url);
|
||||
}
|
||||
}
|
||||
return extractedUrls.toArray(new URL[extractedUrls.size()]);
|
||||
}
|
||||
|
||||
private boolean isSurefireBooterJar(URL url) {
|
||||
return url.getPath().contains("surefirebooter");
|
||||
}
|
||||
|
||||
private List<URL> extractUrlsFromManifestClassPath(URL booterJar) throws Exception {
|
||||
List<URL> urls = new ArrayList<URL>();
|
||||
for (String entry : getClassPath(booterJar)) {
|
||||
urls.add(new URL(entry));
|
||||
}
|
||||
return urls;
|
||||
}
|
||||
|
||||
private String[] getClassPath(URL booterJar) throws Exception {
|
||||
JarFile jarFile = new JarFile(new File(booterJar.toURI()));
|
||||
try {
|
||||
return StringUtils.delimitedListToStringArray(jarFile.getManifest()
|
||||
.getMainAttributes().getValue(Attributes.Name.CLASS_PATH), " ");
|
||||
}
|
||||
finally {
|
||||
jarFile.close();
|
||||
}
|
||||
}
|
||||
|
||||
private URL[] processUrls(URL[] urls, Class<?> testClass) throws Exception {
|
||||
ClassPathEntryFilter filter = new ClassPathEntryFilter(testClass);
|
||||
List<URL> processedUrls = new ArrayList<URL>();
|
||||
processedUrls.addAll(getAdditionalUrls(testClass));
|
||||
for (URL url : urls) {
|
||||
if (!filter.isExcluded(url)) {
|
||||
processedUrls.add(url);
|
||||
}
|
||||
}
|
||||
return processedUrls.toArray(new URL[processedUrls.size()]);
|
||||
}
|
||||
|
||||
private List<URL> getAdditionalUrls(Class<?> testClass) throws Exception {
|
||||
ClassPathOverrides overrides = AnnotationUtils.findAnnotation(testClass,
|
||||
ClassPathOverrides.class);
|
||||
if (overrides == null) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
return resolveCoordinates(overrides.value());
|
||||
}
|
||||
|
||||
private List<URL> resolveCoordinates(String[] coordinates) throws Exception {
|
||||
DefaultServiceLocator serviceLocator = MavenRepositorySystemUtils
|
||||
.newServiceLocator();
|
||||
serviceLocator.addService(RepositoryConnectorFactory.class,
|
||||
BasicRepositoryConnectorFactory.class);
|
||||
serviceLocator.addService(TransporterFactory.class, HttpTransporterFactory.class);
|
||||
RepositorySystem repositorySystem = serviceLocator
|
||||
.getService(RepositorySystem.class);
|
||||
DefaultRepositorySystemSession session = MavenRepositorySystemUtils.newSession();
|
||||
LocalRepository localRepository = new LocalRepository(
|
||||
System.getProperty("user.home") + "/.m2/repository");
|
||||
session.setLocalRepositoryManager(
|
||||
repositorySystem.newLocalRepositoryManager(session, localRepository));
|
||||
CollectRequest collectRequest = new CollectRequest(null,
|
||||
Arrays.asList(new RemoteRepository.Builder("central", "default",
|
||||
"http://central.maven.org/maven2").build()));
|
||||
|
||||
collectRequest.setDependencies(createDependencies(coordinates));
|
||||
DependencyRequest dependencyRequest = new DependencyRequest(collectRequest, null);
|
||||
DependencyResult result = repositorySystem.resolveDependencies(session,
|
||||
dependencyRequest);
|
||||
List<URL> resolvedArtifacts = new ArrayList<URL>();
|
||||
for (ArtifactResult artifact : result.getArtifactResults()) {
|
||||
resolvedArtifacts.add(artifact.getArtifact().getFile().toURI().toURL());
|
||||
}
|
||||
return resolvedArtifacts;
|
||||
}
|
||||
|
||||
private List<Dependency> createDependencies(String[] allCoordinates) {
|
||||
List<Dependency> dependencies = new ArrayList<Dependency>();
|
||||
for (String coordinate : allCoordinates) {
|
||||
dependencies.add(new Dependency(new DefaultArtifact(coordinate), null));
|
||||
}
|
||||
return dependencies;
|
||||
}
|
||||
|
||||
/**
|
||||
* Filter for class path entries.
|
||||
*/
|
||||
private static final class ClassPathEntryFilter {
|
||||
|
||||
private final List<String> exclusions;
|
||||
|
||||
private final AntPathMatcher matcher = new AntPathMatcher();
|
||||
|
||||
private ClassPathEntryFilter(Class<?> testClass) throws Exception {
|
||||
ClassPathExclusions exclusions = AnnotationUtils.findAnnotation(testClass,
|
||||
ClassPathExclusions.class);
|
||||
this.exclusions = exclusions == null ? Collections.<String>emptyList()
|
||||
: Arrays.asList(exclusions.value());
|
||||
}
|
||||
|
||||
private boolean isExcluded(URL url) throws Exception {
|
||||
if (!"file".equals(url.getProtocol())) {
|
||||
return false;
|
||||
}
|
||||
String name = new File(url.toURI()).getName();
|
||||
for (String exclusion : this.exclusions) {
|
||||
if (this.matcher.match(exclusion, name)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Custom {@link TestClass} that uses a modified class path.
|
||||
*/
|
||||
private static final class ModifiedClassPathTestClass extends TestClass {
|
||||
|
||||
private final ClassLoader classLoader;
|
||||
|
||||
ModifiedClassPathTestClass(ClassLoader classLoader, String testClassName)
|
||||
throws ClassNotFoundException {
|
||||
super(classLoader.loadClass(testClassName));
|
||||
this.classLoader = classLoader;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<FrameworkMethod> getAnnotatedMethods(
|
||||
Class<? extends Annotation> annotationClass) {
|
||||
try {
|
||||
return getAnnotatedMethods(annotationClass.getName());
|
||||
}
|
||||
catch (ClassNotFoundException ex) {
|
||||
throw new RuntimeException(ex);
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
private List<FrameworkMethod> getAnnotatedMethods(String annotationClassName)
|
||||
throws ClassNotFoundException {
|
||||
Class<? extends Annotation> annotationClass = (Class<? extends Annotation>) this.classLoader
|
||||
.loadClass(annotationClassName);
|
||||
List<FrameworkMethod> methods = super.getAnnotatedMethods(annotationClass);
|
||||
return wrapFrameworkMethods(methods);
|
||||
}
|
||||
|
||||
private List<FrameworkMethod> wrapFrameworkMethods(
|
||||
List<FrameworkMethod> methods) {
|
||||
List<FrameworkMethod> wrapped = new ArrayList<FrameworkMethod>(
|
||||
methods.size());
|
||||
for (FrameworkMethod frameworkMethod : methods) {
|
||||
wrapped.add(new ModifiedClassPathFrameworkMethod(
|
||||
frameworkMethod.getMethod()));
|
||||
}
|
||||
return wrapped;
|
||||
}
|
||||
|
||||
private <T, E extends Throwable> T doWithModifiedClassPathThreadContextClassLoader(
|
||||
ModifiedClassPathTcclAction<T, E> action) throws E {
|
||||
ClassLoader originalClassLoader = Thread.currentThread()
|
||||
.getContextClassLoader();
|
||||
Thread.currentThread().setContextClassLoader(this.classLoader);
|
||||
try {
|
||||
return action.perform();
|
||||
}
|
||||
finally {
|
||||
Thread.currentThread().setContextClassLoader(originalClassLoader);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* An action to be performed with the {@link ModifiedClassPathClassLoader} set as
|
||||
* the thread context class loader.
|
||||
*/
|
||||
private interface ModifiedClassPathTcclAction<T, E extends Throwable> {
|
||||
|
||||
T perform() throws E;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Custom {@link FrameworkMethod} that runs methods with
|
||||
* {@link ModifiedClassPathClassLoader} as the thread context class loader.
|
||||
*/
|
||||
private final class ModifiedClassPathFrameworkMethod extends FrameworkMethod {
|
||||
|
||||
private ModifiedClassPathFrameworkMethod(Method method) {
|
||||
super(method);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object invokeExplosively(final Object target, final Object... params)
|
||||
throws Throwable {
|
||||
return doWithModifiedClassPathThreadContextClassLoader(
|
||||
new ModifiedClassPathTcclAction<Object, Throwable>() {
|
||||
|
||||
@Override
|
||||
public Object perform() throws Throwable {
|
||||
return ModifiedClassPathFrameworkMethod.super.invokeExplosively(
|
||||
target, params);
|
||||
}
|
||||
|
||||
});
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Custom {@link URLClassLoader} that modifies the class path.
|
||||
*/
|
||||
private static final class ModifiedClassPathClassLoader extends URLClassLoader {
|
||||
|
||||
private final ClassLoader junitLoader;
|
||||
|
||||
ModifiedClassPathClassLoader(URL[] urls, ClassLoader parent,
|
||||
ClassLoader junitLoader) {
|
||||
super(urls, parent);
|
||||
this.junitLoader = junitLoader;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Class<?> loadClass(String name) throws ClassNotFoundException {
|
||||
if (name.startsWith("org.junit") || name.startsWith("org.hamcrest")) {
|
||||
return this.junitLoader.loadClass(name);
|
||||
}
|
||||
return super.loadClass(name);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,9 +1,11 @@
|
||||
package org.springframework.cloud.client.loadbalancer;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import org.junit.runner.RunWith;
|
||||
|
||||
import org.springframework.cloud.ClassPathExclusions;
|
||||
import org.springframework.cloud.FilteredClassPathRunner;
|
||||
import org.springframework.cloud.ModifiedClassPathRunner;
|
||||
import org.springframework.http.client.ClientHttpRequestInterceptor;
|
||||
import org.springframework.web.client.RestTemplate;
|
||||
|
||||
@@ -15,7 +17,7 @@ import static org.hamcrest.Matchers.is;
|
||||
/**
|
||||
* @author Spencer Gibb
|
||||
*/
|
||||
@RunWith(FilteredClassPathRunner.class)
|
||||
@RunWith(ModifiedClassPathRunner.class)
|
||||
@ClassPathExclusions({"spring-retry-*.jar", "spring-boot-starter-aop-*.jar"})
|
||||
public class LoadBalancerAutoConfigurationTests extends AbstractLoadBalancerAutoConfigurationTests {
|
||||
|
||||
|
||||
@@ -2,10 +2,12 @@ package org.springframework.cloud.client.serviceregistry;
|
||||
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
|
||||
import org.springframework.beans.factory.NoSuchBeanDefinitionException;
|
||||
import org.springframework.boot.WebApplicationType;
|
||||
import org.springframework.boot.builder.SpringApplicationBuilder;
|
||||
import org.springframework.cloud.ClassPathExclusions;
|
||||
import org.springframework.cloud.FilteredClassPathRunner;
|
||||
import org.springframework.cloud.ModifiedClassPathRunner;
|
||||
import org.springframework.context.ConfigurableApplicationContext;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
|
||||
@@ -14,13 +16,13 @@ import static org.assertj.core.api.Assertions.fail;
|
||||
/**
|
||||
* @author Spencer Gibb
|
||||
*/
|
||||
@RunWith(FilteredClassPathRunner.class)
|
||||
@RunWith(ModifiedClassPathRunner.class)
|
||||
@ClassPathExclusions({"spring-boot-actuator-*.jar", "spring-boot-starter-actuator-*.jar"})
|
||||
public class ServiceRegistryAutoConfigurationTests {
|
||||
|
||||
@Test
|
||||
public void runsWithoutActuator() {
|
||||
ConfigurableApplicationContext context = new SpringApplicationBuilder(TestConfig.class).web(false).run();
|
||||
ConfigurableApplicationContext context = new SpringApplicationBuilder(TestConfig.class).web(WebApplicationType.NONE).run();
|
||||
try {
|
||||
context.getBean("serviceRegistryEndpoint");
|
||||
fail("found a bean that shouldn't be there");
|
||||
|
||||
@@ -2,6 +2,8 @@ package org.springframework.cloud.autoconfigure;
|
||||
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
|
||||
import org.springframework.boot.WebApplicationType;
|
||||
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
|
||||
import org.springframework.boot.builder.SpringApplicationBuilder;
|
||||
import org.springframework.cloud.ClassPathExclusions;
|
||||
@@ -30,7 +32,7 @@ public class RefreshAutoConfigurationClassPathTests {
|
||||
|
||||
private static ConfigurableApplicationContext getApplicationContext(
|
||||
Class<?> configuration, String... properties) {
|
||||
return new SpringApplicationBuilder(configuration).web(false)
|
||||
return new SpringApplicationBuilder(configuration).web(WebApplicationType.NONE)
|
||||
.properties(properties).run();
|
||||
}
|
||||
|
||||
|
||||
@@ -3,6 +3,7 @@ package org.springframework.cloud.autoconfigure;
|
||||
import org.junit.Rule;
|
||||
import org.junit.Test;
|
||||
|
||||
import org.springframework.boot.WebApplicationType;
|
||||
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
|
||||
import org.springframework.boot.builder.SpringApplicationBuilder;
|
||||
import org.springframework.boot.test.rule.OutputCapture;
|
||||
@@ -33,7 +34,7 @@ public class RefreshAutoConfigurationTests {
|
||||
|
||||
private static ConfigurableApplicationContext getApplicationContext(
|
||||
Class<?> configuration, String... properties) {
|
||||
return new SpringApplicationBuilder(configuration).web(false)
|
||||
return new SpringApplicationBuilder(configuration).web(WebApplicationType.NONE)
|
||||
.properties(properties).run();
|
||||
}
|
||||
|
||||
|
||||
@@ -2,12 +2,11 @@ package org.springframework.cloud.bootstrap;
|
||||
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
|
||||
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
|
||||
import org.springframework.boot.test.context.SpringBootTest;
|
||||
import org.springframework.cloud.bootstrap.BootstrapOrderingSpringApplicationJsonIntegrationTests.Application;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.core.env.ConfigurableEnvironment;
|
||||
import org.springframework.test.context.junit4.SpringRunner;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
@@ -17,9 +16,6 @@ import static org.springframework.cloud.bootstrap.TestHigherPriorityBootstrapCon
|
||||
@SpringBootTest(classes = Application.class)
|
||||
public class BootstrapSourcesOrderingTests {
|
||||
|
||||
@Autowired
|
||||
private ConfigurableEnvironment environment;
|
||||
|
||||
@Test
|
||||
public void sourcesAreOrderedCorrectly() {
|
||||
Class<?> firstConstructedClass = firstToBeCreated.get();
|
||||
|
||||
@@ -4,15 +4,12 @@ import java.util.Arrays;
|
||||
import java.util.Map;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
import static org.hamcrest.Matchers.is;
|
||||
import static org.hamcrest.Matchers.hasItems;
|
||||
import static org.hamcrest.Matchers.is;
|
||||
import static org.hamcrest.Matchers.notNullValue;
|
||||
import static org.hamcrest.Matchers.nullValue;
|
||||
import static org.junit.Assert.assertThat;
|
||||
|
||||
@@ -17,7 +17,9 @@
|
||||
package org.springframework.cloud.context.scope.refresh;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
import org.springframework.beans.factory.support.DefaultListableBeanFactory;
|
||||
import org.springframework.boot.WebApplicationType;
|
||||
import org.springframework.boot.builder.SpringApplicationBuilder;
|
||||
import org.springframework.context.ConfigurableApplicationContext;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
@@ -37,7 +39,7 @@ public class RefreshScopeSerializationTests {
|
||||
@Test
|
||||
public void defaultApplicationContextId() throws Exception {
|
||||
ConfigurableApplicationContext context = new SpringApplicationBuilder(
|
||||
TestConfiguration.class).web(false).run();
|
||||
TestConfiguration.class).web(WebApplicationType.NONE).run();
|
||||
assertThat(context.getId(), is(equalTo("application")));
|
||||
}
|
||||
|
||||
@@ -52,7 +54,7 @@ public class RefreshScopeSerializationTests {
|
||||
|
||||
private DefaultListableBeanFactory getBeanFactory() {
|
||||
ConfigurableApplicationContext context = new SpringApplicationBuilder(
|
||||
TestConfiguration.class).web(false).run();
|
||||
TestConfiguration.class).web(WebApplicationType.NONE).run();
|
||||
DefaultListableBeanFactory factory = (DefaultListableBeanFactory) context
|
||||
.getAutowireCapableBeanFactory();
|
||||
return factory;
|
||||
|
||||
@@ -25,7 +25,9 @@ import java.util.Map;
|
||||
|
||||
import org.junit.After;
|
||||
import org.junit.Test;
|
||||
|
||||
import org.springframework.boot.Banner.Mode;
|
||||
import org.springframework.boot.WebApplicationType;
|
||||
import org.springframework.boot.builder.SpringApplicationBuilder;
|
||||
import org.springframework.boot.test.util.EnvironmentTestUtils;
|
||||
import org.springframework.cloud.bootstrap.config.PropertySourceLocator;
|
||||
@@ -65,7 +67,7 @@ public class RefreshEndpointTests {
|
||||
|
||||
@Test
|
||||
public void keysComputedWhenAdded() throws Exception {
|
||||
this.context = new SpringApplicationBuilder(Empty.class).web(false)
|
||||
this.context = new SpringApplicationBuilder(Empty.class).web(WebApplicationType.NONE)
|
||||
.bannerMode(Mode.OFF).properties("spring.cloud.bootstrap.name:none")
|
||||
.run();
|
||||
RefreshScope scope = new RefreshScope();
|
||||
@@ -79,7 +81,7 @@ public class RefreshEndpointTests {
|
||||
|
||||
@Test
|
||||
public void keysComputedWhenOveridden() throws Exception {
|
||||
this.context = new SpringApplicationBuilder(Empty.class).web(false)
|
||||
this.context = new SpringApplicationBuilder(Empty.class).web(WebApplicationType.NONE)
|
||||
.bannerMode(Mode.OFF).properties("spring.cloud.bootstrap.name:none")
|
||||
.run();
|
||||
RefreshScope scope = new RefreshScope();
|
||||
@@ -94,7 +96,7 @@ public class RefreshEndpointTests {
|
||||
|
||||
@Test
|
||||
public void keysComputedWhenChangesInExternalProperties() throws Exception {
|
||||
this.context = new SpringApplicationBuilder(Empty.class).web(false)
|
||||
this.context = new SpringApplicationBuilder(Empty.class).web(WebApplicationType.NONE)
|
||||
.bannerMode(Mode.OFF).properties("spring.cloud.bootstrap.name:none")
|
||||
.run();
|
||||
RefreshScope scope = new RefreshScope();
|
||||
@@ -110,7 +112,7 @@ public class RefreshEndpointTests {
|
||||
|
||||
@Test
|
||||
public void springMainSourcesEmptyInRefreshCycle() throws Exception {
|
||||
this.context = new SpringApplicationBuilder(Empty.class).web(false)
|
||||
this.context = new SpringApplicationBuilder(Empty.class).web(WebApplicationType.NONE)
|
||||
.bannerMode(Mode.OFF).properties("spring.cloud.bootstrap.name:none")
|
||||
.run();
|
||||
RefreshScope scope = new RefreshScope();
|
||||
@@ -128,7 +130,7 @@ public class RefreshEndpointTests {
|
||||
|
||||
@Test
|
||||
public void eventsPublishedInOrder() throws Exception {
|
||||
this.context = new SpringApplicationBuilder(Empty.class).web(false)
|
||||
this.context = new SpringApplicationBuilder(Empty.class).web(WebApplicationType.NONE)
|
||||
.bannerMode(Mode.OFF).run();
|
||||
RefreshScope scope = new RefreshScope();
|
||||
scope.setApplicationContext(this.context);
|
||||
@@ -144,7 +146,7 @@ public class RefreshEndpointTests {
|
||||
@Test
|
||||
public void shutdownHooksCleaned() {
|
||||
ConfigurableApplicationContext context = new SpringApplicationBuilder(Empty.class)
|
||||
.web(false).bannerMode(Mode.OFF).run();
|
||||
.web(WebApplicationType.NONE).bannerMode(Mode.OFF).run();
|
||||
RefreshScope scope = new RefreshScope();
|
||||
scope.setApplicationContext(context);
|
||||
ContextRefresher contextRefresher = new ContextRefresher(context, scope);
|
||||
|
||||
Reference in New Issue
Block a user