riak-client 1.0.5 → 1.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (56) hide show
  1. data/.document +5 -0
  2. data/.gitignore +4 -3
  3. data/.rspec +1 -0
  4. data/Gemfile +1 -0
  5. data/RELEASE_NOTES.md +47 -0
  6. data/Rakefile +0 -1
  7. data/erl_src/riak_kv_test_backend.erl +34 -0
  8. data/lib/riak/client.rb +3 -1
  9. data/lib/riak/client/beefcake/messages.rb +49 -1
  10. data/lib/riak/client/beefcake/object_methods.rb +14 -21
  11. data/lib/riak/client/beefcake_protobuffs_backend.rb +58 -12
  12. data/lib/riak/client/decaying.rb +31 -23
  13. data/lib/riak/client/feature_detection.rb +88 -0
  14. data/lib/riak/client/http_backend.rb +27 -6
  15. data/lib/riak/client/http_backend/configuration.rb +13 -0
  16. data/lib/riak/client/http_backend/object_methods.rb +33 -25
  17. data/lib/riak/client/node.rb +7 -2
  18. data/lib/riak/client/protobuffs_backend.rb +54 -3
  19. data/lib/riak/client/search.rb +2 -2
  20. data/lib/riak/conflict.rb +13 -0
  21. data/lib/riak/locale/en.yml +2 -0
  22. data/lib/riak/map_reduce.rb +1 -1
  23. data/lib/riak/map_reduce/filter_builder.rb +2 -2
  24. data/lib/riak/map_reduce/results.rb +49 -0
  25. data/lib/riak/node/console.rb +17 -16
  26. data/lib/riak/node/generation.rb +9 -0
  27. data/lib/riak/rcontent.rb +168 -0
  28. data/lib/riak/robject.rb +37 -157
  29. data/lib/riak/util/escape.rb +5 -1
  30. data/lib/riak/version.rb +1 -1
  31. data/riak-client.gemspec +37 -5
  32. data/spec/fixtures/multipart-basic-conflict.txt +15 -0
  33. data/spec/fixtures/munchausen.txt +1033 -0
  34. data/spec/integration/riak/cluster_spec.rb +1 -1
  35. data/spec/integration/riak/http_backends_spec.rb +23 -2
  36. data/spec/integration/riak/node_spec.rb +2 -2
  37. data/spec/integration/riak/protobuffs_backends_spec.rb +17 -2
  38. data/spec/integration/riak/test_server_spec.rb +1 -1
  39. data/spec/integration/riak/threading_spec.rb +3 -3
  40. data/spec/riak/beefcake_protobuffs_backend_spec.rb +58 -25
  41. data/spec/riak/escape_spec.rb +3 -0
  42. data/spec/riak/feature_detection_spec.rb +61 -0
  43. data/spec/riak/http_backend/object_methods_spec.rb +4 -13
  44. data/spec/riak/http_backend_spec.rb +6 -5
  45. data/spec/riak/map_reduce_spec.rb +0 -5
  46. data/spec/riak/robject_spec.rb +12 -11
  47. data/spec/spec_helper.rb +3 -1
  48. data/spec/support/riak_test.rb +77 -0
  49. data/spec/support/search_corpus_setup.rb +18 -0
  50. data/spec/support/sometimes.rb +1 -1
  51. data/spec/support/test_server.rb +1 -1
  52. data/spec/support/unified_backend_examples.rb +53 -7
  53. data/spec/support/version_filter.rb +4 -11
  54. metadata +56 -22
  55. data/lib/riak/client/pool.rb +0 -180
  56. data/spec/riak/pool_spec.rb +0 -306
@@ -1,7 +1,7 @@
1
1
  require 'spec_helper'
2
2
  require 'riak/cluster'
3
3
 
4
- describe Riak::Cluster, :test_server => false, :slow => true do
4
+ describe Riak::Cluster, :test_server => false, :slow => true, :nodegen => true do
5
5
  let(:config) { YAML.load_file("spec/support/test_server.yml").symbolize_keys }
6
6
  subject { described_class.new(config) }
7
7
 
