akamai_rspec 0.4.0 → 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: fb49bd44abd110079985c0b84fa3dcd5c5c792c0
4
- data.tar.gz: 27e1ebf081198f4a3cd07401ea6c8850a901ef90
3
+ metadata.gz: b6ca676a572b65fda62bd771e10b8472cdcb1704
4
+ data.tar.gz: e782f1e731582d5feb4270fbace5d6fef0eb4b46
5
5
  SHA512:
6
- metadata.gz: 66a85bda03be573909a293684fbd98cf41b221a2b3201ddbda984bc02801cda7915fa12b9f95aa89db5dd605f9c77f37427abb057e8016d0de25a470ea1f5571
7
- data.tar.gz: 34c2714e8b34e4ef63e3795133fd5e9df6e9c44559a521d19410e7cb5f9f088f1fd38bc371f1aa28f36d5ab5ea877f03ecec3d80483aff82cc7025d6f63e812a
6
+ metadata.gz: 6f58ba2ed53d2f7edcb81f449b9e658940f69c6a7aa1cd9e938d34ad6ab3a48597325791f2b95fe157c57b62b5913668fc4e5091bc619a65b7bf4fa24b8d140f
7
+ data.tar.gz: 371fbd6072b3a66a3e2db22d1b6186558a898f2448e799bfad310a9983939c79e7956e9d28ab37b14ef830276c3bbc8de2443da9d52efc5d1e692343c6049f82
data/lib/akamai_rspec.rb CHANGED
@@ -1,4 +1,6 @@
1
- require 'akamai_rspec/akamai_headers'
2
- require 'akamai_rspec/matchers/matchers'
1
+ require 'akamai_rspec/matchers'
3
2
  require 'akamai_rspec/request'
4
3
  require 'akamai_rspec/response'
4
+
5
+ module AkamaiRSpec
6
+ end
@@ -0,0 +1,17 @@
1
+
2
+ module AkamaiRSpec
3
+ module Helpers
4
+ module CacheHeaders
5
+ X_CACHE_HEADERS = [:x_true_cache_key, :x_cache_key]
6
+
7
+ def x_cache_headers
8
+ X_CACHE_HEADERS
9
+ end
10
+
11
+ def cache_headers
12
+ x_cache_headers.map {|key| @response.headers[key] }
13
+ end
14
+
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,42 @@
1
+
2
+ module AkamaiRSpec
3
+ module Helpers
4
+ module ChainableRedirect
5
+ def self.included(other)
6
+ other.chain :then do |matcher|
7
+ (@and_then_matchers ||= []).push(matcher)
8
+ end
9
+ end
10
+
11
+ def with_and_without_tls(url)
12
+ url = "http://#{url}" unless URI(url).scheme
13
+ url = url.gsub(/^https:/i, 'http:')
14
+ secure = url.gsub(/^http:/i, 'https:')
15
+ return secure, url
16
+ end
17
+
18
+ def redirect(url, expected_location, expected_response_code)
19
+ response = AkamaiRSpec::Request.get(url)
20
+ fail "Response was #{response.inspect}, expected code #{expected_response_code}" unless response.code == expected_response_code
21
+ unless expected_location === response.headers[:location]
22
+ fail "redirect location was #{response.headers[:location]} (expected #{expected_location})"
23
+ end
24
+
25
+ if @and_then_matchers
26
+ begin
27
+ @and_then_matchers.each {|matcher| expect(response.headers[:location]).to matcher}
28
+ rescue Exception => e
29
+ @and_then_error = e
30
+ return false
31
+ end
32
+ end
33
+
34
+ true
35
+ end
36
+
37
+ def failure_message
38
+ @and_then_error || super
39
+ end
40
+ end
41
+ end
42
+ end
@@ -0,0 +1,15 @@
1
+ require 'securerandom'
2
+ require 'rspec'
3
+
4
+ module AkamaiRSpec
5
+ module Matchers
6
+ extend RSpec::Matchers::DSL
7
+ end
8
+ end
9
+
10
+ require_relative 'matchers/redirects'
11
+ require_relative 'matchers/caching'
12
+ require_relative 'matchers/non_akamai'
13
+ require_relative 'matchers/honour_origin_headers'
14
+ require_relative 'matchers/x_cache_headers'
15
+ require_relative 'matchers/forward_to_index'
@@ -1,44 +1,68 @@
1
1
  require 'rspec'
