issue_spec.rb 25.8 KB
Newer Older
1 2
# frozen_string_literal: true

G
gitlabhq 已提交
3 4
require 'spec_helper'

5
describe Issue do
6 7
  include ExternalAuthorizationServiceHelpers

G
gitlabhq 已提交
8
  describe "Associations" do
9
    it { is_expected.to belong_to(:milestone) }
10
    it { is_expected.to have_many(:assignees) }
G
gitlabhq 已提交
11 12
  end

13
  describe 'modules' do
14 15
    subject { described_class }

16
    it { is_expected.to include_module(Issuable) }
17 18 19
    it { is_expected.to include_module(Referable) }
    it { is_expected.to include_module(Sortable) }
    it { is_expected.to include_module(Taskable) }
20 21 22 23

    it_behaves_like 'AtomicInternalId' do
      let(:internal_id_attribute) { :iid }
      let(:instance) { build(:issue) }
24
      let(:scope) { :project }
25 26 27
      let(:scope_attrs) { { project: instance.project } }
      let(:usage) { :issues }
    end
28 29
  end

30
  subject { create(:issue) }
31

32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57
  describe 'callbacks' do
    describe '#ensure_metrics' do
      it 'creates metrics after saving' do
        issue = create(:issue)

        expect(issue.metrics).to be_persisted
        expect(Issue::Metrics.count).to eq(1)
      end

      it 'does not create duplicate metrics for an issue' do
        issue = create(:issue)

        issue.close!

        expect(issue.metrics).to be_persisted
        expect(Issue::Metrics.count).to eq(1)
      end

      it 'records current metrics' do
        expect_any_instance_of(Issue::Metrics).to receive(:record!)

        create(:issue)
      end
    end
  end

58
  describe 'locking' do
59
    using RSpec::Parameterized::TableSyntax
60

61 62 63 64 65 66 67 68 69 70
    where(:lock_version) do
      [
        [0],
        ["0"]
      ]
    end

    with_them do
      it 'works when an issue has a NULL lock_version' do
        issue = create(:issue)
71

72
        described_class.where(id: issue.id).update_all('lock_version = NULL')
73

74 75 76 77
        issue.update!(lock_version: lock_version, title: 'locking test')

        expect(issue.reload.title).to eq('locking test')
      end
78 79 80
    end
  end

81
  describe '#order_by_position_and_priority' do
82
    let(:project) { create :project }
83 84 85 86 87 88 89 90
    let(:p1) { create(:label, title: 'P1', project: project, priority: 1) }
    let(:p2) { create(:label, title: 'P2', project: project, priority: 2) }
    let!(:issue1) { create(:labeled_issue, project: project, labels: [p1]) }
    let!(:issue2) { create(:labeled_issue, project: project, labels: [p2]) }
    let!(:issue3) { create(:issue, project: project, relative_position: 100) }
    let!(:issue4) { create(:issue, project: project, relative_position: 200) }

    it 'returns ordered list' do
91 92
      expect(project.issues.order_by_position_and_priority)
        .to match [issue3, issue4, issue1, issue2]
93 94 95
    end
  end

96 97 98 99 100 101 102 103 104 105 106 107 108 109 110
  describe '#sort' do
    let(:project) { create(:project) }

    context "by relative_position" do
      let!(:issue)  { create(:issue, project: project) }
      let!(:issue2) { create(:issue, project: project, relative_position: 2) }
      let!(:issue3) { create(:issue, project: project, relative_position: 1) }

      it "sorts asc with nulls at the end" do
        issues = project.issues.sort_by_attribute('relative_position')
        expect(issues).to eq([issue3, issue2, issue])
      end
    end
  end

111 112 113 114 115
  describe '#card_attributes' do
    it 'includes the author name' do
      allow(subject).to receive(:author).and_return(double(name: 'Robert'))
      allow(subject).to receive(:assignees).and_return([])

116 117
      expect(subject.card_attributes)
        .to eq({ 'Author' => 'Robert', 'Assignee' => '' })
