stella 0.7.0.012 → 0.7.0.014

Sign up to get free protection for your applications and to get access to all the features.
data/CHANGES.txt CHANGED
@@ -7,7 +7,7 @@ NOTE: Complete rewrite
7
7
 
8
8
  * New internal architecture.
9
9
  * Improved stability and output for high thread loads.
10
- * Updated test plan DSL
10
+ * Updated configuration
11
11
  * Granular reporting via Benelux
12
12
 
13
13
 
data/bin/stella CHANGED
@@ -19,7 +19,8 @@
19
19
  #--
20
20
 
21
21
  # Put our local lib in first place
22
- lib_dir = File.expand_path File.join(File.dirname(__FILE__), '..', 'lib')
22
+ BASE_PATH = File.expand_path File.join(File.dirname(__FILE__), '..')
23
+ lib_dir = File.join(BASE_PATH, 'lib')
23
24
  $:.unshift lib_dir
24
25
 
25
26
  require 'drydock'
@@ -37,6 +38,9 @@ class Stella::CLI::Definition
37
38
 
38
39
  global :A, :apikey, String, "API Key"
39
40
  global :S, :secret, String, "Secret Key"
41
+ global :n, :nocolor, "Disable output colors" do
42
+ String.disable_color
43
+ end
40
44
  global :q, :quiet, "Be quiet!" do
41
45
  Stella.enable_quiet
42
46
  end
@@ -55,6 +59,14 @@ class Stella::CLI::Definition
55
59
 
56
60
  # ------------------------------------------------ STELLA --------
57
61
  # ------------------------------------------------------------------
62
+ about "Instructions for running the example app and test"
63
+ usage "stella example"
64
+ command :example => Stella::CLI
65
+
66
+ about "Preview the test plan"
67
+ usage "stella preview [-p path/2/testplan.rb] "
68
+ option :p, :testplan, String, "Path to testplan"
69
+ command :preview => Stella::CLI
58
70
 
59
71
  about "Run a functional test"
60
72
  usage "stella verify http://stellaaahhhh.com/"
@@ -68,14 +80,25 @@ class Stella::CLI::Definition
68
80
  usage "stella load http://stellaaahhhh.com:3114/"
69
81
  usage "stella load --clients=10 --repetitions=2 http://stellaaahhhh.com/"
70
82
  usage "stella load -p path/2/testplan.rb -u 100 -r 5 http://stellaaahhhh.com/"
71
- option :w, :nowait, "Ignore wait times"
72
83
  option :c, :clients, Integer, "Number of virtual clients"
73
84
  option :r, :repetitions, Integer, "Number of times to repeat the testplan (per vclient)"
74
- option :t, :time, String, "Max duration to run test"
75
- option :d, :delay, Float, "Delay (in seconds) between client requests (ignored if testplan supplied)"
85
+ option :d, :duration, String, "Max duration to run test"
86
+ option :W, :nowait, "Ignore wait times"
87
+ option :w, :wait, Float, "Wait time (in seconds) between client requests (ignored if testplan supplied)"
76
88
  option :p, :testplan, String, "Path to testplan"
77
89
  command :load => Stella::CLI
78
90
 
91
+ about "Run a stress test"
92
+ usage "stella stress http://stellaaahhhh.com/"
93
+ usage "stella stress http://stellaaahhhh.com:3114/"
94
+ usage "stella stress --clients=10 --repetitions=2 http://stellaaahhhh.com/"
95
+ usage "stella stress -p path/2/testplan.rb -u 100 -r 5 http://stellaaahhhh.com/"
96
+ option :c, :clients, Integer, "Number of virtual clients"
97
+ option :r, :repetitions, Integer, "Number of times to repeat the testplan (per vclient)"
98
+ option :d, :duration, String, "Max duration to run test"
99
+ option :p, :testplan, String, "Path to testplan"
100
+ command :stress => Stella::CLI
101
+
79
102
  about "Initialize Stella configuration"
80
103
  command :init do
81
104
  Stella::Config.init
@@ -119,11 +142,11 @@ rescue Drydock::InvalidArgument => ex
119
142
  STDERR.puts ex.message
120
143
  rescue Stella::Error => ex
121
144
  STDERR.puts ex.message
122
- STDERR.puts ex.backtrace if Drydock.debug?
145
+ STDERR.puts ex.backtrace if Stella.loglev > 2 || Drydock.debug?
123
146
  rescue Interrupt
124
147
  puts "#{$/}Exiting... "
125
148
  exit 1
126
149
  rescue => ex
127
150
  STDERR.puts "ERROR (#{ex.class.to_s}): #{ex.message}"
128
- STDERR.puts ex.backtrace if Drydock.debug?
151
+ STDERR.puts ex.backtrace if Stella.loglev > 2 || Drydock.debug?
129
152
  end
@@ -18,14 +18,14 @@
18
18
  #
19
19
  # This plan contains 3 scenarios:
20
20
  #
21
- # - Simple Search (60%)
22
- # - YAML API (30%)
21
+ # - Simple Search (65%)
22
+ # - YAML API (25%)
23
23
  # - Self-serve API (10%)
24
24
  #
25
25
  # The percentages represent the relative amount
26
26
  # of traffic to be generated for each scenario.
27
- # In a test with 100 virtual users, 60 would
28
- # follow the Simple Search usecase, 30 the YAML
27
+ # In a test with 100 virtual users, 65 would
28
+ # follow the Simple Search usecase, 25 the YAML
29
29
  # API, and 10 would following the Self-Serve API.
