summaryrefslogtreecommitdiff
path: root/spec/lib/gitlab/import_export
diff options
context:
space:
mode:
authorGitLab Bot <gitlab-bot@gitlab.com>2020-06-18 11:18:50 +0000
committerGitLab Bot <gitlab-bot@gitlab.com>2020-06-18 11:18:50 +0000
commit8c7f4e9d5f36cff46365a7f8c4b9c21578c1e781 (patch)
treea77e7fe7a93de11213032ed4ab1f33a3db51b738 /spec/lib/gitlab/import_export
parent00b35af3db1abfe813a778f643dad221aad51fca (diff)
downloadgitlab-ce-8c7f4e9d5f36cff46365a7f8c4b9c21578c1e781.tar.gz
Add latest changes from gitlab-org/gitlab@13-1-stable-ee
Diffstat (limited to 'spec/lib/gitlab/import_export')
-rw-r--r--spec/lib/gitlab/import_export/all_models.yml15
-rw-r--r--spec/lib/gitlab/import_export/attributes_permitter_spec.rb77
-rw-r--r--spec/lib/gitlab/import_export/import_test_coverage_spec.rb101
-rw-r--r--spec/lib/gitlab/import_export/importer_spec.rb51
-rw-r--r--spec/lib/gitlab/import_export/json/streaming_serializer_spec.rb22
-rw-r--r--spec/lib/gitlab/import_export/legacy_relation_tree_saver_spec.rb34
-rw-r--r--spec/lib/gitlab/import_export/project/relation_factory_spec.rb47
-rw-r--r--spec/lib/gitlab/import_export/project/tree_restorer_spec.rb2
-rw-r--r--spec/lib/gitlab/import_export/project/tree_saver_spec.rb2
-rw-r--r--spec/lib/gitlab/import_export/repo_restorer_spec.rb27
-rw-r--r--spec/lib/gitlab/import_export/safe_model_attributes.yml13
-rw-r--r--spec/lib/gitlab/import_export/saver_spec.rb12
-rw-r--r--spec/lib/gitlab/import_export/snippet_repo_restorer_spec.rb16
-rw-r--r--spec/lib/gitlab/import_export/snippets_repo_restorer_spec.rb83
14 files changed, 394 insertions, 108 deletions
diff --git a/spec/lib/gitlab/import_export/all_models.yml b/spec/lib/gitlab/import_export/all_models.yml
index c78b4501310..ef9321dc1fc 100644
--- a/spec/lib/gitlab/import_export/all_models.yml
+++ b/spec/lib/gitlab/import_export/all_models.yml
@@ -179,10 +179,12 @@ merge_request_context_commits:
ci_pipelines:
- project
- user
+- ci_ref
- stages
- statuses
- latest_statuses_ordered_by_stage
- builds
+- bridges
- processables
- trigger_requests
- variables
@@ -195,7 +197,7 @@ ci_pipelines:
- cancelable_statuses
- manual_actions
- scheduled_actions
-- artifacts
+- downloadable_artifacts
- pipeline_schedule
- merge_requests_as_head_pipeline
- merge_request
@@ -220,6 +222,11 @@ ci_pipelines:
- pipeline_config
- security_scans
- daily_build_group_report_results
+- latest_builds
+- daily_report_results
+ci_refs:
+- project
+- ci_pipelines
pipeline_variables:
- pipeline
stages:
@@ -236,6 +243,7 @@ statuses:
- stage
- user
- auto_canceled_by
+- needs
variables:
- project
triggers:
@@ -417,6 +425,7 @@ project:
- deploy_tokens
- settings
- ci_cd_settings
+- project_settings
- import_export_upload
- repository_languages
- pool_repository
@@ -479,6 +488,7 @@ project:
- upstream_project_subscriptions
- downstream_project_subscriptions
- service_desk_setting
+- security_setting
- import_failures
- container_expiration_policy
- resource_groups
@@ -494,6 +504,7 @@ project:
- repository_storage_moves
- freeze_periods
- webex_teams_service
+- build_report_results
award_emoji:
- awardable
- user
@@ -579,6 +590,7 @@ boards:
- board_assignee
- assignee
- labels
+- user_preferences
lists:
- user
- milestone
@@ -596,6 +608,7 @@ design: &design
- versions
- notes
- user_mentions
+- events
designs: *design
actions:
- design
diff --git a/spec/lib/gitlab/import_export/attributes_permitter_spec.rb b/spec/lib/gitlab/import_export/attributes_permitter_spec.rb
new file mode 100644
index 00000000000..d6217811b9c
--- /dev/null
+++ b/spec/lib/gitlab/import_export/attributes_permitter_spec.rb
@@ -0,0 +1,77 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+describe Gitlab::ImportExport::AttributesPermitter do
+ let(:yml_config) do
+ <<-EOF
+ tree:
+ project:
+ - labels:
+ - :priorities
+ - milestones:
+ - events:
+ - :push_event_payload
+
+ included_attributes:
+ labels:
+ - :title
+ - :description
+
+ methods:
+ labels:
+ - :type
+ EOF
+ end
+
+ let(:file) { Tempfile.new(%w(import_export .yml)) }
+ let(:config_hash) { Gitlab::ImportExport::Config.new(config: file.path).to_h }
+
+ before do
+ file.write(yml_config)
+ file.rewind
+ end
+
+ after do
+ file.close
+ file.unlink
+ end
+
+ subject { described_class.new(config: config_hash) }
+
+ describe '#permitted_attributes' do
+ it 'builds permitted attributes hash' do
+ expect(subject.permitted_attributes).to match(
+ a_hash_including(
+ project: [:labels, :milestones],
+ labels: [:priorities, :title, :description, :type],
+ events: [:push_event_payload],
+ milestones: [:events],
+ priorities: [],
+ push_event_payload: []
+ )
+ )
+ end
+ end
+
+ describe '#permit' do
+ let(:unfiltered_hash) do
+ {
+ title: 'Title',
+ description: 'Description',
+ undesired_attribute: 'Undesired Attribute',
+ another_attribute: 'Another Attribute'
+ }
+ end
+
+ it 'only allows permitted attributes' do
+ expect(subject.permit(:labels, unfiltered_hash)).to eq(title: 'Title', description: 'Description')
+ end
+ end
+
+ describe '#permitted_attributes_for' do
+ it 'returns an array of permitted attributes for a relation' do
+ expect(subject.permitted_attributes_for(:labels)).to contain_exactly(:title, :description, :type, :priorities)
+ end
+ end
+end
diff --git a/spec/lib/gitlab/import_export/import_test_coverage_spec.rb b/spec/lib/gitlab/import_export/import_test_coverage_spec.rb
index 038b95809b4..c5a7327332e 100644
--- a/spec/lib/gitlab/import_export/import_test_coverage_spec.rb
+++ b/spec/lib/gitlab/import_export/import_test_coverage_spec.rb
@@ -10,61 +10,66 @@ require 'spec_helper'
describe 'Test coverage of the Project Import' do
include ConfigurationHelper
- # `MUTED_RELATIONS` is a technical debt.
+ # `muted_relations` is a technical debt.
# This list expected to be empty or used as a workround
# in case this spec blocks an important urgent MR.
# It is also expected that adding a relation in the list should lead to
# opening a follow-up issue to fix this.
- MUTED_RELATIONS = %w[
- project.milestones.events.push_event_payload
- project.issues.events
- project.issues.events.push_event_payload
- project.issues.notes.events
- project.issues.notes.events.push_event_payload
- project.issues.milestone.events.push_event_payload
- project.issues.issue_milestones
- project.issues.issue_milestones.milestone
- project.issues.resource_label_events.label.priorities
- project.issues.designs.notes
- project.issues.designs.notes.author
- project.issues.designs.notes.events
- project.issues.designs.notes.events.push_event_payload
- project.merge_requests.metrics
- project.merge_requests.notes.events.push_event_payload
- project.merge_requests.events.push_event_payload
- project.merge_requests.timelogs
- project.merge_requests.label_links
- project.merge_requests.label_links.label
- project.merge_requests.label_links.label.priorities
- project.merge_requests.milestone
- project.merge_requests.milestone.events
- project.merge_requests.milestone.events.push_event_payload
- project.merge_requests.merge_request_milestones
- project.merge_requests.merge_request_milestones.milestone
- project.merge_requests.resource_label_events.label
- project.merge_requests.resource_label_events.label.priorities
- project.ci_pipelines.notes.events
- project.ci_pipelines.notes.events.push_event_payload
- project.protected_branches.unprotect_access_levels
- project.prometheus_metrics
- project.metrics_setting
- project.boards.lists.label.priorities
- project.service_desk_setting
- ].freeze
+ let(:muted_relations) do
+ %w[
+ project.milestones.events.push_event_payload
+ project.issues.events
+ project.issues.events.push_event_payload
+ project.issues.notes.events
+ project.issues.notes.events.push_event_payload
+ project.issues.milestone.events.push_event_payload
+ project.issues.issue_milestones
+ project.issues.issue_milestones.milestone
+ project.issues.resource_label_events.label.priorities
+ project.issues.designs.notes
+ project.issues.designs.notes.author
+ project.issues.designs.notes.events
+ project.issues.designs.notes.events.push_event_payload
+ project.merge_requests.metrics
+ project.merge_requests.notes.events.push_event_payload
+ project.merge_requests.events.push_event_payload
+ project.merge_requests.timelogs
+ project.merge_requests.label_links
+ project.merge_requests.label_links.label
+ project.merge_requests.label_links.label.priorities
+ project.merge_requests.milestone
+ project.merge_requests.milestone.events
+ project.merge_requests.milestone.events.push_event_payload
+ project.merge_requests.merge_request_milestones
+ project.merge_requests.merge_request_milestones.milestone
+ project.merge_requests.resource_label_events.label
+ project.merge_requests.resource_label_events.label.priorities
+ project.ci_pipelines.notes.events
+ project.ci_pipelines.notes.events.push_event_payload
+ project.protected_branches.unprotect_access_levels
+ project.prometheus_metrics
+ project.metrics_setting
+ project.boards.lists.label.priorities
+ project.service_desk_setting
+ project.security_setting
+ ].freeze
+ end
# A list of JSON fixture files we use to test Import.
# Most of the relations are present in `complex/project.json`
# which is our main fixture.
- PROJECT_JSON_FIXTURES = [
- 'spec/fixtures/lib/gitlab/import_export/complex/project.json',
- 'spec/fixtures/lib/gitlab/import_export/group/project.json',
- 'spec/fixtures/lib/gitlab/import_export/light/project.json',
- 'spec/fixtures/lib/gitlab/import_export/milestone-iid/project.json',
- 'spec/fixtures/lib/gitlab/import_export/designs/project.json'
- ].freeze
+ let(:project_json_fixtures) do
+ [
+ 'spec/fixtures/lib/gitlab/import_export/complex/project.json',
+ 'spec/fixtures/lib/gitlab/import_export/group/project.json',
+ 'spec/fixtures/lib/gitlab/import_export/light/project.json',
+ 'spec/fixtures/lib/gitlab/import_export/milestone-iid/project.json',
+ 'spec/fixtures/lib/gitlab/import_export/designs/project.json'
+ ].freeze
+ end
it 'ensures that all imported/exported relations are present in test JSONs' do
- not_tested_relations = (relations_from_config - tested_relations) - MUTED_RELATIONS
+ not_tested_relations = (relations_from_config - tested_relations) - muted_relations
expect(not_tested_relations).to be_empty, failure_message(not_tested_relations)
end
@@ -76,7 +81,7 @@ describe 'Test coverage of the Project Import' do
end
def tested_relations
- PROJECT_JSON_FIXTURES.flat_map(&method(:relations_from_json)).to_set
+ project_json_fixtures.flat_map(&method(:relations_from_json)).to_set
end
def relations_from_json(json_file)
@@ -106,7 +111,7 @@ describe 'Test coverage of the Project Import' do
These relations seem to be added recenty and
they expected to be covered in our Import specs: #{not_tested_relations}.
- To do that, expand one of the files listed in `PROJECT_JSON_FIXTURES`
+ To do that, expand one of the files listed in `project_json_fixtures`
(or expand the list if you consider adding a new fixture file).
After that, add a new spec into
@@ -114,7 +119,7 @@ describe 'Test coverage of the Project Import' do
to check that the relation is being imported correctly.
In case the spec breaks the master or there is a sense of urgency,
- you could include the relations into the `MUTED_RELATIONS` list.
+ you could include the relations into the `muted_relations` list.
Muting relations is considered to be a temporary solution, so please
open a follow-up issue and try to fix that when it is possible.
diff --git a/spec/lib/gitlab/import_export/importer_spec.rb b/spec/lib/gitlab/import_export/importer_spec.rb
index 60179146416..494f7e3a00d 100644
--- a/spec/lib/gitlab/import_export/importer_spec.rb
+++ b/spec/lib/gitlab/import_export/importer_spec.rb
@@ -18,6 +18,7 @@ describe Gitlab::ImportExport::Importer do
FileUtils.mkdir_p(shared.export_path)
ImportExportUpload.create(project: project, import_file: import_file)
+ allow(FileUtils).to receive(:rm_rf).and_call_original
end
after do
@@ -78,6 +79,13 @@ describe Gitlab::ImportExport::Importer do
expect(project.import_export_upload.import_file&.file).to be_nil
end
+ it 'removes tmp files' do
+ importer.execute
+
+ expect(FileUtils).to have_received(:rm_rf).with(shared.base_path)
+ expect(Dir.exist?(shared.base_path)).to eq(false)
+ end
+
it 'sets the correct visibility_level when visibility level is a string' do
project.create_or_update_import_data(
data: { override_params: { visibility_level: Gitlab::VisibilityLevel::PRIVATE.to_s } }
@@ -89,6 +97,49 @@ describe Gitlab::ImportExport::Importer do
end
end
+ context 'when import fails' do
+ let(:error_message) { 'foo' }
+
+ shared_examples 'removes any non migrated snippet' do
+ specify do
+ create_list(:project_snippet, 2, project: project)
+ snippet_with_repo = create(:project_snippet, :repository, project: project)
+
+ expect { importer.execute }.to change(Snippet, :count).by(-2).and(raise_error(Projects::ImportService::Error))
+
+ expect(snippet_with_repo.reload).to be_present
+ end
+ end
+
+ context 'when there is a graceful error' do
+ before do
+ allow_next_instance_of(Gitlab::ImportExport::AvatarRestorer) do |instance|
+ allow(instance).to receive(:avatar_export_file).and_raise(StandardError, error_message)
+ end
+ end
+
+ it 'raises and exception' do
+ expect { importer.execute }.to raise_error(Projects::ImportService::Error, error_message)
+ end
+
+ it_behaves_like 'removes any non migrated snippet'
+ end
+
+ context 'when an unexpected exception is raised' do
+ before do
+ allow_next_instance_of(Gitlab::ImportExport::AvatarRestorer) do |instance|
+ allow(instance).to receive(:restore).and_raise(StandardError, error_message)
+ end
+ end
+
+ it 'captures it and raises the Projects::ImportService::Error exception' do
+ expect { importer.execute }.to raise_error(Projects::ImportService::Error, error_message)
+ end
+
+ it_behaves_like 'removes any non migrated snippet'
+ end
+ end
+
context 'when project successfully restored' do
context "with a project in a user's namespace" do
let!(:existing_project) { create(:project, namespace: user.namespace) }
diff --git a/spec/lib/gitlab/import_export/json/streaming_serializer_spec.rb b/spec/lib/gitlab/import_export/json/streaming_serializer_spec.rb
index 076f454895f..30f8280fda3 100644
--- a/spec/lib/gitlab/import_export/json/streaming_serializer_spec.rb
+++ b/spec/lib/gitlab/import_export/json/streaming_serializer_spec.rb
@@ -95,4 +95,26 @@ describe Gitlab::ImportExport::JSON::StreamingSerializer do
end
end
end
+
+ describe '.batch_size' do
+ context 'when export_reduce_relation_batch_size feature flag is enabled' do
+ before do
+ stub_feature_flags(export_reduce_relation_batch_size: true)
+ end
+
+ it 'returns 20' do
+ expect(described_class.batch_size(exportable)).to eq(described_class::SMALLER_BATCH_SIZE)
+ end
+ end
+
+ context 'when export_reduce_relation_batch_size feature flag is disabled' do
+ before do
+ stub_feature_flags(export_reduce_relation_batch_size: false)
+ end
+
+ it 'returns default batch size' do
+ expect(described_class.batch_size(exportable)).to eq(described_class::BATCH_SIZE)
+ end
+ end
+ end
end
diff --git a/spec/lib/gitlab/import_export/legacy_relation_tree_saver_spec.rb b/spec/lib/gitlab/import_export/legacy_relation_tree_saver_spec.rb
index 958865f52a0..6562aa5b8a6 100644
--- a/spec/lib/gitlab/import_export/legacy_relation_tree_saver_spec.rb
+++ b/spec/lib/gitlab/import_export/legacy_relation_tree_saver_spec.rb
@@ -8,17 +8,35 @@ describe Gitlab::ImportExport::LegacyRelationTreeSaver do
let(:tree) { {} }
describe '#serialize' do
- let(:serializer) { instance_double(Gitlab::ImportExport::FastHashSerializer) }
+ shared_examples 'FastHashSerializer with batch size' do |batch_size|
+ let(:serializer) { instance_double(Gitlab::ImportExport::FastHashSerializer) }
- it 'uses FastHashSerializer' do
- expect(Gitlab::ImportExport::FastHashSerializer)
- .to receive(:new)
- .with(exportable, tree)
- .and_return(serializer)
+ it 'uses FastHashSerializer' do
+ expect(Gitlab::ImportExport::FastHashSerializer)
+ .to receive(:new)
+ .with(exportable, tree, batch_size: batch_size)
+ .and_return(serializer)
- expect(serializer).to receive(:execute)
+ expect(serializer).to receive(:execute)
- relation_tree_saver.serialize(exportable, tree)
+ relation_tree_saver.serialize(exportable, tree)
+ end
+ end
+
+ context 'when export_reduce_relation_batch_size feature flag is enabled' do
+ before do
+ stub_feature_flags(export_reduce_relation_batch_size: true)
+ end
+
+ include_examples 'FastHashSerializer with batch size', Gitlab::ImportExport::JSON::StreamingSerializer::SMALLER_BATCH_SIZE
+ end
+
+ context 'when export_reduce_relation_batch_size feature flag is disabled' do
+ before do
+ stub_feature_flags(export_reduce_relation_batch_size: false)
+ end
+
+ include_examples 'FastHashSerializer with batch size', Gitlab::ImportExport::JSON::StreamingSerializer::BATCH_SIZE
end
end
end
diff --git a/spec/lib/gitlab/import_export/project/relation_factory_spec.rb b/spec/lib/gitlab/import_export/project/relation_factory_spec.rb
index 175da623c1b..3339129cb8f 100644
--- a/spec/lib/gitlab/import_export/project/relation_factory_spec.rb
+++ b/spec/lib/gitlab/import_export/project/relation_factory_spec.rb
@@ -18,6 +18,22 @@ describe Gitlab::ImportExport::Project::RelationFactory do
excluded_keys: excluded_keys)
end
+ before do
+ # Mocks an ActiveRecordish object with the dodgy columns
+ stub_const('FooModel', Class.new)
+ FooModel.class_eval do
+ include ActiveModel::Model
+
+ def initialize(params = {})
+ params.each { |key, value| send("#{key}=", value) }
+ end
+
+ def values
+ instance_variables.map { |ivar| instance_variable_get(ivar) }
+ end
+ end
+ end
+
context 'hook object' do
let(:relation_sym) { :hooks }
let(:id) { 999 }
@@ -83,19 +99,6 @@ describe Gitlab::ImportExport::Project::RelationFactory do
end
end
- # Mocks an ActiveRecordish object with the dodgy columns
- class FooModel
- include ActiveModel::Model
-
- def initialize(params = {})
- params.each { |key, value| send("#{key}=", value) }
- end
-
- def values
- instance_variables.map { |ivar| instance_variable_get(ivar) }
- end
- end
-
context 'merge_request object' do
let(:relation_sym) { :merge_requests }
@@ -208,11 +211,12 @@ describe Gitlab::ImportExport::Project::RelationFactory do
}
end
- class HazardousFooModel < FooModel
- attr_accessor :service_id, :moved_to_id, :namespace_id, :ci_id, :random_project_id, :random_id, :milestone_id, :project_id
- end
-
before do
+ stub_const('HazardousFooModel', Class.new(FooModel))
+ HazardousFooModel.class_eval do
+ attr_accessor :service_id, :moved_to_id, :namespace_id, :ci_id, :random_project_id, :random_id, :milestone_id, :project_id
+ end
+
allow(HazardousFooModel).to receive(:reflect_on_association).and_return(nil)
end
@@ -246,11 +250,12 @@ describe Gitlab::ImportExport::Project::RelationFactory do
Gitlab::ImportExport::Project::RelationFactory::PROJECT_REFERENCES.map { |ref| { ref => 99 } }.inject(:merge)
end
- class ProjectFooModel < FooModel
- attr_accessor(*Gitlab::ImportExport::Project::RelationFactory::PROJECT_REFERENCES)
- end
-
before do
+ stub_const('ProjectFooModel', Class.new(FooModel))
+ ProjectFooModel.class_eval do
+ attr_accessor(*Gitlab::ImportExport::Project::RelationFactory::PROJECT_REFERENCES)
+ end
+
allow(ProjectFooModel).to receive(:reflect_on_association).and_return(nil)
end
diff --git a/spec/lib/gitlab/import_export/project/tree_restorer_spec.rb b/spec/lib/gitlab/import_export/project/tree_restorer_spec.rb
index 58589a7bbbe..867dc37c5c5 100644
--- a/spec/lib/gitlab/import_export/project/tree_restorer_spec.rb
+++ b/spec/lib/gitlab/import_export/project/tree_restorer_spec.rb
@@ -26,7 +26,7 @@ describe Gitlab::ImportExport::Project::TreeRestorer do
@project = create(:project, :builds_enabled, :issues_disabled, name: 'project', path: 'project')
@shared = @project.import_export_shared
- allow(Feature).to receive(:enabled?) { true }
+ stub_all_feature_flags
stub_feature_flags(project_import_ndjson: ndjson_enabled)
setup_import_export_config('complex')
diff --git a/spec/lib/gitlab/import_export/project/tree_saver_spec.rb b/spec/lib/gitlab/import_export/project/tree_saver_spec.rb
index b9bfe253f10..533d1097928 100644
--- a/spec/lib/gitlab/import_export/project/tree_saver_spec.rb
+++ b/spec/lib/gitlab/import_export/project/tree_saver_spec.rb
@@ -29,7 +29,7 @@ describe Gitlab::ImportExport::Project::TreeSaver do
before_all do
RSpec::Mocks.with_temporary_scope do
- allow(Feature).to receive(:enabled?) { true }
+ stub_all_feature_flags
stub_feature_flags(project_export_as_ndjson: ndjson_enabled)
project.add_maintainer(user)
diff --git a/spec/lib/gitlab/import_export/repo_restorer_spec.rb b/spec/lib/gitlab/import_export/repo_restorer_spec.rb
index a61d966bdfa..d5839589633 100644
--- a/spec/lib/gitlab/import_export/repo_restorer_spec.rb
+++ b/spec/lib/gitlab/import_export/repo_restorer_spec.rb
@@ -13,11 +13,8 @@ describe Gitlab::ImportExport::RepoRestorer do
let(:shared) { project.import_export_shared }
let(:bundler) { Gitlab::ImportExport::RepoSaver.new(project: project_with_repo, shared: shared) }
let(:bundle_path) { File.join(shared.export_path, Gitlab::ImportExport.project_bundle_filename) }
- let(:restorer) do
- described_class.new(path_to_bundle: bundle_path,
- shared: shared,
- project: project)
- end
+
+ subject { described_class.new(path_to_bundle: bundle_path, shared: shared, project: project) }
before do
allow_next_instance_of(Gitlab::ImportExport) do |instance|
@@ -36,7 +33,25 @@ describe Gitlab::ImportExport::RepoRestorer do
end
it 'restores the repo successfully' do
- expect(restorer.restore).to be_truthy
+ expect(subject.restore).to be_truthy
+ end
+
+ context 'when the repository creation fails' do
+ before do
+ allow_next_instance_of(Repositories::DestroyService) do |instance|
+ expect(instance).to receive(:execute).and_call_original
+ end
+ end
+
+ it 'logs the error' do
+ allow(project.repository)
+ .to receive(:create_from_bundle)
+ .and_raise('9:CreateRepositoryFromBundle: target directory is non-empty')
+
+ expect(shared).to receive(:error).and_call_original
+
+ expect(subject.restore).to be_falsey
+ end
end
end
end
diff --git a/spec/lib/gitlab/import_export/safe_model_attributes.yml b/spec/lib/gitlab/import_export/safe_model_attributes.yml
index c29a85ce624..0d112bfdb2a 100644
--- a/spec/lib/gitlab/import_export/safe_model_attributes.yml
+++ b/spec/lib/gitlab/import_export/safe_model_attributes.yml
@@ -144,6 +144,7 @@ Releases::Link:
- url
- name
- filepath
+- link_type
- created_at
- updated_at
ProjectMember:
@@ -471,6 +472,7 @@ Service:
- properties
- template
- instance
+- alert_events
- push_events
- issues_events
- commit_events
@@ -701,6 +703,8 @@ Badge:
- type
ProjectCiCdSetting:
- group_runners_enabled
+ProjectSetting:
+- allow_merge_on_skipped_pipeline
ProtectedEnvironment:
- id
- project_id
@@ -749,6 +753,7 @@ ProjectMetricsSetting:
- external_dashboard_url
- created_at
- updated_at
+- dashboard_timezone
Board:
- id
- project_id
@@ -861,3 +866,11 @@ SystemNoteMetadata:
- action
- created_at
- updated_at
+ProjectSecuritySetting:
+ - project_id
+ - auto_fix_container_scanning
+ - auto_fix_dast
+ - auto_fix_dependency_scanning
+ - auto_fix_sast
+ - created_at
+ - updated_at
diff --git a/spec/lib/gitlab/import_export/saver_spec.rb b/spec/lib/gitlab/import_export/saver_spec.rb
index a59cf7a1260..18e9d7da32d 100644
--- a/spec/lib/gitlab/import_export/saver_spec.rb
+++ b/spec/lib/gitlab/import_export/saver_spec.rb
@@ -5,18 +5,21 @@ require 'fileutils'
describe Gitlab::ImportExport::Saver do
let!(:project) { create(:project, :public, name: 'project') }
- let(:export_path) { "#{Dir.tmpdir}/project_tree_saver_spec" }
+ let(:base_path) { "#{Dir.tmpdir}/project_tree_saver_spec" }
+ let(:export_path) { "#{base_path}/project_tree_saver_spec/export" }
let(:shared) { project.import_export_shared }
subject { described_class.new(exportable: project, shared: shared) }
before do
+ allow(shared).to receive(:base_path).and_return(base_path)
allow_next_instance_of(Gitlab::ImportExport) do |instance|
allow(instance).to receive(:storage_path).and_return(export_path)
end
FileUtils.mkdir_p(shared.export_path)
FileUtils.touch("#{shared.export_path}/tmp.bundle")
+ allow(FileUtils).to receive(:rm_rf).and_call_original
end
after do
@@ -31,4 +34,11 @@ describe Gitlab::ImportExport::Saver do
expect(ImportExportUpload.find_by(project: project).export_file.url)
.to match(%r[\/uploads\/-\/system\/import_export_upload\/export_file.*])
end
+
+ it 'removes tmp files' do
+ subject.save
+
+ expect(FileUtils).to have_received(:rm_rf).with(base_path)
+ expect(Dir.exist?(base_path)).to eq(false)
+ end
end
diff --git a/spec/lib/gitlab/import_export/snippet_repo_restorer_spec.rb b/spec/lib/gitlab/import_export/snippet_repo_restorer_spec.rb
index 3ce950d6a64..779b65e33d8 100644
--- a/spec/lib/gitlab/import_export/snippet_repo_restorer_spec.rb
+++ b/spec/lib/gitlab/import_export/snippet_repo_restorer_spec.rb
@@ -25,16 +25,24 @@ describe Gitlab::ImportExport::SnippetRepoRestorer do
expect(snippet.repository_exists?).to be_falsey
aggregate_failures do
- expect(restorer.restore).to be_truthy
-
- expect(snippet.repository_exists?).to be_truthy
- expect(snippet.snippet_repository).not_to be_nil
+ expect do
+ expect(restorer.restore).to be_truthy
+ end.to change { SnippetRepository.count }.by(1)
blob = snippet.repository.blob_at('HEAD', snippet.file_name)
expect(blob).not_to be_nil
expect(blob.data).to eq(snippet.content)
end
end
+
+ context 'when the repository creation fails' do
+ it 'returns false' do
+ allow_any_instance_of(Gitlab::BackgroundMigration::BackfillSnippetRepositories).to receive(:perform_by_ids).and_return(nil)
+
+ expect(restorer.restore).to be false
+ expect(shared.errors.first).to match(/Error creating repository for snippet/)
+ end
+ end
end
context 'when the snippet does not have a bundle file path' do
diff --git a/spec/lib/gitlab/import_export/snippets_repo_restorer_spec.rb b/spec/lib/gitlab/import_export/snippets_repo_restorer_spec.rb
index 242f6f6b58c..fdae259c2f1 100644
--- a/spec/lib/gitlab/import_export/snippets_repo_restorer_spec.rb
+++ b/spec/lib/gitlab/import_export/snippets_repo_restorer_spec.rb
@@ -8,43 +8,92 @@ describe Gitlab::ImportExport::SnippetsRepoRestorer do
describe 'bundle a snippet Git repo' do
let_it_be(:user) { create(:user) }
let_it_be(:project) { create(:project, namespace: user.namespace) }
- let_it_be(:snippet_with_repo) { create(:project_snippet, :repository, project: project, author: user) }
- let_it_be(:snippet_without_repo) { create(:project_snippet, project: project, author: user) }
+ let!(:snippet1) { create(:project_snippet, project: project, author: user) }
+ let!(:snippet2) { create(:project_snippet, project: project, author: user) }
let(:shared) { project.import_export_shared }
let(:exporter) { Gitlab::ImportExport::SnippetsRepoSaver.new(current_user: user, project: project, shared: shared) }
let(:bundle_dir) { ::Gitlab::ImportExport.snippets_repo_bundle_path(shared.export_path) }
+ let(:service) { instance_double(Gitlab::ImportExport::SnippetRepoRestorer) }
let(:restorer) do
described_class.new(user: user,
shared: shared,
project: project)
end
- let(:service) { instance_double(Gitlab::ImportExport::SnippetRepoRestorer) }
-
- before do
- exporter.save
- end
after do
FileUtils.rm_rf(shared.export_path)
end
- it 'calls SnippetRepoRestorer per each snippet with the bundle path' do
- allow(service).to receive(:restore).and_return(true)
+ shared_examples 'imports snippet repositories' do
+ before do
+ snippet1.snippet_repository&.delete
+ snippet1.repository.remove
+
+ snippet2.snippet_repository&.delete
+ snippet2.repository.remove
+ end
+
+ specify do
+ expect(snippet1.repository_exists?).to be false
+ expect(snippet2.repository_exists?).to be false
+
+ expect(Gitlab::ImportExport::SnippetRepoRestorer).to receive(:new).with(hash_including(snippet: snippet1, path_to_bundle: bundle_path(snippet1))).and_call_original
+ expect(Gitlab::ImportExport::SnippetRepoRestorer).to receive(:new).with(hash_including(snippet: snippet2, path_to_bundle: bundle_path(snippet2))).and_call_original
+ expect(restorer.restore).to be_truthy
+
+ snippet1.repository.expire_exists_cache
+ snippet2.repository.expire_exists_cache
+
+ expect(snippet1.blobs).not_to be_empty
+ expect(snippet2.blobs).not_to be_empty
+ end
+ end
+
+ context 'when export has no snippet repository bundle' do
+ before do
+ expect(Dir.exist?(bundle_dir)).to be false
+ end
+
+ it_behaves_like 'imports snippet repositories'
+ end
+
+ context 'when export has snippet repository bundles and snippets without them' do
+ let!(:snippet1) { create(:project_snippet, :repository, project: project, author: user) }
+ let!(:snippet2) { create(:project_snippet, project: project, author: user) }
- expect(Gitlab::ImportExport::SnippetRepoRestorer).to receive(:new).with(hash_including(snippet: snippet_with_repo, path_to_bundle: bundle_path(snippet_with_repo))).and_return(service)
- expect(Gitlab::ImportExport::SnippetRepoRestorer).to receive(:new).with(hash_including(snippet: snippet_without_repo, path_to_bundle: bundle_path(snippet_without_repo))).and_return(service)
+ before do
+ exporter.save
- expect(restorer.restore).to be_truthy
+ expect(File.exist?(bundle_path(snippet1))).to be true
+ expect(File.exist?(bundle_path(snippet2))).to be false
+ end
+
+ it_behaves_like 'imports snippet repositories'
end
- context 'when one snippet cannot be saved' do
- it 'returns false and do not process other snippets' do
- allow(Gitlab::ImportExport::SnippetRepoRestorer).to receive(:new).with(hash_including(snippet: snippet_with_repo)).and_return(service)
+ context 'when export has only snippet bundles' do
+ let!(:snippet1) { create(:project_snippet, :repository, project: project, author: user) }
+ let!(:snippet2) { create(:project_snippet, :repository, project: project, author: user) }
+
+ before do
+ exporter.save
+
+ expect(File.exist?(bundle_path(snippet1))).to be true
+ expect(File.exist?(bundle_path(snippet2))).to be true
+ end
+
+ it_behaves_like 'imports snippet repositories'
+ end
+
+ context 'when any of the snippet repositories cannot be created' do
+ it 'continues processing other snippets and returns false' do
+ allow(Gitlab::ImportExport::SnippetRepoRestorer).to receive(:new).with(hash_including(snippet: snippet1)).and_return(service)
allow(service).to receive(:restore).and_return(false)
- expect(Gitlab::ImportExport::SnippetRepoRestorer).not_to receive(:new).with(hash_including(snippet: snippet_without_repo))
- expect(restorer.restore).to be_falsey
+ expect(Gitlab::ImportExport::SnippetRepoRestorer).to receive(:new).with(hash_including(snippet: snippet2)).and_call_original
+
+ expect(restorer.restore).to be false
end
end