summaryrefslogtreecommitdiff
path: root/spec/lib/gitlab/alert_management/payload/prometheus_spec.rb
diff options
context:
space:
mode:
Diffstat (limited to 'spec/lib/gitlab/alert_management/payload/prometheus_spec.rb')
-rw-r--r--spec/lib/gitlab/alert_management/payload/prometheus_spec.rb240
1 files changed, 240 insertions, 0 deletions
diff --git a/spec/lib/gitlab/alert_management/payload/prometheus_spec.rb b/spec/lib/gitlab/alert_management/payload/prometheus_spec.rb
new file mode 100644
index 00000000000..457db58a28b
--- /dev/null
+++ b/spec/lib/gitlab/alert_management/payload/prometheus_spec.rb
@@ -0,0 +1,240 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe Gitlab::AlertManagement::Payload::Prometheus do
+ let_it_be(:project) { create(:project) }
+ let(:raw_payload) { {} }
+
+ let(:parsed_payload) { described_class.new(project: project, payload: raw_payload) }
+
+ it_behaves_like 'subclass has expected api'
+
+ shared_context 'with environment' do
+ let_it_be(:environment) { create(:environment, project: project, name: 'production') }
+ end
+
+ describe '#title' do
+ subject { parsed_payload.title }
+
+ it_behaves_like 'parsable alert payload field',
+ 'annotations/title',
+ 'annotations/summary',
+ 'labels/alertname'
+ end
+
+ describe '#description' do
+ subject { parsed_payload.description }
+
+ it_behaves_like 'parsable alert payload field', 'annotations/description'
+ end
+
+ describe '#annotations' do
+ subject { parsed_payload.annotations }
+
+ it_behaves_like 'parsable alert payload field', 'annotations'
+ end
+
+ describe '#status' do
+ subject { parsed_payload.status }
+
+ it_behaves_like 'parsable alert payload field', 'status'
+ end
+
+ describe '#starts_at' do
+ let(:current_time) { Time.current.utc }
+
+ around do |example|
+ freeze_time { example.run }
+ end
+
+ subject { parsed_payload.starts_at }
+
+ context 'without payload' do
+ it { is_expected.to eq(current_time) }
+ end
+
+ context "with startsAt" do
+ let(:value) { 10.minutes.ago.change(usec: 0).utc }
+ let(:raw_payload) { { 'startsAt' => value.rfc3339 } }
+
+ it { is_expected.to eq(value) }
+ end
+ end
+
+ describe '#ends_at' do
+ subject { parsed_payload.ends_at }
+
+ context 'without payload' do
+ it { is_expected.to be_nil }
+ end
+
+ context "with endsAt" do
+ let(:value) { Time.current.change(usec: 0).utc }
+ let(:raw_payload) { { 'endsAt' => value.rfc3339 } }
+
+ it { is_expected.to eq(value) }
+ end
+ end
+
+ describe '#generator_url' do
+ subject { parsed_payload.generator_url }
+
+ it_behaves_like 'parsable alert payload field', 'generatorURL'
+ end
+
+ describe '#runbook' do
+ subject { parsed_payload.runbook }
+
+ it_behaves_like 'parsable alert payload field', 'annotations/runbook'
+ end
+
+ describe '#alert_markdown' do
+ subject { parsed_payload.alert_markdown }
+
+ it_behaves_like 'parsable alert payload field', 'annotations/gitlab_incident_markdown'
+ end
+
+ describe '#environment_name' do
+ subject { parsed_payload.environment_name }
+
+ it_behaves_like 'parsable alert payload field', 'labels/gitlab_environment_name'
+ end
+
+ describe '#gitlab_y_label' do
+ subject { parsed_payload.gitlab_y_label }
+
+ it_behaves_like 'parsable alert payload field',
+ 'annotations/gitlab_y_label',
+ 'annotations/title',
+ 'annotations/summary',
+ 'labels/alertname'
+ end
+
+ describe '#monitoring_tool' do
+ subject { parsed_payload.monitoring_tool }
+
+ it { is_expected.to eq('Prometheus') }
+ end
+
+ describe '#full_query' do
+ using RSpec::Parameterized::TableSyntax
+
+ subject { parsed_payload.full_query }
+
+ where(:generator_url, :expected_query) do
+ nil | nil
+ 'http://localhost' | nil
+ 'invalid url' | nil
+ 'http://localhost:9090/graph?g1.expr=vector%281%29' | nil
+ 'http://localhost:9090/graph?g0.expr=vector%281%29' | 'vector(1)'
+ end
+
+ with_them do
+ let(:raw_payload) { { 'generatorURL' => generator_url } }
+
+ it { is_expected.to eq(expected_query) }
+ end
+ end
+
+ describe '#environment' do
+ subject { parsed_payload.environment }
+
+ it { is_expected.to be_nil }
+
+ context 'with environment_name' do
+ let(:raw_payload) { { 'labels' => { 'gitlab_environment_name' => 'production' } } }
+
+ it { is_expected.to be_nil }
+
+ context 'with matching environment' do
+ include_context 'with environment'
+
+ it { is_expected.to eq(environment) }
+ end
+ end
+ end
+
+ describe '#gitlab_fingerprint' do
+ subject { parsed_payload.gitlab_fingerprint }
+
+ let(:raw_payload) do
+ {
+ 'startsAt' => Time.current.to_s,
+ 'generatorURL' => 'http://localhost:9090/graph?g0.expr=vector%281%29',
+ 'annotations' => { 'title' => 'title' }
+ }
+ end
+
+ it 'returns a fingerprint' do
+ plain_fingerprint = [
+ parsed_payload.send(:starts_at_raw),
+ parsed_payload.title,
+ parsed_payload.full_query
+ ].join('/')
+
+ is_expected.to eq(Digest::SHA1.hexdigest(plain_fingerprint))
+ end
+ end
+
+ describe '#metrics_dashboard_url' do
+ include_context 'self-managed prometheus alert attributes' do
+ let(:raw_payload) { payload }
+ end
+
+ subject { parsed_payload.metrics_dashboard_url }
+
+ it { is_expected.to eq(dashboard_url_for_alert) }
+
+ context 'without environment' do
+ let(:raw_payload) { payload.except('labels') }
+
+ it { is_expected.to be_nil }
+ end
+
+ context 'without full query' do
+ let(:raw_payload) { payload.except('generatorURL') }
+
+ it { is_expected.to be_nil }
+ end
+
+ context 'without title' do
+ let(:raw_payload) { payload.except('annotations') }
+
+ it { is_expected.to be_nil }
+ end
+ end
+
+ describe '#has_required_attributes?' do
+ let(:starts_at) { Time.current.change(usec: 0).utc }
+ let(:raw_payload) { { 'annotations' => { 'title' => 'title' }, 'startsAt' => starts_at.rfc3339 } }
+
+ subject { parsed_payload.has_required_attributes? }
+
+ it { is_expected.to be_truthy }
+
+ context 'without project' do
+ let(:parsed_payload) { described_class.new(project: nil, payload: raw_payload) }
+
+ it { is_expected.to be_falsey }
+ end
+
+ context 'without title' do
+ let(:raw_payload) { { 'startsAt' => starts_at.rfc3339 } }
+
+ it { is_expected.to be_falsey }
+ end
+
+ context 'without startsAt' do
+ let(:raw_payload) { { 'annotations' => { 'title' => 'title' } } }
+
+ it { is_expected.to be_falsey }
+ end
+
+ context 'without payload' do
+ let(:parsed_payload) { described_class.new(project: project, payload: nil) }
+
+ it { is_expected.to be_falsey }
+ end
+ end
+end