Skip to content

Commit

Permalink
Add support for dump/restore between MockRedis instances (#176)
Browse files Browse the repository at this point in the history
  • Loading branch information
jdelStrother authored and sds committed Nov 25, 2019
1 parent e8dc650 commit 146beda
Show file tree
Hide file tree
Showing 3 changed files with 82 additions and 0 deletions.
16 changes: 16 additions & 0 deletions lib/mock_redis/database.rb
Expand Up @@ -124,6 +124,22 @@ def flushdb
'OK'
end

def dump(key)
value = data[key]
value ? Marshal.dump(value) : nil
end

def restore(key, ttl, value, replace: false)
if !replace && exists(key)
raise Redis::CommandError, 'BUSYKEY Target key name already exists.'
end
data[key] = Marshal.load(value) # rubocop:disable Security/MarshalLoad
if ttl > 0
pexpire(key, ttl)
end
'OK'
end

def keys(format = '*')
data.keys.grep(redis_pattern_to_ruby_regex(format))
end
Expand Down
19 changes: 19 additions & 0 deletions spec/commands/dump_spec.rb
@@ -0,0 +1,19 @@
require 'spec_helper'

describe '#dump(key)' do
before do
@key = 'mock-redis-test:45794'
# These are mock-only, since our dump/restore implementations
# aren't compatible with real redis.
@mock = @redises.mock
end

it 'returns nil for keys that do not exist' do
@mock.dump(@key).should be_nil
end

it 'returns a serialized value for keys that do exist' do
@mock.set(@key, '2')
@mock.dump(@key).should == Marshal.dump('2')
end
end
47 changes: 47 additions & 0 deletions spec/commands/restore_spec.rb
@@ -0,0 +1,47 @@
require 'spec_helper'

describe '#restore(key, ttl, value)' do
before do
@key = 'mock-redis-test:45794'
@src = MockRedis.new
@src.set(@key, '123')
@dumped_value = @src.dump(@key)
@dst = MockRedis.new
@now = Time.now.round
Time.stub(:now).and_return(@now)
end

it 'allows dump/restoring values between two redis instances' do
expect(@dst.restore(@key, 0, @dumped_value)).to eq('OK')
expect(@dst.get(@key)).to eq('123')
expect(@dst.pttl(@key)).to eq(-1)
end

context 'when the key being restored to already exists' do
before do
@dst.set(@key, '456')
end

it 'raises an error by default' do
expect { @dst.restore(@key, 0, @dumped_value) }.to raise_error(Redis::CommandError)
expect(@dst.get(@key)).to eq('456')
end

it 'allows replacing the key if replace==true' do
expect(@dst.restore(@key, 0, @dumped_value, replace: true)).to eq('OK')
expect(@dst.get(@key)).to eq('123')
end
end

it 'sets ttl in ms' do
@dst.restore(@key, 500, @dumped_value)
expect(@dst.pttl(@key)).to eq(500)
end

it 'can dump/restore more complex data types' do
key = 'a_hash'
@src.mapped_hmset(key, foo: 'bar')
@dst.restore(key, 0, @src.dump(key))
expect(@dst.hgetall(key)).to eq('foo' => 'bar')
end
end

0 comments on commit 146beda

Please sign in to comment.