koala 1.2.0 → 1.3.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.
- data/.gitignore +3 -1
- data/.rspec +1 -0
- data/.travis.yml +4 -0
- data/.yardopts +3 -0
- data/CHANGELOG +43 -0
- data/Gemfile +14 -0
- data/Guardfile +6 -0
- data/koala.gemspec +4 -4
- data/lib/koala/api/batch_operation.rb +83 -0
- data/lib/koala/api/graph_api.rb +476 -0
- data/lib/koala/{graph_batch_api.rb → api/graph_batch_api.rb} +22 -17
- data/lib/koala/api/graph_collection.rb +107 -0
- data/lib/koala/api/legacy.rb +26 -0
- data/lib/koala/{rest_api.rb → api/rest_api.rb} +36 -10
- data/lib/koala/api.rb +93 -0
- data/lib/koala/http_service/multipart_request.rb +41 -0
- data/lib/koala/http_service/response.rb +18 -0
- data/lib/koala/http_service/uploadable_io.rb +187 -0
- data/lib/koala/http_service.rb +73 -23
- data/lib/koala/oauth.rb +173 -36
- data/lib/koala/realtime_updates.rb +89 -51
- data/lib/koala/test_users.rb +122 -32
- data/lib/koala/utils.rb +11 -4
- data/lib/koala/version.rb +1 -1
- data/lib/koala.rb +16 -95
- data/readme.md +30 -13
- data/spec/cases/api_spec.rb +28 -21
- data/spec/cases/error_spec.rb +10 -0
- data/spec/cases/graph_api_batch_spec.rb +100 -58
- data/spec/cases/graph_collection_spec.rb +23 -7
- data/spec/cases/http_service_spec.rb +14 -34
- data/spec/cases/koala_spec.rb +22 -4
- data/spec/cases/legacy_spec.rb +115 -0
- data/spec/cases/multipart_request_spec.rb +66 -0
- data/spec/cases/oauth_spec.rb +232 -108
- data/spec/cases/realtime_updates_spec.rb +154 -47
- data/spec/cases/test_users_spec.rb +276 -217
- data/spec/cases/uploadable_io_spec.rb +1 -1
- data/spec/cases/utils_spec.rb +29 -5
- data/spec/fixtures/mock_facebook_responses.yml +50 -26
- data/spec/spec_helper.rb +3 -0
- data/spec/support/custom_matchers.rb +28 -0
- data/spec/support/graph_api_shared_examples.rb +274 -70
- data/spec/support/koala_test.rb +27 -16
- data/spec/support/mock_http_service.rb +2 -2
- data/spec/support/rest_api_shared_examples.rb +46 -162
- metadata +33 -25
- data/lib/koala/batch_operation.rb +0 -74
- data/lib/koala/graph_api.rb +0 -270
- data/lib/koala/graph_collection.rb +0 -59
- data/lib/koala/uploadable_io.rb +0 -181
- data/spec/cases/graph_and_rest_api_spec.rb +0 -22
- data/spec/cases/graph_api_spec.rb +0 -22
- data/spec/cases/rest_api_spec.rb +0 -41
data/spec/cases/oauth_spec.rb
CHANGED
|
@@ -29,26 +29,27 @@ describe "Koala::Facebook::OAuth" do
|
|
|
29
29
|
@time.stub!(:to_i).and_return(1273363199)
|
|
30
30
|
end
|
|
31
31
|
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
32
|
+
describe ".new" do
|
|
33
|
+
it "properly initializes" do
|
|
34
|
+
@oauth.should
|
|
35
|
+
end
|
|
36
36
|
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
37
|
+
it "properly sets attributes" do
|
|
38
|
+
(@oauth.app_id == @app_id &&
|
|
39
|
+
@oauth.app_secret == @secret &&
|
|
40
|
+
@oauth.oauth_callback_url == @callback_url).should be_true
|
|
41
|
+
end
|
|
42
42
|
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
43
|
+
it "properly initializes without a callback_url" do
|
|
44
|
+
@oauth = Koala::Facebook::OAuth.new(@app_id, @secret)
|
|
45
|
+
end
|
|
46
46
|
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
47
|
+
it "properly sets attributes without a callback URL" do
|
|
48
|
+
@oauth = Koala::Facebook::OAuth.new(@app_id, @secret)
|
|
49
|
+
(@oauth.app_id == @app_id &&
|
|
50
|
+
@oauth.app_secret == @secret &&
|
|
51
|
+
@oauth.oauth_callback_url == nil).should be_true
|
|
52
|
+
end
|
|
52
53
|
end
|
|
53
54
|
|
|
54
55
|
describe "for cookie parsing" do
|
|
@@ -103,13 +104,29 @@ describe "Koala::Facebook::OAuth" do
|
|
|
103
104
|
@oauth.get_user_info_from_cookies(@cookie)["access_token"].should == @token
|
|
104
105
|
end
|
|
105
106
|
|
|
106
|
-
it "returns nil if the call to FB
|
|
107
|
+
it "returns nil if the call to FB returns no data" do
|
|
107
108
|
@oauth.stub(:get_access_token_info).and_return(nil)
|
|
108
109
|
@oauth.get_user_info_from_cookies(@cookie).should be_nil
|
|
109
110
|
end
|
|
111
|
+
|
|
112
|
+
it "returns nil if the call to FB returns an expired code error" do
|
|
113
|
+
@oauth.stub(:get_access_token_info).and_raise(Koala::Facebook::APIError.new(
|
|
114
|
+
"type" => "OAuthException",
|
|
115
|
+
"message" => "Code was invalid or expired. Session has expired at unix time 1324044000. The current unix time is 1324300957."
|
|
116
|
+
))
|
|
117
|
+
@oauth.get_user_info_from_cookies(@cookie).should be_nil
|
|
118
|
+
end
|
|
119
|
+
|
|
120
|
+
it "raises the error if the call to FB returns a different error" do
|
|
121
|
+
@oauth.stub(:get_access_token_info).and_raise(Koala::Facebook::APIError.new(
|
|
122
|
+
"type" => "OtherError",
|
|
123
|
+
"message" => "A Facebook Error"
|
|
124
|
+
))
|
|
125
|
+
expect { @oauth.get_user_info_from_cookies(@cookie) }.to raise_exception(Koala::Facebook::APIError)
|
|
126
|
+
end
|
|
110
127
|
end
|
|
111
128
|
|
|
112
|
-
it "
|
|
129
|
+
it "doesn't parse invalid cookies" do
|
|
113
130
|
# make an invalid string by replacing some values
|
|
114
131
|
bad_cookie_hash = @cookie.inject({}) { |hash, value| hash[value[0]] = value[1].gsub(/[0-9]/, "3") }
|
|
115
132
|
result = @oauth.get_user_info_from_cookies(bad_cookie_hash)
|
|
@@ -118,37 +135,37 @@ describe "Koala::Facebook::OAuth" do
|
|
|
118
135
|
end
|
|
119
136
|
|
|
120
137
|
context "for unsigned cookies" do
|
|
121
|
-
it "
|
|
138
|
+
it "properly parses valid cookies" do
|
|
122
139
|
result = @oauth.get_user_info_from_cookies(KoalaTest.oauth_test_data["valid_cookies"])
|
|
123
140
|
result.should be_a(Hash)
|
|
124
141
|
end
|
|
125
142
|
|
|
126
|
-
it "
|
|
143
|
+
it "returns all the cookie components from valid cookie string" do
|
|
127
144
|
cookie_data = KoalaTest.oauth_test_data["valid_cookies"]
|
|
128
145
|
parsing_results = @oauth.get_user_info_from_cookies(cookie_data)
|
|
129
146
|
number_of_components = cookie_data["fbs_#{@app_id.to_s}"].scan(/\=/).length
|
|
130
147
|
parsing_results.length.should == number_of_components
|
|
131
148
|
end
|
|
132
149
|
|
|
133
|
-
it "
|
|
150
|
+
it "properly parses valid offline access cookies (e.g. no expiration)" do
|
|
134
151
|
result = @oauth.get_user_info_from_cookies(KoalaTest.oauth_test_data["offline_access_cookies"])
|
|
135
152
|
result["uid"].should
|
|
136
153
|
end
|
|
137
154
|
|
|
138
|
-
it "
|
|
155
|
+
it "returns all the cookie components from offline access cookies" do
|
|
139
156
|
cookie_data = KoalaTest.oauth_test_data["offline_access_cookies"]
|
|
140
157
|
parsing_results = @oauth.get_user_info_from_cookies(cookie_data)
|
|
141
158
|
number_of_components = cookie_data["fbs_#{@app_id.to_s}"].scan(/\=/).length
|
|
142
159
|
parsing_results.length.should == number_of_components
|
|
143
160
|
end
|
|
144
161
|
|
|
145
|
-
it "
|
|
162
|
+
it "doesn't parse expired cookies" do
|
|
146
163
|
new_time = @time.to_i * 2
|
|
147
164
|
@time.stub(:to_i).and_return(new_time)
|
|
148
165
|
@oauth.get_user_info_from_cookies(KoalaTest.oauth_test_data["valid_cookies"]).should be_nil
|
|
149
166
|
end
|
|
150
167
|
|
|
151
|
-
it "
|
|
168
|
+
it "doesn't parse invalid cookies" do
|
|
152
169
|
# make an invalid string by replacing some values
|
|
153
170
|
bad_cookie_hash = KoalaTest.oauth_test_data["valid_cookies"].inject({}) { |hash, value| hash[value[0]] = value[1].gsub(/[0-9]/, "3") }
|
|
154
171
|
result = @oauth.get_user_info_from_cookies(bad_cookie_hash)
|
|
@@ -158,132 +175,233 @@ describe "Koala::Facebook::OAuth" do
|
|
|
158
175
|
end
|
|
159
176
|
|
|
160
177
|
describe "get_user_from_cookies" do
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
178
|
+
describe "for signed cookies" do
|
|
179
|
+
before :each do
|
|
180
|
+
# we don't actually want to make requests to Facebook to redeem the code
|
|
181
|
+
@cookie = KoalaTest.oauth_test_data["valid_signed_cookies"]
|
|
182
|
+
@oauth.stub(:get_access_token_info).and_return("access_token" => "my token")
|
|
183
|
+
end
|
|
166
184
|
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
185
|
+
it "does not uses get_user_info_from_cookies to parse the cookies" do
|
|
186
|
+
@oauth.should_not_receive(:get_user_info_from_cookies).with(@cookie).and_return({})
|
|
187
|
+
@oauth.get_user_from_cookies(@cookie)
|
|
188
|
+
end
|
|
189
|
+
|
|
190
|
+
it "uses return the facebook user id string if the cookies are valid" do
|
|
191
|
+
result = @oauth.get_user_from_cookies(@cookie)
|
|
192
|
+
result.should == "2905623" # the user who generated the original test cookie
|
|
193
|
+
end
|
|
194
|
+
|
|
195
|
+
it "returns nil if the cookies are invalid" do
|
|
196
|
+
# make an invalid string by replacing some values
|
|
197
|
+
bad_cookie_hash = @cookie.inject({}) { |hash, value| hash[value[0]] = value[1].gsub(/[0-9]/, "3") }
|
|
198
|
+
result = @oauth.get_user_from_cookies(bad_cookie_hash)
|
|
199
|
+
result.should be_nil
|
|
200
|
+
end
|
|
170
201
|
end
|
|
202
|
+
|
|
203
|
+
describe "for unsigned cookies" do
|
|
204
|
+
before :each do
|
|
205
|
+
# we don't actually want to make requests to Facebook to redeem the code
|
|
206
|
+
@cookie = KoalaTest.oauth_test_data["valid_cookies"]
|
|
207
|
+
end
|
|
208
|
+
|
|
209
|
+
it "uses get_user_info_from_cookies to parse the cookies" do
|
|
210
|
+
@oauth.should_receive(:get_user_info_from_cookies).with(@cookie).and_return({})
|
|
211
|
+
@oauth.get_user_from_cookies(@cookie)
|
|
212
|
+
end
|
|
213
|
+
|
|
214
|
+
it "uses return a string if the cookies are valid" do
|
|
215
|
+
result = @oauth.get_user_from_cookies(@cookie)
|
|
216
|
+
result.should == "2905623" # the user who generated the original test cookie
|
|
217
|
+
end
|
|
171
218
|
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
219
|
+
it "returns nil if the cookies are invalid" do
|
|
220
|
+
# make an invalid string by replacing some values
|
|
221
|
+
bad_cookie_hash = @cookie.inject({}) { |hash, value| hash[value[0]] = value[1].gsub(/[0-9]/, "3") }
|
|
222
|
+
result = @oauth.get_user_from_cookies(bad_cookie_hash)
|
|
223
|
+
result.should be_nil
|
|
224
|
+
end
|
|
177
225
|
end
|
|
178
226
|
end
|
|
179
227
|
end
|
|
180
228
|
|
|
181
|
-
# OAuth URLs
|
|
182
|
-
|
|
183
229
|
describe "for URL generation" do
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
# url_for_oauth_code
|
|
187
|
-
it "should generate a properly formatted OAuth code URL with the default values" do
|
|
230
|
+
describe "#url_for_oauth_code" do
|
|
231
|
+
it "generates a properly formatted OAuth code URL with the default values" do
|
|
188
232
|
url = @oauth.url_for_oauth_code
|
|
189
|
-
url.should
|
|
233
|
+
url.should match_url("https://#{Koala::Facebook::GRAPH_SERVER}/oauth/authorize?client_id=#{@app_id}&redirect_uri=#{CGI.escape @callback_url}")
|
|
190
234
|
end
|
|
191
235
|
|
|
192
|
-
it "
|
|
236
|
+
it "generates a properly formatted OAuth code URL when a callback is given" do
|
|
193
237
|
callback = "foo.com"
|
|
194
238
|
url = @oauth.url_for_oauth_code(:callback => callback)
|
|
195
|
-
url.should
|
|
239
|
+
url.should match_url("https://#{Koala::Facebook::GRAPH_SERVER}/oauth/authorize?client_id=#{@app_id}&redirect_uri=#{callback}")
|
|
196
240
|
end
|
|
197
241
|
|
|
198
|
-
it "
|
|
242
|
+
it "generates a properly formatted OAuth code URL when permissions are requested as a string" do
|
|
199
243
|
permissions = "publish_stream,read_stream"
|
|
200
244
|
url = @oauth.url_for_oauth_code(:permissions => permissions)
|
|
201
|
-
url.should
|
|
245
|
+
url.should match_url("https://#{Koala::Facebook::GRAPH_SERVER}/oauth/authorize?client_id=#{@app_id}&scope=#{CGI.escape permissions}&redirect_uri=#{CGI.escape @callback_url}")
|
|
202
246
|
end
|
|
203
247
|
|
|
204
|
-
it "
|
|
248
|
+
it "generates a properly formatted OAuth code URL when permissions are requested as a string" do
|
|
205
249
|
permissions = ["publish_stream", "read_stream"]
|
|
206
250
|
url = @oauth.url_for_oauth_code(:permissions => permissions)
|
|
207
|
-
url.should
|
|
251
|
+
url.should match_url("https://#{Koala::Facebook::GRAPH_SERVER}/oauth/authorize?client_id=#{@app_id}&scope=#{CGI.escape permissions.join(",")}&redirect_uri=#{CGI.escape @callback_url}")
|
|
208
252
|
end
|
|
209
253
|
|
|
210
|
-
it "
|
|
254
|
+
it "generates a properly formatted OAuth code URL when both permissions and callback are provided" do
|
|
211
255
|
permissions = "publish_stream,read_stream"
|
|
212
256
|
callback = "foo.com"
|
|
213
257
|
url = @oauth.url_for_oauth_code(:callback => callback, :permissions => permissions)
|
|
214
|
-
url.should
|
|
258
|
+
url.should match_url("https://#{Koala::Facebook::GRAPH_SERVER}/oauth/authorize?client_id=#{@app_id}&scope=#{CGI.escape permissions}&redirect_uri=#{CGI.escape callback}")
|
|
215
259
|
end
|
|
216
260
|
|
|
217
|
-
it "
|
|
261
|
+
it "generates a properly formatted OAuth code URL when a display is given as a string" do
|
|
218
262
|
url = @oauth.url_for_oauth_code(:display => "page")
|
|
219
|
-
url.should
|
|
263
|
+
url.should match_url("https://#{Koala::Facebook::GRAPH_SERVER}/oauth/authorize?client_id=#{@app_id}&display=page&redirect_uri=#{CGI.escape @callback_url}")
|
|
220
264
|
end
|
|
221
265
|
|
|
222
|
-
it "
|
|
266
|
+
it "raises an exception if no callback is given in initialization or the call" do
|
|
223
267
|
oauth2 = Koala::Facebook::OAuth.new(@app_id, @secret)
|
|
224
268
|
lambda { oauth2.url_for_oauth_code }.should raise_error(ArgumentError)
|
|
225
269
|
end
|
|
270
|
+
|
|
271
|
+
it "includes any additional options as URL parameters, appropriately escaped" do
|
|
272
|
+
params = {
|
|
273
|
+
:url => "http://foo.bar?c=2",
|
|
274
|
+
:email => "cdc@b.com"
|
|
275
|
+
}
|
|
276
|
+
url = @oauth.url_for_oauth_code(params)
|
|
277
|
+
params.each_pair do |key, value|
|
|
278
|
+
url.should =~ /[\&\?]#{key}=#{CGI.escape value}/
|
|
279
|
+
end
|
|
280
|
+
end
|
|
226
281
|
end
|
|
227
282
|
|
|
228
|
-
describe "
|
|
283
|
+
describe "#url_for_access_token" do
|
|
229
284
|
before :each do
|
|
230
285
|
# since we're just composing a URL here, we don't need to have a real code
|
|
231
286
|
@code ||= "test_code"
|
|
232
287
|
end
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
it "should generate a properly formatted OAuth token URL when provided a code" do
|
|
288
|
+
|
|
289
|
+
it "generates a properly formatted OAuth token URL when provided a code" do
|
|
236
290
|
url = @oauth.url_for_access_token(@code)
|
|
237
|
-
url.should
|
|
291
|
+
url.should match_url("https://#{Koala::Facebook::GRAPH_SERVER}/oauth/access_token?client_id=#{@app_id}&code=#{@code}&client_secret=#{@secret}&redirect_uri=#{CGI.escape @callback_url}").should be_true
|
|
238
292
|
end
|
|
239
293
|
|
|
240
|
-
it "
|
|
294
|
+
it "generates a properly formatted OAuth token URL when provided a callback" do
|
|
241
295
|
callback = "foo.com"
|
|
242
296
|
url = @oauth.url_for_access_token(@code, :callback => callback)
|
|
243
|
-
url.should
|
|
297
|
+
url.should match_url("https://#{Koala::Facebook::GRAPH_SERVER}/oauth/access_token?client_id=#{@app_id}&code=#{@code}&client_secret=#{@secret}&redirect_uri=#{CGI.escape callback}").should be_true
|
|
298
|
+
end
|
|
299
|
+
|
|
300
|
+
it "includes any additional options as URL parameters, appropriately escaped" do
|
|
301
|
+
params = {
|
|
302
|
+
:url => "http://foo.bar?c=2",
|
|
303
|
+
:email => "cdc@b.com"
|
|
304
|
+
}
|
|
305
|
+
url = @oauth.url_for_access_token(@code, params)
|
|
306
|
+
params.each_pair do |key, value|
|
|
307
|
+
url.should =~ /[\&\?]#{key}=#{CGI.escape value}/
|
|
308
|
+
end
|
|
309
|
+
end
|
|
310
|
+
end
|
|
311
|
+
|
|
312
|
+
describe "#url_for_dialog" do
|
|
313
|
+
it "builds the base properly" do
|
|
314
|
+
dialog_type = "my_dialog_type"
|
|
315
|
+
@oauth.url_for_dialog(dialog_type).should =~ /^http:\/\/#{Koala::Facebook::DIALOG_HOST}\/dialog\/#{dialog_type}/
|
|
316
|
+
end
|
|
317
|
+
|
|
318
|
+
it "adds the app_id/client_id to the url" do
|
|
319
|
+
automatic_params = {:app_id => @app_id, :client_id => @client_id}
|
|
320
|
+
url = @oauth.url_for_dialog("foo", automatic_params)
|
|
321
|
+
automatic_params.each_pair do |key, value|
|
|
322
|
+
# we're slightly simplifying how encode_params works, but for strings/ints, it's okay
|
|
323
|
+
url.should =~ /[\&\?]#{key}=#{CGI.escape value.to_s}/
|
|
324
|
+
end
|
|
325
|
+
end
|
|
326
|
+
|
|
327
|
+
it "includes any additional options as URL parameters, appropriately escaped" do
|
|
328
|
+
params = {
|
|
329
|
+
:url => "http://foo.bar?c=2",
|
|
330
|
+
:email => "cdc@b.com"
|
|
331
|
+
}
|
|
332
|
+
url = @oauth.url_for_dialog("friends", params)
|
|
333
|
+
params.each_pair do |key, value|
|
|
334
|
+
# we're slightly simplifying how encode_params works, but strings/ints, it's okay
|
|
335
|
+
url.should =~ /[\&\?]#{key}=#{CGI.escape value.to_s}/
|
|
336
|
+
end
|
|
337
|
+
end
|
|
338
|
+
|
|
339
|
+
describe "real examples from FB documentation" do
|
|
340
|
+
# see http://developers.facebook.com/docs/reference/dialogs/
|
|
341
|
+
# slightly brittle (e.g. if parameter order changes), but still useful
|
|
342
|
+
it "can generate a send dialog" do
|
|
343
|
+
url = @oauth.url_for_dialog("send", :name => "People Argue Just to Win", :link => "http://www.nytimes.com/2011/06/15/arts/people-argue-just-to-win-scholars-assert.html")
|
|
344
|
+
url.should match_url("http://www.facebook.com/dialog/send?app_id=#{@app_id}&client_id=#{@app_id}&link=http%3A%2F%2Fwww.nytimes.com%2F2011%2F06%2F15%2Farts%2Fpeople-argue-just-to-win-scholars-assert.html&name=People+Argue+Just+to+Win&redirect_uri=#{CGI.escape @callback_url}")
|
|
345
|
+
end
|
|
346
|
+
|
|
347
|
+
it "can generate a feed dialog" do
|
|
348
|
+
url = @oauth.url_for_dialog("feed", :name => "People Argue Just to Win", :link => "http://www.nytimes.com/2011/06/15/arts/people-argue-just-to-win-scholars-assert.html")
|
|
349
|
+
url.should match_url("http://www.facebook.com/dialog/feed?app_id=#{@app_id}&client_id=#{@app_id}&link=http%3A%2F%2Fwww.nytimes.com%2F2011%2F06%2F15%2Farts%2Fpeople-argue-just-to-win-scholars-assert.html&name=People+Argue+Just+to+Win&redirect_uri=#{CGI.escape @callback_url}")
|
|
350
|
+
end
|
|
351
|
+
|
|
352
|
+
it "can generate a oauth dialog" do
|
|
353
|
+
url = @oauth.url_for_dialog("oauth", :scope => "email", :response_type => "token")
|
|
354
|
+
url.should match_url("http://www.facebook.com/dialog/oauth?app_id=#{@app_id}&client_id=#{@app_id}&redirect_uri=#{CGI.escape @callback_url}&response_type=token&scope=email")
|
|
355
|
+
end
|
|
356
|
+
|
|
357
|
+
it "can generate a pay dialog" do
|
|
358
|
+
url = @oauth.url_for_dialog("pay", :order_id => "foo", :credits_purchase => false)
|
|
359
|
+
url.should match_url("http://www.facebook.com/dialog/pay?app_id=#{@app_id}&client_id=#{@app_id}&order_id=foo&credits_purchase=false&redirect_uri=#{CGI.escape @callback_url}")
|
|
360
|
+
end
|
|
244
361
|
end
|
|
245
362
|
end
|
|
246
363
|
end
|
|
247
364
|
|
|
248
365
|
describe "for fetching access tokens" do
|
|
249
|
-
describe "
|
|
366
|
+
describe "#get_access_token_info" do
|
|
250
367
|
it "uses options[:redirect_uri] if provided" do
|
|
251
368
|
uri = "foo"
|
|
252
|
-
Koala.should_receive(:make_request).with(anything, hash_including(:redirect_uri => uri), anything, anything).and_return(Koala::Response.new(200, "", {}))
|
|
369
|
+
Koala.should_receive(:make_request).with(anything, hash_including(:redirect_uri => uri), anything, anything).and_return(Koala::HTTPService::Response.new(200, "", {}))
|
|
253
370
|
@oauth.get_access_token_info(@code, :redirect_uri => uri)
|
|
254
371
|
end
|
|
255
372
|
|
|
256
373
|
it "uses the redirect_uri used to create the @oauth if no :redirect_uri option is provided" do
|
|
257
|
-
Koala.should_receive(:make_request).with(anything, hash_including(:redirect_uri => @callback_url), anything, anything).and_return(Koala::Response.new(200, "", {}))
|
|
374
|
+
Koala.should_receive(:make_request).with(anything, hash_including(:redirect_uri => @callback_url), anything, anything).and_return(Koala::HTTPService::Response.new(200, "", {}))
|
|
258
375
|
@oauth.get_access_token_info(@code)
|
|
259
376
|
end
|
|
260
377
|
|
|
261
378
|
it "makes a GET request" do
|
|
262
|
-
Koala.should_receive(:make_request).with(anything, anything, "get", anything).and_return(Koala::Response.new(200, "", {}))
|
|
379
|
+
Koala.should_receive(:make_request).with(anything, anything, "get", anything).and_return(Koala::HTTPService::Response.new(200, "", {}))
|
|
263
380
|
@oauth.get_access_token_info(@code)
|
|
264
381
|
end
|
|
265
382
|
|
|
266
383
|
if KoalaTest.code
|
|
267
|
-
it "
|
|
384
|
+
it "properly gets and parses an access token token results into a hash" do
|
|
268
385
|
result = @oauth.get_access_token_info(@code)
|
|
269
386
|
result.should be_a(Hash)
|
|
270
387
|
end
|
|
271
388
|
|
|
272
|
-
it "
|
|
389
|
+
it "properly includes the access token results" do
|
|
273
390
|
result = @oauth.get_access_token_info(@code)
|
|
274
391
|
result["access_token"].should
|
|
275
392
|
end
|
|
276
|
-
|
|
393
|
+
|
|
394
|
+
it "raises an error when get_access_token is called with a bad code" do
|
|
277
395
|
lambda { @oauth.get_access_token_info("foo") }.should raise_error(Koala::Facebook::APIError)
|
|
278
396
|
end
|
|
279
397
|
end
|
|
280
398
|
end
|
|
281
399
|
|
|
282
|
-
describe "
|
|
400
|
+
describe "#get_access_token" do
|
|
283
401
|
# TODO refactor these to be proper tests with stubs and tests against real data
|
|
284
|
-
it "
|
|
402
|
+
it "passes on any options provided to make_request" do
|
|
285
403
|
options = {:a => 2}
|
|
286
|
-
Koala.should_receive(:make_request).with(anything, anything, anything, hash_including(options)).and_return(Koala::Response.new(200, "", {}))
|
|
404
|
+
Koala.should_receive(:make_request).with(anything, anything, anything, hash_including(options)).and_return(Koala::HTTPService::Response.new(200, "", {}))
|
|
287
405
|
@oauth.get_access_token(@code, options)
|
|
288
406
|
end
|
|
289
407
|
|
|
@@ -310,38 +428,38 @@ describe "Koala::Facebook::OAuth" do
|
|
|
310
428
|
end
|
|
311
429
|
|
|
312
430
|
describe "get_app_access_token_info" do
|
|
313
|
-
it "
|
|
431
|
+
it "properly gets and parses an app's access token as a hash" do
|
|
314
432
|
result = @oauth.get_app_access_token_info
|
|
315
433
|
result.should be_a(Hash)
|
|
316
434
|
end
|
|
317
435
|
|
|
318
|
-
it "
|
|
436
|
+
it "includes the access token" do
|
|
319
437
|
result = @oauth.get_app_access_token_info
|
|
320
438
|
result["access_token"].should
|
|
321
439
|
end
|
|
322
440
|
|
|
323
|
-
it "
|
|
441
|
+
it "passes on any options provided to make_request" do
|
|
324
442
|
options = {:a => 2}
|
|
325
|
-
Koala.should_receive(:make_request).with(anything, anything, anything, hash_including(options)).and_return(Koala::Response.new(200, "", {}))
|
|
443
|
+
Koala.should_receive(:make_request).with(anything, anything, anything, hash_including(options)).and_return(Koala::HTTPService::Response.new(200, "", {}))
|
|
326
444
|
@oauth.get_app_access_token_info(options)
|
|
327
445
|
end
|
|
328
446
|
end
|
|
329
447
|
|
|
330
448
|
describe "get_app_acess_token" do
|
|
331
|
-
it "
|
|
449
|
+
it "uses get_access_token_info to get and parse an access token token results" do
|
|
332
450
|
result = @oauth.get_app_access_token
|
|
333
451
|
result.should be_a(String)
|
|
334
452
|
end
|
|
335
453
|
|
|
336
|
-
it "
|
|
454
|
+
it "returns the access token as a string" do
|
|
337
455
|
result = @oauth.get_app_access_token
|
|
338
456
|
original = @oauth.get_app_access_token_info
|
|
339
457
|
result.should == original["access_token"]
|
|
340
458
|
end
|
|
341
459
|
|
|
342
|
-
it "
|
|
460
|
+
it "passes on any options provided to make_request" do
|
|
343
461
|
options = {:a => 2}
|
|
344
|
-
Koala.should_receive(:make_request).with(anything, anything, anything, hash_including(options)).and_return(Koala::Response.new(200, "", {}))
|
|
462
|
+
Koala.should_receive(:make_request).with(anything, anything, anything, hash_including(options)).and_return(Koala::HTTPService::Response.new(200, "", {}))
|
|
345
463
|
@oauth.get_app_access_token(options)
|
|
346
464
|
end
|
|
347
465
|
end
|
|
@@ -352,13 +470,13 @@ describe "Koala::Facebook::OAuth" do
|
|
|
352
470
|
# since these are pretty fundamental and pretty testable, we want to test them
|
|
353
471
|
|
|
354
472
|
# parse_access_token
|
|
355
|
-
it "
|
|
473
|
+
it "properly parses access token results" do
|
|
356
474
|
result = @oauth.send(:parse_access_token, @raw_token_string)
|
|
357
475
|
has_both_parts = result["access_token"] && result["expires"]
|
|
358
476
|
has_both_parts.should
|
|
359
477
|
end
|
|
360
478
|
|
|
361
|
-
it "
|
|
479
|
+
it "properly parses offline access token results" do
|
|
362
480
|
result = @oauth.send(:parse_access_token, @raw_offline_access_token_string)
|
|
363
481
|
has_both_parts = result["access_token"] && !result["expires"]
|
|
364
482
|
has_both_parts.should
|
|
@@ -368,7 +486,7 @@ describe "Koala::Facebook::OAuth" do
|
|
|
368
486
|
# somewhat duplicative with the tests for get_access_token and get_app_access_token
|
|
369
487
|
# but no harm in thoroughness
|
|
370
488
|
if KoalaTest.code
|
|
371
|
-
it "
|
|
489
|
+
it "fetches a proper token string from Facebook when given a code" do
|
|
372
490
|
result = @oauth.send(:fetch_token_string, :code => @code, :redirect_uri => @callback_url)
|
|
373
491
|
result.should =~ /^access_token/
|
|
374
492
|
end
|
|
@@ -376,7 +494,7 @@ describe "Koala::Facebook::OAuth" do
|
|
|
376
494
|
it "fetch_token_string code test will not be run since the code field in facebook_data.yml is blank."
|
|
377
495
|
end
|
|
378
496
|
|
|
379
|
-
it "
|
|
497
|
+
it "fetches a proper token string from Facebook when asked for the app token" do
|
|
380
498
|
result = @oauth.send(:fetch_token_string, {:type => 'client_cred'}, true)
|
|
381
499
|
result.should =~ /^access_token/
|
|
382
500
|
end
|
|
@@ -386,105 +504,105 @@ describe "Koala::Facebook::OAuth" do
|
|
|
386
504
|
describe "for exchanging session keys" do
|
|
387
505
|
if KoalaTest.session_key
|
|
388
506
|
describe "with get_token_info_from_session_keys" do
|
|
389
|
-
it "
|
|
507
|
+
it "gets an array of session keys from Facebook when passed a single key" do
|
|
390
508
|
result = @oauth.get_tokens_from_session_keys([KoalaTest.session_key])
|
|
391
509
|
result.should be_an(Array)
|
|
392
510
|
result.length.should == 1
|
|
393
511
|
end
|
|
394
512
|
|
|
395
|
-
it "
|
|
513
|
+
it "gets an array of session keys from Facebook when passed multiple keys" do
|
|
396
514
|
result = @oauth.get_tokens_from_session_keys(@multiple_session_keys)
|
|
397
515
|
result.should be_an(Array)
|
|
398
516
|
result.length.should == 2
|
|
399
517
|
end
|
|
400
518
|
|
|
401
|
-
it "
|
|
519
|
+
it "returns the original hashes" do
|
|
402
520
|
result = @oauth.get_token_info_from_session_keys(@multiple_session_keys)
|
|
403
521
|
result[0].should be_a(Hash)
|
|
404
522
|
end
|
|
405
523
|
|
|
406
|
-
it "
|
|
524
|
+
it "properly handles invalid session keys" do
|
|
407
525
|
result = @oauth.get_token_info_from_session_keys(["foo", "bar"])
|
|
408
526
|
#it should return nil for each of the invalid ones
|
|
409
527
|
result.each {|r| r.should be_nil}
|
|
410
528
|
end
|
|
411
529
|
|
|
412
|
-
it "
|
|
530
|
+
it "properly handles a mix of valid and invalid session keys" do
|
|
413
531
|
result = @oauth.get_token_info_from_session_keys(["foo"].concat(@multiple_session_keys))
|
|
414
532
|
# it should return nil for each of the invalid ones
|
|
415
533
|
result.each_with_index {|r, index| index > 0 ? r.should(be_a(Hash)) : r.should(be_nil)}
|
|
416
534
|
end
|
|
417
535
|
|
|
418
|
-
it "
|
|
536
|
+
it "throws an APIError if Facebook returns an empty body (as happens for instance when the API breaks)" do
|
|
419
537
|
@oauth.should_receive(:fetch_token_string).and_return("")
|
|
420
538
|
lambda { @oauth.get_token_info_from_session_keys(@multiple_session_keys) }.should raise_error(Koala::Facebook::APIError)
|
|
421
539
|
end
|
|
422
540
|
|
|
423
|
-
it "
|
|
541
|
+
it "passes on any options provided to make_request" do
|
|
424
542
|
options = {:a => 2}
|
|
425
|
-
Koala.should_receive(:make_request).with(anything, anything, anything, hash_including(options)).and_return(Koala::Response.new(200, "[{}]", {}))
|
|
543
|
+
Koala.should_receive(:make_request).with(anything, anything, anything, hash_including(options)).and_return(Koala::HTTPService::Response.new(200, "[{}]", {}))
|
|
426
544
|
@oauth.get_token_info_from_session_keys([], options)
|
|
427
545
|
end
|
|
428
546
|
end
|
|
429
547
|
|
|
430
548
|
describe "with get_tokens_from_session_keys" do
|
|
431
|
-
it "
|
|
549
|
+
it "calls get_token_info_from_session_keys" do
|
|
432
550
|
args = @multiple_session_keys
|
|
433
551
|
@oauth.should_receive(:get_token_info_from_session_keys).with(args, anything).and_return([])
|
|
434
552
|
@oauth.get_tokens_from_session_keys(args)
|
|
435
553
|
end
|
|
436
554
|
|
|
437
|
-
it "
|
|
555
|
+
it "returns an array of strings" do
|
|
438
556
|
args = @multiple_session_keys
|
|
439
557
|
result = @oauth.get_tokens_from_session_keys(args)
|
|
440
558
|
result.each {|r| r.should be_a(String) }
|
|
441
559
|
end
|
|
442
560
|
|
|
443
|
-
it "
|
|
561
|
+
it "properly handles invalid session keys" do
|
|
444
562
|
result = @oauth.get_tokens_from_session_keys(["foo", "bar"])
|
|
445
563
|
# it should return nil for each of the invalid ones
|
|
446
564
|
result.each {|r| r.should be_nil}
|
|
447
565
|
end
|
|
448
566
|
|
|
449
|
-
it "
|
|
567
|
+
it "properly handles a mix of valid and invalid session keys" do
|
|
450
568
|
result = @oauth.get_tokens_from_session_keys(["foo"].concat(@multiple_session_keys))
|
|
451
569
|
# it should return nil for each of the invalid ones
|
|
452
570
|
result.each_with_index {|r, index| index > 0 ? r.should(be_a(String)) : r.should(be_nil)}
|
|
453
571
|
end
|
|
454
572
|
|
|
455
|
-
it "
|
|
573
|
+
it "passes on any options provided to make_request" do
|
|
456
574
|
options = {:a => 2}
|
|
457
|
-
Koala.should_receive(:make_request).with(anything, anything, anything, hash_including(options)).and_return(Koala::Response.new(200, "[{}]", {}))
|
|
575
|
+
Koala.should_receive(:make_request).with(anything, anything, anything, hash_including(options)).and_return(Koala::HTTPService::Response.new(200, "[{}]", {}))
|
|
458
576
|
@oauth.get_tokens_from_session_keys([], options)
|
|
459
577
|
end
|
|
460
578
|
end
|
|
461
579
|
|
|
462
580
|
describe "get_token_from_session_key" do
|
|
463
|
-
it "
|
|
581
|
+
it "calls get_tokens_from_session_keys when the get_token_from_session_key is called" do
|
|
464
582
|
key = KoalaTest.session_key
|
|
465
583
|
@oauth.should_receive(:get_tokens_from_session_keys).with([key], anything).and_return([])
|
|
466
584
|
@oauth.get_token_from_session_key(key)
|
|
467
585
|
end
|
|
468
586
|
|
|
469
|
-
it "
|
|
587
|
+
it "gets back the access token string from get_token_from_session_key" do
|
|
470
588
|
result = @oauth.get_token_from_session_key(KoalaTest.session_key)
|
|
471
589
|
result.should be_a(String)
|
|
472
590
|
end
|
|
473
591
|
|
|
474
|
-
it "
|
|
592
|
+
it "returns the first value in the array" do
|
|
475
593
|
result = @oauth.get_token_from_session_key(KoalaTest.session_key)
|
|
476
594
|
array = @oauth.get_tokens_from_session_keys([KoalaTest.session_key])
|
|
477
595
|
result.should == array[0]
|
|
478
596
|
end
|
|
479
597
|
|
|
480
|
-
it "
|
|
598
|
+
it "properly handles an invalid session key" do
|
|
481
599
|
result = @oauth.get_token_from_session_key("foo")
|
|
482
600
|
result.should be_nil
|
|
483
601
|
end
|
|
484
602
|
|
|
485
|
-
it "
|
|
603
|
+
it "passes on any options provided to make_request" do
|
|
486
604
|
options = {:a => 2}
|
|
487
|
-
Koala.should_receive(:make_request).with(anything, anything, anything, hash_including(options)).and_return(Koala::Response.new(200, "[{}]", {}))
|
|
605
|
+
Koala.should_receive(:make_request).with(anything, anything, anything, hash_including(options)).and_return(Koala::HTTPService::Response.new(200, "[{}]", {}))
|
|
488
606
|
@oauth.get_token_from_session_key("", options)
|
|
489
607
|
end
|
|
490
608
|
end
|
|
@@ -496,15 +614,21 @@ describe "Koala::Facebook::OAuth" do
|
|
|
496
614
|
describe "for parsing signed requests" do
|
|
497
615
|
# the signed request code is ported directly from Facebook
|
|
498
616
|
# so we only need to test at a high level that it works
|
|
499
|
-
it "
|
|
617
|
+
it "throws an error if the algorithm is unsupported" do
|
|
500
618
|
MultiJson.stub(:decode).and_return("algorithm" => "my fun algorithm")
|
|
501
619
|
lambda { @oauth.parse_signed_request(@signed_request) }.should raise_error
|
|
502
620
|
end
|
|
503
621
|
|
|
504
|
-
it "
|
|
622
|
+
it "throws an error if the signature is invalid" do
|
|
505
623
|
OpenSSL::HMAC.stub!(:hexdigest).and_return("i'm an invalid signature")
|
|
506
624
|
lambda { @oauth.parse_signed_request(@signed_request) }.should raise_error
|
|
507
625
|
end
|
|
626
|
+
|
|
627
|
+
it "throws an error if the signature string is empty" do
|
|
628
|
+
# this occasionally happens due to Facebook error
|
|
629
|
+
lambda { @oauth.parse_signed_request("") }.should raise_error
|
|
630
|
+
lambda { @oauth.parse_signed_request("abc-def") }.should raise_error
|
|
631
|
+
end
|
|
508
632
|
|
|
509
633
|
it "properly parses requests" do
|
|
510
634
|
@oauth = Koala::Facebook::OAuth.new(@app_id, @secret || @app_secret)
|
|
@@ -512,4 +636,4 @@ describe "Koala::Facebook::OAuth" do
|
|
|
512
636
|
end
|
|
513
637
|
end
|
|
514
638
|
|
|
515
|
-
end # describe
|
|
639
|
+
end # describe
|