riak-client 2.1.0 → 2.2.0.pre1

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.
Files changed (58) hide show
  1. checksums.yaml +4 -4
  2. data/Gemfile +3 -1
  3. data/Guardfile +15 -9
  4. data/README.markdown +118 -9
  5. data/lib/riak/bucket.rb +16 -1
  6. data/lib/riak/bucket_properties.rb +67 -0
  7. data/lib/riak/bucket_type.rb +48 -0
  8. data/lib/riak/bucket_typed/bucket.rb +113 -0
  9. data/lib/riak/client/beefcake/bucket_properties_operator.rb +178 -0
  10. data/lib/riak/client/beefcake/message_overlay.rb +42 -20
  11. data/lib/riak/client/beefcake/object_methods.rb +1 -1
  12. data/lib/riak/client/beefcake/socket.rb +6 -6
  13. data/lib/riak/client/beefcake_protobuffs_backend.rb +44 -60
  14. data/lib/riak/client/protobuffs_backend.rb +8 -8
  15. data/lib/riak/client.rb +7 -2
  16. data/lib/riak/crdt/base.rb +29 -1
  17. data/lib/riak/crdt/counter.rb +7 -3
  18. data/lib/riak/crdt/inner_flag.rb +1 -1
  19. data/lib/riak/crdt/map.rb +7 -3
  20. data/lib/riak/crdt/set.rb +7 -4
  21. data/lib/riak/errors/failed_request.rb +2 -0
  22. data/lib/riak/errors/search_error.rb +29 -0
  23. data/lib/riak/locale/en.yml +7 -0
  24. data/lib/riak/map_reduce.rb +70 -6
  25. data/lib/riak/robject.rb +19 -3
  26. data/lib/riak/search/index.rb +73 -0
  27. data/lib/riak/search/query.rb +133 -0
  28. data/lib/riak/search/result_collection.rb +91 -0
  29. data/lib/riak/search/result_document.rb +59 -0
  30. data/lib/riak/search/schema.rb +65 -0
  31. data/lib/riak/search.rb +10 -0
  32. data/lib/riak/secondary_index.rb +6 -0
  33. data/lib/riak/version.rb +1 -1
  34. data/spec/fixtures/yz_schema_template.xml +18 -0
  35. data/spec/integration/riak/bucket_types_spec.rb +218 -39
  36. data/spec/integration/riak/conflict_resolution_spec.rb +96 -0
  37. data/spec/integration/riak/crdt_spec.rb +30 -2
  38. data/spec/integration/riak/properties_spec.rb +69 -0
  39. data/spec/integration/riak/search_spec.rb +104 -0
  40. data/spec/integration/riak/secondary_index_spec.rb +18 -0
  41. data/spec/riak/beefcake_protobuffs_backend/bucket_properties_operator_spec.rb +247 -0
  42. data/spec/riak/bucket_properties_spec.rb +114 -0
  43. data/spec/riak/bucket_type_spec.rb +34 -0
  44. data/spec/riak/bucket_typed/bucket.rb +43 -0
  45. data/spec/riak/client_spec.rb +16 -8
  46. data/spec/riak/crdt/counter_spec.rb +2 -1
  47. data/spec/riak/crdt/map_spec.rb +2 -1
  48. data/spec/riak/crdt/set_spec.rb +2 -1
  49. data/spec/riak/map_reduce_spec.rb +169 -124
  50. data/spec/riak/search/index_spec.rb +62 -0
  51. data/spec/riak/search/query_spec.rb +88 -0
  52. data/spec/riak/search/result_collection_spec.rb +87 -0
  53. data/spec/riak/search/result_document_spec.rb +63 -0
  54. data/spec/riak/search/schema_spec.rb +63 -0
  55. data/spec/spec_helper.rb +2 -1
  56. data/spec/support/search_config.rb +81 -0
  57. data/spec/support/test_client.yml +14 -7
  58. metadata +44 -5
