Relocate projects to spring-boot-project

Move projects to better reflect the way that Spring Boot is released.

The following projects are under `spring-boot-project`:

  - `spring-boot`
  - `spring-boot-autoconfigure`
  - `spring-boot-tools`
  - `spring-boot-starters`
  - `spring-boot-actuator`
  - `spring-boot-actuator-autoconfigure`
  - `spring-boot-test`
  - `spring-boot-test-autoconfigure`
  - `spring-boot-devtools`
  - `spring-boot-cli`
  - `spring-boot-docs`

See gh-9316
This commit is contained in:
Phillip Webb
2017-09-19 14:29:46 -07:00
parent 0419d42b7c
commit 0ba4830b4f
4023 changed files with 0 additions and 0 deletions

View File

@@ -0,0 +1,60 @@
/*
* 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.boot.testsupport.assertj;
import org.assertj.core.api.Condition;
import org.hamcrest.Matcher;
import org.hamcrest.StringDescription;
import org.springframework.util.Assert;
/**
* Adapter class allowing a Hamcrest {@link Matcher} to be used as an AssertJ
* {@link Condition}.
*
* @param <T> the type of object that the condition accepts
* @author Phillip Webb
*/
public final class Matched<T> extends Condition<T> {
private final Matcher<? extends T> matcher;
private Matched(Matcher<? extends T> matcher) {
Assert.notNull(matcher, "Matcher must not be null");
this.matcher = matcher;
}
@Override
public boolean matches(final T value) {
if (this.matcher.matches(value)) {
return true;
}
StringDescription description = new StringDescription();
this.matcher.describeTo(description);
describedAs(description.toString());
return false;
}
public static <T> Condition<T> when(Matcher<? extends T> matcher) {
return by(matcher);
}
public static <T> Condition<T> by(Matcher<? extends T> matcher) {
return new Matched<>(matcher);
}
}

View File

@@ -0,0 +1,20 @@
/*
* 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.
*/
/**
* Utilities and helpers for AssertJ.
*/
package org.springframework.boot.testsupport.assertj;

View File

@@ -0,0 +1,129 @@
/*
* 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.boot.testsupport.compiler;
import java.io.File;
import java.io.IOException;
import java.util.Arrays;
import java.util.Collection;
import javax.annotation.processing.Processor;
import javax.tools.JavaCompiler;
import javax.tools.JavaCompiler.CompilationTask;
import javax.tools.JavaFileObject;
import javax.tools.StandardJavaFileManager;
import javax.tools.StandardLocation;
import javax.tools.ToolProvider;
import org.junit.rules.TemporaryFolder;
/**
* Wrapper to make the {@link JavaCompiler} easier to use in tests.
*
* @author Stephane Nicoll
* @author Phillip Webb
* @author Andy Wilkinson
*/
public class TestCompiler {
/**
* The default source folder.
*/
public static final File SOURCE_FOLDER = new File("src/test/java");
private final JavaCompiler compiler;
private final StandardJavaFileManager fileManager;
private final File outputLocation;
public TestCompiler(TemporaryFolder temporaryFolder) throws IOException {
this(ToolProvider.getSystemJavaCompiler(), temporaryFolder);
}
public TestCompiler(JavaCompiler compiler, TemporaryFolder temporaryFolder)
throws IOException {
this.compiler = compiler;
this.fileManager = compiler.getStandardFileManager(null, null, null);
this.outputLocation = temporaryFolder.newFolder();
Iterable<? extends File> temp = Arrays.asList(this.outputLocation);
this.fileManager.setLocation(StandardLocation.CLASS_OUTPUT, temp);
this.fileManager.setLocation(StandardLocation.SOURCE_OUTPUT, temp);
}
public TestCompilationTask getTask(Collection<File> sourceFiles) {
Iterable<? extends JavaFileObject> javaFileObjects = this.fileManager
.getJavaFileObjectsFromFiles(sourceFiles);
return getTask(javaFileObjects);
}
public TestCompilationTask getTask(Class<?>... types) {
Iterable<? extends JavaFileObject> javaFileObjects = getJavaFileObjects(types);
return getTask(javaFileObjects);
}
private TestCompilationTask getTask(
Iterable<? extends JavaFileObject> javaFileObjects) {
return new TestCompilationTask(this.compiler.getTask(null, this.fileManager, null,
null, null, javaFileObjects));
}
public File getOutputLocation() {
return this.outputLocation;
}
private Iterable<? extends JavaFileObject> getJavaFileObjects(Class<?>... types) {
File[] files = new File[types.length];
for (int i = 0; i < types.length; i++) {
files[i] = getFile(types[i]);
}
return this.fileManager.getJavaFileObjects(files);
}
protected File getFile(Class<?> type) {
return new File(getSourceFolder(), sourcePathFor(type));
}
public static String sourcePathFor(Class<?> type) {
return type.getName().replace('.', '/') + ".java";
}
protected File getSourceFolder() {
return SOURCE_FOLDER;
}
/**
* A compilation task.
*/
public static class TestCompilationTask {
private final CompilationTask task;
public TestCompilationTask(CompilationTask task) {
this.task = task;
}
public void call(Processor... processors) {
this.task.setProcessors(Arrays.asList(processors));
if (!this.task.call()) {
throw new IllegalStateException("Compilation failed");
}
}
}
}