@@ -2,7 +2,7 @@ require 'spec_helper'
2
2
 
3
3
  describe "HTTP" do
4
4
  before do
5
- @web_port = $test_server.http_port
5
+ @web_port = test_server.http_port
6
6
  @client = Riak::Client.new(:http_port => @web_port)
7
7
  end
8
8
 
@@ -16,7 +16,28 @@ describe "HTTP" do
16
16
 
17
17
  it_should_behave_like "Unified backend API"
18
18
 
19
- describe "using Luwak", :version => "0.14.0".."1.0.3" do
19
+ describe "searching fulltext indexes (1.1 and earlier)", :version => "< 1.2.0" do
20
+ include_context "search corpus setup"
21
+
22
+ it 'should find indexed documents, returning ids' do
23
+ results = @backend.search 'search_test', 'fearless elephant rushed', :fl => 'id'
24
+ results.should have_key 'docs'
25
+ results.should have_key 'max_score'
26
+ results.should have_key 'num_found'
27
+ results['docs'].should include({"id" => "munchausen-605"})
28
+ end
29
+
30
+ it 'should find indexed documents, returning documents' do
31
+ # For now use '*' until #122 is merged into riak_search
32
+ results = @backend.search 'search_test', 'fearless elephant rushed', :fl => '*'
33
+ results.should have_key 'docs'
34
+ results.should have_key 'max_score'
35
+ results.should have_key 'num_found'
36
+ results['docs'].should include({"id" => "munchausen-605", "value" => "Fearless I advanced against the elephant, desirous to take alive the haughty Tippoo Sahib; but he drew a pistol from his belt, and discharged it full in my face as I rushed upon him, which did me no further harm than wound my cheek-bone, which disfigures me somewhat under my left eye. I could not withstand the rage and impulse of that moment, and with one blow of my sword separated his head from his body.\n"})
37
+ end
38
+ end
39
+
40
+ context "using Luwak", :version => "< 1.1.0" do
20
41
  let(:file) { File.open(__FILE__) }
21
42
  let(:key) { "spec.rb" }
22
43
  let(:string) { file.read }
@@ -2,7 +2,7 @@ require 'spec_helper'
2
2
  require 'riak/node'
3
3
  require 'yaml'
4
4
 
5
- describe Riak::Node, :test_server => false, :slow => true do
5
+ describe Riak::Node, :test_server => false, :slow => true, :nodegen => true do
6
6
  let(:test_server_config){ YAML.load_file("spec/support/test_server.yml") }
7
7
  let(:node){ described_class.new(:root => ".ripplenode", :source => test_server_config['source']) }
8
8
  subject { node }
@@ -173,7 +173,7 @@ describe Riak::Node, :test_server => false, :slow => true do
173
173
  expect {
174
174
  console.command "ok."
175
175
  console.close
176
- }.should_not raise_error
176
+ }.to_not raise_error
177
177
  end
178
178
  end
179
179
 
@@ -2,8 +2,9 @@ require 'spec_helper'
2
2
 
3
3
  describe "Protocol Buffers" do
4
4
  before do
5
- @pbc_port ||= $test_server.pb_port
6
- @client = Riak::Client.new(:pb_port => @pbc_port, :protocol => "pbc")
5
+ @pbc_port ||= test_server.pb_port
6
+ @http_port ||= test_server.http_port
7
+ @client = Riak::Client.new(:http_port => @http_port, :pb_port => @pbc_port, :protocol => "pbc")
7
8
  end
8
9
 
9
10
  [:BeefcakeProtobuffsBackend].each do |klass|
@@ -15,6 +16,20 @@ describe "Protocol Buffers" do
15
16
  end
16
17
 
17
18
  it_should_behave_like "Unified backend API"
19
+
20
+ describe "searching fulltext indexes (1.1 and earlier)", :version => '< 1.2.0' do
21
+ include_context "search corpus setup"
22
+
23
+ it 'should find document IDs via MapReduce' do
24
+ # Note that the trailing options Hash is ignored when
25
+ # emulating search with MapReduce
26
+ results = @backend.search 'search_test', 'fearless elephant rushed'
27
+ results.should have_key 'docs'
28
+ results.should have_key 'max_score'
29
+ results.should have_key 'num_found'
30
+ results['docs'].should include({"id" => "munchausen-605"})
31
+ end
32
+ end
18
33
  end
