koala 1.1.0 → 1.2.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.
Files changed (52) hide show
  1. data/.travis.yml +2 -1
  2. data/CHANGELOG +36 -0
  3. data/Gemfile +6 -2
  4. data/Rakefile +0 -1
  5. data/koala.gemspec +7 -8
  6. data/lib/koala/batch_operation.rb +15 -15
  7. data/lib/koala/graph_api.rb +85 -73
  8. data/lib/koala/graph_batch_api.rb +21 -11
  9. data/lib/koala/graph_collection.rb +13 -8
  10. data/lib/koala/http_service.rb +176 -0
  11. data/lib/koala/oauth.rb +34 -24
  12. data/lib/koala/realtime_updates.rb +21 -18
  13. data/lib/koala/rest_api.rb +1 -1
  14. data/lib/koala/test_users.rb +33 -17
  15. data/lib/koala/uploadable_io.rb +49 -43
  16. data/lib/koala/utils.rb +11 -0
  17. data/lib/koala/version.rb +3 -0
  18. data/lib/koala.rb +47 -45
  19. data/readme.md +58 -38
  20. data/spec/cases/{api_base_spec.rb → api_spec.rb} +27 -2
  21. data/spec/cases/error_spec.rb +32 -0
  22. data/spec/cases/graph_and_rest_api_spec.rb +12 -21
  23. data/spec/cases/graph_api_batch_spec.rb +92 -119
  24. data/spec/cases/graph_api_spec.rb +11 -14
  25. data/spec/cases/graph_collection_spec.rb +116 -0
  26. data/spec/cases/http_service_spec.rb +446 -0
  27. data/spec/cases/koala_spec.rb +36 -37
  28. data/spec/cases/oauth_spec.rb +318 -212
  29. data/spec/cases/realtime_updates_spec.rb +45 -31
  30. data/spec/cases/rest_api_spec.rb +23 -7
  31. data/spec/cases/test_users_spec.rb +123 -75
  32. data/spec/cases/uploadable_io_spec.rb +77 -36
  33. data/spec/cases/utils_spec.rb +10 -0
  34. data/spec/fixtures/facebook_data.yml +26 -24
  35. data/spec/fixtures/mock_facebook_responses.yml +131 -101
  36. data/spec/spec_helper.rb +29 -5
  37. data/spec/support/graph_api_shared_examples.rb +80 -120
  38. data/spec/support/json_testing_fix.rb +35 -11
  39. data/spec/support/koala_test.rb +187 -0
  40. data/spec/support/mock_http_service.rb +8 -5
  41. data/spec/support/ordered_hash.rb +205 -0
  42. data/spec/support/rest_api_shared_examples.rb +37 -37
  43. data/spec/support/uploadable_io_shared_examples.rb +2 -8
  44. metadata +72 -83
  45. data/lib/koala/http_services/net_http_service.rb +0 -92
  46. data/lib/koala/http_services/typhoeus_service.rb +0 -37
  47. data/lib/koala/http_services.rb +0 -46
  48. data/spec/cases/http_services/http_service_spec.rb +0 -129
  49. data/spec/cases/http_services/net_http_service_spec.rb +0 -532
  50. data/spec/cases/http_services/typhoeus_service_spec.rb +0 -152
  51. data/spec/support/live_testing_data_helper.rb +0 -40
  52. data/spec/support/setup_mocks_or_live.rb +0 -51
@@ -16,17 +16,36 @@ 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}]
20
-
19
+ args = [KoalaTest.user1, {}, "get", {:a => :b}]
21
20
  @api.should_receive(:api).with(*args)
22
-
23
21
  @api.graph_call(*args)
24
22
  end
25
23
 
26
24
  it "should throw an APIError if the result hash has an error key" do
27
25
  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)
26
+ lambda { @api.graph_call(KoalaTest.user1, {}) }.should raise_exception(Koala::Facebook::APIError)
27
+ end
28
+
29
+ it "passes the results through GraphCollection.evaluate" do
30
+ result = {}
31
+ @api.stub(:api).and_return(result)
32
+ Koala::Facebook::GraphCollection.should_receive(:evaluate).with(result, @api)
33
+ @api.graph_call("/me")
29
34
  end
