axel 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (128) hide show
  1. checksums.yaml +15 -0
  2. data/.gitignore +21 -0
  3. data/.octopolo.yml +2 -0
  4. data/.rspec +2 -0
  5. data/.ruby-gemset +1 -0
  6. data/.ruby-version +1 -0
  7. data/.travis.yml +23 -0
  8. data/Gemfile +4 -0
  9. data/LICENSE.txt +22 -0
  10. data/README.md +271 -0
  11. data/Rakefile +13 -0
  12. data/app/models/axel/api_proxy.rb +86 -0
  13. data/app/models/axel/associations/base.rb +64 -0
  14. data/app/models/axel/associations/belongs_to.rb +43 -0
  15. data/app/models/axel/associations/has_many.rb +29 -0
  16. data/app/models/axel/associations/has_one.rb +30 -0
  17. data/app/models/axel/payload.rb +4 -0
  18. data/app/models/axel/payload/base.rb +107 -0
  19. data/app/models/axel/payload/errors.rb +62 -0
  20. data/app/models/axel/payload/metadata.rb +57 -0
  21. data/app/models/axel/querier.rb +166 -0
  22. data/app/models/axel/router.rb +119 -0
  23. data/app/models/axel/service_resource.rb +4 -0
  24. data/app/models/axel/service_resource/associations.rb +80 -0
  25. data/app/models/axel/service_resource/attributes.rb +23 -0
  26. data/app/models/axel/service_resource/automatic_resource.rb +23 -0
  27. data/app/models/axel/service_resource/base.rb +47 -0
  28. data/app/models/axel/service_resource/builder.rb +40 -0
  29. data/app/models/axel/service_resource/inspects.rb +17 -0
  30. data/app/models/axel/service_resource/payload_parser.rb +46 -0
  31. data/app/models/axel/service_resource/queries.rb +25 -0
  32. data/app/models/axel/service_resource/requesters.rb +49 -0
  33. data/app/models/axel/service_resource/routes.rb +19 -0
  34. data/app/models/axel/service_resource/typhoid_extensions.rb +134 -0
  35. data/app/views/axel/base/empty.json.erb +0 -0
  36. data/app/views/axel/base/empty.xml.builder +0 -0
  37. data/app/views/layouts/axel.json.jbuilder +7 -0
  38. data/app/views/layouts/axel.xml.builder +12 -0
  39. data/axel.gemspec +42 -0
  40. data/lib/axel.rb +56 -0
  41. data/lib/axel/application_extensions.rb +13 -0
  42. data/lib/axel/application_helper.rb +27 -0
  43. data/lib/axel/base_controller.rb +6 -0
  44. data/lib/axel/cascadable_attribute.rb +33 -0
  45. data/lib/axel/configurations/resource.rb +29 -0
  46. data/lib/axel/configurations/service.rb +28 -0
  47. data/lib/axel/configurator.rb +54 -0
  48. data/lib/axel/configurators/services.rb +29 -0
  49. data/lib/axel/controller_base.rb +27 -0
  50. data/lib/axel/controller_helpers.rb +209 -0
  51. data/lib/axel/controller_parameters.rb +32 -0
  52. data/lib/axel/engine.rb +14 -0
  53. data/lib/axel/inspector.rb +91 -0
  54. data/lib/axel/payload/remote_error.rb +14 -0
  55. data/lib/axel/request_options.rb +26 -0
  56. data/lib/axel/uri.rb +47 -0
  57. data/lib/axel/version.rb +3 -0
  58. data/lib/generators/axel/install_generator.rb +16 -0
  59. data/lib/generators/templates/README.md +22 -0
  60. data/lib/generators/templates/axel.rb +81 -0
  61. data/script/rails +5 -0
  62. data/spec/controllers/pages_controller_spec.rb +217 -0
  63. data/spec/dummy/README.rdoc +261 -0
  64. data/spec/dummy/Rakefile +7 -0
  65. data/spec/dummy/app/assets/javascripts/application.js +15 -0
  66. data/spec/dummy/app/assets/stylesheets/application.css +13 -0
  67. data/spec/dummy/app/controllers/application_controller.rb +3 -0
  68. data/spec/dummy/app/controllers/pages_controller.rb +6 -0
  69. data/spec/dummy/app/helpers/application_helper.rb +2 -0
  70. data/spec/dummy/app/mailers/.gitkeep +0 -0
  71. data/spec/dummy/app/models/.gitkeep +0 -0
  72. data/spec/dummy/app/views/layouts/application.html.erb +14 -0
  73. data/spec/dummy/config.ru +4 -0
  74. data/spec/dummy/config/application.rb +62 -0
  75. data/spec/dummy/config/boot.rb +10 -0
  76. data/spec/dummy/config/database.yml +25 -0
  77. data/spec/dummy/config/environment.rb +5 -0
  78. data/spec/dummy/config/environments/development.rb +37 -0
  79. data/spec/dummy/config/environments/production.rb +67 -0
  80. data/spec/dummy/config/environments/test.rb +37 -0
  81. data/spec/dummy/config/initializers/backtrace_silencers.rb +7 -0
  82. data/spec/dummy/config/initializers/inflections.rb +15 -0
  83. data/spec/dummy/config/initializers/mime_types.rb +5 -0
  84. data/spec/dummy/config/initializers/secret_token.rb +7 -0
  85. data/spec/dummy/config/initializers/session_store.rb +8 -0
  86. data/spec/dummy/config/initializers/wrap_parameters.rb +14 -0
  87. data/spec/dummy/config/locales/en.yml +5 -0
  88. data/spec/dummy/config/routes.rb +3 -0
  89. data/spec/dummy/db/development.sqlite3 +0 -0
  90. data/spec/dummy/db/test.sqlite3 +0 -0
  91. data/spec/dummy/lib/assets/.gitkeep +0 -0
  92. data/spec/dummy/log/.gitignore +1 -0
  93. data/spec/dummy/log/.gitkeep +0 -0
  94. data/spec/dummy/public/404.html +26 -0
  95. data/spec/dummy/public/422.html +26 -0
  96. data/spec/dummy/public/500.html +25 -0
  97. data/spec/dummy/public/favicon.ico +0 -0
  98. data/spec/dummy/script/rails +6 -0
  99. data/spec/envelope_integration_check.rb +96 -0
  100. data/spec/helpers/axel/application_helper_spec.rb +31 -0
  101. data/spec/lib/axel/associations/base_spec.rb +28 -0
  102. data/spec/lib/axel/associations/belongs_to_spec.rb +62 -0
  103. data/spec/lib/axel/associations/has_many_spec.rb +23 -0
  104. data/spec/lib/axel/associations/has_one_spec.rb +23 -0
  105. data/spec/lib/axel/configurations/resource_spec.rb +15 -0
  106. data/spec/lib/axel/configurations/service_spec.rb +31 -0
  107. data/spec/lib/axel/configurator_spec.rb +26 -0
  108. data/spec/lib/axel/configurators/services_spec.rb +37 -0
  109. data/spec/lib/axel/controller_base_spec.rb +16 -0
  110. data/spec/lib/axel/controller_parameters_spec.rb +31 -0
  111. data/spec/lib/axel/inspector_spec.rb +45 -0
  112. data/spec/lib/axel/request_options_spec.rb +50 -0
  113. data/spec/lib/axel/uri_spec.rb +42 -0
  114. data/spec/lib/axel_spec.rb +64 -0
  115. data/spec/models/axel/api_proxy_spec.rb +66 -0
  116. data/spec/models/axel/payload/errors_spec.rb +165 -0
  117. data/spec/models/axel/payload/metadata_spec.rb +141 -0
  118. data/spec/models/axel/querier_spec.rb +158 -0
  119. data/spec/models/axel/router_spec.rb +115 -0
  120. data/spec/models/axel/service_resource/base_spec.rb +244 -0
  121. data/spec/models/axel/service_resource/builder_spec.rb +64 -0
  122. data/spec/models/axel/service_resource/payload_parser_spec.rb +60 -0
  123. data/spec/spec_helper.rb +39 -0
  124. data/spec/support/address.rb +5 -0
  125. data/spec/support/persona.rb +15 -0
  126. data/spec/support/user.rb +6 -0
  127. data/spec/views/axel/base/empty_spec.rb +34 -0
  128. metadata +508 -0
