stella 0.5.3 → 0.5.4

Sign up to get free protection for your applications and to get access to all the features.
Files changed (88) hide show
  1. data/{README.txt → README.textile} +63 -40
  2. data/Rakefile +7 -5
  3. data/bin/stella +1 -1
  4. data/bin/stella.bat +12 -0
  5. data/lib/pcaplet.rb +180 -0
  6. data/lib/stella/adapter/ab.rb +57 -33
  7. data/lib/stella/adapter/base.rb +11 -1
  8. data/lib/stella/adapter/httperf.rb +13 -10
  9. data/lib/stella/adapter/pcap_watcher.rb +221 -0
  10. data/lib/stella/adapter/proxy_watcher.rb +76 -0
  11. data/lib/stella/adapter/siege.rb +28 -11
  12. data/lib/stella/cli/agents.rb +2 -2
  13. data/lib/stella/cli/base.rb +37 -1
  14. data/lib/stella/cli/localtest.rb +1 -2
  15. data/lib/stella/cli/sysinfo.rb +17 -0
  16. data/lib/stella/cli/watch.rb +278 -0
  17. data/lib/stella/cli.rb +23 -11
  18. data/lib/stella/command/base.rb +1 -10
  19. data/lib/stella/command/localtest.rb +43 -23
  20. data/lib/stella/data/domain.rb +75 -0
  21. data/lib/stella/data/http.rb +124 -0
  22. data/lib/stella/logger.rb +16 -5
  23. data/lib/stella/storable.rb +4 -2
  24. data/lib/stella/support.rb +71 -0
  25. data/lib/stella/sysinfo.rb +247 -0
  26. data/lib/stella/test/base.rb +5 -1
  27. data/lib/stella/test/definition.rb +1 -1
  28. data/lib/stella/test/run/summary.rb +14 -4
  29. data/lib/stella/text/resource.rb +0 -1
  30. data/lib/stella.rb +28 -10
  31. data/lib/utils/domainutil.rb +47 -0
  32. data/lib/utils/fileutil.rb +22 -3
  33. data/lib/utils/httputil.rb +184 -128
  34. data/lib/utils/mathutil.rb +20 -7
  35. data/lib/win32/Console/ANSI.rb +305 -0
  36. data/lib/win32/Console.rb +970 -0
  37. data/spec/show-agents_spec.rb +0 -0
  38. data/support/kvm.h +91 -0
  39. data/support/ruby-pcap-takuma-notes.txt +19 -0
  40. data/support/ruby-pcap-takuma-patch.txt +30 -0
  41. data/support/text/en.yaml +26 -3
  42. data/vendor/frylock/README.textile +72 -0
  43. data/vendor/frylock/bin/example +170 -0
  44. data/vendor/frylock/frylock.gemspec +18 -0
  45. data/vendor/frylock/lib/frylock/exceptions.rb +24 -0
  46. data/vendor/frylock/lib/frylock.rb +232 -0
  47. data/vendor/frylock/test/command_test.rb +33 -0
  48. data/vendor/hitimes-0.4.0/HISTORY +28 -0
  49. data/vendor/hitimes-0.4.0/LICENSE.txt +19 -0
  50. data/vendor/hitimes-0.4.0/README +80 -0
  51. data/vendor/hitimes-0.4.0/Rakefile +63 -0
  52. data/vendor/hitimes-0.4.0/examples/benchmarks.rb +86 -0
  53. data/vendor/hitimes-0.4.0/examples/stats.rb +29 -0
  54. data/vendor/hitimes-0.4.0/ext/extconf.rb +15 -0
  55. data/vendor/hitimes-0.4.0/ext/hitimes_ext.c +21 -0
  56. data/vendor/hitimes-0.4.0/ext/hitimes_instant_clock_gettime.c +20 -0
  57. data/vendor/hitimes-0.4.0/ext/hitimes_instant_osx.c +16 -0
  58. data/vendor/hitimes-0.4.0/ext/hitimes_instant_windows.c +27 -0
  59. data/vendor/hitimes-0.4.0/ext/hitimes_interval.c +340 -0
  60. data/vendor/hitimes-0.4.0/ext/hitimes_interval.h +73 -0
  61. data/vendor/hitimes-0.4.0/ext/hitimes_stats.c +242 -0
  62. data/vendor/hitimes-0.4.0/ext/hitimes_stats.h +30 -0
  63. data/vendor/hitimes-0.4.0/ext/rbconfig-mingw.rb +178 -0
  64. data/vendor/hitimes-0.4.0/ext/rbconfig.rb +178 -0
  65. data/vendor/hitimes-0.4.0/gemspec.rb +54 -0
  66. data/vendor/hitimes-0.4.0/lib/hitimes/mutexed_stats.rb +23 -0
  67. data/vendor/hitimes-0.4.0/lib/hitimes/paths.rb +54 -0
  68. data/vendor/hitimes-0.4.0/lib/hitimes/stats.rb +29 -0
  69. data/vendor/hitimes-0.4.0/lib/hitimes/timer.rb +223 -0
  70. data/vendor/hitimes-0.4.0/lib/hitimes/version.rb +42 -0
  71. data/vendor/hitimes-0.4.0/lib/hitimes.rb +24 -0
  72. data/vendor/hitimes-0.4.0/spec/interval_spec.rb +115 -0
  73. data/vendor/hitimes-0.4.0/spec/mutex_stats_spec.rb +34 -0
  74. data/vendor/hitimes-0.4.0/spec/paths_spec.rb +14 -0
  75. data/vendor/hitimes-0.4.0/spec/spec_helper.rb +6 -0
  76. data/vendor/hitimes-0.4.0/spec/stats_spec.rb +72 -0
  77. data/vendor/hitimes-0.4.0/spec/timer_spec.rb +105 -0
  78. data/vendor/hitimes-0.4.0/spec/version_spec.rb +27 -0
  79. data/vendor/hitimes-0.4.0/tasks/announce.rake +39 -0
  80. data/vendor/hitimes-0.4.0/tasks/config.rb +107 -0
  81. data/vendor/hitimes-0.4.0/tasks/distribution.rake +53 -0
  82. data/vendor/hitimes-0.4.0/tasks/documentation.rake +33 -0
  83. data/vendor/hitimes-0.4.0/tasks/extension.rake +64 -0
  84. data/vendor/hitimes-0.4.0/tasks/rspec.rake +31 -0
  85. data/vendor/hitimes-0.4.0/tasks/rubyforge.rake +52 -0
  86. data/vendor/hitimes-0.4.0/tasks/utils.rb +80 -0
  87. data/vendor/useragent/lib/user_agent.rb +1 -1
  88. metadata +87 -8
