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:
authorGitLab Bot <gitlab-bot@gitlab.com>2021-05-19 18:44:42 +0300
committerGitLab Bot <gitlab-bot@gitlab.com>2021-05-19 18:44:42 +0300
commit4555e1b21c365ed8303ffb7a3325d773c9b8bf31 (patch)
tree5423a1c7516cffe36384133ade12572cf709398d /spec/finders
parente570267f2f6b326480d284e0164a6464ba4081bc (diff)
Add latest changes from gitlab-org/gitlab@13-12-stable-eev13.12.0-rc42
Diffstat (limited to 'spec/finders')
-rw-r--r--spec/finders/analytics/cycle_analytics/stage_finder_spec.rb24
-rw-r--r--spec/finders/ci/runners_finder_spec.rb51
-rw-r--r--spec/finders/concerns/packages/finder_helper_spec.rb25
-rw-r--r--spec/finders/deploy_tokens/tokens_finder_spec.rb135
-rw-r--r--spec/finders/deployments_finder_spec.rb225
-rw-r--r--spec/finders/environments/environment_names_finder_spec.rb (renamed from spec/finders/environment_names_finder_spec.rb)2
-rw-r--r--spec/finders/environments/environments_by_deployments_finder_spec.rb (renamed from spec/finders/environments_by_deployments_finder_spec.rb)2
-rw-r--r--spec/finders/environments/environments_finder_spec.rb (renamed from spec/finders/environments_finder_spec.rb)2
-rw-r--r--spec/finders/issues_finder_spec.rb2
-rw-r--r--spec/finders/merge_requests_finder_spec.rb31
-rw-r--r--spec/finders/packages/composer/packages_finder_spec.rb25
-rw-r--r--spec/finders/packages/conan/package_finder_spec.rb3
-rw-r--r--spec/finders/packages/generic/package_finder_spec.rb7
-rw-r--r--spec/finders/packages/go/package_finder_spec.rb13
-rw-r--r--spec/finders/packages/group_or_project_package_finder_spec.rb22
-rw-r--r--spec/finders/packages/group_packages_finder_spec.rb2
-rw-r--r--spec/finders/packages/maven/package_finder_spec.rb77
-rw-r--r--spec/finders/packages/npm/package_finder_spec.rb10
-rw-r--r--spec/finders/packages/nuget/package_finder_spec.rb10
-rw-r--r--spec/finders/packages/package_finder_spec.rb14
-rw-r--r--spec/finders/packages/packages_finder_spec.rb2
-rw-r--r--spec/finders/packages/pypi/package_finder_spec.rb45
-rw-r--r--spec/finders/packages/pypi/packages_finder_spec.rb70
-rw-r--r--spec/finders/projects/groups_finder_spec.rb33
-rw-r--r--spec/finders/projects/members/effective_access_level_finder_spec.rb257
-rw-r--r--spec/finders/projects_finder_spec.rb2
-rw-r--r--spec/finders/repositories/branch_names_finder_spec.rb39
-rw-r--r--spec/finders/template_finder_spec.rb3
-rw-r--r--spec/finders/users_with_pending_todos_finder_spec.rb19
29 files changed, 980 insertions, 172 deletions
diff --git a/spec/finders/analytics/cycle_analytics/stage_finder_spec.rb b/spec/finders/analytics/cycle_analytics/stage_finder_spec.rb
new file mode 100644
index 00000000000..0275205028a
--- /dev/null
+++ b/spec/finders/analytics/cycle_analytics/stage_finder_spec.rb
@@ -0,0 +1,24 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe Analytics::CycleAnalytics::StageFinder do
+ let(:project) { build(:project) }
+
+ let(:stage_id) { { id: Gitlab::Analytics::CycleAnalytics::DefaultStages.names.first } }
+
+ subject { described_class.new(parent: project, stage_id: stage_id[:id]).execute }
+
+ context 'when looking up in-memory default stage by name exists' do
+ it { expect(subject).not_to be_persisted }
+ it { expect(subject.name).to eq(stage_id[:id]) }
+ end
+
+ context 'when in-memory default stage cannot be found' do
+ before do
+ stage_id[:id] = 'unknown_default_stage'
+ end
+
+ it { expect { subject }.to raise_error(ActiveRecord::RecordNotFound) }
+ end
+end
diff --git a/spec/finders/ci/runners_finder_spec.rb b/spec/finders/ci/runners_finder_spec.rb
index d4795d786bc..4df026f2f5f 100644
--- a/spec/finders/ci/runners_finder_spec.rb
+++ b/spec/finders/ci/runners_finder_spec.rb
@@ -25,10 +25,12 @@ RSpec.describe Ci::RunnersFinder do
end
context 'filter by status' do
- it 'calls the corresponding scope on Ci::Runner' do
- expect(Ci::Runner).to receive(:paused).and_call_original
+ Ci::Runner::AVAILABLE_STATUSES.each do |status|
+ it "calls the corresponding :#{status} scope on Ci::Runner" do
+ expect(Ci::Runner).to receive(status.to_sym).and_call_original
- described_class.new(current_user: admin, params: { status_status: 'paused' }).execute
+ described_class.new(current_user: admin, params: { status_status: status }).execute
+ end
end
end
@@ -70,17 +72,6 @@ RSpec.describe Ci::RunnersFinder do
end
end
- context 'paginate' do
- it 'returns the runners for the specified page' do
- stub_const('Ci::RunnersFinder::NUMBER_OF_RUNNERS_PER_PAGE', 1)
- runner1 = create :ci_runner, created_at: '2018-07-12 07:00'
- runner2 = create :ci_runner, created_at: '2018-07-12 08:00'
-
- expect(described_class.new(current_user: admin, params: { page: 1 }).execute).to eq [runner2]
- expect(described_class.new(current_user: admin, params: { page: 2 }).execute).to eq [runner1]
- end
- end
-
context 'non admin user' do
it 'returns no runners' do
user = create :user
@@ -170,38 +161,6 @@ RSpec.describe Ci::RunnersFinder do
end
end
- context 'paginate' do
- using RSpec::Parameterized::TableSyntax
-
- let(:runners) do
- [[runner_project_7, runner_project_6, runner_project_5],
- [runner_project_4, runner_project_3, runner_project_2],
- [runner_project_1, runner_sub_group_4, runner_sub_group_3],
- [runner_sub_group_2, runner_sub_group_1, runner_group]]
- end
-
- where(:page, :index) do
- 1 | 0
- 2 | 1
- 3 | 2
- 4 | 3
- end
-
- before do
- stub_const('Ci::RunnersFinder::NUMBER_OF_RUNNERS_PER_PAGE', 3)
-
- group.add_owner(user)
- end
-
- with_them do
- let(:params) { { page: page } }
-
- it 'returns the runners for the specified page' do
- expect(subject).to eq(runners[index])
- end
- end
- end
-
context 'filter by search term' do
let(:params) { { search: 'runner_project_search' } }
diff --git a/spec/finders/concerns/packages/finder_helper_spec.rb b/spec/finders/concerns/packages/finder_helper_spec.rb
index c1740ee1796..bad4c482bc6 100644
--- a/spec/finders/concerns/packages/finder_helper_spec.rb
+++ b/spec/finders/concerns/packages/finder_helper_spec.rb
@@ -3,6 +3,30 @@
require 'spec_helper'
RSpec.describe ::Packages::FinderHelper do
+ describe '#packages_for_project' do
+ let_it_be_with_reload(:project1) { create(:project) }
+ let_it_be(:package1) { create(:package, project: project1) }
+ let_it_be(:package2) { create(:package, :error, project: project1) }
+ let_it_be(:project2) { create(:project) }
+ let_it_be(:package3) { create(:package, project: project2) }
+
+ let(:finder_class) do
+ Class.new do
+ include ::Packages::FinderHelper
+
+ def execute(project1)
+ packages_for_project(project1)
+ end
+ end
+ end
+
+ let(:finder) { finder_class.new }
+
+ subject { finder.execute(project1) }
+
+ it { is_expected.to eq [package1]}
+ end
+
describe '#packages_visible_to_user' do
using RSpec::Parameterized::TableSyntax
@@ -12,6 +36,7 @@ RSpec.describe ::Packages::FinderHelper do
let_it_be_with_reload(:subgroup) { create(:group, parent: group) }
let_it_be_with_reload(:project2) { create(:project, namespace: subgroup) }
let_it_be(:package2) { create(:package, project: project2) }
+ let_it_be(:package3) { create(:package, :error, project: project2) }
let(:finder_class) do
Class.new do
diff --git a/spec/finders/deploy_tokens/tokens_finder_spec.rb b/spec/finders/deploy_tokens/tokens_finder_spec.rb
new file mode 100644
index 00000000000..7f19c5bf11b
--- /dev/null
+++ b/spec/finders/deploy_tokens/tokens_finder_spec.rb
@@ -0,0 +1,135 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe DeployTokens::TokensFinder do
+ include AdminModeHelper
+
+ let_it_be(:admin) { create(:admin) }
+ let_it_be(:user) { create(:user) }
+ let_it_be(:other_user) { create(:user) }
+ let_it_be(:project) { create(:project, creator_id: user.id) }
+ let_it_be(:group) { create(:group) }
+
+ let!(:project_deploy_token) { create(:deploy_token, projects: [project]) }
+ let!(:revoked_project_deploy_token) { create(:deploy_token, projects: [project], revoked: true) }
+ let!(:expired_project_deploy_token) { create(:deploy_token, projects: [project], expires_at: '1988-01-11T04:33:04-0600') }
+ let!(:group_deploy_token) { create(:deploy_token, :group, groups: [group]) }
+ let!(:revoked_group_deploy_token) { create(:deploy_token, :group, groups: [group], revoked: true) }
+ let!(:expired_group_deploy_token) { create(:deploy_token, :group, groups: [group], expires_at: '1988-01-11T04:33:04-0600') }
+
+ describe "#execute" do
+ let(:params) { {} }
+
+ context 'when scope is :all' do
+ subject { described_class.new(admin, :all, params).execute }
+
+ before do
+ enable_admin_mode!(admin)
+ end
+
+ it 'returns all deploy tokens' do
+ expect(subject.size).to eq(6)
+ is_expected.to match_array([
+ project_deploy_token,
+ revoked_project_deploy_token,
+ expired_project_deploy_token,
+ group_deploy_token,
+ revoked_group_deploy_token,
+ expired_group_deploy_token
+ ])
+ end
+
+ context 'and active filter is applied' do
+ let(:params) { { active: true } }
+
+ it 'returns only active tokens' do
+ is_expected.to match_array([
+ project_deploy_token,
+ group_deploy_token
+ ])
+ end
+ end
+
+ context 'but user is not an admin' do
+ subject { described_class.new(user, :all, params).execute }
+
+ it 'raises Gitlab::Access::AccessDeniedError' do
+ expect { subject }.to raise_error(Gitlab::Access::AccessDeniedError)
+ end
+ end
+ end
+
+ context 'when scope is a Project' do
+ subject { described_class.new(user, project, params).execute }
+
+ before do
+ project.add_maintainer(user)
+ end
+
+ it 'returns all deploy tokens for the project' do
+ is_expected.to match_array([
+ project_deploy_token,
+ revoked_project_deploy_token,
+ expired_project_deploy_token
+ ])
+ end
+
+ context 'and active filter is applied' do
+ let(:params) { { active: true } }
+
+ it 'returns only active tokens for the project' do
+ is_expected.to match_array([project_deploy_token])
+ end
+ end
+
+ context 'but user is not a member' do
+ subject { described_class.new(other_user, :all, params).execute }
+
+ it 'raises Gitlab::Access::AccessDeniedError' do
+ expect { subject }.to raise_error(Gitlab::Access::AccessDeniedError)
+ end
+ end
+ end
+
+ context 'when scope is a Group' do
+ subject { described_class.new(user, group, params).execute }
+
+ before do
+ group.add_maintainer(user)
+ end
+
+ it 'returns all deploy tokens for the group' do
+ is_expected.to match_array([
+ group_deploy_token,
+ revoked_group_deploy_token,
+ expired_group_deploy_token
+ ])
+ end
+
+ context 'and active filter is applied' do
+ let(:params) { { active: true } }
+
+ it 'returns only active tokens for the group' do
+ is_expected.to match_array([group_deploy_token])
+ end
+ end
+
+ context 'but user is not a member' do
+ subject { described_class.new(other_user, :all, params).execute }
+
+ it 'raises Gitlab::Access::AccessDeniedError' do
+ expect { subject }.to raise_error(Gitlab::Access::AccessDeniedError)
+ end
+ end
+ end
+
+ context 'when scope is nil' do
+ subject { described_class.new(user, nil, params).execute }
+
+ it 'raises ArgumentError' do
+ expect { subject }.to raise_error(ArgumentError)
+ end
+ end
+ end
+end
diff --git a/spec/finders/deployments_finder_spec.rb b/spec/finders/deployments_finder_spec.rb
index 0f659fa1dab..b294f1117f5 100644
--- a/spec/finders/deployments_finder_spec.rb
+++ b/spec/finders/deployments_finder_spec.rb
@@ -5,6 +5,58 @@ require 'spec_helper'
RSpec.describe DeploymentsFinder do
subject { described_class.new(params).execute }
+ describe "validation" do
+ context 'when both updated_at and finished_at filters are specified' do
+ let(:params) { { updated_before: 1.day.ago, finished_before: 1.day.ago } }
+
+ it 'raises an error' do
+ expect { subject }.to raise_error(
+ described_class::InefficientQueryError,
+ 'Both `updated_at` filter and `finished_at` filter can not be specified')
+ end
+ end
+
+ context 'when updated_at filter and id sorting' do
+ let(:params) { { updated_before: 1.day.ago, order_by: :id } }
+
+ it 'raises an error' do
+ expect { subject }.to raise_error(
+ described_class::InefficientQueryError,
+ '`updated_at` filter and `updated_at` sorting must be paired')
+ end
+ end
+
+ context 'when finished_at filter and id sorting' do
+ let(:params) { { finished_before: 1.day.ago, order_by: :id } }
+
+ it 'raises an error' do
+ expect { subject }.to raise_error(
+ described_class::InefficientQueryError,
+ '`finished_at` filter and `finished_at` sorting must be paired')
+ end
+ end
+
+ context 'when finished_at filter with failed status filter' do
+ let(:params) { { finished_before: 1.day.ago, order_by: :finished_at, status: :failed } }
+
+ it 'raises an error' do
+ expect { subject }.to raise_error(
+ described_class::InefficientQueryError,
+ '`finished_at` filter must be combined with `success` status filter.')
+ end
+ end
+
+ context 'when environment filter with non-project scope' do
+ let(:params) { { environment: 'production' } }
+
+ it 'raises an error' do
+ expect { subject }.to raise_error(
+ described_class::InefficientQueryError,
+ '`environment` filter must be combined with `project` scope.')
+ end
+ end
+ end
+
describe "#execute" do
context 'when project or group is missing' do
let(:params) { {} }
@@ -20,13 +72,24 @@ RSpec.describe DeploymentsFinder do
describe 'filtering' do
context 'when updated_at filters are specified' do
- let(:params) { { **base_params, updated_before: 1.day.ago, updated_after: 3.days.ago } }
- let!(:deployment_1) { create(:deployment, :success, project: project, updated_at: 2.days.ago) }
- let!(:deployment_2) { create(:deployment, :success, project: project, updated_at: 4.days.ago) }
- let!(:deployment_3) { create(:deployment, :success, project: project, updated_at: 1.hour.ago) }
+ let_it_be(:deployment_1) { create(:deployment, :success, project: project, updated_at: 48.hours.ago) }
+ let_it_be(:deployment_2) { create(:deployment, :success, project: project, updated_at: 47.hours.ago) }
+ let_it_be(:deployment_3) { create(:deployment, :success, project: project, updated_at: 4.days.ago) }
+ let_it_be(:deployment_4) { create(:deployment, :success, project: project, updated_at: 1.hour.ago) }
+ let(:params) { { **base_params, updated_before: 1.day.ago, updated_after: 3.days.ago, order_by: :updated_at } }
it 'returns deployments with matched updated_at' do
- is_expected.to match_array([deployment_1])
+ is_expected.to match_array([deployment_2, deployment_1])
+ end
+
+ context 'when deployments_finder_implicitly_enforce_ordering_for_updated_at_filter feature flag is disabled' do
+ before do
+ stub_feature_flags(deployments_finder_implicitly_enforce_ordering_for_updated_at_filter: false)
+ end
+
+ it 'returns deployments with matched updated_at' do
+ is_expected.to match_array([deployment_1, deployment_2])
+ end
end
end
@@ -72,30 +135,34 @@ RSpec.describe DeploymentsFinder do
let(:params) { { **base_params, order_by: order_by, sort: sort } }
- let!(:deployment_1) { create(:deployment, :success, project: project, iid: 11, ref: 'master', created_at: 2.days.ago, updated_at: Time.now, finished_at: Time.now) }
- let!(:deployment_2) { create(:deployment, :success, project: project, iid: 12, ref: 'feature', created_at: 1.day.ago, updated_at: 2.hours.ago, finished_at: 2.hours.ago) }
- let!(:deployment_3) { create(:deployment, :success, project: project, iid: 8, ref: 'video', created_at: Time.now, updated_at: 1.hour.ago, finished_at: 1.hour.ago) }
+ let!(:deployment_1) { create(:deployment, :success, project: project, ref: 'master', created_at: 2.days.ago, updated_at: Time.now, finished_at: Time.now) }
+ let!(:deployment_2) { create(:deployment, :success, project: project, ref: 'feature', created_at: 1.day.ago, updated_at: 2.hours.ago, finished_at: 2.hours.ago) }
+ let!(:deployment_3) { create(:deployment, :success, project: project, ref: 'video', created_at: Time.now, updated_at: 1.hour.ago, finished_at: 1.hour.ago) }
where(:order_by, :sort, :ordered_deployments) do
'created_at' | 'asc' | [:deployment_1, :deployment_2, :deployment_3]
'created_at' | 'desc' | [:deployment_3, :deployment_2, :deployment_1]
'id' | 'asc' | [:deployment_1, :deployment_2, :deployment_3]
'id' | 'desc' | [:deployment_3, :deployment_2, :deployment_1]
- 'iid' | 'asc' | [:deployment_3, :deployment_1, :deployment_2]
- 'iid' | 'desc' | [:deployment_2, :deployment_1, :deployment_3]
+ 'iid' | 'asc' | [:deployment_1, :deployment_2, :deployment_3]
+ 'iid' | 'desc' | [:deployment_3, :deployment_2, :deployment_1]
'ref' | 'asc' | [:deployment_2, :deployment_1, :deployment_3]
'ref' | 'desc' | [:deployment_3, :deployment_1, :deployment_2]
- 'updated_at' | 'asc' | [:deployment_2, :deployment_3, :deployment_1]
- 'updated_at' | 'desc' | [:deployment_1, :deployment_3, :deployment_2]
- 'finished_at' | 'asc' | [:deployment_2, :deployment_3, :deployment_1]
- 'finished_at' | 'desc' | [:deployment_1, :deployment_3, :deployment_2]
+ 'updated_at' | 'asc' | described_class::InefficientQueryError
+ 'updated_at' | 'desc' | described_class::InefficientQueryError
+ 'finished_at' | 'asc' | described_class::InefficientQueryError
+ 'finished_at' | 'desc' | described_class::InefficientQueryError
'invalid' | 'asc' | [:deployment_1, :deployment_2, :deployment_3]
- 'iid' | 'err' | [:deployment_3, :deployment_1, :deployment_2]
+ 'iid' | 'err' | [:deployment_1, :deployment_2, :deployment_3]
end
with_them do
it 'returns the deployments ordered' do
- expect(subject).to eq(ordered_deployments.map { |name| public_send(name) })
+ if ordered_deployments == described_class::InefficientQueryError
+ expect { subject }.to raise_error(described_class::InefficientQueryError)
+ else
+ expect(subject).to eq(ordered_deployments.map { |name| public_send(name) })
+ end
end
end
end
@@ -112,8 +179,20 @@ RSpec.describe DeploymentsFinder do
end
end
- describe 'tie-breaker for `finished_at` sorting' do
- let(:params) { { **base_params, order_by: 'updated_at', sort: 'asc' } }
+ describe 'transform `iid` sorting to `id` sorting' do
+ let(:params) { { **base_params, order_by: 'iid', sort: 'asc' } }
+
+ it 'sorts by only one column' do
+ expect(subject.order_values.size).to eq(1)
+ end
+
+ it 'sorts by `id`' do
+ expect(subject.order_values.first.to_sql).to eq(Deployment.arel_table[:id].asc.to_sql)
+ end
+ end
+
+ describe 'tie-breaker for `updated_at` sorting' do
+ let(:params) { { **base_params, updated_after: 1.day.ago, order_by: 'updated_at', sort: 'asc' } }
it 'sorts by two columns' do
expect(subject.order_values.size).to eq(2)
@@ -122,17 +201,62 @@ RSpec.describe DeploymentsFinder do
it 'adds `id` sorting as the second order column' do
order_value = subject.order_values[1]
- expect(order_value.to_sql).to eq(Deployment.arel_table[:id].desc.to_sql)
+ expect(order_value.to_sql).to eq(Deployment.arel_table[:id].asc.to_sql)
end
- it 'uses the `id DESC` as tie-breaker when ordering' do
+ it 'uses the `id ASC` as tie-breaker when ordering' do
updated_at = Time.now
deployment_1 = create(:deployment, :success, project: project, updated_at: updated_at)
deployment_2 = create(:deployment, :success, project: project, updated_at: updated_at)
deployment_3 = create(:deployment, :success, project: project, updated_at: updated_at)
- expect(subject).to eq([deployment_3, deployment_2, deployment_1])
+ expect(subject).to eq([deployment_1, deployment_2, deployment_3])
+ end
+
+ context 'when sort direction is desc' do
+ let(:params) { { **base_params, updated_after: 1.day.ago, order_by: 'updated_at', sort: 'desc' } }
+
+ it 'uses the `id DESC` as tie-breaker when ordering' do
+ updated_at = Time.now
+
+ deployment_1 = create(:deployment, :success, project: project, updated_at: updated_at)
+ deployment_2 = create(:deployment, :success, project: project, updated_at: updated_at)
+ deployment_3 = create(:deployment, :success, project: project, updated_at: updated_at)
+
+ expect(subject).to eq([deployment_3, deployment_2, deployment_1])
+ end
+ end
+ end
+
+ describe 'enforce sorting to `updated_at` sorting' do
+ let(:params) { { **base_params, updated_before: 1.day.ago, order_by: 'id', sort: 'asc' } }
+
+ before do
+ allow(Gitlab::ErrorTracking).to receive(:track_and_raise_for_dev_exception)
+ end
+
+ it 'sorts by only one column' do
+ expect(subject.order_values.size).to eq(2)
+ end
+
+ it 'sorts by `updated_at`' do
+ expect(subject.order_values.first.to_sql).to eq(Deployment.arel_table[:updated_at].asc.to_sql)
+ expect(subject.order_values.second.to_sql).to eq(Deployment.arel_table[:id].asc.to_sql)
+ end
+
+ context 'when deployments_finder_implicitly_enforce_ordering_for_updated_at_filter feature flag is disabled' do
+ before do
+ stub_feature_flags(deployments_finder_implicitly_enforce_ordering_for_updated_at_filter: false)
+ end
+
+ it 'sorts by only one column' do
+ expect(subject.order_values.size).to eq(1)
+ end
+
+ it 'sorts by `id`' do
+ expect(subject.order_values.first.to_sql).to eq(Deployment.arel_table[:id].asc.to_sql)
+ end
end
end
@@ -142,23 +266,76 @@ RSpec.describe DeploymentsFinder do
let!(:deployment_3) { create(:deployment, :success, project: project, finished_at: 5.hours.ago) }
context 'when filtering by finished_after and finished_before' do
- let(:params) { { **base_params, finished_after: 3.days.ago, finished_before: 1.day.ago } }
+ let(:params) { { **base_params, finished_after: 3.days.ago, finished_before: 1.day.ago, status: :success, order_by: :finished_at } }
it { is_expected.to match_array([deployment_1]) }
end
context 'when the finished_before parameter is missing' do
- let(:params) { { **base_params, finished_after: 3.days.ago } }
+ let(:params) { { **base_params, finished_after: 3.days.ago, status: :success, order_by: :finished_at } }
it { is_expected.to match_array([deployment_1, deployment_3]) }
end
context 'when finished_after is missing' do
- let(:params) { { **base_params, finished_before: 3.days.ago } }
+ let(:params) { { **base_params, finished_before: 3.days.ago, status: :success, order_by: :finished_at } }
it { is_expected.to match_array([deployment_2]) }
end
end
end
+
+ context 'at group scope' do
+ let_it_be(:group) { create(:group) }
+ let_it_be(:subgroup) { create(:group, parent: group) }
+
+ let_it_be(:group_project_1) { create(:project, :public, :test_repo, group: group) }
+ let_it_be(:group_project_2) { create(:project, :public, :test_repo, group: group) }
+ let_it_be(:subgroup_project_1) { create(:project, :public, :test_repo, group: subgroup) }
+ let(:base_params) { { group: group } }
+
+ describe 'ordering' do
+ using RSpec::Parameterized::TableSyntax
+
+ let(:params) { { **base_params, order_by: order_by, sort: sort } }
+
+ let!(:group_project_1_deployment) { create(:deployment, :success, project: group_project_1, iid: 11, ref: 'master', created_at: 2.days.ago, updated_at: Time.now, finished_at: Time.now) }
+ let!(:group_project_2_deployment) { create(:deployment, :success, project: group_project_2, iid: 12, ref: 'feature', created_at: 1.day.ago, updated_at: 2.hours.ago, finished_at: 2.hours.ago) }
+ let!(:subgroup_project_1_deployment) { create(:deployment, :success, project: subgroup_project_1, iid: 8, ref: 'video', created_at: Time.now, updated_at: 1.hour.ago, finished_at: 1.hour.ago) }
+
+ where(:order_by, :sort) do
+ 'created_at' | 'asc'
+ 'created_at' | 'desc'
+ 'id' | 'asc'
+ 'id' | 'desc'
+ 'iid' | 'asc'
+ 'iid' | 'desc'
+ 'ref' | 'asc'
+ 'ref' | 'desc'
+ 'invalid' | 'asc'
+ 'iid' | 'err'
+ end
+
+ with_them do
+ it 'returns the deployments unordered' do
+ expect(subject.to_a).to contain_exactly(group_project_1_deployment,
+ group_project_2_deployment,
+ subgroup_project_1_deployment)
+ end
+ end
+ end
+
+ it 'avoids N+1 queries' do
+ execute_queries = -> { described_class.new({ group: group }).execute.first }
+ control_count = ActiveRecord::QueryRecorder.new { execute_queries }.count
+
+ new_project = create(:project, :repository, group: group)
+ new_env = create(:environment, project: new_project, name: "production")
+ create_list(:deployment, 2, status: :success, project: new_project, environment: new_env)
+ group.reload
+
+ expect { execute_queries }.not_to exceed_query_limit(control_count)
+ end
+ end
end
end
diff --git a/spec/finders/environment_names_finder_spec.rb b/spec/finders/environments/environment_names_finder_spec.rb
index fe00c800f0a..438f9e9ea7c 100644
--- a/spec/finders/environment_names_finder_spec.rb
+++ b/spec/finders/environments/environment_names_finder_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe EnvironmentNamesFinder do
+RSpec.describe Environments::EnvironmentNamesFinder do
describe '#execute' do
let!(:group) { create(:group) }
let!(:public_project) { create(:project, :public, namespace: group) }
diff --git a/spec/finders/environments_by_deployments_finder_spec.rb b/spec/finders/environments/environments_by_deployments_finder_spec.rb
index f5fcc4ef72a..1b86aced67d 100644
--- a/spec/finders/environments_by_deployments_finder_spec.rb
+++ b/spec/finders/environments/environments_by_deployments_finder_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe EnvironmentsByDeploymentsFinder do
+RSpec.describe Environments::EnvironmentsByDeploymentsFinder do
let(:project) { create(:project, :repository) }
let(:user) { project.creator }
let(:environment) { create(:environment, :available, project: project) }
diff --git a/spec/finders/environments_finder_spec.rb b/spec/finders/environments/environments_finder_spec.rb
index c2022331ad9..68c0c524478 100644
--- a/spec/finders/environments_finder_spec.rb
+++ b/spec/finders/environments/environments_finder_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe EnvironmentsFinder do
+RSpec.describe Environments::EnvironmentsFinder do
let(:project) { create(:project, :repository) }
let(:user) { project.creator }
let(:environment) { create(:environment, :available, project: project) }
diff --git a/spec/finders/issues_finder_spec.rb b/spec/finders/issues_finder_spec.rb
index a2aac857bf5..27466ab563f 100644
--- a/spec/finders/issues_finder_spec.rb
+++ b/spec/finders/issues_finder_spec.rb
@@ -1178,6 +1178,7 @@ RSpec.describe IssuesFinder do
it 'returns true' do
expect(finder.use_cte_for_search?).to be_truthy
+ expect(finder.execute.to_sql).to match(/^WITH "issues" AS #{Gitlab::Database::AsWithMaterialized.materialized_if_supported}/)
end
end
@@ -1186,6 +1187,7 @@ RSpec.describe IssuesFinder do
it 'returns true' do
expect(finder.use_cte_for_search?).to be_truthy
+ expect(finder.execute.to_sql).to match(/^WITH "issues" AS #{Gitlab::Database::AsWithMaterialized.materialized_if_supported}/)
end
end
end
diff --git a/spec/finders/merge_requests_finder_spec.rb b/spec/finders/merge_requests_finder_spec.rb
index 597d22801ca..3b835d366db 100644
--- a/spec/finders/merge_requests_finder_spec.rb
+++ b/spec/finders/merge_requests_finder_spec.rb
@@ -866,5 +866,36 @@ RSpec.describe MergeRequestsFinder do
end
end
end
+
+ describe '#count_by_state' do
+ let_it_be(:user) { create(:user) }
+ let_it_be(:project) { create(:project, :repository) }
+ let_it_be(:labels) { create_list(:label, 2, project: project) }
+ let_it_be(:merge_requests) { create_list(:merge_request, 4, :unique_branches, author: user, target_project: project, source_project: project, labels: labels) }
+
+ before do
+ project.add_developer(user)
+ end
+
+ context 'when filtering by multiple labels' do
+ it 'returns the correnct counts' do
+ counts = described_class.new(user, { label_name: labels.map(&:name) }).count_by_state
+
+ expect(counts[:all]).to eq(merge_requests.size)
+ end
+ end
+
+ context 'when filtering by approved_by_usernames' do
+ before do
+ merge_requests.each { |mr| mr.approved_by_users << user }
+ end
+
+ it 'returns the correnct counts' do
+ counts = described_class.new(user, { approved_by_usernames: [user.username] }).count_by_state
+
+ expect(counts[:all]).to eq(merge_requests.size)
+ end
+ end
+ end
end
end
diff --git a/spec/finders/packages/composer/packages_finder_spec.rb b/spec/finders/packages/composer/packages_finder_spec.rb
new file mode 100644
index 00000000000..d4328827de3
--- /dev/null
+++ b/spec/finders/packages/composer/packages_finder_spec.rb
@@ -0,0 +1,25 @@
+# frozen_string_literal: true
+require 'spec_helper'
+
+RSpec.describe ::Packages::Composer::PackagesFinder do
+ let_it_be(:user) { create(:user) }
+ let_it_be(:group) { create(:group) }
+ let_it_be(:project) { create(:project, group: group) }
+
+ let(:params) { {} }
+
+ describe '#execute' do
+ let_it_be(:composer_package) { create(:composer_package, project: project) }
+ let_it_be(:composer_package2) { create(:composer_package, project: project) }
+ let_it_be(:error_package) { create(:composer_package, :error, project: project) }
+ let_it_be(:composer_package3) { create(:composer_package) }
+
+ subject { described_class.new(user, group, params).execute }
+
+ before do
+ project.add_developer(user)
+ end
+
+ it { is_expected.to match_array([composer_package, composer_package2]) }
+ end
+end
diff --git a/spec/finders/packages/conan/package_finder_spec.rb b/spec/finders/packages/conan/package_finder_spec.rb
index 936a0e5ff4b..b26f8900090 100644
--- a/spec/finders/packages/conan/package_finder_spec.rb
+++ b/spec/finders/packages/conan/package_finder_spec.rb
@@ -11,7 +11,8 @@ RSpec.describe ::Packages::Conan::PackageFinder do
subject { described_class.new(user, query: query).execute }
- context 'packages that are not visible to user' do
+ context 'packages that are not installable' do
+ let!(:conan_package3) { create(:conan_package, :error, project: project) }
let!(:non_visible_project) { create(:project, :private) }
let!(:non_visible_conan_package) { create(:conan_package, project: non_visible_project) }
let(:query) { "#{conan_package.name.split('/').first[0, 3]}%" }
diff --git a/spec/finders/packages/generic/package_finder_spec.rb b/spec/finders/packages/generic/package_finder_spec.rb
index ed34268e7a9..707f943b285 100644
--- a/spec/finders/packages/generic/package_finder_spec.rb
+++ b/spec/finders/packages/generic/package_finder_spec.rb
@@ -23,6 +23,13 @@ RSpec.describe ::Packages::Generic::PackageFinder do
expect(found_package).to eq(package)
end
+ it 'does not find uninstallable packages' do
+ error_package = create(:generic_package, :error, project: project)
+
+ expect { finder.execute!(error_package.name, error_package.version) }
+ .to raise_error(ActiveRecord::RecordNotFound)
+ end
+
it 'raises ActiveRecord::RecordNotFound if package is not found' do
expect { finder.execute!(package.name, '3.1.4') }
.to raise_error(ActiveRecord::RecordNotFound)
diff --git a/spec/finders/packages/go/package_finder_spec.rb b/spec/finders/packages/go/package_finder_spec.rb
index b6fad1e7061..dbcb8255d47 100644
--- a/spec/finders/packages/go/package_finder_spec.rb
+++ b/spec/finders/packages/go/package_finder_spec.rb
@@ -7,7 +7,7 @@ RSpec.describe Packages::Go::PackageFinder do
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_it_be_with_refind(:package) { create :golang_package, project: project, name: mod.name, version: 'v1.0.1' }
let(:finder) { described_class.new(project, mod_name, version_name) }
@@ -54,6 +54,17 @@ RSpec.describe Packages::Go::PackageFinder do
it { is_expected.to eq(package) }
end
+ context 'with an uninstallable package' do
+ let(:mod_name) { mod.name }
+ let(:version_name) { version.name }
+
+ before do
+ package.update_column(:status, 1)
+ end
+
+ it { is_expected.to eq(nil) }
+ end
+
context 'with an invalid name' do
let(:mod_name) { 'foo/bar' }
let(:version_name) { 'baz' }
diff --git a/spec/finders/packages/group_or_project_package_finder_spec.rb b/spec/finders/packages/group_or_project_package_finder_spec.rb
new file mode 100644
index 00000000000..aaeec8e70d2
--- /dev/null
+++ b/spec/finders/packages/group_or_project_package_finder_spec.rb
@@ -0,0 +1,22 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe Packages::GroupOrProjectPackageFinder do
+ let_it_be(:user) { create(:user) }
+ let_it_be(:project) { create(:project) }
+
+ let(:finder) { described_class.new(user, project) }
+
+ describe 'execute' do
+ subject(:run_finder) { finder.execute }
+
+ it { expect { run_finder }.to raise_error(NotImplementedError) }
+ end
+
+ describe 'execute!' do
+ subject(:run_finder) { finder.execute! }
+
+ it { expect { run_finder }.to raise_error(NotImplementedError) }
+ end
+end
diff --git a/spec/finders/packages/group_packages_finder_spec.rb b/spec/finders/packages/group_packages_finder_spec.rb
index d6daf73aba2..29b2f0fffd7 100644
--- a/spec/finders/packages/group_packages_finder_spec.rb
+++ b/spec/finders/packages/group_packages_finder_spec.rb
@@ -122,7 +122,7 @@ RSpec.describe Packages::GroupPackagesFinder do
end
context 'when there are processing packages' do
- let_it_be(:package4) { create(:nuget_package, project: project, name: Packages::Nuget::TEMPORARY_PACKAGE_NAME) }
+ let_it_be(:package4) { create(:nuget_package, :processing, project: project) }
it { is_expected.to match_array([package1, package2]) }
end
diff --git a/spec/finders/packages/maven/package_finder_spec.rb b/spec/finders/packages/maven/package_finder_spec.rb
index ca144292501..13c603f1ec4 100644
--- a/spec/finders/packages/maven/package_finder_spec.rb
+++ b/spec/finders/packages/maven/package_finder_spec.rb
@@ -6,13 +6,12 @@ RSpec.describe ::Packages::Maven::PackageFinder do
let_it_be(:user) { create(:user) }
let_it_be(:group) { create(:group) }
let_it_be(:project) { create(:project, namespace: group) }
- let_it_be(:package) { create(:maven_package, project: project) }
+ let_it_be_with_refind(:package) { create(:maven_package, project: project) }
let(:param_path) { nil }
- let(:param_project) { nil }
- let(:param_group) { nil }
+ let(:project_or_group) { nil }
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) }
+ 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)
@@ -36,34 +35,28 @@ RSpec.describe ::Packages::Maven::PackageFinder do
expect { subject }.to raise_error(ActiveRecord::RecordNotFound)
end
end
+
+ context 'with an uninstallable package' do
+ let(:param_path) { package.maven_metadatum.path }
+
+ before do
+ package.update_column(:status, 1)
+ end
+
+ it { expect { subject }.to raise_error(ActiveRecord::RecordNotFound) }
+ end
end
context 'within the project' do
- let(:param_project) { project }
+ let(:project_or_group) { 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
+ let(:project_or_group) { group }
- it_behaves_like 'handling valid and invalid paths'
- end
+ it_behaves_like 'handling valid and invalid paths'
end
context 'across all projects' do
@@ -83,7 +76,7 @@ RSpec.describe ::Packages::Maven::PackageFinder do
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(:project_or_group) { group }
let(:param_path) { package_name }
before do
@@ -93,38 +86,14 @@ RSpec.describe ::Packages::Maven::PackageFinder do
create(:package_file, :xml, package: package2)
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 'without order by package file' do
- it { is_expected.to eq(package3) }
- end
-
- context 'with order by package file' do
- let(:param_order_by_package_file) { true }
-
- it { is_expected.to eq(package2) }
- end
+ context 'without order by package file' do
+ it { is_expected.to eq(package3) }
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 'with order by package file' do
+ let(:param_order_by_package_file) { true }
- 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
+ it { is_expected.to eq(package2) }
end
end
end
@@ -146,7 +115,7 @@ RSpec.describe ::Packages::Maven::PackageFinder do
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
+ sql = described_class.new(user, group, path: package.maven_metadatum.path).send(:packages).to_sql
expect(sql).to include('WITH "maven_metadata_by_path" AS')
end
diff --git a/spec/finders/packages/npm/package_finder_spec.rb b/spec/finders/packages/npm/package_finder_spec.rb
index f021d800f31..a995f3b96c4 100644
--- a/spec/finders/packages/npm/package_finder_spec.rb
+++ b/spec/finders/packages/npm/package_finder_spec.rb
@@ -3,7 +3,7 @@ require 'spec_helper'
RSpec.describe ::Packages::Npm::PackageFinder do
let_it_be_with_reload(:project) { create(:project)}
- let_it_be(:package) { create(:npm_package, project: project) }
+ let_it_be_with_refind(:package) { create(:npm_package, project: project) }
let(:project) { package.project }
let(:package_name) { package.name }
@@ -46,6 +46,14 @@ RSpec.describe ::Packages::Npm::PackageFinder do
it { is_expected.to be_empty }
end
+
+ context 'with an uninstallable package' do
+ before do
+ package.update_column(:status, 1)
+ end
+
+ it { is_expected.to be_empty }
+ end
end
subject { finder.execute }
diff --git a/spec/finders/packages/nuget/package_finder_spec.rb b/spec/finders/packages/nuget/package_finder_spec.rb
index 10b5f6c8ec2..59cca2d06dc 100644
--- a/spec/finders/packages/nuget/package_finder_spec.rb
+++ b/spec/finders/packages/nuget/package_finder_spec.rb
@@ -6,7 +6,7 @@ RSpec.describe Packages::Nuget::PackageFinder do
let_it_be(:group) { create(:group) }
let_it_be(:subgroup) { create(:group, parent: group) }
let_it_be(:project) { create(:project, namespace: subgroup) }
- let_it_be(:package1) { create(:nuget_package, project: project) }
+ let_it_be_with_refind(:package1) { create(:nuget_package, project: project) }
let_it_be(:package2) { create(:nuget_package, name: package1.name, version: '2.0.0', project: project) }
let_it_be(:package3) { create(:nuget_package, name: 'Another.Dummy.Package', project: project) }
let_it_be(:other_package_1) { create(:nuget_package, name: package1.name, version: package1.version) }
@@ -33,6 +33,14 @@ RSpec.describe Packages::Nuget::PackageFinder do
it { is_expected.to be_empty }
end
+ context 'with an uninstallable package' do
+ before do
+ package1.update_column(:status, 1)
+ end
+
+ it { is_expected.to contain_exactly(package2) }
+ end
+
context 'with valid version' do
let(:package_version) { '2.0.0' }
diff --git a/spec/finders/packages/package_finder_spec.rb b/spec/finders/packages/package_finder_spec.rb
index e8c7404a612..2bb4f05a41d 100644
--- a/spec/finders/packages/package_finder_spec.rb
+++ b/spec/finders/packages/package_finder_spec.rb
@@ -4,7 +4,7 @@ require 'spec_helper'
RSpec.describe ::Packages::PackageFinder do
let_it_be(:project) { create(:project) }
- let_it_be(:maven_package) { create(:maven_package, project: project) }
+ let_it_be_with_refind(:maven_package) { create(:maven_package, project: project) }
describe '#execute' do
let(:package_id) { maven_package.id }
@@ -13,8 +13,18 @@ RSpec.describe ::Packages::PackageFinder do
it { is_expected.to eq(maven_package) }
+ context 'with non-displayable package' do
+ before do
+ maven_package.update_column(:status, 1)
+ end
+
+ it 'raises an exception' do
+ expect { subject }.to raise_exception(ActiveRecord::RecordNotFound)
+ end
+ end
+
context 'processing packages' do
- let_it_be(:nuget_package) { create(:nuget_package, project: project, name: Packages::Nuget::TEMPORARY_PACKAGE_NAME) }
+ let_it_be(:nuget_package) { create(:nuget_package, :processing, project: project) }
let(:package_id) { nuget_package.id }
it 'are not returned' do
diff --git a/spec/finders/packages/packages_finder_spec.rb b/spec/finders/packages/packages_finder_spec.rb
index 0add77a8478..b72f4aab3ec 100644
--- a/spec/finders/packages/packages_finder_spec.rb
+++ b/spec/finders/packages/packages_finder_spec.rb
@@ -76,7 +76,7 @@ RSpec.describe ::Packages::PackagesFinder do
end
context 'with processing packages' do
- let_it_be(:nuget_package) { create(:nuget_package, project: project, name: Packages::Nuget::TEMPORARY_PACKAGE_NAME) }
+ let_it_be(:nuget_package) { create(:nuget_package, :processing, project: project) }
it { is_expected.to match_array([conan_package, maven_package]) }
end
diff --git a/spec/finders/packages/pypi/package_finder_spec.rb b/spec/finders/packages/pypi/package_finder_spec.rb
new file mode 100644
index 00000000000..7d9eb8a5cd1
--- /dev/null
+++ b/spec/finders/packages/pypi/package_finder_spec.rb
@@ -0,0 +1,45 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe Packages::Pypi::PackageFinder do
+ let_it_be(:user) { create(:user) }
+ let_it_be(:group) { create(:group) }
+ let_it_be(:project) { create(:project, group: group) }
+ let_it_be(:project2) { create(:project, group: group) }
+ let_it_be(:package1) { create(:pypi_package, project: project) }
+ let_it_be(:package2) { create(:pypi_package, project: project) }
+ let_it_be(:package3) { create(:pypi_package, project: project2) }
+
+ let(:package_file) { package2.package_files.first }
+ let(:params) do
+ {
+ filename: package_file.file_name,
+ sha256: package_file.file_sha256
+ }
+ end
+
+ describe 'execute' do
+ subject { described_class.new(user, scope, params).execute }
+
+ context 'within a project' do
+ let(:scope) { project }
+
+ it { is_expected.to eq(package2) }
+ end
+
+ context 'within a group' do
+ let(:scope) { group }
+
+ it { expect { subject }.to raise_error(ActiveRecord::RecordNotFound) }
+
+ context 'user with access' do
+ before do
+ project.add_developer(user)
+ end
+
+ it { is_expected.to eq(package2) }
+ end
+ end
+ end
+end
diff --git a/spec/finders/packages/pypi/packages_finder_spec.rb b/spec/finders/packages/pypi/packages_finder_spec.rb
new file mode 100644
index 00000000000..a69c2317261
--- /dev/null
+++ b/spec/finders/packages/pypi/packages_finder_spec.rb
@@ -0,0 +1,70 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe Packages::Pypi::PackagesFinder do
+ let_it_be(:user) { create(:user) }
+ let_it_be(:group) { create(:group) }
+ let_it_be(:project) { create(:project, group: group) }
+ let_it_be(:project2) { create(:project, group: group) }
+ let_it_be(:package1) { create(:pypi_package, project: project) }
+ let_it_be(:package2) { create(:pypi_package, project: project) }
+ let_it_be(:package3) { create(:pypi_package, name: package2.name, project: project) }
+ let_it_be(:package4) { create(:pypi_package, name: package2.name, project: project2) }
+
+ let(:package_name) { package2.name }
+
+ describe 'execute!' do
+ subject { described_class.new(user, scope, package_name: package_name).execute! }
+
+ shared_examples 'when no package is found' do
+ context 'non-existing package' do
+ let(:package_name) { 'none' }
+
+ it { expect { subject }.to raise_error(ActiveRecord::RecordNotFound) }
+ end
+ end
+
+ shared_examples 'when package_name param is a non-normalized name' do
+ context 'non-existing package' do
+ let(:package_name) { package2.name.upcase.tr('-', '.') }
+
+ it { expect { subject }.to raise_error(ActiveRecord::RecordNotFound) }
+ end
+ end
+
+ context 'within a project' do
+ let(:scope) { project }
+
+ it { is_expected.to contain_exactly(package2, package3) }
+
+ it_behaves_like 'when no package is found'
+ it_behaves_like 'when package_name param is a non-normalized name'
+ end
+
+ context 'within a group' do
+ let(:scope) { group }
+
+ it { expect { subject }.to raise_error(ActiveRecord::RecordNotFound) }
+
+ context 'user with access to only one project' do
+ before do
+ project2.add_developer(user)
+ end
+
+ it { is_expected.to contain_exactly(package4) }
+
+ it_behaves_like 'when no package is found'
+ it_behaves_like 'when package_name param is a non-normalized name'
+
+ context ' user with access to multiple projects' do
+ before do
+ project.add_developer(user)
+ end
+
+ it { is_expected.to contain_exactly(package2, package3, package4) }
+ end
+ end
+ end
+ end
+end
diff --git a/spec/finders/projects/groups_finder_spec.rb b/spec/finders/projects/groups_finder_spec.rb
index 89d4edaec7c..7f01b73c7ca 100644
--- a/spec/finders/projects/groups_finder_spec.rb
+++ b/spec/finders/projects/groups_finder_spec.rb
@@ -8,7 +8,7 @@ RSpec.describe Projects::GroupsFinder do
let_it_be(:root_group) { create(:group, :public) }
let_it_be(:project_group) { create(:group, :public, parent: root_group) }
let_it_be(:shared_group_with_dev_access) { create(:group, :private, parent: root_group) }
- let_it_be(:shared_group_with_reporter_access) { create(:group, :private) }
+ let_it_be(:shared_group_with_reporter_access) { create(:group, :public) }
let_it_be(:public_project) { create(:project, :public, group: project_group) }
let_it_be(:private_project) { create(:project, :private, group: project_group) }
@@ -53,6 +53,24 @@ RSpec.describe Projects::GroupsFinder do
is_expected.to match_array([project_group, root_group, shared_group_with_dev_access])
end
end
+
+ context 'when shared_visible_only is on' do
+ let(:params) { super().merge(shared_visible_only: true) }
+
+ it 'returns ancestor and public shared groups' do
+ is_expected.to match_array([project_group, root_group, shared_group_with_reporter_access])
+ end
+
+ context 'when user has access to the private shared group' do
+ before do
+ shared_group_with_dev_access.add_guest(current_user)
+ end
+
+ it 'returns ancestor and shared groups user has access to' do
+ is_expected.to match_array([project_group, root_group, shared_group_with_reporter_access, shared_group_with_dev_access])
+ end
+ end
+ end
end
context 'when skip group option is on' do
@@ -74,6 +92,19 @@ RSpec.describe Projects::GroupsFinder do
it 'returns ancestor groups for this project' do
is_expected.to match_array([project_group, root_group])
end
+
+ context 'when visible shared groups are requested' do
+ let(:params) do
+ {
+ with_shared: true,
+ shared_visible_only: true
+ }
+ end
+
+ it 'returns ancestor groups and public shared groups for this project' do
+ is_expected.to match_array([project_group, root_group, shared_group_with_reporter_access])
+ end
+ end
end
end
end
diff --git a/spec/finders/projects/members/effective_access_level_finder_spec.rb b/spec/finders/projects/members/effective_access_level_finder_spec.rb
new file mode 100644
index 00000000000..1112dbd0d6e
--- /dev/null
+++ b/spec/finders/projects/members/effective_access_level_finder_spec.rb
@@ -0,0 +1,257 @@
+# frozen_string_literal: true
+require 'spec_helper'
+
+RSpec.describe Projects::Members::EffectiveAccessLevelFinder, '#execute' do
+ let_it_be(:group) { create(:group) }
+ let_it_be(:project) { create(:project, group: group) }
+
+ # The result set is being converted to json just for the ease of testing.
+ subject { described_class.new(project).execute.as_json }
+
+ context 'for a personal project' do
+ let_it_be(:project) { create(:project) }
+
+ shared_examples_for 'includes access level of the owner of the project as Maintainer' do
+ it 'includes access level of the owner of the project as Maintainer' do
+ expect(subject).to(
+ contain_exactly(
+ hash_including(
+ 'user_id' => project.namespace.owner.id,
+ 'access_level' => Gitlab::Access::MAINTAINER
+ )
+ )
+ )
+ end
+ end
+
+ context 'when the project owner is a member of the project' do
+ it_behaves_like 'includes access level of the owner of the project as Maintainer'
+ end
+
+ context 'when the project owner is not explicitly a member of the project' do
+ before do
+ project.members.find_by(user_id: project.namespace.owner.id).destroy!
+ end
+
+ it_behaves_like 'includes access level of the owner of the project as Maintainer'
+ end
+ end
+
+ context 'direct members of the project' do
+ it 'includes access levels of the direct members of the project' do
+ developer = create(:project_member, :developer, source: project)
+ maintainer = create(:project_member, :maintainer, source: project)
+
+ expect(subject).to(
+ include(
+ hash_including(
+ 'user_id' => developer.user.id,
+ 'access_level' => Gitlab::Access::DEVELOPER
+ ),
+ hash_including(
+ 'user_id' => maintainer.user.id,
+ 'access_level' => Gitlab::Access::MAINTAINER
+ )
+ )
+ )
+ end
+
+ it 'does not include access levels of users who have requested access to the project' do
+ member_with_access_request = create(:project_member, :access_request, :developer, source: project)
+
+ expect(subject).not_to(
+ include(
+ hash_including(
+ 'user_id' => member_with_access_request.user.id
+ )
+ )
+ )
+ end
+
+ it 'includes access levels of users who are in non-active state' do
+ blocked_member = create(:project_member, :blocked, :developer, source: project)
+
+ expect(subject).to(
+ include(
+ hash_including(
+ 'user_id' => blocked_member.user.id,
+ 'access_level' => Gitlab::Access::DEVELOPER
+ )
+ )
+ )
+ end
+ end
+
+ context 'for a project within a group' do
+ context 'project in a root group' do
+ it 'includes access levels of users who are direct members of the parent group' do
+ group_member = create(:group_member, :developer, source: group)
+
+ expect(subject).to(
+ include(
+ hash_including(
+ 'user_id' => group_member.user.id,
+ 'access_level' => Gitlab::Access::DEVELOPER
+ )
+ )
+ )
+ end
+ end
+
+ context 'project in a subgroup' do
+ let_it_be(:project) { create(:project, group: create(:group, :nested)) }
+
+ it 'includes access levels of users who are members of the ancestors of the parent group' do
+ group_member = create(:group_member, :maintainer, source: project.group.parent)
+
+ expect(subject).to(
+ include(
+ hash_including(
+ 'user_id' => group_member.user.id,
+ 'access_level' => Gitlab::Access::MAINTAINER
+ )
+ )
+ )
+ end
+ end
+
+ context 'user is both a member of the project and a member of the parent group' do
+ let_it_be(:user) { create(:user) }
+
+ before do
+ group.add_developer(user)
+ project.add_maintainer(user)
+ end
+
+ it 'includes the maximum access level among project and group membership' do
+ expect(subject).to(
+ include(
+ hash_including(
+ 'user_id' => user.id,
+ 'access_level' => Gitlab::Access::MAINTAINER
+ )
+ )
+ )
+ end
+ end
+
+ context 'members from group share' do
+ let_it_be(:shared_with_group) { create(:group) }
+ let_it_be(:user_from_shared_with_group) { create(:user) }
+
+ before do
+ shared_with_group.add_guest(user_from_shared_with_group)
+ create(:group_group_link, :developer, shared_group: project.group, shared_with_group: shared_with_group)
+ end
+
+ it 'includes the user from the group share with the right access level' do
+ expect(subject).to(
+ include(
+ hash_including(
+ 'user_id' => user_from_shared_with_group.id,
+ 'access_level' => Gitlab::Access::GUEST
+ )
+ )
+ )
+ end
+
+ context 'when the project also has the same user as a member, but with a different access level' do
+ before do
+ project.add_maintainer(user_from_shared_with_group)
+ end
+
+ it 'includes the maximum access level among project and group membership' do
+ expect(subject).to(
+ include(
+ hash_including(
+ 'user_id' => user_from_shared_with_group.id,
+ 'access_level' => Gitlab::Access::MAINTAINER
+ )
+ )
+ )
+ end
+ end
+
+ context "when the project's ancestor also has the same user as a member, but with a different access level" do
+ before do
+ project.group.add_maintainer(user_from_shared_with_group)
+ end
+
+ it 'includes the maximum access level among project and group membership' do
+ expect(subject).to(
+ include(
+ hash_including(
+ 'user_id' => user_from_shared_with_group.id,
+ 'access_level' => Gitlab::Access::MAINTAINER
+ )
+ )
+ )
+ end
+ end
+ end
+ end
+
+ context 'for a project that is shared with other group(s)' do
+ let_it_be(:shared_with_group) { create(:group) }
+ let_it_be(:user_from_shared_with_group) { create(:user) }
+
+ before do
+ create(:project_group_link, :developer, project: project, group: shared_with_group)
+ shared_with_group.add_maintainer(user_from_shared_with_group)
+ end
+
+ it 'includes the least among the specified access levels' do
+ expect(subject).to(
+ include(
+ hash_including(
+ 'user_id' => user_from_shared_with_group.id,
+ 'access_level' => Gitlab::Access::DEVELOPER
+ )
+ )
+ )
+ end
+
+ context 'when the group containing the project has forbidden group shares for any of its projects' do
+ let_it_be(:project) { create(:project, group: create(:group)) }
+
+ before do
+ project.namespace.update!(share_with_group_lock: true)
+ end
+
+ it 'does not include the users from any group shares' do
+ expect(subject).not_to(
+ include(
+ hash_including(
+ 'user_id' => user_from_shared_with_group.id
+ )
+ )
+ )
+ end
+ end
+ end
+
+ context 'a combination of all possible avenues of membership' do
+ let_it_be(:user) { create(:user) }
+ let_it_be(:shared_with_group) { create(:group) }
+
+ before do
+ create(:project_group_link, :maintainer, project: project, group: shared_with_group)
+ create(:group_group_link, :reporter, shared_group: project.group, shared_with_group: shared_with_group)
+
+ shared_with_group.add_maintainer(user)
+ group.add_guest(user)
+ project.add_developer(user)
+ end
+
+ it 'includes the highest access level from all avenues of memberships' do
+ expect(subject).to(
+ include(
+ hash_including(
+ 'user_id' => user.id,
+ 'access_level' => Gitlab::Access::MAINTAINER # From project_group_link
+ )
+ )
+ )
+ end
+ end
+end
diff --git a/spec/finders/projects_finder_spec.rb b/spec/finders/projects_finder_spec.rb
index a178261e899..364e5de4ece 100644
--- a/spec/finders/projects_finder_spec.rb
+++ b/spec/finders/projects_finder_spec.rb
@@ -139,7 +139,7 @@ RSpec.describe ProjectsFinder do
describe 'filter by tags' do
before do
- public_project.tag_list.add('foo')
+ public_project.tag_list = 'foo'
public_project.save!
end
diff --git a/spec/finders/repositories/branch_names_finder_spec.rb b/spec/finders/repositories/branch_names_finder_spec.rb
index 4d8bfcc0f20..40f5d339832 100644
--- a/spec/finders/repositories/branch_names_finder_spec.rb
+++ b/spec/finders/repositories/branch_names_finder_spec.rb
@@ -5,21 +5,34 @@ 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'
+ it 'returns all filtered branch names' do
+ expect(create_branch_names_finder(0, 100).execute).to contain_exactly(
+ 'snippet/edit-file',
+ 'snippet/multiple-files',
+ 'snippet/no-files',
+ 'snippet/rename-and-edit-file',
+ 'snippet/single-file'
)
end
+
+ it 'returns a limited number of offset filtered branch names' do
+ starting_names = create_branch_names_finder(0, 3).execute
+ offset_names = create_branch_names_finder(3, 2).execute
+
+ expect(starting_names.count).to eq(3)
+ expect(offset_names.count).to eq(2)
+
+ expect(offset_names).not_to include(*starting_names)
+
+ all_names = create_branch_names_finder(0, 100).execute
+ expect(all_names).to contain_exactly(*starting_names, *offset_names)
+ end
+
+ private
+
+ def create_branch_names_finder(offset, limit)
+ described_class.new(project.repository, search: 'snippet/*', offset: offset, limit: limit)
+ end
end
end
diff --git a/spec/finders/template_finder_spec.rb b/spec/finders/template_finder_spec.rb
index 164975fdfb6..b7339288c51 100644
--- a/spec/finders/template_finder_spec.rb
+++ b/spec/finders/template_finder_spec.rb
@@ -21,7 +21,6 @@ RSpec.describe TemplateFinder do
:gitignores | 'Actionscript'
:gitlab_ci_ymls | 'Android'
:metrics_dashboard_ymls | 'Default'
- :gitlab_ci_syntax_ymls | 'Artifacts example'
end
with_them do
@@ -110,7 +109,6 @@ RSpec.describe TemplateFinder do
:gitlab_ci_ymls | described_class
:licenses | ::LicenseTemplateFinder
:metrics_dashboard_ymls | described_class
- :gitlab_ci_syntax_ymls | described_class
:issues | described_class
:merge_requests | described_class
end
@@ -160,7 +158,6 @@ RSpec.describe TemplateFinder do
:gitignores | 'Actionscript'
:gitlab_ci_ymls | 'Android'
:metrics_dashboard_ymls | 'Default'
- :gitlab_ci_syntax_ymls | 'Artifacts example'
end
with_them do
diff --git a/spec/finders/users_with_pending_todos_finder_spec.rb b/spec/finders/users_with_pending_todos_finder_spec.rb
deleted file mode 100644
index 565b65fbefe..00000000000
--- a/spec/finders/users_with_pending_todos_finder_spec.rb
+++ /dev/null
@@ -1,19 +0,0 @@
-# frozen_string_literal: true
-
-require 'spec_helper'
-
-RSpec.describe UsersWithPendingTodosFinder do
- describe '#execute' do
- it 'returns the users for all pending todos of a target' do
- issue = create(:issue)
- note = create(:note)
- todo = create(:todo, :pending, target: issue)
-
- create(:todo, :pending, target: note)
-
- users = described_class.new(issue).execute
-
- expect(users).to eq([todo.user])
- end
- end
-end