Files
news.gitea.happylizard.me/bin/gems/ethon-0.16.0/spec/ethon/multi_spec.rb
T
pizza2d1 4cee170d66
Gitea Actions Demo / Explore-Gitea-Actions (push) Failing after 9s
Add bin and edit workflow
2026-09-16 13:11:16 -06:00

153 lines
4.2 KiB
Ruby

# frozen_string_literal: true
require 'spec_helper'
describe Ethon::Multi do
describe ".new" do
it "inits curl" do
expect(Ethon::Curl).to receive(:init)
Ethon::Multi.new
end
context "with default options" do
it "allows running #perform with the default execution_mode" do
Ethon::Multi.new.perform
end
it "refuses to run #socket_action" do
expect { Ethon::Multi.new.socket_action }.to raise_error(ArgumentError)
end
end
context "when options not empty" do
context "when pipelining is set" do
let(:options) { { :pipelining => true } }
it "sets pipelining" do
expect_any_instance_of(Ethon::Multi).to receive(:pipelining=).with(true)
Ethon::Multi.new(options)
end
end
context "when execution_mode option is :socket_action" do
let(:options) { { :execution_mode => :socket_action } }
let(:multi) { Ethon::Multi.new(options) }
it "refuses to run #perform" do
expect { multi.perform }.to raise_error(ArgumentError)
end
it "allows running #socket_action" do
multi.socket_action
end
end
end
end
describe "#socket_action" do
let(:options) { { :execution_mode => :socket_action } }
let(:select_state) { { :readers => [], :writers => [], :timeout => 0 } }
let(:multi) {
multi = Ethon::Multi.new(options)
multi.timerfunction = proc do |handle, timeout_ms, userp|
timeout_ms = nil if timeout_ms == -1
select_state[:timeout] = timeout_ms
:ok
end
multi.socketfunction = proc do |handle, sock, what, userp, socketp|
case what
when :remove
select_state[:readers].delete(sock)
select_state[:writers].delete(sock)
when :in
select_state[:readers].push(sock) unless select_state[:readers].include? sock
select_state[:writers].delete(sock)
when :out
select_state[:readers].delete(sock)
select_state[:writers].push(sock) unless select_state[:writers].include? sock
when :inout
select_state[:readers].push(sock) unless select_state[:readers].include? sock
select_state[:writers].push(sock) unless select_state[:writers].include? sock
else
raise ArgumentError, "invalid value for 'what' in socketfunction callback"
end
:ok
end
multi
}
def fds_to_ios(fds)
fds.map do |fd|
IO.for_fd(fd).tap { |io| io.autoclose = false }
end
end
def perform_socket_action_until_complete
multi.socket_action # start things off
while multi.ongoing?
readers, writers, _ = IO.select(
fds_to_ios(select_state[:readers]),
fds_to_ios(select_state[:writers]),
[],
select_state[:timeout]
)
to_notify = Hash.new { |hash, key| hash[key] = [] }
unless readers.nil?
readers.each do |reader|
to_notify[reader] << :in
end
end
unless writers.nil?
writers.each do |writer|
to_notify[writer] << :out
end
end
to_notify.each do |io, readiness|
multi.socket_action(io, readiness)
end
# if we didn't have anything to notify, then we timed out
multi.socket_action if to_notify.empty?
end
ensure
multi.easy_handles.dup.each do |h|
multi.delete(h)
end
end
it "supports an end-to-end request" do
easy = Ethon::Easy.new
easy.url = "http://localhost:3001/"
multi.add(easy)
perform_socket_action_until_complete
expect(multi.ongoing?).to eq(false)
end
it "supports multiple concurrent requests" do
handles = []
10.times do
easy = Ethon::Easy.new
easy.url = "http://localhost:3001/?delay=1"
multi.add(easy)
handles << easy
end
start = Time.now
perform_socket_action_until_complete
duration = Time.now - start
# these should have happened concurrently
expect(duration).to be < 2
expect(multi.ongoing?).to eq(false)
handles.each do |handle|
expect(handle.response_code).to eq(200)
end
end
end
end