CLOVER🍀

That was when it all began.

WildFly 25+Codehaus Cargo Maven 3 Pluginでインテグレーションテスト

これは、なにをしたくて書いたもの?

前にWildFlyとArquillianを使ったエントリを書いたのですが。

WildFly 25+Arquillian+JUnit 5でインテグレーションテスト(Managed/Remote/Bootable JAR) - CLOVER🍀

Codehaus Cargoを使ったインテグレーションテストもやってみたいなと思い、試してみることにしました。

Codehaus Cargo - Home

Codehaus Cargo - Maven 3 Plugin

Arquillianとの直接の比較にはならないとは思いますが。目的や機能が違うので。

Codehaus Cargo

Codehaus Cargoは、Java EE/Jakarta EEのアプリケーションサーバーをAPIで操作する機能を提供します。

Codehaus Cargo - Home

アプリケーションサーバーの起動や停止、アプリケーションのデプロイなどができます。

使用する形態もいくつかあり、Java APIとして使ったり、JUnitのテスト中に利用したり、MavenやAntに組み込んで
使えたりします。

Codehaus Cargo - Functional testing

Codehaus Cargo - Maven 3 Plugin

Codehaus Cargo - Ant support

そして、アプリケーションサーバーの操作を行うために、各アプリケーションサーバーの実装向けの機能が
作り込まれています。

今回はCodehaus Cargo 3 Maven Pluginを使い、インテグレーションテストを実行時にアプリケーションサーバーを
起動してデプロイ、テスト終了時にアプリケーションサーバーを停止する、という流れを書いてみようと思います。
※ "3"というのは、Apache Maven 3のことを指しているみたいです

使用するアプリケーションサーバーは、WildFly 25とします。

また、WildFlyはCodehaus Cargo Maven 3 Pluginでダウンロードする方法と、すでにダウンロード済みの
WildFlyを使う方法の2つを行いたいと思います。

参考

今回、参考にした情報はこのあたりです。

Codehaus Cargo - Maven 3 Plugin

Codehaus Cargo - Maven 3 Plugin Getting Started

Codehaus Cargo - Deploying to a running container

Codehaus Cargo - Starting and stopping a container

Integration Testing with the Maven Cargo plugin | Baeldung

また、Codehaus Cargo Maven 3 PluginでWildFly 25を操作するのには、こちらを参照しました。

Codehaus Cargo - WildFly 25.x

各アプリケーションサーバーの種類、バージョンごとに実装が用意されているみたいです。

また、設定に関してはAPIドキュメントやソースコードを見ることになるかもしれません。

Overview (Codehaus Cargo 1.9.8 API)

org.codehaus.cargo.maven3.configuration (Codehaus Cargo 1.9.8 API)

https://github.com/codehaus-cargo/cargo/blob/codehaus-cargo-1.9.8/extensions/maven3/plugin/src/main/java/org/codehaus/cargo/maven3/configuration/Configuration.java

https://github.com/codehaus-cargo/cargo/blob/codehaus-cargo-1.9.8/extensions/maven3/plugin/src/main/java/org/codehaus/cargo/maven3/configuration/Container.java

https://github.com/codehaus-cargo/cargo/blob/codehaus-cargo-1.9.8/core/api/container/src/main/java/org/codehaus/cargo/container/ContainerType.java

環境

今回の環境は、こちらです。

$ java --version
openjdk 11.0.11 2021-04-20
OpenJDK Runtime Environment (build 11.0.11+9-Ubuntu-0ubuntu2.20.04)
OpenJDK 64-Bit Server VM (build 11.0.11+9-Ubuntu-0ubuntu2.20.04, mixed mode, sharing)


$ mvn --version
Apache Maven 3.8.3 (ff8e977a158738155dc465c6a97ffaf31982d739)
Maven home: $HOME/.sdkman/candidates/maven/current
Java version: 11.0.11, vendor: Ubuntu, runtime: /usr/lib/jvm/java-11-openjdk-amd64
Default locale: ja_JP, platform encoding: UTF-8
OS name: "linux", version: "5.4.0-89-generic", arch: "amd64", family: "unix"

WildFlyは、25.0.1.Finalを使用します。

準備

インテグレーションテストを行うための、テスト用のプログラムを作成します。

