solutious-stella 0.5.5 → 0.6.0

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 (83) hide show
  1. data/CHANGES.txt +39 -2
  2. data/LICENSE.txt +19 -0
  3. data/README.rdoc +85 -0
  4. data/Rakefile +54 -59
  5. data/bin/example_test.rb +82 -0
  6. data/bin/example_webapp.rb +63 -0
  7. data/lib/{stella/logger.rb → logger.rb} +6 -11
  8. data/lib/stella.rb +76 -58
  9. data/lib/stella/clients.rb +161 -0
  10. data/lib/stella/command/base.rb +4 -24
  11. data/lib/stella/command/form.rb +36 -0
  12. data/lib/stella/command/get.rb +44 -0
  13. data/lib/stella/common.rb +53 -0
  14. data/lib/stella/crypto.rb +88 -0
  15. data/lib/stella/data/domain.rb +2 -2
  16. data/lib/stella/data/http.rb +164 -36
  17. data/lib/stella/environment.rb +66 -0
  18. data/lib/stella/functest.rb +105 -0
  19. data/lib/stella/loadtest.rb +186 -0
  20. data/lib/{utils → stella}/stats.rb +16 -20
  21. data/lib/stella/testplan.rb +237 -0
  22. data/lib/stella/testrunner.rb +64 -0
  23. data/lib/storable.rb +280 -0
  24. data/lib/threadify.rb +171 -0
  25. data/lib/timeunits.rb +65 -0
  26. data/lib/util/httputil.rb +266 -0
  27. data/stella.gemspec +69 -0
  28. data/tryouts/drb/drb_test.rb +65 -0
  29. data/tryouts/drb/open4.rb +19 -0
  30. data/tryouts/drb/slave.rb +27 -0
  31. data/tryouts/oo_tryout.rb +30 -0
  32. metadata +39 -107
  33. data/README.textile +0 -162
  34. data/bin/stella +0 -12
  35. data/bin/stella.bat +0 -12
  36. data/lib/daemonize.rb +0 -56
  37. data/lib/pcaplet.rb +0 -180
  38. data/lib/stella/adapter/ab.rb +0 -337
  39. data/lib/stella/adapter/base.rb +0 -106
  40. data/lib/stella/adapter/httperf.rb +0 -305
  41. data/lib/stella/adapter/pcap_watcher.rb +0 -221
  42. data/lib/stella/adapter/proxy_watcher.rb +0 -76
  43. data/lib/stella/adapter/siege.rb +0 -341
  44. data/lib/stella/cli.rb +0 -258
  45. data/lib/stella/cli/agents.rb +0 -73
  46. data/lib/stella/cli/base.rb +0 -55
  47. data/lib/stella/cli/language.rb +0 -18
  48. data/lib/stella/cli/localtest.rb +0 -78
  49. data/lib/stella/cli/sysinfo.rb +0 -16
  50. data/lib/stella/cli/watch.rb +0 -278
  51. data/lib/stella/command/localtest.rb +0 -358
  52. data/lib/stella/response.rb +0 -85
  53. data/lib/stella/storable.rb +0 -201
  54. data/lib/stella/support.rb +0 -276
  55. data/lib/stella/sysinfo.rb +0 -257
  56. data/lib/stella/test/definition.rb +0 -79
  57. data/lib/stella/test/run/summary.rb +0 -70
  58. data/lib/stella/test/stats.rb +0 -114
  59. data/lib/stella/text.rb +0 -64
  60. data/lib/stella/text/resource.rb +0 -38
  61. data/lib/utils/crypto-key.rb +0 -84
  62. data/lib/utils/domainutil.rb +0 -47
  63. data/lib/utils/escape.rb +0 -302
  64. data/lib/utils/fileutil.rb +0 -78
  65. data/lib/utils/httputil.rb +0 -266
  66. data/lib/utils/mathutil.rb +0 -15
  67. data/lib/utils/textgraph.rb +0 -267
  68. data/lib/utils/timerutil.rb +0 -58
  69. data/lib/win32/Console.rb +0 -970
  70. data/lib/win32/Console/ANSI.rb +0 -305
  71. data/support/kvm.h +0 -91
  72. data/support/ruby-pcap-takuma-notes.txt +0 -19
  73. data/support/ruby-pcap-takuma-patch.txt +0 -30
  74. data/support/text/en.yaml +0 -80
  75. data/support/text/nl.yaml +0 -7
  76. data/support/useragents.txt +0 -75
  77. data/tests/01-util_test.rb +0 -0
  78. data/tests/02-stella-util_test.rb +0 -42
  79. data/tests/10-stella_test.rb +0 -104
  80. data/tests/11-stella-storable_test.rb +0 -68
  81. data/tests/60-stella-command_test.rb +0 -248
  82. data/tests/80-stella-cli_test.rb +0 -45
  83. data/tests/spec-helper.rb +0 -31
