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.
Files changed (88) hide show
  1. data/{README.txt → README.textile} +63 -40
  2. data/Rakefile +7 -5
  3. data/bin/stella +1 -1
  4. data/bin/stella.bat +12 -0
  5. data/lib/pcaplet.rb +180 -0
  6. data/lib/stella/adapter/ab.rb +57 -33
  7. data/lib/stella/adapter/base.rb +11 -1
  8. data/lib/stella/adapter/httperf.rb +13 -10
  9. data/lib/stella/adapter/pcap_watcher.rb +221 -0
  10. data/lib/stella/adapter/proxy_watcher.rb +76 -0
  11. data/lib/stella/adapter/siege.rb +28 -11
  12. data/lib/stella/cli/agents.rb +2 -2
  13. data/lib/stella/cli/base.rb +37 -1
  14. data/lib/stella/cli/localtest.rb +1 -2
  15. data/lib/stella/cli/sysinfo.rb +17 -0
  16. data/lib/stella/cli/watch.rb +278 -0
  17. data/lib/stella/cli.rb +23 -11
  18. data/lib/stella/command/base.rb +1 -10
  19. data/lib/stella/command/localtest.rb +43 -23
  20. data/lib/stella/data/domain.rb +75 -0
  21. data/lib/stella/data/http.rb +124 -0
  22. data/lib/stella/logger.rb +16 -5
  23. data/lib/stella/storable.rb +4 -2
  24. data/lib/stella/support.rb +71 -0
  25. data/lib/stella/sysinfo.rb +247 -0
  26. data/lib/stella/test/base.rb +5 -1
  27. data/lib/stella/test/definition.rb +1 -1
  28. data/lib/stella/test/run/summary.rb +14 -4
  29. data/lib/stella/text/resource.rb +0 -1
  30. data/lib/stella.rb +28 -10
  31. data/lib/utils/domainutil.rb +47 -0
  32. data/lib/utils/fileutil.rb +22 -3
  33. data/lib/utils/httputil.rb +184 -128
  34. data/lib/utils/mathutil.rb +20 -7
  35. data/lib/win32/Console/ANSI.rb +305 -0
  36. data/lib/win32/Console.rb +970 -0
  37. data/spec/show-agents_spec.rb +0 -0
  38. data/support/kvm.h +91 -0
  39. data/support/ruby-pcap-takuma-notes.txt +19 -0
  40. data/support/ruby-pcap-takuma-patch.txt +30 -0
  41. data/support/text/en.yaml +26 -3
  42. data/vendor/frylock/README.textile +72 -0
  43. data/vendor/frylock/bin/example +170 -0
  44. data/vendor/frylock/frylock.gemspec +18 -0
  45. data/vendor/frylock/lib/frylock/exceptions.rb +24 -0
  46. data/vendor/frylock/lib/frylock.rb +232 -0
  47. data/vendor/frylock/test/command_test.rb +33 -0
  48. data/vendor/hitimes-0.4.0/HISTORY +28 -0
  49. data/vendor/hitimes-0.4.0/LICENSE.txt +19 -0
  50. data/vendor/hitimes-0.4.0/README +80 -0
  51. data/vendor/hitimes-0.4.0/Rakefile +63 -0
  52. data/vendor/hitimes-0.4.0/examples/benchmarks.rb +86 -0
  53. data/vendor/hitimes-0.4.0/examples/stats.rb +29 -0
  54. data/vendor/hitimes-0.4.0/ext/extconf.rb +15 -0
  55. data/vendor/hitimes-0.4.0/ext/hitimes_ext.c +21 -0
  56. data/vendor/hitimes-0.4.0/ext/hitimes_instant_clock_gettime.c +20 -0
  57. data/vendor/hitimes-0.4.0/ext/hitimes_instant_osx.c +16 -0
  58. data/vendor/hitimes-0.4.0/ext/hitimes_instant_windows.c +27 -0
  59. data/vendor/hitimes-0.4.0/ext/hitimes_interval.c +340 -0
  60. data/vendor/hitimes-0.4.0/ext/hitimes_interval.h +73 -0
  61. data/vendor/hitimes-0.4.0/ext/hitimes_stats.c +242 -0
  62. data/vendor/hitimes-0.4.0/ext/hitimes_stats.h +30 -0
  63. data/vendor/hitimes-0.4.0/ext/rbconfig-mingw.rb +178 -0
  64. data/vendor/hitimes-0.4.0/ext/rbconfig.rb +178 -0
  65. data/vendor/hitimes-0.4.0/gemspec.rb +54 -0
  66. data/vendor/hitimes-0.4.0/lib/hitimes/mutexed_stats.rb +23 -0
  67. data/vendor/hitimes-0.4.0/lib/hitimes/paths.rb +54 -0
  68. data/vendor/hitimes-0.4.0/lib/hitimes/stats.rb +29 -0
  69. data/vendor/hitimes-0.4.0/lib/hitimes/timer.rb +223 -0
  70. data/vendor/hitimes-0.4.0/lib/hitimes/version.rb +42 -0
  71. data/vendor/hitimes-0.4.0/lib/hitimes.rb +24 -0
  72. data/vendor/hitimes-0.4.0/spec/interval_spec.rb +115 -0
  73. data/vendor/hitimes-0.4.0/spec/mutex_stats_spec.rb +34 -0
  74. data/vendor/hitimes-0.4.0/spec/paths_spec.rb +14 -0
  75. data/vendor/hitimes-0.4.0/spec/spec_helper.rb +6 -0
  76. data/vendor/hitimes-0.4.0/spec/stats_spec.rb +72 -0
  77. data/vendor/hitimes-0.4.0/spec/timer_spec.rb +105 -0
  78. data/vendor/hitimes-0.4.0/spec/version_spec.rb +27 -0
  79. data/vendor/hitimes-0.4.0/tasks/announce.rake +39 -0
  80. data/vendor/hitimes-0.4.0/tasks/config.rb +107 -0
  81. data/vendor/hitimes-0.4.0/tasks/distribution.rake +53 -0
  82. data/vendor/hitimes-0.4.0/tasks/documentation.rake +33 -0
  83. data/vendor/hitimes-0.4.0/tasks/extension.rake +64 -0
  84. data/vendor/hitimes-0.4.0/tasks/rspec.rake +31 -0
  85. data/vendor/hitimes-0.4.0/tasks/rubyforge.rake +52 -0
  86. data/vendor/hitimes-0.4.0/tasks/utils.rb +80 -0
  87. data/vendor/useragent/lib/user_agent.rb +1 -1
  88. 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
