rspec-webservice_matchers 4.9.0 → 4.12.2

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.
Files changed (32) hide show
  1. checksums.yaml +5 -5
  2. data/.github/workflows/ruby.yml +35 -0
  3. data/HISTORY.md +13 -0
  4. data/README.md +11 -15
  5. data/circle.yml +2 -0
  6. data/lib/rspec/webservice_matchers/be_fast.rb +2 -46
  7. data/lib/rspec/webservice_matchers/be_status.rb +3 -2
  8. data/lib/rspec/webservice_matchers/be_up.rb +2 -24
  9. data/lib/rspec/webservice_matchers/enforce_https_everywhere.rb +7 -6
  10. data/lib/rspec/webservice_matchers/have_a_valid_cert.rb +3 -2
  11. data/lib/rspec/webservice_matchers/redirect_helpers.rb +5 -4
  12. data/lib/rspec/webservice_matchers/redirect_permanently_to.rb +2 -1
  13. data/lib/rspec/webservice_matchers/redirect_temporarily_to.rb +2 -1
  14. data/lib/rspec/webservice_matchers/version.rb +2 -1
  15. data/lib/web_test/be_fast.rb +59 -0
  16. data/lib/web_test/be_up.rb +25 -0
  17. data/lib/web_test/util.rb +105 -0
  18. data/rspec-webservice_matchers.gemspec +10 -9
  19. data/spec/failure_matchers.rb +16 -0
  20. data/spec/rspec/webservice_matchers/{protcol_spec.rb → protocol_spec.rb} +5 -8
  21. data/spec/rspec/webservice_matchers/public_api_spec.rb +6 -5
  22. data/spec/rspec/webservice_matchers/redirect_spec.rb +19 -18
  23. data/spec/rspec/webservice_matchers/ssl_spec.rb +72 -47
  24. data/spec/spec_helper.rb +3 -54
  25. data/spec/web_mock_config.rb +54 -0
  26. data/spec/web_test/be_up_spec.rb +93 -0
  27. data/spec/web_test/util_spec.rb +6 -0
  28. metadata +53 -35
  29. data/lib/rspec/webservice_matchers/util.rb +0 -97
  30. data/spec/rspec/webservice_matchers/be_fast_spec.rb +0 -28
  31. data/spec/rspec/webservice_matchers/be_up_spec.rb +0 -94
  32. data/spec/rspec/webservice_matchers/page_speed_spec.rb +0 -37