View File

@@ -0,0 +1,20 @@
/*
* 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.
*/
/**
* Utilities to work with the Java compiler at test time.
*/
package org.springframework.boot.testsupport.compiler;

View File

@@ -0,0 +1,95 @@
/*
* 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.boot.testsupport.context;
import java.io.File;
import java.io.IOException;
import java.util.HashSet;
import java.util.Set;
import org.junit.Test;
import org.springframework.asm.Opcodes;
import org.springframework.beans.DirectFieldAccessor;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.io.Resource;
import org.springframework.core.io.support.PathMatchingResourcePatternResolver;
import org.springframework.core.io.support.ResourcePatternResolver;
import org.springframework.core.type.AnnotationMetadata;
import org.springframework.core.type.MethodMetadata;
import org.springframework.core.type.classreading.MetadataReader;
import org.springframework.core.type.classreading.SimpleMetadataReaderFactory;
import static org.assertj.core.api.Assertions.assertThat;
/**
* Abstract base class for {@code @Configuration} sanity checks.
*
* @author Andy Wilkinson
*/
public abstract class AbstractConfigurationClassTests {
private ResourcePatternResolver resolver = new PathMatchingResourcePatternResolver();
@Test
public void allBeanMethodsArePublic() throws IOException, ClassNotFoundException {
Set<String> nonPublicBeanMethods = new HashSet<>();
for (AnnotationMetadata configurationClass : findConfigurationClasses()) {
Set<MethodMetadata> beanMethods = configurationClass
.getAnnotatedMethods(Bean.class.getName());
for (MethodMetadata methodMetadata : beanMethods) {
if (!isPublic(methodMetadata)) {
nonPublicBeanMethods.add(methodMetadata.getDeclaringClassName() + "."
+ methodMetadata.getMethodName());
}
}
}
assertThat(nonPublicBeanMethods).as("Found non-public @Bean methods").isEmpty();
}
private Set<AnnotationMetadata> findConfigurationClasses() throws IOException {
Set<AnnotationMetadata> configurationClasses = new HashSet<>();
Resource[] resources = this.resolver.getResources("classpath*:"
+ getClass().getPackage().getName().replace('.', '/') + "/**/*.class");
for (Resource resource : resources) {
if (!isTestClass(resource)) {
MetadataReader metadataReader = new SimpleMetadataReaderFactory()
.getMetadataReader(resource);
AnnotationMetadata annotationMetadata = metadataReader
.getAnnotationMetadata();
if (annotationMetadata.getAnnotationTypes()
.contains(Configuration.class.getName())) {
configurationClasses.add(annotationMetadata);
}
}
}
return configurationClasses;
}
private boolean isTestClass(Resource resource) throws IOException {
return resource.getFile().getAbsolutePath()
.contains("target" + File.separator + "test-classes");
}
private boolean isPublic(MethodMetadata methodMetadata) {
int access = (Integer) new DirectFieldAccessor(methodMetadata)
.getPropertyValue("access");
return (access & Opcodes.ACC_PUBLIC) != 0;
}
}

View File

@@ -0,0 +1,20 @@
/*
* 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.
*/
/**
* Utilities to help test Spring contexts.
*/
package org.springframework.boot.testsupport.context;

View File

