user_spec.rb 105.9 KB
Newer Older
G
gitlabhq 已提交
1 2
require 'spec_helper'

3
describe User do
B
Bob Van Landuyt 已提交
4
  include ProjectForksHelper
5
  include TermsHelper
6

S
Shinya Maeda 已提交
7
  it_behaves_like 'having unique enum values'
S
Shinya Maeda 已提交
8

9 10 11 12 13 14 15
  describe 'modules' do
    subject { described_class }

    it { is_expected.to include_module(Gitlab::ConfigHelper) }
    it { is_expected.to include_module(Referable) }
    it { is_expected.to include_module(Sortable) }
    it { is_expected.to include_module(TokenAuthenticatable) }
16
    it { is_expected.to include_module(BlocksJsonSerialization) }
17 18
  end

19 20 21 22
  describe 'delegations' do
    it { is_expected.to delegate_method(:path).to(:namespace).with_prefix }
  end

23
  describe 'associations' do
24
    it { is_expected.to have_one(:namespace) }
B
Bob Van Landuyt 已提交
25
    it { is_expected.to have_one(:status) }
26
    it { is_expected.to have_many(:snippets).dependent(:destroy) }
27 28 29
    it { is_expected.to have_many(:members) }
    it { is_expected.to have_many(:project_members) }
    it { is_expected.to have_many(:group_members) }
30 31
    it { is_expected.to have_many(:groups) }
    it { is_expected.to have_many(:keys).dependent(:destroy) }
32
    it { is_expected.to have_many(:deploy_keys).dependent(:nullify) }
33
    it { is_expected.to have_many(:events).dependent(:destroy) }
34
    it { is_expected.to have_many(:issues).dependent(:destroy) }
35 36 37
    it { is_expected.to have_many(:notes).dependent(:destroy) }
    it { is_expected.to have_many(:merge_requests).dependent(:destroy) }
    it { is_expected.to have_many(:identities).dependent(:destroy) }
38
    it { is_expected.to have_many(:spam_logs).dependent(:destroy) }
39
    it { is_expected.to have_many(:todos) }
40
    it { is_expected.to have_many(:award_emoji).dependent(:destroy) }
K
Kamil Trzcinski 已提交
41
    it { is_expected.to have_many(:triggers).dependent(:destroy) }
42 43
    it { is_expected.to have_many(:builds).dependent(:nullify) }
    it { is_expected.to have_many(:pipelines).dependent(:nullify) }
K
Kamil Trzcinski 已提交
44
    it { is_expected.to have_many(:chat_names).dependent(:destroy) }
J
Jan Provaznik 已提交
45
    it { is_expected.to have_many(:uploads) }
46
    it { is_expected.to have_many(:reported_abuse_reports).dependent(:destroy).class_name('AbuseReport') }
47
    it { is_expected.to have_many(:custom_attributes).class_name('UserCustomAttribute') }
48
    it { is_expected.to have_many(:releases).dependent(:nullify) }
49

50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75
    describe "#abuse_report" do
      let(:current_user) { create(:user) }
      let(:other_user) { create(:user) }

      it { is_expected.to have_one(:abuse_report) }

      it "refers to the abuse report whose user_id is the current user" do
        abuse_report = create(:abuse_report, reporter: other_user, user: current_user)

        expect(current_user.abuse_report).to eq(abuse_report)
      end

      it "does not refer to the abuse report whose reporter_id is the current user" do
        create(:abuse_report, reporter: current_user, user: other_user)

        expect(current_user.abuse_report).to be_nil
      end

      it "does not update the user_id of an abuse report when the user is updated" do
        abuse_report = create(:abuse_report, reporter: current_user, user: other_user)

        current_user.block

        expect(abuse_report.reload.user).to eq(other_user)
      end
    end
76 77 78 79

    describe '#group_members' do
      it 'does not include group memberships for which user is a requester' do
        user = create(:user)
80
        group = create(:group, :public, :access_requestable)
81 82 83 84 85 86 87 88 89
        group.request_access(user)

        expect(user.group_members).to be_empty
      end
    end

    describe '#project_members' do
      it 'does not include project memberships for which user is a requester' do
        user = create(:user)
90
        project = create(:project, :public, :access_requestable)
91 92 93 94 95
        project.request_access(user)

        expect(user.project_members).to be_empty
      end
    end
96 97 98
  end

  describe 'validations' do
R
Robert Speicher 已提交
99 100 101 102 103 104 105 106 107
    describe 'username' do
      it 'validates presence' do
        expect(subject).to validate_presence_of(:username)
      end

      it 'rejects blacklisted names' do
        user = build(:user, username: 'dashboard')

        expect(user).not_to be_valid
108
        expect(user.errors.messages[:username]).to eq ['dashboard is a reserved name']
R
Robert Speicher 已提交
109 110
      end

111 112 113 114 115 116 117 118 119 120 121 122
      it 'allows child names' do
        user = build(:user, username: 'avatar')

        expect(user).to be_valid
      end

      it 'allows wildcard names' do
        user = build(:user, username: 'blob')

        expect(user).to be_valid
      end

123 124 125 126 127 128 129 130 131 132
      context 'when username is changed' do
        let(:user) { build_stubbed(:user, username: 'old_path', namespace: build_stubbed(:namespace)) }

        it 'validates move_dir is allowed for the namespace' do
          expect(user.namespace).to receive(:any_project_has_container_registry_tags?).and_return(true)
          user.username = 'new_path'
          expect(user).to be_invalid
          expect(user.errors.messages[:username].first).to match('cannot be changed if a personal project has container registry tags')
        end
      end
133

134 135 136 137 138 139 140 141 142
      context 'when the username is in use by another user' do
        let(:username) { 'foo' }
        let!(:other_user) { create(:user, username: username) }

        it 'is invalid' do
          user = build(:user, username: username)

          expect(user).not_to be_valid
          expect(user.errors.full_messages).to eq(['Username has already been taken'])
143 144
        end
      end
R
Robert Speicher 已提交
145 146
    end

147 148 149 150 151 152 153 154 155 156
    it 'has a DB-level NOT NULL constraint on projects_limit' do
      user = create(:user)

      expect(user.persisted?).to eq(true)

      expect do
        user.update_columns(projects_limit: nil)
      end.to raise_error(ActiveRecord::StatementInvalid)
    end

157 158 159 160
    it { is_expected.to validate_presence_of(:projects_limit) }
    it { is_expected.to validate_numericality_of(:projects_limit) }
    it { is_expected.to allow_value(0).for(:projects_limit) }
    it { is_expected.not_to allow_value(-1).for(:projects_limit) }
161
    it { is_expected.not_to allow_value(Gitlab::Database::MAX_INT_VALUE + 1).for(:projects_limit) }
162

163
    it { is_expected.to validate_length_of(:bio).is_at_most(255) }
164

165 166 167
    it_behaves_like 'an object with email-formated attributes', :email do
      subject { build(:user) }
    end
168

169 170 171
    it_behaves_like 'an object with email-formated attributes', :public_email, :notification_email do
      subject { build(:user).tap { |user| user.emails << build(:email, email: email_value) } }
    end
172

173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188
    describe '#commit_email' do
      subject(:user) { create(:user) }

      it 'defaults to the primary email' do
        expect(user.email).to be_present
        expect(user.commit_email).to eq(user.email)
      end

      it 'defaults to the primary email when the column in the database is null' do
        user.update_column(:commit_email, nil)

        found_user = described_class.find_by(id: user.id)

        expect(found_user.commit_email).to eq(user.email)
      end

189 190 191 192 193 194
      it 'returns the private commit email when commit_email has _private' do
        user.update_column(:commit_email, Gitlab::PrivateCommitEmail::TOKEN)

        expect(user.commit_email).to eq(user.private_commit_email)
      end

195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227
      it 'can be set to a confirmed email' do
        confirmed = create(:email, :confirmed, user: user)
        user.commit_email = confirmed.email

        expect(user).to be_valid
        expect(user.commit_email).to eq(confirmed.email)
      end

      it 'can not be set to an unconfirmed email' do
        unconfirmed = create(:email, user: user)
        user.commit_email = unconfirmed.email

        # This should set the commit_email attribute to the primary email
        expect(user).to be_valid
        expect(user.commit_email).to eq(user.email)
      end

      it 'can not be set to a non-existent email' do
        user.commit_email = 'non-existent-email@nonexistent.nonexistent'

        # This should set the commit_email attribute to the primary email
        expect(user).to be_valid
        expect(user.commit_email).to eq(user.email)
      end

      it 'can not be set to an invalid email, even if confirmed' do
        confirmed = create(:email, :confirmed, :skip_validate, user: user, email: 'invalid')
        user.commit_email = confirmed.email

        expect(user).not_to be_valid
      end
    end

228
    describe 'email' do
229
      context 'when no signup domains whitelisted' do
230
        before do
231
          allow_any_instance_of(ApplicationSetting).to receive(:domain_whitelist).and_return([])
232
        end
233

234 235 236 237 238 239
        it 'accepts any email' do
          user = build(:user, email: "info@example.com")
          expect(user).to be_valid
        end
      end

240
      context 'when a signup domain is whitelisted and subdomains are allowed' do
241
        before do
242
          allow_any_instance_of(ApplicationSetting).to receive(:domain_whitelist).and_return(['example.com', '*.example.com'])
243
        end
244

245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260
        it 'accepts info@example.com' do
          user = build(:user, email: "info@example.com")
          expect(user).to be_valid
        end

        it 'accepts info@test.example.com' do
          user = build(:user, email: "info@test.example.com")
          expect(user).to be_valid
        end

        it 'rejects example@test.com' do
          user = build(:user, email: "example@test.com")
          expect(user).to be_invalid
        end
      end

261
      context 'when a signup domain is whitelisted and subdomains are not allowed' do
262
        before do
263
          allow_any_instance_of(ApplicationSetting).to receive(:domain_whitelist).and_return(['example.com'])
264
        end
265 266 267 268 269 270 271 272 273 274 275 276 277 278 279

        it 'accepts info@example.com' do
          user = build(:user, email: "info@example.com")
          expect(user).to be_valid
        end

        it 'rejects info@test.example.com' do
          user = build(:user, email: "info@test.example.com")
          expect(user).to be_invalid
        end

        it 'rejects example@test.com' do
          user = build(:user, email: "example@test.com")
          expect(user).to be_invalid
        end
280 281 282 283 284

        it 'accepts example@test.com when added by another user' do
          user = build(:user, email: "example@test.com", created_by_id: 1)
          expect(user).to be_valid
        end
285
      end
286

287 288 289 290 291 292
      context 'domain blacklist' do
        before do
          allow_any_instance_of(ApplicationSetting).to receive(:domain_blacklist_enabled?).and_return(true)
          allow_any_instance_of(ApplicationSetting).to receive(:domain_blacklist).and_return(['example.com'])
        end

293
        context 'when a signup domain is blacklisted' do
294 295 296 297 298 299 300 301 302
          it 'accepts info@test.com' do
            user = build(:user, email: 'info@test.com')
            expect(user).to be_valid
          end

          it 'rejects info@example.com' do
            user = build(:user, email: 'info@example.com')
            expect(user).not_to be_valid
          end
303 304 305 306 307

          it 'accepts info@example.com when added by another user' do
            user = build(:user, email: 'info@example.com', created_by_id: 1)
            expect(user).to be_valid
          end
308 309
        end

310
        context 'when a signup domain is blacklisted but a wildcard subdomain is allowed' do
311 312
          before do
            allow_any_instance_of(ApplicationSetting).to receive(:domain_blacklist).and_return(['test.example.com'])
313
            allow_any_instance_of(ApplicationSetting).to receive(:domain_whitelist).and_return(['*.example.com'])
314 315
          end

316
          it 'gives priority to whitelist and allow info@test.example.com' do
317 318 319 320 321 322 323
            user = build(:user, email: 'info@test.example.com')
            expect(user).to be_valid
          end
        end

        context 'with both lists containing a domain' do
          before do
324
            allow_any_instance_of(ApplicationSetting).to receive(:domain_whitelist).and_return(['test.com'])
325 326 327 328 329 330 331 332 333 334 335 336 337 338
          end

          it 'accepts info@test.com' do
            user = build(:user, email: 'info@test.com')
            expect(user).to be_valid
          end

          it 'rejects info@example.com' do
            user = build(:user, email: 'info@example.com')
            expect(user).not_to be_valid
          end
        end
      end

339 340 341 342 343 344
      context 'owns_notification_email' do
        it 'accepts temp_oauth_email emails' do
          user = build(:user, email: "temp-email-for-oauth@example.com")
          expect(user).to be_valid
        end
      end
345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378

      context 'set_commit_email' do
        it 'keeps commit email when private commit email is being used' do
          user = create(:user, commit_email: Gitlab::PrivateCommitEmail::TOKEN)

          expect(user.read_attribute(:commit_email)).to eq(Gitlab::PrivateCommitEmail::TOKEN)
        end

        it 'keeps the commit email when nil' do
          user = create(:user, commit_email: nil)

          expect(user.read_attribute(:commit_email)).to be_nil
        end

        it 'reverts to nil when email is not verified' do
          user = create(:user, commit_email: "foo@bar.com")

          expect(user.read_attribute(:commit_email)).to be_nil
        end
      end

      context 'owns_commit_email' do
        it 'accepts private commit email' do
          user = build(:user, commit_email: Gitlab::PrivateCommitEmail::TOKEN)

          expect(user).to be_valid
        end

        it 'accepts nil commit email' do
          user = build(:user, commit_email: nil)

          expect(user).to be_valid
        end
      end
379
    end
380 381 382 383 384 385 386
  end

  describe "scopes" do
    describe ".with_two_factor" do
      it "returns users with 2fa enabled via OTP" do
        user_with_2fa = create(:user, :two_factor_via_otp)
        user_without_2fa = create(:user)
387
        users_with_two_factor = described_class.with_two_factor.pluck(:id)
388 389 390 391 392 393 394 395

        expect(users_with_two_factor).to include(user_with_2fa.id)
        expect(users_with_two_factor).not_to include(user_without_2fa.id)
      end

      it "returns users with 2fa enabled via U2F" do
        user_with_2fa = create(:user, :two_factor_via_u2f)
        user_without_2fa = create(:user)
396
        users_with_two_factor = described_class.with_two_factor.pluck(:id)
397 398 399 400 401 402 403 404

        expect(users_with_two_factor).to include(user_with_2fa.id)
        expect(users_with_two_factor).not_to include(user_without_2fa.id)
      end

      it "returns users with 2fa enabled via OTP and U2F" do
        user_with_2fa = create(:user, :two_factor_via_otp, :two_factor_via_u2f)
        user_without_2fa = create(:user)
405
        users_with_two_factor = described_class.with_two_factor.pluck(:id)
406 407 408 409

        expect(users_with_two_factor).to eq([user_with_2fa.id])
        expect(users_with_two_factor).not_to include(user_without_2fa.id)
      end
410 411 412 413 414 415 416 417

      it 'works with ORDER BY' do
        user_with_2fa = create(:user, :two_factor_via_otp, :two_factor_via_u2f)

        expect(described_class
          .with_two_factor
          .reorder_by_name).to eq([user_with_2fa])
      end
