puffing-billy 2.3.1 → 3.0.1

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.
Files changed (52) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +17 -0
  3. data/README.md +18 -5
  4. data/lib/billy/browsers/capybara.rb +13 -9
  5. data/lib/billy/browsers/watir.rb +4 -2
  6. data/lib/billy/config.rb +2 -1
  7. data/lib/billy/handlers/proxy_handler.rb +4 -0
  8. data/lib/billy/proxy.rb +1 -1
  9. data/lib/billy/ssl/certificate_helpers.rb +1 -1
  10. data/lib/billy/version.rb +1 -1
  11. metadata +29 -80
  12. data/.gitignore +0 -6
  13. data/.rspec +0 -2
  14. data/.travis.yml +0 -36
  15. data/Dockerfile +0 -14
  16. data/Gemfile +0 -4
  17. data/Guardfile +0 -23
  18. data/Rakefile +0 -11
  19. data/bin/proxy.rb +0 -3
  20. data/examples/README.md +0 -1
  21. data/examples/facebook_api.html +0 -59
  22. data/examples/intercept_request.html +0 -10
  23. data/examples/post_api.html +0 -16
  24. data/examples/preflight_request.html +0 -22
  25. data/examples/tumblr_api.html +0 -22
  26. data/examples/tumblr_api_https.html +0 -22
  27. data/lib/tasks/billy.rake +0 -87
  28. data/log/.gitkeep +0 -0
  29. data/puffing-billy.gemspec +0 -39
  30. data/spec/features/examples/facebook_api_spec.rb +0 -23
  31. data/spec/features/examples/intercept_request_spec.rb +0 -31
  32. data/spec/features/examples/post_api_spec.rb +0 -15
  33. data/spec/features/examples/preflight_request_spec.rb +0 -29
  34. data/spec/features/examples/tumblr_api_spec.rb +0 -59
  35. data/spec/lib/billy/browsers/capybara_spec.rb +0 -28
  36. data/spec/lib/billy/cache_spec.rb +0 -158
  37. data/spec/lib/billy/handlers/cache_handler_spec.rb +0 -191
  38. data/spec/lib/billy/handlers/handler_spec.rb +0 -16
  39. data/spec/lib/billy/handlers/proxy_handler_spec.rb +0 -254
  40. data/spec/lib/billy/handlers/request_handler_spec.rb +0 -200
  41. data/spec/lib/billy/handlers/request_log_spec.rb +0 -74
  42. data/spec/lib/billy/handlers/stub_handler_spec.rb +0 -117
  43. data/spec/lib/billy/proxy_connection_spec.rb +0 -20
  44. data/spec/lib/billy/proxy_request_stub_spec.rb +0 -252
  45. data/spec/lib/billy/resource_utils_spec.rb +0 -55
  46. data/spec/lib/billy/ssl/authority_spec.rb +0 -84
  47. data/spec/lib/billy/ssl/certificate_chain_spec.rb +0 -39
  48. data/spec/lib/billy/ssl/certificate_spec.rb +0 -89
  49. data/spec/lib/billy/watir/watir_spec.rb +0 -18
  50. data/spec/lib/proxy_spec.rb +0 -431
  51. data/spec/spec_helper.rb +0 -52
  52. data/spec/support/test_server.rb +0 -79
