koala 1.5.0 → 1.6.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.
@@ -1,40 +1,76 @@
1
1
  require 'spec_helper'
2
2
 
3
3
  describe Koala::Facebook::APIError do
4
- it "is a StandardError" do
5
- Koala::Facebook::APIError.new.should be_a(StandardError)
4
+ it "is a Koala::KoalaError" do
5
+ Koala::Facebook::APIError.new(nil, nil).should be_a(Koala::KoalaError)
6
6
  end
7
7
 
8
- [:fb_error_type, :fb_error_code, :fb_error_message, :raw_response].each do |accessor|
8
+ [:fb_error_type, :fb_error_code, :fb_error_subcode, :fb_error_message, :http_status, :response_body].each do |accessor|
9
9
  it "has an accessor for #{accessor}" do
10
10
  Koala::Facebook::APIError.instance_methods.map(&:to_sym).should include(accessor)
11
11
  Koala::Facebook::APIError.instance_methods.map(&:to_sym).should include(:"#{accessor}=")
12
12
  end
13
13
  end
14
14
 
15
- it "sets raw_response to the provided error details" do
16
- error_response = {"type" => "foo", "other_details" => "bar"}
17
- Koala::Facebook::APIError.new(error_response).raw_response.should == error_response
15
+ it "sets http_status to the provided status" do
16
+ error_response = '{ "error": {"type": "foo", "other_details": "bar"} }'
17
+ Koala::Facebook::APIError.new(400, error_response).response_body.should == error_response
18
+ end
19
+
20
+ it "sets response_body to the provided response body" do
21
+ Koala::Facebook::APIError.new(400, '').http_status.should == 400
22
+ end
23
+
24
+ context "with an error_info hash" do
25
+ let(:error) {
26
+ error_info = {
27
+ 'type' => 'type',
28
+ 'message' => 'message',
29
+ 'code' => 1,
30
+ 'error_subcode' => 'subcode'
31
+ }
32
+ Koala::Facebook::APIError.new(400, '', error_info)
33
+ }
34
+
35
+ {
36
+ :fb_error_type => 'type',
37
+ :fb_error_message => 'message',
38
+ :fb_error_code => 1,
39
+ :fb_error_subcode => 'subcode'
40
+ }.each_pair do |accessor, value|
41
+ it "sets #{accessor} to #{value}" do
42
+ error.send(accessor).should == value
43
+ end
44
+ end
45
+
46
+ it "sets the error message \"type: error_info['type'], code: error_info['code'], error_subcode: error_info['error_subcode'], message: error_info['message'] [HTTP http_status]\"" do
47
+ error.message.should == "type: type, code: 1, error_subcode: subcode, message: message [HTTP 400]"
48
+ end
18
49
  end
19
50
 
20
- {
21
- :fb_error_type => 'type',
22
- :fb_error_message => 'message',
23
- :fb_error_code => 'code'
24
- }.each_pair do |accessor, key|
25
- it "sets #{accessor} to details['#{key}']" do
26
- value = "foo"
27
- Koala::Facebook::APIError.new(key => value).send(accessor).should == value
51
+ context "with an error_info string" do
52
+ it "sets the error message \"error_info [HTTP http_status]\"" do
53
+ error_info = "Facebook is down."
54
+ error = Koala::Facebook::APIError.new(400, '', error_info)
55
+ error.message.should == "Facebook is down. [HTTP 400]"
28
56
  end
29
57
  end
30
58
 
31
- it "sets the error message details['type']: details['message']" do
32
- type = "foo"
33
- message = "bar"
34
- error = Koala::Facebook::APIError.new("type" => type, "message" => message)
35
- error.message.should =~ /#{type}/
36
- error.message.should =~ /#{message}/
59
+ context "with no error_info and a response_body containing error JSON" do
60
+ it "should extract the error info from the response body" do
61
+ response_body = '{ "error": { "type": "type", "message": "message", "code": 1, "error_subcode": "subcode" } }'
62
+ error = Koala::Facebook::APIError.new(400, response_body)
63
+ {
64
+ :fb_error_type => 'type',
65
+ :fb_error_message => 'message',
66
+ :fb_error_code => 1,
67
+ :fb_error_subcode => 'subcode'
68
+ }.each_pair do |accessor, value|
69
+ error.send(accessor).should == value
70
+ end
71
+ end
37
72
  end
73
+
38
74
  end
39
75
 
40
76
  describe Koala::KoalaError do
@@ -43,3 +79,38 @@ describe Koala::KoalaError do
43
79
  end
44
80
  end
45
81
 
82
+ describe Koala::Facebook::OAuthSignatureError do
83
+ it "is a Koala::KoalaError" do
84
+ Koala::KoalaError.new.should be_a(Koala::KoalaError)
85
+ end
86
+ end
87
+
88
+ describe Koala::Facebook::BadFacebookResponse do
89
+ it "is a Koala::Facebook::APIError" do
90
+ Koala::Facebook::BadFacebookResponse.new(nil, nil).should be_a(Koala::Facebook::APIError)
91
+ end
92
+ end
93
+
94
+ describe Koala::Facebook::OAuthTokenRequestError do
95
+ it "is a Koala::Facebook::APIError" do
96
+ Koala::Facebook::OAuthTokenRequestError.new(nil, nil).should be_a(Koala::Facebook::APIError)
97
+ end
98
+ end
99
+
100
+ describe Koala::Facebook::ServerError do
101
+ it "is a Koala::Facebook::APIError" do
102
+ Koala::Facebook::ServerError.new(nil, nil).should be_a(Koala::Facebook::APIError)
103
+ end
104
+ end
105
+
106
+ describe Koala::Facebook::ClientError do
107
+ it "is a Koala::Facebook::APIError" do
108
+ Koala::Facebook::ClientError.new(nil, nil).should be_a(Koala::Facebook::APIError)
109
+ end
110
+ end
111
+
112
+ describe Koala::Facebook::AuthenticationError do
113
+ it "is a Koala::Facebook::ClientError" do
114
+ Koala::Facebook::AuthenticationError.new(nil, nil).should be_a(Koala::Facebook::ClientError)
115
+ end
116
+ end
@@ -381,58 +381,56 @@ describe "Koala::Facebook::GraphAPI in batch mode" do
381
381
  }.to raise_exception(Koala::Facebook::APIError)
382
382
  end
383
383
 
384
- it "raises an APIError if the body is empty" do
384
+ it "raises a BadFacebookResponse if the body is empty" do
385
385
  Koala.stub(:make_request).and_return(Koala::HTTPService::Response.new(200, "", {}))
386
386
  expect {
387
387
  Koala::Facebook::API.new("foo").batch {|batch_api| batch_api.get_object('me') }
388
- }.to raise_exception(Koala::Facebook::APIError)
388
+ }.to raise_exception(Koala::Facebook::BadFacebookResponse)
389
389
  end
390
390
 
391
391
  context "with the old style" do
392
392
  before :each do
393
- Koala.stub(:make_request).and_return(Koala::HTTPService::Response.new(200, '{"error":190,"error_description":"Error validating access token."}', {}))
393
+ Koala.stub(:make_request).and_return(Koala::HTTPService::Response.new(400, '{"error_code":190,"error_description":"Error validating access token."}', {}))
394
394
  end
395
395
 
396
- it "throws an error if the response is an old Batch API-style error" do
396
+ it "throws an error" do
397
397
  expect {
398
398
  Koala::Facebook::API.new("foo").batch {|batch_api| batch_api.get_object('me') }
399
399
  }.to raise_exception(Koala::Facebook::APIError)
400
400
  end
401
401
 
402
- it "provides a type for the error if the response is an old Batch API-style error" do
402
+ it "passes all the error details" do
403
403
  begin
404
404
  Koala::Facebook::API.new("foo").batch {|batch_api| batch_api.get_object('me') }
405
405
  rescue Koala::Facebook::APIError => err
406
+ err.fb_error_code.should == 190
407
+ err.fb_error_message.should == "Error validating access token."
408
+ err.http_status == 400
409
+ err.response_body == '{"error_code":190,"error_description":"Error validating access token."}'
406
410
  end
