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,2 @@
1
+
2
+ Stella::Utils.require_glob(STELLA_LIB_HOME, 'stella', 'mixins', '*.rb')
@@ -1,5 +1,4 @@
1
1
 
2
-
3
2
  module Stella
4
3
  # Based on Mongrel::Stats, Copyright (c) 2005 Zed A. Shaw
5
4
  class Stats
@@ -17,12 +16,9 @@ class Stats
17
16
 
18
17
  # Resets the internal counters so you can start sampling again.
19
18
  def reset
20
- @sum = 0.0
21
- @sumsq = 0.0
19
+ @n, @sum, @sumsq = 0.0, 0.0, 0.0
22
20
  @last_time = Time.new
23
- @n = 0.0
24
- @min = 0.0
25
- @max = 0.0
21
+ @min, @max = 0.0, 0.0
26
22
  end
27
23
 
28
24
  # Adds a sampling to the calculations.
@@ -81,4 +77,4 @@ class Stats
81
77
  @last_time = now
82
78
  end
83
79
  end
84
- end
80
+ end
@@ -1,237 +1,112 @@
1
+ require 'stella/testplan/usecase'
2
+ require 'stella/testplan/stats'
1
3
 
2
4
  module Stella
3
- class TestPlan
4
- class ResponseHandler
5
- attr_accessor :action
6
- attr_accessor :times
7
- attr_accessor :wait
8
- def initialize(action, times=1, wait=1)
9
- @action = action
10
- @times = times
11
- @wait = wait
12
- end
13
- end
5
+ class Testplan
6
+ include Gibbler::Complex
7
+
8
+ class WackyRatio < Stella::Error
14
9
  end
15
- end
16
-
17
- module Stella
18
-
19
- class TestPlan
20
- # The name of the testplan.
21
- attr_accessor :name
22
- # A brief description of this testplan
23
- attr_accessor :description
24
- # Used as the default protocol for the testplan. One of: http, https
25
- attr_accessor :protocol
26
- # A Stella::TestPlan::Auth object
27
- attr_accessor :auth
28
- # An array of Stella::TestPlan::Request objects representing all "primary" requests
29
- # for the given test plan (an html page for example). Each primary Request object can have an array of "auxilliary"
30
- # requests which represent dependencies for that resource (javascript, images, callbacks, etc...).
31
- attr_accessor :requests
32
-
33
- def initialize(name=:anonymous)
34
- @name = name
35
- @requests = []
36
- @servers = []
37
- @protocol = "http"
38
- end
39
-
40
10
 
41
- def description
42
- @description
43
- end
44
- def description=(val)
45
- val = val.first if val.is_a? Array
46
- @description = val
11
+
12
+ attr_accessor :usecases
13
+ attr_accessor :base_path
14
+ attr_accessor :desc
15
+ attr_reader :stats
16
+
17
+ def initialize
18
+ @desc, @usecases = "Stella's plan", []
19
+ @testplan_current_ratio = 0
20
+ @stats = Stella::Testplan::Stats.new
21
+ end
22
+
23
+ def self.load_file(path)
24
+ conf = File.read path
25
+ plan = Stella::Testplan.new
26
+ plan.base_path = File.dirname path
27
+ # eval so the DSL code can be executed in this namespace.
28
+ plan.instance_eval conf
29
+ plan
30
+ end
31
+
32
+ def check!
33
+ # Adjust ratios if necessary
34
+ needy = @usecases.select { |u| u.ratio == -1 }
35
+ needy.each do |u|
36
+ u.ratio = (remaining_ratio / needy.size).to_f
47
37
  end
48
-
49
- alias :desc :description
50
- alias :desc= :description=
51
-
52
- # Append a Stella::TestPlan::Request object to +requests+.
53
- def add_request(req)
54
- raise "That is not an instance of Stella::Data::HTTPRequest" unless req.is_a? Stella::Data::HTTPRequest
55
- @requests << req
38
+ # Give usecases a name if necessary
39
+ @usecases.each_with_index { |uc,i| uc.desc ||= "Usecase ##{i+1}" }
40
+ if @testplan_current_ratio > 1.0
41
+ msg = "Usecase ratio cannot be higher than 1.0"
42
+ msg << " (#{@testplan_current_ratio})"
43
+ raise WackyRatio, msg
56
44
  end
45
+ end
57
46
 
58
-
59
- # Creates a Stella::TestPlan::Auth object and stores it to +@auth+
60
- def auth=(*args)
61
- type, user, pass = args.flatten
62
- @auth = Stella::Common::Auth.new(type, user, pass)
63
- end
47
+ def usecase(*args, &blk)
48
+ return @usecases if args.empty?
49
+ ratio, name = nil,nil
50
+ ratio, name = args[0], args[1] if args[0].is_a?(Numeric)
51
+ ratio, name = args[1], args[0] if args[0].is_a?(String)
52
+ uc = Stella::Testplan::Usecase.new
53
+ uc.base_path = @base_path
54
+ uc.instance_eval &blk
55
+ uc.ratio, uc.desc = (ratio || -1).to_f, name
56
+ @testplan_current_ratio += uc.ratio if uc.ratio > 0
57
+ add_usecase uc
58
+ end
59
+ def xusecase(*args, &blk); Stella.ld "Skipping usecase"; end
60
+
61
+ def add_usecase(uc)
62
+ Stella.ld "Usecase: #{uc.desc}"
63
+ @usecases << uc
64
+ uc
65
+ end
66
+
67
+ def desc(*args)
68
+ @desc = args.first unless args.empty?
69
+ @desc
70
+ end
64
71
 
65
- # A string to be parsed by URI#parsed or a URI object. The host and port are added to +@servers+
66
- # in the form "host:port". The protocol is stored in +@protocol+. NOTE: The
67
- # protocol is used as a default for the test and if it's already set, this
68
- # method will not try to overwrite it.
69
- def base_uri=(*args)
70
- uri_str = args.flatten.first
71
- begin
72
- uri = URI.parse uri_str
73
- host_str = uri.host
74
- host_str << ":#{uri.port}" if uri.port
75
- @servers << host_str
76
- @protocol = uri.scheme unless @protocol
77
- rescue => ex
78
- Stella.fatal(ex)
72
+ def pretty
73
+ str = []
74
+ str << " %-50s ".att(:reverse) % [@desc]
75
+ @usecases.each_with_index do |uc,i|
76
+ description = uc.desc || "Usecase ##{i+1}"
77
+ str << " %s (%s)".bright % [description, uc.ratio]
78
+ requests = uc.requests.each do |r|
79
+ str << " %-35s %s" % ["#{r.desc}:", r]
80
+ if Stella.loglev > 2
81
+ [:wait].each { |i| str << " %s: %s" % [i, r.send(i)] }
82
+ end
79
83
  end
80
84
  end
81
-
82
-
85
+ str.join($/)
86
+ end
87
+
88
+ private
89
+ def remaining_ratio
90
+ 1.0 - @testplan_current_ratio
83
91
  end
84
-
85
92
 
86
93
  end
94
+ end
87
95
 