30
30
  #
31
31
  #
@@ -40,17 +40,10 @@
40
40
  # 3. START THE EXAMPLE APPLICATION
41
41
  #
42
42
  # You need to start the example web application before
43
- # running this testplan. You can do this in one of the
44
- # following ways:
43
+ # running this testplan. You can generate the commands
44
+ # for your local machine with this command:
45
45
  #
46
- # $ ruby examples/example_webapp.rb
47
- #
48
- # OR
49
- #
50
- # $ thin -R examples/example_webapp.ru start
51
- #
52
- # You can check that it's running by going to:
53
- # http://127.0.0.1:3000/
46
+ # $ stella example
54
47
  #
55
48
  #
56
49
  # 4. RUNNING THE TEST PLAN
@@ -104,9 +97,9 @@ usecase 65, "Simple search" do
104
97
  # homepage ("/").
105
98
  #
106
99
  get "/", "Homepage" do
107
- # This tells Stella to wait between 1 and 5
100
+ # This tells Stella to wait between 1 and 3
108
101
  # seconds before moving to the next request.
109
- wait 1..5
102
+ wait 1..3
110
103
  end
111
104
 
112
105
  # In this request, the user has entered a simple
@@ -120,7 +113,7 @@ usecase 65, "Simple search" do
120
113
  # get "http://example.com:8000/search"
121
114
  #
122
115
  get "/search", "Search Results" do
123
- wait 2..5
116
+ wait 2..3
124
117
 
125
118
  # Two URI parameters will be included with this
126
119
  # request. Notice that the values for the what
@@ -176,7 +169,7 @@ usecase 65, "Simple search" do
176
169
  #
177
170
  get "/listing/:lid" do
178
171
  desc "Selected listing"
179
- wait 1..8
172
+ wait 1..4
180
173
  end
181
174
 
182
175
  end
@@ -241,7 +234,6 @@ usecase 10, "Self-serve API" do
241
234
  # identical to the ones you've seen above.
242
235
  #
243
236
  post "/listing/add", "Add a listing" do
244
- wait 1..4
245
237
  param :name => random(8)
246
238
  param :city => random(['Toronto', 'Vancouver', 'Montreal'])
247
239
  param :logo => file('logo.png')
@@ -252,4 +244,4 @@ usecase 10, "Self-serve API" do
252
244
 
253
245
  end
254
246
 
255
- # a5689bb64829d2dc1e9ab8901223cc90c975fe3a
247
+ # 278a014c48dd64d2f2aca0588fa281b9553e825f
data/lib/stella.rb CHANGED
@@ -59,7 +59,7 @@ module Stella
59
59
  blk.call
60
60
  rescue => ex
61
61
  Stella.le "ERROR: #{ex.message}"
62
- Stella.ld ex.backtrace
62
+ Stella.li3 ex.backtrace
63
63
  end
64
64
  end
65
65
 
data/lib/stella/cli.rb CHANGED
@@ -27,13 +27,57 @@ class Stella::CLI < Drydock::Command
27
27
  def load
28
28
  opts = {}
29
29
  opts[:hosts] = @hosts
30
- [:nowait, :clients, :repetitions, :delay, :time].each do |opt|
30
+ [:nowait, :clients, :repetitions, :wait, :duration].each do |opt|
31
31
  opts[opt] = @option.send(opt) unless @option.send(opt).nil?
32
32
  end
33
33
  ret = Stella::Engine::Load.run @testplan, opts
34
34
  @exit_code = (ret ? 0 : 1)
35
35
  end
36
-
36
+
37
+ def stress_valid?
38
+ create_testplan
39
+ end
40
+
41
+ def stress
42
+ opts = {}
43
+ opts[:hosts] = @hosts
44
+ [:clients, :repetitions, :duration].each do |opt|
45
+ opts[opt] = @option.send(opt) unless @option.send(opt).nil?
46
+ end
47
+ ret = Stella::Engine::Stress.run @testplan, opts
48
+ @exit_code = (ret ? 0 : 1)
49
+ end
50
+
51
+ def example
52
+ base_path = File.expand_path(File.join(Stella::LIB_HOME, '..'))
53
+ thin_path = File.join(base_path, 'support', 'sample_webapp', 'config.ru')
54
+ webrick_path = File.join(base_path, 'support', 'sample_webapp', 'app.rb')
55
+ tp_path = File.join(base_path, 'examples', 'essentials', 'plan.rb')
56
+ puts "1. Start the web app:".bright
57
+ puts %Q{
58
+ $ thin -p 3114 -R #{thin_path} start
59
+ OR
60
+ $ ruby #{webrick_path}
61
+ }
62
+ puts "2. Check the web app in your browser".bright
63
+ puts %Q{
64
+ http://127.0.0.1:3114/
65
+ }
66
+ puts "3. Run a functional test:".bright
67
+ puts %Q{
68
+ $ stella verify -p #{tp_path} 127.0.0.1:3114
69
+ }
70
+ puts "4. Run a load test:".bright
71
+ puts %Q{
72
+ $ stella load -p #{tp_path} 127.0.0.1:3114
73
+ }
74
+ end
75
+
76
+ def preview
77
+ create_testplan
78
+ Stella.li @testplan.pretty(Stella.loglev > 1)
79
+ end
80
+
37
81
  private
38
82
  def create_testplan
39
83
  unless @option.testplan.nil? || File.exists?(@option.testplan)
