rwb 0.2.1

Sign up to get free protection for your applications and to get access to all the features.
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: []