seomoz-riak-client 1.0.0.pre
Sign up to get free protection for your applications and to get access to all the features.
- data/Gemfile +27 -0
- data/Guardfile +14 -0
- data/Rakefile +76 -0
- data/erl_src/riak_kv_test_backend.beam +0 -0
- data/erl_src/riak_kv_test_backend.erl +174 -0
- data/erl_src/riak_search_test_backend.beam +0 -0
- data/erl_src/riak_search_test_backend.erl +175 -0
- data/lib/active_support/cache/riak_store.rb +2 -0
- data/lib/riak.rb +21 -0
- data/lib/riak/bucket.rb +215 -0
- data/lib/riak/cache_store.rb +84 -0
- data/lib/riak/client.rb +415 -0
- data/lib/riak/client/beefcake/messages.rb +147 -0
- data/lib/riak/client/beefcake/object_methods.rb +92 -0
- data/lib/riak/client/beefcake_protobuffs_backend.rb +176 -0
- data/lib/riak/client/excon_backend.rb +65 -0
- data/lib/riak/client/http_backend.rb +203 -0
- data/lib/riak/client/http_backend/configuration.rb +46 -0
- data/lib/riak/client/http_backend/key_streamer.rb +43 -0
- data/lib/riak/client/http_backend/object_methods.rb +94 -0
- data/lib/riak/client/http_backend/request_headers.rb +34 -0
- data/lib/riak/client/http_backend/transport_methods.rb +218 -0
- data/lib/riak/client/net_http_backend.rb +79 -0
- data/lib/riak/client/protobuffs_backend.rb +97 -0
- data/lib/riak/client/pump.rb +30 -0
- data/lib/riak/client/search.rb +94 -0
- data/lib/riak/core_ext.rb +6 -0
- data/lib/riak/core_ext/blank.rb +53 -0
- data/lib/riak/core_ext/extract_options.rb +7 -0
- data/lib/riak/core_ext/json.rb +15 -0
- data/lib/riak/core_ext/slice.rb +18 -0
- data/lib/riak/core_ext/stringify_keys.rb +10 -0
- data/lib/riak/core_ext/symbolize_keys.rb +10 -0
- data/lib/riak/core_ext/to_param.rb +31 -0
- data/lib/riak/encoding.rb +6 -0
- data/lib/riak/failed_request.rb +81 -0
- data/lib/riak/i18n.rb +3 -0
- data/lib/riak/json.rb +28 -0
- data/lib/riak/link.rb +85 -0
- data/lib/riak/locale/en.yml +48 -0
- data/lib/riak/map_reduce.rb +206 -0
- data/lib/riak/map_reduce/filter_builder.rb +94 -0
- data/lib/riak/map_reduce/phase.rb +98 -0
- data/lib/riak/map_reduce_error.rb +7 -0
- data/lib/riak/robject.rb +290 -0
- data/lib/riak/search.rb +3 -0
- data/lib/riak/serializers.rb +74 -0
- data/lib/riak/stamp.rb +77 -0
- data/lib/riak/test_server.rb +252 -0
- data/lib/riak/util/escape.rb +45 -0
- data/lib/riak/util/fiber1.8.rb +48 -0
- data/lib/riak/util/headers.rb +53 -0
- data/lib/riak/util/multipart.rb +52 -0
- data/lib/riak/util/multipart/stream_parser.rb +62 -0
- data/lib/riak/util/tcp_socket_extensions.rb +58 -0
- data/lib/riak/util/translation.rb +19 -0
- data/lib/riak/walk_spec.rb +105 -0
- data/riak-client.gemspec +55 -0
- data/seomoz-riak-client.gemspec +55 -0
- data/spec/fixtures/cat.jpg +0 -0
- data/spec/fixtures/multipart-blank.txt +7 -0
- data/spec/fixtures/multipart-mapreduce.txt +10 -0
- data/spec/fixtures/multipart-with-body.txt +16 -0
- data/spec/fixtures/server.cert.crt +15 -0
- data/spec/fixtures/server.cert.key +15 -0
- data/spec/fixtures/test.pem +1 -0
- data/spec/integration/riak/cache_store_spec.rb +154 -0
- data/spec/integration/riak/http_backends_spec.rb +58 -0
- data/spec/integration/riak/protobuffs_backends_spec.rb +32 -0
- data/spec/integration/riak/test_server_spec.rb +161 -0
- data/spec/riak/beefcake_protobuffs_backend_spec.rb +59 -0
- data/spec/riak/bucket_spec.rb +205 -0
- data/spec/riak/client_spec.rb +517 -0
- data/spec/riak/core_ext/to_param_spec.rb +15 -0
- data/spec/riak/escape_spec.rb +69 -0
- data/spec/riak/excon_backend_spec.rb +64 -0
- data/spec/riak/headers_spec.rb +38 -0
- data/spec/riak/http_backend/configuration_spec.rb +51 -0
- data/spec/riak/http_backend/object_methods_spec.rb +217 -0
- data/spec/riak/http_backend/transport_methods_spec.rb +117 -0
- data/spec/riak/http_backend_spec.rb +269 -0
- data/spec/riak/link_spec.rb +71 -0
- data/spec/riak/map_reduce/filter_builder_spec.rb +32 -0
- data/spec/riak/map_reduce/phase_spec.rb +136 -0
- data/spec/riak/map_reduce_spec.rb +310 -0
- data/spec/riak/multipart_spec.rb +23 -0
- data/spec/riak/net_http_backend_spec.rb +16 -0
- data/spec/riak/robject_spec.rb +427 -0
- data/spec/riak/search_spec.rb +178 -0
- data/spec/riak/serializers_spec.rb +93 -0
- data/spec/riak/stamp_spec.rb +54 -0
- data/spec/riak/stream_parser_spec.rb +53 -0
- data/spec/riak/walk_spec_spec.rb +195 -0
- data/spec/spec_helper.rb +39 -0
- data/spec/support/drb_mock_server.rb +39 -0
- data/spec/support/http_backend_implementation_examples.rb +266 -0
- data/spec/support/integration_setup.rb +10 -0
- data/spec/support/mock_server.rb +81 -0
- data/spec/support/mocks.rb +4 -0
- data/spec/support/test_server.yml.example +2 -0
- data/spec/support/unified_backend_examples.rb +255 -0
- metadata +271 -0
@@ -0,0 +1,59 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
require 'riak/client/beefcake/messages'
|
3
|
+
|
4
|
+
describe Riak::Client::BeefcakeProtobuffsBackend do
|
5
|
+
before :each do
|
6
|
+
@client = Riak::Client.new
|
7
|
+
@backend = Riak::Client::BeefcakeProtobuffsBackend.new(@client)
|
8
|
+
@backend.instance_variable_set(:@server_config, {})
|
9
|
+
end
|
10
|
+
|
11
|
+
it "should only write to the socket one time per request" do
|
12
|
+
exp_bucket, exp_keys = 'foo', ['bar']
|
13
|
+
mock_socket = mock("mock TCP socket")
|
14
|
+
|
15
|
+
@backend.stub!(:socket).and_return(mock_socket)
|
16
|
+
mock_socket.should_receive(:write).exactly(1).with do |param|
|
17
|
+
len, code = param[0,5].unpack("NC")
|
18
|
+
req = Riak::Client::BeefcakeProtobuffsBackend::RpbListKeysReq.decode(param[5..-1])
|
19
|
+
code == 17 && req.bucket == exp_bucket
|
20
|
+
end
|
21
|
+
|
22
|
+
responses = Array.new(2) do |index|
|
23
|
+
resp = Riak::Client::BeefcakeProtobuffsBackend::RpbListKeysResp.new
|
24
|
+
if index == 0
|
25
|
+
resp.keys = exp_keys
|
26
|
+
else
|
27
|
+
resp.done = true
|
28
|
+
end
|
29
|
+
resp
|
30
|
+
end
|
31
|
+
|
32
|
+
responses.each do |response|
|
33
|
+
encoded_response = response.encode
|
34
|
+
mock_socket.should_receive(:read).exactly(1).with(5).and_return([1 + encoded_response.length, 18].pack("NC"))
|
35
|
+
mock_socket.should_receive(:read).exactly(1).with(encoded_response.length).and_return(encoded_response)
|
36
|
+
end
|
37
|
+
|
38
|
+
@backend.list_keys(exp_bucket).should == exp_keys
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
describe Riak::Client::BeefcakeProtobuffsBackend, '#mapred' do
|
43
|
+
before(:each) do
|
44
|
+
@client = Riak::Client.new
|
45
|
+
@backend = Riak::Client::BeefcakeProtobuffsBackend.new(@client)
|
46
|
+
@backend.instance_variable_set(:@server_config, {})
|
47
|
+
end
|
48
|
+
|
49
|
+
it "should not return nil for previous phases that don't return anything" do
|
50
|
+
socket = stub(:socket).as_null_object
|
51
|
+
socket.stub(:read).and_return(stub(:socket_header, :unpack => [2, 24]), stub(:socket_message), stub(:socket_header_2, :unpack => [0, 1]))
|
52
|
+
message = stub(:message, :phase => 1, :response => [{}].to_json)
|
53
|
+
message.stub(:done).and_return(false, true)
|
54
|
+
Riak::Client::BeefcakeProtobuffsBackend::RpbMapRedResp.stub(:decode => message)
|
55
|
+
TCPSocket.stub(:new => socket)
|
56
|
+
|
57
|
+
@backend.mapred('').should == [{}]
|
58
|
+
end
|
59
|
+
end
|
@@ -0,0 +1,205 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Riak::Bucket do
|
4
|
+
before :each do
|
5
|
+
@client = Riak::Client.new
|
6
|
+
@backend = mock("Backend")
|
7
|
+
@client.stub!(:backend).and_return(@backend)
|
8
|
+
@bucket = Riak::Bucket.new(@client, "foo")
|
9
|
+
end
|
10
|
+
|
11
|
+
describe "when initializing" do
|
12
|
+
it "should require a client and a name" do
|
13
|
+
lambda { Riak::Bucket.new }.should raise_error
|
14
|
+
lambda { Riak::Bucket.new(@client) }.should raise_error
|
15
|
+
lambda { Riak::Bucket.new("foo") }.should raise_error
|
16
|
+
lambda { Riak::Bucket.new("foo", @client) }.should raise_error
|
17
|
+
lambda { Riak::Bucket.new(@client, "foo") }.should_not raise_error
|
18
|
+
end
|
19
|
+
|
20
|
+
it "should set the client and name attributes" do
|
21
|
+
bucket = Riak::Bucket.new(@client, "foo")
|
22
|
+
bucket.client.should == @client
|
23
|
+
bucket.name.should == "foo"
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
describe "accessing keys" do
|
28
|
+
it "should list the keys" do
|
29
|
+
@backend.should_receive(:list_keys).with(@bucket).and_return(["bar"])
|
30
|
+
@bucket.keys.should == ["bar"]
|
31
|
+
end
|
32
|
+
|
33
|
+
it "should allow streaming keys through block" do
|
34
|
+
@backend.should_receive(:list_keys).with(@bucket).and_yield([]).and_yield(["bar"]).and_yield(["baz"])
|
35
|
+
all_keys = []
|
36
|
+
@bucket.keys do |list|
|
37
|
+
all_keys.concat(list)
|
38
|
+
end
|
39
|
+
all_keys.should == ["bar", "baz"]
|
40
|
+
end
|
41
|
+
|
42
|
+
it "should not cache the list of keys" do
|
43
|
+
@backend.should_receive(:list_keys).with(@bucket).twice.and_return(["bar"])
|
44
|
+
2.times { @bucket.keys.should == ['bar'] }
|
45
|
+
end
|
46
|
+
|
47
|
+
it "should warn about the expense of list-keys when warnings are not disabled" do
|
48
|
+
Riak.disable_list_keys_warnings = false
|
49
|
+
@backend.stub!(:list_keys).and_return(%w{test test2})
|
50
|
+
@bucket.should_receive(:warn)
|
51
|
+
@bucket.keys
|
52
|
+
Riak.disable_list_keys_warnings = true
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
describe "setting the bucket properties" do
|
57
|
+
it "should prefetch the properties when they are not present" do
|
58
|
+
@backend.stub!(:set_bucket_props)
|
59
|
+
@backend.should_receive(:get_bucket_props).with(@bucket).and_return({"name" => "foo"})
|
60
|
+
@bucket.props = {"precommit" => []}
|
61
|
+
end
|
62
|
+
|
63
|
+
it "should set the new properties on the bucket" do
|
64
|
+
@bucket.instance_variable_set(:@props, {}) # Pretend they are there
|
65
|
+
@backend.should_receive(:set_bucket_props).with(@bucket, { :name => "foo" })
|
66
|
+
@bucket.props = { :name => "foo" }
|
67
|
+
end
|
68
|
+
|
69
|
+
it "should raise an error if an invalid type is given" do
|
70
|
+
lambda { @bucket.props = "blah" }.should raise_error(ArgumentError)
|
71
|
+
end
|
72
|
+
end
|
73
|
+
|
74
|
+
describe "fetching the bucket properties" do
|
75
|
+
it "should fetch properties on first access" do
|
76
|
+
@bucket.instance_variable_get(:@props).should be_nil
|
77
|
+
@backend.should_receive(:get_bucket_props).with(@bucket).and_return({"name" => "foo"})
|
78
|
+
@bucket.props.should == {"name" => "foo"}
|
79
|
+
end
|
80
|
+
|
81
|
+
it "should memoize fetched properties" do
|
82
|
+
@backend.should_receive(:get_bucket_props).once.with(@bucket).and_return({"name" => "foo"})
|
83
|
+
@bucket.props.should == {"name" => "foo"}
|
84
|
+
@bucket.props.should == {"name" => "foo"}
|
85
|
+
end
|
86
|
+
end
|
87
|
+
|
88
|
+
describe "fetching an object" do
|
89
|
+
it "should fetch the object via the backend" do
|
90
|
+
@backend.should_receive(:fetch_object).with(@bucket, "db", nil).and_return(nil)
|
91
|
+
@bucket.get("db")
|
92
|
+
end
|
93
|
+
|
94
|
+
it "should use the specified R quroum" do
|
95
|
+
@backend.should_receive(:fetch_object).with(@bucket, "db", 2).and_return(nil)
|
96
|
+
@bucket.get("db", :r => 2)
|
97
|
+
end
|
98
|
+
end
|
99
|
+
|
100
|
+
describe "creating a new blank object" do
|
101
|
+
it "should instantiate the object with the given key, default to JSON" do
|
102
|
+
obj = @bucket.new('bar')
|
103
|
+
obj.should be_kind_of(Riak::RObject)
|
104
|
+
obj.key.should == 'bar'
|
105
|
+
obj.content_type.should == 'application/json'
|
106
|
+
end
|
107
|
+
end
|
108
|
+
|
109
|
+
describe "fetching or creating a new object" do
|
110
|
+
it "should return the existing object if present" do
|
111
|
+
@object = mock("RObject")
|
112
|
+
@backend.should_receive(:fetch_object).with(@bucket,"db", nil).and_return(@object)
|
113
|
+
@bucket.get_or_new('db').should == @object
|
114
|
+
end
|
115
|
+
|
116
|
+
it "should create a new blank object if the key does not exist" do
|
117
|
+
@backend.should_receive(:fetch_object).and_raise(Riak::HTTPFailedRequest.new(:get, 200, 404, {}, "File not found"))
|
118
|
+
obj = @bucket.get_or_new('db')
|
119
|
+
obj.key.should == 'db'
|
120
|
+
obj.data.should be_blank
|
121
|
+
end
|
122
|
+
|
123
|
+
it "should bubble up non-ok non-missing errors" do
|
124
|
+
@backend.should_receive(:fetch_object).and_raise(Riak::HTTPFailedRequest.new(:get, 200, 500, {}, "File not found"))
|
125
|
+
lambda { @bucket.get_or_new('db') }.should raise_error(Riak::HTTPFailedRequest)
|
126
|
+
end
|
127
|
+
|
128
|
+
it "should pass along the given R quorum parameter" do
|
129
|
+
@object = mock("RObject")
|
130
|
+
@backend.should_receive(:fetch_object).with(@bucket,"db", "all").and_return(@object)
|
131
|
+
@bucket.get_or_new('db', :r => "all").should == @object
|
132
|
+
end
|
133
|
+
end
|
134
|
+
|
135
|
+
describe "get/set allow_mult property" do
|
136
|
+
before :each do
|
137
|
+
@backend.stub!(:get_bucket_props).and_return({"allow_mult" => false})
|
138
|
+
end
|
139
|
+
|
140
|
+
it "should extract the allow_mult property" do
|
141
|
+
@bucket.allow_mult.should be_false
|
142
|
+
end
|
143
|
+
|
144
|
+
it "should set the allow_mult property" do
|
145
|
+
@bucket.should_receive(:props=).with(hash_including('allow_mult' => true))
|
146
|
+
@bucket.allow_mult = true
|
147
|
+
end
|
148
|
+
end
|
149
|
+
|
150
|
+
describe "get/set the N value" do
|
151
|
+
before :each do
|
152
|
+
@backend.stub!(:get_bucket_props).and_return({"n_val" => 3})
|
153
|
+
end
|
154
|
+
|
155
|
+
it "should extract the N value" do
|
156
|
+
@bucket.n_value.should == 3
|
157
|
+
end
|
158
|
+
|
159
|
+
it "should set the N value" do
|
160
|
+
@bucket.should_receive(:props=).with(hash_including('n_val' => 1))
|
161
|
+
@bucket.n_value = 1
|
162
|
+
end
|
163
|
+
end
|
164
|
+
|
165
|
+
[:r, :w, :dw, :rw].each do |q|
|
166
|
+
describe "get/set the default #{q} quorum" do
|
167
|
+
before :each do
|
168
|
+
@backend.stub!(:get_bucket_props).and_return({"r" => "quorum", "w" => "quorum", "dw" => "quorum", "rw" => "quorum"})
|
169
|
+
end
|
170
|
+
|
171
|
+
it "should extract the default #{q} quorum" do
|
172
|
+
@bucket.send(q).should == "quorum"
|
173
|
+
end
|
174
|
+
|
175
|
+
it "should set the #{q} quorum" do
|
176
|
+
@bucket.should_receive(:props=).with(hash_including("#{q}" => 1))
|
177
|
+
@bucket.send("#{q}=",1)
|
178
|
+
end
|
179
|
+
end
|
180
|
+
end
|
181
|
+
|
182
|
+
describe "checking whether a key exists" do
|
183
|
+
it "should return true if the object does exist" do
|
184
|
+
@backend.should_receive(:fetch_object).and_return(mock)
|
185
|
+
@bucket.exists?("foo").should be_true
|
186
|
+
end
|
187
|
+
|
188
|
+
it "should return false if the object doesn't exist" do
|
189
|
+
@backend.should_receive(:fetch_object).and_raise(Riak::HTTPFailedRequest.new(:get, [200,300], 404, {}, "not found"))
|
190
|
+
@bucket.exists?("foo").should be_false
|
191
|
+
end
|
192
|
+
end
|
193
|
+
|
194
|
+
describe "deleting an object" do
|
195
|
+
it "should delete a key from within the bucket" do
|
196
|
+
@backend.should_receive(:delete_object).with(@bucket, "bar", nil)
|
197
|
+
@bucket.delete('bar')
|
198
|
+
end
|
199
|
+
|
200
|
+
it "should use the specified RW quorum" do
|
201
|
+
@backend.should_receive(:delete_object).with(@bucket, "bar", "all")
|
202
|
+
@bucket.delete('bar', :rw => "all")
|
203
|
+
end
|
204
|
+
end
|
205
|
+
end
|
@@ -0,0 +1,517 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Riak::Client do
|
4
|
+
describe "when initializing" do
|
5
|
+
it "should default to the local interface on port 8098 (8087 for protobuffs)" do
|
6
|
+
client = Riak::Client.new
|
7
|
+
client.host.should == "127.0.0.1"
|
8
|
+
client.http_port.should == 8098
|
9
|
+
client.pb_port.should == 8087
|
10
|
+
end
|
11
|
+
|
12
|
+
it "should accept a protocol" do
|
13
|
+
client = Riak::Client.new :protocol => 'https'
|
14
|
+
client.protocol.should eq('https')
|
15
|
+
end
|
16
|
+
|
17
|
+
it "should accept a host" do
|
18
|
+
client = Riak::Client.new :host => "riak.basho.com"
|
19
|
+
client.host.should == "riak.basho.com"
|
20
|
+
end
|
21
|
+
|
22
|
+
it "should accept an HTTP port" do
|
23
|
+
client = Riak::Client.new :http_port => 9000
|
24
|
+
client.http_port.should == 9000
|
25
|
+
end
|
26
|
+
|
27
|
+
it "should accept a Protobuffs port" do
|
28
|
+
client = Riak::Client.new :pb_port => 9000
|
29
|
+
client.pb_port.should == 9000
|
30
|
+
end
|
31
|
+
|
32
|
+
it "should warn on setting :port" do
|
33
|
+
# TODO: make a deprecation utility class/module instead
|
34
|
+
client = Riak::Client.allocate
|
35
|
+
client.should_receive(:warn).and_return(true)
|
36
|
+
client.send :initialize, :port => 9000
|
37
|
+
end
|
38
|
+
|
39
|
+
it "should accept basic_auth" do
|
40
|
+
client = Riak::Client.new :basic_auth => "user:pass"
|
41
|
+
client.basic_auth.should eq("user:pass")
|
42
|
+
end
|
43
|
+
|
44
|
+
it "should accept a client ID" do
|
45
|
+
client = Riak::Client.new :client_id => "AAAAAA=="
|
46
|
+
client.client_id.should == "AAAAAA=="
|
47
|
+
end
|
48
|
+
|
49
|
+
it "should create a client ID if not specified" do
|
50
|
+
Riak::Client.new.client_id.should_not be_nil
|
51
|
+
end
|
52
|
+
|
53
|
+
it "should accept a path prefix" do
|
54
|
+
client = Riak::Client.new(:prefix => "/jiak/")
|
55
|
+
client.prefix.should == "/jiak/"
|
56
|
+
end
|
57
|
+
|
58
|
+
it "should default the prefix to /riak/ if not specified" do
|
59
|
+
Riak::Client.new.prefix.should == "/riak/"
|
60
|
+
end
|
61
|
+
|
62
|
+
it "should accept a mapreduce path" do
|
63
|
+
client = Riak::Client.new(:mapred => "/mr")
|
64
|
+
client.mapred.should == "/mr"
|
65
|
+
end
|
66
|
+
|
67
|
+
it "should default the mapreduce path to /mapred if not specified" do
|
68
|
+
Riak::Client.new.mapred.should == "/mapred"
|
69
|
+
end
|
70
|
+
|
71
|
+
it "should accept a luwak path" do
|
72
|
+
client = Riak::Client.new(:luwak => "/beans")
|
73
|
+
client.luwak.should == "/beans"
|
74
|
+
end
|
75
|
+
|
76
|
+
it "should default the luwak path to /luwak if not specified" do
|
77
|
+
Riak::Client.new.luwak.should == "/luwak"
|
78
|
+
end
|
79
|
+
|
80
|
+
it "should accept a solr path" do
|
81
|
+
client = Riak::Client.new(:solr => "/solar")
|
82
|
+
client.solr.should == "/solar"
|
83
|
+
end
|
84
|
+
end
|
85
|
+
|
86
|
+
it "should expose a Stamp object" do
|
87
|
+
subject.should respond_to(:stamp)
|
88
|
+
subject.stamp.should be_kind_of(Riak::Stamp)
|
89
|
+
end
|
90
|
+
|
91
|
+
describe "reconfiguring" do
|
92
|
+
before :each do
|
93
|
+
@client = Riak::Client.new
|
94
|
+
end
|
95
|
+
|
96
|
+
describe "setting the protocol" do
|
97
|
+
it "should allow setting the protocol" do
|
98
|
+
@client.should respond_to(:protocol=)
|
99
|
+
@client.protocol = "https"
|
100
|
+
@client.protocol.should eq("https")
|
101
|
+
end
|
102
|
+
|
103
|
+
it "should require a valid protocol to be set" do
|
104
|
+
lambda { @client.protocol = 'invalid-protocol' }.should(
|
105
|
+
raise_error(ArgumentError, /^'invalid-protocol' is not a valid protocol/))
|
106
|
+
end
|
107
|
+
|
108
|
+
it "should reset the unified backend when changing the protocol" do
|
109
|
+
old = @client.backend
|
110
|
+
@client.protocol = "pbc"
|
111
|
+
old.should_not eq(@client.backend)
|
112
|
+
end
|
113
|
+
end
|
114
|
+
|
115
|
+
describe "setting the host" do
|
116
|
+
it "should allow setting the host" do
|
117
|
+
@client.should respond_to(:host=)
|
118
|
+
@client.host = "riak.basho.com"
|
119
|
+
@client.host.should == "riak.basho.com"
|
120
|
+
end
|
121
|
+
|
122
|
+
it "should require the host to be an IP or hostname" do
|
123
|
+
[238472384972, ""].each do |invalid|
|
124
|
+
lambda { @client.host = invalid }.should raise_error(ArgumentError)
|
125
|
+
end
|
126
|
+
["127.0.0.1", "10.0.100.5", "localhost", "otherhost.local", "riak.basho.com"].each do |valid|
|
127
|
+
lambda { @client.host = valid }.should_not raise_error
|
128
|
+
end
|
129
|
+
end
|
130
|
+
end
|
131
|
+
|
132
|
+
[:http, :pb].each do |protocol|
|
133
|
+
describe "setting the #{protocol} port" do
|
134
|
+
it "should allow setting the #{protocol} port" do
|
135
|
+
@client.should respond_to("#{protocol}_port=")
|
136
|
+
@client.send("#{protocol}_port=", 9000)
|
137
|
+
@client.send("#{protocol}_port").should == 9000
|
138
|
+
end
|
139
|
+
|
140
|
+
it "should require the port to be a valid number" do
|
141
|
+
[-1,65536,"foo"].each do |invalid|
|
142
|
+
lambda { @client.send("#{protocol}_port=",invalid) }.should raise_error(ArgumentError)
|
143
|
+
end
|
144
|
+
[0,1,65535,8098].each do |valid|
|
145
|
+
lambda { @client.send("#{protocol}_port=", valid) }.should_not raise_error
|
146
|
+
end
|
147
|
+
end
|
148
|
+
end
|
149
|
+
end
|
150
|
+
|
151
|
+
describe "setting the port" do
|
152
|
+
before do
|
153
|
+
@client.stub!(:warn).and_return(true)
|
154
|
+
end
|
155
|
+
it "should raise a deprecation warning" do
|
156
|
+
@client.should_receive(:warn).and_return(true)
|
157
|
+
@client.port = 9000
|
158
|
+
end
|
159
|
+
|
160
|
+
it "should set the port for the selected protocol" do
|
161
|
+
@client.protocol = "pbc"
|
162
|
+
@client.port = 9000
|
163
|
+
@client.pb_port.should == 9000
|
164
|
+
end
|
165
|
+
end
|
166
|
+
|
167
|
+
describe "setting http auth" do
|
168
|
+
it "should allow setting basic_auth" do
|
169
|
+
@client.should respond_to(:basic_auth=)
|
170
|
+
@client.basic_auth = "user:pass"
|
171
|
+
@client.basic_auth.should eq("user:pass")
|
172
|
+
end
|
173
|
+
|
174
|
+
it "should require that basic auth splits into two even parts" do
|
175
|
+
lambda { @client.basic_auth ="user" }.should raise_error(ArgumentError, "basic auth must be set using 'user:pass'")
|
176
|
+
end
|
177
|
+
end
|
178
|
+
|
179
|
+
it "should allow setting the prefix" do
|
180
|
+
@client.should respond_to(:prefix=)
|
181
|
+
@client.prefix = "/another-prefix"
|
182
|
+
@client.prefix.should == "/another-prefix"
|
183
|
+
end
|
184
|
+
|
185
|
+
describe "setting the client id" do
|
186
|
+
it "should accept a string unmodified" do
|
187
|
+
@client.client_id = "foo"
|
188
|
+
@client.client_id.should == "foo"
|
189
|
+
end
|
190
|
+
|
191
|
+
it "should reject an integer equal to the maximum client id" do
|
192
|
+
lambda { @client.client_id = Riak::Client::MAX_CLIENT_ID }.should raise_error(ArgumentError)
|
193
|
+
end
|
194
|
+
|
195
|
+
it "should reject an integer larger than the maximum client id" do
|
196
|
+
lambda { @client.client_id = Riak::Client::MAX_CLIENT_ID + 1 }.should raise_error(ArgumentError)
|
197
|
+
end
|
198
|
+
end
|
199
|
+
end
|
200
|
+
|
201
|
+
describe "choosing an HTTP backend" do
|
202
|
+
before :each do
|
203
|
+
@client = Riak::Client.new
|
204
|
+
end
|
205
|
+
|
206
|
+
it "should choose the selected backend" do
|
207
|
+
@client.http_backend = :NetHTTP
|
208
|
+
@client.http.should be_instance_of(Riak::Client::NetHTTPBackend)
|
209
|
+
|
210
|
+
@client = Riak::Client.new
|
211
|
+
@client.http_backend = :Excon
|
212
|
+
@client.http.should be_instance_of(Riak::Client::ExconBackend)
|
213
|
+
end
|
214
|
+
|
215
|
+
it "should raise an error when the chosen backend is not valid" do
|
216
|
+
Riak::Client::NetHTTPBackend.should_receive(:configured?).and_return(false)
|
217
|
+
lambda { @client.http }.should raise_error
|
218
|
+
end
|
219
|
+
end
|
220
|
+
|
221
|
+
describe "choosing a Protobuffs backend" do
|
222
|
+
before :each do
|
223
|
+
@client = Riak::Client.new(:protocol => "pbc")
|
224
|
+
end
|
225
|
+
|
226
|
+
it "should choose the selected backend" do
|
227
|
+
@client.protobuffs_backend = :Beefcake
|
228
|
+
@client.protobuffs.should be_instance_of(Riak::Client::BeefcakeProtobuffsBackend)
|
229
|
+
end
|
230
|
+
|
231
|
+
it "should raise an error when the chosen backend is not valid" do
|
232
|
+
Riak::Client::BeefcakeProtobuffsBackend.should_receive(:configured?).and_return(false)
|
233
|
+
lambda { @client.protobuffs }.should raise_error
|
234
|
+
end
|
235
|
+
end
|
236
|
+
|
237
|
+
describe "choosing a unified backend" do
|
238
|
+
before :each do
|
239
|
+
@client = Riak::Client.new
|
240
|
+
end
|
241
|
+
|
242
|
+
it "should use HTTP when the protocol is http or https" do
|
243
|
+
%w[http https].each do |p|
|
244
|
+
@client.protocol = p
|
245
|
+
@client.backend.should be_kind_of(Riak::Client::HTTPBackend)
|
246
|
+
end
|
247
|
+
end
|
248
|
+
|
249
|
+
it "should use Protobuffs when the protocol is pbc" do
|
250
|
+
@client.protocol = "pbc"
|
251
|
+
@client.backend.should be_kind_of(Riak::Client::ProtobuffsBackend)
|
252
|
+
end
|
253
|
+
end
|
254
|
+
|
255
|
+
describe "retrieving a bucket" do
|
256
|
+
before :each do
|
257
|
+
@client = Riak::Client.new
|
258
|
+
@backend = mock("Backend")
|
259
|
+
@client.stub!(:backend).and_return(@backend)
|
260
|
+
end
|
261
|
+
|
262
|
+
it "should return a bucket object" do
|
263
|
+
@client.bucket("foo").should be_kind_of(Riak::Bucket)
|
264
|
+
end
|
265
|
+
|
266
|
+
it "should fetch bucket properties if asked" do
|
267
|
+
@backend.should_receive(:get_bucket_props) {|b| b.name.should == "foo"; {} }
|
268
|
+
@client.bucket("foo", :props => true)
|
269
|
+
end
|
270
|
+
|
271
|
+
it "should memoize bucket parameters" do
|
272
|
+
@bucket = mock("Bucket")
|
273
|
+
Riak::Bucket.should_receive(:new).with(@client, "baz").once.and_return(@bucket)
|
274
|
+
@client.bucket("baz").should == @bucket
|
275
|
+
@client.bucket("baz").should == @bucket
|
276
|
+
end
|
277
|
+
end
|
278
|
+
|
279
|
+
describe "listing buckets" do
|
280
|
+
before do
|
281
|
+
@client = Riak::Client.new
|
282
|
+
@backend = mock("Backend")
|
283
|
+
@client.stub!(:backend).and_return(@backend)
|
284
|
+
end
|
285
|
+
|
286
|
+
after { Riak.disable_list_keys_warnings = true }
|
287
|
+
|
288
|
+
it "should list buckets" do
|
289
|
+
@backend.should_receive(:list_buckets).and_return(%w{test test2})
|
290
|
+
buckets = @client.buckets
|
291
|
+
buckets.should have(2).items
|
292
|
+
buckets.should be_all {|b| b.is_a?(Riak::Bucket) }
|
293
|
+
buckets[0].name.should == "test"
|
294
|
+
buckets[1].name.should == "test2"
|
295
|
+
end
|
296
|
+
|
297
|
+
it "should warn about the expense of list-buckets when warnings are not disabled" do
|
298
|
+
Riak.disable_list_keys_warnings = false
|
299
|
+
@backend.stub!(:list_buckets).and_return(%w{test test2})
|
300
|
+
@client.should_receive(:warn)
|
301
|
+
@client.buckets
|
302
|
+
end
|
303
|
+
end
|
304
|
+
|
305
|
+
describe "Luwak (large-files) support" do
|
306
|
+
describe "storing a file" do
|
307
|
+
before :each do
|
308
|
+
@client = Riak::Client.new
|
309
|
+
@http = mock(Riak::Client::HTTPBackend)
|
310
|
+
@client.stub!(:http).and_return(@http)
|
311
|
+
end
|
312
|
+
|
313
|
+
it "should store the file in Luwak and return the key/filename when no filename is given" do
|
314
|
+
@http.should_receive(:post).with(201, "/luwak", anything, {"Content-Type" => "text/plain"}).and_return(:code => 201, :headers => {"location" => ["/luwak/123456789"]})
|
315
|
+
@client.store_file("text/plain", "Hello, world").should == "123456789"
|
316
|
+
end
|
317
|
+
|
318
|
+
it "should store the file in Luwak and return the key/filename when the filename is given" do
|
319
|
+
@http.should_receive(:put).with(204, "/luwak", "greeting.txt", anything, {"Content-Type" => "text/plain"}).and_return(:code => 204, :headers => {})
|
320
|
+
@client.store_file("greeting.txt", "text/plain", "Hello, world").should == "greeting.txt"
|
321
|
+
end
|
322
|
+
end
|
323
|
+
|
324
|
+
describe "retrieving a file" do
|
325
|
+
before :each do
|
326
|
+
@client = Riak::Client.new
|
327
|
+
@http = mock(Riak::Client::HTTPBackend)
|
328
|
+
@client.stub!(:http).and_return(@http)
|
329
|
+
@http.should_receive(:get).with(200, "/luwak", "greeting.txt").and_yield("Hello,").and_yield(" world!").and_return({:code => 200, :headers => {"content-type" => ["text/plain"]}})
|
330
|
+
end
|
331
|
+
|
332
|
+
it "should stream the data to a temporary file" do
|
333
|
+
file = @client.get_file("greeting.txt")
|
334
|
+
file.open {|f| f.read.should == "Hello, world!" }
|
335
|
+
end
|
336
|
+
|
337
|
+
it "should stream the data through the given block, returning nil" do
|
338
|
+
string = ""
|
339
|
+
result = @client.get_file("greeting.txt"){|chunk| string << chunk }
|
340
|
+
result.should be_nil
|
341
|
+
string.should == "Hello, world!"
|
342
|
+
end
|
343
|
+
|
344
|
+
it "should expose the original key and content-type on the temporary file" do
|
345
|
+
file = @client.get_file("greeting.txt")
|
346
|
+
file.content_type.should == "text/plain"
|
347
|
+
file.original_filename.should == "greeting.txt"
|
348
|
+
end
|
349
|
+
end
|
350
|
+
|
351
|
+
it "should delete a file" do
|
352
|
+
@client = Riak::Client.new
|
353
|
+
@http = mock(Riak::Client::HTTPBackend)
|
354
|
+
@client.stub!(:http).and_return(@http)
|
355
|
+
@http.should_receive(:delete).with([204,404], "/luwak", "greeting.txt")
|
356
|
+
@client.delete_file("greeting.txt")
|
357
|
+
end
|
358
|
+
|
359
|
+
it "should return true if the file exists" do
|
360
|
+
@client = Riak::Client.new
|
361
|
+
@client.http.should_receive(:head).and_return(:code => 200)
|
362
|
+
@client.file_exists?("foo").should be_true
|
363
|
+
end
|
364
|
+
|
365
|
+
it "should return false if the file doesn't exist" do
|
366
|
+
@client = Riak::Client.new
|
367
|
+
@client.http.should_receive(:head).and_return(:code => 404)
|
368
|
+
@client.file_exists?("foo").should be_false
|
369
|
+
end
|
370
|
+
|
371
|
+
it "should escape the filename when storing, retrieving or deleting files" do
|
372
|
+
@client = Riak::Client.new
|
373
|
+
@http = mock(Riak::Client::HTTPBackend)
|
374
|
+
@client.stub!(:http).and_return(@http)
|
375
|
+
# Delete escapes keys
|
376
|
+
@http.should_receive(:delete).with([204,404], "/luwak", "docs%2FA%20Big%20PDF.pdf")
|
377
|
+
@client.delete_file("docs/A Big PDF.pdf")
|
378
|
+
# Get escapes keys
|
379
|
+
@http.should_receive(:get).with(200, "/luwak", "docs%2FA%20Big%20PDF.pdf").and_yield("foo").and_return(:headers => {"content-type" => ["text/plain"]}, :code => 200)
|
380
|
+
@client.get_file("docs/A Big PDF.pdf")
|
381
|
+
# Streamed get escapes keys
|
382
|
+
@http.should_receive(:get).with(200, "/luwak", "docs%2FA%20Big%20PDF.pdf").and_yield("foo").and_return(:headers => {"content-type" => ["text/plain"]}, :code => 200)
|
383
|
+
@client.get_file("docs/A Big PDF.pdf"){|chunk| chunk}
|
384
|
+
# Put escapes keys
|
385
|
+
@http.should_receive(:put).with(204, "/luwak", "docs%2FA%20Big%20PDF.pdf", "foo", {"Content-Type" => "text/plain"})
|
386
|
+
@client.store_file("docs/A Big PDF.pdf", "text/plain", "foo")
|
387
|
+
end
|
388
|
+
end
|
389
|
+
|
390
|
+
describe "ssl", :ssl => true do
|
391
|
+
before :each do
|
392
|
+
@client = Riak::Client.new
|
393
|
+
end
|
394
|
+
|
395
|
+
it "should allow passing ssl options into the initializer" do
|
396
|
+
lambda { client = Riak::Client.new(:ssl => {:verify_mode => "peer"}) }.should_not raise_error
|
397
|
+
end
|
398
|
+
|
399
|
+
it "should not have ssl options by default" do
|
400
|
+
@client.ssl_options.should be_nil
|
401
|
+
end
|
402
|
+
|
403
|
+
it "should have a blank hash for ssl options if the protocol is set to https" do
|
404
|
+
@client.protocol = 'https'
|
405
|
+
@client.ssl_options.should be_a(Hash)
|
406
|
+
end
|
407
|
+
|
408
|
+
# The api should have an ssl= method for setting up all of the ssl
|
409
|
+
# options. Once the ssl options have been assigned via `ssl=` they should
|
410
|
+
# be read back out using the read only `ssl_options`. This is to provide
|
411
|
+
# a seperate api for setting ssl options via client configuration and
|
412
|
+
# reading them inside of a http backend.
|
413
|
+
it "should not allow reading ssl options via ssl" do
|
414
|
+
@client.should_not respond_to(:ssl)
|
415
|
+
end
|
416
|
+
|
417
|
+
it "should now allow writing ssl options via ssl_options=" do
|
418
|
+
@client.should_not respond_to(:ssl_options=)
|
419
|
+
end
|
420
|
+
|
421
|
+
it "should allow setting ssl to true" do
|
422
|
+
@client.ssl = true
|
423
|
+
@client.ssl_options[:verify_mode].should eq('none')
|
424
|
+
end
|
425
|
+
|
426
|
+
it "should allow setting ssl options as a hash" do
|
427
|
+
@client.ssl = {:verify_mode => "peer"}
|
428
|
+
@client.ssl_options[:verify_mode].should eq('peer')
|
429
|
+
end
|
430
|
+
|
431
|
+
it "should set the protocol to https when setting ssl to true" do
|
432
|
+
@client.ssl = true
|
433
|
+
@client.protocol.should eq("https")
|
434
|
+
end
|
435
|
+
|
436
|
+
it "should set the protocol to http when setting ssl to false" do
|
437
|
+
@client.protocol = 'https'
|
438
|
+
@client.ssl = false
|
439
|
+
@client.protocol.should eq('http')
|
440
|
+
end
|
441
|
+
|
442
|
+
it "should should clear ssl options when setting ssl to false" do
|
443
|
+
@client.ssl = true
|
444
|
+
@client.ssl_options.should_not be_nil
|
445
|
+
@client.ssl = false
|
446
|
+
@client.ssl_options.should be_nil
|
447
|
+
end
|
448
|
+
|
449
|
+
it "should set the protocol to https when setting ssl options" do
|
450
|
+
@client.ssl = {:verify_mode => "peer"}
|
451
|
+
@client.protocol.should eq("https")
|
452
|
+
end
|
453
|
+
|
454
|
+
it "should allow setting the verify_mode to none" do
|
455
|
+
@client.ssl = {:verify_mode => "none"}
|
456
|
+
@client.ssl_options[:verify_mode].should eq("none")
|
457
|
+
end
|
458
|
+
|
459
|
+
it "should allow setting the verify_mode to peer" do
|
460
|
+
@client.ssl = {:verify_mode => "peer"}
|
461
|
+
@client.ssl_options[:verify_mode].should eq("peer")
|
462
|
+
end
|
463
|
+
|
464
|
+
it "should not allow setting the verify_mode to anything else" do
|
465
|
+
lambda {@client.ssl = {:verify_mode => :your_mom}}.should raise_error(ArgumentError)
|
466
|
+
end
|
467
|
+
|
468
|
+
it "should default verify_mode to none" do
|
469
|
+
@client.ssl = true
|
470
|
+
@client.ssl_options[:verify_mode].should eq("none")
|
471
|
+
end
|
472
|
+
|
473
|
+
it "should let the backend know if ssl is enabled" do
|
474
|
+
@client.should_not be_ssl_enabled
|
475
|
+
@client.ssl = true
|
476
|
+
@client.should be_ssl_enabled
|
477
|
+
end
|
478
|
+
|
479
|
+
it "should allow setting the pem" do
|
480
|
+
@client.ssl = {:pem => 'i-am-a-pem'}
|
481
|
+
@client.ssl_options[:pem].should eq('i-am-a-pem')
|
482
|
+
end
|
483
|
+
|
484
|
+
it "should set them pem from the contents of pem_file" do
|
485
|
+
filepath = File.expand_path(File.join(File.dirname(__FILE__), '../fixtures/test.pem'))
|
486
|
+
@client.ssl = {:pem_file => filepath}
|
487
|
+
@client.ssl_options[:pem].should eq("i-am-a-pem\n")
|
488
|
+
end
|
489
|
+
|
490
|
+
it "should allow setting the pem_password" do
|
491
|
+
@client.ssl = {:pem_password => 'pem-pass'}
|
492
|
+
@client.ssl_options[:pem_password].should eq('pem-pass')
|
493
|
+
end
|
494
|
+
|
495
|
+
it "should allow setting the ca_file" do
|
496
|
+
@client.ssl = {:ca_file => '/path/to/ca.crt'}
|
497
|
+
@client.ssl_options[:ca_file].should eq('/path/to/ca.crt')
|
498
|
+
end
|
499
|
+
|
500
|
+
it "should allow setting the ca_path" do
|
501
|
+
@client.ssl = {:ca_path => '/path/to/certs/'}
|
502
|
+
@client.ssl_options[:ca_path].should eq('/path/to/certs/')
|
503
|
+
end
|
504
|
+
|
505
|
+
%w[pem ca_file ca_path].each do |option|
|
506
|
+
it "should default the verify_mode to peer when setting the #{option}" do
|
507
|
+
@client.ssl = {option.to_sym => 'test-data'}
|
508
|
+
@client.ssl_options[:verify_mode].should eq("peer")
|
509
|
+
end
|
510
|
+
|
511
|
+
it "should allow setting the verify mode when setting the #{option}" do
|
512
|
+
@client.ssl = {option.to_sym => 'test-data', :verify_mode => "none"}
|
513
|
+
@client.ssl_options[:verify_mode].should eq("none")
|
514
|
+
end
|
515
|
+
end
|
516
|
+
end
|
517
|
+
end
|