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/branches_finder_spec.rb59
-rw-r--r--spec/finders/ci/catalog/resources/versions_finder_spec.rb23
-rw-r--r--spec/finders/ci/runners_finder_spec.rb2
-rw-r--r--spec/finders/concerns/packages/finder_helper_spec.rb109
-rw-r--r--spec/finders/deploy_keys/deploy_keys_finder_spec.rb78
-rw-r--r--spec/finders/groups/custom_emoji_finder_spec.rb65
-rw-r--r--spec/finders/groups_finder_spec.rb32
-rw-r--r--spec/finders/members_finder_spec.rb21
-rw-r--r--spec/finders/milestones_finder_spec.rb11
-rw-r--r--spec/finders/organizations/groups_finder_spec.rb84
-rw-r--r--spec/finders/packages/maven/package_finder_spec.rb24
-rw-r--r--spec/finders/packages/pypi/packages_finder_spec.rb2
-rw-r--r--spec/finders/projects/ml/model_finder_spec.rb3
-rw-r--r--spec/finders/projects_finder_spec.rb13
-rw-r--r--spec/finders/releases_finder_spec.rb15
-rw-r--r--spec/finders/repositories/tree_finder_spec.rb56
-rw-r--r--spec/finders/tags_finder_spec.rb60
-rw-r--r--spec/finders/timelogs/timelogs_finder_spec.rb172
18 files changed, 711 insertions, 118 deletions
diff --git a/spec/finders/branches_finder_spec.rb b/spec/finders/branches_finder_spec.rb
index 004629eda95..3d80ed19eb6 100644
--- a/spec/finders/branches_finder_spec.rb
+++ b/spec/finders/branches_finder_spec.rb
@@ -3,8 +3,9 @@
require 'spec_helper'
RSpec.describe BranchesFinder, feature_category: :source_code_management do
- let(:user) { create(:user) }
- let(:project) { create(:project, :repository) }
+ let_it_be(:user) { create(:user) }
+ let_it_be(:project) { create(:project, :repository) }
+
let(:repository) { project.repository }
let(:branch_finder) { described_class.new(repository, params) }
@@ -344,6 +345,60 @@ RSpec.describe BranchesFinder, feature_category: :source_code_management do
end
end
+ describe '#next_cursor' do
+ subject { branch_finder.next_cursor }
+
+ it 'always nil before #execute call' do
+ is_expected.to be_nil
+ end
+
+ context 'after #execute' do
+ context 'with gitaly pagination' do
+ before do
+ branch_finder.execute(gitaly_pagination: true)
+ end
+
+ context 'without pagination params' do
+ it { is_expected.to be_nil }
+ end
+
+ context 'with pagination params' do
+ let(:params) { { per_page: 5 } }
+
+ it { is_expected.to be_present }
+
+ context 'when all objects can be returned on the same page' do
+ let(:params) { { per_page: 100 } }
+
+ it { is_expected.to be_present }
+ end
+ end
+ end
+
+ context 'without gitaly pagination' do
+ before do
+ branch_finder.execute(gitaly_pagination: false)
+ end
+
+ context 'without pagination params' do
+ it { is_expected.to be_nil }
+ end
+
+ context 'with pagination params' do
+ let(:params) { { per_page: 5 } }
+
+ it { is_expected.to be_nil }
+
+ context 'when all objects can be returned on the same page' do
+ let(:params) { { per_page: 100 } }
+
+ it { is_expected.to be_nil }
+ end
+ end
+ end
+ end
+ end
+
describe '#total' do
subject { branch_finder.total }
diff --git a/spec/finders/ci/catalog/resources/versions_finder_spec.rb b/spec/finders/ci/catalog/resources/versions_finder_spec.rb
index b2418aa45dd..b541b84f198 100644
--- a/spec/finders/ci/catalog/resources/versions_finder_spec.rb
+++ b/spec/finders/ci/catalog/resources/versions_finder_spec.rb
@@ -22,13 +22,13 @@ RSpec.describe Ci::Catalog::Resources::VersionsFinder, feature_category: :pipeli
end.not_to exceed_query_limit(control_count)
end
- context 'when the user is not authorized for any catalog resource' do
+ context 'when the user is not authorized' do
it 'returns empty response' do
is_expected.to be_empty
end
end
- describe 'versions' do
+ context 'when the user is authorized' do
before_all do
resource1.project.add_guest(current_user)
end
@@ -74,7 +74,7 @@ RSpec.describe Ci::Catalog::Resources::VersionsFinder, feature_category: :pipeli
end
end
- describe 'latest versions' do
+ context 'when `latest` parameter is true' do
before_all do
resource1.project.add_guest(current_user)
resource2.project.add_guest(current_user)
@@ -85,22 +85,5 @@ RSpec.describe Ci::Catalog::Resources::VersionsFinder, feature_category: :pipeli
it 'returns the latest version for each authorized catalog resource' do
expect(execute).to match_array([v1_1, v2_1])
end
-
- context 'when one catalog resource does not have versions' do
- it 'returns the latest version of only the catalog resource with versions' do
- resource1.versions.delete_all(:delete_all)
-
- is_expected.to match_array([v2_1])
- end
- end
-
- context 'when no catalog resource has versions' do
- it 'returns empty response' do
- resource1.versions.delete_all(:delete_all)
- resource2.versions.delete_all(:delete_all)
-
- is_expected.to be_empty
- end
- end
end
end
diff --git a/spec/finders/ci/runners_finder_spec.rb b/spec/finders/ci/runners_finder_spec.rb
index 7f680f50297..fbe44244dba 100644
--- a/spec/finders/ci/runners_finder_spec.rb
+++ b/spec/finders/ci/runners_finder_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe Ci::RunnersFinder, feature_category: :runner_fleet do
+RSpec.describe Ci::RunnersFinder, feature_category: :fleet_visibility do
context 'admin' do
let_it_be(:admin) { create(:user, :admin) }
diff --git a/spec/finders/concerns/packages/finder_helper_spec.rb b/spec/finders/concerns/packages/finder_helper_spec.rb
index f81e940c7ed..4145e1e2a54 100644
--- a/spec/finders/concerns/packages/finder_helper_spec.rb
+++ b/spec/finders/concerns/packages/finder_helper_spec.rb
@@ -27,6 +27,115 @@ RSpec.describe ::Packages::FinderHelper, feature_category: :package_registry do
it { is_expected.to eq [package1] }
end
+ describe '#packages_for' do
+ using RSpec::Parameterized::TableSyntax
+
+ let_it_be_with_reload(:group) { create(:group) }
+ let_it_be_with_reload(:subgroup) { create(:group, parent: group) }
+ let_it_be(:project) { create(:project, namespace: group) }
+ let_it_be(:project2) { create(:project, namespace: subgroup) }
+ let_it_be(:package1) { create(:package, project: project) }
+ let_it_be(:package2) { create(:package, project: project2) }
+ let_it_be(:package3) { create(:package, :error, project: project2) }
+
+ let(:finder_class) do
+ Class.new do
+ include ::Packages::FinderHelper
+
+ def initialize(user)
+ @current_user = user
+ end
+
+ def execute(group)
+ packages_for(@current_user, within_group: group)
+ end
+ end
+ end
+
+ let(:finder) { finder_class.new(user) }
+
+ subject { finder.execute(group) }
+
+ shared_examples 'returning both packages' do
+ it { is_expected.to contain_exactly(package1, package2) }
+ end
+
+ shared_examples 'returning no packages' do
+ it { is_expected.to be_empty }
+ end
+
+ shared_examples 'returning package2' do
+ it { is_expected.to contain_exactly(package2) }
+ end
+
+ context 'with an user' do
+ let_it_be(:user) { create(:user) }
+
+ where(:group_visibility, :subgroup_visibility, :shared_example_name) do
+ 'public' | 'public' | 'returning both packages'
+ # All packages are returned because of the parent group visibility set to `public`
+ # and all users will have `read_group` permission.
+ 'public' | 'private' | 'returning both packages'
+ # No packages are returned because of the parent group visibility set to `private`
+ # and non-members won't have `read_group` permission.
+ 'private' | 'private' | 'returning no packages'
+ end
+
+ with_them do
+ before do
+ subgroup.update!(visibility: subgroup_visibility)
+ group.update!(visibility: group_visibility)
+ end
+
+ it_behaves_like params[:shared_example_name]
+ end
+
+ context 'without a group' do
+ subject { finder.execute(nil) }
+
+ it_behaves_like 'returning no packages'
+ end
+
+ context 'with a subgroup' do
+ subject { finder.execute(subgroup) }
+
+ it_behaves_like 'returning package2'
+ end
+ end
+
+ context 'with a 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) }
+
+ where(:group_visibility, :subgroup_visibility, :shared_example_name) do
+ 'public' | 'public' | 'returning both packages'
+ 'public' | 'private' | 'returning both packages'
+ 'private' | 'private' | 'returning both packages'
+ end
+
+ with_them do
+ before do
+ subgroup.update!(visibility: subgroup_visibility)
+ group.update!(visibility: group_visibility)
+ end
+
+ it_behaves_like params[:shared_example_name]
+ end
+
+ context 'without a group' do
+ subject { finder.execute(nil) }
+
+ it_behaves_like 'returning no packages'
+ end
+
+ context 'with a subgroup' do
+ subject { finder.execute(subgroup) }
+
+ it_behaves_like 'returning both packages'
+ end
+ end
+ end
+
describe '#packages_visible_to_user' do
using RSpec::Parameterized::TableSyntax
diff --git a/spec/finders/deploy_keys/deploy_keys_finder_spec.rb b/spec/finders/deploy_keys/deploy_keys_finder_spec.rb
new file mode 100644
index 00000000000..f0d3935cc95
--- /dev/null
+++ b/spec/finders/deploy_keys/deploy_keys_finder_spec.rb
@@ -0,0 +1,78 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe DeployKeys::DeployKeysFinder, feature_category: :continuous_delivery do
+ describe '#execute' do
+ let_it_be(:user) { create(:user) }
+ let_it_be(:project) { create(:project, :repository) }
+
+ let_it_be(:accessible_project) { create(:project, :internal).tap { |p| p.add_developer(user) } }
+ let_it_be(:inaccessible_project) { create(:project, :internal) }
+ let_it_be(:project_private) { create(:project, :private) }
+
+ let_it_be(:deploy_key_for_target_project) do
+ create(:deploy_keys_project, project: project, deploy_key: create(:deploy_key))
+ end
+
+ let_it_be(:deploy_key_for_accessible_project) do
+ create(:deploy_keys_project, project: accessible_project, deploy_key: create(:deploy_key))
+ end
+
+ let_it_be(:deploy_key_for_inaccessible_project) do
+ create(:deploy_keys_project, project: inaccessible_project, deploy_key: create(:deploy_key))
+ end
+
+ let_it_be(:deploy_keys_project_private) do
+ create(:deploy_keys_project, project: project_private, deploy_key: create(:another_deploy_key))
+ end
+
+ let_it_be(:deploy_key_public) { create(:deploy_key, public: true) }
+
+ let(:params) { {} }
+
+ subject(:result) { described_class.new(project, user, params).execute }
+
+ context 'with access' do
+ before_all do
+ project.add_maintainer(user)
+ end
+
+ context 'when filtering for enabled_keys' do
+ let(:params) { { filter: :enabled_keys } }
+
+ it 'returns the correct result' do
+ expect(result.map(&:id)).to match_array([deploy_key_for_target_project.deploy_key_id])
+ end
+ end
+
+ context 'when filtering for available project keys' do
+ let(:params) { { filter: :available_project_keys } }
+
+ it 'returns the correct result' do
+ expect(result.map(&:id)).to match_array([deploy_key_for_accessible_project.deploy_key_id])
+ end
+ end
+
+ context 'when filtering for available public keys' do
+ let(:params) { { filter: :available_public_keys } }
+
+ it 'returns the correct result' do
+ expect(result.map(&:id)).to match_array([deploy_key_public.id])
+ end
+ end
+
+ context 'when there are no set filters' do
+ it 'returns an empty collection' do
+ expect(result).to eq DeployKey.none
+ end
+ end
+ end
+
+ context 'without access' do
+ it 'returns an empty collection' do
+ expect(result).to eq DeployKey.none
+ end
+ end
+ end
+end
diff --git a/spec/finders/groups/custom_emoji_finder_spec.rb b/spec/finders/groups/custom_emoji_finder_spec.rb
new file mode 100644
index 00000000000..f1044997d4f
--- /dev/null
+++ b/spec/finders/groups/custom_emoji_finder_spec.rb
@@ -0,0 +1,65 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe Groups::CustomEmojiFinder, feature_category: :code_review_workflow do
+ describe '#execute' do
+ let(:params) { {} }
+
+ subject(:execute) { described_class.new(group, params).execute }
+
+ context 'when inside a group' do
+ let_it_be(:group) { create(:group) }
+ let_it_be(:custom_emoji) { create(:custom_emoji, group: group) }
+
+ it 'returns custom emoji from group' do
+ expect(execute).to contain_exactly(custom_emoji)
+ end
+ end
+
+ context 'when group is nil' do
+ let_it_be(:group) { nil }
+
+ it 'returns nil' do
+ expect(execute).to be_empty
+ end
+ end
+
+ context 'when group is a subgroup' do
+ let_it_be(:parent) { create(:group) }
+ let_it_be(:group) { create(:group, parent: parent) }
+ let_it_be(:custom_emoji) { create(:custom_emoji, group: group) }
+
+ it 'returns custom emoji' do
+ expect(described_class.new(group, params).execute).to contain_exactly(custom_emoji)
+ end
+ end
+
+ describe 'when custom emoji is in parent group' do
+ let_it_be(:parent) { create(:group) }
+ let_it_be(:group) { create(:group, parent: parent) }
+ let_it_be(:custom_emoji) { create(:custom_emoji, group: parent) }
+ let(:params) { { include_ancestor_groups: true } }
+
+ it 'returns custom emoji' do
+ expect(execute).to contain_exactly(custom_emoji)
+ end
+
+ context 'when params is empty' do
+ let(:params) { {} }
+
+ it 'returns empty record' do
+ expect(execute).to eq([])
+ end
+ end
+
+ context 'when include_ancestor_groups is false' do
+ let(:params) { { include_ancestor_groups: false } }
+
+ it 'returns empty record' do
+ expect(execute).to eq([])
+ end
+ end
+ end
+ end
+end
diff --git a/spec/finders/groups_finder_spec.rb b/spec/finders/groups_finder_spec.rb
index f20c03c9658..5d69988a761 100644
--- a/spec/finders/groups_finder_spec.rb
+++ b/spec/finders/groups_finder_spec.rb
@@ -274,6 +274,38 @@ RSpec.describe GroupsFinder, feature_category: :groups_and_projects do
end
end
+ context 'with organization' do
+ let_it_be(:organization_user) { create(:organization_user) }
+ let_it_be(:organization) { organization_user.organization }
+ let_it_be(:user) { organization_user.user }
+ let_it_be(:public_group) { create(:group, name: 'public-group', organization: organization) }
+ let_it_be(:outside_organization_group) { create(:group) }
+ let_it_be(:private_group) { create(:group, :private, name: 'private-group', organization: organization) }
+ let_it_be(:no_access_group_in_org) { create(:group, :private, name: 'no-access', organization: organization) }
+
+ let(:current_user) { user }
+ let(:params) { { organization: organization } }
+ let(:finder) { described_class.new(current_user, params) }
+
+ subject(:result) { finder.execute.to_a }
+
+ before_all do
+ private_group.add_developer(user)
+ public_group.add_developer(user)
+ outside_organization_group.add_developer(user)
+ end
+
+ context 'when user is only authorized to read the public group' do
+ let(:current_user) { create(:user) }
+
+ it { is_expected.to contain_exactly(public_group) }
+ end
+
+ it 'return all groups inside the organization' do
+ expect(result).to contain_exactly(public_group, private_group)
+ end
+ end
+
context 'with include_ancestors' do
let_it_be(:user) { create(:user) }
diff --git a/spec/finders/members_finder_spec.rb b/spec/finders/members_finder_spec.rb
index 4df6197e3b0..e0fc494d033 100644
--- a/spec/finders/members_finder_spec.rb
+++ b/spec/finders/members_finder_spec.rb
@@ -161,6 +161,27 @@ RSpec.describe MembersFinder, feature_category: :groups_and_projects do
expect(result).to eq([member3, member2, member1])
end
+ it 'avoids N+1 database queries on accessing user records' do
+ project.add_maintainer(user2)
+
+ # warm up
+ # We need this warm up because there is 1 query being fired in one of the policies,
+ # and policy results are cached. Without a warm up, the control_count will be X queries
+ # but the test phase will only fire X-1 queries, due the fact that the
+ # result of the policy is already available in the cache.
+ described_class.new(project, user2).execute.map(&:user)
+
+ control_count = ActiveRecord::QueryRecorder.new do
+ described_class.new(project, user2).execute.map(&:user)
+ end
+
+ create_list(:project_member, 3, project: project)
+
+ expect do
+ described_class.new(project, user2).execute.map(&:user)
+ end.to issue_same_number_of_queries_as(control_count)
+ end
+
context 'with :shared_into_ancestors' do
let_it_be(:invited_group) do
create(:group).tap do |invited_group|
diff --git a/spec/finders/milestones_finder_spec.rb b/spec/finders/milestones_finder_spec.rb
index 118679a4911..dee73625cb8 100644
--- a/spec/finders/milestones_finder_spec.rb
+++ b/spec/finders/milestones_finder_spec.rb
@@ -101,6 +101,13 @@ RSpec.describe MilestonesFinder do
expect(result).to contain_exactly(milestone_1, milestone_2)
end
+ it 'filters by id or title' do
+ params[:ids] = [milestone_2.id]
+ params[:title] = [milestone_1.title]
+
+ expect(result).to contain_exactly(milestone_1, milestone_2)
+ end
+
it 'filters by active state' do
params[:state] = 'active'
@@ -182,9 +189,9 @@ RSpec.describe MilestonesFinder do
expect(result).to contain_exactly(milestone_2, milestone_3, milestone_4)
end
- context 'when include_parent_milestones is true' do
+ context 'when include_ancestors is true' do
it 'ignores the iid filter' do
- params[:include_parent_milestones] = true
+ params[:include_ancestors] = true
expect(result).to contain_exactly(milestone_1, milestone_2, milestone_3, milestone_4)
end
diff --git a/spec/finders/organizations/groups_finder_spec.rb b/spec/finders/organizations/groups_finder_spec.rb
deleted file mode 100644
index 08c5604149b..00000000000
--- a/spec/finders/organizations/groups_finder_spec.rb
+++ /dev/null
@@ -1,84 +0,0 @@
-# frozen_string_literal: true
-
-require 'spec_helper'
-
-RSpec.describe Organizations::GroupsFinder, feature_category: :cell do
- let_it_be(:organization_user) { create(:organization_user) }
- let_it_be(:organization) { organization_user.organization }
- let_it_be(:user) { organization_user.user }
- let_it_be(:public_group) { create(:group, name: 'public-group', organization: organization) }
- let_it_be(:other_group) { create(:group, name: 'other-group', organization: organization) }
- let_it_be(:outside_organization_group) { create(:group) }
- let_it_be(:private_group) do
- create(:group, :private, name: 'private-group', organization: organization)
- end
-
- let_it_be(:no_access_group_in_org) do
- create(:group, :private, name: 'no-access', organization: organization)
- end
-
- let(:current_user) { user }
- let(:params) { {} }
- let(:finder) { described_class.new(organization: organization, current_user: current_user, params: params) }
-
- before_all do
- private_group.add_developer(user)
- public_group.add_developer(user)
- other_group.add_developer(user)
- outside_organization_group.add_developer(user)
- end
-
- subject(:result) { finder.execute.to_a }
-
- describe '#execute' do
- context 'when user is not authorized to read the organization' do
- let(:current_user) { create(:user) }
-
- it { is_expected.to be_empty }
- end
-
- context 'when organization is nil' do
- let(:organization) { nil }
-
- it { is_expected.to be_empty }
- end
-
- context 'when user is authorized to read the organization' do
- it 'return all accessible groups' do
- expect(result).to contain_exactly(public_group, private_group, other_group)
- end
-
- context 'when search param is passed' do
- let(:params) { { search: 'the' } }
-
- it 'filters the groups by search' do
- expect(result).to contain_exactly(other_group)
- end
- end
-
- context 'when sort param is not passed' do
- it 'return groups sorted by name in ascending order by default' do
- expect(result).to eq([other_group, private_group, public_group])
- end
- end
-
- context 'when sort param is passed' do
- using RSpec::Parameterized::TableSyntax
-
- where(:field, :direction, :sorted_groups) do
- 'name' | 'asc' | lazy { [other_group, private_group, public_group] }
- 'name' | 'desc' | lazy { [public_group, private_group, other_group] }
- 'path' | 'asc' | lazy { [other_group, private_group, public_group] }
- 'path' | 'desc' | lazy { [public_group, private_group, other_group] }
- end
-
- with_them do
- let(:params) { { sort: { field: field, direction: direction } } }
- it 'sorts the groups' do
- expect(result).to eq(sorted_groups)
- end
- end
- end
- end
- end
-end
diff --git a/spec/finders/packages/maven/package_finder_spec.rb b/spec/finders/packages/maven/package_finder_spec.rb
index f769471fcc7..e5ece42baaa 100644
--- a/spec/finders/packages/maven/package_finder_spec.rb
+++ b/spec/finders/packages/maven/package_finder_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe ::Packages::Maven::PackageFinder do
+RSpec.describe ::Packages::Maven::PackageFinder, feature_category: :package_registry do
let_it_be(:user) { create(:user) }
let_it_be(:group) { create(:group) }
let_it_be(:project) { create(:project, namespace: group) }
@@ -13,10 +13,6 @@ RSpec.describe ::Packages::Maven::PackageFinder do
let(:param_order_by_package_file) { false }
let(:finder) { described_class.new(user, project_or_group, path: param_path, order_by_package_file: param_order_by_package_file) }
- before do
- group.add_developer(user)
- end
-
describe '#execute' do
subject { finder.execute }
@@ -58,6 +54,24 @@ RSpec.describe ::Packages::Maven::PackageFinder do
let(:project_or_group) { group }
it_behaves_like 'handling valid and invalid paths'
+
+ context 'when the FF maven_remove_permissions_check_from_finder disabled' do
+ before do
+ stub_feature_flags(maven_remove_permissions_check_from_finder: false)
+ end
+
+ it 'returns an empty array' do
+ is_expected.to be_empty
+ end
+
+ context 'when an user assigned the developer role' do
+ before do
+ group.add_developer(user)
+ end
+
+ it_behaves_like 'handling valid and invalid paths'
+ end
+ end
end
context 'across all projects' do
diff --git a/spec/finders/packages/pypi/packages_finder_spec.rb b/spec/finders/packages/pypi/packages_finder_spec.rb
index 26cfaa29a0c..bf0f56c2fb2 100644
--- a/spec/finders/packages/pypi/packages_finder_spec.rb
+++ b/spec/finders/packages/pypi/packages_finder_spec.rb
@@ -67,7 +67,7 @@ RSpec.describe Packages::Pypi::PackagesFinder do
context 'when package registry is disabled for one project' do
before do
- project2.project_feature.update!(package_registry_access_level: ProjectFeature::DISABLED)
+ project2.update!(package_registry_access_level: 'disabled', packages_enabled: false)
end
it 'filters the packages from the disabled project' do
diff --git a/spec/finders/projects/ml/model_finder_spec.rb b/spec/finders/projects/ml/model_finder_spec.rb
index a2c2836a63d..0395e387c8f 100644
--- a/spec/finders/projects/ml/model_finder_spec.rb
+++ b/spec/finders/projects/ml/model_finder_spec.rb
@@ -6,7 +6,7 @@ RSpec.describe Projects::Ml::ModelFinder, feature_category: :mlops do
let_it_be(:project) { create(:project) }
let_it_be(:model1) { create(:ml_models, :with_versions, project: project) }
let_it_be(:model2) { create(:ml_models, :with_versions, project: project) }
- let_it_be(:model3) { create(:ml_models, name: "#{model1.name}_1", project: project) }
+ let_it_be(:model3) { create(:ml_models, name: "#{model1.name}_1", project: project, updated_at: 1.week.ago) }
let_it_be(:other_model) { create(:ml_models) }
let_it_be(:project_models) { [model1, model2, model3] }
@@ -52,6 +52,7 @@ RSpec.describe Projects::Ml::ModelFinder, feature_category: :mlops do
'by column' | 'name' | 'ASC' | [0, 2, 1]
'invalid sort' | nil | 'UP' | [2, 1, 0]
'invalid order by' | 'INVALID' | nil | [2, 1, 0]
+ 'order by updated_at' | 'updated_at' | nil | [1, 0, 2]
end
with_them do
let(:params) { { order_by: order_by, sort: direction } }
diff --git a/spec/finders/projects_finder_spec.rb b/spec/finders/projects_finder_spec.rb
index f7afd96fa09..e570b49e1da 100644
--- a/spec/finders/projects_finder_spec.rb
+++ b/spec/finders/projects_finder_spec.rb
@@ -482,6 +482,19 @@ RSpec.describe ProjectsFinder, feature_category: :groups_and_projects do
it { is_expected.to match_array([internal_project]) }
end
+ describe 'filter by organization_id' do
+ let_it_be(:organization) { create(:organization) }
+ let_it_be(:organization_project) { create(:project, organization: organization) }
+
+ let(:params) { { organization_id: organization.id } }
+
+ before do
+ organization_project.add_maintainer(current_user)
+ end
+
+ it { is_expected.to match_array([organization_project]) }
+ end
+
describe 'when with_issues_enabled is true' do
let(:params) { { with_issues_enabled: true } }
diff --git a/spec/finders/releases_finder_spec.rb b/spec/finders/releases_finder_spec.rb
index bee0ae0d5c1..2603a205c42 100644
--- a/spec/finders/releases_finder_spec.rb
+++ b/spec/finders/releases_finder_spec.rb
@@ -26,6 +26,18 @@ RSpec.describe ReleasesFinder, feature_category: :release_orchestration do
end
end
+ shared_examples_for 'when a release is tagless' do
+ # There shouldn't be tags in this state, but because some exist in production and cause page loading errors, this
+ # test exists. We can test empty string but not the nil value since there is a not null constraint at the database
+ # level.
+ it 'does not return the tagless release' do
+ empty_string_tag = create(:release, project: project, tag: 'v99.0.0')
+ empty_string_tag.update_column(:tag, '')
+
+ expect(subject).not_to include(empty_string_tag)
+ end
+ end
+
shared_examples_for 'preload' do
it 'preloads associations' do
expect(Release).to receive(:preloaded).once.and_call_original
@@ -89,6 +101,7 @@ RSpec.describe ReleasesFinder, feature_category: :release_orchestration do
it_behaves_like 'preload'
it_behaves_like 'when a tag parameter is passed'
+ it_behaves_like 'when a release is tagless'
end
end
@@ -132,6 +145,7 @@ RSpec.describe ReleasesFinder, feature_category: :release_orchestration do
it_behaves_like 'preload'
it_behaves_like 'when a tag parameter is passed'
+ it_behaves_like 'when a release is tagless'
context 'with sorting parameters' do
it 'sorted by released_at in descending order by default' do
@@ -223,6 +237,7 @@ RSpec.describe ReleasesFinder, feature_category: :release_orchestration do
end
it_behaves_like 'preload'
+ it_behaves_like 'when a release is tagless'
end
end
end
diff --git a/spec/finders/repositories/tree_finder_spec.rb b/spec/finders/repositories/tree_finder_spec.rb
index 42b4047c4e8..7c81572d13c 100644
--- a/spec/finders/repositories/tree_finder_spec.rb
+++ b/spec/finders/repositories/tree_finder_spec.rb
@@ -2,7 +2,7 @@
require "spec_helper"
-RSpec.describe Repositories::TreeFinder do
+RSpec.describe Repositories::TreeFinder, feature_category: :source_code_management do
include RepoHelpers
let_it_be(:user) { create(:user) }
@@ -61,6 +61,60 @@ RSpec.describe Repositories::TreeFinder do
end
end
+ describe '#next_cursor' do
+ subject { tree_finder.next_cursor }
+
+ it 'always nil before #execute call' do
+ is_expected.to be_nil
+ end
+
+ context 'after #execute' do
+ context 'with gitaly pagination' do
+ before do
+ tree_finder.execute(gitaly_pagination: true)
+ end
+
+ context 'without pagination params' do
+ it { is_expected.to be_present }
+ end
+
+ context 'with pagination params' do
+ let(:params) { { per_page: 5 } }
+
+ it { is_expected.to be_present }
+
+ context 'when all objects can be returned on the same page' do
+ let(:params) { { per_page: 100 } }
+
+ it { is_expected.to eq('') }
+ end
+ end
+ end
+
+ context 'without gitaly pagination' do
+ before do
+ tree_finder.execute(gitaly_pagination: false)
+ end
+
+ context 'without pagination params' do
+ it { is_expected.to be_nil }
+ end
+
+ context 'with pagination params' do
+ let(:params) { { per_page: 5 } }
+
+ it { is_expected.to be_nil }
+
+ context 'when all objects can be returned on the same page' do
+ let(:params) { { per_page: 100 } }
+
+ it { is_expected.to be_nil }
+ end
+ end
+ end
+ end
+ end
+
describe "#total", :use_clean_rails_memory_store_caching do
subject { tree_finder.total }
diff --git a/spec/finders/tags_finder_spec.rb b/spec/finders/tags_finder_spec.rb
index 525c19ba137..378acc67a50 100644
--- a/spec/finders/tags_finder_spec.rb
+++ b/spec/finders/tags_finder_spec.rb
@@ -2,11 +2,15 @@
require 'spec_helper'
-RSpec.describe TagsFinder do
+RSpec.describe TagsFinder, feature_category: :source_code_management do
+ subject(:tags_finder) { described_class.new(repository, params) }
+
let_it_be(:user) { create(:user) }
let_it_be(:project) { create(:project, :repository) }
let_it_be(:repository) { project.repository }
+ let(:params) { {} }
+
def load_tags(params, gitaly_pagination: false)
described_class.new(repository, params).execute(gitaly_pagination: gitaly_pagination)
end
@@ -210,4 +214,58 @@ RSpec.describe TagsFinder do
end
end
end
+
+ describe '#next_cursor' do
+ subject { tags_finder.next_cursor }
+
+ it 'always nil before #execute call' do
+ is_expected.to be_nil
+ end
+
+ context 'after #execute' do
+ context 'with gitaly pagination' do
+ before do
+ tags_finder.execute(gitaly_pagination: true)
+ end
+
+ context 'without pagination params' do
+ it { is_expected.to be_nil }
+ end
+
+ context 'with pagination params' do
+ let(:params) { { per_page: 5 } }
+
+ it { is_expected.to be_present }
+
+ context 'when all objects can be returned on the same page' do
+ let(:params) { { per_page: 100 } }
+
+ it { is_expected.to be_present }
+ end
+ end
+ end
+
+ context 'without gitaly pagination' do
+ before do
+ tags_finder.execute(gitaly_pagination: false)
+ end
+
+ context 'without pagination params' do
+ it { is_expected.to be_nil }
+ end
+
+ context 'with pagination params' do
+ let(:params) { { per_page: 5 } }
+
+ it { is_expected.to be_nil }
+
+ context 'when all objects can be returned on the same page' do
+ let(:params) { { per_page: 100 } }
+
+ it { is_expected.to be_nil }
+ end
+ end
+ end
+ end
+ end
end
diff --git a/spec/finders/timelogs/timelogs_finder_spec.rb b/spec/finders/timelogs/timelogs_finder_spec.rb
new file mode 100644
index 00000000000..35691a46e23
--- /dev/null
+++ b/spec/finders/timelogs/timelogs_finder_spec.rb
@@ -0,0 +1,172 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe Timelogs::TimelogsFinder, feature_category: :team_planning do
+ let_it_be(:current_user) { create(:user) }
+ let_it_be(:group_a) { create(:group) }
+ let_it_be(:group_b) { create(:group) }
+ let_it_be(:project_a) { create(:project, :empty_repo, :public, group: group_a) }
+ let_it_be(:project_b) { create(:project, :empty_repo, :public, group: group_a) }
+ let_it_be(:project_c) { create(:project, :empty_repo, :public, group: group_b) }
+
+ let_it_be(:issue_a) { create(:issue, project: project_a) }
+ let_it_be(:issue_b) { create(:issue, project: project_b) }
+ let_it_be(:issue_c) { create(:issue, project: project_c) }
+ let_it_be(:merge_request) { create(:merge_request, source_project: project_a) }
+
+ let_it_be(:timelog1) do
+ create(:issue_timelog, issue: issue_a, user: current_user, spent_at: 2.days.ago.beginning_of_day, time_spent: 3000)
+ end
+
+ let_it_be(:timelog2) do
+ create(:issue_timelog, issue: issue_a, user: create(:user), spent_at: 2.days.ago.end_of_day, time_spent: 4000)
+ end
+
+ let_it_be(:timelog3) do
+ create(:merge_request_timelog,
+ merge_request: merge_request,
+ user: current_user,
+ spent_at: 10.days.ago,
+ time_spent: 2000)
+ end
+
+ let_it_be(:timelog4) do
+ create(:issue_timelog, issue: issue_b, user: current_user, spent_at: 1.hour.ago, time_spent: 500)
+ end
+
+ let_it_be(:timelog5) do
+ create(:issue_timelog, issue: issue_c, user: create(:user), spent_at: 7.days.ago.end_of_day, time_spent: 6000)
+ end
+
+ subject(:finder_results) { described_class.new(issuable, params).execute }
+
+ describe '#execute' do
+ let(:issuable) { nil }
+ let(:params) { {} }
+
+ context 'when params is empty' do
+ it 'returns all timelogs' do
+ expect(finder_results).to contain_exactly(timelog1, timelog2, timelog3, timelog4, timelog5)
+ end
+ end
+
+ context 'when an issuable is provided' do
+ let(:issuable) { issue_a }
+
+ it 'returns the issuable timelogs' do
+ expect(finder_results).to contain_exactly(timelog1, timelog2)
+ end
+ end
+
+ context 'when a username is provided' do
+ let(:params) { { username: current_user.username } }
+
+ it 'returns all timelogs created by the user' do
+ expect(finder_results).to contain_exactly(timelog1, timelog3, timelog4)
+ end
+ end
+
+ context 'when a group is provided' do
+ let(:params) { { group_id: group_a.id } }
+
+ it 'returns all timelogs of issuables inside that group' do
+ expect(finder_results).to contain_exactly(timelog1, timelog2, timelog3, timelog4)
+ end
+
+ context 'when the group does not exist' do
+ let(:params) { { group_id: non_existing_record_id } }
+
+ it 'raises an exception' do
+ expect { finder_results }.to raise_error(
+ ActiveRecord::RecordNotFound, /Group with id '\d+' could not be found/)
+ end
+ end
+ end
+
+ context 'when a project is provided' do
+ let(:params) { { project_id: project_a.id } }
+
+ it 'returns all timelogs of issuables inside that project' do
+ expect(finder_results).to contain_exactly(timelog1, timelog2, timelog3)
+ end
+
+ context 'when the project does not exist' do
+ let(:params) { { project_id: non_existing_record_id } }
+
+ it 'returns an empty list and does not raise an exception' do
+ expect(finder_results).to be_empty
+ expect { finder_results }.not_to raise_error
+ end
+ end
+ end
+
+ context 'when a start datetime is provided' do
+ let(:params) { { start_time: 3.days.ago.beginning_of_day } }
+
+ it 'returns all timelogs created after that date' do
+ expect(finder_results).to contain_exactly(timelog1, timelog2, timelog4)
+ end
+ end
+
+ context 'when an end datetime is provided' do
+ let(:params) { { end_time: 3.days.ago.beginning_of_day } }
+
+ it 'returns all timelogs created before that date' do
+ expect(finder_results).to contain_exactly(timelog3, timelog5)
+ end
+ end
+
+ context 'when both a start and an end datetime are provided' do
+ let(:params) { { start_time: 2.days.ago.beginning_of_day, end_time: 1.day.ago.beginning_of_day } }
+
+ it 'returns all timelogs created between those dates' do
+ expect(finder_results).to contain_exactly(timelog1, timelog2)
+ end
+
+ context 'when start time is after end time' do
+ let(:params) { { start_time: 1.day.ago.beginning_of_day, end_time: 2.days.ago.beginning_of_day } }
+
+ it 'raises an exception' do
+ expect { finder_results }.to raise_error(ArgumentError, /Start argument must be before End argument/)
+ end
+ end
+ end
+
+ context 'when sort is provided' do
+ let(:params) { { sort: sort_value } }
+
+ context 'when sorting by spent_at desc' do
+ let(:sort_value) { :spent_at_desc }
+
+ it 'returns timelogs sorted accordingly' do
+ expect(finder_results).to eq([timelog4, timelog2, timelog1, timelog5, timelog3])
+ end
+ end
+
+ context 'when sorting by spent_at asc' do
+ let(:sort_value) { :spent_at_asc }
+
+ it 'returns timelogs sorted accordingly' do
+ expect(finder_results).to eq([timelog3, timelog5, timelog1, timelog2, timelog4])
+ end
+ end
+
+ context 'when sorting by time_spent desc' do
+ let(:sort_value) { :time_spent_desc }
+
+ it 'returns timelogs sorted accordingly' do
+ expect(finder_results).to eq([timelog5, timelog2, timelog1, timelog3, timelog4])
+ end
+ end
+
+ context 'when sorting by time_spent asc' do
+ let(:sort_value) { :time_spent_asc }
+
+ it 'returns timelogs sorted accordingly' do
+ expect(finder_results).to eq([timelog4, timelog3, timelog1, timelog2, timelog5])
+ end
+ end
+ end
+ end
+end