koala 1.0.0 → 1.2.0beta1
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 +9 -0
- data/CHANGELOG +52 -2
- data/Gemfile +8 -0
- data/Rakefile +0 -1
- data/autotest/discover.rb +1 -0
- data/koala.gemspec +14 -14
- data/lib/koala/batch_operation.rb +74 -0
- data/lib/koala/graph_api.rb +157 -133
- data/lib/koala/graph_batch_api.rb +87 -0
- data/lib/koala/graph_collection.rb +54 -0
- data/lib/koala/http_service.rb +177 -0
- data/lib/koala/oauth.rb +181 -0
- data/lib/koala/realtime_updates.rb +23 -29
- data/lib/koala/rest_api.rb +13 -8
- data/lib/koala/test_users.rb +33 -16
- data/lib/koala/uploadable_io.rb +152 -87
- data/lib/koala/utils.rb +11 -0
- data/lib/koala.rb +54 -217
- data/readme.md +71 -52
- data/spec/cases/api_base_spec.rb +6 -6
- data/spec/cases/error_spec.rb +32 -0
- data/spec/cases/graph_and_rest_api_spec.rb +20 -3
- data/spec/cases/graph_api_batch_spec.rb +600 -0
- data/spec/cases/graph_api_spec.rb +21 -4
- data/spec/cases/http_service_spec.rb +446 -0
- data/spec/cases/koala_spec.rb +50 -0
- data/spec/cases/oauth_spec.rb +220 -201
- data/spec/cases/realtime_updates_spec.rb +45 -31
- data/spec/cases/rest_api_spec.rb +23 -7
- data/spec/cases/test_users_spec.rb +112 -52
- data/spec/cases/uploadable_io_spec.rb +92 -37
- data/spec/cases/utils_spec.rb +10 -0
- data/spec/fixtures/cat.m4v +0 -0
- data/spec/fixtures/facebook_data.yml +23 -22
- data/spec/fixtures/mock_facebook_responses.yml +201 -76
- data/spec/spec_helper.rb +30 -5
- data/spec/support/graph_api_shared_examples.rb +134 -56
- data/spec/support/json_testing_fix.rb +42 -0
- data/spec/support/koala_test.rb +163 -0
- data/spec/support/mock_http_service.rb +60 -57
- data/spec/support/ordered_hash.rb +205 -0
- data/spec/support/rest_api_shared_examples.rb +139 -15
- data/spec/support/uploadable_io_shared_examples.rb +2 -8
- metadata +98 -112
- data/lib/koala/http_services.rb +0 -146
- data/spec/cases/http_services/http_service_spec.rb +0 -54
- data/spec/cases/http_services/net_http_service_spec.rb +0 -350
- data/spec/cases/http_services/typhoeus_service_spec.rb +0 -144
- data/spec/support/live_testing_data_helper.rb +0 -40
- data/spec/support/setup_mocks_or_live.rb +0 -52
|
@@ -16,7 +16,7 @@ shared_examples_for "Koala GraphAPI" do
|
|
|
16
16
|
# GRAPH CALL
|
|
17
17
|
describe "graph_call" do
|
|
18
18
|
it "should pass all arguments to the api method" do
|
|
19
|
-
args = [
|
|
19
|
+
args = [KoalaTest.user1, {}, "get", {:a => :b}]
|
|
20
20
|
|
|
21
21
|
@api.should_receive(:api).with(*args)
|
|
22
22
|
|
|
@@ -25,7 +25,7 @@ shared_examples_for "Koala GraphAPI" do
|
|
|
25
25
|
|
|
26
26
|
it "should throw an APIError if the result hash has an error key" do
|
|
27
27
|
Koala.stub(:make_request).and_return(Koala::Response.new(500, {"error" => "An error occurred!"}, {}))
|
|
28
|
-
lambda { @api.graph_call(
|
|
28
|
+
lambda { @api.graph_call(KoalaTest.user1, {}) }.should raise_exception(Koala::Facebook::APIError)
|
|
29
29
|
end
|
|
30
30
|
end
|
|
31
31
|
|
|
@@ -40,20 +40,30 @@ shared_examples_for "Koala GraphAPI" do
|
|
|
40
40
|
|
|
41
41
|
# get_object
|
|
42
42
|
it "should get public data about a user" do
|
|
43
|
-
result = @api.get_object(
|
|
43
|
+
result = @api.get_object(KoalaTest.user1)
|
|
44
44
|
# the results should have an ID and a name, among other things
|
|
45
45
|
(result["id"] && result["name"]).should_not be_nil
|
|
46
46
|
end
|
|
47
47
|
|
|
48
48
|
it "should get public data about a Page" do
|
|
49
|
-
result = @api.get_object(
|
|
49
|
+
result = @api.get_object(KoalaTest.page)
|
|
50
50
|
# the results should have an ID and a name, among other things
|
|
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
|
-
results = @api.get_objects([
|
|
56
|
-
results.
|
|
60
|
+
results = @api.get_objects([KoalaTest.page, KoalaTest.user1])
|
|
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,#{KoalaTest.user1}")
|
|
66
|
+
results.should have(2).items
|
|
57
67
|
end
|
|
58
68
|
|
|
59
69
|
it "should be able to access a user's picture" do
|
|
@@ -61,14 +71,24 @@ shared_examples_for "Koala GraphAPI" do
|
|
|
61
71
|
end
|
|
62
72
|
|
|
63
73
|
it "should be able to access a user's picture, given a picture type" do
|
|
64
|
-
@api.get_picture(
|
|
74
|
+
@api.get_picture(KoalaTest.user2, {:type => 'large'}).should =~ /^http[s]*\:\/\//
|
|
65
75
|
end
|
|
66
76
|
|
|
67
77
|
it "should be able to access connections from public Pages" do
|
|
68
|
-
result = @api.get_connections(
|
|
78
|
+
result = @api.get_connections(KoalaTest.page, "photos")
|
|
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,9 +106,8 @@ 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
|
-
result = @api.get_object(
|
|
110
|
+
result = @api.get_object(KoalaTest.user1)
|
|
92
111
|
# updated_time should be a pretty fixed test case
|
|
93
112
|
result["updated_time"].should_not be_nil
|
|
94
113
|
end
|
|
@@ -99,11 +118,11 @@ shared_examples_for "Koala GraphAPI with an access token" do
|
|
|
99
118
|
end
|
|
100
119
|
|
|
101
120
|
it "should be able to get multiple objects" do
|
|
102
|
-
result = @api.get_objects([
|
|
121
|
+
result = @api.get_objects([KoalaTest.page, KoalaTest.user1])
|
|
103
122
|
result.length.should == 2
|
|
104
123
|
end
|
|
105
124
|
it "should be able to access connections from users" do
|
|
106
|
-
result = @api.get_connections(
|
|
125
|
+
result = @api.get_connections(KoalaTest.user2, "friends")
|
|
107
126
|
result.length.should > 0
|
|
108
127
|
end
|
|
109
128
|
|
|
@@ -147,36 +166,91 @@ 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
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
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"))
|
|
173
|
+
|
|
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 "should be able to post photos to the user's wall without an open file object" do
|
|
180
|
+
content_type = "image/jpg",
|
|
181
|
+
file_path = File.join(File.dirname(__FILE__), "..", "fixtures", "beach.jpg")
|
|
182
|
+
|
|
183
|
+
result = @api.put_picture(file_path, content_type)
|
|
184
|
+
@temporary_object_id = result["id"]
|
|
185
|
+
@temporary_object_id.should_not be_nil
|
|
186
|
+
end
|
|
187
|
+
|
|
188
|
+
it "should be able to verify a photo posted to a user's wall" do
|
|
189
|
+
content_type = "image/jpg",
|
|
190
|
+
file_path = File.join(File.dirname(__FILE__), "..", "fixtures", "beach.jpg")
|
|
191
|
+
|
|
192
|
+
expected_message = "This is the test message"
|
|
193
|
+
|
|
194
|
+
result = @api.put_picture(file_path, content_type, :message => expected_message)
|
|
195
|
+
@temporary_object_id = result["id"]
|
|
196
|
+
@temporary_object_id.should_not be_nil
|
|
197
|
+
|
|
198
|
+
get_result = @api.get_object(@temporary_object_id)
|
|
199
|
+
get_result["name"].should == expected_message
|
|
200
|
+
end
|
|
201
|
+
|
|
202
|
+
|
|
203
|
+
describe "using a URL instead of a file" do
|
|
204
|
+
before :each do
|
|
205
|
+
@url = "http://img.slate.com/images/redesign2008/slate_logo.gif"
|
|
206
|
+
end
|
|
207
|
+
|
|
208
|
+
it "should be able to post photo to the user's wall using a URL" do
|
|
209
|
+
result = @api.put_picture(@url)
|
|
210
|
+
@temporary_object_id = result["id"]
|
|
211
|
+
@temporary_object_id.should_not be_nil
|
|
212
|
+
end
|
|
213
|
+
|
|
214
|
+
it "should be able to post photo to the user's wall using a URL and an additional param" do
|
|
215
|
+
result = @api.put_picture(@url, :message => "my message")
|
|
216
|
+
@temporary_object_id = result["id"]
|
|
217
|
+
@temporary_object_id.should_not be_nil
|
|
218
|
+
end
|
|
219
|
+
end
|
|
166
220
|
end
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
221
|
+
|
|
222
|
+
describe ".put_video" do
|
|
223
|
+
before :each do
|
|
224
|
+
@cat_movie = File.join(File.dirname(__FILE__), "..", "fixtures", "cat.m4v")
|
|
225
|
+
@content_type = "video/mpeg4"
|
|
226
|
+
end
|
|
227
|
+
|
|
228
|
+
it "should set options[:video] to true" do
|
|
229
|
+
source = stub("UploadIO")
|
|
230
|
+
Koala::UploadableIO.stub(:new).and_return(source)
|
|
231
|
+
source.stub(:requires_base_http_service).and_return(false)
|
|
232
|
+
Koala.should_receive(:make_request).with(anything, anything, anything, hash_including(:video => true)).and_return(Koala::Response.new(200, "[]", {}))
|
|
233
|
+
@api.put_video("foo")
|
|
234
|
+
end
|
|
235
|
+
|
|
236
|
+
it "should be able to post videos to the user's wall with an open file object" do
|
|
237
|
+
file = File.open(@cat_movie)
|
|
238
|
+
|
|
239
|
+
result = @api.put_video(file, @content_type)
|
|
240
|
+
@temporary_object_id = result["id"]
|
|
241
|
+
@temporary_object_id.should_not be_nil
|
|
242
|
+
end
|
|
243
|
+
|
|
244
|
+
|
|
245
|
+
it "should be able to post videos to the user's wall without an open file object" do
|
|
246
|
+
result = @api.put_video(@cat_movie, @content_type)
|
|
247
|
+
@temporary_object_id = result["id"]
|
|
248
|
+
@temporary_object_id.should_not be_nil
|
|
249
|
+
end
|
|
250
|
+
|
|
251
|
+
# note: Facebook doesn't post videos immediately to the wall, due to processing time
|
|
252
|
+
# during which get_object(video_id) will return false
|
|
253
|
+
# hence we can't do the same verify test we do for photos
|
|
180
254
|
end
|
|
181
255
|
|
|
182
256
|
it "should be able to verify a message with an attachment posted to a feed" do
|
|
@@ -220,6 +294,12 @@ shared_examples_for "Koala GraphAPI with an access token" do
|
|
|
220
294
|
like_result.should be_true
|
|
221
295
|
end
|
|
222
296
|
|
|
297
|
+
# Page Access Token Support
|
|
298
|
+
it "gets a page's access token" do
|
|
299
|
+
# we can't test this live since test users (or random real users) can't be guaranteed to have pages to manage
|
|
300
|
+
@api.should_receive(:api).with("my_page", {:fields => "access_token"}, "get", anything)
|
|
301
|
+
@api.get_page_access_token("my_page")
|
|
302
|
+
end
|
|
223
303
|
|
|
224
304
|
# test all methods to make sure they pass data through to the API
|
|
225
305
|
# we run the tests here (rather than in the common shared example group)
|
|
@@ -240,6 +320,7 @@ shared_examples_for "Koala GraphAPI with an access token" do
|
|
|
240
320
|
:search => 3,
|
|
241
321
|
# methods that have special arguments
|
|
242
322
|
:put_picture => ["x.jpg", "image/jpg", {}, "me"],
|
|
323
|
+
:put_video => ["x.mp4", "video/mpeg4", {}, "me"],
|
|
243
324
|
:get_objects => [["x"], {}]
|
|
244
325
|
}.each_pair do |method_name, params|
|
|
245
326
|
it "should pass http options through for #{method_name}" do
|
|
@@ -277,14 +358,14 @@ shared_examples_for "Koala GraphAPI with GraphCollection" do
|
|
|
277
358
|
describe "when getting a collection" do
|
|
278
359
|
# GraphCollection methods
|
|
279
360
|
it "should get a GraphCollection when getting connections" do
|
|
280
|
-
@result = @api.get_connections(
|
|
361
|
+
@result = @api.get_connections(KoalaTest.page, "photos")
|
|
281
362
|
@result.should be_a(Koala::Facebook::GraphCollection)
|
|
282
363
|
end
|
|
283
364
|
|
|
284
365
|
it "should return nil if the get_collections call fails with nil" do
|
|
285
366
|
# this happens sometimes
|
|
286
367
|
@api.should_receive(:graph_call).and_return(nil)
|
|
287
|
-
@api.get_connections(
|
|
368
|
+
@api.get_connections(KoalaTest.page, "photos").should be_nil
|
|
288
369
|
end
|
|
289
370
|
|
|
290
371
|
it "should get a GraphCollection when searching" do
|
|
@@ -312,12 +393,12 @@ shared_examples_for "Koala GraphAPI with GraphCollection" do
|
|
|
312
393
|
# GraphCollection attributes
|
|
313
394
|
describe "the GraphCollection" do
|
|
314
395
|
before(:each) do
|
|
315
|
-
@result = @api.get_connections(
|
|
396
|
+
@result = @api.get_connections(KoalaTest.page, "photos")
|
|
316
397
|
end
|
|
317
398
|
|
|
318
399
|
it "should have a read-only paging attribute" do
|
|
319
|
-
|
|
320
|
-
|
|
400
|
+
@result.methods.map(&:to_sym).should include(:paging)
|
|
401
|
+
@result.methods.map(&:to_sym).should_not include(:paging=)
|
|
321
402
|
end
|
|
322
403
|
|
|
323
404
|
describe "when getting a whole page" do
|
|
@@ -330,18 +411,18 @@ shared_examples_for "Koala GraphAPI with GraphCollection" do
|
|
|
330
411
|
|
|
331
412
|
it "should return the previous page of results" do
|
|
332
413
|
@result.should_receive(:previous_page_params).and_return([@base, @args])
|
|
333
|
-
@api.should_receive(:graph_call).with(@base, @args).
|
|
414
|
+
@api.should_receive(:graph_call).with(@base, @args).and_yield(@second_page)
|
|
334
415
|
Koala::Facebook::GraphCollection.should_receive(:new).with(@second_page, @api).and_return(@page_of_results)
|
|
335
416
|
|
|
336
|
-
@result.previous_page
|
|
417
|
+
@result.previous_page#.should == @page_of_results
|
|
337
418
|
end
|
|
338
419
|
|
|
339
420
|
it "should return the next page of results" do
|
|
340
421
|
@result.should_receive(:next_page_params).and_return([@base, @args])
|
|
341
|
-
@api.should_receive(:graph_call).with(@base, @args).
|
|
422
|
+
@api.should_receive(:graph_call).with(@base, @args).and_yield(@second_page)
|
|
342
423
|
Koala::Facebook::GraphCollection.should_receive(:new).with(@second_page, @api).and_return(@page_of_results)
|
|
343
424
|
|
|
344
|
-
@result.next_page
|
|
425
|
+
@result.next_page#.should == @page_of_results
|
|
345
426
|
end
|
|
346
427
|
|
|
347
428
|
it "should return nil it there are no other pages" do
|
|
@@ -354,7 +435,7 @@ shared_examples_for "Koala GraphAPI with GraphCollection" do
|
|
|
354
435
|
|
|
355
436
|
describe "when parsing page paramters" do
|
|
356
437
|
before(:each) do
|
|
357
|
-
@graph_collection = Koala::Facebook::GraphCollection.new({"data" => []}, Koala::Facebook::
|
|
438
|
+
@graph_collection = Koala::Facebook::GraphCollection.new({"data" => []}, Koala::Facebook::API.new)
|
|
358
439
|
end
|
|
359
440
|
|
|
360
441
|
it "should return the base as the first array entry" do
|
|
@@ -385,12 +466,11 @@ shared_examples_for "Koala GraphAPI without an access token" do
|
|
|
385
466
|
end
|
|
386
467
|
|
|
387
468
|
it "shouldn't be able to access connections from users" do
|
|
388
|
-
lambda { @api.get_connections("lukeshepard", "
|
|
469
|
+
lambda { @api.get_connections("lukeshepard", "friends") }.should raise_error(Koala::Facebook::APIError)
|
|
389
470
|
end
|
|
390
471
|
|
|
391
472
|
it "should not be able to put an object" do
|
|
392
473
|
lambda { @result = @api.put_object("lukeshepard", "feed", :message => "Hello, world") }.should raise_error(Koala::Facebook::APIError)
|
|
393
|
-
puts "Error! Object #{@result.inspect} somehow put onto Luke Shepard's wall!" if @result
|
|
394
474
|
end
|
|
395
475
|
|
|
396
476
|
# these are not strictly necessary as the other put methods resolve to put_object, but are here for completeness
|
|
@@ -399,13 +479,11 @@ shared_examples_for "Koala GraphAPI without an access token" do
|
|
|
399
479
|
attachment = {:name => "OAuth Playground", :link => "http://oauth.twoalex.com/"}
|
|
400
480
|
@result = @api.put_wall_post("Hello, world", attachment, "contextoptional")
|
|
401
481
|
end).should raise_error(Koala::Facebook::APIError)
|
|
402
|
-
puts "Error! Object #{@result.inspect} somehow put onto Context Optional's wall!" if @result
|
|
403
482
|
end
|
|
404
483
|
|
|
405
484
|
it "should not be able to comment on an object" do
|
|
406
485
|
# random public post on the ContextOptional wall
|
|
407
486
|
lambda { @result = @api.put_comment("7204941866_119776748033392", "The hackathon was great!") }.should raise_error(Koala::Facebook::APIError)
|
|
408
|
-
puts "Error! Object #{@result.inspect} somehow commented on post 7204941866_119776748033392!" if @result
|
|
409
487
|
end
|
|
410
488
|
|
|
411
489
|
it "should not be able to like an object" do
|
|
@@ -421,4 +499,4 @@ shared_examples_for "Koala GraphAPI without an access token" do
|
|
|
421
499
|
it "should not be able to delete a like" do
|
|
422
500
|
lambda { @api.delete_like("7204941866_119776748033392") }.should raise_error(Koala::Facebook::APIError)
|
|
423
501
|
end
|
|
424
|
-
end
|
|
502
|
+
end
|
|
@@ -0,0 +1,42 @@
|
|
|
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
|
+
module MultiJson
|
|
5
|
+
self.engine = :ok_json
|
|
6
|
+
|
|
7
|
+
class << self
|
|
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 fails if we don't assign the ternary result as a local variable
|
|
11
|
+
# separately from calling encode_original)
|
|
12
|
+
encode_original(sort_object(object))
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
alias_method :encode_original, :encode
|
|
16
|
+
alias_method :encode, :encode_with_ordering
|
|
17
|
+
|
|
18
|
+
def decode_with_ordering(string)
|
|
19
|
+
sort_object(decode_original(string))
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
alias_method :decode_original, :decode
|
|
23
|
+
alias_method :decode, :decode_with_ordering
|
|
24
|
+
|
|
25
|
+
private
|
|
26
|
+
|
|
27
|
+
def sort_object(object)
|
|
28
|
+
if object.is_a?(Hash)
|
|
29
|
+
sort_hash(object)
|
|
30
|
+
elsif object.is_a?(Array)
|
|
31
|
+
object.collect {|item| item.is_a?(Hash) ? sort_hash(item) : item}
|
|
32
|
+
else
|
|
33
|
+
object
|
|
34
|
+
end
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
def sort_hash(unsorted_hash)
|
|
38
|
+
sorted_hash = KoalaTest::OrderedHash.new(sorted_hash)
|
|
39
|
+
unsorted_hash.keys.sort {|a, b| a.to_s <=> b.to_s}.inject(sorted_hash) {|hash, k| hash[k] = unsorted_hash[k]; hash}
|
|
40
|
+
end
|
|
41
|
+
end
|
|
42
|
+
end
|
|
@@ -0,0 +1,163 @@
|
|
|
1
|
+
# small helper method for live testing
|
|
2
|
+
module KoalaTest
|
|
3
|
+
|
|
4
|
+
class << self
|
|
5
|
+
attr_accessor :oauth_token, :app_id, :secret, :app_access_token, :code, :session_key
|
|
6
|
+
attr_accessor :oauth_test_data, :subscription_test_data
|
|
7
|
+
end
|
|
8
|
+
|
|
9
|
+
# Test setup
|
|
10
|
+
|
|
11
|
+
def self.setup_test_environment!
|
|
12
|
+
setup_rspec
|
|
13
|
+
|
|
14
|
+
unless ENV['LIVE']
|
|
15
|
+
# By default the Koala specs are run using stubs for HTTP requests,
|
|
16
|
+
# so they won't fail due to Facebook-imposed rate limits or server timeouts.
|
|
17
|
+
#
|
|
18
|
+
# However as a result they are more brittle since
|
|
19
|
+
# we are not testing the latest responses from the Facebook servers.
|
|
20
|
+
# To be certain all specs pass with the current Facebook services,
|
|
21
|
+
# run LIVE=true bundle exec rake spec.
|
|
22
|
+
Koala.http_service = Koala::MockHTTPService
|
|
23
|
+
KoalaTest.setup_test_data(Koala::MockHTTPService::TEST_DATA)
|
|
24
|
+
else
|
|
25
|
+
# Runs Koala specs through the Facebook servers
|
|
26
|
+
# using data for a real app
|
|
27
|
+
live_data = YAML.load_file(File.join(File.dirname(__FILE__), '../fixtures/facebook_data.yml'))
|
|
28
|
+
KoalaTest.setup_test_data(live_data)
|
|
29
|
+
|
|
30
|
+
# allow live tests with different adapters
|
|
31
|
+
adapter = ENV['ADAPTER'] || "typhoeus"# use Typhoeus by default if available
|
|
32
|
+
begin
|
|
33
|
+
require adapter
|
|
34
|
+
Faraday.default_adapter = adapter.to_sym
|
|
35
|
+
rescue LoadError
|
|
36
|
+
puts "Unable to load adapter #{adapter}, using Net::HTTP."
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
# use a test user unless the developer wants to test against a real profile
|
|
40
|
+
unless token = KoalaTest.oauth_token
|
|
41
|
+
KoalaTest.setup_test_users
|
|
42
|
+
else
|
|
43
|
+
KoalaTest.validate_user_info(token)
|
|
44
|
+
end
|
|
45
|
+
end
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
def self.setup_rspec
|
|
49
|
+
# set up a global before block to set the token for tests
|
|
50
|
+
# set the token up for
|
|
51
|
+
RSpec.configure do |config|
|
|
52
|
+
config.before :each do
|
|
53
|
+
@token = KoalaTest.oauth_token
|
|
54
|
+
Koala::Utils.stub(:deprecate) # never fire deprecation warnings
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
config.after :each do
|
|
58
|
+
# clean up any objects posted to Facebook
|
|
59
|
+
if @temporary_object_id && !KoalaTest.mock_interface?
|
|
60
|
+
api = @api || (@test_users ? @test_users.graph_api : nil)
|
|
61
|
+
raise "Unable to locate API when passed temporary object to delete!" unless api
|
|
62
|
+
|
|
63
|
+
# wait 10ms to allow Facebook to propagate data so we can delete it
|
|
64
|
+
sleep(0.01)
|
|
65
|
+
|
|
66
|
+
# clean up any objects we've posted
|
|
67
|
+
result = (api.delete_object(@temporary_object_id) rescue false)
|
|
68
|
+
# if we errored out or Facebook returned false, track that
|
|
69
|
+
puts "Unable to delete #{@temporary_object_id}: #{result} (probably a photo or video, which can't be deleted through the API)" unless result
|
|
70
|
+
end
|
|
71
|
+
end
|
|
72
|
+
end
|
|
73
|
+
end
|
|
74
|
+
|
|
75
|
+
def self.setup_test_data(data)
|
|
76
|
+
# make data accessible to all our tests
|
|
77
|
+
self.oauth_test_data = data["oauth_test_data"]
|
|
78
|
+
self.subscription_test_data = data["subscription_test_data"]
|
|
79
|
+
self.oauth_token = data["oauth_token"]
|
|
80
|
+
self.app_id = data["oauth_test_data"]["app_id"]
|
|
81
|
+
self.app_access_token = data["oauth_test_data"]["app_access_token"]
|
|
82
|
+
self.secret = data["oauth_test_data"]["secret"]
|
|
83
|
+
self.code = data["oauth_test_data"]["code"]
|
|
84
|
+
self.session_key = data["oauth_test_data"]["session_key"]
|
|
85
|
+
end
|
|
86
|
+
|
|
87
|
+
def self.testing_permissions
|
|
88
|
+
"read_stream, publish_stream, user_photos, user_videos, read_insights"
|
|
89
|
+
end
|
|
90
|
+
|
|
91
|
+
def self.setup_test_users
|
|
92
|
+
# note: we don't have to delete the two test users explicitly, since the test user specs do that for us
|
|
93
|
+
# technically, this is a point of brittleness and would break if the tests were run out of order
|
|
94
|
+
# however, for now we can live with it since it would slow tests way too much to constantly recreate our test users
|
|
95
|
+
print "Setting up test users..."
|
|
96
|
+
@test_user_api = Koala::Facebook::TestUsers.new(:app_id => self.app_id, :secret => self.secret)
|
|
97
|
+
|
|
98
|
+
# create two test users with specific names and befriend them
|
|
99
|
+
@live_testing_user = @test_user_api.create(true, testing_permissions, :name => user1_name)
|
|
100
|
+
@live_testing_friend = @test_user_api.create(true, testing_permissions, :name => user2_name)
|
|
101
|
+
@test_user_api.befriend(@live_testing_user, @live_testing_friend)
|
|
102
|
+
self.oauth_token = @live_testing_user["access_token"]
|
|
103
|
+
|
|
104
|
+
puts "done."
|
|
105
|
+
end
|
|
106
|
+
|
|
107
|
+
def self.validate_user_info(token)
|
|
108
|
+
print "Validating permissions for live testing..."
|
|
109
|
+
# make sure we have the necessary permissions
|
|
110
|
+
api = Koala::Facebook::API.new(token)
|
|
111
|
+
perms = api.fql_query("select #{testing_permissions} from permissions where uid = me()")[0]
|
|
112
|
+
perms.each_pair do |perm, value|
|
|
113
|
+
if value == (perm == "read_insights" ? 1 : 0) # live testing depends on insights calls failing
|
|
114
|
+
puts "failed!\n" # put a new line after the print above
|
|
115
|
+
raise ArgumentError, "Your access token must have the read_stream, publish_stream, and user_photos permissions, and lack read_insights. You have: #{perms.inspect}"
|
|
116
|
+
end
|
|
117
|
+
end
|
|
118
|
+
puts "done!"
|
|
119
|
+
end
|
|
120
|
+
|
|
121
|
+
# Info about the testing environment
|
|
122
|
+
def self.real_user?
|
|
123
|
+
!(mock_interface? || @test_user)
|
|
124
|
+
end
|
|
125
|
+
|
|
126
|
+
def self.test_user?
|
|
127
|
+
!!@test_user_api
|
|
128
|
+
end
|
|
129
|
+
|
|
130
|
+
def self.mock_interface?
|
|
131
|
+
Koala.http_service == Koala::MockHTTPService
|
|
132
|
+
end
|
|
133
|
+
|
|
134
|
+
# Data for testing
|
|
135
|
+
def self.user1
|
|
136
|
+
test_user? ? @live_testing_user["id"] : "koppel"
|
|
137
|
+
end
|
|
138
|
+
|
|
139
|
+
def self.user1_id
|
|
140
|
+
test_user? ? @live_testing_user["id"] : 2905623
|
|
141
|
+
end
|
|
142
|
+
|
|
143
|
+
def self.user1_name
|
|
144
|
+
"Alex"
|
|
145
|
+
end
|
|
146
|
+
|
|
147
|
+
def self.user2
|
|
148
|
+
test_user? ? @live_testing_friend["id"] : "lukeshepard"
|
|
149
|
+
end
|
|
150
|
+
|
|
151
|
+
def self.user2_id
|
|
152
|
+
test_user? ? @live_testing_friend["id"] : 2901279
|
|
153
|
+
end
|
|
154
|
+
|
|
155
|
+
def self.user2_name
|
|
156
|
+
"Luke"
|
|
157
|
+
end
|
|
158
|
+
|
|
159
|
+
def self.page
|
|
160
|
+
"contextoptional"
|
|
161
|
+
end
|
|
162
|
+
|
|
163
|
+
end
|