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
Binary file
|
@@ -0,0 +1,16 @@
|
|
1
|
+
|
2
|
+
--5EiMOjuGavQ2IbXAqsJPLLfJNlA
|
3
|
+
Content-Type: multipart/mixed; boundary=7extjTzvYIKVMVHowUiTn0LfvSs
|
4
|
+
|
5
|
+
--7extjTzvYIKVMVHowUiTn0LfvSs
|
6
|
+
X-Riak-Vclock: a85hYGBgyWDKBVHMr9s3ZzAlMuaxMtyZcPAIH1RYyObHDqiwxIZjcOG1M98chAq3bUQIz7SSFQEKM4FUbwMKZwEA
|
7
|
+
Location: /raw/foo/baz
|
8
|
+
Content-Type: text/plain
|
9
|
+
Link: </raw/foo>; rel="up"
|
10
|
+
Etag: 6JdI51eFrvv5lDwY6un7a2
|
11
|
+
Last-Modified: Sat, 16 Jan 2010 22:13:44 GMT
|
12
|
+
|
13
|
+
SCP sloooow....
|
14
|
+
--7extjTzvYIKVMVHowUiTn0LfvSs--
|
15
|
+
|
16
|
+
--5EiMOjuGavQ2IbXAqsJPLLfJNlA--
|
@@ -0,0 +1,141 @@
|
|
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 Riak::Bucket do
|
17
|
+
before :each do
|
18
|
+
@client = Riak::Client.new
|
19
|
+
@bucket = Riak::Bucket.new(@client, "foo")
|
20
|
+
end
|
21
|
+
|
22
|
+
def do_load(overrides={})
|
23
|
+
@bucket.load({
|
24
|
+
:body => '{"props":{"name":"foo","allow_mult":false,"big_vclock":50,"chash_keyfun":{"mod":"riak_util","fun":"chash_std_keyfun"},"linkfun":{"mod":"jiak_object","fun":"mapreduce_linkfun"},"n_val":3,"old_vclock":86400,"small_vclock":10,"young_vclock":20},"keys":["bar"]}',
|
25
|
+
:headers => {
|
26
|
+
"vary" => ["Accept-Encoding"],
|
27
|
+
"server" => ["MochiWeb/1.1 WebMachine/1.5.1 (hack the charles gibson)"],
|
28
|
+
"link" => ['</raw/foo/bar>; riaktag="contained"'],
|
29
|
+
"date" => ["Tue, 12 Jan 2010 15:30:43 GMT"],
|
30
|
+
"content-type" => ["application/json"],
|
31
|
+
"content-length" => ["257"]
|
32
|
+
}
|
33
|
+
}.merge(overrides))
|
34
|
+
end
|
35
|
+
|
36
|
+
|
37
|
+
describe "when initializing" do
|
38
|
+
it "should require a client and a name" do
|
39
|
+
lambda { Riak::Bucket.new }.should raise_error
|
40
|
+
lambda { Riak::Bucket.new(@client) }.should raise_error
|
41
|
+
lambda { Riak::Bucket.new("foo") }.should raise_error
|
42
|
+
lambda { Riak::Bucket.new("foo", @client) }.should raise_error
|
43
|
+
lambda { Riak::Bucket.new(@client, "foo") }.should_not raise_error
|
44
|
+
end
|
45
|
+
|
46
|
+
it "should set the client and name attributes" do
|
47
|
+
bucket = Riak::Bucket.new(@client, "foo")
|
48
|
+
bucket.client.should == @client
|
49
|
+
bucket.name.should == "foo"
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
describe "when loading data from an HTTP response" do
|
54
|
+
it "should load the bucket properties from the response body" do
|
55
|
+
do_load
|
56
|
+
@bucket.props.should == {"name"=>"foo","allow_mult" => false,"big_vclock" => 50,"chash_keyfun" => {"mod" =>"riak_util","fun"=>"chash_std_keyfun"},"linkfun"=>{"mod"=>"jiak_object","fun"=>"mapreduce_linkfun"},"n_val"=>3,"old_vclock"=>86400,"small_vclock"=>10,"young_vclock"=>20}
|
57
|
+
end
|
58
|
+
|
59
|
+
it "should load the keys from the response body" do
|
60
|
+
do_load
|
61
|
+
@bucket.keys.should == ["bar"]
|
62
|
+
end
|
63
|
+
|
64
|
+
it "should raise an error for a response that is not JSON" do
|
65
|
+
lambda do
|
66
|
+
do_load(:headers => {"content-type" => ["text/plain"]})
|
67
|
+
end.should raise_error(Riak::InvalidResponse)
|
68
|
+
end
|
69
|
+
|
70
|
+
it "should unescape key names" do
|
71
|
+
do_load(:body => '{"keys":["foo", "bar%20baz"]}')
|
72
|
+
@bucket.keys.should == ["foo", "bar baz"]
|
73
|
+
end
|
74
|
+
end
|
75
|
+
|
76
|
+
describe "accessing keys" do
|
77
|
+
before :each do
|
78
|
+
@http = mock("HTTPBackend")
|
79
|
+
@client.stub!(:http).and_return(@http)
|
80
|
+
end
|
81
|
+
|
82
|
+
it "should load the keys if not present" do
|
83
|
+
@http.should_receive(:get).with(200, "/raw/", "foo", {:props => false}, {}).and_return({:headers => {"content-type" => ["application/json"]}, :body => '{"keys":["bar"]}'})
|
84
|
+
@bucket.keys.should == ["bar"]
|
85
|
+
end
|
86
|
+
|
87
|
+
it "should allow reloading of the keys" do
|
88
|
+
@http.should_receive(:get).with(200, "/raw/","foo", {:props => false}, {}).and_return({:headers => {"content-type" => ["application/json"]}, :body => '{"keys":["bar"]}'})
|
89
|
+
do_load # Ensures they're already loaded
|
90
|
+
@bucket.keys(:reload => true).should == ["bar"]
|
91
|
+
end
|
92
|
+
|
93
|
+
it "should allow streaming keys through block" do
|
94
|
+
# pending "Needs support in the raw_http_resource"
|
95
|
+
@http.should_receive(:get).with(200, "/raw/","foo", {:props => false}, {}).and_yield("{}").and_yield('{"keys":[]}').and_yield('{"keys":["bar"]}').and_yield('{"keys":["baz"]}')
|
96
|
+
all_keys = []
|
97
|
+
@bucket.keys do |list|
|
98
|
+
all_keys.concat(list)
|
99
|
+
end
|
100
|
+
all_keys.should == ["bar", "baz"]
|
101
|
+
end
|
102
|
+
|
103
|
+
it "should unescape key names" do
|
104
|
+
@http.should_receive(:get).with(200, "/raw/","foo", {:props => false}, {}).and_return({:headers => {"content-type" => ["application/json"]}, :body => '{"keys":["bar%20baz"]}'})
|
105
|
+
@bucket.keys.should == ["bar baz"]
|
106
|
+
end
|
107
|
+
end
|
108
|
+
|
109
|
+
describe "setting the bucket properties" do
|
110
|
+
before :each do
|
111
|
+
@http = mock("HTTPBackend")
|
112
|
+
@client.stub!(:http).and_return(@http)
|
113
|
+
end
|
114
|
+
|
115
|
+
it "should PUT the new properties to the bucket" do
|
116
|
+
@http.should_receive(:put).with(204, "/raw/","foo", '{"props":{"name":"foo"}}', {"Content-Type" => "application/json"}).and_return({:body => "", :headers => {}})
|
117
|
+
@bucket.props = { :name => "foo" }
|
118
|
+
end
|
119
|
+
|
120
|
+
it "should raise an error if an invalid property is given" do
|
121
|
+
lambda { @bucket.props = "blah" }.should raise_error(ArgumentError)
|
122
|
+
end
|
123
|
+
end
|
124
|
+
|
125
|
+
describe "fetching an object" do
|
126
|
+
before :each do
|
127
|
+
@http = mock("HTTPBackend")
|
128
|
+
@client.stub!(:http).and_return(@http)
|
129
|
+
end
|
130
|
+
|
131
|
+
it "should load the object from the server as a Riak::RObject" do
|
132
|
+
@http.should_receive(:get).with(200, "/raw/","foo", "db", {}, {}).and_return({:headers => {"content-type" => ["application/json"]}, :body => '{"name":"Riak","company":"Basho"}'})
|
133
|
+
@bucket.get("db").should be_kind_of(Riak::RObject)
|
134
|
+
end
|
135
|
+
|
136
|
+
it "should use the given query parameters (for R value, etc)" do
|
137
|
+
@http.should_receive(:get).with(200, "/raw/","foo", "db", {:r => 2}, {}).and_return({:headers => {"content-type" => ["application/json"]}, :body => '{"name":"Riak","company":"Basho"}'})
|
138
|
+
@bucket.get("db", :r => 2).should be_kind_of(Riak::RObject)
|
139
|
+
end
|
140
|
+
end
|
141
|
+
end
|
@@ -0,0 +1,169 @@
|
|
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 Riak::Client do
|
17
|
+
describe "when initializing" do
|
18
|
+
it "should default to the local interface on port 8098" do
|
19
|
+
client = Riak::Client.new
|
20
|
+
client.host.should == "127.0.0.1"
|
21
|
+
client.port.should == 8098
|
22
|
+
end
|
23
|
+
|
24
|
+
it "should accept a host" do
|
25
|
+
client = Riak::Client.new :host => "riak.basho.com"
|
26
|
+
client.host.should == "riak.basho.com"
|
27
|
+
end
|
28
|
+
|
29
|
+
it "should accept a port" do
|
30
|
+
client = Riak::Client.new :port => 9000
|
31
|
+
client.port.should == 9000
|
32
|
+
end
|
33
|
+
|
34
|
+
it "should accept a client ID" do
|
35
|
+
client = Riak::Client.new :client_id => "AAAAAA=="
|
36
|
+
client.client_id.should == "AAAAAA=="
|
37
|
+
end
|
38
|
+
|
39
|
+
it "should turn an integer client ID into a base64-encoded string" do
|
40
|
+
client = Riak::Client.new :client_id => 1
|
41
|
+
client.client_id.should == "AAAAAQ=="
|
42
|
+
end
|
43
|
+
|
44
|
+
it "should create a client ID if not specified" do
|
45
|
+
Riak::Client.new.client_id.should be_kind_of(String)
|
46
|
+
end
|
47
|
+
|
48
|
+
it "should accept a path prefix" do
|
49
|
+
client = Riak::Client.new(:prefix => "/jiak/")
|
50
|
+
client.prefix.should == "/jiak/"
|
51
|
+
end
|
52
|
+
|
53
|
+
it "should default the prefix to /raw/ if not specified" do
|
54
|
+
Riak::Client.new.prefix.should == "/raw/"
|
55
|
+
end
|
56
|
+
|
57
|
+
it "should accept a mapreduce path" do
|
58
|
+
client = Riak::Client.new(:mapred => "/mr")
|
59
|
+
client.mapred.should == "/mr"
|
60
|
+
end
|
61
|
+
|
62
|
+
it "should default the mapreduce path to /mapred if not specified" do
|
63
|
+
Riak::Client.new.mapred.should == "/mapred"
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
67
|
+
describe "reconfiguring" do
|
68
|
+
before :each do
|
69
|
+
@client = Riak::Client.new
|
70
|
+
end
|
71
|
+
|
72
|
+
describe "setting the host" do
|
73
|
+
it "should allow setting the host" do
|
74
|
+
@client.should respond_to(:host=)
|
75
|
+
@client.host = "riak.basho.com"
|
76
|
+
@client.host.should == "riak.basho.com"
|
77
|
+
end
|
78
|
+
|
79
|
+
it "should require the host to be an IP or hostname" do
|
80
|
+
[238472384972, ""].each do |invalid|
|
81
|
+
lambda { @client.host = invalid }.should raise_error(ArgumentError)
|
82
|
+
end
|
83
|
+
["127.0.0.1", "10.0.100.5", "localhost", "otherhost.local", "riak.basho.com"].each do |valid|
|
84
|
+
lambda { @client.host = valid }.should_not raise_error
|
85
|
+
end
|
86
|
+
end
|
87
|
+
end
|
88
|
+
|
89
|
+
describe "setting the port" do
|
90
|
+
it "should allow setting the port" do
|
91
|
+
@client.should respond_to(:port=)
|
92
|
+
@client.port = 9000
|
93
|
+
@client.port.should == 9000
|
94
|
+
end
|
95
|
+
|
96
|
+
it "should require the port to be a valid number" do
|
97
|
+
[-1,65536,"foo"].each do |invalid|
|
98
|
+
lambda { @client.port = invalid }.should raise_error(ArgumentError)
|
99
|
+
end
|
100
|
+
[0,1,65535,8098].each do |valid|
|
101
|
+
lambda { @client.port = valid }.should_not raise_error
|
102
|
+
end
|
103
|
+
end
|
104
|
+
end
|
105
|
+
|
106
|
+
it "should allow setting the prefix (although we prefer the raw interface)" do
|
107
|
+
@client.should respond_to(:prefix=)
|
108
|
+
@client.prefix = "/another-prefix"
|
109
|
+
@client.prefix.should == "/another-prefix"
|
110
|
+
end
|
111
|
+
|
112
|
+
describe "setting the client id" do
|
113
|
+
it "should accept a string unmodified" do
|
114
|
+
@client.client_id = "foo"
|
115
|
+
@client.client_id.should == "foo"
|
116
|
+
end
|
117
|
+
|
118
|
+
it "should base64-encode an integer" do
|
119
|
+
@client.client_id = 1
|
120
|
+
@client.client_id.should == "AAAAAQ=="
|
121
|
+
end
|
122
|
+
|
123
|
+
it "should reject an integer equal to the maximum client id" do
|
124
|
+
lambda { @client.client_id = Riak::Client::MAX_CLIENT_ID }.should raise_error(ArgumentError)
|
125
|
+
end
|
126
|
+
|
127
|
+
it "should reject an integer larger than the maximum client id" do
|
128
|
+
lambda { @client.client_id = Riak::Client::MAX_CLIENT_ID + 1 }.should raise_error(ArgumentError)
|
129
|
+
end
|
130
|
+
end
|
131
|
+
end
|
132
|
+
|
133
|
+
describe "choosing an HTTP backend" do
|
134
|
+
before :each do
|
135
|
+
@client = Riak::Client.new
|
136
|
+
end
|
137
|
+
|
138
|
+
it "should choose the Curb backend if Curb is available" do
|
139
|
+
@client.should_receive(:require).with('curb').and_return(true)
|
140
|
+
@client.http.should be_instance_of(Riak::Client::CurbBackend)
|
141
|
+
end
|
142
|
+
|
143
|
+
it "should choose the Net::HTTP backend if Curb is unavailable" do
|
144
|
+
@client.should_receive(:require).with('curb').and_raise(LoadError)
|
145
|
+
@client.should_receive(:warn).and_return(true)
|
146
|
+
@client.http.should be_instance_of(Riak::Client::NetHTTPBackend)
|
147
|
+
end
|
148
|
+
end
|
149
|
+
|
150
|
+
describe "retrieving a bucket" do
|
151
|
+
before :each do
|
152
|
+
@client = Riak::Client.new
|
153
|
+
@http = mock(Riak::Client::HTTPBackend)
|
154
|
+
@client.stub!(:http).and_return(@http)
|
155
|
+
@payload = {:headers => {"content-type" => ["application/json"]}, :body => "{}"}
|
156
|
+
@http.stub!(:get).and_return(@payload)
|
157
|
+
end
|
158
|
+
|
159
|
+
it "should send a GET request to the bucket name and return a Riak::Bucket" do
|
160
|
+
@http.should_receive(:get).with(200, "/raw/", "foo", {}, {}).and_return(@payload)
|
161
|
+
@client.bucket("foo").should be_kind_of(Riak::Bucket)
|
162
|
+
end
|
163
|
+
|
164
|
+
it "should allow requesting bucket properties without the keys" do
|
165
|
+
@http.should_receive(:get).with(200, "/raw/", "foo", {:keys => false}, {}).and_return(@payload)
|
166
|
+
@client.bucket("foo", :keys => false)
|
167
|
+
end
|
168
|
+
end
|
169
|
+
end
|
@@ -0,0 +1,50 @@
|
|
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
|
+
begin
|
17
|
+
require 'curb'
|
18
|
+
rescue LoadError
|
19
|
+
warn "Skipping CurbBackend specs, curb library not found."
|
20
|
+
else
|
21
|
+
describe Riak::Client::CurbBackend do
|
22
|
+
def setup_http_mock(method, uri, options={})
|
23
|
+
method = method.to_s.upcase
|
24
|
+
uri = URI.parse(uri)
|
25
|
+
path = uri.path || "/"
|
26
|
+
query = uri.query || ""
|
27
|
+
status = options[:status] ? Array(options[:status]).first.to_i : 200
|
28
|
+
body = options[:body] || []
|
29
|
+
headers = options[:headers] || {}
|
30
|
+
headers['Content-Type'] ||= "text/plain"
|
31
|
+
$server.attach do |env|
|
32
|
+
env["REQUEST_METHOD"].should == method
|
33
|
+
env["PATH_INFO"].should == path
|
34
|
+
env["QUERY_STRING"].should == query
|
35
|
+
[status, headers, Array(body)]
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
before :each do
|
40
|
+
@client = Riak::Client.new(:port => 4000) # Point to our mock
|
41
|
+
@backend = Riak::Client::CurbBackend.new(@client)
|
42
|
+
end
|
43
|
+
|
44
|
+
it_should_behave_like "HTTP backend"
|
45
|
+
|
46
|
+
after :each do
|
47
|
+
$server.detach
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
@@ -0,0 +1,34 @@
|
|
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 Riak::Util::Headers do
|
17
|
+
it "should include the Net::HTTPHeader module" do
|
18
|
+
Riak::Util::Headers.included_modules.should include(Net::HTTPHeader)
|
19
|
+
end
|
20
|
+
|
21
|
+
it "should be initially empty" do
|
22
|
+
Riak::Util::Headers.new.to_hash.should == {}
|
23
|
+
end
|
24
|
+
|
25
|
+
it "should parse a header line into the key and value" do
|
26
|
+
Riak::Util::Headers.parse("Content-Type: text/plain\n").should == ["Content-Type", "text/plain"]
|
27
|
+
end
|
28
|
+
|
29
|
+
it "should parse a header line and add it to the collection" do
|
30
|
+
h = Riak::Util::Headers.new
|
31
|
+
h.parse("Content-Type: text/plain\n")
|
32
|
+
h.to_hash.should == {"content-type" => ["text/plain"]}
|
33
|
+
end
|
34
|
+
end
|
@@ -0,0 +1,136 @@
|
|
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 Riak::Client::HTTPBackend do
|
17
|
+
before :each do
|
18
|
+
@client = Riak::Client.new
|
19
|
+
@backend = Riak::Client::HTTPBackend.new(@client)
|
20
|
+
end
|
21
|
+
|
22
|
+
it "should take the Riak::Client when creating" do
|
23
|
+
lambda { Riak::Client::HTTPBackend.new(nil) }.should raise_error(ArgumentError)
|
24
|
+
lambda { Riak::Client::HTTPBackend.new(@client) }.should_not raise_error
|
25
|
+
end
|
26
|
+
|
27
|
+
it "should make the client accessible" do
|
28
|
+
@backend.client.should == @client
|
29
|
+
end
|
30
|
+
|
31
|
+
it "should generate default headers for requests based on the client settings" do
|
32
|
+
@client.client_id = "testing"
|
33
|
+
@backend.default_headers.should == {"X-Riak-ClientId" => "testing", "Accept" => "multipart/mixed, application/json;q=0.7, */*;q=0.5"}
|
34
|
+
end
|
35
|
+
|
36
|
+
it "should generate a root URI based on the client settings" do
|
37
|
+
@backend.root_uri.should be_kind_of(URI)
|
38
|
+
@backend.root_uri.to_s.should == "http://127.0.0.1:8098"
|
39
|
+
end
|
40
|
+
|
41
|
+
it "should compute a URI from a relative resource path" do
|
42
|
+
@backend.path("baz").should be_kind_of(URI)
|
43
|
+
@backend.path("foo").to_s.should == "http://127.0.0.1:8098/foo"
|
44
|
+
@backend.path("foo", "bar").to_s.should == "http://127.0.0.1:8098/foo/bar"
|
45
|
+
@backend.path("/foo/bar").to_s.should == "http://127.0.0.1:8098/foo/bar"
|
46
|
+
end
|
47
|
+
|
48
|
+
it "should escape appropriate characters in a relative resource path" do
|
49
|
+
@backend.path("foo bar").to_s.should == "http://127.0.0.1:8098/foo%20bar"
|
50
|
+
@backend.path("foo", "bar", {"param" => "a string"}).to_s.should == "http://127.0.0.1:8098/foo/bar?param=a+string"
|
51
|
+
end
|
52
|
+
|
53
|
+
it "should compute a URI from a relative resource path with a hash of query parameters" do
|
54
|
+
@backend.path("baz", :r => 2).to_s.should == "http://127.0.0.1:8098/baz?r=2"
|
55
|
+
end
|
56
|
+
|
57
|
+
it "should raise an error if a resource path is too short" do
|
58
|
+
lambda { @backend.verify_path!(["/raw/"]) }.should raise_error(ArgumentError)
|
59
|
+
lambda { @backend.verify_path!(["/raw/", "foo"]) }.should_not raise_error
|
60
|
+
lambda { @backend.verify_path!(["/mapred"]) }.should_not raise_error
|
61
|
+
end
|
62
|
+
|
63
|
+
describe "verify_path_and_body!" do
|
64
|
+
it "should separate the path and body from given arguments" do
|
65
|
+
uri, data = @backend.verify_path_and_body!(["/raw/", "foo", "This is the body."])
|
66
|
+
uri.should == ["/raw/", "foo"]
|
67
|
+
data.should == "This is the body."
|
68
|
+
end
|
69
|
+
|
70
|
+
it "should raise an error if the body is not a string or IO" do
|
71
|
+
lambda { @backend.verify_path_and_body!(["/raw/", "foo", nil]) }.should raise_error(ArgumentError)
|
72
|
+
lambda { @backend.verify_path_and_body!(["/raw/", "foo", File.open("spec/fixtures/cat.jpg")]) }.should_not raise_error(ArgumentError)
|
73
|
+
end
|
74
|
+
|
75
|
+
it "should raise an error if a body is not given" do
|
76
|
+
lambda { @backend.verify_path_and_body!(["/raw/", "foo"])}.should raise_error(ArgumentError)
|
77
|
+
end
|
78
|
+
|
79
|
+
it "should raise an error if a path is not given" do
|
80
|
+
lambda { @backend.verify_path_and_body!(["/raw/"])}.should raise_error(ArgumentError)
|
81
|
+
end
|
82
|
+
end
|
83
|
+
|
84
|
+
describe "detecting valid response codes" do
|
85
|
+
it "should accept strings or integers for either argument" do
|
86
|
+
@backend.should be_valid_response("300", "300")
|
87
|
+
@backend.should be_valid_response(300, "300")
|
88
|
+
@backend.should be_valid_response("300", 300)
|
89
|
+
end
|
90
|
+
|
91
|
+
it "should accept an array of strings or integers for the expected code" do
|
92
|
+
@backend.should be_valid_response([200,304], "200")
|
93
|
+
@backend.should be_valid_response(["200",304], "200")
|
94
|
+
@backend.should be_valid_response([200,"304"], "200")
|
95
|
+
@backend.should be_valid_response(["200","304"], "200")
|
96
|
+
@backend.should be_valid_response([200,304], 200)
|
97
|
+
end
|
98
|
+
|
99
|
+
it "should be false when none of the response codes match" do
|
100
|
+
@backend.should_not be_valid_response(200, 404)
|
101
|
+
@backend.should_not be_valid_response(["200","304"], 404)
|
102
|
+
@backend.should_not be_valid_response([200,304], 404)
|
103
|
+
end
|
104
|
+
end
|
105
|
+
|
106
|
+
describe "detecting whether a body should be returned" do
|
107
|
+
it "should be false when the method is :head" do
|
108
|
+
@backend.should_not be_return_body(:head, 200, false)
|
109
|
+
end
|
110
|
+
|
111
|
+
it "should be false when the response code is 204, 205, or 304" do
|
112
|
+
@backend.should_not be_return_body(:get, 204, false)
|
113
|
+
@backend.should_not be_return_body(:get, 205, false)
|
114
|
+
@backend.should_not be_return_body(:get, 304, false)
|
115
|
+
end
|
116
|
+
|
117
|
+
it "should be false when a streaming block was passed" do
|
118
|
+
@backend.should_not be_return_body(:get, 200, true)
|
119
|
+
end
|
120
|
+
|
121
|
+
it "should be true when the method is not head, a code other than 204, 205, or 304 was given, and there was no streaming block" do
|
122
|
+
[:get, :put, :post, :delete].each do |method|
|
123
|
+
[100,101,200,201,202,203,206,300,301,302,303,305,307,400,401,
|
124
|
+
402,403,404,405,406,407,408,409,410,411,412,413,414,415,416,
|
125
|
+
500,501,502,503,504,505].each do |code|
|
126
|
+
@backend.should be_return_body(method, code, false)
|
127
|
+
@backend.should be_return_body(method, code.to_s, false)
|
128
|
+
end
|
129
|
+
end
|
130
|
+
end
|
131
|
+
end
|
132
|
+
|
133
|
+
it "should force subclasses to implement the perform method" do
|
134
|
+
lambda { @backend.send(:perform, :get, "/foo", {}, 200) }.should raise_error(NotImplementedError)
|
135
|
+
end
|
136
|
+
end
|