From 19900f647e81cb7078b9d329c4b57477068c4064 Mon Sep 17 00:00:00 2001 From: Matt Jankowski Date: Tue, 17 Oct 2023 07:05:28 -0400 Subject: [PATCH] Add coverage for `UnreservedUsernameValidator` (#25590) --- .../unreserved_username_validator.rb | 29 ++++- .../unreserved_username_validator_spec.rb | 123 ++++++++++++++---- 2 files changed, 122 insertions(+), 30 deletions(-) diff --git a/app/validators/unreserved_username_validator.rb b/app/validators/unreserved_username_validator.rb index f82f4b91d..55a8c835f 100644 --- a/app/validators/unreserved_username_validator.rb +++ b/app/validators/unreserved_username_validator.rb @@ -11,16 +11,31 @@ class UnreservedUsernameValidator < ActiveModel::Validator private - def pam_controlled? - return false unless Devise.pam_authentication && Devise.pam_controlled_service - - Rpam2.account(Devise.pam_controlled_service, @username).present? + def reserved_username? + pam_username_reserved? || settings_username_reserved? end - def reserved_username? - return true if pam_controlled? - return false unless Setting.reserved_usernames + def pam_username_reserved? + pam_controlled? && pam_reserves_username? + end + def pam_controlled? + Devise.pam_authentication && Devise.pam_controlled_service + end + + def pam_reserves_username? + Rpam2.account(Devise.pam_controlled_service, @username) + end + + def settings_username_reserved? + settings_has_reserved_usernames? && settings_reserves_username? + end + + def settings_has_reserved_usernames? + Setting.reserved_usernames.present? + end + + def settings_reserves_username? Setting.reserved_usernames.include?(@username.downcase) end end diff --git a/spec/validators/unreserved_username_validator_spec.rb b/spec/validators/unreserved_username_validator_spec.rb index 6f353eeaf..0eb5f8368 100644 --- a/spec/validators/unreserved_username_validator_spec.rb +++ b/spec/validators/unreserved_username_validator_spec.rb @@ -2,41 +2,118 @@ require 'rails_helper' -RSpec.describe UnreservedUsernameValidator, type: :validator do - describe '#validate' do - before do - allow(validator).to receive(:reserved_username?) { reserved_username } - validator.validate(account) +describe UnreservedUsernameValidator do + let(:record_class) do + Class.new do + include ActiveModel::Validations + attr_accessor :username + + validates_with UnreservedUsernameValidator end + end + let(:record) { record_class.new } - let(:validator) { described_class.new } - let(:account) { instance_double(Account, username: username, errors: errors) } - let(:errors) { instance_double(ActiveModel::Errors, add: nil) } + describe '#validate' do + context 'when username is nil' do + it 'does not add errors' do + record.username = nil - context 'when @username is blank?' do - let(:username) { nil } - - it 'not calls errors.add' do - expect(errors).to_not have_received(:add).with(:username, any_args) + expect(record).to be_valid + expect(record.errors).to be_empty end end - context 'when @username is not blank?' do - let(:username) { 'f' } + context 'when PAM is enabled' do + before do + allow(Devise).to receive(:pam_authentication).and_return(true) + end - context 'with reserved_username?' do - let(:reserved_username) { true } + context 'with a pam service available' do + let(:service) { double } + let(:pam_class) do + Class.new do + def self.account(service, username); end + end + end - it 'calls errors.add' do - expect(errors).to have_received(:add).with(:username, :reserved) + before do + stub_const('Rpam2', pam_class) + allow(Devise).to receive(:pam_controlled_service).and_return(service) + end + + context 'when the account exists' do + before do + allow(Rpam2).to receive(:account).with(service, 'username').and_return(true) + end + + it 'adds errors to the record' do + record.username = 'username' + + expect(record).to_not be_valid + expect(record.errors.first.attribute).to eq(:username) + expect(record.errors.first.type).to eq(:reserved) + end + end + + context 'when the account does not exist' do + before do + allow(Rpam2).to receive(:account).with(service, 'username').and_return(false) + end + + it 'does not add errors to the record' do + record.username = 'username' + + expect(record).to be_valid + expect(record.errors).to be_empty + end end end - context 'when username is not reserved' do - let(:reserved_username) { false } + context 'without a pam service' do + before do + allow(Devise).to receive(:pam_controlled_service).and_return(false) + end - it 'not calls errors.add' do - expect(errors).to_not have_received(:add).with(:username, any_args) + context 'when there are not any reserved usernames' do + before do + stub_reserved_usernames(nil) + end + + it 'does not add errors to the record' do + record.username = 'username' + + expect(record).to be_valid + expect(record.errors).to be_empty + end + end + + context 'when there are reserved usernames' do + before do + stub_reserved_usernames(%w(alice bob)) + end + + context 'when the username is reserved' do + it 'adds errors to the record' do + record.username = 'alice' + + expect(record).to_not be_valid + expect(record.errors.first.attribute).to eq(:username) + expect(record.errors.first.type).to eq(:reserved) + end + end + + context 'when the username is not reserved' do + it 'does not add errors to the record' do + record.username = 'chris' + + expect(record).to be_valid + expect(record.errors).to be_empty + end + end + end + + def stub_reserved_usernames(value) + allow(Setting).to receive(:[]).with('reserved_usernames').and_return(value) end end end