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