Skip to content

Commit 817895b

Browse files
committed
Extract shared tests into abstract parent
1 parent cde02e1 commit 817895b

4 files changed

Lines changed: 392 additions & 591 deletions

File tree

Lines changed: 323 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,323 @@
1+
import datadog.trace.agent.test.AgentTestRunner
2+
import datadog.trace.agent.test.TestUtils
3+
import datadog.trace.agent.test.utils.OkHttpUtils
4+
import datadog.trace.api.DDSpanTypes
5+
import datadog.trace.api.DDTags
6+
import okhttp3.Credentials
7+
import okhttp3.Interceptor
8+
import okhttp3.OkHttpClient
9+
import okhttp3.Request
10+
import okhttp3.Response
11+
import org.apache.catalina.core.ApplicationFilterChain
12+
import spock.lang.Shared
13+
import spock.lang.Unroll
14+
15+
import javax.servlet.Servlet
16+
17+
// Need to be explicit to unroll inherited tests:
18+
@Unroll
19+
abstract class AbstractServlet3Test<CONTEXT> extends AgentTestRunner {
20+
21+
@Shared
22+
OkHttpClient client = OkHttpUtils.clientBuilder().addNetworkInterceptor(new Interceptor() {
23+
@Override
24+
Response intercept(Interceptor.Chain chain) throws IOException {
25+
def response = chain.proceed(chain.request())
26+
TEST_WRITER.waitForTraces(1)
27+
return response
28+
}
29+
})
30+
.build()
31+
32+
@Shared
33+
int port = TestUtils.randomOpenPort()
34+
@Shared
35+
String user = "user"
36+
@Shared
37+
String pass = "password"
38+
39+
abstract String getContext()
40+
41+
abstract void addServlet(CONTEXT context, String url, Class<Servlet> servlet)
42+
43+
protected void setupServlets(CONTEXT context) {
44+
addServlet(context, "/sync", TestServlet3.Sync)
45+
addServlet(context, "/auth/sync", TestServlet3.Sync)
46+
addServlet(context, "/async", TestServlet3.Async)
47+
addServlet(context, "/auth/async", TestServlet3.Async)
48+
addServlet(context, "/blocking", TestServlet3.BlockingAsync)
49+
addServlet(context, "/dispatch/sync", TestServlet3.DispatchSync)
50+
addServlet(context, "/dispatch/async", TestServlet3.DispatchAsync)
51+
addServlet(context, "/fake", TestServlet3.FakeAsync)
52+
}
53+
54+
def "test #path servlet call (auth: #auth, distributed tracing: #distributedTracing)"() {
55+
setup:
56+
def requestBuilder = new Request.Builder()
57+
.url("http://localhost:$port/$context/$path")
58+
.get()
59+
if (distributedTracing) {
60+
requestBuilder.header("x-datadog-trace-id", "123")
61+
requestBuilder.header("x-datadog-parent-id", "456")
62+
}
63+
if (auth) {
64+
requestBuilder.header("Authorization", Credentials.basic(user, pass))
65+
}
66+
def response = client.newCall(requestBuilder.build()).execute()
67+
68+
expect:
69+
response.body().string().trim() == expectedResponse
70+
71+
assertTraces(1) {
72+
trace(0, 1) {
73+
span(0) {
74+
if (distributedTracing) {
75+
traceId "123"
76+
parentId "456"
77+
} else {
78+
parent()
79+
}
80+
serviceName context
81+
operationName "servlet.request"
82+
resourceName "GET /$context/$path"
83+
spanType DDSpanTypes.WEB_SERVLET
84+
errored false
85+
tags {
86+
"http.url" "http://localhost:$port/$context/$path"
87+
"http.method" "GET"
88+
"span.kind" "server"
89+
"component" "java-web-servlet"
90+
"span.origin.type" { it == "TestServlet3\$$origin" || it == ApplicationFilterChain.name }
91+
"span.type" DDSpanTypes.WEB_SERVLET
92+
"servlet.context" "/$context"
93+
"http.status_code" 200
94+
if (auth) {
95+
"$DDTags.USER_NAME" user
96+
}
97+
defaultTags(distributedTracing)
98+
}
99+
}
100+
}
101+
}
102+
103+
where:
104+
path | expectedResponse | auth | origin | distributedTracing
105+
"async" | "Hello Async" | false | "Async" | false
106+
"sync" | "Hello Sync" | false | "Sync" | false
107+
"auth/async" | "Hello Async" | true | "Async" | false
108+
"auth/sync" | "Hello Sync" | true | "Sync" | false
109+
"blocking" | "Hello BlockingAsync" | false | "BlockingAsync" | false
110+
"fake" | "Hello FakeAsync" | false | "FakeAsync" | false
111+
"async" | "Hello Async" | false | "Async" | true
112+
"sync" | "Hello Sync" | false | "Sync" | true
113+
"auth/async" | "Hello Async" | true | "Async" | true
114+
"auth/sync" | "Hello Sync" | true | "Sync" | true
115+
"blocking" | "Hello BlockingAsync" | false | "BlockingAsync" | true
116+
"fake" | "Hello FakeAsync" | false | "FakeAsync" | true
117+
}
118+
119+
def "test dispatch #path"() {
120+
setup:
121+
def requestBuilder = new Request.Builder()
122+
.url("http://localhost:$port/$context/dispatch/$path")
123+
.get()
124+
if (distributedTracing) {
125+
requestBuilder.header("x-datadog-trace-id", "123")
126+
requestBuilder.header("x-datadog-parent-id", "456")
127+
}
128+
def response = client.newCall(requestBuilder.build()).execute()
129+
130+
expect:
131+
response.body().string().trim() == "Hello $origin"
132+
133+
assertTraces(2) {
134+
trace(0, 1) {
135+
span(0) {
136+
if (distributedTracing) {
137+
traceId "123"
138+
parentId "456"
139+
} else {
140+
parent()
141+
}
142+
serviceName context
143+
operationName "servlet.request"
144+
resourceName "GET /$context/dispatch/$path"
145+
spanType DDSpanTypes.WEB_SERVLET
146+
errored false
147+
tags {
148+
"http.url" "http://localhost:$port/$context/dispatch/$path"
149+
"http.method" "GET"
150+
"span.kind" "server"
151+
"component" "java-web-servlet"
152+
"span.origin.type" { it == "TestServlet3\$Dispatch$origin" || it == ApplicationFilterChain.name }
153+
"span.type" DDSpanTypes.WEB_SERVLET
154+
"http.status_code" 200
155+
"servlet.context" "/$context"
156+
"servlet.dispatch" "/$path"
157+
defaultTags(distributedTracing)
158+
}
159+
}
160+
}
161+
trace(1, 1) {
162+
span(0) {
163+
serviceName context
164+
operationName "servlet.request"
165+
resourceName "GET /$context/$path"
166+
spanType DDSpanTypes.WEB_SERVLET
167+
errored false
168+
childOf TEST_WRITER[0][0]
169+
tags {
170+
"http.url" "http://localhost:$port/$context/$path"
171+
"http.method" "GET"
172+
"span.kind" "server"
173+
"component" "java-web-servlet"
174+
"span.origin.type" { it == "TestServlet3\$$origin" || it == ApplicationFilterChain.name }
175+
"span.type" DDSpanTypes.WEB_SERVLET
176+
"http.status_code" 200
177+
"servlet.context" "/$context"
178+
defaultTags(true)
179+
}
180+
}
181+
}
182+
}
183+
184+
where:
185+
path | distributedTracing
186+
"sync" | true
187+
"sync" | false
188+
"async" | true
189+
"async" | false
190+
191+
origin = path.capitalize()
192+
}
193+
194+
def "servlet instrumentation clears state after async request"() {
195+
setup:
196+
def request = new Request.Builder()
197+
.url("http://localhost:$port/$context/$path")
198+
.get()
199+
.build()
200+
def numTraces = 1
201+
for (int i = 0; i < numTraces; ++i) {
202+
client.newCall(request).execute()
203+
}
204+
205+
expect:
206+
assertTraces(dispatched ? numTraces * 2 : numTraces) {
207+
for (int i = 0; (dispatched ? i + 1 : i) < TEST_WRITER.size(); i += (dispatched ? 2 : 1)) {
208+
if (dispatched) {
209+
trace(i, 1) {
210+
span(0) {
211+
operationName "servlet.request"
212+
resourceName "GET /$context/dispatch/async"
213+
parent()
214+
}
215+
}
216+
}
217+
trace(dispatched ? i + 1 : i, 1) {
218+
span(0) {
219+
operationName "servlet.request"
220+
resourceName "GET /$context/async"
221+
if (dispatched) {
222+
childOf TEST_WRITER[i][0]
223+
} else {
224+
parent()
225+
}
226+
}
227+
}
228+
}
229+
}
230+
231+
where:
232+
path | dispatched
233+
"async" | false
234+
"dispatch/async" | true
235+
}
236+
237+
def "test #path error servlet call"() {
238+
setup:
239+
def request = new Request.Builder()
240+
.url("http://localhost:$port/$context/$path?error=true")
241+
.get()
242+
.build()
243+
def response = client.newCall(request).execute()
244+
245+
expect:
246+
response.body().string().trim() != expectedResponse
247+
248+
assertTraces(1) {
249+
trace(0, 1) {
250+
span(0) {
251+
serviceName context
252+
operationName "servlet.request"
253+
resourceName "GET /$context/$path"
254+
spanType DDSpanTypes.WEB_SERVLET
255+
errored true
256+
parent()
257+
tags {
258+
"http.url" "http://localhost:$port/$context/$path"
259+
"http.method" "GET"
260+
"span.kind" "server"
261+
"component" "java-web-servlet"
262+
"span.type" DDSpanTypes.WEB_SERVLET
263+
"span.origin.type" { it == "TestServlet3\$$origin" || it == ApplicationFilterChain.name }
264+
"servlet.context" "/$context"
265+
"http.status_code" 500
266+
errorTags(RuntimeException, "some $path error")
267+
defaultTags()
268+
}
269+
}
270+
}
271+
}
272+
273+
where:
274+
path | expectedResponse
275+
//"async" | "Hello Async" // FIXME: I can't seem get the async error handler to trigger
276+
"sync" | "Hello Sync"
277+
278+
origin = path.capitalize()
279+
}
280+
281+
def "test #path non-throwing-error servlet call"() {
282+
setup:
283+
def request = new Request.Builder()
284+
.url("http://localhost:$port/$context/$path?non-throwing-error=true")
285+
.get()
286+
.build()
287+
def response = client.newCall(request).execute()
288+
289+
expect:
290+
response.body().string().trim() != expectedResponse
291+
292+
assertTraces(1) {
293+
trace(0, 1) {
294+
span(0) {
295+
serviceName context
296+
operationName "servlet.request"
297+
resourceName "GET /$context/$path"
298+
spanType DDSpanTypes.WEB_SERVLET
299+
errored true
300+
parent()
301+
tags {
302+
"http.url" "http://localhost:$port/$context/$path"
303+
"http.method" "GET"
304+
"span.kind" "server"
305+
"component" "java-web-servlet"
306+
"span.type" DDSpanTypes.WEB_SERVLET
307+
"span.origin.type" { it == "TestServlet3\$$origin" || it == ApplicationFilterChain.name }
308+
"servlet.context" "/$context"
309+
"http.status_code" 500
310+
"error" true
311+
defaultTags()
312+
}
313+
}
314+
}
315+
}
316+
317+
where:
318+
path | expectedResponse
319+
"sync" | "Hello Sync"
320+
321+
origin = path.capitalize()
322+
}
323+
}

0 commit comments

Comments
 (0)