Minimize and centralize assumptions about build output

Closes gh-15471
pull/15473/head
Andy Wilkinson 6 years ago
parent 7d0a7a65c8
commit 61d04db0d7

@ -141,10 +141,10 @@ public class Neo4jPropertiesTests {
@Test
public void embeddedModeWithRelativeLocation() {
Neo4jProperties properties = load(true,
"spring.data.neo4j.uri=file:target/neo4j/my.db");
"spring.data.neo4j.uri=file:relative/path/to/my.db");
Configuration configuration = properties.createConfiguration();
assertDriver(configuration, Neo4jProperties.EMBEDDED_DRIVER,
"file:target/neo4j/my.db");
"file:relative/path/to/my.db");
}
private static void assertDriver(Configuration actual, String driver, String uri) {

@ -24,6 +24,7 @@ import org.junit.Test;
import org.springframework.boot.autoconfigure.AutoConfigurations;
import org.springframework.boot.test.context.runner.ApplicationContextRunner;
import org.springframework.boot.testsupport.BuildOutput;
import org.springframework.boot.testsupport.rule.OutputCapture;
import static org.assertj.core.api.Assertions.assertThat;
@ -36,6 +37,8 @@ import static org.assertj.core.api.Assertions.assertThat;
*/
public class FreeMarkerAutoConfigurationTests {
private final BuildOutput buildOutput = new BuildOutput(getClass());
private final ApplicationContextRunner contextRunner = new ApplicationContextRunner()
.withConfiguration(AutoConfigurations.of(FreeMarkerAutoConfiguration.class));
@ -68,19 +71,24 @@ public class FreeMarkerAutoConfigurationTests {
@Test
public void emptyTemplateLocation() {
new File("target/test-classes/templates/empty-directory").mkdir();
this.contextRunner.withPropertyValues("spring.freemarker.templateLoaderPath:"
+ "classpath:/templates/empty-directory/").run((context) -> {
});
File emptyDirectory = new File(this.buildOutput.getTestResourcesLocation(),
"empty-templates/empty-directory");
emptyDirectory.mkdirs();
this.contextRunner
.withPropertyValues("spring.freemarker.templateLoaderPath:"
+ "classpath:/empty-templates/empty-directory/")
.run((context) -> assertThat(this.output.toString())
.doesNotContain("Cannot find template location"));
}
@Test
public void nonExistentLocationAndEmptyLocation() {
new File("target/test-classes/templates/empty-directory").mkdir();
new File(this.buildOutput.getTestResourcesLocation(),
"empty-templates/empty-directory").mkdirs();
this.contextRunner.withPropertyValues("spring.freemarker.templateLoaderPath:"
+ "classpath:/does-not-exist/,classpath:/templates/empty-directory/")
.run((context) -> {
});
+ "classpath:/does-not-exist/,classpath:/empty-templates/empty-directory/")
.run((context) -> assertThat(this.output.toString())
.doesNotContain("Cannot find template location"));
}
}

@ -31,6 +31,7 @@ import org.junit.Before;
import org.junit.Test;
import org.springframework.boot.test.util.TestPropertyValues;
import org.springframework.boot.testsupport.BuildOutput;
import org.springframework.context.i18n.LocaleContextHolder;
import org.springframework.core.io.ClassPathResource;
import org.springframework.mock.web.MockHttpServletRequest;
@ -53,6 +54,8 @@ import static org.assertj.core.api.Assertions.assertThat;
*/
public class GroovyTemplateAutoConfigurationTests {
private final BuildOutput buildOutput = new BuildOutput(getClass());
private AnnotationConfigWebApplicationContext context = new AnnotationConfigWebApplicationContext();
@Before
@ -76,7 +79,8 @@ public class GroovyTemplateAutoConfigurationTests {
@Test
public void emptyTemplateLocation() {
new File("target/test-classes/templates/empty-directory").mkdir();
new File(this.buildOutput.getTestResourcesLocation(),
"empty-templates/empty-directory").mkdirs();
registerAndRefreshContext("spring.groovy.template.resource-loader-path:"
+ "classpath:/templates/empty-directory/");
}

@ -244,7 +244,7 @@ public class DataSourceAutoConfigurationTests {
public DataSource dataSource() {
this.pool = new BasicDataSource();
this.pool.setDriverClassName("org.hsqldb.jdbcDriver");
this.pool.setUrl("jdbc:hsqldb:target/overridedb");
this.pool.setUrl("jdbc:hsqldb:mem:overridedb");
this.pool.setUsername("sa");
return this.pool;
}

@ -17,6 +17,7 @@
package org.springframework.boot.autoconfigure.mongo.embedded;
import java.io.File;
import java.io.IOException;
import java.util.EnumSet;
import java.util.stream.Collectors;
@ -27,7 +28,9 @@ import de.flapdoodle.embed.mongo.distribution.Feature;
import de.flapdoodle.embed.mongo.distribution.Version;
import org.bson.Document;
import org.junit.After;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.TemporaryFolder;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.autoconfigure.context.PropertyPlaceholderAutoConfiguration;
@ -52,6 +55,9 @@ import static org.assertj.core.api.Assertions.assertThat;
*/
public class EmbeddedMongoAutoConfigurationTests {
@Rule
public final TemporaryFolder temp = new TemporaryFolder();
private AnnotationConfigApplicationContext context;
@After
@ -143,8 +149,8 @@ public class EmbeddedMongoAutoConfigurationTests {
}
@Test
public void mongoWritesToCustomDatabaseDir() {
File customDatabaseDir = new File("target/custom-database-dir");
public void mongoWritesToCustomDatabaseDir() throws IOException {
File customDatabaseDir = this.temp.newFolder("custom-database-dir");
FileSystemUtils.deleteRecursively(customDatabaseDir);
load("spring.mongodb.embedded.storage.databaseDir="
+ customDatabaseDir.getPath());

@ -39,6 +39,7 @@ import org.thymeleaf.templateresolver.ITemplateResolver;
import org.springframework.boot.autoconfigure.ImportAutoConfiguration;
import org.springframework.boot.autoconfigure.context.PropertyPlaceholderAutoConfiguration;
import org.springframework.boot.test.util.TestPropertyValues;
import org.springframework.boot.testsupport.BuildOutput;
import org.springframework.boot.testsupport.rule.OutputCapture;
import org.springframework.boot.web.reactive.context.AnnotationConfigReactiveWebApplicationContext;
import org.springframework.context.annotation.Bean;
@ -61,6 +62,8 @@ import static org.assertj.core.api.Assertions.assertThat;
*/
public class ThymeleafReactiveAutoConfigurationTests {
private final BuildOutput buildOutput = new BuildOutput(getClass());
@Rule
public final OutputCapture output = new OutputCapture();
@ -184,9 +187,10 @@ public class ThymeleafReactiveAutoConfigurationTests {
@Test
public void templateLocationEmpty() {
new File("target/test-classes/templates/empty-directory").mkdir();
new File(this.buildOutput.getTestResourcesLocation(),
"empty-templates/empty-directory").mkdirs();
load(BaseConfiguration.class,
"spring.thymeleaf.prefix:classpath:/templates/empty-directory/");
"spring.thymeleaf.prefix:classpath:/empty-templates/empty-directory/");
assertThat(this.output.toString())
.doesNotContain("Cannot find template location");
}

@ -42,6 +42,7 @@ import org.springframework.boot.autoconfigure.ImportAutoConfiguration;
import org.springframework.boot.autoconfigure.context.PropertyPlaceholderAutoConfiguration;
import org.springframework.boot.test.rule.OutputCapture;
import org.springframework.boot.test.util.TestPropertyValues;
import org.springframework.boot.testsupport.BuildOutput;
import org.springframework.boot.web.servlet.FilterRegistrationBean;
import org.springframework.boot.web.servlet.filter.OrderedCharacterEncodingFilter;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
@ -75,6 +76,8 @@ import static org.hamcrest.Matchers.containsString;
*/
public class ThymeleafServletAutoConfigurationTests {
private final BuildOutput buildOutput = new BuildOutput(getClass());
@Rule
public OutputCapture output = new OutputCapture();
@ -176,9 +179,10 @@ public class ThymeleafServletAutoConfigurationTests {
@Test
public void templateLocationEmpty() {
new File("target/test-classes/templates/empty-directory").mkdir();
new File(this.buildOutput.getTestResourcesLocation(),
"empty-templates/empty-directory").mkdirs();
load(BaseConfiguration.class,
"spring.thymeleaf.prefix:classpath:/templates/empty-directory/");
"spring.thymeleaf.prefix:classpath:/empty-templates/empty-directory/");
}
@Test

@ -17,6 +17,7 @@
package org.springframework.boot.autoconfigure.transaction.jta;
import java.io.File;
import java.io.IOException;
import java.net.InetAddress;
import java.net.UnknownHostException;
@ -35,8 +36,9 @@ import com.atomikos.icatch.config.UserTransactionService;
import com.atomikos.icatch.jta.UserTransactionManager;
import com.atomikos.jms.AtomikosConnectionFactoryBean;
import org.junit.After;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.TemporaryFolder;
import org.springframework.beans.factory.NoSuchBeanDefinitionException;
import org.springframework.boot.autoconfigure.transaction.TransactionAutoConfiguration;
@ -55,7 +57,6 @@ import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.transaction.PlatformTransactionManager;
import org.springframework.transaction.jta.JtaTransactionManager;
import org.springframework.util.FileSystemUtils;
import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.assertThatExceptionOfType;
@ -72,12 +73,10 @@ import static org.mockito.Mockito.mock;
*/
public class JtaAutoConfigurationTests {
private AnnotationConfigApplicationContext context;
@Rule
public final TemporaryFolder temp = new TemporaryFolder();
@Before
public void cleanUpLogs() {
FileSystemUtils.deleteRecursively(new File("target/transaction-logs"));
}
private AnnotationConfigApplicationContext context;
@After
public void closeContext() {
@ -155,15 +154,16 @@ public class JtaAutoConfigurationTests {
}
@Test
public void defaultAtomikosTransactionManagerName() {
public void defaultAtomikosTransactionManagerName() throws IOException {
this.context = new AnnotationConfigApplicationContext();
TestPropertyValues.of("spring.jta.logDir:target/transaction-logs")
File logs = this.temp.newFolder("jta");
TestPropertyValues.of("spring.jta.logDir:" + logs.getAbsolutePath())
.applyTo(this.context);
this.context.register(JtaPropertiesConfiguration.class,
AtomikosJtaConfiguration.class);
this.context.refresh();
File epochFile = new File("target/transaction-logs/tmlog0.log");
File epochFile = new File(logs, "tmlog0.log");
assertThat(epochFile.isFile()).isTrue();
}

@ -18,7 +18,9 @@ package org.springframework.boot.cli;
import java.io.IOException;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.TemporaryFolder;
import org.springframework.boot.cli.infrastructure.CommandLineInvoker;
import org.springframework.boot.cli.infrastructure.CommandLineInvoker.Invocation;
@ -36,7 +38,10 @@ import static org.junit.Assert.assertThat;
*/
public class CommandLineIT {
private final CommandLineInvoker cli = new CommandLineInvoker();
@Rule
public final TemporaryFolder temp = new TemporaryFolder();
private final CommandLineInvoker cli = new CommandLineInvoker(this.temp);
@Test
public void hintProducesListOfValidCommands()

@ -1,5 +1,5 @@
/*
* Copyright 2012-2017 the original author or authors.
* Copyright 2012-2018 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.
@ -18,7 +18,9 @@ package org.springframework.boot.cli;
import java.io.File;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.TemporaryFolder;
import org.springframework.boot.cli.command.archive.JarCommand;
import org.springframework.boot.cli.infrastructure.CommandLineInvoker;
@ -43,8 +45,11 @@ public class JarCommandIT {
private static final boolean JAVA_9_OR_LATER = isClassPresent(
"java.security.cert.URICertStoreParameters");
@Rule
public final TemporaryFolder temp = new TemporaryFolder();
private final CommandLineInvoker cli = new CommandLineInvoker(
new File("src/it/resources/jar-command"));
new File("src/it/resources/jar-command"), this.temp);
@Test
public void noArguments() throws Exception {
@ -66,7 +71,7 @@ public class JarCommandIT {
@Test
public void jarCreationWithGrabResolver() throws Exception {
File jar = new File("target/test-app.jar");
File jar = new File(this.temp.getRoot(), "test-app.jar");
Invocation invocation = this.cli.invoke("run", jar.getAbsolutePath(),
"bad.groovy");
invocation.await();
@ -93,7 +98,7 @@ public class JarCommandIT {
@Test
public void jarCreation() throws Exception {
File jar = new File("target/test-app.jar");
File jar = new File(this.temp.getRoot(), "test-app.jar");
Invocation invocation = this.cli.invoke("jar", jar.getAbsolutePath(),
"jar.groovy");
invocation.await();
@ -127,7 +132,7 @@ public class JarCommandIT {
@Test
public void jarCreationWithIncludes() throws Exception {
File jar = new File("target/test-app.jar");
File jar = new File(this.temp.getRoot(), "test-app.jar");
Invocation invocation = this.cli.invoke("jar", jar.getAbsolutePath(), "--include",
"-public/**,-resources/**", "jar.groovy");
invocation.await();

@ -1,5 +1,5 @@
/*
* Copyright 2012-2017 the original author or authors.
* Copyright 2012-2018 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.
@ -18,7 +18,9 @@ package org.springframework.boot.cli;
import java.io.File;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.TemporaryFolder;
import org.springframework.boot.cli.command.archive.WarCommand;
import org.springframework.boot.cli.infrastructure.CommandLineInvoker;
@ -35,12 +37,15 @@ import static org.assertj.core.api.Assertions.assertThat;
*/
public class WarCommandIT {
@Rule
public final TemporaryFolder temp = new TemporaryFolder();
private final CommandLineInvoker cli = new CommandLineInvoker(
new File("src/it/resources/war-command"));
new File("src/it/resources/war-command"), this.temp);
@Test
public void warCreation() throws Exception {
File war = new File("target/test-app.war");
File war = new File(this.temp.getRoot(), "test-app.war");
Invocation invocation = this.cli.invoke("war", war.getAbsolutePath(),
"war.groovy");
invocation.await();

@ -32,6 +32,9 @@ import java.util.stream.Collectors;
import java.util.zip.ZipEntry;
import java.util.zip.ZipInputStream;
import org.junit.rules.TemporaryFolder;
import org.springframework.boot.testsupport.BuildOutput;
import org.springframework.util.Assert;
import org.springframework.util.StreamUtils;
@ -46,12 +49,15 @@ public final class CommandLineInvoker {
private final File workingDirectory;
public CommandLineInvoker() {
this(new File("."));
private final TemporaryFolder temp;
public CommandLineInvoker(TemporaryFolder temp) {
this(new File("."), temp);
}
public CommandLineInvoker(File workingDirectory) {
public CommandLineInvoker(File workingDirectory, TemporaryFolder temp) {
this.workingDirectory = workingDirectory;
this.temp = temp;
}
public Invocation invoke(String... args) throws IOException {
@ -69,9 +75,9 @@ public final class CommandLineInvoker {
}
private File findLaunchScript() throws IOException {
File unpacked = new File("target/unpacked-cli");
File unpacked = new File(this.temp.getRoot(), "unpacked-cli");
if (!unpacked.isDirectory()) {
File zip = new File("target")
File zip = new BuildOutput(getClass()).getRootLocation()
.listFiles((pathname) -> pathname.getName().endsWith("-bin.zip"))[0];
try (ZipInputStream input = new ZipInputStream(new FileInputStream(zip))) {
ZipEntry entry;

@ -32,6 +32,7 @@ import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;
import org.junit.Assume;
import org.junit.rules.TemporaryFolder;
import org.junit.rules.TestRule;
import org.junit.runner.Description;
import org.junit.runners.model.Statement;
@ -42,6 +43,7 @@ import org.springframework.boot.cli.command.archive.JarCommand;
import org.springframework.boot.cli.command.grab.GrabCommand;
import org.springframework.boot.cli.command.run.RunCommand;
import org.springframework.boot.test.rule.OutputCapture;
import org.springframework.boot.testsupport.BuildOutput;
import org.springframework.util.FileCopyUtils;
import org.springframework.util.StringUtils;
@ -54,6 +56,10 @@ import org.springframework.util.StringUtils;
*/
public class CliTester implements TestRule {
private final TemporaryFolder temp = new TemporaryFolder();
private final BuildOutput buildOutput = new BuildOutput(getClass());
private final OutputCapture outputCapture = new OutputCapture();
private long timeout = TimeUnit.MINUTES.toMillis(6);
@ -62,6 +68,8 @@ public class CliTester implements TestRule {
private final String prefix;
private File serverPortFile;
public CliTester(String prefix) {
this.prefix = prefix;
}
@ -75,14 +83,15 @@ public class CliTester implements TestRule {
boolean classpathUpdated = false;
for (String arg : args) {
if (arg.startsWith("--classpath=")) {
arg = arg + ":" + new File("target/test-classes").getAbsolutePath();
arg = arg + ":"
+ this.buildOutput.getTestClassesLocation().getAbsolutePath();
classpathUpdated = true;
}
updatedArgs.add(arg);
}
if (!classpathUpdated) {
updatedArgs.add(
"--classpath=.:" + new File("target/test-classes").getAbsolutePath());
updatedArgs.add("--classpath=.:"
+ this.buildOutput.getTestClassesLocation().getAbsolutePath());
}
Future<RunCommand> future = submitCommand(new RunCommand(),
StringUtils.toStringArray(updatedArgs));
@ -111,8 +120,8 @@ public class CliTester implements TestRule {
System.setProperty("server.port", "0");
System.setProperty("spring.application.class.name",
"org.springframework.boot.cli.CliTesterSpringApplication");
System.setProperty("portfile",
new File("target/server.port").getAbsolutePath());
this.serverPortFile = new File(this.temp.newFolder(), "server.port");
System.setProperty("portfile", this.serverPortFile.getAbsolutePath());
try {
command.run(sources);
return command;
@ -168,8 +177,9 @@ public class CliTester implements TestRule {
@Override
public Statement apply(Statement base, Description description) {
final Statement statement = CliTester.this.outputCapture
.apply(new RunLauncherStatement(base), description);
final Statement statement = this.temp.apply(
this.outputCapture.apply(new RunLauncherStatement(base), description),
description);
return new Statement() {
@Override
@ -180,6 +190,7 @@ public class CliTester implements TestRule {
.contains("integration"));
statement.evaluate();
}
};
}
@ -190,7 +201,7 @@ public class CliTester implements TestRule {
public String getHttpOutput(String uri) {
try {
int port = Integer.parseInt(
FileCopyUtils.copyToString(new FileReader("target/server.port")));
FileCopyUtils.copyToString(new FileReader(this.serverPortFile)));
InputStream stream = URI.create("http://localhost:" + port + uri).toURL()
.openStream();
BufferedReader reader = new BufferedReader(new InputStreamReader(stream));

@ -1,5 +1,5 @@
/*
* Copyright 2012-2017 the original author or authors.
* Copyright 2012-2018 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.
@ -22,6 +22,7 @@ import org.junit.After;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.TemporaryFolder;
import org.springframework.boot.cli.command.grab.GrabCommand;
import org.springframework.util.FileSystemUtils;
@ -37,13 +38,15 @@ import static org.junit.Assert.fail;
*/
public class GrabCommandIntegrationTests {
@Rule
public TemporaryFolder temp = new TemporaryFolder();
@Rule
public CliTester cli = new CliTester("src/test/resources/grab-samples/");
@Before
@After
public void deleteLocalRepository() {
FileSystemUtils.deleteRecursively(new File("target/repository"));
System.clearProperty("grape.root");
System.clearProperty("groovy.grape.report.downloads");
}
@ -51,13 +54,13 @@ public class GrabCommandIntegrationTests {
@Test
public void grab() throws Exception {
System.setProperty("grape.root", "target");
System.setProperty("grape.root", this.temp.getRoot().getAbsolutePath());
System.setProperty("groovy.grape.report.downloads", "true");
// Use --autoconfigure=false to limit the amount of downloaded dependencies
String output = this.cli.grab("grab.groovy", "--autoconfigure=false");
assertThat(new File("target/repository/joda-time/joda-time").isDirectory())
.isTrue();
assertThat(new File(this.temp.getRoot(), "repository/joda-time/joda-time"))
.isDirectory();
// Should be resolved from local repository cache
assertThat(output.contains("Downloading: file:")).isTrue();
}
@ -76,13 +79,12 @@ public class GrabCommandIntegrationTests {
@Test
public void customMetadata() throws Exception {
System.setProperty("grape.root", "target");
System.setProperty("grape.root", this.temp.getRoot().getAbsolutePath());
File repository = new File(this.temp.getRoot().getAbsolutePath(), "repository");
FileSystemUtils.copyRecursively(
new File("src/test/resources/grab-samples/repository"),
new File("target/repository"));
new File("src/test/resources/grab-samples/repository"), repository);
this.cli.grab("customDependencyManagement.groovy", "--autoconfigure=false");
assertThat(new File("target/repository/javax/ejb/ejb-api/3.0").isDirectory())
.isTrue();
assertThat(new File(repository, "javax/ejb/ejb-api/3.0")).isDirectory();
}
}

@ -1,5 +1,5 @@
/*
* Copyright 2012-2017 the original author or authors.
* Copyright 2012-2018 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.
@ -28,8 +28,6 @@ import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.TemporaryFolder;
import org.springframework.util.FileSystemUtils;
import static org.assertj.core.api.Assertions.assertThat;
import static org.mockito.BDDMockito.given;
import static org.mockito.Mockito.mock;
@ -50,9 +48,7 @@ public class InstallerTests {
@Before
public void setUp() throws IOException {
System.setProperty("spring.home", "target");
FileSystemUtils.deleteRecursively(new File("target/lib"));
System.setProperty("spring.home", this.tempFolder.getRoot().getAbsolutePath());
this.installer = new Installer(this.resolver);
}
@ -119,7 +115,7 @@ public class InstallerTests {
private Set<String> getNamesOfFilesInLibExt() {
Set<String> names = new HashSet<>();
for (File file : new File("target/lib/ext").listFiles()) {
for (File file : new File(this.tempFolder.getRoot(), "lib/ext").listFiles()) {
names.add(file.getName());
}
return names;

@ -16,6 +16,7 @@
package org.springframework.boot.devtools.autoconfigure;
import java.io.IOException;
import java.sql.SQLException;
import java.sql.Statement;
@ -23,7 +24,9 @@ import javax.sql.DataSource;
import org.junit.After;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.TemporaryFolder;
import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration;
import org.springframework.context.ConfigurableApplicationContext;
@ -40,9 +43,13 @@ import static org.mockito.Mockito.verify;
public class DevToolsPooledDataSourceAutoConfigurationTests
extends AbstractDevToolsDataSourceAutoConfigurationTests {
@Rule
public final TemporaryFolder temp = new TemporaryFolder();
@Before
public void before() {
System.setProperty("derby.stream.error.file", "target/derby.log");
public void before() throws IOException {
System.setProperty("derby.stream.error.file",
this.temp.newFile("derby.log").getAbsolutePath());
}
@After

@ -26,6 +26,7 @@ import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest;
import org.springframework.boot.test.context.TestConfiguration;
import org.springframework.boot.testsupport.BuildOutput;
import org.springframework.context.annotation.Bean;
import org.springframework.restdocs.mockmvc.MockMvcRestDocumentation;
import org.springframework.restdocs.mockmvc.RestDocumentationResultHandler;
@ -55,23 +56,26 @@ import static org.springframework.test.web.servlet.request.MockMvcRequestBuilder
@AutoConfigureRestDocs
public class MockMvcRestDocsAutoConfigurationAdvancedConfigurationIntegrationTests {
@Before
public void deleteSnippets() {
FileSystemUtils.deleteRecursively(new File("target/generated-snippets"));
}
@Autowired
private MockMvc mvc;
@Autowired
private RestDocumentationResultHandler documentationHandler;
private File generatedSnippets;
@Before
public void deleteSnippets() {
this.generatedSnippets = new File(new BuildOutput(getClass()).getRootLocation(),
"generated-snippets");
FileSystemUtils.deleteRecursively(this.generatedSnippets);
}
@Test
public void snippetGeneration() throws Exception {
this.mvc.perform(get("/")).andDo(this.documentationHandler.document(links(
linkWithRel("self").description("Canonical location of this resource"))));
File defaultSnippetsDir = new File(
"target/generated-snippets/snippet-generation");
File defaultSnippetsDir = new File(this.generatedSnippets, "snippet-generation");
assertThat(defaultSnippetsDir).exists();
assertThat(new File(defaultSnippetsDir, "curl-request.md"))
.has(contentContaining("'http://localhost:8080/'"));

@ -1,5 +1,5 @@
/*
* Copyright 2012-2017 the original author or authors.
* Copyright 2012-2018 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.
@ -25,6 +25,7 @@ import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest;
import org.springframework.boot.testsupport.BuildOutput;
import org.springframework.test.context.junit4.SpringRunner;
import org.springframework.test.web.servlet.MockMvc;
import org.springframework.util.FileSystemUtils;
@ -43,18 +44,22 @@ import static org.springframework.test.web.servlet.request.MockMvcRequestBuilder
@AutoConfigureRestDocs(uriScheme = "https", uriHost = "api.example.com", uriPort = 443)
public class MockMvcRestDocsAutoConfigurationIntegrationTests {
@Autowired
private MockMvc mvc;
private File generatedSnippets;
@Before
public void deleteSnippets() {
FileSystemUtils.deleteRecursively(new File("target/generated-snippets"));
this.generatedSnippets = new File(new BuildOutput(getClass()).getRootLocation(),
"generated-snippets");
FileSystemUtils.deleteRecursively(this.generatedSnippets);
}
@Autowired
private MockMvc mvc;
@Test
public void defaultSnippetsAreWritten() throws Exception {
this.mvc.perform(get("/")).andDo(document("default-snippets"));
File defaultSnippetsDir = new File("target/generated-snippets/default-snippets");
File defaultSnippetsDir = new File(this.generatedSnippets, "default-snippets");
assertThat(defaultSnippetsDir).exists();
assertThat(new File(defaultSnippetsDir, "curl-request.adoc"))
.has(contentContaining("'https://api.example.com/'"));

@ -28,6 +28,7 @@ import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.boot.test.context.SpringBootTest.WebEnvironment;
import org.springframework.boot.test.context.TestConfiguration;
import org.springframework.boot.testsupport.BuildOutput;
import org.springframework.boot.web.server.LocalServerPort;
import org.springframework.context.annotation.Bean;
import org.springframework.restdocs.mockmvc.MockMvcRestDocumentation;
@ -59,14 +60,18 @@ public class RestAssuredRestDocsAutoConfigurationAdvancedConfigurationIntegratio
@LocalServerPort
private int port;
@Autowired
private RequestSpecification documentationSpec;
private File generatedSnippets;
@Before
public void deleteSnippets() {
FileSystemUtils.deleteRecursively(new File("target/generated-snippets"));
this.generatedSnippets = new File(new BuildOutput(getClass()).getRootLocation(),
"generated-snippets");
FileSystemUtils.deleteRecursively(this.generatedSnippets);
}
@Autowired
private RequestSpecification documentationSpec;
@Test
public void snippetGeneration() {
given(this.documentationSpec)
@ -74,7 +79,7 @@ public class RestAssuredRestDocsAutoConfigurationAdvancedConfigurationIntegratio
preprocessRequest(modifyUris().scheme("https")
.host("api.example.com").removePort())))
.when().port(this.port).get("/").then().assertThat().statusCode(is(200));
File defaultSnippetsDir = new File("target/generated-snippets/default-snippets");
File defaultSnippetsDir = new File(this.generatedSnippets, "default-snippets");
assertThat(defaultSnippetsDir).exists();
assertThat(new File(defaultSnippetsDir, "curl-request.md"))
.has(contentContaining("'https://api.example.com/'"));

@ -27,6 +27,7 @@ import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.boot.test.context.SpringBootTest.WebEnvironment;
import org.springframework.boot.testsupport.BuildOutput;
import org.springframework.boot.web.server.LocalServerPort;
import org.springframework.test.context.junit4.SpringRunner;
import org.springframework.util.FileSystemUtils;
@ -51,14 +52,18 @@ public class RestAssuredRestDocsAutoConfigurationIntegrationTests {
@LocalServerPort
private int port;
@Autowired
private RequestSpecification documentationSpec;
private File generatedSnippets;
@Before
public void deleteSnippets() {
FileSystemUtils.deleteRecursively(new File("target/generated-snippets"));
this.generatedSnippets = new File(new BuildOutput(getClass()).getRootLocation(),
"generated-snippets");
FileSystemUtils.deleteRecursively(this.generatedSnippets);
}
@Autowired
private RequestSpecification documentationSpec;
@Test
public void defaultSnippetsAreWritten() {
given(this.documentationSpec)
@ -66,7 +71,7 @@ public class RestAssuredRestDocsAutoConfigurationIntegrationTests {
preprocessRequest(modifyUris().scheme("https")
.host("api.example.com").removePort())))
.when().port(this.port).get("/").then().assertThat().statusCode(is(200));
File defaultSnippetsDir = new File("target/generated-snippets/default-snippets");
File defaultSnippetsDir = new File(this.generatedSnippets, "default-snippets");
assertThat(defaultSnippetsDir).exists();
assertThat(new File(defaultSnippetsDir, "curl-request.adoc"))
.has(contentContaining("'https://api.example.com/'"));

@ -26,6 +26,7 @@ import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.autoconfigure.web.reactive.WebFluxTest;
import org.springframework.boot.test.context.TestConfiguration;
import org.springframework.boot.testsupport.BuildOutput;
import org.springframework.context.annotation.Bean;
import org.springframework.restdocs.mockmvc.MockMvcRestDocumentation;
import org.springframework.restdocs.mockmvc.RestDocumentationResultHandler;
@ -51,19 +52,23 @@ import static org.springframework.restdocs.webtestclient.WebTestClientRestDocume
@AutoConfigureRestDocs(uriScheme = "https", uriHost = "api.example.com", uriPort = 443)
public class WebTestClientRestDocsAutoConfigurationAdvancedConfigurationIntegrationTests {
@Autowired
private WebTestClient webTestClient;
private File generatedSnippets;
@Before
public void deleteSnippets() {
FileSystemUtils.deleteRecursively(new File("target/generated-snippets"));
this.generatedSnippets = new File(new BuildOutput(getClass()).getRootLocation(),
"generated-snippets");
FileSystemUtils.deleteRecursively(this.generatedSnippets);
}
@Autowired
private WebTestClient webTestClient;
@Test
public void defaultSnippetsAreWritten() throws Exception {
this.webTestClient.get().uri("/").exchange().expectStatus().is2xxSuccessful()
.expectBody().consumeWith(document("default-snippets"));
File defaultSnippetsDir = new File("target/generated-snippets/default-snippets");
File defaultSnippetsDir = new File(this.generatedSnippets, "default-snippets");
assertThat(defaultSnippetsDir).exists();
assertThat(new File(defaultSnippetsDir, "curl-request.md"))
.has(contentContaining("'https://api.example.com/'"));

@ -25,6 +25,7 @@ import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.autoconfigure.web.reactive.WebFluxTest;
import org.springframework.boot.testsupport.BuildOutput;
import org.springframework.security.test.context.support.WithMockUser;
import org.springframework.test.context.junit4.SpringRunner;
import org.springframework.test.web.reactive.server.WebTestClient;
@ -44,19 +45,23 @@ import static org.springframework.restdocs.webtestclient.WebTestClientRestDocume
@AutoConfigureRestDocs(uriScheme = "https", uriHost = "api.example.com", uriPort = 443)
public class WebTestClientRestDocsAutoConfigurationIntegrationTests {
@Autowired
private WebTestClient webTestClient;
private File generatedSnippets;
@Before
public void deleteSnippets() {
FileSystemUtils.deleteRecursively(new File("target/generated-snippets"));
this.generatedSnippets = new File(new BuildOutput(getClass()).getRootLocation(),
"generated-snippets");
FileSystemUtils.deleteRecursively(this.generatedSnippets);
}
@Autowired
private WebTestClient webTestClient;
@Test
public void defaultSnippetsAreWritten() throws Exception {
this.webTestClient.get().uri("/").exchange().expectStatus().is2xxSuccessful()
.expectBody().consumeWith(document("default-snippets"));
File defaultSnippetsDir = new File("target/generated-snippets/default-snippets");
File defaultSnippetsDir = new File(this.generatedSnippets, "default-snippets");
assertThat(defaultSnippetsDir).exists();
assertThat(new File(defaultSnippetsDir, "curl-request.adoc"))
.has(contentContaining("'https://api.example.com/'"));

@ -1,5 +1,5 @@
/*
* Copyright 2012-2017 the original author or authors.
* Copyright 2012-2018 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.
@ -46,9 +46,9 @@ public class FileUtilsTests {
private File originDirectory;
@Before
public void init() {
this.outputDirectory = new File("target/test/remove");
this.originDirectory = new File("target/test/keep");
public void init() throws IOException {
this.outputDirectory = this.temporaryFolder.newFolder("remove");
this.originDirectory = this.temporaryFolder.newFolder("keep");
FileSystemUtils.deleteRecursively(this.outputDirectory);
FileSystemUtils.deleteRecursively(this.originDirectory);
this.outputDirectory.mkdirs();

@ -0,0 +1,81 @@
/*
* Copyright 2012-2018 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;
import java.io.File;
import java.net.URISyntaxException;
/**
* Provides access to build output locations in a build system and IDE agnostic manner.
*
* @author Andy Wilkinson
*/
public class BuildOutput {
private final Class<?> testClass;
public BuildOutput(Class<?> testClass) {
this.testClass = testClass;
}
/**
* Returns the location into which test classes have been built.
* @return test classes location
*/
public File getTestClassesLocation() {
try {
File location = new File(this.testClass.getProtectionDomain().getCodeSource()
.getLocation().toURI());
if (location.getPath().endsWith(path("target", "test-classes"))) {
return location;
}
throw new IllegalStateException(
"Unexpected test classes location '" + location + "'");
}
catch (URISyntaxException ex) {
throw new IllegalStateException("Invalid test class code source location",
ex);
}
}
/**
* Returns the location into which test resources have been built.
* @return test resources location
*/
public File getTestResourcesLocation() {
File testClassesLocation = getTestClassesLocation();
if (testClassesLocation.getPath().endsWith(path("target", "test-classes"))) {
return testClassesLocation;
}
throw new IllegalStateException(
"Cannot determine test resources location from classes location '"
+ testClassesLocation + "'");
}
/**
* Returns the root location into which build output is written.
* @return root location
*/
public File getRootLocation() {
return getTestClassesLocation().getParentFile();
}
private String path(String... components) {
return File.separator + String.join(File.separator, components);
}
}

@ -1,5 +1,5 @@
/*
* Copyright 2012-2017 the original author or authors.
* Copyright 2012-2018 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.
@ -16,7 +16,6 @@
package org.springframework.boot.testsupport.context;
import java.io.File;
import java.io.IOException;
import java.util.HashSet;
import java.util.Set;
@ -25,6 +24,7 @@ import org.junit.Test;
import org.springframework.asm.Opcodes;
import org.springframework.beans.DirectFieldAccessor;
import org.springframework.boot.testsupport.BuildOutput;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.io.Resource;
@ -44,6 +44,8 @@ import static org.assertj.core.api.Assertions.assertThat;
*/
public abstract class AbstractConfigurationClassTests {
private final BuildOutput buildOutput = new BuildOutput(getClass());
private ResourcePatternResolver resolver = new PathMatchingResourcePatternResolver();
@Test
@ -83,7 +85,7 @@ public abstract class AbstractConfigurationClassTests {
private boolean isTestClass(Resource resource) throws IOException {
return resource.getFile().getAbsolutePath()
.contains("target" + File.separator + "test-classes");
.startsWith(this.buildOutput.getTestClassesLocation().getAbsolutePath());
}
private boolean isPublic(MethodMetadata methodMetadata) {

@ -43,6 +43,7 @@ import org.springframework.boot.WebApplicationType;
import org.springframework.boot.context.event.ApplicationEnvironmentPreparedEvent;
import org.springframework.boot.context.event.ApplicationPreparedEvent;
import org.springframework.boot.env.EnvironmentPostProcessor;
import org.springframework.boot.testsupport.BuildOutput;
import org.springframework.boot.testsupport.rule.OutputCapture;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
@ -73,6 +74,8 @@ import static org.assertj.core.api.Assertions.assertThat;
*/
public class ConfigFileApplicationListenerTests {
private final BuildOutput buildOutput = new BuildOutput(getClass());
private final StandardEnvironment environment = new StandardEnvironment();
private final SpringApplication application = new SpringApplication();
@ -486,8 +489,9 @@ public class ConfigFileApplicationListenerTests {
String suffix = (profile != null) ? "-" + profile : "";
String string = ".properties)";
return "Loaded config file '"
+ new File("target/test-classes/application" + suffix + ".properties")
.getAbsoluteFile().toURI().toString()
+ new File(this.buildOutput.getTestResourcesLocation(),
"application" + suffix + ".properties").getAbsoluteFile().toURI()
.toString()
+ "' (classpath:/application" + suffix + string;
}

@ -33,6 +33,7 @@ import org.junit.After;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.TemporaryFolder;
import org.junit.runner.RunWith;
import org.slf4j.bridge.SLF4JBridgeHandler;
import org.slf4j.impl.StaticLoggerBinder;
@ -88,6 +89,9 @@ public class LoggingApplicationListenerTests {
@Rule
public OutputCapture outputCapture = new OutputCapture();
@Rule
public final TemporaryFolder temp = new TemporaryFolder();
private final LoggingApplicationListener initializer = new LoggingApplicationListener();
private final LoggerContext loggerContext = (LoggerContext) StaticLoggerBinder
@ -100,12 +104,14 @@ public class LoggingApplicationListenerTests {
private final GenericApplicationContext context = new GenericApplicationContext();
private File logFile;
@Before
public void init() throws SecurityException, IOException {
LogManager.getLogManager().readConfiguration(
JavaLoggingSystem.class.getResourceAsStream("logging.properties"));
multicastEvent(new ApplicationStartingEvent(new SpringApplication(), NO_ARGS));
new File("target/foo.log").delete();
this.logFile = new File(this.temp.getRoot(), "foo.log");
new File(tmpDir() + "/spring.log").delete();
ConfigurableEnvironment environment = this.context.getEnvironment();
ConfigurationPropertySources.attach(environment);
@ -216,7 +222,7 @@ public class LoggingApplicationListenerTests {
public void addLogFileProperty() {
TestPropertySourceUtils.addInlinedPropertiesToEnvironment(this.context,
"logging.config=classpath:logback-nondefault.xml",
"logging.file.name=target/foo.log");
"logging.file.name=" + this.logFile);
this.initializer.initialize(this.context.getEnvironment(),
this.context.getClassLoader());
Log logger = LogFactory.getLog(LoggingApplicationListenerTests.class);
@ -224,7 +230,7 @@ public class LoggingApplicationListenerTests {
logger.info("Hello world");
String output = this.outputCapture.toString().substring(existingOutput.length())
.trim();
assertThat(output).startsWith("target/foo.log");
assertThat(output).startsWith(this.logFile.getAbsolutePath());
}
@Test
@ -232,7 +238,7 @@ public class LoggingApplicationListenerTests {
public void addLogFilePropertyWithDeprecatedProperty() {
TestPropertySourceUtils.addInlinedPropertiesToEnvironment(this.context,
"logging.config=classpath:logback-nondefault.xml",
"logging.file=target/foo.log");
"logging.file=" + this.logFile);
this.initializer.initialize(this.context.getEnvironment(),
this.context.getClassLoader());
Log logger = LogFactory.getLog(LoggingApplicationListenerTests.class);
@ -240,39 +246,39 @@ public class LoggingApplicationListenerTests {
logger.info("Hello world");
String output = this.outputCapture.toString().substring(existingOutput.length())
.trim();
assertThat(output).startsWith("target/foo.log");
assertThat(output).startsWith(this.logFile.getAbsolutePath());
}
@Test
public void addLogFilePropertyWithDefault() {
assertThat(new File("target/foo.log").exists()).isFalse();
assertThat(this.logFile).doesNotExist();
TestPropertySourceUtils.addInlinedPropertiesToEnvironment(this.context,
"logging.file.name=target/foo.log");
"logging.file.name=" + this.logFile);
this.initializer.initialize(this.context.getEnvironment(),
this.context.getClassLoader());
Log logger = LogFactory.getLog(LoggingApplicationListenerTests.class);
logger.info("Hello world");
assertThat(new File("target/foo.log").exists()).isTrue();
assertThat(this.logFile).isFile();
}
@Test
@Deprecated
public void addLogFilePropertyWithDefaultAndDeprecatedProperty() {
assertThat(new File("target/foo.log").exists()).isFalse();
assertThat(this.logFile).doesNotExist();
TestPropertySourceUtils.addInlinedPropertiesToEnvironment(this.context,
"logging.file=target/foo.log");
"logging.file=" + this.logFile);
this.initializer.initialize(this.context.getEnvironment(),
this.context.getClassLoader());
Log logger = LogFactory.getLog(LoggingApplicationListenerTests.class);
logger.info("Hello world");
assertThat(new File("target/foo.log").exists()).isTrue();
assertThat(this.logFile).isFile();
}
@Test
public void addLogPathProperty() {
TestPropertySourceUtils.addInlinedPropertiesToEnvironment(this.context,
"logging.config=classpath:logback-nondefault.xml",
"logging.file.path=target/foo/");
"logging.file.path=" + this.logFile);
this.initializer.initialize(this.context.getEnvironment(),
this.context.getClassLoader());
Log logger = LogFactory.getLog(LoggingApplicationListenerTests.class);
@ -280,14 +286,14 @@ public class LoggingApplicationListenerTests {
logger.info("Hello world");
String output = this.outputCapture.toString().substring(existingOutput.length())
.trim();
assertThat(output).startsWith("target/foo/spring.log");
assertThat(output).startsWith(this.logFile.getAbsolutePath());
}
@Test
public void addLogPathPropertyWithDeprecatedProperty() {
TestPropertySourceUtils.addInlinedPropertiesToEnvironment(this.context,
"logging.config=classpath:logback-nondefault.xml",
"logging.path=target/foo/");
"logging.path=" + this.temp.getRoot());
this.initializer.initialize(this.context.getEnvironment(),
this.context.getClassLoader());
Log logger = LogFactory.getLog(LoggingApplicationListenerTests.class);
@ -295,7 +301,8 @@ public class LoggingApplicationListenerTests {
logger.info("Hello world");
String output = this.outputCapture.toString().substring(existingOutput.length())
.trim();
assertThat(output).startsWith("target/foo/spring.log");
assertThat(output).startsWith(
new File(this.temp.getRoot(), "spring.log").getAbsolutePath());
}
@Test
@ -539,7 +546,7 @@ public class LoggingApplicationListenerTests {
public void systemPropertiesAreSetForLoggingConfiguration() {
TestPropertySourceUtils.addInlinedPropertiesToEnvironment(this.context,
"logging.exception-conversion-word=conversion",
"logging.file.name=target/log", "logging.file.path=path",
"logging.file.name=" + this.logFile, "logging.file.path=path",
"logging.pattern.console=console", "logging.pattern.file=file",
"logging.pattern.level=level");
this.initializer.initialize(this.context.getEnvironment(),
@ -551,7 +558,7 @@ public class LoggingApplicationListenerTests {
assertThat(System.getProperty(LoggingSystemProperties.EXCEPTION_CONVERSION_WORD))
.isEqualTo("conversion");
assertThat(System.getProperty(LoggingSystemProperties.LOG_FILE))
.isEqualTo("target/log");
.isEqualTo(this.logFile.getAbsolutePath());
assertThat(System.getProperty(LoggingSystemProperties.LOG_LEVEL_PATTERN))
.isEqualTo("level");
assertThat(System.getProperty(LoggingSystemProperties.LOG_PATH))
@ -563,11 +570,11 @@ public class LoggingApplicationListenerTests {
@Deprecated
public void systemPropertiesAreSetForLoggingConfigurationWithDeprecatedProperties() {
TestPropertySourceUtils.addInlinedPropertiesToEnvironment(this.context,
"logging.file=target/log", "logging.path=path");
"logging.file=" + this.logFile, "logging.path=path");
this.initializer.initialize(this.context.getEnvironment(),
this.context.getClassLoader());
assertThat(System.getProperty(LoggingSystemProperties.LOG_FILE))
.isEqualTo("target/log");
.isEqualTo(this.logFile.getAbsolutePath());
assertThat(System.getProperty(LoggingSystemProperties.LOG_PATH))
.isEqualTo("path");
}
@ -597,11 +604,13 @@ public class LoggingApplicationListenerTests {
@Test
public void logFilePropertiesCanReferenceSystemProperties() {
TestPropertySourceUtils.addInlinedPropertiesToEnvironment(this.context,
"logging.file.name=target/${PID}.log");
"logging.file.name=" + this.temp.getRoot().getAbsolutePath()
+ "${PID}.log");
this.initializer.initialize(this.context.getEnvironment(),
this.context.getClassLoader());
assertThat(System.getProperty(LoggingSystemProperties.LOG_FILE))
.isEqualTo("target/" + new ApplicationPid().toString() + ".log");
.isEqualTo(this.temp.getRoot().getAbsolutePath()
+ new ApplicationPid().toString() + ".log");
}
@Test

@ -1,5 +1,5 @@
/*
* Copyright 2012-2016 the original author or authors.
* Copyright 2012-2018 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.
@ -16,21 +16,22 @@
package sample.integration;
import org.springframework.boot.CommandLineRunner;
import org.springframework.boot.ApplicationArguments;
import org.springframework.boot.ApplicationRunner;
import org.springframework.stereotype.Component;
@Component
public class SampleCommandLineRunner implements CommandLineRunner {
public class SampleApplicationRunner implements ApplicationRunner {
private final SampleMessageGateway gateway;
public SampleCommandLineRunner(SampleMessageGateway gateway) {
public SampleApplicationRunner(SampleMessageGateway gateway) {
this.gateway = gateway;
}
@Override
public void run(String... args) throws Exception {
for (String arg : args) {
public void run(ApplicationArguments args) throws Exception {
for (String arg : args.getNonOptionArgs()) {
this.gateway.echo(arg);
}
}

@ -16,7 +16,6 @@
package sample.integration;
import java.io.File;
import java.util.function.Consumer;
import org.springframework.boot.SpringApplication;
@ -35,10 +34,16 @@ import org.springframework.integration.file.FileWritingMessageHandler;
@EnableConfigurationProperties(ServiceProperties.class)
public class SampleIntegrationApplication {
private final ServiceProperties serviceProperties;
public SampleIntegrationApplication(ServiceProperties serviceProperties) {
this.serviceProperties = serviceProperties;
}
@Bean
public FileReadingMessageSource fileReader() {
FileReadingMessageSource reader = new FileReadingMessageSource();
reader.setDirectory(new File("target/input"));
reader.setDirectory(this.serviceProperties.getInputDir());
return reader;
}
@ -55,7 +60,7 @@ public class SampleIntegrationApplication {
@Bean
public FileWritingMessageHandler fileWriter() {
FileWritingMessageHandler writer = new FileWritingMessageHandler(
new File("target/output"));
this.serviceProperties.getOutputDir());
writer.setExpectReply(false);
return writer;
}

@ -1,5 +1,5 @@
/*
* Copyright 2012-2014 the original author or authors.
* Copyright 2012-2018 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.
@ -16,6 +16,8 @@
package sample.integration;
import java.io.File;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.jmx.export.annotation.ManagedAttribute;
import org.springframework.jmx.export.annotation.ManagedResource;
@ -26,6 +28,10 @@ public class ServiceProperties {
private String greeting = "Hello";
private File inputDir;
private File outputDir;
@ManagedAttribute
public String getGreeting() {
return this.greeting;
@ -35,4 +41,20 @@ public class ServiceProperties {
this.greeting = greeting;
}
public File getInputDir() {
return this.inputDir;
}
public void setInputDir(File inputDir) {
this.inputDir = inputDir;
}
public File getOutputDir() {
return this.outputDir;
}
public void setOutputDir(File outputDir) {
this.outputDir = outputDir;
}
}

@ -1,2 +1,4 @@
logging.level.org.springframework.integration.file=DEBUG
service.greeting=Hello
service.input-dir=input
service.output-dir=output

@ -25,9 +25,11 @@ import java.util.concurrent.Future;
import java.util.concurrent.TimeUnit;
import org.junit.After;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.TemporaryFolder;
import sample.integration.SampleIntegrationApplication;
import sample.integration.ServiceProperties;
import sample.integration.producer.ProducerApplication;
import org.springframework.boot.SpringApplication;
@ -35,7 +37,6 @@ import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.core.io.DefaultResourceLoader;
import org.springframework.core.io.Resource;
import org.springframework.core.io.support.ResourcePatternUtils;
import org.springframework.util.FileSystemUtils;
import org.springframework.util.StreamUtils;
import static org.assertj.core.api.Assertions.assertThat;
@ -48,19 +49,10 @@ import static org.assertj.core.api.Assertions.assertThat;
*/
public class SampleIntegrationApplicationTests {
private ConfigurableApplicationContext context;
@Before
public void deleteInputAndOutput() {
deleteIfExists(new File("target/input"));
deleteIfExists(new File("target/output"));
}
@Rule
public final TemporaryFolder temp = new TemporaryFolder();
private void deleteIfExists(File directory) {
if (directory.exists()) {
assertThat(FileSystemUtils.deleteRecursively(directory)).isTrue();
}
}
private ConfigurableApplicationContext context;
@After
public void stop() {
@ -71,29 +63,37 @@ public class SampleIntegrationApplicationTests {
@Test
public void testVanillaExchange() throws Exception {
this.context = SpringApplication.run(SampleIntegrationApplication.class);
SpringApplication.run(ProducerApplication.class, "World");
String output = getOutput();
File inputDir = new File(this.temp.getRoot(), "input");
File outputDir = new File(this.temp.getRoot(), "output");
this.context = SpringApplication.run(SampleIntegrationApplication.class,
"--service.input-dir=" + inputDir, "--service.output-dir=" + outputDir);
SpringApplication.run(ProducerApplication.class, "World",
"--service.input-dir=" + inputDir, "--service.output-dir=" + outputDir);
String output = getOutput(outputDir);
assertThat(output).contains("Hello World");
}
@Test
public void testMessageGateway() throws Exception {
File inputDir = new File(this.temp.getRoot(), "input");
File outputDir = new File(this.temp.getRoot(), "output");
this.context = SpringApplication.run(SampleIntegrationApplication.class,
"testviamg");
String output = getOutput();
"testviamg", "--service.input-dir=" + inputDir,
"--service.output-dir=" + outputDir);
String output = getOutput(
this.context.getBean(ServiceProperties.class).getOutputDir());
assertThat(output).contains("testviamg");
}
private String getOutput() throws Exception {
private String getOutput(File outputDir) throws Exception {
Future<String> future = Executors.newSingleThreadExecutor()
.submit(new Callable<String>() {
@Override
public String call() throws Exception {
Resource[] resources = getResourcesWithContent();
Resource[] resources = getResourcesWithContent(outputDir);
while (resources.length == 0) {
Thread.sleep(200);
resources = getResourcesWithContent();
resources = getResourcesWithContent(outputDir);
}
StringBuilder builder = new StringBuilder();
for (Resource resource : resources) {
@ -108,10 +108,10 @@ public class SampleIntegrationApplicationTests {
return future.get(30, TimeUnit.SECONDS);
}
private Resource[] getResourcesWithContent() throws IOException {
private Resource[] getResourcesWithContent(File outputDir) throws IOException {
Resource[] candidates = ResourcePatternUtils
.getResourcePatternResolver(new DefaultResourceLoader())
.getResources("file:target/output/**");
.getResources("file:" + outputDir.getAbsolutePath() + "/**");
for (Resource candidate : candidates) {
if ((candidate.getFilename() != null
&& candidate.getFilename().endsWith(".writing"))

@ -19,20 +19,32 @@ package sample.integration.producer;
import java.io.File;
import java.io.FileOutputStream;
import org.springframework.boot.CommandLineRunner;
import sample.integration.ServiceProperties;
import org.springframework.boot.ApplicationArguments;
import org.springframework.boot.ApplicationRunner;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Configuration;
@Configuration
public class ProducerApplication implements CommandLineRunner {
@EnableConfigurationProperties(ServiceProperties.class)
public class ProducerApplication implements ApplicationRunner {
private final ServiceProperties serviceProperties;
public ProducerApplication(ServiceProperties serviceProperties) {
this.serviceProperties = serviceProperties;
}
@Override
public void run(String... args) throws Exception {
new File("target/input").mkdirs();
if (args.length > 0) {
public void run(ApplicationArguments args) throws Exception {
this.serviceProperties.getInputDir().mkdirs();
if (args.getNonOptionArgs().size() > 0) {
FileOutputStream stream = new FileOutputStream(
"target/input/data" + System.currentTimeMillis() + ".txt");
for (String arg : args) {
new File(this.serviceProperties.getInputDir(),
"data" + System.currentTimeMillis() + ".txt"));
for (String arg : args.getNonOptionArgs()) {
stream.write(arg.getBytes());
}
stream.flush();

@ -16,7 +16,6 @@
package sample.parent;
import java.io.File;
import java.util.function.Consumer;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
@ -33,7 +32,6 @@ import org.springframework.integration.file.FileReadingMessageSource;
import org.springframework.integration.file.FileWritingMessageHandler;
@SpringBootApplication
@EnableConfigurationProperties(ServiceProperties.class)
public class SampleParentContextApplication {
public static void main(String[] args) throws Exception {
@ -42,12 +40,19 @@ public class SampleParentContextApplication {
}
@EnableAutoConfiguration
@EnableConfigurationProperties(ServiceProperties.class)
protected static class Parent {
private final ServiceProperties serviceProperties;
public Parent(ServiceProperties serviceProperties) {
this.serviceProperties = serviceProperties;
}
@Bean
public FileReadingMessageSource fileReader() {
FileReadingMessageSource reader = new FileReadingMessageSource();
reader.setDirectory(new File("target/input"));
reader.setDirectory(this.serviceProperties.getInputDir());
return reader;
}
@ -64,7 +69,7 @@ public class SampleParentContextApplication {
@Bean
public FileWritingMessageHandler fileWriter() {
FileWritingMessageHandler writer = new FileWritingMessageHandler(
new File("target/output"));
this.serviceProperties.getOutputDir());
writer.setExpectReply(false);
return writer;
}

@ -1,5 +1,5 @@
/*
* Copyright 2012-2014 the original author or authors.
* Copyright 2012-2018 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.
@ -16,6 +16,8 @@
package sample.parent;
import java.io.File;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.jmx.export.annotation.ManagedAttribute;
import org.springframework.jmx.export.annotation.ManagedResource;
@ -26,6 +28,10 @@ public class ServiceProperties {
private String greeting = "Hello";
private File inputDir;
private File outputDir;
@ManagedAttribute
public String getGreeting() {
return this.greeting;
@ -35,4 +41,20 @@ public class ServiceProperties {
this.greeting = greeting;
}
public File getInputDir() {
return this.inputDir;
}
public void setInputDir(File inputDir) {
this.inputDir = inputDir;
}
public File getOutputDir() {
return this.outputDir;
}
public void setOutputDir(File outputDir) {
this.outputDir = outputDir;
}
}

@ -1 +1,3 @@
service.greeting=Hello
service.input-dir=input
service.output-dir=output

@ -16,11 +16,12 @@
package sample.parent.consumer;
import java.io.File;
import java.io.IOException;
import org.junit.AfterClass;
import org.junit.BeforeClass;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.TemporaryFolder;
import sample.parent.SampleParentContextApplication;
import sample.parent.producer.ProducerApplication;
@ -41,34 +42,41 @@ import static org.junit.Assert.fail;
*/
public class SampleIntegrationParentApplicationTests {
private static ConfigurableApplicationContext context;
@BeforeClass
public static void start() {
context = SpringApplication.run(SampleParentContextApplication.class);
}
@AfterClass
public static void stop() {
if (context != null) {
context.close();
}
}
@Rule
public final TemporaryFolder temp = new TemporaryFolder();
@Test
public void testVanillaExchange() throws Exception {
SpringApplication.run(ProducerApplication.class, "World");
awaitOutputContaining("Hello World");
File inputDir = new File(this.temp.getRoot(), "input");
File outputDir = new File(this.temp.getRoot(), "output");
ConfigurableApplicationContext app = SpringApplication.run(
SampleParentContextApplication.class, "--service.input-dir=" + inputDir,
"--service.output-dir=" + outputDir);
try {
ConfigurableApplicationContext producer = SpringApplication.run(
ProducerApplication.class, "--service.input-dir=" + inputDir,
"--service.output-dir=" + outputDir, "World");
try {
awaitOutputContaining(outputDir, "Hello World");
}
finally {
producer.close();
}
}
finally {
app.close();
}
}
private void awaitOutputContaining(String requiredContents) throws Exception {
private void awaitOutputContaining(File outputDir, String requiredContents)
throws Exception {
long endTime = System.currentTimeMillis() + 30000;
String output = null;
while (System.currentTimeMillis() < endTime) {
Resource[] resources = findResources();
Resource[] resources = findResources(outputDir);
if (resources.length == 0) {
Thread.sleep(200);
resources = findResources();
resources = findResources(outputDir);
}
else {
output = readResources(resources);
@ -85,10 +93,10 @@ public class SampleIntegrationParentApplicationTests {
+ "'. Output was '" + output + "'");
}
private Resource[] findResources() throws IOException {
private Resource[] findResources(File outputDir) throws IOException {
return ResourcePatternUtils
.getResourcePatternResolver(new DefaultResourceLoader())
.getResources("file:target/output/*.txt");
.getResources("file:" + outputDir.getAbsolutePath() + "/*.txt");
}
private String readResources(Resource[] resources) throws IOException {

@ -19,20 +19,32 @@ package sample.parent.producer;
import java.io.File;
import java.io.FileOutputStream;
import org.springframework.boot.CommandLineRunner;
import sample.parent.ServiceProperties;
import org.springframework.boot.ApplicationArguments;
import org.springframework.boot.ApplicationRunner;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Configuration;
@Configuration
public class ProducerApplication implements CommandLineRunner {
@EnableConfigurationProperties(ServiceProperties.class)
public class ProducerApplication implements ApplicationRunner {
private final ServiceProperties serviceProperties;
public ProducerApplication(ServiceProperties serviceProperties) {
this.serviceProperties = serviceProperties;
}
@Override
public void run(String... args) throws Exception {
new File("target/input").mkdirs();
if (args.length > 0) {
public void run(ApplicationArguments args) throws Exception {
this.serviceProperties.getInputDir().mkdirs();
if (args.getNonOptionArgs().size() > 0) {
FileOutputStream stream = new FileOutputStream(
"target/input/data" + System.currentTimeMillis() + ".txt");
for (String arg : args) {
new File(this.serviceProperties.getInputDir(),
"data" + System.currentTimeMillis() + ".txt"));
for (String arg : args.getNonOptionArgs()) {
stream.write(arg.getBytes());
}
stream.flush();

@ -26,6 +26,11 @@
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-test-support</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>net.bytebuddy</groupId>
<artifactId>byte-buddy</artifactId>

@ -25,7 +25,7 @@ public class DevToolsTestApplication {
public static void main(String[] args) {
new SpringApplicationBuilder(DevToolsTestApplication.class)
.listeners(new WebServerPortFileWriter("target/server.port")).run(args);
.listeners(new WebServerPortFileWriter(args[0])).run(args);
}
}

@ -0,0 +1,57 @@
/*
* Copyright 2012-2018 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.devtools.tests;
import java.io.File;
import java.io.IOException;
import java.util.List;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import org.springframework.util.FileSystemUtils;
/**
* Base class for all {@link ApplicationLauncher} implementations.
*
* @author Andy Wilkinson
*/
abstract class AbstractApplicationLauncher implements ApplicationLauncher {
private final Directories directories;
AbstractApplicationLauncher(Directories directories) {
this.directories = directories;
}
protected final void copyApplicationTo(File location) throws IOException {
FileSystemUtils.deleteRecursively(location);
location.mkdirs();
FileSystemUtils.copyRecursively(
new File(this.directories.getTestClassesDirectory(), "com"),
new File(location, "com"));
}
protected final List<String> getDependencyJarPaths() {
return Stream.of(this.directories.getDependenciesDirectory().listFiles())
.map(File::getAbsolutePath).collect(Collectors.toList());
}
protected final Directories getDirectories() {
return this.directories;
}
}

@ -1,5 +1,5 @@
/*
* Copyright 2012-2017 the original author or authors.
* Copyright 2012-2018 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.
@ -16,6 +16,8 @@
package org.springframework.boot.devtools.tests;
import java.io.File;
/**
* Launches an application with DevTools.
*
@ -23,6 +25,7 @@ package org.springframework.boot.devtools.tests;
*/
public interface ApplicationLauncher {
LaunchedApplication launchApplication(JvmLauncher javaLauncher) throws Exception;
LaunchedApplication launchApplication(JvmLauncher javaLauncher, File serverPortFile)
throws Exception;
}

@ -18,6 +18,8 @@ package org.springframework.boot.devtools.tests;
import java.io.File;
import java.io.FileReader;
import java.io.IOException;
import java.time.Duration;
import java.util.ArrayList;
import java.util.List;
@ -28,13 +30,16 @@ import net.bytebuddy.dynamic.DynamicType.Builder;
import net.bytebuddy.implementation.FixedValue;
import org.junit.After;
import org.junit.Before;
import org.junit.ClassRule;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.TemporaryFolder;
import org.junit.runner.RunWith;
import org.junit.runners.Parameterized;
import org.junit.runners.Parameterized.Parameters;
import org.springframework.boot.test.web.client.TestRestTemplate;
import org.springframework.boot.testsupport.BuildOutput;
import org.springframework.http.HttpStatus;
import org.springframework.util.FileCopyUtils;
import org.springframework.web.bind.annotation.RequestMapping;
@ -50,9 +55,15 @@ import static org.assertj.core.api.Assertions.assertThat;
@RunWith(Parameterized.class)
public class DevToolsIntegrationTests {
@ClassRule
public static final TemporaryFolder temp = new TemporaryFolder();
private static final BuildOutput buildOutput = new BuildOutput(
DevToolsIntegrationTests.class);
private LaunchedApplication launchedApplication;
private final File serverPortFile = new File("target/server.port");
private final File serverPortFile;
private final ApplicationLauncher applicationLauncher;
@ -61,14 +72,15 @@ public class DevToolsIntegrationTests {
public DevToolsIntegrationTests(ApplicationLauncher applicationLauncher) {
this.applicationLauncher = applicationLauncher;
this.serverPortFile = new File(
DevToolsIntegrationTests.buildOutput.getRootLocation(), "server.port");
}
@Before
public void launchApplication() throws Exception {
this.serverPortFile.delete();
System.out.println("Launching " + this.javaLauncher.getClass());
this.launchedApplication = this.applicationLauncher
.launchApplication(this.javaLauncher);
.launchApplication(this.javaLauncher, this.serverPortFile);
}
@After
@ -205,13 +217,15 @@ public class DevToolsIntegrationTests {
}
private int awaitServerPort() throws Exception {
long end = System.currentTimeMillis() + 40000;
Duration timeToWait = Duration.ofSeconds(40);
long end = System.currentTimeMillis() + timeToWait.toMillis();
System.out.println("Reading server port from '" + this.serverPortFile + "'");
while (this.serverPortFile.length() == 0) {
System.out.println("Getting server port " + this.serverPortFile.length());
if (System.currentTimeMillis() > end) {
throw new IllegalStateException(String.format(
"server.port file was not written within 30 seconds. "
+ "Application output:%n%s%s",
"server.port file '" + this.serverPortFile
+ "' was not written within " + timeToWait.toMillis()
+ "ms. " + "Application output:%n%s%s",
FileCopyUtils.copyToString(new FileReader(
this.launchedApplication.getStandardOut())),
FileCopyUtils.copyToString(new FileReader(
@ -234,10 +248,11 @@ public class DevToolsIntegrationTests {
}
@Parameters(name = "{0}")
public static Object[] parameters() {
return new Object[] { new Object[] { new LocalApplicationLauncher() },
new Object[] { new ExplodedRemoteApplicationLauncher() },
new Object[] { new JarFileRemoteApplicationLauncher() } };
public static Object[] parameters() throws IOException {
Directories directories = new Directories(buildOutput, temp);
return new Object[] { new Object[] { new LocalApplicationLauncher(directories) },
new Object[] { new ExplodedRemoteApplicationLauncher(directories) },
new Object[] { new JarFileRemoteApplicationLauncher(directories) } };
}
private static final class ControllerBuilder {

@ -0,0 +1,57 @@
/*
* Copyright 2012-2018 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.devtools.tests;
import java.io.File;
import org.junit.rules.TemporaryFolder;
import org.springframework.boot.testsupport.BuildOutput;
/**
* Various directories used by the {@link ApplicationLauncher ApplicationLaunchers}.
*
* @author Andy Wilkinson
*/
class Directories {
private final BuildOutput buildOutput;
private final TemporaryFolder temp;
Directories(BuildOutput buildOutput, TemporaryFolder temp) {
this.buildOutput = buildOutput;
this.temp = temp;
}
File getTestClassesDirectory() {
return this.buildOutput.getTestClassesLocation();
}
File getRemoteAppDirectory() {
return new File(this.temp.getRoot(), "remote");
}
File getDependenciesDirectory() {
return new File(this.buildOutput.getRootLocation(), "dependencies");
}
File getAppDirectory() {
return new File(this.temp.getRoot(), "app");
}
}

@ -1,5 +1,5 @@
/*
* Copyright 2012-2017 the original author or authors.
* Copyright 2012-2018 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.
@ -20,7 +20,6 @@ import java.io.File;
import java.util.ArrayList;
import java.util.List;
import org.springframework.util.FileSystemUtils;
import org.springframework.util.StringUtils;
/**
@ -31,18 +30,17 @@ import org.springframework.util.StringUtils;
*/
public class ExplodedRemoteApplicationLauncher extends RemoteApplicationLauncher {
public ExplodedRemoteApplicationLauncher(Directories directories) {
super(directories);
}
@Override
protected String createApplicationClassPath() throws Exception {
File appDirectory = new File("target/app");
FileSystemUtils.deleteRecursively(appDirectory);
appDirectory.mkdirs();
FileSystemUtils.copyRecursively(new File("target/test-classes/com"),
new File("target/app/com"));
File appDirectory = getDirectories().getAppDirectory();
copyApplicationTo(appDirectory);
List<String> entries = new ArrayList<>();
entries.add("target/app");
for (File jar : new File("target/dependencies").listFiles()) {
entries.add(jar.getAbsolutePath());
}
entries.add(appDirectory.getAbsolutePath());
entries.addAll(getDependencyJarPaths());
return StringUtils.collectionToDelimitedString(entries, File.pathSeparator);
}

@ -1,5 +1,5 @@
/*
* Copyright 2012-2017 the original author or authors.
* Copyright 2012-2018 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.
@ -27,7 +27,6 @@ import java.util.jar.JarOutputStream;
import java.util.jar.Manifest;
import java.util.zip.ZipEntry;
import org.springframework.util.FileSystemUtils;
import org.springframework.util.StreamUtils;
import org.springframework.util.StringUtils;
@ -39,28 +38,24 @@ import org.springframework.util.StringUtils;
*/
public class JarFileRemoteApplicationLauncher extends RemoteApplicationLauncher {
public JarFileRemoteApplicationLauncher(Directories directories) {
super(directories);
}
@Override
protected String createApplicationClassPath() throws Exception {
File appDirectory = new File("target/app");
if (appDirectory.isDirectory()
&& !FileSystemUtils.deleteRecursively(appDirectory.toPath())) {
throw new IllegalStateException(
"Failed to delete '" + appDirectory.getAbsolutePath() + "'");
}
appDirectory.mkdirs();
File appDirectory = getDirectories().getAppDirectory();
copyApplicationTo(appDirectory);
Manifest manifest = new Manifest();
manifest.getMainAttributes().put(Attributes.Name.MANIFEST_VERSION, "1.0");
JarOutputStream output = new JarOutputStream(
new FileOutputStream(new File(appDirectory, "app.jar")), manifest);
FileSystemUtils.copyRecursively(new File("target/test-classes/com"),
new File("target/app/com"));
addToJar(output, new File("target/app/"), new File("target/app/"));
File appJar = new File(appDirectory, "app.jar");
JarOutputStream output = new JarOutputStream(new FileOutputStream(appJar),
manifest);
addToJar(output, appDirectory, appDirectory);
output.close();
List<String> entries = new ArrayList<>();
entries.add("target/app/app.jar");
for (File jar : new File("target/dependencies").listFiles()) {
entries.add(jar.getAbsolutePath());
}
entries.add(appJar.getAbsolutePath());
entries.addAll(getDependencyJarPaths());
String classpath = StringUtils.collectionToDelimitedString(entries,
File.pathSeparator);
return classpath;

@ -27,6 +27,7 @@ import org.junit.rules.TestRule;
import org.junit.runner.Description;
import org.junit.runners.model.Statement;
import org.springframework.boot.testsupport.BuildOutput;
import org.springframework.util.StringUtils;
/**
@ -39,12 +40,15 @@ class JvmLauncher implements TestRule {
private static final Pattern NON_ALPHABET_PATTERN = Pattern.compile("[^A-Za-z]+");
private final BuildOutput buildOutput = new BuildOutput(getClass());
private File outputDirectory;
@Override
public Statement apply(Statement base, Description description) {
this.outputDirectory = new File("target/output/" + NON_ALPHABET_PATTERN
.matcher(description.getMethodName()).replaceAll(""));
this.outputDirectory = new File(this.buildOutput.getRootLocation(),
"output/" + NON_ALPHABET_PATTERN.matcher(description.getMethodName())
.replaceAll(""));
this.outputDirectory.mkdirs();
return base;
}

@ -21,7 +21,6 @@ import java.util.ArrayList;
import java.util.List;
import org.springframework.boot.devtools.tests.JvmLauncher.LaunchedJvm;
import org.springframework.util.FileSystemUtils;
import org.springframework.util.StringUtils;
/**
@ -29,28 +28,29 @@ import org.springframework.util.StringUtils;
*
* @author Andy Wilkinson
*/
public class LocalApplicationLauncher implements ApplicationLauncher {
public class LocalApplicationLauncher extends AbstractApplicationLauncher {
LocalApplicationLauncher(Directories directories) {
super(directories);
}
@Override
public LaunchedApplication launchApplication(JvmLauncher jvmLauncher)
throws Exception {
public LaunchedApplication launchApplication(JvmLauncher jvmLauncher,
File serverPortFile) throws Exception {
LaunchedJvm jvm = jvmLauncher.launch("local", createApplicationClassPath(),
"com.example.DevToolsTestApplication", "--server.port=0");
return new LaunchedApplication(new File("target/app"), jvm.getStandardOut(),
jvm.getStandardError(), jvm.getProcess(), null, null);
"com.example.DevToolsTestApplication", serverPortFile.getAbsolutePath(),
"--server.port=0");
return new LaunchedApplication(getDirectories().getAppDirectory(),
jvm.getStandardOut(), jvm.getStandardError(), jvm.getProcess(), null,
null);
}
protected String createApplicationClassPath() throws Exception {
File appDirectory = new File("target/app");
FileSystemUtils.deleteRecursively(appDirectory);
appDirectory.mkdirs();
FileSystemUtils.copyRecursively(new File("target/test-classes/com"),
new File("target/app/com"));
File appDirectory = getDirectories().getAppDirectory();
copyApplicationTo(appDirectory);
List<String> entries = new ArrayList<>();
entries.add("target/app");
for (File jar : new File("target/dependencies").listFiles()) {
entries.add(jar.getAbsolutePath());
}
entries.add(appDirectory.getAbsolutePath());
entries.addAll(getDependencyJarPaths());
return StringUtils.collectionToDelimitedString(entries, File.pathSeparator);
}

@ -25,7 +25,6 @@ import java.util.function.BiFunction;
import org.springframework.boot.devtools.RemoteSpringApplication;
import org.springframework.boot.devtools.tests.JvmLauncher.LaunchedJvm;
import org.springframework.util.FileCopyUtils;
import org.springframework.util.FileSystemUtils;
import org.springframework.util.StringUtils;
/**
@ -34,18 +33,23 @@ import org.springframework.util.StringUtils;
*
* @author Andy Wilkinson
*/
abstract class RemoteApplicationLauncher implements ApplicationLauncher {
abstract class RemoteApplicationLauncher extends AbstractApplicationLauncher {
RemoteApplicationLauncher(Directories directories) {
super(directories);
}
@Override
public LaunchedApplication launchApplication(JvmLauncher javaLauncher)
throws Exception {
public LaunchedApplication launchApplication(JvmLauncher javaLauncher,
File serverPortFile) throws Exception {
LaunchedJvm applicationJvm = javaLauncher.launch("app",
createApplicationClassPath(), "com.example.DevToolsTestApplication",
"--server.port=0", "--spring.devtools.remote.secret=secret");
int port = awaitServerPort(applicationJvm.getStandardOut());
serverPortFile.getAbsolutePath(), "--server.port=0",
"--spring.devtools.remote.secret=secret");
int port = awaitServerPort(applicationJvm.getStandardOut(), serverPortFile);
BiFunction<Integer, File, Process> remoteRestarter = getRemoteRestarter(
javaLauncher);
return new LaunchedApplication(new File("target/remote"),
return new LaunchedApplication(getDirectories().getRemoteAppDirectory(),
applicationJvm.getStandardOut(), applicationJvm.getStandardError(),
applicationJvm.getProcess(), remoteRestarter.apply(port, null),
remoteRestarter);
@ -74,24 +78,18 @@ abstract class RemoteApplicationLauncher implements ApplicationLauncher {
private String createRemoteSpringApplicationClassPath(File classesDirectory)
throws Exception {
File remoteAppDirectory = getDirectories().getRemoteAppDirectory();
if (classesDirectory == null) {
File remoteDirectory = new File("target/remote");
FileSystemUtils.deleteRecursively(remoteDirectory);
remoteDirectory.mkdirs();
FileSystemUtils.copyRecursively(new File("target/test-classes/com"),
new File("target/remote/com"));
copyApplicationTo(remoteAppDirectory);
}
List<String> entries = new ArrayList<>();
entries.add("target/remote");
for (File jar : new File("target/dependencies").listFiles()) {
entries.add(jar.getAbsolutePath());
}
entries.add(remoteAppDirectory.getAbsolutePath());
entries.addAll(getDependencyJarPaths());
return StringUtils.collectionToDelimitedString(entries, File.pathSeparator);
}
private int awaitServerPort(File standardOut) throws Exception {
private int awaitServerPort(File standardOut, File serverPortFile) throws Exception {
long end = System.currentTimeMillis() + 30000;
File serverPortFile = new File("target/server.port");
while (serverPortFile.length() == 0) {
if (System.currentTimeMillis() > end) {
throw new IllegalStateException(String.format(

@ -24,6 +24,11 @@
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-test-support</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>com.samskivert</groupId>
<artifactId>jmustache</artifactId>

@ -41,7 +41,7 @@ public class ResourceHandlingApplication {
public static void main(String[] args) {
new SpringApplicationBuilder(ResourceHandlingApplication.class)
.properties("server.port:0")
.listeners(new WebServerPortFileWriter("target/server.port")).run(args);
.listeners(new WebServerPortFileWriter(args[0])).run(args);
}
@Bean

@ -26,6 +26,7 @@ import java.util.List;
import org.junit.rules.ExternalResource;
import org.springframework.boot.testsupport.BuildOutput;
import org.springframework.util.FileCopyUtils;
import org.springframework.util.StreamUtils;
import org.springframework.util.StringUtils;
@ -40,12 +41,16 @@ abstract class AbstractApplicationLauncher extends ExternalResource {
private final ApplicationBuilder applicationBuilder;
private final BuildOutput buildOutput;
private Process process;
private int httpPort;
protected AbstractApplicationLauncher(ApplicationBuilder applicationBuilder) {
protected AbstractApplicationLauncher(ApplicationBuilder applicationBuilder,
BuildOutput buildOutput) {
this.applicationBuilder = applicationBuilder;
this.buildOutput = buildOutput;
}
@Override
@ -62,7 +67,7 @@ abstract class AbstractApplicationLauncher extends ExternalResource {
return this.httpPort;
}
protected abstract List<String> getArguments(File archive);
protected abstract List<String> getArguments(File archive, File serverPortFile);
protected abstract File getWorkingDirectory();
@ -70,14 +75,12 @@ abstract class AbstractApplicationLauncher extends ExternalResource {
private Process startApplication() throws Exception {
File workingDirectory = getWorkingDirectory();
File serverPortFile = (workingDirectory != null)
? new File(workingDirectory, "target/server.port")
: new File("target/server.port");
File serverPortFile = new File(this.buildOutput.getRootLocation(), "server.port");
serverPortFile.delete();
File archive = this.applicationBuilder.buildApplication();
List<String> arguments = new ArrayList<>();
arguments.add(System.getProperty("java.home") + "/bin/java");
arguments.addAll(getArguments(archive));
arguments.addAll(getArguments(archive, serverPortFile));
ProcessBuilder processBuilder = new ProcessBuilder(
StringUtils.toStringArray(arguments));
if (workingDirectory != null) {

@ -26,6 +26,7 @@ import org.junit.ClassRule;
import org.junit.Rule;
import org.junit.rules.TemporaryFolder;
import org.springframework.boot.testsupport.BuildOutput;
import org.springframework.http.client.ClientHttpResponse;
import org.springframework.util.StringUtils;
import org.springframework.web.client.ResponseErrorHandler;
@ -48,6 +49,9 @@ public abstract class AbstractEmbeddedServletContainerIntegrationTests {
};
public static final BuildOutput buildOutput = new BuildOutput(
AbstractEmbeddedServletContainerIntegrationTests.class);
@Rule
public final AbstractApplicationLauncher launcher;
@ -70,8 +74,9 @@ public abstract class AbstractEmbeddedServletContainerIntegrationTests {
for (Class<? extends AbstractApplicationLauncher> launcherClass : applicationLaunchers) {
try {
AbstractApplicationLauncher launcher = launcherClass
.getDeclaredConstructor(ApplicationBuilder.class)
.newInstance(applicationBuilder);
.getDeclaredConstructor(ApplicationBuilder.class,
BuildOutput.class)
.newInstance(applicationBuilder, buildOutput);
String name = StringUtils.capitalize(container) + ": "
+ launcher.getDescription(packaging);
parameters.add(new Object[] { name, launcher });

@ -1,5 +1,5 @@
/*
* Copyright 2012-2017 the original author or authors.
* Copyright 2012-2018 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.
@ -27,6 +27,7 @@ import java.util.List;
import java.util.jar.JarEntry;
import java.util.jar.JarFile;
import org.springframework.boot.testsupport.BuildOutput;
import org.springframework.util.FileCopyUtils;
import org.springframework.util.FileSystemUtils;
import org.springframework.util.StreamUtils;
@ -40,14 +41,16 @@ import org.springframework.util.StringUtils;
*/
class BootRunApplicationLauncher extends AbstractApplicationLauncher {
private final File exploded = new File("target/run");
private final File exploded;
BootRunApplicationLauncher(ApplicationBuilder applicationBuilder) {
super(applicationBuilder);
BootRunApplicationLauncher(ApplicationBuilder applicationBuilder,
BuildOutput buildOutput) {
super(applicationBuilder, buildOutput);
this.exploded = new File(buildOutput.getRootLocation(), "run");
}
@Override
protected List<String> getArguments(File archive) {
protected List<String> getArguments(File archive, File serverPortFile) {
try {
explodeArchive(archive);
deleteLauncherClasses();
@ -64,7 +67,8 @@ class BootRunApplicationLauncher extends AbstractApplicationLauncher {
return Arrays.asList("-cp",
StringUtils.collectionToDelimitedString(classpath,
File.pathSeparator),
"com.example.ResourceHandlingApplication");
"com.example.ResourceHandlingApplication",
serverPortFile.getAbsolutePath());
}
catch (IOException ex) {
throw new RuntimeException(ex);
@ -76,12 +80,12 @@ class BootRunApplicationLauncher extends AbstractApplicationLauncher {
}
private File populateTargetClasses(File archive) throws IOException {
File targetClasses = new File(this.exploded, "target/classes");
targetClasses.mkdirs();
File builtClasses = new File(this.exploded, "built/classes");
builtClasses.mkdirs();
File source = new File(this.exploded, getClassesPath(archive));
FileSystemUtils.copyRecursively(source, targetClasses);
FileSystemUtils.copyRecursively(source, builtClasses);
FileSystemUtils.deleteRecursively(source);
return targetClasses;
return builtClasses;
}
private File populateDependencies(File archive) throws IOException {

@ -1,5 +1,5 @@
/*
* Copyright 2012-2017 the original author or authors.
* Copyright 2012-2018 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.
@ -22,9 +22,11 @@ import java.io.IOException;
import java.util.Arrays;
import java.util.Enumeration;
import java.util.List;
import java.util.function.Supplier;
import java.util.jar.JarEntry;
import java.util.jar.JarFile;
import org.springframework.boot.testsupport.BuildOutput;
import org.springframework.util.FileSystemUtils;
import org.springframework.util.StreamUtils;
@ -36,15 +38,17 @@ import org.springframework.util.StreamUtils;
*/
class ExplodedApplicationLauncher extends AbstractApplicationLauncher {
private final File exploded = new File("target/exploded");
private final Supplier<File> exploded;
ExplodedApplicationLauncher(ApplicationBuilder applicationBuilder) {
super(applicationBuilder);
ExplodedApplicationLauncher(ApplicationBuilder applicationBuilder,
BuildOutput buildOutput) {
super(applicationBuilder, buildOutput);
this.exploded = () -> new File(buildOutput.getRootLocation(), "exploded");
}
@Override
protected File getWorkingDirectory() {
return this.exploded;
return this.exploded.get();
}
@Override
@ -53,13 +57,14 @@ class ExplodedApplicationLauncher extends AbstractApplicationLauncher {
}
@Override
protected List<String> getArguments(File archive) {
protected List<String> getArguments(File archive, File serverPortFile) {
String mainClass = (archive.getName().endsWith(".war")
? "org.springframework.boot.loader.WarLauncher"
: "org.springframework.boot.loader.JarLauncher");
try {
explodeArchive(archive);
return Arrays.asList("-cp", this.exploded.getAbsolutePath(), mainClass);
return Arrays.asList("-cp", this.exploded.get().getAbsolutePath(), mainClass,
serverPortFile.getAbsolutePath());
}
catch (IOException ex) {
throw new RuntimeException(ex);
@ -67,12 +72,12 @@ class ExplodedApplicationLauncher extends AbstractApplicationLauncher {
}
private void explodeArchive(File archive) throws IOException {
FileSystemUtils.deleteRecursively(this.exploded);
FileSystemUtils.deleteRecursively(this.exploded.get());
JarFile jarFile = new JarFile(archive);
Enumeration<JarEntry> entries = jarFile.entries();
while (entries.hasMoreElements()) {
JarEntry jarEntry = entries.nextElement();
File extracted = new File(this.exploded, jarEntry.getName());
File extracted = new File(this.exploded.get(), jarEntry.getName());
if (jarEntry.isDirectory()) {
extracted.mkdirs();
}

@ -27,6 +27,7 @@ import java.util.List;
import java.util.jar.JarEntry;
import java.util.jar.JarFile;
import org.springframework.boot.testsupport.BuildOutput;
import org.springframework.util.FileCopyUtils;
import org.springframework.util.FileSystemUtils;
import org.springframework.util.StreamUtils;
@ -40,10 +41,12 @@ import org.springframework.util.StringUtils;
*/
class IdeApplicationLauncher extends AbstractApplicationLauncher {
private final File exploded = new File("target/the+ide application");
private final File exploded;
IdeApplicationLauncher(ApplicationBuilder applicationBuilder) {
super(applicationBuilder);
IdeApplicationLauncher(ApplicationBuilder applicationBuilder,
BuildOutput buildOutput) {
super(applicationBuilder, buildOutput);
this.exploded = new File(buildOutput.getRootLocation(), "the+ide application");
}
@Override
@ -57,18 +60,18 @@ class IdeApplicationLauncher extends AbstractApplicationLauncher {
}
@Override
protected List<String> getArguments(File archive) {
protected List<String> getArguments(File archive, File serverPortFile) {
try {
explodeArchive(archive, this.exploded);
deleteLauncherClasses();
File targetClasses = populateTargetClasses(archive);
File builtClasses = populateBuiltClasses(archive);
File dependencies = populateDependencies(archive);
File resourcesProject = explodedResourcesProject(dependencies);
if (archive.getName().endsWith(".war")) {
populateSrcMainWebapp();
}
List<String> classpath = new ArrayList<>();
classpath.add(targetClasses.getAbsolutePath());
classpath.add(builtClasses.getAbsolutePath());
for (File dependency : dependencies.listFiles()) {
classpath.add(dependency.getAbsolutePath());
}
@ -76,20 +79,21 @@ class IdeApplicationLauncher extends AbstractApplicationLauncher {
return Arrays.asList("-cp",
StringUtils.collectionToDelimitedString(classpath,
File.pathSeparator),
"com.example.ResourceHandlingApplication");
"com.example.ResourceHandlingApplication",
serverPortFile.getAbsolutePath());
}
catch (IOException ex) {
throw new RuntimeException(ex);
}
}
private File populateTargetClasses(File archive) throws IOException {
File targetClasses = new File(this.exploded, "target/classes");
targetClasses.mkdirs();
private File populateBuiltClasses(File archive) throws IOException {
File builtClasses = new File(this.exploded, "built/classes");
builtClasses.mkdirs();
File source = new File(this.exploded, getClassesPath(archive));
FileSystemUtils.copyRecursively(source, targetClasses);
FileSystemUtils.copyRecursively(source, builtClasses);
FileSystemUtils.deleteRecursively(source);
return targetClasses;
return builtClasses;
}
private File populateDependencies(File archive) throws IOException {
@ -108,7 +112,7 @@ class IdeApplicationLauncher extends AbstractApplicationLauncher {
private File explodedResourcesProject(File dependencies) throws IOException {
File resourcesProject = new File(this.exploded,
"resources-project/target/classes");
"resources-project/built/classes");
File resourcesJar = new File(dependencies, "resources-1.0.jar");
explodeArchive(resourcesJar, resourcesProject);
resourcesJar.delete();

@ -1,5 +1,5 @@
/*
* Copyright 2012-2017 the original author or authors.
* Copyright 2012-2018 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.
@ -20,6 +20,8 @@ import java.io.File;
import java.util.Arrays;
import java.util.List;
import org.springframework.boot.testsupport.BuildOutput;
/**
* {@link AbstractApplicationLauncher} that launches a packaged Spring Boot application
* using {@code java -jar}.
@ -28,8 +30,9 @@ import java.util.List;
*/
class PackagedApplicationLauncher extends AbstractApplicationLauncher {
PackagedApplicationLauncher(ApplicationBuilder applicationBuilder) {
super(applicationBuilder);
PackagedApplicationLauncher(ApplicationBuilder applicationBuilder,
BuildOutput buildOutput) {
super(applicationBuilder, buildOutput);
}
@Override
@ -43,8 +46,9 @@ class PackagedApplicationLauncher extends AbstractApplicationLauncher {
}
@Override
protected List<String> getArguments(File archive) {
return Arrays.asList("-jar", archive.getAbsolutePath());
protected List<String> getArguments(File archive, File serverPortFile) {
return Arrays.asList("-jar", archive.getAbsolutePath(),
serverPortFile.getAbsolutePath());
}
}

Loading…
Cancel
Save