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.
- data/.document +5 -0
- data/.gitignore +26 -0
- data/LICENSE +13 -0
- data/README.textile +126 -0
- data/RELEASE_NOTES.textile +24 -0
- data/Rakefile +61 -0
- data/VERSION +1 -0
- data/lib/riak.rb +45 -0
- data/lib/riak/bucket.rb +105 -0
- data/lib/riak/client.rb +138 -0
- data/lib/riak/client/curb_backend.rb +63 -0
- data/lib/riak/client/http_backend.rb +209 -0
- data/lib/riak/client/net_http_backend.rb +49 -0
- data/lib/riak/failed_request.rb +37 -0
- data/lib/riak/i18n.rb +15 -0
- data/lib/riak/invalid_response.rb +25 -0
- data/lib/riak/link.rb +54 -0
- data/lib/riak/locale/en.yml +37 -0
- data/lib/riak/map_reduce.rb +240 -0
- data/lib/riak/map_reduce_error.rb +20 -0
- data/lib/riak/robject.rb +234 -0
- data/lib/riak/util/headers.rb +44 -0
- data/lib/riak/util/multipart.rb +52 -0
- data/lib/riak/util/translation.rb +29 -0
- data/lib/riak/walk_spec.rb +113 -0
- data/lib/ripple.rb +48 -0
- data/lib/ripple/core_ext/casting.rb +96 -0
- data/lib/ripple/document.rb +60 -0
- data/lib/ripple/document/attribute_methods.rb +111 -0
- data/lib/ripple/document/attribute_methods/dirty.rb +52 -0
- data/lib/ripple/document/attribute_methods/query.rb +49 -0
- data/lib/ripple/document/attribute_methods/read.rb +38 -0
- data/lib/ripple/document/attribute_methods/write.rb +36 -0
- data/lib/ripple/document/bucket_access.rb +38 -0
- data/lib/ripple/document/finders.rb +84 -0
- data/lib/ripple/document/persistence.rb +93 -0
- data/lib/ripple/document/persistence/callbacks.rb +48 -0
- data/lib/ripple/document/properties.rb +85 -0
- data/lib/ripple/document/validations.rb +44 -0
- data/lib/ripple/embedded_document.rb +38 -0
- data/lib/ripple/embedded_document/persistence.rb +46 -0
- data/lib/ripple/i18n.rb +15 -0
- data/lib/ripple/locale/en.yml +16 -0
- data/lib/ripple/property_type_mismatch.rb +23 -0
- data/lib/ripple/translation.rb +24 -0
- data/ripple.gemspec +159 -0
- data/spec/fixtures/cat.jpg +0 -0
- data/spec/fixtures/multipart-blank.txt +7 -0
- data/spec/fixtures/multipart-with-body.txt +16 -0
- data/spec/riak/bucket_spec.rb +141 -0
- data/spec/riak/client_spec.rb +169 -0
- data/spec/riak/curb_backend_spec.rb +50 -0
- data/spec/riak/headers_spec.rb +34 -0
- data/spec/riak/http_backend_spec.rb +136 -0
- data/spec/riak/link_spec.rb +50 -0
- data/spec/riak/map_reduce_spec.rb +347 -0
- data/spec/riak/multipart_spec.rb +36 -0
- data/spec/riak/net_http_backend_spec.rb +28 -0
- data/spec/riak/object_spec.rb +444 -0
- data/spec/riak/walk_spec_spec.rb +208 -0
- data/spec/ripple/attribute_methods_spec.rb +149 -0
- data/spec/ripple/bucket_access_spec.rb +48 -0
- data/spec/ripple/callbacks_spec.rb +86 -0
- data/spec/ripple/document_spec.rb +35 -0
- data/spec/ripple/embedded_document_spec.rb +52 -0
- data/spec/ripple/finders_spec.rb +146 -0
- data/spec/ripple/persistence_spec.rb +89 -0
- data/spec/ripple/properties_spec.rb +195 -0
- data/spec/ripple/ripple_spec.rb +43 -0
- data/spec/ripple/validations_spec.rb +64 -0
- data/spec/spec.opts +1 -0
- data/spec/spec_helper.rb +32 -0
- data/spec/support/http_backend_implementation_examples.rb +215 -0
- data/spec/support/mock_server.rb +58 -0
- 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
|
data/spec/spec.opts
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
--color
|
data/spec/spec_helper.rb
ADDED
@@ -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
|