Commit 75715dc5 authored by Jan Provaznik's avatar Jan Provaznik Committed by Fabio Pitino

Exclude project namespaces on CI minutes reset

parent 7d567806
......@@ -25,9 +25,8 @@ module Ci
@failed_batches = []
end
def execute!(ids_range: nil, batch_size: BATCH_SIZE)
relation = Namespace
relation = relation.id_in(ids_range) if ids_range
def execute!(ids_range:, batch_size: BATCH_SIZE)
relation = Namespace.without_project_namespaces.id_in(ids_range)
relation.each_batch(of: batch_size) do |namespaces|
reset_ci_minutes!(namespaces)
end
......
......@@ -8,13 +8,10 @@ RSpec.describe Ci::Minutes::BatchResetService do
let(:service) { described_class.new }
describe '#execute!' do
let(:ids_range) { nil }
subject { service.execute!(ids_range: ids_range, batch_size: 3) }
def create_namespace_with_project(id, seconds_used, monthly_minutes_limit = nil)
def create_namespace_with_project(seconds_used, monthly_minutes_limit = nil)
namespace = create(:namespace,
id: id,
shared_runners_minutes_limit: monthly_minutes_limit, # when `nil` it inherits the global limit
extra_shared_runners_minutes_limit: 50,
last_ci_minutes_notification_at: Time.current,
......@@ -37,19 +34,19 @@ RSpec.describe Ci::Minutes::BatchResetService do
allow(::Gitlab::CurrentSettings).to receive(:shared_runners_minutes).and_return(2_000)
end
let!(:namespace_1) { create_namespace_with_project(1, 2_020.minutes, nil) }
let!(:namespace_2) { create_namespace_with_project(2, 2_020.minutes, 2_000) }
let!(:namespace_3) { create_namespace_with_project(3, 2_020.minutes, 2_000) }
let!(:namespace_4) { create_namespace_with_project(4, 1_000.minutes, nil) }
let!(:namespace_5) { create_namespace_with_project(5, 1_000.minutes, 2_000) }
let!(:namespace_6) { create_namespace_with_project(6, 1_000.minutes, 0) }
let_it_be(:project_namespace) { create(:project_namespace) }
let_it_be_with_reload(:namespace_1) { create_namespace_with_project(2_020.minutes, nil) }
let_it_be_with_reload(:namespace_2) { create_namespace_with_project(2_020.minutes, 2_000) }
let_it_be_with_reload(:namespace_3) { create_namespace_with_project(2_020.minutes, 2_000) }
let_it_be_with_reload(:namespace_4) { create_namespace_with_project(1_000.minutes, nil) }
let_it_be_with_reload(:namespace_5) { create_namespace_with_project(1_000.minutes, 2_000) }
let_it_be_with_reload(:namespace_6) { create_namespace_with_project(1_000.minutes, 0) }
context 'when ID range is provided' do
let(:ids_range) { (1..5) }
let(:ids_range) { (project_namespace.id..namespace_5.id) }
let(:namespaces_exceeding_minutes) { [namespace_1, namespace_2, namespace_3] }
let(:namespaces_not_exceeding_minutes) { [namespace_4, namespace_5] }
it 'resets minutes in batches for the given range' do
it 'resets minutes in batches for the given range and ignores project namespaces' do
expect(service).to receive(:reset_ci_minutes!).with([namespace_1, namespace_2, namespace_3])
expect(service).to receive(:reset_ci_minutes!).with([namespace_4, namespace_5])
......@@ -87,36 +84,8 @@ RSpec.describe Ci::Minutes::BatchResetService do
expect(namespace.last_ci_minutes_usage_notification_level).to be_nil
end
end
end
context 'when ID range is not provided' do
let(:ids_range) { nil }
it 'resets minutes in batches for all namespaces' do
expect(service).to receive(:reset_ci_minutes!).with([namespace_1, namespace_2, namespace_3])
expect(service).to receive(:reset_ci_minutes!).with([namespace_4, namespace_5, namespace_6])
subject
end
it 'resets CI minutes and does not recalculate purchased minutes for the namespace having unlimited monthly minutes' do
subject
namespace_6.reset
expect(namespace_6.extra_shared_runners_minutes_limit).to eq 50
expect(namespace_6.namespace_statistics.shared_runners_seconds).to eq 0
expect(namespace_6.namespace_statistics.shared_runners_seconds_last_reset).to be_present
expect(ProjectStatistics.find_by(namespace: namespace_6).shared_runners_seconds).to eq 0
expect(ProjectStatistics.find_by(namespace: namespace_6).shared_runners_seconds_last_reset).to be_present
expect(namespace_6.last_ci_minutes_notification_at).to be_nil
expect(namespace_6.last_ci_minutes_usage_notification_level).to be_nil
end
end
context 'when an ActiveRecordError is raised' do
let(:ids_range) { nil }
before do
expect(Namespace).to receive(:transaction).once.ordered.and_raise(ActiveRecord::ActiveRecordError, 'something went wrong')
expect(Namespace).to receive(:transaction).once.ordered.and_call_original
......@@ -124,7 +93,7 @@ RSpec.describe Ci::Minutes::BatchResetService do
it 'continues its progress and raises exception at the end' do
expect(service).to receive(:reset_ci_minutes!).with([namespace_1, namespace_2, namespace_3]).and_call_original
expect(service).to receive(:reset_ci_minutes!).with([namespace_4, namespace_5, namespace_6]).and_call_original
expect(service).to receive(:reset_ci_minutes!).with([namespace_4, namespace_5]).and_call_original
expect { subject }
.to raise_error(described_class::BatchNotResetError) do |error|
......@@ -132,8 +101,8 @@ RSpec.describe Ci::Minutes::BatchResetService do
expect(error.sentry_extra_data[:failed_batches]).to contain_exactly(
{
count: 3,
first_namespace_id: 1,
last_namespace_id: 3,
first_namespace_id: namespace_1.id,
last_namespace_id: namespace_3.id,
error_message: 'something went wrong',
error_backtrace: kind_of(Array)
}
......@@ -154,7 +123,9 @@ RSpec.describe Ci::Minutes::BatchResetService do
end
with_them do
let!(:namespace) { create_namespace_with_project(1, 100.minutes, namespace_limit) }
let!(:namespace) { create_namespace_with_project(100.minutes, namespace_limit) }
let(:ids_range) { [namespace.id] }
before do
allow(::Gitlab::CurrentSettings).to receive(:shared_runners_minutes).and_return(global_limit)
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment