Welcome to mirror list, hosted at ThFree Co, Russian Federation.

gitlab.com/gitlab-org/gitlab-foss.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to 'spec/lib/gitlab/exclusive_lease_spec.rb')
-rw-r--r--spec/lib/gitlab/exclusive_lease_spec.rb331
1 files changed, 86 insertions, 245 deletions
diff --git a/spec/lib/gitlab/exclusive_lease_spec.rb b/spec/lib/gitlab/exclusive_lease_spec.rb
index c8325c5b359..80154c729e3 100644
--- a/spec/lib/gitlab/exclusive_lease_spec.rb
+++ b/spec/lib/gitlab/exclusive_lease_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe Gitlab::ExclusiveLease, :request_store, :clean_gitlab_redis_shared_state,
+RSpec.describe Gitlab::ExclusiveLease, :request_store,
:clean_gitlab_redis_cluster_shared_state, feature_category: :shared do
let(:unique_key) { SecureRandom.hex(10) }
@@ -20,67 +20,6 @@ RSpec.describe Gitlab::ExclusiveLease, :request_store, :clean_gitlab_redis_share
sleep(2 * timeout) # lease should have expired now
expect(lease.try_obtain).to be_present
end
-
- context 'when migrating across stores' do
- let(:lease) { described_class.new(unique_key, timeout: 3600) }
-
- before do
- stub_feature_flags(use_cluster_shared_state_for_exclusive_lease: false)
- allow(lease).to receive(:same_store).and_return(false)
- end
-
- it 'acquires 2 locks' do
- # stub first SETNX
- Gitlab::Redis::SharedState.with { |r| expect(r).to receive(:set).and_return(true) }
- Gitlab::Redis::ClusterSharedState.with { |r| expect(r).to receive(:set).and_call_original }
-
- expect(lease.try_obtain).to be_truthy
- end
-
- it 'rollback first lock if second lock is not acquired' do
- Gitlab::Redis::ClusterSharedState.with do |r|
- expect(r).to receive(:set).and_return(false)
- expect(r).to receive(:eval).and_call_original
- end
-
- Gitlab::Redis::SharedState.with do |r|
- expect(r).to receive(:set).and_call_original
- expect(r).to receive(:eval).and_call_original
- end
-
- expect(lease.try_obtain).to be_falsey
- end
- end
-
- context 'when cutting over to ClusterSharedState' do
- context 'when lock is not acquired' do
- it 'waits for existing holder to yield the lock' do
- Gitlab::Redis::ClusterSharedState.with { |r| expect(r).to receive(:set).and_call_original }
- Gitlab::Redis::SharedState.with { |r| expect(r).not_to receive(:set) }
-
- lease = described_class.new(unique_key, timeout: 3600)
- expect(lease.try_obtain).to be_truthy
- end
- end
-
- context 'when lock is still acquired' do
- let(:lease) { described_class.new(unique_key, timeout: 3600) }
-
- before do
- # simulates cutover where some application's feature-flag has not updated
- stub_feature_flags(use_cluster_shared_state_for_exclusive_lease: false)
- lease.try_obtain
- stub_feature_flags(use_cluster_shared_state_for_exclusive_lease: true)
- end
-
- it 'waits for existing holder to yield the lock' do
- Gitlab::Redis::ClusterSharedState.with { |r| expect(r).not_to receive(:set) }
- Gitlab::Redis::SharedState.with { |r| expect(r).not_to receive(:set) }
-
- expect(lease.try_obtain).to be_falsey
- end
- end
- end
end
describe '.redis_shared_state_key' do
@@ -104,159 +43,131 @@ RSpec.describe Gitlab::ExclusiveLease, :request_store, :clean_gitlab_redis_share
end
end
- shared_examples 'write operations' do
- describe '#renew' do
- it 'returns true when we have the existing lease' do
- lease = described_class.new(unique_key, timeout: 3600)
- expect(lease.try_obtain).to be_present
- expect(lease.renew).to be_truthy
- end
+ describe '#renew' do
+ it 'returns true when we have the existing lease' do
+ lease = described_class.new(unique_key, timeout: 3600)
+ expect(lease.try_obtain).to be_present
+ expect(lease.renew).to be_truthy
+ end
- it 'returns false when we dont have a lease' do
- lease = described_class.new(unique_key, timeout: 3600)
- expect(lease.renew).to be_falsey
- end
+ it 'returns false when we dont have a lease' do
+ lease = described_class.new(unique_key, timeout: 3600)
+ expect(lease.renew).to be_falsey
end
+ end
- describe 'cancellation' do
- def new_lease(key)
- described_class.new(key, timeout: 3600)
- end
+ describe 'cancellation' do
+ def new_lease(key)
+ described_class.new(key, timeout: 3600)
+ end
- shared_examples 'cancelling a lease' do
- let(:lease) { new_lease(unique_key) }
+ shared_examples 'cancelling a lease' do
+ let(:lease) { new_lease(unique_key) }
- it 'releases the held lease' do
- uuid = lease.try_obtain
- expect(uuid).to be_present
- expect(new_lease(unique_key).try_obtain).to eq(false)
+ it 'releases the held lease' do
+ uuid = lease.try_obtain
+ expect(uuid).to be_present
+ expect(new_lease(unique_key).try_obtain).to eq(false)
- cancel_lease(uuid)
+ cancel_lease(uuid)
- expect(new_lease(unique_key).try_obtain).to be_present
- end
+ expect(new_lease(unique_key).try_obtain).to be_present
end
+ end
- describe '.cancel' do
- def cancel_lease(uuid)
- described_class.cancel(release_key, uuid)
- end
+ describe '.cancel' do
+ def cancel_lease(uuid)
+ described_class.cancel(release_key, uuid)
+ end
- context 'when called with the unprefixed key' do
- it_behaves_like 'cancelling a lease' do
- let(:release_key) { unique_key }
- end
+ context 'when called with the unprefixed key' do
+ it_behaves_like 'cancelling a lease' do
+ let(:release_key) { unique_key }
end
+ end
- context 'when called with the prefixed key' do
- it_behaves_like 'cancelling a lease' do
- let(:release_key) { described_class.redis_shared_state_key(unique_key) }
- end
+ context 'when called with the prefixed key' do
+ it_behaves_like 'cancelling a lease' do
+ let(:release_key) { described_class.redis_shared_state_key(unique_key) }
end
+ end
- it 'does not raise errors when given a nil key' do
- expect { described_class.cancel(nil, nil) }.not_to raise_error
- end
+ it 'does not raise errors when given a nil key' do
+ expect { described_class.cancel(nil, nil) }.not_to raise_error
end
+ end
- describe '#cancel' do
- def cancel_lease(_uuid)
- lease.cancel
- end
+ describe '#cancel' do
+ def cancel_lease(_uuid)
+ lease.cancel
+ end
- it_behaves_like 'cancelling a lease'
+ it_behaves_like 'cancelling a lease'
- it 'is safe to call even if the lease was never obtained' do
- lease = new_lease(unique_key)
+ it 'is safe to call even if the lease was never obtained' do
+ lease = new_lease(unique_key)
- lease.cancel
+ lease.cancel
- expect(new_lease(unique_key).try_obtain).to be_present
- end
+ expect(new_lease(unique_key).try_obtain).to be_present
end
end
+ end
- describe '.reset_all!' do
- it 'removes all existing lease keys from redis' do
- uuid = described_class.new(unique_key, timeout: 3600).try_obtain
+ describe '.reset_all!' do
+ it 'removes all existing lease keys from redis' do
+ uuid = described_class.new(unique_key, timeout: 3600).try_obtain
- expect(described_class.get_uuid(unique_key)).to eq(uuid)
+ expect(described_class.get_uuid(unique_key)).to eq(uuid)
- described_class.reset_all!
+ described_class.reset_all!
- expect(described_class.get_uuid(unique_key)).to be_falsey
- end
+ expect(described_class.get_uuid(unique_key)).to be_falsey
end
end
- shared_examples 'read operations' do
- describe '#exists?' do
- it 'returns true for an existing lease' do
- lease = described_class.new(unique_key, timeout: 3600)
- lease.try_obtain
-
- expect(lease.exists?).to eq(true)
- end
-
- it 'returns false for a lease that does not exist' do
- lease = described_class.new(unique_key, timeout: 3600)
+ describe '#exists?' do
+ it 'returns true for an existing lease' do
+ lease = described_class.new(unique_key, timeout: 3600)
+ lease.try_obtain
- expect(lease.exists?).to eq(false)
- end
+ expect(lease.exists?).to eq(true)
end
- describe '.get_uuid' do
- it 'gets the uuid if lease with the key associated exists' do
- uuid = described_class.new(unique_key, timeout: 3600).try_obtain
-
- expect(described_class.get_uuid(unique_key)).to eq(uuid)
- end
+ it 'returns false for a lease that does not exist' do
+ lease = described_class.new(unique_key, timeout: 3600)
- it 'returns false if the lease does not exist' do
- expect(described_class.get_uuid(unique_key)).to be false
- end
+ expect(lease.exists?).to eq(false)
end
+ end
- describe '#ttl' do
- it 'returns the TTL of the Redis key' do
- lease = described_class.new('kittens', timeout: 100)
- lease.try_obtain
-
- expect(lease.ttl <= 100).to eq(true)
- end
+ describe '.get_uuid' do
+ it 'gets the uuid if lease with the key associated exists' do
+ uuid = described_class.new(unique_key, timeout: 3600).try_obtain
- it 'returns nil when the lease does not exist' do
- lease = described_class.new('kittens', timeout: 10)
+ expect(described_class.get_uuid(unique_key)).to eq(uuid)
+ end
- expect(lease.ttl).to be_nil
- end
+ it 'returns false if the lease does not exist' do
+ expect(described_class.get_uuid(unique_key)).to be false
end
end
- context 'when migrating across stores' do
- before do
- stub_feature_flags(use_cluster_shared_state_for_exclusive_lease: false)
+ describe '#ttl' do
+ it 'returns the TTL of the Redis key' do
+ lease = described_class.new('kittens', timeout: 100)
+ lease.try_obtain
+
+ expect(lease.ttl <= 100).to eq(true)
end
- it_behaves_like 'read operations'
- it_behaves_like 'write operations'
- end
+ it 'returns nil when the lease does not exist' do
+ lease = described_class.new('kittens', timeout: 10)
- context 'when feature flags are all disabled' do
- before do
- stub_feature_flags(
- use_cluster_shared_state_for_exclusive_lease: false,
- enable_exclusive_lease_double_lock_rw: false
- )
+ expect(lease.ttl).to be_nil
end
-
- it_behaves_like 'read operations'
- it_behaves_like 'write operations'
end
- it_behaves_like 'read operations'
- it_behaves_like 'write operations'
-
describe '.throttle' do
it 'prevents repeated execution of the block' do
number = 0
@@ -310,8 +221,8 @@ RSpec.describe Gitlab::ExclusiveLease, :request_store, :clean_gitlab_redis_share
it 'allows count to be specified' do
expect(described_class)
.to receive(:new)
- .with(anything, hash_including(timeout: 15.minutes.to_i))
- .and_call_original
+ .with(anything, hash_including(timeout: 15.minutes.to_i))
+ .and_call_original
described_class.throttle(1, count: 4) {}
end
@@ -319,8 +230,8 @@ RSpec.describe Gitlab::ExclusiveLease, :request_store, :clean_gitlab_redis_share
it 'allows period to be specified' do
expect(described_class)
.to receive(:new)
- .with(anything, hash_including(timeout: 1.day.to_i))
- .and_call_original
+ .with(anything, hash_including(timeout: 1.day.to_i))
+ .and_call_original
described_class.throttle(1, period: 1.day) {}
end
@@ -328,80 +239,10 @@ RSpec.describe Gitlab::ExclusiveLease, :request_store, :clean_gitlab_redis_share
it 'allows period and count to be specified' do
expect(described_class)
.to receive(:new)
- .with(anything, hash_including(timeout: 30.minutes.to_i))
- .and_call_original
+ .with(anything, hash_including(timeout: 30.minutes.to_i))
+ .and_call_original
described_class.throttle(1, count: 48, period: 1.day) {}
end
end
-
- describe 'transitions between feature-flag toggles' do
- shared_examples 'retains behaviours across transitions' do |flag|
- it 'retains read behaviour' do
- lease = described_class.new(unique_key, timeout: 3600)
- uuid = lease.try_obtain
-
- expect(lease.ttl).not_to eq(nil)
- expect(lease.exists?).to be_truthy
- expect(described_class.get_uuid(unique_key)).to eq(uuid)
-
- # simulates transition
- stub_feature_flags({ flag => true })
- Gitlab::SafeRequestStore.clear!
-
- expect(lease.ttl).not_to eq(nil)
- expect(lease.exists?).to be_truthy
- expect(described_class.get_uuid(unique_key)).to eq(uuid)
- end
-
- it 'retains renew behaviour' do
- lease = described_class.new(unique_key, timeout: 3600)
- lease.try_obtain
-
- expect(lease.renew).to be_truthy
-
- # simulates transition
- stub_feature_flags({ flag => true })
- Gitlab::SafeRequestStore.clear!
-
- expect(lease.renew).to be_truthy
- end
-
- it 'retains renew behaviour' do
- lease = described_class.new(unique_key, timeout: 3600)
- uuid = lease.try_obtain
- lease.cancel
-
- # proves successful cancellation
- expect(lease.try_obtain).to eq(uuid)
-
- # simulates transition
- stub_feature_flags({ flag => true })
- Gitlab::SafeRequestStore.clear!
-
- expect(lease.try_obtain).to be_falsey
- lease.cancel
- expect(lease.try_obtain).to eq(uuid)
- end
- end
-
- context 'when enabling enable_exclusive_lease_double_lock_rw' do
- before do
- stub_feature_flags(
- enable_exclusive_lease_double_lock_rw: false,
- use_cluster_shared_state_for_exclusive_lease: false
- )
- end
-
- it_behaves_like 'retains behaviours across transitions', :enable_exclusive_lease_double_lock_rw
- end
-
- context 'when enabling use_cluster_shared_state_for_exclusive_lease' do
- before do
- stub_feature_flags(use_cluster_shared_state_for_exclusive_lease: false)
- end
-
- it_behaves_like 'retains behaviours across transitions', :use_cluster_shared_state_for_exclusive_lease
- end
- end
end