stella 0.7.0.012 → 0.7.0.014

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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