odata4 0.8.0 → 0.8.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -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