waz-storage 1.1.1 → 1.1.2

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.
@@ -0,0 +1,614 @@
1
+ # enabling the load of files from root (on RSpec)
2
+ $LOAD_PATH.unshift(File.dirname(__FILE__) + '/../')
3
+ require 'tests/configuration'
4
+ require 'lib/waz-tables'
5
+
6
+ describe "tables service behavior" do
7
+
8
+ before do
9
+ @table_service = WAZ::Tables::Service.new(:account_name => "mock-account", :access_key => "mock-key", :type_of_service => "table", :use_ssl => true, :base_url => "localhost")
10
+ end
11
+
12
+ it "should get a table" do
13
+ response = <<-eos
14
+ <?xml version=\"1.0" encoding=\"utf-8" standalone=\"yes"?>
15
+ <entry xml:base=\"http://wazstoragejohnny.table.core.windows.net/" xmlns:d=\"http://schemas.microsoft.com/ado/2007/08/dataservices" xmlns:m=\"http://schemas.microsoft.com/ado/2007/08/dataservices/metadata" xmlns=\"http://www.w3.org/2005/Atom">
16
+ <id>http://myaccount.table.core.windows.net/Tables('table1')</id>
17
+ <title type=\"text"></title>
18
+ <updated>2009-12-28T02:00:21Z</updated>
19
+ <author>
20
+ <name />
21
+ </author>
22
+ <link rel=\"edit" title=\"Tables" href=\"Tables('table1')" />
23
+ <category term=\"wazstoragejohnny.Tables" scheme=\"http://schemas.microsoft.com/ado/2007/08/dataservices/scheme" />
24
+ <content type=\"application/xml">
25
+ <m:properties>
26
+ <d:TableName>table1</d:TableName>
27
+ </m:properties>
28
+ </content>
29
+ </entry>
30
+ eos
31
+
32
+ response.stubs(:headers).returns({:x_ms_continuation_nexttablename => 'next-table'})
33
+
34
+ RestClient::Request.any_instance.expects(:execute).returns(response)
35
+ @table_service.expects(:generate_request_uri).with("Tables('table1')", {}, nil).returns("http://localhost/Tables('table1')")
36
+ @table_service.expects(:generate_request).with(:get, "http://localhost/Tables('table1')", { 'Content-Type' => 'application/atom+xml', 'Date' => Time.new.httpdate, 'DataServiceVersion' => '1.0;NetFx', 'MaxDataServiceVersion' => '1.0;NetFx'}, nil).returns(RestClient::Request.new(:method => :get, :url => "http://localhost/Tables('table1')"))
37
+ table = @table_service.get_table('table1')
38
+ table[:name].should == 'table1'
39
+ table[:url].should == "http://myaccount.table.core.windows.net/Tables('table1')"
40
+ end
41
+
42
+ it "should list all tables" do
43
+ response = <<-eos
44
+ <?xml version=\"1.0" encoding=\"utf-8" standalone=\"yes"?>
45
+ <feed xml:base=\"http://myaccount.tables.core.windows.net/" xmlns:d=\"http://schemas.microsoft.com/ado/2007/08/dataservices" xmlns:m=\"http://schemas.microsoft.com/ado/2007/08/dataservices/metadata" xmlns=\"http://www.w3.org/2005/Atom">
46
+ <title type=\"text">Tables</title>
47
+ <id>http://myaccount.tables.core.windows.net/Tables</id>
48
+ <updated>2009-01-04T17:18:54.7062347Z</updated>
49
+ <link rel=\"self" title=\"Tables" href=\"Tables" />
50
+ <entry>
51
+ <id>http://myaccount.tables.core.windows.net/Tables('table1')</id>
52
+ <title type=\"text"></title>
53
+ <updated>2009-01-04T17:18:54.7062347Z</updated>
54
+ <author>
55
+ <name />
56
+ </author>
57
+ <link rel=\"edit" title=\"Tables" href=\"Tables('table1')" />
58
+ <category term=\"myaccount.Tables" scheme=\"http://schemas.microsoft.com/ado/2007/08/dataservices/scheme" />
59
+ <content type=\"application/xml">
60
+ <m:properties>
61
+ <d:TableName>table1</d:TableName>
62
+ </m:properties>
63
+ </content>
64
+ </entry>
65
+ <entry>
66
+ <id>http://myaccount.tables.core.windows.net/Tables('table2')</id>
67
+ <title type=\"text"></title>
68
+ <updated>2009-01-04T17:18:54.7062347Z</updated>
69
+ <author>
70
+ <name />
71
+ </author>
72
+ <link rel=\"edit" title=\"Tables" href=\"Tables('table2')" />
73
+ <category term=\"myaccount.Tables" scheme=\"http://schemas.microsoft.com/ado/2007/08/dataservices/scheme" />
74
+ <content type=\"application/xml">
75
+ <m:properties>
76
+ <d:TableName>table2</d:TableName>
77
+ </m:properties>
78
+ </content>
79
+ </entry>
80
+ </feed>
81
+ eos
82
+ response.stubs(:headers).returns({:x_ms_continuation_nexttablename => 'next-table'})
83
+
84
+ RestClient::Request.any_instance.expects(:execute).returns(response)
85
+ @table_service.expects(:generate_request_uri).with("Tables", {}, nil).returns("http://localhost/Tables")
86
+ @table_service.expects(:generate_request).with(:get, "http://localhost/Tables", {'Content-Type' => 'application/atom+xml', 'Date' => Time.new.httpdate, 'DataServiceVersion' => '1.0;NetFx', 'MaxDataServiceVersion' => '1.0;NetFx'}, nil).returns(RestClient::Request.new(:method => :get, :url => "http://localhost/Tables"))
87
+ tables, next_table_name = @table_service.list_tables
88
+ tables.length.should == 2
89
+ tables.first()[:name].should == 'table1'
90
+ tables.first()[:url].should == "http://myaccount.tables.core.windows.net/Tables('table1')"
91
+ tables.last()[:name].should == 'table2'
92
+ tables.last()[:url].should == "http://myaccount.tables.core.windows.net/Tables('table2')"
93
+ next_table_name.should == 'next-table'
94
+ end
95
+
96
+ it "should include the NextTableName parameter when a continuation token is provided" do
97
+ response = ''
98
+ response.stubs(:headers).returns({:x_ms_continuation_nexttablename => 'next-table'})
99
+ RestClient::Request.any_instance.expects(:execute).returns(response)
100
+ @table_service.expects(:generate_request_uri).with("Tables", { 'NextTableName' => 'next-table-name' }, nil).returns("http://localhost/Tables?NextTableName=next-table-name")
101
+ @table_service.expects(:generate_request).with(:get, "http://localhost/Tables?NextTableName=next-table-name", {'Content-Type' => 'application/atom+xml','Date' => Time.new.httpdate, 'DataServiceVersion' => '1.0;NetFx', 'MaxDataServiceVersion' => '1.0;NetFx'}, nil).returns(RestClient::Request.new(:method => :get, :url => "http://localhost/Tables?NextTableName=next-table-name"))
102
+ tables, next_table_name = @table_service.list_tables('next-table-name')
103
+ end
104
+
105
+ it "should create a table" do
106
+ expected_payload = "<?xml version=\"1.0\" encoding=\"utf-8\" standalone=\"yes\"?><entry xmlns:d=\"http://schemas.microsoft.com/ado/2007/08/dataservices\" xmlns:m=\"http://schemas.microsoft.com/ado/2007/08/dataservices/metadata\" xmlns=\"http://www.w3.org/2005/Atom\"><title /><updated>#{Time.now.utc.iso8601}</updated><author><name/></author><id/><content type=\"application/xml\"><m:properties><d:TableName>Customers</d:TableName></m:properties></content></entry>"
107
+ expected_headers = { 'Date' => Time.new.httpdate, 'Content-Type' => 'application/atom+xml', 'DataServiceVersion' => '1.0;NetFx', 'MaxDataServiceVersion' => '1.0;NetFx' }
108
+ RestClient::Request.any_instance.expects(:execute)
109
+ @table_service.expects(:generate_request_uri).with("Tables", {}).returns("http://localhost/Tables")
110
+ @table_service.expects(:generate_request).with(:post, "http://localhost/Tables", expected_headers, expected_payload).returns(RestClient::Request.new(:method => :post, :url => "http://localhost/Tables", :headers => expected_headers, :payload => expected_payload))
111
+ @table_service.create_table('Customers')
112
+ end
113
+
114
+ it "should throw when a table already exists" do
115
+ failed_response = RestClient::RequestFailed.new
116
+ failed_response.stubs(:http_code).returns(409)
117
+ RestClient::Request.any_instance.expects(:execute).raises(failed_response)
118
+ lambda { @table_service.create_table('existingtable') }.should raise_error(WAZ::Tables::TableAlreadyExists, "The table existingtable already exists on your account.")
119
+ end
120
+
121
+ it "should delete a table" do
122
+ expected_headers = { 'Date' => Time.new.httpdate, 'Content-Type' => 'application/atom+xml', 'DataServiceVersion' => '1.0;NetFx', 'MaxDataServiceVersion' => '1.0;NetFx' }
123
+
124
+ response = mock()
125
+ response.stubs(:code).returns(204)
126
+ RestClient::Request.any_instance.expects(:execute).returns(response)
127
+ @table_service.expects(:generate_request_uri).with("Tables('tabletodelete')", {}).returns("http://localhost/Tables('tabletodelete')")
128
+ @table_service.expects(:generate_request).with(:delete, "http://localhost/Tables('tabletodelete')", expected_headers, nil).returns(RestClient::Request.new(:method => :delete, :url => "http://localhost/Tables('tabletodelete')", :headers => expected_headers))
129
+ @table_service.delete_table('tabletodelete')
130
+ end
131
+
132
+ it "should throw when trying to get an unexisting table" do
133
+ failed_response = RestClient::ResourceNotFound.new
134
+ failed_response.stubs(:http_code).returns(404)
135
+ RestClient::Request.any_instance.expects(:execute).raises(failed_response)
136
+ lambda { @table_service.get_table('unexistingtable') }.should raise_error(WAZ::Tables::TableDoesNotExist, "The specified table unexistingtable does not exist.")
137
+ end
138
+
139
+ it "should throw when trying to delete an unexisting table" do
140
+ failed_response = RestClient::ResourceNotFound.new
141
+ failed_response.stubs(:http_code).returns(404)
142
+ RestClient::Request.any_instance.expects(:execute).raises(failed_response)
143
+ lambda { @table_service.delete_table('unexistingtable') }.should raise_error(WAZ::Tables::TableDoesNotExist, "The specified table unexistingtable does not exist.")
144
+ end
145
+
146
+ it "should insert a new entity" do
147
+ expected_payload = "<?xml version=\"1.0\" encoding=\"utf-8\" standalone=\"yes\"?>" \
148
+ "<entry xmlns:d=\"http://schemas.microsoft.com/ado/2007/08/dataservices\" xmlns:m=\"http://schemas.microsoft.com/ado/2007/08/dataservices/metadata\" xmlns=\"http://www.w3.org/2005/Atom\">" \
149
+ "<id>http://localhost/Customers(PartitionKey='myPartitionKey',RowKey='myRowKey1')</id>" \
150
+ "<title /><updated>#{Time.now.utc.iso8601}</updated><author><name /></author><link rel=\"edit\" title=\"Customers\" href=\"Customers(PartitionKey='myPartitionKey',RowKey='myRowKey1')\" />" \
151
+ "<content type=\"application/xml\">" \
152
+ "<m:properties>" \
153
+ "<d:address m:type=\"Edm.String\">Mountain View</d:address>" \
154
+ "<d:age m:type=\"Edm.Int32\">23</d:age>" \
155
+ "<d:amount_due m:type=\"Edm.Double\">200.23</d:amount_due>" \
156
+ "<d:binary_data m:type=\"Edm.Binary\" m:null=\"true\" />" \
157
+ "<d:customer_code m:type=\"Edm.Guid\">c9da6455-213d-42c9-9a79-3e9149a57833</d:customer_code>" \
158
+ "<d:customer_since m:type=\"Edm.DateTime\">#{Time.now.utc.iso8601}</d:customer_since>" \
159
+ "<d:is_active m:type=\"Edm.Boolean\">true</d:is_active>" \
160
+ "<d:num_of_orders m:type=\"Edm.Int64\">255</d:num_of_orders>" \
161
+ "<d:PartitionKey>myPartitionKey</d:PartitionKey>" \
162
+ "<d:RowKey>myRowKey1</d:RowKey>" \
163
+ "</m:properties></content></entry>"
164
+
165
+ expected_headers = {'Date' => Time.new.httpdate, 'DataServiceVersion' => '1.0;NetFx', 'Content-Type' => 'application/atom+xml', 'MaxDataServiceVersion' => '1.0;NetFx'}
166
+
167
+ RestClient::Request.any_instance.expects(:execute).returns(expected_payload)
168
+ @table_service.expects(:generate_request_uri).with("Customers").returns("http://localhost/Customers")
169
+ @table_service.expects(:generate_request_uri).with("Customers", {}).returns("http://localhost/Customers")
170
+ request = RestClient::Request.new(:method => :post, :url => "http://localhost/Customers", :headers => expected_headers, :payload => expected_payload)
171
+ @table_service.expects(:generate_request).with(:post, "http://localhost/Customers", expected_headers , expected_payload).returns(request)
172
+
173
+ :binary_data.edm_type = 'Edm.Binary'
174
+ :customer_code.edm_type = 'Edm.Guid'
175
+ :num_of_orders.edm_type = 'Edm.Int64'
176
+
177
+ entity = { :address => 'Mountain View',
178
+ :age => 23,
179
+ :amount_due => 200.23,
180
+ :binary_data => nil,
181
+ :customer_code => 'c9da6455-213d-42c9-9a79-3e9149a57833',
182
+ :customer_since => Time.now.utc,
183
+ :is_active => true,
184
+ :num_of_orders => 255,
185
+ :partition_key => 'myPartitionKey',
186
+ :row_key => 'myRowKey1' }
187
+
188
+ new_entity = @table_service.insert_entity('Customers', entity)
189
+ new_entity.length.should == 10
190
+ new_entity.reject{|k,v| entity.keys.include?(k) and entity.values.to_s.include?(v.to_s)}.length.should == 0
191
+ end
192
+
193
+ it "should update an existing entity" do
194
+ expected_payload = "<?xml version=\"1.0\" encoding=\"utf-8\" standalone=\"yes\"?>" \
195
+ "<entry xmlns:d=\"http://schemas.microsoft.com/ado/2007/08/dataservices\" xmlns:m=\"http://schemas.microsoft.com/ado/2007/08/dataservices/metadata\" xmlns=\"http://www.w3.org/2005/Atom\">" \
196
+ "<id>http://localhost/Customers(PartitionKey='myPartitionKey',RowKey='myRowKey1')</id>" \
197
+ "<title /><updated>#{Time.now.utc.iso8601}</updated><author><name /></author><link rel=\"edit\" title=\"Customers\" href=\"Customers(PartitionKey='myPartitionKey',RowKey='myRowKey1')\" />" \
198
+ "<content type=\"application/xml\">" \
199
+ "<m:properties>" \
200
+ "<d:Timestamp m:type=\"Edm.DateTime\">#{Time.now.utc.iso8601}</d:Timestamp>" \
201
+ "<d:address m:type=\"Edm.String\">Mountain View</d:address>" \
202
+ "<d:age m:type=\"Edm.Int32\">23</d:age>" \
203
+ "<d:amount_due m:type=\"Edm.Double\">200.23</d:amount_due>" \
204
+ "<d:binary_data m:type=\"Edm.Binary\">#{Base64.encode64(File.read(__FILE__))}</d:binary_data>" \
205
+ "<d:customer_code m:type=\"Edm.Guid\">c9da6455-213d-42c9-9a79-3e9149a57833</d:customer_code>" \
206
+ "<d:customer_since m:type=\"Edm.DateTime\">#{Time.now.utc.iso8601}</d:customer_since>" \
207
+ "<d:is_active m:type=\"Edm.Boolean\">true</d:is_active>" \
208
+ "<d:num_of_orders m:type=\"Edm.Int64\">255</d:num_of_orders>" \
209
+ "<d:PartitionKey>myPartitionKey</d:PartitionKey>" \
210
+ "<d:RowKey>myRowKey1</d:RowKey>" \
211
+ "</m:properties></content></entry>"
212
+ expected_headers = {'If-Match' => '*', 'Content-Type' => 'application/atom+xml', 'Date' => Time.new.httpdate, 'DataServiceVersion' => '1.0;NetFx', 'MaxDataServiceVersion' => '1.0;NetFx'}
213
+ expected_url = "http://localhost/Customers(PartitionKey='myPartitionKey',RowKey='myRowKey1')"
214
+
215
+ RestClient::Request.any_instance.expects(:execute).returns(expected_payload)
216
+ @table_service.expects(:generate_request_uri).with("Customers").returns("http://localhost/Customers")
217
+ @table_service.expects(:generate_request_uri).with("Customers(PartitionKey='myPartitionKey',RowKey='myRowKey1')", {}).returns(expected_url)
218
+ request = RestClient::Request.new(:method => :put, :url => expected_url, :headers => expected_headers, :payload => expected_payload)
219
+ @table_service.expects(:generate_request).with(:put, expected_url, expected_headers , expected_payload).returns(request)
220
+
221
+ :binary_data.edm_type = 'Edm.Binary'
222
+ :customer_code.edm_type = 'Edm.Guid'
223
+ :num_of_orders.edm_type = 'Edm.Int64'
224
+
225
+ entity = { :address => 'Mountain View',
226
+ :age => 23,
227
+ :amount_due => 200.23,
228
+ :binary_data => File.open(__FILE__),
229
+ :customer_code => 'c9da6455-213d-42c9-9a79-3e9149a57833',
230
+ :customer_since => Time.now.utc,
231
+ :is_active => true,
232
+ :num_of_orders => 255,
233
+ :partition_key => 'myPartitionKey',
234
+ :row_key => 'myRowKey1',
235
+ :Timestamp => Time.now.utc}
236
+
237
+
238
+ updated_entity = @table_service.update_entity('Customers', entity)
239
+
240
+ updated_entity.length.should == 11
241
+ # 1 because of binary_data
242
+ updated_entity.reject{|k,v| entity.keys.include?(k) and entity.values.to_s.include?(v.to_s)}.length.should == 1
243
+ entity[:binary_data].pos = 0
244
+ updated_entity[:binary_data].read.should == entity[:binary_data].read
245
+ end
246
+
247
+ it "should merge an existing entity" do
248
+ expected_payload = "<?xml version=\"1.0\" encoding=\"utf-8\" standalone=\"yes\"?>" \
249
+ "<entry xmlns:d=\"http://schemas.microsoft.com/ado/2007/08/dataservices\" xmlns:m=\"http://schemas.microsoft.com/ado/2007/08/dataservices/metadata\" xmlns=\"http://www.w3.org/2005/Atom\">" \
250
+ "<id>http://localhost/Customers(PartitionKey='myPartitionKey',RowKey='myRowKey1')</id>" \
251
+ "<title /><updated>#{Time.now.utc.iso8601}</updated><author><name /></author><link rel=\"edit\" title=\"Customers\" href=\"Customers(PartitionKey='myPartitionKey',RowKey='myRowKey1')\" />" \
252
+ "<content type=\"application/xml\">" \
253
+ "<m:properties>" \
254
+ "<d:Timestamp m:type=\"Edm.DateTime\">#{Time.now.utc.iso8601}</d:Timestamp>" \
255
+ "<d:address m:type=\"Edm.String\">Mountain View</d:address>" \
256
+ "<d:age m:type=\"Edm.Int32\">23</d:age>" \
257
+ "<d:amount_due m:type=\"Edm.Double\">200.23</d:amount_due>" \
258
+ "<d:binary_data m:type=\"Edm.Binary\" m:null=\"true\" />" \
259
+ "<d:customer_code m:type=\"Edm.Guid\">c9da6455-213d-42c9-9a79-3e9149a57833</d:customer_code>" \
260
+ "<d:customer_since m:type=\"Edm.DateTime\">#{Time.now.utc.iso8601}</d:customer_since>" \
261
+ "<d:is_active m:type=\"Edm.Boolean\">true</d:is_active>" \
262
+ "<d:num_of_orders m:type=\"Edm.Int64\">255</d:num_of_orders>" \
263
+ "<d:PartitionKey>myPartitionKey</d:PartitionKey>" \
264
+ "<d:RowKey>myRowKey1</d:RowKey>" \
265
+ "</m:properties></content></entry>"
266
+
267
+ expected_headers = {'If-Match' => '*', 'Content-Type' => 'application/atom+xml', 'Date' => Time.new.httpdate, 'DataServiceVersion' => '1.0;NetFx', 'MaxDataServiceVersion' => '1.0;NetFx'}
268
+ expected_url = "http://localhost/Customers(PartitionKey='myPartitionKey',RowKey='myRowKey1')"
269
+ request = RestClient::Request.new(:method => :merge, :url => expected_url, :headers => expected_headers, :payload => expected_payload)
270
+
271
+ RestClient::Request.any_instance.expects(:execute).returns(expected_payload)
272
+ @table_service.expects(:generate_request_uri).with("Customers").returns("http://localhost/Customers")
273
+ @table_service.expects(:generate_request_uri).with("Customers(PartitionKey='myPartitionKey',RowKey='myRowKey1')", {}).returns(expected_url)
274
+ @table_service.expects(:generate_request).with(:merge, expected_url, expected_headers , expected_payload).returns(request)
275
+
276
+ :binary_data.edm_type = 'Edm.Binary'
277
+ :customer_code.edm_type = 'Edm.Guid'
278
+ :num_of_orders.edm_type = 'Edm.Int64'
279
+
280
+ entity = { :address => 'Mountain View',
281
+ :age => 23,
282
+ :amount_due => 200.23,
283
+ :binary_data => nil,
284
+ :customer_code => 'c9da6455-213d-42c9-9a79-3e9149a57833',
285
+ :customer_since => Time.now.utc,
286
+ :is_active => true,
287
+ :num_of_orders => 255,
288
+ :partition_key => 'myPartitionKey',
289
+ :row_key => 'myRowKey1',
290
+ :Timestamp => Time.now.utc}
291
+
292
+ merged_entity = @table_service.merge_entity('Customers', entity)
293
+ merged_entity.length.should == 11
294
+ merged_entity.reject{|k,v| entity.keys.include?(k) and entity.values.to_s.include?(v.to_s)}.length.should == 0
295
+ end
296
+
297
+ it "should throw TooManyProperties exception" do
298
+ long_entity = {}
299
+ 253.times { |i| long_entity.merge!({ "test#{i.to_s}".to_sym => "value#{i}"} ) }
300
+ lambda {@table_service.insert_entity('Customers', long_entity)}.should raise_error(WAZ::Tables::TooManyProperties, "The entity contains more properties than allowed (252). The entity has 253 properties.")
301
+ end
302
+
303
+ it "should throw EntityAlreadyExists exception" do
304
+
305
+ entity = { :partition_key => 'myPartitionKey', :row_key => 'myRowKey1', :name => 'name' }
306
+
307
+ response = mock()
308
+ response.stubs(:body).returns('EntityAlreadyExists The specified entity already exists')
309
+ request_failed = RestClient::RequestFailed.new
310
+ request_failed.stubs(:response).returns(response)
311
+ request_failed.stubs(:http_code).returns(409)
312
+
313
+ RestClient::Request.any_instance.expects(:execute).raises(request_failed)
314
+ lambda {@table_service.insert_entity('Customers', entity)}.should raise_error(WAZ::Tables::EntityAlreadyExists, "The specified entity already exists. RowKey: myRowKey1")
315
+ end
316
+
317
+ it "should delete an existing entity" do
318
+ RestClient::Request.any_instance.expects(:execute).returns(mock())
319
+ expected_headers = {'If-Match' => '*', 'Date' => Time.new.httpdate, 'DataServiceVersion' => '1.0;NetFx', 'Content-Type' => 'application/atom+xml', 'MaxDataServiceVersion' => '1.0;NetFx'}
320
+ expected_url = "http://localhost/Customers(PartitionKey='myPartitionKey',RowKey='myRowKey1'"
321
+ request = RestClient::Request.new(:method => :post, :url => expected_url, :headers => expected_headers)
322
+ @table_service.expects(:generate_request_uri).with("Customers(PartitionKey='myPartitionKey',RowKey='myRowKey1')", {}).returns(expected_url)
323
+ @table_service.expects(:generate_request).with(:delete, expected_url, expected_headers, nil).returns(request)
324
+ @table_service.delete_entity('Customers', 'myPartitionKey', 'myRowKey1')
325
+ end
326
+
327
+ it "should throw when trying to delete and entity and the table does not exists" do
328
+ response = mock()
329
+ response.stubs(:body).returns('TableNotFound')
330
+ request_failed = RestClient::ResourceNotFound.new
331
+ request_failed.stubs(:response).returns(response)
332
+ request_failed.stubs(:http_code).returns(404)
333
+
334
+ RestClient::Request.any_instance.expects(:execute).raises(request_failed)
335
+ lambda { @table_service.delete_entity('unexistingtable', 'myPartitionKey', 'myRowKey1') }.should raise_error(WAZ::Tables::TableDoesNotExist, "The specified table unexistingtable does not exist.")
336
+ end
337
+
338
+ it "should throw when trying to delete and entity and the table does not exists" do
339
+ response = mock()
340
+ response.stubs(:body).returns('ResourceNotFound')
341
+ request_failed = RestClient::ResourceNotFound.new
342
+ request_failed.stubs(:response).returns(response)
343
+ request_failed.stubs(:http_code).returns(404)
344
+
345
+ RestClient::Request.any_instance.expects(:execute).raises(request_failed)
346
+ lambda { @table_service.delete_entity('table', 'myPartitionKey', 'myRowKey1') }.should raise_error(WAZ::Tables::EntityDoesNotExist, "The specified entity with (PartitionKey='myPartitionKey',RowKey='myRowKey1') does not exist.")
347
+ end
348
+
349
+ it "should get an entity by a given partitionkey and rowkey" do
350
+ mock_response = <<-eom
351
+ <?xml version="1.0" encoding="utf-8" standalone="yes"?>
352
+ <entry xml:base="http://myaccount.tables.core.windows.net/" xmlns:d="http://schemas.microsoft.com/ado/2007/08/dataservices" xmlns:m="http://schemas.microsoft.com/ado/2007/08/dataservices/metadata" m:etag="W/&quot;datetime'2010-01-01T15%3A50%3A49.9612116Z'&quot;" xmlns="http://www.w3.org/2005/Atom">
353
+ <id>http://myaccount.tables.core.windows.net/Customers(PartitionKey='myPartitionKey',RowKey='myRowKey1')</id>
354
+ <title type="text"></title>
355
+ <updated>2008-10-01T15:26:13Z</updated>
356
+ <author>
357
+ <name />
358
+ </author>
359
+ <link rel="edit" title="Customers" href="Customers (PartitionKey='myPartitionKey',RowKey='myRowKey1')" />
360
+ <category term="myaccount.Customers" scheme="http://schemas.microsoft.com/ado/2007/08/dataservices/scheme" />
361
+ <content type="application/xml">
362
+ <m:properties>
363
+ <d:PartitionKey>myPartitionKey</d:PartitionKey>
364
+ <d:RowKey>myRowKey1</d:RowKey>
365
+ <d:Timestamp m:type="Edm.DateTime">2008-10-01T15:26:04.6812774Z</d:Timestamp>
366
+ <d:Address>123 Lakeview Blvd, Redmond WA 98052</d:Address>
367
+ <d:CustomerSince m:type="Edm.DateTime">2008-10-01T15:25:05.2852025Z</d:CustomerSince>
368
+ <d:Discount m:type="Edm.Double">10</d:Discount>
369
+ <d:Rating16 m:type="Edm.Int16">3</d:Rating16>
370
+ <d:Rating32 m:type="Edm.Int32">6</d:Rating32>
371
+ <d:Rating64 m:type="Edm.Int64">9</d:Rating64>
372
+ <d:BinaryData m:type="Edm.Binary" m:null="true" />
373
+ <d:SomeBoolean m:type="Edm.Boolean">true</d:SomeBoolean>
374
+ <d:SomeSingle m:type="Edm.Single">9.3</d:SomeSingle>
375
+ </m:properties>
376
+ </content>
377
+ </entry>
378
+ eom
379
+ expected_headers = {'Date' => Time.new.httpdate, 'DataServiceVersion' => '1.0;NetFx', 'Content-Type' => 'application/atom+xml', 'MaxDataServiceVersion' => '1.0;NetFx'}
380
+ expected_url = "http://myaccount.tables.core.windows.net/Customers(PartitionKey='myPartitionKey',RowKey='myRowKey1')"
381
+ RestClient::Request.any_instance.expects(:execute).returns(mock_response)
382
+ @table_service.expects(:generate_request_uri).with("Customers(PartitionKey='myPartitionKey',RowKey='myRowKey1')", {}).returns(expected_url)
383
+ @table_service.expects(:generate_request).with(:get, expected_url, expected_headers, nil).returns(RestClient::Request.new(:method => :post, :url => expected_url, :headers => expected_headers))
384
+
385
+ entity = @table_service.get_entity('Customers', 'myPartitionKey', 'myRowKey1')
386
+
387
+ entity.length.should == 12
388
+
389
+ entity[:partition_key].should == 'myPartitionKey'
390
+ entity[:row_key].should == 'myRowKey1'
391
+ entity[:Timestamp].should == Time.parse('2008-10-01T15:26:04.6812774Z')
392
+ entity[:Address].should == '123 Lakeview Blvd, Redmond WA 98052'
393
+ entity[:CustomerSince].should == Time.parse('2008-10-01T15:25:05.2852025Z')
394
+ entity[:Discount].should == 10
395
+ entity[:Rating16].should == 3
396
+ entity[:Rating32].should == 6
397
+ entity[:Rating64].should == 9
398
+ entity[:BinaryData].should == nil
399
+ entity[:SomeBoolean].should == true
400
+ entity[:SomeSingle].should == 9.3
401
+ end
402
+
403
+ it "should get a set of entities" do
404
+ mock_response = <<-eom
405
+ <?xml version="1.0" encoding="utf-8" standalone="yes"?>
406
+ <feed xml:base="http://myaccount.tables.core.windows.net/" xmlns:d="http://schemas.microsoft.com/ado/2007/08/dataservices" xmlns:m="http://schemas.microsoft.com/ado/2007/08/dataservices/metadata" xmlns="http://www.w3.org/2005/Atom">
407
+ <title type="text">Customers</title>
408
+ <id>http://myaccount.tables.core.windows.net/Customers</id>
409
+ <updated>2008-10-01T15:26:13Z</updated>
410
+ <link rel="self" title="Customers" href="Customers" />
411
+ <entry xml:base="http://myaccount.tables.core.windows.net/" xmlns:d="http://schemas.microsoft.com/ado/2007/08/dataservices" xmlns:m="http://schemas.microsoft.com/ado/2007/08/dataservices/metadata" m:etag="W/&quot;datetime'2010-01-01T15%3A50%3A49.9612116Z'&quot;" xmlns="http://www.w3.org/2005/Atom">
412
+ <id>http://myaccount.tables.core.windows.net/Customers(PartitionKey='myPartitionKey',RowKey='myRowKey1')</id>
413
+ <title type="text"></title>
414
+ <updated>2008-10-01T15:26:13Z</updated>
415
+ <author>
416
+ <name />
417
+ </author>
418
+ <link rel="edit" title="Customers" href="Customers (PartitionKey='myPartitionKey',RowKey='myRowKey1')" />
419
+ <category term="myaccount.Customers" scheme="http://schemas.microsoft.com/ado/2007/08/dataservices/scheme" />
420
+ <content type="application/xml">
421
+ <m:properties>
422
+ <d:PartitionKey>myPartitionKey</d:PartitionKey>
423
+ <d:RowKey>myRowKey1</d:RowKey>
424
+ <d:Timestamp m:type="Edm.DateTime">2008-10-01T15:26:04.6812774Z</d:Timestamp>
425
+ <d:Address>123 Lakeview Blvd, Redmond WA 98052</d:Address>
426
+ <d:CustomerSince m:type="Edm.DateTime">2008-10-01T15:25:05.2852025Z</d:CustomerSince>
427
+ <d:Discount m:type="Edm.Double">10</d:Discount>
428
+ <d:Rating m:type="Edm.Int32">3</d:Rating>
429
+ <d:BinaryData m:type="Edm.Binary" m:null="true" />
430
+ </m:properties>
431
+ </content>
432
+ </entry>
433
+ <entry xml:base="http://myaccount.tables.core.windows.net/" xmlns:d="http://schemas.microsoft.com/ado/2007/08/dataservices" xmlns:m="http://schemas.microsoft.com/ado/2007/08/dataservices/metadata" m:etag="W/&quot;datetime'2010-01-01T15%3A50%3A49.9612116Z'&quot;" xmlns="http://www.w3.org/2005/Atom">
434
+ <id>http://myaccount.tables.core.windows.net/Customers(PartitionKey='myPartitionKey',RowKey='myRowKey2')</id>
435
+ <title type="text"></title>
436
+ <updated>2008-10-01T15:26:13Z</updated>
437
+ <author>
438
+ <name />
439
+ </author>
440
+ <link rel="edit" title="Customers" href="Customers (PartitionKey='myPartitionKey',RowKey='myRowKey2')" />
441
+ <category term="myaccount.Customers" scheme="http://schemas.microsoft.com/ado/2007/08/dataservices/scheme" />
442
+ <content type="application/xml">
443
+ <m:properties>
444
+ <d:PartitionKey>myPartitionKey</d:PartitionKey>
445
+ <d:RowKey>myRowKey2</d:RowKey>
446
+ <d:Timestamp m:type="Edm.DateTime">2009-10-01T15:26:04.6812774Z</d:Timestamp>
447
+ <d:Address>234 Lakeview Blvd, Redmond WA 98052</d:Address>
448
+ <d:CustomerSince m:type="Edm.DateTime">2009-10-01T15:25:05.2852025Z</d:CustomerSince>
449
+ <d:Discount m:type="Edm.Double">11</d:Discount>
450
+ <d:Rating m:type="Edm.Int32">4</d:Rating>
451
+ <d:BinaryData m:type="Edm.Binary" m:null="true" />
452
+ </m:properties>
453
+ </content>
454
+ </entry>
455
+ </feed>
456
+ eom
457
+ mock_response.stubs(:headers).returns({})
458
+ expected_headers = {'Date' => Time.new.httpdate, 'DataServiceVersion' => '1.0;NetFx', 'Content-Type' => 'application/atom+xml', 'MaxDataServiceVersion' => '1.0;NetFx'}
459
+ expected_url = "http://myaccount.tables.core.windows.net/Customers()?$filter=expression"
460
+ expected_query = { '$filter' => "expression" }
461
+
462
+ RestClient::Request.any_instance.expects(:execute).once().returns(mock_response)
463
+ @table_service.expects(:generate_request_uri).with("Customers()", expected_query).returns(expected_url)
464
+ @table_service.expects(:generate_request).with(:get, expected_url, expected_headers, nil).returns(RestClient::Request.new(:method => :post, :url => expected_url, :headers => expected_headers))
465
+ entities = @table_service.query('Customers', {:expression => 'expression'})
466
+
467
+ entities.length.should == 2
468
+ entities.continuation_token[:next_partition_key].nil?.should == true
469
+ entities.continuation_token[:next_row_key].nil?.should == true
470
+
471
+ entities.first.length.should == 8
472
+ entities.first[:partition_key].should == 'myPartitionKey'
473
+ entities.first[:row_key].should == 'myRowKey1'
474
+ entities.first[:Timestamp].should == Time.parse('2008-10-01T15:26:04.6812774Z')
475
+ entities.first[:Address].should == '123 Lakeview Blvd, Redmond WA 98052'
476
+ entities.first[:CustomerSince].should == Time.parse('2008-10-01T15:25:05.2852025Z')
477
+ entities.first[:Discount].should == 10
478
+ entities.first[:Rating].should == 3
479
+ entities.first[:BinaryData].should == nil
480
+
481
+ entities.last.length.should == 8
482
+ entities.last[:partition_key].should == 'myPartitionKey'
483
+ entities.last[:row_key].should == 'myRowKey2'
484
+ entities.last[:Timestamp].should == Time.parse('2009-10-01T15:26:04.6812774Z')
485
+ entities.last[:Address].should == '234 Lakeview Blvd, Redmond WA 98052'
486
+ entities.last[:CustomerSince].should == Time.parse('2009-10-01T15:25:05.2852025Z')
487
+ entities.last[:Discount].should == 11
488
+ entities.last[:Rating].should == 4
489
+ entities.last[:BinaryData].should == nil
490
+ end
491
+
492
+ it "should send the $top query parameter when calling the service with top option " do
493
+ mock_response = <<-eom
494
+ <?xml version="1.0" encoding="utf-8" standalone="yes"?>
495
+ <feed xml:base="http://myaccount.tables.core.windows.net/" xmlns:d="http://schemas.microsoft.com/ado/2007/08/dataservices" xmlns:m="http://schemas.microsoft.com/ado/2007/08/dataservices/metadata" xmlns="http://www.w3.org/2005/Atom">
496
+ <title type="text">Customers</title>
497
+ <id>http://myaccount.tables.core.windows.net/Customers</id>
498
+ <updated>2008-10-01T15:26:13Z</updated>
499
+ <link rel="self" title="Customers" href="Customers" />
500
+ <entry xml:base="http://myaccount.tables.core.windows.net/" xmlns:d="http://schemas.microsoft.com/ado/2007/08/dataservices" xmlns:m="http://schemas.microsoft.com/ado/2007/08/dataservices/metadata" m:etag="W/&quot;datetime'2010-01-01T15%3A50%3A49.9612116Z'&quot;" xmlns="http://www.w3.org/2005/Atom">
501
+ <id>http://myaccount.tables.core.windows.net/Customers(PartitionKey='myPartitionKey',RowKey='myRowKey1')</id>
502
+ <title type="text"></title>
503
+ <updated>2008-10-01T15:26:13Z</updated>
504
+ <author>
505
+ <name />
506
+ </author>
507
+ <link rel="edit" title="Customers" href="Customers (PartitionKey='myPartitionKey',RowKey='myRowKey1')" />
508
+ <category term="myaccount.Customers" scheme="http://schemas.microsoft.com/ado/2007/08/dataservices/scheme" />
509
+ <content type="application/xml">
510
+ <m:properties>
511
+ <d:PartitionKey>myPartitionKey</d:PartitionKey>
512
+ <d:RowKey>myRowKey1</d:RowKey>
513
+ <d:Rating m:type="Edm.Int32">3</d:Rating>
514
+ </m:properties>
515
+ </content>
516
+ </entry>
517
+ </feed>
518
+ eom
519
+ mock_response.stubs(:headers).returns({})
520
+
521
+ expected_headers = {'Date' => Time.new.httpdate, 'DataServiceVersion' => '1.0;NetFx', 'Content-Type' => 'application/atom+xml', 'MaxDataServiceVersion' => '1.0;NetFx'}
522
+ expected_url = "http://myaccount.tables.core.windows.net/Customers()?$filter=expression&$top=1"
523
+ expected_query = { '$filter' => "expression", '$top' => 1 }
524
+
525
+ RestClient::Request.any_instance.expects(:execute).once().returns(mock_response)
526
+ @table_service.expects(:generate_request_uri).once().with("Customers()", expected_query).returns(expected_url)
527
+ @table_service.expects(:generate_request).once().with(:get, expected_url, expected_headers, nil).returns(RestClient::Request.new(:method => :post, :url => expected_url, :headers => expected_headers))
528
+ entities = @table_service.query('Customers', {:expression => 'expression', :top => 1 })
529
+
530
+ entities.length.should == 1
531
+ entities.continuation_token[:next_partition_key].nil?.should == true
532
+ entities.continuation_token[:next_row_key].nil?.should == true
533
+ end
534
+
535
+ it "should return a continuation token as array property" do
536
+ sample_feed = <<-eom
537
+ <?xml version="1.0" encoding="utf-8" standalone="yes"?>
538
+ <feed xml:base="http://myaccount.tables.core.windows.net/" xmlns:d="http://schemas.microsoft.com/ado/2007/08/dataservices" xmlns:m="http://schemas.microsoft.com/ado/2007/08/dataservices/metadata" xmlns="http://www.w3.org/2005/Atom">
539
+ <title type="text">Customers</title>
540
+ <id>http://myaccount.tables.core.windows.net/Customers</id>
541
+ <updated>2008-10-01T15:26:13Z</updated>
542
+ <link rel="self" title="Customers" href="Customers" />
543
+ <entry xml:base="http://myaccount.tables.core.windows.net/" xmlns:d="http://schemas.microsoft.com/ado/2007/08/dataservices" xmlns:m="http://schemas.microsoft.com/ado/2007/08/dataservices/metadata" m:etag="W/&quot;datetime'2010-01-01T15%3A50%3A49.9612116Z'&quot;" xmlns="http://www.w3.org/2005/Atom">
544
+ <id>http://myaccount.tables.core.windows.net/Customers(PartitionKey='myPartitionKey',RowKey='myRowKey1')</id>
545
+ <title type="text"></title>
546
+ <updated>2008-10-01T15:26:13Z</updated>
547
+ <author>
548
+ <name />
549
+ </author>
550
+ <link rel="edit" title="Customers" href="Customers (PartitionKey='myPartitionKey',RowKey='myRowKey1')" />
551
+ <category term="myaccount.Customers" scheme="http://schemas.microsoft.com/ado/2007/08/dataservices/scheme" />
552
+ <content type="application/xml">
553
+ <m:properties>
554
+ <d:PartitionKey>myPartitionKey</d:PartitionKey>
555
+ <d:RowKey>myRowKey1</d:RowKey>
556
+ <d:Rating m:type="Edm.Int32">3</d:Rating>
557
+ </m:properties>
558
+ </content>
559
+ </entry>
560
+ </feed>
561
+ eom
562
+ mock_response, mock_response2 = sample_feed
563
+ mock_response.stubs(:headers).returns({:x_ms_continuation_nextpartitionkey => 'next_partition_key_value', :x_ms_continuation_nextrowkey => 'next_row_key_value'})
564
+
565
+ expected_headers = {'Date' => Time.new.httpdate, 'DataServiceVersion' => '1.0;NetFx', 'Content-Type' => 'application/atom+xml', 'MaxDataServiceVersion' => '1.0;NetFx'}
566
+ expected_query = { '$filter' => "expression" }
567
+ rest_client = RestClient::Request.new(:method => :post, :url => "http://myaccount.tables.core.windows.net/Customers()?$filter=expression", :headers => expected_headers)
568
+ rest_client.expects(:execute).once().returns(mock_response)
569
+
570
+ @table_service.expects(:generate_request_uri).with("Customers()", expected_query).returns("http://myaccount.tables.core.windows.net/Customers()?$filter=expression")
571
+ @table_service.expects(:generate_request).once().with(:get, "http://myaccount.tables.core.windows.net/Customers()?$filter=expression", expected_headers, nil).returns(rest_client)
572
+ entities = @table_service.query('Customers', {:expression => 'expression'})
573
+
574
+ entities.length.should == 1
575
+ entities.continuation_token['NextPartitionKey'].should == 'next_partition_key_value'
576
+ entities.continuation_token['NextRowKey'].should == 'next_row_key_value'
577
+ end
578
+
579
+ it "should throw when invalid table name is provided" do
580
+ lambda { @table_service.create_table('9existing') }.should raise_error(WAZ::Tables::InvalidTableName)
581
+ end
582
+
583
+ it "should throw when invalid table name is provided" do
584
+ lambda { @table_service.delete_table('9existing') }.should raise_error(WAZ::Tables::InvalidTableName)
585
+ end
586
+
587
+ it "should throw when invalid table name is provided" do
588
+ lambda { @table_service.get_table('9existing') }.should raise_error(WAZ::Tables::InvalidTableName)
589
+ end
590
+
591
+ it "should throw when invalid table name is provided" do
592
+ lambda { @table_service.insert_entity('9existing', 'entity') }.should raise_error(WAZ::Tables::InvalidTableName)
593
+ end
594
+
595
+ it "should throw when invalid table name is provided" do
596
+ lambda { @table_service.delete_entity('9existing', 'foo', 'foo') }.should raise_error(WAZ::Tables::InvalidTableName)
597
+ end
598
+
599
+ it "should throw when invalid table name is provided" do
600
+ lambda { @table_service.get_entity('9existing', 'foo', 'foo') }.should raise_error(WAZ::Tables::InvalidTableName)
601
+ end
602
+
603
+ it "should throw when invalid table name is provided" do
604
+ lambda { @table_service.query('9existing', 'foo') }.should raise_error(WAZ::Tables::InvalidTableName)
605
+ end
606
+
607
+ it "should throw when invalid table name is provided" do
608
+ lambda { @table_service.update_entity('9existing', {}) }.should raise_error(WAZ::Tables::InvalidTableName)
609
+ end
610
+
611
+ it "should throw when invalid table name is provided" do
612
+ lambda { @table_service.merge_entity('9existing', {}) }.should raise_error(WAZ::Tables::InvalidTableName)
613
+ end
614
+ end