joelind-koala 0.8.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -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!\"}"