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.
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