stella 0.7.0.015 → 0.7.0.017

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.
@@ -1,6 +1,7 @@
1
1
  require "observer"
2
- require "tempfile"
3
- require 'nokogiri'
2
+ require "nokogiri"
3
+
4
+ Stella::Utils.require_vendor "httpclient", '2.1.5.2'
4
5
 
5
6
  module Stella
6
7
  class Client
@@ -21,7 +22,7 @@ module Stella
21
22
  end
22
23
  def execute(usecase, &stat_collector)
23
24
  # We need to make sure the gibbler cache has a value
24
- self.gibbler if self.__gibbler_cache.nil?
25
+ self.gibbler if self.digest_cache.nil?
25
26
 
26
27
  http_client = create_http_client
27
28
  stats = {}
@@ -30,6 +31,8 @@ module Stella
30
31
  usecase.requests.each do |req|
31
32
  counter += 1
32
33
 
34
+ container.reset_temp_vars
35
+
33
36
  stats ||= Benelux::Stats.new
34
37
  update(:prepare_request, usecase, req, counter)
35
38
  uri_obj = URI.parse(req.uri)
@@ -37,14 +40,13 @@ module Stella
37
40
  headers = prepare_headers(container, req.headers)
38
41
  uri = build_request_uri uri_obj, params, container
39
42
  raise NoHostDefined, uri_obj if uri.host.nil? || uri.host.empty?
40
- stella_id = [Time.now, self.gibbler_cache, req.gibbler_cache, params, headers, counter].gibbler
43
+ stella_id = [Time.now, self.digest_cache, req.digest_cache, params, headers, counter].gibbler
41
44
 
42
- Benelux.add_thread_tags :request => req.gibbler_cache
45
+ Benelux.add_thread_tags :request => req.digest_cache
43
46
  Benelux.add_thread_tags :retry => counter
44
47
  Benelux.add_thread_tags :stella_id => stella_id
45
48
 
46
- params['__stella'] = stella_id.short
47
- headers['X-Stella-ID'] = stella_id.short
49
+ params['__stella'] = headers['X-Stella-ID']= stella_id[0..10]
48
50
 
49
51
  meth = req.http_method.to_s.downcase
50
52
  Stella.ld "#{req.http_method}: " << "#{uri_obj.to_s} " << params.inspect
@@ -97,7 +99,7 @@ module Stella
97
99
  end
98
100
 
99
101
  def update(kind, *args)
100
- changed and notify_observers(kind, self.__gibbler_cache, *args)
102
+ changed and notify_observers(kind, self.digest_cache, *args)
101
103
  end
102
104
 
103
105
  def run_sleeper(wait)
@@ -119,7 +121,6 @@ module Stella
119
121
  http_client = HTTPClient.new opts
120
122
  http_client.set_proxy_auth(@proxy.user, @proxy.pass) if @proxy.user
121
123
  http_client.debug_dev = STDOUT if Stella.debug? && Stella.loglev > 3
122
- #http_client.set_cookie_store @cookie_file.path
123
124
  http_client.protocol_version = "HTTP/1.1"
124
125
  http_client
125
126
  end
@@ -10,6 +10,7 @@ class Stella::Client
10
10
  def initialize(usecase)
11
11
  @usecase, @resources = usecase, {}
12
12
  @base_path = usecase.base_path
13
+ @random_value = {}
13
14
  end
14
15
 
15
16
  # This is used to handle custom exception in usecases.
@@ -30,12 +31,21 @@ class Stella::Client
30
31
  YAML.load(body)
31
32
  end
32
33
  end
33
-
34
+
35
+ # Return a resource from the usecase or from this
36
+ # container (in that order).
34
37
  def resource(n)
35
38
  return @usecase.resource(n) if @usecase.resources.has_key? n
36
39
  return @resources[n] if @resources.has_key? n
40
+ nil
37
41
  end
38
42
 
43
+ def reset_temp_vars
44
+ @random_value = {}
45
+ @sequential_value = {}
46
+ @rsequential_value = {}
47
+ end
48
+
39
49
  def body; @response.body.content; end
40
50
  def headers; @response.header; end
