bombard 0.0.2

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 ADDED
@@ -0,0 +1,19 @@
1
+ *.gem
2
+ *.rbc
3
+ .bundle
4
+ .config
5
+ .yardoc
6
+ Gemfile.lock
7
+ InstalledFiles
8
+ _yardoc
9
+ coverage
10
+ doc/
11
+ lib/bundler/man
12
+ pkg
13
+ rdoc
14
+ spec/reports
15
+ test/tmp
16
+ test/version_tmp
17
+ tmp
18
+ .idea
19
+ vendor
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
@@ -0,0 +1,5 @@
1
+ # coding: utf-8
2
+ source 'https://rubygems.org'
3
+
4
+ # Specify your gem's dependencies in bombard.gemspec
5
+ gemspec
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
@@ -0,0 +1,4 @@
1
+ require "bundler/gem_tasks"
2
+ require 'rubocop/rake_task'
3
+
4
+ Rubocop::RakeTask.new
data/bin/bombard ADDED
@@ -0,0 +1,4 @@
1
+ # coding: utf-8
2
+ require 'bombard'
3
+
4
+ Bombard::Cli.start(ARGV)
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,12 @@
1
+ # coding: utf-8
2
+ require 'require_all'
3
+
4
+ require_all File.expand_path('../../lib', __FILE__)
5
+
6
+ module Bombard
7
+ class << self
8
+ def start(opts)
9
+ Runner.new(opts)
10
+ end
11
+ end
12
+ end
@@ -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
@@ -0,0 +1,11 @@
1
+ # coding: utf-8
2
+
3
+ module Bombard
4
+ class Builder
5
+ class Test < Builder
6
+ def urls
7
+ %w[http://www.mcclatchyinteractive.com]
8
+ end
9
+ end
10
+ end
11
+ end
@@ -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,11 @@
1
+ # coding: utf-8
2
+
3
+ module Bombard
4
+ class Publisher
5
+ class Console < Publisher
6
+ def publish
7
+ puts @results.to_s
8
+ end
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,11 @@
1
+ # coding: utf-8
2
+
3
+ module Bombard
4
+ class Publisher
5
+ class FusionTables < Publisher
6
+ def publish
7
+ abort 'Not yet implemented. Please e-mail automation@mcclatchyinteractive.com'
8
+ end
9
+ end
10
+ end
11
+ 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