koala 1.1.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 (50) hide show
  1. data/.travis.yml +2 -1
  2. data/CHANGELOG +26 -0
  3. data/Gemfile +6 -2
  4. data/Rakefile +0 -1
  5. data/koala.gemspec +8 -8
  6. data/lib/koala.rb +42 -45
  7. data/lib/koala/batch_operation.rb +15 -15
  8. data/lib/koala/graph_api.rb +81 -58
  9. data/lib/koala/graph_batch_api.rb +10 -10
  10. data/lib/koala/graph_collection.rb +6 -6
  11. data/lib/koala/http_service.rb +177 -0
  12. data/lib/koala/oauth.rb +2 -2
  13. data/lib/koala/realtime_updates.rb +20 -17
  14. data/lib/koala/rest_api.rb +1 -1
  15. data/lib/koala/test_users.rb +33 -16
  16. data/lib/koala/uploadable_io.rb +47 -42
  17. data/lib/koala/utils.rb +11 -0
  18. data/readme.md +38 -38
  19. data/spec/cases/api_base_spec.rb +2 -2
  20. data/spec/cases/error_spec.rb +32 -0
  21. data/spec/cases/graph_and_rest_api_spec.rb +20 -3
  22. data/spec/cases/graph_api_batch_spec.rb +88 -97
  23. data/spec/cases/graph_api_spec.rb +21 -4
  24. data/spec/cases/http_service_spec.rb +446 -0
  25. data/spec/cases/koala_spec.rb +33 -38
  26. data/spec/cases/oauth_spec.rb +219 -200
  27. data/spec/cases/realtime_updates_spec.rb +45 -31
  28. data/spec/cases/rest_api_spec.rb +23 -7
  29. data/spec/cases/test_users_spec.rb +112 -52
  30. data/spec/cases/uploadable_io_spec.rb +49 -36
  31. data/spec/cases/utils_spec.rb +10 -0
  32. data/spec/fixtures/facebook_data.yml +23 -22
  33. data/spec/fixtures/mock_facebook_responses.yml +126 -96
  34. data/spec/spec_helper.rb +29 -5
  35. data/spec/support/graph_api_shared_examples.rb +59 -52
  36. data/spec/support/json_testing_fix.rb +35 -11
  37. data/spec/support/koala_test.rb +163 -0
  38. data/spec/support/mock_http_service.rb +6 -4
  39. data/spec/support/ordered_hash.rb +205 -0
  40. data/spec/support/rest_api_shared_examples.rb +37 -37
  41. data/spec/support/uploadable_io_shared_examples.rb +2 -8
  42. metadata +78 -79
  43. data/lib/koala/http_services.rb +0 -46
  44. data/lib/koala/http_services/net_http_service.rb +0 -92
  45. data/lib/koala/http_services/typhoeus_service.rb +0 -37
  46. data/spec/cases/http_services/http_service_spec.rb +0 -129
  47. data/spec/cases/http_services/net_http_service_spec.rb +0 -532
  48. data/spec/cases/http_services/typhoeus_service_spec.rb +0 -152
  49. data/spec/support/live_testing_data_helper.rb +0 -40
  50. data/spec/support/setup_mocks_or_live.rb +0 -51
data/spec/spec_helper.rb CHANGED
@@ -4,16 +4,40 @@ rescue LoadError
4
4
  puts 'Although not required, bundler is recommended for running the tests.'
5
5
  end
6
6
 
7
- # load the libraries
7
+ # In Ruby 1.9.2 versions before patchlevel 290, the default Psych
8
+ # parser has an issue with YAML merge keys, which
9
+ # fixtures/mock_facebook_responses.yml relies heavily on.
10
+ #
11
+ # Anyone using an earlier version will see missing mock response
12
+ # errors when running the test suite similar to this:
13
+ #
14
+ # RuntimeError:
15
+ # Missing a mock response for graph_api: /me/videos: source=[FILE]: post: with_token
16
+ # API PATH: /me/videos?source=[FILE]&format=json&access_token=*
17
+ #
18
+ # For now, it seems the best fix is to just downgrade to the old syck YAML parser
19
+ # for these troubled versions.
20
+ #
21
+ # See https://github.com/tenderlove/psych/issues/8 for more details
22
+ YAML::ENGINE.yamler = 'syck' if RUBY_VERSION == '1.9.2' && RUBY_PATCHLEVEL < 290
23
+
24
+ # load the library
8
25
  require 'koala'
