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/finders')
-rw-r--r--spec/finders/applications_finder_spec.rb40
-rw-r--r--spec/finders/ci/variables_finder_spec.rb65
-rw-r--r--spec/finders/concerns/finder_with_group_hierarchy_spec.rb112
-rw-r--r--spec/finders/concerns/packages/finder_helper_spec.rb209
-rw-r--r--spec/finders/design_management/designs_finder_spec.rb1
-rw-r--r--spec/finders/design_management/versions_finder_spec.rb1
-rw-r--r--spec/finders/environments_by_deployments_finder_spec.rb127
-rw-r--r--spec/finders/environments_finder_spec.rb126
-rw-r--r--spec/finders/group_members_finder_spec.rb282
-rw-r--r--spec/finders/issues_finder_spec.rb18
-rw-r--r--spec/finders/merge_requests/oldest_per_commit_finder_spec.rb39
-rw-r--r--spec/finders/merge_requests_finder_spec.rb12
-rw-r--r--spec/finders/metrics/dashboards/annotations_finder_spec.rb1
-rw-r--r--spec/finders/metrics/users_starred_dashboards_finder_spec.rb1
-rw-r--r--spec/finders/notes_finder_spec.rb18
-rw-r--r--spec/finders/packages/go/package_finder_spec.rb71
-rw-r--r--spec/finders/packages/maven/package_finder_spec.rb157
-rw-r--r--spec/finders/pending_todos_finder_spec.rb12
-rw-r--r--spec/finders/projects_finder_spec.rb6
-rw-r--r--spec/finders/repositories/branch_names_finder_spec.rb25
-rw-r--r--spec/finders/repositories/changelog_tag_finder_spec.rb (renamed from spec/finders/repositories/previous_tag_finder_spec.rb)13
-rw-r--r--spec/finders/user_group_notification_settings_finder_spec.rb33
22 files changed, 973 insertions, 396 deletions
diff --git a/spec/finders/applications_finder_spec.rb b/spec/finders/applications_finder_spec.rb
index dc615144b88..b6c48d8cdae 100644
--- a/spec/finders/applications_finder_spec.rb
+++ b/spec/finders/applications_finder_spec.rb
@@ -5,18 +5,48 @@ require 'spec_helper'
RSpec.describe ApplicationsFinder do
let(:application1) { create(:application, name: 'some_application', owner: nil, redirect_uri: 'http://some_application.url', scopes: '') }
let(:application2) { create(:application, name: 'another_application', owner: nil, redirect_uri: 'http://other_application.url', scopes: '') }
+ let(:user_application) { create(:application, name: 'user_application', owner: create(:user), redirect_uri: 'http://user_application.url', scopes: '') }
+ let(:group_application) { create(:application, name: 'group_application', owner: create(:group), redirect_uri: 'http://group_application.url', scopes: '') }
describe '#execute' do
- it 'returns an array of applications' do
+ it 'returns an array of instance applications' do
found = described_class.new.execute
expect(found).to match_array([application1, application2])
end
- it 'returns the application by id' do
- params = { id: application1.id }
- found = described_class.new(params).execute
- expect(found).to match(application1)
+ context 'by_id' do
+ context 'with existing id' do
+ it 'returns the application' do
+ params = { id: application1.id }
+ found = described_class.new(params).execute
+
+ expect(found).to match(application1)
+ end
+ end
+
+ context 'with invalid id' do
+ it 'returns nil for user application' do
+ params = { id: user_application.id }
+ found = described_class.new(params).execute
+
+ expect(found).to be_nil
+ end
+
+ it 'returns nil for group application' do
+ params = { id: group_application.id }
+ found = described_class.new(params).execute
+
+ expect(found).to be_nil
+ end
+
+ it 'returns nil for non-existing application' do
+ params = { id: non_existing_record_id }
+ found = described_class.new(params).execute
+
+ expect(found).to be_nil
+ end
+ end
end
end
end
diff --git a/spec/finders/ci/variables_finder_spec.rb b/spec/finders/ci/variables_finder_spec.rb
index cd5f950ca8e..683788452cc 100644
--- a/spec/finders/ci/variables_finder_spec.rb
+++ b/spec/finders/ci/variables_finder_spec.rb
@@ -3,42 +3,57 @@
require 'spec_helper'
RSpec.describe Ci::VariablesFinder do
- let!(:project) { create(:project) }
- let!(:params) { {} }
+ shared_examples 'scoped variables' do
+ describe '#initialize' do
+ subject { described_class.new(owner, params) }
- let!(:var1) { create(:ci_variable, project: project, key: 'key1', environment_scope: 'staging') }
- let!(:var2) { create(:ci_variable, project: project, key: 'key2', environment_scope: 'staging') }
- let!(:var3) { create(:ci_variable, project: project, key: 'key2', environment_scope: 'production') }
+ context 'without key filter' do
+ let!(:params) { {} }
- describe '#initialize' do
- subject { described_class.new(project, params) }
-
- context 'without key filter' do
- let!(:params) { {} }
-
- it 'raises an error' do
- expect { subject }.to raise_error(ArgumentError, 'Please provide params[:key]')
+ it 'raises an error' do
+ expect { subject }.to raise_error(ArgumentError, 'Please provide params[:key]')
+ end
end
end
- end
- describe '#execute' do
- subject { described_class.new(project.reload, params).execute }
+ describe '#execute' do
+ subject { described_class.new(owner.reload, params).execute }
- context 'with key filter' do
- let!(:params) { { key: 'key1' } }
+ context 'with key filter' do
+ let!(:params) { { key: 'key1' } }
- it 'returns var1' do
- expect(subject).to contain_exactly(var1)
+ it 'returns var1' do
+ expect(subject).to contain_exactly(var1)
+ end
end
- end
- context 'with key and environment_scope filter' do
- let!(:params) { { key: 'key2', filter: { environment_scope: 'staging' } } }
+ context 'with key and environment_scope filter' do
+ let!(:params) { { key: 'key2', filter: { environment_scope: 'staging' } } }
- it 'returns var2' do
- expect(subject).to contain_exactly(var2)
+ it 'returns var2' do
+ expect(subject).to contain_exactly(var2)
+ end
end
end
end
+
+ context 'for a project' do
+ let(:owner) { create(:project) }
+
+ let!(:var1) { create(:ci_variable, project: owner, key: 'key1', environment_scope: 'staging') }
+ let!(:var2) { create(:ci_variable, project: owner, key: 'key2', environment_scope: 'staging') }
+ let!(:var3) { create(:ci_variable, project: owner, key: 'key2', environment_scope: 'production') }
+
+ include_examples 'scoped variables'
+ end
+
+ context 'for a group' do
+ let(:owner) { create(:group) }
+
+ let!(:var1) { create(:ci_group_variable, group: owner, key: 'key1', environment_scope: 'staging') }
+ let!(:var2) { create(:ci_group_variable, group: owner, key: 'key2', environment_scope: 'staging') }
+ let!(:var3) { create(:ci_group_variable, group: owner, key: 'key2', environment_scope: 'production') }
+
+ include_examples 'scoped variables'
+ end
end
diff --git a/spec/finders/concerns/finder_with_group_hierarchy_spec.rb b/spec/finders/concerns/finder_with_group_hierarchy_spec.rb
new file mode 100644
index 00000000000..8c2026a00a1
--- /dev/null
+++ b/spec/finders/concerns/finder_with_group_hierarchy_spec.rb
@@ -0,0 +1,112 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe FinderWithGroupHierarchy do
+ let(:finder_class) do
+ Class.new do
+ include FinderWithGroupHierarchy
+ include Gitlab::Utils::StrongMemoize
+
+ def initialize(current_user, params = {})
+ @current_user = current_user
+ @params = params
+ end
+
+ def execute(skip_authorization: false)
+ @skip_authorization = skip_authorization
+
+ item_ids
+ end
+
+ # normally an array of item ids would be returned,
+ # however for this spec just return the group ids
+ def item_ids
+ group? ? group_ids_for(group) : []
+ end
+
+ private
+
+ attr_reader :current_user, :params, :skip_authorization
+
+ def read_permission
+ :read_label
+ end
+ end
+ end
+
+ let_it_be(:parent_group) { create(:group) }
+ let_it_be(:group) { create(:group, parent: parent_group) }
+ let_it_be(:private_group) { create(:group, :private) }
+ let_it_be(:private_subgroup) { create(:group, :private, parent: private_group) }
+
+ let(:user) { create(:user) }
+
+ context 'when specifying group' do
+ it 'returns only the group by default' do
+ finder = finder_class.new(user, group: group)
+
+ expect(finder.execute).to match_array([group.id])
+ end
+ end
+
+ context 'when specifying group_id' do
+ it 'returns only the group by default' do
+ finder = finder_class.new(user, group_id: group.id)
+
+ expect(finder.execute).to match_array([group.id])
+ end
+ end
+
+ context 'when including items from group ancestors' do
+ before do
+ private_subgroup.add_developer(user)
+ end
+
+ it 'returns group and its ancestors' do
+ private_group.add_developer(user)
+
+ finder = finder_class.new(user, group: private_subgroup, include_ancestor_groups: true)
+
+ expect(finder.execute).to match_array([private_group.id, private_subgroup.id])
+ end
+
+ it 'ignores groups which user can not read' do
+ finder = finder_class.new(user, group: private_subgroup, include_ancestor_groups: true)
+
+ expect(finder.execute).to match_array([private_subgroup.id])
+ end
+
+ it 'returns them all when skip_authorization is true' do
+ finder = finder_class.new(user, group: private_subgroup, include_ancestor_groups: true)
+
+ expect(finder.execute(skip_authorization: true)).to match_array([private_group.id, private_subgroup.id])
+ end
+ end
+
+ context 'when including items from group descendants' do
+ before do
+ private_subgroup.add_developer(user)
+ end
+
+ it 'returns items from group and its descendants' do
+ private_group.add_developer(user)
+
+ finder = finder_class.new(user, group: private_group, include_descendant_groups: true)
+
+ expect(finder.execute).to match_array([private_group.id, private_subgroup.id])
+ end
+
+ it 'ignores items from groups which user can not read' do
+ finder = finder_class.new(user, group: private_group, include_descendant_groups: true)
+
+ expect(finder.execute).to match_array([private_subgroup.id])
+ end
+
+ it 'returns them all when skip_authorization is true' do
+ finder = finder_class.new(user, group: private_group, include_descendant_groups: true)
+
+ expect(finder.execute(skip_authorization: true)).to match_array([private_group.id, private_subgroup.id])
+ end
+ end
+end
diff --git a/spec/finders/concerns/packages/finder_helper_spec.rb b/spec/finders/concerns/packages/finder_helper_spec.rb
index 73f77647573..c1740ee1796 100644
--- a/spec/finders/concerns/packages/finder_helper_spec.rb
+++ b/spec/finders/concerns/packages/finder_helper_spec.rb
@@ -6,7 +6,6 @@ RSpec.describe ::Packages::FinderHelper do
describe '#packages_visible_to_user' do
using RSpec::Parameterized::TableSyntax
- let_it_be(:user) { create(:user) }
let_it_be_with_reload(:group) { create(:group) }
let_it_be_with_reload(:project1) { create(:project, namespace: group) }
let_it_be(:package1) { create(:package, project: project1) }
@@ -44,41 +43,87 @@ RSpec.describe ::Packages::FinderHelper do
it { is_expected.to be_empty }
end
- where(:group_visibility, :subgroup_visibility, :project2_visibility, :user_role, :shared_example_name) do
- 'PUBLIC' | 'PUBLIC' | 'PUBLIC' | :maintainer | 'returning both packages'
- 'PUBLIC' | 'PUBLIC' | 'PUBLIC' | :developer | 'returning both packages'
- 'PUBLIC' | 'PUBLIC' | 'PUBLIC' | :guest | 'returning both packages'
- 'PUBLIC' | 'PUBLIC' | 'PUBLIC' | :anonymous | 'returning both packages'
- 'PUBLIC' | 'PUBLIC' | 'PRIVATE' | :maintainer | 'returning both packages'
- 'PUBLIC' | 'PUBLIC' | 'PRIVATE' | :developer | 'returning both packages'
- 'PUBLIC' | 'PUBLIC' | 'PRIVATE' | :guest | 'returning package1'
- 'PUBLIC' | 'PUBLIC' | 'PRIVATE' | :anonymous | 'returning package1'
- 'PUBLIC' | 'PRIVATE' | 'PRIVATE' | :maintainer | 'returning both packages'
- 'PUBLIC' | 'PRIVATE' | 'PRIVATE' | :developer | 'returning both packages'
- 'PUBLIC' | 'PRIVATE' | 'PRIVATE' | :guest | 'returning package1'
- 'PUBLIC' | 'PRIVATE' | 'PRIVATE' | :anonymous | 'returning package1'
- 'PRIVATE' | 'PRIVATE' | 'PRIVATE' | :maintainer | 'returning both packages'
- 'PRIVATE' | 'PRIVATE' | 'PRIVATE' | :developer | 'returning both packages'
- 'PRIVATE' | 'PRIVATE' | 'PRIVATE' | :guest | 'returning no packages'
- 'PRIVATE' | 'PRIVATE' | 'PRIVATE' | :anonymous | 'returning no packages'
+ context 'with a user' do
+ let_it_be(:user) { create(:user) }
+
+ where(:group_visibility, :subgroup_visibility, :project2_visibility, :user_role, :shared_example_name) do
+ 'PUBLIC' | 'PUBLIC' | 'PUBLIC' | :maintainer | 'returning both packages'
+ 'PUBLIC' | 'PUBLIC' | 'PUBLIC' | :developer | 'returning both packages'
+ 'PUBLIC' | 'PUBLIC' | 'PUBLIC' | :guest | 'returning both packages'
+ 'PUBLIC' | 'PUBLIC' | 'PUBLIC' | :anonymous | 'returning both packages'
+ 'PUBLIC' | 'PUBLIC' | 'PRIVATE' | :maintainer | 'returning both packages'
+ 'PUBLIC' | 'PUBLIC' | 'PRIVATE' | :developer | 'returning both packages'
+ 'PUBLIC' | 'PUBLIC' | 'PRIVATE' | :guest | 'returning package1'
+ 'PUBLIC' | 'PUBLIC' | 'PRIVATE' | :anonymous | 'returning package1'
+ 'PUBLIC' | 'PRIVATE' | 'PRIVATE' | :maintainer | 'returning both packages'
+ 'PUBLIC' | 'PRIVATE' | 'PRIVATE' | :developer | 'returning both packages'
+ 'PUBLIC' | 'PRIVATE' | 'PRIVATE' | :guest | 'returning package1'
+ 'PUBLIC' | 'PRIVATE' | 'PRIVATE' | :anonymous | 'returning package1'
+ 'PRIVATE' | 'PRIVATE' | 'PRIVATE' | :maintainer | 'returning both packages'
+ 'PRIVATE' | 'PRIVATE' | 'PRIVATE' | :developer | 'returning both packages'
+ 'PRIVATE' | 'PRIVATE' | 'PRIVATE' | :guest | 'returning no packages'
+ 'PRIVATE' | 'PRIVATE' | 'PRIVATE' | :anonymous | 'returning no packages'
+ end
+
+ with_them do
+ before do
+ unless user_role == :anonymous
+ group.send("add_#{user_role}", user)
+ subgroup.send("add_#{user_role}", user)
+ project1.send("add_#{user_role}", user)
+ project2.send("add_#{user_role}", user)
+ end
+
+ project2.update!(visibility_level: Gitlab::VisibilityLevel.const_get(project2_visibility, false))
+ subgroup.update!(visibility_level: Gitlab::VisibilityLevel.const_get(subgroup_visibility, false))
+ project1.update!(visibility_level: Gitlab::VisibilityLevel.const_get(group_visibility, false))
+ group.update!(visibility_level: Gitlab::VisibilityLevel.const_get(group_visibility, false))
+ end
+
+ it_behaves_like params[:shared_example_name]
+ end
end
- with_them do
- before do
- unless user_role == :anonymous
- group.send("add_#{user_role}", user)
- subgroup.send("add_#{user_role}", user)
- project1.send("add_#{user_role}", user)
- project2.send("add_#{user_role}", user)
+ context 'with a group deploy token' do
+ let_it_be(:user) { create(:deploy_token, :group, read_package_registry: true) }
+ let_it_be(:group_deploy_token) { create(:group_deploy_token, deploy_token: user, group: group) }
+
+ shared_examples 'handling all conditions' do
+ where(:group_visibility, :subgroup_visibility, :project2_visibility, :shared_example_name) do
+ 'PUBLIC' | 'PUBLIC' | 'PUBLIC' | 'returning both packages'
+ 'PUBLIC' | 'PUBLIC' | 'PRIVATE' | 'returning both packages'
+ 'PUBLIC' | 'PRIVATE' | 'PRIVATE' | 'returning both packages'
+ 'PRIVATE' | 'PRIVATE' | 'PRIVATE' | 'returning both packages'
+ end
+
+ with_them do
+ before do
+ project2.update!(visibility_level: Gitlab::VisibilityLevel.const_get(project2_visibility, false))
+ subgroup.update!(visibility_level: Gitlab::VisibilityLevel.const_get(subgroup_visibility, false))
+ project1.update!(visibility_level: Gitlab::VisibilityLevel.const_get(group_visibility, false))
+ group.update!(visibility_level: Gitlab::VisibilityLevel.const_get(group_visibility, false))
+ end
+
+ it_behaves_like params[:shared_example_name]
+ end
+ end
+
+ context 'with packages_finder_helper_deploy_token enabled' do
+ before do
+ expect(group).not_to receive(:all_projects)
end
- project2.update!(visibility_level: Gitlab::VisibilityLevel.const_get(project2_visibility, false))
- subgroup.update!(visibility_level: Gitlab::VisibilityLevel.const_get(subgroup_visibility, false))
- project1.update!(visibility_level: Gitlab::VisibilityLevel.const_get(group_visibility, false))
- group.update!(visibility_level: Gitlab::VisibilityLevel.const_get(group_visibility, false))
+ it_behaves_like 'handling all conditions'
end
- it_behaves_like params[:shared_example_name]
+ context 'with packages_finder_helper_deploy_token disabled' do
+ before do
+ stub_feature_flags(packages_finder_helper_deploy_token: false)
+ expect(group).to receive(:all_projects).and_call_original
+ end
+
+ it_behaves_like 'handling all conditions'
+ end
end
end
@@ -121,41 +166,87 @@ RSpec.describe ::Packages::FinderHelper do
it { is_expected.to be_empty }
end
- where(:group_visibility, :subgroup_visibility, :project2_visibility, :user_role, :shared_example_name) do
- 'PUBLIC' | 'PUBLIC' | 'PUBLIC' | :maintainer | 'returning both projects'
- 'PUBLIC' | 'PUBLIC' | 'PUBLIC' | :developer | 'returning both projects'
- 'PUBLIC' | 'PUBLIC' | 'PUBLIC' | :guest | 'returning both projects'
- 'PUBLIC' | 'PUBLIC' | 'PUBLIC' | :anonymous | 'returning both projects'
- 'PUBLIC' | 'PUBLIC' | 'PRIVATE' | :maintainer | 'returning both projects'
- 'PUBLIC' | 'PUBLIC' | 'PRIVATE' | :developer | 'returning both projects'
- 'PUBLIC' | 'PUBLIC' | 'PRIVATE' | :guest | 'returning project1'
- 'PUBLIC' | 'PUBLIC' | 'PRIVATE' | :anonymous | 'returning project1'
- 'PUBLIC' | 'PRIVATE' | 'PRIVATE' | :maintainer | 'returning both projects'
- 'PUBLIC' | 'PRIVATE' | 'PRIVATE' | :developer | 'returning both projects'
- 'PUBLIC' | 'PRIVATE' | 'PRIVATE' | :guest | 'returning project1'
- 'PUBLIC' | 'PRIVATE' | 'PRIVATE' | :anonymous | 'returning project1'
- 'PRIVATE' | 'PRIVATE' | 'PRIVATE' | :maintainer | 'returning both projects'
- 'PRIVATE' | 'PRIVATE' | 'PRIVATE' | :developer | 'returning both projects'
- 'PRIVATE' | 'PRIVATE' | 'PRIVATE' | :guest | 'returning no project'
- 'PRIVATE' | 'PRIVATE' | 'PRIVATE' | :anonymous | 'returning no project'
+ context 'with a user' do
+ let_it_be(:user) { create(:user) }
+
+ where(:group_visibility, :subgroup_visibility, :project2_visibility, :user_role, :shared_example_name) do
+ 'PUBLIC' | 'PUBLIC' | 'PUBLIC' | :maintainer | 'returning both projects'
+ 'PUBLIC' | 'PUBLIC' | 'PUBLIC' | :developer | 'returning both projects'
+ 'PUBLIC' | 'PUBLIC' | 'PUBLIC' | :guest | 'returning both projects'
+ 'PUBLIC' | 'PUBLIC' | 'PUBLIC' | :anonymous | 'returning both projects'
+ 'PUBLIC' | 'PUBLIC' | 'PRIVATE' | :maintainer | 'returning both projects'
+ 'PUBLIC' | 'PUBLIC' | 'PRIVATE' | :developer | 'returning both projects'
+ 'PUBLIC' | 'PUBLIC' | 'PRIVATE' | :guest | 'returning project1'
+ 'PUBLIC' | 'PUBLIC' | 'PRIVATE' | :anonymous | 'returning project1'
+ 'PUBLIC' | 'PRIVATE' | 'PRIVATE' | :maintainer | 'returning both projects'
+ 'PUBLIC' | 'PRIVATE' | 'PRIVATE' | :developer | 'returning both projects'
+ 'PUBLIC' | 'PRIVATE' | 'PRIVATE' | :guest | 'returning project1'
+ 'PUBLIC' | 'PRIVATE' | 'PRIVATE' | :anonymous | 'returning project1'
+ 'PRIVATE' | 'PRIVATE' | 'PRIVATE' | :maintainer | 'returning both projects'
+ 'PRIVATE' | 'PRIVATE' | 'PRIVATE' | :developer | 'returning both projects'
+ 'PRIVATE' | 'PRIVATE' | 'PRIVATE' | :guest | 'returning no project'
+ 'PRIVATE' | 'PRIVATE' | 'PRIVATE' | :anonymous | 'returning no project'
+ end
+
+ with_them do
+ before do
+ unless user_role == :anonymous
+ group.send("add_#{user_role}", user)
+ subgroup.send("add_#{user_role}", user)
+ project1.send("add_#{user_role}", user)
+ project2.send("add_#{user_role}", user)
+ end
+
+ project2.update!(visibility_level: Gitlab::VisibilityLevel.const_get(project2_visibility, false))
+ subgroup.update!(visibility_level: Gitlab::VisibilityLevel.const_get(subgroup_visibility, false))
+ project1.update!(visibility_level: Gitlab::VisibilityLevel.const_get(group_visibility, false))
+ group.update!(visibility_level: Gitlab::VisibilityLevel.const_get(group_visibility, false))
+ end
+
+ it_behaves_like params[:shared_example_name]
+ end
end
- with_them do
- before do
- unless user_role == :anonymous
- group.send("add_#{user_role}", user)
- subgroup.send("add_#{user_role}", user)
- project1.send("add_#{user_role}", user)
- project2.send("add_#{user_role}", user)
+ context 'with a group deploy token' do
+ let_it_be(:user) { create(:deploy_token, :group, read_package_registry: true) }
+ let_it_be(:group_deploy_token) { create(:group_deploy_token, deploy_token: user, group: group) }
+
+ shared_examples 'handling all conditions' do
+ where(:group_visibility, :subgroup_visibility, :project2_visibility, :shared_example_name) do
+ 'PUBLIC' | 'PUBLIC' | 'PUBLIC' | 'returning both projects'
+ 'PUBLIC' | 'PUBLIC' | 'PRIVATE' | 'returning both projects'
+ 'PUBLIC' | 'PRIVATE' | 'PRIVATE' | 'returning both projects'
+ 'PRIVATE' | 'PRIVATE' | 'PRIVATE' | 'returning both projects'
end
- project2.update!(visibility_level: Gitlab::VisibilityLevel.const_get(project2_visibility, false))
- subgroup.update!(visibility_level: Gitlab::VisibilityLevel.const_get(subgroup_visibility, false))
- project1.update!(visibility_level: Gitlab::VisibilityLevel.const_get(group_visibility, false))
- group.update!(visibility_level: Gitlab::VisibilityLevel.const_get(group_visibility, false))
+ with_them do
+ before do
+ project2.update!(visibility_level: Gitlab::VisibilityLevel.const_get(project2_visibility, false))
+ subgroup.update!(visibility_level: Gitlab::VisibilityLevel.const_get(subgroup_visibility, false))
+ project1.update!(visibility_level: Gitlab::VisibilityLevel.const_get(group_visibility, false))
+ group.update!(visibility_level: Gitlab::VisibilityLevel.const_get(group_visibility, false))
+ end
+
+ it_behaves_like params[:shared_example_name]
+ end
end
- it_behaves_like params[:shared_example_name]
+ context 'with packages_finder_helper_deploy_token enabled' do
+ before do
+ expect(group).not_to receive(:all_projects)
+ end
+
+ it_behaves_like 'handling all conditions'
+ end
+
+ context 'with packages_finder_helper_deploy_token disabled' do
+ before do
+ stub_feature_flags(packages_finder_helper_deploy_token: false)
+ expect(group).to receive(:all_projects).and_call_original
+ end
+
+ it_behaves_like 'handling all conditions'
+ end
end
end
end
diff --git a/spec/finders/design_management/designs_finder_spec.rb b/spec/finders/design_management/designs_finder_spec.rb
index feb78a4bc4b..631f23b7312 100644
--- a/spec/finders/design_management/designs_finder_spec.rb
+++ b/spec/finders/design_management/designs_finder_spec.rb
@@ -11,6 +11,7 @@ RSpec.describe DesignManagement::DesignsFinder do
let_it_be(:design1) { create(:design, :with_file, issue: issue, versions_count: 1, relative_position: 3) }
let_it_be(:design2) { create(:design, :with_file, issue: issue, versions_count: 1, relative_position: 2) }
let_it_be(:design3) { create(:design, :with_file, issue: issue, versions_count: 1, relative_position: 1) }
+
let(:params) { {} }
subject(:designs) { described_class.new(issue, user, params).execute }
diff --git a/spec/finders/design_management/versions_finder_spec.rb b/spec/finders/design_management/versions_finder_spec.rb
index 6a56ccb10b8..0d606ef46f1 100644
--- a/spec/finders/design_management/versions_finder_spec.rb
+++ b/spec/finders/design_management/versions_finder_spec.rb
@@ -10,6 +10,7 @@ RSpec.describe DesignManagement::VersionsFinder do
let_it_be(:issue) { create(:issue, project: project) }
let_it_be(:design_1) { create(:design, :with_file, issue: issue, versions_count: 1) }
let_it_be(:design_2) { create(:design, :with_file, issue: issue, versions_count: 1) }
+
let(:version_1) { design_1.versions.first }
let(:version_2) { design_2.versions.first }
let(:design_or_collection) { issue.design_collection }
diff --git a/spec/finders/environments_by_deployments_finder_spec.rb b/spec/finders/environments_by_deployments_finder_spec.rb
new file mode 100644
index 00000000000..f5fcc4ef72a
--- /dev/null
+++ b/spec/finders/environments_by_deployments_finder_spec.rb
@@ -0,0 +1,127 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe EnvironmentsByDeploymentsFinder do
+ let(:project) { create(:project, :repository) }
+ let(:user) { project.creator }
+ let(:environment) { create(:environment, :available, project: project) }
+
+ before do
+ project.add_maintainer(user)
+ end
+
+ describe '#execute' do
+ context 'tagged deployment' do
+ let(:environment_two) { create(:environment, project: project) }
+ # Environments need to include commits, so rewind two commits to fit
+ let(:commit) { project.commit('HEAD~2') }
+
+ before do
+ create(:deployment, :success, environment: environment, ref: 'v1.0.0', tag: true, sha: project.commit.id)
+ create(:deployment, :success, environment: environment_two, ref: 'v1.1.0', tag: true, sha: project.commit('HEAD~1').id)
+ end
+
+ it 'returns environment when with_tags is set' do
+ expect(described_class.new(project, user, ref: 'master', commit: commit, with_tags: true).execute)
+ .to contain_exactly(environment, environment_two)
+ end
+
+ it 'does not return environment when no with_tags is set' do
+ expect(described_class.new(project, user, ref: 'master', commit: commit).execute)
+ .to be_empty
+ end
+
+ it 'does not return environment when commit is not part of deployment' do
+ expect(described_class.new(project, user, ref: 'master', commit: project.commit('feature')).execute)
+ .to be_empty
+ end
+
+ # We expect two Gitaly calls: FindCommit, CommitIsAncestor
+ # This tests to ensure we don't call one CommitIsAncestor per environment
+ it 'only calls Gitaly twice when multiple environments are present', :request_store do
+ expect do
+ result = described_class.new(project, user, ref: 'master', commit: commit, with_tags: true, find_latest: true).execute
+
+ expect(result).to contain_exactly(environment_two)
+ end.to change { Gitlab::GitalyClient.get_request_count }.by(2)
+ end
+ end
+
+ context 'branch deployment' do
+ before do
+ create(:deployment, :success, environment: environment, ref: 'master', sha: project.commit.id)
+ end
+
+ it 'returns environment when ref is set' do
+ expect(described_class.new(project, user, ref: 'master', commit: project.commit).execute)
+ .to contain_exactly(environment)
+ end
+
+ it 'does not environment when ref is different' do
+ expect(described_class.new(project, user, ref: 'feature', commit: project.commit).execute)
+ .to be_empty
+ end
+
+ it 'does not return environment when commit is not part of deployment' do
+ expect(described_class.new(project, user, ref: 'master', commit: project.commit('feature')).execute)
+ .to be_empty
+ end
+
+ it 'returns environment when commit constraint is not set' do
+ expect(described_class.new(project, user, ref: 'master').execute)
+ .to contain_exactly(environment)
+ end
+ end
+
+ context 'commit deployment' do
+ before do
+ create(:deployment, :success, environment: environment, ref: 'master', sha: project.commit.id)
+ end
+
+ it 'returns environment' do
+ expect(described_class.new(project, user, commit: project.commit).execute)
+ .to contain_exactly(environment)
+ end
+ end
+
+ context 'recently updated' do
+ context 'when last deployment to environment is the most recent one' do
+ before do
+ create(:deployment, :success, environment: environment, ref: 'feature')
+ end
+
+ it 'finds recently updated environment' do
+ expect(described_class.new(project, user, ref: 'feature', recently_updated: true).execute)
+ .to contain_exactly(environment)
+ end
+ end
+
+ context 'when last deployment to environment is not the most recent' do
+ before do
+ create(:deployment, :success, environment: environment, ref: 'feature')
+ create(:deployment, :success, environment: environment, ref: 'master')
+ end
+
+ it 'does not find environment' do
+ expect(described_class.new(project, user, ref: 'feature', recently_updated: true).execute)
+ .to be_empty
+ end
+ end
+
+ context 'when there are two environments that deploy to the same branch' do
+ let(:second_environment) { create(:environment, project: project) }
+
+ before do
+ create(:deployment, :success, environment: environment, ref: 'feature')
+ create(:deployment, :success, environment: second_environment, ref: 'feature')
+ end
+
+ it 'finds both environments' do
+ expect(described_class.new(project, user, ref: 'feature', recently_updated: true).execute)
+ .to contain_exactly(environment, second_environment)
+ end
+ end
+ end
+ end
+end
diff --git a/spec/finders/environments_finder_spec.rb b/spec/finders/environments_finder_spec.rb
index fd714ab9a8f..c2022331ad9 100644
--- a/spec/finders/environments_finder_spec.rb
+++ b/spec/finders/environments_finder_spec.rb
@@ -12,150 +12,36 @@ RSpec.describe EnvironmentsFinder do
end
describe '#execute' do
- context 'tagged deployment' do
- let(:environment_two) { create(:environment, project: project) }
- # Environments need to include commits, so rewind two commits to fit
- let(:commit) { project.commit('HEAD~2') }
-
- before do
- create(:deployment, :success, environment: environment, ref: 'v1.0.0', tag: true, sha: project.commit.id)
- create(:deployment, :success, environment: environment_two, ref: 'v1.1.0', tag: true, sha: project.commit('HEAD~1').id)
- end
-
- it 'returns environment when with_tags is set' do
- expect(described_class.new(project, user, ref: 'master', commit: commit, with_tags: true).execute)
- .to contain_exactly(environment, environment_two)
- end
-
- it 'does not return environment when no with_tags is set' do
- expect(described_class.new(project, user, ref: 'master', commit: commit).execute)
- .to be_empty
- end
-
- it 'does not return environment when commit is not part of deployment' do
- expect(described_class.new(project, user, ref: 'master', commit: project.commit('feature')).execute)
- .to be_empty
- end
-
- # We expect two Gitaly calls: FindCommit, CommitIsAncestor
- # This tests to ensure we don't call one CommitIsAncestor per environment
- it 'only calls Gitaly twice when multiple environments are present', :request_store do
- expect do
- result = described_class.new(project, user, ref: 'master', commit: commit, with_tags: true, find_latest: true).execute
-
- expect(result).to contain_exactly(environment_two)
- end.to change { Gitlab::GitalyClient.get_request_count }.by(2)
- end
- end
-
- context 'branch deployment' do
- before do
- create(:deployment, :success, environment: environment, ref: 'master', sha: project.commit.id)
- end
-
- it 'returns environment when ref is set' do
- expect(described_class.new(project, user, ref: 'master', commit: project.commit).execute)
- .to contain_exactly(environment)
- end
-
- it 'does not environment when ref is different' do
- expect(described_class.new(project, user, ref: 'feature', commit: project.commit).execute)
- .to be_empty
- end
-
- it 'does not return environment when commit is not part of deployment' do
- expect(described_class.new(project, user, ref: 'master', commit: project.commit('feature')).execute)
- .to be_empty
- end
-
- it 'returns environment when commit constraint is not set' do
- expect(described_class.new(project, user, ref: 'master').execute)
- .to contain_exactly(environment)
- end
- end
-
- context 'commit deployment' do
- before do
- create(:deployment, :success, environment: environment, ref: 'master', sha: project.commit.id)
- end
-
- it 'returns environment' do
- expect(described_class.new(project, user, commit: project.commit).execute)
- .to contain_exactly(environment)
- end
- end
-
- context 'recently updated' do
- context 'when last deployment to environment is the most recent one' do
- before do
- create(:deployment, :success, environment: environment, ref: 'feature')
- end
-
- it 'finds recently updated environment' do
- expect(described_class.new(project, user, ref: 'feature', recently_updated: true).execute)
- .to contain_exactly(environment)
- end
- end
-
- context 'when last deployment to environment is not the most recent' do
- before do
- create(:deployment, :success, environment: environment, ref: 'feature')
- create(:deployment, :success, environment: environment, ref: 'master')
- end
-
- it 'does not find environment' do
- expect(described_class.new(project, user, ref: 'feature', recently_updated: true).execute)
- .to be_empty
- end
- end
-
- context 'when there are two environments that deploy to the same branch' do
- let(:second_environment) { create(:environment, project: project) }
-
- before do
- create(:deployment, :success, environment: environment, ref: 'feature')
- create(:deployment, :success, environment: second_environment, ref: 'feature')
- end
-
- it 'finds both environments' do
- expect(described_class.new(project, user, ref: 'feature', recently_updated: true).execute)
- .to contain_exactly(environment, second_environment)
- end
- end
- end
- end
-
- describe '#find' do
context 'with states parameter' do
let(:stopped_environment) { create(:environment, :stopped, project: project) }
it 'returns environments with the requested state' do
- result = described_class.new(project, user, states: 'available').find
+ result = described_class.new(project, user, states: 'available').execute
expect(result).to contain_exactly(environment)
end
it 'returns environments with any of the requested states' do
- result = described_class.new(project, user, states: %w(available stopped)).find
+ result = described_class.new(project, user, states: %w(available stopped)).execute
expect(result).to contain_exactly(environment, stopped_environment)
end
it 'raises exception when requested state is invalid' do
- expect { described_class.new(project, user, states: %w(invalid stopped)).find }.to(
+ expect { described_class.new(project, user, states: %w(invalid stopped)).execute }.to(
raise_error(described_class::InvalidStatesError, 'Requested states are invalid')
)
end
context 'works with symbols' do
it 'returns environments with the requested state' do
- result = described_class.new(project, user, states: :available).find
+ result = described_class.new(project, user, states: :available).execute
expect(result).to contain_exactly(environment)
end
it 'returns environments with any of the requested states' do
- result = described_class.new(project, user, states: [:available, :stopped]).find
+ result = described_class.new(project, user, states: [:available, :stopped]).execute
expect(result).to contain_exactly(environment, stopped_environment)
end
@@ -167,7 +53,7 @@ RSpec.describe EnvironmentsFinder do
let(:environment3) { create(:environment, :available, name: 'test3', project: project) }
it 'searches environments by name and state' do
- result = described_class.new(project, user, search: 'test', states: :available).find
+ result = described_class.new(project, user, search: 'test', states: :available).execute
expect(result).to contain_exactly(environment3)
end
diff --git a/spec/finders/group_members_finder_spec.rb b/spec/finders/group_members_finder_spec.rb
index a87a05d4408..3238f6744f7 100644
--- a/spec/finders/group_members_finder_spec.rb
+++ b/spec/finders/group_members_finder_spec.rb
@@ -3,174 +3,180 @@
require 'spec_helper'
RSpec.describe GroupMembersFinder, '#execute' do
- let(:group) { create(:group) }
- let(:nested_group) { create(:group, parent: group) }
- let(:deeper_nested_group) { create(:group, parent: nested_group) }
- let(:user1) { create(:user) }
- let(:user2) { create(:user) }
- let(:user3) { create(:user) }
- let(:user4) { create(:user) }
- let(:user5) { create(:user, :two_factor_via_otp) }
-
- it 'returns members for top-level group' do
- member1 = group.add_maintainer(user1)
- member2 = group.add_maintainer(user2)
- member3 = group.add_maintainer(user3)
- create(:group_member, :minimal_access, user: create(:user), source: group)
-
- result = described_class.new(group).execute
-
- expect(result.to_a).to match_array([member3, member2, member1])
+ let(:group) { create(:group) }
+ let(:sub_group) { create(:group, parent: group) }
+ let(:sub_sub_group) { create(:group, parent: sub_group) }
+ let(:user1) { create(:user) }
+ let(:user2) { create(:user) }
+ let(:user3) { create(:user) }
+ let(:user4) { create(:user) }
+ let(:user5) { create(:user, :two_factor_via_otp) }
+
+ let(:groups) do
+ {
+ group: group,
+ sub_group: sub_group,
+ sub_sub_group: sub_sub_group
+ }
end
- it 'returns members & inherited members for nested group by default' do
- group.add_developer(user2)
- nested_group.request_access(user4)
- member1 = group.add_maintainer(user1)
- member3 = nested_group.add_maintainer(user2)
- member4 = nested_group.add_maintainer(user3)
-
- result = described_class.new(nested_group).execute
-
- expect(result.to_a).to match_array([member1, member3, member4])
+ context 'relations' do
+ let!(:members) do
+ {
+ user1_sub_sub_group: create(:group_member, :maintainer, group: sub_sub_group, user: user1),
+ user1_sub_group: create(:group_member, :developer, group: sub_group, user: user1),
+ user1_group: create(:group_member, :reporter, group: group, user: user1),
+ user2_sub_sub_group: create(:group_member, :reporter, group: sub_sub_group, user: user2),
+ user2_sub_group: create(:group_member, :developer, group: sub_group, user: user2),
+ user2_group: create(:group_member, :maintainer, group: group, user: user2),
+ user3_sub_sub_group: create(:group_member, :developer, group: sub_sub_group, user: user3, expires_at: 1.day.from_now),
+ user3_sub_group: create(:group_member, :developer, group: sub_group, user: user3, expires_at: 2.days.from_now),
+ user3_group: create(:group_member, :reporter, group: group, user: user3),
+ user4_sub_sub_group: create(:group_member, :reporter, group: sub_sub_group, user: user4),
+ user4_sub_group: create(:group_member, :developer, group: sub_group, user: user4, expires_at: 1.day.from_now),
+ user4_group: create(:group_member, :developer, group: group, user: user4, expires_at: 2.days.from_now)
+ }
+ end
+
+ using RSpec::Parameterized::TableSyntax
+
+ where(:subject_relations, :subject_group, :expected_members) do
+ nil | :group | [:user1_group, :user2_group, :user3_group, :user4_group]
+ [:direct] | :group | [:user1_group, :user2_group, :user3_group, :user4_group]
+ [:inherited] | :group | []
+ [:descendants] | :group | [:user1_sub_sub_group, :user2_sub_group, :user3_sub_group, :user4_sub_group]
+ [:direct, :inherited] | :group | [:user1_group, :user2_group, :user3_group, :user4_group]
+ [:direct, :descendants] | :group | [:user1_sub_sub_group, :user2_group, :user3_sub_group, :user4_group]
+ [:descendants, :inherited] | :group | [:user1_sub_sub_group, :user2_sub_group, :user3_sub_group, :user4_sub_group]
+ [:direct, :descendants, :inherited] | :group | [:user1_sub_sub_group, :user2_group, :user3_sub_group, :user4_group]
+ nil | :sub_group | [:user1_sub_group, :user2_group, :user3_sub_group, :user4_group]
+ [:direct] | :sub_group | [:user1_sub_group, :user2_sub_group, :user3_sub_group, :user4_sub_group]
+ [:inherited] | :sub_group | [:user1_group, :user2_group, :user3_group, :user4_group]
+ [:descendants] | :sub_group | [:user1_sub_sub_group, :user2_sub_sub_group, :user3_sub_sub_group, :user4_sub_sub_group]
+ [:direct, :inherited] | :sub_group | [:user1_sub_group, :user2_group, :user3_sub_group, :user4_group]
+ [:direct, :descendants] | :sub_group | [:user1_sub_sub_group, :user2_sub_group, :user3_sub_group, :user4_sub_group]
+ [:descendants, :inherited] | :sub_group | [:user1_sub_sub_group, :user2_group, :user3_sub_sub_group, :user4_group]
+ [:direct, :descendants, :inherited] | :sub_group | [:user1_sub_sub_group, :user2_group, :user3_sub_group, :user4_group]
+ nil | :sub_sub_group | [:user1_sub_sub_group, :user2_group, :user3_sub_group, :user4_group]
+ [:direct] | :sub_sub_group | [:user1_sub_sub_group, :user2_sub_sub_group, :user3_sub_sub_group, :user4_sub_sub_group]
+ [:inherited] | :sub_sub_group | [:user1_sub_group, :user2_group, :user3_sub_group, :user4_group]
+ [:descendants] | :sub_sub_group | []
+ [:direct, :inherited] | :sub_sub_group | [:user1_sub_sub_group, :user2_group, :user3_sub_group, :user4_group]
+ [:direct, :descendants] | :sub_sub_group | [:user1_sub_sub_group, :user2_sub_sub_group, :user3_sub_sub_group, :user4_sub_sub_group]
+ [:descendants, :inherited] | :sub_sub_group | [:user1_sub_group, :user2_group, :user3_sub_group, :user4_group]
+ [:direct, :descendants, :inherited] | :sub_sub_group | [:user1_sub_sub_group, :user2_group, :user3_sub_group, :user4_group]
+ end
+
+ with_them do
+ it 'returns correct members' do
+ result = if subject_relations
+ described_class.new(groups[subject_group]).execute(include_relations: subject_relations)
+ else
+ described_class.new(groups[subject_group]).execute
+ end
+
+ expect(result.to_a).to match_array(expected_members.map { |name| members[name] })
+ end
+ end
end
- it 'does not return inherited members for nested group if requested' do
- group.add_maintainer(user1)
- group.add_developer(user2)
- member2 = nested_group.add_maintainer(user2)
- member3 = nested_group.add_maintainer(user3)
+ context 'search' do
+ it 'returns searched members if requested' do
+ group.add_maintainer(user2)
+ group.add_developer(user3)
+ member = group.add_maintainer(user1)
- result = described_class.new(nested_group).execute(include_relations: [:direct])
+ result = described_class.new(group, params: { search: user1.name }).execute
- expect(result.to_a).to match_array([member2, member3])
- end
+ expect(result.to_a).to match_array([member])
+ end
- it 'returns only inherited members for nested group if requested' do
- group.add_developer(user2)
- nested_group.request_access(user4)
- member1 = group.add_maintainer(user1)
- nested_group.add_maintainer(user2)
- nested_group.add_maintainer(user3)
+ it 'returns nothing if search only in inherited relation' do
+ group.add_maintainer(user2)
+ group.add_developer(user3)
+ group.add_maintainer(user1)
- result = described_class.new(nested_group).execute(include_relations: [:inherited])
+ result = described_class.new(group, params: { search: user1.name }).execute(include_relations: [:inherited])
- expect(result.to_a).to match_array([member1])
- end
+ expect(result.to_a).to match_array([])
+ end
- it 'does not return nil if `inherited only` relation is requested on root group' do
- group.add_developer(user2)
+ it 'returns searched member only from sub_group if search only in inherited relation' do
+ group.add_maintainer(user2)
+ group.add_developer(user3)
+ sub_group.add_maintainer(create(:user, name: user1.name))
+ member = group.add_maintainer(user1)
- result = described_class.new(group).execute(include_relations: [:inherited])
+ result = described_class.new(sub_group, params: { search: member.user.name }).execute(include_relations: [:inherited])
- expect(result).not_to be_nil
+ expect(result.to_a).to contain_exactly(member)
+ end
end
- it 'returns members for descendant groups if requested' do
- member1 = group.add_maintainer(user2)
- member2 = group.add_maintainer(user1)
- nested_group.add_maintainer(user2)
- member3 = nested_group.add_maintainer(user3)
- member4 = nested_group.add_maintainer(user4)
+ context 'filter by two-factor' do
+ it 'returns members with two-factor auth if requested by owner' do
+ group.add_owner(user2)
+ group.add_maintainer(user1)
+ member = group.add_maintainer(user5)
- result = described_class.new(group).execute(include_relations: [:direct, :descendants])
+ result = described_class.new(group, user2, params: { two_factor: 'enabled' }).execute
- expect(result.to_a).to match_array([member1, member2, member3, member4])
- end
+ expect(result.to_a).to contain_exactly(member)
+ end
- it 'returns searched members if requested' do
- group.add_maintainer(user2)
- group.add_developer(user3)
- member = group.add_maintainer(user1)
+ it 'returns members without two-factor auth if requested by owner' do
+ member1 = group.add_owner(user2)
+ member2 = group.add_maintainer(user1)
+ member_with_2fa = group.add_maintainer(user5)
- result = described_class.new(group, params: { search: user1.name }).execute
+ result = described_class.new(group, user2, params: { two_factor: 'disabled' }).execute
- expect(result.to_a).to match_array([member])
- end
+ expect(result.to_a).not_to include(member_with_2fa)
+ expect(result.to_a).to match_array([member1, member2])
+ end
- it 'returns nothing if search only in inherited relation' do
- group.add_maintainer(user2)
- group.add_developer(user3)
- group.add_maintainer(user1)
+ it 'returns direct members with two-factor auth if requested by owner' do
+ group.add_owner(user1)
+ group.add_maintainer(user2)
+ sub_group.add_maintainer(user3)
+ member_with_2fa = sub_group.add_maintainer(user5)
- result = described_class.new(group, params: { search: user1.name }).execute(include_relations: [:inherited])
+ result = described_class.new(sub_group, user1, params: { two_factor: 'enabled' }).execute(include_relations: [:direct])
- expect(result.to_a).to match_array([])
- end
+ expect(result.to_a).to match_array([member_with_2fa])
+ end
- it 'returns searched member only from nested_group if search only in inherited relation' do
- group.add_maintainer(user2)
- group.add_developer(user3)
- nested_group.add_maintainer(create(:user, name: user1.name))
- member = group.add_maintainer(user1)
+ it 'returns inherited members with two-factor auth if requested by owner' do
+ group.add_owner(user1)
+ member_with_2fa = group.add_maintainer(user5)
+ sub_group.add_maintainer(user2)
+ sub_group.add_maintainer(user3)
- result = described_class.new(nested_group, params: { search: member.user.name }).execute(include_relations: [:inherited])
+ result = described_class.new(sub_group, user1, params: { two_factor: 'enabled' }).execute(include_relations: [:inherited])
- expect(result.to_a).to contain_exactly(member)
- end
-
- it 'returns members with two-factor auth if requested by owner' do
- group.add_owner(user2)
- group.add_maintainer(user1)
- member = group.add_maintainer(user5)
-
- result = described_class.new(group, user2, params: { two_factor: 'enabled' }).execute
+ expect(result.to_a).to match_array([member_with_2fa])
+ end
- expect(result.to_a).to contain_exactly(member)
- end
-
- it 'returns members without two-factor auth if requested by owner' do
- member1 = group.add_owner(user2)
- member2 = group.add_maintainer(user1)
- member_with_2fa = group.add_maintainer(user5)
+ it 'returns direct members without two-factor auth if requested by owner' do
+ group.add_owner(user1)
+ group.add_maintainer(user2)
+ member3 = sub_group.add_maintainer(user3)
+ sub_group.add_maintainer(user5)
- result = described_class.new(group, user2, params: { two_factor: 'disabled' }).execute
+ result = described_class.new(sub_group, user1, params: { two_factor: 'disabled' }).execute(include_relations: [:direct])
- expect(result.to_a).not_to include(member_with_2fa)
- expect(result.to_a).to match_array([member1, member2])
- end
-
- it 'returns direct members with two-factor auth if requested by owner' do
- group.add_owner(user1)
- group.add_maintainer(user2)
- nested_group.add_maintainer(user3)
- member_with_2fa = nested_group.add_maintainer(user5)
-
- result = described_class.new(nested_group, user1, params: { two_factor: 'enabled' }).execute(include_relations: [:direct])
-
- expect(result.to_a).to match_array([member_with_2fa])
- end
-
- it 'returns inherited members with two-factor auth if requested by owner' do
- group.add_owner(user1)
- member_with_2fa = group.add_maintainer(user5)
- nested_group.add_maintainer(user2)
- nested_group.add_maintainer(user3)
-
- result = described_class.new(nested_group, user1, params: { two_factor: 'enabled' }).execute(include_relations: [:inherited])
-
- expect(result.to_a).to match_array([member_with_2fa])
- end
-
- it 'returns direct members without two-factor auth if requested by owner' do
- group.add_owner(user1)
- group.add_maintainer(user2)
- member3 = nested_group.add_maintainer(user3)
- nested_group.add_maintainer(user5)
-
- result = described_class.new(nested_group, user1, params: { two_factor: 'disabled' }).execute(include_relations: [:direct])
-
- expect(result.to_a).to match_array([member3])
- end
+ expect(result.to_a).to match_array([member3])
+ end
- it 'returns inherited members without two-factor auth if requested by owner' do
- member1 = group.add_owner(user1)
- group.add_maintainer(user5)
- nested_group.add_maintainer(user2)
- nested_group.add_maintainer(user3)
+ it 'returns inherited members without two-factor auth if requested by owner' do
+ member1 = group.add_owner(user1)
+ group.add_maintainer(user5)
+ sub_group.add_maintainer(user2)
+ sub_group.add_maintainer(user3)
- result = described_class.new(nested_group, user1, params: { two_factor: 'disabled' }).execute(include_relations: [:inherited])
+ result = described_class.new(sub_group, user1, params: { two_factor: 'disabled' }).execute(include_relations: [:inherited])
- expect(result.to_a).to match_array([member1])
+ expect(result.to_a).to match_array([member1])
+ end
end
end
diff --git a/spec/finders/issues_finder_spec.rb b/spec/finders/issues_finder_spec.rb
index b794ab626bf..a2aac857bf5 100644
--- a/spec/finders/issues_finder_spec.rb
+++ b/spec/finders/issues_finder_spec.rb
@@ -49,6 +49,13 @@ RSpec.describe IssuesFinder do
let(:expected_issuables) { [issue3, issue4] }
end
+ context 'when assignee_id does not exist' do
+ it_behaves_like 'assignee NOT ID filter' do
+ let(:params) { { not: { assignee_id: -100 } } }
+ let(:expected_issuables) { [issue1, issue2, issue3, issue4, issue5] }
+ end
+ end
+
context 'filter by username' do
let_it_be(:user3) { create(:user) }
@@ -71,6 +78,17 @@ RSpec.describe IssuesFinder do
let(:params) { { not: { assignee_username: [user.username, user2.username] } } }
let(:expected_issuables) { [issue3, issue4] }
end
+
+ context 'when assignee_username does not exist' do
+ it_behaves_like 'assignee NOT username filter' do
+ before do
+ issue2.assignees = [user2]
+ end
+
+ let(:params) { { not: { assignee_username: 'non_existent_username' } } }
+ let(:expected_issuables) { [issue1, issue2, issue3, issue4, issue5] }
+ end
+ end
end
it_behaves_like 'no assignee filter' do
diff --git a/spec/finders/merge_requests/oldest_per_commit_finder_spec.rb b/spec/finders/merge_requests/oldest_per_commit_finder_spec.rb
index 4724a8eb5c7..6dffaff294d 100644
--- a/spec/finders/merge_requests/oldest_per_commit_finder_spec.rb
+++ b/spec/finders/merge_requests/oldest_per_commit_finder_spec.rb
@@ -77,6 +77,45 @@ RSpec.describe MergeRequests::OldestPerCommitFinder do
expect(described_class.new(project).execute(commits)).to eq(sha => mr)
end
+ it 'includes a merge request that was squashed into the target branch' do
+ project = create(:project)
+ sha = Digest::SHA1.hexdigest('foo')
+ mr = create(
+ :merge_request,
+ :merged,
+ target_project: project,
+ squash_commit_sha: sha
+ )
+
+ commits = [double(:commit, id: sha)]
+
+ expect(MergeRequestDiffCommit)
+ .not_to receive(:oldest_merge_request_id_per_commit)
+
+ expect(described_class.new(project).execute(commits)).to eq(sha => mr)
+ end
+
+ it 'includes a merge request for both a squash and merge commit' do
+ project = create(:project)
+ sha1 = Digest::SHA1.hexdigest('foo')
+ sha2 = Digest::SHA1.hexdigest('bar')
+ mr = create(
+ :merge_request,
+ :merged,
+ target_project: project,
+ squash_commit_sha: sha1,
+ merge_commit_sha: sha2
+ )
+
+ commits = [double(:commit1, id: sha1), double(:commit2, id: sha2)]
+
+ expect(MergeRequestDiffCommit)
+ .not_to receive(:oldest_merge_request_id_per_commit)
+
+ expect(described_class.new(project).execute(commits))
+ .to eq(sha1 => mr, sha2 => mr)
+ end
+
it 'includes the oldest merge request when a merge commit is present in a newer merge request' do
project = create(:project)
sha = Digest::SHA1.hexdigest('foo')
diff --git a/spec/finders/merge_requests_finder_spec.rb b/spec/finders/merge_requests_finder_spec.rb
index b3000498bb6..597d22801ca 100644
--- a/spec/finders/merge_requests_finder_spec.rb
+++ b/spec/finders/merge_requests_finder_spec.rb
@@ -156,6 +156,18 @@ RSpec.describe MergeRequestsFinder do
it { is_expected.to eq([merge_request2]) }
end
+
+ context 'when project_id is given' do
+ subject(:query) { described_class.new(user, merged_after: 15.days.ago, merged_before: 6.days.ago, project_id: merge_request2.project).execute }
+
+ it { is_expected.to eq([merge_request2]) }
+
+ it 'queries merge_request_metrics.target_project_id table' do
+ expect(query.to_sql).to include(%{"merge_request_metrics"."target_project_id" = #{merge_request2.target_project_id}})
+
+ expect(query.to_sql).not_to include(%{"merge_requests"."target_project_id"})
+ end
+ end
end
context 'filtering by group' do
diff --git a/spec/finders/metrics/dashboards/annotations_finder_spec.rb b/spec/finders/metrics/dashboards/annotations_finder_spec.rb
index 223fd2c047c..7c5932dde1e 100644
--- a/spec/finders/metrics/dashboards/annotations_finder_spec.rb
+++ b/spec/finders/metrics/dashboards/annotations_finder_spec.rb
@@ -7,6 +7,7 @@ RSpec.describe Metrics::Dashboards::AnnotationsFinder do
subject(:annotations) { described_class.new(dashboard: dashboard, params: params).execute }
let_it_be(:current_user) { create(:user) }
+
let(:path) { 'config/prometheus/common_metrics.yml' }
let(:params) { {} }
let(:environment) { create(:environment) }
diff --git a/spec/finders/metrics/users_starred_dashboards_finder_spec.rb b/spec/finders/metrics/users_starred_dashboards_finder_spec.rb
index 61dadb5239c..4136cf1123a 100644
--- a/spec/finders/metrics/users_starred_dashboards_finder_spec.rb
+++ b/spec/finders/metrics/users_starred_dashboards_finder_spec.rb
@@ -7,6 +7,7 @@ RSpec.describe Metrics::UsersStarredDashboardsFinder do
subject(:starred_dashboards) { described_class.new(user: user, project: project, params: params).execute }
let_it_be(:user) { create(:user) }
+
let(:project) { create(:project) }
let(:dashboard_path) { 'config/prometheus/common_metrics.yml' }
let(:params) { {} }
diff --git a/spec/finders/notes_finder_spec.rb b/spec/finders/notes_finder_spec.rb
index 868b126dc28..11de19cfdbc 100644
--- a/spec/finders/notes_finder_spec.rb
+++ b/spec/finders/notes_finder_spec.rb
@@ -213,6 +213,24 @@ RSpec.describe NotesFinder do
expect { described_class.new(user, params).execute }.to raise_error(RuntimeError)
end
end
+
+ describe 'sorting' do
+ it 'allows sorting' do
+ params = { project: project, sort: 'id_desc' }
+
+ expect(Note).to receive(:order_id_desc).once
+
+ described_class.new(user, params).execute
+ end
+
+ it 'defaults to sort by .fresh' do
+ params = { project: project }
+
+ expect(Note).to receive(:fresh).once
+
+ described_class.new(user, params).execute
+ end
+ end
end
describe '.search' do
diff --git a/spec/finders/packages/go/package_finder_spec.rb b/spec/finders/packages/go/package_finder_spec.rb
new file mode 100644
index 00000000000..b6fad1e7061
--- /dev/null
+++ b/spec/finders/packages/go/package_finder_spec.rb
@@ -0,0 +1,71 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe Packages::Go::PackageFinder do
+ include_context 'basic Go module'
+
+ let_it_be(:mod) { create :go_module, project: project }
+ let_it_be(:version) { create :go_module_version, :tagged, mod: mod, name: 'v1.0.1' }
+ let_it_be(:package) { create :golang_package, project: project, name: mod.name, version: 'v1.0.1' }
+
+ let(:finder) { described_class.new(project, mod_name, version_name) }
+
+ describe '#exists?' do
+ subject { finder.exists? }
+
+ context 'with a valid name and version' do
+ let(:mod_name) { mod.name }
+ let(:version_name) { version.name }
+
+ it 'executes SELECT 1' do
+ expect { subject }.to exceed_query_limit(0).for_query(/^SELECT 1/)
+ end
+
+ it { is_expected.to eq(true) }
+ end
+
+ context 'with an invalid name' do
+ let(:mod_name) { 'foo/bar' }
+ let(:version_name) { 'baz' }
+
+ it { is_expected.to eq(false) }
+ end
+
+ context 'with an invalid version' do
+ let(:mod_name) { mod.name }
+ let(:version_name) { 'baz' }
+
+ it { is_expected.to eq(false) }
+ end
+ end
+
+ describe '#execute' do
+ subject { finder.execute }
+
+ context 'with a valid name and version' do
+ let(:mod_name) { mod.name }
+ let(:version_name) { version.name }
+
+ it 'executes a single query' do
+ expect { subject }.not_to exceed_query_limit(1)
+ end
+
+ it { is_expected.to eq(package) }
+ end
+
+ context 'with an invalid name' do
+ let(:mod_name) { 'foo/bar' }
+ let(:version_name) { 'baz' }
+
+ it { is_expected.to eq(nil) }
+ end
+
+ context 'with an invalid version' do
+ let(:mod_name) { mod.name }
+ let(:version_name) { 'baz' }
+
+ it { is_expected.to eq(nil) }
+ end
+ end
+end
diff --git a/spec/finders/packages/maven/package_finder_spec.rb b/spec/finders/packages/maven/package_finder_spec.rb
index b955c331f28..ca144292501 100644
--- a/spec/finders/packages/maven/package_finder_spec.rb
+++ b/spec/finders/packages/maven/package_finder_spec.rb
@@ -11,71 +11,144 @@ RSpec.describe ::Packages::Maven::PackageFinder do
let(:param_path) { nil }
let(:param_project) { nil }
let(:param_group) { nil }
- let(:finder) { described_class.new(param_path, user, project: param_project, group: param_group) }
+ let(:param_order_by_package_file) { false }
+ let(:finder) { described_class.new(param_path, user, project: param_project, group: param_group, order_by_package_file: param_order_by_package_file) }
before do
group.add_developer(user)
end
- describe '#execute!' do
- subject { finder.execute! }
+ shared_examples 'Packages::Maven::PackageFinder examples' do
+ describe '#execute!' do
+ subject { finder.execute! }
- shared_examples 'handling valid and invalid paths' do
- context 'with a valid path' do
- let(:param_path) { package.maven_metadatum.path }
+ shared_examples 'handling valid and invalid paths' do
+ context 'with a valid path' do
+ let(:param_path) { package.maven_metadatum.path }
- it { is_expected.to eq(package) }
+ it { is_expected.to eq(package) }
+ end
+
+ context 'with an invalid path' do
+ let(:param_path) { 'com/example/my-app/1.0-SNAPSHOT' }
+
+ it 'raises an error' do
+ expect { subject }.to raise_error(ActiveRecord::RecordNotFound)
+ end
+ end
end
- context 'with an invalid path' do
- let(:param_path) { 'com/example/my-app/1.0-SNAPSHOT' }
+ context 'within the project' do
+ let(:param_project) { project }
+ it_behaves_like 'handling valid and invalid paths'
+ end
+
+ context 'within a group' do
+ let(:param_group) { group }
+
+ context 'with maven_packages_group_level_improvements enabled' do
+ before do
+ stub_feature_flags(maven_packages_group_level_improvements: true)
+ expect(finder).to receive(:packages_visible_to_user).with(user, within_group: group).and_call_original
+ end
+
+ it_behaves_like 'handling valid and invalid paths'
+ end
+
+ context 'with maven_packages_group_level_improvements disabled' do
+ before do
+ stub_feature_flags(maven_packages_group_level_improvements: false)
+ expect(finder).not_to receive(:packages_visible_to_user)
+ end
+
+ it_behaves_like 'handling valid and invalid paths'
+ end
+ end
+
+ context 'across all projects' do
it 'raises an error' do
expect { subject }.to raise_error(ActiveRecord::RecordNotFound)
end
end
- end
- context 'within the project' do
- let(:param_project) { project }
+ context 'versionless maven-metadata.xml package' do
+ let_it_be(:sub_group1) { create(:group, parent: group) }
+ let_it_be(:sub_group2) { create(:group, parent: group) }
+ let_it_be(:project1) { create(:project, group: sub_group1) }
+ let_it_be(:project2) { create(:project, group: sub_group2) }
+ let_it_be(:project3) { create(:project, group: sub_group1) }
+ let_it_be(:package_name) { 'foo' }
+ let_it_be(:package1) { create(:maven_package, project: project1, name: package_name, version: nil) }
+ let_it_be(:package2) { create(:maven_package, project: project2, name: package_name, version: nil) }
+ let_it_be(:package3) { create(:maven_package, project: project3, name: package_name, version: nil) }
+
+ let(:param_group) { group }
+ let(:param_path) { package_name }
+
+ before do
+ sub_group1.add_developer(user)
+ sub_group2.add_developer(user)
+ # the package with the most recently published file should be returned
+ create(:package_file, :xml, package: package2)
+ end
- it_behaves_like 'handling valid and invalid paths'
- end
+ context 'with maven_packages_group_level_improvements enabled' do
+ before do
+ stub_feature_flags(maven_packages_group_level_improvements: true)
+ expect(finder).not_to receive(:versionless_package?)
+ end
- context 'within a group' do
- let(:param_group) { group }
+ context 'without order by package file' do
+ it { is_expected.to eq(package3) }
+ end
- it_behaves_like 'handling valid and invalid paths'
- end
+ context 'with order by package file' do
+ let(:param_order_by_package_file) { true }
+
+ it { is_expected.to eq(package2) }
+ end
+ end
+
+ context 'with maven_packages_group_level_improvements disabled' do
+ before do
+ stub_feature_flags(maven_packages_group_level_improvements: false)
+ expect(finder).to receive(:versionless_package?).and_call_original
+ end
- context 'across all projects' do
- it 'raises an error' do
- expect { subject }.to raise_error(ActiveRecord::RecordNotFound)
+ context 'without order by package file' do
+ it { is_expected.to eq(package2) }
+ end
+
+ context 'with order by package file' do
+ let(:param_order_by_package_file) { true }
+
+ it { is_expected.to eq(package2) }
+ end
+ end
end
end
+ end
+
+ context 'when the maven_metadata_by_path_with_optimization_fence feature flag is off' do
+ before do
+ stub_feature_flags(maven_metadata_by_path_with_optimization_fence: false)
+ end
- context 'versionless maven-metadata.xml package' do
- let_it_be(:sub_group1) { create(:group, parent: group) }
- let_it_be(:sub_group2) { create(:group, parent: group) }
- let_it_be(:project1) { create(:project, group: sub_group1) }
- let_it_be(:project2) { create(:project, group: sub_group2) }
- let_it_be(:project3) { create(:project, group: sub_group1) }
- let_it_be(:package_name) { 'foo' }
- let_it_be(:package1) { create(:maven_package, project: project1, name: package_name, version: nil) }
- let_it_be(:package2) { create(:maven_package, project: project2, name: package_name, version: nil) }
- let_it_be(:package3) { create(:maven_package, project: project3, name: package_name, version: nil) }
-
- let(:param_group) { group }
- let(:param_path) { package_name }
-
- before do
- sub_group1.add_developer(user)
- sub_group2.add_developer(user)
- # the package with the most recently published file should be returned
- create(:package_file, :xml, package: package2)
- end
+ it_behaves_like 'Packages::Maven::PackageFinder examples'
+ end
+
+ context 'when the maven_metadata_by_path_with_optimization_fence feature flag is on' do
+ before do
+ stub_feature_flags(maven_metadata_by_path_with_optimization_fence: true)
+ end
+
+ it_behaves_like 'Packages::Maven::PackageFinder examples'
+
+ it 'uses CTE in the query' do
+ sql = described_class.new('some_path', user, group: group).send(:packages_with_path).to_sql
- it { is_expected.to eq(package2) }
+ expect(sql).to include('WITH "maven_metadata_by_path" AS')
end
end
end
diff --git a/spec/finders/pending_todos_finder_spec.rb b/spec/finders/pending_todos_finder_spec.rb
index 10d3c2905be..b17915f0d59 100644
--- a/spec/finders/pending_todos_finder_spec.rb
+++ b/spec/finders/pending_todos_finder_spec.rb
@@ -4,13 +4,15 @@ require 'spec_helper'
RSpec.describe PendingTodosFinder do
let(:user) { create(:user) }
+ let(:user2) { create(:user) }
+ let(:users) { [user, user2] }
describe '#execute' do
it 'returns only pending todos' do
create(:todo, :done, user: user)
todo = create(:todo, :pending, user: user)
- todos = described_class.new(user).execute
+ todos = described_class.new(users).execute
expect(todos).to eq([todo])
end
@@ -22,7 +24,7 @@ RSpec.describe PendingTodosFinder do
create(:todo, :pending, user: user, project: project2)
todo = create(:todo, :pending, user: user, project: project1)
- todos = described_class.new(user, project_id: project1.id).execute
+ todos = described_class.new(users, project_id: project1.id).execute
expect(todos).to eq([todo])
end
@@ -34,7 +36,7 @@ RSpec.describe PendingTodosFinder do
create(:todo, :pending, user: user, target: note)
- todos = described_class.new(user, target_id: issue.id).execute
+ todos = described_class.new(users, target_id: issue.id).execute
expect(todos).to eq([todo])
end
@@ -46,7 +48,7 @@ RSpec.describe PendingTodosFinder do
create(:todo, :pending, user: user, target: note)
- todos = described_class.new(user, target_type: issue.class.name).execute
+ todos = described_class.new(users, target_type: issue.class.name).execute
expect(todos).to eq([todo])
end
@@ -55,7 +57,7 @@ RSpec.describe PendingTodosFinder do
create(:todo, :pending, user: user, commit_id: '456')
todo = create(:todo, :pending, user: user, commit_id: '123')
- todos = described_class.new(user, commit_id: '123').execute
+ todos = described_class.new(users, commit_id: '123').execute
expect(todos).to eq([todo])
end
diff --git a/spec/finders/projects_finder_spec.rb b/spec/finders/projects_finder_spec.rb
index 4d9ff30daba..a178261e899 100644
--- a/spec/finders/projects_finder_spec.rb
+++ b/spec/finders/projects_finder_spec.rb
@@ -129,6 +129,12 @@ RSpec.describe ProjectsFinder do
it { is_expected.to eq([public_project]) }
end
+
+ context 'as string' do
+ let(:params) { { visibility_level: Gitlab::VisibilityLevel::INTERNAL.to_s } }
+
+ it { is_expected.to eq([internal_project]) }
+ end
end
describe 'filter by tags' do
diff --git a/spec/finders/repositories/branch_names_finder_spec.rb b/spec/finders/repositories/branch_names_finder_spec.rb
new file mode 100644
index 00000000000..4d8bfcc0f20
--- /dev/null
+++ b/spec/finders/repositories/branch_names_finder_spec.rb
@@ -0,0 +1,25 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe Repositories::BranchNamesFinder do
+ let(:project) { create(:project, :repository) }
+
+ let(:branch_names_finder) { described_class.new(project.repository, search: 'conflict-*') }
+
+ describe '#execute' do
+ subject(:execute) { branch_names_finder.execute }
+
+ it 'filters branch names' do
+ expect(execute).to contain_exactly(
+ 'conflict-binary-file',
+ 'conflict-resolvable',
+ 'conflict-contains-conflict-markers',
+ 'conflict-missing-side',
+ 'conflict-start',
+ 'conflict-non-utf8',
+ 'conflict-too-large'
+ )
+ end
+ end
+end
diff --git a/spec/finders/repositories/previous_tag_finder_spec.rb b/spec/finders/repositories/changelog_tag_finder_spec.rb
index b332dd158d1..cd79beb3e9e 100644
--- a/spec/finders/repositories/previous_tag_finder_spec.rb
+++ b/spec/finders/repositories/changelog_tag_finder_spec.rb
@@ -2,11 +2,18 @@
require 'spec_helper'
-RSpec.describe Repositories::PreviousTagFinder do
+RSpec.describe Repositories::ChangelogTagFinder do
let(:project) { build_stubbed(:project) }
let(:finder) { described_class.new(project) }
describe '#execute' do
+ context 'when the regular expression is invalid' do
+ it 'raises Gitlab::Changelog::Error' do
+ expect { described_class.new(project, regex: 'foo+*').execute('1.2.3') }
+ .to raise_error(Gitlab::Changelog::Error)
+ end
+ end
+
context 'when there is a previous tag' do
it 'returns the previous tag' do
tag1 = double(:tag1, name: 'v1.0.0')
@@ -15,10 +22,11 @@ RSpec.describe Repositories::PreviousTagFinder do
tag4 = double(:tag4, name: '0.9.0')
tag5 = double(:tag5, name: 'v0.8.0-pre1')
tag6 = double(:tag6, name: 'v0.7.0')
+ tag7 = double(:tag7, name: '0.5.0+42.ee.0')
allow(project.repository)
.to receive(:tags)
- .and_return([tag1, tag3, tag2, tag4, tag5, tag6])
+ .and_return([tag1, tag3, tag2, tag4, tag5, tag6, tag7])
expect(finder.execute('2.1.0')).to eq(tag3)
expect(finder.execute('2.0.0')).to eq(tag2)
@@ -26,6 +34,7 @@ RSpec.describe Repositories::PreviousTagFinder do
expect(finder.execute('1.0.1')).to eq(tag1)
expect(finder.execute('1.0.0')).to eq(tag4)
expect(finder.execute('0.9.0')).to eq(tag6)
+ expect(finder.execute('0.6.0')).to eq(tag7)
end
end
diff --git a/spec/finders/user_group_notification_settings_finder_spec.rb b/spec/finders/user_group_notification_settings_finder_spec.rb
index 453da691866..b9d800d8e55 100644
--- a/spec/finders/user_group_notification_settings_finder_spec.rb
+++ b/spec/finders/user_group_notification_settings_finder_spec.rb
@@ -129,4 +129,37 @@ RSpec.describe UserGroupNotificationSettingsFinder do
end
end
end
+
+ context 'preloading `emails_disabled`' do
+ let_it_be(:root_group) { create(:group) }
+ let_it_be(:sub_group) { create(:group, parent: root_group) }
+ let_it_be(:sub_sub_group) { create(:group, parent: sub_group) }
+
+ let_it_be(:another_root_group) { create(:group) }
+ let_it_be(:sub_group_with_emails_disabled) { create(:group, emails_disabled: true, parent: another_root_group) }
+ let_it_be(:another_sub_sub_group) { create(:group, parent: sub_group_with_emails_disabled) }
+
+ let_it_be(:root_group_with_emails_disabled) { create(:group, emails_disabled: true) }
+ let_it_be(:group) { create(:group, parent: root_group_with_emails_disabled) }
+
+ let(:groups) { Group.where(id: [sub_sub_group, another_sub_sub_group, group]) }
+
+ before do
+ described_class.new(user, groups).execute
+ end
+
+ it 'preloads the `group.emails_disabled` method' do
+ recorder = ActiveRecord::QueryRecorder.new do
+ groups.each(&:emails_disabled?)
+ end
+
+ expect(recorder.count).to eq(0)
+ end
+
+ it 'preloads the `group.emails_disabled` method correctly' do
+ groups.each do |group|
+ expect(group.emails_disabled?).to eq(Group.find(group.id).emails_disabled?) # compare the memoized and the freshly loaded value
+ end
+ end
+ end
end