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
path: root/spec
diff options
context:
space:
mode:
authorGitLab Bot <gitlab-bot@gitlab.com>2023-05-25 22:51:41 +0300
committerGitLab Bot <gitlab-bot@gitlab.com>2023-05-25 22:51:41 +0300
commite7b32a77cc40a14eb0dd6ae1bfc6f036819c66cc (patch)
tree86f33d8f98e4eab9c8a8e900f9e370939921c378 /spec
parent4711b9334036cc4719fb9e475545709e8fd5b649 (diff)
Add latest changes from gitlab-org/gitlab@16-0-stable-ee
Diffstat (limited to 'spec')
-rw-r--r--spec/lib/bitbucket_server/representation/pull_request_spec.rb19
-rw-r--r--spec/lib/gitlab/bitbucket_server_import/importers/lfs_object_importer_spec.rb51
-rw-r--r--spec/lib/gitlab/bitbucket_server_import/importers/lfs_objects_importer_spec.rb113
-rw-r--r--spec/lib/gitlab/bitbucket_server_import/importers/notes_importer_spec.rb47
-rw-r--r--spec/lib/gitlab/bitbucket_server_import/importers/pull_request_importer_spec.rb43
-rw-r--r--spec/lib/gitlab/bitbucket_server_import/importers/pull_request_notes_importer_spec.rb216
-rw-r--r--spec/lib/gitlab/bitbucket_server_import/importers/pull_requests_importer_spec.rb56
-rw-r--r--spec/lib/gitlab/bitbucket_server_import/importers/repository_importer_spec.rb49
-rw-r--r--spec/lib/gitlab/bitbucket_server_import/parallel_importer_spec.rb45
-rw-r--r--spec/lib/gitlab/bitbucket_server_import/user_finder_spec.rb121
-rw-r--r--spec/lib/gitlab/import_sources_spec.rb42
-rw-r--r--spec/support/shared_examples/lib/gitlab/bitbucket_server_import/object_import_shared_examples.rb69
-rw-r--r--spec/support/shared_examples/lib/gitlab/bitbucket_server_import/stage_methods_shared_examples.rb18
-rw-r--r--spec/workers/every_sidekiq_worker_spec.rb6
-rw-r--r--spec/workers/gitlab/bitbucket_server_import/import_lfs_object_worker_spec.rb14
-rw-r--r--spec/workers/gitlab/bitbucket_server_import/import_pull_request_notes_worker_spec.rb9
-rw-r--r--spec/workers/gitlab/bitbucket_server_import/import_pull_request_worker_spec.rb84
-rw-r--r--spec/workers/gitlab/bitbucket_server_import/stage/finish_import_worker_spec.rb23
-rw-r--r--spec/workers/gitlab/bitbucket_server_import/stage/import_lfs_objects_worker_spec.rb28
-rw-r--r--spec/workers/gitlab/bitbucket_server_import/stage/import_notes_worker_spec.rb28
-rw-r--r--spec/workers/gitlab/bitbucket_server_import/stage/import_pull_requests_worker_spec.rb77
-rw-r--r--spec/workers/gitlab/bitbucket_server_import/stage/import_repository_worker_spec.rb77
22 files changed, 1233 insertions, 2 deletions
diff --git a/spec/lib/bitbucket_server/representation/pull_request_spec.rb b/spec/lib/bitbucket_server/representation/pull_request_spec.rb
index d7b893e8081..5312bc1d71b 100644
--- a/spec/lib/bitbucket_server/representation/pull_request_spec.rb
+++ b/spec/lib/bitbucket_server/representation/pull_request_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe BitbucketServer::Representation::PullRequest do
+RSpec.describe BitbucketServer::Representation::PullRequest, feature_category: :importers do
let(:sample_data) { Gitlab::Json.parse(fixture_file('importers/bitbucket_server/pull_request.json')) }
subject { described_class.new(sample_data) }
@@ -105,4 +105,21 @@ RSpec.describe BitbucketServer::Representation::PullRequest do
describe '#target_branch_sha' do
it { expect(subject.target_branch_sha).to eq('839fa9a2d434eb697815b8fcafaecc51accfdbbc') }
end
+
+ describe '#to_hash' do
+ it do
+ expect(subject.to_hash).to match(
+ a_hash_including(
+ author_email: "joe.montana@49ers.com",
+ author_username: "username",
+ author: "root",
+ description: "Test",
+ source_branch_name: "refs/heads/root/CODE_OF_CONDUCTmd-1530600625006",
+ target_branch_name: "refs/heads/master",
+ target_branch_sha: "839fa9a2d434eb697815b8fcafaecc51accfdbbc",
+ title: "Added a new line"
+ )
+ )
+ end
+ end
end
diff --git a/spec/lib/gitlab/bitbucket_server_import/importers/lfs_object_importer_spec.rb b/spec/lib/gitlab/bitbucket_server_import/importers/lfs_object_importer_spec.rb
new file mode 100644
index 00000000000..ba63889ab9d
--- /dev/null
+++ b/spec/lib/gitlab/bitbucket_server_import/importers/lfs_object_importer_spec.rb
@@ -0,0 +1,51 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe Gitlab::BitbucketServerImport::Importers::LfsObjectImporter, feature_category: :importers do
+ let_it_be(:project) { create(:project) }
+
+ let(:lfs_attributes) do
+ {
+ 'oid' => 'myoid',
+ 'size' => 1,
+ 'link' => 'http://www.gitlab.com/lfs_objects/oid',
+ 'headers' => { 'X-Some-Header' => '456' }
+ }
+ end
+
+ let(:importer) { described_class.new(project, lfs_attributes) }
+
+ describe '#execute' do
+ it 'calls the LfsDownloadService with the lfs object attributes' do
+ expect_next_instance_of(
+ Projects::LfsPointers::LfsDownloadService, project, have_attributes(lfs_attributes)
+ ) do |service|
+ expect(service).to receive(:execute).and_return(ServiceResponse.success)
+ end
+
+ importer.execute
+ end
+
+ it 'logs its progress' do
+ allow_next_instance_of(Projects::LfsPointers::LfsDownloadService) do |service|
+ allow(service).to receive(:execute).and_return(ServiceResponse.success)
+ end
+
+ common_log_message = {
+ oid: 'myoid',
+ import_stage: 'import_lfs_object',
+ class: described_class.name,
+ project_id: project.id,
+ project_path: project.full_path
+ }
+
+ expect(Gitlab::BitbucketServerImport::Logger)
+ .to receive(:info).with(common_log_message.merge(message: 'starting')).and_call_original
+ expect(Gitlab::BitbucketServerImport::Logger)
+ .to receive(:info).with(common_log_message.merge(message: 'finished')).and_call_original
+
+ importer.execute
+ end
+ end
+end
diff --git a/spec/lib/gitlab/bitbucket_server_import/importers/lfs_objects_importer_spec.rb b/spec/lib/gitlab/bitbucket_server_import/importers/lfs_objects_importer_spec.rb
new file mode 100644
index 00000000000..0d66ad7c2ec
--- /dev/null
+++ b/spec/lib/gitlab/bitbucket_server_import/importers/lfs_objects_importer_spec.rb
@@ -0,0 +1,113 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe Gitlab::BitbucketServerImport::Importers::LfsObjectsImporter, feature_category: :importers do
+ let_it_be(:project) do
+ create(:project, :import_started,
+ import_data_attributes: {
+ data: { 'project_key' => 'key', 'repo_slug' => 'slug' },
+ credentials: { 'token' => 'token' }
+ }
+ )
+ end
+
+ let(:lfs_attributes) do
+ {
+ oid: 'a' * 64,
+ size: 1,
+ link: 'http://www.gitlab.com/lfs_objects/oid',
+ headers: { 'X-Some-Header' => '456' }
+ }
+ end
+
+ let(:lfs_download_object) { LfsDownloadObject.new(**lfs_attributes) }
+
+ let(:common_log_messages) do
+ {
+ import_stage: 'import_lfs_objects',
+ class: described_class.name,
+ project_id: project.id,
+ project_path: project.full_path
+ }
+ end
+
+ describe '#execute', :clean_gitlab_redis_cache do
+ context 'when lfs is enabled' do
+ before do
+ allow(project).to receive(:lfs_enabled?).and_return(true)
+ end
+
+ it 'imports each lfs object in parallel' do
+ importer = described_class.new(project)
+
+ expect_next_instance_of(Projects::LfsPointers::LfsObjectDownloadListService) do |service|
+ expect(service).to receive(:each_list_item).and_yield(lfs_download_object)
+ end
+
+ expect(Gitlab::BitbucketServerImport::ImportLfsObjectWorker).to receive(:perform_in)
+ .with(1.second, project.id, lfs_attributes.stringify_keys, start_with(Gitlab::JobWaiter::KEY_PREFIX))
+
+ waiter = importer.execute
+
+ expect(waiter).to be_an_instance_of(Gitlab::JobWaiter)
+ expect(waiter.jobs_remaining).to eq(1)
+ end
+
+ it 'logs its progress' do
+ importer = described_class.new(project)
+
+ expect(Gitlab::BitbucketServerImport::Logger)
+ .to receive(:info).with(common_log_messages.merge(message: 'starting')).and_call_original
+ expect(Gitlab::BitbucketServerImport::Logger)
+ .to receive(:info).with(common_log_messages.merge(message: 'finished')).and_call_original
+
+ importer.execute
+ end
+
+ context 'when LFS list download fails' do
+ let(:exception) { StandardError.new('Invalid Project URL') }
+
+ before do
+ allow_next_instance_of(Projects::LfsPointers::LfsObjectDownloadListService) do |service|
+ allow(service).to receive(:each_list_item).and_raise(exception)
+ end
+ end
+
+ it 'rescues and logs the exception' do
+ importer = described_class.new(project)
+
+ expect(Gitlab::Import::ImportFailureService)
+ .to receive(:track)
+ .with(
+ project_id: project.id,
+ exception: exception,
+ error_source: described_class.name
+ ).and_call_original
+
+ waiter = importer.execute
+
+ expect(waiter).to be_an_instance_of(Gitlab::JobWaiter)
+ expect(waiter.jobs_remaining).to eq(0)
+ end
+ end
+ end
+
+ context 'when LFS is not enabled' do
+ before do
+ allow(project).to receive(:lfs_enabled?).and_return(false)
+ end
+
+ it 'logs progress but does nothing' do
+ importer = described_class.new(project)
+
+ expect(Gitlab::BitbucketServerImport::Logger).to receive(:info).twice
+
+ waiter = importer.execute
+
+ expect(waiter).to be_an_instance_of(Gitlab::JobWaiter)
+ expect(waiter.jobs_remaining).to eq(0)
+ end
+ end
+ end
+end
diff --git a/spec/lib/gitlab/bitbucket_server_import/importers/notes_importer_spec.rb b/spec/lib/gitlab/bitbucket_server_import/importers/notes_importer_spec.rb
new file mode 100644
index 00000000000..2237694deb6
--- /dev/null
+++ b/spec/lib/gitlab/bitbucket_server_import/importers/notes_importer_spec.rb
@@ -0,0 +1,47 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe Gitlab::BitbucketServerImport::Importers::NotesImporter, 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
+
+ let_it_be(:merge_request_1) { create(:merge_request, source_project: project, iid: 100, source_branch: 'branch_1') }
+ let_it_be(:merge_request_2) { create(:merge_request, source_project: project, iid: 101, source_branch: 'branch_2') }
+
+ subject(:importer) { described_class.new(project) }
+
+ describe '#execute', :clean_gitlab_redis_cache do
+ it 'schedules a job to import notes for each corresponding merge request', :aggregate_failures do
+ expect(Gitlab::BitbucketServerImport::ImportPullRequestNotesWorker).to receive(:perform_in).twice
+
+ waiter = importer.execute
+
+ expect(waiter).to be_an_instance_of(Gitlab::JobWaiter)
+ expect(waiter.jobs_remaining).to eq(2)
+ expect(Gitlab::Cache::Import::Caching.values_from_set(importer.already_processed_cache_key))
+ .to match_array(%w[100 101])
+ end
+
+ context 'when pull request was already processed' do
+ before do
+ Gitlab::Cache::Import::Caching.set_add(importer.already_processed_cache_key, "100")
+ end
+
+ it 'does not schedule job for processed merge requests', :aggregate_failures do
+ expect(Gitlab::BitbucketServerImport::ImportPullRequestNotesWorker).to receive(:perform_in).once
+
+ waiter = importer.execute
+
+ expect(waiter).to be_an_instance_of(Gitlab::JobWaiter)
+ expect(waiter.jobs_remaining).to eq(2)
+ end
+ end
+ end
+end
diff --git a/spec/lib/gitlab/bitbucket_server_import/importers/pull_request_importer_spec.rb b/spec/lib/gitlab/bitbucket_server_import/importers/pull_request_importer_spec.rb
new file mode 100644
index 00000000000..012cdcdd260
--- /dev/null
+++ b/spec/lib/gitlab/bitbucket_server_import/importers/pull_request_importer_spec.rb
@@ -0,0 +1,43 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe Gitlab::BitbucketServerImport::Importers::PullRequestImporter, feature_category: :importers do
+ include AfterNextHelpers
+
+ let_it_be(:project) { create(:project, :repository) }
+
+ let(:pull_request_data) { Gitlab::Json.parse(fixture_file('importers/bitbucket_server/pull_request.json')) }
+ let(:pull_request) { BitbucketServer::Representation::PullRequest.new(pull_request_data) }
+
+ subject(:importer) { described_class.new(project, pull_request.to_hash) }
+
+ describe '#execute' do
+ it 'imports the merge request correctly' do
+ expect_next(Gitlab::Import::MergeRequestCreator, project).to receive(:execute).and_call_original
+ expect_next(Gitlab::BitbucketServerImport::UserFinder, project).to receive(:author_id).and_call_original
+ expect { importer.execute }.to change { MergeRequest.count }.by(1)
+
+ merge_request = project.merge_requests.find_by_iid(pull_request.iid)
+
+ expect(merge_request).to have_attributes(
+ iid: pull_request.iid,
+ title: pull_request.title,
+ source_branch: 'root/CODE_OF_CONDUCTmd-1530600625006',
+ target_branch: 'master',
+ state: pull_request.state,
+ author_id: project.creator_id,
+ description: "*Created by: #{pull_request.author}*\n\n#{pull_request.description}"
+ )
+ end
+
+ it 'logs its progress' do
+ expect(Gitlab::BitbucketServerImport::Logger)
+ .to receive(:info).with(include(message: 'starting', iid: pull_request.iid)).and_call_original
+ expect(Gitlab::BitbucketServerImport::Logger)
+ .to receive(:info).with(include(message: 'finished', iid: pull_request.iid)).and_call_original
+
+ importer.execute
+ end
+ end
+end
diff --git a/spec/lib/gitlab/bitbucket_server_import/importers/pull_request_notes_importer_spec.rb b/spec/lib/gitlab/bitbucket_server_import/importers/pull_request_notes_importer_spec.rb
new file mode 100644
index 00000000000..c7e91c340b0
--- /dev/null
+++ b/spec/lib/gitlab/bitbucket_server_import/importers/pull_request_notes_importer_spec.rb
@@ -0,0 +1,216 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe Gitlab::BitbucketServerImport::Importers::PullRequestNotesImporter, feature_category: :importers do
+ include AfterNextHelpers
+
+ let_it_be(:project) do
+ create(:project, :repository, :import_started,
+ import_data_attributes: {
+ data: { 'project_key' => 'key', 'repo_slug' => 'slug' },
+ credentials: { 'token' => 'token' }
+ }
+ )
+ end
+
+ let_it_be(:pull_request_data) { Gitlab::Json.parse(fixture_file('importers/bitbucket_server/pull_request.json')) }
+ let_it_be(:pull_request) { BitbucketServer::Representation::PullRequest.new(pull_request_data) }
+ let_it_be(:note_author) { create(:user, username: 'note_author', email: 'note_author@example.org') }
+
+ let_it_be(:pull_request_author) do
+ create(:user, username: 'pull_request_author', email: 'pull_request_author@example.org')
+ end
+
+ let(:merge_event) do
+ instance_double(
+ BitbucketServer::Representation::Activity,
+ comment?: false,
+ merge_event?: true,
+ committer_email: pull_request_author.email,
+ merge_timestamp: now,
+ merge_commit: '12345678'
+ )
+ end
+
+ let(:pr_note) do
+ instance_double(
+ BitbucketServer::Representation::Comment,
+ note: 'Hello world',
+ author_email: note_author.email,
+ author_username: note_author.username,
+ comments: [],
+ created_at: now,
+ updated_at: now,
+ parent_comment: nil)
+ end
+
+ let(:pr_comment) do
+ instance_double(
+ BitbucketServer::Representation::Activity,
+ comment?: true,
+ inline_comment?: false,
+ merge_event?: false,
+ comment: pr_note)
+ end
+
+ let_it_be(:sample) { RepoHelpers.sample_compare }
+ let_it_be(:now) { Time.now.utc.change(usec: 0) }
+
+ def expect_log(stage:, message:)
+ allow(Gitlab::BitbucketServerImport::Logger).to receive(:info).and_call_original
+ expect(Gitlab::BitbucketServerImport::Logger)
+ .to receive(:info).with(include(import_stage: stage, message: message))
+ end
+
+ subject(:importer) { described_class.new(project, pull_request.to_hash) }
+
+ describe '#execute', :clean_gitlab_redis_cache do
+ context 'when a matching merge request is not found' do
+ it 'does nothing' do
+ expect { importer.execute }.not_to change { Note.count }
+ end
+
+ it 'logs its progress' do
+ expect_log(stage: 'import_pull_request_notes', message: 'starting')
+ expect_log(stage: 'import_pull_request_notes', message: 'finished')
+
+ importer.execute
+ end
+ end
+
+ context 'when a matching merge request is found' do
+ let_it_be(:merge_request) { create(:merge_request, iid: pull_request.iid, source_project: project) }
+
+ it 'logs its progress' do
+ allow_next(BitbucketServer::Client).to receive(:activities).and_return([])
+
+ expect_log(stage: 'import_pull_request_notes', message: 'starting')
+ expect_log(stage: 'import_pull_request_notes', message: 'finished')
+
+ importer.execute
+ end
+
+ context 'when PR has comments' do
+ before do
+ allow_next(BitbucketServer::Client).to receive(:activities).and_return([pr_comment])
+ end
+
+ it 'imports the stand alone comments' do
+ expect { subject.execute }.to change { Note.count }.by(1)
+
+ expect(merge_request.notes.count).to eq(1)
+ expect(merge_request.notes.first).to have_attributes(
+ note: end_with(pr_note.note),
+ author: note_author,
+ created_at: pr_note.created_at,
+ updated_at: pr_note.created_at
+ )
+ end
+
+ it 'logs its progress' do
+ expect_log(stage: 'import_standalone_pr_comments', message: 'starting')
+ expect_log(stage: 'import_standalone_pr_comments', message: 'finished')
+
+ importer.execute
+ end
+ end
+
+ context 'when PR has threaded discussion' do
+ let_it_be(:reply_author) { create(:user, username: 'reply_author', email: 'reply_author@example.org') }
+ let_it_be(:inline_note_author) do
+ create(:user, username: 'inline_note_author', email: 'inline_note_author@example.org')
+ end
+
+ let(:reply) do
+ instance_double(
+ BitbucketServer::Representation::PullRequestComment,
+ author_email: reply_author.email,
+ author_username: reply_author.username,
+ note: 'I agree',
+ created_at: now,
+ updated_at: now,
+ parent_comment: nil)
+ end
+
+ let(:pr_inline_note) do
+ instance_double(
+ BitbucketServer::Representation::PullRequestComment,
+ file_type: 'ADDED',
+ from_sha: pull_request.target_branch_sha,
+ to_sha: pull_request.source_branch_sha,
+ file_path: '.gitmodules',
+ old_pos: nil,
+ new_pos: 4,
+ note: 'Hello world',
+ author_email: inline_note_author.email,
+ author_username: inline_note_author.username,
+ comments: [reply],
+ created_at: now,
+ updated_at: now,
+ parent_comment: nil)
+ end
+
+ let(:pr_inline_comment) do
+ instance_double(
+ BitbucketServer::Representation::Activity,
+ comment?: true,
+ inline_comment?: true,
+ merge_event?: false,
+ comment: pr_inline_note)
+ end
+
+ before do
+ allow_next(BitbucketServer::Client).to receive(:activities).and_return([pr_inline_comment])
+ end
+
+ it 'imports the threaded discussion' do
+ expect { subject.execute }.to change { Note.count }.by(2)
+
+ expect(merge_request.discussions.count).to eq(1)
+
+ notes = merge_request.notes.order(:id).to_a
+ start_note = notes.first
+ expect(start_note.type).to eq('DiffNote')
+ expect(start_note.note).to end_with(pr_inline_note.note)
+ expect(start_note.created_at).to eq(pr_inline_note.created_at)
+ expect(start_note.updated_at).to eq(pr_inline_note.updated_at)
+ expect(start_note.position.old_line).to be_nil
+ expect(start_note.position.new_line).to eq(pr_inline_note.new_pos)
+ expect(start_note.author).to eq(inline_note_author)
+
+ reply_note = notes.last
+ expect(reply_note.note).to eq(reply.note)
+ expect(reply_note.author).to eq(reply_author)
+ expect(reply_note.created_at).to eq(reply.created_at)
+ expect(reply_note.updated_at).to eq(reply.created_at)
+ expect(reply_note.position.old_line).to be_nil
+ expect(reply_note.position.new_line).to eq(pr_inline_note.new_pos)
+ end
+
+ it 'logs its progress' do
+ expect_log(stage: 'import_inline_comments', message: 'starting')
+ expect_log(stage: 'import_inline_comments', message: 'finished')
+
+ importer.execute
+ end
+ end
+
+ context 'when PR has a merge event' do
+ before do
+ allow_next(BitbucketServer::Client).to receive(:activities).and_return([merge_event])
+ end
+
+ it 'imports the merge event' do
+ importer.execute
+
+ merge_request.reload
+
+ expect(merge_request.metrics.merged_by).to eq(pull_request_author)
+ expect(merge_request.metrics.merged_at).to eq(merge_event.merge_timestamp)
+ expect(merge_request.merge_commit_sha).to eq(merge_event.merge_commit)
+ end
+ end
+ end
+ end
+end
diff --git a/spec/lib/gitlab/bitbucket_server_import/importers/pull_requests_importer_spec.rb b/spec/lib/gitlab/bitbucket_server_import/importers/pull_requests_importer_spec.rb
new file mode 100644
index 00000000000..b9a9c8dac29
--- /dev/null
+++ b/spec/lib/gitlab/bitbucket_server_import/importers/pull_requests_importer_spec.rb
@@ -0,0 +1,56 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe Gitlab::BitbucketServerImport::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(BitbucketServer::Client) do |client|
+ allow(client).to receive(:pull_requests).and_return(
+ [
+ BitbucketServer::Representation::PullRequest.new({ 'id' => 1 }),
+ BitbucketServer::Representation::PullRequest.new({ 'id' => 2 })
+ ],
+ []
+ )
+ end
+ end
+
+ it 'imports each pull request in parallel', :aggregate_failures do
+ expect(Gitlab::BitbucketServerImport::ImportPullRequestWorker).to receive(:perform_in).twice
+
+ waiter = importer.execute
+
+ expect(waiter).to be_an_instance_of(Gitlab::JobWaiter)
+ expect(waiter.jobs_remaining).to eq(2)
+ expect(Gitlab::Cache::Import::Caching.values_from_set(importer.already_processed_cache_key))
+ .to match_array(%w[1 2])
+ end
+
+ context 'when pull request was already processed' do
+ before do
+ Gitlab::Cache::Import::Caching.set_add(importer.already_processed_cache_key, 1)
+ end
+
+ it 'does not schedule job for processed pull requests', :aggregate_failures do
+ expect(Gitlab::BitbucketServerImport::ImportPullRequestWorker).to receive(:perform_in).once
+
+ waiter = importer.execute
+
+ expect(waiter).to be_an_instance_of(Gitlab::JobWaiter)
+ expect(waiter.jobs_remaining).to eq(2)
+ end
+ end
+ end
+end
diff --git a/spec/lib/gitlab/bitbucket_server_import/importers/repository_importer_spec.rb b/spec/lib/gitlab/bitbucket_server_import/importers/repository_importer_spec.rb
new file mode 100644
index 00000000000..6c4d500efb7
--- /dev/null
+++ b/spec/lib/gitlab/bitbucket_server_import/importers/repository_importer_spec.rb
@@ -0,0 +1,49 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe Gitlab::BitbucketServerImport::Importers::RepositoryImporter, feature_category: :importers do
+ let_it_be(:project) { create(:project, import_url: 'http://bitbucket:test@my-bitbucket') }
+
+ 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_server_import/parallel_importer_spec.rb b/spec/lib/gitlab/bitbucket_server_import/parallel_importer_spec.rb
new file mode 100644
index 00000000000..a36f2403403
--- /dev/null
+++ b/spec/lib/gitlab/bitbucket_server_import/parallel_importer_spec.rb
@@ -0,0 +1,45 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe Gitlab::BitbucketServerImport::ParallelImporter, feature_category: :importers do
+ describe '.async?' do
+ it 'returns true' do
+ expect(described_class).to be_async
+ end
+ end
+
+ describe '.track_start_import' do
+ it 'tracks the start of import' do
+ project = build_stubbed(:project)
+
+ expect_next_instance_of(Gitlab::Import::Metrics, :bitbucket_server_importer, project) do |metric|
+ expect(metric).to receive(:track_start_import)
+ end
+
+ described_class.track_start_import(project)
+ end
+ end
+
+ describe '#execute', :clean_gitlab_redis_shared_state do
+ let_it_be(:project) { create(:project) }
+ let(:importer) { described_class.new(project) }
+
+ before do
+ create(:import_state, :started, project: project)
+ end
+
+ it 'schedules the importing of the repository' do
+ expect(Gitlab::BitbucketServerImport::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_server_import/user_finder_spec.rb b/spec/lib/gitlab/bitbucket_server_import/user_finder_spec.rb
new file mode 100644
index 00000000000..70923df3064
--- /dev/null
+++ b/spec/lib/gitlab/bitbucket_server_import/user_finder_spec.rb
@@ -0,0 +1,121 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe Gitlab::BitbucketServerImport::UserFinder, :clean_gitlab_redis_cache, feature_category: :importers do
+ let_it_be(:user) { create(:user) }
+
+ let(:created_id) { 1 }
+ let(:project) { instance_double(Project, creator_id: created_id, id: 1) }
+
+ subject(:user_finder) { described_class.new(project) }
+
+ describe '#author_id' do
+ it 'calls uid method' do
+ object = { author_username: user.username }
+
+ expect(user_finder).to receive(:uid).with(object).and_return(10)
+ expect(user_finder.author_id(object)).to eq(10)
+ end
+
+ context 'when corresponding user does not exist' do
+ it 'fallsback to project creator_id' do
+ object = { author_email: 'unknown' }
+
+ expect(user_finder.author_id(object)).to eq(created_id)
+ end
+ end
+ end
+
+ describe '#uid' do
+ context 'when provided object is a Hash' do
+ it 'maps to an existing user with the same username' do
+ object = { author_username: user.username }
+
+ expect(user_finder.uid(object)).to eq(user.id)
+ end
+ end
+
+ context 'when provided object is a representation Object' do
+ it 'maps to a existing user with the same username' do
+ object = instance_double(BitbucketServer::Representation::Comment, author_username: user.username)
+
+ expect(user_finder.uid(object)).to eq(user.id)
+ end
+ end
+
+ context 'when corresponding user does not exist' do
+ it 'returns nil' do
+ object = { author_username: 'unknown' }
+
+ expect(user_finder.uid(object)).to eq(nil)
+ end
+ end
+
+ context 'when bitbucket_server_user_mapping_by_username is disabled' do
+ before do
+ stub_feature_flags(bitbucket_server_user_mapping_by_username: false)
+ end
+
+ context 'when provided object is a Hash' do
+ it 'maps to an existing user with the same email' do
+ object = { author_email: user.email }
+
+ expect(user_finder.uid(object)).to eq(user.id)
+ end
+ end
+
+ context 'when provided object is a representation Object' do
+ it 'maps to an existing user with the same email' do
+ object = instance_double(BitbucketServer::Representation::Comment, author_email: user.email)
+
+ expect(user_finder.uid(object)).to eq(user.id)
+ end
+ end
+
+ context 'when corresponding user does not exist' do
+ it 'returns nil' do
+ object = { author_email: 'unknown' }
+
+ expect(user_finder.uid(object)).to eq(nil)
+ end
+ end
+ end
+ end
+
+ describe '#find_user_id' do
+ context 'when user cannot be found' do
+ it 'caches and returns nil' do
+ expect(User).to receive(:find_by_any_email).once.and_call_original
+
+ 2.times do
+ user_id = user_finder.find_user_id(by: :email, value: 'nobody@example.com')
+
+ expect(user_id).to be_nil
+ end
+ end
+ end
+
+ context 'when user can be found' do
+ it 'caches and returns the user ID by email' do
+ expect(User).to receive(:find_by_any_email).once.and_call_original
+
+ 2.times do
+ user_id = user_finder.find_user_id(by: :email, value: user.email)
+
+ expect(user_id).to eq(user.id)
+ end
+ end
+
+ it 'caches and returns the user ID by username' do
+ expect(User).to receive(:find_by_username).once.and_call_original
+
+ 2.times do
+ user_id = user_finder.find_user_id(by: :username, value: user.username)
+
+ expect(user_id).to eq(user.id)
+ end
+ end
+ end
+ end
+end
diff --git a/spec/lib/gitlab/import_sources_spec.rb b/spec/lib/gitlab/import_sources_spec.rb
index f1ea5f3e85e..b243780a020 100644
--- a/spec/lib/gitlab/import_sources_spec.rb
+++ b/spec/lib/gitlab/import_sources_spec.rb
@@ -59,7 +59,7 @@ RSpec.describe Gitlab::ImportSources, feature_category: :importers do
import_sources = {
'github' => Gitlab::GithubImport::ParallelImporter,
'bitbucket' => Gitlab::BitbucketImport::Importer,
- 'bitbucket_server' => Gitlab::BitbucketServerImport::Importer,
+ 'bitbucket_server' => Gitlab::BitbucketServerImport::ParallelImporter,
'fogbugz' => Gitlab::FogbugzImport::Importer,
'git' => nil,
'gitlab_project' => Gitlab::ImportExport::Importer,
@@ -72,6 +72,46 @@ RSpec.describe Gitlab::ImportSources, feature_category: :importers do
expect(described_class.importer(name)).to eq(klass)
end
end
+
+ context 'when flag is disabled' do
+ before do
+ stub_feature_flags(bitbucket_server_parallel_importer: false)
+ end
+
+ it 'returns Gitlab::BitbucketServerImport::Importer when given bitbucket_server' do
+ expect(described_class.importer('bitbucket_server')).to eq(Gitlab::BitbucketServerImport::Importer)
+ end
+ end
+ end
+
+ describe '.import_table' do
+ subject { described_class.import_table }
+
+ it 'returns the ParallelImporter for Bitbucket server' do
+ is_expected.to include(
+ described_class::ImportSource.new(
+ 'bitbucket_server',
+ 'Bitbucket Server',
+ Gitlab::BitbucketServerImport::ParallelImporter
+ )
+ )
+ end
+
+ context 'when flag is disabled' do
+ before do
+ stub_feature_flags(bitbucket_server_parallel_importer: false)
+ end
+
+ it 'returns the legacy Importer for Bitbucket server' do
+ is_expected.to include(
+ described_class::ImportSource.new(
+ 'bitbucket_server',
+ 'Bitbucket Server',
+ Gitlab::BitbucketServerImport::Importer
+ )
+ )
+ end
+ end
end
describe '.title' do
diff --git a/spec/support/shared_examples/lib/gitlab/bitbucket_server_import/object_import_shared_examples.rb b/spec/support/shared_examples/lib/gitlab/bitbucket_server_import/object_import_shared_examples.rb
new file mode 100644
index 00000000000..ec2ae0b8a73
--- /dev/null
+++ b/spec/support/shared_examples/lib/gitlab/bitbucket_server_import/object_import_shared_examples.rb
@@ -0,0 +1,69 @@
+# frozen_string_literal: true
+
+RSpec.shared_examples Gitlab::BitbucketServerImport::ObjectImporter do
+ include AfterNextHelpers
+
+ describe '.sidekiq_retries_exhausted' do
+ let(:job) { { 'args' => [1, {}, 'key'], 'jid' => 'jid' } }
+
+ it 'notifies the waiter' do
+ expect(Gitlab::JobWaiter).to receive(:notify).with('key', 'jid')
+
+ described_class.sidekiq_retries_exhausted_block.call(job, StandardError.new)
+ end
+ end
+
+ describe '#perform' do
+ let_it_be(:import_started_project) { create(:project, :import_started) }
+
+ let(:project_id) { project_id }
+ let(:waiter_key) { 'key' }
+
+ shared_examples 'notifies the waiter' do
+ specify do
+ allow_next(worker.importer_class).to receive(:execute)
+
+ expect(Gitlab::JobWaiter).to receive(:notify).with(waiter_key, anything)
+
+ worker.perform(project_id, {}, waiter_key)
+ end
+ end
+
+ context 'when project does not exist' do
+ let(:project_id) { non_existing_record_id }
+
+ it_behaves_like 'notifies the waiter'
+ end
+
+ context 'when project has import started' do
+ let_it_be(:project) do
+ create(:project, :import_started, import_data_attributes: {
+ data: { 'project_key' => 'key', 'repo_slug' => 'slug' },
+ credentials: { 'token' => 'token' }
+ })
+ end
+
+ let(:project_id) { project.id }
+
+ it 'calls the importer' do
+ expect_next(worker.importer_class, project, kind_of(Hash)).to receive(:execute)
+
+ worker.perform(project_id, {}, waiter_key)
+ end
+
+ it_behaves_like 'notifies the waiter'
+ end
+
+ context 'when project import has been cancelled' do
+ let_it_be(:project_id) { create(:project, :import_canceled).id }
+
+ it 'does not call the importer' do
+ expect_next(worker.importer_class).not_to receive(:execute)
+
+ worker.perform(project_id, {}, waiter_key)
+ end
+
+ it_behaves_like 'notifies the waiter'
+ end
+ end
+end
diff --git a/spec/support/shared_examples/lib/gitlab/bitbucket_server_import/stage_methods_shared_examples.rb b/spec/support/shared_examples/lib/gitlab/bitbucket_server_import/stage_methods_shared_examples.rb
new file mode 100644
index 00000000000..1246dd2979b
--- /dev/null
+++ b/spec/support/shared_examples/lib/gitlab/bitbucket_server_import/stage_methods_shared_examples.rb
@@ -0,0 +1,18 @@
+# frozen_string_literal: true
+
+RSpec.shared_examples Gitlab::BitbucketServerImport::StageMethods do
+ describe '.sidekiq_retries_exhausted' do
+ let(:job) { { 'args' => [project.id] } }
+
+ it 'tracks the import failure' do
+ expect(Gitlab::Import::ImportFailureService)
+ .to receive(:track).with(
+ project_id: project.id,
+ exception: StandardError.new,
+ fail_import: true
+ )
+
+ described_class.sidekiq_retries_exhausted_block.call(job, StandardError.new)
+ end
+ end
+end
diff --git a/spec/workers/every_sidekiq_worker_spec.rb b/spec/workers/every_sidekiq_worker_spec.rb
index 16173e322b6..26dd67bf2c0 100644
--- a/spec/workers/every_sidekiq_worker_spec.rb
+++ b/spec/workers/every_sidekiq_worker_spec.rb
@@ -261,6 +261,12 @@ RSpec.describe 'Every Sidekiq worker', feature_category: :shared do
'Geo::VerificationWorker' => 3,
'GeoRepositoryDestroyWorker' => 3,
'GitGarbageCollectWorker' => false,
+ 'Gitlab::BitbucketServerImport::AdvanceStageWorker' => 3,
+ 'Gitlab::BitbucketServerImport::Stage::FinishImportWorker' => 3,
+ 'Gitlab::BitbucketServerImport::Stage::ImportLfsObjectsWorker' => 3,
+ 'Gitlab::BitbucketServerImport::Stage::ImportNotesWorker' => 3,
+ 'Gitlab::BitbucketServerImport::Stage::ImportPullRequestsWorker' => 3,
+ 'Gitlab::BitbucketServerImport::Stage::ImportRepositoryWorker' => 3,
'Gitlab::GithubImport::AdvanceStageWorker' => 3,
'Gitlab::GithubImport::ImportReleaseAttachmentsWorker' => 5,
'Gitlab::GithubImport::Attachments::ImportReleaseWorker' => 5,
diff --git a/spec/workers/gitlab/bitbucket_server_import/import_lfs_object_worker_spec.rb b/spec/workers/gitlab/bitbucket_server_import/import_lfs_object_worker_spec.rb
new file mode 100644
index 00000000000..a74c148cbc9
--- /dev/null
+++ b/spec/workers/gitlab/bitbucket_server_import/import_lfs_object_worker_spec.rb
@@ -0,0 +1,14 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe Gitlab::BitbucketServerImport::ImportLfsObjectWorker, feature_category: :importers do
+ subject(:worker) { described_class.new }
+
+ it_behaves_like Gitlab::BitbucketServerImport::ObjectImporter do
+ before do
+ # Stub the LfsDownloadObject for these tests so it can be passed an empty Hash
+ allow(LfsDownloadObject).to receive(:new)
+ end
+ end
+end
diff --git a/spec/workers/gitlab/bitbucket_server_import/import_pull_request_notes_worker_spec.rb b/spec/workers/gitlab/bitbucket_server_import/import_pull_request_notes_worker_spec.rb
new file mode 100644
index 00000000000..bc400bc59e8
--- /dev/null
+++ b/spec/workers/gitlab/bitbucket_server_import/import_pull_request_notes_worker_spec.rb
@@ -0,0 +1,9 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe Gitlab::BitbucketServerImport::ImportPullRequestNotesWorker, feature_category: :importers do
+ subject(:worker) { described_class.new }
+
+ it_behaves_like Gitlab::BitbucketServerImport::ObjectImporter
+end
diff --git a/spec/workers/gitlab/bitbucket_server_import/import_pull_request_worker_spec.rb b/spec/workers/gitlab/bitbucket_server_import/import_pull_request_worker_spec.rb
new file mode 100644
index 00000000000..dd3235f846c
--- /dev/null
+++ b/spec/workers/gitlab/bitbucket_server_import/import_pull_request_worker_spec.rb
@@ -0,0 +1,84 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe Gitlab::BitbucketServerImport::ImportPullRequestWorker, feature_category: :importers do
+ let_it_be(:project) { create(:project, :import_started) }
+
+ let(:worker) { described_class.new }
+
+ let(:job_waiter_key) { 'ABC' }
+
+ let(:importer_class) { Gitlab::BitbucketServerImport::Importers::PullRequestImporter }
+
+ before do
+ allow(worker).to receive(:jid).and_return('jid')
+ end
+
+ it_behaves_like Gitlab::BitbucketServerImport::ObjectImporter
+
+ describe '#perform' do
+ context 'when the import succeeds' do
+ before do
+ allow_next_instance_of(importer_class) do |importer|
+ allow(importer).to receive(:execute)
+ end
+ end
+
+ it 'notifies job waiter' do
+ expect(Gitlab::JobWaiter).to receive(:notify).with(job_waiter_key, 'jid')
+
+ worker.perform(project.id, {}, job_waiter_key)
+ end
+
+ it 'logs stage start and finish' do
+ expect(Gitlab::BitbucketServerImport::Logger)
+ .to receive(:info).with(hash_including(message: 'importer started', project_id: project.id))
+ expect(Gitlab::BitbucketServerImport::Logger)
+ .to receive(:info).with(hash_including(message: 'importer finished', project_id: project.id))
+
+ worker.perform(project.id, {}, job_waiter_key)
+ end
+ end
+
+ context 'when project does not exists' do
+ it 'does not call importer and notifies job waiter' do
+ expect(importer_class).not_to receive(:new)
+ expect(Gitlab::JobWaiter).to receive(:notify).with(job_waiter_key, 'jid')
+
+ worker.perform(-1, {}, job_waiter_key)
+ end
+ end
+
+ context 'when project import state is not `started`' do
+ it 'does not call importer' do
+ project = create(:project, :import_canceled)
+
+ expect(importer_class).not_to receive(:new)
+ expect(Gitlab::JobWaiter).to receive(:notify).with(job_waiter_key, 'jid')
+
+ worker.perform(project.id, {}, job_waiter_key)
+ end
+ end
+
+ context 'when the importer fails' do
+ it 'raises an error' do
+ exception = StandardError.new('Error')
+
+ allow_next_instance_of(importer_class) do |importer|
+ allow(importer).to receive(:execute).and_raise(exception)
+ end
+
+ expect(Gitlab::Import::ImportFailureService)
+ .to receive(:track).with(
+ project_id: project.id,
+ exception: exception,
+ error_source: importer_class.name,
+ fail_import: false
+ ).and_call_original
+
+ expect { worker.perform(project.id, {}, job_waiter_key) }.to raise_error(exception)
+ end
+ end
+ end
+end
diff --git a/spec/workers/gitlab/bitbucket_server_import/stage/finish_import_worker_spec.rb b/spec/workers/gitlab/bitbucket_server_import/stage/finish_import_worker_spec.rb
new file mode 100644
index 00000000000..cb61ee13dd1
--- /dev/null
+++ b/spec/workers/gitlab/bitbucket_server_import/stage/finish_import_worker_spec.rb
@@ -0,0 +1,23 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe Gitlab::BitbucketServerImport::Stage::FinishImportWorker, feature_category: :importers do
+ let_it_be(:project) { create(:project, :import_started) }
+
+ subject(:worker) { described_class.new }
+
+ it_behaves_like Gitlab::BitbucketServerImport::StageMethods
+
+ describe '#perform' do
+ it 'finalises the import process' do
+ expect_next_instance_of(Gitlab::Import::Metrics, :bitbucket_server_importer, project) do |metric|
+ expect(metric).to receive(:track_finished_import)
+ end
+
+ worker.perform(project.id)
+
+ expect(project.import_state.reload).to be_finished
+ end
+ end
+end
diff --git a/spec/workers/gitlab/bitbucket_server_import/stage/import_lfs_objects_worker_spec.rb b/spec/workers/gitlab/bitbucket_server_import/stage/import_lfs_objects_worker_spec.rb
new file mode 100644
index 00000000000..449e22e67e2
--- /dev/null
+++ b/spec/workers/gitlab/bitbucket_server_import/stage/import_lfs_objects_worker_spec.rb
@@ -0,0 +1,28 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe Gitlab::BitbucketServerImport::Stage::ImportLfsObjectsWorker, feature_category: :importers do
+ let_it_be(:project) { create(:project, :import_started) }
+
+ subject(:worker) { described_class.new }
+
+ it_behaves_like Gitlab::BitbucketServerImport::StageMethods
+
+ describe '#perform' do
+ context 'when the import succeeds' do
+ before do
+ allow_next_instance_of(Gitlab::BitbucketServerImport::Importers::LfsObjectsImporter) do |importer|
+ allow(importer).to receive(:execute).and_return(Gitlab::JobWaiter.new(2, '123'))
+ end
+ end
+
+ it 'schedules the next stage' do
+ expect(Gitlab::BitbucketServerImport::AdvanceStageWorker).to receive(:perform_async)
+ .with(project.id, { '123' => 2 }, :finish)
+
+ worker.perform(project.id)
+ end
+ end
+ end
+end
diff --git a/spec/workers/gitlab/bitbucket_server_import/stage/import_notes_worker_spec.rb b/spec/workers/gitlab/bitbucket_server_import/stage/import_notes_worker_spec.rb
new file mode 100644
index 00000000000..f7512c74d49
--- /dev/null
+++ b/spec/workers/gitlab/bitbucket_server_import/stage/import_notes_worker_spec.rb
@@ -0,0 +1,28 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe Gitlab::BitbucketServerImport::Stage::ImportNotesWorker, feature_category: :importers do
+ let_it_be(:project) { create(:project, :import_started) }
+
+ subject(:worker) { described_class.new }
+
+ it_behaves_like Gitlab::BitbucketServerImport::StageMethods
+
+ describe '#perform' do
+ context 'when the import succeeds' do
+ before do
+ allow_next_instance_of(Gitlab::BitbucketServerImport::Importers::NotesImporter) do |importer|
+ allow(importer).to receive(:execute).and_return(Gitlab::JobWaiter.new(2, '123'))
+ end
+ end
+
+ it 'schedules the next stage' do
+ expect(Gitlab::BitbucketServerImport::AdvanceStageWorker).to receive(:perform_async)
+ .with(project.id, { '123' => 2 }, :lfs_objects)
+
+ worker.perform(project.id)
+ end
+ end
+ end
+end
diff --git a/spec/workers/gitlab/bitbucket_server_import/stage/import_pull_requests_worker_spec.rb b/spec/workers/gitlab/bitbucket_server_import/stage/import_pull_requests_worker_spec.rb
new file mode 100644
index 00000000000..77400cabefa
--- /dev/null
+++ b/spec/workers/gitlab/bitbucket_server_import/stage/import_pull_requests_worker_spec.rb
@@ -0,0 +1,77 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe Gitlab::BitbucketServerImport::Stage::ImportPullRequestsWorker, feature_category: :importers do
+ let_it_be(:project) { create(:project, :import_started) }
+
+ subject(:worker) { described_class.new }
+
+ it_behaves_like Gitlab::BitbucketServerImport::StageMethods
+
+ describe '#perform' do
+ context 'when the import succeeds' do
+ before do
+ allow_next_instance_of(Gitlab::BitbucketServerImport::Importers::PullRequestsImporter) do |importer|
+ allow(importer).to receive(:execute).and_return(Gitlab::JobWaiter.new(2, '123'))
+ end
+ end
+
+ it 'schedules the next stage' do
+ expect(Gitlab::BitbucketServerImport::AdvanceStageWorker).to receive(:perform_async)
+ .with(project.id, { '123' => 2 }, :notes)
+
+ worker.perform(project.id)
+ end
+
+ it 'logs stage start and finish' do
+ expect(Gitlab::BitbucketServerImport::Logger)
+ .to receive(:info).with(hash_including(message: 'starting stage', project_id: project.id))
+ expect(Gitlab::BitbucketServerImport::Logger)
+ .to receive(:info).with(hash_including(message: 'stage finished', project_id: project.id))
+
+ worker.perform(project.id)
+ end
+ end
+
+ context 'when project does not exists' do
+ it 'does not call the importer' do
+ expect(Gitlab::BitbucketServerImport::Importers::PullRequestsImporter).not_to receive(:new)
+
+ worker.perform(-1)
+ end
+ end
+
+ context 'when project import state is not `started`' do
+ it 'does not call the importer' do
+ project = create(:project, :import_canceled)
+
+ expect(Gitlab::BitbucketServerImport::Importers::PullRequestsImporter).not_to receive(:new)
+
+ worker.perform(project.id)
+ end
+ end
+
+ context 'when the importer fails' do
+ it 'does not schedule the next stage and raises error' do
+ exception = StandardError.new('Error')
+
+ allow_next_instance_of(Gitlab::BitbucketServerImport::Importers::PullRequestsImporter) do |importer|
+ allow(importer).to receive(:execute).and_raise(exception)
+ end
+
+ expect(Gitlab::Import::ImportFailureService)
+ .to receive(:track).with(
+ project_id: project.id,
+ exception: exception,
+ error_source: described_class.name,
+ fail_import: false
+ ).and_call_original
+
+ expect { worker.perform(project.id) }
+ .to change { Gitlab::BitbucketServerImport::AdvanceStageWorker.jobs.size }.by(0)
+ .and raise_error(exception)
+ end
+ end
+ end
+end
diff --git a/spec/workers/gitlab/bitbucket_server_import/stage/import_repository_worker_spec.rb b/spec/workers/gitlab/bitbucket_server_import/stage/import_repository_worker_spec.rb
new file mode 100644
index 00000000000..7ea23041e79
--- /dev/null
+++ b/spec/workers/gitlab/bitbucket_server_import/stage/import_repository_worker_spec.rb
@@ -0,0 +1,77 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe Gitlab::BitbucketServerImport::Stage::ImportRepositoryWorker, feature_category: :importers do
+ let_it_be(:project) { create(:project, :import_started) }
+
+ let(:worker) { described_class.new }
+
+ it_behaves_like Gitlab::BitbucketServerImport::StageMethods
+
+ describe '#perform' do
+ context 'when the import succeeds' do
+ before do
+ allow_next_instance_of(Gitlab::BitbucketServerImport::Importers::RepositoryImporter) do |importer|
+ allow(importer).to receive(:execute)
+ end
+ end
+
+ it 'schedules the next stage' do
+ expect(Gitlab::BitbucketServerImport::Stage::ImportPullRequestsWorker).to receive(:perform_async)
+ .with(project.id)
+
+ worker.perform(project.id)
+ end
+
+ it 'logs stage start and finish' do
+ expect(Gitlab::BitbucketServerImport::Logger)
+ .to receive(:info).with(hash_including(message: 'starting stage', project_id: project.id))
+ expect(Gitlab::BitbucketServerImport::Logger)
+ .to receive(:info).with(hash_including(message: 'stage finished', project_id: project.id))
+
+ worker.perform(project.id)
+ end
+ end
+
+ context 'when project does not exists' do
+ it 'does not call importer' do
+ expect(Gitlab::BitbucketServerImport::Importers::RepositoryImporter).not_to receive(:new)
+
+ worker.perform(-1)
+ end
+ end
+
+ context 'when project import state is not `started`' do
+ it 'does not call importer' do
+ project = create(:project, :import_canceled)
+
+ expect(Gitlab::BitbucketServerImport::Importers::RepositoryImporter).not_to receive(:new)
+
+ worker.perform(project.id)
+ end
+ end
+
+ context 'when the importer fails' do
+ it 'does not schedule the next stage and raises error' do
+ exception = StandardError.new('Error')
+
+ allow_next_instance_of(Gitlab::BitbucketServerImport::Importers::RepositoryImporter) do |importer|
+ allow(importer).to receive(:execute).and_raise(exception)
+ end
+
+ expect(Gitlab::Import::ImportFailureService)
+ .to receive(:track).with(
+ project_id: project.id,
+ exception: exception,
+ error_source: described_class.name,
+ fail_import: true
+ ).and_call_original
+
+ expect { worker.perform(project.id) }
+ .to change { Gitlab::BitbucketServerImport::Stage::ImportPullRequestsWorker.jobs.size }.by(0)
+ .and raise_error(exception)
+ end
+ end
+ end
+end