spec/client_spec.rb in redlock-1.1.0 vs spec/client_spec.rb in redlock-1.2.0
- old
+ new
@@ -1,8 +1,9 @@
require 'spec_helper'
require 'securerandom'
require 'redis'
+require 'connection_pool'
RSpec.describe Redlock::Client do
# It is recommended to have at least 3 servers in production
let(:lock_manager_opts) { { retry_count: 3 } }
let(:lock_manager) { Redlock::Client.new(Redlock::Client::DEFAULT_REDIS_URLS, lock_manager_opts) }
@@ -23,10 +24,19 @@
s.instance_variable_get(:@redis).connection[:host]
end
expect(redlock_servers).to match_array([redis1_host, redis2_host])
end
+
+ it 'accepts ConnectionPool objects' do
+ pool = ConnectionPool.new { Redis.new(url: "redis://#{redis1_host}:#{redis1_port}") }
+ redlock = Redlock::Client.new([pool])
+
+ lock_info = lock_manager.lock(resource_key, ttl)
+ expect(resource_key).to_not be_lockable(lock_manager, ttl)
+ lock_manager.unlock(lock_info)
+ end
end
describe 'lock' do
context 'when lock is available' do
after(:each) { lock_manager.unlock(@lock_info) if @lock_info }
@@ -158,17 +168,33 @@
expect(lock_manager).to receive(:sleep) do |sleep|
expect(sleep).to satisfy { |value| value < expected_maximum / 1000.to_f }
end.at_least(:once)
lock_manager.lock(resource_key, ttl)
end
+
+ it 'accepts retry_delay as proc' do
+ retry_delay = proc do |attempt_number|
+ expect(attempt_number).to eq(1)
+ 2000
+ end
+
+ lock_manager = Redlock::Client.new(Redlock::Client::DEFAULT_REDIS_URLS, retry_count: 1, retry_delay: retry_delay)
+ another_lock_info = lock_manager.lock(resource_key, ttl)
+
+ expect(lock_manager).to receive(:sleep) do |sleep|
+ expect(sleep * 1000).to be_within(described_class::DEFAULT_RETRY_JITTER).of(2000)
+ end.exactly(:once)
+ lock_manager.lock(resource_key, ttl)
+ lock_manager.unlock(another_lock_info)
+ end
end
context 'when a server goes away' do
it 'does not raise an error on connection issues' do
# We re-route the lock manager to a (hopefully) non-existent Redis URL.
redis_instance = lock_manager.instance_variable_get(:@servers).first
- redis_instance.instance_variable_set(:@redis, Redis.new(url: 'redis://localhost:46864'))
+ redis_instance.instance_variable_set(:@redis, unreachable_redis)
expect {
expect(lock_manager.lock(resource_key, ttl)).to be_falsey
}.to_not raise_error
end
@@ -176,17 +202,26 @@
context 'when a server comes back' do
it 'recovers from connection issues' do
# Same as above.
redis_instance = lock_manager.instance_variable_get(:@servers).first
- redis_instance.instance_variable_set(:@redis, Redis.new(url: 'redis://localhost:46864'))
+ old_redis = redis_instance.instance_variable_get(:@redis)
+ redis_instance.instance_variable_set(:@redis, unreachable_redis)
expect(lock_manager.lock(resource_key, ttl)).to be_falsey
- redis_instance.instance_variable_set(:@redis, Redis.new(url: "redis://#{redis1_host}:#{redis1_port}"))
+ redis_instance.instance_variable_set(:@redis, old_redis)
expect(lock_manager.lock(resource_key, ttl)).to be_truthy
end
end
+ def unreachable_redis
+ redis = Redis.new(url: 'redis://localhost:46864')
+ def redis.with
+ yield self
+ end
+ redis
+ end
+
context 'when script cache has been flushed' do
before(:each) do
@manipulated_instance = lock_manager.instance_variable_get(:@servers).first
@manipulated_instance.instance_variable_get(:@redis).script(:flush)
end
@@ -314,10 +349,12 @@
context 'when lock is not available' do
before { @another_lock_info = lock_manager.lock(resource_key, ttl) }
after { lock_manager.unlock(@another_lock_info) }
it 'raises a LockError' do
- expect { lock_manager.lock!(resource_key, ttl) {} }.to raise_error(Redlock::LockError)
+ expect { lock_manager.lock!(resource_key, ttl) {} }.to raise_error(
+ Redlock::LockError, "failed to acquire lock on '#{resource_key}'"
+ )
end
it 'does not execute the block' do
expect do
begin