9
26
 
10
- # load testing data libraries
11
- require 'support/live_testing_data_helper'
12
- require 'support/json_testing_fix' # ensure consistent to_json behavior
27
+ # ensure consistent to_json behavior
28
+ # this must be required first so mock_http_service loads the YAML as expected
29
+ require 'support/ordered_hash'
30
+ require 'support/json_testing_fix'
31
+
32
+ # set up our testing environment
13
33
  require 'support/mock_http_service'
34
+ require 'support/koala_test'
35
+ # load testing data and (if needed) create test users or validate real users
36
+ KoalaTest.setup_test_environment!
37
+
38
+ # load supporting files for our tests
14
39
  require 'support/rest_api_shared_examples'
15
40
  require 'support/graph_api_shared_examples'
16
41
  require 'support/uploadable_io_shared_examples'
17
- require 'support/setup_mocks_or_live'
18
42
 
19
43
  BEACH_BALL_PATH = File.join(File.dirname(__FILE__), "fixtures", "beach.jpg")
@@ -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,13 +40,13 @@ 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
@@ -55,14 +55,14 @@ shared_examples_for "Koala GraphAPI" do
55
55
  results = @api.get_objects([])
56
56
  results.should == []
57
57
  end
58
-
58
+
59
59
  it "should be able to get multiple objects" do
60
- results = @api.get_objects(["contextoptional", "naitik"])
60
+ results = @api.get_objects([KoalaTest.page, KoalaTest.user1])
61
61
  results.should have(2).items
62
62
  end
63
63
 
64
64
  it "should be able to get multiple objects if they're a string" do
65
- results = @api.get_objects("contextoptional,naitik")
65
+ results = @api.get_objects("contextoptional,#{KoalaTest.user1}")
66
66
  results.should have(2).items
67
67
  end
68
68
 
@@ -71,11 +71,11 @@ shared_examples_for "Koala GraphAPI" do
71
71
  end
72
72
 
73
73
  it "should be able to access a user's picture, given a picture type" do
74
- @api.get_picture("lukeshepard", {:type => 'large'}).should =~ /^http[s]*\:\/\//
74
+ @api.get_picture(KoalaTest.user2, {:type => 'large'}).should =~ /^http[s]*\:\/\//
75
75
  end
76
76
 
77
77
  it "should be able to access connections from public Pages" do
78
- result = @api.get_connections("contextoptional", "photos")
78
+ result = @api.get_connections(KoalaTest.page, "photos")
79
79
  result.should be_a(Array)
80
80
  end
81
81
 
@@ -107,7 +107,7 @@ end
107
107
 
108
108
  shared_examples_for "Koala GraphAPI with an access token" do
109
109
  it "should get private data about a user" do
110
- result = @api.get_object("koppel")
110
+ result = @api.get_object(KoalaTest.user1)
111
111
  # updated_time should be a pretty fixed test case
112
112
  result["updated_time"].should_not be_nil
113
113
  end
@@ -118,11 +118,11 @@ shared_examples_for "Koala GraphAPI with an access token" do
118
118
  end
119
119
 
120
120
  it "should be able to get multiple objects" do
121
- result = @api.get_objects(["contextoptional", "naitik"])
121
+ result = @api.get_objects([KoalaTest.page, KoalaTest.user1])
122
122
  result.length.should == 2
123
123
  end
124
124
  it "should be able to access connections from users" do
125
- result = @api.get_connections("lukeshepard", "likes")
125
+ result = @api.get_connections(KoalaTest.user2, "friends")
126
126
  result.length.should > 0
