ruby_odata 0.1.6 → 0.2.0.beta1
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.
- checksums.yaml +4 -4
- data/.travis.yml +2 -0
- data/CHANGELOG.md +5 -0
- data/Gemfile +2 -0
- data/Guardfile +1 -1
- data/features/basic_auth.feature +13 -13
- data/features/cassettes/basic_auth_protected_resource.yml +22 -20
- data/features/cassettes/batch_request_additions.yml +26 -26
- data/features/cassettes/batch_request_deletes.yml +27 -27
- data/features/cassettes/batch_request_updates.yml +26 -26
- data/features/cassettes/clean_database_for_testing.yml +10 -10
- data/features/cassettes/cucumber_tags/basic_auth.yml +54 -163
- data/features/cassettes/cucumber_tags/batch_request.yml +229 -1118
- data/features/cassettes/cucumber_tags/complex_types.yml +81 -191
- data/features/cassettes/cucumber_tags/error_handling.yml +45 -33
- data/features/cassettes/cucumber_tags/query_builder.yml +555 -1248
- data/features/cassettes/cucumber_tags/service_manage.yml +216 -591
- data/features/cassettes/cucumber_tags/service_methods.yml +137 -412
- data/features/cassettes/cucumber_tags/ssl.yml +121 -117
- data/features/cassettes/cucumber_tags/type_conversion.yml +104 -170
- data/features/cassettes/service_manage_additions.yml +26 -28
- data/features/cassettes/service_manage_deletions.yml +21 -21
- data/features/cassettes/service_manage_deletions_2.yml +21 -21
- data/features/cassettes/unsecured_metadata.yml +14 -14
- data/features/service.feature +37 -37
- data/features/service_methods.feature +38 -38
- data/features/step_definitions/pickle_steps.rb +5 -5
- data/features/step_definitions/service_steps.rb +26 -26
- data/features/support/hooks.rb +3 -2
- data/features/support/vcr.rb +13 -13
- data/lib/ruby_odata.rb +4 -1
- data/lib/ruby_odata/association.rb +15 -8
- data/lib/ruby_odata/class_builder.rb +5 -1
- data/lib/ruby_odata/query_builder.rb +171 -173
- data/lib/ruby_odata/resource.rb +153 -0
- data/lib/ruby_odata/service.rb +30 -30
- data/lib/ruby_odata/version.rb +1 -1
- data/ruby_odata.gemspec +48 -43
- data/spec/association_spec.rb +15 -11
- data/spec/fixtures/decimal/metadata.xml +1 -0
- data/spec/fixtures/v4/edmx_metadata.xml +145 -0
- data/spec/fixtures/v4/result_categories.xml +0 -0
- data/spec/revised_service_spec.rb +16 -11
- data/spec/service_spec.rb +149 -114
- data/spec/service_v4_spec.rb +102 -0
- data/spec/spec_helper.rb +6 -1
- metadata +109 -32
- data/features/cassettes/cucumber_tags/service.yml +0 -234
@@ -0,0 +1,153 @@
|
|
1
|
+
module OData
|
2
|
+
class Resource
|
3
|
+
attr_reader :url, :options, :block
|
4
|
+
|
5
|
+
def initialize(url, options={}, backwards_compatibility=nil, &block)
|
6
|
+
@url = url
|
7
|
+
@block = block
|
8
|
+
@options = options.is_a?(Hash) ? options : { user: options, password: backwards_compatibility }
|
9
|
+
|
10
|
+
@conn = Faraday.new(url: url, ssl: { verify: verify_ssl }) do |faraday|
|
11
|
+
faraday.use :gzip
|
12
|
+
faraday.response :raise_error
|
13
|
+
faraday.adapter :excon
|
14
|
+
|
15
|
+
faraday.options.timeout = timeout if timeout
|
16
|
+
faraday.options.open_timeout = open_timeout if open_timeout
|
17
|
+
|
18
|
+
faraday.headers = (faraday.headers || {}).merge(@options[:headers] || {})
|
19
|
+
faraday.headers = (faraday.headers).merge({
|
20
|
+
:accept => '*/*; q=0.5, application/xml',
|
21
|
+
})
|
22
|
+
|
23
|
+
faraday.basic_auth user, password if user# this adds to headers so must be behind
|
24
|
+
end
|
25
|
+
|
26
|
+
@conn.headers[:user_agent] = 'Ruby'
|
27
|
+
end
|
28
|
+
|
29
|
+
def get(additional_headers={})
|
30
|
+
@conn.get do |req|
|
31
|
+
req.url url
|
32
|
+
req.headers = (headers || {}).merge(additional_headers)
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
def head(additional_headers={})
|
37
|
+
@conn.head do |req|
|
38
|
+
req.url url
|
39
|
+
req.headers = (headers || {}).merge(additional_headers)
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
def post(payload, additional_headers={})
|
44
|
+
@conn.post do |req|
|
45
|
+
req.url url
|
46
|
+
req.headers = (headers || {}).merge(additional_headers)
|
47
|
+
req.body = prepare_payload payload
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
def put(payload, additional_headers={})
|
52
|
+
@conn.put do |req|
|
53
|
+
req.url url
|
54
|
+
req.headers = (headers || {}).merge(additional_headers)
|
55
|
+
req.body = prepare_payload payload
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
def patch(payload, additional_headers={})
|
60
|
+
@conn.patch do |req|
|
61
|
+
req.url url
|
62
|
+
req.headers = (headers || {}).merge(additional_headers)
|
63
|
+
req.body = prepare_payload payload
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
67
|
+
def delete(additional_headers={})
|
68
|
+
@conn.delete do |req|
|
69
|
+
req.url url
|
70
|
+
req.headers = (headers || {}).merge(additional_headers)
|
71
|
+
end
|
72
|
+
end
|
73
|
+
|
74
|
+
def to_s
|
75
|
+
url
|
76
|
+
end
|
77
|
+
|
78
|
+
def user
|
79
|
+
options[:user]
|
80
|
+
end
|
81
|
+
|
82
|
+
def password
|
83
|
+
options[:password]
|
84
|
+
end
|
85
|
+
|
86
|
+
def verify_ssl
|
87
|
+
options[:verify_ssl]
|
88
|
+
end
|
89
|
+
|
90
|
+
def headers
|
91
|
+
@conn.headers || {}
|
92
|
+
end
|
93
|
+
|
94
|
+
def timeout
|
95
|
+
options[:timeout]
|
96
|
+
end
|
97
|
+
|
98
|
+
def open_timeout
|
99
|
+
options[:open_timeout]
|
100
|
+
end
|
101
|
+
|
102
|
+
# Construct a subresource, preserving authentication.
|
103
|
+
#
|
104
|
+
# Example:
|
105
|
+
#
|
106
|
+
# site = RestClient::Resource.new('http://example.com', 'adam', 'mypasswd')
|
107
|
+
# site['posts/1/comments'].post 'Good article.', :content_type => 'text/plain'
|
108
|
+
#
|
109
|
+
# This is especially useful if you wish to define your site in one place and
|
110
|
+
# call it in multiple locations:
|
111
|
+
#
|
112
|
+
# def orders
|
113
|
+
# RestClient::Resource.new('http://example.com/orders', 'admin', 'mypasswd')
|
114
|
+
# end
|
115
|
+
#
|
116
|
+
# orders.get # GET http://example.com/orders
|
117
|
+
# orders['1'].get # GET http://example.com/orders/1
|
118
|
+
# orders['1/items'].delete # DELETE http://example.com/orders/1/items
|
119
|
+
#
|
120
|
+
# Nest resources as far as you want:
|
121
|
+
#
|
122
|
+
# site = RestClient::Resource.new('http://example.com')
|
123
|
+
# posts = site['posts']
|
124
|
+
# first_post = posts['1']
|
125
|
+
# comments = first_post['comments']
|
126
|
+
# comments.post 'Hello', :content_type => 'text/plain'
|
127
|
+
#
|
128
|
+
def [](suburl, &new_block)
|
129
|
+
case
|
130
|
+
when block_given? then self.class.new(concat_urls(url, suburl), options, &new_block)
|
131
|
+
when block then self.class.new(concat_urls(url, suburl), options, &block)
|
132
|
+
else
|
133
|
+
self.class.new(concat_urls(url, suburl), options)
|
134
|
+
end
|
135
|
+
end
|
136
|
+
|
137
|
+
def concat_urls(url, suburl) # :nodoc:
|
138
|
+
url = url.to_s
|
139
|
+
suburl = suburl.to_s
|
140
|
+
if url.slice(-1, 1) == '/' or suburl.slice(0, 1) == '/'
|
141
|
+
url + suburl
|
142
|
+
else
|
143
|
+
"#{url}/#{suburl}"
|
144
|
+
end
|
145
|
+
end
|
146
|
+
|
147
|
+
def prepare_payload payload
|
148
|
+
JSON.generate(payload)
|
149
|
+
rescue JSON::GeneratorError
|
150
|
+
payload
|
151
|
+
end
|
152
|
+
end
|
153
|
+
end
|
data/lib/ruby_odata/service.rb
CHANGED
@@ -9,7 +9,7 @@ class Service
|
|
9
9
|
# @option options [String] :username for http basic auth
|
10
10
|
# @option options [String] :password for http basic auth
|
11
11
|
# @option options [Object] :verify_ssl false if no verification, otherwise mode (OpenSSL::SSL::VERIFY_PEER is default)
|
12
|
-
# @option options [Hash] :rest_options a hash of rest-client options that will be passed to all
|
12
|
+
# @option options [Hash] :rest_options a hash of rest-client options that will be passed to all OData::Resource.new calls
|
13
13
|
# @option options [Hash] :additional_params a hash of query string params that will be passed on all calls
|
14
14
|
# @option options [Boolean, true] :eager_partial true if queries should consume partial feeds until the feed is complete, false if explicit calls to next must be performed
|
15
15
|
def initialize(service_uri, options = {})
|
@@ -97,12 +97,12 @@ class Service
|
|
97
97
|
# @raise [ServiceError] if there is an error when talking to the service
|
98
98
|
def execute
|
99
99
|
begin
|
100
|
-
@response =
|
100
|
+
@response = OData::Resource.new(build_query_uri, @rest_options).get
|
101
101
|
rescue Exception => e
|
102
102
|
handle_exception(e)
|
103
103
|
end
|
104
|
-
return Integer(@response) if @response =~ /^\d+$/
|
105
|
-
handle_collection_result(@response)
|
104
|
+
return Integer(@response.body) if @response.body =~ /^\d+$/
|
105
|
+
handle_collection_result(@response.body)
|
106
106
|
end
|
107
107
|
|
108
108
|
# Overridden to identify methods handled by method_missing
|
@@ -147,8 +147,8 @@ class Service
|
|
147
147
|
raise NotSupportedError, "You cannot load a property on an entity that isn't tracked" if obj.send(:__metadata).nil?
|
148
148
|
raise ArgumentError, "'#{nav_prop}' is not a valid navigation property" unless obj.respond_to?(nav_prop.to_sym)
|
149
149
|
raise ArgumentError, "'#{nav_prop}' is not a valid navigation property" unless @class_metadata[obj.class.to_s][nav_prop].nav_prop
|
150
|
-
results =
|
151
|
-
prop_results = build_classes_from_result(results)
|
150
|
+
results = OData::Resource.new(build_load_property_uri(obj, nav_prop), @rest_options).get
|
151
|
+
prop_results = build_classes_from_result(results.body)
|
152
152
|
obj.send "#{nav_prop}=", (singular?(nav_prop) ? prop_results.first : prop_results)
|
153
153
|
end
|
154
154
|
|
@@ -224,7 +224,7 @@ class Service
|
|
224
224
|
@rest_options.merge!(options[:rest_options] || {})
|
225
225
|
@additional_params = options[:additional_params] || {}
|
226
226
|
@namespace = options[:namespace]
|
227
|
-
@json_type = options[:json_type] ||
|
227
|
+
@json_type = options[:json_type] || 'application/json'
|
228
228
|
end
|
229
229
|
|
230
230
|
def default_instance_vars!
|
@@ -236,7 +236,7 @@ class Service
|
|
236
236
|
end
|
237
237
|
|
238
238
|
def set_namespaces
|
239
|
-
@edmx = Nokogiri::XML(
|
239
|
+
@edmx = Nokogiri::XML(OData::Resource.new(build_metadata_uri, @rest_options).get.body)
|
240
240
|
@ds_namespaces = {
|
241
241
|
"m" => "http://schemas.microsoft.com/ado/2007/08/dataservices/metadata",
|
242
242
|
"edmx" => "http://schemas.microsoft.com/ado/2007/06/edmx",
|
@@ -376,8 +376,8 @@ class Service
|
|
376
376
|
def handle_exception(e)
|
377
377
|
raise e unless defined? e.response
|
378
378
|
|
379
|
-
code = e.
|
380
|
-
error = Nokogiri::XML(e.response)
|
379
|
+
code = e.response[:status]
|
380
|
+
error = Nokogiri::XML(e.response[:body])
|
381
381
|
|
382
382
|
message = if error.xpath("m:error/m:message", @ds_namespaces).first
|
383
383
|
error.xpath("m:error/m:message", @ds_namespaces).first.content
|
@@ -509,8 +509,8 @@ class Service
|
|
509
509
|
|
510
510
|
def handle_partial
|
511
511
|
if @next_uri
|
512
|
-
result =
|
513
|
-
results = handle_collection_result(result)
|
512
|
+
result = OData::Resource.new(@next_uri, @rest_options).get
|
513
|
+
results = handle_collection_result(result.body)
|
514
514
|
end
|
515
515
|
results
|
516
516
|
end
|
@@ -600,26 +600,26 @@ class Service
|
|
600
600
|
if operation.kind == "Add"
|
601
601
|
save_uri = build_save_uri(operation)
|
602
602
|
json_klass = operation.klass.to_json(:type => :add)
|
603
|
-
post_result =
|
604
|
-
return build_classes_from_result(post_result)
|
603
|
+
post_result = OData::Resource.new(save_uri, @rest_options).post json_klass, {:content_type => @json_type}
|
604
|
+
return build_classes_from_result(post_result.body)
|
605
605
|
elsif operation.kind == "Update"
|
606
606
|
update_uri = build_resource_uri(operation)
|
607
607
|
json_klass = operation.klass.to_json
|
608
|
-
update_result =
|
609
|
-
return (update_result.
|
608
|
+
update_result = OData::Resource.new(update_uri, @rest_options).put json_klass, {:content_type => @json_type}
|
609
|
+
return (update_result.status == 204)
|
610
610
|
elsif operation.kind == "Delete"
|
611
611
|
delete_uri = build_resource_uri(operation)
|
612
|
-
delete_result =
|
613
|
-
return (delete_result.
|
612
|
+
delete_result = OData::Resource.new(delete_uri, @rest_options).delete
|
613
|
+
return (delete_result.status == 204)
|
614
614
|
elsif operation.kind == "AddLink"
|
615
615
|
save_uri = build_add_link_uri(operation)
|
616
616
|
json_klass = operation.child_klass.to_json(:type => :link)
|
617
|
-
post_result =
|
617
|
+
post_result = OData::Resource.new(save_uri, @rest_options).post json_klass, {:content_type => @json_type}
|
618
618
|
|
619
619
|
# Attach the child to the parent
|
620
|
-
link_child_to_parent(operation) if (post_result.
|
620
|
+
link_child_to_parent(operation) if (post_result.status == 204)
|
621
621
|
|
622
|
-
return(post_result.
|
622
|
+
return(post_result.status == 204)
|
623
623
|
end
|
624
624
|
end
|
625
625
|
|
@@ -633,11 +633,11 @@ class Service
|
|
633
633
|
batch_uri = build_batch_uri
|
634
634
|
|
635
635
|
body = build_batch_body(operations, batch_num, changeset_num)
|
636
|
-
result =
|
636
|
+
result = OData::Resource.new( batch_uri, @rest_options).post body, {:content_type => "multipart/mixed; boundary=batch_#{batch_num}"}
|
637
637
|
|
638
638
|
# TODO: More result validation needs to be done.
|
639
639
|
# The result returns HTTP 202 even if there is an error in the batch
|
640
|
-
return (result.
|
640
|
+
return (result.status == 202)
|
641
641
|
end
|
642
642
|
def build_batch_body(operations, batch_num, changeset_num)
|
643
643
|
# Header
|
@@ -827,17 +827,17 @@ class Service
|
|
827
827
|
func[:parameters].keys.each_with_index { |key, i| params[key] = args[0][i] } unless func[:parameters].nil?
|
828
828
|
|
829
829
|
function_uri = build_function_import_uri(name, params)
|
830
|
-
result =
|
830
|
+
result = OData::Resource.new(function_uri, @rest_options).send(func[:http_method].downcase, {})
|
831
831
|
|
832
832
|
# Is this a 204 (No content) result?
|
833
|
-
return true if result.
|
833
|
+
return true if result.status == 204
|
834
834
|
|
835
835
|
# No? Then we need to parse the results. There are 4 kinds...
|
836
836
|
if func[:return_type] == Array
|
837
837
|
# a collection of entites
|
838
|
-
return build_classes_from_result(result) if @classes.include?(func[:inner_return_type].to_s)
|
838
|
+
return build_classes_from_result(result.body) if @classes.include?(func[:inner_return_type].to_s)
|
839
839
|
# a collection of native types
|
840
|
-
elements = Nokogiri::XML(result).xpath("//ds:element", @ds_namespaces)
|
840
|
+
elements = Nokogiri::XML(result.body).xpath("//ds:element", @ds_namespaces)
|
841
841
|
results = []
|
842
842
|
elements.each do |e|
|
843
843
|
results << parse_primative_type(e.content, func[:inner_return_type])
|
@@ -847,18 +847,18 @@ class Service
|
|
847
847
|
|
848
848
|
# a single entity
|
849
849
|
if @classes.include?(func[:return_type].to_s)
|
850
|
-
entry = Nokogiri::XML(result).xpath("atom:entry[not(ancestor::atom:entry)]", @ds_namespaces)
|
850
|
+
entry = Nokogiri::XML(result.body).xpath("atom:entry[not(ancestor::atom:entry)]", @ds_namespaces)
|
851
851
|
return entry_to_class(entry)
|
852
852
|
end
|
853
853
|
|
854
854
|
# or a single native type
|
855
855
|
unless func[:return_type].nil?
|
856
|
-
e = Nokogiri::XML(result).xpath("/*").first
|
856
|
+
e = Nokogiri::XML(result.body).xpath("/*").first
|
857
857
|
return parse_primative_type(e.content, func[:return_type])
|
858
858
|
end
|
859
859
|
|
860
860
|
# Nothing could be parsed, so just return if we got a 200 or not
|
861
|
-
return (result.
|
861
|
+
return (result.status == 200)
|
862
862
|
end
|
863
863
|
|
864
864
|
# Helpers
|
data/lib/ruby_odata/version.rb
CHANGED
data/ruby_odata.gemspec
CHANGED
@@ -1,43 +1,48 @@
|
|
1
|
-
# -*- encoding: utf-8 -*-
|
2
|
-
$:.push File.expand_path("../lib", __FILE__)
|
3
|
-
require "ruby_odata/version"
|
4
|
-
|
5
|
-
Gem::Specification.new do |s|
|
6
|
-
s.name = "ruby_odata"
|
7
|
-
s.version = OData::VERSION
|
8
|
-
s.platform = Gem::Platform::RUBY
|
9
|
-
s.authors = ["Damien White"]
|
10
|
-
s.email = ["damien.white@visoftinc.com"]
|
11
|
-
s.homepage = %q{http://github.com/visoft/ruby_odata}
|
12
|
-
s.summary = %q{Ruby consumer of OData services.}
|
13
|
-
s.description = %q{An OData Client Library for Ruby. Use this to interact with OData services}
|
14
|
-
s.license = "MIT"
|
15
|
-
|
16
|
-
s.rubyforge_project = "ruby-odata"
|
17
|
-
|
18
|
-
s.required_ruby_version = '>= 1.9.3'
|
19
|
-
|
20
|
-
s.add_dependency("addressable", ">= 2.3.4")
|
21
|
-
s.add_dependency("i18n", "
|
22
|
-
s.add_dependency("activesupport", ">= 3.0.0")
|
23
|
-
s.add_dependency("
|
24
|
-
s.add_dependency("
|
25
|
-
|
26
|
-
s.
|
27
|
-
|
28
|
-
s.add_development_dependency("
|
29
|
-
s.add_development_dependency("
|
30
|
-
s.add_development_dependency("
|
31
|
-
s.add_development_dependency("
|
32
|
-
s.add_development_dependency("
|
33
|
-
s.add_development_dependency("
|
34
|
-
s.add_development_dependency("
|
35
|
-
s.add_development_dependency("
|
36
|
-
s.add_development_dependency("
|
37
|
-
s.add_development_dependency("
|
38
|
-
|
39
|
-
s.
|
40
|
-
s.
|
41
|
-
s.
|
42
|
-
s.
|
43
|
-
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
$:.push File.expand_path("../lib", __FILE__)
|
3
|
+
require "ruby_odata/version"
|
4
|
+
|
5
|
+
Gem::Specification.new do |s|
|
6
|
+
s.name = "ruby_odata"
|
7
|
+
s.version = OData::VERSION
|
8
|
+
s.platform = Gem::Platform::RUBY
|
9
|
+
s.authors = ["Damien White"]
|
10
|
+
s.email = ["damien.white@visoftinc.com"]
|
11
|
+
s.homepage = %q{http://github.com/visoft/ruby_odata}
|
12
|
+
s.summary = %q{Ruby consumer of OData services.}
|
13
|
+
s.description = %q{An OData Client Library for Ruby. Use this to interact with OData services}
|
14
|
+
s.license = "MIT"
|
15
|
+
|
16
|
+
s.rubyforge_project = "ruby-odata"
|
17
|
+
|
18
|
+
s.required_ruby_version = '>= 1.9.3'
|
19
|
+
|
20
|
+
s.add_dependency("addressable", ">= 2.3.4")
|
21
|
+
s.add_dependency("i18n", ">= 0.7.0")
|
22
|
+
s.add_dependency("activesupport", ">= 3.0.0")
|
23
|
+
s.add_dependency("excon", "~> 0.45.3")
|
24
|
+
s.add_dependency("faraday_middleware")
|
25
|
+
s.add_dependency("faraday", "~> 0.9.1")
|
26
|
+
s.add_dependency("nokogiri", ">= 1.4.2")
|
27
|
+
|
28
|
+
s.add_development_dependency("rake", ">=0.9.2")
|
29
|
+
s.add_development_dependency("rspec", "~> 3.2.0")
|
30
|
+
s.add_development_dependency("rspec-its", "~> 1.2.0")
|
31
|
+
s.add_development_dependency("cucumber", "~> 2.0.0")
|
32
|
+
s.add_development_dependency("pickle", "~> 0.5.1")
|
33
|
+
s.add_development_dependency("machinist", "~> 2.0")
|
34
|
+
s.add_development_dependency("webmock", "~> 1.21.0")
|
35
|
+
s.add_development_dependency("guard", "~> 2.12.5")
|
36
|
+
s.add_development_dependency("guard-rspec", "~> 4.5.0")
|
37
|
+
s.add_development_dependency("guard-cucumber", "~> 1.6.0")
|
38
|
+
s.add_development_dependency("vcr", "~> 2.9.3")
|
39
|
+
s.add_development_dependency("simplecov", "~> 0.7.1")
|
40
|
+
s.add_development_dependency("coveralls", "~> 0.6.7")
|
41
|
+
s.add_development_dependency("pry")
|
42
|
+
s.add_development_dependency("pry-nav")
|
43
|
+
|
44
|
+
s.files = `git ls-files`.split("\n")
|
45
|
+
s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
|
46
|
+
s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
|
47
|
+
s.require_paths = ["lib"]
|
48
|
+
end
|
data/spec/association_spec.rb
CHANGED
@@ -4,7 +4,7 @@ module OData
|
|
4
4
|
describe Association do
|
5
5
|
before(:all) do
|
6
6
|
stub_request(:get, /http:\/\/test\.com\/test\.svc\/\$metadata(?:\?.+)?/).
|
7
|
-
with(:headers =>
|
7
|
+
with(:headers => DEFAULT_HEADERS).
|
8
8
|
to_return(:status => 200, :body => File.new(File.expand_path("../fixtures/sample_service/edmx_categories_products.xml", __FILE__)), :headers => {})
|
9
9
|
|
10
10
|
@svc = OData::Service.new "http://test.com/test.svc/$metadata"
|
@@ -13,33 +13,37 @@ module OData
|
|
13
13
|
describe "#initialize singlular navigation property" do
|
14
14
|
before { @association = Association.new @product_category, @svc.edmx }
|
15
15
|
subject { @association }
|
16
|
-
|
17
|
-
it "
|
16
|
+
|
17
|
+
it "sets the association name" do
|
18
18
|
subject.name.should eq 'Category_Products'
|
19
19
|
end
|
20
|
-
|
20
|
+
|
21
|
+
it "sets the association namespace" do
|
21
22
|
subject.namespace.should eq 'RubyODataService'
|
22
23
|
end
|
23
|
-
|
24
|
+
|
25
|
+
it "sets the relationship name" do
|
24
26
|
subject.relationship.should eq 'RubyODataService.Category_Products'
|
25
27
|
end
|
28
|
+
|
26
29
|
context "from_role method" do
|
27
30
|
subject { @association.from_role }
|
28
|
-
it { should have_key 'Category_Products_Target'}
|
29
|
-
it "
|
31
|
+
it { should have_key 'Category_Products_Target'}
|
32
|
+
it "sets the edmx type" do
|
30
33
|
subject['Category_Products_Target'][:edmx_type].should eq 'RubyODataService.Product'
|
31
34
|
end
|
32
|
-
it "
|
35
|
+
it "sets the multiplicity" do
|
33
36
|
subject['Category_Products_Target'][:multiplicity].should eq '*'
|
34
37
|
end
|
35
38
|
end
|
39
|
+
|
36
40
|
context "to_role method" do
|
37
41
|
subject { @association.to_role }
|
38
|
-
it { should have_key 'Category_Products_Source'}
|
39
|
-
it "
|
42
|
+
it { should have_key 'Category_Products_Source'}
|
43
|
+
it "sets the edmx type" do
|
40
44
|
subject['Category_Products_Source'][:edmx_type].should eq 'RubyODataService.Category'
|
41
45
|
end
|
42
|
-
it "
|
46
|
+
it "sets the multiplicity" do
|
43
47
|
subject['Category_Products_Source'][:multiplicity].should eq '1'
|
44
48
|
end
|
45
49
|
end
|