koala 0.4 → 3.7.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 (71) hide show
  1. checksums.yaml +7 -0
  2. data/.github/workflows/test.yml +32 -0
  3. data/.gitignore +9 -0
  4. data/.rspec +1 -0
  5. data/.yardopts +3 -0
  6. data/Gemfile +25 -0
  7. data/ISSUE_TEMPLATE +25 -0
  8. data/LICENSE +22 -0
  9. data/Manifest +32 -5
  10. data/PULL_REQUEST_TEMPLATE +11 -0
  11. data/Rakefile +12 -12
  12. data/changelog.md +781 -0
  13. data/code_of_conduct.md +74 -0
  14. data/koala.gemspec +28 -24
  15. data/lib/koala/api/batch_operation.rb +86 -0
  16. data/lib/koala/api/graph_api_methods.rb +504 -0
  17. data/lib/koala/api/graph_batch_api.rb +167 -0
  18. data/lib/koala/api/graph_collection.rb +129 -0
  19. data/lib/koala/api/graph_error_checker.rb +72 -0
  20. data/lib/koala/api.rb +159 -0
  21. data/lib/koala/configuration.rb +56 -0
  22. data/lib/koala/errors.rb +126 -0
  23. data/lib/koala/http_service/request.rb +133 -0
  24. data/lib/koala/http_service/response.rb +20 -0
  25. data/lib/koala/http_service/uploadable_io.rb +183 -0
  26. data/lib/koala/http_service.rb +108 -0
  27. data/lib/koala/oauth.rb +342 -0
  28. data/lib/koala/realtime_updates.rb +151 -0
  29. data/lib/koala/test_users.rb +189 -0
  30. data/lib/koala/utils.rb +41 -0
  31. data/lib/koala/version.rb +3 -0
  32. data/lib/koala.rb +51 -291
  33. data/readme.md +269 -21
  34. data/spec/cases/api_spec.rb +362 -0
  35. data/spec/cases/configuration_spec.rb +11 -0
  36. data/spec/cases/error_spec.rb +143 -0
  37. data/spec/cases/graph_api_batch_spec.rb +788 -0
  38. data/spec/cases/graph_api_spec.rb +76 -0
  39. data/spec/cases/graph_collection_spec.rb +192 -0
  40. data/spec/cases/graph_error_checker_spec.rb +147 -0
  41. data/spec/cases/http_service/request_spec.rb +250 -0
  42. data/spec/cases/http_service/response_spec.rb +24 -0
  43. data/spec/cases/http_service_spec.rb +280 -0
  44. data/spec/cases/koala_spec.rb +57 -0
  45. data/spec/cases/koala_test_spec.rb +5 -0
  46. data/spec/cases/oauth_spec.rb +647 -0
  47. data/spec/cases/realtime_updates_spec.rb +327 -0
  48. data/spec/cases/test_users_spec.rb +383 -0
  49. data/spec/cases/uploadable_io_spec.rb +266 -0
  50. data/spec/cases/utils_spec.rb +55 -0
  51. data/spec/fixtures/beach.jpg +0 -0
  52. data/spec/fixtures/cat.m4v +0 -0
  53. data/spec/fixtures/facebook_data.yml +63 -0
  54. data/spec/fixtures/mock_facebook_responses.yml +483 -0
  55. data/spec/fixtures/vcr_cassettes/app_test_accounts.yml +97 -0
  56. data/spec/fixtures/vcr_cassettes/friend_list_next_page.yml +121 -0
  57. data/spec/integration/graph_collection_spec.rb +24 -0
  58. data/spec/spec_helper.rb +25 -0
  59. data/spec/support/custom_matchers.rb +28 -0
  60. data/spec/support/graph_api_shared_examples.rb +534 -0
  61. data/spec/support/koala_test.rb +251 -0
  62. data/spec/support/mock_http_service.rb +140 -0
  63. data/spec/support/uploadable_io_shared_examples.rb +70 -0
  64. metadata +206 -62
  65. data/CHANGELOG +0 -24
  66. data/init.rb +0 -2
  67. data/lib/http_services.rb +0 -60
  68. data/test/facebook_data.yml +0 -5
  69. data/test/koala/facebook_no_access_token_tests.rb +0 -119
  70. data/test/koala/facebook_with_access_token_tests.rb +0 -106
  71. data/test/koala_tests.rb +0 -30
