Browse Source

extract link checker from audit process

did not duplicate content lentgh check in preparation for the removal of
content_length as discussed in #131
Paul Hinze 12 years ago
parent
commit
78834bfbd0
  1. 63
      lib/cask/audit.rb
  2. 14
      lib/cask/cli/checklinks.rb
  3. 104
      lib/cask/link_checker.rb
  4. 29
      test/cask/audit_test.rb
  5. 33
      test/cask/link_checker_spec.rb

63
lib/cask/audit.rb

@ -12,11 +12,6 @@ class Cask::Audit
def run!
_check_required_fields
return if errors?
_get_data_from_request
return if errors?
_check_response_status
return if errors?
_check_content_length
end
def add_error(message)
@ -65,62 +60,4 @@ class Cask::Audit
add_error "homepage is required" unless cask.homepage
end
http_responses = [
'HTTP/1.0 200 OK',
'HTTP/1.1 200 OK'
]
OK_RESPONSES = {
'http' => http_responses,
'https' => http_responses,
'ftp' => [ 'OK' ]
}
def _check_response_status
ok = OK_RESPONSES[cask.url.scheme]
unless ok.include?(@response_status)
add_error "unexpected http response, expecting #{ok.map(&:inspect).join(' or ')}, got #{@response_status.inspect}"
end
end
def _check_content_length
remote_content_length = @headers['Content-Length']
if cask.content_length.nil?
add_warning "specify content_length so we can check against URL, currently: content_length '#{remote_content_length}'"
else
unless cask.content_length == remote_content_length
add_warning "unexpected content_length for #{cask}; specified #{cask.content_length.inspect}, but got #{remote_content_length.inspect}"
end
end
end
def _get_data_from_request
response = @fetcher.head(cask.url)
if response.empty?
add_error "timeout while requesting #{cask.url}"
return
end
response_lines = response.split("\n").map(&:chomp)
case cask.url.scheme
when 'http', 'https' then
@response_status = response_lines.grep(/^HTTP/).last
http_headers = response_lines[(response_lines.index(@response_status)+1)..-1]
http_headers.each { |line|
header_name, header_value = line.split(': ')
@headers[header_name] = header_value
}
when 'ftp' then
@response_status = 'OK'
response_lines.each { |line|
header_name, header_value = line.split(': ')
@headers[header_name] = header_value
}
else
add_error "unknown scheme for #{cask.url}"
end
end
end

14
lib/cask/cli/checklinks.rb

@ -0,0 +1,14 @@
class Cask::CLI::Checklinks
def self.run(*args)
casks_to_check = args.empty? ? Cask.all : args.map { |arg| Cask.load(arg) }
casks_to_check.each do |cask|
checker = Cask::LinkChecker.new(cask)
checker.run
puts checker.summary
end
end
def self.help
"checks for bad cask links"
end
end

104
lib/cask/link_checker.rb

