diff --git a/ee/app/models/concerns/geo/selective_sync.rb b/ee/app/models/concerns/geo/selective_sync.rb index ef56565258779d24f2e0c185960c7e0c19811e66..cfedaa7f62b63eca3fe360a561fd0d667d0fc26e 100644 --- a/ee/app/models/concerns/geo/selective_sync.rb +++ b/ee/app/models/concerns/geo/selective_sync.rb @@ -16,6 +16,11 @@ def selective_sync_by_shards? selective_sync_type == 'shards' end + def selective_sync_by_organizations? + # TODO: Implement organization-based selective sync in issue #514251 + false + end + # This method should only be used when: # # - Selective sync is enabled diff --git a/ee/app/models/group_wiki_repository.rb b/ee/app/models/group_wiki_repository.rb index 42f90bc7390856b4a9a6424e69613b2a1b89185b..09474afb8d08bfb56c92985e6e3b328e35eacaf8 100644 --- a/ee/app/models/group_wiki_repository.rb +++ b/ee/app/models/group_wiki_repository.rb @@ -43,6 +43,7 @@ def self.selective_sync_scope(node, **_params) return all unless node.selective_sync? return group_wiki_repositories_for_selected_namespaces(node) if node.selective_sync_by_namespaces? return group_wiki_repositories_for_selected_shards(node) if node.selective_sync_by_shards? + return group_wiki_repositories_for_selected_organizations(node) if node.selective_sync_by_organizations? self.none end @@ -55,6 +56,10 @@ def self.group_wiki_repositories_for_selected_shards(node) self.for_repository_storage(node.selective_sync_shards) end + def self.group_wiki_repositories_for_selected_organizations(node) + self.joins(:group).where(group_id: node.namespaces_for_group_owned_replicables.select(:id)) + end + override :verification_state_table_class def self.verification_state_table_class ::Geo::GroupWikiRepositoryState diff --git a/ee/spec/models/group_wiki_repository_spec.rb b/ee/spec/models/group_wiki_repository_spec.rb index 2209d44b9711bd1d1db029c3853302ca3e109a99..764811f91d587b87149565ee326d4702c3b54e11 100644 --- a/ee/spec/models/group_wiki_repository_spec.rb +++ b/ee/spec/models/group_wiki_repository_spec.rb @@ -80,6 +80,23 @@ expect(broken_wiki_repository.in_replicables_for_current_secondary?).to be false end end + + context 'with selective sync by organizations' do + before do + allow(node).to receive(:selective_sync_by_organizations?).and_return(true) + allow(node).to receive(:namespaces_for_group_owned_replicables).and_return(Group.where(id: [root_group.id, subgroup.id])) + end + + it 'returns true for groups in selected organizations' do + expect(root_group_wiki_repository.in_replicables_for_current_secondary?).to be true + expect(subgroup_wiki_repository.in_replicables_for_current_secondary?).to be true + end + + it 'returns false for groups not in selected organizations' do + allow(node).to receive(:namespaces_for_group_owned_replicables).and_return(Group.where(id: root_group.id)) + expect(broken_wiki_repository.in_replicables_for_current_secondary?).to be false + end + end end describe '.replicables_for_current_secondary' do @@ -125,12 +142,117 @@ end end + context 'with selective sync by organizations' do + before do + allow(node).to receive(:selective_sync_by_organizations?).and_return(true) + end + + it 'returns group wiki repositories that belong to selected organizations' do + allow(node).to receive(:namespaces_for_group_owned_replicables).and_return(Group.where(id: [root_group.id, subgroup.id])) + + expect(described_class.replicables_for_current_secondary(1..described_class.last.id)).to match_array( + [ + root_group_wiki_repository, + subgroup_wiki_repository + ]) + end + + it 'returns only root group wiki repository when only root group is in selected organizations' do + allow(node).to receive(:namespaces_for_group_owned_replicables).and_return(Group.where(id: root_group.id)) + + expect(described_class.replicables_for_current_secondary(1..described_class.last.id)).to match_array( + [ + root_group_wiki_repository + ]) + end + + it 'returns empty when no groups are in selected organizations' do + allow(node).to receive(:namespaces_for_group_owned_replicables).and_return(Group.none) + + expect(described_class.replicables_for_current_secondary(1..described_class.last.id)).to be_empty + end + end + it 'returns nothing if an unrecognised selective sync type is used' do node.update_attribute(:selective_sync_type, 'unknown') expect(described_class.replicables_for_current_secondary(1..described_class.last.id)).to be_empty end end + + describe '.selective_sync_scope' do + it 'returns all repositories when selective sync is disabled' do + node.update!(selective_sync_type: nil) + + expect(described_class.selective_sync_scope(node)).to match_array( + [ + root_group_wiki_repository, + subgroup_wiki_repository, + broken_wiki_repository + ]) + end + + it 'returns repositories for selected namespaces' do + node.update!(selective_sync_type: 'namespaces', namespaces: [root_group]) + + expect(described_class.selective_sync_scope(node)).to match_array( + [ + root_group_wiki_repository, + subgroup_wiki_repository + ]) + end + + it 'returns repositories for selected shards' do + node.update!(selective_sync_type: 'shards', selective_sync_shards: ['default']) + + expect(described_class.selective_sync_scope(node)).to match_array( + [ + root_group_wiki_repository, + subgroup_wiki_repository + ]) + end + + it 'returns repositories for selected organizations' do + allow(node).to receive(:selective_sync_by_organizations?).and_return(true) + allow(node).to receive(:namespaces_for_group_owned_replicables).and_return(Group.where(id: [root_group.id, subgroup.id])) + + expect(described_class.selective_sync_scope(node)).to match_array( + [ + root_group_wiki_repository, + subgroup_wiki_repository + ]) + end + + it 'returns empty scope for unknown selective sync type' do + node.update_attribute(:selective_sync_type, 'unknown') + + expect(described_class.selective_sync_scope(node)).to be_empty + end + end + + describe '.group_wiki_repositories_for_selected_organizations' do + it 'returns repositories for groups in the provided namespace scope' do + namespace_scope = Group.where(id: [root_group.id, subgroup.id]) + allow(node).to receive(:namespaces_for_group_owned_replicables).and_return(namespace_scope) + + result = described_class.group_wiki_repositories_for_selected_organizations(node) + + expect(result).to match_array( + [ + root_group_wiki_repository, + subgroup_wiki_repository + ]) + end + + it 'returns empty when namespace scope is empty' do + namespace_scope = Group.none + allow(node).to receive(:namespaces_for_group_owned_replicables).and_return(namespace_scope) + + result = described_class.group_wiki_repositories_for_selected_organizations(node) + + expect(result).to be_empty + end + end end end