joelind-koala 0.8.1

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.
@@ -0,0 +1,187 @@
1
+ class FacebookRealtimeUpdatesTests < Test::Unit::TestCase
2
+ include Koala
3
+
4
+ describe "Koala RealtimeUpdates" do
5
+ before :all do
6
+ # get oauth data
7
+ @oauth_data = $testing_data["oauth_test_data"]
8
+ @app_id = @oauth_data["app_id"]
9
+ @secret = @oauth_data["secret"]
10
+ @callback_url = @oauth_data["callback_url"]
11
+ @app_access_token = @oauth_data["app_access_token"]
12
+
13
+ # check OAuth data
14
+ unless @app_id && @secret && @callback_url && @app_access_token
15
+ raise Exception, "Must supply OAuth app id, secret, app_access_token, and callback to run live subscription tests!"
16
+ end
17
+
18
+ # get subscription data
19
+ @subscription_data = $testing_data["subscription_test_data"]
20
+ @verify_token = @subscription_data["verify_token"]
21
+ @challenge_data = @subscription_data["challenge_data"]
22
+ @subscription_path = @subscription_data["subscription_path"]
23
+
24
+ # check subscription data
25
+ unless @verify_token && @challenge_data && @subscription_path
26
+ raise Exception, "Must supply verify_token and equivalent challenge_data to run live subscription tests!"
27
+ end
28
+ end
29
+
30
+ describe "when initializing" do
31
+ # basic initialization
32
+ it "should initialize properly with an app_id and an app_access_token" do
33
+ updates = Facebook::RealtimeUpdates.new(:app_id => @app_id, :app_access_token => @app_access_token)
34
+ updates.should be_a(Facebook::RealtimeUpdates)
35
+ end
36
+
37
+ # attributes
38
+ it "should allow read access to app_id, app_access_token, and secret" do
39
+ updates = Facebook::RealtimeUpdates.new(:app_id => @app_id, :app_access_token => @app_access_token)
40
+ # this should not throw errors
41
+ updates.app_id && updates.app_access_token && updates.secret
42
+ end
43
+
44
+ it "should not allow write access to app_id" do
45
+ updates = Facebook::RealtimeUpdates.new(:app_id => @app_id, :app_access_token => @app_access_token)
46
+ # this should not throw errors
47
+ lambda { updates.app_id = 2 }.should raise_error(NoMethodError)
48
+ end
49
+
50
+ it "should not allow write access to app_access_token" do
51
+ updates = Facebook::RealtimeUpdates.new(:app_id => @app_id, :app_access_token => @app_access_token)
52
+ # this should not throw errors
53
+ lambda { updates.app_access_token = 2 }.should raise_error(NoMethodError)
54
+ end
55
+
56
+ it "should not allow write access to secret" do
57
+ updates = Facebook::RealtimeUpdates.new(:app_id => @app_id, :app_access_token => @app_access_token)
58
+ # this should not throw errors
59
+ lambda { updates.secret = 2 }.should raise_error(NoMethodError)
60
+ end
61
+
62
+ # init with secret / fetching the token
63
+ it "should initialize properly with an app_id and a secret" do
64
+ updates = Facebook::RealtimeUpdates.new(:app_id => @app_id, :secret => @secret)
65
+ updates.should be_a(Facebook::RealtimeUpdates)
66
+ end
67
+
68
+ it "should fetch an app_token from Facebook when provided an app_id and a secret" do
69
+ updates = Facebook::RealtimeUpdates.new(:app_id => @app_id, :secret => @secret)
70
+ updates.app_access_token.should_not be_nil
71
+ end
72
+
73
+ it "should use the OAuth class to fetch a token when provided an app_id and a secret" do
74
+ oauth = Facebook::OAuth.new(@app_id, @secret)
75
+ token = oauth.get_app_access_token
76
+ oauth.should_receive(:get_app_access_token).and_return(token)
77
+ Facebook::OAuth.should_receive(:new).with(@app_id, @secret).and_return(oauth)
78
+ updates = Facebook::RealtimeUpdates.new(:app_id => @app_id, :secret => @secret)
79
+ end
80
+ end
81
+
82
+ describe "when used" do
83
+ before :each do
84
+ @updates = Facebook::RealtimeUpdates.new(:app_id => @app_id, :secret => @secret)
85
+ end
86
+
87
+ it "should send a subscription request to a valid server" do
88
+ result = @updates.subscribe("user", "name", @subscription_path, @verify_token)
89
+ result.should be_true
90
+ end
91
+
92
+ it "should send a subscription request to a valid server" do
93
+ result = @updates.subscribe("user", "name", @subscription_path, @verify_token)
94
+ result.should be_true
95
+ end
96
+
97
+ it "should send a subscription request to an invalid path on a valid server" do
98
+ lambda { result = @updates.subscribe("user", "name", @subscription_path + "foo", @verify_token) }.should raise_exception(Koala::Facebook::APIError)
99
+ end
100
+
101
+ it "should fail to send a subscription request to an invalid server" do
102
+ lambda { @updates.subscribe("user", "name", "foo", @verify_token) }.should raise_exception(Koala::Facebook::APIError)
103
+ end
104
+
105
+ it "should unsubscribe a valid individual object successfully" do
106
+ @updates.unsubscribe("user").should be_true
107
+ end
108
+
109
+ it "should unsubscribe all subscriptions successfully" do
110
+ @updates.unsubscribe.should be_true
111
+ end
112
+
113
+ it "should fail when an invalid object is provided to unsubscribe" do
114
+ lambda { @updates.unsubscribe("kittens") }.should raise_error(Koala::Facebook::APIError)
115
+ end
116
+
117
+ it "should is subscriptions properly" do
118
+ @updates.list_subscriptions.should be_a(Array)
119
+ end
120
+ end # describe "when used"
121
+
122
+ describe "when meeting challenge" do
123
+ it "should return false if hub.mode isn't subscribe" do
124
+ params = {'hub.mode' => 'not subscribe'}
125
+ Facebook::RealtimeUpdates.meet_challenge(params).should be_false
126
+ end
127
+
128
+ it "should return false if not given a verify_token or block" do
129
+ params = {'hub.mode' => 'subscribe'}
130
+ Facebook::RealtimeUpdates.meet_challenge(params).should be_false
131
+ end
132
+
133
+ describe "and mode is 'subscribe'" do
134
+ before(:each) do
135
+ @params = {'hub.mode' => 'subscribe'}
136
+ end
137
+
138
+ describe "and a token is given" do
139
+ before(:each) do
140
+ @token = 'token'
141
+ @params['hub.verify_token'] = @token
142
+ end
143
+
144
+ it "should return false if the given verify token doesn't match" do
145
+ Facebook::RealtimeUpdates.meet_challenge(@params, @token + '1').should be_false
146
+ end
147
+
148
+ it "should return the challenge if the given verify token matches" do
149
+ @params['hub.challenge'] = 'challenge val'
150
+ Facebook::RealtimeUpdates.meet_challenge(@params, @token).should == @params['hub.challenge']
151
+ end
152
+ end
153
+
154
+ describe "and a block is given" do
155
+ it "should give the block the token as a parameter" do
156
+ Facebook::RealtimeUpdates.meet_challenge(@params)do |token|
157
+ token.should == @token
158
+ end
159
+ end
160
+
161
+ it "should return false if the given block return false" do
162
+ Facebook::RealtimeUpdates.meet_challenge(@params)do |token|
163
+ false
164
+ end.should be_false
165
+ end
166
+
167
+ it "should return false if the given block returns nil" do
168
+ Facebook::RealtimeUpdates.meet_challenge(@params)do |token|
169
+ nil
170
+ end.should be_false
171
+ end
172
+
173
+ it "should return the challenge if the given block returns true" do
174
+ @params['hub.challenge'] = 'challenge val'
175
+ Facebook::RealtimeUpdates.meet_challenge(@params) do |token|
176
+ true
177
+ end.should be_true
178
+ end
179
+ end
180
+
181
+ end # describe "and mode is subscribe"
182
+
183
+ end # describe "when meeting challenge"
184
+
185
+ end # describe
186
+
187
+ end #class
@@ -0,0 +1,94 @@
1
+ shared_examples_for "Koala RestAPI without an access token" do
2
+ # REST_CALL
3
+ describe "when making a rest request" do
4
+ it "should use the proper path" do
5
+ method = stub('methodName')
6
+ @api.should_receive(:api).with(
7
+ "method/#{method}",
8
+ anything,
9
+ anything,
10
+ anything
11
+ )
12
+
13
+ @api.rest_call(method)
14
+ end
15
+
16
+ it "should always use the rest api" do
17
+ @api.should_receive(:api).with(
18
+ anything,
19
+ anything,
20
+ anything,
21
+ :rest_api => true
22
+ )
23
+
24
+ @api.rest_call('anything')
25
+ end
26
+
27
+ it "should take an optional hash of arguments" do
28
+ args = {:arg1 => 'arg1'}
29
+
30
+ @api.should_receive(:api).with(
31
+ anything,
32
+ hash_including(args),
33
+ anything,
34
+ anything
35
+ )
36
+
37
+ @api.rest_call('anything', args)
38
+ end
39
+
40
+ it "should always ask for JSON" do
41
+ @api.should_receive(:api).with(
42
+ anything,
43
+ hash_including('format' => 'json'),
44
+ anything,
45
+ anything
46
+ )
47
+
48
+ @api.rest_call('anything')
49
+ end
50
+ end
51
+
52
+ # FQL_QUERY
53
+ describe "when making a FQL request" do
54
+ it "should call fql.query method" do
55
+ @api.should_receive(:rest_call).with(
56
+ "fql.query",
57
+ anything
58
+ ).and_return(Koala::Response.new(200, "2", {}))
59
+
60
+ @api.fql_query stub('query string')
61
+ end
62
+
63
+ it "should pass a query argument" do
64
+ query = stub('query string')
65
+
66
+ @api.should_receive(:rest_call).with(
67
+ anything,
68
+ hash_including("query" => query)
69
+ )
70
+
71
+ @api.fql_query(query)
72
+ end
73
+
74
+ it "should be able to access public information via FQL" do
75
+ @result = @api.fql_query("select first_name from user where uid = 216743")
76
+ @result.size.should == 1
77
+ @result.first["first_name"].should == "Chris"
78
+ end
79
+
80
+ it "should not be able to access protected information via FQL" do
81
+ lambda { @api.fql_query("select read_stream from permissions where uid = 216743") }.should raise_error(Koala::Facebook::APIError)
82
+ end
83
+ end
84
+ end
85
+
86
+ class FacebookRestAPINoAccessTokenTest < Test::Unit::TestCase
87
+ before :each do
88
+ @api = Koala::Facebook::RestAPI.new
89
+ end
90
+
91
+ describe "Koala RestAPI without an access token" do
92
+ it_should_behave_like "Koala RestAPI without an access token"
93
+ end
94
+ end
@@ -0,0 +1,36 @@
1
+ shared_examples_for "Koala RestAPI with an access token" do
2
+ # FQL
3
+ it "should be able to access public information via FQL" do
4
+ result = @api.fql_query('select first_name from user where uid = 216743')
5
+ result.size.should == 1
6
+ result.first['first_name'].should == 'Chris'
7
+ end
8
+
9
+ it "should be able to access protected information via FQL" do
10
+ # Tests agains the permissions fql table
11
+
12
+ # get the current user's ID
13
+ # we're sneakily using the Graph API, which should be okay since it has its own tests
14
+ g = Koala::Facebook::GraphAPI.new(@token)
15
+ id = g.get_object("me", :fields => "id")["id"]
16
+
17
+ # now send a query about your permissions
18
+ result = @api.fql_query("select read_stream from permissions where uid = #{id}")
19
+
20
+ result.size.should == 1
21
+ # we assume that you have read_stream permissions, so we can test against that
22
+ # (should we keep this?)
23
+ result.first["read_stream"].should == 1
24
+ end
25
+ end
26
+
27
+ class FacebookRestAPIWithAccessTokenTests < Test::Unit::TestCase
28
+ describe "Koala RestAPI with an access token" do
29
+ it_should_behave_like "live testing examples"
30
+ it_should_behave_like "Koala RestAPI with an access token"
31
+
32
+ before :each do
33
+ @api = Koala::Facebook::RestAPI.new(@token)
34
+ end
35
+ end
36
+ end
@@ -0,0 +1,18 @@
1
+ require 'koala_spec_helper'
2
+ require 'mock_http_service'
3
+
4
+ # Runs Koala specs using stubs for HTTP requests
5
+ #
6
+ # Valid OAuth token and code are not necessary to run these
7
+ # specs. Because of this, specs do not fail due to Facebook
8
+ # imposed rate-limits or server timeouts.
9
+ #
10
+ # However as a result they are more brittle since
11
+ # we are not testing the latest responses from the Facebook servers.
12
+ # Therefore, to be certain all specs pass with the current
13
+ # Facebook services, run koala_spec_without_mocks.rb.
14
+
15
+
16
+ Koala.http_service = Koala::MockHTTPService
17
+
18
+ $testing_data = Koala::MockHTTPService::TEST_DATA
@@ -0,0 +1,30 @@
1
+ require 'test/unit'
2
+ require 'rubygems'
3
+ require 'spec/test/unit'
4
+
5
+ # load the libraries
6
+ require 'koala'
7
+
8
+ # load testing data libraries
9
+ require 'koala/live_testing_data_helper'
10
+
11
+ # API tests
12
+ require 'koala/api_base_tests'
13
+
14
+ require 'koala/graph_api/graph_api_no_access_token_tests'
15
+ require 'koala/graph_api/graph_api_with_access_token_tests'
16
+
17
+ require 'koala/rest_api/rest_api_no_access_token_tests'
18
+ require 'koala/rest_api/rest_api_with_access_token_tests'
19
+
20
+ require 'koala/graph_and_rest_api/graph_and_rest_api_no_token_tests'
21
+ require 'koala/graph_and_rest_api/graph_and_rest_api_with_token_tests'
22
+
23
+ # OAuth tests
24
+ require 'koala/oauth/oauth_tests'
25
+
26
+ # Subscriptions tests
27
+ require 'koala/realtime_updates/realtime_updates_tests'
28
+
29
+ # Services tests
30
+ require 'koala/net_http_service_tests'
@@ -0,0 +1,19 @@
1
+ require 'koala_spec_helper'
2
+
3
+ # Runs Koala specs through the Facebook servers
4
+ #
5
+ # Note that you need a valid OAuth token and code for these
6
+ # specs to run. See facebook_data.yml for more information.
7
+
8
+ # load testing data (see note in readme.md)
9
+ # I'm seeing a bug with spec and gets where the facebook_test_suite.rb file gets read in when gets is called
10
+ # until that's solved, we'll need to store/update tokens in the access_token file
11
+ $testing_data = YAML.load_file(File.join(File.dirname(__FILE__), 'facebook_data.yml')) rescue {}
12
+
13
+ unless $testing_data["oauth_token"]
14
+ puts "Access token tests will fail until you store a valid token in facebook_data.yml"
15
+ end
16
+
17
+ unless $testing_data["oauth_test_data"] && $testing_data["oauth_test_data"]["code"] && $testing_data["oauth_test_data"]["secret"]
18
+ puts "Cookie tests will fail until you store valid data for the cookie hash, app_id, and app secret in facebook_data.yml"
19
+ end
@@ -0,0 +1,228 @@
1
+ # Responses by MockHTTPService are taken directly from
2
+ # this file.
3
+ #
4
+ # Structure
5
+ # ----------
6
+ #
7
+ # path:
8
+ # arguments: # sorted by key
9
+ # method: # HTTP method (GET, POST, DELETE, etc.)
10
+ # with_token:
11
+ # no_token:
12
+
13
+ # ====== REST API =====
14
+ rest_api:
15
+
16
+ # -- Stubbed Responses --
17
+ method/fql.query:
18
+ query=select first_name from user where uid = 216743:
19
+ get:
20
+ no_token: '[{"first_name":"Chris"}]'
21
+ with_token: '[{"first_name":"Chris"}]'
22
+ query=select read_stream from permissions where uid = 216743:
23
+ get:
24
+ with_token: '[{"read_stream":1}]'
25
+ no_token: '{"error_code":104,"error_msg":"Requires valid signature","request_args":[{"key":"method","value":"fql.query"},{"key":"format","value":"json"},{"key":"query","value":"select read_stream from permissions where uid = 216743"}]}'
26
+
27
+
28
+ # ====== GRAPH API =====
29
+ graph_api:
30
+
31
+ # -- Common Responses --
32
+
33
+ # Error responses for when a token is required, but not given
34
+ token_required_responses: &token_required
35
+ no_token: '{"error":{"type":"OAuthAccessTokenException", "message":"An access token is required to request this resource."}}'
36
+
37
+ # Common mock item responses
38
+ item_deleted: &item_deleted
39
+ delete:
40
+ with_token: 'true'
41
+
42
+ # OAuth error response
43
+ oauth_error: &oauth_error
44
+ no_token: '{"error": {"type": "OAuthException", "message": "Error validating verification code."}}'
45
+
46
+ # Subscription error response
47
+ verification_error: &verification_error
48
+ with_token: '{"error": {"type": "OAuthException", "message": "Error validating verification code."}}'
49
+
50
+ # -- Stubbed Responses --
51
+ root:
52
+ ids=contextoptional,naitik:
53
+ get:
54
+ with_token: '[{}, {}]'
55
+ no_token: '[{}, {}]'
56
+ me:
57
+ no_args:
58
+ get:
59
+ <<: *token_required
60
+ with_token: '{"updated_time": 1}'
61
+ fields=id:
62
+ get:
63
+ with_token: '{"id": "216743"}'
64
+
65
+ me/feed:
66
+ message=Hello, world, from the test suite!:
67
+ post:
68
+ with_token: '{"id": "MOCK_FEED_ITEM"}'
69
+ message=Hello, world, from the test suite, testing comments!:
70
+ post:
71
+ with_token: '{"id": "MOCK_FEED_ITEM"}'
72
+ message=the cats are asleep:
73
+ post:
74
+ with_token: '{"id": "FEED_ITEM_CATS"}'
75
+ message=Hello, world, from the test suite delete method!:
76
+ post:
77
+ with_token: '{"id": "FEED_ITEM_DELETE"}'
78
+ link=http://www.contextoptional.com/&message=Hello, world, from the test suite again!&name=Context Optional:
79
+ post:
80
+ with_token: '{"id": "FEED_ITEM_CONTEXT"}'
81
+
82
+ koppel:
83
+ no_args:
84
+ get:
85
+ with_token: '{"id": 1, "name": 1, "updated_time": 1}'
86
+ no_token: '{"id": 1, "name": 1}'
87
+
88
+ contextoptional:
89
+ no_args:
90
+ get:
91
+ with_token: '{"id": 1, "name": 1}'
92
+ no_token: '{"id": 1, "name": 1}'
93
+
94
+ contextoptional/likes:
95
+ no_args:
96
+ get:
97
+ with_token: '{"data": [{}]}'
98
+ no_token: '{"data": [{}]}'
99
+
100
+ lukeshepard/likes:
101
+ no_args:
102
+ get:
103
+ <<: *token_required
104
+ with_token: '{"data": [{}]}'
105
+
106
+ chris.baclig/picture:
107
+ no_args:
108
+ get:
109
+ no_token:
110
+ code: 302
111
+ headers:
112
+ Location: http://facebook.com/
113
+ with_token:
114
+ code: 302
115
+ headers:
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
+
129
+ search:
130
+ q=facebook:
131
+ get:
132
+ with_token: '{"data": [{"id": "507731521_100412693339488"}]}'
133
+ no_token: '{"data": [{"id": "507731521_100412693339488"}]}'
134
+
135
+ '115349521819193_113815981982767':
136
+ no_args:
137
+ delete:
138
+ <<: *token_required
139
+
140
+ # -- OAuth responses --
141
+ oauth/access_token:
142
+ client_id=<%= APP_ID %>&client_secret=<%= SECRET %>&code=<%= OAUTH_CODE %>&redirect_uri=<%= OAUTH_DATA["callback_url"] %>:
143
+ get:
144
+ no_token: access_token=<%= ACCESS_TOKEN %>
145
+ client_id=<%= APP_ID %>&client_secret=<%= SECRET %>&code=foo&redirect_uri=<%= OAUTH_DATA["callback_url"] %>:
146
+ get:
147
+ <<: *oauth_error
148
+ client_id=<%= APP_ID %>&client_secret=<%= SECRET %>&type=client_cred:
149
+ post:
150
+ no_token: access_token=<%= ACCESS_TOKEN %>
151
+ oauth/exchange_sessions:
152
+ client_id=<%= APP_ID %>&client_secret=<%= SECRET %>&sessions=<%= OAUTH_DATA["session_key"] %>&type=client_cred:
153
+ post:
154
+ no_token: '[{"access_token":"<%= ACCESS_TOKEN %>","expires":4315}]'
155
+ client_id=<%= APP_ID %>&client_secret=<%= SECRET %>&sessions=<%= OAUTH_DATA["multiple_session_keys"].join(",") %>&type=client_cred:
156
+ post:
157
+ no_token: '[{"access_token":"<%= ACCESS_TOKEN %>","expires":4315}, {"access_token":"<%= ACCESS_TOKEN %>","expires":4315}]'
158
+
159
+
160
+
161
+ # -- Subscription Responses --
162
+ <%= APP_ID %>/subscriptions:
163
+ callback_url=<%= SUBSCRIPTION_DATA["subscription_path"] %>&fields=name&object=user&verify_token=<%= SUBSCRIPTION_DATA["verify_token"] %>:
164
+ post:
165
+ with_token:
166
+ code: 200
167
+ callback_url=<%= SUBSCRIPTION_DATA["subscription_path"] %>foo&fields=name&object=user&verify_token=<%= SUBSCRIPTION_DATA["verify_token"] %>:
168
+ post:
169
+ with_token: '{"error":{"type":"Exception","message":"(#2200) subscription validation failed"}}'
170
+ callback_url=foo&fields=name&object=user&verify_token=<%= SUBSCRIPTION_DATA["verify_token"] %>:
171
+ post:
172
+ with_token: '{"error":{"type":"Exception","message":"(#100) callback_url URL is not properly formatted"}}'
173
+ object=user:
174
+ delete:
175
+ with_token:
176
+ code: 200
177
+ object=kittens:
178
+ delete:
179
+ with_token: '{"error":{"type":"Exception","message":"(#100) Invalid parameter"}}'
180
+ no_args:
181
+ delete:
182
+ with_token:
183
+ code: 200
184
+ get:
185
+ with_token: '{"data":[{"callback_url":"http://oauth.twoalex.com/subscriptions", "fields":["name"], "object":"user", "active":true}]}'
186
+
187
+
188
+ callback_url=<%= SUBSCRIPTION_DATA["subscription_path"] %>:
189
+ get:
190
+ with_token: '{"data":[{"callback_url":"http://oauth.twoalex.com/subscriptions", "fields":["name"], "object":"user", "active":true}]}'
191
+
192
+ # -- Mock Item Responses --
193
+
194
+ MOCK_FEED_ITEM/likes:
195
+ no_args:
196
+ post:
197
+ with_token: '{"id": "MOCK_LIKE"}'
198
+
199
+ MOCK_FEED_ITEM/comments:
200
+ message=it's my comment!:
201
+ post:
202
+ with_token: '{"id": "MOCK_COMMENT"}'
203
+
204
+ MOCK_FEED_ITEM:
205
+ no_args:
206
+ <<: *item_deleted
207
+
208
+ FEED_ITEM_CONTEXT:
209
+ no_args:
210
+ <<: *item_deleted
211
+ get:
212
+ with_token: '{"link":"http://www.contextoptional.com/", "name": "Context Optional"}'
213
+
214
+ FEED_ITEM_CATS:
215
+ no_args:
216
+ <<: *item_deleted
217
+ get:
218
+ with_token: '{"message": "the cats are asleep"}'
219
+
220
+ FEED_ITEM_DELETE:
221
+ no_args:
222
+ <<: *item_deleted
223
+
224
+ MOCK_COMMENT:
225
+ no_args:
226
+ <<: *item_deleted
227
+ get:
228
+ with_token: "{\"message\": \"it\'s my comment!\"}"