Description:
added first page load test on localhost
Commit status:
[Not Reviewed]
References:
Comments:
0 Commit comments 0 Inline Comments
Unresolved TODOs:
There are no unresolved TODOs
Add another comment

r314:933be61bc431 - - 4 files changed: 28 inserted, 4 deleted

@@ -0,0 +1,7
1 + How to call
2 + ===========
3 +
4 + Load test for front page:
5 +
6 + ruby runner.rb common_visitors.rb FirstPageViewer 10 -t 10
7 +
@@ -0,0 +1,7
1 + visitor "FirstPageViewer" do
2 + stores_cookies
3 +
4 + site_url "http://localhost:3000"
5 +
6 + get "/"
7 + end
@@ -1,148 +1,157
1 #
1 #
2 # This file is part of a web load testing tool (currently having no name)
2 # This file is part of a web load testing tool (currently having no name)
3 # Copyright (C) 2008 Jittat Fakcharoenphol
3 # Copyright (C) 2008 Jittat Fakcharoenphol
4 #
4 #
5 # This program is free software; you can redistribute it and/or modify
5 # This program is free software; you can redistribute it and/or modify
6 # it under the terms of the GNU General Public License as published by
6 # it under the terms of the GNU General Public License as published by
7 # the Free Software Foundation; either version 2 of the License, or
7 # the Free Software Foundation; either version 2 of the License, or
8 # (at your option) any later version.
8 # (at your option) any later version.
9 #
9 #
10 # This program is distributed in the hope that it will be useful, but
10 # This program is distributed in the hope that it will be useful, but
11 # WITHOUT ANY WARRANTY; without even the implied warranty of
11 # WITHOUT ANY WARRANTY; without even the implied warranty of
12 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 # General Public License for more details.
13 # General Public License for more details.
14 #
14 #
15 # You should have received a copy of the GNU General Public License
15 # You should have received a copy of the GNU General Public License
16 # along with this program; if not, write to the Free Software
16 # along with this program; if not, write to the Free Software
17 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
17 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
18 # 02110-1301, USA.
18 # 02110-1301, USA.
19 #
19 #
20
20
21 require 'visitor_curl_cli'
21 require 'visitor_curl_cli'
22
22
23 + TEMP_DIR = './tmp'
24 +
23 def show_usage
25 def show_usage
24 puts <<USAGE
26 puts <<USAGE
25 using: ruby runner.rb <visitor_file> [<type> <number>] [<type> <number>] ... [options]
27 using: ruby runner.rb <visitor_file> [<type> <number>] [<type> <number>] ... [options]
26 * visitor_file : your visitor definition file, (with or without .rb)
28 * visitor_file : your visitor definition file, (with or without .rb)
27 * type, number : the type and the number of visitors of that type
29 * type, number : the type and the number of visitors of that type
28 * options : any of the following
30 * options : any of the following
29 -t <sec> specify how long (in seconds)
31 -t <sec> specify how long (in seconds)
30 -d dry-run: run, but make no real http requests
32 -d dry-run: run, but make no real http requests
31 USAGE
33 USAGE
32 end
34 end
33
35
36 + def initialize_temp_dir
37 + if !FileTest.exists? TEMP_DIR
38 + Dir.mkdir TEMP_DIR
39 + end
40 + end
41 +
34 def runner(visitor_lists, load_time=60, options={})
42 def runner(visitor_lists, load_time=60, options={})
35 visitors = []
43 visitors = []
36 vcount = 0
44 vcount = 0
37
45
38 visitor_lists.each do |cname, num|
46 visitor_lists.each do |cname, num|
39 begin
47 begin
40 c = Kernel.const_get(cname)
48 c = Kernel.const_get(cname)
41
49
42 num.times do
50 num.times do
43 - visitors[vcount] = c.new(vcount+1)
51 + visitors[vcount] = c.new(vcount+1, TEMP_DIR)
44 visitors[vcount].talkative = true
52 visitors[vcount].talkative = true
45 vcount += 1
53 vcount += 1
46 end
54 end
47 rescue NameError
55 rescue NameError
48 puts "Can't find class #{cname}"
56 puts "Can't find class #{cname}"
49 show_usage
57 show_usage
50 exit(0)
58 exit(0)
51 end
59 end
52 end
60 end
53
61
54 puts "Having #{vcount} visitors"
62 puts "Having #{vcount} visitors"
55
63
56 vthread = []
64 vthread = []
57
65
58 all_start_time = Time.new
66 all_start_time = Time.new
59
67
60 # start all visitors
68 # start all visitors
61 vcount.times do |i|
69 vcount.times do |i|
62 vthread[i] = Thread.new do
70 vthread[i] = Thread.new do
63 visitors[i].run(:forever,options)
71 visitors[i].run(:forever,options)
64 end
72 end
65 end
73 end
66
74
67 # wait for load_time seconds
75 # wait for load_time seconds
68 sleep load_time
76 sleep load_time
69
77
70 visitors.each do |visitor| visitor.stop! end
78 visitors.each do |visitor| visitor.stop! end
71
79
72 all_finish_time = Time.new
80 all_finish_time = Time.new
73
81
74 begin
82 begin
75 # wait for all threads to stop
83 # wait for all threads to stop
76 vcount.times do |i|
84 vcount.times do |i|
77 #puts "Waiting for thread #{i}, #{vthread[i].alive?}"
85 #puts "Waiting for thread #{i}, #{vthread[i].alive?}"
78 vthread[i].join
86 vthread[i].join
79 end
87 end
80
88
81 rescue Interrupt
89 rescue Interrupt
82 # kill all remaining threads
90 # kill all remaining threads
83 vcount.times do |i|
91 vcount.times do |i|
84 vthread[i].kill if vthread[i].alive?
92 vthread[i].kill if vthread[i].alive?
85 end
93 end
86 end
94 end
87
95
88 # clean up
96 # clean up
89 visitors.each do |visitor|
97 visitors.each do |visitor|
90 #puts "Clean up: #{visitor.id}"
98 #puts "Clean up: #{visitor.id}"
91 visitor.cleanup
99 visitor.cleanup
92 end
100 end
93
101
94 #all_finish_time = Time.new
102 #all_finish_time = Time.new
95
103
96 total_req = 0
104 total_req = 0
97
105
98 vcount.times do |i|
106 vcount.times do |i|
99 stat = visitors[i].statistics
107 stat = visitors[i].statistics
100 # puts "TYPE: #{visitors[i].class}"
108 # puts "TYPE: #{visitors[i].class}"
101 # puts "Total requested = #{stat[:num_requested]}"
109 # puts "Total requested = #{stat[:num_requested]}"
102 # puts "Average = #{stat[:avg_request_time]}"
110 # puts "Average = #{stat[:avg_request_time]}"
103 # puts "S.D. = #{stat[:std_dev]}"
111 # puts "S.D. = #{stat[:std_dev]}"
104 total_req += stat[:num_requested]
112 total_req += stat[:num_requested]
105 end
113 end
106
114
107 elapsed_time = all_finish_time - all_start_time
115 elapsed_time = all_finish_time - all_start_time
108
116
109 puts
117 puts
110 puts "Total time = #{elapsed_time} sec."
118 puts "Total time = #{elapsed_time} sec."
111 puts "Total requests = #{total_req}"
119 puts "Total requests = #{total_req}"
112 puts "Trans. per sec = #{total_req/elapsed_time}"
120 puts "Trans. per sec = #{total_req/elapsed_time}"
113 end
121 end
114
122
115 ###########################
123 ###########################
116 # MAIN
124 # MAIN
117 ###########################
125 ###########################
118
126
119 if ARGV.length==0
127 if ARGV.length==0
120 show_usage
128 show_usage
121 exit(0)
129 exit(0)
122 end
130 end
123
131
124 visitor_file = ARGV.shift
132 visitor_file = ARGV.shift
125 require visitor_file
133 require visitor_file
126
134
127 load_time = 60
135 load_time = 60
128 dry_run = false
136 dry_run = false
129
137
130 #build visitor list
138 #build visitor list
131 visitor_list = {}
139 visitor_list = {}
132 while ARGV.length>0
140 while ARGV.length>0
133 key = ARGV.shift
141 key = ARGV.shift
134
142
135 case key
143 case key
136 when '-d'
144 when '-d'
137 dry_run = true
145 dry_run = true
138 when '-t'
146 when '-t'
139 num = ARGV.shift.to_i
147 num = ARGV.shift.to_i
140 load_time = num
148 load_time = num
141 else
149 else
142 num = ARGV.shift.to_i
150 num = ARGV.shift.to_i
143 visitor_list[key] = num
151 visitor_list[key] = num
144 end
152 end
145 end
153 end
146
154
155 + initialize_temp_dir
147 runner visitor_list, load_time, {:dry_run => dry_run}
156 runner visitor_list, load_time, {:dry_run => dry_run}
148
157
@@ -1,243 +1,244
1 #
1 #
2 # This file is part of a web load testing tool (currently having no name)
2 # This file is part of a web load testing tool (currently having no name)
3 # Copyright (C) 2008 Jittat Fakcharoenphol
3 # Copyright (C) 2008 Jittat Fakcharoenphol
4 #
4 #
5 # This program is free software; you can redistribute it and/or modify
5 # This program is free software; you can redistribute it and/or modify
6 # it under the terms of the GNU General Public License as published by
6 # it under the terms of the GNU General Public License as published by
7 # the Free Software Foundation; either version 2 of the License, or
7 # the Free Software Foundation; either version 2 of the License, or
8 # (at your option) any later version.
8 # (at your option) any later version.
9 #
9 #
10 # This program is distributed in the hope that it will be useful, but
10 # This program is distributed in the hope that it will be useful, but
11 # WITHOUT ANY WARRANTY; without even the implied warranty of
11 # WITHOUT ANY WARRANTY; without even the implied warranty of
12 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 # General Public License for more details.
13 # General Public License for more details.
14 #
14 #
15 # You should have received a copy of the GNU General Public License
15 # You should have received a copy of the GNU General Public License
16 # along with this program; if not, write to the Free Software
16 # along with this program; if not, write to the Free Software
17 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
17 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
18 # 02110-1301, USA.
18 # 02110-1301, USA.
19 #
19 #
20
20
21 require 'rubygems'
21 require 'rubygems'
22 require 'uri'
22 require 'uri'
23
23
24 class Visitor
24 class Visitor
25
25
26 attr_accessor :talkative
26 attr_accessor :talkative
27
27
28 class << self
28 class << self
29 attr_accessor :commands
29 attr_accessor :commands
30 attr_accessor :base_url
30 attr_accessor :base_url
31 attr_accessor :cookies_stored
31 attr_accessor :cookies_stored
32 end
32 end
33
33
34 def get_cookie_fname
34 def get_cookie_fname
35 - "cookies.#{@id}"
35 + "#{@base_dir}/cookies.#{@id}"
36 end
36 end
37
37
38 def get_output_fname
38 def get_output_fname
39 - "output.#{@id}"
39 + "#{@base_dir}/output.#{@id}"
40 end
40 end
41
41
42 def id
42 def id
43 @id
43 @id
44 end
44 end
45
45
46 - def initialize(id=0)
46 + def initialize(id=0, base_dir='.')
47 # initialize nil class variable
47 # initialize nil class variable
48 self.class.base_url = "" if (self.class.base_url) == nil
48 self.class.base_url = "" if (self.class.base_url) == nil
49 self.class.cookies_stored = false if self.class.cookies_stored == nil
49 self.class.cookies_stored = false if self.class.cookies_stored == nil
50
50
51 @id = id
51 @id = id
52 + @base_dir = base_dir
52 @cookies_fname = get_cookie_fname
53 @cookies_fname = get_cookie_fname
53 @output_fname = get_output_fname
54 @output_fname = get_output_fname
54 @statistics = Array.new
55 @statistics = Array.new
55 @talkative = false
56 @talkative = false
56
57
57 @stopped = false
58 @stopped = false
58 end
59 end
59
60
60 def cleanup
61 def cleanup
61 trial = 0
62 trial = 0
62 while FileTest.exists?(@cookies_fname)
63 while FileTest.exists?(@cookies_fname)
63 File.delete(@cookies_fname)
64 File.delete(@cookies_fname)
64 if FileTest.exists?(@cookies_fname)
65 if FileTest.exists?(@cookies_fname)
65 # wait until system returns
66 # wait until system returns
66 puts "STILL HERE"
67 puts "STILL HERE"
67 sleep 1
68 sleep 1
68 trial += 1
69 trial += 1
69 break if trial>10
70 break if trial>10
70 end
71 end
71 end
72 end
72
73
73 while FileTest.exists?(@output_fname)
74 while FileTest.exists?(@output_fname)
74 File.delete(@output_fname)
75 File.delete(@output_fname)
75 if FileTest.exists?(@output_fname)
76 if FileTest.exists?(@output_fname)
76 # wait until system returns
77 # wait until system returns
77 sleep 1
78 sleep 1
78 trial += 1
79 trial += 1
79 break if trial>10
80 break if trial>10
80 end
81 end
81 end
82 end
82 end
83 end
83
84
84 def self.site_url(url)
85 def self.site_url(url)
85 self.base_url = url
86 self.base_url = url
86 end
87 end
87
88
88 def self.stores_cookies
89 def self.stores_cookies
89 self.cookies_stored = true
90 self.cookies_stored = true
90 end
91 end
91
92
92 def self.preprocess_param_hash(params)
93 def self.preprocess_param_hash(params)
93 return {} if params==nil
94 return {} if params==nil
94 plist = {}
95 plist = {}
95 params.each do |key,val|
96 params.each do |key,val|
96 if key.is_a? Symbol
97 if key.is_a? Symbol
97 key_s = key.to_s
98 key_s = key.to_s
98 else
99 else
99 key_s = key
100 key_s = key
100 end
101 end
101 plist[key_s] = val
102 plist[key_s] = val
102 end
103 end
103 plist
104 plist
104 end
105 end
105
106
106 def self.get(url,params=nil)
107 def self.get(url,params=nil)
107 self.commands = [] if self.commands==nil
108 self.commands = [] if self.commands==nil
108 self.commands << {
109 self.commands << {
109 :command => :get,
110 :command => :get,
110 :url => url,
111 :url => url,
111 :params => Visitor.preprocess_param_hash(params) }
112 :params => Visitor.preprocess_param_hash(params) }
112 end
113 end
113
114
114 def self.post(url,params=nil,options=nil)
115 def self.post(url,params=nil,options=nil)
115 self.commands = [] if self.commands==nil
116 self.commands = [] if self.commands==nil
116 self.commands << { :command => :post,
117 self.commands << { :command => :post,
117 :url => url,
118 :url => url,
118 :params => Visitor.preprocess_param_hash(params),
119 :params => Visitor.preprocess_param_hash(params),
119 :options => options }
120 :options => options }
120 end
121 end
121
122
122 def substitute_id(st)
123 def substitute_id(st)
123 return st if !(st.is_a? String)
124 return st if !(st.is_a? String)
124 st.gsub(/(()|(\$))\$\{id\}/) do |s|
125 st.gsub(/(()|(\$))\$\{id\}/) do |s|
125 if s=="${id}"
126 if s=="${id}"
126 @id.to_s
127 @id.to_s
127 else
128 else
128 "${id}"
129 "${id}"
129 end
130 end
130 end
131 end
131 end
132 end
132
133
133 def encode_params(params)
134 def encode_params(params)
134 enc = ""
135 enc = ""
135 if params!=nil and params.length!=0
136 if params!=nil and params.length!=0
136 params.each do |key,val|
137 params.each do |key,val|
137 if enc != ""
138 if enc != ""
138 enc += '&'
139 enc += '&'
139 end
140 end
140 val = substitute_id(val)
141 val = substitute_id(val)
141 enc += URI.escape(key) + '=' + URI.escape(val.to_s)
142 enc += URI.escape(key) + '=' + URI.escape(val.to_s)
142 end
143 end
143 end
144 end
144 enc
145 enc
145 end
146 end
146
147
147 def get(url,params)
148 def get(url,params)
148 #build url
149 #build url
149
150
150 #puts "----------------------cookies-----------"
151 #puts "----------------------cookies-----------"
151 #system("cat #{@cookies_fname}")
152 #system("cat #{@cookies_fname}")
152 #puts "----------------------cookies-----------"
153 #puts "----------------------cookies-----------"
153
154
154 full_url = "#{self.class.base_url}#{url}"
155 full_url = "#{self.class.base_url}#{url}"
155 if params!=nil and params.length!=0
156 if params!=nil and params.length!=0
156 full_url += '?' + encode_params(params)
157 full_url += '?' + encode_params(params)
157 end
158 end
158
159
159 cmd = "curl -k -b #{@cookies_fname} -D #{@cookies_fname} #{full_url} " +
160 cmd = "curl -k -b #{@cookies_fname} -D #{@cookies_fname} #{full_url} " +
160 " -s -L -o #{@output_fname}"
161 " -s -L -o #{@output_fname}"
161 #puts ">>>>>>>>>>>>>>>>>> " + cmd
162 #puts ">>>>>>>>>>>>>>>>>> " + cmd
162 system(cmd)
163 system(cmd)
163 #system("cat #{@output_fname}")
164 #system("cat #{@output_fname}")
164 end
165 end
165
166
166 def post(url,params,options)
167 def post(url,params,options)
167 #puts "----------------------cookies-----------"
168 #puts "----------------------cookies-----------"
168 #system("cat #{@cookies_fname}")
169 #system("cat #{@cookies_fname}")
169 #puts "----------------------cookies-----------"
170 #puts "----------------------cookies-----------"
170
171
171 full_url = "#{self.class.base_url}#{url}"
172 full_url = "#{self.class.base_url}#{url}"
172 params_str = ""
173 params_str = ""
173 if options!=nil and options[:multipart]==true
174 if options!=nil and options[:multipart]==true
174 params.each do |key,val|
175 params.each do |key,val|
175 if val.is_a? Hash
176 if val.is_a? Hash
176 case val[:type]
177 case val[:type]
177 when :file
178 when :file
178 dval = substitute_id(val[:data])
179 dval = substitute_id(val[:data])
179 params_str += " -F \"#{key}=@#{dval.to_s}\""
180 params_str += " -F \"#{key}=@#{dval.to_s}\""
180 end
181 end
181 else
182 else
182 val = substitute_id(val)
183 val = substitute_id(val)
183 params_str += " -F \"#{key}=#{URI.escape(val.to_s)}\""
184 params_str += " -F \"#{key}=#{URI.escape(val.to_s)}\""
184 end
185 end
185 end
186 end
186 else
187 else
187 params_str += "-d \"#{encode_params(params)}\""
188 params_str += "-d \"#{encode_params(params)}\""
188 end
189 end
189
190
190 #puts params_str
191 #puts params_str
191
192
192 cmd = "curl -L -k -b #{@cookies_fname} -D #{@cookies_fname} " +
193 cmd = "curl -L -k -b #{@cookies_fname} -D #{@cookies_fname} " +
193 " #{params_str} #{full_url} -s -o #{@output_fname}"
194 " #{params_str} #{full_url} -s -o #{@output_fname}"
194 #puts ">>>>>>>>>>>>>>>>>>>>>>>>>>> POST: " + cmd
195 #puts ">>>>>>>>>>>>>>>>>>>>>>>>>>> POST: " + cmd
195 system(cmd)
196 system(cmd)
196 #system("cat #{@output_fname}")
197 #system("cat #{@output_fname}")
197 end
198 end
198
199
199 def stop!
200 def stop!
200 @stopped = true
201 @stopped = true
201 end
202 end
202
203
203 def run(times=nil, options={})
204 def run(times=nil, options={})
204 times = 1 if times == :once
205 times = 1 if times == :once
205
206
206 @stopped = false
207 @stopped = false
207 while times!=0
208 while times!=0
208 self.class.commands.each do |cmd|
209 self.class.commands.each do |cmd|
209 puts "#{@id}: #{cmd[:command]} #{cmd[:url]}" if @talkative
210 puts "#{@id}: #{cmd[:command]} #{cmd[:url]}" if @talkative
210
211
211 start_time = Time.new
212 start_time = Time.new
212
213
213 if !options[:dry_run]
214 if !options[:dry_run]
214 case cmd[:command]
215 case cmd[:command]
215 when :get
216 when :get
216 get cmd[:url], cmd[:params]
217 get cmd[:url], cmd[:params]
217 when :post
218 when :post
218 post cmd[:url], cmd[:params], cmd[:options]
219 post cmd[:url], cmd[:params], cmd[:options]
219 end
220 end
220 end
221 end
221
222
222 finish_time = Time.new
223 finish_time = Time.new
223
224
224 break if @stopped
225 break if @stopped
225
226
226 @statistics << {
227 @statistics << {
227 :url => "#{cmd[:command]}:#{cmd[:url]}",
228 :url => "#{cmd[:command]}:#{cmd[:url]}",
228 :time => finish_time - start_time }
229 :time => finish_time - start_time }
229 end
230 end
230
231
231 times -= 1 if times.is_a? Integer #otherwise, run forever
232 times -= 1 if times.is_a? Integer #otherwise, run forever
232
233
233 break if @stopped
234 break if @stopped
234 end
235 end
235 end
236 end
236
237
237 def show_raw_stat
238 def show_raw_stat
238 @statistics.each do |stat|
239 @statistics.each do |stat|
239 puts "#{stat[:url]} => #{stat[:time]}"
240 puts "#{stat[:url]} => #{stat[:time]}"
240 end
241 end
241 end
242 end
242
243
243 def statistics
244 def statistics
You need to be logged in to leave comments. Login now