@@ -0,0 +1,64 @@
1
+ # ---
2
+ # See: http://codeforpeople.com/lib/ruby/flow/flow-2.0.0/sample/a.rb
3
+ # +++
4
+
5
+ #
6
+ #
7
+ #
8
+ module Stella
9
+ module TestRunner
10
+ attr_accessor :name
11
+ # Name or instance of the testplan to execute
12
+ attr_accessor :testplan
13
+ # Determines the amount of output. Default: 0
14
+ attr_accessor :verbose
15
+
16
+ def initialize(name=:default)
17
+ @name = name
18
+ @verbose = 0
19
+ init if respond_to? :init
20
+ end
21
+
22
+ def update(*args)
23
+ what, *args = args
24
+ self.send("update_#{what}", *args) if respond_to? "update_#{what}"
25
+ end
26
+
27
+ end
28
+ module DSL
29
+ module TestRunner
30
+ attr_accessor :current_test
31
+
32
+ def plan(testplan)
33
+ raise "Unknown testplan, '#{testplan}'" unless @plans.has_key?(testplan)
34
+ return unless @current_test
35
+ @current_test.testplan = @plans[testplan]
36
+ end
37
+
38
+ def run(env_name=nil, test_name=nil)
39
+ to_run = test_name.nil? ? @tests : [@tests[test_name]]
40
+ env = env_name.nil? ? @stella_environments.first : @stella_environments[env_name]
41
+ to_run.each do |t|
42
+ puts '='*60
43
+ puts "RUNNING TEST: #{test_name}"
44
+ puts " %11s: %s" % ['type', t.type]
45
+ puts " %11s: %s" % ['testplan', t.testplan.name]
46
+ puts " %11s: %s" % ['desc', t.testplan.description]
47
+ puts " %11s: %s" % ['env', env_name]
48
+
49
+
50
+ t.run(env, self)
51
+ end
52
+ end
53
+
54
+ def verbose(*args)
55
+ @current_test.verbose += args.first || 1
56
+ end
57
+
58
+ private
59
+
60
+ end
61
+ end
62
+ end
63
+
64
+
data/lib/storable.rb ADDED
@@ -0,0 +1,280 @@
1
+ #--
2
+ # TODO: Handle nested hashes and arrays.
3
+ # TODO: to_xml, see: http://codeforpeople.com/lib/ruby/xx/xx-2.0.0/README
4
+ # TODO: Rename to Stuffany
5
+ #++
6
+
7
+ require 'yaml'
8
+ require 'fileutils'
9
+
10
+
11
+ # Storable makes data available in multiple formats and can
12
+ # re-create objects from files. Fields are defined using the
13
+ # Storable.field method which tells Storable the order and
14
+ # name.
15
+ class Storable
16
+ VERSION = 2
17
+ NICE_TIME_FORMAT = "%Y-%m-%d@%H:%M:%S".freeze unless defined? NICE_TIME_FORMAT
18
+ SUPPORTED_FORMATS = %w{tsv csv yaml json}.freeze unless defined? SUPPORTED_FORMATS
19
+
20
+ # This value will be used as a default unless provided on-the-fly.
21
+ # See SUPPORTED_FORMATS for available values.
22
+ attr_reader :format
23
+
24
+ # See SUPPORTED_FORMATS for available values
25
+ def format=(v)
26
+ raise "Unsupported format: #{v}" unless SUPPORTED_FORMATS.member?(v)
27
+ @format = v
28
+ end
29
+
30
+ # TODO: from_args([HASH or ordered params])
31
+
32
+ def init
33
+ # NOTE: I think this can be removed
34
+ self.class.send(:class_variable_set, :@@field_names, []) unless class_variable_defined?(:@@field_names)
35
+ self.class.send(:class_variable_set, :@@field_types, []) unless class_variable_defined?(:@@field_types)
36
+ end
37
+
38
+ # Accepts field definitions in the one of the follow formats:
39
+ #
40
+ # field :product
41
+ # field :product => Integer
42
+ #
43
+ # The order they're defined determines the order the will be output. The fields
44
+ # data is available by the standard accessors, class.product and class.product= etc...
45
+ # The value of the field will be cast to the type (if provided) when read from a file.
46
+ # The value is not touched when the type is not provided.
47
+ def self.field(args={})
48
+ # TODO: Examine casting from: http://codeforpeople.com/lib/ruby/fattr/fattr-1.0.3/
49
+ args = {args => nil} unless args.is_a? Hash
50
+
51
+ args.each_pair do |m,t|
52
+
53
+ [[:@@field_names, m], [:@@field_types, t]].each do |tuple|
54
+ class_variable_set(tuple[0], []) unless class_variable_defined?(tuple[0])
55
+ class_variable_set(tuple[0], class_variable_get(tuple[0]) << tuple[1])
56
+ end
57
+
58
+ next if method_defined?(m)
59
+
60
+ define_method(m) do instance_variable_get("@#{m}") end
61
+ define_method("#{m}=") do |val|
62
+ instance_variable_set("@#{m}",val)
63
+ end
64
+ end
65
+ end
66
+
67
+ # Returns an array of field names defined by self.field
68
+ def self.field_names
69
+ class_variable_get(:@@field_names)
70
+ end
71
+ # Ditto.
72
+ def field_names
73
+ self.class.send(:class_variable_get, :@@field_names)
74
+ end
75
+ # Returns an array of field types defined by self.field. Fields that did
76
+ # not receive a type are set to nil.
77
+ def self.field_types
78
+ class_variable_get(:@@field_types)
79
+ end
80
+ # Ditto.
81
+ def field_types
82
+ self.class.send(:class_variable_get, :@@field_types)
83
+ end
84
+
85
+ # Dump the object data to the given format.
86
+ def dump(format=nil, with_titles=true)
87
+ format ||= @format
88
+ raise "Format not defined (#{format})" unless SUPPORTED_FORMATS.member?(format)
89
+ send("to_#{format}", with_titles)
90
+ end
91
+
92
+ # Create a new instance of the object using data from file.
93
+ def self.from_file(file_path, format='yaml')
94
+ raise "Cannot read file (#{file_path})" unless File.exists?(file_path)
95
+ raise "#{self} doesn't support from_#{format}" unless self.respond_to?("from_#{format}")
96
+ format = format || File.extname(file_path).tr('.', '')
97
+ me = send("from_#{format}", read_file_to_array(file_path))
98
+ me.format = format
99
+ me
100
+ end
101
+ # Write the object data to the given file.
102
+ def to_file(file_path=nil, with_titles=true)
103
+ raise "Cannot store to nil path" if file_path.nil?
104
+ format = File.extname(file_path).tr('.', '')
105
+ format ||= @format
106
+ Storable.write_file(file_path, dump(format, with_titles))
107
+ end
108
+
109
+ # Create a new instance of the object from a hash.
110
+ def self.from_hash(from={})
111
+ me = self.new
112
+
113
+ return me if !from || from.empty?
114
+
115
+ fnames = field_names
116
+ fnames.each_with_index do |key,index|
117
+
118
+ stored_value = from[key] || from[key.to_s] # support for symbol keys and string keys
119
+
120
+ # TODO: Correct this horrible implementation (sorry, me. It's just one of those days.)
121
+
122
+ if field_types[index] == Array
123
+ ((value ||= []) << stored_value).flatten
124
+ elsif field_types[index] == Hash
125
+ value = stored_value
126
+ else
127
+ # SimpleDB stores attribute shit as lists of values
128
+ value = stored_value.first if stored_value.is_a?(Array) && stored_value.size == 1
129
+
130
+ if field_types[index] == Time
131
+ value = Time.parse(value)
132
+ elsif field_types[index] == DateTime
133
+ value = DateTime.parse(value)
134
+ elsif field_types[index] == TrueClass
135
+ value = (value.to_s == "true")
136
+ elsif field_types[index] == Float
137
+ value = value.to_f
138
+ elsif field_types[index] == Integer
139
+ value = value.to_i
140
+ else
141
+ value = value.first if value.is_a?(Array) && value.size == 1 # I
142
+ end
143
+ end
144
+
145
+ me.send("#{key}=", value) if self.method_defined?("#{key}=")
146
+ end
147
+
148
+ me
149
+ end
150
+ # Return the object data as a hash
151
+ # +with_titles+ is ignored.
152
+ def to_hash(with_titles=true)
153
+ tmp = {}
154
+ field_names.each do |fname|
155
+ tmp[fname] = self.send(fname)
156
+ end
157
+ tmp
158
+ end
159
+
160
+ # Create a new instance of the object from YAML.
161
+ # +from+ a YAML string split into an array by line.
162
+ def self.from_yaml(from=[])
163
+ # from is an array of strings
164
+ from_str = from.join('')
165
+ hash = YAML::load(from_str)
166
+ hash = from_hash(hash) if hash.is_a? Hash
167
+ hash
168
+ end
169
+ def to_yaml(with_titles=true)
170
+ to_hash.to_yaml
171
+ end
172
+
173
+ # Create a new instance of the object from a JSON string.
174
+ # +from+ a JSON string split into an array by line.
175
+ def self.from_json(from=[])
176
+ require 'json'
177
+ # from is an array of strings
178
+ from_str = from.join('')
179
+ tmp = JSON::load(from_str)
180
+ hash_sym = tmp.keys.inject({}) do |hash, key|
181
+ hash[key.to_sym] = tmp[key]
182
+ hash
183
+ end
184
+ hash_sym = from_hash(hash_sym) if hash_sym.is_a? Hash
185
+ hash_sym
186
+ end
187
+ def to_json(with_titles=true)
188
+ require 'json'
189
+ to_hash.to_json
190
+ end
191
+
192
+ # Return the object data as a delimited string.
193
+ # +with_titles+ specifiy whether to include field names (default: false)
194
+ # +delim+ is the field delimiter.
195
+ def to_delimited(with_titles=false, delim=',')
196
+ values = []
197
+ field_names.each do |fname|
198
+ values << self.send(fname.to_s) # TODO: escape values
199
+ end
200
+ output = values.join(delim)
201
+ output = field_names.join(delim) << $/ << output if with_titles
202
+ output
203
+ end
204
+ # Return the object data as a tab delimited string.
205
+ # +with_titles+ specifiy whether to include field names (default: false)
206
+ def to_tsv(with_titles=false)
207
+ to_delimited(with_titles, "\t")
208
+ end
209
+ # Return the object data as a comma delimited string.
210
+ # +with_titles+ specifiy whether to include field names (default: false)
211
+ def to_csv(with_titles=false)
212
+ to_delimited(with_titles, ',')
213
+ end
214
+ # Create a new instance from tab-delimited data.
215
+ # +from+ a JSON string split into an array by line.
216
+ def self.from_tsv(from=[])
217
+ self.from_delimited(from, "\t")
218
+ end
219
+ # Create a new instance of the object from comma-delimited data.
220
+ # +from+ a JSON string split into an array by line.
221
+ def self.from_csv(from=[])
222
+ self.from_delimited(from, ',')
223
+ end
224
+
225
+ # Create a new instance of the object from a delimited string.
226
+ # +from+ a JSON string split into an array by line.
227
+ # +delim+ is the field delimiter.
228
+ def self.from_delimited(from=[],delim=',')
229
+ return if from.empty?
230
+ # We grab an instance of the class so we can
231
+ hash = {}
232
+
233
+ fnames = values = []
234
+ if (from.size > 1 && !from[1].empty?)
235
+ fnames = from[0].chomp.split(delim)
236
+ values = from[1].chomp.split(delim)
237
+ else
238
+ fnames = self.field_names
239
+ values = from[0].chomp.split(delim)
240
+ end
241
+
242
+ fnames.each_with_index do |key,index|
243
+ next unless values[index]
244
+ hash[key.to_sym] = values[index]
245
+ end
246
+ hash = from_hash(hash) if hash.is_a? Hash
247
+ hash
248
+ end
249
+
250
+ def self.read_file_to_array(path)
251
+ contents = []
252
+ return contents unless File.exists?(path)
253
+
254
+ open(path, 'r') do |l|
255
+ contents = l.readlines
256
+ end
257
+
258
+ contents
259
+ end
260
+
261
+ def self.write_file(path, content, flush=true)
262
+ write_or_append_file('w', path, content, flush)
263
+ end
264
+
265
+ def self.append_file(path, content, flush=true)
266
+ write_or_append_file('a', path, content, flush)
267
+ end
268
+
269
+ def self.write_or_append_file(write_or_append, path, content = '', flush = true)
270
+ #STDERR.puts "Writing to #{ path }..."
271
+ create_dir(File.dirname(path))
272
+
273
+ open(path, write_or_append) do |f|
274
+ f.puts content
275
+ f.flush if flush;
276
+ end
277
+ File.chmod(0600, path)
278
+ end
279
+ end
280
+
data/lib/threadify.rb ADDED
@@ -0,0 +1,171 @@
1
+ module Threadify
2
+ VERSION = '0.0.3'
3
+ def Threadify.version() Threadify::VERSION end
4
+
5
+ require 'thread'
6
+
7
+ @threads = 8
8
+ @abort_on_exception = true
9
+
10
+ class << self
11
+ attr_accessor :threads
12
+ attr_accessor :abort_on_exception
13
+ end
14
+
15
+ class Error < ::StandardError; end
16
+ end
17
+
18
+ module Enumerable
19
+ def threadify opts = {}, &block
20
+ # setup
21
+ #
22
+ opts = {:threads => opts} if Numeric === opts
23
+ threads = Integer(opts[:threads] || opts['threads'] || Threadify.threads)
24
+ done = Object.new.freeze
25
+ nothing = done
26
+ #jobs = Array.new(threads).map{ Queue.new }
27
+ jobs = Array.new(threads).map{ [] }
28
+ top = Thread.current
29
+
30
+ # produce jobs
31
+ #
32
+ #producer = Thread.new do
33
+ #this = Thread.current
34
+ #this.abort_on_exception = Threadify.abort_on_exception
35
+
36
+ each_with_index{|args, i| jobs[i % threads].push([args, i])}
37
+ threads.times{|i| jobs[i].push(done)}
38
+ #end
39
+
40
+ # setup consumer list
41
+ #
42
+ consumers = Array.new threads
43
+
44
+ # setup support for short-circuit bailout via 'throw :threadify'
45
+ #
46
+ thrownv = Hash.new
47
+ thrownq = Queue.new
48
+
49
+ caught = false
50
+
51
+ catcher = Thread.new do
52
+ loop do
53
+ thrown = thrownq.pop
54
+ break if thrown == done
55
+ i, thrown = thrown
56
+ thrownv[i] = thrown
57
+ caught = true
58
+ end
59
+ end
60
+
61
+ # fire off the consumers
62
+ #
63
+ threads.times do |i|
64
+ consumers[i] = Thread.new(jobs[i]) do |jobsi|
65
+ this = Thread.current
66
+ this.abort_on_exception = Threadify.abort_on_exception
67
+
68
+ job = nil
69
+
70
+ thrown =
71
+ catch(:threadify) do
72
+ loop{
73
+ break if caught
74
+ #job = jobsi.pop
75
+ job = jobsi.shift
76
+ break if job == done
77
+ args = job.first
78
+ jobsi << (job << block.call(*args))
79
+ }
80
+ nothing
81
+ end
82
+
83
+
84
+ unless nothing == thrown
85
+ args, i = job
86
+ thrownq.push [i, thrown]
87
+ end
88
+ end
89
+ end
90
+
91
+ # wait for consumers to finish
92
+ #
93
+ consumers.map{|t| t.join}
94
+
95
+ # nuke the catcher
96
+ #
97
+ thrownq.push done
98
+ catcher.join
99
+
100
+ # iff something(s) was thrown return the one which would have been thrown
101
+ # earliest in non-parallel execution
102
+ #
103
+ unless thrownv.empty?
104
+ key = thrownv.keys.sort.first
105
+ return thrownv[key]
106
+ end
107
+
108
+ # collect the results and return them
109
+ #
110
+ =begin
111
+ jobs.push done
112
+ ret = []
113
+ while((job = jobs.pop) != done)
114
+ elem, i, value = job
115
+ ret[i] = value
116
+ end
117
+ ret
118
+ end
119
+ =end
120
+
121
+ ret = []
122
+ jobs.each do |results|
123
+ results.each do |result|
124
+ break if result == done
125
+ elem, i, value = result
126
+ ret[i] = value
127
+ end
128
+ end
129
+ ret
130
+ end
131
+
132
+ end
133
+
134
+ class Thread
135
+ def Thread.ify enumerable, *args, &block
136
+ enumerable.send :threadify, *args, &block
137
+ end
138
+ end
139
+
140
+ class Object
141
+ def threadify! *values
142
+ throw :threadify, *values
143
+ end
144
+ end
145
+
146
+
147
+ if __FILE__ == $0
148
+ require 'open-uri'
149
+ require 'yaml'
150
+
151
+ uris = %w( http://google.com http://yahoo.com http://rubyforge.org/ http://ruby-lang.org)
152
+
153
+ Thread.ify uris, :threads => 6 do |uri|
154
+ body = open(uri){|pipe| pipe.read}
155
+ y uri => body.size
156
+ end
157
+ end
158
+
159
+
160
+ __END__
161
+
162
+ sample output
163
+
164
+ ---
165
+ http://yahoo.com: 9562
166
+ ---
167
+ http://google.com: 6290
168
+ ---
169
+ http://rubyforge.org/: 22352
170
+ ---
171
+ http://ruby-lang.org: 9984