Skip to content
Draft
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
15 changes: 15 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -255,6 +255,21 @@ or
WebValve.register FakeBank, url: %r{\Ahttp://mybank.com(/.*)?\z}
```

When a `String` URL is registered, WebValve parses any path component out
of it and strips that prefix from incoming requests before they reach
your `FakeService` — so a service registered at `https://mybank.com/api`
can declare its routes as `get '/accounts'` rather than
`get '/api/accounts'`. WebValve cannot infer a static prefix from a
`Regexp` or `Addressable::Template`, so by default it does not strip any
prefix and your fake routes must use the full request path. If you'd
like to keep relative routes, pass an explicit `path_prefix:`:

```ruby
WebValve.register FakeBank,
url: %r{\Ahttps://api\.mybank\.com/v2/.*\z},
path_prefix: '/v2'
```

## What's in a `FakeService`?

The definition of `FakeService` is really simple. It's just a
Expand Down
12 changes: 8 additions & 4 deletions lib/webvalve/fake_service_config.rb
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,10 @@ module WebValve
class FakeServiceConfig
attr_reader :service_class_name

def initialize(service_class_name:, url: nil)
def initialize(service_class_name:, url: nil, path_prefix: nil)
@service_class_name = service_class_name
@custom_service_url = url
@custom_path_prefix = path_prefix
end

def explicitly_enabled?
Expand All @@ -22,17 +23,20 @@ def full_url
def service_url
@service_url ||= begin
raise missing_url_message if full_url.blank?
strip_basic_auth full_url
full_url.is_a?(String) ? strip_basic_auth(full_url) : full_url
end
end

def path_prefix
@path_prefix ||= URI::parse(service_url).path
@path_prefix ||= begin
raise missing_url_message if full_url.blank?
custom_path_prefix || (full_url.is_a?(String) ? URI.parse(service_url).path : "")
end
end

private

attr_reader :custom_service_url
attr_reader :custom_service_url, :custom_path_prefix

def value_from_env
ENV["#{service_name.to_s.upcase}_ENABLED"]
Expand Down
64 changes: 64 additions & 0 deletions spec/webvalve/fake_service_config_spec.rb
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
require 'spec_helper'
require 'addressable/template'

RSpec.describe WebValve::FakeServiceConfig do
let(:fake_service) do
Expand Down Expand Up @@ -87,6 +88,26 @@ def self.name
expect(subject.service_url).to eq 'http://thingy.dev'
end
end

context 'when registered with a Regexp url' do
let(:url) { %r{\Ahttp://thingy\.dev(/.*)?\z} }

subject { described_class.new(service_class_name: fake_service.name, url: url) }

it 'returns the Regexp unchanged' do
expect(subject.service_url).to equal(url)
end
end

context 'when registered with an Addressable::Template url' do
let(:url) { Addressable::Template.new('http://thingy.dev{/path*}') }

subject { described_class.new(service_class_name: fake_service.name, url: url) }

it 'returns the Addressable::Template unchanged' do
expect(subject.service_url).to equal(url)
end
end
end

describe '.path_prefix' do
Expand All @@ -111,5 +132,48 @@ def self.name
expect(subject.path_prefix).to eq '/welcome' # Ignores trailing '/'
end
end

context 'when registered with a Regexp url' do
subject { described_class.new(service_class_name: fake_service.name, url: %r{\Ahttp://thingy\.dev/api(/.*)?\z}) }

it 'defaults to an empty string so FakeServiceWrapper does not strip from PATH_INFO' do
expect(subject.path_prefix).to eq ''
end
end

context 'when registered with an Addressable::Template url' do
subject { described_class.new(service_class_name: fake_service.name, url: Addressable::Template.new('http://thingy.dev/api{/path*}')) }

it 'defaults to an empty string so FakeServiceWrapper does not strip from PATH_INFO' do
expect(subject.path_prefix).to eq ''
end
end

context 'when an explicit path_prefix is provided' do
it 'uses the override with a String url' do
with_env 'DUMMY_API_URL' => 'http://zombo.com' do
config = described_class.new(service_class_name: fake_service.name, path_prefix: '/api/v2')
expect(config.path_prefix).to eq '/api/v2'
end
end

it 'uses the override with a Regexp url' do
config = described_class.new(
service_class_name: fake_service.name,
url: %r{\Ahttp://thingy\.dev/api/v2(/.*)?\z},
path_prefix: '/api/v2',
)
expect(config.path_prefix).to eq '/api/v2'
end

it 'uses the override with an Addressable::Template url' do
config = described_class.new(
service_class_name: fake_service.name,
url: Addressable::Template.new('http://thingy.dev/api/v2{/path*}'),
path_prefix: '/api/v2',
)
expect(config.path_prefix).to eq '/api/v2'
end
end
end
end
51 changes: 51 additions & 0 deletions spec/webvalve/fake_service_spec.rb
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
require 'spec_helper'
require 'addressable/template'

RSpec.describe WebValve::FakeService do
subject do
Expand Down Expand Up @@ -66,5 +67,55 @@ def self.name
end
end
end

context 'when the service is registered with a Regexp url' do
it 'returns the result from the fake when the request URL matches the pattern' do
WebValve.register subject.name, url: %r{\Ahttp://dummy\.dev/.*\z}
WebValve.setup

expect(Net::HTTP.get(URI('http://dummy.dev/widgets'))).to eq({ result: 'it works!' }.to_json)
end

it 'does not strip a path prefix by default' do
nested = Class.new(described_class) do
def self.name
'FakeNested'
end

get '/api/v2/widgets' do
json({ result: 'nested!' })
end
end
stub_const('FakeNested', nested)

WebValve.register nested.name, url: %r{\Ahttp://nested\.dev/api/v2/.*\z}
WebValve.setup

expect(Net::HTTP.get(URI('http://nested.dev/api/v2/widgets'))).to eq({ result: 'nested!' }.to_json)
end

it 'strips the configured path_prefix when one is given' do
WebValve.register subject.name, url: %r{\Ahttp://dummy\.dev/api/v2/.*\z}, path_prefix: '/api/v2'
WebValve.setup

expect(Net::HTTP.get(URI('http://dummy.dev/api/v2/widgets'))).to eq({ result: 'it works!' }.to_json)
end
end

context 'when the service is registered with an Addressable::Template url' do
it 'returns the result from the fake when the request URL matches the template' do
WebValve.register subject.name, url: Addressable::Template.new('http://dummy.dev{/path*}')
WebValve.setup

expect(Net::HTTP.get(URI('http://dummy.dev/widgets'))).to eq({ result: 'it works!' }.to_json)
end

it 'strips the configured path_prefix when one is given' do
WebValve.register subject.name, url: Addressable::Template.new('http://dummy.dev/api/v2{/path*}'), path_prefix: '/api/v2'
WebValve.setup

expect(Net::HTTP.get(URI('http://dummy.dev/api/v2/widgets'))).to eq({ result: 'it works!' }.to_json)
end
end
end
end
9 changes: 9 additions & 0 deletions spec/webvalve/service_url_converter_spec.rb
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
require 'spec_helper'
require 'addressable/template'

RSpec.describe WebValve::ServiceUrlConverter do
let(:url) { "http://bar.com" }
Expand All @@ -19,6 +20,14 @@
end
end

context "with an Addressable::Template" do
let(:url) { Addressable::Template.new("http://foo.com{/path*}") }

it "returns the same object so WebMock can match against it directly" do
expect(subject.regexp).to equal(url)
end
end

context "with an empty url" do
let(:url) { "" }

Expand Down
Loading