koala 1.1.0 → 1.2.0beta1
Sign up to get free protection for your applications and to get access to all the features.
- 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
|