cotweet_koala 0.8.0.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,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!\"}"
@@ -0,0 +1,81 @@
1
+ require 'erb'
2
+ require 'yaml'
3
+
4
+ module Koala
5
+ module MockHTTPService
6
+ # Mocks all HTTP requests for with koala_spec_with_mocks.rb
7
+
8
+ # Mocked values to be included in TEST_DATA used in specs
9
+ ACCESS_TOKEN = '*'
10
+ OAUTH_CODE = 'OAUTHCODE'
11
+
12
+ # Loads testing data
13
+ TEST_DATA = YAML.load_file(File.join(File.dirname(__FILE__), 'facebook_data.yml'))
14
+ TEST_DATA.merge!('oauth_token' => Koala::MockHTTPService::ACCESS_TOKEN)
15
+ TEST_DATA['oauth_test_data'].merge!('code' => Koala::MockHTTPService::OAUTH_CODE)
16
+
17
+ # Useful in mock_facebook_responses.yml
18
+ OAUTH_DATA = TEST_DATA['oauth_test_data']
19
+ OAUTH_DATA.merge!({
20
+ 'app_access_token' => Koala::MockHTTPService::ACCESS_TOKEN,
21
+ 'session_key' => "session_key",
22
+ 'multiple_session_keys' => ["session_key", "session_key_2"]
23
+ })
24
+ APP_ID = OAUTH_DATA['app_id']
25
+ SECRET = OAUTH_DATA['secret']
26
+ SUBSCRIPTION_DATA = TEST_DATA["subscription_test_data"]
27
+
28
+ # Loads the mock response data via ERB to substitue values for TEST_DATA (see oauth/access_token)
29
+ mock_response_file_path = File.join(File.dirname(__FILE__), 'mock_facebook_responses.yml')
30
+ RESPONSES = YAML.load(ERB.new(IO.read(mock_response_file_path)).result(binding))
31
+
32
+ def self.included(base)
33
+ base.class_eval do
34
+
35
+ def self.make_request(path, args, verb, options = {})
36
+ path = 'root' if path == ''
37
+ verb ||= 'get'
38
+ server = options[:rest_api] ? 'rest_api' : 'graph_api'
39
+ with_token = args.delete('access_token') == ACCESS_TOKEN ? 'with_token' : 'no_token'
40
+
41
+ # Assume format is always JSON
42
+ args.delete('format')
43
+
44
+ # Create a hash key for the arguments
45
+ args = args.empty? ? 'no_args' : args.sort{|a,b| a[0].to_s <=> b[0].to_s }.map{|arr| arr.join('=')}.join('&')
46
+
47
+ begin
48
+ response = RESPONSES[server][path][args][verb][with_token]
49
+
50
+ # Raises an error of with_token/no_token key is missing
51
+ raise NoMethodError unless response
52
+
53
+ # create response class object
54
+ response_object = if response.is_a? String
55
+ Koala::Response.new(200, response, {})
56
+ else
57
+ Koala::Response.new(response["code"] || 200, response["body"] || "", response["headers"] || {})
58
+ end
59
+
60
+ rescue NoMethodError
61
+ # Raises an error message with the place in the data YML
62
+ # to place a mock as well as a URL to request from
63
+ # Facebook's servers for the actual data
64
+ # (Don't forget to replace ACCESS_TOKEN with a real access token)
65
+
66
+ data_trace = [server, path, args, verb, with_token] * ': '
67
+
68
+ args = args == 'no_args' ? '' : "#{args}&"
69
+ args += 'format=json'
70
+ args += "&access_token=#{ACCESS_TOKEN}" if with_token
71
+
72
+ raise "Missing a mock response for #{data_trace}\nAPI PATH: #{[path, args].join('?')}"
73
+ end
74
+
75
+ response_object
76
+ end
77
+
78
+ end # class_eval
79
+ end # included
80
+ end
81
+ end