35
+
36
+ it "returns the results of GraphCollection.evaluate" do
37
+ expected = {}
38
+ @api.stub(:api).and_return([])
39
+ Koala::Facebook::GraphCollection.should_receive(:evaluate).and_return(expected)
40
+ @api.graph_call("/me").should == expected
41
+ end
42
+
43
+ it "returns the post_processing block's results if one is supplied" do
44
+ other_result = [:a, 2, :three]
45
+ block = Proc.new {|r| other_result}
46
+ @api.stub(:api).and_return({})
47
+ @api.graph_call("/me", {}, "get", {}, &block).should == other_result
48
+ end
30
49
  end
31
50
 
32
51
  # SEARCH
@@ -40,13 +59,13 @@ shared_examples_for "Koala GraphAPI" do
40
59
 
41
60
  # get_object
42
61
  it "should get public data about a user" do
43
- result = @api.get_object("koppel")
62
+ result = @api.get_object(KoalaTest.user1)
44
63
  # the results should have an ID and a name, among other things
45
64
  (result["id"] && result["name"]).should_not be_nil
46
65
  end
47
66
 
48
67
  it "should get public data about a Page" do
49
- result = @api.get_object("contextoptional")
68
+ result = @api.get_object(KoalaTest.page)
50
69
  # the results should have an ID and a name, among other things
51
70
  (result["id"] && result["name"]).should
52
71
  end
@@ -55,14 +74,14 @@ shared_examples_for "Koala GraphAPI" do
55
74
  results = @api.get_objects([])
56
75
  results.should == []
57
76
  end
58
-
77
+
59
78
  it "should be able to get multiple objects" do
60
- results = @api.get_objects(["contextoptional", "naitik"])
79
+ results = @api.get_objects([KoalaTest.page, KoalaTest.user1])
61
80
  results.should have(2).items
62
81
  end
63
82
 
64
83
  it "should be able to get multiple objects if they're a string" do
65
- results = @api.get_objects("contextoptional,naitik")
84
+ results = @api.get_objects("contextoptional,#{KoalaTest.user1}")
66
85
  results.should have(2).items
67
86
  end
68
87
 
@@ -71,11 +90,11 @@ shared_examples_for "Koala GraphAPI" do
71
90
  end
72
91
 
73
92
  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]*\:\/\//
93
+ @api.get_picture(KoalaTest.user2, {:type => 'large'}).should =~ /^http[s]*\:\/\//
75
94
  end
76
95
 
77
96
  it "should be able to access connections from public Pages" do
78
- result = @api.get_connections("contextoptional", "photos")
97
+ result = @api.get_connections(KoalaTest.page, "photos")
79
98
  result.should be_a(Array)
80
99
  end
81
100
 
@@ -107,7 +126,7 @@ end
107
126
 
108
127
  shared_examples_for "Koala GraphAPI with an access token" do
109
128
  it "should get private data about a user" do
110
- result = @api.get_object("koppel")
129
+ result = @api.get_object(KoalaTest.user1)
111
130
  # updated_time should be a pretty fixed test case
112
131
  result["updated_time"].should_not be_nil
113
132
  end
@@ -118,11 +137,11 @@ shared_examples_for "Koala GraphAPI with an access token" do
118
137
  end
119
138
 
120
139
  it "should be able to get multiple objects" do
121
- result = @api.get_objects(["contextoptional", "naitik"])
140
+ result = @api.get_objects([KoalaTest.page, KoalaTest.user1])
122
141
  result.length.should == 2
123
142
  end
124
143
  it "should be able to access connections from users" do
125
- result = @api.get_connections("lukeshepard", "likes")
144
+ result = @api.get_connections(KoalaTest.user2, "friends")
126
145
  result.length.should > 0
127
146
  end
128
147
 
@@ -168,52 +187,63 @@ shared_examples_for "Koala GraphAPI with an access token" do
168
187
 
169
188
  describe ".put_picture" do
170
189
  it "should be able to post photos to the user's wall with an open file object" do
171
- content_type = "image/jpg"
190
+ content_type = "image/jpg"
172
191
  file = File.open(File.join(File.dirname(__FILE__), "..", "fixtures", "beach.jpg"))
173
-
192
+
174
193
  result = @api.put_picture(file, content_type)
175
- @temporary_object_id = result["id"]
194
+ @temporary_object_id = result["id"]
176
195
  @temporary_object_id.should_not be_nil
177
196
  end
178
197
 
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
198
  it "should be able to post photos to the user's wall without an open file object" do
188
199
  content_type = "image/jpg",
189
200
  file_path = File.join(File.dirname(__FILE__), "..", "fixtures", "beach.jpg")
190
-
201
+
191
202
  result = @api.put_picture(file_path, content_type)
