internethakai 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (36) hide show
  1. data/CHANGES +53 -0
  2. data/README +177 -0
  3. data/bin/hakaigen +10 -0
  4. data/bin/internethakai +9 -0
  5. data/internethakai.gemspec +27 -0
  6. data/lib/internethakai.rb +26 -0
  7. data/lib/internethakai.rb.~1~ +25 -0
  8. data/lib/internethakai/action.rb +403 -0
  9. data/lib/internethakai/client_handler.rb +175 -0
  10. data/lib/internethakai/client_queue.rb +27 -0
  11. data/lib/internethakai/concurrency_manager.rb +333 -0
  12. data/lib/internethakai/concurrency_manager.rb.~1~ +331 -0
  13. data/lib/internethakai/core.rb +146 -0
  14. data/lib/internethakai/executor.rb +129 -0
  15. data/lib/internethakai/generator.rb +32 -0
  16. data/lib/internethakai/hakairev.rb +119 -0
  17. data/lib/internethakai/hakairev/executor.rb +43 -0
  18. data/lib/internethakai/hakairev/http_client.rb +362 -0
  19. data/lib/internethakai/hakairev/http_client.rb.~1~ +371 -0
  20. data/lib/internethakai/hakairev/monkey.rb +70 -0
  21. data/lib/internethakai/hakairev/revpipe.rb +39 -0
  22. data/lib/internethakai/hakairev/task.rb +39 -0
  23. data/lib/internethakai/hakairev/time_register.rb +116 -0
  24. data/lib/internethakai/hakairev/timer_factory.rb +38 -0
  25. data/lib/internethakai/http_client.rb +120 -0
  26. data/lib/internethakai/logger.rb +52 -0
  27. data/lib/internethakai/main.rb +90 -0
  28. data/lib/internethakai/reporter.rb +143 -0
  29. data/lib/internethakai/response.rb +65 -0
  30. data/lib/internethakai/scenario.rb +98 -0
  31. data/lib/internethakai/scenario.tmpl +58 -0
  32. data/lib/internethakai/scenario_builder.rb +183 -0
  33. data/lib/internethakai/scenario_handler.rb +91 -0
  34. data/lib/internethakai/time_register.rb +53 -0
  35. data/lib/internethakai/util.rb +130 -0
  36. metadata +134 -0
data/CHANGES ADDED
@@ -0,0 +1,53 @@
1
+ 0.2.0:
2
+ * accesslog2yml を削除
3
+ * hakaigen を追加
4
+ * <b>重要</b>: concurrency を max_scenario に、fork を max_process に、変更しました(しばらくは後方互換性を残します)。
5
+
6
+ 0.1.9:
7
+ * 変数の記号を変更
8
+ * <b>重要</b>: %%VAR%% という変数が使えなくなります。かわりに %(VAR)% を使用してください。
9
+ * WAITする機能を追加。
10
+
11
+ 0.1.8:
12
+ * オプション追加。cookie に対応
13
+ * SetVarのバグ修正
14
+
15
+ 0.1.7:
16
+ * SetVarAction/RegexpSetVarActionのエラー修正
17
+
18
+ 0.1.6:
19
+ * RegexpSetVarActionのエラー修正
20
+
21
+ 0.1.5:
22
+ * リダイレクト前にクライアントを解放してしまうバグを修正
23
+ * バージョン番号のまちがいを修正
24
+ * スレッドモードをアップデート(taskの仕様変更に追従)
25
+
26
+ 0.1.4:
27
+ * CPU処理効率化のため、タスクの実行順序を変更
28
+ * 最短レスポンスタイムのワーストランキングを表示
29
+ * CheckNoRedirectActionを追加
30
+
31
+ 0.1.3:
32
+ * fork時にCtrl+Cしてもレポートが表示されるようにした
33
+ * fork時にプロセスが1つ死ぬと全体が死ぬようにした
34
+ * fork時に各プロセスの起動タイミングをずらしていたのをやめた
35
+ * fork時にRequestPerSecとTimePerRequestをまとめて表示するようにした
36
+ * -v にrubyのバージョンもだすように修正
37
+
38
+ 0.1.2:
39
+ * gemが0.1.1aというバージョン番号を認識できないようなので急遽バージョンアップ
40
+ * CHANGESを追加
41
+ * -v, --versionオプションを追加
42
+ * -h, --helpの表示を変更
43
+
44
+ 0.1.1a:
45
+ * max_requestがconcurrencyと同じになるバグを修正
46
+
47
+ 0.1.1:
48
+ * シナリオの順序がおかしくなるバグを修正
49
+ * 余計なパスを叩くバグを修正
50
+ * テストを追加
51
+
52
+ 0.1:
53
+ * gemパッケージ化
data/README ADDED
@@ -0,0 +1,177 @@
1
+ = DESTROY YOUR INTERNET!!
2
+ = 負荷試験スクリプト: インターネット破壊
3
+
4
+ == インターネット破壊とは何か
5
+ CUIで使える高機能な負荷試験スクリプトです。
6
+ 設定ファイルを作成することでシナリオ試験を実施でき、多重I/Oを利用して、簡単に高負荷をかけることができます。
7
+
8
+
9
+ == 基本的な使い方
10
+ コマンドライン引数でコンフィグファイルを指定します。
11
+
12
+ $ internethakai scenario.yml
13
+
14
+ エラーカウントが0だった場合は、exit status 0で終了し、それ以外の場合はexit status が 1 となります。
15
+
16
+
17
+ == シナリオの自動生成
18
+ 以下のコマンドでシナリオを自動で作成することができます。
19
+ 最初に使うときはこちらを使用してみてください。
20
+
21
+ $ hakaigen
22
+
23
+
24
+ == 実行時オプション
25
+ [-h --help] ヘルプを表示
26
+ [-v --version] バージョンを表示
27
+ [-r --max-request] リクエスト並列数を上書きします。
28
+ [-s --max-scenario] シナリオ並列数を上書きします。
29
+ [-l --loop] ループ回数を上書きします。
30
+ [--test] テストモードで実行。テストモードで実行すると、強制的に並列数を1、ループ数1、1プロセス、ログレベル3で実行します。リクエストが正常に送られているか確認するために使用できます。
31
+
32
+
33
+ === シナリオの基本項目
34
+ YAMLの連想配列で設定項目を指定します。指定すべきキー名について解説します。
35
+
36
+ [loop] 各シナリオのループ回数を指定します。
37
+ [max_request] HTTPクライアントの数を指定します。max_requestが10であればHTTPクライアントを10作成し、10のクライアントが同時にリクエストします。なおここで設定した値は全プロセスの合計値です。おすすめの値は "100" です(1プロセスあたり100コネクションくらいになるように調整しましょう)。
38
+ [max_scenario] シナリオの数を指定します。デフォルトではmax_requestと同じ値になります。特に指定の必要はありませんが、アクセスするユーザーの数を増やしたい場合に多めに設定します。たとえば、max_requestが10、max_scenarioが20であれば、20*ループ数分のシナリオを10個のHTTPクラアントが順次実行していきます。<b>concurrencyというキー名から変更しました。</b>
39
+ [log_level]
40
+ ログ出力のレベルを指定します。おすすめの値は "2" です。
41
+
42
+ 4 :: 取得したhtmlの内容まで表示
43
+
44
+ 3 :: 各リクエストの詳細を表示
45
+
46
+ 2 :: 基本項目のみ表示
47
+ [encoding] ページの文字コード UTF-8, Shift_JIS, JIS, EUC-JP
48
+ [domain]
49
+ ホスト名(httpを含める)
50
+
51
+ 例.
52
+ domian:
53
+ http://example.com
54
+ [rev] true, false。true に設定すると、RubyRevを使用し、多重I/Oでのリクエストを行ないます。おすすめの値、true。初期値true。
55
+ [user_agent]
56
+ リクエストに使用するUserAgent
57
+ 例.
58
+ user_agent:
59
+ 'DoCoMo/2.0 P903i(c100;TB;W24H12)'
60
+ [show_report] true, false。 true にすると、結果レポートを表示します。
61
+ [save_report] true, false。 true にすると、結果レポートをファイルに保存します。
62
+ [log_dir] 結果レポートを保存するディレクトリ。省略時は設定ファイルと同じディレクトリとなります。
63
+ [ranking] 平均レスポンス、エラー率のワーストランキングを何位まで表示するか。デフォルトは10。
64
+ [timeout] タイムアウトするまでの秒数。デフォルトは60秒です。おすすめの値、5。
65
+ [actions] リクエストの内容。action のリストを指定します。後述します。
66
+ [max_process]
67
+ 破壊力をあげたい場合に設定しましょう。プロセス数を指定します。1プロセスあたり100コネクションくらいになるように調整しましょう。<b>forkというキー名から変更しました</b>。
68
+ 例.
69
+ max_process: 4
70
+ [host_name] 基本的に指定の必要はありませんが、特別にHOSTヘッダを指定したい場合に設定してください。
71
+
72
+
73
+
74
+
75
+ === actions の書き方
76
+ ==== 基本的な書き方
77
+ YAMLの配列形式で、アクション(1回のリクエストに相当)を書いていきます。
78
+ アクションは連想配列で指定します。pathというキーが必須です(アクションに文字列だけを書いた場合、pathと見なします)。
79
+ path キーにリクエストするパスを指定します。ホスト名を省略した場合は、基本項目で指定したものが使われます。
80
+ methodの値を省略した場合、GETリクエストと見なします。
81
+ 例.
82
+ -
83
+ path: /index.php
84
+ ==== POSTリクエスト
85
+ method に "POST", post_params にパラメータを指定します。
86
+ 例.
87
+ -
88
+ path: /main_loadtest.php/shop/updateWithGamePoint
89
+ method: POST
90
+ post_params:
91
+ equipped: "on"
92
+ item_id: "13"
93
+ ==== 内容のチェック
94
+ scan を指定すると、該当のテキストが HTML に含まれるかどうかチェックします。
95
+ ==== サイズのチェック
96
+ assert_size を指定すると、コンテンツのサイズが一定以上かどうかチェックします。
97
+ ==== リダイレクトの確認
98
+ リダイレクトの確認をしたい場合は、class に RedirectCheckActionを指定してください。
99
+ assert_redirect に リダイレクト先のURLを指定します。
100
+ assert_redirect_scan を指定すると、リダイレクト先のHTMLもチェックできます(省略可能)。
101
+
102
+ 例.
103
+ - path: /main.php/my/index
104
+ scan: "マイページ"
105
+ - path: /main.php/cheat/gp
106
+ class: RedirectCheckAction
107
+ assert_redirect: /main.php/my/index
108
+ assert_redirect_scan: "購入したドレス"
109
+
110
+ また、リダイレクトしないことを確認したい場合は、class に NoRedirectCheckAction を指定してください。
111
+ ==== 変数の設定
112
+ 動的な変数を使用することができます。ユーザーIDなどを動的に取得したい場合に利用してください。
113
+
114
+ 変数を設定するには、class に SetVarAction を指定します。
115
+
116
+ 例.
117
+ - path: /main.php/special/person
118
+ class: SetVarAction
119
+ key: person_id
120
+
121
+ person_id というキー名にレスポンスボディの中身が設定されます。これに続くアクションのパス名やPOSTパラメーターに変数を使用できます。
122
+
123
+ <b>【重要】変数の記号を変えました</b>。
124
+
125
+ 例.
126
+ - path: /main.php/hoge/index?person_id=%(person_id)%
127
+
128
+
129
+ ==== 正規表現による変数の設定
130
+ 正規表現を使用して変数をセットできます(contributed by nakazawa-k)。
131
+
132
+ 変数を設定するには、class に RegexpSetVarAction を指定します。
133
+
134
+ exprというキーで正規表現を使用してください。$~[1] (最後にマッチした正規表現の後方参照の部分)が変数の値となります。
135
+
136
+ 例.
137
+ - path: /main.php/somepath/
138
+ class: RegexpSetVarAction
139
+ expr: 'battle_id=(\d+)'
140
+ key: battle_id
141
+
142
+ battle_id というキー名に正規表現の(\d+)の部分がセットされます。これに続くアクションのパス名やPOSTパラメーターに変数を使用できます。
143
+
144
+
145
+ ==== WAIT
146
+ リクエストの際に、わざと少し待たせることができます。wait というキーを指定すると、リクエストを送る前に指定時間何もしないで待ちます。単位は秒です。
147
+ 例.
148
+ - path: /main.php/somepath/
149
+ wait: 1.5
150
+
151
+
152
+ == 実行時の表示
153
+ [o] 並列数分のリクエストが終了
154
+ [x] タイムアウトなどエラー
155
+ [O] 1プロセス分のリクエストが終了
156
+
157
+
158
+ == 高度な使い方
159
+ クラスを指定することで、挙動の詳細を変更できます。
160
+
161
+ === ソーシャルアプリで使用する
162
+ client_handler に "SocialClientHandler" を指定します。
163
+
164
+ クエリパラメーターに opensocial_viewer_id というキー名で、opensocial_person_id をつけるようになります。
165
+
166
+ opensocial_id_path に opensocial_person_id のリストを書いたファイルのパスを指定すると、そちらの id を選択して使用します(ファイルは改行区切り)。
167
+
168
+ ファイルではなく、opensocial_ids というキー名で、opensocial_person_id のリストを指定することもできます。
169
+
170
+ === 携帯サイトで使用する(動作未検証)
171
+ client_handler に "MobileClientHandler" を指定します。
172
+
173
+ アクションごとに carrier を指定することで、ケータイキャリアを指定することもできます(1=DoCoMo, 2=KDDI, 3=SoftBank)。
174
+
175
+ uid_path に uid のリストを書いたファイルのパスを指定すると、そちらの uid を選択して使用します。ファイルは、改行区切りで、各行に、キャリアid と uid を "," 区切りで書いてください。ファイルではなく、uids というキー名でuidのリストを指定することもできます。
176
+
177
+
data/bin/hakaigen ADDED
@@ -0,0 +1,10 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ begin
4
+ require 'internethakai'
5
+ rescue LoadError
6
+ require 'rubygems'
7
+ require 'internethakai'
8
+ end
9
+ gen = InternetHakai::Generator::new
10
+ gen.build
data/bin/internethakai ADDED
@@ -0,0 +1,9 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ begin
4
+ require 'internethakai'
5
+ rescue LoadError
6
+ require 'rubygems'
7
+ require 'internethakai'
8
+ end
9
+ InternetHakai::Main::new::main
@@ -0,0 +1,27 @@
1
+ require 'rubygems'
2
+ require 'lib/internethakai'
3
+ #バージョンのupdate時は
4
+ #INSTALL, gemspec, Makefile, lib/internethakai.rb をupdate
5
+
6
+ GEMSPEC = Gem::Specification::new do |s|
7
+ s.name = 'internethakai'
8
+ s.version = InternetHakai::VERSION
9
+ s.author = 'takada-at'
10
+ s.email = 'takada-at@klab.jp'
11
+ s.summary = 'scenario test tool for web application'
12
+ s.platform = Gem::Platform::RUBY
13
+ s.required_ruby_version = '>= 1.8.6'
14
+ s.executables = Dir::glob("bin/*").map{|f|File::basename(f)}
15
+ s.default_executable = 'internethakai'
16
+ s.add_dependency('rev', '= 0.3.2')
17
+ s.add_dependency('iobuffer', '= 0.1.3')
18
+ s.files = Dir::glob("{lib,bin}/**/*") + ['internethakai.gemspec']
19
+ s.has_rdoc = true
20
+ s.rdoc_options = %w(-U -c UTF-8 -t "インターネット破壊" --main=README)
21
+ s.extra_rdoc_files = ["README", "CHANGES"]
22
+ s.homepage = ''
23
+ s.rubyforge_project = 'internethakai'
24
+ s.description = <<EOF
25
+ scenario test tool for web application.
26
+ EOF
27
+ end
@@ -0,0 +1,26 @@
1
+ require 'internethakai/core'
2
+ require 'internethakai/scenario_builder'
3
+ require 'internethakai/scenario_handler'
4
+ require 'internethakai/scenario'
5
+ require 'internethakai/executor'
6
+ require 'internethakai/util'
7
+ require 'internethakai/logger'
8
+ require 'internethakai/response'
9
+ require 'internethakai/action'
10
+ require 'internethakai/http_client'
11
+ require 'internethakai/client_handler'
12
+ require 'internethakai/reporter'
13
+ require 'internethakai/time_register'
14
+ require 'internethakai/client_queue'
15
+ require 'internethakai/concurrency_manager'
16
+ require 'internethakai/main'
17
+ require 'internethakai/generator'
18
+
19
+ module InternetHakai
20
+ # インターネット破壊
21
+ VERSION = '0.2.0'
22
+ GET="GET"
23
+ POST="POST"
24
+ PUT="PUT"
25
+ DELETE="DELETE"
26
+ end
@@ -0,0 +1,25 @@
1
+ require 'internethakai/core'
2
+ require 'internethakai/scenario_builder'
3
+ require 'internethakai/scenario_handler'
4
+ require 'internethakai/scenario'
5
+ require 'internethakai/executor'
6
+ require 'internethakai/util'
7
+ require 'internethakai/logger'
8
+ require 'internethakai/response'
9
+ require 'internethakai/action'
10
+ require 'internethakai/http_client'
11
+ require 'internethakai/client_handler'
12
+ require 'internethakai/reporter'
13
+ require 'internethakai/time_register'
14
+ require 'internethakai/client_queue'
15
+ require 'internethakai/concurrency_manager'
16
+ require 'internethakai/main'
17
+
18
+ module InternetHakai
19
+ # インターネット破壊
20
+ VERSION = '0.1.3'
21
+ GET="GET"
22
+ POST="POST"
23
+ PUT="PUT"
24
+ DELETE="DELETE"
25
+ end
@@ -0,0 +1,403 @@
1
+ module InternetHakai
2
+ # = httpリクエストを行なうアクション
3
+ class RequestAction < BaseAction
4
+ require 'kconv'
5
+ ERROR_MAX = 3
6
+ REDIRECT_MAX = 10
7
+ #attr_accessor :client_queue
8
+ def initialize opt, scenario
9
+ super
10
+ if @opt.has_key? "scan"
11
+ @opt["scan"] = Util::convert_encoding(@opt["scan"], @opt)
12
+ end
13
+ @logger = BaseHandler::get_handler(@opt["logger"])
14
+ @logging = @opt['log_level'] >= 3
15
+ if ! @logging
16
+ #メソッド書き換え!
17
+ def log *args
18
+ end
19
+ def http_request( method, path, bodystring = nil)
20
+ if @redirect > REDIRECT_MAX
21
+ return on_error('too many redirect')
22
+ end
23
+ path = @client_handler.handle_url(@http_client, path, @opt)
24
+ bodystring = @client_handler.handle_body(@http_client, bodystring, @opt) if bodystring
25
+
26
+ # リクエスト処理
27
+ @http_client.request_send(method, path, bodystring)
28
+ end
29
+ end
30
+ if @opt['rev']
31
+ @rev = true
32
+ @task_queue = BaseHandler::get_handler('TaskQueue')
33
+ def call_on_complete response
34
+ @task_queue.add(@on_complete_method)
35
+ end
36
+ def on_free
37
+ if @http_client
38
+ @http_client.release
39
+ @http_client = nil
40
+ end
41
+ end
42
+ else
43
+ def call_on_complete response
44
+ on_complete
45
+ end
46
+ def on_free
47
+ end
48
+ end
49
+ @register = BaseHandler::get_handler(@opt["response_handler"])
50
+ clcls = BaseHandler::get_class(@opt["client_handler"])
51
+ @client_handler = clcls::new(@scenario)
52
+ @method_run = method(:run)
53
+ #@call_on_complete_method = method(:call_on_complete)
54
+ @on_complete_method = method(:on_complete)
55
+ @on_error_method = method(:on_error)
56
+ @ruby19 = RUBY_VERSION >= "1.9"
57
+ end
58
+ def set_client cl
59
+ @http_client = cl
60
+ end
61
+ def get_client
62
+ client = @http_client
63
+ client.reconnect
64
+ client.set_callback(@on_complete_method, @on_error_method)
65
+ client
66
+ end
67
+ def mkclient
68
+ #puts "error: run out of http client: create"
69
+ clientcls = @opt['client_class_obj']
70
+ cl = clientcls::create2(@opt['host'], @opt['port'])
71
+ cl.timeout = @opt['timeout']
72
+ cl.set_headers(@opt['header'])
73
+ return cl
74
+ end
75
+ def get_default
76
+ {
77
+ "method" => "GET"
78
+ }
79
+ end
80
+ def run
81
+ super
82
+ return unless @opt['path']
83
+ init
84
+ @client_handler.performance_id = @performance_id
85
+ #p [object_id, @client_handler.object_id]
86
+ @client_handler.set_opt(@opt)
87
+ @http_client = get_client
88
+ #return dispatch_next unless @http_client
89
+ #return unless @http_client
90
+ @http_client = @client_handler.handle_client(@http_client)
91
+ @register_key = @opt["type"]
92
+
93
+ @http_client.set_cookie(@scenario.cookie) if @scenario.cookie
94
+ http_request(@opt['method'], @opt['path'], @opt['post_string'])
95
+ end
96
+ def init
97
+ @redirect = 0
98
+ @debug_msgs = []
99
+ @errorcount = 0
100
+ end
101
+ def on_free
102
+ end
103
+ def free
104
+ on_free
105
+ @scenario.next
106
+ #@_on_complete_calback.call if @_on_complete_calback
107
+ @scenario_handler.quit_action(@scenario_id)
108
+ end
109
+ def log *args
110
+ @debug_msgs << args.join
111
+ end
112
+ # http リクエスト発行
113
+ # path: urlのpath
114
+ # body: postの場合のbody
115
+ def http_request( method, path, bodystring = nil)
116
+ if @redirect > REDIRECT_MAX
117
+ return on_error('too many redirect')
118
+ end
119
+ url = path
120
+ url = @client_handler.handle_url(@http_client, url, @opt)
121
+ #p [self.object_id, self.performance_id, url]
122
+ #bodystring = @client_handler.handle_body(@http_client, bodystring, @opt) unless bodystring.nil?
123
+ bodystring = @client_handler.handle_body(@http_client, bodystring, @opt) if bodystring
124
+
125
+ log("URL:::", url)
126
+ log "BODY:::", bodystring.to_s
127
+ # リクエスト処理
128
+ @http_client.request_send(method, url, bodystring)
129
+ end
130
+
131
+ def on_error err, response=nil
132
+ if err.is_a? String
133
+ @logger.run(err, 2)
134
+ @errorcount += 1
135
+ on_complete response
136
+ return
137
+ elsif err.is_a? TimeoutError
138
+ @logger.run("x", 2)
139
+ @errorcount += 1
140
+ on_complete response
141
+ return
142
+ elsif err.is_a? SystemCallError
143
+ free
144
+ raise err
145
+ elsif err.is_a? SocketError
146
+ free
147
+ raise err
148
+ elsif err.is_a? Interrupt
149
+ free
150
+ raise err
151
+ elsif err.is_a? Exception
152
+ free
153
+ end
154
+ @logger.run("error: #{err.to_s}\n", 2)
155
+ @errorcount += 1
156
+ return on_complete(response)
157
+ end
158
+
159
+ #リクエスト完了時の処理
160
+ def on_complete response
161
+ if response.nil? #レスポンスが空の場合。時間だけ記録
162
+ @http_client.release
163
+ @http_client = nil
164
+
165
+ log "CONTENT_LENGTH:::", 0
166
+ @register.regist(@register_key, 0, response, @errorcount)
167
+ free
168
+ return
169
+ end
170
+
171
+ if (response.status / 100 == 3)
172
+ #リダイレクトの場合
173
+ begin
174
+ ok = false
175
+ url = response.location
176
+ tmp = url.size
177
+ idx = url.index('/', 8) || url.size
178
+ path = url[idx, tmp ]
179
+ path = '/'+path if path[0,1]!='/'
180
+ @logger.run(response.body, 4) if response && @errorcount>0 && (response.content_type.include?('text') || response.content_type.include?('xml'))
181
+ on_redirect path
182
+ @redirect += 1
183
+ @redirect_url = path
184
+ #リダイレクトの場合は次のリクエストへ
185
+ @opt['url'] = url
186
+ log "REDIRECT:::", url
187
+ log "++++++++++++++++++++++++++++++++++++++\n"
188
+ @logger.run(@debug_msgs.join("\n")+"\n",3)
189
+ @debug_msgs = []
190
+
191
+ @logger.run("\r\n+++++++++++++++++++++++++++++++\n", 4)
192
+ @rtime = response.time unless response.nil?
193
+ @register.regist(@register_key, @rtime, response, @errorcount)
194
+ @scenario.set_cookie(response.cookie)
195
+ #@response = nil
196
+ if @opt['follow_redirect']
197
+ @register_key = @redirect_url.gsub( /\?.*$/, '' ).gsub( /[#;].*/, '' )
198
+ @http_client.reconnect
199
+ ok = true
200
+ http_request(GET, @redirect_url, nil)
201
+ return
202
+ else
203
+ #リダイレクトリクエストしない / freen呼ぶ
204
+ free
205
+ return
206
+ end
207
+ rescue
208
+ raise
209
+ free unless ok
210
+ return
211
+ end
212
+ end
213
+
214
+ begin
215
+ #puts "on complete1: #{Time::now.usec/1000.to_f}"
216
+ @http_client.release
217
+ @http_client = nil
218
+ log "STATUS_CODE:::",response.status
219
+ size = 0
220
+ size = response.body.size if response.body
221
+ log "CONTENT_LENGTH:::",size
222
+ if response.status != 200
223
+ if response.content_type != 'application/x-shockwave-flash'
224
+ log "RESPONSE:::", response.body
225
+ end
226
+ end
227
+ @rtime = response.time
228
+ @scenario.set_cookie(response.cookie)
229
+ log "RESPONSE_TIME:::",@rtime
230
+ #puts "on complete1.1: #{Time::now.usec/1000.to_f}"
231
+
232
+ response.body.force_encoding(@opt['encoding']) if @ruby19 and (response.content_type.include?('text') || response.content_type.include?('xml'))
233
+ if(@opt["scan"])
234
+ check_scan response.body, @opt["scan"]
235
+ end
236
+ if(@opt["assert_size"])
237
+ check_size response.body, @opt["assert_size"]
238
+ end
239
+ on_response(response)
240
+
241
+ #puts "on complete2.1: #{Time::now.usec/1000.to_f}"
242
+ @register.regist(@register_key, @rtime, response, @errorcount)
243
+ #puts "on complete2: #{Time::now.usec/1000.to_f}"
244
+
245
+ @debug_msgs << "++++++++++++++++++++++++++++++++++++++\n"
246
+ @logger.run(@debug_msgs.join("\n")+"\n",3)
247
+ @debug_msgs = []
248
+ @logger.run(response.body, 4) if response && (response.content_type.include?('text') || response.content_type.include?('xml'))
249
+ @logger.run("\r\n+++++++++++++++++++++++++++++++\n", 4)
250
+ ensure
251
+ free #絶対freeを呼ぶ!
252
+ end
253
+ end
254
+
255
+ def on_redirect newurl
256
+
257
+ end
258
+ def on_response response
259
+ end
260
+ def check_size body, size
261
+ unless body.size > size
262
+ @debug_msgs << "SIZE_CHECK:::false:::"+body.size.to_s
263
+ @errorcount += 1
264
+ else
265
+ @debug_msgs << "SIZE_CHECK:::true"
266
+ end
267
+ end
268
+ def check_scan body, scan
269
+ unless body.include? scan
270
+ @debug_msgs << "SCAN:::false:::"+scan
271
+ @errorcount += 1
272
+ else
273
+ @debug_msgs << "SCAN:::true"
274
+ end
275
+ end
276
+ def to_s
277
+ "<#{self.class}:#{object_id}:#{@opt['path']}>"
278
+ end
279
+ # 黒魔術
280
+ def set_wait
281
+ @oldrun = method(:run)
282
+ if @opt['rev']
283
+ def self.fire
284
+ @timer.disable
285
+ @oldrun.call
286
+ end
287
+ def self.run
288
+ @timer.reset
289
+ @timer.enable unless @timer.enabled?
290
+ end
291
+ @timer = Rev::TimerWatcher::new(@opt['wait'], true)
292
+ @timer.attach(Rev::Loop::default)
293
+ @timer.disable
294
+ @timer.on_timer(&method(:fire))
295
+ else
296
+ def self.run
297
+ sleep @opt['wait']
298
+ @oldrun.call
299
+ end
300
+ end
301
+ end
302
+ end
303
+ #変数をセットするアクション
304
+ class SetVarAction < RequestAction
305
+ def on_response response
306
+ return if response.nil? || response.status != 200
307
+ if @opt['key']
308
+ @client_handler.set_var(@opt['key'], response.body.chomp)
309
+ @debug_msgs << "SET_VAR:::#{@opt['key']}: #{response.body.chomp}\n"
310
+ end
311
+ end
312
+ end
313
+ #正規表現で取得した変数をセットするアクション
314
+ class RegexpSetVarAction < RequestAction
315
+ def on_response response
316
+ return if response.nil? || response.status != 200
317
+ if @opt['key'] && @opt['expr']
318
+ r = @opt['compiled_expr']
319
+ r =~ response.body
320
+ if Regexp.last_match
321
+ @client_handler.set_var(@opt['key'],Regexp.last_match(1))
322
+ @debug_msgs << "REGEXP_SET_VAR:::#{@opt['key']}: #{Regexp.last_match(1)}\n"
323
+ end
324
+ end
325
+ end
326
+ end
327
+ #リダイレクトしないことをチェック
328
+ class NoRedirectCheckAction < RequestAction
329
+ def on_redirect newurl
330
+ @errorcount+=1
331
+ log "ASSERT_NO_REDIRECT:::false"
332
+ end
333
+ end
334
+ class SleepAction < RequestAction
335
+ def run
336
+ sleep @opt['wait']
337
+ super
338
+ end
339
+ end
340
+ class TimerAction < RequestAction
341
+ alias :run_super :run
342
+ def initialize opt, scenario
343
+ super
344
+ @timer = Rev::TimerWatcher::new(opt['wait'], true)
345
+ @timer.attach(Rev::Loop::default)
346
+ @timer.disable
347
+ @timer.on_timer(&method(:fire))
348
+ end
349
+ def fire
350
+ @timer.disable
351
+ run_super
352
+ end
353
+ def run
354
+ @timer.reset
355
+ @timer.enable unless @timer.enabled?
356
+ end
357
+ end
358
+ #リダイレクトをチェック / config に assert_redirectという名前でリダイレクト先を追加
359
+ class RedirectCheckAction < RequestAction
360
+ def initialize opt, scenario
361
+ super
362
+ if @opt.has_key? "assert_redirect_scan"
363
+ @opt["assert_redirect_scan"] = Util::convert_encoding(@opt["assert_redirect_scan"], @opt)
364
+ end
365
+ end
366
+ def on_redirect newurl
367
+ if curl = @opt["assert_redirect"]
368
+ if curl.is_a? Array
369
+ if curl.any?{|u| newurl.include? u}
370
+ log "ASSERT_REDIRECT:::true #{newurl}"
371
+ else
372
+ @errorcount+=1
373
+ log "ASSERT_REDIRECT:::false #{newurl}"
374
+ #@detail += "invalid redirect: " + newurl
375
+ end
376
+ else
377
+ if ! newurl.include? @opt["assert_redirect"]
378
+ @errorcount+=1
379
+ #@detail += "invalid redirect: " + newurl
380
+ log "ASSERT_REDIRECT:::false #{newurl}"
381
+ else
382
+ log "ASSERT_REDIRECT:::true #{newurl}"
383
+ end
384
+ end
385
+ else
386
+ @errorcount += 1
387
+ end
388
+ end
389
+ def on_complete response
390
+ super
391
+ if(@redirect >= 1 && @opt["assert_redirect_scan"])
392
+ return if response.nil?
393
+ scan = @opt["assert_redirect_scan"]
394
+ unless response.body.include? scan
395
+ log "REDIRECT_SCAN:::false:::"+scan
396
+ @errorcount += 1
397
+ else
398
+ log "REDIRECT_SCAN:::true"
399
+ end
400
+ end
401
+ end
402
+ end
403
+ end