stresser 0.3.2 → 0.4.0

Sign up to get free protection for your applications and to get access to all the features.
data/HISTORY.markdown ADDED
@@ -0,0 +1,3 @@
1
+ ## 0.4
2
+ - added 'started at' column to csv export
3
+ - refactored options pasing in stresser bin to match stresser-grapher and stresser-loggen
data/README.markdown CHANGED
@@ -100,6 +100,10 @@ as often as you like:
100
100
 
101
101
  The `{{n}}` will be replaced with the numbers 0-99.
102
102
 
103
+ ## Tests
104
+ Run `rake spec` to run them tests. Currently, only httperf's output of a session based
105
+ replay log is parsed, but I will add more.
106
+
103
107
  ## Thanks
104
108
 
105
109
  Stresser is based on igvita's autoperf driver for httperf.
data/Rakefile CHANGED
@@ -47,9 +47,17 @@ task :default => :test
47
47
  require 'rake/rdoctask'
48
48
  Rake::RDocTask.new do |rdoc|
49
49
  version = File.exist?('VERSION') ? File.read('VERSION') : ""
50
-
51
50
  rdoc.rdoc_dir = 'rdoc'
52
51
  rdoc.title = "stresser #{version}"
53
52
  rdoc.rdoc_files.include('README*')
54
53
  rdoc.rdoc_files.include('lib/**/*.rb')
55
54
  end
55
+
56
+
57
+ require 'spec/rake/spectask'
58
+
59
+ desc "Run all examples"
60
+ Spec::Rake::SpecTask.new('spec') do |t|
61
+ t.spec_files = FileList['spec/**/*.rb']
62
+ end
63
+
data/VERSION CHANGED
@@ -1 +1 @@
1
- 0.3.2
1
+ 0.4.0
data/bin/stresser CHANGED
@@ -1,7 +1,9 @@
1
1
  #!/usr/bin/env ruby
2
2
  $LOAD_PATH.unshift File.join(File.dirname(__FILE__), '..', 'lib')
3
+ require 'rubygems'
3
4
  require 'mp_perf'
4
5
 
6
+
5
7
  trap("INT") {
6
8
  puts "Terminating tests."
7
9
  Process.exit
data/bin/stresser-grapher CHANGED
@@ -23,7 +23,7 @@ EOS
23
23
  :type => String
24
24
  end.merge(:csv_file => ARGV.last)
25
25
 
26
- Trollop::die :output_dir, "must be writeable" unless opts[:output_dir] and File.stat(opts[:output_dir]).writable?
26
+ Trollop::die :output_dir, "must be writeable" unless opts[:output_dir] and File.stat(opts[:output_dir]).writable?
27
27
  Trollop::die :output_dir, "must be a directory" unless opts[:output_dir] and File.stat(opts[:output_dir]).directory?
28
28
 
29
29
  Grapher.generate_reports(opts)
Binary file
data/lib/httperf.rb CHANGED
@@ -2,11 +2,12 @@ module Httperf
2
2
  extend self
3
3
 
4
4
  def run(conf)
5
- res = Hash.new ""
5
+ res = Hash["started at", Time.now]
6
+
6
7
  httperf_opt = conf.keys.grep(/httperf/).collect {|k| "--#{k.gsub(/httperf_/, '')}=#{conf[k]}"}.join(" ")
7
8
  httperf_cmd = "httperf --hog --server=#{conf['host']} --port=#{conf['port']} #{httperf_opt}"
8
9
  IO.popen("#{httperf_cmd} 2>&1") do |pipe|
9
- res = parse_output(pipe)
10
+ res.merge! parse_output(pipe)
10
11
 
11
12
  # Now calculate the amount of stati per second
12
13
  (1..5).each do |i|
data/lib/mp_perf.rb CHANGED
@@ -1,6 +1,8 @@
1
1
  require 'optparse'
2
2
  require 'ruport'
3
3
  require 'httperf'
4
+ require 'trollop'
5
+
4
6
 
5
7
  #
6
8
  # Takes command line options and attempts to make a benchmark.
@@ -8,29 +10,33 @@ require 'httperf'
8
10
  class MPPerf
9
11
 
10
12
  def initialize(opts = {})
11
- @conf = {}
12
- OptionParser.new do |opts|
13
- opts.banner = "Usage: stresser -c your.conf -o output.csv"
14
- opts.on("-o", "--output FILE", String, "This file will be overwritten with a detailed report of the stresstest") do |v|
15
- @output_file = v
16
- end
17
- opts.on( "-c", "--config FILE", String, "Your stresser configuration file with stresstest options and parameters directly passed to httperf") do |v|
18
- @conf = parse_config(v)
19
- end
20
- end.parse!
13
+ parse_options
14
+ parse_config
15
+ run_suite
16
+ display_hints
17
+ end
21
18
 
22
- run()
19
+ #
20
+ # Parse command line options
21
+ #
22
+ def parse_options
23
+ @conf = Trollop::options do
24
+ banner = MPPerf.options_banner
25
+ opt :output_file, "The name of the csv file to write the results to. Warning: overwrites that file!",
26
+ :type => String
27
+ opt :config_file, "The name of the .conf file defining your testsuite. See http://github.com/moviepilot/stresser",
28
+ :type => String
29
+ end
23
30
 
24
- puts "~"*80
25
- puts "Great, now create a graph with"
26
- puts " stresser-grapher -o #{File.expand_path(File.dirname(@output_file))} #{@output_file}"
27
- puts ""
31
+ Trollop::die :output_file, "must be a writeable file" unless @conf[:config_file]
32
+ Trollop::die :config_file, "must be a readable file" unless @conf[:config_file]
28
33
  end
29
34
 
30
35
  #
31
36
  # Taken from http://github.com/igrigorik/autoperf
32
37
  #
33
- def parse_config(config_file)
38
+ def parse_config
39
+ config_file = @conf[:config_file]
34
40
  raise Errno::EACCES, "#{config_file} is not readable" unless File.readable?(config_file)
35
41
 
36
42
  conf = {}
@@ -56,7 +62,7 @@ class MPPerf
56
62
  end
57
63
  }
