diff options
author | GitLab Bot <gitlab-bot@gitlab.com> | 2023-02-16 15:08:03 +0300 |
---|---|---|
committer | GitLab Bot <gitlab-bot@gitlab.com> | 2023-02-16 15:08:03 +0300 |
commit | 12166c0faf75479889bc0ac432b85b9dae91552b (patch) | |
tree | fc5a3140e12c815beb6c34d44e2ad423a4f302ad /spec | |
parent | b1a0a71628cb4531f3b9a2999f5aa4d22f6ac5fb (diff) |
Add latest changes from gitlab-org/gitlab@master
Diffstat (limited to 'spec')
38 files changed, 333 insertions, 299 deletions
diff --git a/spec/controllers/projects/raw_controller_spec.rb b/spec/controllers/projects/raw_controller_spec.rb index a21727e5691..40252cf65cd 100644 --- a/spec/controllers/projects/raw_controller_spec.rb +++ b/spec/controllers/projects/raw_controller_spec.rb @@ -295,21 +295,6 @@ RSpec.describe Projects::RawController, feature_category: :source_code_managemen expect(response).to have_gitlab_http_status(:not_modified) end end - - context 'when improve_blobs_cache_headers disabled' do - before do - stub_feature_flags(improve_blobs_cache_headers: false) - end - - it 'uses weak etags with a restricted set of headers' do - sign_in create(:user) - request_file - - expect(response.headers['ETag']).to eq("W/\"bdd5aa537c1e1f6d1b66de4bac8a6132\"") - expect(response.cache_control[:no_store]).to be_nil - expect(response.header['Cache-Control']).to eq('max-age=60, public') - end - end end end end diff --git a/spec/controllers/projects/repositories_controller_spec.rb b/spec/controllers/projects/repositories_controller_spec.rb index bc2a3abc2d6..8186176a46b 100644 --- a/spec/controllers/projects/repositories_controller_spec.rb +++ b/spec/controllers/projects/repositories_controller_spec.rb @@ -174,45 +174,6 @@ RSpec.describe Projects::RepositoriesController, feature_category: :source_code_ end end - context 'when improve_blobs_cache_headers is disabled' do - before do - stub_feature_flags(improve_blobs_cache_headers: false) - end - - context 'when project is public' do - let(:project) { create(:project, :repository, :public) } - - it 'sets appropriate caching headers' do - get_archive - - expect(response).to have_gitlab_http_status(:ok) - expect(response.header['ETag']).to be_present - expect(response.header['Cache-Control']).to eq('max-age=60, public') - end - - context 'and repo is private' do - let(:project) { create(:project, :repository, :public, :repository_private) } - - it 'sets appropriate caching headers' do - get_archive - - expect(response).to have_gitlab_http_status(:ok) - expect(response.header['ETag']).to be_present - expect(response.header['Cache-Control']).to eq('max-age=60, private') - end - end - end - - context 'when ref is a commit SHA' do - it 'max-age is set to 3600 in Cache-Control header' do - get_archive('ddd0f15ae83993f5cb66a927a28673882e99100b') - - expect(response).to have_gitlab_http_status(:ok) - expect(response.header['Cache-Control']).to eq('max-age=3600, private') - end - end - end - context 'when If-None-Modified header is set' do it 'returns a 304 status' do # Get the archive cached first diff --git a/spec/db/development/create_base_work_item_types_spec.rb b/spec/db/development/create_base_work_item_types_spec.rb index 914b84d8668..7652ccdc487 100644 --- a/spec/db/development/create_base_work_item_types_spec.rb +++ b/spec/db/development/create_base_work_item_types_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' -RSpec.describe 'Create base work item types in development' do +RSpec.describe 'Create base work item types in development', feature_category: :team_planning do subject { load Rails.root.join('db', 'fixtures', 'development', '001_create_base_work_item_types.rb') } it_behaves_like 'work item base types importer' diff --git a/spec/db/production/create_base_work_item_types_spec.rb b/spec/db/production/create_base_work_item_types_spec.rb index 81d80104bb4..f6c3b0f6395 100644 --- a/spec/db/production/create_base_work_item_types_spec.rb +++ b/spec/db/production/create_base_work_item_types_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' -RSpec.describe 'Create base work item types in production' do +RSpec.describe 'Create base work item types in production', feature_category: :team_planning do subject { load Rails.root.join('db', 'fixtures', 'production', '003_create_base_work_item_types.rb') } it_behaves_like 'work item base types importer' diff --git a/spec/factories/work_items/widget_definitions.rb b/spec/factories/work_items/widget_definitions.rb new file mode 100644 index 00000000000..bbd7c1e7432 --- /dev/null +++ b/spec/factories/work_items/widget_definitions.rb @@ -0,0 +1,11 @@ +# frozen_string_literal: true + +FactoryBot.define do + factory :widget_definition, class: 'WorkItems::WidgetDefinition' do + work_item_type + namespace + + name { 'Description' } + widget_type { 'description' } + end +end diff --git a/spec/features/calendar_spec.rb b/spec/features/calendar_spec.rb index b09e1f16b7b..b2a29c88b68 100644 --- a/spec/features/calendar_spec.rb +++ b/spec/features/calendar_spec.rb @@ -146,9 +146,9 @@ RSpec.describe 'Contributions Calendar', :js, feature_category: :user_profile do describe '1 issue and 1 work item creation calendar activity' do before do - Issues::CreateService.new(project: contributed_project, current_user: user, params: issue_params, spam_params: nil).execute + Issues::CreateService.new(container: contributed_project, current_user: user, params: issue_params, spam_params: nil).execute WorkItems::CreateService.new( - project: contributed_project, + container: contributed_project, current_user: user, params: { title: 'new task' }, spam_params: nil @@ -190,7 +190,7 @@ RSpec.describe 'Contributions Calendar', :js, feature_category: :user_profile do push_code_contribution travel_to(Date.yesterday) do - Issues::CreateService.new(project: contributed_project, current_user: user, params: issue_params, spam_params: nil).execute + Issues::CreateService.new(container: contributed_project, current_user: user, params: issue_params, spam_params: nil).execute end end include_context 'visit user page' diff --git a/spec/features/unsubscribe_links_spec.rb b/spec/features/unsubscribe_links_spec.rb index bcab35335cb..23fa6261bd5 100644 --- a/spec/features/unsubscribe_links_spec.rb +++ b/spec/features/unsubscribe_links_spec.rb @@ -10,7 +10,7 @@ RSpec.describe 'Unsubscribe links', :sidekiq_inline, feature_category: :not_owne let_it_be(:recipient) { create(:user) } let(:params) { { title: 'A bug!', description: 'Fix it!', assignee_ids: [recipient.id] } } - let(:issue) { Issues::CreateService.new(project: project, current_user: author, params: params, spam_params: nil).execute[:issue] } + let(:issue) { Issues::CreateService.new(container: project, current_user: author, params: params, spam_params: nil).execute[:issue] } let(:mail) { ActionMailer::Base.deliveries.last } let(:body) { Capybara::Node::Simple.new(mail.default_part_body.to_s) } diff --git a/spec/features/users/user_browses_projects_on_user_page_spec.rb b/spec/features/users/user_browses_projects_on_user_page_spec.rb index b31e2a054fe..52ca2397582 100644 --- a/spec/features/users/user_browses_projects_on_user_page_spec.rb +++ b/spec/features/users/user_browses_projects_on_user_page_spec.rb @@ -129,7 +129,7 @@ RSpec.describe 'Users > User browses projects on user page', :js, feature_catego end before do - Issues::CreateService.new(project: contributed_project, current_user: user, params: { title: 'Bug in old browser' }, spam_params: nil).execute + Issues::CreateService.new(container: contributed_project, current_user: user, params: { title: 'Bug in old browser' }, spam_params: nil).execute event = create(:push_event, project: contributed_project, author: user) create(:push_event_payload, event: event, commit_count: 3) end diff --git a/spec/frontend/environments/deploy_board_component_spec.js b/spec/frontend/environments/deploy_board_component_spec.js index c005ca22070..73a366457fb 100644 --- a/spec/frontend/environments/deploy_board_component_spec.js +++ b/spec/frontend/environments/deploy_board_component_spec.js @@ -1,6 +1,6 @@ import { GlTooltip, GlIcon, GlLoadingIcon } from '@gitlab/ui'; import { mount } from '@vue/test-utils'; -import Vue, { nextTick } from 'vue'; +import { nextTick } from 'vue'; import CanaryIngress from '~/environments/components/canary_ingress.vue'; import DeployBoard from '~/environments/components/deploy_board.vue'; import { deployBoardMockData } from './mock_data'; @@ -10,7 +10,7 @@ describe('Deploy Board', () => { let wrapper; const createComponent = (props = {}) => - mount(Vue.extend(DeployBoard), { + mount(DeployBoard, { propsData: { deployBoardData: deployBoardMockData, isLoading: false, diff --git a/spec/frontend/environments/folder/environments_folder_view_spec.js b/spec/frontend/environments/folder/environments_folder_view_spec.js index ac9d857e6bd..23506eb018d 100644 --- a/spec/frontend/environments/folder/environments_folder_view_spec.js +++ b/spec/frontend/environments/folder/environments_folder_view_spec.js @@ -55,7 +55,6 @@ describe('Environments Folder View', () => { afterEach(() => { mock.restore(); - wrapper.destroy(); }); describe('successful request', () => { @@ -96,26 +95,6 @@ describe('Environments Folder View', () => { it('should render pagination', () => { expect(wrapper.findComponent(GlPagination).exists()).toBe(true); }); - - it('should make an API request when changing page', () => { - jest.spyOn(wrapper.vm, 'updateContent').mockImplementation(() => {}); - wrapper.find('.gl-pagination .page-item:nth-last-of-type(2) .page-link').trigger('click'); - expect(wrapper.vm.updateContent).toHaveBeenCalledWith({ - scope: wrapper.vm.scope, - page: '10', - nested: true, - }); - }); - - it('should make an API request when using tabs', () => { - jest.spyOn(wrapper.vm, 'updateContent').mockImplementation(() => {}); - findEnvironmentsTabStopped().trigger('click'); - expect(wrapper.vm.updateContent).toHaveBeenCalledWith({ - scope: 'stopped', - page: '1', - nested: true, - }); - }); }); }); @@ -161,29 +140,5 @@ describe('Environments Folder View', () => { expect(wrapper.vm.requestData.page).toEqual('4'); })); }); - - describe('onChangeTab', () => { - it('should set page to 1', () => { - jest.spyOn(wrapper.vm, 'updateContent').mockImplementation(() => {}); - wrapper.vm.onChangeTab('stopped'); - expect(wrapper.vm.updateContent).toHaveBeenCalledWith({ - scope: 'stopped', - page: '1', - nested: true, - }); - }); - }); - - describe('onChangePage', () => { - it('should update page and keep scope', () => { - jest.spyOn(wrapper.vm, 'updateContent').mockImplementation(() => {}); - wrapper.vm.onChangePage(4); - expect(wrapper.vm.updateContent).toHaveBeenCalledWith({ - scope: wrapper.vm.scope, - page: '4', - nested: true, - }); - }); - }); }); }); diff --git a/spec/frontend/environments/mixins/environments_pagination_api_mixin_spec.js b/spec/frontend/environments/mixins/environments_pagination_api_mixin_spec.js new file mode 100644 index 00000000000..b624178e3db --- /dev/null +++ b/spec/frontend/environments/mixins/environments_pagination_api_mixin_spec.js @@ -0,0 +1,69 @@ +import { shallowMount } from '@vue/test-utils'; +import environmentsPaginationApiMixin from '~/environments/mixins/environments_pagination_api_mixin'; + +describe('environments_pagination_api_mixin', () => { + const updateContentMock = jest.fn(); + const mockComponent = { + template: ` + <div> + <button id='change-page' @click="changePageClick" /> + <button id='change-tab' @click="changeTabClick" /> + </div> + `, + methods: { + updateContent: updateContentMock, + changePageClick() { + this.onChangePage(this.nextPage); + }, + changeTabClick() { + this.onChangeTab(this.nextScope); + }, + }, + data() { + return { + scope: 'test', + }; + }, + }; + + let wrapper; + + const createWrapper = ({ scope, nextPage, nextScope }) => + shallowMount(mockComponent, { + mixins: [environmentsPaginationApiMixin], + data() { + return { + nextPage, + nextScope, + scope, + }; + }, + }); + + it.each([ + ['test-scope', 2], + ['test-scope', 10], + ['test-scope-2', 3], + ])('should call updateContent when calling onChangePage', async (scopeName, pageNumber) => { + wrapper = createWrapper({ scope: scopeName, nextPage: pageNumber }); + + await wrapper.find('#change-page').trigger('click'); + + expect(updateContentMock).toHaveBeenCalledWith({ + scope: scopeName, + page: pageNumber.toString(), + nested: true, + }); + }); + + it('should call updateContent when calling onChageTab', async () => { + wrapper = createWrapper({ nextScope: 'stopped' }); + await wrapper.find('#change-tab').trigger('click'); + + expect(updateContentMock).toHaveBeenCalledWith({ + scope: 'stopped', + page: '1', + nested: true, + }); + }); +}); diff --git a/spec/graphql/mutations/ci/job_token_scope/remove_project_spec.rb b/spec/graphql/mutations/ci/job_token_scope/remove_project_spec.rb index a5294e96d71..5385b6ca1cf 100644 --- a/spec/graphql/mutations/ci/job_token_scope/remove_project_spec.rb +++ b/spec/graphql/mutations/ci/job_token_scope/remove_project_spec.rb @@ -46,19 +46,20 @@ RSpec.describe Mutations::Ci::JobTokenScope::RemoveProject, feature_category: :c target_project.add_guest(current_user) end + let(:service) { instance_double('Ci::JobTokenScope::RemoveProjectService') } + context 'with no direction specified' do - it 'defaults to removing an outbound link to the target project' do - expect do - expect(subject).to include(ci_job_token_scope: be_present, errors: be_empty) - end.to change { Ci::JobToken::ProjectScopeLink.count }.by(-1) + it 'defaults to asking the RemoveProjectService to remove the outbound link' do + expect(::Ci::JobTokenScope::RemoveProjectService) + .to receive(:new).with(project, current_user).and_return(service) + expect(service).to receive(:execute).with(target_project, :outbound) + .and_return(instance_double('ServiceResponse', "success?": true)) - expect(links_relation.outbound.reload).to be_empty + subject end end context 'with direction specified' do - let(:service) { instance_double('Ci::JobTokenScope::RemoveProjectService') } - subject do mutation.resolve(project_path: project.full_path, target_project_path: target_project_path, direction: 'inbound') end diff --git a/spec/graphql/resolvers/users/participants_resolver_spec.rb b/spec/graphql/resolvers/users/participants_resolver_spec.rb index 27c3b9643ce..224213d1521 100644 --- a/spec/graphql/resolvers/users/participants_resolver_spec.rb +++ b/spec/graphql/resolvers/users/participants_resolver_spec.rb @@ -115,8 +115,8 @@ RSpec.describe Resolvers::Users::ParticipantsResolver do create(:award_emoji, name: 'thumbsup', awardable: public_note) # 1 extra query per source (3 emojis + 2 notes) to fetch participables collection - # 1 extra query to load work item widgets collection - expect { query.call }.not_to exceed_query_limit(control_count).with_threshold(6) + # 2 extra queries to load work item widgets collection + expect { query.call }.not_to exceed_query_limit(control_count).with_threshold(7) end it 'does not execute N+1 for system note metadata relation' do diff --git a/spec/graphql/resolvers/work_items_resolver_spec.rb b/spec/graphql/resolvers/work_items_resolver_spec.rb index d89ccc7f806..6da62e3adb7 100644 --- a/spec/graphql/resolvers/work_items_resolver_spec.rb +++ b/spec/graphql/resolvers/work_items_resolver_spec.rb @@ -101,7 +101,7 @@ RSpec.describe Resolvers::WorkItemsResolver do end it 'batches queries that only include IIDs', :request_store do - result = batch_sync(max_queries: 7) do + result = batch_sync(max_queries: 8) do [item1, item2] .map { |item| resolve_items(iid: item.iid.to_s) } .flat_map(&:to_a) @@ -111,7 +111,7 @@ RSpec.describe Resolvers::WorkItemsResolver do end it 'finds a specific item with iids', :request_store do - result = batch_sync(max_queries: 7) do + result = batch_sync(max_queries: 8) do resolve_items(iids: [item1.iid]).to_a end diff --git a/spec/lib/gitlab/database_importers/work_items/base_type_importer_spec.rb b/spec/lib/gitlab/database_importers/work_items/base_type_importer_spec.rb index d044170dc75..3b6d10f4a7e 100644 --- a/spec/lib/gitlab/database_importers/work_items/base_type_importer_spec.rb +++ b/spec/lib/gitlab/database_importers/work_items/base_type_importer_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' -RSpec.describe Gitlab::DatabaseImporters::WorkItems::BaseTypeImporter do +RSpec.describe Gitlab::DatabaseImporters::WorkItems::BaseTypeImporter, feature_category: :team_planning do subject { described_class.upsert_types } it_behaves_like 'work item base types importer' diff --git a/spec/models/integrations/microsoft_teams_spec.rb b/spec/models/integrations/microsoft_teams_spec.rb index fa8900497d7..4d5f4065420 100644 --- a/spec/models/integrations/microsoft_teams_spec.rb +++ b/spec/models/integrations/microsoft_teams_spec.rb @@ -53,7 +53,7 @@ RSpec.describe Integrations::MicrosoftTeams do context 'with issue events' do let(:opts) { { title: 'Awesome issue', description: 'please fix' } } let(:issues_sample_data) do - service = Issues::CreateService.new(project: project, current_user: user, params: opts, spam_params: nil) + service = Issues::CreateService.new(container: project, current_user: user, params: opts, spam_params: nil) issue = service.execute[:issue] service.hook_data(issue, 'open') end diff --git a/spec/models/work_items/type_spec.rb b/spec/models/work_items/type_spec.rb index 65c6b22f5c2..e5c88634b26 100644 --- a/spec/models/work_items/type_spec.rb +++ b/spec/models/work_items/type_spec.rb @@ -10,6 +10,20 @@ RSpec.describe WorkItems::Type do describe 'associations' do it { is_expected.to have_many(:work_items).with_foreign_key('work_item_type_id') } it { is_expected.to belong_to(:namespace) } + + it 'has many `widget_definitions`' do + is_expected.to have_many(:widget_definitions) + .class_name('::WorkItems::WidgetDefinition') + .with_foreign_key('work_item_type_id') + end + + it 'has many `enabled_widget_definitions`' do + type = create(:work_item_type) + widget1 = create(:widget_definition, work_item_type: type) + create(:widget_definition, work_item_type: type, disabled: true) + + expect(type.enabled_widget_definitions).to match_array([widget1]) + end end describe 'scopes' do @@ -60,29 +74,14 @@ RSpec.describe WorkItems::Type do it { is_expected.not_to allow_value('s' * 256).for(:icon_name) } end - describe '.available_widgets' do - subject { described_class.available_widgets } - - it 'returns list of all possible widgets' do - is_expected.to include( - ::WorkItems::Widgets::Description, - ::WorkItems::Widgets::Hierarchy, - ::WorkItems::Widgets::Labels, - ::WorkItems::Widgets::Assignees, - ::WorkItems::Widgets::StartAndDueDate, - ::WorkItems::Widgets::Milestone, - ::WorkItems::Widgets::Notes - ) - end - end - describe '.default_by_type' do let(:default_issue_type) { described_class.find_by(namespace_id: nil, base_type: :issue) } subject { described_class.default_by_type(:issue) } it 'returns default work item type by base type without calling importer' do - expect(Gitlab::DatabaseImporters::WorkItems::BaseTypeImporter).not_to receive(:upsert_types) + expect(Gitlab::DatabaseImporters::WorkItems::BaseTypeImporter).not_to receive(:upsert_types).and_call_original + expect(Gitlab::DatabaseImporters::WorkItems::BaseTypeImporter).not_to receive(:upsert_widgets) expect(Gitlab::DatabaseImporters::WorkItems::HierarchyRestrictionsImporter).not_to receive(:upsert_restrictions) expect(subject).to eq(default_issue_type) @@ -94,7 +93,8 @@ RSpec.describe WorkItems::Type do end it 'creates types and restrictions and returns default work item type by base type' do - expect(Gitlab::DatabaseImporters::WorkItems::BaseTypeImporter).to receive(:upsert_types) + expect(Gitlab::DatabaseImporters::WorkItems::BaseTypeImporter).to receive(:upsert_types).and_call_original + expect(Gitlab::DatabaseImporters::WorkItems::BaseTypeImporter).to receive(:upsert_widgets) expect(Gitlab::DatabaseImporters::WorkItems::HierarchyRestrictionsImporter).to receive(:upsert_restrictions) expect(subject).to eq(default_issue_type) @@ -128,19 +128,18 @@ RSpec.describe WorkItems::Type do end describe '#supports_assignee?' do - subject(:supports_assignee) { build(:work_item_type, :task).supports_assignee? } + let_it_be_with_reload(:work_item_type) { create(:work_item_type) } + let_it_be_with_reload(:widget_definition) do + create(:widget_definition, work_item_type: work_item_type, widget_type: :assignees) + end - context 'when the assignees widget is supported' do - before do - stub_const('::WorkItems::Type::WIDGETS_FOR_TYPE', { task: [::WorkItems::Widgets::Assignees] }) - end + subject(:supports_assignee) { work_item_type.supports_assignee? } - it { is_expected.to be_truthy } - end + it { is_expected.to be_truthy } context 'when the assignees widget is not supported' do before do - stub_const('::WorkItems::Type::WIDGETS_FOR_TYPE', { task: [] }) + widget_definition.update!(disabled: true) end it { is_expected.to be_falsey } diff --git a/spec/models/work_items/widget_definition_spec.rb b/spec/models/work_items/widget_definition_spec.rb new file mode 100644 index 00000000000..08f8f4d9663 --- /dev/null +++ b/spec/models/work_items/widget_definition_spec.rb @@ -0,0 +1,92 @@ +# frozen_string_literal: true + +require 'spec_helper' + +RSpec.describe WorkItems::WidgetDefinition, feature_category: :team_planning do + let(:all_widget_classes) do + list = [ + ::WorkItems::Widgets::Description, + ::WorkItems::Widgets::Hierarchy, + ::WorkItems::Widgets::Labels, + ::WorkItems::Widgets::Assignees, + ::WorkItems::Widgets::StartAndDueDate, + ::WorkItems::Widgets::Milestone, + ::WorkItems::Widgets::Notes + ] + + if Gitlab.ee? + list += [ + ::WorkItems::Widgets::Iteration, + ::WorkItems::Widgets::Weight, + ::WorkItems::Widgets::Status, + ::WorkItems::Widgets::HealthStatus, + ::WorkItems::Widgets::Progress, + ::WorkItems::Widgets::RequirementLegacy, + ::WorkItems::Widgets::TestReports + ] + end + + list + end + + describe 'associations' do + it { is_expected.to belong_to(:namespace) } + it { is_expected.to belong_to(:work_item_type) } + end + + describe 'validations' do + it { is_expected.to validate_presence_of(:name) } + it { is_expected.to validate_uniqueness_of(:name).case_insensitive.scoped_to([:namespace_id, :work_item_type_id]) } + it { is_expected.to validate_length_of(:name).is_at_most(255) } + end + + context 'with some widgets disabled' do + before do + described_class.global.where(widget_type: :notes).update_all(disabled: true) + end + + describe '.available_widgets' do + subject { described_class.available_widgets } + + it 'returns all global widgets excluding the disabled ones' do + # WorkItems::Widgets::Notes is excluded from widget class because: + # * although widget_definition below is enabled and uses notes widget, it's namespaced (has namespace != nil) + # * available_widgets takes into account only global definitions (which have namespace=nil) + namespace = create(:namespace) + create(:widget_definition, namespace: namespace, widget_type: :notes) + + is_expected.to match_array(all_widget_classes - [::WorkItems::Widgets::Notes]) + end + + it 'returns all global widgets if there is at least one global widget definition which is enabled' do + create(:widget_definition, namespace: nil, widget_type: :notes) + + is_expected.to match_array(all_widget_classes) + end + end + + describe '.widget_classes' do + subject { described_class.widget_classes } + + it 'returns all widget classes no matter if disabled or not' do + is_expected.to match_array(all_widget_classes) + end + end + end + + describe '#widget_class' do + it 'returns widget class based on widget_type' do + expect(build(:widget_definition, widget_type: :description).widget_class).to eq(::WorkItems::Widgets::Description) + end + + it 'returns nil if there is no class for the widget_type' do + described_class.first.update_column(:widget_type, -1) + + expect(described_class.first.widget_class).to be_nil + end + + it 'returns nil if there is no class for the widget_type' do + expect(build(:widget_definition, widget_type: nil).widget_class).to be_nil + end + end +end diff --git a/spec/policies/issue_policy_spec.rb b/spec/policies/issue_policy_spec.rb index 0040d9dff7e..17558787966 100644 --- a/spec/policies/issue_policy_spec.rb +++ b/spec/policies/issue_policy_spec.rb @@ -425,19 +425,15 @@ RSpec.describe IssuePolicy, feature_category: :team_planning do context 'when accounting for notes widget' do let(:policy) { described_class.new(reporter, note) } - before do - widgets_per_type = WorkItems::Type::WIDGETS_FOR_TYPE.dup - widgets_per_type[:task] = [::WorkItems::Widgets::Description] - stub_const('WorkItems::Type::WIDGETS_FOR_TYPE', widgets_per_type) - end - - context 'and notes widget is disabled for task' do - let(:task) { create(:work_item, :task, project: project) } + context 'and notes widget is disabled for issue' do + before do + WorkItems::Type.default_by_type(:issue).widget_definitions.find_by_widget_type(:notes).update!(disabled: true) + end it 'does not allow accessing notes' do # if notes widget is disabled not even maintainer can access notes - expect(permissions(maintainer, task)).to be_disallowed(:create_note, :read_note, :mark_note_as_internal, :read_internal_note) - expect(permissions(admin, task)).to be_disallowed(:create_note, :read_note, :read_internal_note, :mark_note_as_internal, :set_note_created_at) + expect(permissions(maintainer, issue)).to be_disallowed(:create_note, :read_note, :mark_note_as_internal, :read_internal_note) + expect(permissions(admin, issue)).to be_disallowed(:create_note, :read_note, :read_internal_note, :mark_note_as_internal, :set_note_created_at) end end diff --git a/spec/policies/note_policy_spec.rb b/spec/policies/note_policy_spec.rb index f4abe3a223c..b2191e6925d 100644 --- a/spec/policies/note_policy_spec.rb +++ b/spec/policies/note_policy_spec.rb @@ -260,9 +260,7 @@ RSpec.describe NotePolicy, feature_category: :team_planning do let(:policy) { described_class.new(developer, note) } before do - widgets_per_type = WorkItems::Type::WIDGETS_FOR_TYPE.dup - widgets_per_type[:task] = [::WorkItems::Widgets::Description] - stub_const('WorkItems::Type::WIDGETS_FOR_TYPE', widgets_per_type) + WorkItems::Type.default_by_type(:task).widget_definitions.find_by_widget_type(:notes).update!(disabled: true) end context 'when noteable is task' do diff --git a/spec/requests/api/discussions_spec.rb b/spec/requests/api/discussions_spec.rb index 38016375b8f..c5126dbd1c2 100644 --- a/spec/requests/api/discussions_spec.rb +++ b/spec/requests/api/discussions_spec.rb @@ -42,8 +42,7 @@ RSpec.describe API::Discussions, feature_category: :team_planning do context 'with work item without notes widget' do before do - stub_const('WorkItems::Type::BASE_TYPES', { issue: { name: 'NoNotesWidget', enum_value: 0 } }) - stub_const('WorkItems::Type::WIDGETS_FOR_TYPE', { issue: [::WorkItems::Widgets::Description] }) + WorkItems::Type.default_by_type(:issue).widget_definitions.find_by_widget_type(:notes).update!(disabled: true) end context 'when fetching discussions' do diff --git a/spec/requests/api/graphql/mutations/ci/pipeline_schedule_play_spec.rb b/spec/requests/api/graphql/mutations/ci/pipeline_schedule_play_spec.rb index 9161304cfc3..492c6946c99 100644 --- a/spec/requests/api/graphql/mutations/ci/pipeline_schedule_play_spec.rb +++ b/spec/requests/api/graphql/mutations/ci/pipeline_schedule_play_spec.rb @@ -76,40 +76,5 @@ RSpec.describe 'PipelineSchedulePlay', feature_category: :continuous_integration expect(mutation_response['errors']).to match_array(['Unable to schedule a pipeline to run immediately.']) end end - - context 'when feature flag ci_use_run_pipeline_schedule_worker is disabled' do - before do - stub_feature_flags(ci_use_run_pipeline_schedule_worker: false) - end - - context 'when mutation succeeds' do - let(:service_response) { instance_double('ServiceResponse', payload: new_pipeline) } - let(:new_pipeline) { instance_double('Ci::Pipeline', persisted?: true) } - - it do - expect(Ci::CreatePipelineService).to receive_message_chain(:new, :execute).and_return(service_response) - post_graphql_mutation(mutation, current_user: user) - - expect(mutation_response['pipelineSchedule']['id']).to include(pipeline_schedule.id.to_s) - new_next_run_at = DateTime.parse(mutation_response['pipelineSchedule']['nextRunAt']) - expect(new_next_run_at).not_to eq(pipeline_schedule.next_run_at) - expect(new_next_run_at).to eq(pipeline_schedule.reset.next_run_at) - expect(mutation_response['errors']).to eq([]) - end - end - - context 'when mutation fails' do - it do - expect(RunPipelineScheduleWorker) - .to receive(:perform_async) - .with(pipeline_schedule.id, user.id).and_return(nil) - - post_graphql_mutation(mutation, current_user: user) - - expect(mutation_response['pipelineSchedule']).to be_nil - expect(mutation_response['errors']).to match_array(['Unable to schedule a pipeline to run immediately.']) - end - end - end end end diff --git a/spec/requests/api/graphql/mutations/notes/create/note_spec.rb b/spec/requests/api/graphql/mutations/notes/create/note_spec.rb index 00e25909746..a6253ba424b 100644 --- a/spec/requests/api/graphql/mutations/notes/create/note_spec.rb +++ b/spec/requests/api/graphql/mutations/notes/create/note_spec.rb @@ -122,8 +122,8 @@ RSpec.describe 'Adding a Note', feature_category: :team_planning do let(:variables_extra) { {} } before do - stub_const('WorkItems::Type::BASE_TYPES', { issue: { name: 'NoNotesWidget', enum_value: 0 } }) - stub_const('WorkItems::Type::WIDGETS_FOR_TYPE', { issue: [::WorkItems::Widgets::Description] }) + WorkItems::Type.default_by_type(:issue).widget_definitions.find_by_widget_type(:notes) + .update!(disabled: true) end it_behaves_like 'a Note mutation that does not create a Note' diff --git a/spec/requests/api/graphql/mutations/notes/destroy_spec.rb b/spec/requests/api/graphql/mutations/notes/destroy_spec.rb index eb45e2aa033..f40518a574b 100644 --- a/spec/requests/api/graphql/mutations/notes/destroy_spec.rb +++ b/spec/requests/api/graphql/mutations/notes/destroy_spec.rb @@ -57,8 +57,7 @@ RSpec.describe 'Destroying a Note', feature_category: :team_planning do context 'without notes widget' do before do - stub_const('WorkItems::Type::BASE_TYPES', { issue: { name: 'NoNotesWidget', enum_value: 0 } }) - stub_const('WorkItems::Type::WIDGETS_FOR_TYPE', { issue: [::WorkItems::Widgets::Description] }) + WorkItems::Type.default_by_type(:issue).widget_definitions.find_by_widget_type(:notes).update!(disabled: true) end it 'does not update the Note' do diff --git a/spec/requests/api/graphql/mutations/notes/update/note_spec.rb b/spec/requests/api/graphql/mutations/notes/update/note_spec.rb index dff8a87314b..7918bc860fe 100644 --- a/spec/requests/api/graphql/mutations/notes/update/note_spec.rb +++ b/spec/requests/api/graphql/mutations/notes/update/note_spec.rb @@ -50,8 +50,7 @@ RSpec.describe 'Updating a Note', feature_category: :team_planning do context 'without notes widget' do before do - stub_const('WorkItems::Type::BASE_TYPES', { issue: { name: 'NoNotesWidget', enum_value: 0 } }) - stub_const('WorkItems::Type::WIDGETS_FOR_TYPE', { issue: [::WorkItems::Widgets::Description] }) + WorkItems::Type.default_by_type(:issue).widget_definitions.find_by_widget_type(:notes).update!(disabled: true) end it 'does not update the Note' do diff --git a/spec/requests/api/graphql/mutations/work_items/update_spec.rb b/spec/requests/api/graphql/mutations/work_items/update_spec.rb index 271c2b917ad..ddd294e8f82 100644 --- a/spec/requests/api/graphql/mutations/work_items/update_spec.rb +++ b/spec/requests/api/graphql/mutations/work_items/update_spec.rb @@ -252,7 +252,8 @@ RSpec.describe 'Update a work item', feature_category: :team_planning do let(:input) { { 'descriptionWidget' => { 'description' => "Updating labels.\n/labels ~\"#{label1.name}\"" } } } before do - stub_const('::WorkItems::Type::WIDGETS_FOR_TYPE', { task: [::WorkItems::Widgets::Description] }) + WorkItems::Type.default_by_type(:task).widget_definitions + .find_by_widget_type(:labels).update!(disabled: true) end it 'ignores the quick action' do @@ -370,7 +371,8 @@ RSpec.describe 'Update a work item', feature_category: :team_planning do let(:input) { { 'descriptionWidget' => { 'description' => "Updating due date.\n/due today" } } } before do - stub_const('::WorkItems::Type::WIDGETS_FOR_TYPE', { task: [::WorkItems::Widgets::Description] }) + WorkItems::Type.default_by_type(:task).widget_definitions + .find_by_widget_type(:start_and_due_date).update!(disabled: true) end it 'ignores the quick action' do @@ -736,7 +738,8 @@ RSpec.describe 'Update a work item', feature_category: :team_planning do end before do - stub_const('::WorkItems::Type::WIDGETS_FOR_TYPE', { task: [::WorkItems::Widgets::Description] }) + WorkItems::Type.default_by_type(:task).widget_definitions + .find_by_widget_type(:assignees).update!(disabled: true) end it 'ignores the quick action' do diff --git a/spec/requests/api/graphql/notes/note_spec.rb b/spec/requests/api/graphql/notes/note_spec.rb index 180e54290f8..daceaec0b94 100644 --- a/spec/requests/api/graphql/notes/note_spec.rb +++ b/spec/requests/api/graphql/notes/note_spec.rb @@ -66,7 +66,8 @@ RSpec.describe 'Query.note(id)', feature_category: :team_planning do context 'and notes widget is not available' do before do - stub_const('WorkItems::Type::WIDGETS_FOR_TYPE', { issue: [::WorkItems::Widgets::Description] }) + WorkItems::Type.default_by_type(:issue).widget_definitions + .find_by_widget_type(:notes).update!(disabled: true) end it 'returns nil' do diff --git a/spec/requests/api/graphql/notes/synthetic_note_resolver_spec.rb b/spec/requests/api/graphql/notes/synthetic_note_resolver_spec.rb index 9b11406ae00..1199aeb4c39 100644 --- a/spec/requests/api/graphql/notes/synthetic_note_resolver_spec.rb +++ b/spec/requests/api/graphql/notes/synthetic_note_resolver_spec.rb @@ -44,7 +44,8 @@ RSpec.describe 'Query.synthetic_note(noteable_id, sha)', feature_category: :team context 'and notes widget is not available' do before do - stub_const('WorkItems::Type::WIDGETS_FOR_TYPE', { issue: [::WorkItems::Widgets::Description] }) + WorkItems::Type.default_by_type(:issue).widget_definitions + .find_by_widget_type(:notes).update!(disabled: true) end it 'returns nil' do diff --git a/spec/requests/api/notes_spec.rb b/spec/requests/api/notes_spec.rb index c2d9db1e6fb..c0276e02eb7 100644 --- a/spec/requests/api/notes_spec.rb +++ b/spec/requests/api/notes_spec.rb @@ -210,8 +210,7 @@ RSpec.describe API::Notes, feature_category: :team_planning do let(:request_path) { "/projects/#{ext_proj.id}/issues/#{ext_issue.iid}/notes" } before do - stub_const('WorkItems::Type::BASE_TYPES', { issue: { name: 'NoNotesWidget', enum_value: 0 } }) - stub_const('WorkItems::Type::WIDGETS_FOR_TYPE', { issue: [::WorkItems::Widgets::Description] }) + WorkItems::Type.default_by_type(:issue).widget_definitions.find_by_widget_type(:notes).update!(disabled: true) end it 'does not fetch notes' do diff --git a/spec/services/concerns/rate_limited_service_spec.rb b/spec/services/concerns/rate_limited_service_spec.rb index 04007e8e75a..d913cd17067 100644 --- a/spec/services/concerns/rate_limited_service_spec.rb +++ b/spec/services/concerns/rate_limited_service_spec.rb @@ -4,7 +4,7 @@ require 'spec_helper' RSpec.describe RateLimitedService do let(:key) { :issues_create } - let(:scope) { [:project, :current_user] } + let(:scope) { [:container, :current_user] } let(:opts) { { scope: scope, users_allowlist: -> { [User.support_bot.username] } } } let(:rate_limiter) { ::Gitlab::ApplicationRateLimiter } @@ -39,7 +39,7 @@ RSpec.describe RateLimitedService do let_it_be(:project) { create(:project) } let_it_be(:current_user) { create(:user) } - let(:service) { instance_double(Issues::CreateService, project: project, current_user: current_user) } + let(:service) { instance_double(Issues::CreateService, container: project, current_user: current_user) } let(:evaluated_scope) { [project, current_user] } let(:evaluated_opts) { { scope: evaluated_scope, users_allowlist: %w[support-bot] } } diff --git a/spec/services/issuable/discussions_list_service_spec.rb b/spec/services/issuable/discussions_list_service_spec.rb index a53bf602d40..a6f57088ad1 100644 --- a/spec/services/issuable/discussions_list_service_spec.rb +++ b/spec/services/issuable/discussions_list_service_spec.rb @@ -23,8 +23,7 @@ RSpec.describe Issuable::DiscussionsListService do let_it_be(:issuable) { create(:work_item, :issue, project: project) } before do - stub_const('WorkItems::Type::BASE_TYPES', { issue: { name: 'NoNotesWidget', enum_value: 0 } }) - stub_const('WorkItems::Type::WIDGETS_FOR_TYPE', { issue: [::WorkItems::Widgets::Description] }) + WorkItems::Type.default_by_type(:issue).widget_definitions.find_by_widget_type(:notes).update!(disabled: true) end it "returns no notes" do diff --git a/spec/services/issues/create_service_spec.rb b/spec/services/issues/create_service_spec.rb index abb59ad7ebf..ada5b300d7a 100644 --- a/spec/services/issues/create_service_spec.rb +++ b/spec/services/issues/create_service_spec.rb @@ -11,7 +11,7 @@ RSpec.describe Issues::CreateService do let(:opts) { { title: 'title' } } let(:spam_params) { double } - let(:service) { described_class.new(project: project, current_user: user, params: opts, spam_params: spam_params) } + let(:service) { described_class.new(container: project, current_user: user, params: opts, spam_params: spam_params) } it_behaves_like 'rate limited service' do let(:key) { :issues_create } @@ -147,7 +147,7 @@ RSpec.describe Issues::CreateService do end context 'when a build_service is provided' do - let(:result) { described_class.new(project: project, current_user: user, params: opts, spam_params: spam_params, build_service: build_service).execute } + let(:result) { described_class.new(container: project, current_user: user, params: opts, spam_params: spam_params, build_service: build_service).execute } let(:issue_from_builder) { WorkItem.new(project: project, title: 'Issue from builder') } let(:build_service) { double(:build_service, execute: issue_from_builder) } @@ -160,7 +160,7 @@ RSpec.describe Issues::CreateService do end context 'when skip_system_notes is true' do - let(:issue) { described_class.new(project: project, current_user: user, params: opts, spam_params: spam_params).execute(skip_system_notes: true) } + let(:issue) { described_class.new(container: project, current_user: user, params: opts, spam_params: spam_params).execute(skip_system_notes: true) } it 'does not call Issuable::CommonSystemNotesService' do expect(Issuable::CommonSystemNotesService).not_to receive(:new) @@ -256,7 +256,7 @@ RSpec.describe Issues::CreateService do let_it_be(:non_member) { create(:user) } it 'filters out params that cannot be set without the :set_issue_metadata permission' do - result = described_class.new(project: project, current_user: non_member, params: opts, spam_params: spam_params).execute + result = described_class.new(container: project, current_user: non_member, params: opts, spam_params: spam_params).execute issue = result[:issue] expect(result).to be_success @@ -270,7 +270,7 @@ RSpec.describe Issues::CreateService do end it 'can create confidential issues' do - result = described_class.new(project: project, current_user: non_member, params: opts.merge(confidential: true), spam_params: spam_params).execute + result = described_class.new(container: project, current_user: non_member, params: opts.merge(confidential: true), spam_params: spam_params).execute issue = result[:issue] expect(result).to be_success @@ -281,7 +281,7 @@ RSpec.describe Issues::CreateService do it 'moves the issue to the end, in an asynchronous worker' do expect(Issues::PlacementWorker).to receive(:perform_async).with(be_nil, Integer) - described_class.new(project: project, current_user: user, params: opts, spam_params: spam_params).execute + described_class.new(container: project, current_user: user, params: opts, spam_params: spam_params).execute end context 'when label belongs to project group' do @@ -368,7 +368,7 @@ RSpec.describe Issues::CreateService do it 'invalidates open issues counter for assignees when issue is assigned' do project.add_maintainer(assignee) - described_class.new(project: project, current_user: user, params: opts, spam_params: spam_params).execute + described_class.new(container: project, current_user: user, params: opts, spam_params: spam_params).execute expect(assignee.assigned_open_issues_count).to eq 1 end @@ -439,7 +439,7 @@ RSpec.describe Issues::CreateService do expect(project).to receive(:execute_hooks).with(expected_payload, :issue_hooks) expect(project).to receive(:execute_integrations).with(expected_payload, :issue_hooks) - described_class.new(project: project, current_user: user, params: opts, spam_params: spam_params).execute + described_class.new(container: project, current_user: user, params: opts, spam_params: spam_params).execute end context 'when issue is confidential' do @@ -462,7 +462,7 @@ RSpec.describe Issues::CreateService do expect(project).to receive(:execute_hooks).with(expected_payload, :confidential_issue_hooks) expect(project).to receive(:execute_integrations).with(expected_payload, :confidential_issue_hooks) - described_class.new(project: project, current_user: user, params: opts, spam_params: spam_params).execute + described_class.new(container: project, current_user: user, params: opts, spam_params: spam_params).execute end end end @@ -508,7 +508,7 @@ RSpec.describe Issues::CreateService do it 'removes assignee when user id is invalid' do opts = { title: 'Title', description: 'Description', assignee_ids: [-1] } - result = described_class.new(project: project, current_user: user, params: opts, spam_params: spam_params).execute + result = described_class.new(container: project, current_user: user, params: opts, spam_params: spam_params).execute issue = result[:issue] expect(result).to be_success @@ -518,7 +518,7 @@ RSpec.describe Issues::CreateService do it 'removes assignee when user id is 0' do opts = { title: 'Title', description: 'Description', assignee_ids: [0] } - result = described_class.new(project: project, current_user: user, params: opts, spam_params: spam_params).execute + result = described_class.new(container: project, current_user: user, params: opts, spam_params: spam_params).execute issue = result[:issue] expect(result).to be_success @@ -529,7 +529,7 @@ RSpec.describe Issues::CreateService do project.add_maintainer(assignee) opts = { title: 'Title', description: 'Description', assignee_ids: [assignee.id] } - result = described_class.new(project: project, current_user: user, params: opts, spam_params: spam_params).execute + result = described_class.new(container: project, current_user: user, params: opts, spam_params: spam_params).execute issue = result[:issue] expect(result).to be_success @@ -549,7 +549,7 @@ RSpec.describe Issues::CreateService do project.update!(visibility_level: level) opts = { title: 'Title', description: 'Description', assignee_ids: [assignee.id] } - result = described_class.new(project: project, current_user: user, params: opts, spam_params: spam_params).execute + result = described_class.new(container: project, current_user: user, params: opts, spam_params: spam_params).execute issue = result[:issue] expect(result).to be_success @@ -561,7 +561,7 @@ RSpec.describe Issues::CreateService do end it_behaves_like 'issuable record that supports quick actions' do - let(:issuable) { described_class.new(project: project, current_user: user, params: params, spam_params: spam_params).execute[:issue] } + let(:issuable) { described_class.new(container: project, current_user: user, params: params, spam_params: spam_params).execute[:issue] } end context 'Quick actions' do @@ -702,14 +702,14 @@ RSpec.describe Issues::CreateService do let(:opts) { { discussion_to_resolve: discussion.id, merge_request_to_resolve_discussions_of: merge_request.iid } } it 'resolves the discussion' do - described_class.new(project: project, current_user: user, params: opts, spam_params: spam_params).execute + described_class.new(container: project, current_user: user, params: opts, spam_params: spam_params).execute discussion.first_note.reload expect(discussion.resolved?).to be(true) end it 'added a system note to the discussion' do - described_class.new(project: project, current_user: user, params: opts, spam_params: spam_params).execute + described_class.new(container: project, current_user: user, params: opts, spam_params: spam_params).execute reloaded_discussion = MergeRequest.find(merge_request.id).discussions.first @@ -718,7 +718,7 @@ RSpec.describe Issues::CreateService do it 'sets default title and description values if not provided' do result = described_class.new( - project: project, current_user: user, + container: project, current_user: user, params: opts, spam_params: spam_params ).execute @@ -732,7 +732,7 @@ RSpec.describe Issues::CreateService do it 'takes params from the request over the default values' do result = described_class.new( - project: project, + container: project, current_user: user, params: opts.merge( description: 'Custom issue description', @@ -753,14 +753,14 @@ RSpec.describe Issues::CreateService do let(:opts) { { merge_request_to_resolve_discussions_of: merge_request.iid } } it 'resolves the discussion' do - described_class.new(project: project, current_user: user, params: opts, spam_params: spam_params).execute + described_class.new(container: project, current_user: user, params: opts, spam_params: spam_params).execute discussion.first_note.reload expect(discussion.resolved?).to be(true) end it 'added a system note to the discussion' do - described_class.new(project: project, current_user: user, params: opts, spam_params: spam_params).execute + described_class.new(container: project, current_user: user, params: opts, spam_params: spam_params).execute reloaded_discussion = MergeRequest.find(merge_request.id).discussions.first @@ -769,7 +769,7 @@ RSpec.describe Issues::CreateService do it 'sets default title and description values if not provided' do result = described_class.new( - project: project, current_user: user, + container: project, current_user: user, params: opts, spam_params: spam_params ).execute @@ -783,7 +783,7 @@ RSpec.describe Issues::CreateService do it 'takes params from the request over the default values' do result = described_class.new( - project: project, + container: project, current_user: user, params: opts.merge( description: 'Custom issue description', @@ -836,7 +836,7 @@ RSpec.describe Issues::CreateService do end subject do - described_class.new(project: project, current_user: user, params: params, spam_params: spam_params) + described_class.new(container: project, current_user: user, params: params, spam_params: spam_params) end it 'executes SpamActionService' do diff --git a/spec/services/work_items/create_service_spec.rb b/spec/services/work_items/create_service_spec.rb index 049c90f20b0..1b134c308f2 100644 --- a/spec/services/work_items/create_service_spec.rb +++ b/spec/services/work_items/create_service_spec.rb @@ -29,7 +29,7 @@ RSpec.describe WorkItems::CreateService do describe '#execute' do let(:service) do described_class.new( - project: project, + container: project, current_user: current_user, params: opts, spam_params: spam_params, @@ -118,7 +118,7 @@ RSpec.describe WorkItems::CreateService do let(:service) do described_class.new( - project: project, + container: project, current_user: current_user, params: opts, spam_params: spam_params, @@ -188,7 +188,7 @@ RSpec.describe WorkItems::CreateService do { title: 'Awesome work_item', description: 'please fix', - work_item_type: create(:work_item_type, :task) + work_item_type: WorkItems::Type.default_by_type(:task) } end diff --git a/spec/support/db_cleaner.rb b/spec/support/db_cleaner.rb index 588fe466a42..b9a99eff413 100644 --- a/spec/support/db_cleaner.rb +++ b/spec/support/db_cleaner.rb @@ -12,7 +12,7 @@ module DbCleaner end def deletion_except_tables - %w[work_item_types work_item_hierarchy_restrictions] + %w[work_item_types work_item_hierarchy_restrictions work_item_widget_definitions] end def setup_database_cleaner diff --git a/spec/support/shared_examples/models/chat_integration_shared_examples.rb b/spec/support/shared_examples/models/chat_integration_shared_examples.rb index fe880e4b31b..085fec6ff1e 100644 --- a/spec/support/shared_examples/models/chat_integration_shared_examples.rb +++ b/spec/support/shared_examples/models/chat_integration_shared_examples.rb @@ -165,7 +165,7 @@ RSpec.shared_examples "chat integration" do |integration_name| context "with issue events" do let(:opts) { { title: "Awesome issue", description: "please fix" } } let(:sample_data) do - service = Issues::CreateService.new(project: project, current_user: user, params: opts, spam_params: nil) + service = Issues::CreateService.new(container: project, current_user: user, params: opts, spam_params: nil) issue = service.execute[:issue] service.hook_data(issue, "open") end diff --git a/spec/support/shared_examples/work_item_base_types_importer.rb b/spec/support/shared_examples/work_item_base_types_importer.rb index b1011037584..1703d400aea 100644 --- a/spec/support/shared_examples/work_item_base_types_importer.rb +++ b/spec/support/shared_examples/work_item_base_types_importer.rb @@ -15,6 +15,22 @@ RSpec.shared_examples 'work item base types importer' do expect(WorkItems::Type.all).to all(be_valid) end + it 'creates all default widget definitions' do + WorkItems::WidgetDefinition.delete_all + widget_mapping = ::Gitlab::DatabaseImporters::WorkItems::BaseTypeImporter::WIDGETS_FOR_TYPE + + expect { subject }.to change { WorkItems::WidgetDefinition.count }.from(0).to(widget_mapping.values.flatten.count) + + created_widgets = WorkItems::WidgetDefinition.global.map do |widget| + { name: widget.work_item_type.name, type: widget.widget_type } + end + expected_widgets = widget_mapping.flat_map do |type_sym, widget_types| + widget_types.map { |type| { name: ::WorkItems::Type::TYPE_NAMES[type_sym], type: type.to_s } } + end + + expect(created_widgets).to match_array(expected_widgets) + end + it 'upserts base work item types if they already exist' do first_type = WorkItems::Type.first original_name = first_type.name @@ -29,8 +45,34 @@ RSpec.shared_examples 'work item base types importer' do ) end - it 'executes a single INSERT query' do - expect { subject }.to make_queries_matching(/INSERT/, 1) + it 'upserts default widget definitions if they already exist and type changes' do + widget = WorkItems::WidgetDefinition.global.find_by_widget_type(:labels) + + widget.update!(widget_type: :weight) + + expect do + subject + widget.reload + end.to not_change(WorkItems::WidgetDefinition, :count).and( + change { widget.widget_type }.from('weight').to('labels') + ) + end + + it 'does not change default widget definitions if they already exist with changed disabled status' do + widget = WorkItems::WidgetDefinition.global.find_by_widget_type(:labels) + + widget.update!(disabled: true) + + expect do + subject + widget.reload + end.to not_change(WorkItems::WidgetDefinition, :count).and( + not_change { widget.disabled } + ) + end + + it 'executes single INSERT query per types and widget definitions' do + expect { subject }.to make_queries_matching(/INSERT/, 2) end context 'when some base types exist' do @@ -39,10 +81,22 @@ RSpec.shared_examples 'work item base types importer' do end it 'inserts all types and does nothing if some already existed' do - expect { subject }.to make_queries_matching(/INSERT/, 1).and( + expect { subject }.to make_queries_matching(/INSERT/, 2).and( change { WorkItems::Type.count }.by(1) ) expect(WorkItems::Type.count).to eq(WorkItems::Type::BASE_TYPES.count) end end + + context 'when some widget definitions exist' do + before do + WorkItems::WidgetDefinition.limit(1).delete_all + end + + it 'inserts all widget definitions and does nothing if some already existed' do + expect { subject }.to make_queries_matching(/INSERT/, 2).and( + change { WorkItems::WidgetDefinition.count }.by(1) + ) + end + end end diff --git a/spec/workers/pipeline_schedule_worker_spec.rb b/spec/workers/pipeline_schedule_worker_spec.rb index db58dc00338..da6a0254a17 100644 --- a/spec/workers/pipeline_schedule_worker_spec.rb +++ b/spec/workers/pipeline_schedule_worker_spec.rb @@ -49,19 +49,7 @@ RSpec.describe PipelineScheduleWorker, :sidekiq_inline, feature_category: :conti end end - shared_examples 'successful scheduling with/without ci_use_run_pipeline_schedule_worker' do - it_behaves_like 'successful scheduling' - - context 'when feature flag ci_use_run_pipeline_schedule_worker is disabled' do - before do - stub_feature_flags(ci_use_run_pipeline_schedule_worker: false) - end - - it_behaves_like 'successful scheduling' - end - end - - it_behaves_like 'successful scheduling with/without ci_use_run_pipeline_schedule_worker' + it_behaves_like 'successful scheduling' context 'when the latest commit contains [ci skip]' do before do @@ -70,7 +58,7 @@ RSpec.describe PipelineScheduleWorker, :sidekiq_inline, feature_category: :conti .and_return('some commit [ci skip]') end - it_behaves_like 'successful scheduling with/without ci_use_run_pipeline_schedule_worker' + it_behaves_like 'successful scheduling' end end diff --git a/spec/workers/run_pipeline_schedule_worker_spec.rb b/spec/workers/run_pipeline_schedule_worker_spec.rb index 377333b39e8..75938d3b793 100644 --- a/spec/workers/run_pipeline_schedule_worker_spec.rb +++ b/spec/workers/run_pipeline_schedule_worker_spec.rb @@ -79,16 +79,6 @@ RSpec.describe RunPipelineScheduleWorker, feature_category: :continuous_integrat expect { worker.perform(pipeline_schedule.id, user.id) }.not_to change { pipeline_schedule.reload.next_run_at } end - context 'when feature flag ci_use_run_pipeline_schedule_worker is disabled' do - before do - stub_feature_flags(ci_use_run_pipeline_schedule_worker: false) - end - - it 'does not change the next_run_at' do - expect { worker.perform(pipeline_schedule.id, user.id) }.not_to change { pipeline_schedule.reload.next_run_at } - end - end - context 'when scheduling option is given as true' do it "returns the service response" do expect(worker.perform(pipeline_schedule.id, user.id, scheduling: true)).to eq(service_response) @@ -103,16 +93,6 @@ RSpec.describe RunPipelineScheduleWorker, feature_category: :continuous_integrat it "changes the next_run_at" do expect { worker.perform(pipeline_schedule.id, user.id, scheduling: true) }.to change { pipeline_schedule.reload.next_run_at }.by(1.day) end - - context 'when feature flag ci_use_run_pipeline_schedule_worker is disabled' do - before do - stub_feature_flags(ci_use_run_pipeline_schedule_worker: false) - end - - it 'does not change the next_run_at' do - expect { worker.perform(pipeline_schedule.id, user.id, scheduling: true) }.not_to change { pipeline_schedule.reload.next_run_at } - end - end end end @@ -148,26 +128,6 @@ RSpec.describe RunPipelineScheduleWorker, feature_category: :continuous_integrat worker.perform(pipeline_schedule.id, user.id) end - - context 'when feature flag ci_use_run_pipeline_schedule_worker is disabled' do - let(:pipeline) { instance_double(Ci::Pipeline, persisted?: true) } - - before do - stub_feature_flags(ci_use_run_pipeline_schedule_worker: false) - - expect(Ci::CreatePipelineService).to receive(:new).with(project, user, ref: pipeline_schedule.ref).and_return(create_pipeline_service) - - expect(create_pipeline_service).to receive(:execute).with(:schedule, ignore_skip_ci: true, save_on_errors: false, schedule: pipeline_schedule).and_return(service_response) - end - - it 'does not change the next_run_at' do - expect { worker.perform(pipeline_schedule.id, user.id) }.to not_change { pipeline_schedule.reload.next_run_at } - end - - it "returns the service response" do - expect(worker.perform(pipeline_schedule.id, user.id)).to eq(service_response) - end - end end end |