puffing-billy 2.3.1 → 3.0.1

Sign up to get free protection for your applications and to get access to all the features.
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