247 lines
6.5 KiB
Ruby
247 lines
6.5 KiB
Ruby
|
# 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
|