debian-mirror-gitlab/spec/services/work_items/parent_links/create_service_spec.rb
2022-08-27 11:52:29 +05:30

195 lines
6.8 KiB
Ruby

# frozen_string_literal: true
require 'spec_helper'
RSpec.describe WorkItems::ParentLinks::CreateService do
describe '#execute' do
let_it_be(:user) { create(:user) }
let_it_be(:guest) { create(:user) }
let_it_be(:project) { create(:project) }
let_it_be(:work_item) { create(:work_item, project: project) }
let_it_be(:task) { create(:work_item, :task, project: project) }
let_it_be(:task1) { create(:work_item, :task, project: project) }
let_it_be(:task2) { create(:work_item, :task, project: project) }
let_it_be(:guest_task) { create(:work_item, :task) }
let_it_be(:invalid_task) { build_stubbed(:work_item, :task, id: non_existing_record_id) }
let_it_be(:another_project) { (create :project) }
let_it_be(:other_project_task) { create(:work_item, :task, iid: 100, project: another_project) }
let_it_be(:existing_parent_link) { create(:parent_link, work_item: task, work_item_parent: work_item) }
let(:parent_link_class) { WorkItems::ParentLink }
let(:issuable_type) { :task }
let(:params) { {} }
before do
project.add_reporter(user)
project.add_guest(guest)
guest_task.project.add_guest(user)
another_project.add_reporter(user)
end
shared_examples 'returns not found error' do
it 'returns error' do
error = "No matching #{issuable_type} found. Make sure that you are adding a valid #{issuable_type} ID."
is_expected.to eq(service_error(error))
end
it 'no relationship is created' do
expect { subject }.not_to change(parent_link_class, :count)
end
end
subject { described_class.new(work_item, user, params).execute }
context 'when the reference list is empty' do
let(:params) { { issuable_references: [] } }
it_behaves_like 'returns not found error'
end
context 'when work item not found' do
let(:params) { { issuable_references: [invalid_task] } }
it_behaves_like 'returns not found error'
end
context 'when user has no permission to link work items' do
let(:params) { { issuable_references: [guest_task] } }
it_behaves_like 'returns not found error'
end
context 'child and parent are the same work item' do
let(:params) { { issuable_references: [work_item] } }
it 'no relationship is created' do
expect { subject }.not_to change(parent_link_class, :count)
end
end
context 'when there are tasks to relate' do
let(:params) { { issuable_references: [task1, task2] } }
it 'creates relationships', :aggregate_failures do
expect { subject }.to change(parent_link_class, :count).by(2)
tasks_parent = parent_link_class.where(work_item: [task1, task2]).map(&:work_item_parent).uniq
expect(tasks_parent).to match_array([work_item])
end
it 'returns success status and created links', :aggregate_failures do
expect(subject.keys).to match_array([:status, :created_references])
expect(subject[:status]).to eq(:success)
expect(subject[:created_references].map(&:work_item_id)).to match_array([task1.id, task2.id])
end
it 'creates notes', :aggregate_failures do
subject
work_item_notes = work_item.notes.last(2)
expect(work_item_notes.first.note).to eq("added #{task1.to_reference} as child task")
expect(work_item_notes.last.note).to eq("added #{task2.to_reference} as child task")
expect(task1.notes.last.note).to eq("added #{work_item.to_reference} as parent issue")
expect(task2.notes.last.note).to eq("added #{work_item.to_reference} as parent issue")
end
context 'when task is already assigned' do
let(:params) { { issuable_references: [task, task2] } }
it 'creates links only for non related tasks', :aggregate_failures do
expect { subject }.to change(parent_link_class, :count).by(1)
expect(subject[:created_references].map(&:work_item_id)).to match_array([task2.id])
expect(work_item.notes.last.note).to eq("added #{task2.to_reference} as child task")
expect(task2.notes.last.note).to eq("added #{work_item.to_reference} as parent issue")
expect(task.notes).to be_empty
end
end
context 'when there are invalid children' do
let_it_be(:issue) { create(:work_item, project: project) }
let(:params) { { issuable_references: [task1, issue, other_project_task] } }
it 'creates links only for valid children' do
expect { subject }.to change { parent_link_class.count }.by(1)
end
it 'returns error status' do
error = "#{issue.to_reference} cannot be added: only Task can be assigned as a child in hierarchy.. " \
"#{other_project_task.to_reference} cannot be added: parent must be in the same project as child."
is_expected.to eq(service_error(error, http_status: 422))
end
it 'creates notes for valid links' do
subject
expect(work_item.notes.last.note).to eq("added #{task1.to_reference} as child task")
expect(task1.notes.last.note).to eq("added #{work_item.to_reference} as parent issue")
expect(issue.notes).to be_empty
expect(other_project_task.notes).to be_empty
end
end
context 'when parent type is invalid' do
let(:work_item) { create :work_item, :task, project: project }
let(:params) { { target_issuable: task1 } }
it 'returns error status' do
error = "#{task1.to_reference} cannot be added: only Issue and Incident can be parent of Task."
is_expected.to eq(service_error(error, http_status: 422))
end
end
context 'when max depth is reached' do
let(:params) { { issuable_references: [task2] } }
before do
stub_const("#{parent_link_class}::MAX_CHILDREN", 1)
end
it 'returns error status' do
error = "#{task2.to_reference} cannot be added: parent already has maximum number of children."
is_expected.to eq(service_error(error, http_status: 422))
end
end
context 'when params include invalid ids' do
let(:params) { { issuable_references: [task1, invalid_task] } }
it 'creates links only for valid IDs' do
expect { subject }.to change(parent_link_class, :count).by(1)
end
end
context 'when user is a guest' do
let(:user) { guest }
it_behaves_like 'returns not found error'
end
context 'when user is a guest assigned to the work item' do
let(:user) { guest }
before do
work_item.assignees = [guest]
end
it_behaves_like 'returns not found error'
end
end
end
def service_error(message, http_status: 404)
{
message: message,
status: :error,
http_status: http_status
}
end
end