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.
- data/CHANGES.txt +3 -15
- data/LICENSE.txt +1 -1
- data/README.rdoc +90 -60
- data/Rakefile +32 -42
- data/bin/stella +138 -0
- data/examples/basic/listing_ids.csv +7 -0
- data/examples/basic/plan.rb +71 -0
- data/lib/stella.rb +57 -104
- data/lib/stella/cli.rb +66 -0
- data/lib/stella/client.rb +197 -0
- data/lib/stella/config.rb +87 -0
- data/lib/stella/data.rb +85 -0
- data/lib/stella/data/http.rb +2 -257
- data/lib/stella/data/http/body.rb +15 -0
- data/lib/stella/data/http/request.rb +116 -0
- data/lib/stella/data/http/response.rb +92 -0
- data/lib/stella/dsl.rb +5 -0
- data/lib/stella/engine.rb +55 -0
- data/lib/stella/engine/functional.rb +39 -0
- data/lib/stella/engine/load.rb +106 -0
- data/lib/stella/exceptions.rb +15 -0
- data/lib/stella/guidelines.rb +18 -0
- data/lib/stella/mixins.rb +2 -0
- data/lib/stella/stats.rb +3 -7
- data/lib/stella/testplan.rb +95 -220
- data/lib/stella/testplan/stats.rb +26 -0
- data/lib/stella/testplan/usecase.rb +67 -0
- data/lib/stella/utils.rb +126 -0
- data/lib/{util → stella/utils}/httputil.rb +0 -0
- data/lib/stella/version.rb +15 -0
- data/lib/threadify.rb +0 -6
- data/stella.gemspec +43 -49
- data/support/example_webapp.rb +246 -0
- data/support/useragents.txt +75 -0
- metadata +66 -31
- data/bin/example_test.rb +0 -82
- data/bin/example_webapp.rb +0 -63
- data/lib/logger.rb +0 -79
- data/lib/stella/clients.rb +0 -161
- data/lib/stella/command/base.rb +0 -20
- data/lib/stella/command/form.rb +0 -36
- data/lib/stella/command/get.rb +0 -44
- data/lib/stella/common.rb +0 -53
- data/lib/stella/crypto.rb +0 -88
- data/lib/stella/data/domain.rb +0 -82
- data/lib/stella/environment.rb +0 -66
- data/lib/stella/functest.rb +0 -105
- data/lib/stella/loadtest.rb +0 -186
- data/lib/stella/testrunner.rb +0 -64
- data/lib/storable.rb +0 -280
- data/lib/timeunits.rb +0 -65
- data/tryouts/drb/drb_test.rb +0 -65
- data/tryouts/drb/open4.rb +0 -19
- data/tryouts/drb/slave.rb +0 -27
- data/tryouts/oo_tryout.rb +0 -30
data/lib/stella/stats.rb
CHANGED
@@ -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
|
-
@
|
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
|
data/lib/stella/testplan.rb
CHANGED
@@ -1,237 +1,112 @@
|
|
1
|
+
require 'stella/testplan/usecase'
|
2
|
+
require 'stella/testplan/stats'
|
1
3
|
|
2
4
|
module Stella
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
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
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
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
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
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
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
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
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
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
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
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
|