package com.github.dockerjava.client;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.StringWriter;
import java.lang.reflect.Method;
import java.net.DatagramSocket;
import java.net.ServerSocket;
import java.util.ArrayList;
import java.util.List;
import org.apache.commons.io.IOUtils;
import org.apache.commons.io.LineIterator;
import org.apache.commons.lang.StringUtils;
import org.hamcrest.FeatureMatcher;
import org.hamcrest.Matcher;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.testng.Assert;
import org.testng.ITestResult;
import com.github.dockerjava.api.DockerClient;
import com.github.dockerjava.api.command.InspectContainerResponse;
import com.github.dockerjava.api.command.InspectContainerResponse.Mount;
import com.github.dockerjava.api.exception.DockerException;
import com.github.dockerjava.api.exception.NotFoundException;
import com.github.dockerjava.api.model.Frame;
import com.github.dockerjava.api.model.Network;
import com.github.dockerjava.api.model.Volume;
import com.github.dockerjava.core.DockerClientBuilder;
import com.github.dockerjava.core.DefaultDockerClientConfig;
import com.github.dockerjava.core.TestDockerCmdExecFactory;
import com.github.dockerjava.core.command.BuildImageResultCallback;
import com.github.dockerjava.core.command.LogContainerResultCallback;
import com.github.dockerjava.core.command.PullImageResultCallback;
public abstract class AbstractDockerClientTest extends Assert {
public static final Logger LOG = LoggerFactory.getLogger(AbstractDockerClientTest.class);
protected DockerClient dockerClient;
protected TestDockerCmdExecFactory dockerCmdExecFactory = initTestDockerCmdExecFactory();
protected TestDockerCmdExecFactory initTestDockerCmdExecFactory() {
return new TestDockerCmdExecFactory(
DockerClientBuilder.getDefaultDockerCmdExecFactory());
}
public void beforeTest() throws Exception {
LOG.info("======================= BEFORETEST =======================");
LOG.info("Connecting to Docker server");
dockerClient = DockerClientBuilder.getInstance(config())
.withDockerCmdExecFactory(dockerCmdExecFactory)
.build();
try {
dockerClient.inspectImageCmd("busybox").exec();
} catch (NotFoundException e) {
LOG.info("Pulling image 'busybox'");
// need to block until image is pulled completely
dockerClient.pullImageCmd("busybox").withTag("latest").exec(new PullImageResultCallback()).awaitSuccess();
}
assertNotNull(dockerClient);
LOG.info("======================= END OF BEFORETEST =======================\n\n");
}
private DefaultDockerClientConfig config() {
return config(null);
}
protected DefaultDockerClientConfig config(String password) {
DefaultDockerClientConfig.Builder builder = DefaultDockerClientConfig.createDefaultConfigBuilder()
.withRegistryUrl("https://index.docker.io/v1/");
if (password != null) {
builder = builder.withRegistryPassword(password);
}
return builder.build();
}
public void afterTest() {
LOG.info("======================= END OF AFTERTEST =======================");
}
public void beforeMethod(Method method) {
LOG.info(String.format("################################## STARTING %s ##################################",
method.getName()));
}
public void afterMethod(ITestResult result) {
for (String container : dockerCmdExecFactory.getContainerNames()) {
LOG.info("Cleaning up temporary container {}", container);
try {
dockerClient.removeContainerCmd(container).withForce(true).exec();
} catch (DockerException ignore) {
// ignore.printStackTrace();
}
}
for (String image : dockerCmdExecFactory.getImageNames()) {
LOG.info("Cleaning up temporary image with {}", image);
try {
dockerClient.removeImageCmd(image).withForce(true).exec();
} catch (DockerException ignore) {
// ignore.printStackTrace();
}
}
for (String volume : dockerCmdExecFactory.getVolumeNames()) {
LOG.info("Cleaning up temporary volume with {}", volume);
try {
dockerClient.removeVolumeCmd(volume).exec();
} catch (DockerException ignore) {
// ignore.printStackTrace();
}
}
for (String networkId : dockerCmdExecFactory.getNetworkIds()) {
LOG.info("Cleaning up temporary network with {}", networkId);
try {
dockerClient.removeNetworkCmd(networkId).exec();
} catch (DockerException ignore) {
// ignore.printStackTrace();
}
}
LOG.info("################################## END OF {} ##################################\n", result.getName());
}
protected String asString(InputStream response) {
return consumeAsString(response);
}
public static String consumeAsString(InputStream response) {
StringWriter logwriter = new StringWriter();
try {
LineIterator itr = IOUtils.lineIterator(response, "UTF-8");
while (itr.hasNext()) {
String line = itr.next();
logwriter.write(line + (itr.hasNext() ? "\n" : ""));
LOG.info("line: " + line);
}
response.close();
return logwriter.toString();
} catch (IOException e) {
throw new RuntimeException(e);
} finally {
IOUtils.closeQuietly(response);
}
}
// UTIL
/**
* Checks to see if a specific port is available.
*
* @param port
* the port to check for availability
*/
public static Boolean available(int port) {
if (port < 1100 || port > 60000) {
throw new IllegalArgumentException("Invalid start port: " + port);
}
ServerSocket ss = null;
DatagramSocket ds = null;
try {
ss = new ServerSocket(port);
ss.setReuseAddress(true);
ds = new DatagramSocket(port);
ds.setReuseAddress(true);
return true;
} catch (IOException ignored) {
} finally {
if (ds != null) {
ds.close();
}
if (ss != null) {
try {
ss.close();
} catch (IOException e) {
/* should not be thrown */
}
}
}
return false;
}
protected MountedVolumes mountedVolumes(Matcher<? super List<Volume>> subMatcher) {
return new MountedVolumes(subMatcher, "Mounted volumes", "mountedVolumes");
}
private static class MountedVolumes extends FeatureMatcher<InspectContainerResponse, List<Volume>> {
public MountedVolumes(Matcher<? super List<Volume>> subMatcher, String featureDescription, String featureName) {
super(subMatcher, featureDescription, featureName);
}
@Override
public List<Volume> featureValueOf(InspectContainerResponse item) {
List<Volume> volumes = new ArrayList<Volume>();
for (Mount mount : item.getMounts()) {
volumes.add(mount.getDestination());
}
return volumes;
}
}
protected String containerLog(String containerId) throws Exception {
return dockerClient.logContainerCmd(containerId).withStdOut(true).exec(new LogContainerTestCallback())
.awaitCompletion().toString();
}
public static class LogContainerTestCallback extends LogContainerResultCallback {
protected final StringBuffer log = new StringBuffer();
List<Frame> collectedFrames = new ArrayList<Frame>();
boolean collectFrames = false;
public LogContainerTestCallback() {
this(false);
}
public LogContainerTestCallback(boolean collectFrames) {
this.collectFrames = collectFrames;
}
@Override
public void onNext(Frame frame) {
if(collectFrames) collectedFrames.add(frame);
log.append(new String(frame.getPayload()));
}
@Override
public String toString() {
return log.toString();
}
public List<Frame> getCollectedFrames() {
return collectedFrames;
}
}
protected String buildImage(File baseDir) throws Exception {
return dockerClient.buildImageCmd(baseDir).withNoCache(true).exec(new BuildImageResultCallback())
.awaitImageId();
}
protected Network findNetwork(List<Network> networks, String name) {
for (Network network : networks) {
if (StringUtils.equals(network.getName(), name)) {
return network;
}
}
fail("No network found.");
return null;
}
}