2
2
  require 'securerandom'
3
- require 'akamai_rspec/akamai_headers'
4
-
5
- RSpec::Matchers.define :be_cacheable do |opts={request_count: 10}|
6
- match do |url|
7
- responses = [1..opts[:request_count]].map { AkamaiRSpec::Request.get_with_debug_headers url }
8
-
9
- responses.any? do |response|
10
- fail("Error fetching #{url}: #{response}") if response.code != 200
11
- (
12
- (response.headers[:x_cache] =~ /TCP(\w+)?_HIT/) and not
13
- (response.headers[:x_cache] =~ /TCP_REFRESH/)
14
- )
3
+ require 'akamai_rspec/request'
4
+
5
+ module AkamaiRSpec
6
+ module Matchers
7
+ define :be_cacheable do |request_count: 4, headers: {}, allow_refresh: false|
8
+ match do |url|
9
+ @responses = (1..request_count).map {
10
+ AkamaiRSpec::Request.get url, headers
11
+ }
12
+
13
+ @responses.any? do |response|
14
+ fail("Error fetching #{url}: #{response}") if response.code != 200
15
+ return allow_refresh if refresh_hit? response
16
+ hit?(response)
17
+ end
18
+ end
19
+
20
+ def refresh_hit?(response)
21
+ response.headers[:x_cache] =~ /TCP_REFRESH/
22
+ end
23
+
24
+ def hit?(response)
25
+ response.headers[:x_cache] =~ /TCP(\w+)?_HIT/
26
+ end
27
+
28
+ def suggest_allow_refresh?(allow_refresh)
29
+ !allow_refresh &&
30
+ !@responses.any?(&method(:hit?)) &&
31
+ @responses.any?(&method(:refresh_hit?))
32
+ end
33
+
34
+ description do
35
+ msg = "to be cacheable (got #{cache_headers} from #{@responses.length} requests)"
36
+ msg += ". Try setting 'allow_refresh: true'." if suggest_allow_refresh?(allow_refresh)
37
+ msg
38
+ end
39
+
40
+ def cache_headers
41
+ @responses.map {|response| response.headers[:x_cache] }
42
+ end
15
43
  end
16
- end
17
- end
18
44
 
19
- module RSpec::Matchers
20
- alias_method :be_cachable, :be_cacheable
21
- alias_method :be_cached, :be_cacheable
22
- define_negated_matcher :not_be_cached, :be_cached
23
- end
45
+ alias_method :be_cachable, :be_cacheable
46
+ alias_method :be_cached, :be_cacheable
24
47
 
25
- RSpec::Matchers.define :have_no_cache_set do
26
- match do |url|
27
- response = AkamaiRSpec::Request.get url
28
- cache_control = response.headers[:cache_control]
29
- return cache_control == 'no-cache'
30
- end
31
- end
48
+ define :have_no_cache_set do
49
+ match do |url|
50
+ response = AkamaiRSpec::Request.get url
51
+ cache_control = response.headers[:cache_control]
52
+ return cache_control == 'no-cache'
53
+ end
54
+ end
32
55
 
56
+ define :be_tier_distributed do
57
+ match do |url|
58
+ response = AkamaiRSpec::Request.get_cache_miss(url)
59
+ @tiered = !response.headers[:x_cache_remote].empty?
60
+ response.code == 200 && @tiered
61
+ end
33
62
 
34
- RSpec::Matchers.define :be_tier_distributed do
35
- match do |url|
36
- response = AkamaiRSpec::Request.get_cache_miss(url)
37
- @tiered = !response.headers[:x_cache_remote].nil?
38
- response.code == 200 && @tiered
39
- end
40
- description do
41
- "be tier distributed (as indicated by the presence of an X-Cache-Remote header in response)"
63
+ description do
64
+ "be tier distributed (as indicated by the presence of an X-Cache-Remote header in response)"
65
+ end
66
+ end
42
67
  end
