VOYAGE GROUP エンジニアブログ

voyagegroup_techのブログ
VOYAGE GROUPエンジニアブログです。

programming

滅びの言葉をテストする

こんばんは。VOYAGE GROUPの野良クルー、@katzchangです。

ところでみなさん、バルスしてますか?

バルスとは滅びの言葉、つまりおまいらに解かりやすく言うと、異常系処理をキックするコマンドなわけです。で、やはり、異常系処理も含めてテストされるべきですよ。当然ですね。

ということで、テスト駆動開発、いわゆるTDD"風味"で、バルスのJava実装を作ってみました。とはいえ、要するに System.exit(1) すればよいので、実装は大したことがない。でも、実際にどのような動作になるか、あまり試したことがないのは僕だけじゃないはず。試す価値はありそうです。

方針としては、balseメソッドを実装したBalsableクラスを用意し、システムが無事に異常終了することを確認すればよいということにします。

さて、いきましょう。
package balse; import static org.junit.Assert.*; import org.junit.Test; public class BalsableTest { @Test public void test() { new Balsable().balse(); fail(); } }
テストコードはこんな感じ、new Balsable().balse();を実行すると、次のfail();が実行されないはずです。そうです、このときはそう信じていました………。alt + shift + x, t。

first_test_gray

よし、Gre……………y……?

なんと、JUnit test runnerがバルスしてしまいました。バルスマジバルス。

仕方がないから、外部プロセスとして実行し、結果を確認することにします。方針転換ってやつです。

こんな感じにテスト用のランナーを用意し、
package balse;

public class BalsableRunner { public static void main(String...args) { new Balsable().balse(); } }
外部プロセスとして実行させます。
@Test
public void testBalsableProcess() throws Exception { ProcessBuilder pb = new ProcessBuilder("java", "-classpath", "./target/test-classes;./target/classes", "balse.BalsableRunner"); Process p = pb.start(); assertThat(p.waitFor(), is(1)); }
green

今度はGreen。ちゃんとバルスできています。

ところが、ここで心配になりました。このバルスは、ちゃんとプロセス全体をバルスしているのでしょうか?マルチスレッドでも問題なくバルスるのでしょうか?

そう、不安があったらテストしましょう。

