solutious-stella 0.6.0 → 0.7.0.001

Sign up to get free protection for your applications and to get access to all the features.
Files changed (55) hide show
  1. data/CHANGES.txt +3 -15
  2. data/LICENSE.txt +1 -1
  3. data/README.rdoc +90 -60
  4. data/Rakefile +32 -42
  5. data/bin/stella +138 -0
  6. data/examples/basic/listing_ids.csv +7 -0
  7. data/examples/basic/plan.rb +71 -0
  8. data/lib/stella.rb +57 -104
  9. data/lib/stella/cli.rb +66 -0
  10. data/lib/stella/client.rb +197 -0
  11. data/lib/stella/config.rb +87 -0
  12. data/lib/stella/data.rb +85 -0
  13. data/lib/stella/data/http.rb +2 -257
  14. data/lib/stella/data/http/body.rb +15 -0
  15. data/lib/stella/data/http/request.rb +116 -0
  16. data/lib/stella/data/http/response.rb +92 -0
  17. data/lib/stella/dsl.rb +5 -0
  18. data/lib/stella/engine.rb +55 -0
  19. data/lib/stella/engine/functional.rb +39 -0
  20. data/lib/stella/engine/load.rb +106 -0
  21. data/lib/stella/exceptions.rb +15 -0
  22. data/lib/stella/guidelines.rb +18 -0
  23. data/lib/stella/mixins.rb +2 -0
  24. data/lib/stella/stats.rb +3 -7
  25. data/lib/stella/testplan.rb +95 -220
  26. data/lib/stella/testplan/stats.rb +26 -0
  27. data/lib/stella/testplan/usecase.rb +67 -0
  28. data/lib/stella/utils.rb +126 -0
  29. data/lib/{util → stella/utils}/httputil.rb +0 -0
  30. data/lib/stella/version.rb +15 -0
  31. data/lib/threadify.rb +0 -6
  32. data/stella.gemspec +43 -49
  33. data/support/example_webapp.rb +246 -0
  34. data/support/useragents.txt +75 -0
  35. metadata +66 -31
  36. data/bin/example_test.rb +0 -82
  37. data/bin/example_webapp.rb +0 -63
  38. data/lib/logger.rb +0 -79
  39. data/lib/stella/clients.rb +0 -161
  40. data/lib/stella/command/base.rb +0 -20
  41. data/lib/stella/command/form.rb +0 -36
  42. data/lib/stella/command/get.rb +0 -44
  43. data/lib/stella/common.rb +0 -53
  44. data/lib/stella/crypto.rb +0 -88
  45. data/lib/stella/data/domain.rb +0 -82
  46. data/lib/stella/environment.rb +0 -66
  47. data/lib/stella/functest.rb +0 -105
  48. data/lib/stella/loadtest.rb +0 -186
  49. data/lib/stella/testrunner.rb +0 -64
  50. data/lib/storable.rb +0 -280
  51. data/lib/timeunits.rb +0 -65
  52. data/tryouts/drb/drb_test.rb +0 -65
  53. data/tryouts/drb/open4.rb +0 -19
  54. data/tryouts/drb/slave.rb +0 -27
  55. data/tryouts/oo_tryout.rb +0 -30
