diff options
Diffstat (limited to 'spec')
7 files changed, 286 insertions, 49 deletions
diff --git a/spec/frontend/packages_and_registries/package_registry/components/list/packages_search_spec.js b/spec/frontend/packages_and_registries/package_registry/components/list/packages_search_spec.js index 6a1c34df596..eb5c546d2be 100644 --- a/spec/frontend/packages_and_registries/package_registry/components/list/packages_search_spec.js +++ b/spec/frontend/packages_and_registries/package_registry/components/list/packages_search_spec.js @@ -52,7 +52,7 @@ describe('Package Search', () => { expect(findPersistedSearch().exists()).toBe(false); }); - it('has a LocalStorageSync component', () => { + it('has a LocalStorageSync component with project key', () => { mountComponent(); expect(findLocalStorageSync().props()).toMatchObject({ @@ -64,6 +64,18 @@ describe('Package Search', () => { }); }); + it('has a LocalStorageSync component with group key', () => { + mountComponent(true); + + expect(findLocalStorageSync().props()).toMatchObject({ + storageKey: 'group_package_registry_list_sorting', + value: { + orderBy: LIST_KEY_CREATED_AT, + sort: 'desc', + }, + }); + }); + it.each` isGroupPage | page ${false} | ${'project'} diff --git a/spec/models/ci/pipeline_schedule_spec.rb b/spec/models/ci/pipeline_schedule_spec.rb index c441be58edf..941ccb2dd31 100644 --- a/spec/models/ci/pipeline_schedule_spec.rb +++ b/spec/models/ci/pipeline_schedule_spec.rb @@ -115,6 +115,18 @@ RSpec.describe Ci::PipelineSchedule, feature_category: :continuous_integration d end end + describe '.for_project' do + let(:project) { create(:project) } + let!(:project_pipeline_schedule) { create(:ci_pipeline_schedule, project: project) } + let!(:other_pipeline_schedule) { create(:ci_pipeline_schedule) } + + subject { described_class.for_project(project) } + + it 'returns pipeline schedule only for project' do + is_expected.to eq([project_pipeline_schedule]) + end + end + describe '#set_next_run_at' do let(:now) { Time.zone.local(2021, 3, 2, 1, 0) } let(:pipeline_schedule) { create(:ci_pipeline_schedule, cron: "0 1 * * *") } diff --git a/spec/models/user_spec.rb b/spec/models/user_spec.rb index 7014c9e685f..c40c43db727 100644 --- a/spec/models/user_spec.rb +++ b/spec/models/user_spec.rb @@ -2718,6 +2718,25 @@ RSpec.describe User, feature_category: :user_profile do it { expect(@user.namespaces).to eq([@user.namespace]) } end + shared_examples 'Ci::DropPipelinesAndDisableSchedulesForUserService called with correct arguments' do + let(:reason) { :user_blocked } + let(:include_owned_projects_and_groups) { false } + subject(:action) { user.block! } + + it 'calls Ci::DropPipelinesAndDisableSchedules service with correct arguments' do + drop_disable_service = double + + expect(Ci::DropPipelinesAndDisableSchedulesForUserService).to receive(:new).and_return(drop_disable_service) + expect(drop_disable_service).to receive(:execute).with( + user, + reason: reason, + include_owned_projects_and_groups: include_owned_projects_and_groups + ) + + action + end + end + describe 'blocking user' do let_it_be_with_refind(:user) { create(:user, name: 'John Smith') } @@ -2727,33 +2746,10 @@ RSpec.describe User, feature_category: :user_profile do expect(user.blocked?).to be_truthy end - context 'when user has running CI pipelines' do - let(:pipelines) { build_list(:ci_pipeline, 3, :running) } - - it 'drops all running pipelines and related jobs' do - drop_service = double - disable_service = double - - expect(user).to receive(:pipelines).and_return(pipelines) - expect(Ci::DropPipelineService).to receive(:new).and_return(drop_service) - expect(drop_service).to receive(:execute_async_for_all).with(pipelines, :user_blocked, user) - - expect(Ci::DisableUserPipelineSchedulesService).to receive(:new).and_return(disable_service) - expect(disable_service).to receive(:execute).with(user) - - user.block! - end - - it 'does not drop running pipelines if the transaction rolls back' do - expect(Ci::DropPipelineService).not_to receive(:new) - expect(Ci::DisableUserPipelineSchedulesService).not_to receive(:new) - - User.transaction do - user.block - - raise ActiveRecord::Rollback - end - end + it_behaves_like 'Ci::DropPipelinesAndDisableSchedulesForUserService called with correct arguments' do + let(:reason) { :user_blocked } + let(:include_owned_projects_and_groups) { false } + subject(:action) { user.block! } end context 'when user has active CI pipeline schedules' do @@ -2865,7 +2861,7 @@ RSpec.describe User, feature_category: :user_profile do describe 'banning and unbanning a user', :aggregate_failures do let(:user) { create(:user) } - context 'banning a user' do + context 'when banning a user' do it 'bans and blocks the user' do user.ban @@ -2877,6 +2873,35 @@ RSpec.describe User, feature_category: :user_profile do expect { user.ban }.to change { Users::BannedUser.count }.by(1) expect(Users::BannedUser.last.user_id).to eq(user.id) end + + context 'when GitLab.com' do + before do + allow(::Gitlab).to receive(:com?).and_return(true) + end + + it_behaves_like 'Ci::DropPipelinesAndDisableSchedulesForUserService called with correct arguments' do + let(:reason) { :user_banned } + let(:include_owned_projects_and_groups) { false } + subject(:action) { user.ban! } + end + + context 'when user has "deep_clean_ci_usage_when_banned" custom attribute set' do + before do + create( + :user_custom_attribute, + key: UserCustomAttribute::DEEP_CLEAN_CI_USAGE_WHEN_BANNED, value: true.to_s, + user_id: user.id + ) + user.reload + end + + it_behaves_like 'Ci::DropPipelinesAndDisableSchedulesForUserService called with correct arguments' do + let(:reason) { :user_banned } + let(:include_owned_projects_and_groups) { true } + subject(:action) { user.ban! } + end + end + end end context 'unbanning a user' do diff --git a/spec/services/ci/disable_user_pipeline_schedules_service_spec.rb b/spec/services/ci/disable_user_pipeline_schedules_service_spec.rb deleted file mode 100644 index d422cf0dab9..00000000000 --- a/spec/services/ci/disable_user_pipeline_schedules_service_spec.rb +++ /dev/null @@ -1,19 +0,0 @@ -# frozen_string_literal: true - -require 'spec_helper' - -RSpec.describe Ci::DisableUserPipelineSchedulesService, feature_category: :continuous_integration do - describe '#execute' do - let(:user) { create(:user) } - - subject(:service) { described_class.new.execute(user) } - - context 'when user has active pipeline schedules' do - let(:owned_pipeline_schedule) { create(:ci_pipeline_schedule, active: true, owner: user) } - - it 'disables all active pipeline schedules', :aggregate_failures do - expect { service }.to change { owned_pipeline_schedule.reload.active? } - end - end - end -end diff --git a/spec/services/ci/drop_pipelines_and_disable_schedules_for_user_service_spec.rb b/spec/services/ci/drop_pipelines_and_disable_schedules_for_user_service_spec.rb new file mode 100644 index 00000000000..da3852eed47 --- /dev/null +++ b/spec/services/ci/drop_pipelines_and_disable_schedules_for_user_service_spec.rb @@ -0,0 +1,207 @@ +# frozen_string_literal: true + +require 'spec_helper' + +RSpec.describe Ci::DropPipelinesAndDisableSchedulesForUserService, feature_category: :continuous_integration do + describe '#execute' do + let_it_be(:user) { create(:user) } + + let_it_be(:user_personal_projects) { create_list(:project, 2, :repository, namespace: user.namespace) } + + let_it_be(:group) do + create(:group) do |group| + group.add_owner(user) + end + end + + let_it_be(:subgroup) { create(:group, parent: group) } + + let_it_be(:other_user) do + create(:user) do |new_user| + create(:group_member, :maintainer, user: new_user, group: group) + create(:group_member, :maintainer, user: new_user, group: subgroup) + + user_personal_projects.each do |project| + create(:project_member, :maintainer, user: new_user, project: project) + end + end + end + + let_it_be(:group_projects) { create_list(:project, 2, :repository, namespace: group) } + let_it_be(:subgroup_projects) do + create_list(:project, 2, :repository, namespace: subgroup) + end + + let_it_be(:other_user_personal_projects) { create_list(:project, 2, :repository, namespace: other_user.namespace) } + + subject(:service) { described_class.new.execute(user) } + + context 'when user owns pipelines/schedules and groups with other users also owning pipelines/schedules' do + # Pipelines/pipeline schedules owned by the user in their personal, group and descendent group projects + let_it_be_with_reload(:user_owned_pipelines) do + [user_personal_projects, group_projects, subgroup_projects].flat_map do |projects| + projects.flat_map do |project| + create_list(:ci_pipeline, 2, :running, project: project, user: user) do |pipeline| + create(:ci_build, :running, pipeline: pipeline) + create(:commit_status, :running, pipeline: pipeline) + end + end + end + end + + let_it_be_with_reload(:user_owned_schedules) do + [user_personal_projects, group_projects, subgroup_projects].flat_map do |projects| + projects.flat_map do |project| + create_list(:ci_pipeline_schedule, 2, active: true, project: project, owner: user) + end + end + end + + # Pipelines/pipeline schedules owned by another user in user personal projects and group and descendant group + # projects owned by the user + let_it_be_with_reload(:other_user_owned_group_project_pipelines) do + [user_personal_projects, group_projects, subgroup_projects].flat_map do |projects| + projects.flat_map do |project| + create_list(:ci_pipeline, 2, :running, project: project, user: other_user) do |pipeline| + create(:ci_build, :running, pipeline: pipeline) + create(:commit_status, :running, pipeline: pipeline) + end + end + end + end + + let_it_be_with_reload(:other_user_owned_group_project_schedules) do + [user_personal_projects, group_projects, subgroup_projects].flat_map do |projects| + projects.flat_map do |project| + create_list(:ci_pipeline_schedule, 2, active: true, project: project, owner: other_user) + end + end + end + + # Pipelines/pipeline schedules owned by another user in their personal projects (should never be changed) + let_it_be_with_reload(:other_user_owned_personal_pipelines) do + other_user_personal_projects.flat_map do |project| + create_list(:ci_pipeline, 2, :running, project: project, user: other_user) do |pipeline| + create(:ci_build, :running, pipeline: pipeline) + create(:commit_status, :running, pipeline: pipeline) + end + end + end + + let_it_be_with_reload(:other_user_owned_personal_schedules) do + other_user_personal_projects.flat_map do |project| + create_list(:ci_pipeline_schedule, 2, active: true, project: project, owner: other_user) + end + end + + it 'drops running pipelines/disabled active schedules owned by user', :sidekiq_inline do + expect { service }.to change { + user_owned_pipelines.map(&:reload).map(&:status).uniq + } + .from(["running"]) + .to(["failed"]) + .and change { + user_owned_schedules.map(&:reload).map(&:active?).uniq + } + .from([true]) + .to([false]) + .and not_change { + [ + other_user_owned_group_project_pipelines, + other_user_owned_personal_pipelines + ].flatten.map(&:reload).map(&:status).uniq + } + .and not_change { + [ + other_user_owned_group_project_schedules, + other_user_owned_personal_schedules + ].flatten.map(&:reload).map(&:active?).uniq + } + end + + it 'avoids N+1 queries when reading data' do + control_count = ActiveRecord::QueryRecorder.new do + described_class.new.execute(user) + end.count + + extra_projects = create_list(:project, 2, :repository, namespace: group) + + [extra_projects, user_personal_projects, group_projects, subgroup_projects].flat_map do |projects| + projects.flat_map do |project| + create_list(:ci_pipeline, 2, :running, project: project, user: user) do |pipeline| + create(:ci_build, :running, pipeline: pipeline) + create(:commit_status, :running, pipeline: pipeline) + end + create_list(:ci_pipeline_schedule, 2, active: true, project: project, owner: user) + end + end + + expect do + described_class.new.execute(user) + end.not_to exceed_query_limit(control_count) + end + + context 'when include_owned_projects_and_groups is true' do + subject(:service) { described_class.new.execute(user, include_owned_projects_and_groups: true) } + + it 'drops running pipelines/disabled active schedules owned by user and/or in their owned groups/descendants', + :sidekiq_inline do + expect { service }.to change { + [ + user_owned_pipelines, + other_user_owned_group_project_pipelines + ].flatten.map(&:reload).map(&:status).uniq + } + .from(["running"]) + .to(["failed"]) + .and change { + [ + user_owned_schedules, + other_user_owned_group_project_schedules + ].flatten.map(&:reload).map(&:active?).uniq + } + .from([true]) + .to([false]) + .and not_change { + other_user_owned_personal_pipelines.map(&:reload).map(&:active?).uniq + } + .and not_change { + other_user_owned_personal_schedules.map(&:reload).map(&:active?).uniq + } + end + + it 'avoids N+1 queries when reading data' do + control_count = ActiveRecord::QueryRecorder.new do + described_class.new.execute(user, include_owned_projects_and_groups: true) + end.count + + extra_projects = create_list(:project, 2, :repository, namespace: group) + + [user_personal_projects, extra_projects, group_projects, subgroup_projects].flat_map do |projects| + projects.flat_map do |project| + create_list(:ci_pipeline, 2, :running, project: project, user: user) do |pipeline| + create(:ci_build, :running, pipeline: pipeline) + create(:commit_status, :running, pipeline: pipeline) + end + create_list(:ci_pipeline_schedule, 2, active: true, project: project, owner: user) + end + end + + [extra_projects, group_projects, subgroup_projects].flat_map do |projects| + projects.flat_map do |project| + create_list(:ci_pipeline, 2, :running, project: project, user: other_user) do |pipeline| + create(:ci_build, :running, pipeline: pipeline) + create(:commit_status, :running, pipeline: pipeline) + end + create_list(:ci_pipeline_schedule, 2, active: true, project: project, owner: other_user) + end + end + + expect do + described_class.new.execute(user, include_owned_projects_and_groups: true) + end.not_to exceed_query_limit(control_count) + end + end + end + end +end diff --git a/spec/support/helpers/user_with_namespace_shim.yml b/spec/support/helpers/user_with_namespace_shim.yml index 7e7a25aa023..7f683e3f220 100644 --- a/spec/support/helpers/user_with_namespace_shim.yml +++ b/spec/support/helpers/user_with_namespace_shim.yml @@ -934,6 +934,7 @@ - spec/services/auth/container_registry_authentication_service_spec.rb - spec/services/award_emojis/add_service_spec.rb - spec/services/ci/abort_pipelines_service_spec.rb +- spec/services/ci/drop_pipelines_and_disable_schedules_for_user_service_spec.rb - spec/services/draft_notes/publish_service_spec.rb - spec/services/environments/schedule_to_delete_review_apps_service_spec.rb - spec/services/import/bitbucket_server_service_spec.rb diff --git a/spec/support/rspec_order_todo.yml b/spec/support/rspec_order_todo.yml index 3a0e563f7f8..d67eaf6920c 100644 --- a/spec/support/rspec_order_todo.yml +++ b/spec/support/rspec_order_todo.yml @@ -8510,7 +8510,6 @@ - './spec/services/ci/deployments/destroy_service_spec.rb' - './spec/services/ci/destroy_pipeline_service_spec.rb' - './spec/services/ci/destroy_secure_file_service_spec.rb' -- './spec/services/ci/disable_user_pipeline_schedules_service_spec.rb' - './spec/services/ci/drop_pipeline_service_spec.rb' - './spec/services/ci/ensure_stage_service_spec.rb' - './spec/services/ci/expire_pipeline_cache_service_spec.rb' |