19
34
  end
20
35
  end
@@ -1,7 +1,7 @@
1
1
  require 'spec_helper'
2
2
  require 'riak/test_server'
3
3
 
4
- describe Riak::TestServer do
4
+ describe Riak::TestServer, :nodegen => true do
5
5
  subject { test_server }
6
6
  let(:app_config) { (subject.etc + 'app.config').read }
7
7
 
@@ -61,8 +61,8 @@ describe "Multithreaded client", :test_server => true do
61
61
  ].each do |opts|
62
62
  describe opts.inspect do
63
63
  before do
64
- @pb_port ||= $test_server.pb_port
65
- @http_port ||= $test_server.http_port
64
+ @pb_port ||= test_server.pb_port
65
+ @http_port ||= test_server.http_port
66
66
  @client = Riak::Client.new({
67
67
  :pb_port => @pb_port,
68
68
  :http_port => @http_port
@@ -104,7 +104,7 @@ describe "Multithreaded client", :test_server => true do
104
104
  # This is a 1.0+ spec because putting with the same client ID
105
105
  # will not create siblings on 0.14 in the same way. This will
106
106
  # also likely fail for nodes with vnode_vclocks = false.
107
- it 'should put conflicts in parallel', :version => "1.0.0" do
107
+ it 'should put conflicts in parallel', :version => ">= 1.0.0" do
108
108
  @client['test'].allow_mult = true
109
109
  @client['test'].allow_mult.should == true
110
110
 
@@ -1,19 +1,17 @@
1
1
  require 'spec_helper'
2
- require 'riak/client/beefcake/messages'
3
2
 
4
3
  describe Riak::Client::BeefcakeProtobuffsBackend do
5
- before :each do
6
- @client = Riak::Client.new
7
- @node = @client.nodes.first
8
- @backend = Riak::Client::BeefcakeProtobuffsBackend.new(@client, @node)
9
- @backend.instance_variable_set(:@server_config, {})
10
- end
4
+ before(:all) { described_class.should be_configured }
5
+ before(:each) { backend.stub(:get_server_version => "1.2.0") }
6
+ let(:client) { Riak::Client.new }
7
+ let(:node) { client.nodes.first }
8
+ let(:backend) { Riak::Client::BeefcakeProtobuffsBackend.new(client, node) }
11
9
 
12
10
  it "should only write to the socket one time per request" do
13
11
  exp_bucket, exp_keys = 'foo', ['bar']
14
12
  mock_socket = mock("mock TCP socket")
15
13
 
16
- @backend.stub!(:socket).and_return(mock_socket)
14
+ backend.stub!(:socket).and_return(mock_socket)
17
15
  mock_socket.should_receive(:write).exactly(1).with do |param|
18
16
  len, code = param[0,5].unpack("NC")
19
17
  req = Riak::Client::BeefcakeProtobuffsBackend::RpbListKeysReq.decode(param[5..-1])
@@ -36,27 +34,62 @@ describe Riak::Client::BeefcakeProtobuffsBackend do
36
34
  mock_socket.should_receive(:read).exactly(1).with(encoded_response.length).and_return(encoded_response)
37
35
  end
38
36
 
39
- @backend.list_keys(exp_bucket).should == exp_keys
37
+ backend.list_keys(exp_bucket).should == exp_keys
40
38
  end
41
- end
42
39
 
43
- describe Riak::Client::BeefcakeProtobuffsBackend, '#mapred' do
44
- before(:each) do
45
- @client = Riak::Client.new
46
- @node = @client.nodes.first
47
- @backend = Riak::Client::BeefcakeProtobuffsBackend.new(@client, @node)
48
- @backend.instance_variable_set(:@server_config, {})
40
+ context "#mapred" do
41
+ let(:mapred) { Riak::MapReduce.new(client).add('test').map("function(){}").map("function(){}") }
42
+
43
+ it "should not return nil for previous phases that don't return anything" do
44
+ socket = stub(:socket).as_null_object
45
+ socket.stub(:read).and_return(stub(:socket_header, :unpack => [2, 24]), stub(:socket_message), stub(:socket_header_2, :unpack => [0, 1]))
46
+ message = stub(:message, :phase => 1, :response => [{}].to_json)
47
+ message.stub(:done).and_return(false, true)
48
+ Riak::Client::BeefcakeProtobuffsBackend::RpbMapRedResp.stub(:decode => message)
49
+ TCPSocket.stub(:new => socket)
50
+ backend.send(:reset_socket)
51
+
52
+ backend.mapred(mapred).should == [{}]
53
+ end
49
54
  end
50
55
 
51
- it "should not return nil for previous phases that don't return anything" do
52
- socket = stub(:socket).as_null_object
53
- socket.stub(:read).and_return(stub(:socket_header, :unpack => [2, 24]), stub(:socket_message), stub(:socket_header_2, :unpack => [0, 1]))
54
- message = stub(:message, :phase => 1, :response => [{}].to_json)
55
- message.stub(:done).and_return(false, true)
56
- Riak::Client::BeefcakeProtobuffsBackend::RpbMapRedResp.stub(:decode => message)
57
- TCPSocket.stub(:new => socket)
58
- @backend.send(:reset_socket)
56
+ context "preventing stale writes" do
57
+ before { backend.stub(:decode_response => nil, :get_server_version => "1.0.3") }
59
58
 
60
- @backend.mapred('').should == [{}]
59
+ let(:robject) do
60
+ Riak::RObject.new(client['stale'], 'prevent').tap do |obj|
61
+ obj.prevent_stale_writes = true
62
+ obj.raw_data = "stale"
63
+ obj.content_type = "text/plain"
64
+ end
65
+ end
66
+
67
+ it "should set the if_none_match field when the object is new" do
68
+ backend.should_receive(:write_protobuff) do |msg, req|
69
+ msg.should == :PutReq
70
+ req.if_none_match.should be_true
71
+ end
72
+ backend.store_object(robject)
73
+ end
74
+
75
+ it "should set the if_not_modified field when the object has a vclock" do
76
+ robject.vclock = Base64.encode64("foo")
77
+ backend.should_receive(:write_protobuff) do |msg, req|
78
+ msg.should == :PutReq
79
+ req.if_not_modified.should be_true
80
+ end
81
+ backend.store_object(robject)
82
+ end
83
+
84
+ context "when conditional requests are not supported" do
85
+ before { backend.stub(:get_server_version => "0.14.2") }
86
+ let(:other) { robject.dup.tap {|o| o.vclock = 'bar' } }
87
+
88
+ it "should fetch the original object and raise if not equivalent" do
89
+ robject.vclock = Base64.encode64("foo")
90
+ backend.should_receive(:fetch_object).and_return(other)
91
+ expect { backend.store_object(robject) }.to raise_error(Riak::FailedRequest)
92
+ end
93
+ end
61
94
  end
62
95
  end
@@ -44,6 +44,7 @@ describe Riak::Util::Escape do
44
44
  it "should escape standard non-safe characters" do
45
45
  @object.escape("some string").should == "some%20string"
46
46
  @object.escape("another^one").should == "another%5Eone"
47
+ @object.escape("--one+two--").should == "--one%2Btwo--"
47
48
  end
48
49
 
49
50
  it "should allow URI-safe characters" do
@@ -64,6 +65,8 @@ describe Riak::Util::Escape do
64
65
  @object.unescape("another%5Eone").should == "another^one"
65
66
  @object.unescape("bracket%5Bone").should == "bracket[one"
66
67
  @object.unescape("some%2Finner%2Fpath").should == "some/inner/path"
68
+ @object.unescape("--one%2Btwo--").should == "--one+two--"
69
+ @object.unescape("me%40basho.co").should == "me@basho.co"
67
70
  end
68
71
  end
69
72
  end
@@ -0,0 +1,61 @@
1
+ require 'spec_helper'
2
+ require 'riak/client/feature_detection'
3
+
4
+ describe Riak::Client::FeatureDetection do
5
+ let(:klass) {
6
+ Class.new do
7
+ include Riak::Client::FeatureDetection
8
+ end
9
+ }
10
+ subject { klass.new }
11
+
12
+ context "when the get_server_version is unimplemented" do
13
+ it "should raise a NotImplementedError" do
14
+ expect { subject.server_version }.to raise_error(NotImplementedError)
15
+ end
16
+ end
17
+
18
+ context "when the Riak version is 0.14.x" do
19
+ before { subject.stub!(:get_server_version).and_return("0.14.2") }
20
+ it { should_not be_mapred_phaseless }
21
+ it { should_not be_pb_indexes }
22
+ it { should_not be_pb_search }
23
+ it { should_not be_pb_conditionals }
24
+ it { should_not be_quorum_controls }
25
+ it { should_not be_tombstone_vclocks }
26
+ it { should_not be_pb_head }
27
+ end
28
+
29
+ context "when the Riak version is 1.0.x" do
30
+ before { subject.stub!(:get_server_version).and_return("1.0.3") }
31
+ it { should_not be_mapred_phaseless }
32
+ it { should_not be_pb_indexes }
33
+ it { should_not be_pb_search }
34
+ it { should be_pb_conditionals }
35
+ it { should be_quorum_controls }
36
+ it { should be_tombstone_vclocks }
37
+ it { should be_pb_head }
38
+ end
39
+
40
+ context "when the Riak version is 1.1.x" do
41
+ before { subject.stub!(:get_server_version).and_return("1.1.4") }
42
+ it { should be_mapred_phaseless }
43
+ it { should_not be_pb_indexes }
44
+ it { should_not be_pb_search }
45
+ it { should be_pb_conditionals }
46
+ it { should be_quorum_controls }
47
+ it { should be_tombstone_vclocks }
48
+ it { should be_pb_head }
49
+ end
50
+
51
+ context "when the Riak version is 1.2.x" do
52
+ before { subject.stub!(:get_server_version).and_return("1.2.0") }
53
+ it { should be_mapred_phaseless }
54
+ it { should be_pb_indexes }
55
+ it { should be_pb_search }
56
+ it { should be_pb_conditionals }
57
+ it { should be_quorum_controls }
58
+ it { should be_tombstone_vclocks }
59
+ it { should be_pb_head }
60
+ end
61
+ end
@@ -28,14 +28,13 @@ describe Riak::Client::HTTPBackend::ObjectMethods do
28
28
  end
29
29
 
30
30
  it "should deserialize the body data" do
31
- @object.should_receive(:deserialize).with("{}").and_return({})
32
31
  @backend.load_object(@object, {:headers => {"content-type" => ["application/json"]}, :body => "{}"})
33
32
  @object.data.should == {}
34
33
  end
35
34
 
36
35
  it "should leave the object data unchanged if the response body is blank" do
37
36
  @object.data = "Original data"
38
- @backend.load_object(@object, {:headers => {"content-type" => ["application/json"]}, :body => ""})
37
+ @backend.load_object(@object, {:headers => {"content-type" => ["application/json"]}, :body => "", :code => 304})
39
38
  @object.data.should == "Original data"
40
39
  end
41
40
 
@@ -84,7 +83,7 @@ describe Riak::Client::HTTPBackend::ObjectMethods do
84
83
  end
85
84
 
86
85
  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 } }
