group_spec.rb 8.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227
  1. # Copyright (C) 2012-2024 Zammad Foundation, https://zammad-foundation.org/
  2. require 'rails_helper'
  3. require 'models/application_model_examples'
  4. require 'models/concerns/can_be_imported_examples'
  5. require 'models/concerns/has_object_manager_attributes_examples'
  6. require 'models/concerns/has_collection_update_examples'
  7. require 'models/concerns/has_xss_sanitized_note_examples'
  8. require 'models/concerns/has_image_sanitized_note_examples'
  9. RSpec.describe Group, type: :model do
  10. subject(:group) { create(:group) }
  11. it_behaves_like 'ApplicationModel'
  12. it_behaves_like 'CanBeImported'
  13. it_behaves_like 'HasObjectManagerAttributes'
  14. it_behaves_like 'HasCollectionUpdate', collection_factory: :group
  15. it_behaves_like 'HasXssSanitizedNote', model_factory: :group
  16. it_behaves_like 'HasImageSanitizedNote', model_factory: :group
  17. it_behaves_like 'Association clears cache', association: :users
  18. it_behaves_like 'Association clears cache', association: :roles
  19. describe 'name compatibility layer' do
  20. context 'when creating a new group' do
  21. context 'with name attribute' do
  22. let(:name) { Faker::Lorem.unique.word.capitalize }
  23. it 'sets name_last attribute to name' do
  24. expect(described_class.create(name: name)).to have_attributes(name_last: name)
  25. end
  26. context 'when using complete path' do
  27. let(:group1) { create(:group) }
  28. let(:group2) { create(:group, parent: group1) }
  29. let(:name) { "#{group1.name_last}::#{group2.name_last}::#{Faker::Lorem.unique.word.capitalize}" }
  30. it 'sets parent_id attribute to guessed parent' do
  31. expect(described_class.create(name: name)).to have_attributes(parent_id: group2.id)
  32. end
  33. context 'when path is invalid' do
  34. let(:name) { Array.new(3) { Faker::Lorem.unique.word.capitalize }.join('::') }
  35. it 'raises validation error' do
  36. expect { described_class.create(name: name) }.to raise_error(ActiveRecord::RecordInvalid, 'Validation failed: Name contains invalid path')
  37. end
  38. end
  39. end
  40. end
  41. context 'with name_last attribute' do
  42. let(:name_last) { Faker::Lorem.unique.word.capitalize }
  43. it 'sets name_last attribute to name_last' do
  44. expect(described_class.create(name_last: name_last)).to have_attributes(name_last: name_last)
  45. end
  46. end
  47. context 'with both name and name_last attribute' do
  48. let(:name) { Faker::Lorem.unique.word.capitalize }
  49. let(:name_last) { Faker::Lorem.unique.word.capitalize }
  50. it 'sets name_last attribute to name_last' do
  51. expect(described_class.create(name: name, name_last: name_last)).to have_attributes(name_last: name_last)
  52. end
  53. end
  54. end
  55. context 'when updating an existing group' do
  56. let(:group) { create(:group) }
  57. context 'with name attribute' do
  58. let(:name) { Faker::Lorem.unique.word.capitalize }
  59. before do
  60. group.update!(name: name) if !defined?(skip_before)
  61. end
  62. it 'sets name_last attribute to name' do
  63. expect(group).to have_attributes(name_last: name)
  64. end
  65. context 'when using complete path' do
  66. let(:group1) { create(:group) }
  67. let(:group2) { create(:group, parent: group1) }
  68. let(:name) { "#{group1.name_last}::#{group2.name_last}::#{Faker::Lorem.unique.word.capitalize}" }
  69. it 'sets parent_id attribute to guessed parent' do
  70. expect(group).to have_attributes(parent_id: group2.id)
  71. end
  72. context 'when path is invalid' do
  73. let(:name) { Array.new(3) { Faker::Lorem.unique.word.capitalize }.join('::') }
  74. let(:skip_before) { true }
  75. it 'raises validation error' do
  76. expect { group.update!(name: name) }.to raise_error(ActiveRecord::RecordInvalid, 'Validation failed: Name contains invalid path')
  77. end
  78. end
  79. end
  80. end
  81. context 'with name_last attribute' do
  82. let(:name_last) { Faker::Lorem.unique.word.capitalize }
  83. before do
  84. group.update!(name_last: name_last)
  85. end
  86. it 'sets name_last attribute to name_last' do
  87. expect(described_class.create(name_last: name_last)).to have_attributes(name_last: name_last)
  88. end
  89. end
  90. context 'with both name and name_last attribute' do
  91. let(:name) { Faker::Lorem.unique.word.capitalize }
  92. let(:name_last) { Faker::Lorem.unique.word.capitalize }
  93. before do
  94. group.update!(name: name, name_last: name_last)
  95. end
  96. it 'sets name_last attribute to name_last' do
  97. expect(described_class.create(name_last: name_last)).to have_attributes(name_last: name_last)
  98. end
  99. end
  100. end
  101. end
  102. describe 'tree related functions' do
  103. let!(:group_1) { create(:group) }
  104. let!(:group_2) { create(:group, parent: group_1) }
  105. let!(:group_31) { create(:group, parent: group_2) }
  106. let!(:group_32) { create(:group, parent: group_2) }
  107. let!(:group_4) { create(:group, parent: group_31) }
  108. describe '#all_children' do
  109. it 'does return all children' do
  110. expect(group_1.all_children.sort).to eq([group_2, group_31, group_32, group_4].sort)
  111. end
  112. end
  113. describe '#all_parents' do
  114. it 'does return all parents ids' do
  115. expect(group_4.all_parents).to eq([group_31, group_2, group_1])
  116. end
  117. end
  118. describe '#depth' do
  119. it 'does return group depth' do
  120. expect(group_4.depth).to eq(3)
  121. end
  122. end
  123. describe '#check_max_depth (mysql)', db_adapter: :mysql do
  124. let(:group_1_1) { create(:group, name: 'tree_group_1_1') }
  125. let(:group_1_2) { create(:group, name: 'tree_group_1_2', parent: group_1_1) }
  126. let(:group_1_3) { create(:group, name: 'tree_group_1_3', parent: group_1_2) }
  127. let(:group_1_4) { create(:group, name: 'tree_group_1_4', parent: group_1_3) }
  128. let(:group_1_5) { create(:group, name: 'tree_group_1_5', parent: group_1_4) }
  129. let(:group_1_6) { create(:group, name: 'tree_group_1_6', parent: group_1_5) }
  130. let(:group_1_7) { create(:group, name: 'tree_group_1_7', parent: group_1_6) }
  131. let(:group_2_1) { create(:group, name: 'tree_group_2_1') }
  132. let(:group_2_2) { create(:group, name: 'tree_group_2_2', parent: group_2_1) }
  133. let(:group_2_3) { create(:group, name: 'tree_group_2_3', parent: group_2_2) }
  134. let(:group_2_4) { create(:group, name: 'tree_group_2_4', parent: group_2_3) }
  135. it 'does check depth on creation', :aggregate_failures do
  136. expect do
  137. group_1_1
  138. group_1_2
  139. group_1_3
  140. group_1_4
  141. group_1_5
  142. group_1_6
  143. end.not_to raise_error
  144. expect { group_1_7 }.to raise_error(Exceptions::UnprocessableEntity, 'This group or its children exceed the allowed nesting depth.')
  145. end
  146. it 'does check depth on tree merge', :aggregate_failures do
  147. expect do
  148. group_1_6
  149. group_2_4
  150. end.not_to raise_error
  151. expect { group_2_1.update(parent: group_1_6) }.to raise_error(Exceptions::UnprocessableEntity, 'This group or its children exceed the allowed nesting depth.')
  152. end
  153. end
  154. describe '#check_max_depth (psql)', db_adapter: :postgresql do
  155. def groups_with_depth(depth)
  156. groups = []
  157. groups << create(:group)
  158. groups += create_list(:group, depth - 1)
  159. groups.each_with_index do |group, idx|
  160. next if idx.zero?
  161. group.update!(parent: groups[idx - 1])
  162. end
  163. groups
  164. end
  165. let(:groups_1) { groups_with_depth(10) }
  166. let(:groups_2) { groups_with_depth(4) }
  167. let(:group_1_11) { create(:group, parent: groups_1.last) }
  168. let(:group_2_5) { create(:group, parent: groups_2.last) }
  169. it 'does check depth on creation', :aggregate_failures do
  170. expect { groups_1 }.not_to raise_error
  171. expect { group_1_11 }.to raise_error(Exceptions::UnprocessableEntity, 'This group or its children exceed the allowed nesting depth.')
  172. expect { group_2_5 }.not_to raise_error
  173. end
  174. it 'does check depth on tree merge', :aggregate_failures do
  175. expect do
  176. groups_1.last
  177. groups_2.last
  178. end.not_to raise_error
  179. expect { groups_2.last.update!(parent: groups_1.last) }.to raise_error(Exceptions::UnprocessableEntity, 'This group or its children exceed the allowed nesting depth.')
  180. end
  181. end
  182. end
  183. end