riak-client 0.9.8 → 1.0.0.beta
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +32 -0
- data/Gemfile +17 -11
- data/Guardfile +14 -0
- data/Rakefile +18 -44
- data/erl_src/riak_kv_test_backend.beam +0 -0
- data/erl_src/riak_kv_test_backend.erl +461 -128
- data/erl_src/riak_search_test_backend.beam +0 -0
- data/erl_src/riak_search_test_backend.erl +175 -0
- data/lib/active_support/cache/riak_store.rb +0 -13
- data/lib/riak.rb +11 -16
- data/lib/riak/bucket.rb +59 -41
- data/lib/riak/cache_store.rb +1 -14
- data/lib/riak/client.rb +145 -73
- data/lib/riak/client/beefcake/messages.rb +36 -31
- data/lib/riak/client/beefcake/object_methods.rb +27 -19
- data/lib/riak/client/beefcake_protobuffs_backend.rb +27 -33
- data/lib/riak/client/excon_backend.rb +0 -13
- data/lib/riak/client/http_backend.rb +95 -60
- data/lib/riak/client/http_backend/configuration.rb +144 -19
- data/lib/riak/client/http_backend/key_streamer.rb +1 -14
- data/lib/riak/client/http_backend/object_methods.rb +16 -16
- data/lib/riak/client/http_backend/request_headers.rb +0 -13
- data/lib/riak/client/http_backend/transport_methods.rb +26 -56
- data/lib/riak/client/net_http_backend.rb +11 -13
- data/lib/riak/client/protobuffs_backend.rb +21 -19
- data/lib/riak/client/pump.rb +1 -15
- data/lib/riak/client/search.rb +85 -0
- data/lib/riak/cluster.rb +151 -0
- data/lib/riak/core_ext.rb +1 -0
- data/lib/riak/core_ext/deep_dup.rb +13 -0
- data/lib/riak/core_ext/json.rb +15 -0
- data/lib/riak/core_ext/stringify_keys.rb +1 -1
- data/lib/riak/core_ext/symbolize_keys.rb +1 -1
- data/lib/riak/encoding.rb +6 -0
- data/lib/riak/failed_request.rb +2 -15
- data/lib/riak/i18n.rb +0 -13
- data/lib/riak/json.rb +19 -8
- data/lib/riak/link.rb +18 -20
- data/lib/riak/locale/en.yml +13 -16
- data/lib/riak/map_reduce.rb +40 -20
- data/lib/riak/map_reduce/filter_builder.rb +14 -18
- data/lib/riak/map_reduce/phase.rb +0 -13
- data/lib/riak/map_reduce_error.rb +0 -13
- data/lib/riak/node.rb +38 -0
- data/lib/riak/node/configuration.rb +286 -0
- data/lib/riak/node/console.rb +139 -0
- data/lib/riak/node/control.rb +207 -0
- data/lib/riak/node/defaults.rb +70 -0
- data/lib/riak/node/generation.rb +99 -0
- data/lib/riak/node/log.rb +34 -0
- data/lib/riak/node/version.rb +37 -0
- data/lib/riak/robject.rb +45 -41
- data/lib/riak/search.rb +2 -161
- data/lib/riak/serializers.rb +74 -0
- data/lib/riak/stamp.rb +77 -0
- data/lib/riak/test_server.rb +56 -220
- data/lib/riak/util/escape.rb +58 -17
- data/lib/riak/util/headers.rb +2 -15
- data/lib/riak/util/multipart.rb +0 -13
- data/lib/riak/util/multipart/stream_parser.rb +0 -13
- data/lib/riak/util/tcp_socket_extensions.rb +1 -14
- data/lib/riak/util/translation.rb +0 -13
- data/lib/riak/version.rb +3 -0
- data/lib/riak/walk_spec.rb +0 -13
- data/riak-client.gemspec +27 -47
- data/spec/fixtures/multipart-with-marked-tombstones.txt +17 -0
- data/spec/fixtures/multipart-with-unmarked-tombstone.txt +16 -0
- data/spec/integration/riak/cache_store_spec.rb +2 -40
- data/spec/integration/riak/cluster_spec.rb +88 -0
- data/spec/integration/riak/http_backends_spec.rb +6 -30
- data/spec/integration/riak/node_spec.rb +184 -0
- data/spec/integration/riak/protobuffs_backends_spec.rb +2 -26
- data/spec/integration/riak/test_server_spec.rb +31 -167
- data/spec/riak/beefcake_protobuffs_backend_spec.rb +5 -4
- data/spec/riak/bucket_spec.rb +26 -36
- data/spec/riak/client_spec.rb +44 -38
- data/spec/riak/escape_spec.rb +56 -30
- data/spec/riak/excon_backend_spec.rb +4 -17
- data/spec/riak/headers_spec.rb +1 -14
- data/spec/riak/http_backend/configuration_spec.rb +211 -34
- data/spec/riak/http_backend/object_methods_spec.rb +52 -18
- data/spec/riak/http_backend/transport_methods_spec.rb +5 -38
- data/spec/riak/http_backend_spec.rb +84 -78
- data/spec/riak/link_spec.rb +19 -18
- data/spec/riak/map_reduce/filter_builder_spec.rb +1 -14
- data/spec/riak/map_reduce/phase_spec.rb +1 -14
- data/spec/riak/map_reduce_spec.rb +141 -43
- data/spec/riak/multipart_spec.rb +1 -14
- data/spec/riak/net_http_backend_spec.rb +2 -15
- data/spec/riak/robject_spec.rb +129 -97
- data/spec/riak/search_spec.rb +45 -62
- data/spec/riak/serializers_spec.rb +93 -0
- data/spec/riak/stamp_spec.rb +54 -0
- data/spec/riak/stream_parser_spec.rb +3 -16
- data/spec/riak/walk_spec_spec.rb +1 -14
- data/spec/spec_helper.rb +22 -27
- data/spec/support/http_backend_implementation_examples.rb +49 -79
- data/spec/support/integration_setup.rb +10 -0
- data/spec/support/mock_server.rb +0 -14
- data/spec/support/mocks.rb +0 -13
- data/spec/support/test_server.rb +30 -0
- data/spec/support/test_server.yml.example +14 -2
- data/spec/support/unified_backend_examples.rb +36 -27
- metadata +100 -31
- data/lib/riak/client/curb_backend.rb +0 -89
- data/spec/riak/curb_backend_spec.rb +0 -76
@@ -1,23 +1,12 @@
|
|
1
|
-
|
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__))
|
1
|
+
require 'spec_helper'
|
15
2
|
|
16
3
|
describe Riak::Client::HTTPBackend::ObjectMethods do
|
17
4
|
before :each do
|
18
5
|
@client = Riak::Client.new
|
19
6
|
@backend = Riak::Client::HTTPBackend.new(@client)
|
7
|
+
@bucket = Riak::Bucket.new(@client, "bucket")
|
20
8
|
@object = Riak::RObject.new(@bucket, "bar")
|
9
|
+
@backend.stub!(:new_scheme?).and_return(false)
|
21
10
|
end
|
22
11
|
|
23
12
|
describe "loading object data from the response" do
|
@@ -78,6 +67,12 @@ describe Riak::Client::HTTPBackend::ObjectMethods do
|
|
78
67
|
@object.meta["some-kind-of-robot"].should == ["for AWESOME"]
|
79
68
|
end
|
80
69
|
|
70
|
+
it "should load indexes from the headers" do
|
71
|
+
@backend.load_object(@object, {:headers => {"content-type" => ["application/json"], "x-riak-index-email_bin" => ["sean@basho.com"], "x-riak-index-rank_int" => ["50"]}, :body => "{}"})
|
72
|
+
@object.indexes['email_bin'].should include('sean@basho.com')
|
73
|
+
@object.indexes['rank_int'].should include(50)
|
74
|
+
end
|
75
|
+
|
81
76
|
it "should parse the location header into the key when present" do
|
82
77
|
@backend.load_object(@object, {:headers => {"content-type" => ["application/json"], "location" => ["/riak/foo/baz"]}})
|
83
78
|
@object.key.should == "baz"
|
@@ -88,9 +83,20 @@ describe Riak::Client::HTTPBackend::ObjectMethods do
|
|
88
83
|
@object.key.should == "[baz]"
|
89
84
|
end
|
90
85
|
|
91
|
-
|
92
|
-
|
93
|
-
@
|
86
|
+
context "when the response code is 300 and the content-type is multipart/mixed" do
|
87
|
+
let(:http_response) { {:headers => {"content-type" => ["multipart/mixed; boundary=foo"]}, :code => 300 } }
|
88
|
+
let(:other_object) { Riak::RObject.new(@bucket, "bar2") }
|
89
|
+
|
90
|
+
it 'marks the object as in conflict' do
|
91
|
+
@backend.load_object(@object, http_response)
|
92
|
+
@object.should be_conflict
|
93
|
+
end
|
94
|
+
|
95
|
+
it 'attempts to resolve the conflict' do
|
96
|
+
@object.should respond_to(:attempt_conflict_resolution)
|
97
|
+
@object.should_receive(:attempt_conflict_resolution).and_return(other_object)
|
98
|
+
@backend.load_object(@object, http_response).should be(other_object)
|
99
|
+
end
|
94
100
|
end
|
95
101
|
|
96
102
|
it "should unescape the key given in the location header" do
|
@@ -120,7 +126,7 @@ describe Riak::Client::HTTPBackend::ObjectMethods do
|
|
120
126
|
end
|
121
127
|
end
|
122
128
|
|
123
|
-
describe "headers used for storing the object" do
|
129
|
+
describe "headers used for storing the object" do
|
124
130
|
it "should include the content type" do
|
125
131
|
@object.content_type = "application/json"
|
126
132
|
@backend.store_headers(@object)["Content-Type"].should == "application/json"
|
@@ -168,6 +174,15 @@ describe Riak::Client::HTTPBackend::ObjectMethods do
|
|
168
174
|
@backend.store_headers(@object).should have_key("Link")
|
169
175
|
@backend.store_headers(@object)["Link"].should_not include('riaktag="up"')
|
170
176
|
end
|
177
|
+
|
178
|
+
context "when using the new URL scheme" do
|
179
|
+
before { @backend.stub!(:new_scheme?).and_return(true) }
|
180
|
+
|
181
|
+
it "should encode Links using the new format" do
|
182
|
+
@backend.store_headers(@object).should have_key("Link")
|
183
|
+
@backend.store_headers(@object)['Link'].should include('</buckets/foo/keys/baz>; riaktag="next"')
|
184
|
+
end
|
185
|
+
end
|
171
186
|
end
|
172
187
|
|
173
188
|
it "should exclude the Link header when no links are present" do
|
@@ -195,6 +210,25 @@ describe Riak::Client::HTTPBackend::ObjectMethods do
|
|
195
210
|
@backend.store_headers(@object)["X-Riak-Meta-powers"].should == "for awesome"
|
196
211
|
end
|
197
212
|
end
|
213
|
+
|
214
|
+
describe "when indexes are present" do
|
215
|
+
before :each do
|
216
|
+
@object.indexes = {"email_bin" => Set.new(['sean@basho.com', 'seancribbs@gmail.com']), "rank_int" => Set.new([50])}
|
217
|
+
end
|
218
|
+
|
219
|
+
it "should include X-Riak-Index-* headers for each index key" do
|
220
|
+
@backend.store_headers(@object).should have_key('X-Riak-Index-email_bin')
|
221
|
+
@backend.store_headers(@object).should have_key('X-Riak-Index-rank_int')
|
222
|
+
end
|
223
|
+
|
224
|
+
it "should join multi-valued indexes into a single header" do
|
225
|
+
@backend.store_headers(@object)['X-Riak-Index-email_bin'].should == 'sean@basho.com, seancribbs@gmail.com'
|
226
|
+
end
|
227
|
+
|
228
|
+
it "should turn integer indexes into strings in the header" do
|
229
|
+
@backend.store_headers(@object)['X-Riak-Index-rank_int'].should == '50'
|
230
|
+
end
|
231
|
+
end
|
198
232
|
end
|
199
233
|
|
200
234
|
describe "headers used for reloading the object" do
|
@@ -1,17 +1,4 @@
|
|
1
|
-
|
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__))
|
1
|
+
require 'spec_helper'
|
15
2
|
|
16
3
|
describe Riak::Client::HTTPBackend::TransportMethods do
|
17
4
|
before :each do
|
@@ -41,31 +28,11 @@ describe Riak::Client::HTTPBackend::TransportMethods do
|
|
41
28
|
@backend.path("baz", :r => 2).to_s.should == "http://127.0.0.1:8098/baz?r=2"
|
42
29
|
end
|
43
30
|
|
44
|
-
|
45
|
-
lambda { @backend.verify_path!(["/riak/"]) }.should raise_error(ArgumentError)
|
46
|
-
lambda { @backend.verify_path!(["/riak/", "foo"]) }.should_not raise_error
|
47
|
-
lambda { @backend.verify_path!(["/mapred"]) }.should_not raise_error
|
48
|
-
end
|
49
|
-
|
50
|
-
describe "verify_path_and_body!" do
|
51
|
-
it "should separate the path and body from given arguments" do
|
52
|
-
uri, data = @backend.verify_path_and_body!(["/riak/", "foo", "This is the body."])
|
53
|
-
uri.should == ["/riak/", "foo"]
|
54
|
-
data.should == "This is the body."
|
55
|
-
end
|
56
|
-
|
31
|
+
describe "verify_body!" do
|
57
32
|
it "should raise an error if the body is not a string or IO or IO-like (responds to :read)" do
|
58
|
-
lambda { @backend.
|
59
|
-
lambda { @backend.
|
60
|
-
lambda { @backend.
|
61
|
-
end
|
62
|
-
|
63
|
-
it "should raise an error if a body is not given" do
|
64
|
-
lambda { @backend.verify_path_and_body!(["/riak/", "foo"])}.should raise_error(ArgumentError)
|
65
|
-
end
|
66
|
-
|
67
|
-
it "should raise an error if a path is not given" do
|
68
|
-
lambda { @backend.verify_path_and_body!(["/riak/"])}.should raise_error(ArgumentError)
|
33
|
+
lambda { @backend.verify_body!(nil) }.should raise_error(ArgumentError)
|
34
|
+
lambda { @backend.verify_body!(File.open("spec/fixtures/cat.jpg")) }.should_not raise_error(ArgumentError)
|
35
|
+
lambda { @backend.verify_body!(Tempfile.new('riak-spec')) }.should_not raise_error(ArgumentError)
|
69
36
|
end
|
70
37
|
end
|
71
38
|
|
@@ -1,17 +1,4 @@
|
|
1
|
-
|
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__))
|
1
|
+
require 'spec_helper'
|
15
2
|
|
16
3
|
describe Riak::Client::HTTPBackend do
|
17
4
|
before :each do
|
@@ -31,7 +18,7 @@ describe Riak::Client::HTTPBackend do
|
|
31
18
|
|
32
19
|
context "pinging the server" do
|
33
20
|
it "should succeed on 200" do
|
34
|
-
@backend.should_receive(:get).with(200,
|
21
|
+
@backend.should_receive(:get).with(200, @backend.ping_path).and_return({:code => 200, :body => "OK"})
|
35
22
|
@backend.ping.should be_true
|
36
23
|
end
|
37
24
|
|
@@ -43,17 +30,17 @@ describe Riak::Client::HTTPBackend do
|
|
43
30
|
|
44
31
|
context "fetching an object" do
|
45
32
|
it "should perform a GET request and return an RObject" do
|
46
|
-
@backend.should_receive(:get).with([200,300],
|
33
|
+
@backend.should_receive(:get).with([200,300], @backend.object_path('foo', 'db')).and_return({:headers => {"content-type" => ["application/json"]}, :body => '{"name":"Riak","company":"Basho"}'})
|
47
34
|
@backend.fetch_object("foo", "db").should be_kind_of(Riak::RObject)
|
48
35
|
end
|
49
36
|
|
50
37
|
it "should pass the R quorum as a query parameter" do
|
51
|
-
@backend.should_receive(:get).with([200,300], "
|
52
|
-
@backend.fetch_object("foo", "db", 2)
|
38
|
+
@backend.should_receive(:get).with([200,300], @backend.object_path("foo", "db", {:r => 2})).and_return({:headers => {"content-type" => ["application/json"]}, :body => '{"name":"Riak","company":"Basho"}'})
|
39
|
+
@backend.fetch_object("foo", "db", :r => 2)
|
53
40
|
end
|
54
41
|
|
55
42
|
it "should escape the bucket and key names" do
|
56
|
-
@backend.should_receive(:get).with([200,300],
|
43
|
+
@backend.should_receive(:get).with([200,300], @backend.object_path('foo ', ' bar')).and_return({:headers => {"content-type" => ["application/json"]}, :body => '{"name":"Riak","company":"Basho"}'})
|
57
44
|
@backend.fetch_object('foo ',' bar').should be_kind_of(Riak::RObject)
|
58
45
|
end
|
59
46
|
end
|
@@ -65,7 +52,7 @@ describe Riak::Client::HTTPBackend do
|
|
65
52
|
|
66
53
|
it "should use conditional request headers" do
|
67
54
|
@object.etag = "etag"
|
68
|
-
@backend.should_receive(:get).with([200,300,304],
|
55
|
+
@backend.should_receive(:get).with([200,300,304], @backend.object_path('foo', 'bar'), {'If-None-Match' => "etag"}).and_return({:code => 304})
|
69
56
|
@backend.reload_object(@object)
|
70
57
|
end
|
71
58
|
|
@@ -84,7 +71,7 @@ describe Riak::Client::HTTPBackend do
|
|
84
71
|
# @bucket.should_receive(:name).and_return("some/deep/path")
|
85
72
|
@object.bucket = @client.bucket("some/deep/path")
|
86
73
|
@object.key = "another/deep/path"
|
87
|
-
@backend.should_receive(:get).with([200,300,304],
|
74
|
+
@backend.should_receive(:get).with([200,300,304], @backend.object_path(@object.bucket.name, @object.key), {}).and_return({:code => 304})
|
88
75
|
@backend.reload_object(@object)
|
89
76
|
end
|
90
77
|
end
|
@@ -103,26 +90,20 @@ describe Riak::Client::HTTPBackend do
|
|
103
90
|
body = @object.raw_data = "{this is probably invalid json!}}"
|
104
91
|
@backend.stub(:post).and_return({})
|
105
92
|
@object.should_not_receive(:serialize)
|
106
|
-
@backend.store_object(@object, false)
|
93
|
+
@backend.store_object(@object, :returnbody => false)
|
107
94
|
end
|
108
|
-
|
95
|
+
|
109
96
|
context "when the object has no key" do
|
110
97
|
it "should issue a POST request to the bucket, and update the object properties (returning the body by default)" do
|
111
|
-
@backend.should_receive(:post).with(201, "
|
112
|
-
@backend.store_object(@object,
|
98
|
+
@backend.should_receive(:post).with(201, @backend.object_path("foo", nil, {:returnbody => true}), "This is some text.", @headers).and_return({:headers => {'location' => ["/riak/foo/somereallylongstring"], "x-riak-vclock" => ["areallylonghashvalue"]}, :code => 201})
|
99
|
+
@backend.store_object(@object, :returnbody => true)
|
113
100
|
@object.key.should == "somereallylongstring"
|
114
101
|
@object.vclock.should == "areallylonghashvalue"
|
115
102
|
end
|
116
103
|
|
117
104
|
it "should include persistence-tuning parameters in the query string" do
|
118
|
-
@backend.should_receive(:post).with(201, "
|
119
|
-
@backend.store_object(@object, true,
|
120
|
-
end
|
121
|
-
|
122
|
-
it "should escape the bucket name" do
|
123
|
-
@object.bucket = @client.bucket("foo ")
|
124
|
-
@backend.should_receive(:post).with(201, "/riak/", "foo%20", {:returnbody => true}, "This is some text.", @headers).and_return({:headers => {'location' => ["/riak/foo/somereallylongstring"], "x-riak-vclock" => ["areallylonghashvalue"]}, :code => 201})
|
125
|
-
@backend.store_object(@object, true)
|
105
|
+
@backend.should_receive(:post).with(201, @backend.object_path("foo", nil, {:dw => 2, :returnbody => true}), "This is some text.", @headers).and_return({:headers => {'location' => ["/riak/foo/somereallylongstring"], "x-riak-vclock" => ["areallylonghashvalue"]}, :code => 201})
|
106
|
+
@backend.store_object(@object, :returnbody => true, :dw => 2)
|
126
107
|
end
|
127
108
|
end
|
128
109
|
|
@@ -132,88 +113,71 @@ describe Riak::Client::HTTPBackend do
|
|
132
113
|
end
|
133
114
|
|
134
115
|
it "should issue a PUT request to the bucket, and update the object properties (returning the body by default)" do
|
135
|
-
@backend.should_receive(:put).with([200,204,300], "
|
136
|
-
@backend.store_object(@object,
|
116
|
+
@backend.should_receive(:put).with([200,204,300], @backend.object_path("foo", "bar", {:returnbody => true}), "This is some text.", @headers).and_return({:headers => {'location' => ["/riak/foo/somereallylongstring"], "x-riak-vclock" => ["areallylonghashvalue"]}, :code => 204})
|
117
|
+
@backend.store_object(@object, :returnbody => true)
|
137
118
|
@object.key.should == "somereallylongstring"
|
138
119
|
@object.vclock.should == "areallylonghashvalue"
|
139
120
|
end
|
140
|
-
|
141
|
-
it "should include persistence-tuning parameters in the query string" do
|
142
|
-
@backend.should_receive(:put).with([200,204,300], "/riak/", "foo/bar", {:w => 2, :returnbody => true}, "This is some text.", @headers).and_return({:headers => {'location' => ["/riak/foo/somereallylongstring"], "x-riak-vclock" => ["areallylonghashvalue"]}, :code => 204})
|
143
|
-
@backend.store_object(@object, true, 2, nil)
|
144
|
-
end
|
145
121
|
|
146
|
-
it "should
|
147
|
-
@backend.should_receive(:put).with([200,204,300], "
|
148
|
-
@
|
149
|
-
@object.key = "bar/baz"
|
150
|
-
@backend.store_object(@object, true, nil, nil)
|
122
|
+
it "should include persistence-tuning parameters in the query string" do
|
123
|
+
@backend.should_receive(:put).with([200,204,300], @backend.object_path("foo", "bar", {:w => 2, :returnbody => true}), "This is some text.", @headers).and_return({:headers => {'location' => ["/riak/foo/somereallylongstring"], "x-riak-vclock" => ["areallylonghashvalue"]}, :code => 204})
|
124
|
+
@backend.store_object(@object, :returnbody => true, :w => 2)
|
151
125
|
end
|
152
126
|
end
|
153
127
|
end
|
154
128
|
|
155
129
|
context "deleting an object" do
|
156
130
|
it "should perform a DELETE request" do
|
157
|
-
@backend.should_receive(:delete).with([204,404], "
|
131
|
+
@backend.should_receive(:delete).with([204,404], @backend.object_path("foo", 'bar'), {}).and_return(:code => 204)
|
158
132
|
@backend.delete_object("foo", "bar")
|
159
133
|
end
|
160
134
|
|
161
|
-
it "should
|
162
|
-
@backend.should_receive(:delete).with([204,404], "
|
163
|
-
@backend.delete_object(
|
135
|
+
it "should perform a DELETE request with the provided vclock" do
|
136
|
+
@backend.should_receive(:delete).with([204,404], @backend.object_path("foo", 'bar'), {'X-Riak-VClock' => "myvclock"}).and_return(:code => 204)
|
137
|
+
@backend.delete_object('foo', 'bar', :vclock => "myvclock")
|
138
|
+
end
|
139
|
+
|
140
|
+
it "should perform a DELETE request with the requested quorum value" do
|
141
|
+
@backend.should_receive(:delete).with([204,404], @backend.object_path("foo", 'bar', {:rw => 2}), {'X-Riak-VClock' => "myvclock"}).and_return(:code => 204)
|
142
|
+
@backend.delete_object('foo', 'bar', :vclock => "myvclock", :rw => 2)
|
164
143
|
end
|
165
144
|
end
|
166
145
|
|
167
146
|
context "fetching bucket properties" do
|
168
147
|
it "should GET the bucket URL and parse the response as JSON" do
|
169
|
-
@backend.should_receive(:get).with(200,
|
148
|
+
@backend.should_receive(:get).with(200, @backend.bucket_properties_path('foo')).and_return({:body => '{"props":{"n_val":3}}'})
|
170
149
|
@backend.get_bucket_props("foo").should == {"n_val" => 3}
|
171
150
|
end
|
172
|
-
|
173
|
-
it "should escape the bucket name" do
|
174
|
-
@backend.should_receive(:get).with(200, "/riak/", "foo%20bar", {:keys => false, :props => true}, {}).and_return({:body => '{"props":{"n_val":3}}'})
|
175
|
-
@backend.get_bucket_props("foo bar")
|
176
|
-
end
|
177
151
|
end
|
178
|
-
|
152
|
+
|
179
153
|
context "setting bucket properties" do
|
180
154
|
it "should PUT the properties to the bucket URL as JSON" do
|
181
|
-
@backend.should_receive(:put).with(204,
|
182
|
-
@backend.set_bucket_props("foo", {:n_val => 2})
|
183
|
-
end
|
184
|
-
|
185
|
-
it "should escape the bucket name" do
|
186
|
-
@backend.should_receive(:put).with(204, "/riak/","foo%20bar", '{"props":{"n_val":2}}', {"Content-Type" => "application/json"}).and_return({:body => "", :headers => {}})
|
187
|
-
@backend.set_bucket_props("foo bar", {:n_val => 2})
|
155
|
+
@backend.should_receive(:put).with(204, @backend.bucket_properties_path('foo'), '{"props":{"n_val":2}}', {"Content-Type" => "application/json"}).and_return({:body => "", :headers => {}})
|
156
|
+
@backend.set_bucket_props("foo", {:n_val => 2})
|
188
157
|
end
|
189
158
|
end
|
190
|
-
|
159
|
+
|
191
160
|
context "listing keys" do
|
192
161
|
it "should unescape key names" do
|
193
|
-
@backend.should_receive(:get).with(200,
|
162
|
+
@backend.should_receive(:get).with(200, @backend.key_list_path('foo')).and_return({:headers => {"content-type" => ["application/json"]}, :body => '{"keys":["bar%20baz"]}'})
|
194
163
|
@backend.list_keys("foo").should == ["bar baz"]
|
195
164
|
end
|
196
|
-
|
197
|
-
it "should escape the bucket name" do
|
198
|
-
@backend.should_receive(:get).with(200, "/riak/","unescaped%20", {:props => false, :keys => true}, {}).and_return({:headers => {"content-type" => ["application/json"]}, :body => '{"keys":["bar"]}'})
|
199
|
-
@backend.list_keys("unescaped ").should == ["bar"]
|
200
|
-
end
|
201
165
|
end
|
202
166
|
|
203
167
|
context "listing buckets" do
|
204
|
-
it "should GET the
|
205
|
-
@backend.should_receive(:get).with(200,
|
168
|
+
it "should GET the bucket list URL and parse the response as JSON" do
|
169
|
+
@backend.should_receive(:get).with(200, @backend.bucket_list_path).and_return({:body => '{"buckets":["foo", "bar", "baz"]}'})
|
206
170
|
@backend.list_buckets.should == ["foo", "bar", "baz"]
|
207
171
|
end
|
208
172
|
end
|
209
|
-
|
173
|
+
|
210
174
|
context "performing a MapReduce query" do
|
211
175
|
before do
|
212
176
|
@mr = Riak::MapReduce.new(@client).map("Riak.mapValues", :keep => true)
|
213
177
|
end
|
214
178
|
|
215
179
|
it "should issue POST request to the mapred endpoint" do
|
216
|
-
@backend.should_receive(:post).with(200,
|
180
|
+
@backend.should_receive(:post).with(200, @backend.mapred_path, @mr.to_json, hash_including("Content-Type" => "application/json")).and_return({:headers => {'content-type' => ["application/json"]}, :body => "[]"})
|
217
181
|
@backend.mapred(@mr)
|
218
182
|
end
|
219
183
|
|
@@ -230,7 +194,7 @@ describe Riak::Client::HTTPBackend do
|
|
230
194
|
|
231
195
|
it "should stream results through the block" do
|
232
196
|
data = File.read("spec/fixtures/multipart-mapreduce.txt")
|
233
|
-
@backend.should_receive(:post).with(200,
|
197
|
+
@backend.should_receive(:post).with(200, @backend.mapred_path(:chunked => true), @mr.to_json, hash_including("Content-Type" => "application/json")).and_yield(data)
|
234
198
|
block = mock
|
235
199
|
block.should_receive(:ping).twice.and_return(true)
|
236
200
|
@backend.mapred(@mr) do |phase, data|
|
@@ -243,11 +207,11 @@ describe Riak::Client::HTTPBackend do
|
|
243
207
|
|
244
208
|
context "getting statistics" do
|
245
209
|
it "should get the status URL and parse the response as JSON" do
|
246
|
-
@backend.should_receive(:get).with(200,
|
210
|
+
@backend.should_receive(:get).with(200, @backend.stats_path).and_return({:body => '{"vnode_gets":20348}'})
|
247
211
|
@backend.stats.should == {"vnode_gets" => 20348}
|
248
212
|
end
|
249
213
|
end
|
250
|
-
|
214
|
+
|
251
215
|
context "performing a link-walking query" do
|
252
216
|
before do
|
253
217
|
@bucket = Riak::Bucket.new(@client, "foo")
|
@@ -257,7 +221,7 @@ describe Riak::Client::HTTPBackend do
|
|
257
221
|
end
|
258
222
|
|
259
223
|
it "should perform a GET request for the given object and walk specs" do
|
260
|
-
@backend.should_receive(:get).with(200,
|
224
|
+
@backend.should_receive(:get).with(200, @backend.link_walk_path(@bucket.name, @object.key, @specs)).and_return(:headers => {"content-type" => ["multipart/mixed; boundary=12345"]}, :body => "\n--12345\nContent-Type: multipart/mixed; boundary=09876\n\n--09876--\n\n--12345--\n")
|
261
225
|
@backend.link_walk(@object, @specs)
|
262
226
|
end
|
263
227
|
|
@@ -278,5 +242,47 @@ describe Riak::Client::HTTPBackend do
|
|
278
242
|
@client.should_receive(:bucket).with("foo").and_return(@bucket)
|
279
243
|
@backend.link_walk(@object, @specs)
|
280
244
|
end
|
245
|
+
|
246
|
+
it "should discard unmarked tombstones" do
|
247
|
+
@backend.should_receive(:get).and_return(:headers => {"content-type" => ["multipart/mixed; boundary=CvfrSTCWwIiwezy0Zt1B2zwKgS7"]}, :body => File.read(File.expand_path("../../fixtures/multipart-with-unmarked-tombstone.txt", __FILE__)))
|
248
|
+
results = @backend.link_walk(@object, @specs)
|
249
|
+
results.first.should be_empty
|
250
|
+
end
|
251
|
+
|
252
|
+
it "should discard marked tombstones" do
|
253
|
+
@backend.should_receive(:get).and_return(:headers => {"content-type" => ["multipart/mixed; boundary=ADqgQtdmA5iQgyR5UGzX6V3HZtI"]}, :body => File.read(File.expand_path("../../fixtures/multipart-with-marked-tombstones.txt", __FILE__)))
|
254
|
+
results = @backend.link_walk(@object, @specs)
|
255
|
+
results.first.should be_empty
|
256
|
+
end
|
257
|
+
end
|
258
|
+
|
259
|
+
context "performing a search" do
|
260
|
+
before { @backend.send(:server_config)[:riak_solr_searcher_wm] = '/solr' }
|
261
|
+
|
262
|
+
it "should request the searcher resource" do
|
263
|
+
@backend.should_receive(:get).
|
264
|
+
with(200, @backend.solr_select_path(nil, 'foo', {'wt' => 'json'})).
|
265
|
+
and_return(:code => 200, :headers => {"content-type" => ['application/json']}, :body => '{}')
|
266
|
+
@backend.search(nil, 'foo')
|
267
|
+
end
|
268
|
+
|
269
|
+
it "should vivify JSON responses" do
|
270
|
+
@backend.should_receive(:get).and_return({:code => 200, :headers => {"content-type"=>["application/json"]}, :body => '{"response":{"docs":["foo"]}}'})
|
271
|
+
@backend.search(nil, "foo").should == {"response" => {"docs" => ["foo"]}}
|
272
|
+
end
|
273
|
+
|
274
|
+
it "should return non-JSON responses raw" do
|
275
|
+
@backend.should_receive(:get).and_return({:code => 200, :headers => {"content-type"=>["text/plain"]}, :body => '{"response":{"docs":["foo"]}}'})
|
276
|
+
@backend.search(nil, "foo").should == '{"response":{"docs":["foo"]}}'
|
277
|
+
end
|
278
|
+
end
|
279
|
+
|
280
|
+
context "updating a search index" do
|
281
|
+
before { @backend.send(:server_config)[:riak_solr_indexer_wm] = '/solr' }
|
282
|
+
|
283
|
+
it "should request the indexer resource" do
|
284
|
+
@backend.should_receive(:post).with(200, @backend.solr_update_path(nil), 'postbody', {"Content-Type" => "text/xml"})
|
285
|
+
@backend.update_search_index(nil, 'postbody')
|
286
|
+
end
|
281
287
|
end
|
282
288
|
end
|