module RSpec::Httpd::Server
Constants
- MAX_STARTUP_TIME
Public Instance Methods
logger()
click to toggle source
# File lib/rspec/httpd/server.rb, line 16 def logger # If this file is required as-is, without loading all of rspec/httpd, # ::RSpec::Httpd does not provide a logger. In that case we polyfill # a default logger to STDERR. # # Doing so lets use this file as is; which lets one use the # # RSpec::Httpd::Server.start! ... # # method. if ::RSpec::Httpd.respond_to?(:logger) ::RSpec::Httpd.logger else @logger ||= ::Logger.new(STDERR, level: :info) end end
start!(host: "0.0.0.0", port:, command:, logger: nil)
click to toggle source
builds and returns a server object.
You can use this method to retrieve a client connection to a server specified via host:, port:, and, optionally, a command.
# File lib/rspec/httpd/server.rb, line 37 def start!(host: "0.0.0.0", port:, command:, logger: nil) @servers ||= {} @servers[[host, port, command]] ||= command ? do_start(host, port, command) : check_server(host, port) @logger = logger if logger end
Private Instance Methods
check_server(host, port)
click to toggle source
# File lib/rspec/httpd/server.rb, line 45 def check_server(host, port) unless wait_for_server(host: host, port: port, timeout: MAX_STARTUP_TIME) logger.error "cannot reach server at http://#{host}:#{port}" exit 1 end end
do_start(host, port, command)
click to toggle source
# File lib/rspec/httpd/server.rb, line 52 def do_start(host, port, command) if port_open?(host, port) logger.error "A process is already running on #{host}:#{port}" exit 2 end STDERR.puts <<~MSG ==== Starting server ================================================================ #{command} ===================================================================================== MSG # start child process in a separate process group. at exit we'll # kill the entire process group. This helps if the started process # spawns another child again. pid = spawn(command, pgroup: true) pgid = Process.getpgid(pid) # Install an at_exit handler. This will kill the server. The command # argument is passed in for logging only. at_exit do kill_server "TERM", pgid, command: command, sleep: 0.2 if port_open?(host, port) kill_server "KILL", pgid, command: command, sleep: 0.2 if port_open?(host, port) logger.warn "Cannot stop server at pid #{pid}: #{command}" if port_open?(host, port) end unless wait_for_server(host: host, port: port, pid: pid, timeout: MAX_STARTUP_TIME) logger.error "server didn't start at http://#{host}:#{port} pid #{pid}: #{command}" exit! 1 end logger.info "Started server at pid #{pid}: #{command}" pid end
kill_server(signal, pgid, command:, sleep: nil)
click to toggle source
# File lib/rspec/httpd/server.rb, line 88 def kill_server(signal, pgid, command:, sleep: nil) logger.debug "Kill server in pgid #{pgid} w/#{signal}: #{command}" Process.kill(signal, -pgid) Kernel.sleep(sleep) if sleep rescue Errno::ESRCH, Errno::EPERM end
port_open?(host, port)
click to toggle source
# File lib/rspec/httpd/server.rb, line 109 def port_open?(host, port) Timeout.timeout(0.01) do s = TCPSocket.new(host, port) s.close return true end rescue Errno::ECONNREFUSED, Errno::EHOSTUNREACH, Timeout::Error false end
wait_for_server(host:, port:, pid: nil, timeout:)
click to toggle source
# File lib/rspec/httpd/server.rb, line 96 def wait_for_server(host:, port:, pid: nil, timeout:) while timeout > 0 sleep 0.1 return true if port_open?(host, port) return false if pid && Process.waitpid(pid, Process::WNOHANG) timeout -= 0.1 next if timeout > 0 return false end end