@@ -47,11 +91,11 @@ class Stella::CLI < Drydock::Command
47
91
  @testplan = Stella::Testplan.load_file @option.testplan
48
92
  else
49
93
  opts = {}
50
- opts[:delay] = @option.delay if @option.delay
94
+ opts[:delay] = @option.wait if @option.wait
51
95
  @testplan = Stella::Testplan.new(@argv, opts)
52
96
  end
53
97
  @testplan.check! # raise errors, update usecase ratios
54
- Stella.li3 " File: #{@option.testplan} (#{@testplan.digest})", $/
98
+ Stella.li2 " #{@option.testplan || @testplan.desc} (#{@testplan.digest})"
55
99
  true
56
100
  end
57
101
 
data/lib/stella/client.rb CHANGED
@@ -37,31 +37,35 @@ module Stella
37
37
  headers = prepare_headers(container, req.headers)
38
38
  uri = build_request_uri uri_obj, params, container
39
39
  raise NoHostDefined, uri_obj if uri.host.nil? || uri.host.empty?
40
- stella_id = [Time.now, self.gibbler_cache, req, params, headers, counter].gibbler
40
+ stella_id = [Time.now, self.gibbler_cache, req.gibbler_cache, params, headers, counter].gibbler
41
41
 
42
42
  Benelux.add_thread_tags :request => req.gibbler_cache
43
43
  Benelux.add_thread_tags :retry => counter
44
44
  Benelux.add_thread_tags :stella_id => stella_id
45
45
 
46
- params['__stella'] = stella_id
47
- headers['X-Stella-ID'] = stella_id
46
+ params['__stella'] = stella_id.short
47
+ headers['X-Stella-ID'] = stella_id.short
48
48
 
49
49
  meth = req.http_method.to_s.downcase
50
50
  Stella.ld "#{req.http_method}: " << "#{uri_obj.to_s} " << params.inspect
51
51
 
52
52
  begin
53
53
  send_request http_client, usecase, meth, uri, req, params, headers, container, counter
54
- #http_client.save_cookie_store
55
- update(:stats, http_client, usecase, req)
54
+
55
+ Benelux.add_thread_tags :status => container.status
56
+ Benelux.thread_timeline.add_count :request_header_size, container.response.request.header.dump.size
57
+ Benelux.thread_timeline.add_count :request_content_size, container.response.request.body.content.size
58
+ Benelux.thread_timeline.add_count :response_headers_size, container.response.header.dump.size
59
+ Benelux.thread_timeline.add_count :response_content_size, container.response.body.content.size
60
+ ret = execute_response_handler container, req
61
+ Benelux.remove_thread_tags :status
62
+
56
63
  rescue => ex
64
+ Benelux.thread_timeline.add_count :failed, 1
57
65
  update(:request_error, usecase, uri, req, params, ex)
58
66
  next
59
67
  end
60
68
 
61
- Benelux.add_thread_tags :status => container.status
62
- ret = execute_response_handler container, req
63
- Benelux.remove_thread_tags :status
64
-
65
69
  Stella.lflush
66
70
 
67
71
  run_sleeper(req.wait) if req.wait && !nowait?
@@ -116,6 +120,7 @@ module Stella
116
120
  http_client.set_proxy_auth(@proxy.user, @proxy.pass) if @proxy.user
117
121
  http_client.debug_dev = STDOUT if Stella.debug? && Stella.loglev > 3
118
122
  #http_client.set_cookie_store @cookie_file.path
123
+ http_client.protocol_version = "HTTP/1.1"
119
124
  http_client
120
125
  end
121
126
 
data/lib/stella/engine.rb CHANGED
@@ -4,7 +4,7 @@ module Stella::Engine
4
4
 
5
5
  # These commented out timers are not very revealing.
6
6
  #Benelux.add_timer Stella::Client, :execute
7
- #Benelux.add_timer Stella::Client, :send_request
7
+ Benelux.add_counter Stella::Client, :execute_response_handler
8
8
  #Benelux.add_timer HTTPClient, :create_request
9
9
 
10
10
  # These timers are interesting from a reporting perspective.
@@ -15,7 +15,9 @@ module Stella::Engine
15
15
  Benelux.add_timer HTTPClient::Session, :query
16
16
  Benelux.add_timer HTTPClient::Session, :socket_gets_first_byte
17
17
  Benelux.add_timer HTTPClient::Session, :get_body
18
-
18
+
19
+ #Benelux.add_counter Stella::Client, :execute_response_handler
20
+
19
21
  module Base
20
22
  extend self
21
23
 
@@ -33,18 +35,12 @@ module Stella::Engine
33
35
 
34
36
 
35
37
  def update_quit_usecase client_id, msg
36
- Stella.li2 " Client-%s QUIT %s" % [client_id.shorter, msg]
37
38
  end
38
39
 
39
-
40
40
  def update_repeat_request client_id, counter, total
41
- Stella.li3 " Client-%s REPEAT %d of %d" % [client_id.shorter, counter, total]
42
41
  end
43
42
 
44
43
  def update_stats client_id, http_client, usecase, req
45
- #range = Thread.current.timeline.ranges(:do_request).last
46
- #Thread.current.stathash
47
- #Stella.li "Client-%s: %s-%s %s %.4f" % [client_id.short, usecase.gibbler.short, req.gibbler.short, req.desc, range.duration]
48
44
  end
49
45
 
