diff options
Diffstat (limited to 'spec/support/helpers')
19 files changed, 268 insertions, 106 deletions
diff --git a/spec/support/helpers/bare_repo_operations.rb b/spec/support/helpers/bare_repo_operations.rb deleted file mode 100644 index e29e12a15f6..00000000000 --- a/spec/support/helpers/bare_repo_operations.rb +++ /dev/null @@ -1,44 +0,0 @@ -# frozen_string_literal: true - -require 'zlib' - -class BareRepoOperations - include Gitlab::Popen - - def initialize(path_to_repo) - @path_to_repo = path_to_repo - end - - def commit_tree(tree_id, msg, parent: Gitlab::Git::EMPTY_TREE_ID) - commit_tree_args = ['commit-tree', tree_id, '-m', msg] - commit_tree_args += ['-p', parent] unless parent == Gitlab::Git::EMPTY_TREE_ID - commit_id = execute(commit_tree_args) - - commit_id[0] - end - - private - - def execute(args, allow_failure: false) - output, status = popen(base_args + args, nil) do |stdin| - yield stdin if block_given? - end - - unless status == 0 - if allow_failure - return [] - else - raise "Got a non-zero exit code while calling out `#{args.join(' ')}`: #{output}" - end - end - - output.split("\n") - end - - def base_args - [ - Gitlab.config.git.bin_path, - "--git-dir=#{@path_to_repo}" - ] - end -end diff --git a/spec/support/helpers/ci/template_helpers.rb b/spec/support/helpers/ci/template_helpers.rb index 2e9b6f748cd..2cdd242ac22 100644 --- a/spec/support/helpers/ci/template_helpers.rb +++ b/spec/support/helpers/ci/template_helpers.rb @@ -5,6 +5,51 @@ module Ci def template_registry_host 'registry.gitlab.com' end + + def public_image_exist?(registry, repository, image) + public_image_manifest(registry, repository, image).present? + end + + def public_image_manifest(registry, repository, reference) + token = public_image_repository_token(registry, repository) + + response = with_net_connect_allowed do + Gitlab::HTTP.get(image_manifest_url(registry, repository, reference), + headers: { 'Authorization' => "Bearer #{token}" }) + end + + return unless response.success? + + Gitlab::Json.parse(response.body) + end + + def public_image_repository_token(registry, repository) + @public_image_repository_tokens ||= {} + @public_image_repository_tokens[[registry, repository]] ||= + begin + response = with_net_connect_allowed do + Gitlab::HTTP.get(image_manifest_url(registry, repository, 'latest')) + end + + return unless response.unauthorized? + + www_authenticate = response.headers['www-authenticate'] + return unless www_authenticate + + realm, service, scope = www_authenticate.split(',').map { |s| s[/\w+="(.*)"/, 1] } + token_response = with_net_connect_allowed do + Gitlab::HTTP.get(realm, query: { service: service, scope: scope }) + end + + return unless token_response.success? + + token_response['token'] + end + end + + def image_manifest_url(registry, repository, reference) + "#{registry}/v2/#{repository}/manifests/#{reference}" + end end end diff --git a/spec/support/helpers/content_security_policy_helpers.rb b/spec/support/helpers/content_security_policy_helpers.rb index c9f15e65c74..230075ead70 100644 --- a/spec/support/helpers/content_security_policy_helpers.rb +++ b/spec/support/helpers/content_security_policy_helpers.rb @@ -1,20 +1,14 @@ # frozen_string_literal: true module ContentSecurityPolicyHelpers - # Expecting 2 calls to current_content_security_policy by default, once for - # the call that's being tested and once for the call in ApplicationController - def setup_csp_for_controller(controller_class, times = 2) + # Expecting 2 calls to current_content_security_policy by default: + # 1. call that's being tested + # 2. call in ApplicationController + def setup_csp_for_controller(controller_class, csp = ActionDispatch::ContentSecurityPolicy.new, times: 2) expect_next_instance_of(controller_class) do |controller| - expect(controller).to receive(:current_content_security_policy) - .and_return(ActionDispatch::ContentSecurityPolicy.new).exactly(times).times - end - end - - # Expecting 2 calls to current_content_security_policy by default, once for - # the call that's being tested and once for the call in ApplicationController - def setup_existing_csp_for_controller(controller_class, csp, times = 2) - expect_next_instance_of(controller_class) do |controller| - expect(controller).to receive(:current_content_security_policy).and_return(csp).exactly(times).times + expect(controller) + .to receive(:current_content_security_policy).exactly(times).times + .and_return(csp) end end end diff --git a/spec/support/helpers/database/multiple_databases_helpers.rb b/spec/support/helpers/database/multiple_databases_helpers.rb new file mode 100644 index 00000000000..16f5168ca29 --- /dev/null +++ b/spec/support/helpers/database/multiple_databases_helpers.rb @@ -0,0 +1,112 @@ +# frozen_string_literal: true + +module Database + module MultipleDatabasesHelpers + def skip_if_multiple_databases_not_setup + skip 'Skipping because multiple databases not set up' unless Gitlab::Database.has_config?(:ci) + end + + def skip_if_multiple_databases_are_setup + skip 'Skipping because multiple databases are set up' if Gitlab::Database.has_config?(:ci) + end + + def reconfigure_db_connection(name: nil, config_hash: {}, model: ActiveRecord::Base, config_model: nil) + db_config = (config_model || model).connection_db_config + + new_db_config = ActiveRecord::DatabaseConfigurations::HashConfig.new( + db_config.env_name, + name ? name.to_s : db_config.name, + db_config.configuration_hash.merge(config_hash) + ) + + model.establish_connection(new_db_config) + end + + def ensure_schema_and_empty_tables + # Ensure all schemas for both databases are migrated back + Gitlab::Database.database_base_models.each do |_, base_model| + with_reestablished_active_record_base do + reconfigure_db_connection( + model: ActiveRecord::Base, + config_model: base_model + ) + + delete_from_all_tables!(except: deletion_except_tables) + schema_migrate_up! + end + end + + # ActiveRecord::Base.clear_all_connections! disconnects and clears attribute methods + # Force a refresh to avoid schema failures. + reset_column_in_all_models + refresh_attribute_methods + end + + # 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` + # - removal of primary connections + # + # The execution within a block ensures safe cleanup of all allocated resources. + # + # rubocop:disable Database/MultipleDatabases + def with_reestablished_active_record_base(reconnect: true) + connection_classes = ActiveRecord::Base + .connection_handler + .connection_pool_names + .map(&:constantize) + .index_with(&:connection_db_config) + + original_handler = ActiveRecord::Base.connection_handler + new_handler = ActiveRecord::ConnectionAdapters::ConnectionHandler.new + ActiveRecord::Base.connection_handler = new_handler + + connection_classes.each { |klass, db_config| klass.establish_connection(db_config) } if reconnect + + yield + ensure + ActiveRecord::Base.connection_handler = original_handler + new_handler&.clear_all_connections! + end + # rubocop:enable Database/MultipleDatabases + + def with_added_ci_connection + if Gitlab::Database.has_config?(:ci) + # No need to add a ci: connection if we already have one + yield + else + with_reestablished_active_record_base(reconnect: true) do + reconfigure_db_connection( + name: :ci, + model: Ci::ApplicationRecord, + config_model: ActiveRecord::Base + ) + + yield + + # Cleanup connection_specification_name for Ci::ApplicationRecord + Ci::ApplicationRecord.remove_connection + end + end + end + end + + module ActiveRecordBaseEstablishConnection + def establish_connection(*args) + # rubocop:disable Database/MultipleDatabases + if connected? && + connection&.transaction_open? && + ActiveRecord::Base.connection_handler == ActiveRecord::Base.default_connection_handler + raise "Cannot re-establish '#{self}.establish_connection' within an open transaction " \ + "(#{connection&.open_transactions.to_i}). Use `with_reestablished_active_record_base` " \ + "instead or add `:reestablished_active_record_base` to rspec context." + end + # rubocop:enable Database/MultipleDatabases + + super + end + end +end + +ActiveRecord::Base.singleton_class.prepend(::Database::ActiveRecordBaseEstablishConnection) # rubocop:disable Database/MultipleDatabases diff --git a/spec/support/helpers/features/access_token_helpers.rb b/spec/support/helpers/features/access_token_helpers.rb new file mode 100644 index 00000000000..f4bdb70c160 --- /dev/null +++ b/spec/support/helpers/features/access_token_helpers.rb @@ -0,0 +1,19 @@ +# frozen_string_literal: true +module Spec + module Support + module Helpers + module AccessTokenHelpers + def active_access_tokens + find("[data-testid='active-tokens']") + end + + def created_access_token + within('[data-testid=access-token-section]') do + find('[data-testid=toggle-visibility-button]').click + find_field('new-access-token').value + end + end + end + end + end +end diff --git a/spec/support/helpers/features/releases_helpers.rb b/spec/support/helpers/features/releases_helpers.rb index 9cce9c4882d..a24b99bbe61 100644 --- a/spec/support/helpers/features/releases_helpers.rb +++ b/spec/support/helpers/features/releases_helpers.rb @@ -39,7 +39,7 @@ module Spec wait_for_all_requests - click_button("#{branch_name}") + click_button(branch_name.to_s) end end diff --git a/spec/support/helpers/filter_spec_helper.rb b/spec/support/helpers/filter_spec_helper.rb index ca844b33ba8..7beed9c7755 100644 --- a/spec/support/helpers/filter_spec_helper.rb +++ b/spec/support/helpers/filter_spec_helper.rb @@ -90,10 +90,11 @@ module FilterSpecHelper # # Returns a String def invalidate_reference(reference) - if reference =~ /\A(.+)?[^\d]\d+\z/ + case reference + when /\A(.+)?[^\d]\d+\z/ # Integer-based reference with optional project prefix reference.gsub(/\d+\z/) { |i| i.to_i + 10_000 } - elsif reference =~ /\A(.+@)?(\h{7,40}\z)/ + when /\A(.+@)?(\h{7,40}\z)/ # SHA-based reference with optional prefix reference.gsub(/\h{7,40}\z/) { |v| v.reverse } else diff --git a/spec/support/helpers/filtered_search_helpers.rb b/spec/support/helpers/filtered_search_helpers.rb index 93122ca3d0c..677cea7b804 100644 --- a/spec/support/helpers/filtered_search_helpers.rb +++ b/spec/support/helpers/filtered_search_helpers.rb @@ -254,6 +254,10 @@ module FilteredSearchHelpers expect(page).to have_css '.gl-filtered-search-token', text: "Assignee = #{value}" end + def expect_unioned_assignee_token(value) + expect(page).to have_css '.gl-filtered-search-token', text: "Assignee is one of #{value}" + end + def expect_author_token(value) expect(page).to have_css '.gl-filtered-search-token', text: "Author = #{value}" end diff --git a/spec/support/helpers/full_name_helper.rb b/spec/support/helpers/full_name_helper.rb new file mode 100644 index 00000000000..a41c0da74d4 --- /dev/null +++ b/spec/support/helpers/full_name_helper.rb @@ -0,0 +1,9 @@ +# frozen_string_literal: true + +module FullNameHelper + def full_name(first_name, last_name) + "#{first_name} #{last_name}" + end +end + +FullNameHelper.prepend_mod diff --git a/spec/support/helpers/git_helpers.rb b/spec/support/helpers/git_helpers.rb deleted file mode 100644 index 72bba419116..00000000000 --- a/spec/support/helpers/git_helpers.rb +++ /dev/null @@ -1,11 +0,0 @@ -# frozen_string_literal: true - -module GitHelpers - def rugged_repo(repository) - path = Gitlab::GitalyClient::StorageSettings.allow_disk_access do - File.join(TestEnv.repos_path, repository.disk_path + '.git') - end - - Rugged::Repository.new(path) - end -end diff --git a/spec/support/helpers/graphql_helpers.rb b/spec/support/helpers/graphql_helpers.rb index b2fc6ae3286..bd0efc96bd8 100644 --- a/spec/support/helpers/graphql_helpers.rb +++ b/spec/support/helpers/graphql_helpers.rb @@ -378,7 +378,7 @@ module GraphqlHelpers def field_with_params(name, attributes = {}) namerized = GraphqlHelpers.fieldnamerize(name.to_s) - return "#{namerized}" if attributes.blank? + return namerized.to_s if attributes.blank? field_params = if attributes.is_a?(Hash) "(#{attributes_to_graphql(attributes)})" diff --git a/spec/support/helpers/kubernetes_helpers.rb b/spec/support/helpers/kubernetes_helpers.rb index 912e7d24b25..72524453f34 100644 --- a/spec/support/helpers/kubernetes_helpers.rb +++ b/spec/support/helpers/kubernetes_helpers.rb @@ -142,6 +142,29 @@ module KubernetesHelpers WebMock.stub_request(method, ingresses_url).to_return(response) end + def stub_server_min_version_failed_request + WebMock.stub_request(:get, service.api_url + '/version').to_return( + status: [500, "Internal Server Error"], + body: {}.to_json) + end + + def stub_server_min_version(min_version) + response = kube_response({ + "major": "1", # not used, just added here to be a bit more realistic purposes + "minor": min_version.to_s + }) + + WebMock.stub_request( :get, service.api_url + '/version') + .with( + headers: { + 'Accept' => '*/*', + 'Accept-Encoding' => 'gzip;q=1.0,deflate;q=0.6,identity;q=0.3', + 'Authorization' => 'Bearer aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa', + 'User-Agent' => 'Ruby' + }) + .to_return(response) + end + def stub_kubeclient_knative_services(options = {}) namespace_path = options[:namespace].present? ? "namespaces/#{options[:namespace]}/" : "" @@ -537,7 +560,7 @@ module KubernetesHelpers }, "spec" => { "containers" => [ - { "name" => "#{container_name}" }, + { "name" => container_name.to_s }, { "name" => "#{container_name}-1" } ] }, diff --git a/spec/support/helpers/navbar_structure_helper.rb b/spec/support/helpers/navbar_structure_helper.rb index b44552d6479..e1ed3ffacec 100644 --- a/spec/support/helpers/navbar_structure_helper.rb +++ b/spec/support/helpers/navbar_structure_helper.rb @@ -90,7 +90,11 @@ module NavbarStructureHelper _('Kubernetes'), new_nav_item: { nav_item: _('Observability'), - nav_sub_items: [] + nav_sub_items: [ + _('Dashboards'), + _('Explore'), + _('Manage Dashboards') + ] } ) end diff --git a/spec/support/helpers/reference_parser_helpers.rb b/spec/support/helpers/reference_parser_helpers.rb index b9796ebbe62..370dedabd9b 100644 --- a/spec/support/helpers/reference_parser_helpers.rb +++ b/spec/support/helpers/reference_parser_helpers.rb @@ -12,14 +12,14 @@ module ReferenceParserHelpers end RSpec.shared_examples 'no project N+1 queries' do - it 'avoids N+1 queries in #nodes_visible_to_user' do + it 'avoids N+1 queries in #nodes_visible_to_user', :use_sql_query_cache do context = Banzai::RenderContext.new(project, user) request = lambda do |links| described_class.new(context).nodes_visible_to_user(user, links) end - control = ActiveRecord::QueryRecorder.new { request.call(control_links) } + control = ActiveRecord::QueryRecorder.new(skip_cached: false) { request.call(control_links) } create(:group_member, group: project.group) if project.group create(:project_member, project: project) diff --git a/spec/support/helpers/search_helpers.rb b/spec/support/helpers/search_helpers.rb index 581ef07752e..7d0f8c09933 100644 --- a/spec/support/helpers/search_helpers.rb +++ b/spec/support/helpers/search_helpers.rb @@ -33,13 +33,13 @@ module SearchHelpers end def select_search_scope(scope) - page.within '.search-filter' do + page.within '[data-testid="search-filter"]' do click_link scope end end def has_search_scope?(scope) - page.within '.search-filter' do + page.within '[data-testid="search-filter"]' do has_link?(scope) end end diff --git a/spec/support/helpers/stub_configuration.rb b/spec/support/helpers/stub_configuration.rb index f41457d2420..24c768258a1 100644 --- a/spec/support/helpers/stub_configuration.rb +++ b/spec/support/helpers/stub_configuration.rb @@ -38,6 +38,10 @@ module StubConfiguration allow(Rails.application.routes).to receive(:default_url_options).and_return(url_options) end + def stub_dependency_proxy_setting(messages) + allow(Gitlab.config.dependency_proxy).to receive_messages(to_settings(messages)) + end + def stub_gravatar_setting(messages) allow(Gitlab.config.gravatar).to receive_messages(to_settings(messages)) end diff --git a/spec/support/helpers/stub_feature_flags.rb b/spec/support/helpers/stub_feature_flags.rb index f1654e55b7e..e301e29afc2 100644 --- a/spec/support/helpers/stub_feature_flags.rb +++ b/spec/support/helpers/stub_feature_flags.rb @@ -37,6 +37,10 @@ module StubFeatureFlags # Enable `ci_live_trace` feature flag only on the specified projects. def stub_feature_flags(features) features.each do |feature_name, actors| + unless Feature::Definition.get(feature_name) + ActiveSupport::Deprecation.warn "Invalid Feature Flag #{feature_name} stubbed" + end + # Remove feature flag overwrite feature = Feature.get(feature_name) # rubocop:disable Gitlab/AvoidFeatureGet feature.remove diff --git a/spec/support/helpers/test_env.rb b/spec/support/helpers/test_env.rb index c58353558df..e1b461cf37e 100644 --- a/spec/support/helpers/test_env.rb +++ b/spec/support/helpers/test_env.rb @@ -11,6 +11,8 @@ module TestEnv # When developing the seed repository, comment out the branch you will modify. BRANCH_SHA = { 'signed-commits' => 'c7794c1', + 'gpg-signed' => '8a852d5', + 'x509-signed' => 'a4df3c8', 'not-merged-branch' => 'b83d6e3', 'branch-merged' => '498214d', 'empty-branch' => '7efb185', @@ -43,7 +45,7 @@ module TestEnv 'video' => '8879059', 'crlf-diff' => '5938907', 'conflict-start' => '824be60', - 'conflict-resolvable' => '1450cd6', + 'conflict-resolvable' => '1450cd639e0bc6721eb02800169e464f212cde06', 'conflict-binary-file' => '259a6fb', 'conflict-contains-conflict-markers' => '78a3086', 'conflict-missing-side' => 'eb227b3', @@ -282,15 +284,30 @@ module TestEnv unless File.directory?(repo_path) start = Time.now system(*%W(#{Gitlab.config.git.bin_path} clone --quiet -- #{clone_url} #{repo_path})) - system(*%W(#{Gitlab.config.git.bin_path} -C #{repo_path} remote remove origin)) puts "==> #{repo_path} set up in #{Time.now - start} seconds...\n" end - set_repo_refs(repo_path, refs) + create_bundle = !File.file?(repo_bundle_path) - unless File.file?(repo_bundle_path) + unless set_repo_refs(repo_path, refs) + # Prefer not to fetch over the network. Only fetch when we have failed to + # set all the required local branches. This would happen when a new + # branch is added to BRANCH_SHA, in which case we want to update + # everything. + unless system(*%W(#{Gitlab.config.git.bin_path} -C #{repo_path} fetch origin)) + raise 'Could not fetch test seed repository.' + end + + unless set_repo_refs(repo_path, refs) + raise "Could not update test seed repository, please delete #{repo_path} and try again" + end + + create_bundle = true + end + + if create_bundle start = Time.now - system(git_env, *%W(#{Gitlab.config.git.bin_path} -C #{repo_path} bundle create #{repo_bundle_path} --all)) + system(git_env, *%W(#{Gitlab.config.git.bin_path} -C #{repo_path} bundle create #{repo_bundle_path} --exclude refs/remotes/* --all)) puts "==> #{repo_bundle_path} generated in #{Time.now - start} seconds...\n" end end @@ -392,20 +409,13 @@ module TestEnv end def set_repo_refs(repo_path, branch_sha) - instructions = branch_sha.map { |branch, sha| "update refs/heads/#{branch}\x00#{sha}\x00" }.join("\x00") << "\x00" - update_refs = %W(#{Gitlab.config.git.bin_path} update-ref --stdin -z) - reset = proc do - Dir.chdir(repo_path) do - IO.popen(update_refs, "w") { |io| io.write(instructions) } - $?.success? + IO.popen(%W[#{Gitlab.config.git.bin_path} -C #{repo_path} update-ref --stdin -z], "w") do |io| + branch_sha.each do |branch, sha| + io.write("update refs/heads/#{branch}\x00#{sha}\x00\x00") end end - # Try to reset without fetching to avoid using the network. - unless reset.call - raise 'Could not fetch test seed repository.' unless system(*%W(#{Gitlab.config.git.bin_path} -C #{repo_path} fetch origin)) - raise "Could not update test seed repository, please delete #{repo_path} and try again" unless reset.call - end + $?.success? end def component_timed_setup(component, install_dir:, version:, task:, fresh_install: true, task_args: []) diff --git a/spec/support/helpers/usage_data_helpers.rb b/spec/support/helpers/usage_data_helpers.rb index b4f0cbd8527..92a946db337 100644 --- a/spec/support/helpers/usage_data_helpers.rb +++ b/spec/support/helpers/usage_data_helpers.rb @@ -67,24 +67,12 @@ module UsageDataHelpers projects_with_repositories_enabled projects_with_error_tracking_enabled projects_with_enabled_alert_integrations - projects_with_expiration_policy_enabled - projects_with_expiration_policy_enabled_with_keep_n_unset - projects_with_expiration_policy_enabled_with_keep_n_set_to_1 - projects_with_expiration_policy_enabled_with_keep_n_set_to_5 - projects_with_expiration_policy_enabled_with_keep_n_set_to_10 - projects_with_expiration_policy_enabled_with_keep_n_set_to_25 - projects_with_expiration_policy_enabled_with_keep_n_set_to_50 projects_with_expiration_policy_enabled_with_older_than_unset projects_with_expiration_policy_enabled_with_older_than_set_to_7d projects_with_expiration_policy_enabled_with_older_than_set_to_14d projects_with_expiration_policy_enabled_with_older_than_set_to_30d projects_with_expiration_policy_enabled_with_older_than_set_to_60d projects_with_expiration_policy_enabled_with_older_than_set_to_90d - projects_with_expiration_policy_enabled_with_cadence_set_to_1d - projects_with_expiration_policy_enabled_with_cadence_set_to_7d - projects_with_expiration_policy_enabled_with_cadence_set_to_14d - projects_with_expiration_policy_enabled_with_cadence_set_to_1month - projects_with_expiration_policy_enabled_with_cadence_set_to_3month projects_with_terraform_reports projects_with_terraform_states pages_domains |