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,63 @@
1
+
2
+
3
+ module Stella
4
+ class Logger
5
+ attr_accessor :debug
6
+
7
+ # +args+ is a hash of initialization arguments
8
+ # * <tt>:info_logger</tt> The IO class for info level logging. Default: STDOUT
9
+ # * <tt>:error_logger</tt> The IO class for error level logging. Default: STDERR
10
+ # * <tt>:debug_logger</tt> The IO class for error level logging. Default: STDERR
11
+ # * <tt>:debug</tt> Log debugging output, true or false (default)
12
+ def initialize(args={})
13
+ @debug = args[:debug] || false
14
+ @info_logger = args[:info_logger] || STDOUT
15
+ @error_logger = args[:error_logger] || STDERR
16
+ @debug_logger = args[:debug_logger] || STDERR
17
+ end
18
+
19
+ # +msgs+ is an array which can contain a list of messages or a symbol and a list of values
20
+ # If the first element is a symbol, this will return the output of Stella::Text.msg(msgs[0],msgs[1..-1])
21
+ def info(*msgs)
22
+ return if !msgs || msgs.empty?
23
+ if msgs[0].is_a? Symbol
24
+ txtsym = msgs.shift
25
+ @info_logger.puts Stella::TEXT.msg(txtsym, msgs)
26
+ else
27
+ msgs.each do |m|
28
+ @info_logger.puts m
29
+ end
30
+ end
31
+ @info_logger.flush
32
+ end
33
+
34
+ # Print all messages on a single line.
35
+ def info_print(*msgs)
36
+ msgs.each do |m|
37
+ @info_logger.print m
38
+ end
39
+ @info_logger.flush
40
+ end
41
+
42
+ # Print all messages on a single line.
43
+ def info_printf(pattern, *vals)
44
+ @info_logger.printf(pattern, *vals)
45
+ @info_logger.flush
46
+ end
47
+
48
+ def debug(*msgs)
49
+ return unless @debug
50
+ msgs.each do |m|
51
+ @debug_logger.puts "DEBUG: #{m}"
52
+ end
53
+ @debug_logger.flush
54
+ end
55
+ def error(ex, prefix="ERR: ")
56
+ @error_logger.puts "#{prefix}#{ex.message}"
57
+ return unless @debug
58
+ @error_logger.puts("#{prefix}------------------------------------------")
59
+ @error_logger.puts("#{prefix}#{ex.backtrace.join("\n")}")
60
+ @error_logger.puts("#{prefix}------------------------------------------")
61
+ end
62
+ end
63
+ end
@@ -0,0 +1,82 @@
1
+
2
+
3
+
4
+ module Stella
5
+
6
+ # An object for HTTP response content
7
+ #
8
+ class Response < Storable
9
+ attr_accessor :errors, :content, :messages
10
+ attr_writer :success
11
+
12
+ def initialize
13
+ @success = false
14
+ @errors = []
15
+ @messages = []
16
+ @content = {}
17
+ end
18
+
19
+ def success?
20
+ @success
21
+ end
22
+
23
+ def add(key, value)
24
+ @content[key] = value
25
+ end
26
+
27
+ def get(key)
28
+ @content[key] if @content.has_key? key
29
+ end
30
+
31
+ def message(msg)
32
+ @messages.push(msg)
33
+ end
34
+
35
+ def error(msg)
36
+ @errors.push(msg)
37
+ end
38
+
39
+ def output(format='yaml')
40
+ format = 'yaml' unless self.respond_to? "output_#{format}"
41
+ #STDERR.puts "OUTPUT: #{format}"
42
+ self.send("output_#{format}")
43
+ end
44
+
45
+ def to_hash
46
+ h = {}
47
+ h[:version] = API_VERSION
48
+ h[:errors] = @errors unless @errors.empty?
49
+ h[:messages] = @messages unless @messages.empty?
50
+ h[:content] = @content || {}
51
+ h[:success] = @success || false
52
+ h
53
+ end
54
+
55
+ def output_zip
56
+ output = @content
57
+ end
58
+
59
+ def output_yaml
60
+ to_hash.to_yaml
61
+ end
62
+
63
+ # http://evang.eli.st/blog/2007/2/22/my-rails-gotcha-custom-to_xml-in-a-hash-or-array
64
+ # http://api.rubyonrails.org/classes/ActiveRecord/XmlSerialization.html#M000910
65
+ def output_xml
66
+ output = "<StellaResponse success=\":[\">\n"
67
+ output << "<todo>implement XML</todo>\n"
68
+ output << "</StellaResponse>\n"
69
+ end
70
+
71
+ def output_json
72
+ to_hash.to_json
73
+ end
74
+
75
+ def output_html
76
+ "hello!"
77
+ end
78
+
79
+ end
80
+
81
+ end
82
+
@@ -0,0 +1,116 @@
1
+
2
+
3
+ module Stella
4
+ class Storable
5
+
6
+ SupportedFormats= {
7
+ 'yaml' => 'yml', # format name => file extension
8
+ 'yml' => 'yml',
9
+ 'csv' => 'csv',
10
+ 'tsv' => 'tsv',
11
+ 'json' => 'json'
12
+ }.freeze unless defined? SupportedFormats
13
+
14
+ attr_reader :format
15
+
16
+ def format=(v)
17
+ raise "Unsupported format: #{v}" unless SupportedFormats.has_key?(v)
18
+ @format = v
19
+ end
20
+
21
+ def field_names
22
+ raise "You need to override field_names (#{self.class})"
23
+ end
24
+
25
+ def self.undump(format, file=[])
26
+ #raise "Format not defined (#{@format})" unless self.method_defined?("to_#{@format}")
27
+ #puts "LOAD: from_#{format}"
28
+ send("from_#{format}", file)
29
+ end
30
+
31
+
32
+ def dump(format="yaml", with_titles=true)
33
+ #raise "Format not defined (#{@format})" unless self.method_defined?("to_#{@format}")
34
+ #puts "DUMP: to_#{format}"
35
+ self.send("to_#{format}", with_titles)
36
+ end
37
+
38
+ def to_hash(with_titles=true)
39
+ tmp = {}
40
+
41
+ field_names.each do |fname|
42
+ tmp[fname] = self.send(fname.to_s)
43
+ end
44
+
45
+ tmp
46
+ end
47
+
48
+ def to_yaml(with_titles=true)
49
+ require 'yaml'
50
+ to_hash.to_yaml
51
+ end
52
+
53
+ def to_delimited(with_titles=false, delim=',')
54
+ values = []
55
+ field_names.each do |fname|
56
+ values << self.send(fname.to_s) # TODO: escape values
57
+ end
58
+ output = values.join(delim)
59
+ output = field_names.join(delim) << $/ << output if with_titles
60
+ output
61
+ end
62
+ def to_tsv(with_titles=false)
63
+ to_delimited(with_titles, "\t")
64
+ end
65
+ def to_csv(with_titles=false)
66
+ to_delimited(with_titles, ',')
67
+ end
68
+
69
+
70
+ def self.from_delimited(from=[],delim=',')
71
+ return if from.empty?
72
+ # We grab an instance of the class so we can
73
+ hash = {}
74
+
75
+ fnames = values = []
76
+ if (from.size > 1 && !from[1].empty?)
77
+ fnames = from[0].chomp.split(delim)
78
+ values = from[1].chomp.split(delim)
79
+ else
80
+ fnames = self.new.field_names
81
+ values = from[0].chomp.split(delim)
82
+ end
83
+
84
+ fnames.each_with_index do |key,index|
85
+ next unless values[index]
86
+ number_or_string = (values[index].match(/[\d\.]+/)) ? values[index].to_f : values[index]
87
+ hash[key.to_sym] = number_or_string
88
+ end
89
+ hash
90
+ end
91
+ def self.from_tsv(from=[])
92
+ self.from_delimited(from, "\t")
93
+ end
94
+ def self.from_csv(from=[])
95
+ self.from_delimited(from, ',')
96
+ end
97
+
98
+ def self.from_hash(from={})
99
+ return if from.empty?
100
+ me = self.new
101
+ fnames = me.to_hash.keys
102
+ fnames.each do |key|
103
+ # NOTE: this will skip generated values b/c they don't have a setter method
104
+ me.send("#{key}=", from[key]) if self.method_defined?("#{key}=")
105
+ end
106
+ me
107
+ end
108
+ def self.from_yaml(from=[])
109
+ require 'yaml'
110
+ # from is an array of strings
111
+ from_str = from.join('')
112
+ YAML::load(from_str)
113
+ end
114
+
115
+ end
116
+ end
@@ -0,0 +1,106 @@
1
+
2
+
3
+
4
+ module Stella
5
+
6
+ class InvalidArgument < RuntimeError
7
+ attr_accessor :name
8
+ def initialize(name)
9
+ @name = name
10
+ end
11
+ def message
12
+ Stella::TEXT.err(:error_invalid_argument, @name)
13
+ end
14
+ end
15
+
16
+ class UnavailableAdapter < RuntimeError
17
+ attr_accessor :name
18
+ def initialize(name)
19
+ @name = name
20
+ end
21
+ def message
22
+ Stella::TEXT.err(:error_unavailable_adapter, @name)
23
+ end
24
+ end
25
+
26
+ class UnknownValue < RuntimeError
27
+ attr_accessor :value
28
+ def initialize(value)
29
+ @value = value.to_s
30
+ end
31
+ def message
32
+ Stella::TEXT.err(:error_unknown_value, @value)
33
+ end
34
+ end
35
+
36
+ class UnsupportedLanguage < RuntimeError
37
+ end
38
+
39
+ class Util
40
+
41
+ # process_useragents
42
+ #
43
+ # We read the useragents.txt file into a hash index which
44
+ # useful for refering to specific useragents on the command-line
45
+ # and other places.
46
+ #
47
+ # Examples:
48
+ # --agent=ie-5
49
+ # --agent=ff-2.0.0.2-linux
50
+ # --agent=chrome-windows
51
+ # --agent=safari-3.0-osx
52
+ #
53
+ def self.process_useragents(ua_strs=[])
54
+ agents_index = {}
55
+ return agents_index if ua_strs.empty?
56
+
57
+ ua_strs.each do |ua_str|
58
+ ua_str.chomp! # remove trailing line separator
59
+
60
+ ua = UserAgent.parse(ua_str)
61
+
62
+ # Standardize the index values
63
+ # i.e. firefox-3-windows
64
+ name = ua.browser.downcase.tr(' ', '')
65
+ version = ua.version.to_i
66
+ os = ua.platform.downcase.tr(' ', '')
67
+
68
+ # Non-windows operating systems have the OS string inside of "os"
69
+ # rather than "platform". We look there for the value and then
70
+ # standardize the values.
71
+ # i.e. firefox-3-osx
72
+ if os != 'windows'
73
+ os = ua.os.downcase
74
+ os = 'linux' if os.match(/^linux/)
75
+ os = 'osx' if os.match(/mac os x/)
76
+ os = 'bsd' if os.match(/bsd/)
77
+ end
78
+
79
+ # Make sure all arrays exist before we populate them
80
+ agents_index[name] ||= []
81
+ agents_index["#{name}-#{version}"] ||= []
82
+ agents_index["#{name}-#{version}-#{os}"] ||= []
83
+ agents_index["#{name}-#{os}"] ||= [] # We use this one for failover
84
+
85
+ # Populate each list.
86
+ agents_index[name] << ua
87
+ agents_index["#{name}-#{version}"] << ua
88
+ agents_index["#{name}-#{version}-#{os}"] << ua
89
+ agents_index["#{name}-#{os}"] << ua
90
+
91
+ end
92
+
93
+ agents_index
94
+ end
95
+
96
+ # expand_str
97
+ #
98
+ # Turns a string like ff-4-freebsd into ["ff","4","freebsd"]
99
+ # We use this for command-line values liek agent and rampup
100
+ def self.expand_str(str)
101
+ str.split(/\s*[,\-]\s*/) # remove extra spaces at the same time.
102
+ end
103
+
104
+ end
105
+
106
+ end
@@ -0,0 +1,34 @@
1
+
2
+ module Stella::Test
3
+
4
+ module Base
5
+
6
+ attr_reader :message
7
+ attr_reader :elapsed_time_avg, :transaction_rate_avg, :vusers_avg, :response_time_avg
8
+ attr_reader :elapsed_time_sdev, :transaction_rate_sdev, :vusers_sdev, :response_time_sdev
9
+ attr_accessor :transactions_total, :headers_transferred_total, :data_transferred_total
10
+ attr_accessor :successful_total, :failed_total, :elapsed_time_total, :throughput_avg, :throughput_sdev
11
+
12
+ def availability
13
+ return 0 if @successful_total == 0
14
+ (@transactions_total / @successful_total).to_f * 100
15
+ end
16
+
17
+
18
+ # Defines the fields the are output by to_hash and to_csv.
19
+ # For to_csv, this also determines the field order
20
+ def field_names
21
+ [
22
+ :message,
23
+ :elapsed_time_avg, :transaction_rate_avg, :vusers_avg, :response_time_avg,
24
+ :elapsed_time_sdev, :transaction_rate_sdev, :vusers_sdev, :response_time_sdev,
25
+
26
+ :transactions_total, :successful_total, :failed_total,
27
+ :data_transferred_total, :headers_transferred_total,
28
+
29
+ :elapsed_time_total, :availability, :throughput_avg, :throughput_sdev
30
+ ]
31
+ end
32
+
33
+ end
34
+ end
@@ -0,0 +1,79 @@
1
+
2
+
3
+ module Stella
4
+
5
+
6
+ module Test
7
+
8
+ # Stella::Test::Definition
9
+ #
10
+ # This class defines the properties of load test. These are "generic" properties
11
+ # in that they don't relate to a specific tool.
12
+ class Definition
13
+
14
+ # Stella::Test::Definition::Rampup
15
+ #
16
+ # This class holds the values for a rampup: interval and ceiling.
17
+ class Rampup
18
+ attr_accessor :interval
19
+ attr_accessor :ceiling
20
+ def initialize(interval, ceiling)
21
+ @interval = interval
22
+ @ceiling = ceiling
23
+ end
24
+ def to_s
25
+ to_a.join(',')
26
+ end
27
+ def to_a
28
+ [interval,ceiling]
29
+ end
30
+ end
31
+
32
+ # Number of virtual users to create or to begin with if rampup is specific.
33
+ attr_accessor :vusers
34
+ # The total number of requests per test
35
+ attr_accessor :requests
36
+ # The number of requests per virtual user
37
+ attr_accessor :request_ratio
38
+
39
+ # Number of times to repeat the test run. Integer.
40
+ attr_reader :repetitions
41
+ # The amount of time to pause between test runs
42
+ attr_accessor :sleep
43
+ # Warmup factor (0.1 - 1) for a single test run before the actual test.
44
+ # A warmup factor of 0.5 means run a test run at 50% strength.
45
+ attr_accessor :warmup
46
+ # Contains an interval and maximum threshold to increase virtual users.
47
+ # Rampup object, [R,M] where R is the interval and M is the maximum.
48
+ attr_accessor :rampup
49
+ # An array of string appropriate for a User-Agent HTTP header
50
+ attr_accessor :agents
51
+ # A short reminder to yourself what you're testing
52
+ attr_accessor :message
53
+
54
+ def initialize
55
+ @repetitions = 3
56
+ end
57
+
58
+ def repetitions=(v)
59
+ return unless v && v > 0
60
+ @repetitions = v
61
+ end
62
+
63
+ def rampup=(v)
64
+ return unless v
65
+
66
+ if (v.is_a? Rampup)
67
+ @rampup = v
68
+ elsif (v.is_a?(Array) && v.size == 2)
69
+ @rampup = Rampup.new(v[0], v[1])
70
+ else
71
+ raise UnknownValue.new(v.to_s)
72
+ end
73
+ end
74
+
75
+ end
76
+ end
77
+
78
+ end
79
+