Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Browse files

Merge branch 'fix-travis' into debug_token

  • Loading branch information...
commit 8d6ee50496f506bcb98d7542f3ccfdca2ef36c28 2 parents 4cef14b + 1f7f473
@arsduo authored
View
3  changelog.md
@@ -5,6 +5,9 @@ Internal improvements:
* CHANGED: Gem version restrictions have been removed, and versions updated.
* CHANGED: How support files are loaded in spec_helper has been improved.
+Testing improvements:
+* FIXED: MockHTTPService compares Ruby objects rather than strings.
+
v1.6
====
View
40 lib/koala/api/graph_collection.rb
@@ -6,22 +6,22 @@ class API
# A light wrapper for collections returned from the Graph API.
# It extends Array to allow you to page backward and forward through
# result sets, and providing easy access to paging information.
- class GraphCollection < Array
-
+ class GraphCollection < Array
+
# The raw paging information from Facebook (next/previous URLs).
attr_reader :paging
# @return [Koala::Facebook::GraphAPI] the api used to make requests.
attr_reader :api
# The entire raw response from Facebook.
attr_reader :raw_response
-
+
# Initialize the array of results and store various additional paging-related information.
- #
+ #
# @param response the response from Facebook (a hash whose "data" key is an array)
# @param api the Graph {Koala::Facebook::API API} instance to use to make calls
# (usually the API that made the original call).
#
- # @return [Koala::Facebook::GraphCollection] an initialized GraphCollection
+ # @return [Koala::Facebook::GraphCollection] an initialized GraphCollection
# whose paging, raw_response, and api attributes are populated.
def initialize(response, api)
super response["data"]
@@ -31,32 +31,32 @@ def initialize(response, api)
end
# @private
- # Turn the response into a GraphCollection if they're pageable;
+ # Turn the response into a GraphCollection if they're pageable;
# if not, return the original response.
# The Ads API (uniquely so far) returns a hash rather than an array when queried
- # with get_connections.
+ # with get_connections.
def self.evaluate(response, api)
response.is_a?(Hash) && response["data"].is_a?(Array) ? self.new(response, api) : response
end
-
+
# Retrieve the next page of results.
- #
+ #
# @return a GraphCollection array of additional results (an empty array if there are no more results)
def next_page
base, args = next_page_params
base ? @api.get_page([base, args]) : nil
end
-
+
# Retrieve the previous page of results.
- #
+ #
# @return a GraphCollection array of additional results (an empty array if there are no earlier results)
def previous_page
base, args = previous_page_params
base ? @api.get_page([base, args]) : nil
end
-
- # Arguments that can be sent to {Koala::Facebook::API#graph_call} to retrieve the next page of results.
- #
+
+ # Arguments that can be sent to {Koala::Facebook::API#graph_call} to retrieve the next page of results.
+ #
# @example
# @api.graph_call(*collection.next_page_params)
#
@@ -64,9 +64,9 @@ def previous_page
def next_page_params
@paging && @paging["next"] ? parse_page_url(@paging["next"]) : nil
end
-
- # Arguments that can be sent to {Koala::Facebook::API#graph_call} to retrieve the previous page of results.
- #
+
+ # Arguments that can be sent to {Koala::Facebook::API#graph_call} to retrieve the previous page of results.
+ #
# @example
# @api.graph_call(*collection.previous_page_params)
#
@@ -74,7 +74,7 @@ def next_page_params
def previous_page_params
@paging && @paging["previous"] ? parse_page_url(@paging["previous"]) : nil
end
-
+
# @private
def parse_page_url(url)
GraphCollection.parse_page_url(url)
@@ -102,9 +102,9 @@ def self.parse_page_url(url)
end
end
end
-
+
# @private
- # legacy support for when GraphCollection lived directly under Koala::Facebook
+ # legacy support for when GraphCollection lived directly under Koala::Facebook
GraphCollection = API::GraphCollection
end
end
View
23 spec/cases/graph_api_batch_spec.rb
@@ -507,7 +507,6 @@
pictures = @api.batch do |batch_api|
batch_api.get_picture('me')
end
- puts pictures.inspect
pictures.first.should =~ /http\:\/\// # works both live & stubbed
end
@@ -553,35 +552,31 @@
let(:me_result) { stub("me result") }
let(:friends_result) { stub("friends result") }
- let(:me_callback) { lambda {|data| me_result } }
- let(:friends_callback) { lambda {|data| friends_result } }
+ let(:me_callback) { lambda {|arg| {"result" => me_result, "args" => arg} } }
+ let(:friends_callback) { lambda {|arg| {"result" => friends_result, "args" => arg} } }
it 'calls the callback with the appropriate data' do
- me_callback.should_receive(:call).with(hash_including(
- 'id' => KoalaTest.user1
- ))
- friends_callback.should_receive(:call).with([
- hash_including('id' => KoalaTest.user2)
- ])
- @api.batch do |batch_api|
+ me, friends = @api.batch do |batch_api|
batch_api.get_object('me', &me_callback)
batch_api.get_connections('me', 'friends', &friends_callback)
end
+ me["args"].should include("id" => KoalaTest.user1)
+ friends["args"].should include("id" => KoalaTest.user2)
end
it 'passes GraphCollections, not raw data' do
- friends_callback.should_receive(:call).with(kind_of(Koala::Facebook::API::GraphCollection))
- @api.batch do |batch_api|
+ me, friends = @api.batch do |batch_api|
batch_api.get_object('me')
batch_api.get_connections('me', 'friends', &friends_callback)
end
+ friends["args"].should be_a(Koala::Facebook::API::GraphCollection)
end
it "returns the result of the callback" do
@api.batch do |batch_api|
batch_api.get_object('me', &me_callback)
batch_api.get_connections('me', 'friends', &friends_callback)
- end.should == [me_result, friends_result]
+ end.map {|r| r["result"]}.should == [me_result, friends_result]
end
end
@@ -663,4 +658,4 @@
end
end
end
-end
+end
View
33 spec/cases/graph_api_spec.rb
@@ -10,27 +10,22 @@
end
describe 'post-processing for' do
- let(:post_processing) { lambda {} }
+ let(:result) { stub("result") }
+ let(:post_processing) { lambda {|arg| {"result" => result, "args" => arg} } }
# Most API methods have the same signature, we test get_object representatively
# and the other methods which do some post-processing locally
context '#get_object' do
it 'returns result of block' do
- result = {"id" => 1, "name" => 1, "updated_time" => 1}
- @api.stub(:api).and_return(result)
- post_processing.should_receive(:call).
- with(result).and_return('new result')
- @api.get_object('koppel', &post_processing).should == 'new result'
+ @api.stub(:api).and_return(stub("other results"))
+ @api.get_object('koppel', &post_processing)["result"].should == result
end
end
context '#get_picture' do
it 'returns result of block' do
- result = "http://facebook.com/"
- @api.stub(:api).and_return("Location" => result)
- post_processing.should_receive(:call).
- with(result).and_return('new result')
- @api.get_picture('lukeshepard', &post_processing).should == 'new result'
+ @api.stub(:api).and_return("Location" => stub("other result"))
+ @api.get_picture('lukeshepard', &post_processing)["result"].should == result
end
end
@@ -45,12 +40,11 @@
it 'is called with resolved response' do
resolved_result = {
'query1' => [{'id' => 123}],
- 'query2' => [{'id'=>456}]
+ 'query2' => [{'id' => 456}]
}
- post_processing.should_receive(:call).
- with(resolved_result).and_return('id'=>'123', 'id'=>'456')
- @api.fql_multiquery({}, &post_processing).should ==
- {'id'=>'123', 'id'=>'456'}
+ response = @api.fql_multiquery({}, &post_processing)
+ response["args"].should == resolved_result
+ response["result"].should == result
end
end
@@ -58,10 +52,9 @@
it 'returns result of block' do
token = Koala::MockHTTPService::APP_ACCESS_TOKEN
@api.stub(:api).and_return("access_token" => token)
- post_processing.should_receive(:call).
- with(token).and_return('base64-encoded access token')
- @api.get_page_access_token('facebook', &post_processing).should ==
- 'base64-encoded access token'
+ response = @api.get_page_access_token('facebook', &post_processing)
+ response["args"].should == token
+ response["result"].should == result
end
end
end
View
1  spec/cases/oauth_spec.rb
@@ -148,7 +148,6 @@
it "returns all the cookie components from valid cookie string" do
cookie_data = KoalaTest.oauth_test_data["valid_cookies"]
- puts cookie_data.inspect
parsing_results = @oauth.get_user_info_from_cookies(cookie_data)
number_of_components = cookie_data["fbs_#{@app_id.to_s}"].scan(/\=/).length
parsing_results.length.should == number_of_components
View
5 spec/fixtures/mock_facebook_responses.yml
@@ -126,9 +126,6 @@ graph_api:
post:
with_token: '[{"code": 200, "body":"{\"id\": \"MOCK_PHOTO\"}"}, {"code": 200, "body":"{\"id\": \"MOCK_PHOTO\"}"}]'
-
-
-
/me:
no_args:
get:
@@ -166,7 +163,7 @@ graph_api:
link=http://oauth.twoalex.com/&message=Hello, world, from the test suite again!&name=OAuth Playground:
post:
with_token: '{"id": "FEED_ITEM_CONTEXT"}'
- link=http://oauth.twoalex.com/&message=body&name=It's a big question&picture=http://oauth.twoalex.com//images/logo.png&properties=<%= {"name"=>"Link1'", "text"=>"Left", "href"=>"http://oauth.twoalex.com/"}.to_s %>=<%= {"name"=>"other", "text"=>"Straight ahead"}.to_s %>&type=link:
+ link=http://oauth.twoalex.com/&message=body&name=It's a big question&picture=http://oauth.twoalex.com//images/logo.png&properties=<%= MultiJson.encode([{"name"=>"Link1'", "text"=>"Left", "href"=>"http://oauth.twoalex.com/"}, {"name"=>"other", "text"=>"Straight ahead"}]) %>&type=link:
post:
with_token: '{"id": "FEED_ITEM_CONTEXT"}'
View
35 spec/spec_helper.rb
@@ -1,19 +1,21 @@
-# In Ruby 1.9.2 versions before patchlevel 290, the default Psych
-# parser has an issue with YAML merge keys, which
-# fixtures/mock_facebook_responses.yml relies heavily on.
-#
-# Anyone using an earlier version will see missing mock response
-# errors when running the test suite similar to this:
-#
-# RuntimeError:
-# Missing a mock response for graph_api: /me/videos: source=[FILE]: post: with_token
-# API PATH: /me/videos?source=[FILE]&format=json&access_token=*
-#
-# For now, it seems the best fix is to just downgrade to the old syck YAML parser
-# for these troubled versions.
-#
-# See https://github.com/tenderlove/psych/issues/8 for more details
-YAML::ENGINE.yamler = 'syck' if RUBY_VERSION == '1.9.2' && RUBY_PATCHLEVEL < 290
+if RUBY_VERSION == '1.9.2' && RUBY_PATCHLEVEL < 290 && RUBY_ENGINE != "macruby"
+ # In Ruby 1.9.2 versions before patchlevel 290, the default Psych
+ # parser has an issue with YAML merge keys, which
+ # fixtures/mock_facebook_responses.yml relies heavily on.
+ #
+ # Anyone using an earlier version will see missing mock response
+ # errors when running the test suite similar to this:
+ #
+ # RuntimeError:
+ # Missing a mock response for graph_api: /me/videos: source=[FILE]: post: with_token
+ # API PATH: /me/videos?source=[FILE]&format=json&access_token=*
+ #
+ # For now, it seems the best fix is to just downgrade to the old syck YAML parser
+ # for these troubled versions.
+ #
+ # See https://github.com/tenderlove/psych/issues/8 for more details
+ YAML::ENGINE.yamler = 'syck'
+end
# load the library
require 'koala'
@@ -22,7 +24,6 @@
# we have to first ensure consistent to_json behavior across versions
# otherwise mock_http_service may parse the YAML improperly
require 'support/ordered_hash'
-require 'support/json_testing_fix'
Dir["#{File.dirname(__FILE__)}/support/**/*.rb"].each { |f| require f }
# set up our testing environment
View
15 spec/support/graph_api_shared_examples.rb
@@ -251,23 +251,22 @@
it "can post a message whose attachment has a properties dictionary" do
url = KoalaTest.oauth_test_data["callback_url"]
- options = {
- "picture" => "#{KoalaTest.oauth_test_data["callback_url"]}/images/logo.png",
- "name" => "It's a big question",
- "type" => "link",
- "link" => KoalaTest.oauth_test_data["callback_url"],
- "properties" => [
+ args = {
+ "picture" => "#{KoalaTest.oauth_test_data["callback_url"]}/images/logo.png",
+ "name" => "It's a big question",
+ "type" => "link",
+ "link" => KoalaTest.oauth_test_data["callback_url"],
+ "properties" => [
{"name" => "Link1'", "text" => "Left", "href" => url},
{"name" => "other", "text" => "Straight ahead"}
]
}
- result = @api.put_wall_post("body", options)
+ result = @api.put_wall_post("body", args)
@temporary_object_id = result["id"]
@temporary_object_id.should_not be_nil
end
-
describe "#put_picture" do
it "can post photos to the user's wall with an open file object" do
content_type = "image/jpg"
View
2  spec/support/koala_test.rb
@@ -81,7 +81,7 @@ def self.setup_test_data(data)
self.oauth_test_data = data["oauth_test_data"]
self.subscription_test_data = data["subscription_test_data"]
self.oauth_token = data["oauth_token"]
- self.app_id = data["oauth_test_data"]["app_id"]
+ self.app_id = data["oauth_test_data"]["app_id"].to_s
self.app_access_token = data["oauth_test_data"]["app_access_token"]
self.secret = data["oauth_test_data"]["secret"]
self.code = data["oauth_test_data"]["code"]
View
110 spec/support/mock_http_service.rb
@@ -36,41 +36,22 @@ module MockHTTPService
RESPONSES = YAML.load(ERB.new(IO.read(mock_response_file_path)).result(binding))
def self.make_request(path, args, verb, options = {})
- path = 'root' if path == '' || path == '/'
- verb ||= 'get'
- server = options[:rest_api] ? 'rest_api' : 'graph_api'
- token = args.delete('access_token')
- with_token = (token == ACCESS_TOKEN || token == APP_ACCESS_TOKEN) ? 'with_token' : 'no_token'
-
- # Assume format is always JSON
- args.delete('format')
-
- # Create a hash key for the arguments
- args = create_params_key(args)
-
- begin
- response = RESPONSES[server][path][args][verb][with_token]
-
- # Raises an error of with_token/no_token key is missing
- raise NoMethodError unless response
-
+ if response = match_response(path, args, verb, options)
# create response class object
response_object = if response.is_a? String
- Koala::HTTPService::Response.new(200, response, {})
- else
- Koala::HTTPService::Response.new(response["code"] || 200, response["body"] || "", response["headers"] || {})
- end
-
- rescue NoMethodError
+ Koala::HTTPService::Response.new(200, response, {})
+ else
+ Koala::HTTPService::Response.new(response["code"] || 200, response["body"] || "", response["headers"] || {})
+ end
+ else
# Raises an error message with the place in the data YML
# to place a mock as well as a URL to request from
# Facebook's servers for the actual data
# (Don't forget to replace ACCESS_TOKEN with a real access token)
- data_trace = [server, path, args, verb, with_token] * ': '
+ data_trace = [path, args, verb, options] * ': '
args = args == 'no_args' ? '' : "#{args}&"
args += 'format=json'
- args += "&access_token=#{ACCESS_TOKEN}" if with_token
raise "Missing a mock response for #{data_trace}\nAPI PATH: #{[path, args].join('?')}"
end
@@ -85,15 +66,78 @@ def self.encode_params(*args)
protected
- def self.create_params_key(params_hash)
- if params_hash.empty?
- 'no_args'
+ # For a given query, see if our mock responses YAML has a resopnse for it.
+ def self.match_response(path, args, verb, options = {})
+ server = options[:rest_api] ? 'rest_api' : 'graph_api'
+ path = 'root' if path == '' || path == '/'
+ verb = (verb || 'get').to_s
+ token = args.delete('access_token')
+ with_token = (token == ACCESS_TOKEN || token == APP_ACCESS_TOKEN) ? 'with_token' : 'no_token'
+
+ if endpoint = RESPONSES[server][path]
+ # see if we have a match for the arguments
+ if arg_match = endpoint.find {|query, v| decode_query(query) == massage_args(args)}
+ # we have a match for the server/path/arguments
+ # so if it's the right verb and authentication, we're good
+ # arg_match will be [query, hash_response]
+ arg_match.last[verb][with_token]
+ end
+ end
+ end
+
+ # Since we're comparing the arguments with data in a yaml file, we need to
+ # massage them slightly to get to the format we expect.
+ def self.massage_args(arguments)
+ args = arguments.inject({}) do |hash, (k, v)|
+ # ensure our args are all stringified
+ value = if v.is_a?(String)
+ should_json_decode?(v) ? MultiJson.load(v) : v
+ elsif v.is_a?(Koala::UploadableIO)
+ # obviously there are no files in the yaml
+ "[FILE]"
+ else
+ v
+ end
+ # make sure all keys are strings
+ hash.merge(k.to_s => value)
+ end
+
+ # Assume format is always JSON
+ args.delete('format')
+
+ # if there are no args, return the special keyword no_args
+ args.empty? ? "no_args" : args
+ end
+
+ # Facebook sometimes requires us to encode JSON values in an HTTP query
+ # param. This complicates test matches, since we get into JSON-encoding
+ # issues (what order keys are written into). To avoid string comparisons
+ # and the hacks required to make it work, we decode the query into a
+ # Ruby object.
+ def self.decode_query(string)
+ if string == "no_args"
+ string
else
- params_hash.sort{ |a,b| a[0].to_s <=> b[0].to_s}.map do |arr|
- arr[1] = '[FILE]' if arr[1].kind_of?(Koala::UploadableIO)
- arr.join('=')
- end.join('&')
+ # we can't use Faraday's decode_query because that CGI-unencodes, which
+ # will remove +'s in restriction strings
+ string.split("&").reduce({}) do |hash, component|
+ k, v = component.split("=", 2) # we only care about the first =
+ value = should_json_decode?(v) ? MultiJson.decode(v) : v.to_s rescue v.to_s
+ # some special-casing, unfortunate but acceptable in this testing
+ # environment
+ value = nil if value.empty?
+ value = true if value == "true"
+ value = false if value == "false"
+ hash.merge(k => value)
+ end
end
end
+
+ # We want to decode JSON because it may not be encoded in the same order
+ # all the time -- different Rubies may create a strings with equivalent
+ # content but different order. We want to compare the objects.
+ def self.should_json_decode?(v)
+ v.match(/^[\[\{]/)
+ end
end
end
Please sign in to comment.
Something went wrong with that request. Please try again.