-
-
-
New description
', - lastEditedAt: '2022-09-21T06:18:42Z', - lastEditedBy: { - name: 'Administrator', - webPath: '/root', - }, - }, - ], - }, - newWorkItem: { - __typename: 'WorkItem', - id: 'gid://gitlab/WorkItem/1000000', - iid: '100', - title: 'Updated title', - state: 'OPEN', - createdAt: '2022-08-03T12:41:54Z', - closedAt: null, - description: '', - confidential: false, - project: { - __typename: 'Project', - id: '1', - fullPath: 'test-project-path', - archived: false, - }, - workItemType: { - __typename: 'WorkItemType', - id: 'gid://gitlab/WorkItems::Type/5', - name: 'Task', - iconName: 'issue-type-task', - }, - userPermissions: { - deleteWorkItem: false, - updateWorkItem: false, - setWorkItemMetadata: false, - __typename: 'WorkItemPermissions', - }, - widgets: [], - }, - }, - }, -}; - export const deleteWorkItemResponse = { data: { workItemDelete: { errors: [], __typename: 'WorkItemDeletePayload' } }, }; @@ -1831,18 +1750,6 @@ export const projectMilestonesResponseWithNoMilestones = { }, }; -export const projectWorkItemResponse = { - data: { - workspace: { - id: 'gid://gitlab/Project/1', - workItems: { - nodes: [workItemQueryResponse.data.workItem], - }, - __typename: 'Project', - }, - }, -}; - export const mockWorkItemNotesResponse = { data: { workItem: { diff --git a/spec/frontend/work_items/router_spec.js b/spec/frontend/work_items/router_spec.js index 86e890ea809..b5d54a7c319 100644 --- a/spec/frontend/work_items/router_spec.js +++ b/spec/frontend/work_items/router_spec.js @@ -6,7 +6,7 @@ import { currentUserResponse, workItemAssigneesSubscriptionResponse, workItemDatesSubscriptionResponse, - workItemByIidResponseFactory as workItemResponseFactory, + workItemByIidResponseFactory, workItemTitleSubscriptionResponse, workItemLabelsSubscriptionResponse, workItemMilestoneSubscriptionResponse, @@ -32,7 +32,7 @@ describe('Work items router', () => { Vue.use(VueApollo); - const workItemQueryHandler = jest.fn().mockResolvedValue(workItemResponseFactory()); + const workItemQueryHandler = jest.fn().mockResolvedValue(workItemByIidResponseFactory()); const currentUserQueryHandler = jest.fn().mockResolvedValue(currentUserResponse); const datesSubscriptionHandler = jest.fn().mockResolvedValue(workItemDatesSubscriptionResponse); const titleSubscriptionHandler = jest.fn().mockResolvedValue(workItemTitleSubscriptionResponse); diff --git a/spec/helpers/sessions_helper_spec.rb b/spec/helpers/sessions_helper_spec.rb index b8290fa2337..5a46a20ce1a 100644 --- a/spec/helpers/sessions_helper_spec.rb +++ b/spec/helpers/sessions_helper_spec.rb @@ -87,4 +87,24 @@ RSpec.describe SessionsHelper do expect(subject).to eq('ma**@e******.com') end end + + describe '#remember_me_enabled?' do + subject { helper.remember_me_enabled? } + + context 'when application setting is enabled' do + before do + stub_application_setting(remember_me_enabled: true) + end + + it { is_expected.to be true } + end + + context 'when application setting is disabled' do + before do + stub_application_setting(remember_me_enabled: false) + end + + it { is_expected.to be false } + end + end end diff --git a/spec/lib/gitlab/usage_data_spec.rb b/spec/lib/gitlab/usage_data_spec.rb index a35c9c5e526..e88c89c74dc 100644 --- a/spec/lib/gitlab/usage_data_spec.rb +++ b/spec/lib/gitlab/usage_data_spec.rb @@ -639,8 +639,6 @@ RSpec.describe Gitlab::UsageData, :aggregate_failures, feature_category: :servic create(:alert_management_alert, project: project, created_at: n.days.ago) end - stub_application_setting(self_monitoring_project: project) - for_defined_days_back do create(:product_analytics_event, project: project, se_category: 'epics', se_action: 'promote') end diff --git a/spec/models/application_setting_spec.rb b/spec/models/application_setting_spec.rb index 9f292b0a294..e0bfe41a3ae 100644 --- a/spec/models/application_setting_spec.rb +++ b/spec/models/application_setting_spec.rb @@ -26,12 +26,6 @@ RSpec.describe ApplicationSetting, feature_category: :shared, type: :model do end describe 'associations' do - it do - is_expected.to belong_to(:self_monitoring_project).class_name('Project') - .with_foreign_key(:instance_administration_project_id) - .inverse_of(:application_setting) - end - it do is_expected.to belong_to(:instance_group).class_name('Group') .with_foreign_key(:instance_administrators_group_id) diff --git a/spec/models/integrations/prometheus_spec.rb b/spec/models/integrations/prometheus_spec.rb index aa248abd3bb..a533079f906 100644 --- a/spec/models/integrations/prometheus_spec.rb +++ b/spec/models/integrations/prometheus_spec.rb @@ -90,37 +90,6 @@ RSpec.describe Integrations::Prometheus, :use_clean_rails_memory_store_caching, end end end - - context 'with self-monitoring project and internal Prometheus' do - before do - integration.api_url = 'http://localhost:9090' - - stub_application_setting(self_monitoring_project_id: project.id) - stub_config(prometheus: { enable: true, server_address: 'localhost:9090' }) - end - - it 'allows self-monitoring project to connect to internal Prometheus' do - aggregate_failures do - ['127.0.0.1', '192.168.2.3'].each do |url| - allow(Addrinfo).to receive(:getaddrinfo).with(domain, any_args).and_return([Addrinfo.tcp(url, 80)]) - - expect(integration.can_query?).to be true - end - end - end - - it 'does not allow self-monitoring project to connect to other local URLs' do - integration.api_url = 'http://localhost:8000' - - aggregate_failures do - ['127.0.0.1', '192.168.2.3'].each do |url| - allow(Addrinfo).to receive(:getaddrinfo).with(domain, any_args).and_return([Addrinfo.tcp(url, 80)]) - - expect(integration.can_query?).to be false - end - end - end - end end end @@ -218,23 +187,6 @@ RSpec.describe Integrations::Prometheus, :use_clean_rails_memory_store_caching, it 'blocks local requests' do expect(integration.prometheus_client).to be_nil end - - context 'with self-monitoring project and internal Prometheus URL' do - before do - stub_application_setting(allow_local_requests_from_web_hooks_and_services: false) - stub_application_setting(self_monitoring_project_id: project.id) - - stub_config(prometheus: { - enable: true, - server_address: api_url - }) - end - - it 'allows local requests' do - expect(integration.prometheus_client).not_to be_nil - expect { integration.prometheus_client.ping }.not_to raise_error - end - end end context 'behind IAP' do diff --git a/spec/models/organization_spec.rb b/spec/models/organization_spec.rb new file mode 100644 index 00000000000..9966a7132ce --- /dev/null +++ b/spec/models/organization_spec.rb @@ -0,0 +1,10 @@ +# frozen_string_literal: true + +require 'spec_helper' + +# rubocop: disable Lint/EmptyBlock +# rubocop: disable RSpec/EmptyExampleGroup +RSpec.describe Organization, type: :model, feature_category: :cell do +end +# rubocop: enable RSpec/EmptyExampleGroup +# rubocop: enable Lint/EmptyBlock diff --git a/spec/models/project_spec.rb b/spec/models/project_spec.rb index f25ff0884b9..b5b7a283e39 100644 --- a/spec/models/project_spec.rb +++ b/spec/models/project_spec.rb @@ -7551,24 +7551,6 @@ RSpec.describe Project, factory_default: :keep, feature_category: :projects do end end - describe '#self_monitoring?' do - let_it_be(:project) { create(:project) } - - subject { project.self_monitoring? } - - context 'when the project is instance self-monitoring' do - before do - stub_application_setting(self_monitoring_project_id: project.id) - end - - it { is_expected.to be true } - end - - context 'when the project is not self-monitoring' do - it { is_expected.to be false } - end - end - describe '#add_export_job' do let_it_be(:user) { create(:user) } let_it_be(:project) { create(:project) } diff --git a/spec/models/user_spec.rb b/spec/models/user_spec.rb index 60583bc351d..f1d3b17fd6f 100644 --- a/spec/models/user_spec.rb +++ b/spec/models/user_spec.rb @@ -2174,6 +2174,20 @@ RSpec.describe User, feature_category: :user_profile do end end + describe '#sign_in_with_codes_allowed?' do + let_it_be(:user) { create(:user, :two_factor_via_webauthn) } + + context 'when `webauthn_without_totp` disabled' do + before do + stub_feature_flags(webauthn_without_totp: false) + end + + it { expect(user.sign_in_with_codes_allowed?).to eq(false) } + end + + it { expect(user.sign_in_with_codes_allowed?).to eq(true) } + end + describe '#two_factor_otp_enabled?' do let_it_be(:user) { create(:user) } diff --git a/spec/services/members/destroy_service_spec.rb b/spec/services/members/destroy_service_spec.rb index 2b956bec469..48f59ba596b 100644 --- a/spec/services/members/destroy_service_spec.rb +++ b/spec/services/members/destroy_service_spec.rb @@ -463,16 +463,26 @@ RSpec.describe Members::DestroyService, feature_category: :subgroups do end context 'subresources' do - let(:user) { create(:user) } - let(:member_user) { create(:user) } + let_it_be_with_reload(:user) { create(:user) } + let_it_be_with_reload(:member_user) { create(:user) } - let(:group) { create(:group, :public) } - let(:subgroup) { create(:group, parent: group) } - let(:subsubgroup) { create(:group, parent: subgroup) } - let(:subsubproject) { create(:project, group: subsubgroup) } + let_it_be_with_reload(:group) { create(:group, :public) } + let_it_be_with_reload(:subgroup) { create(:group, parent: group) } + let_it_be(:private_subgroup) { create(:group, :private, parent: group, name: 'private_subgroup') } + let_it_be(:private_subgroup_with_direct_membership) { create(:group, :private, parent: group) } + let_it_be_with_reload(:subsubgroup) { create(:group, parent: subgroup) } - let(:group_project) { create(:project, :public, group: group) } - let(:control_project) { create(:project, group: subsubgroup) } + let_it_be_with_reload(:group_project) { create(:project, :public, group: group) } + let_it_be_with_reload(:control_project) { create(:project, :private, group: subsubgroup) } + let_it_be_with_reload(:subsubproject) { create(:project, :public, group: subsubgroup) } + + let_it_be(:private_subgroup_project) do + create(:project, :private, group: private_subgroup, name: 'private_subgroup_project') + end + + let_it_be(:private_subgroup_with_direct_membership_project) do + create(:project, :private, group: private_subgroup_with_direct_membership, name: 'private_subgroup_project') + end context 'with memberships' do before do @@ -481,14 +491,68 @@ RSpec.describe Members::DestroyService, feature_category: :subgroups do subsubproject.add_developer(member_user) group_project.add_developer(member_user) control_project.add_maintainer(user) + private_subgroup_with_direct_membership.add_developer(member_user) group.add_owner(user) @group_member = create(:group_member, :developer, group: group, user: member_user) end + let_it_be(:todo_in_public_group_project) do + create(:todo, :pending, + project: group_project, + user: member_user, + target: create(:issue, project: group_project) + ) + end + + let_it_be(:mr_in_public_group_project) do + create(:merge_request, source_project: group_project, assignees: [member_user]) + end + + let_it_be(:todo_in_private_subgroup_project) do + create(:todo, :pending, + project: private_subgroup_project, + user: member_user, + target: create(:issue, project: private_subgroup_project) + ) + end + + let_it_be(:mr_in_private_subgroup_project) do + create(:merge_request, source_project: private_subgroup_project, assignees: [member_user]) + end + + let_it_be(:todo_in_public_subsubgroup_project) do + create(:todo, :pending, + project: subsubproject, + user: member_user, + target: create(:issue, project: subsubproject) + ) + end + + let_it_be(:mr_in_public_subsubgroup_project) do + create(:merge_request, source_project: subsubproject, assignees: [member_user]) + end + + let_it_be(:todo_in_private_subgroup_with_direct_membership_project) do + create(:todo, :pending, + project: private_subgroup_with_direct_membership_project, + user: member_user, + target: create(:issue, project: private_subgroup_with_direct_membership_project) + ) + end + + let_it_be(:mr_in_private_subgroup_with_direct_membership_project) do + create(:merge_request, + source_project: private_subgroup_with_direct_membership_project, + assignees: [member_user] + ) + end + context 'with skipping of subresources' do + subject(:execute_service) { described_class.new(user).execute(@group_member, skip_subresources: true) } + before do - described_class.new(user).execute(@group_member, skip_subresources: true) + execute_service end it 'removes the group membership' do @@ -514,11 +578,35 @@ RSpec.describe Members::DestroyService, feature_category: :subgroups do it 'does not remove the user from the control project' do expect(control_project.members.map(&:user)).to include(user) end + + context 'todos', :sidekiq_inline do + it 'removes todos for which the user no longer has access' do + expect(member_user.todos).to include( + todo_in_public_group_project, + todo_in_public_subsubgroup_project, + todo_in_private_subgroup_with_direct_membership_project + ) + + expect(member_user.todos).not_to include(todo_in_private_subgroup_project) + end + end + + context 'issuables', :sidekiq_inline do + subject(:execute_service) do + described_class.new(user).execute(@group_member, skip_subresources: true, unassign_issuables: true) + end + + it 'removes assigned issuables, even in subresources' do + expect(member_user.assigned_merge_requests).to be_empty + end + end end context 'without skipping of subresources' do + subject(:execute_service) { described_class.new(user).execute(@group_member, skip_subresources: false) } + before do - described_class.new(user).execute(@group_member, skip_subresources: false) + execute_service end it 'removes the project membership' do @@ -544,6 +632,30 @@ RSpec.describe Members::DestroyService, feature_category: :subgroups do it 'does not remove the user from the control project' do expect(control_project.members.map(&:user)).to include(user) end + + context 'todos', :sidekiq_inline do + it 'removes todos for which the user no longer has access' do + expect(member_user.todos).to include( + todo_in_public_group_project, + todo_in_public_subsubgroup_project + ) + + expect(member_user.todos).not_to include( + todo_in_private_subgroup_project, + todo_in_private_subgroup_with_direct_membership_project + ) + end + end + + context 'issuables', :sidekiq_inline do + subject(:execute_service) do + described_class.new(user).execute(@group_member, skip_subresources: false, unassign_issuables: true) + end + + it 'removes assigned issuables' do + expect(member_user.assigned_merge_requests).to be_empty + end + end end end @@ -626,4 +738,13 @@ RSpec.describe Members::DestroyService, feature_category: :subgroups do expect(project.members.not_accepted_invitations_by_user(member_user)).to be_empty end end + + describe '#mark_as_recursive_call' do + it 'marks the instance as recursive' do + service = described_class.new(current_user) + service.mark_as_recursive_call + + expect(service.send(:recursive_call?)).to eq(true) + end + end end diff --git a/spec/support/helpers/user_login_helper.rb b/spec/support/helpers/user_login_helper.rb index 47e858cb68c..d8368a94ad7 100644 --- a/spec/support/helpers/user_login_helper.rb +++ b/spec/support/helpers/user_login_helper.rb @@ -30,4 +30,20 @@ module UserLoginHelper def ensure_one_active_pane expect(page).to have_selector('.tab-pane.active', count: 1) end + + def ensure_remember_me_in_tab(tab_name) + find_link(tab_name).click + + within '.tab-pane.active' do + expect(page).to have_content _('Remember me') + end + end + + def ensure_remember_me_not_in_tab(tab_name) + find_link(tab_name).click + + within '.tab-pane.active' do + expect(page).not_to have_content _('Remember me') + end + end end diff --git a/spec/tasks/gitlab/db_rake_spec.rb b/spec/tasks/gitlab/db_rake_spec.rb index fb45bc0864d..c2cc6d05630 100644 --- a/spec/tasks/gitlab/db_rake_spec.rb +++ b/spec/tasks/gitlab/db_rake_spec.rb @@ -961,19 +961,17 @@ RSpec.describe 'gitlab:db namespace rake task', :silence_stdout, feature_categor using RSpec::Parameterized::TableSyntax let(:task) { 'gitlab:db:active' } - let(:self_monitoring) { double('self_monitoring') } - where(:needs_migration, :self_monitoring_project, :project_count, :exit_status, :exit_code) do - true | nil | nil | 1 | false - false | :self_monitoring | 1 | 1 | false - false | nil | 0 | 1 | false - false | :self_monitoring | 2 | 0 | true + where(:needs_migration, :project_count, :exit_status, :exit_code) do + true | nil | 1 | false + false | 1 | 0 | true + false | 0 | 1 | false + false | 2 | 0 | true end with_them do it 'exits 0 or 1 depending on user modifications to the database' do allow_any_instance_of(ActiveRecord::MigrationContext).to receive(:needs_migration?).and_return(needs_migration) - allow_any_instance_of(ApplicationSetting).to receive(:self_monitoring_project).and_return(self_monitoring_project) allow(Project).to receive(:count).and_return(project_count) expect { run_rake_task(task) }.to raise_error do |error|