Welcome to mirror list, hosted at ThFree Co, Russian Federation.

gitlab.com/gitlab-org/gitlab-foss.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to 'spec/lib/gitlab/bitbucket_import')
-rw-r--r--spec/lib/gitlab/bitbucket_import/importer_spec.rb22
-rw-r--r--spec/lib/gitlab/bitbucket_import/importers/pull_request_importer_spec.rb166
-rw-r--r--spec/lib/gitlab/bitbucket_import/importers/pull_requests_importer_spec.rb71
-rw-r--r--spec/lib/gitlab/bitbucket_import/importers/repository_importer_spec.rb49
-rw-r--r--spec/lib/gitlab/bitbucket_import/parallel_importer_spec.rb43
-rw-r--r--spec/lib/gitlab/bitbucket_import/user_finder_spec.rb75
6 files changed, 422 insertions, 4 deletions
diff --git a/spec/lib/gitlab/bitbucket_import/importer_spec.rb b/spec/lib/gitlab/bitbucket_import/importer_spec.rb
index 4c94ecfe745..9786e7a364e 100644
--- a/spec/lib/gitlab/bitbucket_import/importer_spec.rb
+++ b/spec/lib/gitlab/bitbucket_import/importer_spec.rb
@@ -92,6 +92,7 @@ RSpec.describe Gitlab::BitbucketImport::Importer, :clean_gitlab_redis_cache, fea
describe '#import_pull_requests' do
let(:source_branch_sha) { sample.commits.last }
+ let(:merge_commit_sha) { sample.commits.second }
let(:target_branch_sha) { sample.commits.first }
let(:pull_request) do
instance_double(
@@ -101,6 +102,7 @@ RSpec.describe Gitlab::BitbucketImport::Importer, :clean_gitlab_redis_cache, fea
source_branch_name: Gitlab::Git::BRANCH_REF_PREFIX + sample.source_branch,
target_branch_sha: target_branch_sha,
target_branch_name: Gitlab::Git::BRANCH_REF_PREFIX + sample.target_branch,
+ merge_commit_sha: merge_commit_sha,
title: 'This is a title',
description: 'This is a test pull request',
state: 'merged',
@@ -217,17 +219,29 @@ RSpec.describe Gitlab::BitbucketImport::Importer, :clean_gitlab_redis_cache, fea
end
end
- context "when branches' sha is not found in the repository" do
+ context 'when source SHA is not found in the repository' do
let(:source_branch_sha) { 'a' * Commit::MIN_SHA_LENGTH }
- let(:target_branch_sha) { 'b' * Commit::MIN_SHA_LENGTH }
+ let(:target_branch_sha) { 'c' * Commit::MIN_SHA_LENGTH }
- it 'uses the pull request sha references' do
+ it 'uses merge commit SHA for source' do
expect { subject.execute }.to change { MergeRequest.count }.by(1)
merge_request_diff = MergeRequest.first.merge_request_diff
- expect(merge_request_diff.head_commit_sha).to eq source_branch_sha
+ expect(merge_request_diff.head_commit_sha).to eq merge_commit_sha
expect(merge_request_diff.start_commit_sha).to eq target_branch_sha
end
+
+ context 'when the merge commit SHA is also not found' do
+ let(:merge_commit_sha) { 'b' * Commit::MIN_SHA_LENGTH }
+
+ it 'uses the pull request sha references' do
+ expect { subject.execute }.to change { MergeRequest.count }.by(1)
+
+ merge_request_diff = MergeRequest.first.merge_request_diff
+ expect(merge_request_diff.head_commit_sha).to eq source_branch_sha
+ expect(merge_request_diff.start_commit_sha).to eq target_branch_sha
+ end
+ end
end
context "when target_branch_sha is blank" do
diff --git a/spec/lib/gitlab/bitbucket_import/importers/pull_request_importer_spec.rb b/spec/lib/gitlab/bitbucket_import/importers/pull_request_importer_spec.rb
new file mode 100644
index 00000000000..2eca6bb47d6
--- /dev/null
+++ b/spec/lib/gitlab/bitbucket_import/importers/pull_request_importer_spec.rb
@@ -0,0 +1,166 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe Gitlab::BitbucketImport::Importers::PullRequestImporter, :clean_gitlab_redis_cache, feature_category: :importers do
+ include AfterNextHelpers
+
+ let_it_be(:project) { create(:project, :repository) }
+ let_it_be(:bitbucket_user) { create(:user) }
+ let_it_be(:user_2) { create(:user) }
+ let_it_be(:user_3) { create(:user) }
+ let_it_be(:identity) { create(:identity, user: bitbucket_user, extern_uid: 'bitbucket_user', provider: :bitbucket) }
+ let_it_be(:identity_2) { create(:identity, user: user_2, extern_uid: 'user_2', provider: :bitbucket) }
+ let(:source_branch_sha) { project.repository.commit.sha }
+ let(:target_branch_sha) { project.repository.commit('refs/heads/master').sha }
+
+ let(:hash) do
+ {
+ author: 'bitbucket_user',
+ created_at: Date.today,
+ description: 'description',
+ iid: 11,
+ source_branch_name: 'source-branch-name',
+ source_branch_sha: source_branch_sha,
+ state: 'merged',
+ target_branch_name: 'destination-branch-name',
+ target_branch_sha: target_branch_sha,
+ title: 'title',
+ updated_at: Date.today,
+ reviewers: %w[user_2 user_3]
+ }
+ end
+
+ subject(:importer) { described_class.new(project, hash) }
+
+ describe '#execute' do
+ it 'calls MergeRequestCreator' do
+ expect(Gitlab::Import::MergeRequestCreator).to receive_message_chain(:new, :execute)
+
+ importer.execute
+ end
+
+ it 'creates a merge request with the correct attributes' do
+ expect { importer.execute }.to change { project.merge_requests.count }.from(0).to(1)
+
+ merge_request = project.merge_requests.first
+
+ expect(merge_request.iid).to eq(11)
+ expect(merge_request.author).to eq(bitbucket_user)
+ expect(merge_request.title).to eq('title')
+ expect(merge_request.merged?).to be_truthy
+ expect(merge_request.created_at).to eq(Date.today)
+ expect(merge_request.description).to eq('description')
+ expect(merge_request.source_project_id).to eq(project.id)
+ expect(merge_request.target_project_id).to eq(project.id)
+ expect(merge_request.source_branch).to eq('source-branch-name')
+ expect(merge_request.target_branch).to eq('destination-branch-name')
+ expect(merge_request.assignee_ids).to eq([bitbucket_user.id])
+ expect(merge_request.reviewer_ids).to eq([user_2.id])
+ expect(merge_request.merge_request_diffs.first.base_commit_sha).to eq(source_branch_sha)
+ expect(merge_request.merge_request_diffs.first.head_commit_sha).to eq(target_branch_sha)
+ end
+
+ context 'when the state is closed' do
+ it 'marks merge request as closed' do
+ described_class.new(project, hash.merge(state: 'closed')).execute
+
+ expect(project.merge_requests.first.closed?).to be_truthy
+ end
+ end
+
+ context 'when the state is opened' do
+ it 'marks merge request as opened' do
+ described_class.new(project, hash.merge(state: 'opened')).execute
+
+ expect(project.merge_requests.first.opened?).to be_truthy
+ end
+ end
+
+ context 'when the author does not have a bitbucket identity' do
+ before do
+ identity.update!(provider: :github)
+ end
+
+ it 'sets the author and assignee to the project creator and adds the author to the description' do
+ importer.execute
+
+ merge_request = project.merge_requests.first
+
+ expect(merge_request.author).to eq(project.creator)
+ expect(merge_request.assignee).to eq(project.creator)
+ expect(merge_request.description).to eq("*Created by: bitbucket_user*\n\ndescription")
+ end
+ end
+
+ context 'when none of the reviewers have an identity' do
+ before do
+ identity_2.destroy!
+ end
+
+ it 'does not set reviewer_ids' do
+ importer.execute
+
+ merge_request = project.merge_requests.first
+
+ expect(merge_request.reviewer_ids).to be_empty
+ end
+ end
+
+ describe 'head_commit_sha for merge request diff' do
+ let(:diff) { project.merge_requests.first.merge_request_diffs.first }
+ let(:min_length) { Commit::MIN_SHA_LENGTH }
+
+ context 'when the source commit hash from Bitbucket is found on the repo' do
+ it 'is set to the source commit hash' do
+ described_class.new(project, hash.merge(source_branch_sha: source_branch_sha)).execute
+
+ expect(diff.head_commit_sha).to eq(source_branch_sha)
+ end
+ end
+
+ context 'when the source commit hash is not found but the merge commit hash is found' do
+ it 'is set to the merge commit hash' do
+ attrs = { source_branch_sha: 'x' * min_length, merge_commit_sha: source_branch_sha }
+
+ described_class.new(project, hash.merge(attrs)).execute
+
+ expect(diff.head_commit_sha).to eq(source_branch_sha)
+ end
+ end
+
+ context 'when both the source commit and merge commit hash are not found' do
+ it 'is nil' do
+ attrs = { source_branch_sha: 'x' * min_length, merge_commit_sha: 'y' * min_length }
+
+ described_class.new(project, hash.merge(attrs)).execute
+
+ expect(diff.head_commit_sha).to be_nil
+ end
+ end
+ end
+
+ context 'when an error is raised' do
+ before do
+ allow(Gitlab::Import::MergeRequestCreator).to receive(:new).and_raise(StandardError)
+ end
+
+ it 'tracks the failure and does not fail' do
+ expect(Gitlab::Import::ImportFailureService).to receive(:track).once
+
+ importer.execute
+ end
+ end
+
+ it 'logs its progress' do
+ allow(Gitlab::Import::MergeRequestCreator).to receive_message_chain(:new, :execute)
+
+ expect(Gitlab::BitbucketImport::Logger)
+ .to receive(:info).with(include(message: 'starting', iid: anything)).and_call_original
+ expect(Gitlab::BitbucketImport::Logger)
+ .to receive(:info).with(include(message: 'finished', iid: anything)).and_call_original
+
+ importer.execute
+ end
+ end
+end
diff --git a/spec/lib/gitlab/bitbucket_import/importers/pull_requests_importer_spec.rb b/spec/lib/gitlab/bitbucket_import/importers/pull_requests_importer_spec.rb
new file mode 100644
index 00000000000..46bf099de0c
--- /dev/null
+++ b/spec/lib/gitlab/bitbucket_import/importers/pull_requests_importer_spec.rb
@@ -0,0 +1,71 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe Gitlab::BitbucketImport::Importers::PullRequestsImporter, feature_category: :importers do
+ let_it_be(:project) do
+ create(:project, :import_started,
+ import_data_attributes: {
+ data: { 'project_key' => 'key', 'repo_slug' => 'slug' },
+ credentials: { 'base_uri' => 'http://bitbucket.org/', 'user' => 'bitbucket', 'password' => 'password' }
+ }
+ )
+ end
+
+ subject(:importer) { described_class.new(project) }
+
+ describe '#execute', :clean_gitlab_redis_cache do
+ before do
+ allow_next_instance_of(Bitbucket::Client) do |client|
+ allow(client).to receive(:pull_requests).and_return(
+ [
+ Bitbucket::Representation::PullRequest.new({ 'id' => 1, 'state' => 'OPENED' }),
+ Bitbucket::Representation::PullRequest.new({ 'id' => 2, 'state' => 'DECLINED' }),
+ Bitbucket::Representation::PullRequest.new({ 'id' => 3, 'state' => 'MERGED' })
+ ],
+ []
+ )
+ end
+ end
+
+ it 'imports each pull request in parallel', :aggregate_failures do
+ expect(Gitlab::BitbucketImport::ImportPullRequestWorker).to receive(:perform_in).exactly(3).times
+
+ waiter = importer.execute
+
+ expect(waiter).to be_an_instance_of(Gitlab::JobWaiter)
+ expect(waiter.jobs_remaining).to eq(3)
+ expect(Gitlab::Cache::Import::Caching.values_from_set(importer.already_enqueued_cache_key))
+ .to match_array(%w[1 2 3])
+ end
+
+ context 'when the client raises an error' do
+ before do
+ allow_next_instance_of(Bitbucket::Client) do |client|
+ allow(client).to receive(:pull_requests).and_raise(StandardError)
+ end
+ end
+
+ it 'tracks the failure and does not fail' do
+ expect(Gitlab::Import::ImportFailureService).to receive(:track).once
+
+ importer.execute
+ end
+ end
+
+ context 'when pull request was already enqueued' do
+ before do
+ Gitlab::Cache::Import::Caching.set_add(importer.already_enqueued_cache_key, 1)
+ end
+
+ it 'does not schedule job for enqueued pull requests', :aggregate_failures do
+ expect(Gitlab::BitbucketImport::ImportPullRequestWorker).to receive(:perform_in).twice
+
+ waiter = importer.execute
+
+ expect(waiter).to be_an_instance_of(Gitlab::JobWaiter)
+ expect(waiter.jobs_remaining).to eq(3)
+ end
+ end
+ end
+end
diff --git a/spec/lib/gitlab/bitbucket_import/importers/repository_importer_spec.rb b/spec/lib/gitlab/bitbucket_import/importers/repository_importer_spec.rb
new file mode 100644
index 00000000000..1caf0b884c2
--- /dev/null
+++ b/spec/lib/gitlab/bitbucket_import/importers/repository_importer_spec.rb
@@ -0,0 +1,49 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe Gitlab::BitbucketImport::Importers::RepositoryImporter, feature_category: :importers do
+ let_it_be(:project) { create(:project, import_url: 'https://bitbucket.org/vim/vim.git') }
+
+ subject(:importer) { described_class.new(project) }
+
+ describe '#execute' do
+ context 'when repository is empty' do
+ it 'imports the repository' do
+ expect(project.repository).to receive(:import_repository).with(project.import_url)
+ expect(project.repository).to receive(:fetch_as_mirror).with(project.import_url,
+ refmap: ['+refs/pull-requests/*/to:refs/merge-requests/*/head'])
+ expect(project.last_repository_updated_at).to be_present
+
+ importer.execute
+ end
+ end
+
+ context 'when repository is not empty' do
+ before do
+ allow(project).to receive(:empty_repo?).and_return(false)
+
+ project.last_repository_updated_at = 1.day.ago
+ end
+
+ it 'does not import the repository' do
+ expect(project.repository).not_to receive(:import_repository)
+
+ expect { importer.execute }.not_to change { project.last_repository_updated_at }
+ end
+ end
+
+ context 'when a Git CommandError is raised and the repository exists' do
+ before do
+ allow(project.repository).to receive(:import_repository).and_raise(::Gitlab::Git::CommandError)
+ allow(project).to receive(:repository_exists?).and_return(true)
+ end
+
+ it 'expires repository caches' do
+ expect(project.repository).to receive(:expire_content_cache)
+
+ expect { importer.execute }.to raise_error(::Gitlab::Git::CommandError)
+ end
+ end
+ end
+end
diff --git a/spec/lib/gitlab/bitbucket_import/parallel_importer_spec.rb b/spec/lib/gitlab/bitbucket_import/parallel_importer_spec.rb
new file mode 100644
index 00000000000..29919c43d23
--- /dev/null
+++ b/spec/lib/gitlab/bitbucket_import/parallel_importer_spec.rb
@@ -0,0 +1,43 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe Gitlab::BitbucketImport::ParallelImporter, feature_category: :importers do
+ subject { described_class }
+
+ it { is_expected.to be_async }
+
+ describe '.track_start_import' do
+ it 'tracks the start of import' do
+ project = build_stubbed(:project)
+
+ expect_next_instance_of(Gitlab::Import::Metrics, :bitbucket_importer, project) do |metric|
+ expect(metric).to receive(:track_start_import)
+ end
+
+ subject.track_start_import(project)
+ end
+ end
+
+ describe '#execute', :clean_gitlab_redis_shared_state do
+ let_it_be(:project) { create(:project) }
+ let(:importer) { subject.new(project) }
+
+ before do
+ create(:import_state, :started, project: project)
+ end
+
+ it 'schedules the importing of the repository' do
+ expect(Gitlab::BitbucketImport::Stage::ImportRepositoryWorker)
+ .to receive_message_chain(:with_status, :perform_async).with(project.id)
+
+ expect(importer.execute).to eq(true)
+ end
+
+ it 'sets the JID in Redis' do
+ expect(Gitlab::Import::SetAsyncJid).to receive(:set_jid).with(project.import_state).and_call_original
+
+ importer.execute
+ end
+ end
+end
diff --git a/spec/lib/gitlab/bitbucket_import/user_finder_spec.rb b/spec/lib/gitlab/bitbucket_import/user_finder_spec.rb
new file mode 100644
index 00000000000..4ac4c2e4813
--- /dev/null
+++ b/spec/lib/gitlab/bitbucket_import/user_finder_spec.rb
@@ -0,0 +1,75 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe Gitlab::BitbucketImport::UserFinder, :clean_gitlab_redis_cache, feature_category: :importers do
+ let_it_be(:user) { create(:user) }
+ let_it_be(:identity) { create(:identity, user: user, extern_uid: 'uid', provider: :bitbucket) }
+ let(:created_id) { 1 }
+ let(:project) { instance_double(Project, creator_id: created_id, id: 1) }
+ let(:author) { 'uid' }
+ let(:cache_key) { format(described_class::USER_ID_FOR_AUTHOR_CACHE_KEY, project_id: project.id, author: author) }
+
+ subject(:user_finder) { described_class.new(project) }
+
+ describe '#find_user_id' do
+ it 'returns the user id' do
+ expect(User).to receive(:by_provider_and_extern_uid).and_call_original.once
+
+ expect(user_finder.find_user_id(author)).to eq(user.id)
+ expect(user_finder.find_user_id(author)).to eq(user.id)
+ end
+
+ context 'when the id is cached' do
+ before do
+ Gitlab::Cache::Import::Caching.write(cache_key, user.id)
+ end
+
+ it 'does not attempt to find the user' do
+ expect(User).not_to receive(:by_provider_and_extern_uid)
+
+ expect(user_finder.find_user_id(author)).to eq(user.id)
+ end
+ end
+
+ context 'when -1 is cached' do
+ before do
+ Gitlab::Cache::Import::Caching.write(cache_key, -1)
+ end
+
+ it 'does not attempt to find the user and returns nil' do
+ expect(User).not_to receive(:by_provider_and_extern_uid)
+
+ expect(user_finder.find_user_id(author)).to be_nil
+ end
+ end
+
+ context 'when the user does not have a matching bitbucket identity' do
+ before do
+ identity.update!(provider: :github)
+ end
+
+ it 'returns nil' do
+ expect(user_finder.find_user_id(author)).to be_nil
+ end
+ end
+ end
+
+ describe '#gitlab_user_id' do
+ context 'when find_user_id returns a user' do
+ it 'returns the user id' do
+ expect(user_finder.gitlab_user_id(project, author)).to eq(user.id)
+ end
+ end
+
+ context 'when find_user_id does not return a user' do
+ before do
+ allow(user_finder).to receive(:find_user_id).and_return(nil)
+ end
+
+ it 'returns the project creator' do
+ expect(user_finder.gitlab_user_id(project, author)).to eq(created_id)
+ end
+ end
+ end
+end