diff options
Diffstat (limited to 'spec/lib/gitlab/doctor/reset_tokens_spec.rb')
-rw-r--r-- | spec/lib/gitlab/doctor/reset_tokens_spec.rb | 133 |
1 files changed, 133 insertions, 0 deletions
diff --git a/spec/lib/gitlab/doctor/reset_tokens_spec.rb b/spec/lib/gitlab/doctor/reset_tokens_spec.rb new file mode 100644 index 00000000000..0cc947efdb4 --- /dev/null +++ b/spec/lib/gitlab/doctor/reset_tokens_spec.rb @@ -0,0 +1,133 @@ +# frozen_string_literal: true + +require 'spec_helper' + +RSpec.describe Gitlab::Doctor::ResetTokens, feature_category: :runner_fleet do + let(:logger) { instance_double('Logger') } + let(:model_names) { %w[Project Group] } + let(:token_names) { %w[runners_token] } + let(:dry_run) { false } + let(:doctor) { described_class.new(logger, model_names: model_names, token_names: token_names, dry_run: dry_run) } + + let_it_be(:functional_project) { create(:project).tap(&:runners_token) } + let_it_be(:functional_group) { create(:group).tap(&:runners_token) } + + let(:broken_project) { create(:project).tap { |project| project.update_columns(runners_token_encrypted: 'aaa') } } + let(:project_with_cipher_error) do + create(:project).tap do |project| + project.update_columns( + runners_token_encrypted: '|rXs75DSHXPE9MGAIgyxcut8pZc72gaa/2ojU0GS1+R+cXNqkbUB13Vb5BaMwf47d98980fc1') + end + end + + let(:broken_group) { create(:group, runners_token_encrypted: 'aaa') } + + subject(:run!) do + expect(logger).to receive(:info).with( + "Resetting #{token_names.join(', ')} on #{model_names.join(', ')} if they can not be read" + ) + expect(logger).to receive(:info).with('Done!') + doctor.run! + end + + before do + allow(logger).to receive(:info).with(%r{Checked \d/\d Projects}) + allow(logger).to receive(:info).with(%r{Checked \d Projects}) + allow(logger).to receive(:info).with(%r{Checked \d/\d Groups}) + allow(logger).to receive(:info).with(%r{Checked \d Groups}) + end + + it 'fixes broken project and not the functional project' do + expect(logger).to receive(:debug).with("> Fix Project[#{broken_project.id}].runners_token") + + expect { run! }.to change { broken_project.reload.runners_token_encrypted }.from('aaa') + .and not_change { functional_project.reload.runners_token_encrypted } + expect { broken_project.runners_token }.not_to raise_error + end + + it 'fixes project with cipher error' do + expect { project_with_cipher_error.runners_token }.to raise_error(OpenSSL::Cipher::CipherError) + expect(logger).to receive(:debug).with("> Fix Project[#{project_with_cipher_error.id}].runners_token") + + expect { run! }.to change { project_with_cipher_error.reload.runners_token_encrypted } + expect { project_with_cipher_error.runners_token }.not_to raise_error + end + + it 'fixes broken group and not the functional group' do + expect(logger).to receive(:debug).with("> Fix Group[#{broken_group.id}].runners_token") + + expect { run! }.to change { broken_group.reload.runners_token_encrypted }.from('aaa') + .and not_change { functional_group.reload.runners_token_encrypted } + + expect { broken_group.runners_token }.not_to raise_error + end + + context 'when one model specified' do + let(:model_names) { %w[Project] } + + it 'fixes broken project' do + expect(logger).to receive(:debug).with("> Fix Project[#{broken_project.id}].runners_token") + + expect { run! }.to change { broken_project.reload.runners_token_encrypted }.from('aaa') + expect { broken_project.runners_token }.not_to raise_error + end + + it 'does not fix other models' do + expect { run! }.not_to change { broken_group.reload.runners_token_encrypted }.from('aaa') + end + end + + context 'when non-existing token field is given' do + let(:token_names) { %w[nonexisting_token] } + + it 'does not fix anything' do + expect { run! }.not_to change { broken_project.reload.runners_token_encrypted }.from('aaa') + end + end + + context 'when executing in a dry-run mode' do + let(:dry_run) { true } + + it 'prints info about fixed project, but does not actually do anything' do + expect(logger).to receive(:info).with('Executing in DRY RUN mode, no records will actually be updated') + expect(logger).to receive(:debug).with("> Fix Project[#{broken_project.id}].runners_token") + + expect { run! }.not_to change { broken_project.reload.runners_token_encrypted }.from('aaa') + expect { broken_project.runners_token }.to raise_error(TypeError) + end + end + + it 'prints progress along the way' do + stub_const('Gitlab::Doctor::ResetTokens::PRINT_PROGRESS_EVERY', 1) + + broken_project + project_with_cipher_error + + expect(logger).to receive(:info).with( + "Resetting #{token_names.join(', ')} on #{model_names.join(', ')} if they can not be read" + ) + expect(logger).to receive(:info).with('Checked 1/3 Projects') + expect(logger).to receive(:debug).with("> Fix Project[#{broken_project.id}].runners_token") + expect(logger).to receive(:info).with('Checked 2/3 Projects') + expect(logger).to receive(:debug).with("> Fix Project[#{project_with_cipher_error.id}].runners_token") + expect(logger).to receive(:info).with('Checked 3/3 Projects') + expect(logger).to receive(:info).with('Done!') + + doctor.run! + end + + it "prints 'Something went wrong' error when encounters unexpected exception, but continues" do + broken_project + project_with_cipher_error + + expect(logger).to receive(:debug).with( + "> Something went wrong for Project[#{broken_project.id}].runners_token: Error message") + expect(logger).to receive(:debug).with("> Fix Project[#{project_with_cipher_error.id}].runners_token") + + expect(broken_project).to receive(:runners_token).and_raise("Error message") + expect(Project).to receive(:find_each).and_return([broken_project, project_with_cipher_error].each) + + expect { run! }.to not_change { broken_project.reload.runners_token_encrypted }.from('aaa') + .and change { project_with_cipher_error.reload.runners_token_encrypted } + end +end |