webvalve 0.9.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 +7 -0
- data/LICENSE +21 -0
- data/README.md +195 -0
- data/Rakefile +22 -0
- data/lib/generators/webvalve/fake_service_generator.rb +70 -0
- data/lib/generators/webvalve/install_generator.rb +33 -0
- data/lib/tasks/webvalve_tasks.rake +0 -0
- data/lib/webvalve.rb +40 -0
- data/lib/webvalve/engine.rb +26 -0
- data/lib/webvalve/fake_service.rb +22 -0
- data/lib/webvalve/fake_service_config.rb +53 -0
- data/lib/webvalve/fake_service_wrapper.rb +18 -0
- data/lib/webvalve/instrumentation.rb +4 -0
- data/lib/webvalve/instrumentation/log_subscriber.rb +16 -0
- data/lib/webvalve/instrumentation/middleware.rb +24 -0
- data/lib/webvalve/manager.rb +76 -0
- data/lib/webvalve/rspec.rb +8 -0
- data/lib/webvalve/version.rb +3 -0
- data/spec/dummy/README.rdoc +28 -0
- data/spec/dummy/Rakefile +6 -0
- data/spec/dummy/app/assets/javascripts/application.js +13 -0
- data/spec/dummy/app/assets/stylesheets/application.css +15 -0
- data/spec/dummy/app/controllers/application_controller.rb +5 -0
- data/spec/dummy/app/helpers/application_helper.rb +2 -0
- data/spec/dummy/app/views/layouts/application.html.erb +13 -0
- data/spec/dummy/bin/bundle +3 -0
- data/spec/dummy/bin/rails +4 -0
- data/spec/dummy/bin/rake +4 -0
- data/spec/dummy/bin/setup +29 -0
- data/spec/dummy/config.ru +4 -0
- data/spec/dummy/config/application.rb +31 -0
- data/spec/dummy/config/boot.rb +5 -0
- data/spec/dummy/config/database.yml +25 -0
- data/spec/dummy/config/environment.rb +5 -0
- data/spec/dummy/config/environments/development.rb +41 -0
- data/spec/dummy/config/environments/production.rb +79 -0
- data/spec/dummy/config/environments/test.rb +42 -0
- data/spec/dummy/config/initializers/assets.rb +11 -0
- data/spec/dummy/config/initializers/backtrace_silencers.rb +7 -0
- data/spec/dummy/config/initializers/cookies_serializer.rb +3 -0
- data/spec/dummy/config/initializers/filter_parameter_logging.rb +4 -0
- data/spec/dummy/config/initializers/inflections.rb +16 -0
- data/spec/dummy/config/initializers/mime_types.rb +4 -0
- data/spec/dummy/config/initializers/session_store.rb +3 -0
- data/spec/dummy/config/initializers/wrap_parameters.rb +14 -0
- data/spec/dummy/config/locales/en.yml +23 -0
- data/spec/dummy/config/routes.rb +3 -0
- data/spec/dummy/config/secrets.yml +22 -0
- data/spec/dummy/db/test.sqlite3 +0 -0
- data/spec/dummy/log/development.log +0 -0
- data/spec/dummy/log/test.log +3938 -0
- data/spec/dummy/public/404.html +67 -0
- data/spec/dummy/public/422.html +67 -0
- data/spec/dummy/public/500.html +66 -0
- data/spec/dummy/public/favicon.ico +0 -0
- data/spec/examples.txt +30 -0
- data/spec/rails_helper.rb +14 -0
- data/spec/spec_helper.rb +22 -0
- data/spec/support/helpers.rb +24 -0
- data/spec/webvalve/fake_service_config_spec.rb +133 -0
- data/spec/webvalve/fake_service_spec.rb +47 -0
- data/spec/webvalve/manager_spec.rb +132 -0
- data/spec/webvalve_spec.rb +19 -0
- metadata +268 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 75f876084825a8cc70b8977e26afa6133f0191a0
|
4
|
+
data.tar.gz: acb351fdfc895185361b55e0e756d3488e2a2ea0
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 8ed9a0819c09b29f2bfe2fccf03d3234acaf1dec62ef29eeb5387894c2ab20bfa7b6daeeee684ef8b2e044096136fa85cfd7558bba17bcd0ad82ae5434f3b1fa
|
7
|
+
data.tar.gz: cf953ff845781e4320197f6a62c76f49b422514cdc73066ebded9fd2d07716865bb4183f346548b3a12ffa855e989d0435f51134f3e67f9c5a18820c8e822243
|
data/LICENSE
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
MIT License
|
2
|
+
|
3
|
+
Copyright (c) 2017 Betterment
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy of
|
6
|
+
this software and associated documentation files (the "Software"), to deal in
|
7
|
+
the Software without restriction, including without limitation the rights to
|
8
|
+
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
|
9
|
+
of the Software, and to permit persons to whom the Software is furnished to do
|
10
|
+
so, subject to the following conditions:
|
11
|
+
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
13
|
+
copies or substantial portions of the Software.
|
14
|
+
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
21
|
+
SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,195 @@
|
|
1
|
+
WebValve
|
2
|
+
========
|
3
|
+
|
4
|
+
[](https://travis-ci.com/Betterment/webvalve)
|
5
|
+
|
6
|
+
WebValve is a tool for defining and registering fake implementations of
|
7
|
+
HTTP services and toggling between the real services and the fake ones
|
8
|
+
in non-production environments.
|
9
|
+
|
10
|
+
This library is made possible by the incredible gems
|
11
|
+
[WebMock](https://github.com/bblimke/webmock) and
|
12
|
+
[Sinatra](https://github.com/sinatra/sinatra).
|
13
|
+
|
14
|
+
## Getting Started
|
15
|
+
|
16
|
+
### Network connections disabled by default
|
17
|
+
|
18
|
+
The default mode in development and test is to disallow all HTTP network
|
19
|
+
connections. This provides a clean foundation for consuming new
|
20
|
+
services. If you add a new service integration, the first thing that you
|
21
|
+
will be presented with when you attempt to hit it in development or test
|
22
|
+
is a warning that the requested URL was not mocked. This behavior comes
|
23
|
+
straight outta WebMock.
|
24
|
+
|
25
|
+
```ruby
|
26
|
+
irb(main):007:0> Net::HTTP.get(URI('http://bank.dev'))
|
27
|
+
|
28
|
+
WebMock::NetConnectNotAllowedError: Real HTTP connections are disabled. Unregistered request: GET http://bank.dev/ with headers {'Accept'=>'*/*', 'User-Agent'=>'Ruby'}
|
29
|
+
|
30
|
+
You can stub this request with the following snippet:
|
31
|
+
|
32
|
+
stub_request(:get, "http://bank.dev/").
|
33
|
+
with(:headers => {'Accept'=>'*/*', 'User-Agent'=>'Ruby'}).
|
34
|
+
to_return(:status => 200, :body => "", :headers => {})
|
35
|
+
|
36
|
+
============================================================
|
37
|
+
```
|
38
|
+
|
39
|
+
### Creating a config file
|
40
|
+
|
41
|
+
The first thing to do is run the install generator.
|
42
|
+
|
43
|
+
```
|
44
|
+
$ rails generate webvalve:install
|
45
|
+
```
|
46
|
+
|
47
|
+
This will drop a new file in your config directory.
|
48
|
+
|
49
|
+
```ruby
|
50
|
+
# config/webvalve.rb
|
51
|
+
|
52
|
+
# # register services
|
53
|
+
#
|
54
|
+
# WebValve.register FakeBank
|
55
|
+
# WebValve.register FakeExample, url: 'https://api.example.org'
|
56
|
+
#
|
57
|
+
# # whitelist urls
|
58
|
+
#
|
59
|
+
# WebValve.whitelist_url 'https://example.com'
|
60
|
+
```
|
61
|
+
|
62
|
+
### Registering a service
|
63
|
+
|
64
|
+
Next, you will want create a `FakeService` and register
|
65
|
+
it with the framework.
|
66
|
+
|
67
|
+
This can be accomplished by running the fake service generator:
|
68
|
+
|
69
|
+
```
|
70
|
+
$ rails generate webvalve:fake_service Bank
|
71
|
+
```
|
72
|
+
|
73
|
+
This will generate a file `fake_bank.rb` in the top-level folder
|
74
|
+
`webvalve`. This file will be autoloaded by Rails, so you can
|
75
|
+
tweak it as you go without having to restart your application.
|
76
|
+
|
77
|
+
```ruby
|
78
|
+
# webvalve/fake_bank.rb
|
79
|
+
|
80
|
+
class FakeBank < WebValve::FakeService
|
81
|
+
# # define your routes here
|
82
|
+
#
|
83
|
+
# get '/widgets' do
|
84
|
+
# json result: 'it works!'
|
85
|
+
# end
|
86
|
+
#
|
87
|
+
# # toggle this service on via ENV
|
88
|
+
#
|
89
|
+
# export BANK_ENABLED=true
|
90
|
+
end
|
91
|
+
```
|
92
|
+
|
93
|
+
And it will automatically register it in `config/webvalve.rb`
|
94
|
+
|
95
|
+
```ruby
|
96
|
+
# config/webvalve.rb
|
97
|
+
WebValve.register FakeBank
|
98
|
+
```
|
99
|
+
|
100
|
+
You'll also want to define an environment variable for the base url of
|
101
|
+
your service.
|
102
|
+
|
103
|
+
```bash
|
104
|
+
export BANK_API_URL='http://bank.dev'
|
105
|
+
```
|
106
|
+
|
107
|
+
That's it. Now when you hit your service again, it will route your
|
108
|
+
request into the `FakeBank` instance.
|
109
|
+
|
110
|
+
If you want to connect to the _actual_ service, all you have to do is
|
111
|
+
set another environment variable.
|
112
|
+
|
113
|
+
```bash
|
114
|
+
export BANK_ENABLED=true
|
115
|
+
```
|
116
|
+
|
117
|
+
You will have to restart your application after making this change
|
118
|
+
because service faking is an initialization time concern and not a
|
119
|
+
runtime concern.
|
120
|
+
|
121
|
+
## Configuring fakes in tests
|
122
|
+
|
123
|
+
In order to get WebValve fake servies working properly in tests, you
|
124
|
+
have to configure WebValve at the beginning of each test. For RSpec, there
|
125
|
+
is a configuration provided.
|
126
|
+
|
127
|
+
```ruby
|
128
|
+
# spec/rails_helper.rb
|
129
|
+
require 'webvalve/rspec'
|
130
|
+
```
|
131
|
+
|
132
|
+
For any other test framework, you will just want to set up a hook before
|
133
|
+
each test that will run `WebValve.setup`.
|
134
|
+
|
135
|
+
## Setting deterministic fake results in tests
|
136
|
+
|
137
|
+
Given a scenario where we want to mock a specific behavior for an
|
138
|
+
endpoint in a test, we can just use WebMock™.
|
139
|
+
|
140
|
+
```ruby
|
141
|
+
# in an rspec test...
|
142
|
+
|
143
|
+
it 'handles 404s by returning nil' do
|
144
|
+
fake_req = stub_request('http://bank.dev/some/url/1234')
|
145
|
+
.to_return(status: 404, body: nil)
|
146
|
+
|
147
|
+
response = Faraday.get 'http://bank.dev/some/url/1234'
|
148
|
+
expect(response.body).to be_nil
|
149
|
+
expect(fake_req).to have_been_requested
|
150
|
+
end
|
151
|
+
```
|
152
|
+
|
153
|
+
In other scenarios where we don't care about the specific response from
|
154
|
+
the endpoint, you can just lean into the behavior you've configured for
|
155
|
+
that route in your fake service.
|
156
|
+
|
157
|
+
## Overriding conventional defaults
|
158
|
+
|
159
|
+
Sometimes a service integration may want to use an unconventional name
|
160
|
+
for its environment variables. In that case, you can register the fake
|
161
|
+
service using the optional `url:` argument.
|
162
|
+
|
163
|
+
```ruby
|
164
|
+
# config/webvalve.rb
|
165
|
+
|
166
|
+
# using an ENV variable
|
167
|
+
WebValve.register FakeBank, url: ENV.fetch("SOME_CUSTOM_API_URL")
|
168
|
+
|
169
|
+
# or with a constant value
|
170
|
+
WebValve.register FakeBank, url: "https://some-service.com"
|
171
|
+
```
|
172
|
+
|
173
|
+
## What's in a `FakeService`?
|
174
|
+
|
175
|
+
The definition of `FakeService` is really simple. It's just a
|
176
|
+
`Sinatra::Base` class. It is wired up to support returning JSON
|
177
|
+
responses and it will raise when a route is requested but it is
|
178
|
+
not registered.
|
179
|
+
|
180
|
+
## How to Contribute
|
181
|
+
|
182
|
+
We would love for you to contribute! Anything that benefits the majority
|
183
|
+
of `webvalve` users—from a documentation fix to an entirely new
|
184
|
+
feature—is encouraged.
|
185
|
+
|
186
|
+
Before diving in, [check our issue
|
187
|
+
tracker](//github.com/Betterment/webvalve/issues) and consider
|
188
|
+
creating a new issue to get early feedback on your proposed change.
|
189
|
+
|
190
|
+
### Suggested Workflow
|
191
|
+
|
192
|
+
* Fork the project and create a new branch for your contribution.
|
193
|
+
* Write your contribution (and any applicable test coverage).
|
194
|
+
* Make sure all tests pass (`bundle exec rake`).
|
195
|
+
* Submit a pull request.
|
data/Rakefile
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
begin
|
2
|
+
require 'bundler/setup'
|
3
|
+
rescue LoadError
|
4
|
+
puts 'You must `gem install bundler` and `bundle install` to run rake tasks'
|
5
|
+
end
|
6
|
+
|
7
|
+
APP_RAKEFILE = File.expand_path("../spec/dummy/Rakefile", __FILE__)
|
8
|
+
load 'rails/tasks/engine.rake'
|
9
|
+
|
10
|
+
Bundler::GemHelper.install_tasks
|
11
|
+
|
12
|
+
if Rails.env.development? || Rails.env.test?
|
13
|
+
if defined? Dummy
|
14
|
+
require 'rspec/core'
|
15
|
+
require 'rspec/core/rake_task'
|
16
|
+
RSpec::Core::RakeTask.new(:spec)
|
17
|
+
task default: :spec
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
require 'yard'
|
22
|
+
YARD::Rake::YardocTask.new
|
@@ -0,0 +1,70 @@
|
|
1
|
+
require 'rails/generators/base'
|
2
|
+
|
3
|
+
module Webvalve
|
4
|
+
module Generators
|
5
|
+
class FakeServiceGenerator < Rails::Generators::Base
|
6
|
+
desc "Creates a WebValve fake service"
|
7
|
+
|
8
|
+
argument :service_name, required: true
|
9
|
+
|
10
|
+
def create_webvalve_fake_service_file
|
11
|
+
require_config!
|
12
|
+
create_fake_service_file
|
13
|
+
register_fake_in_config
|
14
|
+
end
|
15
|
+
|
16
|
+
private
|
17
|
+
|
18
|
+
def create_fake_service_file
|
19
|
+
create_file full_file_path, <<-FILE.strip_heredoc
|
20
|
+
class #{fake_service_class_name} < WebValve::FakeService
|
21
|
+
# # define your routes here
|
22
|
+
#
|
23
|
+
# get '/widgets' do
|
24
|
+
# json result: 'it works!'
|
25
|
+
# end
|
26
|
+
#
|
27
|
+
# # set the base url for this API via ENV
|
28
|
+
#
|
29
|
+
# export #{parsed_service_name.upcase}_API_URL='http://whatever.dev'
|
30
|
+
#
|
31
|
+
# # toggle this service on via ENV
|
32
|
+
#
|
33
|
+
# export #{parsed_service_name.upcase}_ENABLED=true
|
34
|
+
end
|
35
|
+
FILE
|
36
|
+
end
|
37
|
+
|
38
|
+
def register_fake_in_config
|
39
|
+
append_to_file config_file_path do <<~RUBY
|
40
|
+
WebValve.register #{fake_service_class_name}
|
41
|
+
RUBY
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
def require_config!
|
46
|
+
raise 'No WebValve configuration file found. Please run `rails generate webvalve:install` first' unless File.exists?(config_file_path)
|
47
|
+
end
|
48
|
+
|
49
|
+
def config_file_path
|
50
|
+
"config/webvalve.rb"
|
51
|
+
end
|
52
|
+
|
53
|
+
def full_file_path
|
54
|
+
"webvalve/#{fake_service_filename}.rb"
|
55
|
+
end
|
56
|
+
|
57
|
+
def fake_service_class_name
|
58
|
+
fake_service_filename.camelize
|
59
|
+
end
|
60
|
+
|
61
|
+
def fake_service_filename
|
62
|
+
"fake_#{parsed_service_name.underscore}"
|
63
|
+
end
|
64
|
+
|
65
|
+
def parsed_service_name
|
66
|
+
service_name.sub(/fake/i, '')
|
67
|
+
end
|
68
|
+
end
|
69
|
+
end
|
70
|
+
end
|
@@ -0,0 +1,33 @@
|
|
1
|
+
require 'rails/generators/base'
|
2
|
+
|
3
|
+
module Webvalve
|
4
|
+
module Generators
|
5
|
+
class InstallGenerator < Rails::Generators::Base
|
6
|
+
desc "Install WebValve"
|
7
|
+
|
8
|
+
def create_webvalve_config_file
|
9
|
+
create_config_file
|
10
|
+
create_file "webvalve/.keep", ""
|
11
|
+
end
|
12
|
+
|
13
|
+
private
|
14
|
+
|
15
|
+
def create_config_file
|
16
|
+
create_file full_file_path, <<-FILE.strip_heredoc
|
17
|
+
# # register services
|
18
|
+
#
|
19
|
+
# WebValve.register FakeThing
|
20
|
+
# WebValve.register FakeExample, url: 'https://api.example.org'
|
21
|
+
#
|
22
|
+
# # whitelist urls
|
23
|
+
#
|
24
|
+
# WebValve.whitelist_url 'https://example.com'
|
25
|
+
FILE
|
26
|
+
end
|
27
|
+
|
28
|
+
def full_file_path
|
29
|
+
"config/webvalve.rb"
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
File without changes
|
data/lib/webvalve.rb
ADDED
@@ -0,0 +1,40 @@
|
|
1
|
+
require 'set'
|
2
|
+
|
3
|
+
module WebValve
|
4
|
+
extend ActiveSupport::Autoload
|
5
|
+
autoload :FakeService, 'webvalve/fake_service'
|
6
|
+
autoload :FakeServiceWrapper, 'webvalve/fake_service_wrapper'
|
7
|
+
autoload :FakeServiceConfig, 'webvalve/fake_service_config'
|
8
|
+
autoload :Manager, 'webvalve/manager'
|
9
|
+
|
10
|
+
ENABLED_ENVS = %w(development test).freeze
|
11
|
+
|
12
|
+
class << self
|
13
|
+
# @!method setup
|
14
|
+
# @see WebValve::Manager#setup
|
15
|
+
# @!method register
|
16
|
+
# @see WebValve::Manager#register
|
17
|
+
# @!method whitelist_url
|
18
|
+
# @see WebValve::Manager#whitelist_url
|
19
|
+
# @!method reset
|
20
|
+
# @see WebValve::Manager#reset
|
21
|
+
delegate :setup, :register, :whitelist_url, :reset, to: :manager
|
22
|
+
|
23
|
+
def enabled?
|
24
|
+
Rails.env.in?(ENABLED_ENVS)
|
25
|
+
end
|
26
|
+
|
27
|
+
def config_paths
|
28
|
+
@config_paths ||= Set.new
|
29
|
+
end
|
30
|
+
|
31
|
+
private
|
32
|
+
|
33
|
+
def manager
|
34
|
+
WebValve::Manager.instance
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
require 'webvalve/instrumentation'
|
40
|
+
require 'webvalve/engine'
|
@@ -0,0 +1,26 @@
|
|
1
|
+
module WebValve
|
2
|
+
class Engine < ::Rails::Engine
|
3
|
+
isolate_namespace WebValve
|
4
|
+
|
5
|
+
if WebValve.enabled?
|
6
|
+
initializer "webvalve.set_autoload_paths", before: :set_autoload_paths do |app|
|
7
|
+
WebValve.config_paths << app.root
|
8
|
+
|
9
|
+
WebValve.config_paths.each do |root|
|
10
|
+
app.config.eager_load_paths << root.join('webvalve').to_s
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
initializer "webvalve.setup" do
|
15
|
+
WebValve.config_paths.each do |root|
|
16
|
+
path = root.join('config', 'webvalve.rb').to_s
|
17
|
+
load path if File.exist?(path)
|
18
|
+
end
|
19
|
+
|
20
|
+
config.after_initialize do
|
21
|
+
WebValve.setup
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
require 'sinatra/base'
|
2
|
+
require 'sinatra/json'
|
3
|
+
require 'webvalve/instrumentation/middleware'
|
4
|
+
|
5
|
+
module WebValve
|
6
|
+
class FakeService < Sinatra::Base
|
7
|
+
|
8
|
+
set :dump_errors, false
|
9
|
+
set :show_exceptions, false
|
10
|
+
set :raise_errors, true
|
11
|
+
|
12
|
+
configure do
|
13
|
+
use Instrumentation::Middleware
|
14
|
+
end
|
15
|
+
|
16
|
+
private
|
17
|
+
|
18
|
+
def route_missing
|
19
|
+
raise "route not defined for #{request.request_method} #{uri} in #{self.class.name}."
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|