Skip to content

Commit

Permalink
Automate discovery of broken URIs.
Browse files Browse the repository at this point in the history
  • Loading branch information
georgebrock committed Jan 10, 2013
1 parent b03f863 commit 0a58805
Show file tree
Hide file tree
Showing 11 changed files with 169 additions and 10 deletions.
2 changes: 2 additions & 0 deletions Gemfile
Expand Up @@ -4,6 +4,8 @@ ruby '1.9.3'


gem 'bourne' gem 'bourne'
gem 'colored' gem 'colored'
gem 'httparty'
gem 'json' gem 'json'
gem 'mocha', require: false gem 'mocha', require: false
gem 'rspec' gem 'rspec'
gem 'webmock'
14 changes: 12 additions & 2 deletions Gemfile.lock
@@ -1,15 +1,21 @@
GEM GEM
remote: http://rubygems.org/ remote: http://rubygems.org/
specs: specs:
awesome_print (1.1.0) addressable (2.3.2)
bourne (1.2.0) bourne (1.2.0)
mocha (= 0.12.3) mocha (= 0.12.3)
colored (1.2) colored (1.2)
crack (0.3.2)
diff-lcs (1.1.3) diff-lcs (1.1.3)
httparty (0.9.0)
multi_json (~> 1.0)
multi_xml
json (1.7.5) json (1.7.5)
metaclass (0.0.1) metaclass (0.0.1)
mocha (0.12.3) mocha (0.12.3)
metaclass (~> 0.0.1) metaclass (~> 0.0.1)
multi_json (1.5.0)
multi_xml (0.5.1)
rspec (2.12.0) rspec (2.12.0)
rspec-core (~> 2.12.0) rspec-core (~> 2.12.0)
rspec-expectations (~> 2.12.0) rspec-expectations (~> 2.12.0)
Expand All @@ -18,14 +24,18 @@ GEM
rspec-expectations (2.12.0) rspec-expectations (2.12.0)
diff-lcs (~> 1.1.3) diff-lcs (~> 1.1.3)
rspec-mocks (2.12.0) rspec-mocks (2.12.0)
webmock (1.9.0)
addressable (>= 2.2.7)
crack (>= 0.1.7)


PLATFORMS PLATFORMS
ruby ruby


DEPENDENCIES DEPENDENCIES
awesome_print
bourne bourne
colored colored
httparty
json json
mocha mocha
rspec rspec
webmock
2 changes: 2 additions & 0 deletions lib/helpers/json_validator.rb
Expand Up @@ -13,8 +13,10 @@ def run
def check_json_validation def check_json_validation
if valid_json? if valid_json?
print_progress_marker print_progress_marker
return true
else else
print_error_message print_error_message
return false
end end
end end


Expand Down
4 changes: 3 additions & 1 deletion lib/helpers/trail_runner.rb
Expand Up @@ -15,7 +15,9 @@ def print_starting_message
end end


def run_validations_on_json_files def run_validations_on_json_files
json_files.each { |file| JSONValidator.new(file).run } json_files.each do |file|
JSONValidator.new(file).run && URIValidator.new(file).run
end
end end


def json_files def json_files
Expand Down
45 changes: 45 additions & 0 deletions lib/helpers/uri_extractor.rb
@@ -0,0 +1,45 @@
class URIExtractor
def initialize(file_name)
@file_name = file_name
contents = File.read(@file_name)
@json = JSON.parse(contents)
end

def each(&block)
uris.each(&block)
end

private

def uris
@uris ||= extract_uris(@json)
end

def extract_uris(source)
if source.is_a?(Hash)
extract_uris_from_hash(source)
elsif source.is_a?(Array)
extract_uris_from_array(source)
else
[]
end
end

def extract_uris_from_hash(hash)
uris = []

hash.each do |key, value|
if key == 'uri'
uris << value
else
uris += extract_uris(value)
end
end

uris
end

def extract_uris_from_array(array)
array.map { |o| extract_uris(o) }.flatten
end
end
38 changes: 38 additions & 0 deletions lib/helpers/uri_validator.rb
@@ -0,0 +1,38 @@
require 'httparty'

class URIValidator
def initialize(file_name)
@file_name = file_name
end

def run
uris.each do |uri|
if valid_uri?(uri)
print_progress_marker
else
print_error_message(uri)
end
end
end

private

def uris
URIExtractor.new(@file_name)
end

def valid_uri?(uri)
response = HTTParty.head(uri)
return response.code == 200
rescue SocketError
return false
end

def print_progress_marker
print '.'
end

def print_error_message(uri)
puts "\nERROR: #{uri} cannot be found"
end
end
10 changes: 6 additions & 4 deletions spec/json_validator_spec.rb
@@ -1,24 +1,26 @@
require 'spec_helper' require 'spec_helper'


