Commit 02b1b8b8 authored by nmilojevic1's avatar nmilojevic1

Refactor specs for ndjson

- Make specs faster using let_it_be
- Move shared_examples to spec file
- Apply MR suggestions
parent c5d9f004
...@@ -7,6 +7,7 @@ describe Gitlab::ImportExport::Project::TreeSaver do ...@@ -7,6 +7,7 @@ describe Gitlab::ImportExport::Project::TreeSaver do
let_it_be(:group) { create(:group) } let_it_be(:group) { create(:group) }
let_it_be(:project) { create(:project, group: group) } let_it_be(:project) { create(:project, group: group) }
let_it_be(:issue) { create(:issue, project: project) } let_it_be(:issue) { create(:issue, project: project) }
let_it_be(:shared) { project.import_export_shared }
let_it_be(:design) { create(:design, :with_file, versions_count: 2, issue: issue) } let_it_be(:design) { create(:design, :with_file, versions_count: 2, issue: issue) }
let_it_be(:note) { create(:diff_note_on_design, noteable: design, project: project, author: user) } let_it_be(:note) { create(:diff_note_on_design, noteable: design, project: project, author: user) }
...@@ -15,16 +16,72 @@ describe Gitlab::ImportExport::Project::TreeSaver do ...@@ -15,16 +16,72 @@ describe Gitlab::ImportExport::Project::TreeSaver do
let_it_be(:epic) { create(:epic, group: group) } let_it_be(:epic) { create(:epic, group: group) }
let_it_be(:epic_issue) { create(:epic_issue, issue: issue, epic: epic) } let_it_be(:epic_issue) { create(:epic_issue, issue: issue, epic: epic) }
let(:shared) { project.import_export_shared } let_it_be(:export_path) { "#{Dir.tmpdir}/project_tree_saver_spec_ee" }
let(:export_path) { "#{Dir.tmpdir}/project_tree_saver_spec_ee" }
let(:project_tree_saver) { described_class.new(project: project, current_user: user, shared: shared) }
before do after :all do
project.add_maintainer(user) FileUtils.rm_rf(export_path)
end end
after do shared_examples 'EE saves project tree successfully' do |ndjson_enabled|
FileUtils.rm_rf(export_path) include ::ImportExport::CommonUtil
let_it_be(:project_tree_saver) { described_class.new(project: project, current_user: user, shared: shared) }
let_it_be(:full_path) do
if ndjson_enabled
File.join(shared.export_path, 'tree')
else
File.join(shared.export_path, Gitlab::ImportExport.project_filename)
end
end
let_it_be(:exportable_path) { 'project' }
before_all do
Feature.enable(:project_export_as_ndjson) if ndjson_enabled
project.add_maintainer(user)
expect(project_tree_saver.save).to be true
end
let_it_be(:issue_json) { get_json(full_path, exportable_path, :issues, ndjson_enabled).first }
describe 'the designs json' do
it 'saves issue.designs correctly' do
expect(issue_json['designs'].size).to eq(1)
end
it 'saves issue.design_versions correctly' do
actions = issue_json['design_versions'].flat_map { |v| v['actions'] }
expect(issue_json['design_versions'].size).to eq(2)
issue_json['design_versions'].each do |version|
expect(version['author_id']).to eq(issue.author_id)
end
expect(actions.size).to eq(2)
actions.each do |action|
expect(action['design']).to be_present
end
end
end
context 'epics' do
it 'has epic_issue' do
expect(issue_json['epic_issue']).not_to be_empty
expect(issue_json['epic_issue']['id']).to eql(epic_issue.id)
end
it 'has epic' do
expect(issue_json['epic_issue']['epic']['title']).to eql(epic.title)
end
it 'does not have epic_id' do
expect(issue_json['epic_issue']['epic_id']).to be_nil
end
it 'does not have issue_id' do
expect(issue_json['epic_issue']['issue_id']).to be_nil
end
end
end end
context 'with JSON' do context 'with JSON' do
......
# frozen_string_literal: true
RSpec.shared_examples 'EE saves project tree successfully' do |ndjson_enabled|
include ::ImportExport::CommonUtil
let(:full_path) do
project_tree_saver.save
if ndjson_enabled == true
File.join(shared.export_path, 'tree')
else
File.join(shared.export_path, Gitlab::ImportExport.project_filename)
end
end
let(:exportable_path) { 'project' }
before do
stub_feature_flags(project_export_as_ndjson: ndjson_enabled)
end
it 'saves successfully' do
expect(project_tree_saver.save).to be true
end
describe 'the designs json' do
let(:issue_json) { saved_relations(full_path, exportable_path, :issues, ndjson_enabled).first }
it 'saves issue.designs correctly' do
expect(issue_json['designs'].size).to eq(1)
end
it 'saves issue.design_versions correctly' do
actions = issue_json['design_versions'].flat_map { |v| v['actions'] }
expect(issue_json['design_versions'].size).to eq(2)
issue_json['design_versions'].each do |version|
expect(version['author_id']).to eq(issue.author_id)
end
expect(actions.size).to eq(2)
actions.each do |action|
expect(action['design']).to be_present
end
end
end
context 'epics' do
it 'has epic_issue' do
expect(saved_relations(full_path, exportable_path, :issues, ndjson_enabled).first['epic_issue']).not_to be_empty
expect(saved_relations(full_path, exportable_path, :issues, ndjson_enabled).first['epic_issue']['id']).to eql(epic_issue.id)
end
it 'has epic' do
expect(saved_relations(full_path, exportable_path, :issues, ndjson_enabled).first['epic_issue']['epic']['title']).to eql(epic.title)
end
it 'does not have epic_id' do
expect(saved_relations(full_path, exportable_path, :issues, ndjson_enabled).first['epic_issue']['epic_id']).to be_nil
end
it 'does not have issue_id' do
expect(saved_relations(full_path, exportable_path, :issues, ndjson_enabled).first['epic_issue']['issue_id']).to be_nil
end
end
end
...@@ -38,6 +38,27 @@ describe 'Import/Export - project export integration test', :js do ...@@ -38,6 +38,27 @@ describe 'Import/Export - project export integration test', :js do
sign_in(user) sign_in(user)
end end
shared_examples 'export file without sensitive words' do
it 'exports a project successfully', :sidekiq_inline do
export_project_and_download_file(page, project)
in_directory_with_expanded_export(project) do |exit_status, tmpdir|
expect(exit_status).to eq(0)
project_json_path = File.join(tmpdir, 'project.json')
expect(File).to exist(project_json_path)
project_hash = JSON.parse(IO.read(project_json_path))
sensitive_words.each do |sensitive_word|
found = find_sensitive_attributes(sensitive_word, project_hash)
expect(found).to be_nil, failure_message(found.try(:key_found), found.try(:parent), sensitive_word)
end
end
end
end
context "with legacy export" do context "with legacy export" do
before do before do
stub_feature_flags(streaming_serializer: false) stub_feature_flags(streaming_serializer: false)
...@@ -52,6 +73,7 @@ describe 'Import/Export - project export integration test', :js do ...@@ -52,6 +73,7 @@ describe 'Import/Export - project export integration test', :js do
stub_feature_flags(streaming_serializer: true) stub_feature_flags(streaming_serializer: true)
stub_feature_flags(project_export_as_ndjson: false) stub_feature_flags(project_export_as_ndjson: false)
end end
it_behaves_like "export file without sensitive words" it_behaves_like "export file without sensitive words"
end end
...@@ -61,19 +83,8 @@ describe 'Import/Export - project export integration test', :js do ...@@ -61,19 +83,8 @@ describe 'Import/Export - project export integration test', :js do
stub_feature_flags(project_export_as_ndjson: true) stub_feature_flags(project_export_as_ndjson: true)
end end
it 'exports a project successfully', :sidekiq_might_not_need_inline do it 'exports a project successfully', :sidekiq_inline do
visit edit_project_path(project) export_project_and_download_file(page, project)
expect(page).to have_content('Export project')
find(:link, 'Export project').send_keys(:return)
visit edit_project_path(project)
expect(page).to have_content('Download export')
expect(project.export_status).to eq(:finished)
expect(project.export_file.path).to include('tar.gz')
in_directory_with_expanded_export(project) do |exit_status, tmpdir| in_directory_with_expanded_export(project) do |exit_status, tmpdir|
expect(exit_status).to eq(0) expect(exit_status).to eq(0)
...@@ -99,23 +110,37 @@ describe 'Import/Export - project export integration test', :js do ...@@ -99,23 +110,37 @@ describe 'Import/Export - project export integration test', :js do
end end
end end
end end
end
end
def failure_message(key_found, parent, sensitive_word) def export_project_and_download_file(page, project)
<<-MSG visit edit_project_path(project)
Found a new sensitive word <#{key_found}>, which is part of the hash #{parent.inspect}
If you think this information shouldn't get exported, please exclude the model or attribute in IMPORT_EXPORT_CONFIG. expect(page).to have_content('Export project')
Otherwise, please add the exception to +safe_list+ in CURRENT_SPEC using #{sensitive_word} as the key and the find(:link, 'Export project').send_keys(:return)
correspondent hash or model as the value.
Also, if the attribute is a generated unique token, please add it to RelationFactory::TOKEN_RESET_MODELS if it needs to be visit edit_project_path(project)
reset (to prevent duplicate column problems while importing to the same instance).
IMPORT_EXPORT_CONFIG: #{Gitlab::ImportExport.config_file} expect(page).to have_content('Download export')
CURRENT_SPEC: #{__FILE__} expect(project.export_status).to eq(:finished)
MSG expect(project.export_file.path).to include('tar.gz')
end end
end
def failure_message(key_found, parent, sensitive_word)
<<-MSG
Found a new sensitive word <#{key_found}>, which is part of the hash #{parent.inspect}
If you think this information shouldn't get exported, please exclude the model or attribute in IMPORT_EXPORT_CONFIG.
Otherwise, please add the exception to +safe_list+ in CURRENT_SPEC using #{sensitive_word} as the key and the
correspondent hash or model as the value.
Also, if the attribute is a generated unique token, please add it to RelationFactory::TOKEN_RESET_MODELS if it needs to be
reset (to prevent duplicate column problems while importing to the same instance).
IMPORT_EXPORT_CONFIG: #{Gitlab::ImportExport.config_file}
CURRENT_SPEC: #{__FILE__}
MSG
end end
end end
...@@ -5,7 +5,7 @@ require "spec_helper" ...@@ -5,7 +5,7 @@ require "spec_helper"
describe Gitlab::ImportExport::JSON::NdjsonWriter do describe Gitlab::ImportExport::JSON::NdjsonWriter do
include ImportExport::CommonUtil include ImportExport::CommonUtil
let(:path) { "#{Dir.tmpdir}/legacy_writer_spec/tree" } let(:path) { "#{Dir.tmpdir}/ndjson_writer_spec/tree" }
let(:exportable_path) { 'projects' } let(:exportable_path) { 'projects' }
subject { described_class.new(path) } subject { described_class.new(path) }
......
...@@ -3,21 +3,374 @@ ...@@ -3,21 +3,374 @@
require 'spec_helper' require 'spec_helper'
describe Gitlab::ImportExport::Project::TreeSaver do describe Gitlab::ImportExport::Project::TreeSaver do
let(:shared) { project.import_export_shared } let_it_be(:export_path) { "#{Dir.tmpdir}/project_tree_saver_spec" }
let(:project_tree_saver) { described_class.new(project: project, current_user: user, shared: shared) } let_it_be(:exportable_path) { 'project' }
let(:export_path) { "#{Dir.tmpdir}/project_tree_saver_spec" }
let(:user) { create(:user) } shared_examples 'saves project tree successfully' do |ndjson_enabled|
let!(:project) { setup_project } include ImportExport::CommonUtil
before do subject { get_json(full_path, exportable_path, relation_name, ndjson_enabled) }
project.add_maintainer(user)
allow_any_instance_of(Gitlab::ImportExport).to receive(:storage_path).and_return(export_path) describe 'saves project tree attributes' do
allow_any_instance_of(MergeRequest).to receive(:source_branch_sha).and_return('ABCD') let_it_be(:user) { create(:user) }
allow_any_instance_of(MergeRequest).to receive(:target_branch_sha).and_return('DCBA') let_it_be(:group) { create(:group) }
end let_it_be(:project) { setup_project }
let_it_be(:shared) { project.import_export_shared }
let_it_be(:project_tree_saver ) { described_class.new(project: project, current_user: user, shared: shared) }
let(:relation_name) { :projects }
let_it_be(:full_path) do
if ndjson_enabled
File.join(shared.export_path, 'tree')
else
File.join(shared.export_path, Gitlab::ImportExport.project_filename)
end
end
before_all do
Feature.enable(:project_export_as_ndjson) if ndjson_enabled
project.add_maintainer(user)
project_tree_saver.save
end
after :all do
FileUtils.rm_rf(export_path)
end
context 'with project root' do
it { is_expected.to include({ 'description' => 'description', 'visibility_level' => 20 }) }
it { is_expected.not_to include("runners_token" => 'token') }
it 'has approvals_before_merge set' do
expect(subject['approvals_before_merge']).to eq(1)
end
end
context 'with milestones' do
let(:relation_name) { :milestones }
it { is_expected.not_to be_empty }
end
context 'with merge_requests' do
let(:relation_name) { :merge_requests }
it { is_expected.not_to be_empty }
it 'has merge request\'s milestones' do
expect(subject.first['milestone']).not_to be_empty
end
it 'has merge request\'s source branch SHA' do
expect(subject.first['source_branch_sha']).to eq('b83d6e391c22777fca1ed3012fce84f633d7fed0')
end
it 'has merge request\'s target branch SHA' do
expect(subject.first['target_branch_sha']).to eq('0b4bc9a49b562e85de7cc9e834518ea6828729b9')
end
it 'has events' do
expect(subject.first['milestone']['events']).not_to be_empty
end
it 'has merge requests diffs' do
expect(subject.first['merge_request_diff']).not_to be_empty
end
it 'has merge request diff files' do
expect(subject.first['merge_request_diff']['merge_request_diff_files']).not_to be_empty
end
it 'has merge request diff commits' do
expect(subject.first['merge_request_diff']['merge_request_diff_commits']).not_to be_empty
end
it 'has merge requests comments' do
expect(subject.first['notes']).not_to be_empty
end
it 'has author on merge requests comments' do
expect(subject.first['notes'].first['author']).not_to be_empty
end
it 'has merge request resource label events' do
expect(subject.first['resource_label_events']).not_to be_empty
end
end
context 'with snippets' do
let(:relation_name) { :snippets }
it { is_expected.not_to be_empty }
it 'has snippet notes' do
expect(subject.first['notes']).not_to be_empty
end
end
context 'with releases' do
let(:relation_name) { :releases }
it { is_expected.not_to be_empty }
it 'has no author on releases' do
expect(subject.first['author']).to be_nil
end
it 'has the author ID on releases' do
expect(subject.first['author_id']).not_to be_nil
end
end
context 'with issues' do
let(:relation_name) { :issues }
it { is_expected.not_to be_empty }
it 'has issue comments' do
notes = subject.first['notes']
expect(notes).not_to be_empty
expect(notes.first['type']).to eq('DiscussionNote')
end
it 'has issue assignees' do
expect(subject.first['issue_assignees']).not_to be_empty
end
it 'has author on issue comments' do
expect(subject.first['notes'].first['author']).not_to be_empty
end
it 'has labels associated to records' do
expect(subject.first['label_links'].first['label']).not_to be_empty
end
it 'has project and group labels' do
label_types = subject.first['label_links'].map { |link| link['label']['type'] }
expect(label_types).to match_array(%w(ProjectLabel GroupLabel))
end
it 'has priorities associated to labels' do
priorities = subject.first['label_links'].flat_map { |link| link['label']['priorities'] }
expect(priorities).not_to be_empty
end
it 'has issue resource label events' do
expect(subject.first['resource_label_events']).not_to be_empty
end
end
context 'with ci_pipelines' do
let(:relation_name) { :ci_pipelines }
it { is_expected.not_to be_empty }
it 'has pipeline stages' do
expect(subject.dig(0, 'stages')).not_to be_empty
end
it 'has pipeline statuses' do
expect(subject.dig(0, 'stages', 0, 'statuses')).not_to be_empty
end
it 'has pipeline builds' do
builds_count = subject.dig(0, 'stages', 0, 'statuses')
.count { |hash| hash['type'] == 'Ci::Build' }
expect(builds_count).to eq(1)
end
it 'has ci pipeline notes' do
expect(subject.first['notes']).not_to be_empty
end
end
context 'with labels' do
let(:relation_name) { :labels }
it { is_expected.not_to be_empty }
end
context 'with services' do
let(:relation_name) { :services }
it 'saves the correct service type' do
expect(subject.first['type']).to eq('CustomIssueTrackerService')
end
it 'saves the properties for a service' do
expect(subject.first['properties']).to eq('one' => 'value')
end
end
context 'with project_feature' do
let(:relation_name) { :project_feature }
it { is_expected.not_to be_empty }
it 'has project feature' do
expect(subject["issues_access_level"]).to eq(ProjectFeature::DISABLED)
expect(subject["wiki_access_level"]).to eq(ProjectFeature::ENABLED)
expect(subject["builds_access_level"]).to eq(ProjectFeature::PRIVATE)
end
end
context 'with custom_attributes' do
let(:relation_name) { :custom_attributes }
it 'has custom attributes' do
expect(subject.count).to eq(2)
end
end
context 'with badges' do
let(:relation_name) { :custom_attributes }
it 'has badges' do
expect(subject.count).to eq(2)
end
end
context 'with project_members' do
let(:relation_name) { :project_members }
it { is_expected.not_to be_empty }
end
context 'with boards' do
let(:relation_name) { :boards }
it { is_expected.not_to be_empty }
end
end
describe '#saves project tree' do
let_it_be(:user) { create(:user) }
let_it_be(:group) { create(:group) }
let(:project) { setup_project }
let(:full_path) do
if ndjson_enabled
File.join(shared.export_path, 'tree')
else
File.join(shared.export_path, Gitlab::ImportExport.project_filename)
end
end
let(:shared) { project.import_export_shared }
let(:params) { {} }
let(:project_tree_saver ) { described_class.new(project: project, current_user: user, shared: shared, params: params) }
before do
stub_feature_flags(project_export_as_ndjson: ndjson_enabled)
project.add_maintainer(user)
FileUtils.rm_rf(export_path)
end
after do
FileUtils.rm_rf(export_path)
end
context 'overrides group members' do
let(:user2) { create(:user, email: 'group@member.com') }
let(:relation_name) { :project_members }
let(:member_emails) do
emails = subject.map do |pm|
pm['user']['email']
end
emails
end
before do
group.add_developer(user2)
end
context 'when has no permission' do
before do
group.add_developer(user)
project_tree_saver.save
end
it 'does not export group members' do
expect(member_emails).not_to include('group@member.com')
end
end
context 'when has permission as maintainer' do
before do
group.add_maintainer(user)
project_tree_saver.save
end
it 'does not export group members' do
expect(member_emails).not_to include('group@member.com')
end
end
context 'when has permission as group owner' do
before do
group.add_owner(user)
project_tree_saver.save
end
it 'exports group members as group owner' do
expect(member_emails).to include('group@member.com')
end
end
context 'as admin' do
let(:user) { create(:admin) }
before do
project_tree_saver.save
end
it 'exports group members as admin' do
expect(member_emails).to include('group@member.com')
end
it 'exports group members as project members' do
member_types = subject.map { |pm| pm['source_type'] }
expect(member_types).to all(eq('Project'))
end
end
end
context 'with description override' do
let(:params) { { description: 'Foo Bar' } }
let(:relation_name) { :projects }
before do
project_tree_saver.save
end
it { is_expected.to include({ 'description' => params[:description] }) }
end
it 'saves project successfully' do
expect(project_tree_saver.save).to be true
end
it 'does not complain about non UTF-8 characters in MR diff files' do
ActiveRecord::Base.connection.execute("UPDATE merge_request_diff_files SET diff = '---\n- :diff: !binary |-\n LS0tIC9kZXYvbnVsbAorKysgYi9pbWFnZXMvbnVjb3IucGRmCkBAIC0wLDAg\n KzEsMTY3OSBAQAorJVBERi0xLjUNJeLjz9MNCisxIDAgb2JqDTw8L01ldGFk\n YXR'")
expect(project_tree_saver.save).to be true
end
it 'has no when YML attributes but only the DB column' do
expect_any_instance_of(Gitlab::Ci::YamlProcessor).not_to receive(:build_attributes)
after do project_tree_saver.save
FileUtils.rm_rf(export_path) end
end
end end
context 'with JSON' do context 'with JSON' do
...@@ -30,20 +383,17 @@ describe Gitlab::ImportExport::Project::TreeSaver do ...@@ -30,20 +383,17 @@ describe Gitlab::ImportExport::Project::TreeSaver do
def setup_project def setup_project
release = create(:release) release = create(:release)
group = create(:group)
project = create(:project, project = create(:project,
:public, :public,
:repository, :repository,
:issues_disabled, :issues_disabled,
:wiki_enabled, :wiki_enabled,
:builds_private, :builds_private,
description: 'description', description: 'description',
releases: [release], releases: [release],
group: group, group: group,
approvals_before_merge: 1 approvals_before_merge: 1)
)
allow(project).to receive(:commit).and_return(Commit.new(RepoHelpers.sample_commit, project))
issue = create(:issue, assignees: [user], project: project) issue = create(:issue, assignees: [user], project: project)
snippet = create(:project_snippet, project: project) snippet = create(:project_snippet, project: project)
...@@ -64,9 +414,9 @@ describe Gitlab::ImportExport::Project::TreeSaver do ...@@ -64,9 +414,9 @@ describe Gitlab::ImportExport::Project::TreeSaver do
mr_note = create(:note, noteable: merge_request, project: project) mr_note = create(:note, noteable: merge_request, project: project)
create(:note, noteable: snippet, project: project) create(:note, noteable: snippet, project: project)
create(:note_on_commit, create(:note_on_commit,
author: user, author: user,
project: project, project: project,
commit_id: ci_build.pipeline.sha) commit_id: ci_build.pipeline.sha)
create(:system_note_metadata, action: 'description', note: discussion_note) create(:system_note_metadata, action: 'description', note: discussion_note)
create(:system_note_metadata, commit_count: 1, action: 'commit', note: mr_note) create(:system_note_metadata, commit_count: 1, action: 'commit', note: mr_note)
......
...@@ -26,15 +26,13 @@ module ImportExport ...@@ -26,15 +26,13 @@ module ImportExport
"tmp/tests/gitlab-test/import_export" "tmp/tests/gitlab-test/import_export"
end end
def saved_relations(path, exportable_path, key, ndjson_enabled) def get_json(path, exportable_path, key, ndjson_enabled)
if ndjson_enabled == true if ndjson_enabled
json = if key == :projects json = if key == :projects
consume_attributes(path, exportable_path) consume_attributes(path, exportable_path)
else else
consume_relations(path, exportable_path, key) consume_relations(path, exportable_path, key)
end end
json = json.first if key == :project_feature
else else
json = project_json(path) json = project_json(path)
json = json[key.to_s] unless key == :projects json = json[key.to_s] unless key == :projects
...@@ -86,11 +84,11 @@ module ImportExport ...@@ -86,11 +84,11 @@ module ImportExport
relations << json relations << json
end end
relations.flatten key == :project_feature ? relations.first : relations.flatten
end end
def project_json(filename) def project_json(filename)
::JSON.parse(IO.read(filename)) ActiveSupport::JSON.decode(IO.read(filename))
end end
end end
end end
# frozen_string_literal: true
RSpec.shared_examples 'export file without sensitive words' do
it 'exports a project successfully', :sidekiq_might_not_need_inline do
visit edit_project_path(project)
expect(page).to have_content('Export project')
find(:link, 'Export project').send_keys(:return)
visit edit_project_path(project)
expect(page).to have_content('Download export')
expect(project.export_status).to eq(:finished)
expect(project.export_file.path).to include('tar.gz')
in_directory_with_expanded_export(project) do |exit_status, tmpdir|
expect(exit_status).to eq(0)
project_json_path = File.join(tmpdir, 'project.json')
expect(File).to exist(project_json_path)
project_hash = JSON.parse(IO.read(project_json_path))
sensitive_words.each do |sensitive_word|
found = find_sensitive_attributes(sensitive_word, project_hash)
expect(found).to be_nil, failure_message(found.try(:key_found), found.try(:parent), sensitive_word)
end
end
end
def failure_message(key_found, parent, sensitive_word)
<<-MSG
Found a new sensitive word <#{key_found}>, which is part of the hash #{parent.inspect}
If you think this information shouldn't get exported, please exclude the model or attribute in IMPORT_EXPORT_CONFIG.
Otherwise, please add the exception to +safe_list+ in CURRENT_SPEC using #{sensitive_word} as the key and the
correspondent hash or model as the value.
Also, if the attribute is a generated unique token, please add it to RelationFactory::TOKEN_RESET_MODELS if it needs to be
reset (to prevent duplicate column problems while importing to the same instance).
IMPORT_EXPORT_CONFIG: #{Gitlab::ImportExport.config_file}
CURRENT_SPEC: #{__FILE__}
MSG
end
end
# frozen_string_literal: true
RSpec.shared_examples 'saves project tree successfully' do |ndjson_enabled|
include ImportExport::CommonUtil
let(:full_path) do
project_tree_saver.save
if ndjson_enabled == true
File.join(shared.export_path, 'tree')
else
File.join(shared.export_path, Gitlab::ImportExport.project_filename)
end
end
let(:exportable_path) { 'project' }
before do
stub_feature_flags(project_export_as_ndjson: ndjson_enabled)
end
it 'saves project successfully' do
expect(project_tree_saver.save).to be true
end
# It is not duplicated indoes not contain the runners token
# `spec/lib/gitlab/import_export/fast_hash_serializer_spec.rb`
context 'with description override' do
let(:params) { { description: 'Foo Bar' } }
let(:project_tree_saver) { described_class.new(project: project, current_user: user, shared: shared, params: params) }
it 'overrides the project description' do
expect(saved_relations(full_path, exportable_path, :projects, ndjson_enabled)).to include({ 'description' => params[:description] })
end
end
it 'saves the correct json' do
expect(saved_relations(full_path, exportable_path, :projects, ndjson_enabled)).to include({ 'description' => 'description', 'visibility_level' => 20 })
end
it 'has approvals_before_merge set' do
expect(saved_relations(full_path, exportable_path, :projects, ndjson_enabled)['approvals_before_merge']).to eq(1)
end
it 'has milestones' do
expect(saved_relations(full_path, exportable_path, :milestones, ndjson_enabled)).not_to be_empty
end
it 'has merge requests' do
expect(saved_relations(full_path, exportable_path, :merge_requests, ndjson_enabled)).not_to be_empty
end
it 'has merge request\'s milestones' do
expect(saved_relations(full_path, exportable_path, :merge_requests, ndjson_enabled).first['milestone']).not_to be_empty
end
it 'has merge request\'s source branch SHA' do
expect(saved_relations(full_path, exportable_path, :merge_requests, ndjson_enabled).first['source_branch_sha']).to eq('ABCD')
end
it 'has merge request\'s target branch SHA' do
expect(saved_relations(full_path, exportable_path, :merge_requests, ndjson_enabled).first['target_branch_sha']).to eq('DCBA')
end
it 'has events' do
expect(saved_relations(full_path, exportable_path, :merge_requests, ndjson_enabled).first['milestone']['events']).not_to be_empty
end
it 'has snippets' do
expect(saved_relations(full_path, exportable_path, :snippets, ndjson_enabled)).not_to be_empty
end
it 'has snippet notes' do
expect(saved_relations(full_path, exportable_path, :snippets, ndjson_enabled).first['notes']).not_to be_empty
end
it 'has releases' do
expect(saved_relations(full_path, exportable_path, :releases, ndjson_enabled)).not_to be_empty
end
it 'has no author on releases' do
expect(saved_relations(full_path, exportable_path, :releases, ndjson_enabled).first['author']).to be_nil
end
it 'has the author ID on releases' do
expect(saved_relations(full_path, exportable_path, :releases, ndjson_enabled).first['author_id']).not_to be_nil
end
it 'has issues' do
expect(saved_relations(full_path, exportable_path, :issues, ndjson_enabled)).not_to be_empty
end
it 'has issue comments' do
notes = saved_relations(full_path, exportable_path, :issues, ndjson_enabled).first['notes']
expect(notes).not_to be_empty
expect(notes.first['type']).to eq('DiscussionNote')
end
it 'has issue assignees' do
expect(saved_relations(full_path, exportable_path, :issues, ndjson_enabled).first['issue_assignees']).not_to be_empty
end
it 'has author on issue comments' do
expect(saved_relations(full_path, exportable_path, :issues, ndjson_enabled).first['notes'].first['author']).not_to be_empty
end
it 'has project members' do
expect(saved_relations(full_path, exportable_path, :project_members, ndjson_enabled)).not_to be_empty
end
it 'has merge requests diffs' do
expect(saved_relations(full_path, exportable_path, :merge_requests, ndjson_enabled).first['merge_request_diff']).not_to be_empty
end
it 'has merge request diff files' do
expect(saved_relations(full_path, exportable_path, :merge_requests, ndjson_enabled).first['merge_request_diff']['merge_request_diff_files']).not_to be_empty
end
it 'has merge request diff commits' do
expect(saved_relations(full_path, exportable_path, :merge_requests, ndjson_enabled).first['merge_request_diff']['merge_request_diff_commits']).not_to be_empty
end
it 'has merge requests comments' do
expect(saved_relations(full_path, exportable_path, :merge_requests, ndjson_enabled).first['notes']).not_to be_empty
end
it 'has author on merge requests comments' do
expect(saved_relations(full_path, exportable_path, :merge_requests, ndjson_enabled).first['notes'].first['author']).not_to be_empty
end
it 'has pipeline stages' do
expect(saved_relations(full_path, exportable_path, :ci_pipelines, ndjson_enabled).dig(0, 'stages')).not_to be_empty
end
it 'has pipeline statuses' do
expect(saved_relations(full_path, exportable_path, :ci_pipelines, ndjson_enabled).dig(0, 'stages', 0, 'statuses')).not_to be_empty
end
it 'has pipeline builds' do
builds_count = saved_relations(full_path, exportable_path, :ci_pipelines, ndjson_enabled).dig(0, 'stages', 0, 'statuses')
.count { |hash| hash['type'] == 'Ci::Build' }
expect(builds_count).to eq(1)
end
it 'has no when YML attributes but only the DB column' do
expect_any_instance_of(Gitlab::Ci::YamlProcessor).not_to receive(:build_attributes)
project_tree_saver.save
end
it 'has pipeline commits' do
expect(saved_relations(full_path, exportable_path, :ci_pipelines, ndjson_enabled)).not_to be_empty
end
it 'has ci pipeline notes' do
expect(saved_relations(full_path, exportable_path, :ci_pipelines, ndjson_enabled).first['notes']).not_to be_empty
end
it 'has labels with no associations' do
expect(saved_relations(full_path, exportable_path, :labels, ndjson_enabled)).not_to be_empty
end
it 'has labels associated to records' do
expect(saved_relations(full_path, exportable_path, :issues, ndjson_enabled).first['label_links'].first['label']).not_to be_empty
end
it 'has project and group labels' do
label_types = saved_relations(full_path, exportable_path, :issues, ndjson_enabled).first['label_links'].map { |link| link['label']['type'] }
expect(label_types).to match_array(%w(ProjectLabel GroupLabel))
end
it 'has priorities associated to labels' do
priorities = saved_relations(full_path, exportable_path, :issues, ndjson_enabled).first['label_links'].flat_map { |link| link['label']['priorities'] }
expect(priorities).not_to be_empty
end
it 'has issue resource label events' do
expect(saved_relations(full_path, exportable_path, :issues, ndjson_enabled).first['resource_label_events']).not_to be_empty
end
it 'has merge request resource label events' do
expect(saved_relations(full_path, exportable_path, :merge_requests, ndjson_enabled).first['resource_label_events']).not_to be_empty
end
it 'saves the correct service type' do
expect(saved_relations(full_path, exportable_path, :services, ndjson_enabled).first['type']).to eq('CustomIssueTrackerService')
end
it 'saves the properties for a service' do
expect(saved_relations(full_path, exportable_path, :services, ndjson_enabled).first['properties']).to eq('one' => 'value')
end
it 'has project feature' do
project_feature = saved_relations(full_path, exportable_path, :project_feature, ndjson_enabled)
expect(project_feature).not_to be_empty
expect(project_feature["issues_access_level"]).to eq(ProjectFeature::DISABLED)
expect(project_feature["wiki_access_level"]).to eq(ProjectFeature::ENABLED)
expect(project_feature["builds_access_level"]).to eq(ProjectFeature::PRIVATE)
end
it 'has custom attributes' do
expect(saved_relations(full_path, exportable_path, :custom_attributes, ndjson_enabled).count).to eq(2)
end
it 'has badges' do
expect(saved_relations(full_path, exportable_path, :project_badges, ndjson_enabled).count).to eq(2)
end
it 'does not complain about non UTF-8 characters in MR diff files' do
ActiveRecord::Base.connection.execute("UPDATE merge_request_diff_files SET diff = '---\n- :diff: !binary |-\n LS0tIC9kZXYvbnVsbAorKysgYi9pbWFnZXMvbnVjb3IucGRmCkBAIC0wLDAg\n KzEsMTY3OSBAQAorJVBERi0xLjUNJeLjz9MNCisxIDAgb2JqDTw8L01ldGFk\n YXR'")
expect(project_tree_saver.save).to be true
end
context 'group members' do
let(:user2) { create(:user, email: 'group@member.com') }
let(:member_emails) do
emails = saved_relations(full_path, exportable_path, :project_members, ndjson_enabled).map do |pm|
pm['user']['email']
end
emails
end
before do
Group.first.add_developer(user2)
end
it 'does not export group members if it has no permission' do
Group.first.add_developer(user)
expect(member_emails).not_to include('group@member.com')
end
it 'does not export group members as maintainer' do
Group.first.add_maintainer(user)
expect(member_emails).not_to include('group@member.com')
end
it 'exports group members as group owner' do
Group.first.add_owner(user)
expect(member_emails).to include('group@member.com')
end
context 'as admin' do
let(:user) { create(:admin) }
it 'exports group members as admin' do
expect(member_emails).to include('group@member.com')
end
it 'exports group members as project members' do
member_types = saved_relations(full_path, exportable_path, :project_members, ndjson_enabled).map { |pm| pm['source_type'] }
expect(member_types).to all(eq('Project'))
end
end
end
context 'project attributes' do
it 'does not contain the runners token' do
expect(saved_relations(full_path, exportable_path, :projects, ndjson_enabled)).not_to include("runners_token" => 'token')
end
end
it 'has a board and a list' do
expect(saved_relations(full_path, exportable_path, :boards, ndjson_enabled).first['lists']).not_to be_empty
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