waz-storage 1.2.0 → 1.3.0

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.
Files changed (40) hide show
  1. data/.gitignore +9 -9
  2. data/CHANGELOG.rdoc +72 -72
  3. data/Gemfile +4 -4
  4. data/Gemfile.lock +46 -40
  5. data/LICENSE +18 -18
  6. data/README.rdoc +310 -310
  7. data/lib/waz-blobs.rb +4 -4
  8. data/lib/waz-queues.rb +6 -6
  9. data/lib/waz-storage.rb +39 -39
  10. data/lib/waz-tables.rb +4 -4
  11. data/lib/waz/blobs/blob_object.rb +122 -122
  12. data/lib/waz/blobs/container.rb +172 -161
  13. data/lib/waz/blobs/exceptions.rb +10 -10
  14. data/lib/waz/blobs/service.rb +181 -156
  15. data/lib/waz/queues/exceptions.rb +28 -28
  16. data/lib/waz/queues/message.rb +64 -64
  17. data/lib/waz/queues/queue.rb +164 -164
  18. data/lib/waz/queues/service.rb +105 -105
  19. data/lib/waz/storage/base.rb +70 -70
  20. data/lib/waz/storage/exceptions.rb +33 -33
  21. data/lib/waz/storage/validation_rules.rb +25 -25
  22. data/lib/waz/tables/edm_type_helper.rb +44 -44
  23. data/lib/waz/tables/exceptions.rb +44 -44
  24. data/lib/waz/tables/service.rb +178 -178
  25. data/lib/waz/tables/table.rb +74 -74
  26. data/lib/waz/tables/table_array.rb +10 -10
  27. data/rakefile +8 -21
  28. data/{tests → spec}/configuration.rb +22 -22
  29. data/{tests/waz/blobs/blob_object_test.rb → spec/waz/blobs/blob_object_spec.rb} +80 -80
  30. data/{tests/waz/blobs/container_test.rb → spec/waz/blobs/container_spec.rb} +175 -162
  31. data/{tests/waz/blobs/service_test.rb → spec/waz/blobs/service_spec.rb} +336 -282
  32. data/{tests/waz/queues/message_test.rb → spec/waz/queues/message_spec.rb} +32 -32
  33. data/{tests/waz/queues/queue_test.rb → spec/waz/queues/queue_spec.rb} +205 -205
  34. data/{tests/waz/queues/service_test.rb → spec/waz/queues/service_spec.rb} +298 -298
  35. data/{tests → spec}/waz/storage/base_tests.rb +81 -81
  36. data/{tests/waz/storage/shared_key_core_service_test.rb → spec/waz/storage/shared_key_core_service_spec.rb} +141 -141
  37. data/{tests/waz/tables/service_test.rb → spec/waz/tables/service_spec.rb} +613 -613
  38. data/{tests/waz/tables/table_test.rb → spec/waz/tables/table_spec.rb} +97 -97
  39. data/waz-storage.gemspec +29 -27
  40. metadata +47 -26
