UndertowServerTest.groovy 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266
  1. /*
  2. * Copyright The OpenTelemetry Authors
  3. * SPDX-License-Identifier: Apache-2.0
  4. */
  5. import io.opentelemetry.api.common.AttributeKey
  6. import io.opentelemetry.api.trace.Span
  7. import io.opentelemetry.api.trace.SpanKind
  8. import io.opentelemetry.api.trace.StatusCode
  9. import io.opentelemetry.instrumentation.api.instrumenter.http.internal.HttpAttributes
  10. import io.opentelemetry.instrumentation.api.instrumenter.network.internal.NetworkAttributes
  11. import io.opentelemetry.instrumentation.api.instrumenter.url.internal.UrlAttributes
  12. import io.opentelemetry.instrumentation.api.internal.SemconvStability
  13. import io.opentelemetry.instrumentation.test.AgentTestTrait
  14. import io.opentelemetry.instrumentation.test.base.HttpServerTest
  15. import io.opentelemetry.instrumentation.testing.junit.http.ServerEndpoint
  16. import io.opentelemetry.semconv.trace.attributes.SemanticAttributes
  17. import io.opentelemetry.testing.internal.armeria.common.AggregatedHttpResponse
  18. import io.undertow.Handlers
  19. import io.undertow.Undertow
  20. import io.undertow.util.Headers
  21. import io.undertow.util.HttpString
  22. import io.undertow.util.StatusCodes
  23. import static io.opentelemetry.instrumentation.testing.junit.http.ServerEndpoint.CAPTURE_HEADERS
  24. import static io.opentelemetry.instrumentation.testing.junit.http.ServerEndpoint.ERROR
  25. import static io.opentelemetry.instrumentation.testing.junit.http.ServerEndpoint.EXCEPTION
  26. import static io.opentelemetry.instrumentation.testing.junit.http.ServerEndpoint.INDEXED_CHILD
  27. import static io.opentelemetry.instrumentation.testing.junit.http.ServerEndpoint.QUERY_PARAM
  28. import static io.opentelemetry.instrumentation.testing.junit.http.ServerEndpoint.REDIRECT
  29. import static io.opentelemetry.instrumentation.testing.junit.http.ServerEndpoint.SUCCESS
  30. //TODO make test which mixes handlers and servlets
  31. class UndertowServerTest extends HttpServerTest<Undertow> implements AgentTestTrait {
  32. @Override
  33. Undertow startServer(int port) {
  34. Undertow server = Undertow.builder()
  35. .addHttpListener(port, "localhost")
  36. .setHandler(Handlers.path()
  37. .addExactPath(SUCCESS.rawPath()) { exchange ->
  38. controller(SUCCESS) {
  39. exchange.getResponseSender().send(SUCCESS.body)
  40. }
  41. }
  42. .addExactPath(QUERY_PARAM.rawPath()) { exchange ->
  43. controller(QUERY_PARAM) {
  44. exchange.getResponseSender().send(exchange.getQueryString())
  45. }
  46. }
  47. .addExactPath(REDIRECT.rawPath()) { exchange ->
  48. controller(REDIRECT) {
  49. exchange.setStatusCode(StatusCodes.FOUND)
  50. exchange.getResponseHeaders().put(Headers.LOCATION, REDIRECT.body)
  51. exchange.endExchange()
  52. }
  53. }
  54. .addExactPath(CAPTURE_HEADERS.rawPath()) { exchange ->
  55. controller(CAPTURE_HEADERS) {
  56. exchange.setStatusCode(StatusCodes.OK)
  57. exchange.getResponseHeaders().put(new HttpString("X-Test-Response"), exchange.getRequestHeaders().getFirst("X-Test-Request"))
  58. exchange.getResponseSender().send(CAPTURE_HEADERS.body)
  59. }
  60. }
  61. .addExactPath(ERROR.rawPath()) { exchange ->
  62. controller(ERROR) {
  63. exchange.setStatusCode(ERROR.status)
  64. exchange.getResponseSender().send(ERROR.body)
  65. }
  66. }
  67. .addExactPath(EXCEPTION.rawPath()) { exchange ->
  68. controller(EXCEPTION) {
  69. throw new Exception(EXCEPTION.body)
  70. }
  71. }
  72. .addExactPath(INDEXED_CHILD.rawPath()) { exchange ->
  73. controller(INDEXED_CHILD) {
  74. INDEXED_CHILD.collectSpanAttributes { name -> exchange.getQueryParameters().get(name).peekFirst() }
  75. exchange.getResponseSender().send(INDEXED_CHILD.body)
  76. }
  77. }
  78. .addExactPath("sendResponse") { exchange ->
  79. Span.current().addEvent("before-event")
  80. runWithSpan("sendResponse") {
  81. exchange.setStatusCode(StatusCodes.OK)
  82. exchange.getResponseSender().send("sendResponse")
  83. }
  84. // event is added only when server span has not been ended
  85. // we need to make sure that sending response does not end server span
  86. Span.current().addEvent("after-event")
  87. }
  88. .addExactPath("sendResponseWithException") { exchange ->
  89. Span.current().addEvent("before-event")
  90. runWithSpan("sendResponseWithException") {
  91. exchange.setStatusCode(StatusCodes.OK)
  92. exchange.getResponseSender().send("sendResponseWithException")
  93. }
  94. // event is added only when server span has not been ended
  95. // we need to make sure that sending response does not end server span
  96. Span.current().addEvent("after-event")
  97. throw new Exception("exception after sending response")
  98. }
  99. ).build()
  100. server.start()
  101. return server
  102. }
  103. @Override
  104. void stopServer(Undertow undertow) {
  105. undertow.stop()
  106. }
  107. @Override
  108. Set<AttributeKey<?>> httpAttributes(ServerEndpoint endpoint) {
  109. def attributes = super.httpAttributes(endpoint)
  110. attributes.remove(SemanticAttributes.HTTP_ROUTE)
  111. attributes
  112. }
  113. @Override
  114. boolean hasResponseCustomizer(ServerEndpoint endpoint) {
  115. true
  116. }
  117. def "test send response"() {
  118. setup:
  119. def uri = address.resolve("sendResponse")
  120. AggregatedHttpResponse response = client.get(uri.toString()).aggregate().join()
  121. expect:
  122. response.status().code() == 200
  123. response.contentUtf8().trim() == "sendResponse"
  124. and:
  125. assertTraces(1) {
  126. trace(0, 2) {
  127. it.span(0) {
  128. hasNoParent()
  129. name "GET"
  130. kind SpanKind.SERVER
  131. event(0) {
  132. eventName "before-event"
  133. }
  134. event(1) {
  135. eventName "after-event"
  136. }
  137. if (SemconvStability.emitOldHttpSemconv()) {
  138. attributes {
  139. "$SemanticAttributes.HTTP_CLIENT_IP" TEST_CLIENT_IP
  140. "$SemanticAttributes.HTTP_SCHEME" uri.getScheme()
  141. "$SemanticAttributes.HTTP_TARGET" uri.getPath()
  142. "$SemanticAttributes.HTTP_METHOD" "GET"
  143. "$SemanticAttributes.HTTP_STATUS_CODE" 200
  144. "$SemanticAttributes.USER_AGENT_ORIGINAL" TEST_USER_AGENT
  145. "$SemanticAttributes.HTTP_RESPONSE_CONTENT_LENGTH" Long
  146. "$SemanticAttributes.NET_PROTOCOL_NAME" "http"
  147. "$SemanticAttributes.NET_PROTOCOL_VERSION" "1.1"
  148. "$SemanticAttributes.NET_HOST_NAME" uri.host
  149. "$SemanticAttributes.NET_HOST_PORT" uri.port
  150. "$SemanticAttributes.NET_SOCK_PEER_ADDR" "127.0.0.1"
  151. "$SemanticAttributes.NET_SOCK_PEER_PORT" Long
  152. "$SemanticAttributes.NET_SOCK_HOST_ADDR" "127.0.0.1"
  153. }
  154. }
  155. if (SemconvStability.emitStableHttpSemconv()) {
  156. attributes {
  157. "$NetworkAttributes.CLIENT_ADDRESS" TEST_CLIENT_IP
  158. "$UrlAttributes.URL_SCHEME" uri.getScheme()
  159. "$UrlAttributes.URL_PATH" uri.getPath()
  160. "$HttpAttributes.HTTP_REQUEST_METHOD" "GET"
  161. "$HttpAttributes.HTTP_RESPONSE_STATUS_CODE" 200
  162. "$SemanticAttributes.USER_AGENT_ORIGINAL" TEST_USER_AGENT
  163. "$HttpAttributes.HTTP_RESPONSE_BODY_SIZE" Long
  164. "$NetworkAttributes.NETWORK_PROTOCOL_NAME" "http"
  165. "$NetworkAttributes.NETWORK_PROTOCOL_VERSION" "1.1"
  166. "$NetworkAttributes.NETWORK_TYPE" "ipv4"
  167. "$NetworkAttributes.SERVER_ADDRESS" uri.host
  168. "$NetworkAttributes.SERVER_PORT" uri.port
  169. "$NetworkAttributes.CLIENT_SOCKET_ADDRESS" "127.0.0.1"
  170. "$NetworkAttributes.CLIENT_SOCKET_PORT" Long
  171. }
  172. }
  173. }
  174. span(1) {
  175. name "sendResponse"
  176. kind SpanKind.INTERNAL
  177. childOf span(0)
  178. }
  179. }
  180. }
  181. }
  182. def "test send response with exception"() {
  183. setup:
  184. def uri = address.resolve("sendResponseWithException")
  185. AggregatedHttpResponse response = client.get(uri.toString()).aggregate().join()
  186. expect:
  187. response.status().code() == 200
  188. response.contentUtf8().trim() == "sendResponseWithException"
  189. and:
  190. assertTraces(1) {
  191. trace(0, 2) {
  192. it.span(0) {
  193. hasNoParent()
  194. name "GET"
  195. kind SpanKind.SERVER
  196. status StatusCode.ERROR
  197. event(0) {
  198. eventName "before-event"
  199. }
  200. event(1) {
  201. eventName "after-event"
  202. }
  203. errorEvent(Exception, "exception after sending response", 2)
  204. if (SemconvStability.emitOldHttpSemconv()) {
  205. attributes {
  206. "$SemanticAttributes.HTTP_CLIENT_IP" TEST_CLIENT_IP
  207. "$SemanticAttributes.HTTP_SCHEME" uri.getScheme()
  208. "$SemanticAttributes.HTTP_TARGET" uri.getPath()
  209. "$SemanticAttributes.HTTP_METHOD" "GET"
  210. "$SemanticAttributes.HTTP_STATUS_CODE" 200
  211. "$SemanticAttributes.USER_AGENT_ORIGINAL" TEST_USER_AGENT
  212. "$SemanticAttributes.HTTP_RESPONSE_CONTENT_LENGTH" Long
  213. "$SemanticAttributes.NET_PROTOCOL_NAME" "http"
  214. "$SemanticAttributes.NET_PROTOCOL_VERSION" "1.1"
  215. "$SemanticAttributes.NET_HOST_NAME" uri.host
  216. "$SemanticAttributes.NET_HOST_PORT" uri.port
  217. "$SemanticAttributes.NET_SOCK_PEER_ADDR" "127.0.0.1"
  218. "$SemanticAttributes.NET_SOCK_PEER_PORT" Long
  219. "$SemanticAttributes.NET_SOCK_HOST_ADDR" "127.0.0.1"
  220. }
  221. }
  222. if (SemconvStability.emitStableHttpSemconv()) {
  223. attributes {
  224. "$NetworkAttributes.CLIENT_ADDRESS" TEST_CLIENT_IP
  225. "$UrlAttributes.URL_SCHEME" uri.getScheme()
  226. "$UrlAttributes.URL_PATH" uri.getPath()
  227. "$HttpAttributes.HTTP_REQUEST_METHOD" "GET"
  228. "$HttpAttributes.HTTP_RESPONSE_STATUS_CODE" 200
  229. "$SemanticAttributes.USER_AGENT_ORIGINAL" TEST_USER_AGENT
  230. "$HttpAttributes.HTTP_RESPONSE_BODY_SIZE" Long
  231. "$NetworkAttributes.NETWORK_PROTOCOL_NAME" "http"
  232. "$NetworkAttributes.NETWORK_PROTOCOL_VERSION" "1.1"
  233. "$NetworkAttributes.NETWORK_TYPE" "ipv4"
  234. "$NetworkAttributes.SERVER_ADDRESS" uri.host
  235. "$NetworkAttributes.SERVER_PORT" uri.port
  236. "$NetworkAttributes.CLIENT_SOCKET_ADDRESS" "127.0.0.1"
  237. "$NetworkAttributes.CLIENT_SOCKET_PORT" Long
  238. }
  239. }
  240. }
  241. span(1) {
  242. name "sendResponseWithException"
  243. kind SpanKind.INTERNAL
  244. childOf span(0)
  245. }
  246. }
  247. }
  248. }
  249. }