192
- @temporary_object_id = result["id"]
203
+ @temporary_object_id = result["id"]
193
204
  @temporary_object_id.should_not be_nil
194
205
  end
195
-
206
+
196
207
  it "should be able to verify a photo posted to a user's wall" do
197
208
  content_type = "image/jpg",
198
209
  file_path = File.join(File.dirname(__FILE__), "..", "fixtures", "beach.jpg")
199
-
210
+
200
211
  expected_message = "This is the test message"
201
-
212
+
202
213
  result = @api.put_picture(file_path, content_type, :message => expected_message)
203
- @temporary_object_id = result["id"]
214
+ @temporary_object_id = result["id"]
204
215
  @temporary_object_id.should_not be_nil
205
-
216
+
206
217
  get_result = @api.get_object(@temporary_object_id)
207
218
  get_result["name"].should == expected_message
208
219
  end
220
+
221
+
222
+ describe "using a URL instead of a file" do
223
+ before :each do
224
+ @url = "http://img.slate.com/images/redesign2008/slate_logo.gif"
225
+ end
226
+
227
+ it "should be able to post photo to the user's wall using a URL" do
228
+ result = @api.put_picture(@url)
229
+ @temporary_object_id = result["id"]
230
+ @temporary_object_id.should_not be_nil
231
+ end
232
+
233
+ it "should be able to post photo to the user's wall using a URL and an additional param" do
234
+ result = @api.put_picture(@url, :message => "my message")
235
+ @temporary_object_id = result["id"]
236
+ @temporary_object_id.should_not be_nil
237
+ end
238
+ end
209
239
  end
210
-
240
+
211
241
  describe ".put_video" do
212
242
  before :each do
213
- @cat_movie = File.join(File.dirname(__FILE__), "..", "fixtures", "cat.m4v")
214
- @content_type = "video/mpeg4"
243
+ @cat_movie = File.join(File.dirname(__FILE__), "..", "fixtures", "cat.m4v")
244
+ @content_type = "video/mpeg4"
215
245
  end
216
-
246
+
217
247
  it "should set options[:video] to true" do
218
248
  source = stub("UploadIO")
219
249
  Koala::UploadableIO.stub(:new).and_return(source)
@@ -221,26 +251,19 @@ shared_examples_for "Koala GraphAPI with an access token" do
221
251
  Koala.should_receive(:make_request).with(anything, anything, anything, hash_including(:video => true)).and_return(Koala::Response.new(200, "[]", {}))
222
252
  @api.put_video("foo")
223
253
  end
224
-
254
+
225
255
  it "should be able to post videos to the user's wall with an open file object" do
226
256
  file = File.open(@cat_movie)
227
257
 
228
258
  result = @api.put_video(file, @content_type)
229
- @temporary_object_id = result["id"]
259
+ @temporary_object_id = result["id"]
230
260
  @temporary_object_id.should_not be_nil
231
261
  end
232
262
 
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
263
 
241
264
  it "should be able to post videos to the user's wall without an open file object" do
242
265
  result = @api.put_video(@cat_movie, @content_type)
243
- @temporary_object_id = result["id"]
266
+ @temporary_object_id = result["id"]
244
267
  @temporary_object_id.should_not be_nil
245
268
  end
246
269
 
@@ -290,6 +313,12 @@ shared_examples_for "Koala GraphAPI with an access token" do
290
313
  like_result.should be_true
291
314
  end
292
315
 
316
+ # Page Access Token Support
317
+ it "gets a page's access token" do
318
+ # we can't test this live since test users (or random real users) can't be guaranteed to have pages to manage
319
+ @api.should_receive(:api).with("my_page", {:fields => "access_token"}, "get", anything)
320
+ @api.get_page_access_token("my_page")
321
+ end
293
322
 
294
323
  # test all methods to make sure they pass data through to the API
295
324
  # we run the tests here (rather than in the common shared example group)
@@ -339,23 +368,17 @@ end
339
368
 
340
369
  # GraphCollection
341
370
  shared_examples_for "Koala GraphAPI with GraphCollection" do
342
-
343
- it "should create an array-like object" do
344
- call = @api.graph_call("contextoptional/photos")
345
- Koala::Facebook::GraphCollection.new(call, @api).should be_an(Array)
346
- end
347
-
348
371
  describe "when getting a collection" do
349
372
  # GraphCollection methods
350
373
  it "should get a GraphCollection when getting connections" do
