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.
Files changed (54) hide show
  1. data/.gitignore +3 -1
  2. data/.rspec +1 -0
  3. data/.travis.yml +4 -0
  4. data/.yardopts +3 -0
  5. data/CHANGELOG +43 -0
  6. data/Gemfile +14 -0
  7. data/Guardfile +6 -0
  8. data/koala.gemspec +4 -4
  9. data/lib/koala/api/batch_operation.rb +83 -0
  10. data/lib/koala/api/graph_api.rb +476 -0
  11. data/lib/koala/{graph_batch_api.rb → api/graph_batch_api.rb} +22 -17
  12. data/lib/koala/api/graph_collection.rb +107 -0
  13. data/lib/koala/api/legacy.rb +26 -0
  14. data/lib/koala/{rest_api.rb → api/rest_api.rb} +36 -10
  15. data/lib/koala/api.rb +93 -0
  16. data/lib/koala/http_service/multipart_request.rb +41 -0
  17. data/lib/koala/http_service/response.rb +18 -0
  18. data/lib/koala/http_service/uploadable_io.rb +187 -0
  19. data/lib/koala/http_service.rb +73 -23
  20. data/lib/koala/oauth.rb +173 -36
  21. data/lib/koala/realtime_updates.rb +89 -51
  22. data/lib/koala/test_users.rb +122 -32
  23. data/lib/koala/utils.rb +11 -4
  24. data/lib/koala/version.rb +1 -1
  25. data/lib/koala.rb +16 -95
  26. data/readme.md +30 -13
  27. data/spec/cases/api_spec.rb +28 -21
  28. data/spec/cases/error_spec.rb +10 -0
  29. data/spec/cases/graph_api_batch_spec.rb +100 -58
  30. data/spec/cases/graph_collection_spec.rb +23 -7
  31. data/spec/cases/http_service_spec.rb +14 -34
  32. data/spec/cases/koala_spec.rb +22 -4
  33. data/spec/cases/legacy_spec.rb +115 -0
  34. data/spec/cases/multipart_request_spec.rb +66 -0
  35. data/spec/cases/oauth_spec.rb +232 -108
  36. data/spec/cases/realtime_updates_spec.rb +154 -47
  37. data/spec/cases/test_users_spec.rb +276 -217
  38. data/spec/cases/uploadable_io_spec.rb +1 -1
  39. data/spec/cases/utils_spec.rb +29 -5
  40. data/spec/fixtures/mock_facebook_responses.yml +50 -26
  41. data/spec/spec_helper.rb +3 -0
  42. data/spec/support/custom_matchers.rb +28 -0
  43. data/spec/support/graph_api_shared_examples.rb +274 -70
  44. data/spec/support/koala_test.rb +27 -16
  45. data/spec/support/mock_http_service.rb +2 -2
  46. data/spec/support/rest_api_shared_examples.rb +46 -162
  47. metadata +33 -25
  48. data/lib/koala/batch_operation.rb +0 -74
  49. data/lib/koala/graph_api.rb +0 -270
  50. data/lib/koala/graph_collection.rb +0 -59
  51. data/lib/koala/uploadable_io.rb +0 -181
  52. data/spec/cases/graph_and_rest_api_spec.rb +0 -22
  53. data/spec/cases/graph_api_spec.rb +0 -22
  54. data/spec/cases/rest_api_spec.rb +0 -41
@@ -29,26 +29,27 @@ describe "Koala::Facebook::OAuth" do
29
29
  @time.stub!(:to_i).and_return(1273363199)
30
30
  end
31
31
 
32
- # initialization
33
- it "should properly initialize" do
34
- @oauth.should
35
- end
32
+ describe ".new" do
33
+ it "properly initializes" do
34
+ @oauth.should
35
+ end
36
36
 
37
- it "should properly set 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
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
- it "should properly initialize without a callback_url" do
44
- @oauth = Koala::Facebook::OAuth.new(@app_id, @secret)
45
- end
43
+ it "properly initializes without a callback_url" do
44
+ @oauth = Koala::Facebook::OAuth.new(@app_id, @secret)
45
+ end
46
46
 