58
64
 
59
- return conf
65
+ @conf.merge! conf
60
66
  end
61
67
 
62
68
  #
@@ -71,7 +77,7 @@ class MPPerf
71
77
  return res
72
78
  end
73
79
 
74
- def run
80
+ def run_suite
75
81
  results = {}
76
82
  report = nil
77
83
  (@conf['low_rate']..@conf['high_rate']).step(@conf['rate_step']) do |rate|
@@ -94,9 +100,23 @@ class MPPerf
94
100
  end
95
101
 
96
102
  # Write csv
97
- File.new(@output_file, "w").puts report.to_csv unless report.nil?
103
+ File.new(@conf[:output_file], "w").puts report.to_csv unless report.nil?
104
+ end
105
+
106
+ def display_hints
107
+ puts "~"*80
108
+ puts "Great, now create a graph with"
109
+ puts " stresser-grapher -o #{File.expand_path(File.dirname(@conf[:output_file]))} #{@conf[:output_file]}"
110
+ puts ""
98
111
  end
99
- end
100
-
101
112
 
113
+ def self.options_banner
114
+ <<BANNER
115
+ Runs a stresstest defined in a config file and write the results to a csv file.
102
116
 
117
+ Usage:
118
+ stresser -c my_config_file -o results.csv
119
+ where options are:
120
+ BANNER
121
+ end
122
+ end
data/sample.conf CHANGED
@@ -1,9 +1,9 @@
1
1
  # MPPerf Configuration File
2
2
 
3
3
  # The host, URI (relative to the document root) and port to test.
4
- host = www.intern.moviepilot.de
4
+ host = localhost
5
5
  uri = /
6
- port = 12001
6
+ port = 80
7
7
 
8
8
  # The 'rate' is the number of number of connections to open per second.
9
9
  # A series of tests will be conducted, starting at low rate,
@@ -4,126 +4,137 @@ describe Httperf do
4
4
 
5
5
  describe "parsing httperf output" do
6
6
 
