rack-remote 1.0.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/.gitignore +21 -0
- data/.rspec +1 -0
- data/.travis.yml +7 -0
- data/Gemfile +13 -0
- data/LICENSE.txt +22 -0
- data/README.md +51 -0
- data/Rakefile +16 -0
- data/lib/rack/remote.rb +105 -0
- data/lib/rack/remote/version.rb +5 -0
- data/rack-remote.gemspec +25 -0
- data/spec/rack/remote_spec.rb +79 -0
- data/spec/spec_helper.rb +33 -0
- metadata +101 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 9ee084f59c76f39f41a7614c79e705f1fb5a72ae
|
4
|
+
data.tar.gz: 99063c7072a7088498a142199775ffc9344455f2
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 502915a20911dcf7c64c2db22dba774a92582c9da83ed672d0bb6d079cf543fe276f5b0ecf5d3d091b4b58da5e743bcea5d860569ac4cd3a9f5edbdd36688873
|
7
|
+
data.tar.gz: 31a421babc4c1a5b8ae7f3da06a362b4b7b8c59e80f3a5789ab32f1c1531a3060c3b55e3e6fa0076d7b7c9ce0c1a579c73b86202ad5af54926b7bf18be0b9d4e
|
data/.gitignore
ADDED
data/.rspec
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
--color --backtrace
|
data/.travis.yml
ADDED
data/Gemfile
ADDED
@@ -0,0 +1,13 @@
|
|
1
|
+
source 'https://rubygems.org'
|
2
|
+
|
3
|
+
# Development gems
|
4
|
+
#
|
5
|
+
gem 'rake'
|
6
|
+
gem 'rspec'
|
7
|
+
gem 'coveralls'
|
8
|
+
gem 'webmock', '~> 1.7'
|
9
|
+
gem 'rack-test'
|
10
|
+
|
11
|
+
# Specify your gem's dependencies in acfs.gemspec
|
12
|
+
gemroot = File.dirname File.absolute_path __FILE__
|
13
|
+
gemspec path: gemroot
|
data/LICENSE.txt
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
Copyright (c) 2013 Jan Graichen
|
2
|
+
|
3
|
+
MIT License
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
6
|
+
a copy of this software and associated documentation files (the
|
7
|
+
"Software"), to deal in the Software without restriction, including
|
8
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
9
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
10
|
+
permit persons to whom the Software is furnished to do so, subject to
|
11
|
+
the following conditions:
|
12
|
+
|
13
|
+
The above copyright notice and this permission notice shall be
|
14
|
+
included in all copies or substantial portions of the Software.
|
15
|
+
|
16
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
17
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
18
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
19
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
20
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
21
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
22
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,51 @@
|
|
1
|
+
# Rack::Remote
|
2
|
+
|
3
|
+
*Rack::Remote* is a small request intercepting Rack middleware to invoke
|
4
|
+
remote calls over HTTP. This can be used to invoke e.g. factories on
|
5
|
+
remote services for running integration tests on distributed applications.
|
6
|
+
|
7
|
+
## Installation
|
8
|
+
|
9
|
+
Add this line to your application's Gemfile:
|
10
|
+
|
11
|
+
gem 'rack-remote'
|
12
|
+
|
13
|
+
And then execute:
|
14
|
+
|
15
|
+
$ bundle
|
16
|
+
|
17
|
+
Or install it yourself as:
|
18
|
+
|
19
|
+
$ gem install rack-remote
|
20
|
+
|
21
|
+
## Usage
|
22
|
+
|
23
|
+
### On server/service side
|
24
|
+
|
25
|
+
Register available remote calls:
|
26
|
+
|
27
|
+
```ruby
|
28
|
+
Rack::Remote.register :factory_girl do |params, env, request|
|
29
|
+
FactoryGirl.create params[:factory]
|
30
|
+
end
|
31
|
+
```
|
32
|
+
|
33
|
+
Return value can be a Rack response array or any object that will be converted to JSON.
|
34
|
+
|
35
|
+
### On client side
|
36
|
+
|
37
|
+
```ruby
|
38
|
+
Rack::Remote.add :srv1, 'http://serv.domain.tld/proxyed/path'
|
39
|
+
Rack::Remote.invoke :srv1, :factory_girl, factory: 'user'
|
40
|
+
Rack::Remote.invoke 'http://serv.domain.tld/proxyed/path', :factory_girl, factory: 'user'
|
41
|
+
```
|
42
|
+
|
43
|
+
## Contributing
|
44
|
+
|
45
|
+
1. Fork it
|
46
|
+
2. Create your feature branch (`git checkout -b my-new-feature`)
|
47
|
+
4. Add specs
|
48
|
+
5. Add features
|
49
|
+
6. Commit your changes (`git commit -am 'Add some feature'`)
|
50
|
+
7. Push to the branch (`git push origin my-new-feature`)
|
51
|
+
8. Create new Pull Request
|
data/Rakefile
ADDED
@@ -0,0 +1,16 @@
|
|
1
|
+
require 'bundler/gem_tasks'
|
2
|
+
require 'rspec/core/rake_task'
|
3
|
+
|
4
|
+
RSpec::Core::RakeTask.new(:spec)
|
5
|
+
task :default => :spec
|
6
|
+
|
7
|
+
begin
|
8
|
+
require 'yard'
|
9
|
+
require 'yard/rake/yardoc_task'
|
10
|
+
|
11
|
+
YARD::Rake::YardocTask.new do |t|
|
12
|
+
t.files = %w(lib/**/*.rb)
|
13
|
+
t.options = %w(--output-dir doc/)
|
14
|
+
end
|
15
|
+
rescue LoadError
|
16
|
+
end
|
data/lib/rack/remote.rb
ADDED
@@ -0,0 +1,105 @@
|
|
1
|
+
require 'rack/remote/version'
|
2
|
+
require 'rack/request'
|
3
|
+
require 'multi_json'
|
4
|
+
|
5
|
+
module Rack
|
6
|
+
|
7
|
+
# Rack::Remote is a Rack middleware for intercepting calls
|
8
|
+
# and invoking remote calls. It can be used to call remote
|
9
|
+
# function for test instructions in distributed systems.
|
10
|
+
#
|
11
|
+
class Remote
|
12
|
+
def initialize(app)
|
13
|
+
@app = app
|
14
|
+
end
|
15
|
+
|
16
|
+
def call(env)
|
17
|
+
return @app.call(env) unless env['HTTP_X_RACK_REMOTE_CALL']
|
18
|
+
|
19
|
+
request = ::Rack::Request.new(env)
|
20
|
+
call = env['HTTP_X_RACK_REMOTE_CALL'].to_s
|
21
|
+
|
22
|
+
if (cb = self.class.calls[call])
|
23
|
+
response = cb.call(request.params, env, request)
|
24
|
+
if response.is_a?(Array) && response.size == 3
|
25
|
+
return response
|
26
|
+
else
|
27
|
+
[200, {'Content-Type' => 'application/json'}, StringIO.new(MultiJson.dump response) ]
|
28
|
+
end
|
29
|
+
else
|
30
|
+
[404, {'Content-Type' => 'application/json'}, StringIO.new('{"error":"remote call not defined"}') ]
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
class << self
|
35
|
+
# Register a new remote call. Used on server side to
|
36
|
+
# define available remote calls.
|
37
|
+
#
|
38
|
+
# @example
|
39
|
+
# Rack::Remote.register :factory_girl do |env, request|
|
40
|
+
# FactoryGirl.create request.params[:factory]
|
41
|
+
# end
|
42
|
+
#
|
43
|
+
# @params name [String, #to_s] Remote call name
|
44
|
+
#
|
45
|
+
def register(name, &block)
|
46
|
+
calls[name.to_s] = block
|
47
|
+
end
|
48
|
+
|
49
|
+
# Return hash with registered calls.
|
50
|
+
#
|
51
|
+
def calls
|
52
|
+
@calls ||= {}
|
53
|
+
end
|
54
|
+
|
55
|
+
# Removes all registered calls.
|
56
|
+
def clear
|
57
|
+
calls.clear
|
58
|
+
remotes.clear
|
59
|
+
end
|
60
|
+
|
61
|
+
# Add a new remote to be used in `invoke` by symbolic reference.
|
62
|
+
#
|
63
|
+
def add(name, options = {})
|
64
|
+
raise ArgumentError unless options[:url]
|
65
|
+
remotes[name.to_sym] = options
|
66
|
+
end
|
67
|
+
|
68
|
+
def remotes
|
69
|
+
@remotes ||= {}
|
70
|
+
end
|
71
|
+
|
72
|
+
# Invoke remote call.
|
73
|
+
#
|
74
|
+
# @param remote [Symbol, String, #to_s] Symbolic remote name or remote URL.
|
75
|
+
# @param call [String, #to_s] Remote call to invoke.
|
76
|
+
# @param params [Hash] Key-Value pairs that will be converted to json and sent to remote call.
|
77
|
+
# @param headers [Hash] Header added to request.
|
78
|
+
#
|
79
|
+
def invoke(remote, call, params = {}, headers = {})
|
80
|
+
remote = remotes[remote][:url] if remote.is_a? Symbol
|
81
|
+
uri = URI.parse remote.to_s
|
82
|
+
uri.path = '/' if uri.path.empty?
|
83
|
+
|
84
|
+
Net::HTTP.start uri.host, uri.port do |http|
|
85
|
+
request = Net::HTTP::Post.new uri.path
|
86
|
+
headers.each do |key, value|
|
87
|
+
request[key] = value.to_s
|
88
|
+
end
|
89
|
+
|
90
|
+
request['X-Rack-Remote-Call'] = call.to_s
|
91
|
+
request.form_data = params
|
92
|
+
|
93
|
+
response = http.request request
|
94
|
+
raise StandardError, "Rack Remote Error Response: #{response.code}: #{response.body}" if response.code.to_i != 200
|
95
|
+
|
96
|
+
if response['Content-Type'] == 'application/json'
|
97
|
+
MultiJson.load response.body
|
98
|
+
else
|
99
|
+
response.body
|
100
|
+
end
|
101
|
+
end
|
102
|
+
end
|
103
|
+
end
|
104
|
+
end
|
105
|
+
end
|
data/rack-remote.gemspec
ADDED
@@ -0,0 +1,25 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
lib = File.expand_path('../lib', __FILE__)
|
3
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
+
require 'rack/remote/version'
|
5
|
+
|
6
|
+
Gem::Specification.new do |spec|
|
7
|
+
spec.name = 'rack-remote'
|
8
|
+
spec.version = Rack::Remote::VERSION
|
9
|
+
spec.authors = ['Jan Graichen']
|
10
|
+
spec.email = %w(jg@altimos.de)
|
11
|
+
spec.summary = %q{Small request intercepting rack middleware to invoke remote calls over HTTP.}
|
12
|
+
spec.description = %q{Small request intercepting rack middleware to invoke remote calls over HTTP.}
|
13
|
+
spec.homepage = 'https://github.com/jgraichen/rack-remote'
|
14
|
+
spec.license = 'MIT'
|
15
|
+
|
16
|
+
spec.files = `git ls-files`.split($/)
|
17
|
+
spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
|
18
|
+
spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
|
19
|
+
spec.require_paths = %w(lib)
|
20
|
+
|
21
|
+
spec.add_dependency 'rack'
|
22
|
+
spec.add_dependency 'multi_json'
|
23
|
+
|
24
|
+
spec.add_development_dependency 'bundler'
|
25
|
+
end
|
@@ -0,0 +1,79 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Rack::Remote do
|
4
|
+
include Rack::Test::Methods
|
5
|
+
|
6
|
+
let(:inner_app) { -> (env) { [200, {'Content-Type' => 'text/plain'}, 'All good!'] } }
|
7
|
+
let(:app) { Rack::Remote.new(inner_app) }
|
8
|
+
let(:block) { -> (_, _, _) { } }
|
9
|
+
|
10
|
+
after(:each) { Rack::Remote.clear }
|
11
|
+
|
12
|
+
describe 'call' do
|
13
|
+
before { Rack::Remote.register :factory_girl, &block }
|
14
|
+
|
15
|
+
context 'with intercept call' do
|
16
|
+
let(:request) { -> { get '/', {}, {'HTTP_X_RACK_REMOTE_CALL' => 'factory_girl'} }}
|
17
|
+
|
18
|
+
it 'should invoke registered call' do
|
19
|
+
expect(block).to receive(:call)
|
20
|
+
request.call
|
21
|
+
end
|
22
|
+
|
23
|
+
it 'should not delegate request to inner app' do
|
24
|
+
expect(inner_app).to_not receive(:call)
|
25
|
+
request.call
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
context 'with non-rack-remote call' do
|
30
|
+
let(:request) { -> { get '/' }}
|
31
|
+
|
32
|
+
it 'should delegate request to inner app' do
|
33
|
+
expect(inner_app).to receive(:call).and_call_original
|
34
|
+
request.call
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
describe 'class' do
|
40
|
+
describe '#register' do
|
41
|
+
|
42
|
+
it 'should add callback' do
|
43
|
+
expect {
|
44
|
+
Rack::Remote.register :factory_girl, &block
|
45
|
+
}.to change{ Rack::Remote.calls.size }.from(0).to(1)
|
46
|
+
end
|
47
|
+
|
48
|
+
it 'should add given callback' do
|
49
|
+
Rack::Remote.register :factory_girl, &block
|
50
|
+
expect(Rack::Remote.calls.values.first).to equal block
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
describe '#add' do
|
55
|
+
subject { -> { Rack::Remote.add :users, url: 'http://users.example.org' } }
|
56
|
+
|
57
|
+
it 'should add a remote' do
|
58
|
+
expect { subject.call }.to change { Rack::Remote.remotes.size }.from(0).to(1)
|
59
|
+
end
|
60
|
+
|
61
|
+
it 'should add given remote' do
|
62
|
+
subject.call
|
63
|
+
expect(Rack::Remote.remotes[:users]).to eq url: 'http://users.example.org'
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
67
|
+
describe '#invoke' do
|
68
|
+
before { stub_request(:any, /users\.example\.org/).to_rack(app) }
|
69
|
+
before { Rack::Remote.register :factory_girl, &block }
|
70
|
+
before { Rack::Remote.add :users, url: 'http://users.example.org' }
|
71
|
+
|
72
|
+
it 'should invoke remote call' do
|
73
|
+
expect(block).to receive(:call).with({ 'param1' => 'val1' }, kind_of(Hash), kind_of(Rack::Request)).and_return({id: 1})
|
74
|
+
ret = Rack::Remote.invoke :users, :factory_girl, param1: 'val1'
|
75
|
+
expect(ret).to eq({'id' => 1})
|
76
|
+
end
|
77
|
+
end
|
78
|
+
end
|
79
|
+
end
|
data/spec/spec_helper.rb
ADDED
@@ -0,0 +1,33 @@
|
|
1
|
+
require 'coveralls'
|
2
|
+
Coveralls.wear! do
|
3
|
+
add_filter 'spec'
|
4
|
+
end
|
5
|
+
|
6
|
+
require 'rack/test'
|
7
|
+
require 'rack/remote'
|
8
|
+
require 'webmock/rspec'
|
9
|
+
|
10
|
+
Dir[File.expand_path('spec/support/**/*.rb')].each { |f| require f }
|
11
|
+
|
12
|
+
RSpec.configure do |config|
|
13
|
+
# ## Mock Framework
|
14
|
+
#
|
15
|
+
# If you prefer to use mocha, flexmock or RR, uncomment the appropriate line:
|
16
|
+
#
|
17
|
+
# config.mock_with :mocha
|
18
|
+
# config.mock_with :flexmock
|
19
|
+
# config.mock_with :rr
|
20
|
+
|
21
|
+
# Run specs in random order to surface order dependencies. If you find an
|
22
|
+
# order dependency and want to debug it, you can fix the order by providing
|
23
|
+
# the seed, which is printed after each run.
|
24
|
+
# --seed 1234
|
25
|
+
config.order = 'random'
|
26
|
+
|
27
|
+
config.expect_with :rspec do |c|
|
28
|
+
# Only allow expect syntax
|
29
|
+
c.syntax = :expect
|
30
|
+
end
|
31
|
+
|
32
|
+
config.include WebMock::API
|
33
|
+
end
|
metadata
ADDED
@@ -0,0 +1,101 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: rack-remote
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 1.0.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Jan Graichen
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2013-10-01 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: rack
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - '>='
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '0'
|
20
|
+
type: :runtime
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - '>='
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '0'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: multi_json
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - '>='
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '0'
|
34
|
+
type: :runtime
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - '>='
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '0'
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: bundler
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - '>='
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: '0'
|
48
|
+
type: :development
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - '>='
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '0'
|
55
|
+
description: Small request intercepting rack middleware to invoke remote calls over
|
56
|
+
HTTP.
|
57
|
+
email:
|
58
|
+
- jg@altimos.de
|
59
|
+
executables: []
|
60
|
+
extensions: []
|
61
|
+
extra_rdoc_files: []
|
62
|
+
files:
|
63
|
+
- .gitignore
|
64
|
+
- .rspec
|
65
|
+
- .travis.yml
|
66
|
+
- Gemfile
|
67
|
+
- LICENSE.txt
|
68
|
+
- README.md
|
69
|
+
- Rakefile
|
70
|
+
- lib/rack/remote.rb
|
71
|
+
- lib/rack/remote/version.rb
|
72
|
+
- rack-remote.gemspec
|
73
|
+
- spec/rack/remote_spec.rb
|
74
|
+
- spec/spec_helper.rb
|
75
|
+
homepage: https://github.com/jgraichen/rack-remote
|
76
|
+
licenses:
|
77
|
+
- MIT
|
78
|
+
metadata: {}
|
79
|
+
post_install_message:
|
80
|
+
rdoc_options: []
|
81
|
+
require_paths:
|
82
|
+
- lib
|
83
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
84
|
+
requirements:
|
85
|
+
- - '>='
|
86
|
+
- !ruby/object:Gem::Version
|
87
|
+
version: '0'
|
88
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
89
|
+
requirements:
|
90
|
+
- - '>='
|
91
|
+
- !ruby/object:Gem::Version
|
92
|
+
version: '0'
|
93
|
+
requirements: []
|
94
|
+
rubyforge_project:
|
95
|
+
rubygems_version: 2.0.3
|
96
|
+
signing_key:
|
97
|
+
specification_version: 4
|
98
|
+
summary: Small request intercepting rack middleware to invoke remote calls over HTTP.
|
99
|
+
test_files:
|
100
|
+
- spec/rack/remote_spec.rb
|
101
|
+
- spec/spec_helper.rb
|