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.
Files changed (52) hide show
  1. data/.autotest +12 -0
  2. data/.gitignore +3 -1
  3. data/.travis.yml +9 -0
  4. data/CHANGELOG +52 -2
  5. data/Gemfile +8 -0
  6. data/Rakefile +0 -1
  7. data/autotest/discover.rb +1 -0
  8. data/koala.gemspec +14 -14
  9. data/lib/koala/batch_operation.rb +74 -0
  10. data/lib/koala/graph_api.rb +157 -133
  11. data/lib/koala/graph_batch_api.rb +87 -0
  12. data/lib/koala/graph_collection.rb +54 -0
  13. data/lib/koala/http_service.rb +177 -0
  14. data/lib/koala/oauth.rb +181 -0
  15. data/lib/koala/realtime_updates.rb +23 -29
  16. data/lib/koala/rest_api.rb +13 -8
  17. data/lib/koala/test_users.rb +33 -16
  18. data/lib/koala/uploadable_io.rb +152 -87
  19. data/lib/koala/utils.rb +11 -0
  20. data/lib/koala.rb +54 -217
  21. data/readme.md +71 -52
  22. data/spec/cases/api_base_spec.rb +6 -6
  23. data/spec/cases/error_spec.rb +32 -0
  24. data/spec/cases/graph_and_rest_api_spec.rb +20 -3
  25. data/spec/cases/graph_api_batch_spec.rb +600 -0
  26. data/spec/cases/graph_api_spec.rb +21 -4
  27. data/spec/cases/http_service_spec.rb +446 -0
  28. data/spec/cases/koala_spec.rb +50 -0
  29. data/spec/cases/oauth_spec.rb +220 -201
  30. data/spec/cases/realtime_updates_spec.rb +45 -31
  31. data/spec/cases/rest_api_spec.rb +23 -7
  32. data/spec/cases/test_users_spec.rb +112 -52
  33. data/spec/cases/uploadable_io_spec.rb +92 -37
  34. data/spec/cases/utils_spec.rb +10 -0
  35. data/spec/fixtures/cat.m4v +0 -0
  36. data/spec/fixtures/facebook_data.yml +23 -22
  37. data/spec/fixtures/mock_facebook_responses.yml +201 -76
  38. data/spec/spec_helper.rb +30 -5
  39. data/spec/support/graph_api_shared_examples.rb +134 -56
  40. data/spec/support/json_testing_fix.rb +42 -0
  41. data/spec/support/koala_test.rb +163 -0
  42. data/spec/support/mock_http_service.rb +60 -57
  43. data/spec/support/ordered_hash.rb +205 -0
  44. data/spec/support/rest_api_shared_examples.rb +139 -15
  45. data/spec/support/uploadable_io_shared_examples.rb +2 -8
  46. metadata +98 -112
  47. data/lib/koala/http_services.rb +0 -146
  48. data/spec/cases/http_services/http_service_spec.rb +0 -54
  49. data/spec/cases/http_services/net_http_service_spec.rb +0 -350
  50. data/spec/cases/http_services/typhoeus_service_spec.rb +0 -144
  51. data/spec/support/live_testing_data_helper.rb +0 -40
  52. 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 = ["koppel", {}, "get", {:a => :b}]
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("koppel", {}) }.should raise_exception(Koala::Facebook::APIError)
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("koppel")
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("contextoptional")
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(["contextoptional", "naitik"])
56
- results.length.should == 2
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("lukeshepard", {:type => 'large'}).should =~ /^http[s]*\:\/\//
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("contextoptional", "photos")
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("koppel")
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(["contextoptional", "naitik"])
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("lukeshepard", "likes")
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
- it "should be able to post photos to the user's wall with an open file object" do
151
- content_type = "image/jpg"
152
- file = File.open(File.join(File.dirname(__FILE__), "..", "fixtures", "beach.jpg"))
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
158
-
159
- it "should be able to post photos to the user's wall without an open file object" do
160
- content_type = "image/jpg",
161
- file_path = File.join(File.dirname(__FILE__), "..", "fixtures", "beach.jpg")
162
-
163
- result = @api.put_picture(file_path, content_type)
164
- @temporary_object_id = result["id"]
165
- @temporary_object_id.should_not be_nil
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
- it "should be able to verify a photo posted to a user's wall" do
169
- content_type = "image/jpg",
170
- file_path = File.join(File.dirname(__FILE__), "..", "fixtures", "beach.jpg")
171
-
172
- expected_message = "This is the test message"
173
-
174
- result = @api.put_picture(file_path, content_type, :message => expected_message)
175
- @temporary_object_id = result["id"]
176
- @temporary_object_id.should_not be_nil
177
-
178
- get_result = @api.get_object(@temporary_object_id)
179
- get_result["name"].should == expected_message
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("contextoptional", "photos")
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("contextoptional", "photos").should be_nil
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("contextoptional", "photos")
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
- lambda { @result.paging }.should_not raise_error
320
- lambda { @result.paging = "paging" }.should raise_error(NoMethodError)
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).and_return(@second_page)
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.should == @page_of_results
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).and_return(@second_page)
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.should == @page_of_results
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::GraphAPI.new)
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", "likes") }.should raise_error(Koala::Facebook::APIError)
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