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>2020-02-11 18:08:44 +0300
committerGitLab Bot <gitlab-bot@gitlab.com>2020-02-11 18:08:44 +0300
commitbcc77054ee9aefd1e332e04a4189390fd5a3112e (patch)
treee6e1908c310e4733038794e932196cae0d66ba9a /spec
parent05b5c609cb8c260b10c2eb1b92b711dc82d32c3f (diff)
Add latest changes from gitlab-org/gitlab@master
Diffstat (limited to 'spec')
-rw-r--r--spec/factories/incident_management/project_incident_management_settings.rb10
-rw-r--r--spec/features/issues/issue_detail_spec.rb8
-rw-r--r--spec/features/projects/files/template_type_dropdown_spec.rb5
-rw-r--r--spec/lib/gitlab/graphql/connections/keyset/connection_spec.rb150
-rw-r--r--spec/models/container_expiration_policy_spec.rb4
-rw-r--r--spec/models/incident_management/project_incident_management_setting_spec.rb111
-rw-r--r--spec/services/incident_management/create_issue_service_spec.rb311
-rw-r--r--spec/workers/concerns/worker_context_spec.rb10
-rw-r--r--spec/workers/incident_management/process_alert_worker_spec.rb39
9 files changed, 586 insertions, 62 deletions
diff --git a/spec/factories/incident_management/project_incident_management_settings.rb b/spec/factories/incident_management/project_incident_management_settings.rb
new file mode 100644
index 00000000000..5b6a71d87d5
--- /dev/null
+++ b/spec/factories/incident_management/project_incident_management_settings.rb
@@ -0,0 +1,10 @@
+# frozen_string_literal: true
+
+FactoryBot.define do
+ factory :project_incident_management_setting, class: 'IncidentManagement::ProjectIncidentManagementSetting' do
+ project
+ create_issue { false }
+ issue_template_key { nil }
+ send_email { false }
+ end
+end
diff --git a/spec/features/issues/issue_detail_spec.rb b/spec/features/issues/issue_detail_spec.rb
index a1b53718577..0d24b02a64c 100644
--- a/spec/features/issues/issue_detail_spec.rb
+++ b/spec/features/issues/issue_detail_spec.rb
@@ -23,16 +23,18 @@ describe 'Issue Detail', :js do
context 'when issue description has xss snippet' do
before do
issue.update!(description: '![xss" onload=alert(1);//](a)')
+
sign_in(user)
visit project_issue_path(project, issue)
- wait_for_requests
end
it 'encodes the description to prevent xss issues' do
page.within('.issuable-details .detail-page-description') do
+ image = find('img.js-lazy-loaded')
+
expect(page).to have_selector('img', count: 1)
- expect(find('img')['onerror']).to be_nil
- expect(find('img')['src']).to end_with('/a')
+ expect(image['onerror']).to be_nil
+ expect(image['src']).to end_with('/a')
end
end
end
diff --git a/spec/features/projects/files/template_type_dropdown_spec.rb b/spec/features/projects/files/template_type_dropdown_spec.rb
index ba52a7e7deb..03b4b9b4517 100644
--- a/spec/features/projects/files/template_type_dropdown_spec.rb
+++ b/spec/features/projects/files/template_type_dropdown_spec.rb
@@ -75,6 +75,11 @@ describe 'Projects > Files > Template type dropdown selector', :js do
check_type_selector_toggle_text('.gitignore')
end
+ it 'sets the toggle text when selecting the template type' do
+ select_template_type('.gitignore')
+ check_type_selector_toggle_text('.gitignore')
+ end
+
it 'selects every template type correctly' do
try_selecting_all_types
end
diff --git a/spec/lib/gitlab/graphql/connections/keyset/connection_spec.rb b/spec/lib/gitlab/graphql/connections/keyset/connection_spec.rb
index f617e8b3ce7..c193ab2b50f 100644
--- a/spec/lib/gitlab/graphql/connections/keyset/connection_spec.rb
+++ b/spec/lib/gitlab/graphql/connections/keyset/connection_spec.rb
@@ -103,7 +103,75 @@ describe Gitlab::Graphql::Connections::Keyset::Connection do
end
end
- context 'when multiple orders are defined' do
+ shared_examples 'nodes are in ascending order' do
+ context 'when no cursor is passed' do
+ let(:arguments) { {} }
+
+ it 'returns projects in ascending order' do
+ expect(subject.sliced_nodes).to eq(ascending_nodes)
+ end
+ end
+
+ context 'when before cursor value is not NULL' do
+ let(:arguments) { { before: encoded_cursor(ascending_nodes[2]) } }
+
+ it 'returns all projects before the cursor' do
+ expect(subject.sliced_nodes).to eq(ascending_nodes.first(2))
+ end
+ end
+
+ context 'when after cursor value is not NULL' do
+ let(:arguments) { { after: encoded_cursor(ascending_nodes[1]) } }
+
+ it 'returns all projects after the cursor' do
+ expect(subject.sliced_nodes).to eq(ascending_nodes.last(3))
+ end
+ end
+
+ context 'when before and after cursor' do
+ let(:arguments) { { before: encoded_cursor(ascending_nodes.last), after: encoded_cursor(ascending_nodes.first) } }
+
+ it 'returns all projects after the cursor' do
+ expect(subject.sliced_nodes).to eq(ascending_nodes[1..3])
+ end
+ end
+ end
+
+ shared_examples 'nodes are in descending order' do
+ context 'when no cursor is passed' do
+ let(:arguments) { {} }
+
+ it 'only returns projects in descending order' do
+ expect(subject.sliced_nodes).to eq(descending_nodes)
+ end
+ end
+
+ context 'when before cursor value is not NULL' do
+ let(:arguments) { { before: encoded_cursor(descending_nodes[2]) } }
+
+ it 'returns all projects before the cursor' do
+ expect(subject.sliced_nodes).to eq(descending_nodes.first(2))
+ end
+ end
+
+ context 'when after cursor value is not NULL' do
+ let(:arguments) { { after: encoded_cursor(descending_nodes[1]) } }
+
+ it 'returns all projects after the cursor' do
+ expect(subject.sliced_nodes).to eq(descending_nodes.last(3))
+ end
+ end
+
+ context 'when before and after cursor' do
+ let(:arguments) { { before: encoded_cursor(descending_nodes.last), after: encoded_cursor(descending_nodes.first) } }
+
+ it 'returns all projects after the cursor' do
+ expect(subject.sliced_nodes).to eq(descending_nodes[1..3])
+ end
+ end
+ end
+
+ context 'when multiple orders with nil values are defined' do
let!(:project1) { create(:project, last_repository_check_at: 10.days.ago) } # Asc: project5 Desc: project3
let!(:project2) { create(:project, last_repository_check_at: nil) } # Asc: project1 Desc: project1
let!(:project3) { create(:project, last_repository_check_at: 5.days.ago) } # Asc: project3 Desc: project5
@@ -114,14 +182,9 @@ describe Gitlab::Graphql::Connections::Keyset::Connection do
let(:nodes) do
Project.order(Arel.sql('projects.last_repository_check_at IS NULL')).order(last_repository_check_at: :asc).order(id: :asc)
end
+ let(:ascending_nodes) { [project5, project1, project3, project2, project4] }
- context 'when no cursor is passed' do
- let(:arguments) { {} }
-
- it 'returns projects in ascending order' do
- expect(subject.sliced_nodes).to eq([project5, project1, project3, project2, project4])
- end
- end
+ it_behaves_like 'nodes are in ascending order'
context 'when before cursor value is NULL' do
let(:arguments) { { before: encoded_cursor(project4) } }
@@ -131,14 +194,6 @@ describe Gitlab::Graphql::Connections::Keyset::Connection do
end
end
- context 'when before cursor value is not NULL' do
- let(:arguments) { { before: encoded_cursor(project3) } }
-
- it 'returns all projects before the cursor' do
- expect(subject.sliced_nodes).to eq([project5, project1])
- end
- end
-
context 'when after cursor value is NULL' do
let(:arguments) { { after: encoded_cursor(project2) } }
@@ -146,36 +201,15 @@ describe Gitlab::Graphql::Connections::Keyset::Connection do
expect(subject.sliced_nodes).to eq([project4])
end
end
-
- context 'when after cursor value is not NULL' do
- let(:arguments) { { after: encoded_cursor(project1) } }
-
- it 'returns all projects after the cursor' do
- expect(subject.sliced_nodes).to eq([project3, project2, project4])
- end
- end
-
- context 'when before and after cursor' do
- let(:arguments) { { before: encoded_cursor(project4), after: encoded_cursor(project5) } }
-
- it 'returns all projects after the cursor' do
- expect(subject.sliced_nodes).to eq([project1, project3, project2])
- end
- end
end
context 'when descending' do
let(:nodes) do
Project.order(Arel.sql('projects.last_repository_check_at IS NULL')).order(last_repository_check_at: :desc).order(id: :asc)
end
+ let(:descending_nodes) { [project3, project1, project5, project2, project4] }
- context 'when no cursor is passed' do
- let(:arguments) { {} }
-
- it 'only returns projects in descending order' do
- expect(subject.sliced_nodes).to eq([project3, project1, project5, project2, project4])
- end
- end
+ it_behaves_like 'nodes are in descending order'
context 'when before cursor value is NULL' do
let(:arguments) { { before: encoded_cursor(project4) } }
@@ -185,14 +219,6 @@ describe Gitlab::Graphql::Connections::Keyset::Connection do
end
end
- context 'when before cursor value is not NULL' do
- let(:arguments) { { before: encoded_cursor(project5) } }
-
- it 'returns all projects before the cursor' do
- expect(subject.sliced_nodes).to eq([project3, project1])
- end
- end
-
context 'when after cursor value is NULL' do
let(:arguments) { { after: encoded_cursor(project2) } }
@@ -200,22 +226,32 @@ describe Gitlab::Graphql::Connections::Keyset::Connection do
expect(subject.sliced_nodes).to eq([project4])
end
end
+ end
+ end
- context 'when after cursor value is not NULL' do
- let(:arguments) { { after: encoded_cursor(project1) } }
+ context 'when ordering uses LOWER' do
+ let!(:project1) { create(:project, name: 'A') } # Asc: project1 Desc: project4
+ let!(:project2) { create(:project, name: 'c') } # Asc: project5 Desc: project2
+ let!(:project3) { create(:project, name: 'b') } # Asc: project3 Desc: project3
+ let!(:project4) { create(:project, name: 'd') } # Asc: project2 Desc: project5
+ let!(:project5) { create(:project, name: 'a') } # Asc: project4 Desc: project1
- it 'returns all projects after the cursor' do
- expect(subject.sliced_nodes).to eq([project5, project2, project4])
- end
+ context 'when ascending' do
+ let(:nodes) do
+ Project.order(Arel::Table.new(:projects)['name'].lower.asc).order(id: :asc)
end
+ let(:ascending_nodes) { [project1, project5, project3, project2, project4] }
- context 'when before and after cursor' do
- let(:arguments) { { before: encoded_cursor(project4), after: encoded_cursor(project3) } }
+ it_behaves_like 'nodes are in ascending order'
+ end
- it 'returns all projects after the cursor' do
- expect(subject.sliced_nodes).to eq([project1, project5, project2])
- end
+ context 'when descending' do
+ let(:nodes) do
+ Project.order(Arel::Table.new(:projects)['name'].lower.desc).order(id: :desc)
end
+ let(:descending_nodes) { [project4, project2, project3, project5, project1] }
+
+ it_behaves_like 'nodes are in descending order'
end
end
diff --git a/spec/models/container_expiration_policy_spec.rb b/spec/models/container_expiration_policy_spec.rb
index 1bce4c3b20a..c22362ed5d4 100644
--- a/spec/models/container_expiration_policy_spec.rb
+++ b/spec/models/container_expiration_policy_spec.rb
@@ -49,9 +49,9 @@ RSpec.describe ContainerExpirationPolicy, type: :model do
it 'preloads the associations' do
subject
- query = ActiveRecord::QueryRecorder.new { subject.each(&:project) }
+ query = ActiveRecord::QueryRecorder.new { subject.map(&:project).map(&:full_path) }
- expect(query.count).to eq(2)
+ expect(query.count).to eq(3)
end
end
diff --git a/spec/models/incident_management/project_incident_management_setting_spec.rb b/spec/models/incident_management/project_incident_management_setting_spec.rb
new file mode 100644
index 00000000000..ac3f97e2d89
--- /dev/null
+++ b/spec/models/incident_management/project_incident_management_setting_spec.rb
@@ -0,0 +1,111 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+describe IncidentManagement::ProjectIncidentManagementSetting do
+ let_it_be(:project) { create(:project, :repository, create_templates: :issue) }
+
+ describe 'Associations' do
+ it { is_expected.to belong_to(:project) }
+ end
+
+ describe 'Validations' do
+ describe 'validate issue_template_exists' do
+ subject { build(:project_incident_management_setting, project: project) }
+
+ context 'with create_issue enabled' do
+ before do
+ subject.create_issue = true
+ end
+
+ context 'with valid issue_template_key' do
+ before do
+ subject.issue_template_key = 'bug'
+ end
+
+ it { is_expected.to be_valid }
+ end
+
+ context 'with empty issue_template_key' do
+ before do
+ subject.issue_template_key = ''
+ end
+
+ it { is_expected.to be_valid }
+ end
+
+ context 'with nil issue_template_key' do
+ before do
+ subject.issue_template_key = nil
+ end
+
+ it { is_expected.to be_valid }
+ end
+
+ context 'with invalid issue_template_key' do
+ before do
+ subject.issue_template_key = 'unknown'
+ end
+
+ it { is_expected.to be_invalid }
+
+ it 'returns error' do
+ subject.valid?
+
+ expect(subject.errors[:issue_template_key]).to eq(['not found'])
+ end
+ end
+ end
+
+ context 'with create_issue disabled' do
+ before do
+ subject.create_issue = false
+ end
+
+ context 'with unknown issue_template_key' do
+ before do
+ subject.issue_template_key = 'unknown'
+ end
+
+ it { is_expected.to be_valid }
+ end
+ end
+ end
+ end
+
+ describe '#issue_template_content' do
+ subject { build(:project_incident_management_setting, project: project) }
+
+ shared_examples 'no content' do
+ it 'returns no content' do
+ expect(subject.issue_template_content).to be_nil
+ end
+ end
+
+ context 'with valid issue_template_key' do
+ before do
+ subject.issue_template_key = 'bug'
+ end
+
+ it 'returns issue content' do
+ expect(subject.issue_template_content).to eq('something valid')
+ end
+ end
+
+ context 'with unknown issue_template_key' do
+ before do
+ subject.issue_template_key = 'unknown'
+ end
+
+ it_behaves_like 'no content'
+ end
+
+ context 'without issue_template_key' do
+ before do
+ subject.issue_template_key = nil
+ end
+
+ it_behaves_like 'no content'
+ end
+ end
+end
diff --git a/spec/services/incident_management/create_issue_service_spec.rb b/spec/services/incident_management/create_issue_service_spec.rb
new file mode 100644
index 00000000000..e720aafb897
--- /dev/null
+++ b/spec/services/incident_management/create_issue_service_spec.rb
@@ -0,0 +1,311 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+describe IncidentManagement::CreateIssueService do
+ let(:project) { create(:project, :repository, :private) }
+ let(:user) { User.alert_bot }
+ let(:service) { described_class.new(project, alert_payload) }
+ let(:alert_starts_at) { Time.now }
+ let(:alert_title) { 'TITLE' }
+ let(:alert_annotations) { { title: alert_title } }
+
+ let(:alert_payload) do
+ build_alert_payload(
+ annotations: alert_annotations,
+ starts_at: alert_starts_at
+ )
+ end
+
+ let(:alert_presenter) do
+ Gitlab::Alerting::Alert.new(project: project, payload: alert_payload).present
+ end
+
+ let!(:setting) do
+ create(:project_incident_management_setting, project: project)
+ end
+
+ subject { service.execute }
+
+ context 'when create_issue enabled' do
+ let(:issue) { subject[:issue] }
+ let(:summary_separator) { "\n---\n\n" }
+
+ before do
+ setting.update!(create_issue: true)
+ end
+
+ context 'without issue_template_content' do
+ it 'creates an issue with alert summary only' do
+ expect(subject).to include(status: :success)
+
+ expect(issue.author).to eq(user)
+ expect(issue.title).to eq(alert_title)
+ expect(issue.description).to include(alert_presenter.issue_summary_markdown.strip)
+ expect(separator_count(issue.description)).to eq 0
+ end
+ end
+
+ context 'with erroneous issue service' do
+ let(:invalid_issue) do
+ build(:issue, project: project, title: nil).tap(&:valid?)
+ end
+
+ let(:issue_error) { invalid_issue.errors.full_messages.to_sentence }
+
+ it 'returns and logs the issue error' do
+ expect_next_instance_of(Issues::CreateService) do |issue_service|
+ expect(issue_service).to receive(:execute).and_return(invalid_issue)
+ end
+
+ expect(service)
+ .to receive(:log_error)
+ .with(error_message(issue_error))
+
+ expect(subject).to include(status: :error, message: issue_error)
+ end
+ end
+
+ shared_examples 'GFM template' do
+ context 'plain content' do
+ let(:template_content) { 'some content' }
+
+ it 'creates an issue appending issue template' do
+ expect(subject).to include(status: :success)
+
+ expect(issue.description).to include(alert_presenter.issue_summary_markdown)
+ expect(separator_count(issue.description)).to eq 1
+ expect(issue.description).to include(template_content)
+ end
+ end
+
+ context 'quick actions' do
+ let(:user) { create(:user) }
+ let(:plain_text) { 'some content' }
+
+ let(:template_content) do
+ <<~CONTENT
+ #{plain_text}
+ /due tomorrow
+ /assign @#{user.username}
+ CONTENT
+ end
+
+ before do
+ project.add_maintainer(user)
+ end
+
+ it 'creates an issue interpreting quick actions' do
+ expect(subject).to include(status: :success)
+
+ expect(issue.description).to include(plain_text)
+ expect(issue.due_date).to be_present
+ expect(issue.assignees).to eq([user])
+ end
+ end
+ end
+
+ context 'with gitlab_incident_markdown' do
+ let(:alert_annotations) do
+ { title: alert_title, gitlab_incident_markdown: template_content }
+ end
+
+ it_behaves_like 'GFM template'
+ end
+
+ context 'with issue_template_content' do
+ before do
+ create_issue_template('bug', template_content)
+ setting.update!(issue_template_key: 'bug')
+ end
+
+ it_behaves_like 'GFM template'
+
+ context 'and gitlab_incident_markdown' do
+ let(:template_content) { 'plain text'}
+ let(:alt_template) { 'alternate text' }
+ let(:alert_annotations) do
+ { title: alert_title, gitlab_incident_markdown: alt_template }
+ end
+
+ it 'includes both templates' do
+ expect(subject).to include(status: :success)
+
+ expect(issue.description).to include(alert_presenter.issue_summary_markdown)
+ expect(issue.description).to include(template_content)
+ expect(issue.description).to include(alt_template)
+ expect(separator_count(issue.description)).to eq 2
+ end
+ end
+
+ private
+
+ def create_issue_template(name, content)
+ project.repository.create_file(
+ project.creator,
+ ".gitlab/issue_templates/#{name}.md",
+ content,
+ message: 'message',
+ branch_name: 'master'
+ )
+ end
+ end
+
+ context 'with gitlab alert' do
+ let(:gitlab_alert) { create(:prometheus_alert, project: project) }
+
+ before do
+ alert_payload['labels'] = {
+ 'gitlab_alert_id' => gitlab_alert.prometheus_metric_id.to_s
+ }
+ end
+
+ it 'creates an issue' do
+ query_title = "#{gitlab_alert.title} #{gitlab_alert.computed_operator} #{gitlab_alert.threshold}"
+
+ expect(subject).to include(status: :success)
+
+ expect(issue.author).to eq(user)
+ expect(issue.title).to eq(alert_presenter.full_title)
+ expect(issue.title).to include(gitlab_alert.environment.name)
+ expect(issue.title).to include(query_title)
+ expect(issue.title).to include('for 5 minutes')
+ expect(issue.description).to include(alert_presenter.issue_summary_markdown.strip)
+ expect(separator_count(issue.description)).to eq 0
+ end
+ end
+
+ describe 'with invalid alert payload' do
+ shared_examples 'invalid alert' do
+ it 'does not create an issue' do
+ expect(service)
+ .to receive(:log_error)
+ .with(error_message('invalid alert'))
+
+ expect(subject).to eq(status: :error, message: 'invalid alert')
+ end
+ end
+
+ context 'without title' do
+ let(:alert_annotations) { {} }
+
+ it_behaves_like 'invalid alert'
+ end
+
+ context 'without startsAt' do
+ let(:alert_starts_at) { nil }
+
+ it_behaves_like 'invalid alert'
+ end
+ end
+
+ describe "label `incident`" do
+ let(:title) { 'incident' }
+ let(:color) { '#CC0033' }
+ let(:description) do
+ <<~DESCRIPTION.chomp
+ Denotes a disruption to IT services and \
+ the associated issues require immediate attention
+ DESCRIPTION
+ end
+
+ shared_examples 'existing label' do
+ it 'adds the existing label' do
+ expect { subject }.not_to change(Label, :count)
+
+ expect(issue.labels).to eq([label])
+ end
+ end
+
+ shared_examples 'new label' do
+ it 'adds newly created label' do
+ expect { subject }.to change(Label, :count).by(1)
+
+ label = project.reload.labels.last
+ expect(issue.labels).to eq([label])
+ expect(label.title).to eq(title)
+ expect(label.color).to eq(color)
+ expect(label.description).to eq(description)
+ end
+ end
+
+ context 'with predefined project label' do
+ it_behaves_like 'existing label' do
+ let!(:label) { create(:label, project: project, title: title) }
+ end
+ end
+
+ context 'with predefined group label' do
+ let(:project) { create(:project, group: group) }
+ let(:group) { create(:group) }
+
+ it_behaves_like 'existing label' do
+ let!(:label) { create(:group_label, group: group, title: title) }
+ end
+ end
+
+ context 'without label' do
+ it_behaves_like 'new label'
+ end
+
+ context 'with duplicate labels', issue: 'https://gitlab.com/gitlab-org/gitlab-foss/issues/65042' do
+ before do
+ # Replicate race condition to create duplicates
+ build(:label, project: project, title: title).save!(validate: false)
+ build(:label, project: project, title: title).save!(validate: false)
+ end
+
+ it 'create an issue without labels' do
+ # Verify we have duplicates
+ expect(project.labels.size).to eq(2)
+ expect(project.labels.map(&:title)).to all(eq(title))
+
+ message = <<~MESSAGE.chomp
+ Cannot create incident issue with labels ["#{title}"] for \
+ "#{project.full_name}": Labels is invalid.
+ Retrying without labels.
+ MESSAGE
+
+ expect(service)
+ .to receive(:log_info)
+ .with(message)
+
+ expect(subject).to include(status: :success)
+ expect(issue.labels).to be_empty
+ end
+ end
+ end
+ end
+
+ context 'when create_issue disabled' do
+ before do
+ setting.update!(create_issue: false)
+ end
+
+ it 'returns an error' do
+ expect(service)
+ .to receive(:log_error)
+ .with(error_message('setting disabled'))
+
+ expect(subject).to eq(status: :error, message: 'setting disabled')
+ end
+ end
+
+ private
+
+ def build_alert_payload(annotations: {}, starts_at: Time.now)
+ {
+ 'annotations' => annotations.stringify_keys
+ }.tap do |payload|
+ payload['startsAt'] = starts_at.rfc3339 if starts_at
+ end
+ end
+
+ def error_message(message)
+ %{Cannot create incident issue for "#{project.full_name}": #{message}}
+ end
+
+ def separator_count(text)
+ text.scan(summary_separator).size
+ end
+end
diff --git a/spec/workers/concerns/worker_context_spec.rb b/spec/workers/concerns/worker_context_spec.rb
index 97a88eecd73..4e8c81c57dc 100644
--- a/spec/workers/concerns/worker_context_spec.rb
+++ b/spec/workers/concerns/worker_context_spec.rb
@@ -106,5 +106,15 @@ describe WorkerContext do
expect(Labkit::Context.current.to_h).to include('meta.user' => 'jane-doe')
end
end
+
+ it 'yields the arguments to the block' do
+ a_user = build_stubbed(:user)
+ a_project = build_stubbed(:project)
+
+ worker.new.with_context(user: a_user, project: a_project) do |user:, project:|
+ expect(user).to eq(a_user)
+ expect(project).to eq(a_project)
+ end
+ end
end
end
diff --git a/spec/workers/incident_management/process_alert_worker_spec.rb b/spec/workers/incident_management/process_alert_worker_spec.rb
new file mode 100644
index 00000000000..9f40833dfd7
--- /dev/null
+++ b/spec/workers/incident_management/process_alert_worker_spec.rb
@@ -0,0 +1,39 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+describe IncidentManagement::ProcessAlertWorker do
+ let_it_be(:project) { create(:project) }
+
+ describe '#perform' do
+ let(:alert) { :alert }
+ let(:create_issue_service) { spy(:create_issue_service) }
+
+ subject { described_class.new.perform(project.id, alert) }
+
+ it 'calls create issue service' do
+ expect(Project).to receive(:find_by_id).and_call_original
+
+ expect(IncidentManagement::CreateIssueService)
+ .to receive(:new).with(project, :alert)
+ .and_return(create_issue_service)
+
+ expect(create_issue_service).to receive(:execute)
+
+ subject
+ end
+
+ context 'with invalid project' do
+ let(:invalid_project_id) { 0 }
+
+ subject { described_class.new.perform(invalid_project_id, alert) }
+
+ it 'does not create issues' do
+ expect(Project).to receive(:find_by_id).and_call_original
+ expect(IncidentManagement::CreateIssueService).not_to receive(:new)
+
+ subject
+ end
+ end
+ end
+end