riak-client 2.0.0.rc1 → 2.0.0.rc2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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
|