Skip to content

Commit 0e07f37

Browse files
committed
add appsec instrumentation tests
1 parent e92444d commit 0e07f37

File tree

1 file changed

+169
-1
lines changed

1 file changed

+169
-1
lines changed

dd-java-agent/instrumentation/aws-java/aws-java-lambda-handler-1.2/src/test/groovy/LambdaHandlerInstrumentationTest.groovy

Lines changed: 169 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,20 @@
1+
import static datadog.trace.api.gateway.Events.EVENTS
2+
13
import datadog.trace.agent.test.naming.VersionedNamingTestBase
24
import datadog.trace.api.DDSpanTypes
3-
import java.nio.charset.StandardCharsets
5+
import datadog.trace.api.function.TriConsumer
6+
import datadog.trace.api.function.TriFunction
7+
import datadog.trace.api.gateway.Flow
8+
import datadog.trace.api.gateway.RequestContext
9+
import datadog.trace.api.gateway.RequestContextSlot
10+
import datadog.trace.bootstrap.ActiveSubsystems
11+
import datadog.trace.bootstrap.instrumentation.api.AgentTracer
12+
import datadog.trace.bootstrap.instrumentation.api.URIDataAdapter
413
import com.amazonaws.services.lambda.runtime.Context
14+
import java.nio.charset.StandardCharsets
15+
import java.util.function.BiFunction
16+
import java.util.function.Function
17+
import java.util.function.Supplier
518

619
abstract class LambdaHandlerInstrumentationTest extends VersionedNamingTestBase {
720
def requestId = "test-request-id"
@@ -17,6 +30,53 @@ abstract class LambdaHandlerInstrumentationTest extends VersionedNamingTestBase
1730
null
1831
}
1932

