stella 0.7.5.001 → 0.7.6.001
Sign up to get free protection for your applications and to get access to all the features.
- data/CHANGES.txt +6 -0
- data/lib/stella/cli.rb +5 -0
- data/lib/stella/client.rb +6 -4
- data/lib/stella/common.rb +8 -1
- data/lib/stella/engine/load_em.rb +139 -0
- data/lib/stella/engine.rb +1 -0
- data/lib/stella.rb +1 -1
- data/stella.gemspec +2 -1
- data/vendor/httpclient-2.1.5.2/httpclient/auth.rb +10 -10
- data/vendor/httpclient-2.1.5.2/httpclient/http.rb +12 -2
- data/vendor/httpclient-2.1.5.2/httpclient/session.rb +1 -1
- metadata +3 -2
data/CHANGES.txt
CHANGED
@@ -1,6 +1,12 @@
|
|
1
1
|
STELLA, CHANGES
|
2
2
|
|
3
3
|
|
4
|
+
#### 0.7.6 (2009-11-24) ###############################
|
5
|
+
|
6
|
+
* FIXED: httpclient fix: use full request URI (i.e. path and query string) in authentication (NOTE: SSPINegotiateAuth and NegotiateAuth not tested)
|
7
|
+
* FIXED: Use request URI in authentication domain
|
8
|
+
|
9
|
+
|
4
10
|
#### 0.7.5 (2009-11-16) ###############################
|
5
11
|
|
6
12
|
* FIXED: Correctly capture exceptions in Client
|
data/lib/stella/cli.rb
CHANGED
@@ -36,14 +36,19 @@ class Stella::CLI < Drydock::Command
|
|
36
36
|
[:'disable-templates', :'disable-stats'].each do |opt|
|
37
37
|
opts[opt] = @global.send(opt) unless @global.send(opt).nil?
|
38
38
|
end
|
39
|
+
|
39
40
|
case @global.engine
|
40
41
|
when "package"
|
41
42
|
ret = Stella::Engine::LoadPackage.run @testplan, opts
|
42
43
|
when "create"
|
43
44
|
ret = Stella::Engine::LoadCreate.run @testplan, opts
|
45
|
+
when "em"
|
46
|
+
ret = Stella::Engine::LoadEventMachine.run @testplan, opts
|
44
47
|
else
|
45
48
|
ret = Stella::Engine::LoadQueue.run @testplan, opts
|
46
49
|
end
|
50
|
+
Stella.ld "ENGINE: #{@global.engine}: #{ret.class}"
|
51
|
+
|
47
52
|
@exit_code = (ret ? 0 : 1)
|
48
53
|
end
|
49
54
|
|
data/lib/stella/client.rb
CHANGED
@@ -1,5 +1,6 @@
|
|
1
1
|
require "observer"
|
2
2
|
require "nokogiri"
|
3
|
+
require 'pp'
|
3
4
|
|
4
5
|
Stella::Utils.require_vendor "httpclient", '2.1.5.2'
|
5
6
|
|
@@ -51,11 +52,12 @@ module Stella
|
|
51
52
|
container.params, container.headers = params, headers
|
52
53
|
|
53
54
|
uri = build_request_uri req.uri, params, container
|
54
|
-
|
55
|
+
|
55
56
|
if http_auth = usecase.http_auth || req.http_auth
|
56
57
|
# TODO: The first arg is domain and can include a URI path.
|
57
58
|
# Are there cases where this is important?
|
58
|
-
domain = '%s://%s%s' % [uri.scheme, uri.host,
|
59
|
+
domain = '%s://%s:%d%s' % [uri.scheme, uri.host, uri.port, req.uri]
|
60
|
+
Stella.ld "DOMAIN " << domain
|
59
61
|
user, pass = http_auth.user, http_auth.pass
|
60
62
|
user = container.instance_eval &user if Proc === user
|
61
63
|
pass = container.instance_eval &pass if Proc === pass
|
@@ -72,7 +74,7 @@ module Stella
|
|
72
74
|
|
73
75
|
container.unique_id = stella_id
|
74
76
|
params['__stella'] = headers['X-Stella-ID'] = container.unique_id[0..10]
|
75
|
-
|
77
|
+
|
76
78
|
meth = req.http_method.to_s.downcase
|
77
79
|
Stella.ld "#{req.http_method}: " << "#{req.uri} " << params.inspect
|
78
80
|
|
@@ -178,7 +180,7 @@ module Stella
|
|
178
180
|
}
|
179
181
|
http_client = HTTPClient.new opts
|
180
182
|
http_client.set_proxy_auth(@proxy.user, @proxy.pass) if @proxy.user
|
181
|
-
http_client.debug_dev = STDOUT if Stella.debug?
|
183
|
+
http_client.debug_dev = STDOUT if Stella.debug?
|
182
184
|
http_client.protocol_version = "HTTP/1.1"
|
183
185
|
http_client.ssl_config.verify_mode = ::OpenSSL::SSL::VERIFY_NONE
|
184
186
|
http_client
|
data/lib/stella/common.rb
CHANGED
@@ -3,7 +3,6 @@
|
|
3
3
|
$KCODE = "u" if RUBY_VERSION =~ /^1.8/
|
4
4
|
|
5
5
|
|
6
|
-
|
7
6
|
# Assumes Time::Units and Numeric mixins are available.
|
8
7
|
|
9
8
|
class String
|
@@ -26,6 +25,14 @@ class Thread
|
|
26
25
|
attic :stats
|
27
26
|
end
|
28
27
|
|
28
|
+
# Fix for eventmachine in Ruby 1.9
|
29
|
+
class Thread
|
30
|
+
unless method_defined? :kill!
|
31
|
+
def kill!(*args) kill( *args) end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
|
29
36
|
class Time
|
30
37
|
module Units
|
31
38
|
PER_MICROSECOND = 0.000001.freeze
|
@@ -0,0 +1,139 @@
|
|
1
|
+
require 'eventmachine'
|
2
|
+
|
3
|
+
module Stella::Engine
|
4
|
+
module LoadEventMachine
|
5
|
+
extend Stella::Engine::Base
|
6
|
+
extend Stella::Engine::Load
|
7
|
+
extend self
|
8
|
+
|
9
|
+
def execute_test_plan(packages, reps=1,duration=0,arrival=nil)
|
10
|
+
time_started = Time.now
|
11
|
+
|
12
|
+
pqueue = Queue.new
|
13
|
+
packages.each { |p| pqueue << p }
|
14
|
+
|
15
|
+
@real_reps += 1 # Increments when duration is specified.
|
16
|
+
@threads = []
|
17
|
+
|
18
|
+
|
19
|
+
EM.run{
|
20
|
+
|
21
|
+
conn = EM::Protocols::HttpClient2.connect 'solutious.com', 80
|
22
|
+
|
23
|
+
req = conn.get('/')
|
24
|
+
req.callback{ |response|
|
25
|
+
p(response.status)
|
26
|
+
p(response.headers)
|
27
|
+
#p(response.content)
|
28
|
+
}
|
29
|
+
|
30
|
+
operation = proc {
|
31
|
+
# perform a long-running operation here, such as a database query.
|
32
|
+
"result" # as usual, the last expression evaluated in the block will be the return value.
|
33
|
+
}
|
34
|
+
callback = proc {|result|
|
35
|
+
# do something with result here, such as send it back to a network client.
|
36
|
+
}
|
37
|
+
|
38
|
+
t = EventMachine.defer( operation, callback )
|
39
|
+
|
40
|
+
sleep 0.1
|
41
|
+
|
42
|
+
EM.stop
|
43
|
+
}
|
44
|
+
|
45
|
+
end
|
46
|
+
|
47
|
+
end
|
48
|
+
|
49
|
+
module LoadQueue2
|
50
|
+
extend Stella::Engine::Base
|
51
|
+
extend Stella::Engine::Load
|
52
|
+
extend self
|
53
|
+
ROTATE_TIMELINE = 15
|
54
|
+
def execute_test_plan(packages, reps=1,duration=0,arrival=nil)
|
55
|
+
time_started = Time.now
|
56
|
+
|
57
|
+
pqueue = Queue.new
|
58
|
+
packages.each { |p| pqueue << p }
|
59
|
+
|
60
|
+
@real_reps += 1 # Increments when duration is specified.
|
61
|
+
@threads = []
|
62
|
+
packages.size.times {
|
63
|
+
@max_clients += 1
|
64
|
+
@threads << Thread.new do
|
65
|
+
package = pqueue.pop
|
66
|
+
Thread.current[:real_reps] = 0
|
67
|
+
Thread.current[:real_uctime] = Benelux::Stats::Calculator.new
|
68
|
+
c, uc = package.client, package.usecase
|
69
|
+
Stella.stdout.info4 $/, "======== THREAD %s: START" % [c.digest.short]
|
70
|
+
|
71
|
+
# This thread will stay on this one track.
|
72
|
+
Benelux.current_track c.digest
|
73
|
+
|
74
|
+
Benelux.add_thread_tags :usecase => uc.digest_cache
|
75
|
+
Thread.current[:real_uctime].first_tick
|
76
|
+
prev_ptime ||= Time.now
|
77
|
+
reps.times { |rep|
|
78
|
+
break if Stella.abort?
|
79
|
+
Thread.current[:real_reps] += 1
|
80
|
+
args = [c.digest.short, uc.desc, uc.digest.short, Thread.current[:real_reps]]
|
81
|
+
Stella.stdout.info4 $/, "======== THREAD %s: %s:%s (rep: %d)" % args
|
82
|
+
|
83
|
+
Benelux.add_thread_tags :rep => rep
|
84
|
+
#Stella.stdout.info [package.client.gibbler.shorter, package.usecase.gibbler.shorter, rep].inspect
|
85
|
+
Stella::Engine::Load.rescue(c.digest_cache) {
|
86
|
+
break if Stella.abort?
|
87
|
+
print '.' if Stella.stdout.lev == 2
|
88
|
+
stats = c.execute uc
|
89
|
+
}
|
90
|
+
Benelux.remove_thread_tags :rep
|
91
|
+
|
92
|
+
Thread.current[:real_uctime].tick
|
93
|
+
time_elapsed = (Time.now - time_started).to_i
|
94
|
+
|
95
|
+
if (Time.now - prev_ptime).to_i >= ROTATE_TIMELINE
|
96
|
+
prev_ptime, ruct = Time.now, Thread.current[:real_uctime]
|
97
|
+
if Stella.stdout.lev >= 2 && Thread.current == @threads.first
|
98
|
+
args = [time_elapsed.to_i, ruct.n, ruct.mean, ruct.sd]
|
99
|
+
Stella.stdout.info2 $/, "REAL UC TIME: %ds (reps: %d): %.4fs %.4f(SD)" % args
|
100
|
+
end
|
101
|
+
|
102
|
+
Thread.current.rotate_timeline
|
103
|
+
end
|
104
|
+
|
105
|
+
# If a duration was given, we make sure
|
106
|
+
# to run for only that amount of time.
|
107
|
+
if duration > 0
|
108
|
+
break if (time_elapsed+Thread.current[:real_uctime].mean) >= duration
|
109
|
+
redo if (time_elapsed+Thread.current[:real_uctime].mean) <= duration
|
110
|
+
end
|
111
|
+
}
|
112
|
+
|
113
|
+
Benelux.remove_thread_tags :usecase
|
114
|
+
|
115
|
+
pqueue << package # return the package to the queue
|
116
|
+
end
|
117
|
+
|
118
|
+
unless arrival.nil?
|
119
|
+
# Create 1 second / users per second
|
120
|
+
args = [1/arrival, @threads.size, packages.size]
|
121
|
+
Stella.stdout.info2 $/, "======== ARRIVAL (%s): %s of %s" % args
|
122
|
+
sleep 1/arrival
|
123
|
+
end
|
124
|
+
}
|
125
|
+
|
126
|
+
repscalc = Benelux::Stats::Calculator.new
|
127
|
+
@threads.each { |t| t.join } # wait
|
128
|
+
@threads.each { |t| repscalc.sample(t[:real_reps]) }
|
129
|
+
@real_reps = repscalc.mean.to_i
|
130
|
+
|
131
|
+
#Stella.stdout.info "*** REPETITION #{@real_reps} of #{reps} ***"
|
132
|
+
|
133
|
+
Stella.stdout.info2 $/, $/
|
134
|
+
end
|
135
|
+
|
136
|
+
Benelux.add_timer Stella::Engine::LoadEventMachine, :execute_test_plan
|
137
|
+
|
138
|
+
end
|
139
|
+
end
|
data/lib/stella/engine.rb
CHANGED
@@ -86,6 +86,7 @@ module Stella::Engine
|
|
86
86
|
autoload :LoadPackage, 'stella/engine/load_package'
|
87
87
|
autoload :LoadCreate, 'stella/engine/load_create'
|
88
88
|
autoload :LoadQueue, 'stella/engine/load_queue'
|
89
|
+
autoload :LoadEventMachine, 'stella/engine/load_em'
|
89
90
|
|
90
91
|
# These timers are interesting from a reporting perspective.
|
91
92
|
Benelux.add_counter Stella::Client, :execute_response_handler
|
data/lib/stella.rb
CHANGED
data/stella.gemspec
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
@spec = Gem::Specification.new do |s|
|
2
2
|
s.name = "stella"
|
3
3
|
s.rubyforge_project = 'stella'
|
4
|
-
s.version = "0.7.
|
4
|
+
s.version = "0.7.6.001"
|
5
5
|
s.summary = "Blame Stella for breaking your web applications."
|
6
6
|
s.description = s.summary
|
7
7
|
s.author = "Delano Mandelbaum"
|
@@ -48,6 +48,7 @@
|
|
48
48
|
lib/stella/engine.rb
|
49
49
|
lib/stella/engine/functional.rb
|
50
50
|
lib/stella/engine/load_create.rb
|
51
|
+
lib/stella/engine/load_em.rb
|
51
52
|
lib/stella/engine/load_package.rb
|
52
53
|
lib/stella/engine/load_queue.rb
|
53
54
|
lib/stella/engine/loadbase.rb
|
@@ -113,7 +113,7 @@ class HTTPClient
|
|
113
113
|
command = nil
|
114
114
|
if res.status == HTTP::Status::UNAUTHORIZED
|
115
115
|
if challenge = parse_authentication_header(res, 'www-authenticate')
|
116
|
-
uri = req.header.
|
116
|
+
uri = req.header.create_request_uri
|
117
117
|
challenge.each do |scheme, param_str|
|
118
118
|
@authenticator.each do |auth|
|
119
119
|
if scheme.downcase == auth.scheme.downcase
|
@@ -240,7 +240,7 @@ class HTTPClient
|
|
240
240
|
# * child page of challengeable(got *Authenticate before) uri and,
|
241
241
|
# * child page of defined credential
|
242
242
|
def get(req)
|
243
|
-
target_uri = req.header.
|
243
|
+
target_uri = req.header.create_request_uri
|
244
244
|
return nil unless @challengeable.find { |uri, ok|
|
245
245
|
Util.uri_part_of(target_uri, uri) and ok
|
246
246
|
}
|
@@ -292,7 +292,7 @@ class HTTPClient
|
|
292
292
|
# * child page of challengeable(got *Authenticate before) uri and,
|
293
293
|
# * child page of defined credential
|
294
294
|
def get(req)
|
295
|
-
target_uri = req.header.
|
295
|
+
target_uri = req.header.create_request_uri
|
296
296
|
param = Util.hash_find_value(@challenge) { |uri, v|
|
297
297
|
Util.uri_part_of(target_uri, uri)
|
298
298
|
}
|
@@ -301,8 +301,8 @@ class HTTPClient
|
|
301
301
|
Util.uri_part_of(target_uri, uri)
|
302
302
|
}
|
303
303
|
return nil unless user
|
304
|
-
|
305
|
-
calc_cred(req.header.request_method,
|
304
|
+
path = req.header.create_request_path
|
305
|
+
calc_cred(req.header.request_method, path, user, passwd, param)
|
306
306
|
end
|
307
307
|
|
308
308
|
# Challenge handler: remember URL and challenge token for response.
|
@@ -317,9 +317,9 @@ class HTTPClient
|
|
317
317
|
# http://tools.assembla.com/breakout/wiki/DigestForSoap
|
318
318
|
# Thanks!
|
319
319
|
# supported algorithm: MD5 only for now
|
320
|
-
def calc_cred(method,
|
320
|
+
def calc_cred(method, path, user, passwd, param)
|
321
321
|
a_1 = "#{user}:#{param['realm']}:#{passwd}"
|
322
|
-
a_2 = "#{method}:#{
|
322
|
+
a_2 = "#{method}:#{path}"
|
323
323
|
nonce = param['nonce']
|
324
324
|
cnonce = generate_cnonce()
|
325
325
|
@nonce_count += 1
|
@@ -334,7 +334,7 @@ class HTTPClient
|
|
334
334
|
header << "username=\"#{user}\""
|
335
335
|
header << "realm=\"#{param['realm']}\""
|
336
336
|
header << "nonce=\"#{nonce}\""
|
337
|
-
header << "uri=\"#{
|
337
|
+
header << "uri=\"#{path}\""
|
338
338
|
header << "cnonce=\"#{cnonce}\""
|
339
339
|
header << "nc=#{'%08x' % @nonce_count}"
|
340
340
|
header << "qop=\"#{param['qop']}\""
|
@@ -407,7 +407,7 @@ class HTTPClient
|
|
407
407
|
# See ruby/ntlm for negotiation state transition.
|
408
408
|
def get(req)
|
409
409
|
return nil unless NTLMEnabled
|
410
|
-
target_uri = req.header.
|
410
|
+
target_uri = req.header.create_request_uri
|
411
411
|
domain_uri, param = @challenge.find { |uri, v|
|
412
412
|
Util.uri_part_of(target_uri, uri)
|
413
413
|
}
|
@@ -482,7 +482,7 @@ class HTTPClient
|
|
482
482
|
# See win32/sspi for negotiation state transition.
|
483
483
|
def get(req)
|
484
484
|
return nil unless SSPIEnabled
|
485
|
-
target_uri = req.header.
|
485
|
+
target_uri = req.header.create_request_uri
|
486
486
|
domain_uri, param = @challenge.find { |uri, v|
|
487
487
|
Util.uri_part_of(target_uri, uri)
|
488
488
|
}
|
@@ -287,7 +287,17 @@ module HTTP
|
|
287
287
|
def [](key)
|
288
288
|
get(key).collect { |item| item[1] }
|
289
289
|
end
|
290
|
-
|
290
|
+
|
291
|
+
def create_request_uri
|
292
|
+
path = create_request_path
|
293
|
+
r = "#{ @request_uri.scheme }://#{ @request_uri.host }:#{ @request_uri.port }#{ path }"
|
294
|
+
URI.parse r
|
295
|
+
end
|
296
|
+
|
297
|
+
def create_request_path
|
298
|
+
create_query_uri(@request_uri, @request_query)
|
299
|
+
end
|
300
|
+
|
291
301
|
private
|
292
302
|
|
293
303
|
def request_line
|
@@ -379,7 +389,7 @@ module HTTP
|
|
379
389
|
query_str = Message.create_query_part_str(query)
|
380
390
|
end
|
381
391
|
end
|
382
|
-
if query_str
|
392
|
+
if !query_str.nil? && !query_str.empty?
|
383
393
|
path += "?#{query_str}"
|
384
394
|
end
|
385
395
|
path
|
@@ -123,7 +123,7 @@ class HTTPClient
|
|
123
123
|
@send_timeout = 120
|
124
124
|
@receive_timeout = 60 # For each read_block_size bytes
|
125
125
|
@read_block_size = 1024 * 16 # follows net/http change in 1.8.7
|
126
|
-
@protocol_retry_count =
|
126
|
+
@protocol_retry_count = 2
|
127
127
|
|
128
128
|
@ssl_config = nil
|
129
129
|
@test_loopback_http_response = []
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: stella
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.7.
|
4
|
+
version: 0.7.6.001
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Delano Mandelbaum
|
@@ -9,7 +9,7 @@ autorequire:
|
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
11
|
|
12
|
-
date: 2009-11-
|
12
|
+
date: 2009-11-24 00:00:00 -05:00
|
13
13
|
default_executable:
|
14
14
|
dependencies:
|
15
15
|
- !ruby/object:Gem::Dependency
|
@@ -106,6 +106,7 @@ files:
|
|
106
106
|
- lib/stella/engine.rb
|
107
107
|
- lib/stella/engine/functional.rb
|
108
108
|
- lib/stella/engine/load_create.rb
|
109
|
+
- lib/stella/engine/load_em.rb
|
109
110
|
- lib/stella/engine/load_package.rb
|
110
111
|
- lib/stella/engine/load_queue.rb
|
111
112
|
- lib/stella/engine/loadbase.rb
|