mirror of
https://github.com/zammad/zammad
synced 2026-05-24 09:48:36 +00:00
193 lines
6.7 KiB
Ruby
193 lines
6.7 KiB
Ruby
# Copyright (C) 2012-2026 Zammad Foundation, https://zammad-foundation.org/
|
|
|
|
require 'rails_helper'
|
|
require 'models/application_model_examples'
|
|
require 'models/concerns/can_be_imported_examples'
|
|
require 'models/concerns/has_object_manager_attributes_examples'
|
|
require 'models/concerns/has_collection_update_examples'
|
|
require 'models/concerns/has_xss_sanitized_note_examples'
|
|
require 'models/concerns/has_image_sanitized_note_examples'
|
|
|
|
RSpec.describe Group, type: :model do
|
|
subject(:group) { create(:group) }
|
|
|
|
it_behaves_like 'ApplicationModel'
|
|
it_behaves_like 'CanBeImported'
|
|
it_behaves_like 'HasObjectManagerAttributes'
|
|
it_behaves_like 'HasCollectionUpdate', collection_factory: :group
|
|
it_behaves_like 'HasXssSanitizedNote', model_factory: :group
|
|
it_behaves_like 'HasImageSanitizedNote', model_factory: :group
|
|
it_behaves_like 'Association clears cache', association: :users
|
|
it_behaves_like 'Association clears cache', association: :roles
|
|
|
|
describe 'name compatibility layer' do
|
|
context 'when creating a new group' do
|
|
context 'with name attribute' do
|
|
let(:name) { Faker::Lorem.unique.word.capitalize }
|
|
|
|
it 'sets name_last attribute to name' do
|
|
expect(described_class.create(name: name)).to have_attributes(name_last: name)
|
|
end
|
|
|
|
context 'when using complete path' do
|
|
let(:group1) { create(:group) }
|
|
let(:group2) { create(:group, parent: group1) }
|
|
let(:name) { "#{group1.name_last}::#{group2.name_last}::#{Faker::Lorem.unique.word.capitalize}" }
|
|
|
|
it 'sets parent_id attribute to guessed parent' do
|
|
expect(described_class.create(name: name)).to have_attributes(parent_id: group2.id)
|
|
end
|
|
|
|
context 'when path is invalid' do
|
|
let(:name) { Array.new(3) { Faker::Lorem.unique.word.capitalize }.join('::') }
|
|
|
|
it 'raises validation error' do
|
|
expect { described_class.create(name: name) }.to raise_error(ActiveRecord::RecordInvalid, 'Validation failed: Name contains invalid path')
|
|
end
|
|
end
|
|
end
|
|
end
|
|
|
|
context 'with name_last attribute' do
|
|
let(:name_last) { Faker::Lorem.unique.word.capitalize }
|
|
|
|
it 'sets name_last attribute to name_last' do
|
|
expect(described_class.create(name_last: name_last)).to have_attributes(name_last: name_last)
|
|
end
|
|
end
|
|
|
|
context 'with both name and name_last attribute' do
|
|
let(:name) { Faker::Lorem.unique.word.capitalize }
|
|
let(:name_last) { Faker::Lorem.unique.word.capitalize }
|
|
|
|
it 'sets name_last attribute to name_last' do
|
|
expect(described_class.create(name: name, name_last: name_last)).to have_attributes(name_last: name_last)
|
|
end
|
|
end
|
|
end
|
|
|
|
context 'when updating an existing group' do
|
|
let(:group) { create(:group) }
|
|
|
|
context 'with name attribute' do
|
|
let(:name) { Faker::Lorem.unique.word.capitalize }
|
|
|
|
before do
|
|
group.update!(name: name) if !defined?(skip_before)
|
|
end
|
|
|
|
it 'sets name_last attribute to name' do
|
|
expect(group).to have_attributes(name_last: name)
|
|
end
|
|
|
|
context 'when using complete path' do
|
|
let(:group1) { create(:group) }
|
|
let(:group2) { create(:group, parent: group1) }
|
|
let(:name) { "#{group1.name_last}::#{group2.name_last}::#{Faker::Lorem.unique.word.capitalize}" }
|
|
|
|
it 'sets parent_id attribute to guessed parent' do
|
|
expect(group).to have_attributes(parent_id: group2.id)
|
|
end
|
|
|
|
context 'when path is invalid' do
|
|
let(:name) { Array.new(3) { Faker::Lorem.unique.word.capitalize }.join('::') }
|
|
let(:skip_before) { true }
|
|
|
|
it 'raises validation error' do
|
|
expect { group.update!(name: name) }.to raise_error(ActiveRecord::RecordInvalid, 'Validation failed: Name contains invalid path')
|
|
end
|
|
end
|
|
end
|
|
end
|
|
|
|
context 'with name_last attribute' do
|
|
let(:name_last) { Faker::Lorem.unique.word.capitalize }
|
|
|
|
before do
|
|
group.update!(name_last: name_last)
|
|
end
|
|
|
|
it 'sets name_last attribute to name_last' do
|
|
expect(described_class.create(name_last: name_last)).to have_attributes(name_last: name_last)
|
|
end
|
|
end
|
|
|
|
context 'with both name and name_last attribute' do
|
|
let(:name) { Faker::Lorem.unique.word.capitalize }
|
|
let(:name_last) { Faker::Lorem.unique.word.capitalize }
|
|
|
|
before do
|
|
group.update!(name: name, name_last: name_last)
|
|
end
|
|
|
|
it 'sets name_last attribute to name_last' do
|
|
expect(described_class.create(name_last: name_last)).to have_attributes(name_last: name_last)
|
|
end
|
|
end
|
|
end
|
|
end
|
|
|
|
describe 'tree related functions' do
|
|
let!(:group_1) { create(:group) }
|
|
let!(:group_2) { create(:group, parent: group_1) }
|
|
let!(:group_31) { create(:group, parent: group_2) }
|
|
let!(:group_32) { create(:group, parent: group_2) }
|
|
let!(:group_4) { create(:group, parent: group_31) }
|
|
|
|
describe '#all_children' do
|
|
it 'does return all children' do
|
|
expect(group_1.all_children.sort).to eq([group_2, group_31, group_32, group_4].sort)
|
|
end
|
|
end
|
|
|
|
describe '#all_parents' do
|
|
it 'does return all parents ids' do
|
|
expect(group_4.all_parents).to eq([group_31, group_2, group_1])
|
|
end
|
|
end
|
|
|
|
describe '#depth' do
|
|
it 'does return group depth' do
|
|
expect(group_4.depth).to eq(3)
|
|
end
|
|
end
|
|
|
|
describe '#check_max_depth (psql)' do
|
|
def groups_with_depth(depth)
|
|
groups = []
|
|
|
|
groups << create(:group)
|
|
groups += create_list(:group, depth - 1)
|
|
|
|
groups.each_with_index do |group, idx|
|
|
next if idx.zero?
|
|
|
|
group.update!(parent: groups[idx - 1])
|
|
end
|
|
|
|
groups
|
|
end
|
|
|
|
let(:groups_1) { groups_with_depth(10) }
|
|
let(:groups_2) { groups_with_depth(4) }
|
|
|
|
let(:group_1_11) { create(:group, parent: groups_1.last) }
|
|
let(:group_2_5) { create(:group, parent: groups_2.last) }
|
|
|
|
it 'does check depth on creation', :aggregate_failures do
|
|
expect { groups_1 }.not_to raise_error
|
|
expect { group_1_11 }.to raise_error(Exceptions::UnprocessableContent, 'This group or its children exceed the allowed nesting depth.')
|
|
expect { group_2_5 }.not_to raise_error
|
|
end
|
|
|
|
it 'does check depth on tree merge', :aggregate_failures do
|
|
expect do
|
|
groups_1.last
|
|
groups_2.last
|
|
end.not_to raise_error
|
|
|
|
expect { groups_2.last.update!(parent: groups_1.last) }.to raise_error(Exceptions::UnprocessableContent, 'This group or its children exceed the allowed nesting depth.')
|
|
end
|
|
end
|
|
end
|
|
end
|