118 119 120 121 122 123
    end

    it 'includes the assignee name' do
      allow(subject).to receive(:author).and_return(double(name: 'Robert'))
      allow(subject).to receive(:assignees).and_return([double(name: 'Douwe')])

124 125
      expect(subject.card_attributes)
        .to eq({ 'Author' => 'Robert', 'Assignee' => 'Douwe' })
126 127 128
    end
  end

129 130
  describe '#close' do
    subject(:issue) { create(:issue, state: 'opened') }
F
Felipe Artur 已提交
131

132 133 134 135 136 137 138 139
    it 'sets closed_at to Time.now when an issue is closed' do
      expect { issue.close }.to change { issue.closed_at }.from(nil)
    end

    it 'changes the state to closed' do
      expect { issue.close }.to change { issue.state }.from('opened').to('closed')
    end
  end
R
Rémy Coutable 已提交
140

141 142 143 144 145 146 147 148 149 150 151
  describe '#reopen' do
    let(:user) { create(:user) }
    let(:issue) { create(:issue, state: 'closed', closed_at: Time.now, closed_by: user) }

    it 'sets closed_at to nil when an issue is reopend' do
      expect { issue.reopen }.to change { issue.closed_at }.to(nil)
    end

    it 'sets closed_by to nil when an issue is reopend' do
      expect { issue.reopen }.to change { issue.closed_by }.from(user).to(nil)
    end
F
Felipe Artur 已提交
152

153 154
    it 'changes the state to opened' do
      expect { issue.reopen }.to change { issue.state }.from('closed').to('opened')
F
Felipe Artur 已提交
155 156 157
    end
  end

158
  describe '#to_reference' do
159
    let(:namespace) { build(:namespace, path: 'sample-namespace') }
160
    let(:project)   { build(:project, name: 'sample-project', namespace: namespace) }
161 162
    let(:issue)     { build(:issue, iid: 1, project: project) }
    let(:group)     { create(:group, name: 'Group', path: 'sample-group') }
163

164 165 166 167
    context 'when nil argument' do
      it 'returns issue id' do
        expect(issue.to_reference).to eq "#1"
      end
168 169
    end

170
    context 'when full is true' do
171
      it 'returns complete path to the issue' do
172 173 174
        expect(issue.to_reference(full: true)).to          eq 'sample-namespace/sample-project#1'
        expect(issue.to_reference(project, full: true)).to eq 'sample-namespace/sample-project#1'
        expect(issue.to_reference(group, full: true)).to   eq 'sample-namespace/sample-project#1'
175
      end
176 177
    end

178 179 180 181 182 183 184
    context 'when same project argument' do
      it 'returns issue id' do
        expect(issue.to_reference(project)).to eq("#1")
      end
    end

    context 'when cross namespace project argument' do
185
      let(:another_namespace_project) { create(:project, name: 'another-project') }
186 187 188 189

      it 'returns complete path to the issue' do
        expect(issue.to_reference(another_namespace_project)).to eq 'sample-namespace/sample-project#1'
      end
190 191
    end

192
    it 'supports a cross-project reference' do
193
      another_project = build(:project, name: 'another-project', namespace: project.namespace)
194
      expect(issue.to_reference(another_project)).to eq "sample-project#1"
195
    end
196

197
    context 'when same namespace / cross-project argument' do
198
      let(:another_project) { create(:project, namespace: namespace) }
199 200 201 202 203 204 205 206

      it 'returns path to the issue with the project name' do
        expect(issue.to_reference(another_project)).to eq 'sample-project#1'
      end
    end

    context 'when different namespace / cross-project argument' do
      let(:another_namespace) { create(:namespace, path: 'another-namespace') }
207
      let(:another_project)   { create(:project, path: 'another-project', namespace: another_namespace) }
208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225

      it 'returns full path to the issue' do
        expect(issue.to_reference(another_project)).to eq 'sample-namespace/sample-project#1'
      end
    end

    context 'when argument is a namespace' do
      context 'with same project path' do
        it 'returns path to the issue with the project name' do
          expect(issue.to_reference(namespace)).to eq 'sample-project#1'
        end
      end

      context 'with different project path' do
        it 'returns full path to the issue' do
          expect(issue.to_reference(group)).to eq 'sample-namespace/sample-project#1'
        end
      end
