Test of single connection reuse for Netty (#2630)
* Test of single connection reuse for Netty * Format
This commit is contained in:
parent
43f4ab4734
commit
5a9b0b999f
|
@ -27,6 +27,7 @@ import io.netty.handler.codec.http.HttpMethod
|
||||||
import io.netty.handler.codec.http.HttpVersion
|
import io.netty.handler.codec.http.HttpVersion
|
||||||
import io.opentelemetry.instrumentation.test.AgentTestTrait
|
import io.opentelemetry.instrumentation.test.AgentTestTrait
|
||||||
import io.opentelemetry.instrumentation.test.base.HttpClientTest
|
import io.opentelemetry.instrumentation.test.base.HttpClientTest
|
||||||
|
import io.opentelemetry.instrumentation.test.base.SingleConnection
|
||||||
import io.opentelemetry.javaagent.instrumentation.netty.v4_1.client.HttpClientTracingHandler
|
import io.opentelemetry.javaagent.instrumentation.netty.v4_1.client.HttpClientTracingHandler
|
||||||
import java.util.concurrent.CompletableFuture
|
import java.util.concurrent.CompletableFuture
|
||||||
import java.util.concurrent.ExecutionException
|
import java.util.concurrent.ExecutionException
|
||||||
|
@ -374,4 +375,9 @@ class Netty41ClientTest extends HttpClientTest implements AgentTestTrait {
|
||||||
ch.pipeline().addLast("added_in_initializer", new HttpClientCodec())
|
ch.pipeline().addLast("added_in_initializer", new HttpClientCodec())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
SingleConnection createSingleConnection(String host, int port) {
|
||||||
|
return new SingleNettyConnection(host, port)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,94 @@
|
||||||
|
/*
|
||||||
|
* Copyright The OpenTelemetry Authors
|
||||||
|
* SPDX-License-Identifier: Apache-2.0
|
||||||
|
*/
|
||||||
|
|
||||||
|
import io.netty.bootstrap.Bootstrap;
|
||||||
|
import io.netty.buffer.Unpooled;
|
||||||
|
import io.netty.channel.Channel;
|
||||||
|
import io.netty.channel.ChannelFuture;
|
||||||
|
import io.netty.channel.ChannelInitializer;
|
||||||
|
import io.netty.channel.ChannelOption;
|
||||||
|
import io.netty.channel.ChannelPipeline;
|
||||||
|
import io.netty.channel.EventLoopGroup;
|
||||||
|
import io.netty.channel.nio.NioEventLoopGroup;
|
||||||
|
import io.netty.channel.socket.SocketChannel;
|
||||||
|
import io.netty.channel.socket.nio.NioSocketChannel;
|
||||||
|
import io.netty.handler.codec.http.DefaultFullHttpRequest;
|
||||||
|
import io.netty.handler.codec.http.HttpClientCodec;
|
||||||
|
import io.netty.handler.codec.http.HttpHeaderNames;
|
||||||
|
import io.netty.handler.codec.http.HttpMethod;
|
||||||
|
import io.netty.handler.codec.http.HttpRequest;
|
||||||
|
import io.netty.handler.codec.http.HttpVersion;
|
||||||
|
import io.opentelemetry.instrumentation.test.base.SingleConnection;
|
||||||
|
import java.net.MalformedURLException;
|
||||||
|
import java.net.URL;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.concurrent.CompletableFuture;
|
||||||
|
import java.util.concurrent.ExecutionException;
|
||||||
|
import java.util.concurrent.TimeUnit;
|
||||||
|
import java.util.concurrent.TimeoutException;
|
||||||
|
|
||||||
|
/*
|
||||||
|
Netty does not actually support proper http pipelining and has no way to correlate incoming response
|
||||||
|
message with some sent request. This means that without some support from the higher level protocol
|
||||||
|
we cannot concurrently send several requests across the same channel. Thus doRequest method of this
|
||||||
|
class is synchronised. Yes, it seems kinda pointless, but at least we test that our instrumentation
|
||||||
|
does not wreak havoc on Netty channel.
|
||||||
|
*/
|
||||||
|
public class SingleNettyConnection implements SingleConnection {
|
||||||
|
private final String host;
|
||||||
|
private final int port;
|
||||||
|
private final Channel channel;
|
||||||
|
|
||||||
|
public SingleNettyConnection(String host, int port) {
|
||||||
|
this.host = host;
|
||||||
|
this.port = port;
|
||||||
|
EventLoopGroup group = new NioEventLoopGroup();
|
||||||
|
Bootstrap bootstrap = new Bootstrap();
|
||||||
|
bootstrap
|
||||||
|
.group(group)
|
||||||
|
.channel(NioSocketChannel.class)
|
||||||
|
.option(ChannelOption.CONNECT_TIMEOUT_MILLIS, 10000)
|
||||||
|
.handler(
|
||||||
|
new ChannelInitializer<SocketChannel>() {
|
||||||
|
@Override
|
||||||
|
protected void initChannel(SocketChannel socketChannel) {
|
||||||
|
ChannelPipeline pipeline = socketChannel.pipeline();
|
||||||
|
pipeline.addLast(new HttpClientCodec());
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
ChannelFuture channelFuture = bootstrap.connect(host, port);
|
||||||
|
channelFuture.awaitUninterruptibly();
|
||||||
|
if (!channelFuture.isSuccess()) {
|
||||||
|
throw new IllegalStateException(channelFuture.cause());
|
||||||
|
} else {
|
||||||
|
channel = channelFuture.channel();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public synchronized int doRequest(String path, Map<String, String> headers)
|
||||||
|
throws ExecutionException, InterruptedException, TimeoutException {
|
||||||
|
CompletableFuture<Integer> result = new CompletableFuture<>();
|
||||||
|
|
||||||
|
channel.pipeline().addLast(new ClientHandler(null, result));
|
||||||
|
|
||||||
|
String url;
|
||||||
|
try {
|
||||||
|
url = new URL("http", host, port, path).toString();
|
||||||
|
} catch (MalformedURLException e) {
|
||||||
|
throw new ExecutionException(e);
|
||||||
|
}
|
||||||
|
|
||||||
|
HttpRequest request =
|
||||||
|
new DefaultFullHttpRequest(
|
||||||
|
HttpVersion.HTTP_1_1, HttpMethod.GET, url, Unpooled.EMPTY_BUFFER);
|
||||||
|
request.headers().set(HttpHeaderNames.HOST, host);
|
||||||
|
headers.forEach((k, v) -> request.headers().set(k, v));
|
||||||
|
|
||||||
|
channel.writeAndFlush(request).get();
|
||||||
|
return result.get(20, TimeUnit.SECONDS);
|
||||||
|
}
|
||||||
|
}
|
|
@ -7,6 +7,7 @@ package io.opentelemetry.instrumentation.test.base;
|
||||||
|
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.concurrent.ExecutionException;
|
import java.util.concurrent.ExecutionException;
|
||||||
|
import java.util.concurrent.TimeoutException;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Helper class for http client tests which require a single connection.
|
* Helper class for http client tests which require a single connection.
|
||||||
|
@ -24,5 +25,5 @@ public interface SingleConnection {
|
||||||
String REQUEST_ID_HEADER = "test-request-id";
|
String REQUEST_ID_HEADER = "test-request-id";
|
||||||
|
|
||||||
int doRequest(String path, Map<String, String> headers)
|
int doRequest(String path, Map<String, String> headers)
|
||||||
throws ExecutionException, InterruptedException;
|
throws ExecutionException, InterruptedException, TimeoutException;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue