From 020ea32e767b9ad033f9fedcaa902865a01fa944 Mon Sep 17 00:00:00 2001 From: Lin Jen-Shin Date: Tue, 2 Aug 2016 18:06:31 +0800 Subject: Implement pipeline hooks, extracted from !5525 Closes #20115 --- spec/models/ci/pipeline_spec.rb | 33 +++++++++++++++++++++++++++++++-- 1 file changed, 31 insertions(+), 2 deletions(-) (limited to 'spec/models/ci/pipeline_spec.rb') diff --git a/spec/models/ci/pipeline_spec.rb b/spec/models/ci/pipeline_spec.rb index 0d4c86955ce..aa05fc78f94 100644 --- a/spec/models/ci/pipeline_spec.rb +++ b/spec/models/ci/pipeline_spec.rb @@ -513,7 +513,7 @@ describe Ci::Pipeline, models: true do create :ci_build, :success, pipeline: pipeline, name: 'rspec' create :ci_build, :allowed_to_fail, :failed, pipeline: pipeline, name: 'rubocop' end - + it 'returns true' do is_expected.to be_truthy end @@ -524,7 +524,7 @@ describe Ci::Pipeline, models: true do create :ci_build, :success, pipeline: pipeline, name: 'rspec' create :ci_build, :allowed_to_fail, :success, pipeline: pipeline, name: 'rubocop' end - + it 'returns false' do is_expected.to be_falsey end @@ -542,4 +542,33 @@ describe Ci::Pipeline, models: true do end end end + + describe '#execute_hooks' do + let!(:hook) do + create(:project_hook, project: project, pipeline_events: enabled) + end + let(:enabled) { raise NotImplementedError } + + before do + WebMock.stub_request(:post, hook.url) + pipeline.touch + ProjectWebHookWorker.drain + end + + context 'with pipeline hooks enabled' do + let(:enabled) { true } + + it 'executes pipeline_hook after touched' do + expect(WebMock).to have_requested(:post, hook.url).once + end + end + + context 'with pipeline hooks disabled' do + let(:enabled) { false } + + it 'did not execute pipeline_hook after touched' do + expect(WebMock).not_to have_requested(:post, hook.url) + end + end + end end -- cgit v1.2.1 From 9e06bde269b80b3af01b7cc00bdada1ce2e5e563 Mon Sep 17 00:00:00 2001 From: Lin Jen-Shin Date: Wed, 3 Aug 2016 23:39:14 +0800 Subject: Make sure we only fire hooks upon status changed --- spec/models/ci/pipeline_spec.rb | 22 +++++++++++++++++++++- 1 file changed, 21 insertions(+), 1 deletion(-) (limited to 'spec/models/ci/pipeline_spec.rb') diff --git a/spec/models/ci/pipeline_spec.rb b/spec/models/ci/pipeline_spec.rb index aa05fc78f94..a8c49daf9bb 100644 --- a/spec/models/ci/pipeline_spec.rb +++ b/spec/models/ci/pipeline_spec.rb @@ -551,7 +551,7 @@ describe Ci::Pipeline, models: true do before do WebMock.stub_request(:post, hook.url) - pipeline.touch + pipeline.save ProjectWebHookWorker.drain end @@ -561,6 +561,26 @@ describe Ci::Pipeline, models: true do it 'executes pipeline_hook after touched' do expect(WebMock).to have_requested(:post, hook.url).once end + + context 'with multiple builds' do + def create_build(name) + create(:ci_build, :pending, pipeline: pipeline, name: name) + end + + let(:build_a) { create_build('a') } + let(:build_b) { create_build('b') } + + before do + build_a.run + build_b.run + build_a.success + build_b.success + end + + it 'fires 3 hooks' do + expect(WebMock).to have_requested(:post, hook.url).times(3) + end + end end context 'with pipeline hooks disabled' do -- cgit v1.2.1 From 77540619d5ce0e63edec89ea3d406fa457696a0e Mon Sep 17 00:00:00 2001 From: Lin Jen-Shin Date: Wed, 3 Aug 2016 23:54:44 +0800 Subject: Test against the status in the payload --- spec/models/ci/pipeline_spec.rb | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) (limited to 'spec/models/ci/pipeline_spec.rb') diff --git a/spec/models/ci/pipeline_spec.rb b/spec/models/ci/pipeline_spec.rb index a8c49daf9bb..b0496a017f4 100644 --- a/spec/models/ci/pipeline_spec.rb +++ b/spec/models/ci/pipeline_spec.rb @@ -567,6 +567,12 @@ describe Ci::Pipeline, models: true do create(:ci_build, :pending, pipeline: pipeline, name: name) end + def requested status + have_requested(:post, hook.url).with do |req| + JSON.parse(req.body)['object_attributes']['status'] == status + end.once + end + let(:build_a) { create_build('a') } let(:build_b) { create_build('b') } @@ -578,7 +584,9 @@ describe Ci::Pipeline, models: true do end it 'fires 3 hooks' do - expect(WebMock).to have_requested(:post, hook.url).times(3) + %w(pending running success).each do |status| + expect(WebMock).to requested(status) + end end end end -- cgit v1.2.1 From 3f7680a61933cd2f710236474b01e9cd9b849beb Mon Sep 17 00:00:00 2001 From: Lin Jen-Shin Date: Thu, 4 Aug 2016 00:04:01 +0800 Subject: I was too used to this style... --- spec/models/ci/pipeline_spec.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'spec/models/ci/pipeline_spec.rb') diff --git a/spec/models/ci/pipeline_spec.rb b/spec/models/ci/pipeline_spec.rb index b0496a017f4..b20c617f089 100644 --- a/spec/models/ci/pipeline_spec.rb +++ b/spec/models/ci/pipeline_spec.rb @@ -567,7 +567,7 @@ describe Ci::Pipeline, models: true do create(:ci_build, :pending, pipeline: pipeline, name: name) end - def requested status + def requested(status) have_requested(:post, hook.url).with do |req| JSON.parse(req.body)['object_attributes']['status'] == status end.once -- cgit v1.2.1 From 94b3d33de1417b31ef3994e43f901941dc302ca0 Mon Sep 17 00:00:00 2001 From: Lin Jen-Shin Date: Thu, 4 Aug 2016 00:46:58 +0800 Subject: If we use Rails magic it's breaking this test: spec/lib/gitlab/data_builder/pipeline_data_builder_spec.rb Because it would trigger the event just after saved and it would load no builds and cache it. We should really avoid adding more magic. --- spec/models/ci/pipeline_spec.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'spec/models/ci/pipeline_spec.rb') diff --git a/spec/models/ci/pipeline_spec.rb b/spec/models/ci/pipeline_spec.rb index b20c617f089..326d3c9b44d 100644 --- a/spec/models/ci/pipeline_spec.rb +++ b/spec/models/ci/pipeline_spec.rb @@ -551,7 +551,7 @@ describe Ci::Pipeline, models: true do before do WebMock.stub_request(:post, hook.url) - pipeline.save + pipeline.touch ProjectWebHookWorker.drain end -- cgit v1.2.1 From aa75728853ec03c845adc6ba1ae483023ae8bcd4 Mon Sep 17 00:00:00 2001 From: Lin Jen-Shin Date: Fri, 5 Aug 2016 00:27:12 +0800 Subject: Removed the abstract let, feedback: https://gitlab.com/gitlab-org/gitlab-ce/merge_requests/5620#note_13580861 --- spec/models/ci/pipeline_spec.rb | 1 - 1 file changed, 1 deletion(-) (limited to 'spec/models/ci/pipeline_spec.rb') diff --git a/spec/models/ci/pipeline_spec.rb b/spec/models/ci/pipeline_spec.rb index 326d3c9b44d..f45684414e6 100644 --- a/spec/models/ci/pipeline_spec.rb +++ b/spec/models/ci/pipeline_spec.rb @@ -547,7 +547,6 @@ describe Ci::Pipeline, models: true do let!(:hook) do create(:project_hook, project: project, pipeline_events: enabled) end - let(:enabled) { raise NotImplementedError } before do WebMock.stub_request(:post, hook.url) -- cgit v1.2.1 From a92dd5449524780c2a56e9627059b6c0e2362805 Mon Sep 17 00:00:00 2001 From: Lin Jen-Shin Date: Fri, 5 Aug 2016 00:44:17 +0800 Subject: Define utility functions later, feedback: https://gitlab.com/gitlab-org/gitlab-ce/merge_requests/5620#note_13581143 --- spec/models/ci/pipeline_spec.rb | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) (limited to 'spec/models/ci/pipeline_spec.rb') diff --git a/spec/models/ci/pipeline_spec.rb b/spec/models/ci/pipeline_spec.rb index f45684414e6..542264eb1d9 100644 --- a/spec/models/ci/pipeline_spec.rb +++ b/spec/models/ci/pipeline_spec.rb @@ -562,16 +562,6 @@ describe Ci::Pipeline, models: true do end context 'with multiple builds' do - def create_build(name) - create(:ci_build, :pending, pipeline: pipeline, name: name) - end - - def requested(status) - have_requested(:post, hook.url).with do |req| - JSON.parse(req.body)['object_attributes']['status'] == status - end.once - end - let(:build_a) { create_build('a') } let(:build_b) { create_build('b') } @@ -587,6 +577,16 @@ describe Ci::Pipeline, models: true do expect(WebMock).to requested(status) end end + + def create_build(name) + create(:ci_build, :pending, pipeline: pipeline, name: name) + end + + def requested(status) + have_requested(:post, hook.url).with do |req| + JSON.parse(req.body)['object_attributes']['status'] == status + end.once + end end end -- cgit v1.2.1 From 1d268a89deef10854193db48d65cf5d519a0363d Mon Sep 17 00:00:00 2001 From: tiagonbotelho Date: Mon, 1 Aug 2016 16:00:44 +0100 Subject: adds second batch of tests changed to active tense --- spec/models/ci/pipeline_spec.rb | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'spec/models/ci/pipeline_spec.rb') diff --git a/spec/models/ci/pipeline_spec.rb b/spec/models/ci/pipeline_spec.rb index 0d4c86955ce..ccee591cf7a 100644 --- a/spec/models/ci/pipeline_spec.rb +++ b/spec/models/ci/pipeline_spec.rb @@ -427,7 +427,7 @@ describe Ci::Pipeline, models: true do end describe '#update_state' do - it 'execute update_state after touching object' do + it 'executes update_state after touching object' do expect(pipeline).to receive(:update_state).and_return(true) pipeline.touch end @@ -435,7 +435,7 @@ describe Ci::Pipeline, models: true do context 'dependent objects' do let(:commit_status) { build :commit_status, pipeline: pipeline } - it 'execute update_state after saving dependent object' do + it 'executes update_state after saving dependent object' do expect(pipeline).to receive(:update_state).and_return(true) commit_status.save end @@ -513,7 +513,7 @@ describe Ci::Pipeline, models: true do create :ci_build, :success, pipeline: pipeline, name: 'rspec' create :ci_build, :allowed_to_fail, :failed, pipeline: pipeline, name: 'rubocop' end - + it 'returns true' do is_expected.to be_truthy end @@ -524,7 +524,7 @@ describe Ci::Pipeline, models: true do create :ci_build, :success, pipeline: pipeline, name: 'rspec' create :ci_build, :allowed_to_fail, :success, pipeline: pipeline, name: 'rubocop' end - + it 'returns false' do is_expected.to be_falsey end -- cgit v1.2.1 From 39203f1adfc6fee3eca50f0cab99ffc597865200 Mon Sep 17 00:00:00 2001 From: Kamil Trzcinski Date: Thu, 11 Aug 2016 15:22:35 +0200 Subject: Pre-create all builds for Pipeline when a trigger is received This change simplifies a Pipeline processing by introducing a special new status: created. This status is used for all builds that are created for a pipeline. We are then processing next stages and queueing some of the builds (created -> pending) or skipping them (created -> skipped). This makes it possible to simplify and solve a few ordering problems with how previously builds were scheduled. This also allows us to visualise a full pipeline (with created builds). This also removes an after_touch used for updating a pipeline state parameters. Right now in various places we explicitly call a reload_status! on pipeline to force it to be updated and saved. --- spec/models/ci/pipeline_spec.rb | 316 ++-------------------------------------- 1 file changed, 14 insertions(+), 302 deletions(-) (limited to 'spec/models/ci/pipeline_spec.rb') diff --git a/spec/models/ci/pipeline_spec.rb b/spec/models/ci/pipeline_spec.rb index ccee591cf7a..fdb579ab45c 100644 --- a/spec/models/ci/pipeline_spec.rb +++ b/spec/models/ci/pipeline_spec.rb @@ -38,9 +38,6 @@ describe Ci::Pipeline, models: true do it { expect(pipeline.sha).to start_with(subject) } end - describe '#create_next_builds' do - end - describe '#retried' do subject { pipeline.retried } @@ -54,304 +51,20 @@ describe Ci::Pipeline, models: true do end end - describe '#create_builds' do - let!(:pipeline) { FactoryGirl.create :ci_pipeline, project: project, ref: 'master', tag: false } - - def create_builds(trigger_request = nil) - pipeline.create_builds(nil, trigger_request) - end - - def create_next_builds - pipeline.create_next_builds(pipeline.builds.order(:id).last) - end - - it 'creates builds' do - expect(create_builds).to be_truthy - pipeline.builds.update_all(status: "success") - expect(pipeline.builds.count(:all)).to eq(2) - - expect(create_next_builds).to be_truthy - pipeline.builds.update_all(status: "success") - expect(pipeline.builds.count(:all)).to eq(4) - - expect(create_next_builds).to be_truthy - pipeline.builds.update_all(status: "success") - expect(pipeline.builds.count(:all)).to eq(5) - - expect(create_next_builds).to be_falsey - end - - context 'custom stage with first job allowed to fail' do - let(:yaml) do - { - stages: ['clean', 'test'], - clean_job: { - stage: 'clean', - allow_failure: true, - script: 'BUILD', - }, - test_job: { - stage: 'test', - script: 'TEST', - }, - } - end - - before do - stub_ci_pipeline_yaml_file(YAML.dump(yaml)) - create_builds - end - - it 'properly schedules builds' do - expect(pipeline.builds.pluck(:status)).to contain_exactly('pending') - pipeline.builds.running_or_pending.each(&:drop) - expect(pipeline.builds.pluck(:status)).to contain_exactly('pending', 'failed') - end - end - - context 'properly creates builds when "when" is defined' do - let(:yaml) do - { - stages: ["build", "test", "test_failure", "deploy", "cleanup"], - build: { - stage: "build", - script: "BUILD", - }, - test: { - stage: "test", - script: "TEST", - }, - test_failure: { - stage: "test_failure", - script: "ON test failure", - when: "on_failure", - }, - deploy: { - stage: "deploy", - script: "PUBLISH", - }, - cleanup: { - stage: "cleanup", - script: "TIDY UP", - when: "always", - } - } - end - - before do - stub_ci_pipeline_yaml_file(YAML.dump(yaml)) - end - - context 'when builds are successful' do - it 'properly creates builds' do - expect(create_builds).to be_truthy - expect(pipeline.builds.pluck(:name)).to contain_exactly('build') - expect(pipeline.builds.pluck(:status)).to contain_exactly('pending') - pipeline.builds.running_or_pending.each(&:success) - - expect(pipeline.builds.pluck(:name)).to contain_exactly('build', 'test') - expect(pipeline.builds.pluck(:status)).to contain_exactly('success', 'pending') - pipeline.builds.running_or_pending.each(&:success) - - expect(pipeline.builds.pluck(:name)).to contain_exactly('build', 'test', 'deploy') - expect(pipeline.builds.pluck(:status)).to contain_exactly('success', 'success', 'pending') - pipeline.builds.running_or_pending.each(&:success) - - expect(pipeline.builds.pluck(:name)).to contain_exactly('build', 'test', 'deploy', 'cleanup') - expect(pipeline.builds.pluck(:status)).to contain_exactly('success', 'success', 'success', 'pending') - pipeline.builds.running_or_pending.each(&:success) - - expect(pipeline.builds.pluck(:status)).to contain_exactly('success', 'success', 'success', 'success') - pipeline.reload - expect(pipeline.status).to eq('success') - end - end - - context 'when test job fails' do - it 'properly creates builds' do - expect(create_builds).to be_truthy - expect(pipeline.builds.pluck(:name)).to contain_exactly('build') - expect(pipeline.builds.pluck(:status)).to contain_exactly('pending') - pipeline.builds.running_or_pending.each(&:success) - - expect(pipeline.builds.pluck(:name)).to contain_exactly('build', 'test') - expect(pipeline.builds.pluck(:status)).to contain_exactly('success', 'pending') - pipeline.builds.running_or_pending.each(&:drop) - - expect(pipeline.builds.pluck(:name)).to contain_exactly('build', 'test', 'test_failure') - expect(pipeline.builds.pluck(:status)).to contain_exactly('success', 'failed', 'pending') - pipeline.builds.running_or_pending.each(&:success) - - expect(pipeline.builds.pluck(:name)).to contain_exactly('build', 'test', 'test_failure', 'cleanup') - expect(pipeline.builds.pluck(:status)).to contain_exactly('success', 'failed', 'success', 'pending') - pipeline.builds.running_or_pending.each(&:success) - - expect(pipeline.builds.pluck(:status)).to contain_exactly('success', 'failed', 'success', 'success') - pipeline.reload - expect(pipeline.status).to eq('failed') - end - end - - context 'when test and test_failure jobs fail' do - it 'properly creates builds' do - expect(create_builds).to be_truthy - expect(pipeline.builds.pluck(:name)).to contain_exactly('build') - expect(pipeline.builds.pluck(:status)).to contain_exactly('pending') - pipeline.builds.running_or_pending.each(&:success) - - expect(pipeline.builds.pluck(:name)).to contain_exactly('build', 'test') - expect(pipeline.builds.pluck(:status)).to contain_exactly('success', 'pending') - pipeline.builds.running_or_pending.each(&:drop) - - expect(pipeline.builds.pluck(:name)).to contain_exactly('build', 'test', 'test_failure') - expect(pipeline.builds.pluck(:status)).to contain_exactly('success', 'failed', 'pending') - pipeline.builds.running_or_pending.each(&:drop) - - expect(pipeline.builds.pluck(:name)).to contain_exactly('build', 'test', 'test_failure', 'cleanup') - expect(pipeline.builds.pluck(:status)).to contain_exactly('success', 'failed', 'failed', 'pending') - pipeline.builds.running_or_pending.each(&:success) - - expect(pipeline.builds.pluck(:name)).to contain_exactly('build', 'test', 'test_failure', 'cleanup') - expect(pipeline.builds.pluck(:status)).to contain_exactly('success', 'failed', 'failed', 'success') - pipeline.reload - expect(pipeline.status).to eq('failed') - end - end - - context 'when deploy job fails' do - it 'properly creates builds' do - expect(create_builds).to be_truthy - expect(pipeline.builds.pluck(:name)).to contain_exactly('build') - expect(pipeline.builds.pluck(:status)).to contain_exactly('pending') - pipeline.builds.running_or_pending.each(&:success) - - expect(pipeline.builds.pluck(:name)).to contain_exactly('build', 'test') - expect(pipeline.builds.pluck(:status)).to contain_exactly('success', 'pending') - pipeline.builds.running_or_pending.each(&:success) - - expect(pipeline.builds.pluck(:name)).to contain_exactly('build', 'test', 'deploy') - expect(pipeline.builds.pluck(:status)).to contain_exactly('success', 'success', 'pending') - pipeline.builds.running_or_pending.each(&:drop) - - expect(pipeline.builds.pluck(:name)).to contain_exactly('build', 'test', 'deploy', 'cleanup') - expect(pipeline.builds.pluck(:status)).to contain_exactly('success', 'success', 'failed', 'pending') - pipeline.builds.running_or_pending.each(&:success) - - expect(pipeline.builds.pluck(:status)).to contain_exactly('success', 'success', 'failed', 'success') - pipeline.reload - expect(pipeline.status).to eq('failed') - end - end - - context 'when build is canceled in the second stage' do - it 'does not schedule builds after build has been canceled' do - expect(create_builds).to be_truthy - expect(pipeline.builds.pluck(:name)).to contain_exactly('build') - expect(pipeline.builds.pluck(:status)).to contain_exactly('pending') - pipeline.builds.running_or_pending.each(&:success) - - expect(pipeline.builds.running_or_pending).not_to be_empty - - expect(pipeline.builds.pluck(:name)).to contain_exactly('build', 'test') - expect(pipeline.builds.pluck(:status)).to contain_exactly('success', 'pending') - pipeline.builds.running_or_pending.each(&:cancel) - - expect(pipeline.builds.running_or_pending).to be_empty - expect(pipeline.reload.status).to eq('canceled') - end - end - - context 'when listing manual actions' do - let(:yaml) do - { - stages: ["build", "test", "staging", "production", "cleanup"], - build: { - stage: "build", - script: "BUILD", - }, - test: { - stage: "test", - script: "TEST", - }, - staging: { - stage: "staging", - script: "PUBLISH", - }, - production: { - stage: "production", - script: "PUBLISH", - when: "manual", - }, - cleanup: { - stage: "cleanup", - script: "TIDY UP", - when: "always", - }, - clear_cache: { - stage: "cleanup", - script: "CLEAR CACHE", - when: "manual", - } - } - end - - it 'returns only for skipped builds' do - # currently all builds are created - expect(create_builds).to be_truthy - expect(manual_actions).to be_empty - - # succeed stage build - pipeline.builds.running_or_pending.each(&:success) - expect(manual_actions).to be_empty - - # succeed stage test - pipeline.builds.running_or_pending.each(&:success) - expect(manual_actions).to be_empty - - # succeed stage staging and skip stage production - pipeline.builds.running_or_pending.each(&:success) - expect(manual_actions).to be_many # production and clear cache - - # succeed stage cleanup - pipeline.builds.running_or_pending.each(&:success) - - # after processing a pipeline we should have 6 builds, 5 succeeded - expect(pipeline.builds.count).to eq(6) - expect(pipeline.builds.success.count).to eq(4) - end - - def manual_actions - pipeline.manual_actions - end - end - end - - context 'when no builds created' do - let(:pipeline) { build(:ci_pipeline) } - - before do - stub_ci_pipeline_yaml_file(YAML.dump(before_script: ['ls'])) - end - - it 'returns false' do - expect(pipeline.create_builds(nil)).to be_falsey - expect(pipeline).not_to be_persisted - end - end - end - describe "#finished_at" do let(:pipeline) { FactoryGirl.create :ci_pipeline } it "returns finished_at of latest build" do build = FactoryGirl.create :ci_build, pipeline: pipeline, finished_at: Time.now - 60 FactoryGirl.create :ci_build, pipeline: pipeline, finished_at: Time.now - 120 + pipeline.reload_status! expect(pipeline.finished_at.to_i).to eq(build.finished_at.to_i) end it "returns nil if there is no finished build" do FactoryGirl.create :ci_not_started_build, pipeline: pipeline + pipeline.reload_status! expect(pipeline.finished_at).to be_nil end @@ -359,7 +72,7 @@ describe Ci::Pipeline, models: true do describe "coverage" do let(:project) { FactoryGirl.create :empty_project, build_coverage_regex: "/.*/" } - let(:pipeline) { FactoryGirl.create :ci_pipeline, project: project } + let(:pipeline) { FactoryGirl.create :ci_empty_pipeline, project: project } it "calculates average when there are two builds with coverage" do FactoryGirl.create :ci_build, name: "rspec", coverage: 30, pipeline: pipeline @@ -426,31 +139,30 @@ describe Ci::Pipeline, models: true do end end - describe '#update_state' do - it 'executes update_state after touching object' do - expect(pipeline).to receive(:update_state).and_return(true) - pipeline.touch - end + describe '#reload_status!' do + let(:pipeline) { create :ci_empty_pipeline, project: project } context 'dependent objects' do - let(:commit_status) { build :commit_status, pipeline: pipeline } + let(:commit_status) { create :commit_status, :pending, pipeline: pipeline } + + it 'executes reload_status! after succeeding dependent object' do + expect(pipeline).to receive(:reload_status!).and_return(true) - it 'executes update_state after saving dependent object' do - expect(pipeline).to receive(:update_state).and_return(true) - commit_status.save + commit_status.success end end - context 'update state' do + context 'updates' do let(:current) { Time.now.change(usec: 0) } - let(:build) { FactoryGirl.create :ci_build, :success, pipeline: pipeline, started_at: current - 120, finished_at: current - 60 } + let(:build) { FactoryGirl.create :ci_build, pipeline: pipeline, started_at: current - 120, finished_at: current - 60 } before do build + pipeline.reload_status! end [:status, :started_at, :finished_at, :duration].each do |param| - it "update #{param}" do + it "#{param}" do expect(pipeline.send(param)).to eq(build.send(param)) end end -- cgit v1.2.1 From 99928aca755f4ccf98a58445a0176b80cd16159c Mon Sep 17 00:00:00 2001 From: Kamil Trzcinski Date: Thu, 11 Aug 2016 17:23:35 +0200 Subject: Enhance a pipeline event tests to analyse number of returned builds --- spec/models/ci/pipeline_spec.rb | 39 +++++++++++++++++++-------------------- 1 file changed, 19 insertions(+), 20 deletions(-) (limited to 'spec/models/ci/pipeline_spec.rb') diff --git a/spec/models/ci/pipeline_spec.rb b/spec/models/ci/pipeline_spec.rb index ceae2e60f2f..7da044d4f16 100644 --- a/spec/models/ci/pipeline_spec.rb +++ b/spec/models/ci/pipeline_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' describe Ci::Pipeline, models: true do let(:project) { FactoryGirl.create :empty_project } - let(:pipeline) { FactoryGirl.create :ci_pipeline, project: project } + let(:pipeline) { FactoryGirl.create :ci_empty_pipeline, project: project } it { is_expected.to belong_to(:project) } it { is_expected.to belong_to(:user) } @@ -18,6 +18,8 @@ describe Ci::Pipeline, models: true do it { is_expected.to respond_to :git_author_email } it { is_expected.to respond_to :short_sha } + it { is_expected.to delegate_method(:stages).to(:statuses) } + describe '#valid_commit_sha' do context 'commit.sha can not start with 00000000' do before do @@ -261,43 +263,40 @@ describe Ci::Pipeline, models: true do end before do - WebMock.stub_request(:post, hook.url) - pipeline.touch ProjectWebHookWorker.drain end context 'with pipeline hooks enabled' do let(:enabled) { true } - it 'executes pipeline_hook after touched' do - expect(WebMock).to have_requested(:post, hook.url).once - end - context 'with multiple builds' do - let(:build_a) { create_build('a') } - let(:build_b) { create_build('b') } + let!(:build_a) { create_build('a') } + let!(:build_b) { create_build('b') } - before do + it 'fires exactly 3 hooks' do + stub_request('pending') + build_a.queue + build_b.queue + + stub_request('running') build_a.run build_b.run + + stub_request('success') build_a.success build_b.success end - it 'fires 3 hooks' do - %w(pending running success).each do |status| - expect(WebMock).to requested(status) - end - end - def create_build(name) create(:ci_build, :pending, pipeline: pipeline, name: name) end - def requested(status) - have_requested(:post, hook.url).with do |req| - JSON.parse(req.body)['object_attributes']['status'] == status - end.once + def stub_request(status) + WebMock.stub_request(:post, hook.url).with do |req| + json_body = JSON.parse(req.body) + json_body['object_attributes']['status'] == status && + json_body['builds'].length == 2 + end end end end -- cgit v1.2.1 From 478990bb3ee0aa6939b656763a97d637189f062d Mon Sep 17 00:00:00 2001 From: Kamil Trzcinski Date: Thu, 11 Aug 2016 18:37:36 +0200 Subject: Fix pipeline status change from pending to running --- spec/models/ci/pipeline_spec.rb | 45 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 45 insertions(+) (limited to 'spec/models/ci/pipeline_spec.rb') diff --git a/spec/models/ci/pipeline_spec.rb b/spec/models/ci/pipeline_spec.rb index 7da044d4f16..317f4147545 100644 --- a/spec/models/ci/pipeline_spec.rb +++ b/spec/models/ci/pipeline_spec.rb @@ -257,6 +257,51 @@ describe Ci::Pipeline, models: true do end end + describe '#status' do + let!(:build) { create(:ci_build, :created, pipeline: pipeline, name: 'test') } + + subject { pipeline.reload.status } + + context 'on queuing' do + before { build.queue } + + it { is_expected.to eq('pending') } + end + + context 'on run' do + before do + build.queue + build.run + end + + it { is_expected.to eq('running') } + end + + context 'on drop' do + before do + build.drop + end + + it { is_expected.to eq('failed') } + end + + context 'on success' do + before do + build.success + end + + it { is_expected.to eq('success') } + end + + context 'on cancel' do + before do + build.cancel + end + + it { is_expected.to eq('canceled') } + end + end + describe '#execute_hooks' do let!(:hook) do create(:project_hook, project: project, pipeline_events: enabled) -- cgit v1.2.1 From e2c01f397f2f00138d2b4e618306ee2aa141c97c Mon Sep 17 00:00:00 2001 From: Kamil Trzcinski Date: Thu, 11 Aug 2016 18:37:50 +0200 Subject: Fix tests for pipeline events --- spec/models/ci/pipeline_spec.rb | 64 ++++++++++++++++++++++++++++++----------- 1 file changed, 47 insertions(+), 17 deletions(-) (limited to 'spec/models/ci/pipeline_spec.rb') diff --git a/spec/models/ci/pipeline_spec.rb b/spec/models/ci/pipeline_spec.rb index 317f4147545..685c4178e89 100644 --- a/spec/models/ci/pipeline_spec.rb +++ b/spec/models/ci/pipeline_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' describe Ci::Pipeline, models: true do let(:project) { FactoryGirl.create :empty_project } - let(:pipeline) { FactoryGirl.create :ci_empty_pipeline, project: project } + let(:pipeline) { FactoryGirl.create :ci_empty_pipeline, status: 'created', project: project } it { is_expected.to belong_to(:project) } it { is_expected.to belong_to(:user) } @@ -303,6 +303,9 @@ describe Ci::Pipeline, models: true do end describe '#execute_hooks' do + let!(:build_a) { create_build('a') } + let!(:build_b) { create_build('b') } + let!(:hook) do create(:project_hook, project: project, pipeline_events: enabled) end @@ -314,30 +317,48 @@ describe Ci::Pipeline, models: true do context 'with pipeline hooks enabled' do let(:enabled) { true } + before do + WebMock.stub_request(:post, hook.url) + end + context 'with multiple builds' do - let!(:build_a) { create_build('a') } - let!(:build_b) { create_build('b') } + context 'when build is queued' do + before do + build_a.queue + build_b.queue + end - it 'fires exactly 3 hooks' do - stub_request('pending') - build_a.queue - build_b.queue + it 'receive a pending event once' do + expect(WebMock).to requested('pending').once + end + end - stub_request('running') - build_a.run - build_b.run + context 'when build is run' do + before do + build_a.queue + build_a.run + build_b.queue + build_b.run + end - stub_request('success') - build_a.success - build_b.success + it 'receive a running event once' do + expect(WebMock).to requested('running').once + end end - def create_build(name) - create(:ci_build, :pending, pipeline: pipeline, name: name) + context 'when all builds succeed' do + before do + build_a.success + build_b.success + end + + it 'receive a success event once' do + expect(WebMock).to requested('success').once + end end - def stub_request(status) - WebMock.stub_request(:post, hook.url).with do |req| + def requested(status) + have_requested(:post, hook.url).with do |req| json_body = JSON.parse(req.body) json_body['object_attributes']['status'] == status && json_body['builds'].length == 2 @@ -349,9 +370,18 @@ describe Ci::Pipeline, models: true do context 'with pipeline hooks disabled' do let(:enabled) { false } + before do + build_a.queue + build_b.queue + end + it 'did not execute pipeline_hook after touched' do expect(WebMock).not_to have_requested(:post, hook.url) end end + + def create_build(name) + create(:ci_build, :created, pipeline: pipeline, name: name) + end end end -- cgit v1.2.1 From d983c5bd4671d989edf3741d0db0a54dcef9c3b6 Mon Sep 17 00:00:00 2001 From: Kamil Trzcinski Date: Thu, 11 Aug 2016 18:37:36 +0200 Subject: Verify the pipeline status after executing events on builds --- spec/models/ci/pipeline_spec.rb | 45 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 45 insertions(+) (limited to 'spec/models/ci/pipeline_spec.rb') diff --git a/spec/models/ci/pipeline_spec.rb b/spec/models/ci/pipeline_spec.rb index fdb579ab45c..9a9720cfbfc 100644 --- a/spec/models/ci/pipeline_spec.rb +++ b/spec/models/ci/pipeline_spec.rb @@ -254,4 +254,49 @@ describe Ci::Pipeline, models: true do end end end + + describe '#status' do + let!(:build) { create(:ci_build, :created, pipeline: pipeline, name: 'test') } + + subject { pipeline.reload.status } + + context 'on queuing' do + before { build.queue } + + it { is_expected.to eq('pending') } + end + + context 'on run' do + before do + build.queue + build.run + end + + it { is_expected.to eq('running') } + end + + context 'on drop' do + before do + build.drop + end + + it { is_expected.to eq('failed') } + end + + context 'on success' do + before do + build.success + end + + it { is_expected.to eq('success') } + end + + context 'on cancel' do + before do + build.cancel + end + + it { is_expected.to eq('canceled') } + end + end end -- cgit v1.2.1 From 6a6a69f4afbe0107a75df018b662f02b5ec0166a Mon Sep 17 00:00:00 2001 From: Kamil Trzcinski Date: Thu, 11 Aug 2016 20:54:02 +0200 Subject: Use state machine for pipeline event processing --- spec/models/ci/pipeline_spec.rb | 38 ++++---------------------------------- 1 file changed, 4 insertions(+), 34 deletions(-) (limited to 'spec/models/ci/pipeline_spec.rb') diff --git a/spec/models/ci/pipeline_spec.rb b/spec/models/ci/pipeline_spec.rb index 9a9720cfbfc..eb762276cbe 100644 --- a/spec/models/ci/pipeline_spec.rb +++ b/spec/models/ci/pipeline_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' describe Ci::Pipeline, models: true do let(:project) { FactoryGirl.create :empty_project } - let(:pipeline) { FactoryGirl.create :ci_pipeline, project: project } + let(:pipeline) { FactoryGirl.create :ci_empty_pipeline, project: project } it { is_expected.to belong_to(:project) } it { is_expected.to belong_to(:user) } @@ -51,25 +51,6 @@ describe Ci::Pipeline, models: true do end end - describe "#finished_at" do - let(:pipeline) { FactoryGirl.create :ci_pipeline } - - it "returns finished_at of latest build" do - build = FactoryGirl.create :ci_build, pipeline: pipeline, finished_at: Time.now - 60 - FactoryGirl.create :ci_build, pipeline: pipeline, finished_at: Time.now - 120 - pipeline.reload_status! - - expect(pipeline.finished_at.to_i).to eq(build.finished_at.to_i) - end - - it "returns nil if there is no finished build" do - FactoryGirl.create :ci_not_started_build, pipeline: pipeline - pipeline.reload_status! - - expect(pipeline.finished_at).to be_nil - end - end - describe "coverage" do let(:project) { FactoryGirl.create :empty_project, build_coverage_regex: "/.*/" } let(:pipeline) { FactoryGirl.create :ci_empty_pipeline, project: project } @@ -139,31 +120,20 @@ describe Ci::Pipeline, models: true do end end - describe '#reload_status!' do + describe '#update_counters' do let(:pipeline) { create :ci_empty_pipeline, project: project } - context 'dependent objects' do - let(:commit_status) { create :commit_status, :pending, pipeline: pipeline } - - it 'executes reload_status! after succeeding dependent object' do - expect(pipeline).to receive(:reload_status!).and_return(true) - - commit_status.success - end - end - context 'updates' do let(:current) { Time.now.change(usec: 0) } let(:build) { FactoryGirl.create :ci_build, pipeline: pipeline, started_at: current - 120, finished_at: current - 60 } before do - build - pipeline.reload_status! + build.skip end [:status, :started_at, :finished_at, :duration].each do |param| it "#{param}" do - expect(pipeline.send(param)).to eq(build.send(param)) + expect(pipeline.reload.send(param)).to eq(build.send(param)) end end end -- cgit v1.2.1 From 4ccf39cde7356bf98bef5aae694257fb2c001e75 Mon Sep 17 00:00:00 2001 From: Kamil Trzcinski Date: Thu, 11 Aug 2016 22:54:25 +0200 Subject: Fix test failures, that did occur because of missing previously used `reload_status!` call --- spec/models/ci/pipeline_spec.rb | 24 ++++++++++-------------- 1 file changed, 10 insertions(+), 14 deletions(-) (limited to 'spec/models/ci/pipeline_spec.rb') diff --git a/spec/models/ci/pipeline_spec.rb b/spec/models/ci/pipeline_spec.rb index eb762276cbe..adfe4bdd0c8 100644 --- a/spec/models/ci/pipeline_spec.rb +++ b/spec/models/ci/pipeline_spec.rb @@ -120,22 +120,18 @@ describe Ci::Pipeline, models: true do end end - describe '#update_counters' do - let(:pipeline) { create :ci_empty_pipeline, project: project } + describe '#duration' do + let(:current) { Time.now.change(usec: 0) } + let!(:build) { create :ci_build, name: 'build1', pipeline: pipeline, started_at: current - 60, finished_at: current } + let!(:build2) { create :ci_build, name: 'build2', pipeline: pipeline, started_at: current - 60, finished_at: current } - context 'updates' do - let(:current) { Time.now.change(usec: 0) } - let(:build) { FactoryGirl.create :ci_build, pipeline: pipeline, started_at: current - 120, finished_at: current - 60 } - - before do - build.skip - end + before do + build.skip + build2.skip + end - [:status, :started_at, :finished_at, :duration].each do |param| - it "#{param}" do - expect(pipeline.reload.send(param)).to eq(build.send(param)) - end - end + it 'matches sum of builds duration' do + expect(pipeline.reload.duration).to eq(build.duration + build2.duration) end end -- cgit v1.2.1 From abd3ac4a038a83cce5db2aa93f685c921710abba Mon Sep 17 00:00:00 2001 From: Lin Jen-Shin Date: Fri, 12 Aug 2016 15:29:49 +0800 Subject: Make it more grammatically correct, feedback: https://gitlab.com/gitlab-org/gitlab-ce/merge_requests/5620#note_13811203 --- spec/models/ci/pipeline_spec.rb | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'spec/models/ci/pipeline_spec.rb') diff --git a/spec/models/ci/pipeline_spec.rb b/spec/models/ci/pipeline_spec.rb index 685c4178e89..2266b954aeb 100644 --- a/spec/models/ci/pipeline_spec.rb +++ b/spec/models/ci/pipeline_spec.rb @@ -329,7 +329,7 @@ describe Ci::Pipeline, models: true do end it 'receive a pending event once' do - expect(WebMock).to requested('pending').once + expect(WebMock).to have_requested_pipeline_hook('pending').once end end @@ -342,7 +342,7 @@ describe Ci::Pipeline, models: true do end it 'receive a running event once' do - expect(WebMock).to requested('running').once + expect(WebMock).to have_requested_pipeline_hook('running').once end end @@ -353,11 +353,11 @@ describe Ci::Pipeline, models: true do end it 'receive a success event once' do - expect(WebMock).to requested('success').once + expect(WebMock).to have_requested_pipeline_hook('success').once end end - def requested(status) + def have_requested_pipeline_hook(status) have_requested(:post, hook.url).with do |req| json_body = JSON.parse(req.body) json_body['object_attributes']['status'] == status && -- cgit v1.2.1 From ad3e1edcfce1e24fb9889d5d73852680cf4facf9 Mon Sep 17 00:00:00 2001 From: Kamil Trzcinski Date: Fri, 12 Aug 2016 11:53:27 +0200 Subject: Added specs for started_at and finished_at --- spec/models/ci/pipeline_spec.rb | 46 ++++++++++++++++++++++++++++++++++------- 1 file changed, 38 insertions(+), 8 deletions(-) (limited to 'spec/models/ci/pipeline_spec.rb') diff --git a/spec/models/ci/pipeline_spec.rb b/spec/models/ci/pipeline_spec.rb index adfe4bdd0c8..28d07f67b26 100644 --- a/spec/models/ci/pipeline_spec.rb +++ b/spec/models/ci/pipeline_spec.rb @@ -120,18 +120,48 @@ describe Ci::Pipeline, models: true do end end - describe '#duration' do + describe 'state machine' do let(:current) { Time.now.change(usec: 0) } - let!(:build) { create :ci_build, name: 'build1', pipeline: pipeline, started_at: current - 60, finished_at: current } - let!(:build2) { create :ci_build, name: 'build2', pipeline: pipeline, started_at: current - 60, finished_at: current } + let(:build) { create :ci_build, name: 'build1', pipeline: pipeline, started_at: current - 60, finished_at: current } + let(:build2) { create :ci_build, name: 'build2', pipeline: pipeline, started_at: current - 60, finished_at: current } - before do - build.skip - build2.skip + describe '#duration' do + before do + build.skip + build2.skip + end + + it 'matches sum of builds duration' do + expect(pipeline.reload.duration).to eq(build.duration + build2.duration) + end end - it 'matches sum of builds duration' do - expect(pipeline.reload.duration).to eq(build.duration + build2.duration) + describe '#started_at' do + it 'updates on transitioning to running' do + build.run + + expect(pipeline.reload.started_at).not_to be_nil + end + + it 'do not update on transitioning to success' do + build.success + + expect(pipeline.reload.started_at).to be_nil + end + end + + describe '#finished_at' do + it 'updates on transitioning to success' do + build.success + + expect(pipeline.reload.finished_at).not_to be_nil + end + + it 'do not update on transitioning to running' do + build.run + + expect(pipeline.reload.finished_at).to be_nil + end end end -- cgit v1.2.1 From 160aaca0fbfaa9848dec769019df9c0c78059b56 Mon Sep 17 00:00:00 2001 From: Kamil Trzcinski Date: Fri, 12 Aug 2016 12:11:28 +0200 Subject: Make pipeline to be in created state for hooks tests --- spec/models/ci/pipeline_spec.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'spec/models/ci/pipeline_spec.rb') diff --git a/spec/models/ci/pipeline_spec.rb b/spec/models/ci/pipeline_spec.rb index 9c5d56fe5bb..a3f9934971a 100644 --- a/spec/models/ci/pipeline_spec.rb +++ b/spec/models/ci/pipeline_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' describe Ci::Pipeline, models: true do let(:project) { FactoryGirl.create :empty_project } - let(:pipeline) { FactoryGirl.create :ci_empty_pipeline, project: project } + let(:pipeline) { FactoryGirl.create :ci_empty_pipeline, status: 'created', project: project } it { is_expected.to belong_to(:project) } it { is_expected.to belong_to(:user) } -- cgit v1.2.1 From ea4ac578534d3a233c3525bf8351eb2045f6e632 Mon Sep 17 00:00:00 2001 From: Kamil Trzcinski Date: Fri, 12 Aug 2016 13:57:58 +0200 Subject: Use event `enqueue` instead of `queue` --- spec/models/ci/pipeline_spec.rb | 23 +++++++++++++++++++---- 1 file changed, 19 insertions(+), 4 deletions(-) (limited to 'spec/models/ci/pipeline_spec.rb') diff --git a/spec/models/ci/pipeline_spec.rb b/spec/models/ci/pipeline_spec.rb index 28d07f67b26..950833cb219 100644 --- a/spec/models/ci/pipeline_spec.rb +++ b/spec/models/ci/pipeline_spec.rb @@ -143,7 +143,7 @@ describe Ci::Pipeline, models: true do expect(pipeline.reload.started_at).not_to be_nil end - it 'do not update on transitioning to success' do + it 'does not update on transitioning to success' do build.success expect(pipeline.reload.started_at).to be_nil @@ -157,7 +157,7 @@ describe Ci::Pipeline, models: true do expect(pipeline.reload.finished_at).not_to be_nil end - it 'do not update on transitioning to running' do + it 'does not update on transitioning to running' do build.run expect(pipeline.reload.finished_at).to be_nil @@ -257,14 +257,16 @@ describe Ci::Pipeline, models: true do subject { pipeline.reload.status } context 'on queuing' do - before { build.queue } + before do + build.enqueue + end it { is_expected.to eq('pending') } end context 'on run' do before do - build.queue + build.enqueue build.run end @@ -294,5 +296,18 @@ describe Ci::Pipeline, models: true do it { is_expected.to eq('canceled') } end + + context 'on failure and build retry' do + before do + build.drop + Ci::Build.retry(build) + end + + # We are changing a state: created > failed > running + # Instead of: created > failed > pending + # Since the pipeline already run, so it should not be pending anymore + + it { is_expected.to eq('running') } + end end end -- cgit v1.2.1 From a52fe1648e8a91f6e2f4b3a5c966a06b7f9e01e3 Mon Sep 17 00:00:00 2001 From: Kamil Trzcinski Date: Fri, 12 Aug 2016 17:34:43 +0200 Subject: Rename queue to enqueue in tests --- spec/models/ci/pipeline_spec.rb | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) (limited to 'spec/models/ci/pipeline_spec.rb') diff --git a/spec/models/ci/pipeline_spec.rb b/spec/models/ci/pipeline_spec.rb index 19f1aacaabc..8137e9f8f71 100644 --- a/spec/models/ci/pipeline_spec.rb +++ b/spec/models/ci/pipeline_spec.rb @@ -335,8 +335,8 @@ describe Ci::Pipeline, models: true do context 'with multiple builds' do context 'when build is queued' do before do - build_a.queue - build_b.queue + build_a.enqueue + build_b.enqueue end it 'receive a pending event once' do @@ -346,9 +346,9 @@ describe Ci::Pipeline, models: true do context 'when build is run' do before do - build_a.queue + build_a.enqueue build_a.run - build_b.queue + build_b.enqueue build_b.run end @@ -382,8 +382,8 @@ describe Ci::Pipeline, models: true do let(:enabled) { false } before do - build_a.queue - build_b.queue + build_a.enqueue + build_b.enqueue end it 'did not execute pipeline_hook after touched' do -- cgit v1.2.1