akamai_rspec 0.2.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/lib/akamai_rspec/akamai_headers.rb +7 -0
- data/lib/akamai_rspec/matchers/caching.rb +54 -0
- data/lib/akamai_rspec/matchers/honour_origin_headers.rb +124 -0
- data/lib/akamai_rspec/matchers/matchers.rb +40 -0
- data/lib/akamai_rspec/matchers/non_akamai.rb +67 -0
- data/lib/akamai_rspec/matchers/redirects.rb +28 -0
- data/lib/akamai_rspec/request.rb +89 -0
- data/lib/akamai_rspec.rb +3 -0
- metadata +92 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 06d8b35c313b71c7d4d8723af6c0f6fac7884ec6
|
4
|
+
data.tar.gz: acddb3b50759171eb123010e287a1cf842cc1bb8
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: e9c998292a3c9b68c4e125b43e318b062019903408159916cdc994fc63bf7b58e432190b7ab7dda0f3c3f1d66ef073c8d4c298a87c3749536b2b78a9cfc559d0
|
7
|
+
data.tar.gz: 57043ea5fa5f880a19bd2d964adcbb4970adc28b7bbe9812157186c32e76e6f0fe840703c0b4670743c5c4fbed1548e62150a2a7183ccc029c307b1a0f118357
|
@@ -0,0 +1,7 @@
|
|
1
|
+
module AkamaiHeaders
|
2
|
+
def akamai_debug_headers
|
3
|
+
{
|
4
|
+
pragma: 'akamai-x-cache-on, akamai-x-cache-remote-on, akamai-x-check-cacheable, akamai-x-get-cache-key, akamai-x-get-extracted-values, akamai-x-get-nonces, akamai-x-get-ssl-client-session-id, akamai-x-get-true-cache-key, akamai-x-serial-no'
|
5
|
+
}
|
6
|
+
end
|
7
|
+
end
|
@@ -0,0 +1,54 @@
|
|
1
|
+
require 'rspec'
|
2
|
+
require 'securerandom'
|
3
|
+
|
4
|
+
RSpec::Matchers.define :be_cacheable do
|
5
|
+
match do |url|
|
6
|
+
response = RestClient::Request.responsify url
|
7
|
+
x_check_cacheable(response, 'YES')
|
8
|
+
response.code == 200
|
9
|
+
end
|
10
|
+
end
|
11
|
+
|
12
|
+
module RSpec::Matchers
|
13
|
+
alias_method :be_cachable, :be_cacheable
|
14
|
+
end
|
15
|
+
|
16
|
+
RSpec::Matchers.define :have_no_cache_set do
|
17
|
+
match do |url|
|
18
|
+
response = RestClient::Request.responsify url
|
19
|
+
cache_control = response.headers[:cache_control]
|
20
|
+
fail('Cache-Control has been set') unless cache_control == 'no-cache'
|
21
|
+
true
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
RSpec::Matchers.define :not_be_cached do
|
26
|
+
match do |url|
|
27
|
+
response = RestClient::Request.responsify url
|
28
|
+
x_check_cacheable(response, 'NO')
|
29
|
+
response = RestClient::Request.responsify response.args[:url] # again to prevent spurious cache miss
|
30
|
+
|
31
|
+
not_cached = response.headers[:x_cache] =~ /TCP(\w+)?_MISS/
|
32
|
+
unless not_cached
|
33
|
+
fail("x_cache header does not indicate an origin hit: '#{response.headers[:x_cache]}'")
|
34
|
+
end
|
35
|
+
response.code == 200 && not_cached
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
RSpec::Matchers.define :be_tier_distributed do
|
40
|
+
match do |url|
|
41
|
+
response = RestClient::Request.request_cache_miss(url)
|
42
|
+
tiered = !response.headers[:x_cache_remote].nil?
|
43
|
+
fail('No X-Cache-Remote header in response') unless tiered
|
44
|
+
response.code == 200 && tiered
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
def x_check_cacheable(response, should_be_cacheable)
|
49
|
+
x_check_cacheable = response.headers[:x_check_cacheable]
|
50
|
+
fail('No X-Check-Cacheable header?') if x_check_cacheable.nil?
|
51
|
+
unless (x_check_cacheable == should_be_cacheable)
|
52
|
+
fail("X-Check-Cacheable header is: #{x_check_cacheable} expected #{should_be_cacheable}")
|
53
|
+
end
|
54
|
+
end
|
@@ -0,0 +1,124 @@
|
|
1
|
+
require 'rspec'
|
2
|
+
require 'set'
|
3
|
+
require 'time'
|
4
|
+
require 'uri'
|
5
|
+
|
6
|
+
RSpec::Matchers.define :honour_origin_cache_headers do |origin, headers|
|
7
|
+
header_options = [:cache_control, :expires, :both]
|
8
|
+
headers ||= :both
|
9
|
+
fail("Headers must be one of: #{header_options}") unless header_options.include? headers
|
10
|
+
|
11
|
+
match do |url|
|
12
|
+
akamai_response = RestClient::Request.responsify url
|
13
|
+
origin_response = origin_response(origin)
|
14
|
+
check_cache_control(origin_response, akamai_response, headers)
|
15
|
+
check_expires(origin_response, akamai_response, headers)
|
16
|
+
true
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
def fix_date_header(origin_response)
|
21
|
+
origin_response.headers[:date] = Time.now.httpdate unless origin_response.headers[:date]
|
22
|
+
origin_response
|
23
|
+
end
|
24
|
+
|
25
|
+
def origin_response(origin)
|
26
|
+
fix_date_header(RestClient::Request.execute(method: :get, url: origin, verify_ssl: false))
|
27
|
+
end
|
28
|
+
|
29
|
+
def clean_cc_directives(origin_response, akamai_response)
|
30
|
+
origin_cc_directives = origin_response.headers[:cache_control].split(/[, ]+/).to_set
|
31
|
+
akamai_cc_directives = akamai_response.headers[:cache_control].split(/[, ]+/).to_set
|
32
|
+
|
33
|
+
origin_cc_directives.delete 'must-revalidate' # as Akamai does no pass it on
|
34
|
+
return origin_cc_directives, akamai_cc_directives
|
35
|
+
end
|
36
|
+
|
37
|
+
def cc_directives(origin_response, akamai_response)
|
38
|
+
origin_cc, akamai_cc = clean_cc_directives(origin_response, akamai_response)
|
39
|
+
check_cc(origin_cc, akamai_cc) unless (origin_cc & ['no-store', 'no-cache']).empty?
|
40
|
+
return origin_cc, akamai_cc
|
41
|
+
end
|
42
|
+
|
43
|
+
def check_and_clean_header(origin_cc, akamai_cc, expected)
|
44
|
+
unless akamai_cc.include? expected
|
45
|
+
fail "Akamai was expected to, but did not, add 'Cache-Control: #{expected}' as Origin sent 'no-store' or 'no-cache'"
|
46
|
+
end
|
47
|
+
akamai_cc.delete expected unless origin_cc.include? expected
|
48
|
+
akamai_cc
|
49
|
+
end
|
50
|
+
|
51
|
+
def check_cc(origin_cc, akamai_cc)
|
52
|
+
['no-store', 'max-age=0'].each do |expected|
|
53
|
+
akamai_cc = check_and_clean_header(origin_cc, akamai_cc, expected)
|
54
|
+
end
|
55
|
+
return origin_cc, akamai_cc
|
56
|
+
end
|
57
|
+
|
58
|
+
def max_age(cc_directives)
|
59
|
+
cc_directives.detect { |d| d.start_with? 'max-age=' }
|
60
|
+
end
|
61
|
+
|
62
|
+
def max_age_to_num(max_age)
|
63
|
+
max_age.split('=').last.to_i
|
64
|
+
end
|
65
|
+
|
66
|
+
def clean_max_age(cc_directives)
|
67
|
+
max_age = max_age(cc_directives)
|
68
|
+
cc_directives.delete max_age if max_age
|
69
|
+
return max_age_to_num(max_age), cc_directives
|
70
|
+
end
|
71
|
+
|
72
|
+
def check_max_age(origin_cc_directives, akamai_cc_directives)
|
73
|
+
origin_max_age, origin_cc_directives = clean_max_age(origin_cc_directives)
|
74
|
+
akamai_max_age, akamai_cc_directives = clean_max_age(akamai_cc_directives)
|
75
|
+
if akamai_max_age > origin_max_age
|
76
|
+
fail "Akamai sent a max-age greater than Origin's: #{akamai_max_age} > #{origin_max_age}"
|
77
|
+
end
|
78
|
+
return origin_cc_directives, akamai_cc_directives
|
79
|
+
end
|
80
|
+
|
81
|
+
def validate_akamai_dropped(origin_cc, akamai_cc)
|
82
|
+
dropped = origin_cc - akamai_cc
|
83
|
+
unless dropped.empty?
|
84
|
+
fail "Origin sent 'Cache-Control: #{dropped.to_a.join ','}', but Akamai did not."
|
85
|
+
end
|
86
|
+
end
|
87
|
+
|
88
|
+
def validate_akamai_added(origin_cc, akamai_cc)
|
89
|
+
added = akamai_cc - origin_cc
|
90
|
+
unless added.empty?
|
91
|
+
fail "Akamai unexpectedly added 'Cache-Control: #{added.to_a.join ','}'"
|
92
|
+
end
|
93
|
+
end
|
94
|
+
|
95
|
+
def check_cache_control(origin_response, akamai_response, headers)
|
96
|
+
if [:both, :cache_control].include? headers
|
97
|
+
origin_cc, akamai_cc = cc_directives(origin_response, akamai_response)
|
98
|
+
origin_cc, akamai_cc = check_max_age(origin_cc, akamai_cc)
|
99
|
+
validate_akamai_dropped(origin_cc, akamai_cc)
|
100
|
+
validate_akamai_added(origin_cc, akamai_cc)
|
101
|
+
end
|
102
|
+
end
|
103
|
+
|
104
|
+
def check_expires(origin_response, akamai_response, headers)
|
105
|
+
if [:both, :expires].include? headers
|
106
|
+
origin_expires, akamai_expires = expires(origin_response, akamai_response)
|
107
|
+
validate_expires(origin_expires, akamai_expires)
|
108
|
+
end
|
109
|
+
end
|
110
|
+
|
111
|
+
def validate_expires(origin, akamai)
|
112
|
+
unless akamai.to_i == origin.to_i
|
113
|
+
fail "Origin sent 'Expires: #{origin}' but Akamai sent 'Expires: #{akamai}'"
|
114
|
+
end
|
115
|
+
end
|
116
|
+
|
117
|
+
def expires(origin_response, akamai_response)
|
118
|
+
return origin_expires(origin_response), Time.httpdate(akamai_response.headers[:expires])
|
119
|
+
end
|
120
|
+
|
121
|
+
def origin_expires(origin_response)
|
122
|
+
expires = origin_response.headers[:expires]
|
123
|
+
expires == '0' ? Time.httpdate(origin_response.headers[:date]) : Time.httpdate(expires)
|
124
|
+
end
|
@@ -0,0 +1,40 @@
|
|
1
|
+
require 'securerandom'
|
2
|
+
require 'rspec'
|
3
|
+
require_relative 'redirects'
|
4
|
+
require_relative 'caching'
|
5
|
+
require_relative 'non_akamai'
|
6
|
+
require_relative 'honour_origin_headers'
|
7
|
+
include AkamaiHeaders
|
8
|
+
|
9
|
+
RSpec::Matchers.define :x_cache_key_contains do |contents|
|
10
|
+
match do |url|
|
11
|
+
response = RestClient::Request.responsify url
|
12
|
+
fail 'No X-Cache-Key header' if response.headers[:x_cache_key].nil?
|
13
|
+
unless response.headers[:x_cache_key].include?(contents)
|
14
|
+
fail("x_cache_key has value '#{response.headers[:x_cache_key]}' which doesn't include '#{contents}'")
|
15
|
+
end
|
16
|
+
response.code == 200 && response.headers[:x_cache_key].include?(contents)
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
module RSpec::Matchers
|
21
|
+
alias_method :be_served_from_origin, :x_cache_key_contains
|
22
|
+
alias_method :have_cp_code, :x_cache_key_contains
|
23
|
+
end
|
24
|
+
|
25
|
+
RSpec::Matchers.define :be_forwarded_to_index do |channel|
|
26
|
+
match do |url|
|
27
|
+
response = RestClient.get(url, akamai_debug_headers)
|
28
|
+
|
29
|
+
session_info = response.raw_headers['x-akamai-session-info']
|
30
|
+
if session_info.nil?
|
31
|
+
fail("x-akamai-session-info not found in the headers '#{response.raw_headers}'")
|
32
|
+
end
|
33
|
+
outcome_attribute = session_info.find { |header| header.include? 'AKA_PM_FWD_URL' }
|
34
|
+
if outcome_attribute.nil?
|
35
|
+
fail("AKA_PM_FWD_URL not found in the x-akamai-session-info header '#{session_info}'")
|
36
|
+
end
|
37
|
+
outcome_url = outcome_attribute.split('value=')[1]
|
38
|
+
response.code == 200 && outcome_url == "#{channel}"
|
39
|
+
end
|
40
|
+
end
|
@@ -0,0 +1,67 @@
|
|
1
|
+
require 'rspec'
|
2
|
+
require 'socket'
|
3
|
+
require 'openssl'
|
4
|
+
|
5
|
+
def check_ssl_serial(addr, port, url, serial)
|
6
|
+
cert_serial = ssl_cert(addr, port, url).serial.to_s(16).upcase
|
7
|
+
fail("Incorrect S/N of: #{cert_serial}") unless cert_serial == serial.upcase
|
8
|
+
end
|
9
|
+
|
10
|
+
def ssl_cert(addr, port, url)
|
11
|
+
ssl_client = ssl_client_for_verify_cert(TCPSocket.new(addr, port), addr, url)
|
12
|
+
# We get this after the request as we have layer 7 routing in Akamai
|
13
|
+
cert = OpenSSL::X509::Certificate.new(ssl_client.peer_cert)
|
14
|
+
ssl_client.sysclose
|
15
|
+
cert
|
16
|
+
end
|
17
|
+
|
18
|
+
def dummy_request(url, addr)
|
19
|
+
"GET #{url} HTTP/1.1\r\n" \
|
20
|
+
'User-Agent: Akamai-Regression-Framework\r\n' \
|
21
|
+
"Host: #{addr}\r\n" \
|
22
|
+
'Accept: */*\r\n'
|
23
|
+
end
|
24
|
+
|
25
|
+
def ssl_client_for_verify_cert(tcp_client, addr, url)
|
26
|
+
ssl_client = OpenSSL::SSL::SSLSocket.new(tcp_client)
|
27
|
+
ssl_client.sync_close = true
|
28
|
+
ssl_client.connect
|
29
|
+
ssl_client.puts(dummy_request(url, addr))
|
30
|
+
ssl_client
|
31
|
+
end
|
32
|
+
|
33
|
+
RSpec::Matchers.define :be_successful do
|
34
|
+
match do |url|
|
35
|
+
response = RestClient::Request.responsify url
|
36
|
+
fail('Response was not successful') unless response.code == 200
|
37
|
+
true
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
RSpec::Matchers.define :be_verifiably_secure do (verify = OpenSSL::SSL::VERIFY_PEER)
|
42
|
+
match do |url|
|
43
|
+
begin
|
44
|
+
RestClient::Request.execute(method: :get, url: url, verify_ssl: verify)
|
45
|
+
true
|
46
|
+
rescue => e
|
47
|
+
raise("#{url} could not be verified as secure, :sad_panda: #{e.message}")
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
RSpec::Matchers.define :be_gzipped do
|
53
|
+
match do |response_or_url|
|
54
|
+
response = RestClient::Request.responsify response_or_url
|
55
|
+
response.headers[:content_encoding] == 'gzip'
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
RSpec::Matchers.define :have_cookie do |cookie|
|
60
|
+
match do |response_or_url|
|
61
|
+
response = RestClient::Request.responsify response_or_url
|
62
|
+
unless response.cookies[cookie]
|
63
|
+
fail("Cookie #{cookie} not in #{response.cookies}")
|
64
|
+
end
|
65
|
+
response.cookies[cookie]
|
66
|
+
end
|
67
|
+
end
|
@@ -0,0 +1,28 @@
|
|
1
|
+
require 'rspec'
|
2
|
+
|
3
|
+
RSpec::Matchers.define :be_permanently_redirected_to do |expected_location|
|
4
|
+
match do |url|
|
5
|
+
redirect(url, expected_location, 301)
|
6
|
+
end
|
7
|
+
end
|
8
|
+
|
9
|
+
RSpec::Matchers.define :be_temporarily_redirected_to do |expected_location|
|
10
|
+
match do |url|
|
11
|
+
redirect(url, expected_location, 302)
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
RSpec::Matchers.define :be_temporarily_redirected_with_trailing_slash do
|
16
|
+
match do |url|
|
17
|
+
redirect(url, url + '/', 302)
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
def redirect(url, expected_location, expected_response_code)
|
22
|
+
response = RestClient.get(url) { |response, _, _| response }
|
23
|
+
fail "response was #{response.code}" unless response.code == expected_response_code
|
24
|
+
unless response.headers[:location] == expected_location
|
25
|
+
fail "redirect location was #{response.headers[:location]} (expected #{expected_location})"
|
26
|
+
end
|
27
|
+
true
|
28
|
+
end
|
@@ -0,0 +1,89 @@
|
|
1
|
+
require 'rest-client'
|
2
|
+
require 'akamai_rspec'
|
3
|
+
|
4
|
+
module RestClient
|
5
|
+
class Request
|
6
|
+
@@akamai_network = 'prod'
|
7
|
+
@@akamai_stg_domain = 'overwrite me'
|
8
|
+
@@akamai_prod_domain = 'overwrite me'
|
9
|
+
|
10
|
+
def self.domain
|
11
|
+
env = @@akamai_network
|
12
|
+
case env.downcase
|
13
|
+
when 'staging'
|
14
|
+
@@akamai_stg_domain
|
15
|
+
else
|
16
|
+
@@akamai_prod_domain
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
def self.akamai_network(env)
|
21
|
+
@@akamai_network = env
|
22
|
+
end
|
23
|
+
|
24
|
+
def self.stg_domain(domain)
|
25
|
+
@@akamai_stg_domain = domain
|
26
|
+
end
|
27
|
+
|
28
|
+
def self.prod_domain(domain)
|
29
|
+
@@akamai_prod_domain = domain
|
30
|
+
end
|
31
|
+
|
32
|
+
def self.http_url(url)
|
33
|
+
url = "/#{url}" unless url.start_with?('/')
|
34
|
+
"http://#{domain}#{url}"
|
35
|
+
end
|
36
|
+
|
37
|
+
def self.https_url(url)
|
38
|
+
url = "/#{url}" unless url.start_with?('/')
|
39
|
+
"https://#{domain}#{url}"
|
40
|
+
end
|
41
|
+
|
42
|
+
# Define the Host header and join the Akamai headers
|
43
|
+
def self.options
|
44
|
+
akamai_debug_headers
|
45
|
+
end
|
46
|
+
|
47
|
+
# Make requests to the right network
|
48
|
+
def self.http_get(url, options, cookies = {})
|
49
|
+
do_get(url, options, cookies, false)
|
50
|
+
end
|
51
|
+
|
52
|
+
def self.https_get(url, options, cookies = {})
|
53
|
+
do_get(url, options, cookies, true)
|
54
|
+
end
|
55
|
+
|
56
|
+
def self.do_get(url, options, cookies = {}, is_secure)
|
57
|
+
if is_secure
|
58
|
+
base_url = https_url(url)
|
59
|
+
else
|
60
|
+
base_url = http_url(url)
|
61
|
+
end
|
62
|
+
headers = options.merge(akamai_debug_headers).merge(cookies)
|
63
|
+
do_get_no_ssl(base_url, headers) { |response, _, _| response }
|
64
|
+
end
|
65
|
+
|
66
|
+
def self.do_get_no_ssl(url, additional_headers = {}, &block)
|
67
|
+
headers = (options[:headers] || {}).merge(additional_headers)
|
68
|
+
RestClient::Request.execute(options.merge(
|
69
|
+
method: :get,
|
70
|
+
url: url,
|
71
|
+
verify_ssl: false,
|
72
|
+
headers: headers), &(block || @block))
|
73
|
+
end
|
74
|
+
|
75
|
+
def self.responsify(maybe_a_url)
|
76
|
+
if maybe_a_url.is_a? RestClient::Response
|
77
|
+
maybe_a_url
|
78
|
+
else
|
79
|
+
RestClient.get(maybe_a_url, akamai_debug_headers)
|
80
|
+
end
|
81
|
+
end
|
82
|
+
|
83
|
+
def self.request_cache_miss(url)
|
84
|
+
url += url.include?('?') ? '&' : '?'
|
85
|
+
url += SecureRandom.hex
|
86
|
+
RestClient.get(url, akamai_debug_headers)
|
87
|
+
end
|
88
|
+
end
|
89
|
+
end
|
data/lib/akamai_rspec.rb
ADDED
metadata
ADDED
@@ -0,0 +1,92 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: akamai_rspec
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.2.1
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Bianca Gibson
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2015-07-19 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: rest-client
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - ~>
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '1.7'
|
20
|
+
type: :runtime
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - ~>
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '1.7'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: json
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - ~>
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '1.8'
|
34
|
+
type: :runtime
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - ~>
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '1.8'
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: rspec
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - ~>
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: '3.2'
|
48
|
+
type: :runtime
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - ~>
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '3.2'
|
55
|
+
description:
|
56
|
+
email: bianca.gibson@rea-group.com
|
57
|
+
executables: []
|
58
|
+
extensions: []
|
59
|
+
extra_rdoc_files: []
|
60
|
+
files:
|
61
|
+
- lib/akamai_rspec.rb
|
62
|
+
- lib/akamai_rspec/akamai_headers.rb
|
63
|
+
- lib/akamai_rspec/matchers/caching.rb
|
64
|
+
- lib/akamai_rspec/matchers/honour_origin_headers.rb
|
65
|
+
- lib/akamai_rspec/matchers/matchers.rb
|
66
|
+
- lib/akamai_rspec/matchers/non_akamai.rb
|
67
|
+
- lib/akamai_rspec/matchers/redirects.rb
|
68
|
+
- lib/akamai_rspec/request.rb
|
69
|
+
homepage:
|
70
|
+
licenses: []
|
71
|
+
metadata: {}
|
72
|
+
post_install_message:
|
73
|
+
rdoc_options: []
|
74
|
+
require_paths:
|
75
|
+
- lib
|
76
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
77
|
+
requirements:
|
78
|
+
- - '>='
|
79
|
+
- !ruby/object:Gem::Version
|
80
|
+
version: '0'
|
81
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
82
|
+
requirements:
|
83
|
+
- - '>='
|
84
|
+
- !ruby/object:Gem::Version
|
85
|
+
version: '0'
|
86
|
+
requirements: []
|
87
|
+
rubyforge_project:
|
88
|
+
rubygems_version: 2.1.11
|
89
|
+
signing_key:
|
90
|
+
specification_version: 4
|
91
|
+
summary: Test your akamai configuration with rspec
|
92
|
+
test_files: []
|