DEV: Introduce `TemporaryRedis` and unset `DISCOURSE_*` env vars in the `themes:isolated_test` rake task (#13401)
The `themes:isolated_test` rake task will now unset all `DISCOURSE_*` env variables if `UNSET_DISCOURSE_ENV_VARS` env var is set and will also spin up a temporary redis server so the unicorn web server that's spun up for the tests doesn't leak into the "main" redis server.
This commit is contained in:
parent
30c7a9b06d
commit
d3a3d1b94c
|
@ -42,7 +42,10 @@ task "qunit:test", [:timeout, :qunit_path] do |_, args|
|
|||
"UNICORN_PID_PATH" => "#{Rails.root}/tmp/pids/unicorn_test_#{port}.pid", # So this can run alongside development
|
||||
"UNICORN_PORT" => port.to_s,
|
||||
"UNICORN_SIDEKIQS" => "0",
|
||||
"DISCOURSE_SKIP_CSS_WATCHER" => "1"
|
||||
"DISCOURSE_SKIP_CSS_WATCHER" => "1",
|
||||
"UNICORN_LISTENER" => "127.0.0.1:#{port}",
|
||||
"LOGSTASH_UNICORN_URI" => nil,
|
||||
"UNICORN_WORKERS" => "3"
|
||||
},
|
||||
"#{Rails.root}/bin/unicorn -c config/unicorn.conf.rb",
|
||||
pgroup: true
|
||||
|
|
|
@ -120,7 +120,22 @@ task "themes:qunit", :type, :value do |t, args|
|
|||
end
|
||||
|
||||
desc "Install a theme/component on a temporary DB and run QUnit tests"
|
||||
task "themes:install_and_test" => :environment do |t, args|
|
||||
task "themes:isolated_test" => :environment do |t, args|
|
||||
# This task can be called in a production environment that likely has a bunch
|
||||
# of DISCOURSE_* env vars that we don't want to be picked up by the Unicorn
|
||||
# server that will be spawned for the tests. So we need to unset them all
|
||||
# before we proceed.
|
||||
# Make this behavior opt-in to make it very obvious.
|
||||
if ENV["UNSET_DISCOURSE_ENV_VARS"] == "1"
|
||||
ENV.keys.each do |key|
|
||||
next if !key.start_with?('DISCOURSE_')
|
||||
ENV[key] = nil
|
||||
end
|
||||
end
|
||||
|
||||
redis = TemporaryRedis.new
|
||||
redis.start
|
||||
$redis = redis.instance # rubocop:disable Style/GlobalVars
|
||||
db = TemporaryDb.new
|
||||
db.start
|
||||
db.migrate
|
||||
|
@ -139,6 +154,7 @@ task "themes:install_and_test" => :environment do |t, args|
|
|||
ENV["PGHOST"] = "localhost"
|
||||
ENV["QUNIT_RAILS_ENV"] = "development"
|
||||
ENV["DISCOURSE_DEV_DB"] = "discourse"
|
||||
ENV["DISCOURSE_REDIS_PORT"] = redis.port.to_s
|
||||
|
||||
count = 0
|
||||
themes.each do |(name, id)|
|
||||
|
@ -155,4 +171,5 @@ task "themes:install_and_test" => :environment do |t, args|
|
|||
ensure
|
||||
db&.stop
|
||||
db&.remove
|
||||
redis&.remove
|
||||
end
|
||||
|
|
|
@ -0,0 +1,107 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
class TemporaryRedis
|
||||
REDIS_TEMP_DIR = "/tmp/discourse_temp_redis"
|
||||
REDIS_LOG_PATH = "#{REDIS_TEMP_DIR}/redis.log"
|
||||
REDIS_PID_PATH = "#{REDIS_TEMP_DIR}/redis.pid"
|
||||
|
||||
attr_reader :instance
|
||||
|
||||
def initialize
|
||||
set_redis_server_bin
|
||||
end
|
||||
|
||||
def port
|
||||
@port ||= find_free_port(11000..11900)
|
||||
end
|
||||
|
||||
def start
|
||||
return if @started
|
||||
FileUtils.rm_rf(REDIS_TEMP_DIR)
|
||||
Dir.mkdir(REDIS_TEMP_DIR)
|
||||
FileUtils.touch(REDIS_LOG_PATH)
|
||||
|
||||
puts "Starting redis on port: #{port}"
|
||||
@thread = Thread.new do
|
||||
system(
|
||||
@redis_server_bin,
|
||||
"--port", port.to_s,
|
||||
"--pidfile", REDIS_PID_PATH,
|
||||
"--logfile", REDIS_LOG_PATH,
|
||||
"--databases", "1",
|
||||
"--save", '""',
|
||||
"--appendonly", "no",
|
||||
"--daemonize", "no",
|
||||
"--maxclients", "100",
|
||||
"--dir", REDIS_TEMP_DIR
|
||||
)
|
||||
end
|
||||
|
||||
puts "Waiting for redis server to start..."
|
||||
success = false
|
||||
instance = nil
|
||||
config = {
|
||||
port: port,
|
||||
host: "127.0.0.1",
|
||||
db: 0
|
||||
}
|
||||
start = Time.now
|
||||
while !success
|
||||
begin
|
||||
instance = DiscourseRedis.new(config, namespace: true)
|
||||
success = instance.ping == "PONG"
|
||||
rescue Redis::CannotConnectError
|
||||
ensure
|
||||
if !success && (Time.now - start) >= 5
|
||||
STDERR.puts "ERROR: Could not connect to redis in 5 seconds."
|
||||
self.remove
|
||||
exit(1)
|
||||
elsif !success
|
||||
sleep 0.1
|
||||
end
|
||||
end
|
||||
end
|
||||
puts "Redis is ready"
|
||||
@instance = instance
|
||||
@started = true
|
||||
end
|
||||
|
||||
def remove
|
||||
if @instance
|
||||
@instance.shutdown
|
||||
@thread.join
|
||||
puts "Redis has been shutdown."
|
||||
end
|
||||
FileUtils.rm_rf(REDIS_TEMP_DIR)
|
||||
@started = false
|
||||
puts "Redis files have been cleaned up."
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def set_redis_server_bin
|
||||
path = `which redis-server 2> /dev/null`.strip
|
||||
if path.size < 1
|
||||
STDERR.puts 'ERROR: redis-server is not installed on this machine. Please install it'
|
||||
exit(1)
|
||||
end
|
||||
@redis_server_bin = path
|
||||
rescue => ex
|
||||
STDERR.puts 'ERROR: Failed to find redis-server binary:'
|
||||
STDERR.puts ex.inspect
|
||||
exit(1)
|
||||
end
|
||||
|
||||
def find_free_port(range)
|
||||
range.each do |port|
|
||||
return port if port_available?(port)
|
||||
end
|
||||
end
|
||||
|
||||
def port_available?(port)
|
||||
TCPServer.open(port).close
|
||||
true
|
||||
rescue Errno::EADDRINUSE
|
||||
false
|
||||
end
|
||||
end
|
Loading…
Reference in New Issue