riak-client 2.0.0.rc1 → 2.0.0.rc2
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/Gemfile +0 -4
- data/README.markdown +10 -1
- data/Rakefile +1 -1
- data/lib/riak/client/beefcake/socket.rb +30 -13
- data/lib/riak/client/beefcake_protobuffs_backend.rb +10 -1
- data/lib/riak/client.rb +2 -0
- data/lib/riak/crdt/base.rb +24 -0
- data/lib/riak/crdt/counter.rb +7 -0
- data/lib/riak/crdt/inner_counter.rb +7 -0
- data/lib/riak/crdt/inner_map.rb +22 -0
- data/lib/riak/crdt/inner_set.rb +7 -0
- data/lib/riak/crdt/map.rb +31 -2
- data/lib/riak/crdt/set.rb +7 -0
- data/lib/riak/crdt/typed_collection.rb +47 -0
- data/lib/riak/errors/connection_error.rb +6 -0
- data/lib/riak/locale/en.yml +2 -0
- data/lib/riak/version.rb +1 -1
- data/riak-client.gemspec +2 -2
- data/spec/integration/riak/crdt_spec.rb +26 -6
- data/spec/integration/riak/protobuffs/interrupted_request_spec.rb +33 -0
- data/spec/integration/riak/secondary_index_spec.rb +54 -0
- data/spec/integration/riak/security_spec.rb +9 -3
- data/spec/riak/client_spec.rb +45 -0
- data/spec/support/test_client.yml +10 -7
- metadata +13 -11
- data/spec/riak/beefcake_protobuffs_backend/socket_spec.rb +0 -151
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 6c5f3295a8250149c86f2b932a13f015621d42e5
|
4
|
+
data.tar.gz: 22dca3a33f295d67ada447302bcff4aed5bce2bf
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: d4299561b7b0bd8ee05ee6e1f776e2ca9039d36e09761de4ae0e8dab16ad13633ef2392f2254232dbb9aad5225b0b5f81fc6d49518f63aa2285c1188147e9e37
|
7
|
+
data.tar.gz: 597699ef5a0f67ad7267d2cbce4524ca525639ebecc7475ed927b1f40b338d39857f1cf279362ff579cefe8ac09fbfdcd2643daddb3541c1b132ebda5e096185
|
data/Gemfile
CHANGED
data/README.markdown
CHANGED
@@ -1,4 +1,4 @@
|
|
1
|
-
# Riak Ruby Client (riak-client)
|
1
|
+
# Riak Ruby Client (riak-client)
|
2
2
|
|
3
3
|
`riak-client` is a rich Ruby client/toolkit for Riak, Basho's
|
4
4
|
distributed database that contains a basic wrapper around typical
|
@@ -10,6 +10,15 @@ and map-reduce.
|
|
10
10
|
Ruby 1.9.3, 2.0, and 2.1 are supported. JRuby in 1.9 and 2.0 modes are
|
11
11
|
also supported. `riak-client` is not compatible with Ruby 1.8.
|
12
12
|
|
13
|
+
In JRuby 1.7.13, OCSP validation is absent, and CRL validation always
|
14
|
+
fails. [This issue is being tracked][1] and this document will be updated when
|
15
|
+
it is fixed. Additionally, client certificate authentication doesn't work in
|
16
|
+
JRuby. [This issue is also being tracked][2], and this document will be updated
|
17
|
+
when it works.
|
18
|
+
|
19
|
+
[1]: https://github.com/jruby/jruby-openssl/issues/5
|
20
|
+
[2]: https://github.com/basho/riak_api/issues/65
|
21
|
+
|
13
22
|
`riak-client` requires i18n, builder, beefcake, and multi_json. The
|
14
23
|
cache store implementation requires ActiveSupport 3 or later.
|
15
24
|
|
data/Rakefile
CHANGED
@@ -1,5 +1,5 @@
|
|
1
1
|
require 'openssl'
|
2
|
-
require '
|
2
|
+
require 'cert_validator'
|
3
3
|
require 'riak/client/beefcake/messages'
|
4
4
|
require 'riak/errors/connection_error'
|
5
5
|
|
@@ -62,7 +62,11 @@ module Riak
|
|
62
62
|
|
63
63
|
private
|
64
64
|
def riak_cert
|
65
|
-
@riak_cert ||=
|
65
|
+
@riak_cert ||= @tls.peer_cert
|
66
|
+
end
|
67
|
+
|
68
|
+
def ca_cert
|
69
|
+
@ca_cert ||= @tls.peer_cert_chain[1]
|
66
70
|
end
|
67
71
|
|
68
72
|
# Set up an SSL context with appropriate defaults for Riak TLS
|
@@ -70,8 +74,8 @@ module Riak
|
|
70
74
|
@context = OpenSSL::SSL::SSLContext.new
|
71
75
|
|
72
76
|
# Replace insecure defaults
|
73
|
-
@context.ssl_version = @auth[:ssl_version] ||
|
74
|
-
@context.verify_mode = @auth[:verify_mode] || OpenSSL::SSL::VERIFY_PEER
|
77
|
+
@context.ssl_version = (@auth[:ssl_version] || default_ssl_version).to_sym
|
78
|
+
@context.verify_mode = (@auth[:verify_mode] || OpenSSL::SSL::VERIFY_PEER).to_i
|
75
79
|
|
76
80
|
cert_ify
|
77
81
|
key_ify
|
@@ -82,6 +86,18 @@ module Riak
|
|
82
86
|
end
|
83
87
|
end
|
84
88
|
|
89
|
+
# Choose the most secure SSL version available
|
90
|
+
def default_ssl_version
|
91
|
+
available = OpenSSL::SSL::SSLContext::METHODS
|
92
|
+
selected = %w{TLSv1_2_client TLSv1_1_client TLSv1.1 TLSv1_client TLS}.detect do |v|
|
93
|
+
available.include? v.to_sym
|
94
|
+
end
|
95
|
+
|
96
|
+
raise TlsError::SslVersionConfigurationError.new unless selected
|
97
|
+
|
98
|
+
return selected
|
99
|
+
end
|
100
|
+
|
85
101
|
# Convert cert and client_ca fields to X509 Certs
|
86
102
|
def cert_ify
|
87
103
|
%w{ cert client_ca }.each do |k|
|
@@ -150,23 +166,24 @@ module Riak
|
|
150
166
|
# Validate the TLS session
|
151
167
|
def validate_session
|
152
168
|
if @auth[:verify_hostname] &&
|
153
|
-
!OpenSSL::SSL::verify_certificate_identity(riak_cert
|
169
|
+
!OpenSSL::SSL::verify_certificate_identity(riak_cert, @host)
|
154
170
|
raise TlsError::CertHostMismatchError.new
|
155
171
|
end
|
156
172
|
|
157
|
-
unless riak_cert.
|
173
|
+
unless (riak_cert.not_before..riak_cert.not_after).cover? Time.now
|
158
174
|
raise TlsError::CertNotValidError.new
|
159
175
|
end
|
160
176
|
|
161
|
-
validator =
|
177
|
+
validator = CertValidator.new riak_cert, ca_cert
|
162
178
|
|
163
|
-
|
164
|
-
|
165
|
-
|
166
|
-
|
179
|
+
validator.crl = try_load @auth[:crl_file] if @auth[:crl_file]
|
180
|
+
|
181
|
+
if @auth[:crl]
|
182
|
+
raise TlsError::CertRevokedError.new unless validator.crl_valid?
|
183
|
+
end
|
167
184
|
|
168
|
-
|
169
|
-
raise TlsError::CertRevokedError.new
|
185
|
+
if @auth[:ocsp]
|
186
|
+
raise TlsError::CertRevokedError.new unless validator.ocsp_valid?
|
170
187
|
end
|
171
188
|
end
|
172
189
|
|
@@ -25,7 +25,16 @@ module Riak
|
|
25
25
|
|
26
26
|
def protocol
|
27
27
|
p = Protocol.new socket
|
28
|
-
|
28
|
+
in_request = false
|
29
|
+
result = nil
|
30
|
+
begin
|
31
|
+
in_request = true
|
32
|
+
result = yield p
|
33
|
+
in_request = false
|
34
|
+
ensure
|
35
|
+
reset_socket if in_request
|
36
|
+
end
|
37
|
+
return result
|
29
38
|
end
|
30
39
|
|
31
40
|
def new_socket
|
data/lib/riak/client.rb
CHANGED
@@ -5,6 +5,7 @@ require 'riak'
|
|
5
5
|
require 'riak/util/translation'
|
6
6
|
require 'riak/util/escape'
|
7
7
|
require 'riak/errors/failed_request'
|
8
|
+
require 'riak/errors/protobuffs_error'
|
8
9
|
require 'riak/client/decaying'
|
9
10
|
require 'riak/client/node'
|
10
11
|
require 'riak/client/search'
|
@@ -43,6 +44,7 @@ module Riak
|
|
43
44
|
Errno::ENETUNREACH,
|
44
45
|
SocketError,
|
45
46
|
SystemCallError,
|
47
|
+
Riak::ProtobuffsFailedHeader,
|
46
48
|
]
|
47
49
|
|
48
50
|
Pool = ::Innertube::Pool
|
data/lib/riak/crdt/base.rb
CHANGED
@@ -52,6 +52,30 @@ module Riak
|
|
52
52
|
def context?
|
53
53
|
!!@context
|
54
54
|
end
|
55
|
+
|
56
|
+
def pretty_print(pp)
|
57
|
+
pp.object_group self do
|
58
|
+
pp.breakable
|
59
|
+
pp.text "bucket_type=#{@bucket_type}"
|
60
|
+
pp.comma_breakable
|
61
|
+
pp.text "bucket=#{@bucket.name}"
|
62
|
+
pp.comma_breakable
|
63
|
+
pp.text "key=#{@key}"
|
64
|
+
|
65
|
+
yield
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
69
|
+
def pretty_print_cycle(pp)
|
70
|
+
pp.object_group self do
|
71
|
+
pp.breakable
|
72
|
+
pp.text "#{@bucket_type}/#{@bucket.name}/#{@key}"
|
73
|
+
end
|
74
|
+
end
|
75
|
+
|
76
|
+
def inspect_name
|
77
|
+
"#<#{self.class.name} bucket=#{@bucket.name} key=#{@key} type=#{@bucket_type}>"
|
78
|
+
end
|
55
79
|
|
56
80
|
private
|
57
81
|
def client
|
data/lib/riak/crdt/counter.rb
CHANGED
data/lib/riak/crdt/inner_map.rb
CHANGED
@@ -29,6 +29,28 @@ module Riak
|
|
29
29
|
@parent.operate(name, wrapped_operation)
|
30
30
|
end
|
31
31
|
|
32
|
+
def pretty_print(pp)
|
33
|
+
pp.object_group self do
|
34
|
+
%w{counters flags maps registers sets}.each do |h|
|
35
|
+
pp.comma_breakable
|
36
|
+
pp.text "#{h}="
|
37
|
+
pp.pp send h
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
def pretty_print_cycle(pp)
|
43
|
+
pp.text "InnerMap"
|
44
|
+
end
|
45
|
+
|
46
|
+
def to_value_h
|
47
|
+
%w{counters flags maps registers sets}.map do |k|
|
48
|
+
[k, send(k).to_value_h]
|
49
|
+
end.to_h
|
50
|
+
end
|
51
|
+
|
52
|
+
alias :value :to_value_h
|
53
|
+
|
32
54
|
# @api private
|
33
55
|
def self.delete
|
34
56
|
Operation::Delete.new.tap do |op|
|
data/lib/riak/crdt/inner_set.rb
CHANGED
data/lib/riak/crdt/map.rb
CHANGED
@@ -32,7 +32,11 @@ module Riak
|
|
32
32
|
def initialize(bucket, key, bucket_type=nil, options={})
|
33
33
|
super(bucket, key, bucket_type || DEFAULT_BUCKET_TYPES[:map], options)
|
34
34
|
|
35
|
-
|
35
|
+
if key
|
36
|
+
initialize_collections
|
37
|
+
else
|
38
|
+
initialize_blank_collections
|
39
|
+
end
|
36
40
|
end
|
37
41
|
|
38
42
|
# Maps are frequently updated in batches. Use this method to get a
|
@@ -57,6 +61,24 @@ module Riak
|
|
57
61
|
m.operate operation
|
58
62
|
end
|
59
63
|
end
|
64
|
+
|
65
|
+
def pretty_print(pp)
|
66
|
+
super pp do
|
67
|
+
%w{counters flags maps registers sets}.each do |h|
|
68
|
+
pp.comma_breakable
|
69
|
+
pp.text "#{h}="
|
70
|
+
pp.pp send h
|
71
|
+
end
|
72
|
+
end
|
73
|
+
end
|
74
|
+
|
75
|
+
def to_value_h
|
76
|
+
%w{counters flags maps registers sets}.map do |k|
|
77
|
+
[k, send(k).to_value_h]
|
78
|
+
end.to_h
|
79
|
+
end
|
80
|
+
|
81
|
+
alias :value :to_value_h
|
60
82
|
|
61
83
|
private
|
62
84
|
def vivify(data)
|
@@ -71,8 +93,12 @@ module Riak
|
|
71
93
|
reload if dirty?
|
72
94
|
end
|
73
95
|
|
96
|
+
def initialize_blank_collections
|
97
|
+
vivify counters: {}, flags: {}, maps: {}, registers: {}, sets: {}
|
98
|
+
end
|
99
|
+
|
74
100
|
def write_operations(operations, *args)
|
75
|
-
operator do |op|
|
101
|
+
result = operator do |op|
|
76
102
|
op.operate(bucket.name,
|
77
103
|
key,
|
78
104
|
bucket_type,
|
@@ -80,6 +106,9 @@ module Riak
|
|
80
106
|
*args
|
81
107
|
)
|
82
108
|
end
|
109
|
+
|
110
|
+
@key ||= result.key
|
111
|
+
|
83
112
|
# collections break dirty tracking
|
84
113
|
reload
|
85
114
|
end
|
data/lib/riak/crdt/set.rb
CHANGED
@@ -26,6 +26,45 @@ module Riak
|
|
26
26
|
end
|
27
27
|
end
|
28
28
|
|
29
|
+
def pretty_print(pp)
|
30
|
+
pp.object_group self do
|
31
|
+
pp.breakable
|
32
|
+
pp.text inspect_name
|
33
|
+
pp.comma_breakable
|
34
|
+
pp.text "parent="
|
35
|
+
@parent.pretty_print_cycle(pp)
|
36
|
+
pp.comma_breakable
|
37
|
+
pp.text "contents="
|
38
|
+
pp.pp @contents
|
39
|
+
end
|
40
|
+
# buf = []
|
41
|
+
# buf << inspect_name
|
42
|
+
# buf <<
|
43
|
+
# buf << "contents={#{inspect_contents}}"
|
44
|
+
# "#<#{self.class.name} #{buf.join ' '}>"
|
45
|
+
end
|
46
|
+
|
47
|
+
def pretty_print_cycle(pp)
|
48
|
+
pp.object_group self do
|
49
|
+
pp.breakable
|
50
|
+
@parent.pretty_print_cycle(pp)
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
def inspect_name
|
55
|
+
"contains=#{content_name}"
|
56
|
+
end
|
57
|
+
|
58
|
+
def pretty_print_contents(pp)
|
59
|
+
@contents.map do |k,v|
|
60
|
+
"#{k}=>#{v.inspect}"
|
61
|
+
end.join ', '
|
62
|
+
end
|
63
|
+
|
64
|
+
def content_name
|
65
|
+
@type.name
|
66
|
+
end
|
67
|
+
|
29
68
|
# @api private
|
30
69
|
def reparent(new_parent)
|
31
70
|
reparented = self.class.new(@type,
|
@@ -114,6 +153,14 @@ module Riak
|
|
114
153
|
!!@parent.context?
|
115
154
|
end
|
116
155
|
|
156
|
+
def to_value_h
|
157
|
+
return @contents unless NEEDS_NAME.include? @type
|
158
|
+
|
159
|
+
@contents.map do |k, v|
|
160
|
+
[k, v.value]
|
161
|
+
end.to_h
|
162
|
+
end
|
163
|
+
|
117
164
|
private
|
118
165
|
def normalize_key(unnormalized_key)
|
119
166
|
unnormalized_key.to_s
|
@@ -5,6 +5,12 @@ module Riak
|
|
5
5
|
end
|
6
6
|
|
7
7
|
class TlsError < ConnectionError
|
8
|
+
class SslVersionConfigurationError < TlsError
|
9
|
+
def initialize
|
10
|
+
super t('ssl.version_configuration_error')
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
8
14
|
class CertHostMismatchError < TlsError
|
9
15
|
def initialize
|
10
16
|
super t('ssl.cert_host_mismatch')
|
data/lib/riak/locale/en.yml
CHANGED
@@ -59,6 +59,7 @@ en:
|
|
59
59
|
pbc:
|
60
60
|
failed_header: "Failed to receive a header from Riak."
|
61
61
|
unexpected_eof: "Unexpected EOF on PBC socket"
|
62
|
+
unexpected_response: "Expected PBC %{expected}, got %{actual}."
|
62
63
|
user_not_username: "Authentication hash expects :user, not :username."
|
63
64
|
wanted_index_resp: "Expected IndexResp during secondary index query"
|
64
65
|
wanted_dt_fetch_resp: "Expected PBC DtFetchResp during CRDT fetch"
|
@@ -80,6 +81,7 @@ en:
|
|
80
81
|
read_data_error: "Tried to read cert or key from %{candidate}, caught error %{actual}."
|
81
82
|
unexpected_during_init: "Expected %{expected}, got %{actual} with body %{body} during SSL/TLS initialization."
|
82
83
|
unknown_key_type: "Can't figure out what the client key is. Expected it to be some kind of OpenSSL::PKey::PKey subclass, a filename string, or string data representing the key itself."
|
84
|
+
version_configuration_error: "Couldn't find a supported default ssl_version. Configure one that works with your version of Ruby."
|
83
85
|
stale_write_prevented: "Stale write prevented by client."
|
84
86
|
stored_function_invalid: "function must have :bucket and :key when a hash"
|
85
87
|
streaming_bucket_list_without_block: "Streaming bucket list was requested but no block was given."
|
data/lib/riak/version.rb
CHANGED
data/riak-client.gemspec
CHANGED
@@ -18,14 +18,14 @@ Gem::Specification.new do |gem|
|
|
18
18
|
gem.add_development_dependency "rspec", "~> 3.0.0"
|
19
19
|
gem.add_development_dependency 'rake', '~> 10.1.1'
|
20
20
|
gem.add_development_dependency 'yard', '~> 0.8.7'
|
21
|
-
gem.add_development_dependency '
|
21
|
+
gem.add_development_dependency 'kramdown', '~> 1.4'
|
22
22
|
gem.add_development_dependency 'simplecov', '~> 0.8.2'
|
23
23
|
|
24
24
|
gem.add_runtime_dependency "i18n", ">=0.4.0"
|
25
25
|
gem.add_runtime_dependency "beefcake", ">= 1.0.0.pre1"
|
26
26
|
gem.add_runtime_dependency "multi_json", "~>1.0"
|
27
27
|
gem.add_runtime_dependency "innertube", "~>1.0.2"
|
28
|
-
gem.add_runtime_dependency '
|
28
|
+
gem.add_runtime_dependency 'cert_validator', '~> 0.0.1'
|
29
29
|
|
30
30
|
# Files
|
31
31
|
|
@@ -20,12 +20,32 @@ describe "CRDTs", integration: true, test_client: true do
|
|
20
20
|
end
|
21
21
|
end
|
22
22
|
|
23
|
-
describe '
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
23
|
+
describe 'Riak-assigned names' do
|
24
|
+
describe 'an anonymous counter' do
|
25
|
+
subject { Riak::Crdt::Counter.new bucket, nil }
|
26
|
+
it 'accepts a Riak-assigned name' do
|
27
|
+
subject.increment
|
28
|
+
expect(subject.key).to be
|
29
|
+
expect(subject.value).to eq 1
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
describe 'an anonymous set' do
|
34
|
+
subject { Riak::Crdt::Set.new bucket, nil }
|
35
|
+
it 'accepts a Riak-assigned name' do
|
36
|
+
subject.add 'sandwich'
|
37
|
+
expect(subject.key).to be
|
38
|
+
expect(subject).to include 'sandwich'
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
describe 'an anonymous map' do
|
43
|
+
subject { Riak::Crdt::Map.new bucket, nil }
|
44
|
+
it 'accepts a Riak-assigned name' do
|
45
|
+
subject.registers['coat_pattern'] = 'tabby'
|
46
|
+
expect(subject.key).to be
|
47
|
+
expect(subject.registers['coat_pattern']).to eq 'tabby'
|
48
|
+
end
|
29
49
|
end
|
30
50
|
end
|
31
51
|
|
@@ -0,0 +1,33 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
require 'timeout'
|
3
|
+
|
4
|
+
describe 'Protocol Buffers', test_client: true do
|
5
|
+
describe 'interrupted requests' do
|
6
|
+
|
7
|
+
let(:bucket){ random_bucket 'interrupted_requests' }
|
8
|
+
|
9
|
+
before do
|
10
|
+
first = bucket.new 'first'
|
11
|
+
first.data = 'first'
|
12
|
+
first.content_type = 'text/plain'
|
13
|
+
first.store
|
14
|
+
|
15
|
+
second = bucket.new 'second'
|
16
|
+
second.data = 'second'
|
17
|
+
second.content_type = 'text/plain'
|
18
|
+
second.store
|
19
|
+
end
|
20
|
+
|
21
|
+
it 'fails out when a request is interrupted, and never returns the wrong payload' do
|
22
|
+
expect do
|
23
|
+
Timeout.timeout 1 do
|
24
|
+
loop do
|
25
|
+
expect(bucket.get('first').data).to eq 'first'
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end.to raise_error Timeout::Error
|
29
|
+
|
30
|
+
expect(bucket.get('second').data).to eq 'second'
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
@@ -0,0 +1,54 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe 'Secondary indexes', test_client: true, integration: true do
|
4
|
+
let(:bucket){ random_bucket '2i-integration' }
|
5
|
+
before do
|
6
|
+
50.times do |i|
|
7
|
+
bucket.new(i.to_s).tap do |obj|
|
8
|
+
obj.indexes["index_int"] << i
|
9
|
+
obj.indexes["index_bin"] << i.to_s
|
10
|
+
obj.data = [i]
|
11
|
+
obj.store
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
it "finds keys for an equality query" do
|
17
|
+
expect(bucket.get_index('index_int', 20)).to eq(["20"])
|
18
|
+
end
|
19
|
+
|
20
|
+
it "finds keys for a range query" do
|
21
|
+
expect(bucket.get_index('index_int', 19..21)).to match_array(["19","20", "21"])
|
22
|
+
end
|
23
|
+
|
24
|
+
it "returns an empty array for a query that does not match any keys" do
|
25
|
+
expect(bucket.get_index('index_int', 10000)).to eq([])
|
26
|
+
end
|
27
|
+
|
28
|
+
it "returns terms" do
|
29
|
+
results = nil
|
30
|
+
expect do
|
31
|
+
results = bucket.get_index('index_int',
|
32
|
+
19..21,
|
33
|
+
return_terms: true)
|
34
|
+
end.to_not raise_error
|
35
|
+
|
36
|
+
expect(results).to be_a Array
|
37
|
+
expect(results.with_terms).to be_a Hash
|
38
|
+
end
|
39
|
+
|
40
|
+
it "returns terms matching a term_regex" do
|
41
|
+
results = nil
|
42
|
+
expect do
|
43
|
+
results = bucket.get_index('index_bin',
|
44
|
+
'19'..'21',
|
45
|
+
return_terms: true,
|
46
|
+
term_regex: '20')
|
47
|
+
end.to_not raise_error
|
48
|
+
|
49
|
+
terms = results.with_terms
|
50
|
+
|
51
|
+
expect(terms['20']).to be
|
52
|
+
expect(terms['19']).to be_empty
|
53
|
+
end
|
54
|
+
end
|
@@ -1,7 +1,7 @@
|
|
1
1
|
require 'spec_helper'
|
2
2
|
require 'riak'
|
3
3
|
require 'riak/errors/connection_error'
|
4
|
-
require '
|
4
|
+
require 'cert_validator/errors'
|
5
5
|
|
6
6
|
describe 'Secure Protobuffs', test_client: true, integration: true do
|
7
7
|
let(:config){ test_client_configuration.dup }
|
@@ -59,9 +59,15 @@ describe 'Secure Protobuffs', test_client: true, integration: true do
|
|
59
59
|
it "refuses to connect if the server cert is revoked" do
|
60
60
|
revoked_auth_config = config.dup
|
61
61
|
revoked_auth_config[:authentication] = revoked_auth_config[:authentication].dup
|
62
|
-
|
62
|
+
|
63
63
|
revoked_auth_config[:authentication][:crl_file] =
|
64
|
-
File.expand_path(File.join(
|
64
|
+
File.expand_path(File.join('..',
|
65
|
+
'..',
|
66
|
+
'..',
|
67
|
+
'support',
|
68
|
+
'certs',
|
69
|
+
'server.crl'),
|
70
|
+
__FILE__)
|
65
71
|
revoked_auth_config[:authentication][:crl] = true
|
66
72
|
|
67
73
|
revoked_auth_client = Riak::Client.new revoked_auth_config
|
data/spec/riak/client_spec.rb
CHANGED
@@ -1,4 +1,5 @@
|
|
1
1
|
require 'spec_helper'
|
2
|
+
require 'riak/errors/protobuffs_error'
|
2
3
|
|
3
4
|
describe Riak::Client, test_client: true do
|
4
5
|
describe "when initializing" do
|
@@ -27,6 +28,16 @@ describe Riak::Client, test_client: true do
|
|
27
28
|
it "should create a client ID if not specified" do
|
28
29
|
expect(Riak::Client.new(pb_port: test_client.nodes.first.pb_port).client_id).not_to be_nil
|
29
30
|
end
|
31
|
+
|
32
|
+
it "should accept multiple nodes" do
|
33
|
+
client = Riak::Client.new :nodes => [
|
34
|
+
{:host => 'riak1.basho.com'},
|
35
|
+
{:host => 'riak2.basho.com', :pb_port => 1234},
|
36
|
+
{:host => 'riak3.basho.com', :pb_port => 5678}
|
37
|
+
]
|
38
|
+
expect(client.nodes.size).to eq(3)
|
39
|
+
expect(client.nodes.first.host).to eq("riak1.basho.com")
|
40
|
+
end
|
30
41
|
end
|
31
42
|
|
32
43
|
it "should expose a Stamp object" do
|
@@ -173,4 +184,38 @@ describe Riak::Client, test_client: true do
|
|
173
184
|
expect(buckets.size).to eq(2)
|
174
185
|
end
|
175
186
|
end
|
187
|
+
|
188
|
+
describe "when receiving errors from the backend"
|
189
|
+
before do
|
190
|
+
@client = Riak::Client.new
|
191
|
+
end
|
192
|
+
|
193
|
+
it "should retry on recoverable errors" do
|
194
|
+
call_count = 0
|
195
|
+
|
196
|
+
begin
|
197
|
+
@client.backend do |b|
|
198
|
+
call_count += 1
|
199
|
+
raise Riak::ProtobuffsFailedHeader
|
200
|
+
end
|
201
|
+
rescue RuntimeError
|
202
|
+
end
|
203
|
+
|
204
|
+
expect(call_count).to eq(3)
|
205
|
+
end
|
206
|
+
|
207
|
+
it "should throw a RuntimeError if it runs out of retries" do
|
208
|
+
error = nil
|
209
|
+
begin
|
210
|
+
@client.backend do |b|
|
211
|
+
raise Riak::ProtobuffsFailedHeader
|
212
|
+
end
|
213
|
+
rescue RuntimeError => e
|
214
|
+
error = e
|
215
|
+
end
|
216
|
+
|
217
|
+
expect(error).not_to be_nil
|
218
|
+
expect(error).to be_instance_of(RuntimeError)
|
219
|
+
end
|
220
|
+
|
176
221
|
end
|
@@ -1,7 +1,10 @@
|
|
1
|
-
#
|
2
|
-
|
3
|
-
|
4
|
-
#
|
5
|
-
#
|
6
|
-
#
|
7
|
-
#
|
1
|
+
# This file is used for configuring test_client used by
|
2
|
+
# many of the integration tests.
|
3
|
+
#
|
4
|
+
# Simply set the arguments you'd normally pass to
|
5
|
+
# Riak::Client.new in the file.
|
6
|
+
#
|
7
|
+
# Don't run multiple nodes, integration tests include
|
8
|
+
# quorum checks that may result in race conditions.
|
9
|
+
|
10
|
+
pb_port: 17017
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: riak-client
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 2.0.0.
|
4
|
+
version: 2.0.0.rc2
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Sean Cribbs
|
@@ -9,7 +9,7 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2014-
|
12
|
+
date: 2014-09-02 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: rspec
|
@@ -54,19 +54,19 @@ dependencies:
|
|
54
54
|
- !ruby/object:Gem::Version
|
55
55
|
version: 0.8.7
|
56
56
|
- !ruby/object:Gem::Dependency
|
57
|
-
name:
|
57
|
+
name: kramdown
|
58
58
|
requirement: !ruby/object:Gem::Requirement
|
59
59
|
requirements:
|
60
60
|
- - "~>"
|
61
61
|
- !ruby/object:Gem::Version
|
62
|
-
version:
|
62
|
+
version: '1.4'
|
63
63
|
type: :development
|
64
64
|
prerelease: false
|
65
65
|
version_requirements: !ruby/object:Gem::Requirement
|
66
66
|
requirements:
|
67
67
|
- - "~>"
|
68
68
|
- !ruby/object:Gem::Version
|
69
|
-
version:
|
69
|
+
version: '1.4'
|
70
70
|
- !ruby/object:Gem::Dependency
|
71
71
|
name: simplecov
|
72
72
|
requirement: !ruby/object:Gem::Requirement
|
@@ -138,19 +138,19 @@ dependencies:
|
|
138
138
|
- !ruby/object:Gem::Version
|
139
139
|
version: 1.0.2
|
140
140
|
- !ruby/object:Gem::Dependency
|
141
|
-
name:
|
141
|
+
name: cert_validator
|
142
142
|
requirement: !ruby/object:Gem::Requirement
|
143
143
|
requirements:
|
144
144
|
- - "~>"
|
145
145
|
- !ruby/object:Gem::Version
|
146
|
-
version: 0.0.
|
146
|
+
version: 0.0.1
|
147
147
|
type: :runtime
|
148
148
|
prerelease: false
|
149
149
|
version_requirements: !ruby/object:Gem::Requirement
|
150
150
|
requirements:
|
151
151
|
- - "~>"
|
152
152
|
- !ruby/object:Gem::Version
|
153
|
-
version: 0.0.
|
153
|
+
version: 0.0.1
|
154
154
|
description: riak-client is a rich client for Riak, the distributed database by Basho.
|
155
155
|
It supports the full HTTP and Protocol Buffers interfaces including storage operations,
|
156
156
|
bucket configuration, link-walking, secondary indexes and map-reduce.
|
@@ -262,7 +262,9 @@ files:
|
|
262
262
|
- spec/integration/riak/crdt_spec.rb
|
263
263
|
- spec/integration/riak/crdt_validation/map_spec.rb
|
264
264
|
- spec/integration/riak/crdt_validation/set_spec.rb
|
265
|
+
- spec/integration/riak/protobuffs/interrupted_request_spec.rb
|
265
266
|
- spec/integration/riak/protobuffs_backends_spec.rb
|
267
|
+
- spec/integration/riak/secondary_index_spec.rb
|
266
268
|
- spec/integration/riak/security_spec.rb
|
267
269
|
- spec/integration/riak/threading_spec.rb
|
268
270
|
- spec/integration/yokozuna/index_spec.rb
|
@@ -271,7 +273,6 @@ files:
|
|
271
273
|
- spec/riak/beefcake_protobuffs_backend/crdt_operator_spec.rb
|
272
274
|
- spec/riak/beefcake_protobuffs_backend/object_methods_spec.rb
|
273
275
|
- spec/riak/beefcake_protobuffs_backend/protocol_spec.rb
|
274
|
-
- spec/riak/beefcake_protobuffs_backend/socket_spec.rb
|
275
276
|
- spec/riak/beefcake_protobuffs_backend_spec.rb
|
276
277
|
- spec/riak/bucket_spec.rb
|
277
278
|
- spec/riak/client_spec.rb
|
@@ -340,7 +341,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
340
341
|
version: 1.3.1
|
341
342
|
requirements: []
|
342
343
|
rubyforge_project:
|
343
|
-
rubygems_version: 2.
|
344
|
+
rubygems_version: 2.2.0
|
344
345
|
signing_key:
|
345
346
|
specification_version: 4
|
346
347
|
summary: riak-client is a rich client for Riak, the distributed database by Basho.
|
@@ -362,7 +363,9 @@ test_files:
|
|
362
363
|
- spec/integration/riak/crdt_spec.rb
|
363
364
|
- spec/integration/riak/crdt_validation/map_spec.rb
|
364
365
|
- spec/integration/riak/crdt_validation/set_spec.rb
|
366
|
+
- spec/integration/riak/protobuffs/interrupted_request_spec.rb
|
365
367
|
- spec/integration/riak/protobuffs_backends_spec.rb
|
368
|
+
- spec/integration/riak/secondary_index_spec.rb
|
366
369
|
- spec/integration/riak/security_spec.rb
|
367
370
|
- spec/integration/riak/threading_spec.rb
|
368
371
|
- spec/integration/yokozuna/index_spec.rb
|
@@ -371,7 +374,6 @@ test_files:
|
|
371
374
|
- spec/riak/beefcake_protobuffs_backend/crdt_operator_spec.rb
|
372
375
|
- spec/riak/beefcake_protobuffs_backend/object_methods_spec.rb
|
373
376
|
- spec/riak/beefcake_protobuffs_backend/protocol_spec.rb
|
374
|
-
- spec/riak/beefcake_protobuffs_backend/socket_spec.rb
|
375
377
|
- spec/riak/beefcake_protobuffs_backend_spec.rb
|
376
378
|
- spec/riak/bucket_spec.rb
|
377
379
|
- spec/riak/client_spec.rb
|
@@ -1,151 +0,0 @@
|
|
1
|
-
require 'spec_helper'
|
2
|
-
require 'riak/client/beefcake/socket'
|
3
|
-
|
4
|
-
describe Riak::Client::BeefcakeProtobuffsBackend::BeefcakeSocket do
|
5
|
-
let(:host){ 'host' }
|
6
|
-
let(:pb_port){ 8087 }
|
7
|
-
let(:tcp_socket_instance){ double 'TCPSocket' }
|
8
|
-
|
9
|
-
let(:ssl){ OpenSSL::SSL }
|
10
|
-
|
11
|
-
describe 'without authentication configured' do
|
12
|
-
let(:options){ Hash.new }
|
13
|
-
it 'should start a tcp connection and not start a tls connection' do
|
14
|
-
expect(TCPSocket).to receive(:new).
|
15
|
-
with(host, pb_port).
|
16
|
-
and_return(tcp_socket_instance)
|
17
|
-
|
18
|
-
expect(tcp_socket_instance).to receive(:setsockopt).
|
19
|
-
with(Socket::IPPROTO_TCP, Socket::TCP_NODELAY, true)
|
20
|
-
|
21
|
-
expect(ssl::SSLSocket).not_to receive(:new)
|
22
|
-
|
23
|
-
described_class.new host, pb_port
|
24
|
-
end
|
25
|
-
end
|
26
|
-
|
27
|
-
describe 'with authentication configured' do
|
28
|
-
let(:user){ 'user' }
|
29
|
-
let(:password){ 'password' }
|
30
|
-
let(:options) do
|
31
|
-
{
|
32
|
-
authentication: {
|
33
|
-
user: user,
|
34
|
-
password: password
|
35
|
-
}
|
36
|
-
}
|
37
|
-
end
|
38
|
-
let(:ssl_socket_instance){ double 'SSLSocket' }
|
39
|
-
let(:ssl_peer_cert){ double 'Peer Certificate' }
|
40
|
-
let(:r509_cert){ double 'R509::Cert' }
|
41
|
-
let(:rcv_instance){ double 'R509::Cert::Validator instance' }
|
42
|
-
|
43
|
-
it 'should start a tcp and a tls connection, and send authentication info' do
|
44
|
-
expect(TCPSocket).to receive(:new).
|
45
|
-
with(host, pb_port).
|
46
|
-
and_return(tcp_socket_instance)
|
47
|
-
|
48
|
-
expect(tcp_socket_instance).to receive(:setsockopt).
|
49
|
-
with(Socket::IPPROTO_TCP, Socket::TCP_NODELAY, true)
|
50
|
-
|
51
|
-
allow(tcp_socket_instance).to receive(:write)
|
52
|
-
|
53
|
-
# StartTls
|
54
|
-
expect(tcp_socket_instance).to receive(:read).
|
55
|
-
with(5).
|
56
|
-
and_return([1, 255].pack 'NC')
|
57
|
-
|
58
|
-
expect(ssl::SSLSocket).to receive(:new).
|
59
|
-
with(tcp_socket_instance, kind_of(OpenSSL::SSL::SSLContext)).
|
60
|
-
and_return(ssl_socket_instance)
|
61
|
-
|
62
|
-
expect(ssl_socket_instance).to receive(:connect)
|
63
|
-
|
64
|
-
allow(ssl_socket_instance).to receive(:write)
|
65
|
-
|
66
|
-
expect(ssl_socket_instance).to receive(:peer_cert).
|
67
|
-
and_return(ssl_peer_cert)
|
68
|
-
expect(R509::Cert).to receive(:new).
|
69
|
-
with(cert: ssl_peer_cert).
|
70
|
-
and_return(r509_cert)
|
71
|
-
allow(r509_cert).to receive(:valid?).and_return(true)
|
72
|
-
expect(R509::Cert::Validator).to receive(:new).
|
73
|
-
with(r509_cert).
|
74
|
-
and_return(rcv_instance)
|
75
|
-
|
76
|
-
expect(rcv_instance).to receive(:validate).
|
77
|
-
with(ocsp: false, crl: false, crl_file: nil).
|
78
|
-
and_return(true)
|
79
|
-
|
80
|
-
# AuthResp
|
81
|
-
expect(ssl_socket_instance).to receive(:read).
|
82
|
-
with(5).
|
83
|
-
and_return([1, 254].pack 'NC')
|
84
|
-
|
85
|
-
# PingResp
|
86
|
-
expect(ssl_socket_instance).to receive(:read).
|
87
|
-
with(5).
|
88
|
-
and_return([1, 2].pack 'NC')
|
89
|
-
|
90
|
-
described_class.new host, pb_port, options
|
91
|
-
end
|
92
|
-
|
93
|
-
it 'should pass pass TLS options through to OpenSSL' do
|
94
|
-
options[:authentication][:ca_file] = 'spec/support/certs/ca.crt'
|
95
|
-
options[:authentication][:key] = 'spec/support/certs/client.key'
|
96
|
-
|
97
|
-
expect(TCPSocket).to receive(:new).
|
98
|
-
with(host, pb_port).
|
99
|
-
and_return(tcp_socket_instance)
|
100
|
-
|
101
|
-
expect(tcp_socket_instance).to receive(:setsockopt).
|
102
|
-
with(Socket::IPPROTO_TCP, Socket::TCP_NODELAY, true)
|
103
|
-
|
104
|
-
allow(tcp_socket_instance).to receive(:write)
|
105
|
-
|
106
|
-
# StartTls
|
107
|
-
expect(tcp_socket_instance).to receive(:read).
|
108
|
-
with(5).
|
109
|
-
and_return([1, 255].pack 'NC')
|
110
|
-
|
111
|
-
expect(ssl::SSLSocket).to receive(:new) do |sock, ctx|
|
112
|
-
expect(sock).to eq tcp_socket_instance
|
113
|
-
expect(ctx).to be_a OpenSSL::SSL::SSLContext
|
114
|
-
expect(ctx.key).to be_a OpenSSL::PKey::PKey
|
115
|
-
expect(ctx.ca_file).to eq 'spec/support/certs/ca.crt'
|
116
|
-
|
117
|
-
ssl_socket_instance
|
118
|
-
end
|
119
|
-
|
120
|
-
expect(ssl_socket_instance).to receive(:connect)
|
121
|
-
|
122
|
-
allow(ssl_socket_instance).to receive(:write)
|
123
|
-
|
124
|
-
expect(ssl_socket_instance).to receive(:peer_cert).
|
125
|
-
and_return(ssl_peer_cert)
|
126
|
-
expect(R509::Cert).to receive(:new).
|
127
|
-
with(cert: ssl_peer_cert).
|
128
|
-
and_return(r509_cert)
|
129
|
-
allow(r509_cert).to receive(:valid?).and_return(true)
|
130
|
-
expect(R509::Cert::Validator).to receive(:new).
|
131
|
-
with(r509_cert).
|
132
|
-
and_return(rcv_instance)
|
133
|
-
|
134
|
-
expect(rcv_instance).to receive(:validate).
|
135
|
-
with(ocsp: false, crl: false, crl_file: nil).
|
136
|
-
and_return(true)
|
137
|
-
|
138
|
-
# AuthResp
|
139
|
-
expect(ssl_socket_instance).to receive(:read).
|
140
|
-
with(5).
|
141
|
-
and_return([1, 254].pack 'NC')
|
142
|
-
|
143
|
-
# PingResp
|
144
|
-
expect(ssl_socket_instance).to receive(:read).
|
145
|
-
with(5).
|
146
|
-
and_return([1, 2].pack 'NC')
|
147
|
-
|
148
|
-
described_class.new host, pb_port, options
|
149
|
-
end
|
150
|
-
end
|
151
|
-
end
|