ripple 0.5.1 → 0.6.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -28,15 +28,15 @@ module Ripple
28
28
  # property :body, String
29
29
  # end
30
30
  #
31
- # email = Email.find("37458abc752f8413e") # GET /raw/emails/37458abc752f8413e
31
+ # email = Email.find("37458abc752f8413e") # GET /riak/emails/37458abc752f8413e
32
32
  # email.from = "someone@nowhere.net"
33
- # email.save # PUT /raw/emails/37458abc752f8413e
33
+ # email.save # PUT /riak/emails/37458abc752f8413e
34
34
  #
35
35
  # reply = Email.new
36
36
  # reply.from = "justin@bashoooo.com"
37
37
  # reply.to = "sean@geeemail.com"
38
38
  # reply.body = "Riak is a good fit for scalable Ruby apps."
39
- # reply.save # POST /raw/emails (Riak-assigned key)
39
+ # reply.save # POST /riak/emails (Riak-assigned key)
40
40
  #
41
41
  module Document
42
42
  extend ActiveSupport::Concern
@@ -48,6 +48,7 @@ module Ripple
48
48
  autoload :Persistence
49
49
  autoload :Properties
50
50
  autoload :Property, "ripple/document/properties"
51
+ autoload :Timestamps
51
52
  autoload :Validations
52
53
 
53
54
  included do
@@ -64,7 +64,7 @@ module Ripple
64
64
  # Mass assign the document's attributes.
65
65
  # @param [Hash] attrs the attributes to assign
66
66
  def attributes=(attrs)
67
- raise ArgumentError, "value of attributes must be a Hash" unless Hash === attrs
67
+ raise ArgumentError, t('attribute_hash') unless Hash === attrs
68
68
  attrs.each do |k,v|
69
69
  if respond_to?("#{k}=")
70
70
  __send__("#{k}=",v)
@@ -46,13 +46,14 @@ module Ripple
46
46
  # @return [Array<Document>] all found documents in the bucket
47
47
  # @overload all() {|doc| ... }
48
48
  # Stream all documents in the bucket through the block.
49
- # TODO: Make this work with the CurbBackend (currently single-request oriented).
50
49
  # @yield [Document] doc a found document
51
50
  def all
52
51
  if block_given?
53
- bucket.keys do |key|
54
- obj = find_one(key)
55
- yield obj if obj
52
+ bucket.keys do |keys|
53
+ keys.each do |key|
54
+ obj = find_one(key)
55
+ yield obj if obj
56
+ end
56
57
  end
57
58
  []
58
59
  else
@@ -0,0 +1,22 @@
1
+ module Ripple
2
+ module Document
3
+ module Timestamps
4
+ extend ActiveSupport::Concern
5
+
6
+ module ClassMethods
7
+ def timestamps!
8
+ property :created_at, Time, :default => proc { Time.now.utc }
9
+ property :updated_at, Time
10
+ before_save :touch
11
+ end
12
+ end
13
+
14
+ module InstanceMethods
15
+ def touch
16
+ self.updated_at = Time.now.utc
17
+ end
18
+ end
19
+
20
+ end
21
+ end
22
+ end
@@ -26,6 +26,7 @@ module Ripple
26
26
  extend Ripple::Document::Properties
27
27
  include Persistence
28
28
  include Ripple::Document::AttributeMethods
29
+ include Ripple::Document::Timestamps
29
30
  include Ripple::Document::Validations
30
31
  end
31
32
 
@@ -13,4 +13,5 @@
13
13
  # limitations under the License.
14
14
  en:
15
15
  ripple:
16
- property_type_mismatch: "Cannot cast {{value}} into a {{class}}"
16
+ property_type_mismatch: "Cannot cast {{value}} into a {{class}}"
17
+ attribute_hash: "value of attributes must be a Hash"
@@ -5,11 +5,11 @@
5
5
 
6
6
  Gem::Specification.new do |s|
7
7
  s.name = %q{ripple}
8
- s.version = "0.5.1"
8
+ s.version = "0.6.0"
9
9
 
10
10
  s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
11
11
  s.authors = ["Sean Cribbs"]