418 419 420 421 422 423
    end

    describe ".without_two_factor" do
      it "excludes users with 2fa enabled via OTP" do
        user_with_2fa = create(:user, :two_factor_via_otp)
        user_without_2fa = create(:user)
424
        users_without_two_factor = described_class.without_two_factor.pluck(:id)
425 426 427 428 429 430 431 432

        expect(users_without_two_factor).to include(user_without_2fa.id)
        expect(users_without_two_factor).not_to include(user_with_2fa.id)
      end

      it "excludes users with 2fa enabled via U2F" do
        user_with_2fa = create(:user, :two_factor_via_u2f)
        user_without_2fa = create(:user)
433
        users_without_two_factor = described_class.without_two_factor.pluck(:id)
434 435 436 437 438 439 440 441

        expect(users_without_two_factor).to include(user_without_2fa.id)
        expect(users_without_two_factor).not_to include(user_with_2fa.id)
      end

      it "excludes users with 2fa enabled via OTP and U2F" do
        user_with_2fa = create(:user, :two_factor_via_otp, :two_factor_via_u2f)
        user_without_2fa = create(:user)
442
        users_without_two_factor = described_class.without_two_factor.pluck(:id)
443 444 445 446 447

        expect(users_without_two_factor).to include(user_without_2fa.id)
        expect(users_without_two_factor).not_to include(user_with_2fa.id)
      end
    end
V
Valery Sizov 已提交
448

Y
Yorick Peterse 已提交
449 450 451 452
    describe '.limit_to_todo_authors' do
      context 'when filtering by todo authors' do
        let(:user1) { create(:user) }
        let(:user2) { create(:user) }
V
Valery Sizov 已提交
453

Y
Yorick Peterse 已提交
454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497
        before do
          create(:todo, user: user1, author: user1, state: :done)
          create(:todo, user: user2, author: user2, state: :pending)
        end

        it 'only returns users that have authored todos' do
          users = described_class.limit_to_todo_authors(
            user: user2,
            with_todos: true,
            todo_state: :pending
          )

          expect(users).to eq([user2])
        end

        it 'ignores users that do not have a todo in the matching state' do
          users = described_class.limit_to_todo_authors(
            user: user1,
            with_todos: true,
            todo_state: :pending
          )

          expect(users).to be_empty
        end
      end

      context 'when not filtering by todo authors' do
        it 'returns the input relation' do
          user1 = create(:user)
          user2 = create(:user)
          rel = described_class.limit_to_todo_authors(user: user1)

          expect(rel).to include(user1, user2)
        end
      end

      context 'when no user is provided' do
        it 'returns the input relation' do
          user1 = create(:user)
          user2 = create(:user)
          rel = described_class.limit_to_todo_authors

          expect(rel).to include(user1, user2)
        end
V
Valery Sizov 已提交
498 499
      end
    end
500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516

    describe '.by_username' do
      it 'finds users regardless of the case passed' do
        user = create(:user, username: 'CaMeLcAsEd')
        user2 = create(:user, username: 'UPPERCASE')

        expect(described_class.by_username(%w(CAMELCASED uppercase)))
          .to contain_exactly(user, user2)
      end

      it 'finds a single user regardless of the case passed' do
        user = create(:user, username: 'CaMeLcAsEd')

        expect(described_class.by_username('CAMELCASED'))
          .to contain_exactly(user)
      end
    end
G
gitlabhq 已提交
517 518 519
  end

  describe "Respond to" do
B
blackst0ne 已提交
520
    it { is_expected.to respond_to(:admin?) }
521
    it { is_expected.to respond_to(:name) }
Z
Zeger-Jan van de Weg 已提交
522 523 524 525 526 527 528 529 530 531 532 533 534 535
    it { is_expected.to respond_to(:external?) }
  end

  describe 'before save hook' do
    context 'when saving an external user' do
      let(:user)          { create(:user) }
      let(:external_user) { create(:user, external: true) }

      it "sets other properties aswell" do
        expect(external_user.can_create_team).to be_falsey
        expect(external_user.can_create_group).to be_falsey
        expect(external_user.projects_limit).to be 0
      end
    end
536

537 538
    describe '#check_for_verified_email' do
      let(:user)      { create(:user) }
539 540
      let(:secondary) { create(:email, :confirmed, email: 'secondary@example.com', user: user) }

541
      it 'allows a verfied secondary email to be used as the primary without needing reconfirmation' do
L
Lin Jen-Shin 已提交
542
        user.update!(email: secondary.email)
543 544 545 546 547 548
        user.reload
        expect(user.email).to eq secondary.email
        expect(user.unconfirmed_email).to eq nil
        expect(user.confirmed?).to be_truthy
      end
    end
G
gitlabhq 已提交
549 550
  end

551
  describe 'after commit hook' do
552 553 554 555 556 557 558 559 560 561 562
    describe '#update_emails_with_primary_email' do
      before do
        @user = create(:user, email: 'primary@example.com').tap do |user|
          user.skip_reconfirmation!
        end
        @secondary = create :email, email: 'secondary@example.com', user: @user
        @user.reload
      end

      it 'gets called when email updated' do
        expect(@user).to receive(:update_emails_with_primary_email)
563

L
Lin Jen-Shin 已提交
564
        @user.update!(email: 'new_primary@example.com')
565 566
      end

567
      it 'adds old primary to secondary emails when secondary is a new email ' do
L
Lin Jen-Shin 已提交
568
        @user.update!(email: 'new_primary@example.com')
569
        @user.reload
570

571 572
        expect(@user.emails.count).to eq 2
        expect(@user.emails.pluck(:email)).to match_array([@secondary.email, 'primary@example.com'])
573 574 575
      end

      it 'adds old primary to secondary emails if secondary is becoming a primary' do
L
Lin Jen-Shin 已提交
576
        @user.update!(email: @secondary.email)
577
        @user.reload
578

579 580 581 582 583
        expect(@user.emails.count).to eq 1
        expect(@user.emails.first.email).to eq 'primary@example.com'
      end

      it 'transfers old confirmation values into new secondary' do
L
Lin Jen-Shin 已提交
584
        @user.update!(email: @secondary.email)
585
        @user.reload
586

587 588 589 590
        expect(@user.emails.count).to eq 1
        expect(@user.emails.first.confirmed_at).not_to eq nil
      end
    end
591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652

    describe '#update_notification_email' do
      # Regression: https://gitlab.com/gitlab-org/gitlab-ce/issues/22846
      context 'when changing :email' do
        let(:user) { create(:user) }
        let(:new_email) { 'new-email@example.com' }

        it 'sets :unconfirmed_email' do
          expect do
            user.tap { |u| u.update!(email: new_email) }.reload
          end.to change(user, :unconfirmed_email).to(new_email)
        end

        it 'does not change :notification_email' do
          expect do
            user.tap { |u| u.update!(email: new_email) }.reload
          end.not_to change(user, :notification_email)
        end

        it 'updates :notification_email to the new email once confirmed' do
          user.update!(email: new_email)

          expect do
            user.tap(&:confirm).reload
          end.to change(user, :notification_email).to eq(new_email)
        end

        context 'and :notification_email is set to a secondary email' do
          let!(:email_attrs) { attributes_for(:email, :confirmed, user: user) }
          let(:secondary) { create(:email, :confirmed, email: 'secondary@example.com', user: user) }

          before do
            user.emails.create(email_attrs)
            user.tap { |u| u.update!(notification_email: email_attrs[:email]) }.reload
          end

          it 'does not change :notification_email to :email' do
            expect do
              user.tap { |u| u.update!(email: new_email) }.reload
            end.not_to change(user, :notification_email)
          end

          it 'does not change :notification_email to :email once confirmed' do
            user.update!(email: new_email)

            expect do
              user.tap(&:confirm).reload
            end.not_to change(user, :notification_email)
          end
        end
      end
    end

    describe '#update_invalid_gpg_signatures' do
      let(:user) do
        create(:user, email: 'tula.torphy@abshire.ca').tap do |user|
          user.skip_reconfirmation!
        end
      end

      it 'does nothing when the name is updated' do
        expect(user).not_to receive(:update_invalid_gpg_signatures)
L
Lin Jen-Shin 已提交
653
        user.update!(name: 'Bette')
654 655 656 657
      end

      it 'synchronizes the gpg keys when the email is updated' do
        expect(user).to receive(:update_invalid_gpg_signatures).at_most(:twice)
L
Lin Jen-Shin 已提交
658
        user.update!(email: 'shawnee.ritchie@denesik.com')
659 660
      end
    end
661 662
  end

663
  describe '#update_tracked_fields!', :clean_gitlab_redis_shared_state do
664 665 666 667 668 669 670 671 672 673 674 675 676 677
    let(:request) { OpenStruct.new(remote_ip: "127.0.0.1") }
    let(:user) { create(:user) }

    it 'writes trackable attributes' do
      expect do
        user.update_tracked_fields!(request)
      end.to change { user.reload.current_sign_in_at }
    end

    it 'does not write trackable attributes when called a second time within the hour' do
      user.update_tracked_fields!(request)

      expect do
        user.update_tracked_fields!(request)
678 679 680 681 682 683 684 685 686 687 688
      end.not_to change { user.reload.current_sign_in_at }
    end

    it 'writes trackable attributes for a different user' do
      user2 = create(:user)

      user.update_tracked_fields!(request)

      expect do
        user2.update_tracked_fields!(request)
      end.to change { user2.reload.current_sign_in_at }
689
    end
690 691 692 693 694 695 696 697

    it 'does not write if the DB is in read-only mode' do
      expect(Gitlab::Database).to receive(:read_only?).and_return(true)

      expect do
        user.update_tracked_fields!(request)
      end.not_to change { user.reload.current_sign_in_at }
    end
698 699
  end

700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727
  shared_context 'user keys' do
    let(:user) { create(:user) }
    let!(:key) { create(:key, user: user) }
    let!(:deploy_key) { create(:deploy_key, user: user) }
  end

  describe '#keys' do
    include_context 'user keys'

    context 'with key and deploy key stored' do
      it 'returns stored key, but not deploy_key' do
        expect(user.keys).to include key
        expect(user.keys).not_to include deploy_key
      end
    end
  end

  describe '#deploy_keys' do
    include_context 'user keys'

    context 'with key and deploy key stored' do
      it 'returns stored deploy key, but not normal key' do
        expect(user.deploy_keys).to include deploy_key
        expect(user.deploy_keys).not_to include key
      end
    end
  end

728
  describe '#confirm' do
729 730 731
    before do
      allow_any_instance_of(ApplicationSetting).to receive(:send_user_confirmation_email).and_return(true)
    end
732

733 734 735 736 737 738 739
    let(:user) { create(:user, confirmed_at: nil, unconfirmed_email: 'test@gitlab.com') }

    it 'returns unconfirmed' do
      expect(user.confirmed?).to be_falsey
    end

    it 'confirms a user' do
740
      user.confirm
741 742 743 744
      expect(user.confirmed?).to be_truthy
    end
  end

745 746 747 748 749 750 751 752
  describe '#to_reference' do
    let(:user) { create(:user) }

    it 'returns a String reference to the object' do
      expect(user.to_reference).to eq "@#{user.username}"
    end
  end

753
  describe '#generate_password' do
754
    it "does not generate password by default" do
755
      user = create(:user, password: 'abcdefghe')
756

757
      expect(user.password).to eq('abcdefghe')
758
    end
759 760
  end

761 762 763 764 765 766 767 768 769
  describe 'ensure user preference' do
    it 'has user preference upon user initialization' do
      user = build(:user)

      expect(user.user_preference).to be_present
      expect(user.user_preference).not_to be_persisted
    end
  end

770 771 772
  describe 'ensure incoming email token' do
    it 'has incoming email token' do
      user = create(:user)
773

774 775
      expect(user.incoming_email_token).not_to be_blank
    end
776 777 778 779 780 781 782 783

    it 'uses SecureRandom to generate the incoming email token' do
      expect(SecureRandom).to receive(:hex).and_return('3b8ca303')

      user = create(:user)

      expect(user.incoming_email_token).to eql('gitlab')
    end
784 785
  end

786 787 788 789 790 791 792
  describe '#ensure_user_rights_and_limits' do
    describe 'with external user' do
      let(:user) { create(:user, external: true) }

      it 'receives callback when external changes' do
        expect(user).to receive(:ensure_user_rights_and_limits)

L
Lin Jen-Shin 已提交
793
        user.update(external: false)
794 795 796
      end

      it 'ensures correct rights and limits for user' do
T
Tiago Botelho 已提交
797 798
        stub_config_setting(default_can_create_group: true)

L
Lin Jen-Shin 已提交
799
        expect { user.update(external: false) }.to change { user.can_create_group }.to(true)
800
          .and change { user.projects_limit }.to(Gitlab::CurrentSettings.default_projects_limit)
801 802 803 804 805 806 807 808 809
      end
    end

    describe 'without external user' do
      let(:user) { create(:user, external: false) }

      it 'receives callback when external changes' do
        expect(user).to receive(:ensure_user_rights_and_limits)

L
Lin Jen-Shin 已提交
810
        user.update(external: true)
811 812 813
      end

      it 'ensures correct rights and limits for user' do
L
Lin Jen-Shin 已提交
814
        expect { user.update(external: true) }.to change { user.can_create_group }.to(false)
815 816 817 818 819
          .and change { user.projects_limit }.to(0)
      end
    end
  end

820 821 822 823
  describe 'feed token' do
    it 'ensures a feed token on read' do
      user = create(:user, feed_token: nil)
      feed_token = user.feed_token
824

825 826
      expect(feed_token).not_to be_blank
      expect(user.reload.feed_token).to eq feed_token
827 828 829
    end
  end

830
  describe '#recently_sent_password_reset?' do
831 832 833 834 835 836 837 838 839 840 841 842 843 844 845 846 847 848 849
    it 'is false when reset_password_sent_at is nil' do
      user = build_stubbed(:user, reset_password_sent_at: nil)

      expect(user.recently_sent_password_reset?).to eq false
    end

    it 'is false when sent more than one minute ago' do
      user = build_stubbed(:user, reset_password_sent_at: 5.minutes.ago)

      expect(user.recently_sent_password_reset?).to eq false
    end

    it 'is true when sent less than one minute ago' do
      user = build_stubbed(:user, reset_password_sent_at: Time.now)

      expect(user.recently_sent_password_reset?).to eq true
    end
  end

R
Robert Speicher 已提交
850 851 852 853 854 855 856
  describe '#disable_two_factor!' do
    it 'clears all 2FA-related fields' do
      user = create(:user, :two_factor)

      expect(user).to be_two_factor_enabled
      expect(user.encrypted_otp_secret).not_to be_nil
      expect(user.otp_backup_codes).not_to be_nil
857
      expect(user.otp_grace_period_started_at).not_to be_nil
R
Robert Speicher 已提交
858 859 860 861 862 863 864 865

      user.disable_two_factor!

      expect(user).not_to be_two_factor_enabled
      expect(user.encrypted_otp_secret).to be_nil
      expect(user.encrypted_otp_secret_iv).to be_nil
      expect(user.encrypted_otp_secret_salt).to be_nil
      expect(user.otp_backup_codes).to be_nil
866
      expect(user.otp_grace_period_started_at).to be_nil
R
Robert Speicher 已提交
867 868 869
    end
  end

