mirror of
https://github.com/discourse/discourse.git
synced 2024-11-22 09:12:45 +08:00
PERF: Redis snapshotting during tests (#15260)
We can fake redis transactions so that `fab!` works for redis and PG data, but it's too slow to be used indiscriminately. Instead, you can opt into it with the `use_redis_snapshotting` helper. Insofar as snapshotting allows us to `fab!` more things, it provides a speedup.
This commit is contained in:
parent
e42f33b6ba
commit
02245ce41f
|
@ -53,7 +53,8 @@ class DiscourseRedis
|
|||
:msetnx, :persist, :pexpire, :pexpireat, :psetex, :pttl, :rename, :renamenx, :rpop, :rpoplpush, :rpush, :rpushx, :sadd, :scard,
|
||||
:sdiff, :set, :setbit, :setex, :setnx, :setrange, :sinter, :sismember, :smembers, :sort, :spop, :srandmember, :srem, :strlen,
|
||||
:sunion, :ttl, :type, :watch, :zadd, :zcard, :zcount, :zincrby, :zrange, :zrangebyscore, :zrank, :zrem, :zremrangebyrank,
|
||||
:zremrangebyscore, :zrevrange, :zrevrangebyscore, :zrevrank, :zrangebyscore ].each do |m|
|
||||
:zremrangebyscore, :zrevrange, :zrevrangebyscore, :zrevrank, :zrangebyscore,
|
||||
:dump, :restore].each do |m|
|
||||
define_method m do |*args, **kwargs|
|
||||
args[0] = "#{namespace}:#{args[0]}" if @namespace
|
||||
DiscourseRedis.ignore_readonly { @redis.public_send(m, *args, **kwargs) }
|
||||
|
|
41
lib/redis_snapshot.rb
Normal file
41
lib/redis_snapshot.rb
Normal file
|
@ -0,0 +1,41 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
class RedisSnapshot
|
||||
def self.begin_faux_transaction(redis = Discourse.redis)
|
||||
@stack ||= []
|
||||
@stack.push(RedisSnapshot.load(redis))
|
||||
end
|
||||
|
||||
def self.end_faux_transaction(redis = Discourse.redis)
|
||||
@stack.pop.restore(redis)
|
||||
end
|
||||
|
||||
def self.load(redis = Discourse.redis)
|
||||
keys = redis.keys
|
||||
|
||||
values =
|
||||
redis.pipelined do
|
||||
keys.each do |key|
|
||||
redis.dump(key)
|
||||
end
|
||||
end
|
||||
|
||||
new(keys.zip(values).delete_if { |k, v| v.nil? })
|
||||
end
|
||||
|
||||
def initialize(dump)
|
||||
@dump = dump
|
||||
end
|
||||
|
||||
def restore(redis = Discourse.redis)
|
||||
redis.pipelined do
|
||||
redis.flushdb
|
||||
|
||||
@dump.each do |key, value|
|
||||
redis.restore(key, 0, value)
|
||||
end
|
||||
end
|
||||
|
||||
nil
|
||||
end
|
||||
end
|
21
spec/helpers/redis_snapshot_helper.rb
Normal file
21
spec/helpers/redis_snapshot_helper.rb
Normal file
|
@ -0,0 +1,21 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
module RedisSnapshotHelper
|
||||
def use_redis_snapshotting
|
||||
before(:all) do
|
||||
RedisSnapshot.begin_faux_transaction
|
||||
end
|
||||
|
||||
after(:all) do
|
||||
RedisSnapshot.end_faux_transaction
|
||||
end
|
||||
|
||||
before(:each) do
|
||||
RedisSnapshot.begin_faux_transaction
|
||||
end
|
||||
|
||||
after(:each) do
|
||||
RedisSnapshot.end_faux_transaction
|
||||
end
|
||||
end
|
||||
end
|
|
@ -78,6 +78,7 @@ end
|
|||
# in spec/support/ and its subdirectories.
|
||||
Dir[Rails.root.join("spec/support/**/*.rb")].each { |f| require f }
|
||||
Dir[Rails.root.join("spec/fabricators/*.rb")].each { |f| require f }
|
||||
require_relative './helpers/redis_snapshot_helper'
|
||||
|
||||
# Require plugin helpers at plugin/[plugin]/spec/plugin_helper.rb (includes symlinked plugins).
|
||||
if ENV['LOAD_PLUGINS'] == "1"
|
||||
|
@ -181,6 +182,7 @@ end
|
|||
RSpec.configure do |config|
|
||||
config.fail_fast = ENV['RSPEC_FAIL_FAST'] == "1"
|
||||
config.silence_filter_announcements = ENV['RSPEC_SILENCE_FILTER_ANNOUNCEMENTS'] == "1"
|
||||
config.extend RedisSnapshotHelper
|
||||
config.include Helpers
|
||||
config.include MessageBus
|
||||
config.include RSpecHtmlMatchers
|
||||
|
|
|
@ -1756,11 +1756,13 @@ RSpec.describe TopicsController do
|
|||
end
|
||||
|
||||
describe '#show' do
|
||||
fab!(:private_topic) { Fabricate(:private_message_topic) }
|
||||
let!(:topic) { Fabricate(:post).topic }
|
||||
use_redis_snapshotting
|
||||
|
||||
let!(:p1) { Fabricate(:post, user: topic.user) }
|
||||
let!(:p2) { Fabricate(:post, user: topic.user) }
|
||||
fab!(:private_topic) { Fabricate(:private_message_topic) }
|
||||
fab!(:topic) { Fabricate(:post).topic }
|
||||
|
||||
fab!(:p1) { Fabricate(:post, user: topic.user) }
|
||||
fab!(:p2) { Fabricate(:post, user: topic.user) }
|
||||
|
||||
describe 'when topic is not allowed' do
|
||||
it 'should return the right response' do
|
||||
|
|
Loading…
Reference in New Issue
Block a user