Welcome to mirror list, hosted at ThFree Co, Russian Federation.

gitlab.com/gitlab-org/gitlab-foss.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to 'spec/support')
-rw-r--r--spec/support/before_all_adapter.rb33
-rw-r--r--spec/support/database/prevent_cross_database_modification.rb7
-rw-r--r--spec/support/db_cleaner.rb2
-rw-r--r--spec/support/factory_bot.rb9
-rw-r--r--spec/support/finder_collection.rb2
-rw-r--r--spec/support/finder_collection_allowlist.yml1
-rw-r--r--spec/support/formatters/json_formatter.rb8
-rw-r--r--spec/support/helpers/admin_mode_helpers.rb27
-rw-r--r--spec/support/helpers/cycle_analytics_helpers.rb12
-rw-r--r--spec/support/helpers/database/duplicate_indexes.yml19
-rw-r--r--spec/support/helpers/database/multiple_databases_helpers.rb2
-rw-r--r--spec/support/helpers/debug_with_puts.rb13
-rw-r--r--spec/support/helpers/dns_helpers.rb24
-rw-r--r--spec/support/helpers/features/invite_members_modal_helpers.rb1
-rw-r--r--spec/support/helpers/login_helpers.rb27
-rw-r--r--spec/support/helpers/models/ci/partitioning_testing/partition_identifiers.rb4
-rw-r--r--spec/support/helpers/navbar_structure_helper.rb16
-rw-r--r--spec/support/helpers/orphan_final_artifacts_cleanup_helpers.rb82
-rw-r--r--spec/support/helpers/stub_configuration.rb7
-rw-r--r--spec/support/helpers/stub_gitlab_calls.rb4
-rw-r--r--spec/support/helpers/stub_requests.rb18
-rw-r--r--spec/support/helpers/user_with_namespace_shim.rb73
-rw-r--r--spec/support/helpers/user_with_namespace_shim.yml1000
-rw-r--r--spec/support/matchers/have_user.rb13
-rw-r--r--spec/support/migration.rb2
-rw-r--r--spec/support/rspec_order_todo.yml18
-rw-r--r--spec/support/rspec_run_time.rb11
-rw-r--r--spec/support/shared_contexts/ci/catalog/resources/version_shared_context.rb45
-rw-r--r--spec/support/shared_contexts/features/integrations/instance_integrations_shared_context.rb2
-rw-r--r--spec/support/shared_contexts/graphql/types/query_type_shared_context.rb2
-rw-r--r--spec/support/shared_contexts/lib/gitlab/database/partitioning/list_partitioning_shared_context.rb2
-rw-r--r--spec/support/shared_contexts/lib/gitlab/sidekiq_logging/structured_logger_shared_context.rb4
-rw-r--r--spec/support/shared_contexts/lib/gitlab/sidekiq_middleware/server_metrics_shared_context.rb1
-rw-r--r--spec/support/shared_examples/analytics/cycle_analytics/parentable_examples.rb13
-rw-r--r--spec/support/shared_examples/ci/runner_with_status_scope_shared_examples.rb29
-rw-r--r--spec/support/shared_examples/controllers/base_action_controller_shared_examples.rb4
-rw-r--r--spec/support/shared_examples/controllers/githubish_import_controller_shared_examples.rb6
-rw-r--r--spec/support/shared_examples/controllers/issuables_list_metadata_shared_examples.rb2
-rw-r--r--spec/support/shared_examples/controllers/snippet_shared_examples.rb4
-rw-r--r--spec/support/shared_examples/controllers/variables_shared_examples.rb3
-rw-r--r--spec/support/shared_examples/features/inviting_groups_shared_examples.rb2
-rw-r--r--spec/support/shared_examples/features/variable_list_drawer_shared_examples.rb2
-rw-r--r--spec/support/shared_examples/features/work_items_shared_examples.rb279
-rw-r--r--spec/support/shared_examples/lib/gitlab/import_export/import_failure_service_shared_examples.rb1
-rw-r--r--spec/support/shared_examples/migrations/add_work_item_widget_shared_examples.rb10
-rw-r--r--spec/support/shared_examples/models/concerns/integrations/base_slack_notification_shared_examples.rb2
-rw-r--r--spec/support/shared_examples/models/concerns/integrations/slack_mattermost_notifier_shared_examples.rb2
-rw-r--r--spec/support/shared_examples/models/concerns/repository_storage_movable_shared_examples.rb2
-rw-r--r--spec/support/shared_examples/models/database_event_tracking_shared_examples.rb49
-rw-r--r--spec/support/shared_examples/models/member_shared_examples.rb96
-rw-r--r--spec/support/shared_examples/models/members_notifications_shared_example.rb42
-rw-r--r--spec/support/shared_examples/models/relative_positioning_shared_examples.rb6
-rw-r--r--spec/support/shared_examples/quick_actions/merge_request/rebase_quick_action_shared_examples.rb6
-rw-r--r--spec/support/shared_examples/redis/multi_store_wrapper_shared_examples.rb74
-rw-r--r--spec/support/shared_examples/redis/redis_new_instance_shared_examples.rb37
-rw-r--r--spec/support/shared_examples/redis/redis_shared_examples.rb67
-rw-r--r--spec/support/shared_examples/requests/api/terraform/modules/v1/packages_shared_examples.rb175
-rw-r--r--spec/support/shared_examples/serializers/environment_serializer_shared_examples.rb4
-rw-r--r--spec/support/shared_examples/services/boards/issues_move_service_shared_examples.rb8
-rw-r--r--spec/support/shared_examples/services/common_system_notes_shared_examples.rb6
-rw-r--r--spec/support/shared_examples/services/count_service_shared_examples.rb4
-rw-r--r--spec/support/shared_examples/services/destroy_label_links_shared_examples.rb4
-rw-r--r--spec/support/shared_examples/services/jira/requests/base_shared_examples.rb1
-rw-r--r--spec/support/shared_examples/services/namespace_package_settings_shared_examples.rb4
-rw-r--r--spec/support/shared_examples/services/packages/debian/generate_distribution_shared_examples.rb4
-rw-r--r--spec/support/shared_examples/services/protected_branches_shared_examples.rb41
-rw-r--r--spec/support/shared_examples/work_item_hierarchy_restrictions_importer.rb17
-rw-r--r--spec/support/shared_examples/work_items/widgetable_service_shared_examples.rb6
-rw-r--r--spec/support/shared_examples/workers/gitlab/github_import/stage_methods_shared_examples.rb181
-rw-r--r--spec/support/sidekiq.rb10
-rw-r--r--spec/support/sidekiq_middleware.rb9
71 files changed, 2308 insertions, 395 deletions
diff --git a/spec/support/before_all_adapter.rb b/spec/support/before_all_adapter.rb
deleted file mode 100644
index 35846fcecb8..00000000000
--- a/spec/support/before_all_adapter.rb
+++ /dev/null
@@ -1,33 +0,0 @@
-# frozen_string_literal: true
-
-module TestProfBeforeAllAdapter
- module MultipleDatabaseAdapter
- def self.all_connection_classes
- @all_connection_classes ||= [ActiveRecord::Base] + ActiveRecord::Base.descendants.select(&:connection_class?) # rubocop: disable Database/MultipleDatabases
- end
-
- def self.begin_transaction
- self.all_connection_classes.each do |connection_class|
- connection_class.connection.begin_transaction(joinable: false)
- end
- end
-
- def self.rollback_transaction
- self.all_connection_classes.each do |connection_class|
- if connection_class.connection.open_transactions.zero?
- warn "!!! before_all transaction has been already rollbacked and " \
- "could work incorrectly"
- next
- end
-
- connection_class.connection.rollback_transaction
- end
- end
- end
-
- def self.default_adapter
- MultipleDatabaseAdapter
- end
-end
-
-TestProf::BeforeAll.adapter = ::TestProfBeforeAllAdapter.default_adapter
diff --git a/spec/support/database/prevent_cross_database_modification.rb b/spec/support/database/prevent_cross_database_modification.rb
index 02572d011f7..948bc21dafa 100644
--- a/spec/support/database/prevent_cross_database_modification.rb
+++ b/spec/support/database/prevent_cross_database_modification.rb
@@ -68,4 +68,11 @@ RSpec.configure do |config|
::ApplicationRecord.gitlab_transactions_stack.clear
end
+
+ config.before(:suite) do
+ ActiveSupport::Notifications.subscribe("factory_bot.run_factory") do |_name, _start, _finish, _id, payload|
+ strategy = payload[:strategy]
+ Thread.current[:factory_bot_objects] -= 1 if strategy == :create
+ end
+ end
end
diff --git a/spec/support/db_cleaner.rb b/spec/support/db_cleaner.rb
index 0a1d68a744c..b6539d6215b 100644
--- a/spec/support/db_cleaner.rb
+++ b/spec/support/db_cleaner.rb
@@ -2,7 +2,7 @@
module DbCleaner
def all_connection_classes
- ::TestProfBeforeAllAdapter::MultipleDatabaseAdapter.all_connection_classes
+ ::TestProf::BeforeAll::Adapters::ActiveRecord.all_connections.map(&:connection_class).uniq
end
def delete_from_all_tables!(except: [])
diff --git a/spec/support/factory_bot.rb b/spec/support/factory_bot.rb
index d30098a5cc0..00aa54990ef 100644
--- a/spec/support/factory_bot.rb
+++ b/spec/support/factory_bot.rb
@@ -4,13 +4,14 @@ FactoryBot.define do
after(:build) do |object, _|
next unless object.respond_to?(:factory_bot_built=)
+ # This will help the PreventCrossDatabaseModification to temporarily
+ # allow the object table when it's saved later.
object.factory_bot_built = true
end
- before(:create) do |object, _|
- next unless object.respond_to?(:factory_bot_built=)
-
- object.factory_bot_built = false
+ before(:create) do |_object, _|
+ Thread.current[:factory_bot_objects] ||= 0
+ Thread.current[:factory_bot_objects] += 1
end
end
diff --git a/spec/support/finder_collection.rb b/spec/support/finder_collection.rb
index 494dd4bdca1..93363943449 100644
--- a/spec/support/finder_collection.rb
+++ b/spec/support/finder_collection.rb
@@ -1,6 +1,6 @@
# frozen_string_literal: true
-require 'set'
+require 'set' # rubocop:disable Lint/RedundantRequireStatement -- Ruby 3.1 and earlier needs this. Drop this line after Ruby 3.2+ is only supported.
module Support
# Ensure that finders' `execute` method always returns
diff --git a/spec/support/finder_collection_allowlist.yml b/spec/support/finder_collection_allowlist.yml
index e60cc4278af..37c9da4e4a8 100644
--- a/spec/support/finder_collection_allowlist.yml
+++ b/spec/support/finder_collection_allowlist.yml
@@ -63,6 +63,7 @@
- Security::PipelineVulnerabilitiesFinder
- Security::ScanExecutionPoliciesFinder
- Security::ScanResultPoliciesFinder
+- Security::SecurityPoliciesFinder
- SentryIssueFinder
- ServerlessDomainFinder
- TagsFinder
diff --git a/spec/support/formatters/json_formatter.rb b/spec/support/formatters/json_formatter.rb
index a54004b3024..398ff0187a1 100644
--- a/spec/support/formatters/json_formatter.rb
+++ b/spec/support/formatters/json_formatter.rb
@@ -89,7 +89,13 @@ module Support
[metadata[:file_path], metadata[:line_number]]
else
# If there are nested shared examples, the outermost location is last in the array
- metadata[:shared_group_inclusion_backtrace].last.formatted_inclusion_location.split(':')
+ (
+ metadata[:shared_group_inclusion_backtrace].last.formatted_inclusion_location ||
+ # RSpec ignores some paths by default, e.g. bin/, which result in the above being nil.
+ # Source: https://github.com/rspec/rspec-core/blob/v3.12.2/lib/rspec/core/backtrace_formatter.rb#L11
+ # In that case, we fallback to use the raw `#inclusion_location`.
+ metadata[:shared_group_inclusion_backtrace].last.inclusion_location
+ ).split(':')
end
end
diff --git a/spec/support/helpers/admin_mode_helpers.rb b/spec/support/helpers/admin_mode_helpers.rb
index a6e31791127..8b71552f928 100644
--- a/spec/support/helpers/admin_mode_helpers.rb
+++ b/spec/support/helpers/admin_mode_helpers.rb
@@ -5,17 +5,30 @@
module AdminModeHelper
# Administrators are logged in by default in user mode and have to switch to admin
# mode for accessing any administrative functionality. This helper lets a user
- # be in admin mode without requiring a second authentication step (provided
- # the user is an admin)
+ # access the admin area in two different ways:
+ #
+ # * Fast (use_ui: false) and suitable form the most use cases: fakes calls and grants
+ # access to the admin area without requiring a second authentication step (provided the
+ # user is an admin)
+ # * Slow (use_ui: true): visits the admin UI and enters the users password. A second
+ # authentication step may be needed.
#
# See also tag :enable_admin_mode in spec/spec_helper.rb for a spec-wide
# alternative
- def enable_admin_mode!(user)
- fake_user_mode = instance_double(Gitlab::Auth::CurrentUserMode)
+ def enable_admin_mode!(user, use_ui: false)
+ if use_ui
+ visit new_admin_session_path
+ fill_in 'user_password', with: user.password
+ click_button 'Enter admin mode'
+
+ wait_for_requests
+ else
+ fake_user_mode = instance_double(Gitlab::Auth::CurrentUserMode)
- allow(Gitlab::Auth::CurrentUserMode).to receive(:new).and_call_original
+ allow(Gitlab::Auth::CurrentUserMode).to receive(:new).and_call_original
- allow(Gitlab::Auth::CurrentUserMode).to receive(:new).with(user).and_return(fake_user_mode)
- allow(fake_user_mode).to receive(:admin_mode?).and_return(user&.admin?)
+ allow(Gitlab::Auth::CurrentUserMode).to receive(:new).with(user).and_return(fake_user_mode)
+ allow(fake_user_mode).to receive(:admin_mode?).and_return(user&.admin?)
+ end
end
end
diff --git a/spec/support/helpers/cycle_analytics_helpers.rb b/spec/support/helpers/cycle_analytics_helpers.rb
index 890fefcc7de..d54dcc8a31d 100644
--- a/spec/support/helpers/cycle_analytics_helpers.rb
+++ b/spec/support/helpers/cycle_analytics_helpers.rb
@@ -14,12 +14,14 @@ module CycleAnalyticsHelpers
page.all('.gl-path-button').collect(&:text).map { |name_with_median| name_with_median.split("\n")[0] }
end
- def fill_in_custom_stage_fields
+ def fill_in_custom_stage_fields(stage_name = nil)
index = page.all('[data-testid="value-stream-stage-fields"]').length
last_stage = page.all('[data-testid="value-stream-stage-fields"]').last
+ stage_name = "Cool custom stage - name #{index}" if stage_name.blank?
+
within last_stage do
- find('[name*="custom-stage-name-"]').fill_in with: "Cool custom stage - name #{index}"
+ find('[name*="custom-stage-name-"]').fill_in with: stage_name
select_dropdown_option_by_value "custom-stage-start-event-", 'Merge request created'
select_dropdown_option_by_value "custom-stage-end-event-", 'Merge request merged'
end
@@ -94,8 +96,8 @@ module CycleAnalyticsHelpers
wait_for_requests
end
- def create_value_stream_aggregation(group_or_project_namespace)
- aggregation = Analytics::CycleAnalytics::Aggregation.safe_create_for_namespace(group_or_project_namespace)
+ def create_value_stream_aggregation(namespace)
+ aggregation = Analytics::CycleAnalytics::Aggregation.safe_create_for_namespace(namespace)
Analytics::CycleAnalytics::AggregatorService.new(aggregation: aggregation).execute
end
@@ -123,7 +125,7 @@ module CycleAnalyticsHelpers
def create_commit(message, project, user, branch_name, count: 1, commit_time: nil, skip_push_handler: false)
repository = project.repository
- oldrev = repository.commit(branch_name)&.sha || Gitlab::Git::BLANK_SHA
+ oldrev = repository.commit(branch_name)&.sha || Gitlab::Git::SHA1_BLANK_SHA
commit_shas = Array.new(count) do |index|
commit_sha = repository.create_file(user, generate(:branch), "content", message: message, branch_name: branch_name)
diff --git a/spec/support/helpers/database/duplicate_indexes.yml b/spec/support/helpers/database/duplicate_indexes.yml
index ab9935a7a98..80d409f233d 100644
--- a/spec/support/helpers/database/duplicate_indexes.yml
+++ b/spec/support/helpers/database/duplicate_indexes.yml
@@ -27,6 +27,9 @@ boards_epic_board_recent_visits:
boards_epic_user_preferences:
index_boards_epic_user_preferences_on_board_user_epic_unique:
- index_boards_epic_user_preferences_on_board_id
+ci_build_trace_metadata:
+ index_ci_build_trace_metadata_on_trace_artifact_id:
+ - index_ci_build_trace_metadata_on_trace_artifact_id_partition_id
ci_job_artifacts:
index_ci_job_artifacts_on_id_project_id_and_created_at:
- index_ci_job_artifacts_on_project_id
@@ -63,9 +66,6 @@ error_tracking_errors:
geo_node_namespace_links:
index_geo_node_namespace_links_on_geo_node_id_and_namespace_id:
- index_geo_node_namespace_links_on_geo_node_id
-in_product_marketing_emails:
- index_in_product_marketing_emails_on_user_track_series:
- - index_in_product_marketing_emails_on_user_id
incident_management_oncall_participants:
index_inc_mgmnt_oncall_participants_on_user_id_and_rotation_id:
- index_inc_mgmnt_oncall_participants_on_oncall_user_id
@@ -102,19 +102,6 @@ ml_models:
p_ci_runner_machine_builds:
index_p_ci_runner_machine_builds_on_runner_machine_id:
- index_ci_runner_machine_builds_on_runner_machine_id
-packages_debian_group_distributions:
- uniq_pkgs_debian_group_distributions_group_id_and_codename:
- - index_packages_debian_group_distributions_on_group_id
- uniq_pkgs_debian_group_distributions_group_id_and_suite:
- - index_packages_debian_group_distributions_on_group_id
-packages_debian_project_distributions:
- uniq_pkgs_debian_project_distributions_project_id_and_codename:
- - index_packages_debian_project_distributions_on_project_id
- uniq_pkgs_debian_project_distributions_project_id_and_suite:
- - index_packages_debian_project_distributions_on_project_id
-packages_tags:
- index_packages_tags_on_package_id_and_updated_at:
- - index_packages_tags_on_package_id
pages_domains:
index_pages_domains_on_project_id_and_enabled_until:
- index_pages_domains_on_project_id
diff --git a/spec/support/helpers/database/multiple_databases_helpers.rb b/spec/support/helpers/database/multiple_databases_helpers.rb
index bccd6979af1..9df0685e46a 100644
--- a/spec/support/helpers/database/multiple_databases_helpers.rb
+++ b/spec/support/helpers/database/multiple_databases_helpers.rb
@@ -85,7 +85,7 @@ module Database
# The usage of this method switches temporarily used `connection_handler`
# allowing full manipulation of ActiveRecord::Base connections without
# having side effects like:
- # - misaligned transactions since this is managed by `BeforeAllAdapter`
+ # - misaligned transactions since this is managed by `TestProf::BeforeAll::Adapters::ActiveRecord`
# - removal of primary connections
#
# The execution within a block ensures safe cleanup of all allocated resources.
diff --git a/spec/support/helpers/debug_with_puts.rb b/spec/support/helpers/debug_with_puts.rb
new file mode 100644
index 00000000000..b8599cc7d40
--- /dev/null
+++ b/spec/support/helpers/debug_with_puts.rb
@@ -0,0 +1,13 @@
+# frozen_string_literal: true
+
+# TODO: Remove the debug_with_puts statements below! Used for debugging purposes.
+# TODO: https://gitlab.com/gitlab-org/quality/engineering-productivity/team/-/issues/323#note_1688925316
+module DebugWithPuts
+ def debug_with_puts(message)
+ return unless ENV['CI'] # rubocop:disable RSpec/AvoidConditionalStatements -- Debug information only in the CI
+
+ warn "[#{Time.current}] #{message}"
+ end
+
+ module_function :debug_with_puts
+end
diff --git a/spec/support/helpers/dns_helpers.rb b/spec/support/helpers/dns_helpers.rb
index be26c80d217..0250e432609 100644
--- a/spec/support/helpers/dns_helpers.rb
+++ b/spec/support/helpers/dns_helpers.rb
@@ -1,11 +1,15 @@
# frozen_string_literal: true
module DnsHelpers
+ include ViteHelper
+
def block_dns!
stub_all_dns!
stub_invalid_dns!
permit_local_dns!
permit_postgresql!
+ permit_redis!
+ permit_vite!
end
def permit_dns!
@@ -53,6 +57,26 @@ module DnsHelpers
ActiveRecord::Base.configurations.configs_for(env_name: Rails.env).map(&:host).compact.uniq
end
+ def permit_redis!
+ # https://github.com/redis-rb/redis-client/blob/v0.11.2/lib/redis_client/ruby_connection.rb#L51 uses Socket.tcp that
+ # calls Addrinfo.getaddrinfo internally.
+ hosts = Gitlab::Redis::ALL_CLASSES.map do |redis_instance|
+ redis_instance.redis_client_params[:host]
+ end.uniq.compact
+
+ hosts.each do |host|
+ allow(Addrinfo).to receive(:getaddrinfo).with(host, anything, nil, :STREAM, anything, anything, any_args).and_call_original
+ end
+ end
+
+ def permit_vite!
+ # https://github.com/ElMassimo/vite_ruby/blob/7d2f558c9760802e5d763bfa40efe87607eb166a/vite_ruby/lib/vite_ruby.rb#L91
+ # uses Socket.tcp to connect to vite dev server - this won't necessarily be localhost
+ return unless vite_enabled?
+
+ allow(Addrinfo).to receive(:getaddrinfo).with(ViteRuby.instance.config.host, ViteRuby.instance.config.port, nil, :STREAM, anything, anything, any_args).and_call_original
+ end
+
def stub_resolver(stubbed_lookups = {})
resolver = instance_double('Resolv::DNS')
allow(resolver).to receive(:timeouts=)
diff --git a/spec/support/helpers/features/invite_members_modal_helpers.rb b/spec/support/helpers/features/invite_members_modal_helpers.rb
index c40e060bc8e..fd37abd7381 100644
--- a/spec/support/helpers/features/invite_members_modal_helpers.rb
+++ b/spec/support/helpers/features/invite_members_modal_helpers.rb
@@ -66,6 +66,7 @@ module Features
def choose_options(role, expires_at)
page.within role_dropdown_selector do
+ wait_for_requests
toggle_listbox
select_listbox_item(role, exact_text: true)
end
diff --git a/spec/support/helpers/login_helpers.rb b/spec/support/helpers/login_helpers.rb
index 913316c8622..83849df73dc 100644
--- a/spec/support/helpers/login_helpers.rb
+++ b/spec/support/helpers/login_helpers.rb
@@ -49,18 +49,6 @@ module LoginHelpers
@current_user = user
end
- def gitlab_enable_admin_mode_sign_in(user, use_mock_admin_mode: true)
- if use_mock_admin_mode
- enable_admin_mode!(user)
- else
- visit new_admin_session_path
- fill_in 'user_password', with: user.password
- click_button 'Enter admin mode'
-
- wait_for_requests
- end
- end
-
def gitlab_sign_in_via(provider, user, uid, saml_response = nil)
mock_auth_hash_with_saml_xml(provider, uid, user.email, saml_response)
visit new_user_session_path
@@ -90,8 +78,8 @@ module LoginHelpers
# Requires Javascript driver.
def gitlab_disable_admin_mode
- click_on 'Search or go to…'
- click_on 'Leave admin mode'
+ find_by_testid('user-menu-toggle').click
+ click_on 'Leave Admin Mode'
end
private
@@ -122,7 +110,7 @@ module LoginHelpers
def login_via(provider, user, uid, remember_me: false, additional_info: {})
mock_auth_hash(provider, uid, user.email, additional_info: additional_info)
visit new_user_session_path
- expect(page).to have_css('.omniauth-container')
+ expect(page).to have_css('.js-oauth-login')
check 'remember_me_omniauth' if remember_me
@@ -157,7 +145,7 @@ module LoginHelpers
mock_auth_hash(provider, uid, email, response_object: response_object)
end
- def configure_mock_auth(provider, uid, email, response_object: nil, additional_info: {}, name: 'mockuser')
+ def configure_mock_auth(provider, uid, email, response_object: nil, additional_info: {}, name: 'mockuser', groups: [])
# The mock_auth configuration allows you to set per-provider (or default)
# authentication hashes to return during integration testing.
@@ -180,7 +168,8 @@ module LoginHelpers
name: 'mockuser',
email: email,
image: 'mock_user_thumbnail_url'
- }
+ },
+ 'groups' => groups
}
),
response_object: response_object
@@ -188,9 +177,9 @@ module LoginHelpers
}).merge(additional_info) { |_, old_hash, new_hash| old_hash.merge(new_hash) }
end
- def mock_auth_hash(provider, uid, email, additional_info: {}, response_object: nil, name: 'mockuser')
+ def mock_auth_hash(provider, uid, email, additional_info: {}, response_object: nil, name: 'mockuser', groups: [])
configure_mock_auth(
- provider, uid, email, additional_info: additional_info, response_object: response_object, name: name
+ provider, uid, email, additional_info: additional_info, response_object: response_object, name: name, groups: groups
)
original_env_config_omniauth_auth = Rails.application.env_config['omniauth.auth']
diff --git a/spec/support/helpers/models/ci/partitioning_testing/partition_identifiers.rb b/spec/support/helpers/models/ci/partitioning_testing/partition_identifiers.rb
index aa091095fb6..e139f0c9fb3 100644
--- a/spec/support/helpers/models/ci/partitioning_testing/partition_identifiers.rb
+++ b/spec/support/helpers/models/ci/partitioning_testing/partition_identifiers.rb
@@ -8,6 +8,10 @@ module Ci
def ci_testing_partition_id
99999
end
+
+ def ci_testing_partition_id_for_check_constraints
+ 101
+ end
end
end
end
diff --git a/spec/support/helpers/navbar_structure_helper.rb b/spec/support/helpers/navbar_structure_helper.rb
index 5519a6910a2..2d3f7a1b8a9 100644
--- a/spec/support/helpers/navbar_structure_helper.rb
+++ b/spec/support/helpers/navbar_structure_helper.rb
@@ -76,6 +76,14 @@ module NavbarStructureHelper
)
end
+ def insert_google_artifact_registry_nav
+ insert_after_sub_nav_item(
+ _('Container Registry'),
+ within: _('Deploy'),
+ new_sub_nav_item_name: _('Google Artifact Registry')
+ )
+ end
+
def insert_dependency_proxy_nav
insert_before_sub_nav_item(
_('Kubernetes'),
@@ -124,6 +132,14 @@ module NavbarStructureHelper
)
end
+ def insert_model_registry_nav(within)
+ insert_after_sub_nav_item(
+ within,
+ within: _('Deploy'),
+ new_sub_nav_item_name: _('Model registry')
+ )
+ end
+
def project_analytics_sub_nav_item
[
_('Value stream analytics'),
diff --git a/spec/support/helpers/orphan_final_artifacts_cleanup_helpers.rb b/spec/support/helpers/orphan_final_artifacts_cleanup_helpers.rb
new file mode 100644
index 00000000000..9711a5d7c54
--- /dev/null
+++ b/spec/support/helpers/orphan_final_artifacts_cleanup_helpers.rb
@@ -0,0 +1,82 @@
+# frozen_string_literal: true
+
+module OrphanFinalArtifactsCleanupHelpers
+ def create_fog_file(final: true)
+ path = if final
+ JobArtifactUploader.generate_final_store_path(root_id: 123)
+ else
+ JobArtifactUploader.generate_remote_id
+ end
+
+ fog_connection.directories.new(key: remote_directory)
+ .files
+ .create( # rubocop:disable Rails/SaveBang -- not the AR method
+ key: path_with_bucket_prefix(path),
+ body: 'content'
+ )
+ end
+
+ def path_without_bucket_prefix(path)
+ Pathname.new(path).relative_path_from(bucket_prefix.to_s).to_s
+ end
+
+ def path_with_bucket_prefix(path)
+ File.join([bucket_prefix, path].compact)
+ end
+
+ def expect_object_to_exist(fog_file)
+ expect { fog_connection.get_object(remote_directory, fog_file.key) }.not_to raise_error
+ end
+
+ def expect_object_to_be_deleted(fog_file)
+ expect { fog_connection.get_object(remote_directory, fog_file.key) }.to raise_error(Excon::Error::NotFound)
+ end
+
+ def expect_start_log_message
+ expect_log_message("Looking for orphan job artifact objects")
+ end
+
+ def expect_done_log_message
+ expect_log_message("Done")
+ end
+
+ def expect_first_page_loading_log_message
+ expect_log_message("Loading page (first page)", times: 1)
+ end
+
+ def expect_page_loading_via_marker_log_message(times:)
+ expect_log_message("Loading page (marker:", times: times)
+ end
+
+ def expect_resuming_from_marker_log_message(marker)
+ expect_log_message("Resuming from last page marker: #{marker}", times: 1)
+ end
+
+ def expect_no_resuming_from_marker_log_message
+ expect(Gitlab::AppLogger).not_to have_received(:info).with(a_string_including("Resuming"))
+ end
+
+ def expect_delete_log_message(fog_file)
+ expect_log_message("Delete #{fog_file.key} (#{fog_file.content_length} bytes)")
+ end
+
+ def expect_no_delete_log_message(fog_file)
+ expect_no_log_message("Delete #{fog_file.key} (#{fog_file.content_length} bytes)")
+ end
+
+ def expect_log_message(message, times: 1)
+ message = "[DRY RUN] #{message}" if dry_run
+ expect(Gitlab::AppLogger).to have_received(:info).with(a_string_including(message)).exactly(times).times
+ end
+
+ def expect_no_log_message(message)
+ message = "[DRY RUN] #{message}" if dry_run
+ expect(Gitlab::AppLogger).not_to have_received(:info).with(a_string_including(message))
+ end
+
+ def fetch_saved_marker
+ Gitlab::Redis::SharedState.with do |redis|
+ redis.get(described_class::LAST_PAGE_MARKER_REDIS_KEY)
+ end
+ end
+end
diff --git a/spec/support/helpers/stub_configuration.rb b/spec/support/helpers/stub_configuration.rb
index e043d1249b9..e888f858a2d 100644
--- a/spec/support/helpers/stub_configuration.rb
+++ b/spec/support/helpers/stub_configuration.rb
@@ -1,5 +1,6 @@
# frozen_string_literal: true
+require 'gitlab_edition'
require 'active_support/hash_with_indifferent_access'
require 'active_support/dependencies'
@@ -120,6 +121,10 @@ module StubConfiguration
.to receive(:sentry_clientside_dsn) { clientside_dsn }
end
+ def clear_sentry_settings
+ Sentry.get_current_scope.clear
+ end
+
def stub_microsoft_graph_mailer_setting(messages)
allow(Gitlab.config.microsoft_graph_mailer).to receive_messages(to_settings(messages))
end
@@ -194,6 +199,6 @@ module StubConfiguration
end
require_relative '../../../ee/spec/support/helpers/ee/stub_configuration' if
- Dir.exist?("#{__dir__}/../../../ee")
+ GitlabEdition.ee?
StubConfiguration.prepend_mod_with('StubConfiguration')
diff --git a/spec/support/helpers/stub_gitlab_calls.rb b/spec/support/helpers/stub_gitlab_calls.rb
index 0c92502ba99..33661ce353c 100644
--- a/spec/support/helpers/stub_gitlab_calls.rb
+++ b/spec/support/helpers/stub_gitlab_calls.rb
@@ -102,7 +102,7 @@ module StubGitlabCalls
end
def stub_commonmark_sourcepos_disabled
- engine = Banzai::Filter::MarkdownFilter.render_engine(nil)
+ engine = Banzai::Filter::MarkdownFilter.new('foo', {}).render_engine
allow_next_instance_of(engine) do |instance|
allow(instance).to receive(:sourcepos_disabled?).and_return(true)
@@ -110,7 +110,7 @@ module StubGitlabCalls
end
def stub_commonmark_sourcepos_enabled
- engine = Banzai::Filter::MarkdownFilter.render_engine(nil)
+ engine = Banzai::Filter::MarkdownFilter.new('foo', {}).render_engine
allow_next_instance_of(engine) do |instance|
allow(instance).to receive(:sourcepos_disabled?).and_return(false)
diff --git a/spec/support/helpers/stub_requests.rb b/spec/support/helpers/stub_requests.rb
index bde5535705e..b77b366e037 100644
--- a/spec/support/helpers/stub_requests.rb
+++ b/spec/support/helpers/stub_requests.rb
@@ -18,15 +18,15 @@ module StubRequests
end
def stub_dns(url, ip_address:, port: 80)
- debug_with_puts "beginning of stub_dns"
+ DebugWithPuts.debug_with_puts "beginning of stub_dns"
url = parse_url(url)
- debug_with_puts "before socket = Socket.sockaddr_in"
+ DebugWithPuts.debug_with_puts "before socket = Socket.sockaddr_in"
socket = Socket.sockaddr_in(port, ip_address)
- debug_with_puts "after socket = Socket.sockaddr_in"
+ DebugWithPuts.debug_with_puts "after socket = Socket.sockaddr_in"
- debug_with_puts "before addr = Addrinfo.new(socket)"
+ DebugWithPuts.debug_with_puts "before addr = Addrinfo.new(socket)"
addr = Addrinfo.new(socket)
- debug_with_puts "after addr = Addrinfo.new(socket)"
+ DebugWithPuts.debug_with_puts "after addr = Addrinfo.new(socket)"
# See Gitlab::UrlBlocker
allow(Addrinfo).to receive(:getaddrinfo)
@@ -58,12 +58,4 @@ module StubRequests
def parse_url(url)
url.is_a?(URI) ? url : URI(url)
end
-
- # TODO: Remove the debug_with_puts statements below! Used for debugging purposes.
- # TODO: https://gitlab.com/gitlab-org/quality/engineering-productivity/team/-/issues/323#note_1688925316
- def debug_with_puts(message)
- return unless ENV['CI'] # rubocop:disable RSpec/AvoidConditionalStatements -- Debug information only in the CI
-
- puts "[#{Time.current}] #{message}"
- end
end
diff --git a/spec/support/helpers/user_with_namespace_shim.rb b/spec/support/helpers/user_with_namespace_shim.rb
new file mode 100644
index 00000000000..c4c988b33a0
--- /dev/null
+++ b/spec/support/helpers/user_with_namespace_shim.rb
@@ -0,0 +1,73 @@
+# frozen_string_literal: true
+
+# Modify the FactoryBot user build process to assign a personal namespace.
+# The complement to this shim is in the User factory where we assign_personal_namespace.
+#
+# This is needed to assist with the transition to optional personal namespaces.
+# See https://gitlab.com/gitlab-org/gitlab/-/merge_requests/137065
+module UserWithNamespaceShim
+ extend ActiveSupport::Concern
+
+ USER_WITH_NAMESPACE_SHIM_YAML = File.join(__dir__, 'user_with_namespace_shim.yml')
+
+ class << self
+ include Gitlab::Utils::StrongMemoize
+
+ def enabled?
+ self.enabled ||= false
+ end
+
+ def shim(spec_file)
+ self.enabled = spec_file_shimmed?(spec_file)
+ end
+
+ def unshim
+ self.enabled = false
+ end
+
+ # Determine the spec filename from the current backtrace.
+ def get_spec_file
+ caller.find do |line|
+ match = line.match(%r{^(.+_spec\.rb|.+/frontend/fixtures/.+\.rb):\d+:in})
+ match[1] if match
+ end
+
+ path = ::Regexp.last_match(1)
+ return unless path
+
+ Pathname.new(path)
+ .relative_path_from(Rails.root)
+ .to_s
+ end
+
+ private
+
+ def spec_file_shimmed?(spec_file)
+ shimmed_spec_list.include?(spec_file)
+ end
+
+ def shimmed_spec_list
+ YAML.load_file(USER_WITH_NAMESPACE_SHIM_YAML) || []
+ end
+ strong_memoize_attr :shimmed_spec_list
+
+ attr_accessor :enabled
+ end
+
+ included do
+ # This is our only chance to determine the spec filename.
+ spec_file = UserWithNamespaceShim.get_spec_file
+
+ # We need to use before(:all) instead of before_all otherwise we open a transaction before running the example
+ # which interferes with examples using the the table deletion strategy like those marked as `:delete`.
+ # rubocop:disable RSpec/BeforeAll -- reason above
+ before(:all) do
+ UserWithNamespaceShim.shim(spec_file)
+ end
+ # rubocop:enable RSpec/BeforeAll
+
+ after(:all) do
+ UserWithNamespaceShim.unshim
+ end
+ end
+end
diff --git a/spec/support/helpers/user_with_namespace_shim.yml b/spec/support/helpers/user_with_namespace_shim.yml
new file mode 100644
index 00000000000..7b3dc099cf9
--- /dev/null
+++ b/spec/support/helpers/user_with_namespace_shim.yml
@@ -0,0 +1,1000 @@
+---
+- ee/spec/components/namespaces/storage/user_pre_enforcement_alert_component_spec.rb
+- ee/spec/controllers/admin/users_controller_spec.rb
+- ee/spec/controllers/autocomplete_controller_spec.rb
+- ee/spec/controllers/ee/profiles/preferences_controller_spec.rb
+- ee/spec/controllers/ee/search_controller_spec.rb
+- ee/spec/controllers/groups/sso_controller_spec.rb
+- ee/spec/controllers/profiles/billings_controller_spec.rb
+- ee/spec/controllers/projects/iterations_controller_spec.rb
+- ee/spec/controllers/projects_controller_spec.rb
+- ee/spec/controllers/users_controller_spec.rb
+- ee/spec/features/account_recovery_regular_check_spec.rb
+- ee/spec/features/admin/admin_audit_logs_spec.rb
+- ee/spec/features/admin/admin_groups_spec.rb
+- ee/spec/features/admin/admin_reset_pipeline_minutes_spec.rb
+- ee/spec/features/admin/admin_users_spec.rb
+- ee/spec/features/admin/groups/admin_changes_plan_spec.rb
+- ee/spec/features/admin/users/users_spec.rb
+- ee/spec/features/analytics/code_analytics_spec.rb
+- ee/spec/features/billings/billing_plans_spec.rb
+- ee/spec/features/boards/boards_licensed_features_spec.rb
+- ee/spec/features/boards/boards_spec.rb
+- ee/spec/features/boards/swimlanes/epics_swimlanes_spec.rb
+- ee/spec/features/ci/ci_minutes_spec.rb
+- ee/spec/features/ci_shared_runner_warnings_spec.rb
+- ee/spec/features/code_suggestions_ga_non_owner_alert_spec.rb
+- ee/spec/features/dashboards/todos_spec.rb
+- ee/spec/features/epics/gfm_autocomplete_spec.rb
+- ee/spec/features/epics/issue_promotion_spec.rb
+- ee/spec/features/epics/referencing_epics_spec.rb
+- ee/spec/features/epics/update_epic_spec.rb
+- ee/spec/features/groups/analytics/productivity_analytics_spec.rb
+- ee/spec/features/groups/member_roles_spec.rb
+- ee/spec/features/groups/members/list_members_spec.rb
+- ee/spec/features/groups/security/policies_list_spec.rb
+- ee/spec/features/groups/security/policy_editor_spec.rb
+- ee/spec/features/groups/usage_quotas/code_suggestions_usage_tab_spec.rb
+- ee/spec/features/groups/wikis_spec.rb
+- ee/spec/features/incidents/incident_details_spec.rb
+- ee/spec/features/issues/epic_in_issue_sidebar_spec.rb
+- ee/spec/features/issues/issue_sidebar_spec.rb
+- ee/spec/features/issues/user_bulk_edits_issues_spec.rb
+- ee/spec/features/issues/user_sees_empty_state_spec.rb
+- ee/spec/features/issues/user_uses_quick_actions_spec.rb
+- ee/spec/features/issues/user_views_issues_spec.rb
+- ee/spec/features/merge_request/code_owner_approvals_reset_after_merging_to_source_branch_spec.rb
+- ee/spec/features/merge_request/draft_comments_spec.rb
+- ee/spec/features/merge_request/user_approves_with_password_spec.rb
+- ee/spec/features/merge_request/user_approves_with_saml_auth_spec.rb
+- ee/spec/features/merge_request/user_comments_on_merge_request_spec.rb
+- ee/spec/features/merge_request/user_creates_merge_request_spec.rb
+- ee/spec/features/merge_request/user_creates_multiple_assignees_mr_spec.rb
+- ee/spec/features/merge_request/user_creates_multiple_reviewers_mr_spec.rb
+- ee/spec/features/merge_request/user_edits_multiple_assignees_mr_spec.rb
+- ee/spec/features/merge_request/user_edits_multiple_reviewers_mr_spec.rb
+- ee/spec/features/merge_request/user_merges_immediately_spec.rb
+- ee/spec/features/merge_request/user_merges_with_namespace_storage_limits_spec.rb
+- ee/spec/features/merge_request/user_merges_with_push_rules_spec.rb
+- ee/spec/features/merge_request/user_sees_approve_via_custom_role_spec.rb
+- ee/spec/features/merge_request/user_sees_merge_widget_spec.rb
+- ee/spec/features/merge_request/user_sees_security_policy_rules_licence_compliance_spec.rb
+- ee/spec/features/merge_request/user_sees_status_checks_widget_spec.rb
+- ee/spec/features/merge_request/user_sets_approval_rules_spec.rb
+- ee/spec/features/merge_request/user_sets_approvers_spec.rb
+- ee/spec/features/merge_request/user_uses_slash_commands_spec.rb
+- ee/spec/features/merge_request/user_views_blocked_merge_request_spec.rb
+- ee/spec/features/merge_trains/user_adds_to_merge_train_when_pipeline_succeeds_spec.rb
+- ee/spec/features/namespace_user_cap_reached_alert_spec.rb
+- ee/spec/features/pending_project_memberships_spec.rb
+- ee/spec/features/profiles/account_spec.rb
+- ee/spec/features/profiles/password_spec.rb
+- ee/spec/features/profiles/usage_quotas_spec.rb
+- ee/spec/features/profiles/user_visits_profile_spec.rb
+- ee/spec/features/profiles/user_visits_public_profile_spec.rb
+- ee/spec/features/projects/active_tabs_spec.rb
+- ee/spec/features/projects/audit_events_spec.rb
+- ee/spec/features/projects/custom_projects_template_spec.rb
+- ee/spec/features/projects/environments/environment_spec.rb
+- ee/spec/features/projects/feature_flags/feature_flag_issues_spec.rb
+- ee/spec/features/projects/feature_flags/user_creates_feature_flag_spec.rb
+- ee/spec/features/projects/feature_flags/user_deletes_feature_flag_spec.rb
+- ee/spec/features/projects/feature_flags/user_sees_feature_flag_list_spec.rb
+- ee/spec/features/projects/feature_flags/user_updates_feature_flag_spec.rb
+- ee/spec/features/projects/members/member_leaves_project_spec.rb
+- ee/spec/features/projects/merge_requests/user_approves_merge_request_spec.rb
+- ee/spec/features/projects/milestones/milestone_spec.rb
+- ee/spec/features/projects/navbar_spec.rb
+- ee/spec/features/projects/new_project_from_template_spec.rb
+- ee/spec/features/projects/new_project_spec.rb
+- ee/spec/features/projects/path_locks_spec.rb
+- ee/spec/features/projects/push_rules_spec.rb
+- ee/spec/features/projects/security/policies_list_spec.rb
+- ee/spec/features/projects/security/policy_editor_spec.rb
+- ee/spec/features/projects/settings/ee/repository_mirrors_settings_spec.rb
+- ee/spec/features/projects/settings/merge_requests/user_manages_merge_requests_template_spec.rb
+- ee/spec/features/projects/settings/packages_spec.rb
+- ee/spec/features/projects/settings/user_changes_default_branch_spec.rb
+- ee/spec/features/projects/settings/user_manages_issues_template_spec.rb
+- ee/spec/features/projects/settings/user_manages_merge_requests_template_spec.rb
+- ee/spec/features/projects/show_project_spec.rb
+- ee/spec/features/projects/show_spec.rb
+- ee/spec/features/projects/view_blob_with_code_owners_spec.rb
+- ee/spec/features/projects/wiki/user_views_wiki_empty_spec.rb
+- ee/spec/features/projects_spec.rb
+- ee/spec/features/protected_tags_spec.rb
+- ee/spec/features/remote_development/workspaces_dropdown_group_spec.rb
+- ee/spec/features/search/elastic/global_search_spec.rb
+- ee/spec/features/search/elastic/project_search_spec.rb
+- ee/spec/features/search/elastic/snippet_search_spec.rb
+- ee/spec/features/security/dashboard_access_spec.rb
+- ee/spec/features/security/profile_access_spec.rb
+- ee/spec/features/security/project/discover_spec.rb
+- ee/spec/features/security/project/internal_access_spec.rb
+- ee/spec/features/security/project/private_access_spec.rb
+- ee/spec/features/security/project/public_access_spec.rb
+- ee/spec/features/security/project/snippet/internal_access_spec.rb
+- ee/spec/features/security/project/snippet/public_access_spec.rb
+- ee/spec/features/subscriptions/subscription_flow_for_existing_user_with_eligible_group_spec.rb
+- ee/spec/features/subscriptions_spec.rb
+- ee/spec/features/trials/show_trial_banner_spec.rb
+- ee/spec/features/user_sees_marketing_header_spec.rb
+- ee/spec/features/user_settings/password_spec.rb
+- ee/spec/features/users/login_spec.rb
+- ee/spec/finders/compliance_management/merge_requests/compliance_violations_finder_spec.rb
+- ee/spec/finders/ee/fork_targets_finder_spec.rb
+- ee/spec/finders/issues_finder_spec.rb
+- ee/spec/finders/security/approval_groups_finder_spec.rb
+- ee/spec/frontend/fixtures/namespace.rb
+- ee/spec/frontend/fixtures/search.rb
+- ee/spec/graphql/ee/resolvers/board_lists_resolver_spec.rb
+- ee/spec/graphql/mutations/namespaces/increase_storage_temporarily_spec.rb
+- ee/spec/graphql/mutations/security_policy/assign_security_policy_project_spec.rb
+- ee/spec/graphql/mutations/security_policy/commit_scan_execution_policy_spec.rb
+- ee/spec/graphql/mutations/security_policy/create_security_policy_project_spec.rb
+- ee/spec/graphql/mutations/security_policy/unassign_security_policy_project_spec.rb
+- ee/spec/helpers/ee/users/callouts_helper_spec.rb
+- ee/spec/helpers/projects/security/discover_helper_spec.rb
+- ee/spec/helpers/subscriptions_helper_spec.rb
+- ee/spec/lib/ee/api/entities/user_with_admin_spec.rb
+- ee/spec/lib/ee/gitlab/background_migration/migrate_approver_to_approval_rules_spec.rb
+- ee/spec/lib/ee/gitlab/background_migration/migrate_vulnerabilities_feedback_to_vulnerabilities_state_transition_spec.rb
+- ee/spec/lib/ee/gitlab/ci/pipeline/chain/validate/external_spec.rb
+- ee/spec/lib/ee/gitlab/import_export/project/tree_restorer_spec.rb
+- ee/spec/lib/ee/gitlab/issuable_metadata_spec.rb
+- ee/spec/lib/gitlab/auth/smartcard/certificate_spec.rb
+- ee/spec/lib/gitlab/auth/smartcard/ldap_certificate_spec.rb
+- ee/spec/lib/gitlab/background_migration/create_vulnerability_links_spec.rb
+- ee/spec/lib/gitlab/geo_spec.rb
+- ee/spec/lib/gitlab/graphql/aggregations/security_orchestration_policies/lazy_dast_profile_aggregate_spec.rb
+- ee/spec/lib/gitlab/llm/stage_check_spec.rb
+- ee/spec/lib/gitlab/llm/tanuki_bot_spec.rb
+- ee/spec/lib/gitlab/search/zoekt/client_spec.rb
+- ee/spec/lib/gitlab/subscription_portal/clients/graphql_spec.rb
+- ee/spec/lib/sidebars/groups/menus/analytics_menu_spec.rb
+- ee/spec/migrations/20220831132802_delete_approval_rules_for_vulnerability_spec.rb
+- ee/spec/migrations/20220907122648_populate_security_orchestration_policy_configuration_id_spec.rb
+- ee/spec/migrations/20221130192239_fix_approval_project_rules_without_protected_branches_spec.rb
+- ee/spec/migrations/20230113201308_backfill_namespace_ldap_settings_spec.rb
+- ee/spec/migrations/20230127155217_add_id_column_to_package_metadata_join_table_spec.rb
+- ee/spec/migrations/20230310213308_sync_security_policy_rule_schedules_that_may_have_been_deleted_by_a_bug_spec.rb
+- ee/spec/migrations/20230403221928_resync_scan_result_policies_for_namespaces_spec.rb
+- ee/spec/migrations/20230501165244_remove_software_license_policies_without_scan_result_policy_id_spec.rb
+- ee/spec/migrations/20230612162643_pm_checkpoints_remove_advisory_entries_spec.rb
+- ee/spec/migrations/20231030154117_insert_new_ultimate_trial_plan_into_plans_spec.rb
+- ee/spec/migrations/cleanup_orphan_software_licenses_spec.rb
+- ee/spec/migrations/geo/migrate_ci_job_artifacts_to_separate_registry_spec.rb
+- ee/spec/migrations/geo/migrate_lfs_objects_to_separate_registry_spec.rb
+- ee/spec/migrations/geo/resync_direct_upload_job_artifact_registry_spec.rb
+- ee/spec/migrations/update_can_create_group_application_setting_spec.rb
+- ee/spec/migrations/update_ci_max_total_yaml_size_bytes_default_value_spec.rb
+- ee/spec/models/concerns/ee/mentionable_spec.rb
+- ee/spec/models/concerns/elastic/note_spec.rb
+- ee/spec/models/ee/member_spec.rb
+- ee/spec/models/ee/namespace/root_storage_statistics_spec.rb
+- ee/spec/models/ee/namespace_spec.rb
+- ee/spec/models/ee/namespace_statistics_spec.rb
+- ee/spec/models/ee/namespaces/user_namespace_spec.rb
+- ee/spec/models/ee/pages_domain_spec.rb
+- ee/spec/models/ee/project_member_spec.rb
+- ee/spec/models/ee/project_spec.rb
+- ee/spec/models/ee/project_wiki_spec.rb
+- ee/spec/models/elastic/migration_record_spec.rb
+- ee/spec/models/epic_spec.rb
+- ee/spec/models/factories_spec.rb
+- ee/spec/models/gitlab_subscription_spec.rb
+- ee/spec/models/iteration_spec.rb
+- ee/spec/models/member_spec.rb
+- ee/spec/models/namespace_setting_spec.rb
+- ee/spec/models/namespaces/free_user_cap/enforcement_spec.rb
+- ee/spec/models/project_member_spec.rb
+- ee/spec/models/projects/compliance_standards/adherence_spec.rb
+- ee/spec/models/push_rule_spec.rb
+- ee/spec/policies/ci/minutes/namespace_monthly_usage_policy_spec.rb
+- ee/spec/policies/dependency_proxy/packages/setting_policy_spec.rb
+- ee/spec/policies/global_policy_spec.rb
+- ee/spec/policies/packages/policies/project_policy_spec.rb
+- ee/spec/policies/project_policy_spec.rb
+- ee/spec/policies/requirements_management/requirement_policy_spec.rb
+- ee/spec/policies/vulnerabilities/feedback_policy_spec.rb
+- ee/spec/policies/vulnerabilities/merge_request_link_policy_spec.rb
+- ee/spec/presenters/audit_event_presenter_spec.rb
+- ee/spec/requests/admin/users_controller_spec.rb
+- ee/spec/requests/api/discussions_spec.rb
+- ee/spec/requests/api/epics_spec.rb
+- ee/spec/requests/api/graphql/ci/minutes/usage_spec.rb
+- ee/spec/requests/api/graphql/compliance_management/merge_requests/compliance_violations_spec.rb
+- ee/spec/requests/api/graphql/mutations/security/finding/create_merge_request_spec.rb
+- ee/spec/requests/api/graphql/mutations/security_policy/assign_security_policy_project_spec.rb
+- ee/spec/requests/api/graphql/mutations/security_policy/commit_scan_execution_policy_spec.rb
+- ee/spec/requests/api/graphql/mutations/security_policy/create_security_policy_project_spec.rb
+- ee/spec/requests/api/graphql/mutations/security_policy/unassign_security_policy_project_spec.rb
+- ee/spec/requests/api/graphql/project/path_locks_spec.rb
+- ee/spec/requests/api/graphql/project/pipelines/dast_profile_spec.rb
+- ee/spec/requests/api/graphql/project/push_rules_spec.rb
+- ee/spec/requests/api/graphql/project/requirements_management/requirements_spec.rb
+- ee/spec/requests/api/graphql/work_item_spec.rb
+- ee/spec/requests/api/groups_spec.rb
+- ee/spec/requests/api/internal/ai/x_ray/scan_spec.rb
+- ee/spec/requests/api/internal/base_spec.rb
+- ee/spec/requests/api/issues_spec.rb
+- ee/spec/requests/api/merge_request_approval_rules_spec.rb
+- ee/spec/requests/api/merge_request_approvals_spec.rb
+- ee/spec/requests/api/merge_requests_spec.rb
+- ee/spec/requests/api/namespaces_spec.rb
+- ee/spec/requests/api/project_approval_rules_spec.rb
+- ee/spec/requests/api/project_approval_settings_spec.rb
+- ee/spec/requests/api/project_approvals_spec.rb
+- ee/spec/requests/api/project_milestones_spec.rb
+- ee/spec/requests/api/project_push_rule_spec.rb
+- ee/spec/requests/api/projects_spec.rb
+- ee/spec/requests/api/resource_weight_events_spec.rb
+- ee/spec/requests/api/search_spec.rb
+- ee/spec/requests/api/users_spec.rb
+- ee/spec/requests/custom_roles/admin_merge_request/request_spec.rb
+- ee/spec/requests/custom_roles/admin_vulnerability/request_spec.rb
+- ee/spec/requests/custom_roles/manage_project_access_tokens/request_spec.rb
+- ee/spec/requests/projects/analytics/code_reviews_controller_spec.rb
+- ee/spec/requests/projects/issues_controller_spec.rb
+- ee/spec/requests/projects/metrics_controller_spec.rb
+- ee/spec/requests/projects/security/policies_controller_spec.rb
+- ee/spec/requests/projects/tracing_controller_spec.rb
+- ee/spec/requests/subscriptions/hand_raise_leads_spec.rb
+- ee/spec/requests/trial_registrations_controller_spec.rb
+- ee/spec/requests/users_controller_spec.rb
+- ee/spec/serializers/clusters/environment_serializer_spec.rb
+- ee/spec/services/analytics/cycle_analytics/data_loader_service_spec.rb
+- ee/spec/services/ci/minutes/additional_packs/change_namespace_service_spec.rb
+- ee/spec/services/ci/minutes/update_project_and_namespace_usage_service_spec.rb
+- ee/spec/services/ee/auth/container_registry_authentication_service_spec.rb
+- ee/spec/services/ee/commits/create_service_spec.rb
+- ee/spec/services/ee/issues/create_service_spec.rb
+- ee/spec/services/ee/issues/update_service_spec.rb
+- ee/spec/services/ee/notes/create_service_spec.rb
+- ee/spec/services/ee/notes/quick_actions_service_spec.rb
+- ee/spec/services/ee/notification_service_spec.rb
+- ee/spec/services/ee/post_receive_service_spec.rb
+- ee/spec/services/ee/projects/remove_paid_features_service_spec.rb
+- ee/spec/services/ee/users/destroy_service_spec.rb
+- ee/spec/services/ee/users/migrate_records_to_ghost_user_service_spec.rb
+- ee/spec/services/epic_issues/create_service_spec.rb
+- ee/spec/services/epics/create_service_spec.rb
+- ee/spec/services/epics/issue_promote_service_spec.rb
+- ee/spec/services/epics/transfer_service_spec.rb
+- ee/spec/services/epics/update_service_spec.rb
+- ee/spec/services/namespaces/service_accounts/create_service_spec.rb
+- ee/spec/services/projects/create_from_template_service_spec.rb
+- ee/spec/services/projects/create_service_spec.rb
+- ee/spec/services/projects/destroy_service_spec.rb
+- ee/spec/services/projects/fork_service_spec.rb
+- ee/spec/services/projects/mark_for_deletion_service_spec.rb
+- ee/spec/services/projects/restore_service_spec.rb
+- ee/spec/services/projects/transfer_service_spec.rb
+- ee/spec/services/projects/update_service_spec.rb
+- ee/spec/services/quick_actions/interpret_service_spec.rb
+- ee/spec/services/todo_service_spec.rb
+- ee/spec/services/users/service_accounts/create_service_spec.rb
+- ee/spec/services/vulnerability_exports/exporters/csv_service_spec.rb
+- ee/spec/tasks/gitlab/elastic_rake_spec.rb
+- ee/spec/views/admin/dashboard/index.html.haml_spec.rb
+- ee/spec/views/admin/users/show.html.haml_spec.rb
+- ee/spec/views/compliance_management/compliance_framework/_project_settings.html.haml_spec.rb
+- ee/spec/views/profiles/preferences/show.html.haml_spec.rb
+- ee/spec/views/shared/billings/_eoa_bronze_plan_banner.html.haml_spec.rb
+- ee/spec/views/shared/promotions/_promotion_link_project.html.haml_spec.rb
+- ee/spec/workers/groups/enterprise_users/associate_worker_spec.rb
+- ee/spec/workers/groups/enterprise_users/bulk_associate_by_domain_worker_spec.rb
+- ee/spec/workers/new_epic_worker_spec.rb
+- spec/controllers/admin/users_controller_spec.rb
+- spec/controllers/concerns/checks_collaboration_spec.rb
+- spec/controllers/concerns/routable_actions_spec.rb
+- spec/controllers/dashboard/snippets_controller_spec.rb
+- spec/controllers/dashboard/todos_controller_spec.rb
+- spec/controllers/explore/snippets_controller_spec.rb
+- spec/controllers/groups/shared_projects_controller_spec.rb
+- spec/controllers/import/bitbucket_controller_spec.rb
+- spec/controllers/import/bitbucket_server_controller_spec.rb
+- spec/controllers/import/gitea_controller_spec.rb
+- spec/controllers/import/github_controller_spec.rb
+- spec/controllers/oauth/applications_controller_spec.rb
+- spec/controllers/oauth/authorizations_controller_spec.rb
+- spec/controllers/profiles/notifications_controller_spec.rb
+- spec/controllers/profiles/preferences_controller_spec.rb
+- spec/controllers/profiles_controller_spec.rb
+- spec/controllers/projects/blame_controller_spec.rb
+- spec/controllers/projects/blob_controller_spec.rb
+- spec/controllers/projects/ci/pipeline_editor_controller_spec.rb
+- spec/controllers/projects/commit_controller_spec.rb
+- spec/controllers/projects/forks_controller_spec.rb
+- spec/controllers/projects/labels_controller_spec.rb
+- spec/controllers/projects/merge_requests/drafts_controller_spec.rb
+- spec/controllers/projects/milestones_controller_spec.rb
+- spec/controllers/projects/project_members_controller_spec.rb
+- spec/controllers/projects/snippets_controller_spec.rb
+- spec/controllers/projects/tree_controller_spec.rb
+- spec/controllers/projects/web_ide_schemas_controller_spec.rb
+- spec/controllers/projects/web_ide_terminals_controller_spec.rb
+- spec/controllers/projects/wikis_controller_spec.rb
+- spec/controllers/projects_controller_spec.rb
+- spec/controllers/search_controller_spec.rb
+- spec/controllers/snippets/notes_controller_spec.rb
+- spec/features/abuse_report_spec.rb
+- spec/features/admin/admin_abuse_reports_spec.rb
+- spec/features/admin/admin_appearance_spec.rb
+- spec/features/admin/admin_disables_two_factor_spec.rb
+- spec/features/admin/admin_groups_spec.rb
+- spec/features/admin/admin_mode/workers_spec.rb
+- spec/features/admin/admin_mode_spec.rb
+- spec/features/admin/admin_projects_spec.rb
+- spec/features/admin/users/admin_impersonates_user_spec.rb
+- spec/features/admin/users/admin_sees_unconfirmed_user_spec.rb
+- spec/features/admin/users/admin_sees_user_spec.rb
+- spec/features/admin/users/user_spec.rb
+- spec/features/admin/users/users_spec.rb
+- spec/features/atom/users_spec.rb
+- spec/features/boards/boards_spec.rb
+- spec/features/breadcrumbs_schema_markup_spec.rb
+- spec/features/calendar_spec.rb
+- spec/features/canonical_link_spec.rb
+- spec/features/commits_spec.rb
+- spec/features/contextual_sidebar_spec.rb
+- spec/features/dashboard/datetime_on_tooltips_spec.rb
+- spec/features/dashboard/issuables_counter_spec.rb
+- spec/features/dashboard/issues_filter_spec.rb
+- spec/features/dashboard/milestones_spec.rb
+- spec/features/dashboard/project_member_activity_index_spec.rb
+- spec/features/dashboard/projects_spec.rb
+- spec/features/dashboard/user_filters_projects_spec.rb
+- spec/features/discussion_comments/merge_request_spec.rb
+- spec/features/discussion_comments/snippets_spec.rb
+- spec/features/expand_collapse_diffs_spec.rb
+- spec/features/explore/catalog/catalog_settings_spec.rb
+- spec/features/file_uploads/project_import_spec.rb
+- spec/features/file_uploads/user_avatar_spec.rb
+- spec/features/frequently_visited_projects_and_groups_spec.rb
+- spec/features/global_search_spec.rb
+- spec/features/groups/group_settings_spec.rb
+- spec/features/groups/participants_autocomplete_spec.rb
+- spec/features/groups_spec.rb
+- spec/features/help_dropdown_spec.rb
+- spec/features/ide/user_opens_merge_request_spec.rb
+- spec/features/ide_spec.rb
+- spec/features/import/manifest_import_spec.rb
+- spec/features/incidents/user_creates_new_incident_spec.rb
+- spec/features/incidents/user_views_incident_spec.rb
+- spec/features/issuables/markdown_references/jira_spec.rb
+- spec/features/issuables/shortcuts_issuable_spec.rb
+- spec/features/issuables/user_sees_sidebar_spec.rb
+- spec/features/issues/confidential_notes_spec.rb
+- spec/features/issues/create_issue_for_discussions_in_merge_request_spec.rb
+- spec/features/issues/create_issue_for_single_discussion_in_merge_request_spec.rb
+- spec/features/issues/csv_spec.rb
+- spec/features/issues/discussion_lock_spec.rb
+- spec/features/issues/form_spec.rb
+- spec/features/issues/issue_detail_spec.rb
+- spec/features/issues/issue_sidebar_spec.rb
+- spec/features/issues/markdown_toolbar_spec.rb
+- spec/features/issues/move_spec.rb
+- spec/features/issues/note_polling_spec.rb
+- spec/features/issues/notes_on_issues_spec.rb
+- spec/features/issues/related_issues_spec.rb
+- spec/features/issues/user_comments_on_issue_spec.rb
+- spec/features/issues/user_creates_branch_and_merge_request_spec.rb
+- spec/features/issues/user_creates_issue_spec.rb
+- spec/features/issues/user_edits_issue_spec.rb
+- spec/features/issues/user_interacts_with_awards_spec.rb
+- spec/features/issues/user_resets_their_incoming_email_token_spec.rb
+- spec/features/issues/user_sorts_issues_spec.rb
+- spec/features/issues/user_toggles_subscription_spec.rb
+- spec/features/issues/user_uses_quick_actions_spec.rb
+- spec/features/jira_connect/branches_spec.rb
+- spec/features/markdown/gitlab_flavored_markdown_spec.rb
+- spec/features/markdown/markdown_spec.rb
+- spec/features/merge_request/admin_views_hidden_merge_request_spec.rb
+- spec/features/merge_request/batch_comments_spec.rb
+- spec/features/merge_request/close_reopen_report_toggle_spec.rb
+- spec/features/merge_request/hide_default_award_emojis_spec.rb
+- spec/features/merge_request/maintainer_edits_fork_spec.rb
+- spec/features/merge_request/merge_request_discussion_lock_spec.rb
+- spec/features/merge_request/user_accepts_merge_request_spec.rb
+- spec/features/merge_request/user_allows_commits_from_memebers_who_can_merge_spec.rb
+- spec/features/merge_request/user_approves_spec.rb
+- spec/features/merge_request/user_assigns_themselves_reviewer_spec.rb
+- spec/features/merge_request/user_assigns_themselves_spec.rb
+- spec/features/merge_request/user_closes_reopens_merge_request_state_spec.rb
+- spec/features/merge_request/user_comments_on_commit_spec.rb
+- spec/features/merge_request/user_comments_on_diff_spec.rb
+- spec/features/merge_request/user_comments_on_merge_request_spec.rb
+- spec/features/merge_request/user_comments_on_whitespace_hidden_diff_spec.rb
+- spec/features/merge_request/user_creates_custom_emoji_spec.rb
+- spec/features/merge_request/user_creates_discussion_on_diff_file_spec.rb
+- spec/features/merge_request/user_creates_merge_request_spec.rb
+- spec/features/merge_request/user_creates_mr_spec.rb
+- spec/features/merge_request/user_edits_assignees_sidebar_spec.rb
+- spec/features/merge_request/user_edits_merge_request_spec.rb
+- spec/features/merge_request/user_edits_mr_spec.rb
+- spec/features/merge_request/user_edits_reviewers_sidebar_spec.rb
+- spec/features/merge_request/user_locks_discussion_spec.rb
+- spec/features/merge_request/user_manages_subscription_spec.rb
+- spec/features/merge_request/user_marks_merge_request_as_draft_spec.rb
+- spec/features/merge_request/user_opens_checkout_branch_modal_spec.rb
+- spec/features/merge_request/user_opens_context_commits_modal_spec.rb
+- spec/features/merge_request/user_resolves_diff_notes_and_discussions_resolve_spec.rb
+- spec/features/merge_request/user_reverts_merge_request_spec.rb
+- spec/features/merge_request/user_sees_check_out_branch_modal_spec.rb
+- spec/features/merge_request/user_sees_cherry_pick_modal_spec.rb
+- spec/features/merge_request/user_sees_deployment_widget_spec.rb
+- spec/features/merge_request/user_sees_diff_spec.rb
+- spec/features/merge_request/user_sees_merge_request_file_tree_sidebar_spec.rb
+- spec/features/merge_request/user_sees_merge_widget_spec.rb
+- spec/features/merge_request/user_sees_pipelines_spec.rb
+- spec/features/merge_request/user_selects_branches_for_new_mr_spec.rb
+- spec/features/merge_request/user_squashes_merge_request_spec.rb
+- spec/features/merge_request/user_suggests_changes_on_diff_spec.rb
+- spec/features/merge_request/user_tries_to_access_private_project_info_through_new_mr_spec.rb
+- spec/features/merge_request/user_uses_quick_actions_spec.rb
+- spec/features/merge_request/user_views_auto_expanding_diff_spec.rb
+- spec/features/merge_request/user_views_comment_on_diff_file_spec.rb
+- spec/features/merge_request/user_views_diffs_file_by_file_spec.rb
+- spec/features/merge_request/user_views_open_merge_request_spec.rb
+- spec/features/merge_requests/user_sees_empty_state_spec.rb
+- spec/features/monitor_sidebar_link_spec.rb
+- spec/features/nav/new_nav_for_everyone_callout_spec.rb
+- spec/features/nav/new_nav_invite_members_spec.rb
+- spec/features/nav/pinned_nav_items_spec.rb
+- spec/features/oauth_provider_authorize_spec.rb
+- spec/features/participants_autocomplete_spec.rb
+- spec/features/profile_spec.rb
+- spec/features/profiles/account_spec.rb
+- spec/features/profiles/active_sessions_spec.rb
+- spec/features/profiles/chat_names_spec.rb
+- spec/features/profiles/emails_spec.rb
+- spec/features/profiles/gpg_keys_spec.rb
+- spec/features/profiles/keys_spec.rb
+- spec/features/profiles/list_users_comment_template_spec.rb
+- spec/features/profiles/oauth_applications_spec.rb
+- spec/features/profiles/password_spec.rb
+- spec/features/profiles/personal_access_tokens_spec.rb
+- spec/features/profiles/two_factor_auths_spec.rb
+- spec/features/profiles/user_changes_notified_of_own_activity_spec.rb
+- spec/features/profiles/user_creates_comment_template_spec.rb
+- spec/features/profiles/user_deletes_comment_template_spec.rb
+- spec/features/profiles/user_edit_preferences_spec.rb
+- spec/features/profiles/user_edit_profile_spec.rb
+- spec/features/profiles/user_manages_applications_spec.rb
+- spec/features/profiles/user_manages_emails_spec.rb
+- spec/features/profiles/user_search_settings_spec.rb
+- spec/features/profiles/user_updates_comment_template_spec.rb
+- spec/features/profiles/user_uses_comment_template_spec.rb
+- spec/features/profiles/user_visits_notifications_tab_spec.rb
+- spec/features/profiles/user_visits_profile_authentication_log_spec.rb
+- spec/features/profiles/user_visits_profile_preferences_page_spec.rb
+- spec/features/profiles/user_visits_profile_spec.rb
+- spec/features/projects/active_tabs_spec.rb
+- spec/features/projects/activity/user_sees_private_activity_spec.rb
+- spec/features/projects/blobs/blame_spec.rb
+- spec/features/projects/blobs/blob_show_spec.rb
+- spec/features/projects/blobs/edit_spec.rb
+- spec/features/projects/blobs/user_views_pipeline_editor_button_spec.rb
+- spec/features/projects/branches/user_creates_branch_spec.rb
+- spec/features/projects/branches_spec.rb
+- spec/features/projects/commit/cherry_pick_spec.rb
+- spec/features/projects/commit/user_reverts_commit_spec.rb
+- spec/features/projects/commits/user_browses_commits_spec.rb
+- spec/features/projects/confluence/user_views_confluence_page_spec.rb
+- spec/features/projects/environments/environment_spec.rb
+- spec/features/projects/environments/environments_spec.rb
+- spec/features/projects/feature_flags/user_creates_feature_flag_spec.rb
+- spec/features/projects/feature_flags/user_deletes_feature_flag_spec.rb
+- spec/features/projects/feature_flags/user_sees_feature_flag_list_spec.rb
+- spec/features/projects/feature_flags/user_updates_feature_flag_spec.rb
+- spec/features/projects/features_visibility_spec.rb
+- spec/features/projects/files/editing_a_file_spec.rb
+- spec/features/projects/files/project_owner_creates_license_file_spec.rb
+- spec/features/projects/files/user_browses_files_spec.rb
+- spec/features/projects/files/user_creates_directory_spec.rb
+- spec/features/projects/files/user_creates_files_spec.rb
+- spec/features/projects/files/user_deletes_files_spec.rb
+- spec/features/projects/files/user_edits_files_spec.rb
+- spec/features/projects/files/user_find_file_spec.rb
+- spec/features/projects/files/user_reads_pipeline_status_spec.rb
+- spec/features/projects/files/user_replaces_files_spec.rb
+- spec/features/projects/files/user_searches_for_files_spec.rb
+- spec/features/projects/files/user_uploads_files_spec.rb
+- spec/features/projects/fork_spec.rb
+- spec/features/projects/forks/fork_list_spec.rb
+- spec/features/projects/graph_spec.rb
+- spec/features/projects/import_export/import_file_spec.rb
+- spec/features/projects/issuable_templates_spec.rb
+- spec/features/projects/issues/design_management/user_links_to_designs_in_issue_spec.rb
+- spec/features/projects/issues/design_management/user_views_design_spec.rb
+- spec/features/projects/issues/email_participants_spec.rb
+- spec/features/projects/jobs/permissions_spec.rb
+- spec/features/projects/jobs/user_browses_job_spec.rb
+- spec/features/projects/jobs/user_triggers_manual_job_with_variables_spec.rb
+- spec/features/projects/jobs_spec.rb
+- spec/features/projects/labels/issues_sorted_by_priority_spec.rb
+- spec/features/projects/labels/update_prioritization_spec.rb
+- spec/features/projects/labels/user_views_labels_spec.rb
+- spec/features/projects/members/group_member_cannot_request_access_to_his_group_project_spec.rb
+- spec/features/projects/members/group_requester_cannot_request_access_to_project_spec.rb
+- spec/features/projects/members/manage_members_spec.rb
+- spec/features/projects/members/member_leaves_project_spec.rb
+- spec/features/projects/members/sorting_spec.rb
+- spec/features/projects/members/tabs_spec.rb
+- spec/features/projects/members/user_requests_access_spec.rb
+- spec/features/projects/merge_request_button_spec.rb
+- spec/features/projects/milestones/milestone_editing_spec.rb
+- spec/features/projects/milestones/milestone_showing_spec.rb
+- spec/features/projects/milestones/milestone_spec.rb
+- spec/features/projects/milestones/milestones_sorting_spec.rb
+- spec/features/projects/milestones/new_spec.rb
+- spec/features/projects/milestones/user_interacts_with_labels_spec.rb
+- spec/features/projects/navbar_spec.rb
+- spec/features/projects/network_graph_spec.rb
+- spec/features/projects/new_project_from_template_spec.rb
+- spec/features/projects/new_project_spec.rb
+- spec/features/projects/pipeline_schedules_spec.rb
+- spec/features/projects/settings/merge_requests_settings_spec.rb
+- spec/features/projects/settings/monitor_settings_spec.rb
+- spec/features/projects/settings/registry_settings_cleanup_tags_spec.rb
+- spec/features/projects/settings/registry_settings_spec.rb
+- spec/features/projects/settings/user_archives_project_spec.rb
+- spec/features/projects/settings/user_changes_default_branch_spec.rb
+- spec/features/projects/settings/user_manages_merge_requests_settings_spec.rb
+- spec/features/projects/settings/user_renames_a_project_spec.rb
+- spec/features/projects/settings/user_searches_in_settings_spec.rb
+- spec/features/projects/settings/user_tags_project_spec.rb
+- spec/features/projects/settings/user_transfers_a_project_spec.rb
+- spec/features/projects/settings/visibility_settings_spec.rb
+- spec/features/projects/show/clone_button_spec.rb
+- spec/features/projects/show/download_buttons_spec.rb
+- spec/features/projects/show/no_password_spec.rb
+- spec/features/projects/show/redirects_spec.rb
+- spec/features/projects/show/rss_spec.rb
+- spec/features/projects/show/user_interacts_with_auto_devops_banner_spec.rb
+- spec/features/projects/show/user_interacts_with_stars_spec.rb
+- spec/features/projects/show/user_sees_collaboration_links_spec.rb
+- spec/features/projects/show/user_sees_git_instructions_spec.rb
+- spec/features/projects/show/user_sees_setup_shortcut_buttons_spec.rb
+- spec/features/projects/show/user_uploads_files_spec.rb
+- spec/features/projects/snippets/show_spec.rb
+- spec/features/projects/snippets/user_updates_snippet_spec.rb
+- spec/features/projects/sourcegraph_csp_spec.rb
+- spec/features/projects/tags/user_views_tag_spec.rb
+- spec/features/projects/tags/user_views_tags_spec.rb
+- spec/features/projects/tree/create_directory_spec.rb
+- spec/features/projects/tree/create_file_spec.rb
+- spec/features/projects/tree/rss_spec.rb
+- spec/features/projects/tree/tree_show_spec.rb
+- spec/features/projects/user_creates_project_spec.rb
+- spec/features/projects/user_sees_sidebar_spec.rb
+- spec/features/projects/user_sees_user_popover_spec.rb
+- spec/features/projects/user_uses_shortcuts_spec.rb
+- spec/features/projects/wiki/user_views_wiki_empty_spec.rb
+- spec/features/projects/wikis_spec.rb
+- spec/features/projects/work_items/work_item_spec.rb
+- spec/features/projects_spec.rb
+- spec/features/reportable_note/merge_request_spec.rb
+- spec/features/search/user_searches_for_code_spec.rb
+- spec/features/search/user_searches_for_comments_spec.rb
+- spec/features/search/user_searches_for_commits_spec.rb
+- spec/features/search/user_searches_for_issues_spec.rb
+- spec/features/search/user_searches_for_merge_requests_spec.rb
+- spec/features/search/user_searches_for_milestones_spec.rb
+- spec/features/search/user_searches_for_wiki_pages_spec.rb
+- spec/features/search/user_uses_header_search_field_spec.rb
+- spec/features/search/user_uses_search_filters_spec.rb
+- spec/features/security/dashboard_access_spec.rb
+- spec/features/security/profile_access_spec.rb
+- spec/features/security/project/internal_access_spec.rb
+- spec/features/security/project/private_access_spec.rb
+- spec/features/security/project/public_access_spec.rb
+- spec/features/security/project/snippet/internal_access_spec.rb
+- spec/features/security/project/snippet/private_access_spec.rb
+- spec/features/security/project/snippet/public_access_spec.rb
+- spec/features/snippets/notes_on_personal_snippets_spec.rb
+- spec/features/tags/developer_views_tags_spec.rb
+- spec/features/task_lists_spec.rb
+- spec/features/unsubscribe_links_spec.rb
+- spec/features/uploads/user_uploads_avatar_to_profile_spec.rb
+- spec/features/uploads/user_uploads_file_to_note_spec.rb
+- spec/features/user_opens_link_to_comment_spec.rb
+- spec/features/user_sees_active_nav_items_spec.rb
+- spec/features/user_settings/active_sessions_spec.rb
+- spec/features/user_settings/password_spec.rb
+- spec/features/user_settings/personal_access_tokens_spec.rb
+- spec/features/users/login_spec.rb
+- spec/features/users/overview_spec.rb
+- spec/features/users/rss_spec.rb
+- spec/features/users/show_spec.rb
+- spec/features/users/signup_spec.rb
+- spec/features/users/snippets_spec.rb
+- spec/features/users/user_browses_projects_on_user_page_spec.rb
+- spec/features/webauthn_spec.rb
+- spec/features/whats_new_spec.rb
+- spec/finders/admin/projects_finder_spec.rb
+- spec/finders/autocomplete/move_to_project_finder_spec.rb
+- spec/finders/autocomplete/routes_finder_spec.rb
+- spec/finders/events_finder_spec.rb
+- spec/finders/fork_targets_finder_spec.rb
+- spec/finders/issues_finder_spec.rb
+- spec/finders/members_finder_spec.rb
+- spec/finders/notes_finder_spec.rb
+- spec/finders/packages/npm/package_finder_spec.rb
+- spec/finders/personal_projects_finder_spec.rb
+- spec/finders/projects/topics_finder_spec.rb
+- spec/finders/work_items/work_items_finder_spec.rb
+- spec/frontend/fixtures/autocomplete_sources.rb
+- spec/frontend/fixtures/issues.rb
+- spec/frontend/fixtures/namespaces.rb
+- spec/frontend/fixtures/pipeline_details.rb
+- spec/frontend/fixtures/snippet.rb
+- spec/frontend/fixtures/users.rb
+- spec/frontend/fixtures/webauthn.rb
+- spec/graphql/mutations/users/set_namespace_commit_email_spec.rb
+- spec/graphql/resolvers/board_list_issues_resolver_spec.rb
+- spec/graphql/resolvers/board_lists_resolver_spec.rb
+- spec/graphql/resolvers/board_resolver_spec.rb
+- spec/graphql/resolvers/boards_resolver_spec.rb
+- spec/graphql/resolvers/namespace_projects_resolver_spec.rb
+- spec/graphql/resolvers/projects/fork_targets_resolver_spec.rb
+- spec/graphql/resolvers/recent_boards_resolver_spec.rb
+- spec/graphql/types/project_type_spec.rb
+- spec/helpers/avatars_helper_spec.rb
+- spec/helpers/award_emoji_helper_spec.rb
+- spec/helpers/blob_helper_spec.rb
+- spec/helpers/boards_helper_spec.rb
+- spec/helpers/events_helper_spec.rb
+- spec/helpers/gitlab_routing_helper_spec.rb
+- spec/helpers/markup_helper_spec.rb
+- spec/helpers/notes_helper_spec.rb
+- spec/helpers/projects_helper_spec.rb
+- spec/helpers/search_helper_spec.rb
+- spec/helpers/submodule_helper_spec.rb
+- spec/helpers/tree_helper_spec.rb
+- spec/lib/banzai/filter/references/user_reference_filter_spec.rb
+- spec/lib/banzai/filter/truncate_visible_filter_spec.rb
+- spec/lib/banzai/reference_parser/project_parser_spec.rb
+- spec/lib/bulk_imports/groups/loaders/group_loader_spec.rb
+- spec/lib/constraints/user_url_constrainer_spec.rb
+- spec/lib/feature_spec.rb
+- spec/lib/generators/gitlab/partitioning/foreign_keys_generator_spec.rb
+- spec/lib/gitlab/analytics/usage_trends/workers_argument_builder_spec.rb
+- spec/lib/gitlab/background_migration/backfill_environment_tiers_spec.rb
+- spec/lib/gitlab/background_migration/backfill_root_storage_statistics_fork_storage_sizes_spec.rb
+- spec/lib/gitlab/background_migration/backfill_snippet_repositories_spec.rb
+- spec/lib/gitlab/background_migration/backfill_user_details_fields_spec.rb
+- spec/lib/gitlab/background_migration/job_coordinator_spec.rb
+- spec/lib/gitlab/checks/container_moved_spec.rb
+- spec/lib/gitlab/checks/project_created_spec.rb
+- spec/lib/gitlab/ci/trace/archive_spec.rb
+- spec/lib/gitlab/database/decomposition/migrate_spec.rb
+- spec/lib/gitlab/database/load_balancing/transaction_leaking_spec.rb
+- spec/lib/gitlab/database/load_balancing_spec.rb
+- spec/lib/gitlab/database/lock_writes_manager_spec.rb
+- spec/lib/gitlab/database/migration_helpers/loose_foreign_key_helpers_spec.rb
+- spec/lib/gitlab/database/migration_helpers/v2_spec.rb
+- spec/lib/gitlab/database/migration_helpers_spec.rb
+- spec/lib/gitlab/database/migrations/observers/transaction_duration_spec.rb
+- spec/lib/gitlab/database/migrations/test_batched_background_runner_spec.rb
+- spec/lib/gitlab/database/migrations/timeout_helpers_spec.rb
+- spec/lib/gitlab/database/partitioning/list/convert_table_spec.rb
+- spec/lib/gitlab/database/partitioning/monthly_strategy_spec.rb
+- spec/lib/gitlab/database/partitioning/sliding_list_strategy_spec.rb
+- spec/lib/gitlab/database/partitioning_migration_helpers/backfill_partitioned_table_spec.rb
+- spec/lib/gitlab/database/partitioning_migration_helpers/table_management_helpers_spec.rb
+- spec/lib/gitlab/database/reflection_spec.rb
+- spec/lib/gitlab/database/transaction/observer_spec.rb
+- spec/lib/gitlab/database/with_lock_retries_spec.rb
+- spec/lib/gitlab/error_tracking/processor/sidekiq_processor_spec.rb
+- spec/lib/gitlab/fogbugz_import/project_creator_spec.rb
+- spec/lib/gitlab/git_access_project_spec.rb
+- spec/lib/gitlab/git_access_spec.rb
+- spec/lib/gitlab/gitaly_client/with_feature_flag_actors_spec.rb
+- spec/lib/gitlab/import_export/importer_spec.rb
+- spec/lib/gitlab/import_export/project/export_task_spec.rb
+- spec/lib/gitlab/import_export/project/import_task_spec.rb
+- spec/lib/gitlab/import_export/snippet_repo_restorer_spec.rb
+- spec/lib/gitlab/import_export/snippet_repo_saver_spec.rb
+- spec/lib/gitlab/import_export/snippets_repo_restorer_spec.rb
+- spec/lib/gitlab/issuable_metadata_spec.rb
+- spec/lib/gitlab/legacy_github_import/project_creator_spec.rb
+- spec/lib/gitlab/noteable_metadata_spec.rb
+- spec/lib/gitlab/patch/redis_cache_store_spec.rb
+- spec/lib/gitlab/project_search_results_spec.rb
+- spec/lib/gitlab/project_template_spec.rb
+- spec/lib/gitlab/reference_extractor_spec.rb
+- spec/lib/gitlab/relative_positioning/mover_spec.rb
+- spec/lib/gitlab/sample_data_template_spec.rb
+- spec/lib/gitlab/themes_spec.rb
+- spec/lib/gitlab/utils/username_and_email_generator_spec.rb
+- spec/mailers/emails/service_desk_spec.rb
+- spec/mailers/notify_spec.rb
+- spec/migrations/20221002234454_finalize_group_member_namespace_id_migration_spec.rb
+- spec/migrations/20221018050323_add_objective_and_keyresult_to_work_item_types_spec.rb
+- spec/migrations/20221018062308_schedule_backfill_project_namespace_details_spec.rb
+- spec/migrations/20221018095434_schedule_disable_legacy_open_source_license_for_projects_less_than_five_mb_spec.rb
+- spec/migrations/20221018193635_ensure_task_note_renaming_background_migration_finished_spec.rb
+- spec/migrations/20221021145820_create_routing_table_for_builds_metadata_v2_spec.rb
+- spec/migrations/20221025043930_change_default_value_on_password_last_changed_at_to_user_details_spec.rb
+- spec/migrations/20221028022627_add_index_on_password_last_changed_at_to_user_details_spec.rb
+- spec/migrations/20221101032521_add_default_preferred_language_to_application_settings_spec.rb
+- spec/migrations/20221101032600_add_text_limit_to_default_preferred_language_on_application_settings_spec.rb
+- spec/migrations/20221102090943_create_second_partition_for_builds_metadata_spec.rb
+- spec/migrations/20221102231130_finalize_backfill_user_details_fields_spec.rb
+- spec/migrations/20221104115712_backfill_project_statistics_storage_size_without_uploads_size_spec.rb
+- spec/migrations/20221110152133_delete_orphans_approval_rules_spec.rb
+- spec/migrations/20221115173607_ensure_work_item_type_backfill_migration_finished_spec.rb
+- spec/migrations/20221122132812_schedule_prune_stale_project_export_jobs_spec.rb
+- spec/migrations/20221123133054_queue_reset_status_on_container_repositories_spec.rb
+- spec/migrations/20221209110934_update_import_sources_on_application_settings_spec.rb
+- spec/migrations/20221209110935_fix_update_import_sources_on_application_settings_spec.rb
+- spec/migrations/20221209235940_cleanup_o_auth_access_tokens_with_null_expires_in_spec.rb
+- spec/migrations/20221210154044_update_active_billable_users_index_spec.rb
+- spec/migrations/20221215151822_schedule_backfill_releases_author_id_spec.rb
+- spec/migrations/20221219122320_copy_clickhouse_connection_string_to_encrypted_var_spec.rb
+- spec/migrations/20221220131020_bump_default_partition_id_value_for_ci_tables_spec.rb
+- spec/migrations/20221221110733_remove_temp_index_for_project_statistics_upload_size_migration_spec.rb
+- spec/migrations/20221223123019_delete_queued_jobs_for_vulnerabilities_feedback_migration_spec.rb
+- spec/migrations/20221226153252_queue_fix_incoherent_packages_size_on_project_statistics_spec.rb
+- spec/migrations/20230116111252_finalize_todo_sanitization_spec.rb
+- spec/migrations/20230117114739_clear_duplicate_jobs_cookies_spec.rb
+- spec/migrations/20230118144623_schedule_migration_for_remediation_spec.rb
+- spec/migrations/20230125195503_queue_backfill_compliance_violations_spec.rb
+- spec/migrations/20230130182412_schedule_create_vulnerability_links_migration_spec.rb
+- spec/migrations/20230131125844_add_project_id_name_id_version_index_to_installable_npm_packages_spec.rb
+- spec/migrations/20230201171450_finalize_backfill_environment_tier_migration_spec.rb
+- spec/migrations/20230208125736_schedule_migration_for_links_spec.rb
+- spec/migrations/20230209222452_schedule_remove_project_group_link_with_missing_groups_spec.rb
+- spec/migrations/20230220102212_swap_columns_ci_build_needs_big_int_conversion_spec.rb
+- spec/migrations/20230221093533_add_tmp_partial_index_on_vulnerability_report_types_spec.rb
+- spec/migrations/20230223065753_finalize_nullify_creator_id_of_orphaned_projects_spec.rb
+- spec/migrations/20230224085743_update_issues_internal_id_scope_spec.rb
+- spec/migrations/20230224144233_migrate_evidences_from_raw_metadata_spec.rb
+- spec/migrations/20230228142350_add_notifications_work_item_widget_spec.rb
+- spec/migrations/20230302811133_re_migrate_redis_slot_keys_spec.rb
+- spec/migrations/20230309071242_delete_security_policy_bot_users_spec.rb
+- spec/migrations/20230313142631_backfill_ml_candidates_package_id_spec.rb
+- spec/migrations/20230313150531_reschedule_migration_for_remediation_spec.rb
+- spec/migrations/20230317004428_migrate_daily_redis_hll_events_to_weekly_aggregation_spec.rb
+- spec/migrations/20230317162059_add_current_user_todos_work_item_widget_spec.rb
+- spec/migrations/20230321170823_backfill_ml_candidates_internal_id_spec.rb
+- spec/migrations/20230322085041_remove_user_namespace_records_from_vsa_aggregation_spec.rb
+- spec/migrations/20230327123333_backfill_product_analytics_data_collector_host_spec.rb
+- spec/migrations/20230328030101_add_secureflag_training_provider_spec.rb
+- spec/migrations/20230328100534_truncate_error_tracking_tables_spec.rb
+- spec/migrations/20230412141541_reschedule_links_avoiding_duplication_spec.rb
+- spec/migrations/20230412185837_queue_populate_vulnerability_dismissal_fields_spec.rb
+- spec/migrations/20230419105225_remove_phabricator_from_application_settings_spec.rb
+- spec/migrations/20230426085615_queue_backfill_resource_link_events_spec.rb
+- spec/migrations/20230426102200_fix_import_sources_on_application_settings_after_phabricator_removal_spec.rb
+- spec/migrations/20230428085332_remove_shimo_zentao_integration_records_spec.rb
+- spec/migrations/20230515153600_finalize_back_fill_prepared_at_merge_requests_spec.rb
+- spec/migrations/20230522220709_ensure_incident_work_item_type_backfill_is_finished_spec.rb
+- spec/migrations/add_namespaces_emails_enabled_column_data_spec.rb
+- spec/migrations/add_okr_hierarchy_restrictions_spec.rb
+- spec/migrations/add_projects_emails_enabled_column_data_spec.rb
+- spec/migrations/cleanup_bigint_conversion_for_merge_request_metrics_for_self_hosts_spec.rb
+- spec/migrations/cleanup_vulnerability_state_transitions_with_same_from_state_to_state_spec.rb
+- spec/migrations/delete_migrate_shared_vulnerability_scanners_spec.rb
+- spec/migrations/drop_packages_events_table_spec.rb
+- spec/migrations/ensure_commit_user_mentions_note_id_bigint_backfill_is_finished_for_gitlab_dot_com_spec.rb
+- spec/migrations/ensure_design_user_mentions_note_id_bigint_backfill_is_finished_for_gitlab_dot_com_spec.rb
+- spec/migrations/ensure_epic_user_mentions_bigint_backfill_is_finished_for_gitlab_dot_com_spec.rb
+- spec/migrations/ensure_issue_user_mentions_bigint_backfill_is_finished_for_gitlab_dot_com_spec.rb
+- spec/migrations/ensure_merge_request_metrics_id_bigint_backfill_is_finished_for_gitlab_dot_com_spec.rb
+- spec/migrations/ensure_mr_user_mentions_note_id_bigint_backfill_is_finished_for_gitlab_dot_com_spec.rb
+- spec/migrations/ensure_suggestions_note_id_bigint_backfill_is_finished_for_gitlab_dot_com_spec.rb
+- spec/migrations/ensure_timelogs_note_id_bigint_backfill_is_finished_for_gitlab_dot_com_spec.rb
+- spec/migrations/ensure_unique_debian_packages_spec.rb
+- spec/migrations/ensure_vum_bigint_backfill_is_finished_for_gl_dot_com_spec.rb
+- spec/migrations/finalize_invalid_member_cleanup_spec.rb
+- spec/migrations/finalize_issues_iid_scoping_to_namespace_spec.rb
+- spec/migrations/finalize_issues_namespace_id_backfilling_spec.rb
+- spec/migrations/insert_daily_invites_trial_plan_limits_spec.rb
+- spec/migrations/nullify_last_error_from_project_mirror_data_spec.rb
+- spec/migrations/queue_backfill_prepared_at_data_spec.rb
+- spec/migrations/queue_backfill_user_details_fields_spec.rb
+- spec/migrations/queue_populate_projects_star_count_spec.rb
+- spec/migrations/recount_epic_cache_counts_spec.rb
+- spec/migrations/recount_epic_cache_counts_v3_spec.rb
+- spec/migrations/remove_flowdock_integration_records_spec.rb
+- spec/migrations/requeue_backfill_admin_mode_scope_for_personal_access_tokens_spec.rb
+- spec/migrations/reschedule_incident_work_item_type_id_backfill_spec.rb
+- spec/migrations/reschedule_migrate_shared_vulnerability_scanners_spec.rb
+- spec/migrations/schedule_fixing_security_scan_statuses_spec.rb
+- spec/migrations/second_recount_epic_cache_counts_spec.rb
+- spec/migrations/set_email_confirmation_setting_before_removing_send_user_confirmation_email_column_spec.rb
+- spec/migrations/set_email_confirmation_setting_from_send_user_confirmation_email_setting_spec.rb
+- spec/migrations/set_email_confirmation_setting_from_soft_email_confirmation_ff_spec.rb
+- spec/migrations/swap_epic_user_mentions_note_id_to_bigint_for_gitlab_dot_com_spec.rb
+- spec/migrations/swap_merge_request_user_mentions_note_id_to_bigint_2_spec.rb
+- spec/migrations/swap_note_diff_files_note_id_to_bigint_for_gitlab_dot_com_spec.rb
+- spec/migrations/swap_sent_notifications_id_columns_spec.rb
+- spec/migrations/swap_snippet_user_mentions_note_id_to_bigint_for_gitlab_dot_com_spec.rb
+- spec/migrations/swap_suggestions_note_id_to_bigint_for_gitlab_dot_com_spec.rb
+- spec/migrations/swap_timelogs_note_id_to_bigint_for_gitlab_dot_com_spec.rb
+- spec/models/abuse_report_spec.rb
+- spec/models/analytics/cycle_analytics/aggregation_spec.rb
+- spec/models/analytics/cycle_analytics/issue_stage_event_spec.rb
+- spec/models/analytics/cycle_analytics/merge_request_stage_event_spec.rb
+- spec/models/application_record_spec.rb
+- spec/models/concerns/mentionable_spec.rb
+- spec/models/concerns/pg_full_text_searchable_spec.rb
+- spec/models/concerns/reset_on_column_errors_spec.rb
+- spec/models/concerns/routable_spec.rb
+- spec/models/container_repository_spec.rb
+- spec/models/deploy_key_spec.rb
+- spec/models/design_management/design_spec.rb
+- spec/models/event_spec.rb
+- spec/models/hooks/system_hook_spec.rb
+- spec/models/issue_spec.rb
+- spec/models/member_spec.rb
+- spec/models/namespace/root_storage_statistics_spec.rb
+- spec/models/namespace_setting_spec.rb
+- spec/models/namespace_spec.rb
+- spec/models/namespace_statistics_spec.rb
+- spec/models/note_spec.rb
+- spec/models/notification_recipient_spec.rb
+- spec/models/project_authorization_spec.rb
+- spec/models/project_spec.rb
+- spec/models/project_team_spec.rb
+- spec/models/project_wiki_spec.rb
+- spec/models/review_spec.rb
+- spec/models/snippet_spec.rb
+- spec/models/user_spec.rb
+- spec/policies/ci/build_policy_spec.rb
+- spec/policies/design_management/design_policy_spec.rb
+- spec/policies/global_policy_spec.rb
+- spec/policies/namespace/root_storage_statistics_policy_spec.rb
+- spec/policies/note_policy_spec.rb
+- spec/policies/packages/policies/project_policy_spec.rb
+- spec/policies/project_policy_spec.rb
+- spec/presenters/merge_request_presenter_spec.rb
+- spec/requests/admin/users_controller_spec.rb
+- spec/requests/api/access_requests_spec.rb
+- spec/requests/api/alert_management_alerts_spec.rb
+- spec/requests/api/boards_spec.rb
+- spec/requests/api/clusters/agent_tokens_spec.rb
+- spec/requests/api/clusters/agents_spec.rb
+- spec/requests/api/commits_spec.rb
+- spec/requests/api/discussions_spec.rb
+- spec/requests/api/doorkeeper_access_spec.rb
+- spec/requests/api/environments_spec.rb
+- spec/requests/api/events_spec.rb
+- spec/requests/api/files_spec.rb
+- spec/requests/api/graphql/boards/board_list_issues_query_spec.rb
+- spec/requests/api/graphql/ci/config_spec.rb
+- spec/requests/api/graphql/ci/pipeline_schedules_spec.rb
+- spec/requests/api/graphql/current_user_query_spec.rb
+- spec/requests/api/graphql/merge_request/merge_request_spec.rb
+- spec/requests/api/graphql/mutations/award_emojis/add_spec.rb
+- spec/requests/api/graphql/mutations/award_emojis/toggle_spec.rb
+- spec/requests/api/graphql/namespace/projects_spec.rb
+- spec/requests/api/graphql/namespace/root_storage_statistics_spec.rb
+- spec/requests/api/graphql/project/fork_targets_spec.rb
+- spec/requests/api/graphql/project/merge_request_spec.rb
+- spec/requests/api/graphql/project/merge_requests_spec.rb
+- spec/requests/api/graphql/project/project_members_spec.rb
+- spec/requests/api/graphql/project/recent_issue_boards_query_spec.rb
+- spec/requests/api/graphql/users/set_namespace_commit_email_spec.rb
+- spec/requests/api/groups_spec.rb
+- spec/requests/api/import_bitbucket_server_spec.rb
+- spec/requests/api/import_github_spec.rb
+- spec/requests/api/integrations_spec.rb
+- spec/requests/api/internal/base_spec.rb
+- spec/requests/api/invitations_spec.rb
+- spec/requests/api/issues/get_project_issues_spec.rb
+- spec/requests/api/issues/issues_spec.rb
+- spec/requests/api/issues/post_projects_issues_spec.rb
+- spec/requests/api/issues/put_projects_issues_spec.rb
+- spec/requests/api/keys_spec.rb
+- spec/requests/api/labels_spec.rb
+- spec/requests/api/maven_packages_spec.rb
+- spec/requests/api/merge_request_approvals_spec.rb
+- spec/requests/api/merge_requests_spec.rb
+- spec/requests/api/metrics/dashboard/annotations_spec.rb
+- spec/requests/api/metrics/user_starred_dashboards_spec.rb
+- spec/requests/api/namespaces_spec.rb
+- spec/requests/api/notes_spec.rb
+- spec/requests/api/project_events_spec.rb
+- spec/requests/api/project_hooks_spec.rb
+- spec/requests/api/project_import_spec.rb
+- spec/requests/api/project_milestones_spec.rb
+- spec/requests/api/project_packages_spec.rb
+- spec/requests/api/projects_spec.rb
+- spec/requests/api/protected_tags_spec.rb
+- spec/requests/api/resource_access_tokens_spec.rb
+- spec/requests/api/resource_label_events_spec.rb
+- spec/requests/api/resource_milestone_events_spec.rb
+- spec/requests/api/resource_state_events_spec.rb
+- spec/requests/api/submodules_spec.rb
+- spec/requests/api/task_completion_status_spec.rb
+- spec/requests/api/users_preferences_spec.rb
+- spec/requests/api/users_spec.rb
+- spec/requests/git_http_spec.rb
+- spec/requests/ide_controller_spec.rb
+- spec/requests/lfs_http_spec.rb
+- spec/requests/oauth/applications_controller_spec.rb
+- spec/requests/oauth/authorizations_controller_spec.rb
+- spec/requests/profiles/comment_templates_controller_spec.rb
+- spec/requests/profiles/notifications_controller_spec.rb
+- spec/requests/projects/harbor/repositories_controller_spec.rb
+- spec/requests/projects/settings/packages_and_registries_controller_spec.rb
+- spec/requests/projects/tags_controller_spec.rb
+- spec/requests/projects/wikis_controller_spec.rb
+- spec/requests/recursive_webhook_detection_spec.rb
+- spec/requests/search_controller_spec.rb
+- spec/requests/user_settings_spec.rb
+- spec/requests/users_controller_spec.rb
+- spec/requests/warden_spec.rb
+- spec/serializers/admin/abuse_report_details_entity_spec.rb
+- spec/serializers/ci/pipeline_entity_spec.rb
+- spec/serializers/diff_file_base_entity_spec.rb
+- spec/serializers/merge_request_current_user_entity_spec.rb
+- spec/services/admin/plan_limits/update_service_spec.rb
+- spec/services/admin/set_feature_flag_service_spec.rb
+- spec/services/auth/container_registry_authentication_service_spec.rb
+- spec/services/award_emojis/add_service_spec.rb
+- spec/services/ci/abort_pipelines_service_spec.rb
+- spec/services/draft_notes/publish_service_spec.rb
+- spec/services/environments/schedule_to_delete_review_apps_service_spec.rb
+- spec/services/import/bitbucket_server_service_spec.rb
+- spec/services/import/fogbugz_service_spec.rb
+- spec/services/import/github_service_spec.rb
+- spec/services/import/gitlab_projects/create_project_service_spec.rb
+- spec/services/issuable/bulk_update_service_spec.rb
+- spec/services/issues/create_service_spec.rb
+- spec/services/issues/update_service_spec.rb
+- spec/services/merge_requests/build_service_spec.rb
+- spec/services/merge_requests/create_service_spec.rb
+- spec/services/merge_requests/push_options_handler_service_spec.rb
+- spec/services/merge_requests/update_service_spec.rb
+- spec/services/milestones/promote_service_spec.rb
+- spec/services/milestones/transfer_service_spec.rb
+- spec/services/namespace_settings/update_service_spec.rb
+- spec/services/notes/build_service_spec.rb
+- spec/services/notes/copy_service_spec.rb
+- spec/services/notes/create_service_spec.rb
+- spec/services/notes/update_service_spec.rb
+- spec/services/notification_service_spec.rb
+- spec/services/packages/npm/create_package_service_spec.rb
+- spec/services/post_receive_service_spec.rb
+- spec/services/preview_markdown_service_spec.rb
+- spec/services/projects/create_from_template_service_spec.rb
+- spec/services/projects/create_service_spec.rb
+- spec/services/projects/destroy_service_spec.rb
+- spec/services/projects/download_service_spec.rb
+- spec/services/projects/fork_service_spec.rb
+- spec/services/projects/move_access_service_spec.rb
+- spec/services/projects/move_deploy_keys_projects_service_spec.rb
+- spec/services/projects/move_forks_service_spec.rb
+- spec/services/projects/move_lfs_objects_projects_service_spec.rb
+- spec/services/projects/move_notification_settings_service_spec.rb
+- spec/services/projects/move_project_authorizations_service_spec.rb
+- spec/services/projects/move_project_group_links_service_spec.rb
+- spec/services/projects/move_project_members_service_spec.rb
+- spec/services/projects/move_users_star_projects_service_spec.rb
+- spec/services/projects/overwrite_project_service_spec.rb
+- spec/services/projects/participants_service_spec.rb
+- spec/services/projects/transfer_service_spec.rb
+- spec/services/projects/update_service_spec.rb
+- spec/services/repositories/destroy_service_spec.rb
+- spec/services/resource_access_tokens/create_service_spec.rb
+- spec/services/snippets/create_service_spec.rb
+- spec/services/todo_service_spec.rb
+- spec/services/upload_service_spec.rb
+- spec/services/users/destroy_service_spec.rb
+- spec/services/users/migrate_records_to_ghost_user_service_spec.rb
+- spec/services/users/set_namespace_commit_email_service_spec.rb
+- spec/services/users/update_service_spec.rb
+- spec/services/work_items/update_service_spec.rb
+- spec/tasks/gitlab/backup_rake_spec.rb
+- spec/tasks/gitlab/check_rake_spec.rb
+- spec/tasks/import_rake_spec.rb
+- spec/views/layouts/header/_new_dropdown.haml_spec.rb
+- spec/views/layouts/profile.html.haml_spec.rb
+- spec/views/profiles/preferences/show.html.haml_spec.rb
+- spec/workers/new_issue_worker_spec.rb
+- spec/workers/new_merge_request_worker_spec.rb
diff --git a/spec/support/matchers/have_user.rb b/spec/support/matchers/have_user.rb
new file mode 100644
index 00000000000..64fc84a75cf
--- /dev/null
+++ b/spec/support/matchers/have_user.rb
@@ -0,0 +1,13 @@
+# frozen_string_literal: true
+
+RSpec::Matchers.define :have_user do |user|
+ match do |resource|
+ raise ArgumentError, 'Unknown resource type' unless resource.is_a?(Group) || resource.is_a?(Project)
+
+ expect(resource.has_user?(user)).to be_truthy
+ end
+
+ failure_message do |group|
+ "Expected #{group} to have the user #{user} among its members"
+ end
+end
diff --git a/spec/support/migration.rb b/spec/support/migration.rb
index fc8a4bb12fb..dadcbb1941e 100644
--- a/spec/support/migration.rb
+++ b/spec/support/migration.rb
@@ -17,7 +17,7 @@ RSpec.configure do |config|
end
config.after(:context, :migration) do
- Gitlab::CurrentSettings.clear_in_memory_application_settings!
+ Gitlab::ApplicationSettingFetcher.clear_in_memory_application_settings!
end
config.append_after(:context, :migration) do
diff --git a/spec/support/rspec_order_todo.yml b/spec/support/rspec_order_todo.yml
index 81196fdcbfa..7256fdb4018 100644
--- a/spec/support/rspec_order_todo.yml
+++ b/spec/support/rspec_order_todo.yml
@@ -94,7 +94,6 @@
- './ee/spec/controllers/groups/security/merge_commit_reports_controller_spec.rb'
- './ee/spec/controllers/groups/security/policies_controller_spec.rb'
- './ee/spec/controllers/groups/security/vulnerabilities_controller_spec.rb'
-- './ee/spec/controllers/groups/sso_controller_spec.rb'
- './ee/spec/controllers/groups/todos_controller_spec.rb'
- './ee/spec/controllers/groups/wikis_controller_spec.rb'
- './ee/spec/controllers/ldap/omniauth_callbacks_controller_spec.rb'
@@ -284,7 +283,6 @@
- './ee/spec/features/groups/settings/user_configures_insights_spec.rb'
- './ee/spec/features/groups/settings/user_searches_in_settings_spec.rb'
- './ee/spec/features/groups_spec.rb'
-- './ee/spec/features/groups/sso_spec.rb'
- './ee/spec/features/groups/wikis_spec.rb'
- './ee/spec/features/groups/wiki/user_views_wiki_empty_spec.rb'
- './ee/spec/features/ide/user_opens_ide_spec.rb'
@@ -918,7 +916,6 @@
- './ee/spec/helpers/gitlab_subscriptions/upcoming_reconciliation_helper_spec.rb'
- './ee/spec/helpers/groups/ldap_sync_helper_spec.rb'
- './ee/spec/helpers/groups/security_features_helper_spec.rb'
-- './ee/spec/helpers/groups/sso_helper_spec.rb'
- './ee/spec/helpers/kerberos_helper_spec.rb'
- './ee/spec/helpers/license_helper_spec.rb'
- './ee/spec/helpers/license_monitoring_helper_spec.rb'
@@ -1691,7 +1688,7 @@
- './ee/spec/models/gitlab_subscription_spec.rb'
- './ee/spec/models/gitlab_subscriptions/upcoming_reconciliation_spec.rb'
- './ee/spec/models/group_deletion_schedule_spec.rb'
-- './ee/spec/models/group_member_spec.rb'
+- './ee/spec/models/ee/group_member_spec.rb'
- './ee/spec/models/group_merge_request_approval_setting_spec.rb'
- './ee/spec/models/groups/repository_storage_move_spec.rb'
- './ee/spec/models/group_wiki_repository_spec.rb'
@@ -1715,7 +1712,7 @@
- './ee/spec/models/label_note_spec.rb'
- './ee/spec/models/ldap_group_link_spec.rb'
- './ee/spec/models/license_spec.rb'
-- './ee/spec/models/member_spec.rb'
+- './ee/spec/models/ee/member_spec.rb'
- './ee/spec/models/merge_request/blocking_spec.rb'
- './ee/spec/models/merge_request_block_spec.rb'
- './ee/spec/models/merge_requests/compliance_violation_spec.rb'
@@ -1740,7 +1737,7 @@
- './ee/spec/models/project_feature_spec.rb'
- './ee/spec/models/project_import_data_spec.rb'
- './ee/spec/models/project_import_state_spec.rb'
-- './ee/spec/models/project_member_spec.rb'
+- './ee/spec/models/ee/project_member_spec.rb'
- './ee/spec/models/project_repository_state_spec.rb'
- './ee/spec/models/project_security_setting_spec.rb'
- './ee/spec/models/protected_branch/required_code_owners_section_spec.rb'
@@ -2619,14 +2616,11 @@
- './ee/spec/services/gitlab_subscriptions/preview_billable_user_change_service_spec.rb'
- './ee/spec/services/gitlab_subscriptions/reconciliations/calculate_seat_count_data_service_spec.rb'
- './ee/spec/services/gitlab_subscriptions/reconciliations/check_seat_usage_alerts_eligibility_service_spec.rb'
-- './ee/spec/services/group_saml/group_managed_accounts/clean_up_members_service_spec.rb'
-- './ee/spec/services/group_saml/group_managed_accounts/transfer_membership_service_spec.rb'
- './ee/spec/services/group_saml/identity/destroy_service_spec.rb'
- './ee/spec/services/group_saml/saml_group_links/create_service_spec.rb'
- './ee/spec/services/group_saml/saml_group_links/destroy_service_spec.rb'
- './ee/spec/services/group_saml/saml_provider/create_service_spec.rb'
- './ee/spec/services/group_saml/saml_provider/update_service_spec.rb'
-- './ee/spec/services/group_saml/sign_up_service_spec.rb'
- './ee/spec/services/groups/create_service_spec.rb'
- './ee/spec/services/groups/destroy_service_spec.rb'
- './ee/spec/services/groups/epics_count_service_spec.rb'
@@ -3338,7 +3332,6 @@
- './spec/db/schema_spec.rb'
- './spec/dependencies/omniauth_saml_spec.rb'
- './spec/experiments/application_experiment_spec.rb'
-- './spec/experiments/in_product_guidance_environments_webide_experiment_spec.rb'
- './spec/features/abuse_report_spec.rb'
- './spec/features/action_cable_logging_spec.rb'
- './spec/features/admin/admin_abuse_reports_spec.rb'
@@ -6116,7 +6109,6 @@
- './spec/lib/gitlab/github_import/markdown_text_spec.rb'
- './spec/lib/gitlab/github_import/milestone_finder_spec.rb'
- './spec/lib/gitlab/github_import/object_counter_spec.rb'
-- './spec/lib/gitlab/github_import/page_counter_spec.rb'
- './spec/lib/gitlab/github_import/parallel_importer_spec.rb'
- './spec/lib/gitlab/github_import/parallel_scheduling_spec.rb'
- './spec/lib/gitlab/github_import/representation/diff_note_spec.rb'
@@ -6244,6 +6236,7 @@
- './spec/lib/gitlab/i18n/translation_entry_spec.rb'
- './spec/lib/gitlab/identifier_spec.rb'
- './spec/lib/gitlab/import/database_helpers_spec.rb'
+- './spec/lib/gitlab/import/page_counter_spec.rb'
- './spec/lib/gitlab/import_export/after_export_strategies/base_after_export_strategy_spec.rb'
- './spec/lib/gitlab/import_export/after_export_strategies/web_upload_strategy_spec.rb'
- './spec/lib/gitlab/import_export/after_export_strategy_builder_spec.rb'
@@ -7116,7 +7109,6 @@
- './spec/models/concerns/counter_attribute_spec.rb'
- './spec/models/concerns/cron_schedulable_spec.rb'
- './spec/models/concerns/cross_database_modification_spec.rb'
-- './spec/models/concerns/database_event_tracking_spec.rb'
- './spec/models/concerns/database_reflection_spec.rb'
- './spec/models/concerns/delete_with_limit_spec.rb'
- './spec/models/concerns/deployment_platform_spec.rb'
@@ -8117,7 +8109,6 @@
- './spec/requests/api/tags_spec.rb'
- './spec/requests/api/task_completion_status_spec.rb'
- './spec/requests/api/templates_spec.rb'
-- './spec/requests/api/terraform/modules/v1/packages_spec.rb'
- './spec/requests/api/terraform/state_spec.rb'
- './spec/requests/api/terraform/state_version_spec.rb'
- './spec/requests/api/todos_spec.rb'
@@ -9469,7 +9460,6 @@
- './spec/workers/concerns/cronjob_queue_spec.rb'
- './spec/workers/concerns/gitlab/github_import/object_importer_spec.rb'
- './spec/workers/concerns/gitlab/github_import/rescheduling_methods_spec.rb'
-- './spec/workers/concerns/gitlab/github_import/stage_methods_spec.rb'
- './spec/workers/concerns/limited_capacity/job_tracker_spec.rb'
- './spec/workers/concerns/limited_capacity/worker_spec.rb'
- './spec/workers/concerns/packages/cleanup_artifact_worker_spec.rb'
diff --git a/spec/support/rspec_run_time.rb b/spec/support/rspec_run_time.rb
index 977d4885624..2cfa4008fd3 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,14 @@ module Support
"Current RSS: ~#{rss_in_megabytes.round}M"
end
+
+ def load_average
+ if File.exist?('/proc/loadavg')
+ "load average: #{File.read('/proc/loadavg')}"
+ else
+ `uptime`[/(load average:[^\n]+)/, 1] || '(uptime failed)'
+ end
+ end
end
end
end
diff --git a/spec/support/shared_contexts/ci/catalog/resources/version_shared_context.rb b/spec/support/shared_contexts/ci/catalog/resources/version_shared_context.rb
index 3eeaa52d221..a451608a5cc 100644
--- a/spec/support/shared_contexts/ci/catalog/resources/version_shared_context.rb
+++ b/spec/support/shared_contexts/ci/catalog/resources/version_shared_context.rb
@@ -1,33 +1,42 @@
# frozen_string_literal: true
+# This context generates two catalog resources, each with two releases/versions.
+# `resource1` has versions `v1.0` and `v1.1`, with releases that have real commit shas.
+# `resource2` has versions `v2.0` and `v2.1`.
RSpec.shared_context 'when there are catalog resources with versions' do
let_it_be(:current_user) { create(:user) }
- let_it_be(:project1) { create(:project, :repository, name: 'A') }
- let_it_be(:project2) { create(:project, :repository, name: 'Z') }
- let_it_be(:project3) { create(:project, :repository, name: 'L', description: 'Z') }
+ let_it_be(:project1) { create(:project, :custom_repo, files: { 'README.md' => 'Readme v1.0' }) }
+ let_it_be(:project2) { create(:project, :repository) }
+
let_it_be_with_reload(:resource1) { create(:ci_catalog_resource, project: project1) }
let_it_be_with_reload(:resource2) { create(:ci_catalog_resource, project: project2) }
- let_it_be(:resource3) { create(:ci_catalog_resource, project: project3) }
- let_it_be_with_reload(:release_v1_0) { create(:release, project: project1, tag: 'v1.0', released_at: 4.days.ago) }
- let_it_be(:release_v1_1) { create(:release, project: project1, tag: 'v1.1', released_at: 3.days.ago) }
- let_it_be(:release_v2_0) { create(:release, project: project2, tag: 'v2.0', released_at: 2.days.ago) }
- let_it_be(:release_v2_1) { create(:release, project: project2, tag: 'v2.1', released_at: 1.day.ago) }
+ let(:v1_0) { resource1.versions.by_name('v1.0').first }
+ let(:v1_1) { resource1.versions.by_name('v1.1').first }
+ let(:v2_0) { resource2.versions.by_name('v2.0').first }
+ let(:v2_1) { resource2.versions.by_name('v2.1').first }
- let_it_be(:v1_0) do
- create(:ci_catalog_resource_version, catalog_resource: resource1, release: release_v1_0, created_at: 1.day.ago)
- end
+ before_all do
+ project1.repository.create_branch('branch_v1.1', project1.default_branch)
- let_it_be(:v1_1) do
- create(:ci_catalog_resource_version, catalog_resource: resource1, release: release_v1_1, created_at: 2.days.ago)
- end
+ project1.repository.update_file(
+ current_user, 'README.md', 'Readme v1.1', message: 'Update readme', branch_name: 'branch_v1.1')
- let_it_be(:v2_0) do
- create(:ci_catalog_resource_version, catalog_resource: resource2, release: release_v2_0, created_at: 3.days.ago)
- end
+ tag_v1_0 = project1.repository.add_tag(current_user, 'v1.0', project1.default_branch)
+ tag_v1_1 = project1.repository.add_tag(current_user, 'v1.1', 'branch_v1.1')
+
+ release_v1_0 = create(:release, project: project1, tag: 'v1.0', released_at: 4.days.ago,
+ sha: tag_v1_0.dereferenced_target.sha)
+ release_v1_1 = create(:release, project: project1, tag: 'v1.1', released_at: 3.days.ago,
+ sha: tag_v1_1.dereferenced_target.sha)
+
+ release_v2_0 = create(:release, project: project2, tag: 'v2.0', released_at: 2.days.ago)
+ release_v2_1 = create(:release, project: project2, tag: 'v2.1', released_at: 1.day.ago)
- let_it_be(:v2_1) do
+ create(:ci_catalog_resource_version, catalog_resource: resource1, release: release_v1_0, created_at: 1.day.ago)
+ create(:ci_catalog_resource_version, catalog_resource: resource1, release: release_v1_1, created_at: 2.days.ago)
+ create(:ci_catalog_resource_version, catalog_resource: resource2, release: release_v2_0, created_at: 3.days.ago)
create(:ci_catalog_resource_version, catalog_resource: resource2, release: release_v2_1, created_at: 4.days.ago)
end
end
diff --git a/spec/support/shared_contexts/features/integrations/instance_integrations_shared_context.rb b/spec/support/shared_contexts/features/integrations/instance_integrations_shared_context.rb
index c740917cec4..678199a35ea 100644
--- a/spec/support/shared_contexts/features/integrations/instance_integrations_shared_context.rb
+++ b/spec/support/shared_contexts/features/integrations/instance_integrations_shared_context.rb
@@ -7,7 +7,7 @@ RSpec.shared_context 'instance integration activation' do
before do
sign_in(user)
- gitlab_enable_admin_mode_sign_in(user)
+ enable_admin_mode!(user)
end
def visit_instance_integrations
diff --git a/spec/support/shared_contexts/graphql/types/query_type_shared_context.rb b/spec/support/shared_contexts/graphql/types/query_type_shared_context.rb
index 6ab41d87f44..391336526e3 100644
--- a/spec/support/shared_contexts/graphql/types/query_type_shared_context.rb
+++ b/spec/support/shared_contexts/graphql/types/query_type_shared_context.rb
@@ -26,6 +26,8 @@ RSpec.shared_context 'with FOSS query type fields' do
:milestone,
:namespace,
:note,
+ :organization,
+ :organizations,
:package,
:project,
:projects,
diff --git a/spec/support/shared_contexts/lib/gitlab/database/partitioning/list_partitioning_shared_context.rb b/spec/support/shared_contexts/lib/gitlab/database/partitioning/list_partitioning_shared_context.rb
index 3d978a6fde4..fec11349b62 100644
--- a/spec/support/shared_contexts/lib/gitlab/database/partitioning/list_partitioning_shared_context.rb
+++ b/spec/support/shared_contexts/lib/gitlab/database/partitioning/list_partitioning_shared_context.rb
@@ -13,6 +13,8 @@ RSpec.shared_context 'with a table structure for converting a table to a list pa
let(:table_identifier) { "#{connection.current_schema}.#{table_name}" }
let(:partitioning_column) { :partition_number }
let(:partitioning_default) { 1 }
+ let(:single_partitioning_value) { 1 }
+ let(:multiple_partitioning_values) { [1, 2, 3, 4] }
let(:referenced_table_name) { '_test_referenced_table' }
let(:other_referenced_table_name) { '_test_other_referenced_table' }
let(:referencing_table_name) { '_test_referencing_table' }
diff --git a/spec/support/shared_contexts/lib/gitlab/sidekiq_logging/structured_logger_shared_context.rb b/spec/support/shared_contexts/lib/gitlab/sidekiq_logging/structured_logger_shared_context.rb
index 69c20a00c5a..060976eba2d 100644
--- a/spec/support/shared_contexts/lib/gitlab/sidekiq_logging/structured_logger_shared_context.rb
+++ b/spec/support/shared_contexts/lib/gitlab/sidekiq_logging/structured_logger_shared_context.rb
@@ -93,8 +93,6 @@ RSpec.shared_context 'structured_logger' do
end
before do
- allow(Sidekiq).to receive(:logger).and_return(logger)
-
allow(subject).to receive(:current_time).and_return(timestamp.to_f)
allow(Process).to receive(:clock_gettime).with(Process::CLOCK_REALTIME, :float_second)
@@ -103,7 +101,7 @@ RSpec.shared_context 'structured_logger' do
.and_return(clock_thread_cputime_start, clock_thread_cputime_end)
end
- subject { described_class.new }
+ subject { described_class.new(logger) }
def call_subject(job, queue)
# This structured logger strongly depends on execution of `InstrumentationLogger`
diff --git a/spec/support/shared_contexts/lib/gitlab/sidekiq_middleware/server_metrics_shared_context.rb b/spec/support/shared_contexts/lib/gitlab/sidekiq_middleware/server_metrics_shared_context.rb
index 85ee3ed4183..d541dee438e 100644
--- a/spec/support/shared_contexts/lib/gitlab/sidekiq_middleware/server_metrics_shared_context.rb
+++ b/spec/support/shared_contexts/lib/gitlab/sidekiq_middleware/server_metrics_shared_context.rb
@@ -55,6 +55,7 @@ RSpec.shared_context 'server metrics with mocked prometheus' do
allow(Gitlab::Metrics).to receive(:gauge).with(:sidekiq_mem_total_bytes, anything, {}, :all).and_return(sidekiq_mem_total_bytes)
allow(concurrency_metric).to receive(:set)
+ allow(completion_seconds_metric).to receive(:get)
end
end
diff --git a/spec/support/shared_examples/analytics/cycle_analytics/parentable_examples.rb b/spec/support/shared_examples/analytics/cycle_analytics/parentable_examples.rb
index 5fd0e685c67..a6f028a5a04 100644
--- a/spec/support/shared_examples/analytics/cycle_analytics/parentable_examples.rb
+++ b/spec/support/shared_examples/analytics/cycle_analytics/parentable_examples.rb
@@ -14,15 +14,14 @@ RSpec.shared_examples 'value stream analytics namespace models' do
end
end
- context 'when Namespace is given' do
- it 'fails' do
- namespace = create(:namespace)
+ context 'when personal namespace is given' do
+ it 'is valid' do
+ namespace = create(:namespace, owner: create(:user))
model = build(factory_name, namespace: namespace)
- expect(model).to be_invalid
-
- error_message = s_('CycleAnalytics|the assigned object is not supported')
- expect(model.errors.messages_for(:namespace)).to eq([error_message])
+ expect(model).to be_valid
+ expect(model.save).to be(true)
+ expect(model.namespace).to eq(namespace)
end
end
end
diff --git a/spec/support/shared_examples/ci/runner_with_status_scope_shared_examples.rb b/spec/support/shared_examples/ci/runner_with_status_scope_shared_examples.rb
new file mode 100644
index 00000000000..510721d66b2
--- /dev/null
+++ b/spec/support/shared_examples/ci/runner_with_status_scope_shared_examples.rb
@@ -0,0 +1,29 @@
+# frozen_string_literal: true
+
+RSpec.shared_examples 'runner with status scope' do
+ describe '.with_status' do
+ subject(:scope) { described_class.with_status(status) }
+
+ described_class::AVAILABLE_STATUSES.each do |status|
+ context "with #{status} status" do
+ let(:status) { status }
+
+ it "calls corresponding :#{status} scope" do
+ expect(described_class).to receive(status.to_sym).and_call_original
+
+ scope
+ end
+ end
+ end
+
+ context 'with invalid status' do
+ let(:status) { :invalid_status }
+
+ it 'returns all records' do
+ expect(described_class).to receive(:all).at_least(:once).and_call_original
+
+ expect { scope }.not_to raise_error
+ end
+ end
+ end
+end
diff --git a/spec/support/shared_examples/controllers/base_action_controller_shared_examples.rb b/spec/support/shared_examples/controllers/base_action_controller_shared_examples.rb
index 2eab533ef7f..97748fe9e89 100644
--- a/spec/support/shared_examples/controllers/base_action_controller_shared_examples.rb
+++ b/spec/support/shared_examples/controllers/base_action_controller_shared_examples.rb
@@ -53,7 +53,7 @@ RSpec.shared_examples 'Base action controller' do
skip: 'https://gitlab.com/gitlab-org/gitlab/-/issues/424334' do
before do
stub_rails_env('development')
- stub_feature_flags(vite: true)
+ allow(ViteHelper).to receive(:vite_enabled?).and_return(true)
end
it 'adds vite csp' do
@@ -65,7 +65,7 @@ RSpec.shared_examples 'Base action controller' do
context 'when vite disabled' do
before do
- stub_feature_flags(vite: false)
+ allow(ViteHelper).to receive(:vite_enabled?).and_return(false)
end
it "doesn't add vite csp" do
diff --git a/spec/support/shared_examples/controllers/githubish_import_controller_shared_examples.rb b/spec/support/shared_examples/controllers/githubish_import_controller_shared_examples.rb
index c921da10347..94208e29d77 100644
--- a/spec/support/shared_examples/controllers/githubish_import_controller_shared_examples.rb
+++ b/spec/support/shared_examples/controllers/githubish_import_controller_shared_examples.rb
@@ -125,9 +125,9 @@ RSpec.shared_examples 'a GitHub-ish import controller: GET status' do
group_a.add_owner(user)
create(:project, :import_started, import_type: provider, namespace: user.namespace)
- control_count = ActiveRecord::QueryRecorder.new(skip_cached: false) do
+ control = ActiveRecord::QueryRecorder.new(skip_cached: false) do
get :status, format: :json
- end.count
+ end
stub_client(repos: [repo, org_repo], orgs: [])
group_b = create(:group)
@@ -135,7 +135,7 @@ RSpec.shared_examples 'a GitHub-ish import controller: GET status' do
create(:project, :import_started, import_type: provider, namespace: user.namespace)
expect { get :status, format: :json }
- .not_to exceed_all_query_limit(control_count)
+ .not_to exceed_all_query_limit(control)
end
context 'when user is not allowed to import projects' do
diff --git a/spec/support/shared_examples/controllers/issuables_list_metadata_shared_examples.rb b/spec/support/shared_examples/controllers/issuables_list_metadata_shared_examples.rb
index 446bc4cd92f..461dcf2fcb6 100644
--- a/spec/support/shared_examples/controllers/issuables_list_metadata_shared_examples.rb
+++ b/spec/support/shared_examples/controllers/issuables_list_metadata_shared_examples.rb
@@ -65,7 +65,7 @@ RSpec.shared_examples 'issuables list meta-data' do |issuable_type, action = nil
issuable.update!(source_project: fork_project(project))
end
- expect { get_action(action, project) }.not_to exceed_query_limit(control.count)
+ expect { get_action(action, project) }.not_to exceed_query_limit(control)
end
describe "when given empty collection" do
diff --git a/spec/support/shared_examples/controllers/snippet_shared_examples.rb b/spec/support/shared_examples/controllers/snippet_shared_examples.rb
index f49cc979368..bf8183525a9 100644
--- a/spec/support/shared_examples/controllers/snippet_shared_examples.rb
+++ b/spec/support/shared_examples/controllers/snippet_shared_examples.rb
@@ -17,12 +17,12 @@ RSpec.shared_examples 'snippets views' do
project = create(:project, namespace: user.namespace)
create(:project_snippet, project: project, author: user)
- control_count = ActiveRecord::QueryRecorder.new { get(:index, params: params) }.count
+ control = ActiveRecord::QueryRecorder.new { get(:index, params: params) }
project = create(:project, namespace: user.namespace)
create(:project_snippet, project: project, author: user)
- expect { get(:index, params: params) }.not_to exceed_query_limit(control_count)
+ expect { get(:index, params: params) }.not_to exceed_query_limit(control)
end
end
end
diff --git a/spec/support/shared_examples/controllers/variables_shared_examples.rb b/spec/support/shared_examples/controllers/variables_shared_examples.rb
index d979683cce7..c807ffaba6f 100644
--- a/spec/support/shared_examples/controllers/variables_shared_examples.rb
+++ b/spec/support/shared_examples/controllers/variables_shared_examples.rb
@@ -82,7 +82,7 @@ RSpec.shared_examples 'PATCH #update updates variables' do
context 'with valid new variable parameters' do
let(:variables_attributes) do
[
- variable_attributes.merge(secret_value: 'other_value'),
+ variable_attributes.merge(secret_value: 'other_value', description: 'other_description'),
new_variable_attributes
]
end
@@ -94,6 +94,7 @@ RSpec.shared_examples 'PATCH #update updates variables' do
variable.reload
expect(variable.value).to eq('other_value')
+ expect(variable.description).to eq('other_description')
expect(variable.raw?).not_to be(old_raw)
end
diff --git a/spec/support/shared_examples/features/inviting_groups_shared_examples.rb b/spec/support/shared_examples/features/inviting_groups_shared_examples.rb
index 4921676a065..d21e69b72e1 100644
--- a/spec/support/shared_examples/features/inviting_groups_shared_examples.rb
+++ b/spec/support/shared_examples/features/inviting_groups_shared_examples.rb
@@ -9,7 +9,7 @@ RSpec.shared_examples 'inviting groups search results' do
before do
sign_in(admin)
- gitlab_enable_admin_mode_sign_in(admin)
+ enable_admin_mode!(admin)
end
it 'shows groups where the admin has no direct membership' do
diff --git a/spec/support/shared_examples/features/variable_list_drawer_shared_examples.rb b/spec/support/shared_examples/features/variable_list_drawer_shared_examples.rb
index 04e73cfeee7..1fb4c42ee16 100644
--- a/spec/support/shared_examples/features/variable_list_drawer_shared_examples.rb
+++ b/spec/support/shared_examples/features/variable_list_drawer_shared_examples.rb
@@ -99,7 +99,7 @@ RSpec.shared_examples 'variable list drawer' do
toggle_protected
toggle_masked
toggle_expanded
- click_button('Edit variable')
+ find_by_testid('ci-variable-confirm-button').click
wait_for_requests
diff --git a/spec/support/shared_examples/features/work_items_shared_examples.rb b/spec/support/shared_examples/features/work_items_shared_examples.rb
index 3dfd7604914..0f35681ca7d 100644
--- a/spec/support/shared_examples/features/work_items_shared_examples.rb
+++ b/spec/support/shared_examples/features/work_items_shared_examples.rb
@@ -1,16 +1,45 @@
# frozen_string_literal: true
+RSpec.shared_context 'with work_items_mvc_2' do |flag|
+ before do
+ stub_feature_flags(work_items_mvc_2: flag)
+
+ page.refresh
+ wait_for_all_requests
+ end
+end
+
RSpec.shared_examples 'work items title' do
let(:title_selector) { '[data-testid="work-item-title"]' }
+ let(:title_with_edit_selector) { '[data-testid="work-item-title-with-edit"]' }
- it 'successfully shows and changes the title of the work item' do
- expect(work_item.reload.title).to eq work_item.title
+ context 'when the work_items_mvc_2 FF is disabled' do
+ include_context 'with work_items_mvc_2', false
- find(title_selector).set("Work item title")
- find(title_selector).native.send_keys(:return)
- wait_for_requests
+ it 'successfully shows and changes the title of the work item' do
+ expect(work_item.reload.title).to eq work_item.title
+
+ find(title_selector).set("Work item title")
+ find(title_selector).native.send_keys(:return)
+ wait_for_requests
+
+ expect(work_item.reload.title).to eq 'Work item title'
+ end
+ end
+
+ context 'when the work_items_mvc_2 FF is enabled' do
+ include_context 'with work_items_mvc_2', true
+
+ it 'successfully shows and changes the title of the work item' do
+ expect(work_item.reload.title).to eq work_item.title
+
+ click_button 'Edit', match: :first
+ find(title_with_edit_selector).set("Work item title")
+ send_keys([:command, :enter])
+ wait_for_requests
- expect(work_item.reload.title).to eq 'Work item title'
+ expect(work_item.reload.title).to eq 'Work item title'
+ end
end
end
@@ -299,54 +328,62 @@ RSpec.shared_examples 'work items labels' do
end
RSpec.shared_examples 'work items description' do
- it 'shows GFM autocomplete', :aggregate_failures do
- click_button "Edit description"
- fill_in _('Description'), with: "@#{user.username}"
+ context 'for work_items_mvc_2 FF' do
+ [true, false].each do |work_items_mvc_2_flag| # rubocop:disable RSpec/UselessDynamicDefinition -- check it for both off and on
+ let(:edit_button) { work_items_mvc_2_flag ? 'Edit' : 'Edit description' }
- page.within('.atwho-container') do
- expect(page).to have_text(user.name)
- end
- end
+ include_context 'with work_items_mvc_2', work_items_mvc_2_flag
- it 'autocompletes available quick actions', :aggregate_failures do
- click_button "Edit description"
- fill_in _('Description'), with: '/'
+ it 'shows GFM autocomplete', :aggregate_failures do
+ click_button edit_button, match: :first
+ fill_in _('Description'), with: "@#{user.username}"
- page.within('#at-view-commands') do
- expect(page).to have_text("title")
- expect(page).to have_text("shrug")
- expect(page).to have_text("tableflip")
- expect(page).to have_text("close")
- expect(page).to have_text("cc")
- end
- end
+ page.within('.atwho-container') do
+ expect(page).to have_text(user.name)
+ end
+ end
- context 'on conflict' do
- let_it_be(:other_user) { create(:user) }
- let(:expected_warning) { 'Someone edited the description at the same time you did.' }
+ it 'autocompletes available quick actions', :aggregate_failures do
+ click_button edit_button, match: :first
+ fill_in _('Description'), with: '/'
- before do
- project.add_developer(other_user)
- end
+ page.within('#at-view-commands') do
+ expect(page).to have_text("title")
+ expect(page).to have_text("shrug")
+ expect(page).to have_text("tableflip")
+ expect(page).to have_text("close")
+ expect(page).to have_text("cc")
+ end
+ end
- it 'shows conflict message when description changes', :aggregate_failures do
- click_button "Edit description"
+ context 'on conflict' do
+ let_it_be(:other_user) { create(:user) }
+ let(:expected_warning) { 'Someone edited the description at the same time you did.' }
- ::WorkItems::UpdateService.new(
- container: work_item.project,
- current_user: other_user,
- params: { description: "oh no!" }
- ).execute(work_item)
+ before do
+ project.add_developer(other_user)
+ end
- wait_for_requests
+ it 'shows conflict message when description changes', :aggregate_failures do
+ click_button edit_button, match: :first
+
+ ::WorkItems::UpdateService.new(
+ container: work_item.project,
+ current_user: other_user,
+ params: { description: "oh no!" }
+ ).execute(work_item)
+
+ wait_for_requests
- fill_in _('Description'), with: 'oh yeah!'
+ fill_in _('Description'), with: 'oh yeah!'
- expect(page).to have_text(expected_warning)
+ expect(page).to have_text(expected_warning)
- click_button s_('WorkItem|Save and overwrite')
+ click_button s_('WorkItem|Save and overwrite')
- expect(page.find('[data-testid="work-item-description"]')).to have_text("oh yeah!")
+ expect(page.find('[data-testid="work-item-description"]')).to have_text("oh yeah!")
+ end
+ end
end
end
end
@@ -368,17 +405,61 @@ RSpec.shared_examples 'work items invite members' do
end
RSpec.shared_examples 'work items milestone' do
- it 'searches and sets or removes milestone for the work item' do
- click_button s_('WorkItem|Add to milestone')
- send_keys "\"#{milestone.title}\""
- select_listbox_item(milestone.title, exact_text: true)
+ context 'on work_items_mvc_2 FF off' do
+ include_context 'with work_items_mvc_2', false
+
+ it 'searches and sets or removes milestone for the work item' do
+ click_button s_('WorkItem|Add to milestone')
+ send_keys "\"#{milestone.title}\""
+ select_listbox_item(milestone.title, exact_text: true)
+
+ expect(page).to have_button(milestone.title)
+
+ click_button milestone.title
+ select_listbox_item(s_('WorkItem|No milestone'), exact_text: true)
+
+ expect(page).to have_button(s_('WorkItem|Add to milestone'))
+ end
+ end
+
+ context 'on work_items_mvc_2 FF on' do
+ let(:work_item_milestone_selector) { '[data-testid="work-item-milestone-with-edit"]' }
+
+ include_context 'with work_items_mvc_2', true
- expect(page).to have_button(milestone.title)
+ it 'passes axe automated accessibility testing in closed state' do
+ expect(page).to be_axe_clean.within(work_item_milestone_selector)
+ end
+
+ context 'when edit is clicked' do
+ it 'selects and updates the right milestone', :aggregate_failures do
+ find_and_click_edit(work_item_milestone_selector)
+
+ select_listbox_item(milestones[10].title)
+
+ wait_for_requests
+ within(work_item_milestone_selector) do
+ expect(page).to have_text(milestones[10].title)
+ end
+
+ find_and_click_edit(work_item_milestone_selector)
- click_button milestone.title
- select_listbox_item(s_('WorkItem|No milestone'), exact_text: true)
+ find_and_click_clear(work_item_milestone_selector)
- expect(page).to have_button(s_('WorkItem|Add to milestone'))
+ expect(find(work_item_milestone_selector)).to have_content('None')
+ end
+
+ it 'searches and sets or removes milestone for the work item' do
+ find_and_click_edit(work_item_milestone_selector)
+ within(work_item_milestone_selector) do
+ send_keys "\"#{milestones[11].title}\""
+ wait_for_requests
+
+ select_listbox_item(milestones[11].title)
+ expect(page).to have_text(milestones[11].title)
+ end
+ end
+ end
end
end
@@ -522,3 +603,101 @@ RSpec.shared_examples 'work items parent' do |type|
expect(find_by_testid('work-item-parent-none')).to have_text('None')
end
end
+
+def find_and_click_edit(selector)
+ within(selector) do
+ click_button 'Edit'
+ end
+end
+
+def find_and_click_clear(selector)
+ within(selector) do
+ click_button 'Clear'
+ end
+end
+
+RSpec.shared_examples 'work items iteration' do
+ let(:work_item_iteration_selector) { '[data-testid="work-item-iteration-with-edit"]' }
+ let_it_be(:iteration_cadence) { create(:iterations_cadence, group: group, active: true) }
+ let_it_be(:iteration) do
+ create(
+ :iteration,
+ iterations_cadence: iteration_cadence,
+ group: group,
+ start_date: 1.day.from_now,
+ due_date: 2.days.from_now
+ )
+ end
+
+ let_it_be(:iteration2) do
+ create(
+ :iteration,
+ iterations_cadence: iteration_cadence,
+ group: group,
+ start_date: 2.days.ago,
+ due_date: 1.day.ago,
+ state: 'closed',
+ skip_future_date_validation: true
+ )
+ end
+
+ include_context 'with work_items_mvc_2', true
+
+ context 'for accessibility' do
+ it 'has the work item iteration with edit' do
+ expect(page).to have_selector(work_item_iteration_selector)
+ end
+
+ it 'passes axe automated accessibility testing in closed state' do
+ expect(page).to be_axe_clean.within(work_item_iteration_selector)
+ end
+
+ # TODO, add test for automated accessibility after it is fixed in GlCollapsibleListBox
+ # Invalid ARIA attribute value: aria-owns="listbox-##" when searchable
+ # it 'passes axe automated accessibility testing in open state' do
+ # within(work_item_iteration) do
+ # click_button _('Edit')
+ # wait_for_requests
+
+ # expect(page).to be_axe_clean.within(work_item_iteration)
+ # end
+ # end
+ end
+
+ context 'when edit is clicked' do
+ it 'selects and updates the right iteration', :aggregate_failures do
+ find_and_click_edit(work_item_iteration_selector)
+
+ within(work_item_iteration_selector) do
+ expect(page).to have_text(iteration_cadence.title)
+ expect(page).to have_text(iteration.period)
+ end
+
+ select_listbox_item(iteration.period)
+
+ wait_for_requests
+
+ within(work_item_iteration_selector) do
+ expect(page).to have_text(iteration_cadence.title)
+ expect(page).to have_text(iteration.period)
+ end
+
+ find_and_click_edit(work_item_iteration_selector)
+
+ find_and_click_clear(work_item_iteration_selector)
+
+ expect(find(work_item_iteration_selector)).to have_content('None')
+ end
+
+ it 'searches and sets or removes iteration for the work item' do
+ find_and_click_edit(work_item_iteration_selector)
+ within(work_item_iteration_selector) do
+ send_keys(iteration.title)
+ wait_for_requests
+
+ select_listbox_item(iteration.period)
+ expect(page).to have_text(iteration.period)
+ end
+ end
+ end
+end
diff --git a/spec/support/shared_examples/lib/gitlab/import_export/import_failure_service_shared_examples.rb b/spec/support/shared_examples/lib/gitlab/import_export/import_failure_service_shared_examples.rb
index 67afd2035c4..afb1bfb6dc9 100644
--- a/spec/support/shared_examples/lib/gitlab/import_export/import_failure_service_shared_examples.rb
+++ b/spec/support/shared_examples/lib/gitlab/import_export/import_failure_service_shared_examples.rb
@@ -34,6 +34,7 @@ RSpec.shared_examples 'log import failure' do |importable_column|
expect(import_failure.exception_message).to eq(standard_error_message)
expect(import_failure.correlation_id_value).to eq(correlation_id)
expect(import_failure.retry_count).to eq(retry_count)
+ expect(import_failure.external_identifiers).to eq("iid" => 1234)
end
end
end
diff --git a/spec/support/shared_examples/migrations/add_work_item_widget_shared_examples.rb b/spec/support/shared_examples/migrations/add_work_item_widget_shared_examples.rb
index 37c338a7712..5681dbc158d 100644
--- a/spec/support/shared_examples/migrations/add_work_item_widget_shared_examples.rb
+++ b/spec/support/shared_examples/migrations/add_work_item_widget_shared_examples.rb
@@ -1,9 +1,9 @@
# frozen_string_literal: true
-RSpec.shared_examples 'migration that adds widget to work items definitions' do |widget_name:|
+RSpec.shared_examples 'migration that adds widget to work items definitions' do |widget_name:, work_item_types:|
let(:migration) { described_class.new }
let(:work_item_definitions) { table(:work_item_widget_definitions) }
- let(:work_item_type_count) { 7 }
+ let(:work_item_type_count) { work_item_types.size }
describe '#up' do
it "creates widget definition in all types" do
@@ -14,11 +14,13 @@ RSpec.shared_examples 'migration that adds widget to work items definitions' do
end
it 'logs a warning if the type is missing' do
+ type_name = work_item_types.first
+
allow(described_class::WorkItemType).to receive(:find_by_name_and_namespace_id).and_call_original
allow(described_class::WorkItemType).to receive(:find_by_name_and_namespace_id)
- .with('Issue', nil).and_return(nil)
+ .with(type_name, nil).and_return(nil)
- expect(Gitlab::AppLogger).to receive(:warn).with('type Issue is missing, not adding widget')
+ expect(Gitlab::AppLogger).to receive(:warn).with("type #{type_name} is missing, not adding widget")
migrate!
end
end
diff --git a/spec/support/shared_examples/models/concerns/integrations/base_slack_notification_shared_examples.rb b/spec/support/shared_examples/models/concerns/integrations/base_slack_notification_shared_examples.rb
index 2dad35dc46e..d05c29c39c3 100644
--- a/spec/support/shared_examples/models/concerns/integrations/base_slack_notification_shared_examples.rb
+++ b/spec/support/shared_examples/models/concerns/integrations/base_slack_notification_shared_examples.rb
@@ -111,7 +111,7 @@ RSpec.shared_examples Integrations::BaseSlackNotification do |factory:|
end
context 'for tag_push notification' do
- let(:oldrev) { Gitlab::Git::BLANK_SHA }
+ let(:oldrev) { Gitlab::Git::SHA1_BLANK_SHA }
let(:newrev) { '8a2a6eb295bb170b34c24c76c49ed0e9b2eaf34b' } # gitlab-test: git rev-parse refs/tags/v1.1.0
let(:ref) { 'refs/tags/v1.1.0' }
let(:data) do
diff --git a/spec/support/shared_examples/models/concerns/integrations/slack_mattermost_notifier_shared_examples.rb b/spec/support/shared_examples/models/concerns/integrations/slack_mattermost_notifier_shared_examples.rb
index 2985763426f..9e5b5ecfb48 100644
--- a/spec/support/shared_examples/models/concerns/integrations/slack_mattermost_notifier_shared_examples.rb
+++ b/spec/support/shared_examples/models/concerns/integrations/slack_mattermost_notifier_shared_examples.rb
@@ -143,7 +143,7 @@ RSpec.shared_examples Integrations::SlackMattermostNotifier do |integration_name
end
context 'tag_push events' do
- let(:oldrev) { Gitlab::Git::BLANK_SHA }
+ let(:oldrev) { Gitlab::Git::SHA1_BLANK_SHA }
let(:newrev) { '8a2a6eb295bb170b34c24c76c49ed0e9b2eaf34b' } # gitlab-test: git rev-parse refs/tags/v1.1.0
let(:ref) { 'refs/tags/v1.1.0' }
let(:data) { Git::TagHooksService.new(project, user, change: { oldrev: oldrev, newrev: newrev, ref: ref }).send(:push_data) }
diff --git a/spec/support/shared_examples/models/concerns/repository_storage_movable_shared_examples.rb b/spec/support/shared_examples/models/concerns/repository_storage_movable_shared_examples.rb
index 993c94e2695..ff1d1f66ac4 100644
--- a/spec/support/shared_examples/models/concerns/repository_storage_movable_shared_examples.rb
+++ b/spec/support/shared_examples/models/concerns/repository_storage_movable_shared_examples.rb
@@ -76,7 +76,7 @@ RSpec.shared_examples 'handles repository moves' do
context 'and transitions to scheduled' do
it 'triggers the corresponding repository storage worker' do
- expect(repository_storage_worker).to receive(:perform_async).with(container.id, 'test_second_storage', storage_move.id)
+ expect(repository_storage_worker).to receive(:perform_async).with(storage_move.id)
storage_move.schedule!
diff --git a/spec/support/shared_examples/models/database_event_tracking_shared_examples.rb b/spec/support/shared_examples/models/database_event_tracking_shared_examples.rb
deleted file mode 100644
index 56b36b3ea07..00000000000
--- a/spec/support/shared_examples/models/database_event_tracking_shared_examples.rb
+++ /dev/null
@@ -1,49 +0,0 @@
-# frozen_string_literal: true
-
-RSpec.shared_examples 'database events tracking' do
- describe 'events tracking' do
- # required definitions:
- # :record, :update_params
- #
- # other available attributes:
- # :project, :namespace
-
- let(:user) { nil }
- let(:category) { described_class.to_s }
- let(:label) { described_class.table_name }
- let(:action) { "database_event_#{property}" }
- let(:record_tracked_attributes) { record.attributes.slice(*described_class::SNOWPLOW_ATTRIBUTES.map(&:to_s)) }
- let(:base_extra) { record_tracked_attributes.merge(project: try(:project), namespace: try(:namespace)) }
-
- before do
- allow(Gitlab::Tracking).to receive(:database_event).and_call_original
- end
-
- describe '#create' do
- it_behaves_like 'Snowplow event tracking', overrides: { tracking_method: :database_event } do
- subject(:create_record) { record }
-
- let(:extra) { base_extra }
- let(:property) { 'create' }
- end
- end
-
- describe '#update', :freeze_time do
- it_behaves_like 'Snowplow event tracking', overrides: { tracking_method: :database_event } do
- subject(:update_record) { record.update!(update_params) }
-
- let(:extra) { base_extra.merge(update_params.stringify_keys) }
- let(:property) { 'update' }
- end
- end
-
- describe '#destroy' do
- it_behaves_like 'Snowplow event tracking', overrides: { tracking_method: :database_event } do
- subject(:delete_record) { record.destroy! }
-
- let(:extra) { base_extra }
- let(:property) { 'destroy' }
- end
- end
- end
-end
diff --git a/spec/support/shared_examples/models/member_shared_examples.rb b/spec/support/shared_examples/models/member_shared_examples.rb
index 731500c4510..01d6642e814 100644
--- a/spec/support/shared_examples/models/member_shared_examples.rb
+++ b/spec/support/shared_examples/models/member_shared_examples.rb
@@ -54,6 +54,25 @@ RSpec.shared_examples 'inherited access level as a member of entity' do
expect { non_member.update!(access_level: Gitlab::Access::GUEST) }
.to change { non_member.reload.access_level }
end
+
+ context 'when access request to entity is pending' do
+ before do
+ parent_entity.members.where(user: user).update!(requested_at: Time.current)
+ end
+
+ it 'is allowed to be a reporter of the entity' do
+ entity.add_reporter(user)
+
+ expect(member.access_level).to eq(Gitlab::Access::REPORTER)
+ end
+
+ it 'is allowed to change to be a guest of the entity' do
+ entity.add_maintainer(user)
+
+ expect { member.update!(access_level: Gitlab::Access::GUEST) }
+ .to change { member.reload.access_level }.from(Gitlab::Access::MAINTAINER).to(Gitlab::Access::GUEST)
+ end
+ end
end
end
@@ -63,10 +82,9 @@ RSpec.shared_examples '#valid_level_roles' do |entity_name|
let(:entity) { create(entity_name) } # rubocop:disable Rails/SaveBang
let(:entity_member) { create("#{entity_name}_member", :developer, source: entity, user: member_user) }
let(:presenter) { described_class.new(entity_member, current_user: member_user) }
+ let(:all_permissible_roles) { entity_member.class.permissible_access_level_roles(member_user, entity) }
context 'when no parent member is present' do
- let(:all_permissible_roles) { entity_member.class.permissible_access_level_roles(member_user, entity) }
-
it 'returns all permissible roles' do
expect(presenter.valid_level_roles).to eq(all_permissible_roles)
end
@@ -80,6 +98,16 @@ RSpec.shared_examples '#valid_level_roles' do |entity_name|
it 'returns higher roles when a parent member is present' do
expect(presenter.valid_level_roles).to eq(expected_roles)
end
+
+ context 'when access request to parent is pending' do
+ before do
+ group.members.with_user(member_user).update!(requested_at: Time.current)
+ end
+
+ it 'returns all permissible roles' do
+ expect(presenter.valid_level_roles).to eq(all_permissible_roles)
+ end
+ end
end
end
@@ -108,7 +136,7 @@ RSpec.shared_examples_for "member creation" do
it 'does not update the member' do
member = described_class.add_member(source, project_bot, :maintainer, current_user: user)
- expect(source.users.reload).to include(project_bot)
+ expect(source.reload).to have_user(project_bot)
expect(member).to be_persisted
expect(member.access_level).to eq(Gitlab::Access::DEVELOPER)
expect(member.errors.full_messages).to include(/not authorized to update member/)
@@ -119,7 +147,7 @@ RSpec.shared_examples_for "member creation" do
it 'adds the member' do
member = described_class.add_member(source, project_bot, :maintainer, current_user: user)
- expect(source.users.reload).to include(project_bot)
+ expect(source.reload).to have_user(project_bot)
expect(member).to be_persisted
end
end
@@ -130,7 +158,7 @@ RSpec.shared_examples_for "member creation" do
member = described_class.add_member(source, user, :maintainer, current_user: admin)
expect(member).to be_persisted
- expect(source.users.reload).to include(user)
+ expect(source.reload).to have_user(user)
expect(member.created_by).to eq(admin)
end
end
@@ -140,7 +168,7 @@ RSpec.shared_examples_for "member creation" do
member = described_class.add_member(source, user, :maintainer, current_user: admin)
expect(member).not_to be_persisted
- expect(source.users.reload).not_to include(user)
+ expect(source).not_to have_user(user)
expect(member.errors.full_messages).to include(/not authorized to create member/)
end
end
@@ -153,52 +181,52 @@ RSpec.shared_examples_for "member creation" do
described_class.access_levels.each do |sym_key, int_access_level|
it "accepts the :#{sym_key} symbol as access level", :aggregate_failures do
- expect(source.users).not_to include(user)
+ expect(source).not_to have_user(user)
member = described_class.add_member(source, user.id, sym_key)
expect(member.access_level).to eq(int_access_level)
- expect(source.users.reload).to include(user)
+ expect(source.reload).to have_user(user)
end
it "accepts the #{int_access_level} integer as access level", :aggregate_failures do
- expect(source.users).not_to include(user)
+ expect(source).not_to have_user(user)
member = described_class.add_member(source, user.id, int_access_level)
expect(member.access_level).to eq(int_access_level)
- expect(source.users.reload).to include(user)
+ expect(source.reload).to have_user(user)
end
end
context 'with no current_user' do
context 'when called with a known user id' do
it 'adds the user as a member' do
- expect(source.users).not_to include(user)
+ expect(source).not_to have_user(user)
described_class.add_member(source, user.id, :maintainer)
- expect(source.users.reload).to include(user)
+ expect(source.reload).to have_user(user)
end
end
context 'when called with an unknown user id' do
it 'does not add the user as a member' do
- expect(source.users).not_to include(user)
+ expect(source).not_to have_user(user)
described_class.add_member(source, non_existing_record_id, :maintainer)
- expect(source.users.reload).not_to include(user)
+ expect(source.reload).not_to have_user(user)
end
end
context 'when called with a user object' do
it 'adds the user as a member' do
- expect(source.users).not_to include(user)
+ expect(source).not_to have_user(user)
described_class.add_member(source, user, :maintainer)
- expect(source.users.reload).to include(user)
+ expect(source.reload).to have_user(user)
end
end
@@ -208,29 +236,29 @@ RSpec.shared_examples_for "member creation" do
end
it 'adds the requester as a member', :aggregate_failures do
- expect(source.users).not_to include(user)
+ expect(source.reload).not_to have_user(user)
expect(source.requesters.exists?(user_id: user)).to eq(true)
described_class.add_member(source, user, :maintainer)
- expect(source.users.reload).to include(user)
- expect(source.requesters.reload.exists?(user_id: user)).to eq(false)
+ expect(source.reload).to have_user(user)
+ expect(source.requesters.exists?(user_id: user)).to eq(false)
end
end
context 'when called with a known user email' do
it 'adds the user as a member' do
- expect(source.users).not_to include(user)
+ expect(source).not_to have_user(user)
described_class.add_member(source, user.email, :maintainer)
- expect(source.users.reload).to include(user)
+ expect(source.reload).to have_user(user)
end
end
context 'when called with an unknown user email' do
it 'creates an invited member' do
- expect(source.users).not_to include(user)
+ expect(source).not_to have_user(user)
described_class.add_member(source, 'user@example.com', :maintainer)
@@ -245,18 +273,18 @@ RSpec.shared_examples_for "member creation" do
described_class.add_member(source, email_starting_with_number, :maintainer)
expect(source.members.invite.pluck(:invite_email)).to include(email_starting_with_number)
- expect(source.users.reload).not_to include(user)
+ expect(source.reload).not_to have_user(user)
end
end
end
context 'when current_user can update member', :enable_admin_mode do
it 'creates the member' do
- expect(source.users).not_to include(user)
+ expect(source).not_to have_user(user)
described_class.add_member(source, user, :maintainer, current_user: admin)
- expect(source.users.reload).to include(user)
+ expect(source.reload).to have_user(user)
end
context 'when called with a requester user object' do
@@ -265,12 +293,12 @@ RSpec.shared_examples_for "member creation" do
end
it 'adds the requester as a member', :aggregate_failures do
- expect(source.users).not_to include(user)
+ expect(source).not_to have_user(user)
expect(source.requesters.exists?(user_id: user)).to be_truthy
described_class.add_member(source, user, :maintainer, current_user: admin)
- expect(source.users.reload).to include(user)
+ expect(source.reload).to have_user(user)
expect(source.requesters.reload.exists?(user_id: user)).to be_falsy
end
end
@@ -278,11 +306,11 @@ RSpec.shared_examples_for "member creation" do
context 'when current_user cannot update member' do
it 'does not create the member', :aggregate_failures do
- expect(source.users).not_to include(user)
+ expect(source).not_to have_user(user)
member = described_class.add_member(source, user, :maintainer, current_user: user)
- expect(source.users.reload).not_to include(user)
+ expect(source.reload).not_to have_user(user)
expect(member).not_to be_persisted
end
@@ -292,12 +320,12 @@ RSpec.shared_examples_for "member creation" do
end
it 'does not destroy the requester', :aggregate_failures do
- expect(source.users).not_to include(user)
+ expect(source).not_to have_user(user)
expect(source.requesters.exists?(user_id: user)).to be_truthy
described_class.add_member(source, user, :maintainer, current_user: user)
- expect(source.users.reload).not_to include(user)
+ expect(source.reload).not_to have_user(user)
expect(source.requesters.exists?(user_id: user)).to be_truthy
end
end
@@ -311,7 +339,7 @@ RSpec.shared_examples_for "member creation" do
context 'with no current_user' do
it 'updates the member' do
- expect(source.users).to include(user)
+ expect(source).to have_user(user)
described_class.add_member(source, user, :maintainer)
@@ -321,7 +349,7 @@ RSpec.shared_examples_for "member creation" do
context 'when current_user can update member', :enable_admin_mode do
it 'updates the member' do
- expect(source.users).to include(user)
+ expect(source).to have_user(user)
described_class.add_member(source, user, :maintainer, current_user: admin)
@@ -331,7 +359,7 @@ RSpec.shared_examples_for "member creation" do
context 'when current_user cannot update member' do
it 'does not update the member' do
- expect(source.users).to include(user)
+ expect(source).to have_user(user)
described_class.add_member(source, user, :maintainer, current_user: user)
diff --git a/spec/support/shared_examples/models/members_notifications_shared_example.rb b/spec/support/shared_examples/models/members_notifications_shared_example.rb
index 5c783b5cfa7..01212ed950d 100644
--- a/spec/support/shared_examples/models/members_notifications_shared_example.rb
+++ b/spec/support/shared_examples/models/members_notifications_shared_example.rb
@@ -9,32 +9,6 @@ RSpec.shared_examples 'members notifications' do |entity_type|
allow(member).to receive(:notification_service).and_return(notification_service)
end
- describe "#after_create" do
- let(:member) { build(:"#{entity_type}_member", "#{entity_type}": create(entity_type.to_s), user: user) }
-
- it "sends email to user" do
- expect(notification_service).to receive(:"new_#{entity_type}_member").with(member)
-
- member.save!
- end
- end
-
- describe "#after_update" do
- let(:member) { create(:"#{entity_type}_member", :developer) }
-
- it "calls NotificationService.update_#{entity_type}_member" do
- expect(notification_service).to receive(:"update_#{entity_type}_member").with(member)
-
- member.update_attribute(:access_level, Member::MAINTAINER)
- end
-
- it "does not send an email when the access level has not changed" do
- expect(notification_service).not_to receive(:"update_#{entity_type}_member")
-
- member.touch
- end
- end
-
describe '#after_commit' do
context 'on creation of a member requesting access' do
let(:member) do
@@ -52,27 +26,17 @@ RSpec.shared_examples 'members notifications' do |entity_type|
describe '#accept_request' do
let(:member) { create(:"#{entity_type}_member", :access_request) }
- it "calls NotificationService.new_#{entity_type}_member" do
- expect(notification_service).to receive(:"new_#{entity_type}_member").with(member)
+ it "calls NotificationService.new_member" do
+ expect(notification_service).to receive(:new_member).with(member)
member.accept_request(create(:user))
end
end
- describe "#accept_invite!" do
- let(:member) { create(:"#{entity_type}_member", :invited) }
-
- it "calls NotificationService.accept_#{entity_type}_invite" do
- expect(notification_service).to receive(:"accept_#{entity_type}_invite").with(member)
-
- member.accept_invite!(build(:user))
- end
- end
-
describe "#decline_invite!" do
let(:member) { create(:"#{entity_type}_member", :invited) }
- it "calls NotificationService.decline_#{entity_type}_invite" do
+ it "calls NotificationService.decline_invite" do
expect(notification_service).to receive(:decline_invite).with(member)
member.decline_invite!
diff --git a/spec/support/shared_examples/models/relative_positioning_shared_examples.rb b/spec/support/shared_examples/models/relative_positioning_shared_examples.rb
index 2b46c8c8fb9..692320d45d5 100644
--- a/spec/support/shared_examples/models/relative_positioning_shared_examples.rb
+++ b/spec/support/shared_examples/models/relative_positioning_shared_examples.rb
@@ -175,15 +175,15 @@ RSpec.shared_examples 'a class that supports relative positioning' do
create_items_with_positions(10..12)
a, b, c, d, e, f, *xs = create_items_with_positions([nil] * 10)
- baseline = ActiveRecord::QueryRecorder.new do
+ control = ActiveRecord::QueryRecorder.new do
described_class.move_nulls_to_end([a, b])
end
expect { described_class.move_nulls_to_end([c, d, e, f]) }
- .not_to exceed_query_limit(baseline)
+ .not_to exceed_query_limit(control)
expect { described_class.move_nulls_to_end(xs) }
- .not_to exceed_query_limit(baseline.count)
+ .not_to exceed_query_limit(control)
end
end
diff --git a/spec/support/shared_examples/quick_actions/merge_request/rebase_quick_action_shared_examples.rb b/spec/support/shared_examples/quick_actions/merge_request/rebase_quick_action_shared_examples.rb
index 92705fc1b4d..2c38c716736 100644
--- a/spec/support/shared_examples/quick_actions/merge_request/rebase_quick_action_shared_examples.rb
+++ b/spec/support/shared_examples/quick_actions/merge_request/rebase_quick_action_shared_examples.rb
@@ -59,7 +59,7 @@ RSpec.shared_examples 'rebase quick action' do
it 'tells the user a rebase is in progress' do
add_note('/rebase')
- expect(page).to have_content 'A rebase is already in progress.'
+ expect(page).to have_content Gitlab::QuickActions::MergeRequestActions::REBASE_FAILURE_REBASE_IN_PROGRESS
expect(page).not_to have_content 'Scheduled a rebase'
end
end
@@ -70,7 +70,7 @@ RSpec.shared_examples 'rebase quick action' do
it 'does not rebase the MR' do
add_note("/rebase")
- expect(page).to have_content 'This merge request cannot be rebased while there are conflicts.'
+ expect(page).to have_content Gitlab::QuickActions::MergeRequestActions::REBASE_FAILURE_UNMERGEABLE
end
end
@@ -89,7 +89,7 @@ RSpec.shared_examples 'rebase quick action' do
it 'does not rebase the MR' do
add_note("/rebase")
- expect(page).to have_content 'This merge request branch is protected from force push.'
+ expect(page).to have_content Gitlab::QuickActions::MergeRequestActions::REBASE_FAILURE_PROTECTED_BRANCH
end
end
end
diff --git a/spec/support/shared_examples/redis/multi_store_wrapper_shared_examples.rb b/spec/support/shared_examples/redis/multi_store_wrapper_shared_examples.rb
new file mode 100644
index 00000000000..a53af59f1e6
--- /dev/null
+++ b/spec/support/shared_examples/redis/multi_store_wrapper_shared_examples.rb
@@ -0,0 +1,74 @@
+# frozen_string_literal: true
+
+RSpec.shared_examples "multi_store_wrapper_shared_examples" do
+ let(:config_file_name) { instance_specific_config_file }
+ let_it_be(:pool_name) { "#{described_class.store_name.underscore}_multi_store" }
+
+ before do
+ allow(described_class).to receive(:config_file_name).and_return(Rails.root.join(config_file_name).to_s)
+ allow(described_class).to receive(:redis_yml_path).and_return('/dev/null')
+
+ clear_multistore_pool
+ end
+
+ after do
+ clear_multistore_pool
+ end
+
+ describe '.with' do
+ it 'yields a MultiStore' do
+ described_class.with do |conn|
+ expect(conn).to be_instance_of(Gitlab::Redis::MultiStore)
+ end
+ end
+
+ it 'borrows connection' do
+ described_class.with do |conn|
+ expect(Thread.current[conn.borrow_counter]).to eq(1)
+ end
+ end
+
+ context 'when running on single-threaded runtime' do
+ before do
+ allow(Gitlab::Runtime).to receive(:multi_threaded?).and_return(false)
+ end
+
+ it 'instantiates a connection pool with size 5' do
+ expect(ConnectionPool).to receive(:new).with(size: 5, name: pool_name).and_call_original
+
+ described_class.with { |_redis_shared_example| true }
+ end
+ end
+
+ context 'when running on multi-threaded runtime' do
+ before do
+ allow(Gitlab::Runtime).to receive(:multi_threaded?).and_return(true)
+ allow(Gitlab::Runtime).to receive(:max_threads).and_return(18)
+ end
+
+ it 'instantiates a connection pool with a size based on the concurrency of the worker' do
+ expect(ConnectionPool).to receive(:new).with(size: 18 + 5, name: pool_name).and_call_original
+
+ described_class.with { |_redis_shared_example| true }
+ end
+ end
+
+ context 'when there is no config at all' do
+ before do
+ # Undo top-level stub of config_file_name because we are testing that method now.
+ allow(described_class).to receive(:config_file_name).and_call_original
+ allow(described_class).to receive(:rails_root).and_return(rails_root)
+ end
+
+ it 'can run an empty block' do
+ expect { described_class.with { nil } }.not_to raise_error
+ end
+ end
+ end
+
+ def clear_multistore_pool
+ described_class.remove_instance_variable(:@multistore_pool)
+ rescue NameError
+ # raised if @pool was not set; ignore
+ end
+end
diff --git a/spec/support/shared_examples/redis/redis_new_instance_shared_examples.rb b/spec/support/shared_examples/redis/redis_new_instance_shared_examples.rb
index 4a3732efe13..9b774449379 100644
--- a/spec/support/shared_examples/redis/redis_new_instance_shared_examples.rb
+++ b/spec/support/shared_examples/redis/redis_new_instance_shared_examples.rb
@@ -15,6 +15,37 @@ RSpec.shared_examples "redis_new_instance_shared_examples" do |name, fallback_cl
it_behaves_like "redis_shared_examples"
+ describe '.pool' do
+ before do
+ allow(described_class).to receive(:config_file_name).and_call_original
+ allow(fallback_class).to receive(:params).and_return({})
+
+ clear_class_pool(described_class)
+ clear_class_pool(fallback_class)
+ end
+
+ after do
+ clear_class_pool(described_class)
+ clear_class_pool(fallback_class)
+ end
+
+ context 'when not using fallback config' do
+ it 'creates its own connection pool' do
+ expect(fallback_class.pool == described_class.pool).to eq(false)
+ end
+ end
+
+ context 'when using fallback config' do
+ before do
+ allow(described_class).to receive(:params).and_return({})
+ end
+
+ it 'uses the fallback class connection pool' do
+ expect(fallback_class.pool == described_class.pool).to eq(true)
+ end
+ end
+ end
+
describe '#fetch_config' do
subject { described_class.new('test').send(:fetch_config) }
@@ -81,4 +112,10 @@ RSpec.shared_examples "redis_new_instance_shared_examples" do |name, fallback_cl
end
end
end
+
+ def clear_class_pool(klass)
+ klass.remove_instance_variable(:@pool)
+ rescue NameError
+ # raised if @pool was not set; ignore
+ end
end
diff --git a/spec/support/shared_examples/redis/redis_shared_examples.rb b/spec/support/shared_examples/redis/redis_shared_examples.rb
index 796b483820b..1f7834a4d7c 100644
--- a/spec/support/shared_examples/redis/redis_shared_examples.rb
+++ b/spec/support/shared_examples/redis/redis_shared_examples.rb
@@ -86,6 +86,67 @@ RSpec.shared_examples "redis_shared_examples" do
end
end
+ describe '.redis_client_params' do
+ # .redis_client_params wraps over `.redis_store_options` by modifying its outputs
+ # to be compatible with `RedisClient`. We test for compatibility in this block while
+ # the contents of redis_store_options are tested in the `.params` block.
+
+ subject { described_class.new(rails_env).redis_client_params }
+
+ let(:rails_env) { 'development' }
+ let(:config_file_name) { config_old_format_socket }
+
+ shared_examples 'instrumentation_class in custom key' do
+ it 'moves instrumentation class into custom' do
+ expect(subject[:custom][:instrumentation_class]).to eq(described_class.store_name)
+ expect(subject[:instrumentation_class]).to be_nil
+ end
+ end
+
+ context 'when url is host based' do
+ context 'with old format' do
+ let(:config_file_name) { config_old_format_host }
+
+ it 'does not raise ArgumentError for invalid keywords' do
+ expect { RedisClient.config(**subject) }.not_to raise_error
+ end
+
+ it_behaves_like 'instrumentation_class in custom key'
+ end
+
+ context 'with new format' do
+ let(:config_file_name) { config_new_format_host }
+
+ where(:rails_env, :host) do
+ [
+ %w[development development-host],
+ %w[test test-host],
+ %w[production production-host]
+ ]
+ end
+
+ with_them do
+ it 'does not raise ArgumentError for invalid keywords in SentinelConfig' do
+ expect(subject[:name]).to eq(host)
+ expect { RedisClient.sentinel(**subject) }.not_to raise_error
+ end
+
+ it_behaves_like 'instrumentation_class in custom key'
+ end
+ end
+ end
+
+ context 'when url contains unix socket reference' do
+ let(:config_file_name) { config_old_format_socket }
+
+ it 'does not raise ArgumentError for invalid keywords' do
+ expect { RedisClient.config(**subject) }.not_to raise_error
+ end
+
+ it_behaves_like 'instrumentation_class in custom key'
+ end
+ end
+
describe '.params' do
subject { described_class.new(rails_env).params }
@@ -206,7 +267,7 @@ RSpec.shared_examples "redis_shared_examples" do
end
end
- describe '.with' do
+ describe '.with', if: !(described_class <= Gitlab::Redis::MultiStoreWrapper) do
let(:config_file_name) { config_old_format_socket }
before do
@@ -217,6 +278,10 @@ RSpec.shared_examples "redis_shared_examples" do
clear_pool
end
+ it 'yields a ::Redis' do
+ described_class.with { |conn| expect(conn).to be_instance_of(::Redis) }
+ end
+
context 'when running on single-threaded runtime' do
before do
allow(Gitlab::Runtime).to receive(:multi_threaded?).and_return(false)
diff --git a/spec/support/shared_examples/requests/api/terraform/modules/v1/packages_shared_examples.rb b/spec/support/shared_examples/requests/api/terraform/modules/v1/packages_shared_examples.rb
index ae2855083f6..b56de050d1e 100644
--- a/spec/support/shared_examples/requests/api/terraform/modules/v1/packages_shared_examples.rb
+++ b/spec/support/shared_examples/requests/api/terraform/modules/v1/packages_shared_examples.rb
@@ -150,8 +150,15 @@ RSpec.shared_examples 'grants terraform module package file access' do |user_typ
project.send("add_#{user_type}", user) if add_member && user_type != :anonymous
end
- it_behaves_like 'returning response status', status
it_behaves_like 'a package tracking event', described_class.name, 'pull_package'
+
+ it 'returns a valid response' do
+ subject
+
+ expect(response).to have_gitlab_http_status(status)
+ expect(response.media_type).to eq('application/octet-stream')
+ expect(response.body).to eq(package.package_files.last.file.read)
+ end
end
end
@@ -273,3 +280,169 @@ RSpec.shared_examples 'process terraform module upload' do |user_type, status, a
end
end
end
+
+RSpec.shared_examples 'handling project level terraform module download requests' do
+ using RSpec::Parameterized::TableSyntax
+ let(:project_id) { project.id }
+ let(:package_name) { package.name }
+ let(:url) { "/projects/#{project_id}/packages/terraform/modules/#{package_name}/#{module_version}?archive=tgz" }
+
+ subject { get api(url), headers: headers }
+
+ it { is_expected.to have_request_urgency(:low) }
+
+ context 'with valid project' do
+ where(:visibility, :user_role, :member, :token_type, :shared_examples_name, :expected_status) do
+ :public | :anonymous | false | nil | 'grants terraform module package file access' | :success
+ :private | :anonymous | false | nil | 'rejects terraform module packages access' | :unauthorized
+
+ :public | :developer | true | :invalid | 'rejects terraform module packages access' | :unauthorized
+ :public | :guest | true | :invalid | 'rejects terraform module packages access' | :unauthorized
+ :public | :developer | false | :invalid | 'rejects terraform module packages access' | :unauthorized
+ :public | :guest | false | :invalid | 'rejects terraform module packages access' | :unauthorized
+ :private | :developer | true | :invalid | 'rejects terraform module packages access' | :unauthorized
+ :private | :guest | true | :invalid | 'rejects terraform module packages access' | :unauthorized
+ :private | :developer | false | :invalid | 'rejects terraform module packages access' | :unauthorized
+ :private | :guest | false | :invalid | 'rejects terraform module packages access' | :unauthorized
+ :internal | :developer | true | :invalid | 'rejects terraform module packages access' | :unauthorized
+ :internal | :guest | true | :invalid | 'rejects terraform module packages access' | :unauthorized
+ :internal | :developer | false | :invalid | 'rejects terraform module packages access' | :unauthorized
+ :internal | :guest | false | :invalid | 'rejects terraform module packages access' | :unauthorized
+
+ :public | :developer | true | :personal_access_token | 'grants terraform module package file access' | :success
+ :public | :guest | true | :personal_access_token | 'grants terraform module package file access' | :success
+ :public | :developer | false | :personal_access_token | 'grants terraform module package file access' | :success
+ :public | :guest | false | :personal_access_token | 'grants terraform module package file access' | :success
+ :private | :developer | true | :personal_access_token | 'grants terraform module package file access' | :success
+ :private | :guest | true | :personal_access_token | 'rejects terraform module packages access' | :forbidden
+ :private | :developer | false | :personal_access_token | 'rejects terraform module packages access' | :not_found
+ :private | :guest | false | :personal_access_token | 'rejects terraform module packages access' | :not_found
+ :internal | :developer | true | :personal_access_token | 'grants terraform module package file access' | :success
+ :internal | :guest | true | :personal_access_token | 'grants terraform module package file access' | :success
+ :internal | :developer | false | :personal_access_token | 'grants terraform module package file access' | :success
+ :internal | :guest | false | :personal_access_token | 'grants terraform module package file access' | :success
+
+ :public | :developer | true | :job_token | 'grants terraform module package file access' | :success
+ :public | :guest | true | :job_token | 'grants terraform module package file access' | :success
+ :public | :developer | false | :job_token | 'grants terraform module package file access' | :success
+ :public | :guest | false | :job_token | 'grants terraform module package file access' | :success
+ :private | :developer | true | :job_token | 'grants terraform module package file access' | :success
+ :private | :guest | true | :job_token | 'rejects terraform module packages access' | :forbidden
+ :private | :developer | false | :job_token | 'rejects terraform module packages access' | :not_found
+ :private | :guest | false | :job_token | 'rejects terraform module packages access' | :not_found
+ :internal | :developer | true | :job_token | 'grants terraform module package file access' | :success
+ :internal | :guest | true | :job_token | 'grants terraform module package file access' | :success
+ :internal | :developer | false | :job_token | 'grants terraform module package file access' | :success
+ :internal | :guest | false | :job_token | 'grants terraform module package file access' | :success
+
+ :public | :anonymous | false | :deploy_token | 'grants terraform module package file access' | :success
+ :private | :anonymous | false | :deploy_token | 'grants terraform module package file access' | :success
+ :internal | :anonymous | false | :deploy_token | 'grants terraform module package file access' | :success
+ end
+
+ with_them do
+ let(:headers) do
+ case token_type
+ when :personal_access_token, :invalid
+ basic_auth_headers(user.username, token)
+ when :deploy_token
+ basic_auth_headers(deploy_token.username, token)
+ when :job_token
+ basic_auth_headers(::Gitlab::Auth::CI_JOB_USER, token)
+ else
+ {}
+ end
+ end
+
+ let(:snowplow_gitlab_standard_context) do
+ {
+ project: project,
+ namespace: project.namespace,
+ property: 'i_package_terraform_module_user'
+ }.tap do |context|
+ context[:user] = user if token_type && token_type != :deploy_token
+ context[:user] = deploy_token if token_type == :deploy_token
+ end
+ end
+
+ before do
+ project.update!(visibility: visibility.to_s)
+ end
+
+ it_behaves_like params[:shared_examples_name], params[:user_role], params[:expected_status], params[:member]
+ end
+ end
+
+ context 'with/without module version' do
+ let(:headers) { basic_auth_headers }
+ let(:finder_params) do
+ { package_name: package_name }.tap do |p|
+ p[:package_version] = module_version if module_version
+ end
+ end
+
+ before do
+ project.add_developer(user)
+ end
+
+ it 'calls the finder with the correct params' do
+ expect_next_instance_of(::Packages::TerraformModule::PackagesFinder, project, finder_params) do |finder|
+ expect(finder).to receive(:execute).and_call_original
+ end
+
+ subject
+ end
+ end
+
+ context 'with non-existent module version' do
+ let(:headers) { basic_auth_headers }
+ let(:module_version) { '1.99.322' }
+
+ before do
+ project.add_developer(user)
+ end
+
+ it_behaves_like 'returning response status', :not_found
+ end
+
+ context 'with invalid project' do
+ let(:project_id) { '123456' }
+
+ let(:headers) { basic_auth_headers }
+
+ it_behaves_like 'rejects terraform module packages access', :anonymous, :not_found
+ end
+
+ context 'with invalid package name' do
+ let(:headers) { basic_auth_headers }
+
+ [nil, '', '%20', 'unknown', '..%2F..', '../..'].each do |pkg_name|
+ context "with package name #{pkg_name}" do
+ let(:package_name) { pkg_name }
+
+ it_behaves_like 'rejects terraform module packages access', :anonymous, :not_found
+ end
+ end
+ end
+
+ context 'when terraform-get param is received' do
+ let(:headers) { basic_auth_headers }
+ let(:url) { "#{super().split('?').first}?terraform-get=1" }
+
+ before do
+ project.add_developer(user)
+ end
+
+ it 'returns a valid response' do
+ subject
+
+ expect(response.headers).to include 'X-Terraform-Get'
+ expect(response.headers['X-Terraform-Get']).to include '?archive=tgz'
+ expect(response.headers['X-Terraform-Get']).not_to include 'terraform-get=1'
+ end
+ end
+
+ def basic_auth_headers(username = user.username, password = personal_access_token.token)
+ { Authorization: "Basic #{Base64.strict_encode64("#{username}:#{password}")}" }
+ end
+end
diff --git a/spec/support/shared_examples/serializers/environment_serializer_shared_examples.rb b/spec/support/shared_examples/serializers/environment_serializer_shared_examples.rb
index b7247f1f243..2976018b60f 100644
--- a/spec/support/shared_examples/serializers/environment_serializer_shared_examples.rb
+++ b/spec/support/shared_examples/serializers/environment_serializer_shared_examples.rb
@@ -12,7 +12,7 @@ RSpec.shared_examples 'avoid N+1 on environments serialization' do
# See also: https://gitlab.com/gitlab-org/gitlab/-/issues/373151
relax_count = 4
- expect { serialize(grouping: true) }.not_to exceed_query_limit(control.count + relax_count)
+ expect { serialize(grouping: true) }.not_to exceed_query_limit(control).with_threshold(relax_count)
end
it 'avoids N+1 database queries without grouping', :request_store do
@@ -27,7 +27,7 @@ RSpec.shared_examples 'avoid N+1 on environments serialization' do
# See also: https://gitlab.com/gitlab-org/gitlab/-/issues/373151
relax_count = 5
- expect { serialize(grouping: false) }.not_to exceed_query_limit(control.count + relax_count)
+ expect { serialize(grouping: false) }.not_to exceed_query_limit(control).with_threshold(relax_count)
end
it 'does not preload for environments that does not exist in the page', :request_store do
diff --git a/spec/support/shared_examples/services/boards/issues_move_service_shared_examples.rb b/spec/support/shared_examples/services/boards/issues_move_service_shared_examples.rb
index 9d016e4830e..38c0670880d 100644
--- a/spec/support/shared_examples/services/boards/issues_move_service_shared_examples.rb
+++ b/spec/support/shared_examples/services/boards/issues_move_service_shared_examples.rb
@@ -43,11 +43,11 @@ RSpec.shared_examples 'issues move service' do |group|
described_class.new(parent, user, params).execute(issue)
end
- it 'removes all list-labels from boards and close the issue' do
+ it 'does not change labels and close the issue' do
described_class.new(parent, user, params).execute(issue)
issue.reload
- expect(issue.labels).to contain_exactly(bug, regression)
+ expect(issue.labels).to contain_exactly(bug, development, testing, regression)
expect(issue).to be_closed
end
end
@@ -59,13 +59,11 @@ RSpec.shared_examples 'issues move service' do |group|
let(:issue) { create(:labeled_issue, project: project, labels: [bug, development, testing, regression], milestone: milestone) }
let(:params) { { board_id: board1.id, from_list_id: list2.id, to_list_id: backlog.id } }
- it_behaves_like 'updating timestamps'
-
it 'keeps labels and milestone' do
described_class.new(parent, user, params).execute(issue)
issue.reload
- expect(issue.labels).to contain_exactly(bug, regression)
+ expect(issue.labels).to contain_exactly(bug, development, testing, regression)
expect(issue.milestone).to eq(milestone)
end
end
diff --git a/spec/support/shared_examples/services/common_system_notes_shared_examples.rb b/spec/support/shared_examples/services/common_system_notes_shared_examples.rb
index 1887b38b50e..14b0aa1ab08 100644
--- a/spec/support/shared_examples/services/common_system_notes_shared_examples.rb
+++ b/spec/support/shared_examples/services/common_system_notes_shared_examples.rb
@@ -1,7 +1,9 @@
# frozen_string_literal: true
-RSpec.shared_examples 'system note creation' do |update_params, note_text|
- subject { described_class.new(project: project, current_user: user).execute(issuable, old_labels: []) }
+RSpec.shared_examples 'system note creation' do |update_params, note_text, is_update = true|
+ subject do
+ described_class.new(project: project, current_user: user).execute(issuable, old_labels: [], is_update: is_update)
+ end
before do
issuable.assign_attributes(update_params)
diff --git a/spec/support/shared_examples/services/count_service_shared_examples.rb b/spec/support/shared_examples/services/count_service_shared_examples.rb
index 54c6ff79976..42fe170d2c4 100644
--- a/spec/support/shared_examples/services/count_service_shared_examples.rb
+++ b/spec/support/shared_examples/services/count_service_shared_examples.rb
@@ -10,10 +10,10 @@ RSpec.shared_examples 'a counter caching service' do
describe '#count' do
it 'caches the count', :request_store do
subject.delete_cache
- control_count = ActiveRecord::QueryRecorder.new { subject.count }.count
+ control = ActiveRecord::QueryRecorder.new { subject.count }
subject.delete_cache
- expect { 2.times { subject.count } }.not_to exceed_query_limit(control_count)
+ expect { 2.times { subject.count } }.not_to exceed_query_limit(control)
end
end
diff --git a/spec/support/shared_examples/services/destroy_label_links_shared_examples.rb b/spec/support/shared_examples/services/destroy_label_links_shared_examples.rb
index d2b52468c25..459c957091c 100644
--- a/spec/support/shared_examples/services/destroy_label_links_shared_examples.rb
+++ b/spec/support/shared_examples/services/destroy_label_links_shared_examples.rb
@@ -8,13 +8,13 @@ RSpec.shared_examples_for 'service deleting label links of an issuable' do
end
it 'deletes label links for specified target ID and type' do
- control_count = ActiveRecord::QueryRecorder.new { execute }.count
+ control = ActiveRecord::QueryRecorder.new { execute }
# Create more label links for the target
create(:label_link, target: target)
create(:label_link, target: target)
- expect { execute }.not_to exceed_query_limit(control_count)
+ expect { execute }.not_to exceed_query_limit(control)
expect(target.reload.label_links.count).to eq(0)
end
end
diff --git a/spec/support/shared_examples/services/jira/requests/base_shared_examples.rb b/spec/support/shared_examples/services/jira/requests/base_shared_examples.rb
index 5e49bdd706c..a51215f6c89 100644
--- a/spec/support/shared_examples/services/jira/requests/base_shared_examples.rb
+++ b/spec/support/shared_examples/services/jira/requests/base_shared_examples.rb
@@ -11,6 +11,7 @@ RSpec.shared_examples 'a service that handles Jira API errors' do
Timeout::Error | '' | 'A timeout error occurred'
URI::InvalidURIError | '' | 'The Jira API URL'
SocketError | '' | 'The Jira API URL'
+ Gitlab::HTTP::BlockedUrlError | '' | 'Unable to connect to the Jira URL. Please verify your'
OpenSSL::SSL::SSLError | 'foo' | 'An SSL error occurred while connecting to Jira: foo'
JIRA::HTTPError | 'Unauthorized' | 'The credentials for accessing Jira are not valid'
JIRA::HTTPError | 'Forbidden' | 'The credentials for accessing Jira are not allowed'
diff --git a/spec/support/shared_examples/services/namespace_package_settings_shared_examples.rb b/spec/support/shared_examples/services/namespace_package_settings_shared_examples.rb
index d288c74ae4b..f4bab4d0ad6 100644
--- a/spec/support/shared_examples/services/namespace_package_settings_shared_examples.rb
+++ b/spec/support/shared_examples/services/namespace_package_settings_shared_examples.rb
@@ -12,6 +12,8 @@ RSpec.shared_examples 'updating the namespace package setting attributes' do |to
.and change { namespace.package_settings.reload.nuget_duplicates_allowed }.from(from[:nuget_duplicates_allowed]).to(to[:nuget_duplicates_allowed])
.and change { namespace.package_settings.reload.nuget_duplicate_exception_regex }.from(from[:nuget_duplicate_exception_regex]).to(to[:nuget_duplicate_exception_regex])
.and change { namespace.package_settings.reload.nuget_symbol_server_enabled }.from(from[:nuget_symbol_server_enabled]).to(to[:nuget_symbol_server_enabled])
+ .and change { namespace.package_settings.reload.terraform_module_duplicates_allowed }.from(from[:terraform_module_duplicates_allowed]).to(to[:terraform_module_duplicates_allowed])
+ .and change { namespace.package_settings.reload.terraform_module_duplicate_exception_regex }.from(from[:terraform_module_duplicate_exception_regex]).to(to[:terraform_module_duplicate_exception_regex])
end
end
@@ -36,6 +38,8 @@ RSpec.shared_examples 'creating the namespace package setting' do
expect(namespace.package_setting_relation.nuget_duplicates_allowed).to eq(package_settings[:nuget_duplicates_allowed])
expect(namespace.package_setting_relation.nuget_duplicate_exception_regex).to eq(package_settings[:nuget_duplicate_exception_regex])
expect(namespace.package_setting_relation.nuget_symbol_server_enabled).to eq(package_settings[:nuget_symbol_server_enabled])
+ expect(namespace.package_setting_relation.terraform_module_duplicates_allowed).to eq(package_settings[:terraform_module_duplicates_allowed])
+ expect(namespace.package_setting_relation.terraform_module_duplicate_exception_regex).to eq(package_settings[:terraform_module_duplicate_exception_regex])
end
it_behaves_like 'returning a success'
diff --git a/spec/support/shared_examples/services/packages/debian/generate_distribution_shared_examples.rb b/spec/support/shared_examples/services/packages/debian/generate_distribution_shared_examples.rb
index cb544f42765..97dd2aa96d4 100644
--- a/spec/support/shared_examples/services/packages/debian/generate_distribution_shared_examples.rb
+++ b/spec/support/shared_examples/services/packages/debian/generate_distribution_shared_examples.rb
@@ -244,10 +244,10 @@ RSpec.shared_examples 'Generate Debian Distribution and component files' do
end
create_list(:debian_package, 10, project: project, published_in: project_distribution)
- control_count = ActiveRecord::QueryRecorder.new { subject2 }.count
+ control = ActiveRecord::QueryRecorder.new { subject2 }
create_list(:debian_package, 10, project: project, published_in: project_distribution)
- expect { subject3 }.not_to exceed_query_limit(control_count)
+ expect { subject3 }.not_to exceed_query_limit(control)
end
end
diff --git a/spec/support/shared_examples/services/protected_branches_shared_examples.rb b/spec/support/shared_examples/services/protected_branches_shared_examples.rb
index 6d4b82730da..980241ad586 100644
--- a/spec/support/shared_examples/services/protected_branches_shared_examples.rb
+++ b/spec/support/shared_examples/services/protected_branches_shared_examples.rb
@@ -1,6 +1,6 @@
# frozen_string_literal: true
-RSpec.shared_context 'with scan result policy blocking protected branches' do
+RSpec.shared_context 'with scan result policy' do
include RepoHelpers
let(:policy_path) { Security::OrchestrationPolicyConfiguration::POLICY_PATH }
@@ -8,12 +8,10 @@ RSpec.shared_context 'with scan result policy blocking protected branches' do
let(:default_branch) { policy_project.default_branch }
let(:policy_yaml) do
- build(:orchestration_policy_yaml, scan_execution_policy: [], scan_result_policy: [scan_result_policy])
+ build(:orchestration_policy_yaml, scan_execution_policy: [], scan_result_policy: scan_result_policies)
end
- let(:scan_result_policy) do
- build(:scan_result_policy, branches: [branch_name], approval_settings: { block_branch_modification: true })
- end
+ let(:scan_result_policies) { [scan_result_policy] }
before do
policy_configuration.update_attribute(:security_policy_management_project, policy_project)
@@ -24,25 +22,26 @@ RSpec.shared_context 'with scan result policy blocking protected branches' do
end
end
-RSpec.shared_context 'with scan result policy preventing force pushing' do
- include RepoHelpers
-
- let(:policy_path) { Security::OrchestrationPolicyConfiguration::POLICY_PATH }
- let(:default_branch) { policy_project.default_branch }
- let(:prevent_pushing_and_force_pushing) { true }
-
- let(:scan_result_policy) do
- build(:scan_result_policy, branches: [branch_name],
- approval_settings: { prevent_pushing_and_force_pushing: prevent_pushing_and_force_pushing })
+RSpec.shared_context 'with scan result policy blocking protected branches' do
+ include_context 'with scan result policy' do
+ let(:scan_result_policy) do
+ build(:scan_result_policy, branches: [branch_name], approval_settings: { block_branch_modification: true })
+ end
end
+end
- let(:policy_yaml) do
- build(:orchestration_policy_yaml, scan_result_policy: [scan_result_policy])
- end
+RSpec.shared_context 'with scan result policy preventing force pushing' do
+ include_context 'with scan result policy' do
+ let(:prevent_pushing_and_force_pushing) { true }
- before do
- create_file_in_repo(policy_project, default_branch, default_branch, policy_path, policy_yaml)
- stub_licensed_features(security_orchestration_policies: true)
+ let(:scan_result_policy) do
+ build(:scan_result_policy, branches: [branch_name],
+ approval_settings: { prevent_pushing_and_force_pushing: prevent_pushing_and_force_pushing })
+ end
+
+ let(:policy_yaml) do
+ build(:orchestration_policy_yaml, scan_result_policy: [scan_result_policy])
+ end
end
after do
diff --git a/spec/support/shared_examples/work_item_hierarchy_restrictions_importer.rb b/spec/support/shared_examples/work_item_hierarchy_restrictions_importer.rb
index 0545be7c741..4f6b27a99c6 100644
--- a/spec/support/shared_examples/work_item_hierarchy_restrictions_importer.rb
+++ b/spec/support/shared_examples/work_item_hierarchy_restrictions_importer.rb
@@ -7,12 +7,23 @@ RSpec.shared_examples 'work item hierarchy restrictions importer' do
end
end
+ shared_examples 'clears type reactive cache' do
+ specify do
+ expect_next_found_instances_of(WorkItems::Type, 7) do |instance|
+ expect(instance).to receive(:clear_reactive_cache!)
+ end
+
+ subject
+ end
+ end
+
context 'when restrictions are missing' do
before do
WorkItems::HierarchyRestriction.delete_all
end
it_behaves_like 'adds restrictions'
+ it_behaves_like 'clears type reactive cache'
end
context 'when base types are missing' do
@@ -41,6 +52,8 @@ RSpec.shared_examples 'work item hierarchy restrictions importer' do
change { restriction.maximum_depth }.from(depth + 1).to(depth)
)
end
+
+ it_behaves_like 'clears type reactive cache'
end
context 'when some restrictions are missing' do
@@ -55,6 +68,8 @@ RSpec.shared_examples 'work item hierarchy restrictions importer' do
)
expect(WorkItems::HierarchyRestriction.count).to eq(7)
end
+
+ it_behaves_like 'clears type reactive cache'
end
context 'when restrictions contain attributes not present in the table' do
@@ -70,5 +85,7 @@ RSpec.shared_examples 'work item hierarchy restrictions importer' do
subject
end
+
+ it_behaves_like 'clears type reactive cache'
end
end
diff --git a/spec/support/shared_examples/work_items/widgetable_service_shared_examples.rb b/spec/support/shared_examples/work_items/widgetable_service_shared_examples.rb
index 491662d17d3..26a5be5aea4 100644
--- a/spec/support/shared_examples/work_items/widgetable_service_shared_examples.rb
+++ b/spec/support/shared_examples/work_items/widgetable_service_shared_examples.rb
@@ -4,7 +4,11 @@ RSpec.shared_examples_for 'work item widgetable service' do
it 'executes callbacks for expected widgets' do
supported_widgets.each do |widget|
expect_next_instance_of(widget[:klass]) do |widget_instance|
- expect(widget_instance).to receive(widget[:callback]).with(params: widget[:params])
+ if widget[:params].present?
+ expect(widget_instance).to receive(widget[:callback]).with(params: widget[:params])
+ else
+ expect(widget_instance).to receive(widget[:callback])
+ end
end
end
diff --git a/spec/support/shared_examples/workers/gitlab/github_import/stage_methods_shared_examples.rb b/spec/support/shared_examples/workers/gitlab/github_import/stage_methods_shared_examples.rb
index af5bf33a9a6..b5e3589d86c 100644
--- a/spec/support/shared_examples/workers/gitlab/github_import/stage_methods_shared_examples.rb
+++ b/spec/support/shared_examples/workers/gitlab/github_import/stage_methods_shared_examples.rb
@@ -1,6 +1,8 @@
# frozen_string_literal: true
RSpec.shared_examples Gitlab::GithubImport::StageMethods do
+ let_it_be(:project) { create(:project, :import_started, import_url: 'https://t0ken@github.com/repo/repo.git') }
+
describe '.sidekiq_retries_exhausted' do
it 'tracks the exception and marks the import as failed' do
expect(Gitlab::Import::ImportFailureService).to receive(:track)
@@ -14,4 +16,183 @@ RSpec.shared_examples Gitlab::GithubImport::StageMethods do
described_class.sidekiq_retries_exhausted_block.call({ 'args' => [1] }, StandardError.new)
end
end
+
+ describe '.sidekiq_options' do
+ subject(:sidekiq_options) { worker.class.sidekiq_options }
+
+ it 'has a status_expiration' do
+ is_expected.to include('status_expiration' => Gitlab::Import::StuckImportJob::IMPORT_JOBS_EXPIRATION)
+ end
+
+ it 'has a retry of 6' do
+ is_expected.to include('retry' => 6)
+ end
+ end
+
+ describe '#perform' do
+ it 'returns if no project could be found' do
+ expect(worker).not_to receive(:import)
+
+ worker.perform(-1)
+ end
+
+ it 'returns if the import state is no longer in progress' do
+ project.import_state.fail_op!
+
+ expect(worker).not_to receive(:import)
+
+ expect(Gitlab::GithubImport::Logger)
+ .to receive(:info)
+ .with(
+ {
+ message: 'starting stage',
+ project_id: project.id,
+ import_stage: described_class.name
+ }
+ )
+
+ expect(Gitlab::GithubImport::Logger)
+ .to receive(:info)
+ .with(
+ {
+ message: 'Project import is no longer running. Stopping worker.',
+ project_id: project.id,
+ import_stage: described_class.name,
+ import_status: 'failed'
+ }
+ )
+
+ worker.perform(project.id)
+ end
+
+ it 'imports the data when the project exists' do
+ expect(worker)
+ .to receive(:import)
+ .with(
+ an_instance_of(Gitlab::GithubImport::Client),
+ an_instance_of(Project)
+ )
+
+ expect(Gitlab::GithubImport::Logger)
+ .to receive(:info)
+ .with(
+ {
+ message: 'starting stage',
+ project_id: project.id,
+ import_stage: described_class.name
+ }
+ )
+
+ expect(Gitlab::GithubImport::Logger)
+ .to receive(:info)
+ .with(
+ {
+ message: 'stage finished',
+ project_id: project.id,
+ import_stage: described_class.name
+ }
+ )
+
+ worker.perform(project.id)
+ end
+
+ it 'queues RefreshImportJidWorker' do
+ allow(worker).to receive(:import)
+ allow(worker).to receive(:jid).and_return('mock_jid')
+
+ expect(Gitlab::GithubImport::RefreshImportJidWorker)
+ .to receive(:perform_in_the_future)
+ .with(project.id, 'mock_jid')
+
+ worker.perform(project.id)
+ end
+
+ describe 'rescheduling the worker on certain errors' do
+ using RSpec::Parameterized::TableSyntax
+
+ where(:error) { [Gitlab::GithubImport::RateLimitError, Gitlab::ExclusiveLeaseHelpers::FailedToObtainLockError] }
+
+ with_them do
+ it 'reschedules the worker' do
+ rate_limit_reset = 10
+ client = instance_double(Gitlab::GithubImport::Client, rate_limit_resets_in: rate_limit_reset)
+
+ allow(Gitlab::GithubImport)
+ .to receive(:new_client_for)
+ .and_return(client)
+
+ expect(worker)
+ .to receive(:import)
+ .with(client, project)
+ .and_raise(error)
+
+ expect(worker.class)
+ .to receive(:perform_in)
+ .with(rate_limit_reset, project.id)
+
+ expect(Gitlab::GithubImport::Logger)
+ .to receive(:info)
+ .with(
+ {
+ message: 'starting stage',
+ project_id: project.id,
+ import_stage: described_class.name
+ }
+ )
+
+ expect(Gitlab::GithubImport::Logger)
+ .to receive(:info)
+ .with(
+ {
+ message: 'stage retrying',
+ project_id: project.id,
+ import_stage: described_class.name,
+ exception_class: error.name
+ }
+ )
+
+ worker.perform(project.id)
+ end
+ end
+ end
+
+ it 'logs error when import fails with a StandardError' do
+ exception = StandardError.new('some error')
+
+ expect(worker)
+ .to receive(:import)
+ .and_raise(exception)
+
+ expect(Gitlab::GithubImport::Logger)
+ .to receive(:info)
+ .with(
+ {
+ message: 'starting stage',
+ project_id: project.id,
+ import_stage: described_class.name
+ }
+ )
+
+ expect(Gitlab::Import::ImportFailureService)
+ .to receive(:track)
+ .with(
+ {
+ project_id: project.id,
+ exception: exception,
+ error_source: described_class.name,
+ fail_import: false,
+ metrics: true
+ }
+ ).and_call_original
+
+ expect { worker.perform(project.id) }
+ .to raise_error(exception)
+
+ expect(project.import_state.reload.status).to eq('started')
+
+ expect(project.import_failures).not_to be_empty
+ expect(project.import_failures.last.exception_class).to eq('StandardError')
+ expect(project.import_failures.last.exception_message).to eq('some error')
+ end
+ end
end
diff --git a/spec/support/sidekiq.rb b/spec/support/sidekiq.rb
index b25f39c5e74..6c354c780b2 100644
--- a/spec/support/sidekiq.rb
+++ b/spec/support/sidekiq.rb
@@ -1,13 +1,19 @@
# frozen_string_literal: true
RSpec.configure do |config|
- def gitlab_sidekiq_inline(&block)
+ def gitlab_sidekiq_inline
# We need to cleanup the queues before running jobs in specs because the
# middleware might have written to redis
redis_queues_cleanup!
redis_queues_metadata_cleanup!
- Sidekiq::Testing.inline!(&block)
+
+ # Scoped inline! is thread-safe which breaks capybara specs
+ # see https://github.com/sidekiq/sidekiq/issues/6069
+ Sidekiq::Testing.inline!
+
+ yield
ensure
+ Sidekiq::Testing.fake! # fake is the default so we reset it to that
redis_queues_cleanup!
redis_queues_metadata_cleanup!
end
diff --git a/spec/support/sidekiq_middleware.rb b/spec/support/sidekiq_middleware.rb
index f4d90ff5151..cbd6163d46b 100644
--- a/spec/support/sidekiq_middleware.rb
+++ b/spec/support/sidekiq_middleware.rb
@@ -6,15 +6,6 @@ require 'sidekiq/testing'
module SidekiqMiddleware
def with_sidekiq_server_middleware(&block)
Sidekiq::Testing.server_middleware.clear
-
- if Gem::Version.new(Sidekiq::VERSION) != Gem::Version.new('6.5.12')
- raise 'New version of sidekiq detected, please remove this line'
- end
-
- # This line is a workaround for a Sidekiq bug that is already fixed in v7.0.0
- # https://github.com/mperham/sidekiq/commit/1b83a152786ed382f07fff12d2608534f1e3c922
- Sidekiq::Testing.server_middleware.instance_variable_set(:@config, Sidekiq)
-
Sidekiq::Testing.server_middleware(&block)
ensure
Sidekiq::Testing.server_middleware.clear