対象は、簡単なJAX-RSを使ったアプリケーションにしましょう。

    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
        <maven.compiler.source>11</maven.compiler.source>
        <maven.compiler.target>11</maven.compiler.target>
        <failOnMissingWebXml>false</failOnMissingWebXml>
    </properties>

    <dependencies>
        <dependency>
            <groupId>jakarta.platform</groupId>
            <artifactId>jakarta.jakartaee-web-api</artifactId>
            <version>8.0.0</version>
            <scope>provided</scope>
        </dependency>

        <dependency>
            <groupId>org.junit.jupiter</groupId>
            <artifactId>junit-jupiter</artifactId>
            <version>5.8.1</version>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>io.rest-assured</groupId>
            <artifactId>rest-assured</artifactId>
            <version>4.4.0</version>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>com.fasterxml.jackson.core</groupId>
            <artifactId>jackson-databind</artifactId>
            <version>2.13.0</version>
            <scope>test</scope>
        </dependency>
    </dependencies>

    <build>
        <plugins>
            <plugin>
                <artifactId>maven-surefire-plugin</artifactId>
                <version>2.22.2</version>
            </plugin>
            <plugin>
                <artifactId>maven-failsafe-plugin</artifactId>
                <version>3.0.0-M5</version>
                <configuration>
                    <systemPropertyVariables>
                        <web.archive.name>${project.artifactId}</web.archive.name>
                    </systemPropertyVariables>
                </configuration>
                <executions>
                    <execution>
                        <id>integration-test</id>
                        <goals>
                            <goal>integration-test</goal>
                        </goals>
                    </execution>
                </executions>
            </plugin>
        </plugins>
    </build>

    <profiles>
        <profile>
            <id>install</id>
            <activation>                                                                                                                     
                <activeByDefault>true</activeByDefault>                                                                                      
            </activation> 
            <!-- あとで -->
        </profile>
        <profile>
            <id>existing</id>
            <!-- あとで -->
        </profile>
    </profiles>
</project>

テストは、JUnit 5とREST Assuredで行います。

        <dependency>
            <groupId>org.junit.jupiter</groupId>
            <artifactId>junit-jupiter</artifactId>
            <version>5.8.1</version>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>io.rest-assured</groupId>
            <artifactId>rest-assured</artifactId>
            <version>4.4.0</version>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>com.fasterxml.jackson.core</groupId>
            <artifactId>jackson-databind</artifactId>
            <version>2.13.0</version>
            <scope>test</scope>
        </dependency>

Maven Failsafe Pluginも適用。

            <plugin>
                <artifactId>maven-failsafe-plugin</artifactId>
                <version>3.0.0-M5</version>
                <configuration>
                    <systemPropertyVariables>
                        <web.archive.name>${project.artifactId}</web.archive.name>
                    </systemPropertyVariables>
                </configuration>
                <executions>
                    <execution>
                        <id>integration-test</id>
                        <goals>
                            <goal>integration-test</goal>
                        </goals>
                    </execution>
                </executions>
            </plugin>

Codehaus Cargo Maven 3 Pluginは、Mavenのプロファイルを分けて設定することにします。

    <profiles>
        <profile>
            <id>install</id>
            <activation>                                                                                                                     
                <activeByDefault>true</activeByDefault>                                                                                      
            </activation> 
            <!-- あとで -->
        </profile>
        <profile>
            <id>existing</id>
            <!-- あとで -->
        </profile>
    </profiles>

installはCodehaus Cargo Maven 3 PluginでWildFlyをダウンロードしてきて解凍、起動・停止をするように
設定したもので、existingはすでにローカルにインストールされているWildFlyを起動・停止するように
設定したプロファイルです。

続いて、ソースコード。

JAX-RS有効化。

src/main/java/org/littlewings/wildfly/cargo/JaxrsActivator.java

package org.littlewings.wildfly.cargo;

import javax.ws.rs.ApplicationPath;
import javax.ws.rs.core.Application;

@ApplicationPath("")
public class JaxrsActivator extends Application {
}

JAX-RSリソースクラス。

src/main/java/org/littlewings/wildfly/cargo/EchoResource.java

package org.littlewings.wildfly.cargo;

import java.util.Map;
import javax.ws.rs.GET;
import javax.ws.rs.POST;
import javax.ws.rs.Path;
import javax.ws.rs.Produces;
import javax.ws.rs.QueryParam;
import javax.ws.rs.core.MediaType;

@Path("echo")
public class EchoResource {
    @GET
    @Produces(MediaType.TEXT_PLAIN)
    public String get(@QueryParam("message") String message) {
        return String.format("★★★ %s ★★★", message);
    }

    @POST
    @Produces(MediaType.APPLICATION_JSON)
    public Map<String, Object> post(Map<String, Object> request) {
        return Map.of("message", String.format("★★★ %s ★★★", request.get("message")));
    }
}

GET、POSTで、送信されてきたメッセージを装飾して返すクラスです。

JAX-RSリソースクラスに対する、REST Assuredを使った対応するテストコード。クラス名をITで終わらせて、
インテグレーションテストで動かすようにしています。

src/test/java/org/littlewings/wildfly/cargo/EchoIT.java

package org.littlewings.wildfly.cargo;

import java.util.Map;

import io.restassured.http.ContentType;
import org.junit.jupiter.api.Test;

import static io.restassured.RestAssured.given;
import static org.hamcrest.Matchers.is;

public class EchoIT {
    String baseUrl = "http://localhost:8080/" + System.getProperty("web.archive.name");

    @Test
    public void get() {
        given()
                .queryParam("message", "Hello World")
                .when()
                .get(String.format("%s/%s", baseUrl, "echo"))
                .then()
                .assertThat()
                .statusCode(200)
                .body(is("★★★ Hello World ★★★"));
    }

    @Test
    public void post() {
        given()
                .contentType(ContentType.JSON)
                .body(Map.of("message", "Hello World"))
                .when()
                .post(String.format("%s/%s", baseUrl, "echo"))
                .then()
                .assertThat()
                .statusCode(200)
                .body("message", is("★★★ Hello World ★★★"));
    }
}

では、Codehaus Cargo Maven 3 Pluginを使ってテストしていきましょう。

WildFlyをCodehaus Cargo Maven 3 Pluginでダウンロードして実行する

まずはCodehaus Cargo Maven 3 PluginでWildFlyをダウンロードして、テストを行うようにしてみましょう。

設定は、こうなりました。

        <profile>
            <id>install</id>
            <activation>
                <activeByDefault>true</activeByDefault>
            </activation>
            <build>
                <plugins>
                    <plugin>
                        <groupId>org.codehaus.cargo</groupId>
                        <artifactId>cargo-maven3-plugin</artifactId>
                        <version>1.9.8</version>
                        <configuration>
                            <container>
                                <containerId>wildfly25x</containerId>
                                <zipUrlInstaller>
                                    <url>https://github.com/wildfly/wildfly/releases/download/25.0.1.Final/wildfly-25.0.1.Final.zip</url>
                                    <downloadDir>${project.build.directory}/cargo/downloads</downloadDir>
                                    <extractDir>${project.build.directory}/cargo/extract</extractDir>
                                </zipUrlInstaller>
                            </container>
                        </configuration>
                        <executions>
                            <execution>
                                <id>start-server</id>
                                <phase>pre-integration-test</phase>
                                <goals>
                                    <goal>start</goal>
                                </goals>
                            </execution>
                        </executions>
                    </plugin>
                </plugins>
            </build>
        </profile>

WildFlyをダウンロードする設定は、こちら。${project.build.directory}(target)配下にダウンロード(downloadDir)して、
展開します(extractDir)。

                        <configuration>
                            <container>
                                <containerId>wildfly25x</containerId>
                                <zipUrlInstaller>
                                    <url>https://github.com/wildfly/wildfly/releases/download/25.0.1.Final/wildfly-25.0.1.Final.zip</url>
                                    <downloadDir>${project.build.directory}/cargo/downloads</downloadDir>
                                    <extractDir>${project.build.directory}/cargo/extract</extractDir>
                                </zipUrlInstaller>
                            </container>
                        </configuration>

zipUrlInstallerの使い方は、こちら。

Codehaus Cargo - Installer

urlには、WildFlyをダウンロードするURLそのものを指定します。

<url>https://github.com/wildfly/wildfly/releases/download/25.0.1.Final/wildfly-25.0.1.Final.zip</url>

WildFlyをダウンロードした後は、pre-integration-testフェーズで起動します。

                        <executions>
                            <execution>
                                <id>start-server</id>
                                <phase>pre-integration-test</phase>
                                <goals>
                                    <goal>start</goal>
                                </goals>
                            </execution>
                        </executions>

あとは、テストを実行。
※このパターンはデフォルトのProfileにしています

$ mvn verify

終了すると、WildFlyも停止します。

以下のようにpost-integration-testフェーズで明示的にstopを入れて、しっかり停止処理を実行させてもいいのですが、

                            <execution>
                                <id>stop-server</id>
                                <phase>post-integration-test</phase>
                                <goals>
                                    <goal>stop</goal>
                                </goals>
                            </execution>

こうするとテストが失敗しても、stopでビルド成功、になってしまいます…。

[INFO] 
[ERROR] Tests run: 2, Failures: 1, Errors: 0, Skipped: 0
[INFO] 
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------
[INFO] Total time:  21.476 s
[INFO] Finished at: 2021-11-11T00:05:07+09:00
[INFO] ------------------------------------------------------------------------

