Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Make stub requests accessible #154

Closed
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
21 changes: 21 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -346,6 +346,27 @@ RSpec.configure do |config|
end
```

## Stub requests recording

If you want to record requests to stubbed URIs, set the following configuration option:

```ruby
Billy.configure do |c|
c.record_stub_requests = true
end
```

Example usage:

```ruby
it 'should intercept a GET request' do
stub = proxy.stub('http://example.com/')
visit 'http://example.com/'
expect(stub.has_requests?).to be true
expect(stub.requests).not_to be_empty
end
```

## Proxy timeouts

By default, the Puffing Billy proxy will use the EventMachine:HttpRequest timeouts of 5 seconds
Expand Down
10 changes: 10 additions & 0 deletions examples/intercept_request.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
<!DOCTYPE html>
<body>
<h1>Intercept request example</h1>
<script type='text/javascript' src='http://code.jquery.com/jquery-1.8.2.min.js'></script>
<script type='text/javascript'>
$(function () {
$.post('http://example.com/', { foo: 'bar' });
})
</script>
</body>
3 changes: 2 additions & 1 deletion lib/billy/config.rb
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ class Config
:persist_cache, :ignore_cache_port, :non_successful_cache_disabled, :non_successful_error_level,
:non_whitelisted_requests_disabled, :cache_path, :proxy_host, :proxy_port, :proxied_request_inactivity_timeout,
:proxied_request_connect_timeout, :dynamic_jsonp, :dynamic_jsonp_keys, :merge_cached_responses_whitelist,
:strip_query_params, :proxied_request_host, :proxied_request_port, :cache_request_body_methods
:strip_query_params, :proxied_request_host, :proxied_request_port, :cache_request_body_methods, :record_stub_requests

def initialize
@logger = defined?(Rails) ? Rails.logger : Logger.new(STDOUT)
Expand Down Expand Up @@ -40,6 +40,7 @@ def reset
@proxied_request_host = nil
@proxied_request_port = 80
@cache_request_body_methods = ['post']
@record_stub_requests = false
end
end

Expand Down
2 changes: 1 addition & 1 deletion lib/billy/handlers/stub_handler.rb
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ def handle_request(method, url, headers, body)
if (stub = find_stub(method, url))
query_string = Addressable::URI.parse(url).query || ''
params = CGI.parse(query_string)
stub.call(params, headers, body).tap do |response|
stub.call(method, url, params, headers, body).tap do |response|
Billy.log(:info, "puffing-billy: STUB #{method} for '#{url}'")
return { status: response[0], headers: response[1], content: response[2] }
end
Expand Down
27 changes: 26 additions & 1 deletion lib/billy/proxy_request_stub.rb
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,13 @@

module Billy
class ProxyRequestStub
attr_reader :requests

def initialize(url, options = {})
@options = { method: :get }.merge(options)
@method = @options[:method].to_s.upcase
@url = url
@requests = []
@response = { code: 204, headers: {}, text: '' }
end

Expand All @@ -14,7 +17,9 @@ def and_return(response)
self
end

def call(params, headers, body)
def call(method, url, params, headers, body)
push_request(method, url, params, headers, body)

if @response.respond_to?(:call)
res = @response.call(params, headers, body)
else
Expand Down Expand Up @@ -52,6 +57,10 @@ def call(params, headers, body)
[code, headers, body]
end

def has_requests?
@requests.any?
end

def matches?(method, url)
if method == @method
if @url.is_a?(Regexp)
Expand All @@ -61,5 +70,21 @@ def matches?(method, url)
end
end
end

private

attr_writer :requests

def push_request(method, url, params, headers, body)
if Billy.config.record_stub_requests
@requests.push({
method: method,
url: url,
params: params,
headers: headers,
body: body
})
end
end
end
end
31 changes: 31 additions & 0 deletions spec/features/examples/intercept_request_spec.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
require 'spec_helper'
require 'timeout'

describe 'intercept request example', type: :feature, js: true do
before do
Billy.config.record_stub_requests = true
end

it 'should intercept a GET request directly' do
stub = proxy.stub('http://example.com/').and_return(
headers: { 'Access-Control-Allow-Origin' => '*' },
code: 200
)
visit 'http://example.com/'
expect(stub.has_requests?).to be true
expect(stub.requests).not_to be_empty
end

it 'should intercept a POST request through an intermediary page' do
stub = proxy.stub('http://example.com/', method: 'post').and_return(
headers: { 'Access-Control-Allow-Origin' => '*' },
code: 200
)
visit '/intercept_request.html'
Timeout::timeout(5) do
sleep(0.1) until stub.has_requests?
end
request = stub.requests.shift
expect(request[:body]).to eql 'foo=bar'
end
end
63 changes: 52 additions & 11 deletions spec/lib/billy/proxy_request_stub_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@
let(:subject) { Billy::ProxyRequestStub.new('url') }

it 'returns a 204 empty response' do
expect(subject.call({}, {}, nil)).to eql [204, { 'Content-Type' => 'text/plain' }, '']
expect(subject.call('', '', {}, {}, nil)).to eql [204, { 'Content-Type' => 'text/plain' }, '']
end
end

Expand All @@ -71,7 +71,7 @@

it 'should generate bare responses' do
subject.and_return body: 'baz foo bar'
expect(subject.call({}, {}, nil)).to eql [
expect(subject.call('', '', {}, {}, nil)).to eql [
200,
{},
'baz foo bar'
Expand All @@ -80,7 +80,7 @@

it 'should generate text responses' do
subject.and_return text: 'foo bar baz'
expect(subject.call({}, {}, nil)).to eql [
expect(subject.call('', '', {}, {}, nil)).to eql [
200,
{ 'Content-Type' => 'text/plain' },
'foo bar baz'
Expand All @@ -89,7 +89,7 @@

it 'should generate JSON responses' do
subject.and_return json: { foo: 'bar' }
expect(subject.call({}, {}, nil)).to eql [
expect(subject.call('', '', {}, {}, nil)).to eql [
200,
{ 'Content-Type' => 'application/json' },
'{"foo":"bar"}'
Expand All @@ -99,7 +99,7 @@
context 'JSONP' do
it 'should generate JSONP responses' do
subject.and_return jsonp: { foo: 'bar' }
expect(subject.call({ 'callback' => ['baz'] }, {}, nil)).to eql [
expect(subject.call('', '', { 'callback' => ['baz'] }, {}, nil)).to eql [
200,
{ 'Content-Type' => 'application/javascript' },
'baz({"foo":"bar"})'
Expand All @@ -108,7 +108,7 @@

it 'should generate JSONP responses with custom callback parameter' do
subject.and_return jsonp: { foo: 'bar' }, callback_param: 'cb'
expect(subject.call({ 'cb' => ['bap'] }, {}, nil)).to eql [
expect(subject.call('', '', { 'cb' => ['bap'] }, {}, nil)).to eql [
200,
{ 'Content-Type' => 'application/javascript' },
'bap({"foo":"bar"})'
Expand All @@ -117,7 +117,7 @@

it 'should generate JSONP responses with custom callback name' do
subject.and_return jsonp: { foo: 'bar' }, callback: 'cb'
expect(subject.call({}, {}, nil)).to eql [
expect(subject.call('', '', {}, {}, nil)).to eql [
200,
{ 'Content-Type' => 'application/javascript' },
'cb({"foo":"bar"})'
Expand All @@ -127,7 +127,7 @@

it 'should generate redirection responses' do
subject.and_return redirect_to: 'http://example.com'
expect(subject.call({}, {}, nil)).to eql [
expect(subject.call('', '', {}, {}, nil)).to eql [
302,
{ 'Location' => 'http://example.com' },
nil
Expand All @@ -136,7 +136,7 @@

it 'should set headers' do
subject.and_return text: 'foo', headers: { 'HTTP-X-Foo' => 'bar' }
expect(subject.call({}, {}, nil)).to eql [
expect(subject.call('', '', {}, {}, nil)).to eql [
200,
{ 'Content-Type' => 'text/plain', 'HTTP-X-Foo' => 'bar' },
'foo'
Expand All @@ -145,7 +145,7 @@

it 'should set status codes' do
subject.and_return text: 'baz', code: 410
expect(subject.call({}, {}, nil)).to eql [
expect(subject.call('', '', {}, {}, nil)).to eql [
410,
{ 'Content-Type' => 'text/plain' },
'baz'
Expand All @@ -163,11 +163,52 @@
expect(body).to eql 'body text'
{ code: 418, text: 'success' }
end)
expect(subject.call(expected_params, expected_headers, expected_body)).to eql [
expect(subject.call('', '', expected_params, expected_headers, expected_body)).to eql [
418,
{ 'Content-Type' => 'text/plain' },
'success'
]
end
end

context '#stub_requests' do
let(:subject) { Billy::ProxyRequestStub.new('url') }

before :each do
Billy.config.record_stub_requests = true
end

it 'should record requests' do
subject.call('', '', {}, {}, nil)
expect(subject.has_requests?).to be true
end

it 'should record multiple requests' do
expected_amount = 3
expected_amount.times do
subject.call('', '', {}, {}, nil)
end

expect(subject.requests.length).to eql expected_amount
end

it 'should set a request' do
expected_request = {
method: 'POST',
url: 'test-url',
params: { 'param1' => ['one'], 'param2' => ['two'] },
headers: { 'header1' => 'three', 'header2' => 'four' },
body: 'body text'
}

subject.call(
expected_request[:method],
expected_request[:url],
expected_request[:params],
expected_request[:headers],
expected_request[:body]
)
expect(subject.requests[0]).to eql expected_request
end
end
end