@@ -0,0 +1,20 @@
/*
* 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.
*/
/**
* Internal support classes used in Spring Boot tests.
*/
package org.springframework.boot.testsupport;

View File

@@ -0,0 +1,156 @@
/*
* 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.boot.testsupport.rule;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.io.PrintStream;
import java.util.ArrayList;
import java.util.List;
import org.hamcrest.Matcher;
import org.junit.Assert;
import org.junit.rules.TestRule;
import org.junit.runner.Description;
import org.junit.runners.model.Statement;
import static org.hamcrest.Matchers.allOf;
/**
* Internal JUnit {@code @Rule} to capture output from System.out and System.err.
*
* @author Phillip Webb
* @author Andy Wilkinson
*/
public class OutputCapture implements TestRule {
private CaptureOutputStream captureOut;
private CaptureOutputStream captureErr;
private ByteArrayOutputStream copy;
private List<Matcher<? super String>> matchers = new ArrayList<>();
@Override
public Statement apply(final Statement base, Description description) {
return new Statement() {
@Override
public void evaluate() throws Throwable {
captureOutput();
try {
base.evaluate();
}
finally {
try {
if (!OutputCapture.this.matchers.isEmpty()) {
String output = OutputCapture.this.toString();
Assert.assertThat(output, allOf(OutputCapture.this.matchers));
}
}
finally {
releaseOutput();
}
}
}
};
}
protected void captureOutput() {
// FIXME AnsiOutput.setEnabled(Enabled.NEVER);
this.copy = new ByteArrayOutputStream();
this.captureOut = new CaptureOutputStream(System.out, this.copy);
this.captureErr = new CaptureOutputStream(System.err, this.copy);
System.setOut(new PrintStream(this.captureOut));
System.setErr(new PrintStream(this.captureErr));
}
protected void releaseOutput() {
// FIXME AnsiOutput.setEnabled(Enabled.DETECT);
System.setOut(this.captureOut.getOriginal());
System.setErr(this.captureErr.getOriginal());
this.copy = null;
}
public void flush() {
try {
this.captureOut.flush();
this.captureErr.flush();
}
catch (IOException ex) {
// ignore
}
}
@Override
public String toString() {
flush();
return this.copy.toString();
}
/**
* Verify that the output is matched by the supplied {@code matcher}. Verification is
* performed after the test method has executed.
* @param matcher the matcher
*/
public void expect(Matcher<? super String> matcher) {
this.matchers.add(matcher);
}
private static class CaptureOutputStream extends OutputStream {
private final PrintStream original;
private final OutputStream copy;
CaptureOutputStream(PrintStream original, OutputStream copy) {
this.original = original;
this.copy = copy;
}
@Override
public void write(int b) throws IOException {
this.copy.write(b);
this.original.write(b);
this.original.flush();
}
@Override
public void write(byte[] b) throws IOException {
write(b, 0, b.length);
}
@Override
public void write(byte[] b, int off, int len) throws IOException {
this.copy.write(b, off, len);
this.original.write(b, off, len);
}
public PrintStream getOriginal() {
return this.original;
}
@Override
public void flush() throws IOException {
this.copy.flush();
this.original.flush();
}
}
}

View File