88
-
89
-
90
-
91
-
92
-
93
-
94
-
95
-
96
- module Stella
97
- module DSL
98
- module TestPlan
99
- attr_accessor :current_plan
100
- attr_accessor :current_request
101
-
102
- def testplan(name, &define)
103
- @plans ||= {}
104
- @current_plan = @plans[name] = Stella::TestPlan.new(name)
105
- define.call if define
106
- end
107
-
108
- def plans
109
- @plans
110
- end
111
-
112
- def repeat(*args)
113
- raise "Repeat format does not look like a hash" unless args.first.is_a?(Hash)
114
- response_handler = Stella::TestPlan::ResponseHandler.new(:repeat)
115
- [:times, :wait].each do |att|
116
- response_handler.send("#{att}=", args.first[att])
117
- end
118
-
119
- response_handler
120
- end
121
-
122
- def body(*args)
123
-
124
- raise "current_plan is not a valid testplan: #{@current_plan}" unless @current_plan.is_a? Stella::TestPlan
125
-
126
- # NOTE: @current_request must be set in the calling namespace
127
- # before this method is called. See: make_request
128
- raise "current_request is not a valid request" unless @current_request.is_a? Stella::Data::HTTPRequest
129
-
130
- param, content_type, content = args if args.size == 3
131
- param, content = args if args.size == 2
132
- content = args.first if args.size == 1
133
-
134
- @current_request.add_body(content, param, content_type)
135
- end
136
-
137
- def name(*args)
138
- raise "current_plan is not a valid testplan: #{@current_plan}" unless @current_plan.is_a? Stella::TestPlan
139
-
140
- # NOTE: @current_request must be set in the calling namespace
141
- # before this method is called. See: make_request
142
- raise "current_request is not a valid request" unless @current_request.is_a? Stella::Data::HTTPRequest
143
- @current_request.name = args.first
144
- end
145
-
146
-
147
- def response(*args, &b)
148
- raise "current_plan is not a valid testplan" unless @current_plan.is_a? Stella::TestPlan
149
-
150
- # NOTE: @current_request must be set in the calling namespace
151
- # before this method is called. See: make_request
152
- raise "current_request is not a valid request" unless @current_request.is_a? Stella::Data::HTTPRequest
153
-
154
- @current_request.add_response_handler(*args, &b)
155
- end
156
- private :response
157
-
158
- # Stella::Data::HTTPRequest#add_ methods
159
- [:header, :param].each do |method_name|
160
- eval <<-RUBY, binding, '(Stella::DSL::TestPlan)', 1
161
- def #{method_name}(*args, &b)
162
- raise "current_plan is not a valid testplan" unless @current_plan.is_a? Stella::TestPlan
163
-
164
- # NOTE: @current_request must be set in the calling namespace
165
- # before this method is called. See: make_request
166
- raise "current_request is not a valid request" unless @current_request.is_a? Stella::Data::HTTPRequest
167
-
168
- @current_request.add_#{method_name}(*args, &b)
169
- end
170
- private :#{method_name}
171
- RUBY
172
- end
173
-
174
- # TestPlan#= methods
175
- [:proxy, :auth, :base_uri, :desc, :description].each do |method_name|
176
- eval <<-RUBY, binding, '(Stella::DSL::TestPlan)', 1
177
- def #{method_name}(*args)
178
- return unless @current_plan.is_a? Stella::TestPlan
179
- @current_plan.#{method_name}=(args)
180
- end
181
- private :#{method_name}
182
- RUBY
183
- end
184
-
185
- # = methods
186
- [:protocol].each do |method_name|
187
- eval <<-RUBY, binding, '(Stella::DSL::TestPlan)', 1
188
- def #{method_name}(val)
189
- return unless @current_plan.is_a? Stella::TestPlan
190
- @current_plan.#{method_name}=(val.to_s)
191
- end
192
- private :#{method_name}
193
- RUBY
194
- end
195
-
196
- def post(uri, &define)
197
- make_request(:POST, uri, &define)
198
- end
199
- def xpost(*args); end;
200
- def xget(*args); end;
201
-
202
- def get(uri, &define)
203
- make_request(:GET, uri, &define)
204
- end
205
-
206
- private
207
-
208
- def make_request(method, uri, &define)
209
- return unless @current_plan.is_a? Stella::TestPlan
210
- req = Stella::Data::HTTPRequest.new(uri, method.to_s.upcase)
211
- @current_plan.add_request req
212
- index = @current_plan.requests.size
213
- method_name = :"#{index} #{req.http_method} #{req.uri}"
214
-
215
- req_method = Proc.new {
216
- # These instance variables are very important. The bring in the context
217
- # when the request method is called in the testrunner class. We know what
218
- # the current plan is while we're executing the DSL blocks to define the
219
- # request. The response block however, is called only after a require request
220
- # is made. We set these instance variables so that the response block will
221
- # know what request it's associated too.
222
- instance_variable_set('@current_plan', @current_plan)
223
- instance_variable_set('@current_request', req)
224
- define.call if define
225
- req
226
- }
227
- metaclass.instance_eval do
228
- define_method(method_name, &req_method)
229
- end
230
-
231
- end
232
-
96
+ __END__
97
+ # instance_exec for Ruby 1.8 written by Mauricio Fernandez
98
+ # http://eigenclass.org/hiki/instance_exec
99
+ if RUBY_VERSION =~ /1.8/
100
+ module InstanceExecHelper; end
101
+ include InstanceExecHelper
102
+ def instance_exec(*args, &block) # !> method redefined; discarding old instance_exec
103
+ mname = "__instance_exec_#{Thread.current.object_id.abs}_#{object_id.abs}"
104
+ InstanceExecHelper.module_eval{ define_method(mname, &block) }
105
+ begin
106
+ ret = send(mname, *args)
107
+ ensure
108
+ InstanceExecHelper.module_eval{ undef_method(mname) } rescue nil
233
109
  end
