koala 1.0.0.beta → 1.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (69) hide show
  1. data/.autotest +12 -0
  2. data/.gitignore +5 -0
  3. data/.travis.yml +8 -0
  4. data/CHANGELOG +42 -4
  5. data/Gemfile +7 -0
  6. data/LICENSE +1 -1
  7. data/Manifest +5 -2
  8. data/Rakefile +13 -14
  9. data/autotest/discover.rb +1 -0
  10. data/koala.gemspec +35 -20
  11. data/lib/koala/batch_operation.rb +74 -0
  12. data/lib/koala/graph_api.rb +196 -143
  13. data/lib/koala/graph_batch_api.rb +87 -0
  14. data/lib/koala/graph_collection.rb +54 -0
  15. data/lib/koala/http_services/net_http_service.rb +92 -0
  16. data/lib/koala/http_services/typhoeus_service.rb +37 -0
  17. data/lib/koala/http_services.rb +15 -124
  18. data/lib/koala/oauth.rb +181 -0
  19. data/lib/koala/realtime_updates.rb +5 -14
  20. data/lib/koala/rest_api.rb +13 -8
  21. data/lib/koala/test_users.rb +21 -8
  22. data/lib/koala/uploadable_io.rb +175 -0
  23. data/lib/koala.rb +48 -240
  24. data/readme.md +60 -28
  25. data/spec/cases/api_base_spec.rb +101 -0
  26. data/spec/cases/graph_and_rest_api_spec.rb +31 -0
  27. data/spec/cases/graph_api_batch_spec.rb +609 -0
  28. data/spec/cases/graph_api_spec.rb +25 -0
  29. data/spec/cases/http_services/http_service_spec.rb +129 -0
  30. data/spec/cases/http_services/net_http_service_spec.rb +532 -0
  31. data/spec/cases/http_services/typhoeus_service_spec.rb +152 -0
  32. data/spec/cases/koala_spec.rb +55 -0
  33. data/spec/cases/oauth_spec.rb +409 -0
  34. data/spec/cases/realtime_updates_spec.rb +184 -0
  35. data/spec/cases/rest_api_spec.rb +25 -0
  36. data/spec/{koala/test_users/test_users_tests.rb → cases/test_users_spec.rb} +47 -34
  37. data/spec/cases/uploadable_io_spec.rb +193 -0
  38. data/spec/fixtures/cat.m4v +0 -0
  39. data/spec/{facebook_data.yml → fixtures/facebook_data.yml} +12 -14
  40. data/spec/{mock_facebook_responses.yml → fixtures/mock_facebook_responses.yml} +408 -306
  41. data/spec/spec_helper.rb +19 -0
  42. data/spec/support/graph_api_shared_examples.rb +495 -0
  43. data/spec/support/json_testing_fix.rb +18 -0
  44. data/spec/{koala → support}/live_testing_data_helper.rb +39 -42
  45. data/spec/support/mock_http_service.rb +96 -0
  46. data/spec/support/rest_api_shared_examples.rb +285 -0
  47. data/spec/support/setup_mocks_or_live.rb +51 -0
  48. data/spec/support/uploadable_io_shared_examples.rb +76 -0
  49. metadata +110 -64
  50. data/init.rb +0 -2
  51. data/spec/koala/api_base_tests.rb +0 -102
  52. data/spec/koala/graph_and_rest_api/graph_and_rest_api_no_token_tests.rb +0 -14
  53. data/spec/koala/graph_and_rest_api/graph_and_rest_api_with_token_tests.rb +0 -16
  54. data/spec/koala/graph_api/graph_api_no_access_token_tests.rb +0 -63
  55. data/spec/koala/graph_api/graph_api_tests.rb +0 -86
  56. data/spec/koala/graph_api/graph_api_with_access_token_tests.rb +0 -154
  57. data/spec/koala/graph_api/graph_collection_tests.rb +0 -104
  58. data/spec/koala/net_http_service_tests.rb +0 -430
  59. data/spec/koala/oauth/oauth_tests.rb +0 -409
  60. data/spec/koala/realtime_updates/realtime_updates_tests.rb +0 -187
  61. data/spec/koala/rest_api/rest_api_no_access_token_tests.rb +0 -25
  62. data/spec/koala/rest_api/rest_api_tests.rb +0 -118
  63. data/spec/koala/rest_api/rest_api_with_access_token_tests.rb +0 -38
  64. data/spec/koala/typhoeus_service_tests.rb +0 -156
  65. data/spec/koala_spec.rb +0 -18
  66. data/spec/koala_spec_helper.rb +0 -70
  67. data/spec/koala_spec_without_mocks.rb +0 -19
  68. data/spec/mock_http_service.rb +0 -96
  69. /data/spec/{koala/assets → fixtures}/beach.jpg +0 -0
