summaryrefslogtreecommitdiff
path: root/spec/support
diff options
context:
space:
mode:
authorGitLab Bot <gitlab-bot@gitlab.com>2021-06-16 18:25:58 +0000
committerGitLab Bot <gitlab-bot@gitlab.com>2021-06-16 18:25:58 +0000
commita5f4bba440d7f9ea47046a0a561d49adf0a1e6d4 (patch)
treefb69158581673816a8cd895f9d352dcb3c678b1e /spec/support
parentd16b2e8639e99961de6ddc93909f3bb5c1445ba1 (diff)
downloadgitlab-ce-a5f4bba440d7f9ea47046a0a561d49adf0a1e6d4.tar.gz
Add latest changes from gitlab-org/gitlab@14-0-stable-eev14.0.0-rc42
Diffstat (limited to 'spec/support')
-rw-r--r--spec/support/capybara.rb3
-rw-r--r--spec/support/database_cleaner.rb2
-rw-r--r--spec/support/gitlab/usage/metrics_instrumentation_shared_examples.rb31
-rw-r--r--spec/support/gitlab_stubs/gitlab_ci_for_sast.yml1
-rw-r--r--spec/support/gitlab_stubs/gitlab_ci_for_sast_default_analyzers.yml15
-rw-r--r--spec/support/helpers/access_matchers_helpers.rb16
-rw-r--r--spec/support/helpers/cycle_analytics_helpers.rb5
-rw-r--r--spec/support/helpers/feature_flag_helpers.rb3
-rw-r--r--spec/support/helpers/features/top_nav_spec_helpers.rb53
-rw-r--r--spec/support/helpers/gitaly_setup.rb4
-rw-r--r--spec/support/helpers/global_id_deprecation_helpers.rb13
-rw-r--r--spec/support/helpers/graphql_helpers.rb4
-rw-r--r--spec/support/helpers/javascript_fixtures_helpers.rb10
-rw-r--r--spec/support/helpers/login_helpers.rb6
-rw-r--r--spec/support/helpers/query_recorder.rb7
-rw-r--r--spec/support/helpers/rake_helpers.rb5
-rw-r--r--spec/support/helpers/reference_parser_helpers.rb18
-rw-r--r--spec/support/helpers/usage_data_helpers.rb2
-rw-r--r--spec/support/import_export/common_util.rb8
-rw-r--r--spec/support/matchers/be_one_of.rb11
-rw-r--r--spec/support/redis.rb8
-rw-r--r--spec/support/redis/redis_helpers.rb5
-rw-r--r--spec/support/redis/redis_shared_examples.rb149
-rw-r--r--spec/support/shared_contexts/changes_access_checks_shared_context.rb40
-rw-r--r--spec/support/shared_contexts/features/integrations/group_integrations_shared_context.rb28
-rw-r--r--spec/support/shared_contexts/features/integrations/instance_and_group_integrations_shared_context.rb18
-rw-r--r--spec/support/shared_contexts/features/integrations/instance_integrations_shared_context.rb24
-rw-r--r--spec/support/shared_contexts/features/integrations/integrations_shared_context.rb (renamed from spec/support/shared_contexts/services_shared_context.rb)10
-rw-r--r--spec/support/shared_contexts/features/integrations/project_integrations_jira_context.rb (renamed from spec/support/shared_contexts/project_service_jira_context.rb)0
-rw-r--r--spec/support/shared_contexts/features/integrations/project_integrations_shared_context.rb (renamed from spec/support/shared_contexts/project_service_shared_context.rb)6
-rw-r--r--spec/support/shared_contexts/graphql/requests/packages_shared_context.rb33
-rw-r--r--spec/support/shared_contexts/load_balancing_configuration_shared_context.rb19
-rw-r--r--spec/support/shared_contexts/navbar_structure_context.rb20
-rw-r--r--spec/support/shared_contexts/policies/project_policy_shared_context.rb4
-rw-r--r--spec/support/shared_contexts/read_ci_configuration_shared_context.rb4
-rw-r--r--spec/support/shared_contexts/requests/api/conan_packages_shared_context.rb4
-rw-r--r--spec/support/shared_contexts/requests/api/helm_packages_shared_context.rb10
-rw-r--r--spec/support/shared_contexts/requests/api/npm_packages_shared_context.rb2
-rw-r--r--spec/support/shared_contexts/services/packages/debian/distribution_shared_context.rb20
-rw-r--r--spec/support/shared_contexts/single_change_access_checks_shared_context.rb (renamed from spec/support/shared_contexts/change_access_checks_shared_context.rb)2
-rw-r--r--spec/support/shared_examples/ci/badge_template_shared_examples.rb57
-rw-r--r--spec/support/shared_examples/controllers/wiki_actions_shared_examples.rb4
-rw-r--r--spec/support/shared_examples/features/discussion_comments_shared_example.rb4
-rw-r--r--spec/support/shared_examples/features/integrations/user_activates_mattermost_slash_command_integration_shared_examples.rb34
-rw-r--r--spec/support/shared_examples/features/issuable_invite_members_shared_examples.rb12
-rw-r--r--spec/support/shared_examples/features/variable_list_shared_examples.rb2
-rw-r--r--spec/support/shared_examples/finders/assignees_filter_shared_examples.rb6
-rw-r--r--spec/support/shared_examples/graphql/mutations/can_mutate_spammable_examples.rb6
-rw-r--r--spec/support/shared_examples/graphql/mutations/resolves_subscription_shared_examples.rb53
-rw-r--r--spec/support/shared_examples/lib/gitlab/ci/ci_trace_shared_examples.rb74
-rw-r--r--spec/support/shared_examples/lib/gitlab/experimentation_shared_examples.rb20
-rw-r--r--spec/support/shared_examples/models/chat_integration_shared_examples.rb (renamed from spec/support/shared_examples/models/chat_service_shared_examples.rb)84
-rw-r--r--spec/support/shared_examples/models/concerns/integrations/slack_mattermost_notifier_shared_examples.rb (renamed from spec/support/shared_examples/models/slack_mattermost_notifications_shared_examples.rb)33
-rw-r--r--spec/support/shared_examples/models/concerns/timebox_shared_examples.rb39
-rw-r--r--spec/support/shared_examples/models/integrations/base_slash_commands_shared_examples.rb (renamed from spec/support/shared_examples/models/chat_slash_commands_shared_examples.rb)2
-rw-r--r--spec/support/shared_examples/models/mentionable_shared_examples.rb4
-rw-r--r--spec/support/shared_examples/models/packages/debian/component_file_shared_example.rb18
-rw-r--r--spec/support/shared_examples/models/packages/debian/distribution_key_shared_examples.rb49
-rw-r--r--spec/support/shared_examples/models/packages/debian/distribution_shared_examples.rb1
-rw-r--r--spec/support/shared_examples/namespaces/linear_traversal_examples.rb23
-rw-r--r--spec/support/shared_examples/namespaces/traversal_examples.rb38
-rw-r--r--spec/support/shared_examples/requests/api/conan_packages_shared_examples.rb12
-rw-r--r--spec/support/shared_examples/requests/api/debian_packages_shared_examples.rb222
-rw-r--r--spec/support/shared_examples/requests/api/graphql/packages/package_details_shared_examples.rb27
-rw-r--r--spec/support/shared_examples/requests/api/helm_packages_shared_examples.rb53
-rw-r--r--spec/support/shared_examples/requests/api/packages_shared_examples.rb2
-rw-r--r--spec/support/shared_examples/requests/api/pypi_packages_shared_examples.rb173
-rw-r--r--spec/support/shared_examples/requests/api/resource_label_events_api_shared_examples.rb2
-rw-r--r--spec/support/shared_examples/requests/api/tracking_shared_examples.rb2
-rw-r--r--spec/support/shared_examples/services/clusters/parse_cluster_applications_artifact_shared_examples.rb89
-rw-r--r--spec/support/shared_examples/services/packages/debian/generate_distribution_shared_examples.rb166
-rw-r--r--spec/support/shared_examples/services/users/build_service_shared_examples.rb125
-rw-r--r--spec/support/shared_examples/uncached_response_shared_examples.rb12
-rw-r--r--spec/support/unicorn.rb27
74 files changed, 1702 insertions, 396 deletions
diff --git a/spec/support/capybara.rb b/spec/support/capybara.rb
index f9a28c8e40b..e48a7b322ac 100644
--- a/spec/support/capybara.rb
+++ b/spec/support/capybara.rb
@@ -21,7 +21,8 @@ JS_CONSOLE_FILTER = Regexp.union([
'"[WDS] Hot Module Replacement enabled."',
'"[WDS] Live Reloading enabled."',
'Download the Vue Devtools extension',
- 'Download the Apollo DevTools'
+ 'Download the Apollo DevTools',
+ "Unrecognized feature: 'interest-cohort'"
])
CAPYBARA_WINDOW_SIZE = [1366, 768].freeze
diff --git a/spec/support/database_cleaner.rb b/spec/support/database_cleaner.rb
index 60d82f7e92a..f6339d7343c 100644
--- a/spec/support/database_cleaner.rb
+++ b/spec/support/database_cleaner.rb
@@ -35,8 +35,6 @@ RSpec.configure do |config|
puts "Recreating the database"
start = Gitlab::Metrics::System.monotonic_time
- ActiveRecord::AdvisoryLockBase.clear_all_connections!
-
ActiveRecord::Tasks::DatabaseTasks.drop_current
ActiveRecord::Tasks::DatabaseTasks.create_current
ActiveRecord::Tasks::DatabaseTasks.load_schema_current
diff --git a/spec/support/gitlab/usage/metrics_instrumentation_shared_examples.rb b/spec/support/gitlab/usage/metrics_instrumentation_shared_examples.rb
index c9ff566e94c..de9735df546 100644
--- a/spec/support/gitlab/usage/metrics_instrumentation_shared_examples.rb
+++ b/spec/support/gitlab/usage/metrics_instrumentation_shared_examples.rb
@@ -1,13 +1,38 @@
# frozen_string_literal: true
-RSpec.shared_examples 'a correct instrumented metric value' do |options, expected_value|
- let(:time_frame) { options[:time_frame] }
+RSpec.shared_examples 'a correct instrumented metric value' do |params|
+ let(:time_frame) { params[:time_frame] }
+ let(:options) { params[:options] }
+ let(:metric) { described_class.new(time_frame: time_frame, options: options) }
before do
allow(ActiveRecord::Base.connection).to receive(:transaction_open?).and_return(false)
end
it 'has correct value' do
- expect(described_class.new(time_frame: time_frame).value).to eq(expected_value)
+ expect(metric.value).to eq(expected_value)
end
end
+
+RSpec.shared_examples 'a correct instrumented metric query' do |params|
+ let(:time_frame) { params[:time_frame] }
+ let(:options) { params[:options] }
+ let(:metric) { described_class.new(time_frame: time_frame, options: options) }
+
+ around do |example|
+ freeze_time { example.run }
+ end
+
+ before do
+ allow(ActiveRecord::Base.connection).to receive(:transaction_open?).and_return(false)
+ end
+
+ it 'has correct generate query' do
+ expect(metric.to_sql).to eq(expected_query)
+ end
+end
+
+RSpec.shared_examples 'a correct instrumented metric value and query' do |params|
+ it_behaves_like 'a correct instrumented metric value', params
+ it_behaves_like 'a correct instrumented metric query', params
+end
diff --git a/spec/support/gitlab_stubs/gitlab_ci_for_sast.yml b/spec/support/gitlab_stubs/gitlab_ci_for_sast.yml
index d20078c8904..0e021a85ba6 100644
--- a/spec/support/gitlab_stubs/gitlab_ci_for_sast.yml
+++ b/spec/support/gitlab_stubs/gitlab_ci_for_sast.yml
@@ -4,7 +4,6 @@ include:
variables:
SECURE_ANALYZERS_PREFIX: "registry.gitlab.com/gitlab-org/security-products/analyzers2"
SAST_EXCLUDED_PATHS: "spec, executables"
- SAST_DEFAULT_ANALYZERS: "bandit, brakeman"
SAST_EXCLUDED_ANALYZERS: "brakeman"
stages:
diff --git a/spec/support/gitlab_stubs/gitlab_ci_for_sast_default_analyzers.yml b/spec/support/gitlab_stubs/gitlab_ci_for_sast_default_analyzers.yml
deleted file mode 100644
index c4f3c3aace2..00000000000
--- a/spec/support/gitlab_stubs/gitlab_ci_for_sast_default_analyzers.yml
+++ /dev/null
@@ -1,15 +0,0 @@
-include:
- - template: SAST.gitlab-ci.yml
-
-variables:
- SECURE_ANALYZERS_PREFIX: "registry.gitlab.com/gitlab-org/security-products/analyzers2"
- SAST_EXCLUDED_PATHS: "spec, executables"
- SAST_DEFAULT_ANALYZERS: "bandit, gosec"
-
-stages:
- - our_custom_security_stage
-sast:
- stage: our_custom_security_stage
- variables:
- SEARCH_MAX_DEPTH: 8
- SAST_BRAKEMAN_LEVEL: 2
diff --git a/spec/support/helpers/access_matchers_helpers.rb b/spec/support/helpers/access_matchers_helpers.rb
index 9100f245d36..035653172c1 100644
--- a/spec/support/helpers/access_matchers_helpers.rb
+++ b/spec/support/helpers/access_matchers_helpers.rb
@@ -1,6 +1,8 @@
# frozen_string_literal: true
module AccessMatchersHelpers
+ include Gitlab::Utils::StrongMemoize
+
USER_ACCESSOR_METHOD_NAME = 'user'
def provide_user(role, membership = nil)
@@ -61,11 +63,6 @@ module AccessMatchersHelpers
# (or defined by `method_name`) method generated by `let` definition in example group before it's used by `subject`.
# This override is per concrete example only because the example group class gets re-created for each example.
instance_eval(<<~CODE, __FILE__, __LINE__ + 1)
- if instance_variable_get(:@__#{USER_ACCESSOR_METHOD_NAME}_patched)
- raise ArgumentError, 'An access matcher be_allowed_for/be_denied_for can be used only once per example (`it` block)'
- end
- instance_variable_set(:@__#{USER_ACCESSOR_METHOD_NAME}_patched, true)
-
def #{USER_ACCESSOR_METHOD_NAME}
@#{USER_ACCESSOR_METHOD_NAME} ||= User.find(#{user.id})
end
@@ -81,6 +78,13 @@ module AccessMatchersHelpers
end
end
+ def reset_matcher_environment
+ instance_eval(<<~CODE, __FILE__, __LINE__ + 1)
+ clear_memoization(:#{USER_ACCESSOR_METHOD_NAME})
+ undef #{USER_ACCESSOR_METHOD_NAME} if defined? user
+ CODE
+ end
+
def run_matcher(action, role, membership, owned_objects)
raise_if_non_block_expectation!(action)
@@ -91,5 +95,7 @@ module AccessMatchersHelpers
else
action.call
end
+
+ reset_matcher_environment
end
end
diff --git a/spec/support/helpers/cycle_analytics_helpers.rb b/spec/support/helpers/cycle_analytics_helpers.rb
index 5510284b30d..4515b96c79e 100644
--- a/spec/support/helpers/cycle_analytics_helpers.rb
+++ b/spec/support/helpers/cycle_analytics_helpers.rb
@@ -7,6 +7,11 @@ module CycleAnalyticsHelpers
page.find('[data-testid="dropdown-value-streams"]').click
end
+ def path_nav_stage_names_without_median
+ # Returns the path names with the median value stripped out
+ page.all('.gl-path-button').collect(&:text).map {|name_with_median| name_with_median.split("\n")[0] }
+ end
+
def add_custom_stage_to_form
page.find_button(s_('CreateValueStreamForm|Add another stage')).click
diff --git a/spec/support/helpers/feature_flag_helpers.rb b/spec/support/helpers/feature_flag_helpers.rb
index 93cd915879b..af7a674f3bc 100644
--- a/spec/support/helpers/feature_flag_helpers.rb
+++ b/spec/support/helpers/feature_flag_helpers.rb
@@ -1,7 +1,7 @@
# frozen_string_literal: true
module FeatureFlagHelpers
- def create_flag(project, name, active = true, description: nil, version: Operations::FeatureFlag.versions['legacy_flag'])
+ def create_flag(project, name, active = true, description: nil, version: Operations::FeatureFlag.versions['new_version_flag'])
create(:operations_feature_flag, name: name, active: active, version: version,
description: description, project: project)
end
@@ -90,6 +90,5 @@ module FeatureFlagHelpers
def expect_user_to_see_feature_flags_index_page
expect(page).to have_text('Feature Flags')
- expect(page).to have_text('Lists')
end
end
diff --git a/spec/support/helpers/features/top_nav_spec_helpers.rb b/spec/support/helpers/features/top_nav_spec_helpers.rb
new file mode 100644
index 00000000000..ab664ce4283
--- /dev/null
+++ b/spec/support/helpers/features/top_nav_spec_helpers.rb
@@ -0,0 +1,53 @@
+# frozen_string_literal: true
+
+# These helpers help you interact within the Editor Lite (single-file editor, snippets, etc.).
+#
+module Spec
+ module Support
+ module Helpers
+ module Features
+ module TopNavSpecHelpers
+ def open_top_nav
+ return unless Feature.enabled?(:combined_menu, default_enabled: :yaml)
+
+ find('.js-top-nav-dropdown-toggle').click
+ end
+
+ def within_top_nav
+ if Feature.enabled?(:combined_menu, default_enabled: :yaml)
+ within('.js-top-nav-dropdown-menu') do
+ yield
+ end
+ else
+ within('.navbar-sub-nav') do
+ yield
+ end
+ end
+ end
+
+ def open_top_nav_projects
+ if Feature.enabled?(:combined_menu, default_enabled: :yaml)
+ open_top_nav
+
+ within_top_nav do
+ click_button('Projects')
+ end
+ else
+ find('#nav-projects-dropdown').click
+ end
+ end
+
+ def open_top_nav_groups
+ return unless Feature.enabled?(:combined_menu, default_enabled: :yaml)
+
+ open_top_nav
+
+ within_top_nav do
+ click_button('Groups')
+ end
+ end
+ end
+ end
+ end
+ end
+end
diff --git a/spec/support/helpers/gitaly_setup.rb b/spec/support/helpers/gitaly_setup.rb
index 2ce4bcfa943..5cfd03ecea8 100644
--- a/spec/support/helpers/gitaly_setup.rb
+++ b/spec/support/helpers/gitaly_setup.rb
@@ -15,7 +15,7 @@ module GitalySetup
default_name = ENV['CI'] ? 'DEBUG' : 'WARN'
level_name = ENV['GITLAB_TESTING_LOG_LEVEL']&.upcase
level = Logger.const_get(level_name || default_name, true) # rubocop: disable Gitlab/ConstGetInheritFalse
- Logger.new(STDOUT, level: level, formatter: ->(_, _, _, msg) { msg })
+ Logger.new($stdout, level: level, formatter: ->(_, _, _, msg) { msg })
end
def tmp_tests_gitaly_dir
@@ -153,7 +153,7 @@ module GitalySetup
end
LOGGER.debug "Checking gitaly-ruby bundle...\n"
- out = ENV['CI'] ? STDOUT : '/dev/null'
+ out = ENV['CI'] ? $stdout : '/dev/null'
abort 'bundle check failed' unless system(env, 'bundle', 'check', out: out, chdir: File.dirname(gemfile))
end
diff --git a/spec/support/helpers/global_id_deprecation_helpers.rb b/spec/support/helpers/global_id_deprecation_helpers.rb
new file mode 100644
index 00000000000..37ba1420fb3
--- /dev/null
+++ b/spec/support/helpers/global_id_deprecation_helpers.rb
@@ -0,0 +1,13 @@
+# frozen_string_literal: true
+
+module GlobalIDDeprecationHelpers
+ def stub_global_id_deprecations(*deprecations)
+ old_name_map = deprecations.index_by(&:old_model_name)
+ new_name_map = deprecations.index_by(&:new_model_name)
+ old_graphql_name_map = deprecations.index_by { |d| Types::GlobalIDType.model_name_to_graphql_name(d.old_model_name) }
+
+ stub_const('Gitlab::GlobalId::Deprecations::OLD_NAME_MAP', old_name_map)
+ stub_const('Gitlab::GlobalId::Deprecations::NEW_NAME_MAP', new_name_map)
+ stub_const('Gitlab::GlobalId::Deprecations::OLD_GRAPHQL_NAME_MAP', old_graphql_name_map)
+ end
+end
diff --git a/spec/support/helpers/graphql_helpers.rb b/spec/support/helpers/graphql_helpers.rb
index 5dc6945ec5e..4857fa63114 100644
--- a/spec/support/helpers/graphql_helpers.rb
+++ b/spec/support/helpers/graphql_helpers.rb
@@ -1,6 +1,10 @@
# frozen_string_literal: true
module GraphqlHelpers
+ def self.included(base)
+ base.include(::Gitlab::Graphql::Laziness)
+ end
+
MutationDefinition = Struct.new(:query, :variables)
NoData = Class.new(StandardError)
diff --git a/spec/support/helpers/javascript_fixtures_helpers.rb b/spec/support/helpers/javascript_fixtures_helpers.rb
index 28375c1d51e..8fd8a548011 100644
--- a/spec/support/helpers/javascript_fixtures_helpers.rb
+++ b/spec/support/helpers/javascript_fixtures_helpers.rb
@@ -66,6 +66,14 @@ module JavaScriptFixturesHelpers
File.write(full_fixture_path, fixture)
end
+ def parse_html(fixture)
+ if respond_to?(:use_full_html) && public_send(:use_full_html)
+ Nokogiri::HTML::Document.parse(fixture)
+ else
+ Nokogiri::HTML::DocumentFragment.parse(fixture)
+ end
+ end
+
# Private: Prepare a response object for use as a frontend fixture
#
# response - response object to prepare
@@ -76,7 +84,7 @@ module JavaScriptFixturesHelpers
response_mime_type = Mime::Type.lookup(response.media_type)
if response_mime_type.html?
- doc = Nokogiri::HTML::DocumentFragment.parse(fixture)
+ doc = parse_html(fixture)
link_tags = doc.css('link')
link_tags.remove
diff --git a/spec/support/helpers/login_helpers.rb b/spec/support/helpers/login_helpers.rb
index fc3eb976276..cc88a3fc71e 100644
--- a/spec/support/helpers/login_helpers.rb
+++ b/spec/support/helpers/login_helpers.rb
@@ -77,7 +77,11 @@ module LoginHelpers
# Requires Javascript driver.
def gitlab_disable_admin_mode
- click_on 'Leave Admin Mode'
+ open_top_nav
+
+ within_top_nav do
+ click_on 'Leave Admin Mode'
+ end
end
private
diff --git a/spec/support/helpers/query_recorder.rb b/spec/support/helpers/query_recorder.rb
index 05afbc336da..d18a1d23584 100644
--- a/spec/support/helpers/query_recorder.rb
+++ b/spec/support/helpers/query_recorder.rb
@@ -2,15 +2,16 @@
module ActiveRecord
class QueryRecorder
- attr_reader :log, :skip_cached, :cached, :data
+ attr_reader :log, :skip_cached, :skip_schema_queries, :cached, :data
UNKNOWN = %w[unknown unknown].freeze
- def initialize(skip_cached: true, log_file: nil, query_recorder_debug: false, &block)
+ def initialize(skip_cached: true, skip_schema_queries: true, log_file: nil, query_recorder_debug: false, &block)
@data = Hash.new { |h, k| h[k] = { count: 0, occurrences: [], backtrace: [], durations: [] } }
@log = []
@cached = []
@skip_cached = skip_cached
+ @skip_schema_queries = skip_schema_queries
@query_recorder_debug = ENV['QUERY_RECORDER_DEBUG'] || query_recorder_debug
@log_file = log_file
record(&block) if block_given?
@@ -79,7 +80,7 @@ module ActiveRecord
if values[:cached] && skip_cached
@cached << values[:sql]
- elsif !values[:name]&.include?("SCHEMA")
+ elsif !skip_schema_queries || !values[:name]&.include?("SCHEMA")
backtrace = @query_recorder_debug ? show_backtrace(values, duration) : nil
@log << values[:sql]
store_sql_by_source(values: values, duration: duration, backtrace: backtrace)
diff --git a/spec/support/helpers/rake_helpers.rb b/spec/support/helpers/rake_helpers.rb
index d8f354a69da..4c0fa9d1b0b 100644
--- a/spec/support/helpers/rake_helpers.rb
+++ b/spec/support/helpers/rake_helpers.rb
@@ -10,11 +10,6 @@ module RakeHelpers
allow(main_object).to receive(:warn_user_is_not_gitlab)
end
- def silence_output
- allow(main_object).to receive(:puts)
- allow(main_object).to receive(:print)
- end
-
def silence_progress_bar
allow_any_instance_of(ProgressBar::Output).to receive(:stream).and_return(double.as_null_object)
end
diff --git a/spec/support/helpers/reference_parser_helpers.rb b/spec/support/helpers/reference_parser_helpers.rb
index e65cb8c96db..a6a7948d9d9 100644
--- a/spec/support/helpers/reference_parser_helpers.rb
+++ b/spec/support/helpers/reference_parser_helpers.rb
@@ -11,20 +11,20 @@ module ReferenceParserHelpers
end
RSpec.shared_examples 'no project N+1 queries' do
- it 'avoids N+1 queries in #nodes_visible_to_user', :request_store do
+ it 'avoids N+1 queries in #nodes_visible_to_user' do
context = Banzai::RenderContext.new(project, user)
- record_queries = lambda do |links|
- ActiveRecord::QueryRecorder.new do
- described_class.new(context).nodes_visible_to_user(user, links)
- end
+ request = lambda do |links|
+ described_class.new(context).nodes_visible_to_user(user, links)
end
- control = record_queries.call(control_links)
- actual = record_queries.call(actual_links)
+ control = ActiveRecord::QueryRecorder.new { request.call(control_links) }
- expect(actual.count).to be <= control.count
- expect(actual.cached_count).to be <= control.cached_count
+ create(:group_member, group: project.group) if project.group
+ create(:project_member, project: project)
+ create(:project_group_link, project: project)
+
+ expect { request.call(actual_links) }.not_to exceed_query_limit(control)
end
end
diff --git a/spec/support/helpers/usage_data_helpers.rb b/spec/support/helpers/usage_data_helpers.rb
index c6176b5bcbc..b1a9aade043 100644
--- a/spec/support/helpers/usage_data_helpers.rb
+++ b/spec/support/helpers/usage_data_helpers.rb
@@ -99,7 +99,6 @@ module UsageDataHelpers
projects_with_repositories_enabled
projects_with_error_tracking_enabled
projects_with_enabled_alert_integrations
- projects_with_prometheus_alerts
projects_with_tracing_enabled
projects_with_expiration_policy_enabled
projects_with_expiration_policy_disabled
@@ -163,7 +162,6 @@ module UsageDataHelpers
database
prometheus_metrics_enabled
web_ide_clientside_preview_enabled
- ingress_modsecurity_enabled
object_store
topology
).freeze
diff --git a/spec/support/import_export/common_util.rb b/spec/support/import_export/common_util.rb
index a6b395ad4d5..5fb6af99b79 100644
--- a/spec/support/import_export/common_util.rb
+++ b/spec/support/import_export/common_util.rb
@@ -20,11 +20,11 @@ module ImportExport
def setup_reader(reader)
if reader == :ndjson_reader && Feature.enabled?(:project_import_ndjson, default_enabled: true)
- allow_any_instance_of(Gitlab::ImportExport::JSON::LegacyReader::File).to receive(:exist?).and_return(false)
- allow_any_instance_of(Gitlab::ImportExport::JSON::NdjsonReader).to receive(:exist?).and_return(true)
+ allow_any_instance_of(Gitlab::ImportExport::Json::LegacyReader::File).to receive(:exist?).and_return(false)
+ allow_any_instance_of(Gitlab::ImportExport::Json::NdjsonReader).to receive(:exist?).and_return(true)
else
- allow_any_instance_of(Gitlab::ImportExport::JSON::LegacyReader::File).to receive(:exist?).and_return(true)
- allow_any_instance_of(Gitlab::ImportExport::JSON::NdjsonReader).to receive(:exist?).and_return(false)
+ allow_any_instance_of(Gitlab::ImportExport::Json::LegacyReader::File).to receive(:exist?).and_return(true)
+ allow_any_instance_of(Gitlab::ImportExport::Json::NdjsonReader).to receive(:exist?).and_return(false)
end
end
diff --git a/spec/support/matchers/be_one_of.rb b/spec/support/matchers/be_one_of.rb
new file mode 100644
index 00000000000..16ee32b67c3
--- /dev/null
+++ b/spec/support/matchers/be_one_of.rb
@@ -0,0 +1,11 @@
+# frozen_string_literal: true
+
+RSpec::Matchers.define :be_one_of do |collection|
+ match do |item|
+ expect(collection).to include(item)
+ end
+
+ failure_message do |item|
+ "expected #{item} to be one of #{collection}"
+ end
+end
diff --git a/spec/support/redis.rb b/spec/support/redis.rb
index 8539f202602..eeeb93fa811 100644
--- a/spec/support/redis.rb
+++ b/spec/support/redis.rb
@@ -30,4 +30,12 @@ RSpec.configure do |config|
redis_queues_cleanup!
end
+
+ config.around(:each, :clean_gitlab_redis_trace_chunks) do |example|
+ redis_trace_chunks_cleanup!
+
+ example.run
+
+ redis_trace_chunks_cleanup!
+ end
end
diff --git a/spec/support/redis/redis_helpers.rb b/spec/support/redis/redis_helpers.rb
index 7c571738a01..b8118bf94cc 100644
--- a/spec/support/redis/redis_helpers.rb
+++ b/spec/support/redis/redis_helpers.rb
@@ -17,4 +17,9 @@ module RedisHelpers
def redis_shared_state_cleanup!
Gitlab::Redis::SharedState.with(&:flushall)
end
+
+ # Usage: CI trace chunks
+ def redis_trace_chunks_cleanup!
+ Gitlab::Redis::TraceChunks.with(&:flushall)
+ end
end
diff --git a/spec/support/redis/redis_shared_examples.rb b/spec/support/redis/redis_shared_examples.rb
index f5f6a69738b..25eab5fd6e4 100644
--- a/spec/support/redis/redis_shared_examples.rb
+++ b/spec/support/redis/redis_shared_examples.rb
@@ -4,9 +4,22 @@ RSpec.shared_examples "redis_shared_examples" do
include StubENV
let(:test_redis_url) { "redis://redishost:#{redis_port}"}
+ let(:config_file_name) { instance_specific_config_file }
+ let(:config_old_format_socket) { "spec/fixtures/config/redis_old_format_socket.yml" }
+ let(:config_new_format_socket) { "spec/fixtures/config/redis_new_format_socket.yml" }
+ let(:old_socket_path) {"/path/to/old/redis.sock" }
+ let(:new_socket_path) {"/path/to/redis.sock" }
+ let(:config_old_format_host) { "spec/fixtures/config/redis_old_format_host.yml" }
+ let(:config_new_format_host) { "spec/fixtures/config/redis_new_format_host.yml" }
+ let(:redis_port) { 6379 }
+ let(:redis_database) { 99 }
+ let(:sentinel_port) { 26379 }
+ let(:config_with_environment_variable_inside) { "spec/fixtures/config/redis_config_with_env.yml"}
+ let(:config_env_variable_url) {"TEST_GITLAB_REDIS_URL"}
+ let(:rails_root) { Dir.mktmpdir('redis_shared_examples') }
before do
- stub_env(environment_config_file_name, Rails.root.join(config_file_name))
+ allow(described_class).to receive(:config_file_name).and_return(Rails.root.join(config_file_name).to_s)
clear_raw_config
end
@@ -14,8 +27,71 @@ RSpec.shared_examples "redis_shared_examples" do
clear_raw_config
end
+ describe '.config_file_name' do
+ subject { described_class.config_file_name }
+
+ 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)
+ FileUtils.mkdir_p(File.join(rails_root, 'config'))
+ end
+
+ after do
+ FileUtils.rm_rf(rails_root)
+ end
+
+ context 'when there is no config file anywhere' do
+ it { expect(subject).to be_nil }
+
+ context 'but resque.yml exists' do
+ before do
+ FileUtils.touch(File.join(rails_root, 'config', 'resque.yml'))
+ end
+
+ it { expect(subject).to eq("#{rails_root}/config/resque.yml") }
+
+ it 'returns a path that exists' do
+ expect(File.file?(subject)).to eq(true)
+ end
+
+ context 'and there is a global env override' do
+ before do
+ stub_env('GITLAB_REDIS_CONFIG_FILE', 'global override')
+ end
+
+ it { expect(subject).to eq('global override') }
+
+ context 'and there is an instance specific config file' do
+ before do
+ FileUtils.touch(File.join(rails_root, instance_specific_config_file))
+ end
+
+ it { expect(subject).to eq("#{rails_root}/#{instance_specific_config_file}") }
+
+ it 'returns a path that exists' do
+ expect(File.file?(subject)).to eq(true)
+ end
+
+ context 'and there is a specific env override' do
+ before do
+ stub_env(environment_config_file_name, 'instance specific override')
+ end
+
+ it { expect(subject).to eq('instance specific override') }
+ end
+ end
+ end
+ end
+ end
+ end
+
describe '.params' do
- subject { described_class.params }
+ subject { described_class.new(rails_env).params }
+
+ let(:rails_env) { 'development' }
+ let(:config_file_name) { config_old_format_socket }
it 'withstands mutation' do
params1 = described_class.params
@@ -58,15 +134,27 @@ RSpec.shared_examples "redis_shared_examples" do
context 'with new format' do
let(:config_file_name) { config_new_format_host }
- it 'returns hash with host, port, db, and password' do
- is_expected.to include(host: 'localhost', password: 'mynewpassword', port: redis_port, db: redis_database)
- is_expected.not_to have_key(:url)
+ where(:rails_env, :host) do
+ [
+ %w[development development-host],
+ %w[test test-host],
+ %w[production production-host]
+ ]
+ end
+
+ with_them do
+ it 'returns hash with host, port, db, and password' do
+ is_expected.to include(host: host, password: 'mynewpassword', port: redis_port, db: redis_database)
+ is_expected.not_to have_key(:url)
+ end
end
end
end
end
describe '.url' do
+ let(:config_file_name) { config_old_format_socket }
+
it 'withstands mutation' do
url1 = described_class.url
url2 = described_class.url
@@ -88,6 +176,12 @@ RSpec.shared_examples "redis_shared_examples" do
end
end
+ describe '.version' do
+ it 'returns a version' do
+ expect(described_class.version).to be_present
+ end
+ end
+
describe '._raw_config' do
subject { described_class._raw_config }
@@ -109,6 +203,8 @@ RSpec.shared_examples "redis_shared_examples" do
end
describe '.with' do
+ let(:config_file_name) { config_old_format_socket }
+
before do
clear_pool
end
@@ -140,17 +236,46 @@ RSpec.shared_examples "redis_shared_examples" do
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
+
+ after do
+ FileUtils.rm_rf(rails_root)
+ end
+
+ it 'can run an empty block' do
+ expect { described_class.with { nil } }.not_to raise_error
+ end
+ end
end
describe '#sentinels' do
- subject { described_class.new(Rails.env).sentinels }
+ subject { described_class.new(rails_env).sentinels }
+
+ let(:rails_env) { 'development' }
context 'when sentinels are defined' do
let(:config_file_name) { config_new_format_host }
- it 'returns an array of hashes with host and port keys' do
- is_expected.to include(host: 'localhost', port: sentinel_port)
- is_expected.to include(host: 'replica2', port: sentinel_port)
+ where(:rails_env, :hosts) do
+ [
+ ['development', %w[development-replica1 development-replica2]],
+ ['test', %w[test-replica1 test-replica2]],
+ ['production', %w[production-replica1 production-replica2]]
+ ]
+ end
+
+ with_them do
+ it 'returns an array of hashes with host and port keys' do
+ is_expected.to include(host: hosts[0], port: sentinel_port)
+ is_expected.to include(host: hosts[1], port: sentinel_port)
+ end
end
end
@@ -184,12 +309,6 @@ RSpec.shared_examples "redis_shared_examples" do
end
describe '#raw_config_hash' do
- it 'returns default redis url when no config file is present' do
- expect(subject).to receive(:fetch_config) { false }
-
- expect(subject.send(:raw_config_hash)).to eq(url: class_redis_url )
- end
-
it 'returns old-style single url config in a hash' do
expect(subject).to receive(:fetch_config) { test_redis_url }
expect(subject.send(:raw_config_hash)).to eq(url: test_redis_url)
diff --git a/spec/support/shared_contexts/changes_access_checks_shared_context.rb b/spec/support/shared_contexts/changes_access_checks_shared_context.rb
new file mode 100644
index 00000000000..ec3727b6d6c
--- /dev/null
+++ b/spec/support/shared_contexts/changes_access_checks_shared_context.rb
@@ -0,0 +1,40 @@
+# frozen_string_literal: true
+
+RSpec.shared_context 'changes access checks context' do
+ let_it_be(:user) { create(:user) }
+ let_it_be(:project) { create(:project, :repository) }
+
+ let(:user_access) { Gitlab::UserAccess.new(user, container: project) }
+ let(:protocol) { 'ssh' }
+ let(:timeout) { Gitlab::GitAccess::INTERNAL_TIMEOUT }
+ let(:oldrev) { 'be93687618e4b132087f430a4d8fc3a609c9b77c' }
+ let(:newrev) { '54fcc214b94e78d7a41a9a8fe6d87a5e59500e51' }
+ let(:ref) { 'refs/heads/master' }
+ let(:changes) do
+ [
+ # Update of existing branch
+ { oldrev: oldrev, newrev: newrev, ref: ref },
+ # Creation of new branch
+ { newrev: newrev, ref: 'refs/heads/something' },
+ # Deletion of branch
+ { oldrev: oldrev, ref: 'refs/heads/deleteme' }
+ ]
+ end
+
+ let(:logger) { Gitlab::Checks::TimedLogger.new(timeout: timeout) }
+ let(:changes_access) do
+ Gitlab::Checks::ChangesAccess.new(
+ changes,
+ project: project,
+ user_access: user_access,
+ protocol: protocol,
+ logger: logger
+ )
+ end
+
+ subject { described_class.new(changes_access) }
+
+ before do
+ project.add_developer(user)
+ end
+end
diff --git a/spec/support/shared_contexts/features/integrations/group_integrations_shared_context.rb b/spec/support/shared_contexts/features/integrations/group_integrations_shared_context.rb
new file mode 100644
index 00000000000..5996fcc6593
--- /dev/null
+++ b/spec/support/shared_contexts/features/integrations/group_integrations_shared_context.rb
@@ -0,0 +1,28 @@
+# frozen_string_literal: true
+
+RSpec.shared_context 'group integration activation' do
+ include_context 'instance and group integration activation'
+
+ let_it_be(:group) { create(:group) }
+ let_it_be(:user) { create(:user) }
+
+ before_all do
+ group.add_owner(user)
+ end
+
+ before do
+ sign_in(user)
+ end
+
+ def visit_group_integrations
+ visit group_settings_integrations_path(group)
+ end
+
+ def visit_group_integration(name)
+ visit_group_integrations
+
+ within('#content-body') do
+ click_link(name)
+ end
+ end
+end
diff --git a/spec/support/shared_contexts/features/integrations/instance_and_group_integrations_shared_context.rb b/spec/support/shared_contexts/features/integrations/instance_and_group_integrations_shared_context.rb
new file mode 100644
index 00000000000..58ee341f71f
--- /dev/null
+++ b/spec/support/shared_contexts/features/integrations/instance_and_group_integrations_shared_context.rb
@@ -0,0 +1,18 @@
+# frozen_string_literal: true
+
+RSpec.shared_context 'instance and group integration activation' do
+ include_context 'integration activation'
+
+ def click_save_integration
+ click_save_changes_button
+ click_save_settings_modal
+ end
+
+ def click_save_changes_button
+ click_button('Save changes')
+ end
+
+ def click_save_settings_modal
+ click_button('Save')
+ 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
new file mode 100644
index 00000000000..3b02db994a3
--- /dev/null
+++ b/spec/support/shared_contexts/features/integrations/instance_integrations_shared_context.rb
@@ -0,0 +1,24 @@
+# frozen_string_literal: true
+
+RSpec.shared_context 'instance integration activation' do
+ include_context 'instance and group integration activation'
+
+ let_it_be(:user) { create(:user, :admin) }
+
+ before do
+ sign_in(user)
+ gitlab_enable_admin_mode_sign_in(user)
+ end
+
+ def visit_instance_integrations
+ visit integrations_admin_application_settings_path
+ end
+
+ def visit_instance_integration(name)
+ visit_instance_integrations
+
+ within('#content-body') do
+ click_link(name)
+ end
+ end
+end
diff --git a/spec/support/shared_contexts/services_shared_context.rb b/spec/support/shared_contexts/features/integrations/integrations_shared_context.rb
index 34c92367efa..e532b42fd1c 100644
--- a/spec/support/shared_contexts/services_shared_context.rb
+++ b/spec/support/shared_contexts/features/integrations/integrations_shared_context.rb
@@ -5,8 +5,8 @@ Integration.available_services_names.each do |service|
include JiraServiceHelper if service == 'jira'
let(:dashed_service) { service.dasherize }
- let(:service_method) { "#{service}_service".to_sym }
- let(:service_klass) { Integration.service_name_to_model(service) }
+ let(:service_method) { Project.integration_association_name(service) }
+ let(:service_klass) { Integration.integration_name_to_model(service) }
let(:service_instance) { service_klass.new }
let(:service_fields) { service_instance.fields }
let(:service_attrs_list) { service_fields.inject([]) {|arr, hash| arr << hash[:name].to_sym } }
@@ -70,3 +70,9 @@ Integration.available_services_names.each do |service|
end
end
end
+
+RSpec.shared_context 'integration activation' do
+ def click_active_checkbox
+ find('label', text: 'Active').click
+ end
+end
diff --git a/spec/support/shared_contexts/project_service_jira_context.rb b/spec/support/shared_contexts/features/integrations/project_integrations_jira_context.rb
index 54bb9fd108e..54bb9fd108e 100644
--- a/spec/support/shared_contexts/project_service_jira_context.rb
+++ b/spec/support/shared_contexts/features/integrations/project_integrations_jira_context.rb
diff --git a/spec/support/shared_contexts/project_service_shared_context.rb b/spec/support/shared_contexts/features/integrations/project_integrations_shared_context.rb
index 0e3540a3e15..b10844320d0 100644
--- a/spec/support/shared_contexts/project_service_shared_context.rb
+++ b/spec/support/shared_contexts/features/integrations/project_integrations_shared_context.rb
@@ -1,6 +1,8 @@
# frozen_string_literal: true
RSpec.shared_context 'project service activation' do
+ include_context 'integration activation'
+
let(:project) { create(:project) }
let(:user) { create(:user) }
@@ -21,10 +23,6 @@ RSpec.shared_context 'project service activation' do
end
end
- def click_active_checkbox
- find('label', text: 'Active').click
- end
-
def click_save_integration
click_button('Save changes')
end
diff --git a/spec/support/shared_contexts/graphql/requests/packages_shared_context.rb b/spec/support/shared_contexts/graphql/requests/packages_shared_context.rb
new file mode 100644
index 00000000000..334b11c9f6e
--- /dev/null
+++ b/spec/support/shared_contexts/graphql/requests/packages_shared_context.rb
@@ -0,0 +1,33 @@
+# frozen_string_literal: true
+
+RSpec.shared_context 'package details setup' do
+ let_it_be(:project) { create(:project) }
+ let_it_be(:package) { create(:package, project: project) }
+
+ let(:package_global_id) { global_id_of(package) }
+
+ let(:depth) { 3 }
+ let(:excluded) { %w[metadata apiFuzzingCiConfiguration pipeline packageFiles] }
+ let(:package_files) { all_graphql_fields_for('PackageFile') }
+ let(:user) { project.owner }
+ let(:package_details) { graphql_data_at(:package) }
+ let(:metadata_response) { graphql_data_at(:package, :metadata) }
+ let(:first_file) { package.package_files.find { |f| global_id_of(f) == first_file_response['id'] } }
+ let(:package_files_response) { graphql_data_at(:package, :package_files, :nodes) }
+ let(:first_file_response) { graphql_data_at(:package, :package_files, :nodes, 0)}
+ let(:first_file_response_metadata) { graphql_data_at(:package, :package_files, :nodes, 0, :file_metadata)}
+
+ let(:query) do
+ graphql_query_for(:package, { id: package_global_id }, <<~FIELDS)
+ #{all_graphql_fields_for('PackageDetailsType', max_depth: depth, excluded: excluded)}
+ metadata {
+ #{metadata}
+ }
+ packageFiles {
+ nodes {
+ #{package_files}
+ }
+ }
+ FIELDS
+ end
+end
diff --git a/spec/support/shared_contexts/load_balancing_configuration_shared_context.rb b/spec/support/shared_contexts/load_balancing_configuration_shared_context.rb
new file mode 100644
index 00000000000..a61b8e9a074
--- /dev/null
+++ b/spec/support/shared_contexts/load_balancing_configuration_shared_context.rb
@@ -0,0 +1,19 @@
+# frozen_string_literal: true
+
+RSpec.shared_context 'clear DB Load Balancing configuration' do
+ def clear_load_balancing_configuration
+ proxy = ::Gitlab::Database::LoadBalancing.instance_variable_get(:@proxy)
+ proxy.load_balancer.release_host if proxy
+ ::Gitlab::Database::LoadBalancing.instance_variable_set(:@proxy, nil)
+
+ ::Gitlab::Database::LoadBalancing::Session.clear_session
+ end
+
+ around do |example|
+ clear_load_balancing_configuration
+
+ example.run
+
+ clear_load_balancing_configuration
+ end
+end
diff --git a/spec/support/shared_contexts/navbar_structure_context.rb b/spec/support/shared_contexts/navbar_structure_context.rb
index 4f8e88ae9da..c00b7203af6 100644
--- a/spec/support/shared_contexts/navbar_structure_context.rb
+++ b/spec/support/shared_contexts/navbar_structure_context.rb
@@ -18,8 +18,8 @@ RSpec.shared_context 'project navbar structure' do
{
nav_item: _('Security & Compliance'),
nav_sub_items: [
- _('Configuration'),
- (_('Audit Events') if Gitlab.ee?)
+ (_('Audit Events') if Gitlab.ee?),
+ _('Configuration')
]
}
end
@@ -71,8 +71,16 @@ RSpec.shared_context 'project navbar structure' do
]
end
+ let(:project_context_nav_item) do
+ {
+ nav_item: "#{project.name[0, 1].upcase} #{project.name}",
+ nav_sub_items: []
+ }
+ end
+
let(:structure) do
[
+ project_context_nav_item,
project_information_nav_item,
{
nav_item: _('Repository'),
@@ -200,8 +208,16 @@ RSpec.shared_context 'group navbar structure' do
]
end
+ let(:group_context_nav_item) do
+ {
+ nav_item: "#{group.name[0, 1].upcase} #{group.name}",
+ nav_sub_items: []
+ }
+ end
+
let(:structure) do
[
+ group_context_nav_item,
group_information_nav_item,
{
nav_item: _('Issues'),
diff --git a/spec/support/shared_contexts/policies/project_policy_shared_context.rb b/spec/support/shared_contexts/policies/project_policy_shared_context.rb
index 35dc709b5d9..d638ffcf8fa 100644
--- a/spec/support/shared_contexts/policies/project_policy_shared_context.rb
+++ b/spec/support/shared_contexts/policies/project_policy_shared_context.rb
@@ -26,7 +26,7 @@ RSpec.shared_context 'ProjectPolicy context' do
let(:base_reporter_permissions) do
%i[
admin_issue admin_issue_link admin_label admin_issue_board_list create_snippet
- download_code download_wiki_code fork_project metrics_dashboard
+ daily_statistics download_code download_wiki_code fork_project metrics_dashboard
read_build read_commit_status read_confidential_issues
read_container_image read_deployment read_environment read_merge_request
read_metrics_dashboard_annotation read_pipeline read_prometheus
@@ -44,7 +44,7 @@ RSpec.shared_context 'ProjectPolicy context' do
create_commit_status create_container_image create_deployment
create_environment create_merge_request_from
create_metrics_dashboard_annotation create_pipeline create_release
- create_wiki daily_statistics delete_metrics_dashboard_annotation
+ create_wiki delete_metrics_dashboard_annotation
destroy_container_image push_code read_pod_logs read_terraform_state
resolve_note update_build update_commit_status update_container_image
update_deployment update_environment update_merge_request
diff --git a/spec/support/shared_contexts/read_ci_configuration_shared_context.rb b/spec/support/shared_contexts/read_ci_configuration_shared_context.rb
index 04c50171766..f5d70d5ef5a 100644
--- a/spec/support/shared_contexts/read_ci_configuration_shared_context.rb
+++ b/spec/support/shared_contexts/read_ci_configuration_shared_context.rb
@@ -5,10 +5,6 @@ RSpec.shared_context 'read ci configuration for sast enabled project' do
File.read(Rails.root.join('spec/support/gitlab_stubs/gitlab_ci_for_sast.yml'))
end
- let_it_be(:gitlab_ci_yml_default_analyzers_content) do
- File.read(Rails.root.join('spec/support/gitlab_stubs/gitlab_ci_for_sast_default_analyzers.yml'))
- end
-
let_it_be(:gitlab_ci_yml_excluded_analyzers_content) do
File.read(Rails.root.join('spec/support/gitlab_stubs/gitlab_ci_for_sast_excluded_analyzers.yml'))
end
diff --git a/spec/support/shared_contexts/requests/api/conan_packages_shared_context.rb b/spec/support/shared_contexts/requests/api/conan_packages_shared_context.rb
index ac53be1a1cb..c69a987c00d 100644
--- a/spec/support/shared_contexts/requests/api/conan_packages_shared_context.rb
+++ b/spec/support/shared_contexts/requests/api/conan_packages_shared_context.rb
@@ -8,11 +8,11 @@ RSpec.shared_context 'conan api setup' do
let_it_be(:personal_access_token) { create(:personal_access_token) }
let_it_be(:user) { personal_access_token.user }
let_it_be(:base_secret) { SecureRandom.base64(64) }
- let_it_be(:job) { create(:ci_build, :running, user: user) }
- let_it_be(:job_token) { job.token }
let_it_be(:deploy_token) { create(:deploy_token, read_package_registry: true, write_package_registry: true) }
let(:project) { package.project }
+ let(:job) { create(:ci_build, :running, user: user, project: project) }
+ let(:job_token) { job.token }
let(:auth_token) { personal_access_token.token }
let(:project_deploy_token) { create(:project_deploy_token, deploy_token: deploy_token, project: project) }
diff --git a/spec/support/shared_contexts/requests/api/helm_packages_shared_context.rb b/spec/support/shared_contexts/requests/api/helm_packages_shared_context.rb
new file mode 100644
index 00000000000..099fdec0cc8
--- /dev/null
+++ b/spec/support/shared_contexts/requests/api/helm_packages_shared_context.rb
@@ -0,0 +1,10 @@
+# frozen_string_literal: true
+
+RSpec.shared_context 'helm api setup' do
+ include WorkhorseHelpers
+ include PackagesManagerApiSpecHelpers
+ include HttpBasicAuthHelpers
+
+ let_it_be(:user) { create(:user) }
+ let_it_be(:personal_access_token) { create(:personal_access_token, user: user) }
+end
diff --git a/spec/support/shared_contexts/requests/api/npm_packages_shared_context.rb b/spec/support/shared_contexts/requests/api/npm_packages_shared_context.rb
index 815108be447..c737091df48 100644
--- a/spec/support/shared_contexts/requests/api/npm_packages_shared_context.rb
+++ b/spec/support/shared_contexts/requests/api/npm_packages_shared_context.rb
@@ -11,7 +11,7 @@ RSpec.shared_context 'npm api setup' do
let_it_be(:package, reload: true) { create(:npm_package, project: project, name: "@#{group.path}/scoped_package") }
let_it_be(:token) { create(:oauth_access_token, scopes: 'api', resource_owner: user) }
let_it_be(:personal_access_token) { create(:personal_access_token, user: user) }
- let_it_be(:job, reload: true) { create(:ci_build, user: user, status: :running) }
+ let_it_be(:job, reload: true) { create(:ci_build, user: user, status: :running, project: project) }
let_it_be(:deploy_token) { create(:deploy_token, read_package_registry: true, write_package_registry: true) }
let_it_be(:project_deploy_token) { create(:project_deploy_token, deploy_token: deploy_token, project: project) }
diff --git a/spec/support/shared_contexts/services/packages/debian/distribution_shared_context.rb b/spec/support/shared_contexts/services/packages/debian/distribution_shared_context.rb
new file mode 100644
index 00000000000..67e2c0629cc
--- /dev/null
+++ b/spec/support/shared_contexts/services/packages/debian/distribution_shared_context.rb
@@ -0,0 +1,20 @@
+# frozen_string_literal: true
+
+RSpec.shared_context 'with published Debian package' do
+ let_it_be(:group) { create(:group, :public) }
+ let_it_be(:project) { create(:project, :public, group: group) }
+ let_it_be(:project_distribution) { create(:debian_project_distribution, container: project, codename: 'unstable', valid_time_duration_seconds: 48.hours.to_i) }
+ let_it_be(:package) { create(:debian_package, project: project, published_in: project_distribution) }
+end
+
+RSpec.shared_context 'with Debian distribution' do |container_type|
+ let_it_be(:container_type) { container_type }
+
+ if container_type == :project
+ let_it_be(:container) { project }
+ let_it_be(:distribution, reload: true) { project_distribution }
+ else
+ let_it_be(:container) { group }
+ let_it_be(:distribution, reload: true) { create(:debian_group_distribution, container: group, codename: 'unstable', valid_time_duration_seconds: 48.hours.to_i) }
+ end
+end
diff --git a/spec/support/shared_contexts/change_access_checks_shared_context.rb b/spec/support/shared_contexts/single_change_access_checks_shared_context.rb
index 4c55990c901..bf90c26047b 100644
--- a/spec/support/shared_contexts/change_access_checks_shared_context.rb
+++ b/spec/support/shared_contexts/single_change_access_checks_shared_context.rb
@@ -12,7 +12,7 @@ RSpec.shared_context 'change access checks context' do
let(:timeout) { Gitlab::GitAccess::INTERNAL_TIMEOUT }
let(:logger) { Gitlab::Checks::TimedLogger.new(timeout: timeout) }
let(:change_access) do
- Gitlab::Checks::ChangeAccess.new(
+ Gitlab::Checks::SingleChangeAccess.new(
changes,
project: project,
user_access: user_access,
diff --git a/spec/support/shared_examples/ci/badge_template_shared_examples.rb b/spec/support/shared_examples/ci/badge_template_shared_examples.rb
new file mode 100644
index 00000000000..94aec33ecc2
--- /dev/null
+++ b/spec/support/shared_examples/ci/badge_template_shared_examples.rb
@@ -0,0 +1,57 @@
+# frozen_string_literal: true
+
+RSpec.shared_examples 'a badge template' do |badge_type|
+ describe '#key_text' do
+ it "says #{badge_type} by default" do
+ expect(template.key_text).to eq(badge_type)
+ end
+
+ context 'when custom key_text is defined' do
+ before do
+ allow(badge).to receive(:customization).and_return({ key_text: "custom text" })
+ end
+
+ it 'returns custom value' do
+ expect(template.key_text).to eq("custom text")
+ end
+
+ context 'when its size is larger than the max allowed value' do
+ before do
+ allow(badge).to receive(:customization).and_return({ key_text: 't' * (::Gitlab::Ci::Badge::Template::MAX_KEY_TEXT_SIZE + 1) } )
+ end
+
+ it 'returns default value' do
+ expect(template.key_text).to eq(badge_type)
+ end
+ end
+ end
+ end
+
+ describe '#key_width' do
+ let_it_be(:default_key_width) { ::Gitlab::Ci::Badge::Template::DEFAULT_KEY_WIDTH }
+
+ it 'is fixed by default' do
+ expect(template.key_width).to eq(default_key_width)
+ end
+
+ context 'when custom key_width is defined' do
+ before do
+ allow(badge).to receive(:customization).and_return({ key_width: 101 })
+ end
+
+ it 'returns custom value' do
+ expect(template.key_width).to eq(101)
+ end
+
+ context 'when it is larger than the max allowed value' do
+ before do
+ allow(badge).to receive(:customization).and_return({ key_width: ::Gitlab::Ci::Badge::Template::MAX_KEY_WIDTH + 1 })
+ end
+
+ it 'returns default value' do
+ expect(template.key_width).to eq(default_key_width)
+ end
+ end
+ end
+ end
+end
diff --git a/spec/support/shared_examples/controllers/wiki_actions_shared_examples.rb b/spec/support/shared_examples/controllers/wiki_actions_shared_examples.rb
index cfee26a0d6a..9af35c189d0 100644
--- a/spec/support/shared_examples/controllers/wiki_actions_shared_examples.rb
+++ b/spec/support/shared_examples/controllers/wiki_actions_shared_examples.rb
@@ -298,7 +298,7 @@ RSpec.shared_examples 'wiki controller actions' do
expect(response.headers['Content-Disposition']).to match(/^inline/)
expect(response.headers[Gitlab::Workhorse::DETECT_HEADER]).to eq('true')
expect(response.cache_control[:public]).to be(false)
- expect(response.cache_control[:extras]).to include('no-store')
+ expect(response.headers['Cache-Control']).to eq('no-store')
end
end
end
@@ -486,7 +486,7 @@ RSpec.shared_examples 'wiki controller actions' do
end.not_to change { wiki.list_pages.size }
expect(response).to render_template('shared/wikis/edit')
- expect(assigns(:error).message).to eq('Could not delete wiki page')
+ expect(assigns(:error)).to eq('Could not delete wiki page')
end
end
end
diff --git a/spec/support/shared_examples/features/discussion_comments_shared_example.rb b/spec/support/shared_examples/features/discussion_comments_shared_example.rb
index 808e0be6be2..ff2878f77b4 100644
--- a/spec/support/shared_examples/features/discussion_comments_shared_example.rb
+++ b/spec/support/shared_examples/features/discussion_comments_shared_example.rb
@@ -11,6 +11,8 @@ RSpec.shared_examples 'thread comments for commit and snippet' do |resource_name
let(:comment) { 'My comment' }
it 'clicking "Comment" will post a comment' do
+ wait_for_all_requests
+
expect(page).to have_selector toggle_selector
find("#{form_selector} .note-textarea").send_keys(comment)
@@ -29,6 +31,8 @@ RSpec.shared_examples 'thread comments for commit and snippet' do |resource_name
find("#{form_selector} .note-textarea").send_keys(comment)
find(toggle_selector).click
+
+ wait_for_all_requests
end
it 'has a "Comment" item (selected by default) and "Start thread" item' do
diff --git a/spec/support/shared_examples/features/integrations/user_activates_mattermost_slash_command_integration_shared_examples.rb b/spec/support/shared_examples/features/integrations/user_activates_mattermost_slash_command_integration_shared_examples.rb
new file mode 100644
index 00000000000..cfa043322db
--- /dev/null
+++ b/spec/support/shared_examples/features/integrations/user_activates_mattermost_slash_command_integration_shared_examples.rb
@@ -0,0 +1,34 @@
+# frozen_string_literal: true
+
+RSpec.shared_examples 'user activates the Mattermost Slash Command integration' do
+ it 'shows a help message' do
+ expect(page).to have_content('Use this service to perform common')
+ end
+
+ it 'shows a token placeholder' do
+ token_placeholder = find_field('service_token')['placeholder']
+
+ expect(token_placeholder).to eq('XXxxXXxxXXxxXXxxXXxxXXxx')
+ end
+
+ it 'redirects to the integrations page after saving but not activating' do
+ token = ('a'..'z').to_a.join
+
+ fill_in 'service_token', with: token
+ click_active_checkbox
+ click_save_integration
+
+ expect(current_path).to eq(edit_path)
+ expect(page).to have_content('Mattermost slash commands settings saved, but not active.')
+ end
+
+ it 'redirects to the integrations page after activating' do
+ token = ('a'..'z').to_a.join
+
+ fill_in 'service_token', with: token
+ click_save_integration
+
+ expect(current_path).to eq(edit_path)
+ expect(page).to have_content('Mattermost slash commands settings saved and active.')
+ end
+end
diff --git a/spec/support/shared_examples/features/issuable_invite_members_shared_examples.rb b/spec/support/shared_examples/features/issuable_invite_members_shared_examples.rb
index 736c353c2aa..c0cfc27ceaf 100644
--- a/spec/support/shared_examples/features/issuable_invite_members_shared_examples.rb
+++ b/spec/support/shared_examples/features/issuable_invite_members_shared_examples.rb
@@ -1,9 +1,12 @@
# frozen_string_literal: true
-RSpec.shared_examples 'issuable invite members experiments' do
+RSpec.shared_examples 'issuable invite members' do
context 'when a privileged user can invite' do
- it 'shows a link for inviting members and launches invite modal' do
+ before do
project.add_maintainer(user)
+ end
+
+ it 'shows a link for inviting members and launches invite modal' do
visit issuable_path
find('.block.assignee .edit-link').click
@@ -23,8 +26,11 @@ RSpec.shared_examples 'issuable invite members experiments' do
end
context 'when user cannot invite members in assignee dropdown' do
- it 'shows author in assignee dropdown and no invite link' do
+ before do
project.add_developer(user)
+ end
+
+ it 'shows author in assignee dropdown and no invite link' do
visit issuable_path
find('.block.assignee .edit-link').click
diff --git a/spec/support/shared_examples/features/variable_list_shared_examples.rb b/spec/support/shared_examples/features/variable_list_shared_examples.rb
index 4b94411f009..997500415a9 100644
--- a/spec/support/shared_examples/features/variable_list_shared_examples.rb
+++ b/spec/support/shared_examples/features/variable_list_shared_examples.rb
@@ -283,6 +283,8 @@ RSpec.shared_examples 'variable list' do
end
def fill_variable(key, value, protected: false, masked: false)
+ wait_for_requests
+
page.within('#add-ci-variable') do
find('[data-qa-selector="ci_variable_key_field"] input').set(key)
find('[data-qa-selector="ci_variable_value_field"]').set(value) if value.present?
diff --git a/spec/support/shared_examples/finders/assignees_filter_shared_examples.rb b/spec/support/shared_examples/finders/assignees_filter_shared_examples.rb
index 96b05db4cd9..5cbbed1468f 100644
--- a/spec/support/shared_examples/finders/assignees_filter_shared_examples.rb
+++ b/spec/support/shared_examples/finders/assignees_filter_shared_examples.rb
@@ -24,6 +24,12 @@ RSpec.shared_examples 'assignee NOT username filter' do
end
end
+RSpec.shared_examples 'assignee OR filter' do
+ it 'returns issuables assigned to the given users' do
+ expect(issuables).to contain_exactly(*expected_issuables)
+ end
+end
+
RSpec.shared_examples 'no assignee filter' do
let(:params) { { assignee_id: 'None' } }
diff --git a/spec/support/shared_examples/graphql/mutations/can_mutate_spammable_examples.rb b/spec/support/shared_examples/graphql/mutations/can_mutate_spammable_examples.rb
index fc795012ce7..5e15c91cd41 100644
--- a/spec/support/shared_examples/graphql/mutations/can_mutate_spammable_examples.rb
+++ b/spec/support/shared_examples/graphql/mutations/can_mutate_spammable_examples.rb
@@ -6,9 +6,9 @@ RSpec.shared_examples 'a mutation which can mutate a spammable' do
describe "#additional_spam_params" do
it 'passes additional spam params to the service' do
args = [
- anything,
- anything,
- hash_including(
+ project: anything,
+ current_user: anything,
+ params: hash_including(
api: true,
request: instance_of(ActionDispatch::Request),
captcha_response: captcha_response,
diff --git a/spec/support/shared_examples/graphql/mutations/resolves_subscription_shared_examples.rb b/spec/support/shared_examples/graphql/mutations/resolves_subscription_shared_examples.rb
index ebba312e895..678bb908343 100644
--- a/spec/support/shared_examples/graphql/mutations/resolves_subscription_shared_examples.rb
+++ b/spec/support/shared_examples/graphql/mutations/resolves_subscription_shared_examples.rb
@@ -2,44 +2,37 @@
require 'spec_helper'
-RSpec.shared_examples 'a subscribeable graphql resource' do
- let(:project) { resource.project }
- let_it_be(:user) { create(:user) }
-
- subject(:mutation) { described_class.new(object: nil, context: { current_user: user }, field: nil) }
+RSpec.shared_examples 'a subscribeable not accessible graphql resource' do
+ let(:mutation) { described_class.new(object: nil, context: { current_user: user }, field: nil) }
- specify { expect(described_class).to require_graphql_authorizations(permission_name) }
+ subject { mutation.resolve(project_path: resource.project.full_path, iid: resource.iid, subscribed_state: true) }
- describe '#resolve' do
- let(:subscribe) { true }
- let(:mutated_resource) { subject[resource.class.name.underscore.to_sym] }
-
- subject { mutation.resolve(project_path: resource.project.full_path, iid: resource.iid, subscribed_state: subscribe) }
+ it 'raises an error if the resource is not accessible to the user' do
+ expect { subject }.to raise_error(Gitlab::Graphql::Errors::ResourceNotAvailable)
+ end
+end
- it 'raises an error if the resource is not accessible to the user' do
- expect { subject }.to raise_error(Gitlab::Graphql::Errors::ResourceNotAvailable)
- end
+RSpec.shared_examples 'a subscribeable graphql resource' do
+ let(:mutated_resource) { subject[resource.class.name.underscore.to_sym] }
+ let(:mutation) { described_class.new(object: nil, context: { current_user: user }, field: nil) }
+ let(:subscribe) { true }
- context 'when the user can update the resource' do
- before do
- resource.project.add_developer(user)
- end
+ subject { mutation.resolve(project_path: resource.project.full_path, iid: resource.iid, subscribed_state: subscribe) }
- it 'subscribes to the resource' do
- expect(mutated_resource).to eq(resource)
- expect(mutated_resource.subscribed?(user, project)).to eq(true)
- expect(subject[:errors]).to be_empty
- end
+ it 'subscribes to the resource' do
+ expect(mutated_resource).to eq(resource)
+ expect(mutated_resource.subscribed?(user, project)).to eq(true)
+ expect(subject[:errors]).to be_empty
+ end
- context 'when passing subscribe as false' do
- let(:subscribe) { false }
+ context 'when passing subscribe as false' do
+ let(:subscribe) { false }
- it 'unsubscribes from the discussion' do
- resource.subscribe(user, project)
+ it 'unsubscribes from the discussion' do
+ resource.subscribe(user, project)
- expect(mutated_resource.subscribed?(user, project)).to eq(false)
- end
- end
+ expect(mutated_resource.subscribed?(user, project)).to eq(false)
+ expect(subject[:errors]).to be_empty
end
end
end
diff --git a/spec/support/shared_examples/lib/gitlab/ci/ci_trace_shared_examples.rb b/spec/support/shared_examples/lib/gitlab/ci/ci_trace_shared_examples.rb
index 9c95d1ff9d9..3760325675a 100644
--- a/spec/support/shared_examples/lib/gitlab/ci/ci_trace_shared_examples.rb
+++ b/spec/support/shared_examples/lib/gitlab/ci/ci_trace_shared_examples.rb
@@ -29,6 +29,34 @@ RSpec.shared_examples 'common trace features' do
end
end
+ describe '#read' do
+ context 'gitlab_ci_archived_trace_consistent_reads feature flag enabled' do
+ before do
+ stub_feature_flags(gitlab_ci_archived_trace_consistent_reads: trace.job.project)
+ end
+
+ it 'calls ::Gitlab::Database::LoadBalancing::Sticking.unstick_or_continue_sticking' do
+ expect(::Gitlab::Database::LoadBalancing::Sticking).to receive(:unstick_or_continue_sticking)
+ .with(described_class::LOAD_BALANCING_STICKING_NAMESPACE, trace.job.id)
+ .and_call_original
+
+ trace.read { |stream| stream }
+ end
+ end
+
+ context 'gitlab_ci_archived_trace_consistent_reads feature flag disabled' do
+ before do
+ stub_feature_flags(gitlab_ci_archived_trace_consistent_reads: false)
+ end
+
+ it 'does not call ::Gitlab::Database::LoadBalancing::Sticking.unstick_or_continue_sticking' do
+ expect(::Gitlab::Database::LoadBalancing::Sticking).not_to receive(:unstick_or_continue_sticking)
+
+ trace.read { |stream| stream }
+ end
+ end
+ end
+
describe '#extract_coverage' do
let(:regex) { '\(\d+.\d+\%\) covered' }
@@ -253,6 +281,52 @@ RSpec.shared_examples 'common trace features' do
describe '#archive!' do
subject { trace.archive! }
+ context 'when live trace chunks exists' do
+ before do
+ # Build a trace_chunk manually
+ # It is possible to do so with trace.set but only if ci_enable_live_trace FF is enabled
+ #
+ # We need the job to have a trace_chunk because we only use #stick in
+ # the case where trace_chunks exist.
+ stream = Gitlab::Ci::Trace::Stream.new do
+ Gitlab::Ci::Trace::ChunkedIO.new(trace.job)
+ end
+
+ stream.set(+"12\n34")
+ end
+
+ # We check the before setup actually sets up job trace_chunks
+ it 'has job trace_chunks' do
+ expect(trace.job.trace_chunks).to be_present
+ end
+
+ context 'gitlab_ci_archived_trace_consistent_reads feature flag enabled' do
+ before do
+ stub_feature_flags(gitlab_ci_archived_trace_consistent_reads: trace.job.project)
+ end
+
+ it 'calls ::Gitlab::Database::LoadBalancing::Sticking.stick' do
+ expect(::Gitlab::Database::LoadBalancing::Sticking).to receive(:stick)
+ .with(described_class::LOAD_BALANCING_STICKING_NAMESPACE, trace.job.id)
+ .and_call_original
+
+ subject
+ end
+ end
+
+ context 'gitlab_ci_archived_trace_consistent_reads feature flag disabled' do
+ before do
+ stub_feature_flags(gitlab_ci_archived_trace_consistent_reads: false)
+ end
+
+ it 'does not call ::Gitlab::Database::LoadBalancing::Sticking.stick' do
+ expect(::Gitlab::Database::LoadBalancing::Sticking).not_to receive(:stick)
+
+ subject
+ end
+ end
+ end
+
context 'when build status is success' do
let!(:build) { create(:ci_build, :success, :trace_live) }
diff --git a/spec/support/shared_examples/lib/gitlab/experimentation_shared_examples.rb b/spec/support/shared_examples/lib/gitlab/experimentation_shared_examples.rb
new file mode 100644
index 00000000000..5baa6478225
--- /dev/null
+++ b/spec/support/shared_examples/lib/gitlab/experimentation_shared_examples.rb
@@ -0,0 +1,20 @@
+# frozen_string_literal: true
+
+RSpec.shared_examples 'tracks assignment and records the subject' do |experiment, subject_type|
+ it 'tracks the assignment', :experiment do
+ expect(experiment(experiment))
+ .to track(:assignment)
+ .with_context(subject_type => subject)
+ .on_next_instance
+
+ action
+ end
+
+ it 'records the subject' do
+ stub_experiments(experiment => :candidate)
+
+ expect(Experiment).to receive(:add_subject).with(experiment.to_s, variant: :experimental, subject: subject)
+
+ action
+ end
+end
diff --git a/spec/support/shared_examples/models/chat_service_shared_examples.rb b/spec/support/shared_examples/models/chat_integration_shared_examples.rb
index 4a47aad0957..9f3be3e2e06 100644
--- a/spec/support/shared_examples/models/chat_service_shared_examples.rb
+++ b/spec/support/shared_examples/models/chat_integration_shared_examples.rb
@@ -1,13 +1,13 @@
# frozen_string_literal: true
-RSpec.shared_examples "chat service" do |service_name|
+RSpec.shared_examples "chat integration" do |integration_name|
describe "Associations" do
it { is_expected.to belong_to :project }
it { is_expected.to have_one :service_hook }
end
describe "Validations" do
- context "when service is active" do
+ context "when integration is active" do
before do
subject.active = true
end
@@ -16,7 +16,7 @@ RSpec.shared_examples "chat service" do |service_name|
it_behaves_like "issue tracker service URL attribute", :webhook
end
- context "when service is inactive" do
+ context "when integration is inactive" do
before do
subject.active = false
end
@@ -47,12 +47,12 @@ RSpec.shared_examples "chat service" do |service_name|
WebMock.stub_request(:post, webhook_url)
end
- shared_examples "triggered #{service_name} service" do |branches_to_be_notified: nil|
+ shared_examples "triggered #{integration_name} integration" do |branches_to_be_notified: nil|
before do
subject.branches_to_be_notified = branches_to_be_notified if branches_to_be_notified
end
- it "calls #{service_name} API" do
+ it "calls #{integration_name} API" do
result = subject.execute(sample_data)
expect(result).to be(true)
@@ -63,12 +63,12 @@ RSpec.shared_examples "chat service" do |service_name|
end
end
- shared_examples "untriggered #{service_name} service" do |branches_to_be_notified: nil|
+ shared_examples "untriggered #{integration_name} integration" do |branches_to_be_notified: nil|
before do
subject.branches_to_be_notified = branches_to_be_notified if branches_to_be_notified
end
- it "does not call #{service_name} API" do
+ it "does not call #{integration_name} API" do
result = subject.execute(sample_data)
expect(result).to be(false)
@@ -81,7 +81,7 @@ RSpec.shared_examples "chat service" do |service_name|
Gitlab::DataBuilder::Push.build_sample(project, user)
end
- it_behaves_like "triggered #{service_name} service"
+ it_behaves_like "triggered #{integration_name} integration"
it "specifies the webhook when it is configured", if: defined?(client) do
expect(client).to receive(:new).with(client_arguments).and_return(double(:chat_service).as_null_object)
@@ -95,19 +95,19 @@ RSpec.shared_examples "chat service" do |service_name|
end
context "when only default branch are to be notified" do
- it_behaves_like "triggered #{service_name} service", branches_to_be_notified: "default"
+ it_behaves_like "triggered #{integration_name} integration", branches_to_be_notified: "default"
end
context "when only protected branches are to be notified" do
- it_behaves_like "untriggered #{service_name} service", branches_to_be_notified: "protected"
+ it_behaves_like "untriggered #{integration_name} integration", branches_to_be_notified: "protected"
end
context "when default and protected branches are to be notified" do
- it_behaves_like "triggered #{service_name} service", branches_to_be_notified: "default_and_protected"
+ it_behaves_like "triggered #{integration_name} integration", branches_to_be_notified: "default_and_protected"
end
context "when all branches are to be notified" do
- it_behaves_like "triggered #{service_name} service", branches_to_be_notified: "all"
+ it_behaves_like "triggered #{integration_name} integration", branches_to_be_notified: "all"
end
end
@@ -121,19 +121,19 @@ RSpec.shared_examples "chat service" do |service_name|
end
context "when only default branch are to be notified" do
- it_behaves_like "untriggered #{service_name} service", branches_to_be_notified: "default"
+ it_behaves_like "untriggered #{integration_name} integration", branches_to_be_notified: "default"
end
context "when only protected branches are to be notified" do
- it_behaves_like "triggered #{service_name} service", branches_to_be_notified: "protected"
+ it_behaves_like "triggered #{integration_name} integration", branches_to_be_notified: "protected"
end
context "when default and protected branches are to be notified" do
- it_behaves_like "triggered #{service_name} service", branches_to_be_notified: "default_and_protected"
+ it_behaves_like "triggered #{integration_name} integration", branches_to_be_notified: "default_and_protected"
end
context "when all branches are to be notified" do
- it_behaves_like "triggered #{service_name} service", branches_to_be_notified: "all"
+ it_behaves_like "triggered #{integration_name} integration", branches_to_be_notified: "all"
end
end
@@ -143,19 +143,19 @@ RSpec.shared_examples "chat service" do |service_name|
end
context "when only default branch are to be notified" do
- it_behaves_like "untriggered #{service_name} service", branches_to_be_notified: "default"
+ it_behaves_like "untriggered #{integration_name} integration", branches_to_be_notified: "default"
end
context "when only protected branches are to be notified" do
- it_behaves_like "untriggered #{service_name} service", branches_to_be_notified: "protected"
+ it_behaves_like "untriggered #{integration_name} integration", branches_to_be_notified: "protected"
end
context "when default and protected branches are to be notified" do
- it_behaves_like "untriggered #{service_name} service", branches_to_be_notified: "default_and_protected"
+ it_behaves_like "untriggered #{integration_name} integration", branches_to_be_notified: "default_and_protected"
end
context "when all branches are to be notified" do
- it_behaves_like "triggered #{service_name} service", branches_to_be_notified: "all"
+ it_behaves_like "triggered #{integration_name} integration", branches_to_be_notified: "all"
end
end
end
@@ -168,7 +168,7 @@ RSpec.shared_examples "chat service" do |service_name|
service.hook_data(issue, "open")
end
- it_behaves_like "triggered #{service_name} service"
+ it_behaves_like "triggered #{integration_name} integration"
end
context "with merge events" do
@@ -191,7 +191,7 @@ RSpec.shared_examples "chat service" do |service_name|
project.add_developer(user)
end
- it_behaves_like "triggered #{service_name} service"
+ it_behaves_like "triggered #{integration_name} integration"
end
context "with wiki page events" do
@@ -207,7 +207,7 @@ RSpec.shared_examples "chat service" do |service_name|
let(:wiki_page) { create(:wiki_page, wiki: project.wiki, **opts) }
let(:sample_data) { Gitlab::DataBuilder::WikiPage.build(wiki_page, user, "create") }
- it_behaves_like "triggered #{service_name} service"
+ it_behaves_like "triggered #{integration_name} integration"
end
context "with note events" do
@@ -222,7 +222,7 @@ RSpec.shared_examples "chat service" do |service_name|
note: "a comment on a commit")
end
- it_behaves_like "triggered #{service_name} service"
+ it_behaves_like "triggered #{integration_name} integration"
end
context "with merge request comment" do
@@ -230,7 +230,7 @@ RSpec.shared_examples "chat service" do |service_name|
create(:note_on_merge_request, project: project, note: "merge request note")
end
- it_behaves_like "triggered #{service_name} service"
+ it_behaves_like "triggered #{integration_name} integration"
end
context "with issue comment" do
@@ -238,7 +238,7 @@ RSpec.shared_examples "chat service" do |service_name|
create(:note_on_issue, project: project, note: "issue note")
end
- it_behaves_like "triggered #{service_name} service"
+ it_behaves_like "triggered #{integration_name} integration"
end
context "with snippet comment" do
@@ -246,7 +246,7 @@ RSpec.shared_examples "chat service" do |service_name|
create(:note_on_project_snippet, project: project, note: "snippet note")
end
- it_behaves_like "triggered #{service_name} service"
+ it_behaves_like "triggered #{integration_name} integration"
end
end
@@ -262,14 +262,14 @@ RSpec.shared_examples "chat service" do |service_name|
context "with failed pipeline" do
let(:status) { "failed" }
- it_behaves_like "triggered #{service_name} service"
+ it_behaves_like "triggered #{integration_name} integration"
end
context "with succeeded pipeline" do
let(:status) { "success" }
context "with default notify_only_broken_pipelines" do
- it "does not call #{service_name} API" do
+ it "does not call #{integration_name} API" do
result = subject.execute(sample_data)
expect(result).to be_falsy
@@ -281,7 +281,7 @@ RSpec.shared_examples "chat service" do |service_name|
subject.notify_only_broken_pipelines = false
end
- it_behaves_like "triggered #{service_name} service"
+ it_behaves_like "triggered #{integration_name} integration"
end
end
@@ -291,19 +291,19 @@ RSpec.shared_examples "chat service" do |service_name|
end
context "when only default branch are to be notified" do
- it_behaves_like "triggered #{service_name} service", branches_to_be_notified: "default"
+ it_behaves_like "triggered #{integration_name} integration", branches_to_be_notified: "default"
end
context "when only protected branches are to be notified" do
- it_behaves_like "untriggered #{service_name} service", branches_to_be_notified: "protected"
+ it_behaves_like "untriggered #{integration_name} integration", branches_to_be_notified: "protected"
end
context "when default and protected branches are to be notified" do
- it_behaves_like "triggered #{service_name} service", branches_to_be_notified: "default_and_protected"
+ it_behaves_like "triggered #{integration_name} integration", branches_to_be_notified: "default_and_protected"
end
context "when all branches are to be notified" do
- it_behaves_like "triggered #{service_name} service", branches_to_be_notified: "all"
+ it_behaves_like "triggered #{integration_name} integration", branches_to_be_notified: "all"
end
end
@@ -317,19 +317,19 @@ RSpec.shared_examples "chat service" do |service_name|
end
context "when only default branch are to be notified" do
- it_behaves_like "untriggered #{service_name} service", branches_to_be_notified: "default"
+ it_behaves_like "untriggered #{integration_name} integration", branches_to_be_notified: "default"
end
context "when only protected branches are to be notified" do
- it_behaves_like "triggered #{service_name} service", branches_to_be_notified: "protected"
+ it_behaves_like "triggered #{integration_name} integration", branches_to_be_notified: "protected"
end
context "when default and protected branches are to be notified" do
- it_behaves_like "triggered #{service_name} service", branches_to_be_notified: "default_and_protected"
+ it_behaves_like "triggered #{integration_name} integration", branches_to_be_notified: "default_and_protected"
end
context "when all branches are to be notified" do
- it_behaves_like "triggered #{service_name} service", branches_to_be_notified: "all"
+ it_behaves_like "triggered #{integration_name} integration", branches_to_be_notified: "all"
end
end
@@ -339,19 +339,19 @@ RSpec.shared_examples "chat service" do |service_name|
end
context "when only default branch are to be notified" do
- it_behaves_like "untriggered #{service_name} service", branches_to_be_notified: "default"
+ it_behaves_like "untriggered #{integration_name} integration", branches_to_be_notified: "default"
end
context "when only protected branches are to be notified" do
- it_behaves_like "untriggered #{service_name} service", branches_to_be_notified: "protected"
+ it_behaves_like "untriggered #{integration_name} integration", branches_to_be_notified: "protected"
end
context "when default and protected branches are to be notified" do
- it_behaves_like "untriggered #{service_name} service", branches_to_be_notified: "default_and_protected"
+ it_behaves_like "untriggered #{integration_name} integration", branches_to_be_notified: "default_and_protected"
end
context "when all branches are to be notified" do
- it_behaves_like "triggered #{service_name} service", branches_to_be_notified: "all"
+ it_behaves_like "triggered #{integration_name} integration", branches_to_be_notified: "all"
end
end
end
diff --git a/spec/support/shared_examples/models/slack_mattermost_notifications_shared_examples.rb b/spec/support/shared_examples/models/concerns/integrations/slack_mattermost_notifier_shared_examples.rb
index 09b7d1be704..66448aca2c5 100644
--- a/spec/support/shared_examples/models/slack_mattermost_notifications_shared_examples.rb
+++ b/spec/support/shared_examples/models/concerns/integrations/slack_mattermost_notifier_shared_examples.rb
@@ -1,13 +1,13 @@
# frozen_string_literal: true
-RSpec.shared_examples 'slack or mattermost notifications' do |service_name|
+RSpec.shared_examples Integrations::SlackMattermostNotifier do |service_name|
include StubRequests
let(:chat_service) { described_class.new }
let(:webhook_url) { 'https://example.gitlab.com' }
def execute_with_options(options)
- receive(:new).with(webhook_url, options.merge(http_client: SlackMattermost::Notifier::HTTPClient))
+ receive(:new).with(webhook_url, options.merge(http_client: Integrations::SlackMattermostNotifier::HTTPClient))
.and_return(double(:slack_service).as_null_object)
end
@@ -81,7 +81,7 @@ RSpec.shared_examples 'slack or mattermost notifications' do |service_name|
shared_examples 'calls the service API with the event message' do |event_message|
specify do
- expect_next_instance_of(Slack::Messenger) do |messenger|
+ expect_next_instance_of(::Slack::Messenger) do |messenger|
expect(messenger).to receive(:ping).with(event_message, anything).and_call_original
end
@@ -95,7 +95,7 @@ RSpec.shared_examples 'slack or mattermost notifications' do |service_name|
let(:chat_service_params) { { username: 'slack_username' } }
it 'uses the username as an option' do
- expect(Slack::Messenger).to execute_with_options(username: 'slack_username')
+ expect(::Slack::Messenger).to execute_with_options(username: 'slack_username')
execute_service
end
@@ -110,7 +110,7 @@ RSpec.shared_examples 'slack or mattermost notifications' do |service_name|
let(:chat_service_params) { { push_channel: 'random' } }
it 'uses the right channel for push event' do
- expect(Slack::Messenger).to execute_with_options(channel: ['random'])
+ expect(::Slack::Messenger).to execute_with_options(channel: ['random'])
execute_service
end
@@ -128,6 +128,7 @@ RSpec.shared_examples 'slack or mattermost notifications' do |service_name|
context 'issue events' do
let_it_be(:issue) { create(:issue) }
+
let(:data) { issue.to_hook_data(user) }
it_behaves_like 'calls the service API with the event message', /Issue (.*?) opened by/
@@ -136,7 +137,7 @@ RSpec.shared_examples 'slack or mattermost notifications' do |service_name|
let(:chat_service_params) { { issue_channel: 'random' } }
it 'uses the right channel for issue event' do
- expect(Slack::Messenger).to execute_with_options(channel: ['random'])
+ expect(::Slack::Messenger).to execute_with_options(channel: ['random'])
execute_service
end
@@ -147,7 +148,7 @@ RSpec.shared_examples 'slack or mattermost notifications' do |service_name|
end
it 'falls back to issue channel' do
- expect(Slack::Messenger).to execute_with_options(channel: ['random'])
+ expect(::Slack::Messenger).to execute_with_options(channel: ['random'])
execute_service
end
@@ -156,7 +157,7 @@ RSpec.shared_examples 'slack or mattermost notifications' do |service_name|
let(:chat_service_params) { { issue_channel: 'random', confidential_issue_channel: 'confidential' } }
it 'uses the confidential issue channel when it is defined' do
- expect(Slack::Messenger).to execute_with_options(channel: ['confidential'])
+ expect(::Slack::Messenger).to execute_with_options(channel: ['confidential'])
execute_service
end
@@ -167,6 +168,7 @@ RSpec.shared_examples 'slack or mattermost notifications' do |service_name|
context 'merge request events' do
let_it_be(:merge_request) { create(:merge_request) }
+
let(:data) { merge_request.to_hook_data(user) }
it_behaves_like 'calls the service API with the event message', /opened merge request/
@@ -175,7 +177,7 @@ RSpec.shared_examples 'slack or mattermost notifications' do |service_name|
let(:chat_service_params) { { merge_request_channel: 'random' } }
it 'uses the right channel for merge request event' do
- expect(Slack::Messenger).to execute_with_options(channel: ['random'])
+ expect(::Slack::Messenger).to execute_with_options(channel: ['random'])
execute_service
end
@@ -184,15 +186,16 @@ RSpec.shared_examples 'slack or mattermost notifications' do |service_name|
context 'wiki page events' do
let_it_be(:wiki_page) { create(:wiki_page, wiki: project.wiki, message: 'user created page: Awesome wiki_page') }
+
let(:data) { Gitlab::DataBuilder::WikiPage.build(wiki_page, user, 'create') }
- it_behaves_like 'calls the service API with the event message', / created (.*?)wikis\/(.*?)|wiki page> in/
+ it_behaves_like 'calls the service API with the event message', %r{ created (.*?)wikis/(.*?)|wiki page> in}
context 'with event channel' do
let(:chat_service_params) { { wiki_page_channel: 'random' } }
it 'uses the right channel for wiki event' do
- expect(Slack::Messenger).to execute_with_options(channel: ['random'])
+ expect(::Slack::Messenger).to execute_with_options(channel: ['random'])
execute_service
end
@@ -201,6 +204,7 @@ RSpec.shared_examples 'slack or mattermost notifications' do |service_name|
context 'deployment events' do
let_it_be(:deployment) { create(:deployment) }
+
let(:data) { Gitlab::DataBuilder::Deployment.build(deployment, Time.current) }
it_behaves_like 'calls the service API with the event message', /Deploy to (.*?) created/
@@ -208,6 +212,7 @@ RSpec.shared_examples 'slack or mattermost notifications' do |service_name|
context 'note event' do
let_it_be(:issue_note) { create(:note_on_issue, project: project, note: "issue note") }
+
let(:data) { Gitlab::DataBuilder::Note.build(issue_note, user) }
it_behaves_like 'calls the service API with the event message', /commented on issue/
@@ -216,7 +221,7 @@ RSpec.shared_examples 'slack or mattermost notifications' do |service_name|
let(:chat_service_params) { { note_channel: 'random' } }
it 'uses the right channel' do
- expect(Slack::Messenger).to execute_with_options(channel: ['random'])
+ expect(::Slack::Messenger).to execute_with_options(channel: ['random'])
execute_service
end
@@ -227,7 +232,7 @@ RSpec.shared_examples 'slack or mattermost notifications' do |service_name|
end
it 'falls back to note channel' do
- expect(Slack::Messenger).to execute_with_options(channel: ['random'])
+ expect(::Slack::Messenger).to execute_with_options(channel: ['random'])
execute_service
end
@@ -236,7 +241,7 @@ RSpec.shared_examples 'slack or mattermost notifications' do |service_name|
let(:chat_service_params) { { note_channel: 'random', confidential_note_channel: 'confidential' } }
it 'uses confidential channel' do
- expect(Slack::Messenger).to execute_with_options(channel: ['confidential'])
+ expect(::Slack::Messenger).to execute_with_options(channel: ['confidential'])
execute_service
end
diff --git a/spec/support/shared_examples/models/concerns/timebox_shared_examples.rb b/spec/support/shared_examples/models/concerns/timebox_shared_examples.rb
index 68142e667a4..39121b73bc5 100644
--- a/spec/support/shared_examples/models/concerns/timebox_shared_examples.rb
+++ b/spec/support/shared_examples/models/concerns/timebox_shared_examples.rb
@@ -86,45 +86,6 @@ RSpec.shared_examples 'a timebox' do |timebox_type|
expect(timebox.errors[:project_id]).to include("#{timebox_type} should belong either to a project or a group.")
end
end
-
- describe "#uniqueness_of_title" do
- context "per project" do
- it "does not accept the same title in a project twice" do
- new_timebox = timebox.dup
- expect(new_timebox).not_to be_valid
- end
-
- it "accepts the same title in another project" do
- project = create(:project)
- new_timebox = timebox.dup
- new_timebox.project = project
-
- expect(new_timebox).to be_valid
- end
- end
-
- context "per group" do
- let(:timebox) { create(timebox_type, *timebox_args, group: group) }
-
- before do
- project.update!(group: group)
- end
-
- it "does not accept the same title in a group twice" do
- new_timebox = described_class.new(group: group, title: timebox.title)
-
- expect(new_timebox).not_to be_valid
- end
-
- it "does not accept the same title of a child project timebox" do
- create(timebox_type, *timebox_args, project: group.projects.first)
-
- new_timebox = described_class.new(group: group, title: timebox.title)
-
- expect(new_timebox).not_to be_valid
- end
- end
- end
end
describe "Associations" do
diff --git a/spec/support/shared_examples/models/chat_slash_commands_shared_examples.rb b/spec/support/shared_examples/models/integrations/base_slash_commands_shared_examples.rb
index 49729afce61..128999d02fa 100644
--- a/spec/support/shared_examples/models/chat_slash_commands_shared_examples.rb
+++ b/spec/support/shared_examples/models/integrations/base_slash_commands_shared_examples.rb
@@ -1,6 +1,6 @@
# frozen_string_literal: true
-RSpec.shared_examples 'chat slash commands service' do
+RSpec.shared_examples Integrations::BaseSlashCommands do
describe "Associations" do
it { is_expected.to respond_to :token }
it { is_expected.to have_many :chat_names }
diff --git a/spec/support/shared_examples/models/mentionable_shared_examples.rb b/spec/support/shared_examples/models/mentionable_shared_examples.rb
index 2392658e584..04630484964 100644
--- a/spec/support/shared_examples/models/mentionable_shared_examples.rb
+++ b/spec/support/shared_examples/models/mentionable_shared_examples.rb
@@ -66,7 +66,7 @@ RSpec.shared_examples 'a mentionable' do
expect(subject.gfm_reference).to eq(backref_text)
end
- it "extracts references from its reference property" do
+ it "extracts references from its reference property", :clean_gitlab_redis_cache do
# De-duplicate and omit itself
refs = subject.referenced_mentionables
expect(refs.size).to eq(6)
@@ -98,7 +98,7 @@ RSpec.shared_examples 'a mentionable' do
end
end
- it 'creates cross-reference notes' do
+ it 'creates cross-reference notes', :clean_gitlab_redis_cache do
mentioned_objects = [mentioned_issue, mentioned_mr, mentioned_commit,
ext_issue, ext_mr, ext_commit]
diff --git a/spec/support/shared_examples/models/packages/debian/component_file_shared_example.rb b/spec/support/shared_examples/models/packages/debian/component_file_shared_example.rb
index e6b16d5881d..f08ee820463 100644
--- a/spec/support/shared_examples/models/packages/debian/component_file_shared_example.rb
+++ b/spec/support/shared_examples/models/packages/debian/component_file_shared_example.rb
@@ -142,6 +142,14 @@ RSpec.shared_examples 'Debian Component File' do |container_type, can_freeze|
end
end
+ describe '.with_architecture' do
+ subject { described_class.with_architecture(architecture1_2) }
+
+ it do
+ expect(subject.to_a).to contain_exactly(component_file_other_architecture)
+ end
+ end
+
describe '.with_architecture_name' do
subject { described_class.with_architecture_name(architecture1_2.name) }
@@ -166,12 +174,12 @@ RSpec.shared_examples 'Debian Component File' do |container_type, can_freeze|
end
end
- describe '.created_before' do
- let_it_be(:component_file1) { create("debian_#{container_type}_component_file", component: component1_1, architecture: architecture1_1, created_at: 4.hours.ago) }
- let_it_be(:component_file2) { create("debian_#{container_type}_component_file", component: component1_1, architecture: architecture1_1, created_at: 3.hours.ago) }
- let_it_be(:component_file3) { create("debian_#{container_type}_component_file", component: component1_1, architecture: architecture1_1, created_at: 1.hour.ago) }
+ describe '.updated_before' do
+ let_it_be(:component_file1) { create("debian_#{container_type}_component_file", component: component1_1, architecture: architecture1_1, updated_at: 4.hours.ago) }
+ let_it_be(:component_file2) { create("debian_#{container_type}_component_file", component: component1_1, architecture: architecture1_1, updated_at: 3.hours.ago) }
+ let_it_be(:component_file3) { create("debian_#{container_type}_component_file", component: component1_1, architecture: architecture1_1, updated_at: 1.hour.ago) }
- subject { described_class.created_before(2.hours.ago) }
+ subject { described_class.updated_before(2.hours.ago) }
it do
expect(subject.to_a).to contain_exactly(component_file1, component_file2)
diff --git a/spec/support/shared_examples/models/packages/debian/distribution_key_shared_examples.rb b/spec/support/shared_examples/models/packages/debian/distribution_key_shared_examples.rb
new file mode 100644
index 00000000000..26794c83736
--- /dev/null
+++ b/spec/support/shared_examples/models/packages/debian/distribution_key_shared_examples.rb
@@ -0,0 +1,49 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.shared_examples 'Debian Distribution Key' do |container|
+ let_it_be_with_refind(:distribution_key) { create("debian_#{container}_distribution_key") } # rubocop:disable Rails/SaveBang
+
+ subject { distribution_key }
+
+ describe 'relationships' do
+ it { is_expected.to belong_to(:distribution).class_name("Packages::Debian::#{container.capitalize}Distribution").inverse_of(:key) }
+ end
+
+ describe 'validations' do
+ describe "#distribution" do
+ it { is_expected.to validate_presence_of(:distribution) }
+ end
+
+ describe '#private_key' do
+ it { is_expected.to validate_presence_of(:private_key) }
+
+ it { is_expected.to allow_value("-----BEGIN PGP PRIVATE KEY BLOCK-----\n...").for(:private_key) }
+ it { is_expected.not_to allow_value('A').for(:private_key).with_message('must be ASCII armored') }
+ end
+
+ describe '#passphrase' do
+ it { is_expected.to validate_presence_of(:passphrase) }
+
+ it { is_expected.to allow_value('P@$$w0rd').for(:passphrase) }
+ it { is_expected.to allow_value('A' * 255).for(:passphrase) }
+ it { is_expected.not_to allow_value('A' * 256).for(:passphrase) }
+ end
+
+ describe '#public_key' do
+ it { is_expected.to validate_presence_of(:public_key) }
+
+ it { is_expected.to allow_value("-----BEGIN PGP PUBLIC KEY BLOCK-----\n...").for(:public_key) }
+ it { is_expected.not_to allow_value('A').for(:public_key).with_message('must be ASCII armored') }
+ end
+
+ describe '#fingerprint' do
+ it { is_expected.to validate_presence_of(:passphrase) }
+
+ it { is_expected.to allow_value('abc').for(:passphrase) }
+ it { is_expected.to allow_value('A' * 255).for(:passphrase) }
+ it { is_expected.not_to allow_value('A' * 256).for(:passphrase) }
+ end
+ end
+end
diff --git a/spec/support/shared_examples/models/packages/debian/distribution_shared_examples.rb b/spec/support/shared_examples/models/packages/debian/distribution_shared_examples.rb
index 8693d6868e9..5459d17b1df 100644
--- a/spec/support/shared_examples/models/packages/debian/distribution_shared_examples.rb
+++ b/spec/support/shared_examples/models/packages/debian/distribution_shared_examples.rb
@@ -17,6 +17,7 @@ RSpec.shared_examples 'Debian Distribution' do |factory, container, can_freeze|
it { is_expected.to belong_to(container) }
it { is_expected.to belong_to(:creator).class_name('User') }
+ it { is_expected.to have_one(:key).class_name("Packages::Debian::#{container.capitalize}DistributionKey").with_foreign_key(:distribution_id).inverse_of(:distribution) }
it { is_expected.to have_many(:components).class_name("Packages::Debian::#{container.capitalize}Component").inverse_of(:distribution) }
it { is_expected.to have_many(:architectures).class_name("Packages::Debian::#{container.capitalize}Architecture").inverse_of(:distribution) }
end
diff --git a/spec/support/shared_examples/namespaces/linear_traversal_examples.rb b/spec/support/shared_examples/namespaces/linear_traversal_examples.rb
new file mode 100644
index 00000000000..2fd90c36953
--- /dev/null
+++ b/spec/support/shared_examples/namespaces/linear_traversal_examples.rb
@@ -0,0 +1,23 @@
+# frozen_string_literal: true
+
+# Traversal examples common to linear and recursive methods are in
+# spec/support/shared_examples/namespaces/traversal_examples.rb
+
+RSpec.shared_examples 'linear namespace traversal' do
+ context 'when use_traversal_ids feature flag is enabled' do
+ before do
+ stub_feature_flags(use_traversal_ids: true)
+ end
+
+ context 'scopes' do
+ describe '.as_ids' do
+ let_it_be(:namespace1) { create(:group) }
+ let_it_be(:namespace2) { create(:group) }
+
+ subject { Namespace.where(id: [namespace1, namespace2]).as_ids.pluck(:id) }
+
+ it { is_expected.to contain_exactly(namespace1.id, namespace2.id) }
+ end
+ end
+ end
+end
diff --git a/spec/support/shared_examples/namespaces/traversal_examples.rb b/spec/support/shared_examples/namespaces/traversal_examples.rb
index 77a1705627e..ccc64c80fd4 100644
--- a/spec/support/shared_examples/namespaces/traversal_examples.rb
+++ b/spec/support/shared_examples/namespaces/traversal_examples.rb
@@ -17,6 +17,28 @@ RSpec.shared_examples 'namespace traversal' do
end
end
+ describe '#root_ancestor' do
+ let_it_be(:group) { create(:group) }
+ let_it_be(:nested_group) { create(:group, parent: group) }
+ let_it_be(:deep_nested_group) { create(:group, parent: nested_group) }
+
+ it 'returns the correct root ancestor' do
+ expect(group.root_ancestor).to eq(group)
+ expect(nested_group.root_ancestor).to eq(group)
+ expect(deep_nested_group.root_ancestor).to eq(group)
+ end
+
+ describe '#recursive_root_ancestor' do
+ let(:groups) { [group, nested_group, deep_nested_group] }
+
+ it "is equivalent to #recursive_root_ancestor" do
+ groups.each do |group|
+ expect(group.root_ancestor).to eq(group.recursive_root_ancestor)
+ end
+ end
+ end
+ end
+
describe '#self_and_hierarchy' do
let!(:group) { create(:group, path: 'git_lab') }
let!(:nested_group) { create(:group, parent: group) }
@@ -122,4 +144,20 @@ RSpec.shared_examples 'namespace traversal' do
it_behaves_like 'recursive version', :self_and_descendants
end
end
+
+ describe '#self_and_descendant_ids' do
+ let!(:group) { create(:group, path: 'git_lab') }
+ let!(:nested_group) { create(:group, parent: group) }
+ let!(:deep_nested_group) { create(:group, parent: nested_group) }
+
+ subject { group.self_and_descendant_ids.pluck(:id) }
+
+ it { is_expected.to contain_exactly(group.id, nested_group.id, deep_nested_group.id) }
+
+ describe '#recursive_self_and_descendant_ids' do
+ let(:groups) { [group, nested_group, deep_nested_group] }
+
+ it_behaves_like 'recursive version', :self_and_descendant_ids
+ end
+ end
end
diff --git a/spec/support/shared_examples/requests/api/conan_packages_shared_examples.rb b/spec/support/shared_examples/requests/api/conan_packages_shared_examples.rb
index c938c6432fe..20606ae942d 100644
--- a/spec/support/shared_examples/requests/api/conan_packages_shared_examples.rb
+++ b/spec/support/shared_examples/requests/api/conan_packages_shared_examples.rb
@@ -294,16 +294,6 @@ RSpec.shared_examples 'rejects invalid upload_url params' do
end
end
-RSpec.shared_examples 'successful response when using Unicorn' do
- context 'on Unicorn', :unicorn do
- it 'returns successfully' do
- subject
-
- expect(response).to have_gitlab_http_status(:ok)
- end
- end
-end
-
RSpec.shared_examples 'recipe snapshot endpoint' do
subject { get api(url), headers: headers }
@@ -372,7 +362,6 @@ RSpec.shared_examples 'recipe upload_urls endpoint' do
it_behaves_like 'rejects invalid recipe'
it_behaves_like 'rejects invalid upload_url params'
- it_behaves_like 'successful response when using Unicorn'
it 'returns a set of upload urls for the files requested' do
subject
@@ -434,7 +423,6 @@ RSpec.shared_examples 'package upload_urls endpoint' do
it_behaves_like 'rejects invalid recipe'
it_behaves_like 'rejects invalid upload_url params'
- it_behaves_like 'successful response when using Unicorn'
it 'returns a set of upload urls for the files requested' do
expected_response = {
diff --git a/spec/support/shared_examples/requests/api/debian_packages_shared_examples.rb b/spec/support/shared_examples/requests/api/debian_packages_shared_examples.rb
index dfd19167dcd..0530aa8c760 100644
--- a/spec/support/shared_examples/requests/api/debian_packages_shared_examples.rb
+++ b/spec/support/shared_examples/requests/api/debian_packages_shared_examples.rb
@@ -12,7 +12,35 @@ RSpec.shared_context 'Debian repository shared context' do |container_type, can_
let_it_be(:user, freeze: true) { create(:user) }
let_it_be(:personal_access_token, freeze: true) { create(:personal_access_token, user: user) }
- let(:distribution) { 'bullseye' }
+ let_it_be(:private_distribution, freeze: true) { create("debian_#{container_type}_distribution", container: private_container, codename: 'existing-codename') }
+ let_it_be(:private_component, freeze: true) { create("debian_#{container_type}_component", distribution: private_distribution, name: 'existing-component') }
+ let_it_be(:private_architecture_all, freeze: true) { create("debian_#{container_type}_architecture", distribution: private_distribution, name: 'all') }
+ let_it_be(:private_architecture, freeze: true) { create("debian_#{container_type}_architecture", distribution: private_distribution, name: 'existing-arch') }
+
+ let_it_be(:public_distribution, freeze: true) { create("debian_#{container_type}_distribution", container: public_container, codename: 'existing-codename') }
+ let_it_be(:public_component, freeze: true) { create("debian_#{container_type}_component", distribution: public_distribution, name: 'existing-component') }
+ let_it_be(:public_architecture_all, freeze: true) { create("debian_#{container_type}_architecture", distribution: public_distribution, name: 'all') }
+ let_it_be(:public_architecture, freeze: true) { create("debian_#{container_type}_architecture", distribution: public_distribution, name: 'existing-arch') }
+
+ if container_type == :group
+ let_it_be(:private_project) { create(:project, :private, group: private_container) }
+ let_it_be(:public_project) { create(:project, :public, group: public_container) }
+ let_it_be(:private_project_distribution) { create(:debian_project_distribution, container: private_project, codename: 'existing-codename') }
+ let_it_be(:public_project_distribution) { create(:debian_project_distribution, container: public_project, codename: 'existing-codename') }
+ else
+ let_it_be(:private_project) { private_container }
+ let_it_be(:public_project) { public_container }
+ let_it_be(:private_project_distribution) { private_distribution }
+ let_it_be(:public_project_distribution) { public_distribution }
+ end
+
+ let_it_be(:private_package) { create(:debian_package, project: private_project, published_in: private_project_distribution) }
+ let_it_be(:public_package) { create(:debian_package, project: public_project, published_in: public_project_distribution) }
+
+ let(:visibility_level) { :public }
+
+ let(:distribution) { { private: private_distribution, public: public_distribution }[visibility_level] }
+
let(:component) { 'main' }
let(:architecture) { 'amd64' }
let(:source_package) { 'sample' }
@@ -97,7 +125,7 @@ RSpec.shared_examples 'Debian repository GET request' do |status, body = nil|
expect(response).to have_gitlab_http_status(status)
unless body.nil?
- expect(response.body).to eq(body)
+ expect(response.body).to match(body)
end
end
end
@@ -107,16 +135,25 @@ RSpec.shared_examples 'Debian repository upload request' do |status, body = nil|
if status == :created
it 'creates package files', :aggregate_failures do
- pending "Debian package creation not implemented"
+ expect(::Packages::Debian::FindOrCreateIncomingService).to receive(:new).with(container, user).and_call_original
+ expect(::Packages::Debian::CreatePackageFileService).to receive(:new).with(be_a(Packages::Package), be_an(Hash)).and_call_original
+
+ if file_name.end_with? '.changes'
+ expect(::Packages::Debian::ProcessChangesWorker).to receive(:perform_async)
+ else
+ expect(::Packages::Debian::ProcessChangesWorker).not_to receive(:perform_async)
+ end
expect { subject }
.to change { container.packages.debian.count }.by(1)
+ .and change { container.packages.debian.where(name: 'incoming').count }.by(1)
+ .and change { container.package_files.count }.by(1)
expect(response).to have_gitlab_http_status(status)
expect(response.media_type).to eq('text/plain')
unless body.nil?
- expect(response.body).to eq(body)
+ expect(response.body).to match(body)
end
end
it_behaves_like 'a package tracking event', described_class.name, 'push_package'
@@ -127,7 +164,7 @@ RSpec.shared_examples 'Debian repository upload request' do |status, body = nil|
expect(response).to have_gitlab_http_status(status)
unless body.nil?
- expect(response.body).to eq(body)
+ expect(response.body).to match(body)
end
end
end
@@ -173,18 +210,112 @@ RSpec.shared_examples 'Debian repository upload authorize request' do |status, b
expect(response).to have_gitlab_http_status(status)
unless body.nil?
- expect(response.body).to eq(body)
+ expect(response.body).to match(body)
+ end
+ end
+ end
+end
+
+RSpec.shared_examples 'Debian repository POST distribution request' do |status, body|
+ and_body = body.nil? ? '' : ' and expected body'
+
+ if status == :created
+ it 'creates distribution', :aggregate_failures do
+ expect(::Packages::Debian::CreateDistributionService).to receive(:new).with(container, user, api_params).and_call_original
+
+ expect { subject }
+ .to change { Packages::Debian::GroupDistribution.all.count + Packages::Debian::ProjectDistribution.all.count }.by(1)
+ .and change { Packages::Debian::GroupComponent.all.count + Packages::Debian::ProjectComponent.all.count }.by(1)
+ .and change { Packages::Debian::GroupArchitecture.all.count + Packages::Debian::ProjectArchitecture.all.count }.by(2)
+
+ expect(response).to have_gitlab_http_status(status)
+ expect(response.media_type).to eq('application/json')
+
+ unless body.nil?
+ expect(response.body).to match(body)
+ end
+ end
+ else
+ it "returns #{status}#{and_body}", :aggregate_failures do
+ subject
+
+ expect(response).to have_gitlab_http_status(status)
+
+ unless body.nil?
+ expect(response.body).to match(body)
+ end
+ end
+ end
+end
+
+RSpec.shared_examples 'Debian repository PUT distribution request' do |status, body|
+ and_body = body.nil? ? '' : ' and expected body'
+
+ if status == :success
+ it 'updates distribution', :aggregate_failures do
+ expect(::Packages::Debian::UpdateDistributionService).to receive(:new).with(distribution, api_params.except(:codename)).and_call_original
+
+ expect { subject }
+ .to not_change { Packages::Debian::GroupDistribution.all.count + Packages::Debian::ProjectDistribution.all.count }
+ .and not_change { Packages::Debian::GroupComponent.all.count + Packages::Debian::ProjectComponent.all.count }
+ .and not_change { Packages::Debian::GroupArchitecture.all.count + Packages::Debian::ProjectArchitecture.all.count }
+
+ expect(response).to have_gitlab_http_status(status)
+ expect(response.media_type).to eq('application/json')
+
+ unless body.nil?
+ expect(response.body).to match(body)
+ end
+ end
+ else
+ it "returns #{status}#{and_body}", :aggregate_failures do
+ subject
+
+ expect(response).to have_gitlab_http_status(status)
+
+ unless body.nil?
+ expect(response.body).to match(body)
end
end
end
end
-RSpec.shared_examples 'rejects Debian access with unknown container id' do
+RSpec.shared_examples 'Debian repository DELETE distribution request' do |status, body|
+ and_body = body.nil? ? '' : ' and expected body'
+
+ if status == :success
+ it 'updates distribution', :aggregate_failures do
+ expect { subject }
+ .to change { Packages::Debian::GroupDistribution.all.count + Packages::Debian::ProjectDistribution.all.count }.by(-1)
+ .and change { Packages::Debian::GroupComponent.all.count + Packages::Debian::ProjectComponent.all.count }.by(-1)
+ .and change { Packages::Debian::GroupArchitecture.all.count + Packages::Debian::ProjectArchitecture.all.count }.by(-2)
+
+ expect(response).to have_gitlab_http_status(status)
+ expect(response.media_type).to eq('application/json')
+
+ unless body.nil?
+ expect(response.body).to match(body)
+ end
+ end
+ else
+ it "returns #{status}#{and_body}", :aggregate_failures do
+ subject
+
+ expect(response).to have_gitlab_http_status(status)
+
+ unless body.nil?
+ expect(response.body).to match(body)
+ end
+ end
+ end
+end
+
+RSpec.shared_examples 'rejects Debian access with unknown container id' do |hidden_status|
context 'with an unknown container' do
let(:container) { double(id: non_existing_record_id) }
context 'as anonymous' do
- it_behaves_like 'Debian repository GET request', :unauthorized, nil
+ it_behaves_like 'Debian repository GET request', hidden_status, nil
end
context 'as authenticated user' do
@@ -195,19 +326,25 @@ RSpec.shared_examples 'rejects Debian access with unknown container id' do
end
end
-RSpec.shared_examples 'Debian repository read endpoint' do |desired_behavior, success_status, success_body|
+RSpec.shared_examples 'Debian repository read endpoint' do |desired_behavior, success_status, success_body, authenticate_non_public: true|
+ hidden_status = if authenticate_non_public
+ :unauthorized
+ else
+ :not_found
+ end
+
context 'with valid container' do
using RSpec::Parameterized::TableSyntax
where(:visibility_level, :user_role, :member, :user_token, :expected_status, :expected_body) do
:public | :developer | true | true | success_status | success_body
:public | :guest | true | true | success_status | success_body
- :public | :developer | true | false | success_status | success_body
- :public | :guest | true | false | success_status | success_body
+ :public | :developer | true | false | :unauthorized | nil
+ :public | :guest | true | false | :unauthorized | nil
:public | :developer | false | true | success_status | success_body
:public | :guest | false | true | success_status | success_body
- :public | :developer | false | false | success_status | success_body
- :public | :guest | false | false | success_status | success_body
+ :public | :developer | false | false | :unauthorized | nil
+ :public | :guest | false | false | :unauthorized | nil
:public | :anonymous | false | true | success_status | success_body
:private | :developer | true | true | success_status | success_body
:private | :guest | true | true | :forbidden | nil
@@ -217,7 +354,7 @@ RSpec.shared_examples 'Debian repository read endpoint' do |desired_behavior, su
:private | :guest | false | true | :not_found | nil
:private | :developer | false | false | :unauthorized | nil
:private | :guest | false | false | :unauthorized | nil
- :private | :anonymous | false | true | :unauthorized | nil
+ :private | :anonymous | false | true | hidden_status | nil
end
with_them do
@@ -227,10 +364,16 @@ RSpec.shared_examples 'Debian repository read endpoint' do |desired_behavior, su
end
end
- it_behaves_like 'rejects Debian access with unknown container id'
+ it_behaves_like 'rejects Debian access with unknown container id', hidden_status
end
-RSpec.shared_examples 'Debian repository write endpoint' do |desired_behavior, success_status, success_body|
+RSpec.shared_examples 'Debian repository write endpoint' do |desired_behavior, success_status, success_body, authenticate_non_public: true|
+ hidden_status = if authenticate_non_public
+ :unauthorized
+ else
+ :not_found
+ end
+
context 'with valid container' do
using RSpec::Parameterized::TableSyntax
@@ -252,7 +395,50 @@ RSpec.shared_examples 'Debian repository write endpoint' do |desired_behavior, s
:private | :guest | false | true | :not_found | nil
:private | :developer | false | false | :unauthorized | nil
:private | :guest | false | false | :unauthorized | nil
- :private | :anonymous | false | true | :unauthorized | nil
+ :private | :anonymous | false | true | hidden_status | nil
+ end
+
+ with_them do
+ include_context 'Debian repository access', params[:visibility_level], params[:user_role], params[:member], params[:user_token], :basic do
+ it_behaves_like "Debian repository #{desired_behavior}", params[:expected_status], params[:expected_body]
+ end
+ end
+ end
+
+ it_behaves_like 'rejects Debian access with unknown container id', hidden_status
+end
+
+RSpec.shared_examples 'Debian repository maintainer write endpoint' do |desired_behavior, success_status, success_body, authenticate_non_public: true|
+ hidden_status = if authenticate_non_public
+ :unauthorized
+ else
+ :not_found
+ end
+
+ context 'with valid container' do
+ using RSpec::Parameterized::TableSyntax
+
+ where(:visibility_level, :user_role, :member, :user_token, :expected_status, :expected_body) do
+ :public | :maintainer | true | true | success_status | success_body
+ :public | :developer | true | true | :forbidden | nil
+ :public | :guest | true | true | :forbidden | nil
+ :public | :maintainer | true | false | :unauthorized | nil
+ :public | :guest | true | false | :unauthorized | nil
+ :public | :maintainer | false | true | :forbidden | nil
+ :public | :guest | false | true | :forbidden | nil
+ :public | :maintainer | false | false | :unauthorized | nil
+ :public | :guest | false | false | :unauthorized | nil
+ :public | :anonymous | false | true | :unauthorized | nil
+ :private | :maintainer | true | true | success_status | success_body
+ :private | :developer | true | true | :forbidden | nil
+ :private | :guest | true | true | :forbidden | nil
+ :private | :maintainer | true | false | :unauthorized | nil
+ :private | :guest | true | false | :unauthorized | nil
+ :private | :maintainer | false | true | :not_found | nil
+ :private | :guest | false | true | :not_found | nil
+ :private | :maintainer | false | false | :unauthorized | nil
+ :private | :guest | false | false | :unauthorized | nil
+ :private | :anonymous | false | true | hidden_status | nil
end
with_them do
@@ -262,5 +448,5 @@ RSpec.shared_examples 'Debian repository write endpoint' do |desired_behavior, s
end
end
- it_behaves_like 'rejects Debian access with unknown container id'
+ it_behaves_like 'rejects Debian access with unknown container id', hidden_status
end
diff --git a/spec/support/shared_examples/requests/api/graphql/packages/package_details_shared_examples.rb b/spec/support/shared_examples/requests/api/graphql/packages/package_details_shared_examples.rb
new file mode 100644
index 00000000000..41a61ba5fd7
--- /dev/null
+++ b/spec/support/shared_examples/requests/api/graphql/packages/package_details_shared_examples.rb
@@ -0,0 +1,27 @@
+# frozen_string_literal: true
+
+RSpec.shared_examples 'a package detail' do
+ it_behaves_like 'a working graphql query' do
+ it 'matches the JSON schema' do
+ expect(package_details).to match_schema('graphql/packages/package_details')
+ end
+ end
+end
+
+RSpec.shared_examples 'a package with files' do
+ it 'has the right amount of files' do
+ expect(package_files_response.length).to be(package.package_files.length)
+ end
+
+ it 'has the basic package files data' do
+ expect(first_file_response).to include(
+ 'id' => global_id_of(first_file),
+ 'fileName' => first_file.file_name,
+ 'size' => first_file.size.to_s,
+ 'downloadPath' => first_file.download_path,
+ 'fileSha1' => first_file.file_sha1,
+ 'fileMd5' => first_file.file_md5,
+ 'fileSha256' => first_file.file_sha256
+ )
+ end
+end
diff --git a/spec/support/shared_examples/requests/api/helm_packages_shared_examples.rb b/spec/support/shared_examples/requests/api/helm_packages_shared_examples.rb
new file mode 100644
index 00000000000..585c4fb8a4e
--- /dev/null
+++ b/spec/support/shared_examples/requests/api/helm_packages_shared_examples.rb
@@ -0,0 +1,53 @@
+# frozen_string_literal: true
+
+RSpec.shared_examples 'rejects helm packages access' do |user_type, status, add_member = true|
+ context "for user type #{user_type}" do
+ before do
+ project.send("add_#{user_type}", user) if add_member && user_type != :anonymous
+ end
+
+ it_behaves_like 'returning response status', status
+
+ if status == :unauthorized
+ it 'has the correct response header' do
+ subject
+
+ expect(response.headers['WWW-Authenticate']).to eq 'Basic realm="GitLab Packages Registry"'
+ end
+ end
+ end
+end
+
+RSpec.shared_examples 'process helm download content request' do |user_type, status, add_member = true|
+ context "for user type #{user_type}" do
+ before do
+ 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', 'API::HelmPackages', 'pull_package'
+
+ it 'returns a valid package archive' do
+ subject
+
+ expect(response.media_type).to eq('application/octet-stream')
+ end
+ end
+end
+
+RSpec.shared_examples 'rejects helm access with unknown project id' do
+ context 'with an unknown project' do
+ let(:project) { OpenStruct.new(id: 1234567890) }
+
+ context 'as anonymous' do
+ it_behaves_like 'rejects helm packages access', :anonymous, :unauthorized
+ end
+
+ context 'as authenticated user' do
+ subject { get api(url), headers: basic_auth_header(user.username, personal_access_token.token) }
+
+ it_behaves_like 'rejects helm packages access', :anonymous, :not_found
+ end
+ end
+end
diff --git a/spec/support/shared_examples/requests/api/packages_shared_examples.rb b/spec/support/shared_examples/requests/api/packages_shared_examples.rb
index eb86b7c37d5..42c29084d7b 100644
--- a/spec/support/shared_examples/requests/api/packages_shared_examples.rb
+++ b/spec/support/shared_examples/requests/api/packages_shared_examples.rb
@@ -146,6 +146,6 @@ RSpec.shared_examples 'a package tracking event' do |category, action|
it "creates a gitlab tracking event #{action}", :snowplow do
expect { subject }.to change { Packages::Event.count }.by(1)
- expect_snowplow_event(category: category, action: action)
+ expect_snowplow_event(category: category, action: action, **snowplow_gitlab_standard_context)
end
end
diff --git a/spec/support/shared_examples/requests/api/pypi_packages_shared_examples.rb b/spec/support/shared_examples/requests/api/pypi_packages_shared_examples.rb
index bbcf856350d..8a351226123 100644
--- a/spec/support/shared_examples/requests/api/pypi_packages_shared_examples.rb
+++ b/spec/support/shared_examples/requests/api/pypi_packages_shared_examples.rb
@@ -110,6 +110,7 @@ RSpec.shared_examples 'PyPI package versions' do |user_type, status, add_member
context "for user type #{user_type}" do
before do
project.send("add_#{user_type}", user) if add_member && user_type != :anonymous
+ group.send("add_#{user_type}", user) if add_member && user_type != :anonymous
end
it 'returns the package listing' do
@@ -127,6 +128,7 @@ RSpec.shared_examples 'PyPI package download' do |user_type, status, add_member
context "for user type #{user_type}" do
before do
project.send("add_#{user_type}", user) if add_member && user_type != :anonymous
+ group.send("add_#{user_type}", user) if add_member && user_type != :anonymous
end
it 'returns the package listing' do
@@ -144,24 +146,185 @@ RSpec.shared_examples 'process PyPI api request' do |user_type, status, add_memb
context "for user type #{user_type}" do
before do
project.send("add_#{user_type}", user) if add_member && user_type != :anonymous
+ group.send("add_#{user_type}", user) if add_member && user_type != :anonymous
end
it_behaves_like 'returning response status', status
end
end
+RSpec.shared_examples 'unknown PyPI scope id' do
+ context 'as anonymous' do
+ it_behaves_like 'process PyPI api request', :anonymous, :not_found
+ end
+
+ context 'as authenticated user' do
+ subject { get api(url), headers: basic_auth_header(user.username, personal_access_token.token) }
+
+ it_behaves_like 'process PyPI api request', :anonymous, :not_found
+ end
+end
+
RSpec.shared_examples 'rejects PyPI access with unknown project id' do
context 'with an unknown project' do
let(:project) { OpenStruct.new(id: 1234567890) }
- context 'as anonymous' do
- it_behaves_like 'process PyPI api request', :anonymous, :not_found
+ it_behaves_like 'unknown PyPI scope id'
+ end
+end
+
+RSpec.shared_examples 'rejects PyPI access with unknown group id' do
+ context 'with an unknown project' do
+ let(:group) { OpenStruct.new(id: 1234567890) }
+
+ it_behaves_like 'unknown PyPI scope id'
+ end
+end
+
+RSpec.shared_examples 'pypi simple API endpoint' do
+ using RSpec::Parameterized::TableSyntax
+
+ context 'with valid project' do
+ where(:visibility_level, :user_role, :member, :user_token, :shared_examples_name, :expected_status) do
+ :public | :developer | true | true | 'PyPI package versions' | :success
+ :public | :guest | true | true | 'PyPI package versions' | :success
+ :public | :developer | true | false | 'PyPI package versions' | :success
+ :public | :guest | true | false | 'PyPI package versions' | :success
+ :public | :developer | false | true | 'PyPI package versions' | :success
+ :public | :guest | false | true | 'PyPI package versions' | :success
+ :public | :developer | false | false | 'PyPI package versions' | :success
+ :public | :guest | false | false | 'PyPI package versions' | :success
+ :public | :anonymous | false | true | 'PyPI package versions' | :success
+ :private | :developer | true | true | 'PyPI package versions' | :success
+ :private | :guest | true | true | 'process PyPI api request' | :forbidden
+ :private | :developer | true | false | 'process PyPI api request' | :unauthorized
+ :private | :guest | true | false | 'process PyPI api request' | :unauthorized
+ :private | :developer | false | true | 'process PyPI api request' | :not_found
+ :private | :guest | false | true | 'process PyPI api request' | :not_found
+ :private | :developer | false | false | 'process PyPI api request' | :unauthorized
+ :private | :guest | false | false | 'process PyPI api request' | :unauthorized
+ :private | :anonymous | false | true | 'process PyPI api request' | :unauthorized
end
- context 'as authenticated user' do
- subject { get api(url), headers: basic_auth_header(user.username, personal_access_token.token) }
+ with_them do
+ let(:token) { user_token ? personal_access_token.token : 'wrong' }
+ let(:headers) { user_role == :anonymous ? {} : basic_auth_header(user.username, token) }
- it_behaves_like 'process PyPI api request', :anonymous, :not_found
+ before do
+ project.update_column(:visibility_level, Gitlab::VisibilityLevel.level_value(visibility_level.to_s))
+ group.update_column(:visibility_level, Gitlab::VisibilityLevel.level_value(visibility_level.to_s))
+ end
+
+ it_behaves_like params[:shared_examples_name], params[:user_role], params[:expected_status], params[:member]
+ end
+ end
+
+ context 'with a normalized package name' do
+ let_it_be(:package) { create(:pypi_package, project: project, name: 'my.package') }
+
+ let(:url) { "/projects/#{project.id}/packages/pypi/simple/my-package" }
+ let(:headers) { basic_auth_header(user.username, personal_access_token.token) }
+ let(:snowplow_gitlab_standard_context) { { project: project, namespace: project.namespace } }
+
+ it_behaves_like 'PyPI package versions', :developer, :success
+ end
+end
+
+RSpec.shared_examples 'pypi file download endpoint' do
+ using RSpec::Parameterized::TableSyntax
+
+ context 'with valid project' do
+ where(:visibility_level, :user_role, :member, :user_token) do
+ :public | :developer | true | true
+ :public | :guest | true | true
+ :public | :developer | true | false
+ :public | :guest | true | false
+ :public | :developer | false | true
+ :public | :guest | false | true
+ :public | :developer | false | false
+ :public | :guest | false | false
+ :public | :anonymous | false | true
+ :private | :developer | true | true
+ :private | :guest | true | true
+ :private | :developer | true | false
+ :private | :guest | true | false
+ :private | :developer | false | true
+ :private | :guest | false | true
+ :private | :developer | false | false
+ :private | :guest | false | false
+ :private | :anonymous | false | true
end
+
+ with_them do
+ let(:token) { user_token ? personal_access_token.token : 'wrong' }
+ let(:headers) { user_role == :anonymous ? {} : basic_auth_header(user.username, token) }
+
+ before do
+ project.update_column(:visibility_level, Gitlab::VisibilityLevel.level_value(visibility_level.to_s))
+ group.update_column(:visibility_level, Gitlab::VisibilityLevel.level_value(visibility_level.to_s))
+ end
+
+ it_behaves_like 'PyPI package download', params[:user_role], :success, params[:member]
+ end
+ end
+
+ context 'with deploy token headers' do
+ let(:headers) { basic_auth_header(deploy_token.username, deploy_token.token) }
+
+ context 'valid token' do
+ it_behaves_like 'returning response status', :success
+ end
+
+ context 'invalid token' do
+ let(:headers) { basic_auth_header('foo', 'bar') }
+
+ it_behaves_like 'returning response status', :success
+ end
+ end
+
+ context 'with job token headers' do
+ let(:headers) { basic_auth_header(::Gitlab::Auth::CI_JOB_USER, job.token) }
+
+ context 'valid token' do
+ it_behaves_like 'returning response status', :success
+ end
+
+ context 'invalid token' do
+ let(:headers) { basic_auth_header(::Gitlab::Auth::CI_JOB_USER, 'bar') }
+
+ it_behaves_like 'returning response status', :unauthorized
+ end
+
+ context 'invalid user' do
+ let(:headers) { basic_auth_header('foo', job.token) }
+
+ it_behaves_like 'returning response status', :success
+ end
+ end
+end
+
+RSpec.shared_examples 'a pypi user namespace endpoint' do
+ using RSpec::Parameterized::TableSyntax
+
+ # only group namespaces are supported at this time
+ where(:visibility_level, :user_role, :expected_status) do
+ :public | :owner | :not_found
+ :private | :owner | :not_found
+ :public | :external | :not_found
+ :private | :external | :not_found
+ :public | :anonymous | :not_found
+ :private | :anonymous | :not_found
+ end
+
+ with_them do
+ let_it_be_with_reload(:group) { create(:namespace) }
+ let(:headers) { user_role == :anonymous ? {} : basic_auth_header(user.username, personal_access_token.token) }
+
+ before do
+ group.update_column(:visibility_level, Gitlab::VisibilityLevel.level_value(visibility_level.to_s))
+ group.update_column(:owner_id, user.id) if user_role == :owner
+ end
+
+ it_behaves_like 'returning response status', params[:expected_status]
end
end
diff --git a/spec/support/shared_examples/requests/api/resource_label_events_api_shared_examples.rb b/spec/support/shared_examples/requests/api/resource_label_events_api_shared_examples.rb
index 675b6c5cef6..2ac78131e08 100644
--- a/spec/support/shared_examples/requests/api/resource_label_events_api_shared_examples.rb
+++ b/spec/support/shared_examples/requests/api/resource_label_events_api_shared_examples.rb
@@ -48,7 +48,7 @@ RSpec.shared_examples 'resource_label_events API' do |parent_type, eventable_typ
get api("/#{parent_type}/#{parent.id}/#{eventable_type}/#{eventable[id_name]}/resource_label_events", user)
expect(json_response).to be_an Array
- expect(json_response).to eq []
+ expect(json_response).to be_empty
end
end
end
diff --git a/spec/support/shared_examples/requests/api/tracking_shared_examples.rb b/spec/support/shared_examples/requests/api/tracking_shared_examples.rb
index 826139635ed..af13e3fc14d 100644
--- a/spec/support/shared_examples/requests/api/tracking_shared_examples.rb
+++ b/spec/support/shared_examples/requests/api/tracking_shared_examples.rb
@@ -4,6 +4,6 @@ RSpec.shared_examples 'a gitlab tracking event' do |category, action|
it "creates a gitlab tracking event #{action}", :snowplow do
subject
- expect_snowplow_event(category: category, action: action)
+ expect_snowplow_event(category: category, action: action, **snowplow_standard_context_params)
end
end
diff --git a/spec/support/shared_examples/services/clusters/parse_cluster_applications_artifact_shared_examples.rb b/spec/support/shared_examples/services/clusters/parse_cluster_applications_artifact_shared_examples.rb
deleted file mode 100644
index 466300017d9..00000000000
--- a/spec/support/shared_examples/services/clusters/parse_cluster_applications_artifact_shared_examples.rb
+++ /dev/null
@@ -1,89 +0,0 @@
-# frozen_string_literal: true
-
-RSpec.shared_examples 'parse cluster applications artifact' do |release_name|
- let(:application_class) { Clusters::Cluster::APPLICATIONS[release_name] }
- let(:cluster_application) { cluster.public_send("application_#{release_name}") }
- let(:file) { fixture_file_upload(Rails.root.join(fixture)) }
- let(:artifact) { create(:ci_job_artifact, :cluster_applications, job: job, file: file) }
-
- context 'release is missing' do
- let(:fixture) { "spec/fixtures/helm/helm_list_v2_#{release_name}_missing.json.gz" }
-
- context 'application does not exist' do
- it 'does not create or destroy an application' do
- expect do
- described_class.new(job, user).execute(artifact)
- end.not_to change(application_class, :count)
- end
- end
-
- context 'application exists' do
- before do
- create("clusters_applications_#{release_name}".to_sym, :installed, cluster: cluster)
- end
-
- it 'marks the application as uninstalled' do
- described_class.new(job, user).execute(artifact)
-
- cluster_application.reload
- expect(cluster_application).to be_uninstalled
- end
- end
- end
-
- context 'release is deployed' do
- let(:fixture) { "spec/fixtures/helm/helm_list_v2_#{release_name}_deployed.json.gz" }
-
- context 'application does not exist' do
- it 'creates an application and marks it as installed' do
- expect do
- described_class.new(job, user).execute(artifact)
- end.to change(application_class, :count)
-
- expect(cluster_application).to be_persisted
- expect(cluster_application).to be_externally_installed
- end
- end
-
- context 'application exists' do
- before do
- create("clusters_applications_#{release_name}".to_sym, :errored, cluster: cluster)
- end
-
- it 'marks the application as installed' do
- described_class.new(job, user).execute(artifact)
-
- expect(cluster_application).to be_externally_installed
- end
- end
- end
-
- context 'release is failed' do
- let(:fixture) { "spec/fixtures/helm/helm_list_v2_#{release_name}_failed.json.gz" }
-
- context 'application does not exist' do
- it 'creates an application and marks it as errored' do
- expect do
- described_class.new(job, user).execute(artifact)
- end.to change(application_class, :count)
-
- expect(cluster_application).to be_persisted
- expect(cluster_application).to be_errored
- expect(cluster_application.status_reason).to eq('Helm release failed to install')
- end
- end
-
- context 'application exists' do
- before do
- create("clusters_applications_#{release_name}".to_sym, :installed, cluster: cluster)
- end
-
- it 'marks the application as errored' do
- described_class.new(job, user).execute(artifact)
-
- expect(cluster_application).to be_errored
- expect(cluster_application.status_reason).to eq('Helm release failed to install')
- end
- end
- end
-end
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
new file mode 100644
index 00000000000..9ffeba1b1d0
--- /dev/null
+++ b/spec/support/shared_examples/services/packages/debian/generate_distribution_shared_examples.rb
@@ -0,0 +1,166 @@
+# frozen_string_literal: true
+
+RSpec.shared_examples 'Generate Debian Distribution and component files' do
+ let_it_be(:component_main) { create("debian_#{container_type}_component", distribution: distribution, name: 'main') }
+ let_it_be(:component_contrib) { create("debian_#{container_type}_component", distribution: distribution, name: 'contrib') }
+
+ let_it_be(:architecture_all) { create("debian_#{container_type}_architecture", distribution: distribution, name: 'all') }
+ let_it_be(:architecture_amd64) { create("debian_#{container_type}_architecture", distribution: distribution, name: 'amd64') }
+ let_it_be(:architecture_arm64) { create("debian_#{container_type}_architecture", distribution: distribution, name: 'arm64') }
+
+ let_it_be(:component_file1) { create("debian_#{container_type}_component_file", component: component_contrib, architecture: architecture_all, updated_at: '2020-01-24T08:00:00Z', file_sha256: 'e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855', file_md5: 'd41d8cd98f00b204e9800998ecf8427e', file_fixture: nil, size: 0) } # updated
+ let_it_be(:component_file2) { create("debian_#{container_type}_component_file", component: component_main, architecture: architecture_all, updated_at: '2020-01-24T09:00:00Z', file_sha256: 'a') } # destroyed
+ let_it_be(:component_file3) { create("debian_#{container_type}_component_file", component: component_main, architecture: architecture_amd64, updated_at: '2020-01-24T10:54:59Z', file_sha256: 'b') } # destroyed, 1 second before last generation
+ let_it_be(:component_file4) { create("debian_#{container_type}_component_file", component: component_contrib, architecture: architecture_all, updated_at: '2020-01-24T10:55:00Z', file_sha256: 'c') } # kept, last generation
+ let_it_be(:component_file5) { create("debian_#{container_type}_component_file", component: component_contrib, architecture: architecture_all, updated_at: '2020-01-24T10:55:00Z', file_sha256: 'd') } # kept, last generation
+ let_it_be(:component_file6) { create("debian_#{container_type}_component_file", component: component_contrib, architecture: architecture_amd64, updated_at: '2020-01-25T15:17:18Z', file_sha256: 'e') } # kept, less than 1 hour ago
+
+ def check_component_file(release_date, component_name, component_file_type, architecture_name, expected_content)
+ component_file = distribution
+ .component_files
+ .with_component_name(component_name)
+ .with_file_type(component_file_type)
+ .with_architecture_name(architecture_name)
+ .order_updated_asc
+ .last
+
+ expect(component_file).not_to be_nil
+ expect(component_file.updated_at).to eq(release_date)
+
+ unless expected_content.nil?
+ component_file.file.use_file do |file_path|
+ expect(File.read(file_path)).to eq(expected_content)
+ end
+ end
+ end
+
+ it 'generates Debian distribution and component files', :aggregate_failures do
+ current_time = Time.utc(2020, 01, 25, 15, 17, 18, 123456)
+
+ travel_to(current_time) do
+ expect(Gitlab::ErrorTracking).not_to receive(:log_exception)
+
+ initial_count = 6
+ destroyed_count = 2
+ # updated_count = 1
+ created_count = 5
+
+ expect { subject }
+ .to not_change { Packages::Package.count }
+ .and not_change { Packages::PackageFile.count }
+ .and change { distribution.reload.updated_at }.to(current_time.round)
+ .and change { distribution.component_files.reset.count }.from(initial_count).to(initial_count - destroyed_count + created_count)
+ .and change { component_file1.reload.updated_at }.to(current_time.round)
+
+ debs = package.package_files.with_debian_file_type(:deb).preload_debian_file_metadata.to_a
+ pool_prefix = "pool/unstable/#{project.id}/p/#{package.name}"
+ expected_main_amd64_content = <<~EOF
+ Package: libsample0
+ Source: #{package.name}
+ Version: #{package.version}
+ Installed-Size: 7
+ Maintainer: #{debs[0].debian_fields['Maintainer']}
+ Architecture: amd64
+ Description: Some mostly empty lib
+ Used in GitLab tests.
+ .
+ Testing another paragraph.
+ Multi-Arch: same
+ Homepage: #{debs[0].debian_fields['Homepage']}
+ Section: libs
+ Priority: optional
+ Filename: #{pool_prefix}/libsample0_1.2.3~alpha2_amd64.deb
+ Size: 409600
+ MD5sum: #{debs[0].file_md5}
+ SHA256: #{debs[0].file_sha256}
+
+ Package: sample-dev
+ Source: #{package.name} (#{package.version})
+ Version: 1.2.3~binary
+ Installed-Size: 7
+ Maintainer: #{debs[1].debian_fields['Maintainer']}
+ Architecture: amd64
+ Depends: libsample0 (= 1.2.3~binary)
+ Description: Some mostly empty development files
+ Used in GitLab tests.
+ .
+ Testing another paragraph.
+ Multi-Arch: same
+ Homepage: #{debs[1].debian_fields['Homepage']}
+ Section: libdevel
+ Priority: optional
+ Filename: #{pool_prefix}/sample-dev_1.2.3~binary_amd64.deb
+ Size: 409600
+ MD5sum: #{debs[1].file_md5}
+ SHA256: #{debs[1].file_sha256}
+ EOF
+
+ check_component_file(current_time.round, 'main', :packages, 'all', nil)
+ check_component_file(current_time.round, 'main', :packages, 'amd64', expected_main_amd64_content)
+ check_component_file(current_time.round, 'main', :packages, 'arm64', nil)
+
+ check_component_file(current_time.round, 'contrib', :packages, 'all', nil)
+ check_component_file(current_time.round, 'contrib', :packages, 'amd64', nil)
+ check_component_file(current_time.round, 'contrib', :packages, 'arm64', nil)
+
+ main_amd64_size = expected_main_amd64_content.length
+ main_amd64_md5sum = Digest::MD5.hexdigest(expected_main_amd64_content)
+ main_amd64_sha256 = Digest::SHA256.hexdigest(expected_main_amd64_content)
+
+ contrib_all_size = component_file1.size
+ contrib_all_md5sum = component_file1.file_md5
+ contrib_all_sha256 = component_file1.file_sha256
+
+ expected_release_content = <<~EOF
+ Codename: unstable
+ Date: Sat, 25 Jan 2020 15:17:18 +0000
+ Valid-Until: Mon, 27 Jan 2020 15:17:18 +0000
+ Architectures: all amd64 arm64
+ Components: contrib main
+ MD5Sum:
+ #{contrib_all_md5sum} #{contrib_all_size} contrib/binary-all/Packages
+ d41d8cd98f00b204e9800998ecf8427e 0 contrib/binary-amd64/Packages
+ d41d8cd98f00b204e9800998ecf8427e 0 contrib/binary-arm64/Packages
+ d41d8cd98f00b204e9800998ecf8427e 0 main/binary-all/Packages
+ #{main_amd64_md5sum} #{main_amd64_size} main/binary-amd64/Packages
+ d41d8cd98f00b204e9800998ecf8427e 0 main/binary-arm64/Packages
+ SHA256:
+ #{contrib_all_sha256} #{contrib_all_size} contrib/binary-all/Packages
+ e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855 0 contrib/binary-amd64/Packages
+ e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855 0 contrib/binary-arm64/Packages
+ e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855 0 main/binary-all/Packages
+ #{main_amd64_sha256} #{main_amd64_size} main/binary-amd64/Packages
+ e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855 0 main/binary-arm64/Packages
+ EOF
+
+ distribution.file.use_file do |file_path|
+ expect(File.read(file_path)).to eq(expected_release_content)
+ end
+ end
+ end
+end
+
+RSpec.shared_examples 'Generate minimal Debian Distribution' do
+ it 'generates minimal distribution', :aggregate_failures do
+ travel_to(Time.utc(2020, 01, 25, 15, 17, 18, 123456)) do
+ expect(Gitlab::ErrorTracking).not_to receive(:log_exception)
+
+ expect { subject }
+ .to not_change { Packages::Package.count }
+ .and not_change { Packages::PackageFile.count }
+ .and not_change { distribution.component_files.reset.count }
+
+ expected_release_content = <<~EOF
+ Codename: unstable
+ Date: Sat, 25 Jan 2020 15:17:18 +0000
+ Valid-Until: Mon, 27 Jan 2020 15:17:18 +0000
+ MD5Sum:
+ SHA256:
+ EOF
+
+ distribution.file.use_file do |file_path|
+ expect(File.read(file_path)).to eq(expected_release_content)
+ end
+ end
+ end
+end
diff --git a/spec/support/shared_examples/services/users/build_service_shared_examples.rb b/spec/support/shared_examples/services/users/build_service_shared_examples.rb
new file mode 100644
index 00000000000..6a8695e1786
--- /dev/null
+++ b/spec/support/shared_examples/services/users/build_service_shared_examples.rb
@@ -0,0 +1,125 @@
+# frozen_string_literal: true
+
+RSpec.shared_examples 'common user build items' do
+ it { is_expected.to be_valid }
+
+ it 'sets the created_by_id' do
+ expect(user.created_by_id).to eq(current_user&.id)
+ end
+
+ it 'calls UpdateCanonicalEmailService' do
+ expect(Users::UpdateCanonicalEmailService).to receive(:new).and_call_original
+
+ user
+ end
+
+ context 'when user_type is provided' do
+ context 'when project_bot' do
+ before do
+ params.merge!({ user_type: :project_bot })
+ end
+
+ it { expect(user.project_bot?).to be true }
+ end
+
+ context 'when not a project_bot' do
+ before do
+ params.merge!({ user_type: :alert_bot })
+ end
+
+ it { expect(user).to be_human }
+ end
+ end
+end
+
+RSpec.shared_examples_for 'current user not admin build items' do
+ using RSpec::Parameterized::TableSyntax
+
+ context 'with "user_default_external" application setting' do
+ where(:user_default_external, :external, :email, :user_default_internal_regex, :result) do
+ true | nil | 'fl@example.com' | nil | true
+ true | true | 'fl@example.com' | nil | true
+ true | false | 'fl@example.com' | nil | true # admin difference
+
+ true | nil | 'fl@example.com' | '' | true
+ true | true | 'fl@example.com' | '' | true
+ true | false | 'fl@example.com' | '' | true # admin difference
+
+ true | nil | 'fl@example.com' | '^(?:(?!\.ext@).)*$\r?' | false
+ true | true | 'fl@example.com' | '^(?:(?!\.ext@).)*$\r?' | false # admin difference
+ true | false | 'fl@example.com' | '^(?:(?!\.ext@).)*$\r?' | false
+
+ true | nil | 'tester.ext@domain.com' | '^(?:(?!\.ext@).)*$\r?' | true
+ true | true | 'tester.ext@domain.com' | '^(?:(?!\.ext@).)*$\r?' | true
+ true | false | 'tester.ext@domain.com' | '^(?:(?!\.ext@).)*$\r?' | true # admin difference
+
+ false | nil | 'fl@example.com' | nil | false
+ false | true | 'fl@example.com' | nil | false # admin difference
+ false | false | 'fl@example.com' | nil | false
+
+ false | nil | 'fl@example.com' | '' | false
+ false | true | 'fl@example.com' | '' | false # admin difference
+ false | false | 'fl@example.com' | '' | false
+
+ false | nil | 'fl@example.com' | '^(?:(?!\.ext@).)*$\r?' | false
+ false | true | 'fl@example.com' | '^(?:(?!\.ext@).)*$\r?' | false # admin difference
+ false | false | 'fl@example.com' | '^(?:(?!\.ext@).)*$\r?' | false
+
+ false | nil | 'tester.ext@domain.com' | '^(?:(?!\.ext@).)*$\r?' | false
+ false | true | 'tester.ext@domain.com' | '^(?:(?!\.ext@).)*$\r?' | false # admin difference
+ false | false | 'tester.ext@domain.com' | '^(?:(?!\.ext@).)*$\r?' | false
+ end
+
+ with_them do
+ before do
+ stub_application_setting(user_default_external: user_default_external)
+ stub_application_setting(user_default_internal_regex: user_default_internal_regex)
+
+ params.merge!({ external: external, email: email }.compact)
+ end
+
+ it 'sets the value of Gitlab::CurrentSettings.user_default_external' do
+ expect(user.external).to eq(result)
+ end
+ end
+ end
+
+ context 'when "send_user_confirmation_email" application setting is true' do
+ before do
+ stub_application_setting(send_user_confirmation_email: true, signup_enabled?: true)
+ end
+
+ it 'does not confirm the user' do
+ expect(user).not_to be_confirmed
+ end
+ end
+
+ context 'when "send_user_confirmation_email" application setting is false' do
+ before do
+ stub_application_setting(send_user_confirmation_email: false, signup_enabled?: true)
+ end
+
+ it 'confirms the user' do
+ expect(user).to be_confirmed
+ end
+ end
+
+ context 'with allowed params' do
+ let(:params) do
+ {
+ email: 1,
+ name: 1,
+ password: 1,
+ password_automatically_set: 1,
+ username: 1,
+ user_type: 'project_bot'
+ }
+ end
+
+ it 'sets all allowed attributes' do
+ expect(User).to receive(:new).with(hash_including(params)).and_call_original
+
+ user
+ end
+ end
+end
diff --git a/spec/support/shared_examples/uncached_response_shared_examples.rb b/spec/support/shared_examples/uncached_response_shared_examples.rb
deleted file mode 100644
index 3997017ff35..00000000000
--- a/spec/support/shared_examples/uncached_response_shared_examples.rb
+++ /dev/null
@@ -1,12 +0,0 @@
-# frozen_string_literal: true
-#
-# Pairs with lib/gitlab/no_cache_headers.rb
-#
-
-RSpec.shared_examples 'uncached response' do
- it 'defines an uncached header response' do
- expect(response.headers["Cache-Control"]).to include("no-store", "no-cache")
- expect(response.headers["Pragma"]).to eq("no-cache")
- expect(response.headers["Expires"]).to eq("Fri, 01 Jan 1990 00:00:00 GMT")
- end
-end
diff --git a/spec/support/unicorn.rb b/spec/support/unicorn.rb
deleted file mode 100644
index 0b01fc9e26c..00000000000
--- a/spec/support/unicorn.rb
+++ /dev/null
@@ -1,27 +0,0 @@
-# frozen_string_literal: true
-
-REQUEST_CLASSES = [
- ::Grape::Request,
- ::Rack::Request
-].freeze
-
-def request_body_class
- return ::Unicorn::TeeInput if defined?(::Unicorn)
-
- Class.new(StringIO) do
- def string
- raise NotImplementedError, '#string is only valid under Puma which uses StringIO, use #read instead'
- end
- end
-end
-
-RSpec.configure do |config|
- config.before(:each, :unicorn) do
- REQUEST_CLASSES.each do |request_class|
- allow_any_instance_of(request_class)
- .to receive(:body).and_wrap_original do |m, *args|
- request_body_class.new(m.call(*args).read)
- end
- end
- end
-end