@ -0,0 +1,104 @@
class Cask::LinkChecker
attr_accessor :cask, :errors, :response_status, :headers
def initialize(cask, fetcher=Cask::Fetcher)
@cask = cask
@errors = []
@warnings = []
@headers = {}
@fetcher = fetcher
end
def run
_get_data_from_request
return if errors?
_check_response_status
end
def add_error(message)
@errors << message
end
def add_warning(message)
@warnings << message
end
def errors?
!@errors.empty?
end
def warnings?
!@warnings.empty?
end
def result
if errors?
"#{Tty.red}failed#{Tty.reset}"
elsif warnings?
"#{Tty.yellow}warning#{Tty.reset}"
else
"#{Tty.green}passed#{Tty.reset}"
end
end
def summary
summary = ["audit for #{cask}: #{result}"]
@errors.each do |error|
summary << " #{Tty.red}-#{Tty.reset} #{error}"
end
@warnings.each do |warning|
summary << " #{Tty.yellow}-#{Tty.reset} #{warning}"
end
summary.join("\n")
end
HTTP_RESPONSES = [
'HTTP/1.0 200 OK',
'HTTP/1.1 200 OK'
]
OK_RESPONSES = {
'http' => HTTP_RESPONSES,
'https' => HTTP_RESPONSES,
'ftp' => [ 'OK' ]
}
def _check_response_status
ok = OK_RESPONSES[cask.url.scheme]
unless ok.include?(@response_status)
add_error "unexpected http response, expecting #{ok.map(&:inspect).join(' or ')}, got #{@response_status.inspect}"
end
end
def _get_data_from_request
response = @fetcher.head(cask.url)
if response.empty?
add_error "timeout while requesting #{cask.url}"
return
end
response_lines = response.split("\n").map(&:chomp)
case cask.url.scheme
when 'http', 'https' then
@response_status = response_lines.grep(/^HTTP/).last
http_headers = response_lines[(response_lines.index(@response_status)+1)..-1]
http_headers.each { |line|
header_name, header_value = line.split(': ')
@headers[header_name] = header_value
}
when 'ftp' then
@response_status = 'OK'
response_lines.each { |line|
header_name, header_value = line.split(': ')
@headers[header_name] = header_value
}
else
add_error "unknown scheme for #{cask.url}"
end
end
end

29
test/cask/audit_test.rb

@ -57,34 +57,5 @@ describe Cask::Audit do
end
end
describe "request processing" do
it "adds an error if response is empty" do
cask = TestHelper.test_cask
TestHelper.fake_response_for(cask.url, "")
audit = Cask::Audit.new(cask, TestHelper.fake_fetcher)
audit.run!
audit.errors.must_include "timeout while requesting #{cask.url}"
end
it "properly populates the response code and headers from an http response" do
TestHelper.fake_response_for(TestHelper.test_cask.url, <<-RESPONSE.gsub(/^ /, ''))
HTTP/1.1 200 OK
Content-Type: application/x-apple-diskimage
ETag: "b4208f3e84967be4b078ecaa03fba941"
Content-Length: 23726161
Last-Modified: Sun, 12 Aug 2012 21:17:21 GMT
RESPONSE
audit = Cask::Audit.new(TestHelper.test_cask, TestHelper.fake_fetcher)
audit.run!
audit.response_status.must_equal 'HTTP/1.1 200 OK'
audit.headers.must_equal({
'Content-Type' => 'application/x-apple-diskimage',
'ETag' => '"b4208f3e84967be4b078ecaa03fba941"',
'Content-Length' => '23726161',
'Last-Modified' => 'Sun, 12 Aug 2012 21:17:21 GMT'
})
end
end
end
end

33
test/cask/link_checker_spec.rb

@ -0,0 +1,33 @@
require 'test_helper'
describe Cask::Installer do
describe "request processing" do
it "adds an error if response is empty" do
cask = TestHelper.test_cask
TestHelper.fake_response_for(cask.url, "")
checker = Cask::LinkChecker.new(cask, TestHelper.fake_fetcher)
checker.run
checker.errors.must_include "timeout while requesting #{cask.url}"
end
it "properly populates the response code and headers from an http response" do
TestHelper.fake_response_for(TestHelper.test_cask.url, <<-RESPONSE.gsub(/^ */, ''))
HTTP/1.1 200 OK
Content-Type: application/x-apple-diskimage
ETag: "b4208f3e84967be4b078ecaa03fba941"
Content-Length: 23726161
Last-Modified: Sun, 12 Aug 2012 21:17:21 GMT
RESPONSE
checker = Cask::LinkChecker.new(TestHelper.test_cask, TestHelper.fake_fetcher)
checker.run
checker.response_status.must_equal 'HTTP/1.1 200 OK'
checker.headers.must_equal({
'Content-Type' => 'application/x-apple-diskimage',
'ETag' => '"b4208f3e84967be4b078ecaa03fba941"',
'Content-Length' => '23726161',
'Last-Modified' => 'Sun, 12 Aug 2012 21:17:21 GMT'
})
end
end
end
Loading…
Cancel
Save