870 871
  describe 'projects' do
    before do
872
      @user = create(:user)
873

874 875
      @project = create(:project, namespace: @user.namespace)
      @project_2 = create(:project, group: create(:group)) do |project|
876
        project.add_maintainer(@user)
877
      end
878
      @project_3 = create(:project, group: create(:group)) do |project|
879 880
        project.add_developer(@user)
      end
881 882
    end

883 884 885 886 887 888 889 890 891
    it { expect(@user.authorized_projects).to include(@project) }
    it { expect(@user.authorized_projects).to include(@project_2) }
    it { expect(@user.authorized_projects).to include(@project_3) }
    it { expect(@user.owned_projects).to include(@project) }
    it { expect(@user.owned_projects).not_to include(@project_2) }
    it { expect(@user.owned_projects).not_to include(@project_3) }
    it { expect(@user.personal_projects).to include(@project) }
    it { expect(@user.personal_projects).not_to include(@project_2) }
    it { expect(@user.personal_projects).not_to include(@project_3) }
892 893 894
  end

  describe 'groups' do
895 896 897
    let(:user) { create(:user) }
    let(:group) { create(:group) }

898
    before do
899
      group.add_owner(user)
900 901
    end

902 903 904 905 906 907 908 909 910 911 912 913 914 915 916 917 918 919 920 921 922 923 924 925 926 927
    it { expect(user.several_namespaces?).to be_truthy }
    it { expect(user.authorized_groups).to eq([group]) }
    it { expect(user.owned_groups).to eq([group]) }
    it { expect(user.namespaces).to contain_exactly(user.namespace, group) }
    it { expect(user.manageable_namespaces).to contain_exactly(user.namespace, group) }

    context 'with child groups', :nested_groups do
      let!(:subgroup) { create(:group, parent: group) }

      describe '#manageable_namespaces' do
        it 'includes all the namespaces the user can manage' do
          expect(user.manageable_namespaces).to contain_exactly(user.namespace, group, subgroup)
        end
      end

      describe '#manageable_groups' do
        it 'includes all the namespaces the user can manage' do
          expect(user.manageable_groups).to contain_exactly(group, subgroup)
        end

        it 'does not include duplicates if a membership was added for the subgroup' do
          subgroup.add_owner(user)

          expect(user.manageable_groups).to contain_exactly(group, subgroup)
        end
      end
928 929 930 931 932 933 934 935 936 937 938 939 940 941 942

      describe '#manageable_groups_with_routes' do
        it 'eager loads routes from manageable groups' do
          control_count =
            ActiveRecord::QueryRecorder.new(skip_cached: false) do
              user.manageable_groups_with_routes.map(&:route)
            end.count

          create(:group, parent: subgroup)

          expect do
            user.manageable_groups_with_routes.map(&:route)
          end.not_to exceed_all_query_limit(control_count)
        end
      end
943
    end
944 945
  end

946 947 948 949
  describe 'group multiple owners' do
    before do
      @user = create :user
      @user2 = create :user
950 951
      @group = create :group
      @group.add_owner(@user)
952

953
      @group.add_user(@user2, GroupMember::OWNER)
954 955
    end

956
    it { expect(@user2.several_namespaces?).to be_truthy }
957 958
  end

959 960 961
  describe 'namespaced' do
    before do
      @user = create :user
962
      @project = create(:project, namespace: @user.namespace)
963 964
    end

965
    it { expect(@user.several_namespaces?).to be_falsey }
966
    it { expect(@user.namespaces).to eq([@user.namespace]) }
967 968 969 970 971
  end

  describe 'blocking user' do
    let(:user) { create(:user, name: 'John Smith') }

972
    it "blocks user" do
973
      user.block
974

975
      expect(user.blocked?).to be_truthy
976 977 978
    end
  end

979
  describe '.filter_items' do
980 981 982
    let(:user) { double }

    it 'filters by active users by default' do
983
      expect(described_class).to receive(:active).and_return([user])
984

985
      expect(described_class.filter_items(nil)).to include user
986 987
    end

988
    it 'filters by admins' do
989
      expect(described_class).to receive(:admins).and_return([user])
990

991
      expect(described_class.filter_items('admins')).to include user
992 993
    end

994
    it 'filters by blocked' do
995
      expect(described_class).to receive(:blocked).and_return([user])
996

997
      expect(described_class.filter_items('blocked')).to include user
998 999 1000
    end

    it 'filters by two_factor_disabled' do
1001
      expect(described_class).to receive(:without_two_factor).and_return([user])
1002

1003
      expect(described_class.filter_items('two_factor_disabled')).to include user
1004 1005 1006
    end

    it 'filters by two_factor_enabled' do
1007
      expect(described_class).to receive(:with_two_factor).and_return([user])
1008

1009
      expect(described_class.filter_items('two_factor_enabled')).to include user
1010 1011 1012
    end

    it 'filters by wop' do
1013
      expect(described_class).to receive(:without_projects).and_return([user])
1014

1015
      expect(described_class.filter_items('wop')).to include user
1016
    end
1017 1018
  end

B
Ben Bodenmiller 已提交
1019
  describe '.without_projects' do
1020
    let!(:project) { create(:project, :public, :access_requestable) }
B
Ben Bodenmiller 已提交
1021 1022 1023 1024 1025 1026
    let!(:user) { create(:user) }
    let!(:user_without_project) { create(:user) }
    let!(:user_without_project2) { create(:user) }

    before do
      # add user to project
1027
      project.add_maintainer(user)
B
Ben Bodenmiller 已提交
1028 1029 1030 1031 1032 1033 1034 1035

      # create invite to projet
      create(:project_member, :developer, project: project, invite_token: '1234', invite_email: 'inviteduser1@example.com')

      # create request to join project
      project.request_access(user_without_project2)
    end

1036 1037 1038
    it { expect(described_class.without_projects).not_to include user }
    it { expect(described_class.without_projects).to include user_without_project }
    it { expect(described_class.without_projects).to include user_without_project2 }
B
Ben Bodenmiller 已提交
1039 1040
  end

1041 1042 1043
  describe 'user creation' do
    describe 'normal user' do
      let(:user) { create(:user, name: 'John Smith') }
D
Dmitriy Zaporozhets 已提交
1044

B
blackst0ne 已提交
1045
      it { expect(user.admin?).to be_falsey }
1046 1047 1048 1049
      it { expect(user.require_ssh_key?).to be_truthy }
      it { expect(user.can_create_group?).to be_truthy }
      it { expect(user.can_create_project?).to be_truthy }
      it { expect(user.first_name).to eq('John') }
1050
      it { expect(user.external).to be_falsey }
1051
    end
1052

D
Dmitriy Zaporozhets 已提交
1053
    describe 'with defaults' do
1054
      let(:user) { described_class.new }
D
Dmitriy Zaporozhets 已提交
1055

1056
      it "applies defaults to user" do
1057 1058
        expect(user.projects_limit).to eq(Gitlab.config.gitlab.default_projects_limit)
        expect(user.can_create_group).to eq(Gitlab.config.gitlab.default_can_create_group)
1059
        expect(user.theme_id).to eq(Gitlab.config.gitlab.default_theme)
Z
Zeger-Jan van de Weg 已提交
1060
        expect(user.external).to be_falsey
1061 1062 1063
      end
    end

D
Dmitriy Zaporozhets 已提交
1064
    describe 'with default overrides' do
1065
      let(:user) { described_class.new(projects_limit: 123, can_create_group: false, can_create_team: true) }
D
Dmitriy Zaporozhets 已提交
1066

1067
      it "applies defaults to user" do
1068 1069
        expect(user.projects_limit).to eq(123)
        expect(user.can_create_group).to be_falsey
1070
        expect(user.theme_id).to eq(1)
1071
      end
1072 1073 1074 1075 1076 1077 1078

      it 'does not undo projects_limit setting if it matches old DB default of 10' do
        # If the real default project limit is 10 then this test is worthless
        expect(Gitlab.config.gitlab.default_projects_limit).not_to eq(10)
        user = described_class.new(projects_limit: 10)
        expect(user.projects_limit).to eq(10)
      end
1079
    end
1080

1081
    context 'when Gitlab::CurrentSettings.user_default_external is true' do
1082 1083 1084 1085 1086
      before do
        stub_application_setting(user_default_external: true)
      end

      it "creates external user by default" do
1087
        user = create(:user)
1088 1089

        expect(user.external).to be_truthy
1090 1091
        expect(user.can_create_group).to be_falsey
        expect(user.projects_limit).to be 0
1092 1093 1094 1095
      end

      describe 'with default overrides' do
        it "creates a non-external user" do
1096
          user = create(:user, external: false)
1097 1098 1099 1100 1101

          expect(user.external).to be_falsey
        end
      end
    end
1102

Y
Yorick Peterse 已提交
1103
    describe '#require_ssh_key?', :use_clean_rails_memory_store_caching do
1104 1105 1106
      protocol_and_expectation = {
        'http' => false,
        'ssh' => true,
1107
        '' => true
1108 1109 1110 1111 1112 1113 1114 1115 1116
      }

      protocol_and_expectation.each do |protocol, expected|
        it "has correct require_ssh_key?" do
          stub_application_setting(enabled_git_access_protocol: protocol)
          user = build(:user)

          expect(user.require_ssh_key?).to eq(expected)
        end
1117
      end
Y
Yorick Peterse 已提交
1118 1119 1120 1121 1122 1123

      it 'returns false when the user has 1 or more SSH keys' do
        key = create(:personal_key)

        expect(key.user.require_ssh_key?).to eq(false)
      end
1124
    end
1125
  end
1126

1127 1128 1129 1130 1131 1132 1133 1134
  describe '.find_for_database_authentication' do
    it 'strips whitespace from login' do
      user = create(:user)

      expect(described_class.find_for_database_authentication({ login: " #{user.username} " })).to eq user
    end
  end

1135
  describe '.find_by_any_email' do
1136 1137 1138 1139 1140 1141 1142 1143
    it 'finds user through private commit email' do
      user = create(:user)
      private_email = user.private_commit_email

      expect(described_class.find_by_any_email(private_email)).to eq(user)
      expect(described_class.find_by_any_email(private_email, confirmed: true)).to eq(user)
    end

1144 1145 1146
    it 'finds by primary email' do
      user = create(:user, email: 'foo@example.com')

1147
      expect(described_class.find_by_any_email(user.email)).to eq user
1148
      expect(described_class.find_by_any_email(user.email, confirmed: true)).to eq user
1149 1150
    end

1151 1152 1153 1154 1155 1156 1157
    it 'finds by uppercased email' do
      user = create(:user, email: 'foo@example.com')

      expect(described_class.find_by_any_email(user.email.upcase)).to eq user
      expect(described_class.find_by_any_email(user.email.upcase, confirmed: true)).to eq user
    end

1158 1159
    context 'finds by secondary email' do
      let(:user) { email.user }
1160

1161 1162 1163 1164 1165 1166 1167 1168 1169 1170 1171 1172 1173 1174 1175 1176 1177 1178 1179 1180 1181 1182 1183 1184 1185 1186 1187 1188 1189
      context 'primary email confirmed' do
        context 'secondary email confirmed' do
          let!(:email) { create(:email, :confirmed, email: 'foo@example.com') }

          it 'finds user respecting the confirmed flag' do
            expect(described_class.find_by_any_email(email.email)).to eq user
            expect(described_class.find_by_any_email(email.email, confirmed: true)).to eq user
          end
        end

        context 'secondary email not confirmed' do
          let!(:email) { create(:email, email: 'foo@example.com') }

          it 'finds user respecting the confirmed flag' do
            expect(described_class.find_by_any_email(email.email)).to eq user
            expect(described_class.find_by_any_email(email.email, confirmed: true)).to be_nil
          end
        end
      end

      context 'primary email not confirmed' do
        let(:user) { create(:user, confirmed_at: nil) }
        let!(:email) { create(:email, :confirmed, user: user, email: 'foo@example.com') }

        it 'finds user respecting the confirmed flag' do
          expect(described_class.find_by_any_email(email.email)).to eq user
          expect(described_class.find_by_any_email(email.email, confirmed: true)).to be_nil
        end
      end
1190 1191 1192
    end

    it 'returns nil when nothing found' do
1193
      expect(described_class.find_by_any_email('')).to be_nil
1194
    end
1195 1196 1197 1198 1199 1200 1201

    it 'returns nil when user is not confirmed' do
      user = create(:user, email: 'foo@example.com', confirmed_at: nil)

      expect(described_class.find_by_any_email(user.email, confirmed: false)).to eq(user)
      expect(described_class.find_by_any_email(user.email, confirmed: true)).to be_nil
    end
1202 1203
  end

Y
Yorick Peterse 已提交
1204 1205 1206 1207 1208 1209 1210 1211 1212 1213 1214
  describe '.by_any_email' do
    it 'returns an ActiveRecord::Relation' do
      expect(described_class.by_any_email('foo@example.com'))
        .to be_a_kind_of(ActiveRecord::Relation)
    end

    it 'returns a relation of users' do
      user = create(:user)

      expect(described_class.by_any_email(user.email)).to eq([user])
    end
1215 1216 1217 1218 1219 1220

    it 'returns a relation of users for confirmed users' do
      user = create(:user)

      expect(described_class.by_any_email(user.email, confirmed: true)).to eq([user])
    end
1221 1222 1223 1224 1225 1226 1227 1228 1229 1230 1231 1232 1233 1234 1235 1236

    it 'finds user through a private commit email' do
      user = create(:user)
      private_email = user.private_commit_email

      expect(described_class.by_any_email(private_email)).to eq([user])
      expect(described_class.by_any_email(private_email, confirmed: true)).to eq([user])
    end

    it 'finds user through a private commit email in an array' do
      user = create(:user)
      private_email = user.private_commit_email

      expect(described_class.by_any_email([private_email])).to eq([user])
      expect(described_class.by_any_email([private_email], confirmed: true)).to eq([user])
    end
Y
Yorick Peterse 已提交
1237 1238
  end

1239
  describe '.search' do
1240 1241
    let!(:user) { create(:user, name: 'user', username: 'usern', email: 'email@gmail.com') }
    let!(:user2) { create(:user, name: 'user name', username: 'username', email: 'someemail@gmail.com') }
1242
    let!(:user3) { create(:user, name: 'us', username: 'se', email: 'foo@gmail.com') }
1243

1244 1245 1246 1247
    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])
      end
1248

1249
      it 'returns users with a partially matching name' do
1250
        expect(described_class.search(user.name[0..2])).to eq([user, user2])
1251
      end
1252

1253 1254 1255
      it 'returns users with a matching name regardless of the casing' do
        expect(described_class.search(user2.name.upcase)).to eq([user2])
      end
1256 1257 1258 1259 1260 1261 1262 1263

      it 'returns users with a exact matching name shorter than 3 chars' do
        expect(described_class.search(user3.name)).to eq([user3])
      end

      it 'returns users with a exact matching name shorter than 3 chars regardless of the casing' do
        expect(described_class.search(user3.name.upcase)).to eq([user3])
      end
1264 1265
    end

1266 1267
    describe 'email matching' do
      it 'returns users with a matching Email' do
1268
        expect(described_class.search(user.email)).to eq([user])
1269
      end
1270

