puffing-billy 2.4.1 → 3.0.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (48) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +8 -0
  3. data/README.md +1 -1
  4. data/lib/billy/browsers/capybara.rb +13 -9
  5. data/lib/billy/browsers/watir.rb +4 -2
  6. data/lib/billy/version.rb +1 -1
  7. metadata +29 -80
  8. data/.gitignore +0 -6
  9. data/.rspec +0 -2
  10. data/.travis.yml +0 -36
  11. data/Dockerfile +0 -14
  12. data/Gemfile +0 -4
  13. data/Guardfile +0 -23
  14. data/Rakefile +0 -11
  15. data/bin/proxy.rb +0 -3
  16. data/examples/README.md +0 -1
  17. data/examples/facebook_api.html +0 -59
  18. data/examples/intercept_request.html +0 -10
  19. data/examples/post_api.html +0 -16
  20. data/examples/preflight_request.html +0 -22
  21. data/examples/tumblr_api.html +0 -22
  22. data/examples/tumblr_api_https.html +0 -22
  23. data/lib/tasks/billy.rake +0 -87
  24. data/log/.gitkeep +0 -0
  25. data/puffing-billy.gemspec +0 -39
  26. data/spec/features/examples/facebook_api_spec.rb +0 -23
  27. data/spec/features/examples/intercept_request_spec.rb +0 -31
  28. data/spec/features/examples/post_api_spec.rb +0 -15
  29. data/spec/features/examples/preflight_request_spec.rb +0 -29
  30. data/spec/features/examples/tumblr_api_spec.rb +0 -59
  31. data/spec/lib/billy/browsers/capybara_spec.rb +0 -28
  32. data/spec/lib/billy/cache_spec.rb +0 -158
  33. data/spec/lib/billy/handlers/cache_handler_spec.rb +0 -191
  34. data/spec/lib/billy/handlers/handler_spec.rb +0 -16
  35. data/spec/lib/billy/handlers/proxy_handler_spec.rb +0 -254
  36. data/spec/lib/billy/handlers/request_handler_spec.rb +0 -200
  37. data/spec/lib/billy/handlers/request_log_spec.rb +0 -74
  38. data/spec/lib/billy/handlers/stub_handler_spec.rb +0 -117
  39. data/spec/lib/billy/proxy_connection_spec.rb +0 -20
  40. data/spec/lib/billy/proxy_request_stub_spec.rb +0 -252
  41. data/spec/lib/billy/resource_utils_spec.rb +0 -55
  42. data/spec/lib/billy/ssl/authority_spec.rb +0 -84
  43. data/spec/lib/billy/ssl/certificate_chain_spec.rb +0 -39
  44. data/spec/lib/billy/ssl/certificate_spec.rb +0 -89
  45. data/spec/lib/billy/watir/watir_spec.rb +0 -18
  46. data/spec/lib/proxy_spec.rb +0 -431
  47. data/spec/spec_helper.rb +0 -52
  48. data/spec/support/test_server.rb +0 -79
