Read about our upcoming Code of Conduct on this issue

user_spec.rb 56.1 KB
Newer Older
gitlabhq's avatar
gitlabhq committed
1
2
require 'spec_helper'

Douwe Maan's avatar
Douwe Maan committed
3
describe User, models: true do
4
5
  include Gitlab::CurrentSettings

6
7
8
9
10
11
12
13
14
15
16
  describe 'modules' do
    subject { described_class }

    it { is_expected.to include_module(Gitlab::ConfigHelper) }
    it { is_expected.to include_module(Gitlab::CurrentSettings) }
    it { is_expected.to include_module(Referable) }
    it { is_expected.to include_module(Sortable) }
    it { is_expected.to include_module(TokenAuthenticatable) }
  end

  describe 'associations' do
17
    it { is_expected.to have_one(:namespace) }
18
    it { is_expected.to have_many(:snippets).dependent(:destroy) }
19
20
21
    it { is_expected.to have_many(:project_members).dependent(:destroy) }
    it { is_expected.to have_many(:groups) }
    it { is_expected.to have_many(:keys).dependent(:destroy) }
22
    it { is_expected.to have_many(:deploy_keys).dependent(:destroy) }
23
    it { is_expected.to have_many(:events).dependent(:destroy) }
24
    it { is_expected.to have_many(:recent_events).class_name('Event') }
25
    it { is_expected.to have_many(:issues).dependent(:restrict_with_exception) }
26
27
28
    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) }
29
    it { is_expected.to have_many(:spam_logs).dependent(:destroy) }
30
    it { is_expected.to have_many(:todos).dependent(:destroy) }
31
    it { is_expected.to have_many(:award_emoji).dependent(:destroy) }
32
    it { is_expected.to have_many(:triggers).dependent(:destroy) }
33
34
    it { is_expected.to have_many(:builds).dependent(:nullify) }
    it { is_expected.to have_many(:pipelines).dependent(:nullify) }
35
    it { is_expected.to have_many(:chat_names).dependent(:destroy) }
36
    it { is_expected.to have_many(:uploads).dependent(:destroy) }
37
    it { is_expected.to have_many(:reported_abuse_reports).dependent(:destroy).class_name('AbuseReport') }
38

39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
    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
65
66
67
68

    describe '#group_members' do
      it 'does not include group memberships for which user is a requester' do
        user = create(:user)
69
        group = create(:group, :public, :access_requestable)
70
71
72
73
74
75
76
77
78
        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)
79
        project = create(:empty_project, :public, :access_requestable)
80
81
82
83
84
        project.request_access(user)

        expect(user.project_members).to be_empty
      end
    end
85
86
87
  end

  describe 'validations' do
88
89
90
91
92
93
94
95
96
97
98
99
    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
        expect(user.errors.values).to eq [['dashboard is a reserved name']]
      end

100
101
102
103
104
105
106
107
108
109
110
111
      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

112
      it 'validates uniqueness' do
113
        expect(subject).to validate_uniqueness_of(:username).case_insensitive
114
115
116
      end
    end

117
118
119
120
    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) }
121
    it { is_expected.not_to allow_value(Gitlab::Database::MAX_INT_VALUE + 1).for(:projects_limit) }
122

123
    it { is_expected.to validate_length_of(:bio).is_at_most(255) }
124

125
126
127
    it_behaves_like 'an object with email-formated attributes', :email do
      subject { build(:user) }
    end
128

129
130
131
    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
132

133
    describe 'email' do
134
      context 'when no signup domains whitelisted' do
135
        before do
136
          allow_any_instance_of(ApplicationSetting).to receive(:domain_whitelist).and_return([])
137
        end
138

139
140
141
142
143
144
        it 'accepts any email' do
          user = build(:user, email: "info@example.com")
          expect(user).to be_valid
        end
      end

145
      context 'when a signup domain is whitelisted and subdomains are allowed' do
146
        before do
147
          allow_any_instance_of(ApplicationSetting).to receive(:domain_whitelist).and_return(['example.com', '*.example.com'])
148
        end
149

150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
        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

