OpenProject is the leading open source project management software.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
openproject/spec/models/relation/hierarchy_paths_spec.rb

252 lines
7.5 KiB

#-- encoding: UTF-8
#-- copyright
# OpenProject is a project management system.
# Copyright (C) 2012-2018 the OpenProject Foundation (OPF)
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License version 3.
#
# OpenProject is a fork of ChiliProject, which is a fork of Redmine. The copyright follows:
# Copyright (C) 2006-2017 Jean-Philippe Lang
# Copyright (C) 2010-2013 the ChiliProject Team
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
#
# See docs/COPYRIGHT.rdoc for more details.
#++
require 'spec_helper'
describe Relation, 'hierarchy_paths', type: :model do
let(:parent) { FactoryGirl.create(:work_package) }
let(:child) { FactoryGirl.create(:work_package) }
let(:grand_parent) do
wp = FactoryGirl.create(:work_package)
parent.parent = wp
parent.save!
wp
end
let(:grand_child) { FactoryGirl.create(:work_package, parent: child) }
def record_for(id)
ActiveRecord::Base.connection.select_rows <<-SQL
SELECT work_package_id, path from hierarchy_paths WHERE work_package_id = #{id}
SQL
end
def path_for(id)
record_for(id)[0][1]
end
context 'on creation' do
context 'with a relation between two work packages' do
before do
Relation.create relation_type: 'hierarchy', from: parent, to: child
end
it 'adds a hierarchy path for the child' do
expect(record_for(child.id)).not_to be_empty
end
it 'has the parent_id in the path' do
expect(path_for(child.id)).to eql parent.id.to_s
end
it 'has no hierarchy path for the parent' do
expect(record_for(parent.id)).to be_empty
end
end
context 'with a non hierarchy relation between two work packages' do
before do
Relation.create relation_type: Relation::TYPE_BLOCKS, from: parent, to: child
end
it 'has no hierarchy path for the child' do
expect(record_for(child.id)).to be_empty
end
it 'has no hierarchy path for the parent' do
expect(record_for(parent.id)).to be_empty
end
end
context 'with a relation connecting two already existing hierarchies' do
before do
grand_parent
grand_child
Relation.create relation_type: 'hierarchy', from: parent, to: child
end
it 'adds a hierarchy path for the child' do
expect(record_for(child.id)).not_to be_empty
end
it 'has the grand parent and the parent in the path for the child' do
expect(path_for(child.id)).to eql "#{grand_parent.id},#{parent.id}"
end
it 'has grand parent, parent and child in the path for the grand_child' do
expect(path_for(grand_child.id)).to eql "#{grand_parent.id},#{parent.id},#{child.id}"
end
end
end
context 'on deletion' do
context 'with a simple parent-child relationship' do
before do
relation = Relation.create relation_type: 'hierarchy', from: parent, to: child
relation.destroy
end
it 'removes the hierarchy path for the child' do
expect(record_for(child.id)).to be_empty
end
end
context 'with a relation spanning several hops' do
before do
grand_parent
grand_child
relation = Relation.create relation_type: 'hierarchy', from: parent, to: child
relation.destroy
end
it 'removes the hierarchy path for the child' do
expect(record_for(child.id)).to be_empty
end
it 'has the grand parent in the path for the parent' do
expect(path_for(parent.id)).to eql grand_parent.id.to_s
end
it 'child in the path for the grand_child' do
expect(path_for(grand_child.id)).to eql child.id.to_s
end
end
context 'with a non hierarchy relation connecting hierarchies' do
before do
grand_parent
grand_child
relation = Relation.create relation_type: Relation::TYPE_RELATES, from: parent, to: child
relation.destroy
end
it 'removes the hierarchy path for the child' do
expect(record_for(child.id)).to be_empty
end
it 'has the grand parent in the path for the parent' do
expect(path_for(parent.id)).to eql grand_parent.id.to_s
end
it 'child in the path for the grand_child' do
expect(path_for(grand_child.id)).to eql child.id.to_s
end
end
end
context 'on update' do
let(:parent_child_relation) { Relation.create relation_type: 'hierarchy', from: parent, to: child }
let(:follows_relation) { Relation.create relation_type: 'follows', from: parent, to: child }
let(:other_wp) { FactoryGirl.create :work_package }
context 'on switching the type to non hierarchy' do
before do
parent_child_relation.relation_type = Relation::TYPE_FOLLOWS
parent_child_relation.save
end
it 'removes the hierarchy_path' do
expect(record_for(child.id)).to be_empty
end
end
context 'on switching from_id' do
before do
parent_child_relation.from_id = other_wp.id
parent_child_relation.save!
end
it 'updates the path' do
expect(path_for(child.id)).to eql other_wp.id.to_s
end
end
context 'on switching to_id' do
before do
grand_child
grand_parent
relation = Relation.create to_id: other_wp.id, from_id: parent.id, relation_type: Relation::TYPE_HIERARCHY
relation.to_id = child.id
relation.save!
end
it 'adds a path for the new child' do
expect(path_for(child.id)).to eql "#{grand_parent.id},#{parent.id}"
end
it 'removes the path for the former child' do
expect(record_for(other_wp.id)).to be_empty
end
it 'updates the path to the children of the new child' do
expect(path_for(grand_child.id)).to eql "#{grand_parent.id},#{parent.id},#{child.id}"
end
end
context 'on switching the type to hierarchy' do
before do
follows_relation.relation_type = Relation::TYPE_HIERARCHY
follows_relation.save
end
it 'adds the hierarchy_path' do
expect(record_for(child.id)).not_to be_empty
end
end
end
describe '#rebuild_hierarchy_paths!' do
let!(:parent_child_relation) { Relation.create relation_type: 'hierarchy', from: parent, to: child }
before do
ActiveRecord::Base.connection.select_rows <<-SQL
DELETE FROM hierarchy_paths
SQL
ActiveRecord::Base.connection.execute <<-SQL
INSERT INTO hierarchy_paths (work_package_id, path) VALUES (#{parent.id}, '123')
SQL
Relation.rebuild_hierarchy_paths!
end
it 'adds a hierarchy path for the child' do
expect(record_for(child.id)).not_to be_empty
end
it 'has the parent_id in the path' do
expect(path_for(child.id)).to eql parent.id.to_s
end
it 'has no hierarchy path for the parent' do
expect(record_for(parent.id)).to be_empty
end
end
end