koala 1.1.0 → 1.2.0beta1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (50) hide show
  1. data/.travis.yml +2 -1
  2. data/CHANGELOG +26 -0
  3. data/Gemfile +6 -2
  4. data/Rakefile +0 -1
  5. data/koala.gemspec +8 -8
  6. data/lib/koala.rb +42 -45
  7. data/lib/koala/batch_operation.rb +15 -15
  8. data/lib/koala/graph_api.rb +81 -58
  9. data/lib/koala/graph_batch_api.rb +10 -10
  10. data/lib/koala/graph_collection.rb +6 -6
  11. data/lib/koala/http_service.rb +177 -0
  12. data/lib/koala/oauth.rb +2 -2
  13. data/lib/koala/realtime_updates.rb +20 -17
  14. data/lib/koala/rest_api.rb +1 -1
  15. data/lib/koala/test_users.rb +33 -16
  16. data/lib/koala/uploadable_io.rb +47 -42
  17. data/lib/koala/utils.rb +11 -0
  18. data/readme.md +38 -38
  19. data/spec/cases/api_base_spec.rb +2 -2
  20. data/spec/cases/error_spec.rb +32 -0
  21. data/spec/cases/graph_and_rest_api_spec.rb +20 -3
  22. data/spec/cases/graph_api_batch_spec.rb +88 -97
  23. data/spec/cases/graph_api_spec.rb +21 -4
  24. data/spec/cases/http_service_spec.rb +446 -0
  25. data/spec/cases/koala_spec.rb +33 -38
  26. data/spec/cases/oauth_spec.rb +219 -200
  27. data/spec/cases/realtime_updates_spec.rb +45 -31
  28. data/spec/cases/rest_api_spec.rb +23 -7
  29. data/spec/cases/test_users_spec.rb +112 -52
  30. data/spec/cases/uploadable_io_spec.rb +49 -36
  31. data/spec/cases/utils_spec.rb +10 -0
  32. data/spec/fixtures/facebook_data.yml +23 -22
  33. data/spec/fixtures/mock_facebook_responses.yml +126 -96
  34. data/spec/spec_helper.rb +29 -5
  35. data/spec/support/graph_api_shared_examples.rb +59 -52
  36. data/spec/support/json_testing_fix.rb +35 -11
  37. data/spec/support/koala_test.rb +163 -0
  38. data/spec/support/mock_http_service.rb +6 -4
  39. data/spec/support/ordered_hash.rb +205 -0
  40. data/spec/support/rest_api_shared_examples.rb +37 -37
  41. data/spec/support/uploadable_io_shared_examples.rb +2 -8
  42. metadata +78 -79
  43. data/lib/koala/http_services.rb +0 -46
  44. data/lib/koala/http_services/net_http_service.rb +0 -92
  45. data/lib/koala/http_services/typhoeus_service.rb +0 -37
  46. data/spec/cases/http_services/http_service_spec.rb +0 -129
  47. data/spec/cases/http_services/net_http_service_spec.rb +0 -532
  48. data/spec/cases/http_services/typhoeus_service_spec.rb +0 -152
  49. data/spec/support/live_testing_data_helper.rb +0 -40
  50. data/spec/support/setup_mocks_or_live.rb +0 -51
@@ -1,36 +1,30 @@
1
- require 'koala'
1
+ require "net/http/post/multipart"
2
2
 
3
3
  module Koala
4
4
  class UploadableIO
5
- attr_reader :io_or_path, :content_type, :requires_base_http_service
5
+ attr_reader :io_or_path, :content_type, :filename
6
6
 
7
7
  def initialize(io_or_path_or_mixed, content_type = nil, filename = nil)
8
8
  # see if we got the right inputs
9
- if content_type.nil?
10
- parse_init_mixed_param io_or_path_or_mixed
11
- elsif !content_type.nil? && (io_or_path_or_mixed.respond_to?(:read) or io_or_path_or_mixed.kind_of?(String))
12
- @io_or_path = io_or_path_or_mixed
13
- @content_type = content_type
14
- end
15
-
16
- # Probably a StringIO or similar object, which won't work with Typhoeus
17
- @requires_base_http_service = @io_or_path.respond_to?(:read) && !@io_or_path.kind_of?(File)
9
+ parse_init_mixed_param io_or_path_or_mixed, content_type
18
10
 
19
11
  # filename is used in the Ads API
20
- @filename = filename || "koala-io-file.dum"
12
+ # if it's provided, take precedence over the detected filename
13
+ # otherwise, fall back to a dummy name
14
+ @filename = filename || @filename || "koala-io-file.dum"
21
15
 
22
16
  raise KoalaError.new("Invalid arguments to initialize an UploadableIO") unless @io_or_path
23
- raise KoalaError.new("Unable to determine MIME type for UploadableIO") if !@content_type && Koala.multipart_requires_content_type?
17
+ raise KoalaError.new("Unable to determine MIME type for UploadableIO") if !@content_type
24
18
  end
25
-
19
+
26
20
  def to_upload_io
27
21
  UploadIO.new(@io_or_path, @content_type, @filename)
28
22
  end
29
-
23
+
30
24
  def to_file
31
25
  @io_or_path.is_a?(String) ? File.open(@io_or_path) : @io_or_path
32
26
  end
33
-
27
+
34
28
  def self.binary_content?(content)
35
29
  content.is_a?(UploadableIO) || DETECTION_STRATEGIES.detect {|method| send(method, content)}
36
30
  end
@@ -41,69 +35,80 @@ module Koala
41
35
  :rails_3_param?,
42
36
  :file_param?
43
37
  ]
44
-
38
+
45
39
  PARSE_STRATEGIES = [
46
40
  :parse_rails_3_param,
47
41
  :parse_sinatra_param,
48
42
  :parse_file_object,
49
43
  :parse_string_path
50
44
  ]
51
-
52
- def parse_init_mixed_param(mixed)
45
+
46
+ def parse_init_mixed_param(mixed, content_type = nil)
53
47
  PARSE_STRATEGIES.each do |method|