166
      context 'when a signup domain is whitelisted and subdomains are not allowed' do
167
        before do
168
          allow_any_instance_of(ApplicationSetting).to receive(:domain_whitelist).and_return(['example.com'])
169
        end
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184

        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
185
186
187
188
189

        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
190
      end
191

192
193
194
195
196
197
      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

198
        context 'when a signup domain is blacklisted' do
199
200
201
202
203
204
205
206
207
          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
208
209
210
211
212

          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
213
214
        end

215
        context 'when a signup domain is blacklisted but a wildcard subdomain is allowed' do
216
217
          before do
            allow_any_instance_of(ApplicationSetting).to receive(:domain_blacklist).and_return(['test.example.com'])
218
            allow_any_instance_of(ApplicationSetting).to receive(:domain_whitelist).and_return(['*.example.com'])
219
220
          end

221
          it 'gives priority to whitelist and allow info@test.example.com' do
222
223
224
225
226
227
228
            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
229
            allow_any_instance_of(ApplicationSetting).to receive(:domain_whitelist).and_return(['test.com'])
230
231
232
233
234
235
236
237
238
239
240
241
242
243
          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

244
245
246
247
248
249
      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
250
    end
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
  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)
        users_with_two_factor = User.with_two_factor.pluck(:id)

        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)
        users_with_two_factor = User.with_two_factor.pluck(:id)

        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)
        users_with_two_factor = User.with_two_factor.pluck(:id)

        expect(users_with_two_factor).to eq([user_with_2fa.id])
        expect(users_with_two_factor).not_to include(user_without_2fa.id)
      end
    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)
        users_without_two_factor = User.without_two_factor.pluck(:id)

        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)
        users_without_two_factor = User.without_two_factor.pluck(:id)

        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)
        users_without_two_factor = User.without_two_factor.pluck(:id)

        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
311
312
313
314
315
316
317
318
319
320
321
322
323
324

    describe '.todo_authors' do
      it 'filters users' do
        create :user
        user_2 = create :user
        user_3 = create :user
        current_user = create :user
        create(:todo, user: current_user, author: user_2, state: :done)
        create(:todo, user: current_user, author: user_3, state: :pending)

        expect(User.todo_authors(current_user.id, 'pending')).to eq [user_3]
        expect(User.todo_authors(current_user.id, 'done')).to eq [user_2]
      end
    end
gitlabhq's avatar
gitlabhq committed
325
326
327
  end

  describe "Respond to" do
blackst0ne's avatar
blackst0ne committed
328
    it { is_expected.to respond_to(:admin?) }
329
330
    it { is_expected.to respond_to(:name) }
    it { is_expected.to respond_to(:private_token) }
Zeger-Jan van de Weg's avatar
Zeger-Jan van de Weg committed
331
332
333
334
335
336
337
338
339
340
341
342
343
344
    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
gitlabhq's avatar
gitlabhq committed
345
346
  end

347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
  describe '#update_tracked_fields!', :redis do
    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)
362
363
364
365
366
367
368
369
370
371
372
      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 }
373
374
375
    end
  end

376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
  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

404
  describe '#confirm' do
405
406
407
    before do
      allow_any_instance_of(ApplicationSetting).to receive(:send_user_confirmation_email).and_return(true)
    end
408

409
410
411
412
413
414
415
    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
416
      user.confirm
417
418
419
420
      expect(user.confirmed?).to be_truthy
    end
  end

421
422
423
424
425
426
427
428
  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

429
  describe '#generate_password' do
430
    it "does not generate password by default" do
431
      user = create(:user, password: 'abcdefghe')
432
      expect(user.password).to eq('abcdefghe')
433
    end
434
435
  end

436
  describe 'authentication token' do
437
    it "has authentication token" do
438
      user = create(:user)
439
      expect(user.authentication_token).not_to be_blank
440
    end
Nihad Abbasov's avatar
Nihad Abbasov committed
441
  end
442

443
  describe '#recently_sent_password_reset?' do
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
    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

Robert Speicher's avatar
Robert Speicher committed
463
464
465
466
467
468
469
  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
