antismoker 0.0.1

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