koala 2.4.0 → 3.5.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (60) hide show
  1. checksums.yaml +5 -5
  2. data/.github/workflows/test.yml +32 -0
  3. data/Gemfile +5 -3
  4. data/ISSUE_TEMPLATE +25 -0
  5. data/PULL_REQUEST_TEMPLATE +11 -0
  6. data/changelog.md +161 -4
  7. data/code_of_conduct.md +64 -12
  8. data/koala.gemspec +5 -1
  9. data/lib/koala/api/batch_operation.rb +3 -6
  10. data/lib/koala/api/{graph_api.rb → graph_api_methods.rb} +29 -104
  11. data/lib/koala/api/graph_batch_api.rb +112 -65
  12. data/lib/koala/api/graph_collection.rb +19 -12
  13. data/lib/koala/api/graph_error_checker.rb +4 -3
  14. data/lib/koala/api.rb +65 -26
  15. data/lib/koala/configuration.rb +56 -0
  16. data/lib/koala/errors.rb +22 -2
  17. data/lib/koala/http_service/request.rb +133 -0
  18. data/lib/koala/http_service/response.rb +6 -4
  19. data/lib/koala/http_service/uploadable_io.rb +0 -5
  20. data/lib/koala/http_service.rb +29 -76
  21. data/lib/koala/oauth.rb +8 -8
  22. data/lib/koala/realtime_updates.rb +26 -21
  23. data/lib/koala/test_users.rb +9 -8
  24. data/lib/koala/version.rb +1 -1
  25. data/lib/koala.rb +7 -9
  26. data/readme.md +83 -109
  27. data/spec/cases/api_spec.rb +176 -69
  28. data/spec/cases/configuration_spec.rb +11 -0
  29. data/spec/cases/error_spec.rb +16 -3
  30. data/spec/cases/graph_api_batch_spec.rb +75 -44
  31. data/spec/cases/graph_api_spec.rb +15 -29
  32. data/spec/cases/graph_collection_spec.rb +47 -34
  33. data/spec/cases/graph_error_checker_spec.rb +31 -2
  34. data/spec/cases/http_service/request_spec.rb +250 -0
  35. data/spec/cases/http_service/response_spec.rb +24 -0
  36. data/spec/cases/http_service_spec.rb +126 -286
  37. data/spec/cases/koala_spec.rb +7 -5
  38. data/spec/cases/oauth_spec.rb +41 -2
  39. data/spec/cases/realtime_updates_spec.rb +51 -13
  40. data/spec/cases/test_users_spec.rb +56 -2
  41. data/spec/cases/uploadable_io_spec.rb +31 -31
  42. data/spec/fixtures/cat.m4v +0 -0
  43. data/spec/fixtures/facebook_data.yml +4 -6
  44. data/spec/fixtures/mock_facebook_responses.yml +41 -78
  45. data/spec/fixtures/vcr_cassettes/app_test_accounts.yml +97 -0
  46. data/spec/integration/graph_collection_spec.rb +8 -5
  47. data/spec/spec_helper.rb +2 -2
  48. data/spec/support/graph_api_shared_examples.rb +152 -337
  49. data/spec/support/koala_test.rb +11 -13
  50. data/spec/support/mock_http_service.rb +11 -14
  51. data/spec/support/uploadable_io_shared_examples.rb +4 -4
  52. metadata +47 -48
  53. data/.autotest +0 -12
  54. data/.travis.yml +0 -17
  55. data/Guardfile +0 -6
  56. data/autotest/discover.rb +0 -1
  57. data/lib/koala/api/rest_api.rb +0 -135
  58. data/lib/koala/http_service/multipart_request.rb +0 -41
  59. data/spec/cases/multipart_request_spec.rb +0 -65
  60. data/spec/support/rest_api_shared_examples.rb +0 -168
@@ -1,4 +1,5 @@
1
1
  require 'spec_helper'
2
+ require 'json' unless Hash.respond_to?(:to_json)
2
3
 
3
4
  describe "Koala::Facebook::GraphAPI in batch mode" do
4
5
 
@@ -58,11 +59,11 @@ describe "Koala::Facebook::GraphAPI in batch mode" do
58
59
  @batch_queue = []
59
60
  allow(Koala::Facebook::API).to receive(:batch_calls).and_return(@batch_queue)
60
61
 