@@ -1,431 +0,0 @@
1
- require 'spec_helper'
2
- require 'resolv'
3
-
4
- shared_examples_for 'a proxy server' do
5
- it 'should proxy GET requests' do
6
- expect(http.get('/echo').body).to eql 'GET /echo'
7
- end
8
-
9
- it 'should proxy POST requests' do
10
- expect(http.post('/echo', foo: 'bar').body).to eql "POST /echo\nfoo=bar"
11
- end
12
-
13
- it 'should proxy PUT requests' do
14
- expect(http.post('/echo', foo: 'bar').body).to eql "POST /echo\nfoo=bar"
15
- end
16
-
17
- it 'should proxy HEAD requests' do
18
- expect(http.head('/echo').headers['HTTP-X-EchoServer']).to eql 'HEAD /echo'
19
- end
20
-
21
- it 'should proxy DELETE requests' do
22
- expect(http.delete('/echo').body).to eql 'DELETE /echo'
23
- end
24
-
25
- it 'should proxy OPTIONS requests' do
26
- expect(http.run_request(:options, '/echo', nil, nil).body).to eql 'OPTIONS /echo'
27
- end
28
- end
29
-
30
- shared_examples_for 'a request stub' do
31
- it 'should stub GET requests' do
32
- proxy.stub("#{url}/foo")
33
- .and_return(text: 'hello, GET!')
34
- expect(http.get('/foo').body).to eql 'hello, GET!'
35
- end
36
-
37
- it 'should stub GET response statuses' do
38
- proxy.stub("#{url}/foo")
39
- .and_return(code: 200)
40
- expect(http.get('/foo').status).to eql 200
41
- end
42
-
43
- it 'should stub POST requests' do
44
- proxy.stub("#{url}/bar", method: :post)
45
- .and_return(text: 'hello, POST!')
46
- expect(http.post('/bar', foo: :bar).body).to eql 'hello, POST!'
47
- end
48
-
49
- it 'should stub PUT requests' do
50
- proxy.stub("#{url}/baz", method: :put)
51
- .and_return(text: 'hello, PUT!')
52
- expect(http.put('/baz', foo: :bar).body).to eql 'hello, PUT!'
53
- end
54
-
55
- it 'should stub HEAD requests' do
56
- proxy.stub("#{url}/bap", method: :head)
57
- .and_return(headers: { 'HTTP-X-Hello' => 'hello, HEAD!' })
58
- expect(http.head('/bap').headers['http-x-hello']).to eql 'hello, HEAD!'
59
- end
60
-
61
- it 'should stub DELETE requests' do
62
- proxy.stub("#{url}/bam", method: :delete)
63
- .and_return(text: 'hello, DELETE!')
64
- expect(http.delete('/bam').body).to eql 'hello, DELETE!'
65
- end
66
-
67
- it 'should stub OPTIONS requests' do
68
- proxy.stub("#{url}/bim", method: :options)
69
- .and_return(text: 'hello, OPTIONS!')
70
- expect(http.run_request(:options, '/bim', nil, nil).body).to eql 'hello, OPTIONS!'
71
- end
72
-
73
- it 'should expose the currently registered stubs' do
74
- stub1 = proxy.stub("#{url}/foo", method: :options)
75
- .and_return(text: 'hello, OPTIONS!')
76
- stub2 = proxy.stub("#{url}/bar", method: :options)
77
- .and_return(text: 'hello, OPTIONS!')
78
- expect(proxy.stubs).to eql([stub2, stub1])
79
- end
80
- end
81
-
82
- shared_examples_for 'a cache' do
83
- context 'whitelisted GET requests' do
84
- it 'should not be cached' do
85
- assert_noncached_url
86
- end
87
-
88
- context 'with ports' do
89
- before do
90
- rack_app_url = URI(http.url_prefix)
91
- Billy.config.whitelist = ["#{rack_app_url.host}:#{rack_app_url.port}"]
92
- end
93
-
94
- it 'should not be cached ' do
95
- assert_noncached_url
96
- end
97
- end
98
- end
99
-
100
- context 'non-whitelisted GET requests' do
101
- before do
102
- Billy.config.whitelist = []
103
- end
104
-
105
- it 'should be cached' do
106
- assert_cached_url
107
- end
108
-
109
- context 'with ports' do
110
- before do
111
- rack_app_url = URI(http.url_prefix)
112
- Billy.config.whitelist = ["#{rack_app_url.host}:#{rack_app_url.port + 1}"]
113
- end
114
-
115
- it 'should be cached' do
116
- assert_cached_url
117
- end
118
- end
119
- end
120
-
121
- context 'cache_whitelist GET requests' do
122
- before do
123
- Billy.config.whitelist = [http.host]
124
- Billy.config.cache_whitelist = [http.host]
125
- end
126
-
127
- it 'should be cached' do
128
- assert_cached_url
129
- end
130
-
131
- context 'with ports' do
132
- before do
133
- rack_app_url = URI(http.url_prefix)
134
- Billy.config.whitelist = ["#{rack_app_url.host}:#{rack_app_url.port + 1}"]
135
- Billy.config.cache_whitelist = Billy.config.whitelist
136
- end
137
-
138
- it 'should be cached' do
139
- assert_cached_url
140
- end
141
- end
142
- end
143
-
144
- context 'ignore_params GET requests' do
145
- before do
146
- Billy.config.ignore_params = ['/analytics']
147
- end
148
-
149
- it 'should be cached' do
150
- r = http.get('/analytics?some_param=5')
151
- expect(r.body).to eql 'GET /analytics'
152
- expect do
153
- expect do
154
- r = http.get('/analytics?some_param=20')
155
- end.to change { r.headers['HTTP-X-EchoCount'].to_i }.by(1)
156
- end.to_not change { r.body }
157
- end
158
- end
159
-
160
- context 'path_blacklist GET requests' do
161
- before do
162
- Billy.config.path_blacklist = ['/api']
163
- end
164
-
165
- it 'should be cached' do
166
- assert_cached_url('/api')
167
- end
168
-
169
- context 'path_blacklist includes regex' do
170
- before do
171
- Billy.config.path_blacklist = [/widgets$/]
172
- end
173
-
174
- it 'should not cache a non-match' do
175
- assert_noncached_url('/widgets/5/edit')
176
- end
177
-
178
- it 'should cache a match' do
179
- assert_cached_url('/widgets')
180
- end
181
- end
182
- end
183
-
184
- context 'cache persistence' do
185
- let(:cache_path) { Billy.config.cache_path }
186
- let(:cached_key) { proxy.cache.key('get', "#{url}/foo", '') }
187
- let(:cached_file) do
188
- f = cached_key + '.yml'
189
- File.join(cache_path, f)
190
- end
191
-
192
- before do
193
- Billy.config.whitelist = []
194
- Dir.mkdir(cache_path) unless Dir.exist?(cache_path)
195
- end
196
-
197
- after do
198
- File.delete(cached_file) if File.exist?(cached_file)
199
- end
200
-
201
- context 'enabled' do
202
- before { Billy.config.persist_cache = true }
203
-
204
- it 'should persist' do
205
- http.get('/foo')
206
- expect(File.exist?(cached_file)).to be true
207
- end
208
-
209
- it 'should be read initially from persistent cache' do
210
- File.open(cached_file, 'w') do |f|
211
- cached = {
212
- headers: {},
213
- content: 'GET /foo cached'
214
- }
215
- f.write(cached.to_yaml(Encoding: :Utf8))
216
- end
217
-
218
- r = http.get('/foo')
219
- expect(r.body).to eql 'GET /foo cached'
220
- end
221
-
222
- context 'cache_request_headers requests' do
223
- it 'should not be cached by default' do
224
- http.get('/foo')
225
- saved_cache = Billy.proxy.cache.fetch_from_persistence(cached_key)
226
- expect(saved_cache.keys).not_to include :request_headers
227
- end
228
-
229
- context 'when enabled' do
230
- before do
231
- Billy.config.cache_request_headers = true
232
- end
233
-
234
- it 'should be cached' do
235
- http.get('/foo')
236
- saved_cache = Billy.proxy.cache.fetch_from_persistence(cached_key)
237
- expect(saved_cache.keys).to include :request_headers
238
- end
239
- end
240
- end
241
-
242
- context 'ignore_cache_port requests' do
243
- it 'should be cached without port' do
244
- r = http.get('/foo')
245
- url = URI(r.env[:url])
246
- saved_cache = Billy.proxy.cache.fetch_from_persistence(cached_key)
247
-
248
- expect(saved_cache[:url]).to_not eql(url.to_s)
249
- expect(saved_cache[:url]).to eql(url.to_s.gsub(":#{url.port}", ''))
250
- end
251
- end
252
-
253
- context 'non_whitelisted_requests_disabled requests' do
254
- before { Billy.config.non_whitelisted_requests_disabled = true }
255
-
256
- it 'should raise error when disabled' do
257
- # TODO: Suppress stderr output: https://gist.github.com/adamstegman/926858
258
- expect { http.get('/foo') }.to raise_error(Faraday::ConnectionFailed, 'end of file reached')
259
- end
260
- end
261
-
262
- context 'non_successful_cache_disabled requests' do
263
- before do
264
- rack_app_url = URI(http_error.url_prefix)
265
- Billy.config.whitelist = ["#{rack_app_url.host}:#{rack_app_url.port}"]
266
- Billy.config.non_successful_cache_disabled = true
267
- end
268
-
269
- it 'should not cache non-successful response when enabled' do
270
- http_error.get('/foo')
271
- expect(File.exist?(cached_file)).to be false
272
- end
273
-
274
- it 'should cache successful response when enabled' do
275
- assert_cached_url
276
- end
277
- end
278
-
279
- context 'non_successful_error_level requests' do
280
- before do
281
- rack_app_url = URI(http_error.url_prefix)
282
- Billy.config.whitelist = ["#{rack_app_url.host}:#{rack_app_url.port}"]
283
- Billy.config.non_successful_error_level = :error
284
- end
285
-
286
- it 'should raise error for non-successful responses when :error' do
287
- expect { http_error.get('/foo') }.to raise_error(Faraday::ConnectionFailed)
288
- end
289
- end
290
- end
291
-
292
- context 'disabled' do
293
- before { Billy.config.persist_cache = false }
294
-
295
- it 'shouldnt persist' do
296
- http.get('/foo')
297
- expect(File.exist?(cached_file)).to be false
298
- end
299
- end
300
- end
301
-
302
- def assert_noncached_url(url = '/foo')
303
- r = http.get(url)
304
- expect(r.body).to eql "GET #{url}"
305
- expect do
306
- expect do
307
- r = http.get(url)
308
- end.to change { r.headers['HTTP-X-EchoCount'].to_i }.by(1)
309
- end.to_not change { r.body }
310
- end
311
-
312
- def assert_cached_url(url = '/foo')
313
- r = http.get(url)
314
- expect(r.body).to eql "GET #{url}"
315
- expect do
316
- expect do
317
- r = http.get(url)
318
- end.to_not change { r.headers['HTTP-X-EchoCount'] }
319
- end.to_not change { r.body }
320
- end
321
- end
322
-
323
- describe Billy::Proxy do
324
- before do
325
- # Adding non-valid Faraday options throw an error: https://github.com/arsduo/koala/pull/311
326
- # Valid options: :request, :proxy, :ssl, :builder, :url, :parallel_manager, :params, :headers, :builder_class
327
- faraday_options = {
328
- proxy: { uri: proxy.url },
329
- request: { timeout: 1.0 }
330
- }
331
- faraday_ssl_options = faraday_options.merge(ssl: {
332
- verify: true,
333
- ca_file: Billy.certificate_authority.cert_file
334
- })
335
-
336
- @http = Faraday.new @http_url, faraday_options
337
- @https = Faraday.new @https_url, faraday_ssl_options
338
- @http_error = Faraday.new @error_url, faraday_options
339
- end
340
-
341
- context 'proxying' do
342
- context 'HTTP' do
343
- let!(:http) { @http }
344
- it_should_behave_like 'a proxy server'
345
- end
346
-
347
- context 'HTTPS' do
348
- let!(:http) { @https }
349
- it_should_behave_like 'a proxy server'
350
- end
351
- end
352
-
353
- context 'stubbing' do
354
- context 'HTTP' do
355
- let!(:url) { @http_url }
356
- let!(:http) { @http }
357
- it_should_behave_like 'a request stub'
358
- end
359
-
360
- context 'HTTPS' do
361
- let!(:url) { @https_url }
362
- let!(:http) { @https }
363
- it_should_behave_like 'a request stub'
364
- end
365
- end
366
-
367
- context 'caching' do
368
- it 'defaults to nil scope' do
369
- expect(proxy.cache.scope).to be nil
370
- end
371
-
372
- context 'HTTP' do
373
- let!(:url) { @http_url }
374
- let!(:http) { @http }
375
- let!(:http_error) { @http_error }
376
- it_should_behave_like 'a cache'
377
- end
378
-
379
- context 'HTTPS' do
380
- let!(:url) { @https_url }
381
- let!(:http) { @https }
382
- let!(:http_error) { @http_error }
383
- it_should_behave_like 'a cache'
384
- end
385
-
386
- context 'with a cache scope' do
387
- let!(:url) { @http_url }
388
- let!(:http) { @http }
389
- let!(:http_error) { @http_error }
390
-
391
- before do
392
- proxy.cache.scope_to 'my_cache'
393
- end
394
-
395
- after do
396
- proxy.cache.use_default_scope
397
- end
398
-
399
- it_should_behave_like 'a cache'
400
-
401
- it 'uses the cache scope' do
402
- expect(proxy.cache.scope).to eq('my_cache')
403
- end
404
-
405
- it 'can be reset to the default scope' do
406
- proxy.cache.use_default_scope
407
- expect(proxy.cache.scope).to be nil
408
- end
409
-
410
- it 'can execute a block against a cache scope' do
411
- expect(proxy.cache.scope).to eq 'my_cache'
412
- proxy.cache.with_scope 'another_cache' do
413
- expect(proxy.cache.scope).to eq 'another_cache'
414
- end
415
- expect(proxy.cache.scope).to eq 'my_cache'
416
- end
417
-
418
- it 'requires a block to be passed to with_scope' do
419
- expect { proxy.cache.with_scope 'some_scope' }.to raise_error ArgumentError
420
- end
421
-
422
- it 'should have different keys for the same request under a different scope' do
423
- args = ['get', "#{url}/foo", '']
424
- key = proxy.cache.key(*args)
425
- proxy.cache.with_scope 'another_cache' do
426
- expect(proxy.cache.key(*args)).to_not eq key
427
- end
428
- end
429
- end
430
- end
431
- end
data/spec/spec_helper.rb DELETED
@@ -1,52 +0,0 @@
1
- Dir[File.expand_path('../support/**/*.rb', __FILE__)].each { |f| require f }
2
-
3
- require 'pry'
4
- require 'billy/capybara/rspec'
5
- require 'billy/watir/rspec'
6
- require 'rack'
7
- require 'logger'
8
- require 'fileutils'
9
- require 'webdrivers'
10
-
11
- $stdout.puts `#{::Selenium::WebDriver::Chrome::Service.driver_path.call} --version` if ENV['CI']
12
-
13
- browser = Billy::Browsers::Watir.new :chrome
14
-
15
- Capybara.configure do |config|
16
- config.app = Rack::Directory.new(File.expand_path('../../examples', __FILE__))
17
- config.server = :webrick
18
- config.javascript_driver = :selenium_chrome_headless_billy
19
- end
20
-
21
- Billy.configure do |config|
22
- config.logger = Logger.new(File.expand_path('../../log/test.log', __FILE__))
23
- end
24
-
25
- RSpec.configure do |config|
26
- include Billy::TestServer
27
- config.run_all_when_everything_filtered = true
28
- config.filter_run :focus
29
- config.order = 'random'
30
-
31
- config.before :suite do
32
- FileUtils.rm_rf(Billy.config.certs_path)
33
- FileUtils.rm_rf(Billy.config.cache_path)
34
- end
35
-
36
- config.before :all do
37
- start_test_servers
38
- @browser = browser
39
- end
40
-
41
- config.before :each do
42
- proxy.reset_cache
43
- end
44
-
45
- config.after :each do
46
- Billy.config.reset
47
- end
48
-
49
- config.after :suite do
50
- browser.close
51
- end
52
- end
@@ -1,79 +0,0 @@
1
- require 'eventmachine'
2
- require 'thin'
3
- require 'faraday'
4
-
5
- module Thin::Backends
6
- class TcpServer
7
- def get_port
8
- # seriously, eventmachine, how hard does getting a port have to be?
9
- Socket.unpack_sockaddr_in(EM.get_sockname(@signature)).first
10
- end
11
- end
12
- end
13
-
14
- module Billy
15
- module TestServer
16
- def initialize
17
- Thin::Logging.silent = true
18
- end
19
-
20
- def start_test_servers
21
- q = Queue.new
22
- Thread.new do
23
- EM.run do
24
- echo = echo_app_setup
25
-
26
- http_server = start_server(echo)
27
- q.push http_server.backend.get_port
28
-
29
- https_server = start_server(echo, true)
30
- q.push https_server.backend.get_port
31
-
32
- echo_error = echo_app_setup(500)
33
- error_server = start_server(echo_error)
34
- q.push error_server.backend.get_port
35
- end
36
- end
37
-
38
- @http_url = "http://127.0.0.1:#{q.pop}"
39
- @https_url = "https://127.0.0.1:#{q.pop}"
40
- @error_url = "http://127.0.0.1:#{q.pop}"
41
- end
42
-
43
- def echo_app_setup(response_code = 200)
44
- counter = 0
45
- Proc.new do |env|
46
- req_body = env['rack.input'].read
47
- request_info = "#{env['REQUEST_METHOD']} #{env['PATH_INFO']}"
48
- res_body = request_info
49
- res_body += "\n#{req_body}" unless req_body.empty?
50
- counter += 1
51
- [
52
- response_code,
53
- { 'HTTP-X-EchoServer' => request_info,
54
- 'HTTP-X-EchoCount' => "#{counter}" },
55
- [res_body]
56
- ]
57
- end
58
- end
59
-
60
- def certificate_chain(domain)
61
- ca = Billy.certificate_authority.cert
62
- cert = Billy::Certificate.new(domain)
63
- chain = Billy::CertificateChain.new(domain, cert.cert, ca)
64
- { private_key_file: cert.key_file,
65
- cert_chain_file: chain.file }
66
-
67
- end
68
-
69
- def start_server(echo, ssl = false)
70
- http_server = Thin::Server.new '127.0.0.1', 0, echo
71
- if ssl
72
- http_server.ssl = true
73
- http_server.ssl_options = certificate_chain('localhost')
74
- end
75
- http_server.start
76
- http_server
77
- end
78
- end
79
- end