diff options
Diffstat (limited to 'spec/support/shared_examples/services')
11 files changed, 252 insertions, 102 deletions
diff --git a/spec/support/shared_examples/services/alert_management/alert_processing/alert_firing_shared_examples.rb b/spec/support/shared_examples/services/alert_management/alert_processing/alert_firing_shared_examples.rb index ca86cb082a7..6cae7d8e00f 100644 --- a/spec/support/shared_examples/services/alert_management/alert_processing/alert_firing_shared_examples.rb +++ b/spec/support/shared_examples/services/alert_management/alert_processing/alert_firing_shared_examples.rb @@ -23,7 +23,7 @@ RSpec.shared_examples 'creates an alert management alert or errors' do end context 'and fails to save' do - let(:errors) { double(messages: { hosts: ['hosts array is over 255 chars'] })} + let(:errors) { double(messages: { hosts: ['hosts array is over 255 chars'] }, '[]': [] )} before do allow(service).to receive(:alert).and_call_original @@ -35,9 +35,10 @@ RSpec.shared_examples 'creates an alert management alert or errors' do it 'writes a warning to the log' do expect(Gitlab::AppLogger).to receive(:warn).with( - message: "Unable to create AlertManagement::Alert from #{source}", + message: "Unable to create AlertManagement::Alert", project_id: project.id, - alert_errors: { hosts: ['hosts array is over 255 chars'] } + alert_errors: { hosts: ['hosts array is over 255 chars'] }, + alert_source: source ) subject @@ -45,6 +46,46 @@ RSpec.shared_examples 'creates an alert management alert or errors' do end end +RSpec.shared_examples 'handles race condition in alert creation' do + let(:other_alert) { create(:alert_management_alert, project: project) } + + context 'when another alert is saved at the same time' do + before do + allow_next_instance_of(::AlertManagement::Alert) do |alert| + allow(alert).to receive(:save) do + other_alert.update!(fingerprint: alert.fingerprint) + + raise ActiveRecord::RecordNotUnique + end + end + end + + it 'finds the other alert and increments the counter' do + subject + + expect(other_alert.reload.events).to eq(2) + end + end + + context 'when another alert is saved before the validation runes' do + before do + allow_next_instance_of(::AlertManagement::Alert) do |alert| + allow(alert).to receive(:save).and_wrap_original do |method, *args| + other_alert.update!(fingerprint: alert.fingerprint) + + method.call(*args) + end + end + end + + it 'finds the other alert and increments the counter' do + subject + + expect(other_alert.reload.events).to eq(2) + end + end +end + # This shared_example requires the following variables: # - last_alert_attributes, last created alert # - project, project that alert created diff --git a/spec/support/shared_examples/services/alert_management/alert_processing/alert_recovery_shared_examples.rb b/spec/support/shared_examples/services/alert_management/alert_processing/alert_recovery_shared_examples.rb index f8e096297d3..eb9f76d8626 100644 --- a/spec/support/shared_examples/services/alert_management/alert_processing/alert_recovery_shared_examples.rb +++ b/spec/support/shared_examples/services/alert_management/alert_processing/alert_recovery_shared_examples.rb @@ -4,8 +4,6 @@ # - `alert`, the alert to be resolved RSpec.shared_examples 'resolves an existing alert management alert' do it 'sets the end time and status' do - expect(Gitlab::AppLogger).not_to receive(:warn) - expect { subject } .to change { alert.reload.resolved? }.to(true) .and change { alert.ended_at.present? }.to(true) @@ -22,36 +20,6 @@ RSpec.shared_examples 'does not change the alert end time' do end end -# This shared_example requires the following variables: -# - `project`, expected project for an incoming alert -# - `service`, a service which includes AlertManagement::AlertProcessing -# - `alert` (optional), the alert which should fail to resolve. If not -# included, the log is expected to correspond to a new alert -RSpec.shared_examples 'writes a warning to the log for a failed alert status update' do - before do - allow(service).to receive(:alert).and_call_original - allow(service).to receive_message_chain(:alert, :resolve).and_return(false) - end - - specify do - expect(Gitlab::AppLogger).to receive(:warn).with( - message: 'Unable to update AlertManagement::Alert status to resolved', - project_id: project.id, - alert_id: alert ? alert.id : (last_alert_id + 1) - ) - - # Failure to resolve a recovery alert is not a critical failure - expect(subject).to be_success - end - - private - - def last_alert_id - AlertManagement::Alert.connection - .select_value("SELECT nextval('#{AlertManagement::Alert.sequence_name}')") - end -end - RSpec.shared_examples 'processes recovery alert' do context 'seen for the first time' do let(:alert) { AlertManagement::Alert.last } @@ -69,7 +37,6 @@ RSpec.shared_examples 'processes recovery alert' do it_behaves_like 'creates expected system notes for alert', :recovery_alert, :resolve_alert it_behaves_like 'sends alert notification emails if enabled' it_behaves_like 'closes related incident if enabled' - it_behaves_like 'writes a warning to the log for a failed alert status update' it_behaves_like 'does not create an alert management alert' it_behaves_like 'does not process incident issues' @@ -83,7 +50,6 @@ RSpec.shared_examples 'processes recovery alert' do it_behaves_like 'creates expected system notes for alert', :recovery_alert, :resolve_alert it_behaves_like 'sends alert notification emails if enabled' it_behaves_like 'closes related incident if enabled' - it_behaves_like 'writes a warning to the log for a failed alert status update' it_behaves_like 'does not create an alert management alert' it_behaves_like 'does not process incident issues' @@ -97,7 +63,6 @@ RSpec.shared_examples 'processes recovery alert' do it_behaves_like 'creates expected system notes for alert', :recovery_alert, :resolve_alert it_behaves_like 'sends alert notification emails if enabled' it_behaves_like 'closes related incident if enabled' - it_behaves_like 'writes a warning to the log for a failed alert status update' it_behaves_like 'does not create an alert management alert' it_behaves_like 'does not process incident issues' diff --git a/spec/support/shared_examples/services/alert_management/alert_processing/incident_creation_shared_examples.rb b/spec/support/shared_examples/services/alert_management/alert_processing/incident_creation_shared_examples.rb index 98834f01ce2..6becc3dc071 100644 --- a/spec/support/shared_examples/services/alert_management/alert_processing/incident_creation_shared_examples.rb +++ b/spec/support/shared_examples/services/alert_management/alert_processing/incident_creation_shared_examples.rb @@ -1,6 +1,6 @@ # frozen_string_literal: true -# Expects usage of 'incident settings enabled' context. +# Expects usage of 'incident management settings enabled' context. # # This shared_example includes the following option: # - with_issue: includes a test for when the defined `alert` has an associated issue @@ -8,7 +8,7 @@ # This shared_example requires the following variables: # - `alert`, required if :with_issue is true RSpec.shared_examples 'processes incident issues if enabled' do |with_issue: false| - include_examples 'processes incident issues', with_issue + include_examples 'processes incident issues', with_issue: with_issue context 'with incident setting disabled' do let(:create_issue) { false } diff --git a/spec/support/shared_examples/services/alert_management/alert_processing/incident_resolution_shared_examples.rb b/spec/support/shared_examples/services/alert_management/alert_processing/incident_resolution_shared_examples.rb index 3add5485fca..1973577d742 100644 --- a/spec/support/shared_examples/services/alert_management/alert_processing/incident_resolution_shared_examples.rb +++ b/spec/support/shared_examples/services/alert_management/alert_processing/incident_resolution_shared_examples.rb @@ -1,6 +1,6 @@ # frozen_string_literal: true -# Expects usage of 'incident settings enabled' context. +# Expects usage of 'incident management settings enabled' context. # # This shared_example requires the following variables: # - `alert`, alert for which related incidents should be closed diff --git a/spec/support/shared_examples/services/alert_management/alert_processing/notifications_shared_examples.rb b/spec/support/shared_examples/services/alert_management/alert_processing/notifications_shared_examples.rb index 5f30b58176b..92e7dee7533 100644 --- a/spec/support/shared_examples/services/alert_management/alert_processing/notifications_shared_examples.rb +++ b/spec/support/shared_examples/services/alert_management/alert_processing/notifications_shared_examples.rb @@ -1,11 +1,11 @@ # frozen_string_literal: true -# Expects usage of 'incident settings enabled' context. +# Expects usage of 'incident management settings enabled' context. # # This shared_example includes the following option: # - count: number of notifications expected to be sent RSpec.shared_examples 'sends alert notification emails if enabled' do |count: 1| - include_examples 'sends alert notification emails', count + include_examples 'sends alert notification emails', count: count context 'with email setting disabled' do let(:send_email) { false } diff --git a/spec/support/shared_examples/services/boards/lists_move_service_shared_examples.rb b/spec/support/shared_examples/services/boards/lists_move_service_shared_examples.rb index bf84b912610..97d0bae3552 100644 --- a/spec/support/shared_examples/services/boards/lists_move_service_shared_examples.rb +++ b/spec/support/shared_examples/services/boards/lists_move_service_shared_examples.rb @@ -1,95 +1,103 @@ # frozen_string_literal: true RSpec.shared_examples 'lists move service' do - let!(:planning) { create(:list, board: board, position: 0) } - let!(:development) { create(:list, board: board, position: 1) } - let!(:review) { create(:list, board: board, position: 2) } - let!(:staging) { create(:list, board: board, position: 3) } - let!(:closed) { create(:closed_list, board: board) } + shared_examples 'correct movement behavior' do + context 'when list type is set to label' do + it 'does not reorder lists when new position is nil' do + service = described_class.new(parent, user, position: nil) - context 'when list type is set to label' do - it 'keeps position of lists when new position is nil' do - service = described_class.new(parent, user, position: nil) + service.execute(planning) - service.execute(planning) + expect(ordered_lists).to eq([planning, development, review, staging]) + end - expect(current_list_positions).to eq [0, 1, 2, 3] - end - - it 'keeps position of lists when new position is equal to old position' do - service = described_class.new(parent, user, position: planning.position) + it 'does not reorder lists when new position is equal to old position' do + service = described_class.new(parent, user, position: planning.position) - service.execute(planning) + service.execute(planning) - expect(current_list_positions).to eq [0, 1, 2, 3] - end + expect(ordered_lists).to eq([planning, development, review, staging]) + end - it 'keeps position of lists when new position is negative' do - service = described_class.new(parent, user, position: -1) + it 'does not reorder lists when new position is negative' do + service = described_class.new(parent, user, position: -1) - service.execute(planning) + service.execute(planning) - expect(current_list_positions).to eq [0, 1, 2, 3] - end + expect(ordered_lists).to eq([planning, development, review, staging]) + end - it 'keeps position of lists when new position is equal to number of labels lists' do - service = described_class.new(parent, user, position: board.lists.label.size) + it 'does not reorder lists when new position is bigger then last position' do + service = described_class.new(parent, user, position: ordered_lists.last.position + 1) - service.execute(planning) + service.execute(planning) - expect(current_list_positions).to eq [0, 1, 2, 3] - end + expect(ordered_lists).to eq([planning, development, review, staging]) + end - it 'keeps position of lists when new position is greater than number of labels lists' do - service = described_class.new(parent, user, position: board.lists.label.size + 1) + it 'moves the list to the first position when new position is equal to first position' do + service = described_class.new(parent, user, position: 0) - service.execute(planning) + service.execute(staging) - expect(current_list_positions).to eq [0, 1, 2, 3] - end + expect(ordered_lists).to eq([staging, planning, development, review]) + end - it 'increments position of intermediate lists when new position is equal to first position' do - service = described_class.new(parent, user, position: 0) + it 'moves the list to the last position when new position is equal to last position' do + service = described_class.new(parent, user, position: board.lists.label.last.position) - service.execute(staging) + service.execute(planning) - expect(current_list_positions).to eq [1, 2, 3, 0] - end + expect(ordered_lists).to eq([development, review, staging, planning]) + end - it 'decrements position of intermediate lists when new position is equal to last position' do - service = described_class.new(parent, user, position: board.lists.label.last.position) + it 'moves the list to the correct position when new position is greater than old position (third list)' do + service = described_class.new(parent, user, position: review.position) - service.execute(planning) + service.execute(planning) - expect(current_list_positions).to eq [3, 0, 1, 2] - end + expect(ordered_lists).to eq([development, review, planning, staging]) + end - it 'decrements position of intermediate lists when new position is greater than old position' do - service = described_class.new(parent, user, position: 2) + it 'moves the list to the correct position when new position is lower than old position (second list)' do + service = described_class.new(parent, user, position: development.position) - service.execute(planning) + service.execute(staging) - expect(current_list_positions).to eq [2, 0, 1, 3] + expect(ordered_lists).to eq([planning, staging, development, review]) + end end - it 'increments position of intermediate lists when new position is lower than old position' do - service = described_class.new(parent, user, position: 1) + it 'keeps position of lists when list type is closed' do + service = described_class.new(parent, user, position: 2) - service.execute(staging) + service.execute(closed) - expect(current_list_positions).to eq [0, 2, 3, 1] + expect(ordered_lists).to eq([planning, development, review, staging]) end end - it 'keeps position of lists when list type is closed' do - service = described_class.new(parent, user, position: 2) + context 'with complete position sequence' do + let!(:planning) { create(:list, board: board, position: 0) } + let!(:development) { create(:list, board: board, position: 1) } + let!(:review) { create(:list, board: board, position: 2) } + let!(:staging) { create(:list, board: board, position: 3) } + let!(:closed) { create(:closed_list, board: board) } + + it_behaves_like 'correct movement behavior' + end - service.execute(closed) + context 'with corrupted position sequence' do + let!(:planning) { create(:list, board: board, position: 0) } + let!(:staging) { create(:list, board: board, position: 6) } + let!(:development) { create(:list, board: board, position: 1) } + let!(:review) { create(:list, board: board, position: 4) } + let!(:closed) { create(:closed_list, board: board) } - expect(current_list_positions).to eq [0, 1, 2, 3] + it_behaves_like 'correct movement behavior' end - def current_list_positions - [planning, development, review, staging].map { |list| list.reload.position } + def ordered_lists + board.lists.where.not(position: nil) end end diff --git a/spec/support/shared_examples/services/issuable_shared_examples.rb b/spec/support/shared_examples/services/issuable_shared_examples.rb index a50a386afe1..142d4ae8531 100644 --- a/spec/support/shared_examples/services/issuable_shared_examples.rb +++ b/spec/support/shared_examples/services/issuable_shared_examples.rb @@ -45,7 +45,7 @@ RSpec.shared_examples 'updating a single task' do end it 'creates system note about task status change' do - note1 = find_note('marked the task **Task 1** as completed') + note1 = find_note('marked the checklist item **Task 1** as completed') expect(note1).not_to be_nil @@ -61,7 +61,7 @@ RSpec.shared_examples 'updating a single task' do end it 'creates system note about task status change' do - note1 = find_note('marked the task **Task 2** as incomplete') + note1 = find_note('marked the checklist item **Task 2** as incomplete') expect(note1).not_to be_nil @@ -92,7 +92,7 @@ RSpec.shared_examples 'updating a single task' do end it 'creates system note about task status change' do - note1 = find_note('marked the task **Task 2** as incomplete') + note1 = find_note('marked the checklist item **Task 2** as incomplete') expect(note1).not_to be_nil diff --git a/spec/support/shared_examples/services/packages_shared_examples.rb b/spec/support/shared_examples/services/packages_shared_examples.rb index 6bc4f171d9c..704a4bbe0b8 100644 --- a/spec/support/shared_examples/services/packages_shared_examples.rb +++ b/spec/support/shared_examples/services/packages_shared_examples.rb @@ -81,6 +81,26 @@ RSpec.shared_examples 'returns packages' do |container_type, user_type| end end +RSpec.shared_examples 'returns package' do |container_type, user_type| + context "for #{user_type}" do + before do + send(container_type)&.send("add_#{user_type}", user) unless user_type == :no_type + end + + it 'returns success response' do + subject + + expect(response).to have_gitlab_http_status(:success) + end + + it 'returns a valid response schema' do + subject + + expect(response).to match_response_schema(single_package_schema) + end + end +end + RSpec.shared_examples 'returns packages with subgroups' do |container_type, user_type| context "with subgroups for #{user_type}" do before do diff --git a/spec/support/shared_examples/services/snowplow_tracking_shared_examples.rb b/spec/support/shared_examples/services/snowplow_tracking_shared_examples.rb new file mode 100644 index 00000000000..0687be6f429 --- /dev/null +++ b/spec/support/shared_examples/services/snowplow_tracking_shared_examples.rb @@ -0,0 +1,11 @@ +# frozen_string_literal: true + +shared_examples 'issue_edit snowplow tracking' do + let(:category) { Gitlab::UsageDataCounters::IssueActivityUniqueCounter::ISSUE_CATEGORY } + let(:action) { Gitlab::UsageDataCounters::IssueActivityUniqueCounter::ISSUE_ACTION } + let(:label) { Gitlab::UsageDataCounters::IssueActivityUniqueCounter::ISSUE_LABEL } + let(:namespace) { project.namespace } + let(:feature_flag_name) { :route_hll_to_snowplow_phase2 } + + it_behaves_like 'Snowplow event tracking' +end diff --git a/spec/support/shared_examples/services/timelogs/create_service_shared_examples.rb b/spec/support/shared_examples/services/timelogs/create_service_shared_examples.rb new file mode 100644 index 00000000000..53c42ec0e00 --- /dev/null +++ b/spec/support/shared_examples/services/timelogs/create_service_shared_examples.rb @@ -0,0 +1,89 @@ +# frozen_string_literal: true + +RSpec.shared_examples 'issuable supports timelog creation service' do + shared_examples 'success_response' do + it 'sucessfully saves the timelog' do + is_expected.to be_success + + timelog = subject.payload[:timelog] + + expect(timelog).to be_persisted + expect(timelog.time_spent).to eq(time_spent) + expect(timelog.spent_at).to eq('Fri, 08 Jul 2022 00:00:00.000000000 UTC +00:00') + expect(timelog.summary).to eq(summary) + expect(timelog.issuable).to eq(issuable) + end + end + + context 'when the user does not have permission' do + let(:user) { create(:user) } + + it 'returns an error' do + is_expected.to be_error + + expect(subject.message).to eq( + "#{issuable.base_class_name} doesn't exist or you don't have permission to add timelog to it.") + expect(subject.http_status).to eq(404) + end + end + + context 'when the user has permissions' do + let(:user) { author } + + before do + users_container.add_reporter(user) + end + + context 'when the timelog save fails' do + before do + allow_next_instance_of(Timelog) do |timelog| + allow(timelog).to receive(:save).and_return(false) + end + end + + it 'returns an error' do + is_expected.to be_error + expect(subject.message).to eq('Failed to save timelog') + end + end + + context 'when the creation completes sucessfully' do + it_behaves_like 'success_response' + end + end +end + +RSpec.shared_examples 'issuable does not support timelog creation service' do + shared_examples 'error_response' do + it 'returns an error' do + is_expected.to be_error + + issuable_type = if issuable.nil? + 'Issuable' + else + issuable.base_class_name + end + + expect(subject.message).to eq( + "#{issuable_type} doesn't exist or you don't have permission to add timelog to it." + ) + expect(subject.http_status).to eq(404) + end + end + + context 'when the user does not have permission' do + let(:user) { create(:user) } + + it_behaves_like 'error_response' + end + + context 'when the user has permissions' do + let(:user) { author } + + before do + users_container.add_reporter(user) + end + + it_behaves_like 'error_response' + end +end diff --git a/spec/support/shared_examples/services/work_items/create_task_shared_examples.rb b/spec/support/shared_examples/services/work_items/create_task_shared_examples.rb new file mode 100644 index 00000000000..7771e7f0e21 --- /dev/null +++ b/spec/support/shared_examples/services/work_items/create_task_shared_examples.rb @@ -0,0 +1,16 @@ +# frozen_string_literal: true + +RSpec.shared_examples 'title with extra spaces' do + context 'when title has extra spaces' do + before do + params[:title] = " Awesome work item " + end + + it 'removes extra leading and trailing whitespaces from title' do + subject + + created_work_item = WorkItem.last + expect(created_work_item.title).to eq('Awesome work item') + end + end +end |