@@ -1,307 +1,409 @@
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
- test_user_no_perms: &test_user_no_perms
51
- post:
52
- with_token: '{"id": "777777777", "access_token":"119908831367602|o3wswWQ88LYjEC9-ukR_gjRIOMw.", "login_url":"https://www.facebook.com/platform/test_account.."}'
53
-
54
- # -- Stubbed Responses --
55
- root:
56
- ids=contextoptional,naitik:
57
- get:
58
- with_token: '[{}, {}]'
59
- no_token: '[{}, {}]'
60
- /me:
61
- no_args:
62
- get:
63
- <<: *token_required
64
- with_token: '{"updated_time": 1}'
65
- fields=id:
66
- get:
67
- with_token: '{"id": "216743"}'
68
-
69
- /me/feed:
70
- message=Hello, world, from the test suite!:
71
- post:
72
- with_token: '{"id": "MOCK_FEED_ITEM"}'
73
- message=Hello, world, from the test suite, testing comments!:
74
- post:
75
- with_token: '{"id": "MOCK_FEED_ITEM"}'
76
- message=the cats are asleep:
77
- post:
78
- with_token: '{"id": "FEED_ITEM_CATS"}'
79
- message=Hello, world, from the test suite delete method!:
80
- post:
81
- with_token: '{"id": "FEED_ITEM_DELETE"}'
82
- link=http://www.contextoptional.com/&message=Hello, world, from the test suite again!&name=Context Optional:
83
- post:
84
- with_token: '{"id": "FEED_ITEM_CONTEXT"}'
85
- /me/photos:
86
- source=[FILE]:
87
- post:
88
- <<: *token_required
89
- with_token: '{"id": "MOCK_PHOTO"}'
90
- message=This is the test message&source=[FILE]:
91
- post:
92
- <<: *token_required
93
- with_token: '{"id": "MOCK_PHOTO"}'
94
- /koppel:
95
- no_args:
96
- get:
97
- with_token: '{"id": 1, "name": 1, "updated_time": 1}'
98
- no_token: '{"id": 1, "name": 1}'
99
-
100
- /contextoptional:
101
- no_args:
102
- get:
103
- with_token: '{"id": 1, "name": 1}'
104
- no_token: '{"id": 1, "name": 1}'
105
-
106
- /contextoptional/photos:
107
- no_args:
108
- get:
109
- with_token: '{"data": [{}], "paging": {"previous": "https:\/\/graph.facebook.com\/7204941866\/photos?limit=25&until=2008-09-15T18%3A30%3A25%2B0000", "next": "https:\/\/graph.facebook.com\/7204941866\/photos?limit=25&until=2008-09-15T18%3A30%3A25%2B0000"}}'
110
- no_token: '{"data": [{}], "paging": {"previous": "https:\/\/graph.facebook.com\/7204941866\/photos?limit=25&until=2008-09-15T18%3A30%3A25%2B0000", "next": "https:\/\/graph.facebook.com\/7204941866\/photos?limit=25&until=2008-09-15T18%3A30%3A25%2B0000"}}'
111
-
112
- /lukeshepard/likes:
113
- no_args:
114
- get:
115
- <<: *token_required
116
- with_token: '{"data": [{}]}'
117
-
118
- /chris.baclig/picture:
119
- no_args:
120
- get:
121
- no_token:
122
- code: 302
123
- headers:
124
- Location: http://facebook.com/
125
- with_token:
126
- code: 302
127
- headers:
128
- Location: http://facebook.com/
129
- type=large:
130
- get:
131
- no_token:
132
- code: 302
133
- headers:
134
- Location: http://facebook.com/large
135
- with_token:
136
- code: 302
137
- headers:
138
- Location: http://facebook.com/large
139
-
140
-
141
- /search:
142
- q=facebook:
143
- get:
144
- with_token: '{"data": [{"id": "507731521_100412693339488"}], "paging": {"previous": "https:\/\/graph.facebook.com\/7204941866\/photos?limit=25&until=2008-09-15T18%3A30%3A25%2B0000", "next": "https:\/\/graph.facebook.com\/7204941866\/photos?limit=25&until=2008-09-15T18%3A30%3A25%2B0000"}}'
145
- no_token: '{"data": [{"id": "507731521_100412693339488"}], "paging": {"previous": "https:\/\/graph.facebook.com\/7204941866\/photos?limit=25&until=2008-09-15T18%3A30%3A25%2B0000", "next": "https:\/\/graph.facebook.com\/7204941866\/photos?limit=25&until=2008-09-15T18%3A30%3A25%2B0000"}}'
146
- "limit=25&q=facebook&until=2010-09-23T21:17:33+0000":
147
- get:
148
- with_token: '{"data": [{"id": "507731521_100412693339488"}], "paging": {"previous": "https:\/\/graph.facebook.com\/7204941866\/photos?limit=25&until=2008-09-15T18%3A30%3A25%2B0000", "next": "https:\/\/graph.facebook.com\/7204941866\/photos?limit=25&until=2008-09-15T18%3A30%3A25%2B0000"}}'
149
- no_token: '{"data": [{"id": "507731521_100412693339488"}], "paging": {"previous": "https:\/\/graph.facebook.com\/7204941866\/photos?limit=25&until=2008-09-15T18%3A30%3A25%2B0000", "next": "https:\/\/graph.facebook.com\/7204941866\/photos?limit=25&until=2008-09-15T18%3A30%3A25%2B0000"}}'
150
-
151
- '/115349521819193_113815981982767':
152
- no_args:
153
- delete:
154
- <<: *token_required
155
-
156
- # -- OAuth responses --
157
- /oauth/access_token:
158
- client_id=<%= APP_ID %>&client_secret=<%= SECRET %>&code=<%= OAUTH_CODE %>&redirect_uri=<%= OAUTH_DATA["callback_url"] %>:
159
- get:
160
- no_token: access_token=<%= ACCESS_TOKEN %>
161
- client_id=<%= APP_ID %>&client_secret=<%= SECRET %>&code=foo&redirect_uri=<%= OAUTH_DATA["callback_url"] %>:
162
- get:
163
- <<: *oauth_error
164
- client_id=<%= APP_ID %>&client_secret=<%= SECRET %>&type=client_cred:
165
- post:
166
- no_token: access_token=<%= ACCESS_TOKEN %>
167
- /oauth/exchange_sessions:
168
- client_id=<%= APP_ID %>&client_secret=<%= SECRET %>&sessions=<%= OAUTH_DATA["session_key"] %>&type=client_cred:
169
- post:
170
- no_token: '[{"access_token":"<%= ACCESS_TOKEN %>","expires":4315}]'
171
- client_id=<%= APP_ID %>&client_secret=<%= SECRET %>&sessions=<%= OAUTH_DATA["multiple_session_keys"].join(",") %>&type=client_cred:
172
- post:
173
- no_token: '[{"access_token":"<%= ACCESS_TOKEN %>","expires":4315}, {"access_token":"<%= ACCESS_TOKEN %>","expires":4315}]'
174
- client_id=<%= APP_ID %>&client_secret=<%= SECRET %>&sessions=<%= ["foo"].concat(OAUTH_DATA["multiple_session_keys"]).join(",") %>&type=client_cred:
175
- post:
176
- no_token: '[null, {"access_token":"<%= ACCESS_TOKEN %>","expires":4315}, {"access_token":"<%= ACCESS_TOKEN %>","expires":4315}]'
177
- client_id=<%= APP_ID %>&client_secret=<%= SECRET %>&sessions=foo,bar&type=client_cred:
178
- post:
179
- no_token: '[null, null]'
180
- client_id=<%= APP_ID %>&client_secret=<%= SECRET %>&sessions=foo&type=client_cred:
181
- post:
182
- no_token: '[null]'
183
-
184
-
185
-
186
- # -- Subscription Responses --
187
- /<%= APP_ID %>/subscriptions:
188
- callback_url=<%= SUBSCRIPTION_DATA["subscription_path"] %>&fields=name&object=user&verify_token=<%= SUBSCRIPTION_DATA["verify_token"] %>:
189
- post:
190
- with_token:
191
- code: 200
192
- callback_url=<%= SUBSCRIPTION_DATA["subscription_path"] %>foo&fields=name&object=user&verify_token=<%= SUBSCRIPTION_DATA["verify_token"] %>:
193
- post:
194
- with_token: '{"error":{"type":"Exception","message":"(#2200) subscription validation failed"}}'
195
- callback_url=foo&fields=name&object=user&verify_token=<%= SUBSCRIPTION_DATA["verify_token"] %>:
196
- post:
197
- with_token: '{"error":{"type":"Exception","message":"(#100) callback_url URL is not properly formatted"}}'
198
- object=user:
199
- delete:
200
- with_token:
201
- code: 200
202
- object=kittens:
203
- delete:
204
- with_token: '{"error":{"type":"Exception","message":"(#100) Invalid parameter"}}'
205
- no_args:
206
- delete:
207
- with_token:
208
- code: 200
209
- get:
210
- with_token: '{"data":[{"callback_url":"http://oauth.twoalex.com/subscriptions", "fields":["name"], "object":"user", "active":true}]}'
211
-
212
-
213
- callback_url=<%= SUBSCRIPTION_DATA["subscription_path"] %>:
214
- get:
215
- with_token: '{"data":[{"callback_url":"http://oauth.twoalex.com/subscriptions", "fields":["name"], "object":"user", "active":true}]}'
216
-
217
- # -- Mock Item Responses --
218
-
219
- /MOCK_FEED_ITEM/likes:
220
- no_args:
221
- post:
222
- with_token: '{"id": "MOCK_LIKE"}'
223
-
224
- /MOCK_FEED_ITEM/comments:
225
- message=it's my comment!:
226
- post:
227
- with_token: '{"id": "MOCK_COMMENT"}'
228
-
229
- /MOCK_FEED_ITEM:
230
- no_args:
231
- <<: *item_deleted
232
-
233
- /FEED_ITEM_CONTEXT:
234
- no_args:
235
- <<: *item_deleted
236
- get:
237
- with_token: '{"link":"http://www.contextoptional.com/", "name": "Context Optional"}'
238
-
239
- /FEED_ITEM_CATS:
240
- no_args:
241
- <<: *item_deleted
242
- get:
243
- with_token: '{"message": "the cats are asleep"}'
244
-
245
- /FEED_ITEM_DELETE:
246
- no_args:
247
- <<: *item_deleted
248
-
249
- /FEED_ITEM_DELETE/likes:
250
- no_args:
251
- <<: *item_deleted
252
- post:
253
- with_token: 'true'
254
-
255
- /MOCK_COMMENT:
256
- no_args:
257
- <<: *item_deleted
258
- get:
259
- with_token: "{\"message\": \"it\'s my comment!\"}"
260
- /MOCK_PHOTO:
261
- no_args:
262
- <<: *item_deleted
263
- get:
264
- with_token: "{\"name\": \"This is the test message\"}"
265
-
266
- # -- Mock Test User Responses --
267
- /<%= APP_ID %>/accounts/test-users:
268
- installed=false:
269
- <<: *test_user_no_perms
270
- installed=false&permissions=read_stream:
271
- <<: *test_user_no_perms
272
- installed=true&permissions=read_stream:
273
- post:
274
- with_token: '{"id": "999999999", "access_token":"119908831367602|o3wswWQ88LYjEC9-ukR_gjRIOMw.", "login_url":"https://www.facebook.com/platform/test_account.."}'
275
- installed=true&permissions=read_stream,user_interests:
276
- post:
277
- with_token: '{"id": "888888888", "access_token":"119908831367602|o3wswWQ88LYjEC9-ukR_gjRIOMw.", "login_url":"https://www.facebook.com/platform/test_account.."}'
278
- no_args:
279
- get:
280
- with_token: '{"data":[{"id": "999999999", "access_token":"119908831367602|o3wswWQ88LYjEC9-ukR_gjRIOMw.", "login_url":"https://www.facebook.com/platform/test_account.."}, {"id": "888888888", "access_token":"119908831367602|o3wswWQ88LYjEC9-ukR_gjRIOMw.", "login_url":"https://www.facebook.com/platform/test_account.."}]}'
281
-
282
- /999999999:
283
- no_args:
284
- <<: *item_deleted
285
-
286
- /9999999991:
287
- no_args:
288
- delete:
289
- with_token: '{"error": {"type": "OAuthException", "message": "Error validating verification code."}}'
290
-
291
- /888888888:
292
- no_args:
293
- <<: *item_deleted
294
-
295
- /777777777:
296
- no_args:
297
- <<: *item_deleted
298
-
299
- /999999999/friends/888888888:
300
- no_args:
301
- get:
302
- with_token: 'true'
303
-
304
- /888888888/friends/999999999:
305
- no_args:
306
- get:
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
+ /method/fql.multiquery:
28
+ 'queries=<%= MultiJson.encode({"query1" => "select post_id from stream where source_id = me()", "query2" => "select fromid from comment where post_id in (select post_id from #query1)", "query3" => "select uid, name from user where uid in (select fromid from #query2)"}) %>':
29
+ get:
30
+ with_token: '[{"name":"query1", "fql_result_set":[]},{"name":"query2", "fql_result_set":[]},{"name":"query3", "fql_result_set":[]}]'
31
+ 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"}]}'
32
+ 'queries=<%= MultiJson.encode({"query1" => "select first_name from user where uid = 216743", "query2" => "select first_name from user where uid = 2905623"}) %>':
33
+ get:
34
+ with_token: '[{"name":"query1", "fql_result_set":[{"first_name":"Chris"}]},{"name":"query2", "fql_result_set":[{"first_name":"Alex"}]}]'
35
+ no_token: '[{"name":"query1", "fql_result_set":[{"first_name":"Chris"}]},{"name":"query2", "fql_result_set":[{"first_name":"Alex"}]}]'
36
+
37
+
38
+
39
+
40
+ # ====== GRAPH API =====
41
+ graph_api:
42
+
43
+ # -- Common Responses --
44
+
45
+ # Error responses for when a token is required, but not given
46
+ token_required_responses: &token_required
47
+ no_token: '{"error":{"type":"OAuthAccessTokenException", "message":"An access token is required to request this resource."}}'
48
+
49
+ # Common mock item responses
50
+ item_deleted: &item_deleted
51
+ delete:
52
+ with_token: 'true'
53
+
54
+ # OAuth error response
55
+ oauth_error: &oauth_error
56
+ no_token: '{"error": {"type": "OAuthException", "message": "Error validating verification code."}}'
57
+
58
+ # Subscription error response
59
+ verification_error: &verification_error
60
+ with_token: '{"error": {"type": "OAuthException", "message": "Error validating verification code."}}'
61
+
62
+ test_user_no_perms: &test_user_no_perms
63
+ post:
64
+ with_token: '{"id": "777777777", "access_token":"<%= APP_ACCESS_TOKEN %>", "login_url":"https://www.facebook.com/platform/test_account.."}'
65
+
66
+ test_user_befriended: &test_user_befriended
67
+ post:
68
+ with_token: 'true'
69
+
70
+ # -- Stubbed Responses --
71
+ root:
72
+ ids=contextoptional,naitik:
73
+ get:
74
+ with_token: '{"contextoptional":"{}","naitik":"{}"}'
75
+ no_token: '{"contextoptional":"{}","naitik":"{}"}'
76
+ # Ruby 1.8.7 and 1.9.2 generate JSON with different key ordering, hence we have to dynamically generate it here
77
+ batch=<%= MultiJson.encode([{"method" => "get", "relative_url" => "me"},{"method" => "get", "relative_url" => "koppel"}]) %>:
78
+ post:
79
+ with_token: '[{"body":"{\"id\":\"123\"}"}, {"body":"{\"id\":\"456\"}"}]'
80
+ batch=<%= MultiJson.encode([{"method" => "get", "relative_url" => "me/picture"}]) %>:
81
+ post:
82
+ with_token: '[{"headers":[{"name":"Location","value":"http://google.com"}]}]'
83
+ batch=<%= MultiJson.encode([{"method" => "get", "relative_url" => "me"},{"method" => "get", "relative_url" => "me/friends"}]) %>:
84
+ post:
85
+ with_token: '[{"body":"{\"id\":\"123\"}"}, {"body":"{\"data\":[]}"}]'
86
+ batch=<%= MultiJson.encode([{"method"=>"get", "relative_url"=>"me"}, {"method"=>"get", "relative_url"=>"#{OAUTH_DATA["app_id"]}/insights?access_token=#{CGI.escape APP_ACCESS_TOKEN}"}]) %>:
87
+ post:
88
+ with_token: '[{"body":"{\"id\":\"123\"}"}, {"body":"{\"data\":[]}"}]'
89
+ batch=<%= MultiJson.encode([{"method"=>"get", "relative_url"=>"#{OAUTH_DATA["app_id"]}/insights"}, {"method"=>"get", "relative_url"=>"koppel?access_token=#{CGI.escape APP_ACCESS_TOKEN}"}]) %>:
90
+ post:
91
+ with_token: '[{"body": "{\"error\":{\"type\":\"AnError\", \"message\":\"An error occurred!.\"}}"},{"body":"{\"id\":\"123\"}"}]'
92
+ batch=<%= MultiJson.encode([{"method"=>"post", "relative_url"=>"FEED_ITEM_BATCH/likes"}, {"method"=>"delete", "relative_url"=> "FEED_ITEM_BATCH"}]) %>:
93
+ post:
94
+ with_token: '[{"body": "{\"id\": \"MOCK_LIKE\"}"},{"body":true}]'
95
+ batch=<%= MultiJson.encode([{"method" => "get", "relative_url" => "me/friends?limit=5", "name" => "get-friends"}, {"method" => "get", "relative_url" => "?ids=#{CGI.escape "{result=get-friends:$.data.*.id}"}"}]) %>:
96
+ post:
97
+ with_token: '[null,{"body":"{}"}]'
98
+ batch=<%= MultiJson.encode([{"method" => "get", "relative_url" => "me/friends?limit=5", "name" => "get-friends", "omit_response_on_success" => false}, {"method" => "get", "relative_url" => "?ids=#{CGI.escape "{result=get-friends:$.data.*.id}"}"}]) %>:
99
+ post:
100
+ with_token: '[{"body":"{\"data\":[]}"},{"body":"{}"}]'
101
+ batch=<%= MultiJson.encode([{"method" => "get", "relative_url" => "me/friends?limit=5"}, {"method" => "get", "relative_url" => "?ids=#{CGI.escape "{result=i-dont-exist:$.data.*.id}"}"}]) %>:
102
+ post:
103
+ with_token: '{"error":190,"error_description":"Error validating access token."}'
104
+ batch=<%= MultiJson.encode([{"method" => "post", "relative_url" => "method/fql.query", "body" => "query=select+name+from+user+where+uid%3D4"}]) %>:
105
+ post:
106
+ with_token: '[{"body":"[{\"name\":\"Mark Zuckerberg\"}]"}]'
107
+
108
+ # dependencies
109
+ batch=<%= MultiJson.encode([{"method"=>"get", "relative_url"=>"me", "name" => "getme"}, {"method"=>"get", "relative_url"=>"koppel", "depends_on" => "getme"}]) %>:
110
+ post: &batch_dependent
111
+ with_token: '[null,{"body":"{\"id\":\"123\"}"}]'
112
+ batch=<%= MultiJson.encode([{"method"=>"get", "relative_url"=>"#{OAUTH_DATA["app_id"]}/insights", "name" => "getdata"}, {"method"=>"get", "relative_url"=>"koppel", "depends_on" => "getdata"}]) %>:
113
+ post:
114
+ with_token: '[{"body": "{\"error\":{\"type\":\"AnError\", \"message\":\"An error occurred!.\"}}"},null]'
115
+
116
+ # attached files tests
117
+ batch=<%= MultiJson.encode([{"method"=>"post", "relative_url"=>"me/photos", "attached_files" => "op1_file0"}]) %>&op1_file0=[FILE]:
118
+ post:
119
+ with_token: '[{"body": "{\"error\":{\"type\":\"AnError\", \"message\":\"An error occurred!.\"}}"},null]'
120
+ batch=<%= MultiJson.encode([{"method"=>"post", "relative_url"=>"me/photos", "attached_files" => "op1_file0"}]) %>&op1_file0=[FILE]:
121
+ post:
122
+ with_token: '[{"body":"{\"id\": \"MOCK_PHOTO\"}"}]'
123
+ batch=<%= MultiJson.encode([{"method"=>"post", "relative_url"=>"me/photos", "attached_files" => "op1_file0"}, {"method"=>"post", "relative_url"=>"koppel/photos", "attached_files" => "op2_file0"}]) %>&op1_file0=[FILE]&op2_file0=[FILE]:
124
+ post:
125
+ with_token: '[{"body":"{\"id\": \"MOCK_PHOTO\"}"}, {"body":"{\"id\": \"MOCK_PHOTO\"}"}]'
126
+
127
+
128
+ /me:
129
+ no_args:
130
+ get:
131
+ <<: *token_required
132
+ with_token: '{"updated_time": 1}'
133
+ fields=id:
134
+ get:
135
+ with_token: '{"id": "216743"}'
136
+
137
+ /me/feed:
138
+ message=Hello, world, from the test suite!:
139
+ post:
140
+ with_token: '{"id": "MOCK_FEED_ITEM"}'
141
+ message=Hello, world, from the test suite, testing comments!:
142
+ post:
143
+ with_token: '{"id": "MOCK_FEED_ITEM"}'
144
+ message=the cats are asleep:
145
+ post:
146
+ with_token: '{"id": "FEED_ITEM_CATS"}'
147
+ message=Hello, world, from the test suite delete method!:
148
+ post:
149
+ with_token: '{"id": "FEED_ITEM_DELETE"}'
150
+ message=Hello, world, from the test suite batch API!:
151
+ post:
152
+ with_token: '{"id": "FEED_ITEM_BATCH"}'
153
+ link=http://oauth.twoalex.com/&message=Hello, world, from the test suite again!&name=OAuth Playground:
154
+ post:
155
+ with_token: '{"id": "FEED_ITEM_CONTEXT"}'
156
+ /me/photos:
157
+ source=[FILE]:
158
+ post:
159
+ <<: *token_required
160
+ with_token: '{"id": "MOCK_PHOTO"}'
161
+ message=This is the test message&source=[FILE]:
162
+ post:
163
+ <<: *token_required
164
+ with_token: '{"id": "MOCK_PHOTO"}'
165
+ /me/videos:
166
+ source=[FILE]:
167
+ post:
168
+ <<: *token_required
169
+ with_token: '{"id": "MOCK_PHOTO"}'
170
+ message=This is the test message&source=[FILE]:
171
+ post:
172
+ <<: *token_required
173
+ with_token: '{"id": "MOCK_PHOTO"}'
174
+
175
+ /koppel:
176
+ no_args:
177
+ get:
178
+ with_token: '{"id": 1, "name": 1, "updated_time": 1}'
179
+ no_token: '{"id": 1, "name": 1}'
180
+
181
+ /contextoptional:
182
+ no_args:
183
+ get:
184
+ with_token: '{"id": 1, "name": 1}'
185
+ no_token: '{"id": 1, "name": 1}'
186
+
187
+ /contextoptional/photos:
188
+ no_args:
189
+ get:
190
+ with_token: '{"data": [{}], "paging": {"previous": "https:\/\/graph.facebook.com\/7204941866\/photos?limit=25&until=2008-09-15T18%3A30%3A25%2B0000", "next": "https:\/\/graph.facebook.com\/7204941866\/photos?limit=25&until=2008-09-15T18%3A30%3A25%2B0000"}}'
191
+ no_token: '{"data": [{}], "paging": {"previous": "https:\/\/graph.facebook.com\/7204941866\/photos?limit=25&until=2008-09-15T18%3A30%3A25%2B0000", "next": "https:\/\/graph.facebook.com\/7204941866\/photos?limit=25&until=2008-09-15T18%3A30%3A25%2B0000"}}'
192
+
193
+ /lukeshepard/likes:
194
+ no_args:
195
+ get:
196
+ <<: *token_required
197
+ with_token: '{"data": [{}]}'
198
+
199
+ /lukeshepard/picture:
200
+ type=large:
201
+ get:
202
+ no_token:
203
+ code: 302
204
+ headers:
205
+ Location: https://facebook.com/large
206
+ with_token:
207
+ code: 302
208
+ headers:
209
+ Location: https://facebook.com/large
210
+
211
+
212
+ /chris.baclig/picture:
213
+ no_args:
214
+ get:
215
+ no_token:
216
+ code: 302
217
+ headers:
218
+ Location: http://facebook.com/
219
+ with_token:
220
+ code: 302
221
+ headers:
222
+ Location: http://facebook.com/
223
+
224
+ /comments:
225
+ ids=http://developers.facebook.com/blog/post/472:
226
+ get:
227
+ with_token: '{"http://developers.facebook.com/blog/post/472": []}'
228
+ no_token: '{"http://developers.facebook.com/blog/post/472": []}'
229
+ ids=http://developers.facebook.com/blog/post/490,http://developers.facebook.com/blog/post/472:
230
+ get:
231
+ with_token: '{"http://developers.facebook.com/blog/post/490": [], "http://developers.facebook.com/blog/post/472": []}'
232
+ no_token: '{"http://developers.facebook.com/blog/post/490": [], "http://developers.facebook.com/blog/post/472": []}'
233
+ ids=:
234
+ get:
235
+ body: '{"error": {"type": "OAuthException","message": "Cannot specify an empty identifier"}}'
236
+ code: 400
237
+ no_args:
238
+ get:
239
+ body: '{"error": {"type": "Exception","message": "No node specified"}}'
240
+ code: 500
241
+
242
+ /search:
243
+ q=facebook:
244
+ get:
245
+ with_token: '{"data": [{"id": "507731521_100412693339488"}], "paging": {"previous": "https:\/\/graph.facebook.com\/7204941866\/photos?limit=25&until=2008-09-15T18%3A30%3A25%2B0000", "next": "https:\/\/graph.facebook.com\/7204941866\/photos?limit=25&until=2008-09-15T18%3A30%3A25%2B0000"}}'
246
+ no_token: '{"data": [{"id": "507731521_100412693339488"}], "paging": {"previous": "https:\/\/graph.facebook.com\/7204941866\/photos?limit=25&until=2008-09-15T18%3A30%3A25%2B0000", "next": "https:\/\/graph.facebook.com\/7204941866\/photos?limit=25&until=2008-09-15T18%3A30%3A25%2B0000"}}'
247
+ "limit=25&q=facebook&until=2010-09-23T21:17:33+0000":
248
+ get:
249
+ with_token: '{"data": [{"id": "507731521_100412693339488"}], "paging": {"previous": "https:\/\/graph.facebook.com\/7204941866\/photos?limit=25&until=2008-09-15T18%3A30%3A25%2B0000", "next": "https:\/\/graph.facebook.com\/7204941866\/photos?limit=25&until=2008-09-15T18%3A30%3A25%2B0000"}}'
250
+ no_token: '{"data": [{"id": "507731521_100412693339488"}], "paging": {"previous": "https:\/\/graph.facebook.com\/7204941866\/photos?limit=25&until=2008-09-15T18%3A30%3A25%2B0000", "next": "https:\/\/graph.facebook.com\/7204941866\/photos?limit=25&until=2008-09-15T18%3A30%3A25%2B0000"}}'
251
+
252
+ '/115349521819193_113815981982767':
253
+ no_args:
254
+ delete:
255
+ <<: *token_required
256
+
257
+ # -- OAuth responses --
258
+ /oauth/access_token:
259
+ client_id=<%= APP_ID %>&client_secret=<%= SECRET %>&code=<%= OAUTH_CODE %>&redirect_uri=<%= OAUTH_DATA["callback_url"] %>:
260
+ get:
261
+ no_token: access_token=<%= ACCESS_TOKEN %>
262
+ client_id=<%= APP_ID %>&client_secret=<%= SECRET %>&code=foo&redirect_uri=<%= OAUTH_DATA["callback_url"] %>:
263
+ get:
264
+ <<: *oauth_error
265
+ client_id=<%= APP_ID %>&client_secret=<%= SECRET %>&type=client_cred:
266
+ post:
267
+ no_token: access_token=<%= APP_ACCESS_TOKEN %>
268
+ /oauth/exchange_sessions:
269
+ client_id=<%= APP_ID %>&client_secret=<%= SECRET %>&sessions=<%= OAUTH_DATA["session_key"] %>&type=client_cred:
270
+ post:
271
+ no_token: '[{"access_token":"<%= ACCESS_TOKEN %>","expires":4315}]'
272
+ client_id=<%= APP_ID %>&client_secret=<%= SECRET %>&sessions=<%= OAUTH_DATA["multiple_session_keys"].join(",") %>&type=client_cred:
273
+ post:
274
+ no_token: '[{"access_token":"<%= ACCESS_TOKEN %>","expires":4315}, {"access_token":"<%= ACCESS_TOKEN %>","expires":4315}]'
275
+ client_id=<%= APP_ID %>&client_secret=<%= SECRET %>&sessions=<%= ["foo"].concat(OAUTH_DATA["multiple_session_keys"]).join(",") %>&type=client_cred:
276
+ post:
277
+ no_token: '[null, {"access_token":"<%= ACCESS_TOKEN %>","expires":4315}, {"access_token":"<%= ACCESS_TOKEN %>","expires":4315}]'
278
+ client_id=<%= APP_ID %>&client_secret=<%= SECRET %>&sessions=foo,bar&type=client_cred:
279
+ post:
280
+ no_token: '[null, null]'
281
+ client_id=<%= APP_ID %>&client_secret=<%= SECRET %>&sessions=foo&type=client_cred:
282
+ post:
283
+ no_token: '[null]'
284
+
285
+
286
+
287
+ # -- Subscription Responses --
288
+ /<%= APP_ID %>/subscriptions:
289
+ callback_url=<%= SUBSCRIPTION_DATA["subscription_path"] %>&fields=name&object=user&verify_token=<%= SUBSCRIPTION_DATA["verify_token"] %>:
290
+ post:
291
+ with_token:
292
+ code: 200
293
+ callback_url=<%= SUBSCRIPTION_DATA["subscription_path"] %>foo&fields=name&object=user&verify_token=<%= SUBSCRIPTION_DATA["verify_token"] %>:
294
+ post:
295
+ with_token: '{"error":{"type":"Exception","message":"(#2200) subscription validation failed"}}'
296
+ callback_url=foo&fields=name&object=user&verify_token=<%= SUBSCRIPTION_DATA["verify_token"] %>:
297
+ post:
298
+ with_token: '{"error":{"type":"Exception","message":"(#100) callback_url URL is not properly formatted"}}'
299
+ object=user:
300
+ delete:
301
+ with_token:
302
+ code: 200
303
+ object=kittens:
304
+ delete:
305
+ with_token: '{"error":{"type":"Exception","message":"(#100) Invalid parameter"}}'
306
+ no_args:
307
+ delete:
308
+ with_token:
309
+ code: 200
310
+ get:
311
+ with_token: '{"data":[{"callback_url":"http://oauth.twoalex.com/subscriptions", "fields":["name"], "object":"user", "active":true}]}'
312
+
313
+
314
+ callback_url=<%= SUBSCRIPTION_DATA["subscription_path"] %>:
315
+ get:
316
+ with_token: '{"data":[{"callback_url":"http://oauth.twoalex.com/subscriptions", "fields":["name"], "object":"user", "active":true}]}'
317
+
318
+ # -- Mock Item Responses --
319
+
320
+ /MOCK_FEED_ITEM/likes:
321
+ no_args:
322
+ post:
323
+ with_token: '{"id": "MOCK_LIKE"}'
324
+
325
+ /MOCK_FEED_ITEM/comments:
326
+ message=it's my comment!:
327
+ post:
328
+ with_token: '{"id": "MOCK_COMMENT"}'
329
+
330
+ /MOCK_FEED_ITEM:
331
+ no_args:
332
+ <<: *item_deleted
333
+
334
+ /FEED_ITEM_CONTEXT:
335
+ no_args:
336
+ <<: *item_deleted
337
+ get:
338
+ with_token: '{"link":"http://oauth.twoalex.com/", "name": "OAuth Playground"}'
339
+
340
+ /FEED_ITEM_CATS:
341
+ no_args:
342
+ <<: *item_deleted
343
+ get:
344
+ with_token: '{"message": "the cats are asleep"}'
345
+
346
+ /FEED_ITEM_DELETE:
347
+ no_args:
348
+ <<: *item_deleted
349
+
350
+ /FEED_ITEM_DELETE/likes:
351
+ no_args:
352
+ <<: *item_deleted
353
+ post:
307
354
  with_token: 'true'
