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.
- checksums.yaml +4 -4
- data/Gemfile +3 -1
- data/Guardfile +15 -9
- data/README.markdown +118 -9
- data/lib/riak/bucket.rb +16 -1
- data/lib/riak/bucket_properties.rb +67 -0
- data/lib/riak/bucket_type.rb +48 -0
- data/lib/riak/bucket_typed/bucket.rb +113 -0
- data/lib/riak/client/beefcake/bucket_properties_operator.rb +178 -0
- data/lib/riak/client/beefcake/message_overlay.rb +42 -20
- data/lib/riak/client/beefcake/object_methods.rb +1 -1
- data/lib/riak/client/beefcake/socket.rb +6 -6
- data/lib/riak/client/beefcake_protobuffs_backend.rb +44 -60
- data/lib/riak/client/protobuffs_backend.rb +8 -8
- data/lib/riak/client.rb +7 -2
- data/lib/riak/crdt/base.rb +29 -1
- data/lib/riak/crdt/counter.rb +7 -3
- data/lib/riak/crdt/inner_flag.rb +1 -1
- data/lib/riak/crdt/map.rb +7 -3
- data/lib/riak/crdt/set.rb +7 -4
- data/lib/riak/errors/failed_request.rb +2 -0
- data/lib/riak/errors/search_error.rb +29 -0
- data/lib/riak/locale/en.yml +7 -0
- data/lib/riak/map_reduce.rb +70 -6
- data/lib/riak/robject.rb +19 -3
- data/lib/riak/search/index.rb +73 -0
- data/lib/riak/search/query.rb +133 -0
- data/lib/riak/search/result_collection.rb +91 -0
- data/lib/riak/search/result_document.rb +59 -0
- data/lib/riak/search/schema.rb +65 -0
- data/lib/riak/search.rb +10 -0
- data/lib/riak/secondary_index.rb +6 -0
- data/lib/riak/version.rb +1 -1
- data/spec/fixtures/yz_schema_template.xml +18 -0
- data/spec/integration/riak/bucket_types_spec.rb +218 -39
- data/spec/integration/riak/conflict_resolution_spec.rb +96 -0
- data/spec/integration/riak/crdt_spec.rb +30 -2
- data/spec/integration/riak/properties_spec.rb +69 -0
- data/spec/integration/riak/search_spec.rb +104 -0
- data/spec/integration/riak/secondary_index_spec.rb +18 -0
- data/spec/riak/beefcake_protobuffs_backend/bucket_properties_operator_spec.rb +247 -0
- data/spec/riak/bucket_properties_spec.rb +114 -0
- data/spec/riak/bucket_type_spec.rb +34 -0
- data/spec/riak/bucket_typed/bucket.rb +43 -0
- data/spec/riak/client_spec.rb +16 -8
- data/spec/riak/crdt/counter_spec.rb +2 -1
- data/spec/riak/crdt/map_spec.rb +2 -1
- data/spec/riak/crdt/set_spec.rb +2 -1
- data/spec/riak/map_reduce_spec.rb +169 -124
- data/spec/riak/search/index_spec.rb +62 -0
- data/spec/riak/search/query_spec.rb +88 -0
- data/spec/riak/search/result_collection_spec.rb +87 -0
- data/spec/riak/search/result_document_spec.rb +63 -0
- data/spec/riak/search/schema_spec.rb +63 -0
- data/spec/spec_helper.rb +2 -1
- data/spec/support/search_config.rb +81 -0
- data/spec/support/test_client.yml +14 -7
- metadata +44 -5
@@ -1,93 +1,138 @@
|
|
1
1
|
require 'spec_helper'
|
2
2
|
|
3
3
|
describe Riak::MapReduce do
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
4
|
+
|
5
|
+
let(:backend){ double 'Backend' }
|
6
|
+
let(:client) do
|
7
|
+
Riak::Client.new.tap do |c|
|
8
|
+
allow(c).to receive(:backend).and_yield(backend)
|
9
|
+
end
|
9
10
|
end
|
11
|
+
let(:mr) { Riak::MapReduce.new(client) }
|
12
|
+
|
13
|
+
let(:bucket_type){ client.bucket_type 'type' }
|
14
|
+
let(:typed_bucket){ bucket_type.bucket 'bucket' }
|
15
|
+
let(:typed_object){ Riak::RObject.new typed_bucket, 'key' }
|
16
|
+
|
17
|
+
let(:default_type){ client.bucket_type Riak::BucketType::DEFAULT_NAME }
|
18
|
+
let(:default_bucket){ default_type.bucket 'bucket' }
|
19
|
+
let(:default_object){ Riak::RObject.new default_bucket, 'key' }
|
10
20
|
|
11
21
|
it "requires a client" do
|
12
22
|
expect { Riak::MapReduce.new }.to raise_error
|
13
|
-
expect { Riak::MapReduce.new(
|
23
|
+
expect { Riak::MapReduce.new(client) }.not_to raise_error
|
14
24
|
end
|
15
25
|
|
16
26
|
it "initializes the inputs and query to empty arrays" do
|
17
|
-
expect(
|
18
|
-
expect(
|
27
|
+
expect(mr.inputs).to eq([])
|
28
|
+
expect(mr.query).to eq([])
|
19
29
|
end
|
20
30
|
|
21
31
|
it "yields itself when given a block on initializing" do
|
22
|
-
|
23
|
-
|
24
|
-
|
32
|
+
mapred2 = nil
|
33
|
+
mapred = Riak::MapReduce.new(client) do |mr|
|
34
|
+
mapred2 = mr
|
25
35
|
end
|
26
|
-
expect(
|
36
|
+
expect(mapred2).to eq(mapred)
|
27
37
|
end
|
28
38
|
|
29
39
|
describe "adding inputs" do
|
30
40
|
it "returns self for chaining" do
|
31
|
-
expect(
|
41
|
+
expect(mr.add("foo", "bar")).to eq(mr)
|
32
42
|
end
|
33
43
|
|
34
44
|
it "adds bucket/key pairs to the inputs" do
|
35
|
-
|
36
|
-
expect(
|
45
|
+
mr.add("foo","bar")
|
46
|
+
expect(mr.inputs).to eq([["foo","bar"]])
|
37
47
|
end
|
38
48
|
|
39
49
|
it "adds an array containing a bucket/key pair to the inputs" do
|
40
|
-
|
41
|
-
expect(
|
50
|
+
mr.add(["foo","bar"])
|
51
|
+
expect(mr.inputs).to eq([["foo","bar"]])
|
42
52
|
end
|
43
53
|
|
44
54
|
it "adds an object to the inputs by its bucket and key" do
|
45
|
-
bucket = Riak::Bucket.new(
|
55
|
+
bucket = Riak::Bucket.new(client, "foo")
|
46
56
|
obj = Riak::RObject.new(bucket, "bar")
|
47
|
-
|
48
|
-
expect(
|
57
|
+
mr.add(obj)
|
58
|
+
expect(mr.inputs).to eq([["foo", "bar"]])
|
59
|
+
end
|
60
|
+
|
61
|
+
it 'adds a bucket-typed object to the inputs' do
|
62
|
+
mr.add typed_object
|
63
|
+
expect(mr.inputs).to eq [[typed_bucket.name,
|
64
|
+
typed_object.key,
|
65
|
+
'',
|
66
|
+
typed_bucket.type.name
|
67
|
+
]]
|
49
68
|
end
|
50
69
|
|
51
70
|
it "adds an array containing a bucket/key/key-data triple to the inputs" do
|
52
|
-
|
53
|
-
expect(
|
71
|
+
mr.add(["foo","bar",1000])
|
72
|
+
expect(mr.inputs).to eq([["foo","bar",1000]])
|
54
73
|
end
|
55
74
|
|
56
75
|
it "uses a bucket name as the single input" do
|
57
|
-
|
58
|
-
expect(
|
59
|
-
|
60
|
-
expect(
|
76
|
+
mr.add(Riak::Bucket.new(client, "foo"))
|
77
|
+
expect(mr.inputs).to eq("foo")
|
78
|
+
mr.add("docs")
|
79
|
+
expect(mr.inputs).to eq("docs")
|
80
|
+
end
|
81
|
+
|
82
|
+
it 'accepts a bucket typed bucket as a single input' do
|
83
|
+
mr.add typed_bucket
|
84
|
+
expect(mr.inputs).to eq([bucket_type.name, typed_bucket.name ])
|
85
|
+
end
|
86
|
+
|
87
|
+
it "doesn't pass a default bucket type name" do
|
88
|
+
mr.add default_bucket
|
89
|
+
expect(mr.inputs).to eq default_bucket.name
|
61
90
|
end
|
62
91
|
|
63
92
|
it "accepts a list of key-filters along with a bucket" do
|
64
|
-
|
65
|
-
expect(
|
93
|
+
mr.add("foo", [[:tokenize, "-", 3], [:string_to_int], [:between, 2009, 2010]])
|
94
|
+
expect(mr.inputs).to eq({:bucket => "foo", :key_filters => [[:tokenize, "-", 3], [:string_to_int], [:between, 2009, 2010]]})
|
95
|
+
end
|
96
|
+
|
97
|
+
it 'accepts a list of key-filters along with a bucket-typed bucket' do
|
98
|
+
filters = [
|
99
|
+
[:tokenize, '-', 3],
|
100
|
+
[:string_to_int],
|
101
|
+
[:between, 2009, 2010]
|
102
|
+
]
|
103
|
+
|
104
|
+
mr.add(typed_bucket, filters)
|
105
|
+
|
106
|
+
expect(mr.inputs).to eq(
|
107
|
+
bucket: [typed_bucket.type.name,
|
108
|
+
typed_bucket.name],
|
109
|
+
key_filters: filters
|
110
|
+
)
|
66
111
|
end
|
67
112
|
|
68
113
|
it "adds a bucket and filter list via a builder block" do
|
69
|
-
|
114
|
+
mr.filter("foo") do
|
70
115
|
tokenize "-", 3
|
71
116
|
string_to_int
|
72
117
|
between 2009, 2010
|
73
118
|
end
|
74
|
-
expect(
|
119
|
+
expect(mr.inputs).to eq({:bucket => "foo", :key_filters => [[:tokenize, "-", 3], [:string_to_int], [:between, 2009, 2010]]})
|
75
120
|
end
|
76
121
|
|
77
122
|
context "using secondary indexes as inputs" do
|
78
123
|
it "sets the inputs for equality" do
|
79
|
-
expect(
|
80
|
-
expect(
|
124
|
+
expect(mr.index("foo", "email_bin", "sean@basho.com")).to eq(mr)
|
125
|
+
expect(mr.inputs).to eq({:bucket => "foo", :index => "email_bin", :key => "sean@basho.com"})
|
81
126
|
end
|
82
127
|
|
83
128
|
it "sets the inputs for a range" do
|
84
|
-
expect(
|
85
|
-
expect(
|
129
|
+
expect(mr.index("foo", "rank_int", 10..20)).to eq(mr)
|
130
|
+
expect(mr.inputs).to eq({:bucket => "foo", :index => "rank_int", :start => 10, :end => 20})
|
86
131
|
end
|
87
132
|
|
88
133
|
it "raises an error when given an invalid query" do
|
89
|
-
expect {
|
90
|
-
expect {
|
134
|
+
expect { mr.index("foo", "rank_int", 1.0348) }.to raise_error(ArgumentError)
|
135
|
+
expect { mr.index("foo", "rank_int", Range.new(1.03, 1.05)) }.to raise_error(ArgumentError)
|
91
136
|
end
|
92
137
|
end
|
93
138
|
|
@@ -100,32 +145,32 @@ describe Riak::MapReduce do
|
|
100
145
|
after { Riak.url_decoding = @urldecode }
|
101
146
|
|
102
147
|
it "adds bucket/key pairs to the inputs with bucket and key escaped" do
|
103
|
-
|
104
|
-
expect(
|
148
|
+
mr.add("[foo]","(bar)")
|
149
|
+
expect(mr.inputs).to eq([["%5Bfoo%5D","%28bar%29"]])
|
105
150
|
end
|
106
151
|
|
107
152
|
it "adds an escaped array containing a bucket/key pair to the inputs" do
|
108
|
-
|
109
|
-
expect(
|
153
|
+
mr.add(["[foo]","(bar)"])
|
154
|
+
expect(mr.inputs).to eq([["%5Bfoo%5D","%28bar%29"]])
|
110
155
|
end
|
111
156
|
|
112
157
|
it "adds an object to the inputs by its escaped bucket and key" do
|
113
|
-
bucket = Riak::Bucket.new(
|
158
|
+
bucket = Riak::Bucket.new(client, "[foo]")
|
114
159
|
obj = Riak::RObject.new(bucket, "(bar)")
|
115
|
-
|
116
|
-
expect(
|
160
|
+
mr.add(obj)
|
161
|
+
expect(mr.inputs).to eq([["%5Bfoo%5D", "%28bar%29"]])
|
117
162
|
end
|
118
163
|
|
119
164
|
it "adds an escaped array containing a bucket/key/key-data triple to the inputs" do
|
120
|
-
|
121
|
-
expect(
|
165
|
+
mr.add(["[foo]","(bar)","[]()"])
|
166
|
+
expect(mr.inputs).to eq([["%5Bfoo%5D", "%28bar%29","[]()"]])
|
122
167
|
end
|
123
168
|
|
124
169
|
it "uses an escaped bucket name as the single input" do
|
125
|
-
|
126
|
-
expect(
|
127
|
-
|
128
|
-
expect(
|
170
|
+
mr.add(Riak::Bucket.new(client, "[foo]"))
|
171
|
+
expect(mr.inputs).to eq("%5Bfoo%5D")
|
172
|
+
mr.add("docs")
|
173
|
+
expect(mr.inputs).to eq("docs")
|
129
174
|
end
|
130
175
|
end
|
131
176
|
|
@@ -134,32 +179,32 @@ describe Riak::MapReduce do
|
|
134
179
|
after { Riak.url_decoding = @urldecode }
|
135
180
|
|
136
181
|
it "adds bucket/key pairs to the inputs with bucket and key unescaped" do
|
137
|
-
|
138
|
-
expect(
|
182
|
+
mr.add("[foo]","(bar)")
|
183
|
+
expect(mr.inputs).to eq([["[foo]","(bar)"]])
|
139
184
|
end
|
140
185
|
|
141
186
|
it "adds an unescaped array containing a bucket/key pair to the inputs" do
|
142
|
-
|
143
|
-
expect(
|
187
|
+
mr.add(["[foo]","(bar)"])
|
188
|
+
expect(mr.inputs).to eq([["[foo]","(bar)"]])
|
144
189
|
end
|
145
190
|
|
146
191
|
it "adds an object to the inputs by its unescaped bucket and key" do
|
147
|
-
bucket = Riak::Bucket.new(
|
192
|
+
bucket = Riak::Bucket.new(client, "[foo]")
|
148
193
|
obj = Riak::RObject.new(bucket, "(bar)")
|
149
|
-
|
150
|
-
expect(
|
194
|
+
mr.add(obj)
|
195
|
+
expect(mr.inputs).to eq([["[foo]","(bar)"]])
|
151
196
|
end
|
152
197
|
|
153
198
|
it "adds an unescaped array containing a bucket/key/key-data triple to the inputs" do
|
154
|
-
|
155
|
-
expect(
|
199
|
+
mr.add(["[foo]","(bar)","[]()"])
|
200
|
+
expect(mr.inputs).to eq([["[foo]","(bar)","[]()"]])
|
156
201
|
end
|
157
202
|
|
158
203
|
it "uses an unescaped bucket name as the single input" do
|
159
|
-
|
160
|
-
expect(
|
161
|
-
|
162
|
-
expect(
|
204
|
+
mr.add(Riak::Bucket.new(client, "[foo]"))
|
205
|
+
expect(mr.inputs).to eq("[foo]")
|
206
|
+
mr.add("docs")
|
207
|
+
expect(mr.inputs).to eq("docs")
|
163
208
|
end
|
164
209
|
end
|
165
210
|
end
|
@@ -169,32 +214,32 @@ describe Riak::MapReduce do
|
|
169
214
|
after { Riak.escaper = @oldesc }
|
170
215
|
|
171
216
|
it "adds bucket/key pairs to the inputs with bucket and key escaped" do
|
172
|
-
|
173
|
-
expect(
|
217
|
+
mr.add("[foo]","(bar)")
|
218
|
+
expect(mr.inputs).to eq([["%5Bfoo%5D","%28bar%29"]])
|
174
219
|
end
|
175
220
|
|
176
221
|
it "adds an escaped array containing a bucket/key pair to the inputs" do
|
177
|
-
|
178
|
-
expect(
|
222
|
+
mr.add(["[foo]","(bar)"])
|
223
|
+
expect(mr.inputs).to eq([["%5Bfoo%5D","%28bar%29"]])
|
179
224
|
end
|
180
225
|
|
181
226
|
it "adds an object to the inputs by its escaped bucket and key" do
|
182
|
-
bucket = Riak::Bucket.new(
|
227
|
+
bucket = Riak::Bucket.new(client, "[foo]")
|
183
228
|
obj = Riak::RObject.new(bucket, "(bar)")
|
184
|
-
|
185
|
-
expect(
|
229
|
+
mr.add(obj)
|
230
|
+
expect(mr.inputs).to eq([["%5Bfoo%5D", "%28bar%29"]])
|
186
231
|
end
|
187
232
|
|
188
233
|
it "adds an escaped array containing a bucket/key/key-data triple to the inputs" do
|
189
|
-
|
190
|
-
expect(
|
234
|
+
mr.add(["[foo]","(bar)","[]()"])
|
235
|
+
expect(mr.inputs).to eq([["%5Bfoo%5D", "%28bar%29","[]()"]])
|
191
236
|
end
|
192
237
|
|
193
238
|
it "uses an escaped bucket name as the single input" do
|
194
|
-
|
195
|
-
expect(
|
196
|
-
|
197
|
-
expect(
|
239
|
+
mr.add(Riak::Bucket.new(client, "[foo]"))
|
240
|
+
expect(mr.inputs).to eq("%5Bfoo%5D")
|
241
|
+
mr.add("docs")
|
242
|
+
expect(mr.inputs).to eq("docs")
|
198
243
|
end
|
199
244
|
end
|
200
245
|
|
@@ -203,14 +248,14 @@ describe Riak::MapReduce do
|
|
203
248
|
after { Riak.disable_list_keys_warnings = true }
|
204
249
|
|
205
250
|
it "warns about list-keys on buckets" do
|
206
|
-
expect(
|
207
|
-
|
208
|
-
|
251
|
+
expect(mr).to receive(:warn).twice
|
252
|
+
mr.add("foo")
|
253
|
+
mr.add(Riak::Bucket.new(client, "foo"))
|
209
254
|
end
|
210
255
|
|
211
256
|
it "warns about list-keys on key-filters" do
|
212
|
-
expect(
|
213
|
-
|
257
|
+
expect(mr).to receive(:warn)
|
258
|
+
mr.filter("foo") { matches "bar" }
|
214
259
|
end
|
215
260
|
end
|
216
261
|
end
|
@@ -218,39 +263,39 @@ describe Riak::MapReduce do
|
|
218
263
|
[:map, :reduce].each do |type|
|
219
264
|
describe "adding #{type} phases" do
|
220
265
|
it "returns self for chaining" do
|
221
|
-
expect(
|
266
|
+
expect(mr.send(type, "function(){}")).to eq(mr)
|
222
267
|
end
|
223
268
|
|
224
269
|
it "accepts a function string" do
|
225
|
-
|
226
|
-
expect(
|
227
|
-
phase =
|
270
|
+
mr.send(type, "function(){}")
|
271
|
+
expect(mr.query.size).to eq(1)
|
272
|
+
phase = mr.query.first
|
228
273
|
expect(phase.function).to eq("function(){}")
|
229
274
|
expect(phase.type).to eq(type)
|
230
275
|
end
|
231
276
|
|
232
277
|
it "accepts a function and options" do
|
233
|
-
|
234
|
-
expect(
|
235
|
-
phase =
|
278
|
+
mr.send(type, "function(){}", :keep => true)
|
279
|
+
expect(mr.query.size).to eq(1)
|
280
|
+
phase = mr.query.first
|
236
281
|
expect(phase.function).to eq("function(){}")
|
237
282
|
expect(phase.type).to eq(type)
|
238
283
|
expect(phase.keep).to be_truthy
|
239
284
|
end
|
240
285
|
|
241
286
|
it "accepts a module/function pair" do
|
242
|
-
|
243
|
-
expect(
|
244
|
-
phase =
|
287
|
+
mr.send(type, ["riak","mapsomething"])
|
288
|
+
expect(mr.query.size).to eq(1)
|
289
|
+
phase = mr.query.first
|
245
290
|
expect(phase.function).to eq(["riak", "mapsomething"])
|
246
291
|
expect(phase.type).to eq(type)
|
247
292
|
expect(phase.language).to eq("erlang")
|
248
293
|
end
|
249
294
|
|
250
295
|
it "accepts a module/function pair with extra options" do
|
251
|
-
|
252
|
-
expect(
|
253
|
-
phase =
|
296
|
+
mr.send(type, ["riak", "mapsomething"], :arg => [1000])
|
297
|
+
expect(mr.query.size).to eq(1)
|
298
|
+
phase = mr.query.first
|
254
299
|
expect(phase.function).to eq(["riak", "mapsomething"])
|
255
300
|
expect(phase.type).to eq(type)
|
256
301
|
expect(phase.language).to eq("erlang")
|
@@ -261,22 +306,22 @@ describe Riak::MapReduce do
|
|
261
306
|
|
262
307
|
describe "adding link phases" do
|
263
308
|
it "returns self for chaining" do
|
264
|
-
expect(
|
309
|
+
expect(mr.link({})).to eq(mr)
|
265
310
|
end
|
266
311
|
|
267
312
|
it "accepts a WalkSpec" do
|
268
|
-
|
269
|
-
expect(
|
270
|
-
phase =
|
313
|
+
mr.link(Riak::WalkSpec.new(:tag => "next"))
|
314
|
+
expect(mr.query.size).to eq(1)
|
315
|
+
phase = mr.query.first
|
271
316
|
expect(phase.type).to eq(:link)
|
272
317
|
expect(phase.function).to be_kind_of(Riak::WalkSpec)
|
273
318
|
expect(phase.function.tag).to eq("next")
|
274
319
|
end
|
275
320
|
|
276
321
|
it "accepts a WalkSpec and a hash of options" do
|
277
|
-
|
278
|
-
expect(
|
279
|
-
phase =
|
322
|
+
mr.link(Riak::WalkSpec.new(:bucket => "foo"), :keep => true)
|
323
|
+
expect(mr.query.size).to eq(1)
|
324
|
+
phase = mr.query.first
|
280
325
|
expect(phase.type).to eq(:link)
|
281
326
|
expect(phase.function).to be_kind_of(Riak::WalkSpec)
|
282
327
|
expect(phase.function.bucket).to eq("foo")
|
@@ -284,9 +329,9 @@ describe Riak::MapReduce do
|
|
284
329
|
end
|
285
330
|
|
286
331
|
it "accepts a hash of options intermingled with the walk spec options" do
|
287
|
-
|
288
|
-
expect(
|
289
|
-
phase =
|
332
|
+
mr.link(:tag => "snakes", :arg => [1000])
|
333
|
+
expect(mr.query.size).to eq(1)
|
334
|
+
phase = mr.query.first
|
290
335
|
expect(phase.arg).to eq([1000])
|
291
336
|
expect(phase.function).to be_kind_of(Riak::WalkSpec)
|
292
337
|
expect(phase.function.tag).to eq("snakes")
|
@@ -295,59 +340,59 @@ describe Riak::MapReduce do
|
|
295
340
|
|
296
341
|
describe "converting to JSON for the job" do
|
297
342
|
it "includes the inputs and query keys" do
|
298
|
-
expect(
|
343
|
+
expect(mr.to_json).to match(/"inputs":/)
|
299
344
|
end
|
300
345
|
|
301
346
|
it "maps phases to their JSON equivalents" do
|
302
347
|
phase = Riak::MapReduce::Phase.new(:type => :map, :function => "function(){}")
|
303
|
-
|
304
|
-
expect(
|
305
|
-
expect(
|
348
|
+
mr.query << phase
|
349
|
+
expect(mr.to_json).to include('"source":"function(){}"')
|
350
|
+
expect(mr.to_json).to include('"query":[{"map":{')
|
306
351
|
end
|
307
352
|
|
308
353
|
it "emits only the bucket name when the input is the whole bucket" do
|
309
|
-
|
310
|
-
expect(
|
354
|
+
mr.add("foo")
|
355
|
+
expect(mr.to_json).to include('"inputs":"foo"')
|
311
356
|
end
|
312
357
|
|
313
358
|
it "emits an array of inputs when there are multiple inputs" do
|
314
|
-
|
315
|
-
expect(
|
359
|
+
mr.add("foo","bar",1000).add("foo","baz")
|
360
|
+
expect(mr.to_json).to include('"inputs":[["foo","bar",1000],["foo","baz"]]')
|
316
361
|
end
|
317
362
|
|
318
363
|
it "adds the timeout value when set" do
|
319
|
-
|
320
|
-
expect(
|
364
|
+
mr.timeout(50000)
|
365
|
+
expect(mr.to_json).to include('"timeout":50000')
|
321
366
|
end
|
322
367
|
end
|
323
368
|
|
324
369
|
it "returns self from setting the timeout" do
|
325
|
-
expect(
|
370
|
+
expect(mr.timeout(5000)).to eq(mr)
|
326
371
|
end
|
327
372
|
|
328
373
|
describe "executing the map reduce job" do
|
329
374
|
before :each do
|
330
|
-
|
375
|
+
mr.map("Riak.mapValues",:keep => true)
|
331
376
|
end
|
332
377
|
|
333
378
|
it "submits the query to the backend" do
|
334
|
-
expect(
|
335
|
-
expect(
|
379
|
+
expect(backend).to receive(:mapred).with(mr).and_return([])
|
380
|
+
expect(mr.run).to eq([])
|
336
381
|
end
|
337
382
|
|
338
383
|
it "passes the given block to the backend for streaming" do
|
339
384
|
arr = []
|
340
|
-
expect(
|
341
|
-
|
385
|
+
expect(backend).to receive(:mapred).with(mr).and_yield("foo").and_yield("bar")
|
386
|
+
mr.run {|v| arr << v }
|
342
387
|
expect(arr).to eq(["foo", "bar"])
|
343
388
|
end
|
344
389
|
|
345
390
|
it "interprets failed requests with JSON content-types as map reduce errors" do
|
346
|
-
allow(
|
391
|
+
allow(backend).to receive(:mapred).
|
347
392
|
and_raise(Riak::ProtobuffsFailedRequest.new(:server_error, '{"error":"syntax error"}'))
|
348
|
-
expect{
|
393
|
+
expect{ mr.run }.to raise_error(Riak::MapReduceError)
|
349
394
|
begin
|
350
|
-
|
395
|
+
mr.run
|
351
396
|
rescue Riak::MapReduceError => mre
|
352
397
|
expect(mre.message).to include('{"error":"syntax error"}')
|
353
398
|
else
|
@@ -356,9 +401,9 @@ describe Riak::MapReduce do
|
|
356
401
|
end
|
357
402
|
|
358
403
|
it "re-raises non-JSON error responses" do
|
359
|
-
allow(
|
404
|
+
allow(backend).to receive(:mapred).
|
360
405
|
and_raise(Riak::ProtobuffsFailedRequest.new(:server_error, 'Oops, you bwoke it.'))
|
361
|
-
expect {
|
406
|
+
expect { mr.run }.to raise_error(Riak::FailedRequest)
|
362
407
|
end
|
363
408
|
end
|
364
409
|
end
|
@@ -0,0 +1,62 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
require 'riak/search/index'
|
3
|
+
|
4
|
+
describe Riak::Search::Index do
|
5
|
+
let(:index_name){ 'index_name' }
|
6
|
+
let(:schema_name){ 'schema_name' }
|
7
|
+
|
8
|
+
let(:index_exists_expectation) do
|
9
|
+
expect(backend).to receive(:get_search_index).
|
10
|
+
with(index_name).
|
11
|
+
and_return(index_exists_response)
|
12
|
+
end
|
13
|
+
|
14
|
+
let(:index_exists_response) do
|
15
|
+
instance_double(
|
16
|
+
'Riak::Client::BeefcakeProtobuffsBackend::RpbYokozunaIndexGetResp',
|
17
|
+
index: [{ name: index_name, schema: schema_name, n_val: 3 }]
|
18
|
+
)
|
19
|
+
end
|
20
|
+
|
21
|
+
let(:client){ instance_double 'Riak::Client' }
|
22
|
+
let(:backend) do
|
23
|
+
be = instance_double 'Riak::Client::BeefcakeProtobuffsBackend'
|
24
|
+
allow(client).to receive(:backend).and_yield(be)
|
25
|
+
be
|
26
|
+
end
|
27
|
+
|
28
|
+
subject { described_class.new client, index_name }
|
29
|
+
|
30
|
+
it 'creates index objects with a client and index name' do
|
31
|
+
expect{ described_class.new client, index_name }.to_not raise_error
|
32
|
+
end
|
33
|
+
|
34
|
+
it 'tests for index existence' do
|
35
|
+
index_exists_expectation
|
36
|
+
expect(subject).to be_exists
|
37
|
+
end
|
38
|
+
|
39
|
+
it 'permits index creation' do
|
40
|
+
expect(backend).to receive(:get_search_index).
|
41
|
+
with(index_name).
|
42
|
+
and_raise(Riak::ProtobuffsFailedRequest.new(:not_found, 'not found'))
|
43
|
+
|
44
|
+
expect(backend).to receive(:create_search_index).
|
45
|
+
with(index_name, nil, nil)
|
46
|
+
|
47
|
+
expect{ subject.create! }.to_not raise_error
|
48
|
+
end
|
49
|
+
|
50
|
+
it 'raises an error when creating an index that already exists' do
|
51
|
+
index_exists_expectation
|
52
|
+
|
53
|
+
expect{ subject.create! }.to raise_error(Riak::SearchError::IndexExistsError)
|
54
|
+
end
|
55
|
+
|
56
|
+
it 'returns data about the index' do
|
57
|
+
index_exists_expectation
|
58
|
+
|
59
|
+
expect(subject.n_val).to eq 3
|
60
|
+
expect(subject.schema).to eq schema_name
|
61
|
+
end
|
62
|
+
end
|
@@ -0,0 +1,88 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
require 'riak/search/query'
|
3
|
+
|
4
|
+
describe Riak::Search::Query do
|
5
|
+
let(:client) do
|
6
|
+
instance_double('Riak::Client').tap do |c|
|
7
|
+
allow(c).to receive(:backend).and_yield(backend)
|
8
|
+
end
|
9
|
+
end
|
10
|
+
let(:index) do
|
11
|
+
instance_double(
|
12
|
+
'Riak::Search::Index',
|
13
|
+
name: index_name,
|
14
|
+
'exists?' => true).tap do |i|
|
15
|
+
allow(i).to receive(:is_a?).with(String).and_return(false)
|
16
|
+
allow(i).to receive(:is_a?).with(Riak::Search::Index).and_return(true)
|
17
|
+
end
|
18
|
+
end
|
19
|
+
let(:backend){ instance_double 'Riak::Client::BeefcakeProtobuffsBackend' }
|
20
|
+
|
21
|
+
let(:index_name){ 'yokozuna' }
|
22
|
+
let(:term){ 'bitcask' }
|
23
|
+
|
24
|
+
let(:raw_results) do
|
25
|
+
{
|
26
|
+
"max_score"=>0.7729485034942627,
|
27
|
+
"num_found"=>3,
|
28
|
+
"docs"=>[
|
29
|
+
{"score"=>"7.72948500000000038312e-01",
|
30
|
+
"_yz_rb"=>"search_test-1419261439-ew70sak2qr",
|
31
|
+
"_yz_rt"=>"yokozuna",
|
32
|
+
"_yz_rk"=>"bitcask-10"},
|
33
|
+
{"score"=>"2.35808490000000009479e-01",
|
34
|
+
"_yz_rb"=>"search_test-1419261439-ew70sak2qr",
|
35
|
+
"_yz_rt"=>"yokozuna",
|
36
|
+
"_yz_rk"=>"bitcask-9"},
|
37
|
+
{"score"=>"6.73738599999999937529e-02",
|
38
|
+
"_yz_rb"=>"search_test-1419261439-ew70sak2qr",
|
39
|
+
"_yz_rt"=>"yokozuna",
|
40
|
+
"_yz_rk"=>"bitcask-4"}
|
41
|
+
]
|
42
|
+
}
|
43
|
+
end
|
44
|
+
|
45
|
+
subject { described_class.new client, index, term }
|
46
|
+
|
47
|
+
it 'creates query objects with a client, index, and query string' do
|
48
|
+
expect{ described_class.new client, index, term }.to_not raise_error
|
49
|
+
end
|
50
|
+
|
51
|
+
it 'creates query objects with a client, index name, and query string' do
|
52
|
+
class_double('Riak::Search::Index', new: index).as_stubbed_const
|
53
|
+
allow(index).to receive(:is_a?).with(Riak::Search::Index).and_return(true)
|
54
|
+
|
55
|
+
expect{ described_class.new client, index_name, term }.to_not raise_error
|
56
|
+
end
|
57
|
+
|
58
|
+
it 'errors when querying with a non-existent index' do
|
59
|
+
expect(index).to receive(:exists?).and_return(false)
|
60
|
+
expect{ described_class.new client, index, term }.to raise_error(Riak::SearchError::IndexNonExistError)
|
61
|
+
end
|
62
|
+
|
63
|
+
it 'allows specifying other query options on creation' do
|
64
|
+
expect(backend).to receive(:search).
|
65
|
+
with(index_name, term, hash_including(rows: 5)).
|
66
|
+
and_return(raw_results)
|
67
|
+
|
68
|
+
q = described_class.new client, index, term, rows: 5
|
69
|
+
expect{ q.results }.to_not raise_error
|
70
|
+
end
|
71
|
+
|
72
|
+
it 'allows specifying query options with accessors' do
|
73
|
+
expect(backend).to receive(:search).
|
74
|
+
with(index_name, term, hash_including(rows: 5)).
|
75
|
+
and_return(raw_results)
|
76
|
+
|
77
|
+
subject.rows = 5
|
78
|
+
expect{ subject.results }.to_not raise_error
|
79
|
+
end
|
80
|
+
|
81
|
+
it 'returns a ResultCollection' do
|
82
|
+
expect(backend).to receive(:search).
|
83
|
+
with(index_name, term, instance_of(Hash)).
|
84
|
+
and_return(raw_results)
|
85
|
+
|
86
|
+
expect(subject.results).to be_a Riak::Search::ResultCollection
|
87
|
+
end
|
88
|
+
end
|