微妙…。

WildFlyのダウンロードや起動、デプロイに関するディレクトリを見てみましょう。

ダウンロードしたWildFlyはこちら。展開先も。

$ ll target/cargo/downloads
合計 216064
drwxrwxr-x 2 xxxxx xxxxx      4096 11月 10 23:33 ./
drwxrwxr-x 5 xxxxx xxxxx      4096 11月 11 00:24 ../
-rw-rw-r-- 1 xxxxx xxxxx 221236239 11月  3 04:04 wildfly-25.0.1.Final.zip



$ ll target/cargo/extract/wildfly-25.0.1.Final
合計 16
drwxrwxr-x  3 xxxxx xxxxx 4096 11月 11 00:03 ./
drwxrwxr-x  3 xxxxx xxxxx 4096 11月 11 00:03 ../
-rw-rw-r--  1 xxxxx xxxxx   23 11月 11 00:03 .cargo
drwxrwxr-x 11 xxxxx xxxxx 4096 11月 11 00:03 wildfly-25.0.1.Final/

なんか、wildfly-25.0.1.Finalというディレクトリが2重になっていますが…。

$ ll target/cargo/extract/wildfly-25.0.1.Final/wildfly-25.0.1.Final
合計 580
drwxrwxr-x 11 xxxxx xxxxx   4096 11月 11 00:03 ./
drwxrwxr-x  3 xxxxx xxxxx   4096 11月 11 00:03 ../
drwxrwxr-x  2 xxxxx xxxxx   4096 11月  2 18:06 .installation/
drwxrwxr-x  3 xxxxx xxxxx   4096 11月 11 00:03 .well-known/
-rw-rw-r--  1 xxxxx xxxxx  26530 11月  2 18:06 LICENSE.txt
-rw-rw-r--  1 xxxxx xxxxx   2162 11月  2 18:06 README.txt
drwxrwxr-x  3 xxxxx xxxxx   4096 11月 11 00:03 appclient/
drwxrwxr-x  3 xxxxx xxxxx   4096 11月 11 00:03 bin/
-rw-rw-r--  1 xxxxx xxxxx  19358 11月  2 18:06 copyright.txt
drwxrwxr-x  6 xxxxx xxxxx   4096 11月 11 00:03 docs/
drwxrwxr-x  4 xxxxx xxxxx   4096 11月 11 00:03 domain/
-rw-rw-r--  1 xxxxx xxxxx 495304 11月  2 18:06 jboss-modules.jar
drwxrwxr-x  3 xxxxx xxxxx   4096 11月 11 00:03 modules/
drwxrwxr-x  6 xxxxx xxxxx   4096 11月 11 00:03 standalone/
drwxrwxr-x  2 xxxxx xxxxx   4096 11月 11 00:03 welcome-content/

実際にデプロイされるのは、こちらだったりします。

$ ll target/cargo/configurations/wildfly25x
合計 32
drwxrwxr-x 8 xxxxx xxxxx 4096 11月 11 00:24 ./
drwxrwxr-x 3 xxxxx xxxxx 4096 11月 11 00:24 ../
-rw-rw-r-- 1 xxxxx xxxxx    0 11月 11 00:24 .cargo
drwxrwxr-x 3 xxxxx xxxxx 4096 11月 11 00:24 configuration/
drwxrwxr-x 6 xxxxx xxxxx 4096 11月 11 00:24 data/
drwxrwxr-x 2 xxxxx xxxxx 4096 11月 11 00:24 deployments/
drwxrwxr-x 3 xxxxx xxxxx 4096 11月 11 00:24 lib/
drwxrwxr-x 2 xxxxx xxxxx 4096 11月 11 00:24 log/
drwxrwxr-x 4 xxxxx xxxxx 4096 11月 11 00:24 tmp/

デプロイ時のログ。

[INFO] [stalledLocalDeployer] Deploying [/path/to/wildfly-integration-test-with-cargo/target/wild
fly-integration-test-with-cargo-0.0.1-SNAPSHOT.war] to [/path/to/wildfly-integration-test-with-ca
rgo/target/cargo/configurations/wildfly25x/deployments]...

ダウンロード・展開したアプリケーションサーバーとは、設定は異なるディレクトリで管理されるんですね。

Codehaus Cargo Maven 3 Pluginでインストール済みのWildFlyを使ってテストをする

続いて、インストール済みのWildFlyを使ってCodehaus Cargo Maven 3 Pluginを使って、WildFlyを起動、テスト、
停止します。

