ruby_odata 0.1.0 → 0.1.1
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +3 -2
- data/.travis.yml +2 -1
- data/.yardopts +6 -0
- data/CHANGELOG.md +102 -0
- data/Guardfile +14 -0
- data/README.md +285 -0
- data/Rakefile +0 -7
- data/features/basic_auth.feature +3 -2
- data/features/batch_request.feature +7 -6
- data/features/cassettes/basic_auth_protected_resource.yml +57 -0
- data/features/cassettes/batch_request_additions.yml +69 -0
- data/features/cassettes/batch_request_deletes.yml +69 -0
- data/features/cassettes/batch_request_updates.yml +69 -0
- data/features/cassettes/clean_database_for_testing.yml +46 -0
- data/features/cassettes/cucumber_tags/basic_auth.yml +297 -0
- data/features/cassettes/cucumber_tags/batch_request.yml +1459 -0
- data/features/cassettes/cucumber_tags/complex_types.yml +326 -0
- data/features/cassettes/cucumber_tags/error_handling.yml +64 -0
- data/features/cassettes/cucumber_tags/query_builder.yml +2025 -0
- data/features/cassettes/cucumber_tags/service.yml +234 -0
- data/features/cassettes/cucumber_tags/service_manage.yml +937 -0
- data/features/cassettes/cucumber_tags/service_methods.yml +647 -0
- data/features/cassettes/cucumber_tags/ssl.yml +203 -0
- data/features/cassettes/cucumber_tags/type_conversion.yml +337 -0
- data/features/cassettes/service_manage_additions.yml +65 -0
- data/features/cassettes/service_manage_deletions.yml +58 -0
- data/features/cassettes/service_manage_deletions_2.yml +58 -0
- data/features/cassettes/unsecured_metadata.yml +89 -0
- data/features/complex_types.feature +4 -3
- data/features/error_handling.feature +14 -0
- data/features/query_builder.feature +30 -9
- data/features/service.feature +4 -3
- data/features/service_manage.feature +6 -5
- data/features/service_methods.feature +3 -2
- data/features/ssl.feature +8 -8
- data/features/step_definitions/service_steps.rb +38 -24
- data/features/support/env.rb +1 -3
- data/features/support/hooks.rb +3 -2
- data/features/support/pickle.rb +29 -18
- data/features/support/vcr.rb +24 -0
- data/features/type_conversion.feature +16 -17
- data/lib/ruby_odata/association.rb +7 -6
- data/lib/ruby_odata/class_builder.rb +6 -7
- data/lib/ruby_odata/exceptions.rb +4 -0
- data/lib/ruby_odata/helpers.rb +11 -0
- data/lib/ruby_odata/operation.rb +5 -6
- data/lib/ruby_odata/property_metadata.rb +4 -5
- data/lib/ruby_odata/query_builder.rb +98 -63
- data/lib/ruby_odata/service.rb +118 -103
- data/lib/ruby_odata/version.rb +3 -1
- data/lib/ruby_odata.rb +20 -18
- data/ruby_odata.gemspec +16 -12
- data/spec/query_builder_spec.rb +78 -14
- data/spec/service_spec.rb +83 -83
- data/spec/support/sample_service_matcher.rb +15 -0
- data/test/RubyODataService/RubyODataService/App_Data/.gitkeep +0 -0
- data/test/blueprints.rb +15 -9
- data/test/usage_samples/querying.rb +5 -1
- data/test/usage_samples/sample_data.rb +1 -3
- metadata +213 -39
- data/CHANGELOG.rdoc +0 -88
- data/README.rdoc +0 -259
@@ -0,0 +1,58 @@
|
|
1
|
+
---
|
2
|
+
http_interactions:
|
3
|
+
- request:
|
4
|
+
method: get
|
5
|
+
uri: http://win7dev:8989/SampleService/RubyOData.svc/Products(1)
|
6
|
+
body:
|
7
|
+
encoding: US-ASCII
|
8
|
+
string: ''
|
9
|
+
headers:
|
10
|
+
Accept:
|
11
|
+
- ! '*/*; q=0.5, application/xml'
|
12
|
+
Accept-Encoding:
|
13
|
+
- gzip, deflate
|
14
|
+
User-Agent:
|
15
|
+
- Ruby
|
16
|
+
response:
|
17
|
+
status:
|
18
|
+
code: 200
|
19
|
+
message: OK
|
20
|
+
headers:
|
21
|
+
Cache-Control:
|
22
|
+
- no-cache
|
23
|
+
Content-Length:
|
24
|
+
- '1431'
|
25
|
+
Content-Type:
|
26
|
+
- application/atom+xml;type=entry;charset=utf-8
|
27
|
+
Server:
|
28
|
+
- Microsoft-IIS/7.5
|
29
|
+
Set-Cookie:
|
30
|
+
- ASP.NET_SessionId=pqd44q53aamnklanqbym2pcu; path=/; HttpOnly
|
31
|
+
X-Content-Type-Options:
|
32
|
+
- nosniff
|
33
|
+
Dataserviceversion:
|
34
|
+
- 1.0;
|
35
|
+
X-Aspnet-Version:
|
36
|
+
- 4.0.30319
|
37
|
+
X-Powered-By:
|
38
|
+
- ASP.NET
|
39
|
+
Date:
|
40
|
+
- Tue, 07 Aug 2012 21:47:37 GMT
|
41
|
+
body:
|
42
|
+
encoding: US-ASCII
|
43
|
+
string: <?xml version="1.0" encoding="utf-8"?><entry xml:base="http://win7dev:8989/SampleService/RubyOData.svc/"
|
44
|
+
xmlns="http://www.w3.org/2005/Atom" xmlns:d="http://schemas.microsoft.com/ado/2007/08/dataservices"
|
45
|
+
xmlns:m="http://schemas.microsoft.com/ado/2007/08/dataservices/metadata" xmlns:georss="http://www.georss.org/georss"
|
46
|
+
xmlns:gml="http://www.opengis.net/gml"><id>http://win7dev:8989/SampleService/RubyOData.svc/Products(1)</id><category
|
47
|
+
term="RubyODataService.Product" scheme="http://schemas.microsoft.com/ado/2007/08/dataservices/scheme"
|
48
|
+
/><link rel="edit" title="Product" href="Products(1)" /><link rel="http://schemas.microsoft.com/ado/2007/08/dataservices/related/Category"
|
49
|
+
type="application/atom+xml;type=entry" title="Category" href="Products(1)/Category"
|
50
|
+
/><title /><updated>2012-08-07T21:47:38Z</updated><author><name /></author><content
|
51
|
+
type="application/xml"><m:properties><d:Id m:type="Edm.Int32">1</d:Id><d:Name>Test
|
52
|
+
Product</d:Name><d:Description>Test Widget</d:Description><d:Price m:type="Edm.Decimal">10.25</d:Price><d:DiscontinuedDate
|
53
|
+
m:type="Edm.DateTime" m:null="true" /><d:CategoryId m:type="Edm.Int32">1</d:CategoryId><d:AuditFields
|
54
|
+
m:type="RubyODataService.AuditFields"><d:CreateDate m:type="Edm.DateTime">2012-08-07T21:47:38.157</d:CreateDate><d:ModifiedDate
|
55
|
+
m:type="Edm.DateTime">2012-08-07T21:47:38.157</d:ModifiedDate><d:CreatedBy>Machinist</d:CreatedBy></d:AuditFields></m:properties></content></entry>
|
56
|
+
http_version: !!null
|
57
|
+
recorded_at: Tue, 07 Aug 2012 21:47:38 GMT
|
58
|
+
recorded_with: VCR 2.2.4
|
@@ -0,0 +1,58 @@
|
|
1
|
+
---
|
2
|
+
http_interactions:
|
3
|
+
- request:
|
4
|
+
method: get
|
5
|
+
uri: http://win7dev:8989/SampleService/RubyOData.svc/Products(1)
|
6
|
+
body:
|
7
|
+
encoding: US-ASCII
|
8
|
+
string: ''
|
9
|
+
headers:
|
10
|
+
Accept:
|
11
|
+
- ! '*/*; q=0.5, application/xml'
|
12
|
+
Accept-Encoding:
|
13
|
+
- gzip, deflate
|
14
|
+
User-Agent:
|
15
|
+
- Ruby
|
16
|
+
response:
|
17
|
+
status:
|
18
|
+
code: 200
|
19
|
+
message: OK
|
20
|
+
headers:
|
21
|
+
Cache-Control:
|
22
|
+
- no-cache
|
23
|
+
Content-Length:
|
24
|
+
- '1439'
|
25
|
+
Content-Type:
|
26
|
+
- application/atom+xml;type=entry;charset=utf-8
|
27
|
+
Server:
|
28
|
+
- Microsoft-IIS/7.5
|
29
|
+
Set-Cookie:
|
30
|
+
- ASP.NET_SessionId=1jtoo2ua0isload4ewywcbyh; path=/; HttpOnly
|
31
|
+
X-Content-Type-Options:
|
32
|
+
- nosniff
|
33
|
+
Dataserviceversion:
|
34
|
+
- 1.0;
|
35
|
+
X-Aspnet-Version:
|
36
|
+
- 4.0.30319
|
37
|
+
X-Powered-By:
|
38
|
+
- ASP.NET
|
39
|
+
Date:
|
40
|
+
- Tue, 07 Aug 2012 21:47:37 GMT
|
41
|
+
body:
|
42
|
+
encoding: US-ASCII
|
43
|
+
string: <?xml version="1.0" encoding="utf-8"?><entry xml:base="http://win7dev:8989/SampleService/RubyOData.svc/"
|
44
|
+
xmlns="http://www.w3.org/2005/Atom" xmlns:d="http://schemas.microsoft.com/ado/2007/08/dataservices"
|
45
|
+
xmlns:m="http://schemas.microsoft.com/ado/2007/08/dataservices/metadata" xmlns:georss="http://www.georss.org/georss"
|
46
|
+
xmlns:gml="http://www.opengis.net/gml"><id>http://win7dev:8989/SampleService/RubyOData.svc/Products(1)</id><category
|
47
|
+
term="RubyODataService.Product" scheme="http://schemas.microsoft.com/ado/2007/08/dataservices/scheme"
|
48
|
+
/><link rel="edit" title="Product" href="Products(1)" /><link rel="http://schemas.microsoft.com/ado/2007/08/dataservices/related/Category"
|
49
|
+
type="application/atom+xml;type=entry" title="Category" href="Products(1)/Category"
|
50
|
+
/><title /><updated>2012-08-07T21:47:38Z</updated><author><name /></author><content
|
51
|
+
type="application/xml"><m:properties><d:Id m:type="Edm.Int32">1</d:Id><d:Name>Changed
|
52
|
+
Test Product</d:Name><d:Description>Test Widget</d:Description><d:Price m:type="Edm.Decimal">10.25</d:Price><d:DiscontinuedDate
|
53
|
+
m:type="Edm.DateTime" m:null="true" /><d:CategoryId m:type="Edm.Int32">1</d:CategoryId><d:AuditFields
|
54
|
+
m:type="RubyODataService.AuditFields"><d:CreateDate m:type="Edm.DateTime">2012-08-07T21:47:38.157</d:CreateDate><d:ModifiedDate
|
55
|
+
m:type="Edm.DateTime">2012-08-07T21:47:38.157</d:ModifiedDate><d:CreatedBy>Machinist</d:CreatedBy></d:AuditFields></m:properties></content></entry>
|
56
|
+
http_version: !!null
|
57
|
+
recorded_at: Tue, 07 Aug 2012 21:47:38 GMT
|
58
|
+
recorded_with: VCR 2.2.4
|
@@ -0,0 +1,89 @@
|
|
1
|
+
---
|
2
|
+
http_interactions:
|
3
|
+
- request:
|
4
|
+
method: get
|
5
|
+
uri: http://win7dev:8989/SampleService/RubyOData.svc/$metadata
|
6
|
+
body:
|
7
|
+
encoding: US-ASCII
|
8
|
+
string: ''
|
9
|
+
headers:
|
10
|
+
Accept:
|
11
|
+
- ! '*/*; q=0.5, application/xml'
|
12
|
+
Accept-Encoding:
|
13
|
+
- gzip, deflate
|
14
|
+
User-Agent:
|
15
|
+
- Ruby
|
16
|
+
response:
|
17
|
+
status:
|
18
|
+
code: 200
|
19
|
+
message: OK
|
20
|
+
headers:
|
21
|
+
Cache-Control:
|
22
|
+
- no-cache
|
23
|
+
Content-Length:
|
24
|
+
- '4055'
|
25
|
+
Content-Type:
|
26
|
+
- application/xml;charset=utf-8
|
27
|
+
Server:
|
28
|
+
- Microsoft-IIS/7.5
|
29
|
+
Set-Cookie:
|
30
|
+
- ASP.NET_SessionId=tvkikr3xqyy43kcx0mk1uwdr; path=/; HttpOnly
|
31
|
+
X-Content-Type-Options:
|
32
|
+
- nosniff
|
33
|
+
Dataserviceversion:
|
34
|
+
- 1.0;
|
35
|
+
X-Aspnet-Version:
|
36
|
+
- 4.0.30319
|
37
|
+
X-Powered-By:
|
38
|
+
- ASP.NET
|
39
|
+
Date:
|
40
|
+
- Tue, 07 Aug 2012 21:47:40 GMT
|
41
|
+
body:
|
42
|
+
encoding: US-ASCII
|
43
|
+
string: <?xml version="1.0" encoding="utf-8"?><edmx:Edmx Version="1.0" xmlns:edmx="http://schemas.microsoft.com/ado/2007/06/edmx"><edmx:DataServices
|
44
|
+
m:DataServiceVersion="1.0" m:MaxDataServiceVersion="3.0" xmlns:m="http://schemas.microsoft.com/ado/2007/08/dataservices/metadata"><Schema
|
45
|
+
Namespace="RubyODataService" xmlns="http://schemas.microsoft.com/ado/2008/09/edm"><EntityType
|
46
|
+
Name="Product"><Key><PropertyRef Name="Id" /></Key><Property Name="Id" Type="Edm.Int32"
|
47
|
+
Nullable="false" p6:StoreGeneratedPattern="Identity" xmlns:p6="http://schemas.microsoft.com/ado/2009/02/edm/annotation"
|
48
|
+
/><Property Name="Name" Type="Edm.String" MaxLength="4000" FixedLength="false"
|
49
|
+
Unicode="true" /><Property Name="Description" Type="Edm.String" MaxLength="4000"
|
50
|
+
FixedLength="false" Unicode="true" /><Property Name="Price" Type="Edm.Decimal"
|
51
|
+
Nullable="false" Precision="18" Scale="2" /><Property Name="DiscontinuedDate"
|
52
|
+
Type="Edm.DateTime" /><Property Name="CategoryId" Type="Edm.Int32" Nullable="false"
|
53
|
+
/><Property Name="AuditFields" Type="RubyODataService.AuditFields" Nullable="false"
|
54
|
+
/><NavigationProperty Name="Category" Relationship="RubyODataService.Category_Products"
|
55
|
+
ToRole="Category_Products_Source" FromRole="Category_Products_Target" /></EntityType><ComplexType
|
56
|
+
Name="AuditFields"><Property Name="CreateDate" Type="Edm.DateTime" Nullable="false"
|
57
|
+
/><Property Name="ModifiedDate" Type="Edm.DateTime" Nullable="false" /><Property
|
58
|
+
Name="CreatedBy" Type="Edm.String" MaxLength="4000" FixedLength="false" Unicode="true"
|
59
|
+
/></ComplexType><EntityType Name="Category"><Key><PropertyRef Name="Id" /></Key><Property
|
60
|
+
Name="Id" Type="Edm.Int32" Nullable="false" p6:StoreGeneratedPattern="Identity"
|
61
|
+
xmlns:p6="http://schemas.microsoft.com/ado/2009/02/edm/annotation" /><Property
|
62
|
+
Name="Name" Type="Edm.String" MaxLength="4000" FixedLength="false" Unicode="true"
|
63
|
+
/><Property Name="AuditFields" Type="RubyODataService.AuditFields" Nullable="false"
|
64
|
+
/><NavigationProperty Name="Products" Relationship="RubyODataService.Category_Products"
|
65
|
+
ToRole="Category_Products_Target" FromRole="Category_Products_Source" /></EntityType><EntityType
|
66
|
+
Name="EdmMetadata"><Key><PropertyRef Name="Id" /></Key><Property Name="Id"
|
67
|
+
Type="Edm.Int32" Nullable="false" p6:StoreGeneratedPattern="Identity" xmlns:p6="http://schemas.microsoft.com/ado/2009/02/edm/annotation"
|
68
|
+
/><Property Name="ModelHash" Type="Edm.String" MaxLength="4000" FixedLength="false"
|
69
|
+
Unicode="true" /></EntityType><Association Name="Category_Products"><End Type="RubyODataService.Product"
|
70
|
+
Role="Category_Products_Target" Multiplicity="*" /><End Type="RubyODataService.Category"
|
71
|
+
Role="Category_Products_Source" Multiplicity="1"><OnDelete Action="Cascade"
|
72
|
+
/></End><ReferentialConstraint><Principal Role="Category_Products_Source"><PropertyRef
|
73
|
+
Name="Id" /></Principal><Dependent Role="Category_Products_Target"><PropertyRef
|
74
|
+
Name="CategoryId" /></Dependent></ReferentialConstraint></Association><EntityContainer
|
75
|
+
Name="RubyODataContext" m:IsDefaultEntityContainer="true"><EntitySet Name="Products"
|
76
|
+
EntityType="RubyODataService.Product" /><EntitySet Name="Categories" EntityType="RubyODataService.Category"
|
77
|
+
/><EntitySet Name="EdmMetadatas" EntityType="RubyODataService.EdmMetadata"
|
78
|
+
/><AssociationSet Name="Category_Products" Association="RubyODataService.Category_Products"><End
|
79
|
+
Role="Category_Products_Target" EntitySet="Products" /><End Role="Category_Products_Source"
|
80
|
+
EntitySet="Categories" /></AssociationSet><FunctionImport Name="CleanDatabaseForTesting"
|
81
|
+
m:HttpMethod="POST" /><FunctionImport Name="EntityCategoryWebGet" ReturnType="Collection(RubyODataService.Category)"
|
82
|
+
EntitySet="Categories" m:HttpMethod="GET" /><FunctionImport Name="CategoryNames"
|
83
|
+
ReturnType="Collection(Edm.String)" m:HttpMethod="GET" /><FunctionImport Name="FirstCategoryId"
|
84
|
+
ReturnType="Edm.Int32" m:HttpMethod="GET" /><FunctionImport Name="EntitySingleCategoryWebGet"
|
85
|
+
ReturnType="RubyODataService.Category" EntitySet="Categories" m:HttpMethod="GET"><Parameter
|
86
|
+
Name="id" Type="Edm.Int32" /></FunctionImport></EntityContainer></Schema></edmx:DataServices></edmx:Edmx>
|
87
|
+
http_version: !!null
|
88
|
+
recorded_at: Tue, 07 Aug 2012 21:47:41 GMT
|
89
|
+
recorded_with: VCR 2.2.4
|
@@ -1,3 +1,4 @@
|
|
1
|
+
@complex_types
|
1
2
|
Feature: Complex types
|
2
3
|
In order to fully support OData services
|
3
4
|
As a user of ruby_odata
|
@@ -12,7 +13,7 @@ Scenario: The proxy must generate classes for complex types if they exist
|
|
12
13
|
|
13
14
|
Scenario: Complex properties on an entity must be the correct type
|
14
15
|
Given I call "AddToProducts" on the service with a new "Product" object
|
15
|
-
And I save changes
|
16
|
+
And I save changes
|
16
17
|
And I call "Products" on the service with args: "1"
|
17
18
|
When I run the query
|
18
19
|
Then the first result should have a method: "AuditFields"
|
@@ -25,10 +26,10 @@ Scenario: Complex properties on an entity must be filled
|
|
25
26
|
When I run the query
|
26
27
|
Then the first result should have a method: "AuditFields"
|
27
28
|
When I call "CreateDate" for "AuditFields" on the first result
|
28
|
-
Then the operation should not be null
|
29
|
+
Then the operation should not be null
|
29
30
|
|
30
31
|
# TODO: This scenario should have the AuditFields.CreatedBy field set in the Given
|
31
|
-
# instead it is set by the blueprint
|
32
|
+
# instead it is set by the blueprint
|
32
33
|
Scenario: Complex properties should be able to be added
|
33
34
|
Given I call "AddToProducts" on the service with a new "Product" object
|
34
35
|
And I save changes
|
@@ -0,0 +1,14 @@
|
|
1
|
+
@error_handling
|
2
|
+
Feature: Error handling
|
3
|
+
In order to assist debugging
|
4
|
+
As a user
|
5
|
+
I want more debug information when an error occurs communicating with the server
|
6
|
+
|
7
|
+
Background:
|
8
|
+
Given a HTTP ODataService exists
|
9
|
+
And blueprints exist for the service
|
10
|
+
|
11
|
+
Scenario: Violate a data type conversion (empty string to decimal)
|
12
|
+
Given I call "AddToProducts" on the service with a new "Product" object with Price: ""
|
13
|
+
When I save changes it should throw an exception with message containing "HTTP Error 400"
|
14
|
+
|
@@ -1,7 +1,8 @@
|
|
1
|
+
@query_builder
|
1
2
|
Feature: Query Builder
|
2
3
|
In order to query OData services
|
3
4
|
As a user
|
4
|
-
I want to be able to perform valid OData protocol operations
|
5
|
+
I want to be able to perform valid OData protocol operations
|
5
6
|
|
6
7
|
Background:
|
7
8
|
Given a HTTP ODataService exists
|
@@ -12,7 +13,7 @@ Scenario: Navigation Properties should be able to be eager loaded
|
|
12
13
|
Given I call "AddToCategories" on the service with a new "Category" object with Name: "Test Category"
|
13
14
|
And I save changes
|
14
15
|
And I call "AddToProducts" on the service with a new "Product" object with Category: "@@LastSave.first"
|
15
|
-
And I save changes
|
16
|
+
And I save changes
|
16
17
|
And I call "Products" on the service with args: "1"
|
17
18
|
And I expand the query to include "Category"
|
18
19
|
When I run the query
|
@@ -99,14 +100,14 @@ Scenario: Skip should be allowed on the root level entity
|
|
99
100
|
| Product 2 |
|
100
101
|
| Product 3 |
|
101
102
|
| Product 4 |
|
102
|
-
| Product 5 |
|
103
|
+
| Product 5 |
|
103
104
|
When I call "Products" on the service
|
104
105
|
And I skip 3
|
105
106
|
And I run the query
|
106
107
|
Then the result should be:
|
107
108
|
| Name |
|
108
109
|
| Product 4 |
|
109
|
-
| Product 5 |
|
110
|
+
| Product 5 |
|
110
111
|
|
111
112
|
|
112
113
|
# Top
|
@@ -117,14 +118,14 @@ Scenario: Top should be allowed on the root level entity
|
|
117
118
|
| Product 2 |
|
118
119
|
| Product 3 |
|
119
120
|
| Product 4 |
|
120
|
-
| Product 5 |
|
121
|
+
| Product 5 |
|
121
122
|
When I call "Products" on the service
|
122
123
|
And I ask for the top 3
|
123
124
|
And I run the query
|
124
125
|
Then the result should be:
|
125
126
|
| Name |
|
126
127
|
| Product 1 |
|
127
|
-
| Product 2 |
|
128
|
+
| Product 2 |
|
128
129
|
| Product 3 |
|
129
130
|
|
130
131
|
Scenario: Top should be able to be used along with skip for paging
|
@@ -134,8 +135,8 @@ Scenario: Top should be able to be used along with skip for paging
|
|
134
135
|
| Product 2 |
|
135
136
|
| Product 3 |
|
136
137
|
| Product 4 |
|
137
|
-
| Product 5 |
|
138
|
-
| Product 6 |
|
138
|
+
| Product 5 |
|
139
|
+
| Product 6 |
|
139
140
|
When I call "Products" on the service
|
140
141
|
And I skip 2
|
141
142
|
And I ask for the top 2
|
@@ -143,7 +144,7 @@ Scenario: Top should be able to be used along with skip for paging
|
|
143
144
|
Then the result should be:
|
144
145
|
| Name |
|
145
146
|
| Product 3 |
|
146
|
-
| Product 4 |
|
147
|
+
| Product 4 |
|
147
148
|
|
148
149
|
|
149
150
|
# Links
|
@@ -160,3 +161,23 @@ Scenario: Navigation Properties should be able to represented as links
|
|
160
161
|
And I run the query
|
161
162
|
Then the result count should be 3
|
162
163
|
Then the method "path" on the first result should equal: "/SampleService/RubyOData.svc/Products(1)"
|
164
|
+
|
165
|
+
# Count
|
166
|
+
Scenario: Count should be able to be used on a root collection
|
167
|
+
Given 4 products exist
|
168
|
+
When I call "Products" on the service
|
169
|
+
And I ask for the count
|
170
|
+
And I run the query
|
171
|
+
Then the integer result should be 4
|
172
|
+
|
173
|
+
Scenario: Count should be able to be used on with a filter
|
174
|
+
Given the following products exist:
|
175
|
+
| Name |
|
176
|
+
| Product 1 |
|
177
|
+
| Product 2 |
|
178
|
+
When I call "Products" on the service
|
179
|
+
And I filter the query with: "Name eq 'Product 2'"
|
180
|
+
And I ask for the count
|
181
|
+
And I run the query
|
182
|
+
Then the integer result should be 1
|
183
|
+
|
data/features/service.feature
CHANGED
@@ -1,3 +1,4 @@
|
|
1
|
+
@service
|
1
2
|
Feature: Service Should Generate a Proxy
|
2
3
|
In order to consume the OData
|
3
4
|
As a user
|
@@ -30,7 +31,7 @@ Scenario: Entity should have the correct accessors
|
|
30
31
|
When I run the query
|
31
32
|
Then the first result should have a method: "Id"
|
32
33
|
And the first result should have a method: "Name"
|
33
|
-
|
34
|
+
|
34
35
|
Scenario: Entity should fill values
|
35
36
|
Given I call "AddToCategories" on the service with a new "Category" object with Name: "Test Category"
|
36
37
|
And I save changes
|
@@ -39,9 +40,9 @@ Scenario: Entity should fill values
|
|
39
40
|
Then the method "Id" on the first result should equal: "1"
|
40
41
|
And the method "Name" on the first result should equal: "Test Category"
|
41
42
|
|
42
|
-
Scenario: Navigation Properties should be included in results
|
43
|
+
Scenario: Navigation Properties should be included in results
|
43
44
|
Given I call "AddToProducts" on the service with a new "Product" object
|
44
|
-
And I save changes
|
45
|
+
And I save changes
|
45
46
|
And I call "Products" on the service with args: "1"
|
46
47
|
When I run the query
|
47
48
|
Then the first result should have a method: "Category"
|
@@ -1,3 +1,4 @@
|
|
1
|
+
@service_manage
|
1
2
|
Feature: Service management
|
2
3
|
In order to manage entities
|
3
4
|
As a admin
|
@@ -9,7 +10,7 @@ Background:
|
|
9
10
|
|
10
11
|
Scenario: Service should respond to AddToEntityName for adding objects
|
11
12
|
Given I call "AddToProducts" on the service with a new "Product" object with Name: "Sample Product"
|
12
|
-
When I save changes
|
13
|
+
When I save changes within a cassette named "service_manage_additions"
|
13
14
|
Then the first save result should be of type "Product"
|
14
15
|
And the method "Name" on the first save result should equal: "Sample Product"
|
15
16
|
|
@@ -19,7 +20,7 @@ Scenario: Service should allow for deletes
|
|
19
20
|
Then the first save result should be of type "Product"
|
20
21
|
When I call "delete_object" on the service with the first last save result
|
21
22
|
And I save changes
|
22
|
-
Then the save result should equal: "true"
|
23
|
+
Then the save result should equal: "true"
|
23
24
|
And no "Products" should exist
|
24
25
|
|
25
26
|
Scenario: Untracked entities shouldn't be able to be deleted
|
@@ -29,7 +30,7 @@ Scenario: Entities should be able to be updated
|
|
29
30
|
Given I call "AddToProducts" on the service with a new "Product" object with Name: "Test Product"
|
30
31
|
When I save changes
|
31
32
|
And I call "Products" on the service with args: "1"
|
32
|
-
And I run the query
|
33
|
+
And I run the query within a cassette named "service_manage_deletions"
|
33
34
|
Then the method "Name" on the first result should equal: "Test Product"
|
34
35
|
When I set "Name" on the first result to "Changed Test Product"
|
35
36
|
Then the method "Name" on the first result should equal: "Changed Test Product"
|
@@ -37,7 +38,7 @@ Scenario: Entities should be able to be updated
|
|
37
38
|
And I save changes
|
38
39
|
Then the save result should equal: "true"
|
39
40
|
When I call "Products" on the service with args: "1"
|
40
|
-
And I run the query
|
41
|
+
And I run the query within a cassette named "service_manage_deletions_2"
|
41
42
|
Then the method "Name" on the first result should equal: "Changed Test Product"
|
42
43
|
|
43
44
|
Scenario: Untracked entities shouldn't be able to be updated
|
@@ -47,7 +48,7 @@ Scenario: Related entities shouldn't be recreated on a child add
|
|
47
48
|
Given I call "AddToCategories" on the service with a new "Category" object with Name: "Test Category"
|
48
49
|
And I save changes
|
49
50
|
And I call "AddToProducts" on the service with a new "Product" object with Category: "@@LastSave.first"
|
50
|
-
And I save changes
|
51
|
+
And I save changes
|
51
52
|
And I call "Products" on the service with args: "1"
|
52
53
|
And I expand the query to include "Category"
|
53
54
|
When I run the query
|
@@ -1,3 +1,4 @@
|
|
1
|
+
@service_methods
|
1
2
|
Feature: Service methods
|
2
3
|
In order to use a WCF Data Service more efficiently
|
3
4
|
As a consumer
|
@@ -5,9 +6,9 @@ Feature: Service methods
|
|
5
6
|
|
6
7
|
Background:
|
7
8
|
Given a HTTP ODataService exists
|
8
|
-
And blueprints exist for the service
|
9
|
+
And blueprints exist for the service
|
10
|
+
|
9
11
|
|
10
|
-
|
11
12
|
Scenario: A custom web get (no parameters) that returns an entity
|
12
13
|
Given a category exists
|
13
14
|
And I call the service method "EntityCategoryWebGet"
|
data/features/ssl.feature
CHANGED
@@ -1,13 +1,14 @@
|
|
1
|
+
@ssl
|
1
2
|
Feature: Service Should Access Basic Resources via SSL using a self-signed certificate
|
2
|
-
|
3
|
-
Background:
|
4
|
-
Given a HTTPS BasicAuth ODataService exists using self-signed certificate and username "admin" and password "passwd"
|
5
|
-
And blueprints exist for the service
|
6
3
|
|
7
4
|
Scenario: Service should respond to valid collections
|
5
|
+
Given a HTTPS BasicAuth ODataService exists using self-signed certificate and username "admin" and password "passwd"
|
6
|
+
And blueprints exist for the service
|
8
7
|
Then I should be able to call "Products" on the service
|
9
8
|
|
10
9
|
Scenario: Entity should fill values on protected resource
|
10
|
+
Given a HTTPS BasicAuth ODataService exists using self-signed certificate and username "admin" and password "passwd"
|
11
|
+
And blueprints exist for the service
|
11
12
|
Given I call "AddToCategories" on the service with a new "Category" object with Name: "Auth Test Category"
|
12
13
|
And I save changes
|
13
14
|
And I call "Categories" on the service with args: "1"
|
@@ -15,7 +16,6 @@ Scenario: Entity should fill values on protected resource
|
|
15
16
|
Then the method "Id" on the first result should equal: "1"
|
16
17
|
And the method "Name" on the first result should equal: "Auth Test Category"
|
17
18
|
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
19
|
+
# TODO: Commented this scenario out because it requires the server to be online in order for the tests to run. Would like to move this to a mocked test that would accomplish the same thing...
|
20
|
+
# Scenario: Should get SSL failure if SSL used with self-signed certificate and not passing "false" as :verify_ssl option
|
21
|
+
# Given a HTTPS BasicAuth ODataService exists it should throw an exception with message containing "SSL Verification failed"
|
@@ -2,20 +2,22 @@ STANDARD_URL = "http://#{WEBSERVER}:#{HTTP_PORT_NUMBER}/SampleService/RubyOData.
|
|
2
2
|
BASICAUTH_URL = "http://#{WEBSERVER}:#{HTTP_PORT_NUMBER}/SampleService/BasicAuth/RubyOData.svc"
|
3
3
|
HTTPS_BASICAUTH_URL = "https://#{WEBSERVER}:#{HTTPS_PORT_NUMBER}/SampleService/BasicAuth/RubyOData.svc"
|
4
4
|
|
5
|
-
When /^(.*) first (last query )?result('s)?(.*)$/ do |pre, last_query, apos, post|
|
6
|
-
|
5
|
+
When /^(.*) first (last query )?result(\'s)?(.*)$/ do |pre, last_query, apos, post|
|
6
|
+
the_step = "#{pre} #{last_query}result#{apos}#{post}"
|
7
7
|
first_result
|
8
|
-
|
8
|
+
step the_step
|
9
9
|
end
|
10
10
|
|
11
11
|
When /^(.*) first (last )?save result(.*)$/ do |pre, last, post|
|
12
|
-
|
12
|
+
the_step = "#{pre} #{last}save result#{post}"
|
13
13
|
first_save
|
14
|
-
|
14
|
+
step the_step
|
15
15
|
end
|
16
16
|
|
17
17
|
Given /^a HTTP ODataService exists$/ do
|
18
|
-
|
18
|
+
VCR.use_cassette("unsecured_metadata") do
|
19
|
+
@service = OData::Service.new(STANDARD_URL)
|
20
|
+
end
|
19
21
|
end
|
20
22
|
|
21
23
|
Given /^a HTTP BasicAuth ODataService exists$/ do
|
@@ -30,11 +32,11 @@ Given /^a HTTP BasicAuth ODataService exists using username "([^\"]*)" and passw
|
|
30
32
|
@service = OData::Service.new(BASICAUTH_URL, { :username => username, :password => password })
|
31
33
|
end
|
32
34
|
|
33
|
-
Given /^a HTTP BasicAuth ODataService exists using username "([^\"]*)" and password "([^\"]*)" it should throw an exception with message "([^\"]*)"$/ do |username, password, msg|
|
35
|
+
Given /^a HTTP BasicAuth ODataService exists using username "([^\"]*)" and password "([^\"]*)" it should throw an exception with message "([^\"]*)"$/ do |username, password, msg|
|
34
36
|
lambda { @service = OData::Service.new(BASICAUTH_URL, { :username => username, :password => password }) }.should raise_error(msg)
|
35
37
|
end
|
36
38
|
|
37
|
-
Given /^a HTTP BasicAuth ODataService exists it should throw an exception with message containing "([^\"]*)"$/ do |msg|
|
39
|
+
Given /^a HTTP BasicAuth ODataService exists it should throw an exception with message containing "([^\"]*)"$/ do |msg|
|
38
40
|
lambda { @service = OData::Service.new(BASICAUTH_URL) }.should raise_error(/#{msg}.*/)
|
39
41
|
end
|
40
42
|
|
@@ -42,7 +44,7 @@ Given /^a HTTPS BasicAuth ODataService exists it should throw an exception with
|
|
42
44
|
lambda { @service = OData::Service.new(HTTPS_BASICAUTH_URL) }.should raise_error(/#{msg}.*/)
|
43
45
|
end
|
44
46
|
|
45
|
-
Given /^a HTTP BasicAuth ODataService exists it should throw an exception with message "([^\"]*)"$/ do |msg|
|
47
|
+
Given /^a HTTP BasicAuth ODataService exists it should throw an exception with message "([^\"]*)"$/ do |msg|
|
46
48
|
lambda { @service = OData::Service.new(BASICAUTH_URL) }.should raise_error(msg)
|
47
49
|
end
|
48
50
|
|
@@ -55,7 +57,7 @@ When /^I call "([^\"]*)" on the service$/ do |method|
|
|
55
57
|
end
|
56
58
|
|
57
59
|
Then /^the result should be "([^\"]*)"$/ do |result|
|
58
|
-
@service_result.should eq result
|
60
|
+
@service_result.should eq result
|
59
61
|
end
|
60
62
|
|
61
63
|
Then /^the integer result should be ([^\"]*)$/ do |result|
|
@@ -122,18 +124,22 @@ When /^I ask for the top (\d+)$/ do |top|
|
|
122
124
|
@service_query.top(top)
|
123
125
|
end
|
124
126
|
|
127
|
+
When /^I ask for the count$/ do
|
128
|
+
@service_query.count
|
129
|
+
end
|
130
|
+
|
125
131
|
When /^I ask for the links for "([^\"]*)"$/ do |nav_prop|
|
126
132
|
@service_query.links(nav_prop)
|
127
133
|
end
|
128
134
|
|
129
135
|
Then /^the method "([^\"]*)" on the result should be of type "([^\"]*)"$/ do |method, type|
|
130
|
-
result = @service_result.send(method.to_sym)
|
136
|
+
result = @service_result.send(method.to_sym)
|
131
137
|
result.class.to_s.should eq type
|
132
138
|
end
|
133
139
|
|
134
140
|
Given /^I call "([^\"]*)" on the service with a new "([^\"]*)" object(?: with (.*))?$/ do |method, object, fields|
|
135
141
|
fields_hash = parse_fields_string(fields)
|
136
|
-
|
142
|
+
|
137
143
|
obj = object.constantize.send(:make, fields_hash)
|
138
144
|
@service.send(method.to_sym, obj)
|
139
145
|
end
|
@@ -172,6 +178,10 @@ Given /^I call "([^\"]*)" on the service with a new "([^\"]*)" object it should
|
|
172
178
|
lambda { @service.send(method.to_sym, obj) }.should raise_error(msg)
|
173
179
|
end
|
174
180
|
|
181
|
+
When /^I save changes it should throw an exception with message containing "([^"]*)"$/ do |msg|
|
182
|
+
lambda { @service.save_changes }.should raise_error(/#{msg}.*/)
|
183
|
+
end
|
184
|
+
|
175
185
|
Then /^no "([^\"]*)" should exist$/ do |collection|
|
176
186
|
@service.send(collection)
|
177
187
|
results = @service.execute
|
@@ -180,19 +190,19 @@ end
|
|
180
190
|
|
181
191
|
Then /^the primitive results should be:$/ do |table|
|
182
192
|
# table is a Cucumber::Ast::Table
|
183
|
-
values = table.hashes
|
193
|
+
values = table.hashes
|
184
194
|
result_table = Cucumber::Ast::Table.new(values)
|
185
195
|
table.diff!(result_table)
|
186
196
|
end
|
187
197
|
|
188
198
|
Then /^the result should be:$/ do |table|
|
189
199
|
# table is a Cucumber::Ast::Table
|
190
|
-
|
200
|
+
|
191
201
|
fields = table.hashes[0].keys
|
192
|
-
|
202
|
+
|
193
203
|
# Build an array of hashes so that we can compare tables
|
194
204
|
results = []
|
195
|
-
|
205
|
+
|
196
206
|
@service_result.each do |result|
|
197
207
|
obj_hash = Hash.new
|
198
208
|
fields.each do |field|
|
@@ -200,20 +210,20 @@ Then /^the result should be:$/ do |table|
|
|
200
210
|
end
|
201
211
|
results << obj_hash
|
202
212
|
end
|
203
|
-
|
213
|
+
|
204
214
|
result_table = Cucumber::Ast::Table.new(results)
|
205
|
-
|
215
|
+
|
206
216
|
table.diff!(result_table)
|
207
217
|
end
|
208
218
|
|
209
219
|
Then /^the save result should be:$/ do |table|
|
210
220
|
# table is a Cucumber::Ast::Table
|
211
|
-
|
221
|
+
|
212
222
|
fields = table.hashes[0].keys
|
213
|
-
|
223
|
+
|
214
224
|
# Build an array of hashes so that we can compare tables
|
215
225
|
results = []
|
216
|
-
|
226
|
+
|
217
227
|
@saved_result.each do |result|
|
218
228
|
obj_hash = Hash.new
|
219
229
|
fields.each do |field|
|
@@ -221,10 +231,10 @@ Then /^the save result should be:$/ do |table|
|
|
221
231
|
end
|
222
232
|
results << obj_hash
|
223
233
|
end
|
224
|
-
|
234
|
+
|
225
235
|
result_table = Cucumber::Ast::Table.new(results)
|
226
|
-
|
227
|
-
table.diff!(result_table)
|
236
|
+
|
237
|
+
table.diff!(result_table)
|
228
238
|
end
|
229
239
|
|
230
240
|
Then /^a class named "([^\"]*)" should exist$/ do |klass_name|
|
@@ -299,4 +309,8 @@ Given /^I call the service method "([^"]*)"(?: with (.*))?$/ do |method, args|
|
|
299
309
|
else
|
300
310
|
@service_result = @service.send(method)
|
301
311
|
end
|
312
|
+
end
|
313
|
+
|
314
|
+
When /^(.*) within a cassette named "([^"]*)"$/ do |the_step, cassette_name|
|
315
|
+
VCR.use_cassette(cassette_name) { step the_step }
|
302
316
|
end
|
data/features/support/env.rb
CHANGED
data/features/support/hooks.rb
CHANGED
@@ -1,4 +1,5 @@
|
|
1
1
|
Before do
|
2
|
-
|
3
|
-
|
2
|
+
VCR.use_cassette("clean_database_for_testing") do
|
3
|
+
RestClient.post "http://#{WEBSERVER}:#{HTTP_PORT_NUMBER}/SampleService/RubyOData.svc/CleanDatabaseForTesting", {}
|
4
|
+
end
|
4
5
|
end
|