最近、組み込みTomcatにJAX-RSとCDIを載せて動かしていることが多いのですが、ちょっとしたテストの時に便利だなぁという感じで使っています。ただ、Java EE系のテストといえばArquillianだということで、ふと見た時に気になったのがこの人。
WildFly 8.1.0 - Embedded
https://docs.jboss.org/author/display/ARQ/WildFly+8.1.0+-+Embedded
別に、組み込みWildfFlyというわけではありません。
このページに書かれているMavenの設定の雰囲気を見ていると、WildFlyをダウンロードしてきてそのまま実行しよう!みたいなものみたいです。
ちょっと気になったので、試してみました。
が、いつも通りここはScalaでやります。
使用しているWildFlyは、8.2.0.Finalです。sbtでやっているので、WildFlyは自分でダウンロードしたものを使いました。
ビルド設定
まずは、sbtの設定。
build.sbt
name := "arquillian-wildfly-container-embedded" version := "0.0.1-SNAPSHOT" scalaVersion := "2.11.6" scalacOptions ++= Seq("-Xlint", "-unchecked", "-deprecation", "-feature") updateOptions := updateOptions.value.withCachedResolution(true) fork in Test := true javaOptions ++= Seq("-Djava.util.logging.manager=org.jboss.logmanager.LogManager") // embedded resolvers += "JBoss Public Maven Repository Group" at "https://repository.jboss.org/nexus/content/groups/public/" libraryDependencies ++= Seq( "javax" % "javaee-web-api" % "7.0" % "provided", "org.jboss.arquillian.junit" % "arquillian-junit-container" % "1.1.8.Final" % "test", "org.jboss.shrinkwrap.resolver" % "shrinkwrap-resolver-depchain" % "2.2.0-beta-2" % "test", "org.wildfly" % "wildfly-arquillian-container-embedded" % "8.2.0.Final" % "test", // embedded // "org.wildfly" % "wildfly-arquillian-container-managed" % "8.2.0.Final" % "test", // managed "org.scalatest" %% "scalatest" % "2.2.4" % "test", "junit" % "junit" % "4.12" % "test" )
コメントに「// embedded」と「// managed」とありますが、Managedに切り替える時は「// embedded」と書いている行をコメントアウトすると切り替わります。
テスト対象
テスト対象のコードとして、CDI管理Bean、JAX-RS関連のクラスを作成。
CDI管理Bean。
src/main/scala/org/littlewings/javaee7/service/CalcService.scala
package org.littlewings.javaee7.service import javax.enterprise.context.RequestScoped @RequestScoped class CalcService { def add(a: Int, b: Int): Int = a + b def multiply(a: Int, b: Int): Int = a * b }
JAX-RS関連。
src/main/scala/org/littlewings/javaee7/rest/JaxrsApplication.scala
package org.littlewings.javaee7.rest import javax.ws.rs.ApplicationPath import javax.ws.rs.core.Application @ApplicationPath("rest") class JaxrsApplication extends Application
リソースクラス。
src/main/scala/org/littlewings/javaee7/rest/CalcResource.scala
package org.littlewings.javaee7.rest import javax.enterprise.context.RequestScoped import javax.inject.Inject import javax.ws.rs.{ DefaultValue, GET, Path, QueryParam, Produces } import javax.ws.rs.core.MediaType import org.littlewings.javaee7.service.CalcService @Path("calc") @RequestScoped class CalcResource { @Inject private var calcService: CalcService = _ @GET @Path("add") @Produces(Array(MediaType.TEXT_PLAIN)) def add(@QueryParam("a") @DefaultValue("0") a: Int, @QueryParam("b") @DefaultValue("0") b: Int): Int = calcService.add(a, b) @GET @Path("multiply") @Produces(Array(MediaType.TEXT_PLAIN)) def multiply(@QueryParam("a") @DefaultValue("0") a: Int, @QueryParam("b") @DefaultValue("0") b: Int): Int = calcService.multiply(a, b) }
まあ、リソースクラスもCDI管理対象ですが…。
これらを対象に、テストコードを書きます。
テストコード
sbtでやっているのですが、今回は依存関係も少ないのでpomは作りません。手動でいってしまいましょう。
デプロイする対象も少ないので、Deploymentを作成するトレイトを作りました。
src/test/scala/org/littlewings/javaee7/Deployer.scala
package org.littlewings.javaee7 import org.jboss.arquillian.container.test.api.Deployment import org.jboss.shrinkwrap.api.ShrinkWrap import org.jboss.shrinkwrap.api.asset.EmptyAsset import org.jboss.shrinkwrap.api.spec.WebArchive import org.jboss.shrinkwrap.resolver.api.maven.Maven trait Deployer { @Deployment def createDeployment: WebArchive = ShrinkWrap .create(classOf[WebArchive]) .addPackages(true, "org.littlewings.javaee7") .addAsLibraries { Maven .resolver .resolve("org.scala-lang:scala-library:2.11.6") .withTransitivity .asFile: _* } .addAsLibraries { Maven .resolver .resolve("org.scalatest:scalatest_2.11:2.2.4") .withTransitivity .asFile: _* } }
CDI管理Beanをテストするクラス。
src/test/scala/org/littlewings/javaee7/ServiceTest.scala package org.littlewings.javaee7 import javax.inject.Inject import org.jboss.arquillian.junit.Arquillian import org.junit.runner.RunWith import org.junit.Test import org.scalatest.Matchers._ import org.scalatest.junit.JUnitSuite import org.littlewings.javaee7.service._ object ServiceTest extends Deployer @RunWith(classOf[Arquillian]) class ServiceTest extends JUnitSuite { @Inject private var calcService: CalcService = _ @Test def testServiceAdd(): Unit = calcService.add(1, 2) should be (3) @Test def testServiceMultiply(): Unit = calcService.multiply(3, 4) should be (12) }
JAX-RS側のテストをするクラス。
src/test/scala/org/littlewings/javaee7/RestTest.scala
package org.littlewings.javaee7 import scala.io.Source import java.net.URL import javax.ws.rs.ApplicationPath import org.jboss.arquillian.container.test.api.RunAsClient import org.jboss.arquillian.junit.Arquillian import org.jboss.arquillian.test.api.ArquillianResource import org.junit.runner.RunWith import org.junit.Test import org.scalatest.Matchers._ import org.scalatest.junit.JUnitSuite import org.littlewings.javaee7.rest._ object JaxrsTest extends Deployer @RunWith(classOf[Arquillian]) @RunAsClient class JaxrsTest extends JUnitSuite { private val resourcePrefix: String = classOf[JaxrsApplication] .getAnnotation(classOf[ApplicationPath]) .value @ArquillianResource private var deploymentUrl: URL = _ @Test def testResourceAdd(): Unit = Source .fromURL(s"${deploymentUrl}${resourcePrefix}/calc/add?a=1&b=2") .mkString should be ("3") @Test def testResourceMultiply(): Unit = Source .fromURL(s"${deploymentUrl}${resourcePrefix}/calc/multiply?a=3&b=4") .mkString should be ("12") }
このあたりは、いたって普通のArquillianを使ったテストコードです。
arquillian.xml
最後に、Arquillianの設定ファイルを用意します。
src/test/resources/arquillian.xml
<?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"> <container qualifier="jboss" default="true"> <configuration> <property name="jbossHome">../wildfly-8.2.0.Final</property> <property name="modulePath">../wildfly-8.2.0.Final/modules</property> <!-- embedded --> </configuration> </container> </arquillian>
プロパティmodulePathは、Embeddedでは必要ですが、Managedでは不要です。
WildFly自体は、今回作成したプロジェクトの隣に並べておきました。
ハマったこと
いや、ハマりましたよ、けっこう。
まず、arquillian.xmlに書かれたmodulePathがないと、WildFlyが起動してくれません。
<property name="modulePath">../wildfly-8.2.0.Final/modules</property> <!-- embedded -->
Managedでは要らないのですけど…。
次に、modulePathを設定したら今度はJBoss Log Managerあたりでコケてくれます。
Cannot not load JBoss LogManager. The LogManager has likely been accessed prior to this initialization.
ERROR: JBAS014612: Operation ("parallel-extension-add") failed - address: ([]) java.lang.RuntimeException: JBAS014670: Failed initializing module org.jboss.as.logging at org.jboss.as.controller.extension.ParallelExtensionAddHandler$1.execute(ParallelExtensionAddHandler.java:111) at org.jboss.as.controller.AbstractOperationContext.executeStep(AbstractOperationContext.java:660) at org.jboss.as.controller.AbstractOperationContext.doCompleteStep(AbstractOperationContext.java:501) at org.jboss.as.controller.AbstractOperationContext.completeStepInternal(AbstractOperationContext.java:298) at org.jboss.as.controller.AbstractOperationContext.executeOperation(AbstractOperationContext.java:293) at org.jboss.as.controller.ModelControllerImpl.boot(ModelControllerImpl.java:324) at org.jboss.as.controller.AbstractControllerService.boot(AbstractControllerService.java:297) at org.jboss.as.server.ServerService.boot(ServerService.java:356) at org.jboss.as.server.ServerService.boot(ServerService.java:331) at org.jboss.as.controller.AbstractControllerService$1.run(AbstractControllerService.java:259) at java.lang.Thread.run(Thread.java:745) Caused by: java.util.concurrent.ExecutionException: java.lang.IllegalStateException: JBAS011592: The logging subsystem requires the log manager to be org.jboss.logmanager.LogManager. The subsystem has not be initialized and cannot be used. To use JBoss Log Manager you must add the system property "java.util.logging.manager" and set it to "org.jboss.logmanager.LogManager" at java.util.concurrent.FutureTask.report(FutureTask.java:122) at java.util.concurrent.FutureTask.get(FutureTask.java:192) at org.jboss.as.controller.extension.ParallelExtensionAddHandler$1.execute(ParallelExtensionAddHandler.java:103) ... 10 more Caused by: java.lang.IllegalStateException: JBAS011592: The logging subsystem requires the log manager to be org.jboss.logmanager.LogManager. The subsystem has not be initialized and cannot be used. To use JBoss Log Manager you must add the system property "java.util.logging.manager" and set it to "org.jboss.logmanager.LogManager" at org.jboss.as.logging.LoggingExtension.initialize(LoggingExtension.java:122) at org.jboss.as.controller.extension.ExtensionAddHandler.initializeExtension(ExtensionAddHandler.java:98) at org.jboss.as.controller.extension.ParallelExtensionAddHandler$ExtensionInitializeTask.call(ParallelExtensionAddHandler.java:139) at org.jboss.as.controller.extension.ParallelExtensionAddHandler$ExtensionInitializeTask.call(ParallelExtensionAddHandler.java:125) at java.util.concurrent.FutureTask.run(FutureTask.java:266) at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142) at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617) at java.lang.Thread.run(Thread.java:745) at org.jboss.threads.JBossThread.run(JBossThread.java:122)
この対応で、以下の設定が入っています。
javaOptions ++= Seq("-Djava.util.logging.manager=org.jboss.logmanager.LogManager") // embedded
普通は、maven-surefire-pluginで設定してって感じみたいですね。
Integration test with Arquillian and Wildfly
http://stackoverflow.com/questions/21851790/integration-test-with-arquillian-and-wildfly
あと、sbtの場合はforkしておく必要があります。
fork in Test := true
これは、Embeddedに限った話ではありませんが。
で、Managedと比べてどうなの?
正直、こういう使い方だと変わりがないような…Mavenを使ってWildFlyをダウンロードさせてテスト実行、みたいな使い方だと嬉しいんでしょうかねぇ?Managedに切り替えて動かしてみたりもしましたけど、特に速度が違うとかいうわけでもなさそうですし。
う〜ん、Managedを使えばいいかな?
参考)
Arquillian: Wildfly embedded?
http://stackoverflow.com/questions/20895332/arquillian-wildfly-embedded
JUnit/Arquillian: Run managed Wildfly 8.1 container
http://stackoverflow.com/questions/24615183/junit-arquillian-run-managed-wildfly-8-1-container
今回作成したコードは、こちらに置いています。
https://github.com/kazuhira-r/javaee7-scala-examples/tree/master/arquillian-wildfly-container-embedded