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.
- data/CONTRIBUTORS.textile +1 -0
- data/README.textile +6 -4
- data/RELEASE_NOTES.textile +20 -0
- data/VERSION +1 -1
- data/lib/riak/bucket.rb +52 -2
- data/lib/riak/client.rb +2 -2
- data/lib/riak/client/curb_backend.rb +42 -23
- data/lib/riak/link.rb +4 -4
- data/lib/riak/map_reduce.rb +9 -1
- data/lib/riak/robject.rb +30 -7
- data/lib/riak/util/fiber1.8.rb +48 -0
- data/lib/riak/walk_spec.rb +1 -1
- data/lib/ripple.rb +3 -1
- data/lib/ripple/document.rb +4 -3
- data/lib/ripple/document/attribute_methods.rb +1 -1
- data/lib/ripple/document/finders.rb +5 -4
- data/lib/ripple/document/timestamps.rb +22 -0
- data/lib/ripple/embedded_document.rb +1 -0
- data/lib/ripple/locale/en.yml +2 -1
- data/ripple.gemspec +6 -2
- data/spec/fixtures/multipart-with-body.txt +2 -2
- data/spec/riak/bucket_spec.rb +79 -8
- data/spec/riak/client_spec.rb +4 -4
- data/spec/riak/http_backend_spec.rb +8 -8
- data/spec/riak/link_spec.rb +12 -12
- data/spec/riak/map_reduce_spec.rb +5 -0
- data/spec/riak/object_spec.rb +54 -16
- data/spec/riak/walk_spec_spec.rb +1 -1
- data/spec/ripple/finders_spec.rb +19 -19
- data/spec/ripple/persistence_spec.rb +4 -4
- data/spec/ripple/ripple_spec.rb +1 -0
- data/spec/ripple/timestamps_spec.rb +49 -0
- data/spec/support/http_backend_implementation_examples.rb +36 -36
- metadata +6 -2
data/lib/ripple/document.rb
CHANGED
@@ -28,15 +28,15 @@ module Ripple
|
|
28
28
|
# property :body, String
|
29
29
|
# end
|
30
30
|
#
|
31
|
-
# email = Email.find("37458abc752f8413e") # GET /
|
31
|
+
# email = Email.find("37458abc752f8413e") # GET /riak/emails/37458abc752f8413e
|
32
32
|
# email.from = "someone@nowhere.net"
|
33
|
-
# email.save # PUT /
|
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 /
|
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,
|
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 |
|
54
|
-
|
55
|
-
|
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
|
data/lib/ripple/locale/en.yml
CHANGED
data/ripple.gemspec
CHANGED
@@ -5,11 +5,11 @@
|
|
5
5
|
|
6
6
|
Gem::Specification.new do |s|
|
7
7
|
s.name = %q{ripple}
|
8
|
-
s.version = "0.
|
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-
|
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: /
|
7
|
+
Location: /riak/foo/baz
|
8
8
|
Content-Type: text/plain
|
9
|
-
Link: </
|
9
|
+
Link: </riak/foo>; rel="up"
|
10
10
|
Etag: 6JdI51eFrvv5lDwY6un7a2
|
11
11
|
Last-Modified: Sat, 16 Jan 2010 22:13:44 GMT
|
12
12
|
|
data/spec/riak/bucket_spec.rb
CHANGED
@@ -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" => ['</
|
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, "/
|
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, "/
|
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, "/
|
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, "/
|
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, "/
|
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, "/
|
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, "/
|
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
|
data/spec/riak/client_spec.rb
CHANGED
@@ -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 /
|
54
|
-
Riak::Client.new.prefix.should == "/
|
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, "/
|
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, "/
|
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!(["/
|
59
|
-
lambda { @backend.verify_path!(["/
|
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!(["/
|
66
|
-
uri.should == ["/
|
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!(["/
|
72
|
-
lambda { @backend.verify_path_and_body!(["/
|
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!(["/
|
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!(["/
|
80
|
+
lambda { @backend.verify_path_and_body!(["/riak/"])}.should raise_error(ArgumentError)
|
81
81
|
end
|
82
82
|
end
|
83
83
|
|
data/spec/riak/link_spec.rb
CHANGED
@@ -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('</
|
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('</
|
26
|
-
result[0].url.should == "/
|
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 == "/
|
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", </
|
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", </
|
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("/
|
53
|
-
Riak::Link.new("/
|
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("/
|
58
|
-
lambda { Riak::Link.new("/
|
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("/
|
63
|
-
two = Riak::Link.new("/
|
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
|
data/spec/riak/object_spec.rb
CHANGED
@@ -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" => ['</
|
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 == "/
|
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" => ["/
|
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("/
|
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('</
|
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("/
|
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, "/
|
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, "/
|
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], "/
|
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], "/
|
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], "/
|
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, "/
|
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], "/
|
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("/
|
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("/
|
480
|
+
@object.to_link("next").should == Riak::Link.new("/riak/foo/bar", "next")
|
443
481
|
end
|
444
482
|
end
|