# frozen_string_literal: true require 'fileutils' require 'excon' require 'spec_helper' describe 'Puma' do before(:all) do project_root = File.expand_path('../..', __dir__) config_lines = File.read('spec/rack_servers/configs/puma.rb') .gsub('/home/git/gitlab', project_root) .gsub('/home/git', project_root) config_path = File.join(project_root, "tmp/tests/puma.rb") @socket_path = File.join(project_root, 'tmp/tests/puma.socket') File.write(config_path, config_lines) cmd = %W[puma -e test -C #{config_path} #{File.join(__dir__, 'configs/config.ru')}] @puma_master_pid = spawn(*cmd) wait_puma_boot!(@puma_master_pid, File.join(project_root, 'tmp/tests/puma-worker-ready')) WebMock.allow_net_connect! end %w[SIGQUIT SIGTERM SIGKILL].each do |signal| it "has a worker that self-terminates on signal #{signal}" do response = Excon.get('unix://', socket: @socket_path) expect(response.status).to eq(200) worker_pid = response.body.to_i expect(worker_pid).to be > 0 begin Excon.post("unix://?#{signal}", socket: @socket_path) rescue Excon::Error::Socket # The connection may be closed abruptly end expect(pid_gone?(worker_pid)).to eq(true) end end after(:all) do begin WebMock.disable_net_connect!(allow_localhost: true) Process.kill('TERM', @puma_master_pid) rescue Errno::ESRCH end end def wait_puma_boot!(master_pid, ready_file) # We have seen the boot timeout after 2 minutes in CI so let's set it to 5 minutes. timeout = 5 * 60 timeout.times do return if File.exist?(ready_file) pid = Process.waitpid(master_pid, Process::WNOHANG) raise "puma failed to boot: #{$?}" unless pid.nil? sleep 1 end raise "puma boot timed out after #{timeout} seconds" end def pid_gone?(pid) # Worker termination should take less than a second. That makes 10 # seconds a generous timeout. 10.times do begin Process.kill(0, pid) rescue Errno::ESRCH return true end sleep 1 end false end end