1271 1272
      it 'does not return users with a partially matching Email' do
        expect(described_class.search(user.email[0..2])).not_to include(user, user2)
1273
      end
1274

1275 1276 1277
      it 'returns users with a matching Email regardless of the casing' do
        expect(described_class.search(user2.email.upcase)).to eq([user2])
      end
1278 1279
    end

1280 1281 1282 1283
    describe 'username matching' do
      it 'returns users with a matching username' do
        expect(described_class.search(user.username)).to eq([user, user2])
      end
1284

1285
      it 'returns users with a partially matching username' do
1286
        expect(described_class.search(user.username[0..2])).to eq([user, user2])
1287
      end
1288

1289 1290 1291
      it 'returns users with a matching username regardless of the casing' do
        expect(described_class.search(user2.username.upcase)).to eq([user2])
      end
1292 1293 1294 1295 1296 1297 1298 1299

      it 'returns users with a exact matching username shorter than 3 chars' do
        expect(described_class.search(user3.username)).to eq([user3])
      end

      it 'returns users with a exact matching username shorter than 3 chars regardless of the casing' do
        expect(described_class.search(user3.username.upcase)).to eq([user3])
      end
M
Marin Jankovski 已提交
1300
    end
1301 1302 1303 1304 1305 1306 1307 1308

    it 'returns no matches for an empty string' do
      expect(described_class.search('')).to be_empty
    end

    it 'returns no matches for nil' do
      expect(described_class.search(nil)).to be_empty
    end
1309 1310 1311
  end

  describe '.search_with_secondary_emails' do
D
Douwe Maan 已提交
1312
    delegate :search_with_secondary_emails, to: :described_class
1313

1314 1315
    let!(:user) { create(:user, name: 'John Doe', username: 'john.doe', email: 'john.doe@example.com' ) }
    let!(:another_user) { create(:user, name: 'Albert Smith', username: 'albert.smith', email: 'albert.smith@example.com' ) }
1316 1317 1318
    let!(:email) do
      create(:email, user: another_user, email: 'alias@example.com')
    end
1319 1320 1321 1322 1323 1324 1325 1326 1327 1328 1329 1330 1331 1332 1333 1334 1335

    it 'returns users with a matching name' do
      expect(search_with_secondary_emails(user.name)).to eq([user])
    end

    it 'returns users with a partially matching name' do
      expect(search_with_secondary_emails(user.name[0..2])).to eq([user])
    end

    it 'returns users with a matching name regardless of the casing' do
      expect(search_with_secondary_emails(user.name.upcase)).to eq([user])
    end

    it 'returns users with a matching email' do
      expect(search_with_secondary_emails(user.email)).to eq([user])
    end

1336 1337
    it 'does not return users with a partially matching email' do
      expect(search_with_secondary_emails(user.email[0..2])).not_to include([user])
1338 1339 1340 1341 1342 1343 1344 1345 1346 1347 1348 1349 1350 1351 1352 1353 1354 1355 1356 1357 1358 1359
    end

    it 'returns users with a matching email regardless of the casing' do
      expect(search_with_secondary_emails(user.email.upcase)).to eq([user])
    end

    it 'returns users with a matching username' do
      expect(search_with_secondary_emails(user.username)).to eq([user])
    end

    it 'returns users with a partially matching username' do
      expect(search_with_secondary_emails(user.username[0..2])).to eq([user])
    end

    it 'returns users with a matching username regardless of the casing' do
      expect(search_with_secondary_emails(user.username.upcase)).to eq([user])
    end

    it 'returns users with a matching whole secondary email' do
      expect(search_with_secondary_emails(email.email)).to eq([email.user])
    end

1360 1361
    it 'does not return users with a matching part of secondary email' do
      expect(search_with_secondary_emails(email.email[1..4])).not_to include([email.user])
1362
    end
1363 1364 1365 1366 1367 1368 1369 1370

    it 'returns no matches for an empty string' do
      expect(search_with_secondary_emails('')).to be_empty
    end

    it 'returns no matches for nil' do
      expect(search_with_secondary_emails(nil)).to be_empty
    end
M
Marin Jankovski 已提交
1371 1372
  end

Y
Yorick Peterse 已提交
1373 1374 1375 1376 1377 1378 1379 1380 1381 1382 1383 1384 1385 1386 1387 1388 1389
  describe '.find_by_ssh_key_id' do
    context 'using an existing SSH key ID' do
      let(:user) { create(:user) }
      let(:key) { create(:key, user: user) }

      it 'returns the corresponding User' do
        expect(described_class.find_by_ssh_key_id(key.id)).to eq(user)
      end
    end

    context 'using an invalid SSH key ID' do
      it 'returns nil' do
        expect(described_class.find_by_ssh_key_id(-1)).to be_nil
      end
    end
  end

1390 1391 1392 1393
  describe '.by_login' do
    let(:username) { 'John' }
    let!(:user) { create(:user, username: username) }

1394
    it 'gets the correct user' do
1395 1396 1397 1398 1399 1400
      expect(described_class.by_login(user.email.upcase)).to eq user
      expect(described_class.by_login(user.email)).to eq user
      expect(described_class.by_login(username.downcase)).to eq user
      expect(described_class.by_login(username)).to eq user
      expect(described_class.by_login(nil)).to be_nil
      expect(described_class.by_login('')).to be_nil
1401 1402 1403
    end
  end

1404 1405 1406 1407 1408 1409 1410
  describe '.find_by_username' do
    it 'returns nil if not found' do
      expect(described_class.find_by_username('JohnDoe')).to be_nil
    end

    it 'is case-insensitive' do
      user = create(:user, username: 'JohnDoe')
1411

1412 1413 1414 1415
      expect(described_class.find_by_username('JOHNDOE')).to eq user
    end
  end

R
Robert Speicher 已提交
1416 1417
  describe '.find_by_username!' do
    it 'raises RecordNotFound' do
1418 1419
      expect { described_class.find_by_username!('JohnDoe') }
        .to raise_error(ActiveRecord::RecordNotFound)
R
Robert Speicher 已提交
1420 1421 1422 1423
    end

    it 'is case-insensitive' do
      user = create(:user, username: 'JohnDoe')
1424

R
Robert Speicher 已提交
1425 1426 1427 1428
      expect(described_class.find_by_username!('JOHNDOE')).to eq user
    end
  end

1429 1430 1431 1432 1433 1434 1435
  describe '.find_by_full_path' do
    let!(:user) { create(:user) }

    context 'with a route matching the given path' do
      let!(:route) { user.namespace.route }

      it 'returns the user' do
1436
        expect(described_class.find_by_full_path(route.path)).to eq(user)
1437 1438 1439
      end

      it 'is case-insensitive' do
1440 1441
        expect(described_class.find_by_full_path(route.path.upcase)).to eq(user)
        expect(described_class.find_by_full_path(route.path.downcase)).to eq(user)
1442 1443 1444 1445 1446 1447 1448 1449
      end
    end

    context 'with a redirect route matching the given path' do
      let!(:redirect_route) { user.namespace.redirect_routes.create(path: 'foo') }

      context 'without the follow_redirects option' do
        it 'returns nil' do
1450
          expect(described_class.find_by_full_path(redirect_route.path)).to eq(nil)
1451 1452 1453 1454 1455
        end
      end

      context 'with the follow_redirects option set to true' do
        it 'returns the user' do
1456
          expect(described_class.find_by_full_path(redirect_route.path, follow_redirects: true)).to eq(user)
1457 1458 1459
        end

        it 'is case-insensitive' do
1460 1461
          expect(described_class.find_by_full_path(redirect_route.path.upcase, follow_redirects: true)).to eq(user)
          expect(described_class.find_by_full_path(redirect_route.path.downcase, follow_redirects: true)).to eq(user)
1462 1463 1464 1465 1466 1467 1468
        end
      end
    end

    context 'without a route or a redirect route matching the given path' do
      context 'without the follow_redirects option' do
        it 'returns nil' do
1469
          expect(described_class.find_by_full_path('unknown')).to eq(nil)
1470 1471 1472 1473
        end
      end
      context 'with the follow_redirects option set to true' do
        it 'returns nil' do
1474
          expect(described_class.find_by_full_path('unknown', follow_redirects: true)).to eq(nil)
1475 1476 1477 1478 1479
        end
      end
    end

    context 'with a group route matching the given path' do
1480 1481
      let!(:group) { create(:group, path: 'group_path') }

M
Michael Kozono 已提交
1482
      context 'when the group namespace has an owner_id (legacy data)' do
1483 1484 1485
        before do
          group.update!(owner_id: user.id)
        end
1486

M
Michael Kozono 已提交
1487
        it 'returns nil' do
1488
          expect(described_class.find_by_full_path('group_path')).to eq(nil)
M
Michael Kozono 已提交
1489 1490 1491 1492 1493
        end
      end

      context 'when the group namespace does not have an owner_id' do
        it 'returns nil' do
1494
          expect(described_class.find_by_full_path('group_path')).to eq(nil)
M
Michael Kozono 已提交
1495
        end
1496 1497 1498 1499
      end
    end
  end

G
GitLab 已提交
1500
  describe 'all_ssh_keys' do
1501
    it { is_expected.to have_many(:keys).dependent(:destroy) }
G
GitLab 已提交
1502

1503
    it "has all ssh keys" do
G
GitLab 已提交
1504 1505 1506
      user = create :user
      key = create :key, key: "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQD33bWLBxu48Sev9Fert1yzEO4WGcWglWF7K/AwblIUFselOt/QdOL9DSjpQGxLagO1s9wl53STIO8qGS4Ms0EJZyIXOEFMjFJ5xmjSy+S37By4sG7SsltQEHMxtbtFOaW5LV2wCrX+rUsRNqLMamZjgjcPO0/EgGCXIGMAYW4O7cwGZdXWYIhQ1Vwy+CsVMDdPkPgBXqK7nR/ey8KMs8ho5fMNgB5hBw/AL9fNGhRw3QTD6Q12Nkhl4VZES2EsZqlpNnJttnPdp847DUsT6yuLRlfiQfz5Cn9ysHFdXObMN5VYIiPFwHeYCZp1X2S4fDZooRE8uOLTfxWHPXwrhqSH", user_id: user.id

1507
      expect(user.all_ssh_keys).to include(a_string_starting_with(key.key))
G
GitLab 已提交
1508
    end
G
GitLab 已提交
1509
  end
1510

1511
  describe '#avatar_type' do
D
Dmitriy Zaporozhets 已提交
1512 1513
    let(:user) { create(:user) }

1514
    it 'is true if avatar is image' do
D
Dmitriy Zaporozhets 已提交
1515
      user.update_attribute(:avatar, 'uploads/avatar.png')
1516

1517
      expect(user.avatar_type).to be_truthy
D
Dmitriy Zaporozhets 已提交
1518 1519
    end

1520
    it 'is false if avatar is html page' do
D
Dmitriy Zaporozhets 已提交
1521
      user.update_attribute(:avatar, 'uploads/avatar.html')
1522

1523
      expect(user.avatar_type).to eq(['file format is not supported. Please try one of the following supported formats: png, jpg, jpeg, gif, bmp, tiff, ico'])
D
Dmitriy Zaporozhets 已提交
1524 1525
    end
  end
J
Jerome Dalbert 已提交
1526

1527 1528 1529 1530
  describe '#avatar_url' do
    let(:user) { create(:user, :with_avatar) }

    context 'when avatar file is uploaded' do
1531
      it 'shows correct avatar url' do
1532 1533
        expect(user.avatar_url).to eq(user.avatar.url)
        expect(user.avatar_url(only_path: false)).to eq([Gitlab.config.gitlab.url, user.avatar.url].join)
1534
      end
1535 1536 1537
    end
  end

1538 1539 1540 1541 1542 1543 1544 1545 1546 1547 1548 1549 1550 1551 1552 1553 1554 1555
  describe '#accept_pending_invitations!' do
    let(:user) { create(:user, email: 'user@email.com') }
    let!(:project_member_invite) { create(:project_member, :invited, invite_email: user.email) }
    let!(:group_member_invite) { create(:group_member, :invited, invite_email: user.email) }
    let!(:external_project_member_invite) { create(:project_member, :invited, invite_email: 'external@email.com') }
    let!(:external_group_member_invite) { create(:group_member, :invited, invite_email: 'external@email.com') }

    it 'accepts all the user members pending invitations and returns the accepted_members' do
      accepted_members = user.accept_pending_invitations!

      expect(accepted_members).to match_array([project_member_invite, group_member_invite])
      expect(group_member_invite.reload).not_to be_invite
      expect(project_member_invite.reload).not_to be_invite
      expect(external_project_member_invite.reload).to be_invite
      expect(external_group_member_invite.reload).to be_invite
    end
  end

1556 1557 1558 1559 1560 1561 1562
  describe '#all_emails' do
    let(:user) { create(:user) }

    it 'returns all emails' do
      email_confirmed   = create :email, user: user, confirmed_at: Time.now
      email_unconfirmed = create :email, user: user
      user.reload
1563

1564 1565 1566 1567 1568 1569
      expect(user.all_emails).to contain_exactly(
        user.email,
        user.private_commit_email,
        email_unconfirmed.email,
        email_confirmed.email
      )
1570 1571 1572
    end
  end

1573
  describe '#verified_emails' do
1574 1575 1576
    let(:user) { create(:user) }

    it 'returns only confirmed emails' do
B
Brett Walker 已提交
1577 1578
      email_confirmed = create :email, user: user, confirmed_at: Time.now
      create :email, user: user
1579

1580 1581 1582 1583 1584
      expect(user.verified_emails).to contain_exactly(
        user.email,
        user.private_commit_email,
        email_confirmed.email
      )
1585 1586 1587 1588 1589 1590 1591
    end
  end

  describe '#verified_email?' do
    let(:user) { create(:user) }

    it 'returns true when the email is verified/confirmed' do
B
Brett Walker 已提交
1592 1593
      email_confirmed = create :email, user: user, confirmed_at: Time.now
      create :email, user: user
1594 1595 1596
      user.reload

      expect(user.verified_email?(user.email)).to be_truthy
1597
      expect(user.verified_email?(email_confirmed.email.titlecase)).to be_truthy
1598 1599
    end

1600 1601 1602 1603
    it 'returns true when user is found through private commit email' do
      expect(user.verified_email?(user.private_commit_email)).to be_truthy
    end

1604 1605 1606 1607 1608 1609 1610 1611
    it 'returns true for an outdated private commit email' do
      old_email = user.private_commit_email

      user.update!(username: 'changed-username')

      expect(user.verified_email?(old_email)).to be_truthy
    end

1612 1613 1614 1615 1616 1617 1618 1619
    it 'returns false when the email is not verified/confirmed' do
      email_unconfirmed = create :email, user: user
      user.reload

      expect(user.verified_email?(email_unconfirmed.email)).to be_falsy
    end
  end

1620
  describe '#requires_ldap_check?' do
1621
    let(:user) { described_class.new }
1622

1623 1624
    it 'is false when LDAP is disabled' do
      # Create a condition which would otherwise cause 'true' to be returned
1625
      allow(user).to receive(:ldap_user?).and_return(true)
1626
      user.last_credential_check_at = nil
1627

1628
      expect(user.requires_ldap_check?).to be_falsey
1629 1630
    end

1631
    context 'when LDAP is enabled' do
