diff --git a/CHANGELOG.md b/CHANGELOG.md index 180ee741b..5fde6e1b5 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,7 @@ We use [semantic versioning](http://semver.org/): - PATCH version when you make backwards compatible bug fixes. # Next version +- [fix] _teamscale-maven-plugin_: `prepare-tia-unit-test` and `prepare-tia-integration-test` no longer require a commit or revision when `runImpacted` is `false`. - [fix] _teamscale-gradle-plugin_, _teamscale-maven-plugin_: Testwise coverage reports no longer drop a class directory that contains an archive (JAR, WAR, EAR, ZIP) that contains a JAR. # 39.0.0 diff --git a/common-system-test/src/main/kotlin/com/teamscale/test/commons/SystemTestUtils.kt b/common-system-test/src/main/kotlin/com/teamscale/test/commons/SystemTestUtils.kt index bb2318a23..7b62276eb 100644 --- a/common-system-test/src/main/kotlin/com/teamscale/test/commons/SystemTestUtils.kt +++ b/common-system-test/src/main/kotlin/com/teamscale/test/commons/SystemTestUtils.kt @@ -1,5 +1,6 @@ package com.teamscale.test.commons +import com.teamscale.client.FileSystemUtils import com.teamscale.client.SystemUtils import com.teamscale.report.testwise.model.TestInfo import okhttp3.MediaType.Companion.toMediaTypeOrNull @@ -48,24 +49,37 @@ object SystemTestUtils { /** * Runs the clean and verify goal of the Maven project at the given path with the provided arguments * + * @param removeEnvironmentVariables names of environment variables that Maven does not inherit. * @throws IOException if running Maven fails. */ @Throws(IOException::class) - fun runMavenTests(mavenProjectPath: String, vararg args: String) { + fun runMavenTests( + mavenProjectPath: String, + vararg args: String, + removeEnvironmentVariables: List = emptyList() + ): ProcessUtils.ProcessResult { val allArguments = mutableListOf("clean", "verify").apply { addAll(args) } - runMaven(mavenProjectPath, *allArguments.toTypedArray()) + return runMaven(mavenProjectPath, *allArguments.toTypedArray(), removeEnvironmentVariables = removeEnvironmentVariables) } /** - * Runs Maven in the given Maven project path with the given arguments. + * Runs Maven in the given Maven project path with the given arguments. A build that fails does not throw, so the + * caller must check the exit code of the returned result if it expects the build to succeed. * + * @param removeEnvironmentVariables names of environment variables that Maven does not inherit. * @throws IOException if running Maven fails. */ @Throws(IOException::class) - fun runMaven(mavenProjectPath: String, vararg mavenArguments: String) { - val result = buildMavenProcess(mavenProjectPath, *mavenArguments).execute() + fun runMaven( + mavenProjectPath: String, + vararg mavenArguments: String, + removeEnvironmentVariables: List = emptyList() + ): ProcessUtils.ProcessResult { + val result = buildMavenProcess(mavenProjectPath, *mavenArguments) + .removeEnvironmentVariables(removeEnvironmentVariables) + .execute() // in case the process succeeded, we still log stdout and stderr in case later assertions fail. This helps // debug test failures @@ -75,6 +89,20 @@ object SystemTestUtils { if (result.wasTerminatedByTimeoutOrInterruption) { throw IOException("Running Maven failed: ${result.stdout}\n${result.stderr}") } + return result + } + + /** + * Copies the Maven project at the given path into the given directory and makes its Maven wrapper executable. + * Tests use this to run a Maven project outside of this repository's Git checkout. + * + * @return the absolute path of the copied project. + */ + @Throws(IOException::class) + fun copyMavenProject(mavenProjectPath: String, targetDirectory: Path): String { + FileSystemUtils.copyFiles(File(mavenProjectPath), targetDirectory.toFile()) { true } + targetDirectory.resolve("mvnw").toFile().setExecutable(true) + return targetDirectory.toAbsolutePath().toString() } /** diff --git a/system-tests/maven-external-upload-test/src/test/kotlin/com/teamscale/upload/MavenExternalUploadSystemTest.kt b/system-tests/maven-external-upload-test/src/test/kotlin/com/teamscale/upload/MavenExternalUploadSystemTest.kt index fbb5c7b7c..5bc198cf2 100644 --- a/system-tests/maven-external-upload-test/src/test/kotlin/com/teamscale/upload/MavenExternalUploadSystemTest.kt +++ b/system-tests/maven-external-upload-test/src/test/kotlin/com/teamscale/upload/MavenExternalUploadSystemTest.kt @@ -2,10 +2,10 @@ package com.teamscale.upload import com.teamscale.client.EReportFormat import com.teamscale.client.EnvironmentVariableChecker -import com.teamscale.client.FileSystemUtils import com.teamscale.client.SystemUtils import com.teamscale.test.commons.ProcessUtils import com.teamscale.test.commons.SystemTestUtils +import com.teamscale.test.commons.SystemTestUtils.copyMavenProject import com.teamscale.test.commons.SystemTestUtils.runMavenTests import com.teamscale.test.commons.TeamscaleMockServer import org.assertj.core.api.Assertions @@ -108,9 +108,7 @@ class MavenExternalUploadSystemTest { @Throws(IOException::class) fun testCiEnvironmentVariableCommitResolution(@TempDir tmpDir: Path) { val fakeCommit = "abc123def456abc123def456abc123def456abc1" - FileSystemUtils.copyFiles(File("missing-commit-project"), tmpDir.toFile()) { true } - tmpDir.resolve("mvnw").toFile().setExecutable(true) - val projectPath = tmpDir.toAbsolutePath().toString() + val projectPath = copyMavenProject("missing-commit-project", tmpDir) runMavenTests(projectPath) val result = runCoverageUploadGoal( projectPath, @@ -131,9 +129,7 @@ class MavenExternalUploadSystemTest { @Test @Throws(IOException::class) fun testErrorMessageOnMissingCommit(@TempDir tmpDir: Path) { - FileSystemUtils.copyFiles(File("missing-commit-project"), tmpDir.toFile()) { true } - tmpDir.resolve("mvnw").toFile().setExecutable(true) - val projectPath = tmpDir.toAbsolutePath().toString() + val projectPath = copyMavenProject("missing-commit-project", tmpDir) runMavenTests(projectPath) val result = runCoverageUploadGoal(projectPath, removeEnvironmentVariables = EnvironmentVariableChecker.COMMIT_ENVIRONMENT_VARIABLES) assertThat(result).isNotNull() diff --git a/system-tests/tia-maven/src/test/kotlin/com/teamscale/tia/TiaMavenDumpToFileSystemTest.kt b/system-tests/tia-maven/src/test/kotlin/com/teamscale/tia/TiaMavenDumpToFileSystemTest.kt index 529d7c64d..1db0c1aed 100644 --- a/system-tests/tia-maven/src/test/kotlin/com/teamscale/tia/TiaMavenDumpToFileSystemTest.kt +++ b/system-tests/tia-maven/src/test/kotlin/com/teamscale/tia/TiaMavenDumpToFileSystemTest.kt @@ -1,9 +1,11 @@ package com.teamscale.tia +import com.teamscale.client.EnvironmentVariableChecker import com.teamscale.client.JsonUtils import com.teamscale.report.testwise.model.ETestExecutionResult import com.teamscale.report.testwise.model.TestwiseCoverageReport import com.teamscale.test.commons.SystemTestUtils +import com.teamscale.test.commons.SystemTestUtils.copyMavenProject import com.teamscale.test.commons.SystemTestUtils.coverage import com.teamscale.test.commons.SystemTestUtils.getReportFileNames import com.teamscale.test.commons.SystemTestUtils.runMavenTests @@ -13,8 +15,10 @@ import org.junit.jupiter.api.AfterEach import org.junit.jupiter.api.BeforeEach import org.junit.jupiter.api.Test import org.junit.jupiter.api.assertAll +import org.junit.jupiter.api.io.TempDir import java.io.IOException import java.nio.file.Files +import java.nio.file.Path /** * Runs several Maven projects' Surefire tests that have the agent attached and one of our JUnit run listeners enabled. @@ -39,7 +43,31 @@ class TiaMavenDumpToFileSystemTest { fun testMavenTia() { runMavenTests(MAVEN_PROJECT_NAME) - val unitTestReport = parseDumpedCoverageReport("tia") + assertCoverageReportsDumped(MAVEN_PROJECT_NAME) + } + + /** + * With `runImpacted=false`, the plugin must not require a commit or revision. So the build must succeed outside of + * a Git checkout and without CI environment variables (TS-48002). + */ + @Test + @Throws(Exception::class) + fun testMavenTiaWithoutCommit(@TempDir tmpDir: Path) { + val projectPath = copyMavenProject(MAVEN_PROJECT_NAME, tmpDir) + + val result = runMavenTests( + projectPath, + removeEnvironmentVariables = EnvironmentVariableChecker.COMMIT_ENVIRONMENT_VARIABLES + ) + + assertThat(result.exitCode) + .withFailMessage { "Maven failed:\n${result.stdout}\n${result.stderr}" } + .isEqualTo(0) + assertCoverageReportsDumped(projectPath) + } + + private fun assertCoverageReportsDumped(projectPath: String) { + val unitTestReport = parseDumpedCoverageReport(projectPath, "tia") assertThat(unitTestReport.tests).hasSize(2) assertThat(unitTestReport.partial).isFalse() assertAll({ @@ -54,7 +82,7 @@ class TiaMavenDumpToFileSystemTest { .containsExactly("SUT.java:3,6-7", "SUT.java:3,10-11") }) - val integrationTestReport = parseDumpedCoverageReport("tia-integration") + val integrationTestReport = parseDumpedCoverageReport(projectPath, "tia-integration") assertThat(integrationTestReport.tests).hasSize(2) assertAll({ assertThat(integrationTestReport.tests) @@ -70,8 +98,8 @@ class TiaMavenDumpToFileSystemTest { } @Throws(IOException::class) - private fun parseDumpedCoverageReport(folderName: String): TestwiseCoverageReport { - val files = getReportFileNames(MAVEN_PROJECT_NAME, folderName) + private fun parseDumpedCoverageReport(projectPath: String, folderName: String): TestwiseCoverageReport { + val files = getReportFileNames(projectPath, folderName) return JsonUtils.deserialize( String(Files.readAllBytes(files.first())) ) diff --git a/teamscale-maven-plugin/src/main/java/com/teamscale/maven/tia/TiaMojoBase.java b/teamscale-maven-plugin/src/main/java/com/teamscale/maven/tia/TiaMojoBase.java index 1918d71b7..486b197f7 100644 --- a/teamscale-maven-plugin/src/main/java/com/teamscale/maven/tia/TiaMojoBase.java +++ b/teamscale-maven-plugin/src/main/java/com/teamscale/maven/tia/TiaMojoBase.java @@ -138,6 +138,8 @@ public abstract class TiaMojoBase extends TeamscaleMojoBase { /** * Executes only impacted tests, not all ones if set. Defaults to true. + *

+ * The commit or revision of the code under test is only resolved, and therefore only required, if this is set. */ @Parameter(defaultValue = "true", property = "runImpacted") public boolean runImpacted; @@ -180,7 +182,10 @@ public void execute() throws MojoFailureException, MojoExecutionException { targetDirectory = Paths.get(projectBuildDir, getOutputDirectoryName()).toAbsolutePath(); createTargetDirectory(); - resolveCommitOrRevision(); + // The impacted test engine only needs the commit to query Teamscale for the impacted tests + if (runImpacted) { + resolveCommitOrRevision(); + } setTiaProperties();