86
+ let(:http_response) { {:headers => {"content-type" => ["multipart/mixed; boundary=8XZD3w6ttFTHIz6LCmhVxn9Ex0K"]}, :code => 300, :body => File.read("spec/fixtures/multipart-basic-conflict.txt")} }
88
87
  let(:other_object) { Riak::RObject.new(@bucket, "bar2") }
89
88
 
90
89
  it 'marks the object as in conflict' do
@@ -106,22 +105,14 @@ describe Riak::Client::HTTPBackend::ObjectMethods do
106
105
 
107
106
  describe "extracting siblings" do
108
107
  before :each do
109
- @backend.load_object(@object, {:headers => {"x-riak-vclock" => ["merged"], "content-type" => ["multipart/mixed; boundary=foo"]}, :code => 300, :body => "\n--foo\nContent-Type: text/plain\n\nbar\n--foo\nContent-Type: text/plain\n\nbaz\n--foo--\n"})
108
+ @backend.load_object(@object, {:headers => {"x-riak-vclock" => ["merged"], "content-type" => ["multipart/mixed; boundary=8XZD3w6ttFTHIz6LCmhVxn9Ex0K"]}, :code => 300, :body => File.read("spec/fixtures/multipart-basic-conflict.txt")})
110
109
  end
111
110
 
