stella 0.5.3 → 0.5.4
Sign up to get free protection for your applications and to get access to all the features.
- data/{README.txt → README.textile} +63 -40
- data/Rakefile +7 -5
- data/bin/stella +1 -1
- data/bin/stella.bat +12 -0
- data/lib/pcaplet.rb +180 -0
- data/lib/stella/adapter/ab.rb +57 -33
- data/lib/stella/adapter/base.rb +11 -1
- data/lib/stella/adapter/httperf.rb +13 -10
- data/lib/stella/adapter/pcap_watcher.rb +221 -0
- data/lib/stella/adapter/proxy_watcher.rb +76 -0
- data/lib/stella/adapter/siege.rb +28 -11
- data/lib/stella/cli/agents.rb +2 -2
- data/lib/stella/cli/base.rb +37 -1
- data/lib/stella/cli/localtest.rb +1 -2
- data/lib/stella/cli/sysinfo.rb +17 -0
- data/lib/stella/cli/watch.rb +278 -0
- data/lib/stella/cli.rb +23 -11
- data/lib/stella/command/base.rb +1 -10
- data/lib/stella/command/localtest.rb +43 -23
- data/lib/stella/data/domain.rb +75 -0
- data/lib/stella/data/http.rb +124 -0
- data/lib/stella/logger.rb +16 -5
- data/lib/stella/storable.rb +4 -2
- data/lib/stella/support.rb +71 -0
- data/lib/stella/sysinfo.rb +247 -0
- data/lib/stella/test/base.rb +5 -1
- data/lib/stella/test/definition.rb +1 -1
- data/lib/stella/test/run/summary.rb +14 -4
- data/lib/stella/text/resource.rb +0 -1
- data/lib/stella.rb +28 -10
- data/lib/utils/domainutil.rb +47 -0
- data/lib/utils/fileutil.rb +22 -3
- data/lib/utils/httputil.rb +184 -128
- data/lib/utils/mathutil.rb +20 -7
- data/lib/win32/Console/ANSI.rb +305 -0
- data/lib/win32/Console.rb +970 -0
- data/spec/show-agents_spec.rb +0 -0
- data/support/kvm.h +91 -0
- data/support/ruby-pcap-takuma-notes.txt +19 -0
- data/support/ruby-pcap-takuma-patch.txt +30 -0
- data/support/text/en.yaml +26 -3
- data/vendor/frylock/README.textile +72 -0
- data/vendor/frylock/bin/example +170 -0
- data/vendor/frylock/frylock.gemspec +18 -0
- data/vendor/frylock/lib/frylock/exceptions.rb +24 -0
- data/vendor/frylock/lib/frylock.rb +232 -0
- data/vendor/frylock/test/command_test.rb +33 -0
- data/vendor/hitimes-0.4.0/HISTORY +28 -0
- data/vendor/hitimes-0.4.0/LICENSE.txt +19 -0
- data/vendor/hitimes-0.4.0/README +80 -0
- data/vendor/hitimes-0.4.0/Rakefile +63 -0
- data/vendor/hitimes-0.4.0/examples/benchmarks.rb +86 -0
- data/vendor/hitimes-0.4.0/examples/stats.rb +29 -0
- data/vendor/hitimes-0.4.0/ext/extconf.rb +15 -0
- data/vendor/hitimes-0.4.0/ext/hitimes_ext.c +21 -0
- data/vendor/hitimes-0.4.0/ext/hitimes_instant_clock_gettime.c +20 -0
- data/vendor/hitimes-0.4.0/ext/hitimes_instant_osx.c +16 -0
- data/vendor/hitimes-0.4.0/ext/hitimes_instant_windows.c +27 -0
- data/vendor/hitimes-0.4.0/ext/hitimes_interval.c +340 -0
- data/vendor/hitimes-0.4.0/ext/hitimes_interval.h +73 -0
- data/vendor/hitimes-0.4.0/ext/hitimes_stats.c +242 -0
- data/vendor/hitimes-0.4.0/ext/hitimes_stats.h +30 -0
- data/vendor/hitimes-0.4.0/ext/rbconfig-mingw.rb +178 -0
- data/vendor/hitimes-0.4.0/ext/rbconfig.rb +178 -0
- data/vendor/hitimes-0.4.0/gemspec.rb +54 -0
- data/vendor/hitimes-0.4.0/lib/hitimes/mutexed_stats.rb +23 -0
- data/vendor/hitimes-0.4.0/lib/hitimes/paths.rb +54 -0
- data/vendor/hitimes-0.4.0/lib/hitimes/stats.rb +29 -0
- data/vendor/hitimes-0.4.0/lib/hitimes/timer.rb +223 -0
- data/vendor/hitimes-0.4.0/lib/hitimes/version.rb +42 -0
- data/vendor/hitimes-0.4.0/lib/hitimes.rb +24 -0
- data/vendor/hitimes-0.4.0/spec/interval_spec.rb +115 -0
- data/vendor/hitimes-0.4.0/spec/mutex_stats_spec.rb +34 -0
- data/vendor/hitimes-0.4.0/spec/paths_spec.rb +14 -0
- data/vendor/hitimes-0.4.0/spec/spec_helper.rb +6 -0
- data/vendor/hitimes-0.4.0/spec/stats_spec.rb +72 -0
- data/vendor/hitimes-0.4.0/spec/timer_spec.rb +105 -0
- data/vendor/hitimes-0.4.0/spec/version_spec.rb +27 -0
- data/vendor/hitimes-0.4.0/tasks/announce.rake +39 -0
- data/vendor/hitimes-0.4.0/tasks/config.rb +107 -0
- data/vendor/hitimes-0.4.0/tasks/distribution.rake +53 -0
- data/vendor/hitimes-0.4.0/tasks/documentation.rake +33 -0
- data/vendor/hitimes-0.4.0/tasks/extension.rake +64 -0
- data/vendor/hitimes-0.4.0/tasks/rspec.rake +31 -0
- data/vendor/hitimes-0.4.0/tasks/rubyforge.rake +52 -0
- data/vendor/hitimes-0.4.0/tasks/utils.rb +80 -0
- data/vendor/useragent/lib/user_agent.rb +1 -1
- 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
|
+
Release: 0.5.4-alpha (2009-01-07)
|
4
4
|
|
5
|
-
This is a
|
5
|
+
This is a BETA release. Proceed in double verify mode!
|
6
6
|
|
7
7
|
|
8
|
-
|
8
|
+
h2. Prerequisites
|
9
9
|
|
10
|
-
* Linux,
|
11
|
-
* Ruby 1.8.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
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
15
|
+
** rspec
|
16
|
+
** net-dns
|
17
|
+
** Ruby-Pcap (optional, for packet sniffing)
|
18
|
+
|
18
19
|
* One of:
|
19
|
-
|
20
|
-
|
21
|
-
|
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
|
-
|
25
|
+
h2. Installation
|
25
26
|
|
26
27
|
Get it in one of the following ways:
|
28
|
+
|
27
29
|
* RubyForge: http://stella.rubyforge.org/
|
28
|
-
|
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
|
-
|
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
|
-
|
48
|
+
h3. Installing libpcap and Ruby-Pcap
|
46
49
|
|
47
|
-
|
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
|
-
|
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
|
-
|
60
|
+
h2. Usage Examples
|
53
61
|
|
54
|
-
|
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
|
-
|
58
|
-
|
59
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
145
|
+
|
146
|
+
h2. Report an issue
|
125
147
|
|
126
148
|
Email issues and bugs to stella@solutious.com
|
127
149
|
|
128
150
|
|
129
|
-
|
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
|
-
|
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 = "
|
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.
|
53
|
-
|
54
|
-
|
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
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
|
+
|
data/lib/stella/adapter/ab.rb
CHANGED
@@ -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 :
|
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
|
-
|
60
|
-
|
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| "
|
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
|
-
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
|
125
|
-
|
126
|
-
|
127
|
-
|
128
|
-
|
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
|
data/lib/stella/adapter/base.rb
CHANGED
@@ -10,7 +10,8 @@ module Stella::Adapter
|
|
10
10
|
class Base
|
11
11
|
|
12
12
|
|
13
|
-
attr_accessor :
|
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 :
|
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
|
-
|
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
|
-
|
145
|
-
|
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
|