tyler_koala 1.2.0beta

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 (49) hide show
  1. data/.autotest +12 -0
  2. data/.gitignore +5 -0
  3. data/.travis.yml +9 -0
  4. data/CHANGELOG +185 -0
  5. data/Gemfile +11 -0
  6. data/LICENSE +22 -0
  7. data/Manifest +39 -0
  8. data/Rakefile +16 -0
  9. data/autotest/discover.rb +1 -0
  10. data/koala.gemspec +50 -0
  11. data/lib/koala.rb +119 -0
  12. data/lib/koala/batch_operation.rb +74 -0
  13. data/lib/koala/graph_api.rb +281 -0
  14. data/lib/koala/graph_batch_api.rb +87 -0
  15. data/lib/koala/graph_collection.rb +54 -0
  16. data/lib/koala/http_service.rb +161 -0
  17. data/lib/koala/oauth.rb +181 -0
  18. data/lib/koala/realtime_updates.rb +89 -0
  19. data/lib/koala/rest_api.rb +95 -0
  20. data/lib/koala/test_users.rb +102 -0
  21. data/lib/koala/uploadable_io.rb +180 -0
  22. data/lib/koala/utils.rb +7 -0
  23. data/readme.md +160 -0
  24. data/spec/cases/api_base_spec.rb +101 -0
  25. data/spec/cases/error_spec.rb +30 -0
  26. data/spec/cases/graph_and_rest_api_spec.rb +48 -0
  27. data/spec/cases/graph_api_batch_spec.rb +600 -0
  28. data/spec/cases/graph_api_spec.rb +42 -0
  29. data/spec/cases/http_service_spec.rb +420 -0
  30. data/spec/cases/koala_spec.rb +21 -0
  31. data/spec/cases/oauth_spec.rb +428 -0
  32. data/spec/cases/realtime_updates_spec.rb +198 -0
  33. data/spec/cases/rest_api_spec.rb +41 -0
  34. data/spec/cases/test_users_spec.rb +281 -0
  35. data/spec/cases/uploadable_io_spec.rb +206 -0
  36. data/spec/cases/utils_spec.rb +8 -0
  37. data/spec/fixtures/beach.jpg +0 -0
  38. data/spec/fixtures/cat.m4v +0 -0
  39. data/spec/fixtures/facebook_data.yml +61 -0
  40. data/spec/fixtures/mock_facebook_responses.yml +439 -0
  41. data/spec/spec_helper.rb +43 -0
  42. data/spec/support/graph_api_shared_examples.rb +502 -0
  43. data/spec/support/json_testing_fix.rb +42 -0
  44. data/spec/support/koala_test.rb +163 -0
  45. data/spec/support/mock_http_service.rb +98 -0
  46. data/spec/support/ordered_hash.rb +205 -0
  47. data/spec/support/rest_api_shared_examples.rb +285 -0
  48. data/spec/support/uploadable_io_shared_examples.rb +70 -0
  49. metadata +221 -0