7
- before(:all) do
8
- @pipe = File.open("spec/httperf_output.txt")
9
- @〉 = Httperf.parse_output(@pipe)
7
+ before(:each) do
8
+ @pipe = File.open("spec/httperf_session_based_output.txt")
9
+ Time.stub!(:now).and_return "Tue Nov 30 15:49:08 0100 2010"
10
+
11
+ #
12
+ # The friendly snail is greeting you!
13
+ #
14
+ IO.should_receive(:popen).and_yield @pipe
15
+ @⚋♉ = Httperf.run({})
10
16
  end
11
17
 
12
18
  it "should parse the 'Total' line correctly" do
13
- @〉['conns'].should == 500
14
- @〉['requests'].should == 600
15
- @〉['replies'].should == 300
16
- @〉['duration'].should == 50.354
19
+ @⚋♉['conns'].should == 500
20
+ @⚋♉['requests'].should == 600
21
+ @⚋♉['replies'].should == 300
22
+ @⚋♉['duration'].should == 50.354
17
23
  end
18
24
 
19
25
  it "should parse the 'Connection rate' line correctly" do
20
- @〉['conn/s'].should == 9.9
21
- @〉['ms/connection'].should == 100.7
22
- @〉['concurrent connections max'].should == 8
26
+ @⚋♉['conn/s'].should == 9.9
27
+ @⚋♉['ms/connection'].should == 100.7
28
+ @⚋♉['concurrent connections max'].should == 8
23
29
  end
24
30
 
25
31
  it "should parse the 'Connection time' line correctly" do
26
- @〉['conn time min'].should == 449.7
27
- @〉['conn time avg'].should == 465.1
28
- @〉['conn time max'].should == 2856.6
29
- @〉['conn time median'].should == 451.5
30
- @〉['conn time stddev'].should == 132.1
32
+ @⚋♉['conn time min'].should == 449.7
33
+ @⚋♉['conn time avg'].should == 465.1
34
+ @⚋♉['conn time max'].should == 2856.6
35
+ @⚋♉['conn time median'].should == 451.5
36
+ @⚋♉['conn time stddev'].should == 132.1
31
37
  end
32
38
 
33
39
  it "should parse the second 'Connection time' line correctly" do
34
- @〉['conn time connect'].should == 74.1
40
+ @⚋♉['conn time connect'].should == 74.1
35
41
  end
36
42
 
37
43
  it "should parse the 'Connection length' line correctly" do
38
- @〉['conn length replies/conn'].should == 1.0
44
+ @⚋♉['conn length replies/conn'].should == 1.0
39
45
  end
40
46
 
41
47
  it "should parse the 'Request rate' line correctly" do
42
- @〉['req/s'].should == 9.9
43
- @〉['ms/req'].should == 100.7
48
+ @⚋♉['req/s'].should == 9.9
49
+ @⚋♉['ms/req'].should == 100.7
44
50
  end
45
51
 
46
52
  it "should parse the 'Request size' line correctly" do
47
- @〉['request size'].should == 65.0
53
+ @⚋♉['request size'].should == 65.0
48
54
  end
49
55
 
50
56
  it "should parse the 'Reply rate' line correctly" do
51
- @〉['replies/s min'].should == 9.2
52
- @〉['replies/s avg'].should == 9.9
53
- @〉['replies/s max'].should == 10.0
54
- @〉['replies/s stddev'].should == 0.3
57
+ @⚋♉['replies/s min'].should == 9.2
58
+ @⚋♉['replies/s avg'].should == 9.9
59
+ @⚋♉['replies/s max'].should == 10.0
60
+ @⚋♉['replies/s stddev'].should == 0.3
55
61
  end
56
62
 
57
63
  it "should parse the 'Reply time' line correctly" do
58
- @〉['reply time response'].should == 88.1
59
- @〉['reply time transfer'].should == 302.9
64
+ @⚋♉['reply time response'].should == 88.1
65
+ @⚋♉['reply time transfer'].should == 302.9
60
66
  end
61
67
 
62
68
  it "should parse the 'Reply size' line correctly" do
63
- @〉['reply size header'].should == 274.0
64
- @〉['reply size content'].should == 54744.0
65
- @〉['reply size footer'].should == 2.0
66
- @〉['reply size total'].should == 55020.0
69
+ @⚋♉['reply size header'].should == 274.0
70
+ @⚋♉['reply size content'].should == 54744.0
71
+ @⚋♉['reply size footer'].should == 2.0
72
+ @⚋♉['reply size total'].should == 55020.0
67
73
  end
