agile-proxy 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (103) hide show
  1. checksums.yaml +7 -0
  2. data/.bowerrc +3 -0
  3. data/.gitignore +8 -0
  4. data/.rspec +2 -0
  5. data/.rubocop.yml +36 -0
  6. data/.travis.yml +8 -0
  7. data/Gemfile +4 -0
  8. data/Gemfile.lock +267 -0
  9. data/Guardfile +20 -0
  10. data/LICENSE +22 -0
  11. data/README.md +93 -0
  12. data/Rakefile +13 -0
  13. data/agile-proxy.gemspec +50 -0
  14. data/assets/index.html +39 -0
  15. data/assets/ui/app/HttpFlexibleProxyApi.js +31 -0
  16. data/assets/ui/app/app.js +1 -0
  17. data/assets/ui/app/controller/Stubs.js +64 -0
  18. data/assets/ui/app/controller/main.js +12 -0
  19. data/assets/ui/app/directive/AppEnhancedFormElement.js +21 -0
  20. data/assets/ui/app/directive/AppFor.js +16 -0
  21. data/assets/ui/app/directive/AppResponseEditor.js +54 -0
  22. data/assets/ui/app/model/RequestSpec.js +6 -0
  23. data/assets/ui/app/routes.js +10 -0
  24. data/assets/ui/app/service/Dialog.js +49 -0
  25. data/assets/ui/app/service/DomId.js +10 -0
  26. data/assets/ui/app/service/Error.js +7 -0
  27. data/assets/ui/app/service/Stub.js +36 -0
  28. data/assets/ui/app/view/404.html +2 -0
  29. data/assets/ui/app/view/dialog/error.html +10 -0
  30. data/assets/ui/app/view/dialog/yesNo.html +8 -0
  31. data/assets/ui/app/view/responses/editForm.html +78 -0
  32. data/assets/ui/app/view/status.html +1 -0
  33. data/assets/ui/app/view/stubs.html +19 -0
  34. data/assets/ui/app/view/stubs/edit.html +58 -0
  35. data/assets/ui/css/main.css +3 -0
  36. data/bin/agile_proxy +113 -0
  37. data/bower.json +27 -0
  38. data/config.yml +6 -0
  39. data/db.yml +10 -0
  40. data/db/migrations/20140818110800_create_users.rb +9 -0
  41. data/db/migrations/20140818134700_create_applications.rb +10 -0
  42. data/db/migrations/20140818135200_create_request_specs.rb +13 -0
  43. data/db/migrations/20140821115300_create_responses.rb +14 -0
  44. data/db/migrations/20140823082900_add_method_to_request_specs.rb +7 -0
  45. data/db/migrations/20140823083900_rename_request_spec_columns.rb +8 -0
  46. data/db/migrations/20141031072100_add_url_type_to_request_specs.rb +8 -0
  47. data/db/migrations/20141105125600_add_conditions_to_request_specs.rb +7 -0
  48. data/db/migrations/20141106083100_add_username_and_password_to_applications.rb +8 -0
  49. data/db/migrations/20141119143800_add_record_to_applications.rb +7 -0
  50. data/db/migrations/20141119174300_create_recordings.rb +18 -0
  51. data/db/schema.rb +78 -0
  52. data/examples/README.md +1 -0
  53. data/examples/facebook_api.html +59 -0
  54. data/examples/tumblr_api.html +22 -0
  55. data/lib/agile_proxy.rb +8 -0
  56. data/lib/agile_proxy/api/applications.rb +77 -0
  57. data/lib/agile_proxy/api/recordings.rb +52 -0
  58. data/lib/agile_proxy/api/request_specs.rb +85 -0
  59. data/lib/agile_proxy/api/root.rb +41 -0
  60. data/lib/agile_proxy/config.rb +63 -0
  61. data/lib/agile_proxy/handlers/handler.rb +43 -0
  62. data/lib/agile_proxy/handlers/proxy_handler.rb +110 -0
  63. data/lib/agile_proxy/handlers/request_handler.rb +57 -0
  64. data/lib/agile_proxy/handlers/stub_handler.rb +113 -0
  65. data/lib/agile_proxy/mitm.crt +22 -0
  66. data/lib/agile_proxy/mitm.key +27 -0
  67. data/lib/agile_proxy/model/application.rb +20 -0
  68. data/lib/agile_proxy/model/recording.rb +16 -0
  69. data/lib/agile_proxy/model/request_spec.rb +47 -0
  70. data/lib/agile_proxy/model/response.rb +56 -0
  71. data/lib/agile_proxy/model/user.rb +17 -0
  72. data/lib/agile_proxy/proxy_connection.rb +113 -0
  73. data/lib/agile_proxy/route.rb +106 -0
  74. data/lib/agile_proxy/router.rb +99 -0
  75. data/lib/agile_proxy/server.rb +85 -0
  76. data/lib/agile_proxy/servers/api.rb +41 -0
  77. data/lib/agile_proxy/servers/request_spec.rb +30 -0
  78. data/lib/agile_proxy/version.rb +6 -0
  79. data/load_proxy.js +39 -0
  80. data/log/.gitkeep +0 -0
  81. data/spec/common_helper.rb +32 -0
  82. data/spec/fixtures/test-server.crt +15 -0
  83. data/spec/fixtures/test-server.key +15 -0
  84. data/spec/integration/helpers/request_spec_helper.rb +60 -0
  85. data/spec/integration/specs/lib/server_spec.rb +407 -0
  86. data/spec/integration_spec_helper.rb +18 -0
  87. data/spec/spec_helper.rb +39 -0
  88. data/spec/support/test_server.rb +75 -0
  89. data/spec/unit/agile_proxy/api/applications_spec.rb +102 -0
  90. data/spec/unit/agile_proxy/api/common_helper.rb +31 -0
  91. data/spec/unit/agile_proxy/api/recordings_spec.rb +115 -0
  92. data/spec/unit/agile_proxy/api/request_specs_spec.rb +159 -0
  93. data/spec/unit/agile_proxy/handlers/handler_spec.rb +8 -0
  94. data/spec/unit/agile_proxy/handlers/proxy_handler_spec.rb +138 -0
  95. data/spec/unit/agile_proxy/handlers/request_handler_spec.rb +55 -0
  96. data/spec/unit/agile_proxy/handlers/stub_handler_spec.rb +154 -0
  97. data/spec/unit/agile_proxy/model/recording_spec.rb +0 -0
  98. data/spec/unit/agile_proxy/model/request_spec_spec.rb +45 -0
  99. data/spec/unit/agile_proxy/model/response_spec.rb +38 -0
  100. data/spec/unit/agile_proxy/server_spec.rb +88 -0
  101. data/spec/unit/agile_proxy/servers/api_spec.rb +31 -0
  102. data/spec/unit/agile_proxy/servers/request_spec_spec.rb +32 -0
  103. 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
@@ -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