antismoker 0.0.1

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,17 @@
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
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in antismoker.gemspec
4
+ gemspec
data/LICENSE ADDED
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2012 Yamashita Yuu
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,75 @@
1
+ # antismoker
2
+
3
+ Yet another HTTP smoke testing framework.
4
+
5
+ ## Installation
6
+
7
+ Add this line to your application's Gemfile:
8
+
9
+ gem 'antismoker'
10
+
11
+ And then execute:
12
+
13
+ $ bundle
14
+
15
+ Or install it yourself as:
16
+
17
+ $ gem install antismoker
18
+
19
+ ## Usage
20
+
21
+ The smoke tests are implemented as Rake task.
22
+ You can use `antismoker` rake task with adding following lines in your `Rakefile` or so.
23
+
24
+ ## Rakefile
25
+ load "tasks/antismoker.rake"
26
+
27
+ You can configure `antismoker` from `config/antismoker.yml`.
28
+
29
+ ## config/antismoker.yml
30
+ # GET http://127.0.0.1/foo
31
+ development:
32
+ 127.0.0.1:
33
+ http:
34
+ :port: 80
35
+ :path: /foo
36
+ production:
37
+ 127.0.0.1:
38
+ http:
39
+ :port: 80
40
+ :path: /foo
41
+
42
+ And then run `rake antismoker`.
43
+
44
+ % rake antismoker
45
+ smoke testing: http://127.0.0.1:9001/server-status: [ OK ]
46
+
47
+
48
+ ### Capistrano usage
49
+
50
+ Also you can use `antismoker` from Capistrano.
51
+ To use it, add following in your `config/deploy.rb` or so.
52
+
53
+ # config/deploy.rb
54
+ require "antismoker/capistrano"
55
+ set(:antismoker_use_rollback, false) # set true to enable rollback on failure
56
+
57
+ After all, the `antismoker` task will be run after `deploy` and `deploy:cold`.
58
+
59
+
60
+ ## Contributing
61
+
62
+ 1. Fork it
63
+ 2. Create your feature branch (`git checkout -b my-new-feature`)
64
+ 3. Commit your changes (`git commit -am 'Added some feature'`)
65
+ 4. Push to the branch (`git push origin my-new-feature`)
66
+ 5. Create new Pull Request
67
+
68
+ ## Author
69
+
70
+ - YAMASHITA Yuu (https://github.com/yyuu)
71
+ - Geisha Tokyo Entertainment Inc. (http://www.geishatokyo.com/)
72
+
73
+ ## License
74
+
75
+ MIT
data/Rakefile ADDED
@@ -0,0 +1,2 @@
1
+ #!/usr/bin/env rake
2
+ require "bundler/gem_tasks"
@@ -0,0 +1,19 @@
1
+ # -*- encoding: utf-8 -*-
2
+ require File.expand_path('../lib/antismoker/version', __FILE__)
3
+
4
+ Gem::Specification.new do |gem|
5
+ gem.authors = ["Yamashita Yuu"]
6
+ gem.email = ["yamashita@geishatokyo.com"]
7
+ gem.description = %q{Yet another HTTP smoke testing framework.}
8
+ gem.summary = %q{Yet another HTTP smoke testing framework.}
9
+ gem.homepage = "https://github.com/yyuu/antismoker"
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 = "antismoker"
15
+ gem.require_paths = ["lib"]
16
+ gem.version = AntiSmoker::VERSION
17
+
18
+ gem.add_dependency("rake")
19
+ end
@@ -0,0 +1,11 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require "antismoker/deployment"
4
+
5
+ Capistrano::Configuration.instance(:must_exist).load do
6
+ after "deploy", "antismoker:invoke"
7
+ after "deploy:cold", "antismoker:invoke"
8
+ AntiSmoker::Deployment.define_task(self, :task, :except => { :no_release => true })
9
+ end
10
+
11
+ # vim:set ft=ruby sw=2 ts=2 :
@@ -0,0 +1,64 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ module AntiSmoker
4
+ class Deployment
5
+ def self.define_task(context, task_method = :task, opts = {})
6
+ if defined?(Capistrano) && context.is_a?(Capistrano::Configuration)
7
+ context_name = "capistrano"
8
+ role_default = "{:except => {:no_release => true}}"
9
+ error_type = ::Capistrano::CommandError
10
+ else
11
+ context_name = "vlad"
12
+ role_default = "[:app]"
13
+ error_type = ::Rake::CommandFailedError
14
+ end
15
+
16
+ roles = context.fetch(:antismoker_roles, false)
17
+ opts[:roles] = roles if roles
18
+
19
+ context.send :namespace, :antismoker do
20
+ send :desc, "Run smoke test."
21
+ send task_method, :invoke, opts do
22
+ rake_cmd = context.fetch(:rake, "rake")
23
+ antismoker_task = context.fetch(:antismoker_task, "antismoker:invoke")
24
+ rails_env = context.fetch(:rails_env, "production")
25
+ app_path = context.fetch(:latest_release)
26
+ if app_path.to_s.empty?
27
+ raise error_type.new("Cannot detect current release path - make sure you have deployed at least once.")
28
+ end
29
+ args = []
30
+ args += context.fetch(:antismoker_flags, [])
31
+ args << "RAILS_ENV=#{rails_env}"
32
+
33
+ begin
34
+ run "cd #{app_path} && #{rake_cmd} #{args.join(' ')} #{antismoker_task}"
35
+ antismoker_success
36
+ rescue => error
37
+ logger.info("[ERROR] #{error}")
38
+ antismoker_failure
39
+ ensure
40
+ finalize_antismoker
41
+ end
42
+ end
43
+
44
+ send task_method, :antismoker_success, opts do
45
+ logger.info("It works!")
46
+ end
47
+
48
+ send task_method, :antismoker_failure, opts do
49
+ if context.fetch(:antismoker_use_rollback, false)
50
+ logger.info("Rolling back application.")
51
+ rollback_task = context.fetch(:antismoker_rollback_task, "deploy:rollback")
52
+ find_and_execute_task(rollback_task)
53
+ end
54
+ end
55
+
56
+ send task_method, :finalize_antismoker, opts do
57
+ # nop
58
+ end
59
+ end
60
+ end
61
+ end
62
+ end
63
+
64
+ # vim:set ft=ruby sw=2 ts=2 :
@@ -0,0 +1,59 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require "socket"
4
+ require "yaml"
5
+
6
+ module AntiSmoker
7
+ DEFAULT_PROTOCOL_NAME = "__default__"
8
+ DEFAULT_PROTOCOL_OPTIONS = {
9
+ :count => 3, # test retry count
10
+ :delay => 0.0, # delay for first test in seconds.
11
+ :period => 3.0, # retry interval between each tests.
12
+ :timeout => 5.0, # test timeout
13
+ }
14
+
15
+ def load(file, options={})
16
+ env = options.fetch(:env, "development")
17
+ defs = YAML.load(File.read(file))
18
+ abort("No such environment was defined in #{file}: #{env}") unless defs.has_key?(env)
19
+
20
+ smoketests = []
21
+ defs[env].each do |host, smoke_spec|
22
+ default_options = smoke_spec.delete(DEFAULT_PROTOCOL_NAME)
23
+ DEFAULT_PROTOCOL_OPTIONS.update(default_options) if default_options
24
+
25
+ smoke_spec.each do |protocol, options|
26
+ begin
27
+ require "antismoker/tests/#{protocol}"
28
+ rescue LoadError => error
29
+ abort("Could not load smoke test for #{protocol}: #{error}")
30
+ end
31
+
32
+ begin
33
+ name = protocol.scan(/\w+/).map { |w| w.capitalize }.join
34
+ klass = AntiSmoker.const_get("#{name}Test")
35
+ rescue NameError => error
36
+ abort("[BUG] Broken smoke test for #{protocol}: #{error}")
37
+ end
38
+
39
+ if options.is_a?(Hash)
40
+ options = DEFAULT_PROTOCOL_OPTIONS.merge(options)
41
+ else
42
+ options = DEFAULT_PROTOCOL_OPTIONS.merge(:port => options)
43
+ end
44
+ begin
45
+ options[:port] = Socket.getservbyname(protocol) unless options.has_key?(:port)
46
+ rescue SocketError => error
47
+ abort("Could not resolve well-known port for #{protocol}: #{error}")
48
+ end
49
+ ports = [ options.delete(:port) ].flatten
50
+ smoketests += ports.map { |port| klass.new(host, port, options) }
51
+ end
52
+ end
53
+
54
+ smoketests
55
+ end
56
+ module_function :load
57
+ end
58
+
59
+ # vim:set ft=ruby sw=2 ts=2 :
@@ -0,0 +1,25 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require "thread"
4
+
5
+ module AntiSmoker
6
+ def run(smoketests=[], options={})
7
+ results = smoketests.map { |smoketest|
8
+ run_single(smoketest, options)
9
+ }
10
+ rescue Interrupt
11
+ abort("Interrupted")
12
+ end
13
+ module_function :run
14
+
15
+ def run_single(smoketest, options={})
16
+ begin
17
+ smoketest.run(options)
18
+ rescue => error
19
+ false
20
+ end
21
+ end
22
+ module_function :run_single
23
+ end
24
+
25
+ # vim:set ft=ruby sw=2 ts=2 :
@@ -0,0 +1,60 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require "antismoker/tests"
4
+ require "net/http"
5
+ require "uri"
6
+
7
+ module AntiSmoker
8
+ class HttpTest < AbstractSmokeTest
9
+ def initialize(host, port, options={})
10
+ super
11
+ @data = options.fetch(:data, {})
12
+ @method = options.fetch(:method, "GET")
13
+ @path = options.fetch(:path, "/")
14
+ @ok = options.fetch(:ok, 200)
15
+ end
16
+ attr_reader :data
17
+ attr_reader :method
18
+ attr_reader :path
19
+
20
+ def run_once(options={})
21
+ response = fetch(uri, :method => method)
22
+ logger.debug("HTTP response: #{self} => #{response.code} (#{response.body.length} bytes)")
23
+ response_ok(response)
24
+ end
25
+
26
+ def fetch(uri, options={})
27
+ limit = options.fetch(:limit, 10)
28
+ method = options.fetch(:method, "GET")
29
+ raise(ArgumentError.new("HTTP redirect too deep")) if limit <= 0
30
+ case method
31
+ when /^post$/i
32
+ response = Net::HTTP.post_form(uri, data)
33
+ else
34
+ response = Net::HTTP.get_response(uri)
35
+ end
36
+ if Net::HTTPRedirection === response
37
+ location = URI.parse(response["location"])
38
+ new_uri = (location.absolute?) ? location : uri.merge(location)
39
+ fetch(new_uri, :limit => limit-1)
40
+ else
41
+ response
42
+ end
43
+ end
44
+
45
+ def response_ok(response)
46
+ code = response.code.to_i
47
+ [ @ok ].flatten.compact.map { |x| x === code }.any?
48
+ end
49
+
50
+ def uri
51
+ URI::HTTP.build(:host => host, :port => port, :path => path)
52
+ end
53
+
54
+ def to_s
55
+ "#{method} #{uri}"
56
+ end
57
+ end
58
+ end
59
+
60
+ # vim:set ft=ruby sw=2 ts=2 :
@@ -0,0 +1,78 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require "logger"
4
+ require "timeout"
5
+
6
+ module AntiSmoker
7
+ class AbstractSmokeTest
8
+ def initialize(host, port, options={})
9
+ @host = host
10
+ @port = port
11
+ @options = options
12
+
13
+ @delay = options[:delay]
14
+ @count = options[:count]
15
+ @period = options[:period]
16
+ @timeout = options[:timeout]
17
+
18
+ @logger = Logger.new(STDERR)
19
+ @logger.level = Logger.const_get(options.fetch(:log, :info).to_s.upcase)
20
+ end
21
+ attr_reader :host
22
+ attr_reader :port
23
+ attr_reader :options
24
+
25
+ attr_reader :delay
26
+ attr_reader :count
27
+ attr_reader :period
28
+ attr_reader :timeout
29
+
30
+ attr_reader :logger
31
+
32
+ def sleep_with_progress(n)
33
+ deadline = Time.now + n
34
+ while Time.now < deadline
35
+ STDOUT.putc(?.)
36
+ STDOUT.flush
37
+ sleep(n / 3)
38
+ end
39
+ end
40
+
41
+ def run(options={})
42
+ STDOUT.write("smoke testing: #{self}: ")
43
+ sleep_with_progress(delay)
44
+ n = 0
45
+ while n < count
46
+ if run_once_with_timeout(options)
47
+ STDOUT.puts(" [\e[1;32m OK \e[0m]")
48
+ return true
49
+ else
50
+ STDOUT.putc(?!)
51
+ sleep_with_progress(period)
52
+ n += 1
53
+ end
54
+ end
55
+ STDOUT.puts(" [\e[31m NG \e[0m]")
56
+ return false
57
+ end
58
+
59
+ def run_once_with_timeout(options={})
60
+ begin
61
+ Timeout.timeout(timeout) {
62
+ return run_once(options)
63
+ }
64
+ rescue Timeout::Error => error
65
+ logger.warn("timed out: #{self}: #{error}")
66
+ rescue => error
67
+ logger.warn("unknown error: #{self}: #{error}")
68
+ end
69
+ false
70
+ end
71
+
72
+ def run_once(options={})
73
+ raise("must be overridden")
74
+ end
75
+ end
76
+ end
77
+
78
+ # vim:set ft=ruby sw=2 ts=2 :
@@ -0,0 +1,3 @@
1
+ module AntiSmoker
2
+ VERSION = "0.0.1"
3
+ end
data/lib/antismoker.rb ADDED
@@ -0,0 +1,13 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require "antismoker/deployment"
4
+ require "antismoker/loader"
5
+ require "antismoker/runner"
6
+ require "antismoker/tests"
7
+ require "antismoker/version"
8
+
9
+ module AntiSmoker
10
+ # Your code goes here...
11
+ end
12
+
13
+ # vim:set ft=ruby sw=2 ts=2 :
@@ -0,0 +1,20 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require "antismoker"
4
+
5
+ desc("Run smoke test.")
6
+ task(:antismoker) do
7
+ Rake::Task["antismoker:invoke"].invoke
8
+ end
9
+
10
+ namespace(:antismoker) do
11
+ desc("Run smoke test.")
12
+ task(:invoke) do
13
+ env = defined?(RAILS_ENV) ? RAILS_ENV : ENV.fetch("RAILS_ENV", "development")
14
+ smoketests = AntiSmoker.load("config/antismoker.yml", :env => env)
15
+ results = AntiSmoker.run(smoketests)
16
+ abort unless results.all?
17
+ end
18
+ end
19
+
20
+ # vim:set ft=ruby ts=2 sw=2 :
metadata ADDED
@@ -0,0 +1,76 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: antismoker
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ prerelease:
6
+ platform: ruby
7
+ authors:
8
+ - Yamashita Yuu
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2012-11-30 00:00:00.000000000 Z
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ name: rake
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
+ description: Yet another HTTP smoke testing framework.
31
+ email:
32
+ - yamashita@geishatokyo.com
33
+ executables: []
34
+ extensions: []
35
+ extra_rdoc_files: []
36
+ files:
37
+ - .gitignore
38
+ - Gemfile
39
+ - LICENSE
40
+ - README.md
41
+ - Rakefile
42
+ - antismoker.gemspec
43
+ - lib/antismoker.rb
44
+ - lib/antismoker/capistrano.rb
45
+ - lib/antismoker/deployment.rb
46
+ - lib/antismoker/loader.rb
47
+ - lib/antismoker/runner.rb
48
+ - lib/antismoker/tests.rb
49
+ - lib/antismoker/tests/http.rb
50
+ - lib/antismoker/version.rb
51
+ - lib/tasks/antismoker.rake
52
+ homepage: https://github.com/yyuu/antismoker
53
+ licenses: []
54
+ post_install_message:
55
+ rdoc_options: []
56
+ require_paths:
57
+ - lib
58
+ required_ruby_version: !ruby/object:Gem::Requirement
59
+ none: false
60
+ requirements:
61
+ - - ! '>='
62
+ - !ruby/object:Gem::Version
63
+ version: '0'
64
+ required_rubygems_version: !ruby/object:Gem::Requirement
65
+ none: false
66
+ requirements:
67
+ - - ! '>='
68
+ - !ruby/object:Gem::Version
69
+ version: '0'
70
+ requirements: []
71
+ rubyforge_project:
72
+ rubygems_version: 1.8.23
73
+ signing_key:
74
+ specification_version: 3
75
+ summary: Yet another HTTP smoke testing framework.
76
+ test_files: []