41
51
  alias_method :header, :headers
@@ -24,84 +24,137 @@ module Stella::Data
24
24
  end
25
25
 
26
26
  def random(*args)
27
- input = args.size > 1 ? args : args.first
27
+ if Symbol === args.first
28
+ input, index = *args
29
+ elsif Array === args.first || args.size == 1
30
+ input = args.first
31
+ else
32
+ input = args
33
+ end
34
+
28
35
  Proc.new do
29
- value = case input.class.to_s
30
- when "Symbol"
31
- resource(input)
32
- when "Array"
33
- input
34
- when "Range"
35
- input.to_a
36
- when "Proc"
37
- input.call
38
- when "Fixnum"
39
- Stella::Utils.strand( input )
40
- when "NilClass"
41
- Stella::Utils.strand( rand(100) )
36
+ if @random_value[input]
37
+ value = @random_value[input]
38
+ else
39
+ value = case input.class.to_s
40
+ when "Symbol"
41
+ resource(input)
42
+ when "Array"
43
+ input
44
+ when "Range"
45
+ input.to_a
46
+ when "Proc"
47
+ input.call
48
+ when "Fixnum"
49
+ Stella::Utils.strand( input )
50
+ when "NilClass"
51
+ Stella::Utils.strand( rand(100) )
52
+ end
53
+ raise Stella::Testplan::Usecase::UnknownResource, input if value.nil?
54
+ Stella.ld "RANDVALUES: #{input} #{value.class} #{value.inspect}"
55
+ value = value[ rand(value.size) ] if value.is_a?(Array)
56
+ Stella.ld "SELECTED: #{value.class} #{value} "
57
+ @random_value[input] = value
42
58
  end
43
- raise Stella::Testplan::Usecase::UnknownResource, input if value.nil?
44
- Stella.ld "RANDVALUES: #{input} #{value.inspect}"
45
- value = value[ rand(value.size) ] if value.is_a?(Array)
46
- Stella.ld "SELECTED: #{value}"
59
+
60
+ # The resource may be an Array of Arrays (e.g. a CSV file)
61
+ if value.is_a?(Array) && !index.nil?
62
+ value = value[ index ]
63
+ Stella.ld "SELECTED INDEX: #{index} #{value.inspect} "
64
+ end
65
+
47
66
  value
48
67
  end
49
68
  end
50
69
 
51
70
  def sequential(*args)
52
- input = args.size > 1 ? args : args.first
71
+ if Symbol === args.first
72
+ input, index = *args
73
+ elsif Array === args.first || args.size == 1
74
+ input = args.first
75
+ else
76
+ input = args
77
+ end
53
78
  Proc.new do
54
- value = case input.class.to_s
55
- when "Symbol"
56
- ret = resource(input)
57
- ret
58
- when "Array"
59
- input
60
- when "Range"
61
- input.to_a
62
- when "Proc"
63
- input.call
79
+ if @sequential_value[input]
80
+ value = @sequential_value[input]
81
+ else
82
+ value = case input.class.to_s
83
+ when "Symbol"
84
+ ret = resource(input)
85
+ ret
86
+ when "Array"
87
+ input
88
+ when "Range"
89
+ input.to_a
90
+ when "Proc"
91
+ input.call
92
+ end
93
+ digest = value.gibbler
94
+ @sequential_offset ||= {}
95
+ @sequential_offset[digest] ||= 0
96
+ Stella.ld "SEQVALUES: #{input} #{value.inspect} #{@sequential_offset[digest]}"
97
+ if value.is_a?(Array)
98
+ size = value.size
99
+ @sequential_offset[digest] = 0 if @sequential_offset[digest] >= size
100
+ value = value[ @sequential_offset[digest] ]
101
+ @sequential_offset[digest] += 1
102
+ end
103
+ Stella.ld "SELECTED: #{value}"
104
+ @sequential_value[input] = value
64
105
  end
