stella 0.3.2

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 (56) hide show
  1. data/README.txt +135 -0
  2. data/Rakefile +100 -0
  3. data/bin/stella +12 -0
  4. data/lib/stella.rb +58 -0
  5. data/lib/stella/adapter/ab.rb +303 -0
  6. data/lib/stella/adapter/base.rb +87 -0
  7. data/lib/stella/adapter/httperf.rb +296 -0
  8. data/lib/stella/adapter/siege.rb +321 -0
  9. data/lib/stella/cli.rb +291 -0
  10. data/lib/stella/cli/agents.rb +73 -0
  11. data/lib/stella/cli/base.rb +19 -0
  12. data/lib/stella/cli/language.rb +18 -0
  13. data/lib/stella/cli/localtest.rb +80 -0
  14. data/lib/stella/command/base.rb +111 -0
  15. data/lib/stella/command/localtest.rb +339 -0
  16. data/lib/stella/logger.rb +63 -0
  17. data/lib/stella/response.rb +82 -0
  18. data/lib/stella/storable.rb +116 -0
  19. data/lib/stella/support.rb +106 -0
  20. data/lib/stella/test/base.rb +34 -0
  21. data/lib/stella/test/definition.rb +79 -0
  22. data/lib/stella/test/run/summary.rb +50 -0
  23. data/lib/stella/test/summary.rb +82 -0
  24. data/lib/stella/text.rb +64 -0
  25. data/lib/stella/text/resource.rb +39 -0
  26. data/lib/utils/crypto-key.rb +84 -0
  27. data/lib/utils/escape.rb +302 -0
  28. data/lib/utils/fileutil.rb +59 -0
  29. data/lib/utils/httputil.rb +210 -0
  30. data/lib/utils/mathutil.rb +78 -0
  31. data/lib/utils/textgraph.rb +267 -0
  32. data/lib/utils/timerutil.rb +58 -0
  33. data/support/text/en.yaml +54 -0
  34. data/support/text/nl.yaml +1 -0
  35. data/support/useragents.txt +75 -0
  36. data/vendor/useragent/MIT-LICENSE +20 -0
  37. data/vendor/useragent/README +21 -0
  38. data/vendor/useragent/init.rb +1 -0
  39. data/vendor/useragent/lib/user_agent.rb +83 -0
  40. data/vendor/useragent/lib/user_agent/browsers.rb +24 -0
  41. data/vendor/useragent/lib/user_agent/browsers/all.rb +69 -0
  42. data/vendor/useragent/lib/user_agent/browsers/gecko.rb +43 -0
  43. data/vendor/useragent/lib/user_agent/browsers/internet_explorer.rb +40 -0
  44. data/vendor/useragent/lib/user_agent/browsers/opera.rb +49 -0
  45. data/vendor/useragent/lib/user_agent/browsers/webkit.rb +94 -0
  46. data/vendor/useragent/lib/user_agent/comparable.rb +25 -0
  47. data/vendor/useragent/lib/user_agent/operating_systems.rb +19 -0
  48. data/vendor/useragent/spec/browsers/gecko_user_agent_spec.rb +209 -0
  49. data/vendor/useragent/spec/browsers/internet_explorer_user_agent_spec.rb +99 -0
  50. data/vendor/useragent/spec/browsers/opera_user_agent_spec.rb +59 -0
  51. data/vendor/useragent/spec/browsers/other_user_agent_spec.rb +19 -0
  52. data/vendor/useragent/spec/browsers/webkit_user_agent_spec.rb +373 -0
  53. data/vendor/useragent/spec/spec_helper.rb +1 -0
  54. data/vendor/useragent/spec/user_agent_spec.rb +331 -0
  55. data/vendor/useragent/useragent.gemspec +12 -0
  56. metadata +139 -0
