Welcome to mirror list, hosted at ThFree Co, Russian Federation.

gitlab.com/gitlab-org/gitlab-foss.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to 'spec/models/ci')
-rw-r--r--spec/models/ci/bridge_spec.rb2
-rw-r--r--spec/models/ci/build_metadata_spec.rb12
-rw-r--r--spec/models/ci/build_spec.rb267
-rw-r--r--spec/models/ci/job_artifact_spec.rb62
-rw-r--r--spec/models/ci/pipeline_schedule_spec.rb2
-rw-r--r--spec/models/ci/pipeline_spec.rb18
-rw-r--r--spec/models/ci/runner_spec.rb53
-rw-r--r--spec/models/ci/trigger_spec.rb4
8 files changed, 328 insertions, 92 deletions
diff --git a/spec/models/ci/bridge_spec.rb b/spec/models/ci/bridge_spec.rb
index 8f1ae9c5f02..6fde55103f8 100644
--- a/spec/models/ci/bridge_spec.rb
+++ b/spec/models/ci/bridge_spec.rb
@@ -17,8 +17,6 @@ RSpec.describe Ci::Bridge do
{ trigger: { project: 'my/project', branch: 'master' } }
end
- it { is_expected.to respond_to(:runner_features) }
-
it 'has many sourced pipelines' do
expect(bridge).to have_many(:sourced_pipelines)
end
diff --git a/spec/models/ci/build_metadata_spec.rb b/spec/models/ci/build_metadata_spec.rb
index 069864fa765..b2ffb34da1d 100644
--- a/spec/models/ci/build_metadata_spec.rb
+++ b/spec/models/ci/build_metadata_spec.rb
@@ -121,4 +121,16 @@ RSpec.describe Ci::BuildMetadata do
end
end
end
+
+ describe 'set_cancel_gracefully' do
+ it 'sets cancel_gracefully' do
+ build.set_cancel_gracefully
+
+ expect(build.cancel_gracefully?).to be true
+ end
+
+ it 'returns false' do
+ expect(build.cancel_gracefully?).to be false
+ end
+ end
end
diff --git a/spec/models/ci/build_spec.rb b/spec/models/ci/build_spec.rb
index 2ebf75a1d8a..b7de8ca4337 100644
--- a/spec/models/ci/build_spec.rb
+++ b/spec/models/ci/build_spec.rb
@@ -35,7 +35,8 @@ RSpec.describe Ci::Build do
it { is_expected.to respond_to(:has_trace?) }
it { is_expected.to respond_to(:trace) }
- it { is_expected.to respond_to(:runner_features) }
+ it { is_expected.to respond_to(:set_cancel_gracefully) }
+ it { is_expected.to respond_to(:cancel_gracefully?) }
it { is_expected.to delegate_method(:merge_request?).to(:pipeline) }
it { is_expected.to delegate_method(:merge_request_ref?).to(:pipeline) }
@@ -214,6 +215,26 @@ RSpec.describe Ci::Build do
end
end
+ describe '.license_management_jobs' do
+ subject { described_class.license_management_jobs }
+
+ let!(:management_build) { create(:ci_build, :success, name: :license_management) }
+ let!(:scanning_build) { create(:ci_build, :success, name: :license_scanning) }
+ let!(:another_build) { create(:ci_build, :success, name: :another_type) }
+
+ it 'returns license_scanning jobs' do
+ is_expected.to include(scanning_build)
+ end
+
+ it 'returns license_management jobs' do
+ is_expected.to include(management_build)
+ end
+
+ it 'doesnt return filtered out jobs' do
+ is_expected.not_to include(another_build)
+ end
+ end
+
describe '.finished_before' do
subject { described_class.finished_before(date) }
@@ -350,7 +371,7 @@ RSpec.describe Ci::Build do
it 'sticks the build if the status changed' do
job = create(:ci_build, :pending)
- expect(ApplicationRecord.sticking).to receive(:stick)
+ expect(described_class.sticking).to receive(:stick)
.with(:build, job.id)
job.update!(status: :running)
@@ -1290,7 +1311,7 @@ RSpec.describe Ci::Build do
end
end
- shared_examples_for 'state transition as a deployable' do
+ describe 'state transition as a deployable' do
subject { build.send(event) }
let!(:build) { create(:ci_build, :with_deployment, :start_review_app, project: project, pipeline: pipeline) }
@@ -1332,6 +1353,22 @@ RSpec.describe Ci::Build do
expect(deployment).to be_running
end
+
+ context 'when deployment is already running state' do
+ before do
+ build.deployment.success!
+ end
+
+ it 'does not change deployment status and tracks an error' do
+ expect(Gitlab::ErrorTracking)
+ .to receive(:track_exception).with(
+ instance_of(Deployment::StatusSyncError), deployment_id: deployment.id, build_id: build.id)
+
+ with_cross_database_modification_prevented do
+ expect { subject }.not_to change { deployment.reload.status }
+ end
+ end
+ end
end
context 'when transits to success' do
@@ -1399,36 +1436,6 @@ RSpec.describe Ci::Build do
end
end
- it_behaves_like 'state transition as a deployable' do
- context 'when transits to running' do
- let(:event) { :run! }
-
- context 'when deployment is already running state' do
- before do
- build.deployment.success!
- end
-
- it 'does not change deployment status and tracks an error' do
- expect(Gitlab::ErrorTracking)
- .to receive(:track_exception).with(
- instance_of(Deployment::StatusSyncError), deployment_id: deployment.id, build_id: build.id)
-
- with_cross_database_modification_prevented do
- expect { subject }.not_to change { deployment.reload.status }
- end
- end
- end
- end
- end
-
- context 'when update_deployment_after_transaction_commit feature flag is disabled' do
- before do
- stub_feature_flags(update_deployment_after_transaction_commit: false)
- end
-
- it_behaves_like 'state transition as a deployable'
- end
-
describe '#on_stop' do
subject { build.on_stop }
@@ -2759,7 +2766,10 @@ RSpec.describe Ci::Build do
let(:job_dependency_var) { { key: 'job_dependency', value: 'value', public: true, masked: false } }
before do
- allow(build).to receive(:predefined_variables) { [build_pre_var] }
+ allow_next_instance_of(Gitlab::Ci::Variables::Builder) do |builder|
+ allow(builder).to receive(:predefined_variables) { [build_pre_var] }
+ end
+
allow(build).to receive(:yaml_variables) { [build_yaml_var] }
allow(build).to receive(:persisted_variables) { [] }
allow(build).to receive(:job_jwt_variables) { [job_jwt_var] }
@@ -3411,75 +3421,122 @@ RSpec.describe Ci::Build do
end
describe '#scoped_variables' do
- context 'when build has not been persisted yet' do
- let(:build) do
- described_class.new(
- name: 'rspec',
- stage: 'test',
- ref: 'feature',
- project: project,
- pipeline: pipeline,
- scheduling_type: :stage
- )
- end
+ before do
+ pipeline.clear_memoization(:predefined_vars_in_builder_enabled)
+ end
- let(:pipeline) { create(:ci_pipeline, project: project, ref: 'feature') }
+ it 'records a prometheus metric' do
+ histogram = double(:histogram)
+ expect(::Gitlab::Ci::Pipeline::Metrics).to receive(:pipeline_builder_scoped_variables_histogram)
+ .and_return(histogram)
- it 'does not persist the build' do
- expect(build).to be_valid
- expect(build).not_to be_persisted
+ expect(histogram).to receive(:observe)
+ .with({}, a_kind_of(ActiveSupport::Duration))
- build.scoped_variables
+ build.scoped_variables
+ end
- expect(build).not_to be_persisted
- end
+ shared_examples 'calculates scoped_variables' do
+ context 'when build has not been persisted yet' do
+ let(:build) do
+ described_class.new(
+ name: 'rspec',
+ stage: 'test',
+ ref: 'feature',
+ project: project,
+ pipeline: pipeline,
+ scheduling_type: :stage
+ )
+ end
- it 'returns static predefined variables' do
- keys = %w[CI_JOB_NAME
- CI_COMMIT_SHA
- CI_COMMIT_SHORT_SHA
- CI_COMMIT_REF_NAME
- CI_COMMIT_REF_SLUG
- CI_JOB_STAGE]
+ let(:pipeline) { create(:ci_pipeline, project: project, ref: 'feature') }
- variables = build.scoped_variables
+ it 'does not persist the build' do
+ expect(build).to be_valid
+ expect(build).not_to be_persisted
- variables.map { |env| env[:key] }.tap do |names|
- expect(names).to include(*keys)
+ build.scoped_variables
+
+ expect(build).not_to be_persisted
end
- expect(variables)
- .to include(key: 'CI_COMMIT_REF_NAME', value: 'feature', public: true, masked: false)
+ it 'returns static predefined variables' do
+ keys = %w[CI_JOB_NAME
+ CI_COMMIT_SHA
+ CI_COMMIT_SHORT_SHA
+ CI_COMMIT_REF_NAME
+ CI_COMMIT_REF_SLUG
+ CI_JOB_STAGE]
+
+ variables = build.scoped_variables
+
+ variables.map { |env| env[:key] }.tap do |names|
+ expect(names).to include(*keys)
+ end
+
+ expect(variables)
+ .to include(key: 'CI_COMMIT_REF_NAME', value: 'feature', public: true, masked: false)
+ end
+
+ it 'does not return prohibited variables' do
+ keys = %w[CI_JOB_ID
+ CI_JOB_URL
+ CI_JOB_TOKEN
+ CI_BUILD_ID
+ CI_BUILD_TOKEN
+ CI_REGISTRY_USER
+ CI_REGISTRY_PASSWORD
+ CI_REPOSITORY_URL
+ CI_ENVIRONMENT_URL
+ CI_DEPLOY_USER
+ CI_DEPLOY_PASSWORD]
+
+ build.scoped_variables.map { |env| env[:key] }.tap do |names|
+ expect(names).not_to include(*keys)
+ end
+ end
end
- it 'does not return prohibited variables' do
- keys = %w[CI_JOB_ID
- CI_JOB_URL
- CI_JOB_TOKEN
- CI_BUILD_ID
- CI_BUILD_TOKEN
- CI_REGISTRY_USER
- CI_REGISTRY_PASSWORD
- CI_REPOSITORY_URL
- CI_ENVIRONMENT_URL
- CI_DEPLOY_USER
- CI_DEPLOY_PASSWORD]
+ context 'with dependency variables' do
+ let!(:prepare) { create(:ci_build, name: 'prepare', pipeline: pipeline, stage_idx: 0) }
+ let!(:build) { create(:ci_build, pipeline: pipeline, stage_idx: 1, options: { dependencies: ['prepare'] }) }
+
+ let!(:job_variable) { create(:ci_job_variable, :dotenv_source, job: prepare) }
- build.scoped_variables.map { |env| env[:key] }.tap do |names|
- expect(names).not_to include(*keys)
+ it 'inherits dependent variables' do
+ expect(build.scoped_variables.to_hash).to include(job_variable.key => job_variable.value)
end
end
end
- context 'with dependency variables' do
- let!(:prepare) { create(:ci_build, name: 'prepare', pipeline: pipeline, stage_idx: 0) }
- let!(:build) { create(:ci_build, pipeline: pipeline, stage_idx: 1, options: { dependencies: ['prepare'] }) }
+ it_behaves_like 'calculates scoped_variables'
- let!(:job_variable) { create(:ci_job_variable, :dotenv_source, job: prepare) }
+ it 'delegates to the variable builders' do
+ expect_next_instance_of(Gitlab::Ci::Variables::Builder) do |builder|
+ expect(builder)
+ .to receive(:scoped_variables).with(build, hash_including(:environment, :dependencies))
+ .and_call_original
- it 'inherits dependent variables' do
- expect(build.scoped_variables.to_hash).to include(job_variable.key => job_variable.value)
+ expect(builder).to receive(:predefined_variables).and_call_original
end
+
+ build.scoped_variables
+ end
+
+ context 'when ci builder feature flag is disabled' do
+ before do
+ stub_feature_flags(ci_predefined_vars_in_builder: false)
+ end
+
+ it 'does not delegate to the variable builders' do
+ expect_next_instance_of(Gitlab::Ci::Variables::Builder) do |builder|
+ expect(builder).not_to receive(:predefined_variables)
+ end
+
+ build.scoped_variables
+ end
+
+ it_behaves_like 'calculates scoped_variables'
end
end
@@ -3569,6 +3626,27 @@ RSpec.describe Ci::Build do
include_examples "secret CI variables"
end
+ describe '#kubernetes_variables' do
+ let(:build) { create(:ci_build) }
+ let(:service) { double(execute: template) }
+ let(:template) { double(to_yaml: 'example-kubeconfig', valid?: template_valid) }
+ let(:template_valid) { true }
+
+ subject { build.kubernetes_variables }
+
+ before do
+ allow(Ci::GenerateKubeconfigService).to receive(:new).with(build).and_return(service)
+ end
+
+ it { is_expected.to include(key: 'KUBECONFIG', value: 'example-kubeconfig', public: false, file: true) }
+
+ context 'generated config is invalid' do
+ let(:template_valid) { false }
+
+ it { is_expected.not_to include(key: 'KUBECONFIG', value: 'example-kubeconfig', public: false, file: true) }
+ end
+ end
+
describe '#deployment_variables' do
let(:build) { create(:ci_build, environment: environment) }
let(:environment) { 'production' }
@@ -3728,7 +3806,7 @@ RSpec.describe Ci::Build do
it 'ensures that it is not run in database transaction' do
expect(job.pipeline.persistent_ref).to receive(:create) do
- expect(Gitlab::Database.main).not_to be_inside_transaction
+ expect(ApplicationRecord).not_to be_inside_transaction
end
run_job_without_exception
@@ -5326,4 +5404,23 @@ RSpec.describe Ci::Build do
create(:ci_build)
end
end
+
+ describe '#runner_features' do
+ subject do
+ build.save!
+ build.cancel_gracefully?
+ end
+
+ let_it_be(:build) { create(:ci_build, pipeline: pipeline) }
+
+ it 'cannot cancel gracefully' do
+ expect(subject).to be false
+ end
+
+ it 'can cancel gracefully' do
+ build.set_cancel_gracefully
+
+ expect(subject).to be true
+ end
+ end
end
diff --git a/spec/models/ci/job_artifact_spec.rb b/spec/models/ci/job_artifact_spec.rb
index a94a1dd284a..d63f87e8943 100644
--- a/spec/models/ci/job_artifact_spec.rb
+++ b/spec/models/ci/job_artifact_spec.rb
@@ -351,6 +351,21 @@ RSpec.describe Ci::JobArtifact do
end
end
+ context 'when updating any field except the file' do
+ let(:artifact) { create(:ci_job_artifact, :unarchived_trace_artifact, file_store: 2) }
+
+ before do
+ stub_artifacts_object_storage(direct_upload: true)
+ artifact.file.object_store = 1
+ end
+
+ it 'the `after_commit` hook does not update `file_store`' do
+ artifact.update!(expire_at: Time.current)
+
+ expect(artifact.file_store).to be(2)
+ end
+ end
+
describe 'validates file format' do
subject { artifact }
@@ -507,6 +522,53 @@ RSpec.describe Ci::JobArtifact do
end
end
+ describe '#store_after_commit?' do
+ let(:file_type) { :archive }
+ let(:artifact) { build(:ci_job_artifact, file_type) }
+
+ context 'when direct upload is enabled' do
+ before do
+ stub_artifacts_object_storage(direct_upload: true)
+ end
+
+ context 'when the artifact is a trace' do
+ let(:file_type) { :trace }
+
+ context 'when ci_store_trace_outside_transaction is enabled' do
+ it 'returns true' do
+ expect(artifact.store_after_commit?).to be_truthy
+ end
+ end
+
+ context 'when ci_store_trace_outside_transaction is disabled' do
+ before do
+ stub_feature_flags(ci_store_trace_outside_transaction: false)
+ end
+
+ it 'returns false' do
+ expect(artifact.store_after_commit?).to be_falsey
+ end
+ end
+ end
+
+ context 'when the artifact is not a trace' do
+ it 'returns false' do
+ expect(artifact.store_after_commit?).to be_falsey
+ end
+ end
+ end
+
+ context 'when direct upload is disabled' do
+ before do
+ stub_artifacts_object_storage(direct_upload: false)
+ end
+
+ it 'returns false' do
+ expect(artifact.store_after_commit?).to be_falsey
+ end
+ end
+ end
+
describe 'file is being stored' do
subject { create(:ci_job_artifact, :archive) }
diff --git a/spec/models/ci/pipeline_schedule_spec.rb b/spec/models/ci/pipeline_schedule_spec.rb
index c7e1fe91b1e..fee74f8f674 100644
--- a/spec/models/ci/pipeline_schedule_spec.rb
+++ b/spec/models/ci/pipeline_schedule_spec.rb
@@ -3,7 +3,7 @@
require 'spec_helper'
RSpec.describe Ci::PipelineSchedule do
- let_it_be(:project) { create_default(:project) }
+ let_it_be_with_reload(:project) { create_default(:project) }
subject { build(:ci_pipeline_schedule) }
diff --git a/spec/models/ci/pipeline_spec.rb b/spec/models/ci/pipeline_spec.rb
index 5f3aad0ab24..e573a6ef780 100644
--- a/spec/models/ci/pipeline_spec.rb
+++ b/spec/models/ci/pipeline_spec.rb
@@ -3361,7 +3361,7 @@ RSpec.describe Ci::Pipeline, :mailer, factory_default: :keep do
shared_examples 'sending a notification' do
it 'sends an email', :sidekiq_might_not_need_inline do
- should_only_email(pipeline.user, kind: :bcc)
+ should_only_email(pipeline.user)
end
end
@@ -4595,4 +4595,20 @@ RSpec.describe Ci::Pipeline, :mailer, factory_default: :keep do
end
end
end
+
+ describe '#authorized_cluster_agents' do
+ let(:pipeline) { create(:ci_empty_pipeline, :created) }
+ let(:agent) { instance_double(Clusters::Agent) }
+ let(:authorization) { instance_double(Clusters::Agents::GroupAuthorization, agent: agent) }
+ let(:finder) { double(execute: [authorization]) }
+
+ it 'retrieves agent records from the finder and caches the result' do
+ expect(Clusters::AgentAuthorizationsFinder).to receive(:new).once
+ .with(pipeline.project)
+ .and_return(finder)
+
+ expect(pipeline.authorized_cluster_agents).to contain_exactly(agent)
+ expect(pipeline.authorized_cluster_agents).to contain_exactly(agent) # cached
+ end
+ end
end
diff --git a/spec/models/ci/runner_spec.rb b/spec/models/ci/runner_spec.rb
index 826332268c5..2e79159cc60 100644
--- a/spec/models/ci/runner_spec.rb
+++ b/spec/models/ci/runner_spec.rb
@@ -5,6 +5,14 @@ require 'spec_helper'
RSpec.describe Ci::Runner do
it_behaves_like 'having unique enum values'
+ it_behaves_like 'it has loose foreign keys' do
+ let(:factory_name) { :ci_runner }
+
+ before do
+ Clusters::Applications::Runner # ensure that the referenced model is loaded
+ end
+ end
+
describe 'groups association' do
# Due to other assoctions such as projects this whole spec is allowed to
# generate cross-database queries. So we have this temporary spec to
@@ -44,7 +52,7 @@ RSpec.describe Ci::Runner do
let(:runner) { create(:ci_runner, :group, groups: [group]) }
it 'disallows assigning group if already assigned to a group' do
- runner.groups << build(:group)
+ runner.runner_namespaces << build(:ci_runner_namespace)
expect(runner).not_to be_valid
expect(runner.errors.full_messages).to include('Runner needs to be assigned to exactly one group')
@@ -397,7 +405,7 @@ RSpec.describe Ci::Runner do
it 'sticks the runner to the primary and calls the original method' do
runner = create(:ci_runner)
- expect(ApplicationRecord.sticking).to receive(:stick)
+ expect(described_class.sticking).to receive(:stick)
.with(:runner, runner.id)
expect(Gitlab::Workhorse).to receive(:set_key_and_notify)
@@ -618,7 +626,7 @@ RSpec.describe Ci::Runner do
end
describe '#status' do
- let(:runner) { create(:ci_runner, :instance, contacted_at: 1.second.ago) }
+ let(:runner) { build(:ci_runner, :instance) }
subject { runner.status }
@@ -630,6 +638,45 @@ RSpec.describe Ci::Runner do
it { is_expected.to eq(:not_connected) }
end
+ context 'inactive but online' do
+ before do
+ runner.contacted_at = 1.second.ago
+ runner.active = false
+ end
+
+ it { is_expected.to eq(:online) }
+ end
+
+ context 'contacted 1s ago' do
+ before do
+ runner.contacted_at = 1.second.ago
+ end
+
+ it { is_expected.to eq(:online) }
+ end
+
+ context 'contacted long time ago' do
+ before do
+ runner.contacted_at = 1.year.ago
+ end
+
+ it { is_expected.to eq(:offline) }
+ end
+ end
+
+ describe '#deprecated_rest_status' do
+ let(:runner) { build(:ci_runner, :instance, contacted_at: 1.second.ago) }
+
+ subject { runner.deprecated_rest_status }
+
+ context 'never connected' do
+ before do
+ runner.contacted_at = nil
+ end
+
+ it { is_expected.to eq(:not_connected) }
+ end
+
context 'contacted 1s ago' do
before do
runner.contacted_at = 1.second.ago
diff --git a/spec/models/ci/trigger_spec.rb b/spec/models/ci/trigger_spec.rb
index 4ba6c6e50f7..c254279a32f 100644
--- a/spec/models/ci/trigger_spec.rb
+++ b/spec/models/ci/trigger_spec.rb
@@ -57,4 +57,8 @@ RSpec.describe Ci::Trigger do
it { is_expected.to eq(false) }
end
end
+
+ it_behaves_like 'includes Limitable concern' do
+ subject { build(:ci_trigger, owner: project.owner, project: project) }
+ end
end