@@ -0,0 +1,16 @@
1
+ require 'spec_helper'
2
+
3
+ # So we don't have to add rails-api as a dependency
4
+ ActionController::API = ActionController::Base
5
+ module Axel
6
+ describe ControllerBase do
7
+ its(:configured) { should == ::ActionController::Base }
8
+ context "configured to use rails api" do
9
+ before do
10
+ subject.send(:config).stub uses_rails_api?: true
11
+ end
12
+
13
+ its(:configured) { should == ActionController::API }
14
+ end
15
+ end
16
+ end
@@ -0,0 +1,31 @@
1
+ require 'spec_helper'
2
+
3
+ module Axel
4
+ describe ControllerParameters do
5
+ subject { ControllerParameters.new original_params }
6
+ let(:original_params) { {} }
7
+ let(:params_class) { double }
8
+ it { should respond_to :params_object }
9
+
10
+ describe "with strong params defined" do
11
+ before do
12
+ subject.stub strong_params?: true, params_class: params_class
13
+ end
14
+
15
+ it "creates strong params" do
16
+ params_class.should_receive(:new).with(original_params).once
17
+ subject.params_object
18
+ end
19
+ end
20
+
21
+ describe "without strong params defined" do
22
+ before do
23
+ subject.stub strong_params?: false
24
+ end
25
+
26
+ it "returns the original object" do
27
+ subject.params_object.should be original_params
28
+ end
29
+ end
30
+ end
31
+ end
@@ -0,0 +1,45 @@
1
+ require 'spec_helper'
2
+ module Axel
3
+ describe Inspector do
4
+ subject { Inspector.new object, parens, attributes }
5
+ let(:object) { double(id: 1, name: "Jon", request_uri: "http://some-url/users/1") }
6
+ let(:parens) { [:request_uri] }
7
+ let(:attributes) { { id: 1, name: "Jon" } }
8
+
9
+ its(:object) { should == object }
10
+ it "retrieves parens_params keys" do
11
+ subject.parens_params.keys.should == parens
12
+ end
13
+ its(:attributes) { should == attributes }
14
+
15
+ describe "with parens and attributes set" do
16
+ its(:inspect) { should == "#<RSpec::Mocks::Double(\"http://some-url/users/1\") id: 1, name: \"Jon\">" }
17
+ end
18
+
19
+ describe "with an erroring parens attribute" do
20
+ before { object.stub(:request_uri) { raise "No good" } }
21
+ its(:inspect) { should == "#<RSpec::Mocks::Double(nil) id: 1, name: \"Jon\">" }
22
+ end
23
+
24
+ describe "without parens" do
25
+ let(:parens) { nil }
26
+ its(:inspect) { should == "#<RSpec::Mocks::Double id: 1, name: \"Jon\">" }
27
+ end
28
+
29
+ describe "without attributes" do
30
+ let(:attributes) { nil }
31
+ its(:inspect) { should == "#<RSpec::Mocks::Double(\"http://some-url/users/1\")>" }
32
+ end
33
+
34
+ describe "with a class" do
35
+ before do
36
+ subject.stub class?: true
37
+ end
38
+
39
+ let(:object) { double request_uri: "http://example_uri/users", name: "MyClass" }
40
+ let(:parens) { [:request_uri] }
41
+ let(:attributes) { nil }
42
+ its(:inspect) { should == "MyClass(\"http://example_uri/users\")" }
43
+ end
44
+ end
45
+ end
@@ -0,0 +1,50 @@
1
+ require 'axel/request_options'
2
+ module Axel
3
+ describe RequestOptions do
4
+ subject { RequestOptions.new nil, example_options }
5
+ let(:example_options) { {} }
6
+
7
+ it "compiles with the default headers" do
8
+ subject.compiled.should == {
9
+ 'headers' => {
10
+ 'Content-Type' => 'application/json'
11
+ },
12
+ }
13
+ end
14
+
15
+ describe "non-conflicting params" do
16
+ let(:example_options) { { params: { id: 1 } } }
17
+ it "compiles with the non-conflicting params" do
18
+ subject.compiled.should == {
19
+ 'params' => { 'id' => 1 },
20
+ 'headers' => {
21
+ 'Content-Type' => 'application/json'
22
+ },
23
+ }
24
+ end
25
+ end
26
+
27
+ describe "slightly-conflicting params" do
28
+ let(:example_options) { { headers: { id: 1 } } }
29
+ it "compiles with the non-conflicting params" do
30
+ subject.compiled.should == {
31
+ 'headers' => {
32
+ 'id' => 1,
33
+ 'Content-Type' => 'application/json'
34
+ },
35
+ }
36
+ end
37
+ end
38
+
39
+ describe "truly-conflicting params" do
40
+ let(:example_options) { { headers: { "Content-Type" => 1 } } }
41
+ it "compiles with the non-conflicting params" do
42
+ subject.compiled.should == {
43
+ 'headers' => {
44
+ 'Content-Type' => 1
45
+ },
46
+ }
47
+ end
48
+ end
49
+ end
50
+ end
@@ -0,0 +1,42 @@
1
+ require 'spec_helper'
2
+ module Axel
3
+ describe "Uri" do
4
+ subject { Uri.new base_url }
5
+ let(:base_url) { "http://user-service.stage.com/users" }
6
+
7
+ before do
8
+ subject.stub config: {
9
+ dev: {
10
+ host: ".dev",
11
+ scheme: "http"
12
+ },
13
+ stage: {
14
+ host: ->(base, n) { "#{base}.stage#{n}.com" },
15
+ scheme: "https"
16
+ },
17
+ prod: {
18
+ host: ".your-platform.com",
19
+ scheme: "https"
20
+ }
21
+ }
22
+ end
23
+ it "to dev switches out the stage URI for .dev" do
24
+ subject.to(:dev).to_s.should == "http://user-service.dev/users"
25
+ end
26
+
27
+ it "for stage" do
28
+ subject.to(:stage).to_s.should == "https://user-service.stage.com/users"
29
+ end
30
+
31
+ it "for stage n" do
32
+ subject.to(:stage, 2).to_s.should == "https://user-service.stage2.com/users"
33
+ end
34
+
35
+ it "for prod" do
36
+ subject.to(:prod).to_s.should == "https://user-service.your-platform.com/users"
37
+ end
38
+
39
+ its(:dashed_app_name) { should == "user-service" }
40
+ its(:app_name) { should == "User Service" }
41
+ end
42
+ end
@@ -0,0 +1,64 @@
1
+ require 'spec_helper'
2
+ describe Axel do
3
+ subject { Axel }
4
+
5
+ context "services" do
6
+ it { subject.service_configurator.should be_a Axel::Configurators::Services }
7
+ end
8
+
9
+ context "config" do
10
+ context "with stubs" do
11
+ context "block checks" do
12
+ context "with block" do
13
+ specify do
14
+ expect { |b| subject.config &b }.to yield_with_args
15
+ end
16
+ end
17
+ end
18
+ end
19
+
20
+ context "once" do
21
+ before do
22
+ subject.config do |config|
23
+ config.add_resource :user_service, :user, service: { url: "http://user-service.dev" }
24
+ end
25
+ end
26
+
27
+ it "sets a user service with a configuration" do
28
+ subject.services[:user_service].should be_a Axel::Configurations::Service
29
+ end
30
+
31
+ it "sets a resource configuration" do
32
+ subject.resources[:user].should be_a Axel::Configurations::Resource
33
+ end
34
+
35
+ context "twice" do
36
+ before do
37
+ subject.config do |config|
38
+ config.add_resource :api_proxy, :registry, service: { url: "http://api-proxy.dev" }
39
+ config.add_resource :user_service, :persona
40
+ end
41
+ end
42
+ it "sets a user service with a configuration" do
43
+ subject.services[:user_service].should be_a Axel::Configurations::Service
44
+ end
45
+
46
+ it "sets a user resource configuration" do
47
+ subject.resources[:user].should be_a Axel::Configurations::Resource
48
+ end
49
+
50
+ it "sets a persona resource configuration" do
51
+ subject.resources[:persona].should be_a Axel::Configurations::Resource
52
+ end
53
+
54
+ it "sets a api proxy service with a configuration" do
55
+ subject.services[:api_proxy].should be_a Axel::Configurations::Service
56
+ end
57
+
58
+ it "sets a pers resource configuration" do
59
+ subject.resources[:registry].should be_a Axel::Configurations::Resource
60
+ end
61
+ end
62
+ end
63
+ end
64
+ end
@@ -0,0 +1,66 @@
1
+ require 'spec_helper'
2
+
3
+ module Axel
4
+ describe ApiProxy do
5
+ context "the class" do
6
+ subject { ApiProxy }
7
+
8
+ its(:cache_file) { should be_a Pathname }
9
+ its(:cache_dir) { should be_a Pathname }
10
+
11
+ context "invalid json" do
12
+ let(:json) { "not_json" }
13
+ it "can't parse, toss back hash as we expect" do
14
+ subject.build(nil, double(success?: true, body: json)).should == {}
15
+ end
16
+ end
17
+ end
18
+
19
+ context "the instance" do
20
+ subject { ApiProxy.new endpoint }
21
+ let(:endpoint) { "http://api.not-existant" }
22
+
23
+ context "get new data" do
24
+ let(:new_data) { "{\"routes\":[{\"service\":\"https://user-service.stage.com\",\"path\":\"/personas\",\"matcher\":\"^/personas(\\\\/[\\\\w]+)*\\\\/?(\\\\.\\\\w+)?(\\\\?.*)?$\"},{\"service\":\"https://cms-service.stage.com\",\"path\":\"/mobile_products\",\"matcher\":\"^/mobile_products(\\\\/[\\\\w]+)*\\\\/?(\\\\.\\\\w+)?(\\\\?.*)?$\"}]}" }
25
+
26
+ before do
27
+ loaded = MultiJson.load new_data
28
+ subject.class.stub request: loaded
29
+ subject.stub write_cache: loaded["routes"]
30
+ end
31
+
32
+ it "configs the resources" do
33
+ Axel.send(:_config).should_receive(:add_resource).with(
34
+ "user_service",
35
+ "personas",
36
+ service: { url: "https://user-service.stage.com" }).once
37
+ Axel.send(:_config).should_receive(:add_resource).with(
38
+ "cms_service",
39
+ "mobile_products",
40
+ service: { url: "https://cms-service.stage.com" }).once
41
+ subject.register!
42
+ end
43
+ end
44
+
45
+ context "get old data" do
46
+ let(:cached_data) { [{"service"=>"https://user-service.stage.com", "path"=>"/personas", "matcher"=>"^/personas(\\/[\\w]+)*\\/?(\\.\\w+)?(\\?.*)?$"}, {"service"=>"https://cms-service.stage.com", "path"=>"/mobile_products", "matcher"=>"^/mobile_products(\\/[\\w]+)*\\/?(\\.\\w+)?(\\?.*)?$"}] }
47
+
48
+ before do
49
+ subject.stub read_cache: cached_data
50
+ end
51
+
52
+ it "configs the resources" do
53
+ Axel.send(:_config).should_receive(:add_resource).with(
54
+ "user_service",
55
+ "personas",
56
+ service: { url: "https://user-service.stage.com" }).once
57
+ Axel.send(:_config).should_receive(:add_resource).with(
58
+ "cms_service",
59
+ "mobile_products",
60
+ service: { url: "https://cms-service.stage.com" }).once
61
+ subject.register!
62
+ end
63
+ end
64
+ end
65
+ end
66
+ end
@@ -0,0 +1,165 @@
1
+ require 'spec_helper'
2
+ module Axel
3
+ module Payload
4
+ describe Errors do
5
+ subject { Errors.new params }
6
+ let(:params) { {} }
7
+
8
+ its(:messages) { should == [] }
9
+ its(:status) { should == 200 }
10
+
11
+ context "http created code" do
12
+ let(:params) { { status: 201 } }
13
+ it "should be success" do
14
+ subject.success?.should be_truthy
15
+ subject.display?.should be_falsey
16
+ end
17
+ end
18
+
19
+ context "http accepted code" do
20
+ let(:params) { { status: 202 } }
21
+ it "should be success" do
22
+ subject.success?.should be_truthy
23
+ subject.display?.should be_falsey
24
+ end
25
+ end
26
+
27
+ context "http no content code" do
28
+ let(:params) { { status: 204 } }
29
+ it "should be success" do
30
+ subject.success?.should be_truthy
31
+ subject.display?.should be_falsey
32
+ end
33
+ end
34
+
35
+ context "exception" do
36
+ let(:params) { { status: 404, messages: ["Fail!"] } }
37
+ it "sets exception" do
38
+ subject.exception.should be_a RemoteError
39
+ subject.exception.to_s.should == "Failed. HTTP Status: 404, Messages: Fail!"
40
+ end
41
+ end
42
+
43
+ context "reset!" do
44
+ let(:params) { { status: 404, messages: ["Fail!"] } }
45
+
46
+ it "sets params, resets, clear object" do
47
+ subject.status_code.should == 404
48
+ subject.messages.should == ["Fail!"]
49
+ subject.reset!
50
+ subject.status_code.should == 200
51
+ subject.messages.should == []
52
+ end
53
+ end
54
+
55
+ describe "header status" do
56
+ its(:header_status) { should == 200 }
57
+ context "non-200 status" do
58
+ before do
59
+ subject.status = :unprocessable_entity
60
+ end
61
+
62
+ its(:header_status) { should == 422 }
63
+
64
+ context "suppressed" do
65
+ let(:params) { { suppress_response_codes: 1 } }
66
+ its(:header_status) { should == 200 }
67
+ end
68
+ end
69
+ end
70
+
71
+ describe "drops" do
72
+ let(:params) { { messages: ["no good"], status: 404 } }
73
+
74
+ context "with a drop" do
75
+ it "changes the boolean and drops the message" do
76
+ subject.drop?.should be_falsey
77
+ subject.drop!
78
+ subject.drop?.should be_truthy
79
+ subject.display.should == {}
80
+ end
81
+ end
82
+
83
+ context "without a drop" do
84
+ its(:display) { should == { status: 404, messages: ["no good"] } }
85
+ end
86
+ end
87
+
88
+ describe "<<" do
89
+ it "adds to the error list" do
90
+ expect { subject << "There was an error" }.to change { subject.messages }.from([]).to(["There was an error"])
91
+ end
92
+ end
93
+
94
+ describe "display" do
95
+ its(:display) { should == { status: 200, messages: [] } }
96
+
97
+ context "with some errors and status" do
98
+ before do
99
+ subject << "ERROR"
100
+ subject.status = :unprocessable_entity
101
+ end
102
+
103
+ its(:display) { should == { status: 422, messages: ["ERROR"] } }
104
+ end
105
+ end
106
+
107
+ describe "display?" do
108
+ its(:display?) { should == false }
109
+
110
+ context "with a non 200 status" do
111
+ before do
112
+ subject.status = 403
113
+ end
114
+ its(:display?) { should == true }
115
+ end
116
+
117
+ context "with an error message" do
118
+ before do
119
+ subject << "ERROR"
120
+ end
121
+ its(:display?) { should == true }
122
+ end
123
+ end
124
+
125
+ describe "new_error" do
126
+ context "non-200 status, one message" do
127
+ before do
128
+ subject.new_error 404, "ERROR"
129
+ end
130
+ its(:display) { should == { status: 404, messages: ["ERROR"] } }
131
+ end
132
+
133
+ context "non-200 status, multiple messages" do
134
+ before do
135
+ subject.new_error :not_found, "ERROR", "ERROR 2"
136
+ end
137
+ its(:display) { should == { status: 404, messages: ["ERROR", "ERROR 2"] } }
138
+ end
139
+
140
+ context "200 status, multiple messages" do
141
+ before do
142
+ subject.new_error nil, "ERROR"
143
+ end
144
+ its(:display) { should == { status: 200, messages: ["ERROR"] } }
145
+ end
146
+ end
147
+
148
+ describe "formats" do
149
+ context "no display" do
150
+ its(:to_json) { should == "" }
151
+ its(:to_xml) { should == "" }
152
+ end
153
+
154
+ context "with errors and status" do
155
+ before do
156
+ subject.new_error :not_found, "Not found"
157
+ end
158
+
159
+ its(:to_json) { should == { status: 404, messages: ["Not found"] }.to_json }
160
+ its(:to_xml) { should == { status: 404, messages: ["Not found"] }.to_xml(skip_instruct: true, root: :error) }
161
+ end
162
+ end
163
+ end
164
+ end
165
+ end