43
68
  end
44
-
@@ -0,0 +1,20 @@
1
+
2
+ module AkamaiRSpec
3
+ module Matchers
4
+ define :be_forwarded_to_index do |channel|
5
+ match do |url|
6
+ response = Request.get(url)
7
+ session_info = response.headers[:x_akamai_session_info]
8
+ if session_info.nil?
9
+ fail("x-akamai-session-info not found in the headers '#{response.headers}'")
10
+ end
11
+ outcome_attribute = session_info.find { |header| header.include? 'AKA_PM_FWD_URL' }
12
+ if outcome_attribute.nil?
13
+ fail("AKA_PM_FWD_URL not found in the x-akamai-session-info header '#{session_info}'")
14
+ end
15
+ outcome_url = outcome_attribute.split('value=')[1]
16
+ response.code == 200 && outcome_url == "#{channel}"
17
+ end
18
+ end
19
+ end
20
+ end
@@ -3,122 +3,130 @@ require 'set'
3
3
  require 'time'
4
4
  require 'uri'
5
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 = AkamaiRSpec::Request.get 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
6
+ module AkamaiRSpec
7
+ module Matchers
8
+
9
+ define :honour_origin_cache_headers do |origin, headers=:both|
10
+ header_options = [:cache_control, :expires, :both]
11
+ fail("Headers must be one of: #{header_options}") unless header_options.include? headers
12
+
13
+ match do |url|
14
+ akamai_response = AkamaiRSpec::Request.get url
15
+ url = "http://" + url unless url =~ /^http/
16
+ origin_url = URI(url)
17
+ origin_url.host = URI(origin).hostname || origin
18
+ origin_response = origin_response(origin_url.to_s)
19
+ check_cache_control(origin_response, akamai_response, headers)
20
+ check_expires(origin_response, akamai_response, headers)
21
+ true
22
+ end
23
+
24
+ def fix_date_header(origin_response)
25
+ origin_response.headers[:date] ||= Time.now.httpdate
26
+ origin_response
27
+ end
28
+
29
+ def origin_response(origin)
30
+ fix_date_header(RestClient::Request.execute(method: :get, url: origin, verify_ssl: false))
31
+ end
32
+
33
+ def clean_cc_directives(origin_response, akamai_response)
34
+ origin_cc_directives = origin_response.headers[:cache_control].split(/[, ]+/).to_set
35
+ akamai_cc_directives = akamai_response.headers[:cache_control].split(/[, ]+/).to_set
36
+
37
+ origin_cc_directives.delete 'must-revalidate' # as Akamai does no pass it on
38
+ return origin_cc_directives, akamai_cc_directives
39
+ end
40
+
41
+ def cc_directives(origin_response, akamai_response)
42
+ origin_cc, akamai_cc = clean_cc_directives(origin_response, akamai_response)
43
+ check_cc(origin_cc, akamai_cc) unless (origin_cc & ['no-store', 'no-cache']).empty?
44
+ return origin_cc, akamai_cc
45
+ end
46
+
47
+ def check_and_clean_header(origin_cc, akamai_cc, expected)
48
+ unless akamai_cc.include? expected
49
+ fail "Akamai was expected to, but did not, add 'Cache-Control: #{expected}' as Origin sent 'no-store' or 'no-cache'"
50
+ end
51
+ akamai_cc.delete expected unless origin_cc.include? expected
52
+ akamai_cc
53
+ end
54
+
55
+ def check_cc(origin_cc, akamai_cc)
56
+ ['no-store', 'max-age=0'].each do |expected|
57
+ akamai_cc = check_and_clean_header(origin_cc, akamai_cc, expected)
58
+ end
59
+ return origin_cc, akamai_cc
60
+ end
61
+
62
+ def max_age(cc_directives)
63
+ cc_directives.detect { |d| d.start_with? 'max-age=' }
64
+ end
65
+
66
+ def max_age_to_num(max_age)
67
+ max_age.split('=').last.to_i
68
+ end
69
+
70
+ def clean_max_age(cc_directives)
71
+ max_age = max_age(cc_directives)
72
+ cc_directives.delete max_age if max_age
73
+ return max_age_to_num(max_age), cc_directives
74
+ end
75
+
76
+ def check_max_age(origin_cc_directives, akamai_cc_directives)
77
+ origin_max_age, origin_cc_directives = clean_max_age(origin_cc_directives)
78
+ akamai_max_age, akamai_cc_directives = clean_max_age(akamai_cc_directives)
79
+ if akamai_max_age > origin_max_age
80
+ fail "Akamai sent a max-age greater than Origin's: #{akamai_max_age} > #{origin_max_age}"
81
+ end
82
+ return origin_cc_directives, akamai_cc_directives
83
+ end
84
+
85
+ def validate_akamai_dropped(origin_cc, akamai_cc)
86
+ dropped = origin_cc - akamai_cc
87
+ unless dropped.empty?
88
+ fail "Origin sent 'Cache-Control: #{dropped.to_a.join ','}', but Akamai did not."
89
+ end
90
+ end
91
+
92
+ def validate_akamai_added(origin_cc, akamai_cc)
93
+ added = akamai_cc - origin_cc
94
+ unless added.empty?
95
+ fail "Akamai unexpectedly added 'Cache-Control: #{added.to_a.join ','}'"
96
+ end
97
+ end
98
+
99
+ def check_cache_control(origin_response, akamai_response, headers)
100
+ if [:both, :cache_control].include? headers
101
+ origin_cc, akamai_cc = cc_directives(origin_response, akamai_response)
102
+ origin_cc, akamai_cc = check_max_age(origin_cc, akamai_cc)
103
+ validate_akamai_dropped(origin_cc, akamai_cc)
104
+ validate_akamai_added(origin_cc, akamai_cc)
105
+ end
106
+ end
107
+
108
+ def check_expires(origin_response, akamai_response, headers)
109
+ if [:both, :expires].include? headers
110
+ origin_expires, akamai_expires = expires(origin_response, akamai_response)
111
+ validate_expires(origin_expires, akamai_expires)
112
+ end
113
+ end
114
+
115
+ def validate_expires(origin, akamai)
116
+ unless akamai.to_i == origin.to_i
117
+ fail "Origin sent 'Expires: #{origin}' but Akamai sent 'Expires: #{akamai}'"
118
+ end
119
+ end
120
+
121
+ def expires(origin_response, akamai_response)
122
+ return origin_expires(origin_response), Time.httpdate(akamai_response.headers[:expires])
123
+ end
124
+
125
+ def origin_expires(origin_response)
126
+ expires = origin_response.headers[:expires]
127
+ expires == '0' ? Time.httpdate(origin_response.headers[:date]) : Time.httpdate(expires)
128
+ end
129
+
130
+ end
17
131
  end