@@ -1,81 +1,81 @@
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-blobs'
5
-
6
- describe "Base class for connection management" do
7
- it "should throw an exception when it is not connected" do
8
- lambda {WAZ::Storage::Base.default_connection}.should raise_error(WAZ::Storage::NotConnected)
9
- end
10
-
11
- it "establish connection and set it as default connection" do
12
- WAZ::Storage::Base.establish_connection!(:account_name => 'myAccount',
13
- :access_key => "accountKey",
14
- :use_ssl => true)
15
-
16
- connection = WAZ::Storage::Base.default_connection
17
- connection[:account_name].should == "myAccount"
18
- connection[:access_key].should == "accountKey"
19
- connection[:use_ssl].should == true
20
- end
21
-
22
- it "should throw an exception when no account_name is provided" do
23
- lambda {WAZ::Storage::Base.establish_connection!(:access_key => "accountKey", :use_ssl => false)}.should raise_error(WAZ::Storage::InvalidOption)
24
- end
25
-
26
- it "should throw an exception when no access_key is provided and no use_sas_auth_only" do
27
- lambda {WAZ::Storage::Base.establish_connection!(:account_name => "my_account", :use_ssl => false)}.should raise_error(WAZ::Storage::InvalidOption)
28
- end
29
-
30
- it "should throw and exception when use_sas_auth_only is provided but no sharedaccessignature" do
31
- lambda {WAZ::Storage::Base.establish_connection!(:account_name => "my_account",:use_sas_auth_only => true, :use_ssl => false)}.should raise_error(WAZ::Storage::InvalidOption)
32
- end
33
-
34
-
35
- it "should set use_ssl to false when no paramter provided" do
36
- WAZ::Storage::Base.establish_connection!(:account_name => 'myAccount',
37
- :access_key => "accountKey")
38
-
39
- connection = WAZ::Storage::Base.default_connection
40
- connection[:account_name].should == "myAccount"
41
- connection[:access_key].should == "accountKey"
42
- connection[:use_ssl].should == false
43
- end
44
-
45
- it "should set :use_sas_auth_only to false when no parameter provided" do
46
- WAZ::Storage::Base.establish_connection!(:account_name => 'myAccount',
47
- :access_key => "accountKey")
48
- connection = WAZ::Storage::Base.default_connection
49
- connection[:account_name].should == "myAccount"
50
- connection[:access_key].should == "accountKey"
51
- connection[:use_sas_auth_only] == false
52
- end
53
-
54
-
55
- it "should be able to tell whether it's connected or not" do
56
- WAZ::Storage::Base.establish_connection!(:account_name => 'myAccount',
57
- :access_key => "accountKey")
58
-
59
- WAZ::Storage::Base.connected?.should == true
60
- end
61
-
62
- it "should be able to tell whters it's connected by shared access signature" do
63
- WAZ::Storage::Base.establish_connection!(:account_name => 'myAccount',:use_sas_auth_only=>true, :sharedaccesssignature=>"?se=2011-12-13T23%3A54%3A07Z&sr=c&si=escrituraPAC&sig=e%2Bz6wsGhVRg%2FaxWATiS8A4WjWU%2FbfWjWa6zJ%2BTQIPzM%3D")
64
- WAZ::Storage::Base.connected?.should == true
65
- end
66
-
67
- it "should be able manage scoped connections" do
68
- WAZ::Storage::Base.establish_connection!(:account_name => 'myAccount', :access_key => "accountKey")
69
-
70
- WAZ::Storage::Base.default_connection[:account_name].should == 'myAccount'
71
-
72
- block_executed = false
73
- WAZ::Storage::Base.establish_connection(:account_name => 'otherAccount', :access_key => "accountKey") do
74
- WAZ::Storage::Base.default_connection[:account_name].should == 'otherAccount'
75
- block_executed = true
76
- end
77
- block_executed.should == true
78
-
79
- WAZ::Storage::Base.default_connection[:account_name].should == 'myAccount'
80
- end
81
- end
1
+ # enabling the load of files from root (on RSpec)
2
+ $LOAD_PATH.unshift(File.dirname(__FILE__) + '/../')
3
+ require 'spec/configuration'
4
+ require 'lib/waz-blobs'
5
+
6
+ describe "Base class for connection management" do
7
+ it "should throw an exception when it is not connected" do
8
+ lambda {WAZ::Storage::Base.default_connection}.should raise_error(WAZ::Storage::NotConnected)
9
+ end
10
+
11
+ it "establish connection and set it as default connection" do
12
+ WAZ::Storage::Base.establish_connection!(:account_name => 'myAccount',
13
+ :access_key => "accountKey",
14
+ :use_ssl => true)
15
+
16
+ connection = WAZ::Storage::Base.default_connection
17
+ connection[:account_name].should == "myAccount"
18
+ connection[:access_key].should == "accountKey"
19
+ connection[:use_ssl].should == true
20
+ end
21
+
22
+ it "should throw an exception when no account_name is provided" do
23
+ lambda {WAZ::Storage::Base.establish_connection!(:access_key => "accountKey", :use_ssl => false)}.should raise_error(WAZ::Storage::InvalidOption)
24
+ end
25
+
26
+ it "should throw an exception when no access_key is provided and no use_sas_auth_only" do
27
+ lambda {WAZ::Storage::Base.establish_connection!(:account_name => "my_account", :use_ssl => false)}.should raise_error(WAZ::Storage::InvalidOption)
28
+ end
29
+
30
+ it "should throw and exception when use_sas_auth_only is provided but no sharedaccessignature" do
31
+ lambda {WAZ::Storage::Base.establish_connection!(:account_name => "my_account",:use_sas_auth_only => true, :use_ssl => false)}.should raise_error(WAZ::Storage::InvalidOption)
32
+ end
33
+
34
+
35
+ it "should set use_ssl to false when no paramter provided" do
36
+ WAZ::Storage::Base.establish_connection!(:account_name => 'myAccount',
37
+ :access_key => "accountKey")
38
+
39
+ connection = WAZ::Storage::Base.default_connection
40
+ connection[:account_name].should == "myAccount"
41
+ connection[:access_key].should == "accountKey"
42
+ connection[:use_ssl].should == false
43
+ end
44
+
45
+ it "should set :use_sas_auth_only to false when no parameter provided" do
46
+ WAZ::Storage::Base.establish_connection!(:account_name => 'myAccount',
47
+ :access_key => "accountKey")
48
+ connection = WAZ::Storage::Base.default_connection
49
+ connection[:account_name].should == "myAccount"
50
+ connection[:access_key].should == "accountKey"
51
+ connection[:use_sas_auth_only] == false
52
+ end
53
+
54
+
55
+ it "should be able to tell whether it's connected or not" do
56
+ WAZ::Storage::Base.establish_connection!(:account_name => 'myAccount',
57
+ :access_key => "accountKey")
58
+
59
+ WAZ::Storage::Base.connected?.should == true
60
+ end
61
+
62
+ it "should be able to tell whters it's connected by shared access signature" do
63
+ WAZ::Storage::Base.establish_connection!(:account_name => 'myAccount',:use_sas_auth_only=>true, :sharedaccesssignature=>"?se=2011-12-13T23%3A54%3A07Z&sr=c&si=escrituraPAC&sig=e%2Bz6wsGhVRg%2FaxWATiS8A4WjWU%2FbfWjWa6zJ%2BTQIPzM%3D")
64
+ WAZ::Storage::Base.connected?.should == true
65
+ end
66
+
67
+ it "should be able manage scoped connections" do
68
+ WAZ::Storage::Base.establish_connection!(:account_name => 'myAccount', :access_key => "accountKey")
69
+
70
+ WAZ::Storage::Base.default_connection[:account_name].should == 'myAccount'
71
+
72
+ block_executed = false
73
+ WAZ::Storage::Base.establish_connection(:account_name => 'otherAccount', :access_key => "accountKey") do
74
+ WAZ::Storage::Base.default_connection[:account_name].should == 'otherAccount'
75
+ block_executed = true
76
+ end
77
+ block_executed.should == true
78
+
79
+ WAZ::Storage::Base.default_connection[:account_name].should == 'myAccount'
80
+ end
81
+ end
@@ -1,142 +1,142 @@
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-queues'
5
-
6
- describe "storage service core behavior" do
7
- it "should generate URI with given operation" do
8
- service = WAZ::Queues::Service.new(:account_name => "mock-account", :access_key => "mock-key", :type_of_service => "queue", :use_ssl => true, :base_url => "localhost")
9
- service.generate_request_uri(nil, :comp => 'list').should == "https://mock-account.queue.localhost/?comp=list"
10
- end
11
-
12
- it "should generate an URI without operation when operation is not given" do
13
- service = WAZ::Queues::Service.new(:account_name => "mock-account", :access_key => "mock-key", :type_of_service => "queue", :use_ssl => true, :base_url => "localhost")
14
- service.generate_request_uri("queue").should == "https://mock-account.queue.localhost/queue"
15
- end
16
-
17
- it "should generate a safe URI when path includes forward slash" do
18
- service = WAZ::Queues::Service.new(:account_name => "mock-account", :access_key => "mock-key", :type_of_service => "queue", :use_ssl => true, :base_url => "localhost")
19
- service.generate_request_uri("/queue").should == "https://mock-account.queue.localhost/queue"
20
- end
21
-
22
- it "should include additional parameters when given" do
23
- service = WAZ::Queues::Service.new(:account_name => "mock-account", :access_key => "mock-key", :type_of_service => "queue", :use_ssl => true, :base_url => "localhost")
24
- service.generate_request_uri("/queue", {:comp => 'list', :prefix => "p"}).should == "https://mock-account.queue.localhost/queue?comp=list&prefix=p"
25
- end
26
-
27
- it "should include additional parameters when given althought when there is no comp" do
28
- service = WAZ::Queues::Service.new(:account_name => "mock-account", :access_key => "mock-key", :type_of_service => "queue", :use_ssl => true, :base_url => "localhost")
29
- service.generate_request_uri("/queue", {:prefix => "p", :other => "other"}).should == "https://mock-account.queue.localhost/queue?other=other&prefix=p"
30
- end
31
-
32
- it "should include additional parameters when given althought when there is no comp" do
33
- service = WAZ::Queues::Service.new(:account_name => "mock-account", :access_key => "mock-key", :type_of_service => "queue", :use_ssl => true, :base_url => "localhost")
34
- service.generate_request_uri("/queue", {:comp => "metadata", :messagettl => 650}).should == "https://mock-account.queue.localhost/queue?comp=metadata&messagettl=650"
35
- end
36
-
37
- it "should include additional parameters when given althought when there is no comp" do
38
- service = WAZ::Queues::Service.new(:account_name => "mock-account", :access_key => "mock-key", :type_of_service => "queue", :use_ssl => true, :base_url => "localhost")
39
- service.generate_request_uri("/queue", {:item => "%"}).should == "https://mock-account.queue.localhost/queue?item=%25"
40
- end
41
-
42
- it "should canonicalize headers (order lexicographical, trim values, and join by NEW_LINES)" do
43
- service = WAZ::Queues::Service.new(:account_name => "mock-account", :access_key => "mock-key", :type_of_service => "queue", :use_ssl => true, :base_url => "localhost")
44
- headers = { "Content-Type" => "application/xml",
45
- "x-ms-prop-z" => "p",
46
- "x-ms-meta-name" => "a ",
47
- "x-other" => "other"}
48
-
49
- service.canonicalize_headers(headers).should == "x-ms-meta-name:a\nx-ms-prop-z:p"
50
- end
51
-
52
- it "should return empty string when no MS headers" do
53
- service = WAZ::Queues::Service.new(:account_name => "mock-account", :access_key => "mock-key", :type_of_service => "queue", :use_ssl => true, :base_url => "localhost")
54
- headers = { "Content-Type" => "application/xml",
55
- "x-other" => "other"}
56
-
57
- service.canonicalize_headers(headers).should == ""
58
- end
59
-
60
- it "should cannonicalize message by appending account_name to the request path" do
61
- service = WAZ::Queues::Service.new(:account_name => "mock-account", :access_key => "mock-key", :type_of_service => "queue", :use_ssl => true, :base_url => "localhost")
62
- service.canonicalize_message("http://localhost/queue?comp=list").should == "/mock-account/queue?comp=list"
63
- end
64
-
65
- it "should ignore every other querystring parameter rather than comp=" do
66
- service = WAZ::Queues::Service.new(:account_name => "mock-account", :access_key => "mock-key", :type_of_service => "queue", :use_ssl => true, :base_url => "localhost")
67
- service.canonicalize_message("http://localhost/queue?myparam=1").should == "/mock-account/queue"
68
- end
69
-
70
- it "should properly canonicalize message when no parameter associated with it" do
71
- service = WAZ::Queues::Service.new(:account_name => "mock-account", :access_key => "mock-key", :type_of_service => "queue", :use_ssl => true, :base_url => "localhost")
72
- service.canonicalize_message("http://mock-account.queue.core.windows.net/").should == "/mock-account/"
73
- end
74
-
75
- it "should properly canonicalize message when a resource is associated with it" do
76
- service = WAZ::Queues::Service.new(:account_name => "mock-account", :access_key => "mock-key", :type_of_service => "queue", :use_ssl => true, :base_url => "localhost")
77
- service.canonicalize_message("http://mock-account.queue.core.windows.net/resource?comp=list").should == "/mock-account/resource?comp=list"
78
- end
79
-
80
- it "should generate request with proper headers" do
81
- mock_time = Time.new
82
- Time.stubs(:new).returns(mock_time)
83
- service = WAZ::Queues::Service.new(:account_name => "mock-account", :access_key => "mock-key", :type_of_service => "queue", :use_ssl => true, :base_url => "localhost")
84
-
85
- expected_request_hash = {:headers => {'x-ms-Date' => mock_time.httpdate, "Content-Length" => "payload".length},
86
- :method => :put,
87
- :url => "http://localhost/johnny",
88
- :payload => "payload"}
89
-
90
- # mock the generate signature method since we want to assert against a know value
91
- service.expects(:generate_signature).with(expected_request_hash).returns("a_mock_signature")
92
-
93
- request = service.generate_request("PUT", "http://localhost/johnny", nil, "payload")
94
- request.headers["x-ms-Date"].should == mock_time.httpdate
95
- request.headers["Content-Length"].should == "payload".length
96
- request.headers["Authorization"] = "SharedKey mock-account:a_mock_signature"
97
- end
98
-
99
- it "should set content length when it is not provided" do
100
- mock_time = Time.new
101
- Time.stubs(:new).returns(mock_time)
102
- service = WAZ::Queues::Service.new(:account_name => "mock-account", :access_key => "mock-key", :type_of_service => "queue", :use_ssl => true, :base_url => "localhost")
103
-
104
- expected_request_hash = {:headers => {'x-ms-Date' => mock_time.httpdate, 'Content-Length' => 0},
105
- :method => :put,
106
- :url => "http://localhost/johnny",
107
- :payload => nil}
108
-
109
- # mock the generate signature method since we want to assert against a know value
110
- service.expects(:generate_signature).with(expected_request_hash).returns("a_mock_signature")
111
-
112
- request = service.generate_request("PUT", "http://localhost/johnny", nil)
113
- request.headers["x-ms-Date"].should == mock_time.httpdate
114
- request.headers["Content-Length"].should == 0
115
- request.headers["Authorization"] = "SharedKey mock-account:a_mock_signature"
116
- end
117
-
118
- it "should name headers properly when they are provided as symbols" do
119
- mock_time = Time.new
120
- Time.stubs(:new).returns(mock_time)
121
- service = WAZ::Queues::Service.new(:account_name => "mock-account", :access_key => "mock-key", :type_of_service => "queue", :use_ssl => true, :base_url => "localhost")
122
-
123
- expected_request_hash = {:headers => {'x-ms-Date' => mock_time.httpdate, "Content-Length" => 0, 'Content-Type' => "plain/xml"},
124
- :method => :put,
125
- :url => "http://localhost/johnny",
126
- :payload => nil}
127
-
128
- # mock the generate signature method since we want to assert against a know value
129
- service.expects(:generate_signature).with(expected_request_hash).returns("a_mock_signature")
130
-
131
- request = service.generate_request("PUT", "http://localhost/johnny", {:Content_Type => "plain/xml"})
132
- request.headers["x-ms-Date"].should == mock_time.httpdate
133
- request.headers["Content-Length"].should == 0
134
- request.headers["Authorization"] = "SharedKey mock-account:a_mock_signature"
135
- end
136
-
137
- it "should cannonicalize message by appending account_name to the request path following 2009-09-19 version of the API" do
138
- service = WAZ::Queues::Service.new(:account_name => "myaccount", :access_key => "mock-key", :type_of_service => "queue", :use_ssl => true, :base_url => "localhost")
139
- canonical_message = service.canonicalize_message20090919("http://myaccount.blob.core.windows.net/mycontainer?restype=container&comp=metadata")
140
- canonical_message.should == "/myaccount/mycontainer\ncomp:metadata\nrestype:container"
141
- end
1
+ # enabling the load of files from root (on RSpec)
2
+ $LOAD_PATH.unshift(File.dirname(__FILE__) + '/../')
3
+ require 'spec/configuration'
4
+ require 'lib/waz-queues'
5
+
6
+ describe "storage service core behavior" do
7
+ it "should generate URI with given operation" do
8
+ service = WAZ::Queues::Service.new(:account_name => "mock-account", :access_key => "mock-key", :type_of_service => "queue", :use_ssl => true, :base_url => "localhost")
9
+ service.generate_request_uri(nil, :comp => 'list').should == "https://mock-account.queue.localhost/?comp=list"
10
+ end
11
+
12
+ it "should generate an URI without operation when operation is not given" do
13
+ service = WAZ::Queues::Service.new(:account_name => "mock-account", :access_key => "mock-key", :type_of_service => "queue", :use_ssl => true, :base_url => "localhost")
14
+ service.generate_request_uri("queue").should == "https://mock-account.queue.localhost/queue"
15
+ end
16
+
17
+ it "should generate a safe URI when path includes forward slash" do
18
+ service = WAZ::Queues::Service.new(:account_name => "mock-account", :access_key => "mock-key", :type_of_service => "queue", :use_ssl => true, :base_url => "localhost")
19
+ service.generate_request_uri("/queue").should == "https://mock-account.queue.localhost/queue"
20
+ end
21
+
22
+ it "should include additional parameters when given" do
23
+ service = WAZ::Queues::Service.new(:account_name => "mock-account", :access_key => "mock-key", :type_of_service => "queue", :use_ssl => true, :base_url => "localhost")
24
+ service.generate_request_uri("/queue", {:comp => 'list', :prefix => "p"}).should == "https://mock-account.queue.localhost/queue?comp=list&prefix=p"
25
+ end
26
+
27
+ it "should include additional parameters when given althought when there is no comp" do
28
+ service = WAZ::Queues::Service.new(:account_name => "mock-account", :access_key => "mock-key", :type_of_service => "queue", :use_ssl => true, :base_url => "localhost")
29
+ service.generate_request_uri("/queue", {:prefix => "p", :other => "other"}).should == "https://mock-account.queue.localhost/queue?other=other&prefix=p"
30
+ end
31
+
32
+ it "should include additional parameters when given althought when there is no comp" do
33
+ service = WAZ::Queues::Service.new(:account_name => "mock-account", :access_key => "mock-key", :type_of_service => "queue", :use_ssl => true, :base_url => "localhost")
34
+ service.generate_request_uri("/queue", {:comp => "metadata", :messagettl => 650}).should == "https://mock-account.queue.localhost/queue?comp=metadata&messagettl=650"
35
+ end
36
+
37
+ it "should include additional parameters when given althought when there is no comp" do
38
+ service = WAZ::Queues::Service.new(:account_name => "mock-account", :access_key => "mock-key", :type_of_service => "queue", :use_ssl => true, :base_url => "localhost")
39
+ service.generate_request_uri("/queue", {:item => "%"}).should == "https://mock-account.queue.localhost/queue?item=%25"
40
+ end
41
+
42
+ it "should canonicalize headers (order lexicographical, trim values, and join by NEW_LINES)" do
43
+ service = WAZ::Queues::Service.new(:account_name => "mock-account", :access_key => "mock-key", :type_of_service => "queue", :use_ssl => true, :base_url => "localhost")
44
+ headers = { "Content-Type" => "application/xml",
45
+ "x-ms-prop-z" => "p",
46
+ "x-ms-meta-name" => "a ",
47
+ "x-other" => "other"}
48
+
49
+ service.canonicalize_headers(headers).should == "x-ms-meta-name:a\nx-ms-prop-z:p"
50
+ end
51
+
52
+ it "should return empty string when no MS headers" do
53
+ service = WAZ::Queues::Service.new(:account_name => "mock-account", :access_key => "mock-key", :type_of_service => "queue", :use_ssl => true, :base_url => "localhost")
54
+ headers = { "Content-Type" => "application/xml",
55
+ "x-other" => "other"}
56
+
57
+ service.canonicalize_headers(headers).should == ""
58
+ end
59
+
60
+ it "should cannonicalize message by appending account_name to the request path" do
61
+ service = WAZ::Queues::Service.new(:account_name => "mock-account", :access_key => "mock-key", :type_of_service => "queue", :use_ssl => true, :base_url => "localhost")
62
+ service.canonicalize_message("http://localhost/queue?comp=list").should == "/mock-account/queue?comp=list"
63
+ end
64
+
65
+ it "should ignore every other querystring parameter rather than comp=" do
66
+ service = WAZ::Queues::Service.new(:account_name => "mock-account", :access_key => "mock-key", :type_of_service => "queue", :use_ssl => true, :base_url => "localhost")
67
+ service.canonicalize_message("http://localhost/queue?myparam=1").should == "/mock-account/queue"
68
+ end
69
+
70
+ it "should properly canonicalize message when no parameter associated with it" do
71
+ service = WAZ::Queues::Service.new(:account_name => "mock-account", :access_key => "mock-key", :type_of_service => "queue", :use_ssl => true, :base_url => "localhost")
72
+ service.canonicalize_message("http://mock-account.queue.core.windows.net/").should == "/mock-account/"
73
+ end
74
+
75
+ it "should properly canonicalize message when a resource is associated with it" do
76
+ service = WAZ::Queues::Service.new(:account_name => "mock-account", :access_key => "mock-key", :type_of_service => "queue", :use_ssl => true, :base_url => "localhost")
77
+ service.canonicalize_message("http://mock-account.queue.core.windows.net/resource?comp=list").should == "/mock-account/resource?comp=list"
78
+ end
79
+
80
+ it "should generate request with proper headers" do
81
+ mock_time = Time.new
82
+ Time.stubs(:new).returns(mock_time)
83
+ service = WAZ::Queues::Service.new(:account_name => "mock-account", :access_key => "mock-key", :type_of_service => "queue", :use_ssl => true, :base_url => "localhost")
84
+
85
+ expected_request_hash = {:headers => {'x-ms-Date' => mock_time.httpdate, "Content-Length" => "payload".length},
86
+ :method => :put,
87
+ :url => "http://localhost/johnny",
88
+ :payload => "payload"}
89
+
90
+ # mock the generate signature method since we want to assert against a know value
91
+ service.expects(:generate_signature).with(expected_request_hash).returns("a_mock_signature")
92
+
93
+ request = service.generate_request("PUT", "http://localhost/johnny", nil, "payload")
94
+ request.headers["x-ms-Date"].should == mock_time.httpdate
95
+ request.headers["Content-Length"].should == "payload".length
96
+ request.headers["Authorization"] = "SharedKey mock-account:a_mock_signature"
97
+ end
98
+
99
+ it "should set content length when it is not provided" do
100
+ mock_time = Time.new
101
+ Time.stubs(:new).returns(mock_time)
102
+ service = WAZ::Queues::Service.new(:account_name => "mock-account", :access_key => "mock-key", :type_of_service => "queue", :use_ssl => true, :base_url => "localhost")
103
+
104
+ expected_request_hash = {:headers => {'x-ms-Date' => mock_time.httpdate, 'Content-Length' => 0},
105
+ :method => :put,
106
+ :url => "http://localhost/johnny",
107
+ :payload => nil}
108
+
109
+ # mock the generate signature method since we want to assert against a know value
110
+ service.expects(:generate_signature).with(expected_request_hash).returns("a_mock_signature")
111
+
112
+ request = service.generate_request("PUT", "http://localhost/johnny", nil)
113
+ request.headers["x-ms-Date"].should == mock_time.httpdate
114
+ request.headers["Content-Length"].should == 0
115
+ request.headers["Authorization"] = "SharedKey mock-account:a_mock_signature"
116
+ end
117
+
118
+ it "should name headers properly when they are provided as symbols" do
119
+ mock_time = Time.new
120
+ Time.stubs(:new).returns(mock_time)
121
+ service = WAZ::Queues::Service.new(:account_name => "mock-account", :access_key => "mock-key", :type_of_service => "queue", :use_ssl => true, :base_url => "localhost")
122
+
123
+ expected_request_hash = {:headers => {'x-ms-Date' => mock_time.httpdate, "Content-Length" => 0, 'Content-Type' => "plain/xml"},
124
+ :method => :put,
125
+ :url => "http://localhost/johnny",
126
+ :payload => nil}
127
+
128
+ # mock the generate signature method since we want to assert against a know value
129
+ service.expects(:generate_signature).with(expected_request_hash).returns("a_mock_signature")
130
+
131
+ request = service.generate_request("PUT", "http://localhost/johnny", {:Content_Type => "plain/xml"})
132
+ request.headers["x-ms-Date"].should == mock_time.httpdate
133
+ request.headers["Content-Length"].should == 0
134
+ request.headers["Authorization"] = "SharedKey mock-account:a_mock_signature"
135
+ end
136
+
137
+ it "should cannonicalize message by appending account_name to the request path following 2009-09-19 version of the API" do
138
+ service = WAZ::Queues::Service.new(:account_name => "myaccount", :access_key => "mock-key", :type_of_service => "queue", :use_ssl => true, :base_url => "localhost")
139
+ canonical_message = service.canonicalize_message20090919("http://myaccount.blob.core.windows.net/mycontainer?restype=container&comp=metadata")
140
+ canonical_message.should == "/myaccount/mycontainer\ncomp:metadata\nrestype:container"
141
+ end
142
142
  end
@@ -1,614 +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
1
+ # enabling the load of files from root (on RSpec)
2
+ $LOAD_PATH.unshift(File.dirname(__FILE__) + '/../')
3
+ require 'spec/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
614
  end