stella 0.3.2

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