Jetty の ServletTester の挙動がおかしいと思ったら自分がおかしかったでござる
Jetty に ServletTester というのがあってですね、生 Servlet のテストをしたいときなんかに結構重宝してたりしたんですよ。
<dependency> <groupId>org.mortbay.jetty</groupId> <artifactId>jetty-servlet-tester</artifactId> <version>6.1.26</version> <scope>test</scope> </dependency>
こんな感じにテストが書けます。
package example; import org.junit.Test; import static org.hamcrest.CoreMatchers.*; import static org.junit.Assert.*; import org.mortbay.jetty.testing.HttpTester; import org.mortbay.jetty.testing.ServletTester; public class SampleServletTest { @Test public void testDoGet() throws Exception { ServletTester tester = new ServletTester(); tester.addServlet(SampleServlet.class, "/index"); tester.start(); HttpTester request = new HttpTester(); request.setMethod("GET"); request.setHeader("Host", "tester"); // should be "tester" request.setURI("/index"); request.setVersion("HTTP/1.1"); request.setContent(""); String responses = tester.getResponses(request.generate()); HttpTester response = new HttpTester(); response.parse(responses); assertThat(response.getStatus(), is(equalTo(200))); } }
ただ、この API、パッと見ておわかりいただけると思うんですが、すごく・・変ですよね・・・。なんというか無理矢理感がすごいというか。
ただ、現実問題として生 Servlet と戦うときにこのテストツールは強力な武器になってくれるので、そこはまあ目をつぶるわけですよ。
org.eclipse になって
で、Jetty が 8,9 で org.eclipse に移管されて、パッケージも org.mortbay.jetty から org.eclipse.jetty になった段階で書き換えられたようです。今回は Servlet 3.1 ではなく Servlet 3.0 をやっていたので 9.0.x を示しています。
<dependency> <groupId>org.eclipse.jetty</groupId> <artifactId>jetty-servlet</artifactId> <version>9.0.7.v20131107</version> <scope>test</scope> </dependency>
で、こんな感じに書けるようになったと。
package example; import org.junit.Test; import static org.hamcrest.CoreMatchers.*; import static org.junit.Assert.*; import org.eclipse.jetty.http.HttpTester; import org.eclipse.jetty.servlet.ServletTester; public class SampleServletTest { @Test public void testDoGet() throws Exception { ServletTester tester = new ServletTester(); tester.addServlet(SampleServlet.class, "/index"); tester.start(); HttpTester.Request request = HttpTester.newRequest(); request.setMethod("GET"); request.setHeader("Host", "tester"); // should be "tester" request.setURI("/index"); request.setVersion("HTTP/1.1"); request.setContent(""); HttpTester.Response response = HttpTester.parseResponse(tester.getResponses(request.generate())); assertThat(response.getStatus(), is(equalTo(200))); } }
まあ、これでも冗長さはあるわけですけど Request/Response の無理矢理感はなくなって、だいぶマシになりましたね。パッケージやメソッド名なんかも妥当な感じに改善されているんです。「これはいいな、今後は org.eclipse しかメンテされないんだし、こっちに移行しよう!」と思ったのですが・・・
あれ?
HttpTester の API 改善されてて最高だと思ったら、実行時間がアホみたいに長くなってて悲しみに暮れている。
— Kazuhiro Sera (@seratch) December 6, 2013
実行時間がめちゃくちゃ長くなってしまいました。tester.getResponses(..) のところが遅すぎで普通に 10 秒とかかかっちゃうんですよね。「さすがにそれはおかしいだろう、きっと使い方が悪いに違いない」と思って調べてみたんですが、私が試した限りではどうにもなりませんでした。上記のようなテストであれば 6.x だと一瞬で終わるのですが。
(追記)
という感じで、よくわからないなーと Twitter で日本語で愚痴っていたら Jetty の中の人から SOF で聞いてみたら?とリアクションが。
@joakime Thanks, embedded Jetty is pretty nice. I'm disappointed with ServletTester's slowdown in version 9.x though API is much improved...
— Kazuhiro Sera (@seratch) December 6, 2013
とりあえず stackoverflow にタグ付きで投稿してみました。
http://stackoverflow.com/questions/20428371/why-servlettester-in-jettty-9-x-is-so-slow
早速、こちらの方から回答がもらえました。要はそもそもが私のポカミスだったと・・
@joakime Oh, I got it. Thank you so much!
— Kazuhiro Sera (@seratch) December 6, 2013
Jetty 9 のサーバは HTTP/1.1 なんだけど
Jetty 9's HttpTester also defaults to HTTP/1.0.
とのことで(HttpTester はリクエストをつくってるやつですね)私のサンプルは HTTP/1.1 指定してるんだから
request.setHeader("Connection", "close");
つけるか HTTP/1.0 でリクエストしないとダメということでした。Connection ヘッダのことがすっかり頭から抜け落ちていました・・。そうか、一定時間で接続切られるまで待っていたのか・・
Jetty の件、解決しました。Jetty6 で動いてたからコードはそのままで動くんだろうと思ったけどそうではなかったと。ともあれ ServletTester はオワコンになってなくてよかったです。
— Kazuhiro Sera (@seratch) December 6, 2013
結論としては、実際は私の確認が甘かっただけで ServletTester はオワコンにはなってなかったです。まずは自分のコードを疑えってことですね。
Typesafe Activator について #scalajp #play_ja
Advent Calendar!
この記事は Play framework 2.x Scala Advent Calendar 2013 の 4 日目です。
http://www.adventar.org/calendars/114
Activator については前に書いたことがある
7 月に Typesafe Activator のテンプレートをつくってみたというブログ記事を書きました。使い方はこの記事の内容で十分かと思います。
http://seratch.hatenablog.jp/entry/2013/07/02/005454
それから半年くらい経ち、色々と変化がありましたね。
Typesafe Activator が OSS になった
8 月に Typesafe Activator の実装が公開されました。
https://www.typesafe.com/blog/typesafe-activator-is-now-open-source
https://github.com/typesafehub/activator
これにより issue を登録してフィードバックしたり、実装を修正して pull request を送ったりといったことが可能になりました。
Typesafe Activator 1.0 リリース
9 月に vesrion 1.0 がリリースされました。この時点で 29 個のテンプレートが登録されていたようです。
http://typesafe.com/blog/announcing-activator-10-create-reactive-apps-in-minutes
ちなみに今日時点での最新バージョンは 1.0.8、登録テンプレートは 41 個ありました。
Typesafe Activator をつくりたい人へ
7 月のブログ記事には「どうやって Typesafe Activator のテンプレートつくるか」が書かかれていませんでした。というのも、こちらのページにある内容だけなので
http://typesafe.com/activator/template/contribute
あえて日本語で説明しなくても、という感じだったのですが、簡単に触れておきます。特に難しいことはないのですが、いくつか注意点を。
activator.properties の name を適当につけない
activator.properties というファイルにメタデータを指定します(なぜ Typesafe Config じゃないの・・とちょっと思った)。前にも書きましたが、この name の文字列がそのまま unique key にされてしまうので、適当につけるのはやめましょう。私はあとから hello-scalikejdbc にしたくなったけど、面倒で scalikejdbc-activator-template のままになっています。。
ライセンス表記が必要
何らかの OSS ライセンスを明記する必要があります。プロジェクトのルートディレクトリに LICENSE または LICENSE.md というファイル名で配置してください。
https://github.com/scalikejdbc/hello-scalikejdbc/pull/1
現時点でリポジトリの移動に対応していない
Typesafe Activator のテンプレートは上記の contribute ページから GitHub リポジトリの URL を指定して追加/更新するのですが、12/4 時点でリポジトリの owner が変わった場合に対応できていません。例えば、私が作っている
https://github.com/scalikejdbc/hello-scalikejdbc
は、以前は https://github.com/seratch/hello-scalikejdbc だったのですが owner が seratch として登録されているので scalikejdbc が owner の URL で更新しようとすると permission がねえぞゴラッみたいなエラーになります。回避策としては古い URL でリクエストすると受け付けてくれるようです。
恒久的には手動対応しかないんですかねぇということで、他に問い合わせ先がなかったので issue にしてみました。(追記)対応してくれました。
https://github.com/typesafehub/activator/issues/180
まとめ
感覚として Typesafe Activator のテンプレートを作ったことによってユーザが増えたとかそういう印象はあまりないのですが zip をダウンロードして初回起動までは特に知識がなくてもできるので Scala 初心者の方に体験してもらうにはよいツールではないでしょうか。ぜひ試してみてください。
明日が空いていますけど・・
誰かいませんか?
http://www.adventar.org/calendars/114
FYI:
どうしても困ったら Skinny Framework の宣伝を書きにいきますので、お気軽にご依頼ください(ぇ
— Kazuhiro Sera (@seratch) December 1, 2013
いなかったら本当にやりますよ・・
pvm の紹介とその背景について #play_ja
この記事は Play framework 2.x Java and 1.x Advent Calendar 2013 の 2 日目です。元々 12/3 の予定でしたが 12/2 が空いたままで存亡の危機だったので、一日スライドしました。
http://www.adventar.org/calendars/104
pvm とは
今回は pvm(Play Version Manager)について紹介したいと思います。
https://github.com/kaiinkinen/pvm
pvm は nvm の仕様を踏襲した、複数の Play Framework のバージョンを管理するためのツールです。bash で書かれたシンプルなスクリプトで pvm.sh を .bash_profile などで読みこんで使います。
README では $HOME/utils/pvm に git clone する例が紹介されていますが nvm 的にするなら $HOME/.pvm でもいいかもしれません。実際 $HOME/.pvm で運用しても特に支障はないのですが、単に作者の好みですかね。
git clone git://github.com/kaiinkinen/pvm.git .pvm
使い方は一目瞭然なので使い方の解説は省略します。
$ pvm Play Version Manager Usage: pvm help Show this message pvm install <version> Download and install a <version> pvm uninstall <version> Uninstall a version pvm use <version> Modify PATH to use <version> pvm run <version> [<args>] Run <version> with <args> as arguments pvm ls List installed versions pvm ls <version> List versions matching a given description pvm deactivate Undo effects of PVM on current shell pvm alias [<pattern>] Show all aliases beginning with <pattern> pvm alias <name> <version> Set an alias named <name> pointing to <version> pvm unalias <name> Deletes the alias named <name> pvm clean Removes non-installed versions from the cache pvm clear-cache Deletes all cached zip files Example: pvm install 1.2.4 Install a specific version number pvm use 1.2 Use the latest available 1.2.x release pvm alias default 1.2.4 Auto use the latest installed 1.2 version
bash スクリプトなので Windows では使うことが出来ません。Windows で Play を使っている方、ぜひ Windows 版をつくりましょう!
そもそも必要なの?
「Play って sbt ベースだから play の sbt プラグインのバージョンを各プロジェクトで管理するだけじゃん。こんなの必要なの?」と思われた方、Play 新参者なのがバレてますよ!!!
確かに Play2 にだけ関わっている方であれば不要です。しかし、Play には Plain Old Play Framework ともいうべき 1.2.x がまだ現存しており、かつ世界中でそれなりに稼働し続けているという現実を忘れてはなりません。
http://www.playframework.com/download
こちらは私の開発マシンにインストールされている Play のバージョンです。
$ pvm ls Available: 1.2.5 1.2.6 2.1.3 2.2.1 1.2.5.3 1.2.7 2.1.4 Aliases: default -> 1.2.7 Current version: current -> 1.2.7
特に 1.2.5 と 1.2.6 以降は cookie session の互換性がなかったりと断絶があるので 1.2.5 と最新を両方運用しているというケースはまだまだありそうです。Play1 のリリース管理においても 1.2.5 だけは特別扱いしていて 1.2.5.3 というバージョンが出ていたりします。
また 1.3 に向けた開発も続いています。
http://play.lighthouseapp.com/projects/57987/milestones/106971-13
http://play.lighthouseapp.com/projects/57987-play-framework/tickets
Play1 の運用に関わるならば、これからも pvm を利用することはありそうです。
全国の Play ユーザの皆さんへ
Advent Calendar がちょっと寂しい状況になっていますね。ちょっとしたネタでもよいと思うのでぜひお気軽にご参加ください。
Play framework 2.x Java and 1.x Advent Calendar 2013
http://www.adventar.org/calendars/104
Play framework 2.x Scala Advent Calendar 2013
http://www.adventar.org/calendars/114
FYI:
どうしても困ったら Skinny Framework の宣伝を書きにいきますので、お気軽にご依頼ください(ぇ
— Kazuhiro Sera (@seratch) December 1, 2013
怖い Scala で LT しました #fud_scala
10 月の怖くない Scala 勉強会に対応する形で 11/28 に「怖い Scala」というイベントが開催されました。主催の @yamashiro さん、会場提供いただいたグリー株式会社さん、どうもありがとうございました。
http://connpass.com/event/4112/
これはまさかりを持った @kmizu さんです。このように非常に恐ろしい雰囲気の中、開催された勉強会でした。
LT をしました
ここで「Skinny Framework 進捗どうですか?」というタイトルの LT をしてきました。
Skinny Framework についてはこちらをご覧ください。
https://github.com/skinny-framework/skinny-framework
https://twitter.com/skinnyframework
何か遅かったらしいね?
@yuroyoro さんの ISUCON3 の予選アプリチューニング前状態を Skinny に移植した Scala アプリのスコアがパッとしなくて、LT のときに「先ほど出てきたあまり速くないフレームワークです」と自虐ネタにしましたが
Scala at ISUCON3 2013/11/28 怖いScala @yuroyoro https://dl.dropboxusercontent.com/u/261418/scala_at_isucon3/index.html#/
@yuroyoro さんの資料にもある通り、これに尽きるのかなと思います。
一般的なWebアプリケーション(IO bounds on DB/not CPU bounds)では Scala(Playframework)に性能上のアドバンテージはない。
Play2 + postgresql-async/mysql-async だったり Finatra + finagle-mysql だったりだと、また違うかもしれません。*1
Skinny は Scalatra(Servlet) + JDBC です。「一般的にはどうなの?」というと、以下の Scalatra とほぼ同等と思っていただければよいと思います。そのうち、このベンチマークにも載せてもらうよう pull request したいですね。
http://www.techempower.com/benchmarks/
Skinny Framework に関わりませんか?
LT の中でも触れましたが Skinny Framework の開発は私一人だけでやり続けない方が良いものになるだろうと思っています。仕事で使ってくださる方々もその方が安心できますよね。
とはいえ、開発を一緒にやってくれる方を探すのはそう簡単ではないので、開発自体は相変わらずほぼ一人という状態が続くかもしれませんが、提案やバグレポートなどをしてくれる方が増えていくと非常に嬉しいです。日本語でももちろん OK なので、お気軽にご連絡ください。
Rails4 で response.headers['content-type']
最近 ruby-openid に付属している example の Rails3 アプリをベースに実装を始め、Rails4 にバージョンアップ、微妙な実装箇所を直したり、SReg ではなく AX に対応させるよう修正・・とやっているうちに気がつくとほぼ全部書き換えていた・・!というオチになった私なのですが、その中でも既存の実装を活かし続けていたところでちょっとハマったのでエピソードとして。
response.headers['content-type'] = 'application/xrds+xml' render :text => yadis
これだと Content-Type が application/xrds+xml に設定されずに text/html だとかになってしまう。正しくはこう。
response.headers['Content-Type'] = 'application/xrds+xml' render :text => yadis
Rails3 だとどちらでもよいのですが Rails4 から動作しなくなったようです。この記事でいう Rails4 は 4.0.1 です。
元々 Rails3 だったのでバグっていた訳ではなく Rails4 に移行したので挙動が変わってしまったと。そこまでテストで守れるの?と考えると、ちょっとつらい非互換ではありますね。意図とか原因とか調べるべきなんでしょうけど...>誰か
Skinny Framework 導入
を gist に書きました。よかったらご覧ください。はてなブログには gist を埋め込める機能がありますが、コード例のところがきれいに表示できなかったのでリンクを貼るだけにしておきます。
https://gist.github.com/seratch/7382298#file-getting_started_ja-md
GitHub star 数で見る Scala DB アクセスライブラリ事情(2013/10 版)
定期ポストです。
DB ライブラリ
順位 | 名前 | 2013/06 | 2013/07 | 2013/08 | 2013/09 | 2013/10 | 総増減 |
---|---|---|---|---|---|---|---|
1 | Slick | 613 | 638 | 658 | 692 | 717 (+25) | +104 |
2 | Squeryl | 322 | 329 | 334 | 338 | 340 (+2) | +18 |
3 | postgresql-async | 159 | 187 | 213 | 227 | 240 (+13) | +81 |
4 | ScalikeJDBC | 112 | 135 | 141 | 150 | 180 (+30) | +68 |
5 | Querulous | 154 | 157 | 158 | 162 | 164 (+2) | +10 |
6 | scala-activerecord | 92 | 101 | 104 | 113 | 130 (+17) | +38 |
7 | sqltyped | 109 | 108 | 110 | 119 | 121 (+2) | +12 |
8 | Activate | 85 | 94 | 99 | 103 | 112 (+9) | +27 |
9 | SORM | 91 | 95 | 97 | 100 | 102 (+2) | +11 |
10 | Prequel | 35 | 37 | 39 | 41 | 44 (+3) | +9 |
11 | DataExpress | 24 | 24 | 27 | 27 | 29 (+2) | +5 |
12 | ScalikeJDBC-Async | - | 14 | 20 | 27 | 28 (+1) | +28 |
12 | Scala SQL DSL | 28 | 27 | 27 | 27 | 28 (+1) | 0 |
14 | ScalaSQL | 12 | 13 | 13 | 13 | 13 (0) | +1 |
15 | Scweery | 12 | 12 | 12 | 12 | 12 (0) | 0 |
16 | MyBatis Scala | 1 | 3 | 4 | 4 | 7 (+3) | +4 |
17 | mirage-scala | 4 | 4 | 4 | 5 | 5 (0) | +1 |
18 | shirahae-sql | - | - | 2 | 2 | 2 (0) | +2 |
フレームワークの一部
順位 | 名前 | 2013/06 | 2013/07 | 2013/08 | 2013/09 | 2013/10 |
---|---|---|---|---|---|---|
1 | Anorm | - | - | - | 3697 | 3797 (+100) |
2 | Lift Mapper | - | - | - | 717 | 722 (+5) |
3 | Spring JDBC Scala | 154 | 168 (+14) | 182 (+14) | 194 (+12) | 212 (+18) |
4 | Circumflex ORM | 136 | 136 (0) | 137 (+1) | 140 (+3) | 143 (+3) |
5 | Skinny ORM | - | - | - | - | 99 |