hot_or_not 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
data/.document ADDED
@@ -0,0 +1,5 @@
1
+ lib/**/*.rb
2
+ bin/*
3
+ -
4
+ features/**/*.feature
5
+ LICENSE.txt
data/Gemfile ADDED
@@ -0,0 +1,18 @@
1
+ source "http://rubygems.org"
2
+ # Add dependencies required to use your gem here.
3
+ # Example:
4
+ # gem "activesupport", ">= 2.3.5"
5
+
6
+ # Add dependencies to develop your gem here.
7
+ # Include everything needed to run rake, tests, features, etc.
8
+ group :development do
9
+ gem "shoulda", ">= 0"
10
+ gem "bundler", "~> 1.0.0"
11
+ gem "jeweler", "~> 1.6.0"
12
+ gem "rcov", ">= 0"
13
+ gem "mocha"
14
+ end
15
+
16
+ gem 'rest-client', '~> 1.6.1'
17
+ gem 'diffy', '~> 2.0.1'
18
+ gem 'facets', '~> 2.9.1'
data/Gemfile.lock ADDED
@@ -0,0 +1,30 @@
1
+ GEM
2
+ remote: http://rubygems.org/
3
+ specs:
4
+ diffy (2.0.1)
5
+ facets (2.9.1)
6
+ git (1.2.5)
7
+ jeweler (1.6.0)
8
+ bundler (~> 1.0.0)
9
+ git (>= 1.2.5)
10
+ rake
11
+ mime-types (1.16)
12
+ mocha (0.9.12)
13
+ rake (0.8.7)
14
+ rcov (0.9.9)
15
+ rest-client (1.6.1)
16
+ mime-types (>= 1.16)
17
+ shoulda (2.11.3)
18
+
19
+ PLATFORMS
20
+ ruby
21
+
22
+ DEPENDENCIES
23
+ bundler (~> 1.0.0)
24
+ diffy (~> 2.0.1)
25
+ facets (~> 2.9.1)
26
+ jeweler (~> 1.6.0)
27
+ mocha
28
+ rcov
29
+ rest-client (~> 1.6.1)
30
+ shoulda
data/LICENSE.txt ADDED
@@ -0,0 +1,20 @@
1
+ Copyright (c) 2011 Joel Friedman
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ "Software"), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.rdoc ADDED
@@ -0,0 +1,19 @@
1
+ = hot_or_not
2
+
3
+ Description goes here.
4
+
5
+ == Contributing to hot_or_not
6
+
7
+ * Check out the latest master to make sure the feature hasn't been implemented or the bug hasn't been fixed yet
8
+ * Check out the issue tracker to make sure someone already hasn't requested it and/or contributed it
9
+ * Fork the project
10
+ * Start a feature/bugfix branch
11
+ * Commit and push until you are happy with your contribution
12
+ * Make sure to add tests for it. This is important so I don't break it in a future version unintentionally.
13
+ * Please try not to mess with the Rakefile, version, or history. If you want to have your own version, or is otherwise necessary, that is fine, but please isolate to its own commit so I can cherry-pick around it.
14
+
15
+ == Copyright
16
+
17
+ Copyright (c) 2011 Joel Friedman. See LICENSE.txt for
18
+ further details.
19
+
data/Rakefile ADDED
@@ -0,0 +1,54 @@
1
+ # encoding: utf-8
2
+
3
+ require 'rubygems'
4
+ require 'bundler'
5
+ begin
6
+ Bundler.setup(:default, :development)
7
+ rescue Bundler::BundlerError => e
8
+ $stderr.puts e.message
9
+ $stderr.puts "Run `bundle install` to install missing gems"
10
+ exit e.status_code
11
+ end
12
+ require 'rake'
13
+
14
+ require 'jeweler'
15
+ Jeweler::Tasks.new do |gem|
16
+ # gem is a Gem::Specification... see http://docs.rubygems.org/read/chapter/20 for more options
17
+ gem.name = "hot_or_not"
18
+ gem.homepage = "https://github.com/joelash/hot_or_not"
19
+ gem.license = "MIT"
20
+ gem.summary = %Q{A tool for side-by-side comparsion of web apis}
21
+ gem.description = %Q{Run this with a new version of your site comparing to current version to verify no break changes are made to your api's}
22
+ gem.email = "asher.friedman@gmail.com"
23
+ gem.authors = ["Joel Friedman"]
24
+ gem.executables = ['hot_or_not']
25
+ # dependencies defined in Gemfile
26
+ end
27
+ Jeweler::RubygemsDotOrgTasks.new
28
+
29
+ require 'rake/testtask'
30
+ Rake::TestTask.new(:test) do |test|
31
+ test.libs << 'lib' << 'test'
32
+ test.pattern = 'test/**/*_test.rb'
33
+ test.verbose = true
34
+ end
35
+
36
+ require 'rcov/rcovtask'
37
+ Rcov::RcovTask.new do |test|
38
+ test.libs << 'test'
39
+ test.pattern = 'test/**/*_test.rb'
40
+ test.verbose = true
41
+ test.rcov_opts << '--exclude "gems/*"'
42
+ end
43
+
44
+ task :default => :test
45
+
46
+ require 'rake/rdoctask'
47
+ Rake::RDocTask.new do |rdoc|
48
+ version = File.exist?('VERSION') ? File.read('VERSION') : ""
49
+
50
+ rdoc.rdoc_dir = 'rdoc'
51
+ rdoc.title = "hot_or_not #{version}"
52
+ rdoc.rdoc_files.include('README*')
53
+ rdoc.rdoc_files.include('lib/**/*.rb')
54
+ end
data/VERSION ADDED
@@ -0,0 +1 @@
1
+ 0.1.0
data/bin/hot_or_not ADDED
@@ -0,0 +1,47 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require 'rubygems'
4
+ require File.dirname(__FILE__) + '/../lib/hot_or_not'
5
+ require 'optparse'
6
+
7
+ defaults = {
8
+ :output_directory => 'test_results'
9
+ }
10
+
11
+ options = {}
12
+ parser = ::OptionParser.new do |opts|
13
+ opts.banner = "Usage: hot_or_not [options] URL_FILE"
14
+ opts.on("-o", "--output-dir", "Ouput directory. DEFAULT: #{defaults[:output_directory]}") do |d|
15
+ options[:output_directory] = d
16
+ end
17
+
18
+ opts.on_tail("--example-file", "Output contents of example file") do
19
+ puts
20
+ puts File.read(File.dirname(__FILE__) + '/../test/data/simple_urls.yml')
21
+ exit
22
+ end
23
+
24
+ opts.on_tail("-h", "--help", "Show this message") do
25
+ puts opts
26
+ exit
27
+ end
28
+ end
29
+
30
+ begin
31
+ parser.parse!
32
+ rescue OptionParser::InvalidOption => e
33
+ puts e.message
34
+ puts parser
35
+ exit
36
+ end
37
+
38
+ options = defaults.merge options
39
+
40
+ yaml_file = ARGV[0]
41
+ unless File.exists? yaml_file
42
+ puts "hot_or_not: no such file - #{yaml_file}"
43
+ exit
44
+ end
45
+
46
+ announcer = HotOrNot::ConsoleAnnouncer.new options[:output_directory]
47
+ HotOrNot::Runner.run_from(yaml_file, announcer).run!
@@ -0,0 +1,18 @@
1
+ module HotOrNot
2
+ module Announcer
3
+ def announce_success(result)
4
+ end
5
+
6
+ def announce_failure(result)
7
+ end
8
+
9
+ def announce_error(url, error)
10
+ end
11
+
12
+ def starting
13
+ end
14
+
15
+ def ending
16
+ end
17
+ end
18
+ end
@@ -0,0 +1,72 @@
1
+ module HotOrNot
2
+ class ConsoleAnnouncer
3
+ include Announcer
4
+
5
+ def initialize(output_dir)
6
+ @output_dir = output_dir
7
+ @start, @results = nil, []
8
+ @output_count = 0
9
+ end
10
+
11
+ def starting
12
+ puts "Starting to compare the bodies"
13
+ @start = Time.now
14
+ end
15
+
16
+ def ending
17
+ completion_time = Time.now - @start
18
+ counts = Hash.new(0)
19
+ puts
20
+ @results.each do |result_hash|
21
+ status = result_hash[:status]
22
+ send :"output_#{status}", result_hash
23
+ counts[status] += 1
24
+ end
25
+
26
+ puts "Finsihed in %.6f seconds." % [completion_time]
27
+ puts
28
+ puts "#{@results.count} body comparisons, #{counts[:success]} hot bodies, #{counts[:failure]} not-hot bodies, #{counts[:error]} errored bodies"
29
+ end
30
+
31
+ def announce_success(result)
32
+ @results << { :status => :success, :result => result }
33
+ print "."
34
+ end
35
+
36
+ def announce_failure(result)
37
+ @results << { :status => :failure, :result => result }
38
+ print "N"
39
+ end
40
+
41
+ def announce_error(url, error)
42
+ @results << { :status => :error, :url => url, :error => error }
43
+ print "E"
44
+ end
45
+
46
+ private
47
+ def output_success result_hash
48
+ #do nothing
49
+ end
50
+
51
+ def output_failure result_hash
52
+ result_hash[:result].output_to_files_in results_dir
53
+ to_console "Not Hot:#{$/}#{result_hash[:result].message}"
54
+ end
55
+
56
+ def output_error result_hash
57
+ to_console "Error:#{$/}Retreiving #{result_hash[:url].url} raised error: #{result_hash[:error].message}#{$/}#{result_hash[:error].backtrace.join($/)}"
58
+ end
59
+
60
+ def to_console(message)
61
+ @output_count += 1
62
+ puts " #{@output_count}) #{message}"
63
+ end
64
+
65
+ def results_dir
66
+ @results_dir ||= @output_dir.tap do |dir|
67
+ FileUtils.rm_rf dir
68
+ FileUtils.mkdir_p dir
69
+ end
70
+ end
71
+ end
72
+ end
@@ -0,0 +1,45 @@
1
+ module HotOrNot
2
+ class CompareUrl
3
+
4
+ attr_reader :url, :base_a, :base_b, :options
5
+
6
+ def initialize(name, url, base_a, base_b, options={})
7
+ @name, @url, @base_a, @base_b = name, url, base_a, base_b
8
+ @options = options
9
+ end
10
+
11
+ def full_name
12
+ @name
13
+ end
14
+
15
+ def short_name
16
+ @short_name ||= @name.underscore.gsub(/\s+/, '_')
17
+ end
18
+
19
+ def side_a
20
+ @side_a ||= @base_a + @url
21
+ end
22
+
23
+ def side_b
24
+ @side_b ||= @base_b + @url
25
+ end
26
+
27
+ def self.load_from(filename)
28
+ contents = YAML.load run_erb filename
29
+ side_a, side_b, comparisons = contents['side_a'], contents['side_b'], contents['comparisons']
30
+ raise "You're file is not of the proper format" unless side_a && side_b && comparisons
31
+ comparisons.map do |h|
32
+ h.symbolize_keys!
33
+ name = h.delete :name
34
+ url = h.delete :url
35
+ CompareUrl.new name, url, side_a, side_b, h
36
+ end
37
+ end
38
+
39
+ private
40
+ def self.run_erb(filename)
41
+ contents = IO.read filename
42
+ ERB.new(contents).result
43
+ end
44
+ end
45
+ end
@@ -0,0 +1,72 @@
1
+ module HotOrNot
2
+ class ComparisonResult
3
+
4
+ DEFAULT_OPTIONS = { :method => :get }
5
+ class << self
6
+ def for(compare_url)
7
+ options = DEFAULT_OPTIONS.merge compare_url.options
8
+ new compare_url, retreive(compare_url.side_a, options), retreive(compare_url.side_b, options)
9
+ end
10
+
11
+ private
12
+ def retreive(url, options)
13
+ options[:url] = url
14
+ RestClient::Request.execute(options).tap { |r| raise Exception.new("Invalid response code #{r.code} for '#{url}'") unless r.code.to_s == '200' }
15
+ end
16
+ end
17
+
18
+ attr_reader :message
19
+
20
+ def initialize(compare_url, side_a_results, side_b_results)
21
+ @compare_url, @side_a_results, @side_b_results = compare_url, side_a_results, side_b_results
22
+ @message, @diff = '', ''
23
+ init
24
+ end
25
+
26
+ def success?
27
+ @success
28
+ end
29
+
30
+ def side_a_body
31
+ @side_a_body ||= body_by_content_type @side_a_results
32
+ end
33
+
34
+ def side_b_body
35
+ @side_b_body ||= body_by_content_type @side_b_results
36
+ end
37
+
38
+ def diff(format = :text)
39
+ @diff.to_s format
40
+ end
41
+
42
+ def output_to_files_in(directory)
43
+ write_to directory, "side_a", side_a_body
44
+ write_to directory, "side_b", side_b_body
45
+ write_to directory, "diff", diff
46
+ end
47
+
48
+ private
49
+ def init
50
+ return if @success = side_a_body == side_b_body
51
+ @message = "#{@compare_url.full_name}: #{@compare_url.url}: Body from #{@compare_url.base_a} did not match body from #{@compare_url.base_b}"
52
+ @diff = Diffy::Diff.new(side_a_body, side_b_body)
53
+ end
54
+
55
+ def body_by_content_type(result)
56
+ case result.headers[:content_type]
57
+ when /json/i
58
+ h = JSON.parse result.body
59
+ JSON.pretty_generate h
60
+ else
61
+ result.body
62
+ end
63
+ end
64
+
65
+ def write_to(directory, ext, text)
66
+ filename = File.join(directory, "#{@compare_url.short_name}.#{ext}")
67
+ File.open(filename, 'w+') do |f|
68
+ f << text
69
+ end
70
+ end
71
+ end
72
+ end
@@ -0,0 +1,28 @@
1
+ module HotOrNot
2
+ class Runner
3
+ def self.run_from(file, announcer)
4
+ new CompareUrl.load_from(file), announcer
5
+ end
6
+
7
+ def initialize(urls, announcer)
8
+ @urls, @announcer = urls, announcer
9
+ end
10
+
11
+ def run!
12
+ @announcer.starting
13
+ @urls.each do |url|
14
+ begin
15
+ result = ComparisonResult.for url
16
+ if result.success?
17
+ @announcer.announce_success result
18
+ else
19
+ @announcer.announce_failure result
20
+ end
21
+ rescue StandardError, Exception => e
22
+ @announcer.announce_error url, e
23
+ end
24
+ end
25
+ @announcer.ending
26
+ end
27
+ end
28
+ end
data/lib/hot_or_not.rb ADDED
@@ -0,0 +1,8 @@
1
+ require 'json'
2
+
3
+ require 'rest-client'
4
+ require 'diffy'
5
+ require 'yaml'
6
+ require 'facets'
7
+
8
+ Dir.glob(File.dirname(__FILE__) + '/hot_or_not/**/*.rb').each { |f| require f }
@@ -0,0 +1,71 @@
1
+ require File.dirname(__FILE__) + '/test_helper'
2
+
3
+ module HotOrNot
4
+ class CompareUrlTest < Test::Unit::TestCase
5
+ context "load from file" do
6
+ setup do
7
+ @urls = CompareUrl.load_from File.dirname(__FILE__) + '/data/simple_urls.yml'
8
+ end
9
+
10
+ should "load right number of comparisons" do
11
+ assert_equal 2, @urls.count
12
+ end
13
+
14
+ should "load all urls" do
15
+ assert_equal 'People Test', @urls[0].full_name
16
+ assert_equal 'Names Test', @urls[1].full_name
17
+ end
18
+
19
+ should "load options from file" do
20
+ expected_options = { :headers => { 'authorization' => 'foo123bar' } }
21
+ assert_equal expected_options, @urls[1].options
22
+ end
23
+ end
24
+
25
+ context "load from file with erb" do
26
+ setup do
27
+ @urls = CompareUrl.load_from File.dirname(__FILE__) + '/data/simple_urls.yml.erb'
28
+ end
29
+
30
+ should "load all comparisons" do
31
+ assert_equal 2, @urls.count
32
+ end
33
+
34
+ should "run erb on the file" do
35
+ assert_equal "People Test #{Date.today}", @urls[0].full_name
36
+ end
37
+ end
38
+
39
+ context "object" do
40
+ setup do
41
+ @compare_url = CompareUrl.new 'Foo Url', '/api/foo', 'http://side_a', 'http://side_b'
42
+ end
43
+
44
+ should "contain a test name" do
45
+ assert_equal "Foo Url", @compare_url.full_name
46
+ assert_equal "foo_url", @compare_url.short_name
47
+ end
48
+
49
+ should "create urls for the side_b release" do
50
+ assert_equal 'http://side_a/api/foo', @compare_url.side_a
51
+ assert_equal 'http://side_b/api/foo', @compare_url.side_b
52
+ end
53
+
54
+ should "default options to empty hash" do
55
+ expected_options = {}
56
+ assert_equal expected_options, @compare_url.options
57
+ end
58
+ end
59
+
60
+ context "object with options" do
61
+ setup do
62
+ @compare_url = CompareUrl.new 'Foo Url', '/api/foo', 'http://side_a', 'http://side_b', :headers => { 'authorization' => 'baz321' }
63
+ end
64
+
65
+ should "read provid options as passed in" do
66
+ expected_options = { :headers => { 'authorization' => 'baz321' } }
67
+ assert_equal expected_options, @compare_url.options
68
+ end
69
+ end
70
+ end
71
+ end
@@ -0,0 +1,53 @@
1
+ require File.dirname(__FILE__) + '/test_helper'
2
+
3
+ module HotOrNot
4
+ class ComparisonResultTest < Test::Unit::TestCase
5
+ context "comparing results" do
6
+ setup do
7
+ @compare_url = CompareUrl.new 'Test People', '/api/people', 'http://side_a', 'http://side_b'
8
+ end
9
+
10
+ context "500 error" do
11
+ setup do
12
+ RestClient::Request.expects(:execute).with(:method => :get, :url => @compare_url.side_a).returns FakeResponse.new('foo', 500)
13
+ end
14
+
15
+ should "raise error when response code is not 200" do
16
+ assert_raises(Exception) { ComparisonResult.for @compare_url }
17
+ end
18
+ end
19
+
20
+ context "when results match" do
21
+ setup do
22
+ RestClient::Request.expects(:execute).with(:method => :get, :url => @compare_url.side_a).returns FakeResponse.new 'foo'
23
+ RestClient::Request.expects(:execute).with(:method => :get, :url => @compare_url.side_b).returns FakeResponse.new 'foo'
24
+ @result = ComparisonResult.for @compare_url
25
+ end
26
+
27
+ should "return success" do
28
+ assert @result.success?
29
+ end
30
+ end
31
+
32
+ context "when results don't match" do
33
+ setup do
34
+ RestClient::Request.expects(:execute).with(:method => :get, :url => @compare_url.side_a).returns FakeResponse.new 'side_a'
35
+ RestClient::Request.expects(:execute).with(:method => :get, :url => @compare_url.side_b).returns FakeResponse.new 'side_b'
36
+ @result = ComparisonResult.for @compare_url
37
+ end
38
+
39
+ should "not return success" do
40
+ assert_not @result.success?
41
+ end
42
+
43
+ should "have test unit style failure message" do
44
+ assert_match @result.message, /Test People:.*?\/api\/people/
45
+ end
46
+
47
+ should "provide a diff" do
48
+ assert_present @result.diff
49
+ end
50
+ end
51
+ end
52
+ end
53
+ end
@@ -0,0 +1,67 @@
1
+ require File.dirname(__FILE__) + '/test_helper'
2
+
3
+ module HotOrNot
4
+ class ConsoleAnnouncerTest < Test::Unit::TestCase
5
+ context "run" do
6
+ setup do
7
+ intercept_io
8
+ output_dir = 'test_results'
9
+ @announcer = ConsoleAnnouncer.new output_dir
10
+ end
11
+
12
+ teardown do
13
+ reset_io
14
+ end
15
+
16
+ context "the console output" do
17
+ should "print '.' for passing test" do
18
+ urls = [mock_compare_url('Foo', '/api/foo', 'foo', 'foo')]
19
+ Runner.new(urls, @announcer).run!
20
+
21
+ assert_equal '.', test_output[1].chomp
22
+ end
23
+
24
+ should "print 'N' for a failing test" do
25
+ urls = [mock_compare_url('Foo', '/api/foo', 'foo', 'bar')]
26
+ Runner.new(urls, @announcer).run!
27
+
28
+ output = test_output
29
+ assert_equal 'N', output[1].chomp
30
+ assert_equal ' 1) Not Hot:', output[2].chomp
31
+ end
32
+
33
+ should "print 'E' for a test that errors out" do
34
+ urls = [mock_compare_url('Foo', '/api/foo', 'foo', 'bar', 404)]
35
+ Runner.new(urls, @announcer).run!
36
+
37
+ o = test_output
38
+ assert_equal 'E', o[1].chomp
39
+ end
40
+ end
41
+
42
+ end
43
+
44
+ private
45
+ def intercept_io
46
+ @output_filename = 'test_runner_tests.txt'
47
+ @output_file = File.open(@output_filename, 'w+')
48
+ @orig_stdout = STDOUT.dup
49
+ STDOUT.reopen(@output_file)
50
+ end
51
+
52
+ def reset_io
53
+ @output_file.close
54
+ FileUtils.rm_f @output_filename if leave_last_ouput?
55
+ STDOUT.reopen @orig_stdout
56
+ end
57
+
58
+ def leave_last_ouput?
59
+ ENV['HORN_io'].to_s.downcase != 'false'
60
+ end
61
+
62
+ def test_output
63
+ STDOUT.flush
64
+ File.readlines(@output_file)
65
+ end
66
+ end
67
+ end
@@ -0,0 +1,9 @@
1
+ side_a: 'http://side_a'
2
+ side_b: 'http://side_b'
3
+ comparisons:
4
+ - name: People Test
5
+ url: /api/people
6
+ - name: Names Test
7
+ url: /api/names
8
+ headers:
9
+ authorization: foo123bar
@@ -0,0 +1,7 @@
1
+ side_a: 'http://side_a'
2
+ side_b: 'http://side_b'
3
+ comparisons:
4
+ - name: People Test <%= Date.today %>
5
+ url: /api/people
6
+ - name: Names Test
7
+ url: /api/names
@@ -0,0 +1,102 @@
1
+ require File.dirname(__FILE__) + '/test_helper'
2
+
3
+ module HotOrNot
4
+ class RunnerTest < Test::Unit::TestCase
5
+ def initialize(*args)
6
+ @announcer = Class.new do
7
+ include Announcer
8
+
9
+ attr_reader :messages
10
+ def initialize
11
+ @messages = {}
12
+ end
13
+
14
+ def starting
15
+ @messages[:starting] = true
16
+ end
17
+
18
+ def ending
19
+ @messages[:ending] = true
20
+ end
21
+
22
+ def announce_success(result)
23
+ @messages[:success] = true
24
+ end
25
+
26
+ def announce_failure(result)
27
+ @messages[:failure] = true
28
+ end
29
+
30
+ def announce_error(url, error)
31
+ @messages[:error] = true
32
+ end
33
+ end.new
34
+
35
+ super
36
+ end
37
+
38
+ context "successful comparison" do
39
+ setup do
40
+ urls = [mock_compare_url('Foo', '/api/foo', 'foo', 'foo')]
41
+ Runner.new(urls, @announcer).run!
42
+ end
43
+
44
+ should "announce starting" do
45
+ assert @announcer.messages[:starting]
46
+ end
47
+
48
+ should "announce ending" do
49
+ assert @announcer.messages[:ending]
50
+ end
51
+
52
+ should "only annouce success" do
53
+ assert @announcer.messages[:success]
54
+ assert_false @announcer.messages[:failure]
55
+ assert_false @announcer.messages[:error]
56
+ end
57
+ end
58
+
59
+ context "failing comparison" do
60
+ setup do
61
+ urls = [mock_compare_url('Foo', '/api/foo', 'foo', 'bar')]
62
+ Runner.new(urls, @announcer).run!
63
+ end
64
+
65
+ should "announce starting" do
66
+ assert @announcer.messages[:starting]
67
+ end
68
+
69
+ should "announce ending" do
70
+ assert @announcer.messages[:ending]
71
+ end
72
+
73
+ should "only annouce failure" do
74
+ assert @announcer.messages[:failure]
75
+ assert_false @announcer.messages[:success]
76
+ assert_false @announcer.messages[:error]
77
+ end
78
+ end
79
+
80
+ context "error during comparison" do
81
+ setup do
82
+ urls = [mock_compare_url('Foo', '/api/foo', 'foo', 'bar', 404)]
83
+ Runner.new(urls, @announcer).run!
84
+ end
85
+
86
+ should "announce starting" do
87
+ assert @announcer.messages[:starting]
88
+ end
89
+
90
+ should "announce ending" do
91
+ assert @announcer.messages[:ending]
92
+ end
93
+
94
+ should "only annouce error" do
95
+ assert @announcer.messages[:error]
96
+ assert_false @announcer.messages[:success]
97
+ assert_false @announcer.messages[:failure]
98
+ end
99
+ end
100
+
101
+ end
102
+ end
@@ -0,0 +1,46 @@
1
+ require 'rubygems'
2
+ require 'bundler'
3
+ begin
4
+ Bundler.setup(:default, :development)
5
+ rescue Bundler::BundlerError => e
6
+ $stderr.puts e.message
7
+ $stderr.puts "Run `bundle install` to install missing gems"
8
+ exit e.status_code
9
+ end
10
+ require 'test/unit'
11
+ require 'shoulda'
12
+ require 'mocha'
13
+
14
+ $LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
15
+ $LOAD_PATH.unshift(File.dirname(__FILE__))
16
+ require 'hot_or_not'
17
+
18
+ module HotOrNot
19
+ class FakeResponse
20
+ attr_reader :body, :code, :headers
21
+ def initialize(body, code = '200', headers = {})
22
+ @body, @code = body, code
23
+ @headers = { :content_type => 'html' }.merge headers
24
+ end
25
+ end
26
+ end
27
+
28
+ class Test::Unit::TestCase
29
+ def assert_false(truth, message=nil)
30
+ assert !truth, message
31
+ end
32
+ alias_method :assert_not, :assert_false
33
+
34
+ def assert_present(text)
35
+ assert_not_nil text
36
+ assert_not text.empty?, "#{text} was expected to not be empty"
37
+ end
38
+
39
+ private
40
+ def mock_compare_url(name, url, body_a, body_b, code='200')
41
+ HotOrNot::CompareUrl.new(name, url, 'http://side_a', 'http://side_b').tap do |compare_url|
42
+ RestClient::Request.expects(:execute).with(:method => :get, :url => compare_url.side_a).returns HotOrNot::FakeResponse.new(body_a, code)
43
+ RestClient::Request.expects(:execute).with(:method => :get, :url => compare_url.side_b).returns HotOrNot::FakeResponse.new(body_b, code) if code.to_s == '200'
44
+ end
45
+ end
46
+ end
metadata ADDED
@@ -0,0 +1,209 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: hot_or_not
3
+ version: !ruby/object:Gem::Version
4
+ hash: 27
5
+ prerelease: false
6
+ segments:
7
+ - 0
8
+ - 1
9
+ - 0
10
+ version: 0.1.0
11
+ platform: ruby
12
+ authors:
13
+ - Joel Friedman
14
+ autorequire:
15
+ bindir: bin
16
+ cert_chain: []
17
+
18
+ date: 2011-06-08 00:00:00 -05:00
19
+ default_executable: hot_or_not
20
+ dependencies:
21
+ - !ruby/object:Gem::Dependency
22
+ name: rest-client
23
+ requirement: &id001 !ruby/object:Gem::Requirement
24
+ none: false
25
+ requirements:
26
+ - - ~>
27
+ - !ruby/object:Gem::Version
28
+ hash: 13
29
+ segments:
30
+ - 1
31
+ - 6
32
+ - 1
33
+ version: 1.6.1
34
+ type: :runtime
35
+ prerelease: false
36
+ version_requirements: *id001
37
+ - !ruby/object:Gem::Dependency
38
+ name: diffy
39
+ requirement: &id002 !ruby/object:Gem::Requirement
40
+ none: false
41
+ requirements:
42
+ - - ~>
43
+ - !ruby/object:Gem::Version
44
+ hash: 13
45
+ segments:
46
+ - 2
47
+ - 0
48
+ - 1
49
+ version: 2.0.1
50
+ type: :runtime
51
+ prerelease: false
52
+ version_requirements: *id002
53
+ - !ruby/object:Gem::Dependency
54
+ name: facets
55
+ requirement: &id003 !ruby/object:Gem::Requirement
56
+ none: false
57
+ requirements:
58
+ - - ~>
59
+ - !ruby/object:Gem::Version
60
+ hash: 41
61
+ segments:
62
+ - 2
63
+ - 9
64
+ - 1
65
+ version: 2.9.1
66
+ type: :runtime
67
+ prerelease: false
68
+ version_requirements: *id003
69
+ - !ruby/object:Gem::Dependency
70
+ name: shoulda
71
+ requirement: &id004 !ruby/object:Gem::Requirement
72
+ none: false
73
+ requirements:
74
+ - - ">="
75
+ - !ruby/object:Gem::Version
76
+ hash: 3
77
+ segments:
78
+ - 0
79
+ version: "0"
80
+ type: :development
81
+ prerelease: false
82
+ version_requirements: *id004
83
+ - !ruby/object:Gem::Dependency
84
+ name: bundler
85
+ requirement: &id005 !ruby/object:Gem::Requirement
86
+ none: false
87
+ requirements:
88
+ - - ~>
89
+ - !ruby/object:Gem::Version
90
+ hash: 23
91
+ segments:
92
+ - 1
93
+ - 0
94
+ - 0
95
+ version: 1.0.0
96
+ type: :development
97
+ prerelease: false
98
+ version_requirements: *id005
99
+ - !ruby/object:Gem::Dependency
100
+ name: jeweler
101
+ requirement: &id006 !ruby/object:Gem::Requirement
102
+ none: false
103
+ requirements:
104
+ - - ~>
105
+ - !ruby/object:Gem::Version
106
+ hash: 15
107
+ segments:
108
+ - 1
109
+ - 6
110
+ - 0
111
+ version: 1.6.0
112
+ type: :development
113
+ prerelease: false
114
+ version_requirements: *id006
115
+ - !ruby/object:Gem::Dependency
116
+ name: rcov
117
+ requirement: &id007 !ruby/object:Gem::Requirement
118
+ none: false
119
+ requirements:
120
+ - - ">="
121
+ - !ruby/object:Gem::Version
122
+ hash: 3
123
+ segments:
124
+ - 0
125
+ version: "0"
126
+ type: :development
127
+ prerelease: false
128
+ version_requirements: *id007
129
+ - !ruby/object:Gem::Dependency
130
+ name: mocha
131
+ requirement: &id008 !ruby/object:Gem::Requirement
132
+ none: false
133
+ requirements:
134
+ - - ">="
135
+ - !ruby/object:Gem::Version
136
+ hash: 3
137
+ segments:
138
+ - 0
139
+ version: "0"
140
+ type: :development
141
+ prerelease: false
142
+ version_requirements: *id008
143
+ description: Run this with a new version of your site comparing to current version to verify no break changes are made to your api's
144
+ email: asher.friedman@gmail.com
145
+ executables:
146
+ - hot_or_not
147
+ extensions: []
148
+
149
+ extra_rdoc_files:
150
+ - LICENSE.txt
151
+ - README.rdoc
152
+ files:
153
+ - .document
154
+ - Gemfile
155
+ - Gemfile.lock
156
+ - LICENSE.txt
157
+ - README.rdoc
158
+ - Rakefile
159
+ - VERSION
160
+ - bin/hot_or_not
161
+ - lib/hot_or_not.rb
162
+ - lib/hot_or_not/announcer.rb
163
+ - lib/hot_or_not/announcers/console_announcer.rb
164
+ - lib/hot_or_not/compare_url.rb
165
+ - lib/hot_or_not/comparison_result.rb
166
+ - lib/hot_or_not/runner.rb
167
+ - test/compare_url_test.rb
168
+ - test/comparison_result_test.rb
169
+ - test/console_announcer_test.rb
170
+ - test/data/simple_urls.yml
171
+ - test/data/simple_urls.yml.erb
172
+ - test/runner_test.rb
173
+ - test/test_helper.rb
174
+ has_rdoc: true
175
+ homepage: https://github.com/joelash/hot_or_not
176
+ licenses:
177
+ - MIT
178
+ post_install_message:
179
+ rdoc_options: []
180
+
181
+ require_paths:
182
+ - lib
183
+ required_ruby_version: !ruby/object:Gem::Requirement
184
+ none: false
185
+ requirements:
186
+ - - ">="
187
+ - !ruby/object:Gem::Version
188
+ hash: 3
189
+ segments:
190
+ - 0
191
+ version: "0"
192
+ required_rubygems_version: !ruby/object:Gem::Requirement
193
+ none: false
194
+ requirements:
195
+ - - ">="
196
+ - !ruby/object:Gem::Version
197
+ hash: 3
198
+ segments:
199
+ - 0
200
+ version: "0"
201
+ requirements: []
202
+
203
+ rubyforge_project:
204
+ rubygems_version: 1.3.7
205
+ signing_key:
206
+ specification_version: 3
207
+ summary: A tool for side-by-side comparsion of web apis
208
+ test_files: []
209
+