koala 1.1.0 → 1.2.0beta1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/.travis.yml +2 -1
- data/CHANGELOG +26 -0
- data/Gemfile +6 -2
- data/Rakefile +0 -1
- data/koala.gemspec +8 -8
- data/lib/koala.rb +42 -45
- data/lib/koala/batch_operation.rb +15 -15
- data/lib/koala/graph_api.rb +81 -58
- data/lib/koala/graph_batch_api.rb +10 -10
- data/lib/koala/graph_collection.rb +6 -6
- data/lib/koala/http_service.rb +177 -0
- data/lib/koala/oauth.rb +2 -2
- data/lib/koala/realtime_updates.rb +20 -17
- data/lib/koala/rest_api.rb +1 -1
- data/lib/koala/test_users.rb +33 -16
- data/lib/koala/uploadable_io.rb +47 -42
- data/lib/koala/utils.rb +11 -0
- data/readme.md +38 -38
- data/spec/cases/api_base_spec.rb +2 -2
- data/spec/cases/error_spec.rb +32 -0
- data/spec/cases/graph_and_rest_api_spec.rb +20 -3
- data/spec/cases/graph_api_batch_spec.rb +88 -97
- data/spec/cases/graph_api_spec.rb +21 -4
- data/spec/cases/http_service_spec.rb +446 -0
- data/spec/cases/koala_spec.rb +33 -38
- data/spec/cases/oauth_spec.rb +219 -200
- data/spec/cases/realtime_updates_spec.rb +45 -31
- data/spec/cases/rest_api_spec.rb +23 -7
- data/spec/cases/test_users_spec.rb +112 -52
- data/spec/cases/uploadable_io_spec.rb +49 -36
- data/spec/cases/utils_spec.rb +10 -0
- data/spec/fixtures/facebook_data.yml +23 -22
- data/spec/fixtures/mock_facebook_responses.yml +126 -96
- data/spec/spec_helper.rb +29 -5
- data/spec/support/graph_api_shared_examples.rb +59 -52
- data/spec/support/json_testing_fix.rb +35 -11
- data/spec/support/koala_test.rb +163 -0
- data/spec/support/mock_http_service.rb +6 -4
- data/spec/support/ordered_hash.rb +205 -0
- data/spec/support/rest_api_shared_examples.rb +37 -37
- data/spec/support/uploadable_io_shared_examples.rb +2 -8
- metadata +78 -79
- data/lib/koala/http_services.rb +0 -46
- data/lib/koala/http_services/net_http_service.rb +0 -92
- data/lib/koala/http_services/typhoeus_service.rb +0 -37
- data/spec/cases/http_services/http_service_spec.rb +0 -129
- data/spec/cases/http_services/net_http_service_spec.rb +0 -532
- data/spec/cases/http_services/typhoeus_service_spec.rb +0 -152
- data/spec/support/live_testing_data_helper.rb +0 -40
- data/spec/support/setup_mocks_or_live.rb +0 -51
data/lib/koala/http_services.rb
DELETED
@@ -1,46 +0,0 @@
|
|
1
|
-
module Koala
|
2
|
-
class Response
|
3
|
-
attr_reader :status, :body, :headers
|
4
|
-
def initialize(status, body, headers)
|
5
|
-
@status = status
|
6
|
-
@body = body
|
7
|
-
@headers = headers
|
8
|
-
end
|
9
|
-
end
|
10
|
-
|
11
|
-
module HTTPService
|
12
|
-
# common functionality for all HTTP services
|
13
|
-
def self.included(base)
|
14
|
-
base.class_eval do
|
15
|
-
class << self
|
16
|
-
attr_accessor :always_use_ssl, :proxy, :timeout
|
17
|
-
end
|
18
|
-
|
19
|
-
def self.server(options = {})
|
20
|
-
server = "#{options[:rest_api] ? Facebook::REST_SERVER : Facebook::GRAPH_SERVER}"
|
21
|
-
server.gsub!(/\.facebook/, "-video.facebook") if options[:video]
|
22
|
-
"#{options[:beta] ? "beta." : ""}#{server}"
|
23
|
-
end
|
24
|
-
|
25
|
-
def self.encode_params(param_hash)
|
26
|
-
# unfortunately, we can't use to_query because that's Rails, not Ruby
|
27
|
-
# if no hash (e.g. no auth token) return empty string
|
28
|
-
((param_hash || {}).collect do |key_and_value|
|
29
|
-
key_and_value[1] = MultiJson.encode(key_and_value[1]) unless key_and_value[1].is_a? String
|
30
|
-
"#{key_and_value[0].to_s}=#{CGI.escape key_and_value[1]}"
|
31
|
-
end).join("&")
|
32
|
-
end
|
33
|
-
|
34
|
-
protected
|
35
|
-
|
36
|
-
def self.params_require_multipart?(param_hash)
|
37
|
-
param_hash.any? { |key, value| value.kind_of?(Koala::UploadableIO) }
|
38
|
-
end
|
39
|
-
|
40
|
-
def self.multipart_requires_content_type?
|
41
|
-
true
|
42
|
-
end
|
43
|
-
end
|
44
|
-
end
|
45
|
-
end
|
46
|
-
end
|
@@ -1,92 +0,0 @@
|
|
1
|
-
require "net/http" unless defined?(Net::HTTP)
|
2
|
-
require "net/https"
|
3
|
-
require "net/http/post/multipart"
|
4
|
-
|
5
|
-
module Koala
|
6
|
-
module NetHTTPService
|
7
|
-
# this service uses Net::HTTP to send requests to the graph
|
8
|
-
include Koala::HTTPService
|
9
|
-
|
10
|
-
# Net::HTTP-specific values
|
11
|
-
class << self
|
12
|
-
attr_accessor :ca_file, :ca_path, :verify_mode
|
13
|
-
end
|
14
|
-
|
15
|
-
def self.make_request(path, args, verb, options = {})
|
16
|
-
# We translate args to a valid query string. If post is specified,
|
17
|
-
# we send a POST request to the given path with the given arguments.
|
18
|
-
|
19
|
-
# by default, we use SSL only for private requests
|
20
|
-
# this makes public requests faster
|
21
|
-
private_request = args["access_token"] || @always_use_ssl || options[:use_ssl]
|
22
|
-
|
23
|
-
# if the verb isn't get or post, send it as a post argument
|
24
|
-
args.merge!({:method => verb}) && verb = "post" if verb != "get" && verb != "post"
|
25
|
-
|
26
|
-
http = create_http(server(options), private_request, options)
|
27
|
-
|
28
|
-
response = http.start do |http|
|
29
|
-
if verb == "post"
|
30
|
-
if params_require_multipart? args
|
31
|
-
http.request Net::HTTP::Post::Multipart.new path, encode_multipart_params(args)
|
32
|
-
else
|
33
|
-
http.post(path, encode_params(args))
|
34
|
-
end
|
35
|
-
else
|
36
|
-
http.get("#{path}?#{encode_params(args)}")
|
37
|
-
end
|
38
|
-
end
|
39
|
-
|
40
|
-
Koala::Response.new(response.code.to_i, response.body, response)
|
41
|
-
end
|
42
|
-
|
43
|
-
protected
|
44
|
-
def self.encode_params(param_hash)
|
45
|
-
# unfortunately, we can't use to_query because that's Rails, not Ruby
|
46
|
-
# if no hash (e.g. no auth token) return empty string
|
47
|
-
((param_hash || {}).collect do |key_and_value|
|
48
|
-
key_and_value[1] = MultiJson.encode(key_and_value[1]) if key_and_value[1].class != String
|
49
|
-
"#{key_and_value[0].to_s}=#{CGI.escape key_and_value[1]}"
|
50
|
-
end).join("&")
|
51
|
-
end
|
52
|
-
|
53
|
-
def self.encode_multipart_params(param_hash)
|
54
|
-
Hash[*param_hash.collect do |key, value|
|
55
|
-
[key, value.kind_of?(Koala::UploadableIO) ? value.to_upload_io : value]
|
56
|
-
end.flatten]
|
57
|
-
end
|
58
|
-
|
59
|
-
def self.create_http(server, private_request, options)
|
60
|
-
if proxy_server = options[:proxy] || proxy
|
61
|
-
proxy = URI.parse(proxy_server)
|
62
|
-
http = Net::HTTP.new(server, private_request ? 443 : nil,
|
63
|
-
proxy.host, proxy.port, proxy.user, proxy.password)
|
64
|
-
else
|
65
|
-
http = Net::HTTP.new(server, private_request ? 443 : nil)
|
66
|
-
end
|
67
|
-
|
68
|
-
if timeout_value = options[:timeout] || timeout
|
69
|
-
http.open_timeout = timeout_value
|
70
|
-
http.read_timeout = timeout_value
|
71
|
-
end
|
72
|
-
|
73
|
-
# For HTTPS requests, set the proper CA certificates
|
74
|
-
if private_request
|
75
|
-
http.use_ssl = true
|
76
|
-
http.verify_mode = options[:verify_mode] || verify_mode || OpenSSL::SSL::VERIFY_PEER
|
77
|
-
|
78
|
-
if cert_file = options[:ca_file] || ca_file
|
79
|
-
raise Errno::ENOENT, "Certificate file #{cert_file.inspect} does not exist!" unless File.exists?(cert_file)
|
80
|
-
http.ca_file = cert_file
|
81
|
-
end
|
82
|
-
|
83
|
-
if cert_path = options[:ca_path] || ca_path
|
84
|
-
raise Errno::ENOENT, "Certificate path #{cert_path.inspect} does not exist!" unless File.directory?(cert_path)
|
85
|
-
http.ca_path = cert_path
|
86
|
-
end
|
87
|
-
end
|
88
|
-
|
89
|
-
http
|
90
|
-
end
|
91
|
-
end
|
92
|
-
end
|
@@ -1,37 +0,0 @@
|
|
1
|
-
require "typhoeus" unless defined?(Typhoeus)
|
2
|
-
|
3
|
-
module Koala
|
4
|
-
module TyphoeusService
|
5
|
-
# this service uses Typhoeus to send requests to the graph
|
6
|
-
include Typhoeus
|
7
|
-
include Koala::HTTPService
|
8
|
-
|
9
|
-
def self.make_request(path, args, verb, options = {})
|
10
|
-
# if the verb isn't get or post, send it as a post argument
|
11
|
-
args.merge!({:method => verb}) && verb = "post" if verb != "get" && verb != "post"
|
12
|
-
|
13
|
-
# switch any UploadableIOs to the files Typhoeus expects
|
14
|
-
args.each_pair {|key, value| args[key] = value.to_file if value.is_a?(UploadableIO)}
|
15
|
-
|
16
|
-
# you can pass arguments directly to Typhoeus using the :typhoeus_options key
|
17
|
-
typhoeus_options = {:params => args}.merge(options[:typhoeus_options] || {})
|
18
|
-
|
19
|
-
# if proxy/timeout options aren't passed, check if defaults are set
|
20
|
-
typhoeus_options[:proxy] ||= proxy
|
21
|
-
typhoeus_options[:timeout] ||= timeout
|
22
|
-
|
23
|
-
# by default, we use SSL only for private requests (e.g. with access token)
|
24
|
-
# this makes public requests faster
|
25
|
-
prefix = (args["access_token"] || @always_use_ssl || options[:use_ssl]) ? "https" : "http"
|
26
|
-
|
27
|
-
response = Typhoeus::Request.send(verb, "#{prefix}://#{server(options)}#{path}", typhoeus_options)
|
28
|
-
Koala::Response.new(response.code, response.body, response.headers_hash)
|
29
|
-
end
|
30
|
-
|
31
|
-
protected
|
32
|
-
|
33
|
-
def self.multipart_requires_content_type?
|
34
|
-
false # Typhoeus handles multipart file types, we don't have to require it
|
35
|
-
end
|
36
|
-
end
|
37
|
-
end
|
@@ -1,129 +0,0 @@
|
|
1
|
-
require 'spec_helper'
|
2
|
-
|
3
|
-
|
4
|
-
class Bear
|
5
|
-
include Koala::HTTPService
|
6
|
-
end
|
7
|
-
|
8
|
-
describe "Koala::HTTPService" do
|
9
|
-
|
10
|
-
describe "common methods" do
|
11
|
-
describe "always_use_ssl accessor" do
|
12
|
-
it "should be added" do
|
13
|
-
# in Ruby 1.8, .methods returns strings
|
14
|
-
# in Ruby 1.9, .method returns symbols
|
15
|
-
Bear.methods.collect {|m| m.to_sym}.should include(:always_use_ssl)
|
16
|
-
Bear.methods.collect {|m| m.to_sym}.should include(:always_use_ssl=)
|
17
|
-
end
|
18
|
-
end
|
19
|
-
|
20
|
-
describe "proxy accessor" do
|
21
|
-
it "should be added" do
|
22
|
-
# in Ruby 1.8, .methods returns strings
|
23
|
-
# in Ruby 1.9, .method returns symbols
|
24
|
-
Bear.methods.collect {|m| m.to_sym}.should include(:proxy)
|
25
|
-
Bear.methods.collect {|m| m.to_sym}.should include(:proxy=)
|
26
|
-
end
|
27
|
-
end
|
28
|
-
|
29
|
-
describe "timeout accessor" do
|
30
|
-
it "should be added" do
|
31
|
-
# in Ruby 1.8, .methods returns strings
|
32
|
-
# in Ruby 1.9, .method returns symbols
|
33
|
-
Bear.methods.collect {|m| m.to_sym}.should include(:timeout)
|
34
|
-
Bear.methods.collect {|m| m.to_sym}.should include(:timeout=)
|
35
|
-
end
|
36
|
-
end
|
37
|
-
|
38
|
-
describe "server" do
|
39
|
-
describe "with no options" do
|
40
|
-
it "returns the REST server if options[:rest_api]" do
|
41
|
-
Bear.server(:rest_api => true).should == Koala::Facebook::REST_SERVER
|
42
|
-
end
|
43
|
-
|
44
|
-
it "returns the graph server if !options[:rest_api]" do
|
45
|
-
Bear.server(:rest_api => false).should == Koala::Facebook::GRAPH_SERVER
|
46
|
-
Bear.server({}).should == Koala::Facebook::GRAPH_SERVER
|
47
|
-
end
|
48
|
-
end
|
49
|
-
|
50
|
-
describe "with options[:beta]" do
|
51
|
-
before :each do
|
52
|
-
@options = {:beta => true}
|
53
|
-
end
|
54
|
-
|
55
|
-
it "returns the beta REST server if options[:rest_api]" do
|
56
|
-
server = Bear.server(@options.merge(:rest_api => true))
|
57
|
-
server.should =~ Regexp.new("beta.#{Koala::Facebook::REST_SERVER}")
|
58
|
-
end
|
59
|
-
|
60
|
-
it "returns the beta rest server if !options[:rest_api]" do
|
61
|
-
server = Bear.server(@options)
|
62
|
-
server.should =~ Regexp.new("beta.#{Koala::Facebook::GRAPH_SERVER}")
|
63
|
-
end
|
64
|
-
end
|
65
|
-
|
66
|
-
describe "with options[:video]" do
|
67
|
-
before :each do
|
68
|
-
@options = {:video => true}
|
69
|
-
end
|
70
|
-
|
71
|
-
it "should return the REST video server if options[:rest_api]" do
|
72
|
-
server = Bear.server(@options.merge(:rest_api => true))
|
73
|
-
server.should =~ Regexp.new(Koala::Facebook::REST_SERVER.gsub(/\.facebook/, "-video.facebook"))
|
74
|
-
end
|
75
|
-
|
76
|
-
it "should return the graph video server if !options[:rest_api]" do
|
77
|
-
server = Bear.server(@options)
|
78
|
-
server.should =~ Regexp.new(Koala::Facebook::GRAPH_SERVER.gsub(/\.facebook/, "-video.facebook"))
|
79
|
-
end
|
80
|
-
end
|
81
|
-
end
|
82
|
-
|
83
|
-
describe "#encode_params" do
|
84
|
-
it "should return an empty string if param_hash evaluates to false" do
|
85
|
-
Bear.encode_params(nil).should == ''
|
86
|
-
end
|
87
|
-
|
88
|
-
it "should convert values to JSON if the value is not a String" do
|
89
|
-
val = 'json_value'
|
90
|
-
not_a_string = 'not_a_string'
|
91
|
-
not_a_string.stub(:is_a?).and_return(false)
|
92
|
-
MultiJson.should_receive(:encode).with(not_a_string).and_return(val)
|
93
|
-
|
94
|
-
string = "hi"
|
95
|
-
|
96
|
-
args = {
|
97
|
-
not_a_string => not_a_string,
|
98
|
-
string => string
|
99
|
-
}
|
100
|
-
|
101
|
-
result = Bear.encode_params(args)
|
102
|
-
result.split('&').find do |key_and_val|
|
103
|
-
key_and_val.match("#{not_a_string}=#{val}")
|
104
|
-
end.should be_true
|
105
|
-
end
|
106
|
-
|
107
|
-
it "should escape all values" do
|
108
|
-
args = Hash[*(1..4).map {|i| [i.to_s, "Value #{i}($"]}.flatten]
|
109
|
-
|
110
|
-
result = Bear.encode_params(args)
|
111
|
-
result.split('&').each do |key_val|
|
112
|
-
key, val = key_val.split('=')
|
113
|
-
val.should == CGI.escape(args[key])
|
114
|
-
end
|
115
|
-
end
|
116
|
-
|
117
|
-
it "should convert all keys to Strings" do
|
118
|
-
args = Hash[*(1..4).map {|i| [i, "val#{i}"]}.flatten]
|
119
|
-
|
120
|
-
result = Bear.encode_params(args)
|
121
|
-
result.split('&').each do |key_val|
|
122
|
-
key, val = key_val.split('=')
|
123
|
-
key.should == args.find{|key_val_arr| key_val_arr.last == val}.first.to_s
|
124
|
-
end
|
125
|
-
end
|
126
|
-
end
|
127
|
-
end
|
128
|
-
|
129
|
-
end
|
@@ -1,532 +0,0 @@
|
|
1
|
-
require 'spec_helper'
|
2
|
-
|
3
|
-
|
4
|
-
Horse = Koala::NetHTTPService
|
5
|
-
|
6
|
-
describe "NetHTTPService module holder class Horse" do
|
7
|
-
before :each do
|
8
|
-
# reset global settings
|
9
|
-
Horse.always_use_ssl = Horse.proxy = Horse.timeout = nil
|
10
|
-
end
|
11
|
-
|
12
|
-
it "has a ca_file accessor" do
|
13
|
-
Horse.methods.collect {|m| m.to_sym}.should include(:ca_file)
|
14
|
-
Horse.methods.collect {|m| m.to_sym}.should include(:ca_file=)
|
15
|
-
end
|
16
|
-
|
17
|
-
it "has a ca_path accessor" do
|
18
|
-
Horse.methods.collect {|m| m.to_sym}.should include(:ca_path)
|
19
|
-
Horse.methods.collect {|m| m.to_sym}.should include(:ca_path=)
|
20
|
-
end
|
21
|
-
|
22
|
-
it "has a verify_mode accessor" do
|
23
|
-
Horse.methods.collect {|m| m.to_sym}.should include(:verify_mode)
|
24
|
-
Horse.methods.collect {|m| m.to_sym}.should include(:verify_mode=)
|
25
|
-
end
|
26
|
-
|
27
|
-
it "should define a make_request static module method" do
|
28
|
-
Horse.respond_to?(:make_request).should be_true
|
29
|
-
end
|
30
|
-
|
31
|
-
it "should include the Koala::HTTPService module defining common features" do
|
32
|
-
Horse.included_modules.include?(Koala::HTTPService).should be_true
|
33
|
-
end
|
34
|
-
|
35
|
-
describe "when making a request" do
|
36
|
-
before(:each) do
|
37
|
-
# Setup stubs for make_request to execute without exceptions
|
38
|
-
@mock_body = stub('Net::HTTPResponse body')
|
39
|
-
@mock_http_response = stub('Net::HTTPResponse', :code => 1, :body => @mock_body)
|
40
|
-
|
41
|
-
@http_yield_mock = mock('Net::HTTP start yielded object')
|
42
|
-
|
43
|
-
@http_yield_mock.stub(:post).and_return(@mock_http_response)
|
44
|
-
@http_yield_mock.stub(:get).and_return(@mock_http_response)
|
45
|
-
|
46
|
-
@http_mock = stub('Net::HTTP object', 'use_ssl=' => true, 'verify_mode=' => true)
|
47
|
-
@http_mock.stub(:start).and_yield(@http_yield_mock)
|
48
|
-
@http_mock.stub(:ca_path=)
|
49
|
-
@http_mock.stub(:ca_file=)
|
50
|
-
@http_mock.stub(:verify_mode=)
|
51
|
-
|
52
|
-
Net::HTTP.stub(:new).and_return(@http_mock)
|
53
|
-
end
|
54
|
-
|
55
|
-
describe "the connection" do
|
56
|
-
it "should use POST if verb is not GET" do
|
57
|
-
@http_yield_mock.should_receive(:post).and_return(@mock_http_response)
|
58
|
-
@http_mock.should_receive(:start).and_yield(@http_yield_mock)
|
59
|
-
|
60
|
-
Horse.make_request('anything', {}, 'anything')
|
61
|
-
end
|
62
|
-
|
63
|
-
it "should use GET if that verb is specified" do
|
64
|
-
@http_yield_mock.should_receive(:get).and_return(@mock_http_response)
|
65
|
-
@http_mock.should_receive(:start).and_yield(@http_yield_mock)
|
66
|
-
|
67
|
-
Horse.make_request('anything', {}, 'get')
|
68
|
-
end
|
69
|
-
|
70
|
-
it "should add the method to the arguments if it's not get or post" do
|
71
|
-
args = {}
|
72
|
-
method = "telekenesis"
|
73
|
-
# since the arguments get encoded later, we'll test for merge!
|
74
|
-
# even though that's somewhat testing internal implementation
|
75
|
-
args.should_receive(:merge!).with(:method => method)
|
76
|
-
|
77
|
-
Horse.make_request('anything', args, method)
|
78
|
-
end
|
79
|
-
end
|
80
|
-
|
81
|
-
describe "if the request has an access token" do
|
82
|
-
before :each do
|
83
|
-
@args = {"access_token" => "123"}
|
84
|
-
end
|
85
|
-
|
86
|
-
it "should use SSL" do
|
87
|
-
@http_mock.should_receive('use_ssl=').with(true)
|
88
|
-
|
89
|
-
Horse.make_request('anything', @args, 'anything')
|
90
|
-
end
|
91
|
-
|
92
|
-
it "should set the port to 443" do
|
93
|
-
Net::HTTP.should_receive(:new).with(anything, 443).and_return(@http_mock)
|
94
|
-
|
95
|
-
Horse.make_request('anything', @args, 'anything')
|
96
|
-
end
|
97
|
-
end
|
98
|
-
|
99
|
-
describe "if always_use_ssl is true" do
|
100
|
-
before :each do
|
101
|
-
Horse.always_use_ssl = true
|
102
|
-
end
|
103
|
-
|
104
|
-
it "should use SSL" do
|
105
|
-
@http_mock.should_receive('use_ssl=').with(true)
|
106
|
-
|
107
|
-
Horse.make_request('anything', {}, 'anything')
|
108
|
-
end
|
109
|
-
|
110
|
-
it "should set the port to 443" do
|
111
|
-
Net::HTTP.should_receive(:new).with(anything, 443).and_return(@http_mock)
|
112
|
-
|
113
|
-
Horse.make_request('anything', {}, 'anything')
|
114
|
-
end
|
115
|
-
end
|
116
|
-
|
117
|
-
describe "if the use_ssl option is provided" do
|
118
|
-
it "should use SSL" do
|
119
|
-
@http_mock.should_receive('use_ssl=').with(true)
|
120
|
-
|
121
|
-
Horse.make_request('anything', {}, 'anything', :use_ssl => true)
|
122
|
-
end
|
123
|
-
|
124
|
-
it "should set the port to 443" do
|
125
|
-
Net::HTTP.should_receive(:new).with(anything, 443).and_return(@http_mock)
|
126
|
-
|
127
|
-
Horse.make_request('anything', {}, 'anything', :use_ssl => true)
|
128
|
-
end
|
129
|
-
end
|
130
|
-
|
131
|
-
describe "if there's no token and always_use_ssl isn't true" do
|
132
|
-
it "should not use SSL" do
|
133
|
-
@http_mock.should_not_receive('use_ssl=')
|
134
|
-
Horse.make_request('anything', {}, 'anything')
|
135
|
-
end
|
136
|
-
|
137
|
-
it "should not set the port" do
|
138
|
-
Net::HTTP.should_receive(:new).with(anything, nil).and_return(@http_mock)
|
139
|
-
Horse.make_request('anything', {}, 'anything')
|
140
|
-
end
|
141
|
-
end
|
142
|
-
|
143
|
-
describe "proxy options" do
|
144
|
-
before :each do
|
145
|
-
Horse.proxy = "http://defaultproxy"
|
146
|
-
end
|
147
|
-
after :all do
|
148
|
-
Horse.proxy = nil
|
149
|
-
end
|
150
|
-
|
151
|
-
it "should use passed proxy option if provided" do
|
152
|
-
Net::HTTP.should_receive(:new).with(Koala::Facebook::GRAPH_SERVER, anything, "passedproxy", 80, nil, nil).and_return(@http_mock)
|
153
|
-
Horse.make_request('anything', {} , 'anything', {:proxy => "http://passedproxy"})
|
154
|
-
end
|
155
|
-
|
156
|
-
it "should use default proxy if default is provided and NO proxy option passed" do
|
157
|
-
Net::HTTP.should_receive(:new).with(Koala::Facebook::GRAPH_SERVER, anything, "defaultproxy", 80, nil, nil).and_return(@http_mock)
|
158
|
-
Horse.make_request('anything', {} , 'anything', {})
|
159
|
-
end
|
160
|
-
|
161
|
-
it "should NOT use a proxy if default is NOT provided and NO proxy option passed" do
|
162
|
-
Horse.proxy = nil
|
163
|
-
Net::HTTP.should_receive(:new).with(Koala::Facebook::GRAPH_SERVER, anything).and_return(@http_mock)
|
164
|
-
Horse.make_request('anything', {} , 'anything', {})
|
165
|
-
end
|
166
|
-
end
|
167
|
-
|
168
|
-
describe "timeout options" do
|
169
|
-
before :each do
|
170
|
-
Horse.timeout = 20 # seconds
|
171
|
-
end
|
172
|
-
after :all do
|
173
|
-
Horse.timeout = nil # seconds
|
174
|
-
end
|
175
|
-
|
176
|
-
it "should use passed timeout option if provided" do
|
177
|
-
@http_mock.should_receive('open_timeout=').with(10)
|
178
|
-
@http_mock.should_receive('read_timeout=').with(10)
|
179
|
-
Horse.make_request('anything', {} , 'anything', {:timeout => 10})
|
180
|
-
end
|
181
|
-
|
182
|
-
it "should use default timout if default is provided and NO timeout option passed" do
|
183
|
-
@http_mock.should_receive('open_timeout=').with(20)
|
184
|
-
@http_mock.should_receive('read_timeout=').with(20)
|
185
|
-
Horse.make_request('anything', {} , 'anything', {})
|
186
|
-
end
|
187
|
-
|
188
|
-
it "should NOT use a timeout if default is NOT provided and NO timeout option passed" do
|
189
|
-
Horse.timeout = nil # seconds
|
190
|
-
@http_mock.should_not_receive('open_timeout=')
|
191
|
-
@http_mock.should_not_receive('read_timeout=')
|
192
|
-
Horse.make_request('anything', {} , 'anything', {})
|
193
|
-
end
|
194
|
-
end
|
195
|
-
|
196
|
-
describe "ca_file options" do
|
197
|
-
after :each do
|
198
|
-
Horse.always_use_ssl = nil
|
199
|
-
Horse.ca_file = nil
|
200
|
-
end
|
201
|
-
|
202
|
-
it "should not use a ca_file if the request is not via SSL" do
|
203
|
-
Horse.always_use_ssl = false
|
204
|
-
@http_mock.should_not_receive(:ca_file=)
|
205
|
-
Horse.make_request('anything', {} , 'anything', {:ca_file => '/no/file'})
|
206
|
-
end
|
207
|
-
|
208
|
-
describe "when via SSL" do
|
209
|
-
before :each do
|
210
|
-
Horse.always_use_ssl = true
|
211
|
-
@global_ca_file_path = '/global/ca/file/path'
|
212
|
-
end
|
213
|
-
|
214
|
-
context "if the file doesn't exist" do
|
215
|
-
it "raises Errno::ENOENT if the default ca_file does not exist" do
|
216
|
-
Horse.ca_file = @global_ca_file_path
|
217
|
-
|
218
|
-
File.should_receive(:exists?).with(@global_ca_file_path).and_return(false)
|
219
|
-
expect { Horse.make_request('anything', {} , 'anything', {}) }.to raise_exception(Errno::ENOENT)
|
220
|
-
end
|
221
|
-
|
222
|
-
it "raises Errno::ENOENT if options[:ca_file] does not exist" do
|
223
|
-
File.should_receive(:exists?).with(@global_ca_file_path).and_return(false)
|
224
|
-
expect { Horse.make_request('anything', {} , 'anything', {:ca_file => @global_ca_file_path}) }.to raise_exception(Errno::ENOENT)
|
225
|
-
end
|
226
|
-
end
|
227
|
-
|
228
|
-
context "if the file exists" do
|
229
|
-
before :each do
|
230
|
-
File.stub(:exists?).and_return(true)
|
231
|
-
end
|
232
|
-
|
233
|
-
it "should use options[:ca_file] if provided" do
|
234
|
-
given_ca_file = '/ca/file'
|
235
|
-
|
236
|
-
Horse.ca_file = @global_ca_file_path
|
237
|
-
@http_mock.should_not_receive(:ca_file=).with(@global_ca_file_path)
|
238
|
-
@http_mock.should_receive(:ca_file=).with(given_ca_file)
|
239
|
-
|
240
|
-
Horse.make_request('anything', {} , 'anything', {:ca_file => given_ca_file})
|
241
|
-
end
|
242
|
-
|
243
|
-
it "should use default ca_file if default is provided and NO ca_file option is passed" do
|
244
|
-
Horse.ca_file = @global_ca_file_path
|
245
|
-
@http_mock.should_receive(:ca_file=).with(@global_ca_file_path)
|
246
|
-
|
247
|
-
Horse.make_request('anything', {} , 'anything', {})
|
248
|
-
end
|
249
|
-
|
250
|
-
it "should NOT use a ca_file if default is NOT provided and NO ca_file option is passed" do
|
251
|
-
@http_mock.should_not_receive(:ca_file=)
|
252
|
-
|
253
|
-
Horse.make_request('anything', {} , 'anything', {})
|
254
|
-
end
|
255
|
-
end
|
256
|
-
end
|
257
|
-
end
|
258
|
-
|
259
|
-
describe "ca_path options" do
|
260
|
-
after :each do
|
261
|
-
Horse.always_use_ssl = nil
|
262
|
-
Horse.ca_path = nil
|
263
|
-
end
|
264
|
-
|
265
|
-
it "should not use a ca_path if the request is not via SSL" do
|
266
|
-
Horse.always_use_ssl = false
|
267
|
-
@http_mock.should_not_receive('ca_path=')
|
268
|
-
Horse.make_request('anything', {} , 'anything', {:ca_file => '/no/file'})
|
269
|
-
end
|
270
|
-
|
271
|
-
describe "when via SSL" do
|
272
|
-
before :each do
|
273
|
-
Horse.always_use_ssl = true
|
274
|
-
@global_ca_path = '/global/ca/path'
|
275
|
-
end
|
276
|
-
|
277
|
-
context "if the directory doesn't exist" do
|
278
|
-
it "should not use a default ca_path if the default ca_path does not exist" do
|
279
|
-
Horse.ca_path = @global_ca_path
|
280
|
-
|
281
|
-
File.should_receive(:directory?).with(@global_ca_path).and_return(false)
|
282
|
-
expect { Horse.make_request('anything', {} , 'anything', {}) }.to raise_exception(Errno::ENOENT)
|
283
|
-
end
|
284
|
-
|
285
|
-
it "should not use a default ca_path if the default ca_path does not exist" do
|
286
|
-
File.should_receive(:directory?).with(@global_ca_path).and_return(false)
|
287
|
-
expect { Horse.make_request('anything', {} , 'anything', {:ca_path => @global_ca_path}) }.to raise_exception(Errno::ENOENT)
|
288
|
-
end
|
289
|
-
end
|
290
|
-
|
291
|
-
context "if the directory exists" do
|
292
|
-
before :each do
|
293
|
-
File.stub(:directory?).and_return(true)
|
294
|
-
end
|
295
|
-
|
296
|
-
it "should use passed ca_path options if provided" do
|
297
|
-
given_ca_path = '/ca/path'
|
298
|
-
|
299
|
-
Horse.ca_path = @global_ca_path
|
300
|
-
@http_mock.should_not_receive(:ca_ath=).with(@global_ca_path)
|
301
|
-
@http_mock.should_receive(:ca_path=).with(given_ca_path)
|
302
|
-
|
303
|
-
Horse.make_request('anything', {} , 'anything', {:ca_path => given_ca_path})
|
304
|
-
end
|
305
|
-
|
306
|
-
it "should use default ca_path if default is provided and NO ca_path option is passed" do
|
307
|
-
Horse.ca_path = @global_ca_path
|
308
|
-
@http_mock.should_receive(:ca_path=).with(@global_ca_path)
|
309
|
-
|
310
|
-
Horse.make_request('anything', {} , 'anything', {})
|
311
|
-
end
|
312
|
-
|
313
|
-
it "should NOT use a ca_path if default is NOT provided and NO ca_path option is passed" do
|
314
|
-
@http_mock.should_not_receive(:ca_path=)
|
315
|
-
|
316
|
-
Horse.make_request('anything', {} , 'anything', {})
|
317
|
-
end
|
318
|
-
end
|
319
|
-
end
|
320
|
-
end
|
321
|
-
|
322
|
-
describe "verify_mode options" do
|
323
|
-
after :each do
|
324
|
-
Horse.always_use_ssl = nil
|
325
|
-
Horse.verify_mode = nil
|
326
|
-
end
|
327
|
-
|
328
|
-
it "does not set verify mode if it's not SSL" do
|
329
|
-
Horse.always_use_ssl = nil
|
330
|
-
@http_mock.should_not_receive(:verify_mode=)
|
331
|
-
Horse.make_request('anything', {} , 'anything', {:verify_mode => "abc"})
|
332
|
-
end
|
333
|
-
|
334
|
-
context "when making an SSL request" do
|
335
|
-
before :each do
|
336
|
-
Horse.always_use_ssl = true
|
337
|
-
end
|
338
|
-
|
339
|
-
it "sets verify mode if provided in the options" do
|
340
|
-
mode = "foo"
|
341
|
-
@http_mock.should_receive(:verify_mode=).with(mode)
|
342
|
-
Horse.make_request('anything', {} , 'anything', {:verify_mode => mode})
|
343
|
-
end
|
344
|
-
|
345
|
-
it "sets verify mode to the default if provided (and none set in options)" do
|
346
|
-
Horse.verify_mode = "foo"
|
347
|
-
@http_mock.should_receive(:verify_mode=).with(Horse.verify_mode)
|
348
|
-
Horse.make_request('anything', {} , 'anything', {})
|
349
|
-
end
|
350
|
-
|
351
|
-
it "sets verify mode to the default if provided (and none set in options)" do
|
352
|
-
mode = "bar"
|
353
|
-
Horse.verify_mode = "foo"
|
354
|
-
@http_mock.should_receive(:verify_mode=).with(mode)
|
355
|
-
Horse.make_request('anything', {} , 'anything', {:verify_mode => mode})
|
356
|
-
end
|
357
|
-
|
358
|
-
it "sets verify mode to OpenSSL::SSL::VERIFY_PEER if no default or option is provided" do
|
359
|
-
@http_mock.should_receive(:verify_mode=).with(OpenSSL::SSL::VERIFY_PEER)
|
360
|
-
Horse.make_request('anything', {} , 'anything', {})
|
361
|
-
end
|
362
|
-
end
|
363
|
-
end
|
364
|
-
|
365
|
-
it "should use the graph server by default" do
|
366
|
-
Net::HTTP.should_receive(:new).with(Koala::Facebook::GRAPH_SERVER, anything).and_return(@http_mock)
|
367
|
-
Horse.make_request('anything', {}, 'anything')
|
368
|
-
end
|
369
|
-
|
370
|
-
it "should use the REST server if the :rest_api option is true" do
|
371
|
-
Net::HTTP.should_receive(:new).with(Koala::Facebook::REST_SERVER, anything).and_return(@http_mock)
|
372
|
-
Horse.make_request('anything', {}, 'anything', :rest_api => true)
|
373
|
-
end
|
374
|
-
|
375
|
-
it "should start an HTTP connection" do
|
376
|
-
@http_mock.should_receive(:start).and_yield(@http_yield_mock)
|
377
|
-
Horse.make_request('anything', {}, 'anything')
|
378
|
-
end
|
379
|
-
|
380
|
-
it 'creates a HTTP Proxy object when options contain a proxy' do
|
381
|
-
Net::HTTP.should_receive(:new).with(anything, anything, 'proxy', 1234, 'user', 'pass').and_return(@http_mock)
|
382
|
-
Horse.make_request('anything', {}, 'anything', {:proxy => 'http://user:pass@proxy:1234'})
|
383
|
-
end
|
384
|
-
|
385
|
-
it 'sets both timeouts when options contains a timeout' do
|
386
|
-
@http_mock.should_receive(:open_timeout=).with(10)
|
387
|
-
@http_mock.should_receive(:read_timeout=).with(10)
|
388
|
-
Horse.make_request('anything', {}, 'anything', {:timeout => 10})
|
389
|
-
end
|
390
|
-
|
391
|
-
describe "via POST" do
|
392
|
-
it "should use Net::HTTP to make a POST request" do
|
393
|
-
@http_yield_mock.should_receive(:post).and_return(@mock_http_response)
|
394
|
-
|
395
|
-
Horse.make_request('anything', {}, 'post')
|
396
|
-
end
|
397
|
-
|
398
|
-
it "should go to the specified path adding a / if it doesn't exist" do
|
399
|
-
path = mock('Path')
|
400
|
-
@http_yield_mock.should_receive(:post).with(path, anything).and_return(@mock_http_response)
|
401
|
-
|
402
|
-
Horse.make_request(path, {}, 'post')
|
403
|
-
end
|
404
|
-
|
405
|
-
it "should use encoded parameters" do
|
406
|
-
args = {}
|
407
|
-
params = mock('Encoded parameters')
|
408
|
-
Horse.should_receive(:encode_params).with(args).and_return(params)
|
409
|
-
|
410
|
-
@http_yield_mock.should_receive(:post).with(anything, params).and_return(@mock_http_response)
|
411
|
-
|
412
|
-
Horse.make_request('anything', args, 'post')
|
413
|
-
end
|
414
|
-
|
415
|
-
describe "with multipart/form-data" do
|
416
|
-
before(:each) do
|
417
|
-
Horse.stub(:encode_multipart_params)
|
418
|
-
Horse.stub("params_require_multipart?").and_return(true)
|
419
|
-
|
420
|
-
@multipart_request_stub = stub('Stub Multipart Request')
|
421
|
-
Net::HTTP::Post::Multipart.stub(:new).and_return(@multipart_request_stub)
|
422
|
-
|
423
|
-
@file_stub = stub('fake File', "kind_of?" => true, "path" => 'anypath.jpg')
|
424
|
-
|
425
|
-
@http_yield_mock.stub(:request).with(@multipart_request_stub).and_return(@mock_http_response)
|
426
|
-
end
|
427
|
-
|
428
|
-
it "should use multipart/form-data if any parameter is a valid file hash" do
|
429
|
-
@http_yield_mock.should_receive(:request).with(@multipart_request_stub).and_return(@mock_http_response)
|
430
|
-
|
431
|
-
Horse.make_request('anything', {}, 'post')
|
432
|
-
end
|
433
|
-
|
434
|
-
it "should use the given request path for the request" do
|
435
|
-
args = {"file" => @file_stub}
|
436
|
-
expected_path = 'expected/path'
|
437
|
-
|
438
|
-
Net::HTTP::Post::Multipart.should_receive(:new).with(expected_path, anything).and_return(@multipart_request_stub)
|
439
|
-
|
440
|
-
Horse.make_request(expected_path, {}, 'post')
|
441
|
-
end
|
442
|
-
|
443
|
-
it "should use multipart encoded arguments for the request" do
|
444
|
-
args = {"file" => @file_stub}
|
445
|
-
expected_params = stub('Stub Multipart Params')
|
446
|
-
|
447
|
-
Horse.should_receive(:encode_multipart_params).with(args).and_return(expected_params)
|
448
|
-
Net::HTTP::Post::Multipart.should_receive(:new).with(anything, expected_params).and_return(@multipart_request_stub)
|
449
|
-
|
450
|
-
Horse.make_request('anything', args, 'post')
|
451
|
-
end
|
452
|
-
end
|
453
|
-
end
|
454
|
-
|
455
|
-
describe "via GET" do
|
456
|
-
it "should use Net::HTTP to make a GET request" do
|
457
|
-
@http_yield_mock.should_receive(:get).and_return(@mock_http_response)
|
458
|
-
|
459
|
-
Horse.make_request('anything', {}, 'get')
|
460
|
-
end
|
461
|
-
|
462
|
-
it "should use the correct path, including arguments" do
|
463
|
-
path = mock('Path')
|
464
|
-
params = mock('Encoded parameters')
|
465
|
-
args = {}
|
466
|
-
|
467
|
-
Horse.should_receive(:encode_params).with(args).and_return(params)
|
468
|
-
@http_yield_mock.should_receive(:get).with("#{path}?#{params}").and_return(@mock_http_response)
|
469
|
-
|
470
|
-
Horse.make_request(path, args, 'get')
|
471
|
-
end
|
472
|
-
end
|
473
|
-
|
474
|
-
describe "the returned value" do
|
475
|
-
before(:each) do
|
476
|
-
@response = Horse.make_request('anything', {}, 'anything')
|
477
|
-
end
|
478
|
-
|
479
|
-
it "should return a Koala::Response object" do
|
480
|
-
@response.class.should == Koala::Response
|
481
|
-
end
|
482
|
-
|
483
|
-
it "should return a Koala::Response with the right status" do
|
484
|
-
@response.status.should == @mock_http_response.code
|
485
|
-
end
|
486
|
-
|
487
|
-
it "should reutrn a Koala::Response with the right body" do
|
488
|
-
@response.body.should == @mock_body
|
489
|
-
end
|
490
|
-
|
491
|
-
it "should return a Koala::Response with the Net::HTTPResponse object as headers" do
|
492
|
-
@response.headers.should == @mock_http_response
|
493
|
-
end
|
494
|
-
end # describe return value
|
495
|
-
end # describe when making a request
|
496
|
-
|
497
|
-
describe "when detecting if multipart posting is needed" do
|
498
|
-
it "should be true if any parameter value requires multipart post" do
|
499
|
-
koala_io = mock("Koala::IO")
|
500
|
-
koala_io.should_receive(:kind_of?).with(Koala::UploadableIO).and_return(true)
|
501
|
-
|
502
|
-
args = {
|
503
|
-
"key1" => "val",
|
504
|
-
"key2" => "val",
|
505
|
-
"key3" => koala_io,
|
506
|
-
"key4" => "val"
|
507
|
-
}
|
508
|
-
|
509
|
-
Horse.params_require_multipart?(args).should be_true
|
510
|
-
end
|
511
|
-
|
512
|
-
describe "when encoding multipart/form-data params" do
|
513
|
-
it "should replace Koala::UploadableIO values with UploadIO values" do
|
514
|
-
upload_io = UploadIO.new(__FILE__, "fake type")
|
515
|
-
|
516
|
-
uploadable_io = stub('Koala::UploadableIO')
|
517
|
-
uploadable_io.should_receive(:kind_of?).with(Koala::UploadableIO).and_return(true)
|
518
|
-
uploadable_io.should_receive(:to_upload_io).and_return(upload_io)
|
519
|
-
args = {
|
520
|
-
"not_a_file" => "not a file",
|
521
|
-
"file" => uploadable_io
|
522
|
-
}
|
523
|
-
|
524
|
-
result = Horse.encode_multipart_params(args)
|
525
|
-
|
526
|
-
result["not_a_file"] == args["not_a_file"]
|
527
|
-
result["file"] == upload_io
|
528
|
-
end
|
529
|
-
end
|
530
|
-
|
531
|
-
end
|
532
|
-
end
|