@@ -0,0 +1,152 @@
/*
* 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.boot.testsupport.rule;
import java.time.Duration;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.junit.Assume;
import org.junit.rules.TestRule;
import org.junit.runner.Description;
import org.junit.runners.model.Statement;
import org.springframework.beans.factory.DisposableBean;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.connection.RedisStandaloneConfiguration;
import org.springframework.data.redis.connection.jedis.JedisConnectionFactory;
import org.springframework.data.redis.connection.lettuce.LettuceClientConfiguration;
import org.springframework.data.redis.connection.lettuce.LettuceConnectionFactory;
import org.springframework.util.ClassUtils;
/**
* {@link TestRule} for working with an optional Redis server.
*
* @author Eric Bottard
* @author Gary Russell
* @author Dave Syer
* @author Phillip Webb
*/
public class RedisTestServer implements TestRule {
private static final Log logger = LogFactory.getLog(RedisTestServer.class);
private RedisConnectionFactory connectionFactory;
@Override
public Statement apply(final Statement base, Description description) {
try {
this.connectionFactory = createConnectionFactory();
return new RedisStatement(base, this.connectionFactory);
}
catch (Exception ex) {
logger.error("No Redis server available", ex);
return new SkipStatement();
}
}
private RedisConnectionFactory createConnectionFactory() {
ClassLoader classLoader = RedisTestServer.class.getClassLoader();
RedisConnectionFactory cf;
if (ClassUtils.isPresent("redis.clients.jedis.Jedis", classLoader)) {
cf = new JedisConnectionFactoryConfiguration().createConnectionFactory();
}
else {
cf = new LettuceConnectionFactoryConfiguration().createConnectionFactory();
}
testConnection(cf);
return cf;
}
private void testConnection(RedisConnectionFactory connectionFactory) {
connectionFactory.getConnection().close();
}
/**
* Return the Redis connection factory or {@code null} if the factory is not
* available.
* @return the connection factory or {@code null}
*/
public RedisConnectionFactory getConnectionFactory() {
return this.connectionFactory;
}
private static class RedisStatement extends Statement {
private final Statement base;
private final RedisConnectionFactory connectionFactory;
RedisStatement(Statement base, RedisConnectionFactory connectionFactory) {
this.base = base;
this.connectionFactory = connectionFactory;
}
@Override
public void evaluate() throws Throwable {
try {
this.base.evaluate();
}
finally {
try {
if (this.connectionFactory instanceof DisposableBean) {
((DisposableBean) this.connectionFactory).destroy();
}
}
catch (Exception ex) {
logger.warn("Exception while trying to cleanup redis resource", ex);
}
}
}
}
private static class SkipStatement extends Statement {
@Override
public void evaluate() throws Throwable {
Assume.assumeTrue("Skipping test due to " + "Redis ConnectionFactory"
+ " not being available", false);
}
}
private static class JedisConnectionFactoryConfiguration {
RedisConnectionFactory createConnectionFactory() {
JedisConnectionFactory connectionFactory = new JedisConnectionFactory();
connectionFactory.afterPropertiesSet();
return connectionFactory;
}
}
private static class LettuceConnectionFactoryConfiguration {
RedisConnectionFactory createConnectionFactory() {
LettuceClientConfiguration config = LettuceClientConfiguration.builder()
.shutdownTimeout(Duration.ofMillis(0)).build();
LettuceConnectionFactory connectionFactory = new LettuceConnectionFactory(
new RedisStandaloneConfiguration(), config);
connectionFactory.afterPropertiesSet();
return connectionFactory;
}
}
}

View File

@@ -0,0 +1,20 @@
/*
* 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.
*/
/**
* Internal JUnit rules used in Spring Boot tests.
*/
package org.springframework.boot.testsupport.rule;

View File

@@ -0,0 +1,44 @@
/*
* 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.boot.testsupport.runner.classpath;
import java.io.File;
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 exclude entries
* from the classpath.
*
* @author Andy Wilkinson
*/
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
public @interface ClassPathExclusions {
/**
* One or more Ant-style patterns that identify entries to be excluded from the class
* path. Matching is performed against an entry's {@link File#getName() file name}.
* For example, to exclude Hibernate Validator from the classpath,
* {@code "hibernate-validator-*.jar"} can be used.
* @return the exclusion patterns
*/
String[] value();
}

View File

@@ -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.boot.testsupport.runner.classpath;
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();
}

View File

