diff options
author | Kamil Trzciński <ayufan@ayufan.eu> | 2018-11-29 14:44:48 +0300 |
---|---|---|
committer | Kamil Trzciński <ayufan@ayufan.eu> | 2018-11-29 18:09:18 +0300 |
commit | 64b1044e7ac22d14a9c17ef773dd075b74df00fa (patch) | |
tree | 7b3c6d04c96ceb9183c745d67c34c8b9d4c8da1b /spec/lib/gitlab/config | |
parent | 6775dafa3816239f6fa1b12428df42572be5a158 (diff) |
ci/config: generalize Config validation into Gitlab::Config:: module
This decouples Ci::Config to provide a common interface for handling
user configuration files.
Diffstat (limited to 'spec/lib/gitlab/config')
-rw-r--r-- | spec/lib/gitlab/config/entry/attributable_spec.rb | 60 | ||||
-rw-r--r-- | spec/lib/gitlab/config/entry/boolean_spec.rb | 34 | ||||
-rw-r--r-- | spec/lib/gitlab/config/entry/configurable_spec.rb | 53 | ||||
-rw-r--r-- | spec/lib/gitlab/config/entry/factory_spec.rb | 95 | ||||
-rw-r--r-- | spec/lib/gitlab/config/entry/simplifiable_spec.rb | 88 | ||||
-rw-r--r-- | spec/lib/gitlab/config/entry/undefined_spec.rb | 41 | ||||
-rw-r--r-- | spec/lib/gitlab/config/entry/unspecified_spec.rb | 32 | ||||
-rw-r--r-- | spec/lib/gitlab/config/entry/validatable_spec.rb | 54 | ||||
-rw-r--r-- | spec/lib/gitlab/config/entry/validator_spec.rb | 55 | ||||
-rw-r--r-- | spec/lib/gitlab/config/loader/yaml_spec.rb | 60 |
10 files changed, 572 insertions, 0 deletions
diff --git a/spec/lib/gitlab/config/entry/attributable_spec.rb b/spec/lib/gitlab/config/entry/attributable_spec.rb new file mode 100644 index 00000000000..abb4fff3ad7 --- /dev/null +++ b/spec/lib/gitlab/config/entry/attributable_spec.rb @@ -0,0 +1,60 @@ +require 'spec_helper' + +describe Gitlab::Config::Entry::Attributable do + let(:node) do + Class.new do + include Gitlab::Config::Entry::Attributable + end + end + + let(:instance) { node.new } + + before do + node.class_eval do + attributes :name, :test + end + end + + context 'when config is a hash' do + before do + allow(instance) + .to receive(:config) + .and_return({ name: 'some name', test: 'some test' }) + end + + it 'returns the value of config' do + expect(instance.name).to eq 'some name' + expect(instance.test).to eq 'some test' + end + + it 'returns no method error for unknown attributes' do + expect { instance.unknown }.to raise_error(NoMethodError) + end + end + + context 'when config is not a hash' do + before do + allow(instance) + .to receive(:config) + .and_return('some test') + end + + it 'returns nil' do + expect(instance.test).to be_nil + end + end + + context 'when method is already defined in a superclass' do + it 'raises an error' do + expectation = expect do + Class.new(String) do + include Gitlab::Config::Entry::Attributable + + attributes :length + end + end + + expectation.to raise_error(ArgumentError, 'Method already defined!') + end + end +end diff --git a/spec/lib/gitlab/config/entry/boolean_spec.rb b/spec/lib/gitlab/config/entry/boolean_spec.rb new file mode 100644 index 00000000000..1b7a3f850ec --- /dev/null +++ b/spec/lib/gitlab/config/entry/boolean_spec.rb @@ -0,0 +1,34 @@ +require 'spec_helper' + +describe Gitlab::Config::Entry::Boolean do + let(:entry) { described_class.new(config) } + + describe 'validations' do + context 'when entry config value is valid' do + let(:config) { false } + + describe '#value' do + it 'returns key value' do + expect(entry.value).to eq false + end + end + + describe '#valid?' do + it 'is valid' do + expect(entry).to be_valid + end + end + end + + context 'when entry value is not valid' do + let(:config) { ['incorrect'] } + + describe '#errors' do + it 'saves errors' do + expect(entry.errors) + .to include 'boolean config should be a boolean value' + end + end + end + end +end diff --git a/spec/lib/gitlab/config/entry/configurable_spec.rb b/spec/lib/gitlab/config/entry/configurable_spec.rb new file mode 100644 index 00000000000..85a7cf1d241 --- /dev/null +++ b/spec/lib/gitlab/config/entry/configurable_spec.rb @@ -0,0 +1,53 @@ +require 'spec_helper' + +describe Gitlab::Config::Entry::Configurable do + let(:entry) do + Class.new(Gitlab::Config::Entry::Node) do + include Gitlab::Config::Entry::Configurable + end + end + + describe 'validations' do + context 'when entry is a hash' do + let(:instance) { entry.new(key: 'value') } + + it 'correctly validates an instance' do + expect(instance).to be_valid + end + end + + context 'when entry is not a hash' do + let(:instance) { entry.new('ls') } + + it 'invalidates the instance' do + expect(instance).not_to be_valid + end + end + end + + describe 'configured entries' do + before do + entry.class_eval do + entry :object, Object, description: 'test object' + end + end + + describe '.nodes' do + it 'has valid nodes' do + expect(entry.nodes).to include :object + end + + it 'creates a node factory' do + expect(entry.nodes[:object]) + .to be_an_instance_of Gitlab::Config::Entry::Factory + end + + it 'returns a duplicated factory object' do + first_factory = entry.nodes[:object] + second_factory = entry.nodes[:object] + + expect(first_factory).not_to be_equal(second_factory) + end + end + end +end diff --git a/spec/lib/gitlab/config/entry/factory_spec.rb b/spec/lib/gitlab/config/entry/factory_spec.rb new file mode 100644 index 00000000000..c29d17eaee3 --- /dev/null +++ b/spec/lib/gitlab/config/entry/factory_spec.rb @@ -0,0 +1,95 @@ +require 'spec_helper' + +describe Gitlab::Config::Entry::Factory do + describe '#create!' do + class Script < Gitlab::Config::Entry::Node + include Gitlab::Config::Entry::Validatable + + validations do + validates :config, array_of_strings: true + end + end + + let(:entry) { Script } + let(:factory) { described_class.new(entry) } + + context 'when setting a concrete value' do + it 'creates entry with valid value' do + entry = factory + .value(%w(ls pwd)) + .create! + + expect(entry.value).to eq %w(ls pwd) + end + + context 'when setting description' do + it 'creates entry with description' do + entry = factory + .value(%w(ls pwd)) + .with(description: 'test description') + .create! + + expect(entry.value).to eq %w(ls pwd) + expect(entry.description).to eq 'test description' + end + end + + context 'when setting key' do + it 'creates entry with custom key' do + entry = factory + .value(%w(ls pwd)) + .with(key: 'test key') + .create! + + expect(entry.key).to eq 'test key' + end + end + + context 'when setting a parent' do + let(:object) { Object.new } + + it 'creates entry with valid parent' do + entry = factory + .value('ls') + .with(parent: object) + .create! + + expect(entry.parent).to eq object + end + end + end + + context 'when not setting a value' do + it 'raises error' do + expect { factory.create! }.to raise_error( + Gitlab::Config::Entry::Factory::InvalidFactory + ) + end + end + + context 'when creating entry with nil value' do + it 'creates an unspecified entry' do + entry = factory + .value(nil) + .create! + + expect(entry) + .not_to be_specified + end + end + + context 'when passing metadata' do + let(:entry) { spy('entry') } + + it 'passes metadata as a parameter' do + factory + .value('some value') + .metadata(some: 'hash') + .create! + + expect(entry).to have_received(:new) + .with('some value', { some: 'hash' }) + end + end + end +end diff --git a/spec/lib/gitlab/config/entry/simplifiable_spec.rb b/spec/lib/gitlab/config/entry/simplifiable_spec.rb new file mode 100644 index 00000000000..bc8387ada67 --- /dev/null +++ b/spec/lib/gitlab/config/entry/simplifiable_spec.rb @@ -0,0 +1,88 @@ +require 'spec_helper' + +describe Gitlab::Config::Entry::Simplifiable do + describe '.strategy' do + let(:entry) do + Class.new(described_class) do + strategy :Something, if: -> { 'condition' } + strategy :DifferentOne, if: -> { 'condition' } + end + end + + it 'defines entry strategies' do + expect(entry.strategies.size).to eq 2 + expect(entry.strategies.map(&:name)) + .to eq %i[Something DifferentOne] + end + end + + describe 'setting strategy by a condition' do + let(:first) { double('first strategy') } + let(:second) { double('second strategy') } + let(:unknown) { double('unknown strategy') } + + before do + stub_const("#{described_class.name}::Something", first) + stub_const("#{described_class.name}::DifferentOne", second) + stub_const("#{described_class.name}::UnknownStrategy", unknown) + end + + context 'when first strategy should be used' do + let(:entry) do + Class.new(described_class) do + strategy :Something, if: -> (arg) { arg == 'something' } + strategy :DifferentOne, if: -> (*) { false } + end + end + + it 'attemps to load a first strategy' do + expect(first).to receive(:new).with('something', anything) + + entry.new('something') + end + end + + context 'when second strategy should be used' do + let(:entry) do + Class.new(described_class) do + strategy :Something, if: -> (arg) { arg == 'something' } + strategy :DifferentOne, if: -> (arg) { arg == 'test' } + end + end + + it 'attemps to load a second strategy' do + expect(second).to receive(:new).with('test', anything) + + entry.new('test') + end + end + + context 'when neither one is a valid strategy' do + let(:entry) do + Class.new(described_class) do + strategy :Something, if: -> (*) { false } + strategy :DifferentOne, if: -> (*) { false } + end + end + + it 'instantiates an unknown strategy' do + expect(unknown).to receive(:new).with('test', anything) + + entry.new('test') + end + end + end + + context 'when a unknown strategy class is not defined' do + let(:entry) do + Class.new(described_class) do + strategy :String, if: -> (*) { true } + end + end + + it 'raises an error when being initialized' do + expect { entry.new('something') } + .to raise_error ArgumentError, /UndefinedStrategy not available!/ + end + end +end diff --git a/spec/lib/gitlab/config/entry/undefined_spec.rb b/spec/lib/gitlab/config/entry/undefined_spec.rb new file mode 100644 index 00000000000..48f9d276c95 --- /dev/null +++ b/spec/lib/gitlab/config/entry/undefined_spec.rb @@ -0,0 +1,41 @@ +require 'spec_helper' + +describe Gitlab::Config::Entry::Undefined do + let(:entry) { described_class.new } + + describe '#leaf?' do + it 'is leaf node' do + expect(entry).to be_leaf + end + end + + describe '#valid?' do + it 'is always valid' do + expect(entry).to be_valid + end + end + + describe '#errors' do + it 'is does not contain errors' do + expect(entry.errors).to be_empty + end + end + + describe '#value' do + it 'returns nil' do + expect(entry.value).to eq nil + end + end + + describe '#relevant?' do + it 'is not relevant' do + expect(entry.relevant?).to eq false + end + end + + describe '#specified?' do + it 'is not defined' do + expect(entry.specified?).to eq false + end + end +end diff --git a/spec/lib/gitlab/config/entry/unspecified_spec.rb b/spec/lib/gitlab/config/entry/unspecified_spec.rb new file mode 100644 index 00000000000..64421824a12 --- /dev/null +++ b/spec/lib/gitlab/config/entry/unspecified_spec.rb @@ -0,0 +1,32 @@ +require 'spec_helper' + +describe Gitlab::Config::Entry::Unspecified do + let(:unspecified) { described_class.new(entry) } + let(:entry) { spy('Entry') } + + describe '#valid?' do + it 'delegates method to entry' do + expect(unspecified.valid?).to eq entry + end + end + + describe '#errors' do + it 'delegates method to entry' do + expect(unspecified.errors).to eq entry + end + end + + describe '#value' do + it 'delegates method to entry' do + expect(unspecified.value).to eq entry + end + end + + describe '#specified?' do + it 'is always false' do + allow(entry).to receive(:specified?).and_return(true) + + expect(unspecified.specified?).to be false + end + end +end diff --git a/spec/lib/gitlab/config/entry/validatable_spec.rb b/spec/lib/gitlab/config/entry/validatable_spec.rb new file mode 100644 index 00000000000..5a8f9766d23 --- /dev/null +++ b/spec/lib/gitlab/config/entry/validatable_spec.rb @@ -0,0 +1,54 @@ +require 'spec_helper' + +describe Gitlab::Config::Entry::Validatable do + let(:entry) do + Class.new(Gitlab::Config::Entry::Node) do + include Gitlab::Config::Entry::Validatable + end + end + + describe '.validator' do + before do + entry.class_eval do + attr_accessor :test_attribute + + validations do + validates :test_attribute, presence: true + end + end + end + + it 'returns validator' do + expect(entry.validator.superclass) + .to be Gitlab::Config::Entry::Validator + end + + it 'returns only one validator to mitigate leaks' do + expect { entry.validator }.not_to change { entry.validator } + end + + context 'when validating entry instance' do + let(:entry_instance) { entry.new('something') } + + context 'when attribute is valid' do + before do + entry_instance.test_attribute = 'valid' + end + + it 'instance of validator is valid' do + expect(entry.validator.new(entry_instance)).to be_valid + end + end + + context 'when attribute is not valid' do + before do + entry_instance.test_attribute = nil + end + + it 'instance of validator is invalid' do + expect(entry.validator.new(entry_instance)).to be_invalid + end + end + end + end +end diff --git a/spec/lib/gitlab/config/entry/validator_spec.rb b/spec/lib/gitlab/config/entry/validator_spec.rb new file mode 100644 index 00000000000..efa16c4265c --- /dev/null +++ b/spec/lib/gitlab/config/entry/validator_spec.rb @@ -0,0 +1,55 @@ +require 'spec_helper' + +describe Gitlab::Config::Entry::Validator do + let(:validator) { Class.new(described_class) } + let(:validator_instance) { validator.new(node) } + let(:node) { spy('node') } + + before do + allow(node).to receive(:key).and_return('node') + allow(node).to receive(:ancestors).and_return([]) + end + + describe 'delegated validator' do + before do + validator.class_eval do + validates :test_attribute, presence: true + end + end + + context 'when node is valid' do + before do + allow(node).to receive(:test_attribute).and_return('valid value') + end + + it 'validates attribute in node' do + expect(node).to receive(:test_attribute) + expect(validator_instance).to be_valid + end + + it 'returns no errors' do + validator_instance.validate + + expect(validator_instance.messages).to be_empty + end + end + + context 'when node is invalid' do + before do + allow(node).to receive(:test_attribute).and_return(nil) + end + + it 'validates attribute in node' do + expect(node).to receive(:test_attribute) + expect(validator_instance).to be_invalid + end + + it 'returns errors' do + validator_instance.validate + + expect(validator_instance.messages) + .to include /test attribute can't be blank/ + end + end + end +end diff --git a/spec/lib/gitlab/config/loader/yaml_spec.rb b/spec/lib/gitlab/config/loader/yaml_spec.rb new file mode 100644 index 00000000000..44c9a3896a8 --- /dev/null +++ b/spec/lib/gitlab/config/loader/yaml_spec.rb @@ -0,0 +1,60 @@ +require 'spec_helper' + +describe Gitlab::Config::Loader::Yaml do + let(:loader) { described_class.new(yml) } + + context 'when yaml syntax is correct' do + let(:yml) { 'image: ruby:2.2' } + + describe '#valid?' do + it 'returns true' do + expect(loader.valid?).to be true + end + end + + describe '#load!' do + it 'returns a valid hash' do + expect(loader.load!).to eq(image: 'ruby:2.2') + end + end + end + + context 'when yaml syntax is incorrect' do + let(:yml) { '// incorrect' } + + describe '#valid?' do + it 'returns false' do + expect(loader.valid?).to be false + end + end + + describe '#load!' do + it 'raises error' do + expect { loader.load! }.to raise_error( + Gitlab::Config::Loader::FormatError, + 'Invalid configuration format' + ) + end + end + end + + context 'when there is an unknown alias' do + let(:yml) { 'steps: *bad_alias' } + + describe '#initialize' do + it 'raises FormatError' do + expect { loader }.to raise_error(Gitlab::Config::Loader::FormatError, 'Unknown alias: bad_alias') + end + end + end + + context 'when yaml config is empty' do + let(:yml) { '' } + + describe '#valid?' do + it 'returns false' do + expect(loader.valid?).to be false + end + end + end +end |