@@ -0,0 +1,116 @@
1
+
2
+
3
+ module Stella::Data::HTTP
4
+ class Request < Storable
5
+ include Gibbler::Complex
6
+ include Stella::Data::Helpers
7
+
8
+ # A hash containing blocks to be executed depending on the HTTP response status.
9
+ # The hash keys are numeric HTTP Status Codes.
10
+ #
11
+ # 200 => { ... }
12
+ # 304 => { ... }
13
+ # 500 => { ... }
14
+ #
15
+ attr_accessor :response_handler
16
+
17
+ field :desc
18
+ field :header
19
+ field :uri
20
+ field :wait
21
+ field :params
22
+ field :body
23
+ field :http_method
24
+ field :http_version
25
+ field :content_type
26
+
27
+ def has_body?
28
+ !@body.nil? && !@body.empty?
29
+ end
30
+
31
+ def initialize (method, uri_str, version="1.1", &definition)
32
+ @uri = uri_str
33
+ @http_method, @http_version = method, version
34
+ @headers, @params, @response_handler = {}, {}, {}
35
+ @wait = 0
36
+ @desc = "Request"
37
+ @body = Stella::Data::HTTP::Body.new
38
+ instance_eval &definition unless definition.nil?
39
+ end
40
+
41
+ def desc(*args)
42
+ @desc = args.first unless args.empty?
43
+ @desc
44
+ end
45
+
46
+ def content_type(*args)
47
+ @content_type = args.first unless args.empty?
48
+ @content_type
49
+ end
50
+
51
+ def wait(*args)
52
+ @wait = args.first unless args.empty?
53
+ @wait
54
+ end
55
+ alias_method :sleep, :wait
56
+
57
+ def headers(*args)
58
+ @headers.merge! args.first unless args.empty?
59
+ @headers
60
+ end
61
+ alias_method :header, :headers
62
+
63
+ def params(*args)
64
+ @params.merge! args.first unless args.empty?
65
+ @params
66
+ end
67
+ alias_method :param, :params
68
+
69
+ def response(*args, &definition)
70
+ if definition.nil?
71
+ @response_handler
72
+ else
73
+ args << 200 if args.empty?
74
+ args.each do |status|
75
+ @response_handler[status] = definition
76
+ end
77
+ end
78
+ end
79
+
80
+ # +content+ can be literal content or a file path
81
+ def body(*args)
82
+ return @body if args.empty?
83
+ content, form_param, content_type = *args
84
+
85
+ @body.form_param = form_param if form_param
86
+ @body.content_type = content_type if content_type
87
+
88
+ if File.exists?(content)
89
+ @body.content = File.new(content)
90
+ @body.content_type ||= "application/x-www-form-urlencoded"
91
+ else
92
+ @body.content = content
93
+ end
94
+
95
+ end
96
+
97
+ def inspect
98
+ str = "%s %s HTTP/%s" % [http_method, uri.to_s, http_version]
99
+ #str << $/ + headers.join($/) unless headers.empty?
100
+ #str << $/ + $/ + body.to_s if body
101
+ str
102
+ end
103
+
104
+ def to_s
105
+ str = "%s %s HTTP/%s" % [http_method, uri.to_s, http_version]
106
+ str
107
+ end
108
+
109
+ def cookies
110
+ return [] if !header.is_a?(Hash) || header[:Cookie].empty?
111
+ header[:Cookie]
112
+ end
113
+
114
+ end
115
+
116
+ end
@@ -0,0 +1,92 @@
1
+
2
+
3
+ module Stella::Data::HTTP
4
+
5
+ class Response < Storable
6
+ include Gibbler::Complex
7
+
8
+ attr_reader :raw_data
9
+
10
+ field :time => DateTime
11
+ field :client_ip => String
12
+ field :server_ip => String
13
+ field :header => String
14
+ field :body => String
15
+ field :status => String
16
+ field :message => String
17
+ field :http_version => String
18
+
19
+ def initialize(raw_data=nil)
20
+ @raw_data = raw_data
21
+ parse(@raw_data)
22
+ end
23
+
24
+ def parse(raw)
25
+ return unless raw
26
+ @status, @http_version, @message, @header, @body = HTTPUtil::parse_http_response(raw)
27
+ end
28
+
29
+ def has_body?
30
+ !@body.nil? && !@body.empty?
31
+ end
32
+ def has_request?
33
+ false
34
+ end
35
+ def has_response?
36
+ false
37
+ end
38
+
39
+
40
+ def body
41
+ return nil unless @body
42
+ #TODO: Move to HTTPResponse::Body.to_s
43
+ if is_binary?
44
+ "[skipping binary content]"
45
+ elsif is_gzip?
46
+ #require 'zlib'
47
+ #Zlib::Inflate.inflate(@body)
48
+ "[skipping gzip content]"
49
+ else
50
+ @body
51
+ end
52
+ end
53
+
54
+ def headers
55
+ headers = []
56
+ header.each_pair do |n,v|
57
+ headers << [n.to_s.gsub('_', '-'), v[0]]
58
+ end
59
+ headers
60
+ end
61
+
62
+ def is_binary?
63
+ (!is_text?) == true
64
+ end
65
+
66
+ def is_text?
67
+ (!header[:Content_Type].nil? && (header[:Content_Type][0].is_a? String) && header[:Content_Type][0][/text/] != nil)
68
+ end
69
+
70
+ def is_gzip?
71
+ (!header[:Content_Encoding].nil? && (header[:Content_Encoding][0].is_a? String) && header[:Content_Encoding][0][/gzip/] != nil)
72
+ end
73
+
74
+ def inspect
75
+ str = "HTTP/%s %s (%s)" % [@http_version, @status, @message]
76
+ str << $/ + headers.join($/)
77
+ str << $/ + $/ + body if body
78
+ str
79
+ end
80
+
81
+ def to_s
82
+ str = "%s: HTTP/%s %s (%s)" % [time.strftime(NICE_TIME_FORMAT), @http_version, @status, @message]
83
+ str
84
+ end
85
+
86
+
87
+ def cookies
88
+ return [] unless header.is_a?(Array) && !header[:Set_Cookie].empty?
89
+ header[:Set_Cookie]
90
+ end
91
+ end
92
+ end
@@ -0,0 +1,5 @@
1
+
2
+
3
+ module Stella::DSL; end
4
+
5
+ Stella::Utils.require_glob(STELLA_LIB_HOME, 'stella', 'dsl', '*.rb')
@@ -0,0 +1,55 @@
1
+
2
+
3
+ module Stella::Engine
4
+ module Base
5
+ extend self
6
+ def run
7
+ raise "override the run method"
8
+ end
9
+
10
+ def update(*args)
11
+ what, *args = args
12
+ Stella.ld "OBSERVER UPDATE: #{what}"
13
+ if !respond_to?("update_#{what}")
14
+ Stella.ld "NO UPDATE HANDLER FOR: #{what}"
15
+ else
16
+ Stella.rescue {
17
+ self.send("update_#{what}", *args)
18
+ }
19
+ end
20
+ end
21
+
22
+ def update_send_request(client_id, usecase, meth, uri, req, params, counter)
23
+ notice = "repeat: #{counter-1}" if counter > 1
24
+ Stella.li2 ' ' << " %-46s %16s ".att(:reverse) % [req.desc, notice]
25
+ end
26
+
27
+ def update_receive_response(client_id, usecase, meth, uri, req, params, container)
28
+ Stella.li ' %-59s %3d' % [uri, container.status]
29
+ Stella.li2 " Method: " << req.http_method
30
+ Stella.li2 " Params: " << params.inspect
31
+ Stella.li3 $/, " Headers:"
32
+ container.headers.all.each do |pair|
33
+ Stella.li3 " %s: %s" % pair
34
+ end
35
+ Stella.li3 $/, " Content:"
36
+ Stella.li3 container.body.empty? ? ' [empty]' : container.body
37
+ Stella.li2 $/
38
+ end
39
+
40
+ def update_execute_response_handler(client_id, req, container)
41
+ end
42
+
43
+ def update_error_execute_response_handler(client_id, ex, req, container)
44
+ Stella.le ex.message
45
+ end
46
+
47
+ def update_request_error(client_id, usecase, meth, uri, req, params, ex)
48
+ desc = "#{usecase.desc} > #{req.desc}"
49
+ Stella.le ' Client%-3s %-45s %s' % [client_id, desc, ex.message]
50
+ end
51
+
52
+ end
53
+ end
54
+
55
+ Stella::Utils.require_glob(STELLA_LIB_HOME, 'stella', 'engine', '*.rb')
@@ -0,0 +1,39 @@
1
+
2
+ module Stella::Engine
3
+ module Functional
4
+ extend Stella::Engine::Base
5
+ extend self
6
+
7
+ def run(plan, opts={})
8
+ opts = {
9
+ :hosts => [],
10
+ :benchmark => false,
11
+ :repetitions => 1
12
+ }.merge! opts
13
+ Stella.ld "OPTIONS: #{opts.inspect}"
14
+ Stella.li2 "Hosts: " << opts[:hosts].join(', ') if !opts[:hosts].empty?
15
+
16
+ client = Stella::Client.new opts[:hosts].first
17
+ client.add_observer(self)
18
+ client.enable_benchmark_mode if opts[:benchmark]
19
+
20
+ plan.usecases.each_with_index do |uc,i|
21
+ desc = (uc.desc || "Usecase ##{i+1}")
22
+ Stella.li ' %-65s '.att(:reverse).bright % [desc]
23
+ Stella.rescue { client.execute uc }
24
+ end
25
+
26
+ Drydock::Screen.flush
27
+ end
28
+
29
+ end
30
+ end
31
+
32
+ __END__
33
+
34
+
35
+ $ stella verify -p examples/basic/plan.rb http://localhost:3114
36
+ $ stella load -p examples/basic/plan.rb http://localhost:3114
37
+ $ stella remote-load -p examples/basic/plan.rb http://localhost:3114
38
+ $ stella remote-verify -p examples/basic/plan.rb http://localhost:3114
39
+
@@ -0,0 +1,106 @@
1
+
2
+ module Stella::Engine
3
+ module Load
4
+ extend Stella::Engine::Base
5
+ extend self
6
+
7
+ def run(plan, opts={})
8
+ opts = {
9
+ :hosts => [],
10
+ :users => 1,
11
+ :time => nil,
12
+ :benchmark => false,
13
+ :repetitions => 1
14
+ }.merge! opts
15
+ opts[:users] = plan.usecases.size if opts[:users] < plan.usecases.size
16
+ opts[:users] = 1000 if opts[:users] > 1000
17
+
18
+ Stella.ld "OPTIONS: #{opts.inspect}"
19
+ Stella.li2 "Hosts: " << opts[:hosts].join(', ')
20
+
21
+ packages = build_thread_package plan, opts
22
+ Drydock::Screen.flush
23
+
24
+ Thread.ify packages, :threads => opts[:users] do |package|
25
+ (1..opts[:repetitions]).to_a.each do |rep|
26
+ # We store client specific data in the usecase
27
+ # so we clone it here so each thread is unique.
28
+ Stella.rescue { package.client.execute package.usecase }
29
+ Drydock::Screen.flush
30
+ end
31
+ end
32
+
33
+ Drydock::Screen.flush
34
+ end
35
+
36
+ protected
37
+ class ThreadPackage
38
+ attr_accessor :index
39
+ attr_accessor :client
40
+ attr_accessor :usecase
41
+ def initialize(i, c, u)
42
+ @index, @client, @usecase = i, c, u
43
+ end
44
+ end
45
+
46
+ def build_thread_package(plan, opts)
47
+ packages, pointer = Array.new(opts[:users]), 0
48
+ plan.usecases.each_with_index do |usecase,i|
49
+
50
+ count = case opts[:users]
51
+ when 0..9
52
+ if (opts[:users] % plan.usecases.size > 0)
53
+ raise Stella::Testplan::WackyRatio, "User count does not match usecase count evenly"
54
+ else
55
+ (opts[:users] / plan.usecases.size)
56
+ end
57
+ else
58
+ (opts[:users] * usecase.ratio).to_i
59
+ end
60
+
61
+ Stella.ld "THREAD PACKAGE: #{usecase.desc} #{pointer} #{(pointer+count)} #{count}"
62
+ # Fill the thread_package with the contents of the block
63
+ packages.fill(pointer, count) do |index|
64
+ Stella.li2 "Creating client ##{index+1} "
65
+ client = Stella::Client.new opts[:hosts].first, index+1
66
+ client.add_observer(self)
67
+ client.enable_benchmark_mode if opts[:benchmark]
68
+ ThreadPackage.new(index+1, client, usecase.clone)
69
+ end
70
+ pointer += count
71
+ end
72
+ packages
73
+ end
74
+
75
+ def update_send_request(client_id, usecase, meth, uri, req, params, counter)
76
+
77
+ end
78
+
79
+ def update_receive_response(client_id, usecase, meth, uri, req, params, container)
80
+ desc = "#{usecase.desc} > #{req.desc}"
81
+ Stella.li ' Client%-3s %3d %-6s %-45s %s' % [client_id, container.status, req.http_method, desc, uri]
82
+ end
83
+
84
+ def update_execute_response_handler(client_id, req, container)
85
+ end
86
+
87
+ def update_error_execute_response_handler(client_id, ex, req, container)
88
+ end
89
+
90
+ def update_request_error(client_id, usecase, meth, uri, req, params, ex)
91
+ desc = "#{usecase.desc} > #{req.desc}"
92
+ Stella.le ' Client%-3s %-45s %s' % [client_id, desc, ex.message]
93
+ end
94
+
95
+
96
+ end
97
+ end
98
+
99
+ __END__
100
+
101
+
102
+ $ stella verify -p examples/basic/plan.rb http://localhost:3114
103
+ $ stella load -p examples/basic/plan.rb http://localhost:3114
104
+ $ stella remote-load -p examples/basic/plan.rb http://localhost:3114
105
+ $ stella remote-verify -p examples/basic/plan.rb http://localhost:3114
106
+
@@ -0,0 +1,15 @@
1
+
2
+
3
+ module Stella
4
+ class Error < RuntimeError
5
+ def initialize(obj=nil); @obj = obj; end
6
+ def message; "#{self.class}: #{@obj}"; end
7
+ end
8
+
9
+ class InvalidOption < Stella::Error
10
+ end
11
+
12
+ class NoHostDefined < Stella::Error
13
+ end
14
+
15
+ end
@@ -0,0 +1,18 @@
1
+
2
+
3
+ module Stella
4
+ module Guidelines
5
+ extend self
6
+ AFE = "Always fail early"
7
+ ABA = "Always be accurate"
8
+ CBC = "Consistency before cuteness"
9
+ NDP = "No defensive programming"
10
+ def inspect
11
+ all = Stella::Guidelines.constants
12
+ g = all.collect { |c| '%s="%s"' % [c, const_get(c)] }
13
+ %q{#<Stella::Guidelines:0x%s %s>} % [self.object_id, g.join(' ')]
14
+ end
15
+ end
16
+ end
17
+
18
+ p Stella::Guidelines if __FILE__ == $0