odata4 0.8.0 → 0.8.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.
@@ -1,3 +1,6 @@
1
+ require 'odata4/service/request'
2
+ require 'odata4/service/response'
3
+
1
4
  module OData4
2
5
  # Encapsulates the basic details and functionality needed to interact with an
3
6
  # OData4 service.
@@ -14,6 +17,7 @@ module OData4
14
17
  MIME_TYPES = {
15
18
  atom: 'application/atom+xml',
16
19
  json: 'application/json',
20
+ xml: 'application/xml',
17
21
  plain: 'text/plain'
18
22
  }
19
23
 
@@ -133,55 +137,11 @@ module OData4
133
137
 
134
138
  # Execute a request against the service
135
139
  #
136
- # @param url_chunk [to_s] string to append to service url
137
- # @param additional_options [Hash] options to pass to Typhoeus
138
- # @return [Typhoeus::Response]
139
- def execute(url_chunk, additional_options = {})
140
- accept = content_type(additional_options.delete(:format) || :auto)
141
- accept_header = {'Accept' => accept }
142
-
143
- request_options = options[:typhoeus]
144
- .merge({ method: :get })
145
- .merge(additional_options)
146
-
147
- # Don't overwrite Accept header if already present
148
- unless request_options[:headers]['Accept']
149
- request_options[:headers] = request_options[:headers].merge(accept_header)
150
- end
151
-
152
- request = ::Typhoeus::Request.new(
153
- URI.join("#{service_url}/", URI.escape(url_chunk)),
154
- request_options
155
- )
156
- logger.info "Requesting #{URI.unescape(request.url)}..."
157
- request.run
158
-
159
- response = request.response
160
- logger.debug(response.headers)
161
- logger.debug(response.body)
162
-
163
- validate_response(response)
164
- response
165
- end
166
-
167
- # Find a specific node in the given result set
168
- #
169
- # @param results [Typhoeus::Response]
170
- # @return [Nokogiri::XML::Element]
171
- def find_node(results, node_name)
172
- document = ::Nokogiri::XML(results.body)
173
- document.remove_namespaces!
174
- document.xpath("//#{node_name}").first
175
- end
176
-
177
- # Find entity entries in a result set
178
- #
179
- # @param results [Typhoeus::Response]
180
- # @return [Nokogiri::XML::NodeSet]
181
- def find_entities(results)
182
- document = ::Nokogiri::XML(results.body)
183
- document.remove_namespaces!
184
- document.xpath('//entry')
140
+ # @param url_chunk [to_s] string to append to service URL
141
+ # @param options [Hash] additional request options
142
+ # @return [OData4::Service::Response]
143
+ def execute(url_chunk, options = {})
144
+ Request.new(self, url_chunk, options).execute
185
145
  end
186
146
 
187
147
  # Get the property type for an entity from metadata.
@@ -256,57 +216,29 @@ module OData4
256
216
  def default_options
257
217
  {
258
218
  typhoeus: {
259
- headers: { 'OData4-Version' => '4.0' },
219
+ headers: { 'OData-Version' => '4.0' },
260
220
  timeout: HTTP_TIMEOUT
261
221
  },
262
222
  strict: true # strict property validation
263
223
  }
264
224
  end
265
225
 
266
- def content_type(format)
267
- if format == :auto
268
- MIME_TYPES.values.join(',')
269
- elsif MIME_TYPES.has_key? format
270
- MIME_TYPES[format]
271
- else
272
- raise ArgumentError, "Unknown format '#{format}'"
273
- end
274
- end
275
-
276
226
  def read_metadata
277
- response = nil
278
227
  # From file, good for debugging
279
228
  if options[:metadata_file]
280
229
  data = File.read(options[:metadata_file])
281
230
  ::Nokogiri::XML(data).remove_namespaces!
282
231
  else # From a URL
232
+ response = nil
283
233
  METADATA_TIMEOUTS.each do |timeout|
284
- response = ::Typhoeus::Request.get(URI.escape(metadata_url),
285
- options[:typhoeus].merge(timeout: timeout))
234
+ response = execute(metadata_url, timeout: timeout)
286
235
  break unless response.timed_out?
287
236
  end
288
237
  raise "Metadata Timeout" if response.timed_out?
289
- validate_response(response)
290
238
  ::Nokogiri::XML(response.body).remove_namespaces!
291
239
  end
292
240
  end
293
241
 
