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,252 +0,0 @@
1
- require 'spec_helper'
2
-
3
- describe Billy::ProxyRequestStub do
4
- context '#matches?' do
5
- it 'should match urls and methods' do
6
- expect(Billy::ProxyRequestStub.new('http://example.com')
7
- .matches?('GET', 'http://example.com')).to be
8
- expect(Billy::ProxyRequestStub.new('http://example.com')
9
- .matches?('POST', 'http://example.com')).to_not be
10
-
11
- expect(Billy::ProxyRequestStub.new('http://example.com', method: :get)
12
- .matches?('GET', 'http://example.com')).to be
13
- expect(Billy::ProxyRequestStub.new('http://example.com', method: :post)
14
- .matches?('GET', 'http://example.com')).to_not be
15
- expect(Billy::ProxyRequestStub.new('http://example.com', method: :options)
16
- .matches?('GET', 'http://example.com')).to_not be
17
-
18
- expect(Billy::ProxyRequestStub.new('http://example.com', method: :post)
19
- .matches?('POST', 'http://example.com')).to be
20
- expect(Billy::ProxyRequestStub.new('http://fooxample.com', method: :post)
21
- .matches?('POST', 'http://example.com')).to_not be
22
- expect(Billy::ProxyRequestStub.new('http://fooxample.com', method: :options)
23
- .matches?('POST', 'http://example.com')).to_not be
24
-
25
- expect(Billy::ProxyRequestStub.new('http://example.com', method: :options)
26
- .matches?('OPTIONS', 'http://example.com')).to be
27
- expect(Billy::ProxyRequestStub.new('http://example.com', method: :options)
28
- .matches?('OPTIONS', 'http://zzzzzexample.com')).to_not be
29
- expect(Billy::ProxyRequestStub.new('http://example.com', method: :post)
30
- .matches?('OPTIONS', 'http://example.com')).to_not be
31
- end
32
-
33
- it 'should match regexps' do
34
- expect(Billy::ProxyRequestStub.new(/http:\/\/.+\.com/, method: :post)
35
- .matches?('POST', 'http://example.com')).to be
36
- expect(Billy::ProxyRequestStub.new(/http:\/\/.+\.co\.uk/, method: :get)
37
- .matches?('GET', 'http://example.com')).to_not be
38
- end
39
-
40
- it 'should match up to but not including query strings' do
41
- stub = Billy::ProxyRequestStub.new('http://example.com/foo/bar/')
42
- expect(stub.matches?('GET', 'http://example.com/foo/')).to_not be
43
- expect(stub.matches?('GET', 'http://example.com/foo/bar/')).to be
44
- expect(stub.matches?('GET', 'http://example.com/foo/bar/?baz=bap')).to be
45
- end
46
-
47
- it 'should match all methods' do
48
- expect(Billy::ProxyRequestStub.new('http://example.com', method: :all)
49
- .matches?('GET', 'http://example.com')).to be
50
- expect(Billy::ProxyRequestStub.new('http://example.com', method: :all)
51
- .matches?('POST', 'http://example.com')).to be
52
- expect(Billy::ProxyRequestStub.new('http://example.com', method: :all)
53
- .matches?('OPTIONS', 'http://example.com')).to be
54
- expect(Billy::ProxyRequestStub.new('http://example.com', method: :all)
55
- .matches?('HEAD', 'http://example.com')).to be
56
- end
57
- end
58
-
59
- context "#matches? (with strip_query_params false in config)" do
60
- before do
61
- Billy.config.strip_query_params = false
62
- end
63
-
64
- it 'should not match up to request with query strings' do
65
- stub = Billy::ProxyRequestStub.new('http://example.com/foo/bar/')
66
- expect(stub.matches?('GET', 'http://example.com/foo/')).to_not be
67
- expect(stub.matches?('GET', 'http://example.com/foo/bar/')).to be
68
- expect(stub.matches?('GET', 'http://example.com/foo/bar/?baz=bap')).to_not be
69
- end
70
- end
71
-
72
- context '#call (without #and_return)' do
73
- let(:subject) { Billy::ProxyRequestStub.new('url') }
74
-
75
- it 'returns a 204 empty response' do
76
- expect(subject.call('', '', {}, {}, nil)).to eql [204, { 'Content-Type' => 'text/plain' }, '']
77
- end
78
- end
79
-
80
- context '#and_return + #call' do
81
- let(:subject) { Billy::ProxyRequestStub.new('url') }
82
-
83
- it 'should generate bare responses' do
84
- subject.and_return body: 'baz foo bar'
85
- expect(subject.call('', '', {}, {}, nil)).to eql [
86
- 200,
87
- {},
88
- 'baz foo bar'
89
- ]
90
- end
91
-
92
- it 'should generate text responses' do
93
- subject.and_return text: 'foo bar baz'
94
- expect(subject.call('', '', {}, {}, nil)).to eql [
95
- 200,
96
- { 'Content-Type' => 'text/plain' },
97
- 'foo bar baz'
98
- ]
99
- end
100
-
101
- it 'should generate JSON responses' do
102
- subject.and_return json: { foo: 'bar' }
103
- expect(subject.call('', '', {}, {}, nil)).to eql [
104
- 200,
105
- { 'Content-Type' => 'application/json' },
106
- '{"foo":"bar"}'
107
- ]
108
- end
109
-
110
- context 'JSONP' do
111
- it 'should generate JSONP responses' do
112
- subject.and_return jsonp: { foo: 'bar' }
113
- expect(subject.call('', '', { 'callback' => ['baz'] }, {}, nil)).to eql [
114
- 200,
115
- { 'Content-Type' => 'application/javascript' },
116
- 'baz({"foo":"bar"})'
117
- ]
118
- end
119
-
120
- it 'should generate JSONP responses with custom callback parameter' do
121
- subject.and_return jsonp: { foo: 'bar' }, callback_param: 'cb'
122
- expect(subject.call('', '', { 'cb' => ['bap'] }, {}, nil)).to eql [
123
- 200,
124
- { 'Content-Type' => 'application/javascript' },
125
- 'bap({"foo":"bar"})'
126
- ]
127
- end
128
-
129
- it 'should generate JSONP responses with custom callback name' do
130
- subject.and_return jsonp: { foo: 'bar' }, callback: 'cb'
131
- expect(subject.call('', '', {}, {}, nil)).to eql [
132
- 200,
133
- { 'Content-Type' => 'application/javascript' },
134
- 'cb({"foo":"bar"})'
135
- ]
136
- end
137
- end
138
-
139
- it 'should generate redirection responses' do
140
- subject.and_return redirect_to: 'http://example.com'
141
- expect(subject.call('', '', {}, {}, nil)).to eql [
142
- 302,
143
- { 'Location' => 'http://example.com' },
144
- nil
145
- ]
146
- end
147
-
148
- it 'should set headers' do
149
- subject.and_return text: 'foo', headers: { 'HTTP-X-Foo' => 'bar' }
150
- expect(subject.call('', '', {}, {}, nil)).to eql [
151
- 200,
152
- { 'Content-Type' => 'text/plain', 'HTTP-X-Foo' => 'bar' },
153
- 'foo'
154
- ]
155
- end
156
-
157
- it 'should set status codes' do
158
- subject.and_return text: 'baz', code: 410
159
- expect(subject.call('', '', {}, {}, nil)).to eql [
160
- 410,
161
- { 'Content-Type' => 'text/plain' },
162
- 'baz'
163
- ]
164
- end
165
-
166
- it 'should use a callable' do
167
- expected_params = { 'param1' => ['one'], 'param2' => ['two'] }
168
- expected_headers = { 'header1' => 'three', 'header2' => 'four' }
169
- expected_body = 'body text'
170
-
171
- subject.and_return(proc do |params, headers, body, url, method|
172
- expect(params).to eql expected_params
173
- expect(headers).to eql expected_headers
174
- expect(body).to eql 'body text'
175
- expect(url).to eql 'url'
176
- expect(method).to eql 'GET'
177
- { code: 418, text: 'success' }
178
- end)
179
- expect(subject.call('GET', 'url', expected_params, expected_headers, expected_body)).to eql [
180
- 418,
181
- { 'Content-Type' => 'text/plain' },
182
- 'success'
183
- ]
184
- end
185
-
186
- it 'should use a callable with Billy.pass_request' do
187
- # Add the missing em-synchrony call which is done by
188
- # ProxyConnection#handle_request instead.
189
- EM.synchrony do
190
- subject.and_return(proc do |*args|
191
- response = Billy.pass_request(*args)
192
- response[:body] = 'modified'
193
- response[:code] = 205
194
- response
195
- end)
196
-
197
- # The test server can't be used at this scenario due to the limitations
198
- # of the Ruby GIL. We cannot use fibers (via eventmachine) and ask
199
- # ourself on a different thread to serve a HTTP request. This results
200
- # in +fiber called across threads (FiberError)+ errors. Unfortunately
201
- # we have to ask an external resource.
202
- url = 'http://google.com'
203
-
204
- expect(subject.call('GET', url, {}, {}, 'original')).to eql [
205
- 205,
206
- 'modified'
207
- ]
208
- end
209
- end
210
- end
211
-
212
- context '#stub_requests' do
213
- let(:subject) { Billy::ProxyRequestStub.new('url') }
214
-
215
- before :each do
216
- Billy.config.record_stub_requests = true
217
- end
218
-
219
- it 'should record requests' do
220
- subject.call('', '', {}, {}, nil)
221
- expect(subject.has_requests?).to be true
222
- end
223
-
224
- it 'should record multiple requests' do
225
- expected_amount = 3
226
- expected_amount.times do
227
- subject.call('', '', {}, {}, nil)
228
- end
229
-
230
- expect(subject.requests.length).to eql expected_amount
231
- end
232
-
233
- it 'should set a request' do
234
- expected_request = {
235
- method: 'POST',
236
- url: 'test-url',
237
- params: { 'param1' => ['one'], 'param2' => ['two'] },
238
- headers: { 'header1' => 'three', 'header2' => 'four' },
239
- body: 'body text'
240
- }
241
-
242
- subject.call(
243
- expected_request[:method],
244
- expected_request[:url],
245
- expected_request[:params],
246
- expected_request[:headers],
247
- expected_request[:body]
248
- )
249
- expect(subject.requests[0]).to eql expected_request
250
- end
251
- end
252
- end
@@ -1,55 +0,0 @@
1
- require 'spec_helper'
2
-
3
- describe Billy::JSONUtils do
4
- describe 'sorting' do
5
- describe '#sort_hash_keys' do
6
- it 'sorts simple Hashes' do
7
- data = { c: 'three', a: 'one', b: 'two' }
8
- expected = { a: 'one', b: 'two', c: 'three' }
9
- expect(Billy::JSONUtils.sort_hash_keys(data)).to eq expected
10
- end
11
-
12
- it 'does not sort simple Arrays' do
13
- data = [3, 1, 2, 'two', 'three', 'one']
14
- expect(Billy::JSONUtils.sort_hash_keys(data)).to eq data
15
- end
16
-
17
- it 'does not sort multi-dimensional Arrays' do
18
- data = [[3, 2, 1], [5, 4, 6], %w(b c a)]
19
- expect(Billy::JSONUtils.sort_hash_keys(data)).to eq data
20
- end
21
-
22
- it 'sorts multi-dimensional Hashes' do
23
- data = { c: { l: 2, m: 3, k: 1 }, a: { f: 3, e: 2, d: 1 }, b: { i: 2, h: 1, j: 3 } }
24
- expected = { a: { d: 1, e: 2, f: 3 }, b: { h: 1, i: 2, j: 3 }, c: { k: 1, l: 2, m: 3 } }
25
- expect(Billy::JSONUtils.sort_hash_keys(data)).to eq expected
26
- end
27
-
28
- it 'sorts abnormal data structures' do
29
- data = { b: [%w(b c a), { ab: 5, aa: 4, ac: 6 }, [3, 2, 1], { ba: true, bc: false, bb: nil }], a: { f: 3, e: 2, d: 1 } }
30
- expected = { a: { d: 1, e: 2, f: 3 }, b: [%w(b c a), { aa: 4, ab: 5, ac: 6 }, [3, 2, 1], { ba: true, bb: nil, bc: false }] }
31
- expect(Billy::JSONUtils.sort_hash_keys(data)).to eq expected
32
- end
33
- end
34
-
35
- describe 'sort_json' do
36
- it 'sorts JSON' do
37
- data = '{"c":"three","a":"one","b":"two"}'
38
- expected = '{"a":"one","b":"two","c":"three"}'
39
- expect(Billy::JSONUtils.sort_json(data)).to eq expected
40
- end
41
- end
42
- end
43
-
44
- describe 'json?' do
45
- let(:json) { { a: '1' }.to_json }
46
- let(:non_json) { 'Not JSON.' }
47
-
48
- it 'identifies JSON' do
49
- expect(Billy::JSONUtils.json?(json)).to be true
50
- end
51
- it 'identifies non-JSON' do
52
- expect(Billy::JSONUtils.json?(non_json)).to be false
53
- end
54
- end
55
- end
@@ -1,84 +0,0 @@
1
- require 'spec_helper'
2
-
3
- describe Billy::Authority do
4
- let(:auth1) { Billy::Authority.new }
5
- let(:auth2) { Billy::Authority.new }
6
-
7
- context('#key') do
8
- it 'generates a new key each time' do
9
- expect(auth1.key).not_to be(auth2.key)
10
- end
11
-
12
- it 'generates 2048 bit keys' do
13
- expect(auth1.key.n.num_bytes * 8).to be(2048)
14
- end
15
- end
16
-
17
- context('#cert') do
18
- it 'generates a new certificate each time' do
19
- expect(auth1.cert).not_to be(auth2.cert)
20
- end
21
-
22
- it 'generates unique serials' do
23
- expect(auth1.cert.serial).not_to be(auth2.cert.serial)
24
- end
25
-
26
- it 'configures a start date some days ago' do
27
- expect(auth1.cert.not_before).to \
28
- be_between((Date.today - 3).to_time, Date.today.to_time)
29
- end
30
-
31
- it 'configures an end date in some days' do
32
- expect(auth1.cert.not_after).to \
33
- be_between(Date.today.to_time, (Date.today + 3).to_time)
34
- end
35
-
36
- it 'configures the subject' do
37
- expect(auth1.cert.subject.to_s).to \
38
- be_eql('/CN=Puffing Billy/O=Puffing Billy')
39
- end
40
-
41
- it 'configures the certificate authority constrain' do
42
- expect(auth1.cert.extensions.first.to_s).to \
43
- be_eql('basicConstraints = critical, CA:TRUE')
44
- end
45
-
46
- it 'configures SSLv3' do
47
- # Zero-index version numbers. Yay.
48
- expect(auth1.cert.version).to be(2)
49
- end
50
- end
51
-
52
- context('#key_file') do
53
- it 'pass back the path' do
54
- expect(auth1.key_file).to match(/ca.key$/)
55
- end
56
-
57
- it 'creates a temporary file' do
58
- expect(File.exist?(auth1.key_file)).to be(true)
59
- end
60
-
61
- it 'creates a PEM formatted certificate' do
62
- expect(File.read(auth1.key_file)).to match(/^[A-Za-z0-9\-\+\/\=]+$/)
63
- end
64
-
65
- it 'writes out a private key' do
66
- key = OpenSSL::PKey::RSA.new(File.read(auth1.key_file))
67
- expect(key.private?).to be(true)
68
- end
69
- end
70
-
71
- context('#cert_file') do
72
- it 'pass back the path' do
73
- expect(auth1.cert_file).to match(/ca.crt$/)
74
- end
75
-
76
- it 'creates a temporary file' do
77
- expect(File.exist?(auth1.cert_file)).to be(true)
78
- end
79
-
80
- it 'creates a PEM formatted certificate' do
81
- expect(File.read(auth1.cert_file)).to match(/^[A-Za-z0-9\-\+\/\=]+$/)
82
- end
83
- end
84
- end
@@ -1,39 +0,0 @@
1
- require 'spec_helper'
2
-
3
- describe Billy::CertificateChain do
4
- let(:cert1) { Billy::Certificate.new('localhost') }
5
- let(:cert2) { Billy::Certificate.new('localhost.localdomain') }
6
- let(:chain) do
7
- Billy::CertificateChain.new('localhost', cert1.cert, cert2.cert)
8
- end
9
-
10
- context('#initialize') do
11
- it 'holds all certificates in order' do
12
- expect(chain.certificates).to be_eql([cert1.cert, cert2.cert])
13
- end
14
-
15
- it 'holds the domain' do
16
- expect(chain.domain).to be_eql('localhost')
17
- end
18
- end
19
-
20
- context('#file') do
21
- it 'pass back the path' do
22
- expect(chain.file).to match(/chain-localhost.pem/)
23
- end
24
-
25
- it 'writes out all certificates' do
26
- chain.certificates.each do |cert|
27
- expect(File.read(chain.file)).to include(cert.to_pem)
28
- end
29
- end
30
-
31
- it 'creates a temporary file' do
32
- expect(File.exist?(chain.file)).to be(true)
33
- end
34
-
35
- it 'creates a PEM formatted certificate chain' do
36
- expect(File.read(chain.file)).to match(/^[A-Za-z0-9\-\+\/\=]+$/)
37
- end
38
- end
39
- end
@@ -1,89 +0,0 @@
1
- require 'spec_helper'
2
-
3
- describe Billy::Certificate do
4
- let(:cert1) { Billy::Certificate.new('localhost') }
5
- let(:cert2) { Billy::Certificate.new('localhost.localdomain') }
6
-
7
- context('#domain') do
8
- it 'holds the domain' do
9
- expect(Billy::Certificate.new('test.tld').domain).to be_eql('test.tld')
10
- end
11
- end
12
-
13
- context('#key') do
14
- it 'generates a new key each time' do
15
- expect(cert1.key).not_to be(cert2.key)
16
- end
17
-
18
- it 'generates 2048 bit keys' do
19
- expect(cert1.key.n.num_bytes * 8).to be(2048)
20
- end
21
- end
22
-
23
- context('#cert') do
24
- it 'generates a new certificate each time' do
25
- expect(cert1.cert).not_to be(cert2.cert)
26
- end
27
-
28
- it 'generates unique serials' do
29
- expect(cert1.cert.serial).not_to be(cert2.cert.serial)
30
- end
31
-
32
- it 'configures a start date some days ago' do
33
- expect(cert1.cert.not_before).to \
34
- be_between((Date.today - 3).to_time, Date.today.to_time)
35
- end
36
-
37
- it 'configures an end date in some days' do
38
- expect(cert1.cert.not_after).to \
39
- be_between(Date.today.to_time, (Date.today + 3).to_time)
40
- end
41
-
42
- it 'configures the correct subject' do
43
- expect(cert1.cert.subject.to_s).to be_eql('/CN=localhost')
44
- end
45
-
46
- it 'configures the subject alternative names' do
47
- expect(cert1.cert.extensions.first.to_s).to \
48
- be_eql('subjectAltName = DNS:localhost')
49
- end
50
-
51
- it 'configures SSLv3' do
52
- # Zero-index version numbers. Yay.
53
- expect(cert1.cert.version).to be(2)
54
- end
55
- end
56
-
57
- context('#key_file') do
58
- it 'pass back the path' do
59
- expect(cert1.key_file).to match(/request-localhost.key$/)
60
- end
61
-
62
- it 'creates a temporary file' do
63
- expect(File.exist?(cert1.key_file)).to be(true)
64
- end
65
-
66
- it 'creates a PEM formatted certificate' do
67
- expect(File.read(cert1.key_file)).to match(/^[A-Za-z0-9\-\+\/\=]+$/)
68
- end
69
-
70
- it 'writes out a private key' do
71
- key = OpenSSL::PKey::RSA.new(File.read(cert1.key_file))
72
- expect(key.private?).to be(true)
73
- end
74
- end
75
-
76
- context('#cert_file') do
77
- it 'pass back the path' do
78
- expect(cert1.cert_file).to match(/request-localhost.crt$/)
79
- end
80
-
81
- it 'creates a temporary file' do
82
- expect(File.exist?(cert1.cert_file)).to be(true)
83
- end
84
-
85
- it 'creates a PEM formatted certificate' do
86
- expect(File.read(cert1.cert_file)).to match(/^[A-Za-z0-9\-\+\/\=]+$/)
87
- end
88
- end
89
- end
@@ -1,18 +0,0 @@
1
- require 'spec_helper'
2
-
3
- describe 'Watir-specific tests', type: :feature, js: true do
4
- before do
5
- proxy.stub('http://www.example.com/get').and_return(
6
- text: 'Success!'
7
- )
8
- end
9
-
10
- it 'should raise a NameError if an invalid browser driver is specified' do
11
- expect{Billy::Browsers::Watir.new :invalid}.to raise_error(NameError)
12
- end
13
-
14
- it 'should respond to a stubbed GET request' do
15
- @browser.goto 'http://www.example.com/get'
16
- expect(@browser.text).to eq 'Success!'
17
- end
18
- end