112
111
  it "should extract the siblings" do
113
112
  @object.should have(2).siblings
114
113
  siblings = @object.siblings
115
114
  siblings[0].data.should == "bar"
116
- siblings[1].data.should == "baz"
117
- end
118
-
119
- it "should set the key on both siblings" do
120
- @object.siblings.should be_all {|s| s.key == "bar" }
121
- end
122
-
123
- it "should set the vclock on both siblings to the merged vclock" do
124
- @object.siblings.should be_all {|s| s.vclock == "merged" }
115
+ siblings[1].data.should == "foo"
125
116
  end
126
117
  end
127
118
  end
@@ -183,16 +183,17 @@ describe Riak::Client::HTTPBackend do
183
183
  end
184
184
 
185
185
  it "should issue POST request to the mapred endpoint" do
186
- @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 => "[]"})
186
+ @backend.should_receive(:post).with(200, @backend.mapred_path(:chunked => true), @mr.to_json, hash_including("Content-Type" => "application/json")).and_yield(%Q|--foo\r\nContent-Type: application/json\r\n\r\n{"phase":0,"data":[]}\r\n--foo--\r\n|)
187
187
  @backend.mapred(@mr)
188
188
  end
189
189
 
190
190
  it "should vivify JSON responses" do
191
- @backend.stub!(:post).and_return(:headers => {'content-type' => ["application/json"]}, :body => '[{"key":"value"}]')
191
+ @backend.stub!(:post).and_yield(%Q|--foo\r\nContent-Type: application/json\r\n\r\n{"phase":0,"data":[{"key":"value"}]}\r\n--foo--\r\n|)
192
192
  @backend.mapred(@mr).should == [{"key" => "value"}]
