internethakai 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
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