diff options
author | GitLab Bot <gitlab-bot@gitlab.com> | 2020-05-20 17:34:42 +0300 |
---|---|---|
committer | GitLab Bot <gitlab-bot@gitlab.com> | 2020-05-20 17:34:42 +0300 |
commit | 9f46488805e86b1bc341ea1620b866016c2ce5ed (patch) | |
tree | f9748c7e287041e37d6da49e0a29c9511dc34768 /spec/models/alert_management | |
parent | dfc92d081ea0332d69c8aca2f0e745cb48ae5e6d (diff) |
Add latest changes from gitlab-org/gitlab@13-0-stable-ee
Diffstat (limited to 'spec/models/alert_management')
-rw-r--r-- | spec/models/alert_management/alert_spec.rb | 320 |
1 files changed, 320 insertions, 0 deletions
diff --git a/spec/models/alert_management/alert_spec.rb b/spec/models/alert_management/alert_spec.rb new file mode 100644 index 00000000000..1da0c6d4071 --- /dev/null +++ b/spec/models/alert_management/alert_spec.rb @@ -0,0 +1,320 @@ +# frozen_string_literal: true + +require 'spec_helper' + +describe AlertManagement::Alert do + describe 'associations' do + it { is_expected.to belong_to(:project) } + it { is_expected.to belong_to(:issue) } + end + + describe 'validations' do + it { is_expected.to validate_presence_of(:title) } + it { is_expected.to validate_presence_of(:events) } + it { is_expected.to validate_presence_of(:severity) } + it { is_expected.to validate_presence_of(:status) } + it { is_expected.to validate_presence_of(:started_at) } + + it { is_expected.to validate_length_of(:title).is_at_most(200) } + it { is_expected.to validate_length_of(:description).is_at_most(1000) } + it { is_expected.to validate_length_of(:service).is_at_most(100) } + it { is_expected.to validate_length_of(:monitoring_tool).is_at_most(100) } + + context 'when status is triggered' do + context 'when ended_at is blank' do + subject { build(:alert_management_alert) } + + it { is_expected.to be_valid } + end + + context 'when ended_at is present' do + subject { build(:alert_management_alert, ended_at: Time.current) } + + it { is_expected.to be_invalid } + end + end + + context 'when status is acknowledged' do + context 'when ended_at is blank' do + subject { build(:alert_management_alert, :acknowledged) } + + it { is_expected.to be_valid } + end + + context 'when ended_at is present' do + subject { build(:alert_management_alert, :acknowledged, ended_at: Time.current) } + + it { is_expected.to be_invalid } + end + end + + context 'when status is resolved' do + context 'when ended_at is blank' do + subject { build(:alert_management_alert, :resolved, ended_at: nil) } + + it { is_expected.to be_invalid } + end + + context 'when ended_at is present' do + subject { build(:alert_management_alert, :resolved, ended_at: Time.current) } + + it { is_expected.to be_valid } + end + end + + context 'when status is ignored' do + context 'when ended_at is blank' do + subject { build(:alert_management_alert, :ignored) } + + it { is_expected.to be_valid } + end + + context 'when ended_at is present' do + subject { build(:alert_management_alert, :ignored, ended_at: Time.current) } + + it { is_expected.to be_invalid } + end + end + + describe 'fingerprint' do + let_it_be(:fingerprint) { 'fingerprint' } + let_it_be(:existing_alert) { create(:alert_management_alert, fingerprint: fingerprint) } + let(:new_alert) { build(:alert_management_alert, fingerprint: fingerprint, project: project) } + + subject { new_alert } + + context 'adding an alert with the same fingerprint' do + context 'same project' do + let(:project) { existing_alert.project } + + it { is_expected.not_to be_valid } + end + + context 'different project' do + let(:project) { create(:project) } + + it { is_expected.to be_valid } + end + end + end + + describe 'hosts' do + subject(:alert) { build(:alert_management_alert, hosts: hosts) } + + context 'over 255 total chars' do + let(:hosts) { ['111.111.111.111'] * 18 } + + it { is_expected.not_to be_valid } + end + + context 'under 255 chars' do + let(:hosts) { ['111.111.111.111'] * 17 } + + it { is_expected.to be_valid } + end + end + end + + describe 'enums' do + let(:severity_values) do + { critical: 0, high: 1, medium: 2, low: 3, info: 4, unknown: 5 } + end + + it { is_expected.to define_enum_for(:severity).with_values(severity_values) } + end + + describe 'scopes' do + let_it_be(:project) { create(:project) } + let_it_be(:triggered_alert) { create(:alert_management_alert, project: project) } + let_it_be(:resolved_alert) { create(:alert_management_alert, :resolved, project: project) } + let_it_be(:ignored_alert) { create(:alert_management_alert, :ignored, project: project) } + + describe '.for_iid' do + subject { AlertManagement::Alert.for_iid(triggered_alert.iid) } + + it { is_expected.to match_array(triggered_alert) } + end + + describe '.for_status' do + let(:status) { AlertManagement::Alert::STATUSES[:resolved] } + + subject { AlertManagement::Alert.for_status(status) } + + it { is_expected.to match_array(resolved_alert) } + + context 'with multiple statuses' do + let(:status) { AlertManagement::Alert::STATUSES.values_at(:resolved, :ignored) } + + it { is_expected.to match_array([resolved_alert, ignored_alert]) } + end + end + + describe '.for_fingerprint' do + let_it_be(:fingerprint) { SecureRandom.hex } + let_it_be(:alert_with_fingerprint) { create(:alert_management_alert, project: project, fingerprint: fingerprint) } + let_it_be(:unrelated_alert_with_finger_print) { create(:alert_management_alert, fingerprint: fingerprint) } + + subject { described_class.for_fingerprint(project, fingerprint) } + + it { is_expected.to contain_exactly(alert_with_fingerprint) } + end + + describe '.counts_by_status' do + subject { described_class.counts_by_status } + + it do + is_expected.to eq( + triggered_alert.status => 1, + resolved_alert.status => 1, + ignored_alert.status => 1 + ) + end + end + end + + describe '.search' do + let_it_be(:alert) do + create(:alert_management_alert, + title: 'Title', + description: 'Desc', + service: 'Service', + monitoring_tool: 'Monitor' + ) + end + + subject { AlertManagement::Alert.search(query) } + + context 'does not contain search string' do + let(:query) { 'something else' } + + it { is_expected.to be_empty } + end + + context 'title includes query' do + let(:query) { alert.title.upcase } + + it { is_expected.to contain_exactly(alert) } + end + + context 'description includes query' do + let(:query) { alert.description.upcase } + + it { is_expected.to contain_exactly(alert) } + end + + context 'service includes query' do + let(:query) { alert.service.upcase } + + it { is_expected.to contain_exactly(alert) } + end + + context 'monitoring tool includes query' do + let(:query) { alert.monitoring_tool.upcase } + + it { is_expected.to contain_exactly(alert) } + end + end + + describe '#details' do + let(:payload) do + { + 'title' => 'Details title', + 'custom' => { + 'alert' => { + 'fields' => %w[one two] + } + }, + 'yet' => { + 'another' => 'field' + } + } + end + let(:alert) { build(:alert_management_alert, title: 'Details title', payload: payload) } + + subject { alert.details } + + it 'renders the payload as inline hash' do + is_expected.to eq( + 'custom.alert.fields' => %w[one two], + 'yet.another' => 'field' + ) + end + end + + describe '#trigger' do + subject { alert.trigger } + + context 'when alert is in triggered state' do + let(:alert) { create(:alert_management_alert) } + + it 'does not change the alert status' do + expect { subject }.not_to change { alert.reload.status } + end + end + + context 'when alert not in triggered state' do + let(:alert) { create(:alert_management_alert, :resolved) } + + it 'changes the alert status to triggered' do + expect { subject }.to change { alert.triggered? }.to(true) + end + + it 'resets ended at' do + expect { subject }.to change { alert.reload.ended_at }.to nil + end + end + end + + describe '#acknowledge' do + subject { alert.acknowledge } + + let(:alert) { create(:alert_management_alert, :resolved) } + + it 'changes the alert status to acknowledged' do + expect { subject }.to change { alert.acknowledged? }.to(true) + end + + it 'resets ended at' do + expect { subject }.to change { alert.reload.ended_at }.to nil + end + end + + describe '#resolve' do + let!(:ended_at) { Time.current } + + subject do + alert.ended_at = ended_at + alert.resolve + end + + context 'when alert already resolved' do + let(:alert) { create(:alert_management_alert, :resolved) } + + it 'does not change the alert status' do + expect { subject }.not_to change { alert.reload.status } + end + end + + context 'when alert is not resolved' do + let(:alert) { create(:alert_management_alert) } + + it 'changes alert status to "resolved"' do + expect { subject }.to change { alert.resolved? }.to(true) + end + end + end + + describe '#ignore' do + subject { alert.ignore } + + let(:alert) { create(:alert_management_alert, :resolved) } + + it 'changes the alert status to ignored' do + expect { subject }.to change { alert.ignored? }.to(true) + end + + it 'resets ended at' do + expect { subject }.to change { alert.reload.ended_at }.to nil + end + end +end |