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