Commit b957b2b5 authored by Robert Speicher's avatar Robert Speicher

Merge branch 'ee-da-exclusive-lease-helpers' into 'master'

[EE] Add helper methods to stub Gitlab::ExclusiveLease

See merge request gitlab-org/gitlab-ee!6322
parents f6dbacb8 fd83543c
...@@ -2,6 +2,7 @@ require 'spec_helper' ...@@ -2,6 +2,7 @@ require 'spec_helper'
describe Gitlab::Geo::LogCursor::Daemon, :postgresql, :clean_gitlab_redis_shared_state do describe Gitlab::Geo::LogCursor::Daemon, :postgresql, :clean_gitlab_redis_shared_state do
include ::EE::GeoHelpers include ::EE::GeoHelpers
include ExclusiveLeaseHelpers
set(:primary) { create(:geo_node, :primary) } set(:primary) { create(:geo_node, :primary) }
set(:secondary) { create(:geo_node) } set(:secondary) { create(:geo_node) }
...@@ -37,9 +38,14 @@ describe Gitlab::Geo::LogCursor::Daemon, :postgresql, :clean_gitlab_redis_shared ...@@ -37,9 +38,14 @@ describe Gitlab::Geo::LogCursor::Daemon, :postgresql, :clean_gitlab_redis_shared
end end
it 'skips execution if cannot achieve a lease' do it 'skips execution if cannot achieve a lease' do
lease = stub_exclusive_lease_taken('geo_log_cursor_processed')
allow(lease).to receive(:try_obtain_with_ttl).and_return({ ttl: 1, uuid: false })
allow(lease).to receive(:same_uuid?).and_return(false)
allow(Gitlab::Geo::LogCursor::Lease).to receive(:exclusive_lease).and_return(lease)
is_expected.to receive(:exit?).and_return(false, true) is_expected.to receive(:exit?).and_return(false, true)
is_expected.not_to receive(:run_once!) is_expected.not_to receive(:run_once!)
expect_any_instance_of(Gitlab::ExclusiveLease).to receive(:try_obtain_with_ttl).and_return({ ttl: 1, uuid: false })
daemon.run! daemon.run!
end end
......
require 'spec_helper' require 'spec_helper'
describe Gitlab::Geo::LogCursor::Lease, :clean_gitlab_redis_shared_state do describe Gitlab::Geo::LogCursor::Lease, :clean_gitlab_redis_shared_state do
include ExclusiveLeaseHelpers
describe '.exclusive_lease' do describe '.exclusive_lease' do
it 'returns an exclusive lease instance' do it 'returns an exclusive lease instance' do
expect(described_class.send(:exclusive_lease)).to be_an_instance_of(Gitlab::ExclusiveLease) expect(described_class.send(:exclusive_lease)).to be_an_instance_of(Gitlab::ExclusiveLease)
...@@ -8,15 +10,20 @@ describe Gitlab::Geo::LogCursor::Lease, :clean_gitlab_redis_shared_state do ...@@ -8,15 +10,20 @@ describe Gitlab::Geo::LogCursor::Lease, :clean_gitlab_redis_shared_state do
end end
describe '.renew!' do describe '.renew!' do
let(:lease) { stub_exclusive_lease(described_class::LEASE_KEY, renew: true) }
before do
allow(described_class).to receive(:exclusive_lease).and_return(lease)
end
it 'returns an exclusive lease instance' do it 'returns an exclusive lease instance' do
expect_any_instance_of(Gitlab::ExclusiveLease).to receive(:renew) expect(lease).to receive(:renew)
described_class.renew! described_class.renew!
end end
it 'logs with the correct caller class' do it 'logs with the correct caller class' do
stub_const("Gitlab::Geo::LogCursor::Logger::PID", 111) stub_const("Gitlab::Geo::LogCursor::Logger::PID", 111)
allow_any_instance_of(Gitlab::ExclusiveLease).to receive(:renew).and_return(true)
expect(::Gitlab::Logger).to receive(:debug).with(pid: 111, expect(::Gitlab::Logger).to receive(:debug).with(pid: 111,
class: 'Gitlab::Geo::LogCursor::Lease', class: 'Gitlab::Geo::LogCursor::Lease',
...@@ -44,7 +51,12 @@ describe Gitlab::Geo::LogCursor::Lease, :clean_gitlab_redis_shared_state do ...@@ -44,7 +51,12 @@ describe Gitlab::Geo::LogCursor::Lease, :clean_gitlab_redis_shared_state do
end end
it 'returns > 0 if there was an error' do it 'returns > 0 if there was an error' do
expect(Gitlab::ExclusiveLease).to receive(:cancel) lease = stub_exclusive_lease(described_class::LEASE_KEY, 'uuid')
allow(lease).to receive(:try_obtain_with_ttl).and_return({ ttl: 0, uuid: 'uuid' })
allow(described_class).to receive(:exclusive_lease).and_return(lease)
expect_to_cancel_exclusive_lease(described_class::LEASE_KEY, 'uuid')
result = described_class.try_obtain_with_ttl { raise StandardError } result = described_class.try_obtain_with_ttl { raise StandardError }
......
...@@ -2,21 +2,26 @@ require 'spec_helper' ...@@ -2,21 +2,26 @@ require 'spec_helper'
describe Geo::FileDownloadService do describe Geo::FileDownloadService do
include ::EE::GeoHelpers include ::EE::GeoHelpers
include ExclusiveLeaseHelpers
set(:primary) { create(:geo_node, :primary) } set(:primary) { create(:geo_node, :primary) }
set(:secondary) { create(:geo_node) } set(:secondary) { create(:geo_node) }
before do before do
stub_current_geo_node(secondary) stub_current_geo_node(secondary)
allow_any_instance_of(Gitlab::ExclusiveLease).to receive(:try_obtain).and_return(true)
end end
shared_examples_for 'a service that downloads the file and registers the sync result' do |file_type| shared_examples_for 'a service that downloads the file and registers the sync result' do |file_type|
let(:download_service) { described_class.new(file_type, file.id) } let(:download_service) { described_class.new(file_type, file.id) }
let(:registry) { file_type == 'job_artifact' ? Geo::JobArtifactRegistry : Geo::FileRegistry } let(:registry) { file_type == 'job_artifact' ? Geo::JobArtifactRegistry : Geo::FileRegistry }
subject(:execute!) { download_service.execute } subject(:execute!) { download_service.execute }
before do
stub_exclusive_lease("file_download_service:#{file_type}:#{file.id}",
timeout: Geo::FileDownloadService::LEASE_TIMEOUT)
end
context 'for a new file' do context 'for a new file' do
context 'when the downloader fails before attempting a transfer' do context 'when the downloader fails before attempting a transfer' do
it 'logs that the download failed before attempting a transfer' do it 'logs that the download failed before attempting a transfer' do
......
...@@ -2,18 +2,18 @@ require 'spec_helper' ...@@ -2,18 +2,18 @@ require 'spec_helper'
describe Geo::FileRegistryRemovalService do describe Geo::FileRegistryRemovalService do
include ::EE::GeoHelpers include ::EE::GeoHelpers
include ExclusiveLeaseHelpers
set(:secondary) { create(:geo_node) } set(:secondary) { create(:geo_node) }
before do before do
stub_current_geo_node(secondary) stub_current_geo_node(secondary)
allow_any_instance_of(Gitlab::ExclusiveLease).to receive(:try_obtain).and_return(true)
end end
describe '#execute' do describe '#execute' do
it 'delegates log_error to the Geo logger' do it 'delegates log_error to the Geo logger' do
allow_any_instance_of(Gitlab::ExclusiveLease).to receive(:try_obtain).and_return(false) stub_exclusive_lease_taken("file_registry_removal_service:lfs:99")
expect(Gitlab::Geo::Logger).to receive(:error) expect(Gitlab::Geo::Logger).to receive(:error)
described_class.new(:lfs, 99).execute described_class.new(:lfs, 99).execute
...@@ -22,6 +22,11 @@ describe Geo::FileRegistryRemovalService do ...@@ -22,6 +22,11 @@ describe Geo::FileRegistryRemovalService do
shared_examples 'removes' do shared_examples 'removes' do
subject(:service) { described_class.new(file_registry.file_type, file_registry.file_id) } subject(:service) { described_class.new(file_registry.file_type, file_registry.file_id) }
before do
stub_exclusive_lease("file_registry_removal_service:#{file_registry.file_type}:#{file_registry.file_id}",
timeout: Geo::FileRegistryRemovalService::LEASE_TIMEOUT)
end
it 'file from disk' do it 'file from disk' do
expect do expect do
service.execute service.execute
...@@ -38,6 +43,11 @@ describe Geo::FileRegistryRemovalService do ...@@ -38,6 +43,11 @@ describe Geo::FileRegistryRemovalService do
shared_examples 'removes artifact' do shared_examples 'removes artifact' do
subject(:service) { described_class.new('job_artifact', registry.artifact_id) } subject(:service) { described_class.new('job_artifact', registry.artifact_id) }
before do
stub_exclusive_lease("file_registry_removal_service:job_artifact:#{registry.artifact_id}",
timeout: Geo::FileRegistryRemovalService::LEASE_TIMEOUT)
end
it 'file from disk' do it 'file from disk' do
expect do expect do
service.execute service.execute
......
...@@ -2,13 +2,15 @@ require 'spec_helper' ...@@ -2,13 +2,15 @@ require 'spec_helper'
describe Geo::RepositorySyncService do describe Geo::RepositorySyncService do
include ::EE::GeoHelpers include ::EE::GeoHelpers
include ExclusiveLeaseHelpers
set(:primary) { create(:geo_node, :primary) } set(:primary) { create(:geo_node, :primary) }
set(:secondary) { create(:geo_node) } set(:secondary) { create(:geo_node) }
let(:lease) { double(try_obtain: true) }
set(:project) { create(:project_empty_repo) } set(:project) { create(:project_empty_repo) }
let(:repository) { project.repository } let(:repository) { project.repository }
let(:lease_key) { "geo_sync_service:repository:#{project.id}" }
let(:lease_uuid) { 'uuid'}
subject { described_class.new(project) } subject { described_class.new(project) }
...@@ -23,7 +25,8 @@ describe Geo::RepositorySyncService do ...@@ -23,7 +25,8 @@ describe Geo::RepositorySyncService do
let(:url_to_repo) { "#{primary.url}#{project.full_path}.git" } let(:url_to_repo) { "#{primary.url}#{project.full_path}.git" }
before do before do
allow(subject).to receive(:exclusive_lease).and_return(lease) stub_exclusive_lease(lease_key, lease_uuid)
stub_exclusive_lease("geo_project_housekeeping:#{project.id}")
allow_any_instance_of(Repository).to receive(:fetch_as_mirror) allow_any_instance_of(Repository).to receive(:fetch_as_mirror)
.and_return(true) .and_return(true)
...@@ -47,8 +50,7 @@ describe Geo::RepositorySyncService do ...@@ -47,8 +50,7 @@ describe Geo::RepositorySyncService do
end end
it 'returns the lease when succeed' do it 'returns the lease when succeed' do
expect(Gitlab::ExclusiveLease).to receive(:cancel).once.with( expect_to_cancel_exclusive_lease(lease_key, lease_uuid)
subject.__send__(:lease_key), anything).and_call_original
subject.execute subject.execute
end end
...@@ -64,14 +66,13 @@ describe Geo::RepositorySyncService do ...@@ -64,14 +66,13 @@ describe Geo::RepositorySyncService do
.with(url_to_repo, remote_name: 'geo', forced: true) .with(url_to_repo, remote_name: 'geo', forced: true)
.and_raise(Gitlab::Shell::Error) .and_raise(Gitlab::Shell::Error)
expect(Gitlab::ExclusiveLease).to receive(:cancel).once.with( expect_to_cancel_exclusive_lease(lease_key, lease_uuid)
subject.__send__(:lease_key), anything).and_call_original
subject.execute subject.execute
end end
it 'does not fetch project repository if cannot obtain a lease' do it 'does not fetch project repository if cannot obtain a lease' do
allow(lease).to receive(:try_obtain) { false } stub_exclusive_lease_taken(lease_key)
expect(repository).not_to receive(:fetch_as_mirror) expect(repository).not_to receive(:fetch_as_mirror)
......
...@@ -2,13 +2,15 @@ require 'spec_helper' ...@@ -2,13 +2,15 @@ require 'spec_helper'
RSpec.describe Geo::WikiSyncService do RSpec.describe Geo::WikiSyncService do
include ::EE::GeoHelpers include ::EE::GeoHelpers
include ExclusiveLeaseHelpers
set(:primary) { create(:geo_node, :primary) } set(:primary) { create(:geo_node, :primary) }
set(:secondary) { create(:geo_node) } set(:secondary) { create(:geo_node) }
set(:project) { create(:project_empty_repo) }
let(:lease) { double(try_obtain: true, lease_key: anything ) }
let(:project) { create(:project_empty_repo) }
let(:repository) { project.wiki.repository } let(:repository) { project.wiki.repository }
let(:lease_key) { "geo_sync_service:wiki:#{project.id}" }
let(:lease_uuid) { 'uuid'}
subject { described_class.new(project) } subject { described_class.new(project) }
...@@ -23,7 +25,7 @@ RSpec.describe Geo::WikiSyncService do ...@@ -23,7 +25,7 @@ RSpec.describe Geo::WikiSyncService do
let(:url_to_repo) { "#{primary.url}#{project.full_path}.wiki.git" } let(:url_to_repo) { "#{primary.url}#{project.full_path}.wiki.git" }
before do before do
allow(subject).to receive(:exclusive_lease).and_return(lease) stub_exclusive_lease(lease_key, lease_uuid)
allow_any_instance_of(Repository).to receive(:fetch_as_mirror) allow_any_instance_of(Repository).to receive(:fetch_as_mirror)
.and_return(true) .and_return(true)
...@@ -39,8 +41,7 @@ RSpec.describe Geo::WikiSyncService do ...@@ -39,8 +41,7 @@ RSpec.describe Geo::WikiSyncService do
end end
it 'releases lease' do it 'releases lease' do
expect(Gitlab::ExclusiveLease).to receive(:cancel).at_least(:once).with( expect_to_cancel_exclusive_lease(lease_key, lease_uuid)
subject.__send__(:lease_key), anything).and_call_original
subject.execute subject.execute
end end
...@@ -52,7 +53,7 @@ RSpec.describe Geo::WikiSyncService do ...@@ -52,7 +53,7 @@ RSpec.describe Geo::WikiSyncService do
end end
it 'does not fetch wiki repository if cannot obtain a lease' do it 'does not fetch wiki repository if cannot obtain a lease' do
allow(lease).to receive(:try_obtain) { false } stub_exclusive_lease_taken(lease_key)
expect(repository).not_to receive(:fetch_as_mirror) expect(repository).not_to receive(:fetch_as_mirror)
......
...@@ -2,13 +2,18 @@ require 'spec_helper' ...@@ -2,13 +2,18 @@ require 'spec_helper'
describe Geo::PruneEventLogWorker, :geo do describe Geo::PruneEventLogWorker, :geo do
include ::EE::GeoHelpers include ::EE::GeoHelpers
include ExclusiveLeaseHelpers
subject(:worker) { described_class.new } subject(:worker) { described_class.new }
set(:primary) { create(:geo_node, :primary) } set(:primary) { create(:geo_node, :primary) }
set(:secondary) { create(:geo_node) } set(:secondary) { create(:geo_node) }
let(:lease_key) { 'geo/prune_event_log_worker' }
let(:lease_timeout) { Geo::PruneEventLogWorker::LEASE_TIMEOUT }
before do before do
allow_any_instance_of(Gitlab::ExclusiveLease).to receive(:try_obtain).and_return(true) stub_exclusive_lease(lease_key, timeout: lease_timeout)
end end
describe '#perform' do describe '#perform' do
...@@ -30,7 +35,7 @@ describe Geo::PruneEventLogWorker, :geo do ...@@ -30,7 +35,7 @@ describe Geo::PruneEventLogWorker, :geo do
end end
it 'logs error when it cannot obtain lease' do it 'logs error when it cannot obtain lease' do
allow_any_instance_of(Gitlab::ExclusiveLease).to receive(:try_obtain) { nil } stub_exclusive_lease_taken(lease_key, timeout: lease_timeout)
expect(worker).to receive(:log_error).with(/^Cannot obtain an exclusive lease/) expect(worker).to receive(:log_error).with(/^Cannot obtain an exclusive lease/)
......
...@@ -2,10 +2,12 @@ require 'spec_helper' ...@@ -2,10 +2,12 @@ require 'spec_helper'
describe Geo::RepositoriesCleanUpWorker do describe Geo::RepositoriesCleanUpWorker do
describe '#perform' do describe '#perform' do
include ExclusiveLeaseHelpers
let(:geo_node) { create(:geo_node) } let(:geo_node) { create(:geo_node) }
before do before do
allow_any_instance_of(Gitlab::ExclusiveLease).to receive(:try_obtain) { true } stub_exclusive_lease
end end
context 'when node has namespace restrictions' do context 'when node has namespace restrictions' do
...@@ -68,7 +70,7 @@ describe Geo::RepositoriesCleanUpWorker do ...@@ -68,7 +70,7 @@ describe Geo::RepositoriesCleanUpWorker do
end end
it 'does not perform GeoRepositoryDestroyWorker when cannnot obtain a lease' do it 'does not perform GeoRepositoryDestroyWorker when cannnot obtain a lease' do
allow_any_instance_of(Gitlab::ExclusiveLease).to receive(:try_obtain) { false } stub_exclusive_lease_taken
expect(GeoRepositoryDestroyWorker).not_to receive(:perform_async) expect(GeoRepositoryDestroyWorker).not_to receive(:perform_async)
......
...@@ -4,6 +4,7 @@ require 'spec_helper' ...@@ -4,6 +4,7 @@ require 'spec_helper'
# can't see changes inside a transaction of a different connection. # can't see changes inside a transaction of a different connection.
describe Geo::RepositoryShardSyncWorker, :geo, :delete, :clean_gitlab_redis_cache do describe Geo::RepositoryShardSyncWorker, :geo, :delete, :clean_gitlab_redis_cache do
include ::EE::GeoHelpers include ::EE::GeoHelpers
include ExclusiveLeaseHelpers
let!(:primary) { create(:geo_node, :primary) } let!(:primary) { create(:geo_node, :primary) }
let!(:secondary) { create(:geo_node) } let!(:secondary) { create(:geo_node) }
...@@ -25,8 +26,7 @@ describe Geo::RepositoryShardSyncWorker, :geo, :delete, :clean_gitlab_redis_cach ...@@ -25,8 +26,7 @@ describe Geo::RepositoryShardSyncWorker, :geo, :delete, :clean_gitlab_redis_cach
end end
before do before do
allow_any_instance_of(Gitlab::ExclusiveLease).to receive(:try_obtain) { true } stub_exclusive_lease(renew: true)
allow_any_instance_of(Gitlab::ExclusiveLease).to receive(:renew) { true }
Gitlab::ShardHealthCache.update([shard_name]) Gitlab::ShardHealthCache.update([shard_name])
end end
...@@ -48,6 +48,7 @@ describe Geo::RepositoryShardSyncWorker, :geo, :delete, :clean_gitlab_redis_cach ...@@ -48,6 +48,7 @@ describe Geo::RepositoryShardSyncWorker, :geo, :delete, :clean_gitlab_redis_cach
it 'does not perform Geo::ProjectSyncWorker when shard becomes unhealthy' do it 'does not perform Geo::ProjectSyncWorker when shard becomes unhealthy' do
Gitlab::ShardHealthCache.update([]) Gitlab::ShardHealthCache.update([])
expect(Geo::ProjectSyncWorker).not_to receive(:perform_async) expect(Geo::ProjectSyncWorker).not_to receive(:perform_async)
subject.perform(shard_name) subject.perform(shard_name)
......
...@@ -2,6 +2,7 @@ require 'spec_helper' ...@@ -2,6 +2,7 @@ require 'spec_helper'
describe Geo::RepositoryVerification::Primary::ShardWorker, :postgresql, :clean_gitlab_redis_cache do describe Geo::RepositoryVerification::Primary::ShardWorker, :postgresql, :clean_gitlab_redis_cache do
include ::EE::GeoHelpers include ::EE::GeoHelpers
include ExclusiveLeaseHelpers
let!(:primary) { create(:geo_node, :primary) } let!(:primary) { create(:geo_node, :primary) }
let(:shard_name) { Gitlab.config.repositories.storages.keys.first } let(:shard_name) { Gitlab.config.repositories.storages.keys.first }
...@@ -13,8 +14,7 @@ describe Geo::RepositoryVerification::Primary::ShardWorker, :postgresql, :clean_ ...@@ -13,8 +14,7 @@ describe Geo::RepositoryVerification::Primary::ShardWorker, :postgresql, :clean_
describe '#perform' do describe '#perform' do
before do before do
allow_any_instance_of(Gitlab::ExclusiveLease).to receive(:try_obtain) { true } stub_exclusive_lease(renew: true)
allow_any_instance_of(Gitlab::ExclusiveLease).to receive(:renew) { true }
Gitlab::ShardHealthCache.update([shard_name]) Gitlab::ShardHealthCache.update([shard_name])
end end
......
...@@ -2,6 +2,7 @@ require 'spec_helper' ...@@ -2,6 +2,7 @@ require 'spec_helper'
describe Geo::RepositoryVerification::Primary::SingleWorker, :postgresql, :clean_gitlab_redis_cache do describe Geo::RepositoryVerification::Primary::SingleWorker, :postgresql, :clean_gitlab_redis_cache do
include ::EE::GeoHelpers include ::EE::GeoHelpers
include ExclusiveLeaseHelpers
set(:project) { create(:project) } set(:project) { create(:project) }
...@@ -11,13 +12,10 @@ describe Geo::RepositoryVerification::Primary::SingleWorker, :postgresql, :clean ...@@ -11,13 +12,10 @@ describe Geo::RepositoryVerification::Primary::SingleWorker, :postgresql, :clean
before do before do
stub_current_geo_node(primary) stub_current_geo_node(primary)
stub_exclusive_lease
end end
describe '#perform' do describe '#perform' do
before do
allow_any_instance_of(Gitlab::ExclusiveLease).to receive(:try_obtain) { true }
end
it 'does not calculate the checksum when not running on a primary' do it 'does not calculate the checksum when not running on a primary' do
stub_project_repository(project, repository) stub_project_repository(project, repository)
stub_wiki_repository(project.wiki, wiki) stub_wiki_repository(project.wiki, wiki)
......
...@@ -2,6 +2,7 @@ require 'spec_helper' ...@@ -2,6 +2,7 @@ require 'spec_helper'
describe Geo::RepositoryVerification::Secondary::ShardWorker, :postgresql, :clean_gitlab_redis_cache do describe Geo::RepositoryVerification::Secondary::ShardWorker, :postgresql, :clean_gitlab_redis_cache do
include ::EE::GeoHelpers include ::EE::GeoHelpers
include ExclusiveLeaseHelpers
let!(:secondary) { create(:geo_node) } let!(:secondary) { create(:geo_node) }
let(:shard_name) { Gitlab.config.repositories.storages.keys.first } let(:shard_name) { Gitlab.config.repositories.storages.keys.first }
...@@ -16,8 +17,7 @@ describe Geo::RepositoryVerification::Secondary::ShardWorker, :postgresql, :clea ...@@ -16,8 +17,7 @@ describe Geo::RepositoryVerification::Secondary::ShardWorker, :postgresql, :clea
describe '#perform' do describe '#perform' do
before do before do
allow_any_instance_of(Gitlab::ExclusiveLease).to receive(:try_obtain) { true } stub_exclusive_lease(renew: true)
allow_any_instance_of(Gitlab::ExclusiveLease).to receive(:renew) { true }
Gitlab::ShardHealthCache.update([shard_name]) Gitlab::ShardHealthCache.update([shard_name])
end end
......
...@@ -2,6 +2,7 @@ require 'spec_helper' ...@@ -2,6 +2,7 @@ require 'spec_helper'
describe Geo::RepositoryVerification::Secondary::SingleWorker, :postgresql, :clean_gitlab_redis_cache do describe Geo::RepositoryVerification::Secondary::SingleWorker, :postgresql, :clean_gitlab_redis_cache do
include ::EE::GeoHelpers include ::EE::GeoHelpers
include ExclusiveLeaseHelpers
let!(:secondary) { create(:geo_node) } let!(:secondary) { create(:geo_node) }
let(:project) { create(:project, :repository, :wiki_repo) } let(:project) { create(:project, :repository, :wiki_repo) }
...@@ -9,13 +10,10 @@ describe Geo::RepositoryVerification::Secondary::SingleWorker, :postgresql, :cle ...@@ -9,13 +10,10 @@ describe Geo::RepositoryVerification::Secondary::SingleWorker, :postgresql, :cle
before do before do
stub_current_geo_node(secondary) stub_current_geo_node(secondary)
stub_exclusive_lease
end end
describe '#perform' do describe '#perform' do
before do
allow_any_instance_of(Gitlab::ExclusiveLease).to receive(:try_obtain) { true }
end
it 'does not calculate the checksum when not running on a secondary' do it 'does not calculate the checksum when not running on a secondary' do
allow(Gitlab::Geo).to receive(:secondary?) { false } allow(Gitlab::Geo).to receive(:secondary?) { false }
......
require 'rails_helper' require 'rails_helper'
describe RepositoryUpdateMirrorWorker do describe RepositoryUpdateMirrorWorker do
include ExclusiveLeaseHelpers
describe '#perform' do describe '#perform' do
let(:jid) { '12345678' } let(:jid) { '12345678' }
let!(:project) { create(:project) } let!(:project) { create(:project) }
let!(:import_state) { create(:import_state, :mirror, :scheduled, project: project) } let!(:import_state) { create(:import_state, :mirror, :scheduled, project: project) }
before do before do
allow_any_instance_of(Gitlab::ExclusiveLease).to receive(:try_obtain).and_return(true)
allow(subject).to receive(:jid).and_return(jid) allow(subject).to receive(:jid).and_return(jid)
end end
...@@ -56,6 +57,10 @@ describe RepositoryUpdateMirrorWorker do ...@@ -56,6 +57,10 @@ describe RepositoryUpdateMirrorWorker do
end end
context 'when we obtain the lease' do context 'when we obtain the lease' do
before do
allow(stub_exclusive_lease).to receive(:exists?).and_return(false)
end
it 'performs UpdateAllMirrorsWorker when reschedule_immediately? returns true' do it 'performs UpdateAllMirrorsWorker when reschedule_immediately? returns true' do
allow(Gitlab::Mirror).to receive(:reschedule_immediately?).and_return(true) allow(Gitlab::Mirror).to receive(:reschedule_immediately?).and_return(true)
...@@ -74,7 +79,7 @@ describe RepositoryUpdateMirrorWorker do ...@@ -74,7 +79,7 @@ describe RepositoryUpdateMirrorWorker do
end end
it 'does not perform UpdateAllMirrorsWorker when we cannot obtain the lease' do it 'does not perform UpdateAllMirrorsWorker when we cannot obtain the lease' do
allow_any_instance_of(Gitlab::ExclusiveLease).to receive(:try_obtain).and_return(false) stub_exclusive_lease_taken
expect(UpdateAllMirrorsWorker).not_to receive(:perform_async) expect(UpdateAllMirrorsWorker).not_to receive(:perform_async)
...@@ -82,7 +87,7 @@ describe RepositoryUpdateMirrorWorker do ...@@ -82,7 +87,7 @@ describe RepositoryUpdateMirrorWorker do
end end
it 'does not perform UpdateAllMirrorsWorker when the lease already exists' do it 'does not perform UpdateAllMirrorsWorker when the lease already exists' do
allow_any_instance_of(Gitlab::ExclusiveLease).to receive(:exists?).and_return(true) stub_exclusive_lease_taken
expect(UpdateAllMirrorsWorker).not_to receive(:perform_async) expect(UpdateAllMirrorsWorker).not_to receive(:perform_async)
......
require 'spec_helper' require 'spec_helper'
describe UpdateAllMirrorsWorker do describe UpdateAllMirrorsWorker do
include ExclusiveLeaseHelpers
subject(:worker) { described_class.new } subject(:worker) { described_class.new }
before do before do
allow_any_instance_of(Gitlab::ExclusiveLease).to receive(:try_obtain).and_return(true) stub_exclusive_lease
end end
describe '#perform' do describe '#perform' do
it 'does not execute if cannot get the lease' do it 'does not execute if cannot get the lease' do
create(:project, :mirror) stub_exclusive_lease_taken
allow_any_instance_of(Gitlab::ExclusiveLease).to receive(:try_obtain).and_return(false)
expect(worker).not_to receive(:schedule_mirrors!) expect(worker).not_to receive(:schedule_mirrors!)
......
require 'spec_helper' require 'spec_helper'
describe Mattermost::Session, type: :request do describe Mattermost::Session, type: :request do
include ExclusiveLeaseHelpers
let(:user) { create(:user) } let(:user) { create(:user) }
let(:gitlab_url) { "http://gitlab.com" } let(:gitlab_url) { "http://gitlab.com" }
...@@ -97,26 +99,20 @@ describe Mattermost::Session, type: :request do ...@@ -97,26 +99,20 @@ describe Mattermost::Session, type: :request do
end end
end end
context 'with lease' do context 'exclusive lease' do
before do let(:lease_key) { 'mattermost:session' }
allow(subject).to receive(:lease_try_obtain).and_return('aldkfjsldfk')
end
it 'tries to obtain a lease' do it 'tries to obtain a lease' do
expect(subject).to receive(:lease_try_obtain) expect_to_obtain_exclusive_lease(lease_key, 'uuid')
expect(Gitlab::ExclusiveLease).to receive(:cancel) expect_to_cancel_exclusive_lease(lease_key, 'uuid')
# Cannot setup a session, but we should still cancel the lease # Cannot setup a session, but we should still cancel the lease
expect { subject.with_session }.to raise_error(Mattermost::NoSessionError) expect { subject.with_session }.to raise_error(Mattermost::NoSessionError)
end end
end
context 'without lease' do it 'returns a NoSessionError error without lease' do
before do stub_exclusive_lease_taken(lease_key)
allow(subject).to receive(:lease_try_obtain).and_return(nil)
end
it 'returns a NoSessionError error' do
expect { subject.with_session }.to raise_error(Mattermost::NoSessionError) expect { subject.with_session }.to raise_error(Mattermost::NoSessionError)
end end
end end
......
require 'spec_helper' require 'spec_helper'
describe Ci::BuildTraceChunk, :clean_gitlab_redis_shared_state do describe Ci::BuildTraceChunk, :clean_gitlab_redis_shared_state do
include ExclusiveLeaseHelpers
set(:build) { create(:ci_build, :running) } set(:build) { create(:ci_build, :running) }
let(:chunk_index) { 0 } let(:chunk_index) { 0 }
let(:data_store) { :redis } let(:data_store) { :redis }
...@@ -322,7 +324,7 @@ describe Ci::BuildTraceChunk, :clean_gitlab_redis_shared_state do ...@@ -322,7 +324,7 @@ describe Ci::BuildTraceChunk, :clean_gitlab_redis_shared_state do
describe 'ExclusiveLock' do describe 'ExclusiveLock' do
before do before do
allow_any_instance_of(Gitlab::ExclusiveLease).to receive(:try_obtain) { nil } stub_exclusive_lease_taken
stub_const('Ci::BuildTraceChunk::WRITE_LOCK_RETRY', 1) stub_const('Ci::BuildTraceChunk::WRITE_LOCK_RETRY', 1)
end end
......
require 'spec_helper' require 'spec_helper'
describe ReactiveCaching, :use_clean_rails_memory_store_caching do describe ReactiveCaching, :use_clean_rails_memory_store_caching do
include ExclusiveLeaseHelpers
include ReactiveCachingHelpers include ReactiveCachingHelpers
class CacheTest class CacheTest
...@@ -106,8 +107,8 @@ describe ReactiveCaching, :use_clean_rails_memory_store_caching do ...@@ -106,8 +107,8 @@ describe ReactiveCaching, :use_clean_rails_memory_store_caching do
end end
it 'takes and releases the lease' do it 'takes and releases the lease' do
expect_any_instance_of(Gitlab::ExclusiveLease).to receive(:try_obtain).and_return("000000") expect_to_obtain_exclusive_lease(cache_key, 'uuid')
expect(Gitlab::ExclusiveLease).to receive(:cancel).with(cache_key, "000000") expect_to_cancel_exclusive_lease(cache_key, 'uuid')
go! go!
end end
...@@ -160,11 +161,9 @@ describe ReactiveCaching, :use_clean_rails_memory_store_caching do ...@@ -160,11 +161,9 @@ describe ReactiveCaching, :use_clean_rails_memory_store_caching do
end end
context 'when the lease is already taken' do context 'when the lease is already taken' do
before do
expect_any_instance_of(Gitlab::ExclusiveLease).to receive(:try_obtain).and_return(nil)
end
it 'skips the calculation' do it 'skips the calculation' do
stub_exclusive_lease_taken(cache_key)
expect(instance).to receive(:calculate_reactive_cache).never expect(instance).to receive(:calculate_reactive_cache).never
go! go!
......
require 'spec_helper' require 'spec_helper'
describe Clusters::Applications::CheckIngressIpAddressService do describe Clusters::Applications::CheckIngressIpAddressService do
include ExclusiveLeaseHelpers
let(:application) { create(:clusters_applications_ingress, :installed) } let(:application) { create(:clusters_applications_ingress, :installed) }
let(:service) { described_class.new(application) } let(:service) { described_class.new(application) }
let(:kubeclient) { double(::Kubeclient::Client, get_service: kube_service) } let(:kubeclient) { double(::Kubeclient::Client, get_service: kube_service) }
let(:ingress) { [{ ip: '111.222.111.222' }] } let(:ingress) { [{ ip: '111.222.111.222' }] }
let(:exclusive_lease) { instance_double(Gitlab::ExclusiveLease, try_obtain: true) } let(:lease_key) { "check_ingress_ip_address_service:#{application.id}" }
let(:kube_service) do let(:kube_service) do
::Kubeclient::Resource.new( ::Kubeclient::Resource.new(
...@@ -22,11 +24,8 @@ describe Clusters::Applications::CheckIngressIpAddressService do ...@@ -22,11 +24,8 @@ describe Clusters::Applications::CheckIngressIpAddressService do
subject { service.execute } subject { service.execute }
before do before do
stub_exclusive_lease(lease_key, timeout: 15.seconds.to_i)
allow(application.cluster).to receive(:kubeclient).and_return(kubeclient) allow(application.cluster).to receive(:kubeclient).and_return(kubeclient)
allow(Gitlab::ExclusiveLease)
.to receive(:new)
.with("check_ingress_ip_address_service:#{application.id}", timeout: 15.seconds.to_i)
.and_return(exclusive_lease)
end end
describe '#execute' do describe '#execute' do
...@@ -47,13 +46,9 @@ describe Clusters::Applications::CheckIngressIpAddressService do ...@@ -47,13 +46,9 @@ describe Clusters::Applications::CheckIngressIpAddressService do
end end
context 'when the exclusive lease cannot be obtained' do context 'when the exclusive lease cannot be obtained' do
before do
allow(exclusive_lease)
.to receive(:try_obtain)
.and_return(false)
end
it 'does not call kubeclient' do it 'does not call kubeclient' do
stub_exclusive_lease_taken(lease_key, timeout: 15.seconds.to_i)
subject subject
expect(kubeclient).not_to have_received(:get_service) expect(kubeclient).not_to have_received(:get_service)
......
require 'spec_helper' require 'spec_helper'
describe Users::RefreshAuthorizedProjectsService do describe Users::RefreshAuthorizedProjectsService do
include ExclusiveLeaseHelpers
# We're using let! here so that any expectations for the service class are not # We're using let! here so that any expectations for the service class are not
# triggered twice. # triggered twice.
let!(:project) { create(:project) } let!(:project) { create(:project) }
...@@ -10,12 +12,10 @@ describe Users::RefreshAuthorizedProjectsService do ...@@ -10,12 +12,10 @@ describe Users::RefreshAuthorizedProjectsService do
describe '#execute', :clean_gitlab_redis_shared_state do describe '#execute', :clean_gitlab_redis_shared_state do
it 'refreshes the authorizations using a lease' do it 'refreshes the authorizations using a lease' do
expect_any_instance_of(Gitlab::ExclusiveLease).to receive(:try_obtain) lease_key = "refresh_authorized_projects:#{user.id}"
.and_return('foo')
expect(Gitlab::ExclusiveLease).to receive(:cancel)
.with(an_instance_of(String), 'foo')
expect_to_obtain_exclusive_lease(lease_key, 'uuid')
expect_to_cancel_exclusive_lease(lease_key, 'uuid')
expect(service).to receive(:execute_without_lease) expect(service).to receive(:execute_without_lease)
service.execute service.execute
......
module ExclusiveLeaseHelpers
def stub_exclusive_lease(key = nil, uuid = 'uuid', renew: false, timeout: nil)
key ||= instance_of(String)
timeout ||= instance_of(Integer)
lease = instance_double(
Gitlab::ExclusiveLease,
try_obtain: uuid,
exists?: true,
renew: renew
)
allow(Gitlab::ExclusiveLease)
.to receive(:new)
.with(key, timeout: timeout)
.and_return(lease)
lease
end
def stub_exclusive_lease_taken(key = nil, timeout: nil)
stub_exclusive_lease(key, nil, timeout: timeout)
end
def expect_to_obtain_exclusive_lease(key, uuid = 'uuid', timeout: nil)
lease = stub_exclusive_lease(key, uuid, timeout: timeout)
expect(lease).to receive(:try_obtain)
end
def expect_to_cancel_exclusive_lease(key, uuid)
expect(Gitlab::ExclusiveLease)
.to receive(:cancel)
.with(key, uuid)
end
end
...@@ -247,8 +247,10 @@ shared_examples_for 'common trace features' do ...@@ -247,8 +247,10 @@ shared_examples_for 'common trace features' do
end end
context 'when another process has already been archiving', :clean_gitlab_redis_shared_state do context 'when another process has already been archiving', :clean_gitlab_redis_shared_state do
include ExclusiveLeaseHelpers
before do before do
Gitlab::ExclusiveLease.new("trace:archive:#{trace.job.id}", timeout: 1.hour).try_obtain stub_exclusive_lease_taken("trace:archive:#{trace.job.id}", timeout: 1.hour)
end end
it 'blocks concurrent archiving' do it 'blocks concurrent archiving' do
......
...@@ -76,8 +76,10 @@ shared_examples "migrates" do |to_store:, from_store: nil| ...@@ -76,8 +76,10 @@ shared_examples "migrates" do |to_store:, from_store: nil|
end end
context 'when migrate! is occupied by another process' do context 'when migrate! is occupied by another process' do
include ExclusiveLeaseHelpers
before do before do
@uuid = Gitlab::ExclusiveLease.new(subject.exclusive_lease_key, timeout: 1.hour.to_i).try_obtain stub_exclusive_lease_taken(subject.exclusive_lease_key, timeout: 1.hour.to_i)
end end
it 'does not execute migrate!' do it 'does not execute migrate!' do
...@@ -91,10 +93,6 @@ shared_examples "migrates" do |to_store:, from_store: nil| ...@@ -91,10 +93,6 @@ shared_examples "migrates" do |to_store:, from_store: nil|
expect { subject.use_file }.to raise_error(ObjectStorage::ExclusiveLeaseTaken) expect { subject.use_file }.to raise_error(ObjectStorage::ExclusiveLeaseTaken)
end end
after do
Gitlab::ExclusiveLease.cancel(subject.exclusive_lease_key, @uuid)
end
end end
context 'migration is unsuccessful' do context 'migration is unsuccessful' do
......
require 'spec_helper' require 'spec_helper'
describe ProjectCacheWorker do describe ProjectCacheWorker do
include ExclusiveLeaseHelpers
let(:worker) { described_class.new } let(:worker) { described_class.new }
let(:project) { create(:project, :repository) } let(:project) { create(:project, :repository) }
let(:statistics) { project.statistics } let(:statistics) { project.statistics }
let(:lease_key) { "project_cache_worker:#{project.id}:update_statistics" }
let(:lease_timeout) { ProjectCacheWorker::LEASE_TIMEOUT }
describe '#perform' do describe '#perform' do
before do before do
allow_any_instance_of(Gitlab::ExclusiveLease).to receive(:try_obtain) stub_exclusive_lease(lease_key, timeout: lease_timeout)
.and_return(true)
end end
context 'with a non-existing project' do context 'with a non-existing project' do
...@@ -79,9 +82,7 @@ describe ProjectCacheWorker do ...@@ -79,9 +82,7 @@ describe ProjectCacheWorker do
describe '#update_statistics' do describe '#update_statistics' do
context 'when a lease could not be obtained' do context 'when a lease could not be obtained' do
it 'does not update the repository size' do it 'does not update the repository size' do
allow(worker).to receive(:try_obtain_lease_for) stub_exclusive_lease_taken(lease_key, timeout: lease_timeout)
.with(project.id, :update_statistics)
.and_return(false)
expect(statistics).not_to receive(:refresh!) expect(statistics).not_to receive(:refresh!)
...@@ -91,9 +92,7 @@ describe ProjectCacheWorker do ...@@ -91,9 +92,7 @@ describe ProjectCacheWorker do
context 'when a lease could be obtained' do context 'when a lease could be obtained' do
it 'updates the project statistics' do it 'updates the project statistics' do
allow(worker).to receive(:try_obtain_lease_for) stub_exclusive_lease(lease_key, timeout: lease_timeout)
.with(project.id, :update_statistics)
.and_return(true)
expect(statistics).to receive(:refresh!) expect(statistics).to receive(:refresh!)
.with(only: %i(repository_size)) .with(only: %i(repository_size))
......
require 'spec_helper' require 'spec_helper'
describe ProjectMigrateHashedStorageWorker, :clean_gitlab_redis_shared_state do describe ProjectMigrateHashedStorageWorker, :clean_gitlab_redis_shared_state do
include ExclusiveLeaseHelpers
describe '#perform' do describe '#perform' do
let(:project) { create(:project, :empty_repo) } let(:project) { create(:project, :empty_repo) }
let(:pending_delete_project) { create(:project, :empty_repo, pending_delete: true) } let(:lease_key) { "project_migrate_hashed_storage_worker:#{project.id}" }
let(:lease_timeout) { ProjectMigrateHashedStorageWorker::LEASE_TIMEOUT }
it 'skips when project no longer exists' do
expect(::Projects::HashedStorageMigrationService).not_to receive(:new)
subject.perform(-1)
end
context 'when have exclusive lease' do it 'skips when project is pending delete' do
before do pending_delete_project = create(:project, :empty_repo, pending_delete: true)
lease = subject.lease_for(project.id)
allow(Gitlab::ExclusiveLease).to receive(:new).and_return(lease) expect(::Projects::HashedStorageMigrationService).not_to receive(:new)
allow(lease).to receive(:try_obtain).and_return(true)
end
it 'skips when project no longer exists' do subject.perform(pending_delete_project.id)
nonexistent_id = 999999999999 end
expect(::Projects::HashedStorageMigrationService).not_to receive(:new) it 'delegates removal to service class when have exclusive lease' do
subject.perform(nonexistent_id) stub_exclusive_lease(lease_key, 'uuid', timeout: lease_timeout)
end
it 'skips when project is pending delete' do migration_service = spy
expect(::Projects::HashedStorageMigrationService).not_to receive(:new)
subject.perform(pending_delete_project.id) allow(::Projects::HashedStorageMigrationService)
end .to receive(:new).with(project, subject.logger)
.and_return(migration_service)
it 'delegates removal to service class' do subject.perform(project.id)
service = double('service')
expect(::Projects::HashedStorageMigrationService).to receive(:new).with(project, subject.logger).and_return(service)
expect(service).to receive(:execute)
subject.perform(project.id) expect(migration_service).to have_received(:execute)
end
end end
context 'when dont have exclusive lease' do it 'skips when dont have lease when dont have exclusive lease' do
before do stub_exclusive_lease_taken(lease_key, timeout: lease_timeout)
lease = subject.lease_for(project.id)
allow(Gitlab::ExclusiveLease).to receive(:new).and_return(lease)
allow(lease).to receive(:try_obtain).and_return(false)
end
it 'skips when dont have lease' do expect(::Projects::HashedStorageMigrationService).not_to receive(:new)
expect(::Projects::HashedStorageMigrationService).not_to receive(:new)
subject.perform(project.id) subject.perform(project.id)
end
end end
end end
end end
require 'spec_helper' require 'spec_helper'
describe PropagateServiceTemplateWorker do describe PropagateServiceTemplateWorker do
let!(:service_template) do include ExclusiveLeaseHelpers
PushoverService.create(
template: true,
active: true,
properties: {
device: 'MyDevice',
sound: 'mic',
priority: 4,
user_key: 'asdf',
api_key: '123456789'
})
end
before do
allow_any_instance_of(Gitlab::ExclusiveLease).to receive(:try_obtain)
.and_return(true)
end
describe '#perform' do describe '#perform' do
it 'calls the propagate service with the template' do it 'calls the propagate service with the template' do
expect(Projects::PropagateServiceTemplate).to receive(:propagate).with(service_template) template = PushoverService.create(
template: true,
active: true,
properties: {
device: 'MyDevice',
sound: 'mic',
priority: 4,
user_key: 'asdf',
api_key: '123456789'
})
stub_exclusive_lease("propagate_service_template_worker:#{template.id}",
timeout: PropagateServiceTemplateWorker::LEASE_TIMEOUT)
expect(Projects::PropagateServiceTemplate)
.to receive(:propagate)
.with(template)
subject.perform(service_template.id) subject.perform(template.id)
end end
end end
end end
require 'rails_helper' require 'rails_helper'
describe RepositoryRemoveRemoteWorker do describe RepositoryRemoveRemoteWorker do
subject(:worker) { described_class.new } include ExclusiveLeaseHelpers
describe '#perform' do describe '#perform' do
let(:remote_name) { 'joe'}
let!(:project) { create(:project, :repository) } let!(:project) { create(:project, :repository) }
let(:remote_name) { 'joe'}
let(:lease_key) { "remove_remote_#{project.id}_#{remote_name}" }
let(:lease_timeout) { RepositoryRemoveRemoteWorker::LEASE_TIMEOUT }
context 'when it cannot obtain lease' do it 'returns nil when project does not exist' do
it 'logs error' do expect(subject.perform(-1, 'remote_name')).to be_nil
allow_any_instance_of(Gitlab::ExclusiveLease).to receive(:try_obtain) { nil }
expect_any_instance_of(Repository).not_to receive(:remove_remote)
expect(worker).to receive(:log_error).with('Cannot obtain an exclusive lease. There must be another instance already in execution.')
worker.perform(project.id, remote_name)
end
end end
context 'when it gets the lease' do context 'when project exists' do
before do before do
allow_any_instance_of(Gitlab::ExclusiveLease).to receive(:try_obtain).and_return(true) allow(Project)
.to receive(:find_by)
.with(id: project.id)
.and_return(project)
end end
context 'when project does not exist' do it 'does not remove remote when cannot obtain lease' do
it 'returns nil' do stub_exclusive_lease_taken(lease_key, timeout: lease_timeout)
expect(worker.perform(-1, 'remote_name')).to be_nil
end expect(project.repository)
end .not_to receive(:remove_remote)
context 'when project exists' do expect(subject)
it 'removes remote from repository' do .to receive(:log_error)
masterrev = project.repository.find_branch('master').dereferenced_target .with('Cannot obtain an exclusive lease. There must be another instance already in execution.')
create_remote_branch(remote_name, 'remote_branch', masterrev) subject.perform(project.id, remote_name)
end
expect_any_instance_of(Repository).to receive(:remove_remote).with(remote_name).and_call_original it 'removes remote from repository when obtain a lease' do
stub_exclusive_lease(lease_key, timeout: lease_timeout)
masterrev = project.repository.find_branch('master').dereferenced_target
create_remote_branch(remote_name, 'remote_branch', masterrev)
worker.perform(project.id, remote_name) expect(project.repository)
end .to receive(:remove_remote)
.with(remote_name)
.and_call_original
subject.perform(project.id, remote_name)
end end
end end
end end
...@@ -47,6 +53,7 @@ describe RepositoryRemoveRemoteWorker do ...@@ -47,6 +53,7 @@ describe RepositoryRemoveRemoteWorker do
rugged = Gitlab::GitalyClient::StorageSettings.allow_disk_access do rugged = Gitlab::GitalyClient::StorageSettings.allow_disk_access do
project.repository.rugged project.repository.rugged
end end
rugged.references.create("refs/remotes/#{remote_name}/#{branch_name}", target.id) rugged.references.create("refs/remotes/#{remote_name}/#{branch_name}", target.id)
end end
end end
require 'spec_helper' require 'spec_helper'
describe StuckCiJobsWorker do describe StuckCiJobsWorker do
include ExclusiveLeaseHelpers
let!(:runner) { create :ci_runner } let!(:runner) { create :ci_runner }
let!(:job) { create :ci_build, runner: runner } let!(:job) { create :ci_build, runner: runner }
let(:worker) { described_class.new } let(:trace_lease_key) { "trace:archive:#{job.id}" }
let(:exclusive_lease_uuid) { SecureRandom.uuid } let(:trace_lease_uuid) { SecureRandom.uuid }
let(:worker_lease_key) { StuckCiJobsWorker::EXCLUSIVE_LEASE_KEY }
let(:worker_lease_uuid) { SecureRandom.uuid }
subject(:worker) { described_class.new }
before do before do
stub_exclusive_lease(worker_lease_key, worker_lease_uuid)
stub_exclusive_lease(trace_lease_key, trace_lease_uuid)
job.update!(status: status, updated_at: updated_at) job.update!(status: status, updated_at: updated_at)
allow_any_instance_of(Gitlab::ExclusiveLease).to receive(:try_obtain).and_return(exclusive_lease_uuid)
end end
shared_examples 'job is dropped' do shared_examples 'job is dropped' do
...@@ -44,16 +51,19 @@ describe StuckCiJobsWorker do ...@@ -44,16 +51,19 @@ describe StuckCiJobsWorker do
context 'when job was not updated for more than 1 day ago' do context 'when job was not updated for more than 1 day ago' do
let(:updated_at) { 2.days.ago } let(:updated_at) { 2.days.ago }
it_behaves_like 'job is dropped' it_behaves_like 'job is dropped'
end end
context 'when job was updated in less than 1 day ago' do context 'when job was updated in less than 1 day ago' do
let(:updated_at) { 6.hours.ago } let(:updated_at) { 6.hours.ago }
it_behaves_like 'job is unchanged' it_behaves_like 'job is unchanged'
end end
context 'when job was not updated for more than 1 hour ago' do context 'when job was not updated for more than 1 hour ago' do
let(:updated_at) { 2.hours.ago } let(:updated_at) { 2.hours.ago }
it_behaves_like 'job is unchanged' it_behaves_like 'job is unchanged'
end end
end end
...@@ -65,11 +75,14 @@ describe StuckCiJobsWorker do ...@@ -65,11 +75,14 @@ describe StuckCiJobsWorker do
context 'when job was not updated for more than 1 hour ago' do context 'when job was not updated for more than 1 hour ago' do
let(:updated_at) { 2.hours.ago } let(:updated_at) { 2.hours.ago }
it_behaves_like 'job is dropped' it_behaves_like 'job is dropped'
end end
context 'when job was updated in less than 1 hour ago' do context 'when job was updated in less than 1
hour ago' do
let(:updated_at) { 30.minutes.ago } let(:updated_at) { 30.minutes.ago }
it_behaves_like 'job is unchanged' it_behaves_like 'job is unchanged'
end end
end end
...@@ -80,11 +93,13 @@ describe StuckCiJobsWorker do ...@@ -80,11 +93,13 @@ describe StuckCiJobsWorker do
context 'when job was not updated for more than 1 hour ago' do context 'when job was not updated for more than 1 hour ago' do
let(:updated_at) { 2.hours.ago } let(:updated_at) { 2.hours.ago }
it_behaves_like 'job is dropped' it_behaves_like 'job is dropped'
end end
context 'when job was updated in less than 1 hour ago' do context 'when job was updated in less than 1 hour ago' do
let(:updated_at) { 30.minutes.ago } let(:updated_at) { 30.minutes.ago }
it_behaves_like 'job is unchanged' it_behaves_like 'job is unchanged'
end end
end end
...@@ -93,6 +108,7 @@ describe StuckCiJobsWorker do ...@@ -93,6 +108,7 @@ describe StuckCiJobsWorker do
context "when job is #{status}" do context "when job is #{status}" do
let(:status) { status } let(:status) { status }
let(:updated_at) { 2.days.ago } let(:updated_at) { 2.days.ago }
it_behaves_like 'job is unchanged' it_behaves_like 'job is unchanged'
end end
end end
...@@ -119,23 +135,27 @@ describe StuckCiJobsWorker do ...@@ -119,23 +135,27 @@ describe StuckCiJobsWorker do
it 'is guard by exclusive lease when executed concurrently' do it 'is guard by exclusive lease when executed concurrently' do
expect(worker).to receive(:drop).at_least(:once).and_call_original expect(worker).to receive(:drop).at_least(:once).and_call_original
expect(worker2).not_to receive(:drop) expect(worker2).not_to receive(:drop)
worker.perform worker.perform
allow_any_instance_of(Gitlab::ExclusiveLease).to receive(:try_obtain).and_return(false)
stub_exclusive_lease_taken(worker_lease_key)
worker2.perform worker2.perform
end end
it 'can be executed in sequence' do it 'can be executed in sequence' do
expect(worker).to receive(:drop).at_least(:once).and_call_original expect(worker).to receive(:drop).at_least(:once).and_call_original
expect(worker2).to receive(:drop).at_least(:once).and_call_original expect(worker2).to receive(:drop).at_least(:once).and_call_original
worker.perform worker.perform
worker2.perform worker2.perform
end end
it 'cancels exclusive lease after worker perform' do it 'cancels exclusive leases after worker perform' do
worker.perform expect_to_cancel_exclusive_lease(trace_lease_key, trace_lease_uuid)
expect_to_cancel_exclusive_lease(worker_lease_key, worker_lease_uuid)
expect(Gitlab::ExclusiveLease.new(described_class::EXCLUSIVE_LEASE_KEY, timeout: 1.hour)) worker.perform
.not_to be_exists
end end
end end
end end
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment