1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190
|
# frozen_string_literal: true
RSpec.shared_context "HTTP handling" do
context "without timeouts" do
let(:options) { {:timeout_class => HTTP::Timeout::Null, :timeout_options => {}} }
it "works" do
expect(client.get(server.endpoint).body.to_s).to eq("<!doctype html>")
end
end
context "with a per operation timeout" do
let(:response) { client.get(server.endpoint).body.to_s }
let(:options) do
{
:timeout_class => HTTP::Timeout::PerOperation,
:timeout_options => {
:connect_timeout => conn_timeout,
:read_timeout => read_timeout,
:write_timeout => write_timeout
}
}
end
let(:conn_timeout) { 1 }
let(:read_timeout) { 1 }
let(:write_timeout) { 1 }
it "works" do
expect(response).to eq("<!doctype html>")
end
context "connection" do
context "of 1" do
let(:conn_timeout) { 1 }
it "does not time out" do
expect { response }.to_not raise_error
end
end
end
context "read" do
context "of 0" do
let(:read_timeout) { 0 }
xit "times out", :flaky do
expect { response }.to raise_error(HTTP::TimeoutError, /Read/i)
end
end
context "of 2.5" do
let(:read_timeout) { 2.5 }
it "does not time out", :flaky do
expect { client.get("#{server.endpoint}/sleep").body.to_s }.to_not raise_error
end
end
end
end
context "with a global timeout" do
let(:options) do
{
:timeout_class => HTTP::Timeout::Global,
:timeout_options => {
:global_timeout => global_timeout
}
}
end
let(:global_timeout) { 1 }
let(:response) { client.get(server.endpoint).body.to_s }
it "errors if connecting takes too long" do
expect(TCPSocket).to receive(:open) do
sleep 1.25
end
expect { response }.to raise_error(HTTP::TimeoutError, /execution/)
end
it "errors if reading takes too long" do
expect { client.get("#{server.endpoint}/sleep").body.to_s }.
to raise_error(HTTP::TimeoutError, /Timed out/)
end
context "it resets state when reusing connections" do
let(:extra_options) { {:persistent => server.endpoint} }
let(:global_timeout) { 2.5 }
it "does not timeout", :flaky do
client.get("#{server.endpoint}/sleep").body.to_s
client.get("#{server.endpoint}/sleep").body.to_s
end
end
end
describe "connection reuse" do
let(:sockets_used) do
[
client.get("#{server.endpoint}/socket/1").body.to_s,
client.get("#{server.endpoint}/socket/2").body.to_s
]
end
context "when enabled" do
let(:options) { {:persistent => server.endpoint} }
context "without a host" do
it "infers host from persistent config" do
expect(client.get("/").body.to_s).to eq("<!doctype html>")
end
end
it "re-uses the socket" do
expect(sockets_used).to_not include("")
expect(sockets_used.uniq.length).to eq(1)
end
context "on a mixed state" do
it "re-opens the connection", :flaky do
first_socket_id = client.get("#{server.endpoint}/socket/1").body.to_s
client.instance_variable_set(:@state, :dirty)
second_socket_id = client.get("#{server.endpoint}/socket/2").body.to_s
expect(first_socket_id).to_not eq(second_socket_id)
end
end
context "when trying to read a stale body" do
it "errors" do
client.get("#{server.endpoint}/not-found")
expect { client.get(server.endpoint) }.to raise_error(HTTP::StateError, /Tried to send a request/)
end
end
context "when reading a cached body" do
it "succeeds" do
first_res = client.get(server.endpoint)
first_res.body.to_s
second_res = client.get(server.endpoint)
expect(first_res.body.to_s).to eq("<!doctype html>")
expect(second_res.body.to_s).to eq("<!doctype html>")
end
end
context "with a socket issue" do
it "transparently reopens", :flaky do
first_socket_id = client.get("#{server.endpoint}/socket").body.to_s
expect(first_socket_id).to_not eq("")
# Kill off the sockets we used
# rubocop:disable Style/RescueModifier
DummyServer::Servlet.sockets.each do |socket|
socket.close rescue nil
end
DummyServer::Servlet.sockets.clear
# rubocop:enable Style/RescueModifier
# Should error because we tried to use a bad socket
expect { client.get("#{server.endpoint}/socket").body.to_s }.to raise_error HTTP::ConnectionError
# Should succeed since we create a new socket
second_socket_id = client.get("#{server.endpoint}/socket").body.to_s
expect(second_socket_id).to_not eq(first_socket_id)
end
end
context "with a change in host" do
it "errors" do
expect { client.get("https://invalid.com/socket") }.to raise_error(/Persistence is enabled/i)
end
end
end
context "when disabled" do
let(:options) { {} }
it "opens new sockets", :flaky do
expect(sockets_used).to_not include("")
expect(sockets_used.uniq.length).to eq(2)
end
end
end
end
|