Merge branch '2.0.x' into 2.1.x

Closes gh-17078
This commit is contained in:
Andy Wilkinson
2019-06-07 10:50:34 +01:00
2691 changed files with 27746 additions and 46049 deletions

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2012-2018 the original author or authors.
* Copyright 2012-2019 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.
@@ -67,8 +67,7 @@ public class DevToolsIntegrationTests {
public void launchApplication() throws Exception {
this.serverPortFile.delete();
System.out.println("Launching " + this.javaLauncher.getClass());
this.launchedApplication = this.applicationLauncher
.launchApplication(this.javaLauncher);
this.launchedApplication = this.applicationLauncher.launchApplication(this.javaLauncher);
}
@After
@@ -80,25 +79,20 @@ public class DevToolsIntegrationTests {
public void addARequestMappingToAnExistingController() throws Exception {
TestRestTemplate template = new TestRestTemplate();
String urlBase = "http://localhost:" + awaitServerPort();
assertThat(template.getForObject(urlBase + "/one", String.class))
.isEqualTo("one");
assertThat(template.getForObject(urlBase + "/one", String.class)).isEqualTo("one");
assertThat(template.getForEntity(urlBase + "/two", String.class).getStatusCode())
.isEqualTo(HttpStatus.NOT_FOUND);
controller("com.example.ControllerOne").withRequestMapping("one")
.withRequestMapping("two").build();
controller("com.example.ControllerOne").withRequestMapping("one").withRequestMapping("two").build();
urlBase = "http://localhost:" + awaitServerPort();
assertThat(template.getForObject(urlBase + "/one", String.class))
.isEqualTo("one");
assertThat(template.getForObject(urlBase + "/two", String.class))
.isEqualTo("two");
assertThat(template.getForObject(urlBase + "/one", String.class)).isEqualTo("one");
assertThat(template.getForObject(urlBase + "/two", String.class)).isEqualTo("two");
}
@Test
public void removeARequestMappingFromAnExistingController() throws Exception {
TestRestTemplate template = new TestRestTemplate();
String urlBase = "http://localhost:" + awaitServerPort();
assertThat(template.getForObject(urlBase + "/one", String.class))
.isEqualTo("one");
assertThat(template.getForObject(urlBase + "/one", String.class)).isEqualTo("one");
controller("com.example.ControllerOne").build();
urlBase = "http://localhost:" + awaitServerPort();
assertThat(template.getForEntity(urlBase + "/one", String.class).getStatusCode())
@@ -109,16 +103,13 @@ public class DevToolsIntegrationTests {
public void createAController() throws Exception {
TestRestTemplate template = new TestRestTemplate();
String urlBase = "http://localhost:" + awaitServerPort();
assertThat(template.getForObject(urlBase + "/one", String.class))
.isEqualTo("one");
assertThat(template.getForObject(urlBase + "/one", String.class)).isEqualTo("one");
assertThat(template.getForEntity(urlBase + "/two", String.class).getStatusCode())
.isEqualTo(HttpStatus.NOT_FOUND);
controller("com.example.ControllerTwo").withRequestMapping("two").build();
urlBase = "http://localhost:" + awaitServerPort();
assertThat(template.getForObject(urlBase + "/one", String.class))
.isEqualTo("one");
assertThat(template.getForObject(urlBase + "/two", String.class))
.isEqualTo("two");
assertThat(template.getForObject(urlBase + "/one", String.class)).isEqualTo("one");
assertThat(template.getForObject(urlBase + "/two", String.class)).isEqualTo("two");
}
@@ -126,57 +117,43 @@ public class DevToolsIntegrationTests {
public void createAControllerAndThenAddARequestMapping() throws Exception {
TestRestTemplate template = new TestRestTemplate();
String urlBase = "http://localhost:" + awaitServerPort();
assertThat(template.getForObject(urlBase + "/one", String.class))
.isEqualTo("one");
assertThat(template.getForObject(urlBase + "/one", String.class)).isEqualTo("one");
assertThat(template.getForEntity(urlBase + "/two", String.class).getStatusCode())
.isEqualTo(HttpStatus.NOT_FOUND);
controller("com.example.ControllerTwo").withRequestMapping("two").build();
urlBase = "http://localhost:" + awaitServerPort();
assertThat(template.getForObject(urlBase + "/one", String.class))
.isEqualTo("one");
assertThat(template.getForObject(urlBase + "/two", String.class))
.isEqualTo("two");
controller("com.example.ControllerTwo").withRequestMapping("two")
.withRequestMapping("three").build();
assertThat(template.getForObject(urlBase + "/one", String.class)).isEqualTo("one");
assertThat(template.getForObject(urlBase + "/two", String.class)).isEqualTo("two");
controller("com.example.ControllerTwo").withRequestMapping("two").withRequestMapping("three").build();
urlBase = "http://localhost:" + awaitServerPort();
assertThat(template.getForObject(urlBase + "/three", String.class))
.isEqualTo("three");
assertThat(template.getForObject(urlBase + "/three", String.class)).isEqualTo("three");
}
@Test
public void createAControllerAndThenAddARequestMappingToAnExistingController()
throws Exception {
public void createAControllerAndThenAddARequestMappingToAnExistingController() throws Exception {
TestRestTemplate template = new TestRestTemplate();
String urlBase = "http://localhost:" + awaitServerPort();
assertThat(template.getForObject(urlBase + "/one", String.class))
.isEqualTo("one");
assertThat(template.getForObject(urlBase + "/one", String.class)).isEqualTo("one");
assertThat(template.getForEntity(urlBase + "/two", String.class).getStatusCode())
.isEqualTo(HttpStatus.NOT_FOUND);
controller("com.example.ControllerTwo").withRequestMapping("two").build();
urlBase = "http://localhost:" + awaitServerPort();
assertThat(template.getForObject(urlBase + "/one", String.class))
.isEqualTo("one");
assertThat(template.getForObject(urlBase + "/two", String.class))
.isEqualTo("two");
controller("com.example.ControllerOne").withRequestMapping("one")
.withRequestMapping("three").build();
assertThat(template.getForObject(urlBase + "/one", String.class)).isEqualTo("one");
assertThat(template.getForObject(urlBase + "/two", String.class)).isEqualTo("two");
controller("com.example.ControllerOne").withRequestMapping("one").withRequestMapping("three").build();
urlBase = "http://localhost:" + awaitServerPort();
assertThat(template.getForObject(urlBase + "/one", String.class))
.isEqualTo("one");
assertThat(template.getForObject(urlBase + "/two", String.class))
.isEqualTo("two");
assertThat(template.getForObject(urlBase + "/three", String.class))
.isEqualTo("three");
assertThat(template.getForObject(urlBase + "/one", String.class)).isEqualTo("one");
assertThat(template.getForObject(urlBase + "/two", String.class)).isEqualTo("two");
assertThat(template.getForObject(urlBase + "/three", String.class)).isEqualTo("three");
}
@Test
public void deleteAController() throws Exception {
TestRestTemplate template = new TestRestTemplate();
String urlBase = "http://localhost:" + awaitServerPort();
assertThat(template.getForObject(urlBase + "/one", String.class))
.isEqualTo("one");
assertThat(new File(this.launchedApplication.getClassesDirectory(),
"com/example/ControllerOne.class").delete()).isTrue();
assertThat(template.getForObject(urlBase + "/one", String.class)).isEqualTo("one");
assertThat(new File(this.launchedApplication.getClassesDirectory(), "com/example/ControllerOne.class").delete())
.isTrue();
urlBase = "http://localhost:" + awaitServerPort();
assertThat(template.getForEntity(urlBase + "/one", String.class).getStatusCode())
.isEqualTo(HttpStatus.NOT_FOUND);
@@ -187,18 +164,15 @@ public class DevToolsIntegrationTests {
public void createAControllerAndThenDeleteIt() throws Exception {
TestRestTemplate template = new TestRestTemplate();
String urlBase = "http://localhost:" + awaitServerPort();
assertThat(template.getForObject(urlBase + "/one", String.class))
.isEqualTo("one");
assertThat(template.getForObject(urlBase + "/one", String.class)).isEqualTo("one");
assertThat(template.getForEntity(urlBase + "/two", String.class).getStatusCode())
.isEqualTo(HttpStatus.NOT_FOUND);
controller("com.example.ControllerTwo").withRequestMapping("two").build();
urlBase = "http://localhost:" + awaitServerPort();
assertThat(template.getForObject(urlBase + "/one", String.class))
.isEqualTo("one");
assertThat(template.getForObject(urlBase + "/two", String.class))
.isEqualTo("two");
assertThat(new File(this.launchedApplication.getClassesDirectory(),
"com/example/ControllerTwo.class").delete()).isTrue();
assertThat(template.getForObject(urlBase + "/one", String.class)).isEqualTo("one");
assertThat(template.getForObject(urlBase + "/two", String.class)).isEqualTo("two");
assertThat(new File(this.launchedApplication.getClassesDirectory(), "com/example/ControllerTwo.class").delete())
.isTrue();
urlBase = "http://localhost:" + awaitServerPort();
assertThat(template.getForEntity(urlBase + "/two", String.class).getStatusCode())
.isEqualTo(HttpStatus.NOT_FOUND);
@@ -210,12 +184,9 @@ public class DevToolsIntegrationTests {
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",
FileCopyUtils.copyToString(new FileReader(
this.launchedApplication.getStandardOut())),
FileCopyUtils.copyToString(new FileReader(
this.launchedApplication.getStandardError()))));
"server.port file was not written within 30 seconds. " + "Application output:%n%s%s",
FileCopyUtils.copyToString(new FileReader(this.launchedApplication.getStandardOut())),
FileCopyUtils.copyToString(new FileReader(this.launchedApplication.getStandardError()))));
}
Thread.sleep(100);
}
@@ -229,8 +200,7 @@ public class DevToolsIntegrationTests {
}
private ControllerBuilder controller(String name) {
return new ControllerBuilder(name,
this.launchedApplication.getClassesDirectory());
return new ControllerBuilder(name, this.launchedApplication.getClassesDirectory());
}
@Parameters(name = "{0}")
@@ -259,14 +229,12 @@ public class DevToolsIntegrationTests {
}
public void build() throws Exception {
Builder<Object> builder = new ByteBuddy().subclass(Object.class)
.name(this.name).annotateType(AnnotationDescription.Builder
.ofType(RestController.class).build());
Builder<Object> builder = new ByteBuddy().subclass(Object.class).name(this.name)
.annotateType(AnnotationDescription.Builder.ofType(RestController.class).build());
for (String mapping : this.mappings) {
builder = builder.defineMethod(mapping, String.class, Visibility.PUBLIC)
.intercept(FixedValue.value(mapping)).annotateMethod(
AnnotationDescription.Builder.ofType(RequestMapping.class)
.defineArray("value", mapping).build());
.intercept(FixedValue.value(mapping)).annotateMethod(AnnotationDescription.Builder
.ofType(RequestMapping.class).defineArray("value", mapping).build());
}
builder.make().saveIn(this.classesDirectory);
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2012-2017 the original author or authors.
* Copyright 2012-2019 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.
@@ -36,8 +36,7 @@ public class ExplodedRemoteApplicationLauncher extends RemoteApplicationLauncher
File appDirectory = new File("target/app");
FileSystemUtils.deleteRecursively(appDirectory);
appDirectory.mkdirs();
FileSystemUtils.copyRecursively(new File("target/test-classes/com"),
new File("target/app/com"));
FileSystemUtils.copyRecursively(new File("target/test-classes/com"), new File("target/app/com"));
List<String> entries = new ArrayList<>();
entries.add("target/app");
for (File jar : new File("target/dependencies").listFiles()) {

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2012-2017 the original author or authors.
* Copyright 2012-2019 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.
@@ -42,18 +42,14 @@ public class JarFileRemoteApplicationLauncher extends RemoteApplicationLauncher
@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() + "'");
if (appDirectory.isDirectory() && !FileSystemUtils.deleteRecursively(appDirectory.toPath())) {
throw new IllegalStateException("Failed to delete '" + appDirectory.getAbsolutePath() + "'");
}
appDirectory.mkdirs();
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"));
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/"));
output.close();
List<String> entries = new ArrayList<>();
@@ -61,20 +57,18 @@ public class JarFileRemoteApplicationLauncher extends RemoteApplicationLauncher
for (File jar : new File("target/dependencies").listFiles()) {
entries.add(jar.getAbsolutePath());
}
String classpath = StringUtils.collectionToDelimitedString(entries,
File.pathSeparator);
String classpath = StringUtils.collectionToDelimitedString(entries, File.pathSeparator);
return classpath;
}
private void addToJar(JarOutputStream output, File root, File current)
throws IOException {
private void addToJar(JarOutputStream output, File root, File current) throws IOException {
for (File file : current.listFiles()) {
if (file.isDirectory()) {
addToJar(output, root, file);
}
output.putNextEntry(new ZipEntry(
file.getAbsolutePath().substring(root.getAbsolutePath().length() + 1)
.replace("\\", "/") + (file.isDirectory() ? "/" : "")));
file.getAbsolutePath().substring(root.getAbsolutePath().length() + 1).replace("\\", "/")
+ (file.isDirectory() ? "/" : "")));
if (file.isFile()) {
try (FileInputStream input = new FileInputStream(file)) {
StreamUtils.copy(input, output);

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2012-2018 the original author or authors.
* Copyright 2012-2019 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.
@@ -43,20 +43,20 @@ class JvmLauncher implements TestRule {
@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(
"target/output/" + NON_ALPHABET_PATTERN.matcher(description.getMethodName()).replaceAll(""));
this.outputDirectory.mkdirs();
return base;
}
LaunchedJvm launch(String name, String classpath, String... args) throws IOException {
List<String> command = new ArrayList<>(Arrays
.asList(System.getProperty("java.home") + "/bin/java", "-cp", classpath));
List<String> command = new ArrayList<>(
Arrays.asList(System.getProperty("java.home") + "/bin/java", "-cp", classpath));
command.addAll(Arrays.asList(args));
File standardOut = new File(this.outputDirectory, name + ".out");
File standardError = new File(this.outputDirectory, name + ".err");
Process process = new ProcessBuilder(StringUtils.toStringArray(command))
.redirectError(standardError).redirectOutput(standardOut).start();
Process process = new ProcessBuilder(StringUtils.toStringArray(command)).redirectError(standardError)
.redirectOutput(standardOut).start();
return new LaunchedJvm(process, standardOut, standardError);
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2012-2018 the original author or authors.
* Copyright 2012-2019 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.
@@ -38,9 +38,8 @@ class LaunchedApplication {
private final BiFunction<Integer, File, Process> remoteProcessRestarter;
LaunchedApplication(File classesDirectory, File standardOut, File standardError,
Process localProcess, Process remoteProcess,
BiFunction<Integer, File, Process> remoteProcessRestarter) {
LaunchedApplication(File classesDirectory, File standardOut, File standardError, Process localProcess,
Process remoteProcess, BiFunction<Integer, File, Process> remoteProcessRestarter) {
this.classesDirectory = classesDirectory;
this.standardOut = standardOut;
this.standardError = standardError;
@@ -52,8 +51,7 @@ class LaunchedApplication {
public void restartRemote(int port) throws InterruptedException {
if (this.remoteProcessRestarter != null) {
stop(this.remoteProcess);
this.remoteProcess = this.remoteProcessRestarter.apply(port,
this.classesDirectory);
this.remoteProcess = this.remoteProcessRestarter.apply(port, this.classesDirectory);
}
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2012-2018 the original author or authors.
* Copyright 2012-2019 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.
@@ -32,20 +32,18 @@ import org.springframework.util.StringUtils;
public class LocalApplicationLauncher implements ApplicationLauncher {
@Override
public LaunchedApplication launchApplication(JvmLauncher jvmLauncher)
throws Exception {
public LaunchedApplication launchApplication(JvmLauncher jvmLauncher) 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);
return new LaunchedApplication(new File("target/app"), 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"));
FileSystemUtils.copyRecursively(new File("target/test-classes/com"), new File("target/app/com"));
List<String> entries = new ArrayList<>();
entries.add("target/app");
for (File jar : new File("target/dependencies").listFiles()) {

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2012-2018 the original author or authors.
* Copyright 2012-2019 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.
@@ -37,29 +37,22 @@ import org.springframework.util.StringUtils;
abstract class RemoteApplicationLauncher implements ApplicationLauncher {
@Override
public LaunchedApplication launchApplication(JvmLauncher javaLauncher)
throws Exception {
LaunchedJvm applicationJvm = javaLauncher.launch("app",
createApplicationClassPath(), "com.example.DevToolsTestApplication",
"--server.port=0", "--spring.devtools.remote.secret=secret");
public LaunchedApplication launchApplication(JvmLauncher javaLauncher) throws Exception {
LaunchedJvm applicationJvm = javaLauncher.launch("app", createApplicationClassPath(),
"com.example.DevToolsTestApplication", "--server.port=0", "--spring.devtools.remote.secret=secret");
int port = awaitServerPort(applicationJvm.getStandardOut());
BiFunction<Integer, File, Process> remoteRestarter = getRemoteRestarter(
javaLauncher);
return new LaunchedApplication(new File("target/remote"),
applicationJvm.getStandardOut(), applicationJvm.getStandardError(),
applicationJvm.getProcess(), remoteRestarter.apply(port, null),
BiFunction<Integer, File, Process> remoteRestarter = getRemoteRestarter(javaLauncher);
return new LaunchedApplication(new File("target/remote"), applicationJvm.getStandardOut(),
applicationJvm.getStandardError(), applicationJvm.getProcess(), remoteRestarter.apply(port, null),
remoteRestarter);
}
private BiFunction<Integer, File, Process> getRemoteRestarter(
JvmLauncher javaLauncher) {
private BiFunction<Integer, File, Process> getRemoteRestarter(JvmLauncher javaLauncher) {
return (port, classesDirectory) -> {
try {
LaunchedJvm remoteSpringApplicationJvm = javaLauncher.launch(
"remote-spring-application",
LaunchedJvm remoteSpringApplicationJvm = javaLauncher.launch("remote-spring-application",
createRemoteSpringApplicationClassPath(classesDirectory),
RemoteSpringApplication.class.getName(),
"--spring.devtools.remote.secret=secret",
RemoteSpringApplication.class.getName(), "--spring.devtools.remote.secret=secret",
"http://localhost:" + port);
awaitRemoteSpringApplication(remoteSpringApplicationJvm.getStandardOut());
return remoteSpringApplicationJvm.getProcess();
@@ -72,14 +65,12 @@ abstract class RemoteApplicationLauncher implements ApplicationLauncher {
protected abstract String createApplicationClassPath() throws Exception;
private String createRemoteSpringApplicationClassPath(File classesDirectory)
throws Exception {
private String createRemoteSpringApplicationClassPath(File classesDirectory) throws Exception {
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"));
FileSystemUtils.copyRecursively(new File("target/test-classes/com"), new File("target/remote/com"));
}
List<String> entries = new ArrayList<>();
entries.add("target/remote");
@@ -95,8 +86,7 @@ abstract class RemoteApplicationLauncher implements ApplicationLauncher {
while (serverPortFile.length() == 0) {
if (System.currentTimeMillis() > end) {
throw new IllegalStateException(String.format(
"server.port file was not written within 30 seconds. "
+ "Application output:%n%s",
"server.port file was not written within 30 seconds. " + "Application output:%n%s",
FileCopyUtils.copyToString(new FileReader(standardOut))));
}
Thread.sleep(100);
@@ -110,16 +100,13 @@ abstract class RemoteApplicationLauncher implements ApplicationLauncher {
long end = System.currentTimeMillis() + 30000;
while (!standardOut.exists()) {
if (System.currentTimeMillis() > end) {
throw new IllegalStateException(
"Standard out file was not written " + "within 30 seconds");
throw new IllegalStateException("Standard out file was not written " + "within 30 seconds");
}
Thread.sleep(100);
}
while (!FileCopyUtils.copyToString(new FileReader(standardOut))
.contains("Started RemoteSpringApplication")) {
while (!FileCopyUtils.copyToString(new FileReader(standardOut)).contains("Started RemoteSpringApplication")) {
if (System.currentTimeMillis() > end) {
throw new IllegalStateException(
"RemoteSpringApplication did not start within 30 seconds");
throw new IllegalStateException("RemoteSpringApplication did not start within 30 seconds");
}
Thread.sleep(100);
}