1632 1633 1634
      before do
        allow(Gitlab.config.ldap).to receive(:enabled).and_return(true)
      end
1635

1636
      it 'is false for non-LDAP users' do
1637
        allow(user).to receive(:ldap_user?).and_return(false)
1638

1639
        expect(user.requires_ldap_check?).to be_falsey
1640 1641
      end

1642
      context 'and when the user is an LDAP user' do
1643 1644 1645
        before do
          allow(user).to receive(:ldap_user?).and_return(true)
        end
1646 1647 1648

        it 'is true when the user has never had an LDAP check before' do
          user.last_credential_check_at = nil
1649

1650
          expect(user.requires_ldap_check?).to be_truthy
1651 1652 1653 1654
        end

        it 'is true when the last LDAP check happened over 1 hour ago' do
          user.last_credential_check_at = 2.hours.ago
1655

1656
          expect(user.requires_ldap_check?).to be_truthy
1657
        end
1658 1659 1660 1661
      end
    end
  end

1662
  context 'ldap synchronized user' do
1663
    describe '#ldap_user?' do
1664 1665
      it 'is true if provider name starts with ldap' do
        user = create(:omniauth_user, provider: 'ldapmain')
1666

1667 1668
        expect(user.ldap_user?).to be_truthy
      end
1669

1670 1671
      it 'is false for other providers' do
        user = create(:omniauth_user, provider: 'other-provider')
1672

1673 1674 1675 1676 1677
        expect(user.ldap_user?).to be_falsey
      end

      it 'is false if no extern_uid is provided' do
        user = create(:omniauth_user, extern_uid: nil)
1678

1679 1680
        expect(user.ldap_user?).to be_falsey
      end
1681 1682
    end

1683
    describe '#ldap_identity' do
1684 1685
      it 'returns ldap identity' do
        user = create :omniauth_user
1686

1687 1688
        expect(user.ldap_identity.provider).not_to be_empty
      end
1689 1690
    end

1691 1692 1693 1694 1695
    describe '#ldap_block' do
      let(:user) { create(:omniauth_user, provider: 'ldapmain', name: 'John Smith') }

      it 'blocks user flaging the action caming from ldap' do
        user.ldap_block
1696

1697 1698 1699
        expect(user.blocked?).to be_truthy
        expect(user.ldap_blocked?).to be_truthy
      end
1700 1701 1702
    end
  end

J
Jerome Dalbert 已提交
1703 1704 1705 1706 1707 1708 1709 1710 1711 1712 1713 1714 1715 1716 1717 1718 1719 1720 1721 1722 1723 1724 1725 1726 1727 1728 1729 1730 1731 1732 1733 1734 1735 1736 1737 1738 1739 1740 1741
  describe '#full_website_url' do
    let(:user) { create(:user) }

    it 'begins with http if website url omits it' do
      user.website_url = 'test.com'

      expect(user.full_website_url).to eq 'http://test.com'
    end

    it 'begins with http if website url begins with http' do
      user.website_url = 'http://test.com'

      expect(user.full_website_url).to eq 'http://test.com'
    end

    it 'begins with https if website url begins with https' do
      user.website_url = 'https://test.com'

      expect(user.full_website_url).to eq 'https://test.com'
    end
  end

  describe '#short_website_url' do
    let(:user) { create(:user) }

    it 'does not begin with http if website url omits it' do
      user.website_url = 'test.com'

      expect(user.short_website_url).to eq 'test.com'
    end

    it 'does not begin with http if website url begins with http' do
      user.website_url = 'http://test.com'

      expect(user.short_website_url).to eq 'test.com'
    end

    it 'does not begin with https if website url begins with https' do
      user.website_url = 'https://test.com'
1742

J
Jerome Dalbert 已提交
1743 1744
      expect(user.short_website_url).to eq 'test.com'
    end
G
GitLab 已提交
1745
  end
C
Ciro Santilli 已提交
1746

1747 1748 1749 1750 1751 1752 1753 1754 1755 1756 1757 1758
  describe '#sanitize_attrs' do
    let(:user) { build(:user, name: 'test & user', skype: 'test&user') }

    it 'encodes HTML entities in the Skype attribute' do
      expect { user.sanitize_attrs }.to change { user.skype }.to('test&amp;user')
    end

    it 'does not encode HTML entities in the name attribute' do
      expect { user.sanitize_attrs }.not_to change { user.name }
    end
  end

1759 1760
  describe '#starred?' do
    it 'determines if user starred a project' do
1761
      user = create :user
1762 1763
      project1 = create(:project, :public)
      project2 = create(:project, :public)
1764

1765 1766
      expect(user.starred?(project1)).to be_falsey
      expect(user.starred?(project2)).to be_falsey
1767 1768

      star1 = UsersStarProject.create!(project: project1, user: user)
1769

1770 1771
      expect(user.starred?(project1)).to be_truthy
      expect(user.starred?(project2)).to be_falsey
1772 1773

      star2 = UsersStarProject.create!(project: project2, user: user)
1774

1775 1776
      expect(user.starred?(project1)).to be_truthy
      expect(user.starred?(project2)).to be_truthy
1777 1778

      star1.destroy
1779

1780 1781
      expect(user.starred?(project1)).to be_falsey
      expect(user.starred?(project2)).to be_truthy
1782 1783

      star2.destroy
1784

1785 1786
      expect(user.starred?(project1)).to be_falsey
      expect(user.starred?(project2)).to be_falsey
1787 1788 1789
    end
  end

1790 1791
  describe '#toggle_star' do
    it 'toggles stars' do
C
Ciro Santilli 已提交
1792
      user = create :user
1793
      project = create(:project, :public)
C
Ciro Santilli 已提交
1794

1795
      expect(user.starred?(project)).to be_falsey
1796

C
Ciro Santilli 已提交
1797
      user.toggle_star(project)
1798

1799
      expect(user.starred?(project)).to be_truthy
1800

C
Ciro Santilli 已提交
1801
      user.toggle_star(project)
1802

1803
      expect(user.starred?(project)).to be_falsey
C
Ciro Santilli 已提交
1804 1805
    end
  end
V
Valery Sizov 已提交
1806

1807 1808 1809 1810 1811 1812 1813 1814 1815 1816 1817 1818 1819 1820 1821 1822 1823 1824
  describe '.find_by_private_commit_email' do
    context 'with email' do
      set(:user) { create(:user) }

      it 'returns user through private commit email' do
        expect(described_class.find_by_private_commit_email(user.private_commit_email)).to eq(user)
      end

      it 'returns nil when email other than private_commit_email is used' do
        expect(described_class.find_by_private_commit_email(user.email)).to be_nil
      end
    end

    it 'returns nil when email is nil' do
      expect(described_class.find_by_private_commit_email(nil)).to be_nil
    end
  end

1825
  describe '#sort_by_attribute' do
V
Valery Sizov 已提交
1826
    before do
1827
      described_class.delete_all
1828 1829 1830
      @user = create :user, created_at: Date.today, current_sign_in_at: Date.today, name: 'Alpha'
      @user1 = create :user, created_at: Date.today - 1, current_sign_in_at: Date.today - 1, name: 'Omega'
      @user2 = create :user, created_at: Date.today - 2, name: 'Beta'
V
Valery Sizov 已提交
1831
    end
1832

1833
    context 'when sort by recent_sign_in' do
1834
      let(:users) { described_class.sort_by_attribute('recent_sign_in') }
1835 1836 1837 1838

      it 'sorts users by recent sign-in time' do
        expect(users.first).to eq(@user)
        expect(users.second).to eq(@user1)
1839 1840 1841
      end

      it 'pushes users who never signed in to the end' do
1842
        expect(users.third).to eq(@user2)
1843
      end
V
Valery Sizov 已提交
1844 1845
    end

1846
    context 'when sort by oldest_sign_in' do
1847
      let(:users) { described_class.sort_by_attribute('oldest_sign_in') }
1848

1849
      it 'sorts users by the oldest sign-in time' do
1850 1851
        expect(users.first).to eq(@user1)
        expect(users.second).to eq(@user)
1852 1853 1854
      end

      it 'pushes users who never signed in to the end' do
1855
        expect(users.third).to eq(@user2)
1856
      end
V
Valery Sizov 已提交
1857 1858
    end

1859
    it 'sorts users in descending order by their creation time' do
1860
      expect(described_class.sort_by_attribute('created_desc').first).to eq(@user)
V
Valery Sizov 已提交
1861 1862
    end

1863
    it 'sorts users in ascending order by their creation time' do
1864
      expect(described_class.sort_by_attribute('created_asc').first).to eq(@user2)
V
Valery Sizov 已提交
1865 1866
    end

1867
    it 'sorts users by id in descending order when nil is passed' do
1868
      expect(described_class.sort_by_attribute(nil).first).to eq(@user2)
V
Valery Sizov 已提交
1869 1870
    end
  end
1871

1872
  describe "#contributed_projects" do
1873
    subject { create(:user) }
1874
    let!(:project1) { create(:project) }
B
Bob Van Landuyt 已提交
1875
    let!(:project2) { fork_project(project3) }
1876
    let!(:project3) { create(:project) }
1877
    let!(:merge_request) { create(:merge_request, source_project: project2, target_project: project3, author: subject) }
1878
    let!(:push_event) { create(:push_event, project: project1, author: subject) }
1879
    let!(:merge_event) { create(:event, :created, project: project3, target: merge_request, author: subject) }
1880 1881

    before do
1882 1883
      project1.add_maintainer(subject)
      project2.add_maintainer(subject)
1884 1885 1886
    end

    it "includes IDs for projects the user has pushed to" do
1887
      expect(subject.contributed_projects).to include(project1)
1888 1889 1890
    end

    it "includes IDs for projects the user has had merge requests merged into" do
1891
      expect(subject.contributed_projects).to include(project3)
1892 1893 1894
    end

    it "doesn't include IDs for unrelated projects" do
1895
      expect(subject.contributed_projects).not_to include(project2)
1896 1897
    end
  end
1898

1899 1900 1901 1902 1903 1904 1905 1906 1907 1908 1909 1910 1911 1912 1913 1914 1915
  describe '#fork_of' do
    let(:user) { create(:user) }

    it "returns a user's fork of a project" do
      project = create(:project, :public)
      user_fork = fork_project(project, user, namespace: user.namespace)

      expect(user.fork_of(project)).to eq(user_fork)
    end

    it 'returns nil if the project does not have a fork network' do
      project = create(:project)

      expect(user.fork_of(project)).to be_nil
    end
  end

1916
  describe '#can_be_removed?' do
1917 1918 1919 1920 1921 1922 1923 1924 1925 1926 1927 1928 1929 1930 1931
    subject { create(:user) }

    context 'no owned groups' do
      it { expect(subject.can_be_removed?).to be_truthy }
    end

    context 'has owned groups' do
      before do
        group = create(:group)
        group.add_owner(subject)
      end

      it { expect(subject.can_be_removed?).to be_falsey }
    end
  end
1932 1933

  describe "#recent_push" do
1934 1935 1936
    let(:user) { build(:user) }
    let(:project) { build(:project) }
    let(:event) { build(:push_event) }
1937

1938 1939 1940 1941
    it 'returns the last push event for the user' do
      expect_any_instance_of(Users::LastPushEventService)
        .to receive(:last_event_for_user)
        .and_return(event)
1942

1943
      expect(user.recent_push).to eq(event)
1944 1945
    end

1946 1947 1948 1949
    it 'returns the last push event for a project when one is given' do
      expect_any_instance_of(Users::LastPushEventService)
        .to receive(:last_event_for_project)
        .and_return(event)
1950

1951
      expect(user.recent_push(project)).to eq(event)
1952
    end
1953
  end
1954 1955 1956 1957

  describe '#authorized_groups' do
    let!(:user) { create(:user) }
    let!(:private_group) { create(:group) }
1958 1959 1960 1961
    let!(:child_group) { create(:group, parent: private_group) }

    let!(:project_group) { create(:group) }
    let!(:project) { create(:project, group: project_group) }
1962 1963

    before do
1964 1965
      private_group.add_user(user, Gitlab::Access::MAINTAINER)
      project.add_maintainer(user)
1966 1967
    end

1968
    subject { user.authorized_groups }
1969

1970 1971 1972 1973 1974 1975 1976 1977 1978
    it { is_expected.to contain_exactly private_group, project_group }
  end

  describe '#membership_groups' do
    let!(:user) { create(:user) }
    let!(:parent_group) { create(:group) }
    let!(:child_group) { create(:group, parent: parent_group) }

    before do
1979
      parent_group.add_user(user, Gitlab::Access::MAINTAINER)
1980 1981 1982 1983
    end

    subject { user.membership_groups }

1984
    if Group.supports_nested_objects?
1985 1986 1987 1988
      it { is_expected.to contain_exactly parent_group, child_group }
    else
      it { is_expected.to contain_exactly parent_group }
    end
1989 1990
  end

1991 1992 1993 1994 1995 1996
  describe '#authorizations_for_projects' do
    let!(:user) { create(:user) }
    subject { Project.where("EXISTS (?)", user.authorizations_for_projects) }

    it 'includes projects that belong to a user, but no other projects' do
      owned = create(:project, :private, namespace: user.namespace)
1997
      member = create(:project, :private).tap { |p| p.add_maintainer(user) }
1998 1999 2000 2001 2002 2003 2004 2005 2006 2007 2008 2009 2010 2011 2012 2013 2014
      other = create(:project)

      expect(subject).to include(owned)
      expect(subject).to include(member)
      expect(subject).not_to include(other)
    end

    it 'includes projects a user has access to, but no other projects' do
      other_user = create(:user)
      accessible = create(:project, :private, namespace: other_user.namespace) do |project|
        project.add_developer(user)
      end
      other = create(:project)

      expect(subject).to include(accessible)
      expect(subject).not_to include(other)
    end
2015 2016 2017 2018 2019 2020 2021 2022 2023 2024 2025 2026 2027 2028 2029 2030 2031 2032 2033 2034 2035 2036 2037 2038 2039 2040 2041

    context 'with min_access_level' do
      let!(:user) { create(:user) }
      let!(:project) { create(:project, :private, namespace: user.namespace) }

      before do
        project.add_developer(user)
      end

      subject { Project.where("EXISTS (?)", user.authorizations_for_projects(min_access_level: min_access_level)) }

      context 'when developer access' do
        let(:min_access_level) { Gitlab::Access::DEVELOPER }

        it 'includes projects a user has access to' do
          expect(subject).to include(project)
        end
      end

      context 'when owner access' do
        let(:min_access_level) { Gitlab::Access::OWNER }

        it 'does not include projects with higher access level' do
          expect(subject).not_to include(project)
        end
      end
    end
2042 2043
  end

2044
  describe '#authorized_projects', :delete do
2045 2046 2047
    context 'with a minimum access level' do
      it 'includes projects for which the user is an owner' do
        user = create(:user)
2048
        project = create(:project, :private, namespace: user.namespace)
2049

D
Douwe Maan 已提交
2050 2051
        expect(user.authorized_projects(Gitlab::Access::REPORTER))
          .to contain_exactly(project)
2052
      end
2053

2054
      it 'includes projects for which the user is a maintainer' do
2055
        user = create(:user)
2056
        project = create(:project, :private)
2057

2058
        project.add_maintainer(user)
