package com.github.dockerjava.netty;
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.OK;
import static io.netty.handler.codec.http.HttpVersion.HTTP_1_1;
import static org.testng.Assert.assertEquals;
import io.netty.bootstrap.ServerBootstrap;
import io.netty.buffer.Unpooled;
import io.netty.channel.Channel;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.ChannelPipeline;
import io.netty.channel.SimpleChannelInboundHandler;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
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.HttpContent;
import io.netty.handler.codec.http.HttpRequest;
import io.netty.handler.codec.http.HttpServerCodec;
import io.netty.util.CharsetUtil;
import java.io.IOException;
import java.net.ServerSocket;
import java.util.ArrayList;
import java.util.List;
import org.testng.annotations.Test;
import com.github.dockerjava.api.DockerClient;
import com.github.dockerjava.core.DefaultDockerClientConfig;
import com.github.dockerjava.core.DefaultDockerClientConfig.Builder;
import com.github.dockerjava.core.DockerClientBuilder;
public class NettyDockerCmdExecFactoryConfigTest {
@Test
public void testNettyDockerCmdExecFactoryConfigWithApiVersion() throws Exception {
int dockerPort = getFreePort();
NettyDockerCmdExecFactory factory = new NettyDockerCmdExecFactory();
Builder configBuilder = new DefaultDockerClientConfig.Builder()
.withDockerTlsVerify(false)
.withDockerHost("tcp://localhost:" + dockerPort)
.withApiVersion("1.23");
DockerClient client = DockerClientBuilder.getInstance(configBuilder)
.withDockerCmdExecFactory(factory)
.build();
FakeDockerServer server = new FakeDockerServer(dockerPort);
server.start();
try {
client.versionCmd().exec();
List<HttpRequest> requests = server.getRequests();
assertEquals(requests.size(), 1);
assertEquals(requests.get(0).uri(), "/v1.23/version");
} finally {
server.stop();
}
}
@Test
public void testNettyDockerCmdExecFactoryConfigWithoutApiVersion() throws Exception {
int dockerPort = getFreePort();
NettyDockerCmdExecFactory factory = new NettyDockerCmdExecFactory();
Builder configBuilder = new DefaultDockerClientConfig.Builder()
.withDockerTlsVerify(false)
.withDockerHost("tcp://localhost:" + dockerPort);
DockerClient client = DockerClientBuilder.getInstance(configBuilder)
.withDockerCmdExecFactory(factory)
.build();
FakeDockerServer server = new FakeDockerServer(dockerPort);
server.start();
try {
client.versionCmd().exec();
List<HttpRequest> requests = server.getRequests();
assertEquals(requests.size(), 1);
assertEquals(requests.get(0).uri(), "/version");
} finally {
server.stop();
}
}
private int getFreePort() throws IOException {
ServerSocket socket = new ServerSocket(0);
int freePort = socket.getLocalPort();
socket.close();
return freePort;
}
private class FakeDockerServer {
private final int port;
private final NioEventLoopGroup parent;
private final NioEventLoopGroup child;
private final List<HttpRequest> requests = new ArrayList<>();
private Channel channel;
private FakeDockerServer(int port) {
this.port = port;
this.parent = new NioEventLoopGroup();
this.child = new NioEventLoopGroup();
}
private void start() throws Exception {
ServerBootstrap bootstrap = new ServerBootstrap();
bootstrap.group(parent, child)
.channel(NioServerSocketChannel.class)
.childHandler(new ChannelInitializer<SocketChannel>() {
@Override
protected void initChannel(SocketChannel socketChannel) throws Exception {
ChannelPipeline pipeline = socketChannel.pipeline();
pipeline.addLast("codec", new HttpServerCodec());
pipeline.addLast("httpHandler", new SimpleChannelInboundHandler<Object>() {
@Override
protected void channelRead0(ChannelHandlerContext context, Object message) throws Exception {
if (message instanceof HttpRequest) {
// Keep track of processed requests
HttpRequest request = (HttpRequest) message;
requests.add(request);
}
if (message instanceof HttpContent) {
// Write an empty JSON response back to the client
FullHttpResponse response = new DefaultFullHttpResponse(HTTP_1_1, OK, Unpooled.copiedBuffer("{}", CharsetUtil.UTF_8));
response.headers().set(CONTENT_TYPE, "application/json; charset=UTF-8");
response.headers().set(CONTENT_LENGTH, response.content().readableBytes());
context.writeAndFlush(response);
}
}
});
}
});
channel = bootstrap.bind(port).syncUninterruptibly().channel();
}
private void stop() throws Exception {
parent.shutdownGracefully();
child.shutdownGracefully();
channel.closeFuture().sync();
}
private List<HttpRequest> getRequests() {
return requests;
}
}
}