koala 1.0.0.rc → 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.
- data/.autotest +12 -0
- data/.gitignore +3 -1
- data/.travis.yml +8 -0
- data/CHANGELOG +40 -18
- data/Gemfile +4 -0
- data/LICENSE +1 -1
- data/autotest/discover.rb +1 -0
- data/koala.gemspec +8 -8
- data/lib/koala/batch_operation.rb +74 -0
- data/lib/koala/graph_api.rb +103 -102
- data/lib/koala/graph_batch_api.rb +87 -0
- data/lib/koala/graph_collection.rb +54 -0
- data/lib/koala/http_services/net_http_service.rb +92 -0
- data/lib/koala/http_services/typhoeus_service.rb +37 -0
- data/lib/koala/http_services.rb +13 -113
- data/lib/koala/oauth.rb +181 -0
- data/lib/koala/realtime_updates.rb +5 -14
- data/lib/koala/rest_api.rb +13 -8
- data/lib/koala/uploadable_io.rb +137 -77
- data/lib/koala.rb +39 -215
- data/readme.md +58 -32
- data/spec/cases/api_base_spec.rb +4 -4
- data/spec/cases/graph_api_batch_spec.rb +609 -0
- data/spec/cases/http_services/http_service_spec.rb +87 -12
- data/spec/cases/http_services/net_http_service_spec.rb +259 -77
- data/spec/cases/http_services/typhoeus_service_spec.rb +29 -21
- data/spec/cases/koala_spec.rb +55 -0
- data/spec/cases/oauth_spec.rb +40 -5
- data/spec/cases/realtime_updates_spec.rb +3 -3
- data/spec/cases/test_users_spec.rb +1 -1
- data/spec/cases/uploadable_io_spec.rb +56 -14
- data/spec/fixtures/cat.m4v +0 -0
- data/spec/fixtures/mock_facebook_responses.yml +110 -13
- data/spec/spec_helper.rb +2 -1
- data/spec/support/graph_api_shared_examples.rb +108 -37
- data/spec/support/json_testing_fix.rb +18 -0
- data/spec/support/mock_http_service.rb +57 -56
- data/spec/support/rest_api_shared_examples.rb +131 -7
- data/spec/support/setup_mocks_or_live.rb +3 -4
- metadata +33 -49
|
@@ -1,16 +1,14 @@
|
|
|
1
1
|
require 'spec_helper'
|
|
2
2
|
|
|
3
3
|
|
|
4
|
-
|
|
5
|
-
include Koala::TyphoeusService
|
|
6
|
-
end
|
|
4
|
+
Deer = Koala::TyphoeusService
|
|
7
5
|
|
|
8
6
|
describe "TyphoeusService" do
|
|
9
7
|
|
|
10
8
|
describe "TyphoeusService module holder class Deer" do
|
|
11
9
|
before :each do
|
|
12
|
-
# reset
|
|
13
|
-
Deer.always_use_ssl = nil
|
|
10
|
+
# reset global settings
|
|
11
|
+
Deer.always_use_ssl = Deer.proxy = Deer.timeout = nil
|
|
14
12
|
end
|
|
15
13
|
|
|
16
14
|
it "should define a make_request static module method" do
|
|
@@ -29,55 +27,55 @@ describe "TyphoeusService" do
|
|
|
29
27
|
@mock_http_response = stub(Typhoeus::Response, :code => 1, :headers_hash => @mock_headers_hash, :body => @mock_body)
|
|
30
28
|
|
|
31
29
|
# Typhoeus is an included module, so we stub methods on Deer itself
|
|
32
|
-
|
|
33
|
-
|
|
30
|
+
Typhoeus::Request.stub(:post).and_return(@mock_http_response)
|
|
31
|
+
Typhoeus::Request.stub(:get).and_return(@mock_http_response)
|
|
34
32
|
end
|
|
35
33
|
|
|
36
34
|
it "should use POST if verb is not GET" do
|
|
37
|
-
|
|
35
|
+
Typhoeus::Request.should_receive(:post).and_return(@mock_http_response)
|
|
38
36
|
Deer.make_request('anything', {}, 'anything')
|
|
39
37
|
end
|
|
40
38
|
|
|
41
39
|
it "should use GET if that verb is specified" do
|
|
42
|
-
|
|
40
|
+
Typhoeus::Request.should_receive(:get).and_return(@mock_http_response)
|
|
43
41
|
Deer.make_request('anything', {}, 'get')
|
|
44
42
|
end
|
|
45
43
|
|
|
46
44
|
describe "the connection" do
|
|
47
45
|
it "should use SSL if the request has an access token" do
|
|
48
|
-
|
|
46
|
+
Typhoeus::Request.should_receive(:post).with(/https\:/, anything)
|
|
49
47
|
|
|
50
48
|
Deer.make_request('anything', {"access_token" => "123"}, 'anything')
|
|
51
49
|
end
|
|
52
50
|
|
|
53
51
|
it "should use SSL if always_use_ssl is true, even if there's no token" do
|
|
54
|
-
|
|
52
|
+
Typhoeus::Request.should_receive(:post).with(/https\:/, anything)
|
|
55
53
|
|
|
56
54
|
Deer.always_use_ssl = true
|
|
57
55
|
Deer.make_request('anything', {}, 'anything')
|
|
58
56
|
end
|
|
59
57
|
|
|
60
58
|
it "should use SSL if the :use_ssl option is provided, even if there's no token" do
|
|
61
|
-
|
|
59
|
+
Typhoeus::Request.should_receive(:post).with(/https\:/, anything)
|
|
62
60
|
|
|
63
61
|
Deer.always_use_ssl = true
|
|
64
62
|
Deer.make_request('anything', {}, 'anything', :use_ssl => true)
|
|
65
63
|
end
|
|
66
64
|
|
|
67
65
|
it "should not use SSL if always_use_ssl is false and there's no token" do
|
|
68
|
-
|
|
66
|
+
Typhoeus::Request.should_receive(:post).with(/http\:/, anything)
|
|
69
67
|
|
|
70
68
|
Deer.make_request('anything', {}, 'anything')
|
|
71
69
|
end
|
|
72
70
|
|
|
73
71
|
it "should use the graph server by default" do
|
|
74
|
-
|
|
72
|
+
Typhoeus::Request.should_receive(:post).with(Regexp.new(Koala::Facebook::GRAPH_SERVER), anything)
|
|
75
73
|
|
|
76
74
|
Deer.make_request('anything', {}, 'anything')
|
|
77
75
|
end
|
|
78
76
|
|
|
79
77
|
it "should use the REST server if the :rest_api option is true" do
|
|
80
|
-
|
|
78
|
+
Typhoeus::Request.should_receive(:post).with(Regexp.new(Koala::Facebook::REST_SERVER), anything)
|
|
81
79
|
|
|
82
80
|
Deer.make_request('anything', {}, 'anything', :rest_api => true)
|
|
83
81
|
end
|
|
@@ -85,35 +83,45 @@ describe "TyphoeusService" do
|
|
|
85
83
|
|
|
86
84
|
it "should pass the arguments to Typhoeus under the :params key" do
|
|
87
85
|
args = {:a => 2}
|
|
88
|
-
|
|
86
|
+
Typhoeus::Request.should_receive(:post).with(anything, hash_including(:params => args))
|
|
89
87
|
|
|
90
88
|
Deer.make_request('anything', args, "post")
|
|
91
89
|
end
|
|
92
90
|
|
|
93
91
|
it "should add the method to the arguments if the method isn't get or post" do
|
|
94
92
|
method = "telekenesis"
|
|
95
|
-
|
|
93
|
+
Typhoeus::Request.should_receive(:post).with(anything, hash_including(:params => {:method => method}))
|
|
96
94
|
|
|
97
95
|
Deer.make_request('anything', {}, method)
|
|
98
96
|
end
|
|
99
97
|
|
|
100
98
|
it "should pass :typhoeus_options to Typhoeus if provided" do
|
|
101
99
|
t_options = {:a => :b}
|
|
102
|
-
|
|
100
|
+
Typhoeus::Request.should_receive(:post).with(anything, hash_including(t_options))
|
|
103
101
|
|
|
104
102
|
Deer.make_request("anything", {}, "post", :typhoeus_options => t_options)
|
|
105
103
|
end
|
|
106
|
-
|
|
104
|
+
|
|
105
|
+
it "should pass proxy and timeout :typhoeus_options to Typhoeus if set globally" do
|
|
106
|
+
Deer.proxy = "http://defaultproxy"
|
|
107
|
+
Deer.timeout = 20
|
|
108
|
+
|
|
109
|
+
t_options = {:proxy => "http://defaultproxy", :timeout => 20}
|
|
110
|
+
Typhoeus::Request.should_receive(:post).with(anything, hash_including(t_options))
|
|
111
|
+
|
|
112
|
+
Deer.make_request("anything", {}, "post")
|
|
113
|
+
end
|
|
114
|
+
|
|
107
115
|
# for live tests, run the Graph API tests with Typhoues, which will run file uploads
|
|
108
116
|
it "should pass any files directly on to Typhoues" do
|
|
109
117
|
args = {:file => File.new(__FILE__, "r")}
|
|
110
|
-
|
|
118
|
+
Typhoeus::Request.should_receive(:post).with(anything, hash_including(:params => args)).and_return(Typhoeus::Response.new)
|
|
111
119
|
Deer.make_request("anything", args, :post)
|
|
112
120
|
end
|
|
113
121
|
|
|
114
122
|
it "should include the path in the request" do
|
|
115
123
|
path = "/a/b/c/1"
|
|
116
|
-
|
|
124
|
+
Typhoeus::Request.should_receive(:post).with(Regexp.new(path), anything)
|
|
117
125
|
|
|
118
126
|
Deer.make_request(path, {}, "post")
|
|
119
127
|
end
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
require 'spec_helper'
|
|
2
|
+
|
|
3
|
+
describe "Koala" do
|
|
4
|
+
it "has an http_service accessor" do
|
|
5
|
+
Koala.respond_to?(:http_service)
|
|
6
|
+
end
|
|
7
|
+
|
|
8
|
+
it "should let an http service be set" do
|
|
9
|
+
current_service = Koala.http_service
|
|
10
|
+
Koala.http_service = Koala::MockHTTPService
|
|
11
|
+
Koala.http_service.should == Koala::MockHTTPService
|
|
12
|
+
# reset the service back to the original one (important for live tests)
|
|
13
|
+
Koala.http_service = current_service
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
it "sets Net::HTTP as the base service" do
|
|
17
|
+
Koala.base_http_service.should == Koala::NetHTTPService
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
describe ".always_use_ssl" do
|
|
21
|
+
it "should be added" do
|
|
22
|
+
# in Ruby 1.8, .methods returns strings
|
|
23
|
+
# in Ruby 1.9, .method returns symbols
|
|
24
|
+
Koala.methods.collect {|m| m.to_sym}.should include(:always_use_ssl)
|
|
25
|
+
Koala.methods.collect {|m| m.to_sym}.should include(:always_use_ssl=)
|
|
26
|
+
end
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
describe ".make_request" do
|
|
30
|
+
|
|
31
|
+
before :each do
|
|
32
|
+
@old_service = Koala.http_service
|
|
33
|
+
Koala.http_service = Koala::MockHTTPService
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
after :each do
|
|
37
|
+
Koala.http_service = @old_service
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
it "should use SSL if Koala.always_use_ssl is set to true, even if there's no token" do
|
|
41
|
+
Koala.http_service.should_receive(:make_request).with(anything, anything, anything, hash_including(:use_ssl => true))
|
|
42
|
+
|
|
43
|
+
Koala.always_use_ssl = true
|
|
44
|
+
Koala.make_request('anything', {}, 'anything')
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
it "should allow the caller to override the http_service" do
|
|
48
|
+
http_service = stub
|
|
49
|
+
http_service.should_receive(:make_request)
|
|
50
|
+
|
|
51
|
+
Koala.make_request(anything, anything, anything, :http_service => http_service)
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
end
|
|
55
|
+
end
|
data/spec/cases/oauth_spec.rb
CHANGED
|
@@ -157,7 +157,6 @@ describe "Koala::Facebook::OAuth" do
|
|
|
157
157
|
end
|
|
158
158
|
|
|
159
159
|
describe "for access token URLs" do
|
|
160
|
-
|
|
161
160
|
# url_for_access_token
|
|
162
161
|
it "should generate a properly formatted OAuth token URL when provided a code" do
|
|
163
162
|
url = @oauth.url_for_access_token(@code)
|
|
@@ -204,6 +203,12 @@ describe "Koala::Facebook::OAuth" do
|
|
|
204
203
|
it "should raise an error when get_access_token is called with a bad code" do
|
|
205
204
|
lambda { @oauth.get_access_token("foo") }.should raise_error(Koala::Facebook::APIError)
|
|
206
205
|
end
|
|
206
|
+
|
|
207
|
+
it "should pass on any options provided to make_request" do
|
|
208
|
+
options = {:a => 2}
|
|
209
|
+
Koala.should_receive(:make_request).with(anything, anything, anything, hash_including(options)).and_return(Koala::Response.new(200, "", {}))
|
|
210
|
+
@oauth.get_access_token(@code, options)
|
|
211
|
+
end
|
|
207
212
|
end
|
|
208
213
|
|
|
209
214
|
describe "get_app_access_token_info" do
|
|
@@ -211,11 +216,17 @@ describe "Koala::Facebook::OAuth" do
|
|
|
211
216
|
result = @oauth.get_app_access_token_info
|
|
212
217
|
result.should be_a(Hash)
|
|
213
218
|
end
|
|
214
|
-
|
|
219
|
+
|
|
215
220
|
it "should include the access token" do
|
|
216
221
|
result = @oauth.get_app_access_token_info
|
|
217
222
|
result["access_token"].should
|
|
218
223
|
end
|
|
224
|
+
|
|
225
|
+
it "should pass on any options provided to make_request" do
|
|
226
|
+
options = {:a => 2}
|
|
227
|
+
Koala.should_receive(:make_request).with(anything, anything, anything, hash_including(options)).and_return(Koala::Response.new(200, "", {}))
|
|
228
|
+
@oauth.get_app_access_token_info(options)
|
|
229
|
+
end
|
|
219
230
|
end
|
|
220
231
|
|
|
221
232
|
describe "get_app_acess_token" do
|
|
@@ -229,6 +240,12 @@ describe "Koala::Facebook::OAuth" do
|
|
|
229
240
|
original = @oauth.get_app_access_token_info
|
|
230
241
|
result.should == original["access_token"]
|
|
231
242
|
end
|
|
243
|
+
|
|
244
|
+
it "should pass on any options provided to make_request" do
|
|
245
|
+
options = {:a => 2}
|
|
246
|
+
Koala.should_receive(:make_request).with(anything, anything, anything, hash_including(options)).and_return(Koala::Response.new(200, "", {}))
|
|
247
|
+
@oauth.get_app_access_token(options)
|
|
248
|
+
end
|
|
232
249
|
end
|
|
233
250
|
|
|
234
251
|
describe "protected methods" do
|
|
@@ -299,12 +316,18 @@ describe "Koala::Facebook::OAuth" do
|
|
|
299
316
|
@oauth.should_receive(:fetch_token_string).and_return("")
|
|
300
317
|
lambda { @oauth.get_token_info_from_session_keys(@oauth_data["multiple_session_keys"]) }.should raise_error(Koala::Facebook::APIError)
|
|
301
318
|
end
|
|
319
|
+
|
|
320
|
+
it "should pass on any options provided to make_request" do
|
|
321
|
+
options = {:a => 2}
|
|
322
|
+
Koala.should_receive(:make_request).with(anything, anything, anything, hash_including(options)).and_return(Koala::Response.new(200, "[{}]", {}))
|
|
323
|
+
@oauth.get_token_info_from_session_keys([], options)
|
|
324
|
+
end
|
|
302
325
|
end
|
|
303
326
|
|
|
304
327
|
describe "with get_tokens_from_session_keys" do
|
|
305
328
|
it "should call get_token_info_from_session_keys" do
|
|
306
329
|
args = @oauth_data["multiple_session_keys"]
|
|
307
|
-
@oauth.should_receive(:get_token_info_from_session_keys).with(args).and_return([])
|
|
330
|
+
@oauth.should_receive(:get_token_info_from_session_keys).with(args, anything).and_return([])
|
|
308
331
|
@oauth.get_tokens_from_session_keys(args)
|
|
309
332
|
end
|
|
310
333
|
|
|
@@ -325,12 +348,18 @@ describe "Koala::Facebook::OAuth" do
|
|
|
325
348
|
# it should return nil for each of the invalid ones
|
|
326
349
|
result.each_with_index {|r, index| index > 0 ? r.should(be_a(String)) : r.should(be_nil)}
|
|
327
350
|
end
|
|
351
|
+
|
|
352
|
+
it "should pass on any options provided to make_request" do
|
|
353
|
+
options = {:a => 2}
|
|
354
|
+
Koala.should_receive(:make_request).with(anything, anything, anything, hash_including(options)).and_return(Koala::Response.new(200, "[{}]", {}))
|
|
355
|
+
@oauth.get_tokens_from_session_keys([], options)
|
|
356
|
+
end
|
|
328
357
|
end
|
|
329
358
|
|
|
330
359
|
describe "get_token_from_session_key" do
|
|
331
360
|
it "should call get_tokens_from_session_keys when the get_token_from_session_key is called" do
|
|
332
361
|
key = @oauth_data["session_key"]
|
|
333
|
-
@oauth.should_receive(:get_tokens_from_session_keys).with([key]).and_return([])
|
|
362
|
+
@oauth.should_receive(:get_tokens_from_session_keys).with([key], anything).and_return([])
|
|
334
363
|
@oauth.get_token_from_session_key(key)
|
|
335
364
|
end
|
|
336
365
|
|
|
@@ -349,6 +378,12 @@ describe "Koala::Facebook::OAuth" do
|
|
|
349
378
|
result = @oauth.get_token_from_session_key("foo")
|
|
350
379
|
result.should be_nil
|
|
351
380
|
end
|
|
381
|
+
|
|
382
|
+
it "should pass on any options provided to make_request" do
|
|
383
|
+
options = {:a => 2}
|
|
384
|
+
Koala.should_receive(:make_request).with(anything, anything, anything, hash_including(options)).and_return(Koala::Response.new(200, "[{}]", {}))
|
|
385
|
+
@oauth.get_token_from_session_key("", options)
|
|
386
|
+
end
|
|
352
387
|
end
|
|
353
388
|
end
|
|
354
389
|
|
|
@@ -356,7 +391,7 @@ describe "Koala::Facebook::OAuth" do
|
|
|
356
391
|
# the signed request code is ported directly from Facebook
|
|
357
392
|
# so we only need to test at a high level that it works
|
|
358
393
|
it "should throw an error if the algorithm is unsupported" do
|
|
359
|
-
|
|
394
|
+
MultiJson.stub(:decode).and_return("algorithm" => "my fun algorithm")
|
|
360
395
|
lambda { @oauth.parse_signed_request(@signed_request) }.should raise_error
|
|
361
396
|
end
|
|
362
397
|
|
|
@@ -43,19 +43,19 @@ describe "Koala::Facebook::RealtimeUpdates" do
|
|
|
43
43
|
it "should not allow write access to app_id" do
|
|
44
44
|
updates = Koala::Facebook::RealtimeUpdates.new(:app_id => @app_id, :app_access_token => @app_access_token)
|
|
45
45
|
# this should not throw errors
|
|
46
|
-
|
|
46
|
+
updates.methods.map(&:to_sym).should_not include(:app_id=)
|
|
47
47
|
end
|
|
48
48
|
|
|
49
49
|
it "should not allow write access to app_access_token" do
|
|
50
50
|
updates = Koala::Facebook::RealtimeUpdates.new(:app_id => @app_id, :app_access_token => @app_access_token)
|
|
51
51
|
# this should not throw errors
|
|
52
|
-
|
|
52
|
+
updates.methods.map(&:to_sym).should_not include(:app_access_token=)
|
|
53
53
|
end
|
|
54
54
|
|
|
55
55
|
it "should not allow write access to secret" do
|
|
56
56
|
updates = Koala::Facebook::RealtimeUpdates.new(:app_id => @app_id, :app_access_token => @app_access_token)
|
|
57
57
|
# this should not throw errors
|
|
58
|
-
|
|
58
|
+
updates.methods.map(&:to_sym).should_not include(:secret=)
|
|
59
59
|
end
|
|
60
60
|
|
|
61
61
|
# init with secret / fetching the token
|
|
@@ -16,7 +16,7 @@ describe "Koala::Facebook::TestUsers" do
|
|
|
16
16
|
raise Exception, "Must supply OAuth app id, secret, app_access_token, and callback to run live subscription tests!"
|
|
17
17
|
end
|
|
18
18
|
|
|
19
|
-
@is_mock =
|
|
19
|
+
@is_mock = Koala.http_service.respond_to?(:mock?) && Koala.http_service.mock?
|
|
20
20
|
end
|
|
21
21
|
|
|
22
22
|
describe "when initializing" do
|
|
@@ -9,6 +9,21 @@ module Koala::MIME
|
|
|
9
9
|
end
|
|
10
10
|
|
|
11
11
|
describe "Koala::UploadableIO" do
|
|
12
|
+
def rails_3_mocks
|
|
13
|
+
tempfile = stub('Tempfile', :path => "foo")
|
|
14
|
+
uploaded_file = stub('ActionDispatch::Http::UploadedFile',
|
|
15
|
+
:content_type => true,
|
|
16
|
+
:tempfile => tempfile
|
|
17
|
+
)
|
|
18
|
+
tempfile.stub!(:respond_to?).with(:path).and_return(true)
|
|
19
|
+
|
|
20
|
+
[tempfile, uploaded_file]
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
def sinatra_mocks
|
|
24
|
+
{:type => "type", :tempfile => "Tempfile"}
|
|
25
|
+
end
|
|
26
|
+
|
|
12
27
|
describe "the constructor" do
|
|
13
28
|
describe "when given a file path" do
|
|
14
29
|
before(:each) do
|
|
@@ -29,6 +44,12 @@ describe "Koala::UploadableIO" do
|
|
|
29
44
|
stub_type = @koala_io_params[1] = stub('Content Type')
|
|
30
45
|
Koala::UploadableIO.new(*@koala_io_params).content_type.should == stub_type
|
|
31
46
|
end
|
|
47
|
+
|
|
48
|
+
it "should detect that NetHTTPService must be used" do
|
|
49
|
+
@koala_io_params[0] = mock
|
|
50
|
+
@koala_io_params[0].stub!(:read)
|
|
51
|
+
Koala::UploadableIO.new(*@koala_io_params).requires_base_http_service.should be_true
|
|
52
|
+
end
|
|
32
53
|
end
|
|
33
54
|
|
|
34
55
|
describe "and no content type" do
|
|
@@ -63,13 +84,7 @@ describe "Koala::UploadableIO" do
|
|
|
63
84
|
|
|
64
85
|
describe "when given a Rails 3 ActionDispatch::Http::UploadedFile" do
|
|
65
86
|
before(:each) do
|
|
66
|
-
@tempfile
|
|
67
|
-
@uploaded_file = stub('ActionDispatch::Http::UploadedFile',
|
|
68
|
-
:content_type => true,
|
|
69
|
-
:tempfile => @tempfile
|
|
70
|
-
)
|
|
71
|
-
|
|
72
|
-
@tempfile.stub!(:respond_to?).with(:path).and_return(true)
|
|
87
|
+
@tempfile, @uploaded_file = rails_3_mocks
|
|
73
88
|
end
|
|
74
89
|
|
|
75
90
|
it "should get the content type via the content_type method" do
|
|
@@ -87,10 +102,7 @@ describe "Koala::UploadableIO" do
|
|
|
87
102
|
|
|
88
103
|
describe "when given a Sinatra file parameter hash" do
|
|
89
104
|
before(:each) do
|
|
90
|
-
@file_hash =
|
|
91
|
-
:type => "type",
|
|
92
|
-
:tempfile => "Tempfile"
|
|
93
|
-
}
|
|
105
|
+
@file_hash = sinatra_mocks
|
|
94
106
|
end
|
|
95
107
|
|
|
96
108
|
it "should get the content type from the :type key" do
|
|
@@ -130,9 +142,19 @@ describe "Koala::UploadableIO" do
|
|
|
130
142
|
UploadIO.stub!(:new).with(anything, anything, anything).and_return(@upload_io)
|
|
131
143
|
end
|
|
132
144
|
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
145
|
+
context "if no filename was provided" do
|
|
146
|
+
it "should call the constructor with the content type, file name, and a dummy file name" do
|
|
147
|
+
UploadIO.should_receive(:new).with(BEACH_BALL_PATH, "content/type", anything).and_return(@upload_io)
|
|
148
|
+
Koala::UploadableIO.new(BEACH_BALL_PATH, "content/type").to_upload_io.should == @upload_io
|
|
149
|
+
end
|
|
150
|
+
end
|
|
151
|
+
|
|
152
|
+
context "if a filename was provided" do
|
|
153
|
+
it "should call the constructor with the content type, file name, and the filename" do
|
|
154
|
+
filename = "file"
|
|
155
|
+
UploadIO.should_receive(:new).with(BEACH_BALL_PATH, "content/type", filename).and_return(@upload_io)
|
|
156
|
+
Koala::UploadableIO.new(BEACH_BALL_PATH, "content/type", filename).to_upload_io
|
|
157
|
+
end
|
|
136
158
|
end
|
|
137
159
|
end
|
|
138
160
|
|
|
@@ -148,4 +170,24 @@ describe "Koala::UploadableIO" do
|
|
|
148
170
|
Koala::UploadableIO.new(BEACH_BALL_PATH).to_file.should == result
|
|
149
171
|
end
|
|
150
172
|
end
|
|
173
|
+
|
|
174
|
+
describe "#binary_content?" do
|
|
175
|
+
it "returns true for Rails 3 file uploads" do
|
|
176
|
+
Koala::UploadableIO.binary_content?(rails_3_mocks.last).should be_true
|
|
177
|
+
end
|
|
178
|
+
|
|
179
|
+
it "returns true for Sinatra file uploads" do
|
|
180
|
+
Koala::UploadableIO.binary_content?(rails_3_mocks.last).should be_true
|
|
181
|
+
end
|
|
182
|
+
|
|
183
|
+
it "returns true for File objects" do
|
|
184
|
+
Koala::UploadableIO.binary_content?(File.open(BEACH_BALL_PATH)).should be_true
|
|
185
|
+
end
|
|
186
|
+
|
|
187
|
+
it "returns false for everything else" do
|
|
188
|
+
Koala::UploadableIO.binary_content?(StringIO.new).should be_false
|
|
189
|
+
Koala::UploadableIO.binary_content?(BEACH_BALL_PATH).should be_false
|
|
190
|
+
Koala::UploadableIO.binary_content?(nil).should be_false
|
|
191
|
+
end
|
|
192
|
+
end
|
|
151
193
|
end # describe UploadableIO
|
|
Binary file
|
|
@@ -24,6 +24,18 @@ rest_api:
|
|
|
24
24
|
with_token: '[{"read_stream":1}]'
|
|
25
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
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
|
+
|
|
27
39
|
|
|
28
40
|
# ====== GRAPH API =====
|
|
29
41
|
graph_api:
|
|
@@ -49,7 +61,7 @@ graph_api:
|
|
|
49
61
|
|
|
50
62
|
test_user_no_perms: &test_user_no_perms
|
|
51
63
|
post:
|
|
52
|
-
with_token: '{"id": "777777777", "access_token":"<%=
|
|
64
|
+
with_token: '{"id": "777777777", "access_token":"<%= APP_ACCESS_TOKEN %>", "login_url":"https://www.facebook.com/platform/test_account.."}'
|
|
53
65
|
|
|
54
66
|
test_user_befriended: &test_user_befriended
|
|
55
67
|
post:
|
|
@@ -59,8 +71,60 @@ graph_api:
|
|
|
59
71
|
root:
|
|
60
72
|
ids=contextoptional,naitik:
|
|
61
73
|
get:
|
|
62
|
-
with_token: '
|
|
63
|
-
no_token: '
|
|
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
|
+
|
|
64
128
|
/me:
|
|
65
129
|
no_args:
|
|
66
130
|
get:
|
|
@@ -83,6 +147,9 @@ graph_api:
|
|
|
83
147
|
message=Hello, world, from the test suite delete method!:
|
|
84
148
|
post:
|
|
85
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"}'
|
|
86
153
|
link=http://oauth.twoalex.com/&message=Hello, world, from the test suite again!&name=OAuth Playground:
|
|
87
154
|
post:
|
|
88
155
|
with_token: '{"id": "FEED_ITEM_CONTEXT"}'
|
|
@@ -95,6 +162,16 @@ graph_api:
|
|
|
95
162
|
post:
|
|
96
163
|
<<: *token_required
|
|
97
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
|
+
|
|
98
175
|
/koppel:
|
|
99
176
|
no_args:
|
|
100
177
|
get:
|
|
@@ -118,29 +195,49 @@ graph_api:
|
|
|
118
195
|
get:
|
|
119
196
|
<<: *token_required
|
|
120
197
|
with_token: '{"data": [{}]}'
|
|
121
|
-
|
|
122
|
-
/
|
|
123
|
-
|
|
198
|
+
|
|
199
|
+
/lukeshepard/picture:
|
|
200
|
+
type=large:
|
|
124
201
|
get:
|
|
125
202
|
no_token:
|
|
126
203
|
code: 302
|
|
127
204
|
headers:
|
|
128
|
-
Location:
|
|
205
|
+
Location: https://facebook.com/large
|
|
129
206
|
with_token:
|
|
130
207
|
code: 302
|
|
131
208
|
headers:
|
|
132
|
-
Location:
|
|
133
|
-
|
|
209
|
+
Location: https://facebook.com/large
|
|
210
|
+
|
|
211
|
+
|
|
212
|
+
/chris.baclig/picture:
|
|
213
|
+
no_args:
|
|
134
214
|
get:
|
|
135
215
|
no_token:
|
|
136
216
|
code: 302
|
|
137
217
|
headers:
|
|
138
|
-
Location: http://facebook.com/
|
|
218
|
+
Location: http://facebook.com/
|
|
139
219
|
with_token:
|
|
140
220
|
code: 302
|
|
141
221
|
headers:
|
|
142
|
-
Location: http://facebook.com/
|
|
222
|
+
Location: http://facebook.com/
|
|
143
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
|
|
144
241
|
|
|
145
242
|
/search:
|
|
146
243
|
q=facebook:
|
|
@@ -167,7 +264,7 @@ graph_api:
|
|
|
167
264
|
<<: *oauth_error
|
|
168
265
|
client_id=<%= APP_ID %>&client_secret=<%= SECRET %>&type=client_cred:
|
|
169
266
|
post:
|
|
170
|
-
no_token: access_token=<%=
|
|
267
|
+
no_token: access_token=<%= APP_ACCESS_TOKEN %>
|
|
171
268
|
/oauth/exchange_sessions:
|
|
172
269
|
client_id=<%= APP_ID %>&client_secret=<%= SECRET %>&sessions=<%= OAUTH_DATA["session_key"] %>&type=client_cred:
|
|
173
270
|
post:
|
|
@@ -309,4 +406,4 @@ graph_api:
|
|
|
309
406
|
|
|
310
407
|
/777777777:
|
|
311
408
|
no_args:
|
|
312
|
-
<<: *item_deleted
|
|
409
|
+
<<: *item_deleted
|
data/spec/spec_helper.rb
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
begin
|
|
2
2
|
require 'bundler/setup'
|
|
3
3
|
rescue LoadError
|
|
4
|
-
puts '
|
|
4
|
+
puts 'Although not required, bundler is recommended for running the tests.'
|
|
5
5
|
end
|
|
6
6
|
|
|
7
7
|
# load the libraries
|
|
@@ -9,6 +9,7 @@ require 'koala'
|
|
|
9
9
|
|
|
10
10
|
# load testing data libraries
|
|
11
11
|
require 'support/live_testing_data_helper'
|
|
12
|
+
require 'support/json_testing_fix' # ensure consistent to_json behavior
|
|
12
13
|
require 'support/mock_http_service'
|
|
13
14
|
require 'support/rest_api_shared_examples'
|
|
14
15
|
require 'support/graph_api_shared_examples'
|