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