Ok here there is the example:
@RunWith(Arquillian.class)
public class DockerTest {
@Deployment(managed = false, name = "helloworld", testable = false) //<1>
public static WebArchive createDeployment() {
return ShrinkWrap.create(WebArchive.class, "hello.war")
.addClass(HelloWorldServlet.class); //<2>
}
@ArquillianResource
private Deployer deployer;
@InSequence(1)
@Test
public void startDockerContainer() {
DockerClientConfigBuilder configBuilder = DockerClientConfig
.createDefaultConfigBuilder();
configBuilder.withVersion("1.12").withUri("http://localhost:2375"); //<3>
final DockerClient dockerClient = DockerClientBuilder.getInstance(
configBuilder.build()).build();
ExposedPort jmxPort = ExposedPort.tcp(8089);
final CreateContainerResponse container = dockerClient
.createContainerCmd("tutum/tomcat:7.0")
.withEnv(
"TOMCAT_PASS=mypass",
"JAVA_OPTS=-Dcom.sun.management.jmxremote.port=8089 -Dcom.sun.management.jmxremote.ssl=false -Dcom.sun.management.jmxremote.authenticate=false")
.withExposedPorts(jmxPort).exec(); //<4>
ExposedPort tomcatPort = ExposedPort.tcp(8080);
Ports ports = new Ports(tomcatPort, Ports.Binding(8080));
ports.bind(jmxPort, Ports.Binding(8089));
Runtime.getRuntime().addShutdownHook(new Thread() {
public void run() {
dockerClient.stopContainerCmd(container.getId()).exec();
}
});
dockerClient.startContainerCmd(container.getId())
.withPortBindings(ports).exec(); //<5>
new Thread() {
public void run() {
dockerClient.waitContainerCmd(container.getId()).exec(); //<6>
}
}.start();
}
@InSequence(2)
@Test
public void executeTest() throws InterruptedException,
IOException {
System.out.println("Waiting for container");
Thread.sleep(5000); //<7>
deployer.deploy("helloworld");
URL obj = new URL("http://localhost:8080/hello/HelloWorld");
HttpURLConnection con = (HttpURLConnection) obj.openConnection();
con.setRequestMethod("GET");
BufferedReader in = new BufferedReader(
new InputStreamReader(con.getInputStream()));
String inputLine;
StringBuffer response = new StringBuffer();
while ((inputLine = in.readLine()) != null) {
response.append(inputLine);
}
in.close();
//print result
System.out.println(response.toString());
}
}
There is some hints to be discussed here.
<1> Because it is a simple test not an extension I need to decide when the container is ready to be used.
<2> No secret here an standard package
<3> Some configuration parameters for docker server (note that docker server could be even remote, which means that you can execute your tests to remote docker platform like openshift or tutum.
<4> To create a container we may require to configure a lot of parameters like expose ports, name, quota, …
<5> And more parameters when you want to start the container.
<6> Note that some containers does not return the control, for example in this case (and same for AS), if server is not started as linux service, the control is never returned to caller, so we need to create a thread to not block the execution and stop the container when the JVM dies.
<7> Because of <6> we can know when the container is started but not when the process after the container is booted up is started. For this reason we will need to implement some mechanism to ensure that the AS is up and running.
So for me the first thing to discuss is the configuration. As you may see in https://docs.docker.com/reference/api/docker_remote_api_v1.12/#create-a-container every command has a lot of possible configuration parameters. First approach could be add them in arquillian.xml, but I think it would be a headache for us and for the final users. Do you think to configure the docker server inside arquillian.xml but the rest of parameters use a yaml configuration file? Also I think that it would be easier when we want to boot several docker containers at same test. I am thinking of something like http://www.fig.sh/index.html
Another problem is @ArquillianResource if users use port forwarding then no problem, if not then we will need to use the REST API to get the container IP and deploy the webarchive. But this leave us to another problem. In arquillian.xml you configure the host of remote server. If you don’t use port forwarding then you need to get the ip that docker server has given to the container (which may change in every execution), so we need a way to modify dynamically the property of remote adapter. Of course we can make port forwarding mandatory.
A feature I see I think it would be amazing to implement is that you can even create your containers from Dockerfile from Java. So users would be able to create container images from test and more important they will be able to materialize the Shrinkwrap deployment file inside the container itself.
I send you the pom file used:
<properties>
<maven.compiler.source>1.7</maven.compiler.source>
<maven.compiler.target>1.7</maven.compiler.target>
</properties>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.jboss.arquillian</groupId>
<artifactId>arquillian-bom</artifactId>
<version>1.1.5.Final</version>
<scope>import</scope>
<type>pom</type>
</dependency>
</dependencies>
</dependencyManagement>
<dependencies>
<dependency>
<groupId>org.apache.tomcat</groupId>
<artifactId>tomcat-servlet-api</artifactId>
<version>7.0.56</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.11</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>com.github.docker-java</groupId>
<artifactId>docker-java</artifactId>
<version>0.10.2</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.jboss.arquillian.container</groupId>
<artifactId>arquillian-tomcat-remote-7</artifactId>
<version>1.0.0.CR7</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.jboss.arquillian.junit</groupId>
<artifactId>arquillian-junit-container</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
And arquillian.xml
<?xml version="1.0"?>
<arquillian xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="http://jboss.org/schema/arquillian"
xsi:schemaLocation="http://jboss.org/schema/arquillian http://www.jboss.org/schema/arquillian/arquillian_1_0.xsd">
<container qualifier="tomcat" default="true">
<configuration>
<property name="host">localhost</property>
<property name="port">8080</property>
<property name="user">admin</property>
<property name="pass">mypass</property>
</configuration>
</container>
</arquillian>
For me next steps is to create some kind of BDD specs of what the extension should do.
WDYT?