Continue internal shuffling...

This commit is contained in:
Steven Bazyl 2012-09-24 16:09:17 -07:00
parent f9c1ab67ba
commit fc45135fcd
13 changed files with 503 additions and 385 deletions

View File

@ -1,3 +1,9 @@
# 0.5.0
* Beta candidate, potential incompatible changes with how requests are processed. All requests
should be made using execute() or execute!()
* Reduce memory utilization when uploading large files
* Simplify internal request processing.
# 0.4.7 # 0.4.7
* Added the ability to convert client secrets to an authorization object * Added the ability to convert client secrets to an authorization object

View File

@ -30,9 +30,6 @@ require 'google/api_client/service_account'
require 'google/api_client/batch' require 'google/api_client/batch'
module Google module Google
# TODO(bobaman): Document all this stuff.
## ##
# This class manages APIs communication. # This class manages APIs communication.
class APIClient class APIClient
@ -66,23 +63,23 @@ module Google
def initialize(options={}) def initialize(options={})
# Normalize key to String to allow indifferent access. # Normalize key to String to allow indifferent access.
options = options.inject({}) do |accu, (key, value)| options = options.inject({}) do |accu, (key, value)|
accu[key.to_s] = value accu[key.to_sym] = value
accu accu
end end
# Almost all API usage will have a host of 'www.googleapis.com'. # Almost all API usage will have a host of 'www.googleapis.com'.
self.host = options["host"] || 'www.googleapis.com' self.host = options[:host] || 'www.googleapis.com'
self.port = options["port"] || 443 self.port = options[:port] || 443
self.discovery_path = options["discovery_path"] || '/discovery/v1' self.discovery_path = options[:discovery_path] || '/discovery/v1'
# Most developers will want to leave this value alone and use the # Most developers will want to leave this value alone and use the
# application_name option. # application_name option.
application_string = ( application_string = (
options["application_name"] ? ( options[:application_name] ? (
"#{options["application_name"]}/" + "#{options[:application_name]}/" +
"#{options["application_version"] || '0.0.0'}" "#{options[:application_version] || '0.0.0'}"
) : "" ) : ""
) )
self.user_agent = options["user_agent"] || ( self.user_agent = options[:user_agent] || (
"#{application_string} " + "#{application_string} " +
"google-api-ruby-client/#{VERSION::STRING} " + "google-api-ruby-client/#{VERSION::STRING} " +
ENV::OS_VERSION ENV::OS_VERSION
@ -90,9 +87,9 @@ module Google
# The writer method understands a few Symbols and will generate useful # The writer method understands a few Symbols and will generate useful
# default authentication mechanisms. # default authentication mechanisms.
self.authorization = self.authorization =
options.key?("authorization") ? options["authorization"] : :oauth_2 options.key?(:authorization) ? options[:authorization] : :oauth_2
self.key = options["key"] self.key = options[:key]
self.user_ip = options["user_ip"] self.user_ip = options[:user_ip]
@discovery_uris = {} @discovery_uris = {}
@discovery_documents = {} @discovery_documents = {}
@discovered_apis = {} @discovered_apis = {}
@ -195,31 +192,6 @@ module Google
# The base path. Should almost always be '/discovery/v1'. # The base path. Should almost always be '/discovery/v1'.
attr_accessor :discovery_path attr_accessor :discovery_path
##
# Resolves a URI template against the client's configured base.
#
# @param [String, Addressable::URI, Addressable::Template] template
# The template to resolve.
# @param [Hash] mapping The mapping that corresponds to the template.
# @return [Addressable::URI] The expanded URI.
def resolve_uri(template, mapping={})
@base_uri ||= Addressable::URI.new(
:scheme => 'https',
:host => self.host,
:port => self.port
).normalize
template = if template.kind_of?(Addressable::Template)
template.pattern
elsif template.respond_to?(:to_str)
template.to_str
else
raise TypeError,
"Expected String, Addressable::URI, or Addressable::Template, " +
"got #{template.class}."
end
return Addressable::Template.new(@base_uri + template).expand(mapping)
end
## ##
# Returns the URI for the directory document. # Returns the URI for the directory document.
# #
@ -292,7 +264,7 @@ module Google
response = self.execute!( response = self.execute!(
:http_method => :get, :http_method => :get,
:uri => self.directory_uri, :uri => self.directory_uri,
:authorization => :none :authenticated => false
) )
response.data response.data
end) end)
@ -311,7 +283,7 @@ module Google
response = self.execute!( response = self.execute!(
:http_method => :get, :http_method => :get,
:uri => self.discovery_uri(api, version), :uri => self.discovery_uri(api, version),
:authorization => :none :authenticated => false
) )
response.data response.data
end) end)
@ -447,7 +419,7 @@ module Google
response = self.execute!( response = self.execute!(
:http_method => :get, :http_method => :get,
:uri => 'https://www.googleapis.com/oauth2/v1/certs', :uri => 'https://www.googleapis.com/oauth2/v1/certs',
:authorization => :none :authenticated => false
) )
@certificates.merge!( @certificates.merge!(
Hash[MultiJson.load(response.body).map do |key, cert| Hash[MultiJson.load(response.body).map do |key, cert|
@ -464,31 +436,6 @@ module Google
return nil return nil
end end
def normalize_api_method(options)
method = options[:api_method]
version = options[:version]
if method.kind_of?(Google::APIClient::Method) || method == nil
return method
elsif method.respond_to?(:to_str) || method.kind_of?(Symbol)
# This method of guessing the API is unreliable. This will fail for
# APIs where the first segment of the RPC name does not match the
# service name. However, this is a fallback mechanism anyway.
# Developers should be passing in a reference to the method, rather
# than passing in a string or symbol. This should raise an error
# in the case of a mismatch.
method = method.to_s
api = method[/^([^.]+)\./, 1]
api_method = self.discovered_method(method, api, version)
if api_method.nil?
raise ArgumentError, "API method could not be found."
end
return api_method
else
raise TypeError,
"Expected Google::APIClient::Method, got #{new_api_method.class}."
end
end
## ##
# Generates a request. # Generates a request.
# #
@ -516,46 +463,19 @@ module Google
# {'collection' => 'public', 'userId' => 'me'} # {'collection' => 'public', 'userId' => 'me'}
# ) # )
def generate_request(options={}) def generate_request(options={})
# Note: The merge method on a Hash object will coerce an API Reference options = {
# object into a Hash and merge with the default options. :api_client => self
options={
:version => 'v1',
:authorization => self.authorization,
:key => self.key,
:user_ip => self.user_ip,
:connection => Faraday.default_connection
}.merge(options) }.merge(options)
return Google::APIClient::Request.new(options)
options[:api_method] = self.normalize_api_method(options) unless options[:api_method].nil?
return Google::APIClient::Reference.new(options)
end
##
# Transmits the request using the current HTTP adapter.
#
# @option options [Array, Faraday::Request] :request
# The HTTP request to transmit.
# @option options [Faraday::Connection] :connection
# The HTTP connection to use.
#
# @return [Faraday::Response] The response from the server.
def transmit(options={})
options[:connection] ||= Faraday.default_connection
request = options[:request]
request['User-Agent'] ||= '' + self.user_agent unless self.user_agent.nil?
request_env = request.to_env(options[:connection])
response = options[:connection].app.call(request_env)
return response
end end
## ##
# Executes a request, wrapping it in a Result object. # Executes a request, wrapping it in a Result object.
# #
# @param [Google::APIClient::BatchRequest, Hash, Array] params # @param [Google::APIClient::Request, Hash, Array] params
# Either a Google::APIClient::BatchRequest, a Hash, or an Array. # Either a Google::APIClient::Request, a Hash, or an Array.
# #
# If a Google::APIClient::BatchRequest, no other parameters are expected. # If a Google::APIClient::Request, no other parameters are expected.
# #
# If a Hash, the below parameters are handled. If an Array, the # If a Hash, the below parameters are handled. If an Array, the
# parameters are assumed to be in the below order: # parameters are assumed to be in the below order:
@ -592,6 +512,7 @@ module Google
if params.last.kind_of?(Google::APIClient::Request) && if params.last.kind_of?(Google::APIClient::Request) &&
params.size == 1 params.size == 1
request = params.pop request = params.pop
options = {}
else else
# This block of code allows us to accept multiple parameter passing # This block of code allows us to accept multiple parameter passing
# styles, and maintaining some backwards compatibility. # styles, and maintaining some backwards compatibility.
@ -610,13 +531,16 @@ module Google
options[:client] = self options[:client] = self
request = self.generate_request(options) request = self.generate_request(options)
end end
response = self.transmit(:request => request.to_http_request, :connection => Faraday.default_connection)
result = request.process_response(response) connection = options[:connection] || Faraday.default_connection
request.authorization = options[:authorization] || self.authorization unless options[:authenticated] == false
result = request.send(connection)
if request.upload_type == 'resumable' if request.upload_type == 'resumable'
upload = result.resumable_upload upload = result.resumable_upload
unless upload.complete? unless upload.complete?
response = self.transmit(:request => upload.to_http_request, :connection => Faraday.default_connection) result = upload.send(connection)
result = upload.process_response(response)
end end
end end
return result return result
@ -646,6 +570,61 @@ module Google
end end
return result return result
end end
##
# Ensures API method names specified as strings resolve to
# discovered method instances
def resolve_method(method, version)
version ||= 'v1'
if method.kind_of?(Google::APIClient::Method) || method == nil
return method
elsif method.respond_to?(:to_str) || method.kind_of?(Symbol)
# This method of guessing the API is unreliable. This will fail for
# APIs where the first segment of the RPC name does not match the
# service name. However, this is a fallback mechanism anyway.
# Developers should be passing in a reference to the method, rather
# than passing in a string or symbol. This should raise an error
# in the case of a mismatch.
method = method.to_s
api = method[/^([^.]+)\./, 1]
api_method = self.discovered_method(method, api, version)
if api_method.nil?
raise ArgumentError, "API method could not be found."
end
return api_method
else
raise TypeError,
"Expected Google::APIClient::Method, got #{method.class}."
end
end
protected
##
# Resolves a URI template against the client's configured base.
#
# @param [String, Addressable::URI, Addressable::Template] template
# The template to resolve.
# @param [Hash] mapping The mapping that corresponds to the template.
# @return [Addressable::URI] The expanded URI.
def resolve_uri(template, mapping={})
@base_uri ||= Addressable::URI.new(
:scheme => 'https',
:host => self.host,
:port => self.port
).normalize
template = if template.kind_of?(Addressable::Template)
template.pattern
elsif template.respond_to?(:to_str)
template.to_str
else
raise TypeError,
"Expected String, Addressable::URI, or Addressable::Template, " +
"got #{template.class}."
end
return Addressable::Template.new(@base_uri + template).expand(mapping)
end
end end
end end

View File

@ -40,8 +40,7 @@ module Google
# Creates a new batch request. # Creates a new batch request.
# #
# @param [Hash] options # @param [Hash] options
# Set of options for this request, the only important one being # Set of options for this request
# :connection, which specifies an HTTP connection to use.
# @param [Proc] block # @param [Proc] block
# Callback for every call's response. Won't be called if a call defined # Callback for every call's response. Won't be called if a call defined
# a callback of its own. # a callback of its own.
@ -67,7 +66,7 @@ module Google
# automatically be generated, avoiding collisions. If duplicate call IDs # automatically be generated, avoiding collisions. If duplicate call IDs
# are provided, an error will be thrown. # are provided, an error will be thrown.
# #
# @param [Hash, Google::APIClient::Reference] call: the call to be added. # @param [Hash, Google::APIClient::Request] call: the call to be added.
# @param [String] call_id: the ID to be used for this call. Must be unique # @param [String] call_id: the ID to be used for this call. Must be unique
# @param [Proc] block: callback for this call's response. # @param [Proc] block: callback for this call's response.
# #
@ -90,7 +89,7 @@ module Google
# Processes the HTTP response to the batch request, issuing callbacks. # Processes the HTTP response to the batch request, issuing callbacks.
# #
# @param [Faraday::Response] response: the HTTP response. # @param [Faraday::Response] response: the HTTP response.
def process_response(response) def process_http_response(response)
content_type = find_header('Content-Type', response.headers) content_type = find_header('Content-Type', response.headers)
boundary = /.*boundary=(.+)/.match(content_type)[1] boundary = /.*boundary=(.+)/.match(content_type)[1]
parts = response.body.split(/--#{Regexp.escape(boundary)}/) parts = response.body.split(/--#{Regexp.escape(boundary)}/)
@ -212,21 +211,22 @@ module Google
# #
# @return [StringIO] The request as a string in application/http format. # @return [StringIO] The request as a string in application/http format.
def serialize_call(call_id, call) def serialize_call(call_id, call)
http_request = call.to_http_request call.api_client = self.api_client
body = "#{http_request.method.to_s.upcase} #{http_request.path} HTTP/1.1" method, uri, headers, body = call.to_http_request
http_request.headers.each do |header, value| request = "#{method.to_s.upcase} #{Addressable::URI.parse(uri).path} HTTP/1.1"
body << "\r\n%s: %s" % [header, value] headers.each do |header, value|
request << "\r\n%s: %s" % [header, value]
end end
if http_request.body if body
# TODO - CompositeIO if body is a stream # TODO - CompositeIO if body is a stream
body << "\r\n\r\n" request << "\r\n\r\n"
if http_request.body.respond_to?(:read) if body.respond_to?(:read)
body << http_request.body.read request << body.read
else else
body << http_request.body.to_s request << body.to_s
end end
end end
Faraday::UploadIO.new(StringIO.new(body), 'application/http', 'ruby-api-request', 'Content-ID' => id_to_header(call_id)) Faraday::UploadIO.new(StringIO.new(request), 'application/http', 'ruby-api-request', 'Content-ID' => id_to_header(call_id))
end end
## ##

View File

@ -222,21 +222,14 @@ module Google
# The HTTP connection to use. # The HTTP connection to use.
# #
# @return [Array] The generated HTTP request. # @return [Array] The generated HTTP request.
def generate_request(parameters={}, body='', headers=[], options={}) def generate_request(parameters={}, body='', headers={}, options={})
options[:connection] ||= Faraday.default_connection
if !headers.kind_of?(Array) && !headers.kind_of?(Hash) if !headers.kind_of?(Array) && !headers.kind_of?(Hash)
raise TypeError, "Expected Hash or Array, got #{headers.class}." raise TypeError, "Expected Hash or Array, got #{headers.class}."
end end
method = self.http_method method = self.http_method.to_s.downcase.to_sym
uri = self.generate_uri(parameters) uri = self.generate_uri(parameters)
headers = headers.to_a if headers.kind_of?(Hash) headers = Faraday::Utils::Headers.new(headers)
return options[:connection].build_request( return [method, uri, headers, body]
method.to_s.downcase.to_sym
) do |req|
req.url(Addressable::URI.parse(uri).to_s)
req.headers = Faraday::Utils::Headers.new(headers)
req.body = body
end
end end

View File

@ -131,7 +131,7 @@ module Google
# #
# @param [Faraday::Response] r # @param [Faraday::Response] r
# Result of a chunk upload or range query # Result of a chunk upload or range query
def process_response(response) def process_http_response(response)
case response.status case response.status
when 200...299 when 200...299
@complete = true @complete = true

View File

@ -26,23 +26,23 @@ module Google
class Request class Request
MULTIPART_BOUNDARY = "-----------RubyApiMultipartPost".freeze MULTIPART_BOUNDARY = "-----------RubyApiMultipartPost".freeze
attr_reader :connection, :parameters, :api_method, :headers attr_reader :parameters, :headers
attr_accessor :media, :authorization, :body attr_accessor :api_client, :connection, :api_method, :version ,:media, :authorization, :authenticated, :body
def initialize(options={}) def initialize(options={})
self.connection = options[:connection] || Faraday.default_connection
self.authorization = options[:authorization]
self.api_method = options[:api_method]
@parameters = Hash[options[:parameters] || {}] @parameters = Hash[options[:parameters] || {}]
@headers = Faraday::Utils::Headers.new
self.api_client = options[:api_client]
self.headers.merge!(options[:headers]) unless options[:headers].nil?
self.api_method = options[:api_method]
self.version = options[:version]
self.authenticated = options[:authenticated]
self.authorization = options[:authorization]
# These parameters are handled differently because they're not # These parameters are handled differently because they're not
# parameters to the API method, but rather to the API system. # parameters to the API method, but rather to the API system.
self.parameters['key'] ||= options[:key] if options[:key] self.parameters['key'] ||= options[:key] if options[:key]
self.parameters['userIp'] ||= options[:user_ip] if options[:user_ip] self.parameters['userIp'] ||= options[:user_ip] if options[:user_ip]
@headers = Faraday::Utils::Headers.new
self.headers.merge!(options[:headers]) if options[:headers]
if options[:media] if options[:media]
self.initialize_media_upload(options) self.initialize_media_upload(options)
@ -58,12 +58,102 @@ module Google
unless self.api_method unless self.api_method
self.http_method = options[:http_method] || 'GET' self.http_method = options[:http_method] || 'GET'
self.uri = options[:uri] self.uri = options[:uri]
unless self.parameters.empty?
self.uri.query = Addressable::URI.form_encode(self.parameters)
end
end end
end end
def upload_type
return self.parameters['uploadType'] || self.parameters['upload_type']
end
def http_method
return @http_method ||= self.api_method.http_method.to_s.downcase.to_sym
end
def http_method=(new_http_method)
if new_http_method.kind_of?(Symbol)
@http_method = new_http_method.to_s.downcase.to_sym
elsif new_http_method.respond_to?(:to_str)
@http_method = new_http_method.to_s.downcase.to_sym
else
raise TypeError,
"Expected String or Symbol, got #{new_http_method.class}."
end
end
def uri
return @uri ||= self.api_method.generate_uri(self.parameters)
end
def uri=(new_uri)
@uri = Addressable::URI.parse(new_uri)
@parameters.update(@uri.query_values) unless @uri.query_values.nil?
end
def send(connection)
response = connection.app.call(self.to_env(connection))
self.process_http_response(response)
end
def to_http_request
if self.api_client
self.headers['User-Agent'] ||= '' + self.api_client.user_agent unless self.api_client.user_agent.nil?
self.parameters['key'] ||= self.api_client.key unless self.api_client.key.nil?
self.parameters['userIp'] ||= self.api_client.user_ip unless self.api_client.user_ip.nil?
self.api_method = self.api_client.resolve_method(self.api_method, self.version) unless self.api_method.nil?
end
request = (
if self.uri
unless self.parameters.empty?
self.uri.query = Addressable::URI.form_encode(self.parameters)
end
[self.http_method, self.uri.to_s, self.headers, self.body]
else
self.api_method.generate_request(self.parameters, self.body, self.headers)
end)
end
def to_hash
options = {}
if self.api_method
options[:api_method] = self.api_method
options[:parameters] = self.parameters
else
options[:http_method] = self.http_method
options[:uri] = self.uri
end
options[:headers] = self.headers
options[:body] = self.body
options[:media] = self.media
unless self.authorization.nil?
options[:authorization] = self.authorization
end
return options
end
def to_env(connection)
method, uri, headers, body = self.to_http_request
http_request = connection.build_request(method) do |req|
req.url(uri)
req.headers.update(headers)
req.body = body
end
if self.authorization.respond_to?(:generate_authenticated_request)
http_request = self.authorization.generate_authenticated_request(
:request => http_request,
:connection => connection
)
end
request_env = http_request.to_env(connection)
end
def process_http_response(response)
Result.new(self, response)
end
protected
def initialize_media_upload(options) def initialize_media_upload(options)
self.media = options[:media] self.media = options[:media]
case self.upload_type case self.upload_type
@ -109,97 +199,6 @@ module Google
'Must respond to :to_json or :to_hash.' 'Must respond to :to_json or :to_hash.'
end end
def upload_type
return self.parameters['uploadType'] || self.parameters['upload_type']
end
def connection=(new_connection)
if new_connection.kind_of?(Faraday::Connection)
@connection = new_connection
else
raise TypeError,
"Expected Faraday::Connection, got #{new_connection.class}."
end
end
def api_method=(new_api_method)
if new_api_method.kind_of?(Google::APIClient::Method) ||
new_api_method == nil
@api_method = new_api_method
else
raise TypeError,
"Expected Google::APIClient::Method, got #{new_api_method.class}."
end
end
def http_method
return @http_method ||= self.api_method.http_method.to_s.downcase.to_sym
end
def http_method=(new_http_method)
if new_http_method.kind_of?(Symbol)
@http_method = new_http_method.to_s.downcase.to_sym
elsif new_http_method.respond_to?(:to_str)
@http_method = new_http_method.to_s.downcase.to_sym
else
raise TypeError,
"Expected String or Symbol, got #{new_http_method.class}."
end
end
def uri
return @uri ||= self.api_method.generate_uri(self.parameters)
end
def uri=(new_uri)
@uri = Addressable::URI.parse(new_uri)
end
def to_http_request
request = (
if self.uri
self.connection.build_request(self.http_method) do |req|
req.url(self.uri.to_str)
req.headers.update(self.headers)
req.body = self.body
end
else
self.api_method.generate_request(
self.parameters, self.body, self.headers, :connection => self.connection
)
end)
if self.authorization.respond_to?(:generate_authenticated_request)
request = self.authorization.generate_authenticated_request(
:request => request,
:connection => self.connection
)
end
return request
end
def to_hash
options = {}
if self.api_method
options[:api_method] = self.api_method
options[:parameters] = self.parameters
else
options[:http_method] = self.http_method
options[:uri] = self.uri
end
options[:headers] = self.headers
options[:body] = self.body
options[:connection] = self.connection
options[:media] = self.media
unless self.authorization.nil?
options[:authorization] = self.authorization
end
return options
end
def process_response(response)
Result.new(self, response)
end
end end
class Reference < Request class Reference < Request

View File

@ -226,7 +226,7 @@ describe Google::APIClient::BatchRequest do
it 'should convert to a correct HTTP request' do it 'should convert to a correct HTTP request' do
batch = Google::APIClient::BatchRequest.new { |result| } batch = Google::APIClient::BatchRequest.new { |result| }
batch.add(@call1, '1').add(@call2, '2') batch.add(@call1, '1').add(@call2, '2')
request = batch.to_http_request.to_env(Faraday.default_connection) request = batch.to_env(Faraday.default_connection)
boundary = Google::APIClient::BatchRequest::BATCH_BOUNDARY boundary = Google::APIClient::BatchRequest::BATCH_BOUNDARY
request[:method].to_s.downcase.should == 'post' request[:method].to_s.downcase.should == 'post'
request[:url].to_s.should == 'https://www.googleapis.com/batch' request[:url].to_s.should == 'https://www.googleapis.com/batch'

View File

@ -25,7 +25,24 @@ require 'signet/oauth_1/client'
require 'google/api_client' require 'google/api_client'
require 'google/api_client/version' require 'google/api_client/version'
def TestHandler
def initialize(&block)
@block = block
end
def call(env)
@block.call(env)
end
end
def mock_connection(&block)
connection = Faraday.new do |builder|
use TestHandler block
end
end
describe Google::APIClient do describe Google::APIClient do
include ConnectionHelpers
CLIENT = Google::APIClient.new unless defined?(CLIENT) CLIENT = Google::APIClient.new unless defined?(CLIENT)
after do after do
@ -63,7 +80,7 @@ describe Google::APIClient do
it 'should raise an error for bogus methods' do it 'should raise an error for bogus methods' do
(lambda do (lambda do
CLIENT.generate_request(42) CLIENT.execute(42)
end).should raise_error(TypeError) end).should raise_error(TypeError)
end end
@ -86,44 +103,49 @@ describe Google::APIClient do
it 'should correctly determine the discovery URI if :user_ip is set' do it 'should correctly determine the discovery URI if :user_ip is set' do
CLIENT.user_ip = '127.0.0.1' CLIENT.user_ip = '127.0.0.1'
request = CLIENT.generate_request(
conn = stub_connection do |stub|
stub.get('/discovery/v1/apis/prediction/v1.2/rest?userIp=127.0.0.1') do |env|
end
end
CLIENT.execute(
:http_method => 'GET', :http_method => 'GET',
:uri => CLIENT.discovery_uri('prediction', 'v1.2'), :uri => CLIENT.discovery_uri('prediction', 'v1.2'),
:authenticated => false :authenticated => false,
) :connection => conn
request.to_http_request.to_env(Faraday.default_connection)[:url].to_s.should === (
'https://www.googleapis.com/discovery/v1/apis/prediction/v1.2/rest' +
'?userIp=127.0.0.1'
) )
conn.verify
end end
it 'should correctly determine the discovery URI if :key is set' do it 'should correctly determine the discovery URI if :key is set' do
CLIENT.key = 'qwerty' CLIENT.key = 'qwerty'
request = CLIENT.generate_request( conn = stub_connection do |stub|
stub.get('/discovery/v1/apis/prediction/v1.2/rest?key=qwerty') do |env|
end
end
request = CLIENT.execute(
:http_method => 'GET', :http_method => 'GET',
:uri => CLIENT.discovery_uri('prediction', 'v1.2'), :uri => CLIENT.discovery_uri('prediction', 'v1.2'),
:authenticated => false :authenticated => false,
) :connection => conn
request.to_http_request.to_env(Faraday.default_connection)[:url].to_s.should === ( )
'https://www.googleapis.com/discovery/v1/apis/prediction/v1.2/rest' + conn.verify
'?key=qwerty'
)
end end
it 'should correctly determine the discovery URI if both are set' do it 'should correctly determine the discovery URI if both are set' do
CLIENT.key = 'qwerty' CLIENT.key = 'qwerty'
CLIENT.user_ip = '127.0.0.1' CLIENT.user_ip = '127.0.0.1'
request = CLIENT.generate_request( conn = stub_connection do |stub|
stub.get('/discovery/v1/apis/prediction/v1.2/rest?key=qwerty&userIp=127.0.0.1') do |env|
end
end
request = CLIENT.execute(
:http_method => 'GET', :http_method => 'GET',
:uri => CLIENT.discovery_uri('prediction', 'v1.2'), :uri => CLIENT.discovery_uri('prediction', 'v1.2'),
:authenticated => false :authenticated => false,
) :connection => conn
Addressable::URI.parse( )
request.to_http_request.to_env(Faraday.default_connection)[:url] conn.verify
).query_values.should == {
'key' => 'qwerty',
'userIp' => '127.0.0.1'
}
end end
it 'should correctly generate API objects' do it 'should correctly generate API objects' do
@ -165,7 +187,7 @@ describe Google::APIClient do
it 'should raise an error for bogus methods' do it 'should raise an error for bogus methods' do
(lambda do (lambda do
CLIENT.generate_request(CLIENT.discovered_api('prediction', 'v1.2')) CLIENT.execute(:api_method => CLIENT.discovered_api('prediction', 'v1.2'))
end).should raise_error(TypeError) end).should raise_error(TypeError)
end end
@ -179,44 +201,58 @@ describe Google::APIClient do
end end
it 'should generate valid requests' do it 'should generate valid requests' do
request = CLIENT.generate_request( conn = stub_connection do |stub|
stub.post('/prediction/v1.2/training?data=12345') do |env|
env[:body].should == ''
end
end
request = CLIENT.execute(
:api_method => @prediction.training.insert, :api_method => @prediction.training.insert,
:parameters => {'data' => '12345'} :parameters => {'data' => '12345'},
:connection => conn
) )
request.to_http_request.method.should == :post conn.verify
request.to_http_request.to_env(Faraday.default_connection)[:url].to_s.should ===
'https://www.googleapis.com/prediction/v1.2/training?data=12345'
request.headers.should be_empty
request.body.should == ''
end end
it 'should generate valid requests when repeated parameters are passed' do it 'should generate valid requests when repeated parameters are passed' do
pending("This is caused by Faraday's encoding of query parameters.") pending("This is caused by Faraday's encoding of query parameters.")
request = CLIENT.generate_request( conn = stub_connection do |stub|
stub.post('/prediction/v1.2/training?data=1&data=2') do |env|
env[:params]['data'].should include('1', '2')
end
end
request = CLIENT.execute(
:api_method => @prediction.training.insert, :api_method => @prediction.training.insert,
:parameters => [['data', '1'], ['data','2']] :parameters => [['data', '1'], ['data','2']],
:connection => conn
) )
request.to_http_request.method.should == :post conn.verify
request.to_http_request.to_env(Faraday.default_connection)[:url].to_s.should ===
'https://www.googleapis.com/prediction/v1.2/training?data=1&data=2'
end end
it 'should generate requests against the correct URIs' do it 'should generate requests against the correct URIs' do
request = CLIENT.generate_request( conn = stub_connection do |stub|
stub.post('/prediction/v1.2/training?data=12345') do |env|
end
end
request = CLIENT.execute(
:api_method => @prediction.training.insert, :api_method => @prediction.training.insert,
:parameters => {'data' => '12345'} :parameters => {'data' => '12345'},
:connection => conn
) )
request.to_http_request.to_env(Faraday.default_connection)[:url].to_s.should === conn.verify
'https://www.googleapis.com/prediction/v1.2/training?data=12345'
end end
it 'should generate requests against the correct URIs' do it 'should generate requests against the correct URIs' do
request = CLIENT.generate_request( conn = stub_connection do |stub|
stub.post('/prediction/v1.2/training?data=12345') do |env|
end
end
request = CLIENT.execute(
:api_method => @prediction.training.insert, :api_method => @prediction.training.insert,
:parameters => {'data' => '12345'} :parameters => {'data' => '12345'},
:connection => conn
) )
request.to_http_request.to_env(Faraday.default_connection)[:url].to_s.should === conn.verify
'https://www.googleapis.com/prediction/v1.2/training?data=12345'
end end
it 'should allow modification to the base URIs for testing purposes' do it 'should allow modification to the base URIs for testing purposes' do
@ -225,39 +261,58 @@ describe Google::APIClient do
Google::APIClient.new.discovered_api('prediction', 'v1.2') Google::APIClient.new.discovered_api('prediction', 'v1.2')
prediction_rebase.method_base = prediction_rebase.method_base =
'https://testing-domain.example.com/prediction/v1.2/' 'https://testing-domain.example.com/prediction/v1.2/'
request = CLIENT.generate_request(
conn = stub_connection do |stub|
stub.post('/prediction/v1.2/training') do |env|
env[:url].host.should == 'testing-domain.example.com'
end
end
request = CLIENT.execute(
:api_method => prediction_rebase.training.insert, :api_method => prediction_rebase.training.insert,
:parameters => {'data' => '123'} :parameters => {'data' => '123'},
) :connection => conn
request.to_http_request.to_env(Faraday.default_connection)[:url].to_s.should === (
'https://testing-domain.example.com/' +
'prediction/v1.2/training?data=123'
) )
conn.verify
end end
it 'should generate OAuth 1 requests' do it 'should generate OAuth 1 requests' do
CLIENT.authorization = :oauth_1 CLIENT.authorization = :oauth_1
CLIENT.authorization.token_credential_key = '12345' CLIENT.authorization.token_credential_key = '12345'
CLIENT.authorization.token_credential_secret = '12345' CLIENT.authorization.token_credential_secret = '12345'
request = CLIENT.generate_request(
conn = stub_connection do |stub|
stub.post('/prediction/v1.2/training?data=12345') do |env|
env[:request_headers].should have_key('Authorization')
env[:request_headers]['Authorization'].should =~ /^OAuth/
end
end
request = CLIENT.execute(
:api_method => @prediction.training.insert, :api_method => @prediction.training.insert,
:parameters => {'data' => '12345'} :parameters => {'data' => '12345'},
:connection => conn
) )
http_request = request.to_http_request conn.verify
http_request.headers.should have_key('Authorization')
http_request.headers['Authorization'].should =~ /^OAuth/
end end
it 'should generate OAuth 2 requests' do it 'should generate OAuth 2 requests' do
CLIENT.authorization = :oauth_2 CLIENT.authorization = :oauth_2
CLIENT.authorization.access_token = '12345' CLIENT.authorization.access_token = '12345'
request = CLIENT.generate_request(
conn = stub_connection do |stub|
stub.post('/prediction/v1.2/training?data=12345') do |env|
env[:request_headers].should have_key('Authorization')
env[:request_headers]['Authorization'].should =~ /^Bearer/
end
end
request = CLIENT.execute(
:api_method => @prediction.training.insert, :api_method => @prediction.training.insert,
:parameters => {'data' => '12345'} :parameters => {'data' => '12345'},
:connection => conn
) )
http_request = request.to_http_request conn.verify
http_request.headers.should have_key('Authorization')
http_request.headers['Authorization'].should =~ /^Bearer/
end end
it 'should not be able to execute improperly authorized requests' do it 'should not be able to execute improperly authorized requests' do
@ -305,15 +360,21 @@ describe Google::APIClient do
end end
it 'should correctly handle unnamed parameters' do it 'should correctly handle unnamed parameters' do
conn = stub_connection do |stub|
stub.post('/prediction/v1.2/training') do |env|
env[:request_headers].should have_key('Content-Type')
env[:request_headers]['Content-Type'].should == 'application/json'
end
end
CLIENT.authorization = :oauth_2 CLIENT.authorization = :oauth_2
CLIENT.authorization.access_token = '12345' CLIENT.authorization.access_token = '12345'
result = CLIENT.execute( CLIENT.execute(
@prediction.training.insert, :api_method => @prediction.training.insert,
{}, :body => MultiJson.dump({"id" => "bucket/object"}),
MultiJson.dump({"id" => "bucket/object"}), :headers => {'Content-Type' => 'application/json'},
{'Content-Type' => 'application/json'} :connection => conn
) )
result.reference.to_http_request.headers['Content-Type'].should == 'application/json' conn.verify
end end
end end
@ -353,38 +414,42 @@ describe Google::APIClient do
end end
it 'should generate requests against the correct URIs' do it 'should generate requests against the correct URIs' do
request = CLIENT.generate_request( conn = stub_connection do |stub|
stub.get('/plus/v1/people/107807692475771887386/activities/public' +
'?collection=public&userId=107807692475771887386') do |env|
end
end
request = CLIENT.execute(
:api_method => @plus.activities.list, :api_method => @plus.activities.list,
:parameters => { :parameters => {
'userId' => '107807692475771887386', 'collection' => 'public' 'userId' => '107807692475771887386', 'collection' => 'public'
}, },
:authenticated => false :authenticated => false,
) :connection => conn
request.to_http_request.to_env(Faraday.default_connection)[:url].to_s.should === (
'https://www.googleapis.com/plus/v1/' +
'people/107807692475771887386/activities/public'
) )
conn.verify
end end
it 'should correctly validate parameters' do it 'should correctly validate parameters' do
(lambda do (lambda do
CLIENT.generate_request( CLIENT.execute(
:api_method => @plus.activities.list, :api_method => @plus.activities.list,
:parameters => {'alt' => 'json'}, :parameters => {'alt' => 'json'},
:authenticated => false :authenticated => false
).to_http_request )
end).should raise_error(ArgumentError) end).should raise_error(ArgumentError)
end end
it 'should correctly validate parameters' do it 'should correctly validate parameters' do
(lambda do (lambda do
CLIENT.generate_request( CLIENT.execute(
:api_method => @plus.activities.list, :api_method => @plus.activities.list,
:parameters => { :parameters => {
'userId' => '107807692475771887386', 'collection' => 'bogus' 'userId' => '107807692475771887386', 'collection' => 'bogus'
}, },
:authenticated => false :authenticated => false
).to_http_request ).to_env(Faraday.default_connection)
end).should raise_error(ArgumentError) end).should raise_error(ArgumentError)
end end
end end
@ -431,7 +496,7 @@ describe Google::APIClient do
:api_method => 'latitude.currentLocation.get', :api_method => 'latitude.currentLocation.get',
:authenticated => false :authenticated => false
) )
request.to_http_request.to_env(Faraday.default_connection)[:url].to_s.should === request.to_env(Faraday.default_connection)[:url].to_s.should ===
'https://www.googleapis.com/latitude/v1/currentLocation' 'https://www.googleapis.com/latitude/v1/currentLocation'
end end
@ -440,7 +505,7 @@ describe Google::APIClient do
:api_method => @latitude.current_location.get, :api_method => @latitude.current_location.get,
:authenticated => false :authenticated => false
) )
request.to_http_request.to_env(Faraday.default_connection)[:url].to_s.should === request.to_env(Faraday.default_connection)[:url].to_s.should ===
'https://www.googleapis.com/latitude/v1/currentLocation' 'https://www.googleapis.com/latitude/v1/currentLocation'
end end
@ -491,21 +556,29 @@ describe Google::APIClient do
end end
it 'should generate requests against the correct URIs' do it 'should generate requests against the correct URIs' do
request = CLIENT.generate_request( conn = stub_connection do |stub|
stub.get('/moderator/v1/profiles/@me') do |env|
end
end
request = CLIENT.execute(
:api_method => 'moderator.profiles.get', :api_method => 'moderator.profiles.get',
:authenticated => false :authenticated => false,
:connection => conn
) )
request.to_http_request.to_env(Faraday.default_connection)[:url].to_s.should === conn.verify
'https://www.googleapis.com/moderator/v1/profiles/@me'
end end
it 'should generate requests against the correct URIs' do it 'should generate requests against the correct URIs' do
request = CLIENT.generate_request( conn = stub_connection do |stub|
stub.get('/moderator/v1/profiles/@me') do |env|
end
end
request = CLIENT.execute(
:api_method => @moderator.profiles.get, :api_method => @moderator.profiles.get,
:authenticated => false :authenticated => false,
:connection => conn
) )
request.to_http_request.to_env(Faraday.default_connection)[:url].to_s.should === conn.verify
'https://www.googleapis.com/moderator/v1/profiles/@me'
end end
it 'should not be able to execute requests without authorization' do it 'should not be able to execute requests without authorization' do
@ -551,21 +624,29 @@ describe Google::APIClient do
end end
it 'should generate requests against the correct URIs' do it 'should generate requests against the correct URIs' do
request = CLIENT.generate_request( conn = stub_connection do |stub|
stub.get('/adsense/v1/adclients') do |env|
end
end
request = CLIENT.execute(
:api_method => 'adsense.adclients.list', :api_method => 'adsense.adclients.list',
:authenticated => false :authenticated => false,
:connection => conn
) )
request.to_http_request.to_env(Faraday.default_connection)[:url].to_s.should === conn.verify
'https://www.googleapis.com/adsense/v1/adclients'
end end
it 'should generate requests against the correct URIs' do it 'should generate requests against the correct URIs' do
request = CLIENT.generate_request( conn = stub_connection do |stub|
stub.get('/adsense/v1/adclients') do |env|
end
end
request = CLIENT.execute(
:api_method => @adsense.adclients.list, :api_method => @adsense.adclients.list,
:authenticated => false :authenticated => false,
:connection => conn
) )
request.to_http_request.to_env(Faraday.default_connection)[:url].to_s.should === conn.verify
'https://www.googleapis.com/adsense/v1/adclients'
end end
it 'should not be able to execute requests without authorization' do it 'should not be able to execute requests without authorization' do
@ -578,16 +659,20 @@ describe Google::APIClient do
it 'should fail when validating missing required parameters' do it 'should fail when validating missing required parameters' do
(lambda do (lambda do
CLIENT.generate_request( CLIENT.execute(
:api_method => @adsense.reports.generate, :api_method => @adsense.reports.generate,
:authenticated => false :authenticated => false
).to_http_request )
end).should raise_error(ArgumentError) end).should raise_error(ArgumentError)
end end
it 'should succeed when validating parameters in a correct call' do it 'should succeed when validating parameters in a correct call' do
conn = stub_connection do |stub|
stub.get('/adsense/v1/reports?dimension=DATE&endDate=2010-01-01&metric=PAGE_VIEWS&startDate=2000-01-01') do |env|
end
end
(lambda do (lambda do
CLIENT.generate_request( CLIENT.execute(
:api_method => @adsense.reports.generate, :api_method => @adsense.reports.generate,
:parameters => { :parameters => {
'startDate' => '2000-01-01', 'startDate' => '2000-01-01',
@ -595,14 +680,16 @@ describe Google::APIClient do
'dimension' => 'DATE', 'dimension' => 'DATE',
'metric' => 'PAGE_VIEWS' 'metric' => 'PAGE_VIEWS'
}, },
:authenticated => false :authenticated => false,
).to_http_request :connection => conn
)
end).should_not raise_error end).should_not raise_error
conn.verify
end end
it 'should fail when validating parameters with invalid values' do it 'should fail when validating parameters with invalid values' do
(lambda do (lambda do
CLIENT.generate_request( CLIENT.execute(
:api_method => @adsense.reports.generate, :api_method => @adsense.reports.generate,
:parameters => { :parameters => {
'startDate' => '2000-01-01', 'startDate' => '2000-01-01',
@ -611,13 +698,19 @@ describe Google::APIClient do
'metric' => 'PAGE_VIEWS' 'metric' => 'PAGE_VIEWS'
}, },
:authenticated => false :authenticated => false
).to_http_request )
end).should raise_error(ArgumentError) end).should raise_error(ArgumentError)
end end
it 'should succeed when validating repeated parameters in a correct call' do it 'should succeed when validating repeated parameters in a correct call' do
conn = stub_connection do |stub|
stub.get('/adsense/v1/reports?dimension%5B%5D=DATE&dimension%5B%5D=PRODUCT_CODE'+
'&endDate=2010-01-01&metric%5B%5D=CLICKS&metric%5B%5D=PAGE_VIEWS&'+
'startDate=2000-01-01') do |env|
end
end
(lambda do (lambda do
CLIENT.generate_request( CLIENT.execute(
:api_method => @adsense.reports.generate, :api_method => @adsense.reports.generate,
:parameters => { :parameters => {
'startDate' => '2000-01-01', 'startDate' => '2000-01-01',
@ -625,14 +718,16 @@ describe Google::APIClient do
'dimension' => ['DATE', 'PRODUCT_CODE'], 'dimension' => ['DATE', 'PRODUCT_CODE'],
'metric' => ['PAGE_VIEWS', 'CLICKS'] 'metric' => ['PAGE_VIEWS', 'CLICKS']
}, },
:authenticated => false :authenticated => false,
:connection => conn
) )
end).should_not raise_error end).should_not raise_error
conn.verify
end end
it 'should fail when validating incorrect repeated parameters' do it 'should fail when validating incorrect repeated parameters' do
(lambda do (lambda do
CLIENT.generate_request( CLIENT.execute(
:api_method => @adsense.reports.generate, :api_method => @adsense.reports.generate,
:parameters => { :parameters => {
'startDate' => '2000-01-01', 'startDate' => '2000-01-01',
@ -641,7 +736,7 @@ describe Google::APIClient do
'metric' => ['PAGE_VIEWS', 'CLICKS'] 'metric' => ['PAGE_VIEWS', 'CLICKS']
}, },
:authenticated => false :authenticated => false
).to_http_request )
end).should raise_error(ArgumentError) end).should raise_error(ArgumentError)
end end
end end