@@ -0,0 +1,354 @@
/*
* 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.boot.testsupport.runner.classpath;
import java.io.File;
import java.lang.annotation.Annotation;
import java.lang.management.ManagementFactory;
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 java.util.stream.Stream;
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(
() -> ModifiedClassPathRunner.super.createTest());
}
private URLClassLoader createTestClassLoader(Class<?> testClass) throws Exception {
ClassLoader classLoader = this.getClass().getClassLoader();
return new ModifiedClassPathClassLoader(
processUrls(extractUrls(classLoader), testClass), classLoader.getParent(),
classLoader);
}
private URL[] extractUrls(ClassLoader classLoader) throws Exception {
List<URL> extractedUrls = new ArrayList<>();
doExtractUrls(classLoader).forEach((URL url) -> {
if (isSurefireBooterJar(url)) {
extractedUrls.addAll(extractUrlsFromManifestClassPath(url));
}
else {
extractedUrls.add(url);
}
});
return extractedUrls.toArray(new URL[extractedUrls.size()]);
}
private Stream<URL> doExtractUrls(ClassLoader classLoader) throws Exception {
if (classLoader instanceof URLClassLoader) {
return Stream.of(((URLClassLoader) classLoader).getURLs());
}
return Stream.of(ManagementFactory.getRuntimeMXBean().getClassPath()
.split(File.pathSeparator)).map(this::toURL);
}
private URL toURL(String entry) {
try {
return new File(entry).toURI().toURL();
}
catch (Exception ex) {
throw new IllegalArgumentException(ex);
}
}
private boolean isSurefireBooterJar(URL url) {
return url.getPath().contains("surefirebooter");
}
private List<URL> extractUrlsFromManifestClassPath(URL booterJar) {
List<URL> urls = new ArrayList<>();
try {
for (String entry : getClassPath(booterJar)) {
urls.add(new URL(entry));
}
}
catch (Exception ex) {
throw new RuntimeException(ex);
}
return urls;
}
private String[] getClassPath(URL booterJar) throws Exception {
try (JarFile jarFile = new JarFile(new File(booterJar.toURI()))) {
return StringUtils.delimitedListToStringArray(jarFile.getManifest()
.getMainAttributes().getValue(Attributes.Name.CLASS_PATH), " ");
}
}
private URL[] processUrls(URL[] urls, Class<?> testClass) throws Exception {
ClassPathEntryFilter filter = new ClassPathEntryFilter(testClass);
List<URL> processedUrls = new ArrayList<>();
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<>();
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<>();
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 {
this.exclusions = new ArrayList<>();
this.exclusions.add("log4j-*.jar");
ClassPathExclusions exclusions = AnnotationUtils.findAnnotation(testClass,
ClassPathExclusions.class);
if (exclusions != null) {
this.exclusions.addAll(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<>(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(
() -> 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);
}
}
}

View File

@@ -0,0 +1,20 @@
/*
* 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.
*/
/**
* Custom JUnit runner to change the classpath.
*/
package org.springframework.boot.testsupport.runner.classpath;

View File

@@ -0,0 +1,20 @@
/*
* 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.
*/
/**
* Custom JUnit runners used in Spring Boot's own tests.
*/
package org.springframework.boot.testsupport.runner;

View File

@@ -0,0 +1,51 @@
/*
* 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.boot.testsupport.web.servlet;
import java.io.IOException;
import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
/**
* Simple example Filter used for testing.
*
* @author Phillip Webb
*/
public class ExampleFilter implements Filter {
@Override
public void init(FilterConfig filterConfig) throws ServletException {
}
@Override
public void destroy() {
}
@Override
public void doFilter(ServletRequest request, ServletResponse response,
FilterChain chain) throws IOException, ServletException {
response.getWriter().write("[");
chain.doFilter(request, response);
response.getWriter().write("]");
}
}

View File

@@ -0,0 +1,69 @@
/*
* 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.boot.testsupport.web.servlet;
import java.io.IOException;
import javax.servlet.GenericServlet;
import javax.servlet.ServletException;
import javax.servlet.ServletOutputStream;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import org.springframework.util.StreamUtils;
/**
* Simple example Servlet used for testing.
*
* @author Phillip Webb
*/
@SuppressWarnings("serial")
public class ExampleServlet extends GenericServlet {
private final boolean echoRequestInfo;
private final boolean writeWithoutContentLength;
public ExampleServlet() {
this(false, false);
}
public ExampleServlet(boolean echoRequestInfo, boolean writeWithoutContentLength) {
this.echoRequestInfo = echoRequestInfo;
this.writeWithoutContentLength = writeWithoutContentLength;
}
@Override
public void service(ServletRequest request, ServletResponse response)
throws ServletException, IOException {
String content = "Hello World";
if (this.echoRequestInfo) {
content += " scheme=" + request.getScheme();
content += " remoteaddr=" + request.getRemoteAddr();
}
if (this.writeWithoutContentLength) {
response.setContentType("text/plain");
ServletOutputStream outputStream = response.getOutputStream();
StreamUtils.copy(content.getBytes(), outputStream);
outputStream.flush();
}
else {
response.getWriter().write(content);
}
}
}

View File

