From 1c8af321ddd0f4c768caf54cfe8119c325b689e2 Mon Sep 17 00:00:00 2001 From: James Lopez Date: Tue, 7 Nov 2017 19:11:42 +0000 Subject: Improve GitLab Import rake task to work with Hashed Storage and Subgroups --- .../gitlab/bare_repository_import/importer_spec.rb | 168 +++++++++++++++++++++ .../bare_repository_import/repository_spec.rb | 51 +++++++ 2 files changed, 219 insertions(+) create mode 100644 spec/lib/gitlab/bare_repository_import/importer_spec.rb create mode 100644 spec/lib/gitlab/bare_repository_import/repository_spec.rb (limited to 'spec/lib/gitlab/bare_repository_import') diff --git a/spec/lib/gitlab/bare_repository_import/importer_spec.rb b/spec/lib/gitlab/bare_repository_import/importer_spec.rb new file mode 100644 index 00000000000..7f3bf5fc41c --- /dev/null +++ b/spec/lib/gitlab/bare_repository_import/importer_spec.rb @@ -0,0 +1,168 @@ +require 'spec_helper' + +describe Gitlab::BareRepositoryImport::Importer, repository: true do + let!(:admin) { create(:admin) } + let!(:base_dir) { Dir.mktmpdir + '/' } + let(:bare_repository) { Gitlab::BareRepositoryImport::Repository.new(base_dir, File.join(base_dir, "#{project_path}.git")) } + + subject(:importer) { described_class.new(admin, bare_repository) } + + before do + allow(described_class).to receive(:log) + end + + after do + FileUtils.rm_rf(base_dir) + end + + shared_examples 'importing a repository' do + describe '.execute' do + it 'creates a project for a repository in storage' do + FileUtils.mkdir_p(File.join(base_dir, "#{project_path}.git")) + fake_importer = double + + expect(described_class).to receive(:new).and_return(fake_importer) + expect(fake_importer).to receive(:create_project_if_needed) + + described_class.execute(base_dir) + end + + it 'skips wiki repos' do + repo_dir = File.join(base_dir, 'the-group', 'the-project.wiki.git') + FileUtils.mkdir_p(File.join(repo_dir)) + + expect(described_class).to receive(:log).with(" * Skipping repo #{repo_dir}") + expect(described_class).not_to receive(:new) + + described_class.execute(base_dir) + end + + context 'without admin users' do + let(:admin) { nil } + + it 'raises an error' do + expect { described_class.execute(base_dir) }.to raise_error(Gitlab::BareRepositoryImport::Importer::NoAdminError) + end + end + end + + describe '#create_project_if_needed' do + it 'starts an import for a project that did not exist' do + expect(importer).to receive(:create_project) + + importer.create_project_if_needed + end + + it 'skips importing when the project already exists' do + project = create(:project, path: 'a-project', namespace: existing_group) + + expect(importer).not_to receive(:create_project) + expect(importer).to receive(:log).with(" * #{project.name} (#{project_path}) exists") + + importer.create_project_if_needed + end + + it 'creates a project with the correct path in the database' do + importer.create_project_if_needed + + expect(Project.find_by_full_path(project_path)).not_to be_nil + end + + it 'creates the Git repo in disk' do + FileUtils.mkdir_p(File.join(base_dir, "#{project_path}.git")) + + importer.create_project_if_needed + + project = Project.find_by_full_path(project_path) + + expect(File).to exist(File.join(project.repository_storage_path, project.disk_path + '.git')) + end + + context 'hashed storage enabled' do + it 'creates a project with the correct path in the database' do + stub_application_setting(hashed_storage_enabled: true) + + importer.create_project_if_needed + + expect(Project.find_by_full_path(project_path)).not_to be_nil + end + end + end + end + + context 'with subgroups', :nested_groups do + let(:project_path) { 'a-group/a-sub-group/a-project' } + + let(:existing_group) do + group = create(:group, path: 'a-group') + create(:group, path: 'a-sub-group', parent: group) + end + + it_behaves_like 'importing a repository' + end + + context 'without subgroups' do + let(:project_path) { 'a-group/a-project' } + let(:existing_group) { create(:group, path: 'a-group') } + + it_behaves_like 'importing a repository' + end + + context 'without groups' do + let(:project_path) { 'a-project' } + + it 'starts an import for a project that did not exist' do + expect(importer).to receive(:create_project) + + importer.create_project_if_needed + end + + it 'creates a project with the correct path in the database' do + importer.create_project_if_needed + + expect(Project.find_by_full_path("#{admin.full_path}/#{project_path}")).not_to be_nil + end + + it 'creates the Git repo in disk' do + FileUtils.mkdir_p(File.join(base_dir, "#{project_path}.git")) + + importer.create_project_if_needed + + project = Project.find_by_full_path("#{admin.full_path}/#{project_path}") + + expect(File).to exist(File.join(project.repository_storage_path, project.disk_path + '.git')) + end + end + + context 'with Wiki' do + let(:project_path) { 'a-group/a-project' } + let(:existing_group) { create(:group, path: 'a-group') } + + it_behaves_like 'importing a repository' + + it 'creates the Wiki git repo in disk' do + FileUtils.mkdir_p(File.join(base_dir, "#{project_path}.git")) + FileUtils.mkdir_p(File.join(base_dir, "#{project_path}.wiki.git")) + + importer.create_project_if_needed + + project = Project.find_by_full_path(project_path) + + expect(File).to exist(File.join(project.repository_storage_path, project.disk_path + '.wiki.git')) + end + end + + context 'when subgroups are not available' do + let(:project_path) { 'a-group/a-sub-group/a-project' } + + before do + expect(Group).to receive(:supports_nested_groups?) { false } + end + + describe '#create_project_if_needed' do + it 'raises an error' do + expect { importer.create_project_if_needed }.to raise_error('Nested groups are not supported on MySQL') + end + end + end +end diff --git a/spec/lib/gitlab/bare_repository_import/repository_spec.rb b/spec/lib/gitlab/bare_repository_import/repository_spec.rb new file mode 100644 index 00000000000..2db737f5fb6 --- /dev/null +++ b/spec/lib/gitlab/bare_repository_import/repository_spec.rb @@ -0,0 +1,51 @@ +require 'spec_helper' + +describe ::Gitlab::BareRepositoryImport::Repository do + let(:project_repo_path) { described_class.new('/full/path/', '/full/path/to/repo.git') } + + it 'stores the repo path' do + expect(project_repo_path.repo_path).to eq('/full/path/to/repo.git') + end + + it 'stores the group path' do + expect(project_repo_path.group_path).to eq('to') + end + + it 'stores the project name' do + expect(project_repo_path.project_name).to eq('repo') + end + + it 'stores the wiki path' do + expect(project_repo_path.wiki_path).to eq('/full/path/to/repo.wiki.git') + end + + describe '#wiki?' do + it 'returns true if it is a wiki' do + wiki_path = described_class.new('/full/path/', '/full/path/to/a/b/my.wiki.git') + + expect(wiki_path.wiki?).to eq(true) + end + + it 'returns false if it is not a wiki' do + expect(project_repo_path.wiki?).to eq(false) + end + end + + describe '#hashed?' do + it 'returns true if it is a hashed folder' do + path = described_class.new('/full/path/', '/full/path/@hashed/my.repo.git') + + expect(path.hashed?).to eq(true) + end + + it 'returns false if it is not a hashed folder' do + expect(project_repo_path.hashed?).to eq(false) + end + end + + describe '#project_full_path' do + it 'returns the project full path' do + expect(project_repo_path.repo_path).to eq('/full/path/to/repo.git') + end + end +end -- cgit v1.2.3