Relocate test projects under spring-boot-tests
Move integration and deployment tests under a single `spring-boot-tests` module. See gh-9316
This commit is contained in:
110
spring-boot-tests/spring-boot-integration-tests/pom.xml
Normal file
110
spring-boot-tests/spring-boot-integration-tests/pom.xml
Normal file
@@ -0,0 +1,110 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<parent>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-parent</artifactId>
|
||||
<version>2.0.0.BUILD-SNAPSHOT</version>
|
||||
<relativePath>../spring-boot-parent</relativePath>
|
||||
</parent>
|
||||
<artifactId>spring-boot-integration-tests</artifactId>
|
||||
<packaging>pom</packaging>
|
||||
<name>Spring Boot Integration Tests</name>
|
||||
<description>Spring Boot Integration Tests</description>
|
||||
<url>http://projects.spring.io/spring-boot/</url>
|
||||
<organization>
|
||||
<name>Pivotal Software, Inc.</name>
|
||||
<url>http://www.spring.io</url>
|
||||
</organization>
|
||||
<properties>
|
||||
<main.basedir>${basedir}/..</main.basedir>
|
||||
<java.version>1.8</java.version>
|
||||
</properties>
|
||||
<modules>
|
||||
<module>spring-boot-devtools-tests</module>
|
||||
<module>spring-boot-integration-tests-embedded-servlet-container</module>
|
||||
<module>spring-boot-launch-script-tests</module>
|
||||
<module>spring-boot-security-tests</module>
|
||||
</modules>
|
||||
<profiles>
|
||||
<profile>
|
||||
<id>default</id>
|
||||
<activation>
|
||||
<activeByDefault>true</activeByDefault>
|
||||
</activation>
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<!-- Invoke integration tests in the install phase, after the maven-plugin
|
||||
is available -->
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-invoker-plugin</artifactId>
|
||||
<inherited>false</inherited>
|
||||
<configuration>
|
||||
<settingsFile>src/it/settings.xml</settingsFile>
|
||||
<projectsDirectory>${main.basedir}/spring-boot-samples/</projectsDirectory>
|
||||
<localRepositoryPath>${project.build.directory}/local-repo</localRepositoryPath>
|
||||
<skipInvocation>${skipTests}</skipInvocation>
|
||||
<streamLogs>true</streamLogs>
|
||||
<profiles>
|
||||
<profile>integration-test</profile>
|
||||
</profiles>
|
||||
<localRepositoryPath> </localRepositoryPath>
|
||||
<pomIncludes>
|
||||
<pomInclude>*/pom.xml</pomInclude>
|
||||
</pomIncludes>
|
||||
</configuration>
|
||||
<executions>
|
||||
<execution>
|
||||
<id>integration-test</id>
|
||||
<phase>install</phase>
|
||||
<goals>
|
||||
<goal>install</goal>
|
||||
<goal>run</goal>
|
||||
</goals>
|
||||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-antrun-plugin</artifactId>
|
||||
<inherited>false</inherited>
|
||||
<executions>
|
||||
<execution>
|
||||
<id>clean-samples</id>
|
||||
<phase>clean</phase>
|
||||
<goals>
|
||||
<goal>run</goal>
|
||||
</goals>
|
||||
<configuration>
|
||||
<target>
|
||||
<delete includeemptydirs="true">
|
||||
<fileset dir="${main.basedir}/spring-boot-samples" includes="**/target/" />
|
||||
</delete>
|
||||
</target>
|
||||
</configuration>
|
||||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-clean-plugin</artifactId>
|
||||
<inherited>false</inherited>
|
||||
<executions>
|
||||
<execution>
|
||||
<id>clean-samples</id>
|
||||
<phase>clean</phase>
|
||||
<goals>
|
||||
<goal>clean</goal>
|
||||
</goals>
|
||||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
</profile>
|
||||
<profile>
|
||||
<id>full</id>
|
||||
</profile>
|
||||
</profiles>
|
||||
</project>
|
||||
@@ -0,0 +1,90 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<parent>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-integration-tests</artifactId>
|
||||
<version>2.0.0.BUILD-SNAPSHOT</version>
|
||||
</parent>
|
||||
<artifactId>spring-boot-devtools-tests</artifactId>
|
||||
<name>Spring Boot DevTools Tests</name>
|
||||
<description>${project.name}</description>
|
||||
<url>http://projects.spring.io/spring-boot/</url>
|
||||
<organization>
|
||||
<name>Pivotal Software, Inc.</name>
|
||||
<url>http://www.spring.io</url>
|
||||
</organization>
|
||||
<properties>
|
||||
<main.basedir>${basedir}/../..</main.basedir>
|
||||
</properties>
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-devtools</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-web</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-test</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>net.bytebuddy</groupId>
|
||||
<artifactId>byte-buddy</artifactId>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-dependency-plugin</artifactId>
|
||||
<executions>
|
||||
<execution>
|
||||
<id>copy-dependencies</id>
|
||||
<phase>process-test-resources</phase>
|
||||
<goals>
|
||||
<goal>copy-dependencies</goal>
|
||||
</goals>
|
||||
<configuration>
|
||||
<includeScope>runtime</includeScope>
|
||||
<outputDirectory>${project.build.directory}/dependencies</outputDirectory>
|
||||
<overWriteSnapshots>true</overWriteSnapshots>
|
||||
<overWriteIfNewer>true</overWriteIfNewer>
|
||||
</configuration>
|
||||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
</plugins>
|
||||
<pluginManagement>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.eclipse.m2e</groupId>
|
||||
<artifactId>lifecycle-mapping</artifactId>
|
||||
<version>1.0.0</version>
|
||||
<configuration>
|
||||
<lifecycleMappingMetadata>
|
||||
<pluginExecutions>
|
||||
<pluginExecution>
|
||||
<pluginExecutionFilter>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-dependency-plugin</artifactId>
|
||||
<versionRange>[2.10,)</versionRange>
|
||||
<goals>
|
||||
<goal>copy-dependencies</goal>
|
||||
</goals>
|
||||
</pluginExecutionFilter>
|
||||
<action>
|
||||
<ignore></ignore>
|
||||
</action>
|
||||
</pluginExecution>
|
||||
</pluginExecutions>
|
||||
</lifecycleMappingMetadata>
|
||||
</configuration>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</pluginManagement>
|
||||
</build>
|
||||
</project>
|
||||
@@ -0,0 +1,30 @@
|
||||
/*
|
||||
* Copyright 2012-2016 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 com.example;
|
||||
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
@RestController
|
||||
public class ControllerOne {
|
||||
|
||||
@RequestMapping("/one")
|
||||
public String one() {
|
||||
return "one";
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
/*
|
||||
* Copyright 2012-2016 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 com.example;
|
||||
|
||||
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
||||
import org.springframework.boot.builder.SpringApplicationBuilder;
|
||||
import org.springframework.boot.system.EmbeddedServerPortFileWriter;
|
||||
|
||||
@SpringBootApplication
|
||||
public class DevToolsTestApplication {
|
||||
|
||||
public static void main(String[] args) {
|
||||
new SpringApplicationBuilder(DevToolsTestApplication.class)
|
||||
.listeners(new EmbeddedServerPortFileWriter("target/server.port"))
|
||||
.run(args);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
/*
|
||||
* Copyright 2012-2016 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;
|
||||
|
||||
/**
|
||||
* Launches an application with DevTools.
|
||||
*
|
||||
* @author Andy Wilkinson
|
||||
*/
|
||||
public interface ApplicationLauncher {
|
||||
|
||||
LaunchedApplication launchApplication(JvmLauncher javaLauncher) throws Exception;
|
||||
|
||||
}
|
||||
@@ -0,0 +1,200 @@
|
||||
/*
|
||||
* Copyright 2012-2017 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.boot.devtools.tests;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileReader;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import net.bytebuddy.ByteBuddy;
|
||||
import net.bytebuddy.description.annotation.AnnotationDescription;
|
||||
import net.bytebuddy.description.modifier.Visibility;
|
||||
import net.bytebuddy.dynamic.DynamicType.Builder;
|
||||
import net.bytebuddy.implementation.FixedValue;
|
||||
import org.junit.After;
|
||||
import org.junit.Before;
|
||||
import org.junit.Rule;
|
||||
import org.junit.Test;
|
||||
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.http.HttpStatus;
|
||||
import org.springframework.util.FileCopyUtils;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
/**
|
||||
* Integration tests for DevTools.
|
||||
*
|
||||
* @author Andy Wilkinson
|
||||
*/
|
||||
@RunWith(Parameterized.class)
|
||||
public class DevToolsIntegrationTests {
|
||||
|
||||
private LaunchedApplication launchedApplication;
|
||||
|
||||
private final File serverPortFile = new File("target/server.port");
|
||||
|
||||
private final ApplicationLauncher applicationLauncher;
|
||||
|
||||
@Rule
|
||||
public JvmLauncher javaLauncher = new JvmLauncher();
|
||||
|
||||
@Parameters(name = "{0}")
|
||||
public static Object[] parameters() {
|
||||
return new Object[] { new Object[] { new LocalApplicationLauncher() },
|
||||
new Object[] { new ExplodedRemoteApplicationLauncher() },
|
||||
new Object[] { new JarFileRemoteApplicationLauncher() } };
|
||||
}
|
||||
|
||||
public DevToolsIntegrationTests(ApplicationLauncher applicationLauncher) {
|
||||
this.applicationLauncher = applicationLauncher;
|
||||
}
|
||||
|
||||
@Before
|
||||
public void launchApplication() throws Exception {
|
||||
this.serverPortFile.delete();
|
||||
System.out.println("Launching " + this.javaLauncher.getClass());
|
||||
this.launchedApplication = this.applicationLauncher
|
||||
.launchApplication(this.javaLauncher);
|
||||
}
|
||||
|
||||
@After
|
||||
public void stopApplication() throws InterruptedException {
|
||||
this.launchedApplication.stop();
|
||||
}
|
||||
|
||||
@Test
|
||||
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.getForEntity(urlBase + "/two", String.class).getStatusCode())
|
||||
.isEqualTo(HttpStatus.NOT_FOUND);
|
||||
controller("com.example.ControllerOne").withRequestMapping("one")
|
||||
.withRequestMapping("two").build();
|
||||
assertThat(template.getForObject(urlBase + "/one", String.class))
|
||||
.isEqualTo("one");
|
||||
assertThat(template.getForObject("http://localhost:" + awaitServerPort() + "/two",
|
||||
String.class)).isEqualTo("two");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void removeARequestMappingFromAnExistingController() throws Exception {
|
||||
TestRestTemplate template = new TestRestTemplate();
|
||||
assertThat(template.getForObject("http://localhost:" + awaitServerPort() + "/one",
|
||||
String.class)).isEqualTo("one");
|
||||
controller("com.example.ControllerOne").build();
|
||||
assertThat(template.getForEntity("http://localhost:" + awaitServerPort() + "/one",
|
||||
String.class).getStatusCode()).isEqualTo(HttpStatus.NOT_FOUND);
|
||||
}
|
||||
|
||||
@Test
|
||||
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.getForEntity(urlBase + "/two", String.class).getStatusCode())
|
||||
.isEqualTo(HttpStatus.NOT_FOUND);
|
||||
controller("com.example.ControllerTwo").withRequestMapping("two").build();
|
||||
assertThat(template.getForObject(urlBase + "/one", String.class))
|
||||
.isEqualTo("one");
|
||||
assertThat(template.getForObject("http://localhost:" + awaitServerPort() + "/two",
|
||||
String.class)).isEqualTo("two");
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
public void deleteAController() throws Exception {
|
||||
TestRestTemplate template = new TestRestTemplate();
|
||||
assertThat(template.getForObject("http://localhost:" + awaitServerPort() + "/one",
|
||||
String.class)).isEqualTo("one");
|
||||
assertThat(new File(this.launchedApplication.getClassesDirectory(),
|
||||
"com/example/ControllerOne.class").delete()).isTrue();
|
||||
assertThat(template.getForEntity("http://localhost:" + awaitServerPort() + "/one",
|
||||
String.class).getStatusCode()).isEqualTo(HttpStatus.NOT_FOUND);
|
||||
|
||||
}
|
||||
|
||||
private int awaitServerPort() throws Exception {
|
||||
long end = System.currentTimeMillis() + 30000;
|
||||
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",
|
||||
FileCopyUtils.copyToString(new FileReader(
|
||||
this.launchedApplication.getStandardOut())),
|
||||
FileCopyUtils.copyToString(new FileReader(
|
||||
this.launchedApplication.getStandardError()))));
|
||||
}
|
||||
Thread.sleep(100);
|
||||
}
|
||||
FileReader portReader = new FileReader(this.serverPortFile);
|
||||
int port = Integer.valueOf(FileCopyUtils.copyToString(portReader));
|
||||
this.serverPortFile.delete();
|
||||
System.out.println("Got port " + port);
|
||||
return port;
|
||||
}
|
||||
|
||||
private ControllerBuilder controller(String name) {
|
||||
return new ControllerBuilder(name,
|
||||
this.launchedApplication.getClassesDirectory());
|
||||
}
|
||||
|
||||
private static final class ControllerBuilder {
|
||||
|
||||
private final List<String> mappings = new ArrayList<>();
|
||||
|
||||
private final String name;
|
||||
|
||||
private final File classesDirectory;
|
||||
|
||||
private ControllerBuilder(String name, File classesDirectory) {
|
||||
this.name = name;
|
||||
this.classesDirectory = classesDirectory;
|
||||
}
|
||||
|
||||
public ControllerBuilder withRequestMapping(String mapping) {
|
||||
this.mappings.add(mapping);
|
||||
return this;
|
||||
}
|
||||
|
||||
public void build() throws Exception {
|
||||
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());
|
||||
}
|
||||
builder.make().saveIn(this.classesDirectory);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,54 @@
|
||||
/*
|
||||
* Copyright 2012-2017 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.boot.devtools.tests;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import org.springframework.util.FileSystemUtils;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
/**
|
||||
* {@link ApplicationLauncher} that launches a remote application with its classes
|
||||
* available directly on the file system.
|
||||
*
|
||||
* @author Andy Wilkinson
|
||||
*/
|
||||
public class ExplodedRemoteApplicationLauncher extends RemoteApplicationLauncher {
|
||||
|
||||
@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"));
|
||||
List<String> entries = new ArrayList<>();
|
||||
entries.add("target/app");
|
||||
for (File jar : new File("target/dependencies").listFiles()) {
|
||||
entries.add(jar.getAbsolutePath());
|
||||
}
|
||||
return StringUtils.collectionToDelimitedString(entries, File.pathSeparator);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "exploded remote";
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,90 @@
|
||||
/*
|
||||
* Copyright 2012-2017 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.boot.devtools.tests;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.jar.Attributes;
|
||||
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;
|
||||
|
||||
/**
|
||||
* {@link ApplicationLauncher} that launches a remote application with its classes in a
|
||||
* jar file.
|
||||
*
|
||||
* @author Andy Wilkinson
|
||||
*/
|
||||
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() + "'");
|
||||
}
|
||||
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"));
|
||||
addToJar(output, new File("target/app/"), new File("target/app/"));
|
||||
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());
|
||||
}
|
||||
String classpath = StringUtils.collectionToDelimitedString(entries,
|
||||
File.pathSeparator);
|
||||
return classpath;
|
||||
}
|
||||
|
||||
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() ? "/" : "")));
|
||||
if (file.isFile()) {
|
||||
StreamUtils.copy(new FileInputStream(file), output);
|
||||
}
|
||||
output.closeEntry();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "jar file remote";
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,86 @@
|
||||
/*
|
||||
* Copyright 2012-2017 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.boot.devtools.tests;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
import org.junit.rules.TestRule;
|
||||
import org.junit.runner.Description;
|
||||
import org.junit.runners.model.Statement;
|
||||
|
||||
/**
|
||||
* JUnit {@link TestRule} that launched a JVM and redirects its output to a test
|
||||
* method-specific location.
|
||||
*
|
||||
* @author Andy Wilkinson
|
||||
*/
|
||||
class JvmLauncher implements TestRule {
|
||||
|
||||
private File outputDirectory;
|
||||
|
||||
@Override
|
||||
public Statement apply(Statement base, Description description) {
|
||||
this.outputDirectory = new File("target/output/"
|
||||
+ description.getMethodName().replaceAll("[^A-Za-z]+", ""));
|
||||
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));
|
||||
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(command.toArray(new String[command.size()]))
|
||||
.redirectError(standardError).redirectOutput(standardOut).start();
|
||||
return new LaunchedJvm(process, standardOut, standardError);
|
||||
}
|
||||
|
||||
static class LaunchedJvm {
|
||||
|
||||
private final Process process;
|
||||
|
||||
private final File standardOut;
|
||||
|
||||
private final File standardError;
|
||||
|
||||
LaunchedJvm(Process process, File standardOut, File standardError) {
|
||||
this.process = process;
|
||||
this.standardOut = standardOut;
|
||||
this.standardError = standardError;
|
||||
}
|
||||
|
||||
Process getProcess() {
|
||||
return this.process;
|
||||
}
|
||||
|
||||
File getStandardOut() {
|
||||
return this.standardOut;
|
||||
}
|
||||
|
||||
File getStandardError() {
|
||||
return this.standardError;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,63 @@
|
||||
/*
|
||||
* Copyright 2012-2017 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.boot.devtools.tests;
|
||||
|
||||
import java.io.File;
|
||||
|
||||
/**
|
||||
* An application launched by {@link ApplicationLauncher}.
|
||||
*
|
||||
* @author Andy Wilkinson
|
||||
*/
|
||||
class LaunchedApplication {
|
||||
|
||||
private final File classesDirectory;
|
||||
|
||||
private final File standardOut;
|
||||
|
||||
private final File standardError;
|
||||
|
||||
private final Process[] processes;
|
||||
|
||||
LaunchedApplication(File classesDirectory, File standardOut, File standardError,
|
||||
Process... processes) {
|
||||
this.classesDirectory = classesDirectory;
|
||||
this.standardOut = standardOut;
|
||||
this.standardError = standardError;
|
||||
this.processes = processes;
|
||||
}
|
||||
|
||||
void stop() throws InterruptedException {
|
||||
for (Process process : this.processes) {
|
||||
process.destroy();
|
||||
process.waitFor();
|
||||
}
|
||||
}
|
||||
|
||||
File getStandardOut() {
|
||||
return this.standardOut;
|
||||
}
|
||||
|
||||
File getStandardError() {
|
||||
return this.standardError;
|
||||
}
|
||||
|
||||
File getClassesDirectory() {
|
||||
return this.classesDirectory;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,62 @@
|
||||
/*
|
||||
* Copyright 2012-2017 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.boot.devtools.tests;
|
||||
|
||||
import java.io.File;
|
||||
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;
|
||||
|
||||
/**
|
||||
* {@link ApplicationLauncher} that launches a local application with DevTools enabled.
|
||||
*
|
||||
* @author Andy Wilkinson
|
||||
*/
|
||||
public class LocalApplicationLauncher implements ApplicationLauncher {
|
||||
|
||||
@Override
|
||||
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());
|
||||
}
|
||||
|
||||
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"));
|
||||
List<String> entries = new ArrayList<>();
|
||||
entries.add("target/app");
|
||||
for (File jar : new File("target/dependencies").listFiles()) {
|
||||
entries.add(jar.getAbsolutePath());
|
||||
}
|
||||
return StringUtils.collectionToDelimitedString(entries, File.pathSeparator);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "local";
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,107 @@
|
||||
/*
|
||||
* Copyright 2012-2017 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.boot.devtools.tests;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileReader;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
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;
|
||||
|
||||
/**
|
||||
* Base class for {@link ApplicationLauncher} implementations that use
|
||||
* {@link RemoteSpringApplication}.
|
||||
*
|
||||
* @author Andy Wilkinson
|
||||
*/
|
||||
abstract class RemoteApplicationLauncher implements ApplicationLauncher {
|
||||
|
||||
@Override
|
||||
public LaunchedApplication launchApplication(JvmLauncher javaLauncher)
|
||||
throws Exception {
|
||||
LaunchedJvm applicationJvm = javaLauncher.launch("app",
|
||||
createApplicationClassPath(), "com.example.DevToolsTestApplication",
|
||||
"--server.port=12345", "--spring.devtools.remote.secret=secret");
|
||||
awaitServerPort(applicationJvm.getStandardOut());
|
||||
LaunchedJvm remoteSpringApplicationJvm = javaLauncher.launch(
|
||||
"remote-spring-application", createRemoteSpringApplicationClassPath(),
|
||||
RemoteSpringApplication.class.getName(),
|
||||
"--spring.devtools.remote.secret=secret", "http://localhost:12345");
|
||||
awaitRemoteSpringApplication(remoteSpringApplicationJvm.getStandardOut());
|
||||
return new LaunchedApplication(new File("target/remote"),
|
||||
applicationJvm.getStandardOut(), applicationJvm.getStandardError(),
|
||||
applicationJvm.getProcess(), remoteSpringApplicationJvm.getProcess());
|
||||
}
|
||||
|
||||
protected abstract String createApplicationClassPath() throws Exception;
|
||||
|
||||
private String createRemoteSpringApplicationClassPath() throws Exception {
|
||||
File remoteDirectory = new File("target/remote");
|
||||
FileSystemUtils.deleteRecursively(remoteDirectory);
|
||||
remoteDirectory.mkdirs();
|
||||
FileSystemUtils.copyRecursively(new File("target/test-classes/com"),
|
||||
new File("target/remote/com"));
|
||||
List<String> entries = new ArrayList<>();
|
||||
entries.add("target/remote");
|
||||
for (File jar : new File("target/dependencies").listFiles()) {
|
||||
entries.add(jar.getAbsolutePath());
|
||||
}
|
||||
return StringUtils.collectionToDelimitedString(entries, File.pathSeparator);
|
||||
}
|
||||
|
||||
private int awaitServerPort(File standardOut) 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(
|
||||
"server.port file was not written within 30 seconds. "
|
||||
+ "Application output:%n%s",
|
||||
FileCopyUtils.copyToString(new FileReader(standardOut))));
|
||||
}
|
||||
Thread.sleep(100);
|
||||
}
|
||||
FileReader portReader = new FileReader(serverPortFile);
|
||||
int port = Integer.valueOf(FileCopyUtils.copyToString(portReader));
|
||||
return port;
|
||||
}
|
||||
|
||||
private void awaitRemoteSpringApplication(File standardOut) throws Exception {
|
||||
long end = System.currentTimeMillis() + 30000;
|
||||
while (!standardOut.exists()) {
|
||||
if (System.currentTimeMillis() > end) {
|
||||
throw new IllegalStateException(
|
||||
"Standard out file was not written " + "within 30 seconds");
|
||||
}
|
||||
Thread.sleep(100);
|
||||
}
|
||||
while (!FileCopyUtils.copyToString(new FileReader(standardOut))
|
||||
.contains("Started RemoteSpringApplication")) {
|
||||
if (System.currentTimeMillis() > end) {
|
||||
throw new IllegalStateException(
|
||||
"RemoteSpringApplication did not start within 30 seconds");
|
||||
}
|
||||
Thread.sleep(100);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,66 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<parent>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-integration-tests</artifactId>
|
||||
<version>2.0.0.BUILD-SNAPSHOT</version>
|
||||
</parent>
|
||||
<artifactId>spring-boot-integration-tests-embedded-servlet-container</artifactId>
|
||||
<packaging>jar</packaging>
|
||||
<name>Spring Boot Embedded Servlet Container Integration Tests</name>
|
||||
<url>http://projects.spring.io/spring-boot/</url>
|
||||
<organization>
|
||||
<name>Pivotal Software, Inc.</name>
|
||||
<url>http://www.spring.io</url>
|
||||
</organization>
|
||||
<properties>
|
||||
<main.basedir>${basedir}/../..</main.basedir>
|
||||
</properties>
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-logging</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-test</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.samskivert</groupId>
|
||||
<artifactId>jmustache</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>javax.servlet</groupId>
|
||||
<artifactId>javax.servlet-api</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.apache.maven.shared</groupId>
|
||||
<artifactId>maven-invoker</artifactId>
|
||||
<version>3.0.0</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework</groupId>
|
||||
<artifactId>spring-web</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-surefire-plugin</artifactId>
|
||||
<configuration>
|
||||
<systemPropertyVariables>
|
||||
<maven.home>${maven.home}</maven.home>
|
||||
</systemPropertyVariables>
|
||||
</configuration>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
</project>
|
||||
@@ -0,0 +1,72 @@
|
||||
/*
|
||||
* Copyright 2012-2017 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.example;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.net.URL;
|
||||
|
||||
import javax.servlet.ServletException;
|
||||
import javax.servlet.http.HttpServlet;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
|
||||
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
||||
import org.springframework.boot.builder.SpringApplicationBuilder;
|
||||
import org.springframework.boot.system.EmbeddedServerPortFileWriter;
|
||||
import org.springframework.boot.web.servlet.ServletRegistrationBean;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
|
||||
/**
|
||||
* Test application for verifying an embedded container's static resource handling.
|
||||
*
|
||||
* @author Andy Wilkinson
|
||||
*/
|
||||
@SpringBootApplication
|
||||
public class ResourceHandlingApplication {
|
||||
|
||||
public static void main(String[] args) {
|
||||
new SpringApplicationBuilder(ResourceHandlingApplication.class)
|
||||
.properties("server.port:0")
|
||||
.listeners(new EmbeddedServerPortFileWriter("target/server.port"))
|
||||
.run(args);
|
||||
}
|
||||
|
||||
@Bean
|
||||
public ServletRegistrationBean<?> resourceServletRegistration() {
|
||||
ServletRegistrationBean<?> registration = new ServletRegistrationBean<HttpServlet>(
|
||||
new HttpServlet() {
|
||||
|
||||
@Override
|
||||
protected void doGet(HttpServletRequest req, HttpServletResponse resp)
|
||||
throws ServletException, IOException {
|
||||
URL resource = getServletContext()
|
||||
.getResource(req.getQueryString());
|
||||
if (resource == null) {
|
||||
resp.sendError(404);
|
||||
}
|
||||
else {
|
||||
resp.getWriter().println(resource);
|
||||
resp.getWriter().flush();
|
||||
}
|
||||
}
|
||||
|
||||
});
|
||||
registration.addUrlMappings("/servletContext");
|
||||
return registration;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,104 @@
|
||||
/*
|
||||
* Copyright 2012-2017 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.boot.context.embedded;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileReader;
|
||||
import java.lang.ProcessBuilder.Redirect;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import org.junit.rules.ExternalResource;
|
||||
|
||||
import org.springframework.util.FileCopyUtils;
|
||||
|
||||
/**
|
||||
* Base {@link ExternalResource} for launching a Spring Boot application as part of a
|
||||
* JUnit test.
|
||||
*
|
||||
* @author Andy Wilkinson
|
||||
*/
|
||||
abstract class AbstractApplicationLauncher extends ExternalResource {
|
||||
|
||||
private final ApplicationBuilder applicationBuilder;
|
||||
|
||||
private Process process;
|
||||
|
||||
private int httpPort;
|
||||
|
||||
protected AbstractApplicationLauncher(ApplicationBuilder applicationBuilder) {
|
||||
this.applicationBuilder = applicationBuilder;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected final void before() throws Throwable {
|
||||
this.process = startApplication();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected final void after() {
|
||||
this.process.destroy();
|
||||
}
|
||||
|
||||
public final int getHttpPort() {
|
||||
return this.httpPort;
|
||||
}
|
||||
|
||||
protected abstract List<String> getArguments(File archive);
|
||||
|
||||
protected abstract File getWorkingDirectory();
|
||||
|
||||
protected abstract String getDescription(String packaging);
|
||||
|
||||
private Process startApplication() throws Exception {
|
||||
File workingDirectory = getWorkingDirectory();
|
||||
File serverPortFile = workingDirectory == null ? new File("target/server.port")
|
||||
: new File(workingDirectory, "target/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));
|
||||
ProcessBuilder processBuilder = new ProcessBuilder(
|
||||
arguments.toArray(new String[arguments.size()]));
|
||||
processBuilder.redirectOutput(Redirect.INHERIT);
|
||||
processBuilder.redirectError(Redirect.INHERIT);
|
||||
if (workingDirectory != null) {
|
||||
processBuilder.directory(workingDirectory);
|
||||
}
|
||||
Process process = processBuilder.start();
|
||||
this.httpPort = awaitServerPort(process, serverPortFile);
|
||||
return process;
|
||||
}
|
||||
|
||||
private int awaitServerPort(Process process, File serverPortFile) throws Exception {
|
||||
long end = System.currentTimeMillis() + 30000;
|
||||
while (serverPortFile.length() == 0) {
|
||||
if (System.currentTimeMillis() > end) {
|
||||
throw new IllegalStateException(
|
||||
"server.port file was not written within 30 seconds");
|
||||
}
|
||||
if (!process.isAlive()) {
|
||||
throw new IllegalStateException("Application failed to launch");
|
||||
}
|
||||
Thread.sleep(100);
|
||||
}
|
||||
return Integer
|
||||
.parseInt(FileCopyUtils.copyToString(new FileReader(serverPortFile)));
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,113 @@
|
||||
/*
|
||||
* Copyright 2012-2017 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.boot.context.embedded;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.net.URI;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import org.codehaus.plexus.util.StringUtils;
|
||||
import org.junit.ClassRule;
|
||||
import org.junit.Rule;
|
||||
import org.junit.rules.TemporaryFolder;
|
||||
|
||||
import org.springframework.http.client.ClientHttpResponse;
|
||||
import org.springframework.web.client.ResponseErrorHandler;
|
||||
import org.springframework.web.client.RestTemplate;
|
||||
import org.springframework.web.util.UriTemplateHandler;
|
||||
|
||||
/**
|
||||
* Base class for embedded servlet container integration tests.
|
||||
*
|
||||
* @author Andy Wilkinson
|
||||
*/
|
||||
public abstract class AbstractEmbeddedServletContainerIntegrationTests {
|
||||
|
||||
@ClassRule
|
||||
public static final TemporaryFolder temporaryFolder = new TemporaryFolder();
|
||||
|
||||
@Rule
|
||||
public final AbstractApplicationLauncher launcher;
|
||||
|
||||
protected final RestTemplate rest = new RestTemplate();
|
||||
|
||||
public static Object[] parameters(String packaging,
|
||||
List<Class<? extends AbstractApplicationLauncher>> applicationLaunchers) {
|
||||
List<Object> parameters = new ArrayList<>();
|
||||
parameters.addAll(createParameters(packaging, "jetty", applicationLaunchers));
|
||||
parameters.addAll(createParameters(packaging, "tomcat", applicationLaunchers));
|
||||
parameters.addAll(createParameters(packaging, "undertow", applicationLaunchers));
|
||||
return parameters.toArray(new Object[parameters.size()]);
|
||||
}
|
||||
|
||||
private static List<Object> createParameters(String packaging, String container,
|
||||
List<Class<? extends AbstractApplicationLauncher>> applicationLaunchers) {
|
||||
List<Object> parameters = new ArrayList<>();
|
||||
ApplicationBuilder applicationBuilder = new ApplicationBuilder(temporaryFolder,
|
||||
packaging, container);
|
||||
for (Class<? extends AbstractApplicationLauncher> launcherClass : applicationLaunchers) {
|
||||
try {
|
||||
AbstractApplicationLauncher launcher = launcherClass
|
||||
.getDeclaredConstructor(ApplicationBuilder.class)
|
||||
.newInstance(applicationBuilder);
|
||||
String name = StringUtils.capitalise(container) + ": "
|
||||
+ launcher.getDescription(packaging);
|
||||
parameters.add(new Object[] { name, launcher });
|
||||
}
|
||||
catch (Exception ex) {
|
||||
throw new RuntimeException(ex);
|
||||
}
|
||||
}
|
||||
return parameters;
|
||||
}
|
||||
|
||||
protected AbstractEmbeddedServletContainerIntegrationTests(String name,
|
||||
AbstractApplicationLauncher launcher) {
|
||||
this.launcher = launcher;
|
||||
this.rest.setErrorHandler(new ResponseErrorHandler() {
|
||||
|
||||
@Override
|
||||
public boolean hasError(ClientHttpResponse response) throws IOException {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void handleError(ClientHttpResponse response) throws IOException {
|
||||
|
||||
}
|
||||
|
||||
});
|
||||
this.rest.setUriTemplateHandler(new UriTemplateHandler() {
|
||||
|
||||
@Override
|
||||
public URI expand(String uriTemplate, Object... uriVariables) {
|
||||
return URI.create(
|
||||
"http://localhost:" + launcher.getHttpPort() + uriTemplate);
|
||||
}
|
||||
|
||||
@Override
|
||||
public URI expand(String uriTemplate, Map<String, ?> uriVariables) {
|
||||
return URI.create(
|
||||
"http://localhost:" + launcher.getHttpPort() + uriTemplate);
|
||||
}
|
||||
|
||||
});
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,135 @@
|
||||
/*
|
||||
* Copyright 2012-2017 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.boot.context.embedded;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileNotFoundException;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.FileReader;
|
||||
import java.io.FileWriter;
|
||||
import java.io.IOException;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.jar.JarOutputStream;
|
||||
import java.util.zip.ZipEntry;
|
||||
|
||||
import com.samskivert.mustache.Mustache;
|
||||
import org.apache.maven.shared.invoker.DefaultInvocationRequest;
|
||||
import org.apache.maven.shared.invoker.DefaultInvoker;
|
||||
import org.apache.maven.shared.invoker.InvocationRequest;
|
||||
import org.apache.maven.shared.invoker.InvocationResult;
|
||||
import org.apache.maven.shared.invoker.MavenInvocationException;
|
||||
import org.junit.rules.TemporaryFolder;
|
||||
|
||||
import org.springframework.util.FileCopyUtils;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
/**
|
||||
* Builds a Spring Boot application using Maven. To use this class, the {@code maven.home}
|
||||
* system property must be set.
|
||||
*
|
||||
* @author Andy Wilkinson
|
||||
*/
|
||||
class ApplicationBuilder {
|
||||
|
||||
private final TemporaryFolder temp;
|
||||
|
||||
private final String packaging;
|
||||
|
||||
private final String container;
|
||||
|
||||
ApplicationBuilder(TemporaryFolder temp, String packaging, String container) {
|
||||
this.temp = temp;
|
||||
this.packaging = packaging;
|
||||
this.container = container;
|
||||
}
|
||||
|
||||
File buildApplication() throws Exception {
|
||||
File containerFolder = new File(this.temp.getRoot(), this.container);
|
||||
if (containerFolder.exists()) {
|
||||
return new File(containerFolder, "app/target/app-0.0.1." + this.packaging);
|
||||
}
|
||||
return doBuildApplication(containerFolder);
|
||||
}
|
||||
|
||||
private File doBuildApplication(File containerFolder)
|
||||
throws IOException, FileNotFoundException, MavenInvocationException {
|
||||
File resourcesJar = createResourcesJar();
|
||||
File appFolder = new File(containerFolder, "app");
|
||||
appFolder.mkdirs();
|
||||
writePom(appFolder, resourcesJar);
|
||||
copyApplicationSource(appFolder);
|
||||
packageApplication(appFolder);
|
||||
return new File(appFolder, "target/app-0.0.1." + this.packaging);
|
||||
}
|
||||
|
||||
private File createResourcesJar() throws IOException, FileNotFoundException {
|
||||
File resourcesJar = new File(this.temp.getRoot(), "resources.jar");
|
||||
if (resourcesJar.exists()) {
|
||||
return resourcesJar;
|
||||
}
|
||||
JarOutputStream resourcesJarStream = new JarOutputStream(
|
||||
new FileOutputStream(resourcesJar));
|
||||
resourcesJarStream.putNextEntry(new ZipEntry("META-INF/resources/"));
|
||||
resourcesJarStream.closeEntry();
|
||||
resourcesJarStream.putNextEntry(
|
||||
new ZipEntry("META-INF/resources/nested-meta-inf-resource.txt"));
|
||||
resourcesJarStream.write("nested".getBytes());
|
||||
resourcesJarStream.closeEntry();
|
||||
resourcesJarStream.close();
|
||||
return resourcesJar;
|
||||
}
|
||||
|
||||
private void writePom(File appFolder, File resourcesJar)
|
||||
throws FileNotFoundException, IOException {
|
||||
Map<String, Object> context = new HashMap<>();
|
||||
context.put("packaging", this.packaging);
|
||||
context.put("container", this.container);
|
||||
context.put("bootVersion", Versions.getBootVersion());
|
||||
context.put("resourcesJarPath", resourcesJar.getAbsolutePath());
|
||||
FileWriter out = new FileWriter(new File(appFolder, "pom.xml"));
|
||||
Mustache.compiler().escapeHTML(false)
|
||||
.compile(new FileReader("src/test/resources/pom-template.xml"))
|
||||
.execute(context, out);
|
||||
out.close();
|
||||
}
|
||||
|
||||
private void copyApplicationSource(File appFolder) throws IOException {
|
||||
File examplePackage = new File(appFolder, "src/main/java/com/example");
|
||||
examplePackage.mkdirs();
|
||||
FileCopyUtils.copy(
|
||||
new File("src/test/java/com/example/ResourceHandlingApplication.java"),
|
||||
new File(examplePackage, "ResourceHandlingApplication.java"));
|
||||
if ("war".equals(this.packaging)) {
|
||||
File srcMainWebapp = new File(appFolder, "src/main/webapp");
|
||||
srcMainWebapp.mkdirs();
|
||||
FileCopyUtils.copy("webapp resource",
|
||||
new FileWriter(new File(srcMainWebapp, "webapp-resource.txt")));
|
||||
}
|
||||
}
|
||||
|
||||
private void packageApplication(File appFolder) throws MavenInvocationException {
|
||||
InvocationRequest invocation = new DefaultInvocationRequest();
|
||||
invocation.setBaseDirectory(appFolder);
|
||||
invocation.setGoals(Collections.singletonList("package"));
|
||||
InvocationResult execute = new DefaultInvoker().execute(invocation);
|
||||
assertThat(execute.getExitCode()).isEqualTo(0);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,149 @@
|
||||
/*
|
||||
* Copyright 2012-2017 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.boot.context.embedded;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.Enumeration;
|
||||
import java.util.List;
|
||||
import java.util.jar.JarEntry;
|
||||
import java.util.jar.JarFile;
|
||||
|
||||
import org.springframework.util.FileCopyUtils;
|
||||
import org.springframework.util.FileSystemUtils;
|
||||
import org.springframework.util.StreamUtils;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
/**
|
||||
* {@link AbstractApplicationLauncher} that launches a Spring Boot application with a
|
||||
* classpath similar to that used when run with Maven or Gradle.
|
||||
*
|
||||
* @author Andy Wilkinson
|
||||
*/
|
||||
class BootRunApplicationLauncher extends AbstractApplicationLauncher {
|
||||
|
||||
private final File exploded = new File("target/run");
|
||||
|
||||
BootRunApplicationLauncher(ApplicationBuilder applicationBuilder) {
|
||||
super(applicationBuilder);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected List<String> getArguments(File archive) {
|
||||
try {
|
||||
explodeArchive(archive);
|
||||
deleteLauncherClasses();
|
||||
File targetClasses = populateTargetClasses(archive);
|
||||
File dependencies = populateDependencies(archive);
|
||||
if (archive.getName().endsWith(".war")) {
|
||||
populateSrcMainWebapp();
|
||||
}
|
||||
List<String> classpath = new ArrayList<>();
|
||||
classpath.add(targetClasses.getAbsolutePath());
|
||||
for (File dependency : dependencies.listFiles()) {
|
||||
classpath.add(dependency.getAbsolutePath());
|
||||
}
|
||||
return Arrays.asList("-cp",
|
||||
StringUtils.collectionToDelimitedString(classpath,
|
||||
File.pathSeparator),
|
||||
"com.example.ResourceHandlingApplication");
|
||||
}
|
||||
catch (IOException ex) {
|
||||
throw new RuntimeException(ex);
|
||||
}
|
||||
}
|
||||
|
||||
private void deleteLauncherClasses() {
|
||||
FileSystemUtils.deleteRecursively(new File(this.exploded, "org"));
|
||||
}
|
||||
|
||||
private File populateTargetClasses(File archive) throws IOException {
|
||||
File targetClasses = new File(this.exploded, "target/classes");
|
||||
targetClasses.mkdirs();
|
||||
File source = new File(this.exploded, getClassesPath(archive));
|
||||
FileSystemUtils.copyRecursively(source, targetClasses);
|
||||
FileSystemUtils.deleteRecursively(source);
|
||||
return targetClasses;
|
||||
}
|
||||
|
||||
private File populateDependencies(File archive) throws IOException {
|
||||
File dependencies = new File(this.exploded, "dependencies");
|
||||
dependencies.mkdirs();
|
||||
List<String> libPaths = getLibPaths(archive);
|
||||
for (String libPath : libPaths) {
|
||||
File libDirectory = new File(this.exploded, libPath);
|
||||
for (File jar : libDirectory.listFiles()) {
|
||||
FileCopyUtils.copy(jar, new File(dependencies, jar.getName()));
|
||||
}
|
||||
FileSystemUtils.deleteRecursively(libDirectory);
|
||||
}
|
||||
return dependencies;
|
||||
}
|
||||
|
||||
private void populateSrcMainWebapp() throws IOException {
|
||||
File srcMainWebapp = new File(this.exploded, "src/main/webapp");
|
||||
srcMainWebapp.mkdirs();
|
||||
File source = new File(this.exploded, "webapp-resource.txt");
|
||||
FileCopyUtils.copy(source, new File(srcMainWebapp, "webapp-resource.txt"));
|
||||
source.delete();
|
||||
}
|
||||
|
||||
private String getClassesPath(File archive) {
|
||||
return archive.getName().endsWith(".jar") ? "BOOT-INF/classes"
|
||||
: "WEB-INF/classes";
|
||||
}
|
||||
|
||||
private List<String> getLibPaths(File archive) {
|
||||
return archive.getName().endsWith(".jar")
|
||||
? Collections.singletonList("BOOT-INF/lib")
|
||||
: Arrays.asList("WEB-INF/lib", "WEB-INF/lib-provided");
|
||||
}
|
||||
|
||||
private void explodeArchive(File archive) throws IOException {
|
||||
FileSystemUtils.deleteRecursively(this.exploded);
|
||||
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());
|
||||
if (jarEntry.isDirectory()) {
|
||||
extracted.mkdirs();
|
||||
}
|
||||
else {
|
||||
FileOutputStream extractedOutputStream = new FileOutputStream(extracted);
|
||||
StreamUtils.copy(jarFile.getInputStream(jarEntry), extractedOutputStream);
|
||||
extractedOutputStream.close();
|
||||
}
|
||||
}
|
||||
jarFile.close();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected File getWorkingDirectory() {
|
||||
return this.exploded;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String getDescription(String packaging) {
|
||||
return "build system run " + packaging + " project";
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,67 @@
|
||||
/*
|
||||
* Copyright 2012-2017 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.boot.context.embedded;
|
||||
|
||||
import java.util.Arrays;
|
||||
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.junit.runners.Parameterized;
|
||||
import org.junit.runners.Parameterized.Parameters;
|
||||
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
/**
|
||||
* Integration tests for Spring Boot's embedded servlet container support when developing
|
||||
* a jar application.
|
||||
*
|
||||
* @author Andy Wilkinson
|
||||
*/
|
||||
@RunWith(Parameterized.class)
|
||||
public class EmbeddedServletContainerJarDevelopmentIntegrationTests
|
||||
extends AbstractEmbeddedServletContainerIntegrationTests {
|
||||
|
||||
@Parameters(name = "{0}")
|
||||
public static Object[] parameters() {
|
||||
return AbstractEmbeddedServletContainerIntegrationTests.parameters("jar", Arrays
|
||||
.asList(BootRunApplicationLauncher.class, IdeApplicationLauncher.class));
|
||||
}
|
||||
|
||||
public EmbeddedServletContainerJarDevelopmentIntegrationTests(String name,
|
||||
AbstractApplicationLauncher launcher) {
|
||||
super(name, launcher);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void metaInfResourceFromDependencyIsAvailableViaHttp() throws Exception {
|
||||
ResponseEntity<String> entity = this.rest
|
||||
.getForEntity("/nested-meta-inf-resource.txt", String.class);
|
||||
assertThat(entity.getStatusCode()).isEqualTo(HttpStatus.OK);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void metaInfResourceFromDependencyIsAvailableViaServletContext()
|
||||
throws Exception {
|
||||
ResponseEntity<String> entity = this.rest.getForEntity(
|
||||
"/servletContext?/nested-meta-inf-resource.txt", String.class);
|
||||
assertThat(entity.getStatusCode()).isEqualTo(HttpStatus.OK);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,89 @@
|
||||
/*
|
||||
* Copyright 2012-2017 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.boot.context.embedded;
|
||||
|
||||
import java.util.Arrays;
|
||||
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.junit.runners.Parameterized;
|
||||
import org.junit.runners.Parameterized.Parameters;
|
||||
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
/**
|
||||
* Integration tests for Spring Boot's embedded servlet container support using jar
|
||||
* packaging.
|
||||
*
|
||||
* @author Andy Wilkinson
|
||||
*/
|
||||
@RunWith(Parameterized.class)
|
||||
public class EmbeddedServletContainerJarPackagingIntegrationTests
|
||||
extends AbstractEmbeddedServletContainerIntegrationTests {
|
||||
|
||||
@Parameters(name = "{0}")
|
||||
public static Object[] parameters() {
|
||||
return AbstractEmbeddedServletContainerIntegrationTests.parameters("jar",
|
||||
Arrays.asList(PackagedApplicationLauncher.class,
|
||||
ExplodedApplicationLauncher.class));
|
||||
}
|
||||
|
||||
public EmbeddedServletContainerJarPackagingIntegrationTests(String name,
|
||||
AbstractApplicationLauncher launcher) {
|
||||
super(name, launcher);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void nestedMetaInfResourceIsAvailableViaHttp() throws Exception {
|
||||
ResponseEntity<String> entity = this.rest
|
||||
.getForEntity("/nested-meta-inf-resource.txt", String.class);
|
||||
assertThat(entity.getStatusCode()).isEqualTo(HttpStatus.OK);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void nestedMetaInfResourceIsAvailableViaServletContext() throws Exception {
|
||||
ResponseEntity<String> entity = this.rest.getForEntity(
|
||||
"/servletContext?/nested-meta-inf-resource.txt", String.class);
|
||||
assertThat(entity.getStatusCode()).isEqualTo(HttpStatus.OK);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void nestedJarIsNotAvailableViaHttp() throws Exception {
|
||||
ResponseEntity<String> entity = this.rest
|
||||
.getForEntity("/BOOT-INF/lib/resources-1.0.jar", String.class);
|
||||
assertThat(entity.getStatusCode()).isEqualTo(HttpStatus.NOT_FOUND);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void applicationClassesAreNotAvailableViaHttp() throws Exception {
|
||||
ResponseEntity<String> entity = this.rest.getForEntity(
|
||||
"/BOOT-INF/classes/com/example/ResourceHandlingApplication.class",
|
||||
String.class);
|
||||
assertThat(entity.getStatusCode()).isEqualTo(HttpStatus.NOT_FOUND);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void launcherIsNotAvailableViaHttp() throws Exception {
|
||||
ResponseEntity<String> entity = this.rest.getForEntity(
|
||||
"/org/springframework/boot/loader/Launcher.class", String.class);
|
||||
assertThat(entity.getStatusCode()).isEqualTo(HttpStatus.NOT_FOUND);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,74 @@
|
||||
/*
|
||||
* Copyright 2012-2017 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.boot.context.embedded;
|
||||
|
||||
import java.util.Arrays;
|
||||
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.junit.runners.Parameterized;
|
||||
import org.junit.runners.Parameterized.Parameters;
|
||||
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
/**
|
||||
* Integration tests for Spring Boot's embedded servlet container support when developing
|
||||
* a war application.
|
||||
*
|
||||
* @author Andy Wilkinson
|
||||
*/
|
||||
@RunWith(Parameterized.class)
|
||||
public class EmbeddedServletContainerWarDevelopmentIntegrationTests
|
||||
extends AbstractEmbeddedServletContainerIntegrationTests {
|
||||
|
||||
@Parameters(name = "{0}")
|
||||
public static Object[] parameters() {
|
||||
return AbstractEmbeddedServletContainerIntegrationTests.parameters("war", Arrays
|
||||
.asList(BootRunApplicationLauncher.class, IdeApplicationLauncher.class));
|
||||
}
|
||||
|
||||
public EmbeddedServletContainerWarDevelopmentIntegrationTests(String name,
|
||||
AbstractApplicationLauncher launcher) {
|
||||
super(name, launcher);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void metaInfResourceFromDependencyIsAvailableViaHttp() throws Exception {
|
||||
ResponseEntity<String> entity = this.rest
|
||||
.getForEntity("/nested-meta-inf-resource.txt", String.class);
|
||||
assertThat(entity.getStatusCode()).isEqualTo(HttpStatus.OK);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void metaInfResourceFromDependencyIsAvailableViaServletContext()
|
||||
throws Exception {
|
||||
ResponseEntity<String> entity = this.rest.getForEntity(
|
||||
"/servletContext?/nested-meta-inf-resource.txt", String.class);
|
||||
assertThat(entity.getStatusCode()).isEqualTo(HttpStatus.OK);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void webappResourcesAreAvailableViaHttp() throws Exception {
|
||||
ResponseEntity<String> entity = this.rest.getForEntity("/webapp-resource.txt",
|
||||
String.class);
|
||||
assertThat(entity.getStatusCode()).isEqualTo(HttpStatus.OK);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,100 @@
|
||||
/*
|
||||
* Copyright 2012-2017 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.boot.context.embedded;
|
||||
|
||||
import java.util.Arrays;
|
||||
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.junit.runners.Parameterized;
|
||||
import org.junit.runners.Parameterized.Parameters;
|
||||
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
/**
|
||||
* Integration tests for Spring Boot's embedded servlet container support using war
|
||||
* packaging.
|
||||
*
|
||||
* @author Andy Wilkinson
|
||||
*/
|
||||
@RunWith(Parameterized.class)
|
||||
public class EmbeddedServletContainerWarPackagingIntegrationTests
|
||||
extends AbstractEmbeddedServletContainerIntegrationTests {
|
||||
|
||||
@Parameters(name = "{0}")
|
||||
public static Object[] parameters() {
|
||||
return AbstractEmbeddedServletContainerIntegrationTests.parameters("war",
|
||||
Arrays.asList(PackagedApplicationLauncher.class,
|
||||
ExplodedApplicationLauncher.class));
|
||||
}
|
||||
|
||||
public EmbeddedServletContainerWarPackagingIntegrationTests(String name,
|
||||
AbstractApplicationLauncher launcher) {
|
||||
super(name, launcher);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void nestedMetaInfResourceIsAvailableViaHttp() throws Exception {
|
||||
ResponseEntity<String> entity = this.rest
|
||||
.getForEntity("/nested-meta-inf-resource.txt", String.class);
|
||||
assertThat(entity.getStatusCode()).isEqualTo(HttpStatus.OK);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void nestedMetaInfResourceIsAvailableViaServletContext() throws Exception {
|
||||
ResponseEntity<String> entity = this.rest.getForEntity(
|
||||
"/servletContext?/nested-meta-inf-resource.txt", String.class);
|
||||
assertThat(entity.getStatusCode()).isEqualTo(HttpStatus.OK);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void nestedJarIsNotAvailableViaHttp() throws Exception {
|
||||
ResponseEntity<String> entity = this.rest
|
||||
.getForEntity("/WEB-INF/lib/resources-1.0.jar", String.class);
|
||||
assertThat(entity.getStatusCode()).isEqualTo(HttpStatus.NOT_FOUND);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void applicationClassesAreNotAvailableViaHttp() throws Exception {
|
||||
ResponseEntity<String> entity = this.rest.getForEntity(
|
||||
"/WEB-INF/classes/com/example/ResourceHandlingApplication.class",
|
||||
String.class);
|
||||
assertThat(entity.getStatusCode()).isEqualTo(HttpStatus.NOT_FOUND);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void webappResourcesAreAvailableViaHttp() throws Exception {
|
||||
ResponseEntity<String> entity = this.rest.getForEntity("/webapp-resource.txt",
|
||||
String.class);
|
||||
assertThat(entity.getStatusCode()).isEqualTo(HttpStatus.OK);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void loaderClassesAreNotAvailableViaHttp() throws Exception {
|
||||
ResponseEntity<String> entity = this.rest.getForEntity(
|
||||
"/org/springframework/boot/loader/Launcher.class", String.class);
|
||||
assertThat(entity.getStatusCode()).isEqualTo(HttpStatus.NOT_FOUND);
|
||||
entity = this.rest.getForEntity(
|
||||
"/org/springframework/../springframework/boot/loader/Launcher.class",
|
||||
String.class);
|
||||
assertThat(entity.getStatusCode()).isEqualTo(HttpStatus.NOT_FOUND);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,88 @@
|
||||
/*
|
||||
* Copyright 2012-2017 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.boot.context.embedded;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.util.Arrays;
|
||||
import java.util.Enumeration;
|
||||
import java.util.List;
|
||||
import java.util.jar.JarEntry;
|
||||
import java.util.jar.JarFile;
|
||||
|
||||
import org.springframework.util.FileSystemUtils;
|
||||
import org.springframework.util.StreamUtils;
|
||||
|
||||
/**
|
||||
* {@link AbstractApplicationLauncher} that launches a Spring Boot application using
|
||||
* {@code JarLauncher} or {@code WarLauncher} and an exploded archive.
|
||||
*
|
||||
* @author Andy Wilkinson
|
||||
*/
|
||||
class ExplodedApplicationLauncher extends AbstractApplicationLauncher {
|
||||
|
||||
private final File exploded = new File("target/exploded");
|
||||
|
||||
ExplodedApplicationLauncher(ApplicationBuilder applicationBuilder) {
|
||||
super(applicationBuilder);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected File getWorkingDirectory() {
|
||||
return this.exploded;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String getDescription(String packaging) {
|
||||
return "exploded " + packaging;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected List<String> getArguments(File archive) {
|
||||
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);
|
||||
}
|
||||
catch (IOException ex) {
|
||||
throw new RuntimeException(ex);
|
||||
}
|
||||
}
|
||||
|
||||
private void explodeArchive(File archive) throws IOException {
|
||||
FileSystemUtils.deleteRecursively(this.exploded);
|
||||
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());
|
||||
if (jarEntry.isDirectory()) {
|
||||
extracted.mkdirs();
|
||||
}
|
||||
else {
|
||||
FileOutputStream extractedOutputStream = new FileOutputStream(extracted);
|
||||
StreamUtils.copy(jarFile.getInputStream(jarEntry), extractedOutputStream);
|
||||
extractedOutputStream.close();
|
||||
}
|
||||
}
|
||||
jarFile.close();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,160 @@
|
||||
/*
|
||||
* Copyright 2012-2017 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.boot.context.embedded;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.Enumeration;
|
||||
import java.util.List;
|
||||
import java.util.jar.JarEntry;
|
||||
import java.util.jar.JarFile;
|
||||
|
||||
import org.springframework.util.FileCopyUtils;
|
||||
import org.springframework.util.FileSystemUtils;
|
||||
import org.springframework.util.StreamUtils;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
/**
|
||||
* {@link AbstractApplicationLauncher} that launches a Spring Boot application with a
|
||||
* classpath similar to that used when run in an IDE.
|
||||
*
|
||||
* @author Andy Wilkinson
|
||||
*/
|
||||
class IdeApplicationLauncher extends AbstractApplicationLauncher {
|
||||
|
||||
private final File exploded = new File("target/ide");
|
||||
|
||||
IdeApplicationLauncher(ApplicationBuilder applicationBuilder) {
|
||||
super(applicationBuilder);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected File getWorkingDirectory() {
|
||||
return this.exploded;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String getDescription(String packaging) {
|
||||
return "IDE run " + packaging + " project";
|
||||
}
|
||||
|
||||
@Override
|
||||
protected List<String> getArguments(File archive) {
|
||||
try {
|
||||
explodeArchive(archive, this.exploded);
|
||||
deleteLauncherClasses();
|
||||
File targetClasses = populateTargetClasses(archive);
|
||||
File dependencies = populateDependencies(archive);
|
||||
File resourcesProject = explodedResourcesProject(dependencies);
|
||||
if (archive.getName().endsWith(".war")) {
|
||||
populateSrcMainWebapp();
|
||||
}
|
||||
List<String> classpath = new ArrayList<>();
|
||||
classpath.add(targetClasses.getAbsolutePath());
|
||||
for (File dependency : dependencies.listFiles()) {
|
||||
classpath.add(dependency.getAbsolutePath());
|
||||
}
|
||||
classpath.add(resourcesProject.getAbsolutePath());
|
||||
return Arrays.asList("-cp",
|
||||
StringUtils.collectionToDelimitedString(classpath,
|
||||
File.pathSeparator),
|
||||
"com.example.ResourceHandlingApplication");
|
||||
}
|
||||
catch (IOException ex) {
|
||||
throw new RuntimeException(ex);
|
||||
}
|
||||
}
|
||||
|
||||
private File populateTargetClasses(File archive) throws IOException {
|
||||
File targetClasses = new File(this.exploded, "target/classes");
|
||||
targetClasses.mkdirs();
|
||||
File source = new File(this.exploded, getClassesPath(archive));
|
||||
FileSystemUtils.copyRecursively(source, targetClasses);
|
||||
FileSystemUtils.deleteRecursively(source);
|
||||
return targetClasses;
|
||||
}
|
||||
|
||||
private File populateDependencies(File archive) throws IOException {
|
||||
File dependencies = new File(this.exploded, "dependencies");
|
||||
dependencies.mkdirs();
|
||||
List<String> libPaths = getLibPaths(archive);
|
||||
for (String libPath : libPaths) {
|
||||
File libDirectory = new File(this.exploded, libPath);
|
||||
for (File jar : libDirectory.listFiles()) {
|
||||
FileCopyUtils.copy(jar, new File(dependencies, jar.getName()));
|
||||
}
|
||||
FileSystemUtils.deleteRecursively(libDirectory);
|
||||
}
|
||||
return dependencies;
|
||||
}
|
||||
|
||||
private File explodedResourcesProject(File dependencies) throws IOException {
|
||||
File resourcesProject = new File(this.exploded,
|
||||
"resources-project/target/classes");
|
||||
File resourcesJar = new File(dependencies, "resources-1.0.jar");
|
||||
explodeArchive(resourcesJar, resourcesProject);
|
||||
resourcesJar.delete();
|
||||
return resourcesProject;
|
||||
}
|
||||
|
||||
private void populateSrcMainWebapp() throws IOException {
|
||||
File srcMainWebapp = new File(this.exploded, "src/main/webapp");
|
||||
srcMainWebapp.mkdirs();
|
||||
File source = new File(this.exploded, "webapp-resource.txt");
|
||||
FileCopyUtils.copy(source, new File(srcMainWebapp, "webapp-resource.txt"));
|
||||
source.delete();
|
||||
}
|
||||
|
||||
private void deleteLauncherClasses() {
|
||||
FileSystemUtils.deleteRecursively(new File(this.exploded, "org"));
|
||||
}
|
||||
|
||||
private String getClassesPath(File archive) {
|
||||
return archive.getName().endsWith(".jar") ? "BOOT-INF/classes"
|
||||
: "WEB-INF/classes";
|
||||
}
|
||||
|
||||
private List<String> getLibPaths(File archive) {
|
||||
return archive.getName().endsWith(".jar")
|
||||
? Collections.singletonList("BOOT-INF/lib")
|
||||
: Arrays.asList("WEB-INF/lib", "WEB-INF/lib-provided");
|
||||
}
|
||||
|
||||
private void explodeArchive(File archive, File destination) throws IOException {
|
||||
FileSystemUtils.deleteRecursively(destination);
|
||||
JarFile jarFile = new JarFile(archive);
|
||||
Enumeration<JarEntry> entries = jarFile.entries();
|
||||
while (entries.hasMoreElements()) {
|
||||
JarEntry jarEntry = entries.nextElement();
|
||||
File extracted = new File(destination, jarEntry.getName());
|
||||
if (jarEntry.isDirectory()) {
|
||||
extracted.mkdirs();
|
||||
}
|
||||
else {
|
||||
FileOutputStream extractedOutputStream = new FileOutputStream(extracted);
|
||||
StreamUtils.copy(jarFile.getInputStream(jarEntry), extractedOutputStream);
|
||||
extractedOutputStream.close();
|
||||
}
|
||||
}
|
||||
jarFile.close();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,50 @@
|
||||
/*
|
||||
* Copyright 2012-2017 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.boot.context.embedded;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* {@link AbstractApplicationLauncher} that launches a packaged Spring Boot application
|
||||
* using {@code java -jar}.
|
||||
*
|
||||
* @author Andy Wilkinson
|
||||
*/
|
||||
class PackagedApplicationLauncher extends AbstractApplicationLauncher {
|
||||
|
||||
PackagedApplicationLauncher(ApplicationBuilder applicationBuilder) {
|
||||
super(applicationBuilder);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected File getWorkingDirectory() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String getDescription(String packaging) {
|
||||
return "packaged " + packaging;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected List<String> getArguments(File archive) {
|
||||
return Arrays.asList("-jar", archive.getAbsolutePath());
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,56 @@
|
||||
/*
|
||||
* Copyright 2012-2017 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.boot.context.embedded;
|
||||
|
||||
import java.io.FileReader;
|
||||
|
||||
import javax.xml.xpath.XPath;
|
||||
import javax.xml.xpath.XPathExpression;
|
||||
import javax.xml.xpath.XPathFactory;
|
||||
|
||||
import org.xml.sax.InputSource;
|
||||
|
||||
/**
|
||||
* Provides access to dependency versions by querying the project's pom.
|
||||
*
|
||||
* @author Andy Wilkinson
|
||||
*/
|
||||
final class Versions {
|
||||
|
||||
private Versions() {
|
||||
}
|
||||
|
||||
public static String getBootVersion() {
|
||||
return evaluateExpression(
|
||||
"/*[local-name()='project']/*[local-name()='parent']/*[local-name()='version']"
|
||||
+ "/text()");
|
||||
}
|
||||
|
||||
private static String evaluateExpression(String expression) {
|
||||
try {
|
||||
XPathFactory xPathFactory = XPathFactory.newInstance();
|
||||
XPath xpath = xPathFactory.newXPath();
|
||||
XPathExpression expr = xpath.compile(expression);
|
||||
String version = expr.evaluate(new InputSource(new FileReader("pom.xml")));
|
||||
return version;
|
||||
}
|
||||
catch (Exception ex) {
|
||||
throw new IllegalStateException("Failed to evaluate expression", ex);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,64 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<parent>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-parent</artifactId>
|
||||
<version>{{bootVersion}}</version>
|
||||
<relativePath />
|
||||
</parent>
|
||||
<groupId>com.example</groupId>
|
||||
<artifactId>app</artifactId>
|
||||
<version>0.0.1</version>
|
||||
<packaging>{{packaging}}</packaging>
|
||||
<properties>
|
||||
<resourcesJarPath>{{resourcesJarPath}}</resourcesJarPath>
|
||||
</properties>
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-{{container}}</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework</groupId>
|
||||
<artifactId>spring-web</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>javax.servlet</groupId>
|
||||
<artifactId>javax.servlet-api</artifactId>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.example</groupId>
|
||||
<artifactId>resources</artifactId>
|
||||
<version>1.0</version>
|
||||
<scope>system</scope>
|
||||
<systemPath>${resourcesJarPath}</systemPath>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-maven-plugin</artifactId>
|
||||
<configuration>
|
||||
<includeSystemScope>true</includeSystemScope>
|
||||
</configuration>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
<repositories>
|
||||
<repository>
|
||||
<id>spring-snapshots</id>
|
||||
<url>https://repo.spring.io/libs-snapshot</url>
|
||||
<snapshots>
|
||||
<enabled>true</enabled>
|
||||
</snapshots>
|
||||
</repository>
|
||||
</repositories>
|
||||
</project>
|
||||
@@ -0,0 +1,77 @@
|
||||
= Spring Boot Launch Script Tests
|
||||
|
||||
This module contains integration tests for the default launch script that is used
|
||||
to make a jar file fully executable on Linux. The tests use Docker to verify the
|
||||
functionality in a variety of Linux distributions.
|
||||
|
||||
== Setting up Docker
|
||||
|
||||
The setup that's required varies depending on your operating system.
|
||||
|
||||
=== Docker on OS X
|
||||
|
||||
The latest version of Docker runs as a native Mac application but isn't supported by
|
||||
docker-java. This means that you should use Docker Toolbox. See the
|
||||
https://docs.docker.com/engine/installation/mac/[OS X installation instructions] for
|
||||
details.
|
||||
|
||||
=== Docker on Linux
|
||||
|
||||
Install Docker as appropriate for your Linux distribution. See the
|
||||
https://docs.docker.com/engine/installation/[Linux installation instructions] for more
|
||||
information.
|
||||
|
||||
Next, add your user to the `docker` group. For example:
|
||||
|
||||
----
|
||||
$ sudo usermod -a -G docker awilkinson
|
||||
----
|
||||
|
||||
You may need to log out and back in again for this change to take affect and for your
|
||||
user to be able to connect to the daemon.
|
||||
|
||||
== Preparing to run the tests
|
||||
|
||||
Before running the tests, you must prepare your environment according to your operating
|
||||
system.
|
||||
|
||||
=== Preparation on OS X
|
||||
|
||||
The tests must be run in an environment where various environment variables including
|
||||
`DOCKER_HOST` and `DOCKER_CERT_PATH` have been set:
|
||||
|
||||
----
|
||||
$ eval $(docker-machine env default)
|
||||
----
|
||||
|
||||
=== Preparation on Linux
|
||||
|
||||
Docker Daemon's default configuration on Linux uses a Unix socket for communication.
|
||||
However, Docker's Java client uses HTTP by default. Docker Java's client can be configured
|
||||
to use the Unix socket via the `DOCKER_URL` environment variable:
|
||||
|
||||
----
|
||||
$ export DOCKER_URL=unix:///var/run/docker.sock
|
||||
----
|
||||
|
||||
== Running the tests
|
||||
|
||||
You're now ready to run the tests. Assuming that you're in the same directory as this
|
||||
README, the tests can be launched as follows:
|
||||
|
||||
----
|
||||
$ mvn -Pdocker clean verify
|
||||
----
|
||||
|
||||
The first time the tests are run, Docker will create the container images that are used to
|
||||
run the tests. This can take several minutes, particularly if you have a slow network
|
||||
connection. Subsequent runs will be faster as the images are cached locally. You can run
|
||||
`docker images` to see a list of the cached images. Images created by these tests will be
|
||||
tagged with `spring-boot-it` prefix to easily distinguish them.
|
||||
|
||||
== Cleaning up
|
||||
|
||||
If you want to reclaim the disk space used by the cached images (at the expense of having
|
||||
to wait for them to be downloaded and rebuilt the next time you run the tests), you can
|
||||
use `docker images` to list the images and `docker rmi <image>` to delete them (look for
|
||||
`spring-boot-it` tag). See `docker rmi --help` for further details.
|
||||
@@ -0,0 +1,84 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<parent>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-integration-tests</artifactId>
|
||||
<version>2.0.0.BUILD-SNAPSHOT</version>
|
||||
</parent>
|
||||
<artifactId>spring-boot-launch-script-tests</artifactId>
|
||||
<packaging>jar</packaging>
|
||||
<name>Spring Boot Launch Script Integration Tests</name>
|
||||
<description>Spring Boot Launch Script Integration Tests</description>
|
||||
<url>http://projects.spring.io/spring-boot/</url>
|
||||
<organization>
|
||||
<name>Pivotal Software, Inc.</name>
|
||||
<url>http://www.spring.io</url>
|
||||
</organization>
|
||||
<properties>
|
||||
<main.basedir>${basedir}/../..</main.basedir>
|
||||
<jersey.version>2.11</jersey.version>
|
||||
</properties>
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-web</artifactId>
|
||||
<exclusions>
|
||||
<exclusion>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-tomcat</artifactId>
|
||||
</exclusion>
|
||||
</exclusions>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-undertow</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.github.docker-java</groupId>
|
||||
<artifactId>docker-java</artifactId>
|
||||
<version>2.2.3</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-test</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
<profiles>
|
||||
<profile>
|
||||
<id>docker</id>
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-maven-plugin</artifactId>
|
||||
<configuration>
|
||||
<executable>true</executable>
|
||||
</configuration>
|
||||
<executions>
|
||||
<execution>
|
||||
<goals>
|
||||
<goal>repackage</goal>
|
||||
</goals>
|
||||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-failsafe-plugin</artifactId>
|
||||
<executions>
|
||||
<execution>
|
||||
<goals>
|
||||
<goal>integration-test</goal>
|
||||
<goal>verify</goal>
|
||||
</goals>
|
||||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
</profile>
|
||||
</profiles>
|
||||
</project>
|
||||
@@ -0,0 +1,29 @@
|
||||
/*
|
||||
* Copyright 2012-2016 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.launchscript;
|
||||
|
||||
import org.springframework.boot.SpringApplication;
|
||||
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
||||
|
||||
@SpringBootApplication
|
||||
public class LaunchScriptTestApplication {
|
||||
|
||||
public static void main(String[] args) {
|
||||
SpringApplication.run(LaunchScriptTestApplication.class, args);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
/*
|
||||
* Copyright 2012-2016 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.launchscript;
|
||||
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
@RestController
|
||||
public class LaunchVerificationController {
|
||||
|
||||
@RequestMapping("/")
|
||||
public String verifyLaunch() {
|
||||
return "Launched";
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,466 @@
|
||||
/*
|
||||
* Copyright 2012-2017 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.boot.launchscript;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.InputStream;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
import javax.ws.rs.client.Entity;
|
||||
import javax.ws.rs.client.WebTarget;
|
||||
|
||||
import com.github.dockerjava.api.DockerClient;
|
||||
import com.github.dockerjava.api.DockerClientException;
|
||||
import com.github.dockerjava.api.command.DockerCmd;
|
||||
import com.github.dockerjava.api.model.BuildResponseItem;
|
||||
import com.github.dockerjava.api.model.Frame;
|
||||
import com.github.dockerjava.core.CompressArchiveUtil;
|
||||
import com.github.dockerjava.core.DockerClientBuilder;
|
||||
import com.github.dockerjava.core.DockerClientConfig;
|
||||
import com.github.dockerjava.core.command.AttachContainerResultCallback;
|
||||
import com.github.dockerjava.core.command.BuildImageResultCallback;
|
||||
import com.github.dockerjava.jaxrs.AbstrSyncDockerCmdExec;
|
||||
import com.github.dockerjava.jaxrs.DockerCmdExecFactoryImpl;
|
||||
import org.assertj.core.api.Condition;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.junit.runners.Parameterized;
|
||||
import org.junit.runners.Parameterized.Parameters;
|
||||
|
||||
import org.springframework.boot.ansi.AnsiColor;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.hamcrest.Matchers.containsString;
|
||||
import static org.hamcrest.Matchers.is;
|
||||
import static org.hamcrest.Matchers.not;
|
||||
import static org.junit.Assume.assumeThat;
|
||||
|
||||
/**
|
||||
* Integration tests for Spring Boot's launch script on OSs that use SysVinit.
|
||||
*
|
||||
* @author Andy Wilkinson
|
||||
* @author Ali Shahbour
|
||||
*/
|
||||
@RunWith(Parameterized.class)
|
||||
public class SysVinitLaunchScriptIT {
|
||||
|
||||
private final SpringBootDockerCmdExecFactory commandExecFactory = new SpringBootDockerCmdExecFactory();
|
||||
|
||||
private static final char ESC = 27;
|
||||
|
||||
private final String os;
|
||||
|
||||
private final String version;
|
||||
|
||||
@Parameters(name = "{0} {1}")
|
||||
public static List<Object[]> parameters() {
|
||||
List<Object[]> parameters = new ArrayList<>();
|
||||
for (File os : new File("src/test/resources/conf").listFiles()) {
|
||||
for (File version : os.listFiles()) {
|
||||
parameters.add(new Object[] { os.getName(), version.getName() });
|
||||
}
|
||||
}
|
||||
return parameters;
|
||||
}
|
||||
|
||||
public SysVinitLaunchScriptIT(String os, String version) {
|
||||
this.os = os;
|
||||
this.version = version;
|
||||
}
|
||||
|
||||
@Test
|
||||
public void statusWhenStopped() throws Exception {
|
||||
String output = doTest("status-when-stopped.sh");
|
||||
assertThat(output).contains("Status: 3");
|
||||
assertThat(output).has(coloredString(AnsiColor.RED, "Not running"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void statusWhenStarted() throws Exception {
|
||||
String output = doTest("status-when-started.sh");
|
||||
assertThat(output).contains("Status: 0");
|
||||
assertThat(output).has(
|
||||
coloredString(AnsiColor.GREEN, "Started [" + extractPid(output) + "]"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void statusWhenKilled() throws Exception {
|
||||
String output = doTest("status-when-killed.sh");
|
||||
assertThat(output).contains("Status: 1");
|
||||
assertThat(output).has(coloredString(AnsiColor.RED,
|
||||
"Not running (process " + extractPid(output) + " not found)"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void stopWhenStopped() throws Exception {
|
||||
String output = doTest("stop-when-stopped.sh");
|
||||
assertThat(output).contains("Status: 0");
|
||||
assertThat(output)
|
||||
.has(coloredString(AnsiColor.YELLOW, "Not running (pidfile not found)"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void forceStopWhenStopped() throws Exception {
|
||||
String output = doTest("force-stop-when-stopped.sh");
|
||||
assertThat(output).contains("Status: 0");
|
||||
assertThat(output)
|
||||
.has(coloredString(AnsiColor.YELLOW, "Not running (pidfile not found)"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void startWhenStarted() throws Exception {
|
||||
String output = doTest("start-when-started.sh");
|
||||
assertThat(output).contains("Status: 0");
|
||||
assertThat(output).has(coloredString(AnsiColor.YELLOW,
|
||||
"Already running [" + extractPid(output) + "]"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void restartWhenStopped() throws Exception {
|
||||
String output = doTest("restart-when-stopped.sh");
|
||||
assertThat(output).contains("Status: 0");
|
||||
assertThat(output)
|
||||
.has(coloredString(AnsiColor.YELLOW, "Not running (pidfile not found)"));
|
||||
assertThat(output).has(
|
||||
coloredString(AnsiColor.GREEN, "Started [" + extractPid(output) + "]"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void restartWhenStarted() throws Exception {
|
||||
String output = doTest("restart-when-started.sh");
|
||||
assertThat(output).contains("Status: 0");
|
||||
assertThat(output).has(coloredString(AnsiColor.GREEN,
|
||||
"Started [" + extract("PID1", output) + "]"));
|
||||
assertThat(output).has(coloredString(AnsiColor.GREEN,
|
||||
"Stopped [" + extract("PID1", output) + "]"));
|
||||
assertThat(output).has(coloredString(AnsiColor.GREEN,
|
||||
"Started [" + extract("PID2", output) + "]"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void startWhenStopped() throws Exception {
|
||||
String output = doTest("start-when-stopped.sh");
|
||||
assertThat(output).contains("Status: 0");
|
||||
assertThat(output).has(
|
||||
coloredString(AnsiColor.GREEN, "Started [" + extractPid(output) + "]"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void basicLaunch() throws Exception {
|
||||
doLaunch("basic-launch.sh");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void launchWithSingleCommandLineArgument() throws Exception {
|
||||
doLaunch("launch-with-single-command-line-argument.sh");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void launchWithMultipleCommandLineArguments() throws Exception {
|
||||
doLaunch("launch-with-multiple-command-line-arguments.sh");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void launchWithSingleRunArg() throws Exception {
|
||||
doLaunch("launch-with-single-run-arg.sh");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void launchWithMultipleRunArgs() throws Exception {
|
||||
doLaunch("launch-with-multiple-run-args.sh");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void launchWithSingleJavaOpt() throws Exception {
|
||||
doLaunch("launch-with-single-java-opt.sh");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void launchWithDoubleLinkSingleJavaOpt() throws Exception {
|
||||
doLaunch("launch-with-double-link-single-java-opt.sh");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void launchWithMultipleJavaOpts() throws Exception {
|
||||
doLaunch("launch-with-multiple-java-opts.sh");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void launchWithUseOfStartStopDaemonDisabled() throws Exception {
|
||||
// CentOS doesn't have start-stop-daemon
|
||||
assumeThat(this.os, is(not("CentOS")));
|
||||
doLaunch("launch-with-use-of-start-stop-daemon-disabled.sh");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void launchWithRelativePidFolder() throws Exception {
|
||||
String output = doTest("launch-with-relative-pid-folder.sh");
|
||||
assertThat(output).has(
|
||||
coloredString(AnsiColor.GREEN, "Started [" + extractPid(output) + "]"));
|
||||
assertThat(output).has(
|
||||
coloredString(AnsiColor.GREEN, "Running [" + extractPid(output) + "]"));
|
||||
assertThat(output).has(
|
||||
coloredString(AnsiColor.GREEN, "Stopped [" + extractPid(output) + "]"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void launchWithRelativeLogFolder() throws Exception {
|
||||
String output = doTest("launch-with-relative-log-folder.sh");
|
||||
assertThat(output).contains("Log written");
|
||||
}
|
||||
|
||||
private void doLaunch(String script) throws Exception {
|
||||
assertThat(doTest(script)).contains("Launched");
|
||||
}
|
||||
|
||||
private String doTest(String script) throws Exception {
|
||||
DockerClient docker = createClient();
|
||||
String imageId = buildImage(docker);
|
||||
String container = createContainer(docker, imageId, script);
|
||||
try {
|
||||
copyFilesToContainer(docker, container, script);
|
||||
docker.startContainerCmd(container).exec();
|
||||
StringBuilder output = new StringBuilder();
|
||||
AttachContainerResultCallback resultCallback = docker
|
||||
.attachContainerCmd(container).withStdOut(true).withStdErr(true)
|
||||
.withFollowStream(true).withLogs(true)
|
||||
.exec(new AttachContainerResultCallback() {
|
||||
|
||||
@Override
|
||||
public void onNext(Frame item) {
|
||||
output.append(new String(item.getPayload()));
|
||||
super.onNext(item);
|
||||
}
|
||||
|
||||
});
|
||||
resultCallback.awaitCompletion(60, TimeUnit.SECONDS).close();
|
||||
docker.waitContainerCmd(container).exec();
|
||||
return output.toString();
|
||||
}
|
||||
finally {
|
||||
try {
|
||||
docker.removeContainerCmd(container).exec();
|
||||
}
|
||||
catch (Exception ex) {
|
||||
// Continue
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private DockerClient createClient() {
|
||||
DockerClientConfig config = DockerClientConfig.createDefaultConfigBuilder()
|
||||
.withVersion("1.19").build();
|
||||
DockerClient docker = DockerClientBuilder.getInstance(config)
|
||||
.withDockerCmdExecFactory(this.commandExecFactory).build();
|
||||
return docker;
|
||||
}
|
||||
|
||||
private String buildImage(DockerClient docker) {
|
||||
String dockerfile = "src/test/resources/conf/" + this.os + "/" + this.version
|
||||
+ "/Dockerfile";
|
||||
String tag = "spring-boot-it/" + this.os.toLowerCase() + ":" + this.version;
|
||||
BuildImageResultCallback resultCallback = new BuildImageResultCallback() {
|
||||
|
||||
private List<BuildResponseItem> items = new ArrayList<>();
|
||||
|
||||
@Override
|
||||
public void onNext(BuildResponseItem item) {
|
||||
super.onNext(item);
|
||||
this.items.add(item);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String awaitImageId() {
|
||||
try {
|
||||
awaitCompletion();
|
||||
}
|
||||
catch (InterruptedException ex) {
|
||||
throw new DockerClientException(
|
||||
"Interrupted while waiting for image id", ex);
|
||||
}
|
||||
return getImageId();
|
||||
}
|
||||
|
||||
@SuppressWarnings("deprecation")
|
||||
private String getImageId() {
|
||||
if (this.items.isEmpty()) {
|
||||
throw new DockerClientException("Could not build image");
|
||||
}
|
||||
String imageId = extractImageId();
|
||||
if (imageId == null) {
|
||||
throw new DockerClientException("Could not build image: "
|
||||
+ this.items.get(this.items.size() - 1).getError());
|
||||
}
|
||||
return imageId;
|
||||
}
|
||||
|
||||
private String extractImageId() {
|
||||
Collections.reverse(this.items);
|
||||
for (BuildResponseItem item : this.items) {
|
||||
if (item.isErrorIndicated() || item.getStream() == null) {
|
||||
return null;
|
||||
}
|
||||
if (item.getStream().contains("Successfully built")) {
|
||||
return item.getStream().replace("Successfully built", "").trim();
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
};
|
||||
docker.buildImageCmd(new File(dockerfile)).withTag(tag).exec(resultCallback);
|
||||
String imageId = resultCallback.awaitImageId();
|
||||
return imageId;
|
||||
}
|
||||
|
||||
private String createContainer(DockerClient docker, String imageId,
|
||||
String testScript) {
|
||||
return docker.createContainerCmd(imageId).withTty(false).withCmd("/bin/bash",
|
||||
"-c", "chmod +x " + testScript + " && ./" + testScript).exec().getId();
|
||||
}
|
||||
|
||||
private void copyFilesToContainer(DockerClient docker, final String container,
|
||||
String script) {
|
||||
copyToContainer(docker, container, findApplication());
|
||||
copyToContainer(docker, container,
|
||||
new File("src/test/resources/scripts/test-functions.sh"));
|
||||
copyToContainer(docker, container,
|
||||
new File("src/test/resources/scripts/" + script));
|
||||
}
|
||||
|
||||
private void copyToContainer(DockerClient docker, final String container,
|
||||
final File file) {
|
||||
this.commandExecFactory.createCopyToContainerCmdExec()
|
||||
.exec(new CopyToContainerCmd(container, file));
|
||||
}
|
||||
|
||||
private File findApplication() {
|
||||
File targetDir = new File("target");
|
||||
for (File file : targetDir.listFiles()) {
|
||||
if (file.getName().startsWith("spring-boot-launch-script-tests")
|
||||
&& file.getName().endsWith(".jar")
|
||||
&& !file.getName().endsWith("-sources.jar")) {
|
||||
return file;
|
||||
}
|
||||
}
|
||||
throw new IllegalStateException(
|
||||
"Could not find test application in target directory. Have you built it (mvn package)?");
|
||||
}
|
||||
|
||||
private Condition<String> coloredString(AnsiColor color, String string) {
|
||||
String colorString = ESC + "[0;" + color + "m" + string + ESC + "[0m";
|
||||
return new Condition<String>() {
|
||||
|
||||
@Override
|
||||
public boolean matches(String value) {
|
||||
return containsString(colorString).matches(value);
|
||||
}
|
||||
|
||||
};
|
||||
}
|
||||
|
||||
private String extractPid(String output) {
|
||||
return extract("PID", output);
|
||||
}
|
||||
|
||||
private String extract(String label, String output) {
|
||||
Pattern pattern = Pattern.compile(".*" + label + ": ([0-9]+).*", Pattern.DOTALL);
|
||||
java.util.regex.Matcher matcher = pattern.matcher(output);
|
||||
if (matcher.matches()) {
|
||||
return matcher.group(1);
|
||||
}
|
||||
throw new IllegalArgumentException(
|
||||
"Failed to extract " + label + " from output: " + output);
|
||||
}
|
||||
|
||||
private static final class CopyToContainerCmdExec
|
||||
extends AbstrSyncDockerCmdExec<CopyToContainerCmd, Void> {
|
||||
|
||||
private CopyToContainerCmdExec(WebTarget baseResource,
|
||||
DockerClientConfig dockerClientConfig) {
|
||||
super(baseResource, dockerClientConfig);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Void execute(CopyToContainerCmd command) {
|
||||
try {
|
||||
InputStream streamToUpload = new FileInputStream(CompressArchiveUtil
|
||||
.archiveTARFiles(command.getFile().getParentFile(),
|
||||
Arrays.asList(command.getFile()),
|
||||
command.getFile().getName()));
|
||||
WebTarget webResource = getBaseResource().path("/containers/{id}/archive")
|
||||
.resolveTemplate("id", command.getContainer());
|
||||
webResource.queryParam("path", ".")
|
||||
.queryParam("noOverwriteDirNonDir", false).request()
|
||||
.put(Entity.entity(streamToUpload, "application/x-tar")).close();
|
||||
return null;
|
||||
}
|
||||
catch (Exception ex) {
|
||||
throw new RuntimeException(ex);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private static final class CopyToContainerCmd implements DockerCmd<Void> {
|
||||
|
||||
private final String container;
|
||||
|
||||
private final File file;
|
||||
|
||||
private CopyToContainerCmd(String container, File file) {
|
||||
this.container = container;
|
||||
this.file = file;
|
||||
}
|
||||
|
||||
public String getContainer() {
|
||||
return this.container;
|
||||
}
|
||||
|
||||
public File getFile() {
|
||||
return this.file;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close() {
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private static final class SpringBootDockerCmdExecFactory
|
||||
extends DockerCmdExecFactoryImpl {
|
||||
|
||||
private SpringBootDockerCmdExecFactory() {
|
||||
withClientRequestFilters((requestContext) ->
|
||||
// Workaround for https://go-review.googlesource.com/#/c/3821/
|
||||
requestContext.getHeaders().add("Connection", "close"));
|
||||
}
|
||||
|
||||
private CopyToContainerCmdExec createCopyToContainerCmdExec() {
|
||||
return new CopyToContainerCmdExec(getBaseResource(), getDockerClientConfig());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
# CentOS 6.9 from 02/06/2017
|
||||
FROM centos@sha256:a23bced61701af9a0a758e94229676d9f09996a3ff0f3d26955b06bac8c282e0
|
||||
RUN yum install -y wget && \
|
||||
yum install -y system-config-services && \
|
||||
yum install -y curl && \
|
||||
wget --output-document jdk.rpm \
|
||||
http://cdn.azul.com/zulu/bin/zulu8.21.0.1-jdk8.0.131-linux.x86_64.rpm && \
|
||||
yum --nogpg localinstall -y jdk.rpm && \
|
||||
rm -f jdk.rpm
|
||||
@@ -0,0 +1,9 @@
|
||||
FROM ubuntu:trusty-20160914
|
||||
RUN apt-get update && \
|
||||
apt-get install -y software-properties-common && \
|
||||
add-apt-repository ppa:webupd8team/java -y && \
|
||||
apt-get update && \
|
||||
echo oracle-java7-installer shared/accepted-oracle-license-v1-1 select true | /usr/bin/debconf-set-selections && \
|
||||
apt-get install -y oracle-java8-installer && \
|
||||
apt-get install -y curl && \
|
||||
apt-get clean
|
||||
@@ -0,0 +1,9 @@
|
||||
FROM ubuntu:xenial-20160914
|
||||
RUN apt-get update && \
|
||||
apt-get install -y software-properties-common && \
|
||||
add-apt-repository ppa:webupd8team/java -y && \
|
||||
apt-get update && \
|
||||
echo oracle-java7-installer shared/accepted-oracle-license-v1-1 select true | /usr/bin/debconf-set-selections && \
|
||||
apt-get install -y oracle-java8-installer && \
|
||||
apt-get install -y curl && \
|
||||
apt-get clean
|
||||
@@ -0,0 +1,15 @@
|
||||
<configuration>
|
||||
|
||||
<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
|
||||
<encoder>
|
||||
<pattern>%d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n</pattern>
|
||||
</encoder>
|
||||
</appender>
|
||||
|
||||
<logger name="com.github.dockerjava.core.command" level="DEBUG"/>
|
||||
|
||||
<root level="INFO">
|
||||
<appender-ref ref="STDOUT" />
|
||||
</root>
|
||||
|
||||
</configuration>
|
||||
@@ -0,0 +1,5 @@
|
||||
source ./test-functions.sh
|
||||
install_service
|
||||
start_service
|
||||
await_app
|
||||
curl -s http://127.0.0.1:8080/
|
||||
@@ -0,0 +1,4 @@
|
||||
source ./test-functions.sh
|
||||
install_service
|
||||
force_stop_service
|
||||
echo "Status: $?"
|
||||
@@ -0,0 +1,6 @@
|
||||
source ./test-functions.sh
|
||||
install_double_link_service
|
||||
echo 'JAVA_OPTS=-Dserver.port=8081' > /test-service/spring-boot-app.conf
|
||||
start_service
|
||||
await_app http://127.0.0.1:8081/
|
||||
curl -s http://127.0.0.1:8081/
|
||||
@@ -0,0 +1,5 @@
|
||||
source ./test-functions.sh
|
||||
install_service
|
||||
start_service --server.port=8081 --server.servlet.context-path=/test
|
||||
await_app http://127.0.0.1:8081/test/
|
||||
curl -s http://127.0.0.1:8081/test/
|
||||
@@ -0,0 +1,6 @@
|
||||
source ./test-functions.sh
|
||||
install_service
|
||||
echo 'JAVA_OPTS="-Dserver.port=8081 -Dserver.servlet.context-path=/test"' > /test-service/spring-boot-app.conf
|
||||
start_service
|
||||
await_app http://127.0.0.1:8081/test/
|
||||
curl -s http://127.0.0.1:8081/test/
|
||||
@@ -0,0 +1,6 @@
|
||||
source ./test-functions.sh
|
||||
install_service
|
||||
echo 'RUN_ARGS="--server.port=8081 --server.servlet.context-path=/test"' > /test-service/spring-boot-app.conf
|
||||
start_service
|
||||
await_app http://127.0.0.1:8081/test/
|
||||
curl -s http://127.0.0.1:8081/test/
|
||||
@@ -0,0 +1,8 @@
|
||||
source ./test-functions.sh
|
||||
mkdir ./pid
|
||||
install_service
|
||||
echo 'LOG_FOLDER=log' > /test-service/spring-boot-app.conf
|
||||
mkdir -p /test-service/log
|
||||
start_service
|
||||
await_app
|
||||
[[ -s /test-service/log/spring-boot-app.log ]] && echo "Log written"
|
||||
@@ -0,0 +1,10 @@
|
||||
source ./test-functions.sh
|
||||
install_service
|
||||
mkdir /test-service/pid
|
||||
echo 'PID_FOLDER=pid' > /test-service/spring-boot-app.conf
|
||||
start_service
|
||||
echo "PID: $(cat /test-service/pid/spring-boot-app/spring-boot-app.pid)"
|
||||
await_app
|
||||
curl -s http://127.0.0.1:8080/
|
||||
status_service
|
||||
stop_service
|
||||
@@ -0,0 +1,5 @@
|
||||
source ./test-functions.sh
|
||||
install_service
|
||||
start_service --server.port=8081
|
||||
await_app http://127.0.0.1:8081/
|
||||
curl -s http://127.0.0.1:8081/
|
||||
@@ -0,0 +1,6 @@
|
||||
source ./test-functions.sh
|
||||
install_service
|
||||
echo 'JAVA_OPTS=-Dserver.port=8081' > /test-service/spring-boot-app.conf
|
||||
start_service
|
||||
await_app http://127.0.0.1:8081/
|
||||
curl -s http://127.0.0.1:8081/
|
||||
@@ -0,0 +1,6 @@
|
||||
source ./test-functions.sh
|
||||
install_service
|
||||
echo 'RUN_ARGS=--server.port=8081' > /test-service/spring-boot-app.conf
|
||||
start_service
|
||||
await_app http://127.0.0.1:8081/
|
||||
curl -s http://127.0.0.1:8081/
|
||||
@@ -0,0 +1,7 @@
|
||||
source ./test-functions.sh
|
||||
chmod -x $(type -p start-stop-daemon)
|
||||
install_service
|
||||
echo 'USE_START_STOP_DAEMON=false' > /test-service/spring-boot-app.conf
|
||||
start_service
|
||||
await_app
|
||||
curl -s http://127.0.0.1:8080/
|
||||
@@ -0,0 +1,7 @@
|
||||
source ./test-functions.sh
|
||||
install_service
|
||||
start_service
|
||||
echo "PID1: $(cat /var/run/spring-boot-app/spring-boot-app.pid)"
|
||||
restart_service
|
||||
echo "Status: $?"
|
||||
echo "PID2: $(cat /var/run/spring-boot-app/spring-boot-app.pid)"
|
||||
@@ -0,0 +1,5 @@
|
||||
source ./test-functions.sh
|
||||
install_service
|
||||
restart_service
|
||||
echo "Status: $?"
|
||||
echo "PID: $(cat /var/run/spring-boot-app/spring-boot-app.pid)"
|
||||
@@ -0,0 +1,6 @@
|
||||
source ./test-functions.sh
|
||||
install_service
|
||||
start_service
|
||||
echo "PID: $(cat /var/run/spring-boot-app/spring-boot-app.pid)"
|
||||
start_service
|
||||
echo "Status: $?"
|
||||
@@ -0,0 +1,5 @@
|
||||
source ./test-functions.sh
|
||||
install_service
|
||||
start_service
|
||||
echo "Status: $?"
|
||||
echo "PID: $(cat /var/run/spring-boot-app/spring-boot-app.pid)"
|
||||
@@ -0,0 +1,8 @@
|
||||
source ./test-functions.sh
|
||||
install_service
|
||||
start_service
|
||||
pid=$(cat /var/run/spring-boot-app/spring-boot-app.pid)
|
||||
echo "PID: $pid"
|
||||
kill -9 $pid
|
||||
status_service
|
||||
echo "Status: $?"
|
||||
@@ -0,0 +1,6 @@
|
||||
source ./test-functions.sh
|
||||
install_service
|
||||
start_service
|
||||
status_service
|
||||
echo "Status: $?"
|
||||
echo "PID: $(cat /var/run/spring-boot-app/spring-boot-app.pid)"
|
||||
@@ -0,0 +1,4 @@
|
||||
source ./test-functions.sh
|
||||
install_service
|
||||
status_service
|
||||
echo "Status: $?"
|
||||
@@ -0,0 +1,4 @@
|
||||
source ./test-functions.sh
|
||||
install_service
|
||||
stop_service
|
||||
echo "Status: $?"
|
||||
@@ -0,0 +1,53 @@
|
||||
install_service() {
|
||||
mkdir /test-service
|
||||
mv /spring-boot-launch-script-tests-*.jar /test-service/spring-boot-app.jar
|
||||
chmod +x /test-service/spring-boot-app.jar
|
||||
ln -s /test-service/spring-boot-app.jar /etc/init.d/spring-boot-app
|
||||
}
|
||||
|
||||
install_double_link_service() {
|
||||
mkdir /test-service
|
||||
mv /spring-boot-launch-script-tests-*.jar /test-service/
|
||||
chmod +x /test-service/spring-boot-launch-script-tests-*.jar
|
||||
ln -s /test-service/spring-boot-launch-script-tests-*.jar /test-service/spring-boot-app.jar
|
||||
ln -s /test-service/spring-boot-app.jar /etc/init.d/spring-boot-app
|
||||
}
|
||||
|
||||
start_service() {
|
||||
service spring-boot-app start $@
|
||||
}
|
||||
|
||||
restart_service() {
|
||||
service spring-boot-app restart
|
||||
}
|
||||
|
||||
status_service() {
|
||||
service spring-boot-app status
|
||||
}
|
||||
|
||||
stop_service() {
|
||||
service spring-boot-app stop
|
||||
}
|
||||
|
||||
force_stop_service() {
|
||||
service spring-boot-app force-stop
|
||||
}
|
||||
|
||||
await_app() {
|
||||
if [ -z $1 ]
|
||||
then
|
||||
url=http://127.0.0.1:8080
|
||||
else
|
||||
url=$1
|
||||
fi
|
||||
end=$(date +%s)
|
||||
let "end+=30"
|
||||
until curl -s $url > /dev/null
|
||||
do
|
||||
now=$(date +%s)
|
||||
if [[ $now -ge $end ]]; then
|
||||
break
|
||||
fi
|
||||
sleep 1
|
||||
done
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<parent>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-integration-tests</artifactId>
|
||||
<version>2.0.0.BUILD-SNAPSHOT</version>
|
||||
</parent>
|
||||
<artifactId>spring-boot-security-tests</artifactId>
|
||||
<packaging>pom</packaging>
|
||||
<name>Spring Boot Security Tests</name>
|
||||
<description>${project.name}</description>
|
||||
<url>http://projects.spring.io/spring-boot/</url>
|
||||
<organization>
|
||||
<name>Pivotal Software, Inc.</name>
|
||||
<url>http://www.spring.io</url>
|
||||
</organization>
|
||||
<properties>
|
||||
<main.basedir>${basedir}/../..</main.basedir>
|
||||
</properties>
|
||||
<modules>
|
||||
<module>spring-boot-security-test-web-helloworld</module>
|
||||
</modules>
|
||||
</project>
|
||||
@@ -0,0 +1,40 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<parent>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-security-tests</artifactId>
|
||||
<version>2.0.0.BUILD-SNAPSHOT</version>
|
||||
<relativePath>../</relativePath>
|
||||
</parent>
|
||||
<artifactId>spring-boot-security-test-web-helloworld</artifactId>
|
||||
<name>Spring Boot Security Tests - Web Hello World</name>
|
||||
<description>${project.name}</description>
|
||||
<url>http://projects.spring.io/spring-boot/</url>
|
||||
<organization>
|
||||
<name>Pivotal Software, Inc.</name>
|
||||
<url>http://www.spring.io</url>
|
||||
</organization>
|
||||
<properties>
|
||||
<main.basedir>${basedir}/../../..</main.basedir>
|
||||
</properties>
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-web</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-security</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-test</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
</project>
|
||||
@@ -0,0 +1,38 @@
|
||||
/*
|
||||
* Copyright 2012-2017 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package sample;
|
||||
|
||||
import org.springframework.boot.SpringApplication;
|
||||
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.security.core.userdetails.User;
|
||||
import org.springframework.security.provisioning.InMemoryUserDetailsManager;
|
||||
|
||||
@SpringBootApplication
|
||||
public class HelloWebSecurityApplication {
|
||||
|
||||
@Bean
|
||||
public InMemoryUserDetailsManager inMemoryUserDetailsManager() throws Exception {
|
||||
return new InMemoryUserDetailsManager(
|
||||
User.withUsername("user").password("password").roles("USER").build());
|
||||
}
|
||||
|
||||
public static void main(String[] args) {
|
||||
SpringApplication.run(HelloWebSecurityApplication.class, args);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,77 @@
|
||||
/*
|
||||
* Copyright 2012-2017 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package sample;
|
||||
|
||||
import java.util.Base64;
|
||||
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
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.mock.web.MockFilterChain;
|
||||
import org.springframework.mock.web.MockHttpServletRequest;
|
||||
import org.springframework.mock.web.MockHttpServletResponse;
|
||||
import org.springframework.security.web.FilterChainProxy;
|
||||
import org.springframework.test.context.junit4.SpringRunner;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
@RunWith(SpringRunner.class)
|
||||
@SpringBootTest(webEnvironment = WebEnvironment.RANDOM_PORT)
|
||||
public class HelloWebSecurityApplicationTests {
|
||||
|
||||
@Autowired
|
||||
private FilterChainProxy springSecurityFilterChain;
|
||||
|
||||
private MockHttpServletRequest request;
|
||||
|
||||
private MockHttpServletResponse response;
|
||||
|
||||
private MockFilterChain chain;
|
||||
|
||||
@Before
|
||||
public void setup() {
|
||||
this.request = new MockHttpServletRequest();
|
||||
this.response = new MockHttpServletResponse();
|
||||
this.chain = new MockFilterChain();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void requiresAuthentication() throws Exception {
|
||||
this.request.addHeader("Accept", "application/json");
|
||||
this.springSecurityFilterChain.doFilter(this.request, this.response, this.chain);
|
||||
assertThat(this.response.getStatus())
|
||||
.isEqualTo(HttpServletResponse.SC_UNAUTHORIZED);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void userAuthenticates() throws Exception {
|
||||
this.request.addHeader("Accept", "application/json");
|
||||
this.request.addHeader("Authorization", "Basic " + new String(
|
||||
Base64.getEncoder().encode("user:password".getBytes("UTF-8"))));
|
||||
|
||||
this.springSecurityFilterChain.doFilter(this.request, this.response, this.chain);
|
||||
|
||||
assertThat(this.response.getStatus()).isEqualTo(HttpServletResponse.SC_OK);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<settings>
|
||||
<profiles>
|
||||
<profile>
|
||||
<id>it-repo</id>
|
||||
<activation>
|
||||
<activeByDefault>true</activeByDefault>
|
||||
</activation>
|
||||
<repositories>
|
||||
<repository>
|
||||
<id>local.central</id>
|
||||
<url>@localRepositoryUrl@</url>
|
||||
<releases>
|
||||
<enabled>true</enabled>
|
||||
</releases>
|
||||
<snapshots>
|
||||
<enabled>true</enabled>
|
||||
</snapshots>
|
||||
</repository>
|
||||
</repositories>
|
||||
<pluginRepositories>
|
||||
<pluginRepository>
|
||||
<id>local.central</id>
|
||||
<url>@localRepositoryUrl@</url>
|
||||
<releases>
|
||||
<enabled>true</enabled>
|
||||
</releases>
|
||||
<snapshots>
|
||||
<enabled>true</enabled>
|
||||
</snapshots>
|
||||
</pluginRepository>
|
||||
</pluginRepositories>
|
||||
</profile>
|
||||
</profiles>
|
||||
</settings>
|
||||
Reference in New Issue
Block a user