226
    end
227 228
  end

229 230 231 232 233 234 235 236
  describe '#assignee_or_author?' do
    let(:user) { create(:user) }
    let(:issue) { create(:issue) }

    it 'returns true for a user that is assigned to an issue' do
      issue.assignees << user

      expect(issue.assignee_or_author?(user)).to be_truthy
237
    end
238 239 240 241 242 243 244 245 246

    it 'returns true for a user that is the author of an issue' do
      issue.update(author: user)

      expect(issue.assignee_or_author?(user)).to be_truthy
    end

    it 'returns false for a user that is not the assignee or author' do
      expect(issue.assignee_or_author?(user)).to be_falsey
247 248
    end
  end
A
Andrew8xx8 已提交
249

250 251 252 253 254 255 256 257 258 259
  describe '#can_move?' do
    let(:user) { create(:user) }
    let(:issue) { create(:issue) }
    subject { issue.can_move?(user) }

    context 'user is not a member of project issue belongs to' do
      it { is_expected.to eq false}
    end

    context 'user is reporter in project issue belongs to' do
260
      let(:project) { create(:project) }
261 262
      let(:issue) { create(:issue, project: project) }

263
      before do
264
        project.add_reporter(user)
265
      end
266 267 268

      it { is_expected.to eq true }

269 270 271 272 273
      context 'issue not persisted' do
        let(:issue) { build(:issue, project: project) }
        it { is_expected.to eq false }
      end

274 275
      context 'checking destination project also' do
        subject { issue.can_move?(user, to_project) }
276
        let(:to_project) { create(:project) }
277 278

        context 'destination project allowed' do
279
          before do
280
            to_project.add_reporter(user)
281 282
          end

283 284 285 286
          it { is_expected.to eq true }
        end

        context 'destination project not allowed' do
287
          before do
288
            to_project.add_guest(user)
289 290
          end

291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312
          it { is_expected.to eq false }
        end
      end
    end
  end

  describe '#moved?' do
    let(:issue) { create(:issue) }
    subject { issue.moved? }

    context 'issue not moved' do
      it { is_expected.to eq false }
    end

    context 'issue already moved' do
      let(:moved_to_issue) { create(:issue) }
      let(:issue) { create(:issue, moved_to: moved_to_issue) }

      it { is_expected.to eq true }
    end
  end

