stella 0.5.3 → 0.5.4
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 → 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
@@ -0,0 +1,278 @@
|
|
1
|
+
|
2
|
+
# TODO: Record cookies.
|
3
|
+
# TODO: Investigate packetfu: http://code.google.com/p/packetfu/
|
4
|
+
# TODO: Investigate Winpcap (http://www.winpcap.org/) and libpcap on Windows
|
5
|
+
|
6
|
+
module Stella
|
7
|
+
class CLI
|
8
|
+
class Watch < Stella::CLI::Base
|
9
|
+
|
10
|
+
|
11
|
+
def run
|
12
|
+
@options = process_arguments(@arguments)
|
13
|
+
|
14
|
+
if can_pcap?(@options[:usepcap])
|
15
|
+
require 'stella/adapter/pcap_watcher'
|
16
|
+
@watcher = Stella::Adapter::PcapWatcher.new(@options)
|
17
|
+
|
18
|
+
else
|
19
|
+
require 'stella/adapter/proxy_watcher'
|
20
|
+
@watcher = Stella::Adapter::ProxyWatcher.new(@options)
|
21
|
+
|
22
|
+
# if can_pcap? returned false, but pcap was requested then we'll
|
23
|
+
# call check_pcap to raise the reason why it didn't load.
|
24
|
+
if @options[:usepcap]
|
25
|
+
check_pcap
|
26
|
+
exit 0
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
# We use an observer model so the watcher class will notify us
|
31
|
+
# when they have new data. They call the update method below.
|
32
|
+
@watcher.add_observer(self)
|
33
|
+
|
34
|
+
if @options[:record]
|
35
|
+
|
36
|
+
@record_filepath = generate_record_filepath
|
37
|
+
Stella::LOGGER.info("Writing to #{@record_filepath}")
|
38
|
+
|
39
|
+
if File.exists?(@record_filepath)
|
40
|
+
Stella::LOGGER.error("#{@record_filepath} exists")
|
41
|
+
if @stella_options.force
|
42
|
+
Stella::LOGGER.error("But I'll overwrite it and continue because you forced me too!")
|
43
|
+
else
|
44
|
+
exit 1
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
end
|
49
|
+
|
50
|
+
Stella::LOGGER.info("Filter: #{@options[:filter]}") if @options[:filter]
|
51
|
+
Stella::LOGGER.info("Domain: #{@options[:domain]}") if @options[:domain]
|
52
|
+
|
53
|
+
# Turn wildcards into regular expressions
|
54
|
+
@options[:filter].gsub!('*', '.*') if @options[:filter]
|
55
|
+
@options[:domain].gsub!('*', '.*') if @options[:domain]
|
56
|
+
|
57
|
+
# Used to calculated user think times for session output
|
58
|
+
@think_time = 0
|
59
|
+
|
60
|
+
@watcher.run
|
61
|
+
|
62
|
+
end
|
63
|
+
|
64
|
+
|
65
|
+
|
66
|
+
# update
|
67
|
+
#
|
68
|
+
# This method is called from the watcher class when data is updated.
|
69
|
+
# +service+ is one of: domain, http_request, http_response
|
70
|
+
# +data+ is a string of TCP packet data. The format depends on the value of +service+.
|
71
|
+
def update(service, data_object)
|
72
|
+
|
73
|
+
begin
|
74
|
+
if @options[:record] && !@file_created_already
|
75
|
+
|
76
|
+
if File.exists?(@record_filepath)
|
77
|
+
if @stella_options.force
|
78
|
+
@record_file = FileUtil.create_file(@record_filepath, 'w', '.', :force)
|
79
|
+
else
|
80
|
+
exit 1
|
81
|
+
end
|
82
|
+
else
|
83
|
+
@record_file = FileUtil.create_file(@record_filepath, 'w', '.')
|
84
|
+
end
|
85
|
+
|
86
|
+
raise StellaError.new("Cannot open: #{@record_filepath}") unless @record_file
|
87
|
+
|
88
|
+
@file_created_already = true
|
89
|
+
end
|
90
|
+
rescue => ex
|
91
|
+
raise StellaError.new("Error creating file: #{ex.message}")
|
92
|
+
end
|
93
|
+
|
94
|
+
# TODO: combine requests and responses
|
95
|
+
# Disabled until we have a way to combine request and response objects (otherwise
|
96
|
+
# the requests are filters out but the responses are not).
|
97
|
+
#return if @options[:filter] && !(data_object.raw_data.to_s =~ /#{@options[:filter]}/i)
|
98
|
+
#return if @options[:domain] && !(data_object.uri.to_s =~ /(www.)?#{@options[:domain]}/i)
|
99
|
+
|
100
|
+
if @stella_options.format && data_object.respond_to?("to_#{@stella_options.format}")
|
101
|
+
Stella::LOGGER.info(data_object.send("to_#{@stella_options.format}"))
|
102
|
+
|
103
|
+
if data_object.has_response?
|
104
|
+
Stella::LOGGER.info(data_object.response.send("to_#{@stella_options.format}"))
|
105
|
+
end
|
106
|
+
|
107
|
+
else
|
108
|
+
if @stella_options.verbose > 1
|
109
|
+
Stella::LOGGER.info(data_object.inspect, '')
|
110
|
+
|
111
|
+
if data_object.has_response?
|
112
|
+
Stella::LOGGER.info(data_object.response.inspect, '', '')
|
113
|
+
end
|
114
|
+
|
115
|
+
elsif @stella_options.verbose > 0
|
116
|
+
Stella::LOGGER.info(data_object.to_s)
|
117
|
+
Stella::LOGGER.info(data_object.body) if data_object.has_body?
|
118
|
+
|
119
|
+
if data_object.has_response?
|
120
|
+
Stella::LOGGER.info(data_object.response.to_s)
|
121
|
+
Stella::LOGGER.info(data_object.response.body) if data_object.response.has_body?
|
122
|
+
end
|
123
|
+
|
124
|
+
else
|
125
|
+
Stella::LOGGER.info(data_object.to_s)
|
126
|
+
Stella::LOGGER.info(data_object.response.to_s) if data_object.has_response?
|
127
|
+
|
128
|
+
end
|
129
|
+
end
|
130
|
+
|
131
|
+
rescue Exception => ex
|
132
|
+
Stella::LOGGER.error(ex)
|
133
|
+
#exit 1
|
134
|
+
end
|
135
|
+
|
136
|
+
|
137
|
+
|
138
|
+
# can_pcap?
|
139
|
+
#
|
140
|
+
# Returns true is pcap is available
|
141
|
+
def can_pcap?(usepcap=false)
|
142
|
+
return false unless usepcap
|
143
|
+
begin
|
144
|
+
check_pcap
|
145
|
+
rescue
|
146
|
+
return false
|
147
|
+
end
|
148
|
+
return true
|
149
|
+
end
|
150
|
+
|
151
|
+
# check_pcap
|
152
|
+
#
|
153
|
+
# The Pcap gauntlet. A number of conditions must be met to run the Pcap recorder:
|
154
|
+
# - The watch command must be called with -p
|
155
|
+
# - The OS must be a form of Unix
|
156
|
+
# - Cannot be running via JRuby or Java
|
157
|
+
# - The user must be root (or running through sudo)
|
158
|
+
# - The Ruby-Pcap library must be installed.
|
159
|
+
def check_pcap(usepcap=false)
|
160
|
+
raise MissingDependency.new('pcap', :error_sysinfo_notunix) unless Stella::SYSINFO.os === :unix # pcap not available on windows or java
|
161
|
+
raise MissingDependency.new('pcap', :error_sysinfo_notroot) unless ENV['USER'] === 'root' # Must run as root or sudo
|
162
|
+
begin
|
163
|
+
require 'pcap'
|
164
|
+
rescue Exception, LoadError => ex
|
165
|
+
raise MissingDependency.new('pcap', :error_watch_norubypcap)
|
166
|
+
end
|
167
|
+
false
|
168
|
+
end
|
169
|
+
|
170
|
+
def generate_record_filepath
|
171
|
+
filepath = nil
|
172
|
+
|
173
|
+
if (@options[:record].is_a? String)
|
174
|
+
filepath = File.expand_path(@options[:record])
|
175
|
+
else
|
176
|
+
now = DateTime.now
|
177
|
+
daystr = "#{now.year}-#{now.mon.to_s.rjust(2,'0')}-#{now.mday.to_s.rjust(2,'0')}"
|
178
|
+
dirpath = File.join(@working_directory, 'stories', daystr)
|
179
|
+
|
180
|
+
FileUtil.create_dir(dirpath, ".")
|
181
|
+
filepath = File.join(dirpath, 'story')
|
182
|
+
testnum = 1.to_s.rjust(2,'0')
|
183
|
+
testnum.succ! while(File.exists? "#{filepath}-#{testnum}.txt")
|
184
|
+
filepath = "#{filepath}-#{testnum}.txt"
|
185
|
+
end
|
186
|
+
|
187
|
+
return filepath
|
188
|
+
end
|
189
|
+
|
190
|
+
def after
|
191
|
+
# Close Pcap / Shutdown Proxy
|
192
|
+
@watcher.after
|
193
|
+
|
194
|
+
# We don't need to close or delete a file that wasn't created
|
195
|
+
return unless @record_file
|
196
|
+
|
197
|
+
# And we don't want to delete a file that we're overwriting but may
|
198
|
+
# not have actually written anything to yet. IOW, original file will
|
199
|
+
# remain intact if we haven't written anything to it yet.
|
200
|
+
@record_file.close if @forced_overwrite
|
201
|
+
|
202
|
+
# Delete an empty file, otherwise close it
|
203
|
+
@record_file.stat.size == 0 ? File.unlink(@record_file.path) : @record_file.close
|
204
|
+
end
|
205
|
+
|
206
|
+
def process_arguments(arguments, display=false)
|
207
|
+
opts = OptionParser.new
|
208
|
+
|
209
|
+
opts.banner = "Usage: #{File.basename($0)} [global options] watch [command options] [http|dns]"
|
210
|
+
opts.on("#{$/}Example: #{File.basename($0)} -v watch -C http#{$/}")
|
211
|
+
opts.on('-h', '--help', "Display this message") do
|
212
|
+
Stella::LOGGER.info opts
|
213
|
+
exit 0
|
214
|
+
end
|
215
|
+
|
216
|
+
opts.on("#{$/}Operating mode")
|
217
|
+
opts.on('-P', '--useproxy', "Use an HTTP proxy to filter requests (default)") do |v| v end
|
218
|
+
opts.on('-C', '--usepcap', "Use Pcap to filter TCP packets") do |v| v end
|
219
|
+
#opts.on('-F', '--usepacketfu', "Use Packetfu to filter TCP packets") do |v| v end
|
220
|
+
|
221
|
+
opts.on("#{$/}Pcap-specific options")
|
222
|
+
opts.on('-i=S', '--interface=S', String, "Network device. eri0, en1, etc. (with --usepcap only)") do |v| v end
|
223
|
+
opts.on('-m=N', '--maxpacks=N', Integer, "Maximum number of packets to sniff (with --usepcap only)") do |v| v end
|
224
|
+
opts.on('-R=S', '--protocol=S', String, "Communication protocol to sniff. udp or tcp (with --usepcap only)") do |v| v end
|
225
|
+
|
226
|
+
opts.on("#{$/}Common options")
|
227
|
+
opts.on('-p=N', '--port=N', Integer, "With --useproxy this is the Proxy port. With --usecap this is the TCP port to filter. ") do |v| v end
|
228
|
+
#opts.on('-f=S', '--filter=S', String, "Filter out requests which do not contain this string") do |v| v end
|
229
|
+
#opts.on('-d=S', '--domain=S', String, "Only display requests to the given domain") do |v| v end
|
230
|
+
#opts.on('-r=S', '--record=S', String, "Record requests to file with an optional filename") do |v| v || true end
|
231
|
+
#opts.on('-F=S', '--format=S', "Format of recorded file. One of: simple (for Siege), session (for Httperf)") do |v| v end
|
232
|
+
|
233
|
+
options = opts.getopts(@arguments)
|
234
|
+
options = options.keys.inject({}) do |hash, key|
|
235
|
+
hash[key.to_sym] = options[key]
|
236
|
+
hash
|
237
|
+
end
|
238
|
+
|
239
|
+
# "interface" is more clear on the command line but we use "device" internally
|
240
|
+
options[:device] = options.delete(:interface) if options[:interface]
|
241
|
+
options[:service] = arguments.shift unless arguments.empty?
|
242
|
+
|
243
|
+
options
|
244
|
+
end
|
245
|
+
|
246
|
+
end
|
247
|
+
|
248
|
+
@@commands['watch'] = Stella::CLI::Watch
|
249
|
+
end
|
250
|
+
end
|
251
|
+
|
252
|
+
|
253
|
+
__END__
|
254
|
+
|
255
|
+
# pageload?
|
256
|
+
#
|
257
|
+
# Used while writing the session log file. Returns true when we
|
258
|
+
# suspect a new page has loaded. Otherwise the resource is considered
|
259
|
+
# to be a dependency.
|
260
|
+
def pageload?(now, think_time, host, referer, content_type)
|
261
|
+
time_difference = (now.to_i - @think_time.to_i)
|
262
|
+
time_passed = (@think_time == 0 || time_difference > 4)
|
263
|
+
non_html = (content_type !~ /text\/html/i) if content_type
|
264
|
+
#puts "POOO: #{content_type} #{referer}"
|
265
|
+
|
266
|
+
case [time_passed, non_html]
|
267
|
+
when [true,false]
|
268
|
+
return true
|
269
|
+
when [true,true]
|
270
|
+
return false
|
271
|
+
when [true,nil]
|
272
|
+
return true
|
273
|
+
when [false,false]
|
274
|
+
return false
|
275
|
+
else
|
276
|
+
return false
|
277
|
+
end
|
278
|
+
end
|
data/lib/stella/cli.rb
CHANGED
@@ -1,4 +1,6 @@
|
|
1
1
|
|
2
|
+
# http://www.ruby-doc.org/stdlib/libdoc/observer/rdoc/index.html
|
3
|
+
|
2
4
|
require 'optparse'
|
3
5
|
require 'ostruct'
|
4
6
|
|
@@ -10,8 +12,11 @@ module Stella
|
|
10
12
|
#
|
11
13
|
# This Config class manages the content of ENV['HOME]/.stella. The functionality
|
12
14
|
# is currently disabled so stella is stateless.
|
15
|
+
# RUBY_PLATFORM = 'java' in jruby and i386-mswin32 for windows
|
13
16
|
class Config < Storable
|
14
|
-
|
17
|
+
USER_HOME = ENV['USERPROFILE'] || ENV['HOME']
|
18
|
+
STELLA_DIR = '.stella'
|
19
|
+
DEFAULT_HOME = File.join(USER_HOME, STELLA_DIR).freeze unless defined? DEFAULT_HOME
|
15
20
|
DEFAULT_DATA_HOME = File.join(Dir.getwd, 'stella').freeze unless defined? DEFAULT_DATA_HOME
|
16
21
|
|
17
22
|
attr_accessor :conf_path, :data_path
|
@@ -69,6 +74,8 @@ module Stella
|
|
69
74
|
@options.data_path = @config.working_directory
|
70
75
|
@options.agents = []
|
71
76
|
|
77
|
+
@stella_arguments = []
|
78
|
+
@command_arguments = []
|
72
79
|
end
|
73
80
|
|
74
81
|
def commands
|
@@ -76,6 +83,7 @@ module Stella
|
|
76
83
|
end
|
77
84
|
|
78
85
|
def run
|
86
|
+
|
79
87
|
process_arguments
|
80
88
|
process_options
|
81
89
|
|
@@ -89,14 +97,12 @@ module Stella
|
|
89
97
|
command = @@commands[@command_name].new(@command_name)
|
90
98
|
|
91
99
|
# Give the command object access to the config and runtime options
|
92
|
-
#command.global_config = @config
|
93
100
|
command.stella_options = @options
|
94
101
|
command.arguments = @command_arguments
|
95
102
|
command.working_directory = @options.data_path
|
96
103
|
|
97
104
|
command.run
|
98
105
|
|
99
|
-
|
100
106
|
rescue => ex
|
101
107
|
Stella::LOGGER.error(ex)
|
102
108
|
end
|
@@ -122,9 +128,9 @@ module Stella
|
|
122
128
|
break
|
123
129
|
end
|
124
130
|
end
|
125
|
-
|
126
|
-
@
|
127
|
-
@
|
131
|
+
|
132
|
+
@stella_arguments = [] unless @stella_arguments
|
133
|
+
@command_arguments = [] unless @command_arguments
|
128
134
|
|
129
135
|
# If there's no command we'll assume all the options are for Stella
|
130
136
|
unless @command_name
|
@@ -143,7 +149,7 @@ module Stella
|
|
143
149
|
|
144
150
|
opts = OptionParser.new
|
145
151
|
opts.banner = Stella::TEXT.msg(:option_help_usage)
|
146
|
-
opts.on Stella::TEXT.msg(:option_help_preamble, @@commands.keys.join(', '))
|
152
|
+
opts.on Stella::TEXT.msg(:option_help_preamble, @@commands.keys.sort.join(', '))
|
147
153
|
|
148
154
|
opts.on(Stella::TEXT.msg(:option_help_options_title))
|
149
155
|
opts.on('-V', '--version', Stella::TEXT.msg(:option_help_version)) do
|
@@ -151,8 +157,10 @@ module Stella
|
|
151
157
|
exit 0
|
152
158
|
end
|
153
159
|
opts.on('-h', '--help', Stella::TEXT.msg(:option_help_help)) { puts opts; exit 0 }
|
160
|
+
opts.on('-F', '--force', Stella::TEXT.msg(:option_help_force)) { |v| @options.force = true }
|
154
161
|
|
155
162
|
opts.on('-v', '--verbose', Stella::TEXT.msg(:option_help_verbose)) do
|
163
|
+
|
156
164
|
@options.verbose ||= 0
|
157
165
|
@options.verbose += 1
|
158
166
|
end
|
@@ -189,8 +197,8 @@ module Stella
|
|
189
197
|
@options.rampup = amount
|
190
198
|
end
|
191
199
|
|
192
|
-
opts.on('-x', '--
|
193
|
-
@options.
|
200
|
+
opts.on('-x', '--repetitions=N', Integer, Stella::TEXT.msg(:option_help_testreps)) do |v|
|
201
|
+
@options.repetitions = MathUtil.enforce_limit(v,1,99)
|
194
202
|
end
|
195
203
|
|
196
204
|
opts.on('-w [N]', '--warmup', Float, Stella::TEXT.msg(:option_help_warmup, 0.1)) do |v|
|
@@ -282,10 +290,14 @@ end
|
|
282
290
|
|
283
291
|
# Autoload CLI classes. These classes add themselves to the class variable @@commands.
|
284
292
|
begin
|
293
|
+
previous_path = ""
|
285
294
|
cli_classes = Dir.glob(File.join(STELLA_HOME, 'lib', 'stella', 'cli', "*.rb"))
|
286
295
|
cli_classes.each do |path|
|
296
|
+
previous_path = path
|
287
297
|
require path
|
288
298
|
end
|
289
299
|
rescue LoadError => ex
|
290
|
-
Stella::LOGGER.info("Error loading #{
|
291
|
-
end
|
300
|
+
Stella::LOGGER.info("Error loading #{previous_path}: #{ex.message}")
|
301
|
+
end
|
302
|
+
|
303
|
+
|
data/lib/stella/command/base.rb
CHANGED
@@ -1,5 +1,5 @@
|
|
1
1
|
|
2
|
-
|
2
|
+
|
3
3
|
module Stella::Command
|
4
4
|
class Base
|
5
5
|
|
@@ -98,14 +98,5 @@ module Stella::Command
|
|
98
98
|
end
|
99
99
|
|
100
100
|
|
101
|
-
#
|
102
|
-
# Generates a string of random alphanumeric characters
|
103
|
-
# These are used as IDs throughout the system
|
104
|
-
def strand( len )
|
105
|
-
chars = ("a".."z").to_a + ("0".."9").to_a
|
106
|
-
newpass = ""
|
107
|
-
1.upto(len) { |i| newpass << chars[rand(chars.size-1)] }
|
108
|
-
return newpass
|
109
|
-
end
|
110
101
|
end
|
111
102
|
end
|
@@ -2,9 +2,7 @@
|
|
2
2
|
|
3
3
|
module Stella
|
4
4
|
class LocalTest < Stella::Command::Base
|
5
|
-
|
6
|
-
|
7
|
-
|
5
|
+
|
8
6
|
# A container for the test parameters
|
9
7
|
attr_accessor :testdef
|
10
8
|
# The load tool adapter
|
@@ -33,7 +31,8 @@ module Stella
|
|
33
31
|
@testdef = testdef if testdef
|
34
32
|
@adapter = adapter if adapter
|
35
33
|
|
36
|
-
|
34
|
+
# Disabled until we resolve JRuby on OSX issue (won't load openssl)
|
35
|
+
#@guid = Crypto.sign(rand.to_s, rand.to_s)
|
37
36
|
|
38
37
|
@test_runpaths = []
|
39
38
|
@all_runpaths = []
|
@@ -64,9 +63,9 @@ module Stella
|
|
64
63
|
|
65
64
|
raise UnavailableAdapter.new(@adapter.name) unless @adapter.available?
|
66
65
|
|
66
|
+
# If the adapter isn't being called for a loadtest, we don't have anything to do.
|
67
67
|
unless @adapter.loadtest?
|
68
68
|
system(@adapter.command)
|
69
|
-
|
70
69
|
return
|
71
70
|
end
|
72
71
|
|
@@ -157,6 +156,11 @@ module Stella
|
|
157
156
|
save_summary(File.join(test_path, "SUMMARY-RAMPUP.#{@format}"), test_stats)
|
158
157
|
print_summary(test_stats) if (@testdef.repetitions > 1)
|
159
158
|
end
|
159
|
+
rescue Interrupt
|
160
|
+
puts "HIHIHI2222"
|
161
|
+
exit
|
162
|
+
rescue AdapterError => ex
|
163
|
+
Stella::LOGGER.error(ex.message)
|
160
164
|
end
|
161
165
|
|
162
166
|
def latest_test_symlink_path
|
@@ -181,11 +185,12 @@ module Stella
|
|
181
185
|
# Make sure the test storage directory is created along with the
|
182
186
|
# latest symlink
|
183
187
|
FileUtil.create_dir(test_path)
|
184
|
-
File.unlink(latest_test_symlink_path) if File.exists?(latest_test_symlink_path)
|
185
|
-
File.symlink(File.expand_path(test_path), latest_test_symlink_path)
|
188
|
+
#File.unlink(latest_test_symlink_path) if File.exists?(latest_test_symlink_path)
|
189
|
+
#File.symlink(File.expand_path(test_path), latest_test_symlink_path)
|
186
190
|
|
187
191
|
# Write the test ID to the storage directory
|
188
|
-
|
192
|
+
# NOTE: Disabled until we resolve the issue with JRuby on OSX (won't load openssl)
|
193
|
+
#FileUtil.write_file(test_path + "/ID.txt", @guid, true)
|
189
194
|
|
190
195
|
# And the test run message
|
191
196
|
FileUtil.write_file(test_path + "/MESSAGE.txt", @testdef.message, true) if @testdef.message
|
@@ -241,25 +246,37 @@ module Stella
|
|
241
246
|
FileUtil.write_file(runpath + "/COMMAND.txt", @adapter.command, true)
|
242
247
|
|
243
248
|
# Execute the command, send STDOUT and STDERR to separate files.
|
244
|
-
command = "#{@adapter.command} 1>
|
249
|
+
command = "#{@adapter.command} 1> \"#{@adapter.stdout_path}\" 2> \"#{@adapter.stderr_path}\""
|
245
250
|
Stella::LOGGER.info(" COMMAND: #{command}") if @verbose >= 2
|
246
|
-
|
247
|
-
|
248
|
-
|
249
|
-
|
250
|
-
|
251
|
-
|
251
|
+
|
252
|
+
begin
|
253
|
+
# Call the load tool
|
254
|
+
# $? contains the error status
|
255
|
+
succeeded = system(command)
|
256
|
+
|
257
|
+
# TODO: Catch interrupts for system calls. Currently it will simply and and continue with the next command
|
258
|
+
# i.e. these don't work:
|
259
|
+
rescue Interrupt
|
260
|
+
exit
|
261
|
+
rescue SystemExit
|
262
|
+
exit
|
263
|
+
end
|
264
|
+
|
265
|
+
unless succeeded
|
266
|
+
Stella::LOGGER.info('', '') # We used print so we need a new line for the error message.
|
267
|
+
raise AdapterError.new(@adapter.name, @adapter.error)
|
268
|
+
end
|
269
|
+
|
252
270
|
stats = @adapter.stats
|
253
271
|
|
254
272
|
save_summary(@adapter.summary_path(@format), stats)
|
255
273
|
|
256
274
|
|
257
|
-
|
258
|
-
Stella::LOGGER.info_print(sprintf("%3.0f%% %9.2f/s %8.3fs ", stats.availability, stats.transaction_rate, stats.response_time))
|
259
|
-
Stella::LOGGER.info_print(sprintf("%8.3fMB/s %8.3fMB %8.3fs ", stats.throughput, stats.data_transferred, stats.elapsed_time))
|
275
|
+
if !@quiet && stats && stats.available?
|
276
|
+
Stella::LOGGER.info_print(sprintf("%3.0f%% %9.2f/s %8.3fs ", stats.availability || 0, stats.transaction_rate || 0, stats.response_time || 0))
|
277
|
+
Stella::LOGGER.info_print(sprintf("%8.3fMB/s %8.3fMB %8.3fs ", stats.throughput || 0, stats.data_transferred || 0, stats.elapsed_time || 0))
|
260
278
|
# NOTE: We don't print a line terminator here
|
261
279
|
end
|
262
|
-
|
263
280
|
end
|
264
281
|
end
|
265
282
|
|
@@ -274,10 +291,10 @@ module Stella
|
|
274
291
|
def print_summary(stats)
|
275
292
|
Stella::LOGGER.info(' ' << "-"*67) unless @quiet
|
276
293
|
|
277
|
-
Stella::LOGGER.info_printf("%8s: %10d@%-6d%
|
278
|
-
Stella::LOGGER.info_printf("%8.3fs %8.3fMB/s %8.3fMB %8.3fs", stats.response_time_avg, stats.throughput_avg, stats.data_transferred_total, stats.elapsed_time_total)
|
294
|
+
Stella::LOGGER.info_printf("%8s: %10d@%-6d %3.0f%% %9.2f/s ", "Total", stats.transactions_total || 0, stats.vusers_avg || 0, stats.availability || 0, stats.transaction_rate_avg || 0)
|
295
|
+
Stella::LOGGER.info_printf("%8.3fs %8.3fMB/s %8.3fMB %8.3fs", stats.response_time_avg || 0, stats.throughput_avg || 0, stats.data_transferred_total || 0, stats.elapsed_time_total || 0)
|
279
296
|
Stella::LOGGER.info('') # New line
|
280
|
-
Stella::LOGGER.info_printf("%8s: %22s %9.2f/s %8.3fs %8.3fMB/s %10s %8.3fs", "Std Dev", '', stats.transaction_rate_sdev, stats.response_time_sdev, stats.throughput_sdev, '', stats.elapsed_time_sdev)
|
297
|
+
Stella::LOGGER.info_printf("%8s: %22s %9.2f/s %8.3fs %8.3fMB/s %10s %8.3fs", "Std Dev", '', stats.transaction_rate_sdev || 0, stats.response_time_sdev || 0, stats.throughput_sdev || 0, '', stats.elapsed_time_sdev || 0)
|
281
298
|
Stella::LOGGER.info('') # New line
|
282
299
|
Stella::LOGGER.info('') unless @quiet # Extra new line
|
283
300
|
end
|
@@ -303,16 +320,19 @@ module Stella
|
|
303
320
|
# filepath:: the complete path for the file (string)
|
304
321
|
# stats:: Any object that extends Stella::Test::Base object
|
305
322
|
def save_summary(filepath, stats)
|
306
|
-
FileUtil.write_file(filepath, stats.dump(@format, :with_titles), true)
|
323
|
+
FileUtil.write_file(filepath, stats.dump(@format, :with_titles), true) if stats
|
307
324
|
end
|
308
325
|
|
309
326
|
# Load SUMMARY file for each run and create a summary with
|
310
327
|
# totals, averages, and standard deviations.
|
311
328
|
def process_test_stats(paths)
|
329
|
+
return unless paths && !paths.empty?
|
312
330
|
test_stats = Stella::Test::Summary.new(@message)
|
331
|
+
return unless test_stats
|
313
332
|
all_stats_obj = []
|
314
333
|
paths.each do |path|
|
315
334
|
file_contents = FileUtil.read_file_to_array("#{path}/SUMMARY.#{@format}")
|
335
|
+
next if !file_contents || file_contents.empty?
|
316
336
|
stats = Stella::Test::Run::Summary.undump(@format, file_contents)
|
317
337
|
stats_obj = Stella::Test::Run::Summary.from_hash(stats)
|
318
338
|
test_stats.add_run(stats_obj)
|
@@ -0,0 +1,75 @@
|
|
1
|
+
|
2
|
+
|
3
|
+
module Stella::Data
|
4
|
+
class DomainRequest < Stella::Storable
|
5
|
+
attr_accessor :time, :client_ip, :server_ip, :dns_data, :domain_name, :header
|
6
|
+
attr_reader :raw_data
|
7
|
+
|
8
|
+
def initialize(raw_data)
|
9
|
+
@raw_data = raw_data
|
10
|
+
@dns_data, @domain_name, @header = DomainUtil::parse_domain_request(@raw_data)
|
11
|
+
end
|
12
|
+
|
13
|
+
def has_request?
|
14
|
+
false
|
15
|
+
end
|
16
|
+
def has_response?
|
17
|
+
false
|
18
|
+
end
|
19
|
+
def has_body?
|
20
|
+
false
|
21
|
+
end
|
22
|
+
|
23
|
+
def field_names
|
24
|
+
[ :time, :client_ip, :server_ip, :domain_name, :header ]
|
25
|
+
end
|
26
|
+
|
27
|
+
def to_s
|
28
|
+
"%s: %s -> %s (%s)" % [@time, @client_ip, @server_ip, @domain_name]
|
29
|
+
end
|
30
|
+
|
31
|
+
def inspect
|
32
|
+
str = "#{$/};; REQUEST #{@time.to_s}"
|
33
|
+
str << "#{$/};; %s %s> %s" % [@client_ip, '-'*30, @server_ip]
|
34
|
+
str << "#{$/};;#{$/}"
|
35
|
+
str << @dns_data.inspect
|
36
|
+
str
|
37
|
+
end
|
38
|
+
|
39
|
+
end
|
40
|
+
|
41
|
+
class DomainResponse < Stella::Storable
|
42
|
+
attr_accessor :time, :client_ip, :server_ip, :dns_data, :domain_name, :header, :addresses, :cnames
|
43
|
+
attr_reader :raw_data
|
44
|
+
|
45
|
+
def initialize(raw_data)
|
46
|
+
@raw_data = raw_data
|
47
|
+
@dns_data, @domain_name, @header, @addresses, @cnames = DomainUtil::parse_domain_response(@raw_data)
|
48
|
+
end
|
49
|
+
|
50
|
+
def has_request?
|
51
|
+
false
|
52
|
+
end
|
53
|
+
def has_response?
|
54
|
+
false
|
55
|
+
end
|
56
|
+
def has_body?
|
57
|
+
false
|
58
|
+
end
|
59
|
+
|
60
|
+
def field_names
|
61
|
+
[ :time, :client_ip, :server_ip, :dns_data, :domain_name, :header, :addresses, :cnames ]
|
62
|
+
end
|
63
|
+
|
64
|
+
def to_s
|
65
|
+
"%s: %s <- %s (%s) %s" % [@time, @client_ip, @server_ip, @domain_name, (@addresses || []).join(',')]
|
66
|
+
end
|
67
|
+
|
68
|
+
def inspect
|
69
|
+
str = "#{$/};; RESPONSE #{@time.strftime(NICE_TIME_FORMAT)}"
|
70
|
+
str << "#{$/};; %s <%s %s" % [@client_ip, '-'*30, @server_ip]
|
71
|
+
str << "#{$/};;#{$/}"
|
72
|
+
str << @dns_data.inspect
|
73
|
+
end
|
74
|
+
end
|
75
|
+
end
|