diff options
Diffstat (limited to 'spec')
33 files changed, 755 insertions, 274 deletions
diff --git a/spec/controllers/projects/deployments_controller_spec.rb b/spec/controllers/projects/deployments_controller_spec.rb index d1c960e895d..5b7da81b6a1 100644 --- a/spec/controllers/projects/deployments_controller_spec.rb +++ b/spec/controllers/projects/deployments_controller_spec.rb @@ -15,9 +15,9 @@ describe Projects::DeploymentsController do describe 'GET #index' do it 'returns list of deployments from last 8 hours' do - create(:deployment, environment: environment, created_at: 9.hours.ago) - create(:deployment, environment: environment, created_at: 7.hours.ago) - create(:deployment, environment: environment) + create(:deployment, :success, environment: environment, created_at: 9.hours.ago) + create(:deployment, :success, environment: environment, created_at: 7.hours.ago) + create(:deployment, :success, environment: environment) get :index, deployment_params(after: 8.hours.ago) @@ -27,7 +27,7 @@ describe Projects::DeploymentsController do end it 'returns a list with deployments information' do - create(:deployment, environment: environment) + create(:deployment, :success, environment: environment) get :index, deployment_params @@ -37,7 +37,7 @@ describe Projects::DeploymentsController do end describe 'GET #metrics' do - let(:deployment) { create(:deployment, project: project, environment: environment) } + let(:deployment) { create(:deployment, :success, project: project, environment: environment) } before do allow(controller).to receive(:deployment).and_return(deployment) @@ -110,7 +110,7 @@ describe Projects::DeploymentsController do end describe 'GET #additional_metrics' do - let(:deployment) { create(:deployment, project: project, environment: environment) } + let(:deployment) { create(:deployment, :success, project: project, environment: environment) } before do allow(controller).to receive(:deployment).and_return(deployment) diff --git a/spec/controllers/projects/jobs_controller_spec.rb b/spec/controllers/projects/jobs_controller_spec.rb index 8eb01145ed5..da3d658d061 100644 --- a/spec/controllers/projects/jobs_controller_spec.rb +++ b/spec/controllers/projects/jobs_controller_spec.rb @@ -231,7 +231,7 @@ describe Projects::JobsController, :clean_gitlab_redis_shared_state do context 'with deployment' do let(:merge_request) { create(:merge_request, source_project: project) } let(:environment) { create(:environment, project: project, name: 'staging', state: :available) } - let(:job) { create(:ci_build, :success, environment: environment.name, pipeline: pipeline) } + let(:job) { create(:ci_build, :running, environment: environment.name, pipeline: pipeline) } it 'exposes the deployment information' do expect(response).to have_gitlab_http_status(:ok) diff --git a/spec/controllers/projects/merge_requests_controller_spec.rb b/spec/controllers/projects/merge_requests_controller_spec.rb index dafff4ee405..e62523c65c9 100644 --- a/spec/controllers/projects/merge_requests_controller_spec.rb +++ b/spec/controllers/projects/merge_requests_controller_spec.rb @@ -755,7 +755,7 @@ describe Projects::MergeRequestsController do let(:environment) { create(:environment, project: forked) } let(:pipeline) { create(:ci_pipeline, sha: sha, project: forked) } let(:build) { create(:ci_build, pipeline: pipeline) } - let!(:deployment) { create(:deployment, environment: environment, sha: sha, ref: 'master', deployable: build) } + let!(:deployment) { create(:deployment, :succeed, environment: environment, sha: sha, ref: 'master', deployable: build) } let(:merge_request) do create(:merge_request, source_project: forked, target_project: project, target_branch: 'master', head_pipeline: pipeline) @@ -780,7 +780,7 @@ describe Projects::MergeRequestsController do let(:merge_commit_sha) { project.repository.merge(user, forked.commit.id, merge_request, "merged in test") } let(:post_merge_pipeline) { create(:ci_pipeline, sha: merge_commit_sha, project: project) } let(:post_merge_build) { create(:ci_build, pipeline: post_merge_pipeline) } - let!(:source_deployment) { create(:deployment, environment: source_environment, sha: merge_commit_sha, ref: 'master', deployable: post_merge_build) } + let!(:source_deployment) { create(:deployment, :succeed, environment: source_environment, sha: merge_commit_sha, ref: 'master', deployable: post_merge_build) } before do merge_request.update!(merge_commit_sha: merge_commit_sha) diff --git a/spec/factories/ci/builds.rb b/spec/factories/ci/builds.rb index 0cacdf7931f..90754319f05 100644 --- a/spec/factories/ci/builds.rb +++ b/spec/factories/ci/builds.rb @@ -100,6 +100,30 @@ FactoryBot.define do url: 'http://staging.example.com/$CI_JOB_NAME' } end + trait :deploy_to_production do + environment 'production' + + options environment: { name: 'production', + url: 'http://prd.example.com/$CI_JOB_NAME' } + end + + trait :start_review_app do + environment 'review/$CI_COMMIT_REF_NAME' + + options environment: { name: 'review/$CI_COMMIT_REF_NAME', + url: 'http://staging.example.com/$CI_JOB_NAME', + on_stop: 'stop_review_app' } + end + + trait :stop_review_app do + name 'stop_review_app' + environment 'review/$CI_COMMIT_REF_NAME' + + options environment: { name: 'review/$CI_COMMIT_REF_NAME', + url: 'http://staging.example.com/$CI_JOB_NAME', + action: 'stop' } + end + trait :allowed_to_fail do allow_failure true end diff --git a/spec/factories/deployments.rb b/spec/factories/deployments.rb index 90d6a338479..011c98599a3 100644 --- a/spec/factories/deployments.rb +++ b/spec/factories/deployments.rb @@ -21,5 +21,31 @@ FactoryBot.define do sha { TestEnv::BRANCH_SHA['pages-deploy'] } ref 'pages-deploy' end + + trait :running do + status :running + end + + trait :success do + status :success + finished_at { Time.now } + end + + trait :failed do + status :failed + finished_at { Time.now } + end + + trait :canceled do + status :canceled + finished_at { Time.now } + end + + # This trait hooks the state maechine's events + trait :succeed do + after(:create) do |deployment, evaluator| + deployment.succeed! + end + end end end diff --git a/spec/factories/environments.rb b/spec/factories/environments.rb index b5db57d5148..9d9e3d693b8 100644 --- a/spec/factories/environments.rb +++ b/spec/factories/environments.rb @@ -22,6 +22,7 @@ FactoryBot.define do pipeline: pipeline) deployment = create(:deployment, + :success, environment: environment, project: environment.project, deployable: deployable, diff --git a/spec/features/merge_request/user_sees_deployment_widget_spec.rb b/spec/features/merge_request/user_sees_deployment_widget_spec.rb index a298ead43db..cbd130b9740 100644 --- a/spec/features/merge_request/user_sees_deployment_widget_spec.rb +++ b/spec/features/merge_request/user_sees_deployment_widget_spec.rb @@ -11,7 +11,7 @@ describe 'Merge request > User sees deployment widget', :js do let(:sha) { project.commit(ref).id } let(:pipeline) { create(:ci_pipeline_without_jobs, sha: sha, project: project, ref: ref) } let(:build) { create(:ci_build, :success, pipeline: pipeline) } - let!(:deployment) { create(:deployment, environment: environment, sha: sha, ref: ref, deployable: build) } + let!(:deployment) { create(:deployment, :succeed, environment: environment, sha: sha, ref: ref, deployable: build) } let!(:manual) { } before do diff --git a/spec/features/merge_request/user_sees_merge_widget_spec.rb b/spec/features/merge_request/user_sees_merge_widget_spec.rb index 0c610edd6d1..a703823cb33 100644 --- a/spec/features/merge_request/user_sees_merge_widget_spec.rb +++ b/spec/features/merge_request/user_sees_merge_widget_spec.rb @@ -45,7 +45,8 @@ describe 'Merge request > User sees merge widget', :js do let(:build) { create(:ci_build, :success, pipeline: pipeline) } let!(:deployment) do - create(:deployment, environment: environment, + create(:deployment, :succeed, + environment: environment, ref: merge_request.source_branch, deployable: build, sha: sha) diff --git a/spec/features/projects/environments/environment_spec.rb b/spec/features/projects/environments/environment_spec.rb index 4f8f67aab22..056f4ee2e22 100644 --- a/spec/features/projects/environments/environment_spec.rb +++ b/spec/features/projects/environments/environment_spec.rb @@ -33,7 +33,7 @@ describe 'Environment' do context 'with deployments' do context 'when there is no related deployable' do let(:deployment) do - create(:deployment, environment: environment, deployable: nil) + create(:deployment, :success, environment: environment, deployable: nil) end it 'does show deployment SHA' do @@ -48,7 +48,7 @@ describe 'Environment' do let(:build) { create(:ci_build, pipeline: pipeline) } let(:deployment) do - create(:deployment, environment: environment, deployable: build) + create(:deployment, :success, environment: environment, deployable: build) end it 'does show build name' do @@ -108,7 +108,7 @@ describe 'Environment' do context 'with external_url' do let(:environment) { create(:environment, project: project, external_url: 'https://git.gitlab.com') } let(:build) { create(:ci_build, pipeline: pipeline) } - let(:deployment) { create(:deployment, environment: environment, deployable: build) } + let(:deployment) { create(:deployment, :success, environment: environment, deployable: build) } it 'does show an external link button' do expect(page).to have_link(nil, href: environment.external_url) @@ -169,7 +169,8 @@ describe 'Environment' do end let(:deployment) do - create(:deployment, environment: environment, + create(:deployment, :success, + environment: environment, deployable: build, on_stop: 'close_app') end diff --git a/spec/features/projects/environments/environments_spec.rb b/spec/features/projects/environments/environments_spec.rb index 22d0187ac81..1e26c780237 100644 --- a/spec/features/projects/environments/environments_spec.rb +++ b/spec/features/projects/environments/environments_spec.rb @@ -132,7 +132,8 @@ describe 'Environments page', :js do let(:project) { create(:project, :repository) } let!(:deployment) do - create(:deployment, environment: environment, + create(:deployment, :success, + environment: environment, sha: project.commit.id) end @@ -152,7 +153,8 @@ describe 'Environments page', :js do end let!(:deployment) do - create(:deployment, environment: environment, + create(:deployment, :success, + environment: environment, deployable: build, sha: project.commit.id) end @@ -196,7 +198,7 @@ describe 'Environments page', :js do context 'with external_url' do let(:environment) { create(:environment, project: project, external_url: 'https://git.gitlab.com') } let(:build) { create(:ci_build, pipeline: pipeline) } - let(:deployment) { create(:deployment, environment: environment, deployable: build) } + let(:deployment) { create(:deployment, :success, environment: environment, deployable: build) } it 'shows an external link button' do expect(page).to have_link(nil, href: environment.external_url) @@ -209,7 +211,8 @@ describe 'Environments page', :js do end let(:deployment) do - create(:deployment, environment: environment, + create(:deployment, :success, + environment: environment, deployable: build, on_stop: 'close_app') end diff --git a/spec/features/projects/jobs_spec.rb b/spec/features/projects/jobs_spec.rb index 5cb3f7c732f..cbb935abd53 100644 --- a/spec/features/projects/jobs_spec.rb +++ b/spec/features/projects/jobs_spec.rb @@ -396,8 +396,8 @@ describe 'Jobs', :clean_gitlab_redis_shared_state do end context 'job is successful and has deployment' do - let(:build) { create(:ci_build, :success, :trace_live, environment: environment.name, pipeline: pipeline) } - let!(:deployment) { create(:deployment, environment: environment, project: environment.project, deployable: build) } + let(:build) { create(:ci_build, :success, :trace_live, environment: environment.name, pipeline: pipeline, deployment: deployment) } + let(:deployment) { create(:deployment, :success, environment: environment, project: environment.project) } it 'shows a link for the job' do expect(page).to have_link environment.name @@ -419,7 +419,7 @@ describe 'Jobs', :clean_gitlab_redis_shared_state do end context 'deployment still not finished' do - let(:build) { create(:ci_build, :success, environment: environment.name, pipeline: pipeline) } + let(:build) { create(:ci_build, :running, environment: environment.name, pipeline: pipeline) } it 'shows a link to latest deployment' do expect(page).to have_link environment.name @@ -456,6 +456,8 @@ describe 'Jobs', :clean_gitlab_redis_shared_state do describe 'environment info in job view', :js do before do + allow_any_instance_of(Ci::Build).to receive(:create_deployment) + visit project_job_path(project, job) wait_for_requests end @@ -464,8 +466,8 @@ describe 'Jobs', :clean_gitlab_redis_shared_state do let(:job) { create(:ci_build, :success, :trace_artifact, environment: 'staging', pipeline: pipeline) } let(:second_build) { create(:ci_build, :success, :trace_artifact, environment: 'staging', pipeline: pipeline) } let(:environment) { create(:environment, name: 'staging', project: project) } - let!(:first_deployment) { create(:deployment, environment: environment, deployable: job) } - let!(:second_deployment) { create(:deployment, environment: environment, deployable: second_build) } + let!(:first_deployment) { create(:deployment, :success, environment: environment, deployable: job) } + let!(:second_deployment) { create(:deployment, :success, environment: environment, deployable: second_build) } it 'shows deployment message' do expected_text = 'This job is an out-of-date deployment ' \ @@ -505,7 +507,7 @@ describe 'Jobs', :clean_gitlab_redis_shared_state do end context 'when it has deployment' do - let!(:deployment) { create(:deployment, environment: environment) } + let!(:deployment) { create(:deployment, :success, environment: environment) } it 'shows that deployment will be overwritten' do expected_text = 'This job is creating a deployment to staging' diff --git a/spec/features/projects/view_on_env_spec.rb b/spec/features/projects/view_on_env_spec.rb index a48ad94e9fa..7bfcd46713e 100644 --- a/spec/features/projects/view_on_env_spec.rb +++ b/spec/features/projects/view_on_env_spec.rb @@ -44,7 +44,7 @@ describe 'View on environment', :js do context 'and an active deployment' do let(:sha) { project.commit(branch_name).sha } let(:environment) { create(:environment, project: project, name: 'review/feature', external_url: 'http://feature.review.example.com') } - let!(:deployment) { create(:deployment, environment: environment, ref: branch_name, sha: sha) } + let!(:deployment) { create(:deployment, :success, environment: environment, ref: branch_name, sha: sha) } context 'when visiting the diff of a merge request for the branch' do let(:merge_request) { create(:merge_request, :simple, source_project: project, source_branch: branch_name) } diff --git a/spec/finders/environments_finder_spec.rb b/spec/finders/environments_finder_spec.rb index 3cd421f22eb..25835bb4d94 100644 --- a/spec/finders/environments_finder_spec.rb +++ b/spec/finders/environments_finder_spec.rb @@ -12,7 +12,7 @@ describe EnvironmentsFinder do context 'tagged deployment' do before do - create(:deployment, environment: environment, ref: 'v1.1.0', tag: true, sha: project.commit.id) + create(:deployment, :success, environment: environment, ref: 'v1.1.0', tag: true, sha: project.commit.id) end it 'returns environment when with_tags is set' do @@ -33,7 +33,7 @@ describe EnvironmentsFinder do context 'branch deployment' do before do - create(:deployment, environment: environment, ref: 'master', sha: project.commit.id) + create(:deployment, :success, environment: environment, ref: 'master', sha: project.commit.id) end it 'returns environment when ref is set' do @@ -59,7 +59,7 @@ describe EnvironmentsFinder do context 'commit deployment' do before do - create(:deployment, environment: environment, ref: 'master', sha: project.commit.id) + create(:deployment, :success, environment: environment, ref: 'master', sha: project.commit.id) end it 'returns environment' do @@ -71,7 +71,7 @@ describe EnvironmentsFinder do context 'recently updated' do context 'when last deployment to environment is the most recent one' do before do - create(:deployment, environment: environment, ref: 'feature') + create(:deployment, :success, environment: environment, ref: 'feature') end it 'finds recently updated environment' do @@ -82,8 +82,8 @@ describe EnvironmentsFinder do context 'when last deployment to environment is not the most recent' do before do - create(:deployment, environment: environment, ref: 'feature') - create(:deployment, environment: environment, ref: 'master') + create(:deployment, :success, environment: environment, ref: 'feature') + create(:deployment, :success, environment: environment, ref: 'master') end it 'does not find environment' do @@ -96,8 +96,8 @@ describe EnvironmentsFinder do let(:second_environment) { create(:environment, project: project) } before do - create(:deployment, environment: environment, ref: 'feature') - create(:deployment, environment: second_environment, ref: 'feature') + create(:deployment, :success, environment: environment, ref: 'feature') + create(:deployment, :success, environment: second_environment, ref: 'feature') end it 'finds both environments' do diff --git a/spec/lib/gitlab/cycle_analytics/stage_summary_spec.rb b/spec/lib/gitlab/cycle_analytics/stage_summary_spec.rb index 2e67c1c7f78..f8009709ce2 100644 --- a/spec/lib/gitlab/cycle_analytics/stage_summary_spec.rb +++ b/spec/lib/gitlab/cycle_analytics/stage_summary_spec.rb @@ -44,15 +44,15 @@ describe Gitlab::CycleAnalytics::StageSummary do describe "#deploys" do it "finds the number of deploys made created after the 'from date'" do - Timecop.freeze(5.days.ago) { create(:deployment, project: project) } - Timecop.freeze(5.days.from_now) { create(:deployment, project: project) } + Timecop.freeze(5.days.ago) { create(:deployment, :success, project: project) } + Timecop.freeze(5.days.from_now) { create(:deployment, :success, project: project) } expect(subject.third[:value]).to eq(1) end it "doesn't find commits from other projects" do Timecop.freeze(5.days.from_now) do - create(:deployment, project: create(:project, :repository)) + create(:deployment, :success, project: create(:project, :repository)) end expect(subject.third[:value]).to eq(0) diff --git a/spec/lib/gitlab/slash_commands/command_spec.rb b/spec/lib/gitlab/slash_commands/command_spec.rb index 194cae8c645..eceacac58af 100644 --- a/spec/lib/gitlab/slash_commands/command_spec.rb +++ b/spec/lib/gitlab/slash_commands/command_spec.rb @@ -44,7 +44,7 @@ describe Gitlab::SlashCommands::Command do let!(:build) { create(:ci_build, pipeline: pipeline) } let!(:pipeline) { create(:ci_pipeline, project: project) } let!(:staging) { create(:environment, name: 'staging', project: project) } - let!(:deployment) { create(:deployment, environment: staging, deployable: build) } + let!(:deployment) { create(:deployment, :success, environment: staging, deployable: build) } let!(:manual) do create(:ci_build, :manual, pipeline: pipeline, diff --git a/spec/lib/gitlab/slash_commands/deploy_spec.rb b/spec/lib/gitlab/slash_commands/deploy_spec.rb index 0d57334aa4c..25f3e8a0409 100644 --- a/spec/lib/gitlab/slash_commands/deploy_spec.rb +++ b/spec/lib/gitlab/slash_commands/deploy_spec.rb @@ -31,7 +31,7 @@ describe Gitlab::SlashCommands::Deploy do let!(:staging) { create(:environment, name: 'staging', project: project) } let!(:pipeline) { create(:ci_pipeline, project: project) } let!(:build) { create(:ci_build, pipeline: pipeline) } - let!(:deployment) { create(:deployment, environment: staging, deployable: build) } + let!(:deployment) { create(:deployment, :success, environment: staging, deployable: build) } context 'without actions' do it 'does not execute an action' do diff --git a/spec/migrations/delete_inconsistent_internal_id_records_spec.rb b/spec/migrations/delete_inconsistent_internal_id_records_spec.rb index becb71cf427..4af51217031 100644 --- a/spec/migrations/delete_inconsistent_internal_id_records_spec.rb +++ b/spec/migrations/delete_inconsistent_internal_id_records_spec.rb @@ -65,6 +65,21 @@ describe DeleteInconsistentInternalIdRecords, :migration do context 'for deployments' do let(:scope) { :deployment } + let(:deployments) { table(:deployments) } + let(:internal_ids) { table(:internal_ids) } + + before do + internal_ids.create!(project_id: project1.id, usage: 2, last_value: 2) + internal_ids.create!(project_id: project2.id, usage: 2, last_value: 2) + internal_ids.create!(project_id: project3.id, usage: 2, last_value: 2) + end + + let(:create_models) do + 3.times { |i| deployments.create!(project_id: project1.id, iid: i, environment_id: 1, ref: 'master', sha: 'a', tag: false) } + 3.times { |i| deployments.create!(project_id: project2.id, iid: i, environment_id: 1, ref: 'master', sha: 'a', tag: false) } + 3.times { |i| deployments.create!(project_id: project3.id, iid: i, environment_id: 1, ref: 'master', sha: 'a', tag: false) } + end + it_behaves_like 'deleting inconsistent internal_id records' end diff --git a/spec/migrations/fill_empty_finished_at_in_deployments_spec.rb b/spec/migrations/fill_empty_finished_at_in_deployments_spec.rb new file mode 100644 index 00000000000..cf5c10f77e1 --- /dev/null +++ b/spec/migrations/fill_empty_finished_at_in_deployments_spec.rb @@ -0,0 +1,70 @@ +require 'spec_helper' +require Rails.root.join('db', 'post_migrate', '20181030135124_fill_empty_finished_at_in_deployments') + +describe FillEmptyFinishedAtInDeployments, :migration do + let(:namespaces) { table(:namespaces) } + let(:projects) { table(:projects) } + let(:environments) { table(:environments) } + let(:deployments) { table(:deployments) } + + context 'when a deployment row does not have a value on finished_at' do + context 'when a deployment succeeded' do + before do + namespaces.create!(id: 123, name: 'gitlab1', path: 'gitlab1') + projects.create!(id: 1, name: 'gitlab1', path: 'gitlab1', namespace_id: 123) + environments.create!(id: 1, name: 'production', slug: 'production', project_id: 1) + deployments.create!(id: 1, iid: 1, project_id: 1, environment_id: 1, ref: 'master', sha: 'xxx', tag: false) + end + + it 'correctly replicates finished_at by created_at' do + expect(deployments.last.created_at).not_to be_nil + expect(deployments.last.finished_at).to be_nil + + migrate! + + expect(deployments.last.created_at).not_to be_nil + expect(deployments.last.finished_at).to eq(deployments.last.created_at) + end + end + + context 'when a deployment is running' do + before do + namespaces.create!(id: 123, name: 'gitlab1', path: 'gitlab1') + projects.create!(id: 1, name: 'gitlab1', path: 'gitlab1', namespace_id: 123) + environments.create!(id: 1, name: 'production', slug: 'production', project_id: 1) + deployments.create!(id: 1, iid: 1, project_id: 1, environment_id: 1, ref: 'master', sha: 'xxx', tag: false, status: 1) + end + + it 'does not fill finished_at' do + expect(deployments.last.created_at).not_to be_nil + expect(deployments.last.finished_at).to be_nil + + migrate! + + expect(deployments.last.created_at).not_to be_nil + expect(deployments.last.finished_at).to be_nil + end + end + end + + context 'when a deployment row does has a value on finished_at' do + let(:finished_at) { '2018-10-30 11:12:02 UTC' } + + before do + namespaces.create!(id: 123, name: 'gitlab1', path: 'gitlab1') + projects.create!(id: 1, name: 'gitlab1', path: 'gitlab1', namespace_id: 123) + environments.create!(id: 1, name: 'production', slug: 'production', project_id: 1) + deployments.create!(id: 1, iid: 1, project_id: 1, environment_id: 1, ref: 'master', sha: 'xxx', tag: false, finished_at: finished_at) + end + + it 'does not affect existing value' do + expect(deployments.last.created_at).not_to be_nil + expect(deployments.last.finished_at).not_to be_nil + + migrate! + + expect(deployments.last.created_at).not_to be_nil + expect(deployments.last.finished_at).to eq(finished_at) + end + end +end diff --git a/spec/models/ci/build_spec.rb b/spec/models/ci/build_spec.rb index 4089f099fdf..2e65a6a2a0f 100644 --- a/spec/models/ci/build_spec.rb +++ b/spec/models/ci/build_spec.rb @@ -17,8 +17,8 @@ describe Ci::Build do it { is_expected.to belong_to(:runner) } it { is_expected.to belong_to(:trigger_request) } it { is_expected.to belong_to(:erased_by) } - it { is_expected.to have_many(:deployments) } it { is_expected.to have_many(:trace_sections)} + it { is_expected.to have_one(:deployment) } it { is_expected.to have_one(:runner_session)} it { is_expected.to validate_presence_of(:ref) } it { is_expected.to respond_to(:has_trace?) } @@ -799,17 +799,100 @@ describe Ci::Build do end end + describe 'state transition as a deployable' do + let!(:build) { create(:ci_build, :start_review_app) } + let(:deployment) { build.deployment } + let(:environment) { deployment.environment } + + it 'has deployments record with created status' do + expect(deployment).to be_created + expect(environment.name).to eq('review/master') + end + + context 'when transits to running' do + before do + build.run! + end + + it 'transits deployment status to running' do + expect(deployment).to be_running + end + end + + context 'when transits to success' do + before do + allow(Deployments::SuccessWorker).to receive(:perform_async) + build.success! + end + + it 'transits deployment status to success' do + expect(deployment).to be_success + end + end + + context 'when transits to failed' do + before do + build.drop! + end + + it 'transits deployment status to failed' do + expect(deployment).to be_failed + end + end + + context 'when transits to skipped' do + before do + build.skip! + end + + it 'transits deployment status to canceled' do + expect(deployment).to be_canceled + end + end + + context 'when transits to canceled' do + before do + build.cancel! + end + + it 'transits deployment status to canceled' do + expect(deployment).to be_canceled + end + end + end + + describe '#on_stop' do + subject { build.on_stop } + + context 'when a job has a specification that it can be stopped from the other job' do + let(:build) { create(:ci_build, :start_review_app) } + + it 'returns the other job name' do + is_expected.to eq('stop_review_app') + end + end + + context 'when a job does not have environment information' do + let(:build) { create(:ci_build) } + + it 'returns nil' do + is_expected.to be_nil + end + end + end + describe 'deployment' do - describe '#last_deployment' do - subject { build.last_deployment } + describe '#has_deployment?' do + subject { build.has_deployment? } + + context 'when build has a deployment' do + let!(:deployment) { create(:deployment, deployable: build) } - context 'when multiple deployments are created' do - let!(:deployment1) { create(:deployment, deployable: build) } - let!(:deployment2) { create(:deployment, deployable: build) } + it { is_expected.to be_truthy } + end - it 'returns the latest one' do - is_expected.to eq(deployment2) - end + context 'when build does not have a deployment' do + it { is_expected.to be_falsy } end end @@ -818,14 +901,14 @@ describe Ci::Build do context 'when build succeeded' do let(:build) { create(:ci_build, :success) } - let!(:deployment) { create(:deployment, deployable: build) } + let!(:deployment) { create(:deployment, :success, deployable: build) } context 'current deployment is latest' do it { is_expected.to be_falsey } end context 'current deployment is not latest on environment' do - let!(:deployment2) { create(:deployment, environment: deployment.environment) } + let!(:deployment2) { create(:deployment, :success, environment: deployment.environment) } it { is_expected.to be_truthy } end @@ -3209,10 +3292,14 @@ describe Ci::Build do end describe '#deployment_status' do + before do + allow_any_instance_of(described_class).to receive(:create_deployment) + end + context 'when build is a last deployment' do let(:build) { create(:ci_build, :success, environment: 'production') } let(:environment) { create(:environment, name: 'production', project: build.project) } - let!(:deployment) { create(:deployment, environment: environment, project: environment.project, deployable: build) } + let!(:deployment) { create(:deployment, :success, environment: environment, project: environment.project, deployable: build) } it { expect(build.deployment_status).to eq(:last) } end @@ -3220,8 +3307,8 @@ describe Ci::Build do context 'when there is a newer build with deployment' do let(:build) { create(:ci_build, :success, environment: 'production') } let(:environment) { create(:environment, name: 'production', project: build.project) } - let!(:deployment) { create(:deployment, environment: environment, project: environment.project, deployable: build) } - let!(:last_deployment) { create(:deployment, environment: environment, project: environment.project) } + let!(:deployment) { create(:deployment, :success, environment: environment, project: environment.project, deployable: build) } + let!(:last_deployment) { create(:deployment, :success, environment: environment, project: environment.project) } it { expect(build.deployment_status).to eq(:out_of_date) } end @@ -3229,7 +3316,7 @@ describe Ci::Build do context 'when build with deployment has failed' do let(:build) { create(:ci_build, :failed, environment: 'production') } let(:environment) { create(:environment, name: 'production', project: build.project) } - let!(:deployment) { create(:deployment, environment: environment, project: environment.project, deployable: build) } + let!(:deployment) { create(:deployment, :success, environment: environment, project: environment.project, deployable: build) } it { expect(build.deployment_status).to eq(:failed) } end @@ -3237,14 +3324,7 @@ describe Ci::Build do context 'when build with deployment is running' do let(:build) { create(:ci_build, environment: 'production') } let(:environment) { create(:environment, name: 'production', project: build.project) } - let!(:deployment) { create(:deployment, environment: environment, project: environment.project, deployable: build) } - - it { expect(build.deployment_status).to eq(:creating) } - end - - context 'when build is successful but deployment is not ready yet' do - let(:build) { create(:ci_build, :success, environment: 'production') } - let(:environment) { create(:environment, name: 'production', project: build.project) } + let!(:deployment) { create(:deployment, :success, environment: environment, project: environment.project, deployable: build) } it { expect(build.deployment_status).to eq(:creating) } end diff --git a/spec/models/concerns/deployable_spec.rb b/spec/models/concerns/deployable_spec.rb new file mode 100644 index 00000000000..e30e9689717 --- /dev/null +++ b/spec/models/concerns/deployable_spec.rb @@ -0,0 +1,45 @@ +require 'rails_helper' + +describe Deployable do + describe '#create_deployment' do + let(:deployment) { job.deployment } + let(:environment) { deployment&.environment } + + before do + job.reload + end + + context 'when the deployable object will deploy to production' do + let!(:job) { create(:ci_build, :start_review_app) } + + it 'creates a deployment and environment record' do + expect(deployment.project).to eq(job.project) + expect(deployment.ref).to eq(job.ref) + expect(deployment.tag).to eq(job.tag) + expect(deployment.sha).to eq(job.sha) + expect(deployment.user).to eq(job.user) + expect(deployment.deployable).to eq(job) + expect(deployment.on_stop).to eq('stop_review_app') + expect(environment.name).to eq('review/master') + end + end + + context 'when the deployable object has already had a deployment' do + let!(:job) { create(:ci_build, :start_review_app, deployment: race_deployment) } + let!(:race_deployment) { create(:deployment, :success) } + + it 'does not create a new deployment' do + expect(deployment).to eq(race_deployment) + end + end + + context 'when the deployable object will not deploy' do + let!(:job) { create(:ci_build) } + + it 'does not create a deployment and environment record' do + expect(deployment).to be_nil + expect(environment).to be_nil + end + end + end +end diff --git a/spec/models/deployment_spec.rb b/spec/models/deployment_spec.rb index 146d35122f7..06c1e9c8c6a 100644 --- a/spec/models/deployment_spec.rb +++ b/spec/models/deployment_spec.rb @@ -42,16 +42,174 @@ describe Deployment do end end - describe 'after_create callbacks' do - let(:environment) { create(:environment) } - let(:store) { Gitlab::EtagCaching::Store.new } + describe '.success' do + subject { described_class.success } - it 'invalidates the environment etag cache' do - old_value = store.get(environment.etag_cache_key) + context 'when deployment status is success' do + let(:deployment) { create(:deployment, :success) } - create(:deployment, environment: environment) + it { is_expected.to eq([deployment]) } + end + + context 'when deployment status is created' do + let(:deployment) { create(:deployment, :created) } + + it { is_expected.to be_empty } + end + + context 'when deployment status is running' do + let(:deployment) { create(:deployment, :running) } + + it { is_expected.to be_empty } + end + end + + describe 'state machine' do + context 'when deployment runs' do + let(:deployment) { create(:deployment) } + + before do + deployment.run! + end + + it 'starts running' do + Timecop.freeze do + expect(deployment).to be_running + expect(deployment.finished_at).to be_nil + end + end + end + + context 'when deployment succeeded' do + let(:deployment) { create(:deployment, :running) } + + it 'has correct status' do + Timecop.freeze do + deployment.succeed! + + expect(deployment).to be_success + expect(deployment.finished_at).to eq(Time.now) + end + end + + it 'executes Deployments::SuccessWorker asynchronously' do + expect(Deployments::SuccessWorker) + .to receive(:perform_async).with(deployment.id) - expect(store.get(environment.etag_cache_key)).not_to eq(old_value) + deployment.succeed! + end + end + + context 'when deployment failed' do + let(:deployment) { create(:deployment, :running) } + + it 'has correct status' do + Timecop.freeze do + deployment.drop! + + expect(deployment).to be_failed + expect(deployment.finished_at).to eq(Time.now) + end + end + end + + context 'when deployment was canceled' do + let(:deployment) { create(:deployment, :running) } + + it 'has correct status' do + Timecop.freeze do + deployment.cancel! + + expect(deployment).to be_canceled + expect(deployment.finished_at).to eq(Time.now) + end + end + end + end + + describe '#success?' do + subject { deployment.success? } + + context 'when deployment status is success' do + let(:deployment) { create(:deployment, :success) } + + it { is_expected.to be_truthy } + end + + context 'when deployment status is failed' do + let(:deployment) { create(:deployment, :failed) } + + it { is_expected.to be_falsy } + end + end + + describe '#status_name' do + subject { deployment.status_name } + + context 'when deployment status is success' do + let(:deployment) { create(:deployment, :success) } + + it { is_expected.to eq(:success) } + end + + context 'when deployment status is failed' do + let(:deployment) { create(:deployment, :failed) } + + it { is_expected.to eq(:failed) } + end + end + + describe '#finished_at' do + subject { deployment.finished_at } + + context 'when deployment status is created' do + let(:deployment) { create(:deployment) } + + it { is_expected.to be_nil } + end + + context 'when deployment status is success' do + let(:deployment) { create(:deployment, :success) } + + it { is_expected.to eq(deployment.read_attribute(:finished_at)) } + end + + context 'when deployment status is success' do + let(:deployment) { create(:deployment, :success, finished_at: nil) } + + before do + deployment.update_column(:finished_at, nil) + end + + it { is_expected.to eq(deployment.read_attribute(:created_at)) } + end + + context 'when deployment status is running' do + let(:deployment) { create(:deployment, :running) } + + it { is_expected.to be_nil } + end + end + + describe '#deployed_at' do + subject { deployment.deployed_at } + + context 'when deployment status is created' do + let(:deployment) { create(:deployment) } + + it { is_expected.to be_nil } + end + + context 'when deployment status is success' do + let(:deployment) { create(:deployment, :success) } + + it { is_expected.to eq(deployment.read_attribute(:finished_at)) } + end + + context 'when deployment status is running' do + let(:deployment) { create(:deployment, :running) } + + it { is_expected.to be_nil } end end @@ -112,7 +270,7 @@ describe Deployment do end describe '#metrics' do - let(:deployment) { create(:deployment) } + let(:deployment) { create(:deployment, :success) } let(:prometheus_adapter) { double('prometheus_adapter', can_query?: true) } subject { deployment.metrics } @@ -141,7 +299,7 @@ describe Deployment do describe '#additional_metrics' do let(:project) { create(:project, :repository) } - let(:deployment) { create(:deployment, project: project) } + let(:deployment) { create(:deployment, :succeed, project: project) } subject { deployment.additional_metrics } diff --git a/spec/models/environment_spec.rb b/spec/models/environment_spec.rb index 1de95d881a7..e121369f6ac 100644 --- a/spec/models/environment_spec.rb +++ b/spec/models/environment_spec.rb @@ -95,7 +95,7 @@ describe Environment do context 'with a last deployment' do let!(:deployment) do - create(:deployment, environment: environment, sha: project.commit('master').id) + create(:deployment, :success, environment: environment, sha: project.commit('master').id) end context 'in the same branch' do @@ -136,8 +136,8 @@ describe Environment do describe '#first_deployment_for' do let(:project) { create(:project, :repository) } - let!(:deployment) { create(:deployment, environment: environment, ref: commit.parent.id) } - let!(:deployment1) { create(:deployment, environment: environment, ref: commit.id) } + let!(:deployment) { create(:deployment, :succeed, environment: environment, ref: commit.parent.id) } + let!(:deployment1) { create(:deployment, :succeed, environment: environment, ref: commit.id) } let(:head_commit) { project.commit } let(:commit) { project.commit.parent } @@ -181,7 +181,8 @@ describe Environment do let(:build) { create(:ci_build) } let!(:deployment) do - create(:deployment, environment: environment, + create(:deployment, :success, + environment: environment, deployable: build, on_stop: 'close_app') end @@ -249,7 +250,8 @@ describe Environment do let(:build) { create(:ci_build, pipeline: pipeline) } let!(:deployment) do - create(:deployment, environment: environment, + create(:deployment, :success, + environment: environment, deployable: build, on_stop: 'close_app') end @@ -304,7 +306,7 @@ describe Environment do context 'when last deployment to environment is the most recent one' do before do - create(:deployment, environment: environment, ref: 'feature') + create(:deployment, :success, environment: environment, ref: 'feature') end it { is_expected.to be true } @@ -312,8 +314,8 @@ describe Environment do context 'when last deployment to environment is not the most recent' do before do - create(:deployment, environment: environment, ref: 'feature') - create(:deployment, environment: environment, ref: 'master') + create(:deployment, :success, environment: environment, ref: 'feature') + create(:deployment, :success, environment: environment, ref: 'master') end it { is_expected.to be false } @@ -321,7 +323,7 @@ describe Environment do end describe '#actions_for' do - let(:deployment) { create(:deployment, environment: environment) } + let(:deployment) { create(:deployment, :success, environment: environment) } let(:pipeline) { deployment.deployable.pipeline } let!(:review_action) { create(:ci_build, :manual, name: 'review-apps', pipeline: pipeline, environment: 'review/$CI_COMMIT_REF_NAME' )} let!(:production_action) { create(:ci_build, :manual, name: 'production', pipeline: pipeline, environment: 'production' )} @@ -331,6 +333,70 @@ describe Environment do end end + describe '.deployments' do + subject { environment.deployments } + + context 'when there is a deployment record with created status' do + let(:deployment) { create(:deployment, :created, environment: environment) } + + it 'does not return the record' do + is_expected.to be_empty + end + end + + context 'when there is a deployment record with running status' do + let(:deployment) { create(:deployment, :running, environment: environment) } + + it 'does not return the record' do + is_expected.to be_empty + end + end + + context 'when there is a deployment record with success status' do + let(:deployment) { create(:deployment, :success, environment: environment) } + + it 'returns the record' do + is_expected.to eq([deployment]) + end + end + end + + describe '.last_deployment' do + subject { environment.last_deployment } + + before do + allow_any_instance_of(Deployment).to receive(:create_ref) + end + + context 'when there is an old deployment record' do + let!(:previous_deployment) { create(:deployment, :success, environment: environment) } + + context 'when there is a deployment record with created status' do + let!(:deployment) { create(:deployment, environment: environment) } + + it 'returns the previous deployment' do + is_expected.to eq(previous_deployment) + end + end + + context 'when there is a deployment record with running status' do + let!(:deployment) { create(:deployment, :running, environment: environment) } + + it 'returns the previous deployment' do + is_expected.to eq(previous_deployment) + end + end + + context 'when there is a deployment record with success status' do + let!(:deployment) { create(:deployment, :success, environment: environment) } + + it 'returns the latest successful deployment' do + is_expected.to eq(deployment) + end + end + end + end + describe '#has_terminals?' do subject { environment.has_terminals? } @@ -338,7 +404,7 @@ describe Environment do context 'with a deployment service' do shared_examples 'same behavior between KubernetesService and Platform::Kubernetes' do context 'and a deployment' do - let!(:deployment) { create(:deployment, environment: environment) } + let!(:deployment) { create(:deployment, :success, environment: environment) } it { is_expected.to be_truthy } end diff --git a/spec/models/environment_status_spec.rb b/spec/models/environment_status_spec.rb index e7805d52d75..52b98552184 100644 --- a/spec/models/environment_status_spec.rb +++ b/spec/models/environment_status_spec.rb @@ -1,7 +1,7 @@ require 'spec_helper' describe EnvironmentStatus do - let(:deployment) { create(:deployment, :review_app) } + let(:deployment) { create(:deployment, :succeed, :review_app) } let(:environment) { deployment.environment} let(:project) { deployment.project } let(:merge_request) { create(:merge_request, :deployed_review_app, deployment: deployment) } @@ -12,7 +12,7 @@ describe EnvironmentStatus do it { is_expected.to delegate_method(:id).to(:environment) } it { is_expected.to delegate_method(:name).to(:environment) } it { is_expected.to delegate_method(:project).to(:environment) } - it { is_expected.to delegate_method(:deployed_at).to(:deployment).as(:created_at) } + it { is_expected.to delegate_method(:deployed_at).to(:deployment) } it { is_expected.to delegate_method(:status).to(:deployment) } describe '#project' do diff --git a/spec/models/merge_request_spec.rb b/spec/models/merge_request_spec.rb index 2eb5e39ccfd..3a54725c7ec 100644 --- a/spec/models/merge_request_spec.rb +++ b/spec/models/merge_request_spec.rb @@ -1836,8 +1836,8 @@ describe MergeRequest do let(:environments) { create_list(:environment, 3, project: project) } before do - create(:deployment, environment: environments.first, ref: 'master', sha: project.commit('master').id) - create(:deployment, environment: environments.second, ref: 'feature', sha: project.commit('feature').id) + create(:deployment, :success, environment: environments.first, ref: 'master', sha: project.commit('master').id) + create(:deployment, :success, environment: environments.second, ref: 'feature', sha: project.commit('feature').id) end it 'selects deployed environments' do @@ -1857,7 +1857,7 @@ describe MergeRequest do let(:source_environment) { create(:environment, project: source_project) } before do - create(:deployment, environment: source_environment, ref: 'feature', sha: merge_request.diff_head_sha) + create(:deployment, :success, environment: source_environment, ref: 'feature', sha: merge_request.diff_head_sha) end it 'selects deployed environments' do @@ -1868,7 +1868,7 @@ describe MergeRequest do let(:target_environment) { create(:environment, project: project) } before do - create(:deployment, environment: target_environment, tag: true, sha: merge_request.diff_head_sha) + create(:deployment, :success, environment: target_environment, tag: true, sha: merge_request.diff_head_sha) end it 'selects deployed environments' do diff --git a/spec/models/project_spec.rb b/spec/models/project_spec.rb index 84326724118..f020557e4af 100644 --- a/spec/models/project_spec.rb +++ b/spec/models/project_spec.rb @@ -3976,6 +3976,40 @@ describe Project do end end + describe '.deployments' do + subject { project.deployments } + + let(:project) { create(:project) } + + before do + allow_any_instance_of(Deployment).to receive(:create_ref) + end + + context 'when there is a deployment record with created status' do + let(:deployment) { create(:deployment, :created, project: project) } + + it 'does not return the record' do + is_expected.to be_empty + end + end + + context 'when there is a deployment record with running status' do + let(:deployment) { create(:deployment, :running, project: project) } + + it 'does not return the record' do + is_expected.to be_empty + end + end + + context 'when there is a deployment record with success status' do + let(:deployment) { create(:deployment, :success, project: project) } + + it 'returns the record' do + is_expected.to eq([deployment]) + end + end + end + def rugged_config rugged_repo(project.repository).config end diff --git a/spec/requests/api/deployments_spec.rb b/spec/requests/api/deployments_spec.rb index 61ae053cea7..3dac7225b7a 100644 --- a/spec/requests/api/deployments_spec.rb +++ b/spec/requests/api/deployments_spec.rb @@ -10,9 +10,9 @@ describe API::Deployments do describe 'GET /projects/:id/deployments' do let(:project) { create(:project) } - let!(:deployment_1) { create(:deployment, project: project, iid: 11, ref: 'master', created_at: Time.now) } - let!(:deployment_2) { create(:deployment, project: project, iid: 12, ref: 'feature', created_at: 1.day.ago) } - let!(:deployment_3) { create(:deployment, project: project, iid: 8, ref: 'feature', created_at: 2.days.ago) } + let!(:deployment_1) { create(:deployment, :success, project: project, iid: 11, ref: 'master', created_at: Time.now) } + let!(:deployment_2) { create(:deployment, :success, project: project, iid: 12, ref: 'feature', created_at: 1.day.ago) } + let!(:deployment_3) { create(:deployment, :success, project: project, iid: 8, ref: 'patch', created_at: 2.days.ago) } context 'as member of the project' do it 'returns projects deployments sorted by id asc' do @@ -53,8 +53,8 @@ describe API::Deployments do 'id' | 'desc' | [:deployment_3, :deployment_2, :deployment_1] 'iid' | 'asc' | [:deployment_3, :deployment_1, :deployment_2] 'iid' | 'desc' | [:deployment_2, :deployment_1, :deployment_3] - 'ref' | 'asc' | [:deployment_2, :deployment_3, :deployment_1] - 'ref' | 'desc' | [:deployment_1, :deployment_2, :deployment_3] + 'ref' | 'asc' | [:deployment_2, :deployment_1, :deployment_3] + 'ref' | 'desc' | [:deployment_3, :deployment_1, :deployment_2] end with_them do @@ -76,7 +76,7 @@ describe API::Deployments do describe 'GET /projects/:id/deployments/:deployment_id' do let(:project) { deployment.environment.project } - let!(:deployment) { create(:deployment) } + let!(:deployment) { create(:deployment, :success) } context 'as a member of the project' do it 'returns the projects deployment' do diff --git a/spec/serializers/environment_serializer_spec.rb b/spec/serializers/environment_serializer_spec.rb index 0f0ab5ac796..87493a28d1f 100644 --- a/spec/serializers/environment_serializer_spec.rb +++ b/spec/serializers/environment_serializer_spec.rb @@ -14,7 +14,8 @@ describe EnvironmentSerializer do let(:project) { create(:project, :repository) } let(:deployable) { create(:ci_build) } let(:deployment) do - create(:deployment, deployable: deployable, + create(:deployment, :success, + deployable: deployable, user: user, project: project, sha: project.commit.id) diff --git a/spec/serializers/environment_status_entity_spec.rb b/spec/serializers/environment_status_entity_spec.rb index 1b4d8b70aa6..962ec919092 100644 --- a/spec/serializers/environment_status_entity_spec.rb +++ b/spec/serializers/environment_status_entity_spec.rb @@ -4,8 +4,8 @@ describe EnvironmentStatusEntity do let(:user) { create(:user) } let(:request) { double('request') } - let(:deployment) { create(:deployment, :review_app) } - let(:environment) { deployment.environment} + let(:deployment) { create(:deployment, :succeed, :review_app) } + let(:environment) { deployment.environment } let(:project) { deployment.project } let(:merge_request) { create(:merge_request, :deployed_review_app, deployment: deployment) } diff --git a/spec/services/ci/retry_build_service_spec.rb b/spec/services/ci/retry_build_service_spec.rb index 368abded448..e779675744c 100644 --- a/spec/services/ci/retry_build_service_spec.rb +++ b/spec/services/ci/retry_build_service_spec.rb @@ -32,7 +32,7 @@ describe Ci::RetryBuildService do IGNORE_ACCESSORS = %i[type lock_version target_url base_tags trace_sections - commit_id deployments erased_by_id last_deployment project_id + commit_id deployment erased_by_id project_id runner_id tag_taggings taggings tags trigger_request_id user_id auto_canceled_by_id retried failure_reason artifacts_file_store artifacts_metadata_store diff --git a/spec/services/create_deployment_service_spec.rb b/spec/services/update_deployment_service_spec.rb index b9bfbb11511..572e1e9f14e 100644 --- a/spec/services/create_deployment_service_spec.rb +++ b/spec/services/update_deployment_service_spec.rb @@ -1,50 +1,57 @@ require 'spec_helper' -describe CreateDeploymentService do +describe UpdateDeploymentService do let(:user) { create(:user) } - let(:options) { nil } + let(:options) { { name: 'production' } } let(:job) do create(:ci_build, ref: 'master', tag: false, environment: 'production', - options: { environment: options }) + options: { environment: options }, + project: project) end - let(:project) { job.project } - - let!(:environment) do - create(:environment, project: project, name: 'production') - end - - let(:service) { described_class.new(job) } + let(:project) { create(:project, :repository) } + let(:environment) { deployment.environment } + let(:deployment) { job.deployment } + let(:service) { described_class.new(deployment) } before do - allow_any_instance_of(Deployment).to receive(:create_ref) + job.success! # Create/Succeed deployment end describe '#execute' do subject { service.execute } - context 'when environment exists' do - it 'creates a deployment' do - expect(subject).to be_persisted - end + let(:store) { Gitlab::EtagCaching::Store.new } + + it 'invalidates the environment etag cache' do + old_value = store.get(environment.etag_cache_key) + + subject + + expect(store.get(environment.etag_cache_key)).not_to eq(old_value) end - context 'when environment does not exist' do - let(:environment) {} + it 'creates ref' do + expect_any_instance_of(Repository) + .to receive(:create_ref) + .with(deployment.ref, deployment.send(:ref_path)) - it 'does not create a deployment' do - expect do - expect(subject).to be_nil - end.not_to change { Deployment.count } - end + subject + end + + it 'updates merge request metrics' do + expect_any_instance_of(Deployment) + .to receive(:update_merge_request_metrics!) + + subject end context 'when start action is defined' do - let(:options) { { action: 'start' } } + let(:options) { { name: 'production', action: 'start' } } context 'and environment is stopped' do before do @@ -56,15 +63,11 @@ describe CreateDeploymentService do expect(environment.reload).to be_available end - - it 'creates a deployment' do - expect(subject).to be_persisted - end end end context 'when stop action is defined' do - let(:options) { { action: 'stop' } } + let(:options) { { name: 'production', action: 'stop' } } context 'and environment is available' do before do @@ -76,10 +79,6 @@ describe CreateDeploymentService do expect(environment.reload).to be_stopped end - - it 'does not create a deployment' do - expect(subject).to be_nil - end end end @@ -94,10 +93,6 @@ describe CreateDeploymentService do job.update(environment: 'review-apps/$CI_COMMIT_REF_NAME') end - it 'creates a new deployment' do - expect(subject).to be_persisted - end - it 'does not create a new environment' do expect { subject }.not_to change { Environment.count } end @@ -109,21 +104,6 @@ describe CreateDeploymentService do expect(subject.environment.external_url).to eq('http://master.review-apps.gitlab.com') end end - - context 'when project was removed' do - let(:environment) {} - - before do - job.update(project: nil) - end - - it 'does not create deployment or environment' do - expect { subject }.not_to raise_error - - expect(Environment.count).to be_zero - expect(Deployment.count).to be_zero - end - end end describe '#expanded_environment_url' do @@ -133,7 +113,9 @@ describe CreateDeploymentService do let(:job) do create(:ci_build, ref: 'master', - options: { environment: { url: 'http://review/$CI_COMMIT_REF_NAME' } }) + environment: 'production', + project: project, + options: { environment: { name: 'production', url: 'http://review/$CI_COMMIT_REF_NAME' } }) end it { is_expected.to eq('http://review/master') } @@ -143,16 +125,9 @@ describe CreateDeploymentService do let(:job) do create(:ci_build, ref: 'master', - environment: 'production', - options: { environment: { url: 'http://review/$CI_ENVIRONMENT_SLUG' } }) - end - - let!(:environment) do - create(:environment, - project: job.project, - name: 'production', - slug: 'prod-slug', - external_url: 'http://review/old') + environment: 'prod-slug', + project: project, + options: { environment: { name: 'prod-slug', url: 'http://review/$CI_ENVIRONMENT_SLUG' } }) end it { is_expected.to eq('http://review/prod-slug') } @@ -162,18 +137,16 @@ describe CreateDeploymentService do let(:job) do create(:ci_build, yaml_variables: [{ key: :APP_HOST, value: 'host' }], - options: { environment: { url: 'http://review/$APP_HOST' } }) + environment: 'production', + project: project, + options: { environment: { name: 'production', url: 'http://review/$APP_HOST' } }) end it { is_expected.to eq('http://review/host') } end context 'when yaml environment does not have url' do - let(:job) { create(:ci_build, environment: 'staging') } - - let!(:environment) do - create(:environment, project: job.project, name: job.environment) - end + let(:job) { create(:ci_build, environment: 'staging', project: project) } it 'returns the external_url from persisted environment' do is_expected.to be_nil @@ -181,108 +154,36 @@ describe CreateDeploymentService do end end - describe 'processing of builds' do - shared_examples 'does not create deployment' do - it 'does not create a new deployment' do - expect { subject }.not_to change { Deployment.count } - end - - it 'does not call a service' do - expect_any_instance_of(described_class).not_to receive(:execute) - - subject - end - end - - shared_examples 'creates deployment' do - it 'creates a new deployment' do - expect { subject }.to change { Deployment.count }.by(1) - end - - it 'calls a service' do - expect_any_instance_of(described_class).to receive(:execute) - - subject - end - - it 'is set as deployable' do - subject - - expect(Deployment.last.deployable).to eq(deployable) - end - - it 'updates environment URL' do - subject - - expect(Deployment.last.environment.external_url).not_to be_nil - end - end - - context 'without environment specified' do - let(:job) { create(:ci_build) } - - it_behaves_like 'does not create deployment' do - subject { job.success } - end - end - - context 'when environment is specified' do - let(:deployable) { job } - - let(:options) do - { environment: { name: 'production', url: 'http://gitlab.com' } } - end - - context 'when job succeeds' do - it_behaves_like 'creates deployment' do - subject { job.success } - end - end - - context 'when job fails' do - it_behaves_like 'does not create deployment' do - subject { job.drop } - end - end - - context 'when job is retried' do - it_behaves_like 'creates deployment' do - before do - stub_not_protect_default_branch - - project.add_developer(user) - end - - let(:deployable) { Ci::Build.retry(job, user) } - - subject { deployable.success } - end - end - end - end - describe "merge request metrics" do let(:merge_request) { create(:merge_request, target_branch: 'master', source_branch: 'feature', source_project: project) } context "while updating the 'first_deployed_to_production_at' time" do before do - merge_request.metrics.update!(merged_at: Time.now) + merge_request.metrics.update!(merged_at: 1.hour.ago) end context "for merge requests merged before the current deploy" do it "sets the time if the deploy's environment is 'production'" do - time = Time.now - Timecop.freeze(time) { service.execute } + service.execute - expect(merge_request.reload.metrics.first_deployed_to_production_at).to be_like_time(time) + expect(merge_request.reload.metrics.first_deployed_to_production_at).to be_like_time(deployment.finished_at) end - it "doesn't set the time if the deploy's environment is not 'production'" do - job.update(environment: 'staging') - service = described_class.new(job) - service.execute + context 'when job deploys to staging' do + let(:job) do + create(:ci_build, + ref: 'master', + tag: false, + environment: 'staging', + options: { environment: { name: 'staging' } }, + project: project) + end + + it "doesn't set the time if the deploy's environment is not 'production'" do + service.execute - expect(merge_request.reload.metrics.first_deployed_to_production_at).to be_nil + expect(merge_request.reload.metrics.first_deployed_to_production_at).to be_nil + end end it 'does not raise errors if the merge request does not have a metrics record' do @@ -303,7 +204,6 @@ describe CreateDeploymentService do expect(merge_request.reload.metrics.first_deployed_to_production_at).to be_like_time(time) # Current deploy - service = described_class.new(job) Timecop.freeze(time + 12.hours) { service.execute } expect(merge_request.reload.metrics.first_deployed_to_production_at).to be_like_time(time) @@ -318,15 +218,12 @@ describe CreateDeploymentService do expect(merge_request.reload.metrics.merged_at).to be < merge_request.reload.metrics.first_deployed_to_production_at - merge_request.reload.metrics.update(first_deployed_to_production_at: nil) - - expect(merge_request.reload.metrics.first_deployed_to_production_at).to be_nil + previous_time = merge_request.reload.metrics.first_deployed_to_production_at # Current deploy - service = described_class.new(job) Timecop.freeze(time + 12.hours) { service.execute } - expect(merge_request.reload.metrics.first_deployed_to_production_at).to be_nil + expect(merge_request.reload.metrics.first_deployed_to_production_at).to eq(previous_time) end end end diff --git a/spec/support/helpers/cycle_analytics_helpers.rb b/spec/support/helpers/cycle_analytics_helpers.rb index 83035788a56..ecefdc23811 100644 --- a/spec/support/helpers/cycle_analytics_helpers.rb +++ b/spec/support/helpers/cycle_analytics_helpers.rb @@ -85,7 +85,7 @@ module CycleAnalyticsHelpers raise ArgumentError end - CreateDeploymentService.new(dummy_job).execute + dummy_job.success! # State machine automatically update associated deployment/environment record end def dummy_production_job(user, project) @@ -97,7 +97,7 @@ module CycleAnalyticsHelpers end def dummy_pipeline(project) - Ci::Pipeline.new( + create(:ci_pipeline, sha: project.repository.commit('master').sha, ref: 'master', source: :push, @@ -106,9 +106,7 @@ module CycleAnalyticsHelpers end def new_dummy_job(user, project, environment) - project.environments.find_or_create_by(name: environment) - - Ci::Build.new( + create(:ci_build, project: project, user: user, environment: environment, diff --git a/spec/workers/build_success_worker_spec.rb b/spec/workers/build_success_worker_spec.rb index dba70883130..8e9b178728e 100644 --- a/spec/workers/build_success_worker_spec.rb +++ b/spec/workers/build_success_worker_spec.rb @@ -2,15 +2,39 @@ require 'spec_helper' describe BuildSuccessWorker do describe '#perform' do + subject { described_class.new.perform(build.id) } + + before do + allow_any_instance_of(Deployment).to receive(:create_ref) + end + context 'when build exists' do - context 'when build belogs to the environment' do - let!(:build) { create(:ci_build, environment: 'production') } + context 'when deployment was not created with the build creation' do # An edge case during the transition period + let!(:build) { create(:ci_build, :deploy_to_production) } + + before do + Deployment.delete_all + build.reload + end + + it 'creates a successful deployment' do + expect(build).not_to be_has_deployment + + subject + + build.reload + expect(build).to be_has_deployment + expect(build.deployment).to be_success + end + end + + context 'when deployment was created with the build creation' do # Counter part of the above edge case + let!(:build) { create(:ci_build, :deploy_to_production) } - it 'executes deployment service' do - expect_any_instance_of(CreateDeploymentService) - .to receive(:execute) + it 'does not create a new deployment' do + expect(build).to be_has_deployment - described_class.new.perform(build.id) + expect { subject }.not_to change { Deployment.count } end end @@ -18,10 +42,9 @@ describe BuildSuccessWorker do let!(:build) { create(:ci_build, project: nil) } it 'does not create deployment' do - expect_any_instance_of(CreateDeploymentService) - .not_to receive(:execute) + subject - described_class.new.perform(build.id) + expect(build.reload).not_to be_has_deployment end end end diff --git a/spec/workers/deployments/success_worker_spec.rb b/spec/workers/deployments/success_worker_spec.rb new file mode 100644 index 00000000000..ba7d45eca01 --- /dev/null +++ b/spec/workers/deployments/success_worker_spec.rb @@ -0,0 +1,36 @@ +require 'spec_helper' + +describe Deployments::SuccessWorker do + subject { described_class.new.perform(deployment&.id) } + + context 'when successful deployment' do + let(:deployment) { create(:deployment, :success) } + + it 'executes UpdateDeploymentService' do + expect(UpdateDeploymentService) + .to receive(:new).with(deployment).and_call_original + + subject + end + end + + context 'when canceled deployment' do + let(:deployment) { create(:deployment, :canceled) } + + it 'does not execute UpdateDeploymentService' do + expect(UpdateDeploymentService).not_to receive(:new) + + subject + end + end + + context 'when deploy record does not exist' do + let(:deployment) { nil } + + it 'does not execute UpdateDeploymentService' do + expect(UpdateDeploymentService).not_to receive(:new) + + subject + end + end +end |