65
- digest = value.gibbler
66
- @sequential_offset ||= {}
67
- @sequential_offset[digest] ||= 0
68
- Stella.ld "SEQVALUES: #{input} #{value.inspect} #{@sequential_offset[digest]}"
69
- if value.is_a?(Array)
70
- size = value.size
71
- @sequential_offset[digest] = 0 if @sequential_offset[digest] >= size
72
- value = value[ @sequential_offset[digest] ]
73
- @sequential_offset[digest] += 1
106
+ # The resource may be an Array of Arrays (e.g. a CSV file)
107
+ if value.is_a?(Array) && !index.nil?
108
+ value = value[ index ]
109
+ Stella.ld "SELECTED INDEX: #{index} #{value.inspect} "
74
110
  end
75
- Stella.ld "SELECTED: #{value}"
76
111
  value
77
112
  end
78
113
  end
79
114
 
80
115
  def rsequential(*args)
81
- input = args.size > 1 ? args : args.first
116
+ if Symbol === args.first
117
+ input, index = *args
118
+ elsif Array === args.first || args.size == 1
119
+ input = args.first
120
+ else
121
+ input = args
122
+ end
82
123
  Proc.new do
83
- value = case input.class.to_s
84
- when "Symbol"
85
- ret = resource(input)
86
- ret
87
- when "Array"
88
- input
89
- when "Range"
90
- input.to_a
91
- when "Proc"
92
- input.call
124
+ if @rsequential_value[input.digest]
125
+ value = @rsequential_value[input.digest]
126
+ else
127
+ value = case input.class.to_s
128
+ when "Symbol"
129
+ ret = resource(input)
130
+ ret
131
+ when "Array"
132
+ input
133
+ when "Range"
134
+ input.to_a
135
+ when "Proc"
136
+ input.call
137
+ end
138
+ digest = value.gibbler
139
+ @rsequential_offset ||= {}
140
+ @rsequential_offset[digest] ||= value.size-1 rescue 1
141
+ Stella.ld "RSEQVALUES: #{input} #{value.inspect} #{@rsequential_offset[digest]}"
142
+ if value.is_a?(Array)
143
+ size = value.size
144
+ @rsequential_offset[digest] = size-1 if @rsequential_offset[digest] < 0
145
+ value = value[ @rsequential_offset[digest] ]
146
+ @rsequential_offset[digest] -= 1
147
+ end
148
+ Stella.ld "SELECTED: #{value}"
149
+ @rsequential_value[input.digest] = value
93
150
  end
94
- digest = value.gibbler
95
- @rsequential_offset ||= {}
96
- @rsequential_offset[digest] ||= value.size-1 rescue 1
97
- Stella.ld "RSEQVALUES: #{input} #{value.inspect} #{@rsequential_offset[digest]}"
98
- if value.is_a?(Array)
99
- size = value.size
100
- @rsequential_offset[digest] = size-1 if @rsequential_offset[digest] < 0
101
- value = value[ @rsequential_offset[digest] ]
102
- @rsequential_offset[digest] -= 1
151
+
152
+ # The resource may be an Array of Arrays (e.g. a CSV file)
153
+ if value.is_a?(Array) && !index.nil?
154
+ value = value[ index ]
155
+ Stella.ld "SELECTED INDEX: #{index} #{value.inspect} "
103
156
  end
104
- Stella.ld "SELECTED: #{value}"
157
+
105
158
  value
106
159
  end
107
160
  end
@@ -110,4 +163,4 @@ module Stella::Data
110
163
 
111
164
  end
112
165
 
113
- Stella::Utils.require_glob(Stella::LIB_HOME, 'stella', 'data', '*.rb')
166
+ Stella::Utils.require_glob(STELLA_LIB_HOME, 'stella', 'data', '*.rb')
@@ -1,4 +1,4 @@
1
1
 
2
2
  module Stella::Data::HTTP; end
3
3
 
4
- Stella::Utils.require_glob(Stella::LIB_HOME, 'stella', 'data', 'http', '*.rb')
4
+ Stella::Utils.require_glob(STELLA_LIB_HOME, 'stella', 'data', 'http', '*.rb')
@@ -5,13 +5,13 @@ module Stella::Data::HTTP
5
5
  include Gibbler::Complex
6
6
  include Stella::Data::Helpers
7
7
 