describe JSONValidator, '#run' do describe JSONValidator, '#run' do
it 'returns a dot if the JSON is valid' do it 'returns true and outputs a dot if the JSON is valid' do
$stdout = io = StringIO.new $stdout = io = StringIO.new
dir = File.dirname(__FILE__) dir = File.dirname(__FILE__)
file_name = File.open(dir + '/fixtures/valid.json') file_name = File.open(dir + '/fixtures/valid.json')


JSONValidator.new(file_name).run result = JSONValidator.new(file_name).run


result.should be_true
io.string.should eq '.' io.string.should eq '.'
end end




it 'returns an error if the JSON is not valid' do it 'returns false and outputs an error if the JSON is not valid' do
$stdout = io = StringIO.new $stdout = io = StringIO.new
dir = File.dirname(__FILE__) dir = File.dirname(__FILE__)
file_name = File.open(dir + '/fixtures/invalid.json') file_name = File.open(dir + '/fixtures/invalid.json')


JSONValidator.new(file_name).run result = JSONValidator.new(file_name).run


result.should be_false
io.string.should =~ /ERROR/ io.string.should =~ /ERROR/
end end
end end
2 changes: 2 additions & 0 deletions spec/spec_helper.rb
@@ -1,3 +1,5 @@
require 'webmock/rspec'

script_directory = File.dirname(__FILE__) script_directory = File.dirname(__FILE__)
helper_files = script_directory + '/../lib/helpers/*.rb' helper_files = script_directory + '/../lib/helpers/*.rb'


Expand Down
13 changes: 10 additions & 3 deletions spec/trail_runner_spec.rb
Expand Up @@ -6,29 +6,36 @@
describe TrailRunner, '#run' do describe TrailRunner, '#run' do
it 'returns a starting message' do it 'returns a starting message' do
$stdout = io = StringIO.new $stdout = io = StringIO.new
uri_validator_stub = stub('uri validator stub', :run)
URIValidator.stubs(:new).returns(uri_validator_stub)


TrailRunner.new.run TrailRunner.new.run


io.string.split("\n")[0].should =~ /Starting/ io.string.split("\n")[0].should =~ /Starting/
end end


it 'calls JSONValidator.new(file).run on each file' do it 'calls JSONValidator.new(file).run on each file' do
validator_stub = stub('json validator stub', :run) validator_stub = stub('json validator stub', run: true)
JSONValidator.stubs(:new).returns(validator_stub) JSONValidator.stubs(:new).returns(validator_stub)


dir = File.dirname(__FILE__) uri_validator_stub = stub('uri validator stub', :run)
file_name = File.open(dir + '/fixtures/valid.json') URIValidator.stubs(:new).returns(uri_validator_stub)

file_name = File.expand_path('../fixtures/valid.json', __FILE__)
files = [file_name] files = [file_name]
runner = TrailRunner.new runner = TrailRunner.new
runner.stubs(:json_files).returns(files) runner.stubs(:json_files).returns(files)


runner.run runner.run


JSONValidator.should have_received(:new) JSONValidator.should have_received(:new)
URIValidator.should have_received(:new)
end end


it 'prints a closing puts' do it 'prints a closing puts' do
$stdout = io = StringIO.new $stdout = io = StringIO.new
uri_validator_stub = stub('uri validator stub', :run)
URIValidator.stubs(:new).returns(uri_validator_stub)


TrailRunner.new.run TrailRunner.new.run


Expand Down
15 changes: 15 additions & 0 deletions spec/uri_extractor_spec.rb
@@ -0,0 +1,15 @@
require 'spec_helper'

describe URIExtractor, '#each' do
it 'yields each URI' do
file_name = File.expand_path('../fixtures/valid.json', __FILE__)
found_uris = []

URIExtractor.new(file_name).each { |uri| found_uris << uri }

expect(found_uris).to eq %w(
http://amzn.to/the-linux-programming-interface
http://en.wikipedia.org/wiki/Redirection_%28computing%29
)
end
end
34 changes: 34 additions & 0 deletions spec/uri_validator_spec.rb
@@ -0,0 +1,34 @@
require 'spec_helper'

describe URIValidator, '#run' do
it 'outputs a dot for each valid URI' do
stub_request(:head, 'http://example.org')
stub_request(:head, 'http://example.com')
file_name = 'good_json_file.json'
URIExtractor.stubs(:new).with(file_name).returns %w(
http://example.org
http://example.com
)
$stdout = io = StringIO.new

URIValidator.new(file_name).run

io.string.should eq '..'
end

it 'outputs an error for each invalid URI' do
stub_request(:head, 'http://bad.example.org').to_raise(SocketError)
stub_request(:head, 'http://thoughtbot.com/404').to_return(status: 404)
file_name = 'bad_json_file.json'
URIExtractor.stubs(:new).with(file_name).returns %w(
http://bad.example.org
http://thoughtbot.com/404
)
$stdout = io = StringIO.new

URIValidator.new(file_name).run

io.string.should =~ %r{ERROR: http://bad\.example\.org}
io.string.should =~ %r{ERROR: http://thoughtbot\.com/404}
end
end

0 comments on commit 0a58805

Please sign in to comment.