351
- @result = @api.get_connections("contextoptional", "photos")
374
+ @result = @api.get_connections(KoalaTest.page, "photos")
352
375
  @result.should be_a(Koala::Facebook::GraphCollection)
353
376
  end
354
377
 
355
378
  it "should return nil if the get_collections call fails with nil" do
356
379
  # this happens sometimes
357
380
  @api.should_receive(:graph_call).and_return(nil)
358
- @api.get_connections("contextoptional", "photos").should be_nil
381
+ @api.get_connections(KoalaTest.page, "photos").should be_nil
359
382
  end
360
383
 
361
384
  it "should get a GraphCollection when searching" do
@@ -370,74 +393,14 @@ shared_examples_for "Koala GraphAPI with GraphCollection" do
370
393
  end
371
394
 
372
395
  it "should get a GraphCollection when paging through results" do
373
- @results = @api.get_page(["search", {"q"=>"facebook", "limit"=>"25", "until"=>"2010-09-23T21:17:33+0000"}])
396
+ @results = @api.get_page(["search", {"q"=>"facebook", "limit"=>"25", "until"=> KoalaTest.search_time}])
374
397
  @results.should be_a(Koala::Facebook::GraphCollection)
375
398
  end
376
399
 
377
400
  it "should return nil if the page call fails with nil" do
378
401
  # this happens sometimes
379
402
  @api.should_receive(:graph_call).and_return(nil)
380
- @api.get_page(["search", {"q"=>"facebook", "limit"=>"25", "until"=>"2010-09-23T21:17:33+0000"}]).should be_nil
381
- end
382
-
383
- # GraphCollection attributes
384
- describe "the GraphCollection" do
385
- before(:each) do
386
- @result = @api.get_connections("contextoptional", "photos")
387
- end
388
-
389
- it "should have a read-only paging attribute" do
390
- @result.methods.map(&:to_sym).should include(:paging)
391
- @result.methods.map(&:to_sym).should_not include(:paging=)
392
- end
393
-
394
- describe "when getting a whole page" do
395
- before(:each) do
396
- @second_page = stub("page of Fb graph results")
397
- @base = stub("base")
398
- @args = stub("args")
399
- @page_of_results = stub("page of results")
400
- end
401
-
402
- it "should return the previous page of results" do
403
- @result.should_receive(:previous_page_params).and_return([@base, @args])
404
- @api.should_receive(:graph_call).with(@base, @args).and_yield(@second_page)
405
- Koala::Facebook::GraphCollection.should_receive(:new).with(@second_page, @api).and_return(@page_of_results)
406
-
407
- @result.previous_page#.should == @page_of_results
408
- end
409
-
410
- it "should return the next page of results" do
411
- @result.should_receive(:next_page_params).and_return([@base, @args])
412
- @api.should_receive(:graph_call).with(@base, @args).and_yield(@second_page)
413
- Koala::Facebook::GraphCollection.should_receive(:new).with(@second_page, @api).and_return(@page_of_results)
414
-
415
- @result.next_page#.should == @page_of_results
416
- end
417
-
418
- it "should return nil it there are no other pages" do
419
- %w{next previous}.each do |this|
420
- @result.should_receive("#{this}_page_params".to_sym).and_return(nil)
421
- @result.send("#{this}_page").should == nil
422
- end
423
- end
424
- end
425
-
426
- describe "when parsing page paramters" do
427
- before(:each) do
428
- @graph_collection = Koala::Facebook::GraphCollection.new({"data" => []}, Koala::Facebook::GraphAPI.new)
429
- end
430
-
431
- it "should return the base as the first array entry" do
432
- base = "url_path"
433
- @graph_collection.parse_page_url("anything.com/#{base}?anything").first.should == base
434
- end
435
-
436
- it "should return the arguments as a hash as the last array entry" do
437
- args_hash = {"one" => "val_one", "two" => "val_two"}
438
- @graph_collection.parse_page_url("anything.com/anything?#{args_hash.map {|k,v| "#{k}=#{v}" }.join("&")}").last.should == args_hash
439
- end
440
- end
403
+ @api.get_page(["search", {"q"=>"facebook", "limit"=>"25", "until"=> KoalaTest.search_time}]).should be_nil
441
404
  end
442
405
  end
443
406
  end
@@ -456,12 +419,11 @@ shared_examples_for "Koala GraphAPI without an access token" do
456
419
  end
457
420
 
458
421
  it "shouldn't be able to access connections from users" do
459
- lambda { @api.get_connections("lukeshepard", "likes") }.should raise_error(Koala::Facebook::APIError)
422
+ lambda { @api.get_connections("lukeshepard", "friends") }.should raise_error(Koala::Facebook::APIError)
460
423
  end
461
424
 
462
425
  it "should not be able to put an object" do
463
426
  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
427
  end
466
428
 
467
429
  # these are not strictly necessary as the other put methods resolve to put_object, but are here for completeness
@@ -470,13 +432,11 @@ shared_examples_for "Koala GraphAPI without an access token" do
470
432
  attachment = {:name => "OAuth Playground", :link => "http://oauth.twoalex.com/"}
471
433
  @result = @api.put_wall_post("Hello, world", attachment, "contextoptional")
472
434
  end).should raise_error(Koala::Facebook::APIError)