8
- # A hash containing blocks to be executed depending on the HTTP response status.
9
- # The hash keys are numeric HTTP Status Codes.
10
- #
11
- # 200 => { ... }
12
- # 304 => { ... }
13
- # 500 => { ... }
14
- #
8
+ # A hash containing blocks to be executed depending on the HTTP response status.
9
+ # The hash keys are numeric HTTP Status Codes.
10
+ #
11
+ # 200 => { ... }
12
+ # 304 => { ... }
13
+ # 500 => { ... }
14
+ #
15
15
  attr_accessor :response_handler
16
16
 
17
17
  field :desc
@@ -5,6 +5,8 @@ module Stella::Engine
5
5
  module Base
6
6
  extend self
7
7
 
8
+ @@client_limit = 200
9
+
8
10
  def update(*args)
9
11
  what, *args = args
10
12
  if respond_to?("update_#{what}")
@@ -15,18 +17,41 @@ module Stella::Engine
15
17
  end
16
18
  end
17
19
 
18
- def run; raise; end
19
-
20
-
21
- def update_quit_usecase client_id, msg
22
- end
23
-
24
- def update_repeat_request client_id, counter, total
25
- end
26
-
27
- def update_stats client_id, http_client, usecase, req
20
+ def process_options!(plan, opts={})
21
+ opts = {
22
+ :hosts => [],
23
+ :clients => 1,
24
+ :duration => 0,
25
+ :nowait => false,
26
+ :arrival => nil,
27
+ :repetitions => 1
28
+ }.merge! opts
29
+
30
+ Stella.li3 " Options: #{opts.inspect}"
31
+ Stella.lflush
32
+
33
+ opts[:clients] = plan.usecases.size if opts[:clients] < plan.usecases.size
34
+
35
+ if opts[:clients] > @@client_limit
36
+ Stella.li3 "Client limit is #{@@client_limit}"
37
+ opts[:clients] = @@client_limit
38
+ end
39
+
40
+ # Parses 60m -> 3600. See mixins.
41
+ if opts[:duration].in_seconds.nil?
42
+ raise Stella::WackyDuration, opts[:duration]
43
+ end
44
+
45
+ opts[:duration] = opts[:duration].in_seconds
46
+
47
+ Stella.li3 " Hosts: " << opts[:hosts].join(', ')
48
+ opts
28
49
  end
29
50
 
51
+ def run; raise; end
52
+ def update_quit_usecase(client_id, msg) raise end
53
+ def update_repeat_request(client_id, counter, total) raise end
54
+ def update_stats(client_id, http_client, usecase, req) raise end
30
55
  def update_prepare_request(*args) raise end
31
56
  def update_send_request(*args) raise end
32
57
  def update_receive_response(*args) raise end
@@ -36,7 +61,7 @@ module Stella::Engine
36
61
 
37
62
  end
38
63
 
39
- Stella::Utils.require_glob(Stella::LIB_HOME, 'stella', 'engine', '*.rb')
64
+ Stella::Utils.require_glob(STELLA_LIB_HOME, 'stella', 'engine', '*.rb')
40
65
 
41
66
 
42
67
  # These timers are interesting from a reporting perspective.
@@ -5,11 +5,8 @@ module Stella::Engine
5
5
  extend self
6
6
 
7
7
  def run(plan, opts={})
8
- opts = {
9
- :hosts => [],
10
- :nowait => false,
11
- :repetitions => 1
12
- }.merge! opts
8
+ opts = process_options! plan, opts
9
+
13
10
  Stella.ld "OPTIONS: #{opts.inspect}"
14
11
  Stella.li2 "Hosts: " << opts[:hosts].join(', ') if !opts[:hosts].empty?
15
12
 
@@ -18,13 +15,16 @@ module Stella::Engine
18
15
 
19
16
  client.enable_nowait_mode if opts[:nowait]
20
17
 
21
- Stella.li $/, "Starting test...", $/
18
+ Stella.li2 $/, "Starting test...", $/
22
19
  Stella.lflush
23
20
  sleep 0.3
24
21
 
22
+ dig = Stella.loglev > 1 ? plan.digest_cache : plan.digest_cache.shorter
23
+ Stella.li " %-65s ".att(:reverse) % ["#{plan.desc} (#{dig})"]
25
24
  plan.usecases.each_with_index do |uc,i|
