riak-client 2.1.0 → 2.2.0.pre1

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