tyler_koala 1.2.0beta

Sign up to get free protection for your applications and to get access to all the features.
Files changed (49) hide show
  1. data/.autotest +12 -0
  2. data/.gitignore +5 -0
  3. data/.travis.yml +9 -0
  4. data/CHANGELOG +185 -0
  5. data/Gemfile +11 -0
  6. data/LICENSE +22 -0
  7. data/Manifest +39 -0
  8. data/Rakefile +16 -0
  9. data/autotest/discover.rb +1 -0
  10. data/koala.gemspec +50 -0
  11. data/lib/koala.rb +119 -0
  12. data/lib/koala/batch_operation.rb +74 -0
  13. data/lib/koala/graph_api.rb +281 -0
  14. data/lib/koala/graph_batch_api.rb +87 -0
  15. data/lib/koala/graph_collection.rb +54 -0
  16. data/lib/koala/http_service.rb +161 -0
  17. data/lib/koala/oauth.rb +181 -0
  18. data/lib/koala/realtime_updates.rb +89 -0
  19. data/lib/koala/rest_api.rb +95 -0
  20. data/lib/koala/test_users.rb +102 -0
  21. data/lib/koala/uploadable_io.rb +180 -0
  22. data/lib/koala/utils.rb +7 -0
  23. data/readme.md +160 -0
  24. data/spec/cases/api_base_spec.rb +101 -0
  25. data/spec/cases/error_spec.rb +30 -0
  26. data/spec/cases/graph_and_rest_api_spec.rb +48 -0
  27. data/spec/cases/graph_api_batch_spec.rb +600 -0
  28. data/spec/cases/graph_api_spec.rb +42 -0
  29. data/spec/cases/http_service_spec.rb +420 -0
  30. data/spec/cases/koala_spec.rb +21 -0
  31. data/spec/cases/oauth_spec.rb +428 -0
  32. data/spec/cases/realtime_updates_spec.rb +198 -0
  33. data/spec/cases/rest_api_spec.rb +41 -0
  34. data/spec/cases/test_users_spec.rb +281 -0
  35. data/spec/cases/uploadable_io_spec.rb +206 -0
  36. data/spec/cases/utils_spec.rb +8 -0
  37. data/spec/fixtures/beach.jpg +0 -0
  38. data/spec/fixtures/cat.m4v +0 -0
  39. data/spec/fixtures/facebook_data.yml +61 -0
  40. data/spec/fixtures/mock_facebook_responses.yml +439 -0
  41. data/spec/spec_helper.rb +43 -0
  42. data/spec/support/graph_api_shared_examples.rb +502 -0
  43. data/spec/support/json_testing_fix.rb +42 -0
  44. data/spec/support/koala_test.rb +163 -0
  45. data/spec/support/mock_http_service.rb +98 -0
  46. data/spec/support/ordered_hash.rb +205 -0
  47. data/spec/support/rest_api_shared_examples.rb +285 -0
  48. data/spec/support/uploadable_io_shared_examples.rb +70 -0
  49. metadata +221 -0
