ripple 0.5.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 (75) hide show
  1. data/.document +5 -0
  2. data/.gitignore +26 -0
  3. data/LICENSE +13 -0
  4. data/README.textile +126 -0
  5. data/RELEASE_NOTES.textile +24 -0
  6. data/Rakefile +61 -0
  7. data/VERSION +1 -0
  8. data/lib/riak.rb +45 -0
  9. data/lib/riak/bucket.rb +105 -0
  10. data/lib/riak/client.rb +138 -0
  11. data/lib/riak/client/curb_backend.rb +63 -0
  12. data/lib/riak/client/http_backend.rb +209 -0
  13. data/lib/riak/client/net_http_backend.rb +49 -0
  14. data/lib/riak/failed_request.rb +37 -0
  15. data/lib/riak/i18n.rb +15 -0
  16. data/lib/riak/invalid_response.rb +25 -0
  17. data/lib/riak/link.rb +54 -0
  18. data/lib/riak/locale/en.yml +37 -0
  19. data/lib/riak/map_reduce.rb +240 -0
  20. data/lib/riak/map_reduce_error.rb +20 -0
  21. data/lib/riak/robject.rb +234 -0
  22. data/lib/riak/util/headers.rb +44 -0
  23. data/lib/riak/util/multipart.rb +52 -0
  24. data/lib/riak/util/translation.rb +29 -0
  25. data/lib/riak/walk_spec.rb +113 -0
  26. data/lib/ripple.rb +48 -0
  27. data/lib/ripple/core_ext/casting.rb +96 -0
  28. data/lib/ripple/document.rb +60 -0
  29. data/lib/ripple/document/attribute_methods.rb +111 -0
  30. data/lib/ripple/document/attribute_methods/dirty.rb +52 -0
  31. data/lib/ripple/document/attribute_methods/query.rb +49 -0
  32. data/lib/ripple/document/attribute_methods/read.rb +38 -0
  33. data/lib/ripple/document/attribute_methods/write.rb +36 -0
  34. data/lib/ripple/document/bucket_access.rb +38 -0
  35. data/lib/ripple/document/finders.rb +84 -0
  36. data/lib/ripple/document/persistence.rb +93 -0
  37. data/lib/ripple/document/persistence/callbacks.rb +48 -0
  38. data/lib/ripple/document/properties.rb +85 -0
  39. data/lib/ripple/document/validations.rb +44 -0
  40. data/lib/ripple/embedded_document.rb +38 -0
  41. data/lib/ripple/embedded_document/persistence.rb +46 -0
  42. data/lib/ripple/i18n.rb +15 -0
  43. data/lib/ripple/locale/en.yml +16 -0
  44. data/lib/ripple/property_type_mismatch.rb +23 -0
  45. data/lib/ripple/translation.rb +24 -0
  46. data/ripple.gemspec +159 -0
  47. data/spec/fixtures/cat.jpg +0 -0
  48. data/spec/fixtures/multipart-blank.txt +7 -0
  49. data/spec/fixtures/multipart-with-body.txt +16 -0
  50. data/spec/riak/bucket_spec.rb +141 -0
  51. data/spec/riak/client_spec.rb +169 -0
  52. data/spec/riak/curb_backend_spec.rb +50 -0
  53. data/spec/riak/headers_spec.rb +34 -0
  54. data/spec/riak/http_backend_spec.rb +136 -0
  55. data/spec/riak/link_spec.rb +50 -0
  56. data/spec/riak/map_reduce_spec.rb +347 -0
  57. data/spec/riak/multipart_spec.rb +36 -0
  58. data/spec/riak/net_http_backend_spec.rb +28 -0
  59. data/spec/riak/object_spec.rb +444 -0
  60. data/spec/riak/walk_spec_spec.rb +208 -0
  61. data/spec/ripple/attribute_methods_spec.rb +149 -0
  62. data/spec/ripple/bucket_access_spec.rb +48 -0
  63. data/spec/ripple/callbacks_spec.rb +86 -0
  64. data/spec/ripple/document_spec.rb +35 -0
  65. data/spec/ripple/embedded_document_spec.rb +52 -0
  66. data/spec/ripple/finders_spec.rb +146 -0
  67. data/spec/ripple/persistence_spec.rb +89 -0
  68. data/spec/ripple/properties_spec.rb +195 -0
  69. data/spec/ripple/ripple_spec.rb +43 -0
  70. data/spec/ripple/validations_spec.rb +64 -0
  71. data/spec/spec.opts +1 -0
  72. data/spec/spec_helper.rb +32 -0
  73. data/spec/support/http_backend_implementation_examples.rb +215 -0
  74. data/spec/support/mock_server.rb +58 -0
  75. metadata +221 -0
