koala 0.7.2 → 0.7.3
Sign up to get free protection for your applications and to get access to all the features.
- data/CHANGELOG +12 -0
- data/LICENSE +22 -0
- data/Manifest +1 -0
- data/Rakefile +2 -1
- data/examples/oauth_playground/config/facebook.yml +6 -6
- data/koala.gemspec +4 -4
- data/lib/koala.rb +68 -6
- data/lib/koala/graph_api.rb +4 -4
- data/spec/facebook_data.yml +5 -5
- data/spec/koala/api_base_tests.rb +69 -2
- data/spec/koala/graph_api/graph_api_no_access_token_tests.rb +4 -0
- data/spec/koala/graph_api/graph_api_with_access_token_tests.rb +4 -0
- data/spec/koala/net_http_service_tests.rb +168 -4
- data/spec/koala/oauth/oauth_tests.rb +189 -61
- data/spec/mock_facebook_responses.yml +12 -0
- data/spec/mock_http_service.rb +1 -0
- metadata +5 -3
data/CHANGELOG
CHANGED
@@ -1,3 +1,15 @@
|
|
1
|
+
v0.7.3
|
2
|
+
-- Added support for picture sizes -- thanks thhermansen for the patch!
|
3
|
+
-- Adjusted the return values for several methods (get_access_token, get_app_access_token, get_token_from_session_key, get_tokens_from_session_keys, get_user_from_cookies)
|
4
|
+
-- These methods now return strings, rather than hashes, which makes more sense
|
5
|
+
-- The strings are overloaded with an [] method for backwards compatibility (Ruby is truly amazing)
|
6
|
+
-- Using those methods triggers a deprecation warning
|
7
|
+
-- This will be removed by 1.0
|
8
|
+
-- There are new info methods (get_access_token_info, get_app_access_token_info, get_token_info_from_session_keys, and get_user_info_from_cookies) that natively return hashes, for when you want the expiration date
|
9
|
+
-- Responses with HTTP status 500+ now properly throw errors under Net::HTTP
|
10
|
+
-- Updated changelog
|
11
|
+
-- Added license and copyright
|
12
|
+
|
1
13
|
v0.7.2
|
2
14
|
-- Added support for exchanging session keys for OAuth access tokens (get_token_from_session_key for single keys, get_tokens_from_session_keys for multiple)
|
3
15
|
-- Moved Koala files into a koala/ subdirectory to minimize risk of name collisions
|
data/LICENSE
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
The MIT License
|
2
|
+
|
3
|
+
Copyright (c) 2010 Alex Koppel
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
6
|
+
a copy of this software and associated documentation files (the
|
7
|
+
"Software"), to deal in the Software without restriction, including
|
8
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
9
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
10
|
+
permit persons to whom the Software is furnished to do so, subject to
|
11
|
+
the following conditions:
|
12
|
+
|
13
|
+
The above copyright notice and this permission notice shall be
|
14
|
+
included in all copies or substantial portions of the Software.
|
15
|
+
|
16
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
17
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
18
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
19
|
+
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
20
|
+
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
|
21
|
+
TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
22
|
+
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/Manifest
CHANGED
data/Rakefile
CHANGED
@@ -4,7 +4,7 @@ require 'rake'
|
|
4
4
|
require 'echoe'
|
5
5
|
|
6
6
|
# gem management
|
7
|
-
Echoe.new('koala', '0.7.
|
7
|
+
Echoe.new('koala', '0.7.3') do |p|
|
8
8
|
p.summary = "A lightweight, flexible library for Facebook with support for the Graph API, the old REST API, realtime updates, and OAuth validation."
|
9
9
|
p.description = "Koala is a lightweight, flexible Ruby SDK for Facebook. It allows read/write access to the social graph via the Graph API and the older REST API, as well as support for realtime updates and OAuth and Facebook Connect authentication. Koala is fully tested and supports Net::HTTP and Typhoeus connections out of the box and can accept custom modules for other services."
|
10
10
|
p.url = "http://github.com/arsduo/koala"
|
@@ -12,4 +12,5 @@ Echoe.new('koala', '0.7.2') do |p|
|
|
12
12
|
p.email = "alex@alexkoppel.com"
|
13
13
|
p.ignore_pattern = ["tmp/*", "script/*", "pkg/*"]
|
14
14
|
p.development_dependencies = []
|
15
|
+
p.retain_gemspec = true
|
15
16
|
end
|
@@ -1,13 +1,13 @@
|
|
1
1
|
development:
|
2
|
-
api_key:
|
3
|
-
secret_key:
|
4
|
-
app_id:
|
2
|
+
api_key: 171e3563d4fee42e0ba27450838bba32
|
3
|
+
secret_key: c81302ccef57cbdd2e68b2229e54cd2f
|
4
|
+
app_id: 119347844754245
|
5
5
|
|
6
6
|
test:
|
7
7
|
api_key:
|
8
8
|
secret_key:
|
9
9
|
|
10
10
|
production:
|
11
|
-
api_key:
|
12
|
-
secret_key:
|
13
|
-
app_id:
|
11
|
+
api_key: 25e1cec0df2b3bfa781da3ed78da3a1e
|
12
|
+
secret_key: e45e55a333eec232d4206d2703de1307
|
13
|
+
app_id: 119908831367602
|
data/koala.gemspec
CHANGED
@@ -2,15 +2,15 @@
|
|
2
2
|
|
3
3
|
Gem::Specification.new do |s|
|
4
4
|
s.name = %q{koala}
|
5
|
-
s.version = "0.7.
|
5
|
+
s.version = "0.7.3"
|
6
6
|
|
7
7
|
s.required_rubygems_version = Gem::Requirement.new(">= 1.2") if s.respond_to? :required_rubygems_version=
|
8
8
|
s.authors = ["Alex Koppel, Chris Baclig, Rafi Jacoby, Context Optional"]
|
9
|
-
s.date = %q{2010-06-
|
9
|
+
s.date = %q{2010-06-22}
|
10
10
|
s.description = %q{Koala is a lightweight, flexible Ruby SDK for Facebook. It allows read/write access to the social graph via the Graph API and the older REST API, as well as support for realtime updates and OAuth and Facebook Connect authentication. Koala is fully tested and supports Net::HTTP and Typhoeus connections out of the box and can accept custom modules for other services.}
|
11
11
|
s.email = %q{alex@alexkoppel.com}
|
12
|
-
s.extra_rdoc_files = ["CHANGELOG", "lib/koala.rb", "lib/koala/graph_api.rb", "lib/koala/http_services.rb", "lib/koala/realtime_updates.rb", "lib/koala/rest_api.rb"]
|
13
|
-
s.files = ["CHANGELOG", "Manifest", "Rakefile", "examples/oauth_playground/Capfile", "examples/oauth_playground/LICENSE", "examples/oauth_playground/Rakefile", "examples/oauth_playground/config.ru", "examples/oauth_playground/config/deploy.rb", "examples/oauth_playground/config/facebook.yml", "examples/oauth_playground/lib/load_facebook.rb", "examples/oauth_playground/lib/oauth_playground.rb", "examples/oauth_playground/readme.md", "examples/oauth_playground/spec/oauth_playground_spec.rb", "examples/oauth_playground/spec/spec_helper.rb", "examples/oauth_playground/tmp/restart.txt", "examples/oauth_playground/views/index.erb", "examples/oauth_playground/views/layout.erb", "init.rb", "lib/koala.rb", "lib/koala/graph_api.rb", "lib/koala/http_services.rb", "lib/koala/realtime_updates.rb", "lib/koala/rest_api.rb", "readme.md", "spec/facebook_data.yml", "spec/koala/api_base_tests.rb", "spec/koala/graph_and_rest_api/graph_and_rest_api_no_token_tests.rb", "spec/koala/graph_and_rest_api/graph_and_rest_api_with_token_tests.rb", "spec/koala/graph_api/graph_api_no_access_token_tests.rb", "spec/koala/graph_api/graph_api_with_access_token_tests.rb", "spec/koala/live_testing_data_helper.rb", "spec/koala/net_http_service_tests.rb", "spec/koala/oauth/oauth_tests.rb", "spec/koala/realtime_updates/realtime_updates_tests.rb", "spec/koala/rest_api/rest_api_no_access_token_tests.rb", "spec/koala/rest_api/rest_api_with_access_token_tests.rb", "spec/koala_spec.rb", "spec/koala_spec_helper.rb", "spec/koala_spec_without_mocks.rb", "spec/mock_facebook_responses.yml", "spec/mock_http_service.rb", "koala.gemspec"]
|
12
|
+
s.extra_rdoc_files = ["CHANGELOG", "LICENSE", "lib/koala.rb", "lib/koala/graph_api.rb", "lib/koala/http_services.rb", "lib/koala/realtime_updates.rb", "lib/koala/rest_api.rb"]
|
13
|
+
s.files = ["CHANGELOG", "LICENSE", "Manifest", "Rakefile", "examples/oauth_playground/Capfile", "examples/oauth_playground/LICENSE", "examples/oauth_playground/Rakefile", "examples/oauth_playground/config.ru", "examples/oauth_playground/config/deploy.rb", "examples/oauth_playground/config/facebook.yml", "examples/oauth_playground/lib/load_facebook.rb", "examples/oauth_playground/lib/oauth_playground.rb", "examples/oauth_playground/readme.md", "examples/oauth_playground/spec/oauth_playground_spec.rb", "examples/oauth_playground/spec/spec_helper.rb", "examples/oauth_playground/tmp/restart.txt", "examples/oauth_playground/views/index.erb", "examples/oauth_playground/views/layout.erb", "init.rb", "lib/koala.rb", "lib/koala/graph_api.rb", "lib/koala/http_services.rb", "lib/koala/realtime_updates.rb", "lib/koala/rest_api.rb", "readme.md", "spec/facebook_data.yml", "spec/koala/api_base_tests.rb", "spec/koala/graph_and_rest_api/graph_and_rest_api_no_token_tests.rb", "spec/koala/graph_and_rest_api/graph_and_rest_api_with_token_tests.rb", "spec/koala/graph_api/graph_api_no_access_token_tests.rb", "spec/koala/graph_api/graph_api_with_access_token_tests.rb", "spec/koala/live_testing_data_helper.rb", "spec/koala/net_http_service_tests.rb", "spec/koala/oauth/oauth_tests.rb", "spec/koala/realtime_updates/realtime_updates_tests.rb", "spec/koala/rest_api/rest_api_no_access_token_tests.rb", "spec/koala/rest_api/rest_api_with_access_token_tests.rb", "spec/koala_spec.rb", "spec/koala_spec_helper.rb", "spec/koala_spec_without_mocks.rb", "spec/mock_facebook_responses.yml", "spec/mock_http_service.rb", "koala.gemspec"]
|
14
14
|
s.homepage = %q{http://github.com/arsduo/koala}
|
15
15
|
s.rdoc_options = ["--line-numbers", "--inline-source", "--title", "Koala", "--main", "readme.md"]
|
16
16
|
s.require_paths = ["lib"]
|
data/lib/koala.rb
CHANGED
@@ -52,6 +52,11 @@ module Koala
|
|
52
52
|
# make the request via the provided service
|
53
53
|
result = Koala.make_request(path, args, verb, options)
|
54
54
|
|
55
|
+
# Check for any 500 errors before parsing the body
|
56
|
+
# since we're not guaranteed that the body is valid JSON
|
57
|
+
# in the case of a server error
|
58
|
+
raise APIError.new({"type" => "HTTP #{result.status.to_s}", "message" => "Response body: #{result.body}"}) if result.status >= 500
|
59
|
+
|
55
60
|
# Parse the body as JSON and check for errors if provided a mechanism to do so
|
56
61
|
# Note: Facebook sometimes sends results like "true" and "false", which aren't strictly objects
|
57
62
|
# and cause JSON.parse to fail -- so we account for that by wrapping the result in []
|
@@ -103,11 +108,10 @@ module Koala
|
|
103
108
|
@oauth_callback_url = oauth_callback_url
|
104
109
|
end
|
105
110
|
|
106
|
-
def
|
111
|
+
def get_user_info_from_cookie(cookie_hash)
|
107
112
|
# Parses the cookie set by the official Facebook JavaScript SDK.
|
108
113
|
#
|
109
|
-
# cookies should be a
|
110
|
-
# cookie values.
|
114
|
+
# cookies should be a Hash, like the one Rails provides
|
111
115
|
#
|
112
116
|
# If the user is logged in via Facebook, we return a dictionary with the
|
113
117
|
# keys "uid" and "access_token". The former is the user's Facebook ID,
|
@@ -132,8 +136,20 @@ module Koala
|
|
132
136
|
sig == components["sig"] && (components["expires"] == "0" || Time.now.to_i < components["expires"].to_i) ? components : nil
|
133
137
|
end
|
134
138
|
end
|
139
|
+
alias_method :get_user_info_from_cookies, :get_user_info_from_cookie
|
140
|
+
|
141
|
+
def get_user_from_cookie(cookies)
|
142
|
+
# overload this to be backward compatible with older implementations
|
143
|
+
# icky ruby magic, but it's _really_ cool we can do this
|
144
|
+
info = get_user_info_from_cookies(cookies)
|
145
|
+
string = info["uid"]
|
146
|
+
|
147
|
+
overload_as_hash(string, info)
|
148
|
+
end
|
135
149
|
alias_method :get_user_from_cookies, :get_user_from_cookie
|
136
150
|
|
151
|
+
# URLs
|
152
|
+
|
137
153
|
def url_for_oauth_code(options = {})
|
138
154
|
# for permissions, see http://developers.facebook.com/docs/authentication/permissions
|
139
155
|
permissions = options[:permissions]
|
@@ -157,18 +173,34 @@ module Koala
|
|
157
173
|
"https://#{GRAPH_SERVER}/oauth/access_token?client_id=#{@app_id}&redirect_uri=#{callback}&client_secret=#{@app_secret}&code=#{code}"
|
158
174
|
end
|
159
175
|
|
160
|
-
def
|
176
|
+
def get_access_token_info(code)
|
161
177
|
# convenience method to get a parsed token from Facebook for a given code
|
162
178
|
# should this require an OAuth callback URL?
|
163
179
|
get_token_from_server(:code => code, :redirect_uri => @oauth_callback_url)
|
164
180
|
end
|
165
181
|
|
166
|
-
def
|
182
|
+
def get_access_token(code)
|
183
|
+
info = get_access_token_info(code)
|
184
|
+
# upstream methods will throw errors if needed
|
185
|
+
string = info["access_token"]
|
186
|
+
|
187
|
+
overload_as_hash(string, info)
|
188
|
+
end
|
189
|
+
|
190
|
+
def get_app_access_token_info
|
167
191
|
# convenience method to get a the application's sessionless access token
|
168
192
|
get_token_from_server({:type => 'client_cred'}, true)
|
169
193
|
end
|
170
194
|
|
171
|
-
def
|
195
|
+
def get_app_access_token
|
196
|
+
info = get_app_access_token_info
|
197
|
+
string = info["access_token"]
|
198
|
+
|
199
|
+
overload_as_hash(string, info)
|
200
|
+
end
|
201
|
+
|
202
|
+
# from session keys
|
203
|
+
def get_token_info_from_session_keys(sessions)
|
172
204
|
# fetch the OAuth tokens from Facebook
|
173
205
|
response = fetch_token_string({
|
174
206
|
:type => 'client_cred',
|
@@ -184,8 +216,21 @@ module Koala
|
|
184
216
|
JSON.parse(response)
|
185
217
|
end
|
186
218
|
|
219
|
+
def get_tokens_from_session_keys(sessions)
|
220
|
+
# get the original hash results
|
221
|
+
results = get_token_info_from_session_keys(sessions)
|
222
|
+
# now recollect them as backward-compatible strings
|
223
|
+
# for easier use
|
224
|
+
results.collect do |r|
|
225
|
+
string = r["access_token"]
|
226
|
+
|
227
|
+
overload_as_hash string, r
|
228
|
+
end
|
229
|
+
end
|
230
|
+
|
187
231
|
def get_token_from_session_key(session)
|
188
232
|
# convenience method for a single key
|
233
|
+
# gets the overlaoded strings automatically
|
189
234
|
get_tokens_from_session_keys([session])[0]
|
190
235
|
end
|
191
236
|
|
@@ -216,6 +261,23 @@ module Koala
|
|
216
261
|
:client_secret => @app_secret
|
217
262
|
}.merge!(args), post ? "post" : "get").body
|
218
263
|
end
|
264
|
+
|
265
|
+
# overload the object to be accessible as a hash
|
266
|
+
# used to make get_*_token methods backward compatible
|
267
|
+
# icky ruby magic, but it's _really_ cool we can do this
|
268
|
+
def overload_as_hash(obj, hash)
|
269
|
+
command = <<-EOS
|
270
|
+
def [](index)
|
271
|
+
puts "WARNING: get_app_access_token now provides the access token as a string; use get_app_access_token_info if you want the hash with expirations. Otherwise you no longer need to call [] to get the token itself."
|
272
|
+
hash = #{hash.inspect}
|
273
|
+
hash[index]
|
274
|
+
end
|
275
|
+
EOS
|
276
|
+
|
277
|
+
(class << obj; self; end).class_eval command
|
278
|
+
|
279
|
+
obj
|
280
|
+
end
|
219
281
|
end
|
220
282
|
end
|
221
283
|
|
data/lib/koala/graph_api.rb
CHANGED
@@ -47,11 +47,11 @@ module Koala
|
|
47
47
|
graph_call("#{id}/#{connection_name}", args)["data"]
|
48
48
|
end
|
49
49
|
|
50
|
-
def get_picture(object)
|
51
|
-
result = graph_call("#{object}/picture",
|
50
|
+
def get_picture(object, args = {})
|
51
|
+
result = graph_call("#{object}/picture", args, "get", :http_component => :headers)
|
52
52
|
result["Location"]
|
53
|
-
end
|
54
|
-
|
53
|
+
end
|
54
|
+
|
55
55
|
def put_object(parent_object, connection_name, args = {})
|
56
56
|
# Writes the given object to the graph, connected to the given parent.
|
57
57
|
#
|
data/spec/facebook_data.yml
CHANGED
@@ -5,18 +5,18 @@
|
|
5
5
|
|
6
6
|
# You must supply this value yourself to test the GraphAPI class.
|
7
7
|
# Your OAuth token should have publish_stream and read_stream permissions.
|
8
|
-
oauth_token:
|
8
|
+
oauth_token:
|
9
9
|
|
10
10
|
# for testing the OAuth class
|
11
11
|
# baseline app
|
12
12
|
oauth_test_data:
|
13
13
|
# You must supply this value yourself, since they will expire.
|
14
|
-
code:
|
14
|
+
code:
|
15
15
|
# easiest way to get session keys: use multiple test accounts with the Javascript login at http://oauth.twoalex.com
|
16
|
-
session_key:
|
16
|
+
session_key:
|
17
17
|
multiple_session_keys:
|
18
|
-
-
|
19
|
-
-
|
18
|
+
-
|
19
|
+
-
|
20
20
|
|
21
21
|
# These values will work out of the box
|
22
22
|
app_id: 119908831367602
|
@@ -29,9 +29,45 @@ class ApiBaseTests < Test::Unit::TestCase
|
|
29
29
|
service.api('anything')
|
30
30
|
end
|
31
31
|
|
32
|
-
it "should
|
32
|
+
it "should get the attribute of a Koala::Response given by the http_component parameter" do
|
33
|
+
http_component = :method_name
|
34
|
+
|
35
|
+
response = mock('Mock KoalaResponse', :body => '', :status => 200)
|
36
|
+
response.should_receive(http_component).and_return('')
|
37
|
+
|
38
|
+
Koala.stub(:make_request).and_return(response)
|
39
|
+
|
40
|
+
@service.api('anything', 'get', {}, :http_component => http_component)
|
41
|
+
end
|
33
42
|
|
34
|
-
it "should
|
43
|
+
it "should return the body of the request as JSON if no http_component is given" do
|
44
|
+
response = stub('response', :body => 'body', :status => 200)
|
45
|
+
Koala.stub(:make_request).and_return(response)
|
46
|
+
|
47
|
+
json_body = mock('JSON body')
|
48
|
+
JSON.stub(:parse).and_return([json_body])
|
49
|
+
|
50
|
+
@service.api('anything').should == json_body
|
51
|
+
end
|
52
|
+
|
53
|
+
it "should execute a block with the response body if passed one" do
|
54
|
+
body = '{}'
|
55
|
+
Koala.stub(:make_request).and_return(Koala::Response.new(200, body, {}))
|
56
|
+
|
57
|
+
yield_test = mock('Yield Tester')
|
58
|
+
yield_test.should_receive(:pass)
|
59
|
+
|
60
|
+
@service.api('anything') do |arg|
|
61
|
+
yield_test.pass
|
62
|
+
arg.should == JSON.parse(body)
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
it "should raise an API error if the HTTP response code is greater than or equal to 500" do
|
67
|
+
Koala.stub(:make_request).and_return(Koala::Response.new(500, 'response body', {}))
|
68
|
+
|
69
|
+
lambda { @service.api('anything') }.should raise_exception(Koala::Facebook::APIError)
|
70
|
+
end
|
35
71
|
|
36
72
|
it "should handle rogue true/false as responses" do
|
37
73
|
Koala.should_receive(:make_request).and_return(Koala::Response.new(200, 'true', {}))
|
@@ -41,4 +77,35 @@ class ApiBaseTests < Test::Unit::TestCase
|
|
41
77
|
@service.api('anything').should be_false
|
42
78
|
end
|
43
79
|
end
|
80
|
+
end
|
81
|
+
|
82
|
+
shared_examples_for "methods that return overloaded strings" do
|
83
|
+
before :each do
|
84
|
+
@key ||= "access_token"
|
85
|
+
end
|
86
|
+
|
87
|
+
it "should be overloaded to be backward compatible" do
|
88
|
+
@result.respond_to?(:[]).should be_true
|
89
|
+
end
|
90
|
+
|
91
|
+
it "should allow hash access to the access token info" do
|
92
|
+
@result[@key].should == @result
|
93
|
+
end
|
94
|
+
|
95
|
+
it "should output a deprecation warning when the result is used as a hash" do
|
96
|
+
out = nil
|
97
|
+
|
98
|
+
begin
|
99
|
+
# we want to capture the deprecation warning as well as the output
|
100
|
+
# credit to http://thinkingdigitally.com/archive/capturing-output-from-puts-in-ruby/ for the technique
|
101
|
+
out = StringIO.new
|
102
|
+
$stdout = out
|
103
|
+
@result[@key]
|
104
|
+
ensure
|
105
|
+
$stdout = STDOUT
|
106
|
+
end
|
107
|
+
|
108
|
+
# ensure we got a warning
|
109
|
+
out.should_not be_nil
|
110
|
+
end
|
44
111
|
end
|
@@ -34,6 +34,10 @@ shared_examples_for "Koala GraphAPI without an access token" do
|
|
34
34
|
@api.get_picture("chris.baclig").should =~ /http\:\/\//
|
35
35
|
end
|
36
36
|
|
37
|
+
it "should be able to access a user's picture, given a picture type" do
|
38
|
+
@api.get_picture("chris.baclig", {:type => 'large'}).should =~ /^http\:\/\//
|
39
|
+
end
|
40
|
+
|
37
41
|
it "should be able to access connections from public Pages" do
|
38
42
|
result = @api.get_connections("contextoptional", "likes")
|
39
43
|
result.should be_a(Array)
|
@@ -31,6 +31,10 @@ it "should get public data about a user" do
|
|
31
31
|
@api.get_picture("chris.baclig").should =~ /http\:\/\//
|
32
32
|
end
|
33
33
|
|
34
|
+
it "should be able to access a user's picture, given a picture type" do
|
35
|
+
@api.get_picture("chris.baclig", {:type => 'large'}).should =~ /^http\:\/\//
|
36
|
+
end
|
37
|
+
|
34
38
|
it "should be able to access connections from users" do
|
35
39
|
result = @api.get_connections("lukeshepard", "likes")
|
36
40
|
result.length.should > 0
|
@@ -8,10 +8,174 @@ class NetHTTPServiceTests < Test::Unit::TestCase
|
|
8
8
|
it "should define a make_request static module method" do
|
9
9
|
Bear.respond_to?(:make_request).should be_true
|
10
10
|
end
|
11
|
-
|
12
|
-
it "should return a string for location header"
|
13
11
|
|
14
|
-
|
12
|
+
describe "when making a request" do
|
13
|
+
before(:each) do
|
14
|
+
# Setup stubs for make_request to execute without exceptions
|
15
|
+
@mock_http_response = stub('Net::HTTPResponse', :code => 1)
|
16
|
+
@mock_body = stub('Net::HTTPResponse body')
|
17
|
+
@http_request_result = [@mock_http_response, @mock_body]
|
18
|
+
|
19
|
+
@http_yield_mock = mock('Net::HTTP start yielded object')
|
20
|
+
|
21
|
+
@http_yield_mock.stub(:post).and_return(@http_request_result)
|
22
|
+
@http_yield_mock.stub(:get).and_return(@http_request_result)
|
23
|
+
|
24
|
+
@http_mock = stub('Net::HTTP object', 'use_ssl=' => true, 'verify_mode=' => true)
|
25
|
+
@http_mock.stub(:start).and_yield(@http_yield_mock)
|
26
|
+
|
27
|
+
Net::HTTP.stub(:new).and_return(@http_mock)
|
28
|
+
end
|
29
|
+
|
30
|
+
it "should use POST if verb is not GET" do
|
31
|
+
@http_yield_mock.should_receive(:post).and_return(@mock_http_response)
|
32
|
+
@http_mock.should_receive(:start).and_yield(@http_yield_mock)
|
33
|
+
|
34
|
+
Bear.make_request('anything', {}, 'anything')
|
35
|
+
end
|
36
|
+
|
37
|
+
it "should use port 443" do
|
38
|
+
Net::HTTP.should_receive(:new).with(anything, 443).and_return(@http_mock)
|
39
|
+
|
40
|
+
Bear.make_request('anything', {}, 'anything')
|
41
|
+
end
|
42
|
+
|
43
|
+
it "should use SSL" do
|
44
|
+
@http_mock.should_receive('use_ssl=').with(true)
|
45
|
+
|
46
|
+
Bear.make_request('anything', {}, 'anything')
|
47
|
+
end
|
48
|
+
|
49
|
+
it "should use the graph server by default" do
|
50
|
+
Net::HTTP.should_receive(:new).with(Koala::Facebook::GRAPH_SERVER, anything).and_return(@http_mock)
|
51
|
+
Bear.make_request('anything', {}, 'anything')
|
52
|
+
end
|
53
|
+
|
54
|
+
it "should use the REST server if the :rest_api option is true" do
|
55
|
+
Net::HTTP.should_receive(:new).with(Koala::Facebook::REST_SERVER, anything).and_return(@http_mock)
|
56
|
+
Bear.make_request('anything', {}, 'anything', :rest_api => true)
|
57
|
+
end
|
58
|
+
|
59
|
+
it "should turn off vertificate validaiton warnings" do
|
60
|
+
@http_mock.should_receive('verify_mode=').with(OpenSSL::SSL::VERIFY_NONE)
|
61
|
+
|
62
|
+
Bear.make_request('anything', {}, 'anything')
|
63
|
+
end
|
64
|
+
|
65
|
+
it "should start an HTTP connection" do
|
66
|
+
@http_mock.should_receive(:start).and_yield(@http_yield_mock)
|
67
|
+
Bear.make_request('anything', {}, 'anything')
|
68
|
+
end
|
69
|
+
|
70
|
+
describe "via POST" do
|
71
|
+
it "should use Net::HTTP to make a POST request" do
|
72
|
+
@http_yield_mock.should_receive(:post).and_return(@http_request_result)
|
73
|
+
|
74
|
+
Bear.make_request('anything', {}, 'post')
|
75
|
+
end
|
76
|
+
|
77
|
+
it "should go to the specified path" do
|
78
|
+
path = mock('Path')
|
79
|
+
@http_yield_mock.should_receive(:post).with(path, anything).and_return(@http_request_result)
|
80
|
+
|
81
|
+
Bear.make_request(path, {}, 'post')
|
82
|
+
end
|
83
|
+
|
84
|
+
it "should use encoded parameters" do
|
85
|
+
args = {}
|
86
|
+
params = mock('Encoded parameters')
|
87
|
+
Bear.should_receive(:encode_params).with(args).and_return(params)
|
88
|
+
|
89
|
+
@http_yield_mock.should_receive(:post).with(anything, params).and_return(@http_request_result)
|
90
|
+
|
91
|
+
Bear.make_request('anything', args, 'post')
|
92
|
+
end
|
93
|
+
end
|
94
|
+
|
95
|
+
describe "via GET" do
|
96
|
+
it "should use Net::HTTP to make a GET request" do
|
97
|
+
@http_yield_mock.should_receive(:get).and_return(@http_request_result)
|
98
|
+
|
99
|
+
Bear.make_request('anything', {}, 'get')
|
100
|
+
end
|
101
|
+
|
102
|
+
it "should use the correct path, including arguments" do
|
103
|
+
path = mock('Path')
|
104
|
+
params = mock('Encoded parameters')
|
105
|
+
args = {}
|
106
|
+
|
107
|
+
Bear.should_receive(:encode_params).with(args).and_return(params)
|
108
|
+
@http_yield_mock.should_receive(:get).with("#{path}?#{params}").and_return(@http_request_result)
|
109
|
+
|
110
|
+
Bear.make_request(path, args, 'get')
|
111
|
+
end
|
112
|
+
end
|
113
|
+
|
114
|
+
describe "the returned value" do
|
115
|
+
before(:each) do
|
116
|
+
@response = Bear.make_request('anything', {}, 'anything')
|
117
|
+
end
|
118
|
+
|
119
|
+
it "should return a Koala::Response object" do
|
120
|
+
@response.class.should == Koala::Response
|
121
|
+
end
|
122
|
+
|
123
|
+
it "should return a Koala::Response with the right status" do
|
124
|
+
@response.status.should == @mock_http_response.code
|
125
|
+
end
|
126
|
+
|
127
|
+
it "should reutrn a Koala::Response with the right body" do
|
128
|
+
@response.body.should == @mock_body
|
129
|
+
end
|
130
|
+
|
131
|
+
it "should return a Koala::Response with the Net::HTTPResponse object as headers" do
|
132
|
+
@response.headers.should == @mock_http_response
|
133
|
+
end
|
134
|
+
end # describe return value
|
135
|
+
end # describe when making a request
|
15
136
|
|
16
|
-
|
137
|
+
describe "when encoding parameters" do
|
138
|
+
it "should return an empty string if param_hash evaluates to false" do
|
139
|
+
Bear.encode_params(nil).should == ''
|
140
|
+
end
|
141
|
+
|
142
|
+
it "should convert values to JSON if the value is not a String" do
|
143
|
+
val = 'json_value'
|
144
|
+
not_a_string = 'not_a_string'
|
145
|
+
not_a_string.stub(:class).and_return('NotAString')
|
146
|
+
not_a_string.should_receive(:to_json).and_return(val)
|
147
|
+
|
148
|
+
string = "hi"
|
149
|
+
|
150
|
+
args = {
|
151
|
+
not_a_string => not_a_string,
|
152
|
+
string => string
|
153
|
+
}
|
154
|
+
|
155
|
+
result = Bear.encode_params(args)
|
156
|
+
result.split('&').find do |key_and_val|
|
157
|
+
key_and_val.match("#{not_a_string}=#{val}")
|
158
|
+
end.should be_true
|
159
|
+
end
|
160
|
+
|
161
|
+
it "should escape all values" do
|
162
|
+
args = Hash[*(1..4).map {|i| [i.to_s, "Value #{i}($"]}.flatten]
|
163
|
+
|
164
|
+
result = Bear.encode_params(args)
|
165
|
+
result.split('&').each do |key_val|
|
166
|
+
key, val = key_val.split('=')
|
167
|
+
val.should == CGI.escape(args[key])
|
168
|
+
end
|
169
|
+
end
|
170
|
+
|
171
|
+
it "should convert all keys to Strings" do
|
172
|
+
args = Hash[*(1..4).map {|i| [i, "val#{i}"]}.flatten]
|
173
|
+
|
174
|
+
result = Bear.encode_params(args)
|
175
|
+
result.split('&').each do |key_val|
|
176
|
+
key, val = key_val.split('=')
|
177
|
+
key.should == args.find{|key_val_arr| key_val_arr.last == val}.first.to_s
|
178
|
+
end
|
179
|
+
end
|
180
|
+
end
|
17
181
|
end
|
@@ -51,41 +51,66 @@ class FacebookOAuthTests < Test::Unit::TestCase
|
|
51
51
|
@oauth.oauth_callback_url == nil).should be_true
|
52
52
|
end
|
53
53
|
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
54
|
+
describe "cookie parsing" do
|
55
|
+
describe "get_user_info_from_cookies" do
|
56
|
+
it "should properly parse valid cookies" do
|
57
|
+
result = @oauth.get_user_info_from_cookies(@oauth_data["valid_cookies"])
|
58
|
+
result.should be_a(Hash)
|
59
|
+
end
|
59
60
|
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
61
|
+
it "should return all the cookie components from valid cookie string" do
|
62
|
+
cookie_data = @oauth_data["valid_cookies"]
|
63
|
+
parsing_results = @oauth.get_user_info_from_cookies(cookie_data)
|
64
|
+
number_of_components = cookie_data["fbs_#{@app_id.to_s}"].scan(/\=/).length
|
65
|
+
parsing_results.length.should == number_of_components
|
66
|
+
end
|
66
67
|
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
68
|
+
it "should properly parse valid offline access cookies (e.g. no expiration)" do
|
69
|
+
result = @oauth.get_user_info_from_cookies(@oauth_data["offline_access_cookies"])
|
70
|
+
result["uid"].should
|
71
|
+
end
|
71
72
|
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
73
|
+
it "should return all the cookie components from offline access cookies" do
|
74
|
+
cookie_data = @oauth_data["offline_access_cookies"]
|
75
|
+
parsing_results = @oauth.get_user_info_from_cookies(cookie_data)
|
76
|
+
number_of_components = cookie_data["fbs_#{@app_id.to_s}"].scan(/\=/).length
|
77
|
+
parsing_results.length.should == number_of_components
|
78
|
+
end
|
78
79
|
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
80
|
+
it "shouldn't parse expired cookies" do
|
81
|
+
result = @oauth.get_user_info_from_cookies(@oauth_data["expired_cookies"])
|
82
|
+
result.should be_nil
|
83
|
+
end
|
83
84
|
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
85
|
+
it "shouldn't parse invalid cookies" do
|
86
|
+
# make an invalid string by replacing some values
|
87
|
+
bad_cookie_hash = @oauth_data["valid_cookies"].inject({}) { |hash, value| hash[value[0]] = value[1].gsub(/[0-9]/, "3") }
|
88
|
+
result = @oauth.get_user_info_from_cookies(bad_cookie_hash)
|
89
|
+
result.should be_nil
|
90
|
+
end
|
91
|
+
end
|
92
|
+
|
93
|
+
describe "get_user_from_cookies" do
|
94
|
+
it "should use get_user_info_from_cookies to parse the cookies" do
|
95
|
+
data = @oauth_data["valid_cookies"]
|
96
|
+
@oauth.should_receive(:get_user_info_from_cookies).with(data).and_return({})
|
97
|
+
@oauth.get_user_from_cookies(data)
|
98
|
+
end
|
99
|
+
|
100
|
+
it "should use return a string" do
|
101
|
+
result = @oauth.get_user_from_cookies(@oauth_data["valid_cookies"])
|
102
|
+
result.should be_a(String)
|
103
|
+
end
|
104
|
+
|
105
|
+
describe "backward compatibility" do
|
106
|
+
before :each do
|
107
|
+
@result = @oauth.get_user_from_cookies(@oauth_data["valid_cookies"])
|
108
|
+
@key = "uid"
|
109
|
+
end
|
110
|
+
|
111
|
+
it_should_behave_like "methods that return overloaded strings"
|
112
|
+
end
|
113
|
+
end
|
89
114
|
end
|
90
115
|
|
91
116
|
# OAuth URLs
|
@@ -157,46 +182,149 @@ class FacebookOAuthTests < Test::Unit::TestCase
|
|
157
182
|
out.should_not be_nil
|
158
183
|
end
|
159
184
|
|
160
|
-
|
161
|
-
|
162
|
-
|
163
|
-
|
185
|
+
describe "get_access_token_info" do
|
186
|
+
it "should properly get and parse an access token token results into a hash" do
|
187
|
+
result = @oauth.get_access_token_info(@code)
|
188
|
+
result.should be_a(Hash)
|
189
|
+
end
|
190
|
+
|
191
|
+
it "should properly include the access token results" do
|
192
|
+
result = @oauth.get_access_token_info(@code)
|
193
|
+
result["access_token"].should
|
194
|
+
end
|
195
|
+
|
196
|
+
it "should raise an error when get_access_token is called with a bad code" do
|
197
|
+
lambda { @oauth.get_access_token_info("foo") }.should raise_error(Koala::Facebook::APIError)
|
198
|
+
end
|
164
199
|
end
|
165
200
|
|
166
|
-
|
167
|
-
|
201
|
+
describe "get_access_token" do
|
202
|
+
it "should use get_access_token_info to get and parse an access token token results" do
|
203
|
+
result = @oauth.get_access_token(@code)
|
204
|
+
result.should be_a(String)
|
205
|
+
end
|
206
|
+
|
207
|
+
it "should return the access token as a string" do
|
208
|
+
result = @oauth.get_access_token(@code)
|
209
|
+
original = @oauth.get_access_token_info(@code)
|
210
|
+
result.should == original["access_token"]
|
211
|
+
end
|
212
|
+
|
213
|
+
it "should raise an error when get_access_token is called with a bad code" do
|
214
|
+
lambda { @oauth.get_access_token("foo") }.should raise_error(Koala::Facebook::APIError)
|
215
|
+
end
|
216
|
+
|
217
|
+
describe "backwards compatibility" do
|
218
|
+
before :each do
|
219
|
+
@result = @oauth.get_access_token(@code)
|
220
|
+
end
|
221
|
+
|
222
|
+
it_should_behave_like "methods that return overloaded strings"
|
223
|
+
end
|
168
224
|
end
|
225
|
+
|
226
|
+
describe "get_app_access_token_info" do
|
227
|
+
it "should properly get and parse an app's access token as a hash" do
|
228
|
+
result = @oauth.get_app_access_token_info
|
229
|
+
result.should be_a(Hash)
|
230
|
+
end
|
169
231
|
|
170
|
-
|
171
|
-
|
172
|
-
|
173
|
-
|
174
|
-
result["access_token"].should
|
232
|
+
it "should include the access token" do
|
233
|
+
result = @oauth.get_app_access_token_info
|
234
|
+
result["access_token"].should
|
235
|
+
end
|
175
236
|
end
|
237
|
+
|
238
|
+
describe "get_app_acess_token" do
|
239
|
+
it "should use get_access_token_info to get and parse an access token token results" do
|
240
|
+
result = @oauth.get_app_access_token
|
241
|
+
result.should be_a(String)
|
242
|
+
end
|
176
243
|
|
177
|
-
|
178
|
-
|
179
|
-
|
180
|
-
|
181
|
-
|
244
|
+
it "should return the access token as a string" do
|
245
|
+
result = @oauth.get_app_access_token
|
246
|
+
original = @oauth.get_app_access_token_info
|
247
|
+
result.should == original["access_token"]
|
248
|
+
end
|
249
|
+
|
250
|
+
describe "backwards compatibility" do
|
251
|
+
before :each do
|
252
|
+
@result = @oauth.get_app_access_token
|
253
|
+
end
|
254
|
+
|
255
|
+
it_should_behave_like "methods that return overloaded strings"
|
256
|
+
end
|
182
257
|
end
|
183
258
|
|
184
|
-
|
185
|
-
|
186
|
-
|
187
|
-
|
188
|
-
|
259
|
+
describe "exchanging session keys" do
|
260
|
+
describe "with get_token_info_from_session_keys" do
|
261
|
+
it "should get an array of session keys from Facebook when passed a single key" do
|
262
|
+
result = @oauth.get_tokens_from_session_keys([@oauth_data["session_key"]])
|
263
|
+
result.should be_an(Array)
|
264
|
+
result.length.should == 1
|
265
|
+
end
|
189
266
|
|
190
|
-
|
191
|
-
|
192
|
-
|
193
|
-
|
194
|
-
|
195
|
-
|
196
|
-
|
197
|
-
|
198
|
-
|
199
|
-
|
267
|
+
it "should get an array of session keys from Facebook when passed multiple keys" do
|
268
|
+
result = @oauth.get_tokens_from_session_keys(@oauth_data["multiple_session_keys"])
|
269
|
+
result.should be_an(Array)
|
270
|
+
result.length.should == 2
|
271
|
+
end
|
272
|
+
|
273
|
+
it "should return the original hashes" do
|
274
|
+
result = @oauth.get_token_info_from_session_keys(@oauth_data["multiple_session_keys"])
|
275
|
+
result[0].should be_a(Hash)
|
276
|
+
end
|
277
|
+
end
|
278
|
+
|
279
|
+
describe "with get_tokens_from_session_keys" do
|
280
|
+
it "should call get_token_info_from_session_keys" do
|
281
|
+
args = @oauth_data["multiple_session_keys"]
|
282
|
+
@oauth.should_receive(:get_token_info_from_session_keys).with(args).and_return([])
|
283
|
+
@oauth.get_tokens_from_session_keys(args)
|
284
|
+
end
|
285
|
+
|
286
|
+
it "should return an array of strings" do
|
287
|
+
args = @oauth_data["multiple_session_keys"]
|
288
|
+
result = @oauth.get_tokens_from_session_keys(args)
|
289
|
+
result.each {|r| r.should be_a(String) }
|
290
|
+
end
|
291
|
+
|
292
|
+
describe "backwards compatibility" do
|
293
|
+
before :each do
|
294
|
+
args = @oauth_data["multiple_session_keys"]
|
295
|
+
@result = @oauth.get_tokens_from_session_keys(args)[0]
|
296
|
+
end
|
297
|
+
|
298
|
+
it_should_behave_like "methods that return overloaded strings"
|
299
|
+
end
|
300
|
+
end
|
301
|
+
|
302
|
+
describe "get_token_from_session_key" do
|
303
|
+
it "should call get_tokens_from_session_keys when the get_token_from_session_key is called" do
|
304
|
+
key = @oauth_data["session_key"]
|
305
|
+
@oauth.should_receive(:get_tokens_from_session_keys).with([key]).and_return([])
|
306
|
+
@oauth.get_token_from_session_key(key)
|
307
|
+
end
|
308
|
+
|
309
|
+
it "should get back the access token string from get_token_from_session_key" do
|
310
|
+
result = @oauth.get_token_from_session_key(@oauth_data["session_key"])
|
311
|
+
result.should be_a(String)
|
312
|
+
end
|
313
|
+
|
314
|
+
it "should be the first value in the array" do
|
315
|
+
result = @oauth.get_token_from_session_key(@oauth_data["session_key"])
|
316
|
+
array = @oauth.get_tokens_from_session_keys([@oauth_data["session_key"]])
|
317
|
+
result.should == array[0]
|
318
|
+
end
|
319
|
+
|
320
|
+
describe "backwards compatibility" do
|
321
|
+
before :each do
|
322
|
+
@result = @oauth.get_token_from_session_key(@oauth_data["session_key"])
|
323
|
+
end
|
324
|
+
|
325
|
+
it_should_behave_like "methods that return overloaded strings"
|
326
|
+
end
|
327
|
+
end
|
200
328
|
end
|
201
329
|
|
202
330
|
# protected methods
|
@@ -114,6 +114,18 @@ graph_api:
|
|
114
114
|
code: 302
|
115
115
|
headers:
|
116
116
|
Location: http://facebook.com/
|
117
|
+
type=large:
|
118
|
+
get:
|
119
|
+
no_token:
|
120
|
+
code: 302
|
121
|
+
headers:
|
122
|
+
Location: http://facebook.com/large
|
123
|
+
with_token:
|
124
|
+
code: 302
|
125
|
+
headers:
|
126
|
+
Location: http://facebook.com/large
|
127
|
+
|
128
|
+
|
117
129
|
search:
|
118
130
|
q=facebook:
|
119
131
|
get:
|
data/spec/mock_http_service.rb
CHANGED
metadata
CHANGED
@@ -5,8 +5,8 @@ version: !ruby/object:Gem::Version
|
|
5
5
|
segments:
|
6
6
|
- 0
|
7
7
|
- 7
|
8
|
-
-
|
9
|
-
version: 0.7.
|
8
|
+
- 3
|
9
|
+
version: 0.7.3
|
10
10
|
platform: ruby
|
11
11
|
authors:
|
12
12
|
- Alex Koppel, Chris Baclig, Rafi Jacoby, Context Optional
|
@@ -14,7 +14,7 @@ autorequire:
|
|
14
14
|
bindir: bin
|
15
15
|
cert_chain: []
|
16
16
|
|
17
|
-
date: 2010-06-
|
17
|
+
date: 2010-06-22 00:00:00 -07:00
|
18
18
|
default_executable:
|
19
19
|
dependencies: []
|
20
20
|
|
@@ -26,6 +26,7 @@ extensions: []
|
|
26
26
|
|
27
27
|
extra_rdoc_files:
|
28
28
|
- CHANGELOG
|
29
|
+
- LICENSE
|
29
30
|
- lib/koala.rb
|
30
31
|
- lib/koala/graph_api.rb
|
31
32
|
- lib/koala/http_services.rb
|
@@ -33,6 +34,7 @@ extra_rdoc_files:
|
|
33
34
|
- lib/koala/rest_api.rb
|
34
35
|
files:
|
35
36
|
- CHANGELOG
|
37
|
+
- LICENSE
|
36
38
|
- Manifest
|
37
39
|
- Rakefile
|
38
40
|
- examples/oauth_playground/Capfile
|