puffing-billy 0.4.1 → 0.5.0
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/CHANGELOG.md +7 -0
- data/Gemfile.lock +2 -2
- data/Guardfile +5 -5
- data/README.md +19 -1
- data/Rakefile +1 -1
- data/lib/billy.rb +17 -17
- data/lib/billy/cache.rb +30 -31
- data/lib/billy/config.rb +4 -2
- data/lib/billy/handlers/cache_handler.rb +5 -7
- data/lib/billy/handlers/handler.rb +2 -2
- data/lib/billy/handlers/proxy_handler.rb +16 -16
- data/lib/billy/handlers/request_handler.rb +6 -8
- data/lib/billy/handlers/stub_handler.rb +2 -2
- data/lib/billy/json_utils.rb +1 -2
- data/lib/billy/proxy_connection.rb +5 -5
- data/lib/billy/proxy_request_stub.rb +7 -7
- data/lib/billy/version.rb +1 -1
- data/lib/tasks/billy.rake +13 -15
- data/puffing-billy.gemspec +28 -28
- data/spec/features/examples/facebook_api_spec.rb +7 -7
- data/spec/features/examples/tumblr_api_spec.rb +6 -6
- data/spec/lib/billy/cache_spec.rb +14 -16
- data/spec/lib/billy/handlers/cache_handler_spec.rb +26 -24
- data/spec/lib/billy/handlers/handler_spec.rb +3 -3
- data/spec/lib/billy/handlers/proxy_handler_spec.rb +18 -16
- data/spec/lib/billy/handlers/request_handler_spec.rb +44 -42
- data/spec/lib/billy/handlers/stub_handler_spec.rb +14 -12
- data/spec/lib/billy/proxy_request_stub_spec.rb +55 -42
- data/spec/lib/billy/resource_utils_spec.rb +17 -17
- data/spec/lib/proxy_spec.rb +62 -70
- data/spec/spec_helper.rb +3 -3
- data/spec/support/test_server.rb +2 -2
- metadata +6 -6
@@ -6,9 +6,9 @@ module Billy
|
|
6
6
|
def_delegators :stub_handler, :stub
|
7
7
|
|
8
8
|
def handlers
|
9
|
-
@handlers ||= { :
|
10
|
-
:
|
11
|
-
:
|
9
|
+
@handlers ||= { stubs: StubHandler.new,
|
10
|
+
cache: CacheHandler.new,
|
11
|
+
proxy: ProxyHandler.new }
|
12
12
|
end
|
13
13
|
|
14
14
|
def handle_request(method, url, headers, body)
|
@@ -20,7 +20,7 @@ module Billy
|
|
20
20
|
end
|
21
21
|
|
22
22
|
body_msg = method == 'post' ? " with body '#{body}'" : ''
|
23
|
-
{ :
|
23
|
+
{ error: "Connection to #{url}#{body_msg} not cached and new http connections are disabled" }
|
24
24
|
end
|
25
25
|
|
26
26
|
def handles_request?(method, url, headers, body)
|
@@ -32,9 +32,7 @@ module Billy
|
|
32
32
|
end
|
33
33
|
|
34
34
|
def reset
|
35
|
-
handlers.each_value
|
36
|
-
handler.reset
|
37
|
-
end
|
35
|
+
handlers.each_value(&:reset)
|
38
36
|
end
|
39
37
|
|
40
38
|
def reset_stubs
|
@@ -46,7 +44,7 @@ module Billy
|
|
46
44
|
end
|
47
45
|
|
48
46
|
def restore_cache
|
49
|
-
warn
|
47
|
+
warn '[DEPRECATION] `restore_cache` is deprecated as cache files are dynamically checked. Use `reset_cache` if you just want to clear the cache.'
|
50
48
|
reset_cache
|
51
49
|
end
|
52
50
|
|
@@ -8,7 +8,7 @@ module Billy
|
|
8
8
|
def handle_request(method, url, headers, body)
|
9
9
|
if handles_request?(method, url, headers, body)
|
10
10
|
if (stub = find_stub(method, url))
|
11
|
-
query_string = Addressable::URI.parse(url).query ||
|
11
|
+
query_string = Addressable::URI.parse(url).query || ''
|
12
12
|
params = CGI.parse(query_string)
|
13
13
|
stub.call(params, headers, body).tap do |response|
|
14
14
|
Billy.log(:info, "puffing-billy: STUB #{method} for '#{url}'")
|
@@ -20,7 +20,7 @@ module Billy
|
|
20
20
|
nil
|
21
21
|
end
|
22
22
|
|
23
|
-
def handles_request?(method, url,
|
23
|
+
def handles_request?(method, url, _headers, _body)
|
24
24
|
!find_stub(method, url).nil?
|
25
25
|
end
|
26
26
|
|
data/lib/billy/json_utils.rb
CHANGED
@@ -2,7 +2,6 @@ require 'json'
|
|
2
2
|
|
3
3
|
module Billy
|
4
4
|
module JSONUtils
|
5
|
-
|
6
5
|
def self.json?(value)
|
7
6
|
!!JSON.parse(value)
|
8
7
|
rescue JSON::ParserError, TypeError
|
@@ -33,7 +32,7 @@ module Billy
|
|
33
32
|
# Processing JSON in this way enables a consistent SHA to be derived from
|
34
33
|
# JSON payloads which have the same name/value pairs, but different orders.
|
35
34
|
def self.sort_json(json_str)
|
36
|
-
JSONUtils
|
35
|
+
JSONUtils.sort_hash_keys(JSON.parse(json_str, symbolize_names: true)).to_json
|
37
36
|
end
|
38
37
|
end
|
39
38
|
end
|
@@ -37,7 +37,7 @@ module Billy
|
|
37
37
|
else
|
38
38
|
if @ssl
|
39
39
|
uri = Addressable::URI.parse(@parser.request_url)
|
40
|
-
@url = "https://#{@ssl}#{[uri.path,uri.query].compact.join('?')}"
|
40
|
+
@url = "https://#{@ssl}#{[uri.path, uri.query].compact.join('?')}"
|
41
41
|
else
|
42
42
|
@url = @parser.request_url
|
43
43
|
end
|
@@ -52,17 +52,17 @@ module Billy
|
|
52
52
|
@parser = Http::Parser.new(self)
|
53
53
|
send_data("HTTP/1.0 200 Connection established\r\nProxy-agent: Puffing-Billy/0.0.0\r\n\r\n")
|
54
54
|
start_tls(
|
55
|
-
:
|
56
|
-
:
|
55
|
+
private_key_file: File.expand_path('../mitm.key', __FILE__),
|
56
|
+
cert_chain_file: File.expand_path('../mitm.crt', __FILE__)
|
57
57
|
)
|
58
58
|
end
|
59
59
|
|
60
60
|
def handle_request
|
61
61
|
EM.synchrony do
|
62
62
|
handler.handle_request(@parser.http_method, @url, @headers, @body).tap do |response|
|
63
|
-
if response.
|
63
|
+
if response.key?(:error)
|
64
64
|
close_connection
|
65
|
-
|
65
|
+
fail "puffing-billy: #{response[:error]}"
|
66
66
|
else
|
67
67
|
send_response(response)
|
68
68
|
end
|
@@ -3,10 +3,10 @@ require 'multi_json'
|
|
3
3
|
module Billy
|
4
4
|
class ProxyRequestStub
|
5
5
|
def initialize(url, options = {})
|
6
|
-
@options = {:
|
6
|
+
@options = { method: :get }.merge(options)
|
7
7
|
@method = @options[:method].to_s.upcase
|
8
8
|
@url = url
|
9
|
-
@response = {code: 204, headers: {}, text:
|
9
|
+
@response = { code: 204, headers: {}, text: '' }
|
10
10
|
end
|
11
11
|
|
12
12
|
def and_return(response)
|
@@ -27,10 +27,10 @@ module Billy
|
|
27
27
|
headers['Content-Type'] = res[:content_type] if res[:content_type]
|
28
28
|
|
29
29
|
if res[:json]
|
30
|
-
headers = {'Content-Type' => 'application/json'}.merge(headers)
|
30
|
+
headers = { 'Content-Type' => 'application/json' }.merge(headers)
|
31
31
|
body = MultiJson.dump(res[:json])
|
32
32
|
elsif res[:jsonp]
|
33
|
-
headers = {'Content-Type' => 'application/javascript'}.merge(headers)
|
33
|
+
headers = { 'Content-Type' => 'application/javascript' }.merge(headers)
|
34
34
|
if res[:callback]
|
35
35
|
callback = res[:callback]
|
36
36
|
elsif res[:callback_param]
|
@@ -40,11 +40,11 @@ module Billy
|
|
40
40
|
end
|
41
41
|
body = "#{callback}(#{MultiJson.dump(res[:jsonp])})"
|
42
42
|
elsif res[:text]
|
43
|
-
headers = {'Content-Type' => 'text/plain'}.merge(headers)
|
43
|
+
headers = { 'Content-Type' => 'text/plain' }.merge(headers)
|
44
44
|
body = res[:text]
|
45
45
|
elsif res[:redirect_to]
|
46
46
|
code = 302
|
47
|
-
headers = {'Location' => res[:redirect_to]}
|
47
|
+
headers = { 'Location' => res[:redirect_to] }
|
48
48
|
else
|
49
49
|
body = res[:body]
|
50
50
|
end
|
@@ -57,7 +57,7 @@ module Billy
|
|
57
57
|
if @url.is_a?(Regexp)
|
58
58
|
url.match(@url)
|
59
59
|
else
|
60
|
-
url.split('?')[0] == @url
|
60
|
+
Billy.config.strip_query_params ? (url.split('?')[0] == @url) : (url == @url)
|
61
61
|
end
|
62
62
|
end
|
63
63
|
end
|
data/lib/billy/version.rb
CHANGED
data/lib/tasks/billy.rake
CHANGED
@@ -1,7 +1,6 @@
|
|
1
1
|
require 'addressable/uri'
|
2
2
|
|
3
3
|
namespace :cache do
|
4
|
-
|
5
4
|
desc 'Print out all cache file information'
|
6
5
|
task :print_all do
|
7
6
|
cache_array = load_cache
|
@@ -12,9 +11,9 @@ namespace :cache do
|
|
12
11
|
end
|
13
12
|
|
14
13
|
desc 'Print out specific cache file information'
|
15
|
-
task :print_details, :sha do |
|
16
|
-
|
17
|
-
cache_array = load_cache(Billy.config.cache_path, '*'+args[:sha]+'*.yml')
|
14
|
+
task :print_details, :sha do |_t, args|
|
15
|
+
fail "Missing sha; usage: rake cache:print_details['<sha>']" unless args[:sha]
|
16
|
+
cache_array = load_cache(Billy.config.cache_path, '*' + args[:sha] + '*.yml')
|
18
17
|
|
19
18
|
sort_cache(cache_array).each do |cache|
|
20
19
|
print_cache_details(cache)
|
@@ -22,10 +21,10 @@ namespace :cache do
|
|
22
21
|
end
|
23
22
|
|
24
23
|
desc 'Find specific cache files by URL'
|
25
|
-
task :find_by_url, :api_path do |
|
26
|
-
|
24
|
+
task :find_by_url, :api_path do |_t, args|
|
25
|
+
fail "Missing api path; usage: rake cache:find_by_url['<api_path>']" unless args[:api_path]
|
27
26
|
cache_array = load_cache
|
28
|
-
filtered_cache_array = cache_array.select {|f| f[:url_path].include?(args[:api_path]) }
|
27
|
+
filtered_cache_array = cache_array.select { |f| f[:url_path].include?(args[:api_path]) }
|
29
28
|
|
30
29
|
sort_cache(filtered_cache_array).each do |cache|
|
31
30
|
print_cache_details(cache)
|
@@ -33,10 +32,10 @@ namespace :cache do
|
|
33
32
|
end
|
34
33
|
|
35
34
|
desc 'Find specific cache files by scope'
|
36
|
-
task :find_by_scope, :scope do |
|
37
|
-
|
35
|
+
task :find_by_scope, :scope do |_t, args|
|
36
|
+
fail "Missing scope; usage: rake cache:find_by_scope['<scope>']" unless args[:scope]
|
38
37
|
cache_array = load_cache
|
39
|
-
filtered_cache_array = cache_array.select {|f| f[:scope] && f[:scope].include?(args[:scope]) }
|
38
|
+
filtered_cache_array = cache_array.select { |f| f[:scope] && f[:scope].include?(args[:scope]) }
|
40
39
|
|
41
40
|
sort_cache(filtered_cache_array).each do |cache|
|
42
41
|
print_cache_details(cache)
|
@@ -46,7 +45,7 @@ namespace :cache do
|
|
46
45
|
desc 'Find cache files with non-successful status codes'
|
47
46
|
task :find_non_successful do
|
48
47
|
cache_array = load_cache
|
49
|
-
filtered_cache_array = cache_array.select {|f| !(200..299).include?(f[:status]) }
|
48
|
+
filtered_cache_array = cache_array.select { |f| !(200..299).include?(f[:status]) }
|
50
49
|
|
51
50
|
sort_cache(filtered_cache_array).each do |cache|
|
52
51
|
print_cache_details(cache)
|
@@ -57,11 +56,11 @@ namespace :cache do
|
|
57
56
|
cache_path = Rails.root.join(cache_directory)
|
58
57
|
cache_array = []
|
59
58
|
|
60
|
-
Dir.glob(cache_path+file_pattern) do |filename|
|
59
|
+
Dir.glob(cache_path + file_pattern) do |filename|
|
61
60
|
data = load_cache_file(filename)
|
62
61
|
url = Addressable::URI.parse(data[:url])
|
63
|
-
data[:url_path] = "#{url.path}#{url.query ? '?'+url.query : ''}#{url.fragment ? '#'+url.fragment : ''}"
|
64
|
-
data[:filename] = filename.gsub(Rails.root.to_s+'/','')
|
62
|
+
data[:url_path] = "#{url.path}#{url.query ? '?' + url.query : ''}#{url.fragment ? '#' + url.fragment : ''}"
|
63
|
+
data[:filename] = filename.gsub(Rails.root.to_s + '/', '')
|
65
64
|
cache_array << data
|
66
65
|
end
|
67
66
|
cache_array
|
@@ -85,5 +84,4 @@ namespace :cache do
|
|
85
84
|
def sort_cache(cache, key = :url_path)
|
86
85
|
cache.sort_by { |hsh| hsh[key] }
|
87
86
|
end
|
88
|
-
|
89
87
|
end
|
data/puffing-billy.gemspec
CHANGED
@@ -2,36 +2,36 @@
|
|
2
2
|
require File.expand_path('../lib/billy/version', __FILE__)
|
3
3
|
|
4
4
|
Gem::Specification.new do |gem|
|
5
|
-
gem.authors = [
|
6
|
-
gem.email = [
|
7
|
-
gem.description =
|
8
|
-
gem.summary =
|
9
|
-
gem.homepage =
|
5
|
+
gem.authors = ['Olly Smith']
|
6
|
+
gem.email = ['olly.smith@gmail.com']
|
7
|
+
gem.description = 'A stubbing proxy server for ruby. Connect it to your browser in integration tests to fake interactions with remote HTTP(S) servers.'
|
8
|
+
gem.summary = 'Easy request stubs for browser tests.'
|
9
|
+
gem.homepage = 'https://github.com/oesmith/puffing-billy'
|
10
10
|
|
11
|
-
gem.files = `git ls-files`.split(
|
12
|
-
gem.executables = gem.files.grep(%r{^bin/}).map{ |f| File.basename(f) }
|
11
|
+
gem.files = `git ls-files`.split($OUTPUT_RECORD_SEPARATOR)
|
12
|
+
gem.executables = gem.files.grep(%r{^bin/}).map { |f| File.basename(f) }
|
13
13
|
gem.test_files = gem.files.grep(%r{^(test|spec|features)/})
|
14
|
-
gem.name =
|
15
|
-
gem.require_paths = [
|
14
|
+
gem.name = 'puffing-billy'
|
15
|
+
gem.require_paths = ['lib']
|
16
16
|
gem.version = Billy::VERSION
|
17
17
|
|
18
|
-
gem.add_development_dependency
|
19
|
-
gem.add_development_dependency
|
20
|
-
gem.add_development_dependency
|
21
|
-
gem.add_development_dependency
|
22
|
-
gem.add_development_dependency
|
23
|
-
gem.add_development_dependency
|
24
|
-
gem.add_development_dependency
|
25
|
-
gem.add_development_dependency
|
26
|
-
gem.add_development_dependency
|
27
|
-
gem.add_development_dependency
|
28
|
-
gem.add_development_dependency
|
29
|
-
gem.add_development_dependency
|
30
|
-
gem.add_runtime_dependency
|
31
|
-
gem.add_runtime_dependency
|
32
|
-
gem.add_runtime_dependency
|
33
|
-
gem.add_runtime_dependency
|
34
|
-
gem.add_runtime_dependency
|
35
|
-
gem.add_runtime_dependency
|
36
|
-
gem.add_runtime_dependency
|
18
|
+
gem.add_development_dependency 'rspec'
|
19
|
+
gem.add_development_dependency 'thin'
|
20
|
+
gem.add_development_dependency 'faraday'
|
21
|
+
gem.add_development_dependency 'poltergeist'
|
22
|
+
gem.add_development_dependency 'selenium-webdriver'
|
23
|
+
gem.add_development_dependency 'capybara'
|
24
|
+
gem.add_development_dependency 'capybara-webkit', '~> 1.0'
|
25
|
+
gem.add_development_dependency 'rack'
|
26
|
+
gem.add_development_dependency 'guard'
|
27
|
+
gem.add_development_dependency 'rb-inotify'
|
28
|
+
gem.add_development_dependency 'pry'
|
29
|
+
gem.add_development_dependency 'cucumber'
|
30
|
+
gem.add_runtime_dependency 'addressable'
|
31
|
+
gem.add_runtime_dependency 'eventmachine'
|
32
|
+
gem.add_runtime_dependency 'em-synchrony'
|
33
|
+
gem.add_runtime_dependency 'em-http-request', '~> 1.1.0'
|
34
|
+
gem.add_runtime_dependency 'eventmachine_httpserver'
|
35
|
+
gem.add_runtime_dependency 'http_parser.rb', '~> 0.6.0'
|
36
|
+
gem.add_runtime_dependency 'multi_json'
|
37
37
|
end
|
@@ -1,22 +1,22 @@
|
|
1
1
|
require 'spec_helper'
|
2
2
|
require 'base64'
|
3
3
|
|
4
|
-
describe 'Facebook API example', :
|
4
|
+
describe 'Facebook API example', type: :feature, js: true do
|
5
5
|
before do
|
6
|
-
proxy.stub('https://www.facebook.com:443/dialog/oauth').and_return(
|
6
|
+
proxy.stub('https://www.facebook.com:443/dialog/oauth').and_return(proc do |params, _, _|
|
7
7
|
# mock a signed request from facebook. the JS api never verifies the
|
8
8
|
# signature, so all it needs is the base64-encoded payload
|
9
9
|
signed_request = "xxxxxxxxxx.#{Base64.encode64('{"user_id":"1234567"}')}"
|
10
10
|
# redirect to the 'redirect_uri', with some extra crap in the query string
|
11
|
-
{:
|
12
|
-
|
11
|
+
{ redirect_to: "#{params['redirect_uri'][0]}&access_token=foobar&expires_in=600&base_domain=localhost&https=1&signed_request=#{signed_request}" }
|
12
|
+
end)
|
13
13
|
|
14
|
-
proxy.stub('https://graph.facebook.com:443/me').and_return(:
|
14
|
+
proxy.stub('https://graph.facebook.com:443/me').and_return(jsonp: { name: 'Tester 1' })
|
15
15
|
end
|
16
16
|
|
17
17
|
it 'should show me as logged-in' do
|
18
18
|
visit '/facebook_api.html'
|
19
|
-
click_on
|
20
|
-
expect(page).to have_content
|
19
|
+
click_on 'Login'
|
20
|
+
expect(page).to have_content 'Hi, Tester 1'
|
21
21
|
end
|
22
22
|
end
|
@@ -1,10 +1,10 @@
|
|
1
1
|
require 'spec_helper'
|
2
2
|
|
3
|
-
describe 'Tumblr API example', :
|
3
|
+
describe 'Tumblr API example', type: :feature, js: true do
|
4
4
|
before do
|
5
5
|
proxy.stub('http://blog.howmanyleft.co.uk/api/read/json').and_return(
|
6
|
-
:
|
7
|
-
:
|
6
|
+
jsonp: {
|
7
|
+
posts: [
|
8
8
|
{
|
9
9
|
'regular-title' => 'News Item 1',
|
10
10
|
'url-with-slug' => 'http://example.com/news/1',
|
@@ -16,14 +16,14 @@ describe 'Tumblr API example', :type => :feature, :js => true do
|
|
16
16
|
'regular-body' => 'News item 2 content here'
|
17
17
|
}
|
18
18
|
]
|
19
|
-
|
19
|
+
})
|
20
20
|
end
|
21
21
|
|
22
22
|
it 'should show news stories' do
|
23
23
|
visit '/tumblr_api.html'
|
24
|
-
expect(page).to have_link('News Item 1', :
|
24
|
+
expect(page).to have_link('News Item 1', href: 'http://example.com/news/1')
|
25
25
|
expect(page).to have_content('News item 1 content here')
|
26
|
-
expect(page).to have_link('News Item 2', :
|
26
|
+
expect(page).to have_link('News Item 2', href: 'http://example.com/news/2')
|
27
27
|
expect(page).to have_content('News item 2 content here')
|
28
28
|
end
|
29
29
|
end
|
@@ -27,13 +27,13 @@ describe Billy::Cache do
|
|
27
27
|
expect { cache.format_url(pipe_url) }.not_to raise_error
|
28
28
|
end
|
29
29
|
|
30
|
-
context
|
30
|
+
context 'when dynamic_jsonp is true' do
|
31
31
|
it 'omits the callback param by default' do
|
32
32
|
expect(cache.format_url(params_url_with_callback, false, true)).to eq params_url
|
33
33
|
end
|
34
34
|
|
35
35
|
it 'omits the params listed in Billy.config.dynamic_jsonp_keys' do
|
36
|
-
allow(Billy.config).to receive(:dynamic_jsonp_keys) { [
|
36
|
+
allow(Billy.config).to receive(:dynamic_jsonp_keys) { ['foo'] }
|
37
37
|
|
38
38
|
expect(cache.format_url(params_url_with_callback, false, true)).to eq "#{base_url}?callback=quux"
|
39
39
|
end
|
@@ -56,11 +56,10 @@ describe Billy::Cache do
|
|
56
56
|
end
|
57
57
|
end
|
58
58
|
|
59
|
-
context
|
60
|
-
|
61
|
-
let(:
|
62
|
-
let(:
|
63
|
-
let(:regular_url) { "http://www.example-analytics.com/user.js" }
|
59
|
+
context 'with merge_cached_responses_whitelist set' do
|
60
|
+
let(:analytics_url1) { 'http://www.example-analytics.com/user/SDF879932/' }
|
61
|
+
let(:analytics_url2) { 'http://www.example-analytics.com/user/OIWEMLW39/' }
|
62
|
+
let(:regular_url) { 'http://www.example-analytics.com/user.js' }
|
64
63
|
|
65
64
|
let(:regex_to_match_analytics_urls_only) do
|
66
65
|
# Note that it matches the forward slash at the end of the URL, which doesn't match regular_url:
|
@@ -74,19 +73,18 @@ describe Billy::Cache do
|
|
74
73
|
end
|
75
74
|
|
76
75
|
it "has one cache key for the two analytics urls that match, and a separate one for the other that doesn't" do
|
77
|
-
expect(cache.key(
|
78
|
-
expect(cache.key(
|
76
|
+
expect(cache.key('post', analytics_url1, 'body')).to eq cache.key('post', analytics_url2, 'body')
|
77
|
+
expect(cache.key('post', analytics_url1, 'body')).not_to eq cache.key('post', regular_url, 'body')
|
79
78
|
end
|
80
79
|
|
81
|
-
it
|
82
|
-
identical_cache_key =
|
83
|
-
distinct_cache_key =
|
80
|
+
it 'More specifically, the cache keys should be identical for the 2 analytics urls' do
|
81
|
+
identical_cache_key = 'post_5fcb7a450e4cd54dcffcb526212757ee0ca9dc17'
|
82
|
+
distinct_cache_key = 'post_www.example-analytics.com_81f097654a523bd7ddb10fd4aee781723e076a1a_02083f4579e08a612425c0c1a17ee47add783b94'
|
84
83
|
|
85
|
-
expect(cache.key(
|
86
|
-
expect(cache.key(
|
87
|
-
expect(cache.key(
|
84
|
+
expect(cache.key('post', analytics_url1, 'body')).to eq identical_cache_key
|
85
|
+
expect(cache.key('post', regular_url, 'body')).to eq distinct_cache_key
|
86
|
+
expect(cache.key('post', analytics_url2, 'body')).to eq identical_cache_key
|
88
87
|
end
|
89
|
-
|
90
88
|
end
|
91
89
|
end
|
92
90
|
end
|
@@ -2,13 +2,15 @@ require 'spec_helper'
|
|
2
2
|
|
3
3
|
describe Billy::CacheHandler do
|
4
4
|
let(:handler) { Billy::CacheHandler.new }
|
5
|
-
let(:request)
|
5
|
+
let(:request) do
|
6
|
+
{
|
6
7
|
method: 'post',
|
7
8
|
url: 'http://example.test:8080/index?some=param&callback=dynamicCallback5678',
|
8
|
-
headers: {'Accept-Encoding' => 'gzip',
|
9
|
-
|
9
|
+
headers: { 'Accept-Encoding' => 'gzip',
|
10
|
+
'Cache-Control' => 'no-cache' },
|
10
11
|
body: 'Some body'
|
11
|
-
|
12
|
+
}
|
13
|
+
end
|
12
14
|
|
13
15
|
it 'delegates #reset to the cache' do
|
14
16
|
expect(Billy::Cache.instance).to receive(:reset).at_least(:once)
|
@@ -23,12 +25,12 @@ describe Billy::CacheHandler do
|
|
23
25
|
describe '#handles_request?' do
|
24
26
|
it 'handles the request if it is cached' do
|
25
27
|
expect(Billy::Cache.instance).to receive(:cached?).and_return(true)
|
26
|
-
expect(handler.handles_request?(nil,nil,nil,nil)).to be true
|
28
|
+
expect(handler.handles_request?(nil, nil, nil, nil)).to be true
|
27
29
|
end
|
28
30
|
|
29
31
|
it 'does not handle the request if it is not cached' do
|
30
32
|
expect(Billy::Cache.instance).to receive(:cached?).and_return(false)
|
31
|
-
expect(handler.handles_request?(nil,nil,nil,nil)).to be false
|
33
|
+
expect(handler.handles_request?(nil, nil, nil, nil)).to be false
|
32
34
|
end
|
33
35
|
end
|
34
36
|
|
@@ -43,11 +45,11 @@ describe Billy::CacheHandler do
|
|
43
45
|
|
44
46
|
it 'returns a cached response if the request can be handled' do
|
45
47
|
expect(Billy::Cache.instance).to receive(:cached?).and_return(true)
|
46
|
-
expect(Billy::Cache.instance).to receive(:fetch).and_return(
|
48
|
+
expect(Billy::Cache.instance).to receive(:fetch).and_return(status: 200, headers: { 'Connection' => 'close' }, content: 'The response body')
|
47
49
|
expect(handler.handle_request(request[:method],
|
48
50
|
request[:url],
|
49
51
|
request[:headers],
|
50
|
-
request[:body])).to eql(
|
52
|
+
request[:body])).to eql(status: 200, headers: { 'Connection' => 'close' }, content: 'The response body')
|
51
53
|
end
|
52
54
|
|
53
55
|
context 'updating jsonp callback names enabled' do
|
@@ -57,20 +59,20 @@ describe Billy::CacheHandler do
|
|
57
59
|
|
58
60
|
it 'updates the cached response if the callback is dynamic' do
|
59
61
|
expect(Billy::Cache.instance).to receive(:cached?).and_return(true)
|
60
|
-
expect(Billy::Cache.instance).to receive(:fetch).and_return(
|
62
|
+
expect(Billy::Cache.instance).to receive(:fetch).and_return(status: 200, headers: { 'Connection' => 'close' }, content: 'dynamicCallback1234({"yolo":"kitten"})')
|
61
63
|
expect(handler.handle_request(request[:method],
|
62
64
|
request[:url],
|
63
65
|
request[:headers],
|
64
|
-
request[:body])).to eql(
|
66
|
+
request[:body])).to eql(status: 200, headers: { 'Connection' => 'close' }, content: 'dynamicCallback5678({"yolo":"kitten"})')
|
65
67
|
end
|
66
68
|
|
67
69
|
it 'is flexible about the format of the response body' do
|
68
70
|
expect(Billy::Cache.instance).to receive(:cached?).and_return(true)
|
69
|
-
expect(Billy::Cache.instance).to receive(:fetch).and_return(
|
71
|
+
expect(Billy::Cache.instance).to receive(:fetch).and_return(status: 200, headers: { 'Connection' => 'close' }, content: "/**/ dynamicCallback1234(\n{\"yolo\":\"kitten\"})")
|
70
72
|
expect(handler.handle_request(request[:method],
|
71
73
|
request[:url],
|
72
74
|
request[:headers],
|
73
|
-
request[:body])).to eql(
|
75
|
+
request[:body])).to eql(status: 200, headers: { 'Connection' => 'close' }, content: "/**/ dynamicCallback5678(\n{\"yolo\":\"kitten\"})")
|
74
76
|
end
|
75
77
|
|
76
78
|
it 'does not interfere with non-jsonp requests' do
|
@@ -78,22 +80,22 @@ describe Billy::CacheHandler do
|
|
78
80
|
other_request = {
|
79
81
|
method: 'get',
|
80
82
|
url: 'http://example.test:8080/index?hanukkah=latkes',
|
81
|
-
headers: {'Accept-Encoding'=>'gzip', 'Cache-Control'=>'no-cache' },
|
83
|
+
headers: { 'Accept-Encoding' => 'gzip', 'Cache-Control' => 'no-cache' },
|
82
84
|
body: 'no jsonp'
|
83
85
|
}
|
84
86
|
|
85
87
|
allow(Billy::Cache.instance).to receive(:cached?).and_return(true)
|
86
|
-
allow(Billy::Cache.instance).to receive(:fetch).with(jsonp_request[:method], jsonp_request[:url], jsonp_request[:body]).and_return(
|
87
|
-
|
88
|
-
|
89
|
-
allow(Billy::Cache.instance).to receive(:fetch).with(other_request[:method], other_request[:url], other_request[:body]).and_return(
|
90
|
-
|
91
|
-
|
88
|
+
allow(Billy::Cache.instance).to receive(:fetch).with(jsonp_request[:method], jsonp_request[:url], jsonp_request[:body]).and_return(status: 200,
|
89
|
+
headers: { 'Connection' => 'close' },
|
90
|
+
content: 'dynamicCallback1234({"yolo":"kitten"})')
|
91
|
+
allow(Billy::Cache.instance).to receive(:fetch).with(other_request[:method], other_request[:url], other_request[:body]).and_return(status: 200,
|
92
|
+
headers: { 'Connection' => 'close' },
|
93
|
+
content: 'no jsonp but has parentheses()')
|
92
94
|
|
93
95
|
expect(handler.handle_request(other_request[:method],
|
94
|
-
|
95
|
-
|
96
|
-
|
96
|
+
other_request[:url],
|
97
|
+
other_request[:headers],
|
98
|
+
other_request[:body])).to eql(status: 200, headers: { 'Connection' => 'close' }, content: 'no jsonp but has parentheses()')
|
97
99
|
end
|
98
100
|
end
|
99
101
|
|
@@ -104,11 +106,11 @@ describe Billy::CacheHandler do
|
|
104
106
|
|
105
107
|
it 'does not change the response' do
|
106
108
|
expect(Billy::Cache.instance).to receive(:cached?).and_return(true)
|
107
|
-
expect(Billy::Cache.instance).to receive(:fetch).and_return(
|
109
|
+
expect(Billy::Cache.instance).to receive(:fetch).and_return(status: 200, headers: { 'Connection' => 'close' }, content: 'dynamicCallback1234({"yolo":"kitten"})')
|
108
110
|
expect(handler.handle_request(request[:method],
|
109
111
|
request[:url],
|
110
112
|
request[:headers],
|
111
|
-
request[:body])).to eql(
|
113
|
+
request[:body])).to eql(status: 200, headers: { 'Connection' => 'close' }, content: 'dynamicCallback1234({"yolo":"kitten"})')
|
112
114
|
end
|
113
115
|
end
|
114
116
|
|