koala 0.4 → 3.7.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 (71) hide show
  1. checksums.yaml +7 -0
  2. data/.github/workflows/test.yml +32 -0
  3. data/.gitignore +9 -0
  4. data/.rspec +1 -0
  5. data/.yardopts +3 -0
  6. data/Gemfile +25 -0
  7. data/ISSUE_TEMPLATE +25 -0
  8. data/LICENSE +22 -0
  9. data/Manifest +32 -5
  10. data/PULL_REQUEST_TEMPLATE +11 -0
  11. data/Rakefile +12 -12
  12. data/changelog.md +781 -0
  13. data/code_of_conduct.md +74 -0
  14. data/koala.gemspec +28 -24
  15. data/lib/koala/api/batch_operation.rb +86 -0
  16. data/lib/koala/api/graph_api_methods.rb +504 -0
  17. data/lib/koala/api/graph_batch_api.rb +167 -0
  18. data/lib/koala/api/graph_collection.rb +129 -0
  19. data/lib/koala/api/graph_error_checker.rb +72 -0
  20. data/lib/koala/api.rb +159 -0
  21. data/lib/koala/configuration.rb +56 -0
  22. data/lib/koala/errors.rb +126 -0
  23. data/lib/koala/http_service/request.rb +133 -0
  24. data/lib/koala/http_service/response.rb +20 -0
  25. data/lib/koala/http_service/uploadable_io.rb +183 -0
  26. data/lib/koala/http_service.rb +108 -0
  27. data/lib/koala/oauth.rb +342 -0
  28. data/lib/koala/realtime_updates.rb +151 -0
  29. data/lib/koala/test_users.rb +189 -0
  30. data/lib/koala/utils.rb +41 -0
  31. data/lib/koala/version.rb +3 -0
  32. data/lib/koala.rb +51 -291
  33. data/readme.md +269 -21
  34. data/spec/cases/api_spec.rb +362 -0
  35. data/spec/cases/configuration_spec.rb +11 -0
  36. data/spec/cases/error_spec.rb +143 -0
  37. data/spec/cases/graph_api_batch_spec.rb +788 -0
  38. data/spec/cases/graph_api_spec.rb +76 -0
  39. data/spec/cases/graph_collection_spec.rb +192 -0
  40. data/spec/cases/graph_error_checker_spec.rb +147 -0
  41. data/spec/cases/http_service/request_spec.rb +250 -0
  42. data/spec/cases/http_service/response_spec.rb +24 -0
  43. data/spec/cases/http_service_spec.rb +280 -0
  44. data/spec/cases/koala_spec.rb +57 -0
  45. data/spec/cases/koala_test_spec.rb +5 -0
  46. data/spec/cases/oauth_spec.rb +647 -0
  47. data/spec/cases/realtime_updates_spec.rb +327 -0
  48. data/spec/cases/test_users_spec.rb +383 -0
  49. data/spec/cases/uploadable_io_spec.rb +266 -0
  50. data/spec/cases/utils_spec.rb +55 -0
  51. data/spec/fixtures/beach.jpg +0 -0
  52. data/spec/fixtures/cat.m4v +0 -0
  53. data/spec/fixtures/facebook_data.yml +63 -0
  54. data/spec/fixtures/mock_facebook_responses.yml +483 -0
  55. data/spec/fixtures/vcr_cassettes/app_test_accounts.yml +97 -0
  56. data/spec/fixtures/vcr_cassettes/friend_list_next_page.yml +121 -0
  57. data/spec/integration/graph_collection_spec.rb +24 -0
  58. data/spec/spec_helper.rb +25 -0
  59. data/spec/support/custom_matchers.rb +28 -0
  60. data/spec/support/graph_api_shared_examples.rb +534 -0
  61. data/spec/support/koala_test.rb +251 -0
  62. data/spec/support/mock_http_service.rb +140 -0
  63. data/spec/support/uploadable_io_shared_examples.rb +70 -0
  64. metadata +206 -62
  65. data/CHANGELOG +0 -24
  66. data/init.rb +0 -2
  67. data/lib/http_services.rb +0 -60
  68. data/test/facebook_data.yml +0 -5
  69. data/test/koala/facebook_no_access_token_tests.rb +0 -119
  70. data/test/koala/facebook_with_access_token_tests.rb +0 -106
  71. data/test/koala_tests.rb +0 -30
