257 lines
6.2 KiB
Ruby
257 lines
6.2 KiB
Ruby
# frozen_string_literal: true
|
|
|
|
require 'fast_spec_helper'
|
|
|
|
describe Gitlab::Ci::Config::Extendable::Entry do
|
|
describe '.new' do
|
|
context 'when entry key is not included in the context hash' do
|
|
it 'raises error' do
|
|
expect { described_class.new(:test, something: 'something') }
|
|
.to raise_error StandardError, 'Invalid entry key!'
|
|
end
|
|
end
|
|
end
|
|
|
|
describe '#value' do
|
|
it 'reads a hash value from the context' do
|
|
entry = described_class.new(:test, test: 'something')
|
|
|
|
expect(entry.value).to eq 'something'
|
|
end
|
|
end
|
|
|
|
describe '#extensible?' do
|
|
context 'when entry has inheritance defined' do
|
|
it 'is extensible' do
|
|
entry = described_class.new(:test, test: { extends: 'something' })
|
|
|
|
expect(entry).to be_extensible
|
|
end
|
|
end
|
|
|
|
context 'when entry does not have inheritance specified' do
|
|
it 'is not extensible' do
|
|
entry = described_class.new(:test, test: { script: 'something' })
|
|
|
|
expect(entry).not_to be_extensible
|
|
end
|
|
end
|
|
|
|
context 'when entry value is not a hash' do
|
|
it 'is not extensible' do
|
|
entry = described_class.new(:test, test: 'something')
|
|
|
|
expect(entry).not_to be_extensible
|
|
end
|
|
end
|
|
end
|
|
|
|
describe '#extends_keys' do
|
|
context 'when entry is extensible' do
|
|
it 'returns symbolized extends key value' do
|
|
entry = described_class.new(:test, test: { extends: 'something' })
|
|
|
|
expect(entry.extends_keys).to eq [:something]
|
|
end
|
|
end
|
|
|
|
context 'when entry is not extensible' do
|
|
it 'returns nil' do
|
|
entry = described_class.new(:test, test: 'something')
|
|
|
|
expect(entry.extends_keys).to be_nil
|
|
end
|
|
end
|
|
end
|
|
|
|
describe '#ancestors' do
|
|
let(:parent) do
|
|
described_class.new(:test, test: { extends: 'something' })
|
|
end
|
|
|
|
let(:child) do
|
|
described_class.new(:job, { job: { script: 'something' } }, parent)
|
|
end
|
|
|
|
it 'returns ancestors keys' do
|
|
expect(child.ancestors).to eq [:test]
|
|
end
|
|
end
|
|
|
|
describe '#base_hashes!' do
|
|
subject { described_class.new(:test, hash) }
|
|
|
|
context 'when base hash is not extensible' do
|
|
let(:hash) do
|
|
{
|
|
template: { script: 'rspec' },
|
|
test: { extends: 'template' }
|
|
}
|
|
end
|
|
|
|
it 'returns unchanged base hashes' do
|
|
expect(subject.base_hashes!).to eq([{ script: 'rspec' }])
|
|
end
|
|
end
|
|
|
|
context 'when base hash is extensible too' do
|
|
let(:hash) do
|
|
{
|
|
first: { script: 'rspec' },
|
|
second: { extends: 'first' },
|
|
test: { extends: 'second' }
|
|
}
|
|
end
|
|
|
|
it 'extends the base hashes first' do
|
|
expect(subject.base_hashes!).to eq([{ extends: 'first', script: 'rspec' }])
|
|
end
|
|
|
|
it 'mutates original context' do
|
|
subject.base_hashes!
|
|
|
|
expect(hash.fetch(:second)).to eq(extends: 'first', script: 'rspec')
|
|
end
|
|
end
|
|
end
|
|
|
|
describe '#extend!' do
|
|
subject { described_class.new(:test, hash) }
|
|
|
|
context 'when extending a non-hash value' do
|
|
let(:hash) do
|
|
{
|
|
first: 'my value',
|
|
test: { extends: 'first' }
|
|
}
|
|
end
|
|
|
|
it 'raises an error' do
|
|
expect { subject.extend! }
|
|
.to raise_error(described_class::InvalidExtensionError,
|
|
/invalid base hash/)
|
|
end
|
|
end
|
|
|
|
context 'when extending unknown key' do
|
|
let(:hash) do
|
|
{ test: { extends: 'something' } }
|
|
end
|
|
|
|
it 'raises an error' do
|
|
expect { subject.extend! }
|
|
.to raise_error(described_class::InvalidExtensionError,
|
|
/unknown key/)
|
|
end
|
|
end
|
|
|
|
context 'when extending a hash correctly' do
|
|
let(:hash) do
|
|
{
|
|
first: { script: 'my value' },
|
|
second: { extends: 'first' },
|
|
test: { extends: 'second' }
|
|
}
|
|
end
|
|
|
|
let(:result) do
|
|
{
|
|
first: { script: 'my value' },
|
|
second: { extends: 'first', script: 'my value' },
|
|
test: { extends: 'second', script: 'my value' }
|
|
}
|
|
end
|
|
|
|
it 'returns extended part of the hash' do
|
|
expect(subject.extend!).to eq result[:test]
|
|
end
|
|
|
|
it 'mutates original context' do
|
|
subject.extend!
|
|
|
|
expect(hash).to eq result
|
|
end
|
|
end
|
|
|
|
context 'when extending multiple hashes correctly' do
|
|
let(:hash) do
|
|
{
|
|
first: { script: 'my value', image: 'ubuntu' },
|
|
second: { image: 'alpine' },
|
|
test: { extends: %w(first second) }
|
|
}
|
|
end
|
|
|
|
let(:result) do
|
|
{
|
|
first: { script: 'my value', image: 'ubuntu' },
|
|
second: { image: 'alpine' },
|
|
test: { extends: %w(first second), script: 'my value', image: 'alpine' }
|
|
}
|
|
end
|
|
|
|
it 'returns extended part of the hash' do
|
|
expect(subject.extend!).to eq result[:test]
|
|
end
|
|
|
|
it 'mutates original context' do
|
|
subject.extend!
|
|
|
|
expect(hash).to eq result
|
|
end
|
|
end
|
|
|
|
context 'when hash is not extensible' do
|
|
let(:hash) do
|
|
{
|
|
first: { script: 'my value' },
|
|
second: { extends: 'first' },
|
|
test: { value: 'something' }
|
|
}
|
|
end
|
|
|
|
it 'returns original key value' do
|
|
expect(subject.extend!).to eq(value: 'something')
|
|
end
|
|
|
|
it 'does not mutate orignal context' do
|
|
original = hash.deep_dup
|
|
|
|
subject.extend!
|
|
|
|
expect(hash).to eq original
|
|
end
|
|
end
|
|
|
|
context 'when circular depenency gets detected' do
|
|
let(:hash) do
|
|
{ test: { extends: 'test' } }
|
|
end
|
|
|
|
it 'raises an error' do
|
|
expect { subject.extend! }
|
|
.to raise_error(described_class::CircularDependencyError,
|
|
/circular dependency detected/)
|
|
end
|
|
end
|
|
|
|
context 'when nesting level is too deep' do
|
|
before do
|
|
stub_const("#{described_class}::MAX_NESTING_LEVELS", 0)
|
|
end
|
|
|
|
let(:hash) do
|
|
{
|
|
first: { script: 'my value' },
|
|
second: { extends: 'first' },
|
|
test: { extends: 'second' }
|
|
}
|
|
end
|
|
|
|
it 'raises an error' do
|
|
expect { subject.extend! }
|
|
.to raise_error(described_class::NestingTooDeepError)
|
|
end
|
|
end
|
|
end
|
|
end
|