rspec-webservice_matchers 4.0.1 → 4.0.2
Sign up to get free protection for your applications and to get access to all the features.
- 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
|
-
[![Gem Version](https://badge.fury.io/rb/rspec-webservice_matchers.png)](http://badge.fury.io/rb/rspec-webservice_matchers)
|
3
|
+
[![Gem Version](https://badge.fury.io/rb/rspec-webservice_matchers.png)](http://badge.fury.io/rb/rspec-webservice_matchers) [![Code Climate](https://codeclimate.com/github/dogweather/rspec-webservice_matchers.png)](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
|