68
74
 
69
75
  it "should parse the 'Reply status' line correctly" do
70
- @〉['status 1xx'].should == 1
71
- @〉['status 2xx'].should == 500
72
- @〉['status 3xx'].should == 3
73
- @〉['status 4xx'].should == 4
74
- @〉['status 5xx'].should == 5
76
+ @⚋♉['status 1xx'].should == 1
77
+ @⚋♉['status 2xx'].should == 500
78
+ @⚋♉['status 3xx'].should == 3
79
+ @⚋♉['status 4xx'].should == 4
80
+ @⚋♉['status 5xx'].should == 5
75
81
  end
76
82
 
77
83
  it "should parse the 'CPU time' line correctly" do
78
- @〉['cpu time user'].should == 15.65
79
- @〉['cpu time system'].should == 34.65
80
- @〉['cpu time user %'].should == 31.1
81
- @〉['cpu time system %'].should == 68.8
82
- @〉['cpu time total %'].should == 99.9
84
+ @⚋♉['cpu time user'].should == 15.65
85
+ @⚋♉['cpu time system'].should == 34.65
86
+ @⚋♉['cpu time user %'].should == 31.1
87
+ @⚋♉['cpu time system %'].should == 68.8
88
+ @⚋♉['cpu time total %'].should == 99.9
83
89
  end
84
90
 
85
91
  it "should parse the 'Net I/O' line correctly" do
86
- @〉['net i/o (KB/s)'].should == 534.1
92
+ @⚋♉['net i/o (KB/s)'].should == 534.1
87
93
  end
88
94
 
89
95
  it "should parse the first 'Errors' line correctly" do
90
- @〉['errors total'].should == 1234
91
- @〉['errors client-timo'].should == 2345
92
- @〉['errors socket-timo'].should == 3456
93
- @〉['errors connrefused'].should == 4567
94
- @〉['errors connreset'].should == 5678
96
+ @⚋♉['errors total'].should == 1234
97
+ @⚋♉['errors client-timo'].should == 2345
98
+ @⚋♉['errors socket-timo'].should == 3456
99
+ @⚋♉['errors connrefused'].should == 4567
100
+ @⚋♉['errors connreset'].should == 5678
95
101
  end
96
102
 
97
103
  it "should parse the second 'Errors' line correctly" do
98
- @〉['errors fd-unavail'].should == 1
99
- @〉['errors addrunavail'].should == 2
100
- @〉['errors ftab-full'].should == 3
101
- @〉['errors other'].should == 4
104
+ @⚋♉['errors fd-unavail'].should == 1
105
+ @⚋♉['errors addrunavail'].should == 2
106
+ @⚋♉['errors ftab-full'].should == 3
107
+ @⚋♉['errors other'].should == 4
102
108
  end
103
109
 
104
110
  it "should parse the 'Session rate' line correctly" do
105
- @〉['session rate min'].should == 35.80
106
- @〉['session rate avg'].should == 37.04
107
- @〉['session rate max'].should == 38.20
108
- @〉['session rate stddev'].should == 0.98
109
- @〉['session rate quota'].should == "1000/1000"
111
+ @⚋♉['session rate min'].should == 35.80
112
+ @⚋♉['session rate avg'].should == 37.04
113
+ @⚋♉['session rate max'].should == 38.20
114
+ @⚋♉['session rate stddev'].should == 0.98
115
+ @⚋♉['session rate quota'].should == "1000/1000"
110
116
  end
111
117
 
112
118
  it "should parse the 'Session' line correctly" do
113
- @〉['session avg conns/sess'].should == 2.00
119
+ @⚋♉['session avg conns/sess'].should == 2.00
114
120
  end
115
121
 
116
122
  it "should parse the 'Session lifetime' line correctly" do
117
- @〉['session lifetime [s]'].should == 0.3
123
+ @⚋♉['session lifetime [s]'].should == 0.3
118
124
  end
119
125
 
120
126
  it "should parse the 'Session failtime' line correctly" do
121
- @〉['session failtime [s]'].should == 0.0
127
+ @⚋♉['session failtime [s]'].should == 0.0
122
128
  end
