koala 2.4.0 → 3.5.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 (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
-