frodata 0.9.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 +7 -0
  2. data/.autotest +2 -0
  3. data/.gitignore +24 -0
  4. data/.rspec +2 -0
  5. data/.ruby-gemset +1 -0
  6. data/.ruby-version +1 -0
  7. data/.travis.yml +75 -0
  8. data/CHANGELOG.md +150 -0
  9. data/Gemfile +4 -0
  10. data/LICENSE.txt +23 -0
  11. data/README.md +427 -0
  12. data/Rakefile +7 -0
  13. data/TODO.md +55 -0
  14. data/frodata.gemspec +34 -0
  15. data/lib/frodata.rb +36 -0
  16. data/lib/frodata/entity.rb +332 -0
  17. data/lib/frodata/entity_container.rb +75 -0
  18. data/lib/frodata/entity_set.rb +161 -0
  19. data/lib/frodata/errors.rb +68 -0
  20. data/lib/frodata/navigation_property.rb +29 -0
  21. data/lib/frodata/navigation_property/proxy.rb +80 -0
  22. data/lib/frodata/properties.rb +32 -0
  23. data/lib/frodata/properties/binary.rb +50 -0
  24. data/lib/frodata/properties/boolean.rb +37 -0
  25. data/lib/frodata/properties/collection.rb +50 -0
  26. data/lib/frodata/properties/complex.rb +114 -0
  27. data/lib/frodata/properties/date.rb +27 -0
  28. data/lib/frodata/properties/date_time.rb +83 -0
  29. data/lib/frodata/properties/date_time_offset.rb +17 -0
  30. data/lib/frodata/properties/decimal.rb +50 -0
  31. data/lib/frodata/properties/enum.rb +62 -0
  32. data/lib/frodata/properties/float.rb +67 -0
  33. data/lib/frodata/properties/geography.rb +13 -0
  34. data/lib/frodata/properties/geography/base.rb +162 -0
  35. data/lib/frodata/properties/geography/line_string.rb +33 -0
  36. data/lib/frodata/properties/geography/point.rb +31 -0
  37. data/lib/frodata/properties/geography/polygon.rb +38 -0
  38. data/lib/frodata/properties/guid.rb +17 -0
  39. data/lib/frodata/properties/integer.rb +107 -0
  40. data/lib/frodata/properties/number.rb +14 -0
  41. data/lib/frodata/properties/string.rb +72 -0
  42. data/lib/frodata/properties/time.rb +40 -0
  43. data/lib/frodata/properties/time_of_day.rb +27 -0
  44. data/lib/frodata/property.rb +139 -0
  45. data/lib/frodata/property_registry.rb +41 -0
  46. data/lib/frodata/query.rb +233 -0
  47. data/lib/frodata/query/criteria.rb +92 -0
  48. data/lib/frodata/query/criteria/comparison_operators.rb +49 -0
  49. data/lib/frodata/query/criteria/date_functions.rb +61 -0
  50. data/lib/frodata/query/criteria/geography_functions.rb +21 -0
  51. data/lib/frodata/query/criteria/lambda_operators.rb +27 -0
  52. data/lib/frodata/query/criteria/string_functions.rb +40 -0
  53. data/lib/frodata/query/in_batches.rb +58 -0
  54. data/lib/frodata/railtie.rb +19 -0
  55. data/lib/frodata/schema.rb +155 -0
  56. data/lib/frodata/schema/complex_type.rb +79 -0
  57. data/lib/frodata/schema/enum_type.rb +95 -0
  58. data/lib/frodata/service.rb +254 -0
  59. data/lib/frodata/service/request.rb +85 -0
  60. data/lib/frodata/service/response.rb +162 -0
  61. data/lib/frodata/service/response/atom.rb +40 -0
  62. data/lib/frodata/service/response/json.rb +41 -0
  63. data/lib/frodata/service/response/plain.rb +36 -0
  64. data/lib/frodata/service/response/xml.rb +40 -0
  65. data/lib/frodata/service_registry.rb +52 -0
  66. data/lib/frodata/version.rb +3 -0
  67. data/spec/fixtures/files/entity_to_xml.xml +17 -0
  68. data/spec/fixtures/files/error.xml +5 -0
  69. data/spec/fixtures/files/metadata.xml +150 -0
  70. data/spec/fixtures/files/product_0.json +10 -0
  71. data/spec/fixtures/files/product_0.xml +28 -0
  72. data/spec/fixtures/files/products.json +106 -0
  73. data/spec/fixtures/files/products.xml +308 -0
  74. data/spec/fixtures/files/supplier_0.json +26 -0
  75. data/spec/fixtures/files/supplier_0.xml +32 -0
  76. data/spec/fixtures/vcr_cassettes/entity_set_specs.yml +1635 -0
  77. data/spec/fixtures/vcr_cassettes/entity_set_specs/bad_entry.yml +183 -0
  78. data/spec/fixtures/vcr_cassettes/entity_set_specs/existing_entry.yml +256 -0
  79. data/spec/fixtures/vcr_cassettes/entity_set_specs/new_entry.yml +185 -0
  80. data/spec/fixtures/vcr_cassettes/entity_specs.yml +285 -0
  81. data/spec/fixtures/vcr_cassettes/navigation_property_proxy_specs.yml +346 -0
  82. data/spec/fixtures/vcr_cassettes/query/result_specs.yml +189 -0
  83. data/spec/fixtures/vcr_cassettes/query_specs.yml +1060 -0
  84. data/spec/fixtures/vcr_cassettes/schema/complex_type_specs.yml +127 -0
  85. data/spec/fixtures/vcr_cassettes/service/request_specs.yml +193 -0
  86. data/spec/fixtures/vcr_cassettes/service_registry_specs.yml +129 -0
  87. data/spec/fixtures/vcr_cassettes/service_specs.yml +127 -0
  88. data/spec/fixtures/vcr_cassettes/usage_example_specs.yml +1330 -0
  89. data/spec/frodata/entity/shared_examples.rb +82 -0
  90. data/spec/frodata/entity_container_spec.rb +38 -0
  91. data/spec/frodata/entity_set_spec.rb +168 -0
  92. data/spec/frodata/entity_spec.rb +151 -0
  93. data/spec/frodata/errors_spec.rb +48 -0
  94. data/spec/frodata/navigation_property/proxy_spec.rb +44 -0
  95. data/spec/frodata/navigation_property_spec.rb +55 -0
  96. data/spec/frodata/properties/binary_spec.rb +50 -0
  97. data/spec/frodata/properties/boolean_spec.rb +72 -0
  98. data/spec/frodata/properties/collection_spec.rb +44 -0
  99. data/spec/frodata/properties/date_spec.rb +23 -0
  100. data/spec/frodata/properties/date_time_offset_spec.rb +30 -0
  101. data/spec/frodata/properties/date_time_spec.rb +23 -0
  102. data/spec/frodata/properties/decimal_spec.rb +51 -0
  103. data/spec/frodata/properties/float_spec.rb +45 -0
  104. data/spec/frodata/properties/geography/line_string_spec.rb +33 -0
  105. data/spec/frodata/properties/geography/point_spec.rb +29 -0
  106. data/spec/frodata/properties/geography/polygon_spec.rb +55 -0
  107. data/spec/frodata/properties/geography/shared_examples.rb +72 -0
  108. data/spec/frodata/properties/guid_spec.rb +17 -0
  109. data/spec/frodata/properties/integer_spec.rb +58 -0
  110. data/spec/frodata/properties/string_spec.rb +46 -0
  111. data/spec/frodata/properties/time_of_day_spec.rb +23 -0
  112. data/spec/frodata/properties/time_spec.rb +15 -0
  113. data/spec/frodata/property_registry_spec.rb +16 -0
  114. data/spec/frodata/property_spec.rb +71 -0
  115. data/spec/frodata/query/criteria_spec.rb +229 -0
  116. data/spec/frodata/query_spec.rb +199 -0
  117. data/spec/frodata/schema/complex_type_spec.rb +96 -0
  118. data/spec/frodata/schema/enum_type_spec.rb +112 -0
  119. data/spec/frodata/schema_spec.rb +97 -0
  120. data/spec/frodata/service/request_spec.rb +49 -0
  121. data/spec/frodata/service/response_spec.rb +85 -0
  122. data/spec/frodata/service_registry_spec.rb +18 -0
  123. data/spec/frodata/service_spec.rb +191 -0
  124. data/spec/frodata/usage_example_spec.rb +188 -0
  125. data/spec/spec_helper.rb +32 -0
  126. data/spec/support/coverage.rb +2 -0
  127. data/spec/support/vcr.rb +9 -0
  128. metadata +401 -0
