diff options
Diffstat (limited to 'spec/models/user_spec.rb')
-rw-r--r-- | spec/models/user_spec.rb | 179 |
1 files changed, 167 insertions, 12 deletions
diff --git a/spec/models/user_spec.rb b/spec/models/user_spec.rb index 6ee38048025..bc425b15c6e 100644 --- a/spec/models/user_spec.rb +++ b/spec/models/user_spec.rb @@ -69,6 +69,12 @@ RSpec.describe User do it { is_expected.to delegate_method(:markdown_surround_selection).to(:user_preference) } it { is_expected.to delegate_method(:markdown_surround_selection=).to(:user_preference).with_arguments(:args) } + it { is_expected.to delegate_method(:diffs_deletion_color).to(:user_preference) } + it { is_expected.to delegate_method(:diffs_deletion_color=).to(:user_preference).with_arguments(:args) } + + it { is_expected.to delegate_method(:diffs_addition_color).to(:user_preference) } + it { is_expected.to delegate_method(:diffs_addition_color=).to(:user_preference).with_arguments(:args) } + it { is_expected.to delegate_method(:job_title).to(:user_detail).allow_nil } it { is_expected.to delegate_method(:job_title=).to(:user_detail).with_arguments(:args).allow_nil } @@ -1554,7 +1560,7 @@ RSpec.describe User do end it 'adds the confirmed primary email to emails' do - expect(user.emails.confirmed.map(&:email)).not_to include(user.email) + expect(user.emails.confirmed.map(&:email)).not_to include(user.unconfirmed_email) user.confirm @@ -1613,14 +1619,23 @@ RSpec.describe User do context 'when the email is changed but not confirmed' do let(:user) { create(:user, email: 'primary@example.com') } - it 'does not add the new email to emails yet' do + before do user.update!(email: 'new_primary@example.com') + end + it 'does not add the new email to emails yet' do expect(user.unconfirmed_email).to eq('new_primary@example.com') expect(user.email).to eq('primary@example.com') expect(user).to be_confirmed expect(user.emails.pluck(:email)).not_to include('new_primary@example.com') end + + it 'adds the new email to emails upon confirmation' do + user.confirm + expect(user.email).to eq('new_primary@example.com') + expect(user).to be_confirmed + expect(user.emails.pluck(:email)).to include('new_primary@example.com') + end end context 'when the user is created as not confirmed' do @@ -1630,6 +1645,11 @@ RSpec.describe User do expect(user).not_to be_confirmed expect(user.emails.pluck(:email)).not_to include('primary@example.com') end + + it 'adds the email to emails upon confirmation' do + user.confirm + expect(user.emails.pluck(:email)).to include('primary@example.com') + end end context 'when the user is created as confirmed' do @@ -2083,6 +2103,74 @@ RSpec.describe User do end end + describe 'needs_new_otp_secret?', :freeze_time do + let(:user) { create(:user) } + + context 'when two-factor is not enabled' do + it 'returns true if otp_secret_expires_at is nil' do + expect(user.needs_new_otp_secret?).to eq(true) + end + + it 'returns true if the otp_secret_expires_at has passed' do + user.update!(otp_secret_expires_at: 10.minutes.ago) + + expect(user.reload.needs_new_otp_secret?).to eq(true) + end + + it 'returns false if the otp_secret_expires_at has not passed' do + user.update!(otp_secret_expires_at: 10.minutes.from_now) + + expect(user.reload.needs_new_otp_secret?).to eq(false) + end + end + + context 'when two-factor is enabled' do + let(:user) { create(:user, :two_factor) } + + it 'returns false even if ttl is expired' do + user.otp_secret_expires_at = 10.minutes.ago + + expect(user.needs_new_otp_secret?).to eq(false) + end + end + end + + describe 'otp_secret_expired?', :freeze_time do + let(:user) { create(:user) } + + it 'returns true if otp_secret_expires_at is nil' do + expect(user.otp_secret_expired?).to eq(true) + end + + it 'returns true if the otp_secret_expires_at has passed' do + user.otp_secret_expires_at = 10.minutes.ago + + expect(user.otp_secret_expired?).to eq(true) + end + + it 'returns false if the otp_secret_expires_at has not passed' do + user.otp_secret_expires_at = 20.minutes.from_now + + expect(user.otp_secret_expired?).to eq(false) + end + end + + describe 'update_otp_secret!', :freeze_time do + let(:user) { create(:user) } + + before do + user.update_otp_secret! + end + + it 'sets the otp_secret' do + expect(user.otp_secret).to have_attributes(length: described_class::OTP_SECRET_LENGTH) + end + + it 'updates the otp_secret_expires_at' do + expect(user.otp_secret_expires_at).to eq(Time.current + described_class::OTP_SECRET_TTL) + end + end + describe 'projects' do before do @user = create(:user) @@ -2653,6 +2741,19 @@ RSpec.describe User do let_it_be(:user3) { create(:user, name: 'us', username: 'se', email: 'foo@example.com') } let_it_be(:email) { create(:email, user: user, email: 'alias@example.com') } + describe 'name user and email relative ordering' do + let_it_be(:named_alexander) { create(:user, name: 'Alexander Person', username: 'abcd', email: 'abcd@example.com') } + let_it_be(:username_alexand) { create(:user, name: 'Joao Alexander', username: 'Alexand', email: 'joao@example.com') } + + it 'prioritizes exact matches' do + expect(described_class.search('Alexand')).to eq([username_alexand, named_alexander]) + end + + it 'falls back to ordering by name' do + expect(described_class.search('Alexander')).to eq([named_alexander, username_alexand]) + end + end + describe 'name matching' do it 'returns users with a matching name with exact match first' do expect(described_class.search(user.name)).to eq([user, user2]) @@ -4251,16 +4352,34 @@ RSpec.describe User do end end - it_behaves_like '#ci_owned_runners' + describe '#ci_owned_runners' do + it_behaves_like '#ci_owned_runners' - context 'when FF ci_owned_runners_cross_joins_fix is disabled' do - before do - skip_if_multiple_databases_are_setup + context 'when FF use_traversal_ids is disabled fallbacks to inefficient implementation' do + before do + stub_feature_flags(use_traversal_ids: false) + end - stub_feature_flags(ci_owned_runners_cross_joins_fix: false) + it_behaves_like '#ci_owned_runners' end - it_behaves_like '#ci_owned_runners' + context 'when FF ci_owned_runners_cross_joins_fix is disabled' do + before do + skip_if_multiple_databases_are_setup + + stub_feature_flags(ci_owned_runners_cross_joins_fix: false) + end + + it_behaves_like '#ci_owned_runners' + end + + context 'when FF ci_owned_runners_unnest_index is disabled uses GIN index' do + before do + stub_feature_flags(ci_owned_runners_unnest_index: false) + end + + it_behaves_like '#ci_owned_runners' + end end describe '#projects_with_reporter_access_limited_to' do @@ -4882,17 +5001,36 @@ RSpec.describe User do end describe '#attention_requested_open_merge_requests_count' do - it 'returns number of open merge requests from non-archived projects' do - user = create(:user) - project = create(:project, :public) - archived_project = create(:project, :public, :archived) + let(:user) { create(:user) } + let(:project) { create(:project, :public) } + let(:archived_project) { create(:project, :public, :archived) } + before do create(:merge_request, source_project: project, author: user, reviewers: [user]) create(:merge_request, :closed, source_project: project, author: user, reviewers: [user]) create(:merge_request, source_project: archived_project, author: user, reviewers: [user]) + end + it 'returns number of open merge requests from non-archived projects' do + expect(Rails.cache).not_to receive(:fetch) expect(user.attention_requested_open_merge_requests_count(force: true)).to eq 1 end + + context 'when uncached_mr_attention_requests_count is disabled' do + before do + stub_feature_flags(uncached_mr_attention_requests_count: false) + end + + it 'fetches from cache' do + expect(Rails.cache).to receive(:fetch).with( + user.attention_request_cache_key, + force: false, + expires_in: described_class::COUNT_CACHE_VALIDITY_PERIOD + ).and_call_original + + expect(user.attention_requested_open_merge_requests_count).to eq 1 + end + end end describe '#assigned_open_issues_count' do @@ -6632,6 +6770,23 @@ RSpec.describe User do end end + describe '.without_forbidden_states' do + let_it_be(:normal_user) { create(:user, username: 'johndoe') } + let_it_be(:admin_user) { create(:user, :admin, username: 'iamadmin') } + let_it_be(:blocked_user) { create(:user, :blocked, username: 'notsorandom') } + let_it_be(:banned_user) { create(:user, :banned, username: 'iambanned') } + let_it_be(:external_user) { create(:user, :external) } + let_it_be(:unconfirmed_user) { create(:user, confirmed_at: nil) } + let_it_be(:omniauth_user) { create(:omniauth_user, provider: 'twitter', extern_uid: '123456') } + let_it_be(:internal_user) { User.alert_bot.tap { |u| u.confirm } } + + it 'does not return blocked or banned users' do + expect(described_class.without_forbidden_states).to match_array([ + normal_user, admin_user, external_user, unconfirmed_user, omniauth_user, internal_user + ]) + end + end + describe 'user_project' do it 'returns users project matched by username and public visibility' do user = create(:user) |