Category Archives: jboss / wildfly

Building an executable jar with embedded web server

To make using and deploying our application easier, I want it to be easy to run the application. Instead of requiring the installation of a servlet server like Tomcat, Jetty or a full blown application server, I aim to use an embedded server.

The end result is the ability to run our application using the following command:

java -jar application.jar

Possibly using some additional parameters like

java -DserverPort=8080 -DshutdownPort=8089 -jar application.jar

As web server I chose Undertow, a relatively new server which is also used in WildFly.

I want the result jar to still show the included libraries, so I do not want to make an uber-jar using something like the maven shade plugin. I rather want to build a jar which includes jars with all the dependencies.

Building this jar can be done using the maven assembly plugin, using a configuration like the following:

<assembly xmlns="http://maven.apache.org/plugins/maven-assembly-plugin/assembly/1.1.3"
          xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
          xsi:schemaLocation="http://maven.apache.org/plugins/maven-assembly-plugin/assembly/1.1.3 http://maven.apache.org/xsd/assembly-1.1.3.xsd">
    <id>with-deps</id>
    <formats>
        <format>jar</format>
    </formats>
    <includeBaseDirectory>false</includeBaseDirectory>
    <fileSets>
        <fileSet>
            <outputDirectory>/</outputDirectory>
            <directory>${basedir}/target/classes</directory>
            <excludes>
                <exclude>.PLACEHOLDER.txt</exclude>
            </excludes>
        </fileSet>
    </fileSets>
    <dependencySets>
        <dependencySet>
            <excludes>
                <exclude>ggg:aaa-exe</exclude>
            </excludes>
            <outputDirectory>/lib</outputDirectory>
            <useProjectArtifact>true</useProjectArtifact>
            <unpack>false</unpack>
            <scope>runtime</scope>
        </dependencySet>
    </dependencySets>
</assembly>

I use a separate module to build the jar. In this module the main pom mainly contains all the application dependencies and the following configuration:

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
    <modelVersion>4.0.0</modelVersion>
 
    <parent>
        <groupId>ggg</groupId>
        <artifactId>aaa</artifactId>
        <version>vvv-SNAPSHOT</version>
    </parent>
 
    <artifactId>aaa-exe</artifactId>
    <packaging>jar</packaging>
 
    <name>Build executable jar</name>
 
    <dependencies>
        <!-- module dependencies which build the application -->
    </dependencies>
 
    <build>
        <plugins>
            <plugin>
                <artifactId>maven-assembly-plugin</artifactId>
                <version>2.5.4</version>
                <configuration>
                    <descriptors>
                        <descriptor>${basedir}/src/assembly/include-deps.xml</descriptor>
                    </descriptors>
                    <archive>
                        <manifest>
                            <mainClass>myapp.WarRunner</mainClass>
                            <addDefaultImplementationEntries>true</addDefaultImplementationEntries>
                        </manifest>
                        <manifestEntries>
                            <Implementation-Version>${project.version}</Implementation-Version>
                        </manifestEntries>
                    </archive>
                </configuration>
                <executions>
                    <execution>
                        <id>make-assembly</id> <!-- this is used for inheritance merges -->
                        <phase>package</phase> <!-- bind to the packaging phase -->
                        <goals>
                            <goal>single</goal>
                        </goals>
                    </execution>
                </executions>
            </plugin>
        </plugins>
    </build>
</project>

This module will now build two jars, a normal jar (very small) and one with the dependencies which has the “with-deps” suffix. The latter can be used to start the application.

In the module itself we need only two classes.

We need a main class to start the application (the “mainClass” which is referenced in the manifest). This should start the application. To assure that the embedded jars are used, we need a special classloader. Apart from that, the main method refers to a different class which runs the application.

public final class WarRunner {
 
    private WarRunner() {
        // hide constructor
    }
 
    /**
     * Run de "real" runner from the application.
     *
     * @param args command line parameters
     */
    public static void main(String[] args) {
        try {
            JarClassLoader.invokeMain("myapp.AppRunner", args);
        } catch (Throwable e) {
            System.err.println("Cannot run myapp.AppRunner: " + e.getMessage());
            e.printStackTrace();
        }
    }
 
}

