benchtool 0.1.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/.gitignore +20 -0
- data/Gemfile +3 -0
- data/LICENSE +22 -0
- data/README.txt +67 -0
- data/Rakefile +2 -0
- data/benchtool.gemspec +22 -0
- data/bin/benchtool +120 -0
- data/lib/benchtool.rb +17 -0
- data/lib/benchtool/ab-cmd-builder.rb +36 -0
- data/lib/benchtool/app-config.rb +45 -0
- data/lib/benchtool/configuration.yml.base +28 -0
- data/lib/benchtool/curl-cmd-builder.rb +30 -0
- data/lib/benchtool/dispatcher.rb +118 -0
- data/lib/benchtool/extensions.rb +4 -0
- data/lib/benchtool/helpers.rb +32 -0
- data/lib/benchtool/version.rb +3 -0
- data/lib/deep-symbolizable/deep-symbolize.rb +62 -0
- metadata +111 -0
data/.gitignore
ADDED
data/Gemfile
ADDED
data/LICENSE
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
Copyright (c) 2012 Brad Landers
|
2
|
+
|
3
|
+
MIT License
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
6
|
+
a copy of this software and associated documentation files (the
|
7
|
+
"Software"), to deal in the Software without restriction, including
|
8
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
9
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
10
|
+
permit persons to whom the Software is furnished to do so, subject to
|
11
|
+
the following conditions:
|
12
|
+
|
13
|
+
The above copyright notice and this permission notice shall be
|
14
|
+
included in all copies or substantial portions of the Software.
|
15
|
+
|
16
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
17
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
18
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
19
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
20
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
21
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
22
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.txt
ADDED
@@ -0,0 +1,67 @@
|
|
1
|
+
INTRODUCTION
|
2
|
+
|
3
|
+
Benchtool provides a method to store a list of 'targets', which you can then
|
4
|
+
benchmark using the Apache Bench web server benchmarking tool.
|
5
|
+
|
6
|
+
This tool expects a configuration file at config/configuration.yml. If not
|
7
|
+
found, one will be created for you. This tool also outputs Apache Bench data
|
8
|
+
to a gnuplot file in a directory named 'output'. If it is not present, it will
|
9
|
+
be created. Both of these can be overriden using options.
|
10
|
+
|
11
|
+
PREREQUISITES
|
12
|
+
|
13
|
+
Because benchtool is a simple wrapper script, you must install Apache Bench
|
14
|
+
and Curl prior to running this utility. You can check to see if you have
|
15
|
+
these tools installed by executing the following at a shell prompt:
|
16
|
+
|
17
|
+
which ab
|
18
|
+
which curl
|
19
|
+
|
20
|
+
These commands should return paths to the binaries for each. If nothing is
|
21
|
+
returned, you must install the utility using your preferred package manager.
|
22
|
+
|
23
|
+
BASIC USAGE
|
24
|
+
|
25
|
+
benchtool [options] <command>
|
26
|
+
|
27
|
+
options - optional switches passed to the utility (see OPTIONS)
|
28
|
+
|
29
|
+
command - required command parameter tells the utility what action to take
|
30
|
+
|
31
|
+
See EXAMPLES for more details.
|
32
|
+
|
33
|
+
COMMANDS
|
34
|
+
|
35
|
+
benchmark Execute Apache Benchmark against a target. Builds and executes an
|
36
|
+
Apache Bench command, specifying cookies and headers from the
|
37
|
+
configuration file.
|
38
|
+
test Test a target to determine if it is valid and responding. Builds
|
39
|
+
and executes a Curl command, specifying cookies and headers from
|
40
|
+
the configuration file.
|
41
|
+
|
42
|
+
OPTIONS
|
43
|
+
|
44
|
+
-c, --concurrency [INT] Apache Bench concurrency level (overrides config).
|
45
|
+
-o, --output-dir [PATH] Output directory for Apache Bench gnuplot files.
|
46
|
+
-n, --number [INT] Apache Bench number of requests (overrides config).
|
47
|
+
--no-plotfile Apache Bench will not write a gnuplot file.
|
48
|
+
-p, --print Print the command and exit; does not execute.
|
49
|
+
-t, --target [INT] Specify the index (1-based) of the target.
|
50
|
+
|
51
|
+
EXAMPLES
|
52
|
+
|
53
|
+
benchtool benchmark - Displays a menu list of targets and executes
|
54
|
+
Apache Bench against the selected target.
|
55
|
+
|
56
|
+
benchtool test - Displays a menu list of targets and executes
|
57
|
+
a brief test showing the first 30 lines of
|
58
|
+
the HTTP response.
|
59
|
+
|
60
|
+
benchtool -c 100 benchmark - Override the configuration.yml concurrency
|
61
|
+
setting for Apache Bench.
|
62
|
+
|
63
|
+
benchtool -p benchmark - Prints the resulting bash shell command, rather
|
64
|
+
than executing. Also works for the test command.
|
65
|
+
|
66
|
+
Author: Brad Landers <brad@bradlanders.com>
|
67
|
+
Source: http://github.com/bradland/benchtool/
|
data/Rakefile
ADDED
data/benchtool.gemspec
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
require File.expand_path('../lib/benchtool/version', __FILE__)
|
3
|
+
|
4
|
+
Gem::Specification.new do |gem|
|
5
|
+
gem.authors = ["Brad Landers"]
|
6
|
+
gem.email = ["brad@bradlanders.com"]
|
7
|
+
gem.description = %q{A simple wrapper tool for Apache Bench.}
|
8
|
+
gem.summary = %q{A simple wrapper tool for Apache Bench.}
|
9
|
+
gem.homepage = ""
|
10
|
+
|
11
|
+
gem.files = `git ls-files`.split($\)
|
12
|
+
gem.executables = gem.files.grep(%r{^bin/}).map{ |f| File.basename(f) }
|
13
|
+
gem.test_files = gem.files.grep(%r{^(test|spec|features)/})
|
14
|
+
gem.name = "benchtool"
|
15
|
+
gem.require_paths = ["lib"]
|
16
|
+
gem.version = BenchTool::VERSION
|
17
|
+
|
18
|
+
gem.add_dependency "highline"
|
19
|
+
gem.add_dependency "open4"
|
20
|
+
|
21
|
+
gem.add_development_dependency "awesome_print"
|
22
|
+
end
|
data/bin/benchtool
ADDED
@@ -0,0 +1,120 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
$:.unshift File.join(File.dirname(__FILE__), '..', 'lib')
|
4
|
+
require 'benchtool'
|
5
|
+
require 'optparse'
|
6
|
+
|
7
|
+
banner = %{
|
8
|
+
INTRODUCTION
|
9
|
+
|
10
|
+
Benchtool provides a method to store a list of 'targets', which you can then
|
11
|
+
benchmark using the Apache Bench web server benchmarking tool.
|
12
|
+
|
13
|
+
This tool expects a configuration file at config/configuration.yml. If not
|
14
|
+
found, one will be created for you. This tool also outputs Apache Bench data
|
15
|
+
to a gnuplot file in a directory named 'output'. If it is not present, it will
|
16
|
+
be created. Both of these can be overriden using options.
|
17
|
+
|
18
|
+
PREREQUISITES
|
19
|
+
|
20
|
+
Because benchtool is a simple wrapper script, you must install Apache Bench
|
21
|
+
and Curl prior to running this utility. You can check to see if you have
|
22
|
+
these tools installed by executing the following at a shell prompt:
|
23
|
+
|
24
|
+
which ab
|
25
|
+
which curl
|
26
|
+
|
27
|
+
These commands should return paths to the binaries for each. If nothing is
|
28
|
+
returned, you must install the utility using your preferred package manager.
|
29
|
+
|
30
|
+
BASIC USAGE
|
31
|
+
|
32
|
+
benchtool [options] <command>
|
33
|
+
|
34
|
+
options - optional switches passed to the utility (see OPTIONS)
|
35
|
+
|
36
|
+
command - required command parameter tells the utility what action to take
|
37
|
+
|
38
|
+
See EXAMPLES for more details.
|
39
|
+
|
40
|
+
COMMANDS
|
41
|
+
|
42
|
+
benchmark Execute Apache Benchmark against a target. Builds and executes an
|
43
|
+
Apache Bench command, specifying cookies and headers from the
|
44
|
+
configuration file.
|
45
|
+
test Test a target to determine if it is valid and responding. Builds
|
46
|
+
and executes a Curl command, specifying cookies and headers from
|
47
|
+
the configuration file.
|
48
|
+
|
49
|
+
OPTIONS
|
50
|
+
|
51
|
+
}
|
52
|
+
summary = []
|
53
|
+
footer = %{
|
54
|
+
EXAMPLES
|
55
|
+
|
56
|
+
benchtool benchmark - Displays a menu list of targets and executes
|
57
|
+
Apache Bench against the selected target.
|
58
|
+
|
59
|
+
benchtool test - Displays a menu list of targets and executes
|
60
|
+
a brief test showing the first 30 lines of
|
61
|
+
the HTTP response.
|
62
|
+
|
63
|
+
benchtool -c 100 benchmark - Override the configuration.yml concurrency
|
64
|
+
setting for Apache Bench.
|
65
|
+
|
66
|
+
benchtool -p benchmark - Prints the resulting bash shell command, rather
|
67
|
+
than executing. Also works for the test command.
|
68
|
+
|
69
|
+
Author: Brad Landers <brad@bradlanders.com>
|
70
|
+
Source: http://github.com/bradland/benchtool/
|
71
|
+
}
|
72
|
+
|
73
|
+
options = {}
|
74
|
+
OptionParser.new do |opts|
|
75
|
+
opts.banner = banner
|
76
|
+
|
77
|
+
opts.on('-c', '--concurrency [INT]', Integer, "Apache Bench concurrency level (overrides config).") do |concurrency|
|
78
|
+
options[:ab_concurrency] = concurrency
|
79
|
+
end
|
80
|
+
|
81
|
+
opts.on('-o', '--output-dir [PATH]', String, "Output directory for Apache Bench gnuplot files.") do |string|
|
82
|
+
options[:ab_output]
|
83
|
+
end
|
84
|
+
|
85
|
+
opts.on('-n', '--number [INT]', Integer, "Apache Bench number of requests (overrides config).") do |requests|
|
86
|
+
options[:ab_requests] = requests
|
87
|
+
end
|
88
|
+
|
89
|
+
opts.on('--no-plotfile', "Apache Bench will not write a gnuplot file.") do |boolean|
|
90
|
+
options[:no_plotfile] = boolean
|
91
|
+
end
|
92
|
+
|
93
|
+
opts.on('-p', '--print', "Print the command and exit; does not execute.") do |boolean|
|
94
|
+
options[:print_no_exec] = boolean
|
95
|
+
end
|
96
|
+
|
97
|
+
opts.on('-t', '--target [INT]', Integer, "Specify the index (1-based) of the target.") do |target_idx|
|
98
|
+
options[:target_idx] = target_idx
|
99
|
+
end
|
100
|
+
|
101
|
+
opts.summarize(summary)
|
102
|
+
end.parse!
|
103
|
+
|
104
|
+
command = ARGV[0]
|
105
|
+
|
106
|
+
case command
|
107
|
+
when nil
|
108
|
+
puts banner
|
109
|
+
puts summary
|
110
|
+
puts footer
|
111
|
+
exit 1
|
112
|
+
when "benchmark"
|
113
|
+
BenchTool::Dispatcher.new(options).benchmark
|
114
|
+
exit 0
|
115
|
+
when "test"
|
116
|
+
BenchTool::Dispatcher.new(options).test
|
117
|
+
exit 0
|
118
|
+
end
|
119
|
+
|
120
|
+
# SshForever::SecureShellForever.new(login, options).run
|
data/lib/benchtool.rb
ADDED
@@ -0,0 +1,17 @@
|
|
1
|
+
require 'deep-symbolizable/deep-symbolize'
|
2
|
+
require 'fileutils'
|
3
|
+
require 'highline/import'
|
4
|
+
require 'open4'
|
5
|
+
require 'pathname'
|
6
|
+
require 'pty'
|
7
|
+
require 'rubygems'
|
8
|
+
require 'yaml'
|
9
|
+
|
10
|
+
require 'benchtool/app-config'
|
11
|
+
require 'benchtool/ab-cmd-builder'
|
12
|
+
require 'benchtool/curl-cmd-builder'
|
13
|
+
require 'benchtool/dispatcher'
|
14
|
+
require 'benchtool/extensions'
|
15
|
+
require 'benchtool/helpers'
|
16
|
+
require 'benchtool/version'
|
17
|
+
require 'benchtool'
|
@@ -0,0 +1,36 @@
|
|
1
|
+
module BenchTool
|
2
|
+
class ABCmdBuilder
|
3
|
+
|
4
|
+
def initialize(params, options = {})
|
5
|
+
@params = params
|
6
|
+
@options = options
|
7
|
+
# Sample ab cmd
|
8
|
+
# ab -n #{requests} -c #{concurrency} -g '#{plotfile}' -C '#{cookies}' -H '#{header}' '#{url}'
|
9
|
+
@parts = {
|
10
|
+
:base => "ab ",
|
11
|
+
:requests => "-n %s ",
|
12
|
+
:concurrency => "-c %s ",
|
13
|
+
:plotfile => "-g '%s' ",
|
14
|
+
:cookies => "-C '%s' ",
|
15
|
+
:header => "-H '%s' ",
|
16
|
+
:url => "'%s'",
|
17
|
+
}
|
18
|
+
end
|
19
|
+
|
20
|
+
def to_str
|
21
|
+
cmd = ""
|
22
|
+
cmd << @parts[:base]
|
23
|
+
cmd << @parts[:requests] % @params[:requests]
|
24
|
+
cmd << @parts[:concurrency] % @params[:concurrency]
|
25
|
+
cmd << @parts[:plotfile] % @params[:plotfile] unless @options[:no_plotfile] == false
|
26
|
+
cmd << @parts[:cookies] % @params[:cookies]
|
27
|
+
unless @params[:headers].empty?
|
28
|
+
@params[:headers].each do |header|
|
29
|
+
cmd << @parts[:header] % header
|
30
|
+
end
|
31
|
+
end
|
32
|
+
cmd << @parts[:url] % @params[:url]
|
33
|
+
end
|
34
|
+
|
35
|
+
end # class ABCmdBuilder
|
36
|
+
end # module BenchTool
|
@@ -0,0 +1,45 @@
|
|
1
|
+
module BenchTool
|
2
|
+
class AppConfig
|
3
|
+
|
4
|
+
CONFIG_DIR = File.expand_path('./config')
|
5
|
+
CONFIG_FILE = 'configuration.yml'
|
6
|
+
CONFIG_PATH = File.join(CONFIG_DIR, CONFIG_FILE)
|
7
|
+
APP_CONFIG_DIR = File.expand_path(File.dirname(__FILE__))
|
8
|
+
|
9
|
+
def initialize
|
10
|
+
@options ||= fetch
|
11
|
+
end
|
12
|
+
|
13
|
+
# Return config as hash
|
14
|
+
def to_hash
|
15
|
+
@options
|
16
|
+
end
|
17
|
+
|
18
|
+
private
|
19
|
+
|
20
|
+
# Get options from configuration file
|
21
|
+
def fetch
|
22
|
+
setup unless config_exists?
|
23
|
+
console "Loading config from #{CONFIG_PATH}"
|
24
|
+
@options = YAML::load(File.open(CONFIG_PATH))
|
25
|
+
@options.deep_symbolize
|
26
|
+
end
|
27
|
+
|
28
|
+
def config_exists?
|
29
|
+
File.exists?(CONFIG_PATH)
|
30
|
+
end
|
31
|
+
|
32
|
+
def setup
|
33
|
+
FileUtils.mkdir_p(CONFIG_DIR)
|
34
|
+
FileUtils.cp(File.join(APP_CONFIG_DIR, 'configuration.yml.base'), CONFIG_PATH)
|
35
|
+
console "Default configuration was established in the cwd!"
|
36
|
+
console ""
|
37
|
+
console "NOTICE: The application will exit now. Edit the contents of the config file before proceeeding!"
|
38
|
+
console ""
|
39
|
+
console "Config file path:"
|
40
|
+
console " #{CONFIG_PATH}"
|
41
|
+
exit 0
|
42
|
+
end
|
43
|
+
|
44
|
+
end # module AppConfig
|
45
|
+
end # module BenchTool
|
@@ -0,0 +1,28 @@
|
|
1
|
+
# This is the configuration file. It is intended to be edited by hand. Examples provided.
|
2
|
+
targets:
|
3
|
+
- name: "Label for the target"
|
4
|
+
url: "http://yourdomainhere.com"
|
5
|
+
cookies: "token=value"
|
6
|
+
headers: [
|
7
|
+
"Accept:application/json, text/javascript, */*; q=0.01",
|
8
|
+
"Accept-Charset:ISO-8859-1,utf-8;q=0.7,*;q=0.3",
|
9
|
+
"Accept-Encoding:",
|
10
|
+
"Accept-Language:en-US,en;q=0.8",
|
11
|
+
"Cache-Control:max-age=0",
|
12
|
+
"Connection:keep-alive"
|
13
|
+
]
|
14
|
+
- name: "Label for the target"
|
15
|
+
url: "http://yourdomainhere.com"
|
16
|
+
cookies: "token=value"
|
17
|
+
headers: [
|
18
|
+
"Accept:text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8",
|
19
|
+
"Accept-Charset:ISO-8859-1,utf-8;q=0.7,*;q=0.3",
|
20
|
+
"Accept-Encoding:",
|
21
|
+
"Accept-Language:en-US,en;q=0.8",
|
22
|
+
"Cache-Control:max-age=0",
|
23
|
+
"Connection:keep-alive"
|
24
|
+
]
|
25
|
+
configuration:
|
26
|
+
ab_requests: 10
|
27
|
+
ab_concurrency: 1
|
28
|
+
ab_output: ./benchtool_output
|
@@ -0,0 +1,30 @@
|
|
1
|
+
module BenchTool
|
2
|
+
class CurlCmdBuilder
|
3
|
+
|
4
|
+
def initialize(params, options = {})
|
5
|
+
@params = params
|
6
|
+
@options = options
|
7
|
+
# Sample curl status cmd
|
8
|
+
# curl -IL --cookies '#{cookies}' --header '#{header}' "#{url}"
|
9
|
+
@parts = {
|
10
|
+
:base => "curl -siL ",
|
11
|
+
:cookies => "--cookie '%s' ",
|
12
|
+
:header => "--header '%s' ",
|
13
|
+
:url => "'%s'",
|
14
|
+
}
|
15
|
+
end
|
16
|
+
|
17
|
+
def to_str
|
18
|
+
cmd = ""
|
19
|
+
cmd << @parts[:base]
|
20
|
+
cmd << @parts[:cookies] % @params[:cookies]
|
21
|
+
unless @params[:headers].empty?
|
22
|
+
@params[:headers].each do |header|
|
23
|
+
cmd << @parts[:header] % header
|
24
|
+
end
|
25
|
+
end
|
26
|
+
cmd << @parts[:url] % @params[:url]
|
27
|
+
end
|
28
|
+
|
29
|
+
end # class ABCmdBuilder
|
30
|
+
end # module BenchTool
|
@@ -0,0 +1,118 @@
|
|
1
|
+
module BenchTool
|
2
|
+
class Dispatcher
|
3
|
+
|
4
|
+
def initialize(options = {})
|
5
|
+
@appconfig = AppConfig.new.to_hash
|
6
|
+
@config = @appconfig[:configuration]
|
7
|
+
@targets = @appconfig[:targets]
|
8
|
+
@options = options
|
9
|
+
# Overwrite app config with options (usually passed as CLI options)
|
10
|
+
unless options.nil?
|
11
|
+
@config.merge!(options)
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
# Each command gets a method here
|
16
|
+
|
17
|
+
def benchmark
|
18
|
+
setup_output
|
19
|
+
benchmark_target(select_target)
|
20
|
+
end
|
21
|
+
|
22
|
+
def test
|
23
|
+
test_target(select_target)
|
24
|
+
end
|
25
|
+
|
26
|
+
private
|
27
|
+
|
28
|
+
# The methods below do the actual work. If this utility grows, these should be moved out to their own classes
|
29
|
+
def benchmark_target(target)
|
30
|
+
# Set up the params we'll send to the Apache Bench cmd builder
|
31
|
+
ab_params = {
|
32
|
+
:requests => @config[:ab_requests],
|
33
|
+
:concurrency => @config[:ab_concurrency],
|
34
|
+
:plotfile => File.expand_path(File.join(@config[:ab_output], "apache-#{Time.now.strftime('%Y%m%d-%H%M%S')}.tsv")),
|
35
|
+
:cookies => target[:cookies],
|
36
|
+
:headers => target[:headers],
|
37
|
+
:url => target[:url]
|
38
|
+
}
|
39
|
+
|
40
|
+
# Output to inform the user what is about to happen
|
41
|
+
console ""
|
42
|
+
console "Benchmarking:"
|
43
|
+
console " URL: #{ab_params[:url]}"
|
44
|
+
console " Concurrency: #{ab_params[:concurrency]}"
|
45
|
+
console " Requests: #{ab_params[:requests]}"
|
46
|
+
console ""
|
47
|
+
|
48
|
+
# Build the command and execute or print
|
49
|
+
cmd = ABCmdBuilder.new(ab_params, @options).to_str
|
50
|
+
if @options[:print_no_exec]
|
51
|
+
console "Print cmd requested; no exec:"
|
52
|
+
console ""
|
53
|
+
console
|
54
|
+
else
|
55
|
+
console "Apache Bench output follows [#{Time.now.strftime('%F %T')}]================================"
|
56
|
+
run_shell_cmd cmd
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
def test_target(target)
|
61
|
+
# Set up the params we'll send to the curl cmd builder
|
62
|
+
curl_params = {
|
63
|
+
:cookies => target[:cookies],
|
64
|
+
:headers => target[:headers],
|
65
|
+
:url => target[:url]
|
66
|
+
}
|
67
|
+
|
68
|
+
# Output to inform the user what is about to happen
|
69
|
+
console ""
|
70
|
+
console "Testing:"
|
71
|
+
console " URL: #{curl_params[:url]}"
|
72
|
+
console ""
|
73
|
+
|
74
|
+
# Build the command and execute or print
|
75
|
+
cmd = CurlCmdBuilder.new(curl_params, @options).to_str
|
76
|
+
if @options[:print_no_exec]
|
77
|
+
console "Print cmd requested; no exec:"
|
78
|
+
console ""
|
79
|
+
console cmd
|
80
|
+
else
|
81
|
+
console "Curl output follows [#{Time.now.strftime('%F %T')}]================================"
|
82
|
+
result = `#{cmd}`
|
83
|
+
puts result.split("\n").first(30)
|
84
|
+
end
|
85
|
+
end
|
86
|
+
|
87
|
+
def select_target
|
88
|
+
# Return a target immediately if specified as an option
|
89
|
+
if @options.key?(:target_idx)
|
90
|
+
return @targets[@options[:target_idx]]
|
91
|
+
end
|
92
|
+
# Otherwise present a menu and return the choice
|
93
|
+
begin
|
94
|
+
selection = choose do |menu|
|
95
|
+
menu.prompt = "Select a target:"
|
96
|
+
@targets.each_with_index do |target, i|
|
97
|
+
menu.choice target[:name] { i }
|
98
|
+
end
|
99
|
+
end
|
100
|
+
rescue Interrupt
|
101
|
+
console ""
|
102
|
+
console "SIGINT received, Goodbye!"
|
103
|
+
exit 1
|
104
|
+
end
|
105
|
+
@targets[selection]
|
106
|
+
end
|
107
|
+
|
108
|
+
def setup_output
|
109
|
+
output_dir = File.expand_path(@config[:ab_output])
|
110
|
+
unless Dir.exists?(output_dir)
|
111
|
+
console "Creating output directory because it didn't exist."
|
112
|
+
FileUtils.mkdir_p(output_dir)
|
113
|
+
end
|
114
|
+
console "Using output dir: #{output_dir}"
|
115
|
+
end
|
116
|
+
|
117
|
+
end # class Dispatcher
|
118
|
+
end # module BenchTool
|
@@ -0,0 +1,32 @@
|
|
1
|
+
# Writes msg to STDERR (helps with bash shell redirection)
|
2
|
+
def console(msg)
|
3
|
+
STDERR.puts msg
|
4
|
+
end
|
5
|
+
|
6
|
+
# Open4 version (doesn't write output in real time)
|
7
|
+
# def run_shell_cmd(cmd)
|
8
|
+
# status = Open4::popen4('sh') do |pid, stdin, stdout, stderr|
|
9
|
+
# # puts "debug: #{cmd}" if @options[:debug]
|
10
|
+
# stdin.puts cmd
|
11
|
+
# stdin.close
|
12
|
+
# puts stdout.read
|
13
|
+
# end
|
14
|
+
# status
|
15
|
+
# end
|
16
|
+
|
17
|
+
# PTY version (writes to output in real time)
|
18
|
+
def run_shell_cmd(cmd)
|
19
|
+
begin
|
20
|
+
PTY.spawn(cmd) do |r, w, pid|
|
21
|
+
begin
|
22
|
+
r.each { |line| print line;}
|
23
|
+
rescue Errno::EIO
|
24
|
+
rescue Interrupt
|
25
|
+
console ""
|
26
|
+
console "Goodbye!"
|
27
|
+
end
|
28
|
+
end
|
29
|
+
rescue PTY::ChildExited => e
|
30
|
+
puts "The child process exited!"
|
31
|
+
end
|
32
|
+
end
|
@@ -0,0 +1,62 @@
|
|
1
|
+
# Symbolizes all of hash's keys and subkeys.
|
2
|
+
# Also allows for custom pre-processing of keys (e.g. downcasing, etc)
|
3
|
+
# if the block is given:
|
4
|
+
#
|
5
|
+
# somehash.deep_symbolize { |key| key.downcase }
|
6
|
+
#
|
7
|
+
# Usage: either include it into global Hash class to make it available to
|
8
|
+
# to all hashes, or extend only your own hash objects with this
|
9
|
+
# module.
|
10
|
+
# E.g.:
|
11
|
+
# 1) class Hash; include DeepSymbolizable; end
|
12
|
+
# 2) myhash.extend DeepSymbolizable
|
13
|
+
#
|
14
|
+
# From: https://gist.github.com/998709/aafd65c5780a2ce3cda3ef020b6e5dead7cef1d0
|
15
|
+
|
16
|
+
module DeepSymbolizable
|
17
|
+
def deep_symbolize(&block)
|
18
|
+
method = self.class.to_s.downcase.to_sym
|
19
|
+
syms = DeepSymbolizable::Symbolizers
|
20
|
+
syms.respond_to?(method) ? syms.send(method, self, &block) : self
|
21
|
+
end
|
22
|
+
|
23
|
+
module Symbolizers
|
24
|
+
extend self
|
25
|
+
|
26
|
+
# the primary method - symbolizes keys of the given hash,
|
27
|
+
# preprocessing them with a block if one was given, and recursively
|
28
|
+
# going into all nested enumerables
|
29
|
+
def hash(hash, &block)
|
30
|
+
hash.inject({}) do |result, (key, value)|
|
31
|
+
# Recursively deep-symbolize subhashes
|
32
|
+
value = _recurse_(value, &block)
|
33
|
+
|
34
|
+
# Pre-process the key with a block if it was given
|
35
|
+
key = yield key if block_given?
|
36
|
+
# Symbolize the key string if it responds to to_sym
|
37
|
+
sym_key = key.to_sym rescue key
|
38
|
+
|
39
|
+
# write it back into the result and return the updated hash
|
40
|
+
result[sym_key] = value
|
41
|
+
result
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
# walking over arrays and symbolizing all nested elements
|
46
|
+
def array(ary, &block)
|
47
|
+
ary.map { |v| _recurse_(v, &block) }
|
48
|
+
end
|
49
|
+
|
50
|
+
# handling recursion - any Enumerable elements (except String)
|
51
|
+
# is being extended with the module, and then symbolized
|
52
|
+
def _recurse_(value, &block)
|
53
|
+
if value.is_a?(Enumerable) && !value.is_a?(String)
|
54
|
+
# support for a use case without extended core Hash
|
55
|
+
value.extend DeepSymbolizable unless value.class.include?(DeepSymbolizable)
|
56
|
+
value = value.deep_symbolize(&block)
|
57
|
+
end
|
58
|
+
value
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
end
|
metadata
ADDED
@@ -0,0 +1,111 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: benchtool
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.1.0
|
5
|
+
prerelease:
|
6
|
+
platform: ruby
|
7
|
+
authors:
|
8
|
+
- Brad Landers
|
9
|
+
autorequire:
|
10
|
+
bindir: bin
|
11
|
+
cert_chain: []
|
12
|
+
date: 2012-08-24 00:00:00.000000000 Z
|
13
|
+
dependencies:
|
14
|
+
- !ruby/object:Gem::Dependency
|
15
|
+
name: highline
|
16
|
+
requirement: !ruby/object:Gem::Requirement
|
17
|
+
none: false
|
18
|
+
requirements:
|
19
|
+
- - ! '>='
|
20
|
+
- !ruby/object:Gem::Version
|
21
|
+
version: '0'
|
22
|
+
type: :runtime
|
23
|
+
prerelease: false
|
24
|
+
version_requirements: !ruby/object:Gem::Requirement
|
25
|
+
none: false
|
26
|
+
requirements:
|
27
|
+
- - ! '>='
|
28
|
+
- !ruby/object:Gem::Version
|
29
|
+
version: '0'
|
30
|
+
- !ruby/object:Gem::Dependency
|
31
|
+
name: open4
|
32
|
+
requirement: !ruby/object:Gem::Requirement
|
33
|
+
none: false
|
34
|
+
requirements:
|
35
|
+
- - ! '>='
|
36
|
+
- !ruby/object:Gem::Version
|
37
|
+
version: '0'
|
38
|
+
type: :runtime
|
39
|
+
prerelease: false
|
40
|
+
version_requirements: !ruby/object:Gem::Requirement
|
41
|
+
none: false
|
42
|
+
requirements:
|
43
|
+
- - ! '>='
|
44
|
+
- !ruby/object:Gem::Version
|
45
|
+
version: '0'
|
46
|
+
- !ruby/object:Gem::Dependency
|
47
|
+
name: awesome_print
|
48
|
+
requirement: !ruby/object:Gem::Requirement
|
49
|
+
none: false
|
50
|
+
requirements:
|
51
|
+
- - ! '>='
|
52
|
+
- !ruby/object:Gem::Version
|
53
|
+
version: '0'
|
54
|
+
type: :development
|
55
|
+
prerelease: false
|
56
|
+
version_requirements: !ruby/object:Gem::Requirement
|
57
|
+
none: false
|
58
|
+
requirements:
|
59
|
+
- - ! '>='
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: '0'
|
62
|
+
description: A simple wrapper tool for Apache Bench.
|
63
|
+
email:
|
64
|
+
- brad@bradlanders.com
|
65
|
+
executables:
|
66
|
+
- benchtool
|
67
|
+
extensions: []
|
68
|
+
extra_rdoc_files: []
|
69
|
+
files:
|
70
|
+
- .gitignore
|
71
|
+
- Gemfile
|
72
|
+
- LICENSE
|
73
|
+
- README.txt
|
74
|
+
- Rakefile
|
75
|
+
- benchtool.gemspec
|
76
|
+
- bin/benchtool
|
77
|
+
- lib/benchtool.rb
|
78
|
+
- lib/benchtool/ab-cmd-builder.rb
|
79
|
+
- lib/benchtool/app-config.rb
|
80
|
+
- lib/benchtool/configuration.yml.base
|
81
|
+
- lib/benchtool/curl-cmd-builder.rb
|
82
|
+
- lib/benchtool/dispatcher.rb
|
83
|
+
- lib/benchtool/extensions.rb
|
84
|
+
- lib/benchtool/helpers.rb
|
85
|
+
- lib/benchtool/version.rb
|
86
|
+
- lib/deep-symbolizable/deep-symbolize.rb
|
87
|
+
homepage: ''
|
88
|
+
licenses: []
|
89
|
+
post_install_message:
|
90
|
+
rdoc_options: []
|
91
|
+
require_paths:
|
92
|
+
- lib
|
93
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
94
|
+
none: false
|
95
|
+
requirements:
|
96
|
+
- - ! '>='
|
97
|
+
- !ruby/object:Gem::Version
|
98
|
+
version: '0'
|
99
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
100
|
+
none: false
|
101
|
+
requirements:
|
102
|
+
- - ! '>='
|
103
|
+
- !ruby/object:Gem::Version
|
104
|
+
version: '0'
|
105
|
+
requirements: []
|
106
|
+
rubyforge_project:
|
107
|
+
rubygems_version: 1.8.24
|
108
|
+
signing_key:
|
109
|
+
specification_version: 3
|
110
|
+
summary: A simple wrapper tool for Apache Bench.
|
111
|
+
test_files: []
|