diff options
author | GitLab Bot <gitlab-bot@gitlab.com> | 2022-04-20 13:00:54 +0300 |
---|---|---|
committer | GitLab Bot <gitlab-bot@gitlab.com> | 2022-04-20 13:00:54 +0300 |
commit | 3cccd102ba543e02725d247893729e5c73b38295 (patch) | |
tree | f36a04ec38517f5deaaacb5acc7d949688d1e187 /spec/services/database/consistency_check_service_spec.rb | |
parent | 205943281328046ef7b4528031b90fbda70c75ac (diff) |
Add latest changes from gitlab-org/gitlab@14-10-stable-eev14.10.0-rc42
Diffstat (limited to 'spec/services/database/consistency_check_service_spec.rb')
-rw-r--r-- | spec/services/database/consistency_check_service_spec.rb | 154 |
1 files changed, 154 insertions, 0 deletions
diff --git a/spec/services/database/consistency_check_service_spec.rb b/spec/services/database/consistency_check_service_spec.rb new file mode 100644 index 00000000000..2e642451432 --- /dev/null +++ b/spec/services/database/consistency_check_service_spec.rb @@ -0,0 +1,154 @@ +# frozen_string_literal: true + +require 'spec_helper' + +RSpec.describe Database::ConsistencyCheckService do + let(:batch_size) { 5 } + let(:max_batches) { 2 } + + before do + stub_const("Gitlab::Database::ConsistencyChecker::BATCH_SIZE", batch_size) + stub_const("Gitlab::Database::ConsistencyChecker::MAX_BATCHES", max_batches) + end + + after do + redis_shared_state_cleanup! + end + + subject(:consistency_check_service) do + described_class.new( + source_model: Namespace, + target_model: Ci::NamespaceMirror, + source_columns: %w[id traversal_ids], + target_columns: %w[namespace_id traversal_ids] + ) + end + + describe '#random_start_id' do + let(:batch_size) { 5 } + + before do + create_list(:namespace, 50) # This will also create Ci::NameSpaceMirror objects + end + + it 'generates a random start_id within the records ids' do + 10.times do + start_id = subject.send(:random_start_id) + expect(start_id).to be_between(Namespace.first.id, Namespace.last.id).inclusive + end + end + end + + describe '#execute' do + let(:empty_results) do + { batches: 0, matches: 0, mismatches: 0, mismatches_details: [] } + end + + context 'when empty tables' do + it 'returns results with zero counters' do + result = consistency_check_service.execute + + expect(result).to eq(empty_results) + end + + it 'does not call the ConsistencyCheckService' do + expect(Gitlab::Database::ConsistencyChecker).not_to receive(:new) + consistency_check_service.execute + end + end + + context 'no cursor has been saved before' do + let(:selected_start_id) { Namespace.order(:id).limit(5).pluck(:id).last } + let(:expected_next_start_id) { selected_start_id + batch_size * max_batches } + + before do + create_list(:namespace, 50) # This will also create Ci::NameSpaceMirror objects + expect(consistency_check_service).to receive(:random_start_id).and_return(selected_start_id) + end + + it 'picks a random start_id' do + expected_result = { + batches: 2, + matches: 10, + mismatches: 0, + mismatches_details: [], + start_id: selected_start_id, + next_start_id: expected_next_start_id + } + expect(consistency_check_service.execute).to eq(expected_result) + end + + it 'calls the ConsistencyCheckService with the expected parameters' do + allow_next_instance_of(Gitlab::Database::ConsistencyChecker) do |instance| + expect(instance).to receive(:execute).with(start_id: selected_start_id).and_return({ + batches: 2, + next_start_id: expected_next_start_id, + matches: 10, + mismatches: 0, + mismatches_details: [] + }) + end + + expect(Gitlab::Database::ConsistencyChecker).to receive(:new).with( + source_model: Namespace, + target_model: Ci::NamespaceMirror, + source_columns: %w[id traversal_ids], + target_columns: %w[namespace_id traversal_ids] + ).and_call_original + + expected_result = { + batches: 2, + start_id: selected_start_id, + next_start_id: expected_next_start_id, + matches: 10, + mismatches: 0, + mismatches_details: [] + } + expect(consistency_check_service.execute).to eq(expected_result) + end + + it 'saves the next_start_id in Redis for he next iteration' do + expect(consistency_check_service).to receive(:save_next_start_id).with(expected_next_start_id).and_call_original + consistency_check_service.execute + end + end + + context 'cursor saved in Redis and moving' do + let(:first_namespace_id) { Namespace.order(:id).first.id } + let(:second_namespace_id) { Namespace.order(:id).second.id } + + before do + create_list(:namespace, 30) # This will also create Ci::NameSpaceMirror objects + end + + it "keeps moving the cursor with each call to the service" do + expect(consistency_check_service).to receive(:random_start_id).at_most(:once).and_return(first_namespace_id) + + allow_next_instance_of(Gitlab::Database::ConsistencyChecker) do |instance| + expect(instance).to receive(:execute).ordered.with(start_id: first_namespace_id).and_call_original + expect(instance).to receive(:execute).ordered.with(start_id: first_namespace_id + 10).and_call_original + expect(instance).to receive(:execute).ordered.with(start_id: first_namespace_id + 20).and_call_original + # Gets back to the start of the table + expect(instance).to receive(:execute).ordered.with(start_id: first_namespace_id).and_call_original + end + + 4.times do + consistency_check_service.execute + end + end + + it "keeps moving the cursor from any start point" do + expect(consistency_check_service).to receive(:random_start_id).at_most(:once).and_return(second_namespace_id) + + allow_next_instance_of(Gitlab::Database::ConsistencyChecker) do |instance| + expect(instance).to receive(:execute).ordered.with(start_id: second_namespace_id).and_call_original + expect(instance).to receive(:execute).ordered.with(start_id: second_namespace_id + 10).and_call_original + end + + 2.times do + consistency_check_service.execute + end + end + end + end +end |