@@ -0,0 +1,101 @@
1
+ require 'spec_helper'
2
+
3
+ describe "Koala::Facebook::API" do
4
+ before(:each) do
5
+ @service = Koala::Facebook::API.new
6
+ end
7
+
8
+ it "should not include an access token if none was given" do
9
+ Koala.should_receive(:make_request).with(
10
+ anything,
11
+ hash_not_including('access_token' => 1),
12
+ anything,
13
+ anything
14
+ ).and_return(Koala::Response.new(200, "", ""))
15
+
16
+ @service.api('anything')
17
+ end
18
+
19
+ it "should include an access token if given" do
20
+ token = 'adfadf'
21
+ service = Koala::Facebook::API.new token
22
+
23
+ Koala.should_receive(:make_request).with(
24
+ anything,
25
+ hash_including('access_token' => token),
26
+ anything,
27
+ anything
28
+ ).and_return(Koala::Response.new(200, "", ""))
29
+
30
+ service.api('anything')
31
+ end
32
+
33
+ it "should have an attr_reader for access token" do
34
+ token = 'adfadf'
35
+ service = Koala::Facebook::API.new token
36
+ service.access_token.should == token
37
+ end
38
+
39
+ it "should get the attribute of a Koala::Response given by the http_component parameter" do
40
+ http_component = :method_name
41
+
42
+ response = mock('Mock KoalaResponse', :body => '', :status => 200)
43
+ response.should_receive(http_component).and_return('')
44
+
45
+ Koala.stub(:make_request).and_return(response)
46
+
47
+ @service.api('anything', {}, 'get', :http_component => http_component)
48
+ end
49
+
50
+ it "should return the body of the request as JSON if no http_component is given" do
51
+ response = stub('response', :body => 'body', :status => 200)
52
+ Koala.stub(:make_request).and_return(response)
53
+
54
+ json_body = mock('JSON body')
55
+ MultiJson.stub(:decode).and_return([json_body])
56
+
57
+ @service.api('anything').should == json_body
58
+ end
59
+
60
+ it "should execute an error checking block if provided" do
61
+ body = '{}'
62
+ Koala.stub(:make_request).and_return(Koala::Response.new(200, body, {}))
63
+
64
+ yield_test = mock('Yield Tester')
65
+ yield_test.should_receive(:pass)
66
+
67
+ @service.api('anything', {}, "get") do |arg|
68
+ yield_test.pass
69
+ arg.should == MultiJson.decode(body)
70
+ end
71
+ end
72
+
73
+ it "should raise an API error if the HTTP response code is greater than or equal to 500" do
74
+ Koala.stub(:make_request).and_return(Koala::Response.new(500, 'response body', {}))
75
+
76
+ lambda { @service.api('anything') }.should raise_exception(Koala::Facebook::APIError)
77
+ end
78
+
79
+ it "should handle rogue true/false as responses" do
80
+ Koala.should_receive(:make_request).and_return(Koala::Response.new(200, 'true', {}))
81
+ @service.api('anything').should be_true
82
+
83
+ Koala.should_receive(:make_request).and_return(Koala::Response.new(200, 'false', {}))
84
+ @service.api('anything').should be_false
85
+ end
86
+
87
+ describe "with regard to leading slashes" do
88
+ it "should add a leading / to the path if not present" do
89
+ path = "anything"
90
+ Koala.should_receive(:make_request).with("/#{path}", anything, anything, anything).and_return(Koala::Response.new(200, 'true', {}))
91
+ @service.api(path)
92
+ end
93
+
94
+ it "shouldn't change the path if a leading / is present" do
95
+ path = "/anything"
96
+ Koala.should_receive(:make_request).with(path, anything, anything, anything).and_return(Koala::Response.new(200, 'true', {}))
97
+ @service.api(path)
98
+ end
99
+ end
100
+
101
+ end
@@ -0,0 +1,30 @@
1
+ describe Koala::Facebook::APIError do
2
+ it "is a StandardError" do
3
+ Koala::Facebook::APIError.new.should be_a(StandardError)
4
+ end
5
+
6
+ it "has an accessor for fb_error_type" do
7
+ Koala::Facebook::APIError.instance_methods.map(&:to_sym).should include(:fb_error_type)
8
+ Koala::Facebook::APIError.instance_methods.map(&:to_sym).should include(:fb_error_type=)
9
+ end
10
+
11
+ it "sets fb_error_type to details['type']" do
12
+ type = "foo"
13
+ Koala::Facebook::APIError.new("type" => type).fb_error_type.should == type
14
+ end
15
+
16
+ it "sets the error message details['type']: details['message']" do
17
+ type = "foo"
18
+ message = "bar"
19
+ error = Koala::Facebook::APIError.new("type" => type, "message" => message)
20
+ error.message.should =~ /#{type}/
21
+ error.message.should =~ /#{message}/
22
+ end
23
+ end
24
+
25
+ describe Koala::KoalaError do
26
+ it "is a StandardError" do
27
+ Koala::KoalaError.new.should be_a(StandardError)
28
+ end
29
+ end
30
+
@@ -0,0 +1,48 @@
1
+ require 'spec_helper'
2
+
3
+ describe "Koala::Facebook::GraphAndRestAPI" do
4
+ describe "class consolidation" do
5
+ before :each do
6
+ Koala::Utils.stub(:deprecate) # avoid actual messages to stderr
7
+ end
8
+
9
+ it "still allows you to instantiate a GraphAndRestAPI object" do
10
+ api = Koala::Facebook::GraphAndRestAPI.new("token").should be_a(Koala::Facebook::GraphAndRestAPI)
11
+ end
12
+
13
+ it "ultimately creates an API object" do
14
+ api = Koala::Facebook::GraphAndRestAPI.new("token").should be_a(Koala::Facebook::API)
15
+ end
16
+
17
+ it "fires a depreciation warning" do
18
+ Koala::Utils.should_receive(:deprecate)
19
+ api = Koala::Facebook::GraphAndRestAPI.new("token")
20
+ end
21
+ end
22
+
23
+ describe "with an access token" do
24
+ before(:each) do
25
+ @api = Koala::Facebook::API.new(@token)
26
+ end
27
+
28
+ it_should_behave_like "Koala RestAPI"
29
+ it_should_behave_like "Koala RestAPI with an access token"
30
+
31
+ it_should_behave_like "Koala GraphAPI"
32
+ it_should_behave_like "Koala GraphAPI with an access token"
33
+ it_should_behave_like "Koala GraphAPI with GraphCollection"
34
+ end
35
+
36
+ describe "without an access token" do
37
+ before(:each) do
38
+ @api = Koala::Facebook::API.new
39
+ end
40
+
41
+ it_should_behave_like "Koala RestAPI"
42
+ it_should_behave_like "Koala RestAPI without an access token"
43
+
44
+ it_should_behave_like "Koala GraphAPI"
45
+ it_should_behave_like "Koala GraphAPI without an access token"
46
+ it_should_behave_like "Koala GraphAPI with GraphCollection"
47
+ end
48
+ end
@@ -0,0 +1,600 @@
1
+ require 'spec_helper'
2
+
3
+ describe "Koala::Facebook::GraphAPI in batch mode" do
4
+
5
+ before :each do
6
+ @api = Koala::Facebook::API.new(@token)
7
+ # app API
8
+ @app_id = KoalaTest.app_id
9
+ @app_access_token = KoalaTest.app_access_token
10
+ @app_api = Koala::Facebook::API.new(@app_access_token)
11
+ end
12
+
13
+ describe "BatchOperations" do
14
+ before :each do
15
+ @args = {
16
+ :url => "my url",
17
+ :args => {:a => 2, :b => 3},
18
+ :method => "get",
19
+ :access_token => "12345",
20
+ :http_options => {},
21
+ :post_processing => lambda { }
22
+ }
23
+ end
24
+
25
+ describe "#new" do
26
+ it "makes http_options accessible" do
27
+ Koala::Facebook::BatchOperation.new(@args).http_options.should == @args[:http_options]
28
+ end
29
+
30
+ it "makes post_processing accessible" do
31
+ Koala::Facebook::BatchOperation.new(@args).post_processing.should == @args[:post_processing]
32
+ end
33
+
34
+ it "makes access_token accessible" do
35
+ Koala::Facebook::BatchOperation.new(@args).access_token.should == @args[:access_token]
36
+ end
37
+
38
+ it "doesn't change the original http_options" do
39
+ @args[:http_options][:name] = "baz2"
40
+ expected = @args[:http_options].dup
41
+ Koala::Facebook::BatchOperation.new(@args).to_batch_params(nil)
42
+ @args[:http_options].should == expected
43
+ end
44
+
45
+ it "leaves the file array nil by default" do
46
+ Koala::Facebook::BatchOperation.new(@args).files.should be_nil
47
+ end
48
+
49
+ it "raises a KoalaError if no access token supplied" do
50
+ expect { Koala::Facebook::BatchOperation.new(@args.merge(:access_token => nil)) }.to raise_exception(Koala::KoalaError)
51
+ end
52
+
53
+ describe "when supplied binary files" do
54
+ before :each do
55
+ @binary = stub("Binary file")
56
+ @uploadable_io = stub("UploadableIO 1")
57
+
58
+ @batch_queue = []
59
+ Koala::Facebook::GraphAPI.stub(:batch_calls).and_return(@batch_queue)
60
+
61
+ Koala::UploadableIO.stub(:new).with(@binary).and_return(@uploadable_io)
62
+ Koala::UploadableIO.stub(:binary_content?).and_return(false)
63
+ Koala::UploadableIO.stub(:binary_content?).with(@binary).and_return(true)
64
+ Koala::UploadableIO.stub(:binary_content?).with(@uploadable_io).and_return(true)
65
+ @uploadable_io.stub(:is_a?).with(Koala::UploadableIO).and_return(true)
66
+
67
+ @args[:method] = "post" # files are always post
68
+ end
69
+
70
+ it "adds binary files to the files attribute as UploadableIOs" do
71
+ @args[:args].merge!("source" => @binary)
72
+ batch_op = Koala::Facebook::BatchOperation.new(@args)
73
+ batch_op.files.should_not be_nil
74
+ batch_op.files.find {|k, v| v == @uploadable_io}.should_not be_nil
75
+ end
76
+
77
+ it "works if supplied an UploadableIO as an argument" do
78
+ # as happens with put_picture at the moment
79
+ @args[:args].merge!("source" => @uploadable_io)
80
+ batch_op = Koala::Facebook::BatchOperation.new(@args)
81
+ batch_op.files.should_not be_nil
82
+ batch_op.files.find {|k, v| v == @uploadable_io}.should_not be_nil
83
+ end
84
+
85
+ it "assigns each binary parameter unique name" do
86
+ @args[:args].merge!("source" => @binary, "source2" => @binary)
87
+ batch_op = Koala::Facebook::BatchOperation.new(@args)
88
+ # if the name wasn't unique, there'd just be one item
89
+ batch_op.files.should have(2).items
90
+ end
91
+
92
+ it "assigns each binary parameter unique name across batch requests" do
93
+ @args[:args].merge!("source" => @binary, "source2" => @binary)
94
+ batch_op = Koala::Facebook::BatchOperation.new(@args)
95
+ # simulate the batch operation, since it's used in determination
96
+ @batch_queue << batch_op
97
+ batch_op2 = Koala::Facebook::BatchOperation.new(@args)
98
+ @batch_queue << batch_op2
99
+ # if the name wasn't unique, we should have < 4 items since keys would be the same
100
+ batch_op.files.merge(batch_op2.files).should have(4).items
101
+ end
102
+
103
+ it "removes the value from the arguments" do
104
+ @args[:args].merge!("source" => @binary)
105
+ Koala::Facebook::BatchOperation.new(@args).to_batch_params(nil)[:body].should_not =~ /source=/
106
+ end
107
+ end
108
+
109
+ end
110
+
111
+ describe ".to_batch_params" do
112
+ describe "handling arguments and URLs" do
113
+ shared_examples_for "request with no body" do
114
+ it "adds the args to the URL string, with ? if no args previously present" do
115
+ test_args = "foo"
116
+ @args[:url] = url = "/"
117
+ Koala.http_service.stub(:encode_params).and_return(test_args)
118
+
119
+ Koala::Facebook::BatchOperation.new(@args).to_batch_params(nil)[:relative_url].should == "#{url}?#{test_args}"
120
+ end
121
+
122
+ it "adds the args to the URL string, with & if args previously present" do
123
+ test_args = "foo"
124
+ @args[:url] = url = "/?a=2"
125
+ Koala.http_service.stub(:encode_params).and_return(test_args)
126
+
127
+ Koala::Facebook::BatchOperation.new(@args).to_batch_params(nil)[:relative_url].should == "#{url}&#{test_args}"
128
+ end
129
+
130
+ it "adds nothing to the URL string if there are no args to be added" do
131
+ @args[:args] = {}
132
+ Koala::Facebook::BatchOperation.new(@args).to_batch_params(@args[:access_token])[:relative_url].should == @args[:url]
133
+ end
134
+
135
+ it "adds nothing to the body" do
136
+ Koala::Facebook::BatchOperation.new(@args).to_batch_params(nil)[:body].should be_nil
137
+ end
138
+ end
139
+
140
+ shared_examples_for "requests with a body param" do
141
+ it "sets the body to the encoded args string, if there are args" do
142
+ test_args = "foo"
143
+ Koala.http_service.stub(:encode_params).and_return(test_args)
144
+
145
+ Koala::Facebook::BatchOperation.new(@args).to_batch_params(nil)[:body].should == test_args
146
+ end
147
+
148
+ it "does not set the body if there are no args" do
149
+ test_args = ""
150
+ Koala.http_service.stub(:encode_params).and_return(test_args)
151
+ Koala::Facebook::BatchOperation.new(@args).to_batch_params(nil)[:body].should be_nil
152
+ end
153
+
154
+
155
+ it "doesn't change the url" do
156
+ test_args = "foo"
157
+ Koala.http_service.stub(:encode_params).and_return(test_args)
158
+
159
+ Koala::Facebook::BatchOperation.new(@args).to_batch_params(nil)[:relative_url].should == @args[:url]
160
+ end
161
+ end
162
+
163
+ context "for get operations" do
164
+ before :each do
165
+ @args[:method] = :get
166
+ end
167
+
168
+ it_should_behave_like "request with no body"
169
+ end
170
+
171
+ context "for delete operations" do
172
+ before :each do
173
+ @args[:method] = :delete
174
+ end
175
+
176
+ it_should_behave_like "request with no body"
177
+ end
178
+
179
+ context "for get operations" do
180
+ before :each do
181
+ @args[:method] = :put
182
+ end
183
+
184
+ it_should_behave_like "requests with a body param"
185
+ end
186
+
187
+ context "for delete operations" do
188
+ before :each do
189
+ @args[:method] = :post
190
+ end
191
+
192
+ it_should_behave_like "requests with a body param"
193
+ end
194
+ end
195
+
196
+ it "includes the access token if the token is not the main one for the request" do
197
+ params = Koala::Facebook::BatchOperation.new(@args).to_batch_params(nil)
198
+ params[:relative_url].should =~ /access_token=#{@args[:access_token]}/
199
+ end
200
+
201
+ it "includes the other arguments if the token is not the main one for the request" do
202
+ @args[:args] = {:a => 2}
203
+ params = Koala::Facebook::BatchOperation.new(@args).to_batch_params(nil)
204
+ params[:relative_url].should =~ /a=2/
205
+ end
206
+
207
+ it "does not include the access token if the token is the main one for the request" do
208
+ params = Koala::Facebook::BatchOperation.new(@args).to_batch_params(@args[:access_token])
209
+ params[:relative_url].should_not =~ /access_token=#{@args[:access_token]}/
210
+ end
211
+
212
+ it "includes the other arguments if the token is the main one for the request" do
213
+ @args[:args] = {:a => 2}
214
+ params = Koala::Facebook::BatchOperation.new(@args).to_batch_params(@args[:access_token])
215
+ params[:relative_url].should =~ /a=2/
216
+ end
217
+
218
+ it "includes any arguments passed as http_options[:batch_args]" do
219
+ batch_args = {:name => "baz", :headers => {:some_param => true}}
220
+ @args[:http_options][:batch_args] = batch_args
221
+ params = Koala::Facebook::BatchOperation.new(@args).to_batch_params(nil)
222
+ params.should include(batch_args)
223
+ end
224
+
225
+ it "includes the method" do
226
+ params = Koala::Facebook::BatchOperation.new(@args).to_batch_params(@args[:access_token])
227
+ params[:method].should == @args[:method].to_s
228
+ end
229
+
230
+ it "works with nil http_options" do
231
+ expect { Koala::Facebook::BatchOperation.new(@args.merge(:http_options => nil)).to_batch_params(nil) }.not_to raise_exception
232
+ end
233
+
234
+ it "works with nil args" do
235
+ expect { Koala::Facebook::BatchOperation.new(@args.merge(:args => nil)).to_batch_params(nil) }.not_to raise_exception
236
+ end
237
+
238
+ describe "with binary files" do
239
+ before :each do
240
+ @binary = stub("Binary file")
241
+ Koala::UploadableIO.stub(:binary_content?).and_return(false)
242
+ Koala::UploadableIO.stub(:binary_content?).with(@binary).and_return(true)
243
+ @uploadable_io = stub("UploadableIO")
244
+ Koala::UploadableIO.stub(:new).with(@binary).and_return(@uploadable_io)
245
+ @uploadable_io.stub(:is_a?).with(Koala::UploadableIO).and_return(true)
246
+
247
+ @batch_queue = []
248
+ Koala::Facebook::GraphAPI.stub(:batch_calls).and_return(@batch_queue)
249
+
250
+ @args[:method] = "post" # files are always post
251
+ end
252
+
253
+ it "adds file identifiers as attached_files in a comma-separated list" do
254
+ @args[:args].merge!("source" => @binary, "source2" => @binary)
255
+ batch_op = Koala::Facebook::BatchOperation.new(@args)
256
+ file_ids = batch_op.files.find_all {|k, v| v == @uploadable_io}.map {|k, v| k}
257
+ params = batch_op.to_batch_params(nil)
258
+ params[:attached_files].should == file_ids.join(",")
259
+ end
260
+ end
261
+ end
262
+
263
+ end
264
+
265
+ describe "GraphAPI batch interface" do
266
+
267
+ it "returns nothing for a batch operation" do
268
+ Koala.stub(:make_request).and_return(Koala::Response.new(200, "[]", {}))
269
+ @api.batch do |batch_api|
270
+ batch_api.get_object('me').should be_nil
271
+ end
272
+ end
273
+
274
+ describe "#batch" do
275
+ before :each do
276
+ @fake_response = Koala::Response.new(200, "[]", {})
277
+ Koala.stub(:make_request).and_return(@fake_response)
278
+ end
279
+
280
+ describe "making the request" do
281
+ context "with no calls" do
282
+ it "does not make any requests if batch_calls is empty" do
283
+ Koala.should_not_receive(:make_request)
284
+ @api.batch {|batch_api|}
285
+ end
286
+
287
+ it "returns []" do
288
+ @api.batch {|batch_api|}.should == []
289
+ end
290
+ end
291
+
292
+ it "includes the first operation's access token as the main one in the args" do
293
+ access_token = "foo"
294
+ Koala.should_receive(:make_request).with(anything, hash_including("access_token" => access_token), anything, anything).and_return(@fake_response)
295
+ Koala::Facebook::API.new(access_token).batch do |batch_api|
296
+ batch_api.get_object('me')
297
+ batch_api.get_object('me', {}, {'access_token' => 'bar'})
298
+ end
299
+ end
300
+
301
+ it "sets args['batch'] to a json'd map of all the batch params" do
302
+ access_token = "bar"
303
+ op = Koala::Facebook::BatchOperation.new(:access_token => access_token, :method => :get, :url => "/")
304
+ op.stub(:to_batch_params).and_return({:a => 2})
305
+ Koala::Facebook::BatchOperation.stub(:new).and_return(op)
306
+
307
+ # two requests should generate two batch operations
308
+ expected = MultiJson.encode([op.to_batch_params(access_token), op.to_batch_params(access_token)])
309
+ Koala.should_receive(:make_request).with(anything, hash_including("batch" => expected), anything, anything).and_return(@fake_response)
310
+ Koala::Facebook::API.new(access_token).batch do |batch_api|
311
+ batch_api.get_object('me')
312
+ batch_api.get_object('me')
313
+ end
314
+ end
315
+
316
+ it "adds any files from the batch operations to the arguments" do
317
+ # stub the batch operation
318
+ # we test above to ensure that files are properly assimilated into the BatchOperation instance
319
+ # right now, we want to make sure that batch_api handles them properly
320
+ @key = "file0_0"
321
+ @uploadable_io = stub("UploadableIO")
322
+ batch_op = stub("Koala Batch Operation", :files => {@key => @uploadable_io}, :to_batch_params => {}, :access_token => "foo")
323
+ Koala::Facebook::BatchOperation.stub(:new).and_return(batch_op)
324
+
325
+ Koala.should_receive(:make_request).with(anything, hash_including(@key => @uploadable_io), anything, anything).and_return(@fake_response)
326
+ Koala::Facebook::API.new("bar").batch do |batch_api|
327
+ batch_api.put_picture("path/to/file", "image/jpeg")
328
+ end
329
+ end
330
+
331
+ it "preserves operation order" do
332
+ access_token = "bar"
333
+ # two requests should generate two batch operations
334
+ Koala.should_receive(:make_request) do |url, args, method, options|
335
+ # test the batch operations to make sure they appear in the right order
336
+ (args ||= {})["batch"].should =~ /.*me\/farglebarg.*otheruser\/bababa/
337
+ @fake_response
338
+ end
339
+ Koala::Facebook::API.new(access_token).batch do |batch_api|
340
+ batch_api.get_connections('me', "farglebarg")
341
+ batch_api.get_connections('otheruser', "bababa")
342
+ end
343
+ end
344
+
345
+ it "makes a POST request" do
346
+ Koala.should_receive(:make_request).with(anything, anything, "post", anything).and_return(@fake_response)
347
+ Koala::Facebook::API.new("foo").batch do |batch_api|
348
+ batch_api.get_object('me')
349
+ end
350
+ end
351
+
352
+ it "makes a request to /" do
353
+ Koala.should_receive(:make_request).with("/", anything, anything, anything).and_return(@fake_response)
354
+ Koala::Facebook::API.new("foo").batch do |batch_api|
355
+ batch_api.get_object('me')
356
+ end
357
+ end
358
+
359
+ it "includes any http options specified at the top level" do
360
+ http_options = {"a" => "baz"}
361
+ Koala.should_receive(:make_request).with(anything, anything, anything, hash_including(http_options)).and_return(@fake_response)
362
+ Koala::Facebook::API.new("foo").batch(http_options) do |batch_api|
363
+ batch_api.get_object('me')
364
+ end
365
+ end
366
+ end
367
+
368
+ describe "processing the request" do
369
+ it "throws an error if the response is not 200" do
370
+ Koala.stub(:make_request).and_return(Koala::Response.new(500, "[]", {}))
371
+ expect { Koala::Facebook::API.new("foo").batch do |batch_api|
372
+ batch_api.get_object('me')
373
+ end }.to raise_exception(Koala::Facebook::APIError)
374
+ end
375
+
376
+ it "throws an error if the response is a Batch API-style error" do
377
+ Koala.stub(:make_request).and_return(Koala::Response.new(200, '{"error":190,"error_description":"Error validating access token."}', {}))
378
+ expect { Koala::Facebook::API.new("foo").batch do |batch_api|
379
+ batch_api.get_object('me')
380
+ end }.to raise_exception(Koala::Facebook::APIError)
381
+ end
382
+
383
+ it "returns the result status if http_component is status" do
384
+ Koala.stub(:make_request).and_return(Koala::Response.new(200, '[{"code":203,"headers":[{"name":"Content-Type","value":"text/javascript; charset=UTF-8"}],"body":"{\"id\":\"1234\"}"}]', {}))
385
+ result = @api.batch do |batch_api|
386
+ batch_api.get_object(KoalaTest.user1, {}, :http_component => :status)
387
+ end
388
+ result[0].should == 203
389
+ end
390
+
391
+ it "returns the result headers as a hash if http_component is headers" do
392
+ Koala.stub(:make_request).and_return(Koala::Response.new(200, '[{"code":203,"headers":[{"name":"Content-Type","value":"text/javascript; charset=UTF-8"}],"body":"{\"id\":\"1234\"}"}]', {}))
393
+ result = @api.batch do |batch_api|
394
+ batch_api.get_object(KoalaTest.user1, {}, :http_component => :headers)
395
+ end
396
+ result[0].should == {"Content-Type" => "text/javascript; charset=UTF-8"}
397
+ end
398
+ end
399
+
400
+ it "is thread safe" do
401
+ # ensure batch operations on one thread don't affect those on another
402
+ thread_one_count = 0
403
+ thread_two_count = 0
404
+ first_count = 20
405
+ second_count = 10
406
+
407
+ Koala.stub(:make_request).and_return(@fake_response)
408
+
409
+ thread1 = Thread.new do
410
+ @api.batch do |batch_api|
411
+ first_count.times {|i| batch_api.get_object("me"); sleep(0.01) }
412
+ thread_one_count = batch_api.batch_calls.count
413
+ end
414
+ end
415
+
416
+ thread2 = Thread.new do
417
+ @api.batch do |batch_api|
418
+ second_count.times {|i| batch_api.get_object("me"); sleep(0.01) }
419
+ thread_two_count = batch_api.batch_calls.count
420
+ end
421
+ end
422
+
423
+ thread1.join
424
+ thread2.join
425
+
426
+ thread_one_count.should == first_count
427
+ thread_two_count.should == second_count
428
+ end
429
+ end
430
+ end
431
+
432
+ describe "usage tests" do
433
+ it "can get two results at once" do
434
+ me, koppel = @api.batch do |batch_api|
435
+ batch_api.get_object('me')
436
+ batch_api.get_object(KoalaTest.user1)
437
+ end
438
+ me['id'].should_not be_nil
439
+ koppel['id'].should_not be_nil
440
+ end
441
+
442
+ it 'should be able to make mixed calls inside of a batch' do
443
+ me, friends = @api.batch do |batch_api|
444
+ batch_api.get_object('me')
445
+ batch_api.get_connections('me', 'friends')
446
+ end
447
+ me['id'].should_not be_nil
448
+ friends.should be_an(Array)
449
+ end
450
+
451
+ it 'should be able to make a get_picture call inside of a batch' do
452
+ pictures = @api.batch do |batch_api|
453
+ batch_api.get_picture('me')
454
+ end
455
+ pictures.first.should_not be_empty
456
+ end
457
+
458
+ it "should handle requests for two different tokens" do
459
+ me, insights = @api.batch do |batch_api|
460
+ batch_api.get_object('me')
461
+ batch_api.get_connections(@app_id, 'insights', {}, {"access_token" => @app_api.access_token})
462
+ end
463
+ me['id'].should_not be_nil
464
+ insights.should be_an(Array)
465
+ end
466
+
467
+ it "inserts errors in the appropriate place, without breaking other results" do
468
+ failed_insights, koppel = @api.batch do |batch_api|
469
+ batch_api.get_connections(@app_id, 'insights')
470
+ batch_api.get_object(KoalaTest.user1, {}, {"access_token" => @app_api.access_token})
471
+ end
472
+ failed_insights.should be_a(Koala::Facebook::APIError)
473
+ koppel["id"].should_not be_nil
474
+ end
475
+
476
+ it "handles different request methods" do
477
+ result = @api.put_wall_post("Hello, world, from the test suite batch API!")
478
+ wall_post = result["id"]
479
+
480
+ wall_post, koppel = @api.batch do |batch_api|
481
+ batch_api.put_like(wall_post)
482
+ batch_api.delete_object(wall_post)
483
+ end
484
+ end
485
+
486
+ it "allows FQL" do
487
+ result = @api.batch do |batch_api|
488
+ batch_api.graph_call("method/fql.query", {:query=>"select first_name from user where uid=#{KoalaTest.user1_id}"}, "post")
489
+ end
490
+
491
+ fql_result = result[0]
492
+ fql_result[0].should be_a(Hash)
493
+ fql_result[0]["first_name"].should == "Alex"
494
+ end
495
+
496
+ describe "binary files" do
497
+ it "posts binary files" do
498
+ file = File.open(File.join(File.dirname(__FILE__), "..", "fixtures", "beach.jpg"))
499
+
500
+ Koala::Facebook::BatchOperation.instance_variable_set(:@identifier, 0)
501
+ result = @api.batch do |batch_api|
502
+ batch_api.put_picture(file)
503
+ end
504
+
505
+ @temporary_object_id = result[0]["id"]
506
+ @temporary_object_id.should_not be_nil
507
+ end
508
+
509
+ it "posts binary files with multiple requests" do
510
+ file = File.open(File.join(File.dirname(__FILE__), "..", "fixtures", "beach.jpg"))
511
+ file2 = File.open(File.join(File.dirname(__FILE__), "..", "fixtures", "beach.jpg"))
512
+
513
+ Koala::Facebook::BatchOperation.instance_variable_set(:@identifier, 0)
514
+ results = @api.batch do |batch_api|
515
+ batch_api.put_picture(file)
516
+ batch_api.put_picture(file2, {}, KoalaTest.user1)
517
+ end
518
+ results[0]["id"].should_not be_nil
519
+ results[1]["id"].should_not be_nil
520
+ end
521
+ end
522
+
523
+ describe "relating requests" do
524
+ it "allows you create relationships between requests without omit_response_on_success" do
525
+ results = @api.batch do |batch_api|
526
+ batch_api.get_connections("me", "friends", {:limit => 5}, :batch_args => {:name => "get-friends"})
527
+ batch_api.get_objects("{result=get-friends:$.data.*.id}")
528
+ end
529
+
530
+ results[0].should be_nil
531
+ results[1].should be_an(Hash)
532
+ end
533
+
534
+ it "allows you create relationships between requests with omit_response_on_success" do
535
+ results = @api.batch do |batch_api|
536
+ batch_api.get_connections("me", "friends", {:limit => 5}, :batch_args => {:name => "get-friends", :omit_response_on_success => false})
537
+ batch_api.get_objects("{result=get-friends:$.data.*.id}")
538
+ end
539
+
540
+ results[0].should be_an(Array)
541
+ results[1].should be_an(Hash)
542
+ end
543
+
544
+ it "allows you to create dependencies" do
545
+ me, koppel = @api.batch do |batch_api|
546
+ batch_api.get_object("me", {}, :batch_args => {:name => "getme"})
547
+ batch_api.get_object(KoalaTest.user1, {}, :batch_args => {:depends_on => "getme"})
548
+ end
549
+
550
+ me.should be_nil # gotcha! it's omitted because it's a successfully-executed dependency
551
+ koppel["id"].should_not be_nil
552
+ end
553
+
554
+ it "properly handles dependencies that fail" do
555
+ data, koppel = @api.batch do |batch_api|
556
+ batch_api.get_connections(@app_id, 'insights', {}, :batch_args => {:name => "getdata"})
557
+ batch_api.get_object(KoalaTest.user1, {}, :batch_args => {:depends_on => "getdata"})
558
+ end
559
+
560
+ data.should be_a(Koala::Facebook::APIError)
561
+ koppel.should be_nil
562
+ end
563
+
564
+ it "throws an error for badly-constructed request relationships" do
565
+ expect {
566
+ @api.batch do |batch_api|
567
+ batch_api.get_connections("me", "friends", {:limit => 5})
568
+ batch_api.get_objects("{result=i-dont-exist:$.data.*.id}")
569
+ end
570
+ }.to raise_exception(Koala::Facebook::APIError)
571
+ end
572
+ end
573
+ end
574
+
575
+ describe "new interface" do
576
+ it "includes a deprecation warning on GraphAPI" do
577
+ begin
578
+ Koala::Facebook::GraphAPI.batch do
579
+ end
580
+ rescue NoMethodError => @err
581
+ end
582
+
583
+ # verify the message points people to the wiki page
584
+ @err.should
585
+ @err.message.should =~ /https\:\/\/github.com\/arsduo\/koala\/wiki\/Batch-requests/
586
+ end
587
+
588
+ it "includes a deprecation warning on GraphAndRESTAPI" do
589
+ begin
590
+ Koala::Facebook::GraphAndRestAPI.batch do
591
+ end
592
+ rescue NoMethodError => @err
593
+ end
594
+
595
+ # verify the message points people to the wiki page
596
+ @err.should
597
+ @err.message.should =~ /https\:\/\/github.com\/arsduo\/koala\/wiki\/Batch-requests/
598
+ end
599
+ end
600
+ end