summaryrefslogtreecommitdiff
path: root/spec/finders
diff options
context:
space:
mode:
Diffstat (limited to 'spec/finders')
-rw-r--r--spec/finders/error_tracking/errors_finder_spec.rb53
-rw-r--r--spec/finders/group_members_finder_spec.rb33
-rw-r--r--spec/finders/groups/projects_requiring_authorizations_refresh/on_direct_membership_finder_spec.rb73
-rw-r--r--spec/finders/groups/projects_requiring_authorizations_refresh/on_transfer_finder_spec.rb59
-rw-r--r--spec/finders/incident_management/timeline_events_finder_spec.rb56
-rw-r--r--spec/finders/issues_finder/params_spec.rb49
-rw-r--r--spec/finders/issues_finder_spec.rb234
-rw-r--r--spec/finders/merge_requests_finder_spec.rb3
-rw-r--r--spec/finders/packages/build_infos_finder_spec.rb120
-rw-r--r--spec/finders/packages/build_infos_for_many_packages_finder_spec.rb136
-rw-r--r--spec/finders/personal_access_tokens_finder_spec.rb18
-rw-r--r--spec/finders/projects/serverless/functions_finder_spec.rb185
-rw-r--r--spec/finders/releases_finder_spec.rb126
13 files changed, 480 insertions, 665 deletions
diff --git a/spec/finders/error_tracking/errors_finder_spec.rb b/spec/finders/error_tracking/errors_finder_spec.rb
deleted file mode 100644
index 66eb7769a4c..00000000000
--- a/spec/finders/error_tracking/errors_finder_spec.rb
+++ /dev/null
@@ -1,53 +0,0 @@
-# frozen_string_literal: true
-
-require 'spec_helper'
-
-RSpec.describe ErrorTracking::ErrorsFinder do
- let_it_be(:project) { create(:project) }
- let_it_be(:user) { project.creator }
- let_it_be(:error) { create(:error_tracking_error, project: project) }
- let_it_be(:error_resolved) { create(:error_tracking_error, :resolved, project: project, first_seen_at: 2.hours.ago) }
- let_it_be(:error_yesterday) { create(:error_tracking_error, project: project, first_seen_at: Time.zone.now.yesterday) }
-
- before do
- project.add_maintainer(user)
- end
-
- describe '#execute' do
- let(:params) { {} }
-
- subject { described_class.new(user, project, params).execute }
-
- it { is_expected.to contain_exactly(error, error_resolved, error_yesterday) }
-
- context 'with status parameter' do
- let(:params) { { status: 'resolved' } }
-
- it { is_expected.to contain_exactly(error_resolved) }
- end
-
- context 'with sort parameter' do
- let(:params) { { status: 'unresolved', sort: 'first_seen' } }
-
- it { expect(subject.to_a).to eq([error, error_yesterday]) }
- end
-
- context 'pagination' do
- let(:params) { { limit: '1', sort: 'first_seen' } }
-
- # Sort by first_seen is DESC by default, so the most recent error is `error`
- it { is_expected.to contain_exactly(error) }
-
- it { expect(subject.has_next_page?).to be_truthy }
-
- it 'returns next page by cursor' do
- params_with_cursor = params.merge(cursor: subject.cursor_for_next_page)
- errors = described_class.new(user, project, params_with_cursor).execute
-
- expect(errors).to contain_exactly(error_resolved)
- expect(errors.has_next_page?).to be_truthy
- expect(errors.has_previous_page?).to be_truthy
- end
- end
- end
-end
diff --git a/spec/finders/group_members_finder_spec.rb b/spec/finders/group_members_finder_spec.rb
index a9a8e9d19b8..00aa14209a2 100644
--- a/spec/finders/group_members_finder_spec.rb
+++ b/spec/finders/group_members_finder_spec.rb
@@ -195,4 +195,37 @@ RSpec.describe GroupMembersFinder, '#execute' do
expect(result.to_a).to match_array([member1])
end
end
+
+ context 'filter by access levels' do
+ let!(:owner1) { group.add_owner(user2) }
+ let!(:owner2) { group.add_owner(user3) }
+ let!(:maintainer1) { group.add_maintainer(user4) }
+ let!(:maintainer2) { group.add_maintainer(user5) }
+
+ subject(:by_access_levels) { described_class.new(group, user1, params: { access_levels: access_levels }).execute }
+
+ context 'by owner' do
+ let(:access_levels) { ::Gitlab::Access::OWNER }
+
+ it 'returns owners' do
+ expect(by_access_levels).to match_array([owner1, owner2])
+ end
+ end
+
+ context 'by maintainer' do
+ let(:access_levels) { ::Gitlab::Access::MAINTAINER }
+
+ it 'returns owners' do
+ expect(by_access_levels).to match_array([maintainer1, maintainer2])
+ end
+ end
+
+ context 'by owner and maintainer' do
+ let(:access_levels) { [::Gitlab::Access::OWNER, ::Gitlab::Access::MAINTAINER] }
+
+ it 'returns owners and maintainers' do
+ expect(by_access_levels).to match_array([owner1, owner2, maintainer1, maintainer2])
+ end
+ end
+ end
end
diff --git a/spec/finders/groups/projects_requiring_authorizations_refresh/on_direct_membership_finder_spec.rb b/spec/finders/groups/projects_requiring_authorizations_refresh/on_direct_membership_finder_spec.rb
new file mode 100644
index 00000000000..8cdfa13ba3a
--- /dev/null
+++ b/spec/finders/groups/projects_requiring_authorizations_refresh/on_direct_membership_finder_spec.rb
@@ -0,0 +1,73 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe Groups::ProjectsRequiringAuthorizationsRefresh::OnDirectMembershipFinder do
+ # rubocop:disable Layout/LineLength
+
+ # Group X Group A ------shared with-------------> Group B Group C
+ # | Group X_subgroup_1 | | |
+ # | | Project X_subgroup_1 ---shared with----->| Group A_subgroup_1 | Group B_subgroup_1 <--shared with--------- | Group C_subgroup_1
+ # | | | Project A_subgroup_1 | | Project B_subgroup_1 | | Project C_subgroup_1
+ # | Group A_subgroup_2 | Group B_subgroup_2 <----shared with ------- Project C
+ # | |Project A_subgroup_2 | | Project B_subgroup_2
+
+ # rubocop:enable Layout/LineLength
+
+ let_it_be(:group_x) { create(:group) }
+ let_it_be(:group_a) { create(:group) }
+ let_it_be(:group_b) { create(:group) }
+ let_it_be(:group_c) { create(:group) }
+ let_it_be(:group_x_subgroup_1) { create(:group, parent: group_x) }
+ let_it_be(:group_a_subgroup_1) { create(:group, parent: group_a) }
+ let_it_be(:group_a_subgroup_2) { create(:group, parent: group_a) }
+ let_it_be(:group_b_subgroup_1) { create(:group, parent: group_b) }
+ let_it_be(:group_b_subgroup_2) { create(:group, parent: group_b) }
+ let_it_be(:group_c_subgroup_1) { create(:group, parent: group_c) }
+ let_it_be(:project_x_subgroup_1) { create(:project, group: group_x_subgroup_1, name: 'project_x_subgroup_1') }
+ let_it_be(:project_a_subgroup_1) { create(:project, group: group_a_subgroup_1, name: 'project_a_subgroup_1') }
+ let_it_be(:project_a_subgroup_2) { create(:project, group: group_a_subgroup_2, name: 'project_a_subgroup_2') }
+ let_it_be(:project_b_subgroup_1) { create(:project, group: group_b_subgroup_1, name: 'project_b_subgroup_1') }
+ let_it_be(:project_b_subgroup_2) { create(:project, group: group_b_subgroup_2, name: 'project_b_subgroup_2') }
+ let_it_be(:project_c_subgroup_1) { create(:project, group: group_c_subgroup_1, name: 'project_c_subgroup_1') }
+ let_it_be(:project_c) { create(:project, group: group_c, name: 'project_c') }
+
+ describe '#execute' do
+ context 'projects affected when a new member is added to a specific group (here, `Group B`)' do
+ subject(:result) { described_class.new(group_b).execute }
+
+ before do
+ create(:project_group_link, project: project_x_subgroup_1, group: group_a_subgroup_1)
+ create(:project_group_link, project: project_c, group: group_b_subgroup_2)
+ create(:group_group_link, shared_group: group_a, shared_with_group: group_b)
+ create(:group_group_link, shared_group: group_c_subgroup_1, shared_with_group: group_b_subgroup_1)
+ end
+
+ it 'returns all projects IDs where authorizations need to be created for the user'\
+ 'due to their new membership being created in `Group B`' do
+ new_user = create(:user)
+ group_b.add_maintainer(new_user)
+
+ expect(result).to match_array(new_user.authorized_projects.ids)
+ end
+
+ it 'includes only the expected projects' do
+ expected_projects = Project.id_in(
+ [
+ project_b_subgroup_1, # direct member of Group B gets access to this project due to group hierarchy
+ project_b_subgroup_2, # direct member of Group B gets access to this project due to group hierarchy
+ project_c, # direct member of Group B gets access to this project via project-group share
+ project_a_subgroup_1, # direct member of Group B gets access to this project via group share
+ project_a_subgroup_2, # direct member of Group B gets access to this project via group share
+
+ # direct member of Group B gets access to any projects shared with groups within its shared groups.
+ project_x_subgroup_1
+ ]
+ )
+ # project_c_subgroup_1 is not included in the list because only 'direct' members of
+ # `group_b_subgroup_1` gets access to that project via the group-group share.
+ expect(result).to match_array(expected_projects.ids)
+ end
+ end
+ end
+end
diff --git a/spec/finders/groups/projects_requiring_authorizations_refresh/on_transfer_finder_spec.rb b/spec/finders/groups/projects_requiring_authorizations_refresh/on_transfer_finder_spec.rb
new file mode 100644
index 00000000000..103cef44c94
--- /dev/null
+++ b/spec/finders/groups/projects_requiring_authorizations_refresh/on_transfer_finder_spec.rb
@@ -0,0 +1,59 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe Groups::ProjectsRequiringAuthorizationsRefresh::OnTransferFinder do
+ # rubocop:disable Layout/LineLength
+
+ # Group X Group A ------shared with-------------> Group B Group C
+ # | Group X_subgroup_1 | | |
+ # | | Project X_subgroup_1 ---shared with----->| Group A_subgroup_1 | Group B_subgroup_1 <--shared with--------- | Group C_subgroup_1
+ # | | | Project A_subgroup_1 | | Project B_subgroup_1 | | Project C_subgroup_1
+ # | Group A_subgroup_2 | Group B_subgroup_2 <----shared with ------- Project C
+ # | |Project A_subgroup_2 | | Project B_subgroup_2
+
+ # rubocop:enable Layout/LineLength
+
+ let_it_be(:group_x) { create(:group) }
+ let_it_be(:group_a) { create(:group) }
+ let_it_be(:group_b) { create(:group) }
+ let_it_be(:group_c) { create(:group) }
+ let_it_be(:group_x_subgroup_1) { create(:group, parent: group_x) }
+ let_it_be(:group_a_subgroup_1) { create(:group, parent: group_a) }
+ let_it_be(:group_a_subgroup_2) { create(:group, parent: group_a) }
+ let_it_be(:group_b_subgroup_1) { create(:group, parent: group_b) }
+ let_it_be(:group_b_subgroup_2) { create(:group, parent: group_b) }
+ let_it_be(:group_c_subgroup_1) { create(:group, parent: group_c) }
+ let_it_be(:project_x_subgroup_1) { create(:project, group: group_x_subgroup_1, name: 'project_x_subgroup_1') }
+ let_it_be(:project_a_subgroup_1) { create(:project, group: group_a_subgroup_1, name: 'project_a_subgroup_1') }
+ let_it_be(:project_a_subgroup_2) { create(:project, group: group_a_subgroup_2, name: 'project_a_subgroup_2') }
+ let_it_be(:project_b_subgroup_1) { create(:project, group: group_b_subgroup_1, name: 'project_b_subgroup_1') }
+ let_it_be(:project_b_subgroup_2) { create(:project, group: group_b_subgroup_2, name: 'project_b_subgroup_2') }
+ let_it_be(:project_c_subgroup_1) { create(:project, group: group_c_subgroup_1, name: 'project_c_subgroup_1') }
+ let_it_be(:project_c) { create(:project, group: group_c, name: 'project_c') }
+
+ describe '#execute' do
+ context 'projects requiring authorizations refresh when a group is transferred (here, `Group B`)' do
+ subject(:result) { described_class.new(group_b).execute }
+
+ before do
+ create(:project_group_link, project: project_x_subgroup_1, group: group_a_subgroup_1)
+ create(:project_group_link, project: project_c, group: group_b_subgroup_2)
+ create(:group_group_link, shared_group: group_a, shared_with_group: group_b)
+ create(:group_group_link, shared_group: group_c_subgroup_1, shared_with_group: group_b_subgroup_1)
+ end
+
+ it 'includes only the expected projects' do
+ expected_projects = Project.id_in(
+ [
+ project_b_subgroup_1,
+ project_b_subgroup_2,
+ project_c
+ ]
+ )
+
+ expect(result).to match_array(expected_projects.ids)
+ end
+ end
+ end
+end
diff --git a/spec/finders/incident_management/timeline_events_finder_spec.rb b/spec/finders/incident_management/timeline_events_finder_spec.rb
new file mode 100644
index 00000000000..aa01391c343
--- /dev/null
+++ b/spec/finders/incident_management/timeline_events_finder_spec.rb
@@ -0,0 +1,56 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe IncidentManagement::TimelineEventsFinder do
+ let_it_be(:user) { create(:user) }
+ let_it_be(:project) { create(:project, :private) }
+ let_it_be(:incident) { create(:incident, project: project) }
+ let_it_be(:another_incident) { create(:incident, project: project) }
+
+ let_it_be(:timeline_event1) do
+ create(:incident_management_timeline_event, project: project, incident: incident, occurred_at: Time.current)
+ end
+
+ let_it_be(:timeline_event2) do
+ create(:incident_management_timeline_event, project: project, incident: incident, occurred_at: 1.minute.ago)
+ end
+
+ let_it_be(:timeline_event_of_another_incident) do
+ create(:incident_management_timeline_event, project: project, incident: another_incident)
+ end
+
+ let(:params) { {} }
+
+ describe '#execute' do
+ subject(:execute) { described_class.new(user, incident, params).execute }
+
+ context 'when user has permissions' do
+ before do
+ project.add_guest(user)
+ end
+
+ it 'returns timeline events' do
+ is_expected.to match_array([timeline_event2, timeline_event1])
+ end
+
+ context 'when filtering by ID' do
+ let(:params) { { id: timeline_event1 } }
+
+ it 'returns only matched timeline event' do
+ is_expected.to contain_exactly(timeline_event1)
+ end
+ end
+
+ context 'when incident is nil' do
+ let_it_be(:incident) { nil }
+
+ it { is_expected.to eq(IncidentManagement::TimelineEvent.none) }
+ end
+ end
+
+ context 'when user has no permissions' do
+ it { is_expected.to eq(IncidentManagement::TimelineEvent.none) }
+ end
+ end
+end
diff --git a/spec/finders/issues_finder/params_spec.rb b/spec/finders/issues_finder/params_spec.rb
deleted file mode 100644
index 879ecc364a2..00000000000
--- a/spec/finders/issues_finder/params_spec.rb
+++ /dev/null
@@ -1,49 +0,0 @@
-# frozen_string_literal: true
-
-require 'spec_helper'
-
-RSpec.describe IssuesFinder::Params do
- describe '#include_hidden' do
- subject { described_class.new(params, user, IssuesFinder) }
-
- context 'when param is not set' do
- let(:params) { {} }
-
- context 'with an admin', :enable_admin_mode do
- let(:user) { create(:user, :admin) }
-
- it 'returns true' do
- expect(subject.include_hidden?).to be_truthy
- end
- end
-
- context 'with a regular user' do
- let(:user) { create(:user) }
-
- it 'returns false' do
- expect(subject.include_hidden?).to be_falsey
- end
- end
- end
-
- context 'when param is set' do
- let(:params) { { include_hidden: true } }
-
- context 'with an admin', :enable_admin_mode do
- let(:user) { create(:user, :admin) }
-
- it 'returns true' do
- expect(subject.include_hidden?).to be_truthy
- end
- end
-
- context 'with a regular user' do
- let(:user) { create(:user) }
-
- it 'returns false' do
- expect(subject.include_hidden?).to be_falsey
- end
- end
- end
- end
-end
diff --git a/spec/finders/issues_finder_spec.rb b/spec/finders/issues_finder_spec.rb
index aa9357a686a..3f5a55410d2 100644
--- a/spec/finders/issues_finder_spec.rb
+++ b/spec/finders/issues_finder_spec.rb
@@ -12,52 +12,8 @@ RSpec.describe IssuesFinder do
context 'scope: all' do
let(:scope) { 'all' }
- context 'include_hidden and public_only params' do
- let_it_be(:banned_user) { create(:user, :banned) }
- let_it_be(:hidden_issue) { create(:issue, project: project1, author: banned_user) }
- let_it_be(:confidential_issue) { create(:issue, project: project1, confidential: true) }
-
- context 'when user is an admin', :enable_admin_mode do
- let(:user) { create(:user, :admin) }
-
- it 'returns all issues' do
- expect(issues).to contain_exactly(issue1, issue2, issue3, issue4, issue5, hidden_issue, confidential_issue)
- end
- end
-
- context 'when user is not an admin' do
- context 'when public_only is true' do
- let(:params) { { public_only: true } }
-
- it 'returns public issues' do
- expect(issues).to contain_exactly(issue1, issue2, issue3, issue4, issue5)
- end
- end
-
- context 'when public_only is false' do
- let(:params) { { public_only: false } }
-
- it 'returns public and confidential issues' do
- expect(issues).to contain_exactly(issue1, issue2, issue3, issue4, issue5, confidential_issue)
- end
- end
-
- context 'when public_only is not set' do
- it 'returns public and confidential issue' do
- expect(issues).to contain_exactly(issue1, issue2, issue3, issue4, issue5, confidential_issue)
- end
- end
-
- context 'when ban_user_feature_flag is false' do
- before do
- stub_feature_flags(ban_user_feature_flag: false)
- end
-
- it 'returns all issues' do
- expect(issues).to contain_exactly(issue1, issue2, issue3, issue4, issue5, hidden_issue, confidential_issue)
- end
- end
- end
+ it 'returns all issues' do
+ expect(issues).to contain_exactly(issue1, issue2, issue3, issue4, issue5)
end
context 'user does not have read permissions' do
@@ -1148,64 +1104,132 @@ RSpec.describe IssuesFinder do
end
describe '#with_confidentiality_access_check' do
- let(:user) { create(:user) }
+ let(:guest) { create(:user) }
let_it_be(:authorized_user) { create(:user) }
+ let_it_be(:banned_user) { create(:user, :banned) }
let_it_be(:project) { create(:project, namespace: authorized_user.namespace) }
let_it_be(:public_issue) { create(:issue, project: project) }
let_it_be(:confidential_issue) { create(:issue, project: project, confidential: true) }
+ let_it_be(:hidden_issue) { create(:issue, project: project, author: banned_user) }
- shared_examples 'returns public, does not return confidential' do
+ shared_examples 'returns public, does not return hidden or confidential' do
it 'returns only public issues' do
expect(subject).to include(public_issue)
- expect(subject).not_to include(confidential_issue)
+ expect(subject).not_to include(confidential_issue, hidden_issue)
end
end
- shared_examples 'returns public and confidential' do
- it 'returns public and confidential issues' do
+ shared_examples 'returns public and confidential, does not return hidden' do
+ it 'returns only public and confidential issues' do
expect(subject).to include(public_issue, confidential_issue)
+ expect(subject).not_to include(hidden_issue)
end
end
- subject { described_class.new(user, params).with_confidentiality_access_check }
+ shared_examples 'returns public and hidden, does not return confidential' do
+ it 'returns only public and hidden issues' do
+ expect(subject).to include(public_issue, hidden_issue)
+ expect(subject).not_to include(confidential_issue)
+ end
+ end
+
+ shared_examples 'returns public, confidential, and hidden' do
+ it 'returns all issues' do
+ expect(subject).to include(public_issue, confidential_issue, hidden_issue)
+ end
+ end
context 'when no project filter is given' do
let(:params) { {} }
context 'for an anonymous user' do
- it_behaves_like 'returns public, does not return confidential'
+ subject { described_class.new(nil, params).with_confidentiality_access_check }
+
+ it_behaves_like 'returns public, does not return hidden or confidential'
+
+ context 'when feature flag is disabled' do
+ before do
+ stub_feature_flags(ban_user_feature_flag: false)
+ end
+
+ it_behaves_like 'returns public and hidden, does not return confidential'
+ end
end
context 'for a user without project membership' do
- it_behaves_like 'returns public, does not return confidential'
+ subject { described_class.new(user, params).with_confidentiality_access_check }
+
+ it_behaves_like 'returns public, does not return hidden or confidential'
+
+ context 'when feature flag is disabled' do
+ before do
+ stub_feature_flags(ban_user_feature_flag: false)
+ end
+
+ it_behaves_like 'returns public and hidden, does not return confidential'
+ end
end
context 'for a guest user' do
+ subject { described_class.new(guest, params).with_confidentiality_access_check }
+
before do
- project.add_guest(user)
+ project.add_guest(guest)
end
- it_behaves_like 'returns public, does not return confidential'
+ it_behaves_like 'returns public, does not return hidden or confidential'
+
+ context 'when feature flag is disabled' do
+ before do
+ stub_feature_flags(ban_user_feature_flag: false)
+ end
+
+ it_behaves_like 'returns public and hidden, does not return confidential'
+ end
end
context 'for a project member with access to view confidential issues' do
- before do
- project.add_reporter(user)
- end
+ subject { described_class.new(authorized_user, params).with_confidentiality_access_check }
- it_behaves_like 'returns public and confidential'
+ it_behaves_like 'returns public and confidential, does not return hidden'
+
+ context 'when feature flag is disabled' do
+ before do
+ stub_feature_flags(ban_user_feature_flag: false)
+ end
+
+ it_behaves_like 'returns public, confidential, and hidden'
+ end
end
context 'for an admin' do
- let(:user) { create(:user, :admin) }
+ let(:admin_user) { create(:user, :admin) }
+
+ subject { described_class.new(admin_user, params).with_confidentiality_access_check }
context 'when admin mode is enabled', :enable_admin_mode do
- it_behaves_like 'returns public and confidential'
+ it_behaves_like 'returns public, confidential, and hidden'
+
+ context 'when feature flag is disabled' do
+ before do
+ stub_feature_flags(ban_user_feature_flag: false)
+ end
+
+ it_behaves_like 'returns public, confidential, and hidden'
+ end
end
context 'when admin mode is disabled' do
- it_behaves_like 'returns public, does not return confidential'
+ it_behaves_like 'returns public, does not return hidden or confidential'
+
+ context 'when feature flag is disabled' do
+ before do
+ stub_feature_flags(ban_user_feature_flag: false)
+ end
+
+ it_behaves_like 'returns public and hidden, does not return confidential'
+ end
end
end
end
@@ -1214,9 +1238,17 @@ RSpec.describe IssuesFinder do
let(:params) { { project_id: project.id } }
context 'for an anonymous user' do
- let(:user) { nil }
+ subject { described_class.new(nil, params).with_confidentiality_access_check }
- it_behaves_like 'returns public, does not return confidential'
+ it_behaves_like 'returns public, does not return hidden or confidential'
+
+ context 'when feature flag is disabled' do
+ before do
+ stub_feature_flags(ban_user_feature_flag: false)
+ end
+
+ it_behaves_like 'returns public and hidden, does not return confidential'
+ end
it 'does not filter by confidentiality' do
expect(Issue).not_to receive(:where).with(a_string_matching('confidential'), anything)
@@ -1225,7 +1257,17 @@ RSpec.describe IssuesFinder do
end
context 'for a user without project membership' do
- it_behaves_like 'returns public, does not return confidential'
+ subject { described_class.new(user, params).with_confidentiality_access_check }
+
+ it_behaves_like 'returns public, does not return hidden or confidential'
+
+ context 'when feature flag is disabled' do
+ before do
+ stub_feature_flags(ban_user_feature_flag: false)
+ end
+
+ it_behaves_like 'returns public and hidden, does not return confidential'
+ end
it 'filters by confidentiality' do
expect(subject.to_sql).to match("issues.confidential")
@@ -1233,11 +1275,21 @@ RSpec.describe IssuesFinder do
end
context 'for a guest user' do
+ subject { described_class.new(guest, params).with_confidentiality_access_check }
+
before do
- project.add_guest(user)
+ project.add_guest(guest)
end
- it_behaves_like 'returns public, does not return confidential'
+ it_behaves_like 'returns public, does not return hidden or confidential'
+
+ context 'when feature flag is disabled' do
+ before do
+ stub_feature_flags(ban_user_feature_flag: false)
+ end
+
+ it_behaves_like 'returns public and hidden, does not return confidential'
+ end
it 'filters by confidentiality' do
expect(subject.to_sql).to match("issues.confidential")
@@ -1245,18 +1297,40 @@ RSpec.describe IssuesFinder do
end
context 'for a project member with access to view confidential issues' do
- before do
- project.add_reporter(user)
+ subject { described_class.new(authorized_user, params).with_confidentiality_access_check }
+
+ it_behaves_like 'returns public and confidential, does not return hidden'
+
+ context 'when feature flag is disabled' do
+ before do
+ stub_feature_flags(ban_user_feature_flag: false)
+ end
+
+ it_behaves_like 'returns public, confidential, and hidden'
end
- it_behaves_like 'returns public and confidential'
+ it 'does not filter by confidentiality' do
+ expect(Issue).not_to receive(:where).with(a_string_matching('confidential'), anything)
+
+ subject
+ end
end
context 'for an admin' do
- let(:user) { create(:user, :admin) }
+ let(:admin_user) { create(:user, :admin) }
+
+ subject { described_class.new(admin_user, params).with_confidentiality_access_check }
context 'when admin mode is enabled', :enable_admin_mode do
- it_behaves_like 'returns public and confidential'
+ it_behaves_like 'returns public, confidential, and hidden'
+
+ context 'when feature flag is disabled' do
+ before do
+ stub_feature_flags(ban_user_feature_flag: false)
+ end
+
+ it_behaves_like 'returns public, confidential, and hidden'
+ end
it 'does not filter by confidentiality' do
expect(Issue).not_to receive(:where).with(a_string_matching('confidential'), anything)
@@ -1266,7 +1340,19 @@ RSpec.describe IssuesFinder do
end
context 'when admin mode is disabled' do
- it_behaves_like 'returns public, does not return confidential'
+ it_behaves_like 'returns public, does not return hidden or confidential'
+
+ context 'when feature flag is disabled' do
+ before do
+ stub_feature_flags(ban_user_feature_flag: false)
+ end
+
+ it_behaves_like 'returns public and hidden, does not return confidential'
+ end
+
+ it 'filters by confidentiality' do
+ expect(subject.to_sql).to match("issues.confidential")
+ end
end
end
end
diff --git a/spec/finders/merge_requests_finder_spec.rb b/spec/finders/merge_requests_finder_spec.rb
index 1f63f69a411..96466e99105 100644
--- a/spec/finders/merge_requests_finder_spec.rb
+++ b/spec/finders/merge_requests_finder_spec.rb
@@ -414,6 +414,9 @@ RSpec.describe MergeRequestsFinder do
before do
reviewer = merge_request1.find_reviewer(user2)
reviewer.update!(state: :reviewed)
+
+ merge_request2.find_reviewer(user2).update!(state: :attention_requested)
+ merge_request3.find_assignee(user2).update!(state: :attention_requested)
end
context 'by username' do
diff --git a/spec/finders/packages/build_infos_finder_spec.rb b/spec/finders/packages/build_infos_finder_spec.rb
index 23425de4316..6e7f0623030 100644
--- a/spec/finders/packages/build_infos_finder_spec.rb
+++ b/spec/finders/packages/build_infos_finder_spec.rb
@@ -9,7 +9,20 @@ RSpec.describe ::Packages::BuildInfosFinder do
let_it_be(:build_infos) { create_list(:package_build_info, 5, :with_pipeline, package: package) }
let_it_be(:build_info_with_empty_pipeline) { create(:package_build_info, package: package) }
- let(:finder) { described_class.new(package, params) }
+ let_it_be(:other_package) { create(:package) }
+ let_it_be(:other_build_infos) { create_list(:package_build_info, 5, :with_pipeline, package: other_package) }
+ let_it_be(:other_build_info_with_empty_pipeline) { create(:package_build_info, package: other_package) }
+
+ let_it_be(:all_build_infos) { build_infos + other_build_infos }
+
+ let(:finder) { described_class.new(packages, params) }
+ let(:packages) { nil }
+ let(:first) { nil }
+ let(:last) { nil }
+ let(:after) { nil }
+ let(:before) { nil }
+ let(:max_page_size) { nil }
+ let(:support_next_page) { false }
let(:params) do
{
first: first,
@@ -24,41 +37,100 @@ RSpec.describe ::Packages::BuildInfosFinder do
describe '#execute' do
subject { finder.execute }
- where(:first, :last, :after_index, :before_index, :max_page_size, :support_next_page, :expected_build_infos_indexes) do
- # F L AI BI MPS SNP
- nil | nil | nil | nil | nil | false | [4, 3, 2, 1, 0]
- nil | nil | nil | nil | 10 | false | [4, 3, 2, 1, 0]
- nil | nil | nil | nil | 2 | false | [4, 3]
- 2 | nil | nil | nil | nil | false | [4, 3]
- 2 | nil | nil | nil | nil | true | [4, 3, 2]
- 2 | nil | 3 | nil | nil | false | [2, 1]
- 2 | nil | 3 | nil | nil | true | [2, 1, 0]
- 3 | nil | 4 | nil | 2 | false | [3, 2]
- 3 | nil | 4 | nil | 2 | true | [3, 2, 1]
- nil | 2 | nil | nil | nil | false | [0, 1]
- nil | 2 | nil | nil | nil | true | [0, 1, 2]
- nil | 2 | nil | 1 | nil | false | [2, 3]
- nil | 2 | nil | 1 | nil | true | [2, 3, 4]
- nil | 3 | nil | 0 | 2 | false | [1, 2]
- nil | 3 | nil | 0 | 2 | true | [1, 2, 3]
- end
-
- with_them do
+ shared_examples 'returning the expected build infos' do
let(:expected_build_infos) do
expected_build_infos_indexes.map do |idx|
- build_infos[idx]
+ all_build_infos[idx]
end
end
let(:after) do
- build_infos[after_index].pipeline_id if after_index
+ all_build_infos[after_index].pipeline_id if after_index
end
let(:before) do
- build_infos[before_index].pipeline_id if before_index
+ all_build_infos[before_index].pipeline_id if before_index
end
it { is_expected.to eq(expected_build_infos) }
end
+
+ context 'with nil packages' do
+ let(:packages) { nil }
+
+ it { is_expected.to be_empty }
+ end
+
+ context 'with [] packages' do
+ let(:packages) { [] }
+
+ it { is_expected.to be_empty }
+ end
+
+ context 'with empy scope packages' do
+ let(:packages) { Packages::Package.none }
+
+ it { is_expected.to be_empty }
+ end
+
+ context 'with a single package' do
+ let(:packages) { package.id }
+
+ # rubocop: disable Layout/LineLength
+ where(:first, :last, :after_index, :before_index, :max_page_size, :support_next_page, :expected_build_infos_indexes) do
+ # F L AI BI MPS SNP
+ nil | nil | nil | nil | nil | false | [4, 3, 2, 1, 0]
+ nil | nil | nil | nil | 10 | false | [4, 3, 2, 1, 0]
+ nil | nil | nil | nil | 2 | false | [4, 3]
+ 2 | nil | nil | nil | nil | false | [4, 3]
+ 2 | nil | nil | nil | nil | true | [4, 3, 2]
+ 2 | nil | 3 | nil | nil | false | [2, 1]
+ 2 | nil | 3 | nil | nil | true | [2, 1, 0]
+ 3 | nil | 4 | nil | 2 | false | [3, 2]
+ 3 | nil | 4 | nil | 2 | true | [3, 2, 1]
+ nil | 2 | nil | nil | nil | false | [1, 0]
+ nil | 2 | nil | nil | nil | true | [2, 1, 0]
+ nil | 2 | nil | 1 | nil | false | [3, 2]
+ nil | 2 | nil | 1 | nil | true | [4, 3, 2]
+ nil | 3 | nil | 0 | 2 | false | [2, 1]
+ nil | 3 | nil | 0 | 2 | true | [3, 2, 1]
+ end
+ # rubocop: enable Layout/LineLength
+
+ with_them do
+ it_behaves_like 'returning the expected build infos'
+ end
+ end
+
+ context 'with many packages' do
+ let(:packages) { [package.id, other_package.id] }
+
+ # using after_index/before_index when receiving multiple packages doesn't
+ # make sense but we still verify here that the behavior is coherent.
+ # rubocop: disable Layout/LineLength
+ where(:first, :last, :after_index, :before_index, :max_page_size, :support_next_page, :expected_build_infos_indexes) do
+ # F L AI BI MPS SNP
+ nil | nil | nil | nil | nil | false | [9, 8, 7, 6, 5, 4, 3, 2, 1, 0]
+ nil | nil | nil | nil | 10 | false | [9, 8, 7, 6, 5, 4, 3, 2, 1, 0]
+ nil | nil | nil | nil | 2 | false | [9, 8, 4, 3]
+ 2 | nil | nil | nil | nil | false | [9, 8, 4, 3]
+ 2 | nil | nil | nil | nil | true | [9, 8, 7, 4, 3, 2]
+ 2 | nil | 3 | nil | nil | false | [2, 1]
+ 2 | nil | 3 | nil | nil | true | [2, 1, 0]
+ 3 | nil | 4 | nil | 2 | false | [3, 2]
+ 3 | nil | 4 | nil | 2 | true | [3, 2, 1]
+ nil | 2 | nil | nil | nil | false | [6, 5, 1, 0]
+ nil | 2 | nil | nil | nil | true | [7, 6, 5, 2, 1, 0]
+ nil | 2 | nil | 1 | nil | false | [6, 5, 3, 2]
+ nil | 2 | nil | 1 | nil | true | [7, 6, 5, 4, 3, 2]
+ nil | 3 | nil | 0 | 2 | false | [6, 5, 2, 1]
+ nil | 3 | nil | 0 | 2 | true | [7, 6, 5, 3, 2, 1]
+ end
+
+ with_them do
+ it_behaves_like 'returning the expected build infos'
+ end
+ # rubocop: enable Layout/LineLength
+ end
end
end
diff --git a/spec/finders/packages/build_infos_for_many_packages_finder_spec.rb b/spec/finders/packages/build_infos_for_many_packages_finder_spec.rb
deleted file mode 100644
index f3c79d0c825..00000000000
--- a/spec/finders/packages/build_infos_for_many_packages_finder_spec.rb
+++ /dev/null
@@ -1,136 +0,0 @@
-# frozen_string_literal: true
-
-require 'spec_helper'
-
-RSpec.describe ::Packages::BuildInfosForManyPackagesFinder do
- using RSpec::Parameterized::TableSyntax
-
- let_it_be(:package) { create(:package) }
- let_it_be(:build_infos) { create_list(:package_build_info, 5, :with_pipeline, package: package) }
- let_it_be(:build_info_with_empty_pipeline) { create(:package_build_info, package: package) }
-
- let_it_be(:other_package) { create(:package) }
- let_it_be(:other_build_infos) { create_list(:package_build_info, 5, :with_pipeline, package: other_package) }
- let_it_be(:other_build_info_with_empty_pipeline) { create(:package_build_info, package: other_package) }
-
- let_it_be(:all_build_infos) { build_infos + other_build_infos }
-
- let(:finder) { described_class.new(packages, params) }
- let(:packages) { nil }
- let(:first) { nil }
- let(:last) { nil }
- let(:after) { nil }
- let(:before) { nil }
- let(:max_page_size) { nil }
- let(:support_next_page) { false }
- let(:params) do
- {
- first: first,
- last: last,
- after: after,
- before: before,
- max_page_size: max_page_size,
- support_next_page: support_next_page
- }
- end
-
- describe '#execute' do
- subject { finder.execute }
-
- shared_examples 'returning the expected build infos' do
- let(:expected_build_infos) do
- expected_build_infos_indexes.map do |idx|
- all_build_infos[idx]
- end
- end
-
- let(:after) do
- all_build_infos[after_index].pipeline_id if after_index
- end
-
- let(:before) do
- all_build_infos[before_index].pipeline_id if before_index
- end
-
- it { is_expected.to eq(expected_build_infos) }
- end
-
- context 'with nil packages' do
- let(:packages) { nil }
-
- it { is_expected.to be_empty }
- end
-
- context 'with [] packages' do
- let(:packages) { [] }
-
- it { is_expected.to be_empty }
- end
-
- context 'with empy scope packages' do
- let(:packages) { Packages::Package.none }
-
- it { is_expected.to be_empty }
- end
-
- context 'with a single package' do
- let(:packages) { package.id }
-
- # rubocop: disable Layout/LineLength
- where(:first, :last, :after_index, :before_index, :max_page_size, :support_next_page, :expected_build_infos_indexes) do
- # F L AI BI MPS SNP
- nil | nil | nil | nil | nil | false | [4, 3, 2, 1, 0]
- nil | nil | nil | nil | 10 | false | [4, 3, 2, 1, 0]
- nil | nil | nil | nil | 2 | false | [4, 3]
- 2 | nil | nil | nil | nil | false | [4, 3]
- 2 | nil | nil | nil | nil | true | [4, 3, 2]
- 2 | nil | 3 | nil | nil | false | [2, 1]
- 2 | nil | 3 | nil | nil | true | [2, 1, 0]
- 3 | nil | 4 | nil | 2 | false | [3, 2]
- 3 | nil | 4 | nil | 2 | true | [3, 2, 1]
- nil | 2 | nil | nil | nil | false | [1, 0]
- nil | 2 | nil | nil | nil | true | [2, 1, 0]
- nil | 2 | nil | 1 | nil | false | [3, 2]
- nil | 2 | nil | 1 | nil | true | [4, 3, 2]
- nil | 3 | nil | 0 | 2 | false | [2, 1]
- nil | 3 | nil | 0 | 2 | true | [3, 2, 1]
- end
- # rubocop: enable Layout/LineLength
-
- with_them do
- it_behaves_like 'returning the expected build infos'
- end
- end
-
- context 'with many packages' do
- let(:packages) { [package.id, other_package.id] }
-
- # using after_index/before_index when receiving multiple packages doesn't
- # make sense but we still verify here that the behavior is coherent.
- # rubocop: disable Layout/LineLength
- where(:first, :last, :after_index, :before_index, :max_page_size, :support_next_page, :expected_build_infos_indexes) do
- # F L AI BI MPS SNP
- nil | nil | nil | nil | nil | false | [9, 8, 7, 6, 5, 4, 3, 2, 1, 0]
- nil | nil | nil | nil | 10 | false | [9, 8, 7, 6, 5, 4, 3, 2, 1, 0]
- nil | nil | nil | nil | 2 | false | [9, 8, 4, 3]
- 2 | nil | nil | nil | nil | false | [9, 8, 4, 3]
- 2 | nil | nil | nil | nil | true | [9, 8, 7, 4, 3, 2]
- 2 | nil | 3 | nil | nil | false | [2, 1]
- 2 | nil | 3 | nil | nil | true | [2, 1, 0]
- 3 | nil | 4 | nil | 2 | false | [3, 2]
- 3 | nil | 4 | nil | 2 | true | [3, 2, 1]
- nil | 2 | nil | nil | nil | false | [6, 5, 1, 0]
- nil | 2 | nil | nil | nil | true | [7, 6, 5, 2, 1, 0]
- nil | 2 | nil | 1 | nil | false | [6, 5, 3, 2]
- nil | 2 | nil | 1 | nil | true | [7, 6, 5, 4, 3, 2]
- nil | 3 | nil | 0 | 2 | false | [6, 5, 2, 1]
- nil | 3 | nil | 0 | 2 | true | [7, 6, 5, 3, 2, 1]
- end
-
- with_them do
- it_behaves_like 'returning the expected build infos'
- end
- # rubocop: enable Layout/LineLength
- end
- end
-end
diff --git a/spec/finders/personal_access_tokens_finder_spec.rb b/spec/finders/personal_access_tokens_finder_spec.rb
index 7607d08dc64..f22bff62082 100644
--- a/spec/finders/personal_access_tokens_finder_spec.rb
+++ b/spec/finders/personal_access_tokens_finder_spec.rb
@@ -286,24 +286,6 @@ RSpec.describe PersonalAccessTokensFinder do
end
end
- describe 'with active or expired state' do
- before do
- params[:state] = 'active_or_expired'
- end
-
- it 'includes active tokens' do
- is_expected.to include(active_personal_access_token, active_impersonation_token)
- end
-
- it 'includes expired tokens' do
- is_expected.to include(expired_personal_access_token, expired_impersonation_token)
- end
-
- it 'does not include revoked tokens' do
- is_expected.not_to include(revoked_personal_access_token, revoked_impersonation_token)
- end
- end
-
describe 'with id' do
subject { finder(params).find_by_id(active_personal_access_token.id) }
diff --git a/spec/finders/projects/serverless/functions_finder_spec.rb b/spec/finders/projects/serverless/functions_finder_spec.rb
deleted file mode 100644
index 9b58da2e398..00000000000
--- a/spec/finders/projects/serverless/functions_finder_spec.rb
+++ /dev/null
@@ -1,185 +0,0 @@
-# frozen_string_literal: true
-
-require 'spec_helper'
-
-RSpec.describe Projects::Serverless::FunctionsFinder do
- include KubernetesHelpers
- include PrometheusHelpers
- include ReactiveCachingHelpers
-
- let(:user) { create(:user) }
- let(:project) { create(:project, :repository) }
- let(:cluster) { create(:cluster, :project, :provided_by_gcp, projects: [project]) }
- let(:service) { cluster.platform_kubernetes }
- let(:environment) { create(:environment, project: project) }
- let!(:deployment) { create(:deployment, :success, environment: environment, cluster: cluster) }
- let(:knative_services_finder) { environment.knative_services_finder }
-
- let(:namespace) do
- create(:cluster_kubernetes_namespace,
- cluster: cluster,
- project: project,
- environment: environment)
- end
-
- before do
- project.add_maintainer(user)
- end
-
- describe '#knative_installed' do
- context 'when environment does not exist yet' do
- shared_examples 'before first deployment' do
- let(:service) { cluster.platform_kubernetes }
- let(:deployment) { nil }
-
- it 'returns true if Knative is installed on cluster' do
- stub_kubeclient_discover_knative_found(service.api_url)
- function_finder = described_class.new(project)
- synchronous_reactive_cache(function_finder)
-
- expect(function_finder.knative_installed).to be true
- end
-
- it 'returns false if Knative is not installed on cluster' do
- stub_kubeclient_discover_knative_not_found(service.api_url)
- function_finder = described_class.new(project)
- synchronous_reactive_cache(function_finder)
-
- expect(function_finder.knative_installed).to be false
- end
- end
-
- context 'when project level cluster is present and enabled' do
- it_behaves_like 'before first deployment' do
- let(:cluster) { create(:cluster, :project, :provided_by_gcp, enabled: true) }
- let(:project) { cluster.project }
- end
- end
-
- context 'when group level cluster is present and enabled' do
- it_behaves_like 'before first deployment' do
- let(:cluster) { create(:cluster, :group, :provided_by_gcp, enabled: true) }
- let(:project) { create(:project, group: cluster.groups.first) }
- end
- end
-
- context 'when instance level cluster is present and enabled' do
- it_behaves_like 'before first deployment' do
- let(:project) { create(:project) }
- let(:cluster) { create(:cluster, :instance, :provided_by_gcp, enabled: true) }
- end
- end
-
- context 'when project level cluster is present, but disabled' do
- let(:cluster) { create(:cluster, :project, :provided_by_gcp, enabled: false) }
- let(:project) { cluster.project }
- let(:service) { cluster.platform_kubernetes }
- let(:deployment) { nil }
-
- it 'returns false even if Knative is installed on cluster' do
- stub_kubeclient_discover_knative_found(service.api_url)
- function_finder = described_class.new(project)
- synchronous_reactive_cache(function_finder)
-
- expect(function_finder.knative_installed).to be false
- end
- end
- end
-
- context 'when reactive_caching is still fetching data' do
- it 'returns "checking"' do
- expect(described_class.new(project).knative_installed).to eq 'checking'
- end
- end
-
- context 'when reactive_caching has finished' do
- before do
- allow(Clusters::KnativeServicesFinder)
- .to receive(:new)
- .and_return(knative_services_finder)
- synchronous_reactive_cache(knative_services_finder)
- end
-
- context 'when knative is not installed' do
- it 'returns false' do
- stub_kubeclient_discover_knative_not_found(service.api_url)
-
- expect(described_class.new(project).knative_installed).to eq false
- end
- end
-
- context 'reactive_caching is finished and knative is installed' do
- it 'returns true' do
- stub_kubeclient_knative_services(namespace: namespace.namespace)
- stub_kubeclient_service_pods(nil, namespace: namespace.namespace)
-
- expect(described_class.new(project).knative_installed).to be true
- end
- end
- end
- end
-
- describe 'retrieve data from knative' do
- context 'does not have knative installed' do
- it { expect(described_class.new(project).execute).to be_empty }
- end
-
- context 'has knative installed' do
- let!(:knative) { create(:clusters_applications_knative, :installed, cluster: cluster) }
- let(:finder) { described_class.new(project) }
-
- it 'there are no functions' do
- expect(finder.execute).to be_empty
- end
-
- it 'there are functions', :use_clean_rails_memory_store_caching do
- stub_kubeclient_service_pods
- stub_reactive_cache(knative_services_finder,
- {
- services: kube_knative_services_body(namespace: namespace.namespace, name: cluster.project.name)["items"],
- pods: kube_knative_pods_body(cluster.project.name, namespace.namespace)["items"]
- },
- *knative_services_finder.cache_args)
-
- expect(finder.execute).not_to be_empty
- end
-
- it 'has a function', :use_clean_rails_memory_store_caching do
- stub_kubeclient_service_pods
- stub_reactive_cache(knative_services_finder,
- {
- services: kube_knative_services_body(namespace: namespace.namespace, name: cluster.project.name)["items"],
- pods: kube_knative_pods_body(cluster.project.name, namespace.namespace)["items"]
- },
- *knative_services_finder.cache_args)
-
- result = finder.service(cluster.environment_scope, cluster.project.name)
- expect(result).to be_present
- expect(result.name).to be_eql(cluster.project.name)
- end
-
- it 'has metrics', :use_clean_rails_memory_store_caching do
- end
- end
-
- context 'has prometheus' do
- let(:prometheus_adapter) { double('prometheus_adapter', can_query?: true) }
- let!(:knative) { create(:clusters_applications_knative, :installed, cluster: cluster) }
- let!(:prometheus) { create(:clusters_integrations_prometheus, cluster: cluster) }
- let(:finder) { described_class.new(project) }
-
- before do
- allow(Gitlab::Prometheus::Adapter).to receive(:new).and_return(double(prometheus_adapter: prometheus_adapter))
- allow(prometheus_adapter).to receive(:query).and_return(prometheus_empty_body('matrix'))
- end
-
- it 'is available' do
- expect(finder.has_prometheus?("*")).to be true
- end
-
- it 'has query data' do
- expect(finder.invocation_metrics("*", cluster.project.name)).not_to be_nil
- end
- end
- end
-end
diff --git a/spec/finders/releases_finder_spec.rb b/spec/finders/releases_finder_spec.rb
index b0fa1177245..858a0e566f6 100644
--- a/spec/finders/releases_finder_spec.rb
+++ b/spec/finders/releases_finder_spec.rb
@@ -107,130 +107,4 @@ RSpec.describe ReleasesFinder do
it_behaves_like 'when a tag parameter is passed'
end
end
-
- describe 'when parent is a group' do
- context 'without subgroups' do
- let(:project2) { create(:project, :repository, namespace: group) }
- let!(:v6) { create(:release, project: project2, tag: 'v6') }
-
- subject { described_class.new(group, user, params).execute(**args) }
-
- it_behaves_like 'when the user is not part of the group'
-
- context 'when the user is a project guest on one sibling project' do
- before do
- project.add_guest(user)
- v1_0_0.update_attribute(:released_at, 3.days.ago)
- v1_1_0.update_attribute(:released_at, 1.day.ago)
- end
-
- it 'does not return any releases' do
- expect(subject.size).to eq(0)
- expect(subject).to eq([])
- end
- end
-
- context 'when the user is a guest on the group' do
- before do
- group.add_guest(user)
- v1_0_0.update_attribute(:released_at, 3.days.ago)
- v6.update_attribute(:released_at, 2.days.ago)
- v1_1_0.update_attribute(:released_at, 1.day.ago)
- end
-
- it 'sorts by release date' do
- expect(subject.size).to eq(3)
- expect(subject).to eq([v1_1_0, v6, v1_0_0])
- end
-
- it_behaves_like 'when a tag parameter is passed'
- end
- end
-
- describe 'with subgroups' do
- let(:params) { { include_subgroups: true } }
-
- subject { described_class.new(group, user, params).execute(**args) }
-
- context 'with a single-level subgroup' do
- let(:subgroup) { create :group, parent: group }
- let(:project2) { create(:project, :repository, namespace: subgroup) }
- let!(:v6) { create(:release, project: project2, tag: 'v6') }
-
- it_behaves_like 'when the user is not part of the group'
-
- context 'when the user a project guest in the subgroup project' do
- before do
- project2.add_guest(user)
- end
-
- it 'does not return any releases' do
- expect(subject).to match_array([])
- end
- end
-
- context 'when the user is a guest on the group' do
- before do
- group.add_guest(user)
- v6.update_attribute(:released_at, 2.days.ago)
- end
-
- it 'returns all releases' do
- expect(subject).to match_array([v1_1_0, v1_0_0, v6])
- end
-
- it_behaves_like 'when a tag parameter is passed'
- end
- end
-
- context 'with a multi-level subgroup' do
- let(:subgroup) { create :group, parent: group }
- let(:subsubgroup) { create :group, parent: subgroup }
- let(:project2) { create(:project, :repository, namespace: subgroup) }
- let(:project3) { create(:project, :repository, namespace: subsubgroup) }
- let!(:v6) { create(:release, project: project2, tag: 'v6') }
- let!(:p3) { create(:release, project: project3, tag: 'p3') }
-
- before do
- v6.update_attribute(:released_at, 2.days.ago)
- p3.update_attribute(:released_at, 3.days.ago)
- end
-
- it_behaves_like 'when the user is not part of the group'
-
- context 'when the user a project guest in the subgroup and subsubgroup project' do
- before do
- project2.add_guest(user)
- project3.add_guest(user)
- end
-
- it 'does not return any releases' do
- expect(subject).to match_array([])
- end
- end
-
- context 'when the user a project guest in the subsubgroup project' do
- before do
- project3.add_guest(user)
- end
-
- it 'does not return any releases' do
- expect(subject).to match_array([])
- end
- end
-
- context 'when the user a guest on the group' do
- before do
- group.add_guest(user)
- end
-
- it 'returns all releases' do
- expect(subject).to match_array([v1_1_0, v6, v1_0_0, p3])
- end
-
- it_behaves_like 'when a tag parameter is passed'
- end
- end
- end
- end
end