294
- def validate_response(response)
295
- raise "Bad Request. #{error_message(response)}" if response.code == 400
296
- raise "Access Denied" if response.code == 401
297
- raise "Forbidden" if response.code == 403
298
- raise "Not Found" if [0,404].include?(response.code)
299
- raise "Method Not Allowed" if response.code == 405
300
- raise "Not Acceptable" if response.code == 406
301
- raise "Request Entity Too Large" if response.code == 413
302
- raise "Internal Server Error" if response.code == 500
303
- raise "Service Unavailable" if response.code == 503
304
- end
305
-
306
- def error_message(response)
307
- OData4::Query::Result.new(nil, response).error_message
308
- end
309
-
310
242
  def register_custom_types
311
243
  complex_types.each do |name, type|
312
244
  ::OData4::PropertyRegistry.add(name, type.property_class)
@@ -1,3 +1,3 @@
1
1
  module OData4
2
- VERSION = '0.8.0'
2
+ VERSION = '0.8.1'
3
3
  end
data/lib/odata4.rb CHANGED
@@ -21,9 +21,6 @@ require 'odata4/enum_type'
21
21
  require 'odata4/entity'
22
22
  require 'odata4/entity_container'
23
23
  require 'odata4/entity_set'
24
- require 'odata4/query/criteria'
25
- require 'odata4/query/result'
26
- require 'odata4/query/in_batches'
27
24
  require 'odata4/query'
28
25
  require 'odata4/schema'
29
26
  require 'odata4/service'
@@ -1,6 +1,6 @@
1
1
  <?xml version="1.0"?>
2
2
  <entry xmlns="http://www.w3.org/2005/Atom" xmlns:data="http://docs.oasis-open.org/odata/ns/data" xmlns:metadata="http://docs.oasis-open.org/odata/ns/metadata" xmlns:georss="http://www.georss.org/georss" xmlns:gml="http://www.opengis.net/gml" xml:base="http://services.odata.org/V4/OData/OData.svc">
3
- <category term="ODataDemo.ODataDemo.Product" scheme="http://docs.oasis-open.org/odata/ns/scheme"/>
3
+ <category term="ODataDemo.Product" scheme="http://docs.oasis-open.org/odata/ns/scheme"/>
4
4
  <author>
5
5
  <name/>
6
6
  </author>
