ec39a1d63d
Schedules a Namespace::AggregationSchedule worker if some of the project statistics are refreshed. The worker is only executed if the feature flag is enabled.
299 lines
8.9 KiB
Ruby
299 lines
8.9 KiB
Ruby
# frozen_string_literal: true
|
|
|
|
require 'rails_helper'
|
|
|
|
describe ProjectStatistics do
|
|
let(:project) { create :project }
|
|
let(:statistics) { project.statistics }
|
|
|
|
describe 'associations' do
|
|
it { is_expected.to belong_to(:project) }
|
|
it { is_expected.to belong_to(:namespace) }
|
|
end
|
|
|
|
describe 'scopes' do
|
|
describe '.for_project_ids' do
|
|
it 'returns only requested projects' do
|
|
stats = create_list(:project_statistics, 3)
|
|
project_ids = stats[0..1].map { |s| s.project_id }
|
|
expected_ids = stats[0..1].map { |s| s.id }
|
|
|
|
requested_stats = described_class.for_project_ids(project_ids).pluck(:id)
|
|
|
|
expect(requested_stats).to eq(expected_ids)
|
|
end
|
|
end
|
|
end
|
|
|
|
describe 'statistics columns' do
|
|
it "support values up to 8 exabytes" do
|
|
statistics.update!(
|
|
commit_count: 8.exabytes - 1,
|
|
repository_size: 2.exabytes,
|
|
wiki_size: 1.exabytes,
|
|
lfs_objects_size: 2.exabytes,
|
|
build_artifacts_size: 3.exabytes - 1
|
|
)
|
|
|
|
statistics.reload
|
|
|
|
expect(statistics.commit_count).to eq(8.exabytes - 1)
|
|
expect(statistics.repository_size).to eq(2.exabytes)
|
|
expect(statistics.wiki_size).to eq(1.exabytes)
|
|
expect(statistics.lfs_objects_size).to eq(2.exabytes)
|
|
expect(statistics.build_artifacts_size).to eq(3.exabytes - 1)
|
|
expect(statistics.storage_size).to eq(8.exabytes - 1)
|
|
end
|
|
end
|
|
|
|
describe '#total_repository_size' do
|
|
it "sums repository and LFS object size" do
|
|
statistics.repository_size = 2
|
|
statistics.wiki_size = 6
|
|
statistics.lfs_objects_size = 3
|
|
statistics.build_artifacts_size = 4
|
|
|
|
expect(statistics.total_repository_size).to eq 5
|
|
end
|
|
end
|
|
|
|
describe '#wiki_size' do
|
|
it "is initialized with not null value" do
|
|
expect(statistics.wiki_size).to eq 0
|
|
end
|
|
end
|
|
|
|
describe '#refresh!' do
|
|
before do
|
|
allow(statistics).to receive(:update_commit_count)
|
|
allow(statistics).to receive(:update_repository_size)
|
|
allow(statistics).to receive(:update_wiki_size)
|
|
allow(statistics).to receive(:update_lfs_objects_size)
|
|
allow(statistics).to receive(:update_storage_size)
|
|
end
|
|
|
|
context "without arguments" do
|
|
before do
|
|
statistics.refresh!
|
|
end
|
|
|
|
it "sums all counters" do
|
|
expect(statistics).to have_received(:update_commit_count)
|
|
expect(statistics).to have_received(:update_repository_size)
|
|
expect(statistics).to have_received(:update_wiki_size)
|
|
expect(statistics).to have_received(:update_lfs_objects_size)
|
|
end
|
|
end
|
|
|
|
context "when passing an only: argument" do
|
|
before do
|
|
statistics.refresh! only: [:lfs_objects_size]
|
|
end
|
|
|
|
it "only updates the given columns" do
|
|
expect(statistics).to have_received(:update_lfs_objects_size)
|
|
expect(statistics).not_to have_received(:update_commit_count)
|
|
expect(statistics).not_to have_received(:update_repository_size)
|
|
expect(statistics).not_to have_received(:update_wiki_size)
|
|
end
|
|
end
|
|
|
|
context 'without repositories' do
|
|
it 'does not crash' do
|
|
expect(project.repository.exists?).to be_falsey
|
|
expect(project.wiki.repository.exists?).to be_falsey
|
|
|
|
statistics.refresh!
|
|
|
|
expect(statistics).to have_received(:update_commit_count)
|
|
expect(statistics).to have_received(:update_repository_size)
|
|
expect(statistics).to have_received(:update_wiki_size)
|
|
expect(statistics.repository_size).to eq(0)
|
|
expect(statistics.commit_count).to eq(0)
|
|
expect(statistics.wiki_size).to eq(0)
|
|
end
|
|
end
|
|
|
|
context 'with deleted repositories' do
|
|
let(:project) { create(:project, :repository, :wiki_repo) }
|
|
|
|
before do
|
|
Gitlab::GitalyClient::StorageSettings.allow_disk_access do
|
|
FileUtils.rm_rf(project.repository.path)
|
|
FileUtils.rm_rf(project.wiki.repository.path)
|
|
end
|
|
end
|
|
|
|
it 'does not crash' do
|
|
statistics.refresh!
|
|
|
|
expect(statistics).to have_received(:update_commit_count)
|
|
expect(statistics).to have_received(:update_repository_size)
|
|
expect(statistics).to have_received(:update_wiki_size)
|
|
expect(statistics.repository_size).to eq(0)
|
|
expect(statistics.commit_count).to eq(0)
|
|
expect(statistics.wiki_size).to eq(0)
|
|
end
|
|
end
|
|
|
|
context 'when the column is namespace relatable' do
|
|
let(:namespace) { create(:group) }
|
|
let(:project) { create(:project, namespace: namespace) }
|
|
|
|
context 'when the feature flag is off' do
|
|
it 'does not schedule the aggregation worker' do
|
|
stub_feature_flags(update_statistics_namespace: false, namespace: namespace)
|
|
|
|
expect(Namespaces::ScheduleAggregationWorker)
|
|
.not_to receive(:perform_async)
|
|
|
|
statistics.refresh!(only: [:lfs_objects_size])
|
|
end
|
|
end
|
|
|
|
context 'when the feature flag is on' do
|
|
it 'schedules the aggregation worker' do
|
|
expect(Namespaces::ScheduleAggregationWorker)
|
|
.to receive(:perform_async)
|
|
|
|
statistics.refresh!(only: [:lfs_objects_size])
|
|
end
|
|
end
|
|
|
|
context 'when no argument is passed' do
|
|
it 'schedules the aggregation worker' do
|
|
expect(Namespaces::ScheduleAggregationWorker)
|
|
.to receive(:perform_async)
|
|
|
|
statistics.refresh!
|
|
end
|
|
end
|
|
end
|
|
|
|
context 'when the column is not namespace relatable' do
|
|
it 'does not schedules an aggregation worker' do
|
|
expect(Namespaces::ScheduleAggregationWorker)
|
|
.not_to receive(:perform_async)
|
|
|
|
statistics.refresh!(only: [:commit_count])
|
|
end
|
|
end
|
|
end
|
|
|
|
describe '#update_commit_count' do
|
|
before do
|
|
allow(project.repository).to receive(:commit_count).and_return(23)
|
|
statistics.update_commit_count
|
|
end
|
|
|
|
it "stores the number of commits in the repository" do
|
|
expect(statistics.commit_count).to eq 23
|
|
end
|
|
end
|
|
|
|
describe '#update_repository_size' do
|
|
before do
|
|
allow(project.repository).to receive(:size).and_return(12)
|
|
statistics.update_repository_size
|
|
end
|
|
|
|
it "stores the size of the repository" do
|
|
expect(statistics.repository_size).to eq 12.megabytes
|
|
end
|
|
end
|
|
|
|
describe '#update_wiki_size' do
|
|
before do
|
|
allow(project.wiki.repository).to receive(:size).and_return(34)
|
|
statistics.update_wiki_size
|
|
end
|
|
|
|
it "stores the size of the wiki" do
|
|
expect(statistics.wiki_size).to eq 34.megabytes
|
|
end
|
|
end
|
|
|
|
describe '#update_lfs_objects_size' do
|
|
let!(:lfs_object1) { create(:lfs_object, size: 23.megabytes) }
|
|
let!(:lfs_object2) { create(:lfs_object, size: 34.megabytes) }
|
|
let!(:lfs_objects_project1) { create(:lfs_objects_project, project: project, lfs_object: lfs_object1) }
|
|
let!(:lfs_objects_project2) { create(:lfs_objects_project, project: project, lfs_object: lfs_object2) }
|
|
|
|
before do
|
|
statistics.update_lfs_objects_size
|
|
end
|
|
|
|
it "stores the size of related LFS objects" do
|
|
expect(statistics.lfs_objects_size).to eq 57.megabytes
|
|
end
|
|
end
|
|
|
|
describe '#update_storage_size' do
|
|
it "sums all storage counters" do
|
|
statistics.update!(
|
|
repository_size: 2,
|
|
wiki_size: 4,
|
|
lfs_objects_size: 3
|
|
)
|
|
|
|
statistics.reload
|
|
|
|
expect(statistics.storage_size).to eq 9
|
|
end
|
|
|
|
it 'works during wiki_size backfill' do
|
|
statistics.update!(
|
|
repository_size: 2,
|
|
wiki_size: nil,
|
|
lfs_objects_size: 3
|
|
)
|
|
|
|
statistics.reload
|
|
|
|
expect(statistics.storage_size).to eq 5
|
|
end
|
|
end
|
|
|
|
describe '.increment_statistic' do
|
|
shared_examples 'a statistic that increases storage_size' do
|
|
it 'increases the statistic by that amount' do
|
|
expect { described_class.increment_statistic(project.id, stat, 13) }
|
|
.to change { statistics.reload.send(stat) || 0 }
|
|
.by(13)
|
|
end
|
|
|
|
it 'increases also storage size by that amount' do
|
|
expect { described_class.increment_statistic(project.id, stat, 20) }
|
|
.to change { statistics.reload.storage_size }
|
|
.by(20)
|
|
end
|
|
end
|
|
|
|
context 'when adjusting :build_artifacts_size' do
|
|
let(:stat) { :build_artifacts_size }
|
|
|
|
it_behaves_like 'a statistic that increases storage_size'
|
|
end
|
|
|
|
context 'when adjusting :packages_size' do
|
|
let(:stat) { :packages_size }
|
|
|
|
it_behaves_like 'a statistic that increases storage_size'
|
|
end
|
|
|
|
context 'when the amount is 0' do
|
|
it 'does not execute a query' do
|
|
project
|
|
expect { described_class.increment_statistic(project.id, :build_artifacts_size, 0) }
|
|
.not_to exceed_query_limit(0)
|
|
end
|
|
end
|
|
|
|
context 'when using an invalid column' do
|
|
it 'raises an error' do
|
|
expect { described_class.increment_statistic(project.id, :id, 13) }
|
|
.to raise_error(ArgumentError, "Cannot increment attribute: id")
|
|
end
|
|
end
|
|
end
|
|
end
|