From f2dcb6c2de8323e6a4f5ffddc4af2d8533514550 Mon Sep 17 00:00:00 2001 From: cequele Date: Mon, 3 Mar 2025 16:26:43 +0100 Subject: [PATCH 1/6] Add proxy option to Twingly HTTP Client In case we are being blocked by a domain we need to be able to use a proxy. --- lib/twingly/http.rb | 4 +++- spec/lib/twingly/http_spec.rb | 34 ++++++++++++++++++++++++++++++++++ 2 files changed, 37 insertions(+), 1 deletion(-) diff --git a/lib/twingly/http.rb b/lib/twingly/http.rb index ec1ec29..ccad95d 100644 --- a/lib/twingly/http.rb +++ b/lib/twingly/http.rb @@ -50,10 +50,11 @@ class Client # rubocop:disable Metrics/ClassLength attr_accessor :logger attr_accessor :retryable_exceptions - def initialize(base_user_agent:, logger: default_logger, user_agent: nil) + def initialize(base_user_agent:, logger: default_logger, user_agent: nil, proxy: nil) @base_user_agent = base_user_agent @logger = logger @user_agent = user_agent + @proxy = proxy initialize_defaults end @@ -212,6 +213,7 @@ def create_http_client # rubocop:disable Metrics/MethodLength max_size_bytes: @max_response_body_size_bytes faraday.adapter Faraday.default_adapter faraday.headers[:user_agent] = user_agent + faraday.proxy = @proxy if @proxy end end diff --git a/spec/lib/twingly/http_spec.rb b/spec/lib/twingly/http_spec.rb index 9937192..af96973 100644 --- a/spec/lib/twingly/http_spec.rb +++ b/spec/lib/twingly/http_spec.rb @@ -688,6 +688,40 @@ class CustomError < StandardError; end end end end + + fdescribe "proxy" do + let(:test_url) { "http://example.com" } + + context "when a proxy is set" do + let(:proxy_url) { "http://localhost:1080" } + let(:proxy_client) do + described_class.new( + base_user_agent: base_user_agent, + logger: logger, + user_agent: user_agent, + proxy: proxy_url + ) + end + + before(:all) do + let(:toxiproxy) { Toxiproxy.new(host: "localhost", port: 8474) } + let(:proxy) { toxiproxy.create("proxy", listen: "localhost:1080", upstream: "https://example.com") } + end + + after(:all) do + proxy.delete + toxiproxy.close + end + + it "sets the proxy URL correctly in the Twingly HTTP client" do + allow(proxy_client).to receive(proxy).and_return(proxy_url) + response = proxy_client.get("https://example.com") + + expect(proxy_client.proxy).to eq(proxy_url) + expect(response.status).to eq(200) + end + end + end end describe "#put", vcr: Fixture.put_httpbin_org do From 969325c8c8a6734992e31fffe6d0a68ccfe59ec7 Mon Sep 17 00:00:00 2001 From: cequele Date: Fri, 7 Mar 2025 16:41:43 +0100 Subject: [PATCH 2/6] Add unit test for proxy Make sure that the proxy is configured properly when added to client. --- spec/lib/twingly/http_spec.rb | 26 ++++++-------------------- 1 file changed, 6 insertions(+), 20 deletions(-) diff --git a/spec/lib/twingly/http_spec.rb b/spec/lib/twingly/http_spec.rb index af96973..d830638 100644 --- a/spec/lib/twingly/http_spec.rb +++ b/spec/lib/twingly/http_spec.rb @@ -689,11 +689,9 @@ class CustomError < StandardError; end end end - fdescribe "proxy" do - let(:test_url) { "http://example.com" } - - context "when a proxy is set" do - let(:proxy_url) { "http://localhost:1080" } + describe "proxy" do + context "when a proxy is provided" do + let(:proxy_url) { "http://127.0.0.1:8080" } let(:proxy_client) do described_class.new( base_user_agent: base_user_agent, @@ -703,22 +701,10 @@ class CustomError < StandardError; end ) end - before(:all) do - let(:toxiproxy) { Toxiproxy.new(host: "localhost", port: 8474) } - let(:proxy) { toxiproxy.create("proxy", listen: "localhost:1080", upstream: "https://example.com") } - end - - after(:all) do - proxy.delete - toxiproxy.close - end - - it "sets the proxy URL correctly in the Twingly HTTP client" do - allow(proxy_client).to receive(proxy).and_return(proxy_url) - response = proxy_client.get("https://example.com") + it "sets the proxy" do + connection = proxy_client.send(:create_http_client) - expect(proxy_client.proxy).to eq(proxy_url) - expect(response.status).to eq(200) + expect(connection.proxy.uri.to_s).to eq(proxy_url) end end end From 177316c271e73159b77d10fc86f651af84e84ad0 Mon Sep 17 00:00:00 2001 From: cequele Date: Mon, 10 Mar 2025 17:08:21 +0100 Subject: [PATCH 3/6] Add proxy server for testing Add a proxy server and a target server to enable tests for ensuring requests are routed trough proxy --- Gemfile | 4 ++ spec/lib/twingly/http_spec.rb | 44 +++++++++++++++++++++ spec/rack_servers/echoed_headers_in_body.ru | 9 +++++ spec/rack_servers/proxy_server.ru | 12 ++++++ spec/spec_help/http_test_server.rb | 44 +++++++++++++++++++++ spec/spec_help/port_prober.rb | 37 +++++++++++++++++ spec/spec_helper.rb | 2 + 7 files changed, 152 insertions(+) create mode 100644 spec/rack_servers/echoed_headers_in_body.ru create mode 100644 spec/rack_servers/proxy_server.ru create mode 100644 spec/spec_help/http_test_server.rb create mode 100644 spec/spec_help/port_prober.rb diff --git a/Gemfile b/Gemfile index 63ac0c7..0036857 100644 --- a/Gemfile +++ b/Gemfile @@ -6,6 +6,9 @@ gemspec group :development, :test do gem "climate_control", "~> 0.1" + gem "rack", "~> 3.1" + gem "rack-proxy", "~> 0.7.7" + gem "rackup", "~> 2.2" gem "rake", "~> 12" gem "rspec", "~> 3" gem "rubocop", "~> 1.64.1" @@ -13,4 +16,5 @@ group :development, :test do gem "toxiproxy", "~> 1.0" gem "vcr", "~> 5.0" gem "webmock", "~> 3.7" + gem "webrick", "~> 1.9" end diff --git a/spec/lib/twingly/http_spec.rb b/spec/lib/twingly/http_spec.rb index d830638..81ecf3d 100644 --- a/spec/lib/twingly/http_spec.rb +++ b/spec/lib/twingly/http_spec.rb @@ -1,5 +1,7 @@ # frozen_string_literal: true +require_relative "../../spec_help/http_test_server" + class CustomError < StandardError; end # rubocop:disable RSpec/MultipleMemoizedHelpers @@ -707,6 +709,48 @@ class CustomError < StandardError; end expect(connection.proxy.uri.to_s).to eq(proxy_url) end end + + context "when using a real proxy server" do + let(:proxy_pid_and_url) do + HttpTestServer.spawn("proxy_server") + end + let(:proxy_pid) { proxy_pid_and_url[0] } + let(:proxy_url) { proxy_pid_and_url[1] } + + let(:target_pid_and_url) do + HttpTestServer.spawn("echoed_headers_in_body") + end + let(:target_pid) { target_pid_and_url[0] } + let(:target_url) { target_pid_and_url[1] } + + let(:client) do + described_class.new( + base_user_agent: "Test Agent", + proxy: proxy_url + ) + end + + after do + HttpTestServer.stop(proxy_pid) + HttpTestServer.stop(target_pid) + end + + it "routes requests through the proxy", vcr: false do # rubocop:disable RSpec/ExampleLength + VCR.eject_cassette if VCR.current_cassette + VCR.turn_off! + + begin + WebMock.allow_net_connect! + + response = client.get(target_url) + + expect(response.body).to include("HTTP_X_PROXIED_BY") + ensure + VCR.turn_on! + WebMock.disable_net_connect! + end + end + end end end diff --git a/spec/rack_servers/echoed_headers_in_body.ru b/spec/rack_servers/echoed_headers_in_body.ru new file mode 100644 index 0000000..1d76b59 --- /dev/null +++ b/spec/rack_servers/echoed_headers_in_body.ru @@ -0,0 +1,9 @@ +# frozen_string_literal: true + +require "json" + +run lambda { |env| + request_headers = env.select { |k, _v| k.start_with? "HTTP_" } + + [200, { "content-type" => "application/json" }, [request_headers.to_json]] +} diff --git a/spec/rack_servers/proxy_server.ru b/spec/rack_servers/proxy_server.ru new file mode 100644 index 0000000..35c6277 --- /dev/null +++ b/spec/rack_servers/proxy_server.ru @@ -0,0 +1,12 @@ +# frozen_string_literal: true + +require "rack/proxy" + +class TestProxy < Rack::Proxy + def rewrite_env(env) + env["HTTP_X_PROXIED_BY"] = "test-proxy" + env + end +end + +run TestProxy.new diff --git a/spec/spec_help/http_test_server.rb b/spec/spec_help/http_test_server.rb new file mode 100644 index 0000000..3d1edcd --- /dev/null +++ b/spec/spec_help/http_test_server.rb @@ -0,0 +1,44 @@ +# frozen_string_literal: true + +require "timeout" + +module HttpTestServer + module_function + + def spawn_server_with_echoed_headers_in_body + spawn("echoed_headers_in_body") + end + + def spawn(server_name, env: {}) # rubocop:disable Metrics/MethodLength + ip_address = PortProber.localhost + port = PortProber.random(ip_address) + url = "http://#{ip_address}:#{port}" + server = "spec/rack_servers/#{server_name}.ru" + command = "bundle exec rackup --quiet --port #{port} #{server}" + + puts "starting HTTP test server: #{command}" + pid = fork do + $stdout.reopen File::NULL + $stderr.reopen File::NULL + exec env, command + end + + Timeout.timeout(10.0) do + sleep 0.05 until started?(pid) && PortProber.port_open?(ip_address, port) + end + + [pid, url] + end + + def stop(pid) + Process.kill(:TERM, pid) + Process.wait(pid) + end + + def started?(pid) + Process.getpgid(pid) + true + rescue Errno::ESRCH + false + end +end diff --git a/spec/spec_help/port_prober.rb b/spec/spec_help/port_prober.rb new file mode 100644 index 0000000..d11a16f --- /dev/null +++ b/spec/spec_help/port_prober.rb @@ -0,0 +1,37 @@ +# frozen_string_literal: true + +require "socket" +require "timeout" + +module PortProber + module_function + + def random(host) + server = TCPServer.new(host, 0) + port = server.addr[1] + + port + ensure + server&.close + end + + def port_open?(ip_address, port) + Timeout.timeout(0.5) do + TCPSocket.new(ip_address, port).close + true + end + rescue StandardError + false + end + + def localhost + info = Socket.getaddrinfo("localhost", + 80, + Socket::AF_INET, + Socket::SOCK_STREAM) + + raise "unable to translate 'localhost' for TCP + IPv4" if info.empty? + + info[0][3] + end +end diff --git a/spec/spec_helper.rb b/spec/spec_helper.rb index 01eb8ce..315fef5 100644 --- a/spec/spec_helper.rb +++ b/spec/spec_helper.rb @@ -16,6 +16,8 @@ require_relative "spec_help/fixture" require_relative "spec_help/test_logger" require_relative "spec_help/toxiproxy_config" +require_relative "spec_help/http_test_server" +require_relative "spec_help/port_prober" # Start with a clean slate, destroy all proxies if any Toxiproxy.all.destroy From 090ff670aada7cd4092e3b7cda86fc8cdb678dfc Mon Sep 17 00:00:00 2001 From: cequele Date: Tue, 11 Mar 2025 10:43:32 +0100 Subject: [PATCH 4/6] Add shared examples for proxy configuration tests Implement shared examples for proxy configuration and routing --- spec/lib/twingly/http_spec.rb | 129 ++++++++++++++++++---------------- spec/spec_helper.rb | 16 +++++ 2 files changed, 83 insertions(+), 62 deletions(-) diff --git a/spec/lib/twingly/http_spec.rb b/spec/lib/twingly/http_spec.rb index 81ecf3d..b0d2643 100644 --- a/spec/lib/twingly/http_spec.rb +++ b/spec/lib/twingly/http_spec.rb @@ -535,6 +535,66 @@ class CustomError < StandardError; end end end + RSpec.shared_examples "verifies proxy functionality" do |http_method| + context "when a proxy is provided" do + let(:proxy_pid_and_url) { HttpTestServer.spawn("proxy_server") } + let(:proxy_pid) { proxy_pid_and_url[0] } + let(:proxy_url) { proxy_pid_and_url[1] } + + let(:target_pid_and_url) { HttpTestServer.spawn("echoed_headers_in_body") } + let(:target_pid) { target_pid_and_url[0] } + let(:target_url) { target_pid_and_url[1] } + + let(:client) do + described_class.new( + base_user_agent: "Test Agent", + proxy: proxy_url + ) + end + + after do + HttpTestServer.stop(proxy_pid) + HttpTestServer.stop(target_pid) + end + + it "routes requests through the proxy", vcr: false do # rubocop:disable RSpec/ExampleLength + with_real_http_connections do + response = case http_method + when :get + client.get(target_url) + when :post + client.post(target_url, body: "test") + when :put + client.put(target_url, body: "test") + when :patch + client.patch(target_url, body: "test") + when :delete + client.delete(target_url) + end + + expect(response.body).to include("HTTP_X_PROXIED_BY") + end + end + end + end + + RSpec.shared_examples "configures proxy correctly" do + context "when a proxy is provided" do + let(:proxy_url) { "http://127.0.0.1:8080" } + let(:proxy_client) do + described_class.new( + base_user_agent: base_user_agent, + proxy: proxy_url + ) + end + + it "sets the proxy" do + connection = proxy_client.send(:create_http_client) + expect(connection.proxy.uri.to_s).to eq(proxy_url) + end + end + end + describe "#initialize" do context "when no logger is given" do subject(:default_logger) do @@ -554,6 +614,8 @@ class CustomError < StandardError; end describe "#post", vcr: Fixture.post_example_org do include_examples "common HTTP behaviour for", :post, "example.org" + include_examples "verifies proxy functionality", :post + include_examples "configures proxy correctly", :post let(:post_body) { nil } let(:post_headers) { {} } @@ -602,6 +664,8 @@ class CustomError < StandardError; end describe "#get", vcr: Fixture.example_org do include_examples "common HTTP behaviour for", :get, "example.org" + include_examples "verifies proxy functionality", :get + include_examples "configures proxy correctly", :get let(:request_response) do client.get(url) @@ -690,72 +754,11 @@ class CustomError < StandardError; end end end end - - describe "proxy" do - context "when a proxy is provided" do - let(:proxy_url) { "http://127.0.0.1:8080" } - let(:proxy_client) do - described_class.new( - base_user_agent: base_user_agent, - logger: logger, - user_agent: user_agent, - proxy: proxy_url - ) - end - - it "sets the proxy" do - connection = proxy_client.send(:create_http_client) - - expect(connection.proxy.uri.to_s).to eq(proxy_url) - end - end - - context "when using a real proxy server" do - let(:proxy_pid_and_url) do - HttpTestServer.spawn("proxy_server") - end - let(:proxy_pid) { proxy_pid_and_url[0] } - let(:proxy_url) { proxy_pid_and_url[1] } - - let(:target_pid_and_url) do - HttpTestServer.spawn("echoed_headers_in_body") - end - let(:target_pid) { target_pid_and_url[0] } - let(:target_url) { target_pid_and_url[1] } - - let(:client) do - described_class.new( - base_user_agent: "Test Agent", - proxy: proxy_url - ) - end - - after do - HttpTestServer.stop(proxy_pid) - HttpTestServer.stop(target_pid) - end - - it "routes requests through the proxy", vcr: false do # rubocop:disable RSpec/ExampleLength - VCR.eject_cassette if VCR.current_cassette - VCR.turn_off! - - begin - WebMock.allow_net_connect! - - response = client.get(target_url) - - expect(response.body).to include("HTTP_X_PROXIED_BY") - ensure - VCR.turn_on! - WebMock.disable_net_connect! - end - end - end - end end describe "#put", vcr: Fixture.put_httpbin_org do include_examples "common HTTP behaviour for", :put, "https://httpbin.org/put" + include_examples "configures proxy correctly", :put let(:url) { "https://httpbin.org/put" } @@ -806,6 +809,7 @@ class CustomError < StandardError; end describe "#patch", vcr: Fixture.patch_httpbin_org do include_examples "common HTTP behaviour for", :patch, "https://httpbin.org/patch" + include_examples "configures proxy correctly", :patch let(:url) { "https://httpbin.org/patch" } @@ -856,6 +860,7 @@ class CustomError < StandardError; end describe "#delete", vcr: Fixture.delete_httpbin_org do include_examples "common HTTP behaviour for", :delete, "https://httpbin.org/delete" + include_examples "configures proxy correctly", :delete let(:url) { "https://httpbin.org/delete" } diff --git a/spec/spec_helper.rb b/spec/spec_helper.rb index 315fef5..b8b9502 100644 --- a/spec/spec_helper.rb +++ b/spec/spec_helper.rb @@ -19,6 +19,21 @@ require_relative "spec_help/http_test_server" require_relative "spec_help/port_prober" +module HttpHelpers + def with_real_http_connections + original_cassette = VCR.current_cassette + VCR.eject_cassette if original_cassette + VCR.turn_off! + WebMock.allow_net_connect! + + yield + ensure + WebMock.disable_net_connect! + VCR.turn_on! + VCR.insert_cassette(original_cassette.name) if original_cassette + end +end + # Start with a clean slate, destroy all proxies if any Toxiproxy.all.destroy Toxiproxy.populate(ToxiproxyConfig.proxies) @@ -35,6 +50,7 @@ RSpec.configure do |conf| conf.include EnvHelper + conf.include HttpHelpers conf.after(:suite) do Toxiproxy.all.destroy # Be nice, end with a clean slate From 7894f8d2610a272113b4376823eaa51bfb9004f6 Mon Sep 17 00:00:00 2001 From: cequele Date: Wed, 12 Mar 2025 10:05:05 +0100 Subject: [PATCH 5/6] Refactor proxy tests and remove unused methods --- spec/lib/twingly/http_spec.rb | 54 ++++++------------------------ spec/spec_help/http_helpers.rb | 15 +++++++++ spec/spec_help/http_test_server.rb | 4 --- spec/spec_helper.rb | 17 +--------- 4 files changed, 26 insertions(+), 64 deletions(-) create mode 100644 spec/spec_help/http_helpers.rb diff --git a/spec/lib/twingly/http_spec.rb b/spec/lib/twingly/http_spec.rb index b0d2643..5a134ea 100644 --- a/spec/lib/twingly/http_spec.rb +++ b/spec/lib/twingly/http_spec.rb @@ -535,66 +535,35 @@ class CustomError < StandardError; end end end - RSpec.shared_examples "verifies proxy functionality" do |http_method| + RSpec.shared_examples "verifies proxy functionality" do context "when a proxy is provided" do let(:proxy_pid_and_url) { HttpTestServer.spawn("proxy_server") } let(:proxy_pid) { proxy_pid_and_url[0] } let(:proxy_url) { proxy_pid_and_url[1] } - let(:target_pid_and_url) { HttpTestServer.spawn("echoed_headers_in_body") } let(:target_pid) { target_pid_and_url[0] } let(:target_url) { target_pid_and_url[1] } - let(:client) do described_class.new( - base_user_agent: "Test Agent", + base_user_agent: base_user_agent, proxy: proxy_url ) end + let(:url) { target_url } after do HttpTestServer.stop(proxy_pid) HttpTestServer.stop(target_pid) end - it "routes requests through the proxy", vcr: false do # rubocop:disable RSpec/ExampleLength + it "routes requests through the proxy", vcr: false do with_real_http_connections do - response = case http_method - when :get - client.get(target_url) - when :post - client.post(target_url, body: "test") - when :put - client.put(target_url, body: "test") - when :patch - client.patch(target_url, body: "test") - when :delete - client.delete(target_url) - end - - expect(response.body).to include("HTTP_X_PROXIED_BY") + expect(response.fetch(:body)).to include("HTTP_X_PROXIED_BY") end end end end - RSpec.shared_examples "configures proxy correctly" do - context "when a proxy is provided" do - let(:proxy_url) { "http://127.0.0.1:8080" } - let(:proxy_client) do - described_class.new( - base_user_agent: base_user_agent, - proxy: proxy_url - ) - end - - it "sets the proxy" do - connection = proxy_client.send(:create_http_client) - expect(connection.proxy.uri.to_s).to eq(proxy_url) - end - end - end - describe "#initialize" do context "when no logger is given" do subject(:default_logger) do @@ -614,8 +583,7 @@ class CustomError < StandardError; end describe "#post", vcr: Fixture.post_example_org do include_examples "common HTTP behaviour for", :post, "example.org" - include_examples "verifies proxy functionality", :post - include_examples "configures proxy correctly", :post + include_examples "verifies proxy functionality" let(:post_body) { nil } let(:post_headers) { {} } @@ -664,9 +632,7 @@ class CustomError < StandardError; end describe "#get", vcr: Fixture.example_org do include_examples "common HTTP behaviour for", :get, "example.org" - include_examples "verifies proxy functionality", :get - include_examples "configures proxy correctly", :get - + include_examples "verifies proxy functionality" let(:request_response) do client.get(url) end @@ -758,7 +724,7 @@ class CustomError < StandardError; end describe "#put", vcr: Fixture.put_httpbin_org do include_examples "common HTTP behaviour for", :put, "https://httpbin.org/put" - include_examples "configures proxy correctly", :put + include_examples "verifies proxy functionality" let(:url) { "https://httpbin.org/put" } @@ -809,7 +775,7 @@ class CustomError < StandardError; end describe "#patch", vcr: Fixture.patch_httpbin_org do include_examples "common HTTP behaviour for", :patch, "https://httpbin.org/patch" - include_examples "configures proxy correctly", :patch + include_examples "verifies proxy functionality" let(:url) { "https://httpbin.org/patch" } @@ -860,7 +826,7 @@ class CustomError < StandardError; end describe "#delete", vcr: Fixture.delete_httpbin_org do include_examples "common HTTP behaviour for", :delete, "https://httpbin.org/delete" - include_examples "configures proxy correctly", :delete + include_examples "verifies proxy functionality" let(:url) { "https://httpbin.org/delete" } diff --git a/spec/spec_help/http_helpers.rb b/spec/spec_help/http_helpers.rb new file mode 100644 index 0000000..4ee6d1c --- /dev/null +++ b/spec/spec_help/http_helpers.rb @@ -0,0 +1,15 @@ +# frozen_string_literal: true + +module HttpHelpers + def with_real_http_connections + original_cassette = VCR.eject_cassette + VCR.turn_off! + WebMock.allow_net_connect! + + yield + ensure + WebMock.disable_net_connect! + VCR.turn_on! + VCR.insert_cassette(original_cassette.name) if original_cassette + end +end diff --git a/spec/spec_help/http_test_server.rb b/spec/spec_help/http_test_server.rb index 3d1edcd..c38ca0d 100644 --- a/spec/spec_help/http_test_server.rb +++ b/spec/spec_help/http_test_server.rb @@ -5,10 +5,6 @@ module HttpTestServer module_function - def spawn_server_with_echoed_headers_in_body - spawn("echoed_headers_in_body") - end - def spawn(server_name, env: {}) # rubocop:disable Metrics/MethodLength ip_address = PortProber.localhost port = PortProber.random(ip_address) diff --git a/spec/spec_helper.rb b/spec/spec_helper.rb index b8b9502..9e5f114 100644 --- a/spec/spec_helper.rb +++ b/spec/spec_helper.rb @@ -14,26 +14,11 @@ require_relative "spec_help/env_helper" require_relative "spec_help/fixture" +require_relative "spec_help/http_helpers" require_relative "spec_help/test_logger" require_relative "spec_help/toxiproxy_config" -require_relative "spec_help/http_test_server" require_relative "spec_help/port_prober" -module HttpHelpers - def with_real_http_connections - original_cassette = VCR.current_cassette - VCR.eject_cassette if original_cassette - VCR.turn_off! - WebMock.allow_net_connect! - - yield - ensure - WebMock.disable_net_connect! - VCR.turn_on! - VCR.insert_cassette(original_cassette.name) if original_cassette - end -end - # Start with a clean slate, destroy all proxies if any Toxiproxy.all.destroy Toxiproxy.populate(ToxiproxyConfig.proxies) From a9540111108f3aedc7fd7a221673b689cbed30d4 Mon Sep 17 00:00:00 2001 From: cequele Date: Wed, 12 Mar 2025 11:09:46 +0100 Subject: [PATCH 6/6] Refactor test server to use TestServer struct --- spec/lib/twingly/http_spec.rb | 17 +++++++---------- spec/spec_help/http_test_server.rb | 4 +++- 2 files changed, 10 insertions(+), 11 deletions(-) diff --git a/spec/lib/twingly/http_spec.rb b/spec/lib/twingly/http_spec.rb index 5a134ea..ce7bb6f 100644 --- a/spec/lib/twingly/http_spec.rb +++ b/spec/lib/twingly/http_spec.rb @@ -537,23 +537,19 @@ class CustomError < StandardError; end RSpec.shared_examples "verifies proxy functionality" do context "when a proxy is provided" do - let(:proxy_pid_and_url) { HttpTestServer.spawn("proxy_server") } - let(:proxy_pid) { proxy_pid_and_url[0] } - let(:proxy_url) { proxy_pid_and_url[1] } - let(:target_pid_and_url) { HttpTestServer.spawn("echoed_headers_in_body") } - let(:target_pid) { target_pid_and_url[0] } - let(:target_url) { target_pid_and_url[1] } + let(:proxy_server) { HttpTestServer.spawn("proxy_server") } + let(:target_server) { HttpTestServer.spawn("echoed_headers_in_body") } let(:client) do described_class.new( base_user_agent: base_user_agent, - proxy: proxy_url + proxy: proxy_server.url ) end - let(:url) { target_url } + let(:url) { target_server.url } after do - HttpTestServer.stop(proxy_pid) - HttpTestServer.stop(target_pid) + HttpTestServer.stop(proxy_server.pid) + HttpTestServer.stop(target_server.pid) end it "routes requests through the proxy", vcr: false do @@ -633,6 +629,7 @@ class CustomError < StandardError; end describe "#get", vcr: Fixture.example_org do include_examples "common HTTP behaviour for", :get, "example.org" include_examples "verifies proxy functionality" + let(:request_response) do client.get(url) end diff --git a/spec/spec_help/http_test_server.rb b/spec/spec_help/http_test_server.rb index c38ca0d..1e2e344 100644 --- a/spec/spec_help/http_test_server.rb +++ b/spec/spec_help/http_test_server.rb @@ -5,6 +5,8 @@ module HttpTestServer module_function + TestServer = Struct.new(:pid, :url) + def spawn(server_name, env: {}) # rubocop:disable Metrics/MethodLength ip_address = PortProber.localhost port = PortProber.random(ip_address) @@ -23,7 +25,7 @@ def spawn(server_name, env: {}) # rubocop:disable Metrics/MethodLength sleep 0.05 until started?(pid) && PortProber.port_open?(ip_address, port) end - [pid, url] + TestServer.new(pid, url) end def stop(pid)