18
132
  end
19
-
20
- def fix_date_header(origin_response)
21
- origin_response.headers[:date] ||= Time.now.httpdate
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
@@ -3,76 +3,77 @@ require 'socket'
3
3
  require 'openssl'
4
4
  require 'uri'
5
5
 
6
- def check_ssl_serial(addr, port, url, serial)
7
- cert_serial = ssl_cert(addr, port, url).serial.to_s(16).upcase
8
- fail("Incorrect S/N of: #{cert_serial}") unless cert_serial == serial.upcase
9
- end
10
-
11
- def ssl_cert(addr, port, url)
12
- ssl_client = ssl_client_for_verify_cert(TCPSocket.new(addr, port), addr, url)
13
- # We get this after the request as we have layer 7 routing in Akamai
14
- cert = OpenSSL::X509::Certificate.new(ssl_client.peer_cert)
15
- ssl_client.sysclose
16
- cert
17
- end
6
+ module AkamaiRSpec
7
+ module Matchers
8
+ define :be_successful do |response_codes=(200..299)|
9
+ match do |url|
10
+ @response = AkamaiRSpec::Request.get url
11
+ response_codes === @response.code
12
+ end
18
13
 
19
- def dummy_request(url, addr)
20
- "GET #{url} HTTP/1.1\r\n" \
21
- 'User-Agent: Akamai-Regression-Framework\r\n' \
22
- "Host: #{addr}\r\n" \
23
- 'Accept: */*\r\n'
24
- end
14
+ failure_message do |url|
15
+ "Response #{@response} was not successful for #{url}"
16
+ end
17
+ end
25
18
 
26
- def ssl_client_for_verify_cert(tcp_client, addr, url)
27
- ssl_client = OpenSSL::SSL::SSLSocket.new(tcp_client)
28
- ssl_client.sync_close = true
29
- ssl_client.connect
30
- ssl_client.puts(dummy_request(url, addr))
31
- ssl_client
32
- end
19
+ define :respond_with_headers do |headers|
20
+ match do |url|
21
+ @response = AkamaiRSpec::Request.get url
22
+ headers.each do |k, v|
23
+ fail "Expected header #{k} to be #{v}, got #{@response.headers[k]}" unless @response.headers[k] == v
24
+ end
25
+ true
26
+ end
27
+ end
33
28
 
34
- RSpec::Matchers.define :be_successful do
35
- match do |url|
36
- response = AkamaiRSpec::Request.get url
37
- fail('Response was not successful') unless response.code == 200
38
- true
39
- end
40
- end
29
+ define :be_verifiably_secure do
30
+ match do |url|
31
+ return false if URI(url).scheme == "http"
32
+ url = "https://#{url}" unless URI(url).scheme
33
+ begin
34
+ # Avoid AkamaiRspec::Request as it turns off SSL checking
35
+ @response = RestClient::Request.execute(method: :get, url: url, verify_ssl: OpenSSL::SSL::VERIFY_PEER)
36
+ return true
37
+ rescue => e
38
+ @error = e
39
+ return false
40
+ end
41
+ end
41
42
 
42
- RSpec::Matchers.define :be_verifiably_secure do (verify = OpenSSL::SSL::VERIFY_PEER)
43
- match do |url|
44
- return false if URI(url).scheme == "http"
45
- url = "https://#{url}" unless URI(url).scheme
46
- begin
47
- RestClient::Request.execute(method: :get, url: url, verify_ssl: verify)
48
- return true
49
- rescue => e
50
- return false
43
+ failure_message do |url|
44
+ "got error #{@error} fetching #{@response}"
45
+ end
51
46
  end
52
- end
53
- end
54
47
 
55
- RSpec::Matchers.define :be_gzipped do
56
- match do |response_or_url|
57
- response = AkamaiRSpec::Request.get_decode response_or_url
58
- response.headers[:content_encoding] == 'gzip'
59
- end
60
- end
48
+ define :be_gzipped do
49
+ match do |url|
50
+ @response = AkamaiRSpec::Request.get_decode url
51
+ @response.headers[:content_encoding] == 'gzip'
52
+ end
53
+ failure_message do |url|
54
+ "Expected #{url} to be gzipped (got #{@response})"
55
+ end
56
+ end
61
57
 
62
- RSpec::Matchers.define :have_cookie do |cookie|
63
- match do |response_or_url|
64
- response = AkamaiRSpec::Request.get response_or_url
65
- unless response.cookies[cookie]
66
- fail("Cookie #{cookie} not in #{response.cookies}")
58
+ define :have_cookie do |cookie, value=nil|
59
+ match do |response_or_url|
60
+ response = AkamaiRSpec::Request.get response_or_url
61
+ unless response.cookies[cookie]
62
+ fail("Cookie #{cookie} not in #{response.cookies}")
63
+ end
64
+ if value && response.cookies[cookie] != value
65
+ fail("Cookie #{cookie} was set to #{response.cookies[cookie]}, expected #{value}")
66
+ end
67
+ !!response.cookies[cookie]
68
+ end
67
69
  end
68
- response.cookies[cookie]
69
- end
70
- end
71
70
 
72
- RSpec::Matchers.define :be_forbidden do
73
- match do |url|
74
- response = AkamaiRSpec::Request.get url
75
- fail('Response was not forbidden') unless response.code == 403
76
- true
71
+ define :be_forbidden do
72
+ match do |url|
73
+ response = AkamaiRSpec::Request.get url
74
+ fail("Response #{response} was not forbidden") unless response.code == 403
75
+ true
76
+ end
77
+ end
77
78
  end
78
79
  end
@@ -1,28 +1,53 @@
1
1
  require 'rspec'
2
+ require 'uri'
3
+ require 'akamai_rspec/helpers/chainable_redirect'
2
4
 
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
5
+ module AkamaiRSpec
6
+ module Matchers
7
+ define :be_permanently_redirected_to do |expected_location|
8
+ include AkamaiRSpec::Helpers::ChainableRedirect
9
+ match do |url|
10
+ redirect(url, expected_location, 301)
11
+ end
12
+ end
8
13
 
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
+ define :be_temporarily_redirected_to do |expected_location|
15
+ include AkamaiRSpec::Helpers::ChainableRedirect
16
+ match do |url|
17
+ redirect(url, expected_location, 302)
18
+ end
19
+ end
14
20
 
15
- RSpec::Matchers.define :be_temporarily_redirected_with_trailing_slash do
16
- match do |url|
17
- redirect(url, url + '/', 302)
18
- end
19
- end
21
+ define :redirect_http_to_https do |with: 301|
22
+ include AkamaiRSpec::Helpers::ChainableRedirect
23
+ match do |url|
24
+ secure, url = with_and_without_tls(url)
25
+ redirect(url, secure, with)
26
+ end
27
+ end
28
+
29
+ define :redirect_https_to_http do |with: 301|
30
+ include AkamaiRSpec::Helpers::ChainableRedirect
31
+ match do |url|
32
+ secure, url = with_and_without_tls(url)
33
+ redirect(secure, url, with)
34
+ end
35
+ end
36
+
37
+ define :redirect_to_add_trailing_slash do |with: 301|
38
+ include AkamaiRSpec::Helpers::ChainableRedirect
39
+ match do |url|
40
+ without_trailing_slash = url.gsub(/\/+$/, '')
41
+ with_trailing_slash = without_trailing_slash + "/"
42
+ redirect(without_trailing_slash, with_trailing_slash, with)
43
+ end
44
+ end
20
45
 
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})"
46
+ define :be_temporarily_redirected_with_trailing_slash do
47
+ include AkamaiRSpec::Helpers::ChainableRedirect
48
+ match do |url|
49
+ redirect(url, url + '/', 302)
50
+ end
51
+ end
26
52
  end
27
- true
28
53
  end
@@ -1,29 +1,35 @@
1
1
  require 'rspec'
2
+ require 'akamai_rspec/helpers/cache_headers'
2
3
 
3
4
  module AkamaiRSpec
4
- module Helpers
5
- X_CACHE_HEADERS = [:x_true_cache_key, :x_cache_key]
5
+ module Matchers
6
+ define :be_served_from_origin do |contents|
7
+ include AkamaiRSpec::Helpers::CacheHeaders
6
8
 
7
- def x_cache_headers
8
- X_CACHE_HEADERS
9
+ match do |url|
10
+ @response = AkamaiRSpec::Request.get url
11
+ cache_headers.any? {|h| h.split("/").include? contents}
12
+ end
13
+
14
+ failure_message do |actual|
15
+ "expected \"#{actual}\" to be served from origin \"#{contents}\"; got #{@response} and the cache headers indicated '#{cache_headers.inspect}'"
16
+ end
9
17
  end
10
- end
11
- end
12
18
 
