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

gitlab.com/gitlab-org/gitlab-foss.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRobert Speicher <rspeicher@gmail.com>2015-05-01 06:16:19 +0300
committerRobert Speicher <rspeicher@gmail.com>2015-05-11 07:01:01 +0300
commit48e6fb532a6655b98319403c5e8699f7daf0305e (patch)
tree9137cd844f66842044bd72705268b44d84d44b6c /spec/services
parent0e89ff0fb05973bb3ff6930906d52f10517efa62 (diff)
Add a SystemNoteService class
There's a lot of code in the Note model that only deals with creating system notes, so we're going to split that into its own class.
Diffstat (limited to 'spec/services')
-rw-r--r--spec/services/system_note_service_spec.rb353
1 files changed, 353 insertions, 0 deletions
diff --git a/spec/services/system_note_service_spec.rb b/spec/services/system_note_service_spec.rb
new file mode 100644
index 00000000000..cda4e7698f1
--- /dev/null
+++ b/spec/services/system_note_service_spec.rb
@@ -0,0 +1,353 @@
+require 'spec_helper'
+
+describe SystemNoteService do
+ let(:project) { create(:project) }
+ let(:author) { create(:user) }
+ let(:noteable) { create(:issue, project: project) }
+
+ shared_examples_for 'a system note' do
+ it 'sets the noteable model' do
+ expect(subject.noteable).to eq noteable
+ end
+
+ it 'sets the project' do
+ expect(subject.project).to eq project
+ end
+
+ it 'sets the author' do
+ expect(subject.author).to eq author
+ end
+
+ it 'is a system note' do
+ expect(subject).to be_system
+ end
+ end
+
+ describe '.assignee_change' do
+ let(:assignee) { create(:user) }
+
+ subject { described_class.assignee_change(noteable, project, author, assignee) }
+
+ it_behaves_like 'a system note'
+
+ context 'when assignee added' do
+ it 'sets the note text' do
+ expect(subject.note).to eq "Reassigned to @#{assignee.username}"
+ end
+ end
+
+ context 'when assignee removed' do
+ let(:assignee) { nil }
+
+ it 'sets the note text' do
+ expect(subject.note).to eq 'Assignee removed'
+ end
+ end
+ end
+
+ describe '.cross_reference' do
+ let(:mentioner) { create(:issue, project: project) }
+
+ subject { described_class.cross_reference(noteable, mentioner, author) }
+
+ it_behaves_like 'a system note'
+
+ context 'when cross-reference disallowed' do
+ before do
+ expect(described_class).to receive(:cross_reference_disallowed?).and_return(true)
+ end
+
+ it 'returns nil' do
+ expect(subject).to be_nil
+ end
+ end
+
+ context 'when cross-reference allowed' do
+ before do
+ expect(described_class).to receive(:cross_reference_disallowed?).and_return(false)
+ end
+
+ describe 'note_body' do
+ context 'cross-project' do
+ let(:project2) { create(:project) }
+ let(:mentioner) { create(:issue, project: project2) }
+
+ context 'from Commit' do
+ let(:mentioner) { project2.repository.commit }
+
+ it 'references the mentioning commit' do
+ expect(subject.note).to eq "mentioned in commit #{project2.path_with_namespace}@#{mentioner.id}"
+ end
+ end
+
+ context 'from non-Commit' do
+ it 'references the mentioning object' do
+ expect(subject.note).to eq "mentioned in issue #{project2.path_with_namespace}##{mentioner.iid}"
+ end
+ end
+ end
+
+ context 'same project' do
+ context 'from Commit' do
+ let(:mentioner) { project.repository.commit }
+
+ it 'references the mentioning commit' do
+ expect(subject.note).to eq "mentioned in commit #{mentioner.id}"
+ end
+ end
+
+ context 'from non-Commit' do
+ it 'references the mentioning object' do
+ expect(subject.note).to eq "mentioned in issue ##{mentioner.iid}"
+ end
+ end
+ end
+ end
+ end
+ end
+
+ describe '.label_change' do
+ let(:labels) { create_list(:label, 2) }
+ let(:added) { [] }
+ let(:removed) { [] }
+
+ subject { described_class.label_change(noteable, project, author, added, removed) }
+
+ it_behaves_like 'a system note'
+
+ context 'with added labels' do
+ let(:added) { labels }
+ let(:removed) { [] }
+
+ it 'sets the note text' do
+ expect(subject.note).to eq "Added ~#{labels[0].id} ~#{labels[1].id} labels"
+ end
+ end
+
+ context 'with removed labels' do
+ let(:added) { [] }
+ let(:removed) { labels }
+
+ it 'sets the note text' do
+ expect(subject.note).to eq "Removed ~#{labels[0].id} ~#{labels[1].id} labels"
+ end
+ end
+
+ context 'with added and removed labels' do
+ let(:added) { [labels[0]] }
+ let(:removed) { [labels[1]] }
+
+ it 'sets the note text' do
+ expect(subject.note).to eq "Added ~#{labels[0].id} and removed ~#{labels[1].id} labels"
+ end
+ end
+ end
+
+ describe '.milestone_change' do
+ let(:milestone) { create(:milestone, project: project) }
+
+ subject { described_class.milestone_change(noteable, project, author, milestone) }
+
+ it_behaves_like 'a system note'
+
+ context 'when milestone added' do
+ it 'sets the note text' do
+ expect(subject.note).to eq "Milestone changed to #{milestone.title}"
+ end
+ end
+
+ context 'when milestone removed' do
+ let(:milestone) { nil }
+
+ it 'sets the note text' do
+ expect(subject.note).to eq 'Milestone removed'
+ end
+ end
+ end
+
+ describe '.commit_add' do
+ let(:noteable) { create(:merge_request, source_project: project) }
+ let(:new_commits) { noteable.commits }
+ let(:old_commits) { [] }
+ let(:oldrev) { nil }
+
+ subject { described_class.commit_add(noteable, project, author, new_commits, old_commits, oldrev) }
+
+ it_behaves_like 'a system note'
+
+ describe 'note body' do
+ let(:note_lines) { subject.note.split("\n").reject(&:blank?) }
+
+ context 'without existing commits' do
+ it 'adds a message header' do
+ expect(note_lines[0]).to eq "Added #{new_commits.size} commits:"
+ end
+
+ it 'adds a message line for each commit' do
+ new_commits.each_with_index do |commit, i|
+ # Skip the header
+ expect(note_lines[i + 1]).to eq "* #{commit.short_id} - #{commit.title}"
+ end
+ end
+ end
+
+ describe 'summary line for existing commits' do
+ let(:summary_line) { note_lines[1] }
+
+ context 'with one existing commit' do
+ let(:old_commits) { [noteable.commits.last] }
+
+ it 'includes the existing commit' do
+ expect(summary_line).to eq "* #{old_commits.first.short_id} - 1 commit from branch `feature`"
+ end
+ end
+
+ context 'with multiple existing commits' do
+ let(:old_commits) { noteable.commits[3..-1] }
+
+ context 'with oldrev' do
+ let(:oldrev) { noteable.commits[2].id }
+
+ it 'includes a commit range' do
+ expect(summary_line).to start_with "* #{Commit.truncate_sha(oldrev)}...#{old_commits.last.short_id}"
+ end
+
+ it 'includes a commit count' do
+ expect(summary_line).to end_with " - 2 commits from branch `feature`"
+ end
+ end
+
+ context 'without oldrev' do
+ it 'includes a commit range' do
+ expect(summary_line).to start_with "* #{old_commits[0].short_id}..#{old_commits[-1].short_id}"
+ end
+
+ it 'includes a commit count' do
+ expect(summary_line).to end_with " - 2 commits from branch `feature`"
+ end
+ end
+
+ context 'on a fork' do
+ before do
+ expect(noteable).to receive(:for_fork?).and_return(true)
+ end
+
+ it 'includes the project namespace' do
+ expect(summary_line).to end_with "`#{noteable.target_project_namespace}:feature`"
+ end
+ end
+ end
+ end
+ end
+ end
+
+ describe '.status_change' do
+ let(:status) { 'new_status' }
+ let(:source) { nil }
+
+ subject { described_class.status_change(noteable, project, author, status, source) }
+
+ it_behaves_like 'a system note'
+
+ context 'with a source' do
+ let(:source) { double('commit', gfm_reference: 'commit 123456') }
+
+ it 'sets the note text' do
+ expect(subject.note).to eq "Status changed to #{status} by commit 123456"
+ end
+ end
+
+ context 'without a source' do
+ it 'sets the note text' do
+ expect(subject.note).to eq "Status changed to #{status}"
+ end
+ end
+ end
+
+ describe '.cross_reference?' do
+ it 'is truthy when text begins with expected text' do
+ expect(described_class.cross_reference?('mentioned in issue #1')).to be_truthy
+ end
+
+ it 'is falsey when text does not begin with expected text' do
+ expect(described_class.cross_reference?('this is a note')).to be_falsey
+ end
+ end
+
+ describe '.cross_reference_disallowed?'
+
+ describe '.cross_reference_exists?' do
+ let(:commit0) { project.commit }
+ let(:commit1) { project.commit('HEAD~2') }
+
+ context 'issue from commit' do
+ before do
+ # Mention issue (noteable) from commit0
+ described_class.cross_reference(noteable, commit0, author)
+ end
+
+ it 'is truthy when already mentioned' do
+ expect(described_class.cross_reference_exists?(noteable, commit0)).
+ to be_truthy
+ end
+
+ it 'is falsey when not already mentioned' do
+ expect(described_class.cross_reference_exists?(noteable, commit1)).
+ to be_falsey
+ end
+ end
+
+ context 'commit from commit' do
+ before do
+ # Mention commit1 from commit0
+ described_class.cross_reference(commit0, commit1, author)
+ end
+
+ it 'is truthy when already mentioned' do
+ expect(described_class.cross_reference_exists?(commit0, commit1)).
+ to be_truthy
+ end
+
+ it 'is falsey when not already mentioned' do
+ expect(described_class.cross_reference_exists?(commit1, commit0)).
+ to be_falsey
+ end
+ end
+
+ context 'legacy note with Markdown emphasis' do
+ let(:mentioner) { create(:issue, project: project) }
+
+ before do
+ note = "_mentioned in issue ##{mentioner.iid}_"
+ create(:system_note, noteable: noteable, note: note, project: project)
+ end
+
+ it 'detects if a mentionable with emphasis has been mentioned' do
+ expect(described_class.cross_reference_exists?(noteable, mentioner)).
+ to be_truthy
+ end
+
+ context 'when referenced project has underscores' do
+ let(:project) { create(:empty_project, path: 'first_project') }
+ let(:project2) { create(:empty_project, path: 'second_project') }
+
+ let(:issue) { mentioner }
+ let(:issue2) { create(:issue, project: project2) }
+
+ before do
+ described_class.cross_reference(issue, issue2, author)
+ end
+
+ it 'is truthy when already mentioned' do
+ expect(described_class.cross_reference_exists?(issue, issue2)).
+ to be_truthy
+ end
+
+ it 'is falsey when not already mentioned' do
+ expect(described_class.cross_reference_exists?(issue2, issue)).
+ to be_falsey
+ end
+ end
+ end
+ end
+end