summaryrefslogtreecommitdiff
path: root/spec/support/shared_examples/models/concerns/incident_management/escalatable_shared_examples.rb
diff options
context:
space:
mode:
Diffstat (limited to 'spec/support/shared_examples/models/concerns/incident_management/escalatable_shared_examples.rb')
-rw-r--r--spec/support/shared_examples/models/concerns/incident_management/escalatable_shared_examples.rb246
1 files changed, 246 insertions, 0 deletions
diff --git a/spec/support/shared_examples/models/concerns/incident_management/escalatable_shared_examples.rb b/spec/support/shared_examples/models/concerns/incident_management/escalatable_shared_examples.rb
new file mode 100644
index 00000000000..7b33a95bfa1
--- /dev/null
+++ b/spec/support/shared_examples/models/concerns/incident_management/escalatable_shared_examples.rb
@@ -0,0 +1,246 @@
+# frozen_string_literal: true
+
+RSpec.shared_examples 'a model including Escalatable' do
+ # rubocop:disable Rails/SaveBang -- Usage of factory symbol as argument causes a false-positive
+ let_it_be(:escalatable_factory) { factory_from_class(described_class) }
+ let_it_be(:triggered_escalatable, reload: true) { create(escalatable_factory, :triggered) }
+ let_it_be(:acknowledged_escalatable, reload: true) { create(escalatable_factory, :acknowledged) }
+ let_it_be(:resolved_escalatable, reload: true) { create(escalatable_factory, :resolved) }
+ let_it_be(:ignored_escalatable, reload: true) { create(escalatable_factory, :ignored) }
+
+ context 'validations' do
+ it { is_expected.to validate_presence_of(:status) }
+
+ context 'when status is triggered' do
+ subject { triggered_escalatable }
+
+ context 'when resolved_at is blank' do
+ it { is_expected.to be_valid }
+ end
+
+ context 'when resolved_at is present' do
+ before do
+ triggered_escalatable.resolved_at = Time.current
+ end
+
+ it { is_expected.to be_invalid }
+ end
+ end
+
+ context 'when status is acknowledged' do
+ subject { acknowledged_escalatable }
+
+ context 'when resolved_at is blank' do
+ it { is_expected.to be_valid }
+ end
+
+ context 'when resolved_at is present' do
+ before do
+ acknowledged_escalatable.resolved_at = Time.current
+ end
+
+ it { is_expected.to be_invalid }
+ end
+ end
+
+ context 'when status is resolved' do
+ subject { resolved_escalatable }
+
+ context 'when resolved_at is blank' do
+ before do
+ resolved_escalatable.resolved_at = nil
+ end
+
+ it { is_expected.to be_invalid }
+ end
+
+ context 'when resolved_at is present' do
+ it { is_expected.to be_valid }
+ end
+ end
+
+ context 'when status is ignored' do
+ subject { ignored_escalatable }
+
+ context 'when resolved_at is blank' do
+ it { is_expected.to be_valid }
+ end
+
+ context 'when resolved_at is present' do
+ before do
+ ignored_escalatable.resolved_at = Time.current
+ end
+
+ it { is_expected.to be_invalid }
+ end
+ end
+ end
+
+ context 'scopes' do
+ let(:all_escalatables) { described_class.where(id: [triggered_escalatable, acknowledged_escalatable, ignored_escalatable, resolved_escalatable])}
+
+ describe '.order_status' do
+ subject { all_escalatables.order_status(order) }
+
+ context 'descending' do
+ let(:order) { :desc }
+
+ # Downward arrow in UI always corresponds to default sort
+ it { is_expected.to eq([triggered_escalatable, acknowledged_escalatable, resolved_escalatable, ignored_escalatable]) }
+ end
+
+ context 'ascending' do
+ let(:order) { :asc }
+
+ it { is_expected.to eq([ignored_escalatable, resolved_escalatable, acknowledged_escalatable, triggered_escalatable]) }
+ end
+ end
+ end
+
+ describe '.status_value' do
+ using RSpec::Parameterized::TableSyntax
+
+ where(:status, :status_value) do
+ :triggered | 0
+ :acknowledged | 1
+ :resolved | 2
+ :ignored | 3
+ :unknown | nil
+ end
+
+ with_them do
+ it 'returns status value by its name' do
+ expect(described_class.status_value(status)).to eq(status_value)
+ end
+ end
+ end
+
+ describe '.status_name' do
+ using RSpec::Parameterized::TableSyntax
+
+ where(:raw_status, :status) do
+ 0 | :triggered
+ 1 | :acknowledged
+ 2 | :resolved
+ 3 | :ignored
+ -1 | nil
+ end
+
+ with_them do
+ it 'returns status name by its values' do
+ expect(described_class.status_name(raw_status)).to eq(status)
+ end
+ end
+ end
+
+ describe '#trigger' do
+ subject { escalatable.trigger }
+
+ context 'when escalatable is in triggered state' do
+ let(:escalatable) { triggered_escalatable }
+
+ it 'does not change the escalatable status' do
+ expect { subject }.not_to change { escalatable.reload.status }
+ end
+ end
+
+ context 'when escalatable is not in triggered state' do
+ let(:escalatable) { resolved_escalatable }
+
+ it 'changes the escalatable status to triggered' do
+ expect { subject }.to change { escalatable.triggered? }.to(true)
+ end
+
+ it 'resets resolved at' do
+ expect { subject }.to change { escalatable.reload.resolved_at }.to nil
+ end
+ end
+ end
+
+ describe '#acknowledge' do
+ subject { escalatable.acknowledge }
+
+ let(:escalatable) { resolved_escalatable }
+
+ it 'changes the escalatable status to acknowledged' do
+ expect { subject }.to change { escalatable.acknowledged? }.to(true)
+ end
+
+ it 'resets ended at' do
+ expect { subject }.to change { escalatable.reload.resolved_at }.to nil
+ end
+ end
+
+ describe '#resolve' do
+ let!(:resolved_at) { Time.current }
+
+ subject do
+ escalatable.resolved_at = resolved_at
+ escalatable.resolve
+ end
+
+ context 'when escalatable is already resolved' do
+ let(:escalatable) { resolved_escalatable }
+
+ it 'does not change the escalatable status' do
+ expect { subject }.not_to change { resolved_escalatable.reload.status }
+ end
+ end
+
+ context 'when escalatable is not resolved' do
+ let(:escalatable) { triggered_escalatable }
+
+ it 'changes escalatable status to "resolved"' do
+ expect { subject }.to change { escalatable.resolved? }.to(true)
+ end
+ end
+ end
+
+ describe '#ignore' do
+ subject { escalatable.ignore }
+
+ let(:escalatable) { resolved_escalatable }
+
+ it 'changes the escalatable status to ignored' do
+ expect { subject }.to change { escalatable.ignored? }.to(true)
+ end
+
+ it 'resets ended at' do
+ expect { subject }.to change { escalatable.reload.resolved_at }.to nil
+ end
+ end
+
+ describe '#status_event_for' do
+ using RSpec::Parameterized::TableSyntax
+
+ where(:for_status, :event) do
+ :triggered | :trigger
+ 'triggered' | :trigger
+ :acknowledged | :acknowledge
+ 'acknowledged' | :acknowledge
+ :resolved | :resolve
+ 'resolved' | :resolve
+ :ignored | :ignore
+ 'ignored' | :ignore
+ :unknown | nil
+ nil | nil
+ '' | nil
+ 1 | nil
+ end
+
+ with_them do
+ let(:escalatable) { build(escalatable_factory) }
+
+ it 'returns event by status name' do
+ expect(escalatable.status_event_for(for_status)).to eq(event)
+ end
+ end
+ end
+
+ private
+
+ def factory_from_class(klass)
+ klass.name.underscore.tr('/', '_')
+ end
+end
+# rubocop:enable Rails/SaveBang