470
      expect(user.otp_grace_period_started_at).not_to be_nil
Robert Speicher's avatar
Robert Speicher committed
471
472
473
474
475
476
477
478

      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
479
      expect(user.otp_grace_period_started_at).to be_nil
Robert Speicher's avatar
Robert Speicher committed
480
481
482
    end
  end

483
484
  describe 'projects' do
    before do
485
      @user = create(:user)
486

487
488
489
490
491
492
493
      @project = create(:empty_project, namespace: @user.namespace)
      @project_2 = create(:empty_project, group: create(:group)) do |project|
        project.add_master(@user)
      end
      @project_3 = create(:empty_project, group: create(:group)) do |project|
        project.add_developer(@user)
      end
494
495
    end

496
497
498
499
500
501
502
503
504
    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) }
505
506
507
508
509
  end

  describe 'groups' do
    before do
      @user = create :user
510
511
      @group = create :group
      @group.add_owner(@user)
512
513
    end

514
515
516
    it { expect(@user.several_namespaces?).to be_truthy }
    it { expect(@user.authorized_groups).to eq([@group]) }
    it { expect(@user.owned_groups).to eq([@group]) }
517
    it { expect(@user.namespaces).to match_array([@user.namespace, @group]) }
518
519
  end

520
521
522
523
  describe 'group multiple owners' do
    before do
      @user = create :user
      @user2 = create :user
524
525
      @group = create :group
      @group.add_owner(@user)
526

527
      @group.add_user(@user2, GroupMember::OWNER)
528
529
    end

530
    it { expect(@user2.several_namespaces?).to be_truthy }
531
532
  end

533
534
535
  describe 'namespaced' do
    before do
      @user = create :user
536
      @project = create(:empty_project, namespace: @user.namespace)
537
538
    end

539
    it { expect(@user.several_namespaces?).to be_falsey }
540
    it { expect(@user.namespaces).to eq([@user.namespace]) }
541
542
543
544
545
  end

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

546
    it "blocks user" do
547
      user.block
548
      expect(user.blocked?).to be_truthy
549
550
551
    end
  end

552
553
554
555
556
557
558
  describe '.filter' do
    let(:user) { double }

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

      expect(User.filter(nil)).to include user
559
560
    end

561
562
563
564
    it 'filters by admins' do
      expect(User).to receive(:admins).and_return([user])

      expect(User.filter('admins')).to include user
565
566
    end

567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
    it 'filters by blocked' do
      expect(User).to receive(:blocked).and_return([user])

      expect(User.filter('blocked')).to include user
    end

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

      expect(User.filter('two_factor_disabled')).to include user
    end

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

      expect(User.filter('two_factor_enabled')).to include user
    end

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

      expect(User.filter('wop')).to include user
    end
590
591
  end

592
  describe '.without_projects' do
593
    let!(:project) { create(:empty_project, :public, :access_requestable) }
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
    let!(:user) { create(:user) }
    let!(:user_without_project) { create(:user) }
    let!(:user_without_project2) { create(:user) }

    before do
      # add user to project
      project.team << [user, :master]

      # 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

    it { expect(User.without_projects).not_to include user }
    it { expect(User.without_projects).to include user_without_project }
    it { expect(User.without_projects).to include user_without_project2 }
  end

614
  describe '.not_in_project' do
615
    before do
616
      User.delete_all
617
      @user = create :user
618
      @project = create(:empty_project)
619
620
    end

621
    it { expect(User.not_in_project(@project)).to include(@user, @project.owner) }
622
  end
Dmitriy Zaporozhets's avatar
Dmitriy Zaporozhets committed
623

624
625
626
  describe 'user creation' do
    describe 'normal user' do
      let(:user) { create(:user, name: 'John Smith') }
Dmitriy Zaporozhets's avatar
Dmitriy Zaporozhets committed
627

blackst0ne's avatar
blackst0ne committed
628
      it { expect(user.admin?).to be_falsey }
629
630
631
632
      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') }
633
      it { expect(user.external).to be_falsey }
634
    end
635