313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354
  describe '#suggested_branch_name' do
    let(:repository) { double }

    subject { build(:issue) }

    before do
      allow(subject.project).to receive(:repository).and_return(repository)
    end

    context '#to_branch_name does not exists' do
      before do
        allow(repository).to receive(:branch_exists?).and_return(false)
      end

      it 'returns #to_branch_name' do
        expect(subject.suggested_branch_name).to eq(subject.to_branch_name)
      end
    end

    context '#to_branch_name exists not ending with -index' do
      before do
        allow(repository).to receive(:branch_exists?).and_return(true)
        allow(repository).to receive(:branch_exists?).with(/#{subject.to_branch_name}-\d/).and_return(false)
      end

      it 'returns #to_branch_name ending with -2' do
        expect(subject.suggested_branch_name).to eq("#{subject.to_branch_name}-2")
      end
    end

    context '#to_branch_name exists ending with -index' do
      before do
        allow(repository).to receive(:branch_exists?).and_return(true)
        allow(repository).to receive(:branch_exists?).with("#{subject.to_branch_name}-3").and_return(false)
      end

      it 'returns #to_branch_name ending with max index + 1' do
        expect(subject.suggested_branch_name).to eq("#{subject.to_branch_name}-3")
      end
    end
  end

355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375
  describe '#has_related_branch?' do
    let(:issue) { create(:issue, title: "Blue Bell Knoll") }
    subject { issue.has_related_branch? }

    context 'branch found' do
      before do
        allow(issue.project.repository).to receive(:branch_names).and_return(["iceblink-luck", issue.to_branch_name])
      end

      it { is_expected.to eq true }
    end

    context 'branch not found' do
      before do
        allow(issue.project.repository).to receive(:branch_names).and_return(["lazy-calm"])
      end

      it { is_expected.to eq false }
    end
  end

376
  it_behaves_like 'an editable mentionable' do
377
    subject { create(:issue, project: create(:project, :repository)) }
378

379
    let(:backref_text) { "issue #{subject.to_reference}" }
380
    let(:set_mentionable_text) { ->(txt) { subject.description = txt } }
381
  end
V
Vinnie Okada 已提交
382 383 384 385

  it_behaves_like 'a Taskable' do
    let(:subject) { create :issue }
  end
Z
Zeger-Jan van de Weg 已提交
386 387

  describe "#to_branch_name" do
388
    let(:issue) { create(:issue, title: 'testing-issue') }
Z
Zeger-Jan van de Weg 已提交
389

390
    it 'starts with the issue iid' do
391
      expect(issue.to_branch_name).to match /\A#{issue.iid}-[A-Za-z\-]+\z/
Z
Zeger-Jan van de Weg 已提交
392
    end
393 394

    it "contains the issue title if not confidential" do
395
      expect(issue.to_branch_name).to match /testing-issue\z/
396 397 398 399
    end

    it "does not contain the issue title if confidential" do
      issue = create(:issue, title: 'testing-issue', confidential: true)
400
      expect(issue.to_branch_name).to match /confidential-issue\z/
401
    end
Z
Zeger-Jan van de Weg 已提交
402
  end
Y
Yorick Peterse 已提交
403

404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424
  describe '#can_be_worked_on?' do
    let(:project) { build(:project) }
    subject { build(:issue, :opened, project: project) }

    context 'is closed' do
      subject { build(:issue, :closed) }

      it { is_expected.not_to be_can_be_worked_on }
    end

    context 'project is forked' do
      before do
        allow(project).to receive(:forked?).and_return(true)
      end

      it { is_expected.not_to be_can_be_worked_on }
    end

    it { is_expected.to be_can_be_worked_on }
  end

Y
Yorick Peterse 已提交
425 426
  describe '#participants' do
    context 'using a public project' do
427
      let(:project) { create(:project, :public) }
Y
Yorick Peterse 已提交
428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448
      let(:issue) { create(:issue, project: project) }

      let!(:note1) do
        create(:note_on_issue, noteable: issue, project: project, note: 'a')
      end

      let!(:note2) do
        create(:note_on_issue, noteable: issue, project: project, note: 'b')
      end

      it 'includes the issue author' do
        expect(issue.participants).to include(issue.author)
      end

      it 'includes the authors of the notes' do
        expect(issue.participants).to include(note1.author, note2.author)
      end
    end

    context 'using a private project' do
      it 'does not include mentioned users that do not have access to the project' do
449
        project = create(:project)
Y
Yorick Peterse 已提交
450 451 452 453 454 455 456 457 458 459 460 461
        user = create(:user)
        issue = create(:issue, project: project)

        create(:note_on_issue,
               noteable: issue,
               project: project,
               note: user.to_reference)

        expect(issue.participants).not_to include(user)
      end
    end
  end
J
Josh Frye 已提交
462 463 464 465 466

  describe 'cached counts' do
    it 'updates when assignees change' do
      user1 = create(:user)
      user2 = create(:user)
467
      project = create(:project)
468
      issue = create(:issue, assignees: [user1], project: project)
469 470
      project.add_developer(user1)
      project.add_developer(user2)
J
Josh Frye 已提交
471 472 473 474

      expect(user1.assigned_open_issues_count).to eq(1)
      expect(user2.assigned_open_issues_count).to eq(0)

475
      issue.assignees = [user2]
J
Josh Frye 已提交
476 477 478 479 480 481
      issue.save

      expect(user1.assigned_open_issues_count).to eq(0)
      expect(user2.assigned_open_issues_count).to eq(1)
    end
  end
482 483

  describe '#visible_to_user?' do
484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499
    context 'without a user' do
      let(:issue) { build(:issue) }

      it 'returns true when the issue is publicly visible' do
        expect(issue).to receive(:publicly_visible?).and_return(true)

        expect(issue.visible_to_user?).to eq(true)
      end

      it 'returns false when the issue is not publicly visible' do
        expect(issue).to receive(:publicly_visible?).and_return(false)

        expect(issue.visible_to_user?).to eq(false)
      end
    end

500
    context 'with a user' do
501
      let(:user) { create(:user) }
502 503 504 505 506 507 508 509 510 511 512 513 514 515
      let(:issue) { build(:issue) }

      it 'returns true when the issue is readable' do
        expect(issue).to receive(:readable_by?).with(user).and_return(true)

        expect(issue.visible_to_user?(user)).to eq(true)
      end

      it 'returns false when the issue is not readable' do
        expect(issue).to receive(:readable_by?).with(user).and_return(false)

        expect(issue.visible_to_user?(user)).to eq(false)
      end

516 517
      it 'returns false when feature is disabled' do
        expect(issue).not_to receive(:readable_by?)
518

519
        issue.project.project_feature.update_attribute(:issues_access_level, ProjectFeature::DISABLED)
520

521
        expect(issue.visible_to_user?(user)).to eq(false)
522 523
      end

524 525
      it 'returns false when restricted for members' do
        expect(issue).not_to receive(:readable_by?)
526

527 528 529
        issue.project.project_feature.update_attribute(:issues_access_level, ProjectFeature::PRIVATE)

        expect(issue.visible_to_user?(user)).to eq(false)
530 531 532 533 534 535 536
      end
    end

    describe 'with a regular user that is not a team member' do
      let(:user) { create(:user) }

      context 'using a public project' do
537
        let(:project) { create(:project, :public) }
538 539 540 541

        it 'returns true for a regular issue' do
          issue = build(:issue, project: project)

542
          expect(issue.visible_to_user?(user)).to eq(true)
543 544 545 546 547
        end

        it 'returns false for a confidential issue' do
          issue = build(:issue, project: project, confidential: true)

548
          expect(issue.visible_to_user?(user)).to eq(false)
549 550 551 552
        end
      end

      context 'using an internal project' do
553
        let(:project) { create(:project, :internal) }
554 555 556 557 558

        context 'using an internal user' do
          it 'returns true for a regular issue' do
            issue = build(:issue, project: project)

559
            expect(issue.visible_to_user?(user)).to eq(true)
560 561 562 563 564
          end

          it 'returns false for a confidential issue' do
            issue = build(:issue, :confidential, project: project)

565
            expect(issue.visible_to_user?(user)).to eq(false)
566 567 568 569 570 571 572 573 574 575 576
          end
        end

        context 'using an external user' do
          before do
            allow(user).to receive(:external?).and_return(true)
          end

          it 'returns false for a regular issue' do
            issue = build(:issue, project: project)

577
            expect(issue.visible_to_user?(user)).to eq(false)
578 579 580 581 582
          end

          it 'returns false for a confidential issue' do
            issue = build(:issue, :confidential, project: project)

583
            expect(issue.visible_to_user?(user)).to eq(false)
584 585 586 587 588
          end
        end
      end

      context 'using a private project' do
589
        let(:project) { create(:project, :private) }
590 591 592 593

        it 'returns false for a regular issue' do
          issue = build(:issue, project: project)

594
          expect(issue.visible_to_user?(user)).to eq(false)
595 596 597 598 599
        end

        it 'returns false for a confidential issue' do
          issue = build(:issue, :confidential, project: project)

600
          expect(issue.visible_to_user?(user)).to eq(false)
601 602 603
        end

        context 'when the user is the project owner' do
604
          before do
605
            project.add_maintainer(user)
606
          end
607

608 609 610
          it 'returns true for a regular issue' do
            issue = build(:issue, project: project)

611
            expect(issue.visible_to_user?(user)).to eq(true)
612 613 614 615 616
          end

          it 'returns true for a confidential issue' do
            issue = build(:issue, :confidential, project: project)

617
            expect(issue.visible_to_user?(user)).to eq(true)
618 619 620 621 622 623 624
          end
        end
      end
    end

    context 'with a regular user that is a team member' do
      let(:user) { create(:user) }
625
      let(:project) { create(:project, :public) }
626 627 628

      context 'using a public project' do
        before do
629
          project.add_developer(user)
630 631 632 633 634
        end

        it 'returns true for a regular issue' do
          issue = build(:issue, project: project)

635
          expect(issue.visible_to_user?(user)).to eq(true)
636 637 638 639 640
        end

        it 'returns true for a confidential issue' do
          issue = build(:issue, :confidential, project: project)

641
          expect(issue.visible_to_user?(user)).to eq(true)
642 643 644 645
        end
      end

      context 'using an internal project' do
646
        let(:project) { create(:project, :internal) }
647 648

        before do
649
          project.add_developer(user)
650 651 652 653 654
        end

        it 'returns true for a regular issue' do
          issue = build(:issue, project: project)

655
          expect(issue.visible_to_user?(user)).to eq(true)
656 657 658 659 660
        end

        it 'returns true for a confidential issue' do
          issue = build(:issue, :confidential, project: project)

661
          expect(issue.visible_to_user?(user)).to eq(true)
662 663 664 665
        end
      end

      context 'using a private project' do
666
        let(:project) { create(:project, :private) }
667 668

        before do
669
          project.add_developer(user)
670 671 672 673 674
        end

        it 'returns true for a regular issue' do
          issue = build(:issue, project: project)

675
          expect(issue.visible_to_user?(user)).to eq(true)
676 677 678 679 680
        end

        it 'returns true for a confidential issue' do
          issue = build(:issue, :confidential, project: project)

681
          expect(issue.visible_to_user?(user)).to eq(true)
682 683 684 685 686
        end
      end
    end

    context 'with an admin user' do
687
      let(:project) { create(:project) }
688
      let(:user) { create(:admin) }
689 690 691 692

      it 'returns true for a regular issue' do
        issue = build(:issue, project: project)

693
        expect(issue.visible_to_user?(user)).to eq(true)
694 695 696 697 698
      end

      it 'returns true for a confidential issue' do
        issue = build(:issue, :confidential, project: project)

699
        expect(issue.visible_to_user?(user)).to eq(true)
700 701 702 703 704 705
      end
    end
  end

  describe '#publicly_visible?' do
    context 'using a public project' do
706
      let(:project) { create(:project, :public) }
707 708 709 710

      it 'returns true for a regular issue' do
        issue = build(:issue, project: project)

711
        expect(issue).to be_truthy
712 713 714 715 716
      end

      it 'returns false for a confidential issue' do
        issue = build(:issue, :confidential, project: project)

717
        expect(issue).not_to be_falsy
718 719 720 721
      end
    end

    context 'using an internal project' do
722
      let(:project) { create(:project, :internal) }
723 724 725 726

      it 'returns false for a regular issue' do
        issue = build(:issue, project: project)

727
        expect(issue).not_to be_falsy
728 729 730 731 732
      end

      it 'returns false for a confidential issue' do
        issue = build(:issue, :confidential, project: project)

733
        expect(issue).not_to be_falsy
734 735 736 737
      end
    end

    context 'using a private project' do
738
      let(:project) { create(:project, :private) }
739 740 741 742

      it 'returns false for a regular issue' do
        issue = build(:issue, project: project)

743
        expect(issue).not_to be_falsy
744 745 746 747 748
      end

      it 'returns false for a confidential issue' do
        issue = build(:issue, :confidential, project: project)

749
        expect(issue).not_to be_falsy
750 751 752
      end
    end
  end
753 754

  describe '#hook_attrs' do
755 756 757 758 759 760 761 762
    it 'delegates to Gitlab::HookData::IssueBuilder#build' do
      builder = double

      expect(Gitlab::HookData::IssueBuilder)
        .to receive(:new).with(subject).and_return(builder)
      expect(builder).to receive(:build)

      subject.hook_attrs
763
    end
764
  end
765

766 767
  describe '#check_for_spam?' do
    using RSpec::Parameterized::TableSyntax
768

769 770 771 772 773 774 775 776 777
    where(:visibility_level, :confidential, :new_attributes, :check_for_spam?) do
      Gitlab::VisibilityLevel::PUBLIC   | false | { description: 'woo' } | true
      Gitlab::VisibilityLevel::PUBLIC   | false | { title: 'woo' } | true
      Gitlab::VisibilityLevel::PUBLIC   | true  | { confidential: false } | true
      Gitlab::VisibilityLevel::PUBLIC   | true  | { description: 'woo' } | false
      Gitlab::VisibilityLevel::PUBLIC   | false | { title: 'woo', confidential: true } | false
      Gitlab::VisibilityLevel::PUBLIC   | false | { description: 'original description' } | false
      Gitlab::VisibilityLevel::INTERNAL | false | { description: 'woo' } | false
      Gitlab::VisibilityLevel::PRIVATE  | false | { description: 'woo' } | false
778 779
    end

780 781 782 783
    with_them do
      it 'checks for spam on issues that can be seen anonymously' do
        project = create(:project, visibility_level: visibility_level)
        issue = create(:issue, project: project, confidential: confidential, description: 'original description')
784

785
        issue.assign_attributes(new_attributes)
786

787
        expect(issue.check_for_spam?).to eq(check_for_spam?)
788 789 790
      end
    end
  end
791 792 793 794 795 796 797 798 799 800 801 802 803 804 805 806 807 808

  describe 'removing an issue' do
    it 'refreshes the number of open issues of the project' do
      project = subject.project

      expect { subject.destroy }
        .to change { project.open_issues_count }.from(1).to(0)
    end
  end

  describe '.public_only' do
    it 'only returns public issues' do
      public_issue = create(:issue)
      create(:issue, confidential: true)

      expect(described_class.public_only).to eq([public_issue])
    end
  end
809

810 811 812 813 814 815 816 817 818
  describe '.confidential_only' do
    it 'only returns confidential_only issues' do
      create(:issue)
      confidential_issue = create(:issue, confidential: true)

      expect(described_class.confidential_only).to eq([confidential_issue])
    end
  end

819 820 821
  it_behaves_like 'throttled touch' do
    subject { create(:issue, updated_at: 1.hour.ago) }
  end
822 823 824 825 826 827 828 829 830 831 832 833 834 835 836 837 838 839 840 841 842 843 844 845 846 847 848 849 850 851 852 853 854 855 856 857 858 859 860 861 862 863 864

  context 'when an external authentication service' do
    before do
      enable_external_authorization_service_check
    end

    describe '#visible_to_user?' do
      it 'is `false` when an external authorization service is enabled' do
        issue = build(:issue, project: build(:project, :public))

        expect(issue).not_to be_visible_to_user
      end

      it 'checks the external service to determine if an issue is readable by a user' do
        project = build(:project, :public,
                        external_authorization_classification_label: 'a-label')
        issue = build(:issue, project: project)
        user = build(:user)

        expect(::Gitlab::ExternalAuthorization).to receive(:access_allowed?).with(user, 'a-label') { false }
        expect(issue.visible_to_user?(user)).to be_falsy
      end

      it 'does not check the external service if a user does not have access to the project' do
        project = build(:project, :private,
                        external_authorization_classification_label: 'a-label')
        issue = build(:issue, project: project)
        user = build(:user)

        expect(::Gitlab::ExternalAuthorization).not_to receive(:access_allowed?)
        expect(issue.visible_to_user?(user)).to be_falsy
      end

      it 'does not check the external webservice for admins' do
        issue = build(:issue)
        user = build(:admin)

        expect(::Gitlab::ExternalAuthorization).not_to receive(:access_allowed?)

        issue.visible_to_user?(user)
      end
    end
  end
J
Jan Provaznik 已提交
865 866 867 868 869 870 871 872 873

  describe "#labels_hook_attrs" do
    let(:label) { create(:label) }
    let(:issue) { create(:labeled_issue, labels: [label]) }

    it "returns a list of label hook attributes" do
      expect(issue.labels_hook_attrs).to eq([label.hook_attrs])
    end
  end
G
gitlabhq 已提交
874
end