54
- send(method, mixed)
48
+ send(method, mixed, content_type)
55
49
  return if @io_or_path && @content_type
56
50
  end
57
51
  end
58
-
52
+
59
53
  # Expects a parameter of type ActionDispatch::Http::UploadedFile
60
54
  def self.rails_3_param?(uploaded_file)
61
55
  uploaded_file.respond_to?(:content_type) and uploaded_file.respond_to?(:tempfile) and uploaded_file.tempfile.respond_to?(:path)
62
56
  end
63
-
64
- def parse_rails_3_param(uploaded_file)
65
- if UploadableIO.rails_3_param?(uploaded_file)
57
+
58
+ def parse_rails_3_param(uploaded_file, content_type = nil)
59
+ if UploadableIO.rails_3_param?(uploaded_file)
66
60
  @io_or_path = uploaded_file.tempfile.path
67
- @content_type = uploaded_file.content_type
61
+ @content_type = content_type || uploaded_file.content_type
62
+ @filename = uploaded_file.original_filename
68
63
  end
69
64
  end
70
-
65
+
71
66
  # Expects a Sinatra hash of file info
72
67
  def self.sinatra_param?(file_hash)
73
68
  file_hash.kind_of?(Hash) and file_hash.has_key?(:type) and file_hash.has_key?(:tempfile)
74
69
  end
75
-
76
- def parse_sinatra_param(file_hash)
70
+
71
+ def parse_sinatra_param(file_hash, content_type = nil)
77
72
  if UploadableIO.sinatra_param?(file_hash)
78
73
  @io_or_path = file_hash[:tempfile]
79
- @content_type = file_hash[:type] || detect_mime_type(tempfile)
74
+ @content_type = content_type || file_hash[:type] || detect_mime_type(tempfile)
75
+ @filename = file_hash[:filename]
80
76
  end
81
77
  end
82
-
78
+
83
79
  # takes a file object
84
80
  def self.file_param?(file)
85
81
  file.kind_of?(File)
86
82
  end
87
-
88
- def parse_file_object(file)
83
+
84
+ def parse_file_object(file, content_type = nil)
89
85
  if UploadableIO.file_param?(file)
90
86
  @io_or_path = file
91
- @content_type = detect_mime_type(file.path)
87
+ @content_type = content_type || detect_mime_type(file.path)
88
+ @filename = File.basename(file.path)
92
89
  end
93
90
  end
94
-
95
- def parse_string_path(path)
91
+
92
+ def parse_string_path(path, content_type = nil)
96
93
  if path.kind_of?(String)
97
94
  @io_or_path = path
98
- @content_type = detect_mime_type(path)
95
+ @content_type = content_type || detect_mime_type(path)
96
+ @filename = File.basename(path)
97
+ end
98
+ end
99
+
100
+ def parse_io(io, content_type = nil)
101
+ if io.respond_to?(:read)
102
+ @io_or_path = io
103
+ @content_type = content_type
99
104
  end
100
105
  end
101
-
106
+
102
107
  MIME_TYPE_STRATEGIES = [
103
108
  :use_mime_module,
104
109
  :use_simple_detection
105
110
  ]
106
-
111
+
107
112
  def detect_mime_type(filename)
108
113
  if filename
109
114
  MIME_TYPE_STRATEGIES.each do |method|
@@ -113,7 +118,7 @@ module Koala
113
118
  end
114
119
  nil # if we can't find anything
115
120
  end
116
-
121
+
117
122
  def use_mime_module(filename)
118
123
  # if the user has installed mime/types, we can use that
119
124
  # if not, rescue and return nil
@@ -124,12 +129,12 @@ module Koala
124
129
  nil
125
130
  end
126
131
  end
127
-
132
+
128
133
  def use_simple_detection(filename)
129
134
  # very rudimentary extension analysis for images
130
135
  # first, get the downcased extension, or an empty string if it doesn't exist
131
136
  extension = ((filename.match(/\.([a-zA-Z0-9]+)$/) || [])[1] || "").downcase
132
- case extension
137
+ case extension
133
138
  when ""
134
139
  nil
135
140
  # images
@@ -169,7 +174,7 @@ module Koala
169
174
  "video/ogg"
170
175
  when "wmv"
171
176
  "video/x-ms-wmv"
172
- end
177
+ end
173
178
  end
174
179
  end
175
180
  end