Dmitriy Zaporozhets's avatar
Dmitriy Zaporozhets committed
636
    describe 'with defaults' do
637
      let(:user) { User.new }
Dmitriy Zaporozhets's avatar
Dmitriy Zaporozhets committed
638

639
      it "applies defaults to user" do
640
641
        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)
Zeger-Jan van de Weg's avatar
Zeger-Jan van de Weg committed
642
        expect(user.external).to be_falsey
643
644
645
      end
    end

Dmitriy Zaporozhets's avatar
Dmitriy Zaporozhets committed
646
    describe 'with default overrides' do
647
      let(:user) { User.new(projects_limit: 123, can_create_group: false, can_create_team: true) }
Dmitriy Zaporozhets's avatar
Dmitriy Zaporozhets committed
648

649
      it "applies defaults to user" do
650
651
        expect(user.projects_limit).to eq(123)
        expect(user.can_create_group).to be_falsey
652
      end
653
    end
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673

    context 'when current_application_settings.user_default_external is true' do
      before do
        stub_application_setting(user_default_external: true)
      end

      it "creates external user by default" do
        user = build(:user)

        expect(user.external).to be_truthy
      end

      describe 'with default overrides' do
        it "creates a non-external user" do
          user = build(:user, external: false)

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

675
676
677
678
679
680
681
682
683
684
685
686
687
688
    describe '#require_ssh_key?' do
      protocol_and_expectation = {
        'http' => false,
        'ssh' => true,
        '' => true,
      }

      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
689
690
      end
    end
691
  end
692

693
  describe '.find_by_any_email' do
694
695
696
    it 'finds by primary email' do
      user = create(:user, email: 'foo@example.com')

697
      expect(User.find_by_any_email(user.email)).to eq user
698
699
700
701
702
703
    end

    it 'finds by secondary email' do
      email = create(:email, email: 'foo@example.com')
      user  = email.user

704
      expect(User.find_by_any_email(email.email)).to eq user
705
706
707
    end

    it 'returns nil when nothing found' do
708
      expect(User.find_by_any_email('')).to be_nil
709
710
711
    end
  end

712
713
714
715
716
717
718
719
720
721
722
  describe '.search' do
    let(:user) { create(:user) }

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

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

Yorick Peterse's avatar
Yorick Peterse committed
723
    it 'returns users with a matching name regardless of the casing' do
724
725
726
727
728
729
730
731
732
733
734
      expect(described_class.search(user.name.upcase)).to eq([user])
    end

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

    it 'returns users with a partially matching Email' do
      expect(described_class.search(user.email[0..2])).to eq([user])
    end

Yorick Peterse's avatar
Yorick Peterse committed
735
    it 'returns users with a matching Email regardless of the casing' do
736
737
738
739
740
741
742
743
744
745
746
      expect(described_class.search(user.email.upcase)).to eq([user])
    end

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

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

Yorick Peterse's avatar
Yorick Peterse committed
747
    it 'returns users with a matching username regardless of the casing' do
748
      expect(described_class.search(user.username.upcase)).to eq([user])
749
    end
750
751
752
  end

  describe '.search_with_secondary_emails' do
Douwe Maan's avatar
Douwe Maan committed
753
    delegate :search_with_secondary_emails, to: :described_class
754

755
756
    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' ) }
757
758
759
    let!(:email) do
      create(:email, user: another_user, email: 'alias@example.com')
    end
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824

    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

    it 'returns users with a partially matching email' do
      expect(search_with_secondary_emails(user.email[0..2])).to eq([user])
    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

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

    it 'return users with a matching part of secondary email regardless of case' do
      expect(search_with_secondary_emails(email.email[1..4].upcase)).to eq([email.user])
      expect(search_with_secondary_emails(email.email[1..4].downcase)).to eq([email.user])
      expect(search_with_secondary_emails(email.email[1..4].capitalize)).to eq([email.user])
    end

    it 'returns multiple users with matching secondary emails' do
      email1 = create(:email, email: '1_testemail@example.com')
      email2 = create(:email, email: '2_testemail@example.com')
      email3 = create(:email, email: 'other@email.com')
      email3.user.update_attributes!(email: 'another@mail.com')

      expect(
        search_with_secondary_emails('testemail@example.com').map(&:id)
      ).to include(email1.user.id, email2.user.id)

      expect(
        search_with_secondary_emails('testemail@example.com').map(&:id)
      ).not_to include(email3.user.id)
    end