473
- puts "Error! Object #{@result.inspect} somehow put onto Context Optional's wall!" if @result
474
435
  end
475
436
 
476
437
  it "should not be able to comment on an object" do
477
438
  # random public post on the ContextOptional wall
478
439
  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
440
  end
481
441
 
482
442
  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,187 @@
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, :search_time
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
+ Koala.http_service.http_options[:beta] = true if ENV["beta"] || ENV["BETA"]
40
+
41
+ # use a test user unless the developer wants to test against a real profile
42
+ unless token = KoalaTest.oauth_token
43
+ KoalaTest.setup_test_users
44
+ else
45
+ KoalaTest.validate_user_info(token)
46
+ end
47
+ end
48
+ end
49
+
50
+ def self.setup_rspec
51
+ # set up a global before block to set the token for tests
52
+ # set the token up for
53
+ RSpec.configure do |config|
54
+ config.before :each do
55
+ @token = KoalaTest.oauth_token
56
+ Koala::Utils.stub(:deprecate) # never fire deprecation warnings
57
+ end
58
+
59
+ config.after :each do
60
+ # clean up any objects posted to Facebook
61
+ if @temporary_object_id && !KoalaTest.mock_interface?
62
+ api = @api || (@test_users ? @test_users.graph_api : nil)
63
+ raise "Unable to locate API when passed temporary object to delete!" unless api
64
+
65
+ # wait 10ms to allow Facebook to propagate data so we can delete it
66
+ sleep(0.01)
67
+
68
+ # clean up any objects we've posted
69
+ result = (api.delete_object(@temporary_object_id) rescue false)
70
+ # if we errored out or Facebook returned false, track that
71
+ puts "Unable to delete #{@temporary_object_id}: #{result} (probably a photo or video, which can't be deleted through the API)" unless result
72
+ end
73
+ end
74
+ end
75
+ end
76
+
77
+ def self.setup_test_data(data)
78
+ # make data accessible to all our tests
79
+ self.oauth_test_data = data["oauth_test_data"]
80
+ self.subscription_test_data = data["subscription_test_data"]
81
+ self.oauth_token = data["oauth_token"]
82
+ self.app_id = data["oauth_test_data"]["app_id"]
83
+ self.app_access_token = data["oauth_test_data"]["app_access_token"]
84
+ self.secret = data["oauth_test_data"]["secret"]
85
+ self.code = data["oauth_test_data"]["code"]
86
+ self.session_key = data["oauth_test_data"]["session_key"]
87
+
88
+ # fix the search time so it can be used in the mock responses
89
+ self.search_time = data["search_time"] || (Time.now - 3600).to_s
90
+ end
91
+
92
+ def self.testing_permissions
93
+ "read_stream, publish_stream, user_photos, user_videos, read_insights"
94
+ end
95
+
96
+ def self.setup_test_users
97
+ # note: we don't have to delete the two test users explicitly, since the test user specs do that for us
98
+ # technically, this is a point of brittleness and would break if the tests were run out of order
99
+ # however, for now we can live with it since it would slow tests way too much to constantly recreate our test users
100
+ print "Setting up test users..."
101
+ @test_user_api = Koala::Facebook::TestUsers.new(:app_id => self.app_id, :secret => self.secret)
102
+
103
+ RSpec.configure do |config|
104
+ config.before :all do
105
+ # before each test module, create two test users with specific names and befriend them
106
+ KoalaTest.create_test_users
107
+ end
108
+
109
+ config.after :all do
110
+ # after each test module, delete the test users to avoid cluttering up the application
111
+ KoalaTest.destroy_test_users
112
+ end
113
+ end
114
+
115
+ puts "done."
116
+ end
117
+
118
+ def self.create_test_users
119
+ @live_testing_user = @test_user_api.create(true, KoalaTest.testing_permissions, :name => KoalaTest.user1_name)
120
+ @live_testing_friend = @test_user_api.create(true, KoalaTest.testing_permissions, :name => KoalaTest.user2_name)
121
+ @test_user_api.befriend(@live_testing_user, @live_testing_friend)
122
+ self.oauth_token = @live_testing_user["access_token"]
123
+ end
124
+
125
+ def self.destroy_test_users
126
+ [@live_testing_user, @live_testing_friend].each do |u|
127
+ puts "Unable to delete test user #{u.inspect}" if u && !(@test_user_api.delete(u) rescue false)
128
+ end
129
+ end
130
+
131
+ def self.validate_user_info(token)
132
+ print "Validating permissions for live testing..."
133
+ # make sure we have the necessary permissions
134
+ api = Koala::Facebook::API.new(token)
135
+ perms = api.fql_query("select #{testing_permissions} from permissions where uid = me()")[0]
136
+ perms.each_pair do |perm, value|
137
+ if value == (perm == "read_insights" ? 1 : 0) # live testing depends on insights calls failing
138
+ puts "failed!\n" # put a new line after the print above
139
+ raise ArgumentError, "Your access token must have the read_stream, publish_stream, and user_photos permissions, and lack read_insights. You have: #{perms.inspect}"
140
+ end
141
+ end
142
+ puts "done!"
143
+ end
144
+
145
+ # Info about the testing environment
146
+ def self.real_user?
147
+ !(mock_interface? || @test_user)
148
+ end
149
+
150
+ def self.test_user?
151
+ !!@test_user_api
152
+ end
153
+
154
+ def self.mock_interface?
155
+ Koala.http_service == Koala::MockHTTPService
156
+ end
157
+
158
+ # Data for testing
159
+ def self.user1
160
+ test_user? ? @live_testing_user["id"] : "koppel"
161
+ end
162
+
163
+ def self.user1_id
164
+ test_user? ? @live_testing_user["id"] : 2905623
165
+ end
166
+
167
+ def self.user1_name
168
+ "Alex"
169
+ end
170
+
171
+ def self.user2
172
+ test_user? ? @live_testing_friend["id"] : "lukeshepard"
173
+ end
174
+
175
+ def self.user2_id
176
+ test_user? ? @live_testing_friend["id"] : 2901279
177
+ end
178
+
179
+ def self.user2_name
180
+ "Luke"
181
+ end
182
+
183
+ def self.page
184
+ "contextoptional"
185
+ end
186
+
187
+ end
@@ -18,7 +18,8 @@ module Koala
18
18
  TEST_DATA = YAML.load_file(File.join(File.dirname(__FILE__), '..', 'fixtures', 'facebook_data.yml'))
