agile-proxy-jruby 0.1.25-jruby
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 +10 -0
- data/.rspec +2 -0
- data/.rubocop.yml +36 -0
- data/.travis.yml +10 -0
- data/Gemfile +4 -0
- data/Guardfile +20 -0
- data/LICENSE +22 -0
- data/README.md +131 -0
- data/Rakefile +15 -0
- data/agile-proxy.gemspec +60 -0
- data/assets/index.html +39 -0
- data/assets/ui/app/AgileProxyApi.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 +11 -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 +4 -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/migrations/20150221152500_add_record_requests_to_request_specs.rb +7 -0
- data/db/schema.rb +78 -0
- data/db/seed.rb +26 -0
- data/echo_server.rb +19 -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_spec_recordings.rb +52 -0
- data/lib/agile_proxy/api/request_specs.rb +86 -0
- data/lib/agile_proxy/api/root.rb +45 -0
- data/lib/agile_proxy/cli.rb +116 -0
- data/lib/agile_proxy/config.rb +66 -0
- data/lib/agile_proxy/handlers/handler.rb +43 -0
- data/lib/agile_proxy/handlers/proxy_handler.rb +111 -0
- data/lib/agile_proxy/handlers/request_handler.rb +75 -0
- data/lib/agile_proxy/handlers/stub_handler.rb +146 -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 +17 -0
- data/lib/agile_proxy/model/request_spec.rb +48 -0
- data/lib/agile_proxy/model/response.rb +51 -0
- data/lib/agile_proxy/model/user.rb +17 -0
- data/lib/agile_proxy/proxy_connection.rb +112 -0
- data/lib/agile_proxy/rack/get_only_cache.rb +30 -0
- data/lib/agile_proxy/route.rb +106 -0
- data/lib/agile_proxy/router.rb +99 -0
- data/lib/agile_proxy/server.rb +119 -0
- data/lib/agile_proxy/servers/api.rb +40 -0
- data/lib/agile_proxy/servers/request_spec.rb +40 -0
- data/lib/agile_proxy/servers/request_spec_direct.rb +35 -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/example_static_file.html +1 -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 +84 -0
- data/spec/integration/specs/lib/server_spec.rb +474 -0
- data/spec/integration_spec_helper.rb +16 -0
- data/spec/spec_helper.rb +39 -0
- data/spec/support/test_server.rb +105 -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_spec_recordings_spec.rb +119 -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 +76 -0
- data/spec/unit/agile_proxy/handlers/stub_handler_spec.rb +177 -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 +91 -0
- data/spec/unit/agile_proxy/servers/api_spec.rb +35 -0
- data/spec/unit/agile_proxy/servers/request_spec_direct_spec.rb +51 -0
- data/spec/unit/agile_proxy/servers/request_spec_spec.rb +35 -0
- metadata +736 -0
@@ -0,0 +1,40 @@
|
|
1
|
+
require 'rack'
|
2
|
+
require 'grape'
|
3
|
+
require 'goliath/api'
|
4
|
+
require 'goliath/runner'
|
5
|
+
require 'agile_proxy/api/root'
|
6
|
+
|
7
|
+
module AgileProxy
|
8
|
+
module Servers
|
9
|
+
#
|
10
|
+
# The API Server
|
11
|
+
#
|
12
|
+
# This server is a RACK server responsible for providing access to the system
|
13
|
+
# using REST requests.
|
14
|
+
# This allows remote programming of the proxy using either a client adapter or the built in user interface
|
15
|
+
module Api
|
16
|
+
ROOT = File.expand_path '../../../', File.dirname(__FILE__)
|
17
|
+
class << self
|
18
|
+
#
|
19
|
+
# Starts the webserver on the given host and port
|
20
|
+
# @param webserver_host [String] The host for the server to run on
|
21
|
+
# @param webserver_port [Integer] The port for the server to run on
|
22
|
+
def start(webserver_host, webserver_port)
|
23
|
+
#
|
24
|
+
# The API runner
|
25
|
+
runner = ::Goliath::Runner.new([], nil)
|
26
|
+
runner.address = webserver_host
|
27
|
+
runner.port = webserver_port
|
28
|
+
runner.app = ::Goliath::Rack::Builder.app do
|
29
|
+
use ::Rack::Static, root: File.join(ROOT, 'assets'), urls: ['/ui'], index: 'index.html'
|
30
|
+
map '/api' do
|
31
|
+
run ::AgileProxy::Api::Root.new
|
32
|
+
end
|
33
|
+
end
|
34
|
+
runner.run
|
35
|
+
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
@@ -0,0 +1,40 @@
|
|
1
|
+
require 'eventmachine'
|
2
|
+
require 'goliath/api'
|
3
|
+
require 'goliath/proxy'
|
4
|
+
module AgileProxy
|
5
|
+
module Servers
|
6
|
+
#
|
7
|
+
# The 'Request Spec' server
|
8
|
+
# This server is responsible for handling or passing through a request, depending
|
9
|
+
# on if it has a matching 'Request Specification'
|
10
|
+
class RequestSpec
|
11
|
+
|
12
|
+
# Starts the server
|
13
|
+
def self.start(options = {})
|
14
|
+
new(options).start
|
15
|
+
end
|
16
|
+
def initialize(options = {})
|
17
|
+
@request_handler = AgileProxy::RequestHandler.new enable_cache: options[:enable_cache]
|
18
|
+
end
|
19
|
+
# Starts the server
|
20
|
+
def start
|
21
|
+
#
|
22
|
+
# The API runner
|
23
|
+
runner = ::Goliath::Proxy::Runner.new([], nil)
|
24
|
+
runner.address = '127.0.0.1'
|
25
|
+
runner.port = AgileProxy.config.proxy_port
|
26
|
+
app = @request_handler
|
27
|
+
runner.app = app
|
28
|
+
runner.run
|
29
|
+
self
|
30
|
+
|
31
|
+
end
|
32
|
+
# The port the server is running on
|
33
|
+
# @return [Integer] The port the server is running on
|
34
|
+
def port
|
35
|
+
return AgileProxy.config.proxy_port
|
36
|
+
end
|
37
|
+
private
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
@@ -0,0 +1,35 @@
|
|
1
|
+
require 'rack'
|
2
|
+
require 'goliath/api'
|
3
|
+
require 'goliath/runner'
|
4
|
+
module AgileProxy
|
5
|
+
module Servers
|
6
|
+
#
|
7
|
+
# The API Server
|
8
|
+
#
|
9
|
+
# This server is a RACK server responsible for providing access to the system
|
10
|
+
# using REST requests.
|
11
|
+
# This allows remote programming of the proxy using either a client adapter or the built in user interface
|
12
|
+
module RequestSpecDirect
|
13
|
+
ROOT = Dir.pwd
|
14
|
+
class << self
|
15
|
+
#
|
16
|
+
# Starts the server on the given host and port
|
17
|
+
# @param server_host [String] The host for the server to run on
|
18
|
+
# @param server_port [Integer] The port for the server to run on
|
19
|
+
def start(server_host, server_port, static_dirs = [])
|
20
|
+
|
21
|
+
runner = ::Goliath::Runner.new([], nil)
|
22
|
+
runner.address = server_host
|
23
|
+
runner.port = server_port
|
24
|
+
notFoundApp = -> {[404, {}, 'Not Found']}
|
25
|
+
runner.app = ::Goliath::Rack::Builder.app do
|
26
|
+
map '/' do
|
27
|
+
run ::Rack::Cascade.new([::Rack::Static.new(notFoundApp, root: ROOT, urls: ['']), ::AgileProxy::StubHandler.new])
|
28
|
+
end
|
29
|
+
end
|
30
|
+
runner.run
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
data/load_proxy.js
ADDED
@@ -0,0 +1,39 @@
|
|
1
|
+
var proxy, contracts;
|
2
|
+
proxy = require('flexible_proxy_client');
|
3
|
+
debugger;
|
4
|
+
contracts = [];
|
5
|
+
for (i=0; i< 100; i=i+1) {
|
6
|
+
contracts.push({
|
7
|
+
"created_at": "2014-10-21T09:30:45.217Z",
|
8
|
+
"customer_company_id": "1",
|
9
|
+
"customer_contact_id": "1",
|
10
|
+
"daily_rate_currency": "GBP",
|
11
|
+
"daily_rate_pennies": 10000,
|
12
|
+
"duration": 2678400,
|
13
|
+
"end_date": "2013-01-31T00:00:00.000Z",
|
14
|
+
"fq_name": "My First Contract",
|
15
|
+
"id": "544627c51fedb0383c0000" + i,
|
16
|
+
"name": "My Contract No " + (i + 1),
|
17
|
+
"owner_company_id": "1",
|
18
|
+
"owner_id": "544627c51fedb0383c000092",
|
19
|
+
"start_date": "2013-01-01T00:00:00.000Z",
|
20
|
+
"status": "accepted",
|
21
|
+
"supplier_company_id": "1",
|
22
|
+
"updated_at": "2014-10-21T09:30:45.217Z",
|
23
|
+
"value_currency": "GBP",
|
24
|
+
"value_pennies": 100000,
|
25
|
+
"notes": [
|
26
|
+
|
27
|
+
]
|
28
|
+
});
|
29
|
+
}
|
30
|
+
proxy.define([
|
31
|
+
proxy.stub('http://localhost:9000/api/v1/contracts.json').andReturn({json: {
|
32
|
+
"contracts": contracts,
|
33
|
+
"total": contracts.length,
|
34
|
+
"success": true
|
35
|
+
}}),
|
36
|
+
proxy.stub('http://localhost:35729/livereload.js').andReturn({
|
37
|
+
json: {}
|
38
|
+
})
|
39
|
+
], function () {console.log("YEP")});
|
data/log/.gitkeep
ADDED
File without changes
|
@@ -0,0 +1,32 @@
|
|
1
|
+
module AgileProxy
|
2
|
+
module Test
|
3
|
+
# Common helpers for the test suite
|
4
|
+
module Common
|
5
|
+
def to_rack_env(opts = {})
|
6
|
+
fake_input_buffer = StringIO.new(opts[:body] || '')
|
7
|
+
fake_error_buffer = StringIO.new
|
8
|
+
url_parsed = URI.parse(opts[:url])
|
9
|
+
env = {
|
10
|
+
'rack.input' => ::Rack::Lint::InputWrapper.new(fake_input_buffer),
|
11
|
+
'rack.errors' => ::Rack::Lint::ErrorWrapper.new(fake_error_buffer),
|
12
|
+
'REQUEST_METHOD' => (opts[:method] || 'GET').upcase,
|
13
|
+
'REQUEST_PATH' => url_parsed.path,
|
14
|
+
'PATH_INFO' => url_parsed.path,
|
15
|
+
'QUERY_STRING' => url_parsed.query || '',
|
16
|
+
'REQUEST_URI' => url_parsed.path + (url_parsed.query.nil? ? '' : url_parsed.query),
|
17
|
+
'rack.url_scheme' => url_parsed.scheme,
|
18
|
+
'CONTENT_LENGTH' => (opts[:body] || '').length,
|
19
|
+
'SERVER_NAME' => url_parsed.host,
|
20
|
+
'SERVER_PORT' => url_parsed.port
|
21
|
+
}
|
22
|
+
(opts[:headers] || {}).each do |name, value|
|
23
|
+
converted_name = 'HTTP_' + (name.gsub(/-/, '_').upcase)
|
24
|
+
env[converted_name] = value
|
25
|
+
end
|
26
|
+
env['CONTENT_TYPE'] = env.delete('HTTP_CONTENT_TYPE') if env.key?('HTTP_CONTENT_TYPE')
|
27
|
+
env['CONTENT_LENGTH'] = env.delete('HTTP_CONTENT_LENGTH') if env.key?('HTTP_CONTENT_LENGTH')
|
28
|
+
env
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
@@ -0,0 +1 @@
|
|
1
|
+
Hello World
|
@@ -0,0 +1,15 @@
|
|
1
|
+
-----BEGIN CERTIFICATE-----
|
2
|
+
MIICazCCAdQCCQD9MxXmqmRKtTANBgkqhkiG9w0BAQUFADB6MQswCQYDVQQGEwJV
|
3
|
+
UzELMAkGA1UECBMCQ0ExITAfBgNVBAoTGEludGVybmV0IFdpZGdpdHMgUHR5IEx0
|
4
|
+
ZDEWMBQGA1UEAxMNUHVmZmluZyBCaWxseTEjMCEGCSqGSIb3DQEJARYUb2xseS5z
|
5
|
+
bWl0aEBnbWFpbC5jb20wHhcNMTIxMDA0MDgwNzMxWhcNMTIxMTAzMDgwNzMxWjB6
|
6
|
+
MQswCQYDVQQGEwJVUzELMAkGA1UECBMCQ0ExITAfBgNVBAoTGEludGVybmV0IFdp
|
7
|
+
ZGdpdHMgUHR5IEx0ZDEWMBQGA1UEAxMNUHVmZmluZyBCaWxseTEjMCEGCSqGSIb3
|
8
|
+
DQEJARYUb2xseS5zbWl0aEBnbWFpbC5jb20wgZ8wDQYJKoZIhvcNAQEBBQADgY0A
|
9
|
+
MIGJAoGBAKsUa8bzUeTfC05JFwjBXnD+nBlil5aVTDOB719WJkiq1eDY5WWBaMhk
|
10
|
+
OqlZkNhl1rg7LmG/0NhBBUdICYTblNRXzhEfaejqOIGQ3FZMR3W/b87cBp4S+8b/
|
11
|
+
q9xJPSUgFvQUzX4v+2+//wdiO8qPioinDdRG9RhxwNvS34bqJqpfAgMBAAEwDQYJ
|
12
|
+
KoZIhvcNAQEFBQADgYEADnHq4MP+LgTdp4+ycyearUZh4uhAPzxYXTGDirkkFFQ4
|
13
|
+
YA2QT0zXgPq1JmrZwV5Wo1wKoIq8LtfeYoDou0VDKtZ6Up13c98R+1yuQE2kgNoG
|
14
|
+
9VGn/2la4mvLpj+9Zt8wfNxibFi+ajZ7/zsebI7UM+pW0a3SDowDeU0nVPAmDRM=
|
15
|
+
-----END CERTIFICATE-----
|
@@ -0,0 +1,15 @@
|
|
1
|
+
-----BEGIN RSA PRIVATE KEY-----
|
2
|
+
MIICXgIBAAKBgQCrFGvG81Hk3wtOSRcIwV5w/pwZYpeWlUwzge9fViZIqtXg2OVl
|
3
|
+
gWjIZDqpWZDYZda4Oy5hv9DYQQVHSAmE25TUV84RH2no6jiBkNxWTEd1v2/O3Aae
|
4
|
+
EvvG/6vcST0lIBb0FM1+L/tvv/8HYjvKj4qIpw3URvUYccDb0t+G6iaqXwIDAQAB
|
5
|
+
AoGBAJccJ4KIYzqUZGkWmBjsq92Elx64/gpM/wyz5VpBPvmKo/XBvwWkg4gVN9dj
|
6
|
+
vFPXyAvcgkBm7DJHZEEs+PN3/IEMyLHWVA+C+C3AHisR/E2yl/AyD9oX8F0KDu+Q
|
7
|
+
8bnsL1rFL5zP1saw+QiyofQ13HKtCOj8zjhAUCyZl1NBdiqxAkEA2PNxBHFBSnPU
|
8
|
+
L6+PiCvDOJcbqrHQa5kYcS312SNqX/VQ9BtIJfIQ7QA/ueKIUd40OfNBc/jiOC1x
|
9
|
+
mlSwlsLnFwJBAMnfWagBvlinIwXw4yhAgsqt012gOzPIHCM7FWipJPbCm9LtJykE
|
10
|
+
dGuA06TRE2ZKQq+Oh2yomNni4/LfPVQ6Y/kCQHkej/4W7IiQWem1bcBsDjVNx1ho
|
11
|
+
pR8s/YRSUGrFZuHjpyphAMqOdfyaovk4CzsJfsbLk8MXM9SBKmcq2NuSPEkCQQCM
|
12
|
+
MvTmTIewtCsLtjdcvijXsA9KR7y2ArUf9qmwrUABrDhiLdfzkad0/dx+68FIWiyk
|
13
|
+
Fh2RZin5sKzVARtrwr2pAkEAgIDCCl3YC7Jk5GOm1xVjb999hZSyasOasiVsAafa
|
14
|
+
4UzoA4HlDjTWEROObX8ijbsWRU16/yotbWXDa9XXxnDV3A==
|
15
|
+
-----END RSA PRIVATE KEY-----
|
@@ -0,0 +1,84 @@
|
|
1
|
+
require 'rest_client'
|
2
|
+
module AgileProxy
|
3
|
+
module Test
|
4
|
+
module Integration
|
5
|
+
# A helper for 'request spec' integration tests
|
6
|
+
module RequestSpecHelper
|
7
|
+
class Spec
|
8
|
+
attr_accessor :url, :name, :body
|
9
|
+
def self.for(url, name, body)
|
10
|
+
obj = new
|
11
|
+
obj.url=url + '/'
|
12
|
+
obj.name = name
|
13
|
+
obj.body = body
|
14
|
+
obj.body = obj.body.with_indifferent_access if obj.body.is_a? Hash
|
15
|
+
obj
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
def load_small_set_of_request_specs(options = {})
|
20
|
+
let(:recordings_resource) { RestClient::Resource.new "http://localhost:#{api_port}/api/v1/users/1/applications/#{@recording_application_id}/recordings", headers: { content_type: 'application/json' } }
|
21
|
+
before :context do
|
22
|
+
@stubs_with_recordings = []
|
23
|
+
def configure_applications
|
24
|
+
application_resource.delete # Delete all applications
|
25
|
+
@non_recording_application_id = JSON.parse(application_resource.post user_id: 1, name: 'Non recording app', username: 'anonymous', password: 'password')['id']
|
26
|
+
@recording_application_id = JSON.parse(application_resource.post user_id: 1, name: 'Recording app', username: 'recording', password: 'password', record_requests: true)['id']
|
27
|
+
@direct_application_id = JSON.parse(application_resource.post user_id: 1, name: 'Direct app', username: nil, password: nil, record_requests: false)['id']
|
28
|
+
end
|
29
|
+
|
30
|
+
def application_resource
|
31
|
+
@__application_resource ||= RestClient::Resource.new "http://localhost:#{api_port}/api/v1/users/1/applications", headers: { content_type: 'application/json' }
|
32
|
+
end
|
33
|
+
|
34
|
+
def create_request_spec(attrs)
|
35
|
+
non_recording_resource.post ActiveSupport::JSON.encode attrs
|
36
|
+
recording_response = JSON.parse recording_resource.post(ActiveSupport::JSON.encode attrs).body
|
37
|
+
direct_resource.post ActiveSupport::JSON.encode attrs
|
38
|
+
recording_response
|
39
|
+
end
|
40
|
+
|
41
|
+
def non_recording_resource
|
42
|
+
@__non_recording_resource ||= RestClient::Resource.new "http://localhost:#{api_port}/api/v1/users/1/applications/#{@non_recording_application_id}/request_specs", headers: { content_type: 'application/json' }
|
43
|
+
end
|
44
|
+
|
45
|
+
def recording_resource
|
46
|
+
@__recording_resource ||= RestClient::Resource.new "http://localhost:#{api_port}/api/v1/users/1/applications/#{@recording_application_id}/request_specs", headers: { content_type: 'application/json' }
|
47
|
+
end
|
48
|
+
|
49
|
+
def direct_resource
|
50
|
+
@__direct_resource ||= RestClient::Resource.new "http://localhost:#{api_port}/api/v1/users/1/applications/#{@direct_application_id}/request_specs", headers: { content_type: 'application/json' }
|
51
|
+
end
|
52
|
+
|
53
|
+
|
54
|
+
# Delete all first
|
55
|
+
configure_applications
|
56
|
+
# Now, add some stubs via the REST interface
|
57
|
+
[@http_url, @https_url, @http_url_no_proxy, @https_url_no_proxy].each do |url|
|
58
|
+
@stubs_with_recordings.push Spec.for url, 'index_old', create_request_spec(url: "#{url}/index.html", response: { content_type: 'text/html', content: '<html><body>This Is An Older Mock</body></html>' }) #This is intentional - the system should always use the latest
|
59
|
+
@stubs_with_recordings.push Spec.for url, 'index', create_request_spec(url: "#{url}/index.html", response: { content_type: 'text/html', content: '<html><body>Mocked Content</body></html>' })
|
60
|
+
@stubs_with_recordings.push Spec.for url, 'index_recording', create_request_spec(url: "#{url}/indexRecording.html", response: { content_type: 'text/html', content: '<html><body>Mocked Content</body></html>' })
|
61
|
+
@stubs_with_recordings.push Spec.for url, 'api_forums', create_request_spec(url: "#{url}/api/forums", response: { content_type: 'application/json', content: JSON.pretty_generate(forums: [], total: 0) })
|
62
|
+
@stubs_with_recordings.push Spec.for url, 'api_forums_post', create_request_spec(url: "#{url}/api/forums", http_method: 'POST', response: { content_type: 'application/json', content: '{"created": true}' })
|
63
|
+
@stubs_with_recordings.push Spec.for url, 'api_forum_post', create_request_spec(url: "#{url}/api/forums/:forum_id/:post_id", response: { content_type: 'text/html', content: '<html><body><h1>Sorted By: {{sort}}</h1><h2>{{forum_id}}</h2><h3>{{post_id}}</h3></body></html>', is_template: true })
|
64
|
+
@stubs_with_recordings.push Spec.for url, 'api_forum_post_put', create_request_spec(url: "#{url}/api/forums/:forum_id/:post_id", http_method: 'PUT', response: { content_type: 'application/json', content: '{"updated": true}' })
|
65
|
+
@stubs_with_recordings.push Spec.for url, 'api_forum_post_delete', create_request_spec(url: "#{url}/api/forums/:forum_id/:post_id", http_method: 'DELETE', response: { content_type: 'application/json', content: '{"deleted": true}' })
|
66
|
+
@stubs_with_recordings.push Spec.for url, 'api_forum_post_special', create_request_spec(url: "#{url}/api/forums/:forum_id/:post_id", conditions: '{"post_id": "special"}', response: { content_type: 'text/html', content: '<html><body><h1>Sorted By: {{sort}}</h1><h2>{{forum_id}}</h2><h3>{{post_id}}</h3><p>This is a special response</p></body></html>', is_template: true })
|
67
|
+
@stubs_with_recordings.push Spec.for url, 'api_forum_post_ever_so_special', create_request_spec(url: "#{url}/api/forums/:forum_id/:post_id", conditions: '{"post_id": "special", "sort": "eversospecial"}', response: { content_type: 'text/html', content: '<html><body><h1>Sorted By: {{sort}}</h1><h2>{{forum_id}}</h2><h3>{{post_id}}</h3><p>This is an ever so special response</p></body></html>', is_template: true })
|
68
|
+
@stubs_with_recordings.push Spec.for url, 'api_forum_update', create_request_spec(url: "#{url}/api/forums/:forum_id", http_method: 'POST',response: { content_type: 'text/html', content: '<html><body><h1></h1><h2>WRONG RESULT</h2><h3>{{forum_id}}</h3><p>This is an incorrect result probably because the conditions are being ignored ?</p></body></html>'})
|
69
|
+
@stubs_with_recordings.push Spec.for url, 'api_forum_update_special', create_request_spec(url: "#{url}/api/forums/:forum_id", http_method: 'POST', conditions: '{"posted_var":"special_value"}', response: { content_type: 'text/html', content: '<html><body><h1></h1><h2>{{posted_var}}</h2><h3>{{forum_id}}</h3><p>This should get data from the POSTed data</p></body></html>', is_template: true })
|
70
|
+
@stubs_with_recordings.push Spec.for url, 'api_forums_post', create_request_spec(url: "#{url}/api/forums/:forum_id/posts", response: { content_type: 'application/json', content: JSON.pretty_generate(posts: [
|
71
|
+
{ forum_id: '{{forum_id}}', subject: 'My first post' },
|
72
|
+
{ forum_id: '{{forum_id}}', subject: 'My second post' },
|
73
|
+
{ forum_id: '{{forum_id}}', subject: 'My third post' }
|
74
|
+
], total: 3), is_template: true })
|
75
|
+
end
|
76
|
+
end
|
77
|
+
before :each do
|
78
|
+
recordings_resource.delete if options.key?(:recording) && options[:recording]
|
79
|
+
end
|
80
|
+
end
|
81
|
+
end
|
82
|
+
end
|
83
|
+
end
|
84
|
+
end
|
@@ -0,0 +1,474 @@
|
|
1
|
+
require 'integration_spec_helper'
|
2
|
+
|
3
|
+
# require 'spec_helper'
|
4
|
+
require 'agile_proxy'
|
5
|
+
require 'resolv'
|
6
|
+
require 'rest_client'
|
7
|
+
|
8
|
+
shared_examples_for 'a proxy server' do |options = {}|
|
9
|
+
if options.key?(:recording) && options[:recording]
|
10
|
+
after :each do
|
11
|
+
expect(JSON.parse(recordings_resource.get)['total']).to eql(1)
|
12
|
+
end
|
13
|
+
end
|
14
|
+
it 'should proxy GET requests' do
|
15
|
+
expect(http.get('/echo').body).to eql 'GET /echo'
|
16
|
+
end
|
17
|
+
|
18
|
+
it 'should proxy POST requests' do
|
19
|
+
expect(http.post('/echo', foo: 'bar').body).to eql "POST /echo\nfoo=bar"
|
20
|
+
end
|
21
|
+
|
22
|
+
it 'should proxy PUT requests' do
|
23
|
+
expect(http.post('/echo', foo: 'bar').body).to eql "POST /echo\nfoo=bar"
|
24
|
+
end
|
25
|
+
|
26
|
+
it 'should proxy HEAD requests' do
|
27
|
+
expect(http.head('/echo').headers['HTTP-X-EchoServer']).to eql 'HEAD /echo'
|
28
|
+
end
|
29
|
+
|
30
|
+
it 'should proxy DELETE requests' do
|
31
|
+
expect(http.delete('/echo').body).to eql 'DELETE /echo'
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
shared_examples_for 'a request stub' do |options = {}|
|
36
|
+
recording = false
|
37
|
+
if options.key?(:recording) && options[:recording]
|
38
|
+
recording = true
|
39
|
+
after :each do
|
40
|
+
data = recordings_resource.get
|
41
|
+
count = JSON.parse(data)['total']
|
42
|
+
expect(count).to eql(1)
|
43
|
+
end
|
44
|
+
end
|
45
|
+
def find_stub(client, name)
|
46
|
+
@stubs_with_recordings.select { |stub| stub.url == client.url_prefix.to_s && stub.name == name}.first
|
47
|
+
end
|
48
|
+
def rest_client_for_stub(stub)
|
49
|
+
RestClient::Resource.new("http://localhost:#{api_port}/api/v1/users/1/applications/#{@recording_application_id}/request_specs/#{stub.body[:id]}/recordings", content_type: :json )
|
50
|
+
end
|
51
|
+
def recordings_for(name)
|
52
|
+
stub = find_stub(http, name)
|
53
|
+
JSON.parse(rest_client_for_stub(stub).get).with_indifferent_access
|
54
|
+
end
|
55
|
+
def recordings_matcher_for(name, path)
|
56
|
+
stub = find_stub(http, name)
|
57
|
+
{recordings: a_collection_containing_exactly(a_hash_including request_body: '', request_url: "#{http.url_prefix}#{path.gsub(/^\//, '')}", request_method: 'GET', request_spec_id: stub.body[:id])}
|
58
|
+
end
|
59
|
+
|
60
|
+
it 'should stub GET requests' do
|
61
|
+
response = http.get('/index.html')
|
62
|
+
expect(response.body).to eql '<html><body>Mocked Content</body></html>'
|
63
|
+
expect(response.headers).to include('content-length' => "40")
|
64
|
+
expect(recordings_for 'index').to include(recordings_matcher_for('index', '/index.html')) if recording
|
65
|
+
end
|
66
|
+
|
67
|
+
it 'should stub GET response statuses' do
|
68
|
+
response = http.get('/index.html')
|
69
|
+
expect(response.status).to eql 200
|
70
|
+
end
|
71
|
+
|
72
|
+
#TODO When time allows, work out how to easily test this as the stubs are not recorded for anything but recorded tests
|
73
|
+
#the lookup table would need to contain all stubs and we would need a way of indexing them to allow the test to find
|
74
|
+
# the correct one.
|
75
|
+
xit 'Should record a stub if specified in the stub irrespective of whether app is recording or not' do
|
76
|
+
expect(http.get('/indexRecording.html').status).to eql 200
|
77
|
+
expect(recordings_for('index_recording')).to include(recordings_matcher_for('index_recording', '/indexRecording.html'))
|
78
|
+
end
|
79
|
+
|
80
|
+
it 'Should stub a different get request with json response' do
|
81
|
+
resp = http.get('/api/forums')
|
82
|
+
expect(ActiveSupport::JSON.decode(resp.body).symbolize_keys).to eql forums: [], total: 0
|
83
|
+
expect(resp.status).to eql 200
|
84
|
+
expect(resp.headers).to include('content-type' => 'application/json', 'content-length' => resp.body.length.to_s)
|
85
|
+
expect(recordings_for 'api_forums').to include(recordings_matcher_for('api_forums', '/api/forums')) if recording
|
86
|
+
end
|
87
|
+
|
88
|
+
it 'Should get the mocked content with parameter substitution for the /api/forums/:forum_id/posts url' do
|
89
|
+
resp = http.get '/api/forums/my_forum/posts'
|
90
|
+
expect(ActiveSupport::JSON.decode(resp.body)).to eql 'posts' => [{ 'forum_id' => 'my_forum', 'subject' => 'My first post' }, { 'forum_id' => 'my_forum', 'subject' => 'My second post' }, { 'forum_id' => 'my_forum', 'subject' => 'My third post' }], 'total' => 3
|
91
|
+
expect(resp.status).to eql 200
|
92
|
+
expect(resp.headers).to include('content-type' => 'application/json', 'content-length' => resp.body.length.to_s)
|
93
|
+
end
|
94
|
+
|
95
|
+
it 'Should get the mocked content for api/forums/:forum_id/:post_id with parameter substitution including query parameters' do
|
96
|
+
resp = http.get '/api/forums/my_forum/my_post?sort=id'
|
97
|
+
expect(resp.body).to eql '<html><body><h1>Sorted By: id</h1><h2>my_forum</h2><h3>my_post</h3></body></html>'
|
98
|
+
expect(resp.status).to eql 200
|
99
|
+
expect(resp.headers).to include('content-type' => 'text/html', 'content-length' => resp.body.length.to_s)
|
100
|
+
end
|
101
|
+
it 'Should get the mocked content for api/forums/:forum_id/:post_id.html with parameter substitution including query parameters' do
|
102
|
+
resp = http.get '/api/forums/my_forum/my_post.html?sort=id'
|
103
|
+
expect(resp.body).to eql '<html><body><h1>Sorted By: id</h1><h2>my_forum</h2><h3>my_post</h3></body></html>'
|
104
|
+
expect(resp.status).to eql 200
|
105
|
+
expect(resp.headers).to include('content-type' => 'text/html', 'content-length' => resp.body.length.to_s)
|
106
|
+
end
|
107
|
+
it 'Should respond with an error for api/forums/:forum_id/:post_id.html with parameter substitution with a missing query parameter' do
|
108
|
+
resp = http.get '/api/forums/my_forum/my_post.html'
|
109
|
+
expect(resp.body).to eql '<html><body><h1>Sorted By: </h1><h2>my_forum</h2><h3>my_post</h3></body></html>'
|
110
|
+
expect(resp.headers).to include('content-type' => 'text/html', 'content-length' => resp.body.length.to_s)
|
111
|
+
expect(resp.status).to eql 200
|
112
|
+
end
|
113
|
+
it 'Should match the route by posted json data and the posted data can be output via the template' do
|
114
|
+
resp = http.post '/api/forums/my_forum', '{"posted_var": "special_value"}', 'Content-Type' => 'application/json'
|
115
|
+
expect(resp.body).to eql '<html><body><h1></h1><h2>special_value</h2><h3>my_forum</h3><p>This should get data from the POSTed data</p></body></html>'
|
116
|
+
expect(resp.status).to eql 200
|
117
|
+
expect(resp.headers).to include('content-type' => 'text/html', 'content-length' => resp.body.length.to_s)
|
118
|
+
end
|
119
|
+
it 'Should match the route by posted plain text data and the posted data can be output via the template' do
|
120
|
+
resp = http.post '/api/forums/my_forum', "posted_var=special_value\n", 'Content-Type' => 'text/plain'
|
121
|
+
expect(resp.body).to eql '<html><body><h1></h1><h2>special_value</h2><h3>my_forum</h3><p>This should get data from the POSTed data</p></body></html>'
|
122
|
+
expect(resp.status).to eql 200
|
123
|
+
expect(resp.headers).to include('content-type' => 'text/html', 'content-length' => resp.body.length.to_s)
|
124
|
+
end
|
125
|
+
it 'Should match the route by posted plain text data and the posted data can be output via the template' do
|
126
|
+
resp = http.post '/api/forums/my_forum', "dummy=\nposted_var=special_value\n", 'Content-Type' => 'text/plain'
|
127
|
+
expect(resp.body).to eql '<html><body><h1></h1><h2>special_value</h2><h3>my_forum</h3><p>This should get data from the POSTed data</p></body></html>'
|
128
|
+
expect(resp.status).to eql 200
|
129
|
+
expect(resp.headers).to include('content-type' => 'text/html', 'content-length' => resp.body.length.to_s)
|
130
|
+
end
|
131
|
+
# it 'Should match the route by posted xml data and the posted data can be output via the template' do
|
132
|
+
# resp = http.post "/api/forums/my_forum", '<posted_var>special_value</posted_var>', {'Content-Type' => 'application/xml'}
|
133
|
+
# expect(resp.body).to eql '<html><body><h1></h1><h2>special_value</h2><h3>my_forum</h3><p>This should get data from the POSTed data</p></body></html>'
|
134
|
+
# expect(resp.status).to eql 200
|
135
|
+
# end
|
136
|
+
it 'Should match the route by posted url encoded data and the posted data can be output via the template' do
|
137
|
+
resp = http.post '/api/forums/my_forum', 'posted_var=special_value', 'Content-Type' => 'application/x-www-form-urlencoded'
|
138
|
+
expect(resp.body).to eql '<html><body><h1></h1><h2>special_value</h2><h3>my_forum</h3><p>This should get data from the POSTed data</p></body></html>'
|
139
|
+
expect(resp.headers).to include('content-type' => 'text/html', 'content-length' => resp.body.length.to_s)
|
140
|
+
expect(resp.status).to eql 200
|
141
|
+
end
|
142
|
+
it 'Should match the route by posted multipart encoded data and the posted data can be output via the template' do
|
143
|
+
resp = http.post '/api/forums/my_forum', 'posted_var=special_value', 'Content-Type' => 'multipart/form-data'
|
144
|
+
expect(resp.body).to eql '<html><body><h1></h1><h2>special_value</h2><h3>my_forum</h3><p>This should get data from the POSTed data</p></body></html>'
|
145
|
+
expect(resp.headers).to include('content-type' => 'text/html', 'content-length' => resp.body.length.to_s)
|
146
|
+
expect(resp.status).to eql 200
|
147
|
+
end
|
148
|
+
|
149
|
+
it 'should stub POST requests' do
|
150
|
+
resp = http.post('/api/forums', foo: :bar)
|
151
|
+
expect(resp.body).to eql '{"created": true}'
|
152
|
+
expect(resp.headers).to include('content-type' => 'application/json', 'content-length' => resp.body.length.to_s)
|
153
|
+
|
154
|
+
end
|
155
|
+
|
156
|
+
it 'should stub PUT requests' do
|
157
|
+
resp = http.put('/api/forums/forum_1/my_post', foo: :bar)
|
158
|
+
expect(resp.body).to eql '{"updated": true}'
|
159
|
+
expect(resp.headers).to include('content-type' => 'application/json', 'content-length' => resp.body.length.to_s)
|
160
|
+
end
|
161
|
+
|
162
|
+
it 'should stub DELETE requests' do
|
163
|
+
resp = http.delete('/api/forums/forum_1/my_post')
|
164
|
+
expect(resp.body).to eql '{"deleted": true}'
|
165
|
+
expect(resp.headers).to include('content-type' => 'application/json', 'content-length' => resp.body.length.to_s)
|
166
|
+
end
|
167
|
+
end
|
168
|
+
|
169
|
+
shared_examples_for 'a cache' do
|
170
|
+
|
171
|
+
context 'whitelisted GET requests' do
|
172
|
+
it 'should not be cached' do
|
173
|
+
assert_noncached_url
|
174
|
+
end
|
175
|
+
|
176
|
+
context 'with ports' do
|
177
|
+
before do
|
178
|
+
rack_app_url = URI(http.url_prefix)
|
179
|
+
AgileProxy.config.whitelist = ["#{rack_app_url.host}:#{rack_app_url.port}"]
|
180
|
+
end
|
181
|
+
|
182
|
+
it 'should not be cached ' do
|
183
|
+
assert_noncached_url
|
184
|
+
end
|
185
|
+
end
|
186
|
+
end
|
187
|
+
|
188
|
+
context 'non-whitelisted GET requests' do
|
189
|
+
before do
|
190
|
+
AgileProxy.config.whitelist = []
|
191
|
+
end
|
192
|
+
|
193
|
+
it 'should be cached' do
|
194
|
+
assert_cached_url
|
195
|
+
end
|
196
|
+
|
197
|
+
context 'with ports' do
|
198
|
+
before do
|
199
|
+
rack_app_url = URI(http.url_prefix)
|
200
|
+
AgileProxy.config.whitelist = ["#{rack_app_url.host}:#{rack_app_url.port + 1}"]
|
201
|
+
end
|
202
|
+
|
203
|
+
it 'should be cached' do
|
204
|
+
assert_cached_url
|
205
|
+
end
|
206
|
+
end
|
207
|
+
end
|
208
|
+
|
209
|
+
context 'ignore_params GET requests' do
|
210
|
+
before do
|
211
|
+
AgileProxy.config.ignore_params = ['/analytics']
|
212
|
+
end
|
213
|
+
|
214
|
+
it 'should be cached' do
|
215
|
+
r = http.get('/analytics?some_param=5')
|
216
|
+
expect(r.body).to eql 'GET /analytics'
|
217
|
+
expect do
|
218
|
+
expect do
|
219
|
+
r = http.get('/analytics?some_param=20')
|
220
|
+
end.to change { r.headers['HTTP-X-EchoCount'].to_i }.by(1)
|
221
|
+
end.to_not change { r.body }
|
222
|
+
end
|
223
|
+
end
|
224
|
+
|
225
|
+
context 'path_blacklist GET requests' do
|
226
|
+
before do
|
227
|
+
AgileProxy.config.path_blacklist = ['/api']
|
228
|
+
end
|
229
|
+
|
230
|
+
it 'should be cached' do
|
231
|
+
assert_cached_url('/api')
|
232
|
+
end
|
233
|
+
end
|
234
|
+
|
235
|
+
context 'cache persistence' do
|
236
|
+
let(:cached_key) { proxy.cache.key('get', "#{url}/foo", '') }
|
237
|
+
let(:cached_file) do
|
238
|
+
f = cached_key + '.yml'
|
239
|
+
File.join(AgileProxy.config.cache_path, f)
|
240
|
+
end
|
241
|
+
|
242
|
+
before { AgileProxy.config.whitelist = [] }
|
243
|
+
|
244
|
+
after do
|
245
|
+
File.delete(cached_file) if File.exist?(cached_file)
|
246
|
+
end
|
247
|
+
|
248
|
+
context 'enabled' do
|
249
|
+
before { AgileProxy.config.persist_cache = true }
|
250
|
+
|
251
|
+
it 'should persist' do
|
252
|
+
http.get('/foo')
|
253
|
+
expect(File.exist?(cached_file)).to be_true
|
254
|
+
end
|
255
|
+
|
256
|
+
it 'should be read initially from persistent cache' do
|
257
|
+
File.open(cached_file, 'w') do |f|
|
258
|
+
cached = {
|
259
|
+
headers: {},
|
260
|
+
content: 'GET /foo cached'
|
261
|
+
}
|
262
|
+
f.write(cached.to_yaml(Encoding: :Utf8))
|
263
|
+
end
|
264
|
+
|
265
|
+
r = http.get('/foo')
|
266
|
+
expect(r.body).to eql 'GET /foo cached'
|
267
|
+
end
|
268
|
+
|
269
|
+
context 'cache_request_headers requests' do
|
270
|
+
it 'should not be cached by default' do
|
271
|
+
http.get('/foo')
|
272
|
+
saved_cache = AgileProxy.proxy.cache.fetch_from_persistence(cached_key)
|
273
|
+
expect(saved_cache.keys).not_to include :request_headers
|
274
|
+
end
|
275
|
+
|
276
|
+
context 'when enabled' do
|
277
|
+
before do
|
278
|
+
AgileProxy.config.cache_request_headers = true
|
279
|
+
end
|
280
|
+
|
281
|
+
it 'should be cached' do
|
282
|
+
http.get('/foo')
|
283
|
+
saved_cache = AgileProxy.proxy.cache.fetch_from_persistence(cached_key)
|
284
|
+
expect(saved_cache.keys).to include :request_headers
|
285
|
+
end
|
286
|
+
end
|
287
|
+
end
|
288
|
+
|
289
|
+
context 'ignore_cache_port requests' do
|
290
|
+
it 'should be cached without port' do
|
291
|
+
r = http.get('/foo')
|
292
|
+
url = URI(r.env[:url])
|
293
|
+
saved_cache = AgileProxy.proxy.cache.fetch_from_persistence(cached_key)
|
294
|
+
|
295
|
+
expect(saved_cache[:url]).to_not eql(url.to_s)
|
296
|
+
expect(saved_cache[:url]).to eql(url.to_s.gsub(":#{url.port}", ''))
|
297
|
+
end
|
298
|
+
end
|
299
|
+
|
300
|
+
context 'non_whitelisted_requests_disabled requests' do
|
301
|
+
before { AgileProxy.config.non_whitelisted_requests_disabled = true }
|
302
|
+
|
303
|
+
it 'should raise error when disabled' do
|
304
|
+
# TODO: Suppress stderr output: https://gist.github.com/adamstegman/926858
|
305
|
+
expect { http.get('/foo') }.to raise_error(Faraday::Error::ConnectionFailed, 'end of file reached')
|
306
|
+
end
|
307
|
+
end
|
308
|
+
|
309
|
+
context 'non_successful_cache_disabled requests' do
|
310
|
+
before do
|
311
|
+
rack_app_url = URI(http_error.url_prefix)
|
312
|
+
AgileProxy.config.whitelist = ["#{rack_app_url.host}:#{rack_app_url.port}"]
|
313
|
+
AgileProxy.config.non_successful_cache_disabled = true
|
314
|
+
end
|
315
|
+
|
316
|
+
it 'should not cache non-successful response when enabled' do
|
317
|
+
http_error.get('/foo')
|
318
|
+
expect(File.exist?(cached_file)).to be_false
|
319
|
+
end
|
320
|
+
|
321
|
+
it 'should cache successful response when enabled' do
|
322
|
+
assert_cached_url
|
323
|
+
end
|
324
|
+
end
|
325
|
+
|
326
|
+
context 'non_successful_error_level requests' do
|
327
|
+
before do
|
328
|
+
rack_app_url = URI(http_error.url_prefix)
|
329
|
+
AgileProxy.config.whitelist = ["#{rack_app_url.host}:#{rack_app_url.port}"]
|
330
|
+
AgileProxy.config.non_successful_error_level = :error
|
331
|
+
end
|
332
|
+
|
333
|
+
it 'should raise error for non-successful responses when :error' do
|
334
|
+
# When this config setting is set, the EventMachine running the test servers is killed upon error raising
|
335
|
+
# The `raise` is required to bubble up the error to the test running it
|
336
|
+
# The Faraday error is raised upon `close_connection` so this can be non-pending if we can do one of the following:
|
337
|
+
# 1) Remove the `raise error_message` conditionally for this test
|
338
|
+
# 2) Restart the test servers if they aren't running
|
339
|
+
# 3) Change the test servers to start/stop for each test instead of before all
|
340
|
+
# 4) Remove the test server completely and rely on the server instantiated by the app
|
341
|
+
pending 'Unable to test this without affecting the running test servers'
|
342
|
+
expect { http_error.get('/foo') }.to raise_error(Faraday::Error::ConnectionFailed)
|
343
|
+
end
|
344
|
+
end
|
345
|
+
end
|
346
|
+
context 'disabled' do
|
347
|
+
before { AgileProxy.config.persist_cache = false }
|
348
|
+
|
349
|
+
it 'shouldnt persist' do
|
350
|
+
http.get('/foo')
|
351
|
+
expect(File.exist?(cached_file)).to be_false
|
352
|
+
end
|
353
|
+
end
|
354
|
+
end
|
355
|
+
|
356
|
+
def assert_noncached_url(url = '/foo')
|
357
|
+
r = http.get(url)
|
358
|
+
expect(r.body).to eql "GET #{url}"
|
359
|
+
expect do
|
360
|
+
expect do
|
361
|
+
r = http.get(url)
|
362
|
+
end.to change { r.headers['HTTP-X-EchoCount'].to_i }.by(1)
|
363
|
+
end.to_not change { r.body }
|
364
|
+
end
|
365
|
+
|
366
|
+
def assert_cached_url(url = '/foo')
|
367
|
+
r = http.get(url)
|
368
|
+
expect(r.body).to eql "GET #{url}"
|
369
|
+
expect do
|
370
|
+
expect do
|
371
|
+
r = http.get(url)
|
372
|
+
end.to_not change { r.headers['HTTP-X-EchoCount'] }
|
373
|
+
end.to_not change { r.body }
|
374
|
+
end
|
375
|
+
end
|
376
|
+
|
377
|
+
shared_examples_for 'a static server' do
|
378
|
+
it 'Should serve a file from the current directory' do
|
379
|
+
expect(http.get('/spec/fixtures/example_static_file.html').body).to eql 'Hello World'
|
380
|
+
end
|
381
|
+
end
|
382
|
+
describe AgileProxy::Server, :type => :integration do
|
383
|
+
extend AgileProxy::Test::Integration::RequestSpecHelper
|
384
|
+
describe 'Without recording' do
|
385
|
+
load_small_set_of_request_specs
|
386
|
+
before do
|
387
|
+
# Adding non-valid Faraday options throw an error: https://github.com/arsduo/koala/pull/311
|
388
|
+
# Valid options: :request, :proxy, :ssl, :builder, :url, :parallel_manager, :params, :headers, :builder_class
|
389
|
+
faraday_options = {
|
390
|
+
request: {timeout: 10.0}
|
391
|
+
}
|
392
|
+
faraday_options_with_proxy = faraday_options.merge({
|
393
|
+
proxy: { uri: "http://anonymous:password@localhost:#{proxy_port}" }
|
394
|
+
})
|
395
|
+
@http = Faraday.new @http_url, faraday_options_with_proxy
|
396
|
+
@https = Faraday.new @https_url, faraday_options_with_proxy.merge(ssl: { verify: false })
|
397
|
+
@http_no_proxy = Faraday.new @http_url_no_proxy, faraday_options
|
398
|
+
@https_no_proxy = Faraday.new @https_url_no_proxy, faraday_options.merge(ssl: { verify: false })
|
399
|
+
@http_error = Faraday.new @error_url, faraday_options_with_proxy
|
400
|
+
@http_error_no_proxy = Faraday.new @error_url, faraday_options_with_proxy
|
401
|
+
end
|
402
|
+
context 'proxying' do
|
403
|
+
context 'HTTP' do
|
404
|
+
let!(:http) { @http }
|
405
|
+
it_should_behave_like 'a proxy server'
|
406
|
+
end
|
407
|
+
context 'HTTPS' do
|
408
|
+
let!(:http) { @https }
|
409
|
+
it_should_behave_like 'a proxy server'
|
410
|
+
end
|
411
|
+
end
|
412
|
+
context 'stubbing' do
|
413
|
+
context 'In Proxy Mode' do
|
414
|
+
context 'HTTP' do
|
415
|
+
let!(:url) { @http_url }
|
416
|
+
let!(:http) { @http }
|
417
|
+
it_should_behave_like 'a request stub'
|
418
|
+
end
|
419
|
+
|
420
|
+
context 'HTTPS' do
|
421
|
+
let!(:url) { @https_url }
|
422
|
+
let!(:http) { @https }
|
423
|
+
it_should_behave_like 'a request stub'
|
424
|
+
end
|
425
|
+
end
|
426
|
+
#Server mode only supports http - no real point for https at the moment
|
427
|
+
context 'In Server Mode' do
|
428
|
+
context 'HTTP' do
|
429
|
+
let!(:url) { @http_url_no_proxy }
|
430
|
+
let!(:http) { @http_no_proxy }
|
431
|
+
it_should_behave_like 'a request stub'
|
432
|
+
it_should_behave_like 'a static server'
|
433
|
+
end
|
434
|
+
end
|
435
|
+
end
|
436
|
+
end
|
437
|
+
describe 'With recording' do
|
438
|
+
load_small_set_of_request_specs recording: true
|
439
|
+
before do
|
440
|
+
# Adding non-valid Faraday options throw an error: https://github.com/arsduo/koala/pull/311
|
441
|
+
# Valid options: :request, :proxy, :ssl, :builder, :url, :parallel_manager, :params, :headers, :builder_class
|
442
|
+
faraday_options = {
|
443
|
+
proxy: { uri: 'http://recording:password@localhost:3101' },
|
444
|
+
request: { timeout: 10.0 }
|
445
|
+
}
|
446
|
+
|
447
|
+
@http = Faraday.new @http_url, faraday_options
|
448
|
+
@https = Faraday.new @https_url, faraday_options.merge(ssl: { verify: false })
|
449
|
+
@http_error = Faraday.new @error_url, faraday_options
|
450
|
+
end
|
451
|
+
context 'proxying' do
|
452
|
+
context 'HTTP' do
|
453
|
+
let!(:http) { @http }
|
454
|
+
it_should_behave_like 'a proxy server', recording: true
|
455
|
+
end
|
456
|
+
context 'HTTPS' do
|
457
|
+
let!(:http) { @https }
|
458
|
+
it_should_behave_like 'a proxy server', recording: true
|
459
|
+
end
|
460
|
+
end
|
461
|
+
context 'stubbing' do
|
462
|
+
context 'HTTP' do
|
463
|
+
let!(:url) { @http_url }
|
464
|
+
let!(:http) { @http }
|
465
|
+
it_should_behave_like 'a request stub', recording: true
|
466
|
+
end
|
467
|
+
context 'HTTPS' do
|
468
|
+
let!(:url) { @https_url }
|
469
|
+
let!(:http) { @https }
|
470
|
+
it_should_behave_like 'a request stub', recording: true
|
471
|
+
end
|
472
|
+
end
|
473
|
+
end
|
474
|
+
end
|