diff options
Diffstat (limited to 'spec/lib/gitlab')
3 files changed, 133 insertions, 4 deletions
diff --git a/spec/lib/gitlab/import_export/project/exported_relations_merger_spec.rb b/spec/lib/gitlab/import_export/project/exported_relations_merger_spec.rb new file mode 100644 index 00000000000..a781139acab --- /dev/null +++ b/spec/lib/gitlab/import_export/project/exported_relations_merger_spec.rb @@ -0,0 +1,75 @@ +# frozen_string_literal: true + +require 'spec_helper' + +RSpec.describe Gitlab::ImportExport::Project::ExportedRelationsMerger do + let(:export_job) { create(:project_export_job) } + + let(:shared) { Gitlab::ImportExport::Shared.new(export_job.project) } + + before do + create(:project_relation_export_upload, + relation_export: create(:project_relation_export, relation: 'project', project_export_job: export_job), + export_file: fixture_file_upload("spec/fixtures/gitlab/import_export/project.tar.gz") + ) + + create(:project_relation_export_upload, + relation_export: create(:project_relation_export, relation: 'labels', project_export_job: export_job), + export_file: fixture_file_upload("spec/fixtures/gitlab/import_export/labels.tar.gz") + ) + + create(:project_relation_export_upload, + relation_export: create(:project_relation_export, relation: 'uploads', project_export_job: export_job), + export_file: fixture_file_upload("spec/fixtures/gitlab/import_export/uploads.tar.gz") + ) + end + + describe '#save' do + subject(:service) { described_class.new(export_job: export_job, shared: shared) } + + it 'downloads, extracts, and merges all files into export_path' do + Dir.mktmpdir do |dirpath| + allow(shared).to receive(:export_path).and_return(dirpath) + + result = service.save + + expect(result).to eq(true) + expect(Dir.glob("#{dirpath}/**/*")).to match_array( + [ + "#{dirpath}/project", + "#{dirpath}/project/project.json", + "#{dirpath}/project/labels.ndjson", + "#{dirpath}/uploads", + "#{dirpath}/uploads/70edb596c34ad7795baa6a0f0aa03d44", + "#{dirpath}/uploads/70edb596c34ad7795baa6a0f0aa03d44/file1.txt", + "#{dirpath}/uploads/c8c93c6f546b002cbce4cb8d05d0dfb8", + "#{dirpath}/uploads/c8c93c6f546b002cbce4cb8d05d0dfb8/file2.txt" + ] + ) + end + end + + context 'when exception occurs' do + before do + create(:project_relation_export, relation: 'releases', project_export_job: export_job) + create(:project_relation_export, relation: 'issues', project_export_job: export_job) + end + + it 'registers the exception messages and returns false' do + Dir.mktmpdir do |dirpath| + allow(shared).to receive(:export_path).and_return(dirpath) + + result = service.save + + expect(result).to eq(false) + expect(shared.errors).to match_array( + [ + "undefined method `export_file' for nil:NilClass", + "undefined method `export_file' for nil:NilClass" + ] + ) + end + end + end + end +end diff --git a/spec/lib/gitlab/import_export/project/relation_saver_spec.rb b/spec/lib/gitlab/import_export/project/relation_saver_spec.rb index dec51b3afd1..0467b63e918 100644 --- a/spec/lib/gitlab/import_export/project/relation_saver_spec.rb +++ b/spec/lib/gitlab/import_export/project/relation_saver_spec.rb @@ -28,14 +28,14 @@ RSpec.describe Gitlab::ImportExport::Project::RelationSaver do it 'serializes the root node as a json file in the export path' do relation_saver.save # rubocop:disable Rails/SaveBang - json = read_json(File.join(shared.export_path, 'project.json')) + json = read_json(File.join(shared.export_path, 'tree', 'project.json')) expect(json).to include({ 'description' => 'Project description' }) end it 'serializes only allowed attributes' do relation_saver.save # rubocop:disable Rails/SaveBang - json = read_json(File.join(shared.export_path, 'project.json')) + json = read_json(File.join(shared.export_path, 'tree', 'project.json')) expect(json).to include({ 'description' => 'Project description' }) expect(json.keys).not_to include('name') end @@ -54,7 +54,7 @@ RSpec.describe Gitlab::ImportExport::Project::RelationSaver do it 'serializes the child node as a ndjson file in the export path inside the project folder' do relation_saver.save # rubocop:disable Rails/SaveBang - ndjson = read_ndjson(File.join(shared.export_path, 'project', "#{relation}.ndjson")) + ndjson = read_ndjson(File.join(shared.export_path, 'tree', 'project', "#{relation}.ndjson")) expect(ndjson.first).to include({ 'title' => 'Label 1' }) expect(ndjson.second).to include({ 'title' => 'Label 2' }) end @@ -62,7 +62,7 @@ RSpec.describe Gitlab::ImportExport::Project::RelationSaver do it 'serializes only allowed attributes' do relation_saver.save # rubocop:disable Rails/SaveBang - ndjson = read_ndjson(File.join(shared.export_path, 'project', "#{relation}.ndjson")) + ndjson = read_ndjson(File.join(shared.export_path, 'tree', 'project', "#{relation}.ndjson")) expect(ndjson.first.keys).not_to include('description_html') end diff --git a/spec/lib/gitlab/import_export/recursive_merge_folders_spec.rb b/spec/lib/gitlab/import_export/recursive_merge_folders_spec.rb new file mode 100644 index 00000000000..6e5be0b2829 --- /dev/null +++ b/spec/lib/gitlab/import_export/recursive_merge_folders_spec.rb @@ -0,0 +1,54 @@ +# frozen_string_literal: true + +require 'spec_helper' + +RSpec.describe Gitlab::ImportExport::RecursiveMergeFolders do + describe '.merge' do + it 'merge folder and ignore symlinks' do + Dir.mktmpdir do |tmpdir| + source = "#{tmpdir}/source" + FileUtils.mkdir_p("#{source}/folder/folder") + FileUtils.touch("#{source}/file1.txt") + FileUtils.touch("#{source}/folder/file2.txt") + FileUtils.touch("#{source}/folder/folder/file3.txt") + FileUtils.ln_s("#{source}/file1.txt", "#{source}/symlink-file1.txt") + FileUtils.ln_s("#{source}/folder", "#{source}/symlink-folder") + + target = "#{tmpdir}/target" + FileUtils.mkdir_p("#{target}/folder/folder") + FileUtils.mkdir_p("#{target}/folderA") + FileUtils.touch("#{target}/fileA.txt") + + described_class.merge(source, target) + + expect(Dir.children("#{tmpdir}/target")).to match_array(%w[folder file1.txt folderA fileA.txt]) + expect(Dir.children("#{tmpdir}/target/folder")).to match_array(%w[folder file2.txt]) + expect(Dir.children("#{tmpdir}/target/folder/folder")).to match_array(%w[file3.txt]) + end + end + + it 'raises an error for invalid source path' do + Dir.mktmpdir do |tmpdir| + expect do + described_class.merge("#{tmpdir}/../", tmpdir) + end.to raise_error(Gitlab::Utils::PathTraversalAttackError) + end + end + + it 'raises an error for source path outside temp dir' do + Dir.mktmpdir do |tmpdir| + expect do + described_class.merge('/', tmpdir ) + end.to raise_error(StandardError, 'path / is not allowed') + end + end + + it 'raises an error for invalid target path' do + Dir.mktmpdir do |tmpdir| + expect do + described_class.merge(tmpdir, "#{tmpdir}/../") + end.to raise_error(Gitlab::Utils::PathTraversalAttackError) + end + end + end +end |