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,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
+