Arquillian Warp and TomEE


Arquillian Warp is a great extension to the (now) well known Arquillian library allowing you to execute client code (web browsing for instance) and validating server state.

The last released version is the 1.0.0.Alpha1. I got some issues working with it so here some tips to make it work as fast as possible.

First (not mandatory but better) exclude slf4j-log4j from warp (that’s a transitive dependency which doesn’t bring back slf4j-api so it makes slf4j not usable in the webapp).

<dependency>
  <groupId>org.jboss.arquillian.extension</groupId>
  <artifactId>arquillian-warp-impl</artifactId>
  <version>1.0.0.Alpha1</version>
  <scope>test</scope>
  <exclusions>
   <exclusion>
      <groupId>org.slf4j</groupId>
      <artifactId>slf4j-log4j12</artifactId>
    </exclusion>
  </exclusions>
</dependency>

I used with warp graphene-webdriver 2 and (as usually tomee):

<dependency>
  <groupId>org.jboss.arquillian.graphene</groupId>
  <artifactId>graphene-webdriver</artifactId>
  <version>2.0.0.Alpha2</version>
  <type>pom</type>
  <scope>test</scope>
</dependency>


<dependency>
  <groupId>org.apache.openejb</groupId>
  <artifactId>arquillian-tomee-remote</artifactId>
  <version>1.5.1-SNAPSHOT</version>
</dependency>
<dependency>
  <groupId>org.jboss.arquillian.junit</groupId>
  <artifactId>arquillian-junit-container</artifactId>
  <version>1.0.2.Final</version>
</dependency>
<dependency>
  <groupId>junit</groupId>
  <artifactId>junit</artifactId>
  <version>4.10</version>
</dependency>

Now let say you have a servlet on “/hello” pattern/mapping.

Because it is warp Alpha1 we can’t get the request injected automatically so you can add a filter storing the request in a thread local if you need it:

import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.annotation.WebFilter;
import javax.servlet.http.HttpServletRequest;
import java.io.IOException;

@WebFilter(urlPatterns = "/*")
public class RequestHolder implements Filter {
    public static final ThreadLocal<HttpServletRequest> REQUESTS = new ThreadLocal<HttpServletRequest>();

    @Override
    public void init(final FilterConfig filterConfig) throws ServletException {
        // no-op
    }

    @Override
    public void doFilter(final ServletRequest request, final ServletResponse response, final FilterChain chain) throws IOException, ServletException {
        REQUESTS.set((HttpServletRequest) request);
        try {
            chain.doFilter(request,response);
        } finally {
            REQUESTS.remove();
        }
    }

    @Override
    public void destroy() {
        // no-op
    }
}

Here we are! We can write our Warp test.

Some elements are mandatory:

  • @WarpTest on the test class
  • @RunAsClient on test method
  • @Deployment(testable = true) (by default but don’t override it with testable = false)

The idea is to associte with “client actions” (go on page /hello for us) some server assertions (check the hello servlet added a name in the session for instance).

What to take care about:

  • Use static class for ServerAssertions (Alpha2 will support inner classes)
  • configure the scan.xml file to exclude (=include others) the test class otherwise you’ll need to enrich the war with all its needed dependencies (graphene, selenium…) to be able to load completely the test class

Here the test:

import org.jboss.arquillian.container.test.api.Deployment;
import org.jboss.arquillian.container.test.api.RunAsClient;
import org.jboss.arquillian.drone.api.annotation.Drone;
import org.jboss.arquillian.junit.Arquillian;
import org.jboss.arquillian.test.api.ArquillianResource;
import org.jboss.arquillian.warp.ClientAction;
import org.jboss.arquillian.warp.ServerAssertion;
import org.jboss.arquillian.warp.Warp;
import org.jboss.arquillian.warp.WarpTest;
import org.jboss.arquillian.warp.extension.servlet.AfterServlet;
import org.jboss.arquillian.warp.extension.servlet.BeforeServlet;
import org.jboss.arquillian.warp.server.filter.WarpFilter;
import org.jboss.shrinkwrap.api.ArchivePaths;
import org.jboss.shrinkwrap.api.ShrinkWrap;
import org.jboss.shrinkwrap.api.asset.StringAsset;
import org.jboss.shrinkwrap.api.spec.WebArchive;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.openqa.selenium.WebDriver;

import javax.servlet.http.HttpServletRequest;
import java.io.IOException;
import java.net.URL;

import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNull;

@WarpTest
@RunWith(Arquillian.class)
public class WarpDemoTest {
    @Deployment
    public static WebArchive jar() {
        return ShrinkWrap.create(WebArchive.class, "hello-warp.war")
                    // in this test we don't have a lot of JEE classes so simply list them
                    // in real world we'll use <packages> tag
                    .addAsWebInfResource(new StringAsset("<scan>" +
                            "   <classes>" +
                            "       <class>" + HelloWeb.class.getName() + "</class>" +
                            "       <class>" + WarpFilter.class.getName() + "</class>" +
                            "       <class>" + RequestHolder.class.getName() + "</class>" +
                            "   </classes>" +
                            "</scan>"), ArchivePaths.create("scan.xml"))
                    .addClasses(HelloWeb.class, RequestHolder.class);
    }

    @ArquillianResource
    private URL contextRoot;

    @Drone
    private WebDriver driver;

    @Test
    @RunAsClient
    public void validSessionUpdate() throws IOException {
        Warp.execute(new ClientAction() {
            @Override
            public void action() { // call our servlet which store hello as name in the session
                driver.navigate().to(contextRoot.toExternalForm() + "hello");
            }
        }).verify(new NameSessionAttributeAssertion()); // valid the name is in the session
    }

    // static class because in Warp Alpha1 the test will be serialized otherwise
    public static class NameSessionAttributeAssertion extends ServerAssertion {
        /* with next warp version (Alpha2) we'll be able to do (and remove RequestHolder):
        @ArquillianResource
        private HttpServletRequest request;
        */

        @BeforeServlet
        public void beforeServlet() {
            assertNull(name());
        }

        @AfterServlet
        public void afterServlet() {
            assertEquals("hello", name());
        }

        private String name() {
            return (String) RequestHolder.REQUESTS.get().getSession().getAttribute("name");
        }
    }
}

I would like to thank (again) Aslask Knutsen for his help on this topic.

1 thought on “Arquillian Warp and TomEE

Leave a comment