-
Notifications
You must be signed in to change notification settings - Fork 335
Expand file tree
/
Copy pathCallSiteInstrumentationPluginTest.groovy
More file actions
138 lines (111 loc) · 4.77 KB
/
CallSiteInstrumentationPluginTest.groovy
File metadata and controls
138 lines (111 loc) · 4.77 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
import org.gradle.testkit.runner.BuildResult
import org.gradle.testkit.runner.GradleRunner
import org.gradle.testkit.runner.UnexpectedBuildFailure
import spock.lang.Specification
import spock.lang.TempDir
class CallSiteInstrumentationPluginTest extends Specification {
def buildGradle = '''
plugins {
id 'java'
id 'call-site-instrumentation'
id("com.diffplug.spotless") version "6.13.0"
}
sourceCompatibility = JavaVersion.VERSION_1_8
targetCompatibility = JavaVersion.VERSION_1_8
csi {
suffix = 'CallSite'
targetFolder = 'csi'
rootFolder = file('$$ROOT_FOLDER$$')
}
repositories {
mavenCentral()
}
dependencies {
implementation group: 'net.bytebuddy', name: 'byte-buddy', version: '1.15.11'
implementation group: 'com.google.auto.service', name: 'auto-service-annotations', version: '1.0-rc7'
}
'''
@TempDir
File buildDir
def 'test call site instrumentation plugin'() {
setup:
createGradleProject(buildDir, buildGradle, '''
import datadog.trace.agent.tooling.csi.*;
@CallSite(spi = CallSites.class)
public class BeforeAdviceCallSite {
@CallSite.Before("java.lang.StringBuilder java.lang.StringBuilder.append(java.lang.String)")
public static void beforeAppend(@CallSite.This final StringBuilder self, @CallSite.Argument final String param) {
}
}
''')
when:
final result = buildGradleProject(buildDir)
then:
final generated = resolve(buildDir, 'build', 'csi', 'BeforeAdviceCallSites.java')
generated.exists()
final output = result.output
!output.contains('[⨉]')
output.contains('[✓] @CallSite BeforeAdviceCallSite')
}
def 'test call site instrumentation plugin with error'() {
setup:
createGradleProject(buildDir, buildGradle, '''
import datadog.trace.agent.tooling.csi.*;
@CallSite(spi = CallSites.class)
public class BeforeAdviceCallSite {
@CallSite.Before("java.lang.StringBuilder java.lang.StringBuilder.append(java.lang.String)")
private void beforeAppend(@CallSite.This final StringBuilder self, @CallSite.Argument final String param) {
}
}
''')
when:
buildGradleProject(buildDir)
then:
final error = thrown(UnexpectedBuildFailure)
final generated = resolve(buildDir, 'build', 'csi', 'BeforeAdviceCallSites.java')
!generated.exists()
final output = error.message
!output.contains('[✓]')
output.contains('ADVICE_METHOD_NOT_STATIC_AND_PUBLIC')
}
private static void createGradleProject(final File buildDir, final String gradleFile, final String advice) {
final projectFolder = new File(System.getProperty('user.dir')).parentFile
final callSiteJar = resolve(projectFolder, 'buildSrc', 'call-site-instrumentation-plugin')
final gradleFileContent = gradleFile.replace('$$ROOT_FOLDER$$', projectFolder.toString().replace("\\","\\\\"))
final buildGradle = resolve(buildDir, 'build.gradle')
buildGradle.text = gradleFileContent
final javaFolder = resolve(buildDir, 'src', 'main', 'java')
javaFolder.mkdirs()
final advicePackage = parsePackage(advice)
final adviceClassName = parseClassName(advice)
final adviceFolder = resolve(javaFolder, advicePackage.split('\\.'))
adviceFolder.mkdirs()
final adviceFile = resolve(adviceFolder, "${adviceClassName}.java")
adviceFile.text = advice
final csiSource = resolve(projectFolder, 'dd-java-agent', 'agent-tooling', 'src', 'main', 'java', 'datadog', 'trace', 'agent', 'tooling', 'csi')
final csiTarget = resolve(javaFolder, 'datadog', 'trace', 'agent', 'tooling', 'csi')
csiTarget.mkdirs()
csiSource.listFiles().each { new File(csiTarget, it.name).text = it.text }
}
private static BuildResult buildGradleProject(final File buildDir) {
return GradleRunner.create()
.withTestKitDir(new File(buildDir, '.gradle-test-kit')) // workaround in case the global test-kit cache becomes corrupted
.withDebug(true) // avoids starting daemon which can leave undeleted files post-cleanup
.withProjectDir(buildDir)
.withArguments('build', '--info', '--stacktrace')
.withPluginClasspath()
.forwardOutput()
.build()
}
private static String parsePackage(final String advice) {
final advicePackageMatcher = advice =~ /(?s).*package\s+([\w\.]+)\s*;/
return advicePackageMatcher ? advicePackageMatcher[0][1] as String : ''
}
private static String parseClassName(final String advice) {
return (advice =~ /(?s).*class\s+(\w+)\s+\{\.*/)[0][1]
}
private static File resolve(final File file, final String...path) {
final result = path.inject(file.toPath()) {parent, folder -> parent.resolve(folder)}
return result.toFile()
}
}