2019-04-29 20:27:42 -04:00
|
|
|
# frozen_string_literal: true
|
|
|
|
|
2016-03-02 09:01:48 -05:00
|
|
|
describe DiscourseRedis do
|
2020-06-22 20:41:10 -04:00
|
|
|
it "ignore_readonly returns nil from a pure exception" do
|
|
|
|
result = DiscourseRedis.ignore_readonly { raise Redis::CommandError.new("READONLY") }
|
|
|
|
expect(result).to eq(nil)
|
|
|
|
end
|
2017-10-24 22:19:43 -04:00
|
|
|
|
2020-06-22 20:41:10 -04:00
|
|
|
describe 'redis commands' do
|
|
|
|
let(:raw_redis) { Redis.new(DiscourseRedis.config) }
|
2017-08-02 01:32:01 -04:00
|
|
|
|
2020-06-22 20:41:10 -04:00
|
|
|
before do
|
|
|
|
raw_redis.flushdb
|
|
|
|
end
|
2017-08-02 01:32:01 -04:00
|
|
|
|
2020-06-22 20:41:10 -04:00
|
|
|
after do
|
|
|
|
raw_redis.flushdb
|
|
|
|
end
|
2017-08-02 01:32:01 -04:00
|
|
|
|
2020-06-22 20:41:10 -04:00
|
|
|
describe 'when namespace is enabled' do
|
|
|
|
let(:redis) { DiscourseRedis.new }
|
2017-08-02 01:32:01 -04:00
|
|
|
|
2020-06-22 20:41:10 -04:00
|
|
|
it 'should append namespace to the keys' do
|
|
|
|
raw_redis.set('default:key', 1)
|
|
|
|
raw_redis.set('test:key2', 1)
|
2022-03-28 18:52:17 -04:00
|
|
|
raw_redis.set('default:key3', 1)
|
2017-08-02 01:32:01 -04:00
|
|
|
|
2020-06-22 20:41:10 -04:00
|
|
|
expect(redis.keys).to include('key')
|
|
|
|
expect(redis.keys).to_not include('key2')
|
2022-03-28 18:52:17 -04:00
|
|
|
expect(redis.scan_each.to_a).to contain_exactly('key', 'key3')
|
2018-12-14 19:53:52 -05:00
|
|
|
|
2022-03-28 18:52:17 -04:00
|
|
|
redis.del('key', 'key3')
|
2017-08-02 01:32:01 -04:00
|
|
|
|
2020-06-22 20:41:10 -04:00
|
|
|
expect(raw_redis.get('default:key')).to eq(nil)
|
2022-03-28 18:52:17 -04:00
|
|
|
expect(raw_redis.get('default:key3')).to eq(nil)
|
|
|
|
|
2020-06-22 20:41:10 -04:00
|
|
|
expect(redis.scan_each.to_a).to eq([])
|
2017-08-02 01:32:01 -04:00
|
|
|
|
2020-06-22 20:41:10 -04:00
|
|
|
raw_redis.set('default:key1', '1')
|
|
|
|
raw_redis.set('default:key2', '2')
|
2017-08-02 01:32:01 -04:00
|
|
|
|
2020-06-22 20:41:10 -04:00
|
|
|
expect(redis.mget('key1', 'key2')).to eq(['1', '2'])
|
|
|
|
expect(redis.scan_each.to_a).to contain_exactly('key1', 'key2')
|
2017-08-02 01:32:01 -04:00
|
|
|
end
|
2020-06-22 20:41:10 -04:00
|
|
|
end
|
2017-08-02 01:32:01 -04:00
|
|
|
|
2020-06-22 20:41:10 -04:00
|
|
|
describe 'when namespace is disabled' do
|
|
|
|
let(:redis) { DiscourseRedis.new(nil, namespace: false) }
|
2017-08-02 01:32:01 -04:00
|
|
|
|
2020-06-22 20:41:10 -04:00
|
|
|
it 'should not append any namespace to the keys' do
|
|
|
|
raw_redis.set('default:key', 1)
|
|
|
|
raw_redis.set('test:key2', 1)
|
2017-08-02 01:32:01 -04:00
|
|
|
|
2020-06-22 20:41:10 -04:00
|
|
|
expect(redis.keys).to include('default:key', 'test:key2')
|
2017-08-02 01:32:01 -04:00
|
|
|
|
2020-06-22 20:41:10 -04:00
|
|
|
raw_redis.set('key1', '1')
|
|
|
|
raw_redis.set('key2', '2')
|
2017-08-02 01:32:01 -04:00
|
|
|
|
2020-06-22 20:41:10 -04:00
|
|
|
expect(redis.mget('key1', 'key2')).to eq(['1', '2'])
|
2022-03-28 18:52:17 -04:00
|
|
|
|
|
|
|
redis.del('key1', 'key2')
|
|
|
|
|
|
|
|
expect(redis.mget('key1', 'key2')).to eq([nil, nil])
|
2020-06-22 20:41:10 -04:00
|
|
|
end
|
2017-08-02 01:32:01 -04:00
|
|
|
|
2020-06-22 20:41:10 -04:00
|
|
|
it 'should noop a readonly redis' do
|
|
|
|
expect(Discourse.recently_readonly?).to eq(false)
|
2017-08-02 01:32:01 -04:00
|
|
|
|
2020-06-22 20:41:10 -04:00
|
|
|
redis.without_namespace
|
|
|
|
.expects(:set)
|
|
|
|
.raises(Redis::CommandError.new("READONLY"))
|
2017-08-02 01:32:01 -04:00
|
|
|
|
2020-06-22 20:41:10 -04:00
|
|
|
redis.set('key', 1)
|
2017-08-02 01:32:01 -04:00
|
|
|
|
2020-06-22 20:41:10 -04:00
|
|
|
expect(Discourse.recently_readonly?).to eq(true)
|
2017-08-02 01:32:01 -04:00
|
|
|
end
|
|
|
|
end
|
2021-10-06 10:42:04 -04:00
|
|
|
|
|
|
|
describe "#eval" do
|
|
|
|
it "keys and arvg are passed correcty" do
|
|
|
|
keys = ["key1", "key2"]
|
|
|
|
argv = ["arg1", "arg2"]
|
|
|
|
|
|
|
|
expect(Discourse.redis.eval(
|
|
|
|
"return { KEYS, ARGV };",
|
|
|
|
keys: keys,
|
|
|
|
argv: argv,
|
|
|
|
)).to eq([keys, argv])
|
|
|
|
|
|
|
|
expect(Discourse.redis.eval(
|
|
|
|
"return { KEYS, ARGV };",
|
|
|
|
keys,
|
|
|
|
argv: argv,
|
|
|
|
)).to eq([keys, argv])
|
|
|
|
|
|
|
|
expect(Discourse.redis.eval(
|
|
|
|
"return { KEYS, ARGV };",
|
|
|
|
keys,
|
|
|
|
argv,
|
|
|
|
)).to eq([keys, argv])
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
describe "#evalsha" do
|
|
|
|
it "keys and arvg are passed correcty" do
|
|
|
|
keys = ["key1", "key2"]
|
|
|
|
argv = ["arg1", "arg2"]
|
|
|
|
|
|
|
|
script = "return { KEYS, ARGV };"
|
|
|
|
Discourse.redis.script(:load, script)
|
|
|
|
sha = Digest::SHA1.hexdigest(script)
|
|
|
|
expect(Discourse.redis.evalsha(
|
|
|
|
sha,
|
|
|
|
keys: keys,
|
|
|
|
argv: argv,
|
|
|
|
)).to eq([keys, argv])
|
|
|
|
|
|
|
|
expect(Discourse.redis.evalsha(
|
|
|
|
sha,
|
|
|
|
keys,
|
|
|
|
argv: argv,
|
|
|
|
)).to eq([keys, argv])
|
|
|
|
|
|
|
|
expect(Discourse.redis.evalsha(
|
|
|
|
sha,
|
|
|
|
keys,
|
|
|
|
argv,
|
|
|
|
)).to eq([keys, argv])
|
|
|
|
end
|
|
|
|
end
|
2020-06-22 20:41:10 -04:00
|
|
|
end
|
2022-02-15 11:06:12 -05:00
|
|
|
|
|
|
|
describe DiscourseRedis::EvalHelper do
|
|
|
|
it "works" do
|
|
|
|
helper = DiscourseRedis::EvalHelper.new <<~LUA
|
|
|
|
return 'hello world'
|
|
|
|
LUA
|
|
|
|
expect(helper.eval(Discourse.redis)).to eq('hello world')
|
|
|
|
end
|
|
|
|
|
|
|
|
it "works with arguments" do
|
|
|
|
helper = DiscourseRedis::EvalHelper.new <<~LUA
|
|
|
|
return ARGV[1]..ARGV[2]..KEYS[1]..KEYS[2]
|
|
|
|
LUA
|
|
|
|
expect(helper.eval(Discourse.redis, ['key1', 'key2'], ['arg1', 'arg2'])).to eq("arg1arg2key1key2")
|
|
|
|
end
|
|
|
|
|
|
|
|
it "works with arguments" do
|
|
|
|
helper = DiscourseRedis::EvalHelper.new <<~LUA
|
|
|
|
return ARGV[1]..ARGV[2]..KEYS[1]..KEYS[2]
|
|
|
|
LUA
|
|
|
|
expect(helper.eval(Discourse.redis, ['key1', 'key2'], ['arg1', 'arg2'])).to eq("arg1arg2key1key2")
|
|
|
|
end
|
|
|
|
|
|
|
|
it "uses evalsha correctly" do
|
|
|
|
redis_proxy = Class.new do
|
|
|
|
attr_reader :calls
|
|
|
|
def method_missing(meth, *args, **kwargs, &block)
|
|
|
|
@calls ||= []
|
|
|
|
@calls.push(meth)
|
|
|
|
Discourse.redis.public_send(meth, *args, **kwargs, &block)
|
|
|
|
end
|
|
|
|
end.new
|
|
|
|
|
|
|
|
Discourse.redis.call("SCRIPT", "FLUSH", "SYNC")
|
|
|
|
|
|
|
|
helper = DiscourseRedis::EvalHelper.new <<~LUA
|
|
|
|
return 'hello world'
|
|
|
|
LUA
|
|
|
|
expect(helper.eval(redis_proxy)).to eq("hello world")
|
|
|
|
expect(helper.eval(redis_proxy)).to eq("hello world")
|
|
|
|
expect(helper.eval(redis_proxy)).to eq("hello world")
|
|
|
|
|
|
|
|
expect(redis_proxy.calls).to eq([:evalsha, :eval, :evalsha, :evalsha])
|
|
|
|
end
|
|
|
|
end
|
2016-03-02 09:01:48 -05:00
|
|
|
end
|