puffing-billy 0.7.0 → 0.8.0

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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 3655cba82676b1deab3539e52a0905e2235fd121
4
- data.tar.gz: 1b4fac47e1c38eed0c59038924ae10218bc753d0
3
+ metadata.gz: ab6b245ca1fa1295379ac58fcc023b9ae2d4be4b
4
+ data.tar.gz: d2ed68617bba9beca40b228fbfb116bed58f8641
5
5
  SHA512:
6
- metadata.gz: 161f4b1ac60dd9f946a60f78b2abe69f16c7fdf7cfe3a4e3e8599c495de9c32b2825c5b0f7beb3df644a2bde58694b77c6b1058d83eb9db49d067d547e5590e8
7
- data.tar.gz: 683a32965991b618db46c6943ccd535b9f92a11df8fc5da8dce371b1e4f8b58df4d581c54919047c347adf85f5c61ec4a48becd40597234fcd774d1c3199d814
6
+ metadata.gz: 7d4919dba7d0619860e035edf00580479228b3de38da97185b21356ba077f39c42add963de90f1521f30933e08f20c0e3494de359c892bb3b1e5fa1029bca704
7
+ data.tar.gz: dc18d1801cf9bb821a7fefa6f093cfdfe748f8ea500058f2d60f59e422c78c5135114bacf7f110acf9001c8ea0495e0899311e364d2cea7f84bf6110814db7b6
@@ -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)
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- puffing-billy (0.7.0)
4
+ puffing-billy (0.8.0)
5
5
  addressable
6
6
  em-http-request (~> 1.1.0)
7
7
  em-synchrony
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.should have_content("I'm not Google!")
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.should have_content("I'm not Google!")
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>
@@ -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
@@ -1,3 +1,3 @@
1
1
  module Billy
2
- VERSION = '0.7.0'
2
+ VERSION = '0.8.0'
3
3
  end
@@ -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.7.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-05-06 00:00:00.000000000 Z
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