riakpb 0.2.2 → 0.2.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.
@@ -0,0 +1,199 @@
1
+ require File.expand_path("../spec_helper", File.dirname(__FILE__))
2
+
3
+ describe Riakpb::Client do
4
+ describe "when initializing" do
5
+ it "should default to the local interface on port 8087" do
6
+ client = Riakpb::Client.new
7
+ client.host.should == "127.0.0.1"
8
+ client.port.should == 8087
9
+ end
10
+
11
+ it "should accept a host" do
12
+ client = Riakpb::Client.new :host => "riak.basho.com"
13
+ client.host.should == "riak.basho.com"
14
+ end
15
+
16
+ it "should accept a port" do
17
+ client = Riakpb::Client.new :port => 9000
18
+ client.port.should == 9000
19
+ end
20
+ end
21
+
22
+ describe "reconfiguring" do
23
+ before :each do
24
+ @client = Riakpb::Client.new
25
+ end
26
+
27
+ describe "setting the host" do
28
+ it "should allow setting the host" do
29
+ @client.should respond_to(:host=)
30
+ @client.host = "riak.basho.com"
31
+ @client.host.should == "riak.basho.com"
32
+ end
33
+
34
+ it "should require the host to be an IP or hostname" do
35
+ [238472384972, "", "riak.basho-.com"].each do |invalid|
36
+ lambda { @client.host = invalid }.should raise_error(ArgumentError)
37
+ end
38
+ ["127.0.0.1", "10.0.100.5", "localhost", "otherhost.local", "riak.basho.com"].each do |valid|
39
+ lambda { @client.host = valid }.should_not raise_error
40
+ end
41
+ end
42
+ end # describe "setting the host"
43
+
44
+ describe "setting the port" do
45
+ it "should allow setting the port" do
46
+ @client.should respond_to(:port=)
47
+ @client.port = 9000
48
+ @client.port.should == 9000
49
+ end
50
+
51
+ it "should require the port to be a valid number" do
52
+ [-1,65536,"foo"].each do |invalid|
53
+ lambda { @client.port = invalid }.should raise_error(ArgumentError)
54
+ end
55
+ [0,1,65535,8098].each do |valid|
56
+ lambda { @client.port = valid }.should_not raise_error
57
+ end
58
+ end
59
+ end # describe "setting the port"
60
+
61
+ describe "setting the client id" do
62
+ it "should accept a string unmodified" do
63
+ @client.client_id = "foo"
64
+ @client.client_id.should == "foo"
65
+ end
66
+
67
+ it "should base64-encode an integer" do
68
+ @client.client_id = 1
69
+ @client.client_id.should == "AAAAAQ=="
70
+ end
71
+
72
+ it "should reject an integer equal to the maximum client id" do
73
+ lambda { @client.client_id = Riakpb::Client::MAX_CLIENT_ID }.should raise_error(ArgumentError)
74
+ end
75
+
76
+ it "should reject an integer larger than the maximum client id" do
77
+ lambda { @client.client_id = Riakpb::Client::MAX_CLIENT_ID + 1 }.should raise_error(ArgumentError)
78
+ end
79
+ end # describe "setting the client id"
80
+ end # describe "reconfiguring"
81
+
82
+ describe "sending and receiving protocol buffers" do
83
+ before :each do
84
+ @client = Riakpb::Client.new
85
+ @client.rpc.stub!(:status).and_return(true)
86
+ @client.rpc.stub!(:request).and_return(nil)
87
+ end
88
+
89
+ describe "basic communication with riak node" do
90
+ it "should send a ping request and return true" do
91
+ @client.rpc.stub!(:request).with(
92
+ Riakpb::Util::MessageCode::PING_REQUEST
93
+ ).and_return('')
94
+
95
+ @client.ping?.should == true
96
+ end
97
+
98
+ it "should request the connected riak node's server info and return a Hash" do
99
+ # test length or content? Need to look at what are considered acceptable values
100
+ @client.rpc.stub!(:request).with(
101
+ Riakpb::Util::MessageCode::GET_SERVER_INFO_REQUEST
102
+ ).and_return(Riakpb::RpbGetServerInfoResp.new(
103
+ { :node => "riak@127.0.0.1",
104
+ :server_version => "0.10.1"
105
+ }
106
+ ))
107
+
108
+ @client.info[:node].should be_kind_of(String)
109
+ @client.info[:server_version].should be_kind_of(String)
110
+ end
111
+ end # describe "basic communication with riak node"
112
+
113
+ describe "bucket operations: retrieval (get) and send (set)" do
114
+
115
+ describe "bucket retrieval (get)" do
116
+ it "should send a request to list available bucket names and return a Protobuf::Field::FieldArray" do
117
+ @client.rpc.stub!(:request).with(
118
+ Riakpb::Util::MessageCode::LIST_BUCKETS_REQUEST
119
+ ).and_return(
120
+ Riakpb::RpbListBucketsResp.new(
121
+ { :buckets => ["goog"] }
122
+ ))
123
+
124
+ @client.buckets.should be_kind_of(Protobuf::Field::FieldArray)
125
+ end
126
+
127
+ it "should send a request with the bucket name and return a Riakpb::Bucket" do
128
+ @client.rpc.stub!(:request).with(
129
+ Riakpb::Util::MessageCode::GET_BUCKET_REQUEST,
130
+ Riakpb::RpbGetBucketReq.new(:bucket => "goog")
131
+ ).and_return(
132
+ Riakpb::RpbGetBucketResp.new(
133
+ { :props => {
134
+ :allow_mult => false,
135
+ :n_val => 3
136
+ }
137
+ }
138
+ ))
139
+
140
+ @client.bucket("goog").should be_kind_of(Riakpb::Bucket)
141
+ end
142
+
143
+ it "should send a request to list keys within a bucket and return a Protobuf::Field::FieldArray" do
144
+ @client.rpc.stub!(:request).with(
145
+ Riakpb::Util::MessageCode::LIST_KEYS_REQUEST,
146
+ Riakpb::RpbListKeysReq.new(:bucket => "goog")
147
+ ).and_return(
148
+ Riakpb::RpbListKeysResp.new(
149
+ { :keys => ["2010-04-12", "2008-01-10", "2006-06-06"],
150
+ :done => true
151
+ }
152
+ ))
153
+ @client.keys_in("goog").should be_kind_of(Protobuf::Field::FieldArray)
154
+ end
155
+ end # describe "bucket retrieval (get)"
156
+
157
+ describe "bucket sending (set)" do
158
+ end # describe "bucket sending (set)"
159
+ end # describe "bucket operations and retrieval"
160
+
161
+ describe "key operations: retrieval (get), send (put) and delete (del)" do
162
+ before :each do
163
+ @client.rpc.stub!(:request).with(
164
+ Riakpb::Util::MessageCode::GET_REQUEST,
165
+ Riakpb::RpbGetReq.new(:bucket => "goog", :key => "2010-04-12", :r => nil)
166
+ ).and_return(
167
+ Riakpb::RpbGetResp.new(
168
+ { :content => [],
169
+ :vclock => ""
170
+ }
171
+ ))
172
+ end
173
+
174
+ it "should send a request for a bucket/key pair and return a Riakpb::RpbGetResp" do
175
+ @client.get_request("goog", "2010-04-12").should be_kind_of(Riakpb::RpbGetResp)
176
+ end
177
+
178
+ it "should have a vclock attribute within Riakpb::RpbGetResp of that is a String" do
179
+ @client.get_request("goog", "2010-04-12").vclock.should be_kind_of(String)
180
+ end
181
+ end # describe "key operations and retrieval"
182
+
183
+ describe "key operations and retrieval" do
184
+ before :each do
185
+ @client.rpc.stub!(:request).with(
186
+ Riakpb::Util::MessageCode::GET_REQUEST,
187
+ Riakpb::RpbGetReq.new(:bucket => "goog", :key => "2010-04-12", :r => nil)
188
+ ).and_return(
189
+ Riakpb::RpbGetResp.new(
190
+ { :content => [],
191
+ :vclock => ""
192
+ }
193
+ ))
194
+ end
195
+
196
+
197
+ end # describe "key operations and retrieval"
198
+ end # describe "basic communication with riak node"
199
+ end # Riakpb::Client
@@ -0,0 +1,74 @@
1
+ require File.expand_path("../spec_helper", File.dirname(__FILE__))
2
+
3
+ describe Riakpb::Content do
4
+ describe "when directly initializing" do
5
+ before :each do
6
+ @client = Riakpb::Client.new
7
+ @client.rpc.stub!(:request).with(
8
+ Riakpb::Util::MessageCode::GET_BUCKET_REQUEST,
9
+ Riakpb::RpbGetBucketReq.new(:bucket => "goog")
10
+ ).and_return(
11
+ Riakpb::RpbGetBucketResp.new(
12
+ { :props => {
13
+ :allow_mult => false,
14
+ :n_val => 3
15
+ }
16
+ }
17
+ ))
18
+ @bucket = @client["goog"]
19
+ @key = Riakpb::Key.new(@bucket, "test")
20
+ end
21
+
22
+ it "should default with nil attributes and links/usermeta as instances of Set/Hash" do
23
+ rcontent = Riakpb::Content.new(@key)
24
+ rcontent.key.should == @key
25
+ rcontent.value.should == nil
26
+ rcontent.content_type.should == nil
27
+ rcontent.charset.should == nil
28
+ rcontent.content_encoding.should == nil
29
+ rcontent.vtag.should == nil
30
+ rcontent.links.should be_kind_of(Hash)
31
+ rcontent.last_mod.should be_kind_of(Time)
32
+ rcontent.last_mod_usecs.should == nil
33
+ rcontent.usermeta.should be_kind_of(Hash)
34
+ end
35
+
36
+ it "should allow you to set the Key, after initialization" do
37
+ rcontent = Riakpb::Content.new(@key)
38
+ rcontent.key = @key
39
+ rcontent.key.should == @key
40
+ end
41
+
42
+ it "should accept a Key as an argument to new, tying it back to an owner" do
43
+ rcontent = Riakpb::Content.new(@key)
44
+ rcontent.key.should == @key
45
+ end
46
+
47
+ it "should serialize into a corresponding Protocol Buffer (RpbContent)" do
48
+ rcontent = Riakpb::Content.new(@key, :value => "Test")
49
+ rcontent.to_pb.should be_kind_of(Riakpb::RpbContent)
50
+ end
51
+
52
+ it "should load a Riakpb::RpbContent instance, returning a matching self, Content" do
53
+ rcontent = Riakpb::Content.new(@key)
54
+ rpb_content = Riakpb::RpbContent.new
55
+ rpb_content.value = "{\"Date\":\"2010-04-12\",\"Open\":567.35,\"High\":574.00,\"Low\":566.22,\"Close\":572.73,\"Volume\":2352400,\"Adj. Close\":572.73}"
56
+ rpb_content.content_type = "application/json"
57
+ rpb_content.vtag = "4DNB6Vt0zLl5VJ6P2xx9dc"
58
+ rpb_content.last_mod = 1274645855
59
+ rpb_content.last_mod_usecs = 968694
60
+
61
+ rcontent.load(rpb_content)
62
+ rcontent.key.should == @key
63
+ rcontent.value.should == {"Date" => "2010-04-12".to_date,"Open" => 567.35,"High" => 574.00,"Low" => 566.22,"Close" => 572.73,"Volume" => 2352400,"Adj. Close" => 572.73}
64
+ rcontent.content_type.should == "application/json"
65
+ rcontent.charset.should == nil
66
+ rcontent.content_encoding.should == nil
67
+ rcontent.vtag.should == "4DNB6Vt0zLl5VJ6P2xx9dc"
68
+ rcontent.links.should be_kind_of(Hash)
69
+ rcontent.last_mod.should == Time.at(1274645855.968694)
70
+ rcontent.usermeta.should be_kind_of(Hash)
71
+ end
72
+
73
+ end # describe "when directly initializing"
74
+ end # Riakpb::Content
@@ -0,0 +1,54 @@
1
+ require File.expand_path("../spec_helper", File.dirname(__FILE__))
2
+
3
+ describe Riakpb::Key do
4
+ describe "when directly initializing" do
5
+ before :each do
6
+ @client = Riakpb::Client.new
7
+ @client.rpc.stub!(:request).with(
8
+ Riakpb::Util::MessageCode::GET_BUCKET_REQUEST,
9
+ Riakpb::RpbGetBucketReq.new(:bucket => "goog")
10
+ ).and_return(
11
+ Riakpb::RpbGetBucketResp.new(
12
+ { :props => {
13
+ :allow_mult => false,
14
+ :n_val => 3
15
+ }
16
+ }
17
+ ))
18
+ @bucket = @client["goog"]
19
+ end
20
+
21
+ it "should default with the bucket and name, and an empty vclock" do
22
+ key = Riakpb::Key.new(@bucket, "test")
23
+ key.bucket.should == @bucket
24
+ key.name.should == "test"
25
+ key.vclock.should == nil
26
+ key.content.should be_kind_of(Riakpb::Content)
27
+ end
28
+
29
+ it "should serialize into a Key Protocol Buffer (RpbPutReq)" do
30
+ @client.rpc.stub!(:request).with(
31
+ Riakpb::Util::MessageCode::GET_REQUEST,
32
+ Riakpb::RpbGetReq.new(:bucket => "goog", :key => "2010-04-12", :r => nil)
33
+ ).and_return(
34
+ Riakpb::RpbGetResp.new(
35
+ { :content => [Riakpb::RpbContent.new(:value => "Test")],
36
+ :vclock => "k\xCEa```\xCC`\xCA\x05R,\xACL\xF7^e0%2\xE6\xB12\xC4s\xE6\x1D\xE5\xCB\x02\x00"
37
+ }
38
+ ))
39
+ key = @bucket["2010-04-12"] # Riakpb::Key.new(@bucket, "test")
40
+ pb_put = key.to_pb_put
41
+ pb_put.should be_kind_of(Riakpb::RpbPutReq)
42
+ pb_put.vclock.should == "k\xCEa```\xCC`\xCA\x05R,\xACL\xF7^e0%2\xE6\xB12\xC4s\xE6\x1D\xE5\xCB\x02\x00"
43
+ end
44
+
45
+ it "should serialize into a Link Protocol Buffer (RpbLink)" do
46
+ key = Riakpb::Key.new(@bucket, "test")
47
+ pb_link = key.to_pb_link
48
+ pb_link.should be_kind_of(Riakpb::RpbLink)
49
+ pb_link.bucket.should == "goog"
50
+ pb_link.key.should == "test"
51
+ end
52
+ end # describe "when directly initializing"
53
+ end # Riakpb::Key
54
+
@@ -0,0 +1,327 @@
1
+ require File.expand_path("../spec_helper", File.dirname(__FILE__))
2
+
3
+ describe Riakpb::MapReduce do
4
+ before :each do
5
+ @client = Riakpb::Client.new
6
+ @client.rpc.stub!(:request).and_return(nil)
7
+ @mr = Riakpb::MapReduce.new(@client)
8
+ end
9
+
10
+ it "should require a client" do
11
+ lambda { Riakpb::MapReduce.new }.should raise_error
12
+ lambda { Riakpb::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 = Riakpb::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 = Riakpb::Bucket.new(@client, "foo")
45
+ key = Riakpb::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(Riakpb::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(Riakpb::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(Riakpb::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 = Riakpb::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(Riakpb::FailedRequest.new(:post, 200, 500, {"content-type" => ["application/json"]}, '{"error":"syntax error"}'))
179
+ lambda { @mr.run }.should raise_error(Riakpb::MapReduceError)
180
+ begin
181
+ @mr.run
182
+ rescue Riakpb::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(Riakpb::FailedRequest.new(:post, 200, 500, {"content-type" => ["text/plain"]}, 'Oops, you bwoke it.'))
191
+ lambda { @mr.run }.should raise_error(Riakpb::FailedRequest)
192
+ end
193
+ end
194
+ =end
195
+ end
196
+
197
+ describe Riakpb::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 = Riakpb::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 = Riakpb::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 = Riakpb::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 = Riakpb::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 = Riakpb::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 = Riakpb::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 = Riakpb::MapReduce::Phase.new(:type => :link, :function => Riakpb::WalkSpec.new({}))
240
+ # phase.function.should be_kind_of(Riakpb::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 { Riakpb::MapReduce::Phase.new(:type => :map, :function => Riakpb::WalkSpec.new({})) }.should raise_error(ArgumentError)
245
+ end
246
+
247
+ describe "converting to JSON for the job" do
248
+ before :each do
249
+ @phase = Riakpb::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 = "Riakpb.mapValues"
280
+ @phase.to_json.should include('"name":"Riakpb.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
@@ -0,0 +1,4 @@
1
+ require File.expand_path("../spec_helper", File.dirname(__FILE__))
2
+
3
+ describe Riakpb::Client::Rpc do
4
+ end # Riakpb::Client::Rpc