View File

@ -78,49 +78,49 @@ describe Google::APIClient::ResumableUpload do
it 'should consider 20x status as complete' do it 'should consider 20x status as complete' do
request = @uploader.to_http_request request = @uploader.to_http_request
@uploader.process_response(mock_result(200)) @uploader.process_http_response(mock_result(200))
@uploader.complete?.should == true @uploader.complete?.should == true
end end
it 'should consider 30x status as incomplete' do it 'should consider 30x status as incomplete' do
request = @uploader.to_http_request request = @uploader.to_http_request
@uploader.process_response(mock_result(308)) @uploader.process_http_response(mock_result(308))
@uploader.complete?.should == false @uploader.complete?.should == false
@uploader.expired?.should == false @uploader.expired?.should == false
end end
it 'should consider 40x status as fatal' do it 'should consider 40x status as fatal' do
request = @uploader.to_http_request request = @uploader.to_http_request
@uploader.process_response(mock_result(404)) @uploader.process_http_response(mock_result(404))
@uploader.expired?.should == true @uploader.expired?.should == true
end end
it 'should detect changes to location' do it 'should detect changes to location' do
request = @uploader.to_http_request request = @uploader.to_http_request
@uploader.process_response(mock_result(308, 'location' => 'https://www.googleapis.com/upload/drive/v1/files/abcdef')) @uploader.process_http_response(mock_result(308, 'location' => 'https://www.googleapis.com/upload/drive/v1/files/abcdef'))
@uploader.uri.to_s.should == 'https://www.googleapis.com/upload/drive/v1/files/abcdef' @uploader.uri.to_s.should == 'https://www.googleapis.com/upload/drive/v1/files/abcdef'
end end
it 'should resume from the saved range reported by the server' do it 'should resume from the saved range reported by the server' do
@uploader.chunk_size = 200 @uploader.chunk_size = 200
request = @uploader.to_http_request # Send bytes 0-199, only 0-99 saved @uploader.to_http_request # Send bytes 0-199, only 0-99 saved
@uploader.process_response(mock_result(308, 'range' => '0-99')) @uploader.process_http_response(mock_result(308, 'range' => '0-99'))
request = @uploader.to_http_request # Send bytes 100-299 method, url, headers, body = @uploader.to_http_request # Send bytes 100-299
request.headers['Content-Range'].should == "bytes 100-299/#{@media.length}" headers['Content-Range'].should == "bytes 100-299/#{@media.length}"
request.headers['Content-length'].should == "200" headers['Content-length'].should == "200"
end end
it 'should resync the offset after 5xx errors' do it 'should resync the offset after 5xx errors' do
@uploader.chunk_size = 200 @uploader.chunk_size = 200
request = @uploader.to_http_request @uploader.to_http_request
@uploader.process_response(mock_result(500)) # Invalidates range @uploader.process_http_response(mock_result(500)) # Invalidates range
request = @uploader.to_http_request # Resync method, url, headers, body = @uploader.to_http_request # Resync
request.headers['Content-Range'].should == "bytes */#{@media.length}" headers['Content-Range'].should == "bytes */#{@media.length}"
request.headers['Content-length'].should == "0" headers['Content-length'].should == "0"
@uploader.process_response(mock_result(308, 'range' => '0-99')) @uploader.process_http_response(mock_result(308, 'range' => '0-99'))
request = @uploader.to_http_request # Send next chunk at correct range method, url, headers, body = @uploader.to_http_request # Send next chunk at correct range
request.headers['Content-Range'].should == "bytes 100-299/#{@media.length}" headers['Content-Range'].should == "bytes 100-299/#{@media.length}"
request.headers['Content-length'].should == "200" headers['Content-length'].should == "200"
end end
def mock_result(status, headers = {}) def mock_result(status, headers = {})

