2010年7月30日金曜日

Grailsを1.3.3に上げたら、ユニットテストがNullPointerExceptionで壊滅

Grailsのバージョンはもちろん1.3.3

タイトル通り、Grailsを1.3.3に上げたら、ユニットテストがNullPointerExceptionで壊滅しました
原因はGRAILS-6482で1.3.4で直るらしいですが、とりあえず回避方法としては次のコードをユニットテストにいれるといいらしいです。
protected void setUp() {
super.setUp()
PluginManagerHolder.pluginManager = [hasGrailsPlugin: { String name -> true }] as GrailsPluginManager
}

protected void tearDown() {
super.tearDown()
PluginManagerHolder.pluginManager = null
}

ユニットテストが多くなってくるとめんどいので、_Events.groovyに次のコードを入れました。
import org.codehaus.groovy.grails.plugins.GrailsPluginManager
import org.codehaus.groovy.grails.plugins.PluginManagerHolder

eventTestPhaseStart = { phase ->
if (phase == 'unit') {
PluginManagerHolder.pluginManager = [hasGrailsPlugin: { String name -> true }] as GrailsPluginManager
}
}

eventTestPhaseEnd = { phase ->
if (phase == 'unit') {
PluginManagerHolder.pluginManager = null
}
}

これでいいかどうかは不明ですがとりあえずNullポは消えたので。

2010年7月9日金曜日

hudson+antでgrailsアプリをビルドする その1

Grailsアプリケーションをhudson上でビルドするにはいくつか方法があります。
hudsonにGrailsプラグインがあるので、それを使用してビルドすることもできます。シェルでgrailsコマンドを呼び出すこともできます。
しかし、後々ビルド手順が複雑になったりしたときなどを考えると、やはりantのbuild.xmlにビルド手順をまとめて、hudson上からはbuild.xmlのデフォルトターゲットを呼び出すだけ、くらいにしておいたほうがいいかと。
いや、gantでもpomでもいいんですけどね。

まず、build.xmlを作成するところまで書いてみます。ポイントは、

では↓

1:build.xmlを生成
というか、grailsが作ってくれます。
cd [grails-project]
grails integrate-with --ant
これで、Grailsプロジェクトの中にbuild.xml、ivy.xml、ivysettings.xmlができているはず。
(ちなみにこれらのファイルはgrails upgradeでなぜか更新されないので、grailsを更新したらこれらのファイルを削除してもういちどintegrate-withコマンドを実行)

antコマンドを試してみましょう。基本的にgrailsコマンドに対応したantターゲットができています。
必要な環境変数を設定して、実行
普通にやるとメモリ不足で落ちることが多いので、ヒープサイズも指定しておきます。
set GRAILS_HOME=C:\grails\grails-1.3.2
set ANT_OPTS=-Xmx1024m -XX:MaxPermSize=512m

ant compile

download-ivy:
...(略)...

[ivy:retrieve] ::::::::::::::::::::::::::::::::::::::::::::::
[ivy:retrieve] :: UNRESOLVED DEPENDENCIES ::
[ivy:retrieve] ::::::::::::::::::::::::::::::::::::::::::::::
[ivy:retrieve] :: org.jboss.netty#netty;3.1.5.GA: not found
[ivy:retrieve] ::::::::::::::::::::::::::::::::::::::::::::::
[ivy:retrieve]
[ivy:retrieve]
[ivy:retrieve] :: USE VERBOSE OR DEBUG MESSAGE LEVEL FOR MORE DETAILS

BUILD FAILED
D:\project\literalice\sandbox\grails-ant-build\build.xml:60: impossible to resolve dependencies:
resolve failed - see output for details
…失敗。あれ?
これですね。
http://jira.codehaus.org/browse/GRAILS-6410
1.3.4で直るらしい。でもまあたぶん、リポジトリ追加してやればいいんじゃないかな…

2:依存先リポジトリの追加
先ほど生成したivysettings.xmlに、antビルドが使用しているリポジトリがリストされているので、ここにさっき足りない言われたライブラリのリポジトリを追加します。

















で、もういちど
ant compile
...(略)...
compile:
[grailsTask] Resolving dependencies...
[grailsTask] Dependencies resolved in 738ms.

BUILD FAILED
D:\project\literalice\sandbox\grails-ant-build\build.xml:104: The following error occurred while executing this line:
D:\project\literalice\sandbox\grails-ant-build\build.xml:48: Unable to start Grails: java.lang.reflect.InvocationTargetException
うは失敗しかもイミフ

結論から言うと、antのバージョンが1.8系だとダメみたい。
antのバージョンを1.7.1にしてもう一回!
ant compile
...(略)...
[grailsTask] [groovyc] Compiling 7 source files to D:\project\literalice\sandbox\grails-ant-build\target\classes
[grailsTask]

BUILD SUCCESSFUL
Total time: 5 seconds
OK。

3:依存先リポジトリの追加
さて、私としては、ビルド手順は極力build.xmlに集めたいです。
なので、test、warなどのコマンドをターゲットを順に呼び出すターゲットを作成します。
私はbuild.xmlに直接追加しましたが、別のビルドファイルを作成して、そのファイルからbuild.xmlを呼び出すようにしてもいいかもしれません。

これでもいいですが、私の場合war作成時のビルド環境(dev,prod,test,etc...)を明示したかったので、以下のように修正しました。
あと、non-interactiveをコマンド引数に指定しないと、hudsonに持って行ったときにループっぽくなってビルドが進まなくなります。

まず、antのgrailsマクロにビルド環境の引数を追加します。













つぎにデフォルトターゲットに指定するビルド用ターゲット







これでbuild.xmlができました。あとはhudson上に持って行ってビルドするだけです。
ただし、このままだとgrailsがビルドやテストに使用するディレクトリ(普通は%HOME%/.grails以下)をhudsonジョブ間で共有します。
並行ビルドなど考えると、各ジョブ間の作業ディレクトリはなるべく分割しておきたいところです。

このへんは次回。

2010年7月6日火曜日

GrailsアプリケーションのAntビルドでSSLHandshakeException

grails1.2系で、初めてプロジェクトをビルドするときにantでビルドすると、こんなエラーが起こることがあります。
javax.net.ssl.SSLHandshakeException: sun.security.validator.ValidatorException

これが発生するのは、プロジェクトはあるけど、まだ作業ディレクトリ(.grails)がない状態。つまり、
  • Grailsプロジェクトを新マシンにチェックアウトしてantでビルド
  • 作業ディレクトリを~/.grailsから別の場所に変更してantでビルド
などのときに発生するようです。

Tomcatのプラグインを、httpsのプラグインサイト上から落そうとして証明書エラー…javaが知らない認証局を使ってるらしい。
プラグインサイトが使用している中間認証局の証明書をkeytoolでインポートすれば、とりあえずビルドはできます。

証明書: https://www.startssl.com/certs/sub.class2.server.ca.crt

keytool -import -keystore %JAVA_HOME%/jre/lib/security/cacerts -file sub.class2.server.ca.crt -alias sub.class2.start.com
パスワードは変更していなければ「changeit」
証明書インポートについては、HttpClientでSSL通信が詳しいです。

なお、Grails1.3以降だとtomcatプラグインはネットワークからではなくGRAILS_HOMEから持ってくるようで、このエラーは発生しませんでした。