solutious-stella 0.5.5
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/CHANGES.txt +36 -0
- data/README.textile +162 -0
- data/Rakefile +88 -0
- data/bin/stella +12 -0
- data/bin/stella.bat +12 -0
- data/lib/daemonize.rb +56 -0
- data/lib/pcaplet.rb +180 -0
- data/lib/stella.rb +101 -0
- data/lib/stella/adapter/ab.rb +337 -0
- data/lib/stella/adapter/base.rb +106 -0
- data/lib/stella/adapter/httperf.rb +305 -0
- data/lib/stella/adapter/pcap_watcher.rb +221 -0
- data/lib/stella/adapter/proxy_watcher.rb +76 -0
- data/lib/stella/adapter/siege.rb +341 -0
- data/lib/stella/cli.rb +258 -0
- data/lib/stella/cli/agents.rb +73 -0
- data/lib/stella/cli/base.rb +55 -0
- data/lib/stella/cli/language.rb +18 -0
- data/lib/stella/cli/localtest.rb +78 -0
- data/lib/stella/cli/sysinfo.rb +16 -0
- data/lib/stella/cli/watch.rb +278 -0
- data/lib/stella/command/base.rb +40 -0
- data/lib/stella/command/localtest.rb +358 -0
- data/lib/stella/data/domain.rb +82 -0
- data/lib/stella/data/http.rb +131 -0
- data/lib/stella/logger.rb +84 -0
- data/lib/stella/response.rb +85 -0
- data/lib/stella/storable.rb +201 -0
- data/lib/stella/support.rb +276 -0
- data/lib/stella/sysinfo.rb +257 -0
- data/lib/stella/test/definition.rb +79 -0
- data/lib/stella/test/run/summary.rb +70 -0
- data/lib/stella/test/stats.rb +114 -0
- data/lib/stella/text.rb +64 -0
- data/lib/stella/text/resource.rb +38 -0
- data/lib/utils/crypto-key.rb +84 -0
- data/lib/utils/domainutil.rb +47 -0
- data/lib/utils/escape.rb +302 -0
- data/lib/utils/fileutil.rb +78 -0
- data/lib/utils/httputil.rb +266 -0
- data/lib/utils/mathutil.rb +15 -0
- data/lib/utils/stats.rb +88 -0
- data/lib/utils/textgraph.rb +267 -0
- data/lib/utils/timerutil.rb +58 -0
- data/lib/win32/Console.rb +970 -0
- data/lib/win32/Console/ANSI.rb +305 -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 +80 -0
- data/support/text/nl.yaml +7 -0
- data/support/useragents.txt +75 -0
- data/tests/01-util_test.rb +0 -0
- data/tests/02-stella-util_test.rb +42 -0
- data/tests/10-stella_test.rb +104 -0
- data/tests/11-stella-storable_test.rb +68 -0
- data/tests/60-stella-command_test.rb +248 -0
- data/tests/80-stella-cli_test.rb +45 -0
- data/tests/spec-helper.rb +31 -0
- metadata +165 -0
data/lib/stella.rb
ADDED
@@ -0,0 +1,101 @@
|
|
1
|
+
|
2
|
+
|
3
|
+
require 'date'
|
4
|
+
require 'time'
|
5
|
+
require 'tempfile'
|
6
|
+
require 'socket'
|
7
|
+
require 'ostruct'
|
8
|
+
require 'optparse'
|
9
|
+
require 'rubygems'
|
10
|
+
|
11
|
+
|
12
|
+
# Common utilities
|
13
|
+
require 'utils/domainutil'
|
14
|
+
require 'utils/httputil'
|
15
|
+
require 'utils/fileutil'
|
16
|
+
require 'utils/mathutil'
|
17
|
+
require 'utils/escape'
|
18
|
+
require 'utils/stats'
|
19
|
+
|
20
|
+
# Common dependencies
|
21
|
+
$: << File.join(STELLA_HOME, 'vendor', 'useragent', 'lib')
|
22
|
+
require 'user_agent'
|
23
|
+
|
24
|
+
# Common Stella dependencies
|
25
|
+
require 'stella/support'
|
26
|
+
require 'stella/storable'
|
27
|
+
|
28
|
+
# Common Stella Data Objects
|
29
|
+
require 'stella/data/http'
|
30
|
+
require 'stella/data/domain'
|
31
|
+
|
32
|
+
# Common Stella objects
|
33
|
+
require 'stella/text'
|
34
|
+
|
35
|
+
require 'stella/logger'
|
36
|
+
require 'stella/response'
|
37
|
+
require 'stella/sysinfo'
|
38
|
+
require 'stella/test/definition'
|
39
|
+
require 'stella/test/run/summary'
|
40
|
+
require 'stella/test/stats'
|
41
|
+
|
42
|
+
# Commands
|
43
|
+
require 'stella/command/base'
|
44
|
+
require 'stella/command/localtest'
|
45
|
+
|
46
|
+
# Adapters
|
47
|
+
require 'stella/adapter/base'
|
48
|
+
require 'stella/adapter/ab'
|
49
|
+
require 'stella/adapter/siege'
|
50
|
+
require 'stella/adapter/httperf'
|
51
|
+
|
52
|
+
# = Stella
|
53
|
+
# A friend in performance testing.
|
54
|
+
#
|
55
|
+
# This class ties Stella together. It must be required because it defines
|
56
|
+
# several constants which are used througout the other classes. +SYSINFO+
|
57
|
+
# is particularly important because it detects the platform and requires
|
58
|
+
# platform specific modules.
|
59
|
+
module Stella
|
60
|
+
# Autodetecets information about the local system,
|
61
|
+
# including OS (unix), implementation (freebsd), and architecture (x64)
|
62
|
+
SYSINFO = Stella::SystemInfo.new unless defined? SYSINFO
|
63
|
+
# A global logger for info, error, and debug messages.
|
64
|
+
LOGGER = Stella::Logger.new(:debug=>false) unless defined? LOGGER
|
65
|
+
# A global resource for all interface text.
|
66
|
+
TEXT = Stella::Text.new('en') unless defined? TEXT
|
67
|
+
|
68
|
+
module VERSION #:nodoc:
|
69
|
+
MAJOR = 0.freeze unless defined? MAJOR
|
70
|
+
MINOR = 5.freeze unless defined? MINOR
|
71
|
+
TINY = 5.freeze unless defined? TINY
|
72
|
+
def self.to_s
|
73
|
+
[MAJOR, MINOR, TINY].join('.')
|
74
|
+
end
|
75
|
+
def self.to_f
|
76
|
+
self.to_s.to_f
|
77
|
+
end
|
78
|
+
end
|
79
|
+
|
80
|
+
def self.debug=(enable=false)
|
81
|
+
Stella::LOGGER.debug_level = enable
|
82
|
+
end
|
83
|
+
|
84
|
+
def self.text(*args)
|
85
|
+
TEXT.msg(*args)
|
86
|
+
end
|
87
|
+
|
88
|
+
def self.sysinfo
|
89
|
+
SYSINFO
|
90
|
+
end
|
91
|
+
|
92
|
+
def self.info(*args)
|
93
|
+
LOGGER.info(*args)
|
94
|
+
end
|
95
|
+
|
96
|
+
def self.error(*args)
|
97
|
+
LOGGER.error(*args)
|
98
|
+
end
|
99
|
+
|
100
|
+
end
|
101
|
+
|
@@ -0,0 +1,337 @@
|
|
1
|
+
|
2
|
+
require 'fileutils'
|
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
|
+
attr_writer :n, :c
|
44
|
+
attr_accessor :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
|
+
@private_variables = ['private_variables', 'name', 'arguments', 'load_factor', 'working_directory']
|
49
|
+
@c = 1
|
50
|
+
@n = 1
|
51
|
+
@name = 'ab'
|
52
|
+
@load_factor = 1
|
53
|
+
|
54
|
+
super(options, arguments)
|
55
|
+
|
56
|
+
end
|
57
|
+
|
58
|
+
def error
|
59
|
+
(File.exists? stderr_path) ? FileUtil.read_file(stderr_path) : "Unknown error"
|
60
|
+
end
|
61
|
+
|
62
|
+
def version
|
63
|
+
vsn = 0
|
64
|
+
Stella::Util.capture_output("#{@name} -V") do |stdout, stderr|
|
65
|
+
stdout.join.scan(/Version (\d+?\.\d+)/) { |v| vsn = v[0] }
|
66
|
+
end
|
67
|
+
vsn
|
68
|
+
end
|
69
|
+
|
70
|
+
def percentiles_file
|
71
|
+
@working_directory + "/ab-percentiles.log"
|
72
|
+
end
|
73
|
+
|
74
|
+
def requests_file
|
75
|
+
@working_directory + "/ab-requests.log"
|
76
|
+
end
|
77
|
+
|
78
|
+
def before
|
79
|
+
@e = percentiles_file if @e.nil?
|
80
|
+
@g = requests_file if @g.nil?
|
81
|
+
end
|
82
|
+
|
83
|
+
def command
|
84
|
+
raise CommandNotReady.new(self.class.to_s) unless ready?
|
85
|
+
|
86
|
+
command = "#{@name} "
|
87
|
+
|
88
|
+
instance_variables.each do |name|
|
89
|
+
canon = name.to_s.tr('@', '') # instance_variables returns '@name'
|
90
|
+
next if @private_variables.member?(canon)
|
91
|
+
|
92
|
+
# It's important that we take the value from the getter method
|
93
|
+
# because it applies the load factor.
|
94
|
+
value = self.send(canon)
|
95
|
+
if (value.is_a? Array)
|
96
|
+
value.each { |el| command << "-#{canon} #{EscapeUtil.shell_single_word(value.to_s)} " }
|
97
|
+
else
|
98
|
+
command << "-#{canon} #{EscapeUtil.shell_single_word(value.to_s)} "
|
99
|
+
end
|
100
|
+
|
101
|
+
end
|
102
|
+
|
103
|
+
command << (@arguments.map { |uri| "#{uri}" }).join(' ') unless @arguments.empty?
|
104
|
+
|
105
|
+
command
|
106
|
+
end
|
107
|
+
# loadtest
|
108
|
+
#
|
109
|
+
# True or false: is the call to ab a load test? If it's a call to help or version or
|
110
|
+
# to display the config this with return false. It's no reason for someone to make this
|
111
|
+
# call through Stella but it's here for goodness sake.
|
112
|
+
def loadtest?
|
113
|
+
!@arguments.empty? # The argument is a URI
|
114
|
+
end
|
115
|
+
def ready?
|
116
|
+
(!self.loadtest?) || (@name && !instance_variables.empty? && !@arguments.empty?)
|
117
|
+
end
|
118
|
+
|
119
|
+
|
120
|
+
def process_arguments(arguments)
|
121
|
+
opts = OptionParser.new
|
122
|
+
|
123
|
+
# TODO: there's no need to use an OpenStruct here. It's confusing b/c we can
|
124
|
+
# use the instance var methods here instead of in Base::options=.
|
125
|
+
|
126
|
+
# TODO: Print a note for w that we don't parse the HTML results
|
127
|
+
%w{v w i V k d S r h}.each do |n|
|
128
|
+
opts.on("-#{n}") do |v| instance_variable_set("@#{n}", true) end
|
129
|
+
end
|
130
|
+
|
131
|
+
%w{e g p T x y z P Z f A}.each do |n|
|
132
|
+
opts.on("-#{n} S", String) do |v| instance_variable_set("@#{n}", v) end
|
133
|
+
end
|
134
|
+
|
135
|
+
%w{c n t b}.each do |n|
|
136
|
+
opts.on("-#{n} S", Integer) do |v| instance_variable_set("@#{n}", v) end
|
137
|
+
end
|
138
|
+
|
139
|
+
opts.on('-H S', String) do |v| @H ||= []; @H << v; end
|
140
|
+
opts.on('-C S', String) do |v| @C ||= []; @C << v; end
|
141
|
+
|
142
|
+
opts.on('-b') do |v|
|
143
|
+
Stella.warn("-b is not an ab option. I'll pretend it's not there.")
|
144
|
+
end
|
145
|
+
|
146
|
+
opts.on('-r N',Integer) do |v|
|
147
|
+
Stella.error("-r is not an ab parameter. You probably want -n.")
|
148
|
+
exit 1
|
149
|
+
end
|
150
|
+
|
151
|
+
# NOTE: parse! removes the options it finds in @arguments. It will leave
|
152
|
+
# all unnamed arguments and throw a fit about unknown ones.
|
153
|
+
opts.parse!(arguments)
|
154
|
+
|
155
|
+
if arguments.empty?
|
156
|
+
Stella.error("You need to provide a URI")
|
157
|
+
exit 1
|
158
|
+
elsif arguments.size > 1
|
159
|
+
Stella.warn("ab can handle only one URI. The others will be ignored.")
|
160
|
+
arguments = arguments.first
|
161
|
+
else
|
162
|
+
# Let's make sure the URI has a path (at least a trailing slash). Otherwise
|
163
|
+
# ab gives a cryptic error.
|
164
|
+
begin
|
165
|
+
uri = URI.parse(arguments.first)
|
166
|
+
if !uri || uri.path.empty?
|
167
|
+
Stella.error("ab requires a trailing slash for #{uri.to_s}")
|
168
|
+
exit 1
|
169
|
+
end
|
170
|
+
rescue => ex
|
171
|
+
Stella.error("Bad URI: #{arguments.first}")
|
172
|
+
exit 1
|
173
|
+
end
|
174
|
+
end
|
175
|
+
|
176
|
+
self.arguments = arguments
|
177
|
+
|
178
|
+
rescue OptionParser::InvalidOption => ex
|
179
|
+
# We want to replace this text so we grab just the name of the argument
|
180
|
+
badarg = ex.message.gsub('invalid option: ', '')
|
181
|
+
raise InvalidArgument.new(badarg)
|
182
|
+
end
|
183
|
+
|
184
|
+
def after
|
185
|
+
# We want to maintain copies of all test output, even when the user has
|
186
|
+
# supplied other path names so we'll copy the files from the testrun directory
|
187
|
+
# to the location specified by the user.
|
188
|
+
# NOTE: For tests with more than one test run, the specified files will be
|
189
|
+
# overwritten after each run. Should we force append the run number?
|
190
|
+
[[@e, 'percentiles'], [@g, 'requests']].each do |tuple|
|
191
|
+
if File.expand_path(File.dirname(tuple[0])) != File.expand_path(@working_directory)
|
192
|
+
from = tuple[0]
|
193
|
+
to = @working_directory + "/ab-#{tuple[1]}.log"
|
194
|
+
next unless File.exists?(from)
|
195
|
+
FileUtils.cp(from, to)
|
196
|
+
end
|
197
|
+
end
|
198
|
+
|
199
|
+
|
200
|
+
end
|
201
|
+
|
202
|
+
|
203
|
+
|
204
|
+
|
205
|
+
def add_header(name, value)
|
206
|
+
@H ||= []
|
207
|
+
@H << "#{name}: #{value}"
|
208
|
+
end
|
209
|
+
|
210
|
+
def user_agent=(list=[])
|
211
|
+
return unless list && !list.empty?
|
212
|
+
list = list.to_ary
|
213
|
+
list.each do |agent|
|
214
|
+
add_header("User-Agent", agent)
|
215
|
+
end
|
216
|
+
end
|
217
|
+
|
218
|
+
def vusers
|
219
|
+
c || 0
|
220
|
+
end
|
221
|
+
def vusers=(v)
|
222
|
+
ratio = vuser_requests
|
223
|
+
@c = v
|
224
|
+
@n = ratio * @c
|
225
|
+
end
|
226
|
+
def requests
|
227
|
+
n || 0
|
228
|
+
end
|
229
|
+
def requests=(v)
|
230
|
+
@n = v
|
231
|
+
end
|
232
|
+
def vuser_requests
|
233
|
+
ratio = 1
|
234
|
+
# The request ratio tells us how many requests will be
|
235
|
+
# generated per vuser. It helps us later when we need to
|
236
|
+
# warmp up and ramp up.
|
237
|
+
if @n > 0 && @c > 0
|
238
|
+
ratio = (@n.to_f / @c.to_f).to_f
|
239
|
+
# If concurrency isn't set, we'll assume the total number of requests
|
240
|
+
# is intended to be per request
|
241
|
+
elsif @n > 0
|
242
|
+
ratio = @n
|
243
|
+
end
|
244
|
+
ratio
|
245
|
+
end
|
246
|
+
def c
|
247
|
+
(@c * @load_factor).to_i
|
248
|
+
end
|
249
|
+
def n
|
250
|
+
(@n * @load_factor).to_i
|
251
|
+
end
|
252
|
+
|
253
|
+
def hosts
|
254
|
+
hosts = @arguments || []
|
255
|
+
#hosts << get_hosts_from_file
|
256
|
+
hosts = hosts.map{ |h| tmp = URI.parse(h.strip); "#{tmp.host}:#{tmp.port}" }
|
257
|
+
hosts
|
258
|
+
end
|
259
|
+
|
260
|
+
def paths
|
261
|
+
paths = @arguments || []
|
262
|
+
#hosts << get_hosts_from_file
|
263
|
+
paths = paths.map{ |h| tmp = URI.parse(h.strip); "#{tmp.path}?#{tmp.query}" }
|
264
|
+
paths
|
265
|
+
end
|
266
|
+
|
267
|
+
|
268
|
+
|
269
|
+
# Apache bench writes the summary to STDOUT
|
270
|
+
def summary_file
|
271
|
+
File.new(stdout_path) if File.exists?(stdout_path)
|
272
|
+
end
|
273
|
+
|
274
|
+
def summary
|
275
|
+
return unless summary_file
|
276
|
+
raw = {}
|
277
|
+
summary_file.each_line { |l|
|
278
|
+
l.chomp!
|
279
|
+
nvpair = l.split(':')
|
280
|
+
next unless nvpair && nvpair.size == 2
|
281
|
+
n = nvpair[0].strip.tr(' ', '_').downcase[/\w+/]
|
282
|
+
v = nvpair[1].strip[/[\.\d]+/]
|
283
|
+
|
284
|
+
# Apache Bench outputs two fields with the name "Time per request".
|
285
|
+
# We want only the first one so we don't overwrite values.
|
286
|
+
raw[n.to_sym] = v.to_f unless raw.has_key? n.to_sym
|
287
|
+
}
|
288
|
+
|
289
|
+
# Document Path: /
|
290
|
+
# Document Length: 96 bytes
|
291
|
+
#
|
292
|
+
# Concurrency Level: 75
|
293
|
+
# Time taken for tests: 2.001 seconds
|
294
|
+
# Complete requests: 750
|
295
|
+
# Failed requests: 0
|
296
|
+
# Write errors: 0
|
297
|
+
# Total transferred: 174000 bytes
|
298
|
+
# HTML transferred: 72000 bytes
|
299
|
+
# Requests per second: 374.74 [#/sec] (mean)
|
300
|
+
# Time per request: 200.138 [ms] (mean)
|
301
|
+
# Time per request: 2.669 [ms] (mean, across all concurrent requests)
|
302
|
+
# Transfer rate: 84.90 [Kbytes/sec] received
|
303
|
+
|
304
|
+
stats = Stella::Test::Run::Summary.new
|
305
|
+
|
306
|
+
if !raw.empty? && raw.has_key?(:time_taken_for_tests)
|
307
|
+
|
308
|
+
stats.elapsed_time = raw[:time_taken_for_tests]
|
309
|
+
|
310
|
+
# We want this in MB, Apache Bench gives Bytes.
|
311
|
+
stats.data_transferred = ((raw[:html_transferred] || 0) / 1_048_576)
|
312
|
+
|
313
|
+
# total_transferred is header data + response data (html_transfered)
|
314
|
+
stats.headers_transferred = ((raw[:total_transferred] || 0) / 1_048_576) - stats.data_transferred
|
315
|
+
|
316
|
+
# Apache Bench returns ms
|
317
|
+
stats.response_time = (raw[:time_per_request] || 0) / 1000
|
318
|
+
stats.transaction_rate = raw[:requests_per_second]
|
319
|
+
|
320
|
+
stats.vusers = raw[:concurrency_level].to_i
|
321
|
+
stats.successful = raw[:complete_requests].to_i
|
322
|
+
stats.failed = raw[:failed_requests].to_i
|
323
|
+
|
324
|
+
stats.transactions = stats.successful + stats.failed
|
325
|
+
|
326
|
+
#stats.raw = raw if @global_options.debug
|
327
|
+
end
|
328
|
+
|
329
|
+
stats
|
330
|
+
end
|
331
|
+
|
332
|
+
|
333
|
+
|
334
|
+
end
|
335
|
+
|
336
|
+
end
|
337
|
+
end
|
@@ -0,0 +1,106 @@
|
|
1
|
+
|
2
|
+
|
3
|
+
module Stella::Adapter
|
4
|
+
class CommandNotReady < RuntimeError
|
5
|
+
def initialize(name="")
|
6
|
+
super(Stella::TEXT.msg(:error_adapter_command_not_ready, name))
|
7
|
+
end
|
8
|
+
end
|
9
|
+
|
10
|
+
class Base
|
11
|
+
|
12
|
+
|
13
|
+
attr_accessor :working_directory
|
14
|
+
attr_reader :load_factor, :arguments
|
15
|
+
|
16
|
+
def initialize(options={}, arguments=[])
|
17
|
+
if options.is_a? Array
|
18
|
+
self.process_arguments(options)
|
19
|
+
else
|
20
|
+
self.options = options
|
21
|
+
self.arguments = arguments
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
def load_factor=(load_factor)
|
26
|
+
@load_factor = load_factor
|
27
|
+
end
|
28
|
+
def stdout_path
|
29
|
+
File.join(@working_directory, 'STDOUT.txt')
|
30
|
+
end
|
31
|
+
|
32
|
+
def stderr_path
|
33
|
+
File.join(@working_directory, 'STDERR.txt')
|
34
|
+
end
|
35
|
+
|
36
|
+
def summary_path(ext='yaml')
|
37
|
+
File.join(@working_directory, "SUMMARY.#{ext}")
|
38
|
+
end
|
39
|
+
|
40
|
+
# process_arguments
|
41
|
+
#
|
42
|
+
# This method must be overridden by the implementing class. This is intended
|
43
|
+
# for processing the command-specific command-line arguments
|
44
|
+
def process_arguments
|
45
|
+
raise Stella::TEXT.msg(:error_class_must_override, 'process_options')
|
46
|
+
end
|
47
|
+
|
48
|
+
# options=
|
49
|
+
#
|
50
|
+
# Takes a hash, OpenStruct and applies the values to the instance variables.
|
51
|
+
# The keys should conincide with with the command line argument names.
|
52
|
+
# by process_options first and
|
53
|
+
# i.e. The key for --help should be :help
|
54
|
+
def options=(options={})
|
55
|
+
options = options.marshal_dump if options.is_a? OpenStruct
|
56
|
+
|
57
|
+
unless options.nil? || options.empty?
|
58
|
+
options.each_pair do |name,value|
|
59
|
+
next if @private_variables.member?(name)
|
60
|
+
Stella::LOGGER.info(:error_class_unknown_argument, name) && next unless self.respond_to?("#{name.to_s}=")
|
61
|
+
instance_variable_set("@#{name.to_s}", value)
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
def arguments=(arguments=[])
|
67
|
+
@arguments = arguments unless arguments.nil?
|
68
|
+
end
|
69
|
+
|
70
|
+
def available?
|
71
|
+
(version.to_f > 0)
|
72
|
+
end
|
73
|
+
|
74
|
+
def name
|
75
|
+
@name
|
76
|
+
end
|
77
|
+
|
78
|
+
def rate
|
79
|
+
@rate || 0
|
80
|
+
end
|
81
|
+
def vuser_rate
|
82
|
+
"#{vusers}/#{rate}"
|
83
|
+
end
|
84
|
+
|
85
|
+
def command
|
86
|
+
raise Stella::TEXT.msg(:error_class_must_override, 'command')
|
87
|
+
end
|
88
|
+
|
89
|
+
def summary
|
90
|
+
raise Stella::TEXT.msg(:error_class_must_override, 'summary')
|
91
|
+
end
|
92
|
+
|
93
|
+
def add_header
|
94
|
+
raise Stella::TEXT.msg(:error_class_must_override, 'add_header')
|
95
|
+
end
|
96
|
+
|
97
|
+
def user_agent=
|
98
|
+
raise Stella::TEXT.msg(:error_class_must_override, 'user_agent=')
|
99
|
+
end
|
100
|
+
|
101
|
+
private
|
102
|
+
|
103
|
+
|
104
|
+
end
|
105
|
+
end
|
106
|
+
|