@@ -0,0 +1,5 @@
1
+ <?xml version="1.0" encoding="utf-8"?>
2
+ <m:error xmlns:m="http://docs.oasis-open.org/odata/ns/metadata">
3
+ <m:code />
4
+ <m:message>Resource not found for the segment 'Products'.</m:message>
5
+ </m:error>
@@ -0,0 +1,193 @@
1
+ ---
2
+ http_interactions:
3
+ - request:
4
+ method: get
5
+ uri: http://services.odata.org/V4/OData/OData.svc/Products
6
+ body:
7
+ encoding: US-ASCII
8
+ string: ''
9
+ headers:
10
+ User-Agent:
11
+ - Typhoeus - https://github.com/typhoeus/typhoeus
12
+ OData4-Version:
13
+ - '4.0'
14
+ Accept:
15
+ - application/atom+xml,application/json,application/xml,text/plain
16
+ Expect:
17
+ - ''
18
+ response:
19
+ status:
20
+ code: 200
21
+ message: OK
22
+ headers:
23
+ Cache-Control:
24
+ - no-cache
25
+ Content-Length:
26
+ - '1981'
27
+ Content-Type:
28
+ - application/json;odata.metadata=minimal;odata.streaming=true;IEEE754Compatible=false;charset=utf-8
29
+ Server:
30
+ - Microsoft-IIS/10.0
31
+ X-Content-Type-Options:
32
+ - nosniff
33
+ OData-Version:
34
+ - 4.0;
35
+ X-AspNet-Version:
36
+ - 4.0.30319
37
+ X-Powered-By:
38
+ - ASP.NET
39
+ Access-Control-Allow-Origin:
40
+ - "*"
41
+ Access-Control-Allow-Methods:
42
+ - GET
43
+ Access-Control-Allow-Headers:
44
+ - Accept, Origin, Content-Type, MaxDataServiceVersion
45
+ Access-Control-Expose-Headers:
46
+ - DataServiceVersion
47
+ Date:
48
+ - Thu, 15 Feb 2018 19:55:09 GMT
49
+ body:
50
+ encoding: UTF-8
51
+ string: '{"@odata.context":"http://services.odata.org/V4/OData/OData.svc/$metadata#Products","value":[{"ID":0,"Name":"Bread","Description":"Whole
52
+ grain bread","ReleaseDate":"1992-01-01T00:00:00Z","DiscontinuedDate":null,"Rating":4,"Price":2.5},{"ID":1,"Name":"Milk","Description":"Low
53
+ fat milk","ReleaseDate":"1995-10-01T00:00:00Z","DiscontinuedDate":null,"Rating":3,"Price":3.5},{"ID":2,"Name":"Vint
54
+ soda","Description":"Americana Variety - Mix of 6 flavors","ReleaseDate":"2000-10-01T00:00:00Z","DiscontinuedDate":null,"Rating":3,"Price":20.9},{"ID":3,"Name":"Havina
55
+ Cola","Description":"The Original Key Lime Cola","ReleaseDate":"2005-10-01T00:00:00Z","DiscontinuedDate":"2006-10-01T00:00:00Z","Rating":3,"Price":19.9},{"ID":4,"Name":"Fruit
56
+ Punch","Description":"Mango flavor, 8.3 Ounce Cans (Pack of 24)","ReleaseDate":"2003-01-05T00:00:00Z","DiscontinuedDate":null,"Rating":3,"Price":22.99},{"ID":5,"Name":"Cranberry
57
+ Juice","Description":"16-Ounce Plastic Bottles (Pack of 12)","ReleaseDate":"2006-08-04T00:00:00Z","DiscontinuedDate":null,"Rating":3,"Price":22.8},{"ID":6,"Name":"Pink
58
+ Lemonade","Description":"36 Ounce Cans (Pack of 3)","ReleaseDate":"2006-11-05T00:00:00Z","DiscontinuedDate":null,"Rating":3,"Price":18.8},{"ID":7,"Name":"DVD
59
+ Player","Description":"1080P Upconversion DVD Player","ReleaseDate":"2006-11-15T00:00:00Z","DiscontinuedDate":null,"Rating":5,"Price":35.88},{"ID":8,"Name":"LCD
60
+ HDTV","Description":"42 inch 1080p LCD with Built-in Blu-ray Disc Player","ReleaseDate":"2008-05-08T00:00:00Z","DiscontinuedDate":null,"Rating":3,"Price":1088.8},{"@odata.type":"#ODataDemo.FeaturedProduct","ID":9,"Name":"Lemonade","Description":"Classic,
61
+ refreshing lemonade (Single bottle)","ReleaseDate":"1970-01-01T00:00:00Z","DiscontinuedDate":null,"Rating":7,"Price":1.01},{"@odata.type":"#ODataDemo.FeaturedProduct","ID":10,"Name":"Coffee","Description":"Bulk
62
+ size can of instant coffee","ReleaseDate":"1982-12-31T00:00:00Z","DiscontinuedDate":null,"Rating":1,"Price":6.99}]}'
63
+ http_version: '1.1'
64
+ adapter_metadata:
65
+ effective_url: http://services.odata.org/V4/OData/OData.svc/Products
66
+ recorded_at: Thu, 15 Feb 2018 19:55:10 GMT
67
+ - request:
68
+ method: get
69
+ uri: http://services.odata.org/V4/OData/OData.svc/$metadata
70
+ body:
71
+ encoding: US-ASCII
72
+ string: ''
73
+ headers:
74
+ User-Agent:
75
+ - Typhoeus - https://github.com/typhoeus/typhoeus
76
+ OData4-Version:
77
+ - '4.0'
78
+ Expect:
79
+ - ''
80
+ response:
81
+ status:
82
+ code: 200
83
+ message: OK
84
+ headers:
85
+ Cache-Control:
86
+ - no-cache
87
+ Content-Length:
88
+ - '6742'
89
+ Content-Type:
90
+ - application/xml;charset=utf-8
91
+ Server:
92
+ - Microsoft-IIS/10.0
93
+ X-Content-Type-Options:
94
+ - nosniff
95
+ OData-Version:
96
+ - 4.0;
97
+ X-AspNet-Version:
98
+ - 4.0.30319
99
+ X-Powered-By:
100
+ - ASP.NET
101
+ Access-Control-Allow-Origin:
102
+ - "*"
103
+ Access-Control-Allow-Methods:
104
+ - GET
105
+ Access-Control-Allow-Headers:
106
+ - Accept, Origin, Content-Type, MaxDataServiceVersion
107
+ Access-Control-Expose-Headers:
108
+ - DataServiceVersion
109
+ Date:
110
+ - Thu, 15 Feb 2018 20:48:14 GMT
111
+ body:
112
+ encoding: UTF-8
113
+ string: <?xml version="1.0" encoding="utf-8"?><edmx:Edmx Version="4.0" xmlns:edmx="http://docs.oasis-open.org/odata/ns/edmx"><edmx:DataServices><Schema
114
+ Namespace="ODataDemo" xmlns="http://docs.oasis-open.org/odata/ns/edm"><EntityType
115
+ Name="Product"><Key><PropertyRef Name="ID" /></Key><Property Name="ID" Type="Edm.Int32"
116
+ Nullable="false" /><Property Name="Name" Type="Edm.String" /><Property Name="Description"
117
+ Type="Edm.String" /><Property Name="ReleaseDate" Type="Edm.DateTimeOffset"
118
+ Nullable="false" /><Property Name="DiscontinuedDate" Type="Edm.DateTimeOffset"
119
+ /><Property Name="Rating" Type="Edm.Int16" Nullable="false" /><Property Name="Price"
120
+ Type="Edm.Double" Nullable="false" /><NavigationProperty Name="Categories"
121
+ Type="Collection(ODataDemo.Category)" Partner="Products" /><NavigationProperty
122
+ Name="Supplier" Type="ODataDemo.Supplier" Partner="Products" /><NavigationProperty
123
+ Name="ProductDetail" Type="ODataDemo.ProductDetail" Partner="Product" /></EntityType><EntityType
124
+ Name="FeaturedProduct" BaseType="ODataDemo.Product"><NavigationProperty Name="Advertisement"
125
+ Type="ODataDemo.Advertisement" Partner="FeaturedProduct" /></EntityType><EntityType
126
+ Name="ProductDetail"><Key><PropertyRef Name="ProductID" /></Key><Property
127
+ Name="ProductID" Type="Edm.Int32" Nullable="false" /><Property Name="Details"
128
+ Type="Edm.String" /><NavigationProperty Name="Product" Type="ODataDemo.Product"
129
+ Partner="ProductDetail" /></EntityType><EntityType Name="Category" OpenType="true"><Key><PropertyRef
130
+ Name="ID" /></Key><Property Name="ID" Type="Edm.Int32" Nullable="false" /><Property
131
+ Name="Name" Type="Edm.String" /><NavigationProperty Name="Products" Type="Collection(ODataDemo.Product)"
132
+ Partner="Categories" /></EntityType><EntityType Name="Supplier"><Key><PropertyRef
133
+ Name="ID" /></Key><Property Name="ID" Type="Edm.Int32" Nullable="false" /><Property
134
+ Name="Name" Type="Edm.String" /><Property Name="Address" Type="ODataDemo.Address"
135
+ /><Property Name="Location" Type="Edm.GeographyPoint" SRID="Variable" /><Property
136
+ Name="Concurrency" Type="Edm.Int32" ConcurrencyMode="Fixed" Nullable="false"
137
+ /><NavigationProperty Name="Products" Type="Collection(ODataDemo.Product)"
138
+ Partner="Supplier" /></EntityType><ComplexType Name="Address"><Property Name="Street"
139
+ Type="Edm.String" /><Property Name="City" Type="Edm.String" /><Property Name="State"
140
+ Type="Edm.String" /><Property Name="ZipCode" Type="Edm.String" /><Property
141
+ Name="Country" Type="Edm.String" /></ComplexType><EntityType Name="Person"><Key><PropertyRef
142
+ Name="ID" /></Key><Property Name="ID" Type="Edm.Int32" Nullable="false" /><Property
143
+ Name="Name" Type="Edm.String" /><NavigationProperty Name="PersonDetail" Type="ODataDemo.PersonDetail"
144
+ Partner="Person" /></EntityType><EntityType Name="Customer" BaseType="ODataDemo.Person"><Property
145
+ Name="TotalExpense" Type="Edm.Decimal" Nullable="false" /></EntityType><EntityType
146
+ Name="Employee" BaseType="ODataDemo.Person"><Property Name="EmployeeID" Type="Edm.Int64"
147
+ Nullable="false" /><Property Name="HireDate" Type="Edm.DateTimeOffset" Nullable="false"
148
+ /><Property Name="Salary" Type="Edm.Single" Nullable="false" /></EntityType><EntityType
149
+ Name="PersonDetail"><Key><PropertyRef Name="PersonID" /></Key><Property Name="PersonID"
150
+ Type="Edm.Int32" Nullable="false" /><Property Name="Age" Type="Edm.Byte" Nullable="false"
151
+ /><Property Name="Gender" Type="Edm.Boolean" Nullable="false" /><Property
152
+ Name="Phone" Type="Edm.String" /><Property Name="Address" Type="ODataDemo.Address"
153
+ /><Property Name="Photo" Type="Edm.Stream" Nullable="false" /><NavigationProperty
154
+ Name="Person" Type="ODataDemo.Person" Partner="PersonDetail" /></EntityType><EntityType
155
+ Name="Advertisement" HasStream="true"><Key><PropertyRef Name="ID" /></Key><Property
156
+ Name="ID" Type="Edm.Guid" Nullable="false" /><Property Name="Name" Type="Edm.String"
157
+ /><Property Name="AirDate" Type="Edm.DateTimeOffset" Nullable="false" /><NavigationProperty
158
+ Name="FeaturedProduct" Type="ODataDemo.FeaturedProduct" Partner="Advertisement"
159
+ /></EntityType><EntityContainer Name="DemoService"><EntitySet Name="Products"
160
+ EntityType="ODataDemo.Product"><NavigationPropertyBinding Path="ODataDemo.FeaturedProduct/Advertisement"
161
+ Target="Advertisements" /><NavigationPropertyBinding Path="Categories" Target="Categories"
162
+ /><NavigationPropertyBinding Path="Supplier" Target="Suppliers" /><NavigationPropertyBinding
163
+ Path="ProductDetail" Target="ProductDetails" /></EntitySet><EntitySet Name="ProductDetails"
164
+ EntityType="ODataDemo.ProductDetail"><NavigationPropertyBinding Path="Product"
165
+ Target="Products" /></EntitySet><EntitySet Name="Categories" EntityType="ODataDemo.Category"><NavigationPropertyBinding
166
+ Path="Products" Target="Products" /></EntitySet><EntitySet Name="Suppliers"
167
+ EntityType="ODataDemo.Supplier"><NavigationPropertyBinding Path="Products"
168
+ Target="Products" /></EntitySet><EntitySet Name="Persons" EntityType="ODataDemo.Person"><NavigationPropertyBinding
169
+ Path="PersonDetail" Target="PersonDetails" /></EntitySet><EntitySet Name="PersonDetails"
170
+ EntityType="ODataDemo.PersonDetail"><NavigationPropertyBinding Path="Person"
171
+ Target="Persons" /></EntitySet><EntitySet Name="Advertisements" EntityType="ODataDemo.Advertisement"><NavigationPropertyBinding
172
+ Path="FeaturedProduct" Target="Products" /></EntitySet></EntityContainer><Annotations
173
+ Target="ODataDemo.DemoService"><Annotation Term="Org.OData.Display.V1.Description"
174
+ String="This is a sample OData service with vocabularies" /></Annotations><Annotations
175
+ Target="ODataDemo.Product"><Annotation Term="Org.OData.Display.V1.Description"
176
+ String="All Products available in the online store" /></Annotations><Annotations
177
+ Target="ODataDemo.Product/Name"><Annotation Term="Org.OData.Display.V1.DisplayName"
178
+ String="Product Name" /></Annotations><Annotations Target="ODataDemo.DemoService/Suppliers"><Annotation
179
+ Term="Org.OData.Publication.V1.PublisherName" String="Microsoft Corp." /><Annotation
180
+ Term="Org.OData.Publication.V1.PublisherId" String="MSFT" /><Annotation Term="Org.OData.Publication.V1.Keywords"
181
+ String="Inventory, Supplier, Advertisers, Sales, Finance" /><Annotation Term="Org.OData.Publication.V1.AttributionUrl"
182
+ String="http://www.odata.org/" /><Annotation Term="Org.OData.Publication.V1.AttributionDescription"
183
+ String="All rights reserved" /><Annotation Term="Org.OData.Publication.V1.DocumentationUrl
184
+ " String="http://www.odata.org/" /><Annotation Term="Org.OData.Publication.V1.TermsOfUseUrl"
185
+ String="All rights reserved" /><Annotation Term="Org.OData.Publication.V1.PrivacyPolicyUrl"
186
+ String="http://www.odata.org/" /><Annotation Term="Org.OData.Publication.V1.LastModified"
187
+ String="4/2/2013" /><Annotation Term="Org.OData.Publication.V1.ImageUrl "
188
+ String="http://www.odata.org/" /></Annotations></Schema></edmx:DataServices></edmx:Edmx>
189
+ http_version: '1.1'
190
+ adapter_metadata:
191
+ effective_url: http://services.odata.org/V4/OData/OData.svc/$metadata
192
+ recorded_at: Thu, 15 Feb 2018 20:48:14 GMT
193
+ recorded_with: VCR 4.0.0
@@ -0,0 +1,44 @@
1
+ require 'spec_helper'
2
+
3
+ describe OData4::Properties::Collection do
4
+ let(:subject) { OData4::Properties::Collection.new('Names', names) }
5
+ let(:names) { %w[Dan Greg Jon] }
6
+ let(:new_names) { %w[Andrew Doug Paul] }
7
+
8
+ it { expect(subject.type).to eq('Collection(Edm.String)') }
9
+ it { expect(subject.value).to eq(['Dan', 'Greg', 'Jon']) }
10
+ it { expect(subject.url_value).to eq("['Dan','Greg','Jon']") }
11
+
12
+ describe '#value=' do
13
+ it 'allows an array of string values to be set' do
14
+ subject.value = new_names
15
+ expect(subject.value).to eq(new_names)
16
+ end
17
+ end
18
+
19
+ # TODO: Make collection type work properly with data types other than string
20
+ xcontext 'with value type other than Edm.String' do
21
+ let(:subject) { OData4::Properties::Collection.new('Bits', [1, 0, 1], value_type: 'Edm.Binary') }
22
+
23
+ it { expect(subject.type).to eq('Collection(Edm.Int32)') }
24
+ it { expect(subject.value).to eq([1, 0, 1]) }
25
+ it { expect(subject.url_value).to eq('[1,0,1]') }
26
+
27
+ it 'does not allow other property types to be set' do
28
+ expect {
29
+ subject.value = names
30
+ }.to raise_error(ArgumentError)
31
+ end
32
+
33
+ xdescribe 'lenient validation' do
34
+ let(:subject) do
35
+ OData4::Properties::Collection.new('Names', names, value_type: 'Edm.String', strict: false)
36
+ end
37
+
38
+ it 'ignores invalid values' do
39
+ subject.value = [1, 2, 3]
40
+ expect(subject.value).to eq([])
41
+ end
42
+ end
43
+ end
44
+ end
@@ -132,7 +132,7 @@ describe OData4::Query, vcr: {cassette_name: 'query_specs'} do
132
132
 
