Welcome to mirror list, hosted at ThFree Co, Russian Federation.

gitlab.com/gitlab-org/gitlab-foss.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to 'spec/models/user_spec.rb')
-rw-r--r--spec/models/user_spec.rb254
1 files changed, 174 insertions, 80 deletions
diff --git a/spec/models/user_spec.rb b/spec/models/user_spec.rb
index 7207ee0b172..4a66af4ddf1 100644
--- a/spec/models/user_spec.rb
+++ b/spec/models/user_spec.rb
@@ -81,6 +81,9 @@ RSpec.describe User do
it { is_expected.to delegate_method(:use_legacy_web_ide).to(:user_preference) }
it { is_expected.to delegate_method(:use_legacy_web_ide=).to(:user_preference).with_arguments(:args) }
+ it { is_expected.to delegate_method(:use_new_navigation).to(:user_preference) }
+ it { is_expected.to delegate_method(:use_new_navigation=).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 }
@@ -146,6 +149,21 @@ RSpec.describe User do
it { is_expected.to have_many(:project_callouts).class_name('Users::ProjectCallout') }
it { is_expected.to have_many(:created_projects).dependent(:nullify).class_name('Project') }
+ describe 'default values' do
+ let(:user) { described_class.new }
+
+ it { expect(user.admin).to be_falsey }
+ it { expect(user.external).to eq(Gitlab::CurrentSettings.user_default_external) }
+ it { expect(user.can_create_group).to eq(Gitlab::CurrentSettings.can_create_group) }
+ it { expect(user.can_create_team).to be_falsey }
+ it { expect(user.hide_no_ssh_key).to be_falsey }
+ it { expect(user.hide_no_password).to be_falsey }
+ it { expect(user.project_view).to eq('files') }
+ it { expect(user.notified_of_own_activity).to be_falsey }
+ it { expect(user.preferred_language).to eq(I18n.default_locale.to_s) }
+ it { expect(user.theme_id).to eq(described_class.gitlab_config.default_theme) }
+ end
+
describe '#user_detail' do
it 'does not persist `user_detail` by default' do
expect(create(:user).user_detail).not_to be_persisted
@@ -345,52 +363,33 @@ RSpec.describe User do
context 'check_password_weakness' do
let(:weak_password) { "qwertyuiop" }
- context 'when feature flag is disabled' do
- before do
- stub_feature_flags(block_weak_passwords: false)
- end
-
- it 'does not add an error when password is weak' do
- expect(Security::WeakPasswords).not_to receive(:weak_for_user?)
-
- user.password = weak_password
- expect(user).to be_valid
- end
+ it 'checks for password weakness when password changes' do
+ expect(Security::WeakPasswords).to receive(:weak_for_user?)
+ .with(weak_password, user).and_call_original
+ user.password = weak_password
+ expect(user).not_to be_valid
end
- context 'when feature flag is enabled' do
- before do
- stub_feature_flags(block_weak_passwords: true)
- end
-
- it 'checks for password weakness when password changes' do
- expect(Security::WeakPasswords).to receive(:weak_for_user?)
- .with(weak_password, user).and_call_original
- user.password = weak_password
- expect(user).not_to be_valid
- end
-
- it 'adds an error when password is weak' do
- user.password = weak_password
- expect(user).not_to be_valid
- expect(user.errors).to be_of_kind(:password, 'must not contain commonly used combinations of words and letters')
- end
+ it 'adds an error when password is weak' do
+ user.password = weak_password
+ expect(user).not_to be_valid
+ expect(user.errors).to be_of_kind(:password, 'must not contain commonly used combinations of words and letters')
+ end
- it 'is valid when password is not weak' do
- user.password = ::User.random_password
- expect(user).to be_valid
- end
+ it 'is valid when password is not weak' do
+ user.password = ::User.random_password
+ expect(user).to be_valid
+ end
- it 'is valid when weak password was already set' do
- user = build(:user, password: weak_password)
- user.save!(validate: false)
+ it 'is valid when weak password was already set' do
+ user = build(:user, password: weak_password)
+ user.save!(validate: false)
- expect(Security::WeakPasswords).not_to receive(:weak_for_user?)
+ expect(Security::WeakPasswords).not_to receive(:weak_for_user?)
- # Change an unrelated value
- user.name = "Example McExampleFace"
- expect(user).to be_valid
- end
+ # Change an unrelated value
+ user.name = "Example McExampleFace"
+ expect(user).to be_valid
end
end
end
@@ -417,7 +416,7 @@ RSpec.describe User do
end
it 'falls back to english when I18n.default_locale is not an available language' do
- I18n.default_locale = :kl
+ allow(I18n).to receive(:default_locale) { :kl }
default_preferred_language = user.send(:default_preferred_language)
expect(user.preferred_language).to eq default_preferred_language
@@ -1590,10 +1589,6 @@ RSpec.describe User do
let(:expired_confirmation_sent_at) { Date.today - described_class.confirm_within - 7.days }
let(:extant_confirmation_sent_at) { Date.today }
- before do
- allow_any_instance_of(ApplicationSetting).to receive(:send_user_confirmation_email).and_return(true)
- end
-
let(:user) do
create(:user, :unconfirmed, unconfirmed_email: 'test@gitlab.com').tap do |user|
user.update!(confirmation_sent_at: confirmation_sent_at)
@@ -3090,6 +3085,14 @@ RSpec.describe User do
expect(described_class.find_by_ssh_key_id(-1)).to be_nil
end
end
+
+ it 'does not return a signing-only key', :aggregate_failures do
+ signing_key = create(:key, usage_type: :signing, user: user)
+ auth_and_signing_key = create(:key, usage_type: :auth_and_signing, user: user)
+
+ expect(described_class.find_by_ssh_key_id(signing_key.id)).to be_nil
+ expect(described_class.find_by_ssh_key_id(auth_and_signing_key.id)).to eq(user)
+ end
end
shared_examples "find user by login" do
@@ -3209,6 +3212,7 @@ RSpec.describe User do
expect(described_class.find_by_full_path('unknown')).to eq(nil)
end
end
+
context 'with the follow_redirects option set to true' do
it 'returns nil' do
expect(described_class.find_by_full_path('unknown', follow_redirects: true)).to eq(nil)
@@ -4431,7 +4435,7 @@ RSpec.describe User do
shared_context '#ci_owned_runners' do
let(:user) { create(:user) }
- shared_examples :nested_groups_owner do
+ shared_examples 'nested groups owner' do
context 'when the user is the owner of a multi-level group' do
before do
set_permissions_for_users
@@ -4448,7 +4452,7 @@ RSpec.describe User do
end
end
- shared_examples :group_owner do
+ shared_examples 'group owner' do
context 'when the user is the owner of a one level group' do
before do
group.add_owner(user)
@@ -4464,7 +4468,7 @@ RSpec.describe User do
end
end
- shared_examples :project_owner do
+ shared_examples 'project owner' do
context 'when the user is the owner of a project' do
it 'loads the runner belonging to the project' do
expect(user.ci_owned_runners).to contain_exactly(runner)
@@ -4476,7 +4480,7 @@ RSpec.describe User do
end
end
- shared_examples :project_member do
+ shared_examples 'project member' do
context 'when the user is a maintainer' do
before do
add_user(:maintainer)
@@ -4534,7 +4538,7 @@ RSpec.describe User do
end
end
- shared_examples :group_member do
+ shared_examples 'group member' do
context 'when the user is a maintainer' do
before do
add_user(:maintainer)
@@ -4607,7 +4611,7 @@ RSpec.describe User do
let!(:project) { create(:project, namespace: namespace) }
let!(:runner) { create(:ci_runner, :project, projects: [project]) }
- it_behaves_like :project_owner
+ it_behaves_like 'project owner'
end
context 'with group runner in a non owned group' do
@@ -4618,14 +4622,14 @@ RSpec.describe User do
group.add_member(user, access)
end
- it_behaves_like :group_member
+ it_behaves_like 'group member'
end
context 'with group runner in an owned group' do
let!(:group) { create(:group) }
let!(:group_runner) { create(:ci_runner, :group, groups: [group]) }
- it_behaves_like :group_owner
+ it_behaves_like 'group owner'
end
context 'with group runner in an owned group and group runner in a different owner subgroup' do
@@ -4640,7 +4644,7 @@ RSpec.describe User do
subgroup.add_owner(another_user)
end
- it_behaves_like :nested_groups_owner
+ it_behaves_like 'nested groups owner'
end
context 'with personal project runner in an an owned group and a group runner in that same group' do
@@ -4653,7 +4657,7 @@ RSpec.describe User do
group.add_owner(user)
end
- it_behaves_like :nested_groups_owner
+ it_behaves_like 'nested groups owner'
end
context 'with personal project runner in an owned group and a group runner in a subgroup' do
@@ -4667,7 +4671,7 @@ RSpec.describe User do
group.add_owner(user)
end
- it_behaves_like :nested_groups_owner
+ it_behaves_like 'nested groups owner'
end
context 'with personal project runner in an owned group in an owned namespace and a group runner in that group' do
@@ -4681,7 +4685,7 @@ RSpec.describe User do
group.add_owner(user)
end
- it_behaves_like :nested_groups_owner
+ it_behaves_like 'nested groups owner'
end
context 'with personal project runner in an owned namespace, an owned group, a subgroup and a group runner in that subgroup' do
@@ -4696,7 +4700,7 @@ RSpec.describe User do
group.add_owner(user)
end
- it_behaves_like :nested_groups_owner
+ it_behaves_like 'nested groups owner'
end
context 'with a project runner that belong to projects that belong to a not owned group' do
@@ -4708,7 +4712,7 @@ RSpec.describe User do
project.add_member(user, access)
end
- it_behaves_like :project_member
+ it_behaves_like 'project member'
end
context 'with project runners that belong to projects that do not belong to any group' do
@@ -4731,7 +4735,7 @@ RSpec.describe User do
group.add_member(another_user, :owner)
end
- it_behaves_like :group_member
+ it_behaves_like 'group member'
end
end
@@ -5221,6 +5225,10 @@ RSpec.describe User do
describe '#invalidate_issue_cache_counts' do
let(:user) { build_stubbed(:user) }
+ before do
+ stub_feature_flags(limit_assigned_issues_count: false)
+ end
+
it 'invalidates cache for issue counter' do
cache_mock = double
@@ -5230,6 +5238,23 @@ RSpec.describe User do
user.invalidate_issue_cache_counts
end
+
+ context 'when limit_assigned_issues_count is enabled' do
+ before do
+ stub_feature_flags(limit_assigned_issues_count: true)
+ end
+
+ it 'invalidates cache for issue counter' do
+ cache_mock = double
+
+ expect(cache_mock).to receive(:delete).with(['users', user.id, 'assigned_open_issues_count'])
+ expect(cache_mock).to receive(:delete).with(['users', user.id, 'max_assigned_open_issues_count'])
+
+ allow(Rails).to receive(:cache).and_return(cache_mock)
+
+ user.invalidate_issue_cache_counts
+ end
+ end
end
describe '#invalidate_merge_request_cache_counts' do
@@ -6155,33 +6180,44 @@ RSpec.describe User do
describe '#notification_email_for' do
let(:user) { create(:user) }
- let(:group) { create(:group) }
- subject { user.notification_email_for(group) }
+ subject { user.notification_email_for(namespace) }
- context 'when group is nil' do
- let(:group) { nil }
+ context 'when namespace is nil' do
+ let(:namespace) { nil }
it 'returns global notification email' do
is_expected.to eq(user.notification_email_or_default)
end
end
- context 'when group has no notification email set' do
- it 'returns global notification email' do
- create(:notification_setting, user: user, source: group, notification_email: '')
+ context 'for group namespace' do
+ let(:namespace) { create(:group) }
- is_expected.to eq(user.notification_email_or_default)
+ context 'when group has no notification email set' do
+ it 'returns global notification email' do
+ create(:notification_setting, user: user, source: namespace, notification_email: '')
+
+ is_expected.to eq(user.notification_email_or_default)
+ end
+ end
+
+ context 'when group has notification email set' do
+ it 'returns group notification email' do
+ group_notification_email = 'user+group@example.com'
+ create(:email, :confirmed, user: user, email: group_notification_email)
+ create(:notification_setting, user: user, source: namespace, notification_email: group_notification_email)
+
+ is_expected.to eq(group_notification_email)
+ end
end
end
- context 'when group has notification email set' do
- it 'returns group notification email' do
- group_notification_email = 'user+group@example.com'
- create(:email, :confirmed, user: user, email: group_notification_email)
- create(:notification_setting, user: user, source: group, notification_email: group_notification_email)
+ context 'for user namespace' do
+ let(:namespace) { create(:user_namespace) }
- is_expected.to eq(group_notification_email)
+ it 'returns global notification email' do
+ is_expected.to eq(user.notification_email_or_default)
end
end
end
@@ -6799,7 +6835,8 @@ RSpec.describe User do
{ user_type: :alert_bot },
{ user_type: :support_bot },
{ user_type: :security_bot },
- { user_type: :automation_bot }
+ { user_type: :automation_bot },
+ { user_type: :admin_bot }
]
end
@@ -6881,11 +6918,12 @@ RSpec.describe User do
using RSpec::Parameterized::TableSyntax
where(:user_type, :expected_result) do
- 'human' | true
- 'alert_bot' | false
- 'support_bot' | false
- 'security_bot' | false
- 'automation_bot' | false
+ 'human' | true
+ 'alert_bot' | false
+ 'support_bot' | false
+ 'security_bot' | false
+ 'automation_bot' | false
+ 'admin_bot' | false
end
with_them do
@@ -7034,17 +7072,26 @@ RSpec.describe User do
it_behaves_like 'bot users', :security_bot
it_behaves_like 'bot users', :ghost
it_behaves_like 'bot users', :automation_bot
+ it_behaves_like 'bot users', :admin_bot
it_behaves_like 'bot user avatars', :alert_bot, 'alert-bot.png'
it_behaves_like 'bot user avatars', :support_bot, 'support-bot.png'
it_behaves_like 'bot user avatars', :security_bot, 'security-bot.png'
it_behaves_like 'bot user avatars', :automation_bot, 'support-bot.png'
+ it_behaves_like 'bot user avatars', :admin_bot, 'admin-bot.png'
context 'when bot is the support_bot' do
subject { described_class.support_bot }
it { is_expected.to be_confirmed }
end
+
+ context 'when bot is the admin bot' do
+ subject { described_class.admin_bot }
+
+ it { is_expected.to be_admin }
+ it { is_expected.to be_confirmed }
+ end
end
describe '#confirmation_required_on_sign_in?' do
@@ -7307,4 +7354,51 @@ RSpec.describe User do
expect(user.account_age_in_days).to be(1)
end
end
+
+ describe 'state machine and default attributes' do
+ let(:model) do
+ Class.new(ApplicationRecord) do
+ self.table_name = User.table_name
+
+ attribute :external, default: -> { 1 / 0 }
+
+ state_machine :state, initial: :active do
+ end
+ end
+ end
+
+ it 'raises errors by default' do
+ expect { model }.to raise_error(ZeroDivisionError)
+ end
+
+ context 'with state machine default attributes override' do
+ let(:model) do
+ Class.new(ApplicationRecord) do
+ self.table_name = User.table_name
+
+ attribute :external, default: -> { 1 / 0 }
+
+ state_machine :state, initial: :active do
+ def owner_class_attribute_default; end
+ end
+ end
+ end
+
+ it 'does not raise errors' do
+ expect { model }.not_to raise_error
+ end
+
+ it 'raises errors when default attributes are used' do
+ expect { model.new.attributes }.to raise_error(ZeroDivisionError)
+ end
+
+ it 'does not evaluate default attributes when values are provided' do
+ expect { model.new(external: false).attributes }.not_to raise_error
+ end
+
+ it 'sets the state machine default value' do
+ expect(model.new(external: true).state).to eq('active')
+ end
+ end
+ end
end