bombard 0.0.2
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +19 -0
- data/.rubocop.yml +81 -0
- data/Gemfile +5 -0
- data/LICENSE.txt +22 -0
- data/README.md +40 -0
- data/Rakefile +4 -0
- data/bin/bombard +4 -0
- data/bombard.gemspec +30 -0
- data/lib/bombard.rb +12 -0
- data/lib/bombard/builder.rb +19 -0
- data/lib/bombard/builder/test.rb +11 -0
- data/lib/bombard/cli.rb +33 -0
- data/lib/bombard/config.rb +30 -0
- data/lib/bombard/publisher.rb +24 -0
- data/lib/bombard/publisher/console.rb +11 -0
- data/lib/bombard/publisher/fusiontables.rb +11 -0
- data/lib/bombard/publisher/jenkins_plot.rb +19 -0
- data/lib/bombard/runner.rb +52 -0
- data/lib/bombard/version.rb +5 -0
- data/lib/core_ext/hash.rb +11 -0
- data/lib/siege.rb +43 -0
- data/lib/siege/data/siegerc +2 -0
- data/lib/siege/results.rb +72 -0
- data/lib/siege/temp_file.rb +36 -0
- data/lib/wordlist.rb +13 -0
- data/lib/wordlist/data/american-english +99171 -0
- metadata +191 -0
data/.gitignore
ADDED
data/.rubocop.yml
ADDED
@@ -0,0 +1,81 @@
|
|
1
|
+
AllCops:
|
2
|
+
Include:
|
3
|
+
- 'Gemfile'
|
4
|
+
- 'Thorfile'
|
5
|
+
- 'thor.gemspec'
|
6
|
+
|
7
|
+
# Avoid long parameter lists
|
8
|
+
ParameterLists:
|
9
|
+
Max: 5
|
10
|
+
CountKeywordArgs: true
|
11
|
+
|
12
|
+
MethodLength:
|
13
|
+
CountComments: false
|
14
|
+
Max: 15
|
15
|
+
|
16
|
+
# Avoid more than `Max` levels of nesting.
|
17
|
+
BlockNesting:
|
18
|
+
Max: 4
|
19
|
+
|
20
|
+
# Align with the style guide.
|
21
|
+
CollectionMethods:
|
22
|
+
PreferredMethods:
|
23
|
+
collect: 'map'
|
24
|
+
find: 'detect'
|
25
|
+
find_all: 'select'
|
26
|
+
|
27
|
+
# Do not force public/protected/private keyword to be indented at the same
|
28
|
+
# level as the def keyword. My personal preference is to outdent these keywords
|
29
|
+
# because I think when scanning code it makes it easier to identify the
|
30
|
+
# sections of code and visually separate them. When the keyword is at the same
|
31
|
+
# level I think it sort of blends in with the def keywords and makes it harder
|
32
|
+
# to scan the code and see where the sections are.
|
33
|
+
AccessModifierIndentation:
|
34
|
+
Enabled: false
|
35
|
+
|
36
|
+
# Limit line length
|
37
|
+
LineLength:
|
38
|
+
Enabled: false
|
39
|
+
|
40
|
+
# Disable documentation checking until a class needs to be documented once
|
41
|
+
Documentation:
|
42
|
+
Enabled: false
|
43
|
+
|
44
|
+
# No spaces inside hash literals
|
45
|
+
SpaceInsideHashLiteralBraces:
|
46
|
+
EnforcedStyle: no_space
|
47
|
+
|
48
|
+
# Allow dots at the end of lines
|
49
|
+
DotPosition:
|
50
|
+
Enabled: false
|
51
|
+
|
52
|
+
# Enforce outdenting of access modifiers (i.e. public, private, protected)
|
53
|
+
AccessModifierIndentation:
|
54
|
+
EnforcedStyle: outdent
|
55
|
+
|
56
|
+
EmptyLinesAroundAccessModifier:
|
57
|
+
Enabled: true
|
58
|
+
|
59
|
+
# Align ends correctly
|
60
|
+
EndAlignment:
|
61
|
+
AlignWith: variable
|
62
|
+
|
63
|
+
# Indentation of when/else
|
64
|
+
CaseIndentation:
|
65
|
+
IndentWhenRelativeTo: end
|
66
|
+
IndentOneStep: false
|
67
|
+
|
68
|
+
DoubleNegation:
|
69
|
+
Enabled: false
|
70
|
+
|
71
|
+
PercentLiteralDelimiters:
|
72
|
+
PreferredDelimiters:
|
73
|
+
'%': ()
|
74
|
+
'%i': ()
|
75
|
+
'%q': ()
|
76
|
+
'%Q': ()
|
77
|
+
'%r': '{}'
|
78
|
+
'%s': ()
|
79
|
+
'%w': '[]'
|
80
|
+
'%W': '[]'
|
81
|
+
'%x': ()
|
data/Gemfile
ADDED
data/LICENSE.txt
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
Copyright (c) 2014 Todd Edwards
|
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.md
ADDED
@@ -0,0 +1,40 @@
|
|
1
|
+
# Bombard
|
2
|
+
|
3
|
+
Bombard is a(nother) Siege wrapper for Ruby that's extensible.
|
4
|
+
|
5
|
+
## Installation
|
6
|
+
|
7
|
+
Add this line to your application's Gemfile:
|
8
|
+
|
9
|
+
gem 'bombard'
|
10
|
+
|
11
|
+
And then execute:
|
12
|
+
|
13
|
+
$ bundle
|
14
|
+
|
15
|
+
Or install it yourself as:
|
16
|
+
|
17
|
+
$ gem install bombard
|
18
|
+
|
19
|
+
## Requirements
|
20
|
+
|
21
|
+
* a Ruby implementation running 1.9 or newer
|
22
|
+
* a Unix based Operating System
|
23
|
+
|
24
|
+
## Usage
|
25
|
+
|
26
|
+
TODO: Write usage instructions here
|
27
|
+
|
28
|
+
## Contributing
|
29
|
+
|
30
|
+
1. Fork it
|
31
|
+
2. Create your feature branch (`git checkout -b my-new-feature`)
|
32
|
+
3. Commit your changes (`git commit -am 'Add some feature'`)
|
33
|
+
4. Push to the branch (`git push origin my-new-feature`)
|
34
|
+
5. Create new Pull Request
|
35
|
+
|
36
|
+
## License
|
37
|
+
|
38
|
+
All source code in this repository is licensed under the MIT license unless
|
39
|
+
specified otherwise. A copy of this license can be found in the file "LICENSE.txt"
|
40
|
+
in the root directory of this repository.
|
data/Rakefile
ADDED
data/bin/bombard
ADDED
data/bombard.gemspec
ADDED
@@ -0,0 +1,30 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
lib = File.expand_path('../lib', __FILE__)
|
3
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
+
require 'bombard/version'
|
5
|
+
|
6
|
+
Gem::Specification.new do |spec|
|
7
|
+
spec.name = 'bombard'
|
8
|
+
spec.version = Bombard::VERSION
|
9
|
+
spec.authors = ['Todd Edwards']
|
10
|
+
spec.email = ['tedwards@mcclatchyinteractive.com']
|
11
|
+
spec.description = 'Bombard is a(nother) Siege wrapper for Ruby thats extensible.'
|
12
|
+
spec.summary = spec.description
|
13
|
+
|
14
|
+
spec.homepage = 'http://github.com/triangletodd/bombard'
|
15
|
+
spec.license = 'MIT'
|
16
|
+
|
17
|
+
spec.files = `git ls-files`.split($/)
|
18
|
+
spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
|
19
|
+
spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
|
20
|
+
spec.require_paths = ['lib']
|
21
|
+
|
22
|
+
spec.add_development_dependency 'bundler', '~> 1.3'
|
23
|
+
spec.add_development_dependency 'rubocop'
|
24
|
+
spec.add_development_dependency 'rake'
|
25
|
+
spec.add_development_dependency 'flay'
|
26
|
+
spec.add_development_dependency 'flog'
|
27
|
+
|
28
|
+
spec.add_runtime_dependency 'thor'
|
29
|
+
spec.add_runtime_dependency 'require_all'
|
30
|
+
end
|
data/lib/bombard.rb
ADDED
@@ -0,0 +1,19 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
|
3
|
+
module Bombard
|
4
|
+
class Builder
|
5
|
+
class << self
|
6
|
+
def with_opts(options = nil)
|
7
|
+
new options
|
8
|
+
end
|
9
|
+
end
|
10
|
+
|
11
|
+
def initialize(options = nil)
|
12
|
+
@options = options
|
13
|
+
end
|
14
|
+
|
15
|
+
def urls
|
16
|
+
abort "'urls' method not implemented in #{self.class}"
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
data/lib/bombard/cli.rb
ADDED
@@ -0,0 +1,33 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
require 'thor'
|
3
|
+
|
4
|
+
module Bombard
|
5
|
+
class Cli < Thor
|
6
|
+
OPTIONS = [:builder, :publisher, :require, :publisher_opts, :builder_opts]
|
7
|
+
|
8
|
+
package_name :bombard
|
9
|
+
default_task :default
|
10
|
+
|
11
|
+
# Siege options
|
12
|
+
class_option :delay, type: :string, aliases: :l, required: false
|
13
|
+
class_option :duration, type: :string, aliases: :d, required: false
|
14
|
+
class_option :users, type: :numeric, aliases: :u, required: false
|
15
|
+
class_option :agent, type: :string, aliases: :A, required: false
|
16
|
+
class_option :header, type: :string, aliases: :H, required: false
|
17
|
+
class_option :internet, type: :boolean, aliases: :i, required: false
|
18
|
+
class_option :benchmark, type: :boolean, aliases: :e, required: false
|
19
|
+
|
20
|
+
# Bombard options
|
21
|
+
class_option :verbose, type: :boolean, aliases: :v, required: false
|
22
|
+
class_option :builder, type: :string, aliases: :b, required: false
|
23
|
+
class_option :publisher, type: :string, aliases: :p, required: false
|
24
|
+
class_option :require, type: :string, aliases: :r, required: false
|
25
|
+
class_option :publisher_opts, type: :string, aliases: :P, required: false
|
26
|
+
class_option :builder_opts, type: :string, aliases: :B, required: false
|
27
|
+
|
28
|
+
desc 'default', 'Runs without specifying a task. ie. bombard --etc', hide: true
|
29
|
+
def default
|
30
|
+
Bombard.start(options.dup)
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
@@ -0,0 +1,30 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
require 'ostruct'
|
3
|
+
|
4
|
+
module Bombard
|
5
|
+
class Config
|
6
|
+
class << self
|
7
|
+
def for(opts)
|
8
|
+
new opts
|
9
|
+
end
|
10
|
+
end
|
11
|
+
|
12
|
+
def initialize(opts)
|
13
|
+
@opts = opts
|
14
|
+
end
|
15
|
+
|
16
|
+
def siege
|
17
|
+
@siege ||= opts_for Siege::OPTIONS.map { |k, _| k }
|
18
|
+
end
|
19
|
+
|
20
|
+
def bombard
|
21
|
+
@bombard ||= OpenStruct.new opts_for(Bombard::Cli::OPTIONS)
|
22
|
+
end
|
23
|
+
|
24
|
+
private
|
25
|
+
|
26
|
+
def opts_for(const)
|
27
|
+
@opts.select { |k, _| const.include?(k.to_sym) }.hmap { |k, v| {k.to_sym => v} }
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
@@ -0,0 +1,24 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
|
3
|
+
module Bombard
|
4
|
+
class Publisher
|
5
|
+
class << self
|
6
|
+
def for(results)
|
7
|
+
new results
|
8
|
+
end
|
9
|
+
end
|
10
|
+
|
11
|
+
def initialize(results)
|
12
|
+
@results = results
|
13
|
+
end
|
14
|
+
|
15
|
+
def with_opts(options)
|
16
|
+
@options = options
|
17
|
+
self
|
18
|
+
end
|
19
|
+
|
20
|
+
def publish
|
21
|
+
abort "'publish' method not implemented in #{self.class}"
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
|
3
|
+
module Bombard
|
4
|
+
class Publisher
|
5
|
+
class JenkinsPlot < Publisher
|
6
|
+
def publish
|
7
|
+
site, asset = @options.split(',')
|
8
|
+
prefix = site + '_' + asset + '_'
|
9
|
+
|
10
|
+
%w[response longest shortest failed].each do |p|
|
11
|
+
prop = 'YVALUE=' + @results.send(p).to_s
|
12
|
+
file = File.new(prefix + p + '.properties', 'w')
|
13
|
+
file.puts prop
|
14
|
+
file.close
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
@@ -0,0 +1,52 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
|
3
|
+
module Bombard
|
4
|
+
class Runner
|
5
|
+
attr_reader :conf
|
6
|
+
|
7
|
+
def initialize(opts)
|
8
|
+
@global_opts = Config.for opts
|
9
|
+
@conf = @global_opts.bombard
|
10
|
+
|
11
|
+
load_requirements
|
12
|
+
publish
|
13
|
+
end
|
14
|
+
|
15
|
+
def results
|
16
|
+
@results ||= Siege.new(build.urls, @global_opts.siege).results
|
17
|
+
end
|
18
|
+
|
19
|
+
def publisher
|
20
|
+
@publisher ||= @conf.publisher ? class_for(@conf.publisher, Bombard::Publisher) : Bombard::Publisher::Console
|
21
|
+
end
|
22
|
+
|
23
|
+
def publish
|
24
|
+
puts "Publishing using:\n\t#{publisher}"
|
25
|
+
publisher.for(results).with_opts(@conf.publisher_opts).publish
|
26
|
+
end
|
27
|
+
|
28
|
+
def builder
|
29
|
+
# TODO: Need a sane default or simply fail if not specified.
|
30
|
+
@builder ||= @conf.builder ? class_for(@conf.builder, Bombard::Builder) : Bombard::Builder::Test
|
31
|
+
end
|
32
|
+
|
33
|
+
def build
|
34
|
+
puts "Building using:\n\t#{builder}"
|
35
|
+
builder.with_opts(@conf.builder_opts)
|
36
|
+
end
|
37
|
+
|
38
|
+
def load_requirements
|
39
|
+
require_all @conf.require if @conf.require
|
40
|
+
end
|
41
|
+
|
42
|
+
private
|
43
|
+
|
44
|
+
def class_for(child, parent = Object)
|
45
|
+
child.split('::').reduce(parent) do |mod, class_name|
|
46
|
+
mod.const_get(class_name)
|
47
|
+
end
|
48
|
+
rescue NameError
|
49
|
+
abort "Can't find #{parent}::#{child}. You can load the contents of any directory using the --require switch."
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|