View File

@ -82,7 +82,7 @@ describe Google::APIClient::Result do
reference = @result.next_page reference = @result.next_page
Hash[reference.parameters].should include('pageToken') Hash[reference.parameters].should include('pageToken')
Hash[reference.parameters]['pageToken'].should == 'NEXT+PAGE+TOKEN' Hash[reference.parameters]['pageToken'].should == 'NEXT+PAGE+TOKEN'
url = reference.to_http_request.to_env(Faraday.default_connection)[:url] url = reference.to_env(Faraday.default_connection)[:url]
url.to_s.should include('pageToken=NEXT%2BPAGE%2BTOKEN') url.to_s.should include('pageToken=NEXT%2BPAGE%2BTOKEN')
end end

View File

@ -17,6 +17,7 @@ require 'spec_helper'
require 'google/api_client' require 'google/api_client'
describe Google::APIClient::JWTAsserter do describe Google::APIClient::JWTAsserter do
include ConnectionHelpers
before do before do
@key = OpenSSL::PKey::RSA.new 2048 @key = OpenSSL::PKey::RSA.new 2048
@ -33,7 +34,7 @@ describe Google::APIClient::JWTAsserter do
end end
it 'should send valid access token request' do it 'should send valid access token request' do
stubs = Faraday::Adapter::Test::Stubs.new do |stub| conn = stub_connection do |stub|
stub.post('/o/oauth2/token') do |env| stub.post('/o/oauth2/token') do |env|
params = Addressable::URI.form_unencode(env[:body]) params = Addressable::URI.form_unencode(env[:body])
JWT.decode(params.assoc("assertion").last, @key.public_key) JWT.decode(params.assoc("assertion").last, @key.public_key)
@ -45,14 +46,11 @@ describe Google::APIClient::JWTAsserter do
}'] }']
end end
end end
connection = Faraday.new(:url => 'https://accounts.google.com') do |builder|
builder.adapter(:test, stubs)
end
asserter = Google::APIClient::JWTAsserter.new('client1', 'scope1 scope2', @key) asserter = Google::APIClient::JWTAsserter.new('client1', 'scope1 scope2', @key)
auth = asserter.authorize(nil, { :connection => connection}) auth = asserter.authorize(nil, { :connection => conn })
auth.should_not == nil? auth.should_not == nil?
auth.access_token.should == "1/abcdef1234567890" auth.access_token.should == "1/abcdef1234567890"
conn.verify
end end
end end

