From 9074c332fe9ac63979c41659fbecf1e226f9bf8e Mon Sep 17 00:00:00 2001 From: Alexey Chernenkov Date: Thu, 23 Aug 2018 17:34:21 +0500 Subject: [PATCH 01/19] Add integration test for net_http + read_timeout --- spec/integration/net_http_spec.rb | 9 +++++++++ spec/integration/support/application.rb | 5 +++-- 2 files changed, 12 insertions(+), 2 deletions(-) diff --git a/spec/integration/net_http_spec.rb b/spec/integration/net_http_spec.rb index fcee178..ee722d4 100644 --- a/spec/integration/net_http_spec.rb +++ b/spec/integration/net_http_spec.rb @@ -30,6 +30,15 @@ expect(response.headers["Set-Cookie"]).to eq(cookies) end + it "it supports read timeout" do + request = HTTPI::Request.new(@server.url + "timeout") + request.read_timeout = 0.5 # seconds + + expect do + HTTPI.get(request, adapter) + end.to raise_exception(Net::ReadTimeout) + end + it "executes GET requests" do response = HTTPI.get(@server.url, adapter) expect(response.body).to eq("get") diff --git a/spec/integration/support/application.rb b/spec/integration/support/application.rb index 20c9bc4..0f6d26c 100644 --- a/spec/integration/support/application.rb +++ b/spec/integration/support/application.rb @@ -15,9 +15,10 @@ def self.respond_with(body) } end - map "/repeat" do + map "/timeout" do run lambda { |env| - IntegrationServer.respond_with :body => env["rack.input"].read + sleep 2 + IntegrationServer.respond_with "done" } end From 8b249bcaec4ed8f771665f02e84d9a1f7c785a6d Mon Sep 17 00:00:00 2001 From: Alexey Chernenkov Date: Thu, 23 Aug 2018 17:43:15 +0500 Subject: [PATCH 02/19] Add integration test for net_http_persistent + read_timeout --- spec/integration/net_http_persistent_spec.rb | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/spec/integration/net_http_persistent_spec.rb b/spec/integration/net_http_persistent_spec.rb index 28aabbf..cf4ff47 100644 --- a/spec/integration/net_http_persistent_spec.rb +++ b/spec/integration/net_http_persistent_spec.rb @@ -30,6 +30,17 @@ expect(response.headers["Set-Cookie"]).to eq(cookies) end + it "it supports read timeout" do + require "net/http/persistent" + + request = HTTPI::Request.new(@server.url + "timeout") + request.read_timeout = 0.5 # seconds + + expect do + HTTPI.get(request, adapter) + end.to raise_exception(Net::HTTP::Persistent::Error, /Net::ReadTimeout/) + end + it "executes GET requests" do response = HTTPI.get(@server.url, adapter) expect(response.body).to eq("get") @@ -38,7 +49,7 @@ it "executes POST requests" do request = HTTPI::Request.new(url: @server.url, open_timeout: 1, read_timeout: 1, body: "xml") - + response = HTTPI.post(request, adapter) expect(response.body).to eq("post") expect(response.headers["Content-Type"]).to eq("text/plain") From f692635dcb04b9bdac22a0c6b2cc096de6703b4a Mon Sep 17 00:00:00 2001 From: Alexey Chernenkov Date: Thu, 23 Aug 2018 18:30:49 +0500 Subject: [PATCH 03/19] Add integration test for excon + read_timeout --- spec/integration/excon_spec.rb | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/spec/integration/excon_spec.rb b/spec/integration/excon_spec.rb index ed45b58..31ad00b 100644 --- a/spec/integration/excon_spec.rb +++ b/spec/integration/excon_spec.rb @@ -30,6 +30,17 @@ expect(response.headers["Set-Cookie"]).to eq(cookies) end + it "it supports read timeout" do + require "excon" + + request = HTTPI::Request.new(@server.url + "timeout") + request.read_timeout = 0.5 # seconds + + expect do + HTTPI.get(request, adapter) + end.to raise_exception(Excon::Error::Timeout) + end + it "executes GET requests" do response = HTTPI.get(@server.url, adapter) expect(response.body).to eq("get") From 6046d35c33ceee4167d8c23b532beae045fda6d2 Mon Sep 17 00:00:00 2001 From: Alexey Chernenkov Date: Thu, 23 Aug 2018 18:31:50 +0500 Subject: [PATCH 04/19] Set timeouts in msec in curb adapter Why: for better support of the floating point values in `read_timeout` and `open_timeout` options. --- lib/httpi/adapter/curb.rb | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/httpi/adapter/curb.rb b/lib/httpi/adapter/curb.rb index f6afb41..bfe55a6 100644 --- a/lib/httpi/adapter/curb.rb +++ b/lib/httpi/adapter/curb.rb @@ -72,8 +72,8 @@ def setup_client def basic_setup @client.url = @request.url.to_s @client.proxy_url = @request.proxy.to_s if @request.proxy - @client.timeout = @request.read_timeout if @request.read_timeout - @client.connect_timeout = @request.open_timeout if @request.open_timeout + @client.timeout_ms = @request.read_timeout * 1000 if @request.read_timeout + @client.connect_timeout_ms = @request.open_timeout * 1000 if @request.open_timeout @client.headers = @request.headers.to_hash @client.verbose = false # cURL workaround From bf760e1274f962e129dd98f11508c8207da9c43e Mon Sep 17 00:00:00 2001 From: Alexey Chernenkov Date: Thu, 23 Aug 2018 18:34:09 +0500 Subject: [PATCH 05/19] Add integration test for curb + read_timeout --- spec/integration/curb_spec.rb | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/spec/integration/curb_spec.rb b/spec/integration/curb_spec.rb index a13af0f..912d995 100644 --- a/spec/integration/curb_spec.rb +++ b/spec/integration/curb_spec.rb @@ -33,6 +33,17 @@ expect(response.headers["Set-Cookie"]).to eq(cookies) end + it "it supports read timeout" do + require "curb" + + request = HTTPI::Request.new(@server.url + "timeout") + request.read_timeout = 0.5 # seconds + + expect do + puts HTTPI.get(request, adapter).inspect + end.to raise_exception(Curl::Err::TimeoutError) + end + it "executes GET requests" do response = HTTPI.get(@server.url, adapter) expect(response.body).to eq("get") From 4544e6cee5efe4ad20dfe706d76f5f5be77e46ee Mon Sep 17 00:00:00 2001 From: Alexey Chernenkov Date: Thu, 23 Aug 2018 18:38:50 +0500 Subject: [PATCH 06/19] Add integration test for em_http + read_timeout --- spec/integration/em_http_spec.rb | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/spec/integration/em_http_spec.rb b/spec/integration/em_http_spec.rb index e980b1e..259b86d 100644 --- a/spec/integration/em_http_spec.rb +++ b/spec/integration/em_http_spec.rb @@ -42,6 +42,15 @@ expect(response.headers["Set-Cookie"]).to eq(cookies) end + it "it supports read timeout" do + request = HTTPI::Request.new(@server.url + "timeout") + request.read_timeout = 0.5 # seconds + + expect do + puts HTTPI.get(request, adapter).inspect + end.to raise_exception(HTTPI::TimeoutError) + end + it "executes GET requests" do response = HTTPI.get(@server.url, adapter) expect(response.body).to eq("get") From ec837d20bab001cd8d64250f3a0d8d29322465a5 Mon Sep 17 00:00:00 2001 From: Alexey Chernenkov Date: Thu, 23 Aug 2018 18:42:04 +0500 Subject: [PATCH 07/19] Add integration test for httpclient + read_timeout --- spec/integration/httpclient_spec.rb | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/spec/integration/httpclient_spec.rb b/spec/integration/httpclient_spec.rb index 934a060..a699ee6 100644 --- a/spec/integration/httpclient_spec.rb +++ b/spec/integration/httpclient_spec.rb @@ -30,6 +30,17 @@ expect(response.headers["Set-Cookie"]).to eq(cookies) end + it "it supports read timeout" do + require "httpclient" + + request = HTTPI::Request.new(@server.url + "timeout") + request.read_timeout = 0.5 # seconds + + expect do + puts HTTPI.get(request, adapter).inspect + end.to raise_exception(HTTPClient::ReceiveTimeoutError) + end + it "executes GET requests" do response = HTTPI.get(@server.url, adapter) expect(response.body).to eq("get") From 370e3f5e184ecab3ec6f04e7633d479eb28e0223 Mon Sep 17 00:00:00 2001 From: Alexey Chernenkov Date: Thu, 23 Aug 2018 19:03:38 +0500 Subject: [PATCH 08/19] Add support for open/read timeouts to http adapter --- lib/httpi/adapter/http.rb | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/lib/httpi/adapter/http.rb b/lib/httpi/adapter/http.rb index e60e787..35366c9 100644 --- a/lib/httpi/adapter/http.rb +++ b/lib/httpi/adapter/http.rb @@ -73,6 +73,11 @@ def create_client client = client.via(@request.proxy.host, @request.proxy.port, @request.proxy.user, @request.proxy.password) end + timeouts = {} + timeouts[:connect] = @request.open_timeout if @request.open_timeout + timeouts[:read] = @request.read_timeout if @request.read_timeout + client = client.timeout(timeouts) if timeouts.any? + client.headers(@request.headers) end end From b8426ac1d020d65eeaa476ebc41467af8e1bade5 Mon Sep 17 00:00:00 2001 From: Alexey Chernenkov Date: Thu, 23 Aug 2018 19:04:01 +0500 Subject: [PATCH 09/19] Add integration test for http + read_timeout --- spec/integration/http_spec.rb | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/spec/integration/http_spec.rb b/spec/integration/http_spec.rb index 5f167d3..e65cd1a 100644 --- a/spec/integration/http_spec.rb +++ b/spec/integration/http_spec.rb @@ -30,6 +30,18 @@ expect(response.headers["Set-Cookie"]).to eq(cookies) end + it "it supports read timeout" do + require "http" + + request = HTTPI::Request.new(@server.url + "timeout") + request.read_timeout = 0.5 # seconds + + expect do + HTTPI.get(request, adapter) + end.to raise_exception(HTTP::TimeoutError) + end + + it "executes GET requests" do response = HTTPI.get(@server.url, adapter) expect(response.body).to eq("get") From 06d20863c4f39f28360e30347c4b93828b41d519 Mon Sep 17 00:00:00 2001 From: Alexey Chernenkov Date: Thu, 23 Aug 2018 19:05:16 +0500 Subject: [PATCH 10/19] Remove debug output from timeout specs --- spec/integration/curb_spec.rb | 2 +- spec/integration/em_http_spec.rb | 2 +- spec/integration/httpclient_spec.rb | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/spec/integration/curb_spec.rb b/spec/integration/curb_spec.rb index 912d995..598a82a 100644 --- a/spec/integration/curb_spec.rb +++ b/spec/integration/curb_spec.rb @@ -40,7 +40,7 @@ request.read_timeout = 0.5 # seconds expect do - puts HTTPI.get(request, adapter).inspect + HTTPI.get(request, adapter) end.to raise_exception(Curl::Err::TimeoutError) end diff --git a/spec/integration/em_http_spec.rb b/spec/integration/em_http_spec.rb index 259b86d..fb04bdf 100644 --- a/spec/integration/em_http_spec.rb +++ b/spec/integration/em_http_spec.rb @@ -47,7 +47,7 @@ request.read_timeout = 0.5 # seconds expect do - puts HTTPI.get(request, adapter).inspect + HTTPI.get(request, adapter) end.to raise_exception(HTTPI::TimeoutError) end diff --git a/spec/integration/httpclient_spec.rb b/spec/integration/httpclient_spec.rb index a699ee6..be52cb8 100644 --- a/spec/integration/httpclient_spec.rb +++ b/spec/integration/httpclient_spec.rb @@ -37,7 +37,7 @@ request.read_timeout = 0.5 # seconds expect do - puts HTTPI.get(request, adapter).inspect + HTTPI.get(request, adapter) end.to raise_exception(HTTPClient::ReceiveTimeoutError) end From c59e11a1aa638f81e69dbbd1e7bbd8408a06fad8 Mon Sep 17 00:00:00 2001 From: Alexey Chernenkov Date: Thu, 23 Aug 2018 19:16:13 +0500 Subject: [PATCH 11/19] Fix broken timeout specs for curb adapter --- spec/httpi/adapter/curb_spec.rb | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/spec/httpi/adapter/curb_spec.rb b/spec/httpi/adapter/curb_spec.rb index b624447..2c670e7 100644 --- a/spec/httpi/adapter/curb_spec.rb +++ b/spec/httpi/adapter/curb_spec.rb @@ -146,29 +146,29 @@ end end - describe "timeout" do + describe "timeout_ms" do it "is not set unless it's specified" do - curb.expects(:timeout=).never + curb.expects(:timeout_ms=).never adapter.request(:get) end it "is set if specified" do request.read_timeout = 30 - curb.expects(:timeout=).with(request.read_timeout) + curb.expects(:timeout_ms=).with(30_000) adapter.request(:get) end end - describe "connect_timeout" do + describe "connect_timeout_ms" do it "is not set unless it's specified" do - curb.expects(:connect_timeout=).never + curb.expects(:connect_timeout_ms=).never adapter.request(:get) end it "is set if specified" do request.open_timeout = 30 - curb.expects(:connect_timeout=).with(30) + curb.expects(:connect_timeout_ms=).with(30_000) adapter.request(:get) end From 1c3aba498e9cbd1ccaeee54770b973ad74686181 Mon Sep 17 00:00:00 2001 From: Alexey Chernenkov Date: Thu, 23 Aug 2018 20:43:57 +0500 Subject: [PATCH 12/19] Fix em_http adapter: do not set timeouts to nil explicitly --- lib/httpi/adapter/em_http.rb | 8 ++++---- spec/httpi/adapter/em_http_spec.rb | 21 +++++++++------------ 2 files changed, 13 insertions(+), 16 deletions(-) diff --git a/lib/httpi/adapter/em_http.rb b/lib/httpi/adapter/em_http.rb index 3aeb58d..104e031 100644 --- a/lib/httpi/adapter/em_http.rb +++ b/lib/httpi/adapter/em_http.rb @@ -69,10 +69,10 @@ def _request end def connection_options - options = { - :connect_timeout => @request.open_timeout, - :inactivity_timeout => @request.read_timeout - } + options = {} + + options[:inactivity_timeout] = @request.read_timeout if @request.read_timeout + options[:connect_timeout] = @request.open_timeout if @request.open_timeout options[:proxy] = proxy_options if @request.proxy diff --git a/spec/httpi/adapter/em_http_spec.rb b/spec/httpi/adapter/em_http_spec.rb index a171138..4b82452 100644 --- a/spec/httpi/adapter/em_http_spec.rb +++ b/spec/httpi/adapter/em_http_spec.rb @@ -89,15 +89,12 @@ end it "sets host, port and authorization" do - url = 'http://example.com:80' - + url = "http://example.com:80" connection_options = { - :connect_timeout => nil, - :inactivity_timeout => nil, - :proxy => { - :host => 'proxy-host.com', - :port => 443, - :authorization => ['username', 'password'] + :proxy => { + :host => "proxy-host.com", + :port => 443, + :authorization => ["username", "password"] } } @@ -111,8 +108,8 @@ it "is passed as a connection option" do request.open_timeout = 30 - url = 'http://example.com:80' - connection_options = { :connect_timeout => 30, :inactivity_timeout => nil } + url = "http://example.com:80" + connection_options = { connect_timeout: 30 } EventMachine::HttpRequest.expects(:new).with(url, connection_options) @@ -124,8 +121,8 @@ it "is passed as a connection option" do request.read_timeout = 60 - url = 'http://example.com:80' - connection_options = { :connect_timeout => nil, :inactivity_timeout => 60 } + url = "http://example.com:80" + connection_options = { inactivity_timeout: 60 } EventMachine::HttpRequest.expects(:new).with(url, connection_options) From 8b96c4ace477a09a967d4d8bb23432d6d07635f4 Mon Sep 17 00:00:00 2001 From: Alexey Chernenkov Date: Mon, 27 Aug 2018 12:45:15 +0500 Subject: [PATCH 13/19] Disable read_timeout test for em_http_request adapter on jruby --- spec/integration/em_http_spec.rb | 22 +++++++++++++++------- 1 file changed, 15 insertions(+), 7 deletions(-) diff --git a/spec/integration/em_http_spec.rb b/spec/integration/em_http_spec.rb index fb04bdf..ed15a0e 100644 --- a/spec/integration/em_http_spec.rb +++ b/spec/integration/em_http_spec.rb @@ -42,13 +42,21 @@ expect(response.headers["Set-Cookie"]).to eq(cookies) end - it "it supports read timeout" do - request = HTTPI::Request.new(@server.url + "timeout") - request.read_timeout = 0.5 # seconds - - expect do - HTTPI.get(request, adapter) - end.to raise_exception(HTTPI::TimeoutError) + if RUBY_PLATFORM =~ /java/ + pending <<-MSG + It seems like JRuby is missing support for inactivity timeout! See related issues on GitHub: + - https://github.com/eventmachine/eventmachine/issues/155 + - https://github.com/eventmachine/eventmachine/pull/312 + MSG + else + it "it supports read timeout" do + request = HTTPI::Request.new(@server.url + "timeout") + request.read_timeout = 0.5 # seconds + + expect do + HTTPI.get(request, adapter) + end.to raise_exception(HTTPI::TimeoutError) + end end it "executes GET requests" do From d3edcc48da5f5757f29e46e8a670e212039184f3 Mon Sep 17 00:00:00 2001 From: Alexey Chernenkov Date: Thu, 23 Aug 2018 20:48:43 +0500 Subject: [PATCH 14/19] Add support for write_timeout config option --- lib/httpi/adapter/curb.rb | 3 ++- lib/httpi/adapter/em_http.rb | 3 ++- lib/httpi/adapter/excon.rb | 1 + lib/httpi/adapter/http.rb | 1 + lib/httpi/adapter/httpclient.rb | 1 + lib/httpi/adapter/net_http.rb | 7 +++++++ lib/httpi/adapter/net_http_persistent.rb | 1 + lib/httpi/request.rb | 4 ++-- 8 files changed, 17 insertions(+), 4 deletions(-) diff --git a/lib/httpi/adapter/curb.rb b/lib/httpi/adapter/curb.rb index bfe55a6..99fc3b0 100644 --- a/lib/httpi/adapter/curb.rb +++ b/lib/httpi/adapter/curb.rb @@ -72,7 +72,8 @@ def setup_client def basic_setup @client.url = @request.url.to_s @client.proxy_url = @request.proxy.to_s if @request.proxy - @client.timeout_ms = @request.read_timeout * 1000 if @request.read_timeout + read_or_write_timeout = @request.read_timeout || @request.write_timeout + @client.timeout_ms = read_or_write_timeout * 1000 if read_or_write_timeout @client.connect_timeout_ms = @request.open_timeout * 1000 if @request.open_timeout @client.headers = @request.headers.to_hash @client.verbose = false diff --git a/lib/httpi/adapter/em_http.rb b/lib/httpi/adapter/em_http.rb index 104e031..412bbf3 100644 --- a/lib/httpi/adapter/em_http.rb +++ b/lib/httpi/adapter/em_http.rb @@ -71,7 +71,8 @@ def _request def connection_options options = {} - options[:inactivity_timeout] = @request.read_timeout if @request.read_timeout + read_or_write_timeout = @request.read_timeout || @request.write_timeout + options[:inactivity_timeout] = read_or_write_timeout if read_or_write_timeout options[:connect_timeout] = @request.open_timeout if @request.open_timeout options[:proxy] = proxy_options if @request.proxy diff --git a/lib/httpi/adapter/excon.rb b/lib/httpi/adapter/excon.rb index b80396b..a03cd8f 100644 --- a/lib/httpi/adapter/excon.rb +++ b/lib/httpi/adapter/excon.rb @@ -58,6 +58,7 @@ def client_opts opts[:user], opts[:password] = *@request.auth.credentials if @request.auth.basic? opts[:connect_timeout] = @request.open_timeout if @request.open_timeout opts[:read_timeout] = @request.read_timeout if @request.read_timeout + opts[:write_timeout] = @request.write_timeout if @request.write_timeout opts[:response_block] = @request.on_body if @request.on_body opts[:proxy] = @request.proxy if @request.proxy diff --git a/lib/httpi/adapter/http.rb b/lib/httpi/adapter/http.rb index 35366c9..8b702c0 100644 --- a/lib/httpi/adapter/http.rb +++ b/lib/httpi/adapter/http.rb @@ -76,6 +76,7 @@ def create_client timeouts = {} timeouts[:connect] = @request.open_timeout if @request.open_timeout timeouts[:read] = @request.read_timeout if @request.read_timeout + timeouts[:write] = @request.write_timeout if @request.write_timeout client = client.timeout(timeouts) if timeouts.any? client.headers(@request.headers) diff --git a/lib/httpi/adapter/httpclient.rb b/lib/httpi/adapter/httpclient.rb index 97cd56b..9165805 100644 --- a/lib/httpi/adapter/httpclient.rb +++ b/lib/httpi/adapter/httpclient.rb @@ -45,6 +45,7 @@ def basic_setup @client.proxy = @request.proxy if @request.proxy @client.connect_timeout = @request.open_timeout if @request.open_timeout @client.receive_timeout = @request.read_timeout if @request.read_timeout + @client.send_timeout = @request.write_timeout if @request.write_timeout end def setup_auth diff --git a/lib/httpi/adapter/net_http.rb b/lib/httpi/adapter/net_http.rb index 9aa3855..c31d0d5 100644 --- a/lib/httpi/adapter/net_http.rb +++ b/lib/httpi/adapter/net_http.rb @@ -155,6 +155,13 @@ def setup_client @client.use_ssl = @request.ssl? @client.open_timeout = @request.open_timeout if @request.open_timeout @client.read_timeout = @request.read_timeout if @request.read_timeout + if @request.write_timeout + if @client.respond_to?(:write_timeout=) # Since Ruby 2.6 + @client.write_timeout = @request.write_timeout + else + raise NotSupportedError, "Net::HTTP supports write_timeout since Ruby 2.6" + end + end end def setup_ssl_auth diff --git a/lib/httpi/adapter/net_http_persistent.rb b/lib/httpi/adapter/net_http_persistent.rb index 554cc4e..501c255 100644 --- a/lib/httpi/adapter/net_http_persistent.rb +++ b/lib/httpi/adapter/net_http_persistent.rb @@ -32,6 +32,7 @@ def setup_client @client.open_timeout = @request.open_timeout if @request.open_timeout @client.read_timeout = @request.read_timeout if @request.read_timeout + raise NotSupportedError, "Net::HTTP::Persistent does not support write_timeout" if @request.write_timeout end def thread_key diff --git a/lib/httpi/request.rb b/lib/httpi/request.rb index 8c0d071..8eebf9a 100644 --- a/lib/httpi/request.rb +++ b/lib/httpi/request.rb @@ -11,7 +11,7 @@ module HTTPI class Request # Available attribute writers. - ATTRIBUTES = [:url, :proxy, :headers, :body, :open_timeout, :read_timeout, :follow_redirect, :redirect_limit, :query] + ATTRIBUTES = [:url, :proxy, :headers, :body, :open_timeout, :read_timeout, :write_timeout, :follow_redirect, :redirect_limit, :query] # Accepts a Hash of +args+ to mass assign attributes and authentication credentials. def initialize(args = {}) @@ -90,7 +90,7 @@ def set_cookies(object_or_array) headers["Cookie"] = cookies if cookies end - attr_accessor :open_timeout, :read_timeout + attr_accessor :open_timeout, :read_timeout, :write_timeout attr_reader :body # Sets a body request given a String or a Hash. From f2d0e771a758cbaabbf423a9fe673c2ad80dda42 Mon Sep 17 00:00:00 2001 From: Alexey Chernenkov Date: Thu, 23 Aug 2018 21:00:15 +0500 Subject: [PATCH 15/19] Move excon integration tests to the appropriate file --- spec/httpi/adapter/excon_spec.rb | 124 ------------------- spec/integration/excon_spec.rb | 36 ++++++ spec/integration/net_http_persistent_spec.rb | 2 +- 3 files changed, 37 insertions(+), 125 deletions(-) delete mode 100644 spec/httpi/adapter/excon_spec.rb diff --git a/spec/httpi/adapter/excon_spec.rb b/spec/httpi/adapter/excon_spec.rb deleted file mode 100644 index 52af8c2..0000000 --- a/spec/httpi/adapter/excon_spec.rb +++ /dev/null @@ -1,124 +0,0 @@ -require "spec_helper" -require "integration/support/server" - -describe HTTPI::Adapter::Excon do - - subject(:adapter) { :excon } - - context "http requests" do - before :all do - @server = IntegrationServer.run - end - - after :all do - @server.stop - end - - it "sends and receives HTTP headers" do - request = HTTPI::Request.new(@server.url + "x-header") - request.headers["X-Header"] = "HTTPI" - - response = HTTPI.get(request, adapter) - expect(response.body).to include("HTTPI") - end - - it "executes GET requests" do - response = HTTPI.get(@server.url, adapter) - expect(response.body).to eq("get") - expect(response.headers["Content-Type"]).to eq("text/plain") - end - - it "executes POST requests" do - response = HTTPI.post(@server.url, "xml", adapter) - expect(response.body).to eq("post") - expect(response.headers["Content-Type"]).to eq("text/plain") - end - - it "executes HEAD requests" do - response = HTTPI.head(@server.url, adapter) - expect(response.code).to eq(200) - expect(response.headers["Content-Type"]).to eq("text/plain") - end - - it "executes PUT requests" do - response = HTTPI.put(@server.url, "xml", adapter) - expect(response.body).to eq("put") - expect(response.headers["Content-Type"]).to eq("text/plain") - end - - it "executes DELETE requests" do - response = HTTPI.delete(@server.url, adapter) - expect(response.body).to eq("delete") - expect(response.headers["Content-Type"]).to eq("text/plain") - end - - it "supports basic authentication" do - request = HTTPI::Request.new(@server.url + "basic-auth") - request.auth.basic("admin", "secret") - - response = HTTPI.get(request, adapter) - expect(response.body).to eq("basic-auth") - end - - it "does not support ntlm authentication" do - request = HTTPI::Request.new(@server.url + "ntlm-auth") - request.auth.ntlm("tester", "vReqSoafRe5O") - - expect { HTTPI.get(request, adapter) }. - to raise_error(HTTPI::NotSupportedError, /does not support NTLM authentication/) - end - - it "supports disabling verify mode" do - request = HTTPI::Request.new(@server.url) - request.auth.ssl.verify_mode = :none - adapter_class = HTTPI::Adapter.load(adapter).new(request) - expect(adapter_class.client.data[:ssl_verify_peer]).to eq(false) - end - end - - # it does not support digest auth - - if RUBY_PLATFORM =~ /java/ - pending "Puma Server complains: SSL not supported on JRuby" - else - context "https requests" do - before :all do - @server = IntegrationServer.run(:ssl => true) - end - after :all do - @server.stop - end - - # it does not raise when no certificate was set up - it "works when no client cert is specified" do - request = HTTPI::Request.new(@server.url) - request.auth.ssl.ca_cert_file = IntegrationServer.ssl_ca_file - - response = HTTPI.get(request, adapter) - expect(response.body).to eq("get") - end - - it "works with client cert and key provided as file path" do - request = HTTPI::Request.new(@server.url) - request.auth.ssl.ca_cert_file = IntegrationServer.ssl_ca_file - request.auth.ssl.cert_file = "spec/fixtures/client_cert.pem" - request.auth.ssl.cert_key_file = "spec/fixtures/client_key.pem" - - response = HTTPI.get(request, adapter) - expect(response.body).to eq("get") - end - - it "works with client cert and key set directly" do - request = HTTPI::Request.new(@server.url) - - request.auth.ssl.ca_cert_file = IntegrationServer.ssl_ca_file - request.auth.ssl.cert = OpenSSL::X509::Certificate.new File.open("spec/fixtures/client_cert.pem").read - request.auth.ssl.cert_key = OpenSSL::PKey.read File.open("spec/fixtures/client_key.pem").read - - response = HTTPI.get(request, adapter) - expect(response.body).to eq("get") - end - end - end - -end diff --git a/spec/integration/excon_spec.rb b/spec/integration/excon_spec.rb index 31ad00b..5d3abc2 100644 --- a/spec/integration/excon_spec.rb +++ b/spec/integration/excon_spec.rb @@ -79,6 +79,21 @@ expect(response.body).to eq("basic-auth") end + it "does not support ntlm authentication" do + request = HTTPI::Request.new(@server.url + "ntlm-auth") + request.auth.ntlm("tester", "vReqSoafRe5O") + + expect { HTTPI.get(request, adapter) }. + to raise_error(HTTPI::NotSupportedError, /does not support NTLM authentication/) + end + + it "supports disabling verify mode" do + request = HTTPI::Request.new(@server.url) + request.auth.ssl.verify_mode = :none + adapter_class = HTTPI::Adapter.load(adapter).new(request) + expect(adapter_class.client.data[:ssl_verify_peer]).to eq(false) + end + it "supports chunked response" do request = HTTPI::Request.new(@server.url) res = "" @@ -113,6 +128,27 @@ response = HTTPI.get(request, adapter) expect(response.body).to eq("get") end + + it "works with client cert and key provided as file path" do + request = HTTPI::Request.new(@server.url) + request.auth.ssl.ca_cert_file = IntegrationServer.ssl_ca_file + request.auth.ssl.cert_file = "spec/fixtures/client_cert.pem" + request.auth.ssl.cert_key_file = "spec/fixtures/client_key.pem" + + response = HTTPI.get(request, adapter) + expect(response.body).to eq("get") + end + + it "works with client cert and key set directly" do + request = HTTPI::Request.new(@server.url) + + request.auth.ssl.ca_cert_file = IntegrationServer.ssl_ca_file + request.auth.ssl.cert = OpenSSL::X509::Certificate.new File.open("spec/fixtures/client_cert.pem").read + request.auth.ssl.cert_key = OpenSSL::PKey.read File.open("spec/fixtures/client_key.pem").read + + response = HTTPI.get(request, adapter) + expect(response.body).to eq("get") + end end end diff --git a/spec/integration/net_http_persistent_spec.rb b/spec/integration/net_http_persistent_spec.rb index cf4ff47..15f6a09 100644 --- a/spec/integration/net_http_persistent_spec.rb +++ b/spec/integration/net_http_persistent_spec.rb @@ -48,7 +48,7 @@ end it "executes POST requests" do - request = HTTPI::Request.new(url: @server.url, open_timeout: 1, read_timeout: 1, body: "xml") + request = HTTPI::Request.new(url: @server.url, body: "xml") response = HTTPI.post(request, adapter) expect(response.body).to eq("post") From bf0352c4370b5566d2b9725609d67e55cd46ded5 Mon Sep 17 00:00:00 2001 From: Alexey Chernenkov Date: Thu, 23 Aug 2018 21:16:44 +0500 Subject: [PATCH 16/19] Move http integration tests to the appropriate file --- spec/httpi/adapter/http_spec.rb | 101 -------------------------------- spec/integration/http_spec.rb | 16 +++++ 2 files changed, 16 insertions(+), 101 deletions(-) delete mode 100644 spec/httpi/adapter/http_spec.rb diff --git a/spec/httpi/adapter/http_spec.rb b/spec/httpi/adapter/http_spec.rb deleted file mode 100644 index 34b482d..0000000 --- a/spec/httpi/adapter/http_spec.rb +++ /dev/null @@ -1,101 +0,0 @@ -require "spec_helper" -require "integration/support/server" - -describe HTTPI::Adapter::HTTP do - - subject(:adapter) { :http } - - context "http requests" do - before :all do - @server = IntegrationServer.run - end - - after :all do - @server.stop - end - - it "sends and receives HTTP headers" do - request = HTTPI::Request.new(@server.url + "x-header") - request.headers["X-Header"] = "HTTPI" - - response = HTTPI.get(request, adapter) - expect(response.body).to include("HTTPI") - end - - it "executes GET requests" do - response = HTTPI.get(@server.url, adapter) - expect(response.body).to eq("get") - expect(response.headers["Content-Type"]).to eq("text/plain") - end - - it "executes POST requests" do - response = HTTPI.post(@server.url, "xml", adapter) - expect(response.body).to eq("post") - expect(response.headers["Content-Type"]).to eq("text/plain") - end - - it "executes HEAD requests" do - response = HTTPI.head(@server.url, adapter) - expect(response.code).to eq(200) - expect(response.headers["Content-Type"]).to eq("text/plain") - end - - it "executes PUT requests" do - response = HTTPI.put(@server.url, "xml", adapter) - expect(response.body).to eq("put") - expect(response.headers["Content-Type"]).to eq("text/plain") - end - - it "executes DELETE requests" do - response = HTTPI.delete(@server.url, adapter) - expect(response.body).to eq("delete") - expect(response.headers["Content-Type"]).to eq("text/plain") - end - - it "supports basic authentication" do - request = HTTPI::Request.new(@server.url + "basic-auth") - request.auth.basic("admin", "secret") - - response = HTTPI.get(request, adapter) - expect(response.body).to eq("basic-auth") - end - - it "does not support digest authentication" do - request = HTTPI::Request.new(@server.url + "digest-auth") - request.auth.digest("admin", "secret") - - expect { HTTPI.get(request, adapter) }. - to raise_error(HTTPI::NotSupportedError, /does not support HTTP digest authentication/) - end - - it "does not support ntlm authentication" do - request = HTTPI::Request.new(@server.url + "ntlm-auth") - request.auth.ntlm("tester", "vReqSoafRe5O") - - expect { HTTPI.get(request, adapter) }. - to raise_error(HTTPI::NotSupportedError, /does not support NTLM digest authentication/) - end - end - - if RUBY_PLATFORM =~ /java/ - pending "Puma Server complains: SSL not supported on JRuby" - else - context "https requests" do - before :all do - @server = IntegrationServer.run(:ssl => true) - end - after :all do - @server.stop - end - - it "works when set up properly" do - request = HTTPI::Request.new(@server.url) - request.auth.ssl.ca_cert_file = IntegrationServer.ssl_ca_file - - response = HTTPI.get(request, adapter) - expect(response.body).to eq("get") - end - end - end - -end diff --git a/spec/integration/http_spec.rb b/spec/integration/http_spec.rb index e65cd1a..7d1157b 100644 --- a/spec/integration/http_spec.rb +++ b/spec/integration/http_spec.rb @@ -80,6 +80,22 @@ expect(response.body).to eq("basic-auth") end + it "does not support digest authentication" do + request = HTTPI::Request.new(@server.url + "digest-auth") + request.auth.digest("admin", "secret") + + expect { HTTPI.get(request, adapter) }. + to raise_error(HTTPI::NotSupportedError, /does not support HTTP digest authentication/) + end + + it "does not support ntlm authentication" do + request = HTTPI::Request.new(@server.url + "ntlm-auth") + request.auth.ntlm("tester", "vReqSoafRe5O") + + expect { HTTPI.get(request, adapter) }. + to raise_error(HTTPI::NotSupportedError, /does not support NTLM digest authentication/) + end + it "supports chunked response" do skip("Needs investigation") request = HTTPI::Request.new(@server.url) From eb5f009e879b53fd83d11e192496b0712efb3ed0 Mon Sep 17 00:00:00 2001 From: Alexey Chernenkov Date: Thu, 23 Aug 2018 22:10:22 +0500 Subject: [PATCH 17/19] Move net_http_persistent integration tests to the appropriate file --- .../httpi/adapter/net_http_persistent_spec.rb | 96 ------------------- spec/integration/net_http_persistent_spec.rb | 8 ++ 2 files changed, 8 insertions(+), 96 deletions(-) delete mode 100644 spec/httpi/adapter/net_http_persistent_spec.rb diff --git a/spec/httpi/adapter/net_http_persistent_spec.rb b/spec/httpi/adapter/net_http_persistent_spec.rb deleted file mode 100644 index 8f02ec8..0000000 --- a/spec/httpi/adapter/net_http_persistent_spec.rb +++ /dev/null @@ -1,96 +0,0 @@ -require "spec_helper" -require "integration/support/server" - -describe HTTPI::Adapter::NetHTTPPersistent do - - subject(:adapter) { :net_http_persistent } - - context "http requests" do - before :all do - @server = IntegrationServer.run - end - - after :all do - @server.stop - end - - it "sends and receives HTTP headers" do - request = HTTPI::Request.new(@server.url + "x-header") - request.headers["X-Header"] = "HTTPI" - - response = HTTPI.get(request, adapter) - expect(response.body).to include("HTTPI") - end - - it "executes GET requests" do - response = HTTPI.get(@server.url, adapter) - expect(response.body).to eq("get") - expect(response.headers["Content-Type"]).to eq("text/plain") - end - - it "executes POST requests" do - response = HTTPI.post(@server.url, "xml", adapter) - expect(response.body).to eq("post") - expect(response.headers["Content-Type"]).to eq("text/plain") - end - - it "executes HEAD requests" do - response = HTTPI.head(@server.url, adapter) - expect(response.code).to eq(200) - expect(response.headers["Content-Type"]).to eq("text/plain") - end - - it "executes PUT requests" do - response = HTTPI.put(@server.url, "xml", adapter) - expect(response.body).to eq("put") - expect(response.headers["Content-Type"]).to eq("text/plain") - end - - it "executes DELETE requests" do - response = HTTPI.delete(@server.url, adapter) - expect(response.body).to eq("delete") - expect(response.headers["Content-Type"]).to eq("text/plain") - end - - it "supports basic authentication" do - request = HTTPI::Request.new(@server.url + "basic-auth") - request.auth.basic("admin", "secret") - - response = HTTPI.get(request, adapter) - expect(response.body).to eq("basic-auth") - end - - it "does not support ntlm authentication" do - request = HTTPI::Request.new(@server.url + "ntlm-auth") - request.auth.ntlm("tester", "vReqSoafRe5O") - - expect { HTTPI.get(request, adapter) }. - to raise_error(HTTPI::NotSupportedError, /does not support NTLM authentication/) - end - end - - # it does not support digest auth - - if RUBY_PLATFORM =~ /java/ - pending "Puma Server complains: SSL not supported on JRuby" - else - context "https requests" do - before :all do - @server = IntegrationServer.run(:ssl => true) - end - after :all do - @server.stop - end - - # it does not raise when no certificate was set up - it "works when set up properly" do - request = HTTPI::Request.new(@server.url) - request.auth.ssl.ca_cert_file = IntegrationServer.ssl_ca_file - - response = HTTPI.get(request, adapter) - expect(response.body).to eq("get") - end - end - end - -end diff --git a/spec/integration/net_http_persistent_spec.rb b/spec/integration/net_http_persistent_spec.rb index 15f6a09..c64b094 100644 --- a/spec/integration/net_http_persistent_spec.rb +++ b/spec/integration/net_http_persistent_spec.rb @@ -81,6 +81,14 @@ expect(response.body).to eq("basic-auth") end + it "does not support ntlm authentication" do + request = HTTPI::Request.new(@server.url + "ntlm-auth") + request.auth.ntlm("tester", "vReqSoafRe5O") + + expect { HTTPI.get(request, adapter) }. + to raise_error(HTTPI::NotSupportedError, /does not support NTLM authentication/) + end + # it does not support digest authentication it "supports chunked response" do From 885e373c75b6bc9cb65c291a25754a68c6f6b0a1 Mon Sep 17 00:00:00 2001 From: Alexey Chernenkov Date: Fri, 24 Aug 2018 10:09:04 +0500 Subject: [PATCH 18/19] Move net_http integration tests to the appropriate file --- spec/httpi/adapter/net_http_spec.rb | 198 ---------------------------- spec/integration/net_http_spec.rb | 107 ++++++++++++++- 2 files changed, 106 insertions(+), 199 deletions(-) delete mode 100644 spec/httpi/adapter/net_http_spec.rb diff --git a/spec/httpi/adapter/net_http_spec.rb b/spec/httpi/adapter/net_http_spec.rb deleted file mode 100644 index 51e94e2..0000000 --- a/spec/httpi/adapter/net_http_spec.rb +++ /dev/null @@ -1,198 +0,0 @@ -require "spec_helper" -require "integration/support/server" - -describe HTTPI::Adapter::NetHTTP do - - subject(:adapter) { :net_http } - - context "http requests" do - before :all do - @server = IntegrationServer.run - end - - after :all do - @server.stop - end - - context 'when socks is specified' do - - let(:socks_client) { mock('socks_client') } - let(:request){HTTPI::Request.new(@server.url)} - - it 'uses Net::HTTP.SOCKSProxy as client' do - socks_client.expects(:new).with(URI(@server.url).host, URI(@server.url).port).returns(:socks_client_instance) - Net::HTTP.expects(:SOCKSProxy).with('localhost', 8080).returns socks_client - - request.proxy = 'socks://localhost:8080' - adapter = HTTPI::Adapter::NetHTTP.new(request) - - expect(adapter.client).to eq(:socks_client_instance) - end - end - - it "sends and receives HTTP headers" do - request = HTTPI::Request.new(@server.url + "x-header") - request.headers["X-Header"] = "HTTPI" - - response = HTTPI.get(request, adapter) - expect(response.body).to include("HTTPI") - end - - it "executes GET requests" do - response = HTTPI.get(@server.url, adapter) - expect(response.body).to eq("get") - expect(response.headers["Content-Type"]).to eq("text/plain") - end - - it "executes POST requests" do - response = HTTPI.post(@server.url, "xml", adapter) - expect(response.body).to eq("post") - expect(response.headers["Content-Type"]).to eq("text/plain") - end - - it "executes HEAD requests" do - response = HTTPI.head(@server.url, adapter) - expect(response.code).to eq(200) - expect(response.headers["Content-Type"]).to eq("text/plain") - end - - it "executes PUT requests" do - response = HTTPI.put(@server.url, "xml", adapter) - expect(response.body).to eq("put") - expect(response.headers["Content-Type"]).to eq("text/plain") - end - - it "executes DELETE requests" do - response = HTTPI.delete(@server.url, adapter) - expect(response.body).to eq("delete") - expect(response.headers["Content-Type"]).to eq("text/plain") - end - - context "supports custom methods supported by Net::HTTP" do - let(:request) do - HTTPI::Request.new(@server.url).tap do|r| - r.body = request_body if request_body - end - end - - let(:request_body) { nil } - - let(:response) { HTTPI.request(http_method, request, adapter) } - - shared_examples_for 'any supported custom method' do - specify { response.body.should eq http_method.to_s } - specify { response.headers["Content-Type"].should eq('text/plain') } - end - - context 'PATCH' do - let(:http_method) { :patch } - let(:request_body) { "xml" } - - it_behaves_like 'any supported custom method' - end - - context 'UNSUPPORTED method' do - let(:http_method) { :unsupported } - - specify { expect { response }.to raise_error HTTPI::NotSupportedError } - end - end - - it "supports basic authentication" do - request = HTTPI::Request.new(@server.url + "basic-auth") - request.auth.basic("admin", "secret") - - response = HTTPI.get(request, adapter) - expect(response.body).to eq("basic-auth") - end - - it "does not support digest authentication" do - request = HTTPI::Request.new(@server.url + "digest-auth") - request.auth.digest("admin", "secret") - - expect { HTTPI.get(request, adapter) }. - to raise_error(HTTPI::NotSupportedError, /does not support HTTP digest authentication/) - end - - it "supports ntlm authentication" do - request = HTTPI::Request.new(@server.url + "ntlm-auth") - request.auth.ntlm("tester", "vReqSoafRe5O") - - response = HTTPI.get(request, adapter) - expect(response.body).to eq("ntlm-auth") - end - - it 'does not support ntlm authentication when Net::NTLM is not available' do - Net.expects(:const_defined?).with(:NTLM).returns false - - request = HTTPI::Request.new(@server.url + 'ntlm-auth') - request.auth.ntlm("testing", "failures") - - expect { HTTPI.get(request, adapter) }. - to raise_error(HTTPI::NotSupportedError, /Net::NTLM is not available/) - end - - it 'does not require ntlm when ntlm authenication is not requested' do - HTTPI::Adapter::NetHTTP.any_instance.stubs(:check_net_ntlm_version!).raises(RuntimeError) - request = HTTPI::Request.new(@server.url) - expect(request.auth.ntlm?).to be false - - # make sure a request doesn't call ntlm check if we don't ask for it. - expect { HTTPI.get(request, adapter) }.not_to raise_error - HTTPI::Adapter::NetHTTP.any_instance.unstub(:check_net_ntlm_version!) - end - - it 'does check ntlm when ntlm authentication is requested' do - request = HTTPI::Request.new(@server.url + "ntlm-auth") - request.auth.ntlm("tester", "vReqSoafRe5O") - - expect { HTTPI.get(request, adapter) }.not_to raise_error - - # the check should also verify that the version of ntlm is supported and still fail if it isn't - HTTPI::Adapter::NetHTTP.any_instance.stubs(:ntlm_version).returns("0.1.1") - - request = HTTPI::Request.new(@server.url + "ntlm-auth") - request.auth.ntlm("tester", "vReqSoafRe5O") - - expect { HTTPI.get(request, adapter) }.to raise_error(ArgumentError, /Invalid version/) - - HTTPI::Adapter::NetHTTP.any_instance.unstub(:ntlm_version) - end - - it "does not crash when authenticate header is missing (on second request)" do - request = HTTPI::Request.new(@server.url + 'ntlm-auth') - request.auth.ntlm("tester", "vReqSoafRe5O") - - expect { HTTPI.get(request, adapter) }. - to_not raise_error - - expect { HTTPI.get(request, adapter) }. - to_not raise_error - end - end - - # it does not support digest auth - - if RUBY_PLATFORM =~ /java/ - pending "Puma Server complains: SSL not supported on JRuby" - else - context "https requests" do - before :all do - @server = IntegrationServer.run(:ssl => true) - end - after :all do - @server.stop - end - - # it does not raise when no certificate was set up - it "works when set up properly" do - request = HTTPI::Request.new(@server.url) - request.auth.ssl.ca_cert_file = IntegrationServer.ssl_ca_file - - response = HTTPI.get(request, adapter) - expect(response.body).to eq("get") - end - end - end - -end diff --git a/spec/integration/net_http_spec.rb b/spec/integration/net_http_spec.rb index ee722d4..b98844d 100644 --- a/spec/integration/net_http_spec.rb +++ b/spec/integration/net_http_spec.rb @@ -14,6 +14,21 @@ @server.stop end + context "when socks is specified" do + let(:socks_client) { mock("socks_client") } + let(:request) { HTTPI::Request.new(@server.url) } + + it "uses Net::HTTP.SOCKSProxy as client" do + socks_client.expects(:new).with(URI(@server.url).host, URI(@server.url).port).returns(:socks_client_instance) + Net::HTTP.expects(:SOCKSProxy).with("localhost", 8080).returns socks_client + + request.proxy = "socks://localhost:8080" + adapter = HTTPI::Adapter::NetHTTP.new(request) + + expect(adapter.client).to eq(:socks_client_instance) + end + end + it "sends and receives HTTP headers" do request = HTTPI::Request.new(@server.url + "x-header") request.headers["X-Header"] = "HTTPI" @@ -69,6 +84,34 @@ expect(response.headers["Content-Type"]).to eq("text/plain") end + context "custom methods" do + let(:request) { + HTTPI::Request.new(@server.url).tap do |r| + r.body = request_body if request_body + end + } + let(:request_body) { nil } + let(:response) { HTTPI.request(http_method, request, adapter) } + + shared_examples_for "any supported custom method" do + specify { response.body.should eq http_method.to_s } + specify { response.headers["Content-Type"].should eq("text/plain") } + end + + context "PATCH method" do + let(:http_method) { :patch } + let(:request_body) { "xml" } + + it_behaves_like "any supported custom method" + end + + context "UNSUPPORTED method" do + let(:http_method) { :unsupported } + + specify { expect { response }.to raise_error HTTPI::NotSupportedError } + end + end + it "supports basic authentication" do request = HTTPI::Request.new(@server.url + "basic-auth") request.auth.basic("admin", "secret") @@ -77,7 +120,69 @@ expect(response.body).to eq("basic-auth") end - # it does not support digest authentication + it "does not support digest authentication" do + request = HTTPI::Request.new(@server.url + "digest-auth") + request.auth.digest("admin", "secret") + + expect { HTTPI.get(request, adapter) }. + to raise_error(HTTPI::NotSupportedError, /does not support HTTP digest authentication/) + end + + it "supports ntlm authentication" do + request = HTTPI::Request.new(@server.url + "ntlm-auth") + request.auth.ntlm("tester", "vReqSoafRe5O") + + response = HTTPI.get(request, adapter) + expect(response.body).to eq("ntlm-auth") + end + + it "does not support ntlm authentication when Net::NTLM is not available" do + Net.expects(:const_defined?).with(:NTLM).returns false + + request = HTTPI::Request.new(@server.url + "ntlm-auth") + request.auth.ntlm("testing", "failures") + + expect { HTTPI.get(request, adapter) }. + to raise_error(HTTPI::NotSupportedError, /Net::NTLM is not available/) + end + + it "does not require ntlm when ntlm authenication is not requested" do + HTTPI::Adapter::NetHTTP.any_instance.stubs(:check_net_ntlm_version!).raises(RuntimeError) + request = HTTPI::Request.new(@server.url) + expect(request.auth.ntlm?).to be false + + # make sure a request doesn't call ntlm check if we don't ask for it. + expect { HTTPI.get(request, adapter) }.not_to raise_error + HTTPI::Adapter::NetHTTP.any_instance.unstub(:check_net_ntlm_version!) + end + + it "does check ntlm when ntlm authentication is requested" do + request = HTTPI::Request.new(@server.url + "ntlm-auth") + request.auth.ntlm("tester", "vReqSoafRe5O") + + expect { HTTPI.get(request, adapter) }.not_to raise_error + + # the check should also verify that the version of ntlm is supported and still fail if it isn't + HTTPI::Adapter::NetHTTP.any_instance.stubs(:ntlm_version).returns("0.1.1") + + request = HTTPI::Request.new(@server.url + "ntlm-auth") + request.auth.ntlm("tester", "vReqSoafRe5O") + + expect { HTTPI.get(request, adapter) }.to raise_error(ArgumentError, /Invalid version/) + + HTTPI::Adapter::NetHTTP.any_instance.unstub(:ntlm_version) + end + + it "does not crash when authenticate header is missing (on second request)" do + request = HTTPI::Request.new(@server.url + "ntlm-auth") + request.auth.ntlm("tester", "vReqSoafRe5O") + + expect { HTTPI.get(request, adapter) }. + to_not raise_error + + expect { HTTPI.get(request, adapter) }. + to_not raise_error + end it "supports chunked response" do request = HTTPI::Request.new(@server.url) From 5d83dc92224528eda1155bd868d4a49582a30e68 Mon Sep 17 00:00:00 2001 From: Alexey Chernenkov Date: Fri, 24 Aug 2018 11:15:06 +0500 Subject: [PATCH 19/19] Add tests for different timeout options to all adapters --- lib/httpi/adapter/net_http.rb | 4 +- spec/httpi/adapter/curb_spec.rb | 9 +++- spec/httpi/adapter/em_http_spec.rb | 13 ++++- spec/httpi/adapter/excon_spec.rb | 28 ++++++++++ spec/httpi/adapter/http_spec.rb | 28 ++++++++++ spec/httpi/adapter/httpclient_spec.rb | 14 +++++ .../httpi/adapter/net_http_persistent_spec.rb | 46 ++++++++++++++++ spec/httpi/adapter/net_http_spec.rb | 54 +++++++++++++++++++ spec/integration/net_http_spec.rb | 2 + 9 files changed, 194 insertions(+), 4 deletions(-) create mode 100644 spec/httpi/adapter/excon_spec.rb create mode 100644 spec/httpi/adapter/http_spec.rb create mode 100644 spec/httpi/adapter/net_http_persistent_spec.rb create mode 100644 spec/httpi/adapter/net_http_spec.rb diff --git a/lib/httpi/adapter/net_http.rb b/lib/httpi/adapter/net_http.rb index c31d0d5..8376cd1 100644 --- a/lib/httpi/adapter/net_http.rb +++ b/lib/httpi/adapter/net_http.rb @@ -156,10 +156,10 @@ def setup_client @client.open_timeout = @request.open_timeout if @request.open_timeout @client.read_timeout = @request.read_timeout if @request.read_timeout if @request.write_timeout - if @client.respond_to?(:write_timeout=) # Since Ruby 2.6 + if @client.respond_to?(:write_timeout=) # Expected to appear in Ruby 2.6 @client.write_timeout = @request.write_timeout else - raise NotSupportedError, "Net::HTTP supports write_timeout since Ruby 2.6" + raise NotSupportedError, "Net::HTTP supports write_timeout starting from Ruby 2.6" end end end diff --git a/spec/httpi/adapter/curb_spec.rb b/spec/httpi/adapter/curb_spec.rb index 2c670e7..ec931b7 100644 --- a/spec/httpi/adapter/curb_spec.rb +++ b/spec/httpi/adapter/curb_spec.rb @@ -152,12 +152,19 @@ adapter.request(:get) end - it "is set if specified" do + it "is set if specified read_timeout" do request.read_timeout = 30 curb.expects(:timeout_ms=).with(30_000) adapter.request(:get) end + + it "is set if specified write_timeout" do + request.write_timeout = 30 + curb.expects(:timeout_ms=).with(30_000) + + adapter.request(:get) + end end describe "connect_timeout_ms" do diff --git a/spec/httpi/adapter/em_http_spec.rb b/spec/httpi/adapter/em_http_spec.rb index 4b82452..e0a6eda 100644 --- a/spec/httpi/adapter/em_http_spec.rb +++ b/spec/httpi/adapter/em_http_spec.rb @@ -118,7 +118,7 @@ end describe "receive_timeout" do - it "is passed as a connection option" do + it "is passed as a connection option (when read_timeout specified)" do request.read_timeout = 60 url = "http://example.com:80" @@ -128,6 +128,17 @@ adapter end + + it "is passed as a connection option (when write_timeout specified)" do + request.write_timeout = 60 + + url = "http://example.com:80" + connection_options = { inactivity_timeout: 60 } + + EventMachine::HttpRequest.expects(:new).with(url, connection_options) + + adapter + end end describe "set_auth" do diff --git a/spec/httpi/adapter/excon_spec.rb b/spec/httpi/adapter/excon_spec.rb new file mode 100644 index 0000000..e26ab32 --- /dev/null +++ b/spec/httpi/adapter/excon_spec.rb @@ -0,0 +1,28 @@ +require "spec_helper" +require "httpi/adapter/excon" +require "httpi/request" + +begin + HTTPI::Adapter.load_adapter(:excon) + + describe HTTPI::Adapter::Excon do + let(:adapter) { HTTPI::Adapter::Excon.new(request) } + let(:request) { HTTPI::Request.new("http://example.com") } + + describe "settings" do + describe "connect_timeout, read_timeout, write_timeout" do + it "are passed as connection options" do + request.open_timeout = 30 + request.read_timeout = 40 + request.write_timeout = 50 + + expect(adapter.client.data).to include( + connect_timeout: 30, + read_timeout: 40, + write_timeout: 50 + ) + end + end + end + end +end diff --git a/spec/httpi/adapter/http_spec.rb b/spec/httpi/adapter/http_spec.rb new file mode 100644 index 0000000..aa3e842 --- /dev/null +++ b/spec/httpi/adapter/http_spec.rb @@ -0,0 +1,28 @@ +require "spec_helper" +require "httpi/adapter/http" +require "httpi/request" + +begin + HTTPI::Adapter.load_adapter(:http) + + describe HTTPI::Adapter::HTTP do + let(:adapter) { HTTPI::Adapter::HTTP.new(request) } + let(:request) { HTTPI::Request.new("http://example.com") } + + describe "settings" do + describe "connect_timeout, read_timeout, write_timeout" do + it "are being set on the client" do + request.open_timeout = 30 + request.read_timeout = 40 + request.write_timeout = 50 + + expect(adapter.client.default_options.timeout_options).to eq( + connect_timeout: 30, + read_timeout: 40, + write_timeout: 50 + ) + end + end + end + end +end diff --git a/spec/httpi/adapter/httpclient_spec.rb b/spec/httpi/adapter/httpclient_spec.rb index 41ca299..e6371a3 100644 --- a/spec/httpi/adapter/httpclient_spec.rb +++ b/spec/httpi/adapter/httpclient_spec.rb @@ -100,6 +100,20 @@ end end + describe "send_timeout" do + it "is not set unless specified" do + httpclient.expects(:send_timeout=).never + adapter.request(:get) + end + + it "is set if specified" do + request.write_timeout = 30 + + httpclient.expects(:send_timeout=).with(30) + adapter.request(:get) + end + end + describe "set_auth" do it "is set for HTTP basic auth" do request.auth.basic "username", "password" diff --git a/spec/httpi/adapter/net_http_persistent_spec.rb b/spec/httpi/adapter/net_http_persistent_spec.rb new file mode 100644 index 0000000..9ed7a5f --- /dev/null +++ b/spec/httpi/adapter/net_http_persistent_spec.rb @@ -0,0 +1,46 @@ +require "spec_helper" +require "httpi/adapter/net_http_persistent" +require "httpi/request" + +begin + HTTPI::Adapter.load_adapter(:net_http_persistent) + + describe HTTPI::Adapter::NetHTTPPersistent do + let(:adapter) { HTTPI::Adapter::NetHTTPPersistent.new(request) } + let(:request) { HTTPI::Request.new("http://example.com") } + + let(:response) { + Object.new.tap do |r| + r.stubs(:code).returns(200) + r.stubs(:body).returns("abc") + r.stubs(:to_hash).returns({"Content-Length" => "3"}) + end + } + + before do + Net::HTTP::Persistent.any_instance.stubs(:start).returns(response) + end + + describe "settings" do + describe "open_timeout, read_timeout" do + it "are being set on the client" do + request.open_timeout = 30 + request.read_timeout = 40 + + adapter.client.expects(:open_timeout=).with(30) + adapter.client.expects(:read_timeout=).with(40) + + adapter.request(:get) + end + end + + describe "write_timeout" do + it "is not supported" do + request.write_timeout = 50 + expect { adapter.request(:get) } + .to raise_error(HTTPI::NotSupportedError, /write_timeout/) + end + end + end + end +end diff --git a/spec/httpi/adapter/net_http_spec.rb b/spec/httpi/adapter/net_http_spec.rb new file mode 100644 index 0000000..346b569 --- /dev/null +++ b/spec/httpi/adapter/net_http_spec.rb @@ -0,0 +1,54 @@ +require "spec_helper" +require "httpi/adapter/net_http" +require "httpi/request" + +begin + HTTPI::Adapter.load_adapter(:net_http) + + describe HTTPI::Adapter::NetHTTP do + let(:adapter) { HTTPI::Adapter::NetHTTP.new(request) } + let(:request) { HTTPI::Request.new("http://example.com") } + + let(:response) { + Object.new.tap do |r| + r.stubs(:code).returns(200) + r.stubs(:body).returns("abc") + r.stubs(:to_hash).returns({"Content-Length" => "3"}) + end + } + + before do + Net::HTTP.any_instance.stubs(:start).returns(response) + end + + describe "settings" do + describe "open_timeout, read_timeout" do + it "are being set on the client" do + request.open_timeout = 30 + request.read_timeout = 40 + + adapter.client.expects(:open_timeout=).with(30) + adapter.client.expects(:read_timeout=).with(40) + + adapter.request(:get) + end + end + + describe "write_timeout" do + if Net::HTTP.method_defined?(:write_timeout=) + it "is being set on the client" do + request.write_timeout = 50 + adapter.client.expects(:write_timeout=).with(50) + adapter.request(:get) + end + else + it "can not be set on the client" do + request.write_timeout = 50 + expect { adapter.request(:get) } + .to raise_error(HTTPI::NotSupportedError, /write_timeout/) + end + end + end + end + end +end diff --git a/spec/integration/net_http_spec.rb b/spec/integration/net_http_spec.rb index b98844d..9b34fe8 100644 --- a/spec/integration/net_http_spec.rb +++ b/spec/integration/net_http_spec.rb @@ -46,6 +46,8 @@ end it "it supports read timeout" do + require "net/http" + request = HTTPI::Request.new(@server.url + "timeout") request.read_timeout = 0.5 # seconds