133
133
  describe '#execute' do
134
134
  it { expect(subject).to respond_to(:execute) }
135
- it { expect(subject.execute).to be_a(OData4::Query::Result) }
135
+ it { expect(subject.execute).to be_a(OData4::Service::Response) }
136
136
  end
137
137
 
138
138
  describe '#count' do
@@ -166,7 +166,7 @@ describe OData4::Query, vcr: {cassette_name: 'query_specs'} do
166
166
  batch_count = entity_count = 0
167
167
 
168
168
  subject.in_batches(of: 5) do |batch|
169
- expect(batch).to be_a(OData4::Query::Result)
169
+ expect(batch).to be_a(OData4::Service::Response)
170
170
  expect(batch.count).to eq(5) unless batch_count == 2
171
171
 
172
172
  batch.each do |entity|
@@ -0,0 +1,49 @@
1
+ require 'spec_helper'
2
+
3
+ describe OData4::Service::Request, vcr: {cassette_name: 'service/request_specs'} do
4
+ let(:subject) { OData4::Service::Request.new(service, 'Products') }
5
+ let(:service) { OData4::Service.open(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(OData4::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(OData4::Service::Response)
46
+ end
47
+ it 'retries on wrong content type'
48
+ end
49
+ end
@@ -0,0 +1,77 @@
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 OData4::Entities of the right type' do
15
+ subject.each do |entity|
16
+ expect(entity).to be_a(OData4::Entity)
17
+ expect(entity.type).to eq('ODataDemo.Product')
18
+ end
19
+ end
20
+ end
21
+ end
22
+
23
+ describe OData4::Service::Response, vcr: {cassette_name: 'service/response_specs'} do
24
+ let(:subject) { OData4::Service::Response.new(service, response, entity_set.query) }
25
+ let(:service) { OData4::Service.open(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
+ code: 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
+ end