ripple 0.5.1 → 0.6.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.
@@ -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