|
|
#
|
|
|
# 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 'visitor_curl_cli'
|
|
|
|
|
|
TEMP_DIR = './tmp'
|
|
|
|
|
|
def show_usage
|
|
|
puts <<USAGE
|
|
|
using: ruby runner.rb <visitor_file> [<type> <number>] [<type> <number>] ... [options]
|
|
|
* visitor_file : your visitor definition file, (with or without .rb)
|
|
|
* type, number : the type and the number of visitors of that type
|
|
|
* options : any of the following
|
|
|
-t <sec> specify how long (in seconds)
|
|
|
-d dry-run: run, but make no real http requests
|
|
|
USAGE
|
|
|
end
|
|
|
|
|
|
def initialize_temp_dir
|
|
|
if !FileTest.exists? TEMP_DIR
|
|
|
Dir.mkdir TEMP_DIR
|
|
|
end
|
|
|
end
|
|
|
|
|
|
def runner(visitor_lists, load_time=60, options={})
|
|
|
visitors = []
|
|
|
vcount = 0
|
|
|
|
|
|
visitor_lists.each do |cname, num|
|
|
|
begin
|
|
|
c = Kernel.const_get(cname)
|
|
|
|
|
|
num.times do
|
|
|
visitors[vcount] = c.new(vcount+1, TEMP_DIR)
|
|
|
visitors[vcount].talkative = true
|
|
|
vcount += 1
|
|
|
end
|
|
|
rescue NameError
|
|
|
puts "Can't find class #{cname}"
|
|
|
show_usage
|
|
|
exit(0)
|
|
|
end
|
|
|
end
|
|
|
|
|
|
puts "Having #{vcount} visitors"
|
|
|
|
|
|
vthread = []
|
|
|
|
|
|
all_start_time = Time.new
|
|
|
|
|
|
# start all visitors
|
|
|
vcount.times do |i|
|
|
|
vthread[i] = Thread.new do
|
|
|
visitors[i].run(:forever,options)
|
|
|
end
|
|
|
end
|
|
|
|
|
|
# wait for load_time seconds
|
|
|
sleep load_time
|
|
|
|
|
|
visitors.each do |visitor| visitor.stop! end
|
|
|
|
|
|
all_finish_time = Time.new
|
|
|
|
|
|
begin
|
|
|
# wait for all threads to stop
|
|
|
vcount.times do |i|
|
|
|
#puts "Waiting for thread #{i}, #{vthread[i].alive?}"
|
|
|
vthread[i].join
|
|
|
end
|
|
|
|
|
|
rescue Interrupt
|
|
|
# kill all remaining threads
|
|
|
vcount.times do |i|
|
|
|
vthread[i].kill if vthread[i].alive?
|
|
|
end
|
|
|
end
|
|
|
|
|
|
# clean up
|
|
|
visitors.each do |visitor|
|
|
|
#puts "Clean up: #{visitor.id}"
|
|
|
visitor.cleanup
|
|
|
end
|
|
|
|
|
|
#all_finish_time = Time.new
|
|
|
|
|
|
total_req = 0
|
|
|
|
|
|
vcount.times do |i|
|
|
|
stat = visitors[i].statistics
|
|
|
# puts "TYPE: #{visitors[i].class}"
|
|
|
# puts "Total requested = #{stat[:num_requested]}"
|
|
|
# puts "Average = #{stat[:avg_request_time]}"
|
|
|
# puts "S.D. = #{stat[:std_dev]}"
|
|
|
total_req += stat[:num_requested]
|
|
|
end
|
|
|
|
|
|
elapsed_time = all_finish_time - all_start_time
|
|
|
|
|
|
puts
|
|
|
puts "Total time = #{elapsed_time} sec."
|
|
|
puts "Total requests = #{total_req}"
|
|
|
puts "Trans. per sec = #{total_req/elapsed_time}"
|
|
|
end
|
|
|
|
|
|
###########################
|
|
|
# MAIN
|
|
|
###########################
|
|
|
|
|
|
if ARGV.length==0
|
|
|
show_usage
|
|
|
exit(0)
|
|
|
end
|
|
|
|
|
|
visitor_file = ARGV.shift
|
|
|
|
|
|
load_time = 60
|
|
|
dry_run = false
|
|
|
|
|
|
#build visitor/option list
|
|
|
visitor_list = {}
|
|
|
visitor_option_list = {}
|
|
|
while ARGV.length>0
|
|
|
key = ARGV.shift
|
|
|
|
|
|
case key
|
|
|
when '-d'
|
|
|
dry_run = true
|
|
|
when '-t'
|
|
|
num = ARGV.shift.to_i
|
|
|
load_time = num
|
|
|
else
|
|
|
if key =~ /--(\w+)=(.*)/
|
|
|
# options
|
|
|
lm = Regexp.last_match
|
|
|
visitor_option_list[lm[1]] = lm[2]
|
|
|
else
|
|
|
# new visitor
|
|
|
num = ARGV.shift.to_i
|
|
|
visitor_list[key] = num
|
|
|
end
|
|
|
end
|
|
|
end
|
|
|
|
|
|
VISITOR_OPTION_LIST = visitor_option_list
|
|
|
require visitor_file
|
|
|
|
|
|
initialize_temp_dir
|
|
|
runner visitor_list, load_time, {:dry_run => dry_run}
|
|
|
|
|
|
|