@@ -1,66 +1,86 @@
1
- Stella - Your Performance Testing Friend
1
+ h1. Stella - Your Performance Testing Friend
2
2
 
3
- Release: 0.5.3-preview (2008-12-23)
3
+ Release: 0.5.4-alpha (2009-01-07)
4
4
 
5
- This is a PREVIEW release. Don't trust and double verify!
5
+ This is a BETA release. Proceed in double verify mode!
6
6
 
7
7
 
8
- == Prerequisites
8
+ h2. Prerequisites
9
9
 
10
- * Linux, *BSD, Solaris
11
- * Ruby 1.8.x or 1.9.x
10
+ * Linux, BSD, Solaris
11
+ * Ruby 1.8.x, 1.9.x, or JRuby 1.1
12
+ * Native Libraries (c or c++)
13
+ ** Pcap (optional, for packet sniffing)
12
14
  * Ruby Libraries
13
- * fastthread
14
- * mongrel
15
- * rspec
16
- * rdoc
17
-
15
+ ** rspec
16
+ ** net-dns
17
+ ** Ruby-Pcap (optional, for packet sniffing)
18
+
18
19
  * One of:
19
- * Apache Bench
20
- * Siege
21
- * Httperf
20
+ ** "Apache Bench":http://httpd.apache.org/docs/2.0/programs/ab.html
21
+ ** "Siege":http://www.joedog.org/index/siege-home
22
+ ** "Httperf":http://www.hpl.hp.com/research/linux/httperf/
22
23
 
23
24
 
24
- == Installation
25
+ h2. Installation
25
26
 
26
27
  Get it in one of the following ways:
28
+
27
29
  * RubyForge: http://stella.rubyforge.org/
28
- * gem install stella
29
-
30
+ ** gem install stella
31
+ * git clone git://github.com/solutious/stella.git
32
+ ** git submodule init
33
+ ** git submodule update
34
+
30
35
  Use ab, siege, and httperf like you normally would with the addition of stella at the beginning (examples are below).
