riak-client 0.9.0.beta → 0.9.0.beta2
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/Gemfile +10 -7
- data/Rakefile +21 -3
- data/erl_src/riak_kv_test_backend.beam +0 -0
- data/erl_src/riak_kv_test_backend.erl +29 -13
- data/lib/riak/bucket.rb +1 -1
- data/lib/riak/cache_store.rb +1 -1
- data/lib/riak/client.rb +119 -8
- data/lib/riak/client/beefcake/messages.rb +162 -0
- data/lib/riak/client/beefcake/object_methods.rb +92 -0
- data/lib/riak/client/beefcake_protobuffs_backend.rb +186 -0
- data/lib/riak/client/curb_backend.rb +10 -16
- data/lib/riak/client/excon_backend.rb +14 -18
- data/lib/riak/client/http_backend.rb +13 -13
- data/lib/riak/client/http_backend/object_methods.rb +1 -1
- data/lib/riak/client/http_backend/transport_methods.rb +6 -2
- data/lib/riak/client/net_http_backend.rb +33 -20
- data/lib/riak/client/protobuffs_backend.rb +103 -0
- data/lib/riak/client/pump.rb +44 -0
- data/lib/riak/failed_request.rb +58 -3
- data/lib/riak/locale/en.yml +11 -3
- data/lib/riak/map_reduce.rb +15 -6
- data/lib/riak/map_reduce/filter_builder.rb +4 -4
- data/lib/riak/test_server.rb +5 -1
- data/lib/riak/util/multipart.rb +30 -16
- data/lib/riak/util/multipart/stream_parser.rb +74 -0
- data/riak-client.gemspec +14 -12
- data/spec/fixtures/server.cert.crt +15 -0
- data/spec/fixtures/server.cert.key +15 -0
- data/spec/fixtures/test.pem +1 -0
- data/spec/integration/riak/http_backends_spec.rb +45 -0
- data/spec/integration/riak/protobuffs_backends_spec.rb +45 -0
- data/spec/integration/riak/test_server_spec.rb +2 -2
- data/spec/riak/bucket_spec.rb +4 -4
- data/spec/riak/client_spec.rb +209 -3
- data/spec/riak/excon_backend_spec.rb +8 -7
- data/spec/riak/http_backend/configuration_spec.rb +64 -0
- data/spec/riak/http_backend/object_methods_spec.rb +1 -1
- data/spec/riak/http_backend/transport_methods_spec.rb +129 -0
- data/spec/riak/http_backend_spec.rb +13 -1
- data/spec/riak/map_reduce/filter_builder_spec.rb +45 -0
- data/spec/riak/map_reduce/phase_spec.rb +149 -0
- data/spec/riak/map_reduce_spec.rb +5 -5
- data/spec/riak/net_http_backend_spec.rb +1 -0
- data/spec/riak/{object_spec.rb → robject_spec.rb} +1 -1
- data/spec/riak/stream_parser_spec.rb +66 -0
- data/spec/support/drb_mock_server.rb +2 -2
- data/spec/support/http_backend_implementation_examples.rb +27 -0
- data/spec/support/mock_server.rb +22 -1
- data/spec/support/unified_backend_examples.rb +255 -0
- metadata +43 -54
@@ -104,7 +104,7 @@ describe Riak::MapReduce do
|
|
104
104
|
|
105
105
|
it "should accept a list of key-filters along with a bucket" do
|
106
106
|
@mr.add("foo", [[:tokenize, "-", 3], [:string_to_int], [:between, 2009, 2010]])
|
107
|
-
@mr.inputs.should == {:bucket => "foo", :
|
107
|
+
@mr.inputs.should == {:bucket => "foo", :key_filters => [[:tokenize, "-", 3], [:string_to_int], [:between, 2009, 2010]]}
|
108
108
|
end
|
109
109
|
|
110
110
|
it "should add a bucket and filter list via a builder block" do
|
@@ -113,7 +113,7 @@ describe Riak::MapReduce do
|
|
113
113
|
string_to_int
|
114
114
|
between 2009, 2010
|
115
115
|
end
|
116
|
-
@mr.inputs.should == {:bucket => "foo", :
|
116
|
+
@mr.inputs.should == {:bucket => "foo", :key_filters => [[:tokenize, "-", 3], [:string_to_int], [:between, 2009, 2010]]}
|
117
117
|
end
|
118
118
|
end
|
119
119
|
|
@@ -250,19 +250,19 @@ describe Riak::MapReduce do
|
|
250
250
|
end
|
251
251
|
|
252
252
|
it "should interpret failed requests with JSON content-types as map reduce errors" do
|
253
|
-
@backend.stub!(:mapred).and_raise(Riak::
|
253
|
+
@backend.stub!(:mapred).and_raise(Riak::HTTPFailedRequest.new(:post, 200, 500, {"content-type" => ["application/json"]}, '{"error":"syntax error"}'))
|
254
254
|
lambda { @mr.run }.should raise_error(Riak::MapReduceError)
|
255
255
|
begin
|
256
256
|
@mr.run
|
257
257
|
rescue Riak::MapReduceError => mre
|
258
|
-
mre.message.should
|
258
|
+
mre.message.should include('{"error":"syntax error"}')
|
259
259
|
else
|
260
260
|
fail "No exception raised!"
|
261
261
|
end
|
262
262
|
end
|
263
263
|
|
264
264
|
it "should re-raise non-JSON error responses" do
|
265
|
-
@backend.stub!(:mapred).and_raise(Riak::
|
265
|
+
@backend.stub!(:mapred).and_raise(Riak::HTTPFailedRequest.new(:post, 200, 500, {"content-type" => ["text/plain"]}, 'Oops, you bwoke it.'))
|
266
266
|
lambda { @mr.run }.should raise_error(Riak::FailedRequest)
|
267
267
|
end
|
268
268
|
end
|
@@ -374,7 +374,7 @@ describe Riak::RObject do
|
|
374
374
|
end
|
375
375
|
|
376
376
|
it "should pass through a failed request exception" do
|
377
|
-
@backend.should_receive(:delete_object).and_raise(Riak::
|
377
|
+
@backend.should_receive(:delete_object).and_raise(Riak::HTTPFailedRequest.new(:delete, [204,404], 500, {}, ""))
|
378
378
|
lambda { @object.delete }.should raise_error(Riak::FailedRequest)
|
379
379
|
end
|
380
380
|
end
|
@@ -0,0 +1,66 @@
|
|
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::Multipart::StreamParser do
|
17
|
+
let(:klass) { Riak::Util::Multipart::StreamParser }
|
18
|
+
let(:block) { mock }
|
19
|
+
it "should detect the initial boundary" do
|
20
|
+
text = "--boundary1\r\nContent-Type: text/plain\r\n\r\nfoo\r\n--boundary1--\r\n"
|
21
|
+
parser = klass.new do |result|
|
22
|
+
result[:headers]['content-type'].should include("text/plain")
|
23
|
+
result[:body].should == "foo"
|
24
|
+
end
|
25
|
+
parser.accept text
|
26
|
+
end
|
27
|
+
|
28
|
+
it "should detect inner multipart bodies" do
|
29
|
+
block.should_receive(:ping).once.and_return(true)
|
30
|
+
parser = klass.new do |result|
|
31
|
+
block.ping
|
32
|
+
result.should have(1).item
|
33
|
+
result.first[:headers]['content-type'].should include("text/plain")
|
34
|
+
result.first[:body].should == "SCP sloooow...."
|
35
|
+
end
|
36
|
+
File.open("spec/fixtures/multipart-with-body.txt", "r") do |f|
|
37
|
+
while chunk = f.read(16)
|
38
|
+
parser.accept chunk
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
it "should yield successive complete chunks to the block" do
|
44
|
+
block.should_receive(:ping).twice.and_return(true)
|
45
|
+
parser = klass.new do |result|
|
46
|
+
block.ping
|
47
|
+
result[:headers]['content-type'].should include("application/json")
|
48
|
+
lambda { JSON.parse(result[:body]) }.should_not raise_error
|
49
|
+
end
|
50
|
+
File.open("spec/fixtures/multipart-mapreduce.txt", "r") do |f|
|
51
|
+
while chunk = f.read(16)
|
52
|
+
parser.accept chunk
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
it "should yield successive complete bodies to the block, even when multiple bodies are accepted in a single chunk" do
|
58
|
+
block.should_receive(:ping).twice.and_return(true)
|
59
|
+
parser = klass.new do |result|
|
60
|
+
block.ping
|
61
|
+
result[:headers]['content-type'].should include("application/json")
|
62
|
+
lambda { JSON.parse(result[:body]) }.should_not raise_error
|
63
|
+
end
|
64
|
+
parser.accept File.read("spec/fixtures/multipart-mapreduce.txt")
|
65
|
+
end
|
66
|
+
end
|
@@ -7,7 +7,7 @@ module DrbMockServer
|
|
7
7
|
def start_client
|
8
8
|
# JRuby doesn't support fork
|
9
9
|
if defined? JRUBY_VERSION
|
10
|
-
@server = MockServer.new
|
10
|
+
@server = MockServer.new(2)
|
11
11
|
at_exit { @server.stop }
|
12
12
|
else
|
13
13
|
child_pid = Process.fork do
|
@@ -17,6 +17,7 @@ module DrbMockServer
|
|
17
17
|
at_exit { Process.kill("HUP", child_pid); Process.wait2 }
|
18
18
|
DRb.start_service
|
19
19
|
@server = DRbObject.new_with_uri(DRBURI)
|
20
|
+
sleep 1
|
20
21
|
end
|
21
22
|
true
|
22
23
|
end
|
@@ -29,7 +30,6 @@ module DrbMockServer
|
|
29
30
|
@server.send(meth, *args, &block)
|
30
31
|
end
|
31
32
|
|
32
|
-
private
|
33
33
|
def start_server
|
34
34
|
server = MockServer.new
|
35
35
|
DRb.start_service(DRBURI, server)
|
@@ -212,4 +212,31 @@ shared_examples_for "HTTP backend" do
|
|
212
212
|
end
|
213
213
|
end
|
214
214
|
end
|
215
|
+
|
216
|
+
describe "SSL" do
|
217
|
+
it "should be supported" do
|
218
|
+
@client.port = $mock_server.port + 1 unless @client.http_backend == :NetHTTP
|
219
|
+
@client.ssl = true
|
220
|
+
setup_http_mock(:get, @backend.path("/riak/","ssl").to_s, :body => "Success!")
|
221
|
+
response = @backend.get(200, "/riak/","ssl")
|
222
|
+
response[:code].should == 200
|
223
|
+
end
|
224
|
+
end
|
225
|
+
|
226
|
+
describe "HTTP Basic Authentication", :basic_auth => true do
|
227
|
+
it "should add the http basic auth header" do
|
228
|
+
@client.basic_auth = "ripple:rocks"
|
229
|
+
if @client.http_backend == :NetHTTP
|
230
|
+
setup_http_mock(:get, "http://ripple:rocks@127.0.0.1:8098/riak/auth", :body => 'Success!')
|
231
|
+
else
|
232
|
+
@_mock_set = "Basic #{Base64::encode64("ripple:rocks").strip}"
|
233
|
+
$mock_server.attach do |env|
|
234
|
+
$mock_server.satisfied = env['HTTP_AUTHORIZATION'] == @_mock_set
|
235
|
+
[200, {}, Array('Success!')]
|
236
|
+
end
|
237
|
+
end
|
238
|
+
response = @backend.get(200, "/riak/", "auth")
|
239
|
+
response[:code].should == 200
|
240
|
+
end
|
241
|
+
end
|
215
242
|
end
|
data/spec/support/mock_server.rb
CHANGED
@@ -16,6 +16,9 @@
|
|
16
16
|
# Based on code from Rob Styles and Chris Tierney found at:
|
17
17
|
# http://dynamicorange.com/2009/02/18/ruby-mock-web-server/
|
18
18
|
require 'rack'
|
19
|
+
require 'openssl'
|
20
|
+
require 'webrick/https'
|
21
|
+
require 'rack/handler/webrick'
|
19
22
|
|
20
23
|
class MockServer
|
21
24
|
attr_accessor :port
|
@@ -25,14 +28,24 @@ class MockServer
|
|
25
28
|
self.port = 4000 + rand(61535)
|
26
29
|
@block = nil
|
27
30
|
@parent_thread = Thread.current
|
31
|
+
options = {:AccessLog => [], :Logger => NullLogger.new, :Host => '127.0.0.1'}
|
28
32
|
@thread = Thread.new do
|
29
|
-
Rack::Handler::WEBrick.run(self, :Port => port
|
33
|
+
Rack::Handler::WEBrick.run(self, options.merge(:Port => port))
|
34
|
+
end
|
35
|
+
@ssl_thread = Thread.new do
|
36
|
+
Rack::Handler::WEBrick.run(self, options.merge(:Port => port+1,
|
37
|
+
:SSLEnable => true,
|
38
|
+
:SSLVerifyClient => OpenSSL::SSL::VERIFY_NONE,
|
39
|
+
:SSLCertificate => read_cert,
|
40
|
+
:SSLPrivateKey => read_pkey,
|
41
|
+
:SSLCertName => [ [ "CN",'127.0.0.1' ] ]))
|
30
42
|
end
|
31
43
|
sleep pause # give the server time to fire up… YUK!
|
32
44
|
end
|
33
45
|
|
34
46
|
def stop
|
35
47
|
Thread.kill(@thread)
|
48
|
+
Thread.kill(@ssl_thread)
|
36
49
|
end
|
37
50
|
|
38
51
|
def expect(status, headers, method, path, query, body)
|
@@ -64,6 +77,14 @@ class MockServer
|
|
64
77
|
end
|
65
78
|
end
|
66
79
|
|
80
|
+
def read_pkey
|
81
|
+
OpenSSL::PKey::RSA.new(File.read(File.expand_path(File.dirname(__FILE__) + '/../fixtures/server.cert.key')), 'ripple')
|
82
|
+
end
|
83
|
+
|
84
|
+
def read_cert
|
85
|
+
OpenSSL::X509::Certificate.new(File.read((File.expand_path(File.dirname(__FILE__) + '/../fixtures/server.cert.crt'))))
|
86
|
+
end
|
87
|
+
|
67
88
|
class NullLogger
|
68
89
|
def fatal(msg) end
|
69
90
|
def error(msg) end
|
@@ -0,0 +1,255 @@
|
|
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
|
+
|
15
|
+
shared_examples_for "Unified backend API" do
|
16
|
+
# ping
|
17
|
+
it "should ping the server" do
|
18
|
+
@backend.ping.should be_true
|
19
|
+
end
|
20
|
+
|
21
|
+
# fetch_object
|
22
|
+
context "fetching an object" do
|
23
|
+
before do
|
24
|
+
@robject = Riak::RObject.new(@client.bucket("test"), "fetch")
|
25
|
+
@robject.content_type = "application/json"
|
26
|
+
@robject.data = { "test" => "pass" }
|
27
|
+
@backend.store_object(@robject)
|
28
|
+
end
|
29
|
+
|
30
|
+
it "should find a stored object" do
|
31
|
+
robj = @backend.fetch_object("test", "fetch")
|
32
|
+
robj.should be_kind_of(Riak::RObject)
|
33
|
+
robj.data.should == { "test" => "pass" }
|
34
|
+
end
|
35
|
+
|
36
|
+
it "should raise an error when the object is not found" do
|
37
|
+
begin
|
38
|
+
@backend.fetch_object("test", "notfound")
|
39
|
+
rescue Riak::FailedRequest => exception
|
40
|
+
@exception = exception
|
41
|
+
end
|
42
|
+
@exception.should be_kind_of(Riak::FailedRequest)
|
43
|
+
@exception.should be_not_found
|
44
|
+
end
|
45
|
+
|
46
|
+
[1,2,3,:one,:quorum,:all,:default].each do |q|
|
47
|
+
it "should accept a R value of #{q.inspect} for the request" do
|
48
|
+
robj = @backend.fetch_object("test", "fetch", q)
|
49
|
+
robj.should be_kind_of(Riak::RObject)
|
50
|
+
robj.data.should == { "test" => "pass" }
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
# reload_object
|
56
|
+
context "reloading an existing object" do
|
57
|
+
before do
|
58
|
+
@robject = Riak::RObject.new(@client.bucket('test'), 'reload')
|
59
|
+
@robject.content_type = "application/json"
|
60
|
+
@robject.data = {"test" => "pass"}
|
61
|
+
@backend.store_object(@robject)
|
62
|
+
@robject2 = @backend.fetch_object("test", "reload")
|
63
|
+
@robject2.data["test"] = "second"
|
64
|
+
@backend.store_object(@robject2, true)
|
65
|
+
end
|
66
|
+
|
67
|
+
it "should modify the object with the reloaded data" do
|
68
|
+
@backend.reload_object(@robject)
|
69
|
+
end
|
70
|
+
|
71
|
+
[1,2,3,:one,:quorum,:all,:default].each do |q|
|
72
|
+
it "should accept a valid R value of #{q.inspect} for the request" do
|
73
|
+
@backend.reload_object(@robject, q)
|
74
|
+
end
|
75
|
+
end
|
76
|
+
|
77
|
+
after do
|
78
|
+
@robject.vclock.should == @robject2.vclock
|
79
|
+
@robject.data['test'].should == "second"
|
80
|
+
end
|
81
|
+
end
|
82
|
+
|
83
|
+
# store_object
|
84
|
+
context "storing an object" do
|
85
|
+
before do
|
86
|
+
@robject = Riak::RObject.new(@client.bucket('test'), 'store')
|
87
|
+
@robject.content_type = "application/json"
|
88
|
+
@robject.data = {"test" => "pass"}
|
89
|
+
end
|
90
|
+
|
91
|
+
it "should save the object" do
|
92
|
+
@backend.store_object(@robject)
|
93
|
+
end
|
94
|
+
|
95
|
+
it "should modify the object with the returned data if returnbody" do
|
96
|
+
@backend.store_object(@robject, true)
|
97
|
+
@robject.vclock.should be_present
|
98
|
+
end
|
99
|
+
|
100
|
+
[1,2,3,:one,:quorum,:all,:default].each do |q|
|
101
|
+
it "should accept a W value of #{q.inspect} for the request" do
|
102
|
+
@backend.store_object(@robject, false, q)
|
103
|
+
@client.bucket("test").exists?("store").should be_true
|
104
|
+
end
|
105
|
+
|
106
|
+
it "should accept a DW value of #{q.inspect} for the request" do
|
107
|
+
@backend.store_object(@robject, false, nil, q)
|
108
|
+
end
|
109
|
+
end
|
110
|
+
|
111
|
+
after do
|
112
|
+
@client.bucket("test").exists?("store").should be_true
|
113
|
+
end
|
114
|
+
end
|
115
|
+
|
116
|
+
# delete_object
|
117
|
+
context "deleting an object" do
|
118
|
+
before do
|
119
|
+
@obj = Riak::RObject.new(@client.bucket("test"), "delete")
|
120
|
+
@obj.content_type = "application/json"
|
121
|
+
@obj.data = [1]
|
122
|
+
@backend.store_object(@obj)
|
123
|
+
end
|
124
|
+
|
125
|
+
it "should remove the object" do
|
126
|
+
@backend.delete_object("test", "delete")
|
127
|
+
@obj.bucket.exists?("delete").should be_false
|
128
|
+
end
|
129
|
+
|
130
|
+
[1,2,3,:one,:quorum,:all,:default].each do |q|
|
131
|
+
it "should accept an RW value of #{q.inspect} for the request" do
|
132
|
+
@backend.delete_object("test", "delete", q)
|
133
|
+
end
|
134
|
+
end
|
135
|
+
|
136
|
+
after do
|
137
|
+
@obj.bucket.exists?("delete").should be_false
|
138
|
+
end
|
139
|
+
end
|
140
|
+
|
141
|
+
# get_bucket_props
|
142
|
+
context "fetching bucket properties" do
|
143
|
+
it "should fetch a hash of bucket properties" do
|
144
|
+
props = @backend.get_bucket_props("test")
|
145
|
+
props.should be_kind_of(Hash)
|
146
|
+
props.should include("n_val")
|
147
|
+
end
|
148
|
+
end
|
149
|
+
|
150
|
+
# set_bucket_props
|
151
|
+
context "setting bucket properties" do
|
152
|
+
it "should store properties for the bucket" do
|
153
|
+
@backend.set_bucket_props("test", {"n_val" => 3})
|
154
|
+
@backend.get_bucket_props("test")["n_val"].should == 3
|
155
|
+
end
|
156
|
+
end
|
157
|
+
|
158
|
+
# list_keys
|
159
|
+
context "listing keys in a bucket" do
|
160
|
+
before do
|
161
|
+
obj = Riak::RObject.new(@client.bucket("test"), "keys")
|
162
|
+
obj.content_type = "application/json"
|
163
|
+
obj.data = [1]
|
164
|
+
@backend.store_object(obj)
|
165
|
+
end
|
166
|
+
|
167
|
+
it "should fetch an array of string keys" do
|
168
|
+
@backend.list_keys("test").should == ["keys"]
|
169
|
+
end
|
170
|
+
|
171
|
+
context "streaming through a block" do
|
172
|
+
it "should pass an array of keys to the block" do
|
173
|
+
@backend.list_keys("test") do |keys|
|
174
|
+
keys.should == ["keys"] unless keys.empty?
|
175
|
+
end
|
176
|
+
end
|
177
|
+
|
178
|
+
it "should allow requests issued inside the block to execute" do
|
179
|
+
errors = []
|
180
|
+
@backend.list_keys("test") do |keys|
|
181
|
+
keys.each do |key|
|
182
|
+
begin
|
183
|
+
@backend.fetch_object("test", key)
|
184
|
+
rescue => e
|
185
|
+
errors << e
|
186
|
+
end
|
187
|
+
end
|
188
|
+
end
|
189
|
+
errors.should be_empty
|
190
|
+
end
|
191
|
+
end
|
192
|
+
end
|
193
|
+
|
194
|
+
# list_buckets
|
195
|
+
context "listing buckets" do
|
196
|
+
before do
|
197
|
+
obj = Riak::RObject.new(@client.bucket("test"), "buckets")
|
198
|
+
obj.content_type = "application/json"
|
199
|
+
obj.data = [1]
|
200
|
+
@backend.store_object(obj)
|
201
|
+
end
|
202
|
+
|
203
|
+
it "should fetch a list of string bucket names" do
|
204
|
+
list = @backend.list_buckets
|
205
|
+
list.should be_kind_of(Array)
|
206
|
+
list.should include("test")
|
207
|
+
end
|
208
|
+
end
|
209
|
+
|
210
|
+
# mapred
|
211
|
+
context "performing MapReduce" do
|
212
|
+
before do
|
213
|
+
obj = Riak::RObject.new(@client.bucket("test"), "1")
|
214
|
+
obj.content_type = "application/json"
|
215
|
+
obj.data = {"value" => "1" }
|
216
|
+
@backend.store_object(obj)
|
217
|
+
@mapred = Riak::MapReduce.new(@client).add("test").map("Riak.mapValuesJson", :keep => true)
|
218
|
+
end
|
219
|
+
|
220
|
+
it "should perform a simple MapReduce request" do
|
221
|
+
@backend.mapred(@mapred).should == [{"value" => "1"}]
|
222
|
+
end
|
223
|
+
|
224
|
+
context "streaming results through a block" do
|
225
|
+
it "should pass phase number and result to the block" do
|
226
|
+
@backend.mapred(@mapred) do |phase, result|
|
227
|
+
unless result.empty?
|
228
|
+
phase.should == 0
|
229
|
+
result.should == [{"value" => "1"}]
|
230
|
+
end
|
231
|
+
end
|
232
|
+
end
|
233
|
+
|
234
|
+
it "should allow requests issued inside the block to execute" do
|
235
|
+
errors = []
|
236
|
+
@backend.mapred(@mapred) do |phase, result|
|
237
|
+
unless result.empty?
|
238
|
+
result.each do |v|
|
239
|
+
begin
|
240
|
+
@backend.fetch_object("test", v['value'])
|
241
|
+
rescue => e
|
242
|
+
errors << e
|
243
|
+
end
|
244
|
+
end
|
245
|
+
end
|
246
|
+
end
|
247
|
+
errors.should be_empty
|
248
|
+
end
|
249
|
+
end
|
250
|
+
end
|
251
|
+
|
252
|
+
after do
|
253
|
+
$test_server.recycle if $test_server.started?
|
254
|
+
end
|
255
|
+
end
|