diff options
Diffstat (limited to 'spec/lib/gitlab/alert_management/payload/prometheus_spec.rb')
-rw-r--r-- | spec/lib/gitlab/alert_management/payload/prometheus_spec.rb | 240 |
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 |