31
36
 
32
- === Debian (and derivatives)
37
+ h3. Debian (and derivatives)
33
38
 
34
39
  Debian and its derivative (Ubunutu) handling packing a bit differently (see: http://pkg-ruby-extras.alioth.debian.org/rubygems.html). There are a couple errors to watch out for during the installation. The solutions are below:
35
40
 
36
- "no such file to load -- mkmf (LoadError)"
37
-
38
- apt-get install ruby1.8-dev
41
+ "no such file to load -- mkmf (LoadError)"
42
+ $ apt-get install ruby1.8-dev
39
43
 
40
- "ERROR: RDoc documentation generator not installed!"
41
-
42
- apt-get install rdoc
44
+ "ERROR: RDoc documentation generator not installed!"
45
+ $ apt-get install rdoc
43
46
 
44
47
 
45
- == Examples
48
+ h3. Installing libpcap and Ruby-Pcap
46
49
 
47
- Run Apache Bench with a warmup and rampup from 100 to 300 virtual users in increments of 25
50
+ *Stella currently supports packet filtering with Native Ruby (no JRuby) on Linux/Unix/OS X only.*
51
+ *Ruby-Pcap does not compile with Ruby 1.9.1-RC1*
48
52
 
49
- stella --warmup=0.5 --rampup=25,300 ab -c 100 -n 10000 http://stellaaahhhh.com/search?term=trooper
50
-
53
+ libpcap and Ruby-Pcap are used to by Stella's watch command to filter packets off the network. This allows you to view HTTP requests and response (including headers and content) without having to configure a proxy. Both need to be compiled and installed separately:
54
+ * "libpcap":http://www.tcpdump.org/release/
55
+ * "Ruby-Pcap":http://www.goto.info.waseda.ac.jp/~fukusima/ruby/pcap-e.html
56
+
57
+ On Ruby, 1.8.6, Ruby-Pcap produces the following warnings at runtime: "pcap.bundle: warning: do not use Fixnums as Symbols". See: support/ruby-pcap-takuma-notes.txt.
58
+
51
59
 
52
- Run Siege, repeat the test 5 times. Automatically creates a summary averages and standard deviations.
60
+ h2. Usage Examples
53
61
 
54
- stella --agent=ff-3-osx --testruns=5 siege -c 100 -r 100 -b http://stellaaahhhh.com/search?term=flock+of+seagulls
62
+ Run Apache Bench with a warmup and rampup from 100 to 300 virtual users in increments of 25
63
+ $ stella --warmup=0.5 --rampup=25,300 ab -c 100 -n 10000 http://stellaaahhhh.com/search?term=trooper
55
64
 
65
+ Run Siege, repeat the test 5 times. Automatically creates a summary averages and standard deviations.
66
+ $ stella --agent=ff-3-osx --testruns=5 siege -c 100 -r 100 -b http://stellaaahhhh.com/search?term=flock+of+seagulls
67
+
68
+ Run Httperf like you normally would (but all the test data will be collected for you)
69
+ $ stella httperf --hog --client=0/1 --server=127.0.0.1 --port=5600 --uri=/ --rate=50 --num-conns=3000 --timeout=5
56
70
 
57
- Run Httperf like you normally would (but all the test data will be collected for you)
58
-
59
- stella httperf --hog --client=0/1 --server=127.0.0.1 --port=5600 --uri=/ --rate=50 --num-conns=3000 --timeout=5
71
+ Monitor DNS traffic using Pcap
72
+ $ stella watch -C dns
73
+
74
+ Monitor HTTP traffic using Pcap
75
+ $ stella watch -C http
76
+
77
+ Monitor HTTP traffic using a proxy (don't forget to configure your browser)
78
+ $ stella watch -P
60
79
 
61
80
 
62
- == Sample Output
81
+ h3. Sample Output
63
82
 
83
+ <pre><code>
64
84
  $ stella -f csv -x 5 -w 0.75 -r 25,125 -m "httpd 2.2.9-prefork" siege -c 75 -r 10 -b http://stella:5600/
65
85
  Writing test data to: stella/testruns/2008-12-23/test-054
66
86
 
@@ -93,7 +113,7 @@ Run Httperf like you normally would (but all the test data will be collected for
93
113
  -------------------------------------------------------------------
94
114
  Total: 90000@98 100% 378.58/s 0.259s 0.035MB/s 8.250MB 236.030s
95
115
  Std Dev: 18.09/s 0.042s 0.002MB/s 4.225s
96
-
116
+ </pre></code>
97
117
 
98
118
  All test data is collected under ./stella (this can be changed with the parameter --datapath):
99
119
 
@@ -113,23 +133,26 @@ Each run directory contains all associated data, including the command and confi
113
133
  COMMAND.txt STDOUT.txt siege.log STDERR.txt SUMMARY.csv siegerc
114
134
 
115
135
 
116
- == Known Issues
136
+ h2. Known Issues
117
137
 
118
138
  * The output for the REQ@VU/s columns is a work in progress. It's not aligned across tools and it will likely change in the next release.
119
139
  * The summary data has not been audited. Don't trust and double verify!
120
140
  * httperf is functional but needs a lot more testing (most dev was done with ab and siege).
121
141
  * The Ruby API has not been finalized. It's functional but there's no example because it is subject to change.
122
142
  * There are no specs.
143
+ * There is an issue with parsing ipv6 ip addresses with Ruby-Pcap or Net-DNS. This affects only dns sniffing with pcap. Reproduce by running "stella watch -P dns" and requesting "apple.com"
123
144
 
124
- == Report an issue
145
+
146
+ h2. Report an issue
125
147
 
126
148
  Email issues and bugs to stella@solutious.com
127
149
 
128
150
 
129
- == Even More Information
151
+ h2. More Information
152
+
153
+ "Stellaaahhhh":http://www.youtube.com/watch?v=wmq-JDonTpc
130
154
 
131
- http://www.youtube.com/watch?v=wmq-JDonTpc
132
155
 
133
- == License
156
+ h2. License
134
157
 
135
158
  See LICENSE.txt
data/Rakefile CHANGED
@@ -42,17 +42,19 @@ name = "stella"
42
42
  spec = Gem::Specification.new do |s|
43
43
  s.name = name
44
44
  s.version = version
45
- s.summary = "A friend in performance testing."
45
+ s.summary = "Your friend in performance testing."
46
46
  s.description = "Run Apache Bench, Siege, or httperf tests in batches and aggregate results."
47
47
  s.author = "Delano Mandelbaum"
48
48
  s.email = "delano@solutious.com"
49
49
  s.homepage = "http://stella.solutious.com/"
50
- s.executables = [ "stella" ]
50
+ s.executables = [ "stella", "stella.bat" ]
51
51
  s.rubyforge_project = "stella"
52
- s.extra_rdoc_files = ['README.txt']
53
-
54
- s.add_dependency 'mongrel'
52
+ s.extra_rdoc_files = ['README.textile']
53
+
54
+ # NOTE: how to make optional dependencies?
55
+ #s.add_dependency 'mongrel'
55
56
  s.add_dependency 'rspec'
57
+ s.add_dependency 'net-dns'
56
58
  #s.add_dependency 'session'
57
59
 
58
60
  s.platform = Gem::Platform::RUBY
data/bin/stella CHANGED
@@ -1,7 +1,7 @@
1
1
  #!/usr/bin/env ruby
2
2
 
3
3
  STELLA_HOME = File.expand_path(File.join(File.dirname(__FILE__), '..'))
4
- $: << File.join(STELLA_HOME, 'lib')
4
+ $:.unshift(File.join(STELLA_HOME, 'lib')) # Make sure our local lib is first in line
5
5
 
6
6
  require 'stella'
7
7
  require 'stella/cli'
data/bin/stella.bat ADDED
@@ -0,0 +1,12 @@
1
+ @echo off
2
+
3
+ rem Check for funkiness when called from another batch script.
4
+ rem We want FULL_PATH to contain the full path to the stella bin directory.
5
+ IF EXIST "%~dp0stella.bat" (set FULL_PATH=%~dp0) ELSE (set FULL_PATH=%~dp$PATH:0)
6
+
7
+ rem Check for JRuby, otherwise use Ruby.
8
+ rem We want EXECUTABLE to contain either "jruby" or "ruby"
9
+ IF EXIST "%JRUBY_HOME%" (set EXECUTABLE=jruby) ELSE (set EXECUTABLE=ruby)
10
+
11
+ rem Call the Ruby script, passing it all the arguments.
12
+ @%EXECUTABLE% %FULL_PATH%stella %*
data/lib/pcaplet.rb ADDED
@@ -0,0 +1,180 @@
1
+ require 'pcap'
2
+
3
+
4
+ # Pcaplet
5
+ #
6
+ # Adapted from Ruby portion of Ruby-Pcap:
7
+ # http://www.goto.info.waseda.ac.jp/~fukusima/ruby/pcap-e.html
8
+ # The lib/pcaplet.rb and lib/pcap_misc.rb files are in merge into this file
9
+ # and cleaned up. The Ruby-Pcap C extension was modified to apply several fixes
10
+ # so it would compile on OS X and to remove several warning messages. With
11
+ # help from: http://d.hatena.ne.jp/takuma104/20080210/1202638583
12
+ # We specifically removed the dependency on ARGV and OptParse. It was messy
13
+ # and required ARGV to be specifically modified before requiring this package.
14
+ # Manual: http://www.goto.info.waseda.ac.jp/~fukusima/ruby/pcap/doc/index.html
15
+ class Pcaplet
16
+
17
+ attr_accessor :debug, :verbose
18
+ # do not convert address to name
19
+ attr_accessor :convert
20
+ attr_accessor :device, :rfile, :count, :snaplen, :filter
21
+
22
+ def initialize(args = {})
23
+
24
+ @debug = args[:debug] || false
25
+ @verbose = args[:verbose] || false
26
+ @device = args[:device] || guess_device
27
+ @rfile = args[:rfile]
28
+ @convert = args[:convert] || false
29
+ @count = args[:count].to_i || 1000
30
+ @snaplen = args[:snaplen].to_i > 0 ? args[:snaplen] : 1500
31
+ @filter = args[:filter] || ''
32
+
33
+ Pcap.convert = @convert
34
+
35
+ # check option consistency
36
+ usage(1) if @device && @rfile
37
+ if !@device and !@rfile
38
+ @device = Pcap.lookupdev
39
+ end
40
+
41
+ # open
42
+ begin
43
+ if @device
44
+ @capture = Pcap::Capture.open_live(@device, @snaplen)
45
+ elsif @rfile
46
+ if @rfile !~ /\.gz$/
47
+ @capture = Capture.open_offline(@rfile)
48
+ else
49
+ $stdin = IO.popen("gzip -dc < #@rfile", 'r')
50
+ @capture = Capture.open_offline('-')
51
+ end
52
+ end
53
+ @capture.setfilter(@filter) if @filter
54
+ rescue Pcap::PcapError, ArgumentError
55
+ $stdout.flush
56
+ $stderr.puts $!
57
+ exit(1)
58
+ end
59
+ end
60
+
61
+ attr('capture')
62
+
63
+
64
+ def add_filter(f)
65
+ if @filter == nil || @filter =~ /^\s*$/ # if empty
66
+ #puts "filter is nil or empty"
67
+ @filter = f
68
+ else
69
+ #puts "filter is #{@filter}"
70
+ f = f.source if f.is_a? Filter
71
+ @filter = "( #{@filter} ) and ( #{f} )"
72
+ end
73
+ #puts "filter being set #{@filter}"
74
+ @capture.setfilter(@filter)
75
+ end
76
+
77
+ def each_packet(&block)
78
+
79
+ begin
80
+ duplicated = (RUBY_PLATFORM =~ /linux/ && @device == "lo")
81
+ unless duplicated
82
+ @capture.loop(@count, &block)
83
+ else
84
+ flip = true
85
+ @capture.loop(@count) do |pkt|
86
+ flip = (! flip)
87
+ next if flip
88
+ block.call pkt
89
+ end
90
+ end
91
+ end
92
+ end
93
+
94
+ alias each each_packet
95
+
96
+ def close
97
+ @capture.close
98
+ end
99
+ end
100
+
101
+
102
+
103
+ module Pcap
104
+ class Packet
105
+ def to_s
106
+ 'Some packet'
107
+ end
108
+
109
+ def inspect
110
+ "#<#{type}: #{self}>"
111
+ end
112
+ end
113
+
114
+ class IPPacket
115
+ def to_s
116
+ "#{ip_src} > #{ip_dst}"
117
+ end
118
+ end
119
+
120
+ class TCPPacket
121
+ def tcp_data_len
122
+ ip_len - 4 * (ip_hlen + tcp_hlen)
123
+ end
124
+
125
+ # The 3-way handshake that initiates a request
126
+ # ....S. --->
127
+ # .A..S. <---
128
+ # .A.... --->
129
+ #
130
+ # The teardown procedure at the end of the request
131
+ # .A...F --->
132
+ # .A.... <---
133
+ # .A...F --->
134
+ # .A.... <...
135
+ def tcp_flags_s
136
+ return \
137
+ (tcp_urg? ? 'U' : '.') + # Urgent
138
+ (tcp_ack? ? 'A' : '.') + # ACKnowledgement: Successful transfer
139
+ (tcp_psh? ? 'P' : '.') + # Push
140
+ (tcp_rst? ? 'R' : '.') + # Reset
141
+ (tcp_syn? ? 'S' : '.') + # SYNchronization: this is the first segment in a new transaction
142
+ (tcp_fin? ? 'F' : '.') # FINal: final transaction
143
+ end
144
+
145
+ def to_s
146
+ "#{src}:#{sport} > #{dst}:#{dport} #{tcp_flags_s}"
147
+ end
148
+ end
149
+
150
+ class UDPPacket
151
+ def to_s
152
+ "#{src}:#{sport} > #{dst}:#{dport} len #{udp_len} sum #{udp_sum}"
153
+ end
154
+ end
155
+
156
+ class ICMPPacket
157
+ def to_s
158
+ "#{src} > #{dst}: icmp: #{icmp_typestr}"
159
+ end
160
+ end
161
+
162
+ #
163
+ # Backword compatibility
164
+ #
165
+ IpPacket = IPPacket unless defined? IpPacket
166
+ IpAddress = IPAddress unless defined? IpAddress
167
+ TcpPacket = TCPPacket unless defined? TcpPacket
168
+ UdpPacket = UDPPacket unless defined? UdpPacket
169
+
170
+ end
171
+
172
+ class Time
173
+ # tcpdump style format
174
+ def tcpdump
175
+ sprintf "%0.2d:%0.2d:%0.2d.%0.6d", hour, min, sec, tv_usec
176
+ end
177
+ end
178
+
179
+
180
+
@@ -40,8 +40,8 @@ module Stella
40
40
  # -f protocol Specify SSL/TLS protocol (SSL2, SSL3, TLS1, or ALL)
41
41
  class ApacheBench < Stella::Adapter::Base
42
42
 
43
-
44
- attr_accessor :n, :c, :t, :b, :p, :T, :v, :w, :i, :x, :z, :y
43
+ attr_writer :n, :c
44
+ attr_accessor :t, :b, :p, :T, :v, :w, :i, :x, :z, :y
45
45
  attr_accessor :C, :H, :A, :P, :X, :V, :k, :d, :S, :e, :g, :r, :h, :Z, :f
46
46
 
47
47
  def initialize(options={}, arguments=[])
@@ -53,13 +53,14 @@ module Stella
53
53
  @load_factor = 1
54
54
  end
55
55
 
56
-
56
+ def error
57
+ (File.exists? stderr_path) ? FileUtil.read_file(stderr_path) : "Unknown error"
58
+ end
59
+
57
60
  def version
58
61
  vsn = 0
59
- text = ""
60
- Open3.popen3("#{@name} -V") do |stdin, stdout, stderr|
61
- text = stdout.readlines.join
62
- text.scan(/Version (\d+?\.\d+)/) { |v| vsn = v[0] }
62
+ Stella::Util.capture_output("#{@name} -V") do |stdout, stderr|
63
+ stdout.join.scan(/Version (\d+?\.\d+)/) { |v| vsn = v[0] }
63
64
  end
64
65
  vsn
65
66
  end
@@ -73,13 +74,14 @@ module Stella
73
74
  @g = File.expand_path(@g)
74
75
 
75
76
  end
77
+
76
78
  def command
77
79
  raise CommandNotReady.new(self.class.to_s) unless ready?
78
80
 
79
81
  command = "#{@name} "
80
82
 
81
83
  instance_variables.each do |name|
82
- canon = name.tr('@', '') # instance_variables returns '@name'
84
+ canon = name.to_s.tr('@', '') # instance_variables returns '@name'
83
85
  next if @private_variables.member?(canon)
84
86
 
85
87
  # It's important that we take the value from the getter method
@@ -93,7 +95,7 @@ module Stella
93
95
 
94
96
  end
95
97
 
96
- command << (@arguments.map { |uri| "'#{uri}'" }).join(' ') unless @arguments.empty?
98
+ command << (@arguments.map { |uri| "#{uri}" }).join(' ') unless @arguments.empty?
97
99
  command
98
100
  end
99
101
  # loadtest
@@ -112,36 +114,58 @@ module Stella
112
114
  def process_options(arguments)
113
115
  options = OpenStruct.new
114
116
  opts = OptionParser.new
115
- opts.on('-v') do |v| options.v = true end
116
- opts.on('-w') do |v| options.w = true end # TODO: Print a note that we don't parse the HTML results
117
- opts.on('-i') do |v| options.i = true end
118
- opts.on('-V') do |v| options.V = true end
119
- opts.on('-k') do |v| options.k = true end
120
- opts.on('-d') do |v| options.d = true end
121
- opts.on('-S') do |v| options.S = true end
122
- opts.on('-r') do |v| options.r = true end
123
- opts.on('-h') do |v| options.h = true end
124
- opts.on('-e S', String) do |v| options.e = v end
125
- opts.on('-g S', String) do |v| options.g = v end
126
- opts.on('-p S', String) do |v| options.p = v end
127
- opts.on('-T S', String) do |v| options.t = v end
128
- opts.on('-x S', String) do |v| options.x = v end
129
- opts.on('-y S', String) do |v| options.y = v end
130
- opts.on('-z S', String) do |v| options.z = v end
131
- opts.on('-P S', String) do |v| options.P = v end
132
- opts.on('-Z S', String) do |v| options.Z = v end
133
- opts.on('-f S', String) do |v| options.f = v end
134
- opts.on('-c N', Integer) do |v| options.c = v end
135
- opts.on('-n N', Integer) do |v| options.n = v end
136
- opts.on('-t N', Integer) do |v| options.t = v end
137
- opts.on('-b N', Integer) do |v| options.b = v end
117
+
118
+ # TODO: Print a note for w that we don't parse the HTML results
119
+ %w{v w i V k d S r h}.each do |n|
120
+ opts.on("-#{n}") do |v| options.send("#{n}=", true) end
121
+ end
122
+
123
+ %w{e g p T x y z P Z f A}.each do |n|
124
+ opts.on("-#{n} S", String) do |v| options.send("#{n}=", v) end
125
+ end
126
+
127
+ %w{c n t b}.each do |n|
128
+ opts.on("-#{n} S", Integer) do |v| options.send("#{n}=", v) end
129
+ end
130
+
138
131
  opts.on('-H S', String) do |v| options.H ||= []; options.H << v; end
139
132
  opts.on('-C S', String) do |v| options.C ||= []; options.C << v; end
140
133
 
134
+ opts.on('-b') do |v|
135
+ Stella::LOGGER.warn("-b is not an ab option. I'll pretend it's not there.")
136
+ end
137
+
138
+ opts.on('-r N',Integer) do |v|
139
+ Stella::LOGGER.error("-r is not an ab parameter. You probably want -n.")
140
+ exit 1
141
+ end
142
+
141
143
  # NOTE: parse! removes the options it finds in @arguments. It will leave
142
144
  # all unnamed arguments and throw a fit about unknown ones.
143
145
  opts.parse!(arguments)
144
146
 
147
+ if arguments.empty?
148
+ Stella::LOGGER.error("You need to provide a URI")
149
+ exit 1
150
+ elsif arguments.size > 1
151
+ Stella::LOGGER.warn("ab can handle only one URI. The others will be ignored.")
152
+ arguments = arguments.first
153
+ else
154
+ # Let's make sure the URI has a path (at least a trailing slash). Otherwise
155
+ # ab gives a cryptic error.
156
+ begin
157
+ uri = URI.parse(arguments.first)
158
+ if !uri || uri.path.empty?
159
+ Stella::LOGGER.error("ab requires a trailing slash for #{uri.to_s}")
160
+ exit 1
161
+ end
162
+ rescue => ex
163
+ Stella::LOGGER.error("Bad URI: #{arguments.first}")
164
+ exit 1
165
+ end
166
+ end
167
+
168
+
145
169
  options
146
170
  rescue OptionParser::InvalidOption => ex
147
171
  # We want to replace this text so we grab just the name of the argument
@@ -234,7 +258,7 @@ module Stella
234
258
 
235
259
  # Apache bench writes the summary to STDOUT
236
260
  def stats_file
237
- File.new(stdout_path)
261
+ File.new(stdout_path) if File.exists?(stdout_path)
238
262
  end
239
263
 
240
264
  def stats
@@ -10,7 +10,8 @@ module Stella::Adapter
10
10
  class Base
11
11
 
12
12
 
13
- attr_accessor :arguments, :load_factor, :working_directory, :stats
13
+ attr_accessor :working_directory, :stats
14
+ attr_reader :load_factor, :arguments
14
15
 
15
16
  def initialize(options={}, arguments=[])
16
17
  self.arguments = arguments
@@ -36,10 +37,16 @@ module Stella::Adapter
36
37
  #
37
38
  # This method must be overridden by the implementing class. This is intended
38
39
  # for processing the command-specific command-line arguments
40
+ # TODO: Rename to process_arguments
39
41
  def process_options
40
42
  raise Stella::TEXT.msg(:error_class_must_override, 'process_options')
41
43
  end
42
44
 
45
+ # options=
46
+ #
47
+ # Takes a hash or OpenStruct and applies the values to the instance variables.
48
+ # The keys should conincide with with the command line argument names.
49
+ # i.e. The key for --help should be :help
43
50
  def options=(options={})
44
51
  options = options.marshal_dump if options.is_a? OpenStruct
45
52
  unless options.nil? || options.empty?
@@ -82,6 +89,9 @@ module Stella::Adapter
82
89
  raise Stella::TEXT.msg(:error_class_must_override, 'user_agent=')
83
90
  end
84
91
 
92
+ private
93
+
94
+
85
95
  end
86
96
  end
87
97
 
@@ -21,11 +21,12 @@ module Stella
21
21
 
22
22
 
23
23
  attr_accessor :hog, :server, :uri, :num_conns, :num_calls, :rate, :timeout, :think_timeout, :port
24
- attr_accessor :add_header, :burst_length, :client, :close_with_reset, :debug, :failure_status
24
+ attr_accessor :burst_length, :client, :close_with_reset, :debug, :failure_status
25
25
  attr_accessor :help, :http_version, :max_connections, :max_piped_calls, :method, :no_host_hdr
26
26
  attr_accessor :period, :print_reply, :print_request, :recv_buffer, :retry_on_failure, :send_buffer
27
- attr_accessor :server_name, :session_cookies, :ssl, :ssl_ciphers, :ssl_no_reuse, :verbose
28
- attr_accessor :version, :wlog, :wsess, :wsesslog, :wset
27
+ attr_accessor :server_name, :session_cookies, :ssl, :ssl_ciphers, :ssl_no_reuse, :verbose
28
+
29
+ attr_writer :version, :add_header, :wlog, :wsess, :wsesslog, :wset
29
30
 
30
31
  def initialize(options={}, arguments=[])
31
32
  super(options, arguments)
@@ -36,7 +37,11 @@ module Stella
36
37
  end
37
38
 
38
39
 
39
-
40
+
41
+ def error
42
+ (File.exists? stderr_path) ? FileUtil.read_file(stderr_path) : "Unknown error"
43
+ end
44
+
40
45
  # Before calling run
41
46
  def before
42
47
 
@@ -141,10 +146,8 @@ module Stella
141
146
 
142
147
  def version
143
148
  vsn = 0
144
- text = ""
145
- Open3.popen3("#{@name} --version") do |stdin, stdout, stderr|
146
- text = stdout.readlines.join
147
- text.scan(/httperf\-([\d\.]+)\s/) { |v| vsn = v[0] }
149
+ Stella::Util.capture_output("#{@name} --version") do |stdout, stderr|
150
+ stdout.join.scan(/httperf\-([\d\.]+)\s/) { |v| vsn = v[0] }
148
151
  end
149
152
  vsn
150
153
  end
@@ -222,11 +225,11 @@ module Stella
222
225
 
223
226
  # Siege writes the summary to STDERR
224
227
  def stats_file
225
- File.new(stdout_path)
228
+ File.new(stdout_path) if File.exists?(stdout_path)
226
229
  end
227
230
 
228
231
  def rc_file
229
- File.join(@working_directory, "siegerc")
232
+ File.join(@working_directory, "siegerc")
230
233
  end
231
234
 
232
235
  def log_file