@@ -0,0 +1,224 @@
/*
* 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.boot.testsupport.web.servlet;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.NoSuchElementException;
import javax.servlet.Filter;
import javax.servlet.FilterRegistration;
import javax.servlet.RequestDispatcher;
import javax.servlet.Servlet;
import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.ServletRegistration;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyString;
import static org.mockito.BDDMockito.given;
import static org.mockito.Mockito.mock;
/**
* Base class for Mock {@code ServletWebServer} implementations. Reduces the amount of
* code that would otherwise be duplicated in {@code spring-boot},
* {@code spring-boot-autoconfigure} and {@code spring-boot-actuator}.
*
* @author Phillip Webb
* @author Andy Wilkinson
*/
public abstract class MockServletWebServer {
private ServletContext servletContext;
private final Initializer[] initializers;
private final List<RegisteredServlet> registeredServlets = new ArrayList<>();
private final List<RegisteredFilter> registeredFilters = new ArrayList<>();
private final int port;
public MockServletWebServer(Initializer[] initializers, int port) {
this.initializers = initializers;
this.port = port;
initialize();
}
private void initialize() {
try {
this.servletContext = mock(ServletContext.class);
given(this.servletContext.addServlet(anyString(), (Servlet) any()))
.willAnswer((invocation) -> {
RegisteredServlet registeredServlet = new RegisteredServlet(
(Servlet) invocation.getArguments()[1]);
MockServletWebServer.this.registeredServlets
.add(registeredServlet);
return registeredServlet.getRegistration();
});
given(this.servletContext.addFilter(anyString(), (Filter) any()))
.willAnswer((invocation) -> {
RegisteredFilter registeredFilter = new RegisteredFilter(
(Filter) invocation.getArguments()[1]);
MockServletWebServer.this.registeredFilters.add(registeredFilter);
return registeredFilter.getRegistration();
});
final Map<String, String> initParameters = new HashMap<>();
given(this.servletContext.setInitParameter(anyString(), anyString()))
.will((invocation) -> {
initParameters.put(invocation.getArgument(0),
invocation.getArgument(1));
return null;
});
given(this.servletContext.getInitParameterNames())
.willReturn(Collections.enumeration(initParameters.keySet()));
given(this.servletContext.getInitParameter(anyString())).willAnswer(
(invocation) -> initParameters.get(invocation.getArgument(0)));
given(this.servletContext.getAttributeNames())
.willReturn(MockServletWebServer.<String>emptyEnumeration());
given(this.servletContext.getNamedDispatcher("default"))
.willReturn(mock(RequestDispatcher.class));
for (Initializer initializer : this.initializers) {
initializer.onStartup(this.servletContext);
}
}
catch (ServletException ex) {
throw new RuntimeException(ex);
}
}
public void stop() {
this.servletContext = null;
this.registeredServlets.clear();
}
public ServletContext getServletContext() {
return this.servletContext;
}
public Servlet[] getServlets() {
Servlet[] servlets = new Servlet[this.registeredServlets.size()];
for (int i = 0; i < servlets.length; i++) {
servlets[i] = this.registeredServlets.get(i).getServlet();
}
return servlets;
}
public RegisteredServlet getRegisteredServlet(int index) {
return getRegisteredServlets().get(index);
}
public List<RegisteredServlet> getRegisteredServlets() {
return this.registeredServlets;
}
public RegisteredFilter getRegisteredFilters(int index) {
return getRegisteredFilters().get(index);
}
public List<RegisteredFilter> getRegisteredFilters() {
return this.registeredFilters;
}
public int getPort() {
return this.port;
}
@SuppressWarnings("unchecked")
public static <T> Enumeration<T> emptyEnumeration() {
return (Enumeration<T>) EmptyEnumeration.EMPTY_ENUMERATION;
}
private static class EmptyEnumeration<E> implements Enumeration<E> {
static final MockServletWebServer.EmptyEnumeration<Object> EMPTY_ENUMERATION = new MockServletWebServer.EmptyEnumeration<>();
@Override
public boolean hasMoreElements() {
return false;
}
@Override
public E nextElement() {
throw new NoSuchElementException();
}
}
/**
* A registered servlet.
*/
public static class RegisteredServlet {
private final Servlet servlet;
private final ServletRegistration.Dynamic registration;
public RegisteredServlet(Servlet servlet) {
this.servlet = servlet;
this.registration = mock(ServletRegistration.Dynamic.class);
}
public ServletRegistration.Dynamic getRegistration() {
return this.registration;
}
public Servlet getServlet() {
return this.servlet;
}
}
/**
* A registered filter.
*/
public static class RegisteredFilter {
private final Filter filter;
private final FilterRegistration.Dynamic registration;
public RegisteredFilter(Filter filter) {
this.filter = filter;
this.registration = mock(FilterRegistration.Dynamic.class);
}
public FilterRegistration.Dynamic getRegistration() {
return this.registration;
}
public Filter getFilter() {
return this.filter;
}
}
/**
* Initializer (usually implement by adapting {@code Initializer}).
*/
@FunctionalInterface
protected interface Initializer {
void onStartup(ServletContext context) throws ServletException;
}
}