825
826
  end

Yorick Peterse's avatar
Yorick Peterse committed
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
  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

844
845
846
847
  describe '.by_login' do
    let(:username) { 'John' }
    let!(:user) { create(:user, username: username) }

848
    it 'gets the correct user' do
849
850
851
852
853
854
855
856
857
      expect(User.by_login(user.email.upcase)).to eq user
      expect(User.by_login(user.email)).to eq user
      expect(User.by_login(username.downcase)).to eq user
      expect(User.by_login(username)).to eq user
      expect(User.by_login(nil)).to be_nil
      expect(User.by_login('')).to be_nil
    end
  end

858
859
860
861
862
863
864
865
866
867
868
  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')
      expect(described_class.find_by_username('JOHNDOE')).to eq user
    end
  end

Robert Speicher's avatar
Robert Speicher committed
869
870
  describe '.find_by_username!' do
    it 'raises RecordNotFound' do
871
872
      expect { described_class.find_by_username!('JohnDoe') }.
        to raise_error(ActiveRecord::RecordNotFound)
Robert Speicher's avatar
Robert Speicher committed
873
874
875
876
877
878
879
880
    end

    it 'is case-insensitive' do
      user = create(:user, username: 'JohnDoe')
      expect(described_class.find_by_username!('JOHNDOE')).to eq user
    end
  end

881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
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
928
929
930
931
932
933
934
935
936
937
938
939
  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
        expect(User.find_by_full_path(route.path)).to eq(user)
      end

      it 'is case-insensitive' do
        expect(User.find_by_full_path(route.path.upcase)).to eq(user)
        expect(User.find_by_full_path(route.path.downcase)).to eq(user)
      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
          expect(User.find_by_full_path(redirect_route.path)).to eq(nil)
        end
      end

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

        it 'is case-insensitive' do
          expect(User.find_by_full_path(redirect_route.path.upcase, follow_redirects: true)).to eq(user)
          expect(User.find_by_full_path(redirect_route.path.downcase, follow_redirects: true)).to eq(user)
        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
          expect(User.find_by_full_path('unknown')).to eq(nil)
        end
      end
      context 'with the follow_redirects option set to true' do
        it 'returns nil' do
          expect(User.find_by_full_path('unknown', follow_redirects: true)).to eq(nil)
        end
      end
    end

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

      it 'returns nil' do
        expect(User.find_by_full_path('group_path')).to eq(nil)
      end
    end
  end

GitLab's avatar
GitLab committed
940
  describe 'all_ssh_keys' do
941
    it { is_expected.to have_many(:keys).dependent(:destroy) }
GitLab's avatar
GitLab committed
942

943
    it "has all ssh keys" do
GitLab's avatar
GitLab committed
944
945
946
      user = create :user
      key = create :key, key: "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQD33bWLBxu48Sev9Fert1yzEO4WGcWglWF7K/AwblIUFselOt/QdOL9DSjpQGxLagO1s9wl53STIO8qGS4Ms0EJZyIXOEFMjFJ5xmjSy+S37By4sG7SsltQEHMxtbtFOaW5LV2wCrX+rUsRNqLMamZjgjcPO0/EgGCXIGMAYW4O7cwGZdXWYIhQ1Vwy+CsVMDdPkPgBXqK7nR/ey8KMs8ho5fMNgB5hBw/AL9fNGhRw3QTD6Q12Nkhl4VZES2EsZqlpNnJttnPdp847DUsT6yuLRlfiQfz5Cn9ysHFdXObMN5VYIiPFwHeYCZp1X2S4fDZooRE8uOLTfxWHPXwrhqSH", user_id: user.id

947
      expect(user.all_ssh_keys).to include(a_string_starting_with(key.key))
GitLab's avatar
GitLab committed
948
    end
GitLab's avatar
GitLab committed
949
  end
950

951
  describe '#avatar_type' do
952
953
    let(:user) { create(:user) }

954
    it 'is true if avatar is image' do
955
      user.update_attribute(:avatar, 'uploads/avatar.png')
956
      expect(user.avatar_type).to be_truthy
957
958
    end

959
    it 'is false if avatar is html page' do
960
      user.update_attribute(:avatar, 'uploads/avatar.html')
961
      expect(user.avatar_type).to eq(['only images allowed'])
962
963
    end
  end
Jerome Dalbert's avatar
Jerome Dalbert committed
964

965
966
967
968
  describe '#avatar_url' do
    let(:user) { create(:user, :with_avatar) }

    context 'when avatar file is uploaded' do
969
      let(:gitlab_host) { "http://#{Gitlab.config.gitlab.host}" }
970
971
      let(:avatar_path) { "/uploads/user/avatar/#{user.id}/dk.png" }

972
973
974
975
976
977
978
979
      it 'shows correct avatar url' do
        expect(user.avatar_url).to eq(avatar_path)
        expect(user.avatar_url(only_path: false)).to eq([gitlab_host, avatar_path].join)

        allow(ActionController::Base).to receive(:asset_host).and_return(gitlab_host)

        expect(user.avatar_url).to eq([gitlab_host, avatar_path].join)
      end
980
981
982
    end
  end

983
  describe '#requires_ldap_check?' do
984
985
    let(:user) { User.new }

986
987
    it 'is false when LDAP is disabled' do
      # Create a condition which would otherwise cause 'true' to be returned
988
      allow(user).to receive(:ldap_user?).and_return(true)
989
      user.last_credential_check_at = nil
990
      expect(user.requires_ldap_check?).to be_falsey
991
992
    end

993
    context 'when LDAP is enabled' do
994
995
996
      before do
        allow(Gitlab.config.ldap).to receive(:enabled).and_return(true)
      end
997

998
      it 'is false for non-LDAP users' do
999
        allow(user).to receive(:ldap_user?).and_return(false)
1000
        expect(user.requires_ldap_check?).to be_falsey
1001
1002
      end

1003
      context 'and when the user is an LDAP user' do
1004
1005
1006
        before do
          allow(user).to receive(:ldap_user?).and_return(true)
        end
1007
1008
1009

        it 'is true when the user has never had an LDAP check before' do
          user.last_credential_check_at = nil
1010
          expect(user.requires_ldap_check?).to be_truthy
1011
1012
1013
1014
        end

        it 'is true when the last LDAP check happened over 1 hour ago' do
          user.last_credential_check_at = 2.hours.ago
1015
          expect(user.requires_ldap_check?).to be_truthy
1016
        end
1017
1018
1019
1020
      end
    end
  end

1021
  context 'ldap synchronized user' do
1022
    describe '#ldap_user?' do
1023
1024
1025
1026
      it 'is true if provider name starts with ldap' do
        user = create(:omniauth_user, provider: 'ldapmain')
        expect(user.ldap_user?).to be_truthy
      end
1027

1028
1029
1030
1031
1032
1033
1034
1035
1036
      it 'is false for other providers' do
        user = create(:omniauth_user, provider: 'other-provider')
        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)
        expect(user.ldap_user?).to be_falsey
      end
1037
1038
    end

1039
    describe '#ldap_identity' do
1040
1041
1042
1043
      it 'returns ldap identity' do
        user = create :omniauth_user
        expect(user.ldap_identity.provider).not_to be_empty
      end
1044
1045
    end

1046
1047
1048
1049
1050
1051
1052
1053
    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
        expect(user.blocked?).to be_truthy
        expect(user.ldap_blocked?).to be_truthy
      end
1054
1055
1056
    end
  end

Jerome Dalbert's avatar
Jerome Dalbert committed
1057
1058
1059
1060
1061
1062
1063
1064
1065
1066
1067
1068
1069
1070
1071
1072
1073
1074
1075
1076
1077
1078
1079
1080
1081
1082
1083
1084
1085
1086
1087
1088
1089
1090
1091
1092
1093
1094
1095
  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'
1096

Jerome Dalbert's avatar
Jerome Dalbert committed
1097
1098
      expect(user.short_website_url).to eq 'test.com'
    end
GitLab's avatar
GitLab committed
1099
  end
Ciro Santilli's avatar
Ciro Santilli committed
1100

1101
1102
  describe '#starred?' do
    it 'determines if user starred a project' do
1103
      user = create :user
1104
1105
      project1 = create(:empty_project, :public)
      project2 = create(:empty_project, :public)
1106

1107
1108
      expect(user.starred?(project1)).to be_falsey
      expect(user.starred?(project2)).to be_falsey
1109
1110

      star1 = UsersStarProject.create!(project: project1, user: user)
1111
1112
      expect(user.starred?(project1)).to be_truthy
      expect(user.starred?(project2)).to be_falsey
1113
1114

      star2 = UsersStarProject.create!(project: project2, user: user)
1115
1116
      expect(user.starred?(project1)).to be_truthy
      expect(user.starred?(project2)).to be_truthy
1117
1118

      star1.destroy
1119
1120
      expect(user.starred?(project1)).to be_falsey
      expect(user.starred?(project2)).to be_truthy
1121
1122

      star2.destroy
1123
1124
      expect(user.starred?(project1)).to be_falsey
      expect(user.starred?(project2)).to be_falsey
1125
1126
1127
    end
  end

1128
1129
  describe '#toggle_star' do
    it 'toggles stars' do
Ciro Santilli's avatar
Ciro Santilli committed
1130
      user = create :user
1131
      project = create(:empty_project, :public)
Ciro Santilli's avatar
Ciro Santilli committed
1132

1133
      expect(user.starred?(project)).to be_falsey
Ciro Santilli's avatar
Ciro Santilli committed
1134
      user.toggle_star(project)
1135
      expect(user.starred?(project)).to be_truthy
Ciro Santilli's avatar
Ciro Santilli committed
1136
      user.toggle_star(project)
1137
      expect(user.starred?(project)).to be_falsey
Ciro Santilli's avatar
Ciro Santilli committed
1138
1139
    end
  end
Valery Sizov's avatar
Valery Sizov committed
1140

1141
  describe '#sort' do
Valery Sizov's avatar
Valery Sizov committed
1142
1143
1144
1145
    before do
      User.delete_all
      @user = create :user, created_at: Date.today, last_sign_in_at: Date.today, name: 'Alpha'
      @user1 = create :user, created_at: Date.today - 1, last_sign_in_at: Date.today - 1, name: 'Omega'
1146
      @user2 = create :user, created_at: Date.today - 2, last_sign_in_at: nil, name: 'Beta'
Valery Sizov's avatar
Valery Sizov committed
1147
    end
1148

1149
1150
1151
1152
1153
1154
1155
1156
    context 'when sort by recent_sign_in' do
      it 'sorts users by the recent sign-in time' do
        expect(User.sort('recent_sign_in').first).to eq(@user)
      end

      it 'pushes users who never signed in to the end' do
        expect(User.sort('recent_sign_in').third).to eq(@user2)
      end
Valery Sizov's avatar
Valery Sizov committed
1157
1158
    end

1159
1160
1161
1162
1163
1164
1165
1166
    context 'when sort by oldest_sign_in' do
      it 'sorts users by the oldest sign-in time' do
        expect(User.sort('oldest_sign_in').first).to eq(@user1)
      end

      it 'pushes users who never signed in to the end' do
        expect(User.sort('oldest_sign_in').third).to eq(@user2)
      end
Valery Sizov's avatar
Valery Sizov committed
1167
1168
    end

1169
    it 'sorts users in descending order by their creation time' do
1170
      expect(User.sort('created_desc').first).to eq(@user)
Valery Sizov's avatar
Valery Sizov committed
1171
1172
    end

1173
1174
    it 'sorts users in ascending order by their creation time' do
      expect(User.sort('created_asc').first).to eq(@user2)
