diff options
Diffstat (limited to 'spec/support')
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 |