Show More
Commit Description:
merge
Commit Description:
merge
References:
File last commit:
Show/Diff file:
Action:
test/load/visitor_curl_cli.rb
| 292 lines
| 6.7 KiB
| text/x-ruby
| RubyLexer
|
|
r313 | # | ||
# This file is part of a web load testing tool (currently having no name) | ||||
# Copyright (C) 2008 Jittat Fakcharoenphol | ||||
# | ||||
# This program is free software; you can redistribute it and/or modify | ||||
# it under the terms of the GNU General Public License as published by | ||||
# the Free Software Foundation; either version 2 of the License, or | ||||
# (at your option) any later version. | ||||
# | ||||
# This program is distributed in the hope that it will be useful, but | ||||
# WITHOUT ANY WARRANTY; without even the implied warranty of | ||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||||
# General Public License for more details. | ||||
# | ||||
# You should have received a copy of the GNU General Public License | ||||
# along with this program; if not, write to the Free Software | ||||
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA | ||||
# 02110-1301, USA. | ||||
# | ||||
require 'rubygems' | ||||
require 'uri' | ||||
class Visitor | ||||
attr_accessor :talkative | ||||
class << self | ||||
attr_accessor :commands | ||||
attr_accessor :base_url | ||||
attr_accessor :cookies_stored | ||||
end | ||||
def get_cookie_fname | ||||
|
r314 | "#{@base_dir}/cookies.#{@id}" | ||
|
r313 | end | ||
def get_output_fname | ||||
|
r314 | "#{@base_dir}/output.#{@id}" | ||
|
r313 | end | ||
def id | ||||
@id | ||||
end | ||||
|
r314 | def initialize(id=0, base_dir='.') | ||
|
r313 | # initialize nil class variable | ||
self.class.base_url = "" if (self.class.base_url) == nil | ||||
self.class.cookies_stored = false if self.class.cookies_stored == nil | ||||
@id = id | ||||
|
r314 | @base_dir = base_dir | ||
|
r313 | @cookies_fname = get_cookie_fname | ||
@output_fname = get_output_fname | ||||
@statistics = Array.new | ||||
@talkative = false | ||||
@stopped = false | ||||
end | ||||
def cleanup | ||||
trial = 0 | ||||
while FileTest.exists?(@cookies_fname) | ||||
File.delete(@cookies_fname) | ||||
if FileTest.exists?(@cookies_fname) | ||||
# wait until system returns | ||||
puts "STILL HERE" | ||||
sleep 1 | ||||
trial += 1 | ||||
break if trial>10 | ||||
end | ||||
end | ||||
while FileTest.exists?(@output_fname) | ||||
File.delete(@output_fname) | ||||
if FileTest.exists?(@output_fname) | ||||
# wait until system returns | ||||
sleep 1 | ||||
trial += 1 | ||||
break if trial>10 | ||||
end | ||||
end | ||||
end | ||||
def self.site_url(url) | ||||
self.base_url = url | ||||
end | ||||
def self.stores_cookies | ||||
self.cookies_stored = true | ||||
end | ||||
def self.preprocess_param_hash(params) | ||||
return {} if params==nil | ||||
plist = {} | ||||
params.each do |key,val| | ||||
if key.is_a? Symbol | ||||
key_s = key.to_s | ||||
else | ||||
key_s = key | ||||
end | ||||
plist[key_s] = val | ||||
end | ||||
plist | ||||
end | ||||
def self.get(url,params=nil) | ||||
self.commands = [] if self.commands==nil | ||||
self.commands << { | ||||
:command => :get, | ||||
:url => url, | ||||
:params => Visitor.preprocess_param_hash(params) } | ||||
end | ||||
def self.post(url,params=nil,options=nil) | ||||
self.commands = [] if self.commands==nil | ||||
self.commands << { :command => :post, | ||||
:url => url, | ||||
:params => Visitor.preprocess_param_hash(params), | ||||
:options => options } | ||||
end | ||||
|
r315 | def self.process_options(options) | ||
if options.has_key? "site_url" | ||||
self.base_url = options["site_url"] | ||||
end | ||||
end | ||||
|
r313 | def substitute_id(st) | ||
return st if !(st.is_a? String) | ||||
st.gsub(/(()|(\$))\$\{id\}/) do |s| | ||||
if s=="${id}" | ||||
@id.to_s | ||||
else | ||||
"${id}" | ||||
end | ||||
end | ||||
end | ||||
def encode_params(params) | ||||
enc = "" | ||||
if params!=nil and params.length!=0 | ||||
params.each do |key,val| | ||||
if enc != "" | ||||
enc += '&' | ||||
end | ||||
val = substitute_id(val) | ||||
enc += URI.escape(key) + '=' + URI.escape(val.to_s) | ||||
end | ||||
end | ||||
enc | ||||
end | ||||
def get(url,params) | ||||
#build url | ||||
#puts "----------------------cookies-----------" | ||||
#system("cat #{@cookies_fname}") | ||||
#puts "----------------------cookies-----------" | ||||
full_url = "#{self.class.base_url}#{url}" | ||||
if params!=nil and params.length!=0 | ||||
full_url += '?' + encode_params(params) | ||||
end | ||||
cmd = "curl -k -b #{@cookies_fname} -D #{@cookies_fname} #{full_url} " + | ||||
" -s -L -o #{@output_fname}" | ||||
#puts ">>>>>>>>>>>>>>>>>> " + cmd | ||||
system(cmd) | ||||
#system("cat #{@output_fname}") | ||||
end | ||||
def post(url,params,options) | ||||
#puts "----------------------cookies-----------" | ||||
#system("cat #{@cookies_fname}") | ||||
#puts "----------------------cookies-----------" | ||||
full_url = "#{self.class.base_url}#{url}" | ||||
params_str = "" | ||||
if options!=nil and options[:multipart]==true | ||||
params.each do |key,val| | ||||
if val.is_a? Hash | ||||
case val[:type] | ||||
when :file | ||||
dval = substitute_id(val[:data]) | ||||
params_str += " -F \"#{key}=@#{dval.to_s}\"" | ||||
end | ||||
else | ||||
val = substitute_id(val) | ||||
params_str += " -F \"#{key}=#{URI.escape(val.to_s)}\"" | ||||
end | ||||
end | ||||
else | ||||
params_str += "-d \"#{encode_params(params)}\"" | ||||
end | ||||
#puts params_str | ||||
cmd = "curl -L -k -b #{@cookies_fname} -D #{@cookies_fname} " + | ||||
" #{params_str} #{full_url} -s -o #{@output_fname}" | ||||
#puts ">>>>>>>>>>>>>>>>>>>>>>>>>>> POST: " + cmd | ||||
system(cmd) | ||||
#system("cat #{@output_fname}") | ||||
end | ||||
def stop! | ||||
@stopped = true | ||||
end | ||||
def run(times=nil, options={}) | ||||
times = 1 if times == :once | ||||
@stopped = false | ||||
while times!=0 | ||||
self.class.commands.each do |cmd| | ||||
puts "#{@id}: #{cmd[:command]} #{cmd[:url]}" if @talkative | ||||
start_time = Time.new | ||||
if !options[:dry_run] | ||||
case cmd[:command] | ||||
when :get | ||||
get cmd[:url], cmd[:params] | ||||
when :post | ||||
post cmd[:url], cmd[:params], cmd[:options] | ||||
end | ||||
end | ||||
finish_time = Time.new | ||||
break if @stopped | ||||
@statistics << { | ||||
:url => "#{cmd[:command]}:#{cmd[:url]}", | ||||
:time => finish_time - start_time } | ||||
end | ||||
times -= 1 if times.is_a? Integer #otherwise, run forever | ||||
break if @stopped | ||||
end | ||||
end | ||||
def show_raw_stat | ||||
@statistics.each do |stat| | ||||
puts "#{stat[:url]} => #{stat[:time]}" | ||||
end | ||||
end | ||||
def statistics | ||||
num_requested = @statistics.length | ||||
totaltime = 0.0 | ||||
@statistics.each { |stat| totaltime += stat[:time] } | ||||
if num_requested>0 | ||||
average_request_time = totaltime / num_requested | ||||
else | ||||
average_request_time = 0 | ||||
end | ||||
sq_sum = 0.0 | ||||
@statistics.each do |stat| | ||||
sq_sum += (stat[:time]-average_request_time) ** 2 | ||||
end | ||||
if num_requested>1 | ||||
sd = Math.sqrt(sq_sum/(num_requested-1)) | ||||
else | ||||
sd = 0 | ||||
end | ||||
return { | ||||
:num_requested => num_requested, | ||||
:avg_request_time => average_request_time, | ||||
:std_dev => sd | ||||
} | ||||
end | ||||
end | ||||
|
r315 | def visitor(cname,options={},&blk) | ||
|
r313 | c = Class.new(Visitor) | ||
begin | ||||
Object.const_set(cname,c) | ||||
rescue NameError | ||||
puts <<ERROR | ||||
Error on type #{cname}. | ||||
Type name should be capitalized and follow Ruby constant naming rule. | ||||
ERROR | ||||
exit(0) | ||||
end | ||||
|
r315 | c.process_options(options) | ||
|
r313 | c.instance_eval(&blk) | ||
end | ||||