50
46
  def update_prepare_request(*args) raise end
@@ -12,7 +12,6 @@ module Stella::Engine
12
12
  }.merge! opts
13
13
  Stella.ld "OPTIONS: #{opts.inspect}"
14
14
  Stella.li2 "Hosts: " << opts[:hosts].join(', ') if !opts[:hosts].empty?
15
- Stella.li plan.pretty
16
15
 
17
16
  client = Stella::Client.new opts[:hosts].first
18
17
  client.add_observer(self)
@@ -29,13 +28,18 @@ module Stella::Engine
29
28
  Stella.rescue { client.execute uc }
30
29
  end
31
30
 
32
- !plan.errors?
31
+ #Benelux.update_all_track_timelines
32
+ #tl = Benelux.timeline
33
+
34
+ # errors?
35
+
33
36
  end
34
37
 
35
38
 
36
39
  def update_prepare_request(client_id, usecase, req, counter)
37
40
  notice = "repeat: #{counter-1}" if counter > 1
38
- Stella.li2 " %-46s %16s ".bright % [req.desc, notice]
41
+ desc = "#{req.desc} (#{req.gibbler_cache.shorter}) "
42
+ Stella.li2 " %-46s %16s ".bright % [desc, notice]
39
43
  end
40
44
 
41
45
  def update_receive_response(client_id, usecase, uri, req, counter, container)
@@ -62,16 +66,24 @@ module Stella::Engine
62
66
 
63
67
  def update_error_execute_response_handler(client_id, ex, req, container)
64
68
  Stella.le ex.message
65
- Stella.ld ex.backtrace
69
+ Stella.li3 ex.backtrace
66
70
  end
67
71
 
68
72
  def update_request_error(client_id, usecase, uri, req, params, ex)
69
73
  desc = "#{usecase.desc} > #{req.desc}"
70
74
  Stella.le ' Client-%s %-45s %s' % [client_id.short, desc, ex.message]
71
- Stella.ld ex.backtrace
75
+ Stella.li3 ex.backtrace
76
+ end
77
+
78
+ def update_quit_usecase client_id, msg
79
+ Stella.li4 " Client-%s QUIT %s" % [client_id.shorter, msg]
72
80
  end
73
81
 
74
82
 
83
+ def update_repeat_request client_id, counter, total
84
+ Stella.li4 " Client-%s REPEAT %d of %d" % [client_id.shorter, counter, total]
85
+ end
86
+
75
87
  end
76
88
  end
77
89
 
@@ -3,211 +3,42 @@ module Stella::Engine
3
3
  module Load
4
4
  extend Stella::Engine::Base
5
5
  extend self
6
-
6
+
7
+ @timers = [:do_request]
8
+ @counts = [:response_content_size]
9
+
10
+ class << self
11
+ attr_accessor :timers, :counts
12
+ end
13
+
7
14
  def run(plan, opts={})
8
15
  opts = {
9
- :hosts => [],
16
+ :hosts => [],
10
17
  :clients => 1,
11
- :time => nil,
12
- :nowait => false,
13
- :repetitions => 1
18
+ :duration => nil,
19
+ :nowait => false,
20
+ :repetitions => 1
14
21
  }.merge! opts
15
22
  opts[:clients] = plan.usecases.size if opts[:clients] < plan.usecases.size
16
23
  opts[:clients] = 1000 if opts[:clients] > 1000
17
24
 
18
- Stella.ld "OPTIONS: #{opts.inspect}"
19
- Stella.li3 "Hosts: " << opts[:hosts].join(', ')
20
- Stella.li2 plan.pretty
21
-
22
- counts = calculate_usecase_clients plan, opts
25
+ Stella.li3 " Options: #{opts.inspect}"
26
+ Stella.li3 " Hosts: " << opts[:hosts].join(', ')
23
27
 
24
- Stella.li $/, "Preparing #{counts[:total]} virtual clients...", $/
25
- Stella.lflush
26
- packages = build_thread_package plan, opts, counts
28
+ #wait_for_reporter
27
29
 
28
- Stella.li "Generating load...", $/
29
- Stella.lflush
30
+ # errors?
30
31
 
31
- begin
32
- execute_test_plan packages, opts[:repetitions]
33
- rescue Interrupt
34
- Stella.li "Stopping test...", $/
35
- Stella.abort!
36
- ensure
37
- Stella.li "Processing statistics...", $/
38
- Stella.lflush
39
- generate_report plan
40
-
41
- rep_stats = self.timeline.ranges(:build_thread_package).first
42
- Stella.li "%20s %0.4f" % ['Prep time:', rep_stats.duration]
43
-
44
- rep_stats = self.timeline.ranges(:execute_test_plan).first
45
- Stella.li "%20s %0.4f" % ['Test time:', rep_stats.duration]
46
-
47
- rep_stats = self.timeline.ranges(:generate_report).first
48
- Stella.li "%20s %0.4f" % ['Reporting time:', rep_stats.duration]
49
- Stella.li $/
50
- end
51
-
52
-
53
-
54
- !plan.errors?
55
- end
56
-
57
-
58
- protected
59
- class ThreadPackage
60
- attr_accessor :index
61
- attr_accessor :client
62
- attr_accessor :usecase
63
- def initialize(i, c, u)
64
- @index, @client, @usecase = i, c, u
65
- end
66
32
  end
67
33
 
68
- def calculate_usecase_clients(plan, opts)
69
- counts = { :total => 0 }
70
- plan.usecases.each_with_index do |usecase,i|
71
- count = case opts[:clients]
72
- when 0..9
73
- if (opts[:clients] % plan.usecases.size > 0)
74
- msg = "Client count does not evenly match usecase count"
75
- raise Stella::Testplan::WackyRatio, msg
76
- else
77
- (opts[:clients] / plan.usecases.size)
78
- end
79
- else
80
- (opts[:clients] * usecase.ratio).to_i
81
- end
82
- counts[usecase.gibbler_cache] = count
83
- counts[:total] += count
84
- end
85
- counts
34
+ def wait_for_reporter
35
+ Benelux.reporter.wait
86
36
  end
87
37
 
88
- def build_thread_package(plan, opts, counts)
89
- packages, pointer = Array.new(counts[:total]), 0
90
- plan.usecases.each do |usecase|
91
- count = counts[usecase.gibbler_cache]
92
- Stella.ld "THREAD PACKAGE: #{usecase.desc} (#{pointer} + #{count})"
93
- # Fill the thread_package with the contents of the block
94
- packages.fill(pointer, count) do |index|
95
- Stella.li3 "Creating client ##{index+1} "
96
- client = Stella::Client.new opts[:hosts].first, index+1
97
- client.add_observer(self)
98
- client.enable_nowait_mode if opts[:nowait]
99
- ThreadPackage.new(index+1, client, usecase)
100
- end
101
- pointer += count
102
- end
103
- packages.compact # TODO: Why one nil element sometimes?
104
- end
105
-
106
- def execute_test_plan(packages, reps=1)
107
- Thread.ify packages, :threads => packages.size do |package|
108
-
109
- # This thread will stay on this one track.
110
- Benelux.current_track package.client.gibbler
111
- Benelux.add_thread_tags :usecase => package.usecase.gibbler_cache
112
-
113
- (1..reps).to_a.each do |rep|
114
- Benelux.add_thread_tags :rep => rep
115
- Stella::Engine::Load.rescue(package.client.gibbler_cache) {
116
- print '.' if Stella.loglev == 1
117
- stats = package.client.execute package.usecase
118
- break if Stella.abort?
119
- }
120
- Benelux.remove_thread_tags :rep
121
- end
122
-
123
- Benelux.remove_thread_tags :usecase
124
- end
125
- Stella.li $/, $/
126
- end
127
-
128
- def generate_report(plan)
129
- Benelux.update_all_track_timelines
130
- global_timeline = Benelux.timeline
131
-
132
- Stella.li $/, " %-72s ".att(:reverse) % ["#{plan.desc} (#{plan.gibbler_cache.shorter})"]
133
- plan.usecases.uniq.each_with_index do |uc,i|
134
-
135
- # TODO: Create Ranges object, like Stats object
136
- # global_timeline.ranges(:do_request)[:usecase => '1111']
137
- # The following returns globl do_request ranges.
138
- requests = 0 #global_timeline.ranges(:do_request).size
139
-
140
- desc = uc.desc || "Usecase ##{i+1} "
141
- desc << " (#{uc.gibbler_cache.shorter}) "
142
- str = ' ' << " %-66s %s %d%% ".bright.att(:reverse)
143
- Stella.li str % [desc, '', uc.ratio_pretty]
144
-
145
- uc.requests.each do |req|
146
- desc = req.desc
147
- Stella.li " %-72s ".bright % ["#{req.desc} (#{req.gibbler_cache.shorter})"]
148
- Stella.li " %s" % [req.to_s]
149
- global_timeline.stats.each_pair do |n,stat|
150
- filter = {
151
- :usecase => uc.gibbler_cache,
152
- :request => req.gibbler_cache
153
- }
154
- stats = stat[filter]
155
- Stella.li ' %-30s %.3f <= %.3f >= %.3f; %.3f(SD) %d(N)' % [n, stats.min, stats.mean, stats.max, stats.sd, stats.n]
156
- Stella.lflush
157
- end
158
- Stella.li $/
159
- end
160
- end
161
- end
162
-
163
-
164
- def update_prepare_request(client_id, usecase, req, counter)
165
-
166
- end
167
-
168
- def update_receive_response(client_id, usecase, uri, req, counter, container)
169
- desc = "#{usecase.desc} > #{req.desc}"
170
- Stella.li2 ' Client-%s %3d %-6s %-45s' % [client_id.shorter, container.status, req.http_method, uri]
171
- end
172
-
173
- def update_execute_response_handler(client_id, req, container)
174
- end
175
-
176
- def update_error_execute_response_handler(client_id, ex, req, container)
177
- desc = "#{container.usecase.desc} > #{req.desc}"
178
- Stella.li $/ if Stella.loglev == 1
179
- Stella.le ' Client-%s %-45s %s' % [client_id.shorter, desc, ex.message]
180
- Stella.ld ex.backtrace
181
- end
182
-
183
- def update_request_error(client_id, usecase, uri, req, params, ex)
184
- desc = "#{usecase.desc} > #{req.desc}"
185
- Stella.li $/ if Stella.loglev == 1
186
- Stella.le ' Client-%s %-45s %s' % [client_id.shorter, desc, ex.message]
187
- Stella.ld ex.backtrace
188
- end
189
-
190
-
191
- def self.rescue(client_id, &blk)
192
- blk.call
193
- rescue => ex
194
- Stella.le ' Error in Client-%s: %s' % [client_id.shorter, ex.message]
195
- Stella.ld ex.backtrace
196
- end
38
+ protected
197
39
 
40
+ #Benelux.add_timer Stella::Engine::Load, :build_thread_package
198
41
 
199
- Benelux.add_timer Stella::Engine::Load, :generate_report
200
- Benelux.add_timer Stella::Engine::Load, :build_thread_package
201
- Benelux.add_timer Stella::Engine::Load, :execute_test_plan
202
- Benelux.add_timer Stella::Client, :execute_response_handler
203
42
  end
204
43
  end
205
44
 
206
- __END__
207
-
208
-
209
- $ stella verify -p examples/basic/plan.rb http://localhost:3114
210
- $ stella load -p examples/basic/plan.rb http://localhost:3114
211
- $ stella remote-load -p examples/basic/plan.rb http://localhost:3114
212
- $ stella remote-verify -p examples/basic/plan.rb http://localhost:3114
213
-
@@ -0,0 +1,23 @@
1
+
2
+
3
+ class Numeric
4
+ # TODO: Use 1024
5
+ def to_bytes
6
+ args = case self.abs.to_i
7
+ when 0..1_000
8
+ [(self).to_s, 'B']
9
+ when 1_000..1_000_000
10
+ [(self / 1000).to_s, 'KB']
11
+ when 1_000_000..1_000_000_000
12
+ [(self / (1000**2)).to_s, 'MB']
13
+ when 1_000_000_000..1_000_000_000_000
14
+ [(self / (1000**3)).to_s, 'GB']
15
+ when 1_000_000_000_000..1_000_000_000_000_000
16
+ [(self / (1000**4)).to_s, 'TB']
17
+ else
18
+ [self, 'B']
19
+ end
20
+ '%3.2f%s' % args
21
+ end
22
+ end
23
+
@@ -14,7 +14,7 @@ class Testplan
14
14
  attr_reader :stats
15
15
 
16
16
  def initialize(uris=[], opts={})
17
- @desc, @usecases = "Stella's plan", []
17
+ @desc, @usecases = "Test plan", []
18
18
  @testplan_current_ratio = 0
19
19
  @stats = Stella::Testplan::Stats.new
20
20
 
@@ -27,6 +27,8 @@ class Testplan
27
27
  uri.path = '/' if uri.path.nil? || uri.path.empty?
28
28
  req = usecase.add_request :get, uri.path
29
29
  req.wait = opts[:delay] if opts[:delay]
30
+ req.gibbler
31
+ req.freeze
30
32
  end
31
33
  self.add_usecase usecase
32
34
  end
@@ -43,12 +45,6 @@ class Testplan
43
45
  plan
44
46
  end
45
47
 
46
- # Were there any errors in any of the usecases?
47
- def errors?
48
- Stella.ld "TODO: tally use case errors"
49
- false
50
- end
51
-
52
48
  def check!
53
49
  # Adjust ratios if necessary
54
50
  needy = @usecases.select { |u| u.ratio == -1 }
@@ -93,15 +89,18 @@ class Testplan
93
89
  @desc
94
90
  end
95
91
 
96
- def pretty
92
+ def pretty(long=false)
97
93
  str = []
98
- str << " %-66s ".att(:reverse) % ["#{@desc} (#{self.gibbler_cache.shorter})"]
94
+ dig = long ? self.gibbler_cache : self.gibbler_cache.shorter
95
+ str << " %-66s ".att(:reverse) % ["#{@desc} (#{dig})"]
99
96
  @usecases.each_with_index do |uc,i|
97
+ dig = long ? uc.gibbler_cache : uc.gibbler_cache.shorter
100
98
  desc = uc.desc || "Usecase ##{i+1}"
101
- desc += " (#{uc.gibbler_cache.shorter}) "
99
+ desc += " (#{dig}) "
102
100
  str << (' ' << " %-61s %s%% ".att(:reverse).bright) % [desc, uc.ratio_pretty]
103
101
  requests = uc.requests.each do |r|
104
- str << " %-62s".bright % ["#{r.desc} (#{r.gibbler_cache.shorter})"]
102
+ dig = long ? r.gibbler_cache : r.gibbler_cache.shorter
103
+ str << " %-62s".bright % ["#{r.desc} (#{dig})"]
105
104
  str << " %s" % [r]
106
105
  if Stella.loglev > 2
107
106
  [:wait].each { |i| str << " %s: %s" % [i, r.send(i)] }
@@ -73,8 +73,6 @@ class Testplan
73
73
  req.desc = args[1] if args.size > 1 # Description is optional
74
74
  Stella.ld req
75
75
  @requests << req
76
- req.gibbler
77
- req.freeze
78
76
  req
79
77
  end
80
78
  def get(*args, &blk); add_request :get, *args, &blk; end
@@ -6,7 +6,7 @@ module Stella
6
6
  MAJOR = 0.freeze
7
7
  MINOR = 7.freeze
8
8
  TINY = 0.freeze
9
- PATCH = '012'.freeze
9
+ PATCH = '014'.freeze
10
10
  end
11
11
  def self.to_s; [MAJOR, MINOR, TINY].join('.'); end
12
12
  def self.to_f; self.to_s.to_f; end
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.0.012"
4
+ s.version = "0.7.0.014"
5
5
  s.summary = "Stella: Perform load tests on your web applications with beauty and brute strength."
6
6
  s.description = s.summary
7
7
  s.author = "Delano Mandelbaum"
@@ -15,7 +15,7 @@
15
15
 
