stella 0.5.3 → 0.5.4

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