axel 0.0.1

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