16
16
  s.executables = %w[stella]
17
17
 
18
- s.add_dependency 'benelux', '>= 0.3.2'
18
+ s.add_dependency 'benelux', '>= 0.4.0'
19
19
  s.add_dependency 'drydock', '>= 0.6.8'
20
20
  s.add_dependency 'gibbler', '>= 0.6.3'
21
21
  s.add_dependency 'storable', '>= 0.5.7'
@@ -34,8 +34,6 @@
34
34
  examples/essentials/logo.png
35
35
  examples/essentials/plan.rb
36
36
  examples/essentials/search_terms.csv
37
- examples/example_webapp.rb
38
- examples/example_webapp.ru
39
37
  examples/exceptions/plan.rb
40
38
  lib/stella.rb
41
39
  lib/stella/cli.rb
@@ -54,6 +52,7 @@
54
52
  lib/stella/exceptions.rb
55
53
  lib/stella/guidelines.rb
56
54
  lib/stella/mixins.rb
55
+ lib/stella/mixins/numeric.rb
57
56
  lib/stella/mixins/thread.rb
58
57
  lib/stella/stats.rb
59
58
  lib/stella/testplan.rb
@@ -64,6 +63,8 @@
64
63
  lib/stella/version.rb
65
64
  lib/threadify.rb
66
65
  stella.gemspec
66
+ support/sample_webapp/app.rb
67
+ support/sample_webapp/config.ru
67
68
  support/useragents.txt
68
69
  vendor/httpclient-2.1.5.2/httpclient.rb
69
70
  vendor/httpclient-2.1.5.2/httpclient/auth.rb
@@ -1,16 +1,27 @@
1
1
  #!/usr/bin/ruby
2
2
 
3
+ # Stella Sample Web Application
4
+ #
5
+ # This application plays nicely with the example
6
+ # test plans (see examples/).
7
+ #
8
+ # Usage:
9
+ #
10
+ # $ ruby support/sample_webapp/app.rb
11
+ # OR
12
+ # $ thin -R support/sample_webapp/config.ru -p 3114 start
13
+ #
14
+
3
15
  require "rubygems"
4
16
  require "sinatra"
17
+ require "yaml"
5
18
 
6
- require 'yaml'
7
-
8
- set :run => $0 == __FILE__ ? true : false
9
- set :environment => :development
10
- set :dump_errors => true
11
- set :port => 3114
12
- set :reload => true
13
- set :max_listings => 1000
19
+ set :run => ($0 == __FILE__)
20
+ set :environment => :development
21
+ set :dump_errors => true
22
+ set :port => 3114
23
+ set :reload => true
24
+ set :max_listings => 1000
14
25
 
