rwb 0.2.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (6) hide show
  1. data/NEWS +29 -0
  2. data/README +75 -0
  3. data/TODO +15 -0
  4. data/lib/rwb.rb +493 -0
  5. data/test/test_rwb.rb +362 -0
  6. metadata +41 -0
data/NEWS ADDED
@@ -0,0 +1,29 @@
1
+ version 0.2.1
2
+ + added quartile graphs by url or overall
3
+ + added more information to response objects
4
+ + released as a gem w00t!
5
+
6
+ Version 0.2.0
7
+ + added proxy handling throughout
8
+
9
+ Version 0.1.1
10
+ Changes in this version:
11
+ + added three kinds of warmup methods
12
+
13
+ Version 0.1.0
14
+ Changes in this version:
15
+ + starting to add documentation
16
+ + added more granular control over reporting levels
17
+ + fixed standard deviation
18
+
19
+
20
+ Version 0.0.1
21
+ Changes in this version:
22
+ + made reporting more modular
23
+ + added reporting based on slices of the results
24
+ + added standard deviation for mean time per request
25
+ + fixed standard deviation
26
+
27
+ Version 0.0.0
28
+ Changes in this version:
29
+ + Initial Release
data/README ADDED
@@ -0,0 +1,75 @@
1
+ RWB, the Ruby Web Bench, provides a simple way to manage a performance and
2
+ load tests suite for your webserver. Unlike ab, by which it was inspired, it
3
+ will allow you to build a collection of test URLs with corresponding weights
4
+ which it will use to generate the actual tests that it runs (and reports on).
5
+
6
+ RWB could be used for:
7
+ - testing your website to ensure that it performs within timing
8
+ requirements
9
+ - testing a new webserver to verify that performance is at least as good
10
+ as your existing server
11
+ - testing a website to verify that it will handle expected load
12
+
13
+ While this is an alpha release, it is already useful. The API is expected to
14
+ change somewhat as functionality is added and the design is adjusted.
15
+ Reporting by error type, serializing of results, cookie handling, POST
16
+ requests, and set_up methods are some of the planned additions before rwb
17
+ hits a beta release.
18
+
19
+ A sample RWB script for testing a website looks like this (for more
20
+ information, see the file USING):
21
+
22
+ #!/usr/bin/env ruby
23
+
24
+ require 'rwb'
25
+
26
+ urls = RWB::Builder.new()
27
+
28
+ urls.add_url(10, "http://www.example.com")
29
+ urls.add_url(10, "http://www.example.com/nonesuch")
30
+ urls.add_url(70, "http://www.example.com/entries")
31
+
32
+ queries = ['foo+bar', 'bar+baz', 'quux']
33
+ urls.add_url_group(10, "http://www.example.com:3000/search?", queries)
34
+
35
+ tests = RWB::Runner.new(urls, 100, 20)
36
+ tests.report_header
37
+ tests.report_overall
38
+ tests.graph_quartiles_urls(1000)
39
+
40
+
41
+
42
+ The output from this script looks like this:
43
+ $ ruby -Ilib quick.rb
44
+ completed 10 runs
45
+ completed 20 runs
46
+ completed 30 runs
47
+ completed 40 runs
48
+ completed 50 runs
49
+ completed 60 runs
50
+ completed 70 runs
51
+ completed 80 runs
52
+ completed 90 runs
53
+ completed 100 runs
54
+ Concurrency Level: 20
55
+ Total Requests: 100
56
+ Total time for testing: 2.021048 secs
57
+ Requests per second: 49.4792800566835
58
+ Mean time per request: 236 msecs
59
+ Standard deviation: 342
60
+ Overall results:
61
+ Shortest time: 30 msecs
62
+ 25.0%ile time: 74 msecs
63
+ 50.0%ile time: 98 msecs
64
+ 75.0%ile time: 185 msecs
65
+ Longest time: 1281 msecs
66
+ http://localhost:
67
+ 0: +-| :1000
68
+ http://localhost/nonesuch:
69
+ 0: [|+----| :1000
70
+ http://localhost/entries:
71
+ 0:[ |+--| :1000
72
+ http://localhost:3000/search?:
73
+ 0: |------+--------------------------------------:1000
74
+
75
+ (Additional examples of use can be seen at www.red-bean.com/~pate/
data/TODO ADDED
@@ -0,0 +1,15 @@
1
+ Enhance docs & tests (in progress)
2
+
3
+ Figure out and implement cookie handling
4
+
5
+ Add POST capabilities
6
+
7
+ Enhance reporting to use expanded info in Response Objects (in progress)
8
+
9
+ Migrate to a DSL
10
+
11
+ (maybe) Add html output
12
+
13
+ (maybe) Add PDF output
14
+
15
+
@@ -0,0 +1,493 @@
1
+ require 'net/http'
2
+ require 'uri'
3
+
4
+ module RWB
5
+
6
+ #
7
+ # The Url class holds individual URLs for testing. +Url+s are defined by a
8
+ # Fixnum representing the weight and a String representing the URL itself.
9
+ # The weights are not required to be percentages.
10
+ #
11
+ # url = RWB::Url.new(20, "http://www.example.com")
12
+ class Url
13
+ attr_reader :weight
14
+
15
+ def initialize(weight, url)
16
+ @weight = weight
17
+ @url = url
18
+ end
19
+
20
+ # to_url returns the URL to be requested as a string
21
+ #
22
+ # url.to_url # => "http://www.example.com"
23
+ def to_url
24
+ @url
25
+ end
26
+
27
+ #
28
+ # to_base returns a string suitable for creating a +Regexp+ to match
29
+ # against.
30
+ #
31
+ # url.to_base # => "http://www.example.com "
32
+ #
33
+ def to_base
34
+ @url
35
+ end
36
+
37
+ def to_s
38
+ @weight + " " + @url
39
+ end
40
+ end
41
+
42
+ #
43
+ # A UrlGroup is a collection of related URLs, for example the URL for a
44
+ # search tool, with several search queries. The group is weighted (and
45
+ # reported on) as a whole, but individual requests are made with random
46
+ # elements from an array of extensions.
47
+ #
48
+ # urls = UrlGroup.new(20, "http://www.example.com/search?",
49
+ # ["foo", "bar", "baz"])
50
+ #
51
+ class UrlGroup
52
+ attr_reader :weight
53
+
54
+ def initialize(weight, base, extension_array)
55
+ @weight = weight.to_i
56
+ @base = base.to_s
57
+ @extension_array = extension_array
58
+ end
59
+
60
+ #
61
+ # to_url returns a complete URL to be requested. It takes an optional
62
+ # seed argument, which must be a Fixnum. If given, this will seed the
63
+ # random selection of the extension.
64
+ #
65
+ # urls.to_url(1234) # => "http://www.example.com/search?baz"
66
+ #
67
+ def to_url(seed = nil)
68
+ if seed
69
+ srand = seed
70
+ end
71
+ @base + @extension_array[rand(@extension_array.length)]
72
+ end
73
+
74
+ #
75
+ # to_base returns a String suitable for building a Regex to match
76
+ # against. This String will not include any extensions.
77
+ #
78
+ # urls.to_base # => "http://www.example.com/search?"
79
+ #
80
+ def to_base
81
+ @base
82
+ end
83
+
84
+ def to_s
85
+ @weight + " " + @base
86
+ end
87
+
88
+ end
89
+
90
+ class Result
91
+ attr_reader :id, :timestamp, :url
92
+ attr_reader :elapsed_time, :response_code
93
+
94
+ def initialize(id, timestamp, url, elapsed_time, response_code)
95
+ @id = id
96
+ @timestamp = timestamp
97
+ @url = url
98
+ @elapsed_time = elapsed_time
99
+ @response_code = response_code
100
+ end
101
+ end
102
+
103
+ class RunResults
104
+ attr_reader :results
105
+
106
+ def initialize
107
+ @results = Array.new
108
+ end
109
+
110
+ def add_result(result)
111
+ @results.push(result)
112
+ end
113
+
114
+ def each_by_response_code(code)
115
+ @results.each do |result|
116
+ yield result if result.response_code.to_i == code.to_i
117
+ end
118
+ end
119
+
120
+ def all_by_response_code(code)
121
+ coded_results = Array.new
122
+ @results.each do |result|
123
+ if result.response_code.to_i == code.to_i
124
+ coded_results.push(result)
125
+ end
126
+ end
127
+ coded_results
128
+ end
129
+
130
+ def all_by_url(url)
131
+ coded_results = Array.new
132
+ @results.each do |result|
133
+ if result.url.to_s == url.to_s
134
+ coded_results.push(result)
135
+ end
136
+ end
137
+ coded_results
138
+ end
139
+
140
+ def each_by_url(url)
141
+ @results.each do |result|
142
+ yield result if result.url.to_s == url.to_s
143
+ end
144
+ end
145
+
146
+ def all_with_id
147
+ id_results = Hash.new
148
+ @results.each do |result|
149
+ id_results[result.id] = result
150
+ end
151
+ id_results
152
+ end
153
+
154
+ def times_by_url(url = nil)
155
+ coded_results = Array.new
156
+ @results.each do |result|
157
+ if url
158
+ if result.url.to_s == url.to_s
159
+ coded_results.push(result.elapsed_time)
160
+ end
161
+ else
162
+ coded_results.push(result.elapsed_time)
163
+ end
164
+ end
165
+ coded_results
166
+ end
167
+
168
+ end
169
+
170
+ class Builder
171
+ attr_reader :urls, :total_weight
172
+
173
+ def initialize(testhash = nil)
174
+ @urls = Hash.new
175
+ @total_weight = 0
176
+ if testhash
177
+ build_urls(testhash)
178
+ end
179
+ end
180
+
181
+ def add_url(weight, url)
182
+ @total_weight += weight.to_i
183
+ @urls[@total_weight] = Url.new(weight, url)
184
+ end
185
+
186
+ def add_url_group(weight, base, extension_array)
187
+ @total_weight += weight.to_i
188
+ @urls[@total_weight] = UrlGroup.new(weight, base, extension_array)
189
+ end
190
+
191
+ def get_url(seed = nil)
192
+ if seed
193
+ srand seed
194
+ end
195
+ pick = rand(@total_weight)
196
+ @urls.keys.sort.each do |key|
197
+ if pick <= key
198
+ return @urls[key]
199
+ end
200
+ end
201
+ end
202
+
203
+ def build_urls(tests)
204
+ tests.keys.each do |key|
205
+ add_url(tests[key], key)
206
+ end
207
+ end
208
+ end
209
+
210
+ class Runner
211
+ attr_accessor :sla_levels
212
+
213
+ def initialize(urls, max_runs=100, max_threads=10)
214
+ @urls = urls
215
+ @current_runs = 0
216
+ @current_threads = 0
217
+ @max_runs = max_runs
218
+ @max_threads = max_threads
219
+ @threads = []
220
+ @results_mean = nil
221
+ @results_std_dev = nil
222
+ @sla_levels = [0.5, 0.9]
223
+ @http = Net::HTTP
224
+ @new_results = RunResults.new
225
+ end
226
+
227
+ def add_proxy(proxy_addr, proxy_port = 80, proxy_user = nil,
228
+ proxy_pass = nil)
229
+ @http = Net::HTTP::Proxy(proxy_addr, proxy_port, proxy_user,
230
+ proxy_pass)
231
+ end
232
+
233
+ def warmup(num_runs = 1)
234
+ $stderr.puts "warming up with #{num_runs} runs"
235
+ for run in 1..num_runs
236
+ $stderr.print "#{run} "
237
+ @urls.urls.values.each do |url|
238
+ url = URI.parse(url.to_url)
239
+ @http.start(url.host, url.port) do |http|
240
+ http.request( Net::HTTP::Get.new(url) )
241
+ end
242
+ end
243
+ end
244
+ $stderr.puts
245
+ end
246
+
247
+ def rand_warmup(num_requests)
248
+ $stderr.puts "warming up with #{num_requests} requests"
249
+ checkpoint = num_requests/10
250
+ for run in 1..num_requests
251
+ if run % checkpoint == 0
252
+ $stderr.print "#{run} "
253
+ end
254
+ url = URI.parse(@urls.get_url.to_url)
255
+ @http.start(url.host, url.port) do |http|
256
+ http.request( Net::HTTP::Get.new(url) )
257
+ end
258
+ end
259
+ $stderr.puts
260
+ end
261
+
262
+ def spec_warmup(urls, num_runs=1)
263
+ $stderr.puts "warming up with #{num_runs} runs"
264
+ for run in 1..num_runs
265
+ $stderr.print "#{run} "
266
+ urls.each do |url|
267
+ url = URI.parse(url)
268
+ @http.start(url.host, url.port) do |http|
269
+ http.request( Net::HTTP::Get.new(url) )
270
+ end
271
+ end
272
+ end
273
+ $stderr.puts
274
+ end
275
+
276
+ def run
277
+ printed_runs = Array.new
278
+ total_start_time = Time.now
279
+ checkpoint = @max_runs/10
280
+ while @current_runs < @max_runs
281
+ build_thread
282
+ if @current_runs % checkpoint == 0 &&
283
+ ! ( printed_runs.include?(@current_runs))
284
+ $stderr.puts "completed #{@current_runs} runs"
285
+ printed_runs.push(@current_runs)
286
+ end
287
+ end
288
+
289
+ @threads.each { |th| th.join }
290
+
291
+ total_stop_time = Time.now
292
+ @total_time = total_stop_time - total_start_time
293
+ end
294
+
295
+ def results_mean
296
+ if @results_mean
297
+ return @results_mean
298
+ end
299
+ @results_mean = @new_results.times_by_url.inject(0) do |sum, time|
300
+ sum += time
301
+ end
302
+ @results_mean = @results_mean/@new_results.times_by_url.length
303
+ make_milli(@results_mean)
304
+ end
305
+
306
+ def results_std_dev
307
+ if @results_std_dev
308
+ return @results_std_dev
309
+ end
310
+ unless @results_mean
311
+ results_mean
312
+ end
313
+ @results_std_dev = @new_results.times_by_url.inject(0) do |std_dev, time|
314
+ std_dev += (time - @results_mean) ** 2
315
+ end
316
+ @results_std_dev =
317
+ Math.sqrt(@results_std_dev/@new_results.times_by_url.length)
318
+ make_milli(@results_std_dev)
319
+ end
320
+
321
+ def adjust_scale(scale, max)
322
+ if scale/2 > max
323
+ scale = scale/2
324
+ scale = adjust_scale(scale, max)
325
+ end
326
+ scale
327
+ end
328
+
329
+ def results_quartile(times, scale = nil)
330
+ times = times.map { |t| make_milli(t) }
331
+ size = results_mean + results_std_dev * 2
332
+ min = times[0]
333
+ first = times[(times.length*0.25).to_int - 1]
334
+ second = times[(times.length*0.5).to_int - 1]
335
+ third = times[(times.length*0.75).to_int - 1]
336
+ max = times[-1]
337
+
338
+ len = max.to_s.length
339
+ unless scale
340
+ scale = (max/((10**len).to_f)).ceil * (10**len)
341
+ scale = adjust_scale(scale, max)
342
+ end
343
+ step = scale/50
344
+ step = 1 if step == 0
345
+ scale = 50 if scale < 50
346
+ line = Array.new
347
+ char = ' '
348
+ for i in 0..49 do
349
+ case i
350
+ when max/step
351
+ line[i] = ']'
352
+ when third/step
353
+ line[i] = '|'
354
+ char = ' '
355
+ when second/step
356
+ line[i] = '+'
357
+ when first/step
358
+ line[i] = '|'
359
+ char = '-'
360
+ when min/step
361
+ line[i] = '['
362
+ when 0
363
+ line[i] = ':'
364
+ when 49
365
+ line[i] = ':'
366
+ else
367
+ line[i] = char
368
+ end
369
+ end
370
+ return '0' + line.join('') + scale.to_s
371
+ end
372
+
373
+ def report_full(sla_levels = @sla_levels)
374
+ report_header
375
+ report_overall(sla_levels)
376
+ report_urls(sla_levels)
377
+ report_by_time(sla_levels)
378
+ end
379
+
380
+ def report_overall(sla_levels = @sla_levels)
381
+ results = @new_results.times_by_url
382
+
383
+ puts "Overall results:"
384
+ print_times(results.sort, sla_levels)
385
+ end
386
+
387
+ def report_urls(sla_levels = @sla_levels)
388
+ @urls.urls.keys.sort.each do |key|
389
+ url = @urls.urls[key].to_base
390
+ results = @new_results.times_by_url(url)
391
+ puts "Results for #{url}:"
392
+ if results.length > 0
393
+ print_times(results.sort, sla_levels)
394
+ else
395
+ puts "no results for url"
396
+ end
397
+ end
398
+ end
399
+
400
+ def graph_quartiles_urls(scale = nil)
401
+ @urls.urls.keys.sort.each do |key|
402
+ url = @urls.urls[key].to_base
403
+ results = @new_results.times_by_url(url)
404
+ puts "#{url}:\n\t" + results_quartile(results.sort, scale)
405
+ end
406
+ end
407
+
408
+ def graph_quartiles_overall
409
+ results = @new_results.times_by_url
410
+ puts results_quartile(results.sort)
411
+ end
412
+
413
+ def report_by_time(sla_levels = @sla_levels, granularity = 0.2)
414
+ start = 0.0
415
+ stop = granularity
416
+ results = @new_results.times_by_url
417
+ puts "Results by time:"
418
+ while stop <= 1.0
419
+ first = (results.length * start).to_i
420
+ last = (results.length * stop).to_i
421
+ these_results = results.slice(first..last)
422
+ puts "results for requests #{first} - #{last}"
423
+ print_times(these_results.sort, sla_levels)
424
+ start = stop
425
+ stop += granularity
426
+ end
427
+ end
428
+
429
+ def print_times(results, levels)
430
+ times = get_times(results, levels)
431
+ puts "\tShortest time:\t#{times.shift} msecs"
432
+ levels.each_with_index do |num, index|
433
+ percent = num.to_f * 100.0
434
+ puts "\t#{percent}%ile time:\t#{times[index]} msecs"
435
+ end
436
+ puts "\tLongest time:\t#{times[-1]} msecs"
437
+ end
438
+
439
+ def get_times(results, levels)
440
+ times = Array.new
441
+ times.push(make_milli(results[0]))
442
+ levels.each do |num|
443
+ times.push(make_milli(results[(results.length*num).to_i]))
444
+ end
445
+ times.push(make_milli(results[-1]))
446
+ end
447
+
448
+ def make_milli(num)
449
+ (num * 1000).to_i
450
+ end
451
+
452
+ def report_header
453
+ print <<EOF
454
+ Concurrency Level: #{@max_threads}
455
+ Total Requests: #{@max_runs}
456
+ Total time for testing: #{@total_time} secs
457
+ Requests per second: #{@max_runs/@total_time}
458
+ Mean time per request: #{results_mean} msecs
459
+ Standard deviation: #{results_std_dev}
460
+ EOF
461
+ end
462
+
463
+ def build_thread
464
+ if @current_threads < @max_threads
465
+ @current_runs += 1
466
+ @threads << Thread.new { run_test(@current_runs)}
467
+ @current_threads += 1
468
+ end
469
+ end
470
+
471
+ def run_test(id)
472
+ request = @urls.get_url
473
+ url = URI.parse request.to_url
474
+ base = request.to_base
475
+ start_time = Time.now
476
+ response_code = nil
477
+
478
+ @http.start(url.host, url.port) do |http|
479
+ response = http.request( Net::HTTP::Get.new(url) )
480
+ response_code = response.code
481
+ end
482
+
483
+ stop_time = Time.now
484
+ time = stop_time - start_time
485
+
486
+ result = Result.new(id, Time.now, base, time, response_code)
487
+
488
+ @new_results.add_result(result)
489
+ @current_threads -= 1
490
+ end
491
+ end
492
+
493
+ end
@@ -0,0 +1,362 @@
1
+ require 'test/unit' unless defined? $ZENTEST and $ZENTEST
2
+ require 'rwb'
3
+
4
+ module RWB
5
+ class Runner
6
+ attr_writer :results_mean, :results_std_dev
7
+ end
8
+ end
9
+
10
+
11
+ module TestRWB
12
+ class TestBuilder < Test::Unit::TestCase
13
+ def setup
14
+ @urls = RWB::Builder.new
15
+ end
16
+
17
+ def test_add_url
18
+ @urls.add_url(20, "http://localhost")
19
+ assert_equal(1, @urls.urls.length)
20
+ assert_equal("http://localhost", @urls.get_url.to_url)
21
+ end
22
+
23
+ def test_add_url_group
24
+ @urls.add_url_group(20, "http://localhost/search?", ['foo', 'bar'])
25
+ assert_equal(1, @urls.urls.length)
26
+ assert_instance_of(RWB::UrlGroup, @urls.get_url)
27
+ assert_equal(20, @urls.get_url.weight)
28
+ end
29
+
30
+ def test_build_urls
31
+ config = {
32
+ "http://localhost" => 20,
33
+ "http://localhost/nonesuch" => 20}
34
+ @urls.build_urls(config)
35
+ assert_equal(2, @urls.urls.length)
36
+ end
37
+
38
+ def test_get_url
39
+ @urls.add_url(20, "http://localhost")
40
+ assert_equal("http://localhost", @urls.get_url.to_url)
41
+ @urls.add_url(20, "http://localhost/foo")
42
+ assert_equal("http://localhost", @urls.get_url(1).to_url)
43
+ assert_equal("http://localhost", @urls.get_url(2).to_url)
44
+ assert_equal("http://localhost/foo", @urls.get_url(3).to_url)
45
+ end
46
+
47
+ def test_total_weight
48
+ @urls.add_url(20, "http://localhost")
49
+ assert_equal(20, @urls.total_weight)
50
+ @urls.add_url(20, "http://localhost/foo")
51
+ assert_equal(40, @urls.total_weight)
52
+ end
53
+
54
+ def test_urls
55
+ @urls.add_url(20, "http://localhost")
56
+ @urls.add_url(20, "http://localhost/foo")
57
+ assert_instance_of(Hash, @urls.urls)
58
+ assert_instance_of(RWB::Url, @urls.urls[20])
59
+ assert_equal([40, 20], @urls.urls.keys)
60
+ end
61
+ end
62
+
63
+ class TestRunner < Test::Unit::TestCase
64
+ def test_build_thread
65
+ #raise NotImplementedError, 'Need to write test_build_thread'
66
+ end
67
+
68
+ def test_get_times
69
+ #raise NotImplementedError, 'Need to write test_get_times'
70
+ end
71
+
72
+ def test_make_milli
73
+ tests = RWB::Runner.new(nil)
74
+ assert_equal(23, tests.make_milli(0.023))
75
+ end
76
+
77
+
78
+ def test_results_quartile
79
+ times = [0.011, 0.134, 0.199, 0.212, 0.236, 0.275,
80
+ 0.351, 0.401, 0.479, 0.603, 0.758, 0.978]
81
+ quartile_graph =
82
+ "0[ |---+---------| ]:1000"
83
+ test = RWB::Runner.new(nil)
84
+ test.results_mean = 450
85
+ test.results_std_dev = 200
86
+ assert_equal(quartile_graph, test.results_quartile(times))
87
+ end
88
+
89
+ def test_results_quartile_half_step
90
+ times = [0.011, 0.134, 0.199, 0.212, 0.236, 0.275,
91
+ 0.322, 0.351, 0.379, 0.403, 0.458, 0.478]
92
+ quartile_graph =
93
+ "0:[ |-------+---------| ] :500"
94
+ test = RWB::Runner.new(nil)
95
+ test.results_mean = 450
96
+ test.results_std_dev = 200
97
+ assert_equal(quartile_graph, test.results_quartile(times))
98
+ end
99
+
100
+ def test_results_quartile_mid_values
101
+ times = [0.011, 0.013, 0.019, 0.021, 0.023, 0.027,
102
+ 0.035, 0.040, 0.047, 0.060, 0.075, 0.085]
103
+ quartile_graph =
104
+ "0: [ |---+---------| ] :100"
105
+ test = RWB::Runner.new(nil)
106
+ test.results_mean = 45
107
+ test.results_std_dev = 20
108
+ assert_equal(quartile_graph, test.results_quartile(times))
109
+ end
110
+
111
+ def test_results_quartile_small_values
112
+ times = [0.001, 0.002, 0.003,0.004,0.005,0.006,
113
+ 0.007,0.008,0.009]
114
+ quartile_graph =
115
+ "0:[|-+-| ] :50"
116
+ test = RWB::Runner.new(nil)
117
+ test.results_mean = 4
118
+ test.results_std_dev = 2
119
+ assert_equal(quartile_graph, test.results_quartile(times))
120
+ end
121
+
122
+ def test_results_quartile_set_scale
123
+ times = [0.001, 0.002, 0.003,0.004,0.005,0.006,
124
+ 0.007,0.008,0.009]
125
+ quartile_graph =
126
+ "0] :1000"
127
+ test = RWB::Runner.new(nil)
128
+ test.results_mean = 4
129
+ test.results_std_dev = 2
130
+ assert_equal(quartile_graph, test.results_quartile(times, 1000))
131
+ end
132
+
133
+ def test_adjust_scale
134
+ test = RWB::Runner.new(nil)
135
+ assert_equal(25, test.adjust_scale(100,15))
136
+ assert_equal(50, test.adjust_scale(100,49))
137
+ assert_equal(100, test.adjust_scale(100,75))
138
+ end
139
+
140
+ def test_print_times
141
+ #raise NotImplementedError, 'Need to write test_print_times'
142
+ end
143
+
144
+ def test_report_by_time
145
+ #raise NotImplementedError, 'Need to write test_report_by_time'
146
+ end
147
+
148
+ def test_report_full
149
+ #raise NotImplementedError, 'Need to write test_report_full'
150
+ end
151
+
152
+ def test_report_header
153
+ #raise NotImplementedError, 'Need to write test_report_header'
154
+ end
155
+
156
+ def test_report_overall
157
+ #raise NotImplementedError, 'Need to write test_report_overall'
158
+ end
159
+
160
+ def test_report_urls
161
+ #raise NotImplementedError, 'Need to write test_report_urls'
162
+ end
163
+
164
+ def test_run_test
165
+ # not testing yet ...
166
+ #raise NotImplementedError, 'Need to write test_run_test'
167
+ end
168
+
169
+ end
170
+
171
+ class TestUrl < Test::Unit::TestCase
172
+ def setup
173
+ @url = RWB::Url.new(10, "http://www.example.com")
174
+ end
175
+
176
+ def test_to_base
177
+ assert_equal("http://www.example.com", @url.to_base)
178
+ end
179
+
180
+ def test_to_url
181
+ assert_equal("http://www.example.com", @url.to_url)
182
+ end
183
+
184
+ def test_weight
185
+ assert_equal(10, @url.weight)
186
+ end
187
+ end
188
+
189
+ class TestUrlGroup < Test::Unit::TestCase
190
+ def setup
191
+ queries = ["foo", "bar", "baz"]
192
+ @url = RWB::UrlGroup.new(10, "http://www.example.com/search?", queries)
193
+ end
194
+
195
+ def test_to_base
196
+ assert_equal("http://www.example.com/search?", @url.to_base)
197
+ end
198
+
199
+ def test_to_url
200
+ assert_equal("http://www.example.com/search?foo", @url.to_url(1))
201
+ assert_equal("http://www.example.com/search?baz", @url.to_url(2))
202
+ assert_equal("http://www.example.com/search?baz", @url.to_url(3))
203
+ end
204
+
205
+ def test_weight
206
+ assert_equal(10, @url.weight)
207
+ end
208
+ end
209
+
210
+ class TestResult < Test::Unit::TestCase
211
+ def setup
212
+ @now = Time.now
213
+ @result = RWB::Result.new(1, @now, "http://localhost", 0.234, 200)
214
+ end
215
+
216
+ def test_id
217
+ assert_equal 1, @result.id
218
+ end
219
+
220
+ def test_timestamp
221
+ assert_instance_of(Time, @result.timestamp)
222
+ assert_equal(@now, @result.timestamp)
223
+ end
224
+
225
+ def test_url
226
+ assert_equal("http://localhost", @result.url)
227
+ end
228
+
229
+ def test_elapsed_time
230
+ assert_equal(0.234, @result.elapsed_time)
231
+ end
232
+
233
+ def test_response_code
234
+ assert_equal(200, @result.response_code)
235
+ end
236
+ end
237
+
238
+ class TestRunResults < Test::Unit::TestCase
239
+ def setup
240
+ @results = RWB::RunResults.new
241
+ @now = Time.now
242
+ @result = RWB::Result.new(1, @now, "http://localhost", 0.234, 200)
243
+ end
244
+
245
+ def test_results
246
+ assert_instance_of(Array, @results.results)
247
+ assert_equal(0, @results.results.length)
248
+ end
249
+
250
+ def test_add_result
251
+ @results.add_result(@result)
252
+ assert_equal(1, @results.results.length)
253
+ assert_instance_of(RWB::Result, @results.results[0])
254
+ end
255
+
256
+ def test_all_by_response_code
257
+ @results.add_result(@result)
258
+ assert_instance_of(Array, @results.all_by_response_code(200))
259
+ assert_equal(1, @results.all_by_response_code(200).length)
260
+ assert_equal(0, @results.all_by_response_code(404).length)
261
+ result = RWB::Result.new(2, Time.now,
262
+ "http://localhost/nonesuch",
263
+ 0.118, 404)
264
+ @results.add_result(result)
265
+ third = RWB::Result.new(3, Time.now,
266
+ "http://localhost",
267
+ 0.118, 200)
268
+ @results.add_result(third)
269
+ assert_equal(2, @results.all_by_response_code(200).length)
270
+ assert_equal(1, @results.all_by_response_code(404).length)
271
+ end
272
+
273
+ def test_each_by_response_code
274
+ @results.add_result(@result)
275
+ result = RWB::Result.new(2, Time.now,
276
+ "http://localhost/nonesuch",
277
+ 0.118, 404)
278
+ @results.add_result(result)
279
+ third = RWB::Result.new(3, Time.now,
280
+ "http://localhost",
281
+ 0.118, 200)
282
+ @results.add_result(third)
283
+ @results.each_by_response_code(200) do |result|
284
+ assert_equal(200, result.response_code)
285
+ end
286
+
287
+ @results.each_by_response_code(404) do |result|
288
+ assert_equal(404, result.response_code)
289
+ end
290
+ end
291
+
292
+ def test_all_by_url
293
+ @results.add_result(@result)
294
+ assert_instance_of(Array, @results.all_by_url("http://localhost"))
295
+ assert_equal(1, @results.all_by_url("http://localhost").length)
296
+ result = RWB::Result.new(2, Time.now,
297
+ "http://localhost/nonesuch",
298
+ 0.118, 404)
299
+ @results.add_result(result)
300
+ third = RWB::Result.new(3, Time.now,
301
+ "http://localhost",
302
+ 0.118, 200)
303
+ @results.add_result(third)
304
+ assert_equal(2, @results.all_by_url("http://localhost").length)
305
+ assert_equal(1, @results.all_by_url("http://localhost/nonesuch").length)
306
+ end
307
+
308
+ def test_each_by_url
309
+ @results.add_result(@result)
310
+ result = RWB::Result.new(2, Time.now,
311
+ "http://localhost/nonesuch",
312
+ 0.118, 404)
313
+ @results.add_result(result)
314
+ third = RWB::Result.new(3, Time.now,
315
+ "http://localhost",
316
+ 0.118, 200)
317
+ @results.add_result(third)
318
+ @results.each_by_url("http://localhost") do |result|
319
+ assert_equal("http://localhost", result.url)
320
+ end
321
+
322
+ @results.each_by_url("http://localhost/nonesuch") do |result|
323
+ assert_equal("http://localhost/nonesuch", result.url)
324
+ end
325
+ end
326
+
327
+ def test_all_with_id
328
+ @results.add_result(@result)
329
+ assert_instance_of(Hash, @results.all_with_id)
330
+ assert_equal(1, @results.all_with_id.keys.length)
331
+ result = RWB::Result.new(2, Time.now,
332
+ "http://localhost/nonesuch",
333
+ 0.118, 404)
334
+ @results.add_result(result)
335
+ third = RWB::Result.new(3, Time.now,
336
+ "http://localhost",
337
+ 0.118, 200)
338
+ @results.add_result(third)
339
+ assert_equal([1,2,3], @results.all_with_id.keys)
340
+ end
341
+
342
+ def test_times_by_url
343
+ @results.add_result(@result)
344
+ assert_instance_of(Array, @results.times_by_url("http://localhost"))
345
+ assert_equal(1, @results.times_by_url("http://localhost").length)
346
+ result = RWB::Result.new(2, Time.now,
347
+ "http://localhost/nonesuch",
348
+ 0.118, 404)
349
+ @results.add_result(result)
350
+ third = RWB::Result.new(3, Time.now,
351
+ "http://localhost",
352
+ 0.118, 200)
353
+ @results.add_result(third)
354
+ assert_equal([0.234, 0.118], @results.times_by_url("http://localhost"))
355
+ assert_equal([0.118], @results.times_by_url("http://localhost/nonesuch"))
356
+ assert_equal([0.234, 0.118, 0.118], @results.times_by_url)
357
+ end
358
+
359
+ end
360
+
361
+ end
362
+
metadata ADDED
@@ -0,0 +1,41 @@
1
+ --- !ruby/object:Gem::Specification
2
+ rubygems_version: 0.8.10
3
+ specification_version: 1
4
+ name: rwb
5
+ version: !ruby/object:Gem::Version
6
+ version: 0.2.1
7
+ date: 2005-12-02
8
+ summary: "Ruby Web Bench, a web performance and load testing framework"
9
+ require_paths:
10
+ - lib
11
+ email: pat.eyler@gmail.com
12
+ homepage: http://rubyforge.org/projects/rwb
13
+ rubyforge_project:
14
+ description:
15
+ autorequire: rwb
16
+ default_executable:
17
+ bindir: bin
18
+ has_rdoc: "true"
19
+ required_ruby_version: !ruby/object:Gem::Version::Requirement
20
+ requirements:
21
+ -
22
+ - ">"
23
+ - !ruby/object:Gem::Version
24
+ version: 0.0.0
25
+ version:
26
+ platform: ruby
27
+ authors:
28
+ - Pat Eyler
29
+ files:
30
+ - NEWS
31
+ - README
32
+ - TODO
33
+ - lib/rwb.rb
34
+ - test/test_rwb.rb
35
+ test_files: []
36
+ rdoc_options: []
37
+ extra_rdoc_files: []
38
+ executables: []
39
+ extensions: []
40
+ requirements: []
41
+ dependencies: []