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/workers/bulk_imports/transform_references_worker_spec.rb')
-rw-r--r--spec/workers/bulk_imports/transform_references_worker_spec.rb257
1 files changed, 257 insertions, 0 deletions
diff --git a/spec/workers/bulk_imports/transform_references_worker_spec.rb b/spec/workers/bulk_imports/transform_references_worker_spec.rb
new file mode 100644
index 00000000000..6295ecb47d6
--- /dev/null
+++ b/spec/workers/bulk_imports/transform_references_worker_spec.rb
@@ -0,0 +1,257 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe BulkImports::TransformReferencesWorker, feature_category: :importers do
+ let_it_be(:project) do
+ project = create(:project)
+ project.add_owner(user)
+ project
+ end
+
+ let_it_be(:user) { create(:user) }
+ let_it_be(:bulk_import) { create(:bulk_import) }
+
+ let_it_be(:entity) do
+ create(:bulk_import_entity, :project_entity, project: project, bulk_import: bulk_import,
+ source_full_path: 'source/full/path')
+ end
+
+ let_it_be(:tracker) { create(:bulk_import_tracker, entity: entity) }
+ let_it_be(:config) { create(:bulk_import_configuration, bulk_import: bulk_import, url: 'https://my.gitlab.com') }
+
+ let_it_be_with_refind(:issue) do
+ create(:issue,
+ project: project,
+ description: 'https://my.gitlab.com/source/full/path/-/issues/1')
+ end
+
+ let_it_be(:merge_request) do
+ create(:merge_request,
+ source_project: project,
+ description: 'https://my.gitlab.com/source/full/path/-/merge_requests/1 @source_username? @bob, @alice!')
+ end
+
+ let_it_be(:issue_note) do
+ create(:note,
+ noteable: issue,
+ project: project,
+ note: 'https://my.gitlab.com/source/full/path/-/issues/1 @older_username, not_a@username, and @old_username.')
+ end
+
+ let_it_be(:merge_request_note) do
+ create(:note,
+ noteable: merge_request,
+ project: project,
+ note: 'https://my.gitlab.com/source/full/path/-/merge_requests/1 @same_username')
+ end
+
+ let_it_be(:system_note) do
+ create(:note,
+ project: project,
+ system: true,
+ noteable: issue,
+ note: "mentioned in merge request !#{merge_request.iid} created by @old_username",
+ note_html: 'note html'
+ )
+ end
+
+ let(:expected_url) do
+ expected_url = URI('')
+ expected_url.scheme = ::Gitlab.config.gitlab.https ? 'https' : 'http'
+ expected_url.host = ::Gitlab.config.gitlab.host
+ expected_url.port = ::Gitlab.config.gitlab.port
+ expected_url.path = "/#{project.full_path}"
+ expected_url
+ end
+
+ subject { described_class.new.perform([object.id], object.class.to_s, tracker.id) }
+
+ before do
+ allow(Gitlab::Cache::Import::Caching)
+ .to receive(:values_from_hash)
+ .and_return({
+ 'old_username' => 'new_username',
+ 'older_username' => 'newer_username',
+ 'source_username' => 'destination_username',
+ 'bob' => 'alice-gdk',
+ 'alice' => 'bob-gdk',
+ 'manuelgrabowski' => 'manuelgrabowski-admin',
+ 'manuelgrabowski-admin' => 'manuelgrabowski',
+ 'boaty-mc-boatface' => 'boatymcboatface',
+ 'boatymcboatface' => 'boaty-mc-boatface'
+ })
+ end
+
+ it_behaves_like 'an idempotent worker' do
+ let(:job_args) { [[issue.id], 'Issue', tracker.id] }
+ end
+
+ it 'transforms and saves multiple objects' do
+ old_note = merge_request_note.note
+ merge_request_note_2 = create(:note, noteable: merge_request, project: project, note: old_note)
+
+ described_class.new.perform([merge_request_note.id, merge_request_note_2.id], 'Note', tracker.id)
+
+ expect(merge_request_note.reload.note).not_to eq(old_note)
+ expect(merge_request_note_2.reload.note).not_to eq(old_note)
+ end
+
+ shared_examples 'transforms and saves references' do
+ it 'transforms references and saves the object' do
+ expect_any_instance_of(object.class) do |object|
+ expect(object).to receive(:save!)
+ end
+
+ expect { subject }.not_to change { object.updated_at }
+
+ expect(body).to eq(expected_body)
+ end
+
+ context 'when an error is raised' do
+ before do
+ allow(BulkImports::UsersMapper).to receive(:new).and_raise(StandardError)
+ end
+
+ it 'tracks the error and creates an import failure' do
+ expect(Gitlab::ErrorTracking).to receive(:track_exception)
+ .with(anything, hash_including(bulk_import_id: bulk_import.id))
+
+ expect(BulkImports::Failure).to receive(:create)
+ .with(hash_including(bulk_import_entity_id: entity.id, pipeline_class: 'ReferencesPipeline'))
+
+ subject
+ end
+ end
+ end
+
+ context 'for issue description' do
+ let(:object) { issue }
+ let(:body) { object.reload.description }
+ let(:expected_body) { "http://localhost:80/#{object.namespace.full_path}/-/issues/1" }
+
+ include_examples 'transforms and saves references'
+
+ shared_examples 'returns object unchanged' do
+ it 'returns object unchanged' do
+ issue.update!(description: description)
+
+ subject
+
+ expect(issue.reload.description).to eq(description)
+ end
+
+ it 'does not save the object' do
+ expect_any_instance_of(object.class) do |object|
+ expect(object).to receive(:save!)
+ end
+
+ subject
+ end
+ end
+
+ context 'when object does not have reference or username' do
+ let(:description) { 'foo' }
+
+ include_examples 'returns object unchanged'
+ end
+
+ context 'when there are no matched urls or usernames' do
+ let(:description) { 'https://my.gitlab.com/another/project/path/-/issues/1 @random_username' }
+
+ include_examples 'returns object unchanged'
+ end
+
+ context 'when url path does not start with source full path' do
+ let(:description) { 'https://my.gitlab.com/another/source/full/path/-/issues/1' }
+
+ include_examples 'returns object unchanged'
+ end
+
+ context 'when host does not match and url path starts with source full path' do
+ let(:description) { 'https://another.gitlab.com/source/full/path/-/issues/1' }
+
+ include_examples 'returns object unchanged'
+ end
+
+ context 'when url does not match at all' do
+ let(:description) { 'https://website.example/foo/bar' }
+
+ include_examples 'returns object unchanged'
+ end
+ end
+
+ context 'for merge request description' do
+ let(:object) { merge_request }
+ let(:body) { object.reload.description }
+ let(:expected_body) do
+ "#{expected_url}/-/merge_requests/#{merge_request.iid} @destination_username? @alice-gdk, @bob-gdk!"
+ end
+
+ include_examples 'transforms and saves references'
+ end
+
+ context 'for issue notes' do
+ let(:object) { issue_note }
+ let(:body) { object.reload.note }
+ let(:expected_body) { "#{expected_url}/-/issues/#{issue.iid} @newer_username, not_a@username, and @new_username." }
+
+ include_examples 'transforms and saves references'
+ end
+
+ context 'for merge request notes' do
+ let(:object) { merge_request_note }
+ let(:body) { object.reload.note }
+ let(:expected_body) { "#{expected_url}/-/merge_requests/#{merge_request.iid} @same_username" }
+
+ include_examples 'transforms and saves references'
+ end
+
+ context 'for system notes' do
+ let(:object) { system_note }
+ let(:body) { object.reload.note }
+ let(:expected_body) { "mentioned in merge request !#{merge_request.iid} created by @new_username" }
+
+ include_examples 'transforms and saves references'
+
+ context 'when the note includes a username' do
+ let_it_be(:object) do
+ create(:note,
+ project: project,
+ system: true,
+ noteable: issue,
+ note: 'mentioned in merge request created by @source_username.',
+ note_html: 'empty'
+ )
+ end
+
+ let(:body) { object.reload.note }
+ let(:expected_body) { 'mentioned in merge request created by @destination_username.' }
+
+ include_examples 'transforms and saves references'
+ end
+ end
+
+ context 'when old and new usernames are interchanged' do
+ # e.g
+ # |------------------------|-------------------------|
+ # | old_username | new_username |
+ # |------------------------|-------------------------|
+ # | @manuelgrabowski-admin | @manuelgrabowski |
+ # | @manuelgrabowski | @manuelgrabowski-admin |
+ # |------------------------|-------------------------|
+
+ let_it_be(:object) do
+ create(:note,
+ project: project,
+ noteable: merge_request,
+ note: '@manuelgrabowski-admin, @boaty-mc-boatface'
+ )
+ end
+
+ let(:body) { object.reload.note }
+ let(:expected_body) { '@manuelgrabowski, @boatymcboatface' }
+
+ include_examples 'transforms and saves references'
+ end
+end