abcrunch 0.0.4

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.
@@ -0,0 +1,87 @@
1
+ require 'spec_helper'
2
+
3
+ describe "AbCrunch::AbResult" do
4
+ def new_abr(raw_ab_output, ab_options = {})
5
+ AbCrunch::AbResult.new(raw_ab_output, ab_options)
6
+ end
7
+
8
+ describe "#initialize" do
9
+ it "should remember the provided raw ab output and options" do
10
+ abr = new_abr('foo', {:foo => 'bar'})
11
+ abr.raw.should == 'foo'
12
+ abr.ab_options.should == {:foo => 'bar'}
13
+ end
14
+ end
15
+
16
+ describe "#command" do
17
+ it "should return the ab command used to produce the result" do
18
+ ab_options = {:crunch => 'now'}
19
+ mock(AbCrunch::AbRunner).ab_command(ab_options) { 'tight!' }
20
+ abr = new_abr('blah', ab_options)
21
+ abr.command.should == 'tight!'
22
+ end
23
+ end
24
+
25
+ describe "#avg_response_time" do
26
+ it "should glean the average response time from raw ab output and return as a float" do
27
+ abr = new_abr("fleeblesnork\nTime per request: 43.028 [ms] (mean)\n\nblah")
28
+ abr.avg_response_time.should == 43.028
29
+ end
30
+
31
+ describe "when the raw value is an integer" do
32
+ it "should still be returned as a float" do
33
+ abr = new_abr("fleeblesnork\nTime per request: 43 [ms] (mean)\n\nblah")
34
+ abr.avg_response_time.should == 43.0
35
+ abr.avg_response_time.class.to_s.should == 'Float'
36
+ end
37
+ end
38
+ end
39
+
40
+ describe "#queries_per_second" do
41
+ it "should glean the queries per second from raw ab output and return as a float" do
42
+ abr = new_abr("fleeblesnork\nRequests per second: 162.68 [#/sec] (mean)\n\nblah")
43
+ abr.queries_per_second.should == 162.68
44
+ end
45
+
46
+ describe "when the raw value is an integer" do
47
+ it "should still be returned as a float" do
48
+ abr = new_abr("fleeblesnork\nRequests per second: 162 [#/sec] (mean)\n\nblah")
49
+ abr.queries_per_second.should == 162.0
50
+ abr.queries_per_second.class.to_s.should == 'Float'
51
+ end
52
+ end
53
+ end
54
+
55
+ describe "#failed_requests" do
56
+ it "should glean the failed request count from raw ab output and return as a fixnum" do
57
+ abr = new_abr("fleeblesnork\nFailed requests: 17\n\nblah")
58
+ abr.failed_requests.should == 17
59
+ abr.failed_requests.class.to_s.should == 'Fixnum'
60
+ end
61
+ end
62
+
63
+ describe "#log" do
64
+ it "should log command, avg response time, queries per second, and failed requests" do
65
+ ab_options = {:crunch => 'now'}
66
+ abr = new_abr('blah', ab_options)
67
+ mock(abr).command { 'tight!' }
68
+ mock(abr).avg_response_time { "186" }
69
+ mock(abr).queries_per_second { "50" }
70
+ mock(abr).failed_requests { '10' }
71
+ # ...
72
+ lines = []
73
+ stub(AbCrunch::Logger).log { |*args|
74
+ args[0].should == :ab_result
75
+ lines << args[1]
76
+ }
77
+ abr.log
78
+ lines.should == [
79
+ 'tight!',
80
+ 'Average Response Time: 186',
81
+ 'Queries per Second: 50',
82
+ 'Failed requests: 10'
83
+ ]
84
+ end
85
+ end
86
+
87
+ end
@@ -0,0 +1,47 @@
1
+ require 'spec_helper'
2
+
3
+ describe "AbRunner" do
4
+ describe "#validate_options" do
5
+ it "should throw an error when no url is provided" do
6
+ lambda {
7
+ AbCrunch::AbRunner.validate_options({})
8
+ }.should raise_error "AB Options missing :url"
9
+ end
10
+
11
+ it "should return the options merged into the global configuration's ab_options'" do
12
+ result = AbCrunch::AbRunner.validate_options({:url => 'some url'})
13
+ result.should == AbCrunch::Config.ab_options.merge({:url => 'some url'})
14
+ end
15
+ end
16
+
17
+ describe "#ab_command" do
18
+ it "should return the ab command line based on given options, forcing the page url to reset" do
19
+ options = {
20
+ :concurrency => 'thigh master',
21
+ :num_requests => 'i can only do 5 today',
22
+ :url => '5 minute abs'
23
+ }
24
+ mock.proxy(AbCrunch::Page).get_url(options, true)
25
+
26
+ AbCrunch::AbRunner.ab_command(options).should == "ab -c thigh master -n i can only do 5 today -k -H 'Accept-Encoding: gzip' 5 minute abs"
27
+ end
28
+ end
29
+
30
+ describe "#ab" do
31
+ it "should run ab and wrap the results in an ab result" do
32
+ def Open3.block=(block) ; @block = block ; end
33
+ def Open3.block(cmd, &block)
34
+ self.block = block if block_given?
35
+ block.call(StringIO.new(''), StringIO.new('some fake output'), StringIO.new(''))
36
+ return(@block)
37
+ end
38
+ Open3.block = nil
39
+ stub(Open3).popen3.implemented_by(Open3.method(:block))
40
+
41
+ stub(AbCrunch::AbRunner).ab_command('bar') { 'foo' }
42
+ mock(AbCrunch::AbResult).new('some fake output', 'bar') { 'six pack' }
43
+
44
+ AbCrunch::AbRunner.ab('bar').should == 'six pack'
45
+ end
46
+ end
47
+ end
@@ -0,0 +1,56 @@
1
+ require 'spec_helper'
2
+
3
+ describe "BestRun" do
4
+ before :all do
5
+ @ab_options = {
6
+ :url => 'foo',
7
+ :concurrency => 1,
8
+ :num_requests => 10
9
+ }
10
+ end
11
+
12
+ describe "#of_avg_response_time" do
13
+ it "should run ab on the ab options N times" do
14
+ stub(AbCrunch::Logger).log
15
+ num_runs = 0
16
+ stub(AbCrunch::AbRunner).ab(@ab_options) do
17
+ num_runs += 1
18
+ obj = "foo"
19
+
20
+ class << obj
21
+ def avg_response_time
22
+ 4
23
+ end
24
+ end
25
+ obj
26
+ end
27
+
28
+ AbCrunch::BestRun.of_avg_response_time(7, @ab_options)
29
+
30
+ num_runs.should == 7
31
+ end
32
+
33
+ it "should return the ab result for the run with the lowest avg response time" do
34
+ stub(AbCrunch::Logger).log
35
+ response_times = [3, 87, 1, 590]
36
+
37
+ run_idx = 0
38
+ stub(AbCrunch::AbRunner).ab(@ab_options) do
39
+ obj = Object.new
40
+ response_time = response_times[run_idx]
41
+ obj.singleton_class.class_eval do
42
+ define_method(:avg_response_time) do
43
+ response_time
44
+ end
45
+ end
46
+
47
+ run_idx += 1
48
+ obj
49
+ end
50
+
51
+ result = AbCrunch::BestRun.of_avg_response_time(4, @ab_options)
52
+
53
+ result.avg_response_time.should == 1
54
+ end
55
+ end
56
+ end
@@ -0,0 +1,22 @@
1
+ require 'spec_helper'
2
+
3
+ describe "AbCrunch::Config" do
4
+ it "should have hashes for ab options and max concurrent options" do
5
+ AbCrunch::Config.best_concurrency_options.class.to_s.should == 'Hash'
6
+ AbCrunch::Config.ab_options.class.to_s.should == 'Hash'
7
+ end
8
+
9
+ it "should have a hash for the pages to be tested" do
10
+ AbCrunch::Config.page_sets.class.to_s.should == 'Hash'
11
+ end
12
+
13
+ describe "#page_sets=" do
14
+ it "should remember the new page sets and force new rake tasks to be created" do
15
+ mock(AbCrunch::Config).load(File.join(AbCrunch.root, "lib/abcrunch/tasks/generated.rake"))
16
+
17
+ AbCrunch::Config.page_sets = { :foo => 'bar' }
18
+
19
+ AbCrunch::Config.page_sets.should == { :foo => 'bar' }
20
+ end
21
+ end
22
+ end
@@ -0,0 +1,82 @@
1
+ require 'spec_helper'
2
+
3
+ describe "AbCrunch::LogConsoleWriter" do
4
+ describe "#color_for_type" do
5
+ it "should return the color for the given type" do
6
+ AbCrunch::LogConsoleWriter.color_for_type(:progress).should == :green
7
+ end
8
+
9
+ describe "when the type is unknown" do
10
+ it "should return white" do
11
+ AbCrunch::LogConsoleWriter.color_for_type(:weasel).should == :white
12
+ end
13
+ end
14
+ end
15
+
16
+ describe "#prefix_for_type" do
17
+ it "should return the prefix for the given type" do
18
+ AbCrunch::LogConsoleWriter.prefix_for_type(:progress).should == ' '
19
+ end
20
+
21
+ describe "when the type is unknown" do
22
+ it "should return an empty string" do
23
+ AbCrunch::LogConsoleWriter.prefix_for_type(:weasel).should == ''
24
+ end
25
+ end
26
+ end
27
+
28
+ describe "#log" do
29
+ describe "inline behavior" do
30
+ before :each do
31
+ @calls = []
32
+ @messages = []
33
+ stub(AbCrunch::LogConsoleWriter).print do |msg|
34
+ @calls << 'print'
35
+ @messages << msg
36
+ end
37
+ stub(AbCrunch::LogConsoleWriter).puts do |msg|
38
+ @calls << 'puts'
39
+ @messages << msg
40
+ end
41
+ end
42
+
43
+ describe "when the message is intended to be inline" do
44
+ it "should print instead of puts" do
45
+ AbCrunch::LogConsoleWriter.log(:info, 'foo', {:inline => true})
46
+
47
+ @calls.should == ['print']
48
+ end
49
+ end
50
+
51
+ describe "when the message is NOT intended to be inline" do
52
+ it "should puts instead of print" do
53
+ AbCrunch::LogConsoleWriter.log(:info, 'foo')
54
+
55
+ @calls.should == ['puts']
56
+ end
57
+ end
58
+
59
+ describe "when the previous message was inline, and the current one is not" do
60
+ it "should prepend a new line" do
61
+ AbCrunch::LogConsoleWriter.log(:info, 'foo', {:inline => true})
62
+ AbCrunch::LogConsoleWriter.log(:info, 'foo')
63
+
64
+ @messages[1].should include "\n foo"
65
+ end
66
+ end
67
+ end
68
+
69
+ describe "if the type has a color" do
70
+ it "should should invoke the color on the message" do
71
+ calls = []
72
+ any_instance_of(String) do |s|
73
+ stub(s).green { calls << 'green' }
74
+ end
75
+
76
+ AbCrunch::LogConsoleWriter.log(:progress, 'foo')
77
+
78
+ calls.should == ['green']
79
+ end
80
+ end
81
+ end
82
+ end
@@ -0,0 +1,12 @@
1
+ require 'spec_helper'
2
+
3
+ describe "AbCrunch::Logger" do
4
+ describe "#log" do
5
+ it "should call log on all writers" do
6
+ AbCrunch::Logger.writers = [AbCrunch::LogConsoleWriter]
7
+ mock(AbCrunch::LogConsoleWriter).log(:foo, 'bar', {:bizz => 'bazam!'})
8
+
9
+ AbCrunch::Logger.log(:foo, 'bar', {:bizz => 'bazam!'})
10
+ end
11
+ end
12
+ end
@@ -0,0 +1,64 @@
1
+ require 'spec_helper'
2
+
3
+ describe "AbCrunch::Page" do
4
+ describe "#get_url" do
5
+ describe "when the page url is a string" do
6
+ it "should return the string" do
7
+ page = { :url => 'some url' }
8
+
9
+ AbCrunch::Page.get_url(page).should == 'some url'
10
+ end
11
+ end
12
+
13
+ describe "when the page url is a proc" do
14
+ it "should call the proc and return the result" do
15
+ page = { :url => Proc.new { 'a proc url' } }
16
+
17
+ AbCrunch::Page.get_url(page).should == 'a proc url'
18
+ end
19
+
20
+ describe "when the page url is a proc returning different results each call" do
21
+
22
+ before :each do
23
+ @call_num = 0
24
+ @page = { :url => Proc.new { @call_num += 1 ; "changing url #{@call_num}" } }
25
+ end
26
+
27
+ describe "when called repeatedly without force_new" do
28
+ it "should return the same url each time" do
29
+ AbCrunch::Page.get_url(@page).should == 'changing url 1'
30
+ AbCrunch::Page.get_url(@page).should == 'changing url 1'
31
+ AbCrunch::Page.get_url(@page).should == 'changing url 1'
32
+ end
33
+ end
34
+
35
+ describe "when called repeadedly with force_new = True" do
36
+ it "should return different urls each time" do
37
+ AbCrunch::Page.get_url(@page, true).should == 'changing url 1'
38
+ AbCrunch::Page.get_url(@page, true).should == 'changing url 2'
39
+ AbCrunch::Page.get_url(@page, true).should == 'changing url 3'
40
+ end
41
+ end
42
+ end
43
+ end
44
+
45
+ end
46
+
47
+ describe "#get_display_url" do
48
+ describe "when the url is a string" do
49
+ it "should return the string" do
50
+ page = { :url => 'a text url' }
51
+
52
+ AbCrunch::Page.get_display_url(page).should == 'a text url'
53
+ end
54
+ end
55
+
56
+ describe "when the url is a proc" do
57
+ it "should return an example, noting that it's dynamic'" do
58
+ page = { :url => Proc.new { 'a proc url' } }
59
+
60
+ AbCrunch::Page.get_display_url(page).should == 'Dynamic url example: a proc url'
61
+ end
62
+ end
63
+ end
64
+ end
@@ -0,0 +1,85 @@
1
+ require 'spec_helper'
2
+
3
+ describe "AbCrunch::PageTester" do
4
+ describe "#test" do
5
+
6
+ def stub_strategies(result = nil)
7
+ strategy_result = result ? result : AbCrunchSpec.new_result
8
+
9
+ @strategies.each do |strategy|
10
+ stub(strategy).run { strategy_result }
11
+ end
12
+ end
13
+
14
+ before :each do
15
+ @test_page = AbCrunchSpec.new_page
16
+ @test_result = AbCrunchSpec.new_result
17
+ @strategies = [AbCrunch::StrategyBestConcurrency]
18
+
19
+ stub(AbCrunch::Logger).log
20
+ end
21
+
22
+ it "should show the display url" do
23
+ stub_strategies
24
+
25
+ mock(AbCrunch::Page).get_display_url(@test_page)
26
+
27
+ AbCrunch::PageTester.test(@test_page)
28
+ end
29
+
30
+ it "should run every load testing strategy on the given page" do
31
+ @strategies.each do |strategy|
32
+ mock(strategy).run(@test_page) { @test_result }
33
+ end
34
+
35
+ AbCrunch::PageTester.test(@test_page)
36
+ end
37
+
38
+ it "should use any user provided max avg response time as the max latency for all strategies" do
39
+ stub_strategies
40
+ page = AbCrunchSpec.new_page({:max_avg_response_time => 139.2})
41
+
42
+ AbCrunch::PageTester.test(page)
43
+
44
+ page[:max_latency].should == 139.2
45
+ end
46
+
47
+ it "should fail if the avg response time is over the specified maximum" do
48
+ result = AbCrunchSpec.new_result
49
+ class << result
50
+ def avg_response_time
51
+ 200
52
+ end
53
+ end
54
+ page = AbCrunchSpec.new_page({:max_avg_response_time => 117})
55
+
56
+ stub_strategies(result)
57
+
58
+ passed, qps_result, errors = AbCrunch::PageTester.test(page)
59
+
60
+ passed.should == false
61
+ errors.should == [
62
+ "some page: Avg response time of 200 must be <= 117"
63
+ ]
64
+ end
65
+
66
+ it "should fail if the queries per second is under the specified minimum" do
67
+ result = AbCrunchSpec.new_result
68
+ class << result
69
+ def queries_per_second
70
+ 5
71
+ end
72
+ end
73
+ page = AbCrunchSpec.new_page({:min_queries_per_second => 117})
74
+
75
+ stub_strategies(result)
76
+
77
+ passed, qps_result, errors = AbCrunch::PageTester.test(page)
78
+
79
+ passed.should == false
80
+ errors.should == [
81
+ "some page: QPS of 5 must be >= 117"
82
+ ]
83
+ end
84
+ end
85
+ end