kronk 1.7.8 → 1.8.0
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/History.rdoc +32 -0
- data/Manifest.txt +5 -5
- data/README.rdoc +5 -3
- data/Rakefile +3 -4
- data/TODO.rdoc +22 -6
- data/lib/kronk.rb +13 -7
- data/lib/kronk/buffered_io.rb +26 -0
- data/lib/kronk/cmd.rb +58 -44
- data/lib/kronk/constants.rb +5 -6
- data/lib/kronk/diff.rb +12 -13
- data/lib/kronk/diff/output.rb +1 -1
- data/lib/kronk/http.rb +105 -0
- data/lib/kronk/player.rb +74 -82
- data/lib/kronk/player/benchmark.rb +34 -35
- data/lib/kronk/player/stream.rb +6 -6
- data/lib/kronk/player/suite.rb +17 -16
- data/lib/kronk/player/tsv.rb +51 -0
- data/lib/kronk/queue_runner.rb +126 -102
- data/lib/kronk/request.rb +144 -82
- data/lib/kronk/response.rb +520 -202
- data/lib/kronk/test/helper_methods.rb +1 -1
- data/test/mocks/200_gzip.txt +0 -0
- data/test/mocks/200_inflate.txt +0 -0
- data/test/test_assertions.rb +1 -1
- data/test/test_cmd.rb +18 -11
- data/test/test_diff.rb +39 -0
- data/test/test_helper.rb +18 -14
- data/test/test_helper_methods.rb +5 -4
- data/test/test_kronk.rb +8 -11
- data/test/test_player.rb +67 -123
- data/test/test_request.rb +8 -14
- data/test/test_response.rb +228 -60
- metadata +20 -31
- data/lib/kronk/async.rb +0 -118
- data/lib/kronk/async/em_ext.rb +0 -34
- data/lib/kronk/async/request.rb +0 -73
- data/lib/kronk/async/response.rb +0 -70
- data/lib/kronk/player/output.rb +0 -49
data/lib/kronk/constants.rb
CHANGED
@@ -1,19 +1,19 @@
|
|
1
1
|
class Kronk
|
2
2
|
|
3
3
|
# Generic Request exception.
|
4
|
-
class
|
4
|
+
class Error < ::StandardError; end
|
5
5
|
|
6
6
|
# Raised when parsing fails.
|
7
|
-
class ParserError <
|
7
|
+
class ParserError < Error; end
|
8
8
|
|
9
9
|
# Raised when the URI was not resolvable.
|
10
|
-
class NotFoundError <
|
10
|
+
class NotFoundError < Error; end
|
11
11
|
|
12
12
|
# Raised when HTTP times out.
|
13
|
-
class TimeoutError <
|
13
|
+
class TimeoutError < Error; end
|
14
14
|
|
15
15
|
# Raised when a missing (but non-mandatory) dependency can't be loaded.
|
16
|
-
class MissingDependency <
|
16
|
+
class MissingDependency < Error; end
|
17
17
|
|
18
18
|
|
19
19
|
# Config directory.
|
@@ -80,7 +80,6 @@ class Kronk
|
|
80
80
|
|
81
81
|
# Default config to use.
|
82
82
|
DEFAULT_CONFIG = {
|
83
|
-
:async => 'auto',
|
84
83
|
:content_types => DEFAULT_CONTENT_TYPES.dup,
|
85
84
|
:cache_file => DEFAULT_CACHE_FILE,
|
86
85
|
:context => 3,
|
data/lib/kronk/diff.rb
CHANGED
@@ -96,6 +96,7 @@ class Kronk
|
|
96
96
|
@meta.last[0] = str1.meta[0] if str1.respond_to?(:meta)
|
97
97
|
@meta.last[1] = str2.meta[0] if str2.respond_to?(:meta)
|
98
98
|
end
|
99
|
+
|
99
100
|
diff_ary.concat arr1[c[1], c[0]]
|
100
101
|
|
101
102
|
last_i1 = c[1] + c[0]
|
@@ -161,8 +162,7 @@ class Kronk
|
|
161
162
|
|
162
163
|
arr2_map = {}
|
163
164
|
arr2.each_with_index do |line, j|
|
164
|
-
arr2_map[line] ||= []
|
165
|
-
arr2_map[line] << j
|
165
|
+
(arr2_map[line] ||= []) << j
|
166
166
|
end
|
167
167
|
|
168
168
|
arr1.each_with_index do |line, i|
|
@@ -184,14 +184,7 @@ class Kronk
|
|
184
184
|
end
|
185
185
|
|
186
186
|
len = j - start_j
|
187
|
-
|
188
|
-
sequences[len] ||= []
|
189
|
-
sequences[len] << [len, i, start_j]
|
190
|
-
|
191
|
-
if len > 1
|
192
|
-
sequences[len-1] ||= []
|
193
|
-
sequences[len-1] << [(len-1), i, start_j]
|
194
|
-
end
|
187
|
+
(sequences[len] ||= []) << [len, i, start_j]
|
195
188
|
end
|
196
189
|
end
|
197
190
|
|
@@ -239,11 +232,17 @@ class Kronk
|
|
239
232
|
|
240
233
|
private
|
241
234
|
|
242
|
-
def yield_sequences sequences,
|
243
|
-
while sequences.length >
|
235
|
+
def yield_sequences sequences, &block # :nodoc:
|
236
|
+
while sequences.length > 0
|
244
237
|
item = sequences.pop
|
245
238
|
next unless item
|
246
|
-
item.each
|
239
|
+
item.each do |seq|
|
240
|
+
resp = yield seq
|
241
|
+
if !resp && seq[0] > 1
|
242
|
+
seq[0] = seq[0] - 1
|
243
|
+
(sequences[seq[0]] ||= []) << seq
|
244
|
+
end
|
245
|
+
end
|
247
246
|
end
|
248
247
|
end
|
249
248
|
end
|
data/lib/kronk/diff/output.rb
CHANGED
data/lib/kronk/http.rb
ADDED
@@ -0,0 +1,105 @@
|
|
1
|
+
class Kronk
|
2
|
+
|
3
|
+
class HTTPBadResponse < Net::HTTPBadResponse; end
|
4
|
+
|
5
|
+
##
|
6
|
+
# Wrapper for Net::HTTP
|
7
|
+
|
8
|
+
class HTTP < Net::HTTP
|
9
|
+
|
10
|
+
def request(req, body=nil, opts={}, &block) # :yield: +response+
|
11
|
+
unless started?
|
12
|
+
start {
|
13
|
+
req['connection'] ||= 'close'
|
14
|
+
return request(req, body, &block)
|
15
|
+
}
|
16
|
+
end
|
17
|
+
if proxy_user()
|
18
|
+
req.proxy_basic_auth proxy_user(), proxy_pass() unless use_ssl?
|
19
|
+
end
|
20
|
+
req.set_body_internal body
|
21
|
+
res = transport_request(req, true, opts, &block)
|
22
|
+
if sspi_auth?(res)
|
23
|
+
sspi_auth(req)
|
24
|
+
res = transport_request(req, true, opts, &block)
|
25
|
+
end
|
26
|
+
res
|
27
|
+
end
|
28
|
+
|
29
|
+
|
30
|
+
private
|
31
|
+
|
32
|
+
def transport_request(req, allow_retry=true, opts={})
|
33
|
+
# Check if previous request was made on same socket and needs
|
34
|
+
# to be completed before we can read the new response.
|
35
|
+
if Kronk::BufferedIO === @socket && !@socket.response.read?
|
36
|
+
@socket.response.body
|
37
|
+
end
|
38
|
+
|
39
|
+
begin_transport req
|
40
|
+
req.exec @socket, @curr_http_version, edit_path(req.path)
|
41
|
+
|
42
|
+
begin
|
43
|
+
opts[:timeout] ||= @socket.read_timeout
|
44
|
+
res = Kronk::Response.new(@socket.io, opts)
|
45
|
+
end while kronk_resp_type(res) == Net::HTTPContinue
|
46
|
+
|
47
|
+
if res.headless?
|
48
|
+
raise HTTPBadResponse, "Invalid HTTP response" unless allow_retry
|
49
|
+
@socket.io.close
|
50
|
+
res = transport_request(req, false, opts)
|
51
|
+
end
|
52
|
+
|
53
|
+
@socket = res.io
|
54
|
+
|
55
|
+
res.body {|chunk|
|
56
|
+
yield res, chunk
|
57
|
+
} if block_given?
|
58
|
+
|
59
|
+
end_transport req, res
|
60
|
+
res
|
61
|
+
|
62
|
+
rescue => exception
|
63
|
+
D "Conn close because of error #{exception}"
|
64
|
+
@socket.close if @socket and not @socket.closed?
|
65
|
+
raise exception
|
66
|
+
end
|
67
|
+
|
68
|
+
|
69
|
+
def end_transport(req, res)
|
70
|
+
@curr_http_version = res.http_version
|
71
|
+
if @socket.closed?
|
72
|
+
D 'Conn socket closed'
|
73
|
+
elsif keep_alive?(req, res)
|
74
|
+
D 'Conn keep-alive'
|
75
|
+
elsif not res.body and @close_on_empty_response
|
76
|
+
D 'Conn close'
|
77
|
+
@socket.close
|
78
|
+
else
|
79
|
+
D 'Conn close'
|
80
|
+
@socket.close
|
81
|
+
end
|
82
|
+
end
|
83
|
+
|
84
|
+
|
85
|
+
def sspi_auth?(res)
|
86
|
+
return false unless @sspi_enabled
|
87
|
+
if kronk_resp_type(res) == HTTPProxyAuthenticationRequired and
|
88
|
+
proxy? and res["Proxy-Authenticate"].include?("Negotiate")
|
89
|
+
begin
|
90
|
+
require 'win32/sspi'
|
91
|
+
true
|
92
|
+
rescue LoadError
|
93
|
+
false
|
94
|
+
end
|
95
|
+
else
|
96
|
+
false
|
97
|
+
end
|
98
|
+
end
|
99
|
+
|
100
|
+
|
101
|
+
def kronk_resp_type res
|
102
|
+
Net::HTTPResponse::CODE_TO_OBJ[res.code]
|
103
|
+
end
|
104
|
+
end
|
105
|
+
end
|
data/lib/kronk/player.rb
CHANGED
@@ -2,46 +2,70 @@ class Kronk
|
|
2
2
|
|
3
3
|
##
|
4
4
|
# The Player class is used for running multiple requests and comparisons and
|
5
|
-
# providing useful output through Player
|
6
|
-
# Kronk includes a Suite (test-like)
|
5
|
+
# providing useful output through inherited Player classes.
|
6
|
+
# Kronk includes a Suite (test-like), a Stream (chunked),
|
7
7
|
# and a Benchmark output.
|
8
8
|
|
9
9
|
class Player < QueueRunner
|
10
10
|
|
11
|
-
|
11
|
+
##
|
12
|
+
# Instantiate a new type of player, typically :suite, :stream, or
|
13
|
+
# :benchmark.
|
14
|
+
|
15
|
+
def self.new_type type, opts={}
|
16
|
+
klass =
|
17
|
+
case type.to_s
|
18
|
+
when /^(Player::)?benchmark$/i then Benchmark
|
19
|
+
when /^(Player::)?stream$/i then Stream
|
20
|
+
when /^(Player::)?suite$/i then Suite
|
21
|
+
when /^(Player::)?tsv$/i then TSV
|
22
|
+
else
|
23
|
+
Kronk.find_const type.to_s
|
24
|
+
end
|
25
|
+
|
26
|
+
klass.new opts
|
27
|
+
end
|
28
|
+
|
29
|
+
|
30
|
+
|
31
|
+
attr_accessor :input, :qps, :concurrency, :mutex
|
12
32
|
|
13
33
|
##
|
14
34
|
# Create a new Player for batch diff or response validation.
|
15
35
|
# Supported options are:
|
16
36
|
# :io:: IO - The IO instance to read from
|
17
|
-
# :output:: Class - The output class to use (see Player::Output)
|
18
37
|
# :parser:: Class - The IO parser to use.
|
38
|
+
# :concurrency:: Fixnum - Maximum number of concurrent items to process
|
39
|
+
# :qps:: Fixnum - Number of queries to process per second
|
19
40
|
|
20
41
|
def initialize opts={}
|
21
42
|
super
|
22
|
-
|
43
|
+
|
44
|
+
@concurrency = opts[:concurrency]
|
45
|
+
@concurrency = 1 if !@concurrency || @concurrency <= 0
|
46
|
+
@qps = opts[:qps]
|
23
47
|
|
24
48
|
@input = InputReader.new opts[:io], opts[:parser]
|
25
|
-
@use_output = true
|
26
49
|
@last_req = nil
|
50
|
+
@mutex = Mutex.new
|
27
51
|
|
28
52
|
@on_input = Proc.new do
|
29
53
|
stop_input! if !@number && @input.eof?
|
30
54
|
@last_req = @input.get_next || @queue.last || @last_req || {}
|
31
55
|
end
|
32
56
|
|
33
|
-
@on_result = Proc.new do |kronk, err, mutex|
|
34
|
-
err ? @output.error(err, kronk, mutex) :
|
35
|
-
@output.result(kronk, mutex)
|
36
|
-
end
|
37
|
-
|
38
57
|
on(:input, &@on_input)
|
39
58
|
on(:interrupt){
|
40
|
-
|
59
|
+
interrupt and return if respond_to?(:interrupt)
|
60
|
+
complete if respond_to?(:complete)
|
41
61
|
exit 2
|
42
62
|
}
|
43
|
-
on(:start){
|
44
|
-
|
63
|
+
on(:start){
|
64
|
+
start if respond_to?(:start)
|
65
|
+
}
|
66
|
+
on(:complete){
|
67
|
+
complete if respond_to?(:complete)
|
68
|
+
}
|
45
69
|
end
|
46
70
|
|
47
71
|
|
@@ -58,26 +82,6 @@ class Kronk
|
|
58
82
|
end
|
59
83
|
|
60
84
|
|
61
|
-
##
|
62
|
-
# The kind of output to use. Typically Player::Suite or Player::Stream.
|
63
|
-
# Takes an output class or a string that represents a class constant.
|
64
|
-
|
65
|
-
def output_from new_output
|
66
|
-
return @output = new_output.new(self) if Class === new_output
|
67
|
-
|
68
|
-
klass =
|
69
|
-
case new_output.to_s
|
70
|
-
when /^(Player::)?benchmark$/i then Benchmark
|
71
|
-
when /^(Player::)?stream$/i then Stream
|
72
|
-
when /^(Player::)?suite$/i then Suite
|
73
|
-
else
|
74
|
-
Kronk.find_const new_output
|
75
|
-
end
|
76
|
-
|
77
|
-
@output = klass.new self if klass
|
78
|
-
end
|
79
|
-
|
80
|
-
|
81
85
|
##
|
82
86
|
# Process the queue to compare two uris.
|
83
87
|
# If options are given, they are merged into every request.
|
@@ -85,10 +89,10 @@ class Kronk
|
|
85
89
|
def compare uri1, uri2, opts={}, &block
|
86
90
|
return Cmd.compare uri1, uri2, @queue.shift.merge(opts) if single_request?
|
87
91
|
|
88
|
-
|
92
|
+
on(:result){|(kronk, err)| trigger_result(kronk, err, &block) }
|
89
93
|
|
90
|
-
run do |
|
91
|
-
|
94
|
+
run opts do |kronk|
|
95
|
+
kronk.compare uri1, uri2
|
92
96
|
end
|
93
97
|
end
|
94
98
|
|
@@ -100,55 +104,37 @@ class Kronk
|
|
100
104
|
def request uri, opts={}, &block
|
101
105
|
return Cmd.request uri, @queue.shift.merge(opts) if single_request?
|
102
106
|
|
103
|
-
|
107
|
+
on(:result){|(kronk, err)| trigger_result(kronk, err, &block) }
|
104
108
|
|
105
|
-
run do |
|
106
|
-
|
109
|
+
run opts do |kronk|
|
110
|
+
kronk.request uri
|
107
111
|
end
|
108
112
|
end
|
109
113
|
|
110
114
|
|
111
115
|
##
|
112
|
-
#
|
113
|
-
# Output#error method.
|
114
|
-
#
|
115
|
-
# If given a block, will yield the Kronk instance and error. If
|
116
|
-
# a third argument is given, mutex will also be passed and the
|
117
|
-
# block won't be called from a mutex lock.
|
118
|
-
#
|
119
|
-
# Returns the result of the block or of the called Output method.
|
116
|
+
# Similar to QueueRunner#run but yields a Kronk instance.
|
120
117
|
|
121
|
-
def
|
122
|
-
|
123
|
-
|
124
|
-
|
125
|
-
|
126
|
-
|
127
|
-
|
128
|
-
err = e
|
118
|
+
def run opts={}
|
119
|
+
if @qps
|
120
|
+
method = :periodically
|
121
|
+
arg = 1.0 / @qps.to_f
|
122
|
+
else
|
123
|
+
method = :concurrently
|
124
|
+
arg = @concurrency
|
129
125
|
end
|
130
126
|
|
131
|
-
|
132
|
-
|
127
|
+
send method, arg do |kronk_opts|
|
128
|
+
err = nil
|
129
|
+
kronk = Kronk.new kronk_opts.merge(opts)
|
133
130
|
|
131
|
+
begin
|
132
|
+
yield kronk
|
133
|
+
rescue *Kronk::Cmd::RESCUABLE => e
|
134
|
+
err = e
|
135
|
+
end
|
134
136
|
|
135
|
-
|
136
|
-
# Run a single compare or request and call the Output#result or
|
137
|
-
# Output#error method using EventMachine.
|
138
|
-
#
|
139
|
-
# If given a block, will yield the Kronk instance and error. If
|
140
|
-
# a third argument is given, mutex will also be passed and the
|
141
|
-
# block won't be called from a mutex lock.
|
142
|
-
#
|
143
|
-
# Returns either a EM::MultiRequest or an EM::Connection handler.
|
144
|
-
|
145
|
-
def process_one_async opts={}, *args, &block
|
146
|
-
kronk = Kronk.new opts
|
147
|
-
method = args.shift.to_s + '_async'
|
148
|
-
|
149
|
-
kronk.send(method, *args) do |obj, err|
|
150
|
-
raise err if err && !Kronk::Cmd::RESCUABLE.find{|eclass| eclass === err}
|
151
|
-
trigger_result kronk, err, &block
|
137
|
+
[kronk, err]
|
152
138
|
end
|
153
139
|
end
|
154
140
|
|
@@ -157,14 +143,20 @@ class Kronk
|
|
157
143
|
# Trigger a single kronk result callback.
|
158
144
|
|
159
145
|
def trigger_result kronk, err, &block
|
160
|
-
|
161
|
-
|
162
|
-
|
163
|
-
|
164
|
-
|
165
|
-
|
166
|
-
|
146
|
+
if block_given?
|
147
|
+
if block.arity > 2 || block.arity < 0
|
148
|
+
block.call kronk, err, @mutex
|
149
|
+
else
|
150
|
+
@mutex.synchronize do
|
151
|
+
block.call kronk, err
|
152
|
+
end
|
167
153
|
end
|
154
|
+
|
155
|
+
elsif err && respond_to?(:error)
|
156
|
+
error err, kronk
|
157
|
+
|
158
|
+
elsif respond_to?(:result)
|
159
|
+
result kronk
|
168
160
|
end
|
169
161
|
end
|
170
162
|
|
@@ -13,18 +13,21 @@ class Kronk
|
|
13
13
|
# * Percentage of requests within a certain time
|
14
14
|
# * Slowest endpoints
|
15
15
|
|
16
|
-
class Player::Benchmark < Player
|
16
|
+
class Player::Benchmark < Player
|
17
17
|
|
18
18
|
class ResultSet
|
19
19
|
|
20
|
+
attr_accessor :total_time
|
21
|
+
|
20
22
|
attr_reader :byterate, :count, :fastest, :precision,
|
21
|
-
:slowest, :total_bytes
|
23
|
+
:slowest, :total_bytes, :err_count
|
22
24
|
|
23
|
-
def initialize
|
24
|
-
@times
|
25
|
-
@count
|
26
|
-
@r5XX
|
27
|
-
@r4XX
|
25
|
+
def initialize
|
26
|
+
@times = Hash.new(0)
|
27
|
+
@count = 0
|
28
|
+
@r5XX = 0
|
29
|
+
@r4XX = 0
|
30
|
+
@err_count = 0
|
28
31
|
|
29
32
|
@precision = 3
|
30
33
|
|
@@ -36,7 +39,6 @@ class Kronk
|
|
36
39
|
@total_bytes = 0
|
37
40
|
@byterate = 0
|
38
41
|
|
39
|
-
@start_time = start_time
|
40
42
|
@total_time = 0
|
41
43
|
end
|
42
44
|
|
@@ -58,8 +60,6 @@ class Kronk
|
|
58
60
|
@total_bytes += resp.raw.bytes.count
|
59
61
|
|
60
62
|
@byterate = (@byterate * (@count-1) + resp.byterate) / @count
|
61
|
-
|
62
|
-
@total_time = (Time.now - @start_time).to_f
|
63
63
|
end
|
64
64
|
|
65
65
|
|
@@ -147,9 +147,11 @@ class Kronk
|
|
147
147
|
|
148
148
|
def to_s
|
149
149
|
out = <<-STR
|
150
|
+
|
150
151
|
Completed: #{@count}
|
151
152
|
400s: #{@r4XX}
|
152
153
|
500s: #{@r5XX}
|
154
|
+
Errors: #{@err_count}
|
153
155
|
Req/Sec: #{self.req_per_sec}
|
154
156
|
Total Bytes: #{@total_bytes}
|
155
157
|
Transfer Rate: #{self.transfer_rate} Kbytes/sec
|
@@ -175,7 +177,7 @@ Request Percentages (ms)
|
|
175
177
|
|
176
178
|
unless slowest_reqs.empty?
|
177
179
|
out << "
|
178
|
-
Avg. Slowest Requests (ms,
|
180
|
+
Avg. Slowest Requests (ms, count)
|
179
181
|
#{slowest_reqs.map{|arr| " #{arr[1].inspect} #{arr[0]}"}.join "\n" }"
|
180
182
|
end
|
181
183
|
|
@@ -184,44 +186,39 @@ Avg. Slowest Requests (ms, #)
|
|
184
186
|
end
|
185
187
|
|
186
188
|
|
187
|
-
def initialize player
|
188
|
-
@player = player
|
189
|
-
@results = []
|
190
|
-
@count = 0
|
191
|
-
|
192
|
-
@div = nil
|
193
|
-
@div = @player.number / 10 if @player.number
|
194
|
-
@div = 100 if !@div || @div < 10
|
195
|
-
end
|
196
|
-
|
197
|
-
|
198
189
|
def start
|
190
|
+
@res_count = 0
|
191
|
+
@results = []
|
192
|
+
@div = @number / 10 if @number
|
193
|
+
@div = 100 if !@div || @div < 10
|
199
194
|
puts "Benchmarking..."
|
200
|
-
super
|
201
195
|
end
|
202
196
|
|
203
197
|
|
204
|
-
def result kronk
|
205
|
-
|
206
|
-
|
207
|
-
@
|
208
|
-
@results[i] ||= ResultSet.new(@start_time)
|
198
|
+
def result kronk
|
199
|
+
@mutex.synchronize do
|
200
|
+
kronk.responses.each_with_index do |resp, i|
|
201
|
+
@results[i] ||= ResultSet.new
|
209
202
|
@results[i].add_result resp
|
210
|
-
|
211
|
-
puts "#{@count} requests" if @count % @div == 0
|
212
203
|
end
|
204
|
+
|
205
|
+
@res_count += 1
|
206
|
+
puts "#{@res_count} requests" if @res_count % @div == 0
|
213
207
|
end
|
214
208
|
end
|
215
209
|
|
216
210
|
|
217
|
-
def error err, kronk
|
218
|
-
mutex.synchronize do
|
219
|
-
@
|
211
|
+
def error err, kronk
|
212
|
+
@mutex.synchronize do
|
213
|
+
@res_count += 1
|
214
|
+
@results.each do |res|
|
215
|
+
res.err_count += 1
|
216
|
+
end
|
220
217
|
end
|
221
218
|
end
|
222
219
|
|
223
220
|
|
224
|
-
def
|
221
|
+
def complete
|
225
222
|
puts "Finished!"
|
226
223
|
|
227
224
|
render_head
|
@@ -232,6 +229,8 @@ Avg. Slowest Requests (ms, #)
|
|
232
229
|
|
233
230
|
|
234
231
|
def render_body
|
232
|
+
@results.each{|res| res.total_time = @stop_time - @start_time }
|
233
|
+
|
235
234
|
if @results.length > 1
|
236
235
|
puts Diff.new(@results[0].to_s, @results[1].to_s).formatted
|
237
236
|
else
|
@@ -245,7 +244,7 @@ Avg. Slowest Requests (ms, #)
|
|
245
244
|
|
246
245
|
Benchmark Time: #{(Time.now - @start_time).to_f} sec
|
247
246
|
Number of Requests: #{@count}
|
248
|
-
Concurrency: #{@
|
247
|
+
Concurrency: #{@qps ? "#{@qps} qps" : @concurrency}
|
249
248
|
STR
|
250
249
|
end
|
251
250
|
end
|