2059

D
Douwe Maan 已提交
2060 2061
        expect(user.authorized_projects(Gitlab::Access::REPORTER))
          .to contain_exactly(project)
2062 2063
      end
    end
2064 2065 2066

    it "includes user's personal projects" do
      user    = create(:user)
2067
      project = create(:project, :private, namespace: user.namespace)
2068 2069 2070 2071 2072 2073 2074

      expect(user.authorized_projects).to include(project)
    end

    it "includes personal projects user has been given access to" do
      user1   = create(:user)
      user2   = create(:user)
2075
      project = create(:project, :private, namespace: user1.namespace)
2076

2077
      project.add_developer(user2)
2078 2079 2080 2081 2082 2083

      expect(user2.authorized_projects).to include(project)
    end

    it "includes projects of groups user has been added to" do
      group   = create(:group)
2084
      project = create(:project, group: group)
2085 2086 2087 2088 2089 2090 2091 2092 2093
      user    = create(:user)

      group.add_developer(user)

      expect(user.authorized_projects).to include(project)
    end

    it "does not include projects of groups user has been removed from" do
      group   = create(:group)
2094
      project = create(:project, group: group)
2095 2096 2097
      user    = create(:user)

      member = group.add_developer(user)
2098

2099 2100 2101
      expect(user.authorized_projects).to include(project)

      member.destroy
2102

2103 2104 2105 2106 2107
      expect(user.authorized_projects).not_to include(project)
    end

    it "includes projects shared with user's group" do
      user    = create(:user)
2108
      project = create(:project, :private)
2109 2110 2111 2112 2113 2114 2115 2116 2117 2118 2119
      group   = create(:group)

      group.add_reporter(user)
      project.project_group_links.create(group: group)

      expect(user.authorized_projects).to include(project)
    end

    it "does not include destroyed projects user had access to" do
      user1   = create(:user)
      user2   = create(:user)
2120
      project = create(:project, :private, namespace: user1.namespace)
2121

2122
      project.add_developer(user2)
2123

2124 2125 2126
      expect(user2.authorized_projects).to include(project)

      project.destroy
2127

2128 2129 2130 2131 2132
      expect(user2.authorized_projects).not_to include(project)
    end

    it "does not include projects of destroyed groups user had access to" do
      group   = create(:group)
2133
      project = create(:project, namespace: group)
2134 2135 2136
      user    = create(:user)

      group.add_developer(user)
2137

2138 2139 2140
      expect(user.authorized_projects).to include(project)

      group.destroy
2141

2142 2143
      expect(user.authorized_projects).not_to include(project)
    end
2144
  end
2145

2146 2147 2148 2149
  describe '#projects_where_can_admin_issues' do
    let(:user) { create(:user) }

    it 'includes projects for which the user access level is above or equal to reporter' do
2150 2151
      reporter_project  = create(:project) { |p| p.add_reporter(user) }
      developer_project = create(:project) { |p| p.add_developer(user) }
2152
      maintainer_project = create(:project) { |p| p.add_maintainer(user) }
2153

2154 2155
      expect(user.projects_where_can_admin_issues.to_a).to match_array([maintainer_project, developer_project, reporter_project])
      expect(user.can?(:admin_issue, maintainer_project)).to eq(true)
2156 2157 2158 2159 2160
      expect(user.can?(:admin_issue, developer_project)).to eq(true)
      expect(user.can?(:admin_issue, reporter_project)).to eq(true)
    end

    it 'does not include for which the user access level is below reporter' do
2161 2162
      project = create(:project)
      guest_project = create(:project) { |p| p.add_guest(user) }
2163 2164 2165 2166 2167 2168 2169

      expect(user.projects_where_can_admin_issues.to_a).to be_empty
      expect(user.can?(:admin_issue, guest_project)).to eq(false)
      expect(user.can?(:admin_issue, project)).to eq(false)
    end

    it 'does not include archived projects' do
2170
      project = create(:project, :archived)
2171 2172 2173 2174 2175 2176

      expect(user.projects_where_can_admin_issues.to_a).to be_empty
      expect(user.can?(:admin_issue, project)).to eq(false)
    end

    it 'does not include projects for which issues are disabled' do
2177
      project = create(:project, :issues_disabled)
2178 2179 2180 2181 2182 2183

      expect(user.projects_where_can_admin_issues.to_a).to be_empty
      expect(user.can?(:admin_issue, project)).to eq(false)
    end
  end

2184
  describe '#ci_owned_runners' do
2185
    let(:user) { create(:user) }
2186
    let!(:project) { create(:project) }
2187
    let(:runner) { create(:ci_runner, :project, projects: [project]) }
2188

2189
    context 'without any projects nor groups' do
2190
      it 'does not load' do
2191
        expect(user.ci_owned_runners).to be_empty
2192 2193 2194 2195 2196
      end
    end

    context 'with personal projects runners' do
      let(:namespace) { create(:namespace, owner: user) }
2197
      let!(:project) { create(:project, namespace: namespace) }
2198 2199

      it 'loads' do
2200
        expect(user.ci_owned_runners).to contain_exactly(runner)
2201 2202 2203 2204
      end
    end

    context 'with personal group runner' do
2205 2206
      let!(:project) { create(:project) }
      let(:group_runner) { create(:ci_runner, :group, groups: [group]) }
2207
      let!(:group) do
2208
        create(:group).tap do |group|
2209 2210 2211 2212 2213
          group.add_owner(user)
        end
      end

      it 'loads' do
2214
        expect(user.ci_owned_runners).to contain_exactly(group_runner)
2215 2216 2217 2218 2219
      end
    end

    context 'with personal project and group runner' do
      let(:namespace) { create(:namespace, owner: user) }
2220 2221
      let!(:project) { create(:project, namespace: namespace) }
      let!(:group_runner) { create(:ci_runner, :group, groups: [group]) }
2222 2223

      let!(:group) do
2224
        create(:group).tap do |group|
2225 2226 2227 2228 2229
          group.add_owner(user)
        end
      end

      it 'loads' do
2230
        expect(user.ci_owned_runners).to contain_exactly(runner, group_runner)
2231 2232 2233 2234
      end
    end

    shared_examples :member do
2235
      context 'when the user is a maintainer' do
2236
        before do
2237
          add_user(:maintainer)
2238
        end
2239

2240
        it 'loads' do
2241
          expect(user.ci_owned_runners).to contain_exactly(runner)
2242
        end
2243 2244
      end

2245
      context 'when the user is a developer' do
2246
        before do
2247
          add_user(:developer)
2248
        end
2249

2250
        it 'does not load' do
2251
          expect(user.ci_owned_runners).to be_empty
2252
        end
2253 2254 2255 2256 2257
      end
    end

    context 'with groups projects runners' do
      let(:group) { create(:group) }
2258
      let!(:project) { create(:project, group: group) }
2259 2260 2261 2262 2263 2264 2265 2266 2267

      def add_user(access)
        group.add_user(user, access)
      end

      it_behaves_like :member
    end

    context 'with groups runners' do
2268 2269
      let!(:runner) { create(:ci_runner, :group, groups: [group]) }
      let!(:group) { create(:group) }
2270

L
Lin Jen-Shin 已提交
2271
      def add_user(access)
2272 2273 2274 2275 2276 2277 2278
        group.add_user(user, access)
      end

      it_behaves_like :member
    end

    context 'with other projects runners' do
2279
      let!(:project) { create(:project) }
2280

L
Lin Jen-Shin 已提交
2281
      def add_user(access)
2282
        project.add_role(user, access)
2283 2284 2285 2286
      end

      it_behaves_like :member
    end
2287 2288 2289 2290 2291

    context 'with subgroup with different owner for project runner', :nested_groups do
      let(:group) { create(:group) }
      let(:another_user) { create(:user) }
      let(:subgroup) { create(:group, parent: group) }
2292
      let!(:project) { create(:project, group: subgroup) }
2293 2294 2295 2296 2297 2298 2299 2300 2301

      def add_user(access)
        group.add_user(user, access)
        group.add_user(another_user, :owner)
        subgroup.add_user(another_user, :owner)
      end

      it_behaves_like :member
    end
2302 2303
  end

2304
  describe '#projects_with_reporter_access_limited_to' do
2305 2306
    let(:project1) { create(:project) }
    let(:project2) { create(:project) }
2307 2308 2309
    let(:user) { create(:user) }

    before do
2310 2311
      project1.add_reporter(user)
      project2.add_guest(user)
2312 2313 2314 2315 2316 2317 2318 2319 2320 2321 2322 2323 2324 2325 2326
    end

    it 'returns the projects when using a single project ID' do
      projects = user.projects_with_reporter_access_limited_to(project1.id)

      expect(projects).to eq([project1])
    end

    it 'returns the projects when using an Array of project IDs' do
      projects = user.projects_with_reporter_access_limited_to([project1.id])

      expect(projects).to eq([project1])
    end

    it 'returns the projects when using an ActiveRecord relation' do
2327 2328
      projects = user
        .projects_with_reporter_access_limited_to(Project.select(:id))
2329 2330 2331 2332 2333 2334 2335 2336 2337 2338

      expect(projects).to eq([project1])
    end

    it 'does not return projects you do not have reporter access to' do
      projects = user.projects_with_reporter_access_limited_to(project2.id)

      expect(projects).to be_empty
    end
  end
2339

2340 2341
  describe '#all_expanded_groups' do
    # foo/bar would also match foo/barbaz instead of just foo/bar and foo/bar/baz
2342 2343
    let!(:user) { create(:user) }

2344 2345 2346 2347 2348 2349 2350 2351 2352 2353 2354 2355 2356 2357 2358 2359
    #                group
    #        _______ (foo) _______
    #       |                     |
    #       |                     |
    # nested_group_1        nested_group_2
    # (bar)                 (barbaz)
    #       |                     |
    #       |                     |
    # nested_group_1_1      nested_group_2_1
    # (baz)                 (baz)
    #
    let!(:group) { create :group }
    let!(:nested_group_1) { create :group, parent: group, name: 'bar' }
    let!(:nested_group_1_1) { create :group, parent: nested_group_1, name: 'baz' }
    let!(:nested_group_2) { create :group, parent: group, name: 'barbaz' }
    let!(:nested_group_2_1) { create :group, parent: nested_group_2, name: 'baz' }
2360

2361 2362 2363 2364 2365 2366
    subject { user.all_expanded_groups }

    context 'user is not a member of any group' do
      it 'returns an empty array' do
        is_expected.to eq([])
      end
2367 2368
    end

2369 2370
    context 'user is member of all groups' do
      before do
2371 2372 2373 2374 2375
        group.add_reporter(user)
        nested_group_1.add_developer(user)
        nested_group_1_1.add_maintainer(user)
        nested_group_2.add_developer(user)
        nested_group_2_1.add_maintainer(user)
2376
      end
2377

2378 2379 2380 2381 2382 2383 2384 2385
      it 'returns all groups' do
        is_expected.to match_array [
          group,
          nested_group_1, nested_group_1_1,
          nested_group_2, nested_group_2_1
        ]
      end
    end
2386

2387
    context 'user is member of the top group' do
2388 2389 2390
      before do
        group.add_owner(user)
      end
2391

2392
      if Group.supports_nested_objects?
2393 2394 2395 2396 2397 2398 2399 2400 2401 2402 2403 2404 2405
        it 'returns all groups' do
          is_expected.to match_array [
            group,
            nested_group_1, nested_group_1_1,
            nested_group_2, nested_group_2_1
          ]
        end
      else
        it 'returns the top-level groups' do
          is_expected.to match_array [group]
        end
      end
    end
2406

2407
    context 'user is member of the first child (internal node), branch 1', :nested_groups do
2408 2409 2410
      before do
        nested_group_1.add_owner(user)
      end
2411

2412 2413 2414 2415 2416 2417 2418 2419 2420
      it 'returns the groups in the hierarchy' do
        is_expected.to match_array [
          group,
          nested_group_1, nested_group_1_1
        ]
      end
    end

    context 'user is member of the first child (internal node), branch 2', :nested_groups do
2421 2422 2423
      before do
        nested_group_2.add_owner(user)
      end
2424

2425 2426 2427 2428 2429 2430
      it 'returns the groups in the hierarchy' do
        is_expected.to match_array [
          group,
          nested_group_2, nested_group_2_1
        ]
      end
2431 2432
    end

2433
    context 'user is member of the last child (leaf node)', :nested_groups do
2434 2435 2436
      before do
        nested_group_1_1.add_owner(user)
      end
2437 2438 2439 2440 2441 2442 2443 2444

      it 'returns the groups in the hierarchy' do
        is_expected.to match_array [
          group,
          nested_group_1, nested_group_1_1
        ]
      end
    end
2445 2446
  end

2447
  describe '#refresh_authorized_projects', :clean_gitlab_redis_shared_state do
2448 2449
    let(:project1) { create(:project) }
    let(:project2) { create(:project) }
2450 2451 2452
    let(:user) { create(:user) }

    before do
2453 2454
      project1.add_reporter(user)
      project2.add_guest(user)
2455 2456 2457 2458 2459 2460 2461 2462 2463 2464 2465 2466 2467 2468

      user.project_authorizations.delete_all
      user.refresh_authorized_projects
    end

    it 'refreshes the list of authorized projects' do
      expect(user.project_authorizations.count).to eq(2)
    end

    it 'stores the correct access levels' do
      expect(user.project_authorizations.where(access_level: Gitlab::Access::GUEST).exists?).to eq(true)
      expect(user.project_authorizations.where(access_level: Gitlab::Access::REPORTER).exists?).to eq(true)
    end
  end
D
Douwe Maan 已提交
2469 2470 2471 2472 2473 2474 2475 2476 2477 2478 2479 2480 2481 2482 2483 2484 2485 2486 2487 2488 2489 2490 2491 2492 2493 2494 2495 2496 2497 2498 2499 2500 2501

  describe '#access_level=' do
    let(:user) { build(:user) }

    it 'does nothing for an invalid access level' do
      user.access_level = :invalid_access_level

      expect(user.access_level).to eq(:regular)
      expect(user.admin).to be false
    end

    it "assigns the 'admin' access level" do
      user.access_level = :admin

      expect(user.access_level).to eq(:admin)
      expect(user.admin).to be true
    end

    it "doesn't clear existing access levels when an invalid access level is passed in" do
      user.access_level = :admin
      user.access_level = :invalid_access_level

      expect(user.access_level).to eq(:admin)
      expect(user.admin).to be true
    end

    it "accepts string values in addition to symbols" do
      user.access_level = 'admin'

      expect(user.access_level).to eq(:admin)
      expect(user.admin).to be true
    end
  end
2502

2503 2504 2505 2506 2507 2508 2509 2510 2511 2512 2513 2514 2515 2516
  describe '#full_private_access?' do
    it 'returns false for regular user' do
      user = build(:user)

      expect(user.full_private_access?).to be_falsy
    end

    it 'returns true for admin user' do
      user = build(:user, :admin)

      expect(user.full_private_access?).to be_truthy
    end
  end

2517 2518
  describe '.ghost' do
    it "creates a ghost user if one isn't already present" do
2519
      ghost = described_class.ghost
2520 2521 2522

      expect(ghost).to be_ghost
      expect(ghost).to be_persisted