123
129
 
124
130
  it "should parse the 'Session length histogram' correctly" do
125
- @〉['session length histogram'].should == "0 0 1000"
131
+ @⚋♉['session length histogram'].should == "0 0 1000"
126
132
  end
133
+
134
+ it "should add a started at timestamp for each rate" do
135
+ @⚋♉['started at'].should == "Tue Nov 30 15:49:08 0100 2010"
136
+ end
137
+
127
138
  end
128
139
  end
129
140
 
data/stresser.gemspec CHANGED
@@ -5,11 +5,11 @@
5
5
 
6
6
  Gem::Specification.new do |s|
7
7
  s.name = %q{stresser}
8
- s.version = "0.3.2"
8
+ s.version = "0.4.0"
9
9
 
10
10
  s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
11
11
  s.authors = ["Jannis Hermanns"]
12
- s.date = %q{2010-11-16}
12
+ s.date = %q{2010-11-30}
13
13
  s.description = %q{Wrapper around httperf for stresstesting your app. Runs httperf multiple times with different concurrency levels and generates an executive summary™ in .csv"}
14
14
  s.email = %q{jannis@moviepilot.com}
15
15
  s.executables = ["stresser", "stresser-grapher", "stresser-loggen"]
@@ -20,6 +20,7 @@ Gem::Specification.new do |s|
20
20
  s.files = [
21
21
  ".document",
22
22
  ".gitignore",
23
+ "HISTORY.markdown",
23
24
  "LICENSE",
24
25
  "README.markdown",
25
26
  "Rakefile",
@@ -27,13 +28,13 @@ Gem::Specification.new do |s|
27
28
  "bin/stresser",
28
29
  "bin/stresser-grapher",
29
30
  "bin/stresser-loggen",
30
- "build/stresser-0.3.2.gem",
31
+ "build/stresser-0.4.0.gem",
31
32
  "lib/grapher.rb",
32
33
  "lib/httperf.rb",
33
34
  "lib/mp_perf.rb",
34
35
  "lib/reports.yml",
35
36
  "sample.conf",
36
- "spec/httperf_output.txt",
37
+ "spec/httperf_session_based_output.txt",
37
38
  "spec/lib/httperf_spec.rb",
38
39
  "spec/lib/mp_perf_spec.rb",
39
40
  "spec/spec.opts",
metadata CHANGED
@@ -1,13 +1,13 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: stresser
3
3
  version: !ruby/object:Gem::Version
4
- hash: 23
4
+ hash: 15
5
5
  prerelease: false
6
6
  segments:
7
7
  - 0
8
- - 3
9
- - 2
10
- version: 0.3.2
8
+ - 4
9
+ - 0
10
+ version: 0.4.0
11
11
  platform: ruby
12
12
  authors:
13
13
  - Jannis Hermanns
@@ -15,7 +15,7 @@ autorequire:
15
15
  bindir: bin
16
16
  cert_chain: []
17
17
 
18
- date: 2010-11-16 00:00:00 +01:00
18
+ date: 2010-11-30 00:00:00 +01:00
19
19
  default_executable:
20
20
  dependencies:
21
21
  - !ruby/object:Gem::Dependency
@@ -88,6 +88,7 @@ extra_rdoc_files:
88
88
  files:
89
89
  - .document
90
90
  - .gitignore
91
+ - HISTORY.markdown
91
92
  - LICENSE
92
93
  - README.markdown
93
94
  - Rakefile
@@ -95,13 +96,13 @@ files:
95
96
  - bin/stresser
96
97
  - bin/stresser-grapher
97
98
  - bin/stresser-loggen
98
- - build/stresser-0.3.2.gem
99
+ - build/stresser-0.4.0.gem
99
100
  - lib/grapher.rb
100
101
  - lib/httperf.rb
101
102
  - lib/mp_perf.rb
102
103
  - lib/reports.yml
103
104
  - sample.conf
104
- - spec/httperf_output.txt
105
+ - spec/httperf_session_based_output.txt
105
106
  - spec/lib/httperf_spec.rb
106
107
  - spec/lib/mp_perf_spec.rb
107
108
  - spec/spec.opts
Binary file