ripple 0.5.0

Sign up to get free protection for your applications and to get access to all the features.
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