diff options
author | GitLab Bot <gitlab-bot@gitlab.com> | 2023-12-22 00:07:34 +0300 |
---|---|---|
committer | GitLab Bot <gitlab-bot@gitlab.com> | 2023-12-22 00:07:34 +0300 |
commit | 909dcab6e1f82095408cf4adfe099b463f094301 (patch) | |
tree | d8b4ee0cf1a5313b75c7b039ae52b74d03c6bfd6 /spec | |
parent | d2f2219fd58e572c10d77183e2f65de8fcc8df96 (diff) |
Add latest changes from gitlab-org/gitlab@master
Diffstat (limited to 'spec')
15 files changed, 298 insertions, 46 deletions
diff --git a/spec/controllers/projects/security/configuration_controller_spec.rb b/spec/controllers/projects/security/configuration_controller_spec.rb index 1ce0fcd85db..bfd269f9398 100644 --- a/spec/controllers/projects/security/configuration_controller_spec.rb +++ b/spec/controllers/projects/security/configuration_controller_spec.rb @@ -48,19 +48,6 @@ RSpec.describe Projects::Security::ConfigurationController do expect(sast_feature['available']).to be_truthy expect(dast_feature['available']).to be_falsey end - - context 'with feature flag unify_security_configuration turned off' do - before do - stub_feature_flags(unify_security_configuration: false) - end - - it 'responds with empty configuration data json' do - get :show, params: { namespace_id: project.namespace, project_id: project, format: :json } - - expect(response).to have_gitlab_http_status(:ok) - expect(json_response).to be_empty - end - end end end end diff --git a/spec/graphql/resolvers/concerns/resolves_groups_spec.rb b/spec/graphql/resolvers/concerns/resolves_groups_spec.rb index 79f3708da22..8f0918b3a50 100644 --- a/spec/graphql/resolvers/concerns/resolves_groups_spec.rb +++ b/spec/graphql/resolvers/concerns/resolves_groups_spec.rb @@ -40,8 +40,6 @@ RSpec.describe ResolvesGroups do group_ids = groups.map(&:id) allow_next(resolver).to receive(:resolve_groups).and_return(Group.id_in(group_ids)) - # Prevent authorization queries from affecting the test. - allow(Ability).to receive(:allowed?).and_return(true) single_group_query = ActiveRecord::QueryRecorder.new do data = query_groups(limit: 1) diff --git a/spec/graphql/types/ci/catalog/resources/version_type_spec.rb b/spec/graphql/types/ci/catalog/resources/version_type_spec.rb index 088973cf8f7..e218be57819 100644 --- a/spec/graphql/types/ci/catalog/resources/version_type_spec.rb +++ b/spec/graphql/types/ci/catalog/resources/version_type_spec.rb @@ -11,7 +11,9 @@ RSpec.describe Types::Ci::Catalog::Resources::VersionType, feature_category: :pi created_at released_at tag_name + name tag_path + path author commit components diff --git a/spec/graphql/types/work_items/widgets/notes_type_spec.rb b/spec/graphql/types/work_items/widgets/notes_type_spec.rb index 3ac61a59a9c..4738197e59f 100644 --- a/spec/graphql/types/work_items/widgets/notes_type_spec.rb +++ b/spec/graphql/types/work_items/widgets/notes_type_spec.rb @@ -4,7 +4,7 @@ require 'spec_helper' RSpec.describe Types::WorkItems::Widgets::NotesType, feature_category: :team_planning do it 'exposes the expected fields' do - expected_fields = %i[discussions type] + expected_fields = %i[discussions type discussion_locked] expect(described_class).to have_graphql_fields(*expected_fields) end diff --git a/spec/migrations/20231207145335_cleanup_group_level_work_items_spec.rb b/spec/migrations/20231207145335_cleanup_group_level_work_items_spec.rb new file mode 100644 index 00000000000..a6b547b091a --- /dev/null +++ b/spec/migrations/20231207145335_cleanup_group_level_work_items_spec.rb @@ -0,0 +1,216 @@ +# frozen_string_literal: true + +require 'spec_helper' +require_migration! + +RSpec.describe CleanupGroupLevelWorkItems, feature_category: :team_planning do + include MigrationHelpers::WorkItemTypesHelper + + let(:users) { table(:users) } + let(:projects) { table(:projects) } + let(:namespaces) { table(:namespaces) } + let(:issues) { table(:issues) } + let(:notes) { table(:notes) } + let(:labels) { table(:labels) } + let(:label_links) { table(:label_links) } + let(:todos) { table(:todos) } + let(:work_item_types) { table(:work_item_types) } + + let!(:user) { users.create!(name: 'Test User', email: 'test@example.com', projects_limit: 5) } + + let!(:group1) { namespaces.create!(name: 'group1', path: 'group1', type: 'Group') } + let!(:group2) { namespaces.create!(name: 'group2', path: 'group2', type: 'Group') } + let!(:project_namespace) { namespaces.create!(name: 'project1', path: 'project1', type: 'Project') } + let!(:project) do + projects.create!( + name: 'project1', path: 'project1', namespace_id: group1.id, project_namespace_id: project_namespace.id + ) + end + + let!(:issue_type) do + ensure_work_item_type_exists + work_item_types.first + end + + let!(:group1_issue1) { issues.create!(title: 'Issue1-1', namespace_id: group1.id, work_item_type_id: issue_type.id) } + let!(:group1_issue2) { issues.create!(title: 'Issue1-2', namespace_id: group1.id, work_item_type_id: issue_type.id) } + let!(:group2_issue1) { issues.create!(title: 'Issue2-1', namespace_id: group2.id, work_item_type_id: issue_type.id) } + let!(:group2_issue2) { issues.create!(title: 'Issue2-2', namespace_id: group2.id, work_item_type_id: issue_type.id) } + let!(:project_issue) do + issues.create!( + title: 'Issue2', project_id: project.id, namespace_id: project_namespace.id, work_item_type_id: issue_type.id + ) + end + + # associated labels + let!(:label1) { labels.create!(title: 'label1', group_id: group1.id) } + let!(:label2) { labels.create!(title: 'label2', group_id: group2.id) } + + after(:all) do + # Make sure base types are recreated after running the migration + # because migration specs are not run in a transaction + reset_work_item_types + end + + describe '#up' do + before do + # stub batch to make sure we are also testing the batching deletion + stub_const("#{described_class}::BATCH_SIZE", 2) + + # Project label_link that must not be deleted + label_links.create!(label_id: label1.id, target_id: project_issue.id, target_type: 'Issue') + + label_links.create!(label_id: label1.id, target_id: group1_issue1.id, target_type: 'Issue') + label_links.create!(label_id: label2.id, target_id: group1_issue1.id, target_type: 'Issue') + label_links.create!(label_id: label1.id, target_id: group1_issue2.id, target_type: 'Issue') + label_links.create!(label_id: label2.id, target_id: group1_issue2.id, target_type: 'Issue') + label_links.create!(label_id: label1.id, target_id: group2_issue1.id, target_type: 'Issue') + label_links.create!(label_id: label2.id, target_id: group2_issue1.id, target_type: 'Issue') + label_links.create!(label_id: label1.id, target_id: group2_issue2.id, target_type: 'Issue') + label_links.create!(label_id: label2.id, target_id: group2_issue2.id, target_type: 'Issue') + + # associated notes + + # Project issue note that must not be deleted + notes.create!( + noteable_id: project_issue.id, + noteable_type: 'Issue', + project_id: project.id, + namespace_id: project_namespace.id, + note: "project issue 1 note 1" + ) + + notes.create!( + noteable_id: group1_issue1.id, noteable_type: 'Issue', namespace_id: group1.id, note: "group1 issue 1 note 1" + ) + notes.create!( + noteable_id: group1_issue1.id, noteable_type: 'Issue', namespace_id: group1.id, note: "group1 issue 1 note 2" + ) + notes.create!( + noteable_id: group1_issue2.id, noteable_type: 'Issue', namespace_id: group1.id, note: "group1 issue 2 note 1" + ) + notes.create!( + noteable_id: group1_issue2.id, noteable_type: 'Issue', namespace_id: group1.id, note: "group1 issue 2 note 2" + ) + notes.create!( + noteable_id: group2_issue1.id, noteable_type: 'Issue', namespace_id: group2.id, note: "group2 issue 1 note 1" + ) + notes.create!( + noteable_id: group2_issue1.id, noteable_type: 'Issue', namespace_id: group2.id, note: "group2 issue 1 note 2" + ) + notes.create!( + noteable_id: group2_issue2.id, noteable_type: 'Issue', namespace_id: group2.id, note: "group2 issue 2 note 1" + ) + notes.create!( + noteable_id: group2_issue2.id, noteable_type: 'Issue', namespace_id: group2.id, note: "group2 issue 2 note 2" + ) + + # associated todos + + # Project issue todo that must not be deleted + todos.create!( + target_id: project_issue.id, + target_type: 'Issue', + project_id: project.id, + user_id: user.id, + author_id: user.id, + action: 1, + state: 'pending' + ) + + todos.create!( + target_id: group1_issue1.id, + target_type: 'Issue', + group_id: group1.id, + user_id: user.id, + author_id: user.id, + action: 1, + state: 'pending' + ) + todos.create!( + target_id: group1_issue1.id, + target_type: 'Issue', + group_id: group1.id, + user_id: user.id, + author_id: user.id, + action: 1, + state: 'pending' + ) + todos.create!( + target_id: group1_issue2.id, + target_type: 'Issue', + group_id: group1.id, + user_id: user.id, + author_id: user.id, + action: 1, + state: 'pending' + ) + todos.create!( + target_id: group1_issue2.id, + target_type: 'Issue', + group_id: group1.id, + user_id: user.id, + author_id: user.id, + action: 1, + state: 'pending' + ) + todos.create!( + target_id: group2_issue1.id, + target_type: 'Issue', + group_id: group2.id, + user_id: user.id, + author_id: user.id, + action: 1, + state: 'pending' + ) + todos.create!( + target_id: group2_issue1.id, + target_type: 'Issue', + group_id: group2.id, + user_id: user.id, + author_id: user.id, + action: 1, + state: 'pending' + ) + todos.create!( + target_id: group2_issue2.id, + target_type: 'Issue', + group_id: group2.id, + user_id: user.id, + author_id: user.id, + action: 1, + state: 'pending' + ) + todos.create!( + target_id: group2_issue2.id, + target_type: 'Issue', + group_id: group2.id, + user_id: user.id, + author_id: user.id, + action: 1, + state: 'pending' + ) + end + + it 'removes group level issues' do + # We have 1 record of each table that should not be deleted + expect do + migrate! + end.to change { issues.count }.from(5).to(1).and( + change { label_links.count }.from(9).to(1) + ).and( + change { notes.count }.from(9).to(1) + ).and( + change { todos.count }.from(9).to(1) + ) + end + end + + def ensure_work_item_type_exists + # We need to make sure at least one work item type exists for this spec and they might have been deleted + # by other migrations + work_item_types.find_or_create_by!( + name: 'Issue', namespace_id: nil, base_type: 0, icon_name: 'issue-type-issue' + ) + end +end diff --git a/spec/models/project_spec.rb b/spec/models/project_spec.rb index f7402c273fb..a3db29e7ec4 100644 --- a/spec/models/project_spec.rb +++ b/spec/models/project_spec.rb @@ -7980,6 +7980,24 @@ RSpec.describe Project, factory_default: :keep, feature_category: :groups_and_pr expect(project.reload.topics.map(&:name)).to eq(%w[topic1 topic2 topic3]) end + + it 'assigns slug value for new topics' do + topic = create(:topic, name: 'old topic', title: 'old topic', slug: nil) + project.topic_list = topic.name + project.save! + + project.topic_list = 'old topic, new topic' + expect { expect(project.save).to be true }.to change { Projects::Topic.count }.by(1) + + topics = project.reset.topics + expect(topics.map(&:name)).to match_array(['old topic', 'new topic']) + + old_topic = topics.first + new_topic = topics.last + + expect(old_topic.slug).to be_nil + expect(new_topic.slug).to eq('newtopic') + end end context 'public topics counter' do diff --git a/spec/models/projects/topic_spec.rb b/spec/models/projects/topic_spec.rb index ebe53f3761d..e322fbbbcc3 100644 --- a/spec/models/projects/topic_spec.rb +++ b/spec/models/projects/topic_spec.rb @@ -32,6 +32,21 @@ RSpec.describe Projects::Topic do it { is_expected.not_to allow_value("new\nline").for(:name).with_message(name_format_message) } it { is_expected.not_to allow_value("new\rline").for(:name).with_message(name_format_message) } it { is_expected.not_to allow_value("new\vline").for(:name).with_message(name_format_message) } + + context 'for slug' do + let(:slug_format_message) { "can contain only letters, digits, '_', '-', '.'" } + + it { is_expected.to validate_length_of(:slug).is_at_most(255) } + it { is_expected.to validate_uniqueness_of(:slug).case_insensitive } + + it { is_expected.not_to allow_value("new\nline").for(:slug).with_message(slug_format_message) } + it { is_expected.not_to allow_value("space value").for(:slug).with_message(slug_format_message) } + it { is_expected.not_to allow_value("$special_symbol_value").for(:slug).with_message(slug_format_message) } + + it { is_expected.to allow_value("underscored_value").for(:slug) } + it { is_expected.to allow_value("hypened-value").for(:slug) } + it { is_expected.to allow_value("dotted.value").for(:slug) } + end end describe 'scopes' do diff --git a/spec/requests/api/graphql/ci/catalog/resource_spec.rb b/spec/requests/api/graphql/ci/catalog/resource_spec.rb index 9fe73e7ba45..24f9b6031f4 100644 --- a/spec/requests/api/graphql/ci/catalog/resource_spec.rb +++ b/spec/requests/api/graphql/ci/catalog/resource_spec.rb @@ -164,8 +164,8 @@ RSpec.describe 'Query.ciCatalogResource', feature_category: :pipeline_compositio versions { nodes { id - tagName - tagPath + name + path releasedAt author { id @@ -202,15 +202,15 @@ RSpec.describe 'Query.ciCatalogResource', feature_category: :pipeline_compositio expect(graphql_data_at(:ciCatalogResource, :versions, :nodes)).to contain_exactly( a_graphql_entity_for( version1, - tagName: version1.name, - tagPath: project_tag_path(project, version1.name), + name: version1.name, + path: project_tag_path(project, version1.name), releasedAt: version1.released_at, author: a_graphql_entity_for(author, :name) ), a_graphql_entity_for( version2, - tagName: version2.name, - tagPath: project_tag_path(project, version2.name), + name: version2.name, + path: project_tag_path(project, version2.name), releasedAt: version2.released_at, author: a_graphql_entity_for(author, :name) ) @@ -237,8 +237,8 @@ RSpec.describe 'Query.ciCatalogResource', feature_category: :pipeline_compositio id latestVersion { id - tagName - tagPath + name + path releasedAt author { id @@ -273,8 +273,8 @@ RSpec.describe 'Query.ciCatalogResource', feature_category: :pipeline_compositio resource, latestVersion: a_graphql_entity_for( latest_version, - tagName: latest_version.name, - tagPath: project_tag_path(project, latest_version.name), + name: latest_version.name, + path: project_tag_path(project, latest_version.name), releasedAt: latest_version.released_at, author: a_graphql_entity_for(author, :name) ) diff --git a/spec/requests/api/graphql/ci/catalog/resources_spec.rb b/spec/requests/api/graphql/ci/catalog/resources_spec.rb index 49a3f3be1d7..150507fc442 100644 --- a/spec/requests/api/graphql/ci/catalog/resources_spec.rb +++ b/spec/requests/api/graphql/ci/catalog/resources_spec.rb @@ -106,7 +106,7 @@ RSpec.describe 'Query.ciCatalogResources', feature_category: :pipeline_compositi versions { nodes { id - tagName + name releasedAt author { id @@ -153,7 +153,7 @@ RSpec.describe 'Query.ciCatalogResources', feature_category: :pipeline_compositi id latestVersion { id - tagName + name releasedAt author { id @@ -185,7 +185,7 @@ RSpec.describe 'Query.ciCatalogResources', feature_category: :pipeline_compositi resource1, latestVersion: a_graphql_entity_for( latest_version1, - tagName: latest_version1.name, + name: latest_version1.name, releasedAt: latest_version1.released_at, author: a_graphql_entity_for(author1, :name) ) @@ -194,7 +194,7 @@ RSpec.describe 'Query.ciCatalogResources', feature_category: :pipeline_compositi public_resource, latestVersion: a_graphql_entity_for( latest_version2, - tagName: latest_version2.name, + name: latest_version2.name, releasedAt: latest_version2.released_at, author: a_graphql_entity_for(author2, :name) ) diff --git a/spec/requests/api/graphql/mutations/work_items/create_spec.rb b/spec/requests/api/graphql/mutations/work_items/create_spec.rb index 78b93c3210b..2c2cd5f2acc 100644 --- a/spec/requests/api/graphql/mutations/work_items/create_spec.rb +++ b/spec/requests/api/graphql/mutations/work_items/create_spec.rb @@ -281,6 +281,18 @@ RSpec.describe 'Create a work item', feature_category: :team_planning do it_behaves_like 'creates work item' + # This is a temporary measure just to ensure the internal id migration doesn't get conflicts + # More info in https://gitlab.com/gitlab-org/gitlab/-/merge_requests/139367 + context 'when making the request in a production environment' do + before do + stub_rails_env('production') + end + + it_behaves_like 'a mutation that returns top-level errors', errors: [ + 'Group level work items are disabled. Only project paths allowed in `namespacePath`.' + ] + end + context 'when the namespace_level_work_items feature flag is disabled' do before do stub_feature_flags(namespace_level_work_items: false) diff --git a/spec/services/projects/unlink_fork_service_spec.rb b/spec/services/projects/unlink_fork_service_spec.rb index 2e1a6c03c90..3199614104f 100644 --- a/spec/services/projects/unlink_fork_service_spec.rb +++ b/spec/services/projects/unlink_fork_service_spec.rb @@ -70,14 +70,6 @@ RSpec.describe Projects::UnlinkForkService, :use_clean_rails_memory_store_cachin subject.execute(refresh_statistics: false) end - it 'does not refresh project statistics when the feature flag is disabled' do - stub_feature_flags(refresh_statistics_on_unlink_fork: false) - - expect(ProjectCacheWorker).not_to receive(:perform_async) - - subject.execute - end - context 'when the original project was deleted' do it 'does not fail when the original project is deleted' do source = forked_project.forked_from_project diff --git a/spec/services/spam/spam_verdict_service_spec.rb b/spec/services/spam/spam_verdict_service_spec.rb index 361742699b0..8669bca90bd 100644 --- a/spec/services/spam/spam_verdict_service_spec.rb +++ b/spec/services/spam/spam_verdict_service_spec.rb @@ -263,11 +263,10 @@ RSpec.describe Spam::SpamVerdictService, feature_category: :instance_resiliency end context 'if the endpoint is accessible' do - let(:user_scores) { Abuse::UserTrustScore.new(user) } - before do allow(service).to receive(:spamcheck_client).and_return(spam_client) allow(spam_client).to receive(:spam?).and_return(spam_client_result) + allow(Labkit::Correlation::CorrelationId).to receive(:current_id).and_return('cid') end context 'if the result is a NOOP verdict' do @@ -275,8 +274,8 @@ RSpec.describe Spam::SpamVerdictService, feature_category: :instance_resiliency let(:verdict_value) { ::Spamcheck::SpamVerdict::Verdict::NOOP } it 'returns the verdict' do + expect(Abuse::TrustScoreWorker).not_to receive(:perform_async) is_expected.to eq(NOOP) - expect(user_scores.spam_score).to eq(0.0) end end @@ -286,8 +285,8 @@ RSpec.describe Spam::SpamVerdictService, feature_category: :instance_resiliency context 'the result was evaluated' do it 'returns the verdict and updates the spam score' do + expect(Abuse::TrustScoreWorker).to receive(:perform_async).once.with(user.id, :spamcheck, instance_of(Float), 'cid') is_expected.to eq(ALLOW) - expect(user_scores.spam_score).to be_within(0.000001).of(verdict_score) end end @@ -295,8 +294,8 @@ RSpec.describe Spam::SpamVerdictService, feature_category: :instance_resiliency let(:verdict_evaluated) { false } it 'returns the verdict and does not update the spam score' do + expect(Abuse::TrustScoreWorker).not_to receive(:perform_async) expect(subject).to eq(ALLOW) - expect(user_scores.spam_score).to eq(0.0) end end end @@ -317,8 +316,8 @@ RSpec.describe Spam::SpamVerdictService, feature_category: :instance_resiliency with_them do it "returns expected spam constant and updates the spam score" do + expect(Abuse::TrustScoreWorker).to receive(:perform_async).once.with(user.id, :spamcheck, instance_of(Float), 'cid') is_expected.to eq(expected) - expect(user_scores.spam_score).to be_within(0.000001).of(verdict_score) end end end diff --git a/spec/support/rspec_run_time.rb b/spec/support/rspec_run_time.rb index 977d4885624..3491e5f733a 100644 --- a/spec/support/rspec_run_time.rb +++ b/spec/support/rspec_run_time.rb @@ -87,7 +87,8 @@ module Support unless @last_elapsed_seconds.nil? || elapsed_seconds - @last_elapsed_seconds < 1 output.puts \ "# [RSpecRunTime] RSpec elapsed time: #{readable_duration(elapsed_seconds)}. " \ - "#{current_rss_in_megabytes}\n\n" + "#{current_rss_in_megabytes}. " \ + "#{load_average}\n\n" end @last_elapsed_seconds = elapsed_seconds @@ -98,6 +99,10 @@ module Support "Current RSS: ~#{rss_in_megabytes.round}M" end + + def load_average + `uptime`[/(load average:[^\n]+)/, 1] + end end end end diff --git a/spec/workers/ci/unlock_pipelines_in_queue_worker_spec.rb b/spec/workers/ci/unlock_pipelines_in_queue_worker_spec.rb index ca1d234eb5b..d48eed4ae90 100644 --- a/spec/workers/ci/unlock_pipelines_in_queue_worker_spec.rb +++ b/spec/workers/ci/unlock_pipelines_in_queue_worker_spec.rb @@ -101,6 +101,7 @@ RSpec.describe Ci::UnlockPipelinesInQueueWorker, :unlock_pipelines, :clean_gitla before do stub_feature_flags( + ci_unlock_pipelines_extra_low: false, ci_unlock_pipelines: false, ci_unlock_pipelines_medium: false, ci_unlock_pipelines_high: false @@ -109,6 +110,14 @@ RSpec.describe Ci::UnlockPipelinesInQueueWorker, :unlock_pipelines, :clean_gitla it { is_expected.to eq(0) } + context 'when ci_unlock_pipelines_extra_low flag is enabled' do + before do + stub_feature_flags(ci_unlock_pipelines_extra_low: true) + end + + it { is_expected.to eq(described_class::MAX_RUNNING_EXTRA_LOW) } + end + context 'when ci_unlock_pipelines flag is enabled' do before do stub_feature_flags(ci_unlock_pipelines: true) diff --git a/spec/workers/every_sidekiq_worker_spec.rb b/spec/workers/every_sidekiq_worker_spec.rb index 4f916f93b8b..4067bce8d8d 100644 --- a/spec/workers/every_sidekiq_worker_spec.rb +++ b/spec/workers/every_sidekiq_worker_spec.rb @@ -163,7 +163,6 @@ RSpec.describe 'Every Sidekiq worker', feature_category: :shared do 'Ci::InitialPipelineProcessWorker' => 3, 'Ci::MergeRequests::AddTodoWhenBuildFailsWorker' => 3, 'Ci::Minutes::UpdateProjectAndNamespaceUsageWorker' => 3, - 'Ci::Llm::GenerateConfigWorker' => 3, 'Ci::PipelineArtifacts::CoverageReportWorker' => 3, 'Ci::PipelineArtifacts::CreateQualityReportWorker' => 3, 'Ci::PipelineCleanupRefWorker' => 3, |