61
- allow(Koala::UploadableIO).to receive(:new).with(@binary).and_return(@uploadable_io)
62
- allow(Koala::UploadableIO).to receive(:binary_content?).and_return(false)
63
- allow(Koala::UploadableIO).to receive(:binary_content?).with(@binary).and_return(true)
64
- allow(Koala::UploadableIO).to receive(:binary_content?).with(@uploadable_io).and_return(true)
65
- allow(@uploadable_io).to receive(:is_a?).with(Koala::UploadableIO).and_return(true)
62
+ allow(Koala::HTTPService::UploadableIO).to receive(:new).with(@binary).and_return(@uploadable_io)
63
+ allow(Koala::HTTPService::UploadableIO).to receive(:binary_content?).and_return(false)
64
+ allow(Koala::HTTPService::UploadableIO).to receive(:binary_content?).with(@binary).and_return(true)
65
+ allow(Koala::HTTPService::UploadableIO).to receive(:binary_content?).with(@uploadable_io).and_return(true)
66
+ allow(@uploadable_io).to receive(:is_a?).with(Koala::HTTPService::UploadableIO).and_return(true)
66
67
 
67
68
  @args[:method] = "post" # files are always post
68
69
  end
@@ -243,11 +244,11 @@ describe "Koala::Facebook::GraphAPI in batch mode" do
243
244
  describe "with binary files" do
244
245
  before :each do
245
246
  @binary = double("Binary file")
246
- allow(Koala::UploadableIO).to receive(:binary_content?).and_return(false)
247
- allow(Koala::UploadableIO).to receive(:binary_content?).with(@binary).and_return(true)
247
+ allow(Koala::HTTPService::UploadableIO).to receive(:binary_content?).and_return(false)
248
+ allow(Koala::HTTPService::UploadableIO).to receive(:binary_content?).with(@binary).and_return(true)
248
249
  @uploadable_io = double("UploadableIO")
249
- allow(Koala::UploadableIO).to receive(:new).with(@binary).and_return(@uploadable_io)
250
- allow(@uploadable_io).to receive(:is_a?).with(Koala::UploadableIO).and_return(true)
250
+ allow(Koala::HTTPService::UploadableIO).to receive(:new).with(@binary).and_return(@uploadable_io)
251
+ allow(@uploadable_io).to receive(:is_a?).with(Koala::HTTPService::UploadableIO).and_return(true)
251
252
 
252
253
  @batch_queue = []
253
254
  allow(Koala::Facebook::API).to receive(:batch_calls).and_return(@batch_queue)
@@ -322,7 +323,7 @@ describe "Koala::Facebook::GraphAPI in batch mode" do
322
323
  allow(Koala::Facebook::GraphBatchAPI::BatchOperation).to receive(:new).and_return(op)
323
324
 
324
325
  # two requests should generate two batch operations
325
- expected = MultiJson.dump([op.to_batch_params(access_token, nil), op.to_batch_params(access_token, nil)])
326
+ expected = JSON.dump([op.to_batch_params(access_token, nil), op.to_batch_params(access_token, nil)])
326
327
  expect(Koala).to receive(:make_request).with(anything, hash_including("batch" => expected), anything, anything).and_return(@fake_response)
327
328
  Koala::Facebook::API.new(access_token).batch do |batch_api|
328
329
  batch_api.get_object('me')
@@ -468,17 +469,57 @@ describe "Koala::Facebook::GraphAPI in batch mode" do
468
469
  expect(thread_one_count).to eq(first_count)
469
470
  expect(thread_two_count).to eq(second_count)
470
471
  end
472
+
473
+ end
474
+ end
475
+
476
+ describe '#big_batches' do
477
+ before :each do
478
+ payload = [{code: 200, headers: [{name: "Content-Type", value: "text/javascript; charset=UTF-8"}], body: "{\"id\":\"1234\"}"}]
479
+ allow(Koala).to receive(:make_request) do |_request, args, _verb, _options|
480
+ request_count = JSON.parse(args['batch']).length
481
+ expect(request_count).to be <= 50 # check FB's limit
482
+ Koala::HTTPService::Response.new(200, (payload * request_count).to_json, {})
483
+ end
484
+ end
485
+
486
+ it 'stays within fb limits' do
487
+ count_calls = 0
488
+ expected_calls = 100
489
+ @api.batch do |batch_api|
490
+ expected_calls.times { |_i| batch_api.get_object('me') { |_ret| count_calls += 1 } }
491
+ end
492
+
493
+ expect(count_calls).to eq(expected_calls)
494
+ end
495
+
496
+ it 'is recursive safe' do
497
+ # ensure batch operations whose callbacks call batch operations don't resubmit
498
+ call_count = 0
499
+ iterations = 60
500
+ @api.batch do |batch_api|
501
+ # must do enough calls to provoke a batch submission
502
+ iterations.times { |_i|
503
+ batch_api.get_object('me') { |_ret|
504
+ call_count += 1
505
+ batch_api.get_object('me') { |_ret|
506
+ call_count += 1
507
+ }
508
+ }
509
+ }
510
+ end
511
+ expect(call_count).to eq(2 * iterations)
471
512
  end