View File

@@ -0,0 +1,20 @@
/*
* 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.
*/
/**
* Servlet test support.
*/
package org.springframework.boot.testsupport.web.servlet;

View File

@@ -0,0 +1,60 @@
/*
* 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.boot.testsupport.assertj;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.ExpectedException;
import static org.assertj.core.api.Assertions.assertThat;
import static org.hamcrest.Matchers.startsWith;
/**
* Tests for {@link Matched}.
*
* @author Phillip Webb
*/
public class MatchedTests {
@Rule
public ExpectedException thrown = ExpectedException.none();
@Test
public void byMatcherMatches() {
assertThat("1234").is(Matched.by(startsWith("12")));
}
@Test
public void byMatcherDoesNotMatch() {
this.thrown.expect(AssertionError.class);
this.thrown.expectMessage("a string starting with \"23\"");
assertThat("1234").is(Matched.by(startsWith("23")));
}
@Test
public void whenMatcherMatches() {
assertThat("1234").is(Matched.when(startsWith("12")));
}
@Test
public void whenMatcherDoesNotMatch() {
this.thrown.expect(AssertionError.class);
this.thrown.expectMessage("a string starting with \"23\"");
assertThat("1234").is(Matched.when(startsWith("23")));
}
}

View File

@@ -0,0 +1,59 @@
/*
* 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.boot.testsupport.runner.classpath;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.ExpectedException;
import org.junit.runner.RunWith;
import static org.assertj.core.api.Assertions.assertThat;
import static org.hamcrest.CoreMatchers.isA;
/**
* Tests for {@link ModifiedClassPathRunner} excluding entries from the class path.
*
* @author Andy Wilkinson
*/
@RunWith(ModifiedClassPathRunner.class)
@ClassPathExclusions("hibernate-validator-*.jar")
public class ModifiedClassPathRunnerExclusionsTests {
private static final String EXCLUDED_RESOURCE = "META-INF/services/"
+ "javax.validation.spi.ValidationProvider";
@Rule
public ExpectedException thrown = ExpectedException.none();
@Test
public void entriesAreFilteredFromTestClassClassLoader() {
assertThat(getClass().getClassLoader().getResource(EXCLUDED_RESOURCE)).isNull();
}
@Test
public void entriesAreFilteredFromThreadContextClassLoader() {
assertThat(Thread.currentThread().getContextClassLoader()
.getResource(EXCLUDED_RESOURCE)).isNull();
}
@Test
public void testsThatUseHamcrestWorkCorrectly() {
this.thrown.expect(isA(IllegalStateException.class));
throw new IllegalStateException();
}
}

View File

@@ -0,0 +1,48 @@
/*
* 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.boot.testsupport.runner.classpath;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.context.ApplicationContext;
import org.springframework.util.StringUtils;
import static org.assertj.core.api.Assertions.assertThat;
/**
* Tests for {@link ModifiedClassPathRunner} overriding entries on the class path.
*
* @author Andy Wilkinson
*/
@RunWith(ModifiedClassPathRunner.class)
@ClassPathOverrides("org.springframework:spring-context:4.1.0.RELEASE")
public class ModifiedClassPathRunnerOverridesTests {
@Test
public void classesAreLoadedFromOverride() {
assertThat(ApplicationContext.class.getProtectionDomain().getCodeSource()
.getLocation().toString()).endsWith("spring-context-4.1.0.RELEASE.jar");
}
@Test
public void classesAreLoadedFromTransitiveDependencyOfOverride() {
assertThat(StringUtils.class.getProtectionDomain().getCodeSource().getLocation()
.toString()).endsWith("spring-core-4.1.0.RELEASE.jar");
}
}