マルチスレッドを使ったテスト用ランナーを用意し、それをテストします。今度はリターンコードだけではなく、スレッドが実行されていることを確かめるべく、標準出力の内容も検査することにします。
@Test public void testBalsableThread() throws Exception { ProcessBuilder pb = new ProcessBuilder("java", "-classpath", "./target/test-classes;./target/classes", "balse.BalsableThreadRunner"); Process p = pb.start(); assertThat(p.waitFor(), is(1));
// TODO: helperを作るべき InputStream is = p.getInputStream(); BufferedReader br = new BufferedReader(new InputStreamReader(is)); String line; List<String> lines = new ArrayList<String>(); while ((line = br.readLine()) != null) lines.add(line); is.close(); assertThat(lines.size(), is(2)); assertThat(lines.get(0), is("時間だ!!答えを聞こう!!")); assertThat(lines.get(1), is("バルス!")); }
バルス!

はい、Green。標準出力の内容も意図通りのようです。

他のコードも含めて https://github.com/katzchang/balse にコミットしていますので、煮るなり焼くなり好きにしてください。

これを他のプロダクトに組み込む場合、直接System.exit(1)を呼ぶより、Balsableを通して呼ぶように変えることができます。そのときのテストとしては、MockBalsableを用意し、モックのbalse()メソッドが呼ばれたことを確認すれば、プロダクトへのバルス実装は完了です(Balsableにももう少し手を加える必要はあります)。そして、end-to-endテストとして実際にBalsableを組み込んだ上でバルスしていることを確認できれば、出荷可能です。

さて、この記事はTDD Advent Calendar jp: 2011の10日目の記事でした。

9日目の記事は@yujioramaC言語でもレガシーでも、TDD をやってやれないことはない(レガシーコード改善成分90%、TDD成分10%)、明日は大学でテスト駆動開発プロセスを研究してる@pocketberserkerです。きっと読み応えのある記事を書いてくれることでしょう……!!

純粋なTDDではないけど、まぁこんな感じで進めてますということで…。

FizzBuzz問題をデータ解析環境「R」で

こんにちは、VOYAGE GROUPの水越(@Akiyah)です。
いま話題のFizzBuzz問題をデータ解析環境「R」で書いてみました。

メインの参考ページはここです。
FizzBuzz問題を使って社内プログラミングコンテストを開催してみた - ITは芸術だ
仕様
・1から順番に数をコマンドプロンプト/ターミナルに表示する。
・その数が3で割り切れるなら"Fizz“
・5で割り切れるなら"Buzz“
・両方で割り切れるなら"FizzBuzz"と表示する。
まずは上記のページで紹介されているperl版をほぼそのままRに移植してみます。
args <- commandArgs()
endval <- args[6]

for (i in 1:endval) {
    fizz = i %% 3
    buzz = i %% 5

    if (fizz == 0 && buzz == 0) {
        cat("FizzBuzz")
    }
    else if (fizz == 0) {
        cat("Fizz")
    }
    else if (buzz == 0) {
        cat("Buzz")
    }
    else {
        cat(i)
    }
    cat("\n")
}
Rというなじみのない言語ですが、コードはいたって普通ですね。<-は代入で、catは画面表示する関数です。
このファイルをfizzbuzz.rというファイルに保存して、Rscriptコマンドで実行します。(この記事書くまでRファイルをコマンドラインから実行する方法を知りませんでした! Rでは環境に入って作業するのが普通なのです。)
$ Rscript fizzbuzz.r 20
1
2
Fizz
4
Buzz
Fizz
7
8
Fizz
Buzz
11
Fizz
13
14
FizzBuzz
16
17
Fizz
19
Buzz
もとのperl版からほとんど変えずに動きました。よかったよかった。
さて、Rらしく変更してみます。
args <- commandArgs()
endval <- args[6] i <- 1:endval x <- i x[i%%3==0] <- "Fizz" x[i%%5==0] <- "Buzz" x[i%%3==0 & i%%5==0] <- "FizzBuzz" cat(paste(x, collapse="\n")) cat("\n")
だいぶ短くなりましたね。実行結果はまったく同じです。
ちょっと解説しますね。Rのベクトル(配列みたいなものです)はまとめて演算したり、条件を判断して新しいベクトルを作ることができます。下記はRコマンドでRの実行環境に移動して試しています。
> i <- 1:20
> i
 [1]  1  2  3  4  5  6  7  8  9 10 11 12 13 14 15 16 17 18 19 20
> i%%3
 [1] 1 2 0 1 2 0 1 2 0 1 2 0 1 2 0 1 2 0 1 2
> i%%3==0
 [1] FALSE FALSE  TRUE FALSE FALSE  TRUE FALSE FALSE  TRUE FALSE FALSE  TRUE
[13] FALSE FALSE  TRUE FALSE FALSE  TRUE FALSE FALSE
そしてベクトルの[ ](インデックス)にベクトルを入れたり、それをつかって<-でまとめて値を変更したりできるのです。
> x <- 1:20
> x[i%%3==0]
[1]  3  6  9 12 15 18
> x[i%%3==0] <- "Fizz"
> x
 [1] "1"    "2"    "Fizz" "4"    "5"    "Fizz" "7"    "8"    "Fizz" "10"  
[11] "11"   "Fizz" "13"   "14"   "Fizz" "16"   "17"   "Fizz" "19"   "20"  
このベクトル操作を利用して、ベクトルの3、5、15の倍数の時の値を変更したのです。実は『
FizzBuzz R』で検索するとたくさん見つかって、R業界ではFizzBuzz問題は有名みたいです。上に書いた例と同様のコードも見つかりました。考えてみると、FizzBuzz問題はRの得意分野なんですよね。

参考
The R Project for Statistical Computing
FizzBuzz問題を使って社内プログラミングコンテストを開催してみた - ITは芸術だ
FizzBuzz問題をJavaScriptで - jsdo.it - Share JavaScript, HTML5 and CSS
Fizz-Buzz問題 初級Q&A アーカイブ(7) - RjpWiki

Rails(Web)アプリケーションのセキュリティ(パスワードハッシュstretch編)

こんにちはECナビ山口(tadasy)です。
忙しぶるのはどちらかというと得意です。

最近PeXという部署からECナビ事業本部というところに異動したのでrubyは触ってません。
えぇまったく。

前回の更新からだいぶ期間があきました。
まぁアレです。忙しかったのです。
つれー、つれーわー、実質(ry

前回はログファイルのセキュリティについて触れました。
Rails(Web)アプリケーションのセキュリティ(ログファイル編)

今回はRails2系でよく使われるプラグインのrestful_authenticationでの
パスワードハッシュ化について書きます。
※3系のことはよくわからんです。

restful_authenticationとは?

詳しくは
restful-authentication
を見てもらえればと思いますが
ざっくり説明すると
Webサービスなんかでよくあるユーザ管理(ユーザの登録、ログイン、ログアウト)なんかの機能をまとめた便利プラグインです。

パスワードハッシュ化&stretching

パスワードのハッシュ化とstretchingについては下の春山さんの資料が大変参考になります。

パスワードの話

restful_authenticationでのstretching

ではrestful_authenticationがstretchingしているところを見てみます。
RAILS_ROOT/vendor/plugins/restful-authentication/lib/authentication/by_password.rb

だいぶソースを端折っていますが、REST_AUTH_DIGEST_STRETCHESという定数で繰り返し回数を指定して
stretchingしているようです。
この定数は以下のファイルで設定されているようです。
RAILS_ROOT/config/initializers/site_keys.rb

このファイルは下のコマンドでモデルを作ったときに自動生成されます。
ruby script/generate authenticated user sessions

何回stretchする?

デフォルトの設定では10回のstretchをしているようです。
資料にも書いてありますが、回数が多ければ強度を増すことができます。
ただ、回数が多ければ多いほどハッシュ化に時間がかかりますし、ログイン認証処理にも同様に時間がかかる様になります。
なので、サービス要件を考慮した回数でstretchしたらいいと思います。

ちなみに僕が作るときは1000回以上はstretchするようにしています。
というのも、以前1000回のstretchingでサービスを構築した時の実績として、性能面ではサービスの要件を十分に満たせるレベルでしたし(むしろ速かった)、強度的にもある程度担保できていたと考えるからです。

ただ次回以降は、もう少しstretchして、5,000回くらいで試してみてもいいかもしれないとも思っています。

Rails(Web)アプリケーションのセキュリティ(ログファイル編)

はじめまして、ジョニー・デップに激似の山口(@tadasy)と申します。

僕はPeXという部署で働いておりまして、
PeXpaycaグルピの運営に携わっております。

ECナビではサービスを作るときは、よくPHPを使われるのですが、
PerlやPython,Rubyなどで構築されているサービスもちょいちょいあります。

僕が所属しているPeXという部署でも、主力サービスであるPeXはPHP(symfony)で構築されていますが
payca、グルピはRuby(Ruby on Rails)で構築しました。

そのRailsのwebアプリケーションを構築・運用していく中で、セキュリティ的に気をつけたポイントを
何回かにわけて心折れるまで(おそらく2,3回)書いていこうと思います。

というわけで第1回はログファイルについてです。

ログファイルのセキュリティ?

ログファイルのセキュリティって言われてもあまりピンとこないかもしれませんが、Railsではproduction環境でもデフォルトで、HTTPのパラメータが全部ログに出力されてしまうとこです。そりゃもう全部です。
ログイン画面のパスワードはもちろん、会員情報登録画面の個人情報も当然、ログファイルの書かれます。

せっかくDBに会員パスワード情報を復号できない形でハッシュ化して保存していても、ログファイルに書かれてしまったら、もろもろ台無しです。

回避方法

action packのaction_controllerには filter_parameter_logging というクラスマクロが定義されています。
これを使うことでログファイルへの書き出しを抑止できます。

上記のように記述するとログファイルに記載される該当するパラメータ値が[FILTERED]という文字に置き換えられます。

  • filter適用前のログファイル
  Parameters: {..."user"=>{"password_confirm"=>"naisho", "last_name"=>"石鍋", "password"=>"naisho", "login"=>"loginid", "first_name"=>"太郎"}...}
  • filter適用後のログファイル
  Parameters: {..."user"=>{"password_confirm"=>"[FILTERED]", "last_name"=>"石鍋", "password"=>"[FILTERED]", "login"=>"loginid", "first_name"=>"太郎"}...}

適用後のログファイルをみると"password_confirm"というパラメータも置き換得られていることがわかります。
これは、
filter_parameter_logging :password
と書くことで
/password/i

という正規表現でパラメータ名をチェックされるためです。

詳しい使い方

詳しい使い方についてはaction_controller/base.rbにfilter_parameter_logging定義されていますので
そちらのコメント欄が参考になります。
一応コメントを引用しておきます。

# Replace sensitive parameter data from the request log.
# Filters parameters that have any of the arguments as a substring.
# Looks in all subhashes of the param hash for keys to filter.
# If a block is given, each key and value of the parameter hash and all
# subhashes is passed to it, the value or key
# can be replaced using String#replace or similar method.
#
# Examples:
#   filter_parameter_logging
#   => Does nothing, just slows the logging process down
#
#   filter_parameter_logging :password
#   => replaces the value to all keys matching /password/i with "[FILTERED]"
#
#   filter_parameter_logging :foo, "bar"
#   => replaces the value to all keys matching /foo|bar/i with "[FILTERED]"
#
#   filter_parameter_logging { |k,v| v.reverse! if k =~ /secret/i }
#   => reverses the value to all keys matching /secret/i
#
#   filter_parameter_logging(:foo, "bar") { |k,v| v.reverse! if k =~ /secret/i }
#   => reverses the value to all keys matching /secret/i, and
#replaces the value to all keys matching /foo|bar/i with "[FILTERED]"
ブロックも渡せるらしく、かなり柔軟な使い方ができそうですが
特に使い道が思いつかないので、今はシンプルに利用しています。


注意
Rails3系ではfilter_parameter_loggingはdeprecatedになっており、別の使い方が推奨されているようです。

Ruby DSLを定義してPowerPointスライドを自動生成する話

こんにちは、モバイルショッピング事業室で働いている小芝です。

先日、NTTレゾナント社のRubyコミュニティ「職場.rb」で講演する機会をいただきまして、Ruby DSLとPowerPointスライドの自動生成についてお話させていただきました。

概要

最近DSLという言葉をよく耳にするようになりました。
しかし具体的にいつどんなときにどのように作ればいいかという情報は少ないように思います。
この講演では、簡単にDSLを定義し扱う事ができるようになる事を狙いとして、下記2点の紹介・解説を行いました。
  1. プレゼン資料を表すDSLを定義し、PowerPointスライドを生成する事例の紹介
  2. 簡単にRubyでDSLを作成・活用するためのポイントの解説

提示資料

またhttp://www.ipad-zine.com/b/814/ にも登録しております。

実はこの資料自体が、このお話の中で解説しているDSLから生成したPowerPointスライドを使っています。(ソースの公開については少々お待ち下さい)

DSL楽しいよ

DSLを定義し動かせるようになると、この手法を様々な状況で応用する可能性が見えてきてとても楽しくなりますので、是非お試し下さい!

もし、いい応用例を見つけたり、逆にうまくいかなかったりしたら、是非その内容を共有してもらえるととてもうれしいです。
一緒にDSLトークをしましょう。

【告知】東京Ruby会議05を開催します

2011年2月4日(金)にECナビを会場として、プログラミング言語Rubyについてのカンファレンスの一つである、東京Ruby会議05を開催します。
まずは2011年2月4日の夜の予定を空けておいて下さい。

最新情報は、東京Ruby会議05公式サイトRuby会議日記にて随時お知らせいたしますので、是非チェックしてください! 
 
記事検索
QRコード
QRコード