12
- s.date = %q{2010-02-22}
12
+ s.date = %q{2010-03-05}
13
13
  s.description = %q{ripple is a rich Ruby client for Riak, Basho's distributed database. It includes all the basics of accessing and manipulating Riak buckets and objects, and an object mapper library for building a rich domain on top of Riak.}
14
14
  s.email = %q{seancribbs@gmail.com}
15
15
  s.extra_rdoc_files = [
@@ -39,6 +39,7 @@ Gem::Specification.new do |s|
39
39
  "lib/riak/map_reduce.rb",
40
40
  "lib/riak/map_reduce_error.rb",
41
41
  "lib/riak/robject.rb",
42
+ "lib/riak/util/fiber1.8.rb",
42
43
  "lib/riak/util/headers.rb",
43
44
  "lib/riak/util/multipart.rb",
44
45
  "lib/riak/util/translation.rb",
@@ -56,6 +57,7 @@ Gem::Specification.new do |s|
56
57
  "lib/ripple/document/persistence.rb",
57
58
  "lib/ripple/document/persistence/callbacks.rb",
58
59
  "lib/ripple/document/properties.rb",
60
+ "lib/ripple/document/timestamps.rb",
59
61
  "lib/ripple/document/validations.rb",
60
62
  "lib/ripple/embedded_document.rb",
61
63
  "lib/ripple/embedded_document/persistence.rb",
@@ -87,6 +89,7 @@ Gem::Specification.new do |s|
87
89
  "spec/ripple/persistence_spec.rb",
88
90
  "spec/ripple/properties_spec.rb",
89
91
  "spec/ripple/ripple_spec.rb",
92
+ "spec/ripple/timestamps_spec.rb",
90
93
  "spec/ripple/validations_spec.rb",
91
94
  "spec/spec.opts",
92
95
  "spec/spec_helper.rb",
@@ -120,6 +123,7 @@ Gem::Specification.new do |s|
120
123
  "spec/ripple/persistence_spec.rb",
121
124
  "spec/ripple/properties_spec.rb",
122
125
  "spec/ripple/ripple_spec.rb",
126
+ "spec/ripple/timestamps_spec.rb",
123
127
  "spec/ripple/validations_spec.rb",
124
128
  "spec/spec_helper.rb",
125
129
  "spec/support/http_backend_implementation_examples.rb",
@@ -4,9 +4,9 @@ Content-Type: multipart/mixed; boundary=7extjTzvYIKVMVHowUiTn0LfvSs
4
4
 
5
5
  --7extjTzvYIKVMVHowUiTn0LfvSs
6
6
  X-Riak-Vclock: a85hYGBgyWDKBVHMr9s3ZzAlMuaxMtyZcPAIH1RYyObHDqiwxIZjcOG1M98chAq3bUQIz7SSFQEKM4FUbwMKZwEA
7
- Location: /raw/foo/baz
7
+ Location: /riak/foo/baz
8
8
  Content-Type: text/plain
9
- Link: </raw/foo>; rel="up"
9
+ Link: </riak/foo>; rel="up"
10
10
  Etag: 6JdI51eFrvv5lDwY6un7a2
11
11
  Last-Modified: Sat, 16 Jan 2010 22:13:44 GMT
12
12
 
@@ -25,7 +25,7 @@ describe Riak::Bucket do
25
25
  :headers => {
26
26
  "vary" => ["Accept-Encoding"],
27
27
  "server" => ["MochiWeb/1.1 WebMachine/1.5.1 (hack the charles gibson)"],
28
- "link" => ['</raw/foo/bar>; riaktag="contained"'],
28
+ "link" => ['</riak/foo/bar>; riaktag="contained"'],
29
29
  "date" => ["Tue, 12 Jan 2010 15:30:43 GMT"],
30
30
  "content-type" => ["application/json"],
31
31
  "content-length" => ["257"]
@@ -80,19 +80,19 @@ describe Riak::Bucket do
80
80
  end
81
81
 
82
82
  it "should load the keys if not present" do
83
- @http.should_receive(:get).with(200, "/raw/", "foo", {:props => false}, {}).and_return({:headers => {"content-type" => ["application/json"]}, :body => '{"keys":["bar"]}'})
83
+ @http.should_receive(:get).with(200, "/riak/", "foo", {:props => false}, {}).and_return({:headers => {"content-type" => ["application/json"]}, :body => '{"keys":["bar"]}'})
84
84
  @bucket.keys.should == ["bar"]
85
85
  end
86
86
 
87
87
  it "should allow reloading of the keys" do
88
- @http.should_receive(:get).with(200, "/raw/","foo", {:props => false}, {}).and_return({:headers => {"content-type" => ["application/json"]}, :body => '{"keys":["bar"]}'})
88
+ @http.should_receive(:get).with(200, "/riak/","foo", {:props => false}, {}).and_return({:headers => {"content-type" => ["application/json"]}, :body => '{"keys":["bar"]}'})
89
89
  do_load # Ensures they're already loaded
90
90
  @bucket.keys(:reload => true).should == ["bar"]
91
91
  end
92
92
 
93
93
  it "should allow streaming keys through block" do
94
94
  # pending "Needs support in the raw_http_resource"
95
- @http.should_receive(:get).with(200, "/raw/","foo", {:props => false}, {}).and_yield("{}").and_yield('{"keys":[]}').and_yield('{"keys":["bar"]}').and_yield('{"keys":["baz"]}')
95
+ @http.should_receive(:get).with(200, "/riak/","foo", {:props => false}, {}).and_yield("{}").and_yield('{"keys":[]}').and_yield('{"keys":["bar"]}').and_yield('{"keys":["baz"]}')
96
96
  all_keys = []
97
97
  @bucket.keys do |list|
98
98
  all_keys.concat(list)
@@ -101,7 +101,7 @@ describe Riak::Bucket do
101
101
  end
102
102
 
103
103
  it "should unescape key names" do
104
- @http.should_receive(:get).with(200, "/raw/","foo", {:props => false}, {}).and_return({:headers => {"content-type" => ["application/json"]}, :body => '{"keys":["bar%20baz"]}'})
104
+ @http.should_receive(:get).with(200, "/riak/","foo", {:props => false}, {}).and_return({:headers => {"content-type" => ["application/json"]}, :body => '{"keys":["bar%20baz"]}'})
105
105
  @bucket.keys.should == ["bar baz"]
106
106
  end
107
107
  end
@@ -113,7 +113,7 @@ describe Riak::Bucket do
113
113
  end
114
114
 
115
115
  it "should PUT the new properties to the bucket" do
116
- @http.should_receive(:put).with(204, "/raw/","foo", '{"props":{"name":"foo"}}', {"Content-Type" => "application/json"}).and_return({:body => "", :headers => {}})
116
+ @http.should_receive(:put).with(204, "/riak/","foo", '{"props":{"name":"foo"}}', {"Content-Type" => "application/json"}).and_return({:body => "", :headers => {}})
117
117
  @bucket.props = { :name => "foo" }
118
118
  end
119
119
 
@@ -129,13 +129,84 @@ describe Riak::Bucket do
129
129
  end
130
130
 
131
131
  it "should load the object from the server as a Riak::RObject" do
132
- @http.should_receive(:get).with(200, "/raw/","foo", "db", {}, {}).and_return({:headers => {"content-type" => ["application/json"]}, :body => '{"name":"Riak","company":"Basho"}'})
132
+ @http.should_receive(:get).with(200, "/riak/","foo", "db", {}, {}).and_return({:headers => {"content-type" => ["application/json"]}, :body => '{"name":"Riak","company":"Basho"}'})
133
133
  @bucket.get("db").should be_kind_of(Riak::RObject)
134
134
  end
135
135
 
136
136
  it "should use the given query parameters (for R value, etc)" do
137
- @http.should_receive(:get).with(200, "/raw/","foo", "db", {:r => 2}, {}).and_return({:headers => {"content-type" => ["application/json"]}, :body => '{"name":"Riak","company":"Basho"}'})
137
+ @http.should_receive(:get).with(200, "/riak/","foo", "db", {:r => 2}, {}).and_return({:headers => {"content-type" => ["application/json"]}, :body => '{"name":"Riak","company":"Basho"}'})
138
138
  @bucket.get("db", :r => 2).should be_kind_of(Riak::RObject)
139
139
  end
140
+
141
+ it "should allow 300 responses if allow_mult is set" do
142
+ @bucket.instance_variable_set(:@props, {'allow_mult' => true})
143
+ @http.should_receive(:get).with([200,300], "/riak/","foo", "db", {}, {}).and_return({:headers => {"content-type" => ["application/json"]}, :body => '{"name":"Riak","company":"Basho"}'})
144
+ @bucket.get('db')
145
+ end
146
+ end
147
+
148
+ describe "creating a new blank object" do
149
+ it "should instantiate the object with the given key, default to JSON" do
150
+ obj = @bucket.new('bar')
151
+ obj.should be_kind_of(Riak::RObject)
152
+ obj.key.should == 'bar'
153
+ obj.content_type.should == 'application/json'
154
+ end
155
+ end
156
+
157
+ describe "fetching or creating a new object" do
158
+ before :each do
159
+ @http = mock("HTTPBackend")
160
+ @client.stub!(:http).and_return(@http)
161
+ end
162
+
163
+ it "should return the existing object if present" do
164
+ @http.should_receive(:get).with(200, "/riak/","foo", "db", {}, {}).and_return({:headers => {"content-type" => ["application/json"]}, :body => '{"name":"Riak","company":"Basho"}'})
165
+ obj = @bucket.get_or_new('db')
166
+ obj.key.should == 'db'
167
+ obj.data['name'].should == "Riak"
168
+ end
169
+
170
+ it "should create a new blank object if the key does not exist" do
171
+ @http.should_receive(:get).and_raise(Riak::FailedRequest.new(:get, 200, 404, {}, "File not found"))
172
+ obj = @bucket.get_or_new('db')
173
+ obj.key.should == 'db'
174
+ obj.data.should be_blank
175
+ end
176
+
177
+ it "should bubble up non-ok non-missing errors" do
178
+ @http.should_receive(:get).and_raise(Riak::FailedRequest.new(:get, 200, 500, {}, "File not found"))
179
+ lambda { @bucket.get_or_new('db') }.should raise_error(Riak::FailedRequest)
180
+ end
181
+ end
182
+
183
+ describe "get/set allow_mult property" do
184
+ before :each do
185
+ do_load
186
+ end
187
+
188
+ it "should extract the allow_mult property" do
189
+ @bucket.allow_mult.should be_false
190
+ end
191
+
192
+ it "should set the allow_mult property" do
193
+ @bucket.should_receive(:props=).with(hash_including('allow_mult' => true))
194
+ @bucket.allow_mult = true
195
+ end
196
+ end
197
+
198
+ describe "get/set the N value" do
199
+ before :each do
200
+ do_load
201
+ end
202
+
203
+ it "should extract the N value" do
204
+ @bucket.n_value.should == 3
205
+ end
206
+
207
+ it "should set the N value" do
208
+ @bucket.should_receive(:props=).with(hash_including('n_val' => 1))
209
+ @bucket.n_value = 1
210
+ end
140
211
  end
141
212
  end
@@ -50,8 +50,8 @@ describe Riak::Client do
50
50
  client.prefix.should == "/jiak/"
51
51
  end
52
52
 
53
- it "should default the prefix to /raw/ if not specified" do
54
- Riak::Client.new.prefix.should == "/raw/"
53
+ it "should default the prefix to /riak/ if not specified" do
54
+ Riak::Client.new.prefix.should == "/riak/"
55
55
  end
56
56
 
57
57
  it "should accept a mapreduce path" do
@@ -157,12 +157,12 @@ describe Riak::Client do
157
157
  end
158
158
 
159
159
  it "should send a GET request to the bucket name and return a Riak::Bucket" do
160
- @http.should_receive(:get).with(200, "/raw/", "foo", {}, {}).and_return(@payload)
160
+ @http.should_receive(:get).with(200, "/riak/", "foo", {}, {}).and_return(@payload)
161
161
  @client.bucket("foo").should be_kind_of(Riak::Bucket)
162
162
  end
163
163
 
164
164
  it "should allow requesting bucket properties without the keys" do
165
- @http.should_receive(:get).with(200, "/raw/", "foo", {:keys => false}, {}).and_return(@payload)
165
+ @http.should_receive(:get).with(200, "/riak/", "foo", {:keys => false}, {}).and_return(@payload)
166
166
  @client.bucket("foo", :keys => false)
167
167
  end
168
168
  end
@@ -55,29 +55,29 @@ describe Riak::Client::HTTPBackend do
55
55
  end
56
56
 
57
57
  it "should raise an error if a resource path is too short" do
58
- lambda { @backend.verify_path!(["/raw/"]) }.should raise_error(ArgumentError)
59
- lambda { @backend.verify_path!(["/raw/", "foo"]) }.should_not raise_error
58
+ lambda { @backend.verify_path!(["/riak/"]) }.should raise_error(ArgumentError)
59
+ lambda { @backend.verify_path!(["/riak/", "foo"]) }.should_not raise_error
60
60
  lambda { @backend.verify_path!(["/mapred"]) }.should_not raise_error
61
61
  end
62
62
 
63
63
  describe "verify_path_and_body!" do
64
64
  it "should separate the path and body from given arguments" do
65
- uri, data = @backend.verify_path_and_body!(["/raw/", "foo", "This is the body."])
66
- uri.should == ["/raw/", "foo"]
65
+ uri, data = @backend.verify_path_and_body!(["/riak/", "foo", "This is the body."])
66
+ uri.should == ["/riak/", "foo"]
67
67
  data.should == "This is the body."
68
68
  end
69
69
 
70
70
  it "should raise an error if the body is not a string or IO" do
71
- lambda { @backend.verify_path_and_body!(["/raw/", "foo", nil]) }.should raise_error(ArgumentError)
72
- lambda { @backend.verify_path_and_body!(["/raw/", "foo", File.open("spec/fixtures/cat.jpg")]) }.should_not raise_error(ArgumentError)
71
+ lambda { @backend.verify_path_and_body!(["/riak/", "foo", nil]) }.should raise_error(ArgumentError)
72
+ lambda { @backend.verify_path_and_body!(["/riak/", "foo", File.open("spec/fixtures/cat.jpg")]) }.should_not raise_error(ArgumentError)
73
73
  end
74
74
 
75
75
  it "should raise an error if a body is not given" do
76
- lambda { @backend.verify_path_and_body!(["/raw/", "foo"])}.should raise_error(ArgumentError)
76
+ lambda { @backend.verify_path_and_body!(["/riak/", "foo"])}.should raise_error(ArgumentError)
77
77
  end
78
78
 
79
79
  it "should raise an error if a path is not given" do
80
- lambda { @backend.verify_path_and_body!(["/raw/"])}.should raise_error(ArgumentError)
80
+ lambda { @backend.verify_path_and_body!(["/riak/"])}.should raise_error(ArgumentError)
81
81
  end
82
82
  end
83
83
 
@@ -16,31 +16,31 @@ require File.expand_path("../spec_helper", File.dirname(__FILE__))
16
16
  describe Riak::Link do
17
17
  describe "parsing a link header" do
18
18
  it "should create Link objects from the data" do
19
- result = Riak::Link.parse('</raw/foo/bar>; rel="tag", </raw/foo>; rel="up"')
19
+ result = Riak::Link.parse('</riak/foo/bar>; rel="tag", </riak/foo>; rel="up"')
20
20
  result.should be_kind_of(Array)
21
21
  result.should be_all {|i| Riak::Link === i }
22
22
  end
23
23
 
24
24
  it "should set the bucket, key, url and rel parameters properly" do
25
- result = Riak::Link.parse('</raw/foo/bar>; riaktag="tag", </raw/foo>; rel="up"')
26
- result[0].url.should == "/raw/foo/bar"
25
+ result = Riak::Link.parse('</riak/foo/bar>; riaktag="tag", </riak/foo>; rel="up"')
26
+ result[0].url.should == "/riak/foo/bar"
27
27
  result[0].bucket.should == "foo"
28
28
  result[0].key.should == "bar"
29
29
  result[0].rel.should == "tag"
30
- result[1].url.should == "/raw/foo"
30
+ result[1].url.should == "/riak/foo"
31
31
  result[1].bucket.should == "foo"
32
32
  result[1].key.should == nil
33
33
  result[1].rel.should == "up"
34
34
  end
35
35
 
36
36
  it "should set url properly, and set bucket and key to nil for non-Riak links" do
37
- result = Riak::Link.parse('<http://www.example.com/123.html>; riaktag="tag", </raw/foo>; rel="up"')
37
+ result = Riak::Link.parse('<http://www.example.com/123.html>; riaktag="tag", </riak/foo>; rel="up"')
38
38
  result[0].url.should == "http://www.example.com/123.html"
39
39
  result[0].bucket.should == nil
40
40
  result[0].key.should == nil
41
41
  result[0].rel.should == "tag"
42
42
 
43
- result = Riak::Link.parse('<http://www.example.com/>; riaktag="tag", </raw/foo>; rel="up"')
43
+ result = Riak::Link.parse('<http://www.example.com/>; riaktag="tag", </riak/foo>; rel="up"')
44
44
  result[0].url.should == "http://www.example.com/"
45
45
  result[0].bucket.should == nil
46
46
  result[0].key.should == nil
@@ -49,18 +49,18 @@ describe Riak::Link do
49
49
  end
50
50
 
51
51
  it "should convert to a string appropriate for use in the Link header" do
52
- Riak::Link.new("/raw/foo", "up").to_s.should == '</raw/foo>; riaktag="up"'
53
- Riak::Link.new("/raw/foo/bar", "next").to_s.should == '</raw/foo/bar>; riaktag="next"'
52
+ Riak::Link.new("/riak/foo", "up").to_s.should == '</riak/foo>; riaktag="up"'
53
+ Riak::Link.new("/riak/foo/bar", "next").to_s.should == '</riak/foo/bar>; riaktag="next"'
54
54
  end
55
55
 
56
56
  it "should convert to a walk spec when pointing to an object" do
57
- Riak::Link.new("/raw/foo/bar", "next").to_walk_spec.to_s.should == "foo,next,_"
58
- lambda { Riak::Link.new("/raw/foo", "up").to_walk_spec }.should raise_error
57
+ Riak::Link.new("/riak/foo/bar", "next").to_walk_spec.to_s.should == "foo,next,_"
58
+ lambda { Riak::Link.new("/riak/foo", "up").to_walk_spec }.should raise_error
59
59
  end
60
60
 
61
61
  it "should be equivalent to a link with the same url and rel" do
62
- one = Riak::Link.new("/raw/foo/bar", "next")
63
- two = Riak::Link.new("/raw/foo/bar", "next")
62
+ one = Riak::Link.new("/riak/foo/bar", "next")
63
+ two = Riak::Link.new("/riak/foo/bar", "next")
64
64
  one.should == two
65
65
  [one].should include(two)
66
66
  [two].should include(one)
@@ -173,6 +173,11 @@ describe Riak::MapReduce do
173
173
  @mr.add("foo","bar",1000).add("foo","baz")
174
174
  @mr.to_json.should include('"inputs":[["foo","bar",1000],["foo","baz"]]')
175
175
  end
176
+
177
+ it "should add the timeout value when set" do
178
+ @mr.timeout(50000)
179
+ @mr.to_json.should include('"timeout":50000')
180
+ end
176
181
  end
177
182
 
178
183
  describe "executing the map reduce job" do
@@ -32,13 +32,19 @@ describe Riak::RObject do
32
32
 
33
33
  it "should initialize the links to an empty array" do
34
34
  @object = Riak::RObject.new(@bucket, "bar")
35
- @object.links.should == []
35
+ @object.links.should == Set.new
36
36
  end
37
37
 
38
38
  it "should initialize the meta to an empty hash" do
39
39
  @object = Riak::RObject.new(@bucket, "bar")
40
40
  @object.meta.should == {}
41
41
  end
42
+
43
+ it "should yield itself to a given block" do
44
+ Riak::RObject.new(@bucket, "bar") do |r|
45
+ r.key.should == "bar"
46
+ end
47
+ end
42
48
  end
43
49
 
44
50
  describe "serialization" do
@@ -165,9 +171,9 @@ describe Riak::RObject do
165
171
  end
166
172
 
167
173
  it "should load links from the headers" do
168
- @object.load({:headers => {"content-type" => ["application/json"], "link" => ['</raw/bar>; rel="up"']}, :body => "{}"})
174
+ @object.load({:headers => {"content-type" => ["application/json"], "link" => ['</riak/bar>; rel="up"']}, :body => "{}"})
169
175
  @object.links.should have(1).item
170
- @object.links.first.url.should == "/raw/bar"
176
+ @object.links.first.url.should == "/riak/bar"
171
177
  @object.links.first.rel.should == "up"
172
178
  end
173
179
 
@@ -188,9 +194,35 @@ describe Riak::RObject do
188
194
  end
189
195
 
190
196
  it "should parse the location header into the key when present" do
191
- @object.load({:headers => {"content-type" => ["application/json"], "location" => ["/raw/foo/baz"]}})
197
+ @object.load({:headers => {"content-type" => ["application/json"], "location" => ["/riak/foo/baz"]}})
192
198
  @object.key.should == "baz"
193
199
  end
200
+
201
+ it "should be in conflict when the response code is 300 and the content-type is multipart/mixed" do
202
+ @object.load({:headers => {"content-type" => ["multipart/mixed; boundary=foo"]}, :code => 300 })
203
+ @object.should be_conflict
204
+ end
205
+ end
206
+
207
+ describe "extracting siblings" do
208
+ before :each do
209
+ @object = Riak::RObject.new(@bucket, "bar").load({: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"})
210
+ end
211
+
212
+ it "should extract the siblings" do
213
+ @object.should have(2).siblings
214
+ siblings = @object.siblings
215
+ siblings[0].data.should == "bar"
216
+ siblings[1].data.should == "baz"
217
+ end
218
+
219
+ it "should set the key on both siblings" do
220
+ @object.siblings.should be_all {|s| s.key == "bar" }
221
+ end
222
+
223
+ it "should set the vclock on both siblings to the merged vclock" do
224
+ @object.siblings.should be_all {|s| s.vclock == "merged" }
225
+ end
194
226
  end
195
227
 
196
228
  describe "headers used for storing the object" do
@@ -215,16 +247,16 @@ describe Riak::RObject do
215
247
 
216
248
  describe "when links are defined" do
217
249
  before :each do
218
- @object.links = [Riak::Link.new("/raw/foo/baz", "next")]
250
+ @object.links = [Riak::Link.new("/riak/foo/baz", "next")]
219
251
  end
220
252
 
221
253
  it "should include a Link header with references to other objects" do
222
254
  @object.store_headers.should have_key("Link")
223
- @object.store_headers["Link"].should include('</raw/foo/baz>; riaktag="next"')
255
+ @object.store_headers["Link"].should include('</riak/foo/baz>; riaktag="next"')
224
256
  end
225
257
 
226
258
  it "should exclude the 'up' link to the bucket from the header" do
227
- @object.links << Riak::Link.new("/raw/foo", "up")
259
+ @object.links << Riak::Link.new("/riak/foo", "up")
228
260
  @object.store_headers.should have_key("Link")
229
261
  @object.store_headers["Link"].should_not include('riaktag="up"')
230
262
  end
@@ -297,14 +329,14 @@ describe Riak::RObject do
297
329
 
298
330
  describe "when the object has no key" do
299
331
  it "should issue a POST request to the bucket, and update the object properties (returning the body by default)" do
300
- @http.should_receive(:post).with(201, "/raw/", "foo", {:returnbody => true}, "This is some text.", @headers).and_return({:headers => {'location' => ["/raw/foo/somereallylongstring"], "x-riak-vclock" => ["areallylonghashvalue"]}, :code => 201})
332
+ @http.should_receive(:post).with(201, "/riak/", "foo", {:returnbody => true}, "This is some text.", @headers).and_return({:headers => {'location' => ["/riak/foo/somereallylongstring"], "x-riak-vclock" => ["areallylonghashvalue"]}, :code => 201})
301
333
  @object.store
302
334
  @object.key.should == "somereallylongstring"
303
335
  @object.vclock.should == "areallylonghashvalue"
304
336
  end
305
337
 
306
338
  it "should include persistence-tuning parameters in the query string" do
307
- @http.should_receive(:post).with(201, "/raw/", "foo", {:dw => 2, :returnbody => true}, "This is some text.", @headers).and_return({:headers => {'location' => ["/raw/foo/somereallylongstring"], "x-riak-vclock" => ["areallylonghashvalue"]}, :code => 201})
339
+ @http.should_receive(:post).with(201, "/riak/", "foo", {:dw => 2, :returnbody => true}, "This is some text.", @headers).and_return({:headers => {'location' => ["/riak/foo/somereallylongstring"], "x-riak-vclock" => ["areallylonghashvalue"]}, :code => 201})
308
340
  @object.store(:dw => 2)
309
341
  end
310
342
  end
@@ -315,14 +347,14 @@ describe Riak::RObject do
315
347
  end
316
348
 
317
349
  it "should issue a PUT request to the bucket, and update the object properties (returning the body by default)" do
318
- @http.should_receive(:put).with([200,204], "/raw/", "foo/bar", {:returnbody => true}, "This is some text.", @headers).and_return({:headers => {'location' => ["/raw/foo/somereallylongstring"], "x-riak-vclock" => ["areallylonghashvalue"]}, :code => 204})
350
+ @http.should_receive(:put).with([200,204], "/riak/", "foo/bar", {:returnbody => true}, "This is some text.", @headers).and_return({:headers => {'location' => ["/riak/foo/somereallylongstring"], "x-riak-vclock" => ["areallylonghashvalue"]}, :code => 204})
319
351
  @object.store
320
352
  @object.key.should == "somereallylongstring"
321
353
  @object.vclock.should == "areallylonghashvalue"
322
354
  end
323
355
 
324
356
  it "should include persistence-tuning parameters in the query string" do
325
- @http.should_receive(:put).with([200,204], "/raw/", "foo/bar", {:dw => 2, :returnbody => true}, "This is some text.", @headers).and_return({:headers => {'location' => ["/raw/foo/somereallylongstring"], "x-riak-vclock" => ["areallylonghashvalue"]}, :code => 204})
357
+ @http.should_receive(:put).with([200,204], "/riak/", "foo/bar", {:dw => 2, :returnbody => true}, "This is some text.", @headers).and_return({:headers => {'location' => ["/riak/foo/somereallylongstring"], "x-riak-vclock" => ["areallylonghashvalue"]}, :code => 204})
326
358
  @object.store(:dw => 2)
327
359
  end
328
360
  end
@@ -357,7 +389,7 @@ describe Riak::RObject do
357
389
  it "should pass along the reload_headers" do
358
390
  @headers = {"If-None-Match" => "etag"}
359
391
  @object.should_receive(:reload_headers).and_return(@headers)
360
- @http.should_receive(:get).with([200,304], "/raw/", "foo", "bar", {}, @headers).and_return({:code => 304})
392
+ @http.should_receive(:get).with([200,304], "/riak/", "foo", "bar", {}, @headers).and_return({:code => 304})
361
393
  @object.reload
362
394
  end
363
395
 
@@ -372,6 +404,12 @@ describe Riak::RObject do
372
404
  @object.should_not_receive(:load)
373
405
  lambda { @object.reload }.should raise_error(Riak::FailedRequest)
374
406
  end
407
+
408
+ it "should include 300 in valid responses if the bucket has allow_mult set" do
409
+ @object.bucket.should_receive(:allow_mult).and_return(true)
410
+ @http.should_receive(:get).with([200,300,304], "/riak/", "foo", "bar", {}, {}).and_return({:code => 304})
411
+ @object.reload
412
+ end
375
413
  end
376
414
 
377
415
  describe "walking from the object to linked objects" do
@@ -384,7 +422,7 @@ describe Riak::RObject do
384
422
  end
385
423
 
386
424
  it "should issue a GET request to the given walk spec" do
387
- @http.should_receive(:get).with(200, "/raw/", "foo", "bar", "_,next,1").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")
425
+ @http.should_receive(:get).with(200, "/riak/", "foo", "bar", "_,next,1").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")
388
426
  @object.walk(nil,"next",true)
389
427
  end
390
428
 
@@ -415,7 +453,7 @@ describe Riak::RObject do
415
453
  end
416
454
 
417
455
  it "should make a DELETE request to the Riak server and freeze the object" do
418
- @http.should_receive(:delete).with([204,404], "/raw/", "foo", "bar").and_return({:code => 204, :headers => {}})
456
+ @http.should_receive(:delete).with([204,404], "/riak/", "foo", "bar").and_return({:code => 204, :headers => {}})
419
457
  @object.delete
420
458
  @object.should be_frozen
421
459
  end
@@ -434,11 +472,11 @@ describe Riak::RObject do
434
472
 
435
473
  it "should convert to a link having the same url and an empty tag" do
436
474
  @object = Riak::RObject.new(@bucket, "bar")
437
- @object.to_link.should == Riak::Link.new("/raw/foo/bar", nil)
475
+ @object.to_link.should == Riak::Link.new("/riak/foo/bar", nil)
438
476
  end
439
477
 
440
478
  it "should convert to a link having the same url and a supplied tag" do
441
479
  @object = Riak::RObject.new(@bucket, "bar")
442
- @object.to_link("next").should == Riak::Link.new("/raw/foo/bar", "next")
480
+ @object.to_link("next").should == Riak::Link.new("/riak/foo/bar", "next")
443
481
  end
444
482
  end