13
- RSpec::Matchers.define :be_served_from_origin do |contents|
14
- include AkamaiRSpec::Helpers
15
- match do |url|
16
- response = AkamaiRSpec::Request.get url
17
- response.headers.any? { |key, value| x_cache_headers.include?(key) && value =~ /\/#{contents}\// } && \
18
- response.code == 200
19
- end
20
- end
19
+ define :have_cp_code do |contents|
20
+ include AkamaiRSpec::Helpers::CacheHeaders
21
+ match do |url|
22
+ @response = AkamaiRSpec::Request.get url
23
+ @response.code == 200 && cache_headers.any? do |value|
24
+ value.to_s.split("/").include? contents
25
+ end
26
+ end
21
27
 
22
- RSpec::Matchers.define :have_cp_code do |contents|
23
- include AkamaiRSpec::Helpers
24
- match do |url|
25
- response = AkamaiRSpec::Request.get url
26
- response.headers.any? { |key, value| x_cache_headers.include?(key) && value == contents } && \
27
- response.code == 200
28
+ failure_message do |url|
29
+ headers = {}
30
+ x_cache_headers.each {|h| headers[h] = @response.headers[h] }
31
+ "Expected #{url} to have cp_code #{contents} but responded with #{headers.to_json}"
32
+ end
33
+ end
28
34
  end
29
35
  end
@@ -20,26 +20,42 @@ module AkamaiRSpec
20
20
  @@env = env
21
21
  end
22
22
 
23
- def self.get(url)
24
- new.get(url)
23
+ def self.get(url, headers={})
24
+ new.get(url, headers.merge(debug_headers))
25
25
  end
26
26
 
27
- def self.get_with_debug_headers(url)
28
- new.get(url, AkamaiHeaders.akamai_debug_headers)
27
+ def self.get_without_debug_headers(url, headers={})
28
+ new.get(url, headers)
29
29
  end
30
30
 
31
31
  def self.get_cache_miss(url)
32
32
  url += url.include?('?') ? '&' : '?'
33
33
  url += SecureRandom.hex
34
- new.get(url, AkamaiHeaders.akamai_debug_headers)
34
+ get(url)
35
35
  end
36
36
 
37
37
  def self.get_decode(url)
38
- response = new.get(url, AkamaiHeaders.akamai_debug_headers)
38
+ response = new.get(url, debug_headers.merge({'Accept-Encoding' => 'gzip'}))
39
39
  RestClient::Request.decode(response.headers[:content_encoding], response.body)
40
40
  response
41
41
  end
42
42
 
43
+ def self.debug_headers
44
+ {
45
+ pragma: [
46
+ 'akamai-x-cache-on',
47
+ 'akamai-x-cache-remote-on',
48
+ 'akamai-x-check-cacheable',
49
+ 'akamai-x-get-cache-key',
50
+ 'akamai-x-get-extracted-values',
51
+ 'akamai-x-get-nonces',
52
+ 'akamai-x-get-ssl-client-session-id',
53
+ 'akamai-x-get-true-cache-key',
54
+ 'akamai-x-serial-no'
55
+ ].join(", ")
56
+ }
57
+ end
58
+
43
59
  def initialize
44
60
  @@env ||= 'prod'
45
61
 
@@ -47,7 +63,7 @@ module AkamaiRSpec
47
63
  when 'staging'
48
64
  if @@akamai_stg_domain.nil?
49
65
  raise ArgumentError.new(
50
- "You must set the prod domain: AkamaiRSpec::Request.stg_domain = 'www.example.com.edgesuite.net'"
66
+ "You must set the staging domain: AkamaiRSpec::Request.stg_domain = 'www.example.com.edgesuite.net'"
51
67
  )
52
68
  end
53
69
 
@@ -70,12 +86,18 @@ module AkamaiRSpec
70
86
  delegate [:parse_url_with_auth, :stringify_headers] => :@rest_client
71
87
 
72
88
  def get(url, headers = {})
73
- if url.is_a? RestClient::Response
89
+ # DO NOT USE url.is_a? here - some versions of
90
+ # the JSON gem monkey patch String which causes it to match.
91
+
92
+ if url.class.ancestors.include? RestClient::Response
74
93
  return AkamaiRSpec::Response.new(url)
75
94
  end
76
95
 
77
- uri = parse_url_with_auth(url)
96
+ if url.class.ancestors.include? AkamaiRSpec::Response
97
+ return url
98
+ end
78
99
 
100
+ uri = parse_url_with_auth(url)
79
101
  req = build_request(uri, stringify_headers(headers))
80
102
 
81
103
  req['Host'] = uri.hostname
@@ -6,6 +6,7 @@ module AkamaiRSpec
6
6
 
7
7
  def headers
8
8
  headers = Hash[@response.to_hash.map{ |k, v| [k.gsub(/-/,'_').downcase.to_sym, v] }]
9
+ headers.default = ""
9
10
  headers.each do |k, v|
10
11
  if v.is_a?(Array) && v.size == 1
11
12
  headers[k] = v.first
@@ -20,26 +21,36 @@ module AkamaiRSpec
20
21
  end
21
22
 
22
23
  def cookies
23
- cookie_header = headers.to_hash[:set_cookie]
24
- if cookie_header
25
- if cookie_header.is_a?(Array)
26
- cookies_string = cookie_header.collect do |header_value|
27
- header_value.split('; ')
28
- end
29
- cookies_string.flatten!
30
- cookies_array = cookies_string.collect { |c| c.split('=') }
31
- else
32
- cookies_array = [cookie_header.split('=')]
33
- end
24
+ cookies = {}
34
25
 
35
- Hash[cookies_array]
36
- else
37
- {}
26
+ [headers[:set_cookie]].flatten.each do |cookie|
27
+ name, value = cookie.split(/=/, 2)
28
+ cookies[name] = value
38
29
  end
30
+ cookies
39
31
  end
40
32
 
41
33
  def method_missing(method, *args)
42
34
  @response.send(method, *args)
43
35
  end
36
+
37
+ def to_s
38
+ case code
39
+ when 0..99
40
+ "Invalid status code #{code}"
41
+ when 100..199
42
+ "Informational: #{code}"
43
+ when 200..299
44
+ "Success: #{code}"
45
+ when 300..399
46
+ "Redirect #{code} to #{headers[:location]}"
47
+ when 400..499
48
+ "Client error #{code}"
49
+ when 500..599
50
+ "Server error #{code}"
51
+ else
52
+ "Unknown status code #{code}"
53
+ end
54
+ end
44
55
  end
45
56
  end
metadata CHANGED
@@ -1,14 +1,15 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: akamai_rspec
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.4.0
4
+ version: 1.0.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Bianca Gibson
8
+ - Daniel Heath
8
9
  autorequire:
9
10
  bindir: bin
10
11
  cert_chain: []
11
- date: 2016-10-21 00:00:00.000000000 Z
12
+ date: 2016-10-28 00:00:00.000000000 Z
12
13
  dependencies:
13
14
  - !ruby/object:Gem::Dependency
14
15
  name: rest-client
@@ -59,10 +60,12 @@ extensions: []
59
60
  extra_rdoc_files: []
60
61
  files:
61
62
  - lib/akamai_rspec.rb
62
- - lib/akamai_rspec/akamai_headers.rb
63
+ - lib/akamai_rspec/helpers/cache_headers.rb
64
+ - lib/akamai_rspec/helpers/chainable_redirect.rb
65
+ - lib/akamai_rspec/matchers.rb
63
66
  - lib/akamai_rspec/matchers/caching.rb
67
+ - lib/akamai_rspec/matchers/forward_to_index.rb
64
68
  - lib/akamai_rspec/matchers/honour_origin_headers.rb
65
- - lib/akamai_rspec/matchers/matchers.rb
66
69
  - lib/akamai_rspec/matchers/non_akamai.rb
67
70
  - lib/akamai_rspec/matchers/redirects.rb
68
71
  - lib/akamai_rspec/matchers/x_cache_headers.rb
@@ -1,7 +0,0 @@
1
- module AkamaiHeaders
2
- def self.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
@@ -1,25 +0,0 @@
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
- require_relative 'x_cache_headers'
8
- include AkamaiHeaders
9
-
10
- RSpec::Matchers.define :be_forwarded_to_index do |channel|
11
- match do |url|
12
- response = RestClient.get(url, akamai_debug_headers)
13
-
14
- session_info = response.raw_headers['x-akamai-session-info']
15
- if session_info.nil?
16
- fail("x-akamai-session-info not found in the headers '#{response.raw_headers}'")
17
- end
18
- outcome_attribute = session_info.find { |header| header.include? 'AKA_PM_FWD_URL' }
19
- if outcome_attribute.nil?
20
- fail("AKA_PM_FWD_URL not found in the x-akamai-session-info header '#{session_info}'")
21
- end
22
- outcome_url = outcome_attribute.split('value=')[1]
23
- response.code == 200 && outcome_url == "#{channel}"
24
- end
25
- end