133 lines
6.0 KiB
Groovy
133 lines
6.0 KiB
Groovy
/*
|
|
* Copyright The OpenTelemetry Authors
|
|
* SPDX-License-Identifier: Apache-2.0
|
|
*/
|
|
|
|
import static io.netty.handler.codec.http.HttpHeaderNames.CONTENT_LENGTH
|
|
import static io.netty.handler.codec.http.HttpHeaderNames.CONTENT_TYPE
|
|
import static io.netty.handler.codec.http.HttpResponseStatus.INTERNAL_SERVER_ERROR
|
|
import static io.netty.handler.codec.http.HttpVersion.HTTP_1_1
|
|
import static io.opentelemetry.instrumentation.test.base.HttpServerTest.ServerEndpoint.ERROR
|
|
import static io.opentelemetry.instrumentation.test.base.HttpServerTest.ServerEndpoint.EXCEPTION
|
|
import static io.opentelemetry.instrumentation.test.base.HttpServerTest.ServerEndpoint.INDEXED_CHILD
|
|
import static io.opentelemetry.instrumentation.test.base.HttpServerTest.ServerEndpoint.NOT_FOUND
|
|
import static io.opentelemetry.instrumentation.test.base.HttpServerTest.ServerEndpoint.QUERY_PARAM
|
|
import static io.opentelemetry.instrumentation.test.base.HttpServerTest.ServerEndpoint.REDIRECT
|
|
import static io.opentelemetry.instrumentation.test.base.HttpServerTest.ServerEndpoint.SUCCESS
|
|
|
|
import io.netty.bootstrap.ServerBootstrap
|
|
import io.netty.buffer.ByteBuf
|
|
import io.netty.buffer.Unpooled
|
|
import io.netty.channel.ChannelHandlerContext
|
|
import io.netty.channel.ChannelInitializer
|
|
import io.netty.channel.ChannelPipeline
|
|
import io.netty.channel.EventLoopGroup
|
|
import io.netty.channel.SimpleChannelInboundHandler
|
|
import io.netty.channel.nio.NioEventLoopGroup
|
|
import io.netty.channel.socket.nio.NioServerSocketChannel
|
|
import io.netty.handler.codec.http.DefaultFullHttpResponse
|
|
import io.netty.handler.codec.http.FullHttpResponse
|
|
import io.netty.handler.codec.http.HttpHeaderNames
|
|
import io.netty.handler.codec.http.HttpRequest
|
|
import io.netty.handler.codec.http.HttpResponseStatus
|
|
import io.netty.handler.codec.http.HttpServerCodec
|
|
import io.netty.handler.codec.http.QueryStringDecoder
|
|
import io.netty.handler.logging.LogLevel
|
|
import io.netty.handler.logging.LoggingHandler
|
|
import io.netty.util.CharsetUtil
|
|
import io.opentelemetry.api.trace.Span
|
|
import io.opentelemetry.instrumentation.test.AgentTestTrait
|
|
import io.opentelemetry.instrumentation.test.base.HttpServerTest
|
|
|
|
class Netty41ServerTest extends HttpServerTest<EventLoopGroup> implements AgentTestTrait {
|
|
|
|
static final LoggingHandler LOGGING_HANDLER = new LoggingHandler(SERVER_LOGGER.name, LogLevel.DEBUG)
|
|
|
|
@Override
|
|
EventLoopGroup startServer(int port) {
|
|
def eventLoopGroup = new NioEventLoopGroup()
|
|
|
|
ServerBootstrap bootstrap = new ServerBootstrap()
|
|
.group(eventLoopGroup)
|
|
.handler(LOGGING_HANDLER)
|
|
.childHandler([
|
|
initChannel: { ch ->
|
|
ChannelPipeline pipeline = ch.pipeline()
|
|
pipeline.addFirst("logger", LOGGING_HANDLER)
|
|
|
|
def handlers = [new HttpServerCodec()]
|
|
handlers.each { pipeline.addLast(it) }
|
|
pipeline.addLast([
|
|
channelRead0 : { ctx, msg ->
|
|
if (msg instanceof HttpRequest) {
|
|
def uri = URI.create((msg as HttpRequest).uri())
|
|
ServerEndpoint endpoint = ServerEndpoint.forPath(uri.path)
|
|
ctx.write controller(endpoint) {
|
|
ByteBuf content = null
|
|
FullHttpResponse response
|
|
switch (endpoint) {
|
|
case SUCCESS:
|
|
case ERROR:
|
|
content = Unpooled.copiedBuffer(endpoint.body, CharsetUtil.UTF_8)
|
|
response = new DefaultFullHttpResponse(HTTP_1_1, HttpResponseStatus.valueOf(endpoint.status), content)
|
|
break
|
|
case INDEXED_CHILD:
|
|
QueryStringDecoder queryStringDecoder = new QueryStringDecoder(uri)
|
|
Span.current().setAttribute("test.request.id", queryStringDecoder.parameters().get("id").find() as long)
|
|
response = new DefaultFullHttpResponse(HTTP_1_1, HttpResponseStatus.valueOf(endpoint.status))
|
|
break
|
|
case QUERY_PARAM:
|
|
content = Unpooled.copiedBuffer(uri.query, CharsetUtil.UTF_8)
|
|
response = new DefaultFullHttpResponse(HTTP_1_1, HttpResponseStatus.valueOf(endpoint.status), content)
|
|
break
|
|
case REDIRECT:
|
|
response = new DefaultFullHttpResponse(HTTP_1_1, HttpResponseStatus.valueOf(endpoint.status))
|
|
response.headers().set(HttpHeaderNames.LOCATION, endpoint.body)
|
|
break
|
|
case EXCEPTION:
|
|
throw new Exception(endpoint.body)
|
|
default:
|
|
content = Unpooled.copiedBuffer(NOT_FOUND.body, CharsetUtil.UTF_8)
|
|
response = new DefaultFullHttpResponse(HTTP_1_1, HttpResponseStatus.valueOf(NOT_FOUND.status), content)
|
|
break
|
|
}
|
|
response.headers().set(CONTENT_TYPE, "text/plain")
|
|
if (content) {
|
|
response.headers().set(CONTENT_LENGTH, content.readableBytes())
|
|
}
|
|
return response
|
|
}
|
|
}
|
|
},
|
|
exceptionCaught : { ChannelHandlerContext ctx, Throwable cause ->
|
|
ByteBuf content = Unpooled.copiedBuffer(cause.message, CharsetUtil.UTF_8)
|
|
FullHttpResponse response = new DefaultFullHttpResponse(HTTP_1_1, INTERNAL_SERVER_ERROR, content)
|
|
response.headers().set(CONTENT_TYPE, "text/plain")
|
|
response.headers().set(CONTENT_LENGTH, content.readableBytes())
|
|
ctx.write(response)
|
|
},
|
|
channelReadComplete: { it.flush() }
|
|
] as SimpleChannelInboundHandler)
|
|
}
|
|
] as ChannelInitializer).channel(NioServerSocketChannel)
|
|
bootstrap.bind(port).sync()
|
|
|
|
return eventLoopGroup
|
|
}
|
|
|
|
@Override
|
|
void stopServer(EventLoopGroup server) {
|
|
server?.shutdownGracefully()
|
|
}
|
|
|
|
@Override
|
|
String expectedServerSpanName(ServerEndpoint endpoint) {
|
|
return "HTTP GET"
|
|
}
|
|
|
|
@Override
|
|
boolean testConcurrency() {
|
|
return true
|
|
}
|
|
}
|