26
25
  desc = (uc.desc || "Usecase ##{i+1}")
27
- Stella.li ' %-65s '.att(:reverse).bright % ["#{desc} (#{uc.gibbler_cache.shorter}) "]
26
+ dig = Stella.loglev > 1 ? uc.digest_cache : uc.digest_cache.shorter
27
+ Stella.li ' %-65s '.att(:reverse).bright % ["#{desc} (#{dig}) "]
28
28
  Stella.rescue { client.execute uc }
29
29
  end
30
30
 
@@ -38,7 +38,8 @@ module Stella::Engine
38
38
 
39
39
  def update_prepare_request(client_id, usecase, req, counter)
40
40
  notice = "repeat: #{counter-1}" if counter > 1
41
- desc = "#{req.desc} (#{req.gibbler_cache.shorter}) "
41
+ dig = Stella.loglev > 1 ? req.digest_cache : req.digest_cache.shorter
42
+ desc = "#{req.desc} (#{dig}) "
42
43
  Stella.li2 " %-46s %16s ".bright % [desc, notice]
43
44
  end
44
45
 
@@ -12,23 +12,59 @@ module Stella::Engine
12
12
  end
13
13
 
14
14
  def run(plan, opts={})
15
- opts = {
16
- :hosts => [],
17
- :clients => 1,
18
- :duration => nil,
19
- :nowait => false,
20
- :repetitions => 1
21
- }.merge! opts
22
- opts[:clients] = plan.usecases.size if opts[:clients] < plan.usecases.size
23
- opts[:clients] = 1000 if opts[:clients] > 1000
15
+ opts = process_options! plan, opts
24
16
 
25
- Stella.li3 " Options: #{opts.inspect}"
26
- Stella.li3 " Hosts: " << opts[:hosts].join(', ')
17
+ if Stella.loglev > 1
18
+ Load.timers += [:connect, :create_socket, :query, :socket_gets_first_byte, :get_body]
19
+ Load.counts = [:request_header_size, :request_content_size]
20
+ Load.counts += [:response_headers_size, :response_content_size]
21
+ end
27
22
 
28
- #wait_for_reporter
23
+ counts = calculate_usecase_clients plan, opts
29
24
 
30
- # errors?
25
+ Stella.li $/, "Preparing #{counts[:total]} virtual clients...", $/
26
+ Stella.lflush
27
+ packages = build_thread_package plan, opts, counts
28
+
29
+ if opts[:duration] > 0
30
+ msg = "for #{opts[:duration].seconds}s"
31
+ else
32
+ msg = "for #{opts[:repetitions]} reps"
33
+ end
34
+
35
+ Stella.li "Generating requests #{msg}...", $/
36
+ Stella.lflush
31
37
 
38
+ @mode = :rolling
39
+
40
+ begin
41
+ execute_test_plan packages, opts[:repetitions], opts[:duration]
42
+ rescue Interrupt
43
+ Stella.li "Stopping test...", $/
44
+ Stella.abort!
45
+ ensure
46
+ Stella.li "Processing statistics...", $/
47
+ Stella.lflush
48
+
49
+ wait_for_reporter
50
+
51
+ tt = Benelux.thread_timeline
52
+ test_time = tt.stats.group(:execute_test_plan).mean
53
+
54
+ generate_report plan, test_time
55
+
56
+ #p Benelux.timeline
57
+
58
+ Stella.li "Summary: "
59
+ Stella.li " max clients: %d" % @max_clients
60
+ Stella.li " repetitions: %d" % @real_reps
61
+ Stella.li " test time: %10.2fs" % test_time
62
+ Stella.li " wait time: %10.2fs" % tt.stats.group(:wait_for_reporter).mean
63
+ Stella.li " post time: %10.2fs" % tt.stats.group(:generate_report).mean
64
+ Stella.li $/
65
+ end
66
+
67
+ # errors?
32
68
  end
33
69
 
34
70
  def wait_for_reporter
@@ -36,8 +72,269 @@ module Stella::Engine
36
72
  end
37
73
 
