frodo 0.10.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 (153) hide show
  1. checksums.yaml +7 -0
  2. data/.autotest +2 -0
  3. data/.circleci/config.yml +54 -0
  4. data/.gitignore +24 -0
  5. data/.gitlab-ci.yml +9 -0
  6. data/.rspec +2 -0
  7. data/.ruby-gemset +1 -0
  8. data/.ruby-version +1 -0
  9. data/.travis.yml +75 -0
  10. data/CHANGELOG.md +163 -0
  11. data/Gemfile +4 -0
  12. data/LICENSE.txt +23 -0
  13. data/README.md +479 -0
  14. data/Rakefile +7 -0
  15. data/TODO.md +55 -0
  16. data/frodo.gemspec +39 -0
  17. data/images/frodo.jpg +0 -0
  18. data/lib/frodo/abstract_client.rb +11 -0
  19. data/lib/frodo/client.rb +6 -0
  20. data/lib/frodo/concerns/api.rb +292 -0
  21. data/lib/frodo/concerns/authentication.rb +32 -0
  22. data/lib/frodo/concerns/base.rb +84 -0
  23. data/lib/frodo/concerns/caching.rb +26 -0
  24. data/lib/frodo/concerns/connection.rb +79 -0
  25. data/lib/frodo/concerns/verbs.rb +68 -0
  26. data/lib/frodo/config.rb +143 -0
  27. data/lib/frodo/entity.rb +335 -0
  28. data/lib/frodo/entity_container.rb +75 -0
  29. data/lib/frodo/entity_set.rb +131 -0
  30. data/lib/frodo/errors.rb +70 -0
  31. data/lib/frodo/middleware/authentication/token.rb +13 -0
  32. data/lib/frodo/middleware/authentication.rb +87 -0
  33. data/lib/frodo/middleware/authorization.rb +18 -0
  34. data/lib/frodo/middleware/caching.rb +30 -0
  35. data/lib/frodo/middleware/custom_headers.rb +14 -0
  36. data/lib/frodo/middleware/gzip.rb +33 -0
  37. data/lib/frodo/middleware/instance_url.rb +20 -0
  38. data/lib/frodo/middleware/logger.rb +42 -0
  39. data/lib/frodo/middleware/multipart.rb +64 -0
  40. data/lib/frodo/middleware/odata_headers.rb +13 -0
  41. data/lib/frodo/middleware/raise_error.rb +47 -0
  42. data/lib/frodo/middleware.rb +33 -0
  43. data/lib/frodo/navigation_property/proxy.rb +80 -0
  44. data/lib/frodo/navigation_property.rb +29 -0
  45. data/lib/frodo/properties/binary.rb +50 -0
  46. data/lib/frodo/properties/boolean.rb +37 -0
  47. data/lib/frodo/properties/collection.rb +50 -0
  48. data/lib/frodo/properties/complex.rb +114 -0
  49. data/lib/frodo/properties/date.rb +27 -0
  50. data/lib/frodo/properties/date_time.rb +83 -0
  51. data/lib/frodo/properties/date_time_offset.rb +17 -0
  52. data/lib/frodo/properties/decimal.rb +54 -0
  53. data/lib/frodo/properties/enum.rb +62 -0
  54. data/lib/frodo/properties/float.rb +67 -0
  55. data/lib/frodo/properties/geography/base.rb +162 -0
  56. data/lib/frodo/properties/geography/line_string.rb +33 -0
  57. data/lib/frodo/properties/geography/point.rb +31 -0
  58. data/lib/frodo/properties/geography/polygon.rb +38 -0
  59. data/lib/frodo/properties/geography.rb +13 -0
  60. data/lib/frodo/properties/guid.rb +17 -0
  61. data/lib/frodo/properties/integer.rb +107 -0
  62. data/lib/frodo/properties/number.rb +14 -0
  63. data/lib/frodo/properties/string.rb +72 -0
  64. data/lib/frodo/properties/time.rb +40 -0
  65. data/lib/frodo/properties/time_of_day.rb +27 -0
  66. data/lib/frodo/properties.rb +32 -0
  67. data/lib/frodo/property.rb +139 -0
  68. data/lib/frodo/property_registry.rb +41 -0
  69. data/lib/frodo/query/criteria/comparison_operators.rb +49 -0
  70. data/lib/frodo/query/criteria/date_functions.rb +61 -0
  71. data/lib/frodo/query/criteria/geography_functions.rb +21 -0
  72. data/lib/frodo/query/criteria/lambda_operators.rb +27 -0
  73. data/lib/frodo/query/criteria/string_functions.rb +40 -0
  74. data/lib/frodo/query/criteria.rb +92 -0
  75. data/lib/frodo/query/in_batches.rb +58 -0
  76. data/lib/frodo/query.rb +221 -0
  77. data/lib/frodo/railtie.rb +19 -0
  78. data/lib/frodo/schema/complex_type.rb +79 -0
  79. data/lib/frodo/schema/enum_type.rb +95 -0
  80. data/lib/frodo/schema.rb +164 -0
  81. data/lib/frodo/service.rb +199 -0
  82. data/lib/frodo/service_registry.rb +52 -0
  83. data/lib/frodo/version.rb +3 -0
  84. data/lib/frodo.rb +67 -0
  85. data/spec/fixtures/auth_success_response.json +11 -0
  86. data/spec/fixtures/error.json +11 -0
  87. data/spec/fixtures/files/entity_to_xml.xml +18 -0
  88. data/spec/fixtures/files/error.xml +5 -0
  89. data/spec/fixtures/files/metadata.xml +150 -0
  90. data/spec/fixtures/files/metadata_with_error.xml +157 -0
  91. data/spec/fixtures/files/product_0.json +10 -0
  92. data/spec/fixtures/files/product_0.xml +28 -0
  93. data/spec/fixtures/files/products.json +106 -0
  94. data/spec/fixtures/files/products.xml +308 -0
  95. data/spec/fixtures/files/supplier_0.json +26 -0
  96. data/spec/fixtures/files/supplier_0.xml +32 -0
  97. data/spec/fixtures/leads.json +923 -0
  98. data/spec/fixtures/refresh_error_response.json +8 -0
  99. data/spec/frodo/abstract_client_spec.rb +13 -0
  100. data/spec/frodo/client_spec.rb +57 -0
  101. data/spec/frodo/concerns/authentication_spec.rb +79 -0
  102. data/spec/frodo/concerns/base_spec.rb +68 -0
  103. data/spec/frodo/concerns/caching_spec.rb +40 -0
  104. data/spec/frodo/concerns/connection_spec.rb +65 -0
  105. data/spec/frodo/config_spec.rb +127 -0
  106. data/spec/frodo/entity/shared_examples.rb +83 -0
  107. data/spec/frodo/entity_container_spec.rb +38 -0
  108. data/spec/frodo/entity_set_spec.rb +169 -0
  109. data/spec/frodo/entity_spec.rb +153 -0
  110. data/spec/frodo/errors_spec.rb +48 -0
  111. data/spec/frodo/middleware/authentication/token_spec.rb +87 -0
  112. data/spec/frodo/middleware/authentication_spec.rb +83 -0
  113. data/spec/frodo/middleware/authorization_spec.rb +17 -0
  114. data/spec/frodo/middleware/custom_headers_spec.rb +21 -0
  115. data/spec/frodo/middleware/gzip_spec.rb +68 -0
  116. data/spec/frodo/middleware/instance_url_spec.rb +27 -0
  117. data/spec/frodo/middleware/logger_spec.rb +21 -0
  118. data/spec/frodo/middleware/odata_headers_spec.rb +15 -0
  119. data/spec/frodo/middleware/raise_error_spec.rb +66 -0
  120. data/spec/frodo/navigation_property/proxy_spec.rb +46 -0
  121. data/spec/frodo/navigation_property_spec.rb +55 -0
  122. data/spec/frodo/properties/binary_spec.rb +50 -0
  123. data/spec/frodo/properties/boolean_spec.rb +72 -0
  124. data/spec/frodo/properties/collection_spec.rb +44 -0
  125. data/spec/frodo/properties/date_spec.rb +23 -0
  126. data/spec/frodo/properties/date_time_offset_spec.rb +30 -0
  127. data/spec/frodo/properties/date_time_spec.rb +23 -0
  128. data/spec/frodo/properties/decimal_spec.rb +50 -0
  129. data/spec/frodo/properties/float_spec.rb +45 -0
  130. data/spec/frodo/properties/geography/line_string_spec.rb +33 -0
  131. data/spec/frodo/properties/geography/point_spec.rb +29 -0
  132. data/spec/frodo/properties/geography/polygon_spec.rb +55 -0
  133. data/spec/frodo/properties/geography/shared_examples.rb +72 -0
  134. data/spec/frodo/properties/guid_spec.rb +17 -0
  135. data/spec/frodo/properties/integer_spec.rb +58 -0
  136. data/spec/frodo/properties/string_spec.rb +46 -0
  137. data/spec/frodo/properties/time_of_day_spec.rb +23 -0
  138. data/spec/frodo/properties/time_spec.rb +15 -0
  139. data/spec/frodo/property_registry_spec.rb +16 -0
  140. data/spec/frodo/property_spec.rb +71 -0
  141. data/spec/frodo/query/criteria_spec.rb +229 -0
  142. data/spec/frodo/query_spec.rb +156 -0
  143. data/spec/frodo/schema/complex_type_spec.rb +97 -0
  144. data/spec/frodo/schema/enum_type_spec.rb +112 -0
  145. data/spec/frodo/schema_spec.rb +113 -0
  146. data/spec/frodo/service_registry_spec.rb +19 -0
  147. data/spec/frodo/service_spec.rb +153 -0
  148. data/spec/frodo/usage_example_spec.rb +161 -0
  149. data/spec/spec_helper.rb +35 -0
  150. data/spec/support/coverage.rb +2 -0
  151. data/spec/support/fixture_helpers.rb +14 -0
  152. data/spec/support/middleware.rb +19 -0
  153. metadata +479 -0
@@ -0,0 +1,8 @@
1
+ {
2
+ "error": "invalid_grant",
3
+ "error_description": "AADSTS9002313: Invalid request. Request is malformed or invalid.rnTrace ID: 48716257-6e4f-46fe-b7ec-f98d2f7d0e00rnCorrelation ID: 0127cc73-f029-44b2-a7e2-816525df2229rnTimestamp: 2019-03-12 21:40:14Z",
4
+ "error_codes": [9002313],
5
+ "timestamp": "2019-03-12 21:40:14Z",
6
+ "trace_id": "48716257-6e4f-46fe-b7ec-f98d2f7d0e00",
7
+ "correlation_id": "0127cc73-f029-44b2-a7e2-816525df2229"
8
+ }
@@ -0,0 +1,13 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'spec_helper'
4
+
5
+ describe Frodo::AbstractClient do
6
+ subject { described_class }
7
+
8
+ it { should < Frodo::Concerns::Base }
9
+ it { should < Frodo::Concerns::Connection }
10
+ it { should < Frodo::Concerns::Authentication }
11
+ it { should < Frodo::Concerns::Caching }
12
+ it { should < Frodo::Concerns::API }
13
+ end
@@ -0,0 +1,57 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'spec_helper'
4
+
5
+ describe Frodo::Client do
6
+ subject { described_class }
7
+
8
+ let(:instance_url) { 'http://myservice.com'}
9
+ let(:base_path) { '/api'}
10
+ let(:service_url) { instance_url + base_path }
11
+
12
+ it "creates a client" do
13
+ client = subject.new(
14
+ instance_url: instance_url,
15
+ base_path: base_path,
16
+ client_id: 'client_id',
17
+ client_secret: 'secret'
18
+ )
19
+
20
+ expect(client.options[:client_id]).to eql("client_id")
21
+ expect(client.options[:client_secret]).to eql("secret")
22
+ expect(client.options[:instance_url]).to eql(instance_url)
23
+ expect(client.options[:base_path]).to eql("/api")
24
+
25
+ stub_request(:get, "#{service_url}/$metadata").
26
+ to_return(body: File.new('spec/fixtures/files/metadata.xml'), status: 200)
27
+
28
+ service = client.service
29
+
30
+ expect(service['Products']).to_not be_nil
31
+ expect(service['Products'].name).to eql('Products')
32
+ expect(service['Products'].type).to eql('ODataDemo.Product')
33
+ end
34
+
35
+ it "creates a client and inject a service instead of pulling the configured one" do
36
+ service = Frodo::Service.new(service_url, name: 'Demo', metadata_file: 'spec/fixtures/files/metadata.xml')
37
+ client = subject.new(
38
+ instance_url: instance_url,
39
+ base_path: base_path,
40
+ client_id: 'client_id',
41
+ client_secret: 'secret',
42
+ service: service
43
+ )
44
+
45
+ expect(client.options[:client_id]).to eql("client_id")
46
+ expect(client.options[:client_secret]).to eql("secret")
47
+ expect(client.options[:instance_url]).to eql(instance_url)
48
+ expect(client.options[:base_path]).to eql(base_path)
49
+
50
+ expect(client.service).to eql service
51
+
52
+ expect(service['Products']).to_not be_nil
53
+ expect(service['Products'].name).to eql('Products')
54
+ expect(service['Products'].type).to eql('ODataDemo.Product')
55
+ end
56
+
57
+ end
@@ -0,0 +1,79 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'spec_helper'
4
+
5
+ describe Frodo::Concerns::Authentication do
6
+ let(:klass) do
7
+ context = self
8
+ Class.new {
9
+ include Frodo::Concerns::Base
10
+ include context.described_class
11
+ }
12
+ end
13
+
14
+ let(:client) { klass.new }
15
+ subject { client }
16
+
17
+ describe '.authenticate!' do
18
+ subject(:authenticate!) { client.authenticate! }
19
+
20
+ context 'when there is no authentication middleware' do
21
+ before do
22
+ expect(client).to receive(:authentication_middleware).and_return(nil)
23
+ end
24
+
25
+ it "raises an error" do
26
+ expect { authenticate! }.to raise_error Frodo::AuthenticationError,
27
+ 'No authentication middleware present'
28
+ end
29
+ end
30
+
31
+ context 'when there is authentication middleware' do
32
+ let(:authentication_middleware) { double('Authentication Middleware') }
33
+ subject(:result) { client.authenticate! }
34
+
35
+ it 'authenticates using the middleware' do
36
+ expect(client).to receive(:authentication_middleware).and_return(authentication_middleware).twice
37
+ expect(client).to receive(:options).twice
38
+
39
+ expect(authentication_middleware).to receive(:new).with(nil, client, client.options).and_return(double(authenticate!: 'foo'))
40
+ expect(result).to eq 'foo'
41
+ end
42
+ end
43
+ end
44
+
45
+ describe '.authentication_middleware' do
46
+ subject { client.authentication_middleware }
47
+
48
+ context 'when oauth options are provided' do
49
+ before do
50
+ expect(client).to receive(:oauth_refresh?).and_return(true)
51
+ end
52
+
53
+ it { should eq Frodo::Middleware::Authentication::Token }
54
+ end
55
+ end
56
+
57
+ describe '.oauth_refresh?' do
58
+ subject { client.oauth_refresh? }
59
+ let(:options) { {} }
60
+
61
+ before do
62
+ expect(client).to receive(:options).and_return(options).at_least(1).times
63
+ end
64
+
65
+ context 'when oauth options are provided' do
66
+ let(:options) do
67
+ { refresh_token: 'token',
68
+ client_id: 'client',
69
+ client_secret: 'secret' }
70
+ end
71
+
72
+ it { should be_truthy}
73
+ end
74
+
75
+ context 'when oauth options are not provided' do
76
+ it { should_not be_truthy }
77
+ end
78
+ end
79
+ end
@@ -0,0 +1,68 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'spec_helper'
4
+
5
+ describe Frodo::Concerns::Base do
6
+
7
+ let(:klass) do
8
+ context = self
9
+ Class.new {
10
+ include Frodo::Concerns::Connection
11
+ include context.described_class
12
+ }
13
+ end
14
+
15
+ let(:client) { klass.new }
16
+
17
+ subject { client }
18
+
19
+ describe '#new' do
20
+ context 'without options passed in' do
21
+ it 'does not raise an exception' do
22
+ expect {
23
+ klass.new
24
+ }.to_not raise_error
25
+ end
26
+ end
27
+
28
+ context 'with a non-hash value' do
29
+ it 'raises an ArgumentError exception' do
30
+ expect {
31
+ klass.new 'foo'
32
+ }.to raise_error ArgumentError, 'Please specify a hash of options'
33
+ end
34
+ end
35
+
36
+ it 'yields the builder to the block' do
37
+ expect_any_instance_of(klass).to receive(:builder)
38
+ expect { |b| klass.new(&b) }.to yield_control
39
+ end
40
+ end
41
+
42
+ describe '.options' do
43
+ subject { lambda { client.options } }
44
+ it { should_not raise_error }
45
+ end
46
+
47
+ describe '.instance_url' do
48
+ subject { client.instance_url }
49
+
50
+ context 'when options[:instance_url] is unset' do
51
+ it 'triggers an authentication' do
52
+ def client.authenticate!
53
+ end
54
+ allow(client).to receive(:authenticate!)
55
+ expect(client).to receive :authenticate!
56
+ subject
57
+ end
58
+ end
59
+
60
+ context 'when options[:instance_url] is set' do
61
+ before do
62
+ expect(client).to receive(:options).and_return({ instance_url: 'foo' }).twice
63
+ end
64
+
65
+ it { should eq 'foo' }
66
+ end
67
+ end
68
+ end
@@ -0,0 +1,40 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'spec_helper'
4
+
5
+ describe Frodo::Concerns::Caching do
6
+ describe '.without_caching' do
7
+ let(:options) { double('Options') }
8
+ let(:klass) do
9
+ context = self
10
+ Class.new {
11
+ include Frodo::Concerns::Base
12
+ include context.described_class
13
+ }
14
+ end
15
+ let(:client) { klass.new }
16
+ subject { client }
17
+
18
+ before do
19
+ expect(client).to receive(:options).and_return(options).twice
20
+ end
21
+
22
+ it 'runs the block with caching disabled' do
23
+ expect(options).to receive(:[]=).with(:use_cache, false)
24
+ expect(options).to receive(:delete).with(:use_cache)
25
+ expect { |b| client.without_caching(&b) }.to yield_control
26
+ end
27
+
28
+ context 'when an exception is raised' do
29
+ it 'ensures the :use_cache is deleted' do
30
+ expect(options).to receive(:[]=).with(:use_cache, false)
31
+ expect(options).to receive(:delete).with(:use_cache)
32
+ expect {
33
+ client.without_caching do
34
+ raise 'Foo'
35
+ end
36
+ }.to raise_error 'Foo'
37
+ end
38
+ end
39
+ end
40
+ end
@@ -0,0 +1,65 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'spec_helper'
4
+
5
+ describe Frodo::Concerns::Connection do
6
+ let(:options) { double('Options') }
7
+ let(:klass) do
8
+ context = self
9
+ Class.new {
10
+ include Frodo::Concerns::Base
11
+ include Frodo::Concerns::Authentication
12
+ include Frodo::Concerns::Caching
13
+ include context.described_class
14
+ }
15
+ end
16
+
17
+ let(:client) { klass.new }
18
+ subject { client }
19
+
20
+ describe '.middleware' do
21
+ subject { client.middleware }
22
+ let(:builder) { double('Faraday::Builder') }
23
+
24
+ before do
25
+ expect(client).to receive_message_chain(:connection, builder: builder)
26
+ end
27
+
28
+ it { should eq builder }
29
+ end
30
+
31
+ describe "#connection_options" do
32
+ let(:options) { { ssl: { verify: false } } }
33
+ before { expect(client).to receive(:options).and_return(options).exactly(4).times }
34
+
35
+ it "picks up passed-in SSL options" do
36
+ expect(client.send(:connection_options)).to include(options)
37
+ end
38
+ end
39
+
40
+ describe 'private #connection' do
41
+
42
+ describe ":logger option" do
43
+ let(:options) { { adapter: Faraday.default_adapter } }
44
+
45
+ before(:each) do
46
+ expect(client).to receive(:authentication_middleware)
47
+ expect(client).to receive(:cache)
48
+ expect(client).to receive(:options).and_return(options).at_least(1)
49
+ expect(Frodo).to receive(:log?).and_return(true)
50
+ end
51
+
52
+ it "must always be used last before the Faraday Adapter" do
53
+ expect(client.middleware.handlers.reverse.index(Frodo::Middleware::Logger)).to eq 1
54
+ end
55
+ end
56
+ end
57
+
58
+ describe '#adapter' do
59
+ before do
60
+ expect(client).to receive(:options).and_return({ adapter: :typhoeus })
61
+ end
62
+
63
+ it { expect(subject.options[:adapter]).to eq(:typhoeus) }
64
+ end
65
+ end
@@ -0,0 +1,127 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'spec_helper'
4
+
5
+ describe Frodo do
6
+ before do
7
+ ENV['DYNAMICS_V1_CLIENT_ID'] = nil
8
+ ENV['DYNAMICS_V1_CLIENT_SECRET'] = nil
9
+ end
10
+
11
+ after do
12
+ Frodo.instance_variable_set :@configuration, nil
13
+ end
14
+
15
+ describe '#configuration' do
16
+ subject { Frodo.configuration }
17
+
18
+ it { should be_a Frodo::Configuration }
19
+
20
+ context 'by default' do
21
+ it { expect(subject.host).to eq 'login.microsoftonline.com' }
22
+ it { expect(subject.authentication_retries).to eq 3 }
23
+ it { expect(subject.adapter).to eq Faraday.default_adapter }
24
+ it { expect(subject.ssl).to eq({}) }
25
+ %i[client_id client_secret
26
+ oauth_token refresh_token instance_url compress timeout
27
+ proxy_uri authentication_callback request_headers].each do |attr|
28
+ it { expect(subject.send(attr)).to be_nil }
29
+ end
30
+ end
31
+
32
+ context 'when environment variables are defined' do
33
+ before do
34
+ {
35
+ 'FRODATA_PROXY_URI' => 'proxy',
36
+ }.
37
+ each { |var, value| allow(ENV).to receive(:[]).with(var).and_return(value) }
38
+ end
39
+
40
+ it { expect(subject.proxy_uri).to eq 'proxy' }
41
+ end
42
+ end
43
+
44
+ describe '#configure' do
45
+ %i[client_id client_secret compress
46
+ timeout oauth_token refresh_token instance_url host
47
+ authentication_retries proxy_uri authentication_callback ssl
48
+ request_headers log_level logger].each do |attr|
49
+ it "allows #{attr} to be set" do
50
+ Frodo.configure do |config|
51
+ config.send("#{attr}=", 'foobar')
52
+ end
53
+ expect(Frodo.configuration.send(attr)).to eq 'foobar'
54
+ end
55
+ end
56
+ end
57
+
58
+ describe '#log?' do
59
+ subject { Frodo.log? }
60
+
61
+ context 'by default' do
62
+ it { should be_falsey }
63
+ end
64
+ end
65
+
66
+ describe '#log' do
67
+ context 'with logging disabled' do
68
+ before do
69
+ allow(Frodo).to receive(:log?).and_return(false)
70
+ end
71
+
72
+ it 'doesnt log anytning' do
73
+ expect(Frodo.configuration.logger).not_to receive(:debug)
74
+ Frodo.log 'foobar'
75
+ end
76
+ end
77
+
78
+ context 'with logging enabled' do
79
+ before do
80
+ allow(Frodo).to receive(:log?).and_return(true)
81
+ end
82
+
83
+ it 'logs something' do
84
+ expect(Frodo.configuration.logger).to receive(:debug).with('foobar')
85
+ Frodo.log 'foobar'
86
+ end
87
+
88
+ context "with a custom logger" do
89
+ let(:fake_logger) { double(debug: true) }
90
+
91
+ before do
92
+ Frodo.configure do |config|
93
+ config.logger = fake_logger
94
+ end
95
+ end
96
+
97
+ it "logs using the provided logger" do
98
+ expect(fake_logger).to receive(:debug).with('foobar')
99
+ Frodo.log('foobar')
100
+ end
101
+ end
102
+
103
+ context "with a custom log_level" do
104
+ before do
105
+ Frodo.configure do |config|
106
+ config.log_level = :info
107
+ end
108
+ end
109
+
110
+ it 'logs with the provided log_level' do
111
+ expect(Frodo.configuration.logger).to receive(:info).with('foobar')
112
+ Frodo.log 'foobar'
113
+ end
114
+ end
115
+ end
116
+ end
117
+
118
+ describe '.new' do
119
+ it 'calls its block' do
120
+ checker = double(:block_checker)
121
+ expect(checker).to receive(:check!).once
122
+ Frodo.new do |builder|
123
+ checker.check!
124
+ end
125
+ end
126
+ end
127
+ end
@@ -0,0 +1,83 @@
1
+ shared_examples 'a valid product' do
2
+ it { expect(subject).to be_a(Frodo::Entity) }
3
+
4
+ it { expect(subject.name).to eq('Product') }
5
+ it { expect(subject.type).to eq('ODataDemo.Product') }
6
+ it { expect(subject.namespace).to eq('ODataDemo') }
7
+ it { expect(subject.service_name).to eq('ODataDemo') }
8
+ it { expect(subject.context).to eq('http://services.odata.org/V4/OData/OData.svc/$metadata#Products/$entity') }
9
+ it { expect(subject.id).to eq('Products(0)') }
10
+
11
+ # Check property types
12
+ it { expect(subject.get_property('ID')).to be_a(Frodo::Properties::Integer) }
13
+ it { expect(subject.get_property('Name')).to be_a(Frodo::Properties::String) }
14
+ it { expect(subject.get_property('Description')).to be_a(Frodo::Properties::String) }
15
+ it { expect(subject.get_property('ReleaseDate')).to be_a(Frodo::Properties::DateTimeOffset) }
16
+ it { expect(subject.get_property('DiscontinuedDate')).to be_a(Frodo::Properties::DateTimeOffset) }
17
+ it { expect(subject.get_property('Rating')).to be_a(Frodo::Properties::Integer) }
18
+ it { expect(subject.get_property('Price')).to be_a(Frodo::Properties::Double) }
19
+
20
+ # Navigation property proxies
21
+ # FIXME should we support this or not?
22
+ # it { expect(subject.get_property('Categories')).to be_a(Frodo::NavigationProperty::Proxy)}
23
+ # it { expect(subject.get_property('ProductDetail')).to be_a(Frodo::NavigationProperty::Proxy)}
24
+ # it { expect(subject.get_property('Supplier')).to be_a(Frodo::NavigationProperty::Proxy)}
25
+
26
+ # Check property values
27
+ it { expect(subject['ID']).to eq(0) }
28
+ it { expect(subject['Name']).to eq('Bread') }
29
+ it { expect(subject['Description']).to eq('Whole grain bread') }
30
+ it { expect(subject['ReleaseDate']).to eq(DateTime.new(1992,1,1,0,0,0,0)) }
31
+ it { expect(subject['DiscontinuedDate']).to be_nil }
32
+ it { expect(subject['Rating']).to eq(4) }
33
+ it { expect(subject['Price']).to eq(2.5) }
34
+
35
+ # Navigation properties
36
+ # FIXME should we support this or not?
37
+ # it { expect(subject['Categories']).to be_a(Enumerable) }
38
+ # it { expect(subject['ProductDetail']).to be_nil }
39
+ # it { expect(subject['Supplier']).to be_a(Frodo::Entity) }
40
+
41
+ # it { expect {subject['NonExistant']}.to raise_error(ArgumentError) }
42
+ # it { expect {subject['NonExistant'] = 5}.to raise_error(ArgumentError) }
43
+
44
+ describe '#links' do
45
+ let(:links) do
46
+ {
47
+ 'Categories' => {type: :collection, href: 'Products(0)/Categories'},
48
+ 'Supplier' => {type: :entity, href: 'Products(0)/Supplier'},
49
+ 'ProductDetail' => {type: :entity, href: 'Products(0)/ProductDetail'}
50
+ }
51
+ end
52
+
53
+ it { expect(subject).to respond_to(:links) }
54
+ it { expect(subject.links.size).to eq(3) }
55
+ it { expect(subject.links).to eq(links) }
56
+ end
57
+ end
58
+
59
+ shared_examples 'a valid supplier' do
60
+ it { expect(subject.name).to eq('Supplier') }
61
+ it { expect(subject.type).to eq('ODataDemo.Supplier') }
62
+ it { expect(subject.namespace).to eq('ODataDemo') }
63
+ it { expect(subject.service_name).to eq('ODataDemo') }
64
+ it { expect(subject.context).to eq('http://services.odata.org/V4/OData/OData.svc/$metadata#Suppliers/$entity') }
65
+ it { expect(subject.id).to eq('Suppliers(0)') }
66
+
67
+ # Check property types
68
+ it { expect(subject.get_property('ID')).to be_a(Frodo::Properties::Integer) }
69
+ it { expect(subject.get_property('Name')).to be_a(Frodo::Properties::String) }
70
+ it { expect(subject.get_property('Address')).to be_a(Frodo::Properties::Complex) }
71
+ it { expect(subject.get_property('Location')).to be_a(Frodo::Properties::Geography::Point) }
72
+
73
+ # Check property values
74
+ it { expect(subject['ID']).to eq(0) }
75
+ it { expect(subject['Name']).to eq('Exotic Liquids') }
76
+ it { expect(subject['Address'][ 'Street']).to eq('NE 228th') }
77
+ it { expect(subject['Address'][ 'City']).to eq('Sammamish') }
78
+ it { expect(subject['Address'][ 'State']).to eq('WA') }
79
+ it { expect(subject['Address']['ZipCode']).to eq('98074') }
80
+ it { expect(subject['Address']['Country']).to eq('USA') }
81
+ xit { expect(subject['Location']).to eq([47.6316604614258, -122.03547668457]) }
82
+ xit { expect(subject['Products']).to be_a(Frodo::Entity) }
83
+ end
@@ -0,0 +1,38 @@
1
+ require 'spec_helper'
2
+
3
+ describe Frodo::EntityContainer do
4
+ let(:subject) { Frodo::EntityContainer.new(service) }
5
+ let(:service) do
6
+ Frodo::Service.new('http://services.odata.org/V4/OData/OData.svc', metadata_file: metadata_file)
7
+ end
8
+ let(:metadata_file) { 'spec/fixtures/files/metadata.xml' }
9
+
10
+ describe '#entity_sets' do
11
+ it { expect(subject).to respond_to(:entity_sets) }
12
+ it { expect(subject.entity_sets.size).to eq(7) }
13
+ it { expect(subject.entity_sets.keys).to eq(%w[
14
+ Products
15
+ ProductDetails
16
+ Categories
17
+ Suppliers
18
+ Persons
19
+ PersonDetails
20
+ Advertisements
21
+ ]) }
22
+ it { expect(subject.entity_sets.values).to eq(%w[
23
+ ODataDemo.Product
24
+ ODataDemo.ProductDetail
25
+ ODataDemo.Category
26
+ ODataDemo.Supplier
27
+ ODataDemo.Person
28
+ ODataDemo.PersonDetail
29
+ ODataDemo.Advertisement
30
+ ]) }
31
+ end
32
+
33
+ describe '#[]' do
34
+ let(:entity_sets) { subject.entity_sets.keys.map { |name| subject[name] } }
35
+ it { expect(entity_sets).to all(be_a(Frodo::EntitySet)) }
36
+ it { expect {subject['Nonexistant']}.to raise_error(ArgumentError) }
37
+ end
38
+ end