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,18 @@
|
|
|
1
|
+
require 'require_all'
|
|
2
|
+
require 'airborne'
|
|
3
|
+
|
|
4
|
+
require 'agile_proxy'
|
|
5
|
+
require_all 'spec/support/**/*.rb'
|
|
6
|
+
require_all 'lib/agile_proxy/model'
|
|
7
|
+
require_all 'spec/integration/helpers'
|
|
8
|
+
require 'faker'
|
|
9
|
+
RSpec.configure do |config|
|
|
10
|
+
include AgileProxy::TestServer
|
|
11
|
+
config.before :all do
|
|
12
|
+
start_test_servers
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
end
|
|
16
|
+
Airborne.configure do |config|
|
|
17
|
+
config.base_url = 'http://localhost:3020'
|
|
18
|
+
end
|
data/spec/spec_helper.rb
ADDED
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
Dir[File.expand_path('../support/**/*.rb', __FILE__)].each { |f| require f }
|
|
2
|
+
ENV['RACK_ENV'] ||= 'test'
|
|
3
|
+
require 'pry'
|
|
4
|
+
require 'active_record'
|
|
5
|
+
require 'shoulda-matchers'
|
|
6
|
+
require 'rack'
|
|
7
|
+
require 'logger'
|
|
8
|
+
require_relative './unit/agile_proxy/api/common_helper'
|
|
9
|
+
require_relative './common_helper'
|
|
10
|
+
require_relative '../lib/agile_proxy'
|
|
11
|
+
environment = 'test'
|
|
12
|
+
dbconfig = YAML.load(File.read(AgileProxy.config.database_config_file))
|
|
13
|
+
ActiveRecord::Base.establish_connection dbconfig[environment]
|
|
14
|
+
|
|
15
|
+
AgileProxy.configure do |config|
|
|
16
|
+
config.logger = Logger.new(File.expand_path('../../log/test.log', __FILE__))
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
RSpec.configure do |config|
|
|
20
|
+
include AgileProxy::TestServer
|
|
21
|
+
config.treat_symbols_as_metadata_keys_with_true_values = true
|
|
22
|
+
config.run_all_when_everything_filtered = true
|
|
23
|
+
config.filter_run :focus
|
|
24
|
+
config.order = 'random'
|
|
25
|
+
|
|
26
|
+
config.before :all do
|
|
27
|
+
start_test_servers
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
config.after :each do
|
|
31
|
+
AgileProxy.config.reset
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
config.mock_with :rspec do |mocks|
|
|
35
|
+
mocks.syntax = :expect
|
|
36
|
+
end
|
|
37
|
+
config.include AgileProxy::Test::Api::Common, api_test: true
|
|
38
|
+
config.include AgileProxy::Test::Common
|
|
39
|
+
end
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
require 'eventmachine'
|
|
2
|
+
require 'thin'
|
|
3
|
+
require 'faraday'
|
|
4
|
+
|
|
5
|
+
module Thin
|
|
6
|
+
module Backends
|
|
7
|
+
class TcpServer
|
|
8
|
+
def get_port
|
|
9
|
+
# seriously, eventmachine, how hard does getting a port have to be?
|
|
10
|
+
Socket.unpack_sockaddr_in(EM.get_sockname(@signature)).first
|
|
11
|
+
end
|
|
12
|
+
end
|
|
13
|
+
end
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
module AgileProxy
|
|
17
|
+
module TestServer
|
|
18
|
+
def initialize
|
|
19
|
+
Thin::Logging.silent = true
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
def start_test_servers
|
|
23
|
+
q = Queue.new
|
|
24
|
+
Thread.new do
|
|
25
|
+
EM.run do
|
|
26
|
+
echo = echo_app_setup
|
|
27
|
+
|
|
28
|
+
http_server = start_server(echo)
|
|
29
|
+
q.push http_server.backend.get_port
|
|
30
|
+
|
|
31
|
+
https_server = start_server(echo, true)
|
|
32
|
+
q.push https_server.backend.get_port
|
|
33
|
+
|
|
34
|
+
echo_error = echo_app_setup(500)
|
|
35
|
+
error_server = start_server(echo_error)
|
|
36
|
+
q.push error_server.backend.get_port
|
|
37
|
+
end
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
@http_url = "http://localhost:#{q.pop}"
|
|
41
|
+
@https_url = "https://localhost:#{q.pop}"
|
|
42
|
+
@error_url = "http://localhost:#{q.pop}"
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
def echo_app_setup(response_code = 200)
|
|
46
|
+
counter = 0
|
|
47
|
+
proc do |env|
|
|
48
|
+
req_body = env['rack.input'].read
|
|
49
|
+
request_info = "#{env['REQUEST_METHOD']} #{env['PATH_INFO']}"
|
|
50
|
+
res_body = request_info
|
|
51
|
+
res_body += "\n#{req_body}" unless req_body.empty?
|
|
52
|
+
counter += 1
|
|
53
|
+
[
|
|
54
|
+
response_code,
|
|
55
|
+
{ 'HTTP-X-EchoServer' => request_info,
|
|
56
|
+
'HTTP-X-EchoCount' => "#{counter}" },
|
|
57
|
+
[res_body]
|
|
58
|
+
]
|
|
59
|
+
end
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
def start_server(echo, ssl = false)
|
|
63
|
+
http_server = Thin::Server.new '127.0.0.1', 0, echo
|
|
64
|
+
if ssl
|
|
65
|
+
http_server.ssl = true
|
|
66
|
+
http_server.ssl_options = {
|
|
67
|
+
private_key_file: File.expand_path('../../fixtures/test-server.key', __FILE__),
|
|
68
|
+
cert_chain_file: File.expand_path('../../fixtures/test-server.crt', __FILE__)
|
|
69
|
+
}
|
|
70
|
+
end
|
|
71
|
+
http_server.start
|
|
72
|
+
http_server
|
|
73
|
+
end
|
|
74
|
+
end
|
|
75
|
+
end
|
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
require 'spec_helper'
|
|
2
|
+
require_relative './common_helper'
|
|
3
|
+
require 'rack/test'
|
|
4
|
+
|
|
5
|
+
describe AgileProxy::Api::Applications, api_test: true do
|
|
6
|
+
include Rack::Test::Methods
|
|
7
|
+
include AgileProxy::Test::Api::Common
|
|
8
|
+
let(:applications_assoc_class) { Class.new }
|
|
9
|
+
|
|
10
|
+
describe 'GET /users/1/applications' do
|
|
11
|
+
let(:applications_result) do
|
|
12
|
+
[
|
|
13
|
+
{ username: 'user1', password: 'password1', name: 'application1', record_requests: true, user_id: current_user.id }.stringify_keys,
|
|
14
|
+
{ username: 'user1', password: 'password2', name: 'application2', record_requests: true, user_id: current_user.id }.stringify_keys,
|
|
15
|
+
{ username: 'user1', password: 'password3', name: 'application3', record_requests: true, user_id: current_user.id }.stringify_keys
|
|
16
|
+
]
|
|
17
|
+
end
|
|
18
|
+
before :each do
|
|
19
|
+
expect(current_user).to receive(:applications).and_return(applications_assoc_class)
|
|
20
|
+
expect(applications_assoc_class).to receive(:page).and_return applications_assoc_class
|
|
21
|
+
expect(applications_assoc_class).to receive(:per).and_return applications_assoc_class
|
|
22
|
+
expect(applications_assoc_class).to receive(:padding).and_return applications_assoc_class
|
|
23
|
+
expect(applications_assoc_class).to receive(:total_count).and_return 3
|
|
24
|
+
expect(applications_assoc_class).to receive(:num_pages).and_return 1
|
|
25
|
+
expect(applications_assoc_class).to receive(:current_page).and_return 1
|
|
26
|
+
expect(applications_assoc_class).to receive(:next_page).and_return 1
|
|
27
|
+
expect(applications_assoc_class).to receive(:prev_page).and_return 1
|
|
28
|
+
expect(applications_assoc_class).to receive(:count).and_return 3
|
|
29
|
+
expect(applications_assoc_class).to receive(:as_json).and_return(applications_result)
|
|
30
|
+
end
|
|
31
|
+
it 'returns a populated array of applications' do
|
|
32
|
+
get '/v1/users/1/applications'
|
|
33
|
+
expect(last_response.status).to eq(200)
|
|
34
|
+
expect(JSON.parse(last_response.body)).to eq('applications' => applications_result, 'total' => 3)
|
|
35
|
+
end
|
|
36
|
+
end
|
|
37
|
+
describe 'POST /users/1/applications' do
|
|
38
|
+
let(:create_attributes) { { username: 'user1', password: 'password', name: 'application1', record_requests: true } }
|
|
39
|
+
let(:to_be_created_attributes) { create_attributes.merge(user_id: current_user.id, record_requests: 'true').stringify_keys }
|
|
40
|
+
let(:created_attributes) { to_be_created_attributes }
|
|
41
|
+
let(:mock_application) { double('AgileProxy::Application', create_attributes) }
|
|
42
|
+
before :each do
|
|
43
|
+
expect(current_user).to receive(:applications).and_return applications_assoc_class
|
|
44
|
+
expect(applications_assoc_class).to receive(:create!).with(to_be_created_attributes).and_return(mock_application)
|
|
45
|
+
expect(mock_application).to receive(:as_json).and_return(to_be_created_attributes)
|
|
46
|
+
end
|
|
47
|
+
it 'Creates a new application and returns it' do
|
|
48
|
+
post '/v1/users/1/applications', create_attributes, 'Content-Type' => 'application/json'
|
|
49
|
+
expect(last_response.status).to eq(201)
|
|
50
|
+
expect(JSON.parse(last_response.body)).to eql(created_attributes)
|
|
51
|
+
end
|
|
52
|
+
end
|
|
53
|
+
describe 'DELETE /users/1/applications' do
|
|
54
|
+
before :each do
|
|
55
|
+
expect(current_user).to receive(:applications).and_return(applications_assoc_class)
|
|
56
|
+
expect(applications_assoc_class).to receive(:destroy_all)
|
|
57
|
+
end
|
|
58
|
+
it 'Should destroy all applications for the user' do
|
|
59
|
+
delete '/v1/users/1/applications'
|
|
60
|
+
expect(last_response.status).to eq(200)
|
|
61
|
+
expect(JSON.parse(last_response.body).symbolize_keys).to eql(applications: [], total: 0)
|
|
62
|
+
end
|
|
63
|
+
end
|
|
64
|
+
describe '/users/1/applications/10' do
|
|
65
|
+
let(:persisted_attributes) { { username: 'user1', password: 'password', name: 'application10', record_requests: true, id: 10 } }
|
|
66
|
+
let(:mock_application) { double('AgileProxy::Application', persisted_attributes) }
|
|
67
|
+
before :each do
|
|
68
|
+
expect(current_user).to receive(:applications).and_return(applications_assoc_class)
|
|
69
|
+
expect(applications_assoc_class).to receive(:where).with(id: '10').and_return applications_assoc_class
|
|
70
|
+
expect(applications_assoc_class).to receive(:first).and_return mock_application
|
|
71
|
+
expect(mock_application).to receive(:as_json).with({}).and_return persisted_attributes
|
|
72
|
+
end
|
|
73
|
+
context 'GET' do
|
|
74
|
+
it 'Should retrieve the application from persistence store' do
|
|
75
|
+
get '/v1/users/1/applications/10'
|
|
76
|
+
expect(last_response.status).to eq(200)
|
|
77
|
+
expect(JSON.parse(last_response.body).symbolize_keys).to eql(persisted_attributes)
|
|
78
|
+
end
|
|
79
|
+
end
|
|
80
|
+
context 'DELETE' do
|
|
81
|
+
it 'Should call destroy on the application found' do
|
|
82
|
+
expect(mock_application).to receive(:destroy)
|
|
83
|
+
delete '/v1/users/1/applications/10'
|
|
84
|
+
expect(last_response.status).to eq(200)
|
|
85
|
+
expect(JSON.parse(last_response.body).symbolize_keys).to eql(persisted_attributes)
|
|
86
|
+
end
|
|
87
|
+
end
|
|
88
|
+
context 'PUT' do
|
|
89
|
+
let(:to_be_updated_attributes) { { username: 'user1', password: 'password', name: 'application10 new name', record_requests: 'true' }.stringify_keys }
|
|
90
|
+
let(:updated_attributes) { to_be_updated_attributes.merge(record_requests: true).stringify_keys }
|
|
91
|
+
it 'Should call update_attributes on the application found' do
|
|
92
|
+
expect(mock_application).to receive(:update_attributes).with(to_be_updated_attributes)
|
|
93
|
+
persisted_attributes.merge! updated_attributes
|
|
94
|
+
persisted_attributes.delete(:id) # We dont allow modification of the id
|
|
95
|
+
put '/v1/users/1/applications/10', to_be_updated_attributes
|
|
96
|
+
expect(last_response.status).to eq(200)
|
|
97
|
+
expect(JSON.parse(last_response.body)).to eql(updated_attributes)
|
|
98
|
+
|
|
99
|
+
end
|
|
100
|
+
end
|
|
101
|
+
end
|
|
102
|
+
end
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
module AgileProxy
|
|
2
|
+
module Test
|
|
3
|
+
module Api
|
|
4
|
+
# A common helper for all API unit tests
|
|
5
|
+
module Common
|
|
6
|
+
def self.included(base)
|
|
7
|
+
base.instance_eval do
|
|
8
|
+
before :each do
|
|
9
|
+
setup_active_record_environment!
|
|
10
|
+
def app
|
|
11
|
+
AgileProxy::Api::Root
|
|
12
|
+
end
|
|
13
|
+
end
|
|
14
|
+
end
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
def current_user
|
|
18
|
+
@__current_user ||= double('AgileProxy::User', id: 1, name: 'Test User')
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
def current_application
|
|
22
|
+
@__current_application ||= double('AgileProxy::Application', name: 'Default Application', id: 1)
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
def setup_active_record_environment!
|
|
26
|
+
allow(AgileProxy::User).to receive(:first).and_return current_user
|
|
27
|
+
end
|
|
28
|
+
end
|
|
29
|
+
end
|
|
30
|
+
end
|
|
31
|
+
end
|
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
require 'spec_helper'
|
|
2
|
+
require_relative 'common_helper'
|
|
3
|
+
require 'rack/test'
|
|
4
|
+
|
|
5
|
+
describe AgileProxy::Api::Recordings, api_test: true do
|
|
6
|
+
include Rack::Test::Methods
|
|
7
|
+
include AgileProxy::Test::Api::Common
|
|
8
|
+
let(:applications_assoc_class) do
|
|
9
|
+
Class.new do
|
|
10
|
+
end
|
|
11
|
+
end
|
|
12
|
+
let(:recordings_assoc_class) do
|
|
13
|
+
Class.new do
|
|
14
|
+
def self.destroy_all
|
|
15
|
+
end
|
|
16
|
+
end
|
|
17
|
+
end
|
|
18
|
+
let(:application_instance) { applications_assoc_class.new }
|
|
19
|
+
|
|
20
|
+
before :each do
|
|
21
|
+
expect(current_user).to receive(:applications).and_return(applications_assoc_class)
|
|
22
|
+
expect(applications_assoc_class).to receive(:where).with(id: '1').and_return applications_assoc_class
|
|
23
|
+
expect(applications_assoc_class).to receive(:first).and_return application_instance
|
|
24
|
+
expect(application_instance).to receive(:recordings).and_return recordings_assoc_class
|
|
25
|
+
|
|
26
|
+
end
|
|
27
|
+
describe 'GET /users/1/applications/1/recordings' do
|
|
28
|
+
let(:recordings_result) do
|
|
29
|
+
[
|
|
30
|
+
{
|
|
31
|
+
application_id: 1,
|
|
32
|
+
request_headers: '{}',
|
|
33
|
+
request_body: '',
|
|
34
|
+
request_url: 'http://www.test.com/1',
|
|
35
|
+
request_method: 'GET',
|
|
36
|
+
response_headers: '{}',
|
|
37
|
+
response_body: '{}',
|
|
38
|
+
response_status: '200'
|
|
39
|
+
}.stringify_keys,
|
|
40
|
+
{
|
|
41
|
+
application_id: 1,
|
|
42
|
+
request_headers: '{}',
|
|
43
|
+
request_body: '',
|
|
44
|
+
request_url: 'http://www.test.com/2',
|
|
45
|
+
request_method: 'GET',
|
|
46
|
+
response_headers: '{}',
|
|
47
|
+
response_body: '{}',
|
|
48
|
+
response_status: '200'
|
|
49
|
+
}.stringify_keys,
|
|
50
|
+
{
|
|
51
|
+
application_id: 1,
|
|
52
|
+
request_headers: '{}',
|
|
53
|
+
request_body: '',
|
|
54
|
+
request_url: 'http://www.test.com/3',
|
|
55
|
+
request_method: 'GET',
|
|
56
|
+
response_headers: '{}',
|
|
57
|
+
response_body: '{}',
|
|
58
|
+
response_status: '200'
|
|
59
|
+
}.stringify_keys
|
|
60
|
+
]
|
|
61
|
+
end
|
|
62
|
+
before :each do
|
|
63
|
+
expect(recordings_assoc_class).to receive(:page).and_return recordings_assoc_class
|
|
64
|
+
expect(recordings_assoc_class).to receive(:per).and_return recordings_assoc_class
|
|
65
|
+
expect(recordings_assoc_class).to receive(:padding).and_return recordings_assoc_class
|
|
66
|
+
expect(recordings_assoc_class).to receive(:total_count).and_return 3
|
|
67
|
+
expect(recordings_assoc_class).to receive(:num_pages).and_return 1
|
|
68
|
+
expect(recordings_assoc_class).to receive(:current_page).and_return 1
|
|
69
|
+
expect(recordings_assoc_class).to receive(:next_page).and_return 1
|
|
70
|
+
expect(recordings_assoc_class).to receive(:prev_page).and_return 1
|
|
71
|
+
expect(recordings_assoc_class).to receive(:count).and_return 3
|
|
72
|
+
expect(recordings_assoc_class).to receive(:as_json).with({}).and_return recordings_result
|
|
73
|
+
|
|
74
|
+
end
|
|
75
|
+
it 'returns a populated array of recordings' do
|
|
76
|
+
get '/v1/users/1/applications/1/recordings'
|
|
77
|
+
expect(last_response.status).to eq(200)
|
|
78
|
+
expect(JSON.parse(last_response.body)).to eq('recordings' => recordings_result, 'total' => 3)
|
|
79
|
+
end
|
|
80
|
+
end
|
|
81
|
+
describe 'DELETE /users/1/applications/1/recordings' do
|
|
82
|
+
it 'Should destroy all applications for the user' do
|
|
83
|
+
expect(recordings_assoc_class).to receive(:destroy_all)
|
|
84
|
+
delete '/v1/users/1/applications/1/recordings'
|
|
85
|
+
expect(last_response.status).to eq(200)
|
|
86
|
+
expect(JSON.parse(last_response.body).symbolize_keys).to eql(recordings: [], total: 0)
|
|
87
|
+
end
|
|
88
|
+
end
|
|
89
|
+
describe '/users/1/applications/1/recordings/10' do
|
|
90
|
+
let(:recording_instance) { recordings_assoc_class.new }
|
|
91
|
+
let(:persisted_attributes) { { request_headers: '', response_headers: {} } }
|
|
92
|
+
before :each do
|
|
93
|
+
expect(recordings_assoc_class).to receive(:where).with(id: '10').and_return recordings_assoc_class
|
|
94
|
+
expect(recordings_assoc_class).to receive(:first).and_return recording_instance
|
|
95
|
+
expect(recording_instance).to receive(:as_json).with({}).and_return persisted_attributes
|
|
96
|
+
end
|
|
97
|
+
context 'GET' do
|
|
98
|
+
it 'Should fetch an individual recording' do
|
|
99
|
+
get '/v1/users/1/applications/1/recordings/10'
|
|
100
|
+
expect(last_response.status).to eq(200)
|
|
101
|
+
expect(JSON.parse(last_response.body).symbolize_keys).to eql(persisted_attributes)
|
|
102
|
+
|
|
103
|
+
end
|
|
104
|
+
end
|
|
105
|
+
context 'DELETE' do
|
|
106
|
+
it 'Should delete an individual recording' do
|
|
107
|
+
expect(recording_instance).to receive(:destroy)
|
|
108
|
+
delete '/v1/users/1/applications/1/recordings/10'
|
|
109
|
+
expect(last_response.status).to eq(200)
|
|
110
|
+
expect(JSON.parse(last_response.body).symbolize_keys).to eql(persisted_attributes)
|
|
111
|
+
end
|
|
112
|
+
end
|
|
113
|
+
end
|
|
114
|
+
|
|
115
|
+
end
|
|
@@ -0,0 +1,159 @@
|
|
|
1
|
+
require 'spec_helper'
|
|
2
|
+
require_relative 'common_helper'
|
|
3
|
+
require 'rack/test'
|
|
4
|
+
|
|
5
|
+
describe AgileProxy::Api::RequestSpecs, api_test: true do
|
|
6
|
+
include Rack::Test::Methods
|
|
7
|
+
include AgileProxy::Test::Api::Common
|
|
8
|
+
let(:applications_assoc_class) do
|
|
9
|
+
Class.new do
|
|
10
|
+
end
|
|
11
|
+
end
|
|
12
|
+
let(:request_spec_assoc_class) do
|
|
13
|
+
Class.new do
|
|
14
|
+
def self.destroy_all
|
|
15
|
+
end
|
|
16
|
+
end
|
|
17
|
+
end
|
|
18
|
+
let(:application_instance) { applications_assoc_class.new }
|
|
19
|
+
before :each do
|
|
20
|
+
expect(current_user).to receive(:applications).at_least(:once).and_return(applications_assoc_class)
|
|
21
|
+
expect(applications_assoc_class).to receive(:where).with(id: '1').at_least(:once).and_return applications_assoc_class
|
|
22
|
+
expect(applications_assoc_class).to receive(:first).at_least(:once).and_return application_instance
|
|
23
|
+
expect(application_instance).to receive(:request_specs).and_return request_spec_assoc_class
|
|
24
|
+
end
|
|
25
|
+
let(:default_json_spec) { { include: { response: { except: [:created_at, :updated_at] } } } }
|
|
26
|
+
|
|
27
|
+
# def mock_collection_data
|
|
28
|
+
# @__all_request_specs ||= [double('HttpFlexiblePrAgileProxy', :id => 1),double('AgileProxy::ReAgileProxy=> 2),double('AgileProxy::RequestSpAgileProxyeach do |d|
|
|
29
|
+
# allow(d).to receive(:as_json).with(default_json_spec).and_return({:spec => "Spec #{d.id}"}.as_json)
|
|
30
|
+
# end
|
|
31
|
+
# end
|
|
32
|
+
# def mock_collection_association
|
|
33
|
+
# return @__mock_collection_association if @__mock_collection_association.present?
|
|
34
|
+
# @__mock_collection_association = double('Mock Association')
|
|
35
|
+
# @__mock_collection_association.tap do |o|
|
|
36
|
+
# allow(o).to receive(:total_count).and_return 3
|
|
37
|
+
# allow(o).to receive(:num_pages).and_return 1
|
|
38
|
+
# allow(o).to receive(:current_page).and_return 1
|
|
39
|
+
# allow(o).to receive(:next_page).and_return nil
|
|
40
|
+
# allow(o).to receive(:prev_page).and_return nil
|
|
41
|
+
# allow(o).to receive(:page).and_return o
|
|
42
|
+
# allow(o).to receive(:per).and_return o
|
|
43
|
+
# allow(o).to receive(:padding).and_return o
|
|
44
|
+
# end
|
|
45
|
+
# allow(@__mock_collection_association).to receive(:as_json).with(default_json_spec).and_return(mock_collection_data.as_json(default_json_spec))
|
|
46
|
+
# allow(@__mock_collection_association).to receive(:count).and_return 3
|
|
47
|
+
# allow(@__mock_collection_association).to receive(:where) do |options|
|
|
48
|
+
# if options.key?(:id)
|
|
49
|
+
# mock_collection_data.select{|r| r.id.to_s == options[:id]}
|
|
50
|
+
# else
|
|
51
|
+
# throw "mock_collection_association called with an unknown where clause of #{where.to_json}"
|
|
52
|
+
# end
|
|
53
|
+
# end
|
|
54
|
+
# @__mock_collection_association
|
|
55
|
+
# end
|
|
56
|
+
# def created_member(attrs)
|
|
57
|
+
# double("AgileProxy::RequestSpec", attrs.merge({:as_json => {"spec" => attrs[:spec]}}))
|
|
58
|
+
# end
|
|
59
|
+
describe 'GET /users/1/applications/1/request_specs' do
|
|
60
|
+
let(:request_specs_result) do
|
|
61
|
+
[{ 'spec' => 'Spec 1' }, { 'spec' => 'Spec 2' }, { 'spec' => 'Spec 3' }]
|
|
62
|
+
end
|
|
63
|
+
before :each do
|
|
64
|
+
expect(request_spec_assoc_class).to receive(:page).and_return request_spec_assoc_class
|
|
65
|
+
expect(request_spec_assoc_class).to receive(:per).and_return request_spec_assoc_class
|
|
66
|
+
expect(request_spec_assoc_class).to receive(:padding).and_return request_spec_assoc_class
|
|
67
|
+
expect(request_spec_assoc_class).to receive(:total_count).and_return 3
|
|
68
|
+
expect(request_spec_assoc_class).to receive(:num_pages).and_return 1
|
|
69
|
+
expect(request_spec_assoc_class).to receive(:current_page).and_return 1
|
|
70
|
+
expect(request_spec_assoc_class).to receive(:next_page).and_return 1
|
|
71
|
+
expect(request_spec_assoc_class).to receive(:prev_page).and_return 1
|
|
72
|
+
expect(request_spec_assoc_class).to receive(:count).and_return 3
|
|
73
|
+
expect(request_spec_assoc_class).to receive(:as_json).with(default_json_spec).and_return request_specs_result
|
|
74
|
+
end
|
|
75
|
+
it 'returns a populated array of request specs' do
|
|
76
|
+
get '/v1/users/1/applications/1/request_specs'
|
|
77
|
+
expect(last_response.status).to eq(200)
|
|
78
|
+
expect(JSON.parse(last_response.body)).to eq('request_specs' => [{ 'spec' => 'Spec 1' }, { 'spec' => 'Spec 2' }, { 'spec' => 'Spec 3' }], 'total' => 3)
|
|
79
|
+
end
|
|
80
|
+
it 'Should not list items from a different application'
|
|
81
|
+
it 'Should not list items that belong to a different user'
|
|
82
|
+
end
|
|
83
|
+
describe '/users/1/applications/1/request_specs/2' do
|
|
84
|
+
let(:request_spec_instance) { request_spec_assoc_class.new }
|
|
85
|
+
let(:persisted_attributes) { { user_id: 1, application_id: 1, url: 'http://www.test.com', http_method: 'GET' } }
|
|
86
|
+
before :each do
|
|
87
|
+
expect(request_spec_assoc_class).to receive(:where).with(id: '2').and_return request_spec_assoc_class
|
|
88
|
+
expect(request_spec_assoc_class).to receive(:first).and_return request_spec_instance
|
|
89
|
+
expect(request_spec_instance).to receive(:as_json).with(default_json_spec).and_return persisted_attributes
|
|
90
|
+
end
|
|
91
|
+
describe 'GET' do
|
|
92
|
+
it 'returns a single item in json format' do
|
|
93
|
+
get '/v1/users/1/applications/1/request_specs/2'
|
|
94
|
+
expect(last_response.status).to eq(200)
|
|
95
|
+
expect(JSON.parse(last_response.body).symbolize_keys).to eq(persisted_attributes)
|
|
96
|
+
end
|
|
97
|
+
it 'Should not find a request spec which does not belong to the application specified'
|
|
98
|
+
it 'Should not find a request spec which does not belong to the user specified'
|
|
99
|
+
end
|
|
100
|
+
describe 'PUT' do
|
|
101
|
+
it 'Should update an existing item with the attributes given' do
|
|
102
|
+
expect(current_user).to receive(:id).and_return(1)
|
|
103
|
+
expect(application_instance).to receive(:id).and_return(1)
|
|
104
|
+
expect(request_spec_instance).to receive(:update_attributes).with(spec: 'Renamed Spec 2', user_id: 1, application_id: 1).and_return true
|
|
105
|
+
put '/v1/users/1/applications/1/request_specs/2', { spec: 'Renamed Spec 2' }.to_json, 'CONTENT_TYPE' => 'application/json'
|
|
106
|
+
expect(last_response.status).to eq 200
|
|
107
|
+
expect(JSON.parse(last_response.body).symbolize_keys).to eq(persisted_attributes) # Note that the mocked update_attributes doesnt actually update so the original json is expected
|
|
108
|
+
end
|
|
109
|
+
end
|
|
110
|
+
describe 'DELETE' do
|
|
111
|
+
it 'Should delete the existing item and return it in json form' do
|
|
112
|
+
expect(request_spec_instance).to receive(:destroy)
|
|
113
|
+
delete '/v1/users/1/applications/1/request_specs/2'
|
|
114
|
+
expect(last_response.status).to eq 200
|
|
115
|
+
expect(JSON.parse(last_response.body).symbolize_keys).to eq(persisted_attributes)
|
|
116
|
+
end
|
|
117
|
+
it 'Should not allow deleting of other peoples request specs'
|
|
118
|
+
end
|
|
119
|
+
end
|
|
120
|
+
describe 'POST /users/1/applications/1/request_specs' do
|
|
121
|
+
let(:request_spec_instance) { request_spec_assoc_class.new }
|
|
122
|
+
let(:persisted_attributes) { { user_id: 1, application_id: 1, url: 'http://www.test.com', http_method: 'GET' } }
|
|
123
|
+
before :each do
|
|
124
|
+
expect(request_spec_instance).to receive(:as_json).with(default_json_spec).and_return(persisted_attributes)
|
|
125
|
+
expect(current_user).to receive(:id).and_return(1)
|
|
126
|
+
expect(application_instance).to receive(:id).and_return(1)
|
|
127
|
+
end
|
|
128
|
+
it 'Should create a new item with the correct attributes set' do
|
|
129
|
+
expect(request_spec_assoc_class).to receive(:create).with(spec: 'Spec 4', user_id: 1, application_id: 1).and_return request_spec_instance
|
|
130
|
+
post '/v1/users/1/applications/1/request_specs', { spec: 'Spec 4' }.to_json, 'CONTENT_TYPE' => 'application/json'
|
|
131
|
+
expect([200, 201]).to include(last_response.status)
|
|
132
|
+
expect(JSON.parse(last_response.body).symbolize_keys).to eq(persisted_attributes)
|
|
133
|
+
end
|
|
134
|
+
it 'Should allow creating of a response object also' do
|
|
135
|
+
response_attributes = { name: 'Test Response', content: '<h1>Hello World</h1>', content_type: 'text/html', status_code: 200, headers: '{}', is_template: false }
|
|
136
|
+
expect(request_spec_assoc_class).to receive(:create).with(spec: 'Spec 4', user_id: 1, application_id: 1, response_attributes: Hashie::Mash.new(response_attributes)).and_return request_spec_instance
|
|
137
|
+
post '/v1/users/1/applications/1/request_specs', { spec: 'Spec 4', response: response_attributes }.to_json, 'CONTENT_TYPE' => 'application/json'
|
|
138
|
+
expect([200, 201]).to include(last_response.status)
|
|
139
|
+
expect(JSON.parse(last_response.body).symbolize_keys).to eq(persisted_attributes)
|
|
140
|
+
end
|
|
141
|
+
it 'Should inform the router of the new entry'
|
|
142
|
+
it 'Should not allow the user to specify the user_id to prevent creating for a different user'
|
|
143
|
+
it 'Should not allow setting of an application_id which doesnt belong to the current user'
|
|
144
|
+
end
|
|
145
|
+
describe 'DELETE /users/1/applications/1/request_specs' do
|
|
146
|
+
before :each do
|
|
147
|
+
expect(request_spec_assoc_class).to receive(:delete_all)
|
|
148
|
+
end
|
|
149
|
+
it 'Should delete all request specs for the users application' do
|
|
150
|
+
delete '/v1/users/1/applications/1/request_specs'
|
|
151
|
+
expect(JSON.parse(last_response.body).symbolize_keys).to eq(request_specs: [], total: 0)
|
|
152
|
+
|
|
153
|
+
end
|
|
154
|
+
end
|
|
155
|
+
it 'Should not find other peoples request specs to update'
|
|
156
|
+
it 'Should not allow updates of the user_id to prevent changing ownership'
|
|
157
|
+
it 'Should not allow updates of the application_id to prevent changing ownership via the application'
|
|
158
|
+
it 'Should inform the router of the update if the spec or response has changed'
|
|
159
|
+
end
|