Skip to content

Commit

Permalink
Add a smoke test for Gradle Launcher instrumentation (#8014)
Browse files Browse the repository at this point in the history
  • Loading branch information
nikita-tkachenko-datadog authored Nov 26, 2024
1 parent c21d4a5 commit 983bf0f
Show file tree
Hide file tree
Showing 10 changed files with 421 additions and 112 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@
import java.io.IOException;
import java.io.InputStream;
import java.nio.charset.Charset;
import java.util.Collections;
import java.util.Map;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
import org.slf4j.Logger;
Expand All @@ -24,10 +26,17 @@ public class ShellCommandExecutor {

private final File executionFolder;
private final long timeoutMillis;
private final Map<String, String> environment;

public ShellCommandExecutor(File executionFolder, long timeoutMillis) {
this(executionFolder, timeoutMillis, Collections.emptyMap());
}

public ShellCommandExecutor(
File executionFolder, long timeoutMillis, Map<String, String> environment) {
this.executionFolder = executionFolder;
this.timeoutMillis = timeoutMillis;
this.environment = environment;
}

/**
Expand Down Expand Up @@ -92,6 +101,10 @@ private <T> T executeCommand(
ProcessBuilder processBuilder = new ProcessBuilder(command);
processBuilder.directory(executionFolder);

if (!environment.isEmpty()) {
processBuilder.environment().putAll(environment);
}

p = processBuilder.start();

StreamConsumer inputStreamConsumer = new StreamConsumer(p.getInputStream());
Expand Down
7 changes: 7 additions & 0 deletions dd-smoke-tests/gradle/build.gradle
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
import java.time.Duration
import java.time.temporal.ChronoUnit

plugins {
id "com.github.johnrengelman.shadow"
}
Expand All @@ -14,5 +17,9 @@ test {
testLogging {
events "passed", "skipped", "failed", "standardOut", "standardError"
}

// overriding the default timeout of 9 minutes set in configure_tests.gradle,
// as Gradle smoke tests might run for a longer duration
timeout = Duration.of(15, ChronoUnit.MINUTES)
}

Original file line number Diff line number Diff line change
@@ -0,0 +1,144 @@
package datadog.smoketest

import com.fasterxml.jackson.databind.JsonNode
import com.fasterxml.jackson.databind.ObjectMapper
import datadog.trace.api.Platform
import datadog.trace.civisibility.CiVisibilitySmokeTest
import okhttp3.OkHttpClient
import okhttp3.Request
import okhttp3.Response
import org.gradle.internal.impldep.org.apache.commons.io.FileUtils
import org.gradle.util.GradleVersion
import org.junit.jupiter.api.Assumptions
import spock.lang.AutoCleanup
import spock.lang.Shared
import spock.lang.TempDir
import spock.util.environment.Jvm

import java.nio.charset.StandardCharsets
import java.nio.file.FileVisitResult
import java.nio.file.Files
import java.nio.file.Path
import java.nio.file.Paths
import java.nio.file.SimpleFileVisitor
import java.nio.file.attribute.BasicFileAttributes
import java.util.regex.Matcher
import java.util.regex.Pattern

class AbstractGradleTest extends CiVisibilitySmokeTest {

static final String LATEST_GRADLE_VERSION = getLatestGradleVersion()

// test resources use this instead of ".gradle" to avoid unwanted evaluation
private static final String GRADLE_TEST_RESOURCE_EXTENSION = ".gradleTest"
private static final String GRADLE_REGULAR_EXTENSION = ".gradle"

@TempDir
protected Path projectFolder

@Shared
@AutoCleanup
protected MockBackend mockBackend = new MockBackend()

def setup() {
mockBackend.reset()
}

private static final Pattern PLACEHOLDER_PATTERN = Pattern.compile('\\$\\{(.+?)\\}')

protected void givenGradleProjectFiles(String projectFilesSources, Map<String, Map<String, String>> replacementsByFileName = [:]) {
def projectResourcesUri = this.getClass().getClassLoader().getResource(projectFilesSources).toURI()
def projectResourcesPath = Paths.get(projectResourcesUri)
FileUtils.copyDirectory(projectResourcesPath.toFile(), projectFolder.toFile())

Files.walkFileTree(projectFolder, new SimpleFileVisitor<Path>() {
@Override
FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException {
def replacements = replacementsByFileName.get(file.getFileName().toString())
if (replacements != null) {
def fileContents = new String(Files.readAllBytes(file), StandardCharsets.UTF_8)
Matcher matcher = PLACEHOLDER_PATTERN.matcher(fileContents)

StringBuffer result = new StringBuffer()
while (matcher.find()) {
String propertyName = matcher.group(1)
String replacement = replacements.getOrDefault(propertyName, matcher.group(0))
matcher.appendReplacement(result, Matcher.quoteReplacement(replacement))
}
matcher.appendTail(result)

Files.write(file, result.toString().getBytes(StandardCharsets.UTF_8))
}

if (file.toString().endsWith(GRADLE_TEST_RESOURCE_EXTENSION)) {
def fileWithFixedExtension = Paths.get(file.toString().replace(GRADLE_TEST_RESOURCE_EXTENSION, GRADLE_REGULAR_EXTENSION))
Files.move(file, fileWithFixedExtension)
}

return FileVisitResult.CONTINUE
}
})

// creating empty .git directory so that the tracer could detect projectFolder as repo root
Files.createDirectory(projectFolder.resolve(".git"))
}

protected void givenGradleVersionIsCompatibleWithCurrentJvm(String gradleVersion) {
Assumptions.assumeTrue(isSupported(gradleVersion),
"Current JVM " + Jvm.current.javaVersion + " does not support Gradle version " + gradleVersion)
}

private static boolean isSupported(String gradleVersion) {
// https://docs.gradle.org/current/userguide/compatibility.html
if (Jvm.current.java21Compatible) {
return gradleVersion >= "8.4"
} else if (Jvm.current.java20) {
return gradleVersion >= "8.1"
} else if (Jvm.current.java19) {
return gradleVersion >= "7.6"
} else if (Jvm.current.java18) {
return gradleVersion >= "7.5"
} else if (Jvm.current.java17) {
return gradleVersion >= "7.3"
} else if (Jvm.current.java16) {
return gradleVersion >= "7.0"
} else if (Jvm.current.java15) {
return gradleVersion >= "6.7"
} else if (Jvm.current.java14) {
return gradleVersion >= "6.3"
} else if (Jvm.current.java13) {
return gradleVersion >= "6.0"
} else if (Jvm.current.java12) {
return gradleVersion >= "5.4"
} else if (Jvm.current.java11) {
return gradleVersion >= "5.0"
} else if (Jvm.current.java10) {
return gradleVersion >= "4.7"
} else if (Jvm.current.java9) {
return gradleVersion >= "4.3"
} else if (Jvm.current.java8) {
return gradleVersion >= "2.0"
}
return false
}

protected void givenConfigurationCacheIsCompatibleWithCurrentPlatform(boolean configurationCacheEnabled) {
if (configurationCacheEnabled) {
Assumptions.assumeFalse(Platform.isIbm8(), "Configuration cache is not compatible with IBM 8")
}
}

private static String getLatestGradleVersion() {
OkHttpClient client = new OkHttpClient()
Request request = new Request.Builder().url("https://services.gradle.org/versions/current").build()
try (Response response = client.newCall(request).execute()) {
if (!response.successful) {
return GradleVersion.current().version
}
def responseBody = response.body().string()
ObjectMapper mapper = new ObjectMapper()
JsonNode root = mapper.readTree(responseBody)
return root.get("version").asText()
}
}
}
Original file line number Diff line number Diff line change
@@ -1,52 +1,32 @@
package datadog.smoketest

import com.fasterxml.jackson.databind.JsonNode
import com.fasterxml.jackson.databind.ObjectMapper

import datadog.trace.api.Config
import datadog.trace.api.Platform
import datadog.trace.api.config.CiVisibilityConfig
import datadog.trace.api.config.GeneralConfig
import datadog.trace.civisibility.CiVisibilitySmokeTest
import datadog.trace.util.Strings
import okhttp3.OkHttpClient
import okhttp3.Request
import okhttp3.Response
import org.gradle.internal.impldep.org.apache.commons.io.FileUtils
import org.gradle.testkit.runner.BuildResult
import org.gradle.testkit.runner.GradleRunner
import org.gradle.testkit.runner.TaskOutcome
import org.gradle.util.DistributionLocator
import org.gradle.util.GradleVersion
import org.gradle.wrapper.Download
import org.gradle.wrapper.GradleUserHomeLookup
import org.gradle.wrapper.Install
import org.gradle.wrapper.PathAssembler
import org.gradle.wrapper.WrapperConfiguration
import org.junit.jupiter.api.Assumptions
import spock.lang.AutoCleanup
import spock.lang.IgnoreIf
import spock.lang.Shared
import spock.lang.TempDir
import spock.util.environment.Jvm

import java.nio.file.FileVisitResult
import java.nio.file.Files
import java.nio.file.Path
import java.nio.file.Paths
import java.nio.file.SimpleFileVisitor
import java.nio.file.attribute.BasicFileAttributes

class GradleDaemonSmokeTest extends CiVisibilitySmokeTest {

private static final String LATEST_GRADLE_VERSION = getLatestGradleVersion()
class GradleDaemonSmokeTest extends AbstractGradleTest {

private static final String TEST_SERVICE_NAME = "test-gradle-service"
private static final String TEST_ENVIRONMENT_NAME = "integration-test"

// test resources use this instead of ".gradle" to avoid unwanted evaluation
private static final String GRADLE_TEST_RESOURCE_EXTENSION = ".gradleTest"
private static final String GRADLE_REGULAR_EXTENSION = ".gradle"

private static final int GRADLE_DISTRIBUTION_NETWORK_TIMEOUT = 30_000 // Gradle's default timeout is 10s

private static final String JACOCO_PLUGIN_VERSION = Config.get().ciVisibilityJacocoPluginVersion
Expand All @@ -58,21 +38,10 @@ class GradleDaemonSmokeTest extends CiVisibilitySmokeTest {
@TempDir
Path testKitFolder

@TempDir
Path projectFolder

@Shared
@AutoCleanup
MockBackend mockBackend = new MockBackend()

def setupSpec() {
givenGradleProperties()
}

def setup() {
mockBackend.reset()
}

@IgnoreIf(reason = "Jacoco plugin does not work with OpenJ9 in older Gradle versions", value = {
Platform.isJ9()
})
Expand Down Expand Up @@ -168,26 +137,6 @@ class GradleDaemonSmokeTest extends CiVisibilitySmokeTest {
Files.write(testKitFolder.resolve("gradle.properties"), gradleProperties.getBytes())
}

private void givenGradleProjectFiles(String projectFilesSources) {
def projectResourcesUri = this.getClass().getClassLoader().getResource(projectFilesSources).toURI()
def projectResourcesPath = Paths.get(projectResourcesUri)
FileUtils.copyDirectory(projectResourcesPath.toFile(), projectFolder.toFile())

Files.walkFileTree(projectFolder, new SimpleFileVisitor<Path>() {
@Override
FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException {
if (file.toString().endsWith(GRADLE_TEST_RESOURCE_EXTENSION)) {
def fileWithFixedExtension = Paths.get(file.toString().replace(GRADLE_TEST_RESOURCE_EXTENSION, GRADLE_REGULAR_EXTENSION))
Files.move(file, fileWithFixedExtension)
}
return FileVisitResult.CONTINUE
}
})

// creating empty .git directory so that the tracer could detect projectFolder as repo root
Files.createDirectory(projectFolder.resolve(".git"))
}

private BuildResult runGradleTests(String gradleVersion, boolean successExpected = true, boolean configurationCache = false) {
def arguments = ["test", "--stacktrace"]
if (gradleVersion > "4.5") {
Expand Down Expand Up @@ -255,63 +204,4 @@ class GradleDaemonSmokeTest extends CiVisibilitySmokeTest {
assert task.outcome != TaskOutcome.FAILED
}
}

void givenGradleVersionIsCompatibleWithCurrentJvm(String gradleVersion) {
Assumptions.assumeTrue(isSupported(gradleVersion),
"Current JVM " + Jvm.current.javaVersion + " does not support Gradle version " + gradleVersion)
}

private static boolean isSupported(String gradleVersion) {
// https://docs.gradle.org/current/userguide/compatibility.html
if (Jvm.current.java21Compatible) {
return gradleVersion >= "8.4"
} else if (Jvm.current.java20) {
return gradleVersion >= "8.1"
} else if (Jvm.current.java19) {
return gradleVersion >= "7.6"
} else if (Jvm.current.java18) {
return gradleVersion >= "7.5"
} else if (Jvm.current.java17) {
return gradleVersion >= "7.3"
} else if (Jvm.current.java16) {
return gradleVersion >= "7.0"
} else if (Jvm.current.java15) {
return gradleVersion >= "6.7"
} else if (Jvm.current.java14) {
return gradleVersion >= "6.3"
} else if (Jvm.current.java13) {
return gradleVersion >= "6.0"
} else if (Jvm.current.java12) {
return gradleVersion >= "5.4"
} else if (Jvm.current.java11) {
return gradleVersion >= "5.0"
} else if (Jvm.current.java10) {
return gradleVersion >= "4.7"
} else if (Jvm.current.java9) {
return gradleVersion >= "4.3"
} else if (Jvm.current.java8) {
return gradleVersion >= "2.0"
}
return false
}

void givenConfigurationCacheIsCompatibleWithCurrentPlatform(boolean configurationCacheEnabled) {
if (configurationCacheEnabled) {
Assumptions.assumeFalse(Platform.isIbm8(), "Configuration cache is not compatible with IBM 8")
}
}

private static String getLatestGradleVersion() {
OkHttpClient client = new OkHttpClient()
Request request = new Request.Builder().url("https://services.gradle.org/versions/current").build()
try (Response response = client.newCall(request).execute()) {
if (!response.successful) {
return GradleVersion.current().version
}
def responseBody = response.body().string()
ObjectMapper mapper = new ObjectMapper()
JsonNode root = mapper.readTree(responseBody)
return root.get("version").asText()
}
}
}
Loading

0 comments on commit 983bf0f

Please sign in to comment.