stella 0.3.2
Sign up to get free protection for your applications and to get access to all the features.
- data/README.txt +135 -0
- data/Rakefile +100 -0
- data/bin/stella +12 -0
- data/lib/stella.rb +58 -0
- data/lib/stella/adapter/ab.rb +303 -0
- data/lib/stella/adapter/base.rb +87 -0
- data/lib/stella/adapter/httperf.rb +296 -0
- data/lib/stella/adapter/siege.rb +321 -0
- data/lib/stella/cli.rb +291 -0
- data/lib/stella/cli/agents.rb +73 -0
- data/lib/stella/cli/base.rb +19 -0
- data/lib/stella/cli/language.rb +18 -0
- data/lib/stella/cli/localtest.rb +80 -0
- data/lib/stella/command/base.rb +111 -0
- data/lib/stella/command/localtest.rb +339 -0
- data/lib/stella/logger.rb +63 -0
- data/lib/stella/response.rb +82 -0
- data/lib/stella/storable.rb +116 -0
- data/lib/stella/support.rb +106 -0
- data/lib/stella/test/base.rb +34 -0
- data/lib/stella/test/definition.rb +79 -0
- data/lib/stella/test/run/summary.rb +50 -0
- data/lib/stella/test/summary.rb +82 -0
- data/lib/stella/text.rb +64 -0
- data/lib/stella/text/resource.rb +39 -0
- data/lib/utils/crypto-key.rb +84 -0
- data/lib/utils/escape.rb +302 -0
- data/lib/utils/fileutil.rb +59 -0
- data/lib/utils/httputil.rb +210 -0
- data/lib/utils/mathutil.rb +78 -0
- data/lib/utils/textgraph.rb +267 -0
- data/lib/utils/timerutil.rb +58 -0
- data/support/text/en.yaml +54 -0
- data/support/text/nl.yaml +1 -0
- data/support/useragents.txt +75 -0
- data/vendor/useragent/MIT-LICENSE +20 -0
- data/vendor/useragent/README +21 -0
- data/vendor/useragent/init.rb +1 -0
- data/vendor/useragent/lib/user_agent.rb +83 -0
- data/vendor/useragent/lib/user_agent/browsers.rb +24 -0
- data/vendor/useragent/lib/user_agent/browsers/all.rb +69 -0
- data/vendor/useragent/lib/user_agent/browsers/gecko.rb +43 -0
- data/vendor/useragent/lib/user_agent/browsers/internet_explorer.rb +40 -0
- data/vendor/useragent/lib/user_agent/browsers/opera.rb +49 -0
- data/vendor/useragent/lib/user_agent/browsers/webkit.rb +94 -0
- data/vendor/useragent/lib/user_agent/comparable.rb +25 -0
- data/vendor/useragent/lib/user_agent/operating_systems.rb +19 -0
- data/vendor/useragent/spec/browsers/gecko_user_agent_spec.rb +209 -0
- data/vendor/useragent/spec/browsers/internet_explorer_user_agent_spec.rb +99 -0
- data/vendor/useragent/spec/browsers/opera_user_agent_spec.rb +59 -0
- data/vendor/useragent/spec/browsers/other_user_agent_spec.rb +19 -0
- data/vendor/useragent/spec/browsers/webkit_user_agent_spec.rb +373 -0
- data/vendor/useragent/spec/spec_helper.rb +1 -0
- data/vendor/useragent/spec/user_agent_spec.rb +331 -0
- data/vendor/useragent/useragent.gemspec +12 -0
- metadata +139 -0
data/README.txt
ADDED
@@ -0,0 +1,135 @@
|
|
1
|
+
Stella - Your Performance Testing Friend
|
2
|
+
|
3
|
+
Release: 0.3.2-preview (2008-12-23)
|
4
|
+
|
5
|
+
This is a PREVIEW release. Don't trust and double verify!
|
6
|
+
|
7
|
+
|
8
|
+
== Prerequisites
|
9
|
+
|
10
|
+
* Linux, *BSD, Solaris
|
11
|
+
* Ruby 1.8.x or 1.9.x
|
12
|
+
* Ruby Libraries
|
13
|
+
* fastthread
|
14
|
+
* mongrel
|
15
|
+
* rspec
|
16
|
+
* rdoc
|
17
|
+
|
18
|
+
* One of:
|
19
|
+
* Apache Bench
|
20
|
+
* Siege
|
21
|
+
* Httperf
|
22
|
+
|
23
|
+
|
24
|
+
== Installation
|
25
|
+
|
26
|
+
Get it in one of the following ways:
|
27
|
+
* RubyForge: http://stella.rubyforge.org/
|
28
|
+
* gem install stella
|
29
|
+
|
30
|
+
Use ab, siege, and httperf like you normally would with the addition of stella at the beginning (examples are below).
|
31
|
+
|
32
|
+
=== Debian (and derivatives)
|
33
|
+
|
34
|
+
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
|
+
|
36
|
+
"no such file to load -- mkmf (LoadError)"
|
37
|
+
|
38
|
+
apt-get install ruby1.8-dev
|
39
|
+
|
40
|
+
"ERROR: RDoc documentation generator not installed!"
|
41
|
+
|
42
|
+
apt-get install rdoc
|
43
|
+
|
44
|
+
|
45
|
+
== Examples
|
46
|
+
|
47
|
+
Run Apache Bench with a warmup and rampup from 100 to 300 virtual users in increments of 25
|
48
|
+
|
49
|
+
stella --warmup=0.5 --rampup=25,300 ab -c 100 -n 10000 http://stellaaahhhh.com/search?term=trooper
|
50
|
+
|
51
|
+
|
52
|
+
Run Siege, repeat the test 5 times. Automatically creates a summary averages and standard deviations.
|
53
|
+
|
54
|
+
stella --agent=ff-3-osx --testruns=5 siege -c 100 -r 100 -b http://stellaaahhhh.com/search?term=flock+of+seagulls
|
55
|
+
|
56
|
+
|
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
|
60
|
+
|
61
|
+
|
62
|
+
== Sample Output
|
63
|
+
|
64
|
+
$ 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
|
+
Writing test data to: stella/testruns/2008-12-23/test-054
|
66
|
+
|
67
|
+
Warmup: 3750@37/1 100% 264.29/s 0.140s 0.024MB/s 0.340MB 14.000s .
|
68
|
+
|
69
|
+
-------------------------------------------------------------------
|
70
|
+
REQ@VU/s AVAIL REQ/s RTIME DATA/s DATA TIME
|
71
|
+
|
72
|
+
Run 01: 7500@75/1 100% 345.30/s 0.210s 0.032MB/s 0.690MB 21.720s
|
73
|
+
Run 02: 7500@75/1 100% 360.58/s 0.200s 0.033MB/s 0.690MB 20.800s
|
74
|
+
Run 03: 7500@75/1 100% 359.02/s 0.210s 0.033MB/s 0.690MB 20.890s
|
75
|
+
-------------------------------------------------------------------
|
76
|
+
Total: 22500@73 100% 354.97/s 0.207s 0.033MB/s 2.070MB 63.410s
|
77
|
+
Std Dev: 6.86/s 0.005s 0.001MB/s 0.414s
|
78
|
+
|
79
|
+
Run 04: 10000@100/1 100% 384.47/s 0.260s 0.035MB/s 0.920MB 26.010s
|
80
|
+
Run 05: 10000@100/1 100% 385.06/s 0.260s 0.035MB/s 0.920MB 25.970s
|
81
|
+
Run 06: 10000@100/1 100% 380.95/s 0.260s 0.035MB/s 0.920MB 26.250s
|
82
|
+
-------------------------------------------------------------------
|
83
|
+
Total: 30000@98 100% 383.49/s 0.260s 0.035MB/s 2.760MB 78.230s
|
84
|
+
Std Dev: 1.81/s 0.000s 0.000MB/s 0.124s
|
85
|
+
|
86
|
+
Run 07: 12500@125/1 100% 397.20/s 0.310s 0.036MB/s 1.140MB 31.470s
|
87
|
+
Run 08: 12500@125/1 100% 397.08/s 0.310s 0.036MB/s 1.140MB 31.480s
|
88
|
+
Run 09: 12500@125/1 100% 397.58/s 0.310s 0.036MB/s 1.140MB 31.440s
|
89
|
+
-------------------------------------------------------------------
|
90
|
+
Total: 37500@123 100% 397.29/s 0.310s 0.036MB/s 3.420MB 94.390s
|
91
|
+
Std Dev: 0.21/s 0.000s 0.000MB/s 0.017s
|
92
|
+
|
93
|
+
-------------------------------------------------------------------
|
94
|
+
Total: 90000@98 100% 378.58/s 0.259s 0.035MB/s 8.250MB 236.030s
|
95
|
+
Std Dev: 18.09/s 0.042s 0.002MB/s 4.225s
|
96
|
+
|
97
|
+
|
98
|
+
All test data is collected under ./stella (this can be changed with the parameter --datapath):
|
99
|
+
|
100
|
+
$ ls -l ./stella/testruns/2008-12-23/
|
101
|
+
test-001 test-002 test-003 test-004 test-005 test-006 ... test-054
|
102
|
+
|
103
|
+
|
104
|
+
A symbolic link points to the most recent test:
|
105
|
+
|
106
|
+
$ ls -l ./stella/latest/
|
107
|
+
ID.txt MESSAGE.txt SUMMARY.csv run01 run02 run03 run04 run05 warmup
|
108
|
+
|
109
|
+
|
110
|
+
Each run directory contains all associated data, including the command and configuration
|
111
|
+
|
112
|
+
$ ls -l ./stella/latest/run01/
|
113
|
+
COMMAND.txt STDOUT.txt siege.log STDERR.txt SUMMARY.csv siegerc
|
114
|
+
|
115
|
+
|
116
|
+
== Known Issues
|
117
|
+
|
118
|
+
* 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
|
+
* The summary data has not been audited. Don't trust and double verify!
|
120
|
+
* httperf is functional but needs a lot more testing (most dev was done with ab and siege).
|
121
|
+
* The Ruby API has not been finalized. It's functional but there's no example because it is subject to change.
|
122
|
+
* There are no specs.
|
123
|
+
|
124
|
+
== Report an issue
|
125
|
+
|
126
|
+
Email issues and bugs to stella@solutious.com
|
127
|
+
|
128
|
+
|
129
|
+
== Even More Information
|
130
|
+
|
131
|
+
http://www.youtube.com/watch?v=wmq-JDonTpc
|
132
|
+
|
133
|
+
== License
|
134
|
+
|
135
|
+
See LICENSE.txt
|
data/Rakefile
ADDED
@@ -0,0 +1,100 @@
|
|
1
|
+
require 'rake'
|
2
|
+
require 'spec/rake/spectask'
|
3
|
+
|
4
|
+
desc "Run all specs"
|
5
|
+
Spec::Rake::SpecTask.new('spec') do |t|
|
6
|
+
t.spec_files = FileList['spec/*_spec.rb']
|
7
|
+
end
|
8
|
+
|
9
|
+
desc "Print specdocs"
|
10
|
+
Spec::Rake::SpecTask.new(:doc) do |t|
|
11
|
+
t.spec_opts = ["--format", "specdoc", "--dry-run"]
|
12
|
+
t.spec_files = FileList['spec/*_spec.rb']
|
13
|
+
end
|
14
|
+
|
15
|
+
desc "Run all examples with RCov"
|
16
|
+
Spec::Rake::SpecTask.new('rcov') do |t|
|
17
|
+
t.spec_files = FileList['spec/*_spec.rb']
|
18
|
+
t.rcov = true
|
19
|
+
t.rcov_opts = ['--exclude', 'examples']
|
20
|
+
end
|
21
|
+
|
22
|
+
task :default => :spec
|
23
|
+
|
24
|
+
######################################################
|
25
|
+
|
26
|
+
require 'rake'
|
27
|
+
require 'rake/testtask'
|
28
|
+
require 'rake/clean'
|
29
|
+
require 'rake/gempackagetask'
|
30
|
+
require 'rake/rdoctask'
|
31
|
+
require 'fileutils'
|
32
|
+
include FileUtils
|
33
|
+
|
34
|
+
STELLA_HOME = File.expand_path(File.join(File.dirname(__FILE__)))
|
35
|
+
$: << File.join(STELLA_HOME, 'lib')
|
36
|
+
|
37
|
+
require 'stella'
|
38
|
+
version = Stella::VERSION.to_s
|
39
|
+
|
40
|
+
name = "stella"
|
41
|
+
|
42
|
+
spec = Gem::Specification.new do |s|
|
43
|
+
s.name = name
|
44
|
+
s.version = version
|
45
|
+
s.summary = "A friend in performance testing."
|
46
|
+
s.description = "Run Apache Bench, Siege, or httperf tests in batches and aggregate results."
|
47
|
+
s.author = "Delano Mandelbaum"
|
48
|
+
s.email = "delano@solutious.com"
|
49
|
+
s.homepage = "http://stella.solutious.com/"
|
50
|
+
s.executables = [ "stella" ]
|
51
|
+
s.rubyforge_project = "stella"
|
52
|
+
s.extra_rdoc_files = ['README.txt']
|
53
|
+
|
54
|
+
s.add_dependency 'mongrel'
|
55
|
+
s.add_dependency 'rspec'
|
56
|
+
#s.add_dependency 'session'
|
57
|
+
|
58
|
+
s.platform = Gem::Platform::RUBY
|
59
|
+
s.has_rdoc = true
|
60
|
+
|
61
|
+
s.files = %w(Rakefile) + Dir.glob("{bin,doc,lib,spec,support,vendor}/**/**/*")
|
62
|
+
|
63
|
+
s.require_path = "lib"
|
64
|
+
s.bindir = "bin"
|
65
|
+
end
|
66
|
+
|
67
|
+
Rake::GemPackageTask.new(spec) do |p|
|
68
|
+
p.need_tar = true if RUBY_PLATFORM !~ /mswin/
|
69
|
+
end
|
70
|
+
|
71
|
+
|
72
|
+
task :install => [ :rdoc, :package ] do
|
73
|
+
sh %{sudo gem install pkg/#{name}-#{version}.gem}
|
74
|
+
end
|
75
|
+
|
76
|
+
task :uninstall => [ :clean ] do
|
77
|
+
sh %{sudo gem uninstall #{name}}
|
78
|
+
end
|
79
|
+
|
80
|
+
Rake::TestTask.new do |t|
|
81
|
+
t.libs << "spec"
|
82
|
+
t.test_files = FileList['spec/*_spec.rb']
|
83
|
+
t.verbose = true
|
84
|
+
end
|
85
|
+
|
86
|
+
Rake::RDocTask.new do |t|
|
87
|
+
t.rdoc_dir = 'doc'
|
88
|
+
t.title = "stella, a friend in performance testing"
|
89
|
+
t.options << '--line-numbers' << '--inline-source' << '-A cattr_accessor=object'
|
90
|
+
t.options << '--charset' << 'utf-8'
|
91
|
+
t.rdoc_files.include('LICENSE.txt')
|
92
|
+
t.rdoc_files.include('README.txt')
|
93
|
+
t.rdoc_files.include('lib/utils/*.rb')
|
94
|
+
t.rdoc_files.include('lib/stella.rb')
|
95
|
+
t.rdoc_files.include('lib/stella/*.rb')
|
96
|
+
t.rdoc_files.include('lib/stella/**/*.rb')
|
97
|
+
end
|
98
|
+
|
99
|
+
CLEAN.include [ 'pkg', '*.gem', '.config', 'doc' ]
|
100
|
+
|
data/bin/stella
ADDED
@@ -0,0 +1,12 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
STELLA_HOME = File.expand_path(File.join(File.dirname(__FILE__), '..'))
|
4
|
+
$: << File.join(STELLA_HOME, 'lib')
|
5
|
+
|
6
|
+
require 'stella'
|
7
|
+
require 'stella/cli'
|
8
|
+
|
9
|
+
## Create and run the application
|
10
|
+
app = Stella::CLI.new(ARGV, STDIN)
|
11
|
+
app.run
|
12
|
+
|
data/lib/stella.rb
ADDED
@@ -0,0 +1,58 @@
|
|
1
|
+
|
2
|
+
$: << File.join(STELLA_HOME, 'vendor', 'useragent', 'lib')
|
3
|
+
|
4
|
+
|
5
|
+
require 'date'
|
6
|
+
require 'open3'
|
7
|
+
|
8
|
+
# Common utilities
|
9
|
+
require 'utils/httputil'
|
10
|
+
require 'utils/crypto-key'
|
11
|
+
require 'utils/fileutil'
|
12
|
+
require 'utils/mathutil'
|
13
|
+
require 'utils/escape'
|
14
|
+
|
15
|
+
# Common dependencies
|
16
|
+
require 'stella/support'
|
17
|
+
require 'stella/storable'
|
18
|
+
require 'user_agent'
|
19
|
+
|
20
|
+
# Common objects
|
21
|
+
require 'stella/text'
|
22
|
+
require 'stella/logger'
|
23
|
+
require 'stella/response'
|
24
|
+
require 'stella/test/definition'
|
25
|
+
require 'stella/test/run/summary'
|
26
|
+
require 'stella/test/summary'
|
27
|
+
|
28
|
+
# Commands
|
29
|
+
require 'stella/command/base'
|
30
|
+
require 'stella/command/localtest'
|
31
|
+
|
32
|
+
# Adapters
|
33
|
+
require 'stella/adapter/base'
|
34
|
+
require 'stella/adapter/ab'
|
35
|
+
require 'stella/adapter/siege'
|
36
|
+
require 'stella/adapter/httperf'
|
37
|
+
|
38
|
+
# = Stella
|
39
|
+
# A friend in performance testing.
|
40
|
+
#
|
41
|
+
module Stella
|
42
|
+
LOGGER = Stella::Logger.new(:debug=>false)
|
43
|
+
TEXT = Stella::Text.new('en')
|
44
|
+
|
45
|
+
module VERSION #:nodoc:
|
46
|
+
MAJOR = 0.freeze unless defined? MAJOR
|
47
|
+
MINOR = 3.freeze unless defined? MINOR
|
48
|
+
TINY = 2.freeze unless defined? TINY
|
49
|
+
def self.to_s
|
50
|
+
[MAJOR, MINOR, TINY].join('.')
|
51
|
+
end
|
52
|
+
def self.to_f
|
53
|
+
self.to_s.to_f
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
end
|
58
|
+
|
@@ -0,0 +1,303 @@
|
|
1
|
+
|
2
|
+
|
3
|
+
|
4
|
+
module Stella
|
5
|
+
module Adapter
|
6
|
+
|
7
|
+
#Usage: ab [options] [http[s]://]hostname[:port]/path
|
8
|
+
#Options are:
|
9
|
+
# -n requests Number of requests to perform
|
10
|
+
# -c concurrency Number of multiple requests to make
|
11
|
+
# -t timelimit Seconds to max. wait for responses
|
12
|
+
# -b windowsize Size of TCP send/receive buffer, in bytes
|
13
|
+
# -p postfile File containing data to POST. Remember also to set -T
|
14
|
+
# -T content-type Content-type header for POSTing, eg.
|
15
|
+
# 'application/x-www-form-urlencoded'
|
16
|
+
# Default is 'text/plain'
|
17
|
+
# -v verbosity How much troubleshooting info to print
|
18
|
+
# -w Print out results in HTML tables
|
19
|
+
# -i Use HEAD instead of GET
|
20
|
+
# -x attributes String to insert as table attributes
|
21
|
+
# -y attributes String to insert as tr attributes
|
22
|
+
# -z attributes String to insert as td or th attributes
|
23
|
+
# -C attribute Add cookie, eg. 'Apache=1234. (repeatable)
|
24
|
+
# -H attribute Add Arbitrary header line, eg. 'Accept-Encoding: gzip'
|
25
|
+
# Inserted after all normal header lines. (repeatable)
|
26
|
+
# -A attribute Add Basic WWW Authentication, the attributes
|
27
|
+
# are a colon separated username and password.
|
28
|
+
# -P attribute Add Basic Proxy Authentication, the attributes
|
29
|
+
# are a colon separated username and password.
|
30
|
+
# -X proxy:port Proxyserver and port number to use
|
31
|
+
# -V Print version number and exit
|
32
|
+
# -k Use HTTP KeepAlive feature
|
33
|
+
# -d Do not show percentiles served table.
|
34
|
+
# -S Do not show confidence estimators and warnings.
|
35
|
+
# -g filename Output collected data to gnuplot format file.
|
36
|
+
# -e filename Output CSV file with percentages served
|
37
|
+
# -r Don't exit on socket receive errors.
|
38
|
+
# -h Display usage information (this message)
|
39
|
+
# -Z ciphersuite Specify SSL/TLS cipher suite (See openssl ciphers)
|
40
|
+
# -f protocol Specify SSL/TLS protocol (SSL2, SSL3, TLS1, or ALL)
|
41
|
+
class ApacheBench < Stella::Adapter::Base
|
42
|
+
|
43
|
+
|
44
|
+
attr_accessor :n, :c, :t, :b, :p, :T, :v, :w, :i, :x, :z, :y
|
45
|
+
attr_accessor :C, :H, :A, :P, :X, :V, :k, :d, :S, :e, :g, :r, :h, :Z, :f
|
46
|
+
|
47
|
+
def initialize(options={}, arguments=[])
|
48
|
+
super(options, arguments)
|
49
|
+
@private_variables = ['private_variables', 'name', 'arguments', 'load_factor', 'working_directory']
|
50
|
+
@c = 1
|
51
|
+
@n = 1
|
52
|
+
@name = 'ab'
|
53
|
+
@load_factor = 1
|
54
|
+
end
|
55
|
+
|
56
|
+
|
57
|
+
def version
|
58
|
+
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] }
|
63
|
+
end
|
64
|
+
vsn
|
65
|
+
end
|
66
|
+
|
67
|
+
def before
|
68
|
+
|
69
|
+
@e = @working_directory + "/ab-percentiles.log"
|
70
|
+
@e = File.expand_path(@e)
|
71
|
+
|
72
|
+
@g = @working_directory + "/ab-requests.log"
|
73
|
+
@g = File.expand_path(@g)
|
74
|
+
|
75
|
+
end
|
76
|
+
def command
|
77
|
+
raise CommandNotReady.new(self.class.to_s) unless ready?
|
78
|
+
|
79
|
+
command = "#{@name} "
|
80
|
+
|
81
|
+
instance_variables.each do |name|
|
82
|
+
canon = name.tr('@', '') # instance_variables returns '@name'
|
83
|
+
next if @private_variables.member?(canon)
|
84
|
+
|
85
|
+
# It's important that we take the value from the getter method
|
86
|
+
# because it applies the load factor.
|
87
|
+
value = self.send(canon)
|
88
|
+
if (value.is_a? Array)
|
89
|
+
value.each { |el| command << "-#{canon} #{EscapeUtil.shell_single_word(el.to_s)} " }
|
90
|
+
else
|
91
|
+
command << "-#{canon} #{EscapeUtil.shell_single_word(value.to_s)} "
|
92
|
+
end
|
93
|
+
|
94
|
+
end
|
95
|
+
|
96
|
+
command << (@arguments.map { |uri| "'#{uri}'" }).join(' ') unless @arguments.empty?
|
97
|
+
command
|
98
|
+
end
|
99
|
+
# loadtest
|
100
|
+
#
|
101
|
+
# True or false: is the call to ab a load test? If it's a call to help or version or
|
102
|
+
# to display the config this with return false. It's no reason for someone to make this
|
103
|
+
# call through Stella but it's here for goodness sake.
|
104
|
+
def loadtest?
|
105
|
+
!@arguments.empty? # The argument is a URI
|
106
|
+
end
|
107
|
+
def ready?
|
108
|
+
(!self.loadtest?) || (@name && !instance_variables.empty? && !@arguments.empty?)
|
109
|
+
end
|
110
|
+
|
111
|
+
|
112
|
+
def process_options(arguments)
|
113
|
+
options = OpenStruct.new
|
114
|
+
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
|
138
|
+
opts.on('-H S', String) do |v| options.H ||= []; options.H << v; end
|
139
|
+
opts.on('-C S', String) do |v| options.C ||= []; options.C << v; end
|
140
|
+
|
141
|
+
# NOTE: parse! removes the options it finds in @arguments. It will leave
|
142
|
+
# all unnamed arguments and throw a fit about unknown ones.
|
143
|
+
opts.parse!(arguments)
|
144
|
+
|
145
|
+
options
|
146
|
+
rescue OptionParser::InvalidOption => ex
|
147
|
+
# We want to replace this text so we grab just the name of the argument
|
148
|
+
badarg = ex.message.gsub('invalid option: ', '')
|
149
|
+
raise InvalidArgument.new(badarg)
|
150
|
+
end
|
151
|
+
|
152
|
+
def after
|
153
|
+
# We want to maintain copies of all test output, even when the user has
|
154
|
+
# supplied other path names so we'll copy the files from the testrun directory
|
155
|
+
# to the location specified by the user
|
156
|
+
[[@options.e, 'csv'], [@options.g, 'tsv']].each do |tuple|
|
157
|
+
if File.expand_path(File.dirname(tuple[0])) != File.expand_path(@runpath)
|
158
|
+
from = tuple[0]
|
159
|
+
to = @runpath + "/ab-#{tuple[1]}.log"
|
160
|
+
next unless File.exists?(from)
|
161
|
+
File.copy(from, to)
|
162
|
+
end
|
163
|
+
end
|
164
|
+
|
165
|
+
save_stats
|
166
|
+
end
|
167
|
+
|
168
|
+
|
169
|
+
|
170
|
+
|
171
|
+
def add_header(name, value)
|
172
|
+
@H ||= []
|
173
|
+
@H << "#{name}: #{value}"
|
174
|
+
end
|
175
|
+
|
176
|
+
def user_agent=(list=[])
|
177
|
+
return unless list && !list.empty?
|
178
|
+
list = list.to_ary
|
179
|
+
list.each do |agent|
|
180
|
+
add_header("User-Agent", agent)
|
181
|
+
end
|
182
|
+
end
|
183
|
+
|
184
|
+
def vusers
|
185
|
+
c || 0
|
186
|
+
end
|
187
|
+
def vusers=(v)
|
188
|
+
ratio = vuser_requests
|
189
|
+
@c = v
|
190
|
+
@n = ratio * @c
|
191
|
+
end
|
192
|
+
def requests
|
193
|
+
n || 0
|
194
|
+
end
|
195
|
+
def requests=(v)
|
196
|
+
@n = v
|
197
|
+
end
|
198
|
+
def vuser_requests
|
199
|
+
ratio = 1
|
200
|
+
# The request ratio tells us how many requests will be
|
201
|
+
# generated per vuser. It helps us later when we need to
|
202
|
+
# warmp up and ramp up.
|
203
|
+
if @n > 0 && @c > 0
|
204
|
+
ratio = (@n.to_f / @c.to_f).to_f
|
205
|
+
# If concurrency isn't set, we'll assume the total number of requests
|
206
|
+
# is intended to be per request
|
207
|
+
elsif @n > 0
|
208
|
+
ratio = @n
|
209
|
+
end
|
210
|
+
ratio
|
211
|
+
end
|
212
|
+
def c
|
213
|
+
(@c * @load_factor).to_i
|
214
|
+
end
|
215
|
+
def n
|
216
|
+
(@n * @load_factor).to_i
|
217
|
+
end
|
218
|
+
|
219
|
+
def hosts
|
220
|
+
hosts = @arguments || []
|
221
|
+
#hosts << get_hosts_from_file
|
222
|
+
hosts = hosts.map{ |h| tmp = URI.parse(h.strip); "#{tmp.host}:#{tmp.port}" }
|
223
|
+
hosts
|
224
|
+
end
|
225
|
+
|
226
|
+
def paths
|
227
|
+
paths = @arguments || []
|
228
|
+
#hosts << get_hosts_from_file
|
229
|
+
paths = paths.map{ |h| tmp = URI.parse(h.strip); "#{tmp.path}?#{tmp.query}" }
|
230
|
+
paths
|
231
|
+
end
|
232
|
+
|
233
|
+
|
234
|
+
|
235
|
+
# Apache bench writes the summary to STDOUT
|
236
|
+
def stats_file
|
237
|
+
File.new(stdout_path)
|
238
|
+
end
|
239
|
+
|
240
|
+
def stats
|
241
|
+
return unless stats_file
|
242
|
+
raw = {}
|
243
|
+
stats_file.each_line { |l|
|
244
|
+
l.chomp!
|
245
|
+
nvpair = l.split(':')
|
246
|
+
next unless nvpair && nvpair.size == 2
|
247
|
+
n = nvpair[0].strip.tr(' ', '_').downcase[/\w+/]
|
248
|
+
v = nvpair[1].strip[/[\.\d]+/]
|
249
|
+
|
250
|
+
# Apache Bench outputs two fields with the name "Time per request".
|
251
|
+
# We want only the first one so we don't overwrite values.
|
252
|
+
raw[n.to_sym] = v.to_f unless raw.has_key? n.to_sym
|
253
|
+
}
|
254
|
+
|
255
|
+
# Document Path: /
|
256
|
+
# Document Length: 96 bytes
|
257
|
+
#
|
258
|
+
# Concurrency Level: 75
|
259
|
+
# Time taken for tests: 2.001 seconds
|
260
|
+
# Complete requests: 750
|
261
|
+
# Failed requests: 0
|
262
|
+
# Write errors: 0
|
263
|
+
# Total transferred: 174000 bytes
|
264
|
+
# HTML transferred: 72000 bytes
|
265
|
+
# Requests per second: 374.74 [#/sec] (mean)
|
266
|
+
# Time per request: 200.138 [ms] (mean)
|
267
|
+
# Time per request: 2.669 [ms] (mean, across all concurrent requests)
|
268
|
+
# Transfer rate: 84.90 [Kbytes/sec] received
|
269
|
+
|
270
|
+
stats = Stella::Test::Run::Summary.new
|
271
|
+
|
272
|
+
unless raw.empty? || !raw.has_key?(:time_taken_for_tests)
|
273
|
+
|
274
|
+
stats.elapsed_time = raw[:time_taken_for_tests]
|
275
|
+
|
276
|
+
# We want this in MB, Apache Bench gives Bytes.
|
277
|
+
stats.data_transferred = ((raw[:html_transferred] || 0) / 1_048_576)
|
278
|
+
|
279
|
+
# total_transferred is header data + response data (html_transfered)
|
280
|
+
stats.headers_transferred = ((raw[:total_transferred] || 0) / 1_048_576) - stats.data_transferred
|
281
|
+
|
282
|
+
# Apache Bench returns ms
|
283
|
+
stats.response_time = (raw[:time_per_request] || 0) / 1000
|
284
|
+
stats.transaction_rate = raw[:requests_per_second]
|
285
|
+
|
286
|
+
stats.vusers = raw[:concurrency_level].to_i
|
287
|
+
stats.successful = raw[:complete_requests].to_i
|
288
|
+
stats.failed = raw[:failed_requests].to_i
|
289
|
+
|
290
|
+
stats.transactions = stats.successful + stats.failed
|
291
|
+
|
292
|
+
#stats.raw = raw if @global_options.debug
|
293
|
+
end
|
294
|
+
|
295
|
+
stats
|
296
|
+
end
|
297
|
+
|
298
|
+
|
299
|
+
|
300
|
+
end
|
301
|
+
|
302
|
+
end
|
303
|
+
end
|