herokubench 0.0.7
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.
- checksums.yaml +15 -0
- data/README.md +89 -0
- data/bin/hb +10 -0
- data/lib/herokubench.rb +2 -0
- data/lib/herokubench/bencher.rb +13 -0
- data/lib/herokubench/cli.rb +286 -0
- data/lib/herokubench/version.rb +5 -0
- metadata +102 -0
checksums.yaml
ADDED
@@ -0,0 +1,15 @@
|
|
1
|
+
---
|
2
|
+
!binary "U0hBMQ==":
|
3
|
+
metadata.gz: !binary |-
|
4
|
+
Y2I3MWIyOTY5ZjYwMTNiYTk0MjJmOTBhNGFmM2ZiYTRiMWRhZjcxZg==
|
5
|
+
data.tar.gz: !binary |-
|
6
|
+
OWNiY2M4NWU2MmRlZDMzM2VjYWY3ZjE4NDE3MjgxNzhiMDk2ODhlNg==
|
7
|
+
!binary "U0hBNTEy":
|
8
|
+
metadata.gz: !binary |-
|
9
|
+
NzRiNTIwNTdhYjM3YWFhYmY4MjA0M2Y3MWFmNzkxYzkyODlkN2FkN2M3M2Y4
|
10
|
+
ZTIyZTY5YTBjZTNlY2Y1NWVhZDBhMDllY2M1MGI2MWRjMGY1MmMyMjk4YzBh
|
11
|
+
NjliZjU0NmVhNDg1NDhkODNiZDcyZmU5Njk0NzA2ZDFkOWNkNDA=
|
12
|
+
data.tar.gz: !binary |-
|
13
|
+
NTJmNDc4NDU2Y2YxMjJiNGExMTAwNWRiNmIxYjExMjI1YWViM2UzZDM4NTk0
|
14
|
+
ZWI1ZjIzMGU2NzkxNGM2NTAyOWFmZTUxNmQ5ZjYzNmNlN2M5OTg3ZjIyOTQ5
|
15
|
+
NjhkYzhlZTVkMTZlYTY3Mzc5YzI0NjYxYzM5ODI1YWMxNWYzNzc=
|
data/README.md
ADDED
@@ -0,0 +1,89 @@
|
|
1
|
+
# Heroku Bench
|
2
|
+
|
3
|
+
A build server in the cloud, heavily inspired by Vulcan.
|
4
|
+
|
5
|
+
## Install
|
6
|
+
|
7
|
+
$ gem install herokubench
|
8
|
+
|
9
|
+
## Usage
|
10
|
+
|
11
|
+
$ hb help
|
12
|
+
ommands:
|
13
|
+
hb ab URL # Run apache-bench, using a single, one-off Heroku dyno
|
14
|
+
hb create APP_NAME # Create your personal bench-server on Heroku
|
15
|
+
hb help [COMMAND] # Describe available commands or one specific command
|
16
|
+
hb multi URL # Run apache-bench, using multiple one-off dynos
|
17
|
+
|
18
|
+
Options:
|
19
|
+
[--verbose]
|
20
|
+
|
21
|
+
|
22
|
+
|
23
|
+
## Examples
|
24
|
+
|
25
|
+
### Create a Bench Server
|
26
|
+
$ hb create hbench-david
|
27
|
+
Creating hbench-david... done, stack is cedar
|
28
|
+
http://hbench-david.herokuapp.com/ | git@heroku.com:hbench-david.git
|
29
|
+
...
|
30
|
+
|
31
|
+
### Bench
|
32
|
+
|
33
|
+
$ hb http://nodejssimple.herokuapp.com/
|
34
|
+
Running one-off dyno, please be patient
|
35
|
+
Running `ab -c 1000 -n 10000 http://nodejssimple.herokuapp.com/` attached to terminal... up, run.4045
|
36
|
+
This is ApacheBench, Version 2.3 <$Revision: 1430300 $>
|
37
|
+
Copyright 1996 Adam Twiss, Zeus Technology Ltd, http://www.zeustech.net/
|
38
|
+
Licensed to The Apache Software Foundation, http://www.apache.org/
|
39
|
+
|
40
|
+
Benchmarking nodejssimple.herokuapp.com (be patient)
|
41
|
+
Completed 1000 requests
|
42
|
+
Completed 2000 requests
|
43
|
+
Completed 3000 requests
|
44
|
+
Completed 4000 requests
|
45
|
+
Completed 5000 requests
|
46
|
+
Completed 6000 requests
|
47
|
+
Completed 7000 requests
|
48
|
+
Completed 8000 requests
|
49
|
+
Completed 9000 requests
|
50
|
+
Completed 10000 requests
|
51
|
+
Finished 10000 requests
|
52
|
+
|
53
|
+
|
54
|
+
Server Software:
|
55
|
+
Server Hostname: nodejssimple.herokuapp.com
|
56
|
+
Server Port: 80
|
57
|
+
|
58
|
+
Document Path: /
|
59
|
+
Document Length: 12 bytes
|
60
|
+
|
61
|
+
Concurrency Level: 1000
|
62
|
+
Time taken for tests: 9.687 seconds
|
63
|
+
Complete requests: 10000
|
64
|
+
Failed requests: 0
|
65
|
+
Write errors: 0
|
66
|
+
Total transferred: 1322840 bytes
|
67
|
+
HTML transferred: 120000 bytes
|
68
|
+
Requests per second: 1032.32 [#/sec] (mean)
|
69
|
+
Time per request: 968.692 [ms] (mean)
|
70
|
+
Time per request: 0.969 [ms] (mean, across all concurrent requests)
|
71
|
+
Transfer rate: 133.36 [Kbytes/sec] received
|
72
|
+
|
73
|
+
Connection Times (ms)
|
74
|
+
min mean[+/-sd] median max
|
75
|
+
Connect: 1 8 12.8 3 70
|
76
|
+
Processing: 75 513 742.4 297 5077
|
77
|
+
Waiting: 75 512 742.5 296 5077
|
78
|
+
Total: 121 520 743.3 301 5087
|
79
|
+
|
80
|
+
Percentage of the requests served within a certain time (ms)
|
81
|
+
50% 301
|
82
|
+
66% 373
|
83
|
+
75% 403
|
84
|
+
80% 566
|
85
|
+
90% 889
|
86
|
+
95% 1805
|
87
|
+
98% 3967
|
88
|
+
99% 4041
|
89
|
+
100% 5087 (longest request)
|
data/bin/hb
ADDED
data/lib/herokubench.rb
ADDED
@@ -0,0 +1,13 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
require "heroku/command"
|
4
|
+
require "heroku/command/base"
|
5
|
+
require "heroku/command/help"
|
6
|
+
require "heroku/command/apps"
|
7
|
+
require "heroku/cli"
|
8
|
+
require "heroku/plugin"
|
9
|
+
|
10
|
+
Heroku.user_agent = "heroku-gem/#{Heroku::VERSION} (#{RUBY_PLATFORM}) ruby/#{RUBY_VERSION}"
|
11
|
+
Heroku::Command.load
|
12
|
+
Heroku::Command.run("run", ARGV)
|
13
|
+
|
@@ -0,0 +1,286 @@
|
|
1
|
+
require "digest/sha1"
|
2
|
+
require "heroku/auth"
|
3
|
+
require "heroku/command"
|
4
|
+
require "heroku/command/base"
|
5
|
+
require "heroku/command/help"
|
6
|
+
require "heroku/command/apps"
|
7
|
+
require "heroku/cli"
|
8
|
+
require "heroku/plugin"
|
9
|
+
require "thor"
|
10
|
+
require "tmpdir"
|
11
|
+
require "uri"
|
12
|
+
require "herokubench"
|
13
|
+
require "yaml"
|
14
|
+
require "pathname"
|
15
|
+
require "stringio"
|
16
|
+
require 'tempfile'
|
17
|
+
require 'ruby-progressbar'
|
18
|
+
|
19
|
+
|
20
|
+
# This class is based upon Vulcan, and copies heavily.
|
21
|
+
|
22
|
+
class HerokuBench::CLI < Thor
|
23
|
+
class_option "verbose", :type => :boolean
|
24
|
+
check_unknown_options! :except => [:ab, :multi]
|
25
|
+
default_task :ab
|
26
|
+
@@result_type = {
|
27
|
+
:connection_times=>/(.+):\s+\s+([\d|\.]+)\s+([\d|\.]+)\s+([\d|\.]+)\s+([\d|\.]+)\s+([\d|\.]+)/,
|
28
|
+
:generic_result=> /^([\w\s]+):\s*([\d|\.]+)/,
|
29
|
+
:response_time_cdf=>/(\d+%)\s+(\d+)/
|
30
|
+
}
|
31
|
+
@@summable_fields = ["Complete requests","Failed requests", "Write errors"]
|
32
|
+
@@medianable_fields = ["Connect", "Processing", "Waiting", "Total"]
|
33
|
+
|
34
|
+
class_options["verbose"] = false if class_options["verbose"].nil?
|
35
|
+
Heroku.user_agent = "heroku-gem/#{Heroku::VERSION} (#{RUBY_PLATFORM}) ruby/#{RUBY_VERSION}"
|
36
|
+
Heroku::Command.load
|
37
|
+
|
38
|
+
|
39
|
+
desc "create APP_NAME", "Create your personal bench-server on Heroku"
|
40
|
+
def create(name="")
|
41
|
+
Dir.mktmpdir do |dir|
|
42
|
+
Dir.chdir(dir) do
|
43
|
+
|
44
|
+
args = ["#{name}", "-s","cedar", "--buildpack","https://github.com/wcdolphin/heroku-buildpack-apache.git"]
|
45
|
+
args.delete("")
|
46
|
+
result = capture { Heroku::Command.run("create", args) }
|
47
|
+
name = /\s(.+)\.\.\./.match(result).captures[0]
|
48
|
+
puts "Created your personal benchserver: #{name}"
|
49
|
+
end
|
50
|
+
end
|
51
|
+
write_config :app => name, :host => "#{name}.herokuapp.com"
|
52
|
+
update
|
53
|
+
end
|
54
|
+
|
55
|
+
|
56
|
+
desc "ab [options] [http[s]://]hostname[:port]/path", "Run apache-bench using a single one-off dyno"
|
57
|
+
long_desc <<-LONGDESC
|
58
|
+
'hb ab' will run apache-bench, using a one-off dyno on Heroku in order
|
59
|
+
to best benchmark the performance of your webservice.
|
60
|
+
|
61
|
+
For more information, run `hb ab help`
|
62
|
+
|
63
|
+
> $ hb ab -c 100 -n 1000 http://www.google.com
|
64
|
+
LONGDESC
|
65
|
+
|
66
|
+
def ab(*args)
|
67
|
+
error "no app yet, please create first" unless config[:app]
|
68
|
+
puts "Running one-off dyno, please be patient"
|
69
|
+
Heroku::Command.run("run", ["ab #{args.join(' ')}", "--app", "#{config[:app]}"])
|
70
|
+
end
|
71
|
+
|
72
|
+
|
73
|
+
desc "multi NUMBER [options] [http[s]://]hostname[:port]/path", "Run apache-bench, using multiple one-off dynos"
|
74
|
+
long_desc <<-LONGDESC
|
75
|
+
'hb multi' will run apache-bench, using multiple one-off dynos in order
|
76
|
+
to incrase the throughput of your benchmark.
|
77
|
+
|
78
|
+
The arguments are identical to that of 'hb ab' with the addition
|
79
|
+
of the 'NUMBER' argument, representing the number of one-off dynos
|
80
|
+
to execute your benchmark on.
|
81
|
+
|
82
|
+
> $ hb multi 5 http://www.google.com
|
83
|
+
LONGDESC
|
84
|
+
def multi(dynos, *args)
|
85
|
+
error "no app yet, create first" unless config[:app]
|
86
|
+
error "Number of dynos must be an integer greater than 1" unless dynos.to_i >= 1
|
87
|
+
|
88
|
+
bencher_path = File.expand_path("../bencher.rb",__FILE__)
|
89
|
+
|
90
|
+
dynos = dynos.to_i
|
91
|
+
outputs = []
|
92
|
+
pid_map = {}
|
93
|
+
results = []
|
94
|
+
n = 0
|
95
|
+
|
96
|
+
ab_command = "ab #{args.join(' ')}"
|
97
|
+
|
98
|
+
p_bar = ProgressBar.new('Setup', dynos)
|
99
|
+
|
100
|
+
until n == dynos do
|
101
|
+
p_bar.inc
|
102
|
+
outputs.push Tempfile.new("hbench_out_#{n}")
|
103
|
+
pid = spawn( "ruby #{bencher_path} \"#{ab_command} \" --app #{config[:app]}", :out=>outputs[n].path)
|
104
|
+
pid_map[pid] = n
|
105
|
+
n += 1
|
106
|
+
end
|
107
|
+
|
108
|
+
p_bar.finish
|
109
|
+
p_bar = ProgressBar.new('Benching', dynos)
|
110
|
+
|
111
|
+
until n == 0 do
|
112
|
+
output = outputs[pid_map[Process.wait]]
|
113
|
+
last_output = output.read if n ==1
|
114
|
+
p_bar.inc
|
115
|
+
results.push get_result_hash output
|
116
|
+
output.unlink
|
117
|
+
n -= 1
|
118
|
+
end
|
119
|
+
|
120
|
+
p_bar.finish
|
121
|
+
|
122
|
+
if results.last.length ==3
|
123
|
+
summarize results
|
124
|
+
else
|
125
|
+
error last_output
|
126
|
+
end
|
127
|
+
end
|
128
|
+
|
129
|
+
private
|
130
|
+
|
131
|
+
# Attemptes to parse a value as a Float or integer, defaulting to the original
|
132
|
+
# string if unsuccesful.
|
133
|
+
def parse(v)
|
134
|
+
((float = Float(v)) && (float % 1.0 == 0) ? float.to_i : float) rescue v
|
135
|
+
end
|
136
|
+
|
137
|
+
# pretty much the opposite of parse. Returns a string of the best way
|
138
|
+
# to represent a float, int or string value
|
139
|
+
def unparse(v)
|
140
|
+
((float = v.round(1)) && (float % 1.0 == 0) ? float.to_i.to_s : float.to_s) rescue v.to_s
|
141
|
+
end
|
142
|
+
|
143
|
+
def summarize(results)
|
144
|
+
summary = {}
|
145
|
+
|
146
|
+
results.each do |result|
|
147
|
+
result.each do |type, hash|
|
148
|
+
summary[type] = {} if summary[type].nil?
|
149
|
+
hash.each do |k,v|
|
150
|
+
puts k if v.nil?
|
151
|
+
summary[type][k] = [0.0] * v.length if summary[type][k].nil?
|
152
|
+
v.each_index do |i|
|
153
|
+
if not @@summable_fields.index(k).nil?
|
154
|
+
summary[type][k][i] += v[i]
|
155
|
+
elsif not @@medianable_fields.index(k).nil?
|
156
|
+
summary[type][k][i] += v[i] / results.length.to_f
|
157
|
+
else
|
158
|
+
summary[type][k][i] = v[i]
|
159
|
+
end
|
160
|
+
end
|
161
|
+
end
|
162
|
+
end
|
163
|
+
end
|
164
|
+
|
165
|
+
say "\tCumulative results"
|
166
|
+
say ""
|
167
|
+
summary[:generic_result].each{|k,v| say format(k+":",v, 25)}
|
168
|
+
|
169
|
+
say ""
|
170
|
+
say "\t Connection Times (ms)"
|
171
|
+
say format("",["min", "mean", "[+/-sd]" ,"median","max"],15)
|
172
|
+
summary[:connection_times].each{|k,v| say format(k+":",v, 15)}
|
173
|
+
|
174
|
+
say ""
|
175
|
+
say "\t Percentage of the requests served within a certain time (ms)"
|
176
|
+
say "\t averaged across dynos"
|
177
|
+
summary[:response_time_cdf].each{|k,v| say format(k+"",v, 15)}
|
178
|
+
end
|
179
|
+
|
180
|
+
def format(k,v, pad)
|
181
|
+
"#{fill(k,pad)}#{v.map{|val| fill(unparse val)}.join('')}\r\n"
|
182
|
+
end
|
183
|
+
|
184
|
+
def fill(str, length=12)
|
185
|
+
"#{str}#{" " * (length - str.length)}"
|
186
|
+
end
|
187
|
+
|
188
|
+
def get_result_hash(f)
|
189
|
+
result_hash = {}
|
190
|
+
f.each_line do |line|
|
191
|
+
@@result_type.each do |k,v|
|
192
|
+
group = line.scan(v)
|
193
|
+
if not group.nil? and group.length.equal? 1
|
194
|
+
capture = group[0].map {|v| parse v} #convert to float/int/etc
|
195
|
+
result_hash[k] = {} unless result_hash.has_key?(k)
|
196
|
+
res_key = capture[0]
|
197
|
+
res_values = capture.slice(1, capture.length)
|
198
|
+
result_hash[k][res_key] = res_values
|
199
|
+
end
|
200
|
+
end
|
201
|
+
end
|
202
|
+
result_hash
|
203
|
+
end
|
204
|
+
|
205
|
+
def update
|
206
|
+
error "no app yet, create first" unless config[:app]
|
207
|
+
|
208
|
+
Dir.mktmpdir do |dir|
|
209
|
+
Dir.chdir(dir) do
|
210
|
+
system "git init -q"
|
211
|
+
system "git remote add origin git@github.com:wcdolphin/heroku-benchserver.git"
|
212
|
+
system "git remote add heroku git@#{heroku_git_domain}:#{config[:app]}.git"
|
213
|
+
pullres = capture { system "git pull --quiet origin master"}
|
214
|
+
pushres = capture { system "git push heroku master --quiet"}
|
215
|
+
end
|
216
|
+
end
|
217
|
+
end
|
218
|
+
|
219
|
+
def capture
|
220
|
+
results = $stdout = StringIO.new
|
221
|
+
yield
|
222
|
+
$stdout = STDOUT
|
223
|
+
results.close_write
|
224
|
+
results.rewind
|
225
|
+
return results.read
|
226
|
+
end
|
227
|
+
|
228
|
+
|
229
|
+
|
230
|
+
#Yeah, we are windows compatible. Because you should be too.
|
231
|
+
def null_dev
|
232
|
+
return test(?e, '/dev/null') ? '/dev/null' : 'NUL:'
|
233
|
+
end
|
234
|
+
|
235
|
+
def action(message)
|
236
|
+
print "#{message}... "
|
237
|
+
yield
|
238
|
+
puts "done"
|
239
|
+
end
|
240
|
+
|
241
|
+
def heroku(command)
|
242
|
+
%x{ env BUNDLE_GEMFILE= heroku #{command} 2>&1 }
|
243
|
+
end
|
244
|
+
|
245
|
+
def config_file
|
246
|
+
File.expand_path("~/.herokubench")
|
247
|
+
end
|
248
|
+
|
249
|
+
def config
|
250
|
+
read_config
|
251
|
+
end
|
252
|
+
|
253
|
+
def read_config
|
254
|
+
return {} unless File.exists?(config_file)
|
255
|
+
config = YAML.load_file(config_file)
|
256
|
+
config.is_a?(Hash) ? config : {}
|
257
|
+
end
|
258
|
+
|
259
|
+
def write_config(config)
|
260
|
+
full_config = read_config.merge(config)
|
261
|
+
File.open(config_file, "w") do |file|
|
262
|
+
file.puts YAML.dump(full_config)
|
263
|
+
end
|
264
|
+
end
|
265
|
+
|
266
|
+
def error(message)
|
267
|
+
puts "!! #{message}"
|
268
|
+
exit 1
|
269
|
+
end
|
270
|
+
|
271
|
+
def server_path
|
272
|
+
File.expand_path("../../../server", __FILE__)
|
273
|
+
end
|
274
|
+
|
275
|
+
#
|
276
|
+
# heroku_git_domain checks to see if the heroku-accounts plugin is present,
|
277
|
+
# and if so, it will set the domain to the one that matches the credentials
|
278
|
+
# for the currently set account
|
279
|
+
#
|
280
|
+
def heroku_git_domain
|
281
|
+
suffix = %x{ git config heroku.account }
|
282
|
+
suffix = "com" if suffix.nil? or suffix.strip == ""
|
283
|
+
"heroku.#{suffix.strip}"
|
284
|
+
end
|
285
|
+
|
286
|
+
end
|
metadata
ADDED
@@ -0,0 +1,102 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: herokubench
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.7
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Cory Dolphin
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2013-06-25 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: heroku
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - ! '>='
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: 2.26.0
|
20
|
+
- - <
|
21
|
+
- !ruby/object:Gem::Version
|
22
|
+
version: '3.0'
|
23
|
+
type: :runtime
|
24
|
+
prerelease: false
|
25
|
+
version_requirements: !ruby/object:Gem::Requirement
|
26
|
+
requirements:
|
27
|
+
- - ! '>='
|
28
|
+
- !ruby/object:Gem::Version
|
29
|
+
version: 2.26.0
|
30
|
+
- - <
|
31
|
+
- !ruby/object:Gem::Version
|
32
|
+
version: '3.0'
|
33
|
+
- !ruby/object:Gem::Dependency
|
34
|
+
name: thor
|
35
|
+
requirement: !ruby/object:Gem::Requirement
|
36
|
+
requirements:
|
37
|
+
- - ~>
|
38
|
+
- !ruby/object:Gem::Version
|
39
|
+
version: 0.18.1
|
40
|
+
type: :runtime
|
41
|
+
prerelease: false
|
42
|
+
version_requirements: !ruby/object:Gem::Requirement
|
43
|
+
requirements:
|
44
|
+
- - ~>
|
45
|
+
- !ruby/object:Gem::Version
|
46
|
+
version: 0.18.1
|
47
|
+
- !ruby/object:Gem::Dependency
|
48
|
+
name: ruby-progressbar
|
49
|
+
requirement: !ruby/object:Gem::Requirement
|
50
|
+
requirements:
|
51
|
+
- - ! '>='
|
52
|
+
- !ruby/object:Gem::Version
|
53
|
+
version: 1.1.1
|
54
|
+
type: :runtime
|
55
|
+
prerelease: false
|
56
|
+
version_requirements: !ruby/object:Gem::Requirement
|
57
|
+
requirements:
|
58
|
+
- - ! '>='
|
59
|
+
- !ruby/object:Gem::Version
|
60
|
+
version: 1.1.1
|
61
|
+
description: ! " Make it rain on the cloud.\n\n herokubench, or hb for short,
|
62
|
+
is a simple gem which eanbles you to easily load test websites,\n using a server
|
63
|
+
hosted by Heroku (on AWS). The gem manages deploying\n an app with no running
|
64
|
+
dynos (free), and abuses the concept of one-off\n jobs to run the Apache Benchmark,
|
65
|
+
ab.\n\n Confused? Checkout `hb help`\n"
|
66
|
+
email: wcdolphin@gmail.com
|
67
|
+
executables:
|
68
|
+
- hb
|
69
|
+
extensions: []
|
70
|
+
extra_rdoc_files: []
|
71
|
+
files:
|
72
|
+
- bin/hb
|
73
|
+
- lib/herokubench/bencher.rb
|
74
|
+
- lib/herokubench/cli.rb
|
75
|
+
- lib/herokubench/version.rb
|
76
|
+
- lib/herokubench.rb
|
77
|
+
- README.md
|
78
|
+
homepage: https://github.com/wcdolphin/heroku-bench
|
79
|
+
licenses: []
|
80
|
+
metadata: {}
|
81
|
+
post_install_message: Please run 'hbench create' to create your bench-server.
|
82
|
+
rdoc_options: []
|
83
|
+
require_paths:
|
84
|
+
- lib
|
85
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
86
|
+
requirements:
|
87
|
+
- - ! '>='
|
88
|
+
- !ruby/object:Gem::Version
|
89
|
+
version: '0'
|
90
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
91
|
+
requirements:
|
92
|
+
- - ! '>='
|
93
|
+
- !ruby/object:Gem::Version
|
94
|
+
version: '0'
|
95
|
+
requirements: []
|
96
|
+
rubyforge_project:
|
97
|
+
rubygems_version: 2.0.3
|
98
|
+
signing_key:
|
99
|
+
specification_version: 4
|
100
|
+
summary: A gem to help load testing web applications deployed on AWS or Heroku, using
|
101
|
+
apache-bench
|
102
|
+
test_files: []
|