note_spec.rb 10.8 KB
Newer Older
G
gitlabhq 已提交
1 2
require 'spec_helper'

D
Douwe Maan 已提交
3
describe Note, models: true do
4 5
  include RepoHelpers

R
Robert Speicher 已提交
6
  describe 'associations' do
7
    it { is_expected.to belong_to(:project) }
8
    it { is_expected.to belong_to(:noteable).touch(true) }
9
    it { is_expected.to belong_to(:author).class_name('User') }
10

11
    it { is_expected.to have_many(:todos).dependent(:destroy) }
G
gitlabhq 已提交
12 13
  end

Z
ZJ van de Weg 已提交
14 15 16 17 18 19 20 21 22 23
  describe 'modules' do
    subject { described_class }

    it { is_expected.to include_module(Participable) }
    it { is_expected.to include_module(Mentionable) }
    it { is_expected.to include_module(Awardable) }

    it { is_expected.to include_module(Gitlab::CurrentSettings) }
  end

R
Robert Speicher 已提交
24
  describe 'validation' do
25 26
    it { is_expected.to validate_presence_of(:note) }
    it { is_expected.to validate_presence_of(:project) }
27

28
    context 'when note is on commit' do
29 30 31
      before { allow(subject).to receive(:for_commit?).and_return(true) }

      it { is_expected.to validate_presence_of(:commit_id) }
R
Robert Speicher 已提交
32
      it { is_expected.not_to validate_presence_of(:noteable_id) }
33 34
    end

35
    context 'when note is not on commit' do
36 37
      before { allow(subject).to receive(:for_commit?).and_return(false) }

R
Robert Speicher 已提交
38
      it { is_expected.not_to validate_presence_of(:commit_id) }
39 40 41
      it { is_expected.to validate_presence_of(:noteable_id) }
    end

42
    context 'when noteable and note project differ' do
43
      subject do
44 45
        build(:note, noteable: build_stubbed(:issue),
                     project: build_stubbed(:project))
46 47 48 49 50
      end

      it { is_expected.to be_invalid }
    end

51
    context 'when noteable and note project are the same' do
52 53 54
      subject { create(:note) }
      it { is_expected.to be_valid }
    end
G
gitlabhq 已提交
55 56
  end

57
  describe "Commit notes" do
R
Riyad Preukschas 已提交
58 59
    let!(:note) { create(:note_on_commit, note: "+1 from me") }
    let!(:commit) { note.noteable }
D
Dmitriy Zaporozhets 已提交
60

61
    it "is accessible through #noteable" do
62 63 64
      expect(note.commit_id).to eq(commit.id)
      expect(note.noteable).to be_a(Commit)
      expect(note.noteable).to eq(commit)
R
Riyad Preukschas 已提交
65 66
    end

67
    it "saves a valid note" do
68
      expect(note.commit_id).to eq(commit.id)
R
Riyad Preukschas 已提交
69
      note.noteable == commit
R
Riyad Preukschas 已提交
70 71
    end

72
    it "is recognized by #for_commit?" do
73
      expect(note).to be_for_commit
D
Dmitriy Zaporozhets 已提交
74
    end
75 76 77 78

    it "keeps the commit around" do
      expect(note.project.repository.kept_around?(commit.id)).to be_truthy
    end
R
Riyad Preukschas 已提交
79 80
  end

R
Robert Speicher 已提交
81
  describe 'authorization' do
N
Nihad Abbasov 已提交
82
    before do
83
      @p1 = create(:project)
84 85 86 87
      @p2 = create(:project)
      @u1 = create(:user)
      @u2 = create(:user)
      @u3 = create(:user)
G
gitlabhq 已提交
88 89 90 91
      @abilities = Six.new
      @abilities << Ability
    end

R
Robert Speicher 已提交
92
    describe 'read' do
N
Nihad Abbasov 已提交
93
      before do
94 95
        @p1.project_members.create(user: @u2, access_level: ProjectMember::GUEST)
        @p2.project_members.create(user: @u3, access_level: ProjectMember::GUEST)
G
gitlabhq 已提交
96 97
      end

98 99 100
      it { expect(@abilities.allowed?(@u1, :read_note, @p1)).to be_falsey }
      it { expect(@abilities.allowed?(@u2, :read_note, @p1)).to be_truthy }
      it { expect(@abilities.allowed?(@u3, :read_note, @p1)).to be_falsey }
G
gitlabhq 已提交
101 102
    end

R
Robert Speicher 已提交
103
    describe 'write' do
N
Nihad Abbasov 已提交
104
      before do
105 106
        @p1.project_members.create(user: @u2, access_level: ProjectMember::DEVELOPER)
        @p2.project_members.create(user: @u3, access_level: ProjectMember::DEVELOPER)
G
gitlabhq 已提交
107 108
      end

109 110 111
      it { expect(@abilities.allowed?(@u1, :create_note, @p1)).to be_falsey }
      it { expect(@abilities.allowed?(@u2, :create_note, @p1)).to be_truthy }
      it { expect(@abilities.allowed?(@u3, :create_note, @p1)).to be_falsey }
G
gitlabhq 已提交
112 113
    end

R
Robert Speicher 已提交
114
    describe 'admin' do
N
Nihad Abbasov 已提交
115
      before do
116 117 118
        @p1.project_members.create(user: @u1, access_level: ProjectMember::REPORTER)
        @p1.project_members.create(user: @u2, access_level: ProjectMember::MASTER)
        @p2.project_members.create(user: @u3, access_level: ProjectMember::MASTER)
G
gitlabhq 已提交
119 120
      end

121 122 123
      it { expect(@abilities.allowed?(@u1, :admin_note, @p1)).to be_falsey }
      it { expect(@abilities.allowed?(@u2, :admin_note, @p1)).to be_truthy }
      it { expect(@abilities.allowed?(@u3, :admin_note, @p1)).to be_falsey }
G
gitlabhq 已提交
124 125
    end
  end
126 127

  it_behaves_like 'an editable mentionable' do
D
Douwe Maan 已提交
128
    subject { create :note, noteable: issue, project: issue.project }
129

D
Douwe Maan 已提交
130
    let(:issue) { create :issue }
131 132 133
    let(:backref_text) { issue.gfm_reference }
    let(:set_mentionable_text) { ->(txt) { subject.note = txt } }
  end
134

D
Douwe Maan 已提交
135
  describe "#all_references" do
136 137
    let!(:note1) { create(:note_on_issue) }
    let!(:note2) { create(:note_on_issue) }
D
Douwe Maan 已提交
138 139

    it "reads the rendered note body from the cache" do
140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163
      expect(Banzai::Renderer).to receive(:cache_collection_render).
        with([{
          text: note1.note,
          context: {
            pipeline: :note,
            cache_key: [note1, "note"],
            project: note1.project,
            author: note1.author
          }
        }]).and_call_original

      expect(Banzai::Renderer).to receive(:cache_collection_render).
        with([{
          text: note2.note,
          context: {
            pipeline: :note,
            cache_key: [note2, "note"],
            project: note2.project,
            author: note2.author
          }
        }]).and_call_original

      note1.all_references.users
      note2.all_references.users
D
Douwe Maan 已提交
164 165 166
    end
  end

167
  describe '.search' do
168
    let(:note) { create(:note_on_issue, note: 'WoW') }
169

170 171 172 173 174 175 176
    it 'returns notes with matching content' do
      expect(described_class.search(note.note)).to eq([note])
    end

    it 'returns notes with matching content regardless of the casing' do
      expect(described_class.search('WOW')).to eq([note])
    end
V
Valery Sizov 已提交
177 178

    context "confidential issues" do
179 180 181 182
      let(:user) { create(:user) }
      let(:project) { create(:project) }
      let(:confidential_issue) { create(:issue, :confidential, project: project, author: user) }
      let(:confidential_note) { create(:note, note: "Random", noteable: confidential_issue, project: confidential_issue.project) }
V
Valery Sizov 已提交
183 184 185 186 187 188

      it "returns notes with matching content if user can see the issue" do
        expect(described_class.search(confidential_note.note, as_user: user)).to eq([confidential_note])
      end

      it "does not return notes with matching content if user can not see the issue" do
189 190 191 192 193 194 195
        user = create(:user)
        expect(described_class.search(confidential_note.note, as_user: user)).to be_empty
      end

      it "does not return notes with matching content for project members with guest role" do
        user = create(:user)
        project.team << [user, :guest]
V
Valery Sizov 已提交
196 197 198 199 200 201 202
        expect(described_class.search(confidential_note.note, as_user: user)).to be_empty
      end

      it "does not return notes with matching content for unauthenticated users" do
        expect(described_class.search(confidential_note.note)).to be_empty
      end
    end
203
  end
V
Valery Sizov 已提交
204

205 206 207 208 209 210 211 212 213 214 215
  describe "editable?" do
    it "returns true" do
      note = build(:note)
      expect(note.editable?).to be_truthy
    end

    it "returns false" do
      note = build(:note, system: true)
      expect(note.editable?).to be_falsy
    end
  end
D
Douwe Maan 已提交
216

217 218 219 220 221 222 223 224
  describe "cross_reference_not_visible_for?" do
    let(:private_user)    { create(:user) }
    let(:private_project) { create(:project, namespace: private_user.namespace).tap { |p| p.team << [private_user, :master] } }
    let(:private_issue)   { create(:issue, project: private_project) }

    let(:ext_proj)  { create(:project, :public) }
    let(:ext_issue) { create(:issue, project: ext_proj) }

R
Rémy Coutable 已提交
225
    let(:note) do
226 227 228 229
      create :note,
        noteable: ext_issue, project: ext_proj,
        note: "mentioned in issue #{private_issue.to_reference(ext_proj)}",
        system: true
R
Rémy Coutable 已提交
230
    end
231 232 233 234 235 236 237 238

    it "returns true" do
      expect(note.cross_reference_not_visible_for?(ext_issue.author)).to be_truthy
    end

    it "returns false" do
      expect(note.cross_reference_not_visible_for?(private_user)).to be_falsy
    end
239 240 241 242 243 244 245 246 247 248 249 250 251 252

    it "returns false if user visible reference count set" do
      note.user_visible_reference_count = 1

      expect(note).not_to receive(:reference_mentionables)
      expect(note.cross_reference_not_visible_for?(ext_issue.author)).to be_falsy
    end

    it "returns true if ref count is 0" do
      note.user_visible_reference_count = 0

      expect(note).not_to receive(:reference_mentionables)
      expect(note.cross_reference_not_visible_for?(ext_issue.author)).to be_truthy
    end
253 254
  end

255 256 257 258 259 260 261
  describe 'clear_blank_line_code!' do
    it 'clears a blank line code before validation' do
      note = build(:note, line_code: ' ')

      expect { note.valid? }.to change(note, :line_code).to(nil)
    end
  end
Y
Yorick Peterse 已提交
262 263 264 265 266 267 268 269 270 271

  describe '#participants' do
    it 'includes the note author' do
      project = create(:project, :public)
      issue = create(:issue, project: project)
      note = create(:note_on_issue, noteable: issue, project: project)

      expect(note.participants).to include(note.author)
    end
  end
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 311 312 313 314 315 316 317 318 319 320 321 322 323

  describe ".grouped_diff_discussions" do
    let!(:merge_request) { create(:merge_request) }
    let(:project) { merge_request.project }
    let!(:active_diff_note1) { create(:diff_note_on_merge_request, project: project, noteable: merge_request) }
    let!(:active_diff_note2) { create(:diff_note_on_merge_request, project: project, noteable: merge_request) }
    let!(:active_diff_note3) { create(:diff_note_on_merge_request, project: project, noteable: merge_request, position: active_position2) }
    let!(:outdated_diff_note1) { create(:diff_note_on_merge_request, project: project, noteable: merge_request, position: outdated_position) }
    let!(:outdated_diff_note2) { create(:diff_note_on_merge_request, project: project, noteable: merge_request, position: outdated_position) }

    let(:active_position2) do
      Gitlab::Diff::Position.new(
        old_path: "files/ruby/popen.rb",
        new_path: "files/ruby/popen.rb",
        old_line: 16,
        new_line: 22,
        diff_refs: merge_request.diff_refs
      )
    end

    let(:outdated_position) do
      Gitlab::Diff::Position.new(
        old_path: "files/ruby/popen.rb",
        new_path: "files/ruby/popen.rb",
        old_line: nil,
        new_line: 9,
        diff_refs: project.commit("874797c3a73b60d2187ed6e2fcabd289ff75171e").diff_refs
      )
    end

    subject { merge_request.notes.grouped_diff_discussions }

    it "includes active discussions" do
      discussions = subject.values

      expect(discussions.count).to eq(2)
      expect(discussions.map(&:id)).to eq([active_diff_note1.discussion_id, active_diff_note3.discussion_id])
      expect(discussions.all?(&:active?)).to be true

      expect(discussions.first.notes).to eq([active_diff_note1, active_diff_note2])
      expect(discussions.last.notes).to eq([active_diff_note3])
    end

    it "doesn't include outdated discussions" do
      expect(subject.values.map(&:id)).not_to include(outdated_diff_note1.discussion_id)
    end

    it "groups the discussions by line code" do
      expect(subject[active_diff_note1.line_code].id).to eq(active_diff_note1.discussion_id)
      expect(subject[active_diff_note3.line_code].id).to eq(active_diff_note3.discussion_id)
    end
  end
G
gitlabhq 已提交
324
end