15
26
  LISTINGS = [
16
27
  { :id => 1000, :name => 'John West Smoked Oysters', :city => 'Toronto' },
@@ -0,0 +1,12 @@
1
+ # Stella Sample Web Application
2
+ #
3
+ # This application plays nicely with the example
4
+ # test plans (see examples/).
5
+ #
6
+ # Usage:
7
+ #
8
+ # $ thin -R support/sample_webapp/config.ru -p 3114 start
9
+
10
+ dir = ::File.expand_path(::File.dirname(__FILE__))
11
+ require ::File.join(dir, 'app.rb')
12
+ run Sinatra::Application
@@ -773,10 +773,10 @@ private
773
773
  retry_count -= 1
774
774
  end
775
775
  end
776
-
777
776
  res
778
777
  end
779
-
778
+
779
+ # NOTE: Not tracked by Benelux / Stella
780
780
  def do_request_async(method, uri, query, body, extheader)
781
781
  conn = Connection.new
782
782
  t = Thread.new(conn) { |tconn|
@@ -954,10 +954,10 @@ private
954
954
  res = HTTP::Message.new_response(content)
955
955
  @debug_dev << "= Request\n\n" if @debug_dev
956
956
  sess = @session_manager.query(req, proxy)
957
-
958
957
  res.peer_cert = sess.ssl_peer_cert
959
958
  @debug_dev << "\n\n= Response\n\n" if @debug_dev
960
959
  do_get_header(req, res, sess)
960
+ res.header.size = sess.headers_bytes
961
961
  conn.push(res)
962
962
  sess.get_body do |part|
963
963
  if block
@@ -1005,6 +1005,7 @@ private
1005
1005
 
1006
1006
  def do_get_header(req, res, sess)
1007
1007
  res.version, res.status, res.reason, headers = sess.get_header
1008
+ #Benelux.thread_timeline.add_count :response_header_size, res.header
1008
1009
  headers.each do |key, value|
1009
1010
  res.header.add(key, value)
1010
1011
  end
@@ -95,6 +95,9 @@ module HTTP
95
95
 
96
96
  # Represents HTTP message header.
97
97
  class Headers
98
+ # Size of Header content (original string). Set from session.headers_bytes.
99
+ attr_accessor :size
100
+
98
101
  # HTTP version in a HTTP header. Float.
99
102
  attr_accessor :http_version
100
103
  # Size of body. nil when size is unknown (e.g. chunked response).
@@ -429,6 +432,8 @@ module HTTP
429
432
  # If no dev (the second argument) given, this method returns a dumped
430
433
  # String.
431
434
  def dump(header = '', dev = '')
435
+ #header_size = header.size
436
+ #body_size = 0
432
437
  if @body.is_a?(Parts)
433
438
  dev << header
434
439
  buf = ''
@@ -436,17 +441,24 @@ module HTTP
436
441
  if Message.file?(part)
437
442
  reset_pos(part)
438
443
  while !part.read(@chunk_size, buf).nil?
444
+ #body_size += buf.size
439
445
  dev << buf
440
446
  end
441
447
  else
448
+ #body_size += part.size
442
449
  dev << part
443
450
  end
444
451
  end
445
452
  elsif @body
453
+ #body_size = @body.size
446
454
  dev << header + @body
447
455
  else
448
456
  dev << header
449
457
  end
458
+
459
+ #Benelux.thread_timeline.add_count :data_sent, header_size, :type => :header
460
+ #Benelux.thread_timeline.add_count :data_sent, body_size, :type => :body
461
+
450
462
  dev
451
463
  end
452
464
 
@@ -726,7 +738,7 @@ module HTTP
726
738
  # Returns true if the given HTTP version allows keep alive connection.
727
739
  # version:: Float
728
740
  def keep_alive_enabled?(version)
729
- version >= 1.1
741
+ version.to_f >= 1.1
730
742
  end
731
743
 
732
744
  # Returns true if the given query (or body) has a multiple parameter.
@@ -800,6 +812,7 @@ module HTTP
800
812
  # dev needs to respond to <<.
801
813
  def dump(dev = '')
802
814
  str = header.dump + CRLF
815
+ body_size = body ? body.size : 0
803
816
  if header.chunked
804
817
  dev = body.dump_chunked(str, dev)
805
818
  elsif body
@@ -481,7 +481,10 @@ class HTTPClient
481
481
  attr_accessor :ssl_config
482
482
  attr_reader :ssl_peer_cert
483
483
  attr_accessor :test_loopback_http_response
484
-
484
+
485
+ attr_reader :headers_bytes
486
+ attr_reader :content_bytes
487
+
485
488
  def initialize(client, dest, agent_name, from)
486
489
  @client = client
487
490
  @dest = dest
@@ -512,7 +515,8 @@ class HTTPClient
512
515
  @status = nil
513
516
  @reason = nil
514
517
  @headers = []
515
-
518
+ @headers_bytes = 0
519
+ @content_bytes = 0
516
520
  @socket = nil
517
521
  @readbuf = nil
518
522
  end
@@ -752,6 +756,7 @@ class HTTPClient
752
756
  if initial_line.nil?
753
757
  raise KeepAliveDisconnected.new
754
758
  end
759
+ @headers_bytes += initial_line.size
755
760
  if StatusParseRegexp !~ initial_line
756
761
  @version = '0.9'
757
762
  @status = nil
@@ -774,6 +779,7 @@ class HTTPClient
774
779
  key, value = line.split(/\s*:\s*/, 2)
775
780
  parse_keepalive_header(key, value)
776
781
  @headers << [key, value]
782
+ @headers_bytes += line.size
777
783
  end
778
784
  end while (@version == '1.1' && @status == 100)
779
785
  end
@@ -811,6 +817,7 @@ class HTTPClient
811
817
  end
812
818
  if buf && buf.length > 0
813
819
  @content_length -= buf.length
820
+ @content_bytes += buf.length
814
821
  yield buf
815
822
  else
816
823
  @content_length = 0
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.0.012
4
+ version: 0.7.0.014
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-10-02 00:00:00 -04:00
12
+ date: 2009-10-06 00:00:00 -04:00
13
13
  default_executable:
14
14
  dependencies:
15
15
  - !ruby/object:Gem::Dependency
@@ -20,7 +20,7 @@ dependencies:
20
20
  requirements:
21
21
  - - ">="
22
22
  - !ruby/object:Gem::Version
23
- version: 0.3.2
23
+ version: 0.4.0
24
24
  version:
25
25
  - !ruby/object:Gem::Dependency
26
26
  name: drydock
@@ -92,8 +92,6 @@ files:
92
92
  - examples/essentials/logo.png
93
93
  - examples/essentials/plan.rb
94
94
  - examples/essentials/search_terms.csv
95
- - examples/example_webapp.rb
96
- - examples/example_webapp.ru
97
95
  - examples/exceptions/plan.rb
98
96
  - lib/stella.rb
99
97
  - lib/stella/cli.rb
@@ -112,6 +110,7 @@ files:
112
110
  - lib/stella/exceptions.rb
113
111
  - lib/stella/guidelines.rb
114
112
  - lib/stella/mixins.rb
113
+ - lib/stella/mixins/numeric.rb
115
114
  - lib/stella/mixins/thread.rb
116
115
  - lib/stella/stats.rb
117
116
  - lib/stella/testplan.rb
@@ -122,6 +121,8 @@ files:
122
121
  - lib/stella/version.rb
123
122
  - lib/threadify.rb
124
123
  - stella.gemspec
124
+ - support/sample_webapp/app.rb
125
+ - support/sample_webapp/config.ru
125
126
  - support/useragents.txt
126
127
  - vendor/httpclient-2.1.5.2/httpclient.rb
127
128
  - vendor/httpclient-2.1.5.2/httpclient/auth.rb
@@ -1,9 +0,0 @@
1
- # Stella Demo Rackup
2
- #
3
- # Usage:
4
- #
5
- # $ thin -R examples/example_webapp.ru -p 3114 start
6
-
7
- dir = ::File.expand_path(::File.dirname(__FILE__))
8
- require ::File.join(dir, 'example_webapp.rb')
9
- run Sinatra::Application