stella 0.3.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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
|