127
127
  end
128
128
 
@@ -168,52 +168,63 @@ shared_examples_for "Koala GraphAPI with an access token" do
168
168
 
169
169
  describe ".put_picture" do
170
170
  it "should be able to post photos to the user's wall with an open file object" do
171
- content_type = "image/jpg"
171
+ content_type = "image/jpg"
172
172
  file = File.open(File.join(File.dirname(__FILE__), "..", "fixtures", "beach.jpg"))
173
-
173
+
174
174
  result = @api.put_picture(file, content_type)
175
- @temporary_object_id = result["id"]
175
+ @temporary_object_id = result["id"]
176
176
  @temporary_object_id.should_not be_nil
177
177
  end
178
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
179
  it "should be able to post photos to the user's wall without an open file object" do
188
180
  content_type = "image/jpg",
189
181
  file_path = File.join(File.dirname(__FILE__), "..", "fixtures", "beach.jpg")
190
-
182
+
191
183
  result = @api.put_picture(file_path, content_type)
192
- @temporary_object_id = result["id"]
184
+ @temporary_object_id = result["id"]
193
185
  @temporary_object_id.should_not be_nil
194
186
  end
195
-
187
+
196
188
  it "should be able to verify a photo posted to a user's wall" do
197
189
  content_type = "image/jpg",
198
190
  file_path = File.join(File.dirname(__FILE__), "..", "fixtures", "beach.jpg")
199
-
191
+
200
192
  expected_message = "This is the test message"
201
-
193
+
202
194
  result = @api.put_picture(file_path, content_type, :message => expected_message)
203
- @temporary_object_id = result["id"]
195
+ @temporary_object_id = result["id"]
204
196
  @temporary_object_id.should_not be_nil
205
-
197
+
206
198
  get_result = @api.get_object(@temporary_object_id)
207
199
  get_result["name"].should == expected_message
208
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
209
220
  end
210
-
221
+
211
222
  describe ".put_video" do
212
223
  before :each do
213
- @cat_movie = File.join(File.dirname(__FILE__), "..", "fixtures", "cat.m4v")
214
- @content_type = "video/mpeg4"
224
+ @cat_movie = File.join(File.dirname(__FILE__), "..", "fixtures", "cat.m4v")
225
+ @content_type = "video/mpeg4"
215
226
  end
216
-
227
+
217
228
  it "should set options[:video] to true" do
218
229
  source = stub("UploadIO")
219
230
  Koala::UploadableIO.stub(:new).and_return(source)
@@ -221,26 +232,19 @@ shared_examples_for "Koala GraphAPI with an access token" do
221
232
  Koala.should_receive(:make_request).with(anything, anything, anything, hash_including(:video => true)).and_return(Koala::Response.new(200, "[]", {}))
222
233
  @api.put_video("foo")
223
234
  end
224
-
235
+
225
236
  it "should be able to post videos to the user's wall with an open file object" do
226
237
  file = File.open(@cat_movie)
227
238
 
228
239
  result = @api.put_video(file, @content_type)
229
- @temporary_object_id = result["id"]
240
+ @temporary_object_id = result["id"]
230
241
  @temporary_object_id.should_not be_nil
231
242
  end
232
243
 
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
244
 
241
245
  it "should be able to post videos to the user's wall without an open file object" do
242
246
  result = @api.put_video(@cat_movie, @content_type)
243
- @temporary_object_id = result["id"]
247
+ @temporary_object_id = result["id"]
244
248
  @temporary_object_id.should_not be_nil
245
249
  end
246
250
 
@@ -290,6 +294,12 @@ shared_examples_for "Koala GraphAPI with an access token" do
290
294
  like_result.should be_true
291
295
  end
292
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
293
303
 
294
304
  # test all methods to make sure they pass data through to the API
295
305
  # we run the tests here (rather than in the common shared example group)