- DEFAULT_HOME = File.join(ENV['HOME'], '.stella').freeze unless defined? DEFAULT_HOME
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
- @command_arguments = [] if @command_arguments.nil?
127
- @stella_arguments = [] if @stella_arguments.nil?
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', '--testreps=N', Integer, Stella::TEXT.msg(:option_help_testreps)) do |v|
193
- @options.testreps = MathUtil.enforce_limit(v,1,10)
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 #{path}: #{ex.message}")
291
- end
300
+ Stella::LOGGER.info("Error loading #{previous_path}: #{ex.message}")
301
+ end
302
+
303
+
@@ -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
- @guid = Crypto.sign(rand.to_s, rand.to_s)
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
- FileUtil.write_file(test_path + "/ID.txt", @guid, true)
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> '#{@adapter.stdout_path}' 2> '#{@adapter.stderr_path}'"
249
+ command = "#{@adapter.command} 1> \"#{@adapter.stdout_path}\" 2> \"#{@adapter.stderr_path}\""
245
250
  Stella::LOGGER.info(" COMMAND: #{command}") if @verbose >= 2
246
-
247
- # Call the load tool
248
- # for Windows, see: http://blog.crankybit.com/redirecting-output-to-a-file-in-windows-batch-scripts/
249
- # http://weblogs.asp.net/lorenh/archive/2006/03/24/441004.aspx
250
- system(command)
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
- unless @quiet
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% 3.0f%% %9.2f/s ", "Total", stats.transactions_total, stats.vusers_avg, stats.availability, stats.transaction_rate_avg)
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