2523 2524
      expect(ghost.namespace).not_to be_nil
      expect(ghost.namespace).to be_persisted
2525 2526 2527 2528
    end

    it "does not create a second ghost user if one is already present" do
      expect do
2529 2530 2531 2532
        described_class.ghost
        described_class.ghost
      end.to change { described_class.count }.by(1)
      expect(described_class.ghost).to eq(described_class.ghost)
2533 2534 2535 2536 2537
    end

    context "when a regular user exists with the username 'ghost'" do
      it "creates a ghost user with a non-conflicting username" do
        create(:user, username: 'ghost')
2538
        ghost = described_class.ghost
2539 2540

        expect(ghost).to be_persisted
2541
        expect(ghost.username).to eq('ghost1')
2542 2543 2544 2545 2546 2547
      end
    end

    context "when a regular user exists with the email 'ghost@example.com'" do
      it "creates a ghost user with a non-conflicting email" do
        create(:user, email: 'ghost@example.com')
2548
        ghost = described_class.ghost
2549 2550

        expect(ghost).to be_persisted
2551
        expect(ghost.email).to eq('ghost1@example.com')
2552 2553
      end
    end
2554 2555 2556 2557 2558 2559 2560

    context 'when a domain whitelist is in place' do
      before do
        stub_application_setting(domain_whitelist: ['gitlab.com'])
      end

      it 'creates a ghost user' do
2561
        expect(described_class.ghost).to be_persisted
2562 2563
      end
    end
2564
  end
2565 2566 2567 2568 2569 2570 2571 2572 2573 2574 2575 2576 2577 2578 2579 2580

  describe '#update_two_factor_requirement' do
    let(:user) { create :user }

    context 'with 2FA requirement on groups' do
      let(:group1) { create :group, require_two_factor_authentication: true, two_factor_grace_period: 23 }
      let(:group2) { create :group, require_two_factor_authentication: true, two_factor_grace_period: 32 }

      before do
        group1.add_user(user, GroupMember::OWNER)
        group2.add_user(user, GroupMember::OWNER)

        user.update_two_factor_requirement
      end

      it 'requires 2FA' do
2581
        expect(user.require_two_factor_authentication_from_group).to be true
2582 2583 2584 2585 2586 2587 2588
      end

      it 'uses the shortest grace period' do
        expect(user.two_factor_grace_period).to be 23
      end
    end

2589
    context 'with 2FA requirement on nested parent group', :nested_groups do
2590 2591 2592 2593 2594 2595 2596 2597 2598 2599
      let!(:group1) { create :group, require_two_factor_authentication: true }
      let!(:group1a) { create :group, require_two_factor_authentication: false, parent: group1 }

      before do
        group1a.add_user(user, GroupMember::OWNER)

        user.update_two_factor_requirement
      end

      it 'requires 2FA' do
2600
        expect(user.require_two_factor_authentication_from_group).to be true
2601 2602 2603
      end
    end

2604
    context 'with 2FA requirement on nested child group', :nested_groups do
2605 2606 2607 2608 2609 2610 2611 2612 2613 2614
      let!(:group1) { create :group, require_two_factor_authentication: false }
      let!(:group1a) { create :group, require_two_factor_authentication: true, parent: group1 }

      before do
        group1.add_user(user, GroupMember::OWNER)

        user.update_two_factor_requirement
      end

      it 'requires 2FA' do
2615
        expect(user.require_two_factor_authentication_from_group).to be true
2616 2617 2618
      end
    end

2619 2620 2621 2622 2623 2624 2625 2626 2627 2628
    context 'without 2FA requirement on groups' do
      let(:group) { create :group }

      before do
        group.add_user(user, GroupMember::OWNER)

        user.update_two_factor_requirement
      end

      it 'does not require 2FA' do
2629
        expect(user.require_two_factor_authentication_from_group).to be false
2630 2631 2632 2633 2634 2635 2636
      end

      it 'falls back to the default grace period' do
        expect(user.two_factor_grace_period).to be 48
      end
    end
  end
J
James Lopez 已提交
2637 2638 2639

  context '.active' do
    before do
2640
      described_class.ghost
J
James Lopez 已提交
2641 2642 2643 2644 2645
      create(:user, name: 'user', state: 'active')
      create(:user, name: 'user', state: 'blocked')
    end

    it 'only counts active and non internal users' do
2646
      expect(described_class.active.count).to eq(1)
J
James Lopez 已提交
2647 2648
    end
  end
2649 2650 2651 2652 2653 2654 2655 2656

  describe 'preferred language' do
    it 'is English by default' do
      user = create(:user)

      expect(user.preferred_language).to eq('en')
    end
  end
2657 2658 2659 2660 2661 2662 2663 2664 2665 2666 2667 2668 2669 2670 2671 2672 2673 2674 2675 2676 2677 2678 2679 2680 2681 2682 2683 2684

  context '#invalidate_issue_cache_counts' do
    let(:user) { build_stubbed(:user) }

    it 'invalidates cache for issue counter' do
      cache_mock = double

      expect(cache_mock).to receive(:delete).with(['users', user.id, 'assigned_open_issues_count'])

      allow(Rails).to receive(:cache).and_return(cache_mock)

      user.invalidate_issue_cache_counts
    end
  end

  context '#invalidate_merge_request_cache_counts' do
    let(:user) { build_stubbed(:user) }

    it 'invalidates cache for Merge Request counter' do
      cache_mock = double

      expect(cache_mock).to receive(:delete).with(['users', user.id, 'assigned_open_merge_requests_count'])

      allow(Rails).to receive(:cache).and_return(cache_mock)

      user.invalidate_merge_request_cache_counts
    end
  end
2685

A
Andreas Brandl 已提交
2686 2687 2688 2689 2690 2691 2692 2693 2694 2695 2696 2697 2698 2699
  context '#invalidate_personal_projects_count' do
    let(:user) { build_stubbed(:user) }

    it 'invalidates cache for personal projects counter' do
      cache_mock = double

      expect(cache_mock).to receive(:delete).with(['users', user.id, 'personal_projects_count'])

      allow(Rails).to receive(:cache).and_return(cache_mock)

      user.invalidate_personal_projects_count
    end
  end

2700
  describe '#allow_password_authentication_for_web?' do
2701 2702 2703
    context 'regular user' do
      let(:user) { build(:user) }

2704 2705
      it 'returns true when password authentication is enabled for the web interface' do
        expect(user.allow_password_authentication_for_web?).to be_truthy
2706 2707
      end

2708 2709
      it 'returns false when password authentication is disabled for the web interface' do
        stub_application_setting(password_authentication_enabled_for_web: false)
2710

2711
        expect(user.allow_password_authentication_for_web?).to be_falsey
2712 2713 2714 2715 2716 2717
      end
    end

    it 'returns false for ldap user' do
      user = create(:omniauth_user, provider: 'ldapmain')

2718 2719 2720 2721 2722 2723 2724 2725 2726 2727 2728 2729 2730 2731 2732 2733 2734 2735 2736 2737 2738 2739 2740
      expect(user.allow_password_authentication_for_web?).to be_falsey
    end
  end

  describe '#allow_password_authentication_for_git?' do
    context 'regular user' do
      let(:user) { build(:user) }

      it 'returns true when password authentication is enabled for Git' do
        expect(user.allow_password_authentication_for_git?).to be_truthy
      end

      it 'returns false when password authentication is disabled Git' do
        stub_application_setting(password_authentication_enabled_for_git: false)

        expect(user.allow_password_authentication_for_git?).to be_falsey
      end
    end

    it 'returns false for ldap user' do
      user = create(:omniauth_user, provider: 'ldapmain')

      expect(user.allow_password_authentication_for_git?).to be_falsey
2741 2742
    end
  end
2743

2744 2745 2746 2747 2748 2749 2750 2751 2752 2753 2754 2755 2756 2757 2758 2759 2760 2761 2762 2763 2764 2765 2766 2767 2768 2769 2770 2771
  describe '#assigned_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)

      create(:merge_request, source_project: project, author: user, assignee: user)
      create(:merge_request, :closed, source_project: project, author: user, assignee: user)
      create(:merge_request, source_project: archived_project, author: user, assignee: user)

      expect(user.assigned_open_merge_requests_count(force: true)).to eq 1
    end
  end

  describe '#assigned_open_issues_count' do
    it 'returns number of open issues from non-archived projects' do
      user    = create(:user)
      project = create(:project, :public)
      archived_project = create(:project, :public, :archived)

      create(:issue, project: project, author: user, assignees: [user])
      create(:issue, :closed, project: project, author: user, assignees: [user])
      create(:issue, project: archived_project, author: user, assignees: [user])

      expect(user.assigned_open_issues_count(force: true)).to eq 1
    end
  end

2772 2773 2774 2775 2776
  describe '#personal_projects_count' do
    it 'returns the number of personal projects using a single query' do
      user = build(:user)
      projects = double(:projects, count: 1)

A
Andreas Brandl 已提交
2777
      expect(user).to receive(:personal_projects).and_return(projects)
2778

A
Andreas Brandl 已提交
2779
      expect(user.personal_projects_count).to eq(1)
2780 2781 2782 2783 2784 2785 2786 2787 2788 2789 2790 2791 2792
    end
  end

  describe '#projects_limit_left' do
    it 'returns the number of projects that can be created by the user' do
      user = build(:user)

      allow(user).to receive(:projects_limit).and_return(10)
      allow(user).to receive(:personal_projects_count).and_return(5)

      expect(user.projects_limit_left).to eq(5)
    end
  end
2793 2794 2795 2796 2797 2798 2799

  describe '#ensure_namespace_correct' do
    context 'for a new user' do
      let(:user) { build(:user) }

      it 'creates the namespace' do
        expect(user.namespace).to be_nil
2800

2801
        user.save!
2802

2803 2804 2805 2806 2807 2808 2809 2810 2811 2812 2813 2814 2815 2816
        expect(user.namespace).not_to be_nil
      end
    end

    context 'for an existing user' do
      let(:username) { 'foo' }
      let(:user) { create(:user, username: username) }

      context 'when the user is updated' do
        context 'when the username is changed' do
          let(:new_username) { 'bar' }

          it 'changes the namespace (just to compare to when username is not changed)' do
            expect do
2817
              Timecop.freeze(1.second.from_now) do
S
Sean McGivern 已提交
2818
                user.update!(username: new_username)
2819
              end
2820 2821 2822 2823
            end.to change { user.namespace.updated_at }
          end

          it 'updates the namespace name' do
L
Lin Jen-Shin 已提交
2824
            user.update!(username: new_username)
2825

2826 2827 2828 2829
            expect(user.namespace.name).to eq(new_username)
          end

          it 'updates the namespace path' do
L
Lin Jen-Shin 已提交
2830
            user.update!(username: new_username)
2831

2832 2833 2834 2835
            expect(user.namespace.path).to eq(new_username)
          end

          context 'when there is a validation error (namespace name taken) while updating namespace' do
2836
            let!(:conflicting_namespace) { create(:group, path: new_username) }
2837

2838
            it 'causes the user save to fail' do
L
Lin Jen-Shin 已提交
2839
              expect(user.update(username: new_username)).to be_falsey
2840
              expect(user.namespace.errors.messages[:path].first).to eq('has already been taken')
2841
            end
2842 2843

            it 'adds the namespace errors to the user' do
L
Lin Jen-Shin 已提交
2844
              user.update(username: new_username)
2845

2846
              expect(user.errors.full_messages.first).to eq('Username has already been taken')
2847
            end
2848 2849 2850 2851 2852 2853
          end
        end

        context 'when the username is not changed' do
          it 'does not change the namespace' do
            expect do
L
Lin Jen-Shin 已提交
2854
              user.update!(email: 'asdf@asdf.com')
2855 2856 2857 2858 2859 2860
            end.not_to change { user.namespace.updated_at }
          end
        end
      end
    end
  end
A
Alexis Reigel 已提交
2861

2862 2863 2864 2865 2866 2867 2868 2869 2870 2871 2872 2873 2874 2875 2876 2877 2878 2879 2880 2881 2882 2883
  describe '#username_changed_hook' do
    context 'for a new user' do
      let(:user) { build(:user) }

      it 'does not trigger system hook' do
        expect(user).not_to receive(:system_hook_service)

        user.save!
      end
    end

    context 'for an existing user' do
      let(:user) { create(:user, username: 'old-username') }

      context 'when the username is changed' do
        let(:new_username) { 'very-new-name' }

        it 'triggers the rename system hook' do
          system_hook_service = SystemHooksService.new
          expect(system_hook_service).to receive(:execute_hooks_for).with(user, :rename)
          expect(user).to receive(:system_hook_service).and_return(system_hook_service)

L
Lin Jen-Shin 已提交
2884
          user.update!(username: new_username)
2885 2886 2887 2888 2889 2890 2891
        end
      end

      context 'when the username is not changed' do
        it 'does not trigger system hook' do
          expect(user).not_to receive(:system_hook_service)

L
Lin Jen-Shin 已提交
2892
          user.update!(email: 'asdf@asdf.com')
2893 2894 2895 2896 2897
        end
      end
    end
  end

2898 2899 2900 2901 2902 2903
  describe '#sync_attribute?' do
    let(:user) { described_class.new }

    context 'oauth user' do
      it 'returns true if name can be synced' do
        stub_omniauth_setting(sync_profile_attributes: %w(name location))
2904

2905 2906 2907 2908 2909
        expect(user.sync_attribute?(:name)).to be_truthy
      end

      it 'returns true if email can be synced' do
        stub_omniauth_setting(sync_profile_attributes: %w(name email))
2910

2911 2912 2913 2914 2915
        expect(user.sync_attribute?(:email)).to be_truthy
      end

      it 'returns true if location can be synced' do
        stub_omniauth_setting(sync_profile_attributes: %w(location email))
2916

2917 2918 2919 2920 2921
        expect(user.sync_attribute?(:email)).to be_truthy
      end

      it 'returns false if name can not be synced' do
        stub_omniauth_setting(sync_profile_attributes: %w(location email))
2922

2923 2924 2925 2926 2927
        expect(user.sync_attribute?(:name)).to be_falsey
      end

      it 'returns false if email can not be synced' do
        stub_omniauth_setting(sync_profile_attributes: %w(location email))
2928

2929 2930 2931 2932 2933
        expect(user.sync_attribute?(:name)).to be_falsey
      end

      it 'returns false if location can not be synced' do
        stub_omniauth_setting(sync_profile_attributes: %w(location email))
2934

2935 2936 2937 2938 2939
        expect(user.sync_attribute?(:name)).to be_falsey
      end

      it 'returns true for all syncable attributes if all syncable attributes can be synced' do
        stub_omniauth_setting(sync_profile_attributes: true)
2940

2941 2942 2943 2944 2945 2946 2947 2948 2949 2950 2951 2952 2953 2954 2955
        expect(user.sync_attribute?(:name)).to be_truthy
        expect(user.sync_attribute?(:email)).to be_truthy
        expect(user.sync_attribute?(:location)).to be_truthy
      end

      it 'returns false for all syncable attributes but email if no syncable attributes are declared' do
        expect(user.sync_attribute?(:name)).to be_falsey
        expect(user.sync_attribute?(:email)).to be_truthy
        expect(user.sync_attribute?(:location)).to be_falsey
      end
    end

    context 'ldap user' do
      it 'returns true for email if ldap user' do
        allow(user).to receive(:ldap_user?).and_return(true)