@@ -0,0 +1,362 @@
1
+ require 'spec_helper'
2
+
3
+ describe "Koala::Facebook::API" do
4
+ before :each do
5
+ @service = Koala::Facebook::API.new
6
+ end
7
+ let(:dummy_response) { double("fake response", data: {}, status: 200, body: "", headers: {}) }
8
+
9
+ it "defaults to the globally configured token if one's provided" do
10
+ token = "Foo"
11
+
12
+ Koala.configure do |config|
13
+ config.access_token = token
14
+ end
15
+
16
+ expect(Koala::Facebook::API.new.access_token).to eq(token)
17
+ end
18
+
19
+ it "defaults to the globally configured app_secret if one's provided" do
20
+ app_secret = "Foo"
21
+
22
+ Koala.configure do |config|
23
+ config.app_secret = app_secret
24
+ end
25
+
26
+ expect(Koala::Facebook::API.new.app_secret).to eq(app_secret)
27
+ end
28
+
29
+ it "doesn't include an access token if none was given" do
30
+ expect(Koala).to receive(:make_request).with(
31
+ anything,
32
+ hash_not_including('access_token' => 1),
33
+ anything,
34
+ anything
35
+ ).and_return(Koala::HTTPService::Response.new(200, "", ""))
36
+
37
+ @service.api('anything')
38
+ end
39
+
40
+ it "includes an access token if given" do
41
+ token = 'adfadf'
42
+ service = Koala::Facebook::API.new token
43
+
44
+ expect(Koala).to receive(:make_request).with(
45
+ anything,
46
+ hash_including('access_token' => token),
47
+ anything,
48
+ anything
49
+ ).and_return(Koala::HTTPService::Response.new(200, "", ""))
50
+
51
+ service.api('anything')
52
+ end
53
+
54
+ it "doesn't add token to received arguments" do
55
+ token = 'adfadf'
56
+ service = Koala::Facebook::API.new token
57
+
58
+ expect(Koala).to receive(:make_request).with(
59
+ anything,
60
+ hash_including('access_token' => token),
61
+ anything,
62
+ anything
63
+ ).and_return(Koala::HTTPService::Response.new(200, "", ""))
64
+
65
+ args = {}.freeze
66
+ service.api('anything', args)
67
+ end
68
+
69
+ it "turns arrays of non-enumerables into comma-separated arguments by default" do
70
+ args = [12345, {:foo => [1, 2, "3", :four]}]
71
+ expected = ["/12345", {:foo => "1,2,3,four"}, "get", {}]
72
+ response = double('Mock KoalaResponse', :body => '', :status => 200)
73
+ expect(Koala).to receive(:make_request).with(*expected).and_return(response)
74
+ @service.api(*args)
75
+ end
76
+
77
+ it "can be configured to leave arrays of non-enumerables as is" do
78
+ Koala.configure do |config|
79
+ config.preserve_form_arguments = true
80
+ end
81
+
82
+ args = [12345, {:foo => [1, 2, "3", :four]}]
83
+ expected = ["/12345", {:foo => [1, 2, "3", :four]}, "get", {}]
84
+ response = double('Mock KoalaResponse', :body => '', :status => 200)
85
+ expect(Koala).to receive(:make_request).with(*expected).and_return(response)
86
+ @service.api(*args)
87
+ end
88
+
89
+ it "can be configured on a per-request basis to leave arrays as is" do
90
+ args = [12345, {foo: [1, 2, "3", :four]}, "get", preserve_form_arguments: true]
91
+ expected = ["/12345", {foo: [1, 2, "3", :four]}, "get", preserve_form_arguments: true]
92
+ response = double('Mock KoalaResponse', :body => '', :status => 200)
93
+ expect(Koala).to receive(:make_request).with(*expected).and_return(response)
94
+ @service.api(*args)
95
+ end
96
+
97
+ it "doesn't turn arrays containing enumerables into comma-separated strings" do
98
+ params = {:foo => [1, 2, ["3"], :four]}
99
+ args = [12345, params]
100
+ # we leave this as is -- the HTTP layer can either handle it appropriately
101
+ # (if appropriate behavior is defined)
102
+ # or raise an exception
103
+ expected = ["/12345", params, "get", {}]
104
+ response = double('Mock KoalaResponse', :body => '', :status => 200)
105
+ expect(Koala).to receive(:make_request).with(*expected).and_return(response)
106
+ @service.api(*args)
107
+ end
108
+
109
+ it "doesn't modify any data if the option format of :json is provided" do
110
+ args = [12345, {:foo => [1, 2, "3", :four]}, 'get', format: :json]
111
+ expected = ["/12345", {:foo => [1, 2, "3", :four]}, 'get', format: :json]
112
+ response = double('Mock KoalaResponse', :body => '', :status => 200)
113
+ expect(Koala).to receive(:make_request).with(*expected).and_return(response)
114
+ @service.api(*args)
115
+ end
116
+
117
+ it "raises an API error if the HTTP response code is greater than or equal to 500" do
118
+ allow(Koala).to receive(:make_request).and_return(Koala::HTTPService::Response.new(500, 'response body', {}))
119
+
120
+ expect { @service.api('anything') }.to raise_exception(Koala::Facebook::APIError)
121
+ end
122
+
123
+ describe "path manipulation" do
124
+ context "leading /" do
125
+ it "adds a leading / to the path if not present" do
126
+ path = "anything"
127
+ expect(Koala).to receive(:make_request).with("/#{path}", anything, anything, anything).and_return(Koala::HTTPService::Response.new(200, 'true', {}))
128
+ @service.api(path)
129
+ end
130
+
131
+ it "doesn't change the path if a leading / is present" do
132
+ path = "/anything"
133
+ expect(Koala).to receive(:make_request).with(path, anything, anything, anything).and_return(Koala::HTTPService::Response.new(200, 'true', {}))
134
+ @service.api(path)
135
+ end
136
+ end
137
+ end
138
+
139
+ describe "with an access token" do
140
+ before(:each) do
141
+ @api = Koala::Facebook::API.new(@token)
142
+ @app_access_token = KoalaTest.app_access_token
143
+ end
144
+
145
+ it_should_behave_like "Koala GraphAPI"
146
+ it_should_behave_like "Koala GraphAPI with an access token"
147
+ it_should_behave_like "Koala GraphAPI with GraphCollection"
148
+ end
149
+
150
+ describe "without an access token" do
151
+ before(:each) do
152
+ @api = Koala::Facebook::API.new
153
+ end
154
+
155
+ # In theory this should behave the same with a GraphCollection, but those tests currently hit
156
+ # an endpoint that now requires a token.
157
+ it_should_behave_like "Koala GraphAPI"
158
+ it_should_behave_like "Koala GraphAPI without an access token"
159
+ end
160
+
161
+ context '#api' do
162
+ let(:access_token) { 'access_token' }
163
+ let(:api) { Koala::Facebook::API.new(access_token) }
164
+ let(:path) { '/path' }
165
+ let(:appsecret) { 'appsecret' }
166
+ let(:token_args) { { 'access_token' => access_token } }
167
+ let(:appsecret_proof_args) { { 'appsecret_proof' => OpenSSL::HMAC.hexdigest(OpenSSL::Digest.new('sha256'), appsecret, access_token) } }
168
+ let(:verb) { 'get' }
169
+ let(:response) { Koala::HTTPService::Response.new(200, '', '') }
170
+
171
+ describe "the appsecret_proof arguments" do
172
+ describe "with an API access token present" do
173
+ describe "and with an appsecret included on API initialization " do
174
+ let(:api) { Koala::Facebook::API.new(access_token, appsecret) }
175
+
176
+ it "will be included by default" do
177
+ expect(Koala).to receive(:make_request).with(path, token_args.merge(appsecret_proof_args), verb, {}).and_return(response)
178
+ api.api(path, {}, verb, :appsecret_proof => true)
179
+ end
180
+ end
181
+
182
+ describe "but without an appsecret included on API initialization" do
183
+ it "will not be included" do
184
+ expect(Koala).to receive(:make_request).with(path, token_args, verb, {}).and_return(response)
185
+ api.api(path, {}, verb, :appsecret_proof => true)
186
+ end
187
+ end
188
+ end
189
+
190
+ describe "but without an API access token present" do
191
+ describe "and with an appsecret included on API initialization " do
192
+ let(:api) { Koala::Facebook::API.new(nil, appsecret) }
193
+
194
+ it "will not be included" do
195
+ expect(Koala).to receive(:make_request).with(path, {}, verb, {}).and_return(response)
196
+ api.api(path, {}, verb, :appsecret_proof => true)
197
+ end
198
+ end
199
+
200
+ describe "but without an appsecret included on API initialization" do
201
+ let(:api) { Koala::Facebook::API.new }
202
+
203
+ it "will not be included" do
204
+ expect(Koala).to receive(:make_request).with(path, {}, verb, {}).and_return(response)
205
+ api.api(path, {}, verb, :appsecret_proof => true)
206
+ end
207
+ end
208
+ end
209
+ end
210
+ end
211
+
212
+ describe "#graph_call" do
213
+ it "passes all arguments to the api method" do
214
+ user = KoalaTest.user1
215
+ args = {}
216
+ verb = 'get'
217
+ opts = {:a => :b}
218
+ expect(@service).to receive(:api).with(user, args, verb, opts).and_return(dummy_response)
219
+ @service.graph_call(user, args, verb, opts)
220
+ end
221
+
222
+ it "throws an APIError if the result hash has an error key" do
223
+ allow(Koala).to receive(:make_request).and_return(Koala::HTTPService::Response.new(500, '{"error": "An error occurred!"}', {}))
224
+ expect { @service.graph_call(KoalaTest.user1, {}) }.to raise_exception(Koala::Facebook::APIError)
225
+ end
226
+
227
+ it "passes the results through GraphCollection.evaluate" do
228
+ allow(@service).to receive(:api).and_return(dummy_response)
229
+ expect(Koala::Facebook::API::GraphCollection).to receive(:evaluate).with(dummy_response, @service)
230
+ @service.graph_call("/me")
231
+ end
232
+
233
+ it "returns the results of GraphCollection.evaluate" do
234
+ expected = {}
235
+ allow(@service).to receive(:api).and_return(dummy_response)
236
+ expect(Koala::Facebook::API::GraphCollection).to receive(:evaluate).and_return(expected)
237
+ expect(@service.graph_call("/me")).to eq(expected)
238
+ end
239
+
240
+ it "returns the post_processing block's results if one is supplied" do
241
+ other_result = [:a, 2, :three]
242
+ block = Proc.new {|r| other_result}
243
+ allow(@service).to receive(:api).and_return(dummy_response)
244
+ expect(@service.graph_call("/me", {}, "get", {}, &block)).to eq(other_result)
245
+ end
246
+
247
+ it "gets the status of a Koala::HTTPService::Response if requested" do
248
+ response = Koala::HTTPService::Response.new(200, '', {})
249
+ allow(Koala).to receive(:make_request).and_return(response)
250
+
251
+ expect(@service.graph_call('anything', {}, 'get', http_component: :status)).to eq(200)
252
+ end
253
+
254
+ it "gets the headers of a Koala::HTTPService::Response if requested" do
255
+ headers = {"a" => 2}
256
+ response = Koala::HTTPService::Response.new(200, '', headers)
257
+ allow(Koala).to receive(:make_request).and_return(response)
258
+
259
+ expect(@service.graph_call('anything', {}, 'get', :http_component => :headers)).to eq(headers)
260
+ end
261
+
262
+ it "returns the entire response if http_component => :response" do
263
+ http_component = :response
264
+ response = Koala::HTTPService::Response.new(200, '', {})
265
+ allow(Koala).to receive(:make_request).and_return(response)
266
+ expect(@service.graph_call('anything', {}, 'get', :http_component => http_component)).to eq(response)
267
+ end
268
+
269
+ it "returns the body of the request as JSON if no http_component is given" do
270
+ result = {"a" => 2}
271
+ response = Koala::HTTPService::Response.new(200, result.to_json, {})
272
+ allow(Koala).to receive(:make_request).and_return(response)
273
+
274
+ expect(@service.graph_call('anything')).to eq(result)
275
+ end
276
+
277
+ it "handles rogue true/false as responses" do
278
+ expect(Koala).to receive(:make_request).and_return(Koala::HTTPService::Response.new(200, 'true', {}))
279
+ expect(@service.graph_call('anything')).to be_truthy
280
+
281
+ expect(Koala).to receive(:make_request).and_return(Koala::HTTPService::Response.new(200, 'false', {}))
282
+ expect(@service.graph_call('anything')).to be_falsey
283
+ end
284
+ end
285
+
286
+ describe "Rate limit hook" do
287
+ it "is called when x-business-use-case-usage header is present" do
288
+ api = Koala::Facebook::API.new('', '', ->(limits) {
289
+ expect(limits["x-business-use-case-usage"]).to eq({"123456789012345"=>[{"type"=>"messenger", "call_count"=>1, "total_cputime"=>1, "total_time"=>1, "estimated_time_to_regain_access"=>0}]})
290
+ })
291
+
292
+ result = {"a" => 2}
293
+ response = Koala::HTTPService::Response.new(200, result.to_json, { "x-business-use-case-usage" => "{\"123456789012345\":[{\"type\":\"messenger\",\"call_count\":1,\"total_cputime\":1,\"total_time\":1,\"estimated_time_to_regain_access\":0}]}" })
294
+ allow(Koala).to receive(:make_request).and_return(response)
295
+
296
+ api.graph_call('anything')
297
+ end
298
+
299
+ it "is called when x-ad-account-usage header is present" do
300
+ api = Koala::Facebook::API.new('', '', ->(limits) {
301
+ expect(limits["x-ad-account-usage"]).to eq({"acc_id_util_pct"=>9.67})
302
+ })
303
+
304
+ result = {"a" => 2}
305
+ response = Koala::HTTPService::Response.new(200, result.to_json, { "x-ad-account-usage" => "{\"acc_id_util_pct\":9.67}" })
306
+ allow(Koala).to receive(:make_request).and_return(response)
307
+
308
+ api.graph_call('anything')
309
+ end
310
+
311
+ it "is called when x-app-usage header is present" do
312
+ api = Koala::Facebook::API.new('', '', ->(limits) {
313
+ expect(limits["x-app-usage"]).to eq({"call_count"=>0, "total_cputime"=>0, "total_time"=>0})
314
+ })
315
+
316
+ result = {"a" => 2}
317
+ response = Koala::HTTPService::Response.new(200, result.to_json, { "x-app-usage" => "{\"call_count\":0,\"total_cputime\":0,\"total_time\":0}" })
318
+ allow(Koala).to receive(:make_request).and_return(response)
319
+
320
+ api.graph_call('anything')
321
+ end
322
+
323
+ it "isn't called if none of the rate limit header is present" do
324
+ rate_limit_hook_called = false
325
+
326
+ api = Koala::Facebook::API.new('', '', ->(limits) {
327
+ rate_limit_hook_called = true
328
+ })
329
+
330
+ result = {"a" => 2}
331
+ response = Koala::HTTPService::Response.new(200, result.to_json, {})
332
+ allow(Koala).to receive(:make_request).and_return(response)
333
+
334
+ api.graph_call('anything')
335
+
336
+ expect(rate_limit_hook_called).to be(false)
337
+ end
338
+
339
+ it "isn't called if no rate limit hook is defined" do
340
+ api = Koala::Facebook::API.new('', '', ->(limits) {
341
+ #noop
342
+ })
343
+
344
+ result = {"a" => 2}
345
+ response = Koala::HTTPService::Response.new(200, result.to_json, { "x-ad-account-usage" => "{\"acc_id_util_pct\"9.67}"})
346
+ allow(Koala).to receive(:make_request).and_return(response)
347
+
348
+ expect(Koala::Utils.logger).to receive(:error).with("JSON::ParserError: expected ':' after object key at line 1 column 19 while parsing x-ad-account-usage = {\"acc_id_util_pct\"9.67}")
349
+ api.graph_call('anything')
350
+ end
351
+
352
+ it "logs an error if the rate limit header can't be properly parsed" do
353
+ api = Koala::Facebook::API.new('', '', nil)
354
+
355
+ result = {"a" => 2}
356
+ response = Koala::HTTPService::Response.new(200, result.to_json, {})
357
+ allow(Koala).to receive(:make_request).and_return(response)
358
+
359
+ api.graph_call('anything')
360
+ end
361
+ end
362
+ end
@@ -0,0 +1,11 @@
1
+ require "spec_helper"
2
+
3
+ RSpec.describe Koala::Configuration do
4
+ let(:config) { Koala::Configuration.new }
5
+
6
+ it "defaults the HTTPService's DEFAULT_SERVERS" do
7
+ Koala::HTTPService::DEFAULT_SERVERS.each_pair do |key, value|
8
+ expect(config.public_send(key)).to eq(value)
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,143 @@
1
+ require 'spec_helper'
2
+
3
+ BUC_USAGE_JSON = "{\"123456789012345\":[{\"type\":\"messenger\",\"call_count\":1,\"total_cputime\":1,\"total_time\":1,\"estimated_time_to_regain_access\":0}]}"
4
+ ADA_USAGE_JSON = "{\"acc_id_util_pct\":9.67}"
5
+ APP_USAGE_JSON = "{\"call_count\":0,\"total_cputime\":0,\"total_time\":0}"
6
+
7
+ describe Koala::Facebook::APIError do
8
+ it "is a Koala::KoalaError" do
9
+ expect(Koala::Facebook::APIError.new(nil, nil)).to be_a(Koala::KoalaError)
10
+ end
11
+
12
+ [:fb_error_type, :fb_error_code, :fb_error_subcode, :fb_error_message, :fb_error_user_msg, :fb_error_user_title, :fb_error_trace_id, :fb_error_rev, :fb_error_debug, :http_status, :response_body].each do |accessor|
13
+ it "has an accessor for #{accessor}" do
14
+ expect(Koala::Facebook::APIError.instance_methods.map(&:to_sym)).to include(accessor)
15
+ expect(Koala::Facebook::APIError.instance_methods.map(&:to_sym)).to include(:"#{accessor}=")
16
+ end
17
+ end
18
+
19
+ it "sets http_status to the provided status" do
20
+ error_response = '{ "error": {"type": "foo", "other_details": "bar"} }'
21
+ expect(Koala::Facebook::APIError.new(400, error_response).response_body).to eq(error_response)
22
+ end
23
+
24
+ it "sets response_body to the provided response body" do
25
+ expect(Koala::Facebook::APIError.new(400, '').http_status).to eq(400)
26
+ end
27
+
28
+ context "with an error_info hash" do
29
+ let(:error) {
30
+ error_info = {
31
+ 'type' => 'type',
32
+ 'message' => 'message',
33
+ 'code' => 1,
34
+ 'error_subcode' => 'subcode',
35
+ 'error_user_msg' => 'error user message',
36
+ 'error_user_title' => 'error user title',
37
+ 'fbtrace_id' => 'fb trace id',
38
+ 'x-fb-trace-id' => 'x-fb trace id',
39
+ 'x-fb-debug' => 'fb debug token',
40
+ 'x-fb-rev' => 'fb revision',
41
+ 'x-business-use-case-usage' => BUC_USAGE_JSON,
42
+ 'x-ad-account-usage' => ADA_USAGE_JSON,
43
+ 'x-app-usage' => APP_USAGE_JSON
44
+ }
45
+ Koala::Facebook::APIError.new(400, '', error_info)
46
+ }
47
+
48
+ {
49
+ :fb_error_type => 'type',
50
+ :fb_error_message => 'message',
51
+ :fb_error_code => 1,
52
+ :fb_error_subcode => 'subcode',
53
+ :fb_error_user_msg => 'error user message',
54
+ :fb_error_user_title => 'error user title',
55
+ :fb_error_trace_id => 'fb trace id',
56
+ :fb_error_debug_trace_id => 'x-fb trace id',
57
+ :fb_error_debug => 'fb debug token',
58
+ :fb_error_rev => 'fb revision',
59
+ :fb_buc_usage => JSON.parse(BUC_USAGE_JSON),
60
+ :fb_ada_usage => JSON.parse(ADA_USAGE_JSON),
61
+ :fb_app_usage => JSON.parse(APP_USAGE_JSON)
62
+ }.each_pair do |accessor, value|
63
+ it "sets #{accessor} to #{value}" do
64
+ expect(error.send(accessor)).to eq(value)
65
+ end
66
+ end
67
+
68
+ it "sets the error message appropriately" do
69
+ expect(error.message).to eq("type: type, code: 1, error_subcode: subcode, message: message, error_user_title: error user title, error_user_msg: error user message, fbtrace_id: fb trace id, x-fb-trace-id: x-fb trace id, x-fb-debug: fb debug token, x-fb-rev: fb revision [HTTP 400]")
70
+ end
71
+ end
72
+
73
+ context "with an error_info string" do
74
+ it "sets the error message \"error_info [HTTP http_status]\"" do
75
+ error_info = "Facebook is down."
76
+ error = Koala::Facebook::APIError.new(400, '', error_info)
77
+ expect(error.message).to eq("Facebook is down. [HTTP 400]")
78
+ end
79
+ end
80
+
81
+ context "with no error_info and a response_body containing error JSON" do
82
+ it "should extract the error info from the response body" do
83
+ response_body = '{ "error": { "type": "type", "message": "message", "code": 1, "error_subcode": "subcode", "error_user_msg": "error user message", "error_user_title": "error user title" } }'
84
+ error = Koala::Facebook::APIError.new(400, response_body)
85
+ {
86
+ :fb_error_type => 'type',
87
+ :fb_error_message => 'message',
88
+ :fb_error_code => 1,
89
+ :fb_error_subcode => 'subcode',
90
+ :fb_error_user_msg => 'error user message',
91
+ :fb_error_user_title => 'error user title',
92
+ :fb_buc_usage => nil,
93
+ :fb_ada_usage => nil,
94
+ :fb_app_usage => nil
95
+ }.each_pair do |accessor, value|
96
+ expect(error.send(accessor)).to eq(value)
97
+ end
98
+ end
99
+ end
100
+
101
+ end
102
+
103
+ describe Koala::KoalaError do
104
+ it "is a StandardError" do
105
+ expect(Koala::KoalaError.new).to be_a(StandardError)
106
+ end
107
+ end
108
+
109
+ describe Koala::Facebook::OAuthSignatureError do
110
+ it "is a Koala::KoalaError" do
111
+ expect(Koala::KoalaError.new).to be_a(Koala::KoalaError)
112
+ end
113
+ end
114
+
115
+ describe Koala::Facebook::BadFacebookResponse do
116
+ it "is a Koala::Facebook::APIError" do
117
+ expect(Koala::Facebook::BadFacebookResponse.new(nil, nil)).to be_a(Koala::Facebook::APIError)
118
+ end
119
+ end
120
+
121
+ describe Koala::Facebook::OAuthTokenRequestError do
122
+ it "is a Koala::Facebook::APIError" do
123
+ expect(Koala::Facebook::OAuthTokenRequestError.new(nil, nil)).to be_a(Koala::Facebook::APIError)
124
+ end
125
+ end
126
+
127
+ describe Koala::Facebook::ServerError do
128
+ it "is a Koala::Facebook::APIError" do
129
+ expect(Koala::Facebook::ServerError.new(nil, nil)).to be_a(Koala::Facebook::APIError)
130
+ end
131
+ end
132
+
133
+ describe Koala::Facebook::ClientError do
134
+ it "is a Koala::Facebook::APIError" do
135
+ expect(Koala::Facebook::ClientError.new(nil, nil)).to be_a(Koala::Facebook::APIError)
136
+ end
137
+ end
138
+
139
+ describe Koala::Facebook::AuthenticationError do
140
+ it "is a Koala::Facebook::ClientError" do
141
+ expect(Koala::Facebook::AuthenticationError.new(nil, nil)).to be_a(Koala::Facebook::ClientError)
142
+ end
143
+ end