riakpb 0.1.2 → 0.1.3

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 (3) hide show
  1. data/lib/riak.rb +2 -2
  2. data/spec/riak/map_reduce_spec.rb +324 -1
  3. metadata +2 -2
data/lib/riak.rb CHANGED
@@ -9,7 +9,7 @@ require 'base64'
9
9
  require 'riak/client_pb'
10
10
 
11
11
  module Riak
12
- VERSION = '0.1.2'
12
+ VERSION = '0.1.3'
13
13
 
14
14
  # Domain objects
15
15
  autoload :I18n, 'riak/i18n'
@@ -31,4 +31,4 @@ module Riak
31
31
  autoload :Encode, 'riak/util/encode'
32
32
  autoload :Decode, 'riak/util/decode'
33
33
  end
34
- end
34
+ end
@@ -1,4 +1,327 @@
1
1
  require File.expand_path("../spec_helper", File.dirname(__FILE__))
2
2
 
3
3
  describe Riak::MapReduce do
4
- end
4
+ before :each do
5
+ @client = Riak::Client.new
6
+ @client.rpc.stub!(:request).and_return(nil)
7
+ @mr = Riak::MapReduce.new(@client)
8
+ end
9
+
10
+ it "should require a client" do
11
+ lambda { Riak::MapReduce.new }.should raise_error
12
+ lambda { Riak::MapReduce.new(@client) }.should_not raise_error
13
+ end
14
+
15
+ it "should initialize the inputs and query to empty arrays" do
16
+ @mr.inputs.should == []
17
+ @mr.query.should == []
18
+ end
19
+
20
+ it "should yield itself when given a block on initializing" do
21
+ @mr2 = nil
22
+ @mr = Riak::MapReduce.new(@client) do |mr|
23
+ @mr2 = mr
24
+ end
25
+ @mr2.should == @mr
26
+ end
27
+
28
+ describe "adding inputs" do
29
+ it "should return self for chaining" do
30
+ @mr.add("foo", "bar").should == @mr
31
+ end
32
+
33
+ it "should add bucket/key pairs to the inputs" do
34
+ @mr.add("foo","bar")
35
+ @mr.inputs.should == [["foo","bar"]]
36
+ end
37
+
38
+ it "should add an array containing a bucket/key pair to the inputs" do
39
+ @mr.add(["foo","bar"])
40
+ @mr.inputs.should == [["foo","bar"]]
41
+ end
42
+
43
+ it "should add an object to the inputs by its bucket and key" do
44
+ bucket = Riak::Bucket.new(@client, "foo")
45
+ key = Riak::Key.new(bucket, "bar")
46
+ @mr.add(key)
47
+ @mr.inputs.should == [["foo", "bar"]]
48
+ end
49
+
50
+ it "should add an array containing a bucket/key/key-data triple to the inputs" do
51
+ @mr.add(["foo","bar",1000])
52
+ @mr.inputs.should == [["foo","bar",1000]]
53
+ end
54
+
55
+ it "should use a bucket name as the single input" do
56
+ @mr.add(Riak::Bucket.new(@client, "foo"))
57
+ @mr.inputs.should == "foo"
58
+ @mr.add("docs")
59
+ @mr.inputs.should == "docs"
60
+ end
61
+ end
62
+
63
+ [:map, :reduce].each do |type|
64
+ describe "adding #{type} phases" do
65
+ it "should return self for chaining" do
66
+ @mr.send(type, "function(){}").should == @mr
67
+ end
68
+
69
+ it "should accept a function string" do
70
+ @mr.send(type, "function(){}")
71
+ @mr.query.should have(1).items
72
+ phase = @mr.query.first
73
+ phase.function.should == "function(){}"
74
+ phase.type.should == type
75
+ end
76
+
77
+ it "should accept a function and options" do
78
+ @mr.send(type, "function(){}", :keep => true)
79
+ @mr.query.should have(1).items
80
+ phase = @mr.query.first
81
+ phase.function.should == "function(){}"
82
+ phase.type.should == type
83
+ phase.keep.should be_true
84
+ end
85
+
86
+ it "should accept a module/function pair" do
87
+ @mr.send(type, ["riak","mapsomething"])
88
+ @mr.query.should have(1).items
89
+ phase = @mr.query.first
90
+ phase.function.should == ["riak", "mapsomething"]
91
+ phase.type.should == type
92
+ phase.language.should == "erlang"
93
+ end
94
+
95
+ it "should accept a module/function pair with extra options" do
96
+ @mr.send(type, ["riak", "mapsomething"], :arg => [1000])
97
+ @mr.query.should have(1).items
98
+ phase = @mr.query.first
99
+ phase.function.should == ["riak", "mapsomething"]
100
+ phase.type.should == type
101
+ phase.language.should == "erlang"
102
+ phase.arg.should == [1000]
103
+ end
104
+ end
105
+ end
106
+
107
+ describe "adding link phases" do
108
+ it "should return self for chaining" do
109
+ @mr.link({}).should == @mr
110
+ end
111
+
112
+ it "should accept a Link" do
113
+ @mr.link({:tag => "next"})
114
+ @mr.query.should have(1).items
115
+ phase = @mr.query.first
116
+ phase.type.should == :link
117
+ # phase.function.should be_kind_of(Riak::WalkSpec)
118
+ phase.function[:tag].should == "next"
119
+ end
120
+
121
+ it "should accept a Link and a statement to keep" do
122
+ @mr.link({:bucket => "foo", :keep => true})
123
+ @mr.query.should have(1).items
124
+ phase = @mr.query.first
125
+ phase.type.should == :link
126
+ # phase.function.should be_kind_of(Riak::WalkSpec)
127
+ phase.function[:bucket].should == "foo"
128
+ phase.keep.should be_true
129
+ end
130
+ end
131
+
132
+ describe "converting to JSON for the job" do
133
+ it "should include the inputs and query keys" do
134
+ @mr.to_json.should =~ /"inputs":/
135
+ end
136
+
137
+ it "should map phases to their JSON equivalents" do
138
+ phase = Riak::MapReduce::Phase.new(:type => :map, :function => "function(){}")
139
+ @mr.query << phase
140
+ @mr.to_json.should include('"source":"function(){}"')
141
+ @mr.to_json.should include('"query":[{"map":{')
142
+ end
143
+
144
+ it "should emit only the bucket name when the input is the whole bucket" do
145
+ @mr.add("foo")
146
+ @mr.to_json.should include('"inputs":"foo"')
147
+ end
148
+
149
+ it "should emit an array of inputs when there are multiple inputs" do
150
+ @mr.add("foo","bar",1000).add("foo","baz")
151
+ @mr.to_json.should include('"inputs":[["foo","bar",1000],["foo","baz"]]')
152
+ end
153
+
154
+ it "should add the timeout value when set" do
155
+ @mr.timeout(50000)
156
+ @mr.to_json.should include('"timeout":50000')
157
+ end
158
+ end
159
+ =begin
160
+ describe "executing the map reduce job" do
161
+ it "should issue POST request to the mapred endpoint" do
162
+ @http.should_receive(:post).with(200, "/mapred", @mr.to_json, hash_including("Content-Type" => "application/json")).and_return({:headers => {'content-type' => ["application/json"]}, :body => "{}"})
163
+ @mr.run
164
+ end
165
+
166
+ it "should vivify JSON responses" do
167
+ @http.stub!(:post).and_return(:headers => {'content-type' => ["application/json"]}, :body => '{"key":"value"}')
168
+ @mr.run.should == {"key" => "value"}
169
+ end
170
+
171
+ it "should return the full response hash for non-JSON responses" do
172
+ response = {:code => 200, :headers => {'content-type' => ["text/plain"]}, :body => 'This is some text.'}
173
+ @http.stub!(:post).and_return(response)
174
+ @mr.run.should == response
175
+ end
176
+
177
+ it "should interpret failed requests with JSON content-types as map reduce errors" do
178
+ @http.stub!(:post).and_raise(Riak::FailedRequest.new(:post, 200, 500, {"content-type" => ["application/json"]}, '{"error":"syntax error"}'))
179
+ lambda { @mr.run }.should raise_error(Riak::MapReduceError)
180
+ begin
181
+ @mr.run
182
+ rescue Riak::MapReduceError => mre
183
+ mre.message.should == '{"error":"syntax error"}'
184
+ else
185
+ fail "No exception raised!"
186
+ end
187
+ end
188
+
189
+ it "should re-raise non-JSON error responses" do
190
+ @http.stub!(:post).and_raise(Riak::FailedRequest.new(:post, 200, 500, {"content-type" => ["text/plain"]}, 'Oops, you bwoke it.'))
191
+ lambda { @mr.run }.should raise_error(Riak::FailedRequest)
192
+ end
193
+ end
194
+ =end
195
+ end
196
+
197
+ describe Riak::MapReduce::Phase do
198
+ before :each do
199
+ @fun = "function(v,_,_){ return v['values'][0]['data']; }"
200
+ end
201
+
202
+ it "should initialize with a type and a function" do
203
+ phase = Riak::MapReduce::Phase.new(:type => :map, :function => @fun, :language => "javascript")
204
+ phase.type.should == :map
205
+ phase.function.should == @fun
206
+ phase.language.should == "javascript"
207
+ end
208
+
209
+ it "should initialize with a type and an MF" do
210
+ phase = Riak::MapReduce::Phase.new(:type => :map, :function => ["module", "function"], :language => "erlang")
211
+ phase.type.should == :map
212
+ phase.function.should == ["module", "function"]
213
+ phase.language.should == "erlang"
214
+ end
215
+
216
+ it "should initialize with a type and a bucket/key" do
217
+ phase = Riak::MapReduce::Phase.new(:type => :map, :function => {:bucket => "funs", :key => "awesome_map"}, :language => "javascript")
218
+ phase.type.should == :map
219
+ phase.function.should == {:bucket => "funs", :key => "awesome_map"}
220
+ phase.language.should == "javascript"
221
+ end
222
+
223
+ it "should assume the language is erlang when the function is an array" do
224
+ phase = Riak::MapReduce::Phase.new(:type => :map, :function => ["module", "function"])
225
+ phase.language.should == "erlang"
226
+ end
227
+
228
+ it "should assume the language is javascript when the function is a string" do
229
+ phase = Riak::MapReduce::Phase.new(:type => :map, :function => @fun)
230
+ phase.language.should == "javascript"
231
+ end
232
+
233
+ it "should assume the language is javascript when the function is a hash" do
234
+ phase = Riak::MapReduce::Phase.new(:type => :map, :function => {:bucket => "jobs", :key => "awesome_map"})
235
+ phase.language.should == "javascript"
236
+ end
237
+
238
+ it "should accept a WalkSpec for the function when a link phase" do
239
+ # phase = Riak::MapReduce::Phase.new(:type => :link, :function => Riak::WalkSpec.new({}))
240
+ # phase.function.should be_kind_of(Riak::WalkSpec)
241
+ end
242
+
243
+ it "should raise an error if a WalkSpec is given for a phase type other than :link" do
244
+ # lambda { Riak::MapReduce::Phase.new(:type => :map, :function => Riak::WalkSpec.new({})) }.should raise_error(ArgumentError)
245
+ end
246
+
247
+ describe "converting to JSON for the job" do
248
+ before :each do
249
+ @phase = Riak::MapReduce::Phase.new(:type => :map, :function => "")
250
+ end
251
+
252
+ [:map, :reduce].each do |type|
253
+ describe "when a #{type} phase" do
254
+ before :each do
255
+ @phase.type = type
256
+ end
257
+
258
+ it "should be an object with a single key of '#{type}'" do
259
+ @phase.to_json.should =~ /^\{"#{type}":/
260
+ end
261
+
262
+ it "should include the language" do
263
+ @phase.to_json.should =~ /"language":/
264
+ end
265
+
266
+ it "should include the keep value" do
267
+ @phase.to_json.should =~ /"keep":false/
268
+ @phase.keep = true
269
+ @phase.to_json.should =~ /"keep":true/
270
+ end
271
+
272
+ it "should include the function source when the function is a source string" do
273
+ @phase.function = "function(v,_,_){ return v; }"
274
+ @phase.to_json.should include(@phase.function)
275
+ @phase.to_json.should =~ /"source":/
276
+ end
277
+
278
+ it "should include the function name when the function is not a lambda" do
279
+ @phase.function = "Riak.mapValues"
280
+ @phase.to_json.should include('"name":"Riak.mapValues"')
281
+ @phase.to_json.should_not include('"source"')
282
+ end
283
+
284
+ it "should include the bucket and key when referring to a stored function" do
285
+ @phase.function = {:bucket => "design", :key => "wordcount_map"}
286
+ @phase.to_json.should include('"bucket":"design"')
287
+ @phase.to_json.should include('"key":"wordcount_map"')
288
+ end
289
+
290
+ it "should include the module and function when invoking an Erlang function" do
291
+ @phase.function = ["riak_mapreduce", "mapreduce_fun"]
292
+ @phase.to_json.should include('"module":"riak_mapreduce"')
293
+ @phase.to_json.should include('"function":"mapreduce_fun"')
294
+ end
295
+ end
296
+ end
297
+
298
+ describe "when a link phase" do
299
+ before :each do
300
+ @phase.type = :link
301
+ @phase.function = {}
302
+ end
303
+
304
+ it "should be an object of a single key 'link'" do
305
+ @phase.to_json.should == "{\"link\":{\"keep\":false}}"
306
+ end
307
+
308
+ it "should include the bucket" do
309
+ @phase.function[:bucket] = "foo"
310
+ @phase.to_json.should == "{\"link\":{\"bucket\":\"foo\",\"keep\":false}}"
311
+ end
312
+
313
+ it "should include the tag" do
314
+ @phase.function[:tag] = "parent"
315
+ @phase.to_json.should == "{\"link\":{\"tag\":\"parent\",\"keep\":false}}"
316
+ end
317
+
318
+ it "should include the keep value" do
319
+ @phase.keep = true
320
+ @phase.to_json.should == "{\"link\":{\"keep\":true}}"
321
+ @phase.keep = false
322
+ @phase.function[:keep] = true
323
+ @phase.to_json.should == "{\"link\":{\"keep\":false}}"
324
+ end
325
+ end
326
+ end
327
+ end
metadata CHANGED
@@ -5,8 +5,8 @@ version: !ruby/object:Gem::Version
5
5
  segments:
6
6
  - 0
7
7
  - 1
8
- - 2
9
- version: 0.1.2
8
+ - 3
9
+ version: 0.1.3
10
10
  platform: ruby
11
11
  authors:
12
12
  - Scott Gonyea