193
193
  end
194
194
 
195
195
  it "should return the full response hash for non-JSON responses" do
196
+ pending "It is not clear when Riak would ever return a non-JSON or non-multipart response for mapred."
196
197
  response = {:code => 200, :headers => {'content-type' => ["text/plain"]}, :body => 'This is some text.'}
197
198
  @backend.stub!(:post).and_return(response)
198
199
  @backend.mapred(@mr).should == response
@@ -272,9 +273,9 @@ describe Riak::Client::HTTPBackend do
272
273
  @backend.search(nil, 'foo')
273
274
  end
274
275
 
275
- it "should vivify JSON responses" do
276
- @backend.should_receive(:get).and_return({:code => 200, :headers => {"content-type"=>["application/json"]}, :body => '{"response":{"docs":["foo"]}}'})
277
- @backend.search(nil, "foo").should == {"response" => {"docs" => ["foo"]}}
276
+ it "should vivify and normalize JSON responses" do
277
+ @backend.should_receive(:get).and_return({:code => 200, :headers => {"content-type"=>["application/json"]}, :body => '{"response":{"docs":[{"id":"foo","fields":{},"props":{}}],"maxScore":"0.0345","numFound":1}}'})
278
+ @backend.search(nil, "foo").should == {"docs" => [{"id" => "foo"}], "max_score" => 0.0345, "num_found" => 1}
278
279
  end
279
280
 
280
281
  it "should return non-JSON responses raw" do
@@ -330,11 +330,6 @@ describe Riak::MapReduce do
330
330
  @mr.map("Riak.mapValues",:keep => true)
331
331
  end
332
332
 