View File

@ -21,6 +21,8 @@ require 'google/api_client'
require 'google/api_client/version' require 'google/api_client/version'
shared_examples_for 'configurable user agent' do shared_examples_for 'configurable user agent' do
include ConnectionHelpers
it 'should allow the user agent to be modified' do it 'should allow the user agent to be modified' do
client.user_agent = 'Custom User Agent/1.2.3' client.user_agent = 'Custom User Agent/1.2.3'
client.user_agent.should == 'Custom User Agent/1.2.3' client.user_agent.should == 'Custom User Agent/1.2.3'
@ -34,16 +36,14 @@ shared_examples_for 'configurable user agent' do
it 'should not allow the user agent to be used with bogus values' do it 'should not allow the user agent to be used with bogus values' do
(lambda do (lambda do
client.user_agent = 42 client.user_agent = 42
client.transmit( client.execute(:uri=>'http://www.google.com/')
['GET', 'http://www.google.com/', [], []]
)
end).should raise_error(TypeError) end).should raise_error(TypeError)
end end
it 'should transmit a User-Agent header when sending requests' do it 'should transmit a User-Agent header when sending requests' do
client.user_agent = 'Custom User Agent/1.2.3' client.user_agent = 'Custom User Agent/1.2.3'
stubs = Faraday::Adapter::Test::Stubs.new do |stub| conn = stub_connection do |stub|
stub.get('/') do |env| stub.get('/') do |env|
headers = env[:request_headers] headers = env[:request_headers]
headers.should have_key('User-Agent') headers.should have_key('User-Agent')
@ -51,18 +51,14 @@ shared_examples_for 'configurable user agent' do
[200, {}, ['']] [200, {}, ['']]
end end
end end
connection = Faraday.new(:url => 'https://www.google.com') do |builder| client.execute(:uri=>'http://www.google.com/', :connection => conn)
builder.adapter(:test, stubs) conn.verify
end
request = connection.build_request(:get) do |req|
req.url('http://www.google.com/')
end
client.transmit(:request => request, :connection => connection)
stubs.verify_stubbed_calls
end end
end end
describe Google::APIClient do describe Google::APIClient do
include ConnectionHelpers
let(:client) { Google::APIClient.new } let(:client) { Google::APIClient.new }
it 'should make its version number available' do it 'should make its version number available' do
@ -73,11 +69,18 @@ describe Google::APIClient do
Signet::OAuth2::Client.should === client.authorization Signet::OAuth2::Client.should === client.authorization
end end
it_should_behave_like 'configurable user agent' describe 'configure for no authentication' do
before do
client.authorization = nil
end
it_should_behave_like 'configurable user agent'
end
describe 'configured for OAuth 1' do describe 'configured for OAuth 1' do
before do before do
client.authorization = :oauth_1 client.authorization = :oauth_1
client.authorization.token_credential_key = 'abc'
client.authorization.token_credential_secret = '123'
end end
it 'should use the default OAuth1 client configuration' do it 'should use the default OAuth1 client configuration' do
@ -98,6 +101,7 @@ describe Google::APIClient do
describe 'configured for OAuth 2' do describe 'configured for OAuth 2' do
before do before do
client.authorization = :oauth_2 client.authorization = :oauth_2
client.authorization.access_token = '12345'
end end
# TODO # TODO
@ -107,13 +111,10 @@ describe Google::APIClient do
describe 'when executing requests' do describe 'when executing requests' do
before do before do
client.authorization = :oauth_2 client.authorization = :oauth_2
@connection = Faraday.new(:url => 'https://www.googleapis.com') do |builder| @connection = stub_connection do |stub|
stubs = Faraday::Adapter::Test::Stubs.new do |stub| stub.get('/test') do |env|
stub.get('/test') do |env| env[:request_headers]['Authorization'].should == 'Bearer 12345'
env[:request_headers]['Authorization'].should == 'Bearer 12345'
end
end end
builder.adapter(:test, stubs)
end end
end end

View File

@ -2,6 +2,53 @@ $LOAD_PATH.unshift(File.expand_path('../../lib', __FILE__))
$LOAD_PATH.uniq! $LOAD_PATH.uniq!
require 'rspec' require 'rspec'
require 'faraday'
require 'faraday/adapter/test'
module Faraday
class Connection
def verify
if app.kind_of?(Faraday::Adapter::Test)
app.stubs.verify_stubbed_calls
else
raise TypeError, "Expected test adapter"
end
end
end
end
module ConnectionHelpers
def stub_connection(&block)
stubs = Faraday::Adapter::Test::Stubs.new do |stub|
block.call(stub)
end
connection = Faraday.new do |builder|
builder.adapter(:test, stubs)
end
end
end
module JSONMatchers
class EqualsJson
def initialize(expected)
@expected = JSON.parse(expected)
end
def matches?(target)
@target = JSON.parse(target)
@target.eql?(@expected)
end
def failure_message
"expected #{@target.inspect} to be #{@expected}"
end
def negative_failure_message
"expected #{@target.inspect} not to be #{@expected}"
end
end
def be_json(expected)
EqualsJson.new(expected)
end
end
RSpec.configure do |config| RSpec.configure do |config|
end end