summaryrefslogtreecommitdiff
path: root/spec/lib/gitlab/ci/config/entry/root_spec.rb
diff options
context:
space:
mode:
Diffstat (limited to 'spec/lib/gitlab/ci/config/entry/root_spec.rb')
-rw-r--r--spec/lib/gitlab/ci/config/entry/root_spec.rb359
1 files changed, 359 insertions, 0 deletions
diff --git a/spec/lib/gitlab/ci/config/entry/root_spec.rb b/spec/lib/gitlab/ci/config/entry/root_spec.rb
new file mode 100644
index 00000000000..7a252ed675a
--- /dev/null
+++ b/spec/lib/gitlab/ci/config/entry/root_spec.rb
@@ -0,0 +1,359 @@
+require 'spec_helper'
+
+describe Gitlab::Ci::Config::Entry::Root do
+ let(:root) { described_class.new(hash) }
+
+ describe '.nodes' do
+ it 'returns a hash' do
+ expect(described_class.nodes).to be_a(Hash)
+ end
+
+ context 'when filtering all the entry/node names' do
+ it 'contains the expected node names' do
+ expect(described_class.nodes.keys)
+ .to match_array(%i[before_script image services
+ after_script variables cache
+ stages types include default])
+ end
+ end
+ end
+
+ context 'when configuration is valid' do
+ context 'when top-level entries are defined' do
+ let(:hash) do
+ { before_script: %w(ls pwd),
+ image: 'ruby:2.2',
+ default: {},
+ services: ['postgres:9.1', 'mysql:5.5'],
+ variables: { VAR: 'value' },
+ after_script: ['make clean'],
+ stages: %w(build pages),
+ cache: { key: 'k', untracked: true, paths: ['public/'] },
+ rspec: { script: %w[rspec ls] },
+ spinach: { before_script: [], variables: {}, script: 'spinach' } }
+ end
+
+ describe '#compose!' do
+ before do
+ root.compose!
+ end
+
+ it 'creates nodes hash' do
+ expect(root.descendants).to be_an Array
+ end
+
+ it 'creates node object for each entry' do
+ expect(root.descendants.count).to eq 10
+ end
+
+ it 'creates node object using valid class' do
+ expect(root.descendants.first)
+ .to be_an_instance_of Gitlab::Ci::Config::Entry::Default
+ expect(root.descendants.second)
+ .to be_an_instance_of Gitlab::Config::Entry::Unspecified
+ end
+
+ it 'sets correct description for nodes' do
+ expect(root.descendants.first.description)
+ .to eq 'Default configuration for all jobs.'
+ expect(root.descendants.second.description)
+ .to eq 'List of external YAML files to include.'
+ end
+
+ describe '#leaf?' do
+ it 'is not leaf' do
+ expect(root).not_to be_leaf
+ end
+ end
+ end
+
+ context 'when composed' do
+ before do
+ root.compose!
+ end
+
+ describe '#errors' do
+ it 'has no errors' do
+ expect(root.errors).to be_empty
+ end
+ end
+
+ describe '#stages_value' do
+ context 'when stages key defined' do
+ it 'returns array of stages' do
+ expect(root.stages_value).to eq %w[build pages]
+ end
+ end
+
+ context 'when deprecated types key defined' do
+ let(:hash) do
+ { types: %w(test deploy),
+ rspec: { script: 'rspec' } }
+ end
+
+ it 'returns array of types as stages' do
+ expect(root.stages_value).to eq %w[test deploy]
+ end
+ end
+ end
+
+ describe '#jobs_value' do
+ it 'returns jobs configuration' do
+ expect(root.jobs_value).to eq(
+ rspec: { name: :rspec,
+ script: %w[rspec ls],
+ before_script: %w(ls pwd),
+ image: { name: 'ruby:2.2' },
+ services: [{ name: 'postgres:9.1' }, { name: 'mysql:5.5' }],
+ stage: 'test',
+ cache: { key: 'k', untracked: true, paths: ['public/'], policy: 'pull-push' },
+ variables: {},
+ ignore: false,
+ after_script: ['make clean'],
+ only: { refs: %w[branches tags] } },
+ spinach: { name: :spinach,
+ before_script: [],
+ script: %w[spinach],
+ image: { name: 'ruby:2.2' },
+ services: [{ name: 'postgres:9.1' }, { name: 'mysql:5.5' }],
+ stage: 'test',
+ cache: { key: 'k', untracked: true, paths: ['public/'], policy: 'pull-push' },
+ variables: {},
+ ignore: false,
+ after_script: ['make clean'],
+ only: { refs: %w[branches tags] } }
+ )
+ end
+ end
+ end
+ end
+
+ context 'when a mix of top-level and default entries is used' do
+ let(:hash) do
+ { before_script: %w(ls pwd),
+ after_script: ['make clean'],
+ default: {
+ image: 'ruby:2.1',
+ services: ['postgres:9.1', 'mysql:5.5']
+ },
+ variables: { VAR: 'value' },
+ stages: %w(build pages),
+ cache: { key: 'k', untracked: true, paths: ['public/'] },
+ rspec: { script: %w[rspec ls] },
+ spinach: { before_script: [], variables: { VAR: 'AA' }, script: 'spinach' } }
+ end
+
+ context 'when composed' do
+ before do
+ root.compose!
+ end
+
+ describe '#errors' do
+ it 'has no errors' do
+ expect(root.errors).to be_empty
+ end
+ end
+
+ describe '#jobs_value' do
+ it 'returns jobs configuration' do
+ expect(root.jobs_value).to eq(
+ rspec: { name: :rspec,
+ script: %w[rspec ls],
+ before_script: %w(ls pwd),
+ image: { name: 'ruby:2.1' },
+ services: [{ name: 'postgres:9.1' }, { name: 'mysql:5.5' }],
+ stage: 'test',
+ cache: { key: 'k', untracked: true, paths: ['public/'], policy: "pull-push" },
+ variables: {},
+ ignore: false,
+ after_script: ['make clean'],
+ only: { refs: %w[branches tags] } },
+ spinach: { name: :spinach,
+ before_script: [],
+ script: %w[spinach],
+ image: { name: 'ruby:2.1' },
+ services: [{ name: 'postgres:9.1' }, { name: 'mysql:5.5' }],
+ stage: 'test',
+ cache: { key: 'k', untracked: true, paths: ['public/'], policy: "pull-push" },
+ variables: { 'VAR' => 'AA' },
+ ignore: false,
+ after_script: ['make clean'],
+ only: { refs: %w[branches tags] } }
+ )
+ end
+ end
+ end
+ end
+
+ context 'when most of entires not defined' do
+ before do
+ root.compose!
+ end
+
+ let(:hash) do
+ { cache: { key: 'a' }, rspec: { script: %w[ls] } }
+ end
+
+ describe '#nodes' do
+ it 'instantizes all nodes' do
+ expect(root.descendants.count).to eq 10
+ end
+
+ it 'contains unspecified nodes' do
+ expect(root.descendants.first)
+ .not_to be_specified
+ end
+ end
+
+ describe '#variables_value' do
+ it 'returns root value for variables' do
+ expect(root.variables_value).to eq({})
+ end
+ end
+
+ describe '#stages_value' do
+ it 'returns an array of root stages' do
+ expect(root.stages_value).to eq %w[build test deploy]
+ end
+ end
+
+ describe '#cache_value' do
+ it 'returns correct cache definition' do
+ expect(root.cache_value).to eq(key: 'a', policy: 'pull-push')
+ end
+ end
+ end
+
+ context 'when variables resembles script-type job' do
+ before do
+ root.compose!
+ end
+
+ let(:hash) do
+ {
+ variables: { script: "ENV_VALUE" },
+ rspec: { script: "echo Hello World" }
+ }
+ end
+
+ describe '#variables_value' do
+ it 'returns root value for variables' do
+ expect(root.variables_value).to eq("script" => "ENV_VALUE")
+ end
+ end
+
+ describe '#jobs_value' do
+ it 'returns one job' do
+ expect(root.jobs_value.keys).to contain_exactly(:rspec)
+ end
+ end
+ end
+
+ ##
+ # When nodes are specified but not defined, we assume that
+ # configuration is valid, and we assume that entry is simply undefined,
+ # despite the fact, that key is present. See issue #18775 for more
+ # details.
+ #
+ context 'when entires specified but not defined' do
+ before do
+ root.compose!
+ end
+
+ let(:hash) do
+ { variables: nil, rspec: { script: 'rspec' } }
+ end
+
+ describe '#variables_value' do
+ it 'undefined entry returns a root value' do
+ expect(root.variables_value).to eq({})
+ end
+ end
+ end
+ end
+
+ context 'when configuration is not valid' do
+ before do
+ root.compose!
+ end
+
+ context 'when before script is not an array' do
+ let(:hash) do
+ { before_script: 'ls' }
+ end
+
+ describe '#valid?' do
+ it 'is not valid' do
+ expect(root).not_to be_valid
+ end
+ end
+
+ describe '#errors' do
+ it 'reports errors from child nodes' do
+ expect(root.errors)
+ .to include 'before_script config should be an array of strings'
+ end
+ end
+ end
+
+ context 'when job does not have commands' do
+ let(:hash) do
+ { before_script: ['echo 123'], rspec: { stage: 'test' } }
+ end
+
+ describe '#errors' do
+ it 'reports errors about missing script' do
+ expect(root.errors)
+ .to include "root config contains unknown keys: rspec"
+ end
+ end
+ end
+ end
+
+ context 'when value is not a hash' do
+ let(:hash) { [] }
+
+ describe '#valid?' do
+ it 'is not valid' do
+ expect(root).not_to be_valid
+ end
+ end
+
+ describe '#errors' do
+ it 'returns error about invalid type' do
+ expect(root.errors.first).to match /should be a hash/
+ end
+ end
+ end
+
+ describe '#specified?' do
+ it 'is concrete entry that is defined' do
+ expect(root.specified?).to be true
+ end
+ end
+
+ describe '#[]' do
+ before do
+ root.compose!
+ end
+
+ let(:hash) do
+ { cache: { key: 'a' }, rspec: { script: 'ls' } }
+ end
+
+ context 'when entry exists' do
+ it 'returns correct entry' do
+ expect(root[:cache])
+ .to be_an_instance_of Gitlab::Ci::Config::Entry::Cache
+ expect(root[:jobs][:rspec][:script].value).to eq ['ls']
+ end
+ end
+
+ context 'when entry does not exist' do
+ it 'always return unspecified node' do
+ expect(root[:some][:unknown][:node])
+ .not_to be_specified
+ end
+ end
+ end
+end