koala 1.0.0 → 1.1.0
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.
- data/.autotest +12 -0
- data/.gitignore +3 -1
- data/.travis.yml +8 -0
- data/CHANGELOG +26 -2
- data/Gemfile +4 -0
- data/autotest/discover.rb +1 -0
- data/koala.gemspec +8 -8
- data/lib/koala/batch_operation.rb +74 -0
- data/lib/koala/graph_api.rb +103 -102
- data/lib/koala/graph_batch_api.rb +87 -0
- data/lib/koala/graph_collection.rb +54 -0
- data/lib/koala/http_services/net_http_service.rb +92 -0
- data/lib/koala/http_services/typhoeus_service.rb +37 -0
- data/lib/koala/http_services.rb +13 -113
- data/lib/koala/oauth.rb +181 -0
- data/lib/koala/realtime_updates.rb +5 -14
- data/lib/koala/rest_api.rb +13 -8
- data/lib/koala/uploadable_io.rb +137 -77
- data/lib/koala.rb +36 -196
- data/readme.md +51 -32
- data/spec/cases/api_base_spec.rb +4 -4
- data/spec/cases/graph_api_batch_spec.rb +609 -0
- data/spec/cases/http_services/http_service_spec.rb +87 -12
- data/spec/cases/http_services/net_http_service_spec.rb +259 -77
- data/spec/cases/http_services/typhoeus_service_spec.rb +29 -21
- data/spec/cases/koala_spec.rb +55 -0
- data/spec/cases/oauth_spec.rb +1 -1
- data/spec/cases/realtime_updates_spec.rb +3 -3
- data/spec/cases/test_users_spec.rb +1 -1
- data/spec/cases/uploadable_io_spec.rb +56 -14
- data/spec/fixtures/cat.m4v +0 -0
- data/spec/fixtures/mock_facebook_responses.yml +100 -5
- data/spec/spec_helper.rb +2 -1
- data/spec/support/graph_api_shared_examples.rb +106 -35
- data/spec/support/json_testing_fix.rb +18 -0
- data/spec/support/mock_http_service.rb +57 -56
- data/spec/support/rest_api_shared_examples.rb +131 -7
- data/spec/support/setup_mocks_or_live.rb +3 -4
- metadata +34 -47
|
@@ -51,9 +51,19 @@ shared_examples_for "Koala GraphAPI" do
|
|
|
51
51
|
(result["id"] && result["name"]).should
|
|
52
52
|
end
|
|
53
53
|
|
|
54
|
+
it "should return [] from get_objects if passed an empty array" do
|
|
55
|
+
results = @api.get_objects([])
|
|
56
|
+
results.should == []
|
|
57
|
+
end
|
|
58
|
+
|
|
54
59
|
it "should be able to get multiple objects" do
|
|
55
60
|
results = @api.get_objects(["contextoptional", "naitik"])
|
|
56
|
-
results.
|
|
61
|
+
results.should have(2).items
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
it "should be able to get multiple objects if they're a string" do
|
|
65
|
+
results = @api.get_objects("contextoptional,naitik")
|
|
66
|
+
results.should have(2).items
|
|
57
67
|
end
|
|
58
68
|
|
|
59
69
|
it "should be able to access a user's picture" do
|
|
@@ -69,6 +79,16 @@ shared_examples_for "Koala GraphAPI" do
|
|
|
69
79
|
result.should be_a(Array)
|
|
70
80
|
end
|
|
71
81
|
|
|
82
|
+
it "should be able to access comments for a URL" do
|
|
83
|
+
result = @api.get_comments_for_urls(["http://developers.facebook.com/blog/post/472"])
|
|
84
|
+
(result["http://developers.facebook.com/blog/post/472"]).should
|
|
85
|
+
end
|
|
86
|
+
|
|
87
|
+
it "should be able to access comments for 2 URLs" do
|
|
88
|
+
result = @api.get_comments_for_urls(["http://developers.facebook.com/blog/post/490", "http://developers.facebook.com/blog/post/472"])
|
|
89
|
+
(result["http://developers.facebook.com/blog/post/490"] && result["http://developers.facebook.com/blog/post/472"]).should
|
|
90
|
+
end
|
|
91
|
+
|
|
72
92
|
# SEARCH
|
|
73
93
|
it "should be able to search" do
|
|
74
94
|
result = @api.search("facebook")
|
|
@@ -86,7 +106,6 @@ end
|
|
|
86
106
|
|
|
87
107
|
|
|
88
108
|
shared_examples_for "Koala GraphAPI with an access token" do
|
|
89
|
-
|
|
90
109
|
it "should get private data about a user" do
|
|
91
110
|
result = @api.get_object("koppel")
|
|
92
111
|
# updated_time should be a pretty fixed test case
|
|
@@ -147,36 +166,87 @@ shared_examples_for "Koala GraphAPI with an access token" do
|
|
|
147
166
|
@temporary_object_id.should_not be_nil
|
|
148
167
|
end
|
|
149
168
|
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
result = @api.put_picture(file, content_type)
|
|
155
|
-
@temporary_object_id = result["id"]
|
|
156
|
-
@temporary_object_id.should_not be_nil
|
|
157
|
-
end
|
|
169
|
+
describe ".put_picture" do
|
|
170
|
+
it "should be able to post photos to the user's wall with an open file object" do
|
|
171
|
+
content_type = "image/jpg"
|
|
172
|
+
file = File.open(File.join(File.dirname(__FILE__), "..", "fixtures", "beach.jpg"))
|
|
158
173
|
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
174
|
+
result = @api.put_picture(file, content_type)
|
|
175
|
+
@temporary_object_id = result["id"]
|
|
176
|
+
@temporary_object_id.should_not be_nil
|
|
177
|
+
end
|
|
178
|
+
|
|
179
|
+
it "uses the base HTTP service if the upload is a StringIO or similar" do
|
|
180
|
+
source = stub("UploadIO")
|
|
181
|
+
Koala::UploadableIO.stub(:new).and_return(source)
|
|
182
|
+
source.stub(:requires_base_http_service).and_return(true)
|
|
183
|
+
Koala.should_receive(:make_request).with(anything, anything, anything, hash_including(:http_service => Koala.base_http_service)).and_return(Koala::Response.new(200, "[]", {}))
|
|
184
|
+
@api.put_picture(StringIO.new)
|
|
185
|
+
end
|
|
186
|
+
|
|
187
|
+
it "should be able to post photos to the user's wall without an open file object" do
|
|
188
|
+
content_type = "image/jpg",
|
|
189
|
+
file_path = File.join(File.dirname(__FILE__), "..", "fixtures", "beach.jpg")
|
|
190
|
+
|
|
191
|
+
result = @api.put_picture(file_path, content_type)
|
|
192
|
+
@temporary_object_id = result["id"]
|
|
193
|
+
@temporary_object_id.should_not be_nil
|
|
194
|
+
end
|
|
195
|
+
|
|
196
|
+
it "should be able to verify a photo posted to a user's wall" do
|
|
197
|
+
content_type = "image/jpg",
|
|
198
|
+
file_path = File.join(File.dirname(__FILE__), "..", "fixtures", "beach.jpg")
|
|
199
|
+
|
|
200
|
+
expected_message = "This is the test message"
|
|
201
|
+
|
|
202
|
+
result = @api.put_picture(file_path, content_type, :message => expected_message)
|
|
203
|
+
@temporary_object_id = result["id"]
|
|
204
|
+
@temporary_object_id.should_not be_nil
|
|
205
|
+
|
|
206
|
+
get_result = @api.get_object(@temporary_object_id)
|
|
207
|
+
get_result["name"].should == expected_message
|
|
208
|
+
end
|
|
166
209
|
end
|
|
210
|
+
|
|
211
|
+
describe ".put_video" do
|
|
212
|
+
before :each do
|
|
213
|
+
@cat_movie = File.join(File.dirname(__FILE__), "..", "fixtures", "cat.m4v")
|
|
214
|
+
@content_type = "video/mpeg4"
|
|
215
|
+
end
|
|
167
216
|
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
@temporary_object_id = result["id"]
|
|
176
|
-
@temporary_object_id.should_not be_nil
|
|
217
|
+
it "should set options[:video] to true" do
|
|
218
|
+
source = stub("UploadIO")
|
|
219
|
+
Koala::UploadableIO.stub(:new).and_return(source)
|
|
220
|
+
source.stub(:requires_base_http_service).and_return(false)
|
|
221
|
+
Koala.should_receive(:make_request).with(anything, anything, anything, hash_including(:video => true)).and_return(Koala::Response.new(200, "[]", {}))
|
|
222
|
+
@api.put_video("foo")
|
|
223
|
+
end
|
|
177
224
|
|
|
178
|
-
|
|
179
|
-
|
|
225
|
+
it "should be able to post videos to the user's wall with an open file object" do
|
|
226
|
+
file = File.open(@cat_movie)
|
|
227
|
+
|
|
228
|
+
result = @api.put_video(file, @content_type)
|
|
229
|
+
@temporary_object_id = result["id"]
|
|
230
|
+
@temporary_object_id.should_not be_nil
|
|
231
|
+
end
|
|
232
|
+
|
|
233
|
+
it "uses the base HTTP service if the upload is a StringIO or similar" do
|
|
234
|
+
source = stub("UploadIO")
|
|
235
|
+
Koala::UploadableIO.stub(:new).and_return(source)
|
|
236
|
+
source.stub(:requires_base_http_service).and_return(true)
|
|
237
|
+
Koala.should_receive(:make_request).with(anything, anything, anything, hash_including(:http_service => Koala.base_http_service)).and_return(Koala::Response.new(200, "[]", {}))
|
|
238
|
+
@api.put_video(StringIO.new)
|
|
239
|
+
end
|
|
240
|
+
|
|
241
|
+
it "should be able to post videos to the user's wall without an open file object" do
|
|
242
|
+
result = @api.put_video(@cat_movie, @content_type)
|
|
243
|
+
@temporary_object_id = result["id"]
|
|
244
|
+
@temporary_object_id.should_not be_nil
|
|
245
|
+
end
|
|
246
|
+
|
|
247
|
+
# note: Facebook doesn't post videos immediately to the wall, due to processing time
|
|
248
|
+
# during which get_object(video_id) will return false
|
|
249
|
+
# hence we can't do the same verify test we do for photos
|
|
180
250
|
end
|
|
181
251
|
|
|
182
252
|
it "should be able to verify a message with an attachment posted to a feed" do
|
|
@@ -240,6 +310,7 @@ shared_examples_for "Koala GraphAPI with an access token" do
|
|
|
240
310
|
:search => 3,
|
|
241
311
|
# methods that have special arguments
|
|
242
312
|
:put_picture => ["x.jpg", "image/jpg", {}, "me"],
|
|
313
|
+
:put_video => ["x.mp4", "video/mpeg4", {}, "me"],
|
|
243
314
|
:get_objects => [["x"], {}]
|
|
244
315
|
}.each_pair do |method_name, params|
|
|
245
316
|
it "should pass http options through for #{method_name}" do
|
|
@@ -316,8 +387,8 @@ shared_examples_for "Koala GraphAPI with GraphCollection" do
|
|
|
316
387
|
end
|
|
317
388
|
|
|
318
389
|
it "should have a read-only paging attribute" do
|
|
319
|
-
|
|
320
|
-
|
|
390
|
+
@result.methods.map(&:to_sym).should include(:paging)
|
|
391
|
+
@result.methods.map(&:to_sym).should_not include(:paging=)
|
|
321
392
|
end
|
|
322
393
|
|
|
323
394
|
describe "when getting a whole page" do
|
|
@@ -330,18 +401,18 @@ shared_examples_for "Koala GraphAPI with GraphCollection" do
|
|
|
330
401
|
|
|
331
402
|
it "should return the previous page of results" do
|
|
332
403
|
@result.should_receive(:previous_page_params).and_return([@base, @args])
|
|
333
|
-
@api.should_receive(:graph_call).with(@base, @args).
|
|
404
|
+
@api.should_receive(:graph_call).with(@base, @args).and_yield(@second_page)
|
|
334
405
|
Koala::Facebook::GraphCollection.should_receive(:new).with(@second_page, @api).and_return(@page_of_results)
|
|
335
406
|
|
|
336
|
-
@result.previous_page
|
|
407
|
+
@result.previous_page#.should == @page_of_results
|
|
337
408
|
end
|
|
338
409
|
|
|
339
410
|
it "should return the next page of results" do
|
|
340
411
|
@result.should_receive(:next_page_params).and_return([@base, @args])
|
|
341
|
-
@api.should_receive(:graph_call).with(@base, @args).
|
|
412
|
+
@api.should_receive(:graph_call).with(@base, @args).and_yield(@second_page)
|
|
342
413
|
Koala::Facebook::GraphCollection.should_receive(:new).with(@second_page, @api).and_return(@page_of_results)
|
|
343
414
|
|
|
344
|
-
@result.next_page
|
|
415
|
+
@result.next_page#.should == @page_of_results
|
|
345
416
|
end
|
|
346
417
|
|
|
347
418
|
it "should return nil it there are no other pages" do
|
|
@@ -421,4 +492,4 @@ shared_examples_for "Koala GraphAPI without an access token" do
|
|
|
421
492
|
it "should not be able to delete a like" do
|
|
422
493
|
lambda { @api.delete_like("7204941866_119776748033392") }.should raise_error(Koala::Facebook::APIError)
|
|
423
494
|
end
|
|
424
|
-
end
|
|
495
|
+
end
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
# when testing across Ruby versions, we found that JSON string creation inconsistently ordered keys
|
|
2
|
+
# which is a problem because our mock testing service ultimately matches strings to see if requests are mocked
|
|
3
|
+
# this fix solves that problem by ensuring all hashes are created with a consistent key order every time
|
|
4
|
+
|
|
5
|
+
module MultiJson
|
|
6
|
+
self.engine = :ok_json
|
|
7
|
+
|
|
8
|
+
def encode_with_ordering(object)
|
|
9
|
+
# if it's a hash, recreate it with k/v pairs inserted in sorted-by-key order
|
|
10
|
+
# (for some reason, REE 1.8.7 fails if we don't assign the ternary result as a local variable
|
|
11
|
+
# separate from calling encode_original)
|
|
12
|
+
new_object = object.is_a?(Hash) ? object.keys.sort.inject({}) {|hash, k| hash[k] = object[k]; hash} : object
|
|
13
|
+
encode_original(new_object)
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
alias_method :encode_original, :encode
|
|
17
|
+
alias_method :encode, :encode_with_ordering
|
|
18
|
+
end
|
|
@@ -3,11 +3,15 @@ require 'yaml'
|
|
|
3
3
|
|
|
4
4
|
module Koala
|
|
5
5
|
module MockHTTPService
|
|
6
|
-
|
|
7
|
-
|
|
6
|
+
include Koala::HTTPService
|
|
7
|
+
|
|
8
|
+
# fix our specs to use ok_json, so we always get the same results from to_json
|
|
9
|
+
MultiJson.engine = :ok_json
|
|
8
10
|
|
|
11
|
+
# Mocks all HTTP requests for with koala_spec_with_mocks.rb
|
|
9
12
|
# Mocked values to be included in TEST_DATA used in specs
|
|
10
13
|
ACCESS_TOKEN = '*'
|
|
14
|
+
APP_ACCESS_TOKEN = "**"
|
|
11
15
|
OAUTH_CODE = 'OAUTHCODE'
|
|
12
16
|
|
|
13
17
|
# Loads testing data
|
|
@@ -18,7 +22,7 @@ module Koala
|
|
|
18
22
|
# Useful in mock_facebook_responses.yml
|
|
19
23
|
OAUTH_DATA = TEST_DATA['oauth_test_data']
|
|
20
24
|
OAUTH_DATA.merge!({
|
|
21
|
-
'app_access_token' =>
|
|
25
|
+
'app_access_token' => APP_ACCESS_TOKEN,
|
|
22
26
|
'session_key' => "session_key",
|
|
23
27
|
'multiple_session_keys' => ["session_key", "session_key_2"]
|
|
24
28
|
})
|
|
@@ -30,66 +34,63 @@ module Koala
|
|
|
30
34
|
mock_response_file_path = File.join(File.dirname(__FILE__), '..', 'fixtures', 'mock_facebook_responses.yml')
|
|
31
35
|
RESPONSES = YAML.load(ERB.new(IO.read(mock_response_file_path)).result(binding))
|
|
32
36
|
|
|
33
|
-
def self.
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
path = 'root' if path == '' || path == '/'
|
|
40
|
-
verb ||= 'get'
|
|
41
|
-
server = options[:rest_api] ? 'rest_api' : 'graph_api'
|
|
42
|
-
with_token = args.delete('access_token') == ACCESS_TOKEN ? 'with_token' : 'no_token'
|
|
43
|
-
|
|
44
|
-
# Assume format is always JSON
|
|
45
|
-
args.delete('format')
|
|
37
|
+
def self.make_request(path, args, verb, options = {})
|
|
38
|
+
path = 'root' if path == '' || path == '/'
|
|
39
|
+
verb ||= 'get'
|
|
40
|
+
server = options[:rest_api] ? 'rest_api' : 'graph_api'
|
|
41
|
+
token = args.delete('access_token')
|
|
42
|
+
with_token = (token == ACCESS_TOKEN || token == APP_ACCESS_TOKEN) ? 'with_token' : 'no_token'
|
|
46
43
|
|
|
47
|
-
|
|
48
|
-
|
|
44
|
+
# Assume format is always JSON
|
|
45
|
+
args.delete('format')
|
|
49
46
|
|
|
50
|
-
|
|
51
|
-
|
|
47
|
+
# Create a hash key for the arguments
|
|
48
|
+
args = create_params_key(args)
|
|
52
49
|
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
# create response class object
|
|
57
|
-
response_object = if response.is_a? String
|
|
58
|
-
Koala::Response.new(200, response, {})
|
|
59
|
-
else
|
|
60
|
-
Koala::Response.new(response["code"] || 200, response["body"] || "", response["headers"] || {})
|
|
61
|
-
end
|
|
62
|
-
|
|
63
|
-
rescue NoMethodError
|
|
64
|
-
# Raises an error message with the place in the data YML
|
|
65
|
-
# to place a mock as well as a URL to request from
|
|
66
|
-
# Facebook's servers for the actual data
|
|
67
|
-
# (Don't forget to replace ACCESS_TOKEN with a real access token)
|
|
68
|
-
data_trace = [server, path, args, verb, with_token] * ': '
|
|
69
|
-
|
|
70
|
-
args = args == 'no_args' ? '' : "#{args}&"
|
|
71
|
-
args += 'format=json'
|
|
72
|
-
args += "&access_token=#{ACCESS_TOKEN}" if with_token
|
|
73
|
-
|
|
74
|
-
raise "Missing a mock response for #{data_trace}\nAPI PATH: #{[path, args].join('?')}"
|
|
75
|
-
end
|
|
50
|
+
begin
|
|
51
|
+
response = RESPONSES[server][path][args][verb][with_token]
|
|
76
52
|
|
|
77
|
-
|
|
78
|
-
|
|
53
|
+
# Raises an error of with_token/no_token key is missing
|
|
54
|
+
raise NoMethodError unless response
|
|
79
55
|
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
'no_args'
|
|
56
|
+
# create response class object
|
|
57
|
+
response_object = if response.is_a? String
|
|
58
|
+
Koala::Response.new(200, response, {})
|
|
84
59
|
else
|
|
85
|
-
|
|
86
|
-
arr[1] = '[FILE]' if arr[1].kind_of?(Koala::UploadableIO)
|
|
87
|
-
arr.join('=')
|
|
88
|
-
end.join('&')
|
|
60
|
+
Koala::Response.new(response["code"] || 200, response["body"] || "", response["headers"] || {})
|
|
89
61
|
end
|
|
90
|
-
end
|
|
91
62
|
|
|
92
|
-
|
|
93
|
-
|
|
63
|
+
rescue NoMethodError
|
|
64
|
+
# Raises an error message with the place in the data YML
|
|
65
|
+
# to place a mock as well as a URL to request from
|
|
66
|
+
# Facebook's servers for the actual data
|
|
67
|
+
# (Don't forget to replace ACCESS_TOKEN with a real access token)
|
|
68
|
+
data_trace = [server, path, args, verb, with_token] * ': '
|
|
69
|
+
|
|
70
|
+
args = args == 'no_args' ? '' : "#{args}&"
|
|
71
|
+
args += 'format=json'
|
|
72
|
+
args += "&access_token=#{ACCESS_TOKEN}" if with_token
|
|
73
|
+
|
|
74
|
+
raise "Missing a mock response for #{data_trace}\nAPI PATH: #{[path, args].join('?')}"
|
|
75
|
+
end
|
|
76
|
+
|
|
77
|
+
response_object
|
|
78
|
+
end
|
|
79
|
+
|
|
80
|
+
def self.mock?
|
|
81
|
+
true
|
|
82
|
+
end
|
|
83
|
+
|
|
84
|
+
protected
|
|
85
|
+
def self.create_params_key(params_hash)
|
|
86
|
+
if params_hash.empty?
|
|
87
|
+
'no_args'
|
|
88
|
+
else
|
|
89
|
+
params_hash.sort{ |a,b| a[0].to_s <=> b[0].to_s}.map do |arr|
|
|
90
|
+
arr[1] = '[FILE]' if arr[1].kind_of?(Koala::UploadableIO)
|
|
91
|
+
arr.join('=')
|
|
92
|
+
end.join('&')
|
|
93
|
+
end
|
|
94
|
+
end
|
|
94
95
|
end
|
|
95
96
|
end
|
|
@@ -87,6 +87,29 @@ shared_examples_for "Koala RestAPI" do
|
|
|
87
87
|
|
|
88
88
|
@api.rest_call('anything', {}, options)
|
|
89
89
|
end
|
|
90
|
+
|
|
91
|
+
it "uses get by default" do
|
|
92
|
+
@api.should_receive(:api).with(
|
|
93
|
+
anything,
|
|
94
|
+
anything,
|
|
95
|
+
"get",
|
|
96
|
+
anything
|
|
97
|
+
)
|
|
98
|
+
|
|
99
|
+
@api.rest_call('anything')
|
|
100
|
+
end
|
|
101
|
+
|
|
102
|
+
it "allows you to specify other http methods as the last argument" do
|
|
103
|
+
method = 'bar'
|
|
104
|
+
@api.should_receive(:api).with(
|
|
105
|
+
anything,
|
|
106
|
+
anything,
|
|
107
|
+
method,
|
|
108
|
+
anything
|
|
109
|
+
)
|
|
110
|
+
|
|
111
|
+
@api.rest_call('anything', {}, {}, method)
|
|
112
|
+
end
|
|
90
113
|
|
|
91
114
|
it "should throw an APIError if the result hash has an error key" do
|
|
92
115
|
Koala.stub(:make_request).and_return(Koala::Response.new(500, {"error_code" => "An error occurred!"}, {}))
|
|
@@ -96,8 +119,7 @@ shared_examples_for "Koala RestAPI" do
|
|
|
96
119
|
describe "when making a FQL request" do
|
|
97
120
|
it "should call fql.query method" do
|
|
98
121
|
@api.should_receive(:rest_call).with(
|
|
99
|
-
"fql.query",
|
|
100
|
-
anything
|
|
122
|
+
"fql.query", anything, anything
|
|
101
123
|
).and_return(Koala::Response.new(200, "2", {}))
|
|
102
124
|
|
|
103
125
|
@api.fql_query stub('query string')
|
|
@@ -107,17 +129,78 @@ shared_examples_for "Koala RestAPI" do
|
|
|
107
129
|
query = stub('query string')
|
|
108
130
|
|
|
109
131
|
@api.should_receive(:rest_call).with(
|
|
110
|
-
anything,
|
|
111
|
-
hash_including("query" => query)
|
|
132
|
+
anything, hash_including(:query => query), anything
|
|
112
133
|
)
|
|
113
134
|
|
|
114
135
|
@api.fql_query(query)
|
|
115
136
|
end
|
|
137
|
+
|
|
138
|
+
it "should pass on any other arguments provided" do
|
|
139
|
+
args = {:a => 2}
|
|
140
|
+
@api.should_receive(:rest_call).with(anything, hash_including(args), anything)
|
|
141
|
+
@api.fql_query("a query", args)
|
|
142
|
+
end
|
|
143
|
+
|
|
144
|
+
it "should pass on any http options provided" do
|
|
145
|
+
opts = {:a => 2}
|
|
146
|
+
@api.should_receive(:rest_call).with(anything, anything, hash_including(opts))
|
|
147
|
+
@api.fql_query("a query", {}, opts)
|
|
148
|
+
end
|
|
149
|
+
end
|
|
150
|
+
|
|
151
|
+
describe "when making a FQL-multiquery request" do
|
|
152
|
+
it "should call fql.multiquery method" do
|
|
153
|
+
@api.should_receive(:rest_call).with(
|
|
154
|
+
"fql.multiquery", anything, anything
|
|
155
|
+
).and_return({})
|
|
156
|
+
|
|
157
|
+
@api.fql_multiquery 'query string'
|
|
158
|
+
end
|
|
159
|
+
|
|
160
|
+
it "should pass a queries argument" do
|
|
161
|
+
queries = stub('query string')
|
|
162
|
+
queries_json = "some JSON"
|
|
163
|
+
MultiJson.stub(:encode).with(queries).and_return(queries_json)
|
|
164
|
+
|
|
165
|
+
@api.should_receive(:rest_call).with(
|
|
166
|
+
anything,
|
|
167
|
+
hash_including(:queries => queries_json),
|
|
168
|
+
anything
|
|
169
|
+
)
|
|
170
|
+
|
|
171
|
+
@api.fql_multiquery(queries)
|
|
172
|
+
end
|
|
173
|
+
|
|
174
|
+
it "simplifies the response format" do
|
|
175
|
+
raw_results = [
|
|
176
|
+
{"name" => "query1", "fql_result_set" => [1, 2, 3]},
|
|
177
|
+
{"name" => "query2", "fql_result_set" => [:a, :b, :c]}
|
|
178
|
+
]
|
|
179
|
+
expected_results = {
|
|
180
|
+
"query1" => [1, 2, 3],
|
|
181
|
+
"query2" => [:a, :b, :c]
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
@api.stub(:rest_call).and_return(raw_results)
|
|
185
|
+
results = @api.fql_multiquery({:query => true})
|
|
186
|
+
results.should == expected_results
|
|
187
|
+
end
|
|
188
|
+
|
|
189
|
+
it "should pass on any other arguments provided" do
|
|
190
|
+
args = {:a => 2}
|
|
191
|
+
@api.should_receive(:rest_call).with(anything, hash_including(args), anything)
|
|
192
|
+
@api.fql_multiquery("a query", args)
|
|
193
|
+
end
|
|
194
|
+
|
|
195
|
+
it "should pass on any http options provided" do
|
|
196
|
+
opts = {:a => 2}
|
|
197
|
+
@api.should_receive(:rest_call).with(anything, anything, hash_including(opts))
|
|
198
|
+
@api.fql_multiquery("a query", {}, opts)
|
|
199
|
+
end
|
|
116
200
|
end
|
|
117
201
|
end
|
|
118
202
|
end
|
|
119
203
|
|
|
120
|
-
|
|
121
204
|
shared_examples_for "Koala RestAPI with an access token" do
|
|
122
205
|
# FQL
|
|
123
206
|
it "should be able to access public information via FQL" do
|
|
@@ -126,6 +209,16 @@ shared_examples_for "Koala RestAPI with an access token" do
|
|
|
126
209
|
result.first['first_name'].should == 'Chris'
|
|
127
210
|
end
|
|
128
211
|
|
|
212
|
+
it "should be able to access public information via FQL.multiquery" do
|
|
213
|
+
result = @api.fql_multiquery(
|
|
214
|
+
:query1 => 'select first_name from user where uid = 216743',
|
|
215
|
+
:query2 => 'select first_name from user where uid = 2905623'
|
|
216
|
+
)
|
|
217
|
+
result.size.should == 2
|
|
218
|
+
result["query1"].first['first_name'].should == 'Chris'
|
|
219
|
+
result["query2"].first['first_name'].should == 'Alex'
|
|
220
|
+
end
|
|
221
|
+
|
|
129
222
|
it "should be able to access protected information via FQL" do
|
|
130
223
|
# Tests agains the permissions fql table
|
|
131
224
|
|
|
@@ -138,10 +231,21 @@ shared_examples_for "Koala RestAPI with an access token" do
|
|
|
138
231
|
result = @api.fql_query("select read_stream from permissions where uid = #{id}")
|
|
139
232
|
|
|
140
233
|
result.size.should == 1
|
|
141
|
-
# we
|
|
142
|
-
# (should we keep this?)
|
|
234
|
+
# we've verified that you have read_stream permissions, so we can test against that
|
|
143
235
|
result.first["read_stream"].should == 1
|
|
144
236
|
end
|
|
237
|
+
|
|
238
|
+
|
|
239
|
+
it "should be able to access protected information via FQL.multiquery" do
|
|
240
|
+
result = @api.fql_multiquery(
|
|
241
|
+
:query1 => "select post_id from stream where source_id = me()",
|
|
242
|
+
:query2 => "select fromid from comment where post_id in (select post_id from #query1)",
|
|
243
|
+
:query3 => "select uid, name from user where uid in (select fromid from #query2)"
|
|
244
|
+
)
|
|
245
|
+
result.size.should == 3
|
|
246
|
+
result.keys.should include("query1", "query2", "query3")
|
|
247
|
+
end
|
|
248
|
+
|
|
145
249
|
end
|
|
146
250
|
|
|
147
251
|
|
|
@@ -153,9 +257,29 @@ shared_examples_for "Koala RestAPI without an access token" do
|
|
|
153
257
|
@result.size.should == 1
|
|
154
258
|
@result.first["first_name"].should == "Chris"
|
|
155
259
|
end
|
|
260
|
+
|
|
261
|
+
it "should be able to access public information via FQL.multiquery" do
|
|
262
|
+
result = @api.fql_multiquery(
|
|
263
|
+
:query1 => 'select first_name from user where uid = 216743',
|
|
264
|
+
:query2 => 'select first_name from user where uid = 2905623'
|
|
265
|
+
)
|
|
266
|
+
result.size.should == 2
|
|
267
|
+
result["query1"].first['first_name'].should == 'Chris'
|
|
268
|
+
result["query2"].first['first_name'].should == 'Alex'
|
|
269
|
+
end
|
|
156
270
|
|
|
157
271
|
it "should not be able to access protected information via FQL" do
|
|
158
272
|
lambda { @api.fql_query("select read_stream from permissions where uid = 216743") }.should raise_error(Koala::Facebook::APIError)
|
|
159
273
|
end
|
|
274
|
+
|
|
275
|
+
it "should not be able to access protected information via FQL.multiquery" do
|
|
276
|
+
lambda {
|
|
277
|
+
@api.fql_multiquery(
|
|
278
|
+
:query1 => "select post_id from stream where source_id = me()",
|
|
279
|
+
:query2 => "select fromid from comment where post_id in (select post_id from #query1)",
|
|
280
|
+
:query3 => "select uid, name from user where uid in (select fromid from #query2)"
|
|
281
|
+
)
|
|
282
|
+
}.should raise_error(Koala::Facebook::APIError)
|
|
283
|
+
end
|
|
160
284
|
end
|
|
161
285
|
end
|
|
@@ -4,12 +4,11 @@ module KoalaTest
|
|
|
4
4
|
print "Validating permissions for live testing..."
|
|
5
5
|
# make sure we have the necessary permissions
|
|
6
6
|
api = Koala::Facebook::GraphAndRestAPI.new(token)
|
|
7
|
-
|
|
8
|
-
perms = api.fql_query("select read_stream, publish_stream, user_photos from permissions where uid = #{uid}")[0]
|
|
7
|
+
perms = api.fql_query("select read_stream, publish_stream, user_photos, user_videos, read_insights from permissions where uid = me()")[0]
|
|
9
8
|
perms.each_pair do |perm, value|
|
|
10
|
-
|
|
9
|
+
if value == (perm == "read_insights" ? 1 : 0) # live testing depends on insights calls failing
|
|
11
10
|
puts "failed!\n" # put a new line after the print above
|
|
12
|
-
raise ArgumentError, "Your access token must have the read_stream, publish_stream, and user_photos permissions. You have: #{perms.inspect}"
|
|
11
|
+
raise ArgumentError, "Your access token must have the read_stream, publish_stream, and user_photos permissions, and lack read_insights. You have: #{perms.inspect}"
|
|
13
12
|
end
|
|
14
13
|
end
|
|
15
14
|
puts "done!"
|