From 438a0773dc850d3fa690881ea0b022bc27435e1e Mon Sep 17 00:00:00 2001 From: Bob Van Landuyt Date: Wed, 6 Sep 2017 16:29:52 +0200 Subject: Add a concern to build hierarchies of groups --- spec/models/concerns/group_hierarchy_spec.rb | 61 ++++++++++++++++++++++++++++ 1 file changed, 61 insertions(+) create mode 100644 spec/models/concerns/group_hierarchy_spec.rb (limited to 'spec/models') diff --git a/spec/models/concerns/group_hierarchy_spec.rb b/spec/models/concerns/group_hierarchy_spec.rb new file mode 100644 index 00000000000..14ac910c90d --- /dev/null +++ b/spec/models/concerns/group_hierarchy_spec.rb @@ -0,0 +1,61 @@ +require 'spec_helper' + +describe GroupHierarchy, :nested_groups do + let(:parent) { create(:group) } + let(:subgroup) { create(:group, parent: parent) } + let(:subsub_group) { create(:group, parent: subgroup) } + + context 'for a group' do + describe '#hierarchy' do + it 'builds a hierarchy for a group' do + expected_hierarchy = { parent => { subgroup => subsub_group } } + + expect(subsub_group.hierarchy).to eq(expected_hierarchy) + end + + it 'builds a hierarchy upto a specified parent' do + expected_hierarchy = { subgroup => subsub_group } + + expect(subsub_group.hierarchy(parent)).to eq(expected_hierarchy) + end + + it 'raises an error if specifying a base that is not part of the tree' do + expect { subsub_group.hierarchy(double) }.to raise_error('specified base is not part of the tree') + end + end + + describe '#parent' do + it 'returns the correct parent' do + expect(subsub_group.parent).to eq(subgroup) + end + end + end + + context 'for a project' do + let(:project) { create(:project, namespace: subsub_group) } + + describe '#hierarchy' do + it 'builds a hierarchy for a group' do + expected_hierarchy = { parent => { subgroup => { subsub_group => project } } } + + expect(project.hierarchy).to eq(expected_hierarchy) + end + + it 'builds a hierarchy upto a specified parent' do + expected_hierarchy = { subsub_group => project } + + expect(project.hierarchy(subgroup)).to eq(expected_hierarchy) + end + + it 'raises an error if specifying a base that is not part of the tree' do + expect { project.hierarchy(double) }.to raise_error('specified base is not part of the tree') + end + end + + describe '#parent' do + it 'returns the correct parent' do + expect(project.parent).to eq(subsub_group) + end + end + end +end -- cgit v1.2.1 From 518216c0627cb6c4b3db62f10877b44d0e912ddb Mon Sep 17 00:00:00 2001 From: Bob Van Landuyt Date: Thu, 7 Sep 2017 19:08:56 +0200 Subject: Merge group hierarchies when parents are shared --- spec/models/concerns/group_hierarchy_spec.rb | 68 ++++++++++++++++++++++++++++ 1 file changed, 68 insertions(+) (limited to 'spec/models') diff --git a/spec/models/concerns/group_hierarchy_spec.rb b/spec/models/concerns/group_hierarchy_spec.rb index 14ac910c90d..1f4fab88781 100644 --- a/spec/models/concerns/group_hierarchy_spec.rb +++ b/spec/models/concerns/group_hierarchy_spec.rb @@ -29,6 +29,40 @@ describe GroupHierarchy, :nested_groups do expect(subsub_group.parent).to eq(subgroup) end end + + describe '#merge_hierarchy' do + it 'combines hierarchies' do + other_subgroup = create(:group, parent: parent) + + expected_hierarchy = { parent => [{ subgroup => subsub_group }, other_subgroup] } + + expect(subsub_group.merge_hierarchy(other_subgroup)).to eq(expected_hierarchy) + end + end + + describe '.merge_hierarchies' do + it 'combines hierarchies until the top' do + other_subgroup = create(:group, parent: parent) + other_subsub_group = create(:group, parent: subgroup) + + groups = [other_subgroup, subsub_group, other_subsub_group] + + expected_hierarchy = { parent => [other_subgroup, { subgroup => [subsub_group, other_subsub_group] }] } + + expect(described_class.merge_hierarchies(groups)).to eq(expected_hierarchy) + end + + it 'combines upto a given parent' do + other_subgroup = create(:group, parent: parent) + other_subsub_group = create(:group, parent: subgroup) + + groups = [other_subgroup, subsub_group, other_subsub_group] + + expected_hierarchy = [other_subgroup, { subgroup => [subsub_group, other_subsub_group] }] + + expect(described_class.merge_hierarchies(groups, parent)).to eq(expected_hierarchy) + end + end end context 'for a project' do @@ -57,5 +91,39 @@ describe GroupHierarchy, :nested_groups do expect(project.parent).to eq(subsub_group) end end + + describe '#merge_hierarchy' do + it 'combines hierarchies' do + project = create(:project, namespace: parent) + + expected_hierarchy = { parent => [{ subgroup => subsub_group }, project] } + + expect(subsub_group.merge_hierarchy(project)).to eq(expected_hierarchy) + end + end + + describe '.merge_hierarchies' do + it 'combines hierarchies until the top' do + other_project = create(:project, namespace: parent) + other_subgroup_project = create(:project, namespace: subgroup) + + elements = [other_project, subsub_group, other_subgroup_project] + + expected_hierarchy = { parent => [other_project, { subgroup => [subsub_group, other_subgroup_project] }] } + + expect(described_class.merge_hierarchies(elements)).to eq(expected_hierarchy) + end + + it 'combines upto a given parent' do + other_project = create(:project, namespace: parent) + other_subgroup_project = create(:project, namespace: subgroup) + + elements = [other_project, subsub_group, other_subgroup_project] + + expected_hierarchy = [other_project, { subgroup => [subsub_group, other_subgroup_project] }] + + expect(described_class.merge_hierarchies(elements, parent)).to eq(expected_hierarchy) + end + end end end -- cgit v1.2.1 From bb5187bb2a71f87b3ff49388f70dbcb27dfe4c6a Mon Sep 17 00:00:00 2001 From: Bob Van Landuyt Date: Sun, 10 Sep 2017 17:20:27 +0200 Subject: Handle case where 2 matches in the same tree are found --- spec/models/concerns/group_hierarchy_spec.rb | 6 ++++++ 1 file changed, 6 insertions(+) (limited to 'spec/models') diff --git a/spec/models/concerns/group_hierarchy_spec.rb b/spec/models/concerns/group_hierarchy_spec.rb index 1f4fab88781..bb02983c776 100644 --- a/spec/models/concerns/group_hierarchy_spec.rb +++ b/spec/models/concerns/group_hierarchy_spec.rb @@ -124,6 +124,12 @@ describe GroupHierarchy, :nested_groups do expect(described_class.merge_hierarchies(elements, parent)).to eq(expected_hierarchy) end + + it 'merges to elements in the same hierarchy' do + expected_hierarchy = { parent => subgroup } + + expect(described_class.merge_hierarchies([parent, subgroup])).to eq(expected_hierarchy) + end end end end -- cgit v1.2.1 From 3299a970e09ceca7ecabb3d78a5693f58ef79d79 Mon Sep 17 00:00:00 2001 From: Bob Van Landuyt Date: Tue, 12 Sep 2017 19:03:12 +0200 Subject: Handle all cases for merging a hierarchy The possible cases are: - [Array, Array] - [Array, Hash] - [Array, GroupHierarchy] - [Hash,Hash] - [Hash, GroupHierarchy] - [GroupHierarchy, GroupHierarchy] --- spec/models/concerns/group_hierarchy_spec.rb | 11 +++++++++++ 1 file changed, 11 insertions(+) (limited to 'spec/models') diff --git a/spec/models/concerns/group_hierarchy_spec.rb b/spec/models/concerns/group_hierarchy_spec.rb index bb02983c776..fe30895f15e 100644 --- a/spec/models/concerns/group_hierarchy_spec.rb +++ b/spec/models/concerns/group_hierarchy_spec.rb @@ -62,6 +62,17 @@ describe GroupHierarchy, :nested_groups do expect(described_class.merge_hierarchies(groups, parent)).to eq(expected_hierarchy) end + + it 'handles building a tree out of order' do + other_subgroup = create(:group, parent: parent) + other_subgroup2 = create(:group, parent: parent) + other_subsub_group = create(:group, parent: other_subgroup) + + groups = [subsub_group, other_subgroup2, other_subsub_group] + expected_hierarchy = { parent => [{ subgroup => subsub_group }, other_subgroup2, { other_subgroup => other_subsub_group }] } + + expect(described_class.merge_hierarchies(groups)).to eq(expected_hierarchy) + end end end -- cgit v1.2.1 From 22aa034427b9392b44d9ecba0a51bb1b6c6616d7 Mon Sep 17 00:00:00 2001 From: Bob Van Landuyt Date: Tue, 19 Sep 2017 13:11:09 +0200 Subject: Rename `GroupHierarchy` to `GroupDescendant` --- spec/models/concerns/group_descendant_spec.rb | 173 ++++++++++++++++++++++++++ spec/models/concerns/group_hierarchy_spec.rb | 146 ---------------------- 2 files changed, 173 insertions(+), 146 deletions(-) create mode 100644 spec/models/concerns/group_descendant_spec.rb delete mode 100644 spec/models/concerns/group_hierarchy_spec.rb (limited to 'spec/models') diff --git a/spec/models/concerns/group_descendant_spec.rb b/spec/models/concerns/group_descendant_spec.rb new file mode 100644 index 00000000000..87eee515cde --- /dev/null +++ b/spec/models/concerns/group_descendant_spec.rb @@ -0,0 +1,173 @@ +require 'spec_helper' + +describe GroupDescendant, :nested_groups do + let(:parent) { create(:group) } + let(:subgroup) { create(:group, parent: parent) } + let(:subsub_group) { create(:group, parent: subgroup) } + + context 'for a group' do + describe '#hierarchy' do + it 'builds a hierarchy for a group' do + expected_hierarchy = { parent => { subgroup => subsub_group } } + + expect(subsub_group.hierarchy).to eq(expected_hierarchy) + end + + it 'builds a hierarchy upto a specified parent' do + expected_hierarchy = { subgroup => subsub_group } + + expect(subsub_group.hierarchy(parent)).to eq(expected_hierarchy) + end + + it 'raises an error if specifying a base that is not part of the tree' do + expect { subsub_group.hierarchy(double) }.to raise_error('specified base is not part of the tree') + end + end + + describe '#parent' do + it 'returns the correct parent' do + expect(subsub_group.parent).to eq(subgroup) + end + end + + describe '#merge_hierarchy' do + it 'combines hierarchies' do + other_subgroup = create(:group, parent: parent) + + expected_hierarchy = { parent => [{ subgroup => subsub_group }, other_subgroup] } + + expect(subsub_group.merge_hierarchy(other_subgroup)).to eq(expected_hierarchy) + end + end + + describe '.merge_hierarchies' do + it 'combines hierarchies until the top' do + other_subgroup = create(:group, parent: parent) + other_subsub_group = create(:group, parent: subgroup) + + groups = [other_subgroup, subsub_group, other_subsub_group] + + expected_hierarchy = { parent => [other_subgroup, { subgroup => [subsub_group, other_subsub_group] }] } + + expect(described_class.merge_hierarchies(groups)).to eq(expected_hierarchy) + end + + it 'combines upto a given parent' do + other_subgroup = create(:group, parent: parent) + other_subsub_group = create(:group, parent: subgroup) + + groups = [other_subgroup, subsub_group, other_subsub_group] + + expected_hierarchy = [other_subgroup, { subgroup => [subsub_group, other_subsub_group] }] + + expect(described_class.merge_hierarchies(groups, parent)).to eq(expected_hierarchy) + end + + it 'handles building a tree out of order' do + other_subgroup = create(:group, parent: parent) + other_subgroup2 = create(:group, parent: parent) + other_subsub_group = create(:group, parent: other_subgroup) + + groups = [subsub_group, other_subgroup2, other_subsub_group] + expected_hierarchy = { parent => [{ subgroup => subsub_group }, other_subgroup2, { other_subgroup => other_subsub_group }] } + + expect(described_class.merge_hierarchies(groups)).to eq(expected_hierarchy) + end + end + end + + context 'for a project' do + let(:project) { create(:project, namespace: subsub_group) } + + describe '#hierarchy' do + it 'builds a hierarchy for a group' do + expected_hierarchy = { parent => { subgroup => { subsub_group => project } } } + + expect(project.hierarchy).to eq(expected_hierarchy) + end + + it 'builds a hierarchy upto a specified parent' do + expected_hierarchy = { subsub_group => project } + + expect(project.hierarchy(subgroup)).to eq(expected_hierarchy) + end + + it 'raises an error if specifying a base that is not part of the tree' do + expect { project.hierarchy(double) }.to raise_error('specified base is not part of the tree') + end + end + + describe '#parent' do + it 'returns the correct parent' do + expect(project.parent).to eq(subsub_group) + end + end + + describe '#merge_hierarchy' do + it 'combines hierarchies' do + project = create(:project, namespace: parent) + + expected_hierarchy = { parent => [{ subgroup => subsub_group }, project] } + + expect(subsub_group.merge_hierarchy(project)).to eq(expected_hierarchy) + end + end + + describe '.merge_hierarchies' do + it 'combines hierarchies until the top' do + other_project = create(:project, namespace: parent) + other_subgroup_project = create(:project, namespace: subgroup) + + elements = [other_project, subsub_group, other_subgroup_project] + + expected_hierarchy = { parent => [other_project, { subgroup => [subsub_group, other_subgroup_project] }] } + + expect(described_class.merge_hierarchies(elements)).to eq(expected_hierarchy) + end + + it 'combines upto a given parent' do + other_project = create(:project, namespace: parent) + other_subgroup_project = create(:project, namespace: subgroup) + + elements = [other_project, subsub_group, other_subgroup_project] + + expected_hierarchy = [other_project, { subgroup => [subsub_group, other_subgroup_project] }] + + expect(described_class.merge_hierarchies(elements, parent)).to eq(expected_hierarchy) + end + + it 'merges to elements in the same hierarchy' do + expected_hierarchy = { parent => subgroup } + + expect(described_class.merge_hierarchies([parent, subgroup])).to eq(expected_hierarchy) + end + + it 'merges complex hierarchies' do + project = create(:project, namespace: parent) + sub_project = create(:project, namespace: subgroup) + subsubsub_group = create(:group, parent: subsub_group) + subsub_project = create(:project, namespace: subsub_group) + subsubsub_project = create(:project, namespace: subsubsub_group) + other_subgroup = create(:group, parent: parent) + other_subproject = create(:project, namespace: other_subgroup) + + projects = [project, subsubsub_project, sub_project, other_subproject, subsub_project] + + expected_hierarchy = [ + project, + { + subgroup => [ + { subsub_group => [{ subsubsub_group => subsubsub_project }, subsub_project] }, + sub_project + ] + }, + { other_subgroup => other_subproject } + ] + + actual_hierarchy = described_class.merge_hierarchies(projects, parent) + + expect(actual_hierarchy).to eq(expected_hierarchy) + end + end + end +end diff --git a/spec/models/concerns/group_hierarchy_spec.rb b/spec/models/concerns/group_hierarchy_spec.rb deleted file mode 100644 index fe30895f15e..00000000000 --- a/spec/models/concerns/group_hierarchy_spec.rb +++ /dev/null @@ -1,146 +0,0 @@ -require 'spec_helper' - -describe GroupHierarchy, :nested_groups do - let(:parent) { create(:group) } - let(:subgroup) { create(:group, parent: parent) } - let(:subsub_group) { create(:group, parent: subgroup) } - - context 'for a group' do - describe '#hierarchy' do - it 'builds a hierarchy for a group' do - expected_hierarchy = { parent => { subgroup => subsub_group } } - - expect(subsub_group.hierarchy).to eq(expected_hierarchy) - end - - it 'builds a hierarchy upto a specified parent' do - expected_hierarchy = { subgroup => subsub_group } - - expect(subsub_group.hierarchy(parent)).to eq(expected_hierarchy) - end - - it 'raises an error if specifying a base that is not part of the tree' do - expect { subsub_group.hierarchy(double) }.to raise_error('specified base is not part of the tree') - end - end - - describe '#parent' do - it 'returns the correct parent' do - expect(subsub_group.parent).to eq(subgroup) - end - end - - describe '#merge_hierarchy' do - it 'combines hierarchies' do - other_subgroup = create(:group, parent: parent) - - expected_hierarchy = { parent => [{ subgroup => subsub_group }, other_subgroup] } - - expect(subsub_group.merge_hierarchy(other_subgroup)).to eq(expected_hierarchy) - end - end - - describe '.merge_hierarchies' do - it 'combines hierarchies until the top' do - other_subgroup = create(:group, parent: parent) - other_subsub_group = create(:group, parent: subgroup) - - groups = [other_subgroup, subsub_group, other_subsub_group] - - expected_hierarchy = { parent => [other_subgroup, { subgroup => [subsub_group, other_subsub_group] }] } - - expect(described_class.merge_hierarchies(groups)).to eq(expected_hierarchy) - end - - it 'combines upto a given parent' do - other_subgroup = create(:group, parent: parent) - other_subsub_group = create(:group, parent: subgroup) - - groups = [other_subgroup, subsub_group, other_subsub_group] - - expected_hierarchy = [other_subgroup, { subgroup => [subsub_group, other_subsub_group] }] - - expect(described_class.merge_hierarchies(groups, parent)).to eq(expected_hierarchy) - end - - it 'handles building a tree out of order' do - other_subgroup = create(:group, parent: parent) - other_subgroup2 = create(:group, parent: parent) - other_subsub_group = create(:group, parent: other_subgroup) - - groups = [subsub_group, other_subgroup2, other_subsub_group] - expected_hierarchy = { parent => [{ subgroup => subsub_group }, other_subgroup2, { other_subgroup => other_subsub_group }] } - - expect(described_class.merge_hierarchies(groups)).to eq(expected_hierarchy) - end - end - end - - context 'for a project' do - let(:project) { create(:project, namespace: subsub_group) } - - describe '#hierarchy' do - it 'builds a hierarchy for a group' do - expected_hierarchy = { parent => { subgroup => { subsub_group => project } } } - - expect(project.hierarchy).to eq(expected_hierarchy) - end - - it 'builds a hierarchy upto a specified parent' do - expected_hierarchy = { subsub_group => project } - - expect(project.hierarchy(subgroup)).to eq(expected_hierarchy) - end - - it 'raises an error if specifying a base that is not part of the tree' do - expect { project.hierarchy(double) }.to raise_error('specified base is not part of the tree') - end - end - - describe '#parent' do - it 'returns the correct parent' do - expect(project.parent).to eq(subsub_group) - end - end - - describe '#merge_hierarchy' do - it 'combines hierarchies' do - project = create(:project, namespace: parent) - - expected_hierarchy = { parent => [{ subgroup => subsub_group }, project] } - - expect(subsub_group.merge_hierarchy(project)).to eq(expected_hierarchy) - end - end - - describe '.merge_hierarchies' do - it 'combines hierarchies until the top' do - other_project = create(:project, namespace: parent) - other_subgroup_project = create(:project, namespace: subgroup) - - elements = [other_project, subsub_group, other_subgroup_project] - - expected_hierarchy = { parent => [other_project, { subgroup => [subsub_group, other_subgroup_project] }] } - - expect(described_class.merge_hierarchies(elements)).to eq(expected_hierarchy) - end - - it 'combines upto a given parent' do - other_project = create(:project, namespace: parent) - other_subgroup_project = create(:project, namespace: subgroup) - - elements = [other_project, subsub_group, other_subgroup_project] - - expected_hierarchy = [other_project, { subgroup => [subsub_group, other_subgroup_project] }] - - expect(described_class.merge_hierarchies(elements, parent)).to eq(expected_hierarchy) - end - - it 'merges to elements in the same hierarchy' do - expected_hierarchy = { parent => subgroup } - - expect(described_class.merge_hierarchies([parent, subgroup])).to eq(expected_hierarchy) - end - end - end -end -- cgit v1.2.1 From cd85c22faa7092edabf252fa157125ea571ed054 Mon Sep 17 00:00:00 2001 From: Bob Van Landuyt Date: Fri, 22 Sep 2017 17:36:39 +0200 Subject: Rename hierarchies to descendants where applicable --- spec/models/concerns/group_descendant_spec.rb | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) (limited to 'spec/models') diff --git a/spec/models/concerns/group_descendant_spec.rb b/spec/models/concerns/group_descendant_spec.rb index 87eee515cde..b1578fc593e 100644 --- a/spec/models/concerns/group_descendant_spec.rb +++ b/spec/models/concerns/group_descendant_spec.rb @@ -40,7 +40,7 @@ describe GroupDescendant, :nested_groups do end end - describe '.merge_hierarchies' do + describe '.build_hierarchy' do it 'combines hierarchies until the top' do other_subgroup = create(:group, parent: parent) other_subsub_group = create(:group, parent: subgroup) @@ -49,7 +49,7 @@ describe GroupDescendant, :nested_groups do expected_hierarchy = { parent => [other_subgroup, { subgroup => [subsub_group, other_subsub_group] }] } - expect(described_class.merge_hierarchies(groups)).to eq(expected_hierarchy) + expect(described_class.build_hierarchy(groups)).to eq(expected_hierarchy) end it 'combines upto a given parent' do @@ -60,7 +60,7 @@ describe GroupDescendant, :nested_groups do expected_hierarchy = [other_subgroup, { subgroup => [subsub_group, other_subsub_group] }] - expect(described_class.merge_hierarchies(groups, parent)).to eq(expected_hierarchy) + expect(described_class.build_hierarchy(groups, parent)).to eq(expected_hierarchy) end it 'handles building a tree out of order' do @@ -71,7 +71,7 @@ describe GroupDescendant, :nested_groups do groups = [subsub_group, other_subgroup2, other_subsub_group] expected_hierarchy = { parent => [{ subgroup => subsub_group }, other_subgroup2, { other_subgroup => other_subsub_group }] } - expect(described_class.merge_hierarchies(groups)).to eq(expected_hierarchy) + expect(described_class.build_hierarchy(groups)).to eq(expected_hierarchy) end end end @@ -113,7 +113,7 @@ describe GroupDescendant, :nested_groups do end end - describe '.merge_hierarchies' do + describe '.build_hierarchy' do it 'combines hierarchies until the top' do other_project = create(:project, namespace: parent) other_subgroup_project = create(:project, namespace: subgroup) @@ -122,7 +122,7 @@ describe GroupDescendant, :nested_groups do expected_hierarchy = { parent => [other_project, { subgroup => [subsub_group, other_subgroup_project] }] } - expect(described_class.merge_hierarchies(elements)).to eq(expected_hierarchy) + expect(described_class.build_hierarchy(elements)).to eq(expected_hierarchy) end it 'combines upto a given parent' do @@ -133,13 +133,13 @@ describe GroupDescendant, :nested_groups do expected_hierarchy = [other_project, { subgroup => [subsub_group, other_subgroup_project] }] - expect(described_class.merge_hierarchies(elements, parent)).to eq(expected_hierarchy) + expect(described_class.build_hierarchy(elements, parent)).to eq(expected_hierarchy) end it 'merges to elements in the same hierarchy' do expected_hierarchy = { parent => subgroup } - expect(described_class.merge_hierarchies([parent, subgroup])).to eq(expected_hierarchy) + expect(described_class.build_hierarchy([parent, subgroup])).to eq(expected_hierarchy) end it 'merges complex hierarchies' do @@ -164,7 +164,7 @@ describe GroupDescendant, :nested_groups do { other_subgroup => other_subproject } ] - actual_hierarchy = described_class.merge_hierarchies(projects, parent) + actual_hierarchy = described_class.build_hierarchy(projects, parent) expect(actual_hierarchy).to eq(expected_hierarchy) end -- cgit v1.2.1 From ef043063f9d6f9f9482707d78214709b09620a78 Mon Sep 17 00:00:00 2001 From: Bob Van Landuyt Date: Mon, 2 Oct 2017 14:23:36 +0200 Subject: Clean up public/private api of `GroupDescendant` So only methods that are used elsewhere are public. --- spec/models/concerns/group_descendant_spec.rb | 32 --------------------------- 1 file changed, 32 deletions(-) (limited to 'spec/models') diff --git a/spec/models/concerns/group_descendant_spec.rb b/spec/models/concerns/group_descendant_spec.rb index b1578fc593e..f3a0c342d35 100644 --- a/spec/models/concerns/group_descendant_spec.rb +++ b/spec/models/concerns/group_descendant_spec.rb @@ -24,22 +24,6 @@ describe GroupDescendant, :nested_groups do end end - describe '#parent' do - it 'returns the correct parent' do - expect(subsub_group.parent).to eq(subgroup) - end - end - - describe '#merge_hierarchy' do - it 'combines hierarchies' do - other_subgroup = create(:group, parent: parent) - - expected_hierarchy = { parent => [{ subgroup => subsub_group }, other_subgroup] } - - expect(subsub_group.merge_hierarchy(other_subgroup)).to eq(expected_hierarchy) - end - end - describe '.build_hierarchy' do it 'combines hierarchies until the top' do other_subgroup = create(:group, parent: parent) @@ -97,22 +81,6 @@ describe GroupDescendant, :nested_groups do end end - describe '#parent' do - it 'returns the correct parent' do - expect(project.parent).to eq(subsub_group) - end - end - - describe '#merge_hierarchy' do - it 'combines hierarchies' do - project = create(:project, namespace: parent) - - expected_hierarchy = { parent => [{ subgroup => subsub_group }, project] } - - expect(subsub_group.merge_hierarchy(project)).to eq(expected_hierarchy) - end - end - describe '.build_hierarchy' do it 'combines hierarchies until the top' do other_project = create(:project, namespace: parent) -- cgit v1.2.1 From 167fd71348d145c6fee953004bf77ceebf6efb1e Mon Sep 17 00:00:00 2001 From: Bob Van Landuyt Date: Mon, 2 Oct 2017 18:21:18 +0200 Subject: Always preload all elements in a hierarchy to avoid extra queries. --- spec/models/concerns/group_descendant_spec.rb | 21 +++++++++++++++++++-- 1 file changed, 19 insertions(+), 2 deletions(-) (limited to 'spec/models') diff --git a/spec/models/concerns/group_descendant_spec.rb b/spec/models/concerns/group_descendant_spec.rb index f3a0c342d35..c17c8f2abec 100644 --- a/spec/models/concerns/group_descendant_spec.rb +++ b/spec/models/concerns/group_descendant_spec.rb @@ -7,6 +7,23 @@ describe GroupDescendant, :nested_groups do context 'for a group' do describe '#hierarchy' do + it 'only queries once for the ancestors' do + # make sure the subsub_group does not have anything cached + test_group = create(:group, parent: subsub_group).reload + + query_count = ActiveRecord::QueryRecorder.new { test_group.hierarchy }.count + + expect(query_count).to eq(1) + end + + it 'only queries once for the ancestors when a top is given' do + test_group = create(:group, parent: subsub_group).reload + + query_count = ActiveRecord::QueryRecorder.new { test_group.hierarchy(subgroup) }.count + + expect(query_count).to eq(1) + end + it 'builds a hierarchy for a group' do expected_hierarchy = { parent => { subgroup => subsub_group } } @@ -20,7 +37,7 @@ describe GroupDescendant, :nested_groups do end it 'raises an error if specifying a base that is not part of the tree' do - expect { subsub_group.hierarchy(double) }.to raise_error('specified base is not part of the tree') + expect { subsub_group.hierarchy(build_stubbed(:group)) }.to raise_error('specified top is not part of the tree') end end @@ -77,7 +94,7 @@ describe GroupDescendant, :nested_groups do end it 'raises an error if specifying a base that is not part of the tree' do - expect { project.hierarchy(double) }.to raise_error('specified base is not part of the tree') + expect { project.hierarchy(build_stubbed(:group)) }.to raise_error('specified top is not part of the tree') end end -- cgit v1.2.1 From 57bd3bb34a19bf812fd6a74f394a69c491b05dd0 Mon Sep 17 00:00:00 2001 From: Bob Van Landuyt Date: Wed, 4 Oct 2017 16:57:33 +0200 Subject: Force parents to be preloaded for building a hierarchy --- spec/models/concerns/group_descendant_spec.rb | 38 ++++++++++++++++----------- 1 file changed, 23 insertions(+), 15 deletions(-) (limited to 'spec/models') diff --git a/spec/models/concerns/group_descendant_spec.rb b/spec/models/concerns/group_descendant_spec.rb index c17c8f2abec..c163fb01a81 100644 --- a/spec/models/concerns/group_descendant_spec.rb +++ b/spec/models/concerns/group_descendant_spec.rb @@ -5,6 +5,10 @@ describe GroupDescendant, :nested_groups do let(:subgroup) { create(:group, parent: parent) } let(:subsub_group) { create(:group, parent: subgroup) } + def all_preloaded_groups(*groups) + groups + [parent, subgroup, subsub_group] + end + context 'for a group' do describe '#hierarchy' do it 'only queries once for the ancestors' do @@ -19,9 +23,8 @@ describe GroupDescendant, :nested_groups do it 'only queries once for the ancestors when a top is given' do test_group = create(:group, parent: subsub_group).reload - query_count = ActiveRecord::QueryRecorder.new { test_group.hierarchy(subgroup) }.count - - expect(query_count).to eq(1) + recorder = ActiveRecord::QueryRecorder.new { test_group.hierarchy(subgroup) } + expect(recorder.count).to eq(1) end it 'builds a hierarchy for a group' do @@ -37,7 +40,8 @@ describe GroupDescendant, :nested_groups do end it 'raises an error if specifying a base that is not part of the tree' do - expect { subsub_group.hierarchy(build_stubbed(:group)) }.to raise_error('specified top is not part of the tree') + expect { subsub_group.hierarchy(build_stubbed(:group)) } + .to raise_error('specified top is not part of the tree') end end @@ -46,7 +50,7 @@ describe GroupDescendant, :nested_groups do other_subgroup = create(:group, parent: parent) other_subsub_group = create(:group, parent: subgroup) - groups = [other_subgroup, subsub_group, other_subsub_group] + groups = all_preloaded_groups(other_subgroup, subsub_group, other_subsub_group) expected_hierarchy = { parent => [other_subgroup, { subgroup => [subsub_group, other_subsub_group] }] } @@ -58,9 +62,9 @@ describe GroupDescendant, :nested_groups do other_subsub_group = create(:group, parent: subgroup) groups = [other_subgroup, subsub_group, other_subsub_group] + groups << subgroup # Add the parent as if it was preloaded expected_hierarchy = [other_subgroup, { subgroup => [subsub_group, other_subsub_group] }] - expect(described_class.build_hierarchy(groups, parent)).to eq(expected_hierarchy) end @@ -69,11 +73,16 @@ describe GroupDescendant, :nested_groups do other_subgroup2 = create(:group, parent: parent) other_subsub_group = create(:group, parent: other_subgroup) - groups = [subsub_group, other_subgroup2, other_subsub_group] + groups = all_preloaded_groups(subsub_group, other_subgroup2, other_subsub_group, other_subgroup) expected_hierarchy = { parent => [{ subgroup => subsub_group }, other_subgroup2, { other_subgroup => other_subsub_group }] } expect(described_class.build_hierarchy(groups)).to eq(expected_hierarchy) end + + it 'raises an error if not all elements were preloaded' do + expect { described_class.build_hierarchy([subsub_group]) } + .to raise_error('parent was not preloaded') + end end end @@ -81,7 +90,7 @@ describe GroupDescendant, :nested_groups do let(:project) { create(:project, namespace: subsub_group) } describe '#hierarchy' do - it 'builds a hierarchy for a group' do + it 'builds a hierarchy for a project' do expected_hierarchy = { parent => { subgroup => { subsub_group => project } } } expect(project.hierarchy).to eq(expected_hierarchy) @@ -92,10 +101,6 @@ describe GroupDescendant, :nested_groups do expect(project.hierarchy(subgroup)).to eq(expected_hierarchy) end - - it 'raises an error if specifying a base that is not part of the tree' do - expect { project.hierarchy(build_stubbed(:group)) }.to raise_error('specified top is not part of the tree') - end end describe '.build_hierarchy' do @@ -103,7 +108,7 @@ describe GroupDescendant, :nested_groups do other_project = create(:project, namespace: parent) other_subgroup_project = create(:project, namespace: subgroup) - elements = [other_project, subsub_group, other_subgroup_project] + elements = all_preloaded_groups(other_project, subsub_group, other_subgroup_project) expected_hierarchy = { parent => [other_project, { subgroup => [subsub_group, other_subgroup_project] }] } @@ -115,6 +120,7 @@ describe GroupDescendant, :nested_groups do other_subgroup_project = create(:project, namespace: subgroup) elements = [other_project, subsub_group, other_subgroup_project] + elements << subgroup # Added as if it was preloaded expected_hierarchy = [other_project, { subgroup => [subsub_group, other_subgroup_project] }] @@ -136,7 +142,9 @@ describe GroupDescendant, :nested_groups do other_subgroup = create(:group, parent: parent) other_subproject = create(:project, namespace: other_subgroup) - projects = [project, subsubsub_project, sub_project, other_subproject, subsub_project] + elements = [project, subsubsub_project, sub_project, other_subproject, subsub_project] + # Add parent groups as if they were preloaded + elements += [other_subgroup, subsubsub_group, subsub_group, subgroup] expected_hierarchy = [ project, @@ -149,7 +157,7 @@ describe GroupDescendant, :nested_groups do { other_subgroup => other_subproject } ] - actual_hierarchy = described_class.build_hierarchy(projects, parent) + actual_hierarchy = described_class.build_hierarchy(elements, parent) expect(actual_hierarchy).to eq(expected_hierarchy) end -- cgit v1.2.1 From 951abe2b2efc3a208ceea46d9c1c47d3d253ff63 Mon Sep 17 00:00:00 2001 From: Bob Van Landuyt Date: Thu, 5 Oct 2017 10:32:52 +0200 Subject: Load counts everywhere we render a group tree --- spec/models/concerns/loaded_in_group_list_spec.rb | 28 +++++++++++++++++++++++ 1 file changed, 28 insertions(+) create mode 100644 spec/models/concerns/loaded_in_group_list_spec.rb (limited to 'spec/models') diff --git a/spec/models/concerns/loaded_in_group_list_spec.rb b/spec/models/concerns/loaded_in_group_list_spec.rb new file mode 100644 index 00000000000..d64b288aa0c --- /dev/null +++ b/spec/models/concerns/loaded_in_group_list_spec.rb @@ -0,0 +1,28 @@ +require 'spec_helper' + +describe LoadedInGroupList do + let(:parent) { create(:group) } + subject(:found_group) { Group.with_selects_for_list.find_by(id: parent.id) } + + before do + create(:group, parent: parent) + create(:project, namespace: parent) + parent.add_developer(create(:user)) + end + + describe '.with_selects_for_list' do + it 'includes the preloaded counts for groups' do + found_group = Group.with_selects_for_list.find_by(id: parent.id) + + expect(found_group.preloaded_project_count).to eq(1) + expect(found_group.preloaded_subgroup_count).to eq(1) + expect(found_group.preloaded_member_count).to eq(1) + end + end + + describe '#children_count' do + it 'counts groups and projects' do + expect(found_group.children_count).to eq(2) + end + end +end -- cgit v1.2.1 From b3acd5459c08f61b82799821ae09f17f4dcfec10 Mon Sep 17 00:00:00 2001 From: Bob Van Landuyt Date: Thu, 5 Oct 2017 10:47:32 +0200 Subject: Use `alias_attribute` & `alias_method` to define parent-methods --- spec/models/project_spec.rb | 7 +++++++ 1 file changed, 7 insertions(+) (limited to 'spec/models') diff --git a/spec/models/project_spec.rb b/spec/models/project_spec.rb index 176bb568cbe..def2e0983ac 100644 --- a/spec/models/project_spec.rb +++ b/spec/models/project_spec.rb @@ -2095,6 +2095,13 @@ describe Project do it { expect(project.parent).to eq(project.namespace) } end + describe '#parent_id' do + let(:project) { create(:project) } + + it { expect(project.parent_id).to eq(project.namespace_id) } + end + + describe '#parent_changed?' do let(:project) { create(:project) } -- cgit v1.2.1 From 9d1348d66838b4c5e25ba133d486239482973fca Mon Sep 17 00:00:00 2001 From: Bob Van Landuyt Date: Tue, 10 Oct 2017 15:45:35 +0200 Subject: Move the `ancestors_upto` to `Project` and `Namespace` --- spec/models/namespace_spec.rb | 14 ++++++++++++++ spec/models/project_spec.rb | 15 +++++++++++++++ 2 files changed, 29 insertions(+) (limited to 'spec/models') diff --git a/spec/models/namespace_spec.rb b/spec/models/namespace_spec.rb index 81d5ab7a6d3..4ce9f1b02e3 100644 --- a/spec/models/namespace_spec.rb +++ b/spec/models/namespace_spec.rb @@ -151,6 +151,20 @@ describe Namespace do end end + describe '#ancestors_upto', :nested_groups do + let(:parent) { create(:group) } + let(:child) { create(:group, parent: parent) } + let(:child2) { create(:group, parent: child) } + + it 'returns all ancestors when no namespace is given' do + expect(child2.ancestors_upto).to contain_exactly(child, parent) + end + + it 'includes ancestors upto but excluding the given ancestor' do + expect(child2.ancestors_upto(parent)).to contain_exactly(child) + end + end + describe '#move_dir' do before do @namespace = create :namespace diff --git a/spec/models/project_spec.rb b/spec/models/project_spec.rb index def2e0983ac..dedf3008994 100644 --- a/spec/models/project_spec.rb +++ b/spec/models/project_spec.rb @@ -1731,6 +1731,21 @@ describe Project do it { expect(project.gitea_import?).to be true } end + describe '#ancestors_upto', :nested_groups do + let(:parent) { create(:group) } + let(:child) { create(:group, parent: parent) } + let(:child2) { create(:group, parent: child) } + let(:project) { create(:project, namespace: child2) } + + it 'returns all ancestors when no namespace is given' do + expect(project.ancestors_upto).to contain_exactly(child2, child, parent) + end + + it 'includes ancestors upto but excluding the given ancestor' do + expect(project.ancestors_upto(parent)).to contain_exactly(child2, child) + end + end + describe '#lfs_enabled?' do let(:project) { create(:project) } -- cgit v1.2.1 From 5a903149e75465e4025f154977597aeef94b618c Mon Sep 17 00:00:00 2001 From: Bob Van Landuyt Date: Wed, 11 Oct 2017 10:17:24 +0200 Subject: Handle archived projects in the `GroupDescendantsFinder` --- spec/models/concerns/loaded_in_group_list_spec.rb | 33 ++++++++++++++++++----- 1 file changed, 27 insertions(+), 6 deletions(-) (limited to 'spec/models') diff --git a/spec/models/concerns/loaded_in_group_list_spec.rb b/spec/models/concerns/loaded_in_group_list_spec.rb index d64b288aa0c..bf5bfaa76de 100644 --- a/spec/models/concerns/loaded_in_group_list_spec.rb +++ b/spec/models/concerns/loaded_in_group_list_spec.rb @@ -4,24 +4,45 @@ describe LoadedInGroupList do let(:parent) { create(:group) } subject(:found_group) { Group.with_selects_for_list.find_by(id: parent.id) } - before do - create(:group, parent: parent) - create(:project, namespace: parent) - parent.add_developer(create(:user)) - end - describe '.with_selects_for_list' do it 'includes the preloaded counts for groups' do + create(:group, parent: parent) + create(:project, namespace: parent) + parent.add_developer(create(:user)) + found_group = Group.with_selects_for_list.find_by(id: parent.id) expect(found_group.preloaded_project_count).to eq(1) expect(found_group.preloaded_subgroup_count).to eq(1) expect(found_group.preloaded_member_count).to eq(1) end + + context 'with archived projects' do + it 'counts including archived projects when `true` is passed' do + create(:project, namespace: parent, archived: true) + create(:project, namespace: parent) + + found_group = Group.with_selects_for_list('true').find_by(id: parent.id) + + expect(found_group.preloaded_project_count).to eq(2) + end + + it 'counts only archived projects when `only` is passed' do + create_list(:project, 2, namespace: parent, archived: true) + create(:project, namespace: parent) + + found_group = Group.with_selects_for_list('only').find_by(id: parent.id) + + expect(found_group.preloaded_project_count).to eq(2) + end + end end describe '#children_count' do it 'counts groups and projects' do + create(:group, parent: parent) + create(:project, namespace: parent) + expect(found_group.children_count).to eq(2) end end -- cgit v1.2.1 From bd8943f5adfc377491bedb2a794d8c39b2b4c45e Mon Sep 17 00:00:00 2001 From: Bob Van Landuyt Date: Wed, 11 Oct 2017 11:22:49 +0200 Subject: Fix spinach features And several other failures --- spec/models/project_spec.rb | 1 - 1 file changed, 1 deletion(-) (limited to 'spec/models') diff --git a/spec/models/project_spec.rb b/spec/models/project_spec.rb index 984832b6959..74eba7e33f6 100644 --- a/spec/models/project_spec.rb +++ b/spec/models/project_spec.rb @@ -2199,7 +2199,6 @@ describe Project do it { expect(project.parent_id).to eq(project.namespace_id) } end - describe '#parent_changed?' do let(:project) { create(:project) } -- cgit v1.2.1 From 18907efbc9209ee39d8348eef5b3c7321b9aca26 Mon Sep 17 00:00:00 2001 From: Bob Van Landuyt Date: Wed, 11 Oct 2017 17:05:39 +0200 Subject: Pass `archived:` as a keyword argument --- spec/models/concerns/loaded_in_group_list_spec.rb | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'spec/models') diff --git a/spec/models/concerns/loaded_in_group_list_spec.rb b/spec/models/concerns/loaded_in_group_list_spec.rb index bf5bfaa76de..7a279547a3a 100644 --- a/spec/models/concerns/loaded_in_group_list_spec.rb +++ b/spec/models/concerns/loaded_in_group_list_spec.rb @@ -22,7 +22,7 @@ describe LoadedInGroupList do create(:project, namespace: parent, archived: true) create(:project, namespace: parent) - found_group = Group.with_selects_for_list('true').find_by(id: parent.id) + found_group = Group.with_selects_for_list(archived: 'true').find_by(id: parent.id) expect(found_group.preloaded_project_count).to eq(2) end @@ -31,7 +31,7 @@ describe LoadedInGroupList do create_list(:project, 2, namespace: parent, archived: true) create(:project, namespace: parent) - found_group = Group.with_selects_for_list('only').find_by(id: parent.id) + found_group = Group.with_selects_for_list(archived: 'only').find_by(id: parent.id) expect(found_group.preloaded_project_count).to eq(2) end -- cgit v1.2.1