diff options
author | Cédric Tabin <tabin.cedric@gmail.com> | 2019-09-05 14:50:39 +0000 |
---|---|---|
committer | Kamil Trzciński <ayufan@ayufan.eu> | 2019-09-05 14:50:39 +0000 |
commit | e195e48638dcc56609436e6fcdd9ad3521501798 (patch) | |
tree | f5bef05404ba10a9eeb897f8e9a40725019a8525 /spec | |
parent | be920a6056b1b2bbc376af43d9aef8df92f090f6 (diff) | |
download | gitlab-ce-e195e48638dcc56609436e6fcdd9ad3521501798.tar.gz |
New interruptible attribute supported in YAML parsing.
Since it is not possible to dynamically detect if a job is automatically
cancellable or not, a this new attribute is necessary. Moreover, it let
the maintainer of the repo to adjust the behaviour of the auto cancellation
feature to match exactly what he needs.
Diffstat (limited to 'spec')
-rw-r--r-- | spec/lib/gitlab/ci/yaml_processor_spec.rb | 26 | ||||
-rw-r--r-- | spec/lib/gitlab/import_export/safe_model_attributes.yml | 1 | ||||
-rw-r--r-- | spec/models/concerns/has_status_spec.rb | 12 | ||||
-rw-r--r-- | spec/services/ci/create_pipeline_service_spec.rb | 202 |
4 files changed, 238 insertions, 3 deletions
diff --git a/spec/lib/gitlab/ci/yaml_processor_spec.rb b/spec/lib/gitlab/ci/yaml_processor_spec.rb index 91c559dcd9b..cf496b79a62 100644 --- a/spec/lib/gitlab/ci/yaml_processor_spec.rb +++ b/spec/lib/gitlab/ci/yaml_processor_spec.rb @@ -50,6 +50,32 @@ module Gitlab end end + describe 'interruptible entry' do + describe 'interruptible job' do + let(:config) do + YAML.dump(rspec: { script: 'rspec', interruptible: true }) + end + + it { expect(subject[:interruptible]).to be_truthy } + end + + describe 'interruptible job with default value' do + let(:config) do + YAML.dump(rspec: { script: 'rspec' }) + end + + it { expect(subject).not_to have_key(:interruptible) } + end + + describe 'uninterruptible job' do + let(:config) do + YAML.dump(rspec: { script: 'rspec', interruptible: false }) + end + + it { expect(subject[:interruptible]).to be_falsy } + end + end + describe 'retry entry' do context 'when retry count is specified' do let(:config) do diff --git a/spec/lib/gitlab/import_export/safe_model_attributes.yml b/spec/lib/gitlab/import_export/safe_model_attributes.yml index 1386f8822ce..d34c6d2421b 100644 --- a/spec/lib/gitlab/import_export/safe_model_attributes.yml +++ b/spec/lib/gitlab/import_export/safe_model_attributes.yml @@ -329,6 +329,7 @@ CommitStatus: - failure_reason - scheduled_at - upstream_pipeline_id +- interruptible Ci::Variable: - id - project_id diff --git a/spec/models/concerns/has_status_spec.rb b/spec/models/concerns/has_status_spec.rb index a217dc42537..09fb2fff521 100644 --- a/spec/models/concerns/has_status_spec.rb +++ b/spec/models/concerns/has_status_spec.rb @@ -261,6 +261,18 @@ describe HasStatus do end end + describe '.alive_or_scheduled' do + subject { CommitStatus.alive_or_scheduled } + + %i[running pending preparing created scheduled].each do |status| + it_behaves_like 'containing the job', status + end + + %i[failed success canceled skipped].each do |status| + it_behaves_like 'not containing the job', status + end + end + describe '.created_or_pending' do subject { CommitStatus.created_or_pending } diff --git a/spec/services/ci/create_pipeline_service_spec.rb b/spec/services/ci/create_pipeline_service_spec.rb index fad865a4811..6cec93a53fd 100644 --- a/spec/services/ci/create_pipeline_service_spec.rb +++ b/spec/services/ci/create_pipeline_service_spec.rb @@ -220,11 +220,11 @@ describe Ci::CreatePipelineService do expect(pipeline_on_previous_commit.reload).to have_attributes(status: 'canceled', auto_canceled_by_id: pipeline.id) end - it 'does not cancel running outdated pipelines' do + it 'cancels running outdated pipelines' do pipeline_on_previous_commit.run - execute_service + head_pipeline = execute_service - expect(pipeline_on_previous_commit.reload).to have_attributes(status: 'running', auto_canceled_by_id: nil) + expect(pipeline_on_previous_commit.reload).to have_attributes(status: 'canceled', auto_canceled_by_id: head_pipeline.id) end it 'cancel created outdated pipelines' do @@ -243,6 +243,202 @@ describe Ci::CreatePipelineService do expect(pending_pipeline.reload).to have_attributes(status: 'pending', auto_canceled_by_id: nil) end + + context 'when the interruptible attribute is' do + context 'not defined' do + before do + config = YAML.dump(rspec: { script: 'echo' }) + stub_ci_pipeline_yaml_file(config) + end + + it 'is cancelable' do + pipeline = execute_service + + expect(pipeline.builds.find_by(name: 'rspec').interruptible).to be_nil + end + end + + context 'set to true' do + before do + config = YAML.dump(rspec: { script: 'echo', interruptible: true }) + stub_ci_pipeline_yaml_file(config) + end + + it 'is cancelable' do + pipeline = execute_service + + expect(pipeline.builds.find_by(name: 'rspec').interruptible).to be_truthy + end + end + + context 'set to false' do + before do + config = YAML.dump(rspec: { script: 'echo', interruptible: false }) + stub_ci_pipeline_yaml_file(config) + end + + it 'is not cancelable' do + pipeline = execute_service + + expect(pipeline.builds.find_by(name: 'rspec').interruptible).to be_falsy + end + end + + context 'not defined, but an environment is' do + before do + config = YAML.dump(rspec: { script: 'echo', environment: { name: "review/$CI_COMMIT_REF_NAME" } }) + stub_ci_pipeline_yaml_file(config) + end + + it 'is not cancelable' do + pipeline = execute_service + + expect(pipeline.builds.find_by(name: 'rspec').interruptible).to be_nil + end + end + + context 'overriding the environment definition' do + before do + config = YAML.dump(rspec: { script: 'echo', environment: { name: "review/$CI_COMMIT_REF_NAME" }, interruptible: true }) + stub_ci_pipeline_yaml_file(config) + end + + it 'is cancelable' do + pipeline = execute_service + + expect(pipeline.builds.find_by(name: 'rspec').interruptible).to be_truthy + end + end + end + + context 'interruptible builds' do + before do + stub_ci_pipeline_yaml_file(YAML.dump(config)) + end + + let(:config) do + { + stages: %w[stage1 stage2 stage3 stage4], + + build_1_1: { + stage: 'stage1', + script: 'echo' + }, + build_1_2: { + stage: 'stage1', + script: 'echo', + interruptible: true + }, + build_2_1: { + stage: 'stage2', + script: 'echo', + when: 'delayed', + start_in: '10 minutes' + }, + build_3_1: { + stage: 'stage3', + script: 'echo', + interruptible: false + }, + build_4_1: { + stage: 'stage4', + script: 'echo' + } + } + end + + it 'properly configures interruptible status' do + interruptible_status = + pipeline_on_previous_commit + .builds + .joins(:metadata) + .pluck(:name, 'ci_builds_metadata.interruptible') + + expect(interruptible_status).to contain_exactly( + ['build_1_1', nil], + ['build_1_2', true], + ['build_2_1', nil], + ['build_3_1', false], + ['build_4_1', nil] + ) + end + + context 'when only interruptible builds are running' do + context 'when build marked explicitly by interruptible is running' do + it 'cancels running outdated pipelines' do + pipeline_on_previous_commit + .builds + .find_by_name('build_1_2') + .run! + + pipeline + + expect(pipeline_on_previous_commit.reload).to have_attributes( + status: 'canceled', auto_canceled_by_id: pipeline.id) + end + end + + context 'when build that is not marked as interruptible is running' do + it 'cancels running outdated pipelines' do + pipeline_on_previous_commit + .builds + .find_by_name('build_2_1') + .tap(&:enqueue!) + .run! + + pipeline + + expect(pipeline_on_previous_commit.reload).to have_attributes( + status: 'canceled', auto_canceled_by_id: pipeline.id) + end + end + end + + context 'when an uninterruptible build is running' do + it 'does not cancel running outdated pipelines' do + pipeline_on_previous_commit + .builds + .find_by_name('build_3_1') + .tap(&:enqueue!) + .run! + + pipeline + + expect(pipeline_on_previous_commit.reload).to have_attributes( + status: 'running', auto_canceled_by_id: nil) + end + end + + context 'when an build is waiting on an interruptible scheduled task' do + it 'cancels running outdated pipelines' do + allow(Ci::BuildScheduleWorker).to receive(:perform_at) + + pipeline_on_previous_commit + .builds + .find_by_name('build_2_1') + .schedule! + + pipeline + + expect(pipeline_on_previous_commit.reload).to have_attributes( + status: 'canceled', auto_canceled_by_id: pipeline.id) + end + end + + context 'when a uninterruptible build has finished' do + it 'does not cancel running outdated pipelines' do + pipeline_on_previous_commit + .builds + .find_by_name('build_3_1') + .success! + + pipeline + + expect(pipeline_on_previous_commit.reload).to have_attributes( + status: 'running', auto_canceled_by_id: nil) + end + end + end end context 'auto-cancel disabled' do |