@@ -348,14 +358,14 @@ shared_examples_for "Koala GraphAPI with GraphCollection" do
348
358
  describe "when getting a collection" do
349
359
  # GraphCollection methods
350
360
  it "should get a GraphCollection when getting connections" do
351
- @result = @api.get_connections("contextoptional", "photos")
361
+ @result = @api.get_connections(KoalaTest.page, "photos")
352
362
  @result.should be_a(Koala::Facebook::GraphCollection)
353
363
  end
354
364
 
355
365
  it "should return nil if the get_collections call fails with nil" do
356
366
  # this happens sometimes
357
367
  @api.should_receive(:graph_call).and_return(nil)
358
- @api.get_connections("contextoptional", "photos").should be_nil
368
+ @api.get_connections(KoalaTest.page, "photos").should be_nil
359
369
  end
360
370
 
361
371
  it "should get a GraphCollection when searching" do
@@ -383,7 +393,7 @@ shared_examples_for "Koala GraphAPI with GraphCollection" do
383
393
  # GraphCollection attributes
384
394
  describe "the GraphCollection" do
385
395
  before(:each) do
386
- @result = @api.get_connections("contextoptional", "photos")
396
+ @result = @api.get_connections(KoalaTest.page, "photos")
387
397
  end
388
398
 
389
399
  it "should have a read-only paging attribute" do
@@ -425,7 +435,7 @@ shared_examples_for "Koala GraphAPI with GraphCollection" do
425
435
 
426
436
  describe "when parsing page paramters" do
427
437
  before(:each) do
428
- @graph_collection = Koala::Facebook::GraphCollection.new({"data" => []}, Koala::Facebook::GraphAPI.new)
438
+ @graph_collection = Koala::Facebook::GraphCollection.new({"data" => []}, Koala::Facebook::API.new)
429
439
  end
430
440
 
431
441
  it "should return the base as the first array entry" do
@@ -456,12 +466,11 @@ shared_examples_for "Koala GraphAPI without an access token" do
456
466
  end
457
467
 
458
468
  it "shouldn't be able to access connections from users" do
459
- 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)
460
470
  end
461
471
 
462
472
  it "should not be able to put an object" do
463
473
  lambda { @result = @api.put_object("lukeshepard", "feed", :message => "Hello, world") }.should raise_error(Koala::Facebook::APIError)
464
- puts "Error! Object #{@result.inspect} somehow put onto Luke Shepard's wall!" if @result
465
474
  end
466
475
 
467
476
  # these are not strictly necessary as the other put methods resolve to put_object, but are here for completeness
@@ -470,13 +479,11 @@ shared_examples_for "Koala GraphAPI without an access token" do
470
479
  attachment = {:name => "OAuth Playground", :link => "http://oauth.twoalex.com/"}
471
480
  @result = @api.put_wall_post("Hello, world", attachment, "contextoptional")
472
481
  end).should raise_error(Koala::Facebook::APIError)
473
- puts "Error! Object #{@result.inspect} somehow put onto Context Optional's wall!" if @result
474
482
  end
475
483
 
476
484
  it "should not be able to comment on an object" do
477
485
  # random public post on the ContextOptional wall
478
486
  lambda { @result = @api.put_comment("7204941866_119776748033392", "The hackathon was great!") }.should raise_error(Koala::Facebook::APIError)
479
- puts "Error! Object #{@result.inspect} somehow commented on post 7204941866_119776748033392!" if @result
480
487
  end
481
488
 
482
489
  it "should not be able to like an object" do
@@ -1,18 +1,42 @@
1
1
  # when testing across Ruby versions, we found that JSON string creation inconsistently ordered keys
2
2
  # which is a problem because our mock testing service ultimately matches strings to see if requests are mocked
3
3
  # this fix solves that problem by ensuring all hashes are created with a consistent key order every time
4
-
5
4
  module MultiJson
6
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
7
17
 
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
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
15
36
 
16
- alias_method :encode_original, :encode
17
- alias_method :encode, :encode_with_ordering
18
- end
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