riak-client 1.0.5 → 1.1.0

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