seomoz-riak-client 1.0.0.pre

Sign up to get free protection for your applications and to get access to all the features.
Files changed (102) hide show
  1. data/Gemfile +27 -0
  2. data/Guardfile +14 -0
  3. data/Rakefile +76 -0
  4. data/erl_src/riak_kv_test_backend.beam +0 -0
  5. data/erl_src/riak_kv_test_backend.erl +174 -0
  6. data/erl_src/riak_search_test_backend.beam +0 -0
  7. data/erl_src/riak_search_test_backend.erl +175 -0
  8. data/lib/active_support/cache/riak_store.rb +2 -0
  9. data/lib/riak.rb +21 -0
  10. data/lib/riak/bucket.rb +215 -0
  11. data/lib/riak/cache_store.rb +84 -0
  12. data/lib/riak/client.rb +415 -0
  13. data/lib/riak/client/beefcake/messages.rb +147 -0
  14. data/lib/riak/client/beefcake/object_methods.rb +92 -0
  15. data/lib/riak/client/beefcake_protobuffs_backend.rb +176 -0
  16. data/lib/riak/client/excon_backend.rb +65 -0
  17. data/lib/riak/client/http_backend.rb +203 -0
  18. data/lib/riak/client/http_backend/configuration.rb +46 -0
  19. data/lib/riak/client/http_backend/key_streamer.rb +43 -0
  20. data/lib/riak/client/http_backend/object_methods.rb +94 -0
  21. data/lib/riak/client/http_backend/request_headers.rb +34 -0
  22. data/lib/riak/client/http_backend/transport_methods.rb +218 -0
  23. data/lib/riak/client/net_http_backend.rb +79 -0
  24. data/lib/riak/client/protobuffs_backend.rb +97 -0
  25. data/lib/riak/client/pump.rb +30 -0
  26. data/lib/riak/client/search.rb +94 -0
  27. data/lib/riak/core_ext.rb +6 -0
  28. data/lib/riak/core_ext/blank.rb +53 -0
  29. data/lib/riak/core_ext/extract_options.rb +7 -0
  30. data/lib/riak/core_ext/json.rb +15 -0
  31. data/lib/riak/core_ext/slice.rb +18 -0
  32. data/lib/riak/core_ext/stringify_keys.rb +10 -0
  33. data/lib/riak/core_ext/symbolize_keys.rb +10 -0
  34. data/lib/riak/core_ext/to_param.rb +31 -0
  35. data/lib/riak/encoding.rb +6 -0
  36. data/lib/riak/failed_request.rb +81 -0
  37. data/lib/riak/i18n.rb +3 -0
  38. data/lib/riak/json.rb +28 -0
  39. data/lib/riak/link.rb +85 -0
  40. data/lib/riak/locale/en.yml +48 -0
  41. data/lib/riak/map_reduce.rb +206 -0
  42. data/lib/riak/map_reduce/filter_builder.rb +94 -0
  43. data/lib/riak/map_reduce/phase.rb +98 -0
  44. data/lib/riak/map_reduce_error.rb +7 -0
  45. data/lib/riak/robject.rb +290 -0
  46. data/lib/riak/search.rb +3 -0
  47. data/lib/riak/serializers.rb +74 -0
  48. data/lib/riak/stamp.rb +77 -0
  49. data/lib/riak/test_server.rb +252 -0
  50. data/lib/riak/util/escape.rb +45 -0
  51. data/lib/riak/util/fiber1.8.rb +48 -0
  52. data/lib/riak/util/headers.rb +53 -0
  53. data/lib/riak/util/multipart.rb +52 -0
  54. data/lib/riak/util/multipart/stream_parser.rb +62 -0
  55. data/lib/riak/util/tcp_socket_extensions.rb +58 -0
  56. data/lib/riak/util/translation.rb +19 -0
  57. data/lib/riak/walk_spec.rb +105 -0
  58. data/riak-client.gemspec +55 -0
  59. data/seomoz-riak-client.gemspec +55 -0
  60. data/spec/fixtures/cat.jpg +0 -0
  61. data/spec/fixtures/multipart-blank.txt +7 -0
  62. data/spec/fixtures/multipart-mapreduce.txt +10 -0
  63. data/spec/fixtures/multipart-with-body.txt +16 -0
  64. data/spec/fixtures/server.cert.crt +15 -0
  65. data/spec/fixtures/server.cert.key +15 -0
  66. data/spec/fixtures/test.pem +1 -0
  67. data/spec/integration/riak/cache_store_spec.rb +154 -0
  68. data/spec/integration/riak/http_backends_spec.rb +58 -0
  69. data/spec/integration/riak/protobuffs_backends_spec.rb +32 -0
  70. data/spec/integration/riak/test_server_spec.rb +161 -0
  71. data/spec/riak/beefcake_protobuffs_backend_spec.rb +59 -0
  72. data/spec/riak/bucket_spec.rb +205 -0
  73. data/spec/riak/client_spec.rb +517 -0
  74. data/spec/riak/core_ext/to_param_spec.rb +15 -0
  75. data/spec/riak/escape_spec.rb +69 -0
  76. data/spec/riak/excon_backend_spec.rb +64 -0
  77. data/spec/riak/headers_spec.rb +38 -0
  78. data/spec/riak/http_backend/configuration_spec.rb +51 -0
  79. data/spec/riak/http_backend/object_methods_spec.rb +217 -0
  80. data/spec/riak/http_backend/transport_methods_spec.rb +117 -0
  81. data/spec/riak/http_backend_spec.rb +269 -0
  82. data/spec/riak/link_spec.rb +71 -0
  83. data/spec/riak/map_reduce/filter_builder_spec.rb +32 -0
  84. data/spec/riak/map_reduce/phase_spec.rb +136 -0
  85. data/spec/riak/map_reduce_spec.rb +310 -0
  86. data/spec/riak/multipart_spec.rb +23 -0
  87. data/spec/riak/net_http_backend_spec.rb +16 -0
  88. data/spec/riak/robject_spec.rb +427 -0
  89. data/spec/riak/search_spec.rb +178 -0
  90. data/spec/riak/serializers_spec.rb +93 -0
  91. data/spec/riak/stamp_spec.rb +54 -0
  92. data/spec/riak/stream_parser_spec.rb +53 -0
  93. data/spec/riak/walk_spec_spec.rb +195 -0
  94. data/spec/spec_helper.rb +39 -0
  95. data/spec/support/drb_mock_server.rb +39 -0
  96. data/spec/support/http_backend_implementation_examples.rb +266 -0
  97. data/spec/support/integration_setup.rb +10 -0
  98. data/spec/support/mock_server.rb +81 -0
  99. data/spec/support/mocks.rb +4 -0
  100. data/spec/support/test_server.yml.example +2 -0
  101. data/spec/support/unified_backend_examples.rb +255 -0
  102. metadata +271 -0