@@ -0,0 +1,11 @@
1
+ module Koala
2
+ module Utils
3
+ def self.deprecate(message)
4
+ begin
5
+ send(:warn, "KOALA: Deprecation warning: #{message}")
6
+ rescue Exception => err
7
+ puts "Unable to issue Koala deprecation warning! #{err.message}"
8
+ end
9
+ end
10
+ end
11
+ end
data/readme.md CHANGED
@@ -1,77 +1,77 @@
1
+ [![Build Status](https://secure.travis-ci.org/arsduo/koala.png)](http://travis-ci.org/arsduo/koala)
2
+
1
3
  Koala
2
4
  ====
3
- [Koala](http://github.com/arsduo/koala) is a new Facebook library for Ruby, supporting the Graph API (including the batch requests and photo uploads), the REST API, realtime updates, test users, and OAuth validation. We wrote Koala with four goals:
5
+ [Koala](http://github.com/arsduo/koala) is a Facebook library for Ruby, supporting the Graph API (including the batch requests and photo uploads), the REST API, realtime updates, test users, and OAuth validation. We wrote Koala with four goals:
4
6
 
5
- * Lightweight: Koala should be as light and simple as Facebook’s own new libraries, providing API accessors and returning simple JSON. (We clock in, with comments, at just over 750 lines of code.)
6
- * Fast: Koala should, out of the box, be quick. In addition to supporting the vanilla Ruby networking libraries, it natively supports Typhoeus, our preferred gem for making fast HTTP requests. Of course, that brings us to our next topic:
7
- * Flexible: Koala should be useful to everyone, regardless of their current configuration. (In addition to vanilla Ruby, we support JRuby, Rubinius, and REE, and provide built-in mechanism for using whichever HTTP library you prefer.)
8
- * Tested: Koala should have complete test coverage, so you can rely on it. (Our complete test coverage can be run against either mocked responses or the live Facebook servers.)
7
+ * Lightweight: Koala should be as light and simple as Facebook’s own libraries, providing API accessors and returning simple JSON.
8
+ * Fast: Koala should, out of the box, be quick. Out of the box, we use Facebook's faster read-only servers when possible and if available, the Typhoeus gem to make snappy Facebook requests. Of course, that brings us to our next topic:
9
+ * Flexible: Koala should be useful to everyone, regardless of their current configuration. (We support JRuby, Rubinius, and REE as well as vanilla Ruby, and use the Faraday library to provide complete flexibility over how HTTP requests are made.)
10
+ * Tested: Koala should have complete test coverage, so you can rely on it. (Our test coverage is complete and can be run against either mocked responses or the live Facebook servers.)
9
11
 
10
12
  Installation
11
13
  ---
12
14
 
13
15
  Easy:
14
-
15
- [sudo|rvm] gem install koala
16
-
16
+
17
+ [sudo|rvm] gem install koala --pre # for 1.2 beta
18
+ [sudo|rvm] gem install koala # for 1.1
19
+
17
20
  Or in Bundler:
18
-
19
- gem "koala"
20
-
21
+
22
+ gem "koala", "~> 1.2.0beta"
23
+ gem "koala" # for 1.1
24
+
21
25
  Graph API
22
26
  ----
23
27
  The Graph API is the simple, slick new interface to Facebook's data. Using it with Koala is quite straightforward:
24
28
 
25
- @graph = Koala::Facebook::GraphAPI.new(oauth_access_token)
29
+ @graph = Koala::Facebook::API.new(oauth_access_token)
26
30
  profile = @graph.get_object("me")
27
31
  friends = @graph.get_connections("me", "friends")
28
32
  @graph.put_object("me", "feed", :message => "I am writing on my wall!")
29
33
 
30
34
  The response of most requests is the JSON data returned from the Facebook servers as a Hash.
31
35
 
32
- When retrieving data that returns an array of results (for example, when calling GraphAPI#get_connections or GraphAPI#search) a GraphCollection object (a sub-class of Array) will be returned, which contains added methods for getting the next and previous page of results:
36
+ When retrieving data that returns an array of results (for example, when calling API#get_connections or API#search) a GraphCollection object will be returned, which makes it easy to page through the results:
33
37
 
34
38
  # Returns the feed items for the currently logged-in user as a GraphCollection
35
39
  feed = @graph.get_connections("me", "feed")
36
-
37
- # GraphCollection is a sub-class of Array, so you can use it as a usual Array
38
- first_entry = feed[0]
39
- last_entry = feed.last
40
-
41
- # Returns the next page of results (also as a GraphCollection)
40
+ feed.each {|f| do_something_with_item(f) } # it's a subclass of Array
42
41
  next_feed = feed.next_page
43
42
 
44
- # Returns an array describing the URL for the next page: [path, arguments]
45
- # This is useful for paging across multiple requests
46
- next_path, next_args = feed.next_page_params
47
-
48
- # You can use those params to easily get the next (or previous) page
49
- page = @graph.get_page(feed.next_page_params)
43
+ # You can also get an array describing the URL for the next page: [path, arguments]
44
+ # This is useful for storing page state across multiple browser requests
45
+ next_page_params = feed.next_page_params
46
+ page = @graph.get_page(next_page_params)
50
47
 
51
- You can make multiple calls at once using Facebook's batch API:
48
+ You can also make multiple calls at once using Facebook's batch API:
52
49
 
53
50
  # Returns an array of results as if they were called non-batch
54
51
  @graph.batch do |batch_api|
55
52
  batch_api.get_object('me')
56
- batch_api.get_object('koppel')
53
+ batch_api.put_wall_post('Making a post in a batch.')
57
54
  end
58
55
 
59
- Check out the wiki for more examples.
56
+ Check out the wiki for more details and examples.
60
57
 
61
58
  The REST API
62
59
  -----
63
60
  Where the Graph API and the old REST API overlap, you should choose the Graph API. Unfortunately, that overlap is far from complete, and there are many important API calls that can't yet be done via the Graph.
64
61
 
65
- Koala now supports the old-school REST API using OAuth access tokens; to use this, instantiate your class using the RestAPI class:
62
+ Fortunately, Koala supports the REST API using the very same interface; to use this, instantiate an API:
66
63
 
67
- @rest = Koala::Facebook::RestAPI.new(oauth_access_token)
64
+ @rest = Koala::Facebook::API.new(oauth_access_token)
68
65
  @rest.fql_query(my_fql_query) # convenience method
69
66
  @rest.fql_multiquery(fql_query_hash) # convenience method
70
67
  @rest.rest_call("stream.publish", arguments_hash) # generic version
71
68
 
72
- We reserve the right to expand the built-in REST API coverage to additional convenience methods in the future, depending on how fast Facebook moves to fill in the gaps.
69
+ Of course, you can use the Graph API methods on the same object -- the power of two APIs right in the palm of your hand.
73
70
 
74
- (If you want the power of both APIs in the palm of your hand, try out the GraphAndRestAPI class.)
71
+ @api = Koala::Facebook::API.new(oauth_access_token)
72
+ fql = @api.fql_query(my_fql_query)
73
+ @api.put_wall_post(process_result(fql))
74
+
75
75
 
76
76
  OAuth
77
77
  -----
@@ -130,10 +130,10 @@ Test Users
130
130
  -----
131
131
 
132
132
  We also support the test users API, allowing you to conjure up fake users and command them to do your bidding using the Graph or REST API:
133
-
133
+
134
134
  @test_users = Koala::Facebook::TestUsers.new(:app_id => id, :secret => secret)
135
135
  user = @test_users.create(is_app_installed, desired_permissions)
136
- user_graph_api = Koala::Facebook::GraphAPI.new(user["access_token"])
136
+ user_graph_api = Koala::Facebook::API.new(user["access_token"])
137
137
  # or, if you want to make a whole community:
138
138
  @test_users.create_network(network_size, is_app_installed, common_permissions)
139
139
 
@@ -149,14 +149,14 @@ Testing
149
149
  -----
150
150
 
151
151
  Unit tests are provided for all of Koala's methods. By default, these tests run against mock responses and hence are ready out of the box:
152
-
152
+
153
153
  # From anywhere in the project directory:
154
154
  bundle exec rake spec
155
-
155
+
156
156
 
157
157
  You can also run live tests against Facebook's servers:
158
-
158
+
159
159
  # Again from anywhere in the project directory:
160
160
  LIVE=true bundle exec rake spec
161
161
 
162
- Important Note: to run the live tests, you have to provide some of your own data in spec/fixtures/facebook_data.yml: a valid OAuth access token with publish\_stream, read\_stream, and user\_photos permissions and an OAuth code that can be used to generate an access token. You can get this data at the OAuth Playground; if you want to use your own app, remember to swap out the app ID, secret, and other values. (The file also provides valid values for other tests, which you're welcome to swap out for data specific to your own application.)
162
+ By default, the live tests are run against test users, so you can run them as frequently as you want. If you want to run them against a real user, however, you can fill in the OAuth token, code, and access\_token values in spec/fixtures/facebook_data.yml. See the wiki for more details.
@@ -44,7 +44,7 @@ describe "Koala::Facebook::API" do
44
44
 
45
45
  Koala.stub(:make_request).and_return(response)
46
46
 
47
- @service.api('anything', 'get', {}, :http_component => http_component)
47
+ @service.api('anything', {}, 'get', :http_component => http_component)
48
48
  end
49
49
 
50
50
  it "should return the body of the request as JSON if no http_component is given" do
@@ -98,4 +98,4 @@ describe "Koala::Facebook::API" do
98
98
  end
99
99
  end
100
100
 
101
- end
101
+ end
@@ -0,0 +1,32 @@
1
+ require 'spec_helper'
2
+
3
+ describe Koala::Facebook::APIError do
4
+ it "is a StandardError" do
5
+ Koala::Facebook::APIError.new.should be_a(StandardError)
6
+ end
7
+
8
+ it "has an accessor for fb_error_type" do
9
+ Koala::Facebook::APIError.instance_methods.map(&:to_sym).should include(:fb_error_type)
10
+ Koala::Facebook::APIError.instance_methods.map(&:to_sym).should include(:fb_error_type=)
11
+ end
12
+
13
+ it "sets fb_error_type to details['type']" do
14
+ type = "foo"
15
+ Koala::Facebook::APIError.new("type" => type).fb_error_type.should == type
16
+ end
17
+
18
+ it "sets the error message details['type']: details['message']" do
19
+ type = "foo"
20
+ message = "bar"
21
+ error = Koala::Facebook::APIError.new("type" => type, "message" => message)
22
+ error.message.should =~ /#{type}/
23
+ error.message.should =~ /#{message}/
24
+ end
25
+ end
26
+
27
+ describe Koala::KoalaError do
28
+ it "is a StandardError" do
29
+ Koala::KoalaError.new.should be_a(StandardError)
30
+ end
31
+ end
32
+
@@ -1,11 +1,28 @@
1
1
  require 'spec_helper'
2
2
 
3
3
  describe "Koala::Facebook::GraphAndRestAPI" do
4
- include LiveTestingDataHelper
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::GraphAndRestAPI.new("token").should be_a(Koala::Facebook::GraphAndRestAPI)
11
+ end
12
+
13
+ it "ultimately creates an API object" do
14
+ api = Koala::Facebook::GraphAndRestAPI.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::GraphAndRestAPI.new("token")
20
+ end
21
+ end
5
22
 
6
23
  describe "with an access token" do
7
24
  before(:each) do
8
- @api = Koala::Facebook::GraphAndRestAPI.new(@token)
25
+ @api = Koala::Facebook::API.new(@token)
9
26
  end
10
27
 
11
28
  it_should_behave_like "Koala RestAPI"
@@ -18,7 +35,7 @@ describe "Koala::Facebook::GraphAndRestAPI" do
18
35
 
19
36
  describe "without an access token" do
20
37
  before(:each) do
21
- @api = Koala::Facebook::GraphAndRestAPI.new
38
+ @api = Koala::Facebook::API.new
22
39
  end
23
40
 
24
41
  it_should_behave_like "Koala RestAPI"
@@ -1,16 +1,15 @@
1
1
  require 'spec_helper'
2
2
 
3
3
  describe "Koala::Facebook::GraphAPI in batch mode" do
4
- include LiveTestingDataHelper
4
+
5
5
  before :each do
6
- @api = Koala::Facebook::GraphAPI.new(@token)
6
+ @api = Koala::Facebook::API.new(@token)
7
7
  # app API
8
- @oauth_data = $testing_data["oauth_test_data"]
9
- @app_id = @oauth_data["app_id"]
10
- @app_access_token = @oauth_data["app_access_token"]
11
- @app_api = Koala::Facebook::GraphAPI.new(@app_access_token)
12
- end
13
-
8
+ @app_id = KoalaTest.app_id
9
+ @app_access_token = KoalaTest.app_access_token
10
+ @app_api = Koala::Facebook::API.new(@app_access_token)
11
+ end
12
+
14
13
  describe "BatchOperations" do
15
14
  before :each do
16
15
  @args = {
@@ -22,43 +21,43 @@ describe "Koala::Facebook::GraphAPI in batch mode" do
22
21
  :post_processing => lambda { }
23
22
  }
24
23
  end
25
-
24
+
26
25
  describe "#new" do
27
26
  it "makes http_options accessible" do
28
27
  Koala::Facebook::BatchOperation.new(@args).http_options.should == @args[:http_options]
29
28
  end
30
-
29
+
31
30
  it "makes post_processing accessible" do
32
31
  Koala::Facebook::BatchOperation.new(@args).post_processing.should == @args[:post_processing]
33
32
  end
34
-
33
+
35
34
  it "makes access_token accessible" do
36
35
  Koala::Facebook::BatchOperation.new(@args).access_token.should == @args[:access_token]
37
36
  end
38
-
37
+
39
38
  it "doesn't change the original http_options" do
40
39
  @args[:http_options][:name] = "baz2"
41
40
  expected = @args[:http_options].dup
42
41
  Koala::Facebook::BatchOperation.new(@args).to_batch_params(nil)
43
42
  @args[:http_options].should == expected
44
43
  end
45
-
44
+
46
45
  it "leaves the file array nil by default" do
47
- Koala::Facebook::BatchOperation.new(@args).files.should be_nil
46
+ Koala::Facebook::BatchOperation.new(@args).files.should be_nil
48
47
  end
49
-
48
+
50
49
  it "raises a KoalaError if no access token supplied" do
51
50
  expect { Koala::Facebook::BatchOperation.new(@args.merge(:access_token => nil)) }.to raise_exception(Koala::KoalaError)
52
51
  end
53
-
52
+
54
53
  describe "when supplied binary files" do
55
54
  before :each do
56
55
  @binary = stub("Binary file")
57
56
  @uploadable_io = stub("UploadableIO 1")
58
-
57
+
59
58
  @batch_queue = []
60
59
  Koala::Facebook::GraphAPI.stub(:batch_calls).and_return(@batch_queue)
61
-
60
+
62
61
  Koala::UploadableIO.stub(:new).with(@binary).and_return(@uploadable_io)
63
62
  Koala::UploadableIO.stub(:binary_content?).and_return(false)
64
63
  Koala::UploadableIO.stub(:binary_content?).with(@binary).and_return(true)
@@ -67,14 +66,14 @@ describe "Koala::Facebook::GraphAPI in batch mode" do
67
66
 
68
67
  @args[:method] = "post" # files are always post
69
68
  end
70
-
69
+
71
70
  it "adds binary files to the files attribute as UploadableIOs" do
72
71
  @args[:args].merge!("source" => @binary)
73
72
  batch_op = Koala::Facebook::BatchOperation.new(@args)
74
73
  batch_op.files.should_not be_nil
75
74
  batch_op.files.find {|k, v| v == @uploadable_io}.should_not be_nil
76
75
  end
77
-
76
+
78
77
  it "works if supplied an UploadableIO as an argument" do
79
78
  # as happens with put_picture at the moment
80
79
  @args[:args].merge!("source" => @uploadable_io)
@@ -82,14 +81,14 @@ describe "Koala::Facebook::GraphAPI in batch mode" do
82
81
  batch_op.files.should_not be_nil
83
82
  batch_op.files.find {|k, v| v == @uploadable_io}.should_not be_nil
84
83
  end
85
-
84
+
86
85
  it "assigns each binary parameter unique name" do
87
86
  @args[:args].merge!("source" => @binary, "source2" => @binary)
88
87
  batch_op = Koala::Facebook::BatchOperation.new(@args)
89
88
  # if the name wasn't unique, there'd just be one item
90
89
  batch_op.files.should have(2).items
91
90
  end
92
-
91
+
93
92
  it "assigns each binary parameter unique name across batch requests" do
94
93
  @args[:args].merge!("source" => @binary, "source2" => @binary)
95
94
  batch_op = Koala::Facebook::BatchOperation.new(@args)
@@ -100,59 +99,59 @@ describe "Koala::Facebook::GraphAPI in batch mode" do
100
99
  # if the name wasn't unique, we should have < 4 items since keys would be the same
101
100
  batch_op.files.merge(batch_op2.files).should have(4).items
102
101
  end
103
-
102
+
104
103
  it "removes the value from the arguments" do
105
104
  @args[:args].merge!("source" => @binary)
106
105
  Koala::Facebook::BatchOperation.new(@args).to_batch_params(nil)[:body].should_not =~ /source=/
107
106
  end
108
- end
109
-
107
+ end
108
+
110
109
  end
111
-
112
- describe ".to_batch_params" do
110
+
111
+ describe ".to_batch_params" do
113
112
  describe "handling arguments and URLs" do
114
113
  shared_examples_for "request with no body" do
115
114
  it "adds the args to the URL string, with ? if no args previously present" do
116
115
  test_args = "foo"
117
116
  @args[:url] = url = "/"
118
117
  Koala.http_service.stub(:encode_params).and_return(test_args)
119
-
118
+
120
119
  Koala::Facebook::BatchOperation.new(@args).to_batch_params(nil)[:relative_url].should == "#{url}?#{test_args}"
121
120
  end
122
-
121
+
123
122
  it "adds the args to the URL string, with & if args previously present" do
124
123
  test_args = "foo"
125
124
  @args[:url] = url = "/?a=2"
126
125
  Koala.http_service.stub(:encode_params).and_return(test_args)
127
-
126
+
128
127
  Koala::Facebook::BatchOperation.new(@args).to_batch_params(nil)[:relative_url].should == "#{url}&#{test_args}"
129
128
  end
130
-
129
+
131
130
  it "adds nothing to the URL string if there are no args to be added" do
132
131
  @args[:args] = {}
133
- Koala::Facebook::BatchOperation.new(@args).to_batch_params(@args[:access_token])[:relative_url].should == @args[:url]
132
+ Koala::Facebook::BatchOperation.new(@args).to_batch_params(@args[:access_token])[:relative_url].should == @args[:url]
134
133
  end
135
-
134
+
136
135
  it "adds nothing to the body" do
137
136
  Koala::Facebook::BatchOperation.new(@args).to_batch_params(nil)[:body].should be_nil
138
137
  end
139
138
  end
140
-
139
+
141
140
  shared_examples_for "requests with a body param" do
142
141
  it "sets the body to the encoded args string, if there are args" do
143
142
  test_args = "foo"
144
143
  Koala.http_service.stub(:encode_params).and_return(test_args)
145
-
144
+
146
145
  Koala::Facebook::BatchOperation.new(@args).to_batch_params(nil)[:body].should == test_args
147
146
  end
148
-
147
+
149
148
  it "does not set the body if there are no args" do
150
149
  test_args = ""
151
150
  Koala.http_service.stub(:encode_params).and_return(test_args)
152
151
  Koala::Facebook::BatchOperation.new(@args).to_batch_params(nil)[:body].should be_nil
153
152
  end
154
-
155
-
153
+
154
+
156
155
  it "doesn't change the url" do
157
156
  test_args = "foo"
158
157
  Koala.http_service.stub(:encode_params).and_return(test_args)
@@ -160,40 +159,40 @@ describe "Koala::Facebook::GraphAPI in batch mode" do
160
159
  Koala::Facebook::BatchOperation.new(@args).to_batch_params(nil)[:relative_url].should == @args[:url]
161
160
  end
162
161
  end
163
-
162
+
164
163
  context "for get operations" do
165
164
  before :each do
166
165
  @args[:method] = :get
167
166
  end
168
-
169
- it_should_behave_like "request with no body"
167
+
168
+ it_should_behave_like "request with no body"
170
169
  end
171
-
170
+
172
171
  context "for delete operations" do
173
172
  before :each do
174
173
  @args[:method] = :delete
175
174
  end
176
-
177
- it_should_behave_like "request with no body"
175
+
176
+ it_should_behave_like "request with no body"
178
177
  end
179
-
178
+
180
179
  context "for get operations" do
181
180
  before :each do
182
181
  @args[:method] = :put
183
182
  end
184
-
185
- it_should_behave_like "requests with a body param"
183
+
184
+ it_should_behave_like "requests with a body param"
186
185
  end
187
-
186
+
188
187
  context "for delete operations" do
189
188
  before :each do
190
189
  @args[:method] = :post
191
190
  end
192
-
193
- it_should_behave_like "requests with a body param"
191
+
192
+ it_should_behave_like "requests with a body param"
194
193
  end
195
194
  end
196
-
195
+
197
196
  it "includes the access token if the token is not the main one for the request" do
198
197
  params = Koala::Facebook::BatchOperation.new(@args).to_batch_params(nil)
199
198
  params[:relative_url].should =~ /access_token=#{@args[:access_token]}/
@@ -209,13 +208,13 @@ describe "Koala::Facebook::GraphAPI in batch mode" do
209
208
  params = Koala::Facebook::BatchOperation.new(@args).to_batch_params(@args[:access_token])
210
209
  params[:relative_url].should_not =~ /access_token=#{@args[:access_token]}/
211
210
  end
212
-
211
+
213
212
  it "includes the other arguments if the token is the main one for the request" do
214
213
  @args[:args] = {:a => 2}
215
214
  params = Koala::Facebook::BatchOperation.new(@args).to_batch_params(@args[:access_token])
216
215
  params[:relative_url].should =~ /a=2/
217
216
  end
218
-
217
+
219
218
  it "includes any arguments passed as http_options[:batch_args]" do
220
219
  batch_args = {:name => "baz", :headers => {:some_param => true}}
221
220
  @args[:http_options][:batch_args] = batch_args
@@ -227,22 +226,22 @@ describe "Koala::Facebook::GraphAPI in batch mode" do
227
226
  params = Koala::Facebook::BatchOperation.new(@args).to_batch_params(@args[:access_token])
228
227
  params[:method].should == @args[:method].to_s
229
228
  end
230
-
229
+
231
230
  it "works with nil http_options" do
232
231
  expect { Koala::Facebook::BatchOperation.new(@args.merge(:http_options => nil)).to_batch_params(nil) }.not_to raise_exception
233
232
  end
234
-
233
+
235
234
  it "works with nil args" do
236
235
  expect { Koala::Facebook::BatchOperation.new(@args.merge(:args => nil)).to_batch_params(nil) }.not_to raise_exception
237
- end
238
-
236
+ end
237
+
239
238
  describe "with binary files" do
240
239
  before :each do
241
240
  @binary = stub("Binary file")
242
241
  Koala::UploadableIO.stub(:binary_content?).and_return(false)
243
242
  Koala::UploadableIO.stub(:binary_content?).with(@binary).and_return(true)
244
243
  @uploadable_io = stub("UploadableIO")
245
- Koala::UploadableIO.stub(:new).with(@binary).and_return(@uploadable_io)
244
+ Koala::UploadableIO.stub(:new).with(@binary).and_return(@uploadable_io)
246
245
  @uploadable_io.stub(:is_a?).with(Koala::UploadableIO).and_return(true)
247
246
 
248
247
  @batch_queue = []
@@ -250,7 +249,7 @@ describe "Koala::Facebook::GraphAPI in batch mode" do
250
249
 
251
250
  @args[:method] = "post" # files are always post
252
251
  end
253
-
252
+
254
253
  it "adds file identifiers as attached_files in a comma-separated list" do
255
254
  @args[:args].merge!("source" => @binary, "source2" => @binary)
256
255
  batch_op = Koala::Facebook::BatchOperation.new(@args)
@@ -293,7 +292,7 @@ describe "Koala::Facebook::GraphAPI in batch mode" do
293
292
  it "includes the first operation's access token as the main one in the args" do
294
293
  access_token = "foo"
295
294
  Koala.should_receive(:make_request).with(anything, hash_including("access_token" => access_token), anything, anything).and_return(@fake_response)
296
- Koala::Facebook::GraphAPI.new(access_token).batch do |batch_api|
295
+ Koala::Facebook::API.new(access_token).batch do |batch_api|
297
296
  batch_api.get_object('me')
298
297
  batch_api.get_object('me', {}, {'access_token' => 'bar'})
299
298
  end
@@ -308,7 +307,7 @@ describe "Koala::Facebook::GraphAPI in batch mode" do
308
307
  # two requests should generate two batch operations
309
308
  expected = MultiJson.encode([op.to_batch_params(access_token), op.to_batch_params(access_token)])
310
309
  Koala.should_receive(:make_request).with(anything, hash_including("batch" => expected), anything, anything).and_return(@fake_response)
311
- Koala::Facebook::GraphAPI.new(access_token).batch do |batch_api|
310
+ Koala::Facebook::API.new(access_token).batch do |batch_api|
312
311
  batch_api.get_object('me')
313
312
  batch_api.get_object('me')
314
313
  end
@@ -324,7 +323,7 @@ describe "Koala::Facebook::GraphAPI in batch mode" do
324
323
  Koala::Facebook::BatchOperation.stub(:new).and_return(batch_op)
325
324
 
326
325
  Koala.should_receive(:make_request).with(anything, hash_including(@key => @uploadable_io), anything, anything).and_return(@fake_response)
327
- Koala::Facebook::GraphAPI.new("bar").batch do |batch_api|
326
+ Koala::Facebook::API.new("bar").batch do |batch_api|
328
327
  batch_api.put_picture("path/to/file", "image/jpeg")
329
328
  end
330
329
  end
@@ -337,7 +336,7 @@ describe "Koala::Facebook::GraphAPI in batch mode" do
337
336
  (args ||= {})["batch"].should =~ /.*me\/farglebarg.*otheruser\/bababa/
338
337
  @fake_response
339
338
  end
340
- Koala::Facebook::GraphAPI.new(access_token).batch do |batch_api|
339
+ Koala::Facebook::API.new(access_token).batch do |batch_api|
341
340
  batch_api.get_connections('me', "farglebarg")
342
341
  batch_api.get_connections('otheruser', "bababa")
343
342
  end
@@ -345,14 +344,14 @@ describe "Koala::Facebook::GraphAPI in batch mode" do
345
344
 
346
345
  it "makes a POST request" do
347
346
  Koala.should_receive(:make_request).with(anything, anything, "post", anything).and_return(@fake_response)
348
- Koala::Facebook::GraphAPI.new("foo").batch do |batch_api|
347
+ Koala::Facebook::API.new("foo").batch do |batch_api|
349
348
  batch_api.get_object('me')
350
349
  end
351
350
  end
352
351
 
353
352
  it "makes a request to /" do
354
353
  Koala.should_receive(:make_request).with("/", anything, anything, anything).and_return(@fake_response)
355
- Koala::Facebook::GraphAPI.new("foo").batch do |batch_api|
354
+ Koala::Facebook::API.new("foo").batch do |batch_api|
356
355
  batch_api.get_object('me')
357
356
  end
358
357
  end
@@ -360,7 +359,7 @@ describe "Koala::Facebook::GraphAPI in batch mode" do
360
359
  it "includes any http options specified at the top level" do
361
360
  http_options = {"a" => "baz"}
362
361
  Koala.should_receive(:make_request).with(anything, anything, anything, hash_including(http_options)).and_return(@fake_response)
363
- Koala::Facebook::GraphAPI.new("foo").batch(http_options) do |batch_api|
362
+ Koala::Facebook::API.new("foo").batch(http_options) do |batch_api|
364
363
  batch_api.get_object('me')
365
364
  end
366
365
  end
@@ -369,14 +368,14 @@ describe "Koala::Facebook::GraphAPI in batch mode" do
369
368
  describe "processing the request" do
370
369
  it "throws an error if the response is not 200" do
371
370
  Koala.stub(:make_request).and_return(Koala::Response.new(500, "[]", {}))
372
- expect { Koala::Facebook::GraphAPI.new("foo").batch do |batch_api|
371
+ expect { Koala::Facebook::API.new("foo").batch do |batch_api|
373
372
  batch_api.get_object('me')
374
373
  end }.to raise_exception(Koala::Facebook::APIError)
375
374
  end
376
375
 
377
376
  it "throws an error if the response is a Batch API-style error" do
378
377
  Koala.stub(:make_request).and_return(Koala::Response.new(200, '{"error":190,"error_description":"Error validating access token."}', {}))
379
- expect { Koala::Facebook::GraphAPI.new("foo").batch do |batch_api|
378
+ expect { Koala::Facebook::API.new("foo").batch do |batch_api|
380
379
  batch_api.get_object('me')
381
380
  end }.to raise_exception(Koala::Facebook::APIError)
382
381
  end
@@ -384,7 +383,7 @@ describe "Koala::Facebook::GraphAPI in batch mode" do
384
383
  it "returns the result status if http_component is status" do
385
384
  Koala.stub(:make_request).and_return(Koala::Response.new(200, '[{"code":203,"headers":[{"name":"Content-Type","value":"text/javascript; charset=UTF-8"}],"body":"{\"id\":\"1234\"}"}]', {}))
386
385
  result = @api.batch do |batch_api|
387
- batch_api.get_object("koppel", {}, :http_component => :status)
386
+ batch_api.get_object(KoalaTest.user1, {}, :http_component => :status)
388
387
  end
389
388
  result[0].should == 203
390
389
  end
@@ -392,7 +391,7 @@ describe "Koala::Facebook::GraphAPI in batch mode" do
392
391
  it "returns the result headers as a hash if http_component is headers" do
393
392
  Koala.stub(:make_request).and_return(Koala::Response.new(200, '[{"code":203,"headers":[{"name":"Content-Type","value":"text/javascript; charset=UTF-8"}],"body":"{\"id\":\"1234\"}"}]', {}))
394
393
  result = @api.batch do |batch_api|
395
- batch_api.get_object("koppel", {}, :http_component => :headers)
394
+ batch_api.get_object(KoalaTest.user1, {}, :http_component => :headers)
396
395
  end
397
396
  result[0].should == {"Content-Type" => "text/javascript; charset=UTF-8"}
398
397
  end
@@ -404,26 +403,26 @@ describe "Koala::Facebook::GraphAPI in batch mode" do
404
403
  thread_two_count = 0
405
404
  first_count = 20
406
405
  second_count = 10
407
-
406
+
408
407
  Koala.stub(:make_request).and_return(@fake_response)
409
408
 
410
409
  thread1 = Thread.new do
411
- @api.batch do |batch_api|
410
+ @api.batch do |batch_api|
412
411
  first_count.times {|i| batch_api.get_object("me"); sleep(0.01) }
413
412
  thread_one_count = batch_api.batch_calls.count
414
413
  end
415
414
  end
416
-
415
+
417
416
  thread2 = Thread.new do
418
- @api.batch do |batch_api|
417
+ @api.batch do |batch_api|
419
418
  second_count.times {|i| batch_api.get_object("me"); sleep(0.01) }
420
419
  thread_two_count = batch_api.batch_calls.count
421
420
  end
422
421
  end
423
-
422
+
424
423
  thread1.join
425
424
  thread2.join
426
-
425
+
427
426
  thread_one_count.should == first_count
428
427
  thread_two_count.should == second_count
429
428
  end
@@ -434,16 +433,7 @@ describe "Koala::Facebook::GraphAPI in batch mode" do
434
433
  it "can get two results at once" do
435
434
  me, koppel = @api.batch do |batch_api|
436
435
  batch_api.get_object('me')
437
- batch_api.get_object('koppel')
438
- end
439
- me['id'].should_not be_nil
440
- koppel['id'].should_not be_nil
441
- end
442
-
443
- it "works with GraphAndRestAPI instances" do
444
- me, koppel = Koala::Facebook::GraphAndRestAPI.new(@api.access_token).batch do |batch_api|
445
- batch_api.get_object('me')
446
- batch_api.get_object('koppel')
436
+ batch_api.get_object(KoalaTest.user1)
447
437
  end
448
438
  me['id'].should_not be_nil
449
439
  koppel['id'].should_not be_nil
@@ -477,7 +467,7 @@ describe "Koala::Facebook::GraphAPI in batch mode" do
477
467
  it "inserts errors in the appropriate place, without breaking other results" do
478
468
  failed_insights, koppel = @api.batch do |batch_api|
479
469
  batch_api.get_connections(@app_id, 'insights')
480
- batch_api.get_object("koppel", {}, {"access_token" => @app_api.access_token})
470
+ batch_api.get_object(KoalaTest.user1, {}, {"access_token" => @app_api.access_token})
481
471
  end
482
472
  failed_insights.should be_a(Koala::Facebook::APIError)
483
473
  koppel["id"].should_not be_nil
@@ -495,12 +485,12 @@ describe "Koala::Facebook::GraphAPI in batch mode" do
495
485
 
496
486
  it "allows FQL" do
497
487
  result = @api.batch do |batch_api|
498
- batch_api.graph_call("method/fql.query", {:query=>"select name from user where uid=4"}, "post")
488
+ batch_api.graph_call("method/fql.query", {:query=>"select first_name from user where uid=#{KoalaTest.user1_id}"}, "post")
499
489
  end
500
490
 
501
491
  fql_result = result[0]
502
492
  fql_result[0].should be_a(Hash)
503
- fql_result[0]["name"].should == "Mark Zuckerberg"
493
+ fql_result[0]["first_name"].should == "Alex"
504
494
  end
505
495
 
506
496
  describe "binary files" do
@@ -518,11 +508,12 @@ describe "Koala::Facebook::GraphAPI in batch mode" do
518
508
 
519
509
  it "posts binary files with multiple requests" do
520
510
  file = File.open(File.join(File.dirname(__FILE__), "..", "fixtures", "beach.jpg"))
511
+ file2 = File.open(File.join(File.dirname(__FILE__), "..", "fixtures", "beach.jpg"))
521
512
 
522
513
  Koala::Facebook::BatchOperation.instance_variable_set(:@identifier, 0)
523
514
  results = @api.batch do |batch_api|
524
515
  batch_api.put_picture(file)
525
- batch_api.put_picture(file, {}, "koppel")
516
+ batch_api.put_picture(file2, {}, KoalaTest.user1)
526
517
  end
527
518
  results[0]["id"].should_not be_nil
528
519
  results[1]["id"].should_not be_nil
@@ -553,7 +544,7 @@ describe "Koala::Facebook::GraphAPI in batch mode" do
553
544
  it "allows you to create dependencies" do
554
545
  me, koppel = @api.batch do |batch_api|
555
546
  batch_api.get_object("me", {}, :batch_args => {:name => "getme"})
556
- batch_api.get_object("koppel", {}, :batch_args => {:depends_on => "getme"})
547
+ batch_api.get_object(KoalaTest.user1, {}, :batch_args => {:depends_on => "getme"})
557
548
  end
558
549
 
559
550
  me.should be_nil # gotcha! it's omitted because it's a successfully-executed dependency
@@ -563,7 +554,7 @@ describe "Koala::Facebook::GraphAPI in batch mode" do
563
554
  it "properly handles dependencies that fail" do
564
555
  data, koppel = @api.batch do |batch_api|
565
556
  batch_api.get_connections(@app_id, 'insights', {}, :batch_args => {:name => "getdata"})
566
- batch_api.get_object("koppel", {}, :batch_args => {:depends_on => "getdata"})
557
+ batch_api.get_object(KoalaTest.user1, {}, :batch_args => {:depends_on => "getdata"})
567
558
  end
568
559
 
569
560
  data.should be_a(Koala::Facebook::APIError)
@@ -583,24 +574,24 @@ describe "Koala::Facebook::GraphAPI in batch mode" do
583
574
 
584
575
  describe "new interface" do
585
576
  it "includes a deprecation warning on GraphAPI" do
586
- begin
577
+ begin
587
578
  Koala::Facebook::GraphAPI.batch do
588
579
  end
589
580
  rescue NoMethodError => @err
590
581
  end
591
-
582
+
592
583
  # verify the message points people to the wiki page
593
584
  @err.should
594
585
  @err.message.should =~ /https\:\/\/github.com\/arsduo\/koala\/wiki\/Batch-requests/
595
586
  end
596
-
587
+
597
588
  it "includes a deprecation warning on GraphAndRESTAPI" do
598
- begin
589
+ begin
599
590
  Koala::Facebook::GraphAndRestAPI.batch do
600
591
  end
601
592
  rescue NoMethodError => @err
602
593
  end
603
-
594
+
604
595
  # verify the message points people to the wiki page
605
596
  @err.should
606
597
  @err.message.should =~ /https\:\/\/github.com\/arsduo\/koala\/wiki\/Batch-requests/