diff options
Diffstat (limited to 'spec/services/incident_management')
5 files changed, 170 insertions, 374 deletions
diff --git a/spec/services/incident_management/create_incident_label_service_spec.rb b/spec/services/incident_management/create_incident_label_service_spec.rb index 2f11bcf397e..18a7c019497 100644 --- a/spec/services/incident_management/create_incident_label_service_spec.rb +++ b/spec/services/incident_management/create_incident_label_service_spec.rb @@ -52,7 +52,15 @@ RSpec.describe IncidentManagement::CreateIncidentLabelService do end context 'without label' do - it_behaves_like 'new label' + context 'when user has permissions to create labels' do + it_behaves_like 'new label' + end + + context 'when user has no permissions to create labels' do + let_it_be(:user) { create(:user) } + + it_behaves_like 'new label' + end 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 deleted file mode 100644 index dab9a149458..00000000000 --- a/spec/services/incident_management/create_issue_service_spec.rb +++ /dev/null @@ -1,239 +0,0 @@ -# frozen_string_literal: true - -require 'spec_helper' - -RSpec.describe IncidentManagement::CreateIssueService do - let(:project) { create(:project, :repository, :private) } - let_it_be(:user) { User.alert_bot } - let(:service) { described_class.new(project, alert_payload) } - let(:alert_starts_at) { Time.current } - 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] } - - 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 - it_behaves_like 'create alert issue sets issue labels' - 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.current) - { - '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) - summary_separator = "\n\n---\n\n" - - text.scan(summary_separator).size - end -end diff --git a/spec/services/incident_management/incidents/create_service_spec.rb b/spec/services/incident_management/incidents/create_service_spec.rb new file mode 100644 index 00000000000..404c428cd94 --- /dev/null +++ b/spec/services/incident_management/incidents/create_service_spec.rb @@ -0,0 +1,69 @@ +# frozen_string_literal: true + +require 'spec_helper' + +RSpec.describe IncidentManagement::Incidents::CreateService do + let_it_be(:project) { create(:project) } + let_it_be(:user) { User.alert_bot } + let(:description) { 'Incident description' } + + describe '#execute' do + subject(:create_incident) { described_class.new(project, user, title: title, description: description).execute } + + context 'when incident has title and description' do + let(:title) { 'Incident title' } + let(:new_issue) { Issue.last! } + let(:label_title) { IncidentManagement::CreateIncidentLabelService::LABEL_PROPERTIES[:title] } + + it 'responds with success' do + expect(create_incident).to be_success + end + + it 'creates an incident issue' do + expect { create_incident }.to change(Issue, :count).by(1) + end + + it 'created issue has correct attributes' do + create_incident + aggregate_failures do + expect(new_issue.title).to eq(title) + expect(new_issue.description).to eq(description) + expect(new_issue.author).to eq(user) + expect(new_issue.issue_type).to eq('incident') + expect(new_issue.labels.map(&:title)).to eq([label_title]) + end + end + + context 'when incident label does not exists' do + it 'creates incident label' do + expect { create_incident }.to change { project.labels.where(title: label_title).count }.by(1) + end + end + + context 'when incident label already exists' do + let!(:label) { create(:label, project: project, title: label_title) } + + it 'does not create new labels' do + expect { create_incident }.not_to change(Label, :count) + end + end + end + + context 'when incident has no title' do + let(:title) { '' } + + it 'does not create an issue' do + expect { create_incident }.not_to change(Issue, :count) + end + + it 'responds with errors' do + expect(create_incident).to be_error + expect(create_incident.message).to eq("Title can't be blank") + end + + it 'result payload contains an Issue object' do + expect(create_incident.payload[:issue]).to be_kind_of(Issue) + end + end + end +end diff --git a/spec/services/incident_management/pager_duty/create_incident_issue_service_spec.rb b/spec/services/incident_management/pager_duty/create_incident_issue_service_spec.rb index cf43ed2411d..73ad0532e07 100644 --- a/spec/services/incident_management/pager_duty/create_incident_issue_service_spec.rb +++ b/spec/services/incident_management/pager_duty/create_incident_issue_service_spec.rb @@ -12,84 +12,63 @@ RSpec.describe IncidentManagement::PagerDuty::CreateIncidentIssueService do subject(:execute) { described_class.new(project, incident_payload).execute } describe '#execute' do - context 'when pagerduty_webhook feature enabled' do - before do - stub_feature_flags(pagerduty_webhook: project) - end + context 'when PagerDuty webhook setting is active' do + let_it_be(:incident_management_setting) { create(:project_incident_management_setting, project: project, pagerduty_active: true) } - context 'when PagerDuty webhook setting is active' do - let_it_be(:incident_management_setting) { create(:project_incident_management_setting, project: project, pagerduty_active: true) } - - context 'when issue can be created' do - it 'creates a new issue' do - expect { execute }.to change(Issue, :count).by(1) - end - - it 'responds with success' do - response = execute - - expect(response).to be_success - expect(response.payload[:issue]).to be_kind_of(Issue) - end - - it 'the issue author is Alert bot' do - expect(execute.payload[:issue].author).to eq(User.alert_bot) - end - - it 'issue has a correct title' do - expect(execute.payload[:issue].title).to eq(incident_payload['title']) - end - - it 'issue has a correct description' do - markdown_line_break = ' ' - - expect(execute.payload[:issue].description).to eq( - <<~MARKDOWN.chomp - **Incident:** [My new incident](https://webdemo.pagerduty.com/incidents/PRORDTY)#{markdown_line_break} - **Incident number:** 33#{markdown_line_break} - **Urgency:** high#{markdown_line_break} - **Status:** triggered#{markdown_line_break} - **Incident key:** #{markdown_line_break} - **Created at:** 26 September 2017, 3:14PM (UTC)#{markdown_line_break} - **Assignees:** [Laura Haley](https://webdemo.pagerduty.com/users/P553OPV)#{markdown_line_break} - **Impacted services:** [Production XDB Cluster](https://webdemo.pagerduty.com/services/PN49J75) - MARKDOWN - ) - end + context 'when issue can be created' do + it 'creates a new issue' do + expect { execute }.to change(Issue, :count).by(1) end - context 'when the payload does not contain a title' do - let(:incident_payload) { {} } + it 'responds with success' do + response = execute + + expect(response).to be_success + expect(response.payload[:issue]).to be_kind_of(Issue) + end - it 'does not create a GitLab issue' do - expect { execute }.not_to change(Issue, :count) - end + it 'the issue author is Alert bot' do + expect(execute.payload[:issue].author).to eq(User.alert_bot) + end - it 'responds with error' do - expect(execute).to be_error - expect(execute.message).to eq("Title can't be blank") - end + it 'issue has a correct title' do + expect(execute.payload[:issue].title).to eq(incident_payload['title']) + end + + it 'issue has a correct description' do + markdown_line_break = ' ' + + expect(execute.payload[:issue].description).to eq( + <<~MARKDOWN.chomp + **Incident:** [My new incident](https://webdemo.pagerduty.com/incidents/PRORDTY)#{markdown_line_break} + **Incident number:** 33#{markdown_line_break} + **Urgency:** high#{markdown_line_break} + **Status:** triggered#{markdown_line_break} + **Incident key:** #{markdown_line_break} + **Created at:** 26 September 2017, 3:14PM (UTC)#{markdown_line_break} + **Assignees:** [Laura Haley](https://webdemo.pagerduty.com/users/P553OPV)#{markdown_line_break} + **Impacted services:** [Production XDB Cluster](https://webdemo.pagerduty.com/services/PN49J75) + MARKDOWN + ) end end - context 'when PagerDuty webhook setting is not active' do - let_it_be(:incident_management_setting) { create(:project_incident_management_setting, project: project, pagerduty_active: false) } + context 'when the payload does not contain a title' do + let(:incident_payload) { {} } it 'does not create a GitLab issue' do expect { execute }.not_to change(Issue, :count) end - it 'responds with forbidden' do + it 'responds with error' do expect(execute).to be_error - expect(execute.http_status).to eq(:forbidden) + expect(execute.message).to eq("Title can't be blank") end end end - context 'when pagerduty_webhook feature disabled' do - before do - stub_feature_flags(pagerduty_webhook: false) - end + context 'when PagerDuty webhook setting is not active' do + let_it_be(:incident_management_setting) { create(:project_incident_management_setting, project: project, pagerduty_active: false) } it 'does not create a GitLab issue' do expect { execute }.not_to change(Issue, :count) diff --git a/spec/services/incident_management/pager_duty/process_webhook_service_spec.rb b/spec/services/incident_management/pager_duty/process_webhook_service_spec.rb index 11ce8388427..4c8aebe5fe2 100644 --- a/spec/services/incident_management/pager_duty/process_webhook_service_spec.rb +++ b/spec/services/incident_management/pager_duty/process_webhook_service_spec.rb @@ -19,92 +19,68 @@ RSpec.describe IncidentManagement::PagerDuty::ProcessWebhookService do subject(:execute) { described_class.new(project, nil, webhook_payload).execute(token) } - context 'when pagerduty_webhook feature is enabled' do - before do - stub_feature_flags(pagerduty_webhook: project) - end - - context 'when PagerDuty webhook setting is active' do - let_it_be(:incident_management_setting) { create(:project_incident_management_setting, project: project, pagerduty_active: true) } - - context 'when token is valid' do - let(:token) { incident_management_setting.pagerduty_token } + context 'when PagerDuty webhook setting is active' do + let_it_be(:incident_management_setting) { create(:project_incident_management_setting, project: project, pagerduty_active: true) } - context 'when webhook payload has acceptable size' do - it 'responds with Accepted' do - result = execute + context 'when token is valid' do + let(:token) { incident_management_setting.pagerduty_token } - expect(result).to be_success - expect(result.http_status).to eq(:accepted) - end - - it 'processes issues' do - incident_payload = ::PagerDuty::WebhookPayloadParser.call(webhook_payload).first['incident'] - - expect(::IncidentManagement::PagerDuty::ProcessIncidentWorker) - .to receive(:perform_async) - .with(project.id, incident_payload) - .once + context 'when webhook payload has acceptable size' do + it 'responds with Accepted' do + result = execute - execute - end + expect(result).to be_success + expect(result.http_status).to eq(:accepted) end - context 'when webhook payload is too big' do - let(:deep_size) { instance_double(Gitlab::Utils::DeepSize, valid?: false) } - - before do - allow(Gitlab::Utils::DeepSize) - .to receive(:new) - .with(webhook_payload, max_size: described_class::PAGER_DUTY_PAYLOAD_SIZE_LIMIT) - .and_return(deep_size) - end + it 'processes issues' do + incident_payload = ::PagerDuty::WebhookPayloadParser.call(webhook_payload).first['incident'] - it 'responds with Bad Request' do - result = execute + expect(::IncidentManagement::PagerDuty::ProcessIncidentWorker) + .to receive(:perform_async) + .with(project.id, incident_payload) + .once - expect(result).to be_error - expect(result.http_status).to eq(:bad_request) - end - - it_behaves_like 'does not process incidents' + execute end + end - context 'when webhook payload is blank' do - let(:webhook_payload) { nil } + context 'when webhook payload is too big' do + let(:deep_size) { instance_double(Gitlab::Utils::DeepSize, valid?: false) } - it 'responds with Accepted' do - result = execute + before do + allow(Gitlab::Utils::DeepSize) + .to receive(:new) + .with(webhook_payload, max_size: described_class::PAGER_DUTY_PAYLOAD_SIZE_LIMIT) + .and_return(deep_size) + end - expect(result).to be_success - expect(result.http_status).to eq(:accepted) - end + it 'responds with Bad Request' do + result = execute - it_behaves_like 'does not process incidents' + expect(result).to be_error + expect(result.http_status).to eq(:bad_request) end + + it_behaves_like 'does not process incidents' end - context 'when token is invalid' do - let(:token) { 'invalid-token' } + context 'when webhook payload is blank' do + let(:webhook_payload) { nil } - it 'responds with Unauthorized' do + it 'responds with Accepted' do result = execute - expect(result).to be_error - expect(result.http_status).to eq(:unauthorized) + expect(result).to be_success + expect(result.http_status).to eq(:accepted) end it_behaves_like 'does not process incidents' end end - context 'when both tokens are nil' do - let_it_be(:incident_management_setting) { create(:project_incident_management_setting, project: project, pagerduty_active: false) } - let(:token) { nil } - - before do - incident_management_setting.update_column(:pagerduty_active, true) - end + context 'when token is invalid' do + let(:token) { 'invalid-token' } it 'responds with Unauthorized' do result = execute @@ -115,25 +91,28 @@ RSpec.describe IncidentManagement::PagerDuty::ProcessWebhookService do it_behaves_like 'does not process incidents' end + end - context 'when PagerDuty webhook setting is not active' do - let_it_be(:incident_management_setting) { create(:project_incident_management_setting, project: project, pagerduty_active: false) } + context 'when both tokens are nil' do + let_it_be(:incident_management_setting) { create(:project_incident_management_setting, project: project, pagerduty_active: false) } + let(:token) { nil } - it 'responds with Forbidden' do - result = execute + before do + incident_management_setting.update_column(:pagerduty_active, true) + end - expect(result).to be_error - expect(result.http_status).to eq(:forbidden) - end + it 'responds with Unauthorized' do + result = execute - it_behaves_like 'does not process incidents' + expect(result).to be_error + expect(result.http_status).to eq(:unauthorized) end + + it_behaves_like 'does not process incidents' end - context 'when pagerduty_webhook feature is disabled' do - before do - stub_feature_flags(pagerduty_webhook: false) - end + context 'when PagerDuty webhook setting is not active' do + let_it_be(:incident_management_setting) { create(:project_incident_management_setting, project: project, pagerduty_active: false) } it 'responds with Forbidden' do result = execute |