# frozen_string_literal: true require 'spec_helper' describe Gitlab::Ci::Config::Entry::Retry do let(:entry) { described_class.new(config) } shared_context 'when retry value is a numeric', :numeric do let(:config) { max } let(:max) {} end shared_context 'when retry value is a hash', :hash do let(:config) { { max: max, when: public_send(:when) }.compact } let(:when) {} let(:max) {} end describe '#value' do subject(:value) { entry.value } context 'when retry value is a numeric', :numeric do let(:max) { 2 } it 'is returned as a hash with max key' do expect(value).to eq(max: 2) end end context 'when retry value is a hash', :hash do context 'and `when` is a string' do let(:when) { 'unknown_failure' } it 'returns when wrapped in an array' do expect(value).to eq(when: ['unknown_failure']) end end context 'and `when` is an array' do let(:when) { %w[unknown_failure runner_system_failure] } it 'returns when as it was passed' do expect(value).to eq(when: %w[unknown_failure runner_system_failure]) end end end end describe 'validation' do context 'when retry value is correct' do context 'when it is a numeric', :numeric do let(:max) { 2 } it 'is valid' do expect(entry).to be_valid end end context 'when it is a hash', :hash do context 'with max' do let(:max) { 2 } it 'is valid' do expect(entry).to be_valid end end context 'with string when' do let(:when) { 'unknown_failure' } it 'is valid' do expect(entry).to be_valid end end context 'with string when always' do let(:when) { 'always' } it 'is valid' do expect(entry).to be_valid end end context 'with array when' do let(:when) { %w[unknown_failure runner_system_failure] } it 'is valid' do expect(entry).to be_valid end end # Those values are documented at `doc/ci/yaml/README.md`. If any of # those values gets invalid, documentation must be updated. To make # sure this is catched, check explicitly that all of the documented # values are valid. If they are not it means the documentation and this # array must be updated. retry_when_in_documentation = %w[ always unknown_failure script_failure api_failure stuck_or_timeout_failure runner_system_failure missing_dependency_failure runner_unsupported stale_schedule job_execution_timeout archived_failure unmet_prerequisites scheduler_failure data_integrity_failure ].freeze retry_when_in_documentation.each do |reason| context "with when from documentation `#{reason}`" do let(:when) { reason } it 'is valid' do expect(entry).to be_valid end end end ::Ci::Build.failure_reasons.each_key do |reason| context "with when from CommitStatus.failure_reasons `#{reason}`" do let(:when) { reason } it 'is valid' do expect(entry).to be_valid end end end end end context 'when retry value is not correct' do context 'when it is not a numeric nor an array' do let(:config) { true } it 'returns error about invalid type' do expect(entry).not_to be_valid expect(entry.errors).to include 'retry config has to be either an integer or a hash' end end context 'when it is a numeric', :numeric do context 'when it is lower than zero' do let(:max) { -1 } it 'returns error about value too low' do expect(entry).not_to be_valid expect(entry.errors) .to include 'retry config must be greater than or equal to 0' end end context 'when it is not an integer' do let(:max) { 1.5 } it 'returns error about wrong value' do expect(entry).not_to be_valid expect(entry.errors).to include 'retry config has to be either an integer or a hash' end end context 'when the value is too high' do let(:max) { 10 } it 'returns error about value too high' do expect(entry).not_to be_valid expect(entry.errors).to include 'retry config must be less than or equal to 2' end end end context 'when it is a hash', :hash do context 'with unknown keys' do let(:config) { { max: 2, unknown_key: :something, one_more: :key } } it 'returns error about the unknown key' do expect(entry).not_to be_valid expect(entry.errors) .to include 'retry config contains unknown keys: unknown_key, one_more' end end context 'with max lower than zero' do let(:max) { -1 } it 'returns error about value too low' do expect(entry).not_to be_valid expect(entry.errors) .to include 'retry max must be greater than or equal to 0' end end context 'with max not an integer' do let(:max) { 1.5 } it 'returns error about wrong value' do expect(entry).not_to be_valid expect(entry.errors).to include 'retry max must be an integer' end end context 'iwth max too high' do let(:max) { 10 } it 'returns error about value too high' do expect(entry).not_to be_valid expect(entry.errors).to include 'retry max must be less than or equal to 2' end end context 'with when in wrong format' do let(:when) { true } it 'returns error about the wrong format' do expect(entry).not_to be_valid expect(entry.errors).to include 'retry when should be an array of strings or a string' end end context 'with an unknown when string' do let(:when) { 'unknown_reason' } it 'returns error about the wrong format' do expect(entry).not_to be_valid expect(entry.errors).to include 'retry when is not included in the list' end end context 'with an unknown failure reason in a when array' do let(:when) { %w[unknown_reason runner_system_failure] } it 'returns error about the wrong format' do expect(entry).not_to be_valid expect(entry.errors).to include 'retry when contains unknown values: unknown_reason' end end end end end end