1
1
import datadog.trace.agent.test.AgentTestRunner
2
2
import datadog.trace.agent.test.asserts.TraceAssert
3
+ import datadog.trace.agent.test.base.HttpServerTest
4
+ import datadog.trace.agent.test.base.OkHttpWebsocketClient
5
+ import datadog.trace.agent.test.base.WebsocketServer
3
6
import datadog.trace.api.DDSpanTypes
4
7
import datadog.trace.api.DDTags
5
8
import datadog.trace.bootstrap.instrumentation.api.Tags
@@ -9,6 +12,9 @@ import dd.trace.instrumentation.springwebflux.server.EchoHandlerFunction
9
12
import dd.trace.instrumentation.springwebflux.server.FooModel
10
13
import dd.trace.instrumentation.springwebflux.server.SpringWebFluxTestApplication
11
14
import dd.trace.instrumentation.springwebflux.server.TestController
15
+ import dd.trace.instrumentation.springwebflux.server.WsHandler
16
+ import net.bytebuddy.utility.RandomString
17
+ import org.springframework.beans.factory.annotation.Autowired
12
18
import org.springframework.boot.test.context.SpringBootTest
13
19
import org.springframework.boot.test.context.TestConfiguration
14
20
import org.springframework.boot.web.embedded.netty.NettyReactiveWebServerFactory
@@ -18,9 +24,22 @@ import org.springframework.http.client.reactive.ReactorClientHttpConnector
18
24
import org.springframework.web.reactive.function.BodyExtractors
19
25
import org.springframework.web.reactive.function.BodyInserters
20
26
import org.springframework.web.reactive.function.client.WebClient
27
+ import org.springframework.web.reactive.socket.WebSocketHandler
28
+ import org.springframework.web.reactive.socket.WebSocketSession
29
+ import org.springframework.web.reactive.socket.client.WebSocketClient
21
30
import org.springframework.web.server.ResponseStatusException
22
31
import reactor.core.publisher.Mono
23
32
33
+ import static datadog.trace.agent.test.base.HttpServerTest.ServerEndpoint.WEBSOCKET
34
+ import static datadog.trace.agent.test.base.HttpServerTest.ServerEndpoint.WEBSOCKET
35
+ import static datadog.trace.agent.test.base.HttpServerTest.ServerEndpoint.WEBSOCKET
36
+ import static datadog.trace.agent.test.base.HttpServerTest.websocketCloseSpan
37
+ import static datadog.trace.agent.test.base.HttpServerTest.websocketReceiveSpan
38
+ import static datadog.trace.agent.test.base.HttpServerTest.websocketSendSpan
39
+ import static datadog.trace.agent.test.utils.TraceUtils.basicSpan
40
+ import static org.junit.Assume.assumeTrue
41
+ import static org.junit.Assume.assumeTrue
42
+
24
43
@SpringBootTest (webEnvironment = SpringBootTest.WebEnvironment .RANDOM_PORT ,
25
44
classes = [SpringWebFluxTestApplication , ForceNettyAutoConfiguration ],
26
45
properties = " server.http2.enabled=true" )
@@ -40,13 +59,22 @@ class SpringWebfluxTest extends AgentTestRunner {
40
59
@LocalServerPort
41
60
int port
42
61
43
- WebClient client = WebClient . builder(). clientConnector (new ReactorClientHttpConnector ()). build()
62
+ @Autowired
63
+ private WsHandler wsHandler
64
+
65
+ WebClient client = WebClient . builder(). clientConnector(new ReactorClientHttpConnector ()). build()
44
66
45
67
@Override
46
68
boolean useStrictTraceWrites () {
47
69
false
48
70
}
49
71
72
+ @Override
73
+ protected void configurePreAgent () {
74
+ super . configurePreAgent()
75
+ injectSysConfig(" trace.websocket.messages.enabled" , " true" )
76
+ }
77
+
50
78
def " Basic GET test #testName" () {
51
79
setup :
52
80
String url = " http://localhost:$port $urlPath "
@@ -61,7 +89,7 @@ class SpringWebfluxTest extends AgentTestRunner {
61
89
sortSpansByStart()
62
90
trace(2 ) {
63
91
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))
92
+ traceParent = clientSpan(it, span(0 ), " netty.client.request" , " netty-client" , " GET" , URI . create(url))
65
93
}
66
94
trace(2 ) {
67
95
span {
@@ -142,7 +170,7 @@ class SpringWebfluxTest extends AgentTestRunner {
142
170
def traceParent
143
171
trace(2 ) {
144
172
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))
173
+ traceParent = clientSpan(it, span(0 ), " netty.client.request" , " netty-client" , " GET" , URI . create(url))
146
174
}
147
175
trace(3 ) {
148
176
span {
@@ -237,7 +265,7 @@ class SpringWebfluxTest extends AgentTestRunner {
237
265
def traceParent
238
266
trace(2 ) {
239
267
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))
268
+ traceParent = clientSpan(it, span(0 ), " netty.client.request" , " netty-client" , " GET" , URI . create(url))
241
269
}
242
270
trace(3 ) {
243
271
span {
@@ -285,7 +313,7 @@ class SpringWebfluxTest extends AgentTestRunner {
285
313
def traceParent
286
314
trace(2 ) {
287
315
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 )
316
+ traceParent = clientSpan(it, span(0 ), " netty.client.request" , " netty-client" , " GET" , URI . create(url), 404 , true )
289
317
}
290
318
trace(2 ) {
291
319
span {
@@ -331,7 +359,7 @@ class SpringWebfluxTest extends AgentTestRunner {
331
359
String url = " http://localhost:$port /echo"
332
360
333
361
when :
334
- def response = client. post(). uri(url). body(BodyInserters . fromPublisher(Mono . just(echoString),String )). exchange(). block()
362
+ def response = client. post(). uri(url). body(BodyInserters . fromPublisher(Mono . just(echoString), String )). exchange(). block()
335
363
336
364
then :
337
365
response. statusCode(). value() == 202
@@ -341,7 +369,7 @@ class SpringWebfluxTest extends AgentTestRunner {
341
369
def traceParent
342
370
trace(2 ) {
343
371
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 )
372
+ traceParent = clientSpan(it, span(0 ), " netty.client.request" , " netty-client" , " POST" , URI . create(url), 202 )
345
373
}
346
374
trace(3 ) {
347
375
span {
@@ -406,7 +434,7 @@ class SpringWebfluxTest extends AgentTestRunner {
406
434
def traceParent
407
435
trace(2 ) {
408
436
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 )
437
+ traceParent = clientSpan(it, span(0 ), " netty.client.request" , " netty-client" , " GET" , URI . create(url), 500 )
410
438
}
411
439
trace(2 ) {
412
440
span {
@@ -495,7 +523,7 @@ class SpringWebfluxTest extends AgentTestRunner {
495
523
trace(2 ) {
496
524
sortSpansByStart()
497
525
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 )
526
+ traceParent1 = clientSpan(it, span(0 ), " netty.client.request" , " netty-client" , " GET" , URI . create(url), 307 )
499
527
}
500
528
501
529
trace(2 ) {
@@ -540,7 +568,7 @@ class SpringWebfluxTest extends AgentTestRunner {
540
568
trace(2 ) {
541
569
sortSpansByStart()
542
570
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))
571
+ traceParent2 = clientSpan(it, span(0 ), " netty.client.request" , " netty-client" , " GET" , URI . create(finalUrl))
544
572
}
545
573
trace(2 ) {
546
574
sortSpansByStart()
@@ -599,7 +627,7 @@ class SpringWebfluxTest extends AgentTestRunner {
599
627
def traceParent
600
628
trace(2 ) {
601
629
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))
630
+ traceParent = clientSpan(it, span(0 ), " netty.client.request" , " netty-client" , " GET" , URI . create(url))
603
631
}
604
632
trace(2 ) {
605
633
span {
@@ -660,6 +688,73 @@ class SpringWebfluxTest extends AgentTestRunner {
660
688
" annotation API delayed response" | " /foo-delayed" | " /foo-delayed" | " getFooDelayed" | new FooModel (3L , " delayed" ). toString()
661
689
}
662
690
691
+ def ' test websocket server receive #msgType message of size #size and #chunks chunks' () {
692
+ when :
693
+ String url = " http://localhost:$port /websocket"
694
+ def wsClient = new OkHttpWebsocketClient ()
695
+ wsClient. connect(url)
696
+ wsHandler. awaitConnected()
697
+ if (message instanceof String ) {
698
+ wsClient. send(message as String )
699
+ } else {
700
+ wsClient. send(message as byte [])
701
+ }
702
+ wsHandler. awaitExchangeComplete()
703
+ wsClient. close(1001 , " goodbye" )
704
+
705
+ then :
706
+ assertTraces(3 , {
707
+ DDSpan handshake
708
+ trace(2 ) {
709
+ sortSpansByStart()
710
+ handshake = span(0 )
711
+ span {
712
+ resourceName " GET /websocket"
713
+ operationName " netty.request"
714
+ spanType DDSpanTypes . HTTP_SERVER
715
+ tags {
716
+ " $Tags . COMPONENT " " netty"
717
+ " $Tags . SPAN_KIND " Tags . SPAN_KIND_SERVER
718
+ " $Tags . PEER_HOST_IPV4 " " 127.0.0.1"
719
+ " $Tags . PEER_PORT " Integer
720
+ " $Tags . HTTP_URL " url
721
+ " $Tags . HTTP_HOSTNAME " " localhost"
722
+ " $Tags . HTTP_METHOD " " GET"
723
+ " $Tags . HTTP_STATUS " 101
724
+ " $Tags . HTTP_USER_AGENT " String
725
+ " $Tags . HTTP_CLIENT_IP " " 127.0.0.1"
726
+ " $Tags . HTTP_ROUTE " " /websocket"
727
+ defaultTags()
728
+ }
729
+ }
730
+ span {
731
+ resourceName " WsHandler.handle"
732
+ operationName " WsHandler.handle"
733
+ spanType DDSpanTypes . HTTP_SERVER
734
+ childOfPrevious()
735
+ tags {
736
+ " $Tags . COMPONENT " " spring-webflux-controller"
737
+ " $Tags . SPAN_KIND " Tags . SPAN_KIND_SERVER
738
+ " handler.type" WsHandler . getName()
739
+ defaultTags()
740
+ }
741
+ }
742
+ }
743
+ trace(2 ) {
744
+ sortSpansByStart()
745
+ websocketReceiveSpan(it, handshake, msgType, size, chunks)
746
+ websocketSendSpan(it, handshake, msgType, size, chunks)
747
+ }
748
+ trace(1 ) {
749
+ websocketCloseSpan(it, handshake, false , 1001 , " goodbye" )
750
+ }
751
+ })
752
+ where :
753
+ message | msgType | chunks | size
754
+ RandomString . make(10 ) | " text" | 1 | 10
755
+ RandomString . make(20 ). getBytes(" UTF-8" ) | " binary" | 1 | 20
756
+ }
757
+
663
758
def clientSpan (
664
759
TraceAssert trace ,
665
760
Object parentSpan ,
0 commit comments