summaryrefslogtreecommitdiff
path: root/spec/lib/gitlab/ci/pipeline/chain/limit/rate_limit_spec.rb
diff options
context:
space:
mode:
Diffstat (limited to 'spec/lib/gitlab/ci/pipeline/chain/limit/rate_limit_spec.rb')
-rw-r--r--spec/lib/gitlab/ci/pipeline/chain/limit/rate_limit_spec.rb179
1 files changed, 179 insertions, 0 deletions
diff --git a/spec/lib/gitlab/ci/pipeline/chain/limit/rate_limit_spec.rb b/spec/lib/gitlab/ci/pipeline/chain/limit/rate_limit_spec.rb
new file mode 100644
index 00000000000..aa8aec2af4a
--- /dev/null
+++ b/spec/lib/gitlab/ci/pipeline/chain/limit/rate_limit_spec.rb
@@ -0,0 +1,179 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe ::Gitlab::Ci::Pipeline::Chain::Limit::RateLimit, :freeze_time, :clean_gitlab_redis_rate_limiting do
+ let_it_be(:user) { create(:user) }
+ let_it_be(:namespace) { create(:namespace) }
+ let_it_be(:project, reload: true) { create(:project, namespace: namespace) }
+
+ let(:save_incompleted) { false }
+ let(:throttle_message) do
+ 'Too many pipelines created in the last minute. Try again later.'
+ end
+
+ let(:command) do
+ Gitlab::Ci::Pipeline::Chain::Command.new(
+ project: project,
+ current_user: user,
+ save_incompleted: save_incompleted
+ )
+ end
+
+ let(:pipeline) { build(:ci_pipeline, project: project, source: source) }
+ let(:source) { 'push' }
+ let(:step) { described_class.new(pipeline, command) }
+
+ def perform(count: 2)
+ count.times { step.perform! }
+ end
+
+ context 'when the limit is exceeded' do
+ before do
+ allow(Gitlab::ApplicationRateLimiter).to receive(:rate_limits)
+ .and_return(pipelines_create: { threshold: 1, interval: 1.minute })
+
+ stub_feature_flags(ci_throttle_pipelines_creation_dry_run: false)
+ end
+
+ it 'does not persist the pipeline' do
+ perform
+
+ expect(pipeline).not_to be_persisted
+ expect(pipeline.errors.added?(:base, throttle_message)).to be_truthy
+ end
+
+ it 'breaks the chain' do
+ perform
+
+ expect(step.break?).to be_truthy
+ end
+
+ it 'creates a log entry' do
+ expect(Gitlab::AppJsonLogger).to receive(:info).with(
+ a_hash_including(
+ class: described_class.name,
+ project_id: project.id,
+ subscription_plan: project.actual_plan_name,
+ commit_sha: command.sha
+ )
+ )
+
+ perform
+ end
+
+ context 'with child pipelines' do
+ let(:source) { 'parent_pipeline' }
+
+ it 'does not break the chain' do
+ perform
+
+ expect(step.break?).to be_falsey
+ end
+
+ it 'does not invalidate the pipeline' do
+ perform
+
+ expect(pipeline.errors).to be_empty
+ end
+
+ it 'does not log anything' do
+ expect(Gitlab::AppJsonLogger).not_to receive(:info)
+
+ perform
+ end
+ end
+
+ context 'when saving incompleted pipelines' do
+ let(:save_incompleted) { true }
+
+ it 'does not persist the pipeline' do
+ perform
+
+ expect(pipeline).not_to be_persisted
+ expect(pipeline.errors.added?(:base, throttle_message)).to be_truthy
+ end
+
+ it 'breaks the chain' do
+ perform
+
+ expect(step.break?).to be_truthy
+ end
+ end
+
+ context 'when ci_throttle_pipelines_creation is disabled' do
+ before do
+ stub_feature_flags(ci_throttle_pipelines_creation: false)
+ end
+
+ it 'does not break the chain' do
+ perform
+
+ expect(step.break?).to be_falsey
+ end
+
+ it 'does not invalidate the pipeline' do
+ perform
+
+ expect(pipeline.errors).to be_empty
+ end
+
+ it 'does not log anything' do
+ expect(Gitlab::AppJsonLogger).not_to receive(:info)
+
+ perform
+ end
+ end
+
+ context 'when ci_throttle_pipelines_creation_dry_run is enabled' do
+ before do
+ stub_feature_flags(ci_throttle_pipelines_creation_dry_run: true)
+ end
+
+ it 'does not break the chain' do
+ perform
+
+ expect(step.break?).to be_falsey
+ end
+
+ it 'does not invalidate the pipeline' do
+ perform
+
+ expect(pipeline.errors).to be_empty
+ end
+
+ it 'creates a log entry' do
+ expect(Gitlab::AppJsonLogger).to receive(:info).with(
+ a_hash_including(
+ class: described_class.name,
+ project_id: project.id,
+ subscription_plan: project.actual_plan_name,
+ commit_sha: command.sha
+ )
+ )
+
+ perform
+ end
+ end
+ end
+
+ context 'when the limit is not exceeded' do
+ it 'does not break the chain' do
+ perform
+
+ expect(step.break?).to be_falsey
+ end
+
+ it 'does not invalidate the pipeline' do
+ perform
+
+ expect(pipeline.errors).to be_empty
+ end
+
+ it 'does not log anything' do
+ expect(Gitlab::AppJsonLogger).not_to receive(:info)
+
+ perform
+ end
+ end
+end