debian-mirror-gitlab/spec/lib/gitlab/ci/config/entry/root_spec.rb

Ignoring revisions in .git-blame-ignore-revs. Click here to bypass and see the normal blame view.

496 lines
15 KiB
Ruby
Raw Normal View History

2019-10-12 21:52:04 +05:30
# frozen_string_literal: true
require 'spec_helper'
2020-07-28 23:09:34 +05:30
RSpec.describe Gitlab::Ci::Config::Entry::Root do
2022-03-02 08:16:31 +05:30
let(:user) {}
let(:project) {}
2023-03-04 22:38:38 +05:30
let(:logger) { Gitlab::Ci::Pipeline::Logger.new(project: project) }
let(:root) { described_class.new(hash, user: user, project: project, logger: logger) }
2016-08-24 12:49:21 +05:30
describe '.nodes' do
2017-08-17 22:00:37 +05:30
it 'returns a hash' do
expect(described_class.nodes).to be_a(Hash)
end
2017-08-17 22:00:37 +05:30
context 'when filtering all the entry/node names' do
it 'contains the expected node names' do
2019-12-26 22:10:19 +05:30
# No inheritable fields should be added to the `Root`
#
# Inheritable configuration can only be added to `default:`
#
# The purpose of `Root` is have only globally defined configuration.
2017-08-17 22:00:37 +05:30
expect(described_class.nodes.keys)
2019-12-26 22:10:19 +05:30
.to match_array(%i[before_script image services after_script
2022-07-16 23:28:13 +05:30
variables cache stages include default workflow])
2017-08-17 22:00:37 +05:30
end
end
end
2017-08-17 22:00:37 +05:30
context 'when configuration is valid' do
2019-09-30 21:07:59 +05:30
context 'when top-level entries are defined' do
2016-08-24 12:49:21 +05:30
let(:hash) do
2020-03-13 15:44:24 +05:30
{
before_script: %w(ls pwd),
2022-06-21 17:19:12 +05:30
image: 'image:1.0',
2019-09-30 21:07:59 +05:30
default: {},
2016-08-24 12:49:21 +05:30
services: ['postgres:9.1', 'mysql:5.5'],
2022-11-25 23:54:43 +05:30
variables: {
VAR: 'root',
VAR2: { value: 'val 2', description: 'this is var 2' },
2023-03-04 22:38:38 +05:30
VAR3: { value: 'val3', options: %w[val3 val4 val5], description: 'this is var 3 and some options' }
2022-11-25 23:54:43 +05:30
},
2016-08-24 12:49:21 +05:30
after_script: ['make clean'],
2020-03-13 15:44:24 +05:30
stages: %w(build pages release),
2016-09-13 17:45:13 +05:30
cache: { key: 'k', untracked: true, paths: ['public/'] },
rspec: { script: %w[rspec ls] },
2020-03-13 15:44:24 +05:30
spinach: { before_script: [], variables: {}, script: 'spinach' },
release: {
stage: 'release',
before_script: [],
after_script: [],
2020-04-08 14:13:33 +05:30
variables: { 'VAR' => 'job' },
2020-03-13 15:44:24 +05:30
script: ["make changelog | tee release_changelog.txt"],
release: {
tag_name: 'v0.06',
name: "Release $CI_TAG_NAME",
description: "./release_changelog.txt"
}
}
}
2016-08-24 12:49:21 +05:30
end
2016-09-29 09:46:39 +05:30
describe '#compose!' do
2017-09-10 17:25:29 +05:30
before do
2019-09-30 21:07:59 +05:30
root.compose!
2017-09-10 17:25:29 +05:30
end
2016-08-24 12:49:21 +05:30
it 'creates nodes hash' do
2019-09-30 21:07:59 +05:30
expect(root.descendants).to be_an Array
2016-08-24 12:49:21 +05:30
end
2016-08-24 12:49:21 +05:30
it 'creates node object for each entry' do
2019-12-26 22:10:19 +05:30
expect(root.descendants.count).to eq 11
2016-08-24 12:49:21 +05:30
end
it 'creates node object using valid class' do
2019-09-30 21:07:59 +05:30
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
2016-08-24 12:49:21 +05:30
end
it 'sets correct description for nodes' do
2019-09-30 21:07:59 +05:30
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.'
2016-08-24 12:49:21 +05:30
end
2021-02-22 17:27:13 +05:30
it 'sets correct variables value' do
2022-11-25 23:54:43 +05:30
expect(root.variables_value).to eq('VAR' => 'root', 'VAR2' => 'val 2', 'VAR3' => 'val3')
2021-02-22 17:27:13 +05:30
end
2016-09-13 17:45:13 +05:30
describe '#leaf?' do
it 'is not leaf' do
2019-09-30 21:07:59 +05:30
expect(root).not_to be_leaf
2016-09-13 17:45:13 +05:30
end
end
end
2016-09-29 09:46:39 +05:30
context 'when composed' do
2017-09-10 17:25:29 +05:30
before do
2019-09-30 21:07:59 +05:30
root.compose!
2017-09-10 17:25:29 +05:30
end
2016-09-29 09:46:39 +05:30
describe '#errors' do
it 'has no errors' do
2019-09-30 21:07:59 +05:30
expect(root.errors).to be_empty
2016-08-24 12:49:21 +05:30
end
end
2017-08-17 22:00:37 +05:30
describe '#stages_value' do
2016-08-24 12:49:21 +05:30
context 'when stages key defined' do
it 'returns array of stages' do
2020-03-13 15:44:24 +05:30
expect(root.stages_value).to eq %w[build pages release]
2016-08-24 12:49:21 +05:30
end
end
end
2017-08-17 22:00:37 +05:30
describe '#jobs_value' do
2016-09-13 17:45:13 +05:30
it 'returns jobs configuration' do
2020-03-13 15:44:24 +05:30
expect(root.jobs_value.keys).to eq([:rspec, :spinach, :release])
expect(root.jobs_value[:rspec]).to eq(
{ name: :rspec,
2022-10-11 01:57:18 +05:30
script: %w[rspec ls],
before_script: %w(ls pwd),
image: { name: 'image:1.0' },
services: [{ name: 'postgres:9.1' }, { name: 'mysql:5.5' }],
stage: 'test',
2023-03-17 16:20:25 +05:30
cache: [{ key: 'k', untracked: true, paths: ['public/'], policy: 'pull-push', when: 'on_success',
unprotect: false }],
2022-10-11 01:57:18 +05:30
job_variables: {},
root_variables_inheritance: true,
ignore: false,
after_script: ['make clean'],
only: { refs: %w[branches tags] },
scheduling_type: :stage }
2020-03-13 15:44:24 +05:30
)
expect(root.jobs_value[:spinach]).to eq(
{ name: :spinach,
2022-10-11 01:57:18 +05:30
before_script: [],
script: %w[spinach],
image: { name: 'image:1.0' },
services: [{ name: 'postgres:9.1' }, { name: 'mysql:5.5' }],
stage: 'test',
2023-03-17 16:20:25 +05:30
cache: [{ key: 'k', untracked: true, paths: ['public/'], policy: 'pull-push', when: 'on_success',
unprotect: false }],
2022-10-11 01:57:18 +05:30
job_variables: {},
root_variables_inheritance: true,
ignore: false,
after_script: ['make clean'],
only: { refs: %w[branches tags] },
scheduling_type: :stage }
2020-03-13 15:44:24 +05:30
)
expect(root.jobs_value[:release]).to eq(
{ name: :release,
2022-10-11 01:57:18 +05:30
stage: 'release',
before_script: [],
script: ["make changelog | tee release_changelog.txt"],
release: { name: "Release $CI_TAG_NAME", tag_name: 'v0.06', description: "./release_changelog.txt" },
image: { name: "image:1.0" },
services: [{ name: "postgres:9.1" }, { name: "mysql:5.5" }],
2023-03-17 16:20:25 +05:30
cache: [{ key: "k", untracked: true, paths: ["public/"], policy: "pull-push", when: 'on_success',
unprotect: false }],
2022-10-11 01:57:18 +05:30
only: { refs: %w(branches tags) },
job_variables: { 'VAR' => { value: 'job' } },
root_variables_inheritance: true,
after_script: [],
ignore: false,
scheduling_type: :stage }
2016-09-13 17:45:13 +05:30
)
end
end
end
end
2019-09-30 21:07:59 +05:30
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: {
2022-06-21 17:19:12 +05:30
image: 'image:1.0',
2019-09-30 21:07:59 +05:30
services: ['postgres:9.1', 'mysql:5.5']
},
2020-04-08 14:13:33 +05:30
variables: { VAR: 'root' },
2019-09-30 21:07:59 +05:30
stages: %w(build pages),
cache: { key: 'k', untracked: true, paths: ['public/'] },
rspec: { script: %w[rspec ls] },
2020-04-08 14:13:33 +05:30
spinach: { before_script: [], variables: { VAR: 'job' }, script: 'spinach' } }
2019-09-30 21:07:59 +05:30
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,
2022-10-11 01:57:18 +05:30
script: %w[rspec ls],
before_script: %w(ls pwd),
image: { name: 'image:1.0' },
services: [{ name: 'postgres:9.1' }, { name: 'mysql:5.5' }],
stage: 'test',
2023-03-17 16:20:25 +05:30
cache: [{ key: 'k', untracked: true, paths: ['public/'], policy: 'pull-push', when: 'on_success', unprotect: false }],
2022-10-11 01:57:18 +05:30
job_variables: {},
root_variables_inheritance: true,
ignore: false,
after_script: ['make clean'],
only: { refs: %w[branches tags] },
scheduling_type: :stage },
2019-09-30 21:07:59 +05:30
spinach: { name: :spinach,
2022-10-11 01:57:18 +05:30
before_script: [],
script: %w[spinach],
image: { name: 'image:1.0' },
services: [{ name: 'postgres:9.1' }, { name: 'mysql:5.5' }],
stage: 'test',
2023-03-17 16:20:25 +05:30
cache: [{ key: 'k', untracked: true, paths: ['public/'], policy: 'pull-push', when: 'on_success', unprotect: false }],
2022-10-11 01:57:18 +05:30
job_variables: { 'VAR' => { value: 'job' } },
root_variables_inheritance: true,
ignore: false,
after_script: ['make clean'],
only: { refs: %w[branches tags] },
scheduling_type: :stage }
2019-09-30 21:07:59 +05:30
)
end
end
2023-03-04 22:38:38 +05:30
it 'tracks log entries' do
expect(logger.observations_hash).to match(
a_hash_including(
'config_root_compose_jobs_factory_duration_s' => a_kind_of(Numeric)
)
)
end
2019-09-30 21:07:59 +05:30
end
end
2016-08-24 12:49:21 +05:30
context 'when most of entires not defined' do
2017-09-10 17:25:29 +05:30
before do
2019-09-30 21:07:59 +05:30
root.compose!
2017-09-10 17:25:29 +05:30
end
2016-09-29 09:46:39 +05:30
let(:hash) do
{ cache: { key: 'a' }, rspec: { script: %w[ls] } }
end
2016-08-24 12:49:21 +05:30
describe '#nodes' do
it 'instantizes all nodes' do
2019-12-26 22:10:19 +05:30
expect(root.descendants.count).to eq 11
2016-08-24 12:49:21 +05:30
end
2016-09-29 09:46:39 +05:30
it 'contains unspecified nodes' do
2019-09-30 21:07:59 +05:30
expect(root.descendants.first)
2017-08-17 22:00:37 +05:30
.not_to be_specified
2016-08-24 12:49:21 +05:30
end
end
2017-08-17 22:00:37 +05:30
describe '#variables_value' do
2019-09-30 21:07:59 +05:30
it 'returns root value for variables' do
expect(root.variables_value).to eq({})
2016-08-24 12:49:21 +05:30
end
end
2017-08-17 22:00:37 +05:30
describe '#stages_value' do
2019-09-30 21:07:59 +05:30
it 'returns an array of root stages' do
2019-12-21 20:55:43 +05:30
expect(root.stages_value).to eq %w[.pre build test deploy .post]
end
end
2017-08-17 22:00:37 +05:30
describe '#cache_value' do
2016-08-24 12:49:21 +05:30
it 'returns correct cache definition' do
2023-03-17 16:20:25 +05:30
expect(root.cache_value).to eq([key: 'a', policy: 'pull-push', when: 'on_success', unprotect: false])
2021-04-17 20:07:23 +05:30
end
end
2019-09-30 21:07:59 +05:30
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)
2016-08-24 12:49:21 +05:30
end
end
end
##
# When nodes are specified but not defined, we assume that
2018-12-13 13:39:08 +05:30
# configuration is valid, and we assume that entry is simply undefined,
2016-08-24 12:49:21 +05:30
# despite the fact, that key is present. See issue #18775 for more
# details.
#
2020-03-13 15:44:24 +05:30
context 'when entries are specified but not defined' do
2017-09-10 17:25:29 +05:30
before do
2019-09-30 21:07:59 +05:30
root.compose!
2017-09-10 17:25:29 +05:30
end
2016-09-29 09:46:39 +05:30
let(:hash) do
{ variables: nil, rspec: { script: 'rspec' } }
end
2016-08-24 12:49:21 +05:30
2017-08-17 22:00:37 +05:30
describe '#variables_value' do
2019-09-30 21:07:59 +05:30
it 'undefined entry returns a root value' do
expect(root.variables_value).to eq({})
end
end
end
2023-01-13 00:05:48 +05:30
2023-03-04 22:38:38 +05:30
context 'when variables have `options` data' do
before do
root.compose!
end
context 'and the value is in the `options` array' do
let(:hash) do
{
variables: { 'VAR' => { value: 'val1', options: %w[val1 val2] } },
rspec: { script: 'bin/rspec' }
}
end
it 'returns correct value' do
expect(root.variables_entry.value_with_data).to eq(
'VAR' => { value: 'val1' }
)
expect(root.variables_value).to eq('VAR' => 'val1')
end
end
context 'and the value is not in the `options` array' do
let(:hash) do
{
variables: { 'VAR' => { value: 'val', options: %w[val1 val2] } },
rspec: { script: 'bin/rspec' }
}
end
it 'returns an error' do
expect(root.errors).to contain_exactly('variables:var config value must be present in options')
end
end
end
2023-01-13 00:05:48 +05:30
context 'when variables have "expand" data' do
let(:hash) do
{
variables: { 'VAR1' => 'val 1',
'VAR2' => { value: 'val 2', expand: false },
'VAR3' => { value: 'val 3', expand: true } },
rspec: { script: 'rspec' }
}
end
before do
root.compose!
end
it 'returns correct value' do
expect(root.variables_entry.value_with_data).to eq(
'VAR1' => { value: 'val 1' },
'VAR2' => { value: 'val 2', raw: true },
'VAR3' => { value: 'val 3', raw: false }
)
expect(root.variables_value).to eq(
'VAR1' => 'val 1',
'VAR2' => 'val 2',
'VAR3' => 'val 3'
)
end
end
end
2017-08-17 22:00:37 +05:30
context 'when configuration is not valid' do
2017-09-10 17:25:29 +05:30
before do
2019-09-30 21:07:59 +05:30
root.compose!
2017-09-10 17:25:29 +05:30
end
2022-04-04 11:22:00 +05:30
context 'when before script is a number' do
2017-08-17 22:00:37 +05:30
let(:hash) do
2022-04-04 11:22:00 +05:30
{ before_script: 123 }
2017-08-17 22:00:37 +05:30
end
2017-08-17 22:00:37 +05:30
describe '#valid?' do
it 'is not valid' do
2019-09-30 21:07:59 +05:30
expect(root).not_to be_valid
2017-08-17 22:00:37 +05:30
end
end
2017-08-17 22:00:37 +05:30
describe '#errors' do
it 'reports errors from child nodes' do
2019-09-30 21:07:59 +05:30
expect(root.errors)
2022-04-04 11:22:00 +05:30
.to include 'before_script config should be a string or a nested array of strings up to 10 levels deep'
2017-08-17 22:00:37 +05:30
end
end
end
2017-08-17 22:00:37 +05:30
context 'when job does not have commands' do
let(:hash) do
{ before_script: ['echo 123'], rspec: { stage: 'test' } }
end
describe '#errors' do
2020-11-24 15:15:51 +05:30
it 'reports errors about missing script or trigger' do
2019-09-30 21:07:59 +05:30
expect(root.errors)
2020-11-24 15:15:51 +05:30
.to include 'jobs rspec config should implement a script: or a trigger: keyword'
2017-08-17 22:00:37 +05:30
end
end
end
2022-10-11 01:57:18 +05:30
context 'when a variable has an invalid data key' do
let(:hash) do
{ variables: { VAR1: { invalid: 'hello' } }, rspec: { script: 'hello' } }
end
describe '#errors' do
it 'reports errors about the invalid variable' do
expect(root.errors)
.to include /var1 config uses invalid data keys: invalid/
end
end
end
end
context 'when value is not a hash' do
let(:hash) { [] }
describe '#valid?' do
it 'is not valid' do
2019-09-30 21:07:59 +05:30
expect(root).not_to be_valid
end
end
2016-08-24 12:49:21 +05:30
describe '#errors' do
it 'returns error about invalid type' do
2019-09-30 21:07:59 +05:30
expect(root.errors.first).to match /should be a hash/
2016-08-24 12:49:21 +05:30
end
end
end
2016-09-13 17:45:13 +05:30
describe '#specified?' do
2016-08-24 12:49:21 +05:30
it 'is concrete entry that is defined' do
2019-09-30 21:07:59 +05:30
expect(root.specified?).to be true
2016-08-24 12:49:21 +05:30
end
end
2016-09-29 09:46:39 +05:30
describe '#[]' do
2017-09-10 17:25:29 +05:30
before do
2019-09-30 21:07:59 +05:30
root.compose!
2017-09-10 17:25:29 +05:30
end
2016-09-29 09:46:39 +05:30
let(:hash) do
{ cache: { key: 'a' }, rspec: { script: 'ls' } }
end
2017-08-17 22:00:37 +05:30
context 'when entry exists' do
2016-09-29 09:46:39 +05:30
it 'returns correct entry' do
2019-09-30 21:07:59 +05:30
expect(root[:cache])
2021-06-08 01:23:25 +05:30
.to be_an_instance_of Gitlab::Ci::Config::Entry::Caches
2019-09-30 21:07:59 +05:30
expect(root[:jobs][:rspec][:script].value).to eq ['ls']
2016-09-29 09:46:39 +05:30
end
end
2017-08-17 22:00:37 +05:30
context 'when entry does not exist' do
2016-09-29 09:46:39 +05:30
it 'always return unspecified node' do
2019-09-30 21:07:59 +05:30
expect(root[:some][:unknown][:node])
2016-09-29 09:46:39 +05:30
.not_to be_specified
end
end
end
end