From 571a934f29bee7af9569176e62e5376b471e35fb Mon Sep 17 00:00:00 2001 From: Shinya Maeda Date: Mon, 24 Sep 2018 13:12:11 +0900 Subject: Fix spec. Create scheduled status entry for pipeline --- spec/lib/gitlab/ci/status/pipeline/factory_spec.rb | 35 +++++++--------------- spec/models/concerns/has_status_spec.rb | 2 +- 2 files changed, 11 insertions(+), 26 deletions(-) (limited to 'spec') diff --git a/spec/lib/gitlab/ci/status/pipeline/factory_spec.rb b/spec/lib/gitlab/ci/status/pipeline/factory_spec.rb index defb3fdc0df..8e3d4464898 100644 --- a/spec/lib/gitlab/ci/status/pipeline/factory_spec.rb +++ b/spec/lib/gitlab/ci/status/pipeline/factory_spec.rb @@ -11,8 +11,7 @@ describe Gitlab::Ci::Status::Pipeline::Factory do end context 'when pipeline has a core status' do - (HasStatus::AVAILABLE_STATUSES - [HasStatus::BLOCKED_STATUS]) - .each do |simple_status| + HasStatus::AVAILABLE_STATUSES.each do |simple_status| context "when core status is #{simple_status}" do let(:pipeline) { create(:ci_pipeline, status: simple_status) } @@ -24,8 +23,15 @@ describe Gitlab::Ci::Status::Pipeline::Factory do expect(factory.core_status).to be_a expected_status end - it 'does not match extended statuses' do - expect(factory.extended_statuses).to be_empty + if HasStatus::BLOCKED_STATUS.include?(simple_status) + it 'matches a correct extended statuses' do + expect(factory.extended_statuses) + .to eq [Gitlab::Ci::Status::Pipeline::Blocked] + end + else + it 'does not match extended statuses' do + expect(factory.extended_statuses).to be_empty + end end it "fabricates a core status #{simple_status}" do @@ -40,27 +46,6 @@ describe Gitlab::Ci::Status::Pipeline::Factory do end end end - - context "when core status is manual" do - let(:pipeline) { create(:ci_pipeline, status: :manual) } - - it "matches manual core status" do - expect(factory.core_status) - .to be_a Gitlab::Ci::Status::Manual - end - - it 'matches a correct extended statuses' do - expect(factory.extended_statuses) - .to eq [Gitlab::Ci::Status::Pipeline::Blocked] - end - - it 'extends core status with common pipeline methods' do - expect(status).to have_details - expect(status).not_to have_action - expect(status.details_path) - .to include "pipelines/#{pipeline.id}" - end - end end context 'when pipeline has warnings' do diff --git a/spec/models/concerns/has_status_spec.rb b/spec/models/concerns/has_status_spec.rb index 6866b43432c..fe9a89e8806 100644 --- a/spec/models/concerns/has_status_spec.rb +++ b/spec/models/concerns/has_status_spec.rb @@ -300,7 +300,7 @@ describe HasStatus do describe '::BLOCKED_STATUS' do it 'is a status manual' do - expect(described_class::BLOCKED_STATUS).to eq 'manual' + expect(described_class::BLOCKED_STATUS).to eq %w[manual scheduled] end end end -- cgit v1.2.1 From 173300370a77f84b06755498b488cb68547eb1b3 Mon Sep 17 00:00:00 2001 From: Shinya Maeda Date: Wed, 26 Sep 2018 14:37:11 +0900 Subject: Fix retry_build_service_spec --- spec/services/ci/retry_build_service_spec.rb | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) (limited to 'spec') diff --git a/spec/services/ci/retry_build_service_spec.rb b/spec/services/ci/retry_build_service_spec.rb index 951c0b16a68..a945a769d4e 100644 --- a/spec/services/ci/retry_build_service_spec.rb +++ b/spec/services/ci/retry_build_service_spec.rb @@ -26,7 +26,8 @@ describe Ci::RetryBuildService do erased_at auto_canceled_by job_artifacts job_artifacts_archive job_artifacts_metadata job_artifacts_trace job_artifacts_junit job_artifacts_sast job_artifacts_dependency_scanning - job_artifacts_container_scanning job_artifacts_dast].freeze + job_artifacts_container_scanning job_artifacts_dast + scheduled_at].freeze IGNORE_ACCESSORS = %i[type lock_version target_url base_tags trace_sections @@ -43,7 +44,8 @@ describe Ci::RetryBuildService do create(:ci_build, :failed, :expired, :erased, :queued, :coverage, :tags, :allowed_to_fail, :on_tag, :triggered, :teardown_environment, description: 'my-job', stage: 'test', stage_id: stage.id, - pipeline: pipeline, auto_canceled_by: another_pipeline) + pipeline: pipeline, auto_canceled_by: another_pipeline, + scheduled_at: 10.seconds.since) end before do -- cgit v1.2.1 From 6eee8d2d53a327051515ec18953726fd5606c000 Mon Sep 17 00:00:00 2001 From: Shinya Maeda Date: Wed, 26 Sep 2018 15:13:39 +0900 Subject: Fix process build service spec --- spec/factories/ci/builds.rb | 9 ++++ spec/services/ci/enqueue_build_service_spec.rb | 16 ------- spec/services/ci/process_build_service_spec.rb | 61 ++++++++++++++++++++++++++ 3 files changed, 70 insertions(+), 16 deletions(-) delete mode 100644 spec/services/ci/enqueue_build_service_spec.rb create mode 100644 spec/services/ci/process_build_service_spec.rb (limited to 'spec') diff --git a/spec/factories/ci/builds.rb b/spec/factories/ci/builds.rb index 9813190925b..aea6b5d6b2f 100644 --- a/spec/factories/ci/builds.rb +++ b/spec/factories/ci/builds.rb @@ -98,6 +98,15 @@ FactoryBot.define do success end + trait :schedulable do + self.when 'delayed' + options start_in: '1 minute' + end + + trait :actionable do + self.when 'manual' + end + trait :retried do retried true end diff --git a/spec/services/ci/enqueue_build_service_spec.rb b/spec/services/ci/enqueue_build_service_spec.rb deleted file mode 100644 index e41b8e4800b..00000000000 --- a/spec/services/ci/enqueue_build_service_spec.rb +++ /dev/null @@ -1,16 +0,0 @@ -# frozen_string_literal: true -require 'spec_helper' - -describe Ci::EnqueueBuildService, '#execute' do - let(:user) { create(:user) } - let(:project) { create(:project) } - let(:ci_build) { create(:ci_build, :created) } - - subject { described_class.new(project, user).execute(ci_build) } - - it 'enqueues the build' do - subject - - expect(ci_build.pending?).to be_truthy - end -end diff --git a/spec/services/ci/process_build_service_spec.rb b/spec/services/ci/process_build_service_spec.rb new file mode 100644 index 00000000000..74a81af75f2 --- /dev/null +++ b/spec/services/ci/process_build_service_spec.rb @@ -0,0 +1,61 @@ +# frozen_string_literal: true +require 'spec_helper' + +describe Ci::ProcessBuildService, '#execute' do + let(:user) { create(:user) } + let(:project) { create(:project) } + + subject { described_class.new(project, user).execute(build) } + + before do + project.add_maintainer(user) + end + + context 'when build is schedulable' do + let(:build) { create(:ci_build, :created, :schedulable, user: user, project: project) } + + context 'when ci_enable_scheduled_build feature flag is enabled' do + before do + stub_feature_flags(ci_enable_scheduled_build: true) + end + + it 'schedules the build' do + subject + + expect(build).to be_scheduled + end + end + + context 'when ci_enable_scheduled_build feature flag is disabled' do + before do + stub_feature_flags(ci_enable_scheduled_build: false) + end + + it 'enqueues the build' do + subject + + expect(build).to be_pending + end + end + end + + context 'when build is actionable' do + let(:build) { create(:ci_build, :created, :actionable, user: user, project: project) } + + it 'actionizes the build' do + subject + + expect(build).to be_manual + end + end + + context 'when build does not have any actions' do + let(:build) { create(:ci_build, :created, user: user, project: project) } + + it 'enqueues the build' do + subject + + expect(build).to be_pending + end + end +end -- cgit v1.2.1 From 9266cd5e8b543ab356df3fba78bf9e01536a180d Mon Sep 17 00:00:00 2001 From: Shinya Maeda Date: Wed, 26 Sep 2018 19:12:48 +0900 Subject: Add unit tests for Ci::Build. Fix validation on state transition --- spec/factories/ci/builds.rb | 12 ++++ spec/models/ci/build_spec.rb | 153 +++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 165 insertions(+) (limited to 'spec') diff --git a/spec/factories/ci/builds.rb b/spec/factories/ci/builds.rb index aea6b5d6b2f..73fa16fe6bf 100644 --- a/spec/factories/ci/builds.rb +++ b/spec/factories/ci/builds.rb @@ -70,6 +70,18 @@ FactoryBot.define do status 'created' end + trait :scheduled do + schedulable + status 'scheduled' + scheduled_at 1.minute.since + end + + trait :expired_scheduled do + schedulable + status 'scheduled' + scheduled_at 1.minute.ago + end + trait :manual do status 'manual' self.when 'manual' diff --git a/spec/models/ci/build_spec.rb b/spec/models/ci/build_spec.rb index e82d93d5935..939017e7ee7 100644 --- a/spec/models/ci/build_spec.rb +++ b/spec/models/ci/build_spec.rb @@ -209,6 +209,147 @@ describe Ci::Build do end end + describe '#schedulable?' do + subject { build.schedulable? } + + context 'when build is schedulable' do + let(:build) { create(:ci_build, :created, :schedulable, project: project) } + + it { expect(subject).to be_truthy } + + context 'when feature flag is diabled' do + before do + stub_feature_flags(ci_enable_scheduled_build: false) + end + + it { expect(subject).to be_falsy } + end + end + + context 'when build is not schedulable' do + let(:build) { create(:ci_build, :created, project: project) } + + it { expect(subject).to be_falsy } + end + end + + describe '#schedule' do + subject { build.schedule } + + before do + project.add_developer(user) + end + + let(:build) { create(:ci_build, :created, :schedulable, user: user, project: project) } + + it 'transits to scheduled' do + subject + + expect(build).to be_scheduled + end + + it 'updates scheduled_at column' do + subject + + expect(build.scheduled_at).not_to be_nil + end + + it 'schedules BuildScheduleWorker at the right time' do + Timecop.freeze do + expect(Ci::BuildScheduleWorker) + .to receive(:perform_at).with(1.minute.since, build.id) + + subject + end + end + end + + describe '#unschedule' do + subject { build.unschedule } + + context 'when build is scheduled' do + let(:build) { create(:ci_build, :scheduled, pipeline: pipeline) } + + it 'cleans scheduled_at column' do + subject + + expect(build.scheduled_at).to be_nil + end + + it 'transits to manual' do + subject + + expect(build).to be_manual + end + end + + context 'when build is not scheduled' do + let(:build) { create(:ci_build, :created, pipeline: pipeline) } + + it 'does not transit status' do + subject + + expect(build).to be_created + end + end + end + + describe '#options_scheduled_at' do + subject { build.options_scheduled_at } + + let(:build) { build_stubbed(:ci_build, options: option) } + + context 'when start_in is 1 day' do + let(:option) { { start_in: '1 day' } } + + it 'returns date after 1 day' do + Timecop.freeze do + is_expected.to eq(1.day.since) + end + end + end + + context 'when start_in is 1 week' do + let(:option) { { start_in: '1 week' } } + + it 'returns date after 1 week' do + Timecop.freeze do + is_expected.to eq(1.week.since) + end + end + end + end + + describe '#enqueue_scheduled' do + subject { build.enqueue_scheduled } + + context 'when build is scheduled and the right time has not come yet' do + let(:build) { create(:ci_build, :scheduled, pipeline: pipeline) } + + it 'does not transits the status' do + subject + + expect(build).to be_scheduled + end + end + + context 'when build is scheduled and the right time has already come' do + let(:build) { create(:ci_build, :expired_scheduled, pipeline: pipeline) } + + it 'cleans scheduled_at column' do + subject + + expect(build.scheduled_at).to be_nil + end + + it 'transits to pending' do + subject + + expect(build).to be_pending + end + end + end + describe '#any_runners_online?' do subject { build.any_runners_online? } @@ -1193,6 +1334,12 @@ describe Ci::Build do it { is_expected.to be_truthy } end + context 'when is set to delayed' do + let(:value) { 'delayed' } + + it { is_expected.to be_truthy } + end + context 'when set to something else' do let(:value) { 'something else' } @@ -1463,6 +1610,12 @@ describe Ci::Build do end end + context 'when build is scheduled' do + subject { build_stubbed(:ci_build, :scheduled) } + + it { is_expected.to be_playable } + end + context 'when build is not a manual action' do subject { build_stubbed(:ci_build, :success) } -- cgit v1.2.1 From cc8b8a60b7ac9df0008192a489da6446c7fd5f89 Mon Sep 17 00:00:00 2001 From: Shinya Maeda Date: Wed, 26 Sep 2018 19:49:29 +0900 Subject: Add unit spec for Ci::Pipeline --- spec/models/ci/pipeline_spec.rb | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) (limited to 'spec') diff --git a/spec/models/ci/pipeline_spec.rb b/spec/models/ci/pipeline_spec.rb index 4755702c0e9..0a570394192 100644 --- a/spec/models/ci/pipeline_spec.rb +++ b/spec/models/ci/pipeline_spec.rb @@ -75,6 +75,18 @@ describe Ci::Pipeline, :mailer do end end + describe '#schedule' do + subject { pipeline.schedule } + + let(:pipeline) { build(:ci_pipeline, status: :created) } + + it 'changes pipeline status to schedule' do + subject + + expect(pipeline).to be_scheduled + end + end + describe '#valid_commit_sha' do context 'commit.sha can not start with 00000000' do before do @@ -1288,6 +1300,19 @@ describe Ci::Pipeline, :mailer do end end + context 'when updating status to scheduled' do + before do + allow(pipeline) + .to receive_message_chain(:statuses, :latest, :status) + .and_return(:scheduled) + end + + it 'updates pipeline status to scheduled' do + expect { pipeline.update_status } + .to change { pipeline.reload.status }.to 'scheduled' + end + end + context 'when statuses status was not recognized' do before do allow(pipeline) -- cgit v1.2.1 From 8ed7b34066464758e5cab955abb7a06b44c8e677 Mon Sep 17 00:00:00 2001 From: Shinya Maeda Date: Wed, 26 Sep 2018 20:21:36 +0900 Subject: Add unit tests for CommitStatus and Ci::Stage --- spec/factories/commit_statuses.rb | 4 +++ spec/models/ci/stage_spec.rb | 24 ++++++++++++++++ spec/models/commit_status_spec.rb | 20 +++++++++++++ spec/models/concerns/has_status_spec.rb | 50 +++++++++++++++++++++++++++++++-- 4 files changed, 96 insertions(+), 2 deletions(-) (limited to 'spec') diff --git a/spec/factories/commit_statuses.rb b/spec/factories/commit_statuses.rb index 53368c64e10..381bf07f6a0 100644 --- a/spec/factories/commit_statuses.rb +++ b/spec/factories/commit_statuses.rb @@ -41,6 +41,10 @@ FactoryBot.define do status 'manual' end + trait :scheduled do + status 'scheduled' + end + after(:build) do |build, evaluator| build.project = build.pipeline.project end diff --git a/spec/models/ci/stage_spec.rb b/spec/models/ci/stage_spec.rb index 22a4556c10c..060a1d95293 100644 --- a/spec/models/ci/stage_spec.rb +++ b/spec/models/ci/stage_spec.rb @@ -89,6 +89,18 @@ describe Ci::Stage, :models do end end + context 'when stage is scheduled because of scheduled builds' do + before do + create(:ci_build, :scheduled, stage_id: stage.id) + end + + it 'updates status to scheduled' do + expect { stage.update_status } + .to change { stage.reload.status } + .to 'scheduled' + end + end + context 'when stage is skipped because is empty' do it 'updates status to skipped' do expect { stage.update_status } @@ -188,6 +200,18 @@ describe Ci::Stage, :models do end end + describe '#schedule' do + subject { stage.schedule } + + let(:stage) { create(:ci_stage_entity, status: :created) } + + it 'updates stage status' do + subject + + expect(stage).to be_scheduled + end + end + describe '#position' do context 'when stage has been imported and does not have position index set' do before do diff --git a/spec/models/commit_status_spec.rb b/spec/models/commit_status_spec.rb index f3f2bc28d2c..917685399d4 100644 --- a/spec/models/commit_status_spec.rb +++ b/spec/models/commit_status_spec.rb @@ -129,6 +129,20 @@ describe CommitStatus do end end + describe '#cancel' do + subject { job.cancel } + + context 'when status is scheduled' do + let(:job) { build(:commit_status, :scheduled) } + + it 'updates the status' do + subject + + expect(job).to be_canceled + end + end + end + describe '#auto_canceled?' do subject { commit_status.auto_canceled? } @@ -564,6 +578,12 @@ describe CommitStatus do it_behaves_like 'commit status enqueued' end + + context 'when initial state is :scheduled' do + let(:commit_status) { create(:commit_status, :scheduled) } + + it_behaves_like 'commit status enqueued' + end end describe '#present' do diff --git a/spec/models/concerns/has_status_spec.rb b/spec/models/concerns/has_status_spec.rb index fe9a89e8806..6b1038cb8fd 100644 --- a/spec/models/concerns/has_status_spec.rb +++ b/spec/models/concerns/has_status_spec.rb @@ -270,11 +270,11 @@ describe HasStatus do describe '.cancelable' do subject { CommitStatus.cancelable } - %i[running pending created].each do |status| + %i[running pending created scheduled].each do |status| it_behaves_like 'containing the job', status end - %i[failed success skipped canceled].each do |status| + %i[failed success skipped canceled manual].each do |status| it_behaves_like 'not containing the job', status end end @@ -290,6 +290,18 @@ describe HasStatus do it_behaves_like 'not containing the job', status end end + + describe '.scheduled' do + subject { CommitStatus.scheduled } + + %i[scheduled].each do |status| + it_behaves_like 'containing the job', status + end + + %i[failed success skipped canceled].each do |status| + it_behaves_like 'not containing the job', status + end + end end describe '::DEFAULT_STATUS' do @@ -303,4 +315,38 @@ describe HasStatus do expect(described_class::BLOCKED_STATUS).to eq %w[manual scheduled] end end + + describe 'blocked?' do + subject { object.blocked? } + + %w[ci_pipeline ci_stage ci_build generic_commit_status].each do |type| + let(:object) { build(type, status: status) } + + context 'when status is scheduled' do + let(:status) { :scheduled } + + it { is_expected.to be_truthy } + end + + context 'when status is manual' do + let(:status) { :manual } + + it { is_expected.to be_truthy } + end + + context 'when status is created' do + let(:status) { :created } + + it { is_expected.to be_falsy } + end + end + end + + describe '.status_sql' do + subject { Ci::Build.status_sql } + + it 'returns SQL' do + puts subject + end + end end -- cgit v1.2.1 From f228f23a3243ee64cd4bdcf54d010a5eedf0b8a7 Mon Sep 17 00:00:00 2001 From: Shinya Maeda Date: Thu, 27 Sep 2018 13:26:08 +0900 Subject: Fix process build service spec --- spec/services/ci/process_build_service_spec.rb | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) (limited to 'spec') diff --git a/spec/services/ci/process_build_service_spec.rb b/spec/services/ci/process_build_service_spec.rb index 74a81af75f2..962d07e185b 100644 --- a/spec/services/ci/process_build_service_spec.rb +++ b/spec/services/ci/process_build_service_spec.rb @@ -20,9 +20,14 @@ describe Ci::ProcessBuildService, '#execute' do end it 'schedules the build' do - subject + Timecop.freeze do + expect(Ci::BuildScheduleWorker) + .to receive(:perform_at).with(1.minute.since, build.id) + + subject - expect(build).to be_scheduled + expect(build).to be_scheduled + end end end @@ -34,7 +39,7 @@ describe Ci::ProcessBuildService, '#execute' do it 'enqueues the build' do subject - expect(build).to be_pending + expect(build).to be_manual end end end -- cgit v1.2.1 From 6d712148c9595c4c87247757100ca80198cdd889 Mon Sep 17 00:00:00 2001 From: Shinya Maeda Date: Thu, 27 Sep 2018 13:30:16 +0900 Subject: Fix build_spec --- spec/models/ci/build_spec.rb | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'spec') diff --git a/spec/models/ci/build_spec.rb b/spec/models/ci/build_spec.rb index 939017e7ee7..83add15fab7 100644 --- a/spec/models/ci/build_spec.rb +++ b/spec/models/ci/build_spec.rb @@ -243,12 +243,16 @@ describe Ci::Build do let(:build) { create(:ci_build, :created, :schedulable, user: user, project: project) } it 'transits to scheduled' do + allow(Ci::BuildScheduleWorker).to receive(:perform_at) + subject expect(build).to be_scheduled end it 'updates scheduled_at column' do + allow(Ci::BuildScheduleWorker).to receive(:perform_at) + subject expect(build.scheduled_at).not_to be_nil -- cgit v1.2.1 From b98be35b61aaf71a263ec03807ab8e5d07a9d637 Mon Sep 17 00:00:00 2001 From: Shinya Maeda Date: Thu, 27 Sep 2018 13:53:54 +0900 Subject: Fix safe model attributes --- spec/lib/gitlab/import_export/safe_model_attributes.yml | 1 + 1 file changed, 1 insertion(+) (limited to 'spec') diff --git a/spec/lib/gitlab/import_export/safe_model_attributes.yml b/spec/lib/gitlab/import_export/safe_model_attributes.yml index e9f1be172b0..1d59cff7ba8 100644 --- a/spec/lib/gitlab/import_export/safe_model_attributes.yml +++ b/spec/lib/gitlab/import_export/safe_model_attributes.yml @@ -300,6 +300,7 @@ CommitStatus: - retried - protected - failure_reason +- scheduled_at Ci::Variable: - id - project_id -- cgit v1.2.1 From c6bb038c006f4cfff68666661d3a8fe257c51ed7 Mon Sep 17 00:00:00 2001 From: Shinya Maeda Date: Thu, 27 Sep 2018 13:59:12 +0900 Subject: Fix favicon spec --- spec/lib/gitlab/favicon_spec.rb | 1 + 1 file changed, 1 insertion(+) (limited to 'spec') diff --git a/spec/lib/gitlab/favicon_spec.rb b/spec/lib/gitlab/favicon_spec.rb index 68abcb3520a..49a423191bb 100644 --- a/spec/lib/gitlab/favicon_spec.rb +++ b/spec/lib/gitlab/favicon_spec.rb @@ -58,6 +58,7 @@ RSpec.describe Gitlab::Favicon, :request_store do favicon_status_not_found favicon_status_pending favicon_status_running + favicon_status_scheduled favicon_status_skipped favicon_status_success favicon_status_warning -- cgit v1.2.1 From 80a92650faf9d7ca7a706b6a74019d869598fe41 Mon Sep 17 00:00:00 2001 From: Shinya Maeda Date: Thu, 27 Sep 2018 16:10:55 +0900 Subject: Add Spec for ProcessPipelineService --- spec/services/ci/process_pipeline_service_spec.rb | 203 +++++++++++++++++++++- 1 file changed, 202 insertions(+), 1 deletion(-) (limited to 'spec') diff --git a/spec/services/ci/process_pipeline_service_spec.rb b/spec/services/ci/process_pipeline_service_spec.rb index feb5120bc68..d314d774be4 100644 --- a/spec/services/ci/process_pipeline_service_spec.rb +++ b/spec/services/ci/process_pipeline_service_spec.rb @@ -242,6 +242,187 @@ describe Ci::ProcessPipelineService, '#execute' do end end + context 'when delayed jobs are defined' do + context 'when the scene is timed incremental rollout' do + before do + create_build('build', stage_idx: 0) + create_build('rollout10%', **delayed_options, stage_idx: 1) + create_build('rollout100%', **delayed_options, stage_idx: 2) + create_build('cleanup', stage_idx: 3) + + allow(Ci::BuildScheduleWorker).to receive(:perform_at) + end + + context 'when builds are successful' do + it 'properly processes the pipeline' do + expect(process_pipeline).to be_truthy + expect(builds_names_and_statuses).to eq({ 'build': 'pending' }) + + succeed_pending + + expect(builds_names_and_statuses).to eq({ 'build': 'success', 'rollout10%': 'scheduled' }) + + enqueue_scheduled('rollout10%') + succeed_pending + + expect(builds_names_and_statuses).to eq({ 'build': 'success', 'rollout10%': 'success', 'rollout100%': 'scheduled' }) + + enqueue_scheduled('rollout100%') + succeed_pending + + expect(builds_names_and_statuses).to eq({ 'build': 'success', 'rollout10%': 'success', 'rollout100%': 'success', 'cleanup': 'pending' }) + + succeed_pending + + expect(builds_names_and_statuses).to eq({ 'build': 'success', 'rollout10%': 'success', 'rollout100%': 'success', 'cleanup': 'success' }) + expect(pipeline.reload.status).to eq 'success' + end + end + + context 'when build job fails' do + it 'properly processes the pipeline' do + expect(process_pipeline).to be_truthy + expect(builds_names_and_statuses).to eq({ 'build': 'pending' }) + + fail_running_or_pending + + expect(builds_names_and_statuses).to eq({ 'build': 'failed' }) + expect(pipeline.reload.status).to eq 'failed' + end + end + + context 'when rollout 10% is unscheduled' do + it 'properly processes the pipeline' do + expect(process_pipeline).to be_truthy + expect(builds_names_and_statuses).to eq({ 'build': 'pending' }) + + succeed_pending + + expect(builds_names_and_statuses).to eq({ 'build': 'success', 'rollout10%': 'scheduled' }) + + unschedule + + expect(builds_names_and_statuses).to eq({ 'build': 'success', 'rollout10%': 'manual' }) + expect(pipeline.reload.status).to eq 'manual' + end + + context 'when user plays rollout 10%' do + it 'schedules rollout100%' do + process_pipeline + succeed_pending + unschedule + play_manual_action('rollout10%') + succeed_pending + + expect(builds_names_and_statuses).to eq({ 'build': 'success', 'rollout10%': 'success', 'rollout100%': 'scheduled' }) + expect(pipeline.reload.status).to eq 'scheduled' + end + end + end + + context 'when rollout 10% fails' do + it 'properly processes the pipeline' do + expect(process_pipeline).to be_truthy + expect(builds_names_and_statuses).to eq({ 'build': 'pending' }) + + succeed_pending + + expect(builds_names_and_statuses).to eq({ 'build': 'success', 'rollout10%': 'scheduled' }) + + enqueue_scheduled('rollout10%') + fail_running_or_pending + + expect(builds_names_and_statuses).to eq({ 'build': 'success', 'rollout10%': 'failed' }) + expect(pipeline.reload.status).to eq 'failed' + end + + context 'when user retries rollout 10%' do + it 'does not schedule rollout10% again' do + process_pipeline + succeed_pending + enqueue_scheduled('rollout10%') + fail_running_or_pending + retry_build('rollout10%') + + expect(builds_names_and_statuses).to eq({ 'build': 'success', 'rollout10%': 'pending' }) + expect(pipeline.reload.status).to eq 'running' + end + end + end + + context 'when rollout 10% is played immidiately' do + it 'properly processes the pipeline' do + expect(process_pipeline).to be_truthy + expect(builds_names_and_statuses).to eq({ 'build': 'pending' }) + + succeed_pending + + expect(builds_names_and_statuses).to eq({ 'build': 'success', 'rollout10%': 'scheduled' }) + + play_manual_action('rollout10%') + + expect(builds_names_and_statuses).to eq({ 'build': 'success', 'rollout10%': 'pending' }) + expect(pipeline.reload.status).to eq 'running' + end + end + end + + context 'when only one scheduled job exists in a pipeline' do + before do + create_build('delayed', **delayed_options, stage_idx: 0) + + allow(Ci::BuildScheduleWorker).to receive(:perform_at) + end + + it 'properly processes the pipeline' do + expect(process_pipeline).to be_truthy + expect(builds_names_and_statuses).to eq({ 'delayed': 'scheduled' }) + + expect(pipeline.reload.status).to eq 'scheduled' + end + end + + context 'when there are two delayed jobs in a stage' do + before do + create_build('delayed1', **delayed_options, stage_idx: 0) + create_build('delayed2', **delayed_options, stage_idx: 0) + create_build('job', stage_idx: 1) + + allow(Ci::BuildScheduleWorker).to receive(:perform_at) + end + + it 'blocks the stage until all scheduled jobs finished' do + expect(process_pipeline).to be_truthy + expect(builds_names_and_statuses).to eq({ 'delayed1': 'scheduled', 'delayed2': 'scheduled' }) + + enqueue_scheduled('delayed1') + + expect(builds_names_and_statuses).to eq({ 'delayed1': 'pending', 'delayed2': 'scheduled' }) + expect(pipeline.reload.status).to eq 'scheduled' + end + end + + context 'when a delayed job is allowed to fail' do + before do + create_build('delayed', **delayed_options, allow_failure: true, stage_idx: 0) + create_build('job', stage_idx: 1) + + allow(Ci::BuildScheduleWorker).to receive(:perform_at) + end + + it 'blocks the stage and continues after it failed' do + expect(process_pipeline).to be_truthy + expect(builds_names_and_statuses).to eq({ 'delayed': 'scheduled' }) + + enqueue_scheduled('delayed') + fail_running_or_pending + + expect(builds_names_and_statuses).to eq({ 'delayed': 'failed', 'job': 'pending' }) + expect(pipeline.reload.status).to eq 'pending' + end + end + end + context 'when there are manual action in earlier stages' do context 'when first stage has only optional manual actions' do before do @@ -536,6 +717,10 @@ describe Ci::ProcessPipelineService, '#execute' do builds.pluck(:name) end + def builds_names_and_statuses + builds.inject({}) { |h, b| h[b.name.to_sym] = b.status; h } + end + def all_builds_names all_builds.pluck(:name) end @@ -549,7 +734,7 @@ describe Ci::ProcessPipelineService, '#execute' do end def succeed_pending - builds.pending.update_all(status: 'success') + builds.pending.map(&:success) end def succeed_running_or_pending @@ -568,6 +753,14 @@ describe Ci::ProcessPipelineService, '#execute' do builds.find_by(name: name).play(user) end + def enqueue_scheduled(name) + builds.scheduled.find_by(name: name).enqueue + end + + def retry_build(name) + Ci::Build.retry(builds.find_by(name: name), user) + end + def manual_actions pipeline.manual_actions(true) end @@ -575,4 +768,12 @@ describe Ci::ProcessPipelineService, '#execute' do def create_build(name, **opts) create(:ci_build, :created, pipeline: pipeline, name: name, **opts) end + + def delayed_options + { when: 'delayed', options: { start_in: '1 minute' } } + end + + def unschedule + pipeline.builds.scheduled.map(&:unschedule) + end end -- cgit v1.2.1 From 71fc37c9cf8aee5de3d4d43ec6ea97a56e34537d Mon Sep 17 00:00:00 2001 From: Shinya Maeda Date: Thu, 27 Sep 2018 17:50:50 +0900 Subject: Add spec for BuildScheduleWorker and RunScheduledBuildService --- .../ci/run_scheduled_build_service_spec.rb | 62 ++++++++++++++++++++++ spec/workers/ci/build_schedule_worker_spec.rb | 40 ++++++++++++++ 2 files changed, 102 insertions(+) create mode 100644 spec/services/ci/run_scheduled_build_service_spec.rb create mode 100644 spec/workers/ci/build_schedule_worker_spec.rb (limited to 'spec') diff --git a/spec/services/ci/run_scheduled_build_service_spec.rb b/spec/services/ci/run_scheduled_build_service_spec.rb new file mode 100644 index 00000000000..145905db0cf --- /dev/null +++ b/spec/services/ci/run_scheduled_build_service_spec.rb @@ -0,0 +1,62 @@ +require 'spec_helper' + +describe Ci::RunScheduledBuildService do + let(:user) { create(:user) } + let(:project) { create(:project) } + let(:pipeline) { create(:ci_pipeline, project: project) } + + subject { described_class.new(project, user).execute(build) } + + context 'when user can update build' do + before do + project.add_developer(user) + + create(:protected_branch, :developers_can_merge, + name: pipeline.ref, project: project) + end + + context 'when build is scheduled' do + context 'when scheduled_at is expired' do + let(:build) { create(:ci_build, :expired_scheduled, user: user, project: project, pipeline: pipeline) } + + it 'can run the build' do + expect { subject }.not_to raise_error + + expect(build).to be_pending + end + end + + context 'when scheduled_at is not expired' do + let(:build) { create(:ci_build, :scheduled, user: user, project: project, pipeline: pipeline) } + + it 'can run the build' do + expect { subject }.to raise_error(StateMachines::InvalidTransition) + + expect(build).to be_scheduled + end + end + end + + context 'when build is not scheduled' do + let(:build) { create(:ci_build, :created, user: user, project: project, pipeline: pipeline) } + + it 'can not run the build' do + expect { subject }.to raise_error(StateMachines::InvalidTransition) + + expect(build).to be_created + end + end + end + + context 'when user can not update build' do + context 'when build is scheduled' do + let(:build) { create(:ci_build, :scheduled, user: user, project: project, pipeline: pipeline) } + + it 'can not run the build' do + expect { subject }.to raise_error(Gitlab::Access::AccessDeniedError) + + expect(build).to be_scheduled + end + end + end +end diff --git a/spec/workers/ci/build_schedule_worker_spec.rb b/spec/workers/ci/build_schedule_worker_spec.rb new file mode 100644 index 00000000000..c76537b9233 --- /dev/null +++ b/spec/workers/ci/build_schedule_worker_spec.rb @@ -0,0 +1,40 @@ +require 'spec_helper' + +describe Ci::BuildScheduleWorker do + subject { described_class.new.perform(build.id) } + + context 'when build is found' do + context 'when build is scheduled' do + let(:build) { create(:ci_build, :scheduled) } + + it 'executes RunScheduledBuildService' do + expect_any_instance_of(Ci::RunScheduledBuildService) + .to receive(:execute).once + + subject + end + end + + context 'when build is not scheduled' do + let(:build) { create(:ci_build, :created) } + + it 'executes RunScheduledBuildService' do + expect_any_instance_of(Ci::RunScheduledBuildService) + .not_to receive(:execute) + + subject + end + end + end + + context 'when build is not found' do + let(:build) { build_stubbed(:ci_build, :scheduled) } + + it 'does nothing' do + expect_any_instance_of(Ci::RunScheduledBuildService) + .not_to receive(:execute) + + subject + end + end +end -- cgit v1.2.1 From 587560757faaedb6c61ef7aa77f11934cb76084b Mon Sep 17 00:00:00 2001 From: Shinya Maeda Date: Thu, 27 Sep 2018 18:17:43 +0900 Subject: Fix StuckCiJobsWorker and added tests --- spec/workers/stuck_ci_jobs_worker_spec.rb | 41 +++++++++++++++++++++++++++++++ 1 file changed, 41 insertions(+) (limited to 'spec') diff --git a/spec/workers/stuck_ci_jobs_worker_spec.rb b/spec/workers/stuck_ci_jobs_worker_spec.rb index 856886e3df5..2f8ba4859d7 100644 --- a/spec/workers/stuck_ci_jobs_worker_spec.rb +++ b/spec/workers/stuck_ci_jobs_worker_spec.rb @@ -127,6 +127,47 @@ describe StuckCiJobsWorker do end end + describe 'drop_stale_scheduled_builds' do + let(:status) { 'scheduled' } + let(:updated_at) { } + + context 'when scheduled at 2 hours ago but it is not executed yet' do + let!(:job) { create(:ci_build, :scheduled, scheduled_at: 2.hours.ago) } + + it 'drops the stale scheduled build' do + expect(Ci::Build.scheduled.count).to eq(1) + expect(job).to be_scheduled + + worker.perform + job.reload + + expect(Ci::Build.scheduled.count).to eq(0) + expect(job).to be_failed + expect(job).to be_schedule_expired + end + end + + context 'when scheduled at 30 minutes ago but it is not executed yet' do + let!(:job) { create(:ci_build, :scheduled, scheduled_at: 30.minutes.ago) } + + it 'does not drop the stale scheduled build yet' do + expect(Ci::Build.scheduled.count).to eq(1) + expect(job).to be_scheduled + + worker.perform + + expect(Ci::Build.scheduled.count).to eq(1) + expect(job).to be_scheduled + end + end + + context 'when there are no stale scheduled builds' do + it 'does not drop the stale scheduled build yet' do + expect { worker.perform }.not_to raise_error + end + end + end + describe 'exclusive lease' do let(:status) { 'running' } let(:updated_at) { 2.days.ago } -- cgit v1.2.1 From eee454e142fb99646649f8b8c9ccd8626c9bd70a Mon Sep 17 00:00:00 2001 From: Shinya Maeda Date: Thu, 27 Sep 2018 19:08:11 +0900 Subject: Fix validation methods in Config::Entry::Job. Added spec for that --- spec/lib/gitlab/ci/config/entry/job_spec.rb | 65 +++++++++++++++++++++++++++++ 1 file changed, 65 insertions(+) (limited to 'spec') diff --git a/spec/lib/gitlab/ci/config/entry/job_spec.rb b/spec/lib/gitlab/ci/config/entry/job_spec.rb index 2c9758401b7..d745c4ca2ad 100644 --- a/spec/lib/gitlab/ci/config/entry/job_spec.rb +++ b/spec/lib/gitlab/ci/config/entry/job_spec.rb @@ -39,6 +39,16 @@ describe Gitlab::Ci::Config::Entry::Job do expect(entry.errors).to include "job name can't be blank" end end + + context 'when delayed job' do + context 'when start_in is specified' do + let(:config) { { script: 'echo', when: 'delayed', start_in: '1 day' } } + + it 'returns error about invalid type' do + expect(entry).to be_valid + end + end + end end context 'when entry value is not correct' do @@ -129,6 +139,43 @@ describe Gitlab::Ci::Config::Entry::Job do end end end + + context 'when delayed job' do + context 'when start_in is specified' do + let(:config) { { script: 'echo', when: 'delayed', start_in: '1 day' } } + + it 'returns error about invalid type' do + expect(entry).to be_valid + end + end + + context 'when start_in is empty' do + let(:config) { { when: 'delayed', start_in: nil } } + + it 'returns error about invalid type' do + expect(entry).not_to be_valid + expect(entry.errors).to include 'job start in should be a duration' + end + end + + context 'when start_in is not formateed ad a duration' do + let(:config) { { when: 'delayed', start_in: 'test' } } + + it 'returns error about invalid type' do + expect(entry).not_to be_valid + expect(entry.errors).to include 'job start in should be a duration' + end + end + end + + context 'when start_in specified without delayed specification' do + let(:config) { { start_in: '1 day' } } + + it 'returns error about invalid type' do + expect(entry).not_to be_valid + expect(entry.errors).to include 'job start in must be blank' + end + end end end @@ -238,6 +285,24 @@ describe Gitlab::Ci::Config::Entry::Job do end end + describe '#delayed?' do + context 'when job is a delayed' do + let(:config) { { script: 'deploy', when: 'delayed' } } + + it 'is a delayed' do + expect(entry).to be_delayed + end + end + + context 'when job is not a delayed' do + let(:config) { { script: 'deploy' } } + + it 'is not a delayed' do + expect(entry).not_to be_delayed + end + end + end + describe '#ignored?' do context 'when job is a manual action' do context 'when it is not specified if job is allowed to fail' do -- cgit v1.2.1 From fcb77970b6ca26f031d5bcf935855a91bbb35158 Mon Sep 17 00:00:00 2001 From: Shinya Maeda Date: Thu, 27 Sep 2018 19:32:26 +0900 Subject: Fix Status::Build::Scheduled. Add spec for the class. --- spec/lib/gitlab/ci/status/build/scheduled_spec.rb | 58 +++++++++++++++++++++++ 1 file changed, 58 insertions(+) create mode 100644 spec/lib/gitlab/ci/status/build/scheduled_spec.rb (limited to 'spec') diff --git a/spec/lib/gitlab/ci/status/build/scheduled_spec.rb b/spec/lib/gitlab/ci/status/build/scheduled_spec.rb new file mode 100644 index 00000000000..3098a17c50d --- /dev/null +++ b/spec/lib/gitlab/ci/status/build/scheduled_spec.rb @@ -0,0 +1,58 @@ +require 'spec_helper' + +describe Gitlab::Ci::Status::Build::Scheduled do + let(:user) { create(:user) } + let(:project) { create(:project, :stubbed_repository) } + let(:build) { create(:ci_build, :scheduled, project: project) } + let(:status) { Gitlab::Ci::Status::Core.new(build, user) } + + subject { described_class.new(status) } + + describe '#illustration' do + it { expect(subject.illustration).to include(:image, :size, :title) } + end + + describe '#status_tooltip' do + context 'when scheduled_at is not expired' do + let(:build) { create(:ci_build, scheduled_at: 1.minute.since, project: project) } + + it 'shows execute_in of the scheduled job' do + Timecop.freeze do + expect(subject.status_tooltip).to include('00:01:00') + end + end + end + + context 'when scheduled_at is expired' do + let(:build) { create(:ci_build, :expired_scheduled, project: project) } + + it 'shows 00:00:00' do + Timecop.freeze do + expect(subject.status_tooltip).to include('00:00:00') + end + end + end + end + + describe '.matches?' do + subject { described_class.matches?(build, user) } + + context 'when build is scheduled and scheduled_at is present' do + let(:build) { create(:ci_build, :expired_scheduled, project: project) } + + it { is_expected.to be_truthy } + end + + context 'when build is scheduled' do + let(:build) { create(:ci_build, status: :scheduled, project: project) } + + it { is_expected.to be_falsy } + end + + context 'when scheduled_at is present' do + let(:build) { create(:ci_build, scheduled_at: 1.minute.since, project: project) } + + it { is_expected.to be_falsy } + end + end +end -- cgit v1.2.1 From 5e4824d9ed8d164ff5a8ed5bfbf1e5a0f1bf1cff Mon Sep 17 00:00:00 2001 From: Shinya Maeda Date: Thu, 27 Sep 2018 19:33:41 +0900 Subject: Fix Status::Pipeline::Blocked spec --- spec/lib/gitlab/ci/status/pipeline/blocked_spec.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'spec') diff --git a/spec/lib/gitlab/ci/status/pipeline/blocked_spec.rb b/spec/lib/gitlab/ci/status/pipeline/blocked_spec.rb index 1a2b952d374..49a25b4a389 100644 --- a/spec/lib/gitlab/ci/status/pipeline/blocked_spec.rb +++ b/spec/lib/gitlab/ci/status/pipeline/blocked_spec.rb @@ -15,7 +15,7 @@ describe Gitlab::Ci::Status::Pipeline::Blocked do describe '#label' do it 'overrides status label' do - expect(subject.label).to eq 'waiting for manual action' + expect(subject.label).to eq 'waiting for manual action or delayed job' end end -- cgit v1.2.1 From 5e35e85acb5403ae1a992e2cd1c9618f6fc9273e Mon Sep 17 00:00:00 2001 From: Shinya Maeda Date: Thu, 27 Sep 2018 19:36:09 +0900 Subject: Add spec for scheduled status --- spec/lib/gitlab/ci/status/scheduled_spec.rb | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) create mode 100644 spec/lib/gitlab/ci/status/scheduled_spec.rb (limited to 'spec') diff --git a/spec/lib/gitlab/ci/status/scheduled_spec.rb b/spec/lib/gitlab/ci/status/scheduled_spec.rb new file mode 100644 index 00000000000..c35a6f43d5d --- /dev/null +++ b/spec/lib/gitlab/ci/status/scheduled_spec.rb @@ -0,0 +1,27 @@ +require 'spec_helper' + +describe Gitlab::Ci::Status::Scheduled do + subject do + described_class.new(double('subject'), double('user')) + end + + describe '#text' do + it { expect(subject.text).to eq 'scheduled' } + end + + describe '#label' do + it { expect(subject.label).to eq 'scheduled' } + end + + describe '#icon' do + it { expect(subject.icon).to eq 'status_scheduled' } + end + + describe '#favicon' do + it { expect(subject.favicon).to eq 'favicon_status_scheduled' } + end + + describe '#group' do + it { expect(subject.group).to eq 'scheduled' } + end +end -- cgit v1.2.1 From 9ceb61634e2cf6176bd733e1684b80f97e0bb086 Mon Sep 17 00:00:00 2001 From: Shinya Maeda Date: Thu, 27 Sep 2018 19:43:10 +0900 Subject: Add spec for YamlProcessor --- spec/lib/gitlab/ci/yaml_processor_spec.rb | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) (limited to 'spec') diff --git a/spec/lib/gitlab/ci/yaml_processor_spec.rb b/spec/lib/gitlab/ci/yaml_processor_spec.rb index a2d429fa859..d75c473eb66 100644 --- a/spec/lib/gitlab/ci/yaml_processor_spec.rb +++ b/spec/lib/gitlab/ci/yaml_processor_spec.rb @@ -121,6 +121,21 @@ module Gitlab end end end + + describe 'delayed job entry' do + context 'when delayed is defined' do + let(:config) do + YAML.dump(rspec: { script: 'rollout 10%', + when: 'delayed', + start_in: '1 day' }) + end + + it 'has the attributes' do + expect(subject[:when]).to eq 'delayed' + expect(subject[:options][:start_in]).to eq '1 day' + end + end + end end describe '#stages_attributes' do @@ -1260,7 +1275,7 @@ module Gitlab config = YAML.dump({ rspec: { script: "test", when: 1 } }) expect do Gitlab::Ci::YamlProcessor.new(config) - end.to raise_error(Gitlab::Ci::YamlProcessor::ValidationError, "jobs:rspec when should be on_success, on_failure, always or manual") + end.to raise_error(Gitlab::Ci::YamlProcessor::ValidationError, "jobs:rspec when should be on_success, on_failure, always, manual or delayed") end it "returns errors if job artifacts:name is not an a string" do -- cgit v1.2.1 From ea38e832f0f197c5121504d7e193227d3d9c7867 Mon Sep 17 00:00:00 2001 From: Winnie Hellmann Date: Thu, 27 Sep 2018 13:44:03 +0200 Subject: Allow remaining time of scheduled jobs to overflow one day --- spec/helpers/time_helper_spec.rb | 38 ++++++++++++++++++++++++++++---------- 1 file changed, 28 insertions(+), 10 deletions(-) (limited to 'spec') diff --git a/spec/helpers/time_helper_spec.rb b/spec/helpers/time_helper_spec.rb index 0b371d69ecf..37455c3e491 100644 --- a/spec/helpers/time_helper_spec.rb +++ b/spec/helpers/time_helper_spec.rb @@ -20,17 +20,35 @@ describe TimeHelper do end describe "#duration_in_numbers" do - it "returns minutes and seconds" do - durations_and_expectations = { - 100 => "01:40", - 121 => "02:01", - 3721 => "01:02:01", - 0 => "00:00", - 42 => "00:42" - } + using RSpec::Parameterized::TableSyntax + + context "without passing allow_overflow" do + where(:duration, :formatted_string) do + 0 | "00:00" + 1.second | "00:01" + 42.seconds | "00:42" + 2.minutes + 1.second | "02:01" + 3.hours + 2.minutes + 1.second | "03:02:01" + 30.hours | "06:00:00" + end + + with_them do + it { expect(duration_in_numbers(duration)).to eq formatted_string } + end + end + + context "with allow_overflow = true" do + where(:duration, :formatted_string) do + 0 | "00:00" + 1.second | "00:01" + 42.seconds | "00:42" + 2.minutes + 1.second | "02:01" + 3.hours + 2.minutes + 1.second | "03:02:01" + 30.hours | "30:00:00" + end - durations_and_expectations.each do |duration, expectation| - expect(duration_in_numbers(duration)).to eq(expectation) + with_them do + it { expect(duration_in_numbers(duration, true)).to eq formatted_string } end end end -- cgit v1.2.1 From 54263dc1d9719f871fb2f23ecac4e0cfcabebe77 Mon Sep 17 00:00:00 2001 From: Shinya Maeda Date: Fri, 28 Sep 2018 14:41:39 +0900 Subject: Fix coding style offence --- spec/services/ci/process_pipeline_service_spec.rb | 21 ++++++++++++--------- spec/workers/ci/build_schedule_worker_spec.rb | 2 +- 2 files changed, 13 insertions(+), 10 deletions(-) (limited to 'spec') diff --git a/spec/services/ci/process_pipeline_service_spec.rb b/spec/services/ci/process_pipeline_service_spec.rb index d314d774be4..3ce3785b162 100644 --- a/spec/services/ci/process_pipeline_service_spec.rb +++ b/spec/services/ci/process_pipeline_service_spec.rb @@ -257,7 +257,7 @@ describe Ci::ProcessPipelineService, '#execute' do it 'properly processes the pipeline' do expect(process_pipeline).to be_truthy expect(builds_names_and_statuses).to eq({ 'build': 'pending' }) - + succeed_pending expect(builds_names_and_statuses).to eq({ 'build': 'success', 'rollout10%': 'scheduled' }) @@ -283,7 +283,7 @@ describe Ci::ProcessPipelineService, '#execute' do it 'properly processes the pipeline' do expect(process_pipeline).to be_truthy expect(builds_names_and_statuses).to eq({ 'build': 'pending' }) - + fail_running_or_pending expect(builds_names_and_statuses).to eq({ 'build': 'failed' }) @@ -295,11 +295,11 @@ describe Ci::ProcessPipelineService, '#execute' do it 'properly processes the pipeline' do expect(process_pipeline).to be_truthy expect(builds_names_and_statuses).to eq({ 'build': 'pending' }) - + succeed_pending expect(builds_names_and_statuses).to eq({ 'build': 'success', 'rollout10%': 'scheduled' }) - + unschedule expect(builds_names_and_statuses).to eq({ 'build': 'success', 'rollout10%': 'manual' }) @@ -324,11 +324,11 @@ describe Ci::ProcessPipelineService, '#execute' do it 'properly processes the pipeline' do expect(process_pipeline).to be_truthy expect(builds_names_and_statuses).to eq({ 'build': 'pending' }) - + succeed_pending expect(builds_names_and_statuses).to eq({ 'build': 'success', 'rollout10%': 'scheduled' }) - + enqueue_scheduled('rollout10%') fail_running_or_pending @@ -354,11 +354,11 @@ describe Ci::ProcessPipelineService, '#execute' do it 'properly processes the pipeline' do expect(process_pipeline).to be_truthy expect(builds_names_and_statuses).to eq({ 'build': 'pending' }) - + succeed_pending expect(builds_names_and_statuses).to eq({ 'build': 'success', 'rollout10%': 'scheduled' }) - + play_manual_action('rollout10%') expect(builds_names_and_statuses).to eq({ 'build': 'success', 'rollout10%': 'pending' }) @@ -718,7 +718,10 @@ describe Ci::ProcessPipelineService, '#execute' do end def builds_names_and_statuses - builds.inject({}) { |h, b| h[b.name.to_sym] = b.status; h } + builds.each_with_object({}) do |h, b| + h[b.name.to_sym] = b.status + h + end end def all_builds_names diff --git a/spec/workers/ci/build_schedule_worker_spec.rb b/spec/workers/ci/build_schedule_worker_spec.rb index c76537b9233..4a3fe84d7f7 100644 --- a/spec/workers/ci/build_schedule_worker_spec.rb +++ b/spec/workers/ci/build_schedule_worker_spec.rb @@ -10,7 +10,7 @@ describe Ci::BuildScheduleWorker do it 'executes RunScheduledBuildService' do expect_any_instance_of(Ci::RunScheduledBuildService) .to receive(:execute).once - + subject end end -- cgit v1.2.1 From 97c556bf1d49d9b5362fdd18255244d2da349a17 Mon Sep 17 00:00:00 2001 From: Shinya Maeda Date: Fri, 28 Sep 2018 15:55:13 +0900 Subject: Fix spec failure --- spec/services/ci/process_pipeline_service_spec.rb | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) (limited to 'spec') diff --git a/spec/services/ci/process_pipeline_service_spec.rb b/spec/services/ci/process_pipeline_service_spec.rb index 3ce3785b162..4f1e487197e 100644 --- a/spec/services/ci/process_pipeline_service_spec.rb +++ b/spec/services/ci/process_pipeline_service_spec.rb @@ -31,17 +31,14 @@ describe Ci::ProcessPipelineService, '#execute' do succeed_pending expect(builds.success.count).to eq(2) - expect(process_pipeline).to be_truthy succeed_pending expect(builds.success.count).to eq(4) - expect(process_pipeline).to be_truthy succeed_pending expect(builds.success.count).to eq(5) - expect(process_pipeline).to be_falsey end it 'does not process pipeline if existing stage is running' do @@ -718,7 +715,7 @@ describe Ci::ProcessPipelineService, '#execute' do end def builds_names_and_statuses - builds.each_with_object({}) do |h, b| + builds.each_with_object({}) do |b, h| h[b.name.to_sym] = b.status h end -- cgit v1.2.1 From 6d4511135d08aa2dc2ffa8aec236cea3ff77e1e8 Mon Sep 17 00:00:00 2001 From: Shinya Maeda Date: Fri, 28 Sep 2018 16:17:01 +0900 Subject: Add spec for ProcessBuildService --- spec/services/ci/process_build_service_spec.rb | 199 +++++++++++++++++++++---- 1 file changed, 171 insertions(+), 28 deletions(-) (limited to 'spec') diff --git a/spec/services/ci/process_build_service_spec.rb b/spec/services/ci/process_build_service_spec.rb index 962d07e185b..692f28c80cb 100644 --- a/spec/services/ci/process_build_service_spec.rb +++ b/spec/services/ci/process_build_service_spec.rb @@ -5,62 +5,205 @@ describe Ci::ProcessBuildService, '#execute' do let(:user) { create(:user) } let(:project) { create(:project) } - subject { described_class.new(project, user).execute(build) } + subject { described_class.new(project, user).execute(build, current_status) } before do project.add_maintainer(user) end - context 'when build is schedulable' do - let(:build) { create(:ci_build, :created, :schedulable, user: user, project: project) } + shared_examples_for 'Enqueuing properly' do |valid_statuses_for_when| + valid_statuses_for_when.each do |status_for_prior_stages| + context "when status for prior stages is #{status_for_prior_stages}" do + let(:current_status) { status_for_prior_stages } - context 'when ci_enable_scheduled_build feature flag is enabled' do - before do - stub_feature_flags(ci_enable_scheduled_build: true) + %w[created skipped manual scheduled].each do |status| + context "when build status is #{status}" do + let(:build) { create(:ci_build, status.to_sym, when: when_option, user: user, project: project) } + + it 'enqueues the build' do + expect { subject }.to change { build.status }.to('pending') + end + end + end + + %w[pending running success failed canceled].each do |status| + context "when build status is #{status}" do + let(:build) { create(:ci_build, status.to_sym, when: when_option, user: user, project: project) } + + it 'does not change the build status' do + expect { subject }.not_to change { build.status } + end + end + end end + end - it 'schedules the build' do - Timecop.freeze do - expect(Ci::BuildScheduleWorker) - .to receive(:perform_at).with(1.minute.since, build.id) + (HasStatus::AVAILABLE_STATUSES - valid_statuses_for_when).each do |status_for_prior_stages| + let(:current_status) { status_for_prior_stages } - subject + context "when status for prior stages is #{status_for_prior_stages}" do + %w[created pending].each do |status| + context "when build status is #{status}" do + let(:build) { create(:ci_build, status.to_sym, when: when_option, user: user, project: project) } - expect(build).to be_scheduled + it 'skips the build' do + expect { subject }.to change { build.status }.to('skipped') + end + end + end + + (HasStatus::AVAILABLE_STATUSES - %w[created pending]).each do |status| + context "when build status is #{status}" do + let(:build) { create(:ci_build, status.to_sym, when: when_option, user: user, project: project) } + + it 'does not change build status' do + expect { subject }.not_to change { build.status } + end + end end end end + end + + shared_examples_for 'Actionizing properly' do |valid_statuses_for_when| + valid_statuses_for_when.each do |status_for_prior_stages| + context "when status for prior stages is #{status_for_prior_stages}" do + let(:current_status) { status_for_prior_stages } + + %w[created].each do |status| + context "when build status is #{status}" do + let(:build) { create(:ci_build, status.to_sym, :actionable, user: user, project: project) } - context 'when ci_enable_scheduled_build feature flag is disabled' do - before do - stub_feature_flags(ci_enable_scheduled_build: false) + it 'enqueues the build' do + expect { subject }.to change { build.status }.to('manual') + end + end + end + + %w[manual skipped pending running success failed canceled scheduled].each do |status| + context "when build status is #{status}" do + let(:build) { create(:ci_build, status.to_sym, :actionable, user: user, project: project) } + + it 'does not change the build status' do + expect { subject }.not_to change { build.status } + end + end + end end + end + + (HasStatus::AVAILABLE_STATUSES - valid_statuses_for_when).each do |status_for_prior_stages| + let(:current_status) { status_for_prior_stages } - it 'enqueues the build' do - subject + context "when status for prior stages is #{status_for_prior_stages}" do + %w[created pending].each do |status| + context "when build status is #{status}" do + let(:build) { create(:ci_build, status.to_sym, :actionable, user: user, project: project) } - expect(build).to be_manual + it 'skips the build' do + expect { subject }.to change { build.status }.to('skipped') + end + end + end + + (HasStatus::AVAILABLE_STATUSES - %w[created pending]).each do |status| + context "when build status is #{status}" do + let(:build) { create(:ci_build, status.to_sym, :actionable, user: user, project: project) } + + it 'does not change build status' do + expect { subject }.not_to change { build.status } + end + end + end end end end - context 'when build is actionable' do - let(:build) { create(:ci_build, :created, :actionable, user: user, project: project) } + shared_examples_for 'Scheduling properly' do |valid_statuses_for_when| + valid_statuses_for_when.each do |status_for_prior_stages| + context "when status for prior stages is #{status_for_prior_stages}" do + let(:current_status) { status_for_prior_stages } + + %w[created].each do |status| + context "when build status is #{status}" do + let(:build) { create(:ci_build, status.to_sym, :schedulable, user: user, project: project) } + + it 'enqueues the build' do + expect { subject }.to change { build.status }.to('scheduled') + end + end + end + + %w[manual skipped pending running success failed canceled scheduled].each do |status| + context "when build status is #{status}" do + let(:build) { create(:ci_build, status.to_sym, :schedulable, user: user, project: project) } + + it 'does not change the build status' do + expect { subject }.not_to change { build.status } + end + end + end + end + end - it 'actionizes the build' do - subject + (HasStatus::AVAILABLE_STATUSES - valid_statuses_for_when).each do |status_for_prior_stages| + let(:current_status) { status_for_prior_stages } - expect(build).to be_manual + context "when status for prior stages is #{status_for_prior_stages}" do + %w[created pending].each do |status| + context "when build status is #{status}" do + let(:build) { create(:ci_build, status.to_sym, :schedulable, user: user, project: project) } + + it 'skips the build' do + expect { subject }.to change { build.status }.to('skipped') + end + end + end + + (HasStatus::AVAILABLE_STATUSES - %w[created pending]).each do |status| + context "when build status is #{status}" do + let(:build) { create(:ci_build, status.to_sym, :schedulable, user: user, project: project) } + + it 'does not change build status' do + expect { subject }.not_to change { build.status } + end + end + end + end end end - context 'when build does not have any actions' do - let(:build) { create(:ci_build, :created, user: user, project: project) } + context 'when build has on_success option' do + let(:when_option) { :on_success } - it 'enqueues the build' do - subject + it_behaves_like 'Enqueuing properly', %w[success skipped] + end + + context 'when build has on_failure option' do + let(:when_option) { :on_failure } + + it_behaves_like 'Enqueuing properly', %w[failed] + end + + context 'when build has always option' do + let(:when_option) { :always } + + it_behaves_like 'Enqueuing properly', %w[success failed skipped] + end + + context 'when build has manual option' do + let(:when_option) { :manual } + + it_behaves_like 'Actionizing properly', %w[success skipped] + end + + context 'when build has delayed option' do + let(:when_option) { :delayed } - expect(build).to be_pending + before do + allow(Ci::BuildScheduleWorker).to receive(:perform_at) { } end + + it_behaves_like 'Scheduling properly', %w[success skipped] end end -- cgit v1.2.1 From 19fb42b5ca917d94b44544e596b9e474e50e0907 Mon Sep 17 00:00:00 2001 From: Shinya Maeda Date: Fri, 28 Sep 2018 17:26:45 +0900 Subject: Add spec for Build::Factory --- spec/lib/gitlab/ci/status/build/factory_spec.rb | 49 +++++++++++++++++++++++++ 1 file changed, 49 insertions(+) (limited to 'spec') diff --git a/spec/lib/gitlab/ci/status/build/factory_spec.rb b/spec/lib/gitlab/ci/status/build/factory_spec.rb index 8b92088902b..1073c4b7ccd 100644 --- a/spec/lib/gitlab/ci/status/build/factory_spec.rb +++ b/spec/lib/gitlab/ci/status/build/factory_spec.rb @@ -319,4 +319,53 @@ describe Gitlab::Ci::Status::Build::Factory do end end end + + context 'when build is a delayed action' do + let(:build) { create(:ci_build, :scheduled) } + + it 'matches correct core status' do + expect(factory.core_status).to be_a Gitlab::Ci::Status::Scheduled + end + + it 'matches correct extended statuses' do + expect(factory.extended_statuses) + .to eq [Gitlab::Ci::Status::Build::Scheduled, + Gitlab::Ci::Status::Build::Play, + Gitlab::Ci::Status::Build::Action] + end + + it 'fabricates action detailed status' do + expect(status).to be_a Gitlab::Ci::Status::Build::Action + end + + it 'fabricates status with correct details' do + expect(status.text).to eq 'scheduled' + expect(status.group).to eq 'scheduled' + expect(status.icon).to eq 'status_scheduled' + expect(status.favicon).to eq 'favicon_status_scheduled' + expect(status.illustration).to include(:image, :size, :title, :content) + expect(status.label).to include 'manual play action' + expect(status).to have_details + expect(status.action_path).to include 'play' + end + + context 'when user has ability to play action' do + it 'fabricates status that has action' do + expect(status).to have_action + end + end + + context 'when user does not have ability to play action' do + before do + allow(build.project).to receive(:empty_repo?).and_return(false) + + create(:protected_branch, :no_one_can_push, + name: build.ref, project: build.project) + end + + it 'fabricates status that has no action' do + expect(status).not_to have_action + end + end + end end -- cgit v1.2.1 From 384da9279eefd7ebcdfd684ff234540d935ededd Mon Sep 17 00:00:00 2001 From: Shinya Maeda Date: Mon, 1 Oct 2018 13:57:11 +0900 Subject: Fix spec --- spec/lib/gitlab/ci/status/pipeline/factory_spec.rb | 6 +++--- spec/services/ci/run_scheduled_build_service_spec.rb | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) (limited to 'spec') diff --git a/spec/lib/gitlab/ci/status/pipeline/factory_spec.rb b/spec/lib/gitlab/ci/status/pipeline/factory_spec.rb index 8e3d4464898..d83f260927f 100644 --- a/spec/lib/gitlab/ci/status/pipeline/factory_spec.rb +++ b/spec/lib/gitlab/ci/status/pipeline/factory_spec.rb @@ -32,10 +32,10 @@ describe Gitlab::Ci::Status::Pipeline::Factory do it 'does not match extended statuses' do expect(factory.extended_statuses).to be_empty end - end - it "fabricates a core status #{simple_status}" do - expect(status).to be_a expected_status + it "fabricates a core status #{simple_status}" do + expect(status).to be_a expected_status + end end it 'extends core status with common pipeline methods' do diff --git a/spec/services/ci/run_scheduled_build_service_spec.rb b/spec/services/ci/run_scheduled_build_service_spec.rb index 145905db0cf..be2aad33ef4 100644 --- a/spec/services/ci/run_scheduled_build_service_spec.rb +++ b/spec/services/ci/run_scheduled_build_service_spec.rb @@ -29,7 +29,7 @@ describe Ci::RunScheduledBuildService do context 'when scheduled_at is not expired' do let(:build) { create(:ci_build, :scheduled, user: user, project: project, pipeline: pipeline) } - it 'can run the build' do + it 'can not run the build' do expect { subject }.to raise_error(StateMachines::InvalidTransition) expect(build).to be_scheduled -- cgit v1.2.1 From 533f5ca4c9f899910f9cdc4f0e0b43d619a9c7df Mon Sep 17 00:00:00 2001 From: Shinya Maeda Date: Mon, 1 Oct 2018 17:09:07 +0900 Subject: Fix spec --- spec/services/ci/process_pipeline_service_spec.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'spec') diff --git a/spec/services/ci/process_pipeline_service_spec.rb b/spec/services/ci/process_pipeline_service_spec.rb index 4f1e487197e..8c7258c42ad 100644 --- a/spec/services/ci/process_pipeline_service_spec.rb +++ b/spec/services/ci/process_pipeline_service_spec.rb @@ -395,7 +395,7 @@ describe Ci::ProcessPipelineService, '#execute' do enqueue_scheduled('delayed1') expect(builds_names_and_statuses).to eq({ 'delayed1': 'pending', 'delayed2': 'scheduled' }) - expect(pipeline.reload.status).to eq 'scheduled' + expect(pipeline.reload.status).to eq 'running' end end -- cgit v1.2.1 From 786ae683679d90a0e55bfe844ac694aeb7d68ce6 Mon Sep 17 00:00:00 2001 From: Winnie Hellmann Date: Mon, 1 Oct 2018 12:55:09 +0200 Subject: Do not omit leading zeros in duration_in_numbers helper --- spec/helpers/time_helper_spec.rb | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'spec') diff --git a/spec/helpers/time_helper_spec.rb b/spec/helpers/time_helper_spec.rb index 37455c3e491..cc310766433 100644 --- a/spec/helpers/time_helper_spec.rb +++ b/spec/helpers/time_helper_spec.rb @@ -39,10 +39,10 @@ describe TimeHelper do context "with allow_overflow = true" do where(:duration, :formatted_string) do - 0 | "00:00" - 1.second | "00:01" - 42.seconds | "00:42" - 2.minutes + 1.second | "02:01" + 0 | "00:00:00" + 1.second | "00:00:01" + 42.seconds | "00:00:42" + 2.minutes + 1.second | "00:02:01" 3.hours + 2.minutes + 1.second | "03:02:01" 30.hours | "30:00:00" end -- cgit v1.2.1 From fc8d4c7046807ac65e36ce65df982ff5c4ff4a9a Mon Sep 17 00:00:00 2001 From: Winnie Hellmann Date: Mon, 1 Oct 2018 15:21:33 +0200 Subject: Add scheduled job dropdown to pipelines list --- spec/javascripts/datetime_utility_spec.js | 25 +++++++++++++++++++------ 1 file changed, 19 insertions(+), 6 deletions(-) (limited to 'spec') diff --git a/spec/javascripts/datetime_utility_spec.js b/spec/javascripts/datetime_utility_spec.js index 492171684dc..6c3e73f134e 100644 --- a/spec/javascripts/datetime_utility_spec.js +++ b/spec/javascripts/datetime_utility_spec.js @@ -6,9 +6,7 @@ describe('Date time utils', () => { const date = new Date(); date.setFullYear(date.getFullYear() - 1); - expect( - datetimeUtility.timeFor(date), - ).toBe('Past due'); + expect(datetimeUtility.timeFor(date)).toBe('Past due'); }); it('returns remaining time when in the future', () => { @@ -19,9 +17,7 @@ describe('Date time utils', () => { // short of a full year, timeFor will return '11 months remaining' date.setDate(date.getDate() + 1); - expect( - datetimeUtility.timeFor(date), - ).toBe('1 year remaining'); + expect(datetimeUtility.timeFor(date)).toBe('1 year remaining'); }); }); @@ -168,3 +164,20 @@ describe('getTimeframeWindowFrom', () => { }); }); }); + +describe('formatTime', () => { + const expectedTimestamps = [ + [0, '00:00:00'], + [1000, '00:00:01'], + [42000, '00:00:42'], + [121000, '00:02:01'], + [10921000, '03:02:01'], + [108000000, '30:00:00'], + ]; + + expectedTimestamps.forEach(([milliseconds, expectedTimestamp]) => { + it(`formats ${milliseconds}ms as ${expectedTimestamp}`, () => { + expect(datetimeUtility.formatTime(milliseconds)).toBe(expectedTimestamp); + }); + }); +}); -- cgit v1.2.1 From 46fc55993a295b3832f82359d9a6ac4cd1ee8aa7 Mon Sep 17 00:00:00 2001 From: Shinya Maeda Date: Tue, 2 Oct 2018 13:43:45 +0900 Subject: Add feature flag spec for process_build_service --- spec/services/ci/process_build_service_spec.rb | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) (limited to 'spec') diff --git a/spec/services/ci/process_build_service_spec.rb b/spec/services/ci/process_build_service_spec.rb index 692f28c80cb..9f47439dc4a 100644 --- a/spec/services/ci/process_build_service_spec.rb +++ b/spec/services/ci/process_build_service_spec.rb @@ -204,6 +204,20 @@ describe Ci::ProcessBuildService, '#execute' do allow(Ci::BuildScheduleWorker).to receive(:perform_at) { } end - it_behaves_like 'Scheduling properly', %w[success skipped] + context 'when ci_enable_scheduled_build is enabled' do + before do + stub_feature_flags(ci_enable_scheduled_build: true) + end + + it_behaves_like 'Scheduling properly', %w[success skipped] + end + + context 'when ci_enable_scheduled_build is enabled' do + before do + stub_feature_flags(ci_enable_scheduled_build: false) + end + + it_behaves_like 'Actionizing properly', %w[success skipped] + end end end -- cgit v1.2.1 From 4dd70b9e1e67b50d846b4fb48c0ff942104119a5 Mon Sep 17 00:00:00 2001 From: Shinya Maeda Date: Tue, 2 Oct 2018 18:10:58 +0900 Subject: Fix spec --- spec/lib/gitlab/ci/status/build/factory_spec.rb | 6 +++--- spec/lib/gitlab/ci/status/pipeline/blocked_spec.rb | 2 +- spec/lib/gitlab/ci/status/pipeline/factory_spec.rb | 7 ++++++- spec/lib/gitlab/import_export/all_models.yml | 1 + spec/workers/stuck_ci_jobs_worker_spec.rb | 2 +- 5 files changed, 12 insertions(+), 6 deletions(-) (limited to 'spec') diff --git a/spec/lib/gitlab/ci/status/build/factory_spec.rb b/spec/lib/gitlab/ci/status/build/factory_spec.rb index 1073c4b7ccd..aa53ecd5967 100644 --- a/spec/lib/gitlab/ci/status/build/factory_spec.rb +++ b/spec/lib/gitlab/ci/status/build/factory_spec.rb @@ -330,7 +330,7 @@ describe Gitlab::Ci::Status::Build::Factory do it 'matches correct extended statuses' do expect(factory.extended_statuses) .to eq [Gitlab::Ci::Status::Build::Scheduled, - Gitlab::Ci::Status::Build::Play, + Gitlab::Ci::Status::Build::Unschedule, Gitlab::Ci::Status::Build::Action] end @@ -344,9 +344,9 @@ describe Gitlab::Ci::Status::Build::Factory do expect(status.icon).to eq 'status_scheduled' expect(status.favicon).to eq 'favicon_status_scheduled' expect(status.illustration).to include(:image, :size, :title, :content) - expect(status.label).to include 'manual play action' + expect(status.label).to include 'unschedule action' expect(status).to have_details - expect(status.action_path).to include 'play' + expect(status.action_path).to include 'unschedule' end context 'when user has ability to play action' do diff --git a/spec/lib/gitlab/ci/status/pipeline/blocked_spec.rb b/spec/lib/gitlab/ci/status/pipeline/blocked_spec.rb index 49a25b4a389..1a2b952d374 100644 --- a/spec/lib/gitlab/ci/status/pipeline/blocked_spec.rb +++ b/spec/lib/gitlab/ci/status/pipeline/blocked_spec.rb @@ -15,7 +15,7 @@ describe Gitlab::Ci::Status::Pipeline::Blocked do describe '#label' do it 'overrides status label' do - expect(subject.label).to eq 'waiting for manual action or delayed job' + expect(subject.label).to eq 'waiting for manual action' end end diff --git a/spec/lib/gitlab/ci/status/pipeline/factory_spec.rb b/spec/lib/gitlab/ci/status/pipeline/factory_spec.rb index d83f260927f..694d4ce160a 100644 --- a/spec/lib/gitlab/ci/status/pipeline/factory_spec.rb +++ b/spec/lib/gitlab/ci/status/pipeline/factory_spec.rb @@ -23,11 +23,16 @@ describe Gitlab::Ci::Status::Pipeline::Factory do expect(factory.core_status).to be_a expected_status end - if HasStatus::BLOCKED_STATUS.include?(simple_status) + if simple_status == 'manual' it 'matches a correct extended statuses' do expect(factory.extended_statuses) .to eq [Gitlab::Ci::Status::Pipeline::Blocked] end + elsif simple_status == 'scheduled' + it 'matches a correct extended statuses' do + expect(factory.extended_statuses) + .to eq [Gitlab::Ci::Status::Pipeline::Scheduled] + end else it 'does not match extended statuses' do expect(factory.extended_statuses).to be_empty diff --git a/spec/lib/gitlab/import_export/all_models.yml b/spec/lib/gitlab/import_export/all_models.yml index ec2bdbe22e1..fe167033941 100644 --- a/spec/lib/gitlab/import_export/all_models.yml +++ b/spec/lib/gitlab/import_export/all_models.yml @@ -117,6 +117,7 @@ pipelines: - retryable_builds - cancelable_statuses - manual_actions +- scheduled_actions - artifacts - pipeline_schedule - merge_requests diff --git a/spec/workers/stuck_ci_jobs_worker_spec.rb b/spec/workers/stuck_ci_jobs_worker_spec.rb index 2f8ba4859d7..f38bc11f7f0 100644 --- a/spec/workers/stuck_ci_jobs_worker_spec.rb +++ b/spec/workers/stuck_ci_jobs_worker_spec.rb @@ -143,7 +143,7 @@ describe StuckCiJobsWorker do expect(Ci::Build.scheduled.count).to eq(0) expect(job).to be_failed - expect(job).to be_schedule_expired + expect(job).to be_stale_schedule end end -- cgit v1.2.1 From 7fe14c42a913c683bd6f7c4f8791fff63db3c499 Mon Sep 17 00:00:00 2001 From: Shinya Maeda Date: Tue, 2 Oct 2018 18:47:41 +0900 Subject: Add integration spec --- spec/controllers/projects/jobs_controller_spec.rb | 40 +++++++++++++++++++++++ 1 file changed, 40 insertions(+) (limited to 'spec') diff --git a/spec/controllers/projects/jobs_controller_spec.rb b/spec/controllers/projects/jobs_controller_spec.rb index fd11cb31a2a..f1eefdbaaaf 100644 --- a/spec/controllers/projects/jobs_controller_spec.rb +++ b/spec/controllers/projects/jobs_controller_spec.rb @@ -632,6 +632,46 @@ describe Projects::JobsController, :clean_gitlab_redis_shared_state do end end + describe 'POST unschedule' do + before do + project.add_developer(user) + + create(:protected_branch, :developers_can_merge, + name: 'master', project: project) + + sign_in(user) + + post_unschedule + end + + context 'when job is scheduled' do + let(:job) { create(:ci_build, :scheduled, pipeline: pipeline) } + + it 'redirects to the unscheduled job page' do + expect(response).to have_gitlab_http_status(:found) + expect(response).to redirect_to(namespace_project_job_path(id: job.id)) + end + + it 'transits to manual' do + expect(job.reload).to be_manual + end + end + + context 'when job is not scheduled' do + let(:job) { create(:ci_build, pipeline: pipeline) } + + it 'renders unprocessable_entity' do + expect(response).to have_gitlab_http_status(:unprocessable_entity) + end + end + + def post_unschedule + post :unschedule, namespace_id: project.namespace, + project_id: project, + id: job.id + end + end + describe 'POST cancel_all' do before do project.add_developer(user) -- cgit v1.2.1 From 9613f7e2fb2d5b4190adff29107b1bca6993fd41 Mon Sep 17 00:00:00 2001 From: Shinya Maeda Date: Tue, 2 Oct 2018 19:45:39 +0900 Subject: Stub feature flag for spec --- spec/models/ci/build_spec.rb | 4 ++++ spec/services/ci/run_scheduled_build_service_spec.rb | 4 ++++ 2 files changed, 8 insertions(+) (limited to 'spec') diff --git a/spec/models/ci/build_spec.rb b/spec/models/ci/build_spec.rb index 83add15fab7..ffad82c7820 100644 --- a/spec/models/ci/build_spec.rb +++ b/spec/models/ci/build_spec.rb @@ -327,6 +327,10 @@ describe Ci::Build do describe '#enqueue_scheduled' do subject { build.enqueue_scheduled } + before do + stub_feature_flags(ci_enable_scheduled_build: true) + end + context 'when build is scheduled and the right time has not come yet' do let(:build) { create(:ci_build, :scheduled, pipeline: pipeline) } diff --git a/spec/services/ci/run_scheduled_build_service_spec.rb b/spec/services/ci/run_scheduled_build_service_spec.rb index be2aad33ef4..2c921dac238 100644 --- a/spec/services/ci/run_scheduled_build_service_spec.rb +++ b/spec/services/ci/run_scheduled_build_service_spec.rb @@ -7,6 +7,10 @@ describe Ci::RunScheduledBuildService do subject { described_class.new(project, user).execute(build) } + before do + stub_feature_flags(ci_enable_scheduled_build: true) + end + context 'when user can update build' do before do project.add_developer(user) -- cgit v1.2.1 From c5b2c66b0fcb1f8d1f6530b359be4310427cd98d Mon Sep 17 00:00:00 2001 From: Alessio Caiazza Date: Tue, 2 Oct 2018 15:50:36 +0200 Subject: fix style --- spec/controllers/projects/jobs_controller_spec.rb | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'spec') diff --git a/spec/controllers/projects/jobs_controller_spec.rb b/spec/controllers/projects/jobs_controller_spec.rb index f1eefdbaaaf..5b09e4a082c 100644 --- a/spec/controllers/projects/jobs_controller_spec.rb +++ b/spec/controllers/projects/jobs_controller_spec.rb @@ -667,8 +667,8 @@ describe Projects::JobsController, :clean_gitlab_redis_shared_state do def post_unschedule post :unschedule, namespace_id: project.namespace, - project_id: project, - id: job.id + project_id: project, + id: job.id end end -- cgit v1.2.1 From e5e307dd75f74c5e98b039332c58170dc9c2735f Mon Sep 17 00:00:00 2001 From: Alessio Caiazza Date: Tue, 2 Oct 2018 15:52:39 +0200 Subject: delay scheduled_at evaluation in factory --- spec/factories/ci/builds.rb | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'spec') diff --git a/spec/factories/ci/builds.rb b/spec/factories/ci/builds.rb index 73fa16fe6bf..7a4b1dfafac 100644 --- a/spec/factories/ci/builds.rb +++ b/spec/factories/ci/builds.rb @@ -73,13 +73,13 @@ FactoryBot.define do trait :scheduled do schedulable status 'scheduled' - scheduled_at 1.minute.since + scheduled_at { 1.minute.since } end trait :expired_scheduled do schedulable status 'scheduled' - scheduled_at 1.minute.ago + scheduled_at { 1.minute.ago } end trait :manual do -- cgit v1.2.1 From 5905d89b924fc518a3896ac6b4ccec11a164df5d Mon Sep 17 00:00:00 2001 From: Shinya Maeda Date: Wed, 3 Oct 2018 15:05:50 +0900 Subject: Add spec for build presenter --- spec/presenters/ci/build_presenter_spec.rb | 36 ++++++++++++++++++++++++++++++ 1 file changed, 36 insertions(+) (limited to 'spec') diff --git a/spec/presenters/ci/build_presenter_spec.rb b/spec/presenters/ci/build_presenter_spec.rb index 547d95e0908..b2fe10bb0b0 100644 --- a/spec/presenters/ci/build_presenter_spec.rb +++ b/spec/presenters/ci/build_presenter_spec.rb @@ -218,6 +218,42 @@ describe Ci::BuildPresenter do end end + describe '#execute_in' do + subject { presenter.execute_in } + + context 'when build is scheduled' do + context 'when schedule is not expired' do + let(:build) { create(:ci_build, :scheduled) } + + it 'returns execution time' do + Timecop.freeze do + is_expected.to eq(60.0) + end + end + end + + context 'when schedule is expired' do + let(:build) { create(:ci_build, :expired_scheduled) } + + it 'returns execution time' do + Timecop.freeze do + is_expected.to eq(0) + end + end + end + end + + context 'when build is not delayed' do + let(:build) { create(:ci_build) } + + it 'does not return execution time' do + Timecop.freeze do + is_expected.to be_falsy + end + end + end + end + describe '#callout_failure_message' do let(:build) { create(:ci_build, :failed, :api_failure) } -- cgit v1.2.1 From 66b3bd5e2689c735675dc192746c972ebf627a97 Mon Sep 17 00:00:00 2001 From: Shinya Maeda Date: Wed, 3 Oct 2018 15:09:48 +0900 Subject: Add spec for build_action_entity_spec --- spec/serializers/build_action_entity_spec.rb | 12 ++++++++++++ 1 file changed, 12 insertions(+) (limited to 'spec') diff --git a/spec/serializers/build_action_entity_spec.rb b/spec/serializers/build_action_entity_spec.rb index 15720d86583..9e2bee2ee60 100644 --- a/spec/serializers/build_action_entity_spec.rb +++ b/spec/serializers/build_action_entity_spec.rb @@ -22,5 +22,17 @@ describe BuildActionEntity do it 'contains whether it is playable' do expect(subject[:playable]).to eq job.playable? end + + context 'when job is scheduled' do + let(:job) { create(:ci_build, :scheduled) } + + it 'returns scheduled_at' do + expect(subject[:scheduled_at]).to eq(job.scheduled_at) + end + + it 'returns unschedule path' do + expect(subject[:unschedule_path]).to include "jobs/#{job.id}/unschedule" + end + end end end -- cgit v1.2.1 From 137f74b56396bc8feee87ead9c827ccc0fb47cd2 Mon Sep 17 00:00:00 2001 From: Shinya Maeda Date: Wed, 3 Oct 2018 15:17:12 +0900 Subject: Add job_entity_spec --- spec/serializers/job_entity_spec.rb | 12 ++++++++++++ 1 file changed, 12 insertions(+) (limited to 'spec') diff --git a/spec/serializers/job_entity_spec.rb b/spec/serializers/job_entity_spec.rb index 8e1ca3f308d..5fc27da4906 100644 --- a/spec/serializers/job_entity_spec.rb +++ b/spec/serializers/job_entity_spec.rb @@ -109,6 +109,18 @@ describe JobEntity do end end + context 'when job is scheduled' do + let(:job) { create(:ci_build, :scheduled) } + + it 'contains path to unschedule action' do + expect(subject).to include(:unschedule_path) + end + + it 'contains scheduled_at' do + expect(subject[:scheduled_at]).to eq(job.scheduled_at) + end + end + context 'when job is generic commit status' do let(:job) { create(:generic_commit_status, target_url: 'http://google.com') } -- cgit v1.2.1 From 64d1eabf86d1717d033b38a72b1b6563b8d001c7 Mon Sep 17 00:00:00 2001 From: Shinya Maeda Date: Wed, 3 Oct 2018 15:18:44 +0900 Subject: Add spec for pipeline_details_entity_spec --- spec/serializers/pipeline_details_entity_spec.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'spec') diff --git a/spec/serializers/pipeline_details_entity_spec.rb b/spec/serializers/pipeline_details_entity_spec.rb index 45e18086894..8e73a3e67c6 100644 --- a/spec/serializers/pipeline_details_entity_spec.rb +++ b/spec/serializers/pipeline_details_entity_spec.rb @@ -29,7 +29,7 @@ describe PipelineDetailsEntity do expect(subject[:details]) .to include :duration, :finished_at expect(subject[:details]) - .to include :stages, :artifacts, :manual_actions + .to include :stages, :artifacts, :manual_actions, :scheduled_actions expect(subject[:details][:status]).to include :icon, :favicon, :text, :label end -- cgit v1.2.1 From 5f3c1a541228a6b042e9bfd33eb6058008a3a345 Mon Sep 17 00:00:00 2001 From: Shinya Maeda Date: Wed, 3 Oct 2018 15:25:17 +0900 Subject: Add spec for Gitlab::Ci::Status::Build::Unschedule --- spec/lib/gitlab/ci/status/build/unschedule_spec.rb | 94 ++++++++++++++++++++++ 1 file changed, 94 insertions(+) create mode 100644 spec/lib/gitlab/ci/status/build/unschedule_spec.rb (limited to 'spec') diff --git a/spec/lib/gitlab/ci/status/build/unschedule_spec.rb b/spec/lib/gitlab/ci/status/build/unschedule_spec.rb new file mode 100644 index 00000000000..ed046d66ca5 --- /dev/null +++ b/spec/lib/gitlab/ci/status/build/unschedule_spec.rb @@ -0,0 +1,94 @@ +require 'spec_helper' + +describe Gitlab::Ci::Status::Build::Unschedule do + let(:status) { double('core status') } + let(:user) { double('user') } + + subject do + described_class.new(status) + end + + describe '#label' do + it { expect(subject.label).to eq 'unschedule action' } + end + + describe 'action details' do + let(:user) { create(:user) } + let(:build) { create(:ci_build) } + let(:status) { Gitlab::Ci::Status::Core.new(build, user) } + + describe '#has_action?' do + context 'when user is allowed to update build' do + before do + stub_not_protect_default_branch + + build.project.add_developer(user) + end + + it { is_expected.to have_action } + end + + context 'when user is not allowed to update build' do + it { is_expected.not_to have_action } + end + end + + describe '#action_path' do + it { expect(subject.action_path).to include "#{build.id}/unschedule" } + end + + describe '#action_icon' do + it { expect(subject.action_icon).to eq 'time-out' } + end + + describe '#action_title' do + it { expect(subject.action_title).to eq 'Unschedule' } + end + + describe '#action_button_title' do + it { expect(subject.action_button_title).to eq 'Unschedule job' } + end + end + + describe '.matches?' do + subject { described_class.matches?(build, user) } + + context 'when build is scheduled' do + context 'when build unschedules an delayed job' do + let(:build) { create(:ci_build, :scheduled) } + + it 'is a correct match' do + expect(subject).to be true + end + end + + context 'when build unschedules an normal job' do + let(:build) { create(:ci_build) } + + it 'does not match' do + expect(subject).to be false + end + end + end + end + + describe '#status_tooltip' do + it 'does not override status status_tooltip' do + expect(status).to receive(:status_tooltip) + + subject.status_tooltip + end + end + + describe '#badge_tooltip' do + let(:user) { create(:user) } + let(:build) { create(:ci_build, :playable) } + let(:status) { Gitlab::Ci::Status::Core.new(build, user) } + + it 'does not override status badge_tooltip' do + expect(status).to receive(:badge_tooltip) + + subject.badge_tooltip + end + end +end -- cgit v1.2.1 From 1da4ae719a704125738f2be2544ba134ebfec385 Mon Sep 17 00:00:00 2001 From: Shinya Maeda Date: Wed, 3 Oct 2018 15:28:17 +0900 Subject: Add spec for Status::Pipeline::Scheduled --- spec/factories/ci/pipelines.rb | 4 +++ .../gitlab/ci/status/pipeline/scheduled_spec.rb | 42 ++++++++++++++++++++++ 2 files changed, 46 insertions(+) create mode 100644 spec/lib/gitlab/ci/status/pipeline/scheduled_spec.rb (limited to 'spec') diff --git a/spec/factories/ci/pipelines.rb b/spec/factories/ci/pipelines.rb index 9fef424e425..8a44ce52849 100644 --- a/spec/factories/ci/pipelines.rb +++ b/spec/factories/ci/pipelines.rb @@ -54,6 +54,10 @@ FactoryBot.define do status :manual end + trait :scheduled do + status :scheduled + end + trait :success do status :success end diff --git a/spec/lib/gitlab/ci/status/pipeline/scheduled_spec.rb b/spec/lib/gitlab/ci/status/pipeline/scheduled_spec.rb new file mode 100644 index 00000000000..29afa08b56b --- /dev/null +++ b/spec/lib/gitlab/ci/status/pipeline/scheduled_spec.rb @@ -0,0 +1,42 @@ +require 'spec_helper' + +describe Gitlab::Ci::Status::Pipeline::Scheduled do + let(:pipeline) { double('pipeline') } + + subject do + described_class.new(pipeline) + end + + describe '#text' do + it 'overrides status text' do + expect(subject.text).to eq 'scheduled' + end + end + + describe '#label' do + it 'overrides status label' do + expect(subject.label).to eq 'waiting for delayed job' + end + end + + describe '.matches?' do + let(:user) { double('user') } + subject { described_class.matches?(pipeline, user) } + + context 'when pipeline is scheduled' do + let(:pipeline) { create(:ci_pipeline, :scheduled) } + + it 'is a correct match' do + expect(subject).to be true + end + end + + context 'when pipeline is not scheduled' do + let(:pipeline) { create(:ci_pipeline, :success) } + + it 'does not match' do + expect(subject).to be false + end + end + end +end -- cgit v1.2.1 From 9621bbb94cde3d33fce3c2c25fb98748f7a1824a Mon Sep 17 00:00:00 2001 From: Shinya Maeda Date: Wed, 3 Oct 2018 16:11:08 +0900 Subject: Add feature spec --- spec/features/projects/jobs_spec.rb | 25 +++++++++++++++ spec/features/projects/pipelines/pipeline_spec.rb | 34 ++++++++++++++++++++ spec/features/projects/pipelines/pipelines_spec.rb | 37 ++++++++++++++++++++++ 3 files changed, 96 insertions(+) (limited to 'spec') diff --git a/spec/features/projects/jobs_spec.rb b/spec/features/projects/jobs_spec.rb index d0bf4975b81..5b767c96910 100644 --- a/spec/features/projects/jobs_spec.rb +++ b/spec/features/projects/jobs_spec.rb @@ -429,6 +429,31 @@ describe 'Jobs', :clean_gitlab_redis_shared_state do end end + context 'Delayed job' do + let(:job) { create(:ci_build, :scheduled, pipeline: pipeline) } + + before do + project.add_developer(user) + visit project_job_path(project, job) + end + + it 'shows delayed job' do + expect(page).to have_content(job.detailed_status(user).illustration[:title]) + expect(page).to have_content('This is a scheduled to run in') + expect(page).to have_content("This job will automatically run after it's timer finishes.") + expect(page).to have_link('Unschedule job') + end + + it 'unschedule delayed job and shows manual action', :js do + click_link 'Unschedule job' + + wait_for_requests + expect(page).to have_content('This job requires a manual action') + expect(page).to have_content('This job depends on a user to trigger its process. Often they are used to deploy code to production environments') + expect(page).to have_link('Trigger this manual action') + end + end + context 'Non triggered job' do let(:job) { create(:ci_build, :created, pipeline: pipeline) } diff --git a/spec/features/projects/pipelines/pipeline_spec.rb b/spec/features/projects/pipelines/pipeline_spec.rb index 603503a531c..b728f4c00f2 100644 --- a/spec/features/projects/pipelines/pipeline_spec.rb +++ b/spec/features/projects/pipelines/pipeline_spec.rb @@ -31,6 +31,11 @@ describe 'Pipeline', :js do pipeline: pipeline, stage: 'deploy', name: 'manual-build') end + let!(:build_scheduled) do + create(:ci_build, :scheduled, + pipeline: pipeline, stage: 'deploy', name: 'delayed-job') + end + let!(:build_external) do create(:generic_commit_status, status: 'success', pipeline: pipeline, @@ -105,6 +110,25 @@ describe 'Pipeline', :js do end end + context 'when pipeline has scheduled builds' do + it 'shows the scheduled icon and a unschedule action for the scheduled build' do + page.within('#ci-badge-delayed-job') do + expect(page).to have_selector('.js-ci-status-icon-scheduled') + expect(page).to have_content('delayed-job') + end + + page.within('#ci-badge-delayed-job .ci-action-icon-container.js-icon-time-out') do + expect(page).to have_selector('svg') + end + end + + it 'should be possible to unschedule the scheduled job' do + find('#ci-badge-delayed-job .ci-action-icon-container').click + + expect(page).not_to have_content('Unschedule job') + end + end + context 'when pipeline has failed builds' do it 'shows the failed icon and a retry action for the failed build' do page.within('#ci-badge-test') do @@ -315,6 +339,16 @@ describe 'Pipeline', :js do it { expect(build_manual.reload).to be_pending } end + context 'unscheduling scheduled job' do + before do + within '.pipeline-holder' do + click_link('Unschedule') + end + end + + it { expect(build_scheduled.reload).to be_manual } + end + context 'failed jobs' do it 'displays a tooltip with the failure reason' do page.within('.ci-table') do diff --git a/spec/features/projects/pipelines/pipelines_spec.rb b/spec/features/projects/pipelines/pipelines_spec.rb index 41822babbc9..43f9608e8e3 100644 --- a/spec/features/projects/pipelines/pipelines_spec.rb +++ b/spec/features/projects/pipelines/pipelines_spec.rb @@ -232,6 +232,43 @@ describe 'Pipelines', :js do end end + context 'with delayed job' do + let!(:delayed_job) do + create(:ci_build, :scheduled, + pipeline: pipeline, + name: 'delayed job', + stage: 'test', + commands: 'test') + end + + before do + visit_project_pipelines + end + + it 'has a dropdown with play button' do + expect(page).to have_selector('.dropdown-new.btn.btn-default .icon-play') + end + + it 'has link to the scheduled action' do + find('.js-pipeline-dropdown-manual-actions').click + + expect(page).to have_button('delayed job') + end + + context 'when scheduled action was played' do + before do + accept_confirm do + find('.js-pipeline-dropdown-manual-actions').click + click_button('delayed job') + end + end + + it 'enqueues scheduled action job' do + expect(page).to have_selector('.js-pipeline-dropdown-manual-actions:disabled') + end + end + end + context 'for generic statuses' do context 'when running' do let!(:running) do -- cgit v1.2.1 From 980c0e19d7c78cfe071620aac5a28a868d05f9f6 Mon Sep 17 00:00:00 2001 From: Shinya Maeda Date: Wed, 3 Oct 2018 17:46:40 +0900 Subject: Fix pipeline spec --- spec/features/projects/pipelines/pipeline_spec.rb | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'spec') diff --git a/spec/features/projects/pipelines/pipeline_spec.rb b/spec/features/projects/pipelines/pipeline_spec.rb index b728f4c00f2..e6cb137b023 100644 --- a/spec/features/projects/pipelines/pipeline_spec.rb +++ b/spec/features/projects/pipelines/pipeline_spec.rb @@ -87,7 +87,9 @@ describe 'Pipeline', :js do it 'should be possible to cancel the running build' do find('#ci-badge-deploy .ci-action-icon-container').click - expect(page).not_to have_content('Cancel running') + page.within('#ci-badge-deploy') do + expect(page).to have_css('.js-icon-retry') + end end end -- cgit v1.2.1 From 5974eff83c1d0cbc1445e3a8b4b30c540663d5f9 Mon Sep 17 00:00:00 2001 From: Shinya Maeda Date: Wed, 3 Oct 2018 18:52:18 +0900 Subject: Improve performance of stale scheduled builds search --- spec/workers/stuck_ci_jobs_worker_spec.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'spec') diff --git a/spec/workers/stuck_ci_jobs_worker_spec.rb b/spec/workers/stuck_ci_jobs_worker_spec.rb index f38bc11f7f0..557934346c9 100644 --- a/spec/workers/stuck_ci_jobs_worker_spec.rb +++ b/spec/workers/stuck_ci_jobs_worker_spec.rb @@ -127,7 +127,7 @@ describe StuckCiJobsWorker do end end - describe 'drop_stale_scheduled_builds' do + describe 'drop stale scheduled builds' do let(:status) { 'scheduled' } let(:updated_at) { } -- cgit v1.2.1 From 10b09db46ddfdc6dfab55fa9671e716cd46a565b Mon Sep 17 00:00:00 2001 From: Shinya Maeda Date: Thu, 4 Oct 2018 15:11:36 +0900 Subject: Avoid conflicts between enumlator's schedule! method and state machine's schedule! method --- spec/workers/pipeline_schedule_worker_spec.rb | 2 +- spec/workers/run_pipeline_schedule_worker_spec.rb | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) (limited to 'spec') diff --git a/spec/workers/pipeline_schedule_worker_spec.rb b/spec/workers/pipeline_schedule_worker_spec.rb index a2fe4734d47..3ce394789be 100644 --- a/spec/workers/pipeline_schedule_worker_spec.rb +++ b/spec/workers/pipeline_schedule_worker_spec.rb @@ -25,7 +25,7 @@ describe PipelineScheduleWorker do shared_examples 'successful scheduling' do it 'creates a new pipeline' do expect { subject }.to change { project.pipelines.count }.by(1) - expect(Ci::Pipeline.last).to be_schedule + expect(Ci::Pipeline.last).to be_source_schedule pipeline_schedule.reload expect(pipeline_schedule.next_run_at).to be > Time.now diff --git a/spec/workers/run_pipeline_schedule_worker_spec.rb b/spec/workers/run_pipeline_schedule_worker_spec.rb index 481a84837f9..afda3d9287b 100644 --- a/spec/workers/run_pipeline_schedule_worker_spec.rb +++ b/spec/workers/run_pipeline_schedule_worker_spec.rb @@ -30,7 +30,7 @@ describe RunPipelineScheduleWorker do it 'calls the Service' do expect(Ci::CreatePipelineService).to receive(:new).with(project, user, ref: pipeline_schedule.ref).and_return(create_pipeline_service) - expect(create_pipeline_service).to receive(:execute).with(:schedule, ignore_skip_ci: true, save_on_errors: false, schedule: pipeline_schedule) + expect(create_pipeline_service).to receive(:execute).with(:source_schedule, ignore_skip_ci: true, save_on_errors: false, schedule: pipeline_schedule) worker.perform(pipeline_schedule.id, user.id) end -- cgit v1.2.1 From f84db3cc917b595752389745eed9da70adee42b2 Mon Sep 17 00:00:00 2001 From: Shinya Maeda Date: Thu, 4 Oct 2018 16:35:05 +0900 Subject: Revert "Avoid conflicts between enumlator's schedule! method and state machine's schedule! method" This reverts commit 10b09db46ddfdc6dfab55fa9671e716cd46a565b. --- spec/workers/pipeline_schedule_worker_spec.rb | 2 +- spec/workers/run_pipeline_schedule_worker_spec.rb | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) (limited to 'spec') diff --git a/spec/workers/pipeline_schedule_worker_spec.rb b/spec/workers/pipeline_schedule_worker_spec.rb index 3ce394789be..a2fe4734d47 100644 --- a/spec/workers/pipeline_schedule_worker_spec.rb +++ b/spec/workers/pipeline_schedule_worker_spec.rb @@ -25,7 +25,7 @@ describe PipelineScheduleWorker do shared_examples 'successful scheduling' do it 'creates a new pipeline' do expect { subject }.to change { project.pipelines.count }.by(1) - expect(Ci::Pipeline.last).to be_source_schedule + expect(Ci::Pipeline.last).to be_schedule pipeline_schedule.reload expect(pipeline_schedule.next_run_at).to be > Time.now diff --git a/spec/workers/run_pipeline_schedule_worker_spec.rb b/spec/workers/run_pipeline_schedule_worker_spec.rb index afda3d9287b..481a84837f9 100644 --- a/spec/workers/run_pipeline_schedule_worker_spec.rb +++ b/spec/workers/run_pipeline_schedule_worker_spec.rb @@ -30,7 +30,7 @@ describe RunPipelineScheduleWorker do it 'calls the Service' do expect(Ci::CreatePipelineService).to receive(:new).with(project, user, ref: pipeline_schedule.ref).and_return(create_pipeline_service) - expect(create_pipeline_service).to receive(:execute).with(:source_schedule, ignore_skip_ci: true, save_on_errors: false, schedule: pipeline_schedule) + expect(create_pipeline_service).to receive(:execute).with(:schedule, ignore_skip_ci: true, save_on_errors: false, schedule: pipeline_schedule) worker.perform(pipeline_schedule.id, user.id) end -- cgit v1.2.1 From d3b9e4ef38f09a9be84b687f847984d5605cc95a Mon Sep 17 00:00:00 2001 From: Shinya Maeda Date: Thu, 4 Oct 2018 17:33:05 +0900 Subject: Fix spec according to the Ci::Pipeline#delay rename --- spec/models/ci/pipeline_spec.rb | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'spec') diff --git a/spec/models/ci/pipeline_spec.rb b/spec/models/ci/pipeline_spec.rb index 0a570394192..b19e75a956d 100644 --- a/spec/models/ci/pipeline_spec.rb +++ b/spec/models/ci/pipeline_spec.rb @@ -75,8 +75,8 @@ describe Ci::Pipeline, :mailer do end end - describe '#schedule' do - subject { pipeline.schedule } + describe '#delay' do + subject { pipeline.delay } let(:pipeline) { build(:ci_pipeline, status: :created) } -- cgit v1.2.1 From e84230ebb6db5ff9e5990e945aa1e1aebf4e9fa9 Mon Sep 17 00:00:00 2001 From: Shinya Maeda Date: Thu, 4 Oct 2018 18:59:34 +0900 Subject: Add limitation for start_in keyword --- spec/lib/gitlab/ci/config/entry/job_spec.rb | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) (limited to 'spec') diff --git a/spec/lib/gitlab/ci/config/entry/job_spec.rb b/spec/lib/gitlab/ci/config/entry/job_spec.rb index d745c4ca2ad..1169938b80c 100644 --- a/spec/lib/gitlab/ci/config/entry/job_spec.rb +++ b/spec/lib/gitlab/ci/config/entry/job_spec.rb @@ -44,9 +44,7 @@ describe Gitlab::Ci::Config::Entry::Job do context 'when start_in is specified' do let(:config) { { script: 'echo', when: 'delayed', start_in: '1 day' } } - it 'returns error about invalid type' do - expect(entry).to be_valid - end + it { expect(entry).to be_valid } end end end @@ -158,7 +156,7 @@ describe Gitlab::Ci::Config::Entry::Job do end end - context 'when start_in is not formateed ad a duration' do + context 'when start_in is not formatted as a duration' do let(:config) { { when: 'delayed', start_in: 'test' } } it 'returns error about invalid type' do @@ -166,6 +164,15 @@ describe Gitlab::Ci::Config::Entry::Job do expect(entry.errors).to include 'job start in should be a duration' end end + + context 'when start_in is longer than one day' do + let(:config) { { when: 'delayed', start_in: '2 days' } } + + it 'returns error about exceeding the limit' do + expect(entry).not_to be_valid + expect(entry.errors).to include 'job start in should not exceed the limit' + end + end end context 'when start_in specified without delayed specification' do -- cgit v1.2.1 From 4741c07f3fa61326665c36d4b9974025bf9dd9e9 Mon Sep 17 00:00:00 2001 From: Shinya Maeda Date: Thu, 4 Oct 2018 20:52:14 +0900 Subject: Groomed specs --- spec/features/projects/jobs_spec.rb | 2 +- spec/features/projects/pipelines/pipeline_spec.rb | 18 +++++++++++------- spec/features/projects/pipelines/pipelines_spec.rb | 19 +++++++++---------- 3 files changed, 21 insertions(+), 18 deletions(-) (limited to 'spec') diff --git a/spec/features/projects/jobs_spec.rb b/spec/features/projects/jobs_spec.rb index 45fc492f23f..6a7bf0860e9 100644 --- a/spec/features/projects/jobs_spec.rb +++ b/spec/features/projects/jobs_spec.rb @@ -574,7 +574,7 @@ describe 'Jobs', :clean_gitlab_redis_shared_state do expect(page).to have_link('Unschedule job') end - it 'unschedule delayed job and shows manual action', :js do + it 'unschedules delayed job and shows manual action', :js do click_link 'Unschedule job' wait_for_requests diff --git a/spec/features/projects/pipelines/pipeline_spec.rb b/spec/features/projects/pipelines/pipeline_spec.rb index e6cb137b023..491c64fc329 100644 --- a/spec/features/projects/pipelines/pipeline_spec.rb +++ b/spec/features/projects/pipelines/pipeline_spec.rb @@ -84,7 +84,7 @@ describe 'Pipeline', :js do end end - it 'should be possible to cancel the running build' do + it 'cancels the running build and shows retry button' do find('#ci-badge-deploy .ci-action-icon-container').click page.within('#ci-badge-deploy') do @@ -112,8 +112,8 @@ describe 'Pipeline', :js do end end - context 'when pipeline has scheduled builds' do - it 'shows the scheduled icon and a unschedule action for the scheduled build' do + context 'when pipeline has a delayed job' do + it 'shows the scheduled icon and an unschedule action for the delayed job' do page.within('#ci-badge-delayed-job') do expect(page).to have_selector('.js-ci-status-icon-scheduled') expect(page).to have_content('delayed-job') @@ -124,10 +124,12 @@ describe 'Pipeline', :js do end end - it 'should be possible to unschedule the scheduled job' do + it 'unschedules the delayed job and shows play button as a manual job' do find('#ci-badge-delayed-job .ci-action-icon-container').click - expect(page).not_to have_content('Unschedule job') + page.within('#ci-badge-delayed-job') do + expect(page).to have_css('.js-icon-play') + end end end @@ -341,14 +343,16 @@ describe 'Pipeline', :js do it { expect(build_manual.reload).to be_pending } end - context 'unscheduling scheduled job' do + context 'when user unschedules a delayed job' do before do within '.pipeline-holder' do click_link('Unschedule') end end - it { expect(build_scheduled.reload).to be_manual } + it 'unschedules the delayed job and shows play button as a manual job' do + expect(page).to have_content('Trigger this manual action') + end end context 'failed jobs' do diff --git a/spec/features/projects/pipelines/pipelines_spec.rb b/spec/features/projects/pipelines/pipelines_spec.rb index 43f9608e8e3..f6197a31ee1 100644 --- a/spec/features/projects/pipelines/pipelines_spec.rb +++ b/spec/features/projects/pipelines/pipelines_spec.rb @@ -232,7 +232,7 @@ describe 'Pipelines', :js do end end - context 'with delayed job' do + context 'when there is a delayed job' do let!(:delayed_job) do create(:ci_build, :scheduled, pipeline: pipeline, @@ -245,26 +245,25 @@ describe 'Pipelines', :js do visit_project_pipelines end - it 'has a dropdown with play button' do + it 'has a dropdown for actionable jobs' do expect(page).to have_selector('.dropdown-new.btn.btn-default .icon-play') end - it 'has link to the scheduled action' do + it "has link to the delayed job's action" do find('.js-pipeline-dropdown-manual-actions').click expect(page).to have_button('delayed job') end - context 'when scheduled action was played' do + context 'when user played a delayed job immediately' do before do - accept_confirm do - find('.js-pipeline-dropdown-manual-actions').click - click_button('delayed job') - end + find('.js-pipeline-dropdown-manual-actions').click + page.accept_confirm { click_button('delayed job') } + wait_for_requests end - it 'enqueues scheduled action job' do - expect(page).to have_selector('.js-pipeline-dropdown-manual-actions:disabled') + it 'enqueues the delayed job', :js do + expect(delayed_job.reload).to be_pending end end end -- cgit v1.2.1 From 0fc93df02b7d1be4ec243298ff17045cbd4f049a Mon Sep 17 00:00:00 2001 From: Winnie Hellmann Date: Thu, 4 Oct 2018 14:53:15 +0200 Subject: Add component tests for scheduled job frontend --- .../pipelines/pipelines_actions_spec.js | 89 +++++++++++++++------- .../pipelines/pipelines_table_row_spec.js | 7 ++ 2 files changed, 70 insertions(+), 26 deletions(-) (limited to 'spec') diff --git a/spec/javascripts/pipelines/pipelines_actions_spec.js b/spec/javascripts/pipelines/pipelines_actions_spec.js index 72fb0a8f9ef..fe60a883f77 100644 --- a/spec/javascripts/pipelines/pipelines_actions_spec.js +++ b/spec/javascripts/pipelines/pipelines_actions_spec.js @@ -1,46 +1,83 @@ import Vue from 'vue'; -import pipelinesActionsComp from '~/pipelines/components/pipelines_actions.vue'; +import eventHub from '~/pipelines/event_hub'; +import PipelinesActions from '~/pipelines/components/pipelines_actions.vue'; +import mountComponent from 'spec/helpers/vue_mount_component_helper'; +import { TEST_HOST } from 'spec/test_constants'; describe('Pipelines Actions dropdown', () => { - let component; - let actions; - let ActionsComponent; + const Component = Vue.extend(PipelinesActions); + let vm; - beforeEach(() => { - ActionsComponent = Vue.extend(pipelinesActionsComp); + afterEach(() => { + vm.$destroy(); + }); - actions = [ + describe('manual actions', () => { + const actions = [ { name: 'stop_review', - path: '/root/review-app/builds/1893/play', + path: `${TEST_HOST}/root/review-app/builds/1893/play`, }, { name: 'foo', - path: '#', + path: `${TEST_HOST}/disabled/pipeline/action`, playable: false, }, ]; - component = new ActionsComponent({ - propsData: { - actions, - }, - }).$mount(); - }); + beforeEach(() => { + vm = mountComponent(Component, { actions }); + }); - it('should render a dropdown with the provided actions', () => { - expect( - component.$el.querySelectorAll('.dropdown-menu li').length, - ).toEqual(actions.length); + it('renders a dropdown with the provided actions', () => { + const dropdownItems = vm.$el.querySelectorAll('.dropdown-menu li'); + expect(dropdownItems.length).toEqual(actions.length); + }); + + it("renders a disabled action when it's not playable", () => { + const dropdownItem = vm.$el.querySelector('.dropdown-menu li:last-child button'); + expect(dropdownItem).toBeDisabled(); + }); }); - it('should render a disabled action when it\'s not playable', () => { - expect( - component.$el.querySelector('.dropdown-menu li:last-child button').getAttribute('disabled'), - ).toEqual('disabled'); + describe('scheduled jobs', () => { + const scheduledJobAction = { + name: 'scheduled action', + path: `${TEST_HOST}/scheduled/job/action`, + playable: true, + scheduled_at: '2063-04-05T00:42:00Z', + }; + const findDropdownItem = () => vm.$el.querySelector('.dropdown-menu li button'); + + beforeEach(() => { + spyOn(Date, 'now').and.callFake(() => new Date('2063-04-04T00:42:00Z').getTime()); + vm = mountComponent(Component, { actions: [scheduledJobAction] }); + }); + + it('emits postAction event after confirming', () => { + const emitSpy = jasmine.createSpy('emit'); + eventHub.$on('postAction', emitSpy); + spyOn(window, 'confirm').and.callFake(() => true); + + findDropdownItem().click(); + + expect(window.confirm).toHaveBeenCalled(); + expect(emitSpy).toHaveBeenCalledWith(scheduledJobAction.path); + }); + + it('does not emit postAction event if confirmation is cancelled', () => { + const emitSpy = jasmine.createSpy('emit'); + eventHub.$on('postAction', emitSpy); + spyOn(window, 'confirm').and.callFake(() => false); + + findDropdownItem().click(); + + expect(window.confirm).toHaveBeenCalled(); + expect(emitSpy).not.toHaveBeenCalled(); + }); - expect( - component.$el.querySelector('.dropdown-menu li:last-child button').classList.contains('disabled'), - ).toEqual(true); + it('displays the remaining time in the dropdown', () => { + expect(findDropdownItem()).toContainText('24:00:00'); + }); }); }); diff --git a/spec/javascripts/pipelines/pipelines_table_row_spec.js b/spec/javascripts/pipelines/pipelines_table_row_spec.js index 03ffc122795..42795f5c134 100644 --- a/spec/javascripts/pipelines/pipelines_table_row_spec.js +++ b/spec/javascripts/pipelines/pipelines_table_row_spec.js @@ -158,8 +158,13 @@ describe('Pipelines Table Row', () => { }); describe('actions column', () => { + const scheduledJobAction = { + name: 'some scheduled job', + }; + beforeEach(() => { const withActions = Object.assign({}, pipeline); + withActions.details.scheduled_actions = [scheduledJobAction]; withActions.flags.cancelable = true; withActions.flags.retryable = true; withActions.cancel_path = '/cancel'; @@ -171,6 +176,8 @@ describe('Pipelines Table Row', () => { it('should render the provided actions', () => { expect(component.$el.querySelector('.js-pipelines-retry-button')).not.toBeNull(); expect(component.$el.querySelector('.js-pipelines-cancel-button')).not.toBeNull(); + const dropdownMenu = component.$el.querySelectorAll('.dropdown-menu'); + expect(dropdownMenu).toContainText(scheduledJobAction.name); }); it('emits `retryPipeline` event when retry button is clicked and toggles loading', () => { -- cgit v1.2.1 From acfe7ec65c75f65f2f87bf3e8598c1725c9150f4 Mon Sep 17 00:00:00 2001 From: Alessio Caiazza Date: Thu, 4 Oct 2018 16:15:28 +0200 Subject: fix method name in stage spec --- spec/models/ci/stage_spec.rb | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'spec') diff --git a/spec/models/ci/stage_spec.rb b/spec/models/ci/stage_spec.rb index 060a1d95293..5076f7faeac 100644 --- a/spec/models/ci/stage_spec.rb +++ b/spec/models/ci/stage_spec.rb @@ -200,8 +200,8 @@ describe Ci::Stage, :models do end end - describe '#schedule' do - subject { stage.schedule } + describe '#delay' do + subject { stage.delay } let(:stage) { create(:ci_stage_entity, status: :created) } -- cgit v1.2.1 From aeaa0261c7376485bdaa6b58682d19729a0a8c8c Mon Sep 17 00:00:00 2001 From: Shinya Maeda Date: Fri, 5 Oct 2018 11:54:09 +0900 Subject: Add :js tag for a feature spec --- spec/features/projects/jobs_spec.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'spec') diff --git a/spec/features/projects/jobs_spec.rb b/spec/features/projects/jobs_spec.rb index 7bebd066b80..4e440c1befa 100644 --- a/spec/features/projects/jobs_spec.rb +++ b/spec/features/projects/jobs_spec.rb @@ -567,7 +567,7 @@ describe 'Jobs', :clean_gitlab_redis_shared_state do visit project_job_path(project, job) end - it 'shows delayed job' do + it 'shows delayed job', :js do expect(page).to have_content(job.detailed_status(user).illustration[:title]) expect(page).to have_content('This is a scheduled to run in') expect(page).to have_content("This job will automatically run after it's timer finishes.") -- cgit v1.2.1 From e8f14ef8859c2b6f870090666331f538702c40b9 Mon Sep 17 00:00:00 2001 From: Shinya Maeda Date: Fri, 5 Oct 2018 16:07:28 +0900 Subject: Add feature spec for remaining time --- spec/features/projects/jobs_spec.rb | 3 +++ spec/features/projects/pipelines/pipelines_spec.rb | 18 ++++++++++++++++++ 2 files changed, 21 insertions(+) (limited to 'spec') diff --git a/spec/features/projects/jobs_spec.rb b/spec/features/projects/jobs_spec.rb index 4e440c1befa..67b4a520184 100644 --- a/spec/features/projects/jobs_spec.rb +++ b/spec/features/projects/jobs_spec.rb @@ -568,9 +568,12 @@ describe 'Jobs', :clean_gitlab_redis_shared_state do end it 'shows delayed job', :js do + time_diff = [0, job.scheduled_at - Time.now].max + expect(page).to have_content(job.detailed_status(user).illustration[:title]) expect(page).to have_content('This is a scheduled to run in') expect(page).to have_content("This job will automatically run after it's timer finishes.") + expect(page).to have_content(Time.at(time_diff).utc.strftime("%H:%M:%S")) expect(page).to have_link('Unschedule job') end diff --git a/spec/features/projects/pipelines/pipelines_spec.rb b/spec/features/projects/pipelines/pipelines_spec.rb index f6197a31ee1..16a1ef813e3 100644 --- a/spec/features/projects/pipelines/pipelines_spec.rb +++ b/spec/features/projects/pipelines/pipelines_spec.rb @@ -252,7 +252,25 @@ describe 'Pipelines', :js do it "has link to the delayed job's action" do find('.js-pipeline-dropdown-manual-actions').click + time_diff = [0, delayed_job.scheduled_at - Time.now].max expect(page).to have_button('delayed job') + expect(page).to have_content(Time.at(time_diff).utc.strftime("%H:%M:%S")) + end + + context 'when delayed job is expired already' do + let!(:delayed_job) do + create(:ci_build, :expired_scheduled, + pipeline: pipeline, + name: 'delayed job', + stage: 'test', + commands: 'test') + end + + it "shows 00:00:00 as the remaining time" do + find('.js-pipeline-dropdown-manual-actions').click + + expect(page).to have_content(Time.at(time_diff).utc.strftime("00:00:00")) + end end context 'when user played a delayed job immediately' do -- cgit v1.2.1 From c5dead78558e552801205bf6e0a9b78f1e88711d Mon Sep 17 00:00:00 2001 From: Winnie Hellmann Date: Fri, 5 Oct 2018 09:34:08 +0200 Subject: Make sure remaining time of scheduled jobs is positive in pipelines list --- .../pipelines/pipelines_actions_spec.js | 25 +++++++++++++++++----- 1 file changed, 20 insertions(+), 5 deletions(-) (limited to 'spec') diff --git a/spec/javascripts/pipelines/pipelines_actions_spec.js b/spec/javascripts/pipelines/pipelines_actions_spec.js index fe60a883f77..0566bc55693 100644 --- a/spec/javascripts/pipelines/pipelines_actions_spec.js +++ b/spec/javascripts/pipelines/pipelines_actions_spec.js @@ -47,11 +47,22 @@ describe('Pipelines Actions dropdown', () => { playable: true, scheduled_at: '2063-04-05T00:42:00Z', }; - const findDropdownItem = () => vm.$el.querySelector('.dropdown-menu li button'); + const expiredJobAction = { + name: 'expired action', + path: `${TEST_HOST}/expired/job/action`, + playable: true, + scheduled_at: '2018-10-05T08:23:00Z', + }; + const findDropdownItem = action => { + const buttons = vm.$el.querySelectorAll('.dropdown-menu li button'); + return Array.prototype.find.call(buttons, element => + element.innerText.trim().startsWith(action.name), + ); + }; beforeEach(() => { spyOn(Date, 'now').and.callFake(() => new Date('2063-04-04T00:42:00Z').getTime()); - vm = mountComponent(Component, { actions: [scheduledJobAction] }); + vm = mountComponent(Component, { actions: [scheduledJobAction, expiredJobAction] }); }); it('emits postAction event after confirming', () => { @@ -59,7 +70,7 @@ describe('Pipelines Actions dropdown', () => { eventHub.$on('postAction', emitSpy); spyOn(window, 'confirm').and.callFake(() => true); - findDropdownItem().click(); + findDropdownItem(scheduledJobAction).click(); expect(window.confirm).toHaveBeenCalled(); expect(emitSpy).toHaveBeenCalledWith(scheduledJobAction.path); @@ -70,14 +81,18 @@ describe('Pipelines Actions dropdown', () => { eventHub.$on('postAction', emitSpy); spyOn(window, 'confirm').and.callFake(() => false); - findDropdownItem().click(); + findDropdownItem(scheduledJobAction).click(); expect(window.confirm).toHaveBeenCalled(); expect(emitSpy).not.toHaveBeenCalled(); }); it('displays the remaining time in the dropdown', () => { - expect(findDropdownItem()).toContainText('24:00:00'); + expect(findDropdownItem(scheduledJobAction)).toContainText('24:00:00'); + }); + + it('displays 00:00:00 for expired jobs in the dropdown', () => { + expect(findDropdownItem(expiredJobAction)).toContainText('00:00:00'); }); }); }); -- cgit v1.2.1 From ada45a7496971656af180f1790d61d75806361d2 Mon Sep 17 00:00:00 2001 From: Shinya Maeda Date: Fri, 5 Oct 2018 17:11:37 +0900 Subject: Fix pipelines spec --- spec/features/projects/pipelines/pipelines_spec.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'spec') diff --git a/spec/features/projects/pipelines/pipelines_spec.rb b/spec/features/projects/pipelines/pipelines_spec.rb index 16a1ef813e3..17772a35779 100644 --- a/spec/features/projects/pipelines/pipelines_spec.rb +++ b/spec/features/projects/pipelines/pipelines_spec.rb @@ -269,7 +269,7 @@ describe 'Pipelines', :js do it "shows 00:00:00 as the remaining time" do find('.js-pipeline-dropdown-manual-actions').click - expect(page).to have_content(Time.at(time_diff).utc.strftime("00:00:00")) + expect(page).to have_content("00:00:00") end end -- cgit v1.2.1