agile-proxy 0.1.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/.bowerrc +3 -0
- data/.gitignore +8 -0
- data/.rspec +2 -0
- data/.rubocop.yml +36 -0
- data/.travis.yml +8 -0
- data/Gemfile +4 -0
- data/Gemfile.lock +267 -0
- data/Guardfile +20 -0
- data/LICENSE +22 -0
- data/README.md +93 -0
- data/Rakefile +13 -0
- data/agile-proxy.gemspec +50 -0
- data/assets/index.html +39 -0
- data/assets/ui/app/HttpFlexibleProxyApi.js +31 -0
- data/assets/ui/app/app.js +1 -0
- data/assets/ui/app/controller/Stubs.js +64 -0
- data/assets/ui/app/controller/main.js +12 -0
- data/assets/ui/app/directive/AppEnhancedFormElement.js +21 -0
- data/assets/ui/app/directive/AppFor.js +16 -0
- data/assets/ui/app/directive/AppResponseEditor.js +54 -0
- data/assets/ui/app/model/RequestSpec.js +6 -0
- data/assets/ui/app/routes.js +10 -0
- data/assets/ui/app/service/Dialog.js +49 -0
- data/assets/ui/app/service/DomId.js +10 -0
- data/assets/ui/app/service/Error.js +7 -0
- data/assets/ui/app/service/Stub.js +36 -0
- data/assets/ui/app/view/404.html +2 -0
- data/assets/ui/app/view/dialog/error.html +10 -0
- data/assets/ui/app/view/dialog/yesNo.html +8 -0
- data/assets/ui/app/view/responses/editForm.html +78 -0
- data/assets/ui/app/view/status.html +1 -0
- data/assets/ui/app/view/stubs.html +19 -0
- data/assets/ui/app/view/stubs/edit.html +58 -0
- data/assets/ui/css/main.css +3 -0
- data/bin/agile_proxy +113 -0
- data/bower.json +27 -0
- data/config.yml +6 -0
- data/db.yml +10 -0
- data/db/migrations/20140818110800_create_users.rb +9 -0
- data/db/migrations/20140818134700_create_applications.rb +10 -0
- data/db/migrations/20140818135200_create_request_specs.rb +13 -0
- data/db/migrations/20140821115300_create_responses.rb +14 -0
- data/db/migrations/20140823082900_add_method_to_request_specs.rb +7 -0
- data/db/migrations/20140823083900_rename_request_spec_columns.rb +8 -0
- data/db/migrations/20141031072100_add_url_type_to_request_specs.rb +8 -0
- data/db/migrations/20141105125600_add_conditions_to_request_specs.rb +7 -0
- data/db/migrations/20141106083100_add_username_and_password_to_applications.rb +8 -0
- data/db/migrations/20141119143800_add_record_to_applications.rb +7 -0
- data/db/migrations/20141119174300_create_recordings.rb +18 -0
- data/db/schema.rb +78 -0
- data/examples/README.md +1 -0
- data/examples/facebook_api.html +59 -0
- data/examples/tumblr_api.html +22 -0
- data/lib/agile_proxy.rb +8 -0
- data/lib/agile_proxy/api/applications.rb +77 -0
- data/lib/agile_proxy/api/recordings.rb +52 -0
- data/lib/agile_proxy/api/request_specs.rb +85 -0
- data/lib/agile_proxy/api/root.rb +41 -0
- data/lib/agile_proxy/config.rb +63 -0
- data/lib/agile_proxy/handlers/handler.rb +43 -0
- data/lib/agile_proxy/handlers/proxy_handler.rb +110 -0
- data/lib/agile_proxy/handlers/request_handler.rb +57 -0
- data/lib/agile_proxy/handlers/stub_handler.rb +113 -0
- data/lib/agile_proxy/mitm.crt +22 -0
- data/lib/agile_proxy/mitm.key +27 -0
- data/lib/agile_proxy/model/application.rb +20 -0
- data/lib/agile_proxy/model/recording.rb +16 -0
- data/lib/agile_proxy/model/request_spec.rb +47 -0
- data/lib/agile_proxy/model/response.rb +56 -0
- data/lib/agile_proxy/model/user.rb +17 -0
- data/lib/agile_proxy/proxy_connection.rb +113 -0
- data/lib/agile_proxy/route.rb +106 -0
- data/lib/agile_proxy/router.rb +99 -0
- data/lib/agile_proxy/server.rb +85 -0
- data/lib/agile_proxy/servers/api.rb +41 -0
- data/lib/agile_proxy/servers/request_spec.rb +30 -0
- data/lib/agile_proxy/version.rb +6 -0
- data/load_proxy.js +39 -0
- data/log/.gitkeep +0 -0
- data/spec/common_helper.rb +32 -0
- data/spec/fixtures/test-server.crt +15 -0
- data/spec/fixtures/test-server.key +15 -0
- data/spec/integration/helpers/request_spec_helper.rb +60 -0
- data/spec/integration/specs/lib/server_spec.rb +407 -0
- data/spec/integration_spec_helper.rb +18 -0
- data/spec/spec_helper.rb +39 -0
- data/spec/support/test_server.rb +75 -0
- data/spec/unit/agile_proxy/api/applications_spec.rb +102 -0
- data/spec/unit/agile_proxy/api/common_helper.rb +31 -0
- data/spec/unit/agile_proxy/api/recordings_spec.rb +115 -0
- data/spec/unit/agile_proxy/api/request_specs_spec.rb +159 -0
- data/spec/unit/agile_proxy/handlers/handler_spec.rb +8 -0
- data/spec/unit/agile_proxy/handlers/proxy_handler_spec.rb +138 -0
- data/spec/unit/agile_proxy/handlers/request_handler_spec.rb +55 -0
- data/spec/unit/agile_proxy/handlers/stub_handler_spec.rb +154 -0
- data/spec/unit/agile_proxy/model/recording_spec.rb +0 -0
- data/spec/unit/agile_proxy/model/request_spec_spec.rb +45 -0
- data/spec/unit/agile_proxy/model/response_spec.rb +38 -0
- data/spec/unit/agile_proxy/server_spec.rb +88 -0
- data/spec/unit/agile_proxy/servers/api_spec.rb +31 -0
- data/spec/unit/agile_proxy/servers/request_spec_spec.rb +32 -0
- metadata +618 -0
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
require 'spec_helper'
|
|
2
|
+
|
|
3
|
+
describe AgileProxy::Handler do
|
|
4
|
+
let(:handler) { Class.new { include AgileProxy::Handler }.new }
|
|
5
|
+
it '#handle_request raises an error if not overridden' do
|
|
6
|
+
expect(handler.call(nil)).to eql([500, {}, 'The handler has not overridden the handle_request method!'])
|
|
7
|
+
end
|
|
8
|
+
end
|
|
@@ -0,0 +1,138 @@
|
|
|
1
|
+
require 'spec_helper'
|
|
2
|
+
|
|
3
|
+
describe AgileProxy::ProxyHandler do
|
|
4
|
+
subject { AgileProxy::ProxyHandler.new }
|
|
5
|
+
let(:request) do
|
|
6
|
+
ActionDispatch::Request.new to_rack_env(
|
|
7
|
+
method: 'post',
|
|
8
|
+
url: 'http://example.test:8080/index?some=param',
|
|
9
|
+
headers: { 'Accept-Encoding' => 'gzip',
|
|
10
|
+
'Cache-Control' => 'no-cache' },
|
|
11
|
+
body: 'Some body'
|
|
12
|
+
)
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
def request_for_url(url)
|
|
16
|
+
ActionDispatch::Request.new to_rack_env(
|
|
17
|
+
method: 'post',
|
|
18
|
+
url: url,
|
|
19
|
+
headers: { 'Accept-Encoding' => 'gzip',
|
|
20
|
+
'Cache-Control' => 'no-cache' },
|
|
21
|
+
body: 'Some body'
|
|
22
|
+
)
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
describe '#handles_request?' do
|
|
26
|
+
context 'with non-whitelisted requests enabled' do
|
|
27
|
+
before do
|
|
28
|
+
expect(AgileProxy.config).to receive(:non_whitelisted_requests_disabled).and_return(false)
|
|
29
|
+
end
|
|
30
|
+
end
|
|
31
|
+
context 'with non-whitelisted requests disabled' do
|
|
32
|
+
before do
|
|
33
|
+
expect(AgileProxy.config).to receive(:non_whitelisted_requests_disabled).and_return(true)
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
it 'does not handle requests that are not white or black listed' do
|
|
37
|
+
expect(subject.send(:handles_request?, request)).to be_falsy
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
context 'a whitelisted host' do
|
|
41
|
+
context 'with a blacklisted path' do
|
|
42
|
+
before do
|
|
43
|
+
expect(AgileProxy.config).to receive(:path_blacklist) { ['/index'] }
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
it 'does not handle requests for blacklisted paths' do
|
|
47
|
+
req = request_for_url 'http://example.test:8080/index?some=param'
|
|
48
|
+
expect(subject.send(:handles_request?, req)).to be_falsy
|
|
49
|
+
end
|
|
50
|
+
end
|
|
51
|
+
context 'without a port' do
|
|
52
|
+
before do
|
|
53
|
+
expect(AgileProxy.config).to receive(:whitelist) { ['example.test'] }
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
it 'handles requests for the host without a port' do
|
|
57
|
+
req = request_for_url 'http://example.test'
|
|
58
|
+
expect(subject.send(:handles_request?, req)).to be_truthy
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
it 'handles requests for the host with a port' do
|
|
62
|
+
req = request_for_url 'http://example.test:8080'
|
|
63
|
+
expect(subject.send(:handles_request?, req)).to be_truthy
|
|
64
|
+
end
|
|
65
|
+
end
|
|
66
|
+
|
|
67
|
+
context 'with a port' do
|
|
68
|
+
before do
|
|
69
|
+
expect(AgileProxy.config).to receive(:whitelist) { ['example.test:8080'] }
|
|
70
|
+
end
|
|
71
|
+
|
|
72
|
+
it 'does not handle requests whitelisted for a specific port' do
|
|
73
|
+
req = request_for_url 'http://example.test'
|
|
74
|
+
expect(subject.send(:handles_request?, req)).to be_falsy
|
|
75
|
+
end
|
|
76
|
+
|
|
77
|
+
it 'handles requests for the host with a port' do
|
|
78
|
+
req = request_for_url 'http://example.test:8080'
|
|
79
|
+
expect(subject.send(:handles_request?, req)).to be_truthy
|
|
80
|
+
end
|
|
81
|
+
end
|
|
82
|
+
end
|
|
83
|
+
end
|
|
84
|
+
end
|
|
85
|
+
|
|
86
|
+
describe '#call' do
|
|
87
|
+
it 'returns nil if it does not handle the request' do
|
|
88
|
+
expect(subject).to receive(:handles_request?).and_return(false)
|
|
89
|
+
expect(subject.call(request.env)).to eql [404, {}, 'Not proxied']
|
|
90
|
+
end
|
|
91
|
+
|
|
92
|
+
context 'with a handled request' do
|
|
93
|
+
let(:response_header) do
|
|
94
|
+
header = Struct.new(:status, :raw).new
|
|
95
|
+
header.status = 200
|
|
96
|
+
header.raw = {}
|
|
97
|
+
header
|
|
98
|
+
end
|
|
99
|
+
|
|
100
|
+
let(:em_response) { double('response') }
|
|
101
|
+
let(:em_request) do
|
|
102
|
+
double('EM::HttpRequest', error: nil, response: em_response, response_header: response_header)
|
|
103
|
+
end
|
|
104
|
+
|
|
105
|
+
before do
|
|
106
|
+
allow(subject).to receive(:handles_request?).and_return(true)
|
|
107
|
+
allow(em_response).to receive(:force_encoding).and_return('The response body')
|
|
108
|
+
allow(EventMachine::HttpRequest).to receive(:new).and_return(em_request)
|
|
109
|
+
expect(em_request).to receive(:post).and_return(em_request)
|
|
110
|
+
end
|
|
111
|
+
|
|
112
|
+
it 'Should pass through a not allowed response' do
|
|
113
|
+
allow(response_header).to receive(:status).and_return(503)
|
|
114
|
+
expect(subject.call(request.env)).to eql [503, { 'Connection' => 'close' }, 'The response body']
|
|
115
|
+
end
|
|
116
|
+
it 'returns any error in the response' do
|
|
117
|
+
allow(em_request).to receive(:error).and_return('ERROR!')
|
|
118
|
+
expect(subject.call(request.env)).to eql([500, {}, "Request to #{request.url} failed with error: ERROR!"])
|
|
119
|
+
end
|
|
120
|
+
|
|
121
|
+
it 'returns a hashed response if the request succeeds' do
|
|
122
|
+
expect(subject.call(request.env)).to eql([200, { 'Connection' => 'close' }, 'The response body'])
|
|
123
|
+
end
|
|
124
|
+
|
|
125
|
+
it 'returns nil if both the error and response are for some reason nil' do
|
|
126
|
+
allow(em_request).to receive(:response).and_return(nil)
|
|
127
|
+
expect(subject.call(request.env)).to eql [404, {}, 'Not proxied']
|
|
128
|
+
end
|
|
129
|
+
|
|
130
|
+
it 'uses the timeouts defined in configuration' do
|
|
131
|
+
allow(AgileProxy.config).to receive(:proxied_request_inactivity_timeout).and_return(42)
|
|
132
|
+
allow(AgileProxy.config).to receive(:proxied_request_connect_timeout).and_return(24)
|
|
133
|
+
expect(EventMachine::HttpRequest).to receive(:new).with(request.url, inactivity_timeout: 42, connect_timeout: 24)
|
|
134
|
+
subject.call(request.env)
|
|
135
|
+
end
|
|
136
|
+
end
|
|
137
|
+
end
|
|
138
|
+
end
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
require 'spec_helper'
|
|
2
|
+
|
|
3
|
+
describe AgileProxy::RequestHandler do
|
|
4
|
+
subject { AgileProxy::RequestHandler.new }
|
|
5
|
+
|
|
6
|
+
it 'implements Handler' do
|
|
7
|
+
expect(subject).to be_a AgileProxy::Handler
|
|
8
|
+
end
|
|
9
|
+
|
|
10
|
+
context 'with stubbed handlers' do
|
|
11
|
+
let(:env) { to_rack_env(url: 'http://dummy.host.com/index.html') }
|
|
12
|
+
let(:stub_handler) { Class.new }
|
|
13
|
+
let(:proxy_handler) { Class.new }
|
|
14
|
+
let(:application_class) { Class.new }
|
|
15
|
+
let(:recordings_class) { Class.new }
|
|
16
|
+
let(:application) { double('Application', record_requests: false, recordings: recordings_class) }
|
|
17
|
+
|
|
18
|
+
before do
|
|
19
|
+
stub_const 'AgileProxy::StubHandler', stub_handler
|
|
20
|
+
stub_const 'AgileProxy::ProxyHandler', proxy_handler
|
|
21
|
+
stub_const 'AgileProxy::Application', application_class
|
|
22
|
+
allow(application_class).to receive(:where).and_return [application]
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
describe '#call' do
|
|
26
|
+
it 'returns error 500 if no handlers handle the request' do
|
|
27
|
+
expect_any_instance_of(stub_handler).to receive(:call).and_return [404, {}, 'It didnt work']
|
|
28
|
+
expect_any_instance_of(proxy_handler).to receive(:call).and_return [404, {}, 'It didnt work']
|
|
29
|
+
expect(subject.call(env)).to start_with [500, {}]
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
it 'returns 200 immediately if the stub handler handles the request' do
|
|
33
|
+
expect_any_instance_of(stub_handler).to receive(:call).with(env).and_return [200, {}, 'Some data']
|
|
34
|
+
expect_any_instance_of(proxy_handler).to_not receive(:call)
|
|
35
|
+
expect(subject.call(env)).to eql [200, {}, 'Some data']
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
it 'returns true if the proxy handler handles the request' do
|
|
39
|
+
expect_any_instance_of(stub_handler).to receive(:call).with(env).and_return [404, {}, 'Irrelevant']
|
|
40
|
+
expect_any_instance_of(proxy_handler).to receive(:call).with(env).and_return [200, {}, 'Some data']
|
|
41
|
+
expect(subject.call(env)).to eql [200, {}, 'Some data']
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
it 'Calls application.recordings.create if record_requests is true' do
|
|
45
|
+
allow(application).to receive(:record_requests).and_return true
|
|
46
|
+
expect(application.recordings).to receive(:create)
|
|
47
|
+
expect_any_instance_of(stub_handler).to receive(:call).with(env).and_return [200, {}, 'Some data']
|
|
48
|
+
expect_any_instance_of(proxy_handler).to_not receive(:call)
|
|
49
|
+
expect(subject.call(env)).to eql [200, {}, 'Some data']
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
end
|
|
55
|
+
end
|
|
@@ -0,0 +1,154 @@
|
|
|
1
|
+
require 'spec_helper'
|
|
2
|
+
|
|
3
|
+
describe AgileProxy::StubHandler do
|
|
4
|
+
let(:route_not_found_response) { [404, { 'X-Cascade' => 'pass' }, ['Not Found']] }
|
|
5
|
+
let(:handler) { AgileProxy::StubHandler.new }
|
|
6
|
+
let(:request) do
|
|
7
|
+
request_for(
|
|
8
|
+
method: 'GET',
|
|
9
|
+
url: 'http://example.test:8080/index?some=param',
|
|
10
|
+
headers: { 'Accept-Encoding' => 'gzip',
|
|
11
|
+
'Cache-Control' => 'no-cache' }
|
|
12
|
+
)
|
|
13
|
+
end
|
|
14
|
+
let(:application_class) { Class.new }
|
|
15
|
+
let(:request_spec_class) { Class.new }
|
|
16
|
+
let(:application) { application_class.new }
|
|
17
|
+
|
|
18
|
+
def request_for(options)
|
|
19
|
+
request = ActionDispatch::Request.new(to_rack_env(options))
|
|
20
|
+
request.params
|
|
21
|
+
request
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
before :each do
|
|
25
|
+
stub_const('AgileProxy::Application', application_class)
|
|
26
|
+
allow(application_class).to receive(:where).and_return application_class
|
|
27
|
+
allow(application_class).to receive(:first).and_return application
|
|
28
|
+
allow(application).to receive(:request_specs).and_return request_spec_class
|
|
29
|
+
end
|
|
30
|
+
describe 'With find_stub mocked' do
|
|
31
|
+
|
|
32
|
+
describe '#handle_request' do
|
|
33
|
+
it 'returns 404 if the request is not stubbed' do
|
|
34
|
+
stub = double('stub', http_method: 'GET', url: 'http://example.test:8080/index', conditions: {}, call: [404, {}, 'Not found'])
|
|
35
|
+
expect(request_spec_class).to receive(:where).and_return double('association', all: [stub])
|
|
36
|
+
expect(handler.call(to_rack_env(url: 'http://example.test:8080/index'))).to eql [404, {}, 'Not found']
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
it 'returns a response hash if the request is stubbed' do
|
|
40
|
+
stub = double('stub', http_method: 'GET', url: 'http://example.test:8080/index', conditions: {}, call: [200, { 'Content-Type' => 'application/json' }, 'Some content'])
|
|
41
|
+
expect(request_spec_class).to receive(:where).and_return double('association', all: [stub])
|
|
42
|
+
expect(handler.call(request.env)).to eql([200, { 'Content-Type' => 'application/json' }, 'Some content'])
|
|
43
|
+
end
|
|
44
|
+
it 'Passes on the correct parameters to the stub call method' do
|
|
45
|
+
stub = double('stub', http_method: 'GET', url: 'http://example.test:8080/index', conditions: {})
|
|
46
|
+
expect(request_spec_class).to receive(:where).and_return double('association', all: [stub])
|
|
47
|
+
body = request.body.read
|
|
48
|
+
request.body.rewind
|
|
49
|
+
expect(stub).to receive(:call).with({ some: 'param' }, { 'Accept-Encoding' => 'gzip', 'Cache-Control' => 'no-cache' }, body).and_return([200, { 'Content-Type' => 'application/json' }, 'Some Content'])
|
|
50
|
+
expect(handler.call(request.env)).to eql([200, { 'Content-Type' => 'application/json' }, 'Some Content'])
|
|
51
|
+
|
|
52
|
+
end
|
|
53
|
+
describe 'Routing patterns' do
|
|
54
|
+
describe 'With a simple GET match on the root of a domain' do
|
|
55
|
+
let(:request_stub) { double 'stub', url: 'http://example.com', http_method: 'GET', conditions: {} }
|
|
56
|
+
before :each do
|
|
57
|
+
allow(request_spec_class).to receive(:where).with('url LIKE ?', 'http://example.com%').and_return double('association', all: [request_stub])
|
|
58
|
+
allow(request_spec_class).to receive(:where).with('url LIKE ?', 'http://subdomain.example.com%').and_return double('association', all: [])
|
|
59
|
+
allow(request_stub).to receive(:call).and_return([200, {}, ''])
|
|
60
|
+
end
|
|
61
|
+
it 'Should match with a get on the same domain but not with a post or a different domain' do
|
|
62
|
+
expect(handler.call(request_for(url: 'http://example.com').env)).to eql([200, {}, ''])
|
|
63
|
+
expect(handler.call(request_for(url: 'http://example.com/').env)).to eql([200, {}, ''])
|
|
64
|
+
expect(handler.call(request_for(url: 'http://example.com/', method: 'POST').env)).to eql route_not_found_response
|
|
65
|
+
expect(handler.call(request_for(url: 'http://subdomain.example.com/').env)).to eql route_not_found_response
|
|
66
|
+
end
|
|
67
|
+
|
|
68
|
+
end
|
|
69
|
+
describe 'With a simple GET match inside a domain' do
|
|
70
|
+
let(:request_stub) { double 'stub for simple get inside a domain', url: 'http://example.com/index', http_method: 'GET', conditions: {} }
|
|
71
|
+
before :each do
|
|
72
|
+
allow(request_spec_class).to receive(:where).with('url LIKE ?', 'http://example.com%').and_return double('association', all: [request_stub])
|
|
73
|
+
allow(request_spec_class).to receive(:where).with('url LIKE ?', 'http://subdomain.example.com%').and_return double('association', all: [])
|
|
74
|
+
expect(request_stub).to receive(:call).and_return([200, {}, ''])
|
|
75
|
+
end
|
|
76
|
+
it 'Should match with a get on the same domain but not with a post or a different domain' do
|
|
77
|
+
expect(handler.call(request_for(url: 'http://example.com/index').env)).to eql([200, {}, ''])
|
|
78
|
+
expect(handler.call(request_for(method: 'POST', url: 'http://example.com/index').env)).to eql route_not_found_response
|
|
79
|
+
expect(handler.call(request_for(url: 'http://subdomain.example.com/index').env)).to eql route_not_found_response
|
|
80
|
+
expect(handler.call(request_for(url: 'http://example.com/').env)).to eql route_not_found_response
|
|
81
|
+
expect(handler.call(request_for(url: 'http://example.com').env)).to eql route_not_found_response
|
|
82
|
+
end
|
|
83
|
+
|
|
84
|
+
end
|
|
85
|
+
describe 'With a simple POST match on the root of a domain' do
|
|
86
|
+
let(:request_stub) { double 'stub', url: 'http://example.com', http_method: 'POST', conditions: {} }
|
|
87
|
+
before :each do
|
|
88
|
+
allow(request_spec_class).to receive(:where).with('url LIKE ?', 'http://example.com%').and_return double('association', all: [request_stub])
|
|
89
|
+
allow(request_spec_class).to receive(:where).with('url LIKE ?', 'http://subdomain.example.com%').and_return double('association', all: [])
|
|
90
|
+
allow(request_stub).to receive(:call).and_return([200, {}, ''])
|
|
91
|
+
end
|
|
92
|
+
it 'Should match with a post on the same domain but not with a get or a post on a different domain' do
|
|
93
|
+
expect(handler.call(request_for(method: 'POST', url: 'http://example.com').env)).to eql([200, {}, ''])
|
|
94
|
+
expect(handler.call(request_for(method: 'POST', url: 'http://example.com/').env)).to eql([200, {}, ''])
|
|
95
|
+
expect(handler.call(request_for(url: 'http://example.com/').env)).to eql route_not_found_response
|
|
96
|
+
expect(handler.call(request_for(method: 'POST', url: 'http://subdomain.example.com/').env)).to eql route_not_found_response
|
|
97
|
+
end
|
|
98
|
+
|
|
99
|
+
end
|
|
100
|
+
describe 'With a more complex route with conditions inside a domain' do
|
|
101
|
+
let(:request_stub) { double 'stub for complex route inside a domain', url: 'http://example.com/users/:user_id/index', http_method: 'GET', conditions: { user_id: '1' }.to_json }
|
|
102
|
+
before :each do
|
|
103
|
+
allow(request_spec_class).to receive(:where).with('url LIKE ?', 'http://example.com%').and_return double('association', all: [request_stub])
|
|
104
|
+
expect(request_stub).to receive(:call).and_return([200, {}, ''])
|
|
105
|
+
end
|
|
106
|
+
it 'Should match with a get on the same domain but not with a post or a different domain' do
|
|
107
|
+
expect(handler.call(request_for(url: 'http://example.com/users/1/index').env)).to eql([200, {}, ''])
|
|
108
|
+
expect(handler.call(request_for(url: 'http://example.com/users/2/index').env)).to eql route_not_found_response
|
|
109
|
+
expect(handler.call(request_for(method: 'POST', url: 'http://example.com/users/1/index').env)).to eql route_not_found_response
|
|
110
|
+
expect(handler.call(request_for(url: 'http://example.com/users/1/').env)).to eql route_not_found_response
|
|
111
|
+
expect(handler.call(request_for(url: 'http://example.com/users/1').env)).to eql route_not_found_response
|
|
112
|
+
end
|
|
113
|
+
end
|
|
114
|
+
describe 'With a more complex route with conditions including query params inside a domain' do
|
|
115
|
+
let(:request_stub) { double 'stub for complex route inside a domain', url: 'http://example.com/users/:user_id/index', http_method: 'GET', conditions: { user_id: '1', extra_1: 'extra_1', extra_2: 'extra_2' }.to_json }
|
|
116
|
+
before :each do
|
|
117
|
+
allow(request_spec_class).to receive(:where).with('url LIKE ?', 'http://example.com%').and_return double('association', all: [request_stub])
|
|
118
|
+
allow(request_stub).to receive(:call).and_return([200, {}, ''])
|
|
119
|
+
end
|
|
120
|
+
it 'Should match with a get on the same domain but not with a post or a different domain' do
|
|
121
|
+
expect(handler.call(request_for(url: 'http://example.com/users/1/index?extra_1=extra_1&extra_2=extra_2').env)).to eql([200, {}, ''])
|
|
122
|
+
expect(handler.call(request_for(url: 'http://example.com/users/1/index?some_other=2&extra_1=extra_1&extra_2=extra_2').env)).to eql([200, {}, ''])
|
|
123
|
+
expect(handler.call(request_for(url: 'http://example.com/users/2/index').env)).to eql route_not_found_response
|
|
124
|
+
expect(handler.call(request_for(method: 'POST', url: 'http://example.com/users/1/index').env)).to eql route_not_found_response
|
|
125
|
+
expect(handler.call(request_for(url: 'http://example.com/users/1/').env)).to eql route_not_found_response
|
|
126
|
+
expect(handler.call(request_for(url: 'http://example.com/users/1').env)).to eql route_not_found_response
|
|
127
|
+
end
|
|
128
|
+
end
|
|
129
|
+
|
|
130
|
+
# it 'should match regexps' do
|
|
131
|
+
# expect(AgileProxy::RequestSpec.new(:url => "http:\/\/.+\.com", :method => :post, :regex => true).
|
|
132
|
+
# matches?('POST', 'http://example.com')).to be
|
|
133
|
+
# expect(AgileProxy::RequestSpec.new(:url => "http:\/\/.+\.co\.uk", :method => :get, :regex => true).
|
|
134
|
+
# matches?('GET', 'http://example.com')).to_not be
|
|
135
|
+
# end
|
|
136
|
+
#
|
|
137
|
+
# it 'should match up to but not including query strings' do
|
|
138
|
+
# stub = AgileProxy::RequestSpec.new(:url => 'http://example.com/foo/bar/')
|
|
139
|
+
# expect(stub.matches?('GET', 'http://example.com/foo/')).to_not be
|
|
140
|
+
# expect(stub.matches?('GET', 'http://example.com/foo/bar/')).to be
|
|
141
|
+
# expect(stub.matches?('GET', 'http://example.com/foo/bar/?baz=bap')).to be
|
|
142
|
+
# end
|
|
143
|
+
# it 'Should match routes using pattern matching' do
|
|
144
|
+
# stub = AgileProxy::RequestSpec.new(:url => "http://example.com/users/:user_id/application/:application_id")
|
|
145
|
+
# expect(stub.matches?('GET', 'http://example.com/users/user_id/application/application_id')).to be
|
|
146
|
+
# expect(stub.matches?('GET', 'http://example.com/users/user_id/somethingelse/application_id')).not_to be
|
|
147
|
+
# end
|
|
148
|
+
|
|
149
|
+
end
|
|
150
|
+
end
|
|
151
|
+
|
|
152
|
+
end
|
|
153
|
+
|
|
154
|
+
end
|
|
File without changes
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
require 'agile_proxy/model/request_spec'
|
|
2
|
+
describe AgileProxy::RequestSpec do
|
|
3
|
+
let(:response_class) do
|
|
4
|
+
Class.new do
|
|
5
|
+
def initialize(config = {})
|
|
6
|
+
@config = config
|
|
7
|
+
end
|
|
8
|
+
attr_accessor :config
|
|
9
|
+
|
|
10
|
+
end
|
|
11
|
+
end
|
|
12
|
+
let(:mock_response) { response_class.new }
|
|
13
|
+
before :each do
|
|
14
|
+
stub_const('AgileProxy::Response', response_class)
|
|
15
|
+
end
|
|
16
|
+
it 'Should allow a nested response' do
|
|
17
|
+
subject.should accept_nested_attributes_for(:response)
|
|
18
|
+
end
|
|
19
|
+
it 'Should belong to a user' do
|
|
20
|
+
expect(subject).to belong_to(:user)
|
|
21
|
+
end
|
|
22
|
+
it 'Should belong to an application' do
|
|
23
|
+
expect(subject).to belong_to(:application)
|
|
24
|
+
end
|
|
25
|
+
it 'Should belong to a response' do
|
|
26
|
+
expect(subject).to belong_to(:response)
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
describe 'Interface for the stub handler' do
|
|
30
|
+
context '#call (without #and_return)' do
|
|
31
|
+
let(:subject) { AgileProxy::RequestSpec.new(url: 'url') }
|
|
32
|
+
it 'returns a 204 empty response' do
|
|
33
|
+
expect(subject).to receive(:response).and_return nil
|
|
34
|
+
expect(subject.call({}, {}, nil)).to eql [204, { 'Content-Type' => 'text/plain' }, '']
|
|
35
|
+
end
|
|
36
|
+
end
|
|
37
|
+
context '#call With conditions' do
|
|
38
|
+
let(:subject) { AgileProxy::RequestSpec.new(url: 'url', conditions: '{"a": 1, "b": 2}') }
|
|
39
|
+
it 'returns a the correct json' do
|
|
40
|
+
expect(subject.conditions_json).to eql('a' => 1, 'b' => 2)
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
end
|
|
44
|
+
end
|
|
45
|
+
end
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
require 'em-synchrony'
|
|
2
|
+
require 'spec_helper'
|
|
3
|
+
describe AgileProxy::Response do
|
|
4
|
+
it 'Should have many requests ' do
|
|
5
|
+
expect(subject).to have_many(:request_specs)
|
|
6
|
+
end
|
|
7
|
+
it 'Should serialize the headers in json format' do
|
|
8
|
+
expect(subject).to serialize(:headers)
|
|
9
|
+
end
|
|
10
|
+
describe 'With a configured delay' do
|
|
11
|
+
before :each do
|
|
12
|
+
subject.delay = 0.5
|
|
13
|
+
subject.content = 'Test'
|
|
14
|
+
subject.content_type = 'text/plain'
|
|
15
|
+
end
|
|
16
|
+
it 'Should respond with a delay using the Em::Synchrony.sleep method' do
|
|
17
|
+
expect(EventMachine::Synchrony).to receive(:sleep).with(0.5)
|
|
18
|
+
expect(subject.to_rack({}, {}, '')).to eql([200, { 'Content-Type' => 'text/plain' }, 'Test'])
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
end
|
|
22
|
+
describe 'Using templates' do
|
|
23
|
+
describe 'Using text' do
|
|
24
|
+
before :each do
|
|
25
|
+
subject.is_template = true
|
|
26
|
+
subject.content = 'Hello {{name}}'
|
|
27
|
+
subject.content_type = 'text/plain'
|
|
28
|
+
end
|
|
29
|
+
it 'Should pass the params to the template and the output should be correct' do
|
|
30
|
+
expect(subject.to_rack({ name: 'World' }, {}, '')).to eql([200, { 'Content-Type' => 'text/plain' }, 'Hello World'])
|
|
31
|
+
end
|
|
32
|
+
it 'Should deal with if a parameter is missing' do
|
|
33
|
+
expect(subject.to_rack({}, {}, '')).to eql([500, { 'Content-Type' => 'text/plain' }, "Missing var or method 'name' in data."])
|
|
34
|
+
end
|
|
35
|
+
end
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
end
|