これは、なにをしたくて書いたもの?
前に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は、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>
<projectbuildsourceEncoding>UTF-8</projectbuildsourceEncoding>
<projectreportingoutputEncoding>UTF-8</projectreportingoutputEncoding>
<mavencompilersource>11</mavencompilersource>
<mavencompilertarget>11</mavencompilertarget>
<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>
<webarchivename>${project.artifactId}</webarchivename>
</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>
<webarchivename>${project.artifactId}</webarchivename>
</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を使ってテストしていきましょう。
まずは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]...
ダウンロード・展開したアプリケーションサーバーとは、設定は異なるディレクトリで管理されるんですね。
続いて、インストール済みの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と組み合わせて使うのもありかもしれません。