== Containerless Server and Docker In all previous sections we have seen that the application is deployed inside a container. For example in case of _Tomcat_ application, resources are deployed inside a _Servlet_ container or for example in case of _Apache TomEE_ you can deploy _EJBs_ inside an _EJB_ container. But nowadays there other kind of applications that contains the container (if they have one) embedded inside them. Typically these applications uses an embedded server and they are run as _CLI_ applications. Some examples can be _Spring Boot_, _Netty_, _SparkJava_ or _Undertow_. If you are using some of these technologies with _Docker_, you can still use *Arquillian Cube* to write your tests. === Java Embedded Servers Let's suppose we are writing a service which should return as text the current day and time. To serve this service to the world we decide to use _undertow_ embedded server. The code looks like: [source, java] .DaytimeServer.java ---- import io.undertow.Undertow; import io.undertow.server.HttpHandler; import io.undertow.server.HttpServerExchange; import io.undertow.util.Headers; import java.text.SimpleDateFormat; import java.util.Date; public class DaytimeServer { public static void main(String[] args) { //<1> Undertow server = Undertow.builder() .addHttpListener(8080, "0.0.0.0") .setHandler(new HttpHandler() { @Override public void handleRequest(final HttpServerExchange exchange) throws Exception { SimpleDateFormat simpleDateFormat = new SimpleDateFormat(); exchange.getResponseHeaders().put(Headers.CONTENT_TYPE, "text/plain"); exchange.getResponseSender().send(simpleDateFormat.format(new Date()) + System.lineSeparator()); //<2> } }).build(); server.start(); } } ---- <1> This class is a CLI application. <2> Returns a text with the day and time formatted with +SimpleDateFormat+. See that this application is a CLI application which is pretty different from previous examples. Previously the packaged application was deployed inside an application server, which in fact means that *Arquillian* connects to the server and tells it to deploy that file. In this example there is no application server nor servlet server waiting for *Arquillian* to deploy an archive but the application is self-contained, it contains everything. So in fact if you want to run the application probably you will end up by doing something like +java -jar daytime.jar+. So how to write a test for these classes if we are using _Docker_ as runtime container? The first thing to do is add +arquillian-cube-containerless+ dependency. [source, xml] .pom.xml ---- org.arquillian.cube arquillian-cube-containerless ${arquillian.cube.version} ---- Next step is creating a +Dockerfile+. This is required because we need to set not only the container image to be used but how to run the application. But see that there is a problem on creating a +Dockerfile+ in this case. The +jar+ name is not static because it will depend on the name you give during the creation of the archive (using _Shrinkwrap_). So in fact +Dockerfile+ should be templaterized. And this is something that *Arquillian Cube* can do for you. The idea is creating a file called +DockerfileTemplate+. [source, terminal] .src/test/resources/daytime/DockerfileTemplate ---- FROM java:7 WORKDIR /usr/src/server COPY ${deployableFilename} /usr/src/server/${deployableFilename} # <1> EXPOSE 8080 CMD ["java", "-jar", "${deployableFilename}"] ---- <1> +${deployableFilname}+ will be replaced at runtime by the name of the +jar+ file created by _Shrinkwrap_. Then we need to touch +arquillian.xml+ file by setting an special container definition so *Arquillian* doesn't crash because of trying to deploy the archive into a none defined container. [source, xml] .src/test/resources/arquillian.xml ---- 1.12 http://localhost:2375 daytime: buildImage: dockerfileLocation: src/test/resources/undertow noCache: true remove: true await: strategy: polling portBindings: [8080/tcp] daytime 8080 ---- <1> The Docker container is defined as per usual. <2> buildImage attribute is used to define the dockerfile location. <3> This attribute sets the directory where the +Dockerfile+ is stored. In fact in this case it is the directory where +DockerfileTemplate+ file is stored. <4> A container provided by *Arquillian Cube* must be defined. <5> This property is used to set which container must be started. <6> This property sets the exposed port by the embedded server. IMPORTANT: If containerless definition only contains only one image, it is not necessary to use _containerlessDocker_ property. At the same time if the image only exposes one port, it is not necessary to use _embeddedPort_ proeprty to set the port. So in previous example you could avoid using _containerlessDocker_ and _embeddedPort_. And finally the test: [source, java] .DaytimeTest.java ---- @RunWith(Arquillian.class) public class DaytimeTest { private static final String LINE_SEPARATOR = System .getProperty("line.separator"); @Deployment(testable = false) //<1> public static JavaArchive createDeployment() { JavaArchive[] undertow = Maven.resolver().resolve("io.undertow:undertow-core:1.1.1.Final").withTransitivity().as(JavaArchive.class); //<2> JavaArchive jar = ShrinkWrap .create(JavaArchive.class, "daytime.jar") .addClass(DaytimeServer.class); //<3> for (JavaArchive javaArchive : undertow) { //<4> jar.merge(javaArchive); } jar.addAsManifestResource( new StringAsset( "Main-Class: org.arquillian.cube.impl.containerless.DaytimeServer" + LINE_SEPARATOR), "MANIFEST.MF"); //<5> return jar; } @Test public void shouldReturnDateFromDaytimeServer(@ArquillianResource URL base) { //<6> try ( BufferedReader in = new BufferedReader(new InputStreamReader( base.openStream()));) { String userInput = in.readLine(); assertThat(userInput, notNullValue()); } catch (UnknownHostException e) { fail("Don't know about host "); } catch (IOException e) { fail("Couldn't get I/O for the connection to "); } } } ---- <1> Tests should be run as-client. <2> _ShrinkWrap_ Maven resolver gets all dependencies for _Undertow_. <3> Create a +jar+ file called +daytime.jar+ with +DaytimeServer+ class. <4> +Undertow+ dependencies are merged inside +jar+. <5> Because it is a runnable +jar+, +MANIFEST+ is created accordantly. <6> Simple test.