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.
Files changed (40) hide show
  1. data/.autotest +12 -0
  2. data/.gitignore +3 -1
  3. data/.travis.yml +8 -0
  4. data/CHANGELOG +40 -18
  5. data/Gemfile +4 -0
  6. data/LICENSE +1 -1
  7. data/autotest/discover.rb +1 -0
  8. data/koala.gemspec +8 -8
  9. data/lib/koala/batch_operation.rb +74 -0
  10. data/lib/koala/graph_api.rb +103 -102
  11. data/lib/koala/graph_batch_api.rb +87 -0
  12. data/lib/koala/graph_collection.rb +54 -0
  13. data/lib/koala/http_services/net_http_service.rb +92 -0
  14. data/lib/koala/http_services/typhoeus_service.rb +37 -0
  15. data/lib/koala/http_services.rb +13 -113
  16. data/lib/koala/oauth.rb +181 -0
  17. data/lib/koala/realtime_updates.rb +5 -14
  18. data/lib/koala/rest_api.rb +13 -8
  19. data/lib/koala/uploadable_io.rb +137 -77
  20. data/lib/koala.rb +39 -215
  21. data/readme.md +58 -32
  22. data/spec/cases/api_base_spec.rb +4 -4
  23. data/spec/cases/graph_api_batch_spec.rb +609 -0
  24. data/spec/cases/http_services/http_service_spec.rb +87 -12
  25. data/spec/cases/http_services/net_http_service_spec.rb +259 -77
  26. data/spec/cases/http_services/typhoeus_service_spec.rb +29 -21
  27. data/spec/cases/koala_spec.rb +55 -0
  28. data/spec/cases/oauth_spec.rb +40 -5
  29. data/spec/cases/realtime_updates_spec.rb +3 -3
  30. data/spec/cases/test_users_spec.rb +1 -1
  31. data/spec/cases/uploadable_io_spec.rb +56 -14
  32. data/spec/fixtures/cat.m4v +0 -0
  33. data/spec/fixtures/mock_facebook_responses.yml +110 -13
  34. data/spec/spec_helper.rb +2 -1
  35. data/spec/support/graph_api_shared_examples.rb +108 -37
  36. data/spec/support/json_testing_fix.rb +18 -0
  37. data/spec/support/mock_http_service.rb +57 -56
  38. data/spec/support/rest_api_shared_examples.rb +131 -7
  39. data/spec/support/setup_mocks_or_live.rb +3 -4
  40. metadata +33 -49
@@ -1,16 +1,14 @@
1
1
  require 'spec_helper'
2
2
 
3
3
 
4
- module Deer
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 the always_use_ssl parameter
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
- Deer.stub(:post).and_return(@mock_http_response)
33
- Deer.stub(:get).and_return(@mock_http_response)
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
- Deer.should_receive(:post).and_return(@mock_http_response)
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
- Deer.should_receive(:get).and_return(@mock_http_response)
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
- Deer.should_receive(:post).with(/https\:/, anything)
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
- Deer.should_receive(:post).with(/https\:/, anything)
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
- Deer.should_receive(:post).with(/https\:/, anything)
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
- Deer.should_receive(:post).with(/http\:/, anything)
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
- Deer.should_receive(:post).with(Regexp.new(Koala::Facebook::GRAPH_SERVER), anything)
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
- Deer.should_receive(:post).with(Regexp.new(Koala::Facebook::REST_SERVER), anything)
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
- Deer.should_receive(:post).with(anything, hash_including(:params => args))
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
- Deer.should_receive(:post).with(anything, hash_including(:params => {:method => method}))
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
- Deer.should_receive(:post).with(anything, hash_including(t_options))
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
- Deer.should_receive(:post).with(anything, hash_including(:params => args)).and_return(Typhoeus::Response.new)
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
- Deer.should_receive(:post).with(Regexp.new(path), anything)
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
@@ -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
- JSON.stub!(:parse).and_return("algorithm" => "my fun algorithm")
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
- lambda { updates.app_id = 2 }.should raise_error(NoMethodError)
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
- lambda { updates.app_access_token = 2 }.should raise_error(NoMethodError)
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
- lambda { updates.secret = 2 }.should raise_error(NoMethodError)
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 = defined?(Koala::IS_MOCK) && Koala::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 = stub('Tempfile', :path => "foo")
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
- it "should call the constructor with the content type, file name, and a dummy file name" do
134
- UploadIO.should_receive(:new).with(BEACH_BALL_PATH, "content/type", anything).and_return(@upload_io)
135
- Koala::UploadableIO.new(BEACH_BALL_PATH, "content/type").to_upload_io.should == @upload_io
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":"<%= ACCESS_TOKEN %>", "login_url":"https://www.facebook.com/platform/test_account.."}'
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
- /chris.baclig/picture:
123
- no_args:
198
+
199
+ /lukeshepard/picture:
200
+ type=large:
124
201
  get:
125
202
  no_token:
126
203
  code: 302
127
204
  headers:
128
- Location: http://facebook.com/
205
+ Location: https://facebook.com/large
129
206
  with_token:
130
207
  code: 302
131
208
  headers:
132
- Location: http://facebook.com/
133
- type=large:
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/large
218
+ Location: http://facebook.com/
139
219
  with_token:
140
220
  code: 302
141
221
  headers:
142
- Location: http://facebook.com/large
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=<%= 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 'although not required, bundler is recommened for running the tests'
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'