@@ -0,0 +1,327 @@
1
+ require 'spec_helper'
2
+ require 'base64'
3
+
4
+ describe "Koala::Facebook::RealtimeUpdates" do
5
+ before :all do
6
+ # get oauth data
7
+ @app_id = KoalaTest.app_id
8
+ @secret = KoalaTest.secret
9
+ @callback_url = KoalaTest.oauth_test_data["callback_url"]
10
+ @app_access_token = KoalaTest.app_access_token
11
+
12
+ # check OAuth data
13
+ unless @app_id && @secret && @callback_url && @app_access_token
14
+ raise Exception, "Must supply OAuth app id, secret, app_access_token, and callback to run live subscription tests!"
15
+ end
16
+
17
+ # get subscription data
18
+ @verify_token = KoalaTest.subscription_test_data["verify_token"]
19
+ @challenge_data = KoalaTest.subscription_test_data["challenge_data"]
20
+ @subscription_path = KoalaTest.subscription_test_data["subscription_path"]
21
+
22
+ # check subscription data
23
+ unless @verify_token && @challenge_data && @subscription_path
24
+ raise Exception, "Must supply verify_token and equivalent challenge_data to run subscription tests!"
25
+ end
26
+ end
27
+
28
+ before :each do
29
+ @updates = Koala::Facebook::RealtimeUpdates.new(:app_id => @app_id, :secret => @secret)
30
+ end
31
+
32
+ describe ".new" do
33
+ # basic initialization
34
+ it "initializes properly with an app_id and an app_access_token" do
35
+ updates = Koala::Facebook::RealtimeUpdates.new(:app_id => @app_id, :app_access_token => @app_access_token)
36
+ expect(updates).to be_a(Koala::Facebook::RealtimeUpdates)
37
+ end
38
+
39
+ context "with global defaults" do
40
+ let(:app_id) { :app_id }
41
+ let(:app_secret) { :app_secret }
42
+ let(:app_access_token) { :app_access_token }
43
+
44
+ before :each do
45
+ Koala.configure do |config|
46
+ config.app_id = app_id
47
+ config.app_secret = app_secret
48
+ config.app_access_token = app_access_token
49
+ end
50
+ end
51
+
52
+ it "defaults to the configured data if not otherwise provided" do
53
+ rtu = Koala::Facebook::RealtimeUpdates.new
54
+ expect(rtu.app_id).to eq(app_id)
55
+ expect(rtu.secret).to eq(app_secret)
56
+ expect(rtu.app_access_token).to eq(app_access_token)
57
+ end
58
+
59
+ it "lets you override app_id" do
60
+ other_value = :another_id
61
+ rtu = Koala::Facebook::RealtimeUpdates.new(app_id: other_value)
62
+ expect(rtu.app_id).to eq(other_value)
63
+ end
64
+
65
+ it "lets you override secret" do
66
+ other_value = :another_secret
67
+ rtu = Koala::Facebook::RealtimeUpdates.new(secret: other_value)
68
+ expect(rtu.secret).to eq(other_value)
69
+ end
70
+
71
+ it "lets you override app_id" do
72
+ other_value = :another_token
73
+ rtu = Koala::Facebook::RealtimeUpdates.new(app_access_token: other_value)
74
+ expect(rtu.app_access_token).to eq(other_value)
75
+ end
76
+ end
77
+
78
+ # attributes
79
+ it "allows read access to app_id" do
80
+ # in Ruby 1.9, .method returns symbols
81
+ expect(Koala::Facebook::RealtimeUpdates.instance_methods.map(&:to_sym)).to include(:app_id)
82
+ expect(Koala::Facebook::RealtimeUpdates.instance_methods.map(&:to_sym)).not_to include(:app_id=)
83
+ end
84
+
85
+ it "allows read access to app_access_token" do
86
+ # in Ruby 1.9, .method returns symbols
87
+ expect(Koala::Facebook::RealtimeUpdates.instance_methods.map(&:to_sym)).to include(:app_access_token)
88
+ expect(Koala::Facebook::RealtimeUpdates.instance_methods.map(&:to_sym)).not_to include(:app_access_token=)
89
+ end
90
+
91
+ it "allows read access to secret" do
92
+ # in Ruby 1.9, .method returns symbols
93
+ expect(Koala::Facebook::RealtimeUpdates.instance_methods.map(&:to_sym)).to include(:secret)
94
+ expect(Koala::Facebook::RealtimeUpdates.instance_methods.map(&:to_sym)).not_to include(:secret=)
95
+ end
96
+
97
+ it "allows read access to api" do
98
+ # in Ruby 1.9, .method returns symbols
99
+ expect(Koala::Facebook::RealtimeUpdates.instance_methods.map(&:to_sym)).to include(:api)
100
+ expect(Koala::Facebook::RealtimeUpdates.instance_methods.map(&:to_sym)).not_to include(:api=)
101
+ end
102
+
103
+ # init with secret / fetching the token
104
+ it "initializes properly with an app_id and a secret" do
105
+ updates = Koala::Facebook::RealtimeUpdates.new(:app_id => @app_id, :secret => @secret)
106
+ expect(updates).to be_a(Koala::Facebook::RealtimeUpdates)
107
+ end
108
+
109
+ it "sets up the API with the app access token" do
110
+ updates = Koala::Facebook::RealtimeUpdates.new(:app_id => @app_id, :app_access_token => @app_access_token)
111
+ expect(updates.api).to be_a(Koala::Facebook::API)
112
+ expect(updates.api.access_token).to eq(@app_access_token)
113
+ end
114
+ end
115
+
116
+ describe "#app_access_token" do
117
+ it "fetches an app_token from Facebook when provided an app_id and a secret" do
118
+ # integration test
119
+ updates = Koala::Facebook::RealtimeUpdates.new(:app_id => @app_id, :secret => @secret)
120
+ expect(updates.app_access_token).not_to be_nil
121
+ end
122
+
123
+ it "returns the provided token if provided" do
124
+ updates = Koala::Facebook::RealtimeUpdates.new(app_id: @app_id, app_access_token: @app_access_token)
125
+ expect(updates.app_access_token).to eq(@app_access_token)
126
+ end
127
+ end
128
+
129
+ describe "#subscribe" do
130
+ it "makes a POST to the subscription path" do
131
+ expect(@updates.api).to receive(:graph_call).with(@updates.subscription_path, anything, "post", anything)
132
+ @updates.subscribe("user", "name", @subscription_path, @verify_token)
133
+ end
134
+
135
+ it "properly formats the subscription request" do
136
+ obj = "user"
137
+ fields = "name"
138
+ expect(@updates.api).to receive(:graph_call).with(anything, hash_including(
139
+ :object => obj,
140
+ :fields => fields,
141
+ :callback_url => @subscription_path,
142
+ :verify_token => @verify_token
143
+ ), anything, anything)
144
+ @updates.subscribe("user", "name", @subscription_path, @verify_token)
145
+ end
146
+
147
+ it "accepts an options hash" do
148
+ options = {:a => 2, :b => "c"}
149
+ expect(@updates.api).to receive(:graph_call).with(anything, anything, anything, hash_including(options))
150
+ @updates.subscribe("user", "name", @subscription_path, @verify_token, options)
151
+ end
152
+
153
+ describe "in practice" do
154
+ it "sends a subscription request" do
155
+ expect { @updates.subscribe("user", "name", @subscription_path, @verify_token) }.to_not raise_error
156
+ end
157
+
158
+ it "fails if you try to hit an invalid path on your valid server" do
159
+ expect { result = @updates.subscribe("user", "name", @subscription_path + "foo", @verify_token) }.to raise_exception(Koala::Facebook::APIError)
160
+ end
161
+
162
+ it "fails to send a subscription request to an invalid server" do
163
+ expect { @updates.subscribe("user", "name", "foo", @verify_token) }.to raise_exception(Koala::Facebook::APIError)
164
+ end
165
+ end
166
+ end
167
+
168
+ describe "#unsubscribe" do
169
+ it "makes a DELETE to the subscription path" do
170
+ expect(@updates.api).to receive(:graph_call).with(@updates.subscription_path, anything, "delete", anything)
171
+ @updates.unsubscribe("user")
172
+ end
173
+
174
+ it "includes the object if provided" do
175
+ obj = "user"
176
+ expect(@updates.api).to receive(:graph_call).with(anything, hash_including(:object => obj), anything, anything)
177
+ @updates.unsubscribe(obj)
178
+ end
179
+
180
+ it "accepts an options hash" do
181
+ options = {:a => 2, :b => "C"}
182
+ expect(@updates.api).to receive(:graph_call).with(anything, anything, anything, hash_including(options))
183
+ @updates.unsubscribe("user", options)
184
+ end
185
+
186
+ describe "in practice" do
187
+ it "unsubscribes a valid individual object successfully" do
188
+ expect { @updates.unsubscribe("user") }.to_not raise_error
189
+ end
190
+
191
+ it "unsubscribes all subscriptions successfully" do
192
+ expect { @updates.unsubscribe }.to_not raise_error
193
+ end
194
+
195
+ it "fails when an invalid object is provided to unsubscribe" do
196
+ expect { @updates.unsubscribe("kittens") }.to raise_error(Koala::Facebook::APIError)
197
+ end
198
+ end
199
+ end
200
+
201
+ describe "#list_subscriptions" do
202
+ it "GETs the subscription path" do
203
+ expect(@updates.api).to receive(:graph_call).with(@updates.subscription_path, anything, "get", anything)
204
+ @updates.list_subscriptions
205
+ end
206
+
207
+ it "accepts options" do
208
+ options = {:a => 3, :b => "D"}
209
+ expect(@updates.api).to receive(:graph_call).with(anything, anything, anything, hash_including(options))
210
+ @updates.list_subscriptions(options)
211
+ end
212
+
213
+ describe "in practice" do
214
+ it "lists subscriptions properly" do
215
+ expect(@updates.list_subscriptions).to be_a(Array)
216
+ end
217
+ end
218
+ end
219
+
220
+ describe "#subscription_path" do
221
+ it "returns the app_id/subscriptions" do
222
+ expect(@updates.subscription_path).to eq("#{@app_id}/subscriptions")
223
+ end
224
+ end
225
+
226
+ describe "#validate_update" do
227
+ it "raises an error if no secret is defined" do
228
+ updates = Koala::Facebook::RealtimeUpdates.new(:app_id => @app_id, :app_access_token => "foo")
229
+ expect {
230
+ updates.validate_update("", {})
231
+ }.to raise_exception(Koala::Facebook::AppSecretNotDefinedError)
232
+ end
233
+
234
+ it "returns false if there is no X-Hub-Signature header" do
235
+ expect(@updates.validate_update("", {})).to be_falsey
236
+ end
237
+
238
+ it "returns false if the signature doesn't match the body" do
239
+ expect(@updates.validate_update("", {"X-Hub-Signature" => "sha1=badsha1"})).to be_falsey
240
+ end
241
+
242
+ it "results true if the signature matches the body with the secret" do
243
+ body = "BODY"
244
+ signature = OpenSSL::HMAC.hexdigest('sha1', @secret, body).chomp
245
+ expect(@updates.validate_update(body, {"X-Hub-Signature" => "sha1=#{signature}"})).to be_truthy
246
+ end
247
+
248
+ it "results true with alternate HTTP_X_HUB_SIGNATURE header" do
249
+ body = "BODY"
250
+ signature = OpenSSL::HMAC.hexdigest('sha1', @secret, body).chomp
251
+ expect(@updates.validate_update(body, {"HTTP_X_HUB_SIGNATURE" => "sha1=#{signature}"})).to be_truthy
252
+ end
253
+
254
+ end
255
+
256
+ describe ".meet_challenge" do
257
+ it "returns false if hub.mode isn't subscribe" do
258
+ params = {'hub.mode' => 'not subscribe'}
259
+ expect(Koala::Facebook::RealtimeUpdates.meet_challenge(params)).to be_falsey
260
+ end
261
+
262
+ it "doesn't evaluate the block if hub.mode isn't subscribe" do
263
+ params = {'hub.mode' => 'not subscribe'}
264
+ block_evaluated = false
265
+ Koala::Facebook::RealtimeUpdates.meet_challenge(params){|token| block_evaluated = true}
266
+ expect(block_evaluated).to be_falsey
267
+ end
268
+
269
+ it "returns false if not given a verify_token or block" do
270
+ params = {'hub.mode' => 'subscribe'}
271
+ expect(Koala::Facebook::RealtimeUpdates.meet_challenge(params)).to be_falsey
272
+ end
273
+
274
+ describe "and mode is 'subscribe'" do
275
+ before(:each) do
276
+ @params = {'hub.mode' => 'subscribe'}
277
+ end
278
+
279
+ describe "and a token is given" do
280
+ before(:each) do
281
+ @token = 'token'
282
+ @params['hub.verify_token'] = @token
283
+ end
284
+
285
+ it "returns false if the given verify token doesn't match" do
286
+ expect(Koala::Facebook::RealtimeUpdates.meet_challenge(@params, @token + '1')).to be_falsey
287
+ end
288
+
289
+ it "returns the challenge if the given verify token matches" do
290
+ @params['hub.challenge'] = 'challenge val'
291
+ expect(Koala::Facebook::RealtimeUpdates.meet_challenge(@params, @token)).to eq(@params['hub.challenge'])
292
+ end
293
+ end
294
+
295
+ describe "and a block is given" do
296
+ before :each do
297
+ @params['hub.verify_token'] = @token
298
+ end
299
+
300
+ it "gives the block the token as a parameter" do
301
+ Koala::Facebook::RealtimeUpdates.meet_challenge(@params) do |token|
302
+ expect(token).to eq(@token)
303
+ end
304
+ end
305
+
306
+ it "returns false if the given block return false" do
307
+ expect(Koala::Facebook::RealtimeUpdates.meet_challenge(@params) do |token|
308
+ false
309
+ end).to be_falsey
310
+ end
311
+
312
+ it "returns false if the given block returns nil" do
313
+ expect(Koala::Facebook::RealtimeUpdates.meet_challenge(@params) do |token|
314
+ nil
315
+ end).to be_falsey
316
+ end
317
+
318
+ it "returns the challenge if the given block returns true" do
319
+ @params['hub.challenge'] = 'challenge val'
320
+ expect(Koala::Facebook::RealtimeUpdates.meet_challenge(@params) do |token|
321
+ true
322
+ end).to be_truthy
323
+ end
324
+ end
325
+ end
326
+ end
327
+ end