rspec-webservice_matchers 4.0.1 → 4.0.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.
- checksums.yaml +4 -4
- data/README.md +3 -5
- data/lib/rspec/webservice_matchers/be_status.rb +14 -12
- data/lib/rspec/webservice_matchers/be_up.rb +12 -10
- data/lib/rspec/webservice_matchers/enforce_https_everywhere.rb +39 -35
- data/lib/rspec/webservice_matchers/have_a_valid_cert.rb +14 -12
- data/lib/rspec/webservice_matchers/redirect_permanently_to.rb +30 -24
- data/lib/rspec/webservice_matchers/redirect_temporarily_to.rb +31 -25
- data/lib/rspec/webservice_matchers/util.rb +29 -12
- data/lib/rspec/webservice_matchers/version.rb +1 -1
- metadata +3 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: a235a451fd315c776f1f3d3b11755e2d93c88b73
|
4
|
+
data.tar.gz: 3826ce984adaae4a9cb9b49b361bd7f3b9aab6bf
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 831a900c20d355fa637fd9f2b8146737457e379e4b1a22e8dd528a09de48fea8d5695e99e706a84887d593c1ea64c199a07ae4e937259b4645416fabb590aff4
|
7
|
+
data.tar.gz: a9b1d9a7a937a0ec451f40d3198b47d9b1868d1b5849211ca094d626f3b260d35fc8a9ea6fac3d67fd6f0ffe3e5d3565b3b0cce39d1ffa31779714151e66551c
|
data/README.md
CHANGED
@@ -1,9 +1,9 @@
|
|
1
1
|
# RSpec::WebserviceMatchers
|
2
2
|
|
3
|
-
[](http://badge.fury.io/rb/rspec-webservice_matchers)
|
3
|
+
[](http://badge.fury.io/rb/rspec-webservice_matchers) [](https://codeclimate.com/github/dogweather/rspec-webservice_matchers)
|
4
4
|
|
5
5
|
|
6
|
-
|
6
|
+
A [gem](https://rubygems.org/gems/rspec-webservice_matchers) to black-box test a web server configuration. For example, whether a site's SSL certificate is correctly configured and not expired. It's a tool for doing **Test Driven Devops** (I just made that up). See [the introductory blog post](http://robb.weblaws.org/2014/01/16/new-open-source-library-for-test-driven-devops/) for more about my motivations.
|
7
7
|
|
8
8
|
This library takes a minimalist approach: it simply adds new RSpec matchers. Therefore, you can use your own RSpec writing style; there's no new DSL to learn.
|
9
9
|
|
@@ -36,7 +36,7 @@ Here's an example which uses them all:
|
|
36
36
|
```Ruby
|
37
37
|
require 'rspec/webservice_matchers'
|
38
38
|
|
39
|
-
describe 'My app' do
|
39
|
+
describe 'My app' do
|
40
40
|
context 'www.myapp.com' do
|
41
41
|
it { should be_up }
|
42
42
|
it { should have_a_valid_cert }
|
@@ -60,5 +60,3 @@ Related Projects
|
|
60
60
|
----------------
|
61
61
|
* [serverspec](http://serverspec.org)
|
62
62
|
* [HTTP Assertions](https://github.com/dogweather/HTTP-Assertions): A precusor to this library. Written in the older test case / assert style.
|
63
|
-
|
64
|
-
|
@@ -2,18 +2,20 @@ require 'rspec/webservice_matchers/util'
|
|
2
2
|
|
3
3
|
module RSpec
|
4
4
|
module WebserviceMatchers
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
5
|
+
module BeStatus
|
6
|
+
# Pass when a URL returns the expected status code
|
7
|
+
# Codes are defined in http://www.rfc-editor.org/rfc/rfc2616.txt
|
8
|
+
RSpec::Matchers.define :be_status do |expected_code|
|
9
|
+
actual_code = nil
|
10
|
+
|
11
|
+
match do |url_or_domain_name|
|
12
|
+
actual_code = Util.status(url_or_domain_name)
|
13
|
+
actual_code == expected_code.to_i
|
14
|
+
end
|
15
|
+
|
16
|
+
failure_message do
|
17
|
+
"Received status #{actual_code}"
|
18
|
+
end
|
17
19
|
end
|
18
20
|
end
|
19
21
|
end
|
@@ -2,18 +2,20 @@ require 'rspec/webservice_matchers/util'
|
|
2
2
|
|
3
3
|
module RSpec
|
4
4
|
module WebserviceMatchers
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
5
|
+
module BeUp
|
6
|
+
# Pass when the response code is 200, following redirects
|
7
|
+
# if necessary.
|
8
|
+
RSpec::Matchers.define :be_up do
|
9
|
+
status = nil
|
9
10
|
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
11
|
+
match do |url_or_domain_name|
|
12
|
+
status = Util.status(url_or_domain_name, follow: true)
|
13
|
+
status == 200
|
14
|
+
end
|
14
15
|
|
15
|
-
|
16
|
-
|
16
|
+
failure_message do
|
17
|
+
"Received status #{status}"
|
18
|
+
end
|
17
19
|
end
|
18
20
|
end
|
19
21
|
end
|
@@ -1,47 +1,51 @@
|
|
1
1
|
require 'faraday'
|
2
|
-
|
3
2
|
require 'rspec/webservice_matchers/util'
|
3
|
+
|
4
4
|
module RSpec
|
5
5
|
module WebserviceMatchers
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
6
|
+
module EnforceHttpsEverywhere
|
7
|
+
# This is a high level matcher which checks three things:
|
8
|
+
# 1. Permanent redirect
|
9
|
+
# 2. to an https url
|
10
|
+
# 3. which is correctly configured
|
11
|
+
RSpec::Matchers.define :enforce_https_everywhere do
|
12
|
+
error_msg = status = final_protocol = has_valid_cert = nil
|
13
|
+
|
14
|
+
match do |domain_name|
|
15
|
+
begin
|
16
|
+
status, new_url, final_protocol = get_info(domain_name)
|
17
|
+
meets_expectations?(status, final_protocol, Util.valid_cert?(new_url))
|
18
|
+
rescue Faraday::Error::ConnectionFailed
|
19
|
+
error_msg = 'Connection failed'
|
20
|
+
false
|
21
|
+
end
|
22
|
+
end
|
12
23
|
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
actual_valid_cert = Util.valid_ssl_cert?(new_url)
|
20
|
-
(status == 301) &&
|
21
|
-
(actual_protocol == 'https') &&
|
22
|
-
(actual_valid_cert == true)
|
23
|
-
rescue Faraday::Error::ConnectionFailed
|
24
|
-
error_msg = 'Connection failed'
|
25
|
-
false
|
24
|
+
def get_info(domain_name)
|
25
|
+
status, headers = Util.head(domain_name)
|
26
|
+
location = headers['location']
|
27
|
+
/^(https?)/ =~ location
|
28
|
+
protocol = $1 || nil
|
29
|
+
[status, location, protocol]
|
26
30
|
end
|
27
|
-
end
|
28
31
|
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
32
|
+
def meets_expectations?(status, protocol, valid_cert)
|
33
|
+
(status == 301) && (protocol == 'https') && valid_cert
|
34
|
+
end
|
35
|
+
|
36
|
+
# Create a compound error message listing all of the
|
37
|
+
# relevant actual values received.
|
38
|
+
failure_message do
|
39
|
+
error_msg || higher_level_errors(status, final_protocol, has_valid_cert)
|
40
|
+
end
|
41
|
+
|
42
|
+
def higher_level_errors(status, protocol, cert_is_valid)
|
35
43
|
mesgs = []
|
36
|
-
if status != 301
|
37
|
-
|
38
|
-
|
39
|
-
if !actual_protocol.nil? && actual_protocol != 'https'
|
40
|
-
mesgs << "destination uses protocol #{actual_protocol.upcase}"
|
41
|
-
end
|
42
|
-
if !actual_valid_cert
|
43
|
-
mesgs << "there's no valid SSL certificate"
|
44
|
+
mesgs << "received status #{status} instead of 301" if status != 301
|
45
|
+
if !protocol.nil? && protocol != 'https'
|
46
|
+
mesgs << "destination uses protocol #{protocol.upcase}"
|
44
47
|
end
|
48
|
+
mesgs << "there's no valid SSL certificate" unless cert_is_valid
|
45
49
|
mesgs.join('; ').capitalize
|
46
50
|
end
|
47
51
|
end
|
@@ -2,21 +2,23 @@ require 'rspec/webservice_matchers/util'
|
|
2
2
|
|
3
3
|
module RSpec
|
4
4
|
module WebserviceMatchers
|
5
|
-
|
6
|
-
|
7
|
-
|
5
|
+
module HaveAValidCert
|
6
|
+
# Is https is correctly implemented?
|
7
|
+
RSpec::Matchers.define :have_a_valid_cert do
|
8
|
+
error_message = nil
|
8
9
|
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
10
|
+
match do |domain_name_or_url|
|
11
|
+
begin
|
12
|
+
Util.try_ssl_connection(domain_name_or_url)
|
13
|
+
rescue Exception => e
|
14
|
+
error_message = e.message
|
15
|
+
false
|
16
|
+
end
|
15
17
|
end
|
16
|
-
end
|
17
18
|
|
18
|
-
|
19
|
-
|
19
|
+
failure_message do
|
20
|
+
error_message
|
21
|
+
end
|
20
22
|
end
|
21
23
|
end
|
22
24
|
end
|
@@ -2,37 +2,43 @@ require 'rspec/webservice_matchers/util'
|
|
2
2
|
|
3
3
|
module RSpec
|
4
4
|
module WebserviceMatchers
|
5
|
-
|
6
|
-
|
7
|
-
|
5
|
+
module RedirectPermanentlyTo
|
6
|
+
# Do we get a 301 to the place we intend?
|
7
|
+
RSpec::Matchers.define :redirect_permanently_to do |expected|
|
8
|
+
include RSpec
|
9
|
+
exception = status = actual_location = nil
|
8
10
|
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
11
|
+
match do |url_or_domain_name|
|
12
|
+
begin
|
13
|
+
status, headers = Util.head(url_or_domain_name)
|
14
|
+
actual_location = headers['location']
|
13
15
|
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
16
|
+
Util.permanent_redirect?(status) &&
|
17
|
+
expected_location?(expected, actual_location)
|
18
|
+
rescue Exception => e
|
19
|
+
exception = e
|
20
|
+
false
|
21
|
+
end
|
18
22
|
end
|
19
|
-
end
|
20
23
|
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
mesgs << "received a temporary redirect, status #{status}"
|
24
|
+
failure_message do
|
25
|
+
return Util.error_message(exception) if exception
|
26
|
+
|
27
|
+
errors = []
|
28
|
+
if Util.temp_redirect? status
|
29
|
+
errors << "received a temporary redirect, status #{status}"
|
28
30
|
end
|
29
|
-
|
30
|
-
|
31
|
+
unless expected_location?(expected, actual_location)
|
32
|
+
errors << "received location #{actual_location}"
|
31
33
|
end
|
32
|
-
|
33
|
-
|
34
|
+
unless Util.redirect? status
|
35
|
+
errors << "not a redirect: received status #{status}"
|
34
36
|
end
|
35
|
-
|
37
|
+
Util.error_message(errors)
|
38
|
+
end
|
39
|
+
|
40
|
+
def expected_location?(expected, actual)
|
41
|
+
actual =~ %r{#{expected}/?}
|
36
42
|
end
|
37
43
|
end
|
38
44
|
end
|
@@ -2,38 +2,44 @@ require 'rspec/webservice_matchers/util'
|
|
2
2
|
|
3
3
|
module RSpec
|
4
4
|
module WebserviceMatchers
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
5
|
+
module RedirectTemporarilyTo
|
6
|
+
# Do we get a 302 or 307 to the place we intend?
|
7
|
+
RSpec::Matchers.define :redirect_temporarily_to do |expected|
|
8
|
+
include RSpec
|
9
|
+
status = actual_location = exception = nil
|
9
10
|
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
11
|
+
match do |url_or_domain_name|
|
12
|
+
begin
|
13
|
+
status, headers = Util.head(url_or_domain_name)
|
14
|
+
actual_location = headers['location']
|
14
15
|
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
16
|
+
Util.temp_redirect?(status) &&
|
17
|
+
expected_location?(expected, actual_location)
|
18
|
+
rescue Exception => e
|
19
|
+
exception = e
|
20
|
+
false
|
21
|
+
end
|
19
22
|
end
|
20
|
-
end
|
21
23
|
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
mesgs << "received a permanent redirect, status #{status}"
|
24
|
+
failure_message do
|
25
|
+
return Util.error_message(exception) if exception
|
26
|
+
|
27
|
+
errors = []
|
28
|
+
if Util.permanent_redirect? status
|
29
|
+
errors << 'received a permanent redirect'
|
29
30
|
end
|
30
|
-
|
31
|
-
|
31
|
+
unless expected_location? expected, actual_location
|
32
|
+
errors << "received location #{actual_location}"
|
32
33
|
end
|
33
|
-
|
34
|
-
|
34
|
+
unless Util.redirect? status
|
35
|
+
errors << "not a redirect: received status #{status}"
|
35
36
|
end
|
36
|
-
|
37
|
+
|
38
|
+
Util.error_message(errors)
|
39
|
+
end
|
40
|
+
|
41
|
+
def expected_location?(expected, actual)
|
42
|
+
actual =~ %r{#{expected}/?}
|
37
43
|
end
|
38
44
|
end
|
39
45
|
end
|
@@ -3,14 +3,33 @@ require 'faraday'
|
|
3
3
|
require 'faraday_middleware'
|
4
4
|
require 'pry'
|
5
5
|
|
6
|
-
|
7
|
-
|
8
|
-
OPEN_TIMEOUT = 20
|
6
|
+
TIMEOUT_IN_SECONDS = 20
|
7
|
+
OPEN_TIMEOUT_IN_SECONDS = 20
|
9
8
|
|
10
9
|
module RSpec
|
11
10
|
module WebserviceMatchers
|
12
|
-
# Refactored utility functions
|
13
11
|
module Util
|
12
|
+
def self.error_message(errors)
|
13
|
+
return errors.message if errors.respond_to?(:message)
|
14
|
+
|
15
|
+
errors
|
16
|
+
.map(&:to_s)
|
17
|
+
.join('; ')
|
18
|
+
.capitalize
|
19
|
+
end
|
20
|
+
|
21
|
+
def self.redirect?(status)
|
22
|
+
temp_redirect?(status) || permanent_redirect?(status)
|
23
|
+
end
|
24
|
+
|
25
|
+
def self.temp_redirect?(status)
|
26
|
+
[302, 307].include?(status)
|
27
|
+
end
|
28
|
+
|
29
|
+
def self.permanent_redirect?(status)
|
30
|
+
status == 301
|
31
|
+
end
|
32
|
+
|
14
33
|
def self.status(url_or_domain_name, follow: false)
|
15
34
|
head(url_or_domain_name, follow: follow)[0]
|
16
35
|
end
|
@@ -30,7 +49,7 @@ module RSpec
|
|
30
49
|
response.status == 200
|
31
50
|
end
|
32
51
|
|
33
|
-
def self.
|
52
|
+
def self.valid_cert?(domain_name_or_url)
|
34
53
|
try_ssl_connection(domain_name_or_url)
|
35
54
|
true
|
36
55
|
rescue
|
@@ -48,8 +67,8 @@ module RSpec
|
|
48
67
|
|
49
68
|
def self.connection(follow: false)
|
50
69
|
Faraday.new do |c|
|
51
|
-
c.options[:timeout] =
|
52
|
-
c.options[:open_timeout] =
|
70
|
+
c.options[:timeout] = TIMEOUT_IN_SECONDS
|
71
|
+
c.options[:open_timeout] = OPEN_TIMEOUT_IN_SECONDS
|
53
72
|
c.use(FaradayMiddleware::FollowRedirects, limit: 4) if follow
|
54
73
|
c.adapter :excon
|
55
74
|
end
|
@@ -72,11 +91,9 @@ module RSpec
|
|
72
91
|
end
|
73
92
|
|
74
93
|
def self.recheck_on_timeout
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
yield
|
79
|
-
end
|
94
|
+
yield
|
95
|
+
rescue Faraday::Error::TimeoutError
|
96
|
+
yield
|
80
97
|
end
|
81
98
|
end
|
82
99
|
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: rspec-webservice_matchers
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 4.0.
|
4
|
+
version: 4.0.2
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Robb Shecter
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2016-01-29 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bundler
|
@@ -170,7 +170,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
170
170
|
version: '0'
|
171
171
|
requirements: []
|
172
172
|
rubyforge_project:
|
173
|
-
rubygems_version: 2.
|
173
|
+
rubygems_version: 2.5.0
|
174
174
|
signing_key:
|
175
175
|
specification_version: 4
|
176
176
|
summary: Black-box web app configuration testing
|