472
513
  end
473
514
 
474
515
  describe "usage tests" do
475
516
  it "gets two results at once" do
476
- me, koppel = @api.batch do |batch_api|
517
+ me, barackobama = @api.batch do |batch_api|
477
518
  batch_api.get_object('me')
478
519
  batch_api.get_object(KoalaTest.user1)
479
520
  end
480
521
  expect(me['id']).not_to be_nil
481
- expect(koppel['id']).not_to be_nil
522
+ expect(barackobama['id']).not_to be_nil
482
523
  end
483
524
 
484
525
  it 'makes mixed calls inside of a batch' do
@@ -486,7 +527,7 @@ describe "Koala::Facebook::GraphAPI in batch mode" do
486
527
  batch_api.get_object('me')
487
528
  batch_api.get_connections('me', 'friends')
488
529
  end
489
- expect(friends).to be_a(Koala::Facebook::GraphCollection)
530
+ expect(friends).to be_a(Koala::Facebook::API::GraphCollection)
490
531
  end
491
532
 
492
533
  it 'turns pageable results into GraphCollections' do
@@ -502,7 +543,7 @@ describe "Koala::Facebook::GraphAPI in batch mode" do
502
543
  pictures = @api.batch do |batch_api|
503
544
  batch_api.get_picture('me')
504
545
  end
505
- expect(pictures.first).to match(/http\:\/\//) # works both live & stubbed
546
+ expect(pictures.first).to match(/https\:\/\//) # works both live & stubbed
506
547
  end
507
548
 
508
549
  it 'takes an after processing block for a get_picture call inside of a batch' do
@@ -510,40 +551,40 @@ describe "Koala::Facebook::GraphAPI in batch mode" do
510
551
  @api.batch do |batch_api|
511
552
  batch_api.get_picture('me') { |pic| picture = pic }
512
553
  end
513
- expect(picture).to match(/http\:\/\//) # works both live & stubbed
554
+ expect(picture).to match(/https\:\/\//) # works both live & stubbed
514
555
  end
515
556
 
516
557
  it "handles requests for two different tokens" do
517
- me, insights = @api.batch do |batch_api|
558
+ me, app_event_types = @api.batch do |batch_api|
518
559
  batch_api.get_object('me')
519
- batch_api.get_connections(@app_id, 'insights', {}, {"access_token" => @app_api.access_token})
560
+ batch_api.get_connections(@app_id, 'app_event_types', {}, {"access_token" => @app_api.access_token})
520
561
  end
521
562
  expect(me['id']).not_to be_nil
522
- expect(insights).to be_an(Koala::Facebook::GraphCollection)
563
+ expect(app_event_types).to be_an(Koala::Facebook::API::GraphCollection)
523
564
  end
524
565
 
525
566
  it "handles requests passing the access token option as a symbol instead of a string" do
526
- me, insights = @api.batch do |batch_api|
567
+ me, app_event_types = @api.batch do |batch_api|
527
568
  batch_api.get_object('me')
528
- batch_api.get_connections(@app_id, 'insights', {}, {:access_token => @app_api.access_token})
569
+ batch_api.get_connections(@app_id, 'app_event_types', {}, {:access_token => @app_api.access_token})
529
570
  end
530
571
  expect(me['id']).not_to be_nil
531
- expect(insights).to be_an(Koala::Facebook::GraphCollection)
572
+ expect(app_event_types).to be_an(Koala::Facebook::API::GraphCollection)
532
573
  end
533
574
 
534
575
  it "preserves batch-op specific access tokens in GraphCollection returned from batch" do
535
576
  # Provide an alternate token for a batch operation
536
577
  @other_access_token_args = { 'access_token' => @app_api.access_token }
537
578
 
538
- # make a batch call for insights using another token
539
- me, insights = @api.batch do |batch_api|
579
+ # make a batch call for app_event_types using another token
580
+ me, app_event_types = @api.batch do |batch_api|
540
581
  batch_api.get_object('me')
541
- batch_api.get_connections(@app_id, 'insights', {}, @other_access_token_args)
582
+ batch_api.get_connections(@app_id, 'app_event_types', {}, @other_access_token_args)
542
583
  end
543
584
 
544
585
  # The alternate token is returned with the next page parameters
545
586
  # The GraphCollection should receive a request for the next_page_params during paging
546
- expect(insights).to receive(:next_page_params).and_return([double("base"), @other_access_token_args.dup])
587
+ expect(app_event_types).to receive(:next_page_params).and_return([double("base"), @other_access_token_args.dup])
547
588
 
548
589
  # The alternate access token should pass through to making the request
549
590
  # Koala should receive a request during paging using the alternate token
@@ -552,41 +593,31 @@ describe "Koala::Facebook::GraphAPI in batch mode" do
552
593
  hash_including(@other_access_token_args.dup),
553
594
  anything,
554
595
  anything
555
- ).and_return(Koala::HTTPService::Response.new(200, "", ""))
596
+ ).and_return(Koala::HTTPService::Response.new(200, "", {}))
556
597
 
557
598
  # Page the collection
558
- insights.next_page
599
+ app_event_types.next_page
559
600
  end
560
601
 
561
602
  it "inserts errors in the appropriate place, without breaking other results" do
562
- failed_call, koppel = @api.batch do |batch_api|
603
+ failed_call, barackobama = @api.batch do |batch_api|
563
604
  batch_api.get_connection("2", "invalidconnection")
564
605
  batch_api.get_object(KoalaTest.user1, {}, {"access_token" => @app_api.access_token})
565
606
  end
566
607
  expect(failed_call).to be_a(Koala::Facebook::ClientError)
567
- expect(koppel["id"]).not_to be_nil
608
+ expect(barackobama["id"]).not_to be_nil
568
609
  end
569
610
 
570
611
  it "handles different request methods" do
571
612
  result = @api.put_wall_post("Hello, world, from the test suite batch API!")
572
613
  wall_post = result["id"]
573
614
 
574
- wall_post, koppel = @api.batch do |batch_api|
615
+ wall_post, barackobama = @api.batch do |batch_api|
575
616
  batch_api.put_like(wall_post)
576
617
  batch_api.delete_object(wall_post)
577
618
  end
578
619
  end
579
620
 
580
- it "allows FQL" do
581
- result = @api.batch do |batch_api|
582
- batch_api.graph_call("method/fql.query", {:query=>"select first_name from user where uid=#{KoalaTest.user1_id}"}, "post")
583
- end
584
-
585
- fql_result = result[0]
586
- expect(fql_result[0]).to be_a(Hash)
587
- expect(fql_result[0]["first_name"]).to eq("Alex")
588
- end
589
-
590
621
  describe 'with post-processing callback' do
591
622
  let(:me_result) { double("me result") }
592
623
  let(:friends_result) { [double("friends result")] }
@@ -668,23 +699,23 @@ describe "Koala::Facebook::GraphAPI in batch mode" do
668
699
  end
669
700
 
670
701
  it "allows you to create dependencies" do
671
- me, koppel = @api.batch do |batch_api|
702
+ me, barackobama = @api.batch do |batch_api|
672
703
  batch_api.get_object("me", {}, :batch_args => {:name => "getme"})
673
704
  batch_api.get_object(KoalaTest.user1, {}, :batch_args => {:depends_on => "getme"})
674
705
  end
675
706
 
676
707
  expect(me).to be_nil # gotcha! it's omitted because it's a successfully-executed dependency
677
- expect(koppel["id"]).not_to be_nil
708
+ expect(barackobama["id"]).not_to be_nil
678
709
  end
679
710
 
680
711
  it "properly handles dependencies that fail" do
681
- failed_call, koppel = @api.batch do |batch_api|
712
+ failed_call, barackobama = @api.batch do |batch_api|
682
713
  batch_api.get_connections("2", "invalidconnection", {}, :batch_args => {:name => "getdata"})
683
714
  batch_api.get_object(KoalaTest.user1, {}, :batch_args => {:depends_on => "getdata"})
684
715
  end
685
716
 
686
717
  expect(failed_call).to be_a(Koala::Facebook::ClientError)
687
- expect(koppel).to be_nil
718
+ expect(barackobama).to be_nil
688
719
  end
689
720
 
690
721
  it "throws an error for badly-constructed request relationships" do
@@ -9,6 +9,8 @@ describe 'Koala::Facebook::GraphAPIMethods' do
9
9
  @app_api = Koala::Facebook::API.new(@app_access_token)
10
10
  end
11
11
 
12
+ let(:dummy_response) { double("fake response", data: {}, status: 200, body: "", headers: {}) }
13
+
12
14
  describe 'post-processing for' do
13
15
  let(:result) { double("result") }
14
16
  let(:post_processing) { lambda {|arg| {"result" => result, "args" => arg} } }
@@ -17,47 +19,31 @@ describe 'Koala::Facebook::GraphAPIMethods' do
17
19
  # and the other methods which do some post-processing locally
18
20
  context '#get_object' do
19
21
  it 'returns result of block' do
20
- allow(@api).to receive(:api).and_return(double("other results"))
21
- expect(@api.get_object('koppel', &post_processing)["result"]).to eq(result)
22
+ allow(@api).to receive(:api).and_return(dummy_response)
23
+ expect(@api.get_object('barackobama', &post_processing)["result"]).to eq(result)
22
24
  end
23
25
 
24
26
  it "doesn't add token to received arguments" do
25
27
  args = {}.freeze
26
- expect(Koala).to receive(:make_request).and_return(Koala::HTTPService::Response.new(200, "", ""))
27
- expect(@api.get_object('koppel', args, &post_processing)["result"]).to eq(result)
28
+ expect(Koala).to receive(:make_request).and_return(dummy_response)
29
+ expect(@api.get_object('barackobama', args, &post_processing)["result"]).to eq(result)
28
30
  end
29
31
  end
30
32
 
31
33
  context '#get_picture' do
32
34
  it 'returns result of block' do
33
- allow(@api).to receive(:api).and_return({"data" => {"is_silhouette" => false, "url" => result}})
34
- expect(@api.get_picture('lukeshepard', &post_processing)["result"]).to eq(result)
35
- end
36
- end
37
-
38
- context '#fql_multiquery' do
39
- before do
40
- expect(@api).to receive(:get_object).and_return([
41
- {"name" => "query1", "fql_result_set" => [{"id" => 123}]},
42
- {"name" => "query2", "fql_result_set" => ["id" => 456]}
43
- ])
44
- end
45
-
46
- it 'is called with resolved response' do
47
- resolved_result = {
48
- 'query1' => [{'id' => 123}],
49
- 'query2' => [{'id' => 456}]
50
- }
51
- response = @api.fql_multiquery({}, &post_processing)
52
- expect(response["args"]).to eq(resolved_result)
53
- expect(response["result"]).to eq(result)
35
+ result_url = "a url"
36
+ allow(@api).to receive(:api).and_return(Koala::HTTPService::Response.new(200, {"data" => {"is_silhouette" => false, "url" => result_url}}.to_json, {}))
37
+ expect(@api.get_picture('koppel', &post_processing)["result"]).to eq(result)
54
38
  end
55
39
  end
56
40
 
57
41
  context '#get_page_access_token' do
58
42
  it 'returns result of block' do
59
43
  token = Koala::MockHTTPService::APP_ACCESS_TOKEN
60
- allow(@api).to receive(:api).and_return("access_token" => token)
44
+ allow(@api).to receive(:api).and_return(
45
+ Koala::HTTPService::Response.new(200, {"access_token" => token}.to_json, {})
46
+ )
61
47
  response = @api.get_page_access_token('facebook', &post_processing)
62
48
  expect(response["args"]).to eq(token)
63
49
  expect(response["result"]).to eq(result)
@@ -71,18 +57,18 @@ describe 'Koala::Facebook::GraphAPIMethods' do
71
57
 
72
58
  it "is enabled by default if an app secret is present" do
73
59
  api = Koala::Facebook::API.new(@token, "mysecret")
74
- expect(api).to receive(:api).with(path, {}, 'get', :appsecret_proof => true)
60
+ expect(api).to receive(:api).with(path, {}, 'get', :appsecret_proof => true).and_return(dummy_response)
75
61
  api.graph_call(path)
76
62
  end
77
63
 
78
64
  it "can be disabled manually" do
79
65
  api = Koala::Facebook::API.new(@token, "mysecret")
80
- expect(api).to receive(:api).with(path, {}, 'get', hash_not_including(appsecret_proof: true))
66
+ expect(api).to receive(:api).with(path, {}, 'get', hash_not_including(appsecret_proof: true)).and_return(dummy_response)
81
67
  api.graph_call(path, {}, "get", appsecret_proof: false)
82
68
  end
83
69
 
84
70
  it "isn't included if no app secret is present" do
85
- expect(@api).to receive(:api).with(path, {}, 'get', {})
71
+ expect(@api).to receive(:api).with(path, {}, 'get', {}).and_return(dummy_response)
86
72
  @api.graph_call(path)
87
73
  end
88
74
  end
@@ -1,28 +1,30 @@
1
1
  require 'spec_helper'
2
2
 
3
- describe Koala::Facebook::GraphCollection do
4
- let(:paging){ {:paging => true} }
3
+ describe Koala::Facebook::API::GraphCollection do
4
+ let(:paging){ {"paging" => true} }
5
5
 
6
6
  before(:each) do
7
- @result = {
8
- "data" => [1, 2, :three],
7
+ @headers = {'Content-Type' => 'application/json'}
8
+ @data = {
9
+ "data" => [1, 2, 'three'],
9
10
  "paging" => paging,
10
11
  "summary" => [3]
11
12
  }
13
+ @result = Koala::HTTPService::Response.new(200, @data.to_json, @headers)
12
14
  @api = Koala::Facebook::API.new("123")
13
- @collection = Koala::Facebook::GraphCollection.new(@result, @api)
15
+ @collection = Koala::Facebook::API::GraphCollection.new(@result, @api)
14
16
  end
15
17
 
16
18
  it "subclasses Array" do
17
- expect(Koala::Facebook::GraphCollection.ancestors).to include(Array)
19
+ expect(Koala::Facebook::API::GraphCollection.ancestors).to include(Array)
18
20
  end
19
21
 
20
22
  it "creates an array-like object" do
21
- expect(Koala::Facebook::GraphCollection.new(@result, @api)).to be_an(Array)
23
+ expect(Koala::Facebook::API::GraphCollection.new(@result, @api)).to be_an(Array)
22
24
  end
23
25
 
24
26
  it "contains the result data" do
25
- @result["data"].each_with_index {|r, i| expect(@collection[i]).to eq(r)}
27
+ @data["data"].each_with_index {|r, i| expect(@collection[i]).to eq(r)}
26
28
  end
27
29
 
28
30
  it "has a read-only paging attribute" do
@@ -31,43 +33,49 @@ describe Koala::Facebook::GraphCollection do
31
33
  end
32
34
 
33
35
  it "sets paging to results['paging']" do
34
- expect(@collection.paging).to eq(@result["paging"])
36
+ expect(@collection.paging).to eq(@data["paging"])
35
37
  end
36
38
 
37
39
  it "sets summary to results['summary']" do
38
- expect(@collection.summary).to eq(@result["summary"])
40
+ expect(@collection.summary).to eq(@data["summary"])
39
41
  end
40
42
 
41
43
  it "sets raw_response to the original results" do
42
- expect(@collection.raw_response).to eq(@result)
44
+ expect(@collection.raw_response).to eq(@result.data)
43
45
  end
44
46
 
45
47
  it "sets the API to the provided API" do
46
48
  expect(@collection.api).to eq(@api)
47
49
  end
48
50
 
51
+ it "sets the headers correctly" do
52
+ expect(@collection.headers).to eq(@headers)
53
+ end
54
+
49
55
  describe "when getting a whole page" do
50
56
  before(:each) do
51
57
  @second_page = {
52
- "data" => [:second, :page, :data],
58
+ "data" => ["second", "page", "data"],
53
59
  "paging" => {}
54
60
  }
55
61
  @base = double("base")
56
62
  @args = {"a" => 1}
57
63
  @page_of_results = double("page of results")
64
+ @result = Koala::HTTPService::Response.new(200, @second_page.to_json, {})
65
+ @result.data
58
66
  end
59
67
 
60
68
  it "should return the previous page of results" do
61
69
  expect(@collection).to receive(:previous_page_params).and_return([@base, @args])
62
- expect(@api).to receive(:api).with(@base, @args, anything, anything).and_return(@second_page)
63
- expect(Koala::Facebook::GraphCollection).to receive(:new).with(@second_page, @api).and_return(@page_of_results)
70
+ expect(@api).to receive(:api).with(@base, @args, anything, anything).and_return(@result)
71
+ expect(Koala::Facebook::API::GraphCollection).to receive(:new).with(@result, @api).and_return(@page_of_results)
64
72
  expect(@collection.previous_page).to eq(@page_of_results)
65
73
  end
66
74
 
67
75
  it "should return the next page of results" do
68
76
  expect(@collection).to receive(:next_page_params).and_return([@base, @args])
69
- expect(@api).to receive(:api).with(@base, @args, anything, anything).and_return(@second_page)
70
- expect(Koala::Facebook::GraphCollection).to receive(:new).with(@second_page, @api).and_return(@page_of_results)
77
+ expect(@api).to receive(:api).with(@base, @args, anything, anything).and_return(@result)
78
+ expect(Koala::Facebook::API::GraphCollection).to receive(:new).with(@result, @api).and_return(@page_of_results)
71
79
 
72
80
  expect(@collection.next_page).to eq(@page_of_results)
73
81
  end
@@ -84,13 +92,13 @@ describe Koala::Facebook::GraphCollection do
84
92
  describe "#parse_page_url" do
85
93
  it "should pass the url to the class method" do
86
94
  url = double("url")
87
- expect(Koala::Facebook::GraphCollection).to receive(:parse_page_url).with(url)
95
+ expect(Koala::Facebook::API::GraphCollection).to receive(:parse_page_url).with(url)
88
96
  @collection.parse_page_url(url)
89
97
  end
90
98
 
91
99
  it "should return the result of the class method" do
92
100
  parsed_content = double("parsed_content")
93
- allow(Koala::Facebook::GraphCollection).to receive(:parse_page_url).and_return(parsed_content)
101
+ allow(Koala::Facebook::API::GraphCollection).to receive(:parse_page_url).and_return(parsed_content)
94
102
  expect(@collection.parse_page_url(double("url"))).to eq(parsed_content)
95
103
  end
96
104
  end
@@ -98,54 +106,59 @@ describe Koala::Facebook::GraphCollection do
98
106
  describe ".parse_page_url" do
99
107
  it "should return the base as the first array entry" do
100
108
  base = "url_path"
101
- expect(Koala::Facebook::GraphCollection.parse_page_url("http://facebook.com/#{base}?anything").first).to eq(base)
109
+ expect(Koala::Facebook::API::GraphCollection.parse_page_url("http://facebook.com/#{base}?anything").first).to eq(base)
102
110
  end
103
111
 
104
112
  it "should return the arguments as a hash as the last array entry" do
105
113
  args_hash = {"one" => "val_one", "two" => "val_two"}
106
- expect(Koala::Facebook::GraphCollection.parse_page_url("http://facebook.com/anything?#{args_hash.map {|k,v| "#{k}=#{v}" }.join("&")}").last).to eq(args_hash)
114
+ expect(Koala::Facebook::API::GraphCollection.parse_page_url("http://facebook.com/anything?#{args_hash.map {|k,v| "#{k}=#{v}" }.join("&")}").last).to eq(args_hash)
107
115
  end
108
116
 
109
117
  it "works with non-.com addresses" do
110
118
  base = "url_path"
111
119
  args_hash = {"one" => "val_one", "two" => "val_two"}
112
- expect(Koala::Facebook::GraphCollection.parse_page_url("http://facebook.com/#{base}?#{args_hash.map {|k,v| "#{k}=#{v}" }.join("&")}")).to eq([base, args_hash])
120
+ expect(Koala::Facebook::API::GraphCollection.parse_page_url("http://facebook.com/#{base}?#{args_hash.map {|k,v| "#{k}=#{v}" }.join("&")}")).to eq([base, args_hash])
113
121
  end
114
122
 
115
123
  it "works with addresses with irregular characters" do
116
124
  access_token = "appid123a|fdcba"
117
- base, args_hash = Koala::Facebook::GraphCollection.parse_page_url("http://facebook.com/foo?token=#{access_token}")
125
+ base, args_hash = Koala::Facebook::API::GraphCollection.parse_page_url("http://facebook.com/foo?token=#{access_token}")
118
126
  expect(args_hash["token"]).to eq(access_token)
119
127
  end
120
128
  end
121
129
  end
122
130
 
123
131
  describe ".evaluate" do
124
- it "returns the original result if it's provided a non-hash result" do
125
- result = []
126
- expect(Koala::Facebook::GraphCollection.evaluate(result, @api)).to eq(result)
132
+ it "returns the body of the original response if it's provided a Response with a non-hash data key" do
133
+ result = double('fake response')
134
+ allow(result).to receive(:is_a?).with(Hash).and_return(false)
135
+ allow(result).to receive(:data).and_return([])
136
+ expect(Koala::Facebook::API::GraphCollection.evaluate(result, @api)).to eq([])
127
137
  end
128
138
 
129
139
  it "returns the original result if it's provided a nil result" do
130
140
  result = nil
131
- expect(Koala::Facebook::GraphCollection.evaluate(result, @api)).to eq(result)
141
+ expect(Koala::Facebook::API::GraphCollection.evaluate(result, @api)).to eq(result)
132
142
  end
133
143
 
134
- it "returns the original result if the result doesn't have a data key" do
135
- result = {"paging" => {}}
136
- expect(Koala::Facebook::GraphCollection.evaluate(result, @api)).to eq(result)
144
+ it "returns the original result body if the result doesn't have a data key" do
145
+ paging = {"paging" => {}}
146
+ result = Koala::HTTPService::Response.new(200, paging.to_json, {})
147
+ expect(Koala::Facebook::API::GraphCollection.evaluate(result, @api)).to eq(paging)
137
148
  end
138
149
 
139
150
  it "returns the original result if the result's data key isn't an array" do
140
- result = {"data" => {}, "paging" => {}}
141
- expect(Koala::Facebook::GraphCollection.evaluate(result, @api)).to eq(result)
151
+ body = {"data" => {}, "paging" => {}}
152
+ result = Koala::HTTPService::Response.new(200, body.to_json, {})
153
+ expect(Koala::Facebook::API::GraphCollection.evaluate(result, @api)).to eq(body)
142
154
  end
143
155
 
144
156
  it "returns a new GraphCollection of the result if it has an array data key and a paging key" do
145
- result = {"data" => [], "paging" => {}}
157
+ body = {"data" => [], "paging" => {}}
158
+ result = Koala::HTTPService::Response.new(200, body.to_json, {})
146
159
  expected = :foo
147
- expect(Koala::Facebook::GraphCollection).to receive(:new).with(result, @api).and_return(expected)
148
- expect(Koala::Facebook::GraphCollection.evaluate(result, @api)).to eq(expected)
160
+ expect(Koala::Facebook::API::GraphCollection).to receive(:new).with(result, @api).and_return(expected)
161
+ expect(Koala::Facebook::API::GraphCollection.evaluate(result, @api)).to eq(expected)
149
162
  end
150
163
  end
151
164
 
@@ -11,7 +11,10 @@ module Koala
11
11
  expect(GraphErrorChecker::DEBUG_HEADERS).to match_array([
12
12
  "x-fb-rev",
13
13
  "x-fb-debug",
14
- "x-fb-trace-id"
14
+ "x-fb-trace-id",
15
+ "x-business-use-case-usage",
16
+ "x-ad-account-usage",
17
+ "x-app-usage"
15
18
  ])
16
19
  end
17
20
 
@@ -54,6 +57,18 @@ module Koala
54
57
  expect(error.response_body).to eq(body)
55
58
  end
56
59
 
60
+ it "returns a ClientError if the body is empty" do
61
+ body.replace("")
62
+ expect(error).to be_a(ClientError)
63
+ expect(error.response_body).to eq(body)
64
+ end
65
+
66
+ it "returns a ClientError if the body is null" do
67
+ body.replace("null")
68
+ expect(error).to be_a(ClientError)
69
+ expect(error.response_body).to eq(body)
70
+ end
71
+
57
72
  it "adds error data from the body" do
58
73
  error_data = {
59
74
  "type" => "FB error type",
@@ -78,10 +93,25 @@ module Koala
78
93
  "x-fb-debug" => double("fb debug"),
79
94
  "x-fb-rev" => double("fb rev"),
80
95
  "x-fb-trace-id" => double("fb trace id"),
96
+ "x-business-use-case-usage" => { 'a' => 1, 'b' => 2 }.to_json,
97
+ "x-ad-account-usage" => { 'c' => 3, 'd' => 4 }.to_json,
98
+ "x-app-usage" => { 'e' => 5, 'f' => 6 }.to_json
81
99
  )
82
100
  expect(error.fb_error_trace_id).to eq(headers["x-fb-trace-id"])
83
101
  expect(error.fb_error_debug).to eq(headers["x-fb-debug"])
84
102
  expect(error.fb_error_rev).to eq(headers["x-fb-rev"])
103
+ expect(error.fb_buc_usage).to eq({ 'a' => 1, 'b' => 2 })
104
+ expect(error.fb_ada_usage).to eq({ 'c' => 3, 'd' => 4 })
105
+ expect(error.fb_app_usage).to eq({ 'e' => 5, 'f' => 6 })
106
+ end
107
+
108
+ it "logs if one of the FB debug headers can't be parsed" do
109
+ headers.merge!(
110
+ "x-app-usage" => '{invalid:json}'
111
+ )
112
+
113
+ expect(Koala::Utils.logger).to receive(:error).with(/JSON::ParserError:.*unexpected token at '{invalid:json}' while parsing x-app-usage = {invalid:json}/)
114
+ expect(error.fb_app_usage).to eq(nil)
85
115
  end
86
116
 
87
117
  context "it returns an AuthenticationError" do
@@ -113,4 +143,3 @@ module Koala
113
143
  end
114
144
  end
115
145
  end
116
-