19
19
  TEST_DATA.merge!('oauth_token' => Koala::MockHTTPService::ACCESS_TOKEN)
20
20
  TEST_DATA['oauth_test_data'].merge!('code' => Koala::MockHTTPService::OAUTH_CODE)
21
-
21
+ TEST_DATA['search_time'] = (Time.now - 3600).to_s
22
+
22
23
  # Useful in mock_facebook_responses.yml
23
24
  OAUTH_DATA = TEST_DATA['oauth_test_data']
24
25
  OAUTH_DATA.merge!({
@@ -38,7 +39,7 @@ module Koala
38
39
  path = 'root' if path == '' || path == '/'
39
40
  verb ||= 'get'
40
41
  server = options[:rest_api] ? 'rest_api' : 'graph_api'
41
- token = args.delete('access_token')
42
+ token = args.delete('access_token')
42
43
  with_token = (token == ACCESS_TOKEN || token == APP_ACCESS_TOKEN) ? 'with_token' : 'no_token'
43
44
 
44
45
  # Assume format is always JSON
@@ -77,11 +78,13 @@ module Koala
77
78
  response_object
78
79
  end
79
80
 
80
- def self.mock?
81
- true
81
+ def self.encode_params(*args)
82
+ # use HTTPService's encode_params
83
+ HTTPService.encode_params(*args)
82
84
  end
83
85
 
84
86
  protected
87
+
85
88
  def self.create_params_key(params_hash)
86
89
  if params_hash.empty?
87
90
  'no_args'
@@ -93,4 +96,4 @@ module Koala
93
96
  end
94
97
  end
95
98
  end
96
- end
99
+ end