sealights-rspec-agent 2.0.4 → 2.0.5
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.
- checksums.yaml +4 -4
- data/agent/config.rb +6 -6
- data/agent/dependencies/faraday-0.17.0/LICENSE.md +20 -0
- data/agent/dependencies/faraday-0.17.0/README.md +384 -0
- data/agent/dependencies/faraday-0.17.0/lib/faraday.rb +248 -0
- data/agent/dependencies/faraday-0.17.0/lib/faraday/adapter.rb +55 -0
- data/agent/dependencies/faraday-0.17.0/lib/faraday/adapter/em_http.rb +243 -0
- data/agent/dependencies/faraday-0.17.0/lib/faraday/adapter/em_synchrony.rb +106 -0
- data/agent/dependencies/faraday-0.17.0/lib/faraday/adapter/em_synchrony/parallel_manager.rb +66 -0
- data/agent/dependencies/faraday-0.17.0/lib/faraday/adapter/excon.rb +82 -0
- data/agent/dependencies/faraday-0.17.0/lib/faraday/adapter/httpclient.rb +128 -0
- data/agent/dependencies/faraday-0.17.0/lib/faraday/adapter/net_http.rb +152 -0
- data/agent/dependencies/faraday-0.17.0/lib/faraday/adapter/net_http_persistent.rb +68 -0
- data/agent/dependencies/faraday-0.17.0/lib/faraday/adapter/patron.rb +95 -0
- data/agent/dependencies/faraday-0.17.0/lib/faraday/adapter/rack.rb +58 -0
- data/agent/dependencies/faraday-0.17.0/lib/faraday/adapter/sl_em_http_ssl_patch.rb +56 -0
- data/agent/dependencies/faraday-0.17.0/lib/faraday/adapter/test.rb +213 -0
- data/agent/dependencies/faraday-0.17.0/lib/faraday/adapter/typhoeus.rb +12 -0
- data/agent/dependencies/faraday-0.17.0/lib/faraday/autoload.rb +84 -0
- data/agent/dependencies/faraday-0.17.0/lib/faraday/connection.rb +484 -0
- data/agent/dependencies/faraday-0.17.0/lib/faraday/error.rb +66 -0
- data/agent/dependencies/faraday-0.17.0/lib/faraday/middleware.rb +37 -0
- data/agent/dependencies/faraday-0.17.0/lib/faraday/options.rb +373 -0
- data/agent/dependencies/faraday-0.17.0/lib/faraday/parameters.rb +198 -0
- data/agent/dependencies/faraday-0.17.0/lib/faraday/rack_builder.rb +237 -0
- data/agent/dependencies/faraday-0.17.0/lib/faraday/request.rb +114 -0
- data/agent/dependencies/faraday-0.17.0/lib/faraday/request/authorization.rb +41 -0
- data/agent/dependencies/faraday-0.17.0/lib/faraday/request/basic_authentication.rb +13 -0
- data/agent/dependencies/faraday-0.17.0/lib/faraday/request/instrumentation.rb +36 -0
- data/agent/dependencies/faraday-0.17.0/lib/faraday/request/multipart.rb +68 -0
- data/agent/dependencies/faraday-0.17.0/lib/faraday/request/retry.rb +212 -0
- data/agent/dependencies/faraday-0.17.0/lib/faraday/request/token_authentication.rb +15 -0
- data/agent/dependencies/faraday-0.17.0/lib/faraday/request/url_encoded.rb +36 -0
- data/agent/dependencies/faraday-0.17.0/lib/faraday/response.rb +97 -0
- data/agent/dependencies/faraday-0.17.0/lib/faraday/response/logger.rb +80 -0
- data/agent/dependencies/faraday-0.17.0/lib/faraday/response/raise_error.rb +21 -0
- data/agent/dependencies/faraday-0.17.0/lib/faraday/upload_io.rb +67 -0
- data/agent/dependencies/faraday-0.17.0/lib/faraday/utils.rb +326 -0
- data/agent/dependencies/jwt-2.2.1/AUTHORS +84 -0
- data/agent/dependencies/jwt-2.2.1/Appraisals +14 -0
- data/agent/dependencies/jwt-2.2.1/CHANGELOG.md +570 -0
- data/agent/dependencies/jwt-2.2.1/Gemfile +3 -0
- data/agent/dependencies/jwt-2.2.1/LICENSE +7 -0
- data/agent/dependencies/jwt-2.2.1/README.md +489 -0
- data/agent/dependencies/jwt-2.2.1/Rakefile +11 -0
- data/agent/dependencies/jwt-2.2.1/lib/jwt.rb +30 -0
- data/agent/dependencies/jwt-2.2.1/lib/jwt/algos/ecdsa.rb +35 -0
- data/agent/dependencies/jwt-2.2.1/lib/jwt/algos/eddsa.rb +23 -0
- data/agent/dependencies/jwt-2.2.1/lib/jwt/algos/hmac.rb +33 -0
- data/agent/dependencies/jwt-2.2.1/lib/jwt/algos/ps.rb +43 -0
- data/agent/dependencies/jwt-2.2.1/lib/jwt/algos/rsa.rb +19 -0
- data/agent/dependencies/jwt-2.2.1/lib/jwt/algos/unsupported.rb +16 -0
- data/agent/dependencies/jwt-2.2.1/lib/jwt/base64.rb +19 -0
- data/agent/dependencies/jwt-2.2.1/lib/jwt/claims_validator.rb +33 -0
- data/agent/dependencies/jwt-2.2.1/lib/jwt/decode.rb +100 -0
- data/agent/dependencies/jwt-2.2.1/lib/jwt/default_options.rb +15 -0
- data/agent/dependencies/jwt-2.2.1/lib/jwt/encode.rb +68 -0
- data/agent/dependencies/jwt-2.2.1/lib/jwt/error.rb +20 -0
- data/agent/dependencies/jwt-2.2.1/lib/jwt/json.rb +18 -0
- data/agent/dependencies/jwt-2.2.1/lib/jwt/jwk.rb +31 -0
- data/agent/dependencies/jwt-2.2.1/lib/jwt/jwk/key_finder.rb +57 -0
- data/agent/dependencies/jwt-2.2.1/lib/jwt/jwk/rsa.rb +47 -0
- data/agent/dependencies/jwt-2.2.1/lib/jwt/security_utils.rb +57 -0
- data/agent/dependencies/jwt-2.2.1/lib/jwt/signature.rb +52 -0
- data/agent/dependencies/jwt-2.2.1/lib/jwt/verify.rb +98 -0
- data/agent/dependencies/jwt-2.2.1/lib/jwt/version.rb +24 -0
- data/agent/dependencies/jwt-2.2.1/ruby-jwt.gemspec +34 -0
- data/agent/dependencies/multipart-post-2.1.1/Gemfile +6 -0
- data/agent/dependencies/multipart-post-2.1.1/History.txt +64 -0
- data/agent/dependencies/multipart-post-2.1.1/LICENSE +21 -0
- data/agent/dependencies/multipart-post-2.1.1/Manifest.txt +9 -0
- data/agent/dependencies/multipart-post-2.1.1/README.md +127 -0
- data/agent/dependencies/multipart-post-2.1.1/Rakefile +6 -0
- data/agent/dependencies/multipart-post-2.1.1/lib/composite_io.rb +108 -0
- data/agent/dependencies/multipart-post-2.1.1/lib/multipart_post.rb +9 -0
- data/agent/dependencies/multipart-post-2.1.1/lib/multipartable.rb +48 -0
- data/agent/dependencies/multipart-post-2.1.1/lib/net/http/post/multipart.rb +28 -0
- data/agent/dependencies/multipart-post-2.1.1/lib/parts.rb +126 -0
- data/agent/dependencies/multipart-post-2.1.1/multipart-post.gemspec +23 -0
- data/agent/http_client.rb +46 -0
- data/agent/listener.rb +1 -1
- data/agent/sealights-rspec-agent.rb +2 -2
- data/agent/tia.rb +5 -1
- metadata +80 -3
- data/agent/rest-client-wrapper.rb +0 -27
@@ -0,0 +1,68 @@
|
|
1
|
+
module SLFaraday
|
2
|
+
class Adapter
|
3
|
+
class NetHttpPersistent < NetHttp
|
4
|
+
dependency 'net/http/persistent'
|
5
|
+
|
6
|
+
private
|
7
|
+
|
8
|
+
def net_http_connection(env)
|
9
|
+
@cached_connection ||=
|
10
|
+
if Net::HTTP::Persistent.instance_method(:initialize).parameters.first == [:key, :name]
|
11
|
+
options = {name: 'Faraday'}
|
12
|
+
options[:pool_size] = @connection_options[:pool_size] if @connection_options.key?(:pool_size)
|
13
|
+
Net::HTTP::Persistent.new(options)
|
14
|
+
else
|
15
|
+
Net::HTTP::Persistent.new('Faraday')
|
16
|
+
end
|
17
|
+
|
18
|
+
proxy_uri = proxy_uri(env)
|
19
|
+
@cached_connection.proxy = proxy_uri if @cached_connection.proxy_uri != proxy_uri
|
20
|
+
@cached_connection
|
21
|
+
end
|
22
|
+
|
23
|
+
def proxy_uri(env)
|
24
|
+
proxy_uri = nil
|
25
|
+
if (proxy = env[:request][:proxy])
|
26
|
+
proxy_uri = ::URI::HTTP === proxy[:uri] ? proxy[:uri].dup : ::URI.parse(proxy[:uri].to_s)
|
27
|
+
proxy_uri.user = proxy_uri.password = nil
|
28
|
+
# awful patch for net-http-persistent 2.8 not unescaping user/password
|
29
|
+
(class << proxy_uri; self; end).class_eval do
|
30
|
+
define_method(:user) { proxy[:user] }
|
31
|
+
define_method(:password) { proxy[:password] }
|
32
|
+
end if proxy[:user]
|
33
|
+
end
|
34
|
+
proxy_uri
|
35
|
+
end
|
36
|
+
|
37
|
+
def perform_request(http, env)
|
38
|
+
http.request env[:url], create_request(env)
|
39
|
+
rescue Errno::ETIMEDOUT => error
|
40
|
+
raise SLFaraday::Error::TimeoutError, error
|
41
|
+
rescue Net::HTTP::Persistent::Error => error
|
42
|
+
if error.message.include? 'Timeout'
|
43
|
+
raise SLFaraday::Error::TimeoutError, error
|
44
|
+
elsif error.message.include? 'connection refused'
|
45
|
+
raise SLFaraday::Error::ConnectionFailed, error
|
46
|
+
else
|
47
|
+
raise
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
def configure_ssl(http, ssl)
|
52
|
+
http_set(http, :verify_mode, ssl_verify_mode(ssl))
|
53
|
+
http_set(http, :cert_store, ssl_cert_store(ssl))
|
54
|
+
|
55
|
+
http_set(http, :certificate, ssl[:client_cert]) if ssl[:client_cert]
|
56
|
+
http_set(http, :private_key, ssl[:client_key]) if ssl[:client_key]
|
57
|
+
http_set(http, :ca_file, ssl[:ca_file]) if ssl[:ca_file]
|
58
|
+
http_set(http, :ssl_version, ssl[:version]) if ssl[:version]
|
59
|
+
end
|
60
|
+
|
61
|
+
def http_set(http, attr, value)
|
62
|
+
if http.send(attr) != value
|
63
|
+
http.send("#{attr}=", value)
|
64
|
+
end
|
65
|
+
end
|
66
|
+
end
|
67
|
+
end
|
68
|
+
end
|
@@ -0,0 +1,95 @@
|
|
1
|
+
module SLFaraday
|
2
|
+
class Adapter
|
3
|
+
class Patron < SLFaraday::Adapter
|
4
|
+
dependency 'patron'
|
5
|
+
|
6
|
+
def call(env)
|
7
|
+
super
|
8
|
+
# TODO: support streaming requests
|
9
|
+
env[:body] = env[:body].read if env[:body].respond_to? :read
|
10
|
+
|
11
|
+
session = ::Patron::Session.new
|
12
|
+
@config_block.call(session) if @config_block
|
13
|
+
configure_ssl(session, env[:ssl]) if env[:url].scheme == 'https' and env[:ssl]
|
14
|
+
|
15
|
+
if req = env[:request]
|
16
|
+
session.timeout = session.connect_timeout = req[:timeout] if req[:timeout]
|
17
|
+
session.connect_timeout = req[:open_timeout] if req[:open_timeout]
|
18
|
+
|
19
|
+
if proxy = req[:proxy]
|
20
|
+
proxy_uri = proxy[:uri].dup
|
21
|
+
proxy_uri.user = proxy[:user] && Utils.escape(proxy[:user]).gsub('+', '%20')
|
22
|
+
proxy_uri.password = proxy[:password] && Utils.escape(proxy[:password]).gsub('+', '%20')
|
23
|
+
session.proxy = proxy_uri.to_s
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
response = begin
|
28
|
+
data = env[:body] ? env[:body].to_s : nil
|
29
|
+
session.request(env[:method], env[:url].to_s, env[:request_headers], :data => data)
|
30
|
+
rescue Errno::ECONNREFUSED, ::Patron::ConnectionFailed
|
31
|
+
raise Error::ConnectionFailed, $!
|
32
|
+
end
|
33
|
+
|
34
|
+
# Remove the "HTTP/1.1 200", leaving just the reason phrase
|
35
|
+
reason_phrase = response.status_line.gsub(/^.* \d{3} /, '')
|
36
|
+
|
37
|
+
save_response(env, response.status, response.body, response.headers, reason_phrase)
|
38
|
+
|
39
|
+
@app.call env
|
40
|
+
rescue ::Patron::TimeoutError => err
|
41
|
+
if connection_timed_out_message?(err.message)
|
42
|
+
raise SLFaraday::Error::ConnectionFailed, err
|
43
|
+
else
|
44
|
+
raise SLFaraday::Error::TimeoutError, err
|
45
|
+
end
|
46
|
+
rescue ::Patron::Error => err
|
47
|
+
if err.message.include?("code 407")
|
48
|
+
raise Error::ConnectionFailed, %{407 "Proxy Authentication Required "}
|
49
|
+
else
|
50
|
+
raise Error::ConnectionFailed, err
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
if loaded? && defined?(::Patron::Request::VALID_ACTIONS)
|
55
|
+
# HAX: helps but doesn't work completely
|
56
|
+
# https://github.com/toland/patron/issues/34
|
57
|
+
::Patron::Request::VALID_ACTIONS.tap do |actions|
|
58
|
+
if actions[0].is_a?(Symbol)
|
59
|
+
actions << :patch unless actions.include? :patch
|
60
|
+
actions << :options unless actions.include? :options
|
61
|
+
else
|
62
|
+
# Patron 0.4.20 and up
|
63
|
+
actions << "PATCH" unless actions.include? "PATCH"
|
64
|
+
actions << "OPTIONS" unless actions.include? "OPTIONS"
|
65
|
+
end
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
69
|
+
def configure_ssl(session, ssl)
|
70
|
+
if ssl.fetch(:verify, true)
|
71
|
+
session.cacert = ssl[:ca_file]
|
72
|
+
else
|
73
|
+
session.insecure = true
|
74
|
+
end
|
75
|
+
end
|
76
|
+
|
77
|
+
private
|
78
|
+
|
79
|
+
CURL_TIMEOUT_MESSAGES = [ "Connection time-out",
|
80
|
+
"Connection timed out",
|
81
|
+
"Timed out before name resolve",
|
82
|
+
"server connect has timed out",
|
83
|
+
"Resolving timed out",
|
84
|
+
"name lookup timed out",
|
85
|
+
"timed out before SSL",
|
86
|
+
"connect() timed out"
|
87
|
+
].freeze
|
88
|
+
|
89
|
+
def connection_timed_out_message?(message)
|
90
|
+
CURL_TIMEOUT_MESSAGES.any? { |curl_message| message.include?(curl_message) }
|
91
|
+
end
|
92
|
+
|
93
|
+
end
|
94
|
+
end
|
95
|
+
end
|
@@ -0,0 +1,58 @@
|
|
1
|
+
module SLFaraday
|
2
|
+
class Adapter
|
3
|
+
# Sends requests to a Rack app.
|
4
|
+
#
|
5
|
+
# Examples
|
6
|
+
#
|
7
|
+
# class MyRackApp
|
8
|
+
# def call(env)
|
9
|
+
# [200, {'Content-Type' => 'text/html'}, ["hello world"]]
|
10
|
+
# end
|
11
|
+
# end
|
12
|
+
#
|
13
|
+
# Faraday.new do |conn|
|
14
|
+
# conn.adapter :rack, MyRackApp.new
|
15
|
+
# end
|
16
|
+
class Rack < SLFaraday::Adapter
|
17
|
+
dependency 'rack/test'
|
18
|
+
|
19
|
+
# not prefixed with "HTTP_"
|
20
|
+
SPECIAL_HEADERS = %w[ CONTENT_LENGTH CONTENT_TYPE ]
|
21
|
+
|
22
|
+
def initialize(faraday_app, rack_app)
|
23
|
+
super(faraday_app)
|
24
|
+
mock_session = ::Rack::MockSession.new(rack_app)
|
25
|
+
@session = ::Rack::Test::Session.new(mock_session)
|
26
|
+
end
|
27
|
+
|
28
|
+
def call(env)
|
29
|
+
super
|
30
|
+
rack_env = {
|
31
|
+
:method => env[:method],
|
32
|
+
:input => env[:body].respond_to?(:read) ? env[:body].read : env[:body],
|
33
|
+
'rack.url_scheme' => env[:url].scheme
|
34
|
+
}
|
35
|
+
|
36
|
+
env[:request_headers].each do |name, value|
|
37
|
+
name = name.upcase.tr('-', '_')
|
38
|
+
name = "HTTP_#{name}" unless SPECIAL_HEADERS.include? name
|
39
|
+
rack_env[name] = value
|
40
|
+
end if env[:request_headers]
|
41
|
+
|
42
|
+
timeout = env[:request][:timeout] || env[:request][:open_timeout]
|
43
|
+
response = if timeout
|
44
|
+
Timer.timeout(timeout, SLFaraday::Error::TimeoutError) { execute_request(env, rack_env) }
|
45
|
+
else
|
46
|
+
execute_request(env, rack_env)
|
47
|
+
end
|
48
|
+
|
49
|
+
save_response(env, response.status, response.body, response.headers)
|
50
|
+
@app.call env
|
51
|
+
end
|
52
|
+
|
53
|
+
def execute_request(env, rack_env)
|
54
|
+
@session.request(env[:url].to_s, rack_env)
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
@@ -0,0 +1,56 @@
|
|
1
|
+
require 'openssl'
|
2
|
+
require_relative 'em-http'
|
3
|
+
|
4
|
+
module SLEmHttpSslPatch
|
5
|
+
def ssl_verify_peer(cert_string)
|
6
|
+
cert = nil
|
7
|
+
begin
|
8
|
+
cert = OpenSSL::X509::Certificate.new(cert_string)
|
9
|
+
rescue OpenSSL::X509::CertificateError
|
10
|
+
return false
|
11
|
+
end
|
12
|
+
|
13
|
+
@last_seen_cert = cert
|
14
|
+
|
15
|
+
if certificate_store.verify(@last_seen_cert)
|
16
|
+
begin
|
17
|
+
certificate_store.add_cert(@last_seen_cert)
|
18
|
+
rescue OpenSSL::X509::StoreError => e
|
19
|
+
raise e unless e.message == 'cert already in hash table'
|
20
|
+
end
|
21
|
+
true
|
22
|
+
else
|
23
|
+
raise OpenSSL::SSL::SSLError.new(%(unable to verify the server certificate for "#{host}"))
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
def ssl_handshake_completed
|
28
|
+
return true unless verify_peer?
|
29
|
+
|
30
|
+
unless OpenSSL::SSL.verify_certificate_identity(@last_seen_cert, host)
|
31
|
+
raise OpenSSL::SSL::SSLError.new(%(host "#{host}" does not match the server certificate))
|
32
|
+
else
|
33
|
+
true
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
def verify_peer?
|
38
|
+
parent.connopts.tls[:verify_peer]
|
39
|
+
end
|
40
|
+
|
41
|
+
def host
|
42
|
+
parent.uri.host
|
43
|
+
end
|
44
|
+
|
45
|
+
def certificate_store
|
46
|
+
@certificate_store ||= begin
|
47
|
+
store = OpenSSL::X509::Store.new
|
48
|
+
store.set_default_paths
|
49
|
+
ca_file = parent.connopts.tls[:cert_chain_file]
|
50
|
+
store.add_file(ca_file) if ca_file
|
51
|
+
store
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
EventMachine::HttpStubConnection.send(:include, SLEmHttpSslPatch)
|
@@ -0,0 +1,213 @@
|
|
1
|
+
module SLFaraday
|
2
|
+
class Adapter
|
3
|
+
# Examples
|
4
|
+
#
|
5
|
+
# test = Faraday::Connection.new do
|
6
|
+
# use Faraday::Adapter::Test do |stub|
|
7
|
+
# # simply define matcher to match the request
|
8
|
+
# stub.get '/resource.json' do
|
9
|
+
# # return static content
|
10
|
+
# [200, {'Content-Type' => 'application/json'}, 'hi world']
|
11
|
+
# end
|
12
|
+
#
|
13
|
+
# # response with content generated based on request
|
14
|
+
# stub.get '/showget' do |env|
|
15
|
+
# [200, {'Content-Type' => 'text/plain'}, env[:method].to_s]
|
16
|
+
# end
|
17
|
+
#
|
18
|
+
# # regular expression can be used as matching filter
|
19
|
+
# stub.get /\A\/items\/(\d+)\z/ do |env, meta|
|
20
|
+
# # in case regular expression is used an instance of MatchData can be received
|
21
|
+
# [200, {'Content-Type' => 'text/plain'}, "showing item: #{meta[:match_data][1]}"]
|
22
|
+
# end
|
23
|
+
# end
|
24
|
+
# end
|
25
|
+
#
|
26
|
+
# resp = test.get '/resource.json'
|
27
|
+
# resp.body # => 'hi world'
|
28
|
+
#
|
29
|
+
# resp = test.get '/showget'
|
30
|
+
# resp.body # => 'get'
|
31
|
+
#
|
32
|
+
# resp = test.get '/items/1'
|
33
|
+
# resp.body # => 'showing item: 1'
|
34
|
+
#
|
35
|
+
# resp = test.get '/items/2'
|
36
|
+
# resp.body # => 'showing item: 2'
|
37
|
+
#
|
38
|
+
|
39
|
+
class Test < SLFaraday::Adapter
|
40
|
+
attr_accessor :stubs
|
41
|
+
|
42
|
+
class Stubs
|
43
|
+
class NotFound < StandardError
|
44
|
+
end
|
45
|
+
|
46
|
+
def initialize
|
47
|
+
# {:get => [Stub, Stub]}
|
48
|
+
@stack, @consumed = {}, {}
|
49
|
+
yield(self) if block_given?
|
50
|
+
end
|
51
|
+
|
52
|
+
def empty?
|
53
|
+
@stack.empty?
|
54
|
+
end
|
55
|
+
|
56
|
+
def match(request_method, host, path, headers, body)
|
57
|
+
return false if !@stack.key?(request_method)
|
58
|
+
stack = @stack[request_method]
|
59
|
+
consumed = (@consumed[request_method] ||= [])
|
60
|
+
|
61
|
+
stub, meta = matches?(stack, host, path, headers, body)
|
62
|
+
if stub
|
63
|
+
consumed << stack.delete(stub)
|
64
|
+
return stub, meta
|
65
|
+
end
|
66
|
+
matches?(consumed, host, path, headers, body)
|
67
|
+
end
|
68
|
+
|
69
|
+
def get(path, headers = {}, &block)
|
70
|
+
new_stub(:get, path, headers, &block)
|
71
|
+
end
|
72
|
+
|
73
|
+
def head(path, headers = {}, &block)
|
74
|
+
new_stub(:head, path, headers, &block)
|
75
|
+
end
|
76
|
+
|
77
|
+
def post(path, body=nil, headers = {}, &block)
|
78
|
+
new_stub(:post, path, headers, body, &block)
|
79
|
+
end
|
80
|
+
|
81
|
+
def put(path, body=nil, headers = {}, &block)
|
82
|
+
new_stub(:put, path, headers, body, &block)
|
83
|
+
end
|
84
|
+
|
85
|
+
def patch(path, body=nil, headers = {}, &block)
|
86
|
+
new_stub(:patch, path, headers, body, &block)
|
87
|
+
end
|
88
|
+
|
89
|
+
def delete(path, headers = {}, &block)
|
90
|
+
new_stub(:delete, path, headers, &block)
|
91
|
+
end
|
92
|
+
|
93
|
+
def options(path, headers = {}, &block)
|
94
|
+
new_stub(:options, path, headers, &block)
|
95
|
+
end
|
96
|
+
|
97
|
+
# Raises an error if any of the stubbed calls have not been made.
|
98
|
+
def verify_stubbed_calls
|
99
|
+
failed_stubs = []
|
100
|
+
@stack.each do |method, stubs|
|
101
|
+
unless stubs.size == 0
|
102
|
+
failed_stubs.concat(stubs.map {|stub|
|
103
|
+
"Expected #{method} #{stub}."
|
104
|
+
})
|
105
|
+
end
|
106
|
+
end
|
107
|
+
raise failed_stubs.join(" ") unless failed_stubs.size == 0
|
108
|
+
end
|
109
|
+
|
110
|
+
protected
|
111
|
+
|
112
|
+
def new_stub(request_method, path, headers = {}, body=nil, &block)
|
113
|
+
normalized_path, host =
|
114
|
+
if path.is_a?(Regexp)
|
115
|
+
path
|
116
|
+
else
|
117
|
+
[SLFaraday::Utils.normalize_path(path), SLFaraday::Utils.URI(path).host]
|
118
|
+
end
|
119
|
+
|
120
|
+
(@stack[request_method] ||= []) << Stub.new(host, normalized_path, headers, body, block)
|
121
|
+
end
|
122
|
+
|
123
|
+
def matches?(stack, host, path, headers, body)
|
124
|
+
stack.each do |stub|
|
125
|
+
match_result, meta = stub.matches?(host, path, headers, body)
|
126
|
+
return stub, meta if match_result
|
127
|
+
end
|
128
|
+
nil
|
129
|
+
end
|
130
|
+
end
|
131
|
+
|
132
|
+
class Stub < Struct.new(:host, :path, :params, :headers, :body, :block)
|
133
|
+
def initialize(host, full, headers, body, block)
|
134
|
+
path, query = full.respond_to?(:split) ? full.split("?") : full
|
135
|
+
params = query ?
|
136
|
+
SLFaraday::Utils.parse_nested_query(query) :
|
137
|
+
{}
|
138
|
+
super(host, path, params, headers, body, block)
|
139
|
+
end
|
140
|
+
|
141
|
+
def matches?(request_host, request_uri, request_headers, request_body)
|
142
|
+
request_path, request_query = request_uri.split('?')
|
143
|
+
request_params = request_query ?
|
144
|
+
SLFaraday::Utils.parse_nested_query(request_query) :
|
145
|
+
{}
|
146
|
+
# meta is a hash use as carrier
|
147
|
+
# that will be yielded to consumer block
|
148
|
+
meta = {}
|
149
|
+
return (host.nil? || host == request_host) &&
|
150
|
+
path_match?(request_path, meta) &&
|
151
|
+
params_match?(request_params) &&
|
152
|
+
(body.to_s.size.zero? || request_body == body) &&
|
153
|
+
headers_match?(request_headers), meta
|
154
|
+
end
|
155
|
+
|
156
|
+
def path_match?(request_path, meta)
|
157
|
+
if path.is_a? Regexp
|
158
|
+
!!(meta[:match_data] = path.match(request_path))
|
159
|
+
else
|
160
|
+
path == request_path
|
161
|
+
end
|
162
|
+
end
|
163
|
+
|
164
|
+
def params_match?(request_params)
|
165
|
+
params.keys.all? do |key|
|
166
|
+
request_params[key] == params[key]
|
167
|
+
end
|
168
|
+
end
|
169
|
+
|
170
|
+
def headers_match?(request_headers)
|
171
|
+
headers.keys.all? do |key|
|
172
|
+
request_headers[key] == headers[key]
|
173
|
+
end
|
174
|
+
end
|
175
|
+
|
176
|
+
def to_s
|
177
|
+
"#{path} #{body}"
|
178
|
+
end
|
179
|
+
end
|
180
|
+
|
181
|
+
def initialize(app, stubs=nil, &block)
|
182
|
+
super(app)
|
183
|
+
@stubs = stubs || Stubs.new
|
184
|
+
configure(&block) if block
|
185
|
+
end
|
186
|
+
|
187
|
+
def configure
|
188
|
+
yield(stubs)
|
189
|
+
end
|
190
|
+
|
191
|
+
def call(env)
|
192
|
+
super
|
193
|
+
host = env[:url].host
|
194
|
+
normalized_path = SLFaraday::Utils.normalize_path(env[:url])
|
195
|
+
params_encoder = env.request.params_encoder || SLFaraday::Utils.default_params_encoder
|
196
|
+
|
197
|
+
stub, meta = stubs.match(env[:method], host, normalized_path, env.request_headers, env[:body])
|
198
|
+
if stub
|
199
|
+
env[:params] = (query = env[:url].query) ?
|
200
|
+
params_encoder.decode(query) : {}
|
201
|
+
block_arity = stub.block.arity
|
202
|
+
status, headers, body = (block_arity >= 0) ?
|
203
|
+
stub.block.call(*[env, meta].take(block_arity)) :
|
204
|
+
stub.block.call(env, meta)
|
205
|
+
save_response(env, status, body, headers)
|
206
|
+
else
|
207
|
+
raise Stubs::NotFound, "no stubbed request for #{env[:method]} #{normalized_path} #{env[:body]}"
|
208
|
+
end
|
209
|
+
@app.call(env)
|
210
|
+
end
|
211
|
+
end
|
212
|
+
end
|
213
|
+
end
|