diff options
author | GitLab Bot <gitlab-bot@gitlab.com> | 2020-06-18 11:18:50 +0000 |
---|---|---|
committer | GitLab Bot <gitlab-bot@gitlab.com> | 2020-06-18 11:18:50 +0000 |
commit | 8c7f4e9d5f36cff46365a7f8c4b9c21578c1e781 (patch) | |
tree | a77e7fe7a93de11213032ed4ab1f33a3db51b738 /spec/support/helpers | |
parent | 00b35af3db1abfe813a778f643dad221aad51fca (diff) | |
download | gitlab-ce-8c7f4e9d5f36cff46365a7f8c4b9c21578c1e781.tar.gz |
Add latest changes from gitlab-org/gitlab@13-1-stable-ee
Diffstat (limited to 'spec/support/helpers')
-rw-r--r-- | spec/support/helpers/api_helpers.rb | 11 | ||||
-rw-r--r-- | spec/support/helpers/design_management_test_helpers.rb | 3 | ||||
-rw-r--r-- | spec/support/helpers/filter_spec_helper.rb | 16 | ||||
-rw-r--r-- | spec/support/helpers/graphql_helpers.rb | 65 | ||||
-rw-r--r-- | spec/support/helpers/http_basic_auth_helpers.rb | 26 | ||||
-rw-r--r-- | spec/support/helpers/login_helpers.rb | 6 | ||||
-rw-r--r-- | spec/support/helpers/markdown_feature.rb | 8 | ||||
-rw-r--r-- | spec/support/helpers/partitioning_helpers.rb | 54 | ||||
-rw-r--r-- | spec/support/helpers/prometheus_helpers.rb | 47 | ||||
-rw-r--r-- | spec/support/helpers/stub_action_cable_connection.rb | 7 | ||||
-rw-r--r-- | spec/support/helpers/stub_feature_flags.rb | 58 | ||||
-rw-r--r-- | spec/support/helpers/stub_gitlab_calls.rb | 6 | ||||
-rw-r--r-- | spec/support/helpers/trigger_helpers.rb | 65 | ||||
-rw-r--r-- | spec/support/helpers/usage_data_helpers.rb | 24 | ||||
-rw-r--r-- | spec/support/helpers/wiki_helpers.rb | 4 |
15 files changed, 350 insertions, 50 deletions
diff --git a/spec/support/helpers/api_helpers.rb b/spec/support/helpers/api_helpers.rb index eb9594a4fb6..b1e6078c4f2 100644 --- a/spec/support/helpers/api_helpers.rb +++ b/spec/support/helpers/api_helpers.rb @@ -40,17 +40,6 @@ module ApiHelpers end end - def basic_auth_header(user = nil) - return { 'HTTP_AUTHORIZATION' => user } unless user.respond_to?(:username) - - { - 'HTTP_AUTHORIZATION' => ActionController::HttpAuthentication::Basic.encode_credentials( - user.username, - create(:personal_access_token, user: user).token - ) - } - end - def expect_empty_array_response expect_successful_response_with_paginated_array expect(json_response.length).to eq(0) diff --git a/spec/support/helpers/design_management_test_helpers.rb b/spec/support/helpers/design_management_test_helpers.rb index bf41e2f5079..1daa92e8ad4 100644 --- a/spec/support/helpers/design_management_test_helpers.rb +++ b/spec/support/helpers/design_management_test_helpers.rb @@ -1,9 +1,8 @@ # frozen_string_literal: true module DesignManagementTestHelpers - def enable_design_management(enabled = true, ref_filter = true) + def enable_design_management(enabled = true) stub_lfs_setting(enabled: enabled) - stub_feature_flags(design_management_reference_filter_gfm_pipeline: ref_filter) end def delete_designs(*designs) diff --git a/spec/support/helpers/filter_spec_helper.rb b/spec/support/helpers/filter_spec_helper.rb index c165128040f..ca844b33ba8 100644 --- a/spec/support/helpers/filter_spec_helper.rb +++ b/spec/support/helpers/filter_spec_helper.rb @@ -56,14 +56,11 @@ module FilterSpecHelper pipeline.call(body) end - def reference_pipeline(context = {}) + def reference_pipeline(filter: described_class, **context) context.reverse_merge!(project: project) if defined?(project) context.reverse_merge!(current_user: current_user) if defined?(current_user) - filters = [ - Banzai::Filter::AutolinkFilter, - described_class - ] + filters = [Banzai::Filter::AutolinkFilter, filter].compact redact = context.delete(:redact) filters.push(Banzai::Filter::ReferenceRedactorFilter) if redact @@ -75,8 +72,13 @@ module FilterSpecHelper reference_pipeline(context).call(body) end - def reference_filter(html, context = {}) - reference_pipeline(context).to_document(html) + def reference_filter(text, context = {}) + reference_pipeline(**context).to_document(text) + end + + # Use to test no-ops + def null_filter(text, context = {}) + reference_pipeline(filter: nil, **context).to_document(text) end # Modify a String reference to make it invalid diff --git a/spec/support/helpers/graphql_helpers.rb b/spec/support/helpers/graphql_helpers.rb index b3d7f7bcece..87525734490 100644 --- a/spec/support/helpers/graphql_helpers.rb +++ b/spec/support/helpers/graphql_helpers.rb @@ -11,9 +11,19 @@ module GraphqlHelpers underscored_field_name.to_s.camelize(:lower) end - # Run a loader's named resolver + # Run a loader's named resolver in a way that closely mimics the framework. + # + # First the `ready?` method is called. If it turns out that the resolver is not + # ready, then the early return is returned instead. + # + # Then the resolve method is called. def resolve(resolver_class, obj: nil, args: {}, ctx: {}, field: nil) - resolver_class.new(object: obj, context: ctx, field: field).resolve(args) + resolver = resolver_class.new(object: obj, context: ctx, field: field) + ready, early_return = sync_all { resolver.ready?(**args) } + + return early_return unless ready + + resolver.resolve(args) end # Eagerly run a loader's named resolver @@ -51,12 +61,12 @@ module GraphqlHelpers # BatchLoader::GraphQL returns a wrapper, so we need to :sync in order # to get the actual values def batch_sync(max_queries: nil, &blk) - wrapper = proc do - lazy_vals = yield - lazy_vals.is_a?(Array) ? lazy_vals.map { |val| sync(val) } : sync(lazy_vals) - end + batch(max_queries: max_queries) { sync_all(&blk) } + end - batch(max_queries: max_queries, &wrapper) + def sync_all(&blk) + lazy_vals = yield + lazy_vals.is_a?(Array) ? lazy_vals.map { |val| sync(val) } : sync(lazy_vals) end def graphql_query_for(name, attributes = {}, fields = nil) @@ -67,10 +77,14 @@ module GraphqlHelpers QUERY end - def graphql_mutation(name, input, fields = nil) + def graphql_mutation(name, input, fields = nil, &block) + raise ArgumentError, 'Please pass either `fields` parameter or a block to `#graphql_mutation`, but not both.' if fields.present? && block_given? + mutation_name = GraphqlHelpers.fieldnamerize(name) input_variable_name = "$#{input_variable_name_for_mutation(name)}" mutation_field = GitlabSchema.mutation.fields[mutation_name] + + fields = yield if block_given? fields ||= all_graphql_fields_for(mutation_field.type.to_graphql) query = <<~MUTATION @@ -139,7 +153,15 @@ module GraphqlHelpers end def wrap_fields(fields) - fields = Array.wrap(fields).join("\n") + fields = Array.wrap(fields).map do |field| + case field + when Symbol + GraphqlHelpers.fieldnamerize(field) + else + field + end + end.join("\n") + return unless fields.present? <<~FIELDS @@ -257,8 +279,13 @@ module GraphqlHelpers end def graphql_dig_at(data, *path) - keys = path.map { |segment| GraphqlHelpers.fieldnamerize(segment) } - data.dig(*keys) + keys = path.map { |segment| segment.is_a?(Integer) ? segment : GraphqlHelpers.fieldnamerize(segment) } + + # Allows for array indexing, like this + # ['project', 'boards', 'edges', 0, 'node', 'lists'] + keys.reduce(data) do |memo, key| + memo.is_a?(Array) ? memo[key] : memo&.dig(key) + end end def graphql_errors @@ -294,6 +321,22 @@ module GraphqlHelpers graphql_data.fetch(GraphqlHelpers.fieldnamerize(mutation_name)) end + def scalar_fields_of(type_name) + GitlabSchema.types[type_name].fields.map do |name, field| + next if nested_fields?(field) || required_arguments?(field) + + name + end.compact + end + + def nested_fields_of(type_name) + GitlabSchema.types[type_name].fields.map do |name, field| + next if !nested_fields?(field) || required_arguments?(field) + + [name, field] + end.compact + end + def nested_fields?(field) !scalar?(field) && !enum?(field) end diff --git a/spec/support/helpers/http_basic_auth_helpers.rb b/spec/support/helpers/http_basic_auth_helpers.rb new file mode 100644 index 00000000000..c0b24b3dfa4 --- /dev/null +++ b/spec/support/helpers/http_basic_auth_helpers.rb @@ -0,0 +1,26 @@ +# frozen_string_literal: true + +module HttpBasicAuthHelpers + def user_basic_auth_header(user) + access_token = create(:personal_access_token, user: user) + + basic_auth_header(user.username, access_token.token) + end + + def job_basic_auth_header(job) + basic_auth_header(Ci::Build::CI_REGISTRY_USER, job.token) + end + + def client_basic_auth_header(client) + basic_auth_header(client.uid, client.secret) + end + + def basic_auth_header(username, password) + { + 'HTTP_AUTHORIZATION' => ActionController::HttpAuthentication::Basic.encode_credentials( + username, + password + ) + } + end +end diff --git a/spec/support/helpers/login_helpers.rb b/spec/support/helpers/login_helpers.rb index cb880939b1c..92f6d673255 100644 --- a/spec/support/helpers/login_helpers.rb +++ b/spec/support/helpers/login_helpers.rb @@ -57,13 +57,13 @@ module LoginHelpers 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 - click_link provider + click_button provider end def gitlab_enable_admin_mode_sign_in_via(provider, user, uid, saml_response = nil) mock_auth_hash_with_saml_xml(provider, uid, user.email, saml_response) visit new_admin_session_path - click_link provider + click_button provider end # Requires Javascript driver. @@ -103,7 +103,7 @@ module LoginHelpers check 'remember_me' if remember_me - click_link "oauth-login-#{provider}" + click_button "oauth-login-#{provider}" end def fake_successful_u2f_authentication diff --git a/spec/support/helpers/markdown_feature.rb b/spec/support/helpers/markdown_feature.rb index eea03fb9325..40e0d4413e2 100644 --- a/spec/support/helpers/markdown_feature.rb +++ b/spec/support/helpers/markdown_feature.rb @@ -36,12 +36,12 @@ class MarkdownFeature end end - def project_wiki - @project_wiki ||= ProjectWiki.new(project, user) + def wiki + @wiki ||= ProjectWiki.new(project, user) end - def project_wiki_page - @project_wiki_page ||= build(:wiki_page, wiki: project_wiki) + def wiki_page + @wiki_page ||= build(:wiki_page, wiki: wiki) end def issue diff --git a/spec/support/helpers/partitioning_helpers.rb b/spec/support/helpers/partitioning_helpers.rb new file mode 100644 index 00000000000..98a13915d76 --- /dev/null +++ b/spec/support/helpers/partitioning_helpers.rb @@ -0,0 +1,54 @@ +# frozen_string_literal: true + +module PartitioningHelpers + def expect_table_partitioned_by(table, columns, part_type: :range) + columns_with_part_type = columns.map { |c| [part_type.to_s, c] } + actual_columns = find_partitioned_columns(table) + + expect(columns_with_part_type).to match_array(actual_columns) + end + + def expect_range_partition_of(partition_name, table_name, min_value, max_value) + definition = find_partition_definition(partition_name) + + expect(definition).not_to be_nil + expect(definition['base_table']).to eq(table_name.to_s) + expect(definition['condition']).to eq("FOR VALUES FROM (#{min_value}) TO (#{max_value})") + end + + private + + def find_partitioned_columns(table) + connection.select_rows(<<~SQL) + select + case partstrat + when 'l' then 'list' + when 'r' then 'range' + when 'h' then 'hash' + end as partstrat, + cols.column_name + from ( + select partrelid, partstrat, unnest(partattrs) as col_pos + from pg_partitioned_table + ) pg_part + inner join pg_class + on pg_part.partrelid = pg_class.oid + inner join information_schema.columns cols + on cols.table_name = pg_class.relname + and cols.ordinal_position = pg_part.col_pos + where pg_class.relname = '#{table}'; + SQL + end + + def find_partition_definition(partition) + connection.select_one(<<~SQL) + select + parent_class.relname as base_table, + pg_get_expr(pg_class.relpartbound, inhrelid) as condition + from pg_class + inner join pg_inherits i on pg_class.oid = inhrelid + inner join pg_class parent_class on parent_class.oid = inhparent + where pg_class.relname = '#{partition}' and pg_class.relispartition; + SQL + end +end diff --git a/spec/support/helpers/prometheus_helpers.rb b/spec/support/helpers/prometheus_helpers.rb index fdce00e7dec..d49abbf3f19 100644 --- a/spec/support/helpers/prometheus_helpers.rb +++ b/spec/support/helpers/prometheus_helpers.rb @@ -236,4 +236,51 @@ module PrometheusHelpers ] } end + + def prometheus_alert_payload(firing: [], resolved: []) + status = firing.any? ? 'firing' : 'resolved' + alerts = firing + resolved + alert_name = alerts.first&.title || '' + prometheus_metric_id = alerts.first&.prometheus_metric_id&.to_s + + alerts_map = \ + firing.map { |alert| prometheus_map_alert_payload('firing', alert) } + + resolved.map { |alert| prometheus_map_alert_payload('resolved', alert) } + + # See https://prometheus.io/docs/alerting/configuration/#%3Cwebhook_config%3E + { + 'version' => '4', + 'receiver' => 'gitlab', + 'status' => status, + 'alerts' => alerts_map, + 'groupLabels' => { + 'alertname' => alert_name + }, + 'commonLabels' => { + 'alertname' => alert_name, + 'gitlab' => 'hook', + 'gitlab_alert_id' => prometheus_metric_id + }, + 'commonAnnotations' => {}, + 'externalURL' => '', + 'groupKey' => "{}:{alertname=\'#{alert_name}\'}" + } + end + + private + + def prometheus_map_alert_payload(status, alert) + { + 'status' => status, + 'labels' => { + 'alertname' => alert.title, + 'gitlab' => 'hook', + 'gitlab_alert_id' => alert.prometheus_metric_id.to_s + }, + 'annotations' => {}, + 'startsAt' => '2018-09-24T08:57:31.095725221Z', + 'endsAt' => '0001-01-01T00:00:00Z', + 'generatorURL' => 'http://prometheus-prometheus-server-URL' + } + end end diff --git a/spec/support/helpers/stub_action_cable_connection.rb b/spec/support/helpers/stub_action_cable_connection.rb new file mode 100644 index 00000000000..b4e9c2ae48c --- /dev/null +++ b/spec/support/helpers/stub_action_cable_connection.rb @@ -0,0 +1,7 @@ +# frozen_string_literal: true + +module StubActionCableConnection + def stub_action_cable_connection(current_user: nil, request: ActionDispatch::TestRequest.create) + stub_connection(current_user: current_user, request: request) + end +end diff --git a/spec/support/helpers/stub_feature_flags.rb b/spec/support/helpers/stub_feature_flags.rb index 5b8a85b206f..696148cacaf 100644 --- a/spec/support/helpers/stub_feature_flags.rb +++ b/spec/support/helpers/stub_feature_flags.rb @@ -1,6 +1,38 @@ # frozen_string_literal: true module StubFeatureFlags + class StubFeatureGate + attr_reader :flipper_id + + def initialize(flipper_id) + @flipper_id = flipper_id + end + end + + def stub_all_feature_flags + adapter = Flipper::Adapters::Memory.new + flipper = Flipper.new(adapter) + + allow(Feature).to receive(:flipper).and_return(flipper) + + # All new requested flags are enabled by default + allow(Feature).to receive(:enabled?).and_wrap_original do |m, *args| + feature_flag = m.call(*args) + + # If feature flag is not persisted we mark the feature flag as enabled + # We do `m.call` as we want to validate the execution of method arguments + # and a feature flag state if it is not persisted + unless Feature.persisted_name?(args.first) + # TODO: this is hack to support `promo_feature_available?` + # We enable all feature flags by default unless they are `promo_` + # Issue: https://gitlab.com/gitlab-org/gitlab/-/issues/218667 + feature_flag = true unless args.first.to_s.start_with?('promo_') + end + + feature_flag + end + end + # Stub Feature flags with `flag_name: true/false` # # @param [Hash] features where key is feature name and value is boolean whether enabled or not. @@ -14,23 +46,29 @@ module StubFeatureFlags # Enable `ci_live_trace` feature flag only on the specified projects. def stub_feature_flags(features) features.each do |feature_name, actors| - allow(Feature).to receive(:enabled?).with(feature_name, any_args).and_return(false) - allow(Feature).to receive(:enabled?).with(feature_name.to_s, any_args).and_return(false) + # Remove feature flag overwrite + feature = Feature.get(feature_name) # rubocop:disable Gitlab/AvoidFeatureGet + feature.remove Array(actors).each do |actor| raise ArgumentError, "actor cannot be Hash" if actor.is_a?(Hash) - case actor - when false, true - allow(Feature).to receive(:enabled?).with(feature_name, any_args).and_return(actor) - allow(Feature).to receive(:enabled?).with(feature_name.to_s, any_args).and_return(actor) - when nil, ActiveRecord::Base, Symbol, RSpec::Mocks::Double - allow(Feature).to receive(:enabled?).with(feature_name, actor, any_args).and_return(true) - allow(Feature).to receive(:enabled?).with(feature_name.to_s, actor, any_args).and_return(true) + # Control a state of feature flag + if actor == true || actor.nil? || actor.respond_to?(:flipper_id) + feature.enable(actor) + elsif actor == false + feature.disable else - raise ArgumentError, "#stub_feature_flags accepts only `nil`, `true`, `false`, `ActiveRecord::Base` or `Symbol` as actors" + raise ArgumentError, "#stub_feature_flags accepts only `nil`, `bool`, an object responding to `#flipper_id` or including `FeatureGate`." end end end end + + def stub_feature_flag_gate(object) + return if object.nil? + return object if object.is_a?(FeatureGate) + + StubFeatureGate.new(object) + end end diff --git a/spec/support/helpers/stub_gitlab_calls.rb b/spec/support/helpers/stub_gitlab_calls.rb index 120d432655b..4da8f760056 100644 --- a/spec/support/helpers/stub_gitlab_calls.rb +++ b/spec/support/helpers/stub_gitlab_calls.rb @@ -141,6 +141,12 @@ module StubGitlabCalls .to_return(status: 200, body: "", headers: {}) end + def stub_webide_config_file(content, sha: anything) + allow_any_instance_of(Repository) + .to receive(:blob_data_at).with(sha, '.gitlab/.gitlab-webide.yml') + .and_return(content) + end + def project_hash_array f = File.read(Rails.root.join('spec/support/gitlab_stubs/projects.json')) Gitlab::Json.parse(f) diff --git a/spec/support/helpers/trigger_helpers.rb b/spec/support/helpers/trigger_helpers.rb new file mode 100644 index 00000000000..fa4f499b900 --- /dev/null +++ b/spec/support/helpers/trigger_helpers.rb @@ -0,0 +1,65 @@ +# frozen_string_literal: true + +module TriggerHelpers + def expect_function_to_exist(name) + expect(find_function_def(name)).not_to be_nil + end + + def expect_function_not_to_exist(name) + expect(find_function_def(name)).to be_nil + end + + def expect_function_to_contain(name, *statements) + return_stmt, *body_stmts = parsed_function_statements(name).reverse + + expect(return_stmt).to eq('return old') + expect(body_stmts).to contain_exactly(*statements) + end + + def expect_trigger_not_to_exist(table_name, name) + expect(find_trigger_def(table_name, name)).to be_nil + end + + def expect_valid_function_trigger(table_name, name, fn_name, fires_on) + events, timing, definition = cleaned_trigger_def(table_name, name) + + events = events&.split(',') + expected_timing, expected_events = fires_on.first + expect(timing).to eq(expected_timing.to_s) + expect(events).to match_array(Array.wrap(expected_events)) + expect(definition).to eq("execute procedure #{fn_name}()") + end + + private + + def parsed_function_statements(name) + cleaned_definition = find_function_def(name)['body'].downcase.gsub(/\s+/, ' ') + statements = cleaned_definition.sub(/\A\s*begin\s*(.*)\s*end\s*\Z/, "\\1") + statements.split(';').map! { |stmt| stmt.strip.presence }.compact! + end + + def find_function_def(name) + connection.select_one(<<~SQL) + SELECT prosrc AS body + FROM pg_proc + WHERE proname = '#{name}' + SQL + end + + def cleaned_trigger_def(table_name, name) + find_trigger_def(table_name, name).values_at('event', 'action_timing', 'action_statement').map!(&:downcase) + end + + def find_trigger_def(table_name, name) + connection.select_one(<<~SQL) + SELECT + string_agg(event_manipulation, ',') AS event, + action_timing, + action_statement + FROM information_schema.triggers + WHERE event_object_table = '#{table_name}' + AND trigger_name = '#{name}' + GROUP BY 2, 3 + SQL + end +end diff --git a/spec/support/helpers/usage_data_helpers.rb b/spec/support/helpers/usage_data_helpers.rb index 382e4f6a1a4..f6c415a75bc 100644 --- a/spec/support/helpers/usage_data_helpers.rb +++ b/spec/support/helpers/usage_data_helpers.rb @@ -78,6 +78,7 @@ module UsageDataHelpers labels lfs_objects merge_requests + merge_requests_users milestone_lists milestones notes @@ -117,12 +118,18 @@ module UsageDataHelpers 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 protected_branches releases remote_mirrors snippets + personal_snippets + project_snippets suggestions + terraform_reports + terraform_states todos uploads web_hooks @@ -157,6 +164,11 @@ module UsageDataHelpers object_store ).freeze + def stub_usage_data_connections + allow(ActiveRecord::Base.connection).to receive(:transaction_open?).and_return(false) + allow(Gitlab::Prometheus::Internal).to receive(:prometheus_enabled?).and_return(false) + end + def stub_object_store_settings allow(Settings).to receive(:[]).with('artifacts') .and_return( @@ -209,4 +221,16 @@ module UsageDataHelpers 'proxy_download' => false } } ) end + + def expect_prometheus_api_to(*receive_matchers) + expect_next_instance_of(Gitlab::PrometheusClient) do |client| + receive_matchers.each { |m| expect(client).to m } + end + end + + def allow_prometheus_queries + allow_next_instance_of(Gitlab::PrometheusClient) do |client| + allow(client).to receive(:aggregate).and_return({}) + end + end end diff --git a/spec/support/helpers/wiki_helpers.rb b/spec/support/helpers/wiki_helpers.rb index e6818ff8f0c..ae0d53d1297 100644 --- a/spec/support/helpers/wiki_helpers.rb +++ b/spec/support/helpers/wiki_helpers.rb @@ -8,14 +8,14 @@ module WikiHelpers find('.svg-content .js-lazy-loaded') if example.nil? || example.metadata.key?(:js) end - def upload_file_to_wiki(project, user, file_name) + def upload_file_to_wiki(container, user, file_name) opts = { file_name: file_name, file_content: File.read(expand_fixture_path(file_name)) } ::Wikis::CreateAttachmentService.new( - container: project, + container: container, current_user: user, params: opts ).execute[:result][:file_path] |