The second class is the JarClassLoader. This is based on the code from embedded jar classloader, but with some fixes.

public class JarClassLoader extends URLClassLoader {
 
    private static boolean isJar(String fileName) {
        return fileName != null && fileName.toLowerCase().endsWith(".jar");
    }
 
    private static File jarEntryAsFile(JarFile jarFile, JarEntry jarEntry) throws IOException {
        String name = jarEntry.getName().replace('/', '_');
        int i = name.lastIndexOf(".");
        String extension = i > -1 ? name.substring(i) : "";
        File file = File.createTempFile(name.substring(0, name.length() - extension.length()) + ".", extension);
        file.deleteOnExit();
        try (InputStream input = jarFile.getInputStream(jarEntry)) {
            try (OutputStream output = new FileOutputStream(file)) {
                int readCount;
                byte[] buffer = new byte[4096];
                while ((readCount = input.read(buffer)) != -1) {
                    output.write(buffer, 0, readCount);
                }
                return file;
            }
        } 
    }
 
    /**
     * Build classpath with extra jars in it.
     * @param urls urls
     * @param parent parent class loader
     */
    public JarClassLoader(URL[] urls, ClassLoader parent) {
        super(urls, parent);
        try {
            ProtectionDomain protectionDomain = getClass().getProtectionDomain();
            CodeSource codeSource = protectionDomain.getCodeSource();
            URL rootJarUrl = codeSource.getLocation();
            String rootJarName = rootJarUrl.getFile();
            if (isJar(rootJarName)) {
                addJarResource(new File(rootJarUrl.getPath()));
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
 
    private void addJarResource(File file) throws IOException {
        JarFile jarFile = new JarFile(file);
        addURL(file.toURL());
        Enumeration<JarEntry> jarEntries = jarFile.entries();
        while (jarEntries.hasMoreElements()) {
            JarEntry jarEntry = jarEntries.nextElement();
            if (!jarEntry.isDirectory() && isJar(jarEntry.getName())) {
                addJarResource(jarEntryAsFile(jarFile, jarEntry));
            }
        }
    }
 
    @Override
    public synchronized Class<?> loadClass(String name) throws ClassNotFoundException {
        try {
            Class<?> clazz = findLoadedClass(name);
            if (clazz == null) {
                clazz = findClass(name);
            }
            return clazz;
        } catch (ClassNotFoundException e) {
            return super.loadClass(name);
        }
    }
 
    /**
     * Invoke main method in given class using this classloader.
     * @param name class to invoke
     * @param args command line arguments
     * @throws ClassNotFoundException oops
     * @throws NoSuchMethodException oops
     * @throws InvocationTargetException oops
     */
    public static void invokeMain(String name, String[] args) throws ClassNotFoundException, NoSuchMethodException, InvocationTargetException {
        ClassLoader contextClassLoader = Thread.currentThread().getContextClassLoader();
        try {
            final String mainMethodName = "main";
            JarClassLoader loader = new JarClassLoader(((URLClassLoader) ClassLoader.getSystemClassLoader()).getURLs(), contextClassLoader);
            Thread.currentThread().setContextClassLoader(loader); // replace contextClassloader
            Class<?> clazz = loader.loadClass(name);
            Method method = clazz.getMethod(mainMethodName, String[].class);
            method.setAccessible(true);
            int mods = method.getModifiers();
            if (method.getReturnType() != void.class || !Modifier.isStatic(mods) || !Modifier.isPublic(mods)) {
                throw new NoSuchMethodException(mainMethodName);
            }
            try {
                method.invoke(null, (Object) args); // Crazy cast "(Object)args" because param is: "Object... args"
            } catch (IllegalAccessException e) {
                // This should not happen, as we have disabled access checks
                System.err.println("Probleem during JarClassLoader.invokeMain: " + e.getMessage());
                e.printStackTrace();
            }
        } finally {
            Thread.currentThread().setContextClassLoader(contextClassLoader);
        }
    }
 
}

What remains to be done is write the AppRunner class (which should be in the module with the application code):

public final class AppRunner {
 
    private static final Logger LOG = LoggerFactory.getLogger(AppRunner.class);
 
    private static final String CONTEXT_PATH = "/app";
    private static final int SERVER_PORT = 8080;
    private static final int SHUTDOWN_PORT = 8089;
    private static final int SHUTDOWN_WAIT = 5;
 
    private static GracefulShutdownHandler shutdownHandler;
    private static Undertow server;
 
    private AppRunner() {
        // hide constructor
    }
 
    /**
     * Main method to start the application
     *
     * @param args command line parameters - not used at the moment - configuration through properties
     */
    public static void main(final String[] args) {
        int serverPort = getProperty("km.server.port").orElse(SERVER_PORT);
        int shutdownPort = getProperty("km.shutdown.port").orElse(SHUTDOWN_PORT);
        int shutdownWaitSeconds = getProperty("km.shutdown.wait").orElse(SHUTDOWN_WAIT);
 
        try {
            ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
            DeploymentInfo servletBuilder = Servlets.deployment()
                    .setClassLoader(AppRunner.class.getClassLoader())
                    .setContextPath(CONTEXT_PATH)
                    .setDeploymentName("app.war")
                    .addInitParameter("contextConfigLocation", "classpath:app-web-applicationContext.xml")
                    .addInitParameter("resteasy.logger.type", "SLF4J")
                    .addInitParameter("resteasy.wider.request.matching", "true")
                    .addWelcomePage("index.html")
                    .setDefaultSessionTimeout(60)
                    .addListener(new ListenerInfo(RequestContextListener.class))
                    .addListener(new ListenerInfo(ResteasyBootstrap.class))
                    .addListener(new ListenerInfo(SpringContextLoaderListener.class))
                    .addServlets(Servlets.servlet("RESTEasy", HttpServletDispatcher.class)
                            .addMapping("/rest/*"))
                    .setResourceManager(new ClassPathResourceManager(classLoader, "web"));
 
            DeploymentManager manager = Servlets.defaultContainer().addDeployment(servletBuilder);
            manager.deploy();
 
            HttpHandler servletHandler = manager.start();
            PathHandler path = Handlers.path(Handlers.redirect(CONTEXT_PATH))
                    .addPrefixPath(CONTEXT_PATH, servletHandler);
            shutdownHandler = Handlers.gracefulShutdown(path);
            server = Undertow.builder()
                    .addHttpListener(serverPort, "localhost")
                    .addHttpListener(shutdownPort, "localhost", exchange -> {
                        exchange.getResponseHeaders().put(Headers.CONTENT_TYPE, "text/plain");
                        exchange.getResponseSender().send(
                                String.format("Going to shutdown when all requests have ended or %s seconds, whichever occurs first.", shutdownWaitSeconds));
                        new Thread(() -> {
                            try {
                                shutdownHandler.shutdown();
                                shutdownHandler.awaitShutdown(shutdownWaitSeconds * 1000);
                            } catch (InterruptedException ie) {
                                LOG.warn("Wait for undertow requests to end was interrupted.", ie);
                            }
                            server.stop();
                            LOG.info("Gracefully shut down.");
                            System.exit(0);
                        }).run();
                    })
                    .setHandler(shutdownHandler)
                    .build();
            server.start();
 
        }  catch (ServletException e) {
            LOG.error("Kan servlet niet starten.", e);
        }
    }
 
    private static Optional<Integer> getProperty(String propertyName) {
        String propertyValue = System.getProperty("km.server.port");
        if (StringUtils.isNotBlank(propertyValue)) {
            try {
                return Optional.of(Integer.parseInt(propertyValue));
            } catch (NumberFormatException nfe) {
                LOG.error(String.format("Cannot parse property %s with value %s to a number, ignoring value.", propertyName, propertyValue));
            }
        }
        return Optional.empty();
    }
 
}

This code starts creates a servlet. It says that the resources to be served can be found in the “web” package (as there is no webapp (folder) you have to give the explicit location.
It also registers a shutdown handler. Any request on the shutdown port will block incoming requests and wait for max 5s until pending requests are all handled. Then the server is shut down.

EE integration testing using Arquillian

Writing tests in a EE environment is a challenge. Compared to test support in spring framework there is some work.

Fortunately though, thanks to Arquillian, there is hope.

A lot of the complications are related with the difference in environment. In spring framework, you include all the libraries in your application, which means everything is readily available. In EE you need a container which provides facilities which are not directly included. Arquillian fixes this by allowing you to run your tests inside the container.

An Arquillian tests is almost the same as a non-Arquillian test, except that you also have to build the deployment package to run the test. While the general recommendation seems that you make such package as small as possible, I believe this can be a challenge as you do need all dependencies for these minimal classes needed for the test. In my mind it seems best to simply deploy the full package under development (jar or war) to run your tests.

The situation in Spring is similar. While it is easy to have a different context for each test, in practice it is better to reduce the number of context for running tests. Partly to make sure there are no dangling dependencies and partly to reduce the run time of your test suite.

In Arquillian the complexity is again slightly increased as you also need to include all project dependencies (as in “other” jars). You have to specify the project classes to include and the location of all dependencies.

In my application I use a base class for all integration tests. The dependency details are picked up from the maven pom (including sub-dependencies – unfourtunately just including all dependencies at once did not work). For the project classes themselves, I use a helper to simply include all classes of a package include the sub-packages which are found in the source. You also need to make sure all required resources are managed. Here again they are scanned from the source.

@RunWith(Arquillian.class)
public abstract class AbstractIT {
 
    private static final String SOURCES_DIR = "src/main/java";
    private static final String RESOURCES_DIR = "src/main/resources";
 
    @Deployment
    public static Archive<?> createDeployment() throws Exception {
        String pathPrefix = ""; // trick to make this work from both the main as
        // module root directory
        File currentDir = new File(".");
        if (!currentDir.getCanonicalPath().endsWith("back-impl")) {
            pathPrefix = "back-impl/";
        }
        PomEquippedResolveStage pom = Maven.resolver().loadPomFromFile(pathPrefix + "pom.xml");
        File[] commonsLang = pom.resolve("org.apache.commons:commons-lang3").withTransitivity().asFile();
        File[] appApi = pom.resolve("be.myapp:myapp-api").withTransitivity().asFile();
        File[] jTransfoCore = pom.resolve("org.jtransfo:jtransfo-core").withTransitivity().asFile();
        File[] jTransfoCdi = pom.resolve("org.jtransfo:jtransfo-cdi").withTransitivity().asFile();
        File[] queryDsl = pom.resolve("com.mysema.querydsl:querydsl-jpa").withTransitivity().asFile();
        File[] flyway = pom.resolve("com.googlecode.flyway:flyway-core").withTransitivity().asFile();
        File[] festAssert = pom.resolve("org.easytesting:fest-assert").withTransitivity().asFile();
        File[] httpclient = pom.resolve("org.apache.httpcomponents:httpclient").withTransitivity().asFile();
        File[] deltaspikeCore = pom.resolve("org.apache.deltaspike.core:deltaspike-core-impl").withTransitivity().asFile();
        File[] deltaspikeData = pom.resolve("org.apache.deltaspike.modules:deltaspike-data-module-impl").withTransitivity().asFile();
        WebArchive war = ShrinkWrap.create(WebArchive.class, "test.war").
                addAsLibraries(commonsLang).
                addAsLibraries(appApi).
                addAsLibraries(jTransfoCore).
                addAsLibraries(jTransfoCdi).
                addAsLibraries(queryDsl).
                addAsLibraries(flyway).
                addAsLibraries(festAssert).
                addAsLibraries(httpclient).
                addAsLibraries(deltaspikeCore).
                addAsLibraries(deltaspikeData).
                addAsResource("META-INF/persistence.xml").
                addAsResource("META-INF/beans.xml");
        addAllPackages(war, "be.fluxtock.back.impl", new File(pathPrefix + SOURCES_DIR + "/be/fluxtock/back/impl"));
        addAllResources(war, pathPrefix + RESOURCES_DIR);
        return war;
    }
 
    /**
     * Add all packages starting with given prefix from given path.
     *
     * @param war war archive to add packages to
     * @param prefix base package
     * @param dir directory for the base package
     */
    private static void addAllPackages(WebArchive war, String prefix, File dir) {
        war.addPackage(prefix);
        for (File file : dir.listFiles(File::isDirectory)) {
            addAllPackages(war, prefix + "." + file.getName(), file);
        }
    }
 
    /**
     * Add all resources from the given directory, recursively. Only adds
     * subdirectories when they start with a lower case letter
     *
     * @param war war archive to add packages to
     * @param directory directory with resources to add
     */
    private static void addAllResources(WebArchive war, String directory) {
        for (File file : new File(directory).listFiles(pathname -> pathname.isFile() || Character.isLowerCase(pathname.getName().charAt(0)))) {
            addAllResources(war, "", file);
        }
    }
 
    private static void addAllResources(WebArchive war, String prefix, File dir) {
        if (dir.isDirectory()) {
            prefix += dir.getName() + "/";
            for (File file : dir.listFiles()) {
                addAllResources(war, prefix, file);
            }
        } else {
            war.addAsResource(dir, prefix + dir.getName());
        }
    }
 
}

To allow the dependencies to be resolved from the pom, you need an extra dependency.

<dependency>
    <groupId>org.jboss.shrinkwrap.resolver</groupId>
    <artifactId>shrinkwrap-resolver-impl-maven</artifactId>
    <version>2.0.0</version>
    <scope>test</scope>
</dependency>

When using a database to run your tests, you also need to make sure your database is not polluted by your tests. Something similar to Spring’s AbstractTransactionalJUnit4SpringContextTests can be built quite easily.

/**
 * Transactional integration test. Transaction is rolled back at the end.
 */
public abstract class AbstractRollbackIT extends AbstractIT {
 
    @PersistenceContext
    EntityManager em;
 
    @Inject
    UserTransaction utx;
 
    @Before
    public void setUp() throws Exception {
        utx.begin();
        em.joinTransaction();
    }
 
    @After
    public void tearDown() throws Exception {
        utx.rollback();
    }
 
}

With these base classes test are running fine. Unfortunately it does seem that a new deployment is created for each test. It would be nice (and faster) if tests which share the same deployment could also reuse that deployment – reducing the number of times the deployment is started in the container. Fortunately – compared to context initialization in spring framework – this initialization is very fast, but it would probably make a big difference when there are many integration tests.

Setting up WildFly for integration testing and Arquillian using maven

For a multi-module JEE7 project, I wanted to be able to have a WildFly setup which is ready for both integration testing using Arquillian and regular integration testing (REST client and Selenium).

To be able to test JEE code, Arquillian is a suitable option (the only I know of). This runs the tests in container. I did not manage to get the embedded container working with WildFly, so the Arquillian tests use the same WildFly version as the traditional integration tests.

From maven, using cargo is handy when dealing with application servers. This can install the server you want and it can run your deployed application, including waiting for the application to fully load.

The build was organized in a way to assure only one WildFly copy was built and configured and that copy is used for the tests in all modules and for for tests in the IDE.

Then configuration is entirely done in the parent pom for the project. Only modules which do client testing (using Selenium, REST tests or other) need the following configration (these need to be war or ear modules):

<plugin>
    <groupId>org.codehaus.cargo</groupId>
    <artifactId>cargo-maven2-plugin</artifactId>
</plugin>

This allows you to use “mvn cargo:run” on that module and also assures the container with the module deployed is running while doing integration tests.

We need quite a bit of configuration in the parent pom.
For starters, some properties:

<properties>
    <wildfly.home.parent>${project.basedir}/.cargo/extracts/wildfly-8.0.0.CR1/wildfly-8.0.0.CR1</wildfly.home.parent>
    <wildfly.home.module>${project.basedir}/../.cargo/extracts/wildfly-8.0.0.CR1/wildfly-8.0.0.CR1</wildfly.home.module>
    <jboss.home>${wildfly.home.module}</jboss.home>
 
    <postgresql.version>9.3-1100-jdbc41</postgresql.version>
    <wildfly.version>8.0.0.CR1</wildfly.version>
</properties>

We configure two locations where WildFly can be found, one to be used from child modules (one level down the directory tree), and one relative with the parent pom. We also configure an alias for the module path, partly because it us shorter, partly because the Arquillian WildFly container expects a jbossHome variable.

Some variables need to be known when the tests are running, so configure the following plugins:

<plugin>
    <groupId>org.apache.maven.plugins</groupId>
    <artifactId>maven-surefire-plugin</artifactId>
    <version>2.14.1</version>
    <configuration>
        <argLine>${argLine} -Xmx1124m -Xms256m</argLine>
        <systemPropertyVariables>
            <java.util.logging.manager>org.jboss.logmanager.LogManager</java.util.logging.manager>
            <jboss.home>${jboss.home}</jboss.home>
            <module.path>${jboss.home}/modules</module.path>
        </systemPropertyVariables>
    </configuration>
</plugin>
 
<plugin>
    <groupId>org.apache.maven.plugins</groupId>
    <artifactId>maven-failsafe-plugin</artifactId>
    <version>2.16</version>
    <configuration>
        <argLine>${argLine} -Xmx1024m -Xms256m</argLine>
        <systemPropertyVariables>
            <java.util.logging.manager>org.jboss.logmanager.LogManager</java.util.logging.manager>
            <jboss.home>${jboss.home}</jboss.home>
            <module.path>${jboss.home}/modules</module.path>
        </systemPropertyVariables>
    </configuration>
    <executions>
        <execution>
            <id>integration-test</id>
            <goals>
                <goal>integration-test</goal>
            </goals>
        </execution>
        <execution>
            <id>verify</id>
            <goals>
                <goal>verify</goal>
            </goals>
        </execution>
    </executions>
</plugin>

Now we need to configure cargo for starting and stopping the container on integration tests (in pluginManagement):

<plugin>
    <groupId>org.codehaus.cargo</groupId>
    <artifactId>cargo-maven2-plugin</artifactId>
    <version>1.4.6</version>
    <configuration>
        <container>
            <containerId>wildfly8x</containerId>
            <log>${basedir}/target/cargo.log</log>
            <output>${basedir}/target/wildfly.log</output>
            <zipUrlInstaller>
                <url>http://download.jboss.org/wildfly/8.0.0.CR1/wildfly-8.0.0.CR1.zip</url>
                <downloadDir>${project.basedir}/../.cargo/downloads</downloadDir>
                <extractDir>${project.basedir}/../.cargo/extracts</extractDir>
            </zipUrlInstaller>
        </container>
        <configuration>
            <properties>
                <cargo.servlet.port>8080</cargo.servlet.port>
                <cargo.logging>medium</cargo.logging>
                <cargo.jvmargs>${argLine} -Denv=test -Dtapestry.execution-mode=development</cargo.jvmargs>
                <cargo.jboss.configuration>standalone-full</cargo.jboss.configuration>
            </properties>
        </configuration>
    </configuration>
    <executions>
        <execution>
            <id>start-cargo</id>
            <phase>pre-integration-test</phase>
            <goals><goal>start</goal></goals>
            <configuration>
                <deployables>
                    <deployable>
                        <!-- Use exploded deploy: override location to point to the exploded webapp. -->
                        <location>${project.basedir}/target/${project.artifactId}-${project.version}</location>
                        <pingURL>http://localhost:8080/myApp</pingURL>
                        <pingTimeout>120000</pingTimeout> <!-- 2 min -->
                        <properties>
                            <context>myApp</context>
                        </properties>
                    </deployable>
                </deployables>
            </configuration>
        </execution>
        <execution>
            <id>stop-cargo</id>
            <phase>post-integration-test</phase>
            <goals><goal>stop</goal></goals>
        </execution>
    </executions>
</plugin>

This indicates that cargo needs to be started and stopped before and after integration tests. It also indicates where WildFly can be found.

To make this work, we need to assure the installed WildFly is preconfigured. In my case I need a fix to allow httpclient to be used and I need to assure the correct data source is installed (both the driver jar and the configuration itself). This can be done using the command:

mvn -Dsetup process-test-resources

The configuration is put in a profile to assure it is not included in every build. As the .cargo is not cleared when running “mvn clean” the configuration is long lasting.

<profile>
    <!-- setup wildfly container for use by cargo -->
    <id>setup-cargo</id>
    <activation>
        <property>
            <name>setup</name>
        </property>
    </activation>
    <build>
        <plugins>
            <plugin>
                <inherited>false</inherited>
                <groupId>org.codehaus.cargo</groupId>
                <artifactId>cargo-maven2-plugin</artifactId>
                <configuration>
                    <container>
                        <containerId>wildfly8x</containerId>
                        <zipUrlInstaller>
                            <url>http://download.jboss.org/wildfly/8.0.0.CR1/wildfly-8.0.0.CR1.zip</url>
                            <downloadDir>${project.basedir}/.cargo/downloads</downloadDir>
                            <extractDir>${project.basedir}/.cargo/extracts</extractDir>
                        </zipUrlInstaller>
                    </container>
                </configuration>
                <executions>
                    <execution>
                        <id>install-cargo</id>
                        <phase>process-test-resources</phase>
                        <goals><goal>install</goal></goals>
                    </execution>
                </executions>
            </plugin>
            <plugin>
                <inherited>false</inherited>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-dependency-plugin</artifactId>
                <version>2.8</version>
                <executions>
                    <execution>
                        <id>copy-db-driver</id>
                        <phase>process-test-resources</phase>
                        <goals>
                            <goal>copy</goal>
                        </goals>
                        <configuration>
                            <artifactItems>
                                <artifactItem>
                                    <groupId>org.postgresql</groupId>
                                    <artifactId>postgresql</artifactId>
                                    <version>${postgresql.version}</version>
                                    <outputDirectory>${wildfly.home.parent}/standalone/deployments</outputDirectory>
                                </artifactItem>
                            </artifactItems>
                        </configuration>
                    </execution>
                </executions>
            </plugin>
            <plugin>
                <inherited>false</inherited>
                <artifactId>maven-resources-plugin</artifactId>
                <version>2.6</version>
                <executions>
                    <execution>
                        <id>copy-resources-ds</id>
                        <phase>process-test-resources</phase>
                        <goals>
                            <goal>copy-resources</goal>
                        </goals>
                        <configuration>
                            <outputDirectory>${wildfly.home.parent}/standalone/deployments</outputDirectory>
                            <resources>
                                <resource>
                                    <directory>etc/wildfly/deploy/test</directory>
                                    <filtering>false</filtering>
                                </resource>
                            </resources>
                        </configuration>
                    </execution>
                    <execution>
                        <id>copy-resources-wfly-2634</id>
                        <phase>process-test-resources</phase>
                        <goals>
                            <goal>copy-resources</goal>
                        </goals>
                        <configuration>
                            <outputDirectory>${wildfly.home.parent}/modules/system/layers/base/org/jboss/resteasy/resteasy-jaxrs/main</outputDirectory>
                            <resources>
                                <resource>
                                    <directory>etc/wildfly/deploy/WFLY-2634</directory>
                                    <filtering>false</filtering>
                                </resource>
                            </resources>
                        </configuration>
                    </execution>
                </executions>
            </plugin>
        </plugins>
    </build>
</profile>

To finish, your arquillian.xml needs to be configured correctly.

<?xml version="1.0" encoding="UTF-8"?>
<arquillian xmlns="http://jboss.org/schema/arquillian"
            xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
            xsi:schemaLocation="http://jboss.org/schema/arquillian http://jboss.org/schema/arquillian/arquillian_1_0.xsd">
 
    <defaultProtocol type="Servlet 3.0" />
 
    <container qualifier="jboss" default="true">
        <configuration>
            <property name="jbossHome">${jboss.home}</property>
            <property name="serverConfig">standalone-full.xml</property>
            <!-- uncomment below for debugging
            <property name="javaVmArguments">-Xmx512m -XX:MaxPermSize=128m -agentlib:jdwp=transport=dt_socket,server=y,suspend=y,address=8787</property>
            -->
        </configuration>
    </container>
</arquillian>

Using the maven build always uses the correct WildFly installation and my IDE (IntelliJ IDEA) allows me to run individual Arquillian tests.