110
+ ret
234
111
  end
235
112
  end
236
-
237
-
@@ -0,0 +1,26 @@
1
+
2
+ module Stella
3
+ class Testplan
4
+
5
+ class Stats
6
+ include Gibbler::Complex
7
+ attr_reader :requests
8
+
9
+ def initialize
10
+ @requests = OpenStruct.new
11
+ reset
12
+ end
13
+
14
+ def total_requests
15
+ @requests.successful + @requests.failed
16
+ end
17
+
18
+ def reset
19
+ @requests.successful = 0
20
+ @requests.failed = 0
21
+ end
22
+
23
+ end
24
+
25
+ end
26
+ end
@@ -0,0 +1,67 @@
1
+
2
+
3
+ module Stella
4
+ class Testplan
5
+
6
+ class Usecase
7
+ include Gibbler::Complex
8
+ attr_accessor :desc
9
+ attr_accessor :requests
10
+ attr_writer :ratio
11
+ attr_accessor :resources
12
+ attr_accessor :base_path
13
+
14
+ def initialize(&blk)
15
+ @requests, @resources = [], {}
16
+ instance_eval &blk unless blk.nil?
17
+ end
18
+
19
+ def desc(*args)
20
+ @desc = args.first unless args.empty?
21
+ @desc
22
+ end
23
+
24
+ def resource(name, value=nil)
25
+ @resources[name] = value unless value.nil?
26
+ @resources[name]
27
+ end
28
+
29
+ def ratio
30
+ r = (@ratio || 0).to_f
31
+ r = r/100 if r > 1
32
+ r
33
+ end
34
+
35
+ # Reads the contents of the file <tt>path</tt> (the current working
36
+ # directory is assumed to be the same directory containing the test plan).
37
+ def file(path)
38
+ path = File.join(@base_path, path) if @base_path
39
+ File.read(path)
40
+ end
41
+
42
+ def list(path)
43
+ file(path).split $/
44
+ end
45
+
46
+ def add_request(meth, *args, &blk)
47
+ req = Stella::Data::HTTP::Request.new meth.to_s.upcase, args[0], &blk
48
+ req.desc = args[1] if args.size > 1 # Description is optional
49
+ Stella.ld req
50
+ @requests << req
51
+ req
52
+ end
53
+ def get(*args, &blk); add_request :get, *args, &blk; end
54
+ def put(*args, &blk); add_request :put, *args, &blk; end
55
+ def post(*args, &blk); add_request :post, *args, &blk; end
56
+ def head(*args, &blk); add_request :head, *args, &blk; end
57
+ def delete(*args, &blk); add_request :delete, *args, &blk; end
58
+
59
+ def xget(*args, &blk); Stella.ld "Skipping get" end
60
+ def xput(*args, &blk); Stella.ld "Skipping put" end
61
+ def xpost(*args, &blk); Stella.ld "Skipping post" end
62
+ def xhead(*args, &blk); Stella.ld "Skipping head" end
63
+ def xdelete(*args, &blk); Stella.ld "Skipping delete" end
64
+
65
+ end
66
+ end
67
+ end