Valery Sizov's avatar
Valery Sizov committed
1175
1176
    end

1177
1178
    it 'sorts users by id in descending order when nil is passed' do
      expect(User.sort(nil).first).to eq(@user2)
Valery Sizov's avatar
Valery Sizov committed
1179
1180
    end
  end
1181

1182
  describe "#contributed_projects" do
1183
    subject { create(:user) }
1184
1185
1186
    let!(:project1) { create(:empty_project) }
    let!(:project2) { create(:empty_project, forked_from_project: project3) }
    let!(:project3) { create(:empty_project) }
1187
    let!(:merge_request) { create(:merge_request, source_project: project2, target_project: project3, author: subject) }
1188
1189
    let!(:push_event) { create(:event, :pushed, project: project1, target: project1, author: subject) }
    let!(:merge_event) { create(:event, :created, project: project3, target: merge_request, author: subject) }
1190
1191
1192
1193
1194
1195
1196

    before do
      project1.team << [subject, :master]
      project2.team << [subject, :master]
    end

    it "includes IDs for projects the user has pushed to" do
1197
      expect(subject.contributed_projects).to include(project1)
1198
1199
1200
    end

    it "includes IDs for projects the user has had merge requests merged into" do
1201
      expect(subject.contributed_projects).to include(project3)
1202
1203
1204
    end

    it "doesn't include IDs for unrelated projects" do
1205
      expect(subject.contributed_projects).not_to include(project2)
1206
1207
    end
  end
1208

1209
  describe '#can_be_removed?' do
1210
1211
1212
1213
1214
1215
1216
1217
1218
1219
1220
1221
1222
1223
1224
    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
1225
1226
1227

  describe "#recent_push" do
    subject { create(:user) }
1228
1229
    let!(:project1) { create(:project, :repository) }
    let!(:project2) { create(:project, :repository, forked_from_project: project1) }
1230
    let!(:push_data) do
1231
      Gitlab::DataBuilder::Push.build_sample(project2, subject)
1232
    end
1233
    let!(:push_event) { create(:event, :pushed, project: project2, target: project1, author: subject, data: push_data) }
1234
1235
1236
1237
1238
1239
1240
1241
1242
1243
1244
1245
1246
1247
1248
1249
1250
1251
1252
1253
1254

    before do
      project1.team << [subject, :master]
      project2.team << [subject, :master]
    end

    it "includes push event" do
      expect(subject.recent_push).to eq(push_event)
    end

    it "excludes push event if branch has been deleted" do
      allow_any_instance_of(Repository).to receive(:branch_names).and_return(['foo'])

      expect(subject.recent_push).to eq(nil)
    end

    it "excludes push event if MR is opened for it" do
      create(:merge_request, source_project: project2, target_project: project1, source_branch: project2.default_branch, target_branch: 'fix', author: subject)

      expect(subject.recent_push).to eq(nil)
    end
1255
1256
1257
1258
1259
1260

    it "includes push events on any of the provided projects" do
      expect(subject.recent_push(project1)).to eq(nil)
      expect(subject.recent_push(project2)).to eq(push_event)

      push_data1 = Gitlab::DataBuilder::Push.build_sample(project1, subject)
1261
      push_event1 = create(:event, :pushed, project: project1, target: project1, author: subject, data: push_data1)
1262
1263
1264

      expect(subject.recent_push([project1, project2])).to eq(push_event1) # Newest
    end
1265
  end
1266
1267
1268
1269
1270
1271
1272
1273
1274

  describe '#authorized_groups' do
    let!(:user) { create(:user) }
    let!(:private_group) { create(:group) }

    before do
      private_group.add_user(user, Gitlab::Access::MASTER)
    end

1275
    subject { user.authorized_groups }
1276

1277
    it { is_expected.to eq([private_group]) }
1278
1279
  end

1280
  describe '#authorized_projects', truncate: true do
1281
1282
1283
1284
    context 'with a minimum access level' do
      it 'includes projects for which the user is an owner' do
        user = create(:user)
        project = create(:empty_project, :private, namespace: user.namespace)
Yorick Peterse's avatar