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/models/container_repository_spec.rb')
-rw-r--r--spec/models/container_repository_spec.rb327
1 files changed, 226 insertions, 101 deletions
diff --git a/spec/models/container_repository_spec.rb b/spec/models/container_repository_spec.rb
index c8d86edc55f..2ea042fb767 100644
--- a/spec/models/container_repository_spec.rb
+++ b/spec/models/container_repository_spec.rb
@@ -122,6 +122,27 @@ RSpec.describe ContainerRepository, :aggregate_failures do
expect(repository).to be_import_aborted
end
end
+
+ context 'already imported' do
+ it 'finishes the import' do
+ expect(repository).to receive(:migration_pre_import).and_return(:already_imported)
+
+ expect { subject }
+ .to change { repository.reload.migration_state }.to('import_done')
+ .and change { repository.reload.migration_skipped_reason }.to('native_import')
+ end
+ end
+
+ context 'non-existing repository' do
+ it 'finishes the import' do
+ expect(repository).to receive(:migration_pre_import).and_return(:not_found)
+
+ expect { subject }
+ .to change { repository.reload.migration_state }.to('import_done')
+ .and change { repository.migration_skipped_reason }.to('not_found')
+ .and change { repository.migration_import_done_at }.from(nil)
+ end
+ end
end
shared_examples 'transitioning to importing', skip_import_success: true do
@@ -151,6 +172,16 @@ RSpec.describe ContainerRepository, :aggregate_failures do
expect(repository).to be_import_aborted
end
end
+
+ context 'already imported' do
+ it 'finishes the import' do
+ expect(repository).to receive(:migration_import).and_return(:already_imported)
+
+ expect { subject }
+ .to change { repository.reload.migration_state }.to('import_done')
+ .and change { repository.reload.migration_skipped_reason }.to('native_import')
+ end
+ end
end
shared_examples 'transitioning out of import_aborted' do
@@ -193,7 +224,7 @@ RSpec.describe ContainerRepository, :aggregate_failures do
end
end
- it_behaves_like 'transitioning from allowed states', %w[default]
+ it_behaves_like 'transitioning from allowed states', %w[default pre_importing importing import_aborted]
it_behaves_like 'transitioning to pre_importing'
end
@@ -208,7 +239,7 @@ RSpec.describe ContainerRepository, :aggregate_failures do
end
end
- it_behaves_like 'transitioning from allowed states', %w[import_aborted]
+ it_behaves_like 'transitioning from allowed states', %w[pre_importing importing import_aborted]
it_behaves_like 'transitioning to pre_importing'
it_behaves_like 'transitioning out of import_aborted'
end
@@ -218,7 +249,7 @@ RSpec.describe ContainerRepository, :aggregate_failures do
subject { repository.finish_pre_import }
- it_behaves_like 'transitioning from allowed states', %w[pre_importing import_aborted]
+ it_behaves_like 'transitioning from allowed states', %w[pre_importing importing import_aborted]
it 'sets migration_pre_import_done_at' do
expect { subject }.to change { repository.reload.migration_pre_import_done_at }
@@ -238,7 +269,7 @@ RSpec.describe ContainerRepository, :aggregate_failures do
end
end
- it_behaves_like 'transitioning from allowed states', %w[pre_import_done]
+ it_behaves_like 'transitioning from allowed states', %w[pre_import_done pre_importing importing import_aborted]
it_behaves_like 'transitioning to importing'
end
@@ -253,7 +284,7 @@ RSpec.describe ContainerRepository, :aggregate_failures do
end
end
- it_behaves_like 'transitioning from allowed states', %w[import_aborted]
+ it_behaves_like 'transitioning from allowed states', %w[pre_importing importing import_aborted]
it_behaves_like 'transitioning to importing'
it_behaves_like 'no action when feature flag is disabled'
end
@@ -263,7 +294,7 @@ RSpec.describe ContainerRepository, :aggregate_failures do
subject { repository.finish_import }
- it_behaves_like 'transitioning from allowed states', %w[importing import_aborted]
+ it_behaves_like 'transitioning from allowed states', %w[default pre_importing importing import_aborted]
it_behaves_like 'queueing the next import'
it 'sets migration_import_done_at and queues the next import' do
@@ -302,6 +333,19 @@ RSpec.describe ContainerRepository, :aggregate_failures do
expect(repository.migration_aborted_in_state).to eq('importing')
expect(repository).to be_import_aborted
end
+
+ context 'above the max retry limit' do
+ before do
+ stub_application_setting(container_registry_import_max_retries: 1)
+ end
+
+ it 'skips the migration' do
+ expect { subject }.to change { repository.migration_skipped_at }
+
+ expect(repository.reload).to be_import_skipped
+ expect(repository.migration_skipped_reason).to eq('too_many_retries')
+ end
+ end
end
describe '#skip_import' do
@@ -309,7 +353,7 @@ RSpec.describe ContainerRepository, :aggregate_failures do
subject { repository.skip_import(reason: :too_many_retries) }
- it_behaves_like 'transitioning from allowed states', ContainerRepository::ABORTABLE_MIGRATION_STATES
+ it_behaves_like 'transitioning from allowed states', ContainerRepository::SKIPPABLE_MIGRATION_STATES
it 'sets migration_skipped_at and migration_skipped_reason' do
expect { subject }.to change { repository.reload.migration_skipped_at }
@@ -334,7 +378,7 @@ RSpec.describe ContainerRepository, :aggregate_failures do
end
end
- it_behaves_like 'transitioning from allowed states', %w[pre_importing import_aborted]
+ it_behaves_like 'transitioning from allowed states', %w[pre_importing importing import_aborted]
it_behaves_like 'transitioning to importing'
end
end
@@ -391,7 +435,7 @@ RSpec.describe ContainerRepository, :aggregate_failures do
describe '#retry_aborted_migration' do
subject { repository.retry_aborted_migration }
- shared_examples 'no action' do
+ context 'when migration_state is not aborted' do
it 'does nothing' do
expect { subject }.not_to change { repository.reload.migration_state }
@@ -399,104 +443,45 @@ RSpec.describe ContainerRepository, :aggregate_failures do
end
end
- shared_examples 'retrying the pre_import' do
- it 'retries the pre_import' do
- expect(repository).to receive(:migration_pre_import).and_return(:ok)
-
- expect { subject }.to change { repository.reload.migration_state }.to('pre_importing')
- end
- end
-
- shared_examples 'retrying the import' do
- it 'retries the import' do
- expect(repository).to receive(:migration_import).and_return(:ok)
-
- expect { subject }.to change { repository.reload.migration_state }.to('importing')
- end
- end
-
- context 'when migration_state is not aborted' do
- it_behaves_like 'no action'
- end
-
context 'when migration_state is aborted' do
before do
repository.abort_import
allow(repository.gitlab_api_client)
- .to receive(:import_status).with(repository.path).and_return(client_response)
+ .to receive(:import_status).with(repository.path).and_return(status)
end
- context 'native response' do
- let(:client_response) { 'native' }
-
- it 'raises an error' do
- expect { subject }.to raise_error(described_class::NativeImportError)
- end
- end
+ it_behaves_like 'reconciling migration_state' do
+ context 'error response' do
+ let(:status) { 'error' }
- context 'import_in_progress response' do
- let(:client_response) { 'import_in_progress' }
-
- it_behaves_like 'no action'
- end
-
- context 'import_complete response' do
- let(:client_response) { 'import_complete' }
-
- it 'finishes the import' do
- expect { subject }.to change { repository.reload.migration_state }.to('import_done')
- end
- end
-
- context 'import_failed response' do
- let(:client_response) { 'import_failed' }
-
- it_behaves_like 'retrying the import'
- end
-
- context 'pre_import_in_progress response' do
- let(:client_response) { 'pre_import_in_progress' }
-
- it_behaves_like 'no action'
- end
+ context 'migration_pre_import_done_at is NULL' do
+ it_behaves_like 'retrying the pre_import'
+ end
- context 'pre_import_complete response' do
- let(:client_response) { 'pre_import_complete' }
+ context 'migration_pre_import_done_at is not NULL' do
+ before do
+ repository.update_columns(
+ migration_pre_import_started_at: 5.minutes.ago,
+ migration_pre_import_done_at: Time.zone.now
+ )
+ end
- it 'finishes the pre_import and starts the import' do
- expect(repository).to receive(:finish_pre_import).and_call_original
- expect(repository).to receive(:migration_import).and_return(:ok)
-
- expect { subject }.to change { repository.reload.migration_state }.to('importing')
+ it_behaves_like 'retrying the import'
+ end
end
end
+ end
+ end
- context 'pre_import_failed response' do
- let(:client_response) { 'pre_import_failed' }
-
- it_behaves_like 'retrying the pre_import'
- end
-
- context 'error response' do
- let(:client_response) { 'error' }
-
- context 'migration_pre_import_done_at is NULL' do
- it_behaves_like 'retrying the pre_import'
- end
-
- context 'migration_pre_import_done_at is not NULL' do
- before do
- repository.update_columns(
- migration_pre_import_started_at: 5.minutes.ago,
- migration_pre_import_done_at: Time.zone.now
- )
- end
+ describe '#reconcile_import_status' do
+ subject { repository.reconcile_import_status(status) }
- it_behaves_like 'retrying the import'
- end
- end
+ before do
+ repository.abort_import
end
+
+ it_behaves_like 'reconciling migration_state'
end
describe '#tag' do
@@ -667,7 +652,7 @@ RSpec.describe ContainerRepository, :aggregate_failures do
context 'supports gitlab api on .com with a recent repository' do
before do
expect(repository.gitlab_api_client).to receive(:supports_gitlab_api?).and_return(true)
- expect(repository.gitlab_api_client).to receive(:repository_details).with(repository.path, with_size: true).and_return(response)
+ expect(repository.gitlab_api_client).to receive(:repository_details).with(repository.path, sizing: :self).and_return(response)
end
context 'with a size_bytes field' do
@@ -722,12 +707,12 @@ RSpec.describe ContainerRepository, :aggregate_failures do
end
context 'registry migration' do
- shared_examples 'handling the migration step' do |step|
- let(:client_response) { :foobar }
+ before do
+ allow(repository.gitlab_api_client).to receive(:supports_gitlab_api?).and_return(true)
+ end
- before do
- allow(repository.gitlab_api_client).to receive(:supports_gitlab_api?).and_return(true)
- end
+ shared_examples 'gitlab migration client request' do |step|
+ let(:client_response) { :foobar }
it 'returns the same response as the client' do
expect(repository.gitlab_api_client)
@@ -746,6 +731,10 @@ RSpec.describe ContainerRepository, :aggregate_failures do
expect(subject).to eq(:error)
end
end
+ end
+
+ shared_examples 'handling the migration step' do |step|
+ it_behaves_like 'gitlab migration client request', step
context 'too many imports' do
it 'raises an error when it receives too_many_imports as a response' do
@@ -767,6 +756,67 @@ RSpec.describe ContainerRepository, :aggregate_failures do
it_behaves_like 'handling the migration step', :import_repository
end
+
+ describe '#migration_cancel' do
+ subject { repository.migration_cancel }
+
+ it_behaves_like 'gitlab migration client request', :cancel_repository_import
+ end
+
+ describe '#force_migration_cancel' do
+ subject { repository.force_migration_cancel }
+
+ shared_examples 'returning the same response as the client' do
+ it 'returns the same response' do
+ expect(repository.gitlab_api_client)
+ .to receive(:cancel_repository_import).with(repository.path, force: true).and_return(client_response)
+
+ expect(subject).to eq(client_response)
+ end
+ end
+
+ context 'successful cancellation' do
+ let(:client_response) { { status: :ok } }
+
+ it_behaves_like 'returning the same response as the client'
+
+ it 'skips the migration' do
+ expect(repository.gitlab_api_client)
+ .to receive(:cancel_repository_import).with(repository.path, force: true).and_return(client_response)
+
+ expect { subject }.to change { repository.reload.migration_state }.to('import_skipped')
+ .and change { repository.migration_skipped_reason }.to('migration_forced_canceled')
+ .and change { repository.migration_skipped_at }
+ end
+ end
+
+ context 'failed cancellation' do
+ let(:client_response) { { status: :error } }
+
+ it_behaves_like 'returning the same response as the client'
+
+ it 'does not skip the migration' do
+ expect(repository.gitlab_api_client)
+ .to receive(:cancel_repository_import).with(repository.path, force: true).and_return(client_response)
+
+ expect { subject }.to not_change { repository.reload.migration_state }
+ .and not_change { repository.migration_skipped_reason }
+ .and not_change { repository.migration_skipped_at }
+ end
+ end
+
+ context 'when the gitlab_api feature is not supported' do
+ before do
+ allow(repository.gitlab_api_client).to receive(:supports_gitlab_api?).and_return(false)
+ end
+
+ it 'returns :error' do
+ expect(repository.gitlab_api_client).not_to receive(:cancel_repository_import)
+
+ expect(subject).to eq(:error)
+ end
+ end
+ end
end
describe '.build_from_path' do
@@ -1081,6 +1131,43 @@ RSpec.describe ContainerRepository, :aggregate_failures do
end
end
+ describe '.all_migrated?' do
+ let_it_be(:project) { create(:project) }
+
+ subject { project.container_repositories.all_migrated? }
+
+ context 'with no repositories' do
+ it { is_expected.to be_truthy }
+ end
+
+ context 'with only recent repositories' do
+ let_it_be(:container_repository1) { create(:container_repository, project: project) }
+ let_it_be_with_reload(:container_repository2) { create(:container_repository, project: project) }
+
+ it { is_expected.to be_truthy }
+
+ context 'with one old non migrated repository' do
+ before do
+ container_repository2.update!(created_at: described_class::MIGRATION_PHASE_1_ENDED_AT - 3.months)
+ end
+
+ it { is_expected.to be_falsey }
+ end
+
+ context 'with one old migrated repository' do
+ before do
+ container_repository2.update!(
+ created_at: described_class::MIGRATION_PHASE_1_ENDED_AT - 3.months,
+ migration_state: 'import_done',
+ migration_import_done_at: Time.zone.now
+ )
+ end
+
+ it { is_expected.to be_truthy }
+ end
+ end
+ end
+
describe '.with_enabled_policy' do
let_it_be(:repository) { create(:container_repository) }
let_it_be(:repository2) { create(:container_repository) }
@@ -1168,6 +1255,17 @@ RSpec.describe ContainerRepository, :aggregate_failures do
end
end
+ context 'not found response' do
+ let(:response) { :not_found }
+
+ it 'completes the migration' do
+ expect(subject).to eq(false)
+
+ expect(container_repository).to be_import_done
+ expect(container_repository.reload.migration_skipped_reason).to eq('not_found')
+ end
+ end
+
context 'other response' do
let(:response) { :error }
@@ -1185,6 +1283,30 @@ RSpec.describe ContainerRepository, :aggregate_failures do
end
end
+ describe '#retried_too_many_times?' do
+ subject { repository.retried_too_many_times? }
+
+ before do
+ stub_application_setting(container_registry_import_max_retries: 3)
+ end
+
+ context 'migration_retries_count is equal or greater than max_retries' do
+ before do
+ repository.update_column(:migration_retries_count, 3)
+ end
+
+ it { is_expected.to eq(true) }
+ end
+
+ context 'migration_retries_count is lower than max_retries' do
+ before do
+ repository.update_column(:migration_retries_count, 2)
+ end
+
+ it { is_expected.to eq(false) }
+ end
+ end
+
context 'with repositories' do
let_it_be_with_reload(:repository) { create(:container_repository, :cleanup_unscheduled) }
let_it_be(:other_repository) { create(:container_repository, :cleanup_unscheduled) }
@@ -1241,11 +1363,12 @@ RSpec.describe ContainerRepository, :aggregate_failures do
let_it_be(:import_done_repository) { create(:container_repository, :import_done, migration_pre_import_done_at: 3.days.ago, migration_import_done_at: 2.days.ago) }
let_it_be(:import_aborted_repository) { create(:container_repository, :import_aborted, migration_pre_import_done_at: 5.days.ago, migration_aborted_at: 1.day.ago) }
let_it_be(:pre_import_done_repository) { create(:container_repository, :pre_import_done, migration_pre_import_done_at: 1.hour.ago) }
+ let_it_be(:import_skipped_repository) { create(:container_repository, :import_skipped, migration_skipped_at: 90.minutes.ago) }
subject { described_class.recently_done_migration_step }
it 'returns completed imports by done_at date' do
- expect(subject.to_a).to eq([pre_import_done_repository, import_aborted_repository, import_done_repository])
+ expect(subject.to_a).to eq([pre_import_done_repository, import_skipped_repository, import_aborted_repository, import_done_repository])
end
end
@@ -1255,7 +1378,7 @@ RSpec.describe ContainerRepository, :aggregate_failures do
subject { described_class.ready_for_import }
before do
- stub_application_setting(container_registry_import_target_plan: root_group.actual_plan_name)
+ stub_application_setting(container_registry_import_target_plan: valid_container_repository.migration_plan)
end
it 'works' do
@@ -1266,13 +1389,15 @@ RSpec.describe ContainerRepository, :aggregate_failures do
describe '#last_import_step_done_at' do
let_it_be(:aborted_at) { Time.zone.now - 1.hour }
let_it_be(:pre_import_done_at) { Time.zone.now - 2.hours }
+ let_it_be(:skipped_at) { Time.zone.now - 3.hours }
subject { repository.last_import_step_done_at }
before do
repository.update_columns(
migration_pre_import_done_at: pre_import_done_at,
- migration_aborted_at: aborted_at
+ migration_aborted_at: aborted_at,
+ migration_skipped_at: skipped_at
)
end