Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
package org.springframework.boot.maven;

import java.io.File;
import java.io.IOException;

import org.junit.jupiter.api.TestTemplate;
import org.junit.jupiter.api.condition.DisabledOnOs;
Expand Down Expand Up @@ -101,6 +102,19 @@ void whenUseTestClasspathIsEnabledTheApplicationHasTestDependenciesOnItsClasspat
.execute((project) -> assertThat(buildLog(project)).contains("I haz been run"));
}

@TestTemplate
void whenUseTestClasspathIsAllTheApplicationRunsWithTestClassesAndDependencies(MavenBuild mavenBuild) {
mavenBuild.project("test-run")
.goals("spring-boot:run", "-X")
.systemProperty("spring-boot.run.useTestClasspath", "ALL")
.execute((project) -> assertThat(buildLog(project))
.contains("Main class name = org.test.TestSampleApplication")
.contains("1. " + canonicalPathOf(project, "target/test-classes"))
.contains("2. " + canonicalPathOf(project, "target/classes"))
.containsPattern("3\\. .*spring-core")
.containsPattern("4\\. .*commons-logging"));
}

@TestTemplate
void whenAWorkingDirectoryIsConfiguredTheApplicationIsRunFromThatDirectory(MavenBuild mavenBuild) {
mavenBuild.project("run-working-directory")
Expand Down Expand Up @@ -163,4 +177,8 @@ private String buildLog(File project) {
return contentOf(new File(project, "target/build.log"));
}

private String canonicalPathOf(File project, String path) throws IOException {
return new File(project, path).getCanonicalPath();
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,18 @@ class StartStopIntegrationTests {
void startStopWaitsForApplicationToBeReadyAndThenRequestsShutdown(MavenBuild mavenBuild) {
mavenBuild.project("start-stop")
.goals("verify")
.execute((project) -> assertThat(buildLog(project)).contains("isReady: true")
.execute((project) -> assertThat(buildLog(project)).doesNotContain("Running application from test classes")
.contains("isReady: true")
.contains("Shutdown requested"));
}

@TestTemplate
void startStopWithAllTestClasspathRunsApplicationFromTestClasses(MavenBuild mavenBuild) {
mavenBuild.project("start-stop")
.goals("verify")
.systemProperty("use-test-classpath", "ALL")
.execute((project) -> assertThat(buildLog(project)).contains("Running application from test classes")
.contains("isReady: true")
.contains("Shutdown requested"));
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<maven.compiler.source>@java.version@</maven.compiler.source>
<maven.compiler.target>@java.version@</maven.compiler.target>
<use-test-classpath>false</use-test-classpath>
</properties>
<build>
<plugins>
Expand Down Expand Up @@ -51,6 +52,7 @@
</executions>
<configuration>
<jmxPort>${jmx.port}</jmxPort>
<useTestClasspath>${use-test-classpath}</useTestClasspath>
</configuration>
</plugin>
</plugins>
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
/*
* Copyright 2012-present 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
*
* https://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.test;

/**
* Test application used to verify that the start goal can use test classes.
*
* @author Henrique (henriquejsza)
*/
public class TestSampleApplication {

public static void main(String[] args) throws Exception {
System.out.println("Running application from test classes");
SampleApplication.main(args);
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@
* @author Daniel Young
* @author Dmytro Nosan
* @author Moritz Halbritter
* @author Henrique (henriquejsza)
* @since 1.3.0
* @see RunMojo
* @see StartMojo
Expand Down Expand Up @@ -205,6 +206,14 @@ public abstract class AbstractRunMojo extends AbstractDependencyFilterMojo {
@SuppressWarnings("NullAway.Init")
private File classesDirectory;

/**
* Directory containing the test classes and resource files that should be used to run
* the application.
*/
@Parameter(defaultValue = "${project.build.testOutputDirectory}", required = true)
@SuppressWarnings("NullAway.Init")
private File testClassesDirectory;

/**
* Skip the execution.
*
Expand Down Expand Up @@ -241,11 +250,20 @@ private String determineMainClass() throws MojoExecutionException {
* @since 3.1.0
*/
protected List<File> getClassesDirectories() {
return List.of(this.classesDirectory);
List<File> classesDirectories = new ArrayList<>();
if (isUseTestClasses()) {
classesDirectories.add(this.testClassesDirectory);
}
classesDirectories.add(this.classesDirectory);
return classesDirectories;
}

protected abstract boolean isUseTestClasspath();

protected boolean isUseTestClasses() {
return false;
}

private void run(String startClassName) throws MojoExecutionException, MojoFailureException {
List<String> args = new ArrayList<>();
addAgents(args);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -55,11 +55,15 @@ public class RunMojo extends AbstractRunMojo {
private boolean optimizedLaunch;

/**
* Flag to include the test classpath when running.
* Test classpath to use when running. Valid values are {@code OFF} (no test
* classpath), {@code DEPENDENCIES} (test dependencies only), and {@code ALL} (test
* dependencies, classes, and resources). For backwards compatibility, {@code false}
* is equivalent to {@code OFF} and {@code true} is equivalent to
* {@code DEPENDENCIES}.
* @since 1.3.0
*/
@Parameter(property = "spring-boot.run.useTestClasspath", defaultValue = "false")
private boolean useTestClasspath;
private String useTestClasspath = "false";

@Inject
public RunMojo(ToolchainManager toolchainManager) {
Expand All @@ -86,7 +90,12 @@ protected void run(JavaProcessExecutor processExecutor, File workingDirectory, L

@Override
protected boolean isUseTestClasspath() {
return this.useTestClasspath;
return TestClasspath.of(this.useTestClasspath).isUseTestDependencies();
}

@Override
protected boolean isUseTestClasses() {
return TestClasspath.of(this.useTestClasspath).isUseTestClasses();
}

private static final class RunProcessKiller implements Runnable {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -90,10 +90,14 @@ public class StartMojo extends AbstractRunMojo {
private final Object lock = new Object();

/**
* Flag to include the test classpath when running.
* Test classpath to use when running. Valid values are {@code OFF} (no test
* classpath), {@code DEPENDENCIES} (test dependencies only), and {@code ALL} (test
* dependencies, classes, and resources). For backwards compatibility, {@code false}
* is equivalent to {@code OFF} and {@code true} is equivalent to
* {@code DEPENDENCIES}.
*/
@Parameter(property = "spring-boot.run.useTestClasspath", defaultValue = "false")
private boolean useTestClasspath;
private String useTestClasspath = "false";

@Inject
public StartMojo(ToolchainManager toolchainManager) {
Expand Down Expand Up @@ -206,7 +210,12 @@ public <T> T execute(long wait, int maxAttempts, Callable<@Nullable T> callback)

@Override
protected boolean isUseTestClasspath() {
return this.useTestClasspath;
return TestClasspath.of(this.useTestClasspath).isUseTestDependencies();
}

@Override
protected boolean isUseTestClasses() {
return TestClasspath.of(this.useTestClasspath).isUseTestClasses();
}

private class CreateJmxConnector implements Callable<@Nullable JMXConnector> {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
/*
* Copyright 2012-present 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
*
* https://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.maven;

import java.util.Locale;

/**
* Use of the test classpath when running an application.
*
* @author Henrique (henriquejsza)
*/
enum TestClasspath {

OFF(false, false),

DEPENDENCIES(true, false),

ALL(true, true);

private final boolean useTestDependencies;

private final boolean useTestClasses;

TestClasspath(boolean useTestDependencies, boolean useTestClasses) {
this.useTestDependencies = useTestDependencies;
this.useTestClasses = useTestClasses;
}

boolean isUseTestDependencies() {
return this.useTestDependencies;
}

boolean isUseTestClasses() {
return this.useTestClasses;
}

static TestClasspath of(String value) {
if ("true".equalsIgnoreCase(value)) {
return DEPENDENCIES;
}
if ("false".equalsIgnoreCase(value)) {
return OFF;
}
try {
return valueOf(value.toUpperCase(Locale.ROOT));
}
catch (IllegalArgumentException ex) {
String message = "Unsupported test classpath '%s'. Valid values are OFF, DEPENDENCIES, ALL, true, and false"
.formatted(value);
throw new IllegalArgumentException(message, ex);
}
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,6 @@
package org.springframework.boot.maven;

import java.io.File;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;

Expand Down Expand Up @@ -57,24 +56,14 @@ public class TestRunMojo extends AbstractRunMojo {
@Parameter(property = "spring-boot.test-run.optimizedLaunch", defaultValue = "true")
private boolean optimizedLaunch;

/**
* Directory containing the test classes and resource files that should be used to run
* the application.
*/
@Parameter(defaultValue = "${project.build.testOutputDirectory}", required = true)
@SuppressWarnings("NullAway.Init")
private File testClassesDirectory;

@Inject
public TestRunMojo(ToolchainManager toolchainManager) {
super(toolchainManager);
}

@Override
protected List<File> getClassesDirectories() {
ArrayList<File> classesDirectories = new ArrayList<>(super.getClassesDirectories());
classesDirectories.add(0, this.testClassesDirectory);
return classesDirectories;
protected boolean isUseTestClasses() {
return true;
}

@Override
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
/*
* Copyright 2012-present 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
*
* https://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.maven;

import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.CsvSource;

import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.assertThatIllegalArgumentException;

/**
* Tests for {@link TestClasspath}.
*
* @author Henrique (henriquejsza)
*/
class TestClasspathTests {

@ParameterizedTest
@CsvSource({ "false, OFF", "off, OFF", "true, DEPENDENCIES", "dependencies, DEPENDENCIES", "all, ALL" })
void mapsValueToTestClasspath(String value, TestClasspath expected) {
assertThat(TestClasspath.of(value)).isEqualTo(expected);
}

@ParameterizedTest
@CsvSource({ "OFF, false, false", "DEPENDENCIES, true, false", "ALL, true, true" })
void exposesIncludedParts(TestClasspath testClasspath, boolean useTestDependencies, boolean useTestClasses) {
assertThat(testClasspath.isUseTestDependencies()).isEqualTo(useTestDependencies);
assertThat(testClasspath.isUseTestClasses()).isEqualTo(useTestClasses);
}

@ParameterizedTest
@CsvSource({ "unknown", "yes" })
void rejectsUnsupportedValue(String value) {
assertThatIllegalArgumentException().isThrownBy(() -> TestClasspath.of(value))
.withMessage("Unsupported test classpath '%s'. Valid values are OFF, DEPENDENCIES, ALL, true, and false",
value);
}

}
Loading