Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
G
gitlab-ce
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
1
Merge Requests
1
Analytics
Analytics
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Commits
Issue Boards
Open sidebar
nexedi
gitlab-ce
Commits
df5a8953
Commit
df5a8953
authored
Apr 29, 2021
by
Sarah Yasonik
Committed by
Arturo Herrero
Apr 29, 2021
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Refactor alert processing specs for uniformity
parent
e8aec7f5
Changes
20
Show whitespace changes
Inline
Side-by-side
Showing
20 changed files
with
903 additions
and
775 deletions
+903
-775
ee/spec/services/alert_management/network_alert_service_spec.rb
...c/services/alert_management/network_alert_service_spec.rb
+47
-119
ee/spec/services/alert_management/process_prometheus_alert_service_spec.rb
...alert_management/process_prometheus_alert_service_spec.rb
+17
-10
ee/spec/services/projects/alerting/notify_service_spec.rb
ee/spec/services/projects/alerting/notify_service_spec.rb
+19
-4
ee/spec/services/projects/prometheus/alerts/notify_service_spec.rb
...ervices/projects/prometheus/alerts/notify_service_spec.rb
+4
-3
ee/spec/support/shared_examples/alert_notification_service_shared_examples.rb
...ed_examples/alert_notification_service_shared_examples.rb
+0
-19
ee/spec/support/shared_examples/incident_management/oncall_notifications_shared_examples.rb
...cident_management/oncall_notifications_shared_examples.rb
+0
-43
ee/spec/support/shared_examples/services/alert_management/alert_processing/alert_firing_shared_examples.rb
...nagement/alert_processing/alert_firing_shared_examples.rb
+35
-0
ee/spec/support/shared_examples/services/alert_management/alert_processing/alert_recovery_shared_examples.rb
...gement/alert_processing/alert_recovery_shared_examples.rb
+65
-0
ee/spec/support/shared_examples/services/alert_management/alert_processing/oncall_notifications_shared_examples.rb
.../alert_processing/oncall_notifications_shared_examples.rb
+36
-0
spec/services/alert_management/process_prometheus_alert_service_spec.rb
...alert_management/process_prometheus_alert_service_spec.rb
+30
-206
spec/services/projects/alerting/notify_service_spec.rb
spec/services/projects/alerting/notify_service_spec.rb
+63
-195
spec/services/projects/prometheus/alerts/notify_service_spec.rb
...ervices/projects/prometheus/alerts/notify_service_spec.rb
+40
-43
spec/support/shared_examples/alert_notification_service_shared_examples.rb
...ed_examples/alert_notification_service_shared_examples.rb
+0
-44
spec/support/shared_examples/services/alert_management/alert_processing/alert_firing_shared_examples.rb
...nagement/alert_processing/alert_firing_shared_examples.rb
+161
-0
spec/support/shared_examples/services/alert_management/alert_processing/alert_recovery_shared_examples.rb
...gement/alert_processing/alert_recovery_shared_examples.rb
+177
-0
spec/support/shared_examples/services/alert_management/alert_processing/incident_creation_shared_examples.rb
...ent/alert_processing/incident_creation_shared_examples.rb
+52
-0
spec/support/shared_examples/services/alert_management/alert_processing/incident_resolution_shared_examples.rb
...t/alert_processing/incident_resolution_shared_examples.rb
+44
-0
spec/support/shared_examples/services/alert_management/alert_processing/notifications_shared_examples.rb
...agement/alert_processing/notifications_shared_examples.rb
+34
-0
spec/support/shared_examples/services/alert_management/alert_processing/system_notes_shared_examples.rb
...nagement/alert_processing/system_notes_shared_examples.rb
+34
-0
spec/support/shared_examples/services/alert_management_shared_examples.rb
...red_examples/services/alert_management_shared_examples.rb
+45
-89
No files found.
ee/spec/services/alert_management/network_alert_service_spec.rb
View file @
df5a8953
...
@@ -6,37 +6,23 @@ RSpec.describe AlertManagement::NetworkAlertService do
...
@@ -6,37 +6,23 @@ RSpec.describe AlertManagement::NetworkAlertService do
let_it_be
(
:project
,
reload:
true
)
{
create
(
:project
,
:repository
)
}
let_it_be
(
:project
,
reload:
true
)
{
create
(
:project
,
:repository
)
}
let_it_be
(
:environment
)
{
create
(
:environment
,
project:
project
)
}
let_it_be
(
:environment
)
{
create
(
:environment
,
project:
project
)
}
describe
'#execute'
do
let
(
:payload_raw
)
{
build
(
:network_alert_payload
)
}
let
(
:service
)
{
described_class
.
new
(
project
,
payload
)
}
let
(
:payload
)
{
ActionController
::
Parameters
.
new
(
payload_raw
).
permit!
}
let
(
:tool
)
{
Gitlab
::
AlertManagement
::
Payload
::
MONITORING_TOOLS
[
:cilium
]
}
let
(
:starts_at
)
{
Time
.
current
.
change
(
usec:
0
)
}
let
(
:ended_at
)
{
nil
}
let
(
:fingerprint
)
{
'test'
}
let
(
:domain
)
{
'threat_monitoring'
}
let
(
:incident_management_setting
)
{
double
(
auto_close_incident?:
auto_close_enabled
)
}
let
(
:auto_close_enabled
)
{
true
}
let
(
:service
)
{
described_class
.
new
(
project
,
payload
)
}
before
do
describe
'#execute'
do
allow
(
service
).
to
receive
(
:incident_management_setting
).
and_return
(
include_context
'incident management settings enabled'
incident_management_setting
)
end
subject
(
:execute
)
{
service
.
execute
}
subject
(
:execute
)
{
service
.
execute
}
context
'with valid payload'
do
shared_examples
'never-before-seen network alert'
do
let
(
:payload_raw
)
{
build
(
:network_alert_payload
)
}
it_behaves_like
'creates an alert management alert or errors'
it_behaves_like
'creates expected system notes for alert'
,
:new_alert
let
(
:payload
)
{
ActionController
::
Parameters
.
new
(
payload_raw
).
permit!
}
it_behaves_like
'does not send alert notification emails'
it_behaves_like
'does not process incident issues'
let
(
:last_alert_attributes
)
do
it
'assigns the correct properties'
do
AlertManagement
::
Alert
.
last
.
attributes
.
except
(
'id'
,
'iid'
,
'created_at'
,
'updated_at'
)
.
with_indifferent_access
end
it
'create alert and assigns properties'
do
subject
subject
expect
(
last_alert_attributes
).
to
match
(
a_hash_including
({
expect
(
last_alert_attributes
).
to
match
(
a_hash_including
({
...
@@ -57,125 +43,67 @@ RSpec.describe AlertManagement::NetworkAlertService do
...
@@ -57,125 +43,67 @@ RSpec.describe AlertManagement::NetworkAlertService do
title:
'Cilium Alert'
title:
'Cilium Alert'
}))
}))
end
end
it
'creates a system note corresponding to alert creation'
do
expect
{
subject
}.
to
change
(
Note
,
:count
).
by
(
1
)
expect
(
Note
.
last
.
note
).
to
include
(
'Cilium'
)
end
context
'when alert exists'
do
let!
(
:alert
)
do
create
(
:alert_management_alert
,
project:
project
,
domain: :threat_monitoring
,
fingerprint:
'89269ffa3902af37f036a77bc9ea57cdee3a52c2'
)
end
end
it_behaves_like
'does not an create alert management alert'
shared_examples
'existing network alert'
do
it_behaves_like
'adds an alert management alert event'
it_behaves_like
'does not create a system note for alert'
it_behaves_like
'does not send alert notification emails'
it_behaves_like
'does not process incident issues'
end
end
context
'existing alert with same fingerprint'
do
context
'with valid payload'
do
let
(
:fingerprint_sha
)
{
'89269ffa3902af37f036a77bc9ea57cdee3a52c2'
}
let
(
:source
)
{
Gitlab
::
AlertManagement
::
Payload
::
MONITORING_TOOLS
[
:cilium
]
}
let!
(
:alert
)
do
let
(
:last_alert_attributes
)
do
create
(
:alert_management_alert
,
domain: :threat_monitoring
,
project:
project
,
fingerprint:
fingerprint_sha
)
AlertManagement
::
Alert
.
last
.
attributes
.
except
(
'id'
,
'iid'
,
'created_at'
,
'updated_at'
)
.
with_indifferent_access
end
end
it_behaves_like
'adds an alert management alert event'
it_behaves_like
'never-before-seen network alert'
context
'end time given'
do
let
(
:ended_at
)
{
Time
.
current
.
change
(
nsec:
0
)
}
context
'auto_close disabled'
do
let
(
:auto_close_enabled
)
{
false
}
it
'does not resolve the alert'
do
context
'for an existing alert with the same fingerprint'
do
expect
{
subject
}.
not_to
change
{
alert
.
reload
.
status
}
let_it_be
(
:fingerprint_sha
)
{
'89269ffa3902af37f036a77bc9ea57cdee3a52c2'
}
end
it
'does not set the ended at'
do
subject
expect
(
alert
.
reload
.
ended_at
).
to
be_nil
context
'which is triggered'
do
let_it_be
(
:alert
)
do
create
(
:alert_management_alert
,
:triggered
,
domain: :threat_monitoring
,
project:
project
,
fingerprint:
fingerprint_sha
)
end
end
it_behaves_like
'does not an create alert management alert'
it_behaves_like
'existing network alert'
end
end
context
'existing alert is resolved
'
do
context
'with an additional existing resolved alert
'
do
let!
(
:alert
)
do
before
do
create
(
create
(
:alert_management_alert
,
:alert_management_alert
,
:resolved
,
:resolved
,
project:
project
,
domain: :threat_monitoring
,
fingerprint:
fingerprint_sha
domain: :threat_monitoring
,
project:
project
,
fingerprint:
fingerprint_sha
)
)
end
end
it_behaves_like
'creates an alert management
alert'
it_behaves_like
'existing network
alert'
end
end
context
'existing alert is ignored'
do
let!
(
:alert
)
do
create
(
:alert_management_alert
,
:ignored
,
project:
project
,
domain: :threat_monitoring
,
fingerprint:
fingerprint_sha
)
end
end
it_behaves_like
'adds an alert management alert event'
context
'which is resolved'
do
let_it_be
(
:alert
)
do
create
(
:alert_management_alert
,
:resolved
,
domain: :threat_monitoring
,
project:
project
,
fingerprint:
fingerprint_sha
)
end
end
context
'two existing alerts, one resolved one open'
do
it_behaves_like
'never-before-seen network alert'
let!
(
:resolved_existing_alert
)
do
create
(
:alert_management_alert
,
:resolved
,
project:
project
,
fingerprint:
fingerprint_sha
)
end
let!
(
:alert
)
do
create
(
:alert_management_alert
,
domain: :threat_monitoring
,
project:
project
,
fingerprint:
fingerprint_sha
)
end
it_behaves_like
'adds an alert management alert event'
end
end
end
end
end
end
context
'with overlong payload'
do
context
'with overlong payload'
do
let
(
:deep_size_object
)
{
instance_double
(
Gitlab
::
Utils
::
DeepSize
,
valid?:
false
)
}
let
(
:deep_size_object
)
{
instance_double
(
Gitlab
::
Utils
::
DeepSize
,
valid?:
false
)
}
let
(
:payload
)
{
ActionController
::
Parameters
.
new
({}).
permit!
}
before
do
before
do
allow
(
Gitlab
::
Utils
::
DeepSize
).
to
receive
(
:new
).
and_return
(
deep_size_object
)
allow
(
Gitlab
::
Utils
::
DeepSize
).
to
receive
(
:new
).
and_return
(
deep_size_object
)
end
end
it_behaves_like
'does not process incident issues due to error'
,
http_status: :bad_request
it_behaves_like
'alerts service responds with an error and takes no actions'
,
:bad_request
it_behaves_like
'does not an create alert management alert'
end
context
'error duing save'
do
let
(
:payload_raw
)
{
build
(
:network_alert_payload
)
}
let
(
:logger
)
{
double
(
warn:
{})
}
let
(
:payload
)
{
ActionController
::
Parameters
.
new
(
payload_raw
).
permit!
}
it
'logs warning'
do
expect_any_instance_of
(
AlertManagement
::
Alert
).
to
receive
(
:save
).
and_return
(
false
)
expect_any_instance_of
(
described_class
).
to
receive
(
:logger
).
and_return
(
logger
)
subject
expect
(
logger
).
to
have_received
(
:warn
).
with
(
hash_including
(
message:
"Unable to create AlertManagement::Alert from
#{
tool
}
"
,
project_id:
project
.
id
,
alert_errors:
{}
)
)
end
end
end
end
end
end
end
ee/spec/services/alert_management/process_prometheus_alert_service_spec.rb
View file @
df5a8953
...
@@ -5,25 +5,23 @@ require 'spec_helper'
...
@@ -5,25 +5,23 @@ require 'spec_helper'
RSpec
.
describe
AlertManagement
::
ProcessPrometheusAlertService
do
RSpec
.
describe
AlertManagement
::
ProcessPrometheusAlertService
do
let_it_be
(
:project
,
refind:
true
)
{
create
(
:project
)
}
let_it_be
(
:project
,
refind:
true
)
{
create
(
:project
)
}
before
do
allow
(
ProjectServiceWorker
).
to
receive
(
:perform_async
)
end
describe
'#execute'
do
describe
'#execute'
do
let
(
:service
)
{
described_class
.
new
(
project
,
payload
)
}
let
(
:service
)
{
described_class
.
new
(
project
,
payload
)
}
subject
(
:execute
)
{
service
.
execute
}
subject
(
:execute
)
{
service
.
execute
}
context
'when alert payload is valid'
do
context
'when alert payload is valid'
do
let
(
:parsed_payload
)
{
Gitlab
::
AlertManagement
::
Payload
.
parse
(
project
,
payload
,
monitoring_tool:
'Prometheus'
)
}
let_it_be
(
:starts_at
)
{
'2020-04-27T10:10:22.265949279Z'
}
let
(
:fingerprint
)
{
parsed_payload
.
gitlab_fingerprint
}
let_it_be
(
:title
)
{
'Alert title'
}
let_it_be
(
:gitlab_fingerprint
)
{
Digest
::
SHA1
.
hexdigest
([
starts_at
,
title
,
'vector(1)'
].
join
(
'/'
))
}
let
(
:payload
)
{
raw_payload
}
let
(
:payload
)
{
raw_payload
}
let
(
:raw_payload
)
do
let
(
:raw_payload
)
do
{
{
'status'
=>
'firing'
,
'status'
=>
'firing'
,
'labels'
=>
{
'alertname'
=>
'GitalyFileServerDown'
},
'labels'
=>
{
'alertname'
=>
'GitalyFileServerDown'
},
'annotations'
=>
{
'title'
=>
'Alert title'
},
'annotations'
=>
{
'title'
=>
title
},
'startsAt'
=>
'2020-04-27T10:10:22.265949279Z'
,
'startsAt'
=>
starts_at
,
'endsAt'
=>
'2020-04-27T10:20:22.265949279Z'
,
'endsAt'
=>
'2020-04-27T10:20:22.265949279Z'
,
'generatorURL'
=>
'http://8d467bd4607a:9090/graph?g0.expr=vector%281%29&g0.tab=1'
'generatorURL'
=>
'http://8d467bd4607a:9090/graph?g0.expr=vector%281%29&g0.tab=1'
}
}
...
@@ -33,10 +31,19 @@ RSpec.describe AlertManagement::ProcessPrometheusAlertService do
...
@@ -33,10 +31,19 @@ RSpec.describe AlertManagement::ProcessPrometheusAlertService do
let_it_be
(
:schedule
)
{
create
(
:incident_management_oncall_schedule
,
project:
project
)
}
let_it_be
(
:schedule
)
{
create
(
:incident_management_oncall_schedule
,
project:
project
)
}
let_it_be
(
:rotation
)
{
create
(
:incident_management_oncall_rotation
,
schedule:
schedule
)
}
let_it_be
(
:rotation
)
{
create
(
:incident_management_oncall_rotation
,
schedule:
schedule
)
}
let_it_be
(
:participant
)
{
create
(
:incident_management_oncall_participant
,
:with_developer_access
,
rotation:
rotation
)
}
let_it_be
(
:participant
)
{
create
(
:incident_management_oncall_participant
,
:with_developer_access
,
rotation:
rotation
)
}
let
(
:resolving_payload
)
{
raw_payload
.
merge
(
'status'
=>
'resolved'
)
}
let
(
:users
)
{
[
participant
.
user
]
}
let
(
:users
)
{
[
participant
.
user
]
}
it_behaves_like
'oncall users are correctly notified'
before
do
stub_licensed_features
(
oncall_schedules:
project
)
end
include_examples
'oncall users are correctly notified of firing alert'
context
'with resolving payload'
do
let
(
:payload
)
{
raw_payload
.
merge
(
'status'
=>
'resolved'
)
}
include_examples
'oncall users are correctly notified of Prometheus recovery alert'
end
end
end
end
end
end
end
...
...
ee/spec/services/projects/alerting/notify_service_spec.rb
View file @
df5a8953
...
@@ -69,13 +69,28 @@ RSpec.describe Projects::Alerting::NotifyService do
...
@@ -69,13 +69,28 @@ RSpec.describe Projects::Alerting::NotifyService do
let_it_be
(
:schedule
)
{
create
(
:incident_management_oncall_schedule
,
project:
project
)
}
let_it_be
(
:schedule
)
{
create
(
:incident_management_oncall_schedule
,
project:
project
)
}
let_it_be
(
:rotation
)
{
create
(
:incident_management_oncall_rotation
,
schedule:
schedule
)
}
let_it_be
(
:rotation
)
{
create
(
:incident_management_oncall_rotation
,
schedule:
schedule
)
}
let_it_be
(
:participant
)
{
create
(
:incident_management_oncall_participant
,
:with_developer_access
,
rotation:
rotation
)
}
let_it_be
(
:participant
)
{
create
(
:incident_management_oncall_participant
,
:with_developer_access
,
rotation:
rotation
)
}
let_it_be
(
:fingerprint
)
{
'fingerprint'
}
let_it_be
(
:gitlab_fingerprint
)
{
Digest
::
SHA1
.
hexdigest
(
fingerprint
)
}
let
(
:payload
)
{
{
'fingerprint'
=>
'fingerprint'
}
}
let
(
:payload
)
{
{
'fingerprint'
=>
fingerprint
}
}
let
(
:resolving_payload
)
{
{
'fingerprint'
=>
'fingerprint'
,
"end_time"
:
Time
.
current
.
iso8601
}
}
let
(
:users
)
{
[
participant
.
user
]
}
let
(
:users
)
{
[
participant
.
user
]
}
let
(
:fingerprint
)
{
Digest
::
SHA1
.
hexdigest
(
'fingerprint'
)
}
it_behaves_like
'oncall users are correctly notified'
before
do
stub_licensed_features
(
oncall_schedules:
project
)
end
include_examples
'oncall users are correctly notified of firing alert'
context
'with resolving payload'
do
let
(
:payload
)
do
{
'fingerprint'
=>
fingerprint
,
'end_time'
=>
Time
.
current
.
iso8601
}
end
include_examples
'oncall users are correctly notified of recovery alert'
end
end
end
end
end
end
end
ee/spec/services/projects/prometheus/alerts/notify_service_spec.rb
View file @
df5a8953
...
@@ -10,7 +10,7 @@ RSpec.describe Projects::Prometheus::Alerts::NotifyService do
...
@@ -10,7 +10,7 @@ RSpec.describe Projects::Prometheus::Alerts::NotifyService do
let
(
:service
)
{
described_class
.
new
(
project
,
payload
)
}
let
(
:service
)
{
described_class
.
new
(
project
,
payload
)
}
let
(
:token_input
)
{
'token'
}
let
(
:token_input
)
{
'token'
}
let
!
(
:setting
)
do
let
_it_be
(
:setting
)
do
create
(
:project_incident_management_setting
,
project:
project
,
send_email:
true
,
create_issue:
true
)
create
(
:project_incident_management_setting
,
project:
project
,
send_email:
true
,
create_issue:
true
)
end
end
...
@@ -23,6 +23,7 @@ RSpec.describe Projects::Prometheus::Alerts::NotifyService do
...
@@ -23,6 +23,7 @@ RSpec.describe Projects::Prometheus::Alerts::NotifyService do
let
(
:payload
)
{
ActionController
::
Parameters
.
new
(
payload_raw
).
permit!
}
let
(
:payload
)
{
ActionController
::
Parameters
.
new
(
payload_raw
).
permit!
}
let
(
:payload_alert_firing
)
{
payload_raw
[
'alerts'
].
first
}
let
(
:payload_alert_firing
)
{
payload_raw
[
'alerts'
].
first
}
let
(
:token
)
{
'token'
}
let
(
:token
)
{
'token'
}
let
(
:source
)
{
'Prometheus'
}
context
'with environment specific clusters'
do
context
'with environment specific clusters'
do
let
(
:prd_cluster
)
do
let
(
:prd_cluster
)
do
...
@@ -51,11 +52,11 @@ RSpec.describe Projects::Prometheus::Alerts::NotifyService do
...
@@ -51,11 +52,11 @@ RSpec.describe Projects::Prometheus::Alerts::NotifyService do
context
'without token'
do
context
'without token'
do
let
(
:token_input
)
{
nil
}
let
(
:token_input
)
{
nil
}
i
t_behaves_like
'Alert Notification Service sends notification email
'
i
nclude_examples
'processes one firing and one resolved prometheus alerts
'
end
end
context
'with token'
do
context
'with token'
do
it_behaves_like
'
Alert Notification Service sends no notifications'
,
http_status:
:unauthorized
it_behaves_like
'
alerts service responds with an error'
,
:unauthorized
end
end
end
end
end
end
...
...
ee/spec/support/shared_examples/alert_notification_service_shared_examples.rb
deleted
100644 → 0
View file @
e8aec7f5
# frozen_string_literal: true
# Requires `users` and `fingerprint` to be defined
RSpec
.
shared_examples
'Alert Notification Service sends notification email to on-call users'
do
let
(
:notification_service
)
{
instance_double
(
NotificationService
)
}
it
'sends a notification'
do
expect
(
NotificationService
).
to
receive
(
:new
).
and_return
(
notification_service
)
expect
(
notification_service
)
.
to
receive_message_chain
(
:async
,
:notify_oncall_users_of_alert
)
.
with
(
users
,
having_attributes
(
class:
AlertManagement
::
Alert
,
fingerprint:
fingerprint
)
)
expect
(
subject
).
to
be_success
end
end
ee/spec/support/shared_examples/incident_management/oncall_notifications_shared_examples.rb
deleted
100644 → 0
View file @
e8aec7f5
# frozen_string_literal: true
# Requires `project`, `users`, `fingerprint`, and `resolving_payload`
RSpec
.
shared_examples
'oncall users are correctly notified'
do
context
'with feature enabled'
do
before
do
stub_licensed_features
(
oncall_schedules:
project
)
end
it_behaves_like
'Alert Notification Service sends notification email to on-call users'
context
'when alert with the same fingerprint already exists'
do
let!
(
:alert
)
{
create
(
:alert_management_alert
,
status
,
fingerprint:
fingerprint
,
project:
project
)
}
it_behaves_like
'Alert Notification Service sends notification email to on-call users'
do
let
(
:status
)
{
:triggered
}
end
it_behaves_like
'Alert Notification Service sends no notifications'
do
let
(
:status
)
{
:acknowledged
}
end
it_behaves_like
'Alert Notification Service sends notification email to on-call users'
do
let
(
:status
)
{
:resolved
}
end
it_behaves_like
'Alert Notification Service sends no notifications'
do
let
(
:status
)
{
:ignored
}
end
context
'with resolving payload'
do
let
(
:status
)
{
:triggered
}
let
(
:payload
)
{
resolving_payload
}
it_behaves_like
'Alert Notification Service sends notification email to on-call users'
end
end
end
context
'with feature disabled'
do
it_behaves_like
'Alert Notification Service sends no notifications'
end
end
ee/spec/support/shared_examples/services/alert_management/alert_processing/alert_firing_shared_examples.rb
0 → 100644
View file @
df5a8953
# frozen_string_literal: true
# This shared_example requires the following variables:
# - `project`, expected project for an incoming alert
# - `users`, users expected to receive on-call notifications
# - `gitlab_fingerprint`, sha which is used to uniquely identify the alert
RSpec
.
shared_examples
'oncall users are correctly notified of firing alert'
do
it_behaves_like
'sends on-call notification if enabled'
context
'when alert with the same fingerprint already exists'
do
context
'which is triggered'
do
let_it_be
(
:alert
)
{
create
(
:alert_management_alert
,
:triggered
,
fingerprint:
gitlab_fingerprint
,
project:
project
)
}
it_behaves_like
'sends on-call notification if enabled'
end
context
'which is acknowledged'
do
let_it_be
(
:alert
)
{
create
(
:alert_management_alert
,
:acknowledged
,
fingerprint:
gitlab_fingerprint
,
project:
project
)
}
it_behaves_like
'does not send on-call notification'
end
context
'which is resolved'
do
let_it_be
(
:alert
)
{
create
(
:alert_management_alert
,
:resolved
,
fingerprint:
gitlab_fingerprint
,
project:
project
)
}
it_behaves_like
'sends on-call notification if enabled'
end
context
'which is ignored'
do
let_it_be
(
:alert
)
{
create
(
:alert_management_alert
,
:ignored
,
fingerprint:
gitlab_fingerprint
,
project:
project
)
}
it_behaves_like
'does not send on-call notification'
end
end
end
ee/spec/support/shared_examples/services/alert_management/alert_processing/alert_recovery_shared_examples.rb
0 → 100644
View file @
df5a8953
# frozen_string_literal: true
# This shared_example requires the following variables:
# - `project`, expected project for an incoming alert
# - `users`, users expected to receive on-call notifications
# - `gitlab_fingerprint`, sha which is used to uniquely identify the alert
RSpec
.
shared_examples
'oncall users are correctly notified of recovery alert'
do
it_behaves_like
'sends on-call notification if enabled'
context
'when alert with the same fingerprint already exists'
do
context
'which is triggered'
do
let_it_be
(
:alert
)
{
create
(
:alert_management_alert
,
:triggered
,
fingerprint:
gitlab_fingerprint
,
project:
project
)
}
it_behaves_like
'sends on-call notification if enabled'
end
context
'which is acknowledged'
do
let_it_be
(
:alert
)
{
create
(
:alert_management_alert
,
:acknowledged
,
fingerprint:
gitlab_fingerprint
,
project:
project
)
}
it_behaves_like
'sends on-call notification if enabled'
end
context
'which is resolved'
do
let_it_be
(
:alert
)
{
create
(
:alert_management_alert
,
:resolved
,
fingerprint:
gitlab_fingerprint
,
project:
project
)
}
it_behaves_like
'sends on-call notification if enabled'
end
context
'which is ignored'
do
let_it_be
(
:alert
)
{
create
(
:alert_management_alert
,
:ignored
,
fingerprint:
gitlab_fingerprint
,
project:
project
)
}
it_behaves_like
'sends on-call notification if enabled'
end
end
end
RSpec
.
shared_examples
'oncall users are correctly notified of Prometheus recovery alert'
do
it_behaves_like
'does not send on-call notification'
context
'when alert with the same fingerprint already exists'
do
context
'which is triggered'
do
let_it_be
(
:alert
)
{
create
(
:alert_management_alert
,
:triggered
,
fingerprint:
gitlab_fingerprint
,
project:
project
)
}
it_behaves_like
'sends on-call notification if enabled'
end
context
'which is acknowledged'
do
let_it_be
(
:alert
)
{
create
(
:alert_management_alert
,
:acknowledged
,
fingerprint:
gitlab_fingerprint
,
project:
project
)
}
it_behaves_like
'sends on-call notification if enabled'
end
context
'which is resolved'
do
let_it_be
(
:alert
)
{
create
(
:alert_management_alert
,
:resolved
,
fingerprint:
gitlab_fingerprint
,
project:
project
)
}
it_behaves_like
'does not send on-call notification'
end
context
'which is ignored'
do
let_it_be
(
:alert
)
{
create
(
:alert_management_alert
,
:ignored
,
fingerprint:
gitlab_fingerprint
,
project:
project
)
}
it_behaves_like
'sends on-call notification if enabled'
end
end
end
ee/spec/support/shared_examples/services/alert_management/alert_processing/oncall_notifications_shared_examples.rb
0 → 100644
View file @
df5a8953
# frozen_string_literal: true
# This shared_example requires the following variables:
# - `users`, users expected to receive on-call notifications
# - `gitlab_fingerprint`, SHA which is used to uniquely identify the alert
RSpec
.
shared_examples
'sends on-call notification if enabled'
do
context
'with on-call schedules enabled'
do
let
(
:notification_async
)
{
double
(
NotificationService
::
Async
)
}
it
'sends on-call notification'
do
allow
(
NotificationService
).
to
receive_message_chain
(
:new
,
:async
).
and_return
(
notification_async
)
expect
(
notification_async
).
to
receive
(
:notify_oncall_users_of_alert
).
with
(
users
,
having_attributes
(
class:
AlertManagement
::
Alert
,
fingerprint:
gitlab_fingerprint
)
)
subject
end
end
context
'with on-call schedules disabled'
do
before
do
stub_licensed_features
(
oncall_schedules:
false
)
end
it_behaves_like
'does not send on-call notification'
end
end
RSpec
.
shared_examples
'does not send on-call notification'
do
specify
do
expect
(
NotificationService
).
not_to
receive
(
:new
)
subject
end
end
spec/services/alert_management/process_prometheus_alert_service_spec.rb
View file @
df5a8953
...
@@ -5,38 +5,27 @@ require 'spec_helper'
...
@@ -5,38 +5,27 @@ require 'spec_helper'
RSpec
.
describe
AlertManagement
::
ProcessPrometheusAlertService
do
RSpec
.
describe
AlertManagement
::
ProcessPrometheusAlertService
do
let_it_be
(
:project
,
reload:
true
)
{
create
(
:project
,
:repository
)
}
let_it_be
(
:project
,
reload:
true
)
{
create
(
:project
,
:repository
)
}
before
do
let
(
:service
)
{
described_class
.
new
(
project
,
payload
)
}
allow
(
ProjectServiceWorker
).
to
receive
(
:perform_async
)
end
describe
'#execute'
do
describe
'#execute'
do
let
(
:service
)
{
described_class
.
new
(
project
,
payload
)
}
include_context
'incident management settings enabled'
let
(
:source
)
{
'Prometheus'
}
let
(
:auto_close_incident
)
{
true
}
subject
(
:execute
)
{
service
.
execute
}
let
(
:create_issue
)
{
true
}
let
(
:send_email
)
{
true
}
let
(
:incident_management_setting
)
do
double
(
auto_close_incident?:
auto_close_incident
,
create_issue?:
create_issue
,
send_email?:
send_email
)
end
before
do
before
do
allow
(
service
)
stub_licensed_features
(
oncall_schedules:
false
,
generic_alert_fingerprinting:
false
)
.
to
receive
(
:incident_management_setting
)
.
and_return
(
incident_management_setting
)
end
end
subject
(
:execute
)
{
service
.
execute
}
context
'when alert payload is valid'
do
context
'when alert payload is valid'
do
let
(
:parsed_payload
)
{
Gitlab
::
AlertManagement
::
Payload
.
parse
(
project
,
payload
,
monitoring_tool:
source
)
}
let_it_be
(
:starts_at
)
{
'2020-04-27T10:10:22.265949279Z'
}
let
(
:fingerprint
)
{
parsed_payload
.
gitlab_fingerprint
}
let_it_be
(
:title
)
{
'Alert title'
}
let_it_be
(
:fingerprint
)
{
[
starts_at
,
title
,
'vector(1)'
].
join
(
'/'
)
}
let_it_be
(
:source
)
{
'Prometheus'
}
let
(
:prometheus_status
)
{
'firing'
}
let
(
:payload
)
do
let
(
:payload
)
do
{
{
'status'
=>
status
,
'status'
=>
prometheus_
status
,
'labels'
=>
{
'labels'
=>
{
'alertname'
=>
'GitalyFileServerDown'
,
'alertname'
=>
'GitalyFileServerDown'
,
'channel'
=>
'gitaly'
,
'channel'
=>
'gitaly'
,
...
@@ -46,209 +35,47 @@ RSpec.describe AlertManagement::ProcessPrometheusAlertService do
...
@@ -46,209 +35,47 @@ RSpec.describe AlertManagement::ProcessPrometheusAlertService do
'annotations'
=>
{
'annotations'
=>
{
'description'
=>
'Alert description'
,
'description'
=>
'Alert description'
,
'runbook'
=>
'troubleshooting/gitaly-down.md'
,
'runbook'
=>
'troubleshooting/gitaly-down.md'
,
'title'
=>
'Alert title'
'title'
=>
title
},
},
'startsAt'
=>
'2020-04-27T10:10:22.265949279Z'
,
'startsAt'
=>
starts_at
,
'endsAt'
=>
'2020-04-27T10:20:22.265949279Z'
,
'endsAt'
=>
'2020-04-27T10:20:22.265949279Z'
,
'generatorURL'
=>
'http://8d467bd4607a:9090/graph?g0.expr=vector%281%29&g0.tab=1'
,
'generatorURL'
=>
'http://8d467bd4607a:9090/graph?g0.expr=vector%281%29&g0.tab=1'
'fingerprint'
=>
'b6ac4d42057c43c1'
}
}
end
end
let
(
:status
)
{
'firing'
}
it_behaves_like
'processes new firing alert'
context
'when Prometheus alert status is firing'
do
context
'when alert with the same fingerprint already exists'
do
let!
(
:alert
)
{
create
(
:alert_management_alert
,
project:
project
,
fingerprint:
fingerprint
)
}
it_behaves_like
'adds an alert management alert event'
it_behaves_like
'processes incident issues'
it_behaves_like
'Alert Notification Service sends notification email'
context
'existing alert is resolved'
do
let!
(
:alert
)
{
create
(
:alert_management_alert
,
:resolved
,
project:
project
,
fingerprint:
fingerprint
)
}
it_behaves_like
'creates an alert management alert'
it_behaves_like
'Alert Notification Service sends notification email'
end
context
'existing alert is ignored'
do
let!
(
:alert
)
{
create
(
:alert_management_alert
,
:ignored
,
project:
project
,
fingerprint:
fingerprint
)
}
it_behaves_like
'adds an alert management alert event'
it_behaves_like
'Alert Notification Service sends no notifications'
end
context
'existing alert is acknowledged'
do
let!
(
:alert
)
{
create
(
:alert_management_alert
,
:acknowledged
,
project:
project
,
fingerprint:
fingerprint
)
}
it_behaves_like
'adds an alert management alert event'
it_behaves_like
'Alert Notification Service sends no notifications'
end
context
'two existing alerts, one resolved one open'
do
let!
(
:resolved_alert
)
{
create
(
:alert_management_alert
,
:resolved
,
project:
project
,
fingerprint:
fingerprint
)
}
let!
(
:alert
)
{
create
(
:alert_management_alert
,
project:
project
,
fingerprint:
fingerprint
)
}
it_behaves_like
'adds an alert management alert event'
it_behaves_like
'Alert Notification Service sends notification email'
end
context
'when auto-creation of issues is disabled'
do
let
(
:create_issue
)
{
false
}
it_behaves_like
'does not process incident issues'
end
context
'when emails are disabled'
do
let
(
:send_email
)
{
false
}
it_behaves_like
'Alert Notification Service sends no notifications'
end
end
context
'when alert does not exist'
do
context
'when alert can be created'
do
it_behaves_like
'creates an alert management alert'
it_behaves_like
'Alert Notification Service sends notification email'
it_behaves_like
'processes incident issues'
it_behaves_like
'creates single system note based on the source of the alert'
context
'when auto-alert creation is disabled'
do
let
(
:create_issue
)
{
false
}
it_behaves_like
'does not process incident issues'
end
context
'when emails are disabled'
do
let
(
:send_email
)
{
false
}
it_behaves_like
'Alert Notification Service sends no notifications'
end
end
context
'when alert cannot be created'
do
let
(
:errors
)
{
double
(
messages:
{
hosts:
[
'hosts array is over 255 chars'
]
})}
before
do
allow
(
service
).
to
receive
(
:alert
).
and_call_original
allow
(
service
).
to
receive_message_chain
(
:alert
,
:save
).
and_return
(
false
)
allow
(
service
).
to
receive_message_chain
(
:alert
,
:errors
).
and_return
(
errors
)
end
it_behaves_like
'Alert Notification Service sends no notifications'
,
http_status: :bad_request
it_behaves_like
'does not process incident issues due to error'
,
http_status: :bad_request
it
'writes a warning to the log'
do
expect
(
Gitlab
::
AppLogger
).
to
receive
(
:warn
).
with
(
message:
'Unable to create AlertManagement::Alert from Prometheus'
,
project_id:
project
.
id
,
alert_errors:
{
hosts:
[
'hosts array is over 255 chars'
]
}
)
execute
end
end
it
{
is_expected
.
to
be_success
}
end
end
context
'when Prometheus alert status is resolved'
do
let
(
:status
)
{
'resolved'
}
let!
(
:alert
)
{
create
(
:alert_management_alert
,
project:
project
,
fingerprint:
fingerprint
,
monitoring_tool:
source
)
}
context
'when auto_resolve_incident set to true'
do
context
'when status can be changed'
do
it_behaves_like
'Alert Notification Service sends notification email'
it_behaves_like
'does not process incident issues'
it
'resolves an existing alert without error'
do
expect
(
Gitlab
::
AppLogger
).
not_to
receive
(
:warn
)
expect
{
execute
}.
to
change
{
alert
.
reload
.
resolved?
}.
to
(
true
)
end
it_behaves_like
'creates status-change system note for an auto-resolved alert'
context
'existing issue'
do
let!
(
:alert
)
{
create
(
:alert_management_alert
,
:with_issue
,
project:
project
,
fingerprint:
fingerprint
)
}
it
'closes the issue
'
do
context
'with resolving payload
'
do
issue
=
alert
.
issue
let
(
:prometheus_status
)
{
'resolved'
}
expect
{
execute
}
it_behaves_like
'processes prometheus recovery alert'
.
to
change
{
issue
.
reload
.
state
}
.
from
(
'opened'
)
.
to
(
'closed'
)
end
end
it
'creates a resource state event'
do
context
'environment given'
do
expect
{
execute
}.
to
change
(
ResourceStateEvent
,
:count
).
by
(
1
)
let
(
:environment
)
{
create
(
:environment
,
project:
project
)
}
end
let
(
:alert
)
{
project
.
alert_management_alerts
.
last
}
end
end
context
'when status change did not succeed'
do
before
do
before
do
allow
(
AlertManagement
::
Alert
).
to
receive
(
:for_fingerprint
).
and_return
([
alert
])
payload
[
'labels'
][
'gitlab_environment_name'
]
=
environment
.
name
allow
(
alert
).
to
receive
(
:resolve
).
and_return
(
false
)
end
it
'writes a warning to the log'
do
expect
(
Gitlab
::
AppLogger
).
to
receive
(
:warn
).
with
(
message:
'Unable to update AlertManagement::Alert status to resolved'
,
project_id:
project
.
id
,
alert_id:
alert
.
id
)
execute
end
it_behaves_like
'Alert Notification Service sends notification email'
end
it
{
is_expected
.
to
be_success
}
end
context
'when auto_resolve_incident set to false'
do
let
(
:auto_close_incident
)
{
false
}
it
'does not resolve an existing alert'
do
expect
{
execute
}.
not_to
change
{
alert
.
reload
.
resolved?
}
end
it_behaves_like
'creates single system note based on the source of the alert'
end
context
'when emails are disabled'
do
let
(
:send_email
)
{
false
}
it_behaves_like
'Alert Notification Service sends no notifications'
end
end
end
context
'environment given'
do
let
(
:environment
)
{
create
(
:environment
,
project:
project
)
}
it
'sets the environment'
do
it
'sets the environment'
do
payload
[
'labels'
][
'gitlab_environment_name'
]
=
environment
.
name
execute
execute
alert
=
project
.
alert_management_alerts
.
last
expect
(
alert
.
environment
).
to
eq
(
environment
)
expect
(
alert
.
environment
).
to
eq
(
environment
)
end
end
end
end
context
'prometheus alert given'
do
context
'prometheus alert given'
do
let
(
:prometheus_alert
)
{
create
(
:prometheus_alert
,
project:
project
)
}
let
(
:prometheus_alert
)
{
create
(
:prometheus_alert
,
project:
project
)
}
let
(
:alert
)
{
project
.
alert_management_alerts
.
last
}
it
'sets the prometheus alert and environment'
do
before
do
payload
[
'labels'
][
'gitlab_alert_id'
]
=
prometheus_alert
.
prometheus_metric_id
payload
[
'labels'
][
'gitlab_alert_id'
]
=
prometheus_alert
.
prometheus_metric_id
execute
end
alert
=
project
.
alert_management_alerts
.
last
it
'sets the prometheus alert and environment'
do
execute
expect
(
alert
.
prometheus_alert
).
to
eq
(
prometheus_alert
)
expect
(
alert
.
prometheus_alert
).
to
eq
(
prometheus_alert
)
expect
(
alert
.
environment
).
to
eq
(
prometheus_alert
.
environment
)
expect
(
alert
.
environment
).
to
eq
(
prometheus_alert
.
environment
)
...
@@ -259,10 +86,7 @@ RSpec.describe AlertManagement::ProcessPrometheusAlertService do
...
@@ -259,10 +86,7 @@ RSpec.describe AlertManagement::ProcessPrometheusAlertService do
context
'when alert payload is invalid'
do
context
'when alert payload is invalid'
do
let
(
:payload
)
{
{}
}
let
(
:payload
)
{
{}
}
it
'responds with bad_request'
do
it_behaves_like
'alerts service responds with an error and takes no actions'
,
:bad_request
expect
(
execute
).
to
be_error
expect
(
execute
.
http_status
).
to
eq
(
:bad_request
)
end
end
end
end
end
end
end
spec/services/projects/alerting/notify_service_spec.rb
View file @
df5a8953
...
@@ -3,27 +3,43 @@
...
@@ -3,27 +3,43 @@
require
'spec_helper'
require
'spec_helper'
RSpec
.
describe
Projects
::
Alerting
::
NotifyService
do
RSpec
.
describe
Projects
::
Alerting
::
NotifyService
do
let_it_be_with_reload
(
:project
)
{
create
(
:project
,
:repository
)
}
let_it_be_with_reload
(
:project
)
{
create
(
:project
)
}
let
(
:payload
)
{
ActionController
::
Parameters
.
new
(
payload_raw
).
permit!
}
let
(
:payload_raw
)
{
{}
}
let
(
:service
)
{
described_class
.
new
(
project
,
payload
)
}
before
do
before
do
allow
(
ProjectServiceWorker
).
to
receive
(
:perform_async
)
stub_licensed_features
(
oncall_schedules:
false
,
generic_alert_fingerprinting:
false
)
end
end
describe
'#execute'
do
describe
'#execute'
do
let
(
:token
)
{
'invalid-token'
}
include_context
'incident management settings enabled'
let
(
:starts_at
)
{
Time
.
current
.
change
(
usec:
0
)
}
let
(
:fingerprint
)
{
'testing'
}
subject
{
service
.
execute
(
token
,
integration
)
}
let
(
:service
)
{
described_class
.
new
(
project
,
payload
)
}
context
'with HTTP integration'
do
let_it_be_with_reload
(
:integration
)
{
create
(
:alert_management_http_integration
,
project:
project
)
}
context
'with valid token'
do
let
(
:token
)
{
integration
.
token
}
context
'with valid payload'
do
let_it_be
(
:environment
)
{
create
(
:environment
,
project:
project
)
}
let_it_be
(
:environment
)
{
create
(
:environment
,
project:
project
)
}
let
(
:environment
)
{
create
(
:environment
,
project:
project
)
}
let_it_be
(
:fingerprint
)
{
'testing'
}
let_it_be
(
:source
)
{
'GitLab RSpec'
}
let_it_be
(
:starts_at
)
{
Time
.
current
.
change
(
usec:
0
)
}
let
(
:ended_at
)
{
nil
}
let
(
:ended_at
)
{
nil
}
let
(
:domain
)
{
'operations'
}
let
(
:payload_raw
)
do
let
(
:payload_raw
)
do
{
{
title:
'alert title'
,
title:
'alert title'
,
start_time:
starts_at
.
rfc3339
,
start_time:
starts_at
.
rfc3339
,
end_time:
ended_at
&
.
rfc3339
,
end_time:
ended_at
&
.
rfc3339
,
severity:
'low'
,
severity:
'low'
,
monitoring_tool:
'GitLab RSpec'
,
monitoring_tool:
source
,
service:
'GitLab Test Suite'
,
service:
'GitLab Test Suite'
,
description:
'Very detailed description'
,
description:
'Very detailed description'
,
hosts:
[
'1.1.1.1'
,
'2.2.2.2'
],
hosts:
[
'1.1.1.1'
,
'2.2.2.2'
],
...
@@ -32,58 +48,14 @@ RSpec.describe Projects::Alerting::NotifyService do
...
@@ -32,58 +48,14 @@ RSpec.describe Projects::Alerting::NotifyService do
}.
with_indifferent_access
}.
with_indifferent_access
end
end
let
(
:payload
)
{
ActionController
::
Parameters
.
new
(
payload_raw
).
permit!
}
subject
{
service
.
execute
(
token
,
nil
)
}
shared_examples
'notifications are handled correctly'
do
context
'with valid token'
do
let
(
:token
)
{
integration
.
token
}
let
(
:incident_management_setting
)
{
double
(
send_email?:
email_enabled
,
create_issue?:
issue_enabled
,
auto_close_incident?:
auto_close_enabled
)
}
let
(
:email_enabled
)
{
false
}
let
(
:issue_enabled
)
{
false
}
let
(
:auto_close_enabled
)
{
false
}
before
do
allow
(
service
)
.
to
receive
(
:incident_management_setting
)
.
and_return
(
incident_management_setting
)
end
context
'with valid payload'
do
shared_examples
'assigns the alert properties'
do
it
'ensure that created alert has all data properly assigned'
do
subject
expect
(
last_alert_attributes
).
to
match
(
project_id:
project
.
id
,
title:
payload_raw
.
fetch
(
:title
),
started_at:
Time
.
zone
.
parse
(
payload_raw
.
fetch
(
:start_time
)),
severity:
payload_raw
.
fetch
(
:severity
),
status:
AlertManagement
::
Alert
.
status_value
(
:triggered
),
events:
1
,
domain:
'operations'
,
hosts:
payload_raw
.
fetch
(
:hosts
),
payload:
payload_raw
.
with_indifferent_access
,
issue_id:
nil
,
description:
payload_raw
.
fetch
(
:description
),
monitoring_tool:
payload_raw
.
fetch
(
:monitoring_tool
),
service:
payload_raw
.
fetch
(
:service
),
fingerprint:
Digest
::
SHA1
.
hexdigest
(
fingerprint
),
environment_id:
environment
.
id
,
ended_at:
nil
,
prometheus_alert_id:
nil
)
end
end
let
(
:last_alert_attributes
)
do
let
(
:last_alert_attributes
)
do
AlertManagement
::
Alert
.
last
.
attributes
AlertManagement
::
Alert
.
last
.
attributes
.
except
(
'id'
,
'iid'
,
'created_at'
,
'updated_at'
)
.
except
(
'id'
,
'iid'
,
'created_at'
,
'updated_at'
)
.
with_indifferent_access
.
with_indifferent_access
end
end
it_behaves_like
'
creates an alert management
alert'
it_behaves_like
'
processes new firing
alert'
it_behaves_like
'assigns the alert properties'
it_behaves_like
'
properly
assigns the alert properties'
it
'passes the integration to alert processing'
do
it
'passes the integration to alert processing'
do
expect
(
Gitlab
::
AlertManagement
::
Payload
)
expect
(
Gitlab
::
AlertManagement
::
Payload
)
...
@@ -94,101 +66,18 @@ RSpec.describe Projects::Alerting::NotifyService do
...
@@ -94,101 +66,18 @@ RSpec.describe Projects::Alerting::NotifyService do
subject
subject
end
end
it
'creates a system note corresponding to alert creation'
do
context
'with partial payload'
do
expect
{
subject
}.
to
change
(
Note
,
:count
).
by
(
1
)
let_it_be
(
:source
)
{
integration
.
name
}
expect
(
Note
.
last
.
note
).
to
include
(
payload_raw
.
fetch
(
:monitoring_tool
))
let_it_be
(
:payload_raw
)
do
end
context
'existing alert with same fingerprint'
do
let
(
:fingerprint_sha
)
{
Digest
::
SHA1
.
hexdigest
(
fingerprint
)
}
let!
(
:alert
)
{
create
(
:alert_management_alert
,
project:
project
,
fingerprint:
fingerprint_sha
)
}
it_behaves_like
'adds an alert management alert event'
context
'end time given'
do
let
(
:ended_at
)
{
Time
.
current
.
change
(
nsec:
0
)
}
it
'does not resolve the alert'
do
expect
{
subject
}.
not_to
change
{
alert
.
reload
.
status
}
end
it
'does not set the ended at'
do
subject
expect
(
alert
.
reload
.
ended_at
).
to
be_nil
end
it_behaves_like
'does not an create alert management alert'
it_behaves_like
'creates single system note based on the source of the alert'
context
'auto_close_enabled setting enabled'
do
let
(
:auto_close_enabled
)
{
true
}
it
'resolves the alert and sets the end time'
,
:aggregate_failures
do
subject
alert
.
reload
expect
(
alert
.
resolved?
).
to
eq
(
true
)
expect
(
alert
.
ended_at
).
to
eql
(
ended_at
)
end
it_behaves_like
'creates status-change system note for an auto-resolved alert'
context
'related issue exists'
do
let
(
:alert
)
{
create
(
:alert_management_alert
,
:with_issue
,
project:
project
,
fingerprint:
fingerprint_sha
)
}
let
(
:issue
)
{
alert
.
issue
}
it
{
expect
{
subject
}.
to
change
{
issue
.
reload
.
state
}.
from
(
'opened'
).
to
(
'closed'
)
}
it
{
expect
{
subject
}.
to
change
(
ResourceStateEvent
,
:count
).
by
(
1
)
}
end
context
'with issue enabled'
do
let
(
:issue_enabled
)
{
true
}
it_behaves_like
'does not process incident issues'
end
end
end
context
'existing alert is resolved'
do
let!
(
:alert
)
{
create
(
:alert_management_alert
,
:resolved
,
project:
project
,
fingerprint:
fingerprint_sha
)
}
it_behaves_like
'creates an alert management alert'
it_behaves_like
'assigns the alert properties'
end
context
'existing alert is ignored'
do
let!
(
:alert
)
{
create
(
:alert_management_alert
,
:ignored
,
project:
project
,
fingerprint:
fingerprint_sha
)
}
it_behaves_like
'adds an alert management alert event'
end
context
'two existing alerts, one resolved one open'
do
let!
(
:resolved_existing_alert
)
{
create
(
:alert_management_alert
,
:resolved
,
project:
project
,
fingerprint:
fingerprint_sha
)
}
let!
(
:alert
)
{
create
(
:alert_management_alert
,
project:
project
,
fingerprint:
fingerprint_sha
)
}
it_behaves_like
'adds an alert management alert event'
end
end
context
'end time given'
do
let
(
:ended_at
)
{
Time
.
current
}
it_behaves_like
'creates an alert management alert'
it_behaves_like
'assigns the alert properties'
end
context
'with a minimal payload'
do
let
(
:payload_raw
)
do
{
{
title:
'alert title'
,
title:
'alert title'
,
start_time:
starts_at
.
rfc3339
start_time:
starts_at
.
rfc3339
}
}
end
end
i
t_behaves_like
'creates an alert management
alert'
i
nclude_examples
'processes never-before-seen
alert'
it
'
created alert has all data properly assigned
'
do
it
'
assigns the alert properties
'
do
subject
subject
expect
(
last_alert_attributes
).
to
match
(
expect
(
last_alert_attributes
).
to
match
(
...
@@ -212,7 +101,19 @@ RSpec.describe Projects::Alerting::NotifyService do
...
@@ -212,7 +101,19 @@ RSpec.describe Projects::Alerting::NotifyService do
)
)
end
end
it_behaves_like
'creates single system note based on the source of the alert'
context
'with existing alert with matching payload'
do
let_it_be
(
:fingerprint
)
{
payload_raw
.
except
(
:start_time
).
stringify_keys
}
let_it_be
(
:gitlab_fingerprint
)
{
Gitlab
::
AlertManagement
::
Fingerprint
.
generate
(
fingerprint
)
}
let_it_be
(
:alert
)
{
create
(
:alert_management_alert
,
project:
project
,
fingerprint:
gitlab_fingerprint
)
}
include_examples
'processes never-before-seen alert'
end
end
context
'with resolving payload'
do
let
(
:ended_at
)
{
Time
.
current
.
change
(
usec:
0
)
}
it_behaves_like
'processes recovery alert'
end
end
end
end
...
@@ -223,63 +124,30 @@ RSpec.describe Projects::Alerting::NotifyService do
...
@@ -223,63 +124,30 @@ RSpec.describe Projects::Alerting::NotifyService do
allow
(
Gitlab
::
Utils
::
DeepSize
).
to
receive
(
:new
).
and_return
(
deep_size_object
)
allow
(
Gitlab
::
Utils
::
DeepSize
).
to
receive
(
:new
).
and_return
(
deep_size_object
)
end
end
it_behaves_like
'does not process incident issues due to error'
,
http_status: :bad_request
it_behaves_like
'alerts service responds with an error and takes no actions'
,
:bad_request
it_behaves_like
'does not an create alert management alert'
end
end
it_behaves_like
'does not process incident issues'
context
'with inactive integration'
do
before
do
context
'issue enabled'
do
integration
.
update!
(
active:
false
)
let
(
:issue_enabled
)
{
true
}
it_behaves_like
'processes incident issues'
context
'when alert already exists'
do
let
(
:fingerprint_sha
)
{
Digest
::
SHA1
.
hexdigest
(
fingerprint
)
}
let!
(
:alert
)
{
create
(
:alert_management_alert
,
project:
project
,
fingerprint:
fingerprint_sha
)
}
context
'when existing alert does not have an associated issue'
do
it_behaves_like
'processes incident issues'
end
end
context
'when existing alert has an associated issue'
do
it_behaves_like
'alerts service responds with an error and takes no actions'
,
:forbidden
let!
(
:alert
)
{
create
(
:alert_management_alert
,
:with_issue
,
project:
project
,
fingerprint:
fingerprint_sha
)
}
it_behaves_like
'does not process incident issues'
end
end
end
context
'with emails turned on'
do
let
(
:email_enabled
)
{
true
}
it_behaves_like
'Alert Notification Service sends notification email'
end
end
end
end
context
'with invalid token'
do
context
'with invalid token'
do
it_behaves_like
'does not process incident issues due to error'
,
http_status: :unauthorized
let
(
:token
)
{
'invalid-token'
}
it_behaves_like
'does not an create alert management alert'
end
end
context
'with an HTTP Integration'
do
let_it_be_with_reload
(
:integration
)
{
create
(
:alert_management_http_integration
,
project:
project
)
}
subject
{
service
.
execute
(
token
,
integration
)
}
it_behaves_like
'notifications are handled correctly'
do
it_behaves_like
'alerts service responds with an error and takes no actions'
,
:unauthorized
let
(
:source
)
{
integration
.
name
}
end
end
context
'with deactivated HTTP Integration'
do
before
do
integration
.
update!
(
active:
false
)
end
end
it_behaves_like
'does not process incident issues due to error'
,
http_status: :forbidden
context
'without HTTP integration'
do
it_behaves_like
'does not an create alert management alert'
let
(
:integration
)
{
nil
}
end
let
(
:token
)
{
nil
}
it_behaves_like
'alerts service responds with an error and takes no actions'
,
:forbidden
end
end
end
end
end
end
spec/services/projects/prometheus/alerts/notify_service_spec.rb
View file @
df5a8953
...
@@ -6,25 +6,26 @@ RSpec.describe Projects::Prometheus::Alerts::NotifyService do
...
@@ -6,25 +6,26 @@ RSpec.describe Projects::Prometheus::Alerts::NotifyService do
include
PrometheusHelpers
include
PrometheusHelpers
using
RSpec
::
Parameterized
::
TableSyntax
using
RSpec
::
Parameterized
::
TableSyntax
let_it_be
(
:project
,
reload:
true
)
{
create
(
:project
)
}
let_it_be_with_reload
(
:project
)
{
create
(
:project
)
}
let_it_be_with_reload
(
:setting
)
do
create
(
:project_incident_management_setting
,
project:
project
,
send_email:
true
,
create_issue:
true
)
end
let
(
:service
)
{
described_class
.
new
(
project
,
payload
)
}
let
(
:service
)
{
described_class
.
new
(
project
,
payload
)
}
let
(
:token_input
)
{
'token'
}
let
(
:token_input
)
{
'token'
}
let!
(
:setting
)
do
subject
{
service
.
execute
(
token_input
)
}
create
(
:project_incident_management_setting
,
project:
project
,
send_email:
true
,
create_issue:
true
)
end
let
(
:subject
)
{
service
.
execute
(
token_input
)
}
context
'with valid payload'
do
context
'with valid payload'
do
let_it_be
(
:alert_firing
)
{
create
(
:prometheus_alert
,
project:
project
)
}
let_it_be
(
:alert_firing
)
{
create
(
:prometheus_alert
,
project:
project
)
}
let_it_be
(
:alert_resolved
)
{
create
(
:prometheus_alert
,
project:
project
)
}
let_it_be
(
:alert_resolved
)
{
create
(
:prometheus_alert
,
project:
project
)
}
let_it_be
(
:cluster
)
{
create
(
:cluster
,
:provided_by_user
,
projects:
[
project
])
}
let_it_be
(
:cluster
,
reload:
true
)
{
create
(
:cluster
,
:provided_by_user
,
projects:
[
project
])
}
let
(
:payload_raw
)
{
prometheus_alert_payload
(
firing:
[
alert_firing
],
resolved:
[
alert_resolved
])
}
let
(
:payload_raw
)
{
prometheus_alert_payload
(
firing:
[
alert_firing
],
resolved:
[
alert_resolved
])
}
let
(
:payload
)
{
ActionController
::
Parameters
.
new
(
payload_raw
).
permit!
}
let
(
:payload
)
{
ActionController
::
Parameters
.
new
(
payload_raw
).
permit!
}
let
(
:payload_alert_firing
)
{
payload_raw
[
'alerts'
].
first
}
let
(
:payload_alert_firing
)
{
payload_raw
[
'alerts'
].
first
}
let
(
:token
)
{
'token'
}
let
(
:token
)
{
'token'
}
let
(
:source
)
{
'Prometheus'
}
context
'with environment specific clusters'
do
context
'with environment specific clusters'
do
let
(
:prd_cluster
)
do
let
(
:prd_cluster
)
do
...
@@ -53,11 +54,11 @@ RSpec.describe Projects::Prometheus::Alerts::NotifyService do
...
@@ -53,11 +54,11 @@ RSpec.describe Projects::Prometheus::Alerts::NotifyService do
context
'without token'
do
context
'without token'
do
let
(
:token_input
)
{
nil
}
let
(
:token_input
)
{
nil
}
i
t_behaves_like
'Alert Notification Service sends notification email
'
i
nclude_examples
'processes one firing and one resolved prometheus alerts
'
end
end
context
'with token'
do
context
'with token'
do
it_behaves_like
'
Alert Notification Service sends no notifications'
,
http_status:
:unauthorized
it_behaves_like
'
alerts service responds with an error and takes no actions'
,
:unauthorized
end
end
end
end
...
@@ -87,9 +88,9 @@ RSpec.describe Projects::Prometheus::Alerts::NotifyService do
...
@@ -87,9 +88,9 @@ RSpec.describe Projects::Prometheus::Alerts::NotifyService do
case
result
=
params
[
:result
]
case
result
=
params
[
:result
]
when
:success
when
:success
i
t_behaves_like
'Alert Notification Service sends notification email
'
i
nclude_examples
'processes one firing and one resolved prometheus alerts
'
when
:failure
when
:failure
it_behaves_like
'
Alert Notification Service sends no notifications'
,
http_status:
:unauthorized
it_behaves_like
'
alerts service responds with an error and takes no actions'
,
:unauthorized
else
else
raise
"invalid result:
#{
result
.
inspect
}
"
raise
"invalid result:
#{
result
.
inspect
}
"
end
end
...
@@ -97,9 +98,9 @@ RSpec.describe Projects::Prometheus::Alerts::NotifyService do
...
@@ -97,9 +98,9 @@ RSpec.describe Projects::Prometheus::Alerts::NotifyService do
end
end
context
'without project specific cluster'
do
context
'without project specific cluster'
do
let
!
(
:cluster
)
{
create
(
:cluster
,
enabled:
true
)
}
let
_it_be
(
:cluster
)
{
create
(
:cluster
,
enabled:
true
)
}
it_behaves_like
'
Alert Notification Service sends no notifications'
,
http_status:
:unauthorized
it_behaves_like
'
alerts service responds with an error and takes no actions'
,
:unauthorized
end
end
context
'with manual prometheus installation'
do
context
'with manual prometheus installation'
do
...
@@ -126,9 +127,9 @@ RSpec.describe Projects::Prometheus::Alerts::NotifyService do
...
@@ -126,9 +127,9 @@ RSpec.describe Projects::Prometheus::Alerts::NotifyService do
case
result
=
params
[
:result
]
case
result
=
params
[
:result
]
when
:success
when
:success
it_behaves_like
'
Alert Notification Service sends notification email
'
it_behaves_like
'
processes one firing and one resolved prometheus alerts
'
when
:failure
when
:failure
it_behaves_like
'
Alert Notification Service sends no notifications'
,
http_status:
:unauthorized
it_behaves_like
'
alerts service responds with an error and takes no actions'
,
:unauthorized
else
else
raise
"invalid result:
#{
result
.
inspect
}
"
raise
"invalid result:
#{
result
.
inspect
}
"
end
end
...
@@ -150,50 +151,53 @@ RSpec.describe Projects::Prometheus::Alerts::NotifyService do
...
@@ -150,50 +151,53 @@ RSpec.describe Projects::Prometheus::Alerts::NotifyService do
let
(
:token_input
)
{
public_send
(
token
)
if
token
}
let
(
:token_input
)
{
public_send
(
token
)
if
token
}
let
(
:integration
)
{
create
(
:alert_management_http_integration
,
active
,
project:
project
)
if
active
}
let
(
:integration
)
{
create
(
:alert_management_http_integration
,
active
,
project:
project
)
if
active
}
let
(
:subject
)
{
service
.
execute
(
token_input
,
integration
)
}
subject
{
service
.
execute
(
token_input
,
integration
)
}
case
result
=
params
[
:result
]
case
result
=
params
[
:result
]
when
:success
when
:success
it_behaves_like
'
Alert Notification Service sends notification email
'
it_behaves_like
'
processes one firing and one resolved prometheus alerts
'
when
:failure
when
:failure
it_behaves_like
'
Alert Notification Service sends no notifications'
,
http_status:
:unauthorized
it_behaves_like
'
alerts service responds with an error and takes no actions'
,
:unauthorized
else
else
raise
"invalid result:
#{
result
.
inspect
}
"
raise
"invalid result:
#{
result
.
inspect
}
"
end
end
end
end
end
end
context
'
alert email
s'
do
context
'
incident setting
s'
do
before
do
before
do
create
(
:prometheus_service
,
project:
project
)
create
(
:prometheus_service
,
project:
project
)
create
(
:project_alerting_setting
,
project:
project
,
token:
token
)
create
(
:project_alerting_setting
,
project:
project
,
token:
token
)
end
end
context
'when incident_management_setting does not exist'
do
it_behaves_like
'processes one firing and one resolved prometheus alerts'
let!
(
:setting
)
{
nil
}
it
'does not send notification email'
,
:sidekiq_might_not_need_inline
do
expect_any_instance_of
(
NotificationService
)
.
not_to
receive
(
:async
)
expect
(
subject
).
to
be_success
context
'when incident_management_setting does not exist'
do
end
before
do
setting
.
destroy!
end
end
context
'when incident_management_setting.send_email is true'
do
it
{
is_expected
.
to
be_success
}
it_behaves_like
'Alert Notification Service sends notification email'
include_examples
'does not send alert notification emails'
include_examples
'does not process incident issues'
end
end
context
'incident_management_setting.send_email is false'
do
context
'incident_management_setting.send_email is false'
do
let!
(
:setting
)
do
before
do
create
(
:project_incident_management_setting
,
send_email:
false
,
project:
project
)
setting
.
update!
(
send_email:
false
)
end
end
it
'does not send notification'
do
it
{
is_expected
.
to
be_success
}
expect
(
NotificationService
).
not_to
receive
(
:new
)
include_examples
'does not send alert notification emails'
end
expect
(
subject
).
to
be_success
context
'incident_management_setting.create_issue is false'
do
before
do
setting
.
update!
(
create_issue:
false
)
end
end
it
{
is_expected
.
to
be_success
}
include_examples
'does not process incident issues'
end
end
end
end
...
@@ -233,7 +237,7 @@ RSpec.describe Projects::Prometheus::Alerts::NotifyService do
...
@@ -233,7 +237,7 @@ RSpec.describe Projects::Prometheus::Alerts::NotifyService do
.
and_return
(
false
)
.
and_return
(
false
)
end
end
it_behaves_like
'
Alert Notification Service sends no notifications'
,
http_status:
:unprocessable_entity
it_behaves_like
'
alerts service responds with an error and takes no actions'
,
:unprocessable_entity
end
end
context
'when the payload is too big'
do
context
'when the payload is too big'
do
...
@@ -244,14 +248,7 @@ RSpec.describe Projects::Prometheus::Alerts::NotifyService do
...
@@ -244,14 +248,7 @@ RSpec.describe Projects::Prometheus::Alerts::NotifyService do
allow
(
Gitlab
::
Utils
::
DeepSize
).
to
receive
(
:new
).
and_return
(
deep_size_object
)
allow
(
Gitlab
::
Utils
::
DeepSize
).
to
receive
(
:new
).
and_return
(
deep_size_object
)
end
end
it_behaves_like
'Alert Notification Service sends no notifications'
,
http_status: :bad_request
it_behaves_like
'alerts service responds with an error and takes no actions'
,
:bad_request
it
'does not process Prometheus alerts'
do
expect
(
AlertManagement
::
ProcessPrometheusAlertService
)
.
not_to
receive
(
:new
)
subject
end
end
end
end
end
...
...
spec/support/shared_examples/alert_notification_service_shared_examples.rb
deleted
100644 → 0
View file @
e8aec7f5
# frozen_string_literal: true
RSpec
.
shared_examples
'Alert Notification Service sends notification email'
do
let
(
:notification_service
)
{
spy
}
it
'sends a notification'
do
expect
(
NotificationService
)
.
to
receive
(
:new
)
.
and_return
(
notification_service
)
expect
(
notification_service
)
.
to
receive_message_chain
(
:async
,
:prometheus_alerts_fired
)
expect
(
subject
).
to
be_success
end
end
RSpec
.
shared_examples
'Alert Notification Service sends no notifications'
do
|
http_status:
nil
|
it
'does not notify'
do
expect
(
NotificationService
).
not_to
receive
(
:new
)
if
http_status
.
present?
expect
(
subject
).
to
be_error
expect
(
subject
.
http_status
).
to
eq
(
http_status
)
else
expect
(
subject
).
to
be_success
end
end
end
RSpec
.
shared_examples
'creates status-change system note for an auto-resolved alert'
do
it
'has 2 new system notes'
do
expect
{
subject
}.
to
change
(
Note
,
:count
).
by
(
2
)
expect
(
Note
.
last
.
note
).
to
include
(
'Resolved'
)
end
end
# Requires `source` to be defined
RSpec
.
shared_examples
'creates single system note based on the source of the alert'
do
it
'has one new system note'
do
expect
{
subject
}.
to
change
(
Note
,
:count
).
by
(
1
)
expect
(
Note
.
last
.
note
).
to
include
(
source
)
end
end
spec/support/shared_examples/services/alert_management/alert_processing/alert_firing_shared_examples.rb
0 → 100644
View file @
df5a8953
# frozen_string_literal: true
# This shared_example requires the following variables:
# - `service`, the service which includes AlertManagement::AlertProcessing
RSpec
.
shared_examples
'creates an alert management alert or errors'
do
it
{
is_expected
.
to
be_success
}
it
'creates AlertManagement::Alert'
do
expect
(
Gitlab
::
AppLogger
).
not_to
receive
(
:warn
)
expect
{
subject
}.
to
change
(
AlertManagement
::
Alert
,
:count
).
by
(
1
)
end
it
'executes the alert service hooks'
do
expect_next_instance_of
(
AlertManagement
::
Alert
)
do
|
alert
|
expect
(
alert
).
to
receive
(
:execute_services
)
end
subject
end
context
'and fails to save'
do
let
(
:errors
)
{
double
(
messages:
{
hosts:
[
'hosts array is over 255 chars'
]
})}
before
do
allow
(
service
).
to
receive
(
:alert
).
and_call_original
allow
(
service
).
to
receive_message_chain
(
:alert
,
:save
).
and_return
(
false
)
allow
(
service
).
to
receive_message_chain
(
:alert
,
:errors
).
and_return
(
errors
)
end
it_behaves_like
'alerts service responds with an error'
,
:bad_request
it
'writes a warning to the log'
do
expect
(
Gitlab
::
AppLogger
).
to
receive
(
:warn
).
with
(
message:
"Unable to create AlertManagement::Alert from
#{
source
}
"
,
project_id:
project
.
id
,
alert_errors:
{
hosts:
[
'hosts array is over 255 chars'
]
}
)
subject
end
end
end
# This shared_example requires the following variables:
# - last_alert_attributes, last created alert
# - project, project that alert created
# - payload_raw, hash representation of payload
# - environment, project's environment
# - fingerprint, fingerprint hash
RSpec
.
shared_examples
'properly assigns the alert properties'
do
specify
do
subject
expect
(
last_alert_attributes
).
to
match
({
project_id:
project
.
id
,
title:
payload_raw
.
fetch
(
:title
),
started_at:
Time
.
zone
.
parse
(
payload_raw
.
fetch
(
:start_time
)),
severity:
payload_raw
.
fetch
(
:severity
,
nil
),
status:
AlertManagement
::
Alert
.
status_value
(
:triggered
),
events:
1
,
domain:
domain
,
hosts:
payload_raw
.
fetch
(
:hosts
,
nil
),
payload:
payload_raw
.
with_indifferent_access
,
issue_id:
nil
,
description:
payload_raw
.
fetch
(
:description
,
nil
),
monitoring_tool:
payload_raw
.
fetch
(
:monitoring_tool
,
nil
),
service:
payload_raw
.
fetch
(
:service
,
nil
),
fingerprint:
Digest
::
SHA1
.
hexdigest
(
fingerprint
),
environment_id:
environment
.
id
,
ended_at:
nil
,
prometheus_alert_id:
nil
}.
with_indifferent_access
)
end
end
RSpec
.
shared_examples
'does not create an alert management alert'
do
specify
do
expect
{
subject
}.
not_to
change
(
AlertManagement
::
Alert
,
:count
)
end
end
# This shared_example requires the following variables:
# - `alert`, the alert for which events should be incremented
RSpec
.
shared_examples
'adds an alert management alert event'
do
specify
do
expect
(
alert
).
not_to
receive
(
:execute_services
)
expect
{
subject
}.
to
change
{
alert
.
reload
.
events
}.
by
(
1
)
expect
(
subject
).
to
be_success
end
it_behaves_like
'does not create an alert management alert'
end
# This shared_example requires the following variables:
# - `alert`, the alert for which events should not be incremented
RSpec
.
shared_examples
'does not add an alert management alert event'
do
specify
do
expect
{
subject
}.
not_to
change
{
alert
.
reload
.
events
}
end
end
RSpec
.
shared_examples
'processes new firing alert'
do
include_examples
'processes never-before-seen alert'
context
'for an existing alert with the same fingerprint'
do
let_it_be
(
:gitlab_fingerprint
)
{
Digest
::
SHA1
.
hexdigest
(
fingerprint
)
}
context
'which is triggered'
do
let_it_be
(
:alert
)
{
create
(
:alert_management_alert
,
:triggered
,
fingerprint:
gitlab_fingerprint
,
project:
project
)
}
it_behaves_like
'adds an alert management alert event'
it_behaves_like
'sends alert notification emails if enabled'
it_behaves_like
'processes incident issues if enabled'
,
with_issue:
true
it_behaves_like
'does not create an alert management alert'
it_behaves_like
'does not create a system note for alert'
context
'with an existing resolved alert as well'
do
let_it_be
(
:resolved_alert
)
{
create
(
:alert_management_alert
,
:resolved
,
project:
project
,
fingerprint:
gitlab_fingerprint
)
}
it_behaves_like
'adds an alert management alert event'
it_behaves_like
'sends alert notification emails if enabled'
it_behaves_like
'processes incident issues if enabled'
,
with_issue:
true
it_behaves_like
'does not create an alert management alert'
it_behaves_like
'does not create a system note for alert'
end
end
context
'which is acknowledged'
do
let_it_be
(
:alert
)
{
create
(
:alert_management_alert
,
:acknowledged
,
fingerprint:
gitlab_fingerprint
,
project:
project
)
}
it_behaves_like
'adds an alert management alert event'
it_behaves_like
'processes incident issues if enabled'
,
with_issue:
true
it_behaves_like
'does not create an alert management alert'
it_behaves_like
'does not create a system note for alert'
it_behaves_like
'does not send alert notification emails'
end
context
'which is ignored'
do
let_it_be
(
:alert
)
{
create
(
:alert_management_alert
,
:ignored
,
fingerprint:
gitlab_fingerprint
,
project:
project
)
}
it_behaves_like
'adds an alert management alert event'
it_behaves_like
'processes incident issues if enabled'
,
with_issue:
true
it_behaves_like
'does not create an alert management alert'
it_behaves_like
'does not create a system note for alert'
it_behaves_like
'does not send alert notification emails'
end
context
'which is resolved'
do
let_it_be
(
:alert
)
{
create
(
:alert_management_alert
,
:resolved
,
fingerprint:
gitlab_fingerprint
,
project:
project
)
}
include_examples
'processes never-before-seen alert'
end
end
end
spec/support/shared_examples/services/alert_management/alert_processing/alert_recovery_shared_examples.rb
0 → 100644
View file @
df5a8953
# frozen_string_literal: true
# This shared_example requires the following variables:
# - `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
)
expect
(
subject
).
to
be_success
end
end
# This shared_example requires the following variables:
# - `alert`, the alert not to be updated
RSpec
.
shared_examples
'does not change the alert end time'
do
specify
do
expect
{
subject
}.
not_to
change
{
alert
.
reload
.
ended_at
}
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
}
include_examples
'processes never-before-seen recovery alert'
end
context
'for an existing alert with the same fingerprint'
do
let_it_be
(
:gitlab_fingerprint
)
{
Digest
::
SHA1
.
hexdigest
(
fingerprint
)
}
context
'which is triggered'
do
let_it_be
(
:alert
)
{
create
(
:alert_management_alert
,
:triggered
,
project:
project
,
fingerprint:
gitlab_fingerprint
,
monitoring_tool:
source
)
}
it_behaves_like
'resolves an existing alert management alert'
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'
it_behaves_like
'does not add an alert management alert event'
end
context
'which is ignored'
do
let_it_be
(
:alert
)
{
create
(
:alert_management_alert
,
:ignored
,
project:
project
,
fingerprint:
gitlab_fingerprint
,
monitoring_tool:
source
)
}
it_behaves_like
'resolves an existing alert management alert'
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'
it_behaves_like
'does not add an alert management alert event'
end
context
'which is acknowledged'
do
let_it_be
(
:alert
)
{
create
(
:alert_management_alert
,
:acknowledged
,
project:
project
,
fingerprint:
gitlab_fingerprint
,
monitoring_tool:
source
)
}
it_behaves_like
'resolves an existing alert management alert'
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'
it_behaves_like
'does not add an alert management alert event'
end
context
'which is resolved'
do
let_it_be
(
:alert
)
{
create
(
:alert_management_alert
,
:resolved
,
project:
project
,
fingerprint:
gitlab_fingerprint
,
monitoring_tool:
source
)
}
include_examples
'processes never-before-seen recovery alert'
end
end
end
RSpec
.
shared_examples
'processes prometheus recovery alert'
do
context
'seen for the first time'
do
it_behaves_like
'does not create an alert management alert'
it_behaves_like
'does not send alert notification emails'
it_behaves_like
'does not process incident issues'
end
context
'for an existing alert with the same fingerprint'
do
let_it_be
(
:gitlab_fingerprint
)
{
Digest
::
SHA1
.
hexdigest
(
fingerprint
)
}
context
'which is triggered'
do
let_it_be
(
:alert
)
{
create
(
:alert_management_alert
,
:triggered
,
project:
project
,
fingerprint:
gitlab_fingerprint
,
monitoring_tool:
source
)
}
it_behaves_like
'resolves an existing alert management alert'
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'
it_behaves_like
'does not add an alert management alert event'
end
context
'which is ignored'
do
let_it_be
(
:alert
)
{
create
(
:alert_management_alert
,
:ignored
,
project:
project
,
fingerprint:
gitlab_fingerprint
,
monitoring_tool:
source
)
}
it_behaves_like
'resolves an existing alert management alert'
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'
it_behaves_like
'does not add an alert management alert event'
end
context
'which is acknowledged'
do
let_it_be
(
:alert
)
{
create
(
:alert_management_alert
,
:acknowledged
,
project:
project
,
fingerprint:
gitlab_fingerprint
,
monitoring_tool:
source
)
}
it_behaves_like
'resolves an existing alert management alert'
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'
it_behaves_like
'does not add an alert management alert event'
end
context
'which is resolved'
do
let_it_be
(
:alert
)
{
create
(
:alert_management_alert
,
:resolved
,
project:
project
,
fingerprint:
gitlab_fingerprint
,
monitoring_tool:
source
)
}
it_behaves_like
'does not create an alert management alert'
it_behaves_like
'does not send alert notification emails'
it_behaves_like
'does not change the alert end time'
it_behaves_like
'does not process incident issues'
it_behaves_like
'does not add an alert management alert event'
end
end
end
spec/support/shared_examples/services/alert_management/alert_processing/incident_creation_shared_examples.rb
0 → 100644
View file @
df5a8953
# frozen_string_literal: true
# Expects usage of 'incident settings enabled' context.
#
# This shared_example includes the following option:
# - with_issue: includes a test for when the defined `alert` has an associated issue
#
# 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
context
'with incident setting disabled'
do
let
(
:create_issue
)
{
false
}
it_behaves_like
'does not process incident issues'
end
end
RSpec
.
shared_examples
'processes incident issues'
do
|
with_issue:
false
|
before
do
allow_next_instance_of
(
AlertManagement
::
Alert
)
do
|
alert
|
allow
(
alert
).
to
receive
(
:execute_services
)
end
end
specify
do
expect
(
IncidentManagement
::
ProcessAlertWorker
)
.
to
receive
(
:perform_async
)
.
with
(
nil
,
nil
,
kind_of
(
Integer
))
Sidekiq
::
Testing
.
inline!
do
expect
(
subject
).
to
be_success
end
end
context
'with issue'
,
if:
with_issue
do
before
do
alert
.
update!
(
issue:
create
(
:issue
,
project:
project
))
end
it_behaves_like
'does not process incident issues'
end
end
RSpec
.
shared_examples
'does not process incident issues'
do
specify
do
expect
(
IncidentManagement
::
ProcessAlertWorker
).
not_to
receive
(
:perform_async
)
subject
end
end
spec/support/shared_examples/services/alert_management/alert_processing/incident_resolution_shared_examples.rb
0 → 100644
View file @
df5a8953
# frozen_string_literal: true
# Expects usage of 'incident settings enabled' context.
#
# This shared_example requires the following variables:
# - `alert`, alert for which related incidents should be closed
# - `project`, project of the alert
RSpec
.
shared_examples
'closes related incident if enabled'
do
context
'with issue'
do
before
do
alert
.
update!
(
issue:
create
(
:issue
,
project:
project
))
end
it
{
expect
{
subject
}.
to
change
{
alert
.
issue
.
reload
.
closed?
}.
from
(
false
).
to
(
true
)
}
it
{
expect
{
subject
}.
to
change
(
ResourceStateEvent
,
:count
).
by
(
1
)
}
end
context
'without issue'
do
it
{
expect
{
subject
}.
not_to
change
{
alert
.
reload
.
issue
}
}
it
{
expect
{
subject
}.
not_to
change
(
ResourceStateEvent
,
:count
)
}
end
context
'with incident setting disabled'
do
let
(
:auto_close_incident
)
{
false
}
it_behaves_like
'does not close related incident'
end
end
RSpec
.
shared_examples
'does not close related incident'
do
context
'with issue'
do
before
do
alert
.
update!
(
issue:
create
(
:issue
,
project:
project
))
end
it
{
expect
{
subject
}.
not_to
change
{
alert
.
issue
.
reload
.
state
}
}
it
{
expect
{
subject
}.
not_to
change
(
ResourceStateEvent
,
:count
)
}
end
context
'without issue'
do
it
{
expect
{
subject
}.
not_to
change
{
alert
.
reload
.
issue
}
}
it
{
expect
{
subject
}.
not_to
change
(
ResourceStateEvent
,
:count
)
}
end
end
spec/support/shared_examples/services/alert_management/alert_processing/notifications_shared_examples.rb
0 → 100644
View file @
df5a8953
# frozen_string_literal: true
# Expects usage of 'incident 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
context
'with email setting disabled'
do
let
(
:send_email
)
{
false
}
it_behaves_like
'does not send alert notification emails'
end
end
RSpec
.
shared_examples
'sends alert notification emails'
do
|
count:
1
|
let
(
:notification_async
)
{
double
(
NotificationService
::
Async
)
}
specify
do
allow
(
NotificationService
).
to
receive_message_chain
(
:new
,
:async
).
and_return
(
notification_async
)
expect
(
notification_async
).
to
receive
(
:prometheus_alerts_fired
).
exactly
(
count
).
times
subject
end
end
RSpec
.
shared_examples
'does not send alert notification emails'
do
specify
do
expect
(
NotificationService
).
not_to
receive
(
:new
)
subject
end
end
spec/support/shared_examples/services/alert_management/alert_processing/system_notes_shared_examples.rb
0 → 100644
View file @
df5a8953
# frozen_string_literal: true
# This shared_example includes the following option:
# - notes: any of [:new_alert, :recovery_alert, :resolve_alert].
# Represents which notes are expected to be created.
#
# This shared_example requires the following variables:
# - `source` (optional), the monitoring tool or integration name
# expected in the applicable system notes
RSpec
.
shared_examples
'creates expected system notes for alert'
do
|*
notes
|
let
(
:expected_note_count
)
{
expected_notes
.
length
}
let
(
:new_notes
)
{
Note
.
last
(
expected_note_count
).
pluck
(
:note
)
}
let
(
:expected_notes
)
do
{
new_alert:
source
,
recovery_alert:
source
,
resolve_alert:
'Resolved'
}.
slice
(
*
notes
)
end
it
"for
#{
notes
.
join
(
', '
)
}
"
do
expect
{
subject
}.
to
change
(
Note
,
:count
).
by
(
expected_note_count
)
expected_notes
.
each_value
.
with_index
do
|
value
,
index
|
expect
(
new_notes
[
index
]).
to
include
(
value
)
end
end
end
RSpec
.
shared_examples
'does not create a system note for alert'
do
specify
do
expect
{
subject
}.
not_to
change
(
Note
,
:count
)
end
end
spec/support/shared_examples/services/alert_management_shared_examples.rb
View file @
df5a8953
# frozen_string_literal: true
# frozen_string_literal: true
RSpec
.
shared_examples
'
creates an alert management alert'
do
RSpec
.
shared_examples
'
alerts service responds with an error and takes no actions'
do
|
http_status
|
i
t
{
is_expected
.
to
be_success
}
i
nclude_examples
'alerts service responds with an error'
,
http_status
it
'creates AlertManagement::Alert'
do
it_behaves_like
'does not create an alert management alert'
expect
{
subject
}.
to
change
(
AlertManagement
::
Alert
,
:count
).
by
(
1
)
it_behaves_like
'does not create a system note for alert'
end
it_behaves_like
'does not process incident issues'
it_behaves_like
'does not send alert notification emails'
it
'executes the alert service hooks'
do
end
expect_next_instance_of
(
AlertManagement
::
Alert
)
do
|
alert
|
expect
(
alert
).
to
receive
(
:execute_services
)
end
subject
RSpec
.
shared_examples
'alerts service responds with an error'
do
|
http_status
|
specify
do
expect
(
subject
).
to
be_error
expect
(
subject
.
http_status
).
to
eq
(
http_status
)
end
end
end
end
# This shared_example requires the following variables:
# This shared_example requires the following variables:
# - last_alert_attributes, last created alert
# - `service`, a service which includes ::IncidentManagement::Settings
# - project, project that alert created
RSpec
.
shared_context
'incident management settings enabled'
do
# - payload_raw, hash representation of payload
let
(
:auto_close_incident
)
{
true
}
# - environment, project's environment
let
(
:create_issue
)
{
true
}
# - fingerprint, fingerprint hash
let
(
:send_email
)
{
true
}
RSpec
.
shared_examples
'assigns the alert properties'
do
it
'ensures that created alert has all data properly assigned'
do
let
(
:incident_management_setting
)
do
subject
double
(
auto_close_incident?:
auto_close_incident
,
expect
(
last_alert_attributes
).
to
match
(
create_issue?:
create_issue
,
project_id:
project
.
id
,
send_email?:
send_email
title:
payload_raw
.
fetch
(
:title
),
started_at:
Time
.
zone
.
parse
(
payload_raw
.
fetch
(
:start_time
)),
severity:
payload_raw
.
fetch
(
:severity
),
status:
AlertManagement
::
Alert
.
status_value
(
:triggered
),
events:
1
,
domain:
domain
,
hosts:
payload_raw
.
fetch
(
:hosts
),
payload:
payload_raw
.
with_indifferent_access
,
issue_id:
nil
,
description:
payload_raw
.
fetch
(
:description
),
monitoring_tool:
payload_raw
.
fetch
(
:monitoring_tool
),
service:
payload_raw
.
fetch
(
:service
),
fingerprint:
Digest
::
SHA1
.
hexdigest
(
fingerprint
),
environment_id:
environment
.
id
,
ended_at:
nil
,
prometheus_alert_id:
nil
)
)
end
end
end
RSpec
.
shared_examples
'does not an create alert management alert'
do
before
do
it
'does not create alert'
do
allow
(
ProjectServiceWorker
).
to
receive
(
:perform_async
)
expect
{
subject
}.
not_to
change
(
AlertManagement
::
Alert
,
:count
)
allow
(
service
)
.
to
receive
(
:incident_management_setting
)
.
and_return
(
incident_management_setting
)
end
end
end
end
RSpec
.
shared_examples
'adds an alert management alert event'
do
RSpec
.
shared_examples
'processes never-before-seen alert'
do
it
{
is_expected
.
to
be_success
}
it_behaves_like
'creates an alert management alert or errors'
it_behaves_like
'creates expected system notes for alert'
,
:new_alert
it
'does not create an alert'
do
it_behaves_like
'processes incident issues if enabled'
expect
{
subject
}.
not_to
change
(
AlertManagement
::
Alert
,
:count
)
it_behaves_like
'sends alert notification emails if enabled'
end
it
'increases alert events count'
do
expect
{
subject
}.
to
change
{
alert
.
reload
.
events
}.
by
(
1
)
end
it
'does not executes the alert service hooks'
do
expect
(
alert
).
not_to
receive
(
:execute_services
)
subject
end
end
end
RSpec
.
shared_examples
'processes incident issues'
do
RSpec
.
shared_examples
'processes never-before-seen recovery alert'
do
let
(
:create_incident_service
)
{
spy
}
it_behaves_like
'creates an alert management alert or errors'
it_behaves_like
'creates expected system notes for alert'
,
:new_alert
before
do
it_behaves_like
'sends alert notification emails if enabled'
allow_any_instance_of
(
AlertManagement
::
Alert
).
to
receive
(
:execute_services
)
it_behaves_like
'processes incident issues if enabled'
end
it
'processes issues'
do
expect
(
IncidentManagement
::
ProcessAlertWorker
)
.
to
receive
(
:perform_async
)
.
with
(
nil
,
nil
,
kind_of
(
Integer
))
.
once
Sidekiq
::
Testing
.
inline!
do
expect
(
subject
).
to
be_success
end
end
end
end
RSpec
.
shared_examples
'does not process incident issues'
do
RSpec
.
shared_examples
'processes one firing and one resolved prometheus alerts'
do
it
'does not process issues'
do
it
'creates AlertManagement::Alert'
do
expect
(
IncidentManagement
::
ProcessAlertWorker
)
expect
(
Gitlab
::
AppLogger
).
not_to
receive
(
:warn
)
.
not_to
receive
(
:perform_async
)
expect
(
subject
).
to
be_success
expect
{
subject
}
.
to
change
(
AlertManagement
::
Alert
,
:count
).
by
(
1
)
.
and
change
(
Note
,
:count
).
by
(
1
)
end
end
end
RSpec
.
shared_examples
'does not process incident issues due to error'
do
|
http_status
:|
it
'does not process issues'
do
expect
(
IncidentManagement
::
ProcessAlertWorker
)
.
not_to
receive
(
:perform_async
)
expect
(
subject
).
to
be_error
it_behaves_like
'processes incident issues'
expect
(
subject
.
http_status
).
to
eq
(
http_status
)
it_behaves_like
'sends alert notification emails'
,
count:
1
end
end
end
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment