11import datadog.trace.agent.test.AgentTestRunner
22import datadog.trace.agent.test.asserts.TraceAssert
3+ import datadog.trace.agent.test.base.OkHttpWebsocketClient
34import datadog.trace.api.DDSpanTypes
45import datadog.trace.api.DDTags
56import datadog.trace.bootstrap.instrumentation.api.Tags
@@ -9,6 +10,9 @@ import dd.trace.instrumentation.springwebflux.server.EchoHandlerFunction
910import dd.trace.instrumentation.springwebflux.server.FooModel
1011import dd.trace.instrumentation.springwebflux.server.SpringWebFluxTestApplication
1112import dd.trace.instrumentation.springwebflux.server.TestController
13+ import dd.trace.instrumentation.springwebflux.server.WsHandler
14+ import net.bytebuddy.utility.RandomString
15+ import org.springframework.beans.factory.annotation.Autowired
1216import org.springframework.boot.test.context.SpringBootTest
1317import org.springframework.boot.test.context.TestConfiguration
1418import org.springframework.boot.web.embedded.netty.NettyReactiveWebServerFactory
@@ -21,6 +25,10 @@ import org.springframework.web.reactive.function.client.WebClient
2125import org.springframework.web.server.ResponseStatusException
2226import reactor.core.publisher.Mono
2327
28+ import static datadog.trace.agent.test.base.HttpServerTest.websocketCloseSpan
29+ import static datadog.trace.agent.test.base.HttpServerTest.websocketReceiveSpan
30+ import static datadog.trace.agent.test.base.HttpServerTest.websocketSendSpan
31+
2432@SpringBootTest (webEnvironment = SpringBootTest.WebEnvironment .RANDOM_PORT ,
2533classes = [SpringWebFluxTestApplication , ForceNettyAutoConfiguration ],
2634properties = " server.http2.enabled=true" )
@@ -40,13 +48,22 @@ class SpringWebfluxTest extends AgentTestRunner {
4048 @LocalServerPort
4149 int port
4250
43- WebClient client = WebClient . builder(). clientConnector (new ReactorClientHttpConnector ()). build()
51+ @Autowired
52+ private WsHandler wsHandler
53+
54+ WebClient client = WebClient . builder(). clientConnector(new ReactorClientHttpConnector ()). build()
4455
4556 @Override
4657 boolean useStrictTraceWrites () {
4758 false
4859 }
4960
61+ @Override
62+ protected void configurePreAgent () {
63+ super . configurePreAgent()
64+ injectSysConfig(" trace.websocket.messages.enabled" , " true" )
65+ }
66+
5067 def " Basic GET test #testName" () {
5168 setup :
5269 String url = " http://localhost:$port $urlPath "
@@ -61,7 +78,7 @@ class SpringWebfluxTest extends AgentTestRunner {
6178 sortSpansByStart()
6279 trace(2 ) {
6380 clientSpan(it, null , " http.request" , " spring-webflux-client" , " GET" , URI . create(url))
64- traceParent = clientSpan(it, span(0 ), " netty.client.request" , " netty-client" , " GET" , URI . create(url))
81+ traceParent = clientSpan(it, span(0 ), " netty.client.request" , " netty-client" , " GET" , URI . create(url))
6582 }
6683 trace(2 ) {
6784 span {
@@ -142,7 +159,7 @@ class SpringWebfluxTest extends AgentTestRunner {
142159 def traceParent
143160 trace(2 ) {
144161 clientSpan(it, null , " http.request" , " spring-webflux-client" , " GET" , URI . create(url))
145- traceParent = clientSpan(it, span(0 ), " netty.client.request" , " netty-client" , " GET" , URI . create(url))
162+ traceParent = clientSpan(it, span(0 ), " netty.client.request" , " netty-client" , " GET" , URI . create(url))
146163 }
147164 trace(3 ) {
148165 span {
@@ -237,7 +254,7 @@ class SpringWebfluxTest extends AgentTestRunner {
237254 def traceParent
238255 trace(2 ) {
239256 clientSpan(it, null , " http.request" , " spring-webflux-client" , " GET" , URI . create(url))
240- traceParent = clientSpan(it, span(0 ), " netty.client.request" , " netty-client" , " GET" , URI . create(url))
257+ traceParent = clientSpan(it, span(0 ), " netty.client.request" , " netty-client" , " GET" , URI . create(url))
241258 }
242259 trace(3 ) {
243260 span {
@@ -285,7 +302,7 @@ class SpringWebfluxTest extends AgentTestRunner {
285302 def traceParent
286303 trace(2 ) {
287304 clientSpan(it, null , " http.request" , " spring-webflux-client" , " GET" , URI . create(url), 404 , true )
288- traceParent = clientSpan(it, span(0 ), " netty.client.request" , " netty-client" , " GET" , URI . create(url), 404 , true )
305+ traceParent = clientSpan(it, span(0 ), " netty.client.request" , " netty-client" , " GET" , URI . create(url), 404 , true )
289306 }
290307 trace(2 ) {
291308 span {
@@ -331,7 +348,7 @@ class SpringWebfluxTest extends AgentTestRunner {
331348 String url = " http://localhost:$port /echo"
332349
333350 when :
334- def response = client. post(). uri(url). body(BodyInserters . fromPublisher(Mono . just(echoString),String )). exchange(). block()
351+ def response = client. post(). uri(url). body(BodyInserters . fromPublisher(Mono . just(echoString), String )). exchange(). block()
335352
336353 then :
337354 response. statusCode(). value() == 202
@@ -341,7 +358,7 @@ class SpringWebfluxTest extends AgentTestRunner {
341358 def traceParent
342359 trace(2 ) {
343360 clientSpan(it, null , " http.request" , " spring-webflux-client" , " POST" , URI . create(url), 202 )
344- traceParent = clientSpan(it, span(0 ), " netty.client.request" , " netty-client" , " POST" , URI . create(url), 202 )
361+ traceParent = clientSpan(it, span(0 ), " netty.client.request" , " netty-client" , " POST" , URI . create(url), 202 )
345362 }
346363 trace(3 ) {
347364 span {
@@ -406,7 +423,7 @@ class SpringWebfluxTest extends AgentTestRunner {
406423 def traceParent
407424 trace(2 ) {
408425 clientSpan(it, null , " http.request" , " spring-webflux-client" , " GET" , URI . create(url), 500 )
409- traceParent = clientSpan(it, span(0 ), " netty.client.request" , " netty-client" , " GET" , URI . create(url), 500 )
426+ traceParent = clientSpan(it, span(0 ), " netty.client.request" , " netty-client" , " GET" , URI . create(url), 500 )
410427 }
411428 trace(2 ) {
412429 span {
@@ -495,7 +512,7 @@ class SpringWebfluxTest extends AgentTestRunner {
495512 trace(2 ) {
496513 sortSpansByStart()
497514 clientSpan(it, null , " http.request" , " spring-webflux-client" , " GET" , URI . create(url), 307 )
498- traceParent1 = clientSpan(it, span(0 ), " netty.client.request" , " netty-client" , " GET" , URI . create(url), 307 )
515+ traceParent1 = clientSpan(it, span(0 ), " netty.client.request" , " netty-client" , " GET" , URI . create(url), 307 )
499516 }
500517
501518 trace(2 ) {
@@ -540,7 +557,7 @@ class SpringWebfluxTest extends AgentTestRunner {
540557 trace(2 ) {
541558 sortSpansByStart()
542559 clientSpan(it, null , " http.request" , " spring-webflux-client" , " GET" , URI . create(finalUrl))
543- traceParent2 = clientSpan(it, span(0 ), " netty.client.request" , " netty-client" , " GET" , URI . create(finalUrl))
560+ traceParent2 = clientSpan(it, span(0 ), " netty.client.request" , " netty-client" , " GET" , URI . create(finalUrl))
544561 }
545562 trace(2 ) {
546563 sortSpansByStart()
@@ -599,7 +616,7 @@ class SpringWebfluxTest extends AgentTestRunner {
599616 def traceParent
600617 trace(2 ) {
601618 clientSpan(it, null , " http.request" , " spring-webflux-client" , " GET" , URI . create(url))
602- traceParent = clientSpan(it, span(0 ), " netty.client.request" , " netty-client" , " GET" , URI . create(url))
619+ traceParent = clientSpan(it, span(0 ), " netty.client.request" , " netty-client" , " GET" , URI . create(url))
603620 }
604621 trace(2 ) {
605622 span {
@@ -660,6 +677,73 @@ class SpringWebfluxTest extends AgentTestRunner {
660677 " annotation API delayed response" | " /foo-delayed" | " /foo-delayed" | " getFooDelayed" | new FooModel (3L , " delayed" ). toString()
661678 }
662679
680+ def ' test websocket server receive #msgType message of size #size and #chunks chunks' () {
681+ when :
682+ String url = " http://localhost:$port /websocket"
683+ def wsClient = new OkHttpWebsocketClient ()
684+ wsClient. connect(url)
685+ wsHandler. awaitConnected()
686+ if (message instanceof String ) {
687+ wsClient. send(message as String )
688+ } else {
689+ wsClient. send(message as byte [])
690+ }
691+ wsHandler. awaitExchangeComplete()
692+ wsClient. close(1001 , " goodbye" )
693+
694+ then :
695+ assertTraces(3 , {
696+ DDSpan handshake
697+ trace(2 ) {
698+ sortSpansByStart()
699+ handshake = span(0 )
700+ span {
701+ resourceName " GET /websocket"
702+ operationName " netty.request"
703+ spanType DDSpanTypes . HTTP_SERVER
704+ tags {
705+ " $Tags . COMPONENT " " netty"
706+ " $Tags . SPAN_KIND " Tags . SPAN_KIND_SERVER
707+ " $Tags . PEER_HOST_IPV4 " " 127.0.0.1"
708+ " $Tags . PEER_PORT " Integer
709+ " $Tags . HTTP_URL " url
710+ " $Tags . HTTP_HOSTNAME " " localhost"
711+ " $Tags . HTTP_METHOD " " GET"
712+ " $Tags . HTTP_STATUS " 101
713+ " $Tags . HTTP_USER_AGENT " String
714+ " $Tags . HTTP_CLIENT_IP " " 127.0.0.1"
715+ " $Tags . HTTP_ROUTE " " /websocket"
716+ defaultTags()
717+ }
718+ }
719+ span {
720+ resourceName " WsHandler.handle"
721+ operationName " WsHandler.handle"
722+ spanType DDSpanTypes . HTTP_SERVER
723+ childOfPrevious()
724+ tags {
725+ " $Tags . COMPONENT " " spring-webflux-controller"
726+ " $Tags . SPAN_KIND " Tags . SPAN_KIND_SERVER
727+ " handler.type" WsHandler . getName()
728+ defaultTags()
729+ }
730+ }
731+ }
732+ trace(2 ) {
733+ sortSpansByStart()
734+ websocketReceiveSpan(it, handshake, msgType, size, chunks)
735+ websocketSendSpan(it, handshake, msgType, size, chunks)
736+ }
737+ trace(1 ) {
738+ websocketCloseSpan(it, handshake, false , 1001 , " goodbye" )
739+ }
740+ })
741+ where :
742+ message | msgType | chunks | size
743+ RandomString . make(10 ) | " text" | 1 | 10
744+ RandomString . make(20 ). getBytes(" UTF-8" ) | " binary" | 1 | 20
745+ }
746+
663747 def clientSpan (
664748 TraceAssert trace ,
665749 Object parentSpan ,
0 commit comments