2956

2957 2958 2959 2960 2961 2962 2963 2964
        expect(user.sync_attribute?(:name)).to be_falsey
        expect(user.sync_attribute?(:email)).to be_truthy
        expect(user.sync_attribute?(:location)).to be_falsey
      end

      it 'returns true for email and location if ldap user and location declared as syncable' do
        allow(user).to receive(:ldap_user?).and_return(true)
        stub_omniauth_setting(sync_profile_attributes: %w(location))
2965

2966 2967 2968 2969 2970 2971
        expect(user.sync_attribute?(:name)).to be_falsey
        expect(user.sync_attribute?(:email)).to be_truthy
        expect(user.sync_attribute?(:location)).to be_truthy
      end
    end
  end
2972 2973 2974 2975 2976 2977 2978 2979 2980 2981 2982 2983 2984 2985 2986 2987

  describe '#confirm_deletion_with_password?' do
    where(
      password_automatically_set: [true, false],
      ldap_user: [true, false],
      password_authentication_disabled: [true, false]
    )

    with_them do
      let!(:user) { create(:user, password_automatically_set: password_automatically_set) }
      let!(:identity) { create(:identity, user: user) if ldap_user }

      # Only confirm deletion with password if all inputs are false
      let(:expected) { !(password_automatically_set || ldap_user || password_authentication_disabled) }

      before do
2988 2989
        stub_application_setting(password_authentication_enabled_for_web: !password_authentication_disabled)
        stub_application_setting(password_authentication_enabled_for_git: !password_authentication_disabled)
2990 2991 2992 2993 2994 2995 2996 2997 2998 2999 3000 3001 3002 3003 3004 3005 3006 3007 3008 3009 3010 3011 3012 3013 3014 3015 3016 3017
      end

      it 'returns false unless all inputs are true' do
        expect(user.confirm_deletion_with_password?).to eq(expected)
      end
    end
  end

  describe '#delete_async' do
    let(:user) { create(:user) }
    let(:deleted_by) { create(:user) }

    it 'blocks the user then schedules them for deletion if a hard delete is specified' do
      expect(DeleteUserWorker).to receive(:perform_async).with(deleted_by.id, user.id, hard_delete: true)

      user.delete_async(deleted_by: deleted_by, params: { hard_delete: true })

      expect(user).to be_blocked
    end

    it 'schedules user for deletion without blocking them' do
      expect(DeleteUserWorker).to receive(:perform_async).with(deleted_by.id, user.id, {})

      user.delete_async(deleted_by: deleted_by)

      expect(user).not_to be_blocked
    end
  end
3018 3019 3020 3021 3022 3023

  describe '#max_member_access_for_project_ids' do
    shared_examples 'max member access for projects' do
      let(:user) { create(:user) }
      let(:group) { create(:group) }
      let(:owner_project) { create(:project, group: group) }
3024
      let(:maintainer_project) { create(:project) }
3025 3026 3027 3028 3029 3030
      let(:reporter_project) { create(:project) }
      let(:developer_project) { create(:project) }
      let(:guest_project) { create(:project) }
      let(:no_access_project) { create(:project) }

      let(:projects) do
3031
        [owner_project, maintainer_project, reporter_project, developer_project, guest_project, no_access_project].map(&:id)
3032 3033 3034 3035 3036
      end

      let(:expected) do
        {
          owner_project.id => Gitlab::Access::OWNER,
3037
          maintainer_project.id => Gitlab::Access::MAINTAINER,
3038 3039 3040 3041 3042 3043 3044 3045 3046
          reporter_project.id => Gitlab::Access::REPORTER,
          developer_project.id => Gitlab::Access::DEVELOPER,
          guest_project.id => Gitlab::Access::GUEST,
          no_access_project.id => Gitlab::Access::NO_ACCESS
        }
      end

      before do
        create(:group_member, user: user, group: group)
3047
        maintainer_project.add_maintainer(user)
3048 3049 3050 3051 3052 3053 3054 3055 3056 3057 3058 3059 3060 3061 3062 3063 3064 3065 3066 3067 3068 3069 3070 3071 3072 3073
        reporter_project.add_reporter(user)
        developer_project.add_developer(user)
        guest_project.add_guest(user)
      end

      it 'returns correct roles for different projects' do
        expect(user.max_member_access_for_project_ids(projects)).to eq(expected)
      end
    end

    context 'with RequestStore enabled', :request_store do
      include_examples 'max member access for projects'

      def access_levels(projects)
        user.max_member_access_for_project_ids(projects)
      end

      it 'does not perform extra queries when asked for projects who have already been found' do
        access_levels(projects)

        expect { access_levels(projects) }.not_to exceed_query_limit(0)

        expect(access_levels(projects)).to eq(expected)
      end

      it 'only requests the extra projects when uncached projects are passed' do
3074
        second_maintainer_project = create(:project)
3075
        second_developer_project = create(:project)
3076
        second_maintainer_project.add_maintainer(user)
3077 3078
        second_developer_project.add_developer(user)

3079
        all_projects = projects + [second_maintainer_project.id, second_developer_project.id]
3080

3081
        expected_all = expected.merge(second_maintainer_project.id => Gitlab::Access::MAINTAINER,
3082 3083 3084 3085 3086 3087 3088
                                      second_developer_project.id => Gitlab::Access::DEVELOPER)

        access_levels(projects)

        queries = ActiveRecord::QueryRecorder.new { access_levels(all_projects) }

        expect(queries.count).to eq(1)
3089
        expect(queries.log_message).to match(/\W(#{second_maintainer_project.id}, #{second_developer_project.id})\W/)
3090 3091 3092 3093 3094 3095 3096 3097 3098 3099 3100 3101 3102
        expect(access_levels(all_projects)).to eq(expected_all)
      end
    end

    context 'with RequestStore disabled' do
      include_examples 'max member access for projects'
    end
  end

  describe '#max_member_access_for_group_ids' do
    shared_examples 'max member access for groups' do
      let(:user) { create(:user) }
      let(:owner_group) { create(:group) }
3103
      let(:maintainer_group) { create(:group) }
3104 3105 3106 3107 3108 3109
      let(:reporter_group) { create(:group) }
      let(:developer_group) { create(:group) }
      let(:guest_group) { create(:group) }
      let(:no_access_group) { create(:group) }

      let(:groups) do
3110
        [owner_group, maintainer_group, reporter_group, developer_group, guest_group, no_access_group].map(&:id)
3111 3112 3113 3114 3115
      end

      let(:expected) do
        {
          owner_group.id => Gitlab::Access::OWNER,
3116
          maintainer_group.id => Gitlab::Access::MAINTAINER,
3117 3118 3119 3120 3121 3122 3123 3124 3125
          reporter_group.id => Gitlab::Access::REPORTER,
          developer_group.id => Gitlab::Access::DEVELOPER,
          guest_group.id => Gitlab::Access::GUEST,
          no_access_group.id => Gitlab::Access::NO_ACCESS
        }
      end

      before do
        owner_group.add_owner(user)
3126
        maintainer_group.add_maintainer(user)
3127 3128 3129 3130 3131 3132 3133 3134 3135 3136 3137 3138 3139 3140 3141 3142 3143 3144 3145 3146 3147 3148 3149 3150 3151 3152
        reporter_group.add_reporter(user)
        developer_group.add_developer(user)
        guest_group.add_guest(user)
      end

      it 'returns correct roles for different groups' do
        expect(user.max_member_access_for_group_ids(groups)).to eq(expected)
      end
    end

    context 'with RequestStore enabled', :request_store do
      include_examples 'max member access for groups'

      def access_levels(groups)
        user.max_member_access_for_group_ids(groups)
      end

      it 'does not perform extra queries when asked for groups who have already been found' do
        access_levels(groups)

        expect { access_levels(groups) }.not_to exceed_query_limit(0)

        expect(access_levels(groups)).to eq(expected)
      end

      it 'only requests the extra groups when uncached groups are passed' do
3153
        second_maintainer_group = create(:group)
3154
        second_developer_group = create(:group)
3155
        second_maintainer_group.add_maintainer(user)
3156 3157
        second_developer_group.add_developer(user)

3158
        all_groups = groups + [second_maintainer_group.id, second_developer_group.id]
3159

3160
        expected_all = expected.merge(second_maintainer_group.id => Gitlab::Access::MAINTAINER,
3161 3162 3163 3164 3165 3166 3167
                                      second_developer_group.id => Gitlab::Access::DEVELOPER)

        access_levels(groups)

        queries = ActiveRecord::QueryRecorder.new { access_levels(all_groups) }

        expect(queries.count).to eq(1)
3168
        expect(queries.log_message).to match(/\W(#{second_maintainer_group.id}, #{second_developer_group.id})\W/)
3169 3170 3171 3172 3173 3174 3175 3176
        expect(access_levels(all_groups)).to eq(expected_all)
      end
    end

    context 'with RequestStore disabled' do
      include_examples 'max member access for groups'
    end
  end
3177

B
Bob Van Landuyt 已提交
3178 3179
  context 'changing a username' do
    let(:user) { create(:user, username: 'foo') }
3180

B
Bob Van Landuyt 已提交
3181 3182 3183
    it 'creates a redirect route' do
      expect { user.update!(username: 'bar') }
        .to change { RedirectRoute.where(path: 'foo').count }.by(1)
3184 3185
    end

B
Bob Van Landuyt 已提交
3186 3187 3188 3189 3190
    it 'deletes the redirect when a user with the old username was created' do
      user.update!(username: 'bar')

      expect { create(:user, username: 'foo') }
        .to change { RedirectRoute.where(path: 'foo').count }.by(-1)
3191 3192
    end
  end
3193 3194 3195 3196 3197 3198 3199 3200 3201 3202 3203 3204 3205 3206 3207 3208 3209 3210 3211 3212 3213 3214 3215 3216 3217 3218

  describe '#required_terms_not_accepted?' do
    let(:user) { build(:user) }
    subject { user.required_terms_not_accepted? }

    context "when terms are not enforced" do
      it { is_expected.to be_falsy }
    end

    context "when terms are enforced and accepted by the user" do
      before do
        enforce_terms
        accept_terms(user)
      end

      it { is_expected.to be_falsy }
    end

    context "when terms are enforced but the user has not accepted" do
      before do
        enforce_terms
      end

      it { is_expected.to be_truthy }
    end
  end
3219 3220 3221 3222 3223 3224 3225 3226 3227 3228 3229 3230 3231 3232

  describe '#increment_failed_attempts!' do
    subject(:user) { create(:user, failed_attempts: 0) }

    it 'logs failed sign-in attempts' do
      expect { user.increment_failed_attempts! }.to change(user, :failed_attempts).from(0).to(1)
    end

    it 'does not log failed sign-in attempts when in a GitLab read-only instance' do
      allow(Gitlab::Database).to receive(:read_only?) { true }

      expect { user.increment_failed_attempts! }.not_to change(user, :failed_attempts)
    end
  end
J
Jan Provaznik 已提交
3233

3234 3235 3236 3237 3238 3239 3240 3241 3242 3243 3244 3245 3246 3247 3248 3249 3250 3251 3252 3253 3254 3255 3256 3257 3258 3259 3260 3261 3262 3263 3264 3265 3266 3267 3268 3269 3270 3271 3272 3273 3274 3275
  describe '#requires_usage_stats_consent?' do
    let(:user) { create(:user, created_at: 8.days.ago) }

    before do
      allow(user).to receive(:has_current_license?).and_return false
    end

    context 'in single-user environment' do
      it 'requires user consent after one week' do
        create(:user, ghost: true)

        expect(user.requires_usage_stats_consent?).to be true
      end

      it 'requires user consent after one week if there is another ghost user' do
        expect(user.requires_usage_stats_consent?).to be true
      end

      it 'does not require consent in the first week' do
        user.created_at = 6.days.ago

        expect(user.requires_usage_stats_consent?).to be false
      end

      it 'does not require consent if usage stats were set by this user' do
        allow(Gitlab::CurrentSettings).to receive(:usage_stats_set_by_user_id).and_return(user.id)

        expect(user.requires_usage_stats_consent?).to be false
      end
    end

    context 'in multi-user environment' do
      before do
        create(:user)
      end

      it 'does not require consent' do
        expect(user.requires_usage_stats_consent?).to be false
      end
    end
  end

J
Jan Provaznik 已提交
3276
  context 'with uploads' do
3277
    it_behaves_like 'model with uploads', false do
J
Jan Provaznik 已提交
3278 3279 3280 3281 3282
      let(:model_object) { create(:user, :with_avatar) }
      let(:upload_attribute) { :avatar }
      let(:uploader_class) { AttachmentUploader }
    end
  end
Y
Yorick Peterse 已提交
3283 3284 3285 3286 3287 3288 3289 3290 3291 3292 3293 3294 3295 3296 3297 3298 3299 3300 3301 3302 3303 3304 3305 3306 3307 3308 3309 3310 3311 3312 3313 3314 3315 3316 3317 3318 3319 3320 3321 3322 3323 3324 3325 3326 3327 3328 3329 3330 3331 3332 3333 3334 3335 3336 3337 3338 3339 3340 3341 3342 3343 3344 3345 3346 3347 3348 3349 3350 3351 3352 3353 3354 3355 3356 3357 3358 3359 3360 3361 3362 3363 3364

  describe '.union_with_user' do
    context 'when no user ID is provided' do
      it 'returns the input relation' do
        user = create(:user)

        expect(described_class.union_with_user).to eq([user])
      end
    end

    context 'when a user ID is provided' do
      it 'includes the user object in the returned relation' do
        user1 = create(:user)
        user2 = create(:user)
        users = described_class.where(id: user1.id).union_with_user(user2.id)

        expect(users).to include(user1)
        expect(users).to include(user2)
      end

      it 'does not re-apply any WHERE conditions on the outer query' do
        relation = described_class.where(id: 1).union_with_user(2)

        expect(relation.arel.where_sql).to be_nil
      end
    end
  end

  describe '.optionally_search' do
    context 'using nil as the argument' do
      it 'returns the current relation' do
        user = create(:user)

        expect(described_class.optionally_search).to eq([user])
      end
    end

    context 'using an empty String as the argument' do
      it 'returns the current relation' do
        user = create(:user)

        expect(described_class.optionally_search('')).to eq([user])
      end
    end

    context 'using a non-empty String' do
      it 'returns users matching the search query' do
        user1 = create(:user)
        create(:user)

        expect(described_class.optionally_search(user1.name)).to eq([user1])
      end
    end
  end

  describe '.where_not_in' do
    context 'without an argument' do
      it 'returns the current relation' do
        user = create(:user)

        expect(described_class.where_not_in).to eq([user])
      end
    end

    context 'using a list of user IDs' do
      it 'excludes the users from the returned relation' do
        user1 = create(:user)
        user2 = create(:user)

        expect(described_class.where_not_in([user2.id])).to eq([user1])
      end
    end
  end

  describe '.reorder_by_name' do
    it 'reorders the input relation' do
      user1 = create(:user, name: 'A')
      user2 = create(:user, name: 'B')

      expect(described_class.reorder_by_name).to eq([user1, user2])
    end
  end
G
gitlabhq 已提交
3365
end