@@ -0,0 +1,105 @@
1
+ # frozen_string_literal: true
2
+ require 'faraday'
3
+ require 'faraday_middleware'
4
+
5
+ TIMEOUT_IN_SECONDS = 5
6
+ OPEN_TIMEOUT_IN_SECONDS = 5
7
+
8
+ module WebTest
9
+ module Util
10
+ def self.error_message(errors)
11
+ return errors.message if errors.respond_to?(:message)
12
+
13
+ errors
14
+ .map(&:to_s)
15
+ .join('; ')
16
+ .capitalize
17
+ end
18
+
19
+ def self.status(url_or_domain_name, follow: false)
20
+ code = head(url_or_domain_name, follow: follow)[0]
21
+ return code if code != 405
22
+ get(url_or_domain_name, follow: follow)[0]
23
+ end
24
+
25
+ def self.head(url_or_domain_name, follow: false)
26
+ request(:head, url_or_domain_name, follow: follow)
27
+ end
28
+
29
+ def self.get(url_or_domain_name, follow: false)
30
+ request(:get, url_or_domain_name, follow: follow)
31
+ end
32
+
33
+ def self.request(method, url_or_domain_name, follow: false)
34
+ url = make_url(url_or_domain_name)
35
+ response = recheck_on_timeout { connection(follow: follow).send(method, url) }
36
+ [response.status, response.headers]
37
+ end
38
+
39
+ # @return true if the given page has status 200,
40
+ # and follow a few redirects if necessary.
41
+ def self.up?(url_or_domain_name)
42
+ url = make_url(url_or_domain_name)
43
+ conn = connection(follow: true)
44
+ response = recheck_on_timeout { conn.head(url) }
45
+ response.status == 200
46
+ end
47
+
48
+ def self.valid_cert?(domain_name_or_url)
49
+ try_ssl_connection(domain_name_or_url)
50
+ true
51
+ rescue
52
+ # Not serving SSL, expired, or incorrect domain name in certificate
53
+ false
54
+ end
55
+
56
+ def self.try_ssl_connection(domain_name_or_url)
57
+ url = "https://#{remove_protocol(domain_name_or_url)}"
58
+ recheck_on_timeout { connection.head(url) }
59
+ true
60
+ end
61
+
62
+ # private
63
+
64
+ def self.connection(follow: false)
65
+ Faraday.new do |c|
66
+ c.options[:timeout] = TIMEOUT_IN_SECONDS
67
+ c.options[:open_timeout] = OPEN_TIMEOUT_IN_SECONDS
68
+ c.use(FaradayMiddleware::FollowRedirects, limit: 4) if follow
69
+ c.adapter :net_http
70
+ end
71
+ end
72
+
73
+ # Ensure that the given string is a URL,
74
+ # making it into one if necessary.
75
+ def self.make_url(url_or_domain_name)
76
+ if %r{^https?://} =~ url_or_domain_name
77
+ url_or_domain_name
78
+ else
79
+ "http://#{url_or_domain_name}"
80
+ end
81
+ end
82
+
83
+ # Return just the domain name portion of a URL if
84
+ # it's simply of the form http://name.tld
85
+ def self.make_domain_name(url_or_domain_name)
86
+ if %r{^https?://(.+)} =~ url_or_domain_name
87
+ $1
88
+ else
89
+ url_or_domain_name
90
+ end
91
+ end
92
+
93
+ # Normalize the input: remove 'http(s)://' if it's there
94
+ def self.remove_protocol(domain_name_or_url)
95
+ %r{^https?://(?<name>.+)$} =~ domain_name_or_url
96
+ name || domain_name_or_url
97
+ end
98
+
99
+ def self.recheck_on_timeout
100
+ yield
101
+ rescue Faraday::TimeoutError
102
+ yield
103
+ end
104
+ end
105
+ end
@@ -1,6 +1,6 @@
1
- # coding: utf-8
2
1
  # frozen_string_literal: true
3
- lib = File.expand_path('../lib', __FILE__)
2
+
3
+ lib = File.expand_path('lib', __dir__)
4
4
  $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
5
5
  require 'rspec/webservice_matchers/version'
6
6
 
@@ -8,27 +8,28 @@ Gem::Specification.new do |spec|
8
8
  spec.name = 'rspec-webservice_matchers'
9
9
  spec.version = RSpec::WebserviceMatchers::VERSION
10
10
  spec.authors = ['Robb Shecter']
11
- spec.email = ['robb@weblaws.org']
11
+ spec.email = ['robb@public.law']
12
12
  spec.description = 'Black-box web app configuration testing'
13
13
  spec.summary = 'Black-box web app configuration testing'
14
14
  spec.homepage = 'https://github.com/dogweather/rspec-webservice_matchers'
15
15
  spec.license = 'MIT'
16
16
 
17
17
  spec.files = `git ls-files`.split($INPUT_RECORD_SEPARATOR)
18
- spec.executables = spec.files.grep(/^bin\//) { |f| File.basename(f) }
19
- spec.test_files = spec.files.grep(/^(test|spec|features)\//)
18
+ spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
19
+ spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
20
20
  spec.require_paths = ['lib']
21
- spec.required_ruby_version = '>= 2.1.0'
21
+ spec.required_ruby_version = '>= 2.4.0'
22
22
 
23
- spec.add_development_dependency 'bundler', '~> 1.3'
23
+ spec.add_development_dependency 'bundler', '~> 2.0'
24
24
  spec.add_development_dependency 'pry'
25
25
  spec.add_development_dependency 'rake'
26
26
  spec.add_development_dependency 'rspec'
27
27
  spec.add_development_dependency 'rspec_junit_formatter', '0.2.2'
28
28
  spec.add_development_dependency 'webmock'
29
29
 
30
- spec.add_runtime_dependency 'rspec', '~> 3.0'
31
30
  spec.add_runtime_dependency 'faraday'
32
31
  spec.add_runtime_dependency 'faraday_middleware'
33
- spec.add_runtime_dependency 'validated_object'
32
+ spec.add_runtime_dependency 'rspec-core', '~> 3.0'
33
+ spec.add_runtime_dependency 'rspec-expectations', '~> 3.0'
34
+ spec.add_runtime_dependency 'validated_object', '~> 1.1.0'
34
35
  end
@@ -0,0 +1,16 @@
1
+ module RSpec
2
+ # Matchers to help test RSpec matchers
3
+ module Matchers
4
+ def fail
5
+ raise_error(RSpec::Expectations::ExpectationNotMetError)
6
+ end
7
+
8
+ def fail_with(message)
9
+ raise_error(RSpec::Expectations::ExpectationNotMetError, message)
10
+ end
11
+
12
+ def fail_matching(regex)
13
+ raise_error(RSpec::Expectations::ExpectationNotMetError, regex)
14
+ end
15
+ end
16
+ end
@@ -1,7 +1,8 @@
1
1
  # frozen_string_literal: true
2
2
  require 'spec_helper'
3
3
  require 'rspec/webservice_matchers'
4
- require 'rspec/webservice_matchers/util'
4
+ require 'web_test/util'
5
+
5
6
 
6
7
  describe 'be_status' do
7
8
  it 'can check 200 for successful resource requests' do
@@ -30,7 +31,7 @@ describe 'be_status' do
30
31
  }.to fail_matching(/404/)
31
32
  end
32
33
 
33
- it 'succeeds even if the site times out on the first try' do
34
+ xit 'succeeds even if the site times out on the first try' do
34
35
  expect('http://www.timeout-once.com').to be_status 200
35
36
  end
36
37
 
@@ -50,7 +51,7 @@ describe 'be_up' do
50
51
  end
51
52
 
52
53
  it 'is available via a public API' do
53
- status = RSpec::WebserviceMatchers::Util.up?('http://www.website.com/')
54
+ status = WebTest::Util.up?('http://www.website.com/')
54
55
  expect(status).to be true
55
56
  end
56
57
 
@@ -60,11 +61,7 @@ describe 'be_up' do
60
61
  }.to fail_matching(/^received status 404$/i)
61
62
  end
62
63
 
63
- it 'succeeds even if the site times out on the first try' do
64
+ xit 'succeeds even if the site times out on the first try' do
64
65
  expect('http://www.timeout-once.com').to be_up
65
66
  end
66
-
67
- it 'works on cars.com' do
68
- expect('http://cars.com').to be_up
69
- end
70
67
  end
@@ -1,15 +1,16 @@
1
1
  # frozen_string_literal: true
2
2
  require 'spec_helper'
3
- require 'rspec/webservice_matchers/util'
3
+ require 'web_test/util'
4
+
4
5
  include RSpec::WebserviceMatchers
5
6
 
6
7
  describe '#up?' do
7
8
  it 'follows redirects when necessary' do
8
- expect(Util.up?('perm-redirector.com')).to be_truthy
9
- expect(Util.up?('temp-redirector.org')).to be_truthy
9
+ expect(WebTest::Util.up?('perm-redirector.com')).to be_truthy
10
+ expect(WebTest::Util.up?('temp-redirector.org')).to be_truthy
10
11
  end
11
12
 
12
- it 'retries timeout errors once' do
13
- expect(Util.up?('http://www.timeout-once.com')).to be_truthy
13
+ xit 'retries timeout errors once' do
14
+ expect(WebTest::Util.up?('http://www.timeout-once.com')).to be_truthy
14
15
  end
15
16
  end
@@ -1,4 +1,5 @@
1
1
  # frozen_string_literal: true
2
+
2
3
  require 'spec_helper'
3
4
  require 'rspec/webservice_matchers'
4
5
 
@@ -16,27 +17,27 @@ describe 'redirect_permanently_to' do
16
17
  end
17
18
 
18
19
  it 'gives a good error message for the wrong redirect type' do
19
- expect {
20
+ expect do
20
21
  expect('temp-redirector.org').to redirect_permanently_to 'http://a-page.com/a/page.txt'
21
- }.to fail_matching(/temporary/i)
22
+ end.to fail_matching(/temporary/i)
22
23
  end
23
24
 
24
25
  it 'gives a good error message for a redirect to the wrong location' do
25
- expect {
26
+ expect do
26
27
  expect('perm-redirector.com').to redirect_permanently_to 'http://the-wrong-site.com/'
27
- }.to fail_matching(/location/i)
28
+ end.to fail_matching(/location/i)
28
29
  end
29
30
 
30
31
  it 'gives a good error message for a non-redirect status' do
31
- expect {
32
+ expect do
32
33
  expect('notfound.com').to redirect_permanently_to 'http://the-wrong-site.com/'
33
- }.to fail_matching(/^not a redirect: received status 404$/i)
34
+ end.to fail_matching(/^not a redirect: received status 404$/i)
34
35
  end
35
36
 
36
37
  it 'gives a good error message when the hostname is bad' do
37
- expect {
38
- expect('asdhfjadhsfksd.com').to redirect_permanently_to 'http://the-wrong-site.com/'
39
- }.to fail_matching(/not known/i)
38
+ expect do
39
+ expect('not-a-domain.com').to redirect_permanently_to 'http://the-wrong-site.com/'
40
+ end.to fail_matching(/not known/i)
40
41
  end
41
42
  end
42
43
 
@@ -54,26 +55,26 @@ describe 'redirect_temporarily_to' do
54
55
  end
55
56
 
56
57
  it 'gives a good error message for the wrong redirect type' do
57
- expect {
58
+ expect do
58
59
  expect('perm-redirector.com').to redirect_temporarily_to 'www.website.com/'
59
- }.to fail_matching(/permanent/i)
60
+ end.to fail_matching(/permanent/i)
60
61
  end
61
62
 
62
63
  it 'gives a good error message for a redirect to the wrong location' do
63
- expect {
64
+ expect do
64
65
  expect('temp-307-redirector.net').to redirect_temporarily_to 'www.nowhere.com'
65
- }.to fail_matching(/location/i)
66
+ end.to fail_matching(/location/i)
66
67
  end
67
68
 
68
69
  it 'gives a good error message for a non-redirect status' do
69
- expect {
70
+ expect do
70
71
  expect('notfound.com').to redirect_temporarily_to 'www.nowhere.com'
71
- }.to fail_matching(/^not a redirect: received status 404$/i)
72
+ end.to fail_matching(/^not a redirect: received status 404$/i)
72
73
  end
73
74
 
74
75
  it 'gives a good error message when the hostname is bad' do
75
- expect {
76
- expect('234678234687234.com').to redirect_temporarily_to 'www.nowhere.com'
77
- }.to fail_matching(/not known/i)
76
+ expect do
77
+ expect('not-a-domain.com').to redirect_temporarily_to 'www.nowhere.com'
78
+ end.to fail_matching(/not known/i)
78
79
  end
79
80
  end
@@ -1,62 +1,87 @@
1
1
  # frozen_string_literal: true
2
+
2
3
  require 'spec_helper'
3
4
  require 'rspec/webservice_matchers'
4
5
 
5
- describe 'have_a_valid_cert matcher' do
6
- it 'passes when SSL is properly configured' do
7
- # EFF created the HTTPS Everywhere movement
8
- # TODO: set up a test server for this. (?)
9
- expect('www.eff.org').to have_a_valid_cert
10
- end
6
+ describe 'SSL tests' do
7
+ before(:each) { WebMock.allow_net_connect! }
8
+ after(:each) { WebMock.disable_net_connect! }
11
9
 
12
- it 'fails if the server is not serving SSL at all' do
13
- expect {
14
- expect('www.psu.edu').to have_a_valid_cert
15
- }.to fail_matching(/443/)
16
- end
10
+ describe 'have_a_valid_cert matcher' do
11
+ it 'passes when SSL is properly configured' do
12
+ # EFF created the HTTPS Everywhere movement
13
+ # TODO: set up a test server for this. (?)
14
+ expect('www.eff.org').to have_a_valid_cert
15
+ end
17
16
 
18
- it 'provides a relevant error message' do
19
- expect {
20
- expect('www.psu.edu').to have_a_valid_cert
21
- }.to fail_matching(/(unreachable)|(no route to host)|(connection refused)/i)
22
- end
17
+ it 'fails if the server is not serving SSL at all' do
18
+ expect do
19
+ expect('neverssl.com').to have_a_valid_cert
20
+ end.to fail_matching(/Unable to verify/)
21
+ end
23
22
 
24
- it "provides a relevant error message when the domain name doesn't exist" do
25
- expect {
26
- expect('sdfgkljhsdfghjkhsdfgj.edu').to have_a_valid_cert
27
- }.to fail_matching(/not known/i)
28
- end
23
+ it 'provides a relevant error message' do
24
+ expect do
25
+ expect('neverssl.com').to have_a_valid_cert
26
+ end.to fail_matching(/(unreachable)|(no route to host)|(connection refused)|(redirect was detected)/i)
27
+ end
29
28
 
30
- it "provides a good error message when it's a redirect" do
31
- expect {
32
- # Can't figure out how to do this with WebMock.
33
- expect('bloc.io').to have_a_valid_cert
34
- }.to fail_matching(/redirect/i)
35
- end
29
+ xit "provides a relevant error message when the domain name doesn't exist" do
30
+ expect do
31
+ expect('sdfgkljhsdfghjkhsdfgj.edu').to have_a_valid_cert
32
+ end.to fail_matching(/not known/i)
33
+ end
36
34
 
37
- # TODO: Find a good way to test this.
38
- # it 'provides a good error message if the request times out' do
39
- # expect {
40
- # expect('www.myapp.com').to have_a_valid_cert
41
- # }.to fail_matching(/(timeout)|(execution expired)/)
42
- # end
43
- end
35
+ xit "provides a good error message when it's a redirect" do
36
+ expect do
37
+ # Can't figure out how to do this with WebMock.
38
+ expect('bloc.io').to have_a_valid_cert
39
+ end.to fail_matching(/redirect/i)
40
+ end
44
41
 
45
- # See https://www.eff.org/https-everywhere
46
- describe 'enforce_https_everywhere' do
47
- it 'passes when http requests are redirected to valid https urls' do
48
- expect('eff.org').to enforce_https_everywhere
42
+ # TODO: Find a good way to test this.
43
+ xit 'provides a good error message if the request times out' do
44
+ expect {
45
+ expect('www.myapp.com').to have_a_valid_cert
46
+ }.to fail_matching(/(timeout)|(execution expired)/)
47
+ end
49
48
  end
50
49
 
51
- it 'provides a relevant error message' do
52
- expect {
53
- expect('www.psu.edu').to enforce_https_everywhere
54
- }.to fail_matching(/200/)
55
- end
50
+ # See https://www.eff.org/https-everywhere
51
+ describe 'enforce_https_everywhere' do
52
+ it 'passes when http requests are redirected to valid https urls' do
53
+ expect('www.eff.org').to enforce_https_everywhere
54
+ end
55
+
56
+ it 'passes when given an https url' do
57
+ expect('https://www.eff.org').to enforce_https_everywhere
58
+ end
59
+
60
+ it 'passes when given an http url' do
61
+ expect('http://www.eff.org').to enforce_https_everywhere
62
+ end
63
+
64
+ it 'provides a relevant error code' do
65
+ expect do
66
+ expect('neverssl.com').to enforce_https_everywhere
67
+ end.to fail_matching(/200/)
68
+ end
69
+
70
+ it 'provides a relevant error code with https url' do
71
+ expect do
72
+ expect('https://neverssl.com').to enforce_https_everywhere
73
+ end.to fail_matching(/200/)
74
+ end
56
75
 
57
- it "provides a relevant error message when the domain name doesn't exist" do
58
- expect {
59
- expect('asdhfjkalsdhfjklasdfhjkasdhfl.com').to enforce_https_everywhere
60
- }.to fail_matching(/connection failed/i)
76
+ it 'provides a relevant error code with http url' do
77
+ expect do
78
+ expect('http://neverssl.com').to enforce_https_everywhere
79
+ end.to fail_matching(/200/)
80
+ end
81
+ # it "provides a relevant error message when the domain name doesn't exist" do
82
+ # expect do
83
+ # expect('asdhfjkalsdhfjklasdfhjkasdhfl.com').to enforce_https_everywhere
84
+ # end.to fail_matching(/connection failed/i)
85
+ # end
61
86
  end
62
87
  end
@@ -1,56 +1,5 @@
1
1
  # frozen_string_literal: true
2
- require 'webmock/rspec'
2
+ require 'web_mock_config'
3
+ require 'failure_matchers'
3
4
 
4
- RSpec.configure do |config|
5
- config.before(:each) do
6
- WebMock.stub_request :any, 'http://a-page.com/a/page.txt'
7
- WebMock.stub_request :any, 'www.website.com'
8
- WebMock.stub_request(:any, /notfound.com/).to_return(status: 404)
9
- WebMock.stub_request(:any, 'outoforder.com').to_return(status: 503)
10
-
11
- # A host which doesn't support HEAD
12
- WebMock.stub_request(:head, 'appengine.com').to_return(status: 405)
13
- WebMock.stub_request(:get, 'appengine.com').to_return(status: 200)
14
-
15
- WebMock.stub_request(:any, 'perm-redirector.com')
16
- .to_return(status: 301, headers: { Location: 'http://www.website.com/' })
17
-
18
- WebMock.stub_request(:any, 'temp-redirector.org')
19
- .to_return(status: 302, headers: { Location: 'http://a-page.com/a/page.txt' })
20
-
21
- WebMock.stub_request(:any, 'temp-307-redirector.net')
22
- .to_return(status: 307, headers: { Location: 'http://a-page.com/a/page.txt' })
23
-
24
- # Timeout scenarios
25
- WebMock.stub_request(:any, 'www.timeout.com').to_timeout
26
- WebMock.stub_request(:any, 'www.timeout-once.com').to_timeout.then.to_return(body: 'abc')
27
-
28
- # Insights API
29
- key = ENV['WEBSERVICE_MATCHER_INSIGHTS_KEY']
30
- WebMock.stub_request(:get, "https://www.googleapis.com/pagespeedonline/v2/runPagespeed?key=#{key}&screenshot=false&url=http://nonstop.qa")
31
- .with(headers: { 'Accept' => '*/*', 'Accept-Encoding' => 'gzip;q=1.0,deflate;q=0.6,identity;q=0.3', 'User-Agent' => 'Faraday v0.9.2' })
32
- .to_return(
33
- status: 200,
34
- body: IO.read('spec/fixtures/pagespeed.json'),
35
- headers: {})
36
-
37
- WebMock.allow_net_connect!
38
- end
39
- end
40
-
41
- module RSpec
42
- # Matchers to help test RSpec matchers
43
- module Matchers
44
- def fail
45
- raise_error(RSpec::Expectations::ExpectationNotMetError)
46
- end
47
-
48
- def fail_with(message)
49
- raise_error(RSpec::Expectations::ExpectationNotMetError, message)
50
- end
51
-
52
- def fail_matching(regex)
53
- raise_error(RSpec::Expectations::ExpectationNotMetError, regex)
54
- end
55
- end
56
- end
5
+ SAMPLE_PAGESPEED_JSON_RESPONSE = 'spec/fixtures/pagespeed.json'