407
- err.fb_error_type.should
408
- end
409
-
410
- it "passes all the error details if an old Batch API-style error is raised" do
411
- begin
412
- Koala::Facebook::API.new("foo").batch {|batch_api| batch_api.get_object('me') }
413
- rescue Koala::Facebook::APIError => err
414
- end
415
- err.raw_response["error"].should == 190
416
411
  end
417
412
  end
418
413
 
419
414
  context "with the new style" do
420
415
  before :each do
421
- Koala.stub(:make_request).and_return(Koala::HTTPService::Response.new(200, '{"error":{"message":"Request 0 cannot depend on an unresolved request with name f. Requests can only depend on preceding requests","type":"GraphBatchException"}}', {}))
416
+ Koala.stub(:make_request).and_return(Koala::HTTPService::Response.new(400, '{"error":{"message":"Request 0 cannot depend on an unresolved request with name f. Requests can only depend on preceding requests","type":"GraphBatchException"}}', {}))
422
417
  end
423
418
 
424
- it "throws an error if the response is a new Graph API-style error" do
419
+ it "throws an error" do
425
420
  expect {
426
421
  Koala::Facebook::API.new("foo").batch {|batch_api| batch_api.get_object('me') }
427
422
  }.to raise_exception(Koala::Facebook::APIError)
428
423
  end
429
424
 
430
- it "passes all the error details if an old Batch API-style error is raised" do
425
+ it "passes all the error details" do
431
426
  begin
432
427
  Koala::Facebook::API.new("foo").batch {|batch_api| batch_api.get_object('me') }
433
428
  rescue Koala::Facebook::APIError => err
429
+ err.fb_error_type.should == "GraphBatchException"
430
+ err.fb_error_message.should == "Request 0 cannot depend on an unresolved request with name f. Requests can only depend on preceding requests"
431
+ err.http_status == 400
432
+ err.response_body == '{"error":{"message":"Request 0 cannot depend on an unresolved request with name f. Requests can only depend on preceding requests","type":"GraphBatchException"}}'
434
433
  end
435
- err.raw_response["message"].should
436
434
  end
437
435
  end
438
436
  end
@@ -509,7 +507,8 @@ describe "Koala::Facebook::GraphAPI in batch mode" do
509
507
  pictures = @api.batch do |batch_api|
510
508
  batch_api.get_picture('me')
511
509
  end
512
- pictures.first.should_not be_empty
510
+ puts pictures.inspect
511
+ pictures.first.should =~ /http\:\/\// # works both live & stubbed
513
512
  end
514
513
 
515
514
  it "handles requests for two different tokens" do
@@ -526,7 +525,7 @@ describe "Koala::Facebook::GraphAPI in batch mode" do
526
525
  batch_api.get_connection("2", "invalidconnection")
527
526
  batch_api.get_object(KoalaTest.user1, {}, {"access_token" => @app_api.access_token})
528
527
  end
529
- failed_call.should be_a(Koala::Facebook::APIError)
528
+ failed_call.should be_a(Koala::Facebook::ClientError)
530
529
  koppel["id"].should_not be_nil
531
530
  end
532
531
 
@@ -550,6 +549,42 @@ describe "Koala::Facebook::GraphAPI in batch mode" do
550
549
  fql_result[0]["first_name"].should == "Alex"
551
550
  end
552
551
 
552
+ describe 'with post-processing callback' do
553
+ let(:me_result) { stub("me result") }
554
+ let(:friends_result) { stub("friends result") }
555
+
556
+ let(:me_callback) { lambda {|data| me_result } }
557
+ let(:friends_callback) { lambda {|data| friends_result } }
558
+
559
+ it 'calls the callback with the appropriate data' do
560
+ me_callback.should_receive(:call).with(hash_including(
561
+ 'id' => KoalaTest.user1
562
+ ))
563
+ friends_callback.should_receive(:call).with([
564
+ hash_including('id' => KoalaTest.user2)
565
+ ])
566
+ @api.batch do |batch_api|
567
+ batch_api.get_object('me', &me_callback)
568
+ batch_api.get_connections('me', 'friends', &friends_callback)
569
+ end
570
+ end
571
+
572
+ it 'passes GraphCollections, not raw data' do
573
+ friends_callback.should_receive(:call).with(kind_of(Koala::Facebook::API::GraphCollection))
574
+ @api.batch do |batch_api|
575
+ batch_api.get_object('me')
576
+ batch_api.get_connections('me', 'friends', &friends_callback)
577
+ end
578
+ end
579
+
580
+ it "returns the result of the callback" do
581
+ @api.batch do |batch_api|
582
+ batch_api.get_object('me', &me_callback)
583
+ batch_api.get_connections('me', 'friends', &friends_callback)
584
+ end.should == [me_result, friends_result]
585
+ end
586
+ end
587
+
553
588
  describe "binary files" do
