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:
authorGitLab Bot <gitlab-bot@gitlab.com>2022-03-18 23:02:30 +0300
committerGitLab Bot <gitlab-bot@gitlab.com>2022-03-18 23:02:30 +0300
commit41fe97390ceddf945f3d967b8fdb3de4c66b7dea (patch)
tree9c8d89a8624828992f06d892cd2f43818ff5dcc8 /spec/models/projects/build_artifacts_size_refresh_spec.rb
parent0804d2dc31052fb45a1efecedc8e06ce9bc32862 (diff)
Add latest changes from gitlab-org/gitlab@14-9-stable-eev14.9.0-rc42
Diffstat (limited to 'spec/models/projects/build_artifacts_size_refresh_spec.rb')
-rw-r--r--spec/models/projects/build_artifacts_size_refresh_spec.rb227
1 files changed, 227 insertions, 0 deletions
diff --git a/spec/models/projects/build_artifacts_size_refresh_spec.rb b/spec/models/projects/build_artifacts_size_refresh_spec.rb
new file mode 100644
index 00000000000..22c27c986f8
--- /dev/null
+++ b/spec/models/projects/build_artifacts_size_refresh_spec.rb
@@ -0,0 +1,227 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe Projects::BuildArtifactsSizeRefresh, type: :model do
+ describe 'associations' do
+ it { is_expected.to belong_to(:project) }
+ end
+
+ it_behaves_like 'having unique enum values'
+
+ describe 'validations' do
+ it { is_expected.to validate_presence_of(:project) }
+ end
+
+ describe 'scopes' do
+ let_it_be(:refresh_1) { create(:project_build_artifacts_size_refresh, :running, updated_at: 4.days.ago) }
+ let_it_be(:refresh_2) { create(:project_build_artifacts_size_refresh, :running, updated_at: 2.days.ago) }
+ let_it_be(:refresh_3) { create(:project_build_artifacts_size_refresh, :pending) }
+ let_it_be(:refresh_4) { create(:project_build_artifacts_size_refresh, :created) }
+
+ describe 'stale' do
+ it 'returns records in running state and has not been updated for more than 3 days' do
+ expect(described_class.stale).to eq([refresh_1])
+ end
+ end
+
+ describe 'remaining' do
+ it 'returns stale, created, and pending records' do
+ expect(described_class.remaining).to match_array([refresh_1, refresh_3, refresh_4])
+ end
+ end
+ end
+
+ describe 'state machine', :clean_gitlab_redis_shared_state do
+ around do |example|
+ freeze_time { example.run }
+ end
+
+ let(:now) { Time.zone.now }
+
+ describe 'initial state' do
+ let(:refresh) { create(:project_build_artifacts_size_refresh) }
+
+ it 'defaults to created' do
+ expect(refresh).to be_created
+ end
+ end
+
+ describe '#process!' do
+ context 'when refresh state is created' do
+ let!(:refresh) do
+ create(
+ :project_build_artifacts_size_refresh,
+ :created,
+ updated_at: 2.days.ago,
+ refresh_started_at: nil,
+ last_job_artifact_id: nil
+ )
+ end
+
+ before do
+ stats = create(:project_statistics, project: refresh.project, build_artifacts_size: 120)
+ stats.increment_counter(:build_artifacts_size, 30)
+ end
+
+ it 'transitions the state to running' do
+ expect { refresh.process! }.to change { refresh.reload.state }.to(described_class::STATES[:running])
+ end
+
+ it 'sets the refresh_started_at' do
+ expect { refresh.process! }.to change { refresh.reload.refresh_started_at.to_i }.to(now.to_i)
+ end
+
+ it 'bumps the updated_at' do
+ expect { refresh.process! }.to change { refresh.reload.updated_at.to_i }.to(now.to_i)
+ end
+
+ it 'resets the build artifacts size stats' do
+ expect { refresh.process! }.to change { refresh.project.statistics.reload.build_artifacts_size }.to(0)
+ end
+
+ it 'resets the counter attribute to zero' do
+ expect { refresh.process! }.to change { refresh.project.statistics.get_counter_value(:build_artifacts_size) }.to(0)
+ end
+ end
+
+ context 'when refresh state is pending' do
+ let!(:refresh) do
+ create(
+ :project_build_artifacts_size_refresh,
+ :pending,
+ updated_at: 2.days.ago
+ )
+ end
+
+ before do
+ create(:project_statistics, project: refresh.project)
+ end
+
+ it 'transitions the state to running' do
+ expect { refresh.process! }.to change { refresh.reload.state }.to(described_class::STATES[:running])
+ end
+
+ it 'bumps the updated_at' do
+ expect { refresh.process! }.to change { refresh.reload.updated_at.to_i }.to(now.to_i)
+ end
+ end
+
+ context 'when refresh state is running' do
+ let!(:refresh) do
+ create(
+ :project_build_artifacts_size_refresh,
+ :running,
+ updated_at: 2.days.ago
+ )
+ end
+
+ before do
+ create(:project_statistics, project: refresh.project)
+ end
+
+ it 'keeps the state at running' do
+ expect { refresh.process! }.not_to change { refresh.reload.state }
+ end
+
+ it 'bumps the updated_at' do
+ # If this was a stale job, we want to bump the updated at now so that
+ # it won't be picked up by another worker while we're recalculating
+ expect { refresh.process! }.to change { refresh.reload.updated_at.to_i }.to(now.to_i)
+ end
+ end
+ end
+
+ describe '#requeue!' do
+ let!(:refresh) do
+ create(
+ :project_build_artifacts_size_refresh,
+ :running,
+ updated_at: 2.days.ago,
+ last_job_artifact_id: 111
+ )
+ end
+
+ let(:last_job_artifact_id) { 123 }
+
+ it 'transitions refresh state from running to pending' do
+ expect { refresh.requeue!(last_job_artifact_id) }.to change { refresh.reload.state }.to(described_class::STATES[:pending])
+ end
+
+ it 'bumps updated_at' do
+ expect { refresh.requeue!(last_job_artifact_id) }.to change { refresh.reload.updated_at.to_i }.to(now.to_i)
+ end
+
+ it 'updates last_job_artifact_id' do
+ expect { refresh.requeue!(last_job_artifact_id) }.to change { refresh.reload.last_job_artifact_id.to_i }.to(last_job_artifact_id)
+ end
+ end
+ end
+
+ describe '.process_next_refresh!' do
+ let!(:refresh_running) { create(:project_build_artifacts_size_refresh, :running) }
+ let!(:refresh_created) { create(:project_build_artifacts_size_refresh, :created) }
+ let!(:refresh_stale) { create(:project_build_artifacts_size_refresh, :stale) }
+ let!(:refresh_pending) { create(:project_build_artifacts_size_refresh, :pending) }
+
+ subject(:processed_refresh) { described_class.process_next_refresh! }
+
+ it 'picks the first record from the remaining work' do
+ expect(processed_refresh).to eq(refresh_created)
+ expect(processed_refresh.reload).to be_running
+ end
+ end
+
+ describe '.enqueue_refresh' do
+ let_it_be(:project_1) { create(:project) }
+ let_it_be(:project_2) { create(:project) }
+
+ let(:projects) { [project_1, project_1, project_2] }
+
+ it 'creates refresh records for each given project, skipping duplicates' do
+ expect { described_class.enqueue_refresh(projects) }
+ .to change { described_class.count }.from(0).to(2)
+
+ expect(described_class.first).to have_attributes(
+ project_id: project_1.id,
+ last_job_artifact_id: nil,
+ refresh_started_at: nil,
+ state: described_class::STATES[:created]
+ )
+
+ expect(described_class.last).to have_attributes(
+ project_id: project_2.id,
+ last_job_artifact_id: nil,
+ refresh_started_at: nil,
+ state: described_class::STATES[:created]
+ )
+ end
+ end
+
+ describe '#next_batch' do
+ let!(:project) { create(:project) }
+ let!(:artifact_1) { create(:ci_job_artifact, project: project, created_at: 14.days.ago) }
+ let!(:artifact_2) { create(:ci_job_artifact, project: project, created_at: 13.days.ago) }
+ let!(:artifact_3) { create(:ci_job_artifact, project: project, created_at: 12.days.ago) }
+
+ # This should not be included in the recalculation as it is created later than the refresh start time
+ let!(:future_artifact) { create(:ci_job_artifact, project: project, size: 8, created_at: refresh.refresh_started_at + 1.second) }
+
+ let!(:refresh) do
+ create(
+ :project_build_artifacts_size_refresh,
+ :pending,
+ project: project,
+ updated_at: 2.days.ago,
+ refresh_started_at: 10.days.ago,
+ last_job_artifact_id: artifact_1.id
+ )
+ end
+
+ subject(:batch) { refresh.next_batch(limit: 3) }
+
+ it 'returns the job artifact records that were created not later than the refresh_started_at and IDs greater than the last_job_artifact_id' do
+ expect(batch).to eq([artifact_2, artifact_3])
+ end
+ end
+end