38
74
  protected
75
+ class ThreadPackage
76
+ attr_accessor :index
77
+ attr_accessor :client
78
+ attr_accessor :usecase
79
+ def initialize(i, c, u)
80
+ @index, @client, @usecase = i, c, u
81
+ end
82
+ end
83
+
84
+ def calculate_usecase_clients(plan, opts)
85
+ counts = { :total => 0 }
86
+ plan.usecases.each_with_index do |usecase,i|
87
+ count = case opts[:clients]
88
+ when 0..9
89
+ if (opts[:clients] % plan.usecases.size > 0)
90
+ msg = "Client count does not evenly match usecase count"
91
+ raise Stella::WackyRatio, msg
92
+ else
93
+ (opts[:clients] / plan.usecases.size)
94
+ end
95
+ else
96
+ (opts[:clients] * usecase.ratio).to_i
97
+ end
98
+ counts[usecase.digest_cache] = count
99
+ counts[:total] += count
100
+ end
101
+ counts
102
+ end
103
+
104
+ def build_thread_package(plan, opts, counts)
105
+ packages, pointer = Array.new(counts[:total]), 0
106
+ plan.usecases.each do |usecase|
107
+ count = counts[usecase.digest_cache]
108
+ Stella.ld "THREAD PACKAGE: #{usecase.desc} (#{pointer} + #{count})"
109
+ # Fill the thread_package with the contents of the block
110
+ packages.fill(pointer, count) do |index|
111
+ client = Stella::Client.new opts[:hosts].first, index+1
112
+ client.add_observer(self)
113
+ client.enable_nowait_mode if opts[:nowait]
114
+ Stella.li4 "Created client #{client.digest.short}"
115
+ ThreadPackage.new(index+1, client, usecase)
116
+ end
117
+ pointer += count
118
+ end
119
+ packages.compact # TODO: Why one nil element sometimes?
120
+ end
121
+
122
+ def execute_test_plan(packages, reps=1, duration=0)
123
+ time_started = Time.now
124
+
125
+ @threads, @max_clients, @real_reps = [], 0, 0
126
+ (1..reps).to_a.each { |rep|
127
+ @real_reps += 1 # Increments when duration is specified.
128
+ Stella.li3 "*** REPETITION #{@real_reps} of #{reps} ***"
129
+ packages.each { |package|
130
+ if running_threads.size <= packages.size
131
+ @threads << Thread.new do
132
+ c, uc = package.client, package.usecase
133
+ msg = "THREAD START: client %s: " % [c.digest.short]
134
+ msg << "%s:%s (rep: %d)" % [uc.desc, uc.digest.short, @real_reps]
135
+ Stella.li4 $/, "======== " << msg
136
+ # This thread will stay on this one track.
137
+ Benelux.current_track c.digest
138
+ Benelux.add_thread_tags :usecase => uc.digest_cache
139
+
140
+ Benelux.add_thread_tags :rep => @real_reps
141
+ Stella::Engine::Load.rescue(c.digest_cache) {
142
+ break if Stella.abort?
143
+ print '.' if Stella.loglev == 2
144
+ stats = c.execute uc
145
+ }
146
+ Benelux.remove_thread_tags :rep
147
+ Benelux.remove_thread_tags :usecase
148
+
149
+ end
150
+ Stella.sleep :create_thread
151
+ end
152
+
153
+ if running_threads.size > @max_clients
154
+ @max_clients = running_threads.size
155
+ end
156
+
157
+ if @mode == :rolling
158
+ tries = 0
159
+ while (reps > 1 || duration > 0) && running_threads.size >= packages.size
160
+ Stella.sleep :check_threads
161
+ msg = "#{running_threads.size} (max: #{@max_clients})"
162
+ Stella.li3 "*** RUNNING THREADS: #{msg} ***"
163
+ (tries += 1)
164
+ end
165
+ end
166
+ }
167
+
168
+ if @mode != :rolling && running_threads.size > 0
169
+ args = [running_threads.size, @max_clients]
170
+ Stella.li3 "*** WAITING FOR %d THREADS TO FINISH (max: %d) ***" % args
171
+ @threads.each { |t| t.join } # wait
172
+ end
173
+
174
+ # If a duration was given, we make sure
175
+ # to run for only that amount of time.
176
+ # TODO: do not redo if
177
+ # time_elapsed + usecase.mean > duration
178
+ if duration > 0
179
+ time_elapsed = (Time.now - time_started).to_i
180
+ msg = "#{time_elapsed} of #{duration} (threads: %d)" % running_threads.size
181
+ Stella.li3 "*** TIME ELAPSED: #{msg} ***"
182
+ sleep 0.5 and redo if time_elapsed <= duration
183
+ break if time_elapsed >= duration
184
+ end
185
+
186
+ }
187
+
188
+ if @mode == :rolling && running_threads.size > 0
189
+ Stella.li3 "*** WAITING FOR THREADS TO FINISH ***"
190
+ @threads.each { |t| t.join } # wait
191
+ end
192
+ Stella.li2 $/, $/
193
+ end
194
+ def running_threads
195
+ @threads.select { |t| t.status } # non-false status are still running
196
+ end
197
+ def generate_report(plan,test_time)
198
+ #Benelux.update_all_track_timelines
199
+ global_timeline = Benelux.timeline
200
+
201
+ Stella.li $/, " %-72s ".att(:reverse) % ["#{plan.desc} (#{plan.digest_cache.shorter})"]
202
+ plan.usecases.uniq.each_with_index do |uc,i|
203
+
204
+ # TODO: Create Ranges object, like Stats object
205
+ # global_timeline.ranges(:do_request)[:usecase => '1111']
206
+ # The following returns globl do_request ranges.
207
+ requests = 0 #global_timeline.ranges(:do_request).size
208
+
209
+ desc = uc.desc || "Usecase ##{i+1} "
210
+ desc << " (#{uc.digest_cache.shorter}) "
211
+ str = ' ' << " %-66s %s %d%% ".bright.att(:reverse)
212
+ Stella.li str % [desc, '', uc.ratio_pretty]
213
+
214
+ uc.requests.each do |req|
215
+ filter = [uc.digest_cache, req.digest_cache]
216
+ desc = req.desc
217
+ Stella.li " %-72s ".bright % ["#{req.desc} (#{req.digest_cache.shorter})"]
218
+ Stella.li " %s" % [req.to_s]
219
+ Load.timers.each do |sname|
220
+ stats = global_timeline.stats.group(sname)[filter].merge
221
+ # Stella.li stats.inspect
222
+ str = ' %-30s %.3f <= ' << '%.3fs' << ' >= %.3f; %.3f(SD) %d(N)'
223
+ Stella.li str % [sname, stats.min, stats.mean, stats.max, stats.sd, stats.n]
224
+ Stella.lflush
225
+ end
226
+ Stella.li $/
227
+ end
228
+
229
+ Stella.li " Sub Total:".bright
230
+
231
+ stats = global_timeline.stats.group(:do_request)[uc.digest_cache].merge
232
+ failed = global_timeline.stats.group(:failed)[uc.digest_cache].merge
233
+ respgrp = global_timeline.stats.group(:execute_response_handler)[uc.digest_cache]
234
+ resst = respgrp.tag_values(:status)
235
+ statusi = []
236
+ resst.each do |status|
237
+ size = respgrp[:status => status].size
238
+ statusi << "#{status}: #{size}"
239
+ end
240
+ Stella.li ' %-30s %d (%s)' % ['Total requests', stats.n, statusi.join(', ')]
241
+ Stella.li ' %-29s %d' % [:success, stats.n - failed.n]
242
+ Stella.li ' %-29s %d' % [:failed, failed.n]
243
+
244
+ Load.timers.each do |sname|
245
+ stats = global_timeline.stats.group(sname)[uc.digest_cache].merge
246
+ Stella.li ' %-30s %.3fs %.3f(SD)' % [sname, stats.mean, stats.sd]
247
+ Stella.lflush
248
+ end
249
+
250
+ Load.counts.each do |sname|
251
+ stats = global_timeline.stats.group(sname)[uc.digest_cache].merge
252
+ Stella.li ' %-30s %-12s (avg:%s)' % [sname, stats.sum.to_bytes, stats.mean.to_bytes]
253
+ Stella.lflush
254
+ end
255
+ Stella.li $/
256
+ end
257
+
258
+ Stella.li ' ' << " %-66s ".att(:reverse) % 'Total:'
259
+ stats = global_timeline.stats.group(:do_request).merge
260
+ failed = global_timeline.stats.group(:failed)
261
+ respgrp = global_timeline.stats.group(:execute_response_handler)
262
+ resst = respgrp.tag_values(:status)
263
+ statusi = []
264
+ resst.each do |status|
265
+ size = respgrp[:status => status].size
266
+ statusi << [status, size]
267
+ end
268
+ Stella.li ' %-30s %d' % ['Total requests', stats.n]
269
+ success = stats.n - failed.n
270
+ Stella.li ' %-29s %d (req/s: %.2f)' % [:success, success, success/test_time]
271
+ statusi.each do |pair|
272
+ Stella.li2 ' %-28s %s: %d' % ['', *pair]
273
+ end
274
+ Stella.li ' %-29s %d' % [:failed, failed.n]
275
+
276
+ Load.timers.each do |sname|
277
+ stats = global_timeline.stats.group(sname).merge
278
+ Stella.li ' %-30s %-.3fs %-.3f(SD)' % [sname, stats.mean, stats.sd]
279
+ Stella.lflush
280
+ end
281
+
282
+ Load.counts.each do |sname|
283
+ stats = global_timeline.stats.group(sname).merge
284
+ Stella.li ' %-30s %-12s (avg:%s)' % [sname, stats.sum.to_bytes, stats.mean.to_bytes]
285
+ Stella.lflush
286
+ end
287
+ Stella.li $/
288
+ end
289
+
290
+
291
+ def update_prepare_request(client_id, usecase, req, counter)
292
+
293
+ end
294
+
295
+ def update_receive_response(client_id, usecase, uri, req, counter, container)
296
+ desc = "#{usecase.desc} > #{req.desc}"
297
+ Stella.li3 ' Client-%s %3d %-6s %-45s' % [client_id.shorter, container.status, req.http_method, uri]
298
+ end
299
+
300
+ def update_execute_response_handler(client_id, req, container)
301
+ end
302
+
303
+ def update_error_execute_response_handler(client_id, ex, req, container)
304
+ desc = "#{container.usecase.desc} > #{req.desc}"
305
+ Stella.li $/ if Stella.loglev == 1
306
+ Stella.le ' Client-%s %-45s %s' % [client_id.shorter, desc, ex.message]
307
+ Stella.li3 ex.backtrace
308
+ end
309
+
310
+ def update_request_error(client_id, usecase, uri, req, params, ex)
311
+ desc = "#{usecase.desc} > #{req.desc}"
312
+ Stella.li $/ if Stella.loglev == 1
313
+ Stella.le ' Client-%s %-45s %s' % [client_id.shorter, desc, ex.message]
314
+ Stella.li3 ex.backtrace
315
+ end
316
+
317
+ def update_quit_usecase client_id, msg
318
+ Stella.li3 " Client-%s QUIT %s" % [client_id.shorter, msg]
319
+ end
320
+
321
+
322
+ def update_repeat_request client_id, counter, total
323
+ Stella.li3 " Client-%s REPEAT %d of %d" % [client_id.shorter, counter, total]
324
+ end
325
+
326
+ def self.rescue(client_id, &blk)
327
+ blk.call
328
+ rescue => ex
329
+ Stella.le ' Error in Client-%s: %s' % [client_id.shorter, ex.message]
330
+ Stella.li3 ex.backtrace
331
+ end
332
+
39
333
 
40
- #Benelux.add_timer Stella::Engine::Load, :build_thread_package
334
+ Benelux.add_timer Stella::Engine::Load, :build_thread_package
335
+ Benelux.add_timer Stella::Engine::Load, :execute_test_plan
336
+ Benelux.add_timer Stella::Engine::Load, :generate_report
337
+ Benelux.add_timer Stella::Engine::Load, :wait_for_reporter
41
338
 
42
339
  end
43
340
  end