これは、なにをしたくて書いたもの?
前にWildFlyとArquillianを使ったエントリを書いたのですが。
WildFly 25+Arquillian+JUnit 5でインテグレーションテスト(Managed/Remote/Bootable JAR) - CLOVER🍀
Codehaus Cargoを使ったインテグレーションテストもやってみたいなと思い、試してみることにしました。
Codehaus Cargo - Maven 3 Plugin
Arquillianとの直接の比較にはならないとは思いますが。目的や機能が違うので。
Codehaus Cargo
Codehaus Cargoは、Java EE/Jakarta EEのアプリケーションサーバーをAPIで操作する機能を提供します。
アプリケーションサーバーの起動や停止、アプリケーションのデプロイなどができます。
使用する形態もいくつかあり、Java APIとして使ったり、JUnitのテスト中に利用したり、MavenやAntに組み込んで
使えたりします。
Codehaus Cargo - Functional testing
Codehaus Cargo - Maven 3 Plugin
そして、アプリケーションサーバーの操作を行うために、各アプリケーションサーバーの実装向けの機能が
作り込まれています。
今回は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を操作するのには、こちらを参照しました。
各アプリケーションサーバーの種類、バージョンごとに実装が用意されているみたいです。
また、設定に関してはAPIドキュメントやソースコードを見ることになるかもしれません。
Overview (Codehaus Cargo 1.9.8 API)
org.codehaus.cargo.maven3.configuration (Codehaus Cargo 1.9.8 API)
環境
今回の環境は、こちらです。
$ 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
の使い方は、こちら。
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と組み合わせて使うのもありかもしれません。