@@ -0,0 +1,89 @@
1
+ # Copyright 2010 Sean Cribbs, Sonian Inc., and Basho Technologies, Inc.
2
+ #
3
+ # Licensed under the Apache License, Version 2.0 (the "License");
4
+ # you may not use this file except in compliance with the License.
5
+ # You may obtain a copy of the License at
6
+ #
7
+ # http://www.apache.org/licenses/LICENSE-2.0
8
+ #
9
+ # Unless required by applicable law or agreed to in writing, software
10
+ # distributed under the License is distributed on an "AS IS" BASIS,
11
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ # See the License for the specific language governing permissions and
13
+ # limitations under the License.
14
+ require File.expand_path("../../spec_helper", __FILE__)
15
+
16
+ describe Ripple::Document::Persistence do
17
+ before :all do
18
+ class Widget
19
+ include Ripple::Document
20
+ property :size, Integer
21
+ property :name, String, :default => "widget"
22
+ end
23
+ end
24
+
25
+ before :each do
26
+ @http = mock("HTTP Backend")
27
+ @client = Ripple.client
28
+ @client.stub!(:http).and_return(@http)
29
+ @bucket = Riak::Bucket.new(@client, "widgets")
30
+ @client.stub!(:[]).and_return(@bucket)
31
+ @widget = Widget.new(:size => 1000)
32
+ end
33
+
34
+ it "should save a new object to Riak" do
35
+ json = @widget.attributes.merge("_type" => "Widget").to_json
36
+ @http.should_receive(:post).with(201, "/raw/", "widgets", an_instance_of(Hash), json, hash_including("Content-Type" => "application/json")).and_return(:code => 201, :headers => {'location' => ["/raw/widgets/new_widget"]})
37
+ @widget.save
38
+ @widget.key.should == "new_widget"
39
+ @widget.should_not be_new_record
40
+ @widget.changes.should be_blank
41
+ end
42
+
43
+ it "should reload a saved object" do
44
+ json = @widget.attributes.merge("_type" => "Widget").to_json
45
+ @http.should_receive(:post).with(201, "/raw/", "widgets", an_instance_of(Hash), json, hash_including("Content-Type" => "application/json")).and_return(:code => 201, :headers => {'location' => ["/raw/widgets/new_widget"]})
46
+ @widget.save
47
+ @http.should_receive(:get).and_return(:code => 200, :headers => {'content-type' => ["application/json"]}, :body => '{"name":"spring","size":10}')
48
+ @widget.reload
49
+ @widget.changes.should be_blank
50
+ @widget.name.should == "spring"
51
+ @widget.size.should == 10
52
+ end
53
+
54
+ it "should destroy a saved object" do
55
+ @http.should_receive(:post).and_return(:code => 201, :headers => {'location' => ["/raw/widgets/new_widget"]})
56
+ @widget.save
57
+ @http.should_receive(:delete).and_return(:code => 204, :headers => {})
58
+ @widget.destroy.should be_true
59
+ @widget.should be_frozen
60
+ end
61
+
62
+ it "should freeze an unsaved object when destroying" do
63
+ @http.should_not_receive(:delete)
64
+ @widget.destroy.should be_true
65
+ @widget.should be_frozen
66
+ end
67
+
68
+ describe "when storing a class using single-bucket inheritance" do
69
+ before :all do
70
+ class Cog < Widget; property :name, String, :default => "cog"; end
71
+ @cog = Cog.new(:size => 1000)
72
+ end
73
+
74
+ it "should store the _type field as the class name" do
75
+ json = @cog.attributes.merge("_type" => "Cog").to_json
76
+ @http.should_receive(:post).and_return(:code => 201, :headers => {'location' => ["/raw/widgets/new_widget"]})
77
+ @cog.save
78
+ @cog.should_not be_new_record
79
+ end
80
+
81
+ after :all do
82
+ Object.send(:remove_const, :Cog)
83
+ end
84
+ end
85
+
86
+ after :all do
87
+ Object.send(:remove_const, :Widget)
88
+ end
89
+ end
@@ -0,0 +1,195 @@
1
+ # Copyright 2010 Sean Cribbs, Sonian Inc., and Basho Technologies, Inc.
2
+ #
3
+ # Licensed under the Apache License, Version 2.0 (the "License");
4
+ # you may not use this file except in compliance with the License.
5
+ # You may obtain a copy of the License at
6
+ #
7
+ # http://www.apache.org/licenses/LICENSE-2.0
8
+ #
9
+ # Unless required by applicable law or agreed to in writing, software
10
+ # distributed under the License is distributed on an "AS IS" BASIS,
11
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ # See the License for the specific language governing permissions and
13
+ # limitations under the License.
14
+ require File.expand_path("../../spec_helper", __FILE__)
15
+
16
+ describe Ripple::Document::Properties do
17
+ before :all do
18
+ class Email; include Ripple::Document; end
19
+ end
20
+
21
+ it "should make the model class have a property definition method" do
22
+ Email.should respond_to(:property)
23
+ end
24
+
25
+ it "should add properties to the class via the property method" do
26
+ Email.property :from, String
27
+ Email.properties.should include(:from)
28
+ end
29
+
30
+ it "should make the model class have a collection of properties" do
31
+ Email.should respond_to(:properties)
32
+ Email.properties.should be_kind_of(Hash)
33
+ end
34
+
35
+ it "should make subclasses inherit properties from the parent class" do
36
+ Email.properties[:foo] = "bar"
37
+ class Forward < Email; end
38
+ Forward.properties[:foo].should == "bar"
39
+ end
40
+
41
+
42
+ after :all do
43
+ Object.send(:remove_const, :Email)
44
+ end
45
+ end
46
+
47
+ describe Ripple::Document::Property do
48
+ it "should have a key symbol" do
49
+ prop = Ripple::Document::Property.new('foo', String)
50
+ prop.should respond_to(:key)
51
+ prop.key.should == :foo
52
+ end
53
+
54
+ it "should have a type" do
55
+ prop = Ripple::Document::Property.new('foo', String)
56
+ prop.should respond_to(:type)
57
+ prop.type.should == String
58
+ end
59
+
60
+ it "should capture extra options" do
61
+ prop = Ripple::Document::Property.new('foo', String, 'default' => "bar")
62
+ prop.should respond_to(:options)
63
+ prop.options.should == {:default => "bar"}
64
+ end
65
+
66
+ it "should expose validation options" do
67
+ prop = Ripple::Document::Property.new('foo', String, 'default' => "bar", :presence => true)
68
+ prop.validation_options.should == {:presence => true}
69
+ end
70
+
71
+ describe "default value" do
72
+ it "should be nil when not specified" do
73
+ prop = Ripple::Document::Property.new('foo', String)
74
+ prop.default.should be_nil
75
+ end
76
+
77
+ it "should allow literal values" do
78
+ prop = Ripple::Document::Property.new('foo', String, :default => "bar")
79
+ prop.default.should == "bar"
80
+ end
81
+
82
+ it "should cast to the proper type" do
83
+ prop = Ripple::Document::Property.new('foo', String, :default => :bar)
84
+ prop.default.should == "bar"
85
+ end
86
+
87
+ it "should allow lambdas for deferred evaluation" do
88
+ prop = Ripple::Document::Property.new('foo', String, :default => lambda { "bar" })
89
+ prop.default.should == "bar"
90
+ end
91
+ end
92
+
93
+ describe "casting a value" do
94
+ describe "when type is Boolean" do
95
+ before :each do
96
+ @prop = Ripple::Document::Property.new('foo', Boolean)
97
+ end
98
+
99
+ [0, 0.0, "", [], false, "f", "FALSE"].each do |v|
100
+ it "should cast #{v.inspect} to false" do
101
+ @prop.type_cast(v).should == false
102
+ end
103
+ end
104
+
105
+ [1, 1.0, "true", "1", [1], true, "t", "TRUE"].each do |v|
106
+ it "should cast #{v.inspect} to true" do
107
+ @prop.type_cast(v).should == true
108
+ end
109
+ end
110
+
111
+ it "should not cast nil" do
112
+ @prop.type_cast(nil).should be_nil
113
+ end
114
+ end
115
+
116
+ describe "when type is String" do
117
+ before :each do
118
+ @prop = Ripple::Document::Property.new('foo', String)
119
+ end
120
+
121
+ it "should cast anything to a string using to_s" do
122
+ @prop.type_cast("s").should == "s"
123
+ @prop.type_cast(1).should == "1"
124
+ @prop.type_cast(true).should == "true"
125
+ @prop.type_cast([]).should == ""
126
+ end
127
+ end
128
+
129
+ describe "when type is an Integer type" do
130
+ before :each do
131
+ @prop = Ripple::Document::Property.new(:foo, Integer)
132
+ end
133
+
134
+ [5.0, "5", " 5", "05", Rational(10,2)].each do |v|
135
+ it "should cast #{v.inspect} to 5" do
136
+ @prop.type_cast(v).should == 5
137
+ end
138
+ end
139
+
140
+ [0.0, "0", " 000", ""].each do |v|
141
+ it "should cast #{v.inspect} to 0" do
142
+ @prop.type_cast(v).should == 0
143
+ end
144
+ end
145
+
146
+ [true, false, [], ["something else"]].each do |v|
147
+ it "should raise an error casting #{v.inspect}" do
148
+ lambda { @prop.type_cast(v) }.should raise_error(Ripple::PropertyTypeMismatch)
149
+ end
150
+ end
151
+ end
152
+
153
+ describe "when type is a Float type" do
154
+ before :each do
155
+ @prop = Ripple::Document::Property.new(:foo, Float)
156
+ end
157
+
158
+ [0, "0", "0.0", " 0.0", ""].each do |v|
159
+ it "should cast #{v.inspect} to 0.0" do
160
+ @prop.type_cast(v).should == 0.0
161
+ end
162
+ end
163
+
164
+ [5.0, "5", " 5.0", "05", Rational(10,2)].each do |v|
165
+ it "should cast #{v.inspect} to 5.0" do
166
+ @prop.type_cast(v).should == 5.0
167
+ end
168
+ end
169
+
170
+ [true, false, :symbol, [], {}].each do |v|
171
+ it "should raise an error casting #{v.inspect}" do
172
+ lambda { @prop.type_cast(v) }.should raise_error(Ripple::PropertyTypeMismatch)
173
+ end
174
+ end
175
+ end
176
+
177
+ describe "when type is a Numeric type" do
178
+ before :each do
179
+ @prop = Ripple::Document::Property.new(:foo, Numeric)
180
+ end
181
+
182
+ [5.0, "5", " 5.0", "05"].each do |v|
183
+ it "should cast #{v.inspect} to 5" do
184
+ @prop.type_cast(v).should == 5
185
+ end
186
+ end
187
+
188
+ [5.2, "5.2542", " 6.4", "0.5327284"].each do |v|
189
+ it "should cast #{v.inspect} to a float" do
190
+ @prop.type_cast(v).should be_kind_of(Float)
191
+ end
192
+ end
193
+ end
194
+ end
195
+ end
@@ -0,0 +1,43 @@
1
+ # Copyright 2010 Sean Cribbs, Sonian Inc., and Basho Technologies, Inc.
2
+ #
3
+ # Licensed under the Apache License, Version 2.0 (the "License");
4
+ # you may not use this file except in compliance with the License.
5
+ # You may obtain a copy of the License at
6
+ #
7
+ # http://www.apache.org/licenses/LICENSE-2.0
8
+ #
9
+ # Unless required by applicable law or agreed to in writing, software
10
+ # distributed under the License is distributed on an "AS IS" BASIS,
11
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ # See the License for the specific language governing permissions and
13
+ # limitations under the License.
14
+ require File.expand_path("../spec_helper", File.dirname(__FILE__))
15
+
16
+ describe Ripple do
17
+ it "should have a client" do
18
+ Ripple.client.should be_kind_of(Riak::Client)
19
+ end
20
+
21
+ it "should have a unique client per thread" do
22
+ client = Ripple.client
23
+ th = Thread.new { Ripple.client.should_not == client }
24
+ th.join
25
+ end
26
+
27
+ it "should be configurable" do
28
+ Ripple.should respond_to(:config)
29
+ end
30
+
31
+ it "should allow setting the client manually" do
32
+ Ripple.should respond_to(:client=)
33
+ client = Riak::Client.new(:port => 9000)
34
+ Ripple.client = client
35
+ Ripple.client.should == client
36
+ end
37
+
38
+ it "should reset the client when the configuration changes" do
39
+ c = Ripple.client
40
+ Ripple.config = {:port => 9000}
41
+ Ripple.client.should_not == c
42
+ end
43
+ end
@@ -0,0 +1,64 @@
1
+ # Copyright 2010 Sean Cribbs, Sonian Inc., and Basho Technologies, Inc.
2
+ #
3
+ # Licensed under the Apache License, Version 2.0 (the "License");
4
+ # you may not use this file except in compliance with the License.
5
+ # You may obtain a copy of the License at
6
+ #
7
+ # http://www.apache.org/licenses/LICENSE-2.0
8
+ #
9
+ # Unless required by applicable law or agreed to in writing, software
10
+ # distributed under the License is distributed on an "AS IS" BASIS,
11
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ # See the License for the specific language governing permissions and
13
+ # limitations under the License.
14
+ require File.expand_path("../../spec_helper", __FILE__)
15
+
16
+ describe Ripple::Document::Validations do
17
+ before :all do
18
+ class Box; include Ripple::Document; property :shape, String end
19
+ end
20
+
21
+ before :each do
22
+ @box = Box.new
23
+ end
24
+
25
+ it "should add validation declarations to the class" do
26
+ [:validates, :validate, :validates_with, :validates_each,
27
+ :validates_acceptance_of, :validates_confirmation_of, :validates_exclusion_of,
28
+ :validates_format_of, :validates_inclusion_of, :validates_length_of,
29
+ :validates_numericality_of, :validates_presence_of].each do |meth|
30
+ Box.should respond_to(meth)
31
+ end
32
+ end
33
+
34
+ it "should add validation methods to the instance" do
35
+ %w{errors valid? invalid?}.each do |meth|
36
+ @box.should respond_to(meth)
37
+ end
38
+ end
39
+
40
+ it "should override save to run validations" do
41
+ @box.should_receive(:valid?).and_return(false)
42
+ @box.save.should be_false
43
+ end
44
+
45
+ it "should automatically add validations from property options" do
46
+ Box.property :size, Integer, :inclusion => {:in => 1..30 }
47
+ @box.size = 0
48
+ @box.should_not be_valid
49
+ Box.properties.delete :size
50
+ end
51
+
52
+ it "should run validations at the correct lifecycle state" do
53
+ pending "@_on_validate seems not to work?!"
54
+ Box.property :size, Integer
55
+ Box.validates_inclusion_of :size, :in => 1..30, :on => :update
56
+ @box.size = 0
57
+ @box.should be_valid
58
+ Box.properties.delete :size
59
+ end
60
+
61
+ after :all do
62
+ Object.send(:remove_const, :Box)
63
+ end
64
+ end
@@ -0,0 +1 @@
1
+ --color
@@ -0,0 +1,32 @@
1
+ # Copyright 2010 Sean Cribbs, Sonian Inc., and Basho Technologies, Inc.
2
+ #
3
+ # Licensed under the Apache License, Version 2.0 (the "License");
4
+ # you may not use this file except in compliance with the License.
5
+ # You may obtain a copy of the License at
6
+ #
7
+ # http://www.apache.org/licenses/LICENSE-2.0
8
+ #
9
+ # Unless required by applicable law or agreed to in writing, software
10
+ # distributed under the License is distributed on an "AS IS" BASIS,
11
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ # See the License for the specific language governing permissions and
13
+ # limitations under the License.
14
+ $LOAD_PATH.unshift(File.dirname(__FILE__))
15
+ $LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
16
+
17
+ require 'rubygems' # Use the gems path only for the spec suite
18
+ require 'ripple'
19
+ require 'spec'
20
+ require 'spec/autorun'
21
+ require 'fakeweb'
22
+
23
+ Dir[File.join(File.dirname(__FILE__), "support", "*.rb")].each {|f| require f }
24
+
25
+ $server = MockServer.new
26
+ at_exit { $server.stop }
27
+
28
+ Spec::Runner.configure do |config|
29
+ config.before(:each) do
30
+ FakeWeb.clean_registry
31
+ end
32
+ end
@@ -0,0 +1,215 @@
1
+ # Copyright 2010 Sean Cribbs, Sonian Inc., and Basho Technologies, Inc.
2
+ #
3
+ # Licensed under the Apache License, Version 2.0 (the "License");
4
+ # you may not use this file except in compliance with the License.
5
+ # You may obtain a copy of the License at
6
+ #
7
+ # http://www.apache.org/licenses/LICENSE-2.0
8
+ #
9
+ # Unless required by applicable law or agreed to in writing, software
10
+ # distributed under the License is distributed on an "AS IS" BASIS,
11
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ # See the License for the specific language governing permissions and
13
+ # limitations under the License.
14
+ shared_examples_for "HTTP backend" do
15
+ describe "HEAD requests" do
16
+ before :each do
17
+ setup_http_mock(:head, @backend.path("/raw/","foo").to_s, :body => "")
18
+ end
19
+
20
+ it "should return only the headers when the request succeeds" do
21
+ response = @backend.head(200, "/raw/","foo")
22
+ response.should_not have_key(:body)
23
+ response[:headers].should be_kind_of(Hash)
24
+ response[:code].should == 200
25
+ end
26
+
27
+ it "should raise a FailedRequest exception when the request fails" do
28
+ lambda { @backend.head(301, "/raw/", "foo") }.should raise_error(Riak::FailedRequest)
29
+ end
30
+
31
+ it "should raise an error if an invalid resource path is given" do
32
+ lambda { @backend.head(200, "/raw/") }.should raise_error(ArgumentError)
33
+ end
34
+
35
+ it "should not raise a FailedRequest if one of the expected response codes matches" do
36
+ lambda { @backend.head([200, 301], "/raw/", "foo") }.should_not raise_error(Riak::FailedRequest)
37
+ end
38
+ end
39
+
40
+ describe "GET requests" do
41
+ before :each do
42
+ setup_http_mock(:get, @backend.path("/raw/","foo").to_s, :body => "Success!")
43
+ end
44
+
45
+ it "should return the response body and headers when the request succeeds" do
46
+ response = @backend.get(200, "/raw/","foo")
47
+ response[:body].should == "Success!"
48
+ response[:headers].should be_kind_of(Hash)
49
+ response[:code].should == 200
50
+ end
51
+
52
+ it "should raise a FailedRequest exception when the request fails" do
53
+ lambda { @backend.get(304, "/raw/","foo") }.should raise_error(Riak::FailedRequest)
54
+ end
55
+
56
+ it "should not raise a FailedRequest if one of the expected response codes matches" do
57
+ lambda { @backend.get([200, 301], "/raw/","foo") }.should_not raise_error(Riak::FailedRequest)
58
+ end
59
+
60
+ it "should yield successive chunks of the response to the given block but not return the entire body" do
61
+ chunks = ""
62
+ response = @backend.get(200, "/raw/","foo") do |chunk|
63
+ chunks << chunk
64
+ end
65
+ chunks.should == "Success!"
66
+ response.should_not have_key(:body)
67
+ response[:headers].should be_kind_of(Hash)
68
+ response[:code].should == 200
69
+ end
70
+
71
+ it "should raise an error if an invalid resource path is given" do
72
+ lambda { @backend.get(200, "/raw/") }.should raise_error(ArgumentError)
73
+ end
74
+ end
75
+
76
+ describe "DELETE requests" do
77
+ before :each do
78
+ setup_http_mock(:delete, @backend.path("/raw/","foo").to_s, :body => "Success!")
79
+ end
80
+
81
+ it "should return the response body and headers when the request succeeds" do
82
+ response = @backend.delete(200, "/raw/","foo")
83
+ response[:body].should == "Success!"
84
+ response[:headers].should be_kind_of(Hash)
85
+ end
86
+
87
+ it "should raise a FailedRequest exception when the request fails" do
88
+ lambda { @backend.delete(304, "/raw/","foo") }.should raise_error(Riak::FailedRequest)
89
+ end
90
+
91
+ it "should not raise a FailedRequest if one of the expected response codes matches" do
92
+ lambda { @backend.delete([200, 301], "/raw/","foo") }.should_not raise_error(Riak::FailedRequest)
93
+ end
94
+
95
+ it "should yield successive chunks of the response to the given block but not return the entire body" do
96
+ chunks = ""
97
+ response = @backend.delete(200, "/raw/","foo") do |chunk|
98
+ chunks << chunk
99
+ end
100
+ chunks.should == "Success!"
101
+ response.should_not have_key(:body)
102
+ response[:headers].should be_kind_of(Hash)
103
+ response[:code].should == 200
104
+ end
105
+
106
+ it "should raise an error if an invalid resource path is given" do
107
+ lambda { @backend.delete(200, "/raw/") }.should raise_error(ArgumentError)
108
+ end
109
+ end
110
+
111
+ describe "PUT requests" do
112
+ before :each do
113
+ setup_http_mock(:put, @backend.path("/raw/","foo").to_s, :body => "Success!")
114
+ end
115
+
116
+ it "should return the response body, headers, and code when the request succeeds" do
117
+ response = @backend.put(200, "/raw/","foo", "This is the body.")
118
+ response[:body].should == "Success!"
119
+ response[:headers].should be_kind_of(Hash)
120
+ response[:code].should == 200
121
+ end
122
+
123
+ it "should raise a FailedRequest exception when the request fails" do
124
+ lambda { @backend.put(204, "/raw/","foo", "This is the body.") }.should raise_error(Riak::FailedRequest)
125
+ end
126
+
127
+ it "should not raise a FailedRequest if one of the expected response codes matches" do
128
+ lambda { @backend.put([200, 204], "/raw/","foo", "This is the body.") }.should_not raise_error(Riak::FailedRequest)
129
+ end
130
+
131
+
132
+ it "should yield successive chunks of the response to the given block but not return the entire body" do
133
+ chunks = ""
134
+ response = @backend.put(200, "/raw/","foo", "This is the body.") do |chunk|
135
+ chunks << chunk
136
+ end
137
+ chunks.should == "Success!"
138
+ response.should_not have_key(:body)
139
+ response[:headers].should be_kind_of(Hash)
140
+ response[:code].should == 200
141
+ end
142
+
143
+ it "should raise an error if an invalid resource path is given" do
144
+ lambda { @backend.put(200, "/raw/") }.should raise_error(ArgumentError)
145
+ end
146
+
147
+ it "should raise an error if no body data is given" do
148
+ lambda { @backend.put(200, "/raw/","foo") }.should raise_error(ArgumentError)
149
+ end
150
+
151
+ it "should raise an error if the body is not a string" do
152
+ lambda { @backend.put(200, "/raw/","foo", 123) }.should raise_error(ArgumentError)
153
+ end
154
+ end
155
+
156
+ describe "POST requests" do
157
+ before :each do
158
+ setup_http_mock(:post, @backend.path("/raw/","foo").to_s, :body => "Success!")
159
+ end
160
+
161
+ it "should return the response body, headers, and code when the request succeeds" do
162
+ response = @backend.post(200, "/raw/","foo", "This is the body.")
163
+ response[:body].should == "Success!"
164
+ response[:headers].should be_kind_of(Hash)
165
+ response[:code].should == 200
166
+ end
167
+
168
+ it "should raise a FailedRequest exception when the request fails" do
169
+ lambda { @backend.post(204, "/raw/", "foo", "This is the body.") }.should raise_error(Riak::FailedRequest)
170
+ end
171
+
172
+ it "should not raise a FailedRequest if one of the expected response codes matches" do
173
+ lambda { @backend.post([200, 204], "/raw/", "foo", "This is the body.") }.should_not raise_error(Riak::FailedRequest)
174
+ end
175
+
176
+ it "should yield successive chunks of the response to the given block but not return the entire body" do
177
+ chunks = ""
178
+ response = @backend.post(200, "/raw/", "foo", "This is the body.") do |chunk|
179
+ chunks << chunk
180
+ end
181
+ chunks.should == "Success!"
182
+ response.should_not have_key(:body)
183
+ response[:headers].should be_kind_of(Hash)
184
+ response[:code].should == 200
185
+ end
186
+
187
+ it "should raise an error if an invalid resource path is given" do
188
+ lambda { @backend.post(200, "/raw/") }.should raise_error(ArgumentError)
189
+ end
190
+
191
+ it "should raise an error if no body data is given" do
192
+ lambda { @backend.post(200, "/raw/", "foo") }.should raise_error(ArgumentError)
193
+ end
194
+
195
+ it "should raise an error if the body is not a string" do
196
+ lambda { @backend.post(200, "/raw/", "foo", 123) }.should raise_error(ArgumentError)
197
+ end
198
+ end
199
+
200
+ describe "Responses with no body" do
201
+ [204, 205, 304].each do |code|
202
+ [:get, :post, :put, :delete].each do |method|
203
+ it "should not return a body on #{method.to_s.upcase} for #{code}" do
204
+ setup_http_mock(method, @backend.path("/raw/","foo").to_s, :status => code)
205
+ response = if method == :post || method == :put
206
+ @backend.send(method, code,"/raw/","foo", "This is the body")
207
+ else
208
+ @backend.send(method, code, "/raw/", "foo")
209
+ end
210
+ response.should_not have_key(:body)
211
+ end
212
+ end
213
+ end
214
+ end
215
+ end