@@ -1,22 +0,0 @@
1
- <!doctype html>
2
- <body>
3
- <h1>Latest news</h1>
4
- <div id="news"></div>
5
-
6
- <script type='text/javascript' src='http://code.jquery.com/jquery-1.8.2.min.js'></script>
7
- <script type='text/javascript'>
8
- $(function () {
9
- var url = 'https://blog.howmanyleft.co.uk/api/read/json?callback=?&type=text&num=3&filter=text';
10
- $.getJSON(url, function (data) {
11
- $.each(data.posts, function (idx, post) {
12
- var title = post['regular-title'];
13
- var href = post['url-with-slug'];
14
- var body = post['regular-body'];
15
- $('#news').append(
16
- '<h3><a href="' + href + '">' + title + '</a></h3>' +
17
- '<p>' + body + '</p>');
18
- });
19
- });
20
- })
21
- </script>
22
- </body>
data/lib/tasks/billy.rake DELETED
@@ -1,87 +0,0 @@
1
- require 'addressable/uri'
2
-
3
- namespace :cache do
4
- desc 'Print out all cache file information'
5
- task :print_all do
6
- cache_array = load_cache
7
-
8
- sort_cache(cache_array).each do |cache|
9
- print_cache_details(cache)
10
- end
11
- end
12
-
13
- desc 'Print out specific cache file information'
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')
17
-
18
- sort_cache(cache_array).each do |cache|
19
- print_cache_details(cache)
20
- end
21
- end
22
-
23
- desc 'Find specific cache files by URL'
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]
26
- cache_array = load_cache
27
- filtered_cache_array = cache_array.select { |f| f[:url_path].include?(args[:api_path]) }
28
-
29
- sort_cache(filtered_cache_array).each do |cache|
30
- print_cache_details(cache)
31
- end
32
- end
33
-
34
- desc 'Find specific cache files by scope'
35
- task :find_by_scope, :scope do |_t, args|
36
- fail "Missing scope; usage: rake cache:find_by_scope['<scope>']" unless args[:scope]
37
- cache_array = load_cache
38
- filtered_cache_array = cache_array.select { |f| f[:scope] && f[:scope].include?(args[:scope]) }
39
-
40
- sort_cache(filtered_cache_array).each do |cache|
41
- print_cache_details(cache)
42
- end
43
- end
44
-
45
- desc 'Find cache files with non-successful status codes'
46
- task :find_non_successful do
47
- cache_array = load_cache
48
- filtered_cache_array = cache_array.select { |f| !(200..299).include?(f[:status]) }
49
-
50
- sort_cache(filtered_cache_array).each do |cache|
51
- print_cache_details(cache)
52
- end
53
- end
54
-
55
- def load_cache(cache_directory = Billy.config.cache_path, file_pattern = '*.yml')
56
- cache_path = Rails.root.join(cache_directory)
57
- cache_array = []
58
-
59
- Dir.glob(cache_path + file_pattern) do |filename|
60
- data = load_cache_file(filename)
61
- url = Addressable::URI.parse(data[:url])
62
- data[:url_path] = "#{url.path}#{url.query ? '?' + url.query : ''}#{url.fragment ? '#' + url.fragment : ''}"
63
- data[:filename] = filename.gsub(Rails.root.to_s + '/', '')
64
- cache_array << data
65
- end
66
- cache_array
67
- end
68
-
69
- def load_cache_file(filename)
70
- YAML.load_file(filename)
71
- rescue ArgumentError => e
72
- puts "Could not parse YAML: #{e.message}"
73
- end
74
-
75
- def print_cache_details(cache)
76
- puts " Scope: #{cache[:scope]}" if cache[:scope]
77
- puts " URL: #{cache[:url]}"
78
- puts " Body: #{cache[:body]}" if Billy.config.cache_request_body_methods.include?(cache[:method])
79
- puts " Details: Request method '#{cache[:method]}' returned response status code: '#{cache[:status]}'"
80
- puts "Filename: #{cache[:filename]}"
81
- puts "\n\n"
82
- end
83
-
84
- def sort_cache(cache, key = :url_path)
85
- cache.sort_by { |hsh| hsh[key] }
86
- end
87
- end
data/log/.gitkeep DELETED
File without changes
@@ -1,39 +0,0 @@
1
- # -*- encoding: utf-8 -*-
2
- require File.expand_path('../lib/billy/version', __FILE__)
3
-
4
- Gem::Specification.new do |gem|
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
-
11
- gem.files = `git ls-files`.split($OUTPUT_RECORD_SEPARATOR)
12
- gem.executables = gem.files.grep(%r{^bin/}).map { |f| File.basename(f) }
13
- gem.test_files = gem.files.grep(%r{^(test|spec|features)/})
14
- gem.name = 'puffing-billy'
15
- gem.require_paths = ['lib']
16
- gem.version = Billy::VERSION
17
-
18
- gem.add_development_dependency 'rspec'
19
- gem.add_development_dependency 'thin'
20
- gem.add_development_dependency 'faraday', '>= 0.9.0'
21
- gem.add_development_dependency 'apparition'
22
- gem.add_development_dependency 'capybara'
23
- gem.add_development_dependency 'selenium-webdriver'
24
- gem.add_development_dependency 'rack'
25
- gem.add_development_dependency 'rake'
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_development_dependency 'watir', '~> 6.10.0'
31
- gem.add_development_dependency 'webdrivers'
32
- gem.add_runtime_dependency 'addressable', '~> 2.5'
33
- gem.add_runtime_dependency 'eventmachine', '~> 1.2'
34
- gem.add_runtime_dependency 'em-synchrony'
35
- gem.add_runtime_dependency 'em-http-request', '~> 1.1', '>= 1.1.0'
36
- gem.add_runtime_dependency 'eventmachine_httpserver'
37
- gem.add_runtime_dependency 'http_parser.rb', '~> 0.6.0'
38
- gem.add_runtime_dependency 'multi_json'
39
- end
@@ -1,23 +0,0 @@
1
- require 'spec_helper'
2
- require 'base64'
3
-
4
- # FIXME: Looks like Facebook API changed recently and this test fails consistently now -RS 2018-03-05
5
- xdescribe 'Facebook API example', type: :feature, js: true do
6
- before do
7
- proxy.stub('https://www.facebook.com:443/dialog/oauth').and_return(proc do |params, _, _|
8
- # mock a signed request from facebook. the JS api never verifies the
9
- # signature, so all it needs is the base64-encoded payload
10
- signed_request = "xxxxxxxxxx.#{Base64.encode64('{"user_id":"1234567"}')}"
11
- # redirect to the 'redirect_uri', with some extra crap in the query string
12
- { redirect_to: "#{params['redirect_uri'][0]}&access_token=foobar&expires_in=600&base_domain=localhost&https=1&signed_request=#{signed_request}" }
13
- end)
14
-
15
- proxy.stub('https://graph.facebook.com:443/me').and_return(jsonp: { name: 'Tester 1' })
16
- end
17
-
18
- it 'should show me as logged-in' do
19
- visit '/facebook_api.html'
20
- click_on 'Login'
21
- expect(page).to have_content 'Hi, Tester 1'
22
- end
23
- end
@@ -1,31 +0,0 @@
1
- require 'spec_helper'
2
- require 'timeout'
3
-
4
- describe 'intercept request example', type: :feature, js: true do
5
- before do
6
- Billy.config.record_stub_requests = true
7
- end
8
-
9
- it 'should intercept a GET request directly' do
10
- stub = proxy.stub('http://example.com/').and_return(
11
- headers: { 'Access-Control-Allow-Origin' => '*' },
12
- code: 200
13
- )
14
- visit 'http://example.com/'
15
- expect(stub.has_requests?).to be true
16
- expect(stub.requests).not_to be_empty
17
- end
18
-
19
- it 'should intercept a POST request through an intermediary page' do
20
- stub = proxy.stub('http://example.com/', method: 'post').and_return(
21
- headers: { 'Access-Control-Allow-Origin' => '*' },
22
- code: 200
23
- )
24
- visit '/intercept_request.html'
25
- Timeout::timeout(5) do
26
- sleep(0.1) until stub.has_requests?
27
- end
28
- request = stub.requests.shift
29
- expect(request[:body]).to eql 'foo=bar'
30
- end
31
- end
@@ -1,15 +0,0 @@
1
- require 'spec_helper'
2
-
3
- describe 'jQuery POST API example', type: :feature, js: true do
4
- before do
5
- proxy.stub('http://example.com/api', method: 'post').and_return(
6
- headers: { 'Access-Control-Allow-Origin' => '*' },
7
- code: 201
8
- )
9
- end
10
-
11
- it 'posts to an API' do
12
- visit '/post_api.html'
13
- expect(page.find('#result')).to have_content 'Success!'
14
- end
15
- end
@@ -1,29 +0,0 @@
1
- require 'spec_helper'
2
-
3
- describe 'jQuery preflight request example', type: :feature, js: true do
4
- let(:url) { 'http://example.com/api' }
5
-
6
- before do
7
- proxy.stub(url, method: 'get').and_return(
8
- headers: { 'Access-Control-Allow-Origin' => '*' },
9
- code: 201
10
- )
11
- end
12
-
13
- it 'stubs out the OPTIONS request' do
14
- visit '/preflight_request.html'
15
- expect(page.find('#result')).to have_content 'Fail!'
16
-
17
- proxy.stub(url, method: 'options').and_return(
18
- headers: {
19
- 'Access-Control-Allow-Methods' => 'GET, OPTIONS',
20
- 'Access-Control-Allow-Headers' => 'Content-Type',
21
- 'Access-Control-Allow-Origin' => '*'
22
- },
23
- code: 200
24
- )
25
-
26
- visit '/preflight_request.html'
27
- expect(page.find('#result')).to have_content 'Success!'
28
- end
29
- end
@@ -1,59 +0,0 @@
1
- require 'spec_helper'
2
-
3
- RSpec.shared_examples 'tumblr/expectations' do
4
- it 'should show news stories' do
5
- visit '/tumblr_api.html'
6
- expect(page).to have_link('News Item 1', href: 'http://example.com/news/1')
7
- expect(page).to have_content('News item 1 content here')
8
- expect(page).to have_link('News Item 2', href: 'http://example.com/news/2')
9
- expect(page).to have_content('News item 2 content here')
10
- end
11
- end
12
-
13
- describe 'Tumblr API example', type: :feature, js: true do
14
- context 'without scope external references' do
15
- before do
16
- proxy.stub('http://blog.howmanyleft.co.uk/api/read/json').and_return(
17
- jsonp: {
18
- posts: [
19
- {
20
- 'regular-title' => 'News Item 1',
21
- 'url-with-slug' => 'http://example.com/news/1',
22
- 'regular-body' => 'News item 1 content here'
23
- },
24
- {
25
- 'regular-title' => 'News Item 2',
26
- 'url-with-slug' => 'http://example.com/news/2',
27
- 'regular-body' => 'News item 2 content here'
28
- }
29
- ]
30
- })
31
- end
32
-
33
- include_examples 'tumblr/expectations'
34
- end
35
-
36
- context 'with scope external references' do
37
- let(:posts) do
38
- [
39
- {
40
- 'regular-title' => 'News Item 1',
41
- 'url-with-slug' => 'http://example.com/news/1',
42
- 'regular-body' => 'News item 1 content here'
43
- },
44
- {
45
- 'regular-title' => 'News Item 2',
46
- 'url-with-slug' => 'http://example.com/news/2',
47
- 'regular-body' => 'News item 2 content here'
48
- }
49
- ]
50
- end
51
-
52
- before do
53
- proxy.stub('http://blog.howmanyleft.co.uk/api/read/json')
54
- .and_return(proc { { jsonp: { posts: posts } } })
55
- end
56
-
57
- include_examples 'tumblr/expectations'
58
- end
59
- end
@@ -1,28 +0,0 @@
1
- require 'spec_helper'
2
-
3
- describe 'Capybara drivers', type: :feature, js: true do
4
- it 'allows HTTPS calls' do
5
- proxy.stub('https://blog.howmanyleft.co.uk:443/api/read/json').and_return(
6
- jsonp: {
7
- posts: [
8
- {
9
- 'regular-title' => 'News Item 1',
10
- 'url-with-slug' => 'http://example.com/news/1',
11
- 'regular-body' => 'News item 1 content here'
12
- },
13
- {
14
- 'regular-title' => 'News Item 2',
15
- 'url-with-slug' => 'http://example.com/news/2',
16
- 'regular-body' => 'News item 2 content here'
17
- }
18
- ]
19
- })
20
-
21
- visit '/tumblr_api_https.html'
22
-
23
- expect(page).to have_link('News Item 1', href: 'http://example.com/news/1')
24
- expect(page).to have_content('News item 1 content here')
25
- expect(page).to have_link('News Item 2', href: 'http://example.com/news/2')
26
- expect(page).to have_content('News item 2 content here')
27
- end
28
- end
@@ -1,158 +0,0 @@
1
- require 'spec_helper'
2
-
3
- describe Billy::Cache do
4
- let(:cache) { Billy::Cache.instance }
5
- let(:params) { '?foo=bar' }
6
- let(:callback) { '&callback=quux' }
7
- let(:fragment) { '#baz' }
8
- let(:base_url) { 'http://example.com' }
9
- let(:pipe_url) { 'https://fonts.googleapis.com:443/css?family=Cabin+Sketch:400,700|Love+Ya+Like+A+Sister' }
10
- let(:fragment_url) { "#{base_url}/#{fragment}" }
11
- let(:params_url) { "#{base_url}#{params}" }
12
- let(:params_url_with_callback) { "#{base_url}#{params}#{callback}" }
13
- let(:params_fragment_url) { "#{base_url}#{params}#{fragment}" }
14
-
15
- describe 'format_url' do
16
- context 'with ignore_params set to false' do
17
- it 'is a no-op if there are no params' do
18
- expect(cache.format_url(base_url)).to eq base_url
19
- end
20
- it 'appends params if there are params' do
21
- expect(cache.format_url(params_url)).to eq params_url
22
- end
23
- it 'appends params and fragment if both are present' do
24
- expect(cache.format_url(params_fragment_url)).to eq params_fragment_url
25
- end
26
- it 'does not raise error for URLs with pipes' do
27
- expect { cache.format_url(pipe_url) }.not_to raise_error
28
- end
29
-
30
- context 'when dynamic_jsonp is true' do
31
- it 'omits the callback param by default' do
32
- expect(cache.format_url(params_url_with_callback, false, true)).to eq params_url
33
- end
34
-
35
- it 'omits the params listed in Billy.config.dynamic_jsonp_keys' do
36
- allow(Billy.config).to receive(:dynamic_jsonp_keys) { ['foo'] }
37
-
38
- expect(cache.format_url(params_url_with_callback, false, true)).to eq "#{base_url}?callback=quux"
39
- end
40
- end
41
-
42
- it 'retains the callback param is dynamic_jsonp is false' do
43
- expect(cache.format_url(params_url_with_callback)).to eq params_url_with_callback
44
- end
45
- end
46
-
47
- context 'with ignore_params set to true' do
48
- it 'is a no-op if there are no params' do
49
- expect(cache.format_url(base_url, true)).to eq base_url
50
- end
51
- it 'omits params if there are params' do
52
- expect(cache.format_url(params_url, true)).to eq base_url
53
- end
54
- it 'omits params and fragment if both are present' do
55
- expect(cache.format_url(params_fragment_url, true)).to eq base_url
56
- end
57
- end
58
-
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' }
63
-
64
- let(:regex_to_match_analytics_urls_only) do
65
- # Note that it matches the forward slash at the end of the URL, which doesn't match regular_url:
66
- /www\.example\-analytics\.com\/user\//
67
- end
68
-
69
- before do
70
- allow(Billy.config).to receive(:merge_cached_responses_whitelist) {
71
- [regex_to_match_analytics_urls_only]
72
- }
73
- end
74
-
75
- it "has one cache key for the two analytics urls that match, and a separate one for the other that doesn't" do
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')
78
- end
79
-
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'
83
-
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
87
- end
88
- end
89
-
90
- context 'with cache_request_body_methods set' do
91
- before do
92
- allow(Billy.config).to receive(:cache_request_body_methods) {
93
- ['patch']
94
- }
95
- end
96
-
97
- context "for requests with methods specified in cache_request_body_methods" do
98
- it "should have a different cache key for requests with different bodies" do
99
- key1 = cache.key('patch', "http://example.com", "body1")
100
- key2 = cache.key('patch', "http://example.com", "body2")
101
- expect(key1).not_to eq key2
102
- end
103
-
104
- it "should have the same cache key for requests with the same bodies" do
105
- key1 = cache.key('patch', "http://example.com", "body1")
106
- key2 = cache.key('patch', "http://example.com", "body1")
107
- expect(key1).to eq key2
108
- end
109
- end
110
-
111
- it "should have the same cache key for request with different bodies if their methods are not included in cache_request_body_methods" do
112
- key1 = cache.key('put', "http://example.com", "body1")
113
- key2 = cache.key('put', "http://example.com", "body2")
114
- expect(key1).to eq key2
115
- end
116
- end
117
- end
118
-
119
- describe 'key' do
120
- context 'with use_ignore_params set to false' do
121
- before do
122
- allow(Billy.config).to receive(:use_ignore_params) { false }
123
- end
124
-
125
- it "should use the same cache key if the base url IS NOT whitelisted in allow_params" do
126
- key1 = cache.key('put', params_url, 'body')
127
- key2 = cache.key('put', params_url, 'body')
128
- expect(key1).to eq key2
129
- end
130
-
131
- it "should have the same cache key if the base IS whitelisted in allow_params" do
132
- allow(Billy.config).to receive(:allow_params) { [base_url] }
133
- key1 = cache.key('put', params_url, 'body')
134
- key2 = cache.key('put', params_url, 'body')
135
- expect(key1).to eq key2
136
- end
137
-
138
- it "should have different cache keys if the base url is added in between two requests" do
139
- key1 = cache.key('put', params_url, 'body')
140
- allow(Billy.config).to receive(:allow_params) { [base_url] }
141
- key2 = cache.key('put', params_url, 'body')
142
- expect(key1).not_to eq key2
143
- end
144
-
145
- it "should not use ignore_params when whitelisted" do
146
- allow(Billy.config).to receive(:allow_params) { [base_url] }
147
- expect(cache).to receive(:format_url).once.with(params_url, true).and_call_original
148
- expect(cache).to receive(:format_url).once.with(params_url, false).and_call_original
149
- key1 = cache.key('put', params_url, 'body')
150
- end
151
-
152
- it "should use ignore_params when not whitelisted" do
153
- expect(cache).to receive(:format_url).twice.with(params_url, true).and_call_original
154
- cache.key('put', params_url, 'body')
155
- end
156
- end
157
- end
158
- end