@@ -0,0 +1,32 @@
1
+ require 'spec_helper'
2
+
3
+ describe Riak::MapReduce::FilterBuilder do
4
+ subject { Riak::MapReduce::FilterBuilder.new }
5
+ it "should evaluate the passed block on initialization" do
6
+ subject.class.new do
7
+ matches "foo"
8
+ end.to_a.should == [[:matches, "foo"]]
9
+ end
10
+
11
+ it "should add filters to the list" do
12
+ subject.to_lower
13
+ subject.similar_to("ripple", 3)
14
+ subject.to_a.should == [[:to_lower],[:similar_to, "ripple", 3]]
15
+ end
16
+
17
+ it "should add a logical operation with a block" do
18
+ subject.OR do
19
+ starts_with "foo"
20
+ ends_with "bar"
21
+ end
22
+ subject.to_a.should == [[:or, [[:starts_with, "foo"],[:ends_with, "bar"]]]]
23
+ end
24
+
25
+ it "should raise an error on a filter arity mismatch" do
26
+ lambda { subject.less_than }.should raise_error(ArgumentError)
27
+ end
28
+
29
+ it "should raise an error when a block is not given to a logical operation" do
30
+ lambda { subject._or }.should raise_error(ArgumentError)
31
+ end
32
+ end
@@ -0,0 +1,136 @@
1
+ require 'spec_helper'
2
+
3
+ describe Riak::MapReduce::Phase do
4
+ before :each do
5
+ @fun = "function(v,_,_){ return v['values'][0]['data']; }"
6
+ end
7
+
8
+ it "should initialize with a type and a function" do
9
+ phase = Riak::MapReduce::Phase.new(:type => :map, :function => @fun, :language => "javascript")
10
+ phase.type.should == :map
11
+ phase.function.should == @fun
12
+ phase.language.should == "javascript"
13
+ end
14
+
15
+ it "should initialize with a type and an MF" do
16
+ phase = Riak::MapReduce::Phase.new(:type => :map, :function => ["module", "function"], :language => "erlang")
17
+ phase.type.should == :map
18
+ phase.function.should == ["module", "function"]
19
+ phase.language.should == "erlang"
20
+ end
21
+
22
+ it "should initialize with a type and a bucket/key" do
23
+ phase = Riak::MapReduce::Phase.new(:type => :map, :function => {:bucket => "funs", :key => "awesome_map"}, :language => "javascript")
24
+ phase.type.should == :map
25
+ phase.function.should == {:bucket => "funs", :key => "awesome_map"}
26
+ phase.language.should == "javascript"
27
+ end
28
+
29
+ it "should assume the language is erlang when the function is an array" do
30
+ phase = Riak::MapReduce::Phase.new(:type => :map, :function => ["module", "function"])
31
+ phase.language.should == "erlang"
32
+ end
33
+
34
+ it "should assume the language is javascript when the function is a string" do
35
+ phase = Riak::MapReduce::Phase.new(:type => :map, :function => @fun)
36
+ phase.language.should == "javascript"
37
+ end
38
+
39
+ it "should assume the language is javascript when the function is a hash" do
40
+ phase = Riak::MapReduce::Phase.new(:type => :map, :function => {:bucket => "jobs", :key => "awesome_map"})
41
+ phase.language.should == "javascript"
42
+ end
43
+
44
+ it "should accept a WalkSpec for the function when a link phase" do
45
+ phase = Riak::MapReduce::Phase.new(:type => :link, :function => Riak::WalkSpec.new({}))
46
+ phase.function.should be_kind_of(Riak::WalkSpec)
47
+ end
48
+
49
+ it "should raise an error if a WalkSpec is given for a phase type other than :link" do
50
+ lambda { Riak::MapReduce::Phase.new(:type => :map, :function => Riak::WalkSpec.new({})) }.should raise_error(ArgumentError)
51
+ end
52
+
53
+ describe "converting to JSON for the job" do
54
+ before :each do
55
+ @phase = Riak::MapReduce::Phase.new(:type => :map, :function => "")
56
+ end
57
+
58
+ [:map, :reduce].each do |type|
59
+ describe "when a #{type} phase" do
60
+ before :each do
61
+ @phase.type = type
62
+ end
63
+
64
+ it "should be an object with a single key of '#{type}'" do
65
+ @phase.to_json.should =~ /^\{"#{type}":/
66
+ end
67
+
68
+ it "should include the language" do
69
+ @phase.to_json.should =~ /"language":/
70
+ end
71
+
72
+ it "should include the keep value" do
73
+ @phase.to_json.should =~ /"keep":false/
74
+ @phase.keep = true
75
+ @phase.to_json.should =~ /"keep":true/
76
+ end
77
+
78
+ it "should include the function source when the function is a source string" do
79
+ @phase.function = "function(v,_,_){ return v; }"
80
+ @phase.to_json.should include(@phase.function)
81
+ @phase.to_json.should =~ /"source":/
82
+ end
83
+
84
+ it "should include the function name when the function is not a lambda" do
85
+ @phase.function = "Riak.mapValues"
86
+ @phase.to_json.should include('"name":"Riak.mapValues"')
87
+ @phase.to_json.should_not include('"source"')
88
+ end
89
+
90
+ it "should include the bucket and key when referring to a stored function" do
91
+ @phase.function = {:bucket => "design", :key => "wordcount_map"}
92
+ @phase.to_json.should include('"bucket":"design"')
93
+ @phase.to_json.should include('"key":"wordcount_map"')
94
+ end
95
+
96
+ it "should include the module and function when invoking an Erlang function" do
97
+ @phase.function = ["riak_mapreduce", "mapreduce_fun"]
98
+ @phase.to_json.should include('"module":"riak_mapreduce"')
99
+ @phase.to_json.should include('"function":"mapreduce_fun"')
100
+ end
101
+ end
102
+ end
103
+
104
+ describe "when a link phase" do
105
+ before :each do
106
+ @phase.type = :link
107
+ @phase.function = {}
108
+ end
109
+
110
+ it "should be an object of a single key 'link'" do
111
+ @phase.to_json.should =~ /^\{"link":/
112
+ end
113
+
114
+ it "should include the bucket" do
115
+ @phase.to_json.should =~ /"bucket":"_"/
116
+ @phase.function[:bucket] = "foo"
117
+ @phase.to_json.should =~ /"bucket":"foo"/
118
+ end
119
+
120
+ it "should include the tag" do
121
+ @phase.to_json.should =~ /"tag":"_"/
122
+ @phase.function[:tag] = "parent"
123
+ @phase.to_json.should =~ /"tag":"parent"/
124
+ end
125
+
126
+ it "should include the keep value" do
127
+ @phase.to_json.should =~ /"keep":false/
128
+ @phase.keep = true
129
+ @phase.to_json.should =~ /"keep":true/
130
+ @phase.keep = false
131
+ @phase.function[:keep] = true
132
+ @phase.to_json.should =~ /"keep":true/
133
+ end
134
+ end
135
+ end
136
+ end
@@ -0,0 +1,310 @@
1
+ require 'spec_helper'
2
+
3
+ describe Riak::MapReduce do
4
+ before :each do
5
+ @client = Riak::Client.new
6
+ @backend = mock("Backend")
7
+ @client.stub!(:backend).and_return(@backend)
8
+ @mr = Riak::MapReduce.new(@client)
9
+ end
10
+
11
+ it "should require a client" do
12
+ lambda { Riak::MapReduce.new }.should raise_error
13
+ lambda { Riak::MapReduce.new(@client) }.should_not raise_error
14
+ end
15
+
16
+ it "should initialize the inputs and query to empty arrays" do
17
+ @mr.inputs.should == []
18
+ @mr.query.should == []
19
+ end
20
+
21
+ it "should yield itself when given a block on initializing" do
22
+ @mr2 = nil
23
+ @mr = Riak::MapReduce.new(@client) do |mr|
24
+ @mr2 = mr
25
+ end
26
+ @mr2.should == @mr
27
+ end
28
+
29
+ describe "adding inputs" do
30
+ it "should return self for chaining" do
31
+ @mr.add("foo", "bar").should == @mr
32
+ end
33
+
34
+ it "should add bucket/key pairs to the inputs" do
35
+ @mr.add("foo","bar")
36
+ @mr.inputs.should == [["foo","bar"]]
37
+ end
38
+
39
+ it "should add an array containing a bucket/key pair to the inputs" do
40
+ @mr.add(["foo","bar"])
41
+ @mr.inputs.should == [["foo","bar"]]
42
+ end
43
+
44
+ it "should add an object to the inputs by its bucket and key" do
45
+ bucket = Riak::Bucket.new(@client, "foo")
46
+ obj = Riak::RObject.new(bucket, "bar")
47
+ @mr.add(obj)
48
+ @mr.inputs.should == [["foo", "bar"]]
49
+ end
50
+
51
+ it "should add an array containing a bucket/key/key-data triple to the inputs" do
52
+ @mr.add(["foo","bar",1000])
53
+ @mr.inputs.should == [["foo","bar",1000]]
54
+ end
55
+
56
+ it "should use a bucket name as the single input" do
57
+ @mr.add(Riak::Bucket.new(@client, "foo"))
58
+ @mr.inputs.should == "foo"
59
+ @mr.add("docs")
60
+ @mr.inputs.should == "docs"
61
+ end
62
+
63
+ it "should accept a list of key-filters along with a bucket" do
64
+ @mr.add("foo", [[:tokenize, "-", 3], [:string_to_int], [:between, 2009, 2010]])
65
+ @mr.inputs.should == {:bucket => "foo", :key_filters => [[:tokenize, "-", 3], [:string_to_int], [:between, 2009, 2010]]}
66
+ end
67
+
68
+ it "should add a bucket and filter list via a builder block" do
69
+ @mr.filter("foo") do
70
+ tokenize "-", 3
71
+ string_to_int
72
+ between 2009, 2010
73
+ end
74
+ @mr.inputs.should == {:bucket => "foo", :key_filters => [[:tokenize, "-", 3], [:string_to_int], [:between, 2009, 2010]]}
75
+ end
76
+
77
+ describe "escaping" do
78
+ before { @oldesc, Riak.escaper = Riak.escaper, CGI }
79
+ after { Riak.escaper = @oldesc }
80
+ it "should add bucket/key pairs to the inputs with bucket and key escaped" do
81
+ @mr.add("[foo]","(bar)")
82
+ @mr.inputs.should == [["%5Bfoo%5D","%28bar%29"]]
83
+ end
84
+
85
+ it "should add an escaped array containing a bucket/key pair to the inputs" do
86
+ @mr.add(["[foo]","(bar)"])
87
+ @mr.inputs.should == [["%5Bfoo%5D","%28bar%29"]]
88
+ end
89
+
90
+ it "should add an object to the inputs by its escaped bucket and key" do
91
+ bucket = Riak::Bucket.new(@client, "[foo]")
92
+ obj = Riak::RObject.new(bucket, "(bar)")
93
+ @mr.add(obj)
94
+ @mr.inputs.should == [["%5Bfoo%5D", "%28bar%29"]]
95
+ end
96
+
97
+ it "should add an escaped array containing a bucket/key/key-data triple to the inputs" do
98
+ @mr.add(["[foo]","(bar)","[]()"])
99
+ @mr.inputs.should == [["%5Bfoo%5D", "%28bar%29","[]()"]]
100
+ end
101
+
102
+ it "should use an escaped bucket name as the single input" do
103
+ @mr.add(Riak::Bucket.new(@client, "[foo]"))
104
+ @mr.inputs.should == "%5Bfoo%5D"
105
+ @mr.add("docs")
106
+ @mr.inputs.should == "docs"
107
+ end
108
+ end
109
+
110
+ context "escaping" do
111
+ before { @oldesc, Riak.escaper = Riak.escaper, CGI }
112
+ after { Riak.escaper = @oldesc }
113
+
114
+ it "should add bucket/key pairs to the inputs with bucket and key escaped" do
115
+ @mr.add("[foo]","(bar)")
116
+ @mr.inputs.should == [["%5Bfoo%5D","%28bar%29"]]
117
+ end
118
+
119
+ it "should add an escaped array containing a bucket/key pair to the inputs" do
120
+ @mr.add(["[foo]","(bar)"])
121
+ @mr.inputs.should == [["%5Bfoo%5D","%28bar%29"]]
122
+ end
123
+
124
+ it "should add an object to the inputs by its escaped bucket and key" do
125
+ bucket = Riak::Bucket.new(@client, "[foo]")
126
+ obj = Riak::RObject.new(bucket, "(bar)")
127
+ @mr.add(obj)
128
+ @mr.inputs.should == [["%5Bfoo%5D", "%28bar%29"]]
129
+ end
130
+
131
+ it "should add an escaped array containing a bucket/key/key-data triple to the inputs" do
132
+ @mr.add(["[foo]","(bar)","[]()"])
133
+ @mr.inputs.should == [["%5Bfoo%5D", "%28bar%29","[]()"]]
134
+ end
135
+
136
+ it "should use an escaped bucket name as the single input" do
137
+ @mr.add(Riak::Bucket.new(@client, "[foo]"))
138
+ @mr.inputs.should == "%5Bfoo%5D"
139
+ @mr.add("docs")
140
+ @mr.inputs.should == "docs"
141
+ end
142
+ end
143
+
144
+ context "when adding an input that will result in full-bucket mapreduce" do
145
+ before { Riak.disable_list_keys_warnings = false }
146
+ after { Riak.disable_list_keys_warnings = true }
147
+
148
+ it "should warn about list-keys on buckets" do
149
+ @mr.should_receive(:warn).twice
150
+ @mr.add("foo")
151
+ @mr.add(Riak::Bucket.new(@client, "foo"))
152
+ end
153
+
154
+ it "should warn about list-keys on key-filters" do
155
+ @mr.should_receive(:warn)
156
+ @mr.filter("foo") { matches "bar" }
157
+ end
158
+ end
159
+ end
160
+
161
+ [:map, :reduce].each do |type|
162
+ describe "adding #{type} phases" do
163
+ it "should return self for chaining" do
164
+ @mr.send(type, "function(){}").should == @mr
165
+ end
166
+
167
+ it "should accept a function string" do
168
+ @mr.send(type, "function(){}")
169
+ @mr.query.should have(1).items
170
+ phase = @mr.query.first
171
+ phase.function.should == "function(){}"
172
+ phase.type.should == type
173
+ end
174
+
175
+ it "should accept a function and options" do
176
+ @mr.send(type, "function(){}", :keep => true)
177
+ @mr.query.should have(1).items
178
+ phase = @mr.query.first
179
+ phase.function.should == "function(){}"
180
+ phase.type.should == type
181
+ phase.keep.should be_true
182
+ end
183
+
184
+ it "should accept a module/function pair" do
185
+ @mr.send(type, ["riak","mapsomething"])
186
+ @mr.query.should have(1).items
187
+ phase = @mr.query.first
188
+ phase.function.should == ["riak", "mapsomething"]
189
+ phase.type.should == type
190
+ phase.language.should == "erlang"
191
+ end
192
+
193
+ it "should accept a module/function pair with extra options" do
194
+ @mr.send(type, ["riak", "mapsomething"], :arg => [1000])
195
+ @mr.query.should have(1).items
196
+ phase = @mr.query.first
197
+ phase.function.should == ["riak", "mapsomething"]
198
+ phase.type.should == type
199
+ phase.language.should == "erlang"
200
+ phase.arg.should == [1000]
201
+ end
202
+ end
203
+ end
204
+
205
+ describe "adding link phases" do
206
+ it "should return self for chaining" do
207
+ @mr.link({}).should == @mr
208
+ end
209
+
210
+ it "should accept a WalkSpec" do
211
+ @mr.link(Riak::WalkSpec.new(:tag => "next"))
212
+ @mr.query.should have(1).items
213
+ phase = @mr.query.first
214
+ phase.type.should == :link
215
+ phase.function.should be_kind_of(Riak::WalkSpec)
216
+ phase.function.tag.should == "next"
217
+ end
218
+
219
+ it "should accept a WalkSpec and a hash of options" do
220
+ @mr.link(Riak::WalkSpec.new(:bucket => "foo"), :keep => true)
221
+ @mr.query.should have(1).items
222
+ phase = @mr.query.first
223
+ phase.type.should == :link
224
+ phase.function.should be_kind_of(Riak::WalkSpec)
225
+ phase.function.bucket.should == "foo"
226
+ phase.keep.should be_true
227
+ end
228
+
229
+ it "should accept a hash of options intermingled with the walk spec options" do
230
+ @mr.link(:tag => "snakes", :arg => [1000])
231
+ @mr.query.should have(1).items
232
+ phase = @mr.query.first
233
+ phase.arg.should == [1000]
234
+ phase.function.should be_kind_of(Riak::WalkSpec)
235
+ phase.function.tag.should == "snakes"
236
+ end
237
+ end
238
+
239
+ describe "converting to JSON for the job" do
240
+ it "should include the inputs and query keys" do
241
+ @mr.to_json.should =~ /"inputs":/
242
+ end
243
+
244
+ it "should map phases to their JSON equivalents" do
245
+ phase = Riak::MapReduce::Phase.new(:type => :map, :function => "function(){}")
246
+ @mr.query << phase
247
+ @mr.to_json.should include('"source":"function(){}"')
248
+ @mr.to_json.should include('"query":[{"map":{')
249
+ end
250
+
251
+ it "should emit only the bucket name when the input is the whole bucket" do
252
+ @mr.add("foo")
253
+ @mr.to_json.should include('"inputs":"foo"')
254
+ end
255
+
256
+ it "should emit an array of inputs when there are multiple inputs" do
257
+ @mr.add("foo","bar",1000).add("foo","baz")
258
+ @mr.to_json.should include('"inputs":[["foo","bar",1000],["foo","baz"]]')
259
+ end
260
+
261
+ it "should add the timeout value when set" do
262
+ @mr.timeout(50000)
263
+ @mr.to_json.should include('"timeout":50000')
264
+ end
265
+ end
266
+
267
+ it "should return self from setting the timeout" do
268
+ @mr.timeout(5000).should == @mr
269
+ end
270
+
271
+ describe "executing the map reduce job" do
272
+ before :each do
273
+ @mr.map("Riak.mapValues",:keep => true)
274
+ end
275
+
276
+ it "should raise an exception when no phases are defined" do
277
+ @mr.query.clear
278
+ lambda { @mr.run }.should raise_error(Riak::MapReduceError)
279
+ end
280
+
281
+ it "should submit the query to the backend" do
282
+ @backend.should_receive(:mapred).with(@mr).and_return([])
283
+ @mr.run.should == []
284
+ end
285
+
286
+ it "should pass the given block to the backend for streaming" do
287
+ arr = []
288
+ @backend.should_receive(:mapred).with(@mr).and_yield("foo").and_yield("bar")
289
+ @mr.run {|v| arr << v }
290
+ arr.should == ["foo", "bar"]
291
+ end
292
+
293
+ it "should interpret failed requests with JSON content-types as map reduce errors" do
294
+ @backend.stub!(:mapred).and_raise(Riak::HTTPFailedRequest.new(:post, 200, 500, {"content-type" => ["application/json"]}, '{"error":"syntax error"}'))
295
+ lambda { @mr.run }.should raise_error(Riak::MapReduceError)
296
+ begin
297
+ @mr.run
298
+ rescue Riak::MapReduceError => mre
299
+ mre.message.should include('{"error":"syntax error"}')
300
+ else
301
+ fail "No exception raised!"
302
+ end
303
+ end
304
+
305
+ it "should re-raise non-JSON error responses" do
306
+ @backend.stub!(:mapred).and_raise(Riak::HTTPFailedRequest.new(:post, 200, 500, {"content-type" => ["text/plain"]}, 'Oops, you bwoke it.'))
307
+ lambda { @mr.run }.should raise_error(Riak::FailedRequest)
308
+ end
309
+ end
310
+ end