diff options
author | GitLab Bot <gitlab-bot@gitlab.com> | 2020-05-20 17:34:42 +0300 |
---|---|---|
committer | GitLab Bot <gitlab-bot@gitlab.com> | 2020-05-20 17:34:42 +0300 |
commit | 9f46488805e86b1bc341ea1620b866016c2ce5ed (patch) | |
tree | f9748c7e287041e37d6da49e0a29c9511dc34768 /spec/lib/gitlab/import_export/group | |
parent | dfc92d081ea0332d69c8aca2f0e745cb48ae5e6d (diff) |
Add latest changes from gitlab-org/gitlab@13-0-stable-ee
Diffstat (limited to 'spec/lib/gitlab/import_export/group')
3 files changed, 325 insertions, 1 deletions
diff --git a/spec/lib/gitlab/import_export/group/legacy_tree_restorer_spec.rb b/spec/lib/gitlab/import_export/group/legacy_tree_restorer_spec.rb index 3030cdf4cf8..4c926da1436 100644 --- a/spec/lib/gitlab/import_export/group/legacy_tree_restorer_spec.rb +++ b/spec/lib/gitlab/import_export/group/legacy_tree_restorer_spec.rb @@ -141,7 +141,7 @@ describe Gitlab::ImportExport::Group::LegacyTreeRestorer do let(:filepath) { "group_exports/visibility_levels/#{visibility_level}" } it "imports all subgroups as #{visibility_level}" do - expect(group.children.map(&:visibility_level)).to eq(expected_visibilities) + expect(group.children.map(&:visibility_level)).to match_array(expected_visibilities) end end end diff --git a/spec/lib/gitlab/import_export/group/tree_restorer_spec.rb b/spec/lib/gitlab/import_export/group/tree_restorer_spec.rb new file mode 100644 index 00000000000..327f36c664e --- /dev/null +++ b/spec/lib/gitlab/import_export/group/tree_restorer_spec.rb @@ -0,0 +1,184 @@ +# frozen_string_literal: true + +require 'spec_helper' + +describe Gitlab::ImportExport::Group::TreeRestorer do + include ImportExport::CommonUtil + + describe 'restore group tree' do + before_all do + # Using an admin for import, so we can check assignment of existing members + user = create(:admin, email: 'root@gitlabexample.com') + create(:user, email: 'adriene.mcclure@gitlabexample.com') + create(:user, email: 'gwendolyn_robel@gitlabexample.com') + + RSpec::Mocks.with_temporary_scope do + @group = create(:group, name: 'group', path: 'group') + @shared = Gitlab::ImportExport::Shared.new(@group) + + setup_import_export_config('group_exports/complex') + + group_tree_restorer = described_class.new(user: user, shared: @shared, group: @group) + + expect(group_tree_restorer.restore).to be_truthy + end + end + + it 'has the group description' do + expect(Group.find_by_path('group').description).to eq('Group Description') + end + + it 'has group labels' do + expect(@group.labels.count).to eq(10) + end + + context 'issue boards' do + it 'has issue boards' do + expect(@group.boards.count).to eq(1) + end + + it 'has board label lists' do + lists = @group.boards.find_by(name: 'first board').lists + + expect(lists.count).to eq(3) + expect(lists.first.label.title).to eq('TSL') + expect(lists.second.label.title).to eq('Sosync') + end + end + + it 'has badges' do + expect(@group.badges.count).to eq(1) + end + + it 'has milestones' do + expect(@group.milestones.count).to eq(5) + end + + it 'has group children' do + expect(@group.children.count).to eq(2) + end + + it 'has group members' do + expect(@group.members.map(&:user).map(&:email)).to contain_exactly( + 'root@gitlabexample.com', + 'adriene.mcclure@gitlabexample.com', + 'gwendolyn_robel@gitlabexample.com' + ) + end + end + + context 'child with no parent' do + let(:user) { create(:user) } + let(:group) { create(:group) } + let(:shared) { Gitlab::ImportExport::Shared.new(group) } + let(:group_tree_restorer) { described_class.new(user: user, shared: shared, group: group) } + + before do + setup_import_export_config('group_exports/child_with_no_parent') + + expect(group_tree_restorer.restore).to be_falsey + end + + it 'fails when a child group does not have a valid parent_id' do + expect(shared.errors).to include('Parent group not found') + end + end + + context 'excluded attributes' do + let!(:source_user) { create(:user, id: 123) } + let!(:importer_user) { create(:user) } + let(:group) { create(:group, name: 'user-inputed-name', path: 'user-inputed-path') } + let(:shared) { Gitlab::ImportExport::Shared.new(group) } + let(:group_tree_restorer) { described_class.new(user: importer_user, shared: shared, group: group) } + let(:exported_file) { File.join(shared.export_path, 'tree/groups/4352.json') } + let(:group_json) { ActiveSupport::JSON.decode(IO.read(exported_file)) } + + shared_examples 'excluded attributes' do + excluded_attributes = %w[ + id + parent_id + owner_id + created_at + updated_at + runners_token + runners_token_encrypted + saml_discovery_token + ] + + before do + group.add_owner(importer_user) + + setup_import_export_config('group_exports/complex') + + expect(File.exist?(exported_file)).to be_truthy + + group_tree_restorer.restore + group.reload + end + + it 'does not import root group name' do + expect(group.name).to eq('user-inputed-name') + end + + it 'does not import root group path' do + expect(group.path).to eq('user-inputed-path') + end + + excluded_attributes.each do |excluded_attribute| + it 'does not allow override of excluded attributes' do + unless group.public_send(excluded_attribute).nil? + expect(group_json[excluded_attribute]).not_to eq(group.public_send(excluded_attribute)) + end + end + end + end + + include_examples 'excluded attributes' + end + + context 'group.json file access check' do + let(:user) { create(:user) } + let!(:group) { create(:group, name: 'group2', path: 'group2') } + let(:shared) { Gitlab::ImportExport::Shared.new(group) } + let(:group_tree_restorer) { described_class.new(user: user, shared: shared, group: group) } + + it 'does not read a symlink' do + Dir.mktmpdir do |tmpdir| + FileUtils.mkdir_p(File.join(tmpdir, 'tree', 'groups')) + setup_symlink(tmpdir, 'tree/groups/_all.ndjson') + + allow(shared).to receive(:export_path).and_return(tmpdir) + + expect(group_tree_restorer.restore).to eq(false) + expect(shared.errors).to include('Incorrect JSON format') + end + end + end + + context 'group visibility levels' do + let(:user) { create(:user) } + let(:shared) { Gitlab::ImportExport::Shared.new(group) } + let(:group_tree_restorer) { described_class.new(user: user, shared: shared, group: group) } + + before do + setup_import_export_config(filepath) + + group_tree_restorer.restore + end + + shared_examples 'with visibility level' do |visibility_level, expected_visibilities| + context "when visibility level is #{visibility_level}" do + let(:group) { create(:group, visibility_level) } + let(:filepath) { "group_exports/visibility_levels/#{visibility_level}" } + + it "imports all subgroups as #{visibility_level}" do + expect(group.children.map(&:visibility_level)).to eq(expected_visibilities) + end + end + end + + include_examples 'with visibility level', :public, [20, 10, 0] + include_examples 'with visibility level', :private, [0, 0, 0] + include_examples 'with visibility level', :internal, [10, 10, 0] + end +end diff --git a/spec/lib/gitlab/import_export/group/tree_saver_spec.rb b/spec/lib/gitlab/import_export/group/tree_saver_spec.rb new file mode 100644 index 00000000000..06e8484a3cb --- /dev/null +++ b/spec/lib/gitlab/import_export/group/tree_saver_spec.rb @@ -0,0 +1,140 @@ +# frozen_string_literal: true + +require 'spec_helper' + +describe Gitlab::ImportExport::Group::TreeSaver do + describe 'saves the group tree into a json object' do + let_it_be(:user) { create(:user) } + let_it_be(:group) { setup_groups } + + let(:shared) { Gitlab::ImportExport::Shared.new(group) } + let(:export_path) { "#{Dir.tmpdir}/group_tree_saver_spec" } + + subject(:group_tree_saver) { described_class.new(group: group, current_user: user, shared: shared) } + + before_all do + group.add_maintainer(user) + end + + before do + allow_next_instance_of(Gitlab::ImportExport) do |import_export| + allow(import_export).to receive(:storage_path).and_return(export_path) + end + end + + after do + FileUtils.rm_rf(export_path) + end + + it 'saves the group successfully' do + expect(group_tree_saver.save).to be true + end + + it 'fails to export a group' do + allow_next_instance_of(Gitlab::ImportExport::JSON::NdjsonWriter) do |ndjson_writer| + allow(ndjson_writer).to receive(:write_relation_array).and_raise(RuntimeError, 'exception') + end + + expect(shared).to receive(:error).with(RuntimeError).and_call_original + + expect(group_tree_saver.save).to be false + end + + context 'exported files' do + before do + group_tree_saver.save + end + + it 'has one group per line' do + groups_catalog = + File.readlines(exported_path_for('_all.ndjson')) + .map { |line| Integer(line) } + + expect(groups_catalog.size).to eq(3) + expect(groups_catalog).to eq([ + group.id, + group.descendants.first.id, + group.descendants.first.descendants.first.id + ]) + end + + it 'has a file per group' do + group.self_and_descendants.pluck(:id).each do |id| + group_attributes_file = exported_path_for("#{id}.json") + + expect(File.exist?(group_attributes_file)).to be(true) + end + end + + context 'group attributes file' do + let(:group_attributes_file) { exported_path_for("#{group.id}.json") } + let(:group_attributes) { ::JSON.parse(File.read(group_attributes_file)) } + + it 'has a file for each group with its attributes' do + expect(group_attributes['description']).to eq(group.description) + expect(group_attributes['parent_id']).to eq(group.parent_id) + end + + shared_examples 'excluded attributes' do + excluded_attributes = %w[ + owner_id + created_at + updated_at + runners_token + runners_token_encrypted + saml_discovery_token + ] + + excluded_attributes.each do |excluded_attribute| + it 'does not contain excluded attribute' do + expect(group_attributes).not_to include(excluded_attribute => group.public_send(excluded_attribute)) + end + end + end + + include_examples 'excluded attributes' + end + + it 'has a file for each group association' do + group.self_and_descendants do |g| + %w[ + badges + boards + epics + labels + members + milestones + ].each do |association| + path = exported_path_for("#{g.id}", "#{association}.ndjson") + expect(File.exist?(path)).to eq(true), "#{path} does not exist" + end + end + end + end + end + + def exported_path_for(*file) + File.join(group_tree_saver.full_path, 'groups', *file) + end + + def setup_groups + root = setup_group + subgroup = setup_group(parent: root) + setup_group(parent: subgroup) + + root + end + + def setup_group(parent: nil) + group = create(:group, description: 'description', parent: parent) + create(:milestone, group: group) + create(:group_badge, group: group) + group_label = create(:group_label, group: group) + board = create(:board, group: group, milestone_id: Milestone::Upcoming.id) + create(:list, board: board, label: group_label) + create(:group_badge, group: group) + create(:label_priority, label: group_label, priority: 1) + + group + end +end |