355
+
356
+ /MOCK_COMMENT:
357
+ no_args:
358
+ <<: *item_deleted
359
+ get:
360
+ with_token: "{\"message\": \"it's my comment!\"}"
361
+ /MOCK_PHOTO:
362
+ no_args:
363
+ <<: *item_deleted
364
+ get:
365
+ with_token: "{\"name\": \"This is the test message\"}"
366
+
367
+ # -- Mock Test User Responses --
368
+ /<%= APP_ID %>/accounts/test-users:
369
+ installed=false:
370
+ <<: *test_user_no_perms
371
+ installed=false&permissions=read_stream:
372
+ <<: *test_user_no_perms
373
+ installed=true&permissions=read_stream:
374
+ post:
375
+ with_token: '{"id": "999999999", "access_token":"<%= ACCESS_TOKEN %>", "login_url":"https://www.facebook.com/platform/test_account.."}'
376
+ installed=true&permissions=read_stream,user_interests:
377
+ post:
378
+ with_token: '{"id": "888888888", "access_token":"<%= ACCESS_TOKEN %>", "login_url":"https://www.facebook.com/platform/test_account.."}'
379
+ no_args:
380
+ get:
381
+ with_token: '{"data":[{"id": "999999999", "access_token":"<%= ACCESS_TOKEN %>", "login_url":"https://www.facebook.com/platform/test_account.."}, {"id": "888888888", "access_token":"119908831367602|o3wswWQ88LYjEC9-ukR_gjRIOMw.", "login_url":"https://www.facebook.com/platform/test_account.."}]}'
382
+
383
+ /999999999:
384
+ no_args:
385
+ <<: *item_deleted
386
+
387
+ /999999999/friends/888888888:
388
+ no_args:
389
+ post:
390
+ with_token: 'true'
391
+
392
+
393
+ /9999999991:
394
+ no_args:
395
+ delete:
396
+ with_token: '{"error": {"type": "OAuthException", "message": "Error validating verification code."}}'
397
+
398
+ /888888888:
399
+ no_args:
400
+ <<: *item_deleted
401
+
402
+ /888888888/friends/999999999:
403
+ no_args:
404
+ <<: *test_user_befriended
405
+
406
+
407
+ /777777777:
408
+ no_args:
409
+ <<: *item_deleted