@@ -0,0 +1,247 @@
1
+ require 'spec_helper'
2
+ Riak::Client::BeefcakeProtobuffsBackend.configured?
3
+
4
+ describe Riak::Client::BeefcakeProtobuffsBackend::BucketPropertiesOperator do
5
+ let(:backend_class){ Riak::Client::BeefcakeProtobuffsBackend }
6
+ let(:backend) { instance_double('Riak::Client::BeefcakeProtobuffsBackend') }
7
+
8
+ let(:protocol) do
9
+ instance_double('Riak::Client::BeefcakeProtobuffsBackend::Protocol').
10
+ tap do |p|
11
+ allow(backend).to receive(:protocol).and_yield(p)
12
+ end
13
+ end
14
+
15
+ let(:bucket_name){ 'bucket_name' }
16
+ let(:bucket) do
17
+ instance_double('Riak::Bucket').tap do |b|
18
+ allow(b).to receive(:name).and_return(bucket_name)
19
+ allow(b).to receive(:is_a?).with(Riak::Bucket).and_return(true)
20
+ allow(b).to receive(:needs_type?).and_return(false)
21
+ end
22
+ end
23
+
24
+ let(:test_props) do
25
+ backend_class::RpbBucketProps.
26
+ new(
27
+ n_val: 3,
28
+ pr: 0xffffffff - 1,
29
+ r: 0xffffffff - 2,
30
+ w: 0xffffffff - 3,
31
+ pw: 0xffffffff - 4,
32
+ dw: 0,
33
+ rw: 1,
34
+ precommit: precommit,
35
+ postcommit: backend_class::RpbCommitHook.new(name: 'piper'),
36
+ linkfun: backend_class::RpbModFun.new(module: 'nachos',
37
+ function: 'galacticos')
38
+ )
39
+ end
40
+
41
+ let(:precommit) do
42
+ backend_class::RpbCommitHook.
43
+ new(
44
+ modfun: backend_class::RpbModFun.new(
45
+ module: 'validate_json',
46
+ function: 'validate'
47
+ ))
48
+ end
49
+
50
+ let(:get_bucket_request) do
51
+ backend_class::RpbGetBucketReq.new bucket: bucket_name
52
+ end
53
+
54
+ let(:get_bucket_response) do
55
+ backend_class::RpbGetBucketResp.
56
+ new(props: test_props)
57
+ end
58
+
59
+ let(:get_bucket_expectation) do
60
+ expect(protocol).to receive(:write).
61
+ with(:GetBucketReq, get_bucket_request)
62
+
63
+ expect(protocol).to receive(:expect).
64
+ with(:GetBucketResp,
65
+ backend_class::RpbGetBucketResp).
66
+ and_return(get_bucket_response)
67
+ end
68
+
69
+ subject{ described_class.new backend }
70
+
71
+ it 'is initialized with a backend' do
72
+ expect{ described_class.new backend }.to_not raise_error
73
+ end
74
+
75
+ it 'passes through scalar properties' do
76
+ get_bucket_expectation
77
+
78
+ resp = nil
79
+ expect{ resp = subject.get bucket }.to_not raise_error
80
+
81
+ expect(resp['n_val']).to eq 3
82
+ end
83
+
84
+ describe 'quorums' do
85
+ it 'rubyfies' do
86
+ get_bucket_expectation
87
+
88
+ resp = nil
89
+ expect{ resp = subject.get bucket }.to_not raise_error
90
+
91
+ expect(resp['pr']).to eq 'one'
92
+ expect(resp['r']).to eq 'quorum'
93
+ expect(resp['w']).to eq 'all'
94
+ expect(resp['pw']).to eq 'default'
95
+ expect(resp['dw']).to eq 0
96
+ expect(resp['rw']).to eq 1
97
+ end
98
+
99
+ it 'riakifies' do
100
+ expected_props = backend_class::RpbBucketProps.
101
+ new(
102
+ pr: 0xffffffff - 1,
103
+ r: 0xffffffff - 2,
104
+ w: 0xffffffff - 3,
105
+ pw: 0xffffffff - 4,
106
+ dw: 0,
107
+ rw: 1
108
+ )
109
+
110
+ set_bucket_request = backend_class::RpbSetBucketReq.new
111
+ set_bucket_request.bucket = bucket_name
112
+ set_bucket_request.props = expected_props
113
+
114
+ expect(protocol).to receive(:write).
115
+ with(:SetBucketReq, set_bucket_request)
116
+
117
+ expect(protocol).to receive(:expect).
118
+ with(:SetBucketResp)
119
+
120
+ # support both strings and symbols for quorum names
121
+ write_props = {
122
+ pr: 'one',
123
+ r: :quorum,
124
+ w: 'all',
125
+ pw: :default,
126
+ dw: 0,
127
+ rw: 1
128
+ }
129
+
130
+ expect{ subject.put bucket, write_props }.to_not raise_error
131
+ end
132
+ end
133
+
134
+ describe 'commit hooks' do
135
+ it 'rubyfies' do
136
+ expect(protocol).to receive(:write).
137
+ with(:GetBucketReq, get_bucket_request)
138
+
139
+ expect(protocol).to receive(:expect).
140
+ with(:GetBucketResp,
141
+ backend_class::RpbGetBucketResp).
142
+ and_return(get_bucket_response)
143
+
144
+ resp = nil
145
+ expect{ resp = subject.get bucket }.to_not raise_error
146
+
147
+ expect(resp['precommit']).to be_an Array
148
+ expect(pre = resp['precommit'].first).to be_a Hash
149
+ expect(pre['mod']).to eq 'validate_json'
150
+ expect(pre['fun']).to eq 'validate'
151
+
152
+ expect(resp['postcommit'].first).to eq 'piper'
153
+ end
154
+
155
+ it 'riakifies' do
156
+ modfun = backend_class::RpbModFun.new(
157
+ module: 'validate_json',
158
+ function: 'validate'
159
+ )
160
+ expected_props = backend_class::RpbBucketProps.
161
+ new(
162
+ precommit: [backend_class::RpbCommitHook.
163
+ new(modfun: modfun)],
164
+ postcommit: [backend_class::RpbCommitHook.
165
+ new(name: 'piper')]
166
+ )
167
+
168
+ set_bucket_request = backend_class::RpbSetBucketReq.new
169
+ set_bucket_request.bucket = bucket_name
170
+ set_bucket_request.props = expected_props
171
+
172
+ expect(protocol).to receive(:write).
173
+ with(:SetBucketReq, set_bucket_request)
174
+
175
+ expect(protocol).to receive(:expect).
176
+ with(:SetBucketResp)
177
+
178
+ write_props = {
179
+ precommit: { mod: 'validate_json', fun: 'validate' },
180
+ postcommit: ['piper']
181
+ }
182
+
183
+ expect{ subject.put bucket, write_props }.to_not raise_error
184
+ end
185
+ end
186
+
187
+ describe 'modfuns' do
188
+ it 'rubyfies' do
189
+ get_bucket_expectation
190
+
191
+ resp = nil
192
+ expect{ resp = subject.get bucket }.to_not raise_error
193
+
194
+ expect(resp['linkfun']).to eq({
195
+ 'mod' => 'nachos',
196
+ 'fun' => 'galacticos'
197
+ })
198
+
199
+ expect(resp['chash_keyfun']).to_not be
200
+ end
201
+
202
+ it 'riakifies' do
203
+ expected_props = backend_class::RpbBucketProps.
204
+ new(
205
+ linkfun: backend_class::RpbModFun.new(module: 'nachos',
206
+ function: 'galacticos')
207
+ )
208
+
209
+ set_bucket_request = backend_class::RpbSetBucketReq.new
210
+ set_bucket_request.bucket = bucket_name
211
+ set_bucket_request.props = expected_props
212
+
213
+ expect(protocol).to receive(:write).
214
+ with(:SetBucketReq, set_bucket_request)
215
+
216
+ expect(protocol).to receive(:expect).
217
+ with(:SetBucketResp)
218
+
219
+ write_props = {
220
+ linkfun: { mod: 'nachos', fun: 'galacticos' }
221
+ }
222
+
223
+ expect{ subject.put bucket, write_props }.to_not raise_error
224
+ end
225
+ end
226
+
227
+ describe 'repl modes' do
228
+ it 'riakifies symbols' do
229
+ expected_props = backend_class::RpbBucketProps.
230
+ new(repl: 2)
231
+
232
+ set_bucket_request = backend_class::RpbSetBucketReq.new
233
+ set_bucket_request.bucket = bucket_name
234
+ set_bucket_request.props = expected_props
235
+
236
+ expect(protocol).to receive(:write).
237
+ with(:SetBucketReq, set_bucket_request)
238
+
239
+ expect(protocol).to receive(:expect).
240
+ with(:SetBucketResp)
241
+
242
+ write_props = { repl: :fullsync }
243
+
244
+ expect{ subject.put bucket, write_props }.to_not raise_error
245
+ end
246
+ end
247
+ end
@@ -0,0 +1,114 @@
1
+ require 'spec_helper'
2
+ require 'riak/bucket_properties'
3
+
4
+ describe Riak::BucketProperties do
5
+ let(:client){ instance_double 'Riak::Client' }
6
+ let(:backend) do
7
+ instance_double('Riak::Client::BeefcakeProtobuffsBackend').tap do |be|
8
+ allow(client).to receive(:backend).and_yield be
9
+ end
10
+ end
11
+
12
+ let(:props_operator) do
13
+ instance_double('Riak::Client::BeefcakeProtobuffsBackend::BucketPropertiesOperator').
14
+ tap do |po|
15
+ allow(backend).to receive(:bucket_properties_operator).
16
+ and_return(po)
17
+ end
18
+ end
19
+
20
+ let(:bucket) do
21
+ instance_double('Riak::Bucket').tap do |b|
22
+ allow(b).to receive(:client).and_return(client)
23
+ allow(b).to receive(:needs_type?).and_return(false)
24
+ end
25
+ end
26
+
27
+ let(:typed_bucket) do
28
+ instance_double('Riak::BucketTyped::Bucket').tap do |b|
29
+ allow(b).to receive(:client).and_return(client)
30
+ end
31
+ end
32
+
33
+ subject{ described_class.new bucket }
34
+
35
+ it 'is initialized with a bucket' do
36
+ p = nil
37
+ expect{ p = described_class.new bucket }.to_not raise_error
38
+ expect(p.client).to eq client
39
+ expect(p.bucket).to eq bucket
40
+ end
41
+
42
+ it 'initialzies correctly with a bucket-typed bucket' do
43
+ p = nil
44
+ expect{ p = described_class.new typed_bucket }.to_not raise_error
45
+ expect(p.client).to eq client
46
+ expect(p.bucket).to eq typed_bucket
47
+ end
48
+
49
+ it 'provides hash-like access to properties' do
50
+ expect(props_operator).to receive(:get).
51
+ with(bucket).
52
+ and_return('allow_mult' => true)
53
+
54
+ expect(subject['allow_mult']).to be
55
+
56
+ subject['allow_mult'] = false
57
+
58
+ expect(props_operator).to receive(:put).
59
+ with(bucket, hash_including('allow_mult' => false))
60
+
61
+ subject.store
62
+ end
63
+
64
+ it 'merges properties from hashes' do
65
+ expect(props_operator).to receive(:get).
66
+ with(bucket).
67
+ and_return('allow_mult' => true)
68
+
69
+ expect(subject['allow_mult']).to be
70
+
71
+ property_hash = { 'allow_mult' => false }
72
+ expect{ subject.merge! property_hash }.to_not raise_error
73
+
74
+ expect(props_operator).to receive(:put).
75
+ with(bucket, hash_including('allow_mult' => false))
76
+
77
+ subject.store
78
+ end
79
+
80
+ it 'merges properties from other bucket properties objects' do
81
+ expect(props_operator).to receive(:get).
82
+ with(bucket).
83
+ and_return('allow_mult' => true)
84
+
85
+ expect(subject['allow_mult']).to be
86
+
87
+ other_props = described_class.new typed_bucket
88
+ other_props.
89
+ instance_variable_set :@cached_props, { 'allow_mult' => false}
90
+
91
+ expect{ subject.merge! other_props }.to_not raise_error
92
+
93
+ expect(props_operator).to receive(:put).
94
+ with(bucket, hash_including('allow_mult' => false))
95
+
96
+ subject.store
97
+ end
98
+
99
+ it 'reloads' do
100
+ expect(props_operator).to receive(:get).
101
+ with(bucket).
102
+ and_return('allow_mult' => true)
103
+
104
+ expect(subject['allow_mult']).to be
105
+
106
+ expect(props_operator).to receive(:get).
107
+ with(bucket).
108
+ and_return('allow_mult' => false)
109
+
110
+ expect{ subject.reload }.to_not raise_error
111
+
112
+ expect(subject['allow_mult']).to_not be
113
+ end
114
+ end
@@ -0,0 +1,34 @@
1
+ require 'spec_helper'
2
+ require 'riak/bucket_type'
3
+
4
+ describe Riak::BucketType do
5
+ let(:client){ Riak::Client.allocate }
6
+ let(:name){ 'bucket_type_spec' }
7
+ let(:backend) do
8
+ double('Backend').tap do |backend|
9
+ allow(client).to receive(:backend).and_yield(backend)
10
+ end
11
+ end
12
+
13
+ subject{ described_class.new client, name }
14
+
15
+ it 'is created with a client and name' do
16
+ expect{ described_class.new client, name }.to_not raise_error
17
+ end
18
+
19
+ it 'returns a typed bucket' do
20
+ typed_bucket = subject.bucket 'empanadas'
21
+ expect(typed_bucket).to be_a Riak::Bucket
22
+ expect(typed_bucket).to be_a Riak::BucketTyped::Bucket
23
+ expect(typed_bucket.name).to eq 'empanadas'
24
+ expect(typed_bucket.type).to eq subject
25
+ end
26
+
27
+ let(:sample_props){ { allow_mult: true } }
28
+
29
+ it 'has properties' do
30
+ expect(backend).to receive(:get_bucket_type_props).with(name).and_return(sample_props)
31
+ expect(props = subject.properties).to be_a Hash
32
+ expect(props[:allow_mult]).to be
33
+ end
34
+ end
@@ -0,0 +1,43 @@
1
+ require 'spec_helper'
2
+ require 'riak/bucket_typed/bucket'
3
+
4
+ describe Riak::BucketTyped::Bucket do
5
+ let(:client){ Riak::Client.allocate }
6
+ let(:type){ client.bucket_type 'type' }
7
+ let(:name){ 'bucket_typed_bucket_spec' }
8
+
9
+ subject{ described_class.new client, name, type }
10
+
11
+ it 'initializes a typed RObject' do
12
+ typed_robject = subject.new 'panther'
13
+ expect(typed_robject).to be_a Riak::RObject
14
+ expect(typed_robject.key).to eq 'panther'
15
+ expect(typed_robject.type).to eq type
16
+ end
17
+
18
+ it 'has a bucket type' do
19
+ expect(subject.type).to eq type
20
+ expect(subject.type.name).to eq 'type'
21
+ end
22
+
23
+ describe 'bucket properties' do
24
+ it 'returns properties scoped by bucket and type' do
25
+ expect(client).to receive(:get_bucket_props).with(subject, { type: subject.type.name }).and_return('allow_mult' => true)
26
+
27
+ expect(props = subject.props).to be_a Hash
28
+ expect(props['allow_mult']).to be
29
+ end
30
+
31
+ it 'clears properties scoped by bucket and type' do
32
+ expect(client).to receive(:clear_bucket_props).with(subject, { type: subject.type.name })
33
+
34
+ expect{ subject.clear_props }.to_not raise_error
35
+ end
36
+
37
+ it 'sets properties scoped by bucket and type' do
38
+ expect(client).to receive(:set_bucket_props).with(subject, { 'allow_mult' => true }, subject.type.name)
39
+
40
+ expect{ subject.props = { 'allow_mult' => true } }.to_not raise_error
41
+ end
42
+ end
43
+ end
@@ -31,10 +31,10 @@ describe Riak::Client, test_client: true do
31
31
 
