2019-07-31 22:56:46 +05:30
|
|
|
# frozen_string_literal: true
|
|
|
|
|
2016-06-02 11:05:42 +05:30
|
|
|
require 'spec_helper'
|
|
|
|
|
2020-07-28 23:09:34 +05:30
|
|
|
RSpec.describe Issues::MoveService do
|
2016-06-02 11:05:42 +05:30
|
|
|
let(:user) { create(:user) }
|
|
|
|
let(:author) { create(:user) }
|
|
|
|
let(:title) { 'Some issue' }
|
2020-03-13 15:44:24 +05:30
|
|
|
let(:description) { "Some issue description with mention to #{user.to_reference}" }
|
2018-11-08 19:23:39 +05:30
|
|
|
let(:group) { create(:group, :private) }
|
|
|
|
let(:sub_group_1) { create(:group, :private, parent: group) }
|
|
|
|
let(:sub_group_2) { create(:group, :private, parent: group) }
|
|
|
|
let(:old_project) { create(:project, namespace: sub_group_1) }
|
|
|
|
let(:new_project) { create(:project, namespace: sub_group_2) }
|
2016-06-02 11:05:42 +05:30
|
|
|
|
|
|
|
let(:old_issue) do
|
2019-02-15 15:39:39 +05:30
|
|
|
create(:issue, title: title, description: description, project: old_project, author: author)
|
2016-06-02 11:05:42 +05:30
|
|
|
end
|
|
|
|
|
2018-11-08 19:23:39 +05:30
|
|
|
subject(:move_service) do
|
2016-06-02 11:05:42 +05:30
|
|
|
described_class.new(old_project, user)
|
|
|
|
end
|
|
|
|
|
|
|
|
shared_context 'user can move issue' do
|
|
|
|
before do
|
2018-03-17 18:26:18 +05:30
|
|
|
old_project.add_reporter(user)
|
|
|
|
new_project.add_reporter(user)
|
2016-06-02 11:05:42 +05:30
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
describe '#execute' do
|
|
|
|
shared_context 'issue move executed' do
|
2016-06-16 23:09:34 +05:30
|
|
|
let!(:award_emoji) { create(:award_emoji, awardable: old_issue) }
|
2016-06-02 11:05:42 +05:30
|
|
|
|
|
|
|
let!(:new_issue) { move_service.execute(old_issue, new_project) }
|
|
|
|
end
|
|
|
|
|
|
|
|
context 'issue movable' do
|
2020-03-13 15:44:24 +05:30
|
|
|
let!(:note_with_mention) { create(:note, noteable: old_issue, author: author, project: old_project, note: "note with mention #{user.to_reference}") }
|
|
|
|
let!(:note_with_no_mention) { create(:note, noteable: old_issue, author: author, project: old_project, note: "note without mention") }
|
|
|
|
|
2016-06-02 11:05:42 +05:30
|
|
|
include_context 'user can move issue'
|
|
|
|
|
|
|
|
context 'generic issue' do
|
|
|
|
include_context 'issue move executed'
|
|
|
|
|
|
|
|
it 'creates a new issue in a new project' do
|
|
|
|
expect(new_issue.project).to eq new_project
|
|
|
|
end
|
|
|
|
|
|
|
|
it 'rewrites issue title' do
|
|
|
|
expect(new_issue.title).to eq title
|
|
|
|
end
|
|
|
|
|
|
|
|
it 'rewrites issue description' do
|
|
|
|
expect(new_issue.description).to eq description
|
|
|
|
end
|
|
|
|
|
|
|
|
it 'adds system note to old issue at the end' do
|
2017-08-17 22:00:37 +05:30
|
|
|
expect(old_issue.notes.last.note).to start_with 'moved to'
|
2016-06-02 11:05:42 +05:30
|
|
|
end
|
|
|
|
|
|
|
|
it 'adds system note to new issue at the end' do
|
2017-08-17 22:00:37 +05:30
|
|
|
expect(new_issue.notes.last.note).to start_with 'moved from'
|
2016-06-02 11:05:42 +05:30
|
|
|
end
|
|
|
|
|
|
|
|
it 'closes old issue' do
|
|
|
|
expect(old_issue.closed?).to be true
|
|
|
|
end
|
|
|
|
|
|
|
|
it 'persists new issue' do
|
|
|
|
expect(new_issue.persisted?).to be true
|
|
|
|
end
|
|
|
|
|
|
|
|
it 'persists all changes' do
|
|
|
|
expect(old_issue.changed?).to be false
|
|
|
|
expect(new_issue.changed?).to be false
|
|
|
|
end
|
|
|
|
|
|
|
|
it 'preserves author' do
|
|
|
|
expect(new_issue.author).to eq author
|
|
|
|
end
|
|
|
|
|
|
|
|
it 'creates a new internal id for issue' do
|
|
|
|
expect(new_issue.iid).to be 1
|
|
|
|
end
|
|
|
|
|
|
|
|
it 'marks issue as moved' do
|
|
|
|
expect(old_issue.moved?).to eq true
|
|
|
|
expect(old_issue.moved_to).to eq new_issue
|
|
|
|
end
|
|
|
|
|
|
|
|
it 'preserves create time' do
|
|
|
|
expect(old_issue.created_at).to eq new_issue.created_at
|
|
|
|
end
|
2016-06-16 23:09:34 +05:30
|
|
|
|
|
|
|
it 'moves the award emoji' do
|
|
|
|
expect(old_issue.award_emoji.first.name).to eq new_issue.reload.award_emoji.first.name
|
|
|
|
end
|
2020-03-13 15:44:24 +05:30
|
|
|
|
|
|
|
context 'when issue has notes with mentions' do
|
|
|
|
it 'saves user mentions with actual mentions for new issue' do
|
2020-04-22 19:07:51 +05:30
|
|
|
expect(new_issue.user_mentions.find_by(note_id: nil).mentioned_users_ids).to match_array([user.id])
|
2020-03-13 15:44:24 +05:30
|
|
|
expect(new_issue.user_mentions.where.not(note_id: nil).first.mentioned_users_ids).to match_array([user.id])
|
|
|
|
expect(new_issue.user_mentions.where.not(note_id: nil).count).to eq 1
|
|
|
|
expect(new_issue.user_mentions.count).to eq 2
|
|
|
|
end
|
|
|
|
end
|
2016-06-02 11:05:42 +05:30
|
|
|
end
|
|
|
|
|
2019-02-15 15:39:39 +05:30
|
|
|
context 'issue with assignee' do
|
|
|
|
let(:assignee) { create(:user) }
|
2019-01-03 12:48:30 +05:30
|
|
|
|
2019-02-15 15:39:39 +05:30
|
|
|
before do
|
|
|
|
old_issue.assignees = [assignee]
|
2019-01-03 12:48:30 +05:30
|
|
|
end
|
2016-11-03 12:29:30 +05:30
|
|
|
|
2019-02-15 15:39:39 +05:30
|
|
|
it 'preserves assignee with access to the new issue' do
|
|
|
|
new_project.add_reporter(assignee)
|
2019-01-03 12:48:30 +05:30
|
|
|
|
2019-02-15 15:39:39 +05:30
|
|
|
new_issue = move_service.execute(old_issue, new_project)
|
2019-01-03 12:48:30 +05:30
|
|
|
|
2019-02-15 15:39:39 +05:30
|
|
|
expect(new_issue.assignees).to eq([assignee])
|
2019-01-03 12:48:30 +05:30
|
|
|
end
|
|
|
|
|
2019-02-15 15:39:39 +05:30
|
|
|
it 'ignores assignee without access to the new issue' do
|
|
|
|
new_issue = move_service.execute(old_issue, new_project)
|
2019-01-03 12:48:30 +05:30
|
|
|
|
2019-02-15 15:39:39 +05:30
|
|
|
expect(new_issue.assignees).to be_empty
|
2016-11-03 12:29:30 +05:30
|
|
|
end
|
2016-06-02 11:05:42 +05:30
|
|
|
end
|
|
|
|
|
|
|
|
context 'moving to same project' do
|
|
|
|
let(:new_project) { old_project }
|
|
|
|
|
|
|
|
it 'raises error' do
|
|
|
|
expect { move_service.execute(old_issue, new_project) }
|
|
|
|
.to raise_error(StandardError, /Cannot move issue/)
|
|
|
|
end
|
|
|
|
end
|
2018-03-17 18:26:18 +05:30
|
|
|
|
|
|
|
context 'project issue hooks' do
|
|
|
|
let!(:hook) { create(:project_hook, project: old_project, issues_events: true) }
|
|
|
|
|
|
|
|
it 'executes project issue hooks' do
|
2020-01-01 13:55:28 +05:30
|
|
|
allow_next_instance_of(WebHookService) do |instance|
|
|
|
|
allow(instance).to receive(:execute)
|
|
|
|
end
|
2018-03-17 18:26:18 +05:30
|
|
|
|
|
|
|
# Ideally, we'd test that `WebHookWorker.jobs.size` increased by 1,
|
|
|
|
# but since the entire spec run takes place in a transaction, we never
|
|
|
|
# actually get to the `after_commit` hook that queues these jobs.
|
|
|
|
expect { move_service.execute(old_issue, new_project) }
|
|
|
|
.not_to raise_error # Sidekiq::Worker::EnqueueFromTransactionError
|
|
|
|
end
|
|
|
|
end
|
2016-06-02 11:05:42 +05:30
|
|
|
end
|
|
|
|
|
|
|
|
describe 'move permissions' do
|
|
|
|
let(:move) { move_service.execute(old_issue, new_project) }
|
|
|
|
|
|
|
|
context 'user is reporter in both projects' do
|
|
|
|
include_context 'user can move issue'
|
2016-06-16 23:09:34 +05:30
|
|
|
it { expect { move }.not_to raise_error }
|
2016-06-02 11:05:42 +05:30
|
|
|
end
|
|
|
|
|
|
|
|
context 'user is reporter only in new project' do
|
2017-09-10 17:25:29 +05:30
|
|
|
before do
|
2018-03-17 18:26:18 +05:30
|
|
|
new_project.add_reporter(user)
|
2017-09-10 17:25:29 +05:30
|
|
|
end
|
|
|
|
|
2016-06-02 11:05:42 +05:30
|
|
|
it { expect { move }.to raise_error(StandardError, /permissions/) }
|
|
|
|
end
|
|
|
|
|
|
|
|
context 'user is reporter only in old project' do
|
2017-09-10 17:25:29 +05:30
|
|
|
before do
|
2018-03-17 18:26:18 +05:30
|
|
|
old_project.add_reporter(user)
|
2017-09-10 17:25:29 +05:30
|
|
|
end
|
|
|
|
|
2016-06-02 11:05:42 +05:30
|
|
|
it { expect { move }.to raise_error(StandardError, /permissions/) }
|
|
|
|
end
|
|
|
|
|
|
|
|
context 'user is reporter in one project and guest in another' do
|
|
|
|
before do
|
2018-03-17 18:26:18 +05:30
|
|
|
new_project.add_guest(user)
|
|
|
|
old_project.add_reporter(user)
|
2016-06-02 11:05:42 +05:30
|
|
|
end
|
|
|
|
|
|
|
|
it { expect { move }.to raise_error(StandardError, /permissions/) }
|
|
|
|
end
|
|
|
|
|
|
|
|
context 'issue has already been moved' do
|
|
|
|
include_context 'user can move issue'
|
|
|
|
|
|
|
|
let(:moved_to_issue) { create(:issue) }
|
|
|
|
|
|
|
|
let(:old_issue) do
|
|
|
|
create(:issue, project: old_project, author: author,
|
|
|
|
moved_to: moved_to_issue)
|
|
|
|
end
|
|
|
|
|
|
|
|
it { expect { move }.to raise_error(StandardError, /permissions/) }
|
|
|
|
end
|
|
|
|
|
|
|
|
context 'issue is not persisted' do
|
|
|
|
include_context 'user can move issue'
|
|
|
|
let(:old_issue) { build(:issue, project: old_project, author: author) }
|
2020-01-01 13:55:28 +05:30
|
|
|
|
2016-06-02 11:05:42 +05:30
|
|
|
it { expect { move }.to raise_error(StandardError, /permissions/) }
|
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
2020-07-28 23:09:34 +05:30
|
|
|
|
|
|
|
context 'updating sent notifications' do
|
|
|
|
let!(:old_issue_notification_1) { create(:sent_notification, project: old_issue.project, noteable: old_issue) }
|
|
|
|
let!(:old_issue_notification_2) { create(:sent_notification, project: old_issue.project, noteable: old_issue) }
|
|
|
|
let!(:other_issue_notification) { create(:sent_notification, project: old_issue.project) }
|
|
|
|
|
|
|
|
include_context 'user can move issue'
|
|
|
|
|
|
|
|
context 'when issue is from service desk' do
|
|
|
|
before do
|
|
|
|
allow(old_issue).to receive(:from_service_desk?).and_return(true)
|
|
|
|
end
|
|
|
|
|
|
|
|
it 'updates moved issue sent notifications' do
|
|
|
|
new_issue = move_service.execute(old_issue, new_project)
|
|
|
|
|
|
|
|
old_issue_notification_1.reload
|
|
|
|
old_issue_notification_2.reload
|
|
|
|
expect(old_issue_notification_1.project_id).to eq(new_issue.project_id)
|
|
|
|
expect(old_issue_notification_1.noteable_id).to eq(new_issue.id)
|
|
|
|
expect(old_issue_notification_2.project_id).to eq(new_issue.project_id)
|
|
|
|
expect(old_issue_notification_2.noteable_id).to eq(new_issue.id)
|
|
|
|
end
|
|
|
|
|
|
|
|
it 'does not update other issues sent notifications' do
|
|
|
|
expect do
|
|
|
|
move_service.execute(old_issue, new_project)
|
|
|
|
other_issue_notification.reload
|
|
|
|
end.not_to change { other_issue_notification.noteable_id }
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
context 'when issue is not from service desk' do
|
|
|
|
it 'does not update sent notifications' do
|
|
|
|
move_service.execute(old_issue, new_project)
|
|
|
|
|
|
|
|
old_issue_notification_1.reload
|
|
|
|
old_issue_notification_2.reload
|
|
|
|
expect(old_issue_notification_1.project_id).to eq(old_issue.project_id)
|
|
|
|
expect(old_issue_notification_1.noteable_id).to eq(old_issue.id)
|
|
|
|
expect(old_issue_notification_2.project_id).to eq(old_issue.project_id)
|
|
|
|
expect(old_issue_notification_2.noteable_id).to eq(old_issue.id)
|
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
2016-06-02 11:05:42 +05:30
|
|
|
end
|