diff options
author | GitLab Bot <gitlab-bot@gitlab.com> | 2022-05-19 07:33:21 +0000 |
---|---|---|
committer | GitLab Bot <gitlab-bot@gitlab.com> | 2022-05-19 07:33:21 +0000 |
commit | 36a59d088eca61b834191dacea009677a96c052f (patch) | |
tree | e4f33972dab5d8ef79e3944a9f403035fceea43f /spec/finders | |
parent | a1761f15ec2cae7c7f7bbda39a75494add0dfd6f (diff) | |
download | gitlab-ce-36a59d088eca61b834191dacea009677a96c052f.tar.gz |
Add latest changes from gitlab-org/gitlab@15-0-stable-eev15.0.0-rc42
Diffstat (limited to 'spec/finders')
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 |