rwb 0.2.2 → 0.2.3

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,62 @@
1
+ require 'rubygems'
2
+ require 'rake/clean'
3
+ require 'rake/rdoctask'
4
+ require 'rake/testtask'
5
+ require 'rake/gempackagetask'
6
+ require 'rubygems'
7
+
8
+
9
+ Rake::RDocTask.new do |rd|
10
+ rd.main = "readme"
11
+ rd.rdoc_files.include("readme", "lib/**/*.rb")
12
+ end
13
+
14
+ Rake::TestTask.new(:unittests) do |t|
15
+ t.test_files = FileList['test/test*.rb']
16
+ t.warning = true
17
+ t.verbose = false
18
+ end
19
+
20
+ task :test => [:unittests]
21
+
22
+ spec = Gem::Specification.new do |s|
23
+ s.name = 'rwb'
24
+ s.version = "0.2.3"
25
+ s.author = "Pat Eyler"
26
+ s.email = "pat.eyler@gmail.com"
27
+ s.homepage = "http://rubyforge.org/projects/rwb"
28
+ s.platform = Gem::Platform::RUBY
29
+ s.summary = "Ruby Web Bench, a web performance and load testing framework"
30
+ s.files = Dir.glob("{test,lib,bin}/**/*").delete_if {|item|
31
+ item.include?("CVS") || item.include?("rdoc")}
32
+ s.files += ['NEWS', 'README', 'TODO', 'Rakefile']
33
+ s.require_path = 'lib'
34
+ s.autorequire = 'rwb'
35
+ s.has_rdoc = 'true'
36
+ end
37
+
38
+ if $0==__FILE__
39
+ Gem::manage_gems
40
+ Gem::Builder.new(spec).build
41
+ end
42
+
43
+ Rake::GemPackageTask.new(spec) do |pkg|
44
+ pkg.need_zip = true
45
+ pkg.need_tar = true
46
+ end
47
+
48
+
49
+ desc "Perform a cvs update"
50
+ # relies on ssh keys being set up correctly
51
+ task :update do
52
+ sh "cvs update"
53
+ end
54
+
55
+ desc "Perform a cvs commit after running unit tests and
56
+ updating"
57
+ # relies on ssh keys being set up correctly
58
+ task :commit => [:update, :unittests] do |t|
59
+ msg = "commit from Rake:\n"
60
+ msg << ENV['MSG']
61
+ sh "cvs commit -m '#{msg}'"
62
+ end
@@ -0,0 +1,100 @@
1
+ module RWB
2
+ class Runner
3
+
4
+ def report_full(sla_levels = @sla_levels)
5
+ report_header
6
+ report_overall(sla_levels)
7
+ report_urls(sla_levels)
8
+ report_by_time(sla_levels)
9
+ end
10
+
11
+ def report_overall(sla_levels = @sla_levels)
12
+ results = @new_results.times_by_url
13
+
14
+ puts "Overall results:"
15
+ print_times(results.sort, sla_levels)
16
+ end
17
+
18
+ def report_urls(sla_levels = @sla_levels)
19
+ @urls.urls.keys.sort.each do |key|
20
+ url = @urls.urls[key].to_base
21
+ results = @new_results.times_by_url(url)
22
+ puts "Results for #{url}:"
23
+ if results.length > 0
24
+ print_times(results.sort, sla_levels)
25
+ else
26
+ puts "no results for url"
27
+ end
28
+ end
29
+ end
30
+
31
+ def graph_quartiles_urls(scale = nil)
32
+ @urls.urls.keys.sort.each do |key|
33
+ url = @urls.urls[key].to_base
34
+ results = @new_results.times_by_url(url)
35
+ puts "#{url}:\n\t" + results_quartile(results.sort, scale)
36
+ end
37
+ end
38
+
39
+ def graph_quartiles_overall
40
+ results = @new_results.times_by_url
41
+ puts results_quartile(results.sort)
42
+ end
43
+
44
+ def report_by_time(sla_levels = @sla_levels, granularity = 0.2)
45
+ start = 0.0
46
+ stop = granularity
47
+ results = @new_results.times_by_url
48
+ puts "Results by time:"
49
+ while stop <= 1.0
50
+ first = (results.length * start).to_i
51
+ last = (results.length * stop).to_i
52
+ these_results = results.slice(first..last)
53
+ puts "results for requests #{first} - #{last}"
54
+ print_times(these_results.sort, sla_levels)
55
+ start = stop
56
+ stop += granularity
57
+ end
58
+ end
59
+
60
+ def print_times(results, levels)
61
+ times = get_times(results, levels)
62
+ puts "\tShortest time:\t#{times.shift} msecs"
63
+ levels.each_with_index do |num, index|
64
+ percent = num.to_f * 100.0
65
+ puts "\t#{percent}%ile time:\t#{times[index]} msecs"
66
+ end
67
+ puts "\tLongest time:\t#{times[-1]} msecs"
68
+ end
69
+
70
+ def get_times(results, levels)
71
+ times = Array.new
72
+ times.push(make_milli(results[0]))
73
+ levels.each do |num|
74
+ times.push(make_milli(results[(results.length*num - 1).round]))
75
+ end
76
+ unless times.last == make_milli(results.last)
77
+ times.push(make_milli(results.last))
78
+ end
79
+ times
80
+ end
81
+
82
+ def make_milli(num)
83
+ (num * 1000).to_i
84
+ end
85
+
86
+ def report_header
87
+ print <<EOF
88
+ Concurrency Level: #{@max_threads}
89
+ Total Requests: #{@max_runs}
90
+ Total time for testing: #{@total_time} secs
91
+ Requests per second: #{@max_runs/@total_time}
92
+ Mean time per request: #{results_mean} msecs
93
+ Standard deviation: #{results_std_dev}
94
+ EOF
95
+ end
96
+
97
+
98
+
99
+ end
100
+ end
@@ -0,0 +1,164 @@
1
+ module RWB
2
+
3
+ class Result
4
+ attr_reader :id, :timestamp, :url
5
+ attr_reader :elapsed_time, :response_code
6
+
7
+ def initialize(id, timestamp, url, elapsed_time, response_code)
8
+ @id = id
9
+ @timestamp = timestamp
10
+ @url = url
11
+ @elapsed_time = elapsed_time
12
+ @response_code = response_code
13
+ end
14
+ end
15
+
16
+ class RunResults
17
+ attr_reader :results
18
+
19
+ def initialize
20
+ @results = Array.new
21
+ end
22
+
23
+ def add_result(result)
24
+ @results.push(result)
25
+ end
26
+
27
+ def each_by_response_code(code)
28
+ @results.each do |result|
29
+ yield result if result.response_code.to_i == code.to_i
30
+ end
31
+ end
32
+
33
+ def all_by_response_code(code)
34
+ coded_results = Array.new
35
+ @results.each do |result|
36
+ if result.response_code.to_i == code.to_i
37
+ coded_results.push(result)
38
+ end
39
+ end
40
+ coded_results
41
+ end
42
+
43
+ def all_by_url(url)
44
+ coded_results = Array.new
45
+ @results.each do |result|
46
+ if result.url.to_s == url.to_s
47
+ coded_results.push(result)
48
+ end
49
+ end
50
+ coded_results
51
+ end
52
+
53
+ def each_by_url(url)
54
+ @results.each do |result|
55
+ yield result if result.url.to_s == url.to_s
56
+ end
57
+ end
58
+
59
+ def all_with_id
60
+ id_results = Hash.new
61
+ @results.each do |result|
62
+ id_results[result.id] = result
63
+ end
64
+ id_results
65
+ end
66
+
67
+ def times_by_url(url = nil)
68
+ coded_results = Array.new
69
+ @results.each do |result|
70
+ if url
71
+ if result.url.to_s == url.to_s
72
+ coded_results.push(result.elapsed_time)
73
+ end
74
+ else
75
+ coded_results.push(result.elapsed_time)
76
+ end
77
+ end
78
+ coded_results
79
+ end
80
+
81
+ end
82
+
83
+ class Runner
84
+ def results_mean
85
+ if @results_mean
86
+ return @results_mean
87
+ end
88
+ @results_mean = @new_results.times_by_url.inject(0) do |sum, time|
89
+ sum += time
90
+ end
91
+ @results_mean = @results_mean/@new_results.times_by_url.length
92
+ make_milli(@results_mean)
93
+ end
94
+
95
+ def results_std_dev
96
+ if @results_std_dev
97
+ return @results_std_dev
98
+ end
99
+ unless @results_mean
100
+ results_mean
101
+ end
102
+ @results_std_dev = @new_results.times_by_url.inject(0) do |std_dev, time|
103
+ std_dev += (time - @results_mean) ** 2
104
+ end
105
+ @results_std_dev =
106
+ Math.sqrt(@results_std_dev/@new_results.times_by_url.length)
107
+ make_milli(@results_std_dev)
108
+ end
109
+
110
+ def adjust_scale(scale, max)
111
+ if scale/2 > max
112
+ scale = scale/2
113
+ scale = adjust_scale(scale, max)
114
+ end
115
+ scale
116
+ end
117
+
118
+ def results_quartile(times, scale = nil)
119
+ times = times.map { |t| make_milli(t) }
120
+ size = results_mean + results_std_dev * 2
121
+ min = times[0]
122
+ first = times[(times.length*0.25).to_int - 1]
123
+ second = times[(times.length*0.5).to_int - 1]
124
+ third = times[(times.length*0.75).to_int - 1]
125
+ max = times[-1]
126
+
127
+ len = max.to_s.length
128
+ unless scale
129
+ scale = (max/((10**len).to_f)).ceil * (10**len)
130
+ scale = adjust_scale(scale, max)
131
+ end
132
+ step = scale/50
133
+ step = 1 if step == 0
134
+ scale = 50 if scale < 50
135
+ line = Array.new
136
+ char = ' '
137
+ for i in 0..49 do
138
+ case i
139
+ when max/step
140
+ line[i] = ']'
141
+ when third/step
142
+ line[i] = '|'
143
+ char = ' '
144
+ when second/step
145
+ line[i] = '+'
146
+ when first/step
147
+ line[i] = '|'
148
+ char = '-'
149
+ when min/step
150
+ line[i] = '['
151
+ when 0
152
+ line[i] = ':'
153
+ when 49
154
+ line[i] = ':'
155
+ else
156
+ line[i] = char
157
+ end
158
+ end
159
+ return '0' + line.join('') + scale.to_s
160
+ end
161
+ end
162
+
163
+
164
+ end
@@ -0,0 +1,126 @@
1
+ module RWB
2
+
3
+ #
4
+ # The Url class holds individual URLs for testing. +Url+s are defined by a
5
+ # Fixnum representing the weight and a String representing the URL itself.
6
+ # The weights are not required to be percentages.
7
+ #
8
+ # url = RWB::Url.new(20, "http://www.example.com")
9
+ class Url
10
+ attr_reader :weight, :method
11
+
12
+ def initialize(weight, url, method='GET')
13
+ @weight = weight
14
+ @url = url
15
+ @method = read_method(method)
16
+ end
17
+
18
+ def read_method(method = 'GET')
19
+ method = method.to_s.upcase
20
+ if method != 'GET' && method != 'POST'
21
+ return 'GET'
22
+ else
23
+ return method
24
+ end
25
+ end
26
+
27
+ # to_url returns the URL to be requested as a string
28
+ #
29
+ # url.to_url # => "http://www.example.com"
30
+ def to_url
31
+ @url
32
+ end
33
+
34
+ #
35
+ # to_base returns a string suitable for creating a +Regexp+ to match
36
+ # against.
37
+ #
38
+ # url.to_base # => "http://www.example.com "
39
+ #
40
+ def to_base
41
+ @url
42
+ end
43
+
44
+ def to_s
45
+ @weight.to_s + " " + @url
46
+ end
47
+ end
48
+
49
+ #
50
+ # A UrlGroup is a collection of related URLs, for example the URL for a
51
+ # search tool, with several search queries. The group is weighted (and
52
+ # reported on) as a whole, but individual requests are made with random
53
+ # elements from an array of extensions.
54
+ #
55
+ # urls = UrlGroup.new(20, "http://www.example.com/search?",
56
+ # ["foo", "bar", "baz"])
57
+ #
58
+ class UrlGroup < RWB::Url
59
+
60
+ def initialize(weight, base, extension_array, method='GET')
61
+ @weight = weight.to_i
62
+ @base = base.to_s
63
+ @extension_array = extension_array
64
+ @method = read_method(method)
65
+ end
66
+
67
+
68
+ #
69
+ # to_url returns a complete URL to be requested. It takes an optional
70
+ # seed argument, which must be a Fixnum. If given, this will seed the
71
+ # random selection of the extension.
72
+ #
73
+ # urls.to_url(1234) # => "http://www.example.com/search?baz"
74
+ #
75
+ def to_url(seed = nil)
76
+ if seed
77
+ srand = seed
78
+ end
79
+ @base + @extension_array[rand(@extension_array.length)]
80
+ end
81
+
82
+ #
83
+ # to_base returns a String suitable for building a Regex to match
84
+ # against. This String will not include any extensions.
85
+ #
86
+ # urls.to_base # => "http://www.example.com/search?"
87
+ #
88
+ def to_base
89
+ @base
90
+ end
91
+
92
+ def to_s
93
+ @weight.to_s + " " + @base
94
+ end
95
+
96
+ end
97
+
98
+
99
+ class UrlSession < RWB::Url
100
+ def initialize(weight, session, name, method='GET')
101
+ @weight = weight
102
+ @session = session
103
+ @urls = []
104
+ @name = name
105
+ @method = read_method(method)
106
+ end
107
+
108
+ def to_url
109
+ if @urls == []
110
+ @urls << @session
111
+ @urls.flatten!
112
+ end
113
+ @urls.shift
114
+ end
115
+
116
+ def to_base
117
+ @name
118
+ end
119
+
120
+ def to_s
121
+ @weight.to_s + " " + @name
122
+ end
123
+ end
124
+
125
+
126
+ end
@@ -0,0 +1,48 @@
1
+ module RWB
2
+
3
+ class Runner
4
+ def warmup(num_runs = 1)
5
+ $stderr.puts "warming up with #{num_runs} runs"
6
+ for run in 1..num_runs
7
+ $stderr.print "#{run} "
8
+ @urls.urls.values.each do |url|
9
+ url = URI.parse(url.to_url)
10
+ @http.start(url.host, url.port) do |http|
11
+ http.request( Net::HTTP::Get.new(url) )
12
+ end
13
+ end
14
+ end
15
+ $stderr.puts
16
+ end
17
+
18
+ def rand_warmup(num_requests)
19
+ $stderr.puts "warming up with #{num_requests} requests"
20
+ checkpoint = num_requests/10
21
+ for run in 1..num_requests
22
+ if run % checkpoint == 0
23
+ $stderr.print "#{run} "
24
+ end
25
+ url = URI.parse(@urls.get_url.to_url)
26
+ @http.start(url.host, url.port) do |http|
27
+ http.request( Net::HTTP::Get.new(url) )
28
+ end
29
+ end
30
+ $stderr.puts
31
+ end
32
+
33
+ def spec_warmup(urls, num_runs=1)
34
+ $stderr.puts "warming up with #{num_runs} runs"
35
+ for run in 1..num_runs
36
+ $stderr.print "#{run} "
37
+ urls.each do |url|
38
+ url = URI.parse(url)
39
+ @http.start(url.host, url.port) do |http|
40
+ http.request( Net::HTTP::Get.new(url) )
41
+ end
42
+ end
43
+ end
44
+ $stderr.puts
45
+ end
46
+
47
+ end
48
+ end
metadata CHANGED
@@ -3,8 +3,8 @@ rubygems_version: 0.8.11
3
3
  specification_version: 1
4
4
  name: rwb
5
5
  version: !ruby/object:Gem::Version
6
- version: 0.2.2
7
- date: 2007-01-31 00:00:00 -07:00
6
+ version: 0.2.3
7
+ date: 2007-02-01 00:00:00 -07:00
8
8
  summary: Ruby Web Bench, a web performance and load testing framework
9
9
  require_paths:
10
10
  - lib
@@ -28,11 +28,17 @@ cert_chain:
28
28
  authors:
29
29
  - Pat Eyler
30
30
  files:
31
+ - test/test_rwb.rb
32
+ - lib/rwb
33
+ - lib/rwb.rb
34
+ - lib/rwb/warmup.rb
35
+ - lib/rwb/report.rb
36
+ - lib/rwb/url.rb
37
+ - lib/rwb/results.rb
31
38
  - NEWS
32
39
  - README
33
40
  - TODO
34
- - lib/rwb.rb
35
- - test/test_rwb.rb
41
+ - Rakefile
36
42
  test_files: []
37
43
 
38
44
  rdoc_options: []