33+
def ig
34+
def appSecStarted = false
35+
def capturedMethod = null
36+
def capturedPath = null
37+
def capturedHeaders = [:]
38+
def capturedBody = null
39+
def appSecEnded = false
40+
41+
def setup() {
42+
ig = AgentTracer.get().getCallbackProvider(RequestContextSlot.APPSEC)
43+
ActiveSubsystems.APPSEC_ACTIVE = true
44+
appSecStarted = false
45+
capturedMethod = null
46+
capturedPath = null
47+
capturedHeaders = [:]
48+
capturedBody = null
49+
appSecEnded = false
50+
ig.registerCallback(EVENTS.requestStarted(), {
51+
appSecStarted = true
52+
new Flow.ResultFlow(new Object())
53+
} as Supplier)
54+
ig.registerCallback(EVENTS.requestMethodUriRaw(), { RequestContext ctx, String method, URIDataAdapter uri ->
55+
capturedMethod = method
56+
capturedPath = uri.path()
57+
Flow.ResultFlow.empty()
58+
} as TriFunction)
59+
ig.registerCallback(EVENTS.requestHeader(), { RequestContext ctx, String name, String value ->
60+
capturedHeaders[name] = value
61+
} as TriConsumer)
62+
ig.registerCallback(EVENTS.requestHeaderDone(), { RequestContext ctx ->
63+
Flow.ResultFlow.empty()
64+
} as Function)
65+
ig.registerCallback(EVENTS.requestBodyProcessed(), { RequestContext ctx, Object body ->
66+
capturedBody = body
67+
Flow.ResultFlow.empty()
68+
} as BiFunction)
69+
ig.registerCallback(EVENTS.requestEnded(), { RequestContext ctx, Object spanInfo ->
70+
appSecEnded = true
71+
Flow.ResultFlow.empty()
72+
} as BiFunction)
73+
}
74+
75+
def cleanup() {
76+
ig.reset()
77+
ActiveSubsystems.APPSEC_ACTIVE = false
78+
}
79+
2080
def "test lambda streaming handler"() {
2181
when:
2282
def input = new ByteArrayInputStream(StandardCharsets.UTF_8.encode("Hello").array())
@@ -76,6 +136,114 @@ abstract class LambdaHandlerInstrumentationTest extends VersionedNamingTestBase
76136
}
77137
}
78138
}
139+
140+
def "appsec callbacks are invoked for API Gateway v1 event"() {
141+
given:
142+
def eventJson = """{
143+
"path": "/api/users/123",
144+
"headers": {"content-type": "application/json", "x-forwarded-for": "203.0.113.1"},
145+
"body": "{\\"key\\": \\"value\\"}",
146+
"requestContext": {
147+
"httpMethod": "GET",
148+
"requestId": "req-abc",
149+
"identity": {"sourceIp": "203.0.113.1"}
150+
}
151+
}"""
152+
153+
when:
154+
def input = new ByteArrayInputStream(eventJson.getBytes(StandardCharsets.UTF_8))
155+
def output = new ByteArrayOutputStream()
156+
def ctx = Stub(Context) { getAwsRequestId() >> requestId }
157+
new HandlerStreaming().handleRequest(input, output, ctx)
158+
159+
then:
160+
appSecStarted
161+
capturedMethod == "GET"
162+
capturedPath == "/api/users/123"
163+
capturedHeaders["content-type"] == "application/json"
164+
capturedBody instanceof Map
165+
appSecEnded
166+
assertTraces(1) {
167+
trace(1) {
168+
span {
169+
operationName operation()
170+
spanType DDSpanTypes.SERVERLESS
171+
errored false
172+
}
173+
}
174+
}
175+
}
176+
177+
def "appsec callbacks are invoked for API Gateway v2 HTTP event"() {
178+
given:
179+
def eventJson = """{
180+
"version": "2.0",
181+
"headers": {"content-type": "application/json", "accept": "application/json"},
182+
"cookies": ["session=abc123"],
183+
"body": "{\\"key\\": \\"value\\"}",
184+
"requestContext": {
185+
"http": {
186+
"method": "POST",
187+
"path": "/api/items",
188+
"sourceIp": "198.51.100.1"
189+
},
190+
"domainName": "api.example.com"
191+
}
192+
}"""
193+
194+
when:
195+
def input = new ByteArrayInputStream(eventJson.getBytes(StandardCharsets.UTF_8))
196+
def output = new ByteArrayOutputStream()
197+
def ctx = Stub(Context) { getAwsRequestId() >> requestId }
198+
new HandlerStreaming().handleRequest(input, output, ctx)
199+
200+
then:
201+
appSecStarted
202+
capturedMethod == "POST"
203+
capturedPath == "/api/items"
204+
capturedHeaders["content-type"] == "application/json"
205+
capturedHeaders["cookie"] == "session=abc123"
206+
capturedBody instanceof Map
207+
appSecEnded
208+
assertTraces(1) {
209+
trace(1) {
210+
span {
211+
operationName operation()
212+
spanType DDSpanTypes.SERVERLESS
213+
errored false
214+
}
215+
}
216+
}
217+
}
218+
219+
def "appsec callbacks are not invoked when appsec is disabled"() {
220+
given:
221+
ActiveSubsystems.APPSEC_ACTIVE = false
222+
223+
when:
224+
def eventJson = """{
225+
"path": "/api/test",
226+
"requestContext": {"httpMethod": "GET", "requestId": "req-xyz"}
227+
}"""
228+
def input = new ByteArrayInputStream(eventJson.getBytes(StandardCharsets.UTF_8))
229+
def output = new ByteArrayOutputStream()
230+
def ctx = Stub(Context) { getAwsRequestId() >> requestId }
231+
new HandlerStreaming().handleRequest(input, output, ctx)
232+
233+
then:
234+
!appSecStarted
235+
capturedMethod == null
236+
!appSecEnded
237+
assertTraces(1) {
238+
trace(1) {
239+
span {
240+
operationName operation()
241+
spanType DDSpanTypes.SERVERLESS
242+
errored false
243+
}
244+
}
245+
}
246+
}
79247
}
80248

81249

0 commit comments

Comments
 (0)