@@ -0,0 +1,59 @@
1
+ require 'ftools'
2
+
3
+ module FileUtil
4
+
5
+ def FileUtil.read_file(path)
6
+ FileUtil.read_file_to_array(path).join('')
7
+ end
8
+
9
+ def FileUtil.read_file_to_array(path)
10
+ contents = []
11
+ return contents unless File.exists?(path)
12
+
13
+ open(path, 'r') do |l|
14
+ contents = l.readlines
15
+ end
16
+
17
+ contents
18
+ end
19
+ def FileUtil.read_binary_file(path)
20
+ contents = ''
21
+ return contents unless File.exists?(path)
22
+
23
+ open(path, 'rb') do |l|
24
+ while (!l.eof?)
25
+ contents << l.read(4096)
26
+ end
27
+ end
28
+
29
+ contents
30
+ end
31
+
32
+
33
+
34
+ def FileUtil.write_file(path, content, flush=true)
35
+ FileUtil.write_or_append_file('w', path, content, flush)
36
+ end
37
+
38
+ def FileUtil.append_file(path, content, flush=true)
39
+ FileUtil.write_or_append_file('a', path, content, flush)
40
+ end
41
+
42
+ def FileUtil.write_or_append_file(write_or_append, path, content = '', flush = true)
43
+ #STDERR.puts "Writing to #{ path }..."
44
+ FileUtil.create_dir(File.dirname(path))
45
+
46
+ open(path, write_or_append) do |f|
47
+ f.puts content
48
+ f.flush if flush;
49
+ end
50
+ File.chmod(0600, path)
51
+ end
52
+
53
+ def FileUtil.create_dir(dirpath)
54
+ return if File.directory?(dirpath)
55
+
56
+ #STDERR.puts "Creating #{ dirpath }"
57
+ File.makedirs(dirpath)
58
+ end
59
+ end
@@ -0,0 +1,210 @@
1
+ require 'net/http'
2
+ require 'uri'
3
+ require 'timeout'
4
+
5
+ module HTTPUtil
6
+ VALID_METHODS = %w{GET HEAD POST PUT DELETE}
7
+ @@timeout = 20
8
+
9
+ def HTTPUtil.hostname(tmp_uri)
10
+ return if tmp_uri.empty?
11
+ uri = URI.parse(tmp_uri) if tmp_uri.is_a? String
12
+
13
+ #STDERR.puts "Hostname for #{ uri.port }"
14
+ uri.host
15
+ end
16
+
17
+ # Normalize all URIs before they are used for anything else
18
+ def HTTPUtil.normalize(uri_str, scheme = true)
19
+
20
+
21
+ #STDERR.puts " BEFORE: " << uri_str
22
+ if (!uri_str.index(/^https?:\/\//))
23
+ uri_str = 'http://' << uri_str
24
+ end
25
+ #STDERR.puts " AFTER: " << uri_str
26
+
27
+ uri_str.gsub!(/\s/, '%20')
28
+
29
+ uri = URI.parse(uri_str)
30
+
31
+ uri_clean = ""
32
+
33
+ # TODO: use URI.to_s instead of manually creating the string
34
+
35
+ if (scheme)
36
+ uri_clean << uri.scheme.to_s + '://'
37
+ end
38
+
39
+
40
+ if (!uri.userinfo.nil?)
41
+ uri_clean << uri.userinfo.to_s
42
+ uri_clean << '@'
43
+ end
44
+
45
+ #uri.host.gsub!(/^www\./, '')
46
+
47
+ uri_clean << uri.host.to_s
48
+
49
+ if (!uri.port.nil? && uri.port != 80 && uri.port != 443)
50
+ uri_clean << ':' + uri.port.to_s
51
+ end
52
+
53
+
54
+
55
+ if (!uri.path.nil? && !uri.path.empty?)
56
+ uri_clean << uri.path
57
+ elsif
58
+ uri_clean << '/'
59
+ end
60
+
61
+
62
+ if (!uri.query.nil? && !uri.path.empty?)
63
+ uri_clean << "?" << uri.query
64
+ end
65
+
66
+ #STDERR.puts "IN: " << uri_str
67
+ #STDERR.puts "OUT: " << uri_clean
68
+
69
+ uri_clean
70
+ end
71
+
72
+ def HTTPUtil.fetch_content(uri, limit = 10)
73
+ res = self.fetch(uri,limit)
74
+ return (res) ? res.body : ""
75
+ end
76
+
77
+ def HTTPUtil.fetch(uri, limit = 10)
78
+
79
+ # You should choose better exception.
80
+ raise ArgumentError, 'HTTP redirect too deep' if limit == 0
81
+ STDERR.puts "URL: #{uri.to_s}"
82
+ uri = URI.parse(uri) if uri.is_a? String
83
+
84
+ begin
85
+ timeout(@@timeout) do
86
+ response = Net::HTTP.get_response(uri)
87
+
88
+
89
+ case response
90
+ when Net::HTTPSuccess then response
91
+ when Net::HTTPRedirection then fetch(response['location'], limit - 1)
92
+ else
93
+ STDERR.puts "Not found: " << uri.to_s
94
+ end
95
+ end
96
+ rescue TimeoutError
97
+ STDERR.puts "Net::HTTP timed out for " << uri.to_s
98
+ return
99
+ rescue => ex
100
+ STDERR.puts "Error: #{ex.message}"
101
+ end
102
+
103
+ end
104
+
105
+ def HTTPUtil.post(uri, params = {}, limit = 10)
106
+
107
+ # You should choose better exception.
108
+ raise ArgumentError, 'HTTP redirect too deep' if limit == 0
109
+
110
+ uri = URI.parse(uri) if uri.is_a? String
111
+
112
+ begin
113
+ timeout(@@timeout) do
114
+ response = Net::HTTP.post_form(uri, params)
115
+
116
+ case response
117
+ when Net::HTTPSuccess then response
118
+ when Net::HTTPRedirection then fetch(response['location'], limit - 1)
119
+ else
120
+ STDERR.puts "Error for " << uri.to_s
121
+ STDERR.puts response.body
122
+ end
123
+ end
124
+ rescue TimeoutError
125
+ STDERR.puts "Net::HTTP timed out for " << uri.to_s
126
+ return
127
+ end
128
+
129
+
130
+
131
+ end
132
+
133
+ def HTTPUtil.exists(uri)
134
+
135
+ begin
136
+ response = fetch(uri)
137
+ case response
138
+ when Net::HTTPSuccess then true
139
+ when Net::HTTPRedirection then fetch(response['location'], limit - 1)
140
+ else
141
+ false
142
+ end
143
+
144
+ rescue Exception => e
145
+ STDERR.puts "Problem: " + e.message
146
+ false
147
+ end
148
+
149
+ end
150
+
151
+ def HTTPUtil.parse_query(query)
152
+ params = Hash.new([].freeze)
153
+
154
+ query.split(/[&;]/n).each do |pairs|
155
+ key, value = pairs.split('=',2).collect{|v| URI.unescape(v) }
156
+ if params.has_key?(key)
157
+ params[key].push(value)
158
+ else
159
+ params[key] = [value]
160
+ end
161
+ end
162
+
163
+ params
164
+ end
165
+
166
+ def HTTPUtil.validate_method(meth='GET')
167
+ meth = (VALID_METHODS.member? meth.upcase) ? meth : VALID_METHODS[0]
168
+ end
169
+
170
+ # Extend the basic query string parser provided by the cgi module.
171
+ # converts single valued params (the most common case) to
172
+ # objects instead of arrays
173
+ #
174
+ # Input:
175
+ # the query string
176
+ #
177
+ # Output:
178
+ # hash of parameters, contains arrays for multivalued parameters
179
+ # (multiselect, checkboxes , etc)
180
+ # If no query string is provided (nil or "") returns an empty hash.
181
+
182
+ def HTTPUtil.query_to_hash(query_string)
183
+ return {} unless query_string
184
+
185
+ query_parameters = HTTPUtil.parse_query(query_string)
186
+
187
+ query_parameters.each { |key, val|
188
+ # replace the array with an object
189
+ query_parameters[key] = val[0] if 1 == val.length
190
+ }
191
+
192
+ # set default value to nil! cgi sets this to []
193
+ query_parameters.default = nil
194
+
195
+ return query_parameters
196
+ end
197
+
198
+ def HTTPUtil.hash_to_query(parameters)
199
+ return '' unless parameters
200
+ pairs = []
201
+ parameters.each do |param, value|
202
+ pairs << "#{param}=#{URI.escape(value.to_s)}"
203
+ end
204
+ return pairs.join('&')
205
+ #return pairs.join(";")
206
+ end
207
+
208
+
209
+ end
210
+
@@ -0,0 +1,78 @@
1
+
2
+
3
+ module MathUtil
4
+
5
+ def self.variance(population)
6
+ n = 0
7
+ mean = 0.0
8
+ s = 0.0
9
+ population.each { |x|
10
+ n = n + 1
11
+ delta = (x - mean).to_f
12
+ mean = (mean + (delta / n)).to_f
13
+ s = (s + delta * (x - mean)).to_f
14
+ }
15
+
16
+ return s / n
17
+ end
18
+
19
+ # calculate the standard deviation of a population
20
+ # accepts: an array, the population
21
+ # returns: the standard deviation
22
+ def self.standard_deviation(population)
23
+ Math.sqrt(variance(population))
24
+ end
25
+
26
+ # enforce_limit
27
+ #
28
+ # Enforce a minimum and maximum value
29
+ def self.enforce_limit(val,min,max)
30
+ val = min if val < min
31
+ val = max if val > max
32
+ val
33
+ end
34
+
35
+ end
36
+
37
+
38
+
39
+
40
+ module Enumerable
41
+
42
+ ##
43
+ # Sum of all the elements of the Enumerable
44
+
45
+ def sum
46
+ return self.inject(0) { |acc, i| acc + i }
47
+ end
48
+
49
+ ##
50
+ # Average of all the elements of the Enumerable
51
+ #
52
+ # The Enumerable must respond to #length
53
+
54
+ def average
55
+ return self.sum / self.length.to_f
56
+ end
57
+
58
+ ##
59
+ # Sample variance of all the elements of the Enumerable
60
+ #
61
+ # The Enumerable must respond to #length
62
+
63
+ def sample_variance
64
+ avg = self.average
65
+ sum = self.inject(0) { |acc, i| acc + (i - avg) ** 2 }
66
+ return (1 / self.length.to_f * sum)
67
+ end
68
+
69
+ ##
70
+ # Standard deviation of all the elements of the Enumerable
71
+ #
72
+ # The Enumerable must respond to #length
73
+
74
+ def standard_deviation
75
+ return Math.sqrt(self.sample_variance)
76
+ end
77
+
78
+ end
@@ -0,0 +1,267 @@
1
+ # A port of Text::Graph, which generates pretty ascii bar graphs from
2
+ # numeric datasets, like
3
+ #
4
+ # aaaa : (1)
5
+ # bb :..* (22)
6
+ # ccc :...* (43)
7
+ # dddddd :.....* (500)
8
+ # ee :......*(1000)
9
+ # f :.....* (300)
10
+ # ghi :...* (50)
11
+ #
12
+ # It accepts data in the following forms (see the 'extract' method):
13
+ #
14
+ # # { label => value, label => value, ... }
15
+ # # { :values => { label => value, ...} }
16
+ # # { :values => [values] }
17
+ # # {:values => { label => value, label => value }, :labels => [...]}
18
+ # # {:values => [values], :labels => [labels]}
19
+ # # [ [label, value], [label, value], ...]
20
+ # # [[values], [labels]]
21
+ #
22
+ # Numeric parameters:
23
+ # :minval
24
+ # :maxval
25
+ # :maxlen
26
+ #
27
+ # Boolean parameters:
28
+ # :log # logarithmic scale
29
+ # :right # label justification
30
+ #
31
+ # Display parameters:
32
+ # :marker
33
+ # :fill
34
+ # :separator
35
+ # :style # {:bar|:line} - sets default values for marker and fill
36
+ # :showval # numeric value after bar
37
+
38
+ # Text::Graph
39
+ # Port of Wade Johnson's Text::Graph for perl
40
+ # http://search.cpan.org/src/GWADEJ/Text-Graph-0.23/Graph.pm
41
+ #
42
+ # Author: Martin DeMello <martindeme...@gmail.com>
43
+
44
+ module Enumerable
45
+ def minmax
46
+ min = 1.0/0
47
+ max = -1.0/0
48
+ each {|i|
49
+ min = i if i < min
50
+ max = i if i > max
51
+ }
52
+ [min, max]
53
+ end
54
+
55
+ def map_with_index
56
+ a = []
57
+ each_with_index {|e, i| a << yield(e,i)}
58
+ a
59
+ end
60
+ end
61
+
62
+ class TextGraph
63
+ include Math
64
+
65
+ def initialize(data, params = {})
66
+ @data = extract(data)
67
+ @params = {:style => (params[:style] || :bar)}
68
+ apply_style(@params[:style])
69
+ @params.update(params)
70
+ @params[:separator] ||= " :"
71
+ end
72
+
73
+ def update_params(par)
74
+ apply_style(par[:style]) if par[:style]
75
+ @params.update(par)
76
+ end
77
+
78
+ def apply_style(style)
79
+ if style == :bar
80
+ @params[:marker] = "*"
81
+ @params[:fill] = "*"
82
+ elsif style == :line
83
+ @params[:marker] = '*'
84
+ @params[:fill] = ' '
85
+ else
86
+ raise "Invalid style #{style}"
87
+ end
88
+ end
89
+
90
+ def extract(data)
91
+ if data.is_a? Array
92
+ if data.length == 2 and data[0].is_a? Array and data[1].is_a? Array
93
+ # [[values], [labels]]
94
+ a = {}
95
+ a[:values] = data[0]
96
+ a[:labels] = data[1]
97
+ data = a
98
+ else
99
+ # [ [label, value], [label, value], ...]
100
+ a = {:values => [], :labels => []}
101
+ data.each {|i,j| a[:labels] << i; a[:values] << j}
102
+ end
103
+ end
104
+
105
+ if (data.length == 2) and data[:values] and data[:labels]
106
+ if data[:values].is_a? Array
107
+ # {:values => [values], :labels => [labels]}
108
+ # do nothing
109
+ elsif data[:values].is_a? Hash
110
+ # {:values => { label => value, label => value }, :labels => [...]}
111
+ a = data[:labels].map {|i| data[:values][i]}
112
+ data[:values] = a
113
+ else
114
+ raise "Invalid valueset"
115
+ end
116
+ elsif (data.length == 1) and data[:values]
117
+ if data[:values].is_a? Array
118
+ # { :values => [values] }
119
+ data[:labels] = data[:values].map {""}
120
+ elsif data[:values].is_a? Hash
121
+ # { :values => { label => value, ...} }
122
+ data[:labels] = data[:values].keys.sort_by {|i| i.to_s}
123
+ data[:values] = data[:labels].map {|i| data[:values][i]}
124
+ else
125
+ raise "Invalid valueset"
126
+ end
127
+ else
128
+ # { label => value, label => value, ... }
129
+ a = {}
130
+ a[:labels] = data.keys.sort_by {|i| i.to_s}
131
+ a[:values] = a[:labels].map {|i| data[i]}
132
+ data = a
133
+ end
134
+ data[:labels].map! {|i| i.to_s}
135
+ data
136
+ end
137
+
138
+ def make_within(val, min, max)
139
+ (val < min) ? min : (val > max ? max : val)
140
+ end
141
+
142
+ def makebar(val, m, f)
143
+ val = (val + 0.5).to_i
144
+ (val > 0) ? (f*(val - 1) + m) : ""
145
+ end
146
+
147
+ def fmt_labels (right, labels)
148
+ len = labels.map {|i| i.length}.max
149
+ just = right ? :rjust : :ljust
150
+ labels.map {|i| i.send(just, len)}
151
+ end
152
+
153
+ def make_labelled_lines(data)
154
+ labels = fmt_labels(@params[:right], data[:labels])
155
+ lines = histogram(data)
156
+ lines.zip(labels).map {|line, label| label + @params[:separator] + line}
157
+ end
158
+
159
+ def histogram(data)
160
+ values = data[:values].dup
161
+ minval, maxval, maxlen =
162
+ @params[:minval], @params[:maxval], @params[:maxlen]
163
+
164
+ if @params[:log]
165
+ values.map! {|i| log(i)}
166
+ minval = log(minval) rescue 1 if minval
167
+ maxval = log(maxval) rescue 1 if maxval
168
+ end
169
+
170
+ min, max = values.minmax
171
+ minval ||= min
172
+ maxval ||= max
173
+ maxl = maxval - minval + 1
174
+ maxlen ||= maxl
175
+ scale = maxlen*1.0/maxl
176
+ values = values.map {|i|
177
+ j = make_within(i, minval, maxval) - minval
178
+ makebar(j*scale, @params[:marker], @params[:fill])
179
+ }
180
+
181
+ if(@params[:showval])
182
+ values = values.map_with_index {|v, i|
183
+ v.ljust(maxlen) + "(#{data[:values][i]})"
184
+ }
185
+ end
186
+
187
+ values
188
+ end
189
+
190
+ def to_s
191
+ make_labelled_lines(@data).join("\n") + "\n"
192
+ end
193
+ end
194
+
195
+ if __FILE__ == $0
196
+
197
+ a = TextGraph.new({
198
+ :values => [100,142,43,54,111,62,52],
199
+ :labels => %w(aaaa bb ccc dddddd ee f ghi)
200
+ })
201
+
202
+ puts a
203
+
204
+ # aaaa :
205
+ # bb :*
206
+ # ccc :***
207
+ # dddddd :****
208
+ # ee :*********
209
+ # f :**
210
+ # ghi :****
211
+
212
+ puts "-------------------------------------------------------------"
213
+
214
+ a.update_params(:style => :line, :right => true, :showval => true)
215
+ puts a
216
+
217
+ # aaaa : (1)
218
+ # bb :* (2)
219
+ # ccc : * (4)
220
+ # dddddd : * (5)
221
+ # ee : * (10)
222
+ # f : * (3)
223
+ # ghi : * (5)
224
+
225
+ puts "-------------------------------------------------------------"
226
+
227
+ b = TextGraph.new({ :a=>1, :b=>5, :c=>20, :d=>10, :e=>17 }, {:maxlen => 10})
228
+ puts b
229
+
230
+ # a :
231
+ # b :**
232
+ # c :**********
233
+ # d :*****
234
+ # e :********
235
+
236
+ puts "-------------------------------------------------------------"
237
+
238
+ c = TextGraph.new({:values => { :a=>1, :b=>5, :c=>20, :d=>10, :e=>17 },
239
+ :labels => [:a, :c, :d]},
240
+ {:minval => 0, :maxval => 15, :showval => true})
241
+ puts c
242
+
243
+ # a :* (1)
244
+ # c :*************** (20)
245
+ # d :********** (10)
246
+
247
+ puts "-------------------------------------------------------------"
248
+
249
+ d = TextGraph.new([[10,22,43,500,1000,300,50], %w(aaaa bb ccc dddddd ee f ghi)],
250
+ { :style => :line,
251
+ :right => true, # right-justify labels
252
+ :fill => '.', # change fill-marker
253
+ :log => false, # logarithmic graph
254
+ :showval => true # show actual values
255
+ }
256
+ )
257
+ puts d
258
+
259
+ # aaaa : (1)
260
+ # bb :..* (22)
261
+ # ccc :...* (43)
262
+ # dddddd :.....* (500)
263
+ # ee :......*(1000)
264
+ # f :.....* (300)
265
+ # ghi :...* (50)
266
+
267
+ end