koala 2.4.0 → 3.5.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +5 -5
- data/.github/workflows/test.yml +32 -0
- data/Gemfile +5 -3
- data/ISSUE_TEMPLATE +25 -0
- data/PULL_REQUEST_TEMPLATE +11 -0
- data/changelog.md +161 -4
- data/code_of_conduct.md +64 -12
- data/koala.gemspec +5 -1
- data/lib/koala/api/batch_operation.rb +3 -6
- data/lib/koala/api/{graph_api.rb → graph_api_methods.rb} +29 -104
- data/lib/koala/api/graph_batch_api.rb +112 -65
- data/lib/koala/api/graph_collection.rb +19 -12
- data/lib/koala/api/graph_error_checker.rb +4 -3
- data/lib/koala/api.rb +65 -26
- data/lib/koala/configuration.rb +56 -0
- data/lib/koala/errors.rb +22 -2
- data/lib/koala/http_service/request.rb +133 -0
- data/lib/koala/http_service/response.rb +6 -4
- data/lib/koala/http_service/uploadable_io.rb +0 -5
- data/lib/koala/http_service.rb +29 -76
- data/lib/koala/oauth.rb +8 -8
- data/lib/koala/realtime_updates.rb +26 -21
- data/lib/koala/test_users.rb +9 -8
- data/lib/koala/version.rb +1 -1
- data/lib/koala.rb +7 -9
- data/readme.md +83 -109
- data/spec/cases/api_spec.rb +176 -69
- data/spec/cases/configuration_spec.rb +11 -0
- data/spec/cases/error_spec.rb +16 -3
- data/spec/cases/graph_api_batch_spec.rb +75 -44
- data/spec/cases/graph_api_spec.rb +15 -29
- data/spec/cases/graph_collection_spec.rb +47 -34
- data/spec/cases/graph_error_checker_spec.rb +31 -2
- data/spec/cases/http_service/request_spec.rb +250 -0
- data/spec/cases/http_service/response_spec.rb +24 -0
- data/spec/cases/http_service_spec.rb +126 -286
- data/spec/cases/koala_spec.rb +7 -5
- data/spec/cases/oauth_spec.rb +41 -2
- data/spec/cases/realtime_updates_spec.rb +51 -13
- data/spec/cases/test_users_spec.rb +56 -2
- data/spec/cases/uploadable_io_spec.rb +31 -31
- data/spec/fixtures/cat.m4v +0 -0
- data/spec/fixtures/facebook_data.yml +4 -6
- data/spec/fixtures/mock_facebook_responses.yml +41 -78
- data/spec/fixtures/vcr_cassettes/app_test_accounts.yml +97 -0
- data/spec/integration/graph_collection_spec.rb +8 -5
- data/spec/spec_helper.rb +2 -2
- data/spec/support/graph_api_shared_examples.rb +152 -337
- data/spec/support/koala_test.rb +11 -13
- data/spec/support/mock_http_service.rb +11 -14
- data/spec/support/uploadable_io_shared_examples.rb +4 -4
- metadata +47 -48
- data/.autotest +0 -12
- data/.travis.yml +0 -17
- data/Guardfile +0 -6
- data/autotest/discover.rb +0 -1
- data/lib/koala/api/rest_api.rb +0 -135
- data/lib/koala/http_service/multipart_request.rb +0 -41
- data/spec/cases/multipart_request_spec.rb +0 -65
- data/spec/support/rest_api_shared_examples.rb +0 -168
data/readme.md
CHANGED
@@ -1,10 +1,10 @@
|
|
1
|
-
Koala [![Version](https://img.shields.io/gem/v/koala.svg)](https://rubygems.org/gems/koala) [![
|
1
|
+
Koala [![Version](https://img.shields.io/gem/v/koala.svg)](https://rubygems.org/gems/koala) [![Build Status](https://img.shields.io/travis/arsduo/koala.svg)](http://travis-ci.org/arsduo/koala) [![Code Climate](https://img.shields.io/codeclimate/coverage-letter/arsduo/koala.svg)](https://codeclimate.com/github/arsduo/koala) [![Code Coverage](https://img.shields.io/codeclimate/coverage/arsduo/koala.svg)](https://codeclimate.com/github/arsduo/koala)
|
2
2
|
====
|
3
|
-
[Koala](http://github.com/arsduo/koala) is a Facebook library for Ruby, supporting the Graph API (including the batch requests and photo uploads), the
|
3
|
+
[Koala](http://github.com/arsduo/koala) is a Facebook library for Ruby, supporting the Graph API (including the batch requests and photo uploads), the Marketing API, the Atlas API, realtime updates, test users, and OAuth validation. We wrote Koala with four goals:
|
4
4
|
|
5
5
|
* Lightweight: Koala should be as light and simple as Facebook’s own libraries, providing API accessors and returning simple JSON.
|
6
6
|
* Fast: Koala should, out of the box, be quick. Out of the box, we use Facebook's faster read-only servers when possible and if available, the Typhoeus gem to make snappy Facebook requests. Of course, that brings us to our next topic:
|
7
|
-
* Flexible: Koala should be useful to everyone, regardless of their current configuration. We support
|
7
|
+
* Flexible: Koala should be useful to everyone, regardless of their current configuration. We support all currently-supported Ruby versions (MRI 2.1-2.4) and Koala should work on JRuby and Rubinius.
|
8
8
|
* Tested: Koala should have complete test coverage, so you can rely on it. Our test coverage is complete and can be run against either mocked responses or the live Facebook servers; we're also on [Travis CI](http://travis-ci.org/arsduo/koala/).
|
9
9
|
|
10
10
|
**Found a bug? Interested in contributing?** Check out the Maintenance section below!
|
@@ -12,9 +12,12 @@ Koala [![Version](https://img.shields.io/gem/v/koala.svg)](https://rubygems.org/
|
|
12
12
|
Installation
|
13
13
|
------------
|
14
14
|
|
15
|
+
**Koala 3.0 is out! There should be no significant changes** for most users. If you encounter any
|
16
|
+
problems, please file an issue and I'll take a look.
|
17
|
+
|
15
18
|
In Bundler:
|
16
19
|
```ruby
|
17
|
-
gem "koala"
|
20
|
+
gem "koala"
|
18
21
|
```
|
19
22
|
|
20
23
|
Otherwise:
|
@@ -22,23 +25,41 @@ Otherwise:
|
|
22
25
|
[sudo|rvm] gem install koala
|
23
26
|
```
|
24
27
|
|
25
|
-
|
26
|
-
|
28
|
+
Configuration
|
29
|
+
-------------
|
30
|
+
|
31
|
+
Most applications will only use one application configuration. Rather than having to provide that
|
32
|
+
value every time, you can configure Koala to use global settings:
|
33
|
+
|
34
|
+
```ruby
|
35
|
+
# In Rails, you could put this in config/initializers/koala.rb
|
36
|
+
Koala.configure do |config|
|
37
|
+
config.access_token = MY_TOKEN
|
38
|
+
config.app_access_token = MY_APP_ACCESS_TOKEN
|
39
|
+
config.app_id = MY_APP_ID
|
40
|
+
config.app_secret = MY_APP_SECRET
|
41
|
+
# See Koala::Configuration for more options, including details on how to send requests through
|
42
|
+
# your own proxy servers.
|
43
|
+
end
|
44
|
+
```
|
27
45
|
|
28
|
-
|
29
|
-
|
30
|
-
details.
|
46
|
+
**Note**: this is not currently threadsafe. (PRs welcome as long as they support both threaded and
|
47
|
+
non-threaded configuration.)
|
31
48
|
|
32
49
|
Graph API
|
33
50
|
---------
|
34
51
|
|
35
|
-
The Graph API is the
|
36
|
-
|
37
|
-
|
52
|
+
The Graph API is the interface to Facebook's data. Using it with Koala is quite straightforward.
|
53
|
+
First, you'll need an access token, which you can get through Facebook's [Graph API
|
54
|
+
Explorer](https://developers.facebook.com/tools/explorer) (click on 'Get Access Token').
|
55
|
+
|
38
56
|
Then, go exploring:
|
39
57
|
|
40
58
|
```ruby
|
41
|
-
|
59
|
+
require 'koala'
|
60
|
+
|
61
|
+
# access_token and other values aren't required if you set the defaults as described above
|
62
|
+
@graph = Koala::Facebook::API.new(access_token)
|
42
63
|
|
43
64
|
profile = @graph.get_object("me")
|
44
65
|
friends = @graph.get_connections("me", "friends")
|
@@ -54,14 +75,14 @@ friends = @graph.get_connections("me", "friends")
|
|
54
75
|
# For extra security (recommended), you can provide an appsecret parameter,
|
55
76
|
# tying your access tokens to your app secret.
|
56
77
|
# (See https://developers.facebook.com/docs/reference/api/securing-graph-api/
|
57
|
-
|
78
|
+
|
79
|
+
# You may need to turn on 'Require proof on all calls' in the advanced section
|
58
80
|
# of your app's settings when doing this.
|
59
|
-
@graph = Koala::Facebook::API.new(
|
81
|
+
@graph = Koala::Facebook::API.new(access_token, app_secret)
|
60
82
|
|
61
83
|
# Facebook is now versioning their API. # If you don't specify a version, Facebook
|
62
|
-
# will default to the oldest version your app is allowed to use.
|
63
|
-
#
|
64
|
-
# https://developers.facebook.com/docs/apps/versions for more information.
|
84
|
+
# will default to the oldest version your app is allowed to use.
|
85
|
+
# See https://developers.facebook.com/docs/apps/versions for more information.
|
65
86
|
#
|
66
87
|
# You can specify version either globally:
|
67
88
|
Koala.config.api_version = "v2.0"
|
@@ -113,85 +134,20 @@ the results apart from a long list of array entries:
|
|
113
134
|
|
114
135
|
Check out the wiki for more details and examples.
|
115
136
|
|
116
|
-
|
117
|
-
------------
|
118
|
-
|
119
|
-
Where the Graph API and the old REST API overlap, you should choose the Graph API. Unfortunately, that overlap is far from complete, and there are many important API calls that can't yet be done via the Graph.
|
120
|
-
|
121
|
-
Fortunately, Koala supports the REST API using the very same interface; to use this, instantiate an API:
|
122
|
-
```ruby
|
123
|
-
@rest = Koala::Facebook::API.new(oauth_access_token)
|
124
|
-
|
125
|
-
@rest.fql_query(my_fql_query) # convenience method
|
126
|
-
@rest.fql_multiquery(fql_query_hash) # convenience method
|
127
|
-
@rest.rest_call("stream.publish", arguments_hash) # generic version
|
128
|
-
```
|
129
|
-
|
130
|
-
Of course, you can use the Graph API methods on the same object -- the power of two APIs right in the palm of your hand.
|
131
|
-
```ruby
|
132
|
-
@api = Koala::Facebook::API.new(oauth_access_token)
|
133
|
-
fql = @api.fql_query(my_fql_query)
|
134
|
-
@api.put_wall_post(process_result(fql))
|
135
|
-
```
|
136
|
-
|
137
|
-
Configuration
|
138
|
-
-------------
|
139
|
-
|
140
|
-
You can change the host that koala makes requests to (point to a mock server, apigee, runscope etc..)
|
141
|
-
```ruby
|
142
|
-
# config/initializers/koala.rb
|
143
|
-
require 'koala'
|
144
|
-
|
145
|
-
Koala.configure do |config|
|
146
|
-
config.graph_server = 'my-graph-mock.mysite.com'
|
147
|
-
# other common options are `rest_server` and `dialog_host`
|
148
|
-
# see lib/koala/http_service.rb
|
149
|
-
end
|
150
|
-
```
|
151
|
-
|
152
|
-
Of course the defaults are the facebook endpoints and you can additionally configure the beta
|
153
|
-
tier and video upload matching and replacement strings.
|
154
|
-
|
155
|
-
OAuth
|
137
|
+
App Access Tokens
|
156
138
|
-----
|
157
139
|
|
158
|
-
You
|
140
|
+
You get your application's own access token, which can be used without a user session for subscriptions and certain other requests:
|
159
141
|
```ruby
|
160
142
|
@oauth = Koala::Facebook::OAuth.new(app_id, app_secret, callback_url)
|
161
|
-
```
|
162
|
-
|
163
|
-
If your application uses Koala and the Facebook [JavaScript SDK](http://github.com/facebook/facebook-js-sdk) (formerly Facebook Connect), you can use the OAuth class to parse the cookies:
|
164
|
-
```ruby
|
165
|
-
# parses and returns a hash including the token and the user id
|
166
|
-
# NOTE: this method can only be called once per session, as the OAuth code
|
167
|
-
# Facebook supplies can only be redeemed once. Your application must handle
|
168
|
-
# cross-request storage of this information; you can no longer call this method
|
169
|
-
# multiple times.
|
170
|
-
@oauth.get_user_info_from_cookies(cookies)
|
171
|
-
```
|
172
|
-
And if you have to use the more complicated [redirect-based OAuth process](http://developers.facebook.com/docs/authentication/), Koala helps out there, too:
|
173
|
-
|
174
|
-
```ruby
|
175
|
-
# generate authenticating URL
|
176
|
-
@oauth.url_for_oauth_code
|
177
|
-
# fetch the access token once you have the code
|
178
|
-
@oauth.get_access_token(code)
|
179
|
-
```
|
180
|
-
|
181
|
-
You can also get your application's own access token, which can be used without a user session for subscriptions and certain other requests:
|
182
|
-
```ruby
|
183
143
|
@oauth.get_app_access_token
|
184
144
|
```
|
185
145
|
For those building apps on Facebook, parsing signed requests is simple:
|
186
146
|
```ruby
|
187
147
|
@oauth.parse_signed_request(signed_request_string)
|
188
148
|
```
|
189
|
-
|
190
|
-
|
191
|
-
@oauth.get_token_from_session_key(session_key)
|
192
|
-
@oauth.get_tokens_from_session_keys(array_of_session_keys)
|
193
|
-
```
|
194
|
-
That's it! It's pretty simple once you get the hang of it. If you're new to OAuth, though, check out the wiki and the OAuth Playground example site (see below).
|
149
|
+
|
150
|
+
The OAuth class has additional methods that may occasionally be useful.
|
195
151
|
|
196
152
|
Real-time Updates
|
197
153
|
-----------------
|
@@ -200,6 +156,7 @@ Sometimes, reaching out to Facebook is a pain -- let it reach out to you instead
|
|
200
156
|
|
201
157
|
Koala makes it easy to interact with your applications using the RealtimeUpdates class:
|
202
158
|
```ruby
|
159
|
+
# This class also supports the defaults as described above
|
203
160
|
@updates = Koala::Facebook::RealtimeUpdates.new(app_id: app_id, secret: secret)
|
204
161
|
```
|
205
162
|
You can do just about anything with your real-time update subscriptions using the RealtimeUpdates class:
|
@@ -220,17 +177,50 @@ Koala::Facebook::RealtimeUpdates.meet_challenge(params, your_verify_token)
|
|
220
177
|
```
|
221
178
|
For more information about meet_challenge and the RealtimeUpdates class, check out the Real-Time Updates page on the wiki.
|
222
179
|
|
180
|
+
Rate limits
|
181
|
+
-----------
|
182
|
+
|
183
|
+
We support Facebook rate limit informations as defined here: [https://developers.facebook.com/docs/graph-api/overview/rate-limiting/](https://developers.facebook.com/docs/graph-api/overview/rate-limiting/)
|
184
|
+
|
185
|
+
The information is available either via the `Facebook::APIError`:
|
186
|
+
|
187
|
+
```ruby
|
188
|
+
error.fb_buc_usage
|
189
|
+
error.fb_ada_usage
|
190
|
+
error.fb_app_usage
|
191
|
+
```
|
192
|
+
|
193
|
+
Or with the rate_limit_hook:
|
194
|
+
|
195
|
+
```ruby
|
196
|
+
# App level configuration
|
197
|
+
|
198
|
+
Koala.configure do |config|
|
199
|
+
config.rate_limit_hook = ->(limits) {
|
200
|
+
limits["x-app-usage"] # {"call_count"=>0, "total_cputime"=>0, "total_time"=>0}
|
201
|
+
limits["x-ad-account-usage"] # {"acc_id_util_pct"=>9.67}
|
202
|
+
limits["x-business-use-case-usage"] # {"123456789012345"=>[{"type"=>"messenger", "call_count"=>1, "total_cputime"=>1, "total_time"=>1, "estimated_time_to_regain_access"=>0}]}
|
203
|
+
}
|
204
|
+
end
|
205
|
+
|
206
|
+
# Per API configuration
|
207
|
+
|
208
|
+
Koala::Facebook::API.new('', '', ->(limits) {})
|
209
|
+
```
|
210
|
+
|
223
211
|
Test Users
|
224
212
|
----------
|
225
213
|
|
226
|
-
We also support the test users API, allowing you to conjure up fake users and command them to do your bidding using the Graph
|
214
|
+
We also support the test users API, allowing you to conjure up fake users and command them to do your bidding using the Graph API:
|
227
215
|
```ruby
|
216
|
+
# This class also supports the defaults as described above
|
228
217
|
@test_users = Koala::Facebook::TestUsers.new(app_id: id, secret: secret)
|
229
218
|
user = @test_users.create(is_app_installed, desired_permissions)
|
230
219
|
user_graph_api = Koala::Facebook::API.new(user["access_token"])
|
231
220
|
# or, if you want to make a whole community:
|
232
221
|
@test_users.create_network(network_size, is_app_installed, common_permissions)
|
233
222
|
```
|
223
|
+
|
234
224
|
Talking to Facebook
|
235
225
|
-------------------
|
236
226
|
|
@@ -253,14 +243,6 @@ Some resources to help you as you play with Koala and the Graph API:
|
|
253
243
|
* Complete Koala documentation <a href="https://github.com/arsduo/koala/wiki">on the wiki</a>
|
254
244
|
* Facebook's <a href="http://facebook.stackoverflow.com/">Stack Overflow site</a> is a stupendous place to ask questions, filled with people who will help you figure out what's up with the Facebook API.
|
255
245
|
* Facebook's <a href="http://developers.facebook.com/tools/explorer/">Graph API Explorer</a>, where you can play with the Graph API in your browser
|
256
|
-
* The Koala-powered <a href="http://oauth.twoalex.com" target="_blank">OAuth Playground</a>, where you can easily generate OAuth access tokens and any other data needed to test out the APIs or OAuth
|
257
|
-
* Follow Koala on <a href="http://www.facebook.com/pages/Koala/315368291823667">Facebook</a> and <a href="https://twitter.com/#!/koala_fb">Twitter</a> for SDK updates and occasional news about Facebook API changes.
|
258
|
-
|
259
|
-
*Note*: I use the Koala issues tracker on Github to triage and address issues
|
260
|
-
with the gem itself; if you need help using the Facebook API, the above
|
261
|
-
resources will be far more effective. Depending on how much time I have, Github
|
262
|
-
issues filed about how to use the Facebook API may be closed with a reference
|
263
|
-
to the Facebook Stack Overflow page.
|
264
246
|
|
265
247
|
Testing
|
266
248
|
-------
|
@@ -278,26 +260,18 @@ LIVE=true bundle exec rake spec
|
|
278
260
|
# you can also test against Facebook's beta tier
|
279
261
|
LIVE=true BETA=true bundle exec rake spec
|
280
262
|
```
|
263
|
+
|
281
264
|
By default, the live tests are run against test users, so you can run them as frequently as you want. If you want to run them against a real user, however, you can fill in the OAuth token, code, and access\_token values in spec/fixtures/facebook_data.yml. See the wiki for more details.
|
282
265
|
|
283
266
|
Maintenance
|
284
267
|
-----------
|
285
268
|
|
286
269
|
_Pull requests_: Koala exists as it does thanks to the amazing support and work of community members of all
|
287
|
-
backgrounds and levels of experience. Pull requests are very welcome!
|
288
|
-
|
270
|
+
backgrounds and levels of experience. Pull requests are very welcome!
|
271
|
+
|
272
|
+
_Issues_: If you have any questions about the gem, found an issue in the Ruby code or
|
273
|
+
documentation, or have another question that isn't right for StackOverflow, just open an issue and fill out the template.
|
289
274
|
|
290
275
|
Please note that this project is released with a Contributor Code of Conduct. By participating in
|
291
276
|
this project you agree to abide by its terms. See
|
292
277
|
[code_of_conduct.md](https://github.com/arsduo/koala/blob/master/code_of_conduct.md) for more information.
|
293
|
-
|
294
|
-
_Schedule_: In order to keep Koala moving forward on a regular and predictable schedule, I will
|
295
|
-
address issues and pull requests at least three times a year: late July/early August, late
|
296
|
-
December/early January, and late March/early April. I may respond to issues in between maintenance
|
297
|
-
periods, but it'll depend on other life/work goings-on.
|
298
|
-
|
299
|
-
Breaking/new Facebook changes and other urgent issues obviously will get addressed much more
|
300
|
-
quickly. (We've never had a security issue, but obviously that would be priority 0.)
|
301
|
-
|
302
|
-
Have questions? Found a breaking bug or urgent issue? [Tweet at me](http://twitter.com/arsduo) --
|
303
|
-
I'm always happy to respond.
|
data/spec/cases/api_spec.rb
CHANGED
@@ -1,9 +1,30 @@
|
|
1
1
|
require 'spec_helper'
|
2
2
|
|
3
3
|
describe "Koala::Facebook::API" do
|
4
|
-
before
|
4
|
+
before :each do
|
5
5
|
@service = Koala::Facebook::API.new
|
6
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
|
7
28
|
|
8
29
|
it "doesn't include an access token if none was given" do
|
9
30
|
expect(Koala).to receive(:make_request).with(
|
@@ -45,36 +66,6 @@ describe "Koala::Facebook::API" do
|
|
45
66
|
service.api('anything', args)
|
46
67
|
end
|
47
68
|
|
48
|
-
it "has an attr_reader for access token" do
|
49
|
-
token = 'adfadf'
|
50
|
-
service = Koala::Facebook::API.new token
|
51
|
-
expect(service.access_token).to eq(token)
|
52
|
-
end
|
53
|
-
|
54
|
-
it "has an attr_reader for app_secret" do
|
55
|
-
secret = double
|
56
|
-
service = Koala::Facebook::API.new(@token, secret)
|
57
|
-
expect(service.app_secret).to eq(secret)
|
58
|
-
end
|
59
|
-
|
60
|
-
it "gets the attribute of a Koala::HTTPService::Response given by the http_component parameter" do
|
61
|
-
http_component = :method_name
|
62
|
-
|
63
|
-
response = double('Mock KoalaResponse', :body => '', :status => 200)
|
64
|
-
result = double("result")
|
65
|
-
allow(response).to receive(http_component).and_return(result)
|
66
|
-
allow(Koala).to receive(:make_request).and_return(response)
|
67
|
-
|
68
|
-
expect(@service.api('anything', {}, 'get', :http_component => http_component)).to eq(result)
|
69
|
-
end
|
70
|
-
|
71
|
-
it "returns the entire response if http_component => :response" do
|
72
|
-
http_component = :response
|
73
|
-
response = double('Mock KoalaResponse', :body => '', :status => 200)
|
74
|
-
allow(Koala).to receive(:make_request).and_return(response)
|
75
|
-
expect(@service.api('anything', {}, 'get', :http_component => http_component)).to eq(response)
|
76
|
-
end
|
77
|
-
|
78
69
|
it "turns arrays of non-enumerables into comma-separated arguments by default" do
|
79
70
|
args = [12345, {:foo => [1, 2, "3", :four]}]
|
80
71
|
expected = ["/12345", {:foo => "1,2,3,four"}, "get", {}]
|
@@ -123,43 +114,12 @@ describe "Koala::Facebook::API" do
|
|
123
114
|
@service.api(*args)
|
124
115
|
end
|
125
116
|
|
126
|
-
it "returns the body of the request as JSON if no http_component is given" do
|
127
|
-
response = double('response', :body => 'body', :status => 200)
|
128
|
-
allow(Koala).to receive(:make_request).and_return(response)
|
129
|
-
|
130
|
-
json_body = double('JSON body')
|
131
|
-
allow(MultiJson).to receive(:load).and_return([json_body])
|
132
|
-
|
133
|
-
expect(@service.api('anything')).to eq(json_body)
|
134
|
-
end
|
135
|
-
|
136
|
-
it "executes an error checking block if provided" do
|
137
|
-
response = Koala::HTTPService::Response.new(200, '{}', {})
|
138
|
-
allow(Koala).to receive(:make_request).and_return(response)
|
139
|
-
|
140
|
-
yield_test = double('Yield Tester')
|
141
|
-
expect(yield_test).to receive(:pass)
|
142
|
-
|
143
|
-
@service.api('anything', {}, "get") do |arg|
|
144
|
-
yield_test.pass
|
145
|
-
expect(arg).to eq(response)
|
146
|
-
end
|
147
|
-
end
|
148
|
-
|
149
117
|
it "raises an API error if the HTTP response code is greater than or equal to 500" do
|
150
118
|
allow(Koala).to receive(:make_request).and_return(Koala::HTTPService::Response.new(500, 'response body', {}))
|
151
119
|
|
152
120
|
expect { @service.api('anything') }.to raise_exception(Koala::Facebook::APIError)
|
153
121
|
end
|
154
122
|
|
155
|
-
it "handles rogue true/false as responses" do
|
156
|
-
expect(Koala).to receive(:make_request).and_return(Koala::HTTPService::Response.new(200, 'true', {}))
|
157
|
-
expect(@service.api('anything')).to be_truthy
|
158
|
-
|
159
|
-
expect(Koala).to receive(:make_request).and_return(Koala::HTTPService::Response.new(200, 'false', {}))
|
160
|
-
expect(@service.api('anything')).to be_falsey
|
161
|
-
end
|
162
|
-
|
163
123
|
describe "path manipulation" do
|
164
124
|
context "leading /" do
|
165
125
|
it "adds a leading / to the path if not present" do
|
@@ -179,11 +139,9 @@ describe "Koala::Facebook::API" do
|
|
179
139
|
describe "with an access token" do
|
180
140
|
before(:each) do
|
181
141
|
@api = Koala::Facebook::API.new(@token)
|
142
|
+
@app_access_token = KoalaTest.app_access_token
|
182
143
|
end
|
183
144
|
|
184
|
-
it_should_behave_like "Koala RestAPI"
|
185
|
-
it_should_behave_like "Koala RestAPI with an access token"
|
186
|
-
|
187
145
|
it_should_behave_like "Koala GraphAPI"
|
188
146
|
it_should_behave_like "Koala GraphAPI with an access token"
|
189
147
|
it_should_behave_like "Koala GraphAPI with GraphCollection"
|
@@ -194,12 +152,10 @@ describe "Koala::Facebook::API" do
|
|
194
152
|
@api = Koala::Facebook::API.new
|
195
153
|
end
|
196
154
|
|
197
|
-
|
198
|
-
|
199
|
-
|
155
|
+
# In theory this should behave the same with a GraphCollection, but those tests currently hit
|
156
|
+
# an endpoint that now requires a token.
|
200
157
|
it_should_behave_like "Koala GraphAPI"
|
201
158
|
it_should_behave_like "Koala GraphAPI without an access token"
|
202
|
-
it_should_behave_like "Koala GraphAPI with GraphCollection"
|
203
159
|
end
|
204
160
|
|
205
161
|
context '#api' do
|
@@ -252,4 +208,155 @@ describe "Koala::Facebook::API" do
|
|
252
208
|
end
|
253
209
|
end
|
254
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:.*unexpected token at '{"acc_id_util_pct"9.67}' 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
|
255
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
|
data/spec/cases/error_spec.rb
CHANGED
@@ -1,5 +1,9 @@
|
|
1
1
|
require 'spec_helper'
|
2
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
|
+
|
3
7
|
describe Koala::Facebook::APIError do
|
4
8
|
it "is a Koala::KoalaError" do
|
5
9
|
expect(Koala::Facebook::APIError.new(nil, nil)).to be_a(Koala::KoalaError)
|
@@ -32,7 +36,10 @@ describe Koala::Facebook::APIError do
|
|
32
36
|
'error_user_title' => 'error user title',
|
33
37
|
'x-fb-trace-id' => 'fb trace id',
|
34
38
|
'x-fb-debug' => 'fb debug token',
|
35
|
-
'x-fb-rev' => 'fb revision'
|
39
|
+
'x-fb-rev' => 'fb revision',
|
40
|
+
'x-business-use-case-usage' => BUC_USAGE_JSON,
|
41
|
+
'x-ad-account-usage' => ADA_USAGE_JSON,
|
42
|
+
'x-app-usage' => APP_USAGE_JSON
|
36
43
|
}
|
37
44
|
Koala::Facebook::APIError.new(400, '', error_info)
|
38
45
|
}
|
@@ -46,7 +53,10 @@ describe Koala::Facebook::APIError do
|
|
46
53
|
:fb_error_user_title => 'error user title',
|
47
54
|
:fb_error_trace_id => 'fb trace id',
|
48
55
|
:fb_error_debug => 'fb debug token',
|
49
|
-
:fb_error_rev => 'fb revision'
|
56
|
+
:fb_error_rev => 'fb revision',
|
57
|
+
:fb_buc_usage => JSON.parse(BUC_USAGE_JSON),
|
58
|
+
:fb_ada_usage => JSON.parse(ADA_USAGE_JSON),
|
59
|
+
:fb_app_usage => JSON.parse(APP_USAGE_JSON)
|
50
60
|
}.each_pair do |accessor, value|
|
51
61
|
it "sets #{accessor} to #{value}" do
|
52
62
|
expect(error.send(accessor)).to eq(value)
|
@@ -76,7 +86,10 @@ describe Koala::Facebook::APIError do
|
|
76
86
|
:fb_error_code => 1,
|
77
87
|
:fb_error_subcode => 'subcode',
|
78
88
|
:fb_error_user_msg => 'error user message',
|
79
|
-
:fb_error_user_title => 'error user title'
|
89
|
+
:fb_error_user_title => 'error user title',
|
90
|
+
:fb_buc_usage => nil,
|
91
|
+
:fb_ada_usage => nil,
|
92
|
+
:fb_app_usage => nil
|
80
93
|
}.each_pair do |accessor, value|
|
81
94
|
expect(error.send(accessor)).to eq(value)
|
82
95
|
end
|