diff options
author | GitLab Bot <gitlab-bot@gitlab.com> | 2019-11-17 21:06:14 +0000 |
---|---|---|
committer | GitLab Bot <gitlab-bot@gitlab.com> | 2019-11-17 21:06:14 +0000 |
commit | 77fc73217e022d796ce25c0e684268b1efc680f4 (patch) | |
tree | c5f65b059e3b80037f251e7511533fda9fa478f0 /spec | |
parent | 0a358b68c5a6f3d17c7435714e21fd827fa3cfa8 (diff) | |
download | gitlab-ce-77fc73217e022d796ce25c0e684268b1efc680f4.tar.gz |
Add latest changes from gitlab-org/gitlab@master
Diffstat (limited to 'spec')
-rw-r--r-- | spec/lib/gitlab/ci/build/context/build_spec.rb | 26 | ||||
-rw-r--r-- | spec/lib/gitlab/ci/build/context/global_spec.rb | 25 | ||||
-rw-r--r-- | spec/lib/gitlab/ci/build/policy/variables_spec.rb | 4 | ||||
-rw-r--r-- | spec/lib/gitlab/ci/build/rules/rule_spec.rb | 2 | ||||
-rw-r--r-- | spec/lib/gitlab/ci/build/rules_spec.rb | 12 | ||||
-rw-r--r-- | spec/lib/gitlab/ci/config/entry/default_spec.rb | 2 | ||||
-rw-r--r-- | spec/lib/gitlab/ci/config/entry/root_spec.rb | 9 | ||||
-rw-r--r-- | spec/lib/gitlab/ci/config/entry/workflow_spec.rb | 76 | ||||
-rw-r--r-- | spec/lib/gitlab/ci/pipeline/chain/evaluate_workflow_rules_spec.rb | 60 | ||||
-rw-r--r-- | spec/lib/gitlab/ci/pipeline/seed/build_spec.rb | 6 | ||||
-rw-r--r-- | spec/lib/gitlab/ci/yaml_processor_spec.rb | 102 | ||||
-rw-r--r-- | spec/services/ci/create_pipeline_service/rules_spec.rb | 272 |
12 files changed, 567 insertions, 29 deletions
diff --git a/spec/lib/gitlab/ci/build/context/build_spec.rb b/spec/lib/gitlab/ci/build/context/build_spec.rb new file mode 100644 index 00000000000..3adde213f59 --- /dev/null +++ b/spec/lib/gitlab/ci/build/context/build_spec.rb @@ -0,0 +1,26 @@ +require 'spec_helper' + +describe Gitlab::Ci::Build::Context::Build do + let(:pipeline) { create(:ci_pipeline) } + let(:seed_attributes) { { 'name' => 'some-job' } } + + let(:context) { described_class.new(pipeline, seed_attributes) } + + describe '#variables' do + subject { context.variables } + + it { is_expected.to include('CI_COMMIT_REF_NAME' => 'master') } + it { is_expected.to include('CI_PIPELINE_IID' => pipeline.iid.to_s) } + it { is_expected.to include('CI_PROJECT_PATH' => pipeline.project.full_path) } + it { is_expected.to include('CI_JOB_NAME' => 'some-job') } + it { is_expected.to include('CI_BUILD_REF_NAME' => 'master') } + + context 'without passed build-specific attributes' do + let(:context) { described_class.new(pipeline) } + + it { is_expected.to include('CI_JOB_NAME' => nil) } + it { is_expected.to include('CI_BUILD_REF_NAME' => 'master') } + it { is_expected.to include('CI_PROJECT_PATH' => pipeline.project.full_path) } + end + end +end diff --git a/spec/lib/gitlab/ci/build/context/global_spec.rb b/spec/lib/gitlab/ci/build/context/global_spec.rb new file mode 100644 index 00000000000..6bc8f862779 --- /dev/null +++ b/spec/lib/gitlab/ci/build/context/global_spec.rb @@ -0,0 +1,25 @@ +require 'spec_helper' + +describe Gitlab::Ci::Build::Context::Global do + let(:pipeline) { create(:ci_pipeline) } + let(:yaml_variables) { {} } + + let(:context) { described_class.new(pipeline, yaml_variables: yaml_variables) } + + describe '#variables' do + subject { context.variables } + + it { is_expected.to include('CI_COMMIT_REF_NAME' => 'master') } + it { is_expected.to include('CI_PIPELINE_IID' => pipeline.iid.to_s) } + it { is_expected.to include('CI_PROJECT_PATH' => pipeline.project.full_path) } + + it { is_expected.not_to have_key('CI_JOB_NAME') } + it { is_expected.not_to have_key('CI_BUILD_REF_NAME') } + + context 'with passed yaml variables' do + let(:yaml_variables) { [{ key: 'SUPPORTED', value: 'parsed', public: true }] } + + it { is_expected.to include('SUPPORTED' => 'parsed') } + end + end +end diff --git a/spec/lib/gitlab/ci/build/policy/variables_spec.rb b/spec/lib/gitlab/ci/build/policy/variables_spec.rb index 7140c14facb..66f2cb640b9 100644 --- a/spec/lib/gitlab/ci/build/policy/variables_spec.rb +++ b/spec/lib/gitlab/ci/build/policy/variables_spec.rb @@ -16,7 +16,7 @@ describe Gitlab::Ci::Build::Policy::Variables do let(:seed) do double('build seed', to_resource: ci_build, - scoped_variables_hash: ci_build.scoped_variables_hash + variables: ci_build.scoped_variables_hash ) end @@ -91,7 +91,7 @@ describe Gitlab::Ci::Build::Policy::Variables do let(:seed) do double('bridge seed', to_resource: bridge, - scoped_variables_hash: ci_build.scoped_variables_hash + variables: ci_build.scoped_variables_hash ) end diff --git a/spec/lib/gitlab/ci/build/rules/rule_spec.rb b/spec/lib/gitlab/ci/build/rules/rule_spec.rb index e0f341461fb..04cdaa9d0ae 100644 --- a/spec/lib/gitlab/ci/build/rules/rule_spec.rb +++ b/spec/lib/gitlab/ci/build/rules/rule_spec.rb @@ -6,7 +6,7 @@ describe Gitlab::Ci::Build::Rules::Rule do let(:seed) do double('build seed', to_resource: ci_build, - scoped_variables_hash: ci_build.scoped_variables_hash + variables: ci_build.scoped_variables_hash ) end diff --git a/spec/lib/gitlab/ci/build/rules_spec.rb b/spec/lib/gitlab/ci/build/rules_spec.rb index b783bbb8287..1ebcc4f9414 100644 --- a/spec/lib/gitlab/ci/build/rules_spec.rb +++ b/spec/lib/gitlab/ci/build/rules_spec.rb @@ -9,11 +9,11 @@ describe Gitlab::Ci::Build::Rules do let(:seed) do double('build seed', to_resource: ci_build, - scoped_variables_hash: ci_build.scoped_variables_hash + variables: ci_build.scoped_variables_hash ) end - let(:rules) { described_class.new(rule_list) } + let(:rules) { described_class.new(rule_list, default_when: 'on_success') } describe '.new' do let(:rules_ivar) { rules.instance_variable_get :@rule_list } @@ -62,7 +62,7 @@ describe Gitlab::Ci::Build::Rules do context 'with a specified default when:' do let(:rule_list) { [{ if: '$VAR == null', when: 'always' }] } - let(:rules) { described_class.new(rule_list, 'manual') } + let(:rules) { described_class.new(rule_list, default_when: 'manual') } it 'sets @rule_list to an array of a single rule' do expect(rules_ivar).to be_an(Array) @@ -83,7 +83,7 @@ describe Gitlab::Ci::Build::Rules do it { is_expected.to eq(described_class::Result.new('on_success')) } context 'and when:manual set as the default' do - let(:rules) { described_class.new(rule_list, 'manual') } + let(:rules) { described_class.new(rule_list, default_when: 'manual') } it { is_expected.to eq(described_class::Result.new('manual')) } end @@ -95,7 +95,7 @@ describe Gitlab::Ci::Build::Rules do it { is_expected.to eq(described_class::Result.new('never')) } context 'and when:manual set as the default' do - let(:rules) { described_class.new(rule_list, 'manual') } + let(:rules) { described_class.new(rule_list, default_when: 'manual') } it { is_expected.to eq(described_class::Result.new('never')) } end @@ -159,7 +159,7 @@ describe Gitlab::Ci::Build::Rules do it { is_expected.to eq(described_class::Result.new('never')) } context 'and when:manual set as the default' do - let(:rules) { described_class.new(rule_list, 'manual') } + let(:rules) { described_class.new(rule_list, default_when: 'manual') } it 'does not return the default when:' do expect(subject).to eq(described_class::Result.new('never')) diff --git a/spec/lib/gitlab/ci/config/entry/default_spec.rb b/spec/lib/gitlab/ci/config/entry/default_spec.rb index a0856037340..dad4f408e50 100644 --- a/spec/lib/gitlab/ci/config/entry/default_spec.rb +++ b/spec/lib/gitlab/ci/config/entry/default_spec.rb @@ -13,7 +13,7 @@ describe Gitlab::Ci::Config::Entry::Default do # that we know that we don't want to inherit # as they do not have sense in context of Default let(:ignored_inheritable_columns) do - %i[default include variables stages types] + %i[default include variables stages types workflow] end end diff --git a/spec/lib/gitlab/ci/config/entry/root_spec.rb b/spec/lib/gitlab/ci/config/entry/root_spec.rb index 3877eec8887..43bd53b780f 100644 --- a/spec/lib/gitlab/ci/config/entry/root_spec.rb +++ b/spec/lib/gitlab/ci/config/entry/root_spec.rb @@ -18,9 +18,8 @@ describe Gitlab::Ci::Config::Entry::Root do # # The purpose of `Root` is have only globally defined configuration. expect(described_class.nodes.keys) - .to match_array(%i[before_script image services - after_script variables cache - stages types include default]) + .to match_array(%i[before_script image services after_script + variables cache stages types include default workflow]) end end end @@ -50,7 +49,7 @@ describe Gitlab::Ci::Config::Entry::Root do end it 'creates node object for each entry' do - expect(root.descendants.count).to eq 10 + expect(root.descendants.count).to eq 11 end it 'creates node object using valid class' do @@ -203,7 +202,7 @@ describe Gitlab::Ci::Config::Entry::Root do describe '#nodes' do it 'instantizes all nodes' do - expect(root.descendants.count).to eq 10 + expect(root.descendants.count).to eq 11 end it 'contains unspecified nodes' do diff --git a/spec/lib/gitlab/ci/config/entry/workflow_spec.rb b/spec/lib/gitlab/ci/config/entry/workflow_spec.rb new file mode 100644 index 00000000000..f2832b94bf0 --- /dev/null +++ b/spec/lib/gitlab/ci/config/entry/workflow_spec.rb @@ -0,0 +1,76 @@ +# frozen_string_literal: true + +require 'spec_helper' + +describe Gitlab::Ci::Config::Entry::Workflow do + let(:factory) { Gitlab::Config::Entry::Factory.new(described_class).value(rules_hash) } + let(:config) { factory.create! } + + describe 'validations' do + context 'when work config value is a string' do + let(:rules_hash) { 'build' } + + describe '#valid?' do + it 'is invalid' do + expect(config).not_to be_valid + end + + it 'attaches an error specifying that workflow should point to a hash' do + expect(config.errors).to include('workflow config should be a hash') + end + end + + describe '#value' do + it 'returns the invalid configuration' do + expect(config.value).to eq(rules_hash) + end + end + end + + context 'when work config value is a hash' do + let(:rules_hash) { { rules: [{ if: '$VAR' }] } } + + describe '#valid?' do + it 'is valid' do + expect(config).to be_valid + end + + it 'attaches no errors' do + expect(config.errors).to be_empty + end + end + + describe '#value' do + it 'returns the config' do + expect(config.value).to eq(rules_hash) + end + end + + context 'with an invalid key' do + let(:rules_hash) { { trash: [{ if: '$VAR' }] } } + + describe '#valid?' do + it 'is invalid' do + expect(config).not_to be_valid + end + + it 'attaches an error specifying the unknown key' do + expect(config.errors).to include('workflow config contains unknown keys: trash') + end + end + + describe '#value' do + it 'returns the invalid configuration' do + expect(config.value).to eq(rules_hash) + end + end + end + end + end + + describe '.default' do + it 'is nil' do + expect(described_class.default).to be_nil + end + end +end diff --git a/spec/lib/gitlab/ci/pipeline/chain/evaluate_workflow_rules_spec.rb b/spec/lib/gitlab/ci/pipeline/chain/evaluate_workflow_rules_spec.rb new file mode 100644 index 00000000000..7b76adaf683 --- /dev/null +++ b/spec/lib/gitlab/ci/pipeline/chain/evaluate_workflow_rules_spec.rb @@ -0,0 +1,60 @@ +# frozen_string_literal: true + +require 'spec_helper' + +describe Gitlab::Ci::Pipeline::Chain::EvaluateWorkflowRules do + let(:project) { create(:project) } + let(:user) { create(:user) } + let(:pipeline) { build(:ci_pipeline, project: project) } + + let(:command) do + Gitlab::Ci::Pipeline::Chain::Command.new(project: project, current_user: user) + end + + let(:step) { described_class.new(pipeline, command) } + + describe '#perform!' do + context 'when pipeline has been skipped by workflow configuration' do + before do + allow(step).to receive(:workflow_passed?) + .and_return(false) + + step.perform! + end + + it 'does not save the pipeline' do + expect(pipeline).not_to be_persisted + end + + it 'breaks the chain' do + expect(step.break?).to be true + end + + it 'attaches an error to the pipeline' do + expect(pipeline.errors[:base]).to include('Pipeline filtered out by workflow rules.') + end + end + + context 'when pipeline has not been skipped by workflow configuration' do + before do + allow(step).to receive(:workflow_passed?) + .and_return(true) + + step.perform! + end + + it 'continues the pipeline processing chain' do + expect(step.break?).to be false + end + + it 'does not skip the pipeline' do + expect(pipeline).not_to be_persisted + expect(pipeline).not_to be_skipped + end + + it 'attaches no errors' do + expect(pipeline.errors).to be_empty + end + end + end +end diff --git a/spec/lib/gitlab/ci/pipeline/seed/build_spec.rb b/spec/lib/gitlab/ci/pipeline/seed/build_spec.rb index 62e5fd566f7..53dcb6359fe 100644 --- a/spec/lib/gitlab/ci/pipeline/seed/build_spec.rb +++ b/spec/lib/gitlab/ci/pipeline/seed/build_spec.rb @@ -869,10 +869,4 @@ describe Gitlab::Ci::Pipeline::Seed::Build do end end end - - describe '#scoped_variables_hash' do - subject { seed_build.scoped_variables_hash } - - it { is_expected.to eq(seed_build.to_resource.scoped_variables_hash) } - end end diff --git a/spec/lib/gitlab/ci/yaml_processor_spec.rb b/spec/lib/gitlab/ci/yaml_processor_spec.rb index 35a4749922e..4b1c7483b11 100644 --- a/spec/lib/gitlab/ci/yaml_processor_spec.rb +++ b/spec/lib/gitlab/ci/yaml_processor_spec.rb @@ -268,6 +268,108 @@ module Gitlab end end + describe '#workflow_attributes' do + context 'with disallowed workflow:variables' do + let(:config) do + <<-EOYML + workflow: + rules: + - if: $VAR == "value" + variables: + UNSUPPORTED: "unparsed" + EOYML + end + + it 'parses the workflow:rules configuration' do + expect { subject }.to raise_error(Gitlab::Ci::YamlProcessor::ValidationError, 'workflow config contains unknown keys: variables') + end + end + + context 'with rules and variables' do + let(:config) do + <<-EOYML + variables: + SUPPORTED: "parsed" + + workflow: + rules: + - if: $VAR == "value" + + hello: + script: echo world + EOYML + end + + it 'parses the workflow:rules configuration' do + expect(subject.workflow_attributes[:rules]).to contain_exactly({ if: '$VAR == "value"' }) + end + + it 'parses the root:variables as yaml_variables:' do + expect(subject.workflow_attributes[:yaml_variables]) + .to contain_exactly({ key: 'SUPPORTED', value: 'parsed', public: true }) + end + end + + context 'with rules and no variables' do + let(:config) do + <<-EOYML + workflow: + rules: + - if: $VAR == "value" + + hello: + script: echo world + EOYML + end + + it 'parses the workflow:rules configuration' do + expect(subject.workflow_attributes[:rules]).to contain_exactly({ if: '$VAR == "value"' }) + end + + it 'parses the root:variables as yaml_variables:' do + expect(subject.workflow_attributes[:yaml_variables]).to eq([]) + end + end + + context 'with variables and no rules' do + let(:config) do + <<-EOYML + variables: + SUPPORTED: "parsed" + + hello: + script: echo world + EOYML + end + + it 'parses the workflow:rules configuration' do + expect(subject.workflow_attributes[:rules]).to be_nil + end + + it 'parses the root:variables as yaml_variables:' do + expect(subject.workflow_attributes[:yaml_variables]) + .to contain_exactly({ key: 'SUPPORTED', value: 'parsed', public: true }) + end + end + + context 'with no rules and no variables' do + let(:config) do + <<-EOYML + hello: + script: echo world + EOYML + end + + it 'parses the workflow:rules configuration' do + expect(subject.workflow_attributes[:rules]).to be_nil + end + + it 'parses the root:variables as yaml_variables:' do + expect(subject.workflow_attributes[:yaml_variables]).to eq([]) + end + end + end + describe 'only / except policies validations' do context 'when `only` has an invalid value' do let(:config) { { rspec: { script: "rspec", type: "test", only: only } } } diff --git a/spec/services/ci/create_pipeline_service/rules_spec.rb b/spec/services/ci/create_pipeline_service/rules_spec.rb index 40a3b115cb5..c922266647b 100644 --- a/spec/services/ci/create_pipeline_service/rules_spec.rb +++ b/spec/services/ci/create_pipeline_service/rules_spec.rb @@ -1,16 +1,16 @@ # frozen_string_literal: true - require 'spec_helper' describe Ci::CreatePipelineService do - context 'rules' do - let(:user) { create(:admin) } - let(:ref) { 'refs/heads/master' } - let(:source) { :push } - let(:service) { described_class.new(project, user, { ref: ref }) } - let(:pipeline) { service.execute(source) } - let(:build_names) { pipeline.builds.pluck(:name) } + let(:user) { create(:admin) } + let(:ref) { 'refs/heads/master' } + let(:source) { :push } + let(:project) { create(:project, :repository) } + let(:service) { described_class.new(project, user, { ref: ref }) } + let(:pipeline) { service.execute(source) } + let(:build_names) { pipeline.builds.pluck(:name) } + context 'job:rules' do before do stub_ci_pipeline_yaml_file(config) allow_any_instance_of(Ci::BuildScheduleWorker).to receive(:perform).and_return(true) @@ -41,6 +41,7 @@ describe Ci::CreatePipelineService do start_in: 4 hours EOY end + let(:regular_job) { pipeline.builds.find_by(name: 'regular-job') } let(:rules_job) { pipeline.builds.find_by(name: 'rules-job') } let(:delayed_job) { pipeline.builds.find_by(name: 'delayed-job') } @@ -91,4 +92,259 @@ describe Ci::CreatePipelineService do end end end + + context 'when workflow:rules are used' do + before do + stub_ci_pipeline_yaml_file(config) + end + + context 'with a single regex-matching if: clause' do + let(:config) do + <<-EOY + workflow: + rules: + - if: $CI_COMMIT_REF_NAME =~ /master/ + - if: $CI_COMMIT_REF_NAME =~ /wip$/ + when: never + - if: $CI_COMMIT_REF_NAME =~ /feature/ + + regular-job: + script: 'echo Hello, World!' + EOY + end + + context 'matching the first rule in the list' do + it 'saves the pipeline' do + expect(pipeline).to be_persisted + end + + it 'sets the pipeline state to pending' do + expect(pipeline).to be_pending + end + end + + context 'matching the last rule in the list' do + let(:ref) { 'refs/heads/feature' } + + it 'saves the pipeline' do + expect(pipeline).to be_persisted + end + + it 'sets the pipeline state to pending' do + expect(pipeline).to be_pending + end + end + + context 'matching the when:never rule' do + let(:ref) { 'refs/heads/wip' } + + it 'does not save the pipeline' do + expect(pipeline).not_to be_persisted + end + + it 'attaches errors' do + expect(pipeline.errors[:base]).to include('Pipeline filtered out by workflow rules.') + end + end + + context 'matching no rules in the list' do + let(:ref) { 'refs/heads/fix' } + + it 'does not save the pipeline' do + expect(pipeline).not_to be_persisted + end + + it 'attaches errors' do + expect(pipeline.errors[:base]).to include('Pipeline filtered out by workflow rules.') + end + end + end + + context 'when root variables are used' do + let(:config) do + <<-EOY + variables: + VARIABLE: value + + workflow: + rules: + - if: $VARIABLE + + regular-job: + script: 'echo Hello, World!' + EOY + end + + context 'matching the first rule in the list' do + it 'saves the pipeline' do + expect(pipeline).to be_persisted + end + + it 'sets the pipeline state to pending' do + expect(pipeline).to be_pending + end + end + end + + context 'with a multiple regex-matching if: clause' do + let(:config) do + <<-EOY + workflow: + rules: + - if: $CI_COMMIT_REF_NAME =~ /master/ + - if: $CI_COMMIT_REF_NAME =~ /^feature/ && $CI_COMMIT_REF_NAME =~ /conflict$/ + when: never + - if: $CI_COMMIT_REF_NAME =~ /feature/ + + regular-job: + script: 'echo Hello, World!' + EOY + end + + context 'with partial match' do + let(:ref) { 'refs/heads/feature' } + + it 'saves the pipeline' do + expect(pipeline).to be_persisted + end + + it 'sets the pipeline state to pending' do + expect(pipeline).to be_pending + end + end + + context 'with complete match' do + let(:ref) { 'refs/heads/feature_conflict' } + + it 'does not save the pipeline' do + expect(pipeline).not_to be_persisted + end + + it 'attaches errors' do + expect(pipeline.errors[:base]).to include('Pipeline filtered out by workflow rules.') + end + end + end + + context 'with job rules' do + let(:config) do + <<-EOY + workflow: + rules: + - if: $CI_COMMIT_REF_NAME =~ /master/ + - if: $CI_COMMIT_REF_NAME =~ /feature/ + + regular-job: + script: 'echo Hello, World!' + rules: + - if: $CI_COMMIT_REF_NAME =~ /wip/ + - if: $CI_COMMIT_REF_NAME =~ /feature/ + EOY + end + + context 'where workflow passes and the job fails' do + let(:ref) { 'refs/heads/master' } + + it 'does not save the pipeline' do + expect(pipeline).not_to be_persisted + end + + it 'attaches an error about no job in the pipeline' do + expect(pipeline.errors[:base]).to include('No stages / jobs for this pipeline.') + end + + context 'with workflow:rules shut off' do + before do + stub_feature_flags(workflow_rules: false) + end + + it 'does not save the pipeline' do + expect(pipeline).not_to be_persisted + end + + it 'attaches an error about no job in the pipeline' do + expect(pipeline.errors[:base]).to include('No stages / jobs for this pipeline.') + end + end + end + + context 'where workflow passes and the job passes' do + let(:ref) { 'refs/heads/feature' } + + it 'saves the pipeline' do + expect(pipeline).to be_persisted + end + + it 'sets the pipeline state to pending' do + expect(pipeline).to be_pending + end + + context 'with workflow:rules shut off' do + before do + stub_feature_flags(workflow_rules: false) + end + + it 'saves the pipeline' do + expect(pipeline).to be_persisted + end + + it 'sets the pipeline state to pending' do + expect(pipeline).to be_pending + end + end + end + + context 'where workflow fails and the job fails' do + let(:ref) { 'refs/heads/fix' } + + it 'does not save the pipeline' do + expect(pipeline).not_to be_persisted + end + + it 'attaches an error about workflow rules' do + expect(pipeline.errors[:base]).to include('Pipeline filtered out by workflow rules.') + end + + context 'with workflow:rules shut off' do + before do + stub_feature_flags(workflow_rules: false) + end + + it 'does not save the pipeline' do + expect(pipeline).not_to be_persisted + end + + it 'attaches an error about job rules' do + expect(pipeline.errors[:base]).to include('No stages / jobs for this pipeline.') + end + end + end + + context 'where workflow fails and the job passes' do + let(:ref) { 'refs/heads/wip' } + + it 'does not save the pipeline' do + expect(pipeline).not_to be_persisted + end + + it 'attaches an error about workflow rules' do + expect(pipeline.errors[:base]).to include('Pipeline filtered out by workflow rules.') + end + + context 'with workflow:rules shut off' do + before do + stub_feature_flags(workflow_rules: false) + end + + it 'saves the pipeline' do + expect(pipeline).to be_persisted + end + + it 'sets the pipeline state to pending' do + expect(pipeline).to be_pending + end + end + end + end + end end |