bombard 0.0.2

Sign up to get free protection for your applications and to get access to all the features.
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