puffing-billy 0.7.0 → 0.8.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +6 -0
- data/Gemfile.lock +1 -1
- data/README.md +42 -2
- data/examples/intercept_request.html +10 -0
- data/lib/billy/config.rb +4 -1
- data/lib/billy/handlers/cache_handler.rb +5 -0
- data/lib/billy/handlers/stub_handler.rb +1 -1
- data/lib/billy/proxy_request_stub.rb +26 -1
- data/lib/billy/version.rb +1 -1
- data/spec/features/examples/intercept_request_spec.rb +31 -0
- data/spec/lib/billy/handlers/cache_handler_spec.rb +17 -0
- data/spec/lib/billy/proxy_request_stub_spec.rb +52 -11
- metadata +5 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: ab6b245ca1fa1295379ac58fcc023b9ae2d4be4b
|
4
|
+
data.tar.gz: d2ed68617bba9beca40b228fbfb116bed58f8641
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 7d4919dba7d0619860e035edf00580479228b3de38da97185b21356ba077f39c42add963de90f1521f30933e08f20c0e3494de359c892bb3b1e5fa1029bca704
|
7
|
+
data.tar.gz: dc18d1801cf9bb821a7fefa6f093cfdfe748f8ea500058f2d60f59e422c78c5135114bacf7f110acf9001c8ea0495e0899311e364d2cea7f84bf6110814db7b6
|
data/CHANGELOG.md
CHANGED
@@ -1,3 +1,9 @@
|
|
1
|
+
v0.8.0, 2016-06-02
|
2
|
+
------------------
|
3
|
+
* Add optional after_cache_handles_request callback for manipulating cached responses [#149](https://github.com/oesmith/puffing-billy/pull/149)
|
4
|
+
* Remove rspec-expectations deprecation warning for README example [#153](https://github.com/oesmith/puffing-billy/pull/153)
|
5
|
+
* Make stub requests accessible [#154](https://github.com/oesmith/puffing-billy/pull/154)
|
6
|
+
|
1
7
|
v0.7.0, 2016-05-05
|
2
8
|
------------------
|
3
9
|
* Change WebKit driver to ignore SSL errors [#140](https://github.com/oesmith/puffing-billy/pull/140)
|
data/Gemfile.lock
CHANGED
data/README.md
CHANGED
@@ -23,7 +23,7 @@ you can test it!
|
|
23
23
|
it 'should stub google' do
|
24
24
|
proxy.stub('http://www.google.com/').and_return(:text => "I'm not Google!")
|
25
25
|
visit 'http://www.google.com/'
|
26
|
-
page.
|
26
|
+
expect(page).to have_content("I'm not Google!")
|
27
27
|
end
|
28
28
|
```
|
29
29
|
|
@@ -145,7 +145,7 @@ end
|
|
145
145
|
And /^a stub for google$/ do
|
146
146
|
proxy.stub('http://www.google.com/').and_return(:text => "I'm not Google!")
|
147
147
|
visit 'http://www.google.com/'
|
148
|
-
page.
|
148
|
+
expect(page).to have_content("I'm not Google!")
|
149
149
|
end
|
150
150
|
```
|
151
151
|
|
@@ -284,6 +284,25 @@ server is required to access the internet. Most common in larger companies.
|
|
284
284
|
|
285
285
|
`c.cache_request_body_methods` is used to specify HTTP methods of requests that you would like to cache separately based on the contents of the request body. The default is ['post'].
|
286
286
|
|
287
|
+
`c.after_cache_handles_request` is used to configure a callback that can operate on the response after it has been retrieved from the cache but before it is returned. The callback receives the request and response as arguments, with a request object like: `{ method: method, url: url, headers: headers, body: body }`. An example usage would be manipulating the Access-Control-Allow-Origin header so that your test server doesn't always have to run on the same port in order to accept cached responses to CORS requests:
|
288
|
+
|
289
|
+
```
|
290
|
+
Billy.configure do |c|
|
291
|
+
...
|
292
|
+
fix_cors_header = proc do |_request, response|
|
293
|
+
allowed_origins = response[:headers]['Access-Control-Allow-Origin']
|
294
|
+
if allowed_origins.present?
|
295
|
+
localhost_port_pattern = %r{(?<=http://127\.0\.0\.1:)(\d+)}
|
296
|
+
allowed_origins.sub!(
|
297
|
+
localhost_port_pattern, Capybara.current_session.server.port.to_s
|
298
|
+
)
|
299
|
+
end
|
300
|
+
end
|
301
|
+
c.after_cache_handles_request = fix_cors_header
|
302
|
+
...
|
303
|
+
end
|
304
|
+
```
|
305
|
+
|
287
306
|
### Cache Scopes
|
288
307
|
|
289
308
|
If you need to cache different responses to the same HTTP request, you can use
|
@@ -346,6 +365,27 @@ RSpec.configure do |config|
|
|
346
365
|
end
|
347
366
|
```
|
348
367
|
|
368
|
+
## Stub requests recording
|
369
|
+
|
370
|
+
If you want to record requests to stubbed URIs, set the following configuration option:
|
371
|
+
|
372
|
+
```ruby
|
373
|
+
Billy.configure do |c|
|
374
|
+
c.record_stub_requests = true
|
375
|
+
end
|
376
|
+
```
|
377
|
+
|
378
|
+
Example usage:
|
379
|
+
|
380
|
+
```ruby
|
381
|
+
it 'should intercept a GET request' do
|
382
|
+
stub = proxy.stub('http://example.com/')
|
383
|
+
visit 'http://example.com/'
|
384
|
+
expect(stub.has_requests?).to be true
|
385
|
+
expect(stub.requests).not_to be_empty
|
386
|
+
end
|
387
|
+
```
|
388
|
+
|
349
389
|
## Proxy timeouts
|
350
390
|
|
351
391
|
By default, the Puffing Billy proxy will use the EventMachine:HttpRequest timeouts of 5 seconds
|
@@ -0,0 +1,10 @@
|
|
1
|
+
<!DOCTYPE html>
|
2
|
+
<body>
|
3
|
+
<h1>Intercept request example</h1>
|
4
|
+
<script type='text/javascript' src='http://code.jquery.com/jquery-1.8.2.min.js'></script>
|
5
|
+
<script type='text/javascript'>
|
6
|
+
$(function () {
|
7
|
+
$.post('http://example.com/', { foo: 'bar' });
|
8
|
+
})
|
9
|
+
</script>
|
10
|
+
</body>
|
data/lib/billy/config.rb
CHANGED
@@ -10,7 +10,8 @@ module Billy
|
|
10
10
|
:persist_cache, :ignore_cache_port, :non_successful_cache_disabled, :non_successful_error_level,
|
11
11
|
:non_whitelisted_requests_disabled, :cache_path, :proxy_host, :proxy_port, :proxied_request_inactivity_timeout,
|
12
12
|
:proxied_request_connect_timeout, :dynamic_jsonp, :dynamic_jsonp_keys, :merge_cached_responses_whitelist,
|
13
|
-
:strip_query_params, :proxied_request_host, :proxied_request_port, :cache_request_body_methods
|
13
|
+
:strip_query_params, :proxied_request_host, :proxied_request_port, :cache_request_body_methods, :after_cache_handles_request,
|
14
|
+
:record_stub_requests
|
14
15
|
|
15
16
|
def initialize
|
16
17
|
@logger = defined?(Rails) ? Rails.logger : Logger.new(STDOUT)
|
@@ -40,6 +41,8 @@ module Billy
|
|
40
41
|
@proxied_request_host = nil
|
41
42
|
@proxied_request_port = 80
|
42
43
|
@cache_request_body_methods = ['post']
|
44
|
+
@after_cache_handles_request = nil
|
45
|
+
@record_stub_requests = false
|
43
46
|
end
|
44
47
|
end
|
45
48
|
|
@@ -25,6 +25,11 @@ module Billy
|
|
25
25
|
replace_response_callback(response, url)
|
26
26
|
end
|
27
27
|
|
28
|
+
if Billy.config.after_cache_handles_request
|
29
|
+
request = { method: method, url: url, headers: headers, body: body }
|
30
|
+
Billy.config.after_cache_handles_request.call(request, response)
|
31
|
+
end
|
32
|
+
|
28
33
|
return response
|
29
34
|
end
|
30
35
|
end
|
@@ -10,7 +10,7 @@ module Billy
|
|
10
10
|
if (stub = find_stub(method, url))
|
11
11
|
query_string = Addressable::URI.parse(url).query || ''
|
12
12
|
params = CGI.parse(query_string)
|
13
|
-
stub.call(params, headers, body).tap do |response|
|
13
|
+
stub.call(method, url, params, headers, body).tap do |response|
|
14
14
|
Billy.log(:info, "puffing-billy: STUB #{method} for '#{url}'")
|
15
15
|
return { status: response[0], headers: response[1], content: response[2] }
|
16
16
|
end
|
@@ -2,10 +2,13 @@ require 'multi_json'
|
|
2
2
|
|
3
3
|
module Billy
|
4
4
|
class ProxyRequestStub
|
5
|
+
attr_reader :requests
|
6
|
+
|
5
7
|
def initialize(url, options = {})
|
6
8
|
@options = { method: :get }.merge(options)
|
7
9
|
@method = @options[:method].to_s.upcase
|
8
10
|
@url = url
|
11
|
+
@requests = []
|
9
12
|
@response = { code: 204, headers: {}, text: '' }
|
10
13
|
end
|
11
14
|
|
@@ -14,7 +17,9 @@ module Billy
|
|
14
17
|
self
|
15
18
|
end
|
16
19
|
|
17
|
-
def call(params, headers, body)
|
20
|
+
def call(method, url, params, headers, body)
|
21
|
+
push_request(method, url, params, headers, body)
|
22
|
+
|
18
23
|
if @response.respond_to?(:call)
|
19
24
|
res = @response.call(params, headers, body)
|
20
25
|
else
|
@@ -52,6 +57,10 @@ module Billy
|
|
52
57
|
[code, headers, body]
|
53
58
|
end
|
54
59
|
|
60
|
+
def has_requests?
|
61
|
+
@requests.any?
|
62
|
+
end
|
63
|
+
|
55
64
|
def matches?(method, url)
|
56
65
|
if method == @method
|
57
66
|
if @url.is_a?(Regexp)
|
@@ -61,5 +70,21 @@ module Billy
|
|
61
70
|
end
|
62
71
|
end
|
63
72
|
end
|
73
|
+
|
74
|
+
private
|
75
|
+
|
76
|
+
attr_writer :requests
|
77
|
+
|
78
|
+
def push_request(method, url, params, headers, body)
|
79
|
+
if Billy.config.record_stub_requests
|
80
|
+
@requests.push({
|
81
|
+
method: method,
|
82
|
+
url: url,
|
83
|
+
params: params,
|
84
|
+
headers: headers,
|
85
|
+
body: body
|
86
|
+
})
|
87
|
+
end
|
88
|
+
end
|
64
89
|
end
|
65
90
|
end
|
data/lib/billy/version.rb
CHANGED
@@ -0,0 +1,31 @@
|
|
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
|
@@ -97,6 +97,23 @@ describe Billy::CacheHandler do
|
|
97
97
|
other_request[:headers],
|
98
98
|
other_request[:body])).to eql(status: 200, headers: { 'Connection' => 'close' }, content: 'no jsonp but has parentheses()')
|
99
99
|
end
|
100
|
+
|
101
|
+
context 'when after_cache_handles_request is set' do
|
102
|
+
it "should call the callback with the request and response" do
|
103
|
+
allow(Billy.config).to receive(:after_cache_handles_request) do
|
104
|
+
proc do |request, response|
|
105
|
+
response[:headers]['Access-Control-Allow-Origin'] = "*"
|
106
|
+
response[:content] = request[:body]
|
107
|
+
end
|
108
|
+
end
|
109
|
+
expect(Billy::Cache.instance).to receive(:cached?).and_return(true)
|
110
|
+
expect(Billy::Cache.instance).to receive(:fetch).and_return(status: 200, headers: { 'Connection' => 'close' }, content: 'The response body')
|
111
|
+
expect(handler.handle_request(request[:method],
|
112
|
+
request[:url],
|
113
|
+
request[:headers],
|
114
|
+
request[:body])).to eql(status: 200, headers: { 'Connection' => 'close', 'Access-Control-Allow-Origin' => "*" }, content: 'Some body')
|
115
|
+
end
|
116
|
+
end
|
100
117
|
end
|
101
118
|
|
102
119
|
context 'updating jsonp callback names disabled' do
|
@@ -62,7 +62,7 @@ describe Billy::ProxyRequestStub do
|
|
62
62
|
let(:subject) { Billy::ProxyRequestStub.new('url') }
|
63
63
|
|
64
64
|
it 'returns a 204 empty response' do
|
65
|
-
expect(subject.call({}, {}, nil)).to eql [204, { 'Content-Type' => 'text/plain' }, '']
|
65
|
+
expect(subject.call('', '', {}, {}, nil)).to eql [204, { 'Content-Type' => 'text/plain' }, '']
|
66
66
|
end
|
67
67
|
end
|
68
68
|
|
@@ -71,7 +71,7 @@ describe Billy::ProxyRequestStub do
|
|
71
71
|
|
72
72
|
it 'should generate bare responses' do
|
73
73
|
subject.and_return body: 'baz foo bar'
|
74
|
-
expect(subject.call({}, {}, nil)).to eql [
|
74
|
+
expect(subject.call('', '', {}, {}, nil)).to eql [
|
75
75
|
200,
|
76
76
|
{},
|
77
77
|
'baz foo bar'
|
@@ -80,7 +80,7 @@ describe Billy::ProxyRequestStub do
|
|
80
80
|
|
81
81
|
it 'should generate text responses' do
|
82
82
|
subject.and_return text: 'foo bar baz'
|
83
|
-
expect(subject.call({}, {}, nil)).to eql [
|
83
|
+
expect(subject.call('', '', {}, {}, nil)).to eql [
|
84
84
|
200,
|
85
85
|
{ 'Content-Type' => 'text/plain' },
|
86
86
|
'foo bar baz'
|
@@ -89,7 +89,7 @@ describe Billy::ProxyRequestStub do
|
|
89
89
|
|
90
90
|
it 'should generate JSON responses' do
|
91
91
|
subject.and_return json: { foo: 'bar' }
|
92
|
-
expect(subject.call({}, {}, nil)).to eql [
|
92
|
+
expect(subject.call('', '', {}, {}, nil)).to eql [
|
93
93
|
200,
|
94
94
|
{ 'Content-Type' => 'application/json' },
|
95
95
|
'{"foo":"bar"}'
|
@@ -99,7 +99,7 @@ describe Billy::ProxyRequestStub do
|
|
99
99
|
context 'JSONP' do
|
100
100
|
it 'should generate JSONP responses' do
|
101
101
|
subject.and_return jsonp: { foo: 'bar' }
|
102
|
-
expect(subject.call({ 'callback' => ['baz'] }, {}, nil)).to eql [
|
102
|
+
expect(subject.call('', '', { 'callback' => ['baz'] }, {}, nil)).to eql [
|
103
103
|
200,
|
104
104
|
{ 'Content-Type' => 'application/javascript' },
|
105
105
|
'baz({"foo":"bar"})'
|
@@ -108,7 +108,7 @@ describe Billy::ProxyRequestStub do
|
|
108
108
|
|
109
109
|
it 'should generate JSONP responses with custom callback parameter' do
|
110
110
|
subject.and_return jsonp: { foo: 'bar' }, callback_param: 'cb'
|
111
|
-
expect(subject.call({ 'cb' => ['bap'] }, {}, nil)).to eql [
|
111
|
+
expect(subject.call('', '', { 'cb' => ['bap'] }, {}, nil)).to eql [
|
112
112
|
200,
|
113
113
|
{ 'Content-Type' => 'application/javascript' },
|
114
114
|
'bap({"foo":"bar"})'
|
@@ -117,7 +117,7 @@ describe Billy::ProxyRequestStub do
|
|
117
117
|
|
118
118
|
it 'should generate JSONP responses with custom callback name' do
|
119
119
|
subject.and_return jsonp: { foo: 'bar' }, callback: 'cb'
|
120
|
-
expect(subject.call({}, {}, nil)).to eql [
|
120
|
+
expect(subject.call('', '', {}, {}, nil)).to eql [
|
121
121
|
200,
|
122
122
|
{ 'Content-Type' => 'application/javascript' },
|
123
123
|
'cb({"foo":"bar"})'
|
@@ -127,7 +127,7 @@ describe Billy::ProxyRequestStub do
|
|
127
127
|
|
128
128
|
it 'should generate redirection responses' do
|
129
129
|
subject.and_return redirect_to: 'http://example.com'
|
130
|
-
expect(subject.call({}, {}, nil)).to eql [
|
130
|
+
expect(subject.call('', '', {}, {}, nil)).to eql [
|
131
131
|
302,
|
132
132
|
{ 'Location' => 'http://example.com' },
|
133
133
|
nil
|
@@ -136,7 +136,7 @@ describe Billy::ProxyRequestStub do
|
|
136
136
|
|
137
137
|
it 'should set headers' do
|
138
138
|
subject.and_return text: 'foo', headers: { 'HTTP-X-Foo' => 'bar' }
|
139
|
-
expect(subject.call({}, {}, nil)).to eql [
|
139
|
+
expect(subject.call('', '', {}, {}, nil)).to eql [
|
140
140
|
200,
|
141
141
|
{ 'Content-Type' => 'text/plain', 'HTTP-X-Foo' => 'bar' },
|
142
142
|
'foo'
|
@@ -145,7 +145,7 @@ describe Billy::ProxyRequestStub do
|
|
145
145
|
|
146
146
|
it 'should set status codes' do
|
147
147
|
subject.and_return text: 'baz', code: 410
|
148
|
-
expect(subject.call({}, {}, nil)).to eql [
|
148
|
+
expect(subject.call('', '', {}, {}, nil)).to eql [
|
149
149
|
410,
|
150
150
|
{ 'Content-Type' => 'text/plain' },
|
151
151
|
'baz'
|
@@ -163,11 +163,52 @@ describe Billy::ProxyRequestStub do
|
|
163
163
|
expect(body).to eql 'body text'
|
164
164
|
{ code: 418, text: 'success' }
|
165
165
|
end)
|
166
|
-
expect(subject.call(expected_params, expected_headers, expected_body)).to eql [
|
166
|
+
expect(subject.call('', '', expected_params, expected_headers, expected_body)).to eql [
|
167
167
|
418,
|
168
168
|
{ 'Content-Type' => 'text/plain' },
|
169
169
|
'success'
|
170
170
|
]
|
171
171
|
end
|
172
172
|
end
|
173
|
+
|
174
|
+
context '#stub_requests' do
|
175
|
+
let(:subject) { Billy::ProxyRequestStub.new('url') }
|
176
|
+
|
177
|
+
before :each do
|
178
|
+
Billy.config.record_stub_requests = true
|
179
|
+
end
|
180
|
+
|
181
|
+
it 'should record requests' do
|
182
|
+
subject.call('', '', {}, {}, nil)
|
183
|
+
expect(subject.has_requests?).to be true
|
184
|
+
end
|
185
|
+
|
186
|
+
it 'should record multiple requests' do
|
187
|
+
expected_amount = 3
|
188
|
+
expected_amount.times do
|
189
|
+
subject.call('', '', {}, {}, nil)
|
190
|
+
end
|
191
|
+
|
192
|
+
expect(subject.requests.length).to eql expected_amount
|
193
|
+
end
|
194
|
+
|
195
|
+
it 'should set a request' do
|
196
|
+
expected_request = {
|
197
|
+
method: 'POST',
|
198
|
+
url: 'test-url',
|
199
|
+
params: { 'param1' => ['one'], 'param2' => ['two'] },
|
200
|
+
headers: { 'header1' => 'three', 'header2' => 'four' },
|
201
|
+
body: 'body text'
|
202
|
+
}
|
203
|
+
|
204
|
+
subject.call(
|
205
|
+
expected_request[:method],
|
206
|
+
expected_request[:url],
|
207
|
+
expected_request[:params],
|
208
|
+
expected_request[:headers],
|
209
|
+
expected_request[:body]
|
210
|
+
)
|
211
|
+
expect(subject.requests[0]).to eql expected_request
|
212
|
+
end
|
213
|
+
end
|
173
214
|
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: puffing-billy
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.8.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Olly Smith
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2016-
|
11
|
+
date: 2016-06-02 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: rspec
|
@@ -298,6 +298,7 @@ files:
|
|
298
298
|
- bin/proxy.rb
|
299
299
|
- examples/README.md
|
300
300
|
- examples/facebook_api.html
|
301
|
+
- examples/intercept_request.html
|
301
302
|
- examples/post_api.html
|
302
303
|
- examples/preflight_request.html
|
303
304
|
- examples/tumblr_api.html
|
@@ -325,6 +326,7 @@ files:
|
|
325
326
|
- log/.gitkeep
|
326
327
|
- puffing-billy.gemspec
|
327
328
|
- spec/features/examples/facebook_api_spec.rb
|
329
|
+
- spec/features/examples/intercept_request_spec.rb
|
328
330
|
- spec/features/examples/post_api_spec.rb
|
329
331
|
- spec/features/examples/preflight_request_spec.rb
|
330
332
|
- spec/features/examples/tumblr_api_spec.rb
|
@@ -366,6 +368,7 @@ specification_version: 4
|
|
366
368
|
summary: Easy request stubs for browser tests.
|
367
369
|
test_files:
|
368
370
|
- spec/features/examples/facebook_api_spec.rb
|
371
|
+
- spec/features/examples/intercept_request_spec.rb
|
369
372
|
- spec/features/examples/post_api_spec.rb
|
370
373
|
- spec/features/examples/preflight_request_spec.rb
|
371
374
|
- spec/features/examples/tumblr_api_spec.rb
|