554
589
  it "posts binary files" do
555
590
  file = File.open(File.join(File.dirname(__FILE__), "..", "fixtures", "beach.jpg"))
@@ -614,7 +649,7 @@ describe "Koala::Facebook::GraphAPI in batch mode" do
614
649
  batch_api.get_object(KoalaTest.user1, {}, :batch_args => {:depends_on => "getdata"})
615
650
  end
616
651
 
617
- failed_call.should be_a(Koala::Facebook::APIError)
652
+ failed_call.should be_a(Koala::Facebook::ClientError)
618
653
  koppel.should be_nil
619
654
  end
620
655
 
@@ -624,7 +659,7 @@ describe "Koala::Facebook::GraphAPI in batch mode" do
624
659
  batch_api.get_connections("me", "friends", {:limit => 5})
625
660
  batch_api.get_objects("{result=i-dont-exist:$.data.*.id}")
626
661
  end
627
- }.to raise_exception(Koala::Facebook::APIError)
662
+ }.to raise_exception(Koala::Facebook::ClientError)
628
663
  end
629
664
  end
630
665
  end
@@ -0,0 +1,68 @@
1
+ require 'spec_helper'
2
+
3
+ describe 'Koala::Facebook::GraphAPIMethods' do
4
+ before do
5
+ @api = Koala::Facebook::API.new(@token)
6
+ # app API
7
+ @app_id = KoalaTest.app_id
8
+ @app_access_token = KoalaTest.app_access_token
9
+ @app_api = Koala::Facebook::API.new(@app_access_token)
10
+ end
11
+
12
+ describe 'post-processing for' do
13
+ let(:post_processing) { lambda {} }
14
+
15
+ # Most API methods have the same signature, we test get_object representatively
16
+ # and the other methods which do some post-processing locally
17
+ context '#get_object' do
18
+ it 'returns result of block' do
19
+ result = {"id" => 1, "name" => 1, "updated_time" => 1}
20
+ @api.stub(:api).and_return(result)
21
+ post_processing.should_receive(:call).
22
+ with(result).and_return('new result')
23
+ @api.get_object('koppel', &post_processing).should == 'new result'
24
+ end
25
+ end
26
+
27
+ context '#get_picture' do
28
+ it 'returns result of block' do
29
+ result = "http://facebook.com/"
30
+ @api.stub(:api).and_return("Location" => result)
31
+ post_processing.should_receive(:call).
32
+ with(result).and_return('new result')
33
+ @api.get_picture('lukeshepard', &post_processing).should == 'new result'
34
+ end
35
+ end
36
+
37
+ context '#fql_multiquery' do
38
+ before do
39
+ @api.should_receive(:get_object).and_return([
40
+ {"name" => "query1", "fql_result_set" => [{"id" => 123}]},
41
+ {"name" => "query2", "fql_result_set" => ["id" => 456]}
42
+ ])
43
+ end
44
+
45
+ it 'is called with resolved response' do
46
+ resolved_result = {
47
+ 'query1' => [{'id' => 123}],
48
+ 'query2' => [{'id'=>456}]
49
+ }
50
+ post_processing.should_receive(:call).
51
+ with(resolved_result).and_return('id'=>'123', 'id'=>'456')
52
+ @api.fql_multiquery({}, &post_processing).should ==
53
+ {'id'=>'123', 'id'=>'456'}
54
+ end
55
+ end
56
+
57
+ context '#get_page_access_token' do
58
+ it 'returns result of block' do
59
+ token = Koala::MockHTTPService::APP_ACCESS_TOKEN
60
+ @api.stub(:api).and_return("access_token" => token)
61
+ post_processing.should_receive(:call).
62
+ with(token).and_return('base64-encoded access token')
63
+ @api.get_page_access_token('facebook', &post_processing).should ==
64
+ 'base64-encoded access token'
65
+ end
66
+ end
67
+ end
68
+ end
@@ -104,6 +104,12 @@ describe Koala::Facebook::GraphCollection do
104
104
  args_hash = {"one" => "val_one", "two" => "val_two"}
105
105
  Koala::Facebook::GraphCollection.parse_page_url("http://facebook.com/#{base}?#{args_hash.map {|k,v| "#{k}=#{v}" }.join("&")}").should == [base, args_hash]
106
106
  end
107
+
108
+ it "works with addresses with irregular characters" do
109
+ access_token = "appid123a|fdcba"
110
+ base, args_hash = Koala::Facebook::GraphCollection.parse_page_url("http://facebook.com/foo?token=#{access_token}")
111
+ args_hash["token"].should == access_token
112
+ end
107
113
  end
108
114
  end
109
115
 
@@ -1,7 +1,7 @@
1
1
  require 'spec_helper'
2
2
 
3
3
  describe "Koala::Facebook::OAuth" do
4
- before :each do
4
+ before :all do
5
5
  # make the relevant test data easily accessible
6
6
  @app_id = KoalaTest.app_id
7
7
  @secret = KoalaTest.secret
@@ -24,7 +24,9 @@ describe "Koala::Facebook::OAuth" do
24
24
  @multiple_session_keys = [KoalaTest.session_key, KoalaTest.session_key] if KoalaTest.session_key
25
25
 
26
26
  @oauth = Koala::Facebook::OAuth.new(@app_id, @secret, @callback_url)
27
+ end
27
28
 
29
+ before :each do
28
30
  @time = Time.now
29
31
  Time.stub!(:now).and_return(@time)
30
32
  @time.stub!(:to_i).and_return(1273363199)
@@ -117,19 +119,16 @@ describe "Koala::Facebook::OAuth" do
117
119
  end
118
120
 
119
121
  it "returns nil if the call to FB returns an expired code error" do
120
- @oauth.stub(:get_access_token_info).and_raise(Koala::Facebook::APIError.new(
121
- "type" => "OAuthException",
122
- "message" => "Code was invalid or expired. Session has expired at unix time 1324044000. The current unix time is 1324300957."
122
+ @oauth.stub(:get_access_token_info).and_raise(Koala::Facebook::OAuthTokenRequestError.new(400,
123
+ '{ "error": { "type": "OAuthException", "message": "Code was invalid or expired. Session has expired at unix time 1324044000. The current unix time is 1324300957." } }'
123
124
  ))
124
125
  @oauth.get_user_info_from_cookies(@cookie).should be_nil
125
126
  end
126
127
 
127
128
  it "raises the error if the call to FB returns a different error" do
128
- @oauth.stub(:get_access_token_info).and_raise(Koala::Facebook::APIError.new(
129
- "type" => "OtherError",
130
- "message" => "A Facebook Error"
131
- ))
132
- expect { @oauth.get_user_info_from_cookies(@cookie) }.to raise_exception(Koala::Facebook::APIError)
129
+ @oauth.stub(:get_access_token_info).and_raise(Koala::Facebook::OAuthTokenRequestError.new(400,
130
+ '{ "error": { "type": "OtherError", "message": "A Facebook Error" } }'))
131
+ expect { @oauth.get_user_info_from_cookies(@cookie) }.to raise_exception(Koala::Facebook::OAuthTokenRequestError)
133
132
  end
134
133
  end
135
134
 
@@ -149,6 +148,7 @@ describe "Koala::Facebook::OAuth" do
149
148
 
150
149
  it "returns all the cookie components from valid cookie string" do
151
150
  cookie_data = KoalaTest.oauth_test_data["valid_cookies"]
151
+ puts cookie_data.inspect
152
152
  parsing_results = @oauth.get_user_info_from_cookies(cookie_data)
153
153
  number_of_components = cookie_data["fbs_#{@app_id.to_s}"].scan(/\=/).length
154
154
  parsing_results.length.should == number_of_components
@@ -295,13 +295,13 @@ describe "Koala::Facebook::OAuth" do
295
295
 
296
296
  it "generates a properly formatted OAuth token URL when provided a code" do
297
297
  url = @oauth.url_for_access_token(@code)
298
- url.should match_url("https://#{Koala::Facebook::GRAPH_SERVER}/oauth/access_token?client_id=#{@app_id}&code=#{@code}&client_secret=#{@secret}&redirect_uri=#{CGI.escape @callback_url}").should be_true
298
+ url.should match_url("https://#{Koala::Facebook::GRAPH_SERVER}/oauth/access_token?client_id=#{@app_id}&code=#{@code}&client_secret=#{@secret}&redirect_uri=#{CGI.escape @callback_url}")
299
299
  end
300
300
 
301
301
  it "generates a properly formatted OAuth token URL when provided a callback" do
302
302
  callback = "foo.com"
303
303
  url = @oauth.url_for_access_token(@code, :callback => callback)
304
- url.should match_url("https://#{Koala::Facebook::GRAPH_SERVER}/oauth/access_token?client_id=#{@app_id}&code=#{@code}&client_secret=#{@secret}&redirect_uri=#{CGI.escape callback}").should be_true
304
+ url.should match_url("https://#{Koala::Facebook::GRAPH_SERVER}/oauth/access_token?client_id=#{@app_id}&code=#{@code}&client_secret=#{@secret}&redirect_uri=#{CGI.escape callback}")
305
305
  end
306
306
 
307
307
  it "includes any additional options as URL parameters, appropriately escaped" do
@@ -399,7 +399,7 @@ describe "Koala::Facebook::OAuth" do
399
399
  end
400
400
 
401
401
  it "raises an error when get_access_token is called with a bad code" do
402
- lambda { @oauth.get_access_token_info("foo") }.should raise_error(Koala::Facebook::APIError)
402
+ lambda { @oauth.get_access_token_info("foo") }.should raise_error(Koala::Facebook::OAuthTokenRequestError)
403
403
  end
404
404
  end
405
405
  end
@@ -425,7 +425,7 @@ describe "Koala::Facebook::OAuth" do
425
425
  end
426
426
 
427
427
  it "raises an error when get_access_token is called with a bad code" do
428
- lambda { @oauth.get_access_token("foo") }.should raise_error(Koala::Facebook::APIError)
428
+ lambda { @oauth.get_access_token("foo") }.should raise_error(Koala::Facebook::OAuthTokenRequestError)
429
429
  end
430
430
  end
431
431
  end
@@ -493,7 +493,7 @@ describe "Koala::Facebook::OAuth" do
493
493
  end
494
494
 
495
495
  it "raises an error when exchange_access_token_info is called with a bad code" do
496
- lambda { @oauth.exchange_access_token_info("foo") }.should raise_error(Koala::Facebook::APIError)
496
+ lambda { @oauth.exchange_access_token_info("foo") }.should raise_error(Koala::Facebook::OAuthTokenRequestError)
497
497
  end
498
498
  end
499
499
 
@@ -579,9 +579,9 @@ describe "Koala::Facebook::OAuth" do
579
579
  result.each_with_index {|r, index| index > 0 ? r.should(be_a(Hash)) : r.should(be_nil)}
580
580
  end
581
581
 
582
- it "throws an APIError if Facebook returns an empty body (as happens for instance when the API breaks)" do
582
+ it "throws a BadFacebookResponse if Facebook returns an empty body (as happens for instance when the API breaks)" do
583
583
  @oauth.should_receive(:fetch_token_string).and_return("")
584
- lambda { @oauth.get_token_info_from_session_keys(@multiple_session_keys) }.should raise_error(Koala::Facebook::APIError)
584
+ lambda { @oauth.get_token_info_from_session_keys(@multiple_session_keys) }.should raise_error(Koala::Facebook::BadFacebookResponse)
585
585
  end
586
586
 
587
587
  it "passes on any options provided to make_request" do