@@ -0,0 +1,112 @@
1
+ require 'spec_helper'
2
+
3
+ describe FrOData::Schema::EnumType, vcr: {cassette_name: 'schema/enum_type_specs'} do
4
+ before(:example) do
5
+ FrOData::Service.new('http://services.odata.org/V4/OData/OData.svc', name: 'ODataDemo', metadata_file: metadata_file)
6
+ end
7
+
8
+ let(:metadata_file) { 'spec/fixtures/files/metadata.xml' }
9
+ let(:service) { FrOData::ServiceRegistry['ODataDemo'] }
10
+
11
+ let(:enum_type) { service.enum_types['ODataDemo.ProductStatus'] }
12
+ let(:subject) { enum_type.property_class.new('ProductStatus', nil) }
13
+
14
+ describe 'is properly parsed from service metadata' do
15
+ it { expect(enum_type.name).to eq('ProductStatus') }
16
+ it { expect(enum_type.namespace).to eq('ODataDemo') }
17
+ it { expect(enum_type.type).to eq('ODataDemo.ProductStatus') }
18
+ it { expect(enum_type.is_flags?).to eq(false) }
19
+ it { expect(enum_type.underlying_type).to eq('Edm.Byte') }
20
+ it { expect(enum_type.members.values).to eq(%w{Available LowStock Backordered Discontinued}) }
21
+ end
22
+
23
+ # Check property instance inheritance hierarchy
24
+ it { expect(subject).to be_a(FrOData::Property) }
25
+ it { expect(subject).to be_a(FrOData::Properties::Enum) }
26
+
27
+ it { expect(subject).to respond_to(:name) }
28
+ it { expect(subject).to respond_to(:type) }
29
+ it { expect(subject).to respond_to(:members) }
30
+
31
+ describe '#value=' do
32
+ it 'allows setting a valid value' do
33
+ subject.value = 'Available'
34
+ expect(subject.value).to eq('Available')
35
+ end
36
+
37
+ it 'does not allow setting an invalid value' do
38
+ expect {
39
+ subject.value = 'Invalid'
40
+ }.to raise_error(ArgumentError)
41
+ end
42
+
43
+ it 'allows setting by numeric value' do
44
+ expect {
45
+ subject.value = 1
46
+ }.not_to raise_error
47
+ expect(subject.value).to eq('LowStock')
48
+ end
49
+
50
+ context 'when `IsFlags` is false' do
51
+ it 'does not allow setting multiple values' do
52
+ expect {
53
+ subject.value = 'Available, Backordered'
54
+ }.to raise_error(ArgumentError)
55
+ end
56
+ end
57
+
58
+ context 'when `IsFlags` is true' do
59
+ before do
60
+ subject.define_singleton_method(:is_flags?) { true }
61
+ end
62
+
63
+ it 'allows setting multiple values' do
64
+ subject.value = 'Available, Backordered'
65
+ expect(subject.value).to eq(%w[Available Backordered])
66
+ end
67
+
68
+ it 'does not allow setting invalid values' do
69
+ expect {
70
+ subject.value = 'Available, Invalid'
71
+ }.to raise_error(ArgumentError)
72
+ end
73
+
74
+ it 'allows setting by numeric value' do
75
+ expect {
76
+ subject.value = '0, 1'
77
+ }.not_to raise_error
78
+ expect(subject.value).to eq(%w[Available LowStock])
79
+ end
80
+ end
81
+ end
82
+
83
+ describe 'lenient validation' do
84
+ let(:subject) do
85
+ enum_type.property_class.new('ProductStatus', nil, strict: false)
86
+ end
87
+
88
+ describe '#value=' do
89
+ it 'ignores invalid values' do
90
+ expect {
91
+ subject.value = 'Invalid'
92
+ }.not_to raise_error
93
+
94
+ expect(subject.value).to be_nil
95
+ end
96
+
97
+ context 'when `IsFlags` is true' do
98
+ before do
99
+ subject.define_singleton_method(:is_flags?) { true }
100
+ end
101
+
102
+ it 'ignores invalid values' do
103
+ expect {
104
+ subject.value = 'Available, Invalid'
105
+ }.not_to raise_error
106
+
107
+ expect(subject.value).to eq(['Available'])
108
+ end
109
+ end
110
+ end
111
+ end
112
+ end
@@ -0,0 +1,97 @@
1
+ require 'spec_helper'
2
+
3
+ describe FrOData::Schema do
4
+ let(:subject) { FrOData::Schema.new(schema_xml, service) }
5
+ let(:service) do
6
+ FrOData::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
+ let(:schema_xml) { service.metadata.xpath('//Schema').first }
10
+
11
+ let(:entity_types) { %w{Product FeaturedProduct ProductDetail Category Supplier Person Customer Employee PersonDetail Advertisement} }
12
+ let(:complex_types) { %w{Address} }
13
+ let(:enum_types) { %w{ProductStatus} }
14
+
15
+ describe '#namespace' do
16
+ it { expect(subject).to respond_to(:namespace) }
17
+ it "returns the schema's namespace attribute" do
18
+ expect(subject.namespace).to eq('ODataDemo')
19
+ end
20
+ end
21
+
22
+ describe '#actions' do
23
+ # TODO add a action definition to metadata
24
+ it { expect(subject).to respond_to(:actions) }
25
+ it { expect(subject.actions.size).to eq(0) }
26
+ end
27
+
28
+ describe '#annotations' do
29
+ # TBD
30
+ end
31
+
32
+ describe '#complex_types' do
33
+ it { expect(subject).to respond_to(:complex_types) }
34
+ it { expect(subject.complex_types.size).to eq(1) }
35
+ it { expect(subject.complex_types.keys).to eq(complex_types) }
36
+ end
37
+
38
+ describe '#entity_types' do
39
+ it { expect(subject).to respond_to(:entity_types) }
40
+ it { expect(subject.entity_types.size).to eq(10) }
41
+ it { expect(subject.entity_types).to eq(entity_types) }
42
+ end
43
+
44
+ describe '#enum_types' do
45
+ it { expect(subject).to respond_to(:enum_types) }
46
+ it { expect(subject.enum_types.size).to eq(1) }
47
+ it { expect(subject.enum_types.keys).to eq(enum_types)}
48
+ end
49
+
50
+ describe '#functions' do
51
+ # TODO add a function definition to metadata
52
+ it { expect(subject).to respond_to(:functions) }
53
+ it { expect(subject.functions.size).to eq(0) }
54
+ end
55
+
56
+ describe '#terms' do
57
+ # TBD
58
+ end
59
+
60
+ describe '#type_definitions' do
61
+ # TODO add a type definition to metadata
62
+ it { expect(subject).to respond_to(:type_definitions) }
63
+ it { expect(subject.type_definitions.size).to eq(0) }
64
+ end
65
+
66
+ describe '#navigation_properties' do
67
+ it { expect(subject).to respond_to(:navigation_properties) }
68
+ it { expect(subject.navigation_properties['Product'].size).to eq(3) }
69
+ it { expect(subject.navigation_properties['Product'].values).to all(be_a(FrOData::NavigationProperty)) }
70
+ end
71
+
72
+ describe '#get_property_type' do
73
+ it { expect(subject).to respond_to(:get_property_type) }
74
+ it { expect(subject.get_property_type('Product', 'ID')).to eq('Edm.Int32') }
75
+ it { expect(subject.get_property_type('Product', 'ProductStatus')).to eq('ODataDemo.ProductStatus') }
76
+ end
77
+
78
+ describe '#primary_key_for' do
79
+ it { expect(subject).to respond_to(:primary_key_for) }
80
+ it { expect(subject.primary_key_for('Product')).to eq('ID') }
81
+ end
82
+
83
+ describe '#properties_for_entity' do
84
+ it { expect(subject).to respond_to(:properties_for_entity) }
85
+ it { expect(subject.properties_for_entity('Product').keys).to eq(%w[
86
+ ID
87
+ Name
88
+ Description
89
+ ReleaseDate
90
+ DiscontinuedDate
91
+ Rating
92
+ Price
93
+ ProductStatus
94
+ ]) }
95
+ it { expect(subject.properties_for_entity('Product').values).to all(be_a(FrOData::Property)) }
96
+ end
97
+ end
@@ -0,0 +1,49 @@
1
+ require 'spec_helper'
2
+
3
+ describe FrOData::Service::Request, vcr: {cassette_name: 'service/request_specs'} do
4
+ let(:subject) { FrOData::Service::Request.new(service, 'Products') }
5
+ let(:service) { FrOData::Service.new(service_url, name: 'ODataDemo', metadata_file: metadata_file) }
6
+ let(:service_url) { 'http://services.odata.org/V4/OData/OData.svc' }
7
+ let(:metadata_file) { 'spec/fixtures/files/metadata.xml' }
8
+
9
+ describe '#url' do
10
+ it 'returns the full request URL' do
11
+ expect(subject.url).to eq('http://services.odata.org/V4/OData/OData.svc/Products')
12
+ end
13
+ end
14
+
15
+ describe '#method' do
16
+ it 'defaults to GET' do
17
+ expect(subject.method).to eq(:get)
18
+ end
19
+ end
20
+
21
+ describe '#format' do
22
+ it 'defaults to :auto' do
23
+ expect(subject.format).to eq(:auto)
24
+ end
25
+ end
26
+
27
+ describe '#content_type' do
28
+ it 'return all acceptable types when format = :auto' do
29
+ expect(subject.content_type).to eq(FrOData::Service::MIME_TYPES.values.join(','))
30
+ end
31
+
32
+ it 'returns the correct MIME type when format = :atom' do
33
+ subject.format = :atom
34
+ expect(subject.content_type).to eq('application/atom+xml')
35
+ end
36
+
37
+ it 'returns the correct MIME type when format = :json' do
38
+ subject.format = :json
39
+ expect(subject.content_type).to eq('application/json')
40
+ end
41
+ end
42
+
43
+ describe '#execute' do
44
+ it 'returns a response object' do
45
+ expect(subject.execute).to be_a(FrOData::Service::Response)
46
+ end
47
+ it 'retries on wrong content type'
48
+ end
49
+ end
@@ -0,0 +1,85 @@
1
+ require 'spec_helper'
2
+
3
+ shared_examples 'a valid response' do
4
+ it { expect(subject).to be_success }
5
+ it { expect(subject.count).to eq(11) }
6
+
7
+ describe '#empty?' do
8
+ it { expect(subject).to respond_to(:empty?) }
9
+ it { expect(subject.empty?).to eq(false) }
10
+ end
11
+
12
+ describe '#each' do
13
+ it { expect(subject).to respond_to(:each) }
14
+ it 'returns just FrOData::Entities of the right type' do
15
+ subject.each do |entity|
16
+ expect(entity).to be_a(FrOData::Entity)
17
+ expect(entity.type).to eq('ODataDemo.Product')
18
+ end
19
+ end
20
+ end
21
+ end
22
+
23
+ describe FrOData::Service::Response, vcr: {cassette_name: 'service/response_specs'} do
24
+ let(:subject) { FrOData::Service::Response.new(service, entity_set.query) { response } }
25
+ let(:service) { FrOData::Service.new(service_url, name: 'ODataDemo', metadata_file: metadata_file) }
26
+ let(:service_url) { 'http://services.odata.org/V4/OData/OData.svc' }
27
+ let(:metadata_file) { 'spec/fixtures/files/metadata.xml' }
28
+ let(:entity_set) { service['Products'] }
29
+ let(:response) do
30
+ response = double('response')
31
+ allow(response).to receive_messages(
32
+ headers: { 'Content-Type' => content_type },
33
+ status: response_status,
34
+ body: response_body
35
+ )
36
+ response
37
+ end
38
+
39
+ context 'with Atom result' do
40
+ let(:content_type) { 'application/atom+xml' }
41
+ let(:response_status) { 200 }
42
+ let(:response_body) { File.read('spec/fixtures/files/products.xml') }
43
+
44
+ it_behaves_like 'a valid response'
45
+ end
46
+
47
+ context 'with JSON result' do
48
+ let(:content_type) { 'application/json' }
49
+ let(:response_status) { 200 }
50
+ let(:response_body) { File.read('spec/fixtures/files/products.json') }
51
+
52
+ it_behaves_like 'a valid response'
53
+ end
54
+
55
+ context 'with XML result' do
56
+ let(:content_type) { 'application/xml' }
57
+ let(:response_status) { 200 }
58
+ let(:response_body) { File.read('spec/fixtures/files/error.xml') }
59
+
60
+ it 'contains no entities' do
61
+ expect(subject.empty?).to eq(true)
62
+ end
63
+
64
+ it 'contains error message' do
65
+ expect(subject.error_message).to match(/Resource not found/)
66
+ end
67
+ end
68
+
69
+ context 'with plain text result' do
70
+ let(:content_type) { 'text/plain' }
71
+ let(:response_status) { 200 }
72
+ let(:response_body) { '123' }
73
+
74
+ it { expect(subject).to be_success }
75
+ it { expect(subject.body).to match(/123/) }
76
+ end
77
+
78
+ context 'with unregistered content type' do
79
+ let(:content_type) { 'text/unknown' }
80
+ let(:response_status) { 200 }
81
+ let(:response_body) { '123' }
82
+
83
+ it { expect { subject }.to raise_error(FrOData::RequestError) }
84
+ end
85
+ end
@@ -0,0 +1,18 @@
1
+ require 'spec_helper'
2
+
3
+ describe FrOData::ServiceRegistry, vcr: {cassette_name: 'service_registry_specs'} do
4
+ let(:subject) { FrOData::ServiceRegistry }
5
+ let(:sample_service) { FrOData::Service.new('http://services.odata.org/V4/OData/OData.svc', name: 'demoService') }
6
+
7
+ it { expect(subject).to respond_to(:add) }
8
+ it { expect(subject).to respond_to(:[]) }
9
+
10
+ describe '#add' do
11
+ before(:example) do
12
+ subject.add(sample_service)
13
+ end
14
+
15
+ it { expect(subject['demoService']).to eq(sample_service) }
16
+ it { expect(subject['http://services.odata.org/V4/OData/OData.svc']).to eq(sample_service) }
17
+ end
18
+ end
@@ -0,0 +1,191 @@
1
+ require 'spec_helper'
2
+
3
+ describe FrOData::Service, vcr: {cassette_name: 'service_specs'} do
4
+ let(:service_url) { 'http://services.odata.org/V4/OData/OData.svc' }
5
+ let(:metadata_file) { 'spec/fixtures/files/metadata.xml' }
6
+ let(:subject) { FrOData::Service.new(service_url, name: 'ODataDemo', metadata_file: metadata_file) }
7
+
8
+ describe '.new' do
9
+ it 'adds itself to FrOData::ServiceRegistry on creation' do
10
+ expect(FrOData::ServiceRegistry['ODataDemo']).to be_nil
11
+ expect(FrOData::ServiceRegistry[service_url]).to be_nil
12
+
13
+ service = FrOData::Service.new(service_url, name: 'ODataDemo')
14
+
15
+ expect(FrOData::ServiceRegistry['ODataDemo']).to eq(service)
16
+ expect(FrOData::ServiceRegistry[service_url]).to eq(service)
17
+ end
18
+
19
+ it 'registers custom types on creation' do
20
+ service = FrOData::Service.new(service_url, name: 'ODataDemo')
21
+
22
+ expect(FrOData::PropertyRegistry['ODataDemo.Address']).to be_a(Class)
23
+ expect(FrOData::PropertyRegistry['ODataDemo.ProductStatus']).to be_a(Class)
24
+ end
25
+
26
+ it 'allows connection to be set by passing it instead of service_url' do
27
+ connection = Faraday.new(service_url)
28
+ service = FrOData::Service.new(connection)
29
+ expect(service.connection).to eq(connection)
30
+ end
31
+
32
+ it 'allows connection to be customized via options hash' do
33
+ service = FrOData::Service.new(service_url, connection: {
34
+ headers: { 'X-Custom-Header' => 'foo' }
35
+ })
36
+ expect(service.connection.headers).to include('X-Custom-Header' => 'foo')
37
+ end
38
+
39
+ it 'allows connection to be customized via block argument' do
40
+ service = FrOData::Service.new(service_url) do |conn|
41
+ conn.headers['X-Custom-Header'] = 'foo'
42
+ conn.adapter Faraday.default_adapter
43
+ end
44
+ expect(service.connection.headers).to include('X-Custom-Header' => 'foo')
45
+ end
46
+
47
+ it 'allows logger to be set via option' do
48
+ logger = Logger.new(STDERR).tap { |l| l.level = Logger::ERROR }
49
+ service = FrOData::Service.new(service_url, logger: logger)
50
+ expect(service.logger).to eq(logger)
51
+ end
52
+ end
53
+
54
+ describe '#connection' do
55
+ it 'returns the connection object used by the service' do
56
+ expect(subject.connection).to be_a(Faraday::Connection)
57
+ end
58
+
59
+ it 'uses the service URL as URL prefix' do
60
+ expect(subject.connection.url_prefix.to_s).to eq(subject.service_url)
61
+ end
62
+ end
63
+
64
+ describe '#logger' do
65
+ let(:logger) { Logger.new(STDERR).tap { |l| l.level = Logger::ERROR } }
66
+
67
+ it 'returns the logger used by the service' do
68
+ expect(subject.logger).to be_a(Logger)
69
+ end
70
+
71
+ it 'returns the default logger if none was set' do
72
+ expect(subject.logger.level).to eq(Logger::WARN)
73
+ end
74
+
75
+ it 'uses Rails logger if available' do
76
+ stub_const 'Rails', Class.new { def self.logger; end }
77
+ allow(Rails).to receive(:logger).and_return(logger)
78
+ expect(subject.logger).to eq(logger)
79
+ end
80
+
81
+ it 'allows logger to be set via attribute writer' do
82
+ expect(subject.logger).not_to eq(logger)
83
+ subject.logger = logger
84
+ expect(subject.logger).to eq(logger)
85
+ end
86
+ end
87
+
88
+ describe '#service_url' do
89
+ it { expect(subject).to respond_to(:service_url) }
90
+ it { expect(subject.service_url).to eq(service_url) }
91
+ end
92
+
93
+ describe '#schemas' do
94
+ it { expect(subject).to respond_to(:schemas) }
95
+ it { expect(subject.schemas.keys).to eq(['ODataDemo']) }
96
+ it { expect(subject.schemas.values).to all(be_a(FrOData::Schema)) }
97
+ it {
98
+ subject.schemas.each do |namespace, schema|
99
+ expect(schema.namespace).to eq(namespace)
100
+ end
101
+ }
102
+ end
103
+
104
+ describe '#entity_types' do
105
+ it { expect(subject).to respond_to(:entity_types) }
106
+ it { expect(subject.entity_types.size).to eq(10) }
107
+ it { expect(subject.entity_types).to eq(%w[
108
+ ODataDemo.Product
109
+ ODataDemo.FeaturedProduct
110
+ ODataDemo.ProductDetail
111
+ ODataDemo.Category
112
+ ODataDemo.Supplier
113
+ ODataDemo.Person
114
+ ODataDemo.Customer
115
+ ODataDemo.Employee
116
+ ODataDemo.PersonDetail
117
+ ODataDemo.Advertisement
118
+ ]) }
119
+ end
120
+
121
+ describe '#entity_sets' do
122
+ it { expect(subject).to respond_to(:entity_sets) }
123
+ it { expect(subject.entity_sets.size).to eq(7) }
124
+ it { expect(subject.entity_sets.keys).to eq(%w[
125
+ Products
126
+ ProductDetails
127
+ Categories
128
+ Suppliers
129
+ Persons
130
+ PersonDetails
131
+ Advertisements
132
+ ]) }
133
+ it { expect(subject.entity_sets.values).to eq(%w[
134
+ ODataDemo.Product
135
+ ODataDemo.ProductDetail
136
+ ODataDemo.Category
137
+ ODataDemo.Supplier
138
+ ODataDemo.Person
139
+ ODataDemo.PersonDetail
140
+ ODataDemo.Advertisement
141
+ ]) }
142
+ end
143
+
144
+ describe '#complex_types' do
145
+ it { expect(subject).to respond_to(:complex_types) }
146
+ it { expect(subject.complex_types.size).to eq(1) }
147
+ it { expect(subject.complex_types.keys).to eq(['ODataDemo.Address']) }
148
+ end
149
+
150
+ describe '#enum_types' do
151
+ it { expect(subject).to respond_to(:enum_types) }
152
+ it { expect(subject.enum_types.size).to eq(1) }
153
+ it { expect(subject.enum_types.keys).to eq(['ODataDemo.ProductStatus'])}
154
+ end
155
+
156
+ describe '#namespace' do
157
+ it { expect(subject.namespace).to eq('ODataDemo') }
158
+ end
159
+
160
+ describe '#[]' do
161
+ let(:entity_sets) { subject.entity_sets.keys.map { |name| subject[name] } }
162
+ it { expect(entity_sets).to all(be_a(FrOData::EntitySet)) }
163
+ it { expect {subject['Nonexistant']}.to raise_error(ArgumentError) }
164
+ end
165
+
166
+ describe '#get_property_type' do
167
+ it { expect(subject).to respond_to(:get_property_type) }
168
+ it { expect(subject.get_property_type('ODataDemo.Product', 'ID')).to eq('Edm.Int32') }
169
+ it { expect(subject.get_property_type('ODataDemo.Product', 'ProductStatus')).to eq('ODataDemo.ProductStatus') }
170
+ end
171
+
172
+ describe '#primary_key_for' do
173
+ it { expect(subject).to respond_to(:primary_key_for) }
174
+ it { expect(subject.primary_key_for('ODataDemo.Product')).to eq('ID') }
175
+ end
176
+
177
+ describe '#properties_for_entity' do
178
+ it { expect(subject).to respond_to(:properties_for_entity) }
179
+ it { expect(subject.properties_for_entity('ODataDemo.Product').keys).to eq(%w[
180
+ ID
181
+ Name
182
+ Description
183
+ ReleaseDate
184
+ DiscontinuedDate
185
+ Rating
186
+ Price
187
+ ProductStatus
188
+ ]) }
189
+ it { expect(subject.properties_for_entity('ODataDemo.Product').values).to all(be_a(FrOData::Property)) }
190
+ end
191
+ end