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:
@@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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;
|
||||
@@ -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");
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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;
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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;
|
||||
@@ -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;
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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;
|
||||
@@ -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();
|
||||
|
||||
}
|
||||
@@ -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();
|
||||
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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;
|
||||
@@ -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;
|
||||
@@ -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("]");
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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;
|
||||
@@ -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")));
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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");
|
||||
}
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user