WildFlyをダウンロードしておきます。

$ curl -OL https://github.com/wildfly/wildfly/releases/download/25.0.1.Final/wildfly-25.0.1.Final.zip
$ unzip wildfly-25.0.1.Final.zip

Codehaus Cargo Maven 3 Pluginを使った設定は、こちら。

        <profile>
            <id>existing</id>
            <build>
                <plugins>
                    <plugin>
                        <groupId>org.codehaus.cargo</groupId>
                        <artifactId>cargo-maven3-plugin</artifactId>
                        <version>1.9.8</version>
                        <configuration>
                            <container>
                                <containerId>wildfly25x</containerId>
                                <type>installed</type>
                                <home>/path/to/wildfly-25.0.1.Final</home>
                            </container>
                            <configuration>
                                <type>existing</type>
                                <home>/path/to/wildfly-25.0.1.Final/standalone</home>
                            </configuration>
                        </configuration>
                        <executions>
                            <execution>
                                <id>start-server</id>
                                <phase>pre-integration-test</phase>
                                <goals>
                                    <goal>start</goal>
                                </goals>
                            </execution>
                            <execution>
                                <id>undeploy</id>
                                <phase>post-integration-test</phase>
                                <goals>
                                    <goal>undeploy</goal>
                                </goals>
                            </execution>
                        </executions>
                    </plugin>
                </plugins>
            </build>
        </profile>

インストールしたWildFlyのディレクトリと、standaloneディレクトリをそれぞれ指定します。

                        <configuration>
                            <container>
                                <containerId>wildfly25x</containerId>
                                <type>installed</type>
                                <home>/path/to/wildfly-25.0.1.Final</home>
                            </container>
                            <configuration>
                                <type>existing</type>
                                <home>/path/to/wildfly-25.0.1.Final/standalone</home>
                            </configuration>
                        </configuration>

pre-integration-testフェーズにWildFlyを起動し、post-integration-testフェーズでアンデプロイするように指定。

                        <executions>
                            <execution>
                                <id>start-server</id>
                                <phase>pre-integration-test</phase>
                                <goals>
                                    <goal>start</goal>
                                </goals>
                            </execution>
                            <execution>
                                <id>undeploy</id>
                                <phase>post-integration-test</phase>
                                <goals>
                                    <goal>undeploy</goal>
                                </goals>
                            </execution>
                        </executions>

アンデプロイを入れないと、そのままWARファイルが残り続けます…。

実行。

$ mvn verify -Pexisting

インストール済みのWildFlyが起動し、ふつうにデプロイが行われます。そして、テストも行われます。

デプロイ時の情報。

[INFO] [talledLocalContainer] 00:37:07,884 INFO  [org.jboss.as.server] (ServerService Thread Pool -- 45) WFLYSRV0010: Deployed "cargocpc.war" (runtime-name : "cargocpc.war")
[INFO] [talledLocalContainer] 00:37:07,885 INFO  [org.jboss.as.server] (ServerService Thread Pool -- 45) WFLYSRV0010: Deployed "wildfly-integration-test-with-cargo.war" (runtime-name : "wildfly-integration-test-with-cargo.war")

post-integration-testフェーズでundeployを入れているので、テストが失敗した際にビルドが失敗しないのは、
先のパターンから予想できることですね…。

[INFO] 
[ERROR] Tests run: 2, Failures: 1, Errors: 0, Skipped: 0

...

[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------
[INFO] Total time:  42.053 s
[INFO] Finished at: 2021-11-10T23:58:30+09:00
[INFO] ------------------------------------------------------------------------

これなら、stopも含めてもいいかもしれません。

                            <execution>
                                <id>undeploy</id>
                                <phase>post-integration-test</phase>
                                <goals>
                                    <goal>undeploy</goal>
                                    <goal>stop</goal>
                                </goals>
                            </execution>

ちなみに、undeployおよびstopはなくても、WildFly自体は停止します。強制終了みたいな感じには見えますが。

また、すでに起動済みのWildFlyにデプロイしたければ、startを外せばOKです。

ちょっと組み合わせは考えどころですが、とりあえずこんなところでしょうか。

まとめ

Codehaus Cargo Maven 3 Pluginを使って、WildFlyをダウンロードしたり、起動・停止の合間にインテグレーションテストを
してみました。

post-integration-testフェーズでアプリケーションサーバーを停止させるかは、テストの失敗でビルドが失敗しなくなるので
微妙なところですが、使うならちょっと組み合わせを考えたいところですね。

Arquillianと組み合わせて使うのもありかもしれません。