Skip to content
Merged
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
22 changes: 19 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -103,9 +103,25 @@ proxy.stub('https://example.com:443/secure/').and_return(:text => 'secrets!!1!')
# params: Query string parameters hash, CGI::escape-style
# headers: Headers hash
# body: Request body string
#
proxy.stub('https://example.com/proc/').and_return(Proc.new { |params, headers, body|
{ :text => "Hello, #{params['name'][0]}"}
# url: The actual URL which was requested
# method: The HTTP verb which was requested
proxy.stub('https://example.com/proc/').and_return(Proc.new { |params, headers, body, url, method|
{
:code => 200,
:text => "Hello, #{params['name'][0]}"
}
})

# You can also use Puffing Billy to intercept requests and responses. Just pass
# a Proc and use the pass_request method. You can manipulate the request
# (headers, URL, HTTP method, etc) and also the response from the upstream
# server.
proxy.stub('http://example.com/').and_return(Proc.new { |*args|
response = pass_request(*args)
response[:headers]['Content-Type'] = 'text/plain'
response[:body] = 'Hello World!'
response[:code] = 200
response
})

# Stub out a POST. Don't forget to allow a CORS request and set the method to 'post'
Expand Down
12 changes: 11 additions & 1 deletion lib/billy/proxy_request_stub.rb
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ 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)
res = instance_exec(params, headers, body, url, method, &@response)
else
res = @response
end
Expand Down Expand Up @@ -71,6 +71,16 @@ def matches?(method, url)
end
end

def pass_request(params, headers, body, url, method)
handler = Billy.proxy.request_handler.handlers[:proxy]
response = handler.handle_request(method, url, headers, body)
{
code: response[:status],
body: response[:content],
headers: response[:headers]
}
end

private

attr_writer :requests
Expand Down
37 changes: 35 additions & 2 deletions spec/lib/billy/proxy_request_stub_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -157,18 +157,51 @@
expected_headers = { 'header1' => 'three', 'header2' => 'four' }
expected_body = 'body text'

subject.and_return(proc do |params, headers, body|
# Required due to the instance_exec implementation
subject.extend(RSpec::Matchers)

subject.and_return(proc do |params, headers, body, url, method|
expect(params).to eql expected_params
expect(headers).to eql expected_headers
expect(body).to eql 'body text'
expect(url).to eql 'url'
expect(method).to eql 'GET'
{ code: 418, text: 'success' }
end)
expect(subject.call('', '', expected_params, expected_headers, expected_body)).to eql [
expect(subject.call('GET', 'url', expected_params, expected_headers, expected_body)).to eql [
418,
{ 'Content-Type' => 'text/plain' },
'success'
]
end

it 'should use a callable with pass_request' do
# Add the missing em-synchrony call which is done by
# ProxyConnection#handle_request instead.
EM.synchrony do
# Required due to the instance_exec implementation
subject.extend(RSpec::Matchers)

subject.and_return(proc do |*args|
response = pass_request(*args)
response[:body] = 'modified'
response[:code] = 205
response
end)

# The test server can't be used at this scenario due to the limitations
# of the Ruby GIL. We cannot use fibers (via eventmachine) and ask
# ourself on a different thread to serve a HTTP request. This results
# in +fiber called across threads (FiberError)+ errors. Unfortunately
# we have to ask an external resource.
url = 'http://google.com'

expect(subject.call('GET', url, {}, {}, 'original')).to eql [
205,
'modified'
]
end
end
end

context '#stub_requests' do
Expand Down