333
- it "should raise an exception when no phases are defined" do
334
- @mr.query.clear
335
- lambda { @mr.run }.should raise_error(Riak::MapReduceError)
336
- end
337
-
338
333
  it "should submit the query to the backend" do
339
334
  @backend.should_receive(:mapred).with(@mr).and_return([])
340
335
  @mr.run.should == []
@@ -50,14 +50,14 @@ describe Riak::RObject do
50
50
  @object.content_type = 'text/plain'
51
51
  Riak::Serializers.should respond_to(:serialize).with(2).arguments
52
52
  Riak::Serializers.should_receive(:serialize).with('text/plain', "foo").and_return("serialized foo")
53
- @object.serialize("foo").should == "serialized foo"
53
+ @object.content.serialize("foo").should == "serialized foo"
54
54
  end
55
55
 
56
56
  it 'delegates #deserialize to the appropriate serializer for the content type' do
57
57
  @object.content_type = 'text/plain'
58
58
  Riak::Serializers.should respond_to(:deserialize).with(2).arguments
59
59
  Riak::Serializers.should_receive(:deserialize).with('text/plain', "foo").and_return("deserialized foo")
60
- @object.deserialize("foo").should == "deserialized foo"
60
+ @object.content.deserialize("foo").should == "deserialized foo"
61
61
  end
62
62
  end
63
63
 
@@ -113,7 +113,7 @@ describe Riak::RObject do
113
113
  let(:io_object) { stub(:read => 'the io object') }
114
114
 
115
115
  it 'reads the object before deserializing it' do
116
- @object.should_receive(:deserialize).with('the io object').and_return('deserialized')
116
+ @object.content.should_receive(:deserialize).with('the io object').and_return('deserialized')
117
117
  @object.raw_data = io_object
118
118
  @object.data.should == 'deserialized'
119
119
  end
@@ -214,8 +214,8 @@ describe Riak::RObject do
214
214
  @object.conflict?.should be_false
215
215
  end
216
216
 
217
- it 'should return [self] for siblings' do
218
- @object.siblings.should == [@object]
217
+ it 'should return [RContent] for siblings' do
218
+ @object.siblings.should == [@object.content]
219
219
  end
220
220
 
221
221
  describe "when there are multiple values in an object" do
@@ -241,13 +241,9 @@ describe Riak::RObject do
241
241
  end
242
242
 
243
243
  it "should be in conflict" do
244
- @object.data.should_not be_present
244
+ expect { @object.data }.to raise_error(Riak::Conflict)
245
245
  @object.should be_conflict
246
246
  end
247
-
248
- it "should assign the same vclock to all the siblings" do
249
- @object.siblings.should be_all {|s| s.vclock == @object.vclock }
250
- end
251
247
  end
252
248
  end
253
249
 
@@ -285,6 +281,11 @@ describe Riak::RObject do
285
281
  @backend.should_receive(:store_object).with(@object, :returnbody => false, :w => 3, :dw => 2).and_return(true)
286
282
  @object.store(:returnbody => false, :w => 3, :dw => 2)
287
283
  end
284
+
285
+ it "should raise an error if the object is in conflict" do
286
+ @object.siblings << Riak::RContent.new(@object)
287
+ expect { @object.store }.to raise_error(Riak::Conflict)
288
+ end
288
289
  end
289
290
 
290
291
  describe "when reloading the object" do
@@ -419,7 +420,7 @@ describe Riak::RObject do
419
420
  end
420
421
 
421
422
  describe '#attempt_conflict_resolution' do
422
- let(:conflicted_robject) { Riak::RObject.new(@bucket, "conflicted") { |r| r.conflict = true } }
423
+ let(:conflicted_robject) { Riak::RObject.new(@bucket, "conflicted") { |r| r.siblings = [ Riak::RContent.new(r), Riak::RContent.new(r)] } }
423
424
  let(:resolved_robject) { Riak::RObject.new(@bucket, "resolved") }
424
425
  let(:invoked_resolvers) { [] }
425
426
  let(:resolver_1) { lambda { |r| invoked_resolvers << :resolver_1; nil } }