solutious-stella 0.5.5
Sign up to get free protection for your applications and to get access to all the features.
- 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
|
+
|