Skip to content

Instantly share code, notes, and snippets.

@hatyuki
Created June 24, 2015 09:32
Show Gist options
  • Save hatyuki/f79bad568526a10f2c16 to your computer and use it in GitHub Desktop.
Save hatyuki/f79bad568526a10f2c16 to your computer and use it in GitHub Desktop.
module Test
class RedisServer
# Create a new redis-server instance, and start it if block given.
#
# @param timeout [Fixnum]
# @param config [Hash]
def initialize (timeout: 3, config: { }, &block)
@owner_pid = $$
@pid = nil
@timeout = timeout
@config = config
if @config[:loglevel].to_s == 'warning'
$stderr.puts 'Test::RedisServer does not support "loglevel warning", using "notice" instead.'
@config[:loglevel] = 'notice'
end
start(&block) if block
end
# Start redis-server instance.
#
# @yield [connect_info]
# @yieldparam connect_info [Hash]
def start
return if @pid
Dir.mktmpdir do |tmpdir|
yield start_redis_server(tmpdir)
stop
end
end
private
def start_redis_server (tmpdir)
logfile = "#{tmpdir}/redis-server.log"
config_file = prepare_config_file(tmpdir)
File.open(logfile, 'w') do |redirect|
@pid = Process.fork do
stderr = $stderr.dup
begin
exec 'redis-server', config_file, out: redirect, err: redirect
rescue => error
stderr.puts "exec failed: #{error}"
exit error.errno
end
end
end
(@timeout * 10).times do
if !Process.waitpid(@pid, Process::WNOHANG).nil?
@pid = nil
break
else
if File.read(logfile) =~ /The server is now ready to accept connections/
return connect_info
end
end
sleep 0.1
end
stop if @pid
raise RuntimeError, "failed to launch redis-server\n#{File.read(logfile)}"
end
def prepare_config_file (directory)
if @config[:unixsocket].nil? && @config[:port].nil?
@config[:unixsocket] = "#{directory}/redis.sock"
@config[:port] = 0
end
if @config[:dir].nil?
@config[:dir] = "#{directory}/"
end
"#{directory}/redis.conf".tap do |config_file|
File.write(config_file, config)
end
end
def config
@config.inject('') do |memo, (key, value)|
next if value.to_s.empty?
memo += "#{key} #{value}\n"
end
end
def connect_info
host = @config[:bind].nil? ? '0.0.0.0' : @config[:bind]
port = @config[:port]
if port.is_a?(Fixnum) && port > 0
{ url: "redis://#{host}:#{port}/" }
else
{ path: @config[:unixsocket] }
end
end
def stop (signal = :TERM)
return if @pid.nil?
Process.kill(signal, @pid)
while Process.waitpid(@pid, Process::WNOHANG); end
@pid = nil
end
end
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment