Welcome to mirror list, hosted at ThFree Co, Russian Federation.

gitlab.com/gitlab-org/gitlab-foss.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to 'spec/models/namespaces/traversal/cached_spec.rb')
-rw-r--r--spec/models/namespaces/traversal/cached_spec.rb196
1 files changed, 135 insertions, 61 deletions
diff --git a/spec/models/namespaces/traversal/cached_spec.rb b/spec/models/namespaces/traversal/cached_spec.rb
index 8263e28bb98..dd52f9c3d70 100644
--- a/spec/models/namespaces/traversal/cached_spec.rb
+++ b/spec/models/namespaces/traversal/cached_spec.rb
@@ -3,101 +3,175 @@
require 'spec_helper'
RSpec.describe Namespaces::Traversal::Cached, feature_category: :database do
- let_it_be_with_refind(:old_parent) { create(:group) }
- let_it_be_with_refind(:new_parent) { create(:group) }
- let_it_be_with_refind(:group) { create(:group, parent: old_parent) }
- let_it_be_with_refind(:subgroup) { create(:group, parent: group) }
+ describe 'callbacks' do
+ let_it_be_with_refind(:old_parent) { create(:group) }
+ let_it_be_with_refind(:new_parent) { create(:group) }
+ let_it_be_with_refind(:group) { create(:group, parent: old_parent) }
+ let_it_be_with_refind(:subgroup) { create(:group, parent: group) }
- context 'when the namespace_descendants_cache_expiration feature flag is off' do
- let!(:cache) { create(:namespace_descendants, namespace: group) }
+ context 'when the namespace_descendants_cache_expiration feature flag is off' do
+ let!(:cache) { create(:namespace_descendants, namespace: group) }
- before do
- stub_feature_flags(namespace_descendants_cache_expiration: false)
- end
+ before do
+ stub_feature_flags(namespace_descendants_cache_expiration: false)
+ end
- it 'does not invalidate the cache' do
- expect { group.update!(parent: new_parent) }.not_to change { cache.reload.outdated_at }
- end
+ it 'does not invalidate the cache' do
+ expect { group.update!(parent: new_parent) }.not_to change { cache.reload.outdated_at }
+ end
- context 'when the group is deleted' do
- it 'invalidates the cache' do
- expect { group.destroy! }.not_to change { cache.reload.outdated_at }
+ context 'when the group is deleted' do
+ it 'invalidates the cache' do
+ expect { group.destroy! }.not_to change { cache.reload.outdated_at }
+ end
end
end
- end
- context 'when no cached records are present' do
- it 'does nothing' do
- group.parent = new_parent
+ context 'when no cached records are present' do
+ it 'does nothing' do
+ group.parent = new_parent
- expect { group.save! }.not_to change { Namespaces::Descendants.all.to_a }
+ expect { group.save! }.not_to change { Namespaces::Descendants.all.to_a }
+ end
end
- end
- context 'when the namespace record is UserNamespace' do
- it 'does nothing' do
- # we won't use the optimization for UserNamespace
- namespace = create(:user_namespace)
- cache = create(:namespace_descendants, namespace: namespace)
+ context 'when the namespace record is UserNamespace' do
+ it 'does nothing' do
+ # we won't use the optimization for UserNamespace
+ namespace = create(:user_namespace)
+ cache = create(:namespace_descendants, namespace: namespace)
- expect { namespace.destroy! }.not_to change { cache.reload.outdated_at }
+ expect { namespace.destroy! }.not_to change { cache.reload.outdated_at }
+ end
end
- end
- context 'when cached record is present' do
- let!(:cache) { create(:namespace_descendants, namespace: group) }
+ context 'when cached record is present' do
+ let!(:cache) { create(:namespace_descendants, namespace: group) }
- it 'invalidates the cache' do
- expect { group.update!(parent: new_parent) }.to change { cache.reload.outdated_at }.from(nil)
- end
+ it 'invalidates the cache' do
+ expect { group.update!(parent: new_parent) }.to change { cache.reload.outdated_at }.from(nil)
+ end
- it 'does not invalidate the cache of subgroups' do
- subgroup_cache = create(:namespace_descendants, namespace: subgroup)
+ it 'does not invalidate the cache of subgroups' do
+ subgroup_cache = create(:namespace_descendants, namespace: subgroup)
- expect { group.update!(parent: new_parent) }.not_to change { subgroup_cache.reload.outdated_at }
+ expect { group.update!(parent: new_parent) }.not_to change { subgroup_cache.reload.outdated_at }
+ end
+
+ context 'when a new subgroup is added' do
+ it 'invalidates the cache' do
+ expect { create(:group, parent: group) }.to change { cache.reload.outdated_at }
+ end
+ end
+
+ context 'when a new project is added' do
+ it 'invalidates the cache' do
+ expect { create(:project, group: group) }.to change { cache.reload.outdated_at }
+ end
+ end
end
- context 'when a new subgroup is added' do
- it 'invalidates the cache' do
- expect { create(:group, parent: group) }.to change { cache.reload.outdated_at }
+ context 'when parent group has cached record' do
+ it 'invalidates the parent cache' do
+ old_parent_cache = create(:namespace_descendants, namespace: old_parent)
+ new_parent_cache = create(:namespace_descendants, namespace: new_parent)
+
+ group.update!(parent: new_parent)
+
+ expect(old_parent_cache.reload.outdated_at).not_to be_nil
+ expect(new_parent_cache.reload.outdated_at).not_to be_nil
end
end
- context 'when a new project is added' do
+ context 'when group is destroyed' do
it 'invalidates the cache' do
- expect { create(:project, group: group) }.to change { cache.reload.outdated_at }
+ cache = create(:namespace_descendants, namespace: group)
+
+ expect { group.destroy! }.to change { cache.reload.outdated_at }.from(nil)
end
- end
- end
- context 'when parent group has cached record' do
- it 'invalidates the parent cache' do
- old_parent_cache = create(:namespace_descendants, namespace: old_parent)
- new_parent_cache = create(:namespace_descendants, namespace: new_parent)
+ context 'when parent group has cached record' do
+ it 'invalidates the parent cache' do
+ old_parent_cache = create(:namespace_descendants, namespace: old_parent)
+ new_parent_cache = create(:namespace_descendants, namespace: new_parent)
- group.update!(parent: new_parent)
+ group.destroy!
- expect(old_parent_cache.reload.outdated_at).not_to be_nil
- expect(new_parent_cache.reload.outdated_at).not_to be_nil
+ expect(old_parent_cache.reload.outdated_at).not_to be_nil
+ expect(new_parent_cache.reload.outdated_at).to be_nil # no change
+ end
+ end
end
end
- context 'when group is destroyed' do
- it 'invalidates the cache' do
- cache = create(:namespace_descendants, namespace: group)
+ describe 'query methods' do
+ let_it_be(:group) { create(:group) }
+ let_it_be(:subgroup) { create(:group, parent: group) }
+ let_it_be(:subsubgroup) { create(:group, parent: subgroup) }
+
+ let_it_be(:project1) { create(:project, group: group) }
+ let_it_be(:project2) { create(:project, group: subsubgroup) }
+
+ # deliberately making self_and_descendant_group_ids different from the actual
+ # self_and_descendant_ids so we can verify that the cached query is running.
+ let_it_be_with_refind(:namespace_descendants) do
+ create(:namespace_descendants,
+ :up_to_date,
+ namespace: group,
+ self_and_descendant_group_ids: [group.id, subgroup.id],
+ all_project_ids: [project1.id]
+ )
+ end
+
+ describe '#self_and_descendant_ids' do
+ subject(:ids) { group.self_and_descendant_ids.pluck(:id) }
+
+ it 'returns the cached values' do
+ expect(ids).to eq(namespace_descendants.self_and_descendant_group_ids)
+ end
+
+ context 'when the cache is outdated' do
+ it 'returns the values from the uncached self_and_descendant_ids query' do
+ namespace_descendants.update!(outdated_at: Time.current)
+
+ expect(ids.sort).to eq([group.id, subgroup.id, subsubgroup.id])
+ end
+ end
+
+ context 'when the group_hierarchy_optimization feature flag is disabled' do
+ before do
+ stub_feature_flags(group_hierarchy_optimization: false)
+ end
- expect { group.destroy! }.to change { cache.reload.outdated_at }.from(nil)
+ it 'returns the values from the uncached self_and_descendant_ids query' do
+ expect(ids.sort).to eq([group.id, subgroup.id, subsubgroup.id])
+ end
+ end
end
- context 'when parent group has cached record' do
- it 'invalidates the parent cache' do
- old_parent_cache = create(:namespace_descendants, namespace: old_parent)
- new_parent_cache = create(:namespace_descendants, namespace: new_parent)
+ describe '#all_project_ids' do
+ subject(:ids) { group.all_project_ids.pluck(:id) }
- group.destroy!
+ it 'returns the cached values' do
+ expect(ids).to eq(namespace_descendants.all_project_ids)
+ end
- expect(old_parent_cache.reload.outdated_at).not_to be_nil
- expect(new_parent_cache.reload.outdated_at).to be_nil # no change
+ context 'when the cache is outdated' do
+ it 'returns the values from the uncached all_project_ids query' do
+ namespace_descendants.update!(outdated_at: Time.current)
+
+ expect(ids.sort).to eq([project1.id, project2.id])
+ end
+ end
+
+ context 'when the group_hierarchy_optimization feature flag is disabled' do
+ before do
+ stub_feature_flags(group_hierarchy_optimization: false)
+ end
+
+ it 'returns the values from the uncached all_project_ids query' do
+ expect(ids.sort).to eq([project1.id, project2.id])
+ end
end
end
end