@@ -0,0 +1,41 @@
1
+ require 'spec_helper'
2
+
3
+ describe "Koala::Facebook::RestAPI" do
4
+ describe "class consolidation" do
5
+ before :each do
6
+ Koala::Utils.stub(:deprecate) # avoid actual messages to stderr
7
+ end
8
+
9
+ it "still allows you to instantiate a GraphAndRestAPI object" do
10
+ api = Koala::Facebook::RestAPI.new("token").should be_a(Koala::Facebook::RestAPI)
11
+ end
12
+
13
+ it "ultimately creates an API object" do
14
+ api = Koala::Facebook::RestAPI.new("token").should be_a(Koala::Facebook::API)
15
+ end
16
+
17
+ it "fires a depreciation warning" do
18
+ Koala::Utils.should_receive(:deprecate)
19
+ api = Koala::Facebook::RestAPI.new("token")
20
+ end
21
+ end
22
+
23
+ context "without an access token" do
24
+ before :each do
25
+ @api = Koala::Facebook::API.new
26
+ end
27
+
28
+ it_should_behave_like "Koala RestAPI"
29
+ it_should_behave_like "Koala RestAPI without an access token"
30
+ end
31
+
32
+ context "with an access token" do
33
+ before :each do
34
+ @api = Koala::Facebook::API.new(@token)
35
+ end
36
+
37
+ it_should_behave_like "Koala RestAPI"
38
+ it_should_behave_like "Koala RestAPI with an access token"
39
+ end
40
+
41
+ end
@@ -0,0 +1,281 @@
1
+ require 'spec_helper'
2
+
3
+ describe "Koala::Facebook::TestUsers" do
4
+ context "with access token" do
5
+ before :all do
6
+ # get oauth data
7
+ @app_id = KoalaTest.app_id
8
+ @secret = KoalaTest.secret
9
+ @app_access_token = KoalaTest.app_access_token
10
+
11
+ # check OAuth data
12
+ unless @app_id && @secret && @app_access_token
13
+ raise Exception, "Must supply OAuth app id, secret, app_access_token, and callback to run live subscription tests!"
14
+ end
15
+ end
16
+
17
+ describe "when initializing" do
18
+ # basic initialization
19
+ it "should initialize properly with an app_id and an app_access_token" do
20
+ test_users = Koala::Facebook::TestUsers.new(:app_id => @app_id, :app_access_token => @app_access_token)
21
+ test_users.should be_a(Koala::Facebook::TestUsers)
22
+ end
23
+
24
+ # init with secret / fetching the token
25
+ it "should initialize properly with an app_id and a secret" do
26
+ test_users = Koala::Facebook::TestUsers.new(:app_id => @app_id, :secret => @secret)
27
+ test_users.should be_a(Koala::Facebook::TestUsers)
28
+ end
29
+
30
+ it "should use the OAuth class to fetch a token when provided an app_id and a secret" do
31
+ oauth = Koala::Facebook::OAuth.new(@app_id, @secret)
32
+ token = oauth.get_app_access_token
33
+ oauth.should_receive(:get_app_access_token).and_return(token)
34
+ Koala::Facebook::OAuth.should_receive(:new).with(@app_id, @secret).and_return(oauth)
35
+ test_users = Koala::Facebook::TestUsers.new(:app_id => @app_id, :secret => @secret)
36
+ end
37
+
38
+ # attributes
39
+ it "should allow read access to app_id, app_access_token, and secret" do
40
+ # in Ruby 1.9, .method returns symbols
41
+ Koala::Facebook::TestUsers.instance_methods.map(&:to_sym).should include(:app_id)
42
+ Koala::Facebook::TestUsers.instance_methods.map(&:to_sym).should_not include(:app_id=)
43
+ end
44
+
45
+ it "should allow read access to app_access_token" do
46
+ # in Ruby 1.9, .method returns symbols
47
+ Koala::Facebook::TestUsers.instance_methods.map(&:to_sym).should include(:app_access_token)
48
+ Koala::Facebook::TestUsers.instance_methods.map(&:to_sym).should_not include(:app_access_token=)
49
+ end
50
+
51
+ it "should allow read access to secret" do
52
+ # in Ruby 1.9, .method returns symbols
53
+ Koala::Facebook::TestUsers.instance_methods.map(&:to_sym).should include(:secret)
54
+ Koala::Facebook::TestUsers.instance_methods.map(&:to_sym).should_not include(:secret=)
55
+ end
56
+
57
+ it "should allow read access to api" do
58
+ # in Ruby 1.9, .method returns symbols
59
+ Koala::Facebook::TestUsers.instance_methods.map(&:to_sym).should include(:api)
60
+ Koala::Facebook::TestUsers.instance_methods.map(&:to_sym).should_not include(:api=)
61
+ end
62
+
63
+ # old graph_api accessor
64
+ it "returns the api object when graph_api is called" do
65
+ test_users = Koala::Facebook::TestUsers.new(:app_id => @app_id, :secret => @secret)
66
+ test_users.graph_api.should == test_users.api
67
+ end
68
+
69
+ it "fire a deprecation warning when graph_api is called" do
70
+ test_users = Koala::Facebook::TestUsers.new(:app_id => @app_id, :secret => @secret)
71
+ Koala::Utils.should_receive(:deprecate)
72
+ test_users.graph_api
73
+ end
74
+ end
75
+
76
+ describe "when used without network" do
77
+ before :each do
78
+ @test_users = Koala::Facebook::TestUsers.new({:app_access_token => @app_access_token, :app_id => @app_id})
79
+ end
80
+
81
+ # TEST USER MANAGEMENT
82
+
83
+ describe ".create" do
84
+ it "should create a test user when not given installed" do
85
+ result = @test_users.create(false)
86
+ @temporary_object_id = result["id"]
87
+ result.should be_a(Hash)
88
+ (result["id"] && result["access_token"] && result["login_url"]).should
89
+ end
90
+
91
+ it "should create a test user when not given installed, ignoring permissions" do
92
+ result = @test_users.create(false, "read_stream")
93
+ @temporary_object_id = result["id"]
94
+ result.should be_a(Hash)
95
+ (result["id"] && result["access_token"] && result["login_url"]).should
96
+ end
97
+
98
+ it "should accept permissions as a string" do
99
+ @test_users.graph_api.should_receive(:graph_call).with(anything, hash_including("permissions" => "read_stream,publish_stream"), anything, anything)
100
+ result = @test_users.create(true, "read_stream,publish_stream")
101
+ end
102
+
103
+ it "should accept permissions as an array" do
104
+ @test_users.graph_api.should_receive(:graph_call).with(anything, hash_including("permissions" => "read_stream,publish_stream"), anything, anything)
105
+ result = @test_users.create(true, ["read_stream", "publish_stream"])
106
+ end
107
+
108
+ it "should create a test user when given installed and a permission" do
109
+ result = @test_users.create(true, "read_stream")
110
+ @temporary_object_id = result["id"]
111
+ result.should be_a(Hash)
112
+ (result["id"] && result["access_token"] && result["login_url"]).should
113
+ end
114
+
115
+ it "lets you specify other graph arguments, like uid and access token" do
116
+ args = {:uid => "some test user ID", :owner_access_token => "some owner access token"}
117
+ @test_users.graph_api.should_receive(:graph_call).with(anything, hash_including(args), anything, anything)
118
+ @test_users.create(true, nil, args)
119
+ end
120
+
121
+ it "lets you specify http options that get passed through to the graph call" do
122
+ options = {:some_http_option => true}
123
+ @test_users.graph_api.should_receive(:graph_call).with(anything, anything, anything, options)
124
+ @test_users.create(true, nil, {}, options)
125
+ end
126
+ end
127
+
128
+ describe ".delete" do
129
+ before :each do
130
+ @user1 = @test_users.create(true, "read_stream")
131
+ @user2 = @test_users.create(true, "read_stream,user_interests")
132
+ end
133
+
134
+ after :each do
135
+ @test_users.delete(@user1) if @user1
136
+ @test_users.delete(@user2) if @user2
137
+ end
138
+
139
+ it "should delete a user by id" do
140
+ @test_users.delete(@user1['id']).should be_true
141
+ @user1 = nil
142
+ end
143
+
144
+ it "should delete a user by hash" do
145
+ @test_users.delete(@user2).should be_true
146
+ @user2 = nil
147
+ end
148
+
149
+ it "should not delete users when provided a false ID" do
150
+ lambda { @test_users.delete("#{@user1['id']}1") }.should raise_exception(Koala::Facebook::APIError)
151
+ end
152
+ end
153
+
154
+ describe ".delete_all" do
155
+ it "should delete all users found by the list commnand" do
156
+ array = [1, 2, 3]
157
+ @test_users.should_receive(:list).and_return(array)
158
+ array.each {|i| @test_users.should_receive(:delete).with(i) }
159
+ @test_users.delete_all
160
+ end
161
+ end
162
+
163
+ describe ".update" do
164
+ before :each do
165
+ @updates = {:name => "Foo Baz"}
166
+ end
167
+
168
+ it "makes a POST with the test user Graph API " do
169
+ user = @test_users.create(true)
170
+ @test_users.graph_api.should_receive(:graph_call).with(anything, anything, "post", anything)
171
+ @test_users.update(user, @updates)
172
+ end
173
+
174
+ it "makes a request to the test user with the update params " do
175
+ user = @test_users.create(true)
176
+ @test_users.graph_api.should_receive(:graph_call).with(user["id"], @updates, anything, anything)
177
+ @test_users.update(user, @updates)
178
+ end
179
+
180
+ it "works" do
181
+ user = @test_users.create(true)
182
+ @test_users.update(user, @updates)
183
+ user_info = Koala::Facebook::API.new(user["access_token"]).get_object(user["id"])
184
+ user_info["name"].should == @updates[:name]
185
+ end
186
+ end
187
+
188
+ describe "with existing users" do
189
+ before :each do
190
+ @user1 = @test_users.create(true, "read_stream")
191
+ @user2 = @test_users.create(true, "read_stream,user_interests")
192
+ end
193
+
194
+ after :each do
195
+ @test_users.delete(@user1)
196
+ @test_users.delete(@user2)
197
+ end
198
+
199
+ it "should list test users" do
200
+ result = @test_users.list
201
+ result.should be_an(Array)
202
+ first_user, second_user = result[0], result[1]
203
+ (first_user["id"] && first_user["access_token"] && first_user["login_url"]).should
204
+ (second_user["id"] && second_user["access_token"] && second_user["login_url"]).should
205
+ end
206
+
207
+ it "should make two users into friends with string hashes" do
208
+ result = @test_users.befriend(@user1, @user2)
209
+ result.should be_true
210
+ end
211
+
212
+ it "should make two users into friends with symbol hashes" do
213
+ new_user_1 = {}
214
+ @user1.each_pair {|k, v| new_user_1[k.to_sym] = v}
215
+ new_user_2 = {}
216
+ @user2.each_pair {|k, v| new_user_2[k.to_sym] = v}
217
+
218
+ result = @test_users.befriend(new_user_1, new_user_2)
219
+ result.should be_true
220
+ end
221
+
222
+ it "should not accept user IDs anymore" do
223
+ lambda { @test_users.befriend(@user1["id"], @user2["id"]) }.should raise_exception
224
+ end
225
+ end # with existing users
226
+
227
+ end # when used without network
228
+
229
+ describe "when creating a network of friends" do
230
+ before :each do
231
+ @test_users = Koala::Facebook::TestUsers.new({:app_access_token => @app_access_token, :app_id => @app_id})
232
+ @network = []
233
+
234
+ if KoalaTest.mock_interface?
235
+ id_counter = 999999900
236
+ @test_users.stub!(:create).and_return do
237
+ id_counter += 1
238
+ {"id" => id_counter, "access_token" => @token, "login_url" => "https://www.facebook.com/platform/test_account.."}
239
+ end
240
+ @test_users.stub!(:befriend).and_return(true)
241
+ @test_users.stub!(:delete).and_return(true)
242
+ end
243
+ end
244
+
245
+ describe "tests that create users" do
246
+ before :each do
247
+ test_users = Koala::Facebook::TestUsers.new({:app_access_token => @app_access_token, :app_id => @app_id})
248
+ test_users.delete_all
249
+ end
250
+
251
+ after :each do
252
+ test_users = Koala::Facebook::TestUsers.new({:app_access_token => @app_access_token, :app_id => @app_id})
253
+ test_users.delete_all
254
+ end
255
+
256
+ it "should create a 5 person network" do
257
+ size = 5
258
+ @network = @test_users.create_network(size)
259
+ @network.should be_a(Array)
260
+ @network.size.should == size
261
+ end
262
+ end
263
+
264
+ it "should limit to a 50 person network" do
265
+ @test_users.should_receive(:create).exactly(50).times
266
+ @test_users.stub!(:befriend)
267
+ @network = @test_users.create_network(51)
268
+ end
269
+
270
+ it "should pass on the installed and permissions parameters to create" do
271
+ perms = ["read_stream", "offline_access"]
272
+ installed = false
273
+ count = 25
274
+ @test_users.should_receive(:create).exactly(count).times.with(installed, perms)
275
+ @test_users.stub!(:befriend)
276
+ @network = @test_users.create_network(count, installed, perms)
277
+ end
278
+
279
+ end # when creating network
280
+ end
281
+ end # describe Koala TestUsers
@@ -0,0 +1,206 @@
1
+ # fake MIME::Types
2
+ module Koala::MIME
3
+ module Types
4
+ def self.type_for(type)
5
+ # this should be faked out in tests
6
+ nil
7
+ end
8
+ end
9
+ end
10
+
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
+ :original_filename => "bar"
18
+ )
19
+ tempfile.stub!(:respond_to?).with(:path).and_return(true)
20
+
21
+ [tempfile, uploaded_file]
22
+ end
23
+
24
+ def sinatra_mocks
25
+ {:type => "type", :tempfile => "Tempfile", :filename => "foo.bar"}
26
+ end
27
+
28
+ describe "the constructor" do
29
+ describe "when given a file path" do
30
+ before(:each) do
31
+ @path = BEACH_BALL_PATH
32
+ @koala_io_params = [@path]
33
+ end
34
+
35
+ describe "and a content type" do
36
+ before :each do
37
+ @stub_type = stub("image/jpg")
38
+ @koala_io_params.concat([@stub_type])
39
+ end
40
+
41
+ it "returns an UploadIO with the same file path" do
42
+ Koala::UploadableIO.new(*@koala_io_params).io_or_path.should == @path
43
+ end
44
+
45
+ it "returns an UploadIO with the same content type" do
46
+ Koala::UploadableIO.new(*@koala_io_params).content_type.should == @stub_type
47
+ end
48
+
49
+ it "returns an UploadIO with the file's name" do
50
+ Koala::UploadableIO.new(*@koala_io_params).filename.should == File.basename(@path)
51
+ end
52
+ end
53
+
54
+ describe "and no content type" do
55
+ it_should_behave_like "determining a mime type"
56
+ end
57
+ end
58
+
59
+ describe "when given a File object" do
60
+ before(:each) do
61
+ @file = File.open(BEACH_BALL_PATH)
62
+ @koala_io_params = [@file]
63
+ end
64
+
65
+ describe "and a content type" do
66
+ before :each do
67
+ @koala_io_params.concat(["image/jpg"])
68
+ end
69
+
70
+ it "returns an UploadIO with the same io" do
71
+ Koala::UploadableIO.new(*@koala_io_params).io_or_path.should == @koala_io_params[0]
72
+ end
73
+
74
+ it "returns an UploadableIO with the same content_type" do
75
+ content_stub = @koala_io_params[1] = stub('Content Type')
76
+ Koala::UploadableIO.new(*@koala_io_params).content_type.should == content_stub
77
+ end
78
+
79
+ it "returns an UploadableIO with the right filename" do
80
+ Koala::UploadableIO.new(*@koala_io_params).filename.should == File.basename(@file.path)
81
+ end
82
+ end
83
+
84
+ describe "and no content type" do
85
+ it_should_behave_like "determining a mime type"
86
+ end
87
+ end
88
+
89
+ describe "when given a Rails 3 ActionDispatch::Http::UploadedFile" do
90
+ before(:each) do
91
+ @tempfile, @uploaded_file = rails_3_mocks
92
+ end
93
+
94
+ it "gets the path from the tempfile associated with the UploadedFile" do
95
+ expected_path = stub('Tempfile')
96
+ @tempfile.should_receive(:path).and_return(expected_path)
97
+ Koala::UploadableIO.new(@uploaded_file).io_or_path.should == expected_path
98
+ end
99
+
100
+ it "gets the content type via the content_type method" do
101
+ expected_content_type = stub('Content Type')
102
+ @uploaded_file.should_receive(:content_type).and_return(expected_content_type)
103
+ Koala::UploadableIO.new(@uploaded_file).content_type.should == expected_content_type
104
+ end
105
+
106
+ it "gets the filename from the UploadedFile" do
107
+ Koala::UploadableIO.new(@uploaded_file).filename.should == @uploaded_file.original_filename
108
+ end
109
+ end
110
+
111
+ describe "when given a Sinatra file parameter hash" do
112
+ before(:each) do
113
+ @file_hash = sinatra_mocks
114
+ end
115
+
116
+ it "gets the io_or_path from the :tempfile key" do
117
+ expected_file = stub('File')
118
+ @file_hash[:tempfile] = expected_file
119
+
120
+ uploadable = Koala::UploadableIO.new(@file_hash)
121
+ uploadable.io_or_path.should == expected_file
122
+ end
123
+
124
+ it "gets the content type from the :type key" do
125
+ expected_content_type = stub('Content Type')
126
+ @file_hash[:type] = expected_content_type
127
+
128
+ uploadable = Koala::UploadableIO.new(@file_hash)
129
+ uploadable.content_type.should == expected_content_type
130
+ end
131
+
132
+ it "gets the content type from the :type key" do
133
+ uploadable = Koala::UploadableIO.new(@file_hash)
134
+ uploadable.filename.should == @file_hash[:filename]
135
+ end
136
+ end
137
+
138
+ describe "for files with with recognizable MIME types" do
139
+ # what that means is tested below
140
+ it "should accept a file object alone" do
141
+ params = [BEACH_BALL_PATH]
142
+ lambda { Koala::UploadableIO.new(*params) }.should_not raise_exception(Koala::KoalaError)
143
+ end
144
+
145
+ it "should accept a file path alone" do
146
+ params = [BEACH_BALL_PATH]
147
+ lambda { Koala::UploadableIO.new(*params) }.should_not raise_exception(Koala::KoalaError)
148
+ end
149
+ end
150
+ end
151
+
152
+ describe "getting an UploadableIO" do
153
+ before(:each) do
154
+ @upload_io = stub("UploadIO")
155
+ UploadIO.stub!(:new).with(anything, anything, anything).and_return(@upload_io)
156
+ end
157
+
158
+ context "if no filename was provided" do
159
+ it "should call the constructor with the content type, file name, and a dummy file name" do
160
+ UploadIO.should_receive(:new).with(BEACH_BALL_PATH, "content/type", anything).and_return(@upload_io)
161
+ Koala::UploadableIO.new(BEACH_BALL_PATH, "content/type").to_upload_io.should == @upload_io
162
+ end
163
+ end
164
+
165
+ context "if a filename was provided" do
166
+ it "should call the constructor with the content type, file name, and the filename" do
167
+ filename = "file"
168
+ UploadIO.should_receive(:new).with(BEACH_BALL_PATH, "content/type", filename).and_return(@upload_io)
169
+ Koala::UploadableIO.new(BEACH_BALL_PATH, "content/type", filename).to_upload_io
170
+ end
171
+ end
172
+ end
173
+
174
+ describe "getting a file" do
175
+ it "returns the File if initialized with a file" do
176
+ f = File.new(BEACH_BALL_PATH)
177
+ Koala::UploadableIO.new(f).to_file.should == f
178
+ end
179
+
180
+ it "should open up and return a file corresponding to the path if io_or_path is a path" do
181
+ result = stub("File")
182
+ File.should_receive(:open).with(BEACH_BALL_PATH).and_return(result)
183
+ Koala::UploadableIO.new(BEACH_BALL_PATH).to_file.should == result
184
+ end
185
+ end
186
+
187
+ describe "#binary_content?" do
188
+ it "returns true for Rails 3 file uploads" do
189
+ Koala::UploadableIO.binary_content?(rails_3_mocks.last).should be_true
190
+ end
191
+
192
+ it "returns true for Sinatra file uploads" do
193
+ Koala::UploadableIO.binary_content?(rails_3_mocks.last).should be_true
194
+ end
195
+
196
+ it "returns true for File objects" do
197
+ Koala::UploadableIO.binary_content?(File.open(BEACH_BALL_PATH)).should be_true
198
+ end
199
+
200
+ it "returns false for everything else" do
201
+ Koala::UploadableIO.binary_content?(StringIO.new).should be_false
202
+ Koala::UploadableIO.binary_content?(BEACH_BALL_PATH).should be_false
203
+ Koala::UploadableIO.binary_content?(nil).should be_false
204
+ end
205
+ end
206
+ end # describe UploadableIO