stella 0.7.1 → 0.7.2
Sign up to get free protection for your applications and to get access to all the features.
- data/CHANGES.txt +16 -0
- data/Rudyfile +63 -27
- data/bin/stella +1 -0
- data/examples/essentials/plan.rb +1 -1
- data/examples/exceptions/plan.rb +1 -1
- data/lib/stella.rb +5 -1
- data/lib/stella/cli.rb +1 -1
- data/lib/stella/client.rb +119 -53
- data/lib/stella/client/container.rb +264 -14
- data/lib/stella/client/modifiers.rb +1 -0
- data/lib/stella/data.rb +182 -61
- data/lib/stella/data/http/request.rb +20 -2
- data/lib/stella/engine.rb +6 -2
- data/lib/stella/engine/functional.rb +35 -20
- data/lib/stella/engine/load_create.rb +2 -0
- data/lib/stella/engine/load_queue.rb +27 -7
- data/lib/stella/engine/loadbase.rb +22 -12
- data/lib/stella/testplan.rb +8 -1
- data/lib/stella/testplan/usecase.rb +14 -1
- data/lib/stella/version.rb +2 -2
- data/stella.gemspec +3 -1
- data/support/sample_webapp/app.rb +0 -1
- data/tryouts/configs/failed_requests.rb +31 -0
- data/tryouts/configs/global_sequential.rb +18 -0
- data/vendor/httpclient-2.1.5.2/httpclient.rb +2 -2
- metadata +5 -3
@@ -32,6 +32,7 @@ module Stella::Data::HTTP
|
|
32
32
|
@uri = uri_str
|
33
33
|
@http_method, @http_version = method, version
|
34
34
|
@headers, @params, @response_handler = {}, {}, {}
|
35
|
+
@resources = {}
|
35
36
|
@wait = 0
|
36
37
|
@desc = "Request"
|
37
38
|
@body = Stella::Data::HTTP::Body.new
|
@@ -55,13 +56,30 @@ module Stella::Data::HTTP
|
|
55
56
|
alias_method :sleep, :wait
|
56
57
|
|
57
58
|
def headers(*args)
|
58
|
-
|
59
|
+
unless args.empty?
|
60
|
+
h = Hash === args[0] ? args[0] : {args[0]=> args[1]}
|
61
|
+
@headers.merge! h unless h.empty?
|
62
|
+
end
|
59
63
|
@headers
|
60
64
|
end
|
61
65
|
alias_method :header, :headers
|
62
66
|
|
67
|
+
# Set a resource key value pair in the get, post block.
|
68
|
+
# These will be process later in Stella::Client
|
69
|
+
def set(*args)
|
70
|
+
unless args.empty?
|
71
|
+
h = Hash === args[0] ? args[0] : {args[0]=> args[1]}
|
72
|
+
@resources.merge! h unless h.empty?
|
73
|
+
end
|
74
|
+
@resources
|
75
|
+
end
|
76
|
+
alias_method :resources, :set
|
77
|
+
|
63
78
|
def params(*args)
|
64
|
-
|
79
|
+
unless args.empty?
|
80
|
+
h = Hash === args[0] ? args[0] : {args[0]=> args[1]}
|
81
|
+
@params.merge! h unless h.empty?
|
82
|
+
end
|
65
83
|
@params
|
66
84
|
end
|
67
85
|
alias_method :param, :params
|
data/lib/stella/engine.rb
CHANGED
@@ -10,13 +10,17 @@ module Stella::Engine
|
|
10
10
|
def update(*args)
|
11
11
|
what, *args = args
|
12
12
|
if respond_to?("update_#{what}")
|
13
|
-
Stella.ld "OBSERVER UPDATE: #{what}"
|
13
|
+
#Stella.ld "OBSERVER UPDATE: #{what}"
|
14
14
|
Stella.rescue { self.send("update_#{what}", *args) }
|
15
15
|
else
|
16
16
|
Stella.ld "NO UPDATE HANDLER FOR: #{what}"
|
17
17
|
end
|
18
18
|
end
|
19
|
-
|
19
|
+
|
20
|
+
def runid
|
21
|
+
|
22
|
+
end
|
23
|
+
|
20
24
|
def process_options!(plan, opts={})
|
21
25
|
opts = {
|
22
26
|
:hosts => [],
|
@@ -19,6 +19,9 @@ module Stella::Engine
|
|
19
19
|
Stella.lflush
|
20
20
|
sleep 0.3
|
21
21
|
|
22
|
+
# Identify this thread to Benelux
|
23
|
+
Benelux.current_track :functional
|
24
|
+
|
22
25
|
dig = Stella.loglev > 1 ? plan.digest_cache : plan.digest_cache.shorter
|
23
26
|
Stella.li " %-65s ".att(:reverse) % ["#{plan.desc} (#{dig})"]
|
24
27
|
plan.usecases.each_with_index do |uc,i|
|
@@ -28,11 +31,8 @@ module Stella::Engine
|
|
28
31
|
Stella.rescue { client.execute uc }
|
29
32
|
end
|
30
33
|
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
# errors?
|
35
|
-
|
34
|
+
tl = Benelux.thread_timeline
|
35
|
+
tl.stats.group(:failed).merge.n == 0
|
36
36
|
end
|
37
37
|
|
38
38
|
|
@@ -44,30 +44,42 @@ module Stella::Engine
|
|
44
44
|
end
|
45
45
|
|
46
46
|
def update_receive_response(client_id, usecase, uri, req, params, counter, container)
|
47
|
-
msg = '
|
47
|
+
msg = ' %-6s %-53s ' % [req.http_method, uri]
|
48
48
|
msg << container.status.to_s if Stella.loglev == 1
|
49
49
|
Stella.li msg
|
50
50
|
|
51
|
-
Stella.li2
|
52
|
-
|
53
|
-
Stella.li2 $/, " Request-Params:"
|
51
|
+
Stella.li2 $/, " Params:"
|
54
52
|
params.each do |pair|
|
55
53
|
Stella.li2 " %s: %s" % pair
|
56
54
|
end
|
57
55
|
|
58
|
-
Stella.li2 $/,
|
56
|
+
Stella.li2 $/, ' ' << container.response.request.header.send(:request_line)
|
57
|
+
|
59
58
|
container.response.request.header.all.each do |pair|
|
60
|
-
Stella.li2 "
|
59
|
+
Stella.li2 " %s: %s" % pair
|
61
60
|
end
|
62
61
|
|
63
|
-
|
62
|
+
if req.http_method == 'POST'
|
63
|
+
cont = container.response.request.body.content
|
64
|
+
if String === cont
|
65
|
+
Stella.li2 (' ' << cont.split($/).join("#{$/} "))
|
66
|
+
elsif HTTP::Message::Body::Parts === cont
|
67
|
+
cont.parts.each do |part|
|
68
|
+
if File === part
|
69
|
+
Stella.li2 "<#{part.path}>"
|
70
|
+
else
|
71
|
+
Stella.li2 part
|
72
|
+
end
|
73
|
+
end
|
74
|
+
end
|
75
|
+
end
|
64
76
|
|
65
|
-
|
77
|
+
resh = container.response.header
|
78
|
+
Stella.li2 $/, ' HTTP/%s %3d %s' % [resh.http_version, resh.status_code, resh.reason_phrase]
|
66
79
|
container.headers.all.each do |pair|
|
67
|
-
Stella.li2 "
|
80
|
+
Stella.li2 " %s: %s" % pair
|
68
81
|
end
|
69
|
-
Stella.
|
70
|
-
Stella.li3 container.body.empty? ? ' [empty]' : container.body
|
82
|
+
Stella.li4 container.body.empty? ? ' [empty]' : container.body
|
71
83
|
Stella.li2 $/
|
72
84
|
end
|
73
85
|
|
@@ -76,22 +88,25 @@ module Stella::Engine
|
|
76
88
|
|
77
89
|
def update_error_execute_response_handler(client_id, ex, req, container)
|
78
90
|
Stella.le ex.message
|
79
|
-
Stella.
|
91
|
+
Stella.ld ex.backtrace
|
80
92
|
end
|
81
93
|
|
82
94
|
def update_request_error(client_id, usecase, uri, req, params, ex)
|
83
95
|
desc = "#{usecase.desc} > #{req.desc}"
|
84
96
|
Stella.le ' Client-%s %-45s %s' % [client_id.short, desc, ex.message]
|
85
|
-
Stella.
|
97
|
+
Stella.ld ex.backtrace
|
86
98
|
end
|
87
99
|
|
88
100
|
def update_quit_usecase client_id, msg
|
89
|
-
Stella.
|
101
|
+
Stella.li " QUIT %s" % [msg]
|
90
102
|
end
|
91
103
|
|
104
|
+
def update_fail_request client_id, msg
|
105
|
+
Stella.li " FAILED %s" % [msg]
|
106
|
+
end
|
92
107
|
|
93
108
|
def update_repeat_request client_id, counter, total
|
94
|
-
Stella.
|
109
|
+
Stella.li3 " Client-%s REPEAT %d of %d" % [client_id.shorter, counter, total]
|
95
110
|
end
|
96
111
|
|
97
112
|
end
|
@@ -4,7 +4,7 @@ module Stella::Engine
|
|
4
4
|
extend Stella::Engine::Base
|
5
5
|
extend Stella::Engine::Load
|
6
6
|
extend self
|
7
|
-
|
7
|
+
ROTATE_TIMELINE = 15
|
8
8
|
def execute_test_plan(packages, reps=1,duration=0)
|
9
9
|
time_started = Time.now
|
10
10
|
|
@@ -46,13 +46,15 @@ module Stella::Engine
|
|
46
46
|
Thread.current[:real_uctime].tick
|
47
47
|
time_elapsed = (Time.now - time_started).to_i
|
48
48
|
|
49
|
-
if
|
50
|
-
Thread.current == @threads.first &&
|
51
|
-
(Time.now - prev_ptime).to_i >= 5
|
49
|
+
if (Time.now - prev_ptime).to_i >= ROTATE_TIMELINE
|
52
50
|
prev_ptime, ruct = Time.now, Thread.current[:real_uctime]
|
53
|
-
|
54
|
-
|
55
|
-
|
51
|
+
if Stella.loglev >= 2 && Thread.current == @threads.first
|
52
|
+
args = [time_elapsed.to_i, ruct.n, ruct.mean, ruct.sd]
|
53
|
+
Stella.li2 $/, "REAL UC TIME: %ds (reps: %d): %.4fs %.4f(SD)" % args
|
54
|
+
Stella.lflush
|
55
|
+
end
|
56
|
+
|
57
|
+
Thread.current.rotate_timeline
|
56
58
|
end
|
57
59
|
|
58
60
|
# If a duration was given, we make sure
|
@@ -69,6 +71,24 @@ module Stella::Engine
|
|
69
71
|
end
|
70
72
|
}
|
71
73
|
|
74
|
+
data_dumper = Thread.new do
|
75
|
+
prev_ptime = Time.now
|
76
|
+
loop do
|
77
|
+
break if Stella.abort?
|
78
|
+
break if @threads.select { |t| (!t.nil? && t.status) }.empty?
|
79
|
+
if (Time.now - prev_ptime).to_i >= (ROTATE_TIMELINE * 4)
|
80
|
+
Benelux.update_global_timeline
|
81
|
+
Stella.li $/, [:logger, (Time.now - prev_ptime).to_i, Benelux.timeline.size].inspect
|
82
|
+
prev_ptime = Time.now
|
83
|
+
##TODO: Dump to file
|
84
|
+
##Benelux.timeline.clear
|
85
|
+
end
|
86
|
+
sleep 5
|
87
|
+
end
|
88
|
+
|
89
|
+
end
|
90
|
+
data_dumper.join
|
91
|
+
|
72
92
|
repscalc = Benelux::Stats::Calculator.new
|
73
93
|
@threads.each { |t| t.join } # wait
|
74
94
|
@threads.each { |t| repscalc.sample(t[:real_reps]) }
|
@@ -36,7 +36,7 @@ module Stella::Engine
|
|
36
36
|
Stella.li "Generating requests #{msg}...", $/
|
37
37
|
Stella.lflush
|
38
38
|
|
39
|
-
|
39
|
+
bt = Benelux.timeline
|
40
40
|
|
41
41
|
begin
|
42
42
|
execute_test_plan packages, opts[:repetitions], opts[:duration]
|
@@ -49,8 +49,7 @@ module Stella::Engine
|
|
49
49
|
Stella.lflush
|
50
50
|
|
51
51
|
Benelux.update_global_timeline
|
52
|
-
|
53
|
-
bt = Benelux.timeline
|
52
|
+
|
54
53
|
tt = Benelux.thread_timeline
|
55
54
|
|
56
55
|
test_time = tt.stats.group(:execute_test_plan).mean
|
@@ -71,7 +70,7 @@ module Stella::Engine
|
|
71
70
|
Stella.li $/
|
72
71
|
end
|
73
72
|
|
74
|
-
|
73
|
+
bt.stats.group(:failed).merge.n == 0
|
75
74
|
end
|
76
75
|
|
77
76
|
protected
|
@@ -111,7 +110,9 @@ module Stella::Engine
|
|
111
110
|
Stella.ld "THREAD PACKAGE: #{usecase.desc} (#{pointer} + #{count})"
|
112
111
|
# Fill the thread_package with the contents of the block
|
113
112
|
packages.fill(pointer, count) do |index|
|
114
|
-
|
113
|
+
copts = {}
|
114
|
+
copts[:parse_templates] = false if opts[:'disable-templates']
|
115
|
+
client = Stella::Client.new opts[:hosts].first, index+1, copts
|
115
116
|
client.add_observer(self)
|
116
117
|
client.enable_nowait_mode if opts[:nowait]
|
117
118
|
Stella.li4 "Created client #{client.digest.short}"
|
@@ -132,6 +133,11 @@ module Stella::Engine
|
|
132
133
|
def generate_report(plan,test_time)
|
133
134
|
#Benelux.update_all_track_timelines
|
134
135
|
global_timeline = Benelux.timeline
|
136
|
+
global_stats = global_timeline.stats.group(:do_request).merge
|
137
|
+
if global_stats.n == 0
|
138
|
+
Stella.ld "No stats"
|
139
|
+
return
|
140
|
+
end
|
135
141
|
|
136
142
|
Stella.li $/, " %-72s ".att(:reverse) % ["#{plan.desc} (#{plan.digest_cache.shorter})"]
|
137
143
|
plan.usecases.uniq.each_with_index do |uc,i|
|
@@ -191,7 +197,7 @@ module Stella::Engine
|
|
191
197
|
end
|
192
198
|
|
193
199
|
Stella.li ' ' << " %-66s ".att(:reverse) % 'Total:'
|
194
|
-
|
200
|
+
|
195
201
|
failed = global_timeline.stats.group(:failed)
|
196
202
|
respgrp = global_timeline.stats.group(:execute_response_handler)
|
197
203
|
resst = respgrp.tag_values(:status)
|
@@ -200,8 +206,8 @@ module Stella::Engine
|
|
200
206
|
size = respgrp[:status => status].size
|
201
207
|
statusi << [status, size]
|
202
208
|
end
|
203
|
-
Stella.li ' %-30s %d' % ['Total requests',
|
204
|
-
success =
|
209
|
+
Stella.li ' %-30s %d' % ['Total requests', global_stats.n]
|
210
|
+
success = global_stats.n - failed.n
|
205
211
|
Stella.li ' %-29s %d (req/s: %.2f)' % [:success, success, success/test_time]
|
206
212
|
statusi.each do |pair|
|
207
213
|
Stella.li2 ' %-28s %s: %d' % ['', *pair]
|
@@ -229,7 +235,9 @@ module Stella::Engine
|
|
229
235
|
|
230
236
|
def update_receive_response(client_id, usecase, uri, req, params, counter, container)
|
231
237
|
desc = "#{usecase.desc} > #{req.desc}"
|
232
|
-
|
238
|
+
args = [client_id.shorter, container.status, req.http_method, uri, params.inspect]
|
239
|
+
Stella.li3 ' Client-%s %3d %-6s %s %s' % args
|
240
|
+
Stella.ld ' Client-%s %3d %s' % [client_id.shorter, container.status, container.body]
|
233
241
|
end
|
234
242
|
|
235
243
|
def update_execute_response_handler(client_id, req, container)
|
@@ -239,20 +247,23 @@ module Stella::Engine
|
|
239
247
|
desc = "#{container.usecase.desc} > #{req.desc}"
|
240
248
|
Stella.li $/ if Stella.loglev == 1
|
241
249
|
Stella.le ' Client-%s %-45s %s' % [client_id.shorter, desc, ex.message]
|
242
|
-
Stella.
|
250
|
+
Stella.li ex.backtrace
|
243
251
|
end
|
244
252
|
|
245
253
|
def update_request_error(client_id, usecase, uri, req, params, ex)
|
246
254
|
desc = "#{usecase.desc} > #{req.desc}"
|
247
255
|
Stella.li $/ if Stella.loglev == 1
|
248
256
|
Stella.le ' Client-%s %-45s %s' % [client_id.shorter, desc, ex.message]
|
249
|
-
Stella.
|
257
|
+
Stella.li ex.backtrace
|
250
258
|
end
|
251
259
|
|
252
260
|
def update_quit_usecase client_id, msg
|
253
261
|
Stella.li3 " Client-%s QUIT %s" % [client_id.shorter, msg]
|
254
262
|
end
|
255
263
|
|
264
|
+
def update_fail_request client_id, msg
|
265
|
+
Stella.li3 " Client-%s FAILED %s" % [client_id.shorter, msg]
|
266
|
+
end
|
256
267
|
|
257
268
|
def update_repeat_request client_id, counter, total
|
258
269
|
Stella.li3 " Client-%s REPEAT %d of %d" % [client_id.shorter, counter, total]
|
@@ -262,7 +273,6 @@ module Stella::Engine
|
|
262
273
|
blk.call
|
263
274
|
rescue => ex
|
264
275
|
Stella.le ' Error in Client-%s: %s' % [client_id.shorter, ex.message]
|
265
|
-
Stella.li3 ex.backtrace
|
266
276
|
end
|
267
277
|
|
268
278
|
Benelux.add_timer Stella::Engine::Load, :build_thread_package
|
data/lib/stella/testplan.rb
CHANGED
@@ -7,6 +7,7 @@ class Testplan
|
|
7
7
|
extend Attic
|
8
8
|
|
9
9
|
attic :base_path
|
10
|
+
attic :plan_path
|
10
11
|
|
11
12
|
attr_accessor :usecases
|
12
13
|
attr_accessor :desc
|
@@ -36,8 +37,9 @@ class Testplan
|
|
36
37
|
conf = File.read path
|
37
38
|
plan = Stella::Testplan.new
|
38
39
|
plan.base_path = File.dirname path
|
40
|
+
plan.plan_path = path
|
39
41
|
# eval so the DSL code can be executed in this namespace.
|
40
|
-
plan.instance_eval conf
|
42
|
+
plan.instance_eval conf, path
|
41
43
|
plan
|
42
44
|
end
|
43
45
|
|
@@ -58,6 +60,7 @@ class Testplan
|
|
58
60
|
|
59
61
|
# make sure all clients share identical test plans
|
60
62
|
def freeze
|
63
|
+
Stella.ld "FREEZE TESTPLAN: #{desc}"
|
61
64
|
@usecases.each { |uc| uc.freeze }
|
62
65
|
super
|
63
66
|
self
|
@@ -70,6 +73,7 @@ class Testplan
|
|
70
73
|
ratio, name = args[1], args[0] if args[0].is_a?(String)
|
71
74
|
uc = Stella::Testplan::Usecase.new
|
72
75
|
uc.base_path = self.base_path
|
76
|
+
uc.plan_path = self.plan_path
|
73
77
|
uc.instance_eval &blk
|
74
78
|
uc.ratio, uc.desc = (ratio || -1).to_f, name
|
75
79
|
@testplan_current_ratio += uc.ratio if uc.ratio > 0
|
@@ -97,6 +101,9 @@ class Testplan
|
|
97
101
|
desc = uc.desc || "Usecase ##{i+1}"
|
98
102
|
desc += " (#{dig}) "
|
99
103
|
str << (' ' << " %-61s %s%% ".att(:reverse).bright) % [desc, uc.ratio_pretty]
|
104
|
+
unless uc.http_auth.nil?
|
105
|
+
str << ' Auth: %s (%s/%s)' % uc.http_auth.values
|
106
|
+
end
|
100
107
|
requests = uc.requests.each do |r|
|
101
108
|
dig = long ? r.digest_cache : r.digest_cache.shorter
|
102
109
|
str << " %-62s".bright % ["#{r.desc} (#{dig})"]
|
@@ -21,10 +21,16 @@ class Testplan
|
|
21
21
|
include Gibbler::Complex
|
22
22
|
extend Attic
|
23
23
|
|
24
|
+
class Auth < Struct.new(:kind, :user, :pass)
|
25
|
+
include Gibbler::Complex
|
26
|
+
end
|
27
|
+
|
24
28
|
attic :base_path # we don't want gibbler to see this
|
29
|
+
attic :plan_path
|
25
30
|
|
26
31
|
attr_accessor :desc
|
27
32
|
attr_writer :ratio
|
33
|
+
attr_reader :http_auth
|
28
34
|
|
29
35
|
attr_accessor :requests
|
30
36
|
attr_accessor :resources
|
@@ -63,15 +69,17 @@ class Testplan
|
|
63
69
|
# directory is assumed to be the same directory containing the test plan).
|
64
70
|
def read(path)
|
65
71
|
path = File.join(base_path, path) if base_path
|
72
|
+
Stella.ld "READING FILE: #{path}"
|
66
73
|
File.read(path)
|
67
74
|
end
|
68
|
-
|
75
|
+
|
69
76
|
def list(path)
|
70
77
|
read(path).split $/
|
71
78
|
end
|
72
79
|
|
73
80
|
def csv(path)
|
74
81
|
path = File.join(base_path, path) if base_path
|
82
|
+
Stella.ld "READING CSV: #{path}"
|
75
83
|
CSV.read(path)
|
76
84
|
end
|
77
85
|
|
@@ -81,6 +89,11 @@ class Testplan
|
|
81
89
|
self
|
82
90
|
end
|
83
91
|
|
92
|
+
def auth(user, pass=nil, kind=:basic)
|
93
|
+
@http_auth ||= Auth.new
|
94
|
+
@http_auth.user, @http_auth.pass, @http_auth.kind = user, pass, kind
|
95
|
+
end
|
96
|
+
|
84
97
|
def add_request(meth, *args, &blk)
|
85
98
|
req = Stella::Data::HTTP::Request.new meth.to_s.upcase, args[0], &blk
|
86
99
|
req.desc = args[1] if args.size > 1 # Description is optional
|
data/lib/stella/version.rb
CHANGED
@@ -5,10 +5,10 @@ module Stella
|
|
5
5
|
unless defined?(MAJOR)
|
6
6
|
MAJOR = 0.freeze
|
7
7
|
MINOR = 7.freeze
|
8
|
-
TINY =
|
8
|
+
TINY = 2.freeze
|
9
9
|
PATCH = '001'.freeze
|
10
10
|
end
|
11
|
-
def self.to_s; [MAJOR, MINOR, TINY
|
11
|
+
def self.to_s; [MAJOR, MINOR, TINY].join('.'); end
|
12
12
|
def self.to_f; self.to_s.to_f; end
|
13
13
|
def self.patch; PATCH; end
|
14
14
|
end
|