32
32
  it "accepts multiple nodes" do
33
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
- ]
34
+ {:host => 'riak1.basho.com'},
35
+ {:host => 'riak2.basho.com', :pb_port => 1234},
36
+ {:host => 'riak3.basho.com', :pb_port => 5678}
37
+ ]
38
38
  expect(client.nodes.size).to eq(3)
39
39
  expect(client.nodes.first.host).to eq("riak1.basho.com")
40
40
  end
@@ -45,6 +45,13 @@ describe Riak::Client, test_client: true do
45
45
  expect(subject.stamp).to be_kind_of(Riak::Stamp)
46
46
  end
47
47
 
48
+ it 'exposes bucket types' do
49
+ bucket_type = nil
50
+ expect{ bucket_type = subject.bucket_type('example') }.to_not raise_error
51
+ expect(bucket_type).to be_a Riak::BucketType
52
+ expect(bucket_type.name).to eq 'example'
53
+ end
54
+
48
55
  describe "reconfiguring" do
49
56
  before :each do
50
57
  @client = Riak::Client.new
@@ -108,9 +115,9 @@ describe Riak::Client, test_client: true do
108
115
  expect(@bucket).to receive(:[]).with('value1').and_return(double('robject'))
109
116
  expect(@bucket).to receive(:[]).with('value2').and_return(double('robject'))
110
117
  @pairs = [
111
- [@bucket, 'value1'],
112
- [@bucket, 'value2']
113
- ]
118
+ [@bucket, 'value1'],
119
+ [@bucket, 'value2']
120
+ ]
114
121
  end
115
122
 
116
123
  it 'accepts an array of bucket and key pairs' do
@@ -185,7 +192,7 @@ describe Riak::Client, test_client: true do
185
192
  end
186
193
  end
187
194
 
188
- describe "when receiving errors from the backend"
195
+ describe "when receiving errors from the backend" do
189
196
  before do
190
197
  @client = Riak::Client.new
191
198
  end
@@ -217,4 +224,5 @@ describe Riak::Client, test_client: true do
217
224
  expect(error).not_to be_nil
218
225
  expect(error).to be_instance_of(RuntimeError)
219
226
  end
227
+ end
220
228
  end
@@ -5,7 +5,8 @@ describe Riak::Crdt::Counter do
5
5
  let(:bucket) do
6
6
  double('bucket').tap do |b|
7
7
  allow(b).to receive(:name).and_return('bucket')
8
- allow(b).to receive(:is_a?).and_return(true)
8
+ allow(b).to receive(:is_a?).with(Riak::Bucket).and_return(true)
9
+ allow(b).to receive(:is_a?).with(Riak::BucketTyped::Bucket).and_return(false)
9
10
  end
10
11
  end
11
12
  it 'initializes with bucket, key, and optional bucket-type' do
@@ -5,7 +5,8 @@ describe Riak::Crdt::Map do
5
5
  let(:bucket) do
6
6
  double('bucket').tap do |b|
7
7
  allow(b).to receive(:name).and_return('bucket')
8
- allow(b).to receive(:is_a?).and_return(true)
8
+ allow(b).to receive(:is_a?).with(Riak::Bucket).and_return(true)
9
+ allow(b).to receive(:is_a?).with(Riak::BucketTyped::Bucket).and_return(false)
9
10
  allow(b).to receive(:client).and_return(client)
10
11
  end
11
12
  end
@@ -5,7 +5,8 @@ describe Riak::Crdt::Set do
5
5
  let(:bucket) do
6
6
  double('bucket').tap do |b|
7
7
  allow(b).to receive(:name).and_return('bucket')
8
- allow(b).to receive(:is_a?).and_return(true)
8
+ allow(b).to receive(:is_a?).with(Riak::Bucket).and_return(true)
9
+ allow(b).to receive(:is_a?).with(Riak::BucketTyped::Bucket).and_return(false)
9
10
  end
10
11
  end
11
12