a0101ebf84
Rename column in the database Rename fields related to import/export feature Rename API endpoints Rename documentation links Rename the rest of occurrences in the code Replace the images that contain the words "build succeeds" and docs referencing to them Make sure pipeline is green and nothing is missing. updated doc images renamed only_allow_merge_if_build_succeeds in projects and fixed references more updates fix some spec failures fix rubocop offences fix v3 api spec fix MR specs fixed issues with partials fix MR spec fix alignment add missing v3 to v4 doc wip - refactor v3 endpoints fix specs fix a few typos fix project specs copy entities fully to V3 fix entity error more fixes fix failing specs fixed missing entities in V3 API remove comment updated code based on feedback typo fix spec
843 lines
42 KiB
Ruby
843 lines
42 KiB
Ruby
require 'spec_helper'
|
|
|
|
describe TodoService, services: true do
|
|
let(:author) { create(:user) }
|
|
let(:assignee) { create(:user) }
|
|
let(:non_member) { create(:user) }
|
|
let(:member) { create(:user) }
|
|
let(:guest) { create(:user) }
|
|
let(:admin) { create(:admin) }
|
|
let(:john_doe) { create(:user) }
|
|
let(:project) { create(:project) }
|
|
let(:mentions) { 'FYI: ' + [author, assignee, john_doe, member, guest, non_member, admin].map(&:to_reference).join(' ') }
|
|
let(:directly_addressed) { [author, assignee, john_doe, member, guest, non_member, admin].map(&:to_reference).join(' ') }
|
|
let(:directly_addressed_and_mentioned) { member.to_reference + ", what do you think? cc: " + [guest, admin].map(&:to_reference).join(' ') }
|
|
let(:service) { described_class.new }
|
|
|
|
before do
|
|
project.team << [guest, :guest]
|
|
project.team << [author, :developer]
|
|
project.team << [member, :developer]
|
|
project.team << [john_doe, :developer]
|
|
end
|
|
|
|
describe 'Issues' do
|
|
let(:issue) { create(:issue, project: project, assignee: john_doe, author: author, description: "- [ ] Task 1\n- [ ] Task 2 #{mentions}") }
|
|
let(:addressed_issue) { create(:issue, project: project, assignee: john_doe, author: author, description: "#{directly_addressed}\n- [ ] Task 1\n- [ ] Task 2") }
|
|
let(:unassigned_issue) { create(:issue, project: project, assignee: nil) }
|
|
let(:confidential_issue) { create(:issue, :confidential, project: project, author: author, assignee: assignee, description: mentions) }
|
|
let(:addressed_confident_issue) { create(:issue, :confidential, project: project, author: author, assignee: assignee, description: directly_addressed) }
|
|
|
|
describe '#new_issue' do
|
|
it 'creates a todo if assigned' do
|
|
service.new_issue(issue, author)
|
|
|
|
should_create_todo(user: john_doe, target: issue, action: Todo::ASSIGNED)
|
|
end
|
|
|
|
it 'does not create a todo if unassigned' do
|
|
should_not_create_any_todo { service.new_issue(unassigned_issue, author) }
|
|
end
|
|
|
|
it 'creates a todo if assignee is the current user' do
|
|
unassigned_issue.update_attribute(:assignee, john_doe)
|
|
service.new_issue(unassigned_issue, john_doe)
|
|
|
|
should_create_todo(user: john_doe, target: unassigned_issue, author: john_doe, action: Todo::ASSIGNED)
|
|
end
|
|
|
|
it 'creates a todo for each valid mentioned user' do
|
|
service.new_issue(issue, author)
|
|
|
|
should_create_todo(user: member, target: issue, action: Todo::MENTIONED)
|
|
should_create_todo(user: guest, target: issue, action: Todo::MENTIONED)
|
|
should_create_todo(user: author, target: issue, action: Todo::MENTIONED)
|
|
should_not_create_todo(user: john_doe, target: issue, action: Todo::MENTIONED)
|
|
should_not_create_todo(user: non_member, target: issue, action: Todo::MENTIONED)
|
|
end
|
|
|
|
it 'creates a directly addressed todo for each valid addressed user' do
|
|
service.new_issue(addressed_issue, author)
|
|
|
|
should_create_todo(user: member, target: addressed_issue, action: Todo::DIRECTLY_ADDRESSED)
|
|
should_create_todo(user: guest, target: addressed_issue, action: Todo::DIRECTLY_ADDRESSED)
|
|
should_create_todo(user: author, target: addressed_issue, action: Todo::DIRECTLY_ADDRESSED)
|
|
should_not_create_todo(user: john_doe, target: addressed_issue, action: Todo::DIRECTLY_ADDRESSED)
|
|
should_not_create_todo(user: non_member, target: addressed_issue, action: Todo::DIRECTLY_ADDRESSED)
|
|
end
|
|
|
|
it 'creates correct todos for each valid user based on the type of mention' do
|
|
issue.update(description: directly_addressed_and_mentioned)
|
|
|
|
service.new_issue(issue, author)
|
|
|
|
should_create_todo(user: member, target: issue, action: Todo::DIRECTLY_ADDRESSED)
|
|
should_create_todo(user: admin, target: issue, action: Todo::MENTIONED)
|
|
should_create_todo(user: guest, target: issue, action: Todo::MENTIONED)
|
|
end
|
|
|
|
it 'does not create todo if user can not see the issue when issue is confidential' do
|
|
service.new_issue(confidential_issue, john_doe)
|
|
|
|
should_create_todo(user: assignee, target: confidential_issue, author: john_doe, action: Todo::ASSIGNED)
|
|
should_create_todo(user: author, target: confidential_issue, author: john_doe, action: Todo::MENTIONED)
|
|
should_create_todo(user: member, target: confidential_issue, author: john_doe, action: Todo::MENTIONED)
|
|
should_create_todo(user: admin, target: confidential_issue, author: john_doe, action: Todo::MENTIONED)
|
|
should_not_create_todo(user: guest, target: confidential_issue, author: john_doe, action: Todo::MENTIONED)
|
|
should_create_todo(user: john_doe, target: confidential_issue, author: john_doe, action: Todo::MENTIONED)
|
|
end
|
|
|
|
it 'does not create directly addressed todo if user cannot see the issue when issue is confidential' do
|
|
service.new_issue(addressed_confident_issue, john_doe)
|
|
|
|
should_create_todo(user: assignee, target: addressed_confident_issue, author: john_doe, action: Todo::ASSIGNED)
|
|
should_create_todo(user: author, target: addressed_confident_issue, author: john_doe, action: Todo::DIRECTLY_ADDRESSED)
|
|
should_create_todo(user: member, target: addressed_confident_issue, author: john_doe, action: Todo::DIRECTLY_ADDRESSED)
|
|
should_create_todo(user: admin, target: addressed_confident_issue, author: john_doe, action: Todo::DIRECTLY_ADDRESSED)
|
|
should_not_create_todo(user: guest, target: addressed_confident_issue, author: john_doe, action: Todo::DIRECTLY_ADDRESSED)
|
|
should_create_todo(user: john_doe, target: addressed_confident_issue, author: john_doe, action: Todo::DIRECTLY_ADDRESSED)
|
|
end
|
|
|
|
context 'when a private group is mentioned' do
|
|
let(:group) { create :group, :private }
|
|
let(:project) { create :project, :private, group: group }
|
|
let(:issue) { create :issue, author: author, project: project, description: group.to_reference }
|
|
|
|
before do
|
|
group.add_owner(author)
|
|
group.add_user(member, Gitlab::Access::DEVELOPER)
|
|
group.add_user(john_doe, Gitlab::Access::DEVELOPER)
|
|
|
|
service.new_issue(issue, author)
|
|
end
|
|
|
|
it 'creates a todo for group members' do
|
|
should_create_todo(user: member, target: issue)
|
|
should_create_todo(user: john_doe, target: issue)
|
|
end
|
|
end
|
|
end
|
|
|
|
describe '#update_issue' do
|
|
it 'creates a todo for each valid mentioned user' do
|
|
service.update_issue(issue, author)
|
|
|
|
should_create_todo(user: member, target: issue, action: Todo::MENTIONED)
|
|
should_create_todo(user: guest, target: issue, action: Todo::MENTIONED)
|
|
should_create_todo(user: john_doe, target: issue, action: Todo::MENTIONED)
|
|
should_create_todo(user: author, target: issue, action: Todo::MENTIONED)
|
|
should_not_create_todo(user: non_member, target: issue, action: Todo::MENTIONED)
|
|
end
|
|
|
|
it 'creates a todo for each valid user based on the type of mention' do
|
|
issue.update(description: directly_addressed_and_mentioned)
|
|
|
|
service.update_issue(issue, author)
|
|
|
|
should_create_todo(user: member, target: issue, action: Todo::DIRECTLY_ADDRESSED)
|
|
should_create_todo(user: guest, target: issue, action: Todo::MENTIONED)
|
|
should_create_todo(user: admin, target: issue, action: Todo::MENTIONED)
|
|
end
|
|
|
|
it 'creates a directly addressed todo for each valid addressed user' do
|
|
service.update_issue(addressed_issue, author)
|
|
|
|
should_create_todo(user: member, target: addressed_issue, action: Todo::DIRECTLY_ADDRESSED)
|
|
should_create_todo(user: guest, target: addressed_issue, action: Todo::DIRECTLY_ADDRESSED)
|
|
should_create_todo(user: john_doe, target: addressed_issue, action: Todo::DIRECTLY_ADDRESSED)
|
|
should_create_todo(user: author, target: addressed_issue, action: Todo::DIRECTLY_ADDRESSED)
|
|
should_not_create_todo(user: non_member, target: addressed_issue, action: Todo::DIRECTLY_ADDRESSED)
|
|
end
|
|
|
|
it 'does not create a todo if user was already mentioned' do
|
|
create(:todo, :mentioned, user: member, project: project, target: issue, author: author)
|
|
|
|
expect { service.update_issue(issue, author) }.not_to change(member.todos, :count)
|
|
end
|
|
|
|
it 'does not create a directly addressed todo if user was already mentioned or addressed' do
|
|
create(:todo, :directly_addressed, user: member, project: project, target: addressed_issue, author: author)
|
|
|
|
expect { service.update_issue(addressed_issue, author) }.not_to change(member.todos, :count)
|
|
end
|
|
|
|
it 'does not create todo if user can not see the issue when issue is confidential' do
|
|
service.update_issue(confidential_issue, john_doe)
|
|
|
|
should_create_todo(user: author, target: confidential_issue, author: john_doe, action: Todo::MENTIONED)
|
|
should_create_todo(user: assignee, target: confidential_issue, author: john_doe, action: Todo::MENTIONED)
|
|
should_create_todo(user: member, target: confidential_issue, author: john_doe, action: Todo::MENTIONED)
|
|
should_create_todo(user: admin, target: confidential_issue, author: john_doe, action: Todo::MENTIONED)
|
|
should_not_create_todo(user: guest, target: confidential_issue, author: john_doe, action: Todo::MENTIONED)
|
|
should_create_todo(user: john_doe, target: confidential_issue, author: john_doe, action: Todo::MENTIONED)
|
|
end
|
|
|
|
it 'does not create a directly addressed todo if user can not see the issue when issue is confidential' do
|
|
service.update_issue(addressed_confident_issue, john_doe)
|
|
|
|
should_create_todo(user: author, target: addressed_confident_issue, author: john_doe, action: Todo::DIRECTLY_ADDRESSED)
|
|
should_create_todo(user: assignee, target: addressed_confident_issue, author: john_doe, action: Todo::DIRECTLY_ADDRESSED)
|
|
should_create_todo(user: member, target: addressed_confident_issue, author: john_doe, action: Todo::DIRECTLY_ADDRESSED)
|
|
should_create_todo(user: admin, target: addressed_confident_issue, author: john_doe, action: Todo::DIRECTLY_ADDRESSED)
|
|
should_not_create_todo(user: guest, target: addressed_confident_issue, author: john_doe, action: Todo::DIRECTLY_ADDRESSED)
|
|
should_create_todo(user: john_doe, target: addressed_confident_issue, author: john_doe, action: Todo::DIRECTLY_ADDRESSED)
|
|
end
|
|
|
|
context 'issues with a task list' do
|
|
it 'does not create todo when tasks are marked as completed' do
|
|
issue.update(description: "- [x] Task 1\n- [X] Task 2 #{mentions}")
|
|
|
|
service.update_issue(issue, author)
|
|
|
|
should_not_create_todo(user: admin, target: issue, action: Todo::MENTIONED)
|
|
should_not_create_todo(user: assignee, target: issue, action: Todo::MENTIONED)
|
|
should_not_create_todo(user: author, target: issue, action: Todo::MENTIONED)
|
|
should_not_create_todo(user: john_doe, target: issue, action: Todo::MENTIONED)
|
|
should_not_create_todo(user: member, target: issue, action: Todo::MENTIONED)
|
|
should_not_create_todo(user: non_member, target: issue, action: Todo::MENTIONED)
|
|
end
|
|
|
|
it 'does not create directly addressed todo when tasks are marked as completed' do
|
|
addressed_issue.update(description: "#{directly_addressed}\n- [x] Task 1\n- [x] Task 2\n")
|
|
|
|
service.update_issue(addressed_issue, author)
|
|
|
|
should_not_create_todo(user: admin, target: addressed_issue, action: Todo::DIRECTLY_ADDRESSED)
|
|
should_not_create_todo(user: assignee, target: addressed_issue, action: Todo::DIRECTLY_ADDRESSED)
|
|
should_not_create_todo(user: author, target: addressed_issue, action: Todo::DIRECTLY_ADDRESSED)
|
|
should_not_create_todo(user: john_doe, target: addressed_issue, action: Todo::DIRECTLY_ADDRESSED)
|
|
should_not_create_todo(user: member, target: addressed_issue, action: Todo::DIRECTLY_ADDRESSED)
|
|
should_not_create_todo(user: non_member, target: addressed_issue, action: Todo::DIRECTLY_ADDRESSED)
|
|
end
|
|
|
|
it 'does not raise an error when description not change' do
|
|
issue.update(title: 'Sample')
|
|
|
|
expect { service.update_issue(issue, author) }.not_to raise_error
|
|
end
|
|
end
|
|
end
|
|
|
|
describe '#close_issue' do
|
|
it 'marks related pending todos to the target for the user as done' do
|
|
first_todo = create(:todo, :assigned, user: john_doe, project: project, target: issue, author: author)
|
|
second_todo = create(:todo, :assigned, user: john_doe, project: project, target: issue, author: author)
|
|
|
|
service.close_issue(issue, john_doe)
|
|
|
|
expect(first_todo.reload).to be_done
|
|
expect(second_todo.reload).to be_done
|
|
end
|
|
end
|
|
|
|
describe '#destroy_issue' do
|
|
it 'refresh the todos count cache for the user' do
|
|
expect(john_doe).to receive(:update_todos_count_cache).and_call_original
|
|
|
|
service.destroy_issue(issue, john_doe)
|
|
end
|
|
end
|
|
|
|
describe '#reassigned_issue' do
|
|
it 'creates a pending todo for new assignee' do
|
|
unassigned_issue.update_attribute(:assignee, john_doe)
|
|
service.reassigned_issue(unassigned_issue, author)
|
|
|
|
should_create_todo(user: john_doe, target: unassigned_issue, action: Todo::ASSIGNED)
|
|
end
|
|
|
|
it 'does not create a todo if unassigned' do
|
|
issue.update_attribute(:assignee, nil)
|
|
|
|
should_not_create_any_todo { service.reassigned_issue(issue, author) }
|
|
end
|
|
|
|
it 'creates a todo if new assignee is the current user' do
|
|
unassigned_issue.update_attribute(:assignee, john_doe)
|
|
service.reassigned_issue(unassigned_issue, john_doe)
|
|
|
|
should_create_todo(user: john_doe, target: unassigned_issue, author: john_doe, action: Todo::ASSIGNED)
|
|
end
|
|
end
|
|
|
|
describe '#mark_pending_todos_as_done' do
|
|
it 'marks related pending todos to the target for the user as done' do
|
|
first_todo = create(:todo, :assigned, user: john_doe, project: project, target: issue, author: author)
|
|
second_todo = create(:todo, :assigned, user: john_doe, project: project, target: issue, author: author)
|
|
|
|
service.mark_pending_todos_as_done(issue, john_doe)
|
|
|
|
expect(first_todo.reload).to be_done
|
|
expect(second_todo.reload).to be_done
|
|
end
|
|
|
|
describe 'cached counts' do
|
|
it 'updates when todos change' do
|
|
create(:todo, :assigned, user: john_doe, project: project, target: issue, author: author)
|
|
|
|
expect(john_doe.todos_done_count).to eq(0)
|
|
expect(john_doe.todos_pending_count).to eq(1)
|
|
expect(john_doe).to receive(:update_todos_count_cache).and_call_original
|
|
|
|
service.mark_pending_todos_as_done(issue, john_doe)
|
|
|
|
expect(john_doe.todos_done_count).to eq(1)
|
|
expect(john_doe.todos_pending_count).to eq(0)
|
|
end
|
|
end
|
|
end
|
|
|
|
shared_examples 'updating todos state' do |meth, state, new_state|
|
|
let!(:first_todo) { create(:todo, state, user: john_doe, project: project, target: issue, author: author) }
|
|
let!(:second_todo) { create(:todo, state, user: john_doe, project: project, target: issue, author: author) }
|
|
|
|
it 'updates related todos for the user with the new_state' do
|
|
service.send(meth, collection, john_doe)
|
|
|
|
expect(first_todo.reload.state?(new_state)).to be true
|
|
expect(second_todo.reload.state?(new_state)).to be true
|
|
end
|
|
|
|
describe 'cached counts' do
|
|
it 'updates when todos change' do
|
|
expect(john_doe.todos.where(state: new_state).count).to eq(0)
|
|
expect(john_doe.todos.where(state: state).count).to eq(2)
|
|
expect(john_doe).to receive(:update_todos_count_cache).and_call_original
|
|
|
|
service.send(meth, collection, john_doe)
|
|
|
|
expect(john_doe.todos.where(state: new_state).count).to eq(2)
|
|
expect(john_doe.todos.where(state: state).count).to eq(0)
|
|
end
|
|
end
|
|
end
|
|
|
|
describe '#mark_todos_as_done' do
|
|
it_behaves_like 'updating todos state', :mark_todos_as_done, :pending, :done do
|
|
let(:collection) { [first_todo, second_todo] }
|
|
end
|
|
end
|
|
|
|
describe '#mark_todos_as_done_by_ids' do
|
|
it_behaves_like 'updating todos state', :mark_todos_as_done_by_ids, :pending, :done do
|
|
let(:collection) { [first_todo, second_todo].map(&:id) }
|
|
end
|
|
end
|
|
|
|
describe '#mark_todos_as_pending' do
|
|
it_behaves_like 'updating todos state', :mark_todos_as_pending, :done, :pending do
|
|
let(:collection) { [first_todo, second_todo] }
|
|
end
|
|
end
|
|
|
|
describe '#mark_todos_as_pending_by_ids' do
|
|
it_behaves_like 'updating todos state', :mark_todos_as_pending_by_ids, :done, :pending do
|
|
let(:collection) { [first_todo, second_todo].map(&:id) }
|
|
end
|
|
end
|
|
|
|
describe '#new_note' do
|
|
let!(:first_todo) { create(:todo, :assigned, user: john_doe, project: project, target: issue, author: author) }
|
|
let!(:second_todo) { create(:todo, :assigned, user: john_doe, project: project, target: issue, author: author) }
|
|
let(:confidential_issue) { create(:issue, :confidential, project: project, author: author, assignee: assignee) }
|
|
let(:note) { create(:note, project: project, noteable: issue, author: john_doe, note: mentions) }
|
|
let(:addressed_note) { create(:note, project: project, noteable: issue, author: john_doe, note: directly_addressed) }
|
|
let(:note_on_commit) { create(:note_on_commit, project: project, author: john_doe, note: mentions) }
|
|
let(:addressed_note_on_commit) { create(:note_on_commit, project: project, author: john_doe, note: directly_addressed) }
|
|
let(:note_on_confidential_issue) { create(:note_on_issue, noteable: confidential_issue, project: project, note: mentions) }
|
|
let(:addressed_note_on_confidential_issue) { create(:note_on_issue, noteable: confidential_issue, project: project, note: directly_addressed) }
|
|
let(:note_on_project_snippet) { create(:note_on_project_snippet, project: project, author: john_doe, note: mentions) }
|
|
let(:system_note) { create(:system_note, project: project, noteable: issue) }
|
|
|
|
it 'mark related pending todos to the noteable for the note author as done' do
|
|
first_todo = create(:todo, :assigned, user: john_doe, project: project, target: issue, author: author)
|
|
second_todo = create(:todo, :assigned, user: john_doe, project: project, target: issue, author: author)
|
|
|
|
service.new_note(note, john_doe)
|
|
|
|
expect(first_todo.reload).to be_done
|
|
expect(second_todo.reload).to be_done
|
|
end
|
|
|
|
it 'does not mark related pending todos it is a system note' do
|
|
service.new_note(system_note, john_doe)
|
|
|
|
expect(first_todo.reload).to be_pending
|
|
expect(second_todo.reload).to be_pending
|
|
end
|
|
|
|
it 'creates a todo for each valid mentioned user' do
|
|
service.new_note(note, john_doe)
|
|
|
|
should_create_todo(user: member, target: issue, author: john_doe, action: Todo::MENTIONED, note: note)
|
|
should_create_todo(user: guest, target: issue, author: john_doe, action: Todo::MENTIONED, note: note)
|
|
should_create_todo(user: author, target: issue, author: john_doe, action: Todo::MENTIONED, note: note)
|
|
should_create_todo(user: john_doe, target: issue, author: john_doe, action: Todo::MENTIONED, note: note)
|
|
should_not_create_todo(user: non_member, target: issue, author: john_doe, action: Todo::MENTIONED, note: note)
|
|
end
|
|
|
|
it 'creates a todo for each valid user based on the type of mention' do
|
|
note.update(note: directly_addressed_and_mentioned)
|
|
|
|
service.new_note(note, john_doe)
|
|
|
|
should_create_todo(user: member, target: issue, author: john_doe, action: Todo::DIRECTLY_ADDRESSED, note: note)
|
|
should_create_todo(user: admin, target: issue, author: john_doe, action: Todo::MENTIONED, note: note)
|
|
should_create_todo(user: guest, target: issue, author: john_doe, action: Todo::MENTIONED, note: note)
|
|
end
|
|
|
|
it 'creates a directly addressed todo for each valid addressed user' do
|
|
service.new_note(addressed_note, john_doe)
|
|
|
|
should_create_todo(user: member, target: issue, author: john_doe, action: Todo::DIRECTLY_ADDRESSED, note: addressed_note)
|
|
should_create_todo(user: guest, target: issue, author: john_doe, action: Todo::DIRECTLY_ADDRESSED, note: addressed_note)
|
|
should_create_todo(user: author, target: issue, author: john_doe, action: Todo::DIRECTLY_ADDRESSED, note: addressed_note)
|
|
should_create_todo(user: john_doe, target: issue, author: john_doe, action: Todo::DIRECTLY_ADDRESSED, note: addressed_note)
|
|
should_not_create_todo(user: non_member, target: issue, author: john_doe, action: Todo::DIRECTLY_ADDRESSED, note: addressed_note)
|
|
end
|
|
|
|
it 'does not create todo if user can not see the issue when leaving a note on a confidential issue' do
|
|
service.new_note(note_on_confidential_issue, john_doe)
|
|
|
|
should_create_todo(user: author, target: confidential_issue, author: john_doe, action: Todo::MENTIONED, note: note_on_confidential_issue)
|
|
should_create_todo(user: assignee, target: confidential_issue, author: john_doe, action: Todo::MENTIONED, note: note_on_confidential_issue)
|
|
should_create_todo(user: member, target: confidential_issue, author: john_doe, action: Todo::MENTIONED, note: note_on_confidential_issue)
|
|
should_create_todo(user: admin, target: confidential_issue, author: john_doe, action: Todo::MENTIONED, note: note_on_confidential_issue)
|
|
should_not_create_todo(user: guest, target: confidential_issue, author: john_doe, action: Todo::MENTIONED, note: note_on_confidential_issue)
|
|
should_create_todo(user: john_doe, target: confidential_issue, author: john_doe, action: Todo::MENTIONED, note: note_on_confidential_issue)
|
|
end
|
|
|
|
it 'does not create a directly addressed todo if user can not see the issue when leaving a note on a confidential issue' do
|
|
service.new_note(addressed_note_on_confidential_issue, john_doe)
|
|
|
|
should_create_todo(user: author, target: confidential_issue, author: john_doe, action: Todo::DIRECTLY_ADDRESSED, note: addressed_note_on_confidential_issue)
|
|
should_create_todo(user: assignee, target: confidential_issue, author: john_doe, action: Todo::DIRECTLY_ADDRESSED, note: addressed_note_on_confidential_issue)
|
|
should_create_todo(user: member, target: confidential_issue, author: john_doe, action: Todo::DIRECTLY_ADDRESSED, note: addressed_note_on_confidential_issue)
|
|
should_create_todo(user: admin, target: confidential_issue, author: john_doe, action: Todo::DIRECTLY_ADDRESSED, note: addressed_note_on_confidential_issue)
|
|
should_not_create_todo(user: guest, target: confidential_issue, author: john_doe, action: Todo::DIRECTLY_ADDRESSED, note: addressed_note_on_confidential_issue)
|
|
should_create_todo(user: john_doe, target: confidential_issue, author: john_doe, action: Todo::DIRECTLY_ADDRESSED, note: addressed_note_on_confidential_issue)
|
|
end
|
|
|
|
it 'creates a todo for each valid mentioned user when leaving a note on commit' do
|
|
service.new_note(note_on_commit, john_doe)
|
|
|
|
should_create_todo(user: member, target_id: nil, target_type: 'Commit', commit_id: note_on_commit.commit_id, author: john_doe, action: Todo::MENTIONED, note: note_on_commit)
|
|
should_create_todo(user: author, target_id: nil, target_type: 'Commit', commit_id: note_on_commit.commit_id, author: john_doe, action: Todo::MENTIONED, note: note_on_commit)
|
|
should_create_todo(user: john_doe, target_id: nil, target_type: 'Commit', commit_id: note_on_commit.commit_id, author: john_doe, action: Todo::MENTIONED, note: note_on_commit)
|
|
should_not_create_todo(user: non_member, target_id: nil, target_type: 'Commit', commit_id: note_on_commit.commit_id, author: john_doe, action: Todo::MENTIONED, note: note_on_commit)
|
|
end
|
|
|
|
it 'creates a directly addressed todo for each valid mentioned user when leaving a note on commit' do
|
|
service.new_note(addressed_note_on_commit, john_doe)
|
|
|
|
should_create_todo(user: member, target_id: nil, target_type: 'Commit', commit_id: addressed_note_on_commit.commit_id, author: john_doe, action: Todo::DIRECTLY_ADDRESSED, note: addressed_note_on_commit)
|
|
should_create_todo(user: author, target_id: nil, target_type: 'Commit', commit_id: addressed_note_on_commit.commit_id, author: john_doe, action: Todo::DIRECTLY_ADDRESSED, note: addressed_note_on_commit)
|
|
should_create_todo(user: john_doe, target_id: nil, target_type: 'Commit', commit_id: addressed_note_on_commit.commit_id, author: john_doe, action: Todo::DIRECTLY_ADDRESSED, note: addressed_note_on_commit)
|
|
should_not_create_todo(user: non_member, target_id: nil, target_type: 'Commit', commit_id: addressed_note_on_commit.commit_id, author: john_doe, action: Todo::DIRECTLY_ADDRESSED, note: addressed_note_on_commit)
|
|
end
|
|
|
|
it 'does not create todo when leaving a note on snippet' do
|
|
should_not_create_any_todo { service.new_note(note_on_project_snippet, john_doe) }
|
|
end
|
|
end
|
|
|
|
describe '#mark_todo' do
|
|
it 'creates a todo from a issue' do
|
|
service.mark_todo(unassigned_issue, author)
|
|
|
|
should_create_todo(user: author, target: unassigned_issue, action: Todo::MARKED)
|
|
end
|
|
end
|
|
|
|
describe '#todo_exists?' do
|
|
it 'returns false when no todo exist for the given issuable' do
|
|
expect(service.todo_exist?(unassigned_issue, author)).to be_falsy
|
|
end
|
|
|
|
it 'returns true when a todo exist for the given issuable' do
|
|
service.mark_todo(unassigned_issue, author)
|
|
|
|
expect(service.todo_exist?(unassigned_issue, author)).to be_truthy
|
|
end
|
|
end
|
|
end
|
|
|
|
describe 'Merge Requests' do
|
|
let(:mr_assigned) { create(:merge_request, source_project: project, author: author, assignee: john_doe, description: "- [ ] Task 1\n- [ ] Task 2 #{mentions}") }
|
|
let(:addressed_mr_assigned) { create(:merge_request, source_project: project, author: author, assignee: john_doe, description: "#{directly_addressed}\n- [ ] Task 1\n- [ ] Task 2") }
|
|
let(:mr_unassigned) { create(:merge_request, source_project: project, author: author, assignee: nil) }
|
|
|
|
describe '#new_merge_request' do
|
|
it 'creates a pending todo if assigned' do
|
|
service.new_merge_request(mr_assigned, author)
|
|
|
|
should_create_todo(user: john_doe, target: mr_assigned, action: Todo::ASSIGNED)
|
|
end
|
|
|
|
it 'does not create a todo if unassigned' do
|
|
should_not_create_any_todo { service.new_merge_request(mr_unassigned, author) }
|
|
end
|
|
|
|
it 'does not create a todo if assignee is the current user' do
|
|
should_not_create_any_todo { service.new_merge_request(mr_unassigned, john_doe) }
|
|
end
|
|
|
|
it 'creates a todo for each valid mentioned user' do
|
|
service.new_merge_request(mr_assigned, author)
|
|
|
|
should_create_todo(user: member, target: mr_assigned, action: Todo::MENTIONED)
|
|
should_not_create_todo(user: guest, target: mr_assigned, action: Todo::MENTIONED)
|
|
should_create_todo(user: author, target: mr_assigned, action: Todo::MENTIONED)
|
|
should_not_create_todo(user: john_doe, target: mr_assigned, action: Todo::MENTIONED)
|
|
should_not_create_todo(user: non_member, target: mr_assigned, action: Todo::MENTIONED)
|
|
end
|
|
|
|
it 'creates a todo for each valid user based on the type of mention' do
|
|
mr_assigned.update(description: directly_addressed_and_mentioned)
|
|
|
|
service.new_merge_request(mr_assigned, author)
|
|
|
|
should_create_todo(user: member, target: mr_assigned, action: Todo::DIRECTLY_ADDRESSED)
|
|
should_create_todo(user: admin, target: mr_assigned, action: Todo::MENTIONED)
|
|
end
|
|
|
|
it 'creates a directly addressed todo for each valid addressed user' do
|
|
service.new_merge_request(addressed_mr_assigned, author)
|
|
|
|
should_create_todo(user: member, target: addressed_mr_assigned, action: Todo::DIRECTLY_ADDRESSED)
|
|
should_not_create_todo(user: guest, target: addressed_mr_assigned, action: Todo::DIRECTLY_ADDRESSED)
|
|
should_create_todo(user: author, target: addressed_mr_assigned, action: Todo::DIRECTLY_ADDRESSED)
|
|
should_not_create_todo(user: john_doe, target: addressed_mr_assigned, action: Todo::DIRECTLY_ADDRESSED)
|
|
should_not_create_todo(user: non_member, target: addressed_mr_assigned, action: Todo::DIRECTLY_ADDRESSED)
|
|
end
|
|
end
|
|
|
|
describe '#update_merge_request' do
|
|
it 'creates a todo for each valid mentioned user' do
|
|
service.update_merge_request(mr_assigned, author)
|
|
|
|
should_create_todo(user: member, target: mr_assigned, action: Todo::MENTIONED)
|
|
should_not_create_todo(user: guest, target: mr_assigned, action: Todo::MENTIONED)
|
|
should_create_todo(user: john_doe, target: mr_assigned, action: Todo::MENTIONED)
|
|
should_create_todo(user: author, target: mr_assigned, action: Todo::MENTIONED)
|
|
should_not_create_todo(user: non_member, target: mr_assigned, action: Todo::MENTIONED)
|
|
end
|
|
|
|
it 'creates a todo for each valid user based on the type of mention' do
|
|
mr_assigned.update(description: directly_addressed_and_mentioned)
|
|
|
|
service.update_merge_request(mr_assigned, author)
|
|
|
|
should_create_todo(user: member, target: mr_assigned, action: Todo::DIRECTLY_ADDRESSED)
|
|
should_create_todo(user: admin, target: mr_assigned, action: Todo::MENTIONED)
|
|
end
|
|
|
|
it 'creates a directly addressed todo for each valid addressed user' do
|
|
service.update_merge_request(addressed_mr_assigned, author)
|
|
|
|
should_create_todo(user: member, target: addressed_mr_assigned, action: Todo::DIRECTLY_ADDRESSED)
|
|
should_not_create_todo(user: guest, target: addressed_mr_assigned, action: Todo::DIRECTLY_ADDRESSED)
|
|
should_create_todo(user: john_doe, target: addressed_mr_assigned, action: Todo::DIRECTLY_ADDRESSED)
|
|
should_create_todo(user: author, target: addressed_mr_assigned, action: Todo::DIRECTLY_ADDRESSED)
|
|
should_not_create_todo(user: non_member, target: addressed_mr_assigned, action: Todo::DIRECTLY_ADDRESSED)
|
|
end
|
|
|
|
it 'does not create a todo if user was already mentioned' do
|
|
create(:todo, :mentioned, user: member, project: project, target: mr_assigned, author: author)
|
|
|
|
expect { service.update_merge_request(mr_assigned, author) }.not_to change(member.todos, :count)
|
|
end
|
|
|
|
it 'does not create a directly addressed todo if user was already mentioned or addressed' do
|
|
create(:todo, :directly_addressed, user: member, project: project, target: addressed_mr_assigned, author: author)
|
|
|
|
expect{ service.update_merge_request(addressed_mr_assigned, author) }.not_to change(member.todos, :count)
|
|
end
|
|
|
|
context 'with a task list' do
|
|
it 'does not create todo when tasks are marked as completed' do
|
|
mr_assigned.update(description: "- [x] Task 1\n- [X] Task 2 #{mentions}")
|
|
|
|
service.update_merge_request(mr_assigned, author)
|
|
|
|
should_not_create_todo(user: admin, target: mr_assigned, action: Todo::MENTIONED)
|
|
should_not_create_todo(user: assignee, target: mr_assigned, action: Todo::MENTIONED)
|
|
should_not_create_todo(user: author, target: mr_assigned, action: Todo::MENTIONED)
|
|
should_not_create_todo(user: john_doe, target: mr_assigned, action: Todo::MENTIONED)
|
|
should_not_create_todo(user: member, target: mr_assigned, action: Todo::MENTIONED)
|
|
should_not_create_todo(user: non_member, target: mr_assigned, action: Todo::MENTIONED)
|
|
should_not_create_todo(user: guest, target: mr_assigned, action: Todo::MENTIONED)
|
|
end
|
|
|
|
it 'does not create directly addressed todo when tasks are marked as completed' do
|
|
addressed_mr_assigned.update(description: "#{directly_addressed}\n- [x] Task 1\n- [X] Task 2")
|
|
|
|
service.update_merge_request(addressed_mr_assigned, author)
|
|
|
|
should_not_create_todo(user: admin, target: addressed_mr_assigned, action: Todo::DIRECTLY_ADDRESSED)
|
|
should_not_create_todo(user: assignee, target: addressed_mr_assigned, action: Todo::DIRECTLY_ADDRESSED)
|
|
should_not_create_todo(user: author, target: addressed_mr_assigned, action: Todo::DIRECTLY_ADDRESSED)
|
|
should_not_create_todo(user: john_doe, target: addressed_mr_assigned, action: Todo::DIRECTLY_ADDRESSED)
|
|
should_not_create_todo(user: member, target: addressed_mr_assigned, action: Todo::DIRECTLY_ADDRESSED)
|
|
should_not_create_todo(user: non_member, target: addressed_mr_assigned, action: Todo::DIRECTLY_ADDRESSED)
|
|
should_not_create_todo(user: guest, target: addressed_mr_assigned, action: Todo::DIRECTLY_ADDRESSED)
|
|
end
|
|
|
|
it 'does not raise an error when description not change' do
|
|
mr_assigned.update(title: 'Sample')
|
|
|
|
expect { service.update_merge_request(mr_assigned, author) }.not_to raise_error
|
|
end
|
|
end
|
|
end
|
|
|
|
describe '#close_merge_request' do
|
|
it 'marks related pending todos to the target for the user as done' do
|
|
first_todo = create(:todo, :assigned, user: john_doe, project: project, target: mr_assigned, author: author)
|
|
second_todo = create(:todo, :assigned, user: john_doe, project: project, target: mr_assigned, author: author)
|
|
service.close_merge_request(mr_assigned, john_doe)
|
|
|
|
expect(first_todo.reload).to be_done
|
|
expect(second_todo.reload).to be_done
|
|
end
|
|
end
|
|
|
|
describe '#destroy_merge_request' do
|
|
it 'refresh the todos count cache for the user' do
|
|
expect(john_doe).to receive(:update_todos_count_cache).and_call_original
|
|
|
|
service.destroy_merge_request(mr_assigned, john_doe)
|
|
end
|
|
end
|
|
|
|
describe '#reassigned_merge_request' do
|
|
it 'creates a pending todo for new assignee' do
|
|
mr_unassigned.update_attribute(:assignee, john_doe)
|
|
service.reassigned_merge_request(mr_unassigned, author)
|
|
|
|
should_create_todo(user: john_doe, target: mr_unassigned, action: Todo::ASSIGNED)
|
|
end
|
|
|
|
it 'does not create a todo if unassigned' do
|
|
mr_assigned.update_attribute(:assignee, nil)
|
|
|
|
should_not_create_any_todo { service.reassigned_merge_request(mr_assigned, author) }
|
|
end
|
|
|
|
it 'creates a todo if new assignee is the current user' do
|
|
mr_assigned.update_attribute(:assignee, john_doe)
|
|
service.reassigned_merge_request(mr_assigned, john_doe)
|
|
|
|
should_create_todo(user: john_doe, target: mr_assigned, author: john_doe, action: Todo::ASSIGNED)
|
|
end
|
|
|
|
it 'does not create a todo for guests' do
|
|
service.reassigned_merge_request(mr_assigned, author)
|
|
should_not_create_todo(user: guest, target: mr_assigned, action: Todo::MENTIONED)
|
|
end
|
|
|
|
it 'does not create a directly addressed todo for guests' do
|
|
service.reassigned_merge_request(addressed_mr_assigned, author)
|
|
should_not_create_todo(user: guest, target: addressed_mr_assigned, action: Todo::DIRECTLY_ADDRESSED)
|
|
end
|
|
end
|
|
|
|
describe '#merge_merge_request' do
|
|
it 'marks related pending todos to the target for the user as done' do
|
|
first_todo = create(:todo, :assigned, user: john_doe, project: project, target: mr_assigned, author: author)
|
|
second_todo = create(:todo, :assigned, user: john_doe, project: project, target: mr_assigned, author: author)
|
|
service.merge_merge_request(mr_assigned, john_doe)
|
|
|
|
expect(first_todo.reload).to be_done
|
|
expect(second_todo.reload).to be_done
|
|
end
|
|
|
|
it 'does not create todo for guests' do
|
|
service.merge_merge_request(mr_assigned, john_doe)
|
|
should_not_create_todo(user: guest, target: mr_assigned, action: Todo::MENTIONED)
|
|
end
|
|
|
|
it 'does not create directly addressed todo for guests' do
|
|
service.merge_merge_request(addressed_mr_assigned, john_doe)
|
|
should_not_create_todo(user: guest, target: addressed_mr_assigned, action: Todo::DIRECTLY_ADDRESSED)
|
|
end
|
|
end
|
|
|
|
describe '#new_award_emoji' do
|
|
it 'marks related pending todos to the target for the user as done' do
|
|
todo = create(:todo, user: john_doe, project: project, target: mr_assigned, author: author)
|
|
service.new_award_emoji(mr_assigned, john_doe)
|
|
|
|
expect(todo.reload).to be_done
|
|
end
|
|
end
|
|
|
|
describe '#merge_request_build_failed' do
|
|
it 'creates a pending todo for the merge request author' do
|
|
service.merge_request_build_failed(mr_unassigned)
|
|
|
|
should_create_todo(user: author, target: mr_unassigned, action: Todo::BUILD_FAILED)
|
|
end
|
|
|
|
it 'creates a pending todo for merge_user' do
|
|
mr_unassigned.update(merge_when_pipeline_succeeds: true, merge_user: admin)
|
|
service.merge_request_build_failed(mr_unassigned)
|
|
|
|
should_create_todo(user: admin, author: admin, target: mr_unassigned, action: Todo::BUILD_FAILED)
|
|
end
|
|
end
|
|
|
|
describe '#merge_request_push' do
|
|
it 'marks related pending todos to the target for the user as done' do
|
|
first_todo = create(:todo, :build_failed, user: author, project: project, target: mr_assigned, author: john_doe)
|
|
second_todo = create(:todo, :build_failed, user: john_doe, project: project, target: mr_assigned, author: john_doe)
|
|
service.merge_request_push(mr_assigned, author)
|
|
|
|
expect(first_todo.reload).to be_done
|
|
expect(second_todo.reload).not_to be_done
|
|
end
|
|
end
|
|
|
|
describe '#merge_request_became_unmergeable' do
|
|
it 'creates a pending todo for a merge_user' do
|
|
mr_unassigned.update(merge_when_pipeline_succeeds: true, merge_user: admin)
|
|
service.merge_request_became_unmergeable(mr_unassigned)
|
|
|
|
should_create_todo(user: admin, author: admin, target: mr_unassigned, action: Todo::UNMERGEABLE)
|
|
end
|
|
end
|
|
|
|
describe '#mark_todo' do
|
|
it 'creates a todo from a merge request' do
|
|
service.mark_todo(mr_unassigned, author)
|
|
|
|
should_create_todo(user: author, target: mr_unassigned, action: Todo::MARKED)
|
|
end
|
|
end
|
|
|
|
describe '#new_note' do
|
|
let(:mention) { john_doe.to_reference }
|
|
let(:diff_note_on_merge_request) { create(:diff_note_on_merge_request, project: project, noteable: mr_unassigned, author: author, note: "Hey #{mention}") }
|
|
let(:addressed_diff_note_on_merge_request) { create(:diff_note_on_merge_request, project: project, noteable: mr_unassigned, author: author, note: "#{mention}, hey!") }
|
|
let(:legacy_diff_note_on_merge_request) { create(:legacy_diff_note_on_merge_request, project: project, noteable: mr_unassigned, author: author, note: "Hey #{mention}") }
|
|
|
|
it 'creates a todo for mentioned user on new diff note' do
|
|
service.new_note(diff_note_on_merge_request, author)
|
|
|
|
should_create_todo(user: john_doe, target: mr_unassigned, author: author, action: Todo::MENTIONED, note: diff_note_on_merge_request)
|
|
end
|
|
|
|
it 'creates a directly addressed todo for addressed user on new diff note' do
|
|
service.new_note(addressed_diff_note_on_merge_request, author)
|
|
|
|
should_create_todo(user: john_doe, target: mr_unassigned, author: author, action: Todo::DIRECTLY_ADDRESSED, note: addressed_diff_note_on_merge_request)
|
|
end
|
|
|
|
it 'creates a todo for mentioned user on legacy diff note' do
|
|
service.new_note(legacy_diff_note_on_merge_request, author)
|
|
|
|
should_create_todo(user: john_doe, target: mr_unassigned, author: author, action: Todo::MENTIONED, note: legacy_diff_note_on_merge_request)
|
|
end
|
|
|
|
it 'does not create todo for guests' do
|
|
note_on_merge_request = create :note_on_merge_request, project: project, noteable: mr_assigned, note: mentions
|
|
service.new_note(note_on_merge_request, author)
|
|
|
|
should_not_create_todo(user: guest, target: mr_assigned, action: Todo::MENTIONED)
|
|
end
|
|
end
|
|
end
|
|
|
|
it 'updates cached counts when a todo is created' do
|
|
issue = create(:issue, project: project, assignee: john_doe, author: author, description: mentions)
|
|
|
|
expect(john_doe.todos_pending_count).to eq(0)
|
|
expect(john_doe).to receive(:update_todos_count_cache)
|
|
|
|
service.new_issue(issue, author)
|
|
|
|
expect(Todo.where(user_id: john_doe.id, state: :pending).count).to eq 1
|
|
expect(john_doe.todos_pending_count).to eq(1)
|
|
end
|
|
|
|
describe '#mark_todos_as_done' do
|
|
let(:issue) { create(:issue, project: project, author: author, assignee: john_doe) }
|
|
let(:another_issue) { create(:issue, project: project, author: author, assignee: john_doe) }
|
|
|
|
it 'marks a relation of todos as done' do
|
|
create(:todo, :mentioned, user: john_doe, target: issue, project: project)
|
|
|
|
todos = TodosFinder.new(john_doe, {}).execute
|
|
expect { TodoService.new.mark_todos_as_done(todos, john_doe) }
|
|
.to change { john_doe.todos.done.count }.from(0).to(1)
|
|
end
|
|
|
|
it 'marks an array of todos as done' do
|
|
todo = create(:todo, :mentioned, user: john_doe, target: issue, project: project)
|
|
|
|
expect { TodoService.new.mark_todos_as_done([todo], john_doe) }
|
|
.to change { todo.reload.state }.from('pending').to('done')
|
|
end
|
|
|
|
it 'returns the number of updated todos' do # Needed on API
|
|
todo = create(:todo, :mentioned, user: john_doe, target: issue, project: project)
|
|
|
|
expect(TodoService.new.mark_todos_as_done([todo], john_doe)).to eq(1)
|
|
end
|
|
|
|
context 'when some of the todos are done already' do
|
|
before do
|
|
create(:todo, :mentioned, user: john_doe, target: issue, project: project)
|
|
create(:todo, :mentioned, user: john_doe, target: another_issue, project: project)
|
|
end
|
|
|
|
it 'returns the number of those still pending' do
|
|
TodoService.new.mark_pending_todos_as_done(issue, john_doe)
|
|
|
|
expect(TodoService.new.mark_todos_as_done(Todo.all, john_doe)).to eq(1)
|
|
end
|
|
|
|
it 'returns 0 if all are done' do
|
|
TodoService.new.mark_pending_todos_as_done(issue, john_doe)
|
|
TodoService.new.mark_pending_todos_as_done(another_issue, john_doe)
|
|
|
|
expect(TodoService.new.mark_todos_as_done(Todo.all, john_doe)).to eq(0)
|
|
end
|
|
end
|
|
|
|
it 'caches the number of todos of a user', :caching do
|
|
create(:todo, :mentioned, user: john_doe, target: issue, project: project)
|
|
todo = create(:todo, :mentioned, user: john_doe, target: issue, project: project)
|
|
TodoService.new.mark_todos_as_done([todo], john_doe)
|
|
|
|
expect_any_instance_of(TodosFinder).not_to receive(:execute)
|
|
|
|
expect(john_doe.todos_done_count).to eq(1)
|
|
expect(john_doe.todos_pending_count).to eq(1)
|
|
end
|
|
end
|
|
|
|
def should_create_todo(attributes = {})
|
|
attributes.reverse_merge!(
|
|
project: project,
|
|
author: author,
|
|
state: :pending
|
|
)
|
|
|
|
expect(Todo.where(attributes).count).to eq 1
|
|
end
|
|
|
|
def should_not_create_todo(attributes = {})
|
|
attributes.reverse_merge!(
|
|
project: project,
|
|
author: author,
|
|
state: :pending
|
|
)
|
|
|
|
expect(Todo.where(attributes).count).to eq 0
|
|
end
|
|
|
|
def should_not_create_any_todo
|
|
expect { yield }.not_to change(Todo, :count)
|
|
end
|
|
end
|