diff options
author | GitLab Bot <gitlab-bot@gitlab.com> | 2021-04-12 21:12:15 +0300 |
---|---|---|
committer | GitLab Bot <gitlab-bot@gitlab.com> | 2021-04-12 21:12:15 +0300 |
commit | da59ce8b217f67707b391d9fb3503dbdf8c4e511 (patch) | |
tree | 6839f806745e333f25ddb29317aead689cced15b /spec | |
parent | 3df6bfc24c8877b9442d567378b8ebd8816cd443 (diff) |
Add latest changes from gitlab-org/gitlab@master
Diffstat (limited to 'spec')
22 files changed, 361 insertions, 174 deletions
diff --git a/spec/controllers/groups/group_links_controller_spec.rb b/spec/controllers/groups/group_links_controller_spec.rb index a2f7161ca41..94d3c1ffa0f 100644 --- a/spec/controllers/groups/group_links_controller_spec.rb +++ b/spec/controllers/groups/group_links_controller_spec.rb @@ -9,16 +9,17 @@ RSpec.describe Groups::GroupLinksController do let(:group_member) { create(:user) } let!(:project) { create(:project, group: shared_group) } - around do |example| - travel_to DateTime.new(2019, 4, 1) { example.run } - end - before do + travel_to DateTime.new(2019, 4, 1) sign_in(user) shared_with_group.add_developer(group_member) end + after do + travel_back + end + shared_examples 'placeholder is passed as `id` parameter' do |action| it 'returns a 404' do post( diff --git a/spec/controllers/groups/group_members_controller_spec.rb b/spec/controllers/groups/group_members_controller_spec.rb index aa9fd3759e5..19655687028 100644 --- a/spec/controllers/groups/group_members_controller_spec.rb +++ b/spec/controllers/groups/group_members_controller_spec.rb @@ -9,8 +9,12 @@ RSpec.describe Groups::GroupMembersController do let(:group) { create(:group, :public) } let(:membership) { create(:group_member, group: group) } - around do |example| - travel_to DateTime.new(2019, 4, 1) { example.run } + before do + travel_to DateTime.new(2019, 4, 1) + end + + after do + travel_back end describe 'GET index' do diff --git a/spec/controllers/projects/group_links_controller_spec.rb b/spec/controllers/projects/group_links_controller_spec.rb index 2fcdfbc2436..d514c486f60 100644 --- a/spec/controllers/projects/group_links_controller_spec.rb +++ b/spec/controllers/projects/group_links_controller_spec.rb @@ -8,15 +8,16 @@ RSpec.describe Projects::GroupLinksController do let_it_be(:project) { create(:project, :private, group: group2) } let_it_be(:user) { create(:user) } - around do |example| - travel_to DateTime.new(2019, 4, 1) { example.run } - end - before do + travel_to DateTime.new(2019, 4, 1) project.add_maintainer(user) sign_in(user) end + after do + travel_back + end + describe '#create' do shared_context 'link project to group' do before do diff --git a/spec/controllers/projects/merge_requests/drafts_controller_spec.rb b/spec/controllers/projects/merge_requests/drafts_controller_spec.rb index af39d4dec72..580211893dc 100644 --- a/spec/controllers/projects/merge_requests/drafts_controller_spec.rb +++ b/spec/controllers/projects/merge_requests/drafts_controller_spec.rb @@ -297,7 +297,7 @@ RSpec.describe Projects::MergeRequests::DraftsController do expect { post :publish, params: params }.to change { Note.count }.by(0).and change { DraftNote.count }.by(0) end - it 'publishes a draft note with quick actions and applies them' do + it 'publishes a draft note with quick actions and applies them', :sidekiq_inline do project.add_developer(user2) create(:draft_note, merge_request: merge_request, author: user, note: "/assign #{user2.to_reference}") diff --git a/spec/controllers/projects/project_members_controller_spec.rb b/spec/controllers/projects/project_members_controller_spec.rb index 53a7c2ca069..46a0fc8edb0 100644 --- a/spec/controllers/projects/project_members_controller_spec.rb +++ b/spec/controllers/projects/project_members_controller_spec.rb @@ -7,8 +7,12 @@ RSpec.describe Projects::ProjectMembersController do let(:group) { create(:group, :public) } let(:project) { create(:project, :public) } - around do |example| - travel_to DateTime.new(2019, 4, 1) { example.run } + before do + travel_to DateTime.new(2019, 4, 1) + end + + after do + travel_back end describe 'GET index' do diff --git a/spec/factories/clusters/applications/helm.rb b/spec/factories/clusters/applications/helm.rb index db4eb961ecd..1ff1292c36e 100644 --- a/spec/factories/clusters/applications/helm.rb +++ b/spec/factories/clusters/applications/helm.rb @@ -4,18 +4,26 @@ FactoryBot.define do factory :clusters_applications_helm, class: 'Clusters::Applications::Helm' do cluster factory: %i(cluster provided_by_gcp) - before(:create) do - allow(Gitlab::Kubernetes::Helm::V2::Certificate).to receive(:generate_root) - .and_return( - double( - key_string: File.read(Rails.root.join('spec/fixtures/clusters/sample_key.key')), - cert_string: File.read(Rails.root.join('spec/fixtures/clusters/sample_cert.pem')) + transient do + helm_installed { true } + end + + before(:create) do |_record, evaluator| + if evaluator.helm_installed + allow(Gitlab::Kubernetes::Helm::V2::Certificate).to receive(:generate_root) + .and_return( + double( + key_string: File.read(Rails.root.join('spec/fixtures/clusters/sample_key.key')), + cert_string: File.read(Rails.root.join('spec/fixtures/clusters/sample_cert.pem')) + ) ) - ) + end end - after(:create) do - allow(Gitlab::Kubernetes::Helm::V2::Certificate).to receive(:generate_root).and_call_original + after(:create) do |_record, evaluator| + if evaluator.helm_installed + allow(Gitlab::Kubernetes::Helm::V2::Certificate).to receive(:generate_root).and_call_original + end end trait :not_installable do @@ -78,14 +86,19 @@ FactoryBot.define do updated_at { ClusterWaitForAppInstallationWorker::TIMEOUT.ago } end + # Common trait used by the apps below + trait :no_helm_installed do + cluster factory: %i(cluster provided_by_gcp) + + transient do + helm_installed { false } + end + end + factory :clusters_applications_ingress, class: 'Clusters::Applications::Ingress' do modsecurity_enabled { false } cluster factory: %i(cluster with_installed_helm provided_by_gcp) - trait :no_helm_installed do - cluster factory: %i(cluster provided_by_gcp) - end - trait :modsecurity_blocking do modsecurity_enabled { true } modsecurity_mode { :blocking } @@ -108,62 +121,34 @@ FactoryBot.define do factory :clusters_applications_cert_manager, class: 'Clusters::Applications::CertManager' do email { 'admin@example.com' } cluster factory: %i(cluster with_installed_helm provided_by_gcp) - - trait :no_helm_installed do - cluster factory: %i(cluster provided_by_gcp) - end end factory :clusters_applications_elastic_stack, class: 'Clusters::Applications::ElasticStack' do cluster factory: %i(cluster with_installed_helm provided_by_gcp) - - trait :no_helm_installed do - cluster factory: %i(cluster provided_by_gcp) - end end factory :clusters_applications_crossplane, class: 'Clusters::Applications::Crossplane' do stack { 'gcp' } cluster factory: %i(cluster with_installed_helm provided_by_gcp) - - trait :no_helm_installed do - cluster factory: %i(cluster provided_by_gcp) - end end factory :clusters_applications_prometheus, class: 'Clusters::Applications::Prometheus' do cluster factory: %i(cluster with_installed_helm provided_by_gcp) - - trait :no_helm_installed do - cluster factory: %i(cluster provided_by_gcp) - end end factory :clusters_applications_runner, class: 'Clusters::Applications::Runner' do runner factory: %i(ci_runner) cluster factory: %i(cluster with_installed_helm provided_by_gcp) - - trait :no_helm_installed do - cluster factory: %i(cluster provided_by_gcp) - end end factory :clusters_applications_knative, class: 'Clusters::Applications::Knative' do hostname { 'example.com' } cluster factory: %i(cluster with_installed_helm provided_by_gcp) - - trait :no_helm_installed do - cluster factory: %i(cluster provided_by_gcp) - end end factory :clusters_applications_jupyter, class: 'Clusters::Applications::Jupyter' do oauth_application factory: :oauth_application cluster factory: %i(cluster with_installed_helm provided_by_gcp project) - - trait :no_helm_installed do - cluster factory: %i(cluster provided_by_gcp) - end end factory :clusters_applications_fluentd, class: 'Clusters::Applications::Fluentd' do @@ -171,18 +156,10 @@ FactoryBot.define do waf_log_enabled { true } cilium_log_enabled { true } cluster factory: %i(cluster with_installed_helm provided_by_gcp) - - trait :no_helm_installed do - cluster factory: %i(cluster provided_by_gcp) - end end factory :clusters_applications_cilium, class: 'Clusters::Applications::Cilium' do cluster factory: %i(cluster with_installed_helm provided_by_gcp) - - trait :no_helm_installed do - cluster factory: %i(cluster provided_by_gcp) - end end end end diff --git a/spec/features/error_pages_spec.rb b/spec/features/error_pages_spec.rb index 77f8aa87237..8dc9e5ade46 100644 --- a/spec/features/error_pages_spec.rb +++ b/spec/features/error_pages_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' -RSpec.describe 'Error Pages' do +RSpec.describe 'Error Pages', :js do let(:user) { create(:user) } let(:project) { create(:project, :public) } @@ -14,7 +14,12 @@ RSpec.describe 'Error Pages' do it 'shows nav links' do expect(page).to have_link("Home", href: root_path) expect(page).to have_link("Help", href: help_path) - expect(page).to have_link(nil, href: destroy_user_session_path) + end + + it 'allows user to sign out' do + click_link 'Sign out and sign in with a different account' + + expect(page).to have_current_path(new_user_session_path) end end diff --git a/spec/features/projects/user_sees_user_popover_spec.rb b/spec/features/projects/user_sees_user_popover_spec.rb index 52e65deae3b..e357824a533 100644 --- a/spec/features/projects/user_sees_user_popover_spec.rb +++ b/spec/features/projects/user_sees_user_popover_spec.rb @@ -35,7 +35,7 @@ RSpec.describe 'User sees user popover', :js do end end - it "displays user popover in system note" do + it 'displays user popover in system note', :sidekiq_inline do add_note("/assign @#{user.username}") find('.system-note-message .js-user-link').hover diff --git a/spec/frontend/content_editor/markdown_processing_spec.js b/spec/frontend/content_editor/markdown_processing_spec.js index 79ddfb8b125..e435af30e9f 100644 --- a/spec/frontend/content_editor/markdown_processing_spec.js +++ b/spec/frontend/content_editor/markdown_processing_spec.js @@ -1,13 +1,12 @@ -import createEditor from '~/content_editor/services/create_editor'; -import toMarkdown from '~/content_editor/services/to_markdown'; +import { createEditor } from '~/content_editor'; import { loadMarkdownApiExamples, loadMarkdownApiResult } from './markdown_processing_examples'; describe('markdown processing', () => { // Ensure we generate same markdown that was provided to Markdown API. it.each(loadMarkdownApiExamples())('correctly handles %s', async (testName, markdown) => { const { html } = loadMarkdownApiResult(testName); - const editor = await createEditor({ content: html }); + const editor = await createEditor({ content: markdown, renderMarkdown: () => html }); - expect(toMarkdown(editor.state.doc)).toBe(markdown); + expect(editor.getSerializedContent()).toBe(markdown); }); }); diff --git a/spec/frontend/content_editor/services/create_editor_spec.js b/spec/frontend/content_editor/services/create_editor_spec.js new file mode 100644 index 00000000000..4cf63e608eb --- /dev/null +++ b/spec/frontend/content_editor/services/create_editor_spec.js @@ -0,0 +1,39 @@ +import { PROVIDE_SERIALIZER_OR_RENDERER_ERROR } from '~/content_editor/constants'; +import createEditor from '~/content_editor/services/create_editor'; +import createMarkdownSerializer from '~/content_editor/services/markdown_serializer'; + +jest.mock('~/content_editor/services/markdown_serializer'); + +describe('content_editor/services/create_editor', () => { + const buildMockSerializer = () => ({ + serialize: jest.fn(), + deserialize: jest.fn(), + }); + + describe('creating an editor', () => { + it('uses markdown serializer when a renderMarkdown function is provided', async () => { + const renderMarkdown = () => true; + const mockSerializer = buildMockSerializer(); + createMarkdownSerializer.mockReturnValueOnce(mockSerializer); + + await createEditor({ renderMarkdown }); + + expect(createMarkdownSerializer).toHaveBeenCalledWith({ render: renderMarkdown }); + }); + + it('uses custom serializer when it is provided', async () => { + const mockSerializer = buildMockSerializer(); + const serializedContent = '**bold**'; + + mockSerializer.serialize.mockReturnValueOnce(serializedContent); + + const editor = await createEditor({ serializer: mockSerializer }); + + expect(editor.getSerializedContent()).toBe(serializedContent); + }); + + it('throws an error when neither a serializer or renderMarkdown fn are provided', async () => { + await expect(createEditor()).rejects.toThrow(PROVIDE_SERIALIZER_OR_RENDERER_ERROR); + }); + }); +}); diff --git a/spec/graphql/resolvers/repository_branch_names_resolver_spec.rb b/spec/graphql/resolvers/repository_branch_names_resolver_spec.rb new file mode 100644 index 00000000000..398dd7a2e2e --- /dev/null +++ b/spec/graphql/resolvers/repository_branch_names_resolver_spec.rb @@ -0,0 +1,36 @@ +# frozen_string_literal: true + +require 'spec_helper' + +RSpec.describe Resolvers::RepositoryBranchNamesResolver do + include GraphqlHelpers + + let(:project) { create(:project, :repository) } + + describe '#resolve' do + subject(:resolve_branch_names) do + resolve( + described_class, + obj: project.repository, + args: { search_pattern: pattern }, + ctx: { current_user: project.creator } + ) + end + + context 'with empty search pattern' do + let(:pattern) { '' } + + it 'returns nil' do + expect(resolve_branch_names).to eq(nil) + end + end + + context 'with a valid search pattern' do + let(:pattern) { 'mas*' } + + it 'returns matching branches' do + expect(resolve_branch_names).to match_array(['master']) + end + end + end +end diff --git a/spec/graphql/types/repository_type_spec.rb b/spec/graphql/types/repository_type_spec.rb index a3bb7e502f2..fa1e54dfcfa 100644 --- a/spec/graphql/types/repository_type_spec.rb +++ b/spec/graphql/types/repository_type_spec.rb @@ -14,4 +14,6 @@ RSpec.describe GitlabSchema.types['Repository'] do specify { expect(described_class).to have_graphql_field(:exists, calls_gitaly?: true, complexity: 2) } specify { expect(described_class).to have_graphql_field(:blobs) } + + specify { expect(described_class).to have_graphql_field(:branch_names, calls_gitaly?: true, complexity: 170) } end diff --git a/spec/lib/gitlab/ci/pipeline/chain/pipeline/process_spec.rb b/spec/lib/gitlab/ci/pipeline/chain/pipeline/process_spec.rb index 0fc46211044..3885cea2d1b 100644 --- a/spec/lib/gitlab/ci/pipeline/chain/pipeline/process_spec.rb +++ b/spec/lib/gitlab/ci/pipeline/chain/pipeline/process_spec.rb @@ -23,21 +23,6 @@ RSpec.describe Gitlab::Ci::Pipeline::Chain::Pipeline::Process do perform end - - context 'with async processing disabled' do - before do - stub_feature_flags(ci_async_initial_pipeline_processing: false) - end - - it 'processes pipeline inline' do - expect(::Ci::ProcessPipelineService) - .to receive(:new) - .with(pipeline) - .and_call_original - - perform - end - end end describe '#break?' do diff --git a/spec/migrations/move_container_registry_enabled_to_project_features_spec.rb b/spec/migrations/move_container_registry_enabled_to_project_features2_spec.rb index c7b07f3ef37..11d43a36bc9 100644 --- a/spec/migrations/move_container_registry_enabled_to_project_features_spec.rb +++ b/spec/migrations/move_container_registry_enabled_to_project_features2_spec.rb @@ -1,9 +1,9 @@ # frozen_string_literal: true require 'spec_helper' -require Rails.root.join('db', 'post_migrate', '20210226120851_move_container_registry_enabled_to_project_features.rb') +require Rails.root.join('db', 'post_migrate', '20210401131948_move_container_registry_enabled_to_project_features2.rb') -RSpec.describe MoveContainerRegistryEnabledToProjectFeatures, :migration do +RSpec.describe MoveContainerRegistryEnabledToProjectFeatures2, :migration do let(:namespace) { table(:namespaces).create!(name: 'gitlab', path: 'gitlab-org') } let!(:projects) do @@ -30,6 +30,10 @@ RSpec.describe MoveContainerRegistryEnabledToProjectFeatures, :migration do it 'schedules jobs for ranges of projects' do migrate! + # Since track_jobs is true, each job should have an entry in the background_migration_jobs + # table. + expect(table(:background_migration_jobs).count).to eq(2) + expect(described_class::MIGRATION) .to be_scheduled_delayed_migration(2.minutes, projects[0].id, projects[2].id) diff --git a/spec/requests/api/notes_spec.rb b/spec/requests/api/notes_spec.rb index baab72d106f..d4f8b841c96 100644 --- a/spec/requests/api/notes_spec.rb +++ b/spec/requests/api/notes_spec.rb @@ -251,7 +251,7 @@ RSpec.describe API::Notes do expect { subject }.not_to change { Note.where(system: false).count } end - it 'does however create a system note about the change' do + it 'does however create a system note about the change', :sidekiq_inline do expect { subject }.to change { Note.system.count }.by(1) end diff --git a/spec/serializers/diff_file_entity_spec.rb b/spec/serializers/diff_file_entity_spec.rb index 1b8456e5c49..b8c5ccb9e7b 100644 --- a/spec/serializers/diff_file_entity_spec.rb +++ b/spec/serializers/diff_file_entity_spec.rb @@ -49,6 +49,14 @@ RSpec.describe DiffFileEntity do expect(subject).to include(:load_collapsed_diff_url) end + + context 'when diff_view is unknown' do + let(:options) { { diff_view: :unknown } } + + it 'hides highlighted_diff_lines and parallel_diff_lines' do + is_expected.not_to include(:highlighted_diff_lines, :parallel_diff_lines) + end + end end describe '#parallel_diff_lines' do diff --git a/spec/services/draft_notes/publish_service_spec.rb b/spec/services/draft_notes/publish_service_spec.rb index f83e91b683f..f93622dc25a 100644 --- a/spec/services/draft_notes/publish_service_spec.rb +++ b/spec/services/draft_notes/publish_service_spec.rb @@ -229,7 +229,7 @@ RSpec.describe DraftNotes::PublishService do expect(DraftNote.count).to eq(2) end - context 'with quick actions' do + context 'with quick actions', :sidekiq_inline do it 'performs quick actions' do other_user = create(:user) project.add_developer(other_user) diff --git a/spec/services/merge_requests/handle_assignees_change_service_spec.rb b/spec/services/merge_requests/handle_assignees_change_service_spec.rb new file mode 100644 index 00000000000..cc595aab04b --- /dev/null +++ b/spec/services/merge_requests/handle_assignees_change_service_spec.rb @@ -0,0 +1,114 @@ +# frozen_string_literal: true + +require 'spec_helper' + +RSpec.describe MergeRequests::HandleAssigneesChangeService do + let_it_be(:project) { create(:project, :repository) } + let_it_be(:user) { create(:user) } + let_it_be(:assignee) { create(:user) } + let_it_be(:merge_request) { create(:merge_request, author: user, source_project: project, assignees: [assignee]) } + let_it_be(:old_assignees) { create_list(:user, 3) } + + let(:options) { {} } + let(:service) { described_class.new(project, user) } + + before_all do + project.add_maintainer(user) + project.add_developer(assignee) + + old_assignees.each do |old_assignee| + project.add_developer(old_assignee) + end + end + + describe '#async_execute' do + def async_execute + service.async_execute(merge_request, old_assignees, options) + end + + it 'performs MergeRequests::HandleAssigneesChangeWorker asynchronously' do + expect(MergeRequests::HandleAssigneesChangeWorker) + .to receive(:perform_async) + .with( + merge_request.id, + user.id, + old_assignees.map(&:id), + options + ) + + async_execute + end + + context 'when async_handle_merge_request_assignees_change feature is disabled' do + before do + stub_feature_flags(async_handle_merge_request_assignees_change: false) + end + + it 'calls #execute' do + expect(service).to receive(:execute).with(merge_request, old_assignees, options) + + async_execute + end + end + end + + describe '#execute' do + def execute + service.execute(merge_request, old_assignees, options) + end + + it 'creates assignee note' do + execute + + note = merge_request.notes.last + + expect(note).not_to be_nil + expect(note.note).to include "assigned to #{assignee.to_reference} and unassigned #{old_assignees.map(&:to_reference).to_sentence}" + end + + it 'sends email notifications to old and new assignees', :mailer, :sidekiq_inline do + perform_enqueued_jobs do + execute + end + + should_email(assignee) + old_assignees.each do |old_assignee| + should_email(old_assignee) + end + end + + it 'creates pending todo for assignee' do + execute + + todo = assignee.todos.last + + expect(todo).to be_pending + end + + it 'tracks users assigned event' do + expect(Gitlab::UsageDataCounters::MergeRequestActivityUniqueCounter) + .to receive(:track_users_assigned_to_mr).once.with(users: [assignee]) + + execute + end + + it 'tracks assignees changed event' do + expect(Gitlab::UsageDataCounters::MergeRequestActivityUniqueCounter) + .to receive(:track_assignees_changed_action).once.with(user: user) + + execute + end + + context 'when execute_hooks option is set to true' do + let(:options) { { execute_hooks: true } } + + it 'execute hooks and services' do + expect(merge_request.project).to receive(:execute_hooks).with(anything, :merge_request_hooks) + expect(merge_request.project).to receive(:execute_services).with(anything, :merge_request_hooks) + expect(service).to receive(:enqueue_jira_connect_messages_for).with(merge_request) + + execute + end + end + end +end diff --git a/spec/services/merge_requests/update_assignees_service_spec.rb b/spec/services/merge_requests/update_assignees_service_spec.rb index aa6aad854a6..de03aab5418 100644 --- a/spec/services/merge_requests/update_assignees_service_spec.rb +++ b/spec/services/merge_requests/update_assignees_service_spec.rb @@ -37,9 +37,11 @@ RSpec.describe MergeRequests::UpdateAssigneesService do context 'when the parameters are valid' do it 'updates the MR, and queues the more expensive work for later' do - expect(MergeRequests::AssigneesChangeWorker) - .to receive(:perform_async) - .with(merge_request.id, user.id, [user3.id]) + expect_next(MergeRequests::HandleAssigneesChangeService, project, user) do |service| + expect(service) + .to receive(:async_execute) + .with(merge_request, [user3], execute_hooks: true) + end expect { update_merge_request } .to change(merge_request, :assignees).to([user2]) @@ -54,9 +56,11 @@ RSpec.describe MergeRequests::UpdateAssigneesService do end it 'is more efficient than using the full update-service' do - allow(MergeRequests::AssigneesChangeWorker) - .to receive(:perform_async) - .with(merge_request.id, user.id, [user3.id]) + allow_next(MergeRequests::HandleAssigneesChangeService, project, user) do |service| + expect(service) + .to receive(:async_execute) + .with(merge_request, [user3], execute_hooks: true) + end other_mr = create(:merge_request, :simple, :unique_branches, title: merge_request.title, @@ -72,17 +76,4 @@ RSpec.describe MergeRequests::UpdateAssigneesService do end end end - - describe '#handle_assignee_changes' do - subject { service.handle_assignee_changes(merge_request, [user2]) } - - it 'calls UpdateService#handle_assignee_changes and executes hooks' do - expect(service).to receive(:handle_assignees_change).with(merge_request, [user2]) - expect(merge_request.project).to receive(:execute_hooks).with(anything, :merge_request_hooks) - expect(merge_request.project).to receive(:execute_services).with(anything, :merge_request_hooks) - expect(service).to receive(:enqueue_jira_connect_messages_for).with(merge_request) - - subject - end - end end diff --git a/spec/services/merge_requests/update_service_spec.rb b/spec/services/merge_requests/update_service_spec.rb index 579d274d910..24b7c3b933b 100644 --- a/spec/services/merge_requests/update_service_spec.rb +++ b/spec/services/merge_requests/update_service_spec.rb @@ -205,30 +205,6 @@ RSpec.describe MergeRequests::UpdateService, :mailer do MergeRequests::UpdateService.new(project, user, opts).execute(merge_request) end - context 'assignees' do - context 'when assignees changed' do - it 'tracks assignees changed event' do - expect(Gitlab::UsageDataCounters::MergeRequestActivityUniqueCounter) - .to receive(:track_assignees_changed_action).once.with(user: user) - - opts[:assignees] = [user2] - - MergeRequests::UpdateService.new(project, user, opts).execute(merge_request) - end - end - - context 'when assignees did not change' do - it 'does not track assignees changed event' do - expect(Gitlab::UsageDataCounters::MergeRequestActivityUniqueCounter) - .not_to receive(:track_assignees_changed_action) - - opts[:assignees] = merge_request.assignees - - MergeRequests::UpdateService.new(project, user, opts).execute(merge_request) - end - end - end - context 'reviewers' do context 'when reviewers changed' do it 'tracks reviewers changed event' do @@ -326,21 +302,6 @@ RSpec.describe MergeRequests::UpdateService, :mailer do ) end - it 'sends email to user2 about assign of new merge request and email to user3 about merge request unassignment', :sidekiq_might_not_need_inline do - deliveries = ActionMailer::Base.deliveries - email = deliveries.last - recipients = deliveries.last(2).flat_map(&:to) - expect(recipients).to include(user2.email, user3.email) - expect(email.subject).to include(merge_request.title) - end - - it 'creates system note about merge_request reassign' do - note = find_note('assigned to') - - expect(note).not_to be_nil - expect(note.note).to include "assigned to #{user.to_reference} and unassigned #{user3.to_reference}" - end - context 'with reviewers' do let(:opts) { { reviewer_ids: [user2.id] } } @@ -664,20 +625,6 @@ RSpec.describe MergeRequests::UpdateService, :mailer do it 'marks previous assignee pending todos as done' do expect(pending_todo.reload).to be_done end - - it 'creates a pending todo for new assignee' do - attributes = { - project: project, - author: user, - user: user2, - target_id: merge_request.id, - target_type: merge_request.class.name, - action: Todo::ASSIGNED, - state: :pending - } - - expect(Todo.where(attributes).count).to eq 1 - end end context 'when reviewers gets changed' do @@ -999,6 +946,8 @@ RSpec.describe MergeRequests::UpdateService, :mailer do it 'does not update assignee when assignee_id is invalid' do merge_request.update!(assignee_ids: [user.id]) + expect(MergeRequests::HandleAssigneesChangeService).not_to receive(:new) + update_merge_request(assignee_ids: [-1]) expect(merge_request.reload.assignees).to eq([user]) @@ -1007,29 +956,35 @@ RSpec.describe MergeRequests::UpdateService, :mailer do it 'unassigns assignee when user id is 0' do merge_request.update!(assignee_ids: [user.id]) + expect_next_instance_of(MergeRequests::HandleAssigneesChangeService, project, user) do |service| + expect(service) + .to receive(:async_execute) + .with(merge_request, [user]) + end + update_merge_request(assignee_ids: [0]) expect(merge_request.assignee_ids).to be_empty end it 'saves assignee when user id is valid' do + expect_next_instance_of(MergeRequests::HandleAssigneesChangeService, project, user) do |service| + expect(service) + .to receive(:async_execute) + .with(merge_request, [user3]) + end + update_merge_request(assignee_ids: [user.id]) expect(merge_request.assignee_ids).to eq([user.id]) end - it 'updates the tracking when user ids are valid' do - expect(Gitlab::UsageDataCounters::MergeRequestActivityUniqueCounter) - .to receive(:track_users_assigned_to_mr) - .with(users: [user]) - - update_merge_request(assignee_ids: [user.id]) - end - it 'does not update assignee_id when user cannot read issue' do non_member = create(:user) original_assignees = merge_request.assignees + expect(MergeRequests::HandleAssigneesChangeService).not_to receive(:new) + update_merge_request(assignee_ids: [non_member.id]) expect(merge_request.reload.assignees).to eq(original_assignees) diff --git a/spec/workers/merge_requests/assignees_change_worker_spec.rb b/spec/workers/merge_requests/assignees_change_worker_spec.rb index ccb0e5885ac..33478daf8d3 100644 --- a/spec/workers/merge_requests/assignees_change_worker_spec.rb +++ b/spec/workers/merge_requests/assignees_change_worker_spec.rb @@ -19,7 +19,7 @@ RSpec.describe MergeRequests::AssigneesChangeWorker do describe '#perform' do context 'with a non-existing merge request' do it 'does nothing' do - expect(::MergeRequests::UpdateAssigneesService).not_to receive(:new) + expect(::MergeRequests::HandleAssigneesChangeService).not_to receive(:new) worker.perform(non_existing_record_id, user.id, user_ids) end @@ -27,7 +27,7 @@ RSpec.describe MergeRequests::AssigneesChangeWorker do context 'with a non-existing user' do it 'does nothing' do - expect(::MergeRequests::UpdateAssigneesService).not_to receive(:new) + expect(::MergeRequests::HandleAssigneesChangeService).not_to receive(:new) worker.perform(merge_request.id, non_existing_record_id, user_ids) end @@ -35,7 +35,7 @@ RSpec.describe MergeRequests::AssigneesChangeWorker do context 'when there are no changes' do it 'does nothing' do - expect(::MergeRequests::UpdateAssigneesService).not_to receive(:new) + expect(::MergeRequests::HandleAssigneesChangeService).not_to receive(:new) worker.perform(merge_request.id, user.id, merge_request.assignee_ids) end @@ -43,15 +43,15 @@ RSpec.describe MergeRequests::AssigneesChangeWorker do context 'when the old users cannot be found' do it 'does nothing' do - expect(::MergeRequests::UpdateAssigneesService).not_to receive(:new) + expect(::MergeRequests::HandleAssigneesChangeService).not_to receive(:new) worker.perform(merge_request.id, user.id, [non_existing_record_id]) end end it 'gets MergeRequests::UpdateAssigneesService to handle the changes' do - expect_next(::MergeRequests::UpdateAssigneesService) - .to receive(:handle_assignee_changes).with(merge_request, match_array(old_assignees)) + expect_next(::MergeRequests::HandleAssigneesChangeService) + .to receive(:execute).with(merge_request, match_array(old_assignees), execute_hooks: true) worker.perform(merge_request.id, user.id, user_ids) end diff --git a/spec/workers/merge_requests/handle_assignees_change_worker_spec.rb b/spec/workers/merge_requests/handle_assignees_change_worker_spec.rb new file mode 100644 index 00000000000..43f5196c92f --- /dev/null +++ b/spec/workers/merge_requests/handle_assignees_change_worker_spec.rb @@ -0,0 +1,62 @@ +# frozen_string_literal: true + +require 'spec_helper' + +RSpec.describe MergeRequests::HandleAssigneesChangeWorker do + include AfterNextHelpers + + let_it_be(:merge_request) { create(:merge_request) } + let_it_be(:user) { create(:user) } + let_it_be(:old_assignees) { create_list(:user, 3) } + + let(:user_ids) { old_assignees.map(&:id).to_a } + let(:options) { {} } + let(:worker) { described_class.new } + + it_behaves_like 'an idempotent worker' do + let(:job_args) { [merge_request.id, user.id, user_ids, options] } + end + + describe '#perform' do + it 'calls MergeRequests::HandleAssigneesChangeService#execute to handle the changes' do + expect_next(::MergeRequests::HandleAssigneesChangeService) + .to receive(:execute).with(merge_request, old_assignees, options) + + worker.perform(merge_request.id, user.id, user_ids, options) + end + + context 'when there are no changes' do + it 'still calls MergeRequests::HandleAssigneesChangeService#execute' do + expect_next(::MergeRequests::HandleAssigneesChangeService) + .to receive(:execute).with(merge_request, [], options) + + worker.perform(merge_request.id, user.id, merge_request.assignee_ids, options) + end + end + + context 'when the old assignees cannot be found' do + it 'still calls MergeRequests::HandleAssigneesChangeService#execute' do + expect_next(::MergeRequests::HandleAssigneesChangeService) + .to receive(:execute).with(merge_request, [], options) + + worker.perform(merge_request.id, user.id, [non_existing_record_id], options) + end + end + + context 'with a non-existing merge request' do + it 'does nothing' do + expect(::MergeRequests::HandleAssigneesChangeService).not_to receive(:new) + + worker.perform(non_existing_record_id, user.id, user_ids, options) + end + end + + context 'with a non-existing user' do + it 'does nothing' do + expect(::MergeRequests::HandleAssigneesChangeService).not_to receive(:new) + + worker.perform(merge_request.id, non_existing_record_id, user_ids, options) + end + end + end +end |