47
- it "should properly set 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
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 fails" do
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 "shouldn't parse invalid cookies" do
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 "should properly parse valid cookies" do
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 "should return all the cookie components from valid cookie string" do
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 "should properly parse valid offline access cookies (e.g. no expiration)" do
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 "should return all the cookie components from offline access cookies" do
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 "shouldn't parse expired cookies" do
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 "shouldn't parse invalid cookies" do
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
- it "should use get_user_info_from_cookies to parse the cookies" do
162
- data = KoalaTest.oauth_test_data["valid_cookies"]
163
- @oauth.should_receive(:get_user_info_from_cookies).with(data).and_return({})
164
- @oauth.get_user_from_cookies(data)
165
- end
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
- it "should use return a string if the cookies are valid" do
168
- result = @oauth.get_user_from_cookies(KoalaTest.oauth_test_data["valid_cookies"])
169
- result.should be_a(String)
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
- it "should return nil if the cookies are invalid" do
173
- # make an invalid string by replacing some values
174
- bad_cookie_hash = KoalaTest.oauth_test_data["valid_cookies"].inject({}) { |hash, value| hash[value[0]] = value[1].gsub(/[0-9]/, "3") }
175
- result = @oauth.get_user_from_cookies(bad_cookie_hash)
176
- result.should be_nil
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
- describe "for OAuth codes" do
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 == "https://#{Koala::Facebook::GRAPH_SERVER}/oauth/authorize?client_id=#{@app_id}&redirect_uri=#{@callback_url}"
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 "should generate a properly formatted OAuth code URL when a callback is given" do
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 == "https://#{Koala::Facebook::GRAPH_SERVER}/oauth/authorize?client_id=#{@app_id}&redirect_uri=#{callback}"
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 "should generate a properly formatted OAuth code URL when permissions are requested as a string" do
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 == "https://#{Koala::Facebook::GRAPH_SERVER}/oauth/authorize?client_id=#{@app_id}&redirect_uri=#{@callback_url}&scope=#{permissions}"
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 "should generate a properly formatted OAuth code URL when permissions are requested as a string" do
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 == "https://#{Koala::Facebook::GRAPH_SERVER}/oauth/authorize?client_id=#{@app_id}&redirect_uri=#{@callback_url}&scope=#{permissions.join(",")}"
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 "should generate a properly formatted OAuth code URL when both permissions and callback are provided" do
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 == "https://#{Koala::Facebook::GRAPH_SERVER}/oauth/authorize?client_id=#{@app_id}&redirect_uri=#{callback}&scope=#{permissions}"
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 "should generate a properly formatted OAuth code URL when a display is given as a string" do
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 == "https://#{Koala::Facebook::GRAPH_SERVER}/oauth/authorize?client_id=#{@app_id}&redirect_uri=#{@callback_url}&display=page"
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 "should raise an exception if no callback is given in initialization or the call" do
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 "for access token URLs" do
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
- # url_for_access_token
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 == "https://#{Koala::Facebook::GRAPH_SERVER}/oauth/access_token?client_id=#{@app_id}&redirect_uri=#{@callback_url}&client_secret=#{@secret}&code=#{@code}"
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 "should generate a properly formatted OAuth token URL when provided a callback" do
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 == "https://#{Koala::Facebook::GRAPH_SERVER}/oauth/access_token?client_id=#{@app_id}&redirect_uri=#{callback}&client_secret=#{@secret}&code=#{@code}"
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 ".get_access_token_info" do
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 "should properly get and parse an access token token results into a hash" do
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 "should properly include the access token results" do
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
- it "should raise an error when get_access_token is called with a bad code" do
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 ".get_access_token" do
400
+ describe "#get_access_token" do
283
401
  # TODO refactor these to be proper tests with stubs and tests against real data
284
- it "should pass on any options provided to make_request" do
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 "should properly get and parse an app's access token as a hash" do
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 "should include the access token" do
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 "should pass on any options provided to make_request" do
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 "should use get_access_token_info to get and parse an access token token results" do
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 "should return the access token as a string" do
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 "should pass on any options provided to make_request" do
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 "should properly parse access token results" do
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 "should properly parse offline access token results" do
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 "should fetch a proper token string from Facebook when given a code" do
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 "should fetch a proper token string from Facebook when asked for the app token" do
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 "should get an array of session keys from Facebook when passed a single key" do
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 "should get an array of session keys from Facebook when passed multiple keys" do
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 "should return the original hashes" do
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 "should properly handle invalid session keys" do
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 "should properly handle a mix of valid and invalid session keys" do
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 "should throw an APIError if Facebook returns an empty body (as happens for instance when the API breaks)" do
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 "should pass on any options provided to make_request" do
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 "should call get_token_info_from_session_keys" do
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 "should return an array of strings" do
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 "should properly handle invalid session keys" do
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 "should properly handle a mix of valid and invalid session keys" do
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 "should pass on any options provided to make_request" do
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 "should call get_tokens_from_session_keys when the get_token_from_session_key is called" do
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 "should get back the access token string from get_token_from_session_key" do
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 "should be the first value in the array" do
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 "should properly handle an invalid session key" do
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 "should pass on any options provided to make_request" do
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 "should throw an error if the algorithm is unsupported" do
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 "should throw an error if the signature is invalid" do
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