Skip to content

Commit 983bf0f

Browse files
Add a smoke test for Gradle Launcher instrumentation (#8014)
1 parent c21d4a5 commit 983bf0f

File tree

10 files changed

+421
-112
lines changed

10 files changed

+421
-112
lines changed

dd-java-agent/agent-ci-visibility/src/main/java/datadog/trace/civisibility/utils/ShellCommandExecutor.java

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,8 @@
1111
import java.io.IOException;
1212
import java.io.InputStream;
1313
import java.nio.charset.Charset;
14+
import java.util.Collections;
15+
import java.util.Map;
1416
import java.util.concurrent.TimeUnit;
1517
import java.util.concurrent.TimeoutException;
1618
import org.slf4j.Logger;
@@ -24,10 +26,17 @@ public class ShellCommandExecutor {
2426

2527
private final File executionFolder;
2628
private final long timeoutMillis;
29+
private final Map<String, String> environment;
2730

2831
public ShellCommandExecutor(File executionFolder, long timeoutMillis) {
32+
this(executionFolder, timeoutMillis, Collections.emptyMap());
33+
}
34+
35+
public ShellCommandExecutor(
36+
File executionFolder, long timeoutMillis, Map<String, String> environment) {
2937
this.executionFolder = executionFolder;
3038
this.timeoutMillis = timeoutMillis;
39+
this.environment = environment;
3140
}
3241

3342
/**
@@ -92,6 +101,10 @@ private <T> T executeCommand(
92101
ProcessBuilder processBuilder = new ProcessBuilder(command);
93102
processBuilder.directory(executionFolder);
94103

104+
if (!environment.isEmpty()) {
105+
processBuilder.environment().putAll(environment);
106+
}
107+
95108
p = processBuilder.start();
96109

97110
StreamConsumer inputStreamConsumer = new StreamConsumer(p.getInputStream());

dd-smoke-tests/gradle/build.gradle

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,6 @@
1+
import java.time.Duration
2+
import java.time.temporal.ChronoUnit
3+
14
plugins {
25
id "com.github.johnrengelman.shadow"
36
}
@@ -14,5 +17,9 @@ test {
1417
testLogging {
1518
events "passed", "skipped", "failed", "standardOut", "standardError"
1619
}
20+
21+
// overriding the default timeout of 9 minutes set in configure_tests.gradle,
22+
// as Gradle smoke tests might run for a longer duration
23+
timeout = Duration.of(15, ChronoUnit.MINUTES)
1724
}
1825

Lines changed: 144 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,144 @@
1+
package datadog.smoketest
2+
3+
import com.fasterxml.jackson.databind.JsonNode
4+
import com.fasterxml.jackson.databind.ObjectMapper
5+
import datadog.trace.api.Platform
6+
import datadog.trace.civisibility.CiVisibilitySmokeTest
7+
import okhttp3.OkHttpClient
8+
import okhttp3.Request
9+
import okhttp3.Response
10+
import org.gradle.internal.impldep.org.apache.commons.io.FileUtils
11+
import org.gradle.util.GradleVersion
12+
import org.junit.jupiter.api.Assumptions
13+
import spock.lang.AutoCleanup
14+
import spock.lang.Shared
15+
import spock.lang.TempDir
16+
import spock.util.environment.Jvm
17+
18+
import java.nio.charset.StandardCharsets
19+
import java.nio.file.FileVisitResult
20+
import java.nio.file.Files
21+
import java.nio.file.Path
22+
import java.nio.file.Paths
23+
import java.nio.file.SimpleFileVisitor
24+
import java.nio.file.attribute.BasicFileAttributes
25+
import java.util.regex.Matcher
26+
import java.util.regex.Pattern
27+
28+
class AbstractGradleTest extends CiVisibilitySmokeTest {
29+
30+
static final String LATEST_GRADLE_VERSION = getLatestGradleVersion()
31+
32+
// test resources use this instead of ".gradle" to avoid unwanted evaluation
33+
private static final String GRADLE_TEST_RESOURCE_EXTENSION = ".gradleTest"
34+
private static final String GRADLE_REGULAR_EXTENSION = ".gradle"
35+
36+
@TempDir
37+
protected Path projectFolder
38+
39+
@Shared
40+
@AutoCleanup
41+
protected MockBackend mockBackend = new MockBackend()
42+
43+
def setup() {
44+
mockBackend.reset()
45+
}
46+
47+
private static final Pattern PLACEHOLDER_PATTERN = Pattern.compile('\\$\\{(.+?)\\}')
48+
49+
protected void givenGradleProjectFiles(String projectFilesSources, Map<String, Map<String, String>> replacementsByFileName = [:]) {
50+
def projectResourcesUri = this.getClass().getClassLoader().getResource(projectFilesSources).toURI()
51+
def projectResourcesPath = Paths.get(projectResourcesUri)
52+
FileUtils.copyDirectory(projectResourcesPath.toFile(), projectFolder.toFile())
53+
54+
Files.walkFileTree(projectFolder, new SimpleFileVisitor<Path>() {
55+
@Override
56+
FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException {
57+
def replacements = replacementsByFileName.get(file.getFileName().toString())
58+
if (replacements != null) {
59+
def fileContents = new String(Files.readAllBytes(file), StandardCharsets.UTF_8)
60+
Matcher matcher = PLACEHOLDER_PATTERN.matcher(fileContents)
61+
62+
StringBuffer result = new StringBuffer()
63+
while (matcher.find()) {
64+
String propertyName = matcher.group(1)
65+
String replacement = replacements.getOrDefault(propertyName, matcher.group(0))
66+
matcher.appendReplacement(result, Matcher.quoteReplacement(replacement))
67+
}
68+
matcher.appendTail(result)
69+
70+
Files.write(file, result.toString().getBytes(StandardCharsets.UTF_8))
71+
}
72+
73+
if (file.toString().endsWith(GRADLE_TEST_RESOURCE_EXTENSION)) {
74+
def fileWithFixedExtension = Paths.get(file.toString().replace(GRADLE_TEST_RESOURCE_EXTENSION, GRADLE_REGULAR_EXTENSION))
75+
Files.move(file, fileWithFixedExtension)
76+
}
77+
78+
return FileVisitResult.CONTINUE
79+
}
80+
})
81+
82+
// creating empty .git directory so that the tracer could detect projectFolder as repo root
83+
Files.createDirectory(projectFolder.resolve(".git"))
84+
}
85+
86+
protected void givenGradleVersionIsCompatibleWithCurrentJvm(String gradleVersion) {
87+
Assumptions.assumeTrue(isSupported(gradleVersion),
88+
"Current JVM " + Jvm.current.javaVersion + " does not support Gradle version " + gradleVersion)
89+
}
90+
91+
private static boolean isSupported(String gradleVersion) {
92+
// https://docs.gradle.org/current/userguide/compatibility.html
93+
if (Jvm.current.java21Compatible) {
94+
return gradleVersion >= "8.4"
95+
} else if (Jvm.current.java20) {
96+
return gradleVersion >= "8.1"
97+
} else if (Jvm.current.java19) {
98+
return gradleVersion >= "7.6"
99+
} else if (Jvm.current.java18) {
100+
return gradleVersion >= "7.5"
101+
} else if (Jvm.current.java17) {
102+
return gradleVersion >= "7.3"
103+
} else if (Jvm.current.java16) {
104+
return gradleVersion >= "7.0"
105+
} else if (Jvm.current.java15) {
106+
return gradleVersion >= "6.7"
107+
} else if (Jvm.current.java14) {
108+
return gradleVersion >= "6.3"
109+
} else if (Jvm.current.java13) {
110+
return gradleVersion >= "6.0"
111+
} else if (Jvm.current.java12) {
112+
return gradleVersion >= "5.4"
113+
} else if (Jvm.current.java11) {
114+
return gradleVersion >= "5.0"
115+
} else if (Jvm.current.java10) {
116+
return gradleVersion >= "4.7"
117+
} else if (Jvm.current.java9) {
118+
return gradleVersion >= "4.3"
119+
} else if (Jvm.current.java8) {
120+
return gradleVersion >= "2.0"
121+
}
122+
return false
123+
}
124+
125+
protected void givenConfigurationCacheIsCompatibleWithCurrentPlatform(boolean configurationCacheEnabled) {
126+
if (configurationCacheEnabled) {
127+
Assumptions.assumeFalse(Platform.isIbm8(), "Configuration cache is not compatible with IBM 8")
128+
}
129+
}
130+
131+
private static String getLatestGradleVersion() {
132+
OkHttpClient client = new OkHttpClient()
133+
Request request = new Request.Builder().url("https://services.gradle.org/versions/current").build()
134+
try (Response response = client.newCall(request).execute()) {
135+
if (!response.successful) {
136+
return GradleVersion.current().version
137+
}
138+
def responseBody = response.body().string()
139+
ObjectMapper mapper = new ObjectMapper()
140+
JsonNode root = mapper.readTree(responseBody)
141+
return root.get("version").asText()
142+
}
143+
}
144+
}

dd-smoke-tests/gradle/src/test/groovy/datadog/smoketest/GradleDaemonSmokeTest.groovy

Lines changed: 2 additions & 112 deletions
Original file line numberDiff line numberDiff line change
@@ -1,52 +1,32 @@
11
package datadog.smoketest
22

3-
import com.fasterxml.jackson.databind.JsonNode
4-
import com.fasterxml.jackson.databind.ObjectMapper
3+
54
import datadog.trace.api.Config
65
import datadog.trace.api.Platform
76
import datadog.trace.api.config.CiVisibilityConfig
87
import datadog.trace.api.config.GeneralConfig
9-
import datadog.trace.civisibility.CiVisibilitySmokeTest
108
import datadog.trace.util.Strings
11-
import okhttp3.OkHttpClient
12-
import okhttp3.Request
13-
import okhttp3.Response
14-
import org.gradle.internal.impldep.org.apache.commons.io.FileUtils
159
import org.gradle.testkit.runner.BuildResult
1610
import org.gradle.testkit.runner.GradleRunner
1711
import org.gradle.testkit.runner.TaskOutcome
1812
import org.gradle.util.DistributionLocator
1913
import org.gradle.util.GradleVersion
2014
import org.gradle.wrapper.Download
21-
import org.gradle.wrapper.GradleUserHomeLookup
2215
import org.gradle.wrapper.Install
2316
import org.gradle.wrapper.PathAssembler
2417
import org.gradle.wrapper.WrapperConfiguration
25-
import org.junit.jupiter.api.Assumptions
26-
import spock.lang.AutoCleanup
2718
import spock.lang.IgnoreIf
2819
import spock.lang.Shared
2920
import spock.lang.TempDir
30-
import spock.util.environment.Jvm
3121

32-
import java.nio.file.FileVisitResult
3322
import java.nio.file.Files
3423
import java.nio.file.Path
35-
import java.nio.file.Paths
36-
import java.nio.file.SimpleFileVisitor
37-
import java.nio.file.attribute.BasicFileAttributes
38-
39-
class GradleDaemonSmokeTest extends CiVisibilitySmokeTest {
4024

41-
private static final String LATEST_GRADLE_VERSION = getLatestGradleVersion()
25+
class GradleDaemonSmokeTest extends AbstractGradleTest {
4226

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

46-
// test resources use this instead of ".gradle" to avoid unwanted evaluation
47-
private static final String GRADLE_TEST_RESOURCE_EXTENSION = ".gradleTest"
48-
private static final String GRADLE_REGULAR_EXTENSION = ".gradle"
49-
5030
private static final int GRADLE_DISTRIBUTION_NETWORK_TIMEOUT = 30_000 // Gradle's default timeout is 10s
5131

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

61-
@TempDir
62-
Path projectFolder
63-
64-
@Shared
65-
@AutoCleanup
66-
MockBackend mockBackend = new MockBackend()
67-
6841
def setupSpec() {
6942
givenGradleProperties()
7043
}
7144

72-
def setup() {
73-
mockBackend.reset()
74-
}
75-
7645
@IgnoreIf(reason = "Jacoco plugin does not work with OpenJ9 in older Gradle versions", value = {
7746
Platform.isJ9()
7847
})
@@ -168,26 +137,6 @@ class GradleDaemonSmokeTest extends CiVisibilitySmokeTest {
168137
Files.write(testKitFolder.resolve("gradle.properties"), gradleProperties.getBytes())
169138
}
170139

171-
private void givenGradleProjectFiles(String projectFilesSources) {
172-
def projectResourcesUri = this.getClass().getClassLoader().getResource(projectFilesSources).toURI()
173-
def projectResourcesPath = Paths.get(projectResourcesUri)
174-
FileUtils.copyDirectory(projectResourcesPath.toFile(), projectFolder.toFile())
175-
176-
Files.walkFileTree(projectFolder, new SimpleFileVisitor<Path>() {
177-
@Override
178-
FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException {
179-
if (file.toString().endsWith(GRADLE_TEST_RESOURCE_EXTENSION)) {
180-
def fileWithFixedExtension = Paths.get(file.toString().replace(GRADLE_TEST_RESOURCE_EXTENSION, GRADLE_REGULAR_EXTENSION))
181-
Files.move(file, fileWithFixedExtension)
182-
}
183-
return FileVisitResult.CONTINUE
184-
}
185-
})
186-
187-
// creating empty .git directory so that the tracer could detect projectFolder as repo root
188-
Files.createDirectory(projectFolder.resolve(".git"))
189-
}
190-
191140
private BuildResult runGradleTests(String gradleVersion, boolean successExpected = true, boolean configurationCache = false) {
192141
def arguments = ["test", "--stacktrace"]
193142
if (gradleVersion > "4.5") {
@@ -255,63 +204,4 @@ class GradleDaemonSmokeTest extends CiVisibilitySmokeTest {
255204
assert task.outcome != TaskOutcome.FAILED
256205
}
257206
}
258-
259-
void givenGradleVersionIsCompatibleWithCurrentJvm(String gradleVersion) {
260-
Assumptions.assumeTrue(isSupported(gradleVersion),
261-
"Current JVM " + Jvm.current.javaVersion + " does not support Gradle version " + gradleVersion)
262-
}
263-
264-
private static boolean isSupported(String gradleVersion) {
265-
// https://docs.gradle.org/current/userguide/compatibility.html
266-
if (Jvm.current.java21Compatible) {
267-
return gradleVersion >= "8.4"
268-
} else if (Jvm.current.java20) {
269-
return gradleVersion >= "8.1"
270-
} else if (Jvm.current.java19) {
271-
return gradleVersion >= "7.6"
272-
} else if (Jvm.current.java18) {
273-
return gradleVersion >= "7.5"
274-
} else if (Jvm.current.java17) {
275-
return gradleVersion >= "7.3"
276-
} else if (Jvm.current.java16) {
277-
return gradleVersion >= "7.0"
278-
} else if (Jvm.current.java15) {
279-
return gradleVersion >= "6.7"
280-
} else if (Jvm.current.java14) {
281-
return gradleVersion >= "6.3"
282-
} else if (Jvm.current.java13) {
283-
return gradleVersion >= "6.0"
284-
} else if (Jvm.current.java12) {
285-
return gradleVersion >= "5.4"
286-
} else if (Jvm.current.java11) {
287-
return gradleVersion >= "5.0"
288-
} else if (Jvm.current.java10) {
289-
return gradleVersion >= "4.7"
290-
} else if (Jvm.current.java9) {
291-
return gradleVersion >= "4.3"
292-
} else if (Jvm.current.java8) {
293-
return gradleVersion >= "2.0"
294-
}
295-
return false
296-
}
297-
298-
void givenConfigurationCacheIsCompatibleWithCurrentPlatform(boolean configurationCacheEnabled) {
299-
if (configurationCacheEnabled) {
300-
Assumptions.assumeFalse(Platform.isIbm8(), "Configuration cache is not compatible with IBM 8")
301-
}
302-
}
303-
304-
private static String getLatestGradleVersion() {
305-
OkHttpClient client = new OkHttpClient()
306-
Request request = new Request.Builder().url("https://services.gradle.org/versions/current").build()
307-
try (Response response = client.newCall(request).execute()) {
308-
if (!response.successful) {
309-
return GradleVersion.current().version
310-
}
311-
def responseBody = response.body().string()
312-
ObjectMapper mapper = new ObjectMapper()
313-
JsonNode root = mapper.readTree(responseBody)
314-
return root.get("version").asText()
315-
}
316-
}
317207
}

0 commit comments

Comments
 (0)