diff options
author | GitLab Bot <gitlab-bot@gitlab.com> | 2022-11-16 15:09:30 +0300 |
---|---|---|
committer | GitLab Bot <gitlab-bot@gitlab.com> | 2022-11-16 15:09:30 +0300 |
commit | e3748b81ca29b24197276767e245158d8f84fda3 (patch) | |
tree | 02b2dbe099f8e09e9e85dc71cce1bd8e858be7ac | |
parent | 4e1af5260dc9187ca0637fcfcf56b450f6443192 (diff) |
Add latest changes from gitlab-org/gitlab@master
36 files changed, 444 insertions, 345 deletions
diff --git a/.rubocop_todo/layout/line_length.yml b/.rubocop_todo/layout/line_length.yml index 8b34f2d5e9b..75e04ddcbd4 100644 --- a/.rubocop_todo/layout/line_length.yml +++ b/.rubocop_todo/layout/line_length.yml @@ -2906,7 +2906,6 @@ Layout/LineLength: - 'ee/spec/workers/update_all_mirrors_worker_spec.rb' - 'ee/spec/workers/vulnerability_exports/export_deletion_worker_spec.rb' - 'lib/api/admin/instance_clusters.rb' - - 'lib/api/admin/plan_limits.rb' - 'lib/api/api.rb' - 'lib/api/appearance.rb' - 'lib/api/award_emoji.rb' diff --git a/.rubocop_todo/rspec/timecop_travel.yml b/.rubocop_todo/rspec/timecop_travel.yml index a8ca3a5fad5..3a9ebc443fd 100644 --- a/.rubocop_todo/rspec/timecop_travel.yml +++ b/.rubocop_todo/rspec/timecop_travel.yml @@ -1,5 +1,4 @@ --- RSpec/TimecopTravel: Exclude: - - spec/workers/concerns/reenqueuer_spec.rb - qa/spec/support/repeater_spec.rb diff --git a/GITALY_SERVER_VERSION b/GITALY_SERVER_VERSION index 5d4b003c8fe..1f9ab02102a 100644 --- a/GITALY_SERVER_VERSION +++ b/GITALY_SERVER_VERSION @@ -1 +1 @@ -cdc87c3fefb4386c150cb4d71fcb4530d2b0501b +40398eb9e22e8cf09365f508f6779030ee90432a diff --git a/app/assets/javascripts/boards/components/board_list_header.vue b/app/assets/javascripts/boards/components/board_list_header.vue index cb2f68df0d1..bfc4b52baaf 100644 --- a/app/assets/javascripts/boards/components/board_list_header.vue +++ b/app/assets/javascripts/boards/components/board_list_header.vue @@ -171,6 +171,9 @@ export default { filters: this.filterParams, }; }, + context: { + isSingleRequest: true, + }, skip() { return this.isEpicBoard; }, diff --git a/app/assets/javascripts/lib/utils/dom_utils.js b/app/assets/javascripts/lib/utils/dom_utils.js index bca6978c206..cafee641174 100644 --- a/app/assets/javascripts/lib/utils/dom_utils.js +++ b/app/assets/javascripts/lib/utils/dom_utils.js @@ -106,3 +106,15 @@ export const setAttributes = (el, attributes) => { el.setAttribute(key, attributes[key]); }); }; + +/** + * Get the height of the wrapper page element + * This height can be used to determine where the highest element goes in a page + * Useful for gl-drawer's header-height prop + * @param {String} contentWrapperClass the content wrapper class + * @returns {String} height in px + */ +export const getContentWrapperHeight = (contentWrapperClass) => { + const wrapperEl = document.querySelector(contentWrapperClass); + return wrapperEl ? `${wrapperEl.offsetTop}px` : ''; +}; diff --git a/app/workers/authorized_keys_worker.rb b/app/workers/authorized_keys_worker.rb index 039fe629a61..77f2ed5f495 100644 --- a/app/workers/authorized_keys_worker.rb +++ b/app/workers/authorized_keys_worker.rb @@ -7,8 +7,6 @@ class AuthorizedKeysWorker sidekiq_options retry: 3 - PERMITTED_ACTIONS = %w[add_key remove_key].freeze - feature_category :source_code_management urgency :high weight 2 diff --git a/app/workers/gitlab_shell_worker.rb b/app/workers/gitlab_shell_worker.rb index 1bcaf5a42be..2f396dcdb86 100644 --- a/app/workers/gitlab_shell_worker.rb +++ b/app/workers/gitlab_shell_worker.rb @@ -14,18 +14,12 @@ class GitlabShellWorker # rubocop:disable Scalability/IdempotentWorker loggable_arguments 0 def perform(action, *arg) - # Gitlab::Shell is being removed but we need to continue to process jobs - # enqueued in the previous release, so handle them here. - # - # See https://gitlab.com/gitlab-org/gitlab/-/issues/25095 for more details - if AuthorizedKeysWorker::PERMITTED_ACTIONS.include?(action.to_s) - AuthorizedKeysWorker.new.perform(action, *arg) - - return + if ::Feature.enabled?(:verify_gitlab_shell_worker_method_names) && Gitlab::Shell::PERMITTED_ACTIONS.exclude?(action) + raise(ArgumentError, "#{action} not allowed for #{self.class.name}") end Gitlab::GitalyClient::NamespaceService.allow do - gitlab_shell.__send__(action, *arg) # rubocop:disable GitlabSecurity/PublicSend + gitlab_shell.public_send(action, *arg) # rubocop:disable GitlabSecurity/PublicSend end end end diff --git a/config/feature_flags/development/verify_gitlab_shell_worker_method_names.yml b/config/feature_flags/development/verify_gitlab_shell_worker_method_names.yml new file mode 100644 index 00000000000..d6b28c28600 --- /dev/null +++ b/config/feature_flags/development/verify_gitlab_shell_worker_method_names.yml @@ -0,0 +1,8 @@ +--- +name: verify_gitlab_shell_worker_method_names +introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/103783 +rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/371470 +milestone: '15.6' +type: development +group: group::scalability +default_enabled: false diff --git a/config/gitlab_loose_foreign_keys.yml b/config/gitlab_loose_foreign_keys.yml index 9e1bf15dee1..efb14cdea36 100644 --- a/config/gitlab_loose_foreign_keys.yml +++ b/config/gitlab_loose_foreign_keys.yml @@ -14,10 +14,6 @@ ci_builds: - table: ci_runners column: runner_id on_delete: async_nullify -ci_builds_metadata: - - table: projects - column: project_id - on_delete: async_delete ci_daily_build_group_report_results: - table: namespaces column: group_id diff --git a/config/initializers/database_query_analyzers.rb b/config/initializers/database_query_analyzers.rb index fcfc75341df..ad6ed20b94d 100644 --- a/config/initializers/database_query_analyzers.rb +++ b/config/initializers/database_query_analyzers.rb @@ -7,6 +7,7 @@ Gitlab::Database::QueryAnalyzer.instance.tap do |query_analyzer| query_analyzer.all_analyzers.tap do |analyzers| analyzers.append(::Gitlab::Database::QueryAnalyzers::GitlabSchemasMetrics) analyzers.append(::Gitlab::Database::QueryAnalyzers::PreventCrossDatabaseModification) + analyzers.append(::Gitlab::Database::QueryAnalyzers::Ci::PartitioningRoutingAnalyzer) if Gitlab.dev_or_test_env? analyzers.append(::Gitlab::Database::QueryAnalyzers::GitlabSchemasValidateConnection) diff --git a/config/open_api.yml b/config/open_api.yml index 96e72819d73..7f02fd23484 100644 --- a/config/open_api.yml +++ b/config/open_api.yml @@ -75,6 +75,8 @@ metadata: description: Operations related to User-starred metrics dashboards - name: package_files description: Operations about package files + - name: plan_limits + description: Operations related to plan limits - name: project_export description: Operations related to exporting projects - name: project_hooks diff --git a/config/sidekiq_queues.yml b/config/sidekiq_queues.yml index a403c0992fc..4ed4dca8912 100644 --- a/config/sidekiq_queues.yml +++ b/config/sidekiq_queues.yml @@ -259,6 +259,8 @@ - 1 - - integrations_slack_event - 1 +- - integrations_slack_interactivity + - 1 - - invalid_gpg_signature_update - 2 - - issuable_export_csv diff --git a/db/fixtures/development/17_cycle_analytics.rb b/db/fixtures/development/17_cycle_analytics.rb index 5c71e1ecdac..4f6bfc5c82a 100644 --- a/db/fixtures/development/17_cycle_analytics.rb +++ b/db/fixtures/development/17_cycle_analytics.rb @@ -2,6 +2,7 @@ require './spec/support/sidekiq_middleware' require './spec/support/helpers/test_env' +require 'active_support/testing/time_helpers' # Usage: # @@ -18,6 +19,8 @@ require './spec/support/helpers/test_env' # VSA_SEED_PROJECT_ID=10 FILTER=cycle_analytics SEED_VSA=1 bundle exec rake db:seed_fu class Gitlab::Seeder::CycleAnalytics + include ActiveSupport::Testing::TimeHelpers + attr_reader :project, :issues, :merge_requests, :developers FLAG = 'SEED_VSA' @@ -133,7 +136,7 @@ class Gitlab::Seeder::CycleAnalytics def create_issues! @issue_count.times do - Timecop.travel start_time + rand(5).days do + travel_to(start_time + rand(5).days) do title = "#{FFaker::Product.brand}-#{suffix}" @issues << Issue.create!(project: project, title: title, author: developers.sample) end diff --git a/doc/.vale/gitlab/Uppercase.yml b/doc/.vale/gitlab/Uppercase.yml index 72a4e2244f3..f53e1c72dcb 100644 --- a/doc/.vale/gitlab/Uppercase.yml +++ b/doc/.vale/gitlab/Uppercase.yml @@ -145,6 +145,7 @@ exceptions: - NOTE - NPM - NTP + - OCI - OKD - ONLY - OSS diff --git a/doc/.vale/gitlab/spelling-exceptions.txt b/doc/.vale/gitlab/spelling-exceptions.txt index 2a50a076098..0fc7c9703ac 100644 --- a/doc/.vale/gitlab/spelling-exceptions.txt +++ b/doc/.vale/gitlab/spelling-exceptions.txt @@ -615,6 +615,7 @@ Silverlight Sisense Sitespeed skippable +skopeo Slack Slackbot Slony diff --git a/lefthook.yml b/lefthook.yml index 03542a437e3..dc2c0b70c6f 100644 --- a/lefthook.yml +++ b/lefthook.yml @@ -54,7 +54,7 @@ pre-push: glob: 'doc/*.md' run: 'if [ $VALE_WARNINGS ]; then minWarnings=warning; else minWarnings=error; fi; if command -v vale > /dev/null 2>&1; then if ! vale --config .vale.ini --minAlertLevel $minWarnings {files}; then echo "ERROR: Fix any linting errors and make sure you are using the latest version of Vale."; exit 1; fi; else echo "ERROR: Vale not found. For more information, see https://docs.errata.ai/vale/install."; exit 1; fi' gettext: - skip: true # This is disabled by default. You can enable this check by adding skip: false in lefhook-local.yml https://github.com/evilmartians/lefthook/blob/master/docs/full_guide.md#skipping-commands + skip: true # This is disabled by default. You can enable this check by adding skip: false in lefhook-local.yml https://github.com/evilmartians/lefthook/blob/master/docs/configuration.md#skip tags: backend frontend view haml files: git diff --name-only --diff-filter=d $(git merge-base origin/master HEAD)..HEAD | while read file;do git diff --unified=1 $(git merge-base origin/master HEAD)..HEAD $file | grep -Fqe '_(' && echo $file;done; true glob: "*.{haml,rb,js,vue}" diff --git a/lib/api/admin/plan_limits.rb b/lib/api/admin/plan_limits.rb index 7ce70d85d46..49b41b44a18 100644 --- a/lib/api/admin/plan_limits.rb +++ b/lib/api/admin/plan_limits.rb @@ -5,6 +5,8 @@ module API class PlanLimits < ::API::Base before { authenticated_as_admin! } + PLAN_LIMITS_TAGS = %w[plan_limits].freeze + feature_category :not_owned # rubocop:todo Gitlab/AvoidFeatureCategoryNotOwned helpers do @@ -17,10 +19,17 @@ module API end desc 'Get current plan limits' do + detail 'List the current limits of a plan on the GitLab instance.' success Entities::PlanLimit + failure [ + { code: 401, message: 'Unauthorized' }, + { code: 403, message: 'Forbidden' } + ] + tags PLAN_LIMITS_TAGS end params do - optional :plan_name, type: String, values: Plan.all_plans, default: Plan::DEFAULT, desc: 'Name of the plan' + optional :plan_name, type: String, values: Plan.all_plans, default: Plan::DEFAULT, + desc: 'Name of the plan to get the limits from. Default: default.' end get "application/plan_limits" do params = declared_params(include_missing: false) @@ -29,16 +38,24 @@ module API present plan.actual_limits, with: Entities::PlanLimit end - desc 'Modify plan limits' do + desc 'Change plan limits' do + detail 'Modify the limits of a plan on the GitLab instance.' success Entities::PlanLimit + failure [ + { code: 400, message: 'Bad request' }, + { code: 401, message: 'Unauthorized' }, + { code: 403, message: 'Forbidden' } + ] + tags PLAN_LIMITS_TAGS end params do - requires :plan_name, type: String, values: Plan.all_plans, desc: 'Name of the plan' + requires :plan_name, type: String, values: Plan.all_plans, desc: 'Name of the plan to update' optional :ci_pipeline_size, type: Integer, desc: 'Maximum number of jobs in a single pipeline' optional :ci_active_jobs, type: Integer, desc: 'Total number of jobs in currently active pipelines' optional :ci_active_pipelines, type: Integer, desc: 'Maximum number of active pipelines per project' - optional :ci_project_subscriptions, type: Integer, desc: 'Maximum number of pipeline subscriptions to and from a project' + optional :ci_project_subscriptions, type: Integer, + desc: 'Maximum number of pipeline subscriptions to and from a project' optional :ci_pipeline_schedules, type: Integer, desc: 'Maximum number of pipeline schedules' optional :ci_needs_size_limit, type: Integer, desc: 'Maximum number of DAG dependencies that a job can have' optional :ci_registered_group_runners, type: Integer, desc: 'Maximum number of runners registered per group' @@ -50,7 +67,8 @@ module API optional :npm_max_file_size, type: Integer, desc: 'Maximum NPM package file size in bytes' optional :nuget_max_file_size, type: Integer, desc: 'Maximum NuGet package file size in bytes' optional :pypi_max_file_size, type: Integer, desc: 'Maximum PyPI package file size in bytes' - optional :terraform_module_max_file_size, type: Integer, desc: 'Maximum Terraform Module package file size in bytes' + optional :terraform_module_max_file_size, type: Integer, + desc: 'Maximum Terraform Module package file size in bytes' optional :storage_size_limit, type: Integer, desc: 'Maximum storage size for the root namespace in megabytes' end put "application/plan_limits" do diff --git a/lib/api/api.rb b/lib/api/api.rb index 2b69249f09c..c0d5e84f5b1 100644 --- a/lib/api/api.rb +++ b/lib/api/api.rb @@ -173,6 +173,7 @@ module API mount ::API::AccessRequests mount ::API::Admin::Ci::Variables mount ::API::Admin::InstanceClusters + mount ::API::Admin::PlanLimits mount ::API::Appearance mount ::API::Applications mount ::API::Avatar @@ -265,7 +266,6 @@ module API # Keep in alphabetical order mount ::API::Admin::BatchedBackgroundMigrations - mount ::API::Admin::PlanLimits mount ::API::Admin::Sidekiq mount ::API::AlertManagementAlerts mount ::API::AwardEmoji diff --git a/lib/api/entities/plan_limit.rb b/lib/api/entities/plan_limit.rb index 94e50f19b35..34018f03eb1 100644 --- a/lib/api/entities/plan_limit.rb +++ b/lib/api/entities/plan_limit.rb @@ -3,23 +3,23 @@ module API module Entities class PlanLimit < Grape::Entity - expose :ci_pipeline_size - expose :ci_active_jobs - expose :ci_active_pipelines - expose :ci_project_subscriptions - expose :ci_pipeline_schedules - expose :ci_needs_size_limit - expose :ci_registered_group_runners - expose :ci_registered_project_runners - expose :conan_max_file_size - expose :generic_packages_max_file_size - expose :helm_max_file_size - expose :maven_max_file_size - expose :npm_max_file_size - expose :nuget_max_file_size - expose :pypi_max_file_size - expose :terraform_module_max_file_size - expose :storage_size_limit + expose :ci_pipeline_size, documentation: { type: 'integer', example: 0 } + expose :ci_active_jobs, documentation: { type: 'integer', example: 0 } + expose :ci_active_pipelines, documentation: { type: 'integer', example: 0 } + expose :ci_project_subscriptions, documentation: { type: 'integer', example: 2 } + expose :ci_pipeline_schedules, documentation: { type: 'integer', example: 10 } + expose :ci_needs_size_limit, documentation: { type: 'integer', example: 50 } + expose :ci_registered_group_runners, documentation: { type: 'integer', example: 1000 } + expose :ci_registered_project_runners, documentation: { type: 'integer', example: 1000 } + expose :conan_max_file_size, documentation: { type: 'integer', example: 3221225472 } + expose :generic_packages_max_file_size, documentation: { type: 'integer', example: 5368709120 } + expose :helm_max_file_size, documentation: { type: 'integer', example: 5242880 } + expose :maven_max_file_size, documentation: { type: 'integer', example: 3221225472 } + expose :npm_max_file_size, documentation: { type: 'integer', example: 524288000 } + expose :nuget_max_file_size, documentation: { type: 'integer', example: 524288000 } + expose :pypi_max_file_size, documentation: { type: 'integer', example: 3221225472 } + expose :terraform_module_max_file_size, documentation: { type: 'integer', example: 1073741824 } + expose :storage_size_limit, documentation: { type: 'integer', example: 15000 } end end end diff --git a/lib/gitlab/database/query_analyzers/ci/partitioning_analyzer.rb b/lib/gitlab/database/query_analyzers/ci/partitioning_id_analyzer.rb index 055d34b3309..47277182d9a 100644 --- a/lib/gitlab/database/query_analyzers/ci/partitioning_analyzer.rb +++ b/lib/gitlab/database/query_analyzers/ci/partitioning_id_analyzer.rb @@ -4,47 +4,25 @@ module Gitlab module Database module QueryAnalyzers module Ci - # The purpose of this analyzer is to detect queries not going through a partitioning routing table - class PartitioningAnalyzer < Database::QueryAnalyzers::Base - RoutingTableNotUsedError = Class.new(QueryAnalyzerError) + # The purpose of this analyzer is to detect queries missing partition_id clause + # when selecting, inserting, updating or deleting data. + class PartitioningIdAnalyzer < Database::QueryAnalyzers::Base PartitionIdMissingError = Class.new(QueryAnalyzerError) - ENABLED_TABLES = %w[ - ci_builds_metadata - ].freeze - - ROUTING_TABLES = ENABLED_TABLES.map { |table| "p_#{table}" }.freeze + ROUTING_TABLES = %w[p_ci_builds_metadata].freeze class << self def enabled? ::Feature::FlipperFeature.table_exists? && - ::Feature.enabled?(:ci_partitioning_analyze_queries, type: :ops) + ::Feature.enabled?(:ci_partitioning_analyze_queries_partition_id_check, type: :ops) end def analyze(parsed) - analyze_legacy_tables_usage(parsed) - analyze_partition_id_presence(parsed) if partition_id_check_enabled? + analyze_partition_id_presence(parsed) end private - def partition_id_check_enabled? - ::Feature::FlipperFeature.table_exists? && - ::Feature.enabled?(:ci_partitioning_analyze_queries_partition_id_check, type: :ops) - end - - def analyze_legacy_tables_usage(parsed) - detected = ENABLED_TABLES & (parsed.pg.dml_tables + parsed.pg.select_tables) - - return if detected.none? - - log_and_raise_error( - RoutingTableNotUsedError.new( - "Detected non-partitioned table use #{detected.inspect}: #{parsed.sql}" - ) - ) - end - def analyze_partition_id_presence(parsed) detected = ROUTING_TABLES & (parsed.pg.dml_tables + parsed.pg.select_tables) return if detected.none? @@ -56,7 +34,7 @@ module Gitlab return if partition_id_included?(detected_with_selected_columns) end - log_and_raise_error( + ::Gitlab::ErrorTracking.track_and_raise_for_dev_exception( PartitionIdMissingError.new( "Detected query against a partitioned table without partition id: #{parsed.sql}" ) @@ -78,10 +56,6 @@ module Gitlab result.all? { |_routing_table, columns| columns.include?('partition_id') } end - def log_and_raise_error(error) - ::Gitlab::ErrorTracking.track_and_raise_for_dev_exception(error) - end - def insert_query?(parsed) parsed.sql.start_with?('INSERT') end diff --git a/lib/gitlab/database/query_analyzers/ci/partitioning_routing_analyzer.rb b/lib/gitlab/database/query_analyzers/ci/partitioning_routing_analyzer.rb new file mode 100644 index 00000000000..eb55ebc7619 --- /dev/null +++ b/lib/gitlab/database/query_analyzers/ci/partitioning_routing_analyzer.rb @@ -0,0 +1,39 @@ +# frozen_string_literal: true + +module Gitlab + module Database + module QueryAnalyzers + module Ci + # The purpose of this analyzer is to detect queries not going through a partitioning routing table + class PartitioningRoutingAnalyzer < Database::QueryAnalyzers::Base + RoutingTableNotUsedError = Class.new(QueryAnalyzerError) + + ENABLED_TABLES = %w[ci_builds_metadata].freeze + + class << self + def enabled? + ::Feature::FlipperFeature.table_exists? && + ::Feature.enabled?(:ci_partitioning_analyze_queries, type: :ops) + end + + def analyze(parsed) + analyze_legacy_tables_usage(parsed) + end + + private + + def analyze_legacy_tables_usage(parsed) + detected = ENABLED_TABLES & (parsed.pg.dml_tables + parsed.pg.select_tables) + + return if detected.none? + + ::Gitlab::ErrorTracking.track_and_raise_for_dev_exception( + RoutingTableNotUsedError.new("Detected non-partitioned table use #{detected.inspect}: #{parsed.sql}") + ) + end + end + end + end + end + end +end diff --git a/lib/gitlab/shell.rb b/lib/gitlab/shell.rb index b167afe589a..bc59d4ce943 100644 --- a/lib/gitlab/shell.rb +++ b/lib/gitlab/shell.rb @@ -14,6 +14,11 @@ module Gitlab class Shell Error = Class.new(StandardError) + PERMITTED_ACTIONS = %w[ + mv_repository remove_repository add_namespace rm_namespace mv_namespace + repository_exists? + ].freeze + class << self # Retrieve GitLab Shell secret token # diff --git a/lib/gitlab/slash_commands/incident_management/incident_command.rb b/lib/gitlab/slash_commands/incident_management/incident_command.rb index 13d371151f9..3fa08621777 100644 --- a/lib/gitlab/slash_commands/incident_management/incident_command.rb +++ b/lib/gitlab/slash_commands/incident_management/incident_command.rb @@ -15,3 +15,5 @@ module Gitlab end end end + +Gitlab::SlashCommands::IncidentManagement::IncidentCommand.prepend_mod diff --git a/lib/gitlab/slash_commands/incident_management/incident_new.rb b/lib/gitlab/slash_commands/incident_management/incident_new.rb index ce148f888b8..722fcff151d 100644 --- a/lib/gitlab/slash_commands/incident_management/incident_new.rb +++ b/lib/gitlab/slash_commands/incident_management/incident_new.rb @@ -16,12 +16,6 @@ module Gitlab text == 'incident declare' end - def execute(_match) - response = ServiceResponse.success(message: 'It works!') - - presenter.present(response.message) - end - private def presenter @@ -31,3 +25,5 @@ module Gitlab end end end + +Gitlab::SlashCommands::IncidentManagement::IncidentNew.prepend_mod diff --git a/locale/gitlab.pot b/locale/gitlab.pot index 05a11512583..a2b05faa74f 100644 --- a/locale/gitlab.pot +++ b/locale/gitlab.pot @@ -1157,6 +1157,9 @@ msgstr "" msgid "%{type} only supports %{name} name" msgstr "" +msgid "%{url} (optional)" +msgstr "" + msgid "%{userName} (cannot merge)" msgstr "" @@ -11643,6 +11646,9 @@ msgstr "" msgid "Credit card:" msgstr "" +msgid "Critical - S1" +msgstr "" + msgid "Critical vulnerabilities present" msgstr "" @@ -20083,6 +20089,9 @@ msgstr "" msgid "Hierarchy|You can start using these items now." msgstr "" +msgid "High - S2" +msgstr "" + msgid "High or unknown vulnerabilities present" msgstr "" @@ -21328,12 +21337,18 @@ msgstr "" msgid "Incident Management Limits" msgstr "" +msgid "Incident creation cancelled." +msgstr "" + msgid "Incident details" msgstr "" msgid "Incident template (optional)." msgstr "" +msgid "Incident title" +msgstr "" + msgid "IncidentManagement|%{hours} hours, %{minutes} minutes remaining" msgstr "" @@ -24702,6 +24717,9 @@ msgstr "" msgid "Logs" msgstr "" +msgid "Low - S4" +msgstr "" + msgid "Low vulnerabilities present" msgstr "" @@ -25308,6 +25326,9 @@ msgstr "" msgid "Measured in bytes of code. Excludes generated and vendored code." msgstr "" +msgid "Medium - S3" +msgstr "" + msgid "Medium timeout" msgstr "" @@ -26952,6 +26973,9 @@ msgstr "" msgid "New identity" msgstr "" +msgid "New incident" +msgstr "" + msgid "New issue" msgstr "" @@ -30511,6 +30535,9 @@ msgstr "" msgid "Please click the link in the confirmation email before continuing. It was sent to %{html_tag_strong_start}%{email}%{html_tag_strong_end}." msgstr "" +msgid "Please complete the incident creation form." +msgstr "" + msgid "Please complete your profile with email address" msgstr "" @@ -37181,6 +37208,9 @@ msgstr "" msgid "Select reviewer(s)" msgstr "" +msgid "Select severity (optional)" +msgstr "" + msgid "Select source" msgstr "" @@ -38370,6 +38400,9 @@ msgstr "" msgid "Something went wrong while closing the epic. Please try again later." msgstr "" +msgid "Something went wrong while closing the incident form." +msgstr "" + msgid "Something went wrong while closing the merge request. Please try again later." msgstr "" @@ -38439,6 +38472,9 @@ msgstr "" msgid "Something went wrong while obtaining the Let's Encrypt certificate." msgstr "" +msgid "Something went wrong while opening the incident form." +msgstr "" + msgid "Something went wrong while promoting the issue to an epic. Please try again." msgstr "" @@ -46395,6 +46431,9 @@ msgstr "" msgid "Write a description or drag your files here…" msgstr "" +msgid "Write a description..." +msgstr "" + msgid "Write a description…" msgstr "" @@ -46781,6 +46820,9 @@ msgstr "" msgid "You could not create a new trigger." msgstr "" +msgid "You do not have access to any projects for creating incidents." +msgstr "" + msgid "You do not have any subscriptions yet" msgstr "" @@ -47512,6 +47554,9 @@ msgstr "" msgid "ZentaoIntegration|ZenTao issues" msgstr "" +msgid "Zoom" +msgstr "" + msgid "Zoom meeting added" msgstr "" @@ -47527,6 +47572,9 @@ msgstr "" msgid "[Redacted]" msgstr "" +msgid "[Supports GitLab-flavored markdown, including quick actions]" +msgstr "" + msgid "`end_time` should not exceed one month after `start_time`" msgstr "" diff --git a/qa/qa/specs/spec_helper.rb b/qa/qa/specs/spec_helper.rb index 8fb0ce0ab2f..a4721040683 100644 --- a/qa/qa/specs/spec_helper.rb +++ b/qa/qa/specs/spec_helper.rb @@ -1,6 +1,7 @@ # frozen_string_literal: true require_relative '../../qa' +require 'active_support/testing/time_helpers' QA::Specs::QaDeprecationToolkitEnv.configure! @@ -18,6 +19,7 @@ RSpec.configure(&:disable_monkey_patching!) require_relative('../../../jh/qa/qa/specs/spec_helper') if GitlabEdition.jh? RSpec.configure do |config| + config.include ActiveSupport::Testing::TimeHelpers config.include QA::Support::Matchers::EventuallyMatcher config.include QA::Support::Matchers::HaveMatcher diff --git a/qa/spec/tools/test_resources_data_processor_spec.rb b/qa/spec/tools/test_resources_data_processor_spec.rb index 2ae43974a0c..73fc2f6e853 100644 --- a/qa/spec/tools/test_resources_data_processor_spec.rb +++ b/qa/spec/tools/test_resources_data_processor_spec.rb @@ -1,7 +1,5 @@ # frozen_string_literal: true - require 'active_support/testing/time_helpers' - RSpec.describe QA::Tools::TestResourceDataProcessor do include QA::Support::Helpers::StubEnv include ActiveSupport::Testing::TimeHelpers diff --git a/spec/db/schema_spec.rb b/spec/db/schema_spec.rb index c383c4b6f24..ad49a763361 100644 --- a/spec/db/schema_spec.rb +++ b/spec/db/schema_spec.rb @@ -14,6 +14,8 @@ RSpec.describe 'Database schema' do issues: %w[work_item_type_id] }.with_indifferent_access.freeze + TABLE_PARTITIONS = %w[ci_builds_metadata].freeze + # List of columns historically missing a FK, don't add more columns # See: https://docs.gitlab.com/ee/development/database/foreign_keys.html#naming-foreign-keys IGNORED_FK_COLUMNS = { @@ -32,7 +34,6 @@ RSpec.describe 'Database schema' do chat_names: %w[chat_id team_id user_id], chat_teams: %w[team_id], ci_builds: %w[erased_by_id trigger_request_id partition_id], - ci_builds_metadata: %w[partition_id], p_ci_builds_metadata: %w[partition_id], ci_job_artifacts: %w[partition_id], ci_namespace_monthly_usages: %w[namespace_id], @@ -108,7 +109,7 @@ RSpec.describe 'Database schema' do }.with_indifferent_access.freeze context 'for table' do - ActiveRecord::Base.connection.tables.sort.each do |table| + (ActiveRecord::Base.connection.tables - TABLE_PARTITIONS).sort.each do |table| describe table do let(:indexes) { connection.indexes(table) } let(:columns) { connection.columns(table) } diff --git a/spec/frontend/fixtures/freeze_period.rb b/spec/frontend/fixtures/freeze_period.rb index dd16bd81b51..5aa466ef015 100644 --- a/spec/frontend/fixtures/freeze_period.rb +++ b/spec/frontend/fixtures/freeze_period.rb @@ -16,7 +16,7 @@ RSpec.describe 'Freeze Periods (JavaScript fixtures)' do around do |example| freeze_time do # Mock time to sept 19 (intl. talk like a pirate day) - Timecop.travel(2020, 9, 19) + travel_to(Time.utc(2020, 9, 19)) example.run end diff --git a/spec/frontend/lib/utils/dom_utils_spec.js b/spec/frontend/lib/utils/dom_utils_spec.js index b537e6b2bf8..d6bac935970 100644 --- a/spec/frontend/lib/utils/dom_utils_spec.js +++ b/spec/frontend/lib/utils/dom_utils_spec.js @@ -1,8 +1,10 @@ import { setHTMLFixture, resetHTMLFixture } from 'helpers/fixtures'; + import { addClassIfElementExists, canScrollUp, canScrollDown, + getContentWrapperHeight, parseBooleanDataAttributes, isElementVisible, getParents, @@ -235,4 +237,30 @@ describe('DOM Utils', () => { expect(div.getAttribute('title')).toBe('another test'); }); }); + + describe('getContentWrapperHeight', () => { + const fixture = ` + <div> + <div class="content-wrapper"> + <div class="content"></div> + </div> + </div> + `; + + beforeEach(() => { + setHTMLFixture(fixture); + }); + + afterEach(() => { + resetHTMLFixture(); + }); + + it('returns the height of an element that exists', () => { + expect(getContentWrapperHeight('.content-wrapper')).toBe('0px'); + }); + + it('returns an empty string for a class that does not exist', () => { + expect(getContentWrapperHeight('.does-not-exist')).toBe(''); + }); + }); }); diff --git a/spec/lib/gitlab/database/query_analyzers/ci/partitioning_analyzer_spec.rb b/spec/lib/gitlab/database/query_analyzers/ci/partitioning_analyzer_spec.rb deleted file mode 100644 index 01990933d0a..00000000000 --- a/spec/lib/gitlab/database/query_analyzers/ci/partitioning_analyzer_spec.rb +++ /dev/null @@ -1,163 +0,0 @@ -# frozen_string_literal: true - -require 'spec_helper' - -RSpec.describe Gitlab::Database::QueryAnalyzers::Ci::PartitioningAnalyzer, query_analyzers: false do - let(:analyzer) { described_class } - - before do - allow(Gitlab::Database::QueryAnalyzer.instance).to receive(:all_analyzers).and_return([analyzer]) - end - - context 'when ci_partitioning_analyze_queries is disabled' do - before do - stub_feature_flags(ci_partitioning_analyze_queries: false) - end - - it 'does not analyze the query' do - expect(analyzer).not_to receive(:analyze) - - process_sql(Ci::BuildMetadata, "SELECT 1 FROM ci_builds_metadata") - end - end - - context 'when ci_partitioning_analyze_queries is enabled' do - context 'when analyzing targeted tables' do - described_class::ENABLED_TABLES.each do |enabled_table| - context 'when querying a non routing table' do - it 'tracks exception' do - expect(::Gitlab::ErrorTracking).to receive(:track_and_raise_for_dev_exception) - process_sql(Ci::ApplicationRecord, "SELECT 1 FROM #{enabled_table}") - end - - it 'raises RoutingTableNotUsedError' do - expect { process_sql(Ci::ApplicationRecord, "SELECT 1 FROM #{enabled_table}") } - .to raise_error(described_class::RoutingTableNotUsedError) - end - end - end - - context 'when updating a record' do - it 'raises RoutingTableNotUsedError' do - expect { process_sql(Ci::BuildMetadata, "UPDATE ci_builds_metadata SET id = 1") } - .to raise_error(described_class::RoutingTableNotUsedError) - end - end - - context 'when inserting a record' do - it 'raises RoutingTableNotUsedError' do - expect { process_sql(Ci::BuildMetadata, "INSERT INTO ci_builds_metadata (id) VALUES(1)") } - .to raise_error(described_class::RoutingTableNotUsedError) - end - end - end - - context 'when analyzing non targeted table' do - it 'does not raise error' do - expect { process_sql(Ci::BuildMetadata, "SELECT 1 FROM projects") }.not_to raise_error - end - end - - context 'when querying a routing table' do - shared_examples 'a good query' do |sql| - it 'does not raise error' do - expect { process_sql(Ci::BuildMetadata, sql) }.not_to raise_error - end - end - - shared_examples 'a bad query' do |sql| - it 'raises PartitionIdMissingError' do - expect { process_sql(Ci::BuildMetadata, sql) }.to raise_error(described_class::PartitionIdMissingError) - end - end - - context 'when selecting data' do - it_behaves_like 'a good query', 'SELECT * FROM p_ci_builds_metadata WHERE partition_id = 100' - end - - context 'with a join query' do - sql = <<~SQL - SELECT ci_builds.id - FROM p_ci_builds - JOIN p_ci_builds_metadata ON p_ci_builds_metadata.build_id = ci_builds.id - WHERE ci_builds.type = 'Ci::Build' - AND ci_builds.partition_id = 100 - AND (NOT p_ci_builds_metadata.id IN - (SELECT p_ci_builds_metadata.id - FROM p_ci_builds_metadata - WHERE p_ci_builds_metadata.build_id = ci_builds.id - AND p_ci_builds_metadata.interruptible = TRUE - AND p_ci_builds_metadata.partition_id = 100 )); - SQL - - it_behaves_like 'a good query', sql - end - - context 'when removing data' do - it_behaves_like 'a good query', 'DELETE FROM p_ci_builds_metadata WHERE partition_id = 100' - end - - context 'when updating data' do - it_behaves_like 'a good query', 'UPDATE p_ci_builds_metadata SET interruptible = false WHERE partition_id = 100' - end - - context 'when inserting a record' do - it_behaves_like 'a good query', 'INSERT INTO p_ci_builds_metadata (id, partition_id) VALUES(1, 1)' - end - - context 'when partition_id is missing' do - context 'when inserting a record' do - it_behaves_like 'a bad query', 'INSERT INTO p_ci_builds_metadata (id) VALUES(1)' - end - - context 'when selecting data' do - it_behaves_like 'a bad query', 'SELECT * FROM p_ci_builds_metadata WHERE id = 1' - end - - context 'when removing data' do - it_behaves_like 'a bad query', 'DELETE FROM p_ci_builds_metadata WHERE id = 1' - end - - context 'when updating data' do - it_behaves_like 'a bad query', 'UPDATE p_ci_builds_metadata SET interruptible = false WHERE id = 1' - end - - context 'with a join query' do - sql = <<~SQL - SELECT ci_builds.id - FROM ci_builds - JOIN p_ci_builds_metadata ON p_ci_builds_metadata.build_id = ci_builds.id - WHERE ci_builds.type = 'Ci::Build' - AND ci_builds.partition_id = 100 - AND (NOT p_ci_builds_metadata.id IN - (SELECT p_ci_builds_metadata.id - FROM p_ci_builds_metadata - WHERE p_ci_builds_metadata.build_id = ci_builds.id - AND p_ci_builds_metadata.interruptible = TRUE )); - SQL - - it_behaves_like 'a bad query', sql - end - end - - context 'when ci_partitioning_analyze_queries_partition_id_check is disabled' do - before do - stub_feature_flags(ci_partitioning_analyze_queries_partition_id_check: false) - end - - it 'does not check if partition_id is included in the query' do - expect { process_sql(Ci::BuildMetadata, 'SELECT * from p_ci_builds_metadata') }.not_to raise_error - end - end - end - end - - private - - def process_sql(model, sql) - Gitlab::Database::QueryAnalyzer.instance.within do - # Skip load balancer and retrieve connection assigned to model - Gitlab::Database::QueryAnalyzer.instance.send(:process_sql, sql, model.retrieve_connection) - end - end -end diff --git a/spec/lib/gitlab/database/query_analyzers/ci/partitioning_id_analyzer_spec.rb b/spec/lib/gitlab/database/query_analyzers/ci/partitioning_id_analyzer_spec.rb new file mode 100644 index 00000000000..0fe19041b6d --- /dev/null +++ b/spec/lib/gitlab/database/query_analyzers/ci/partitioning_id_analyzer_spec.rb @@ -0,0 +1,121 @@ +# frozen_string_literal: true + +require 'spec_helper' + +RSpec.describe Gitlab::Database::QueryAnalyzers::Ci::PartitioningIdAnalyzer, query_analyzers: false do + let(:analyzer) { described_class } + + before do + allow(Gitlab::Database::QueryAnalyzer.instance).to receive(:all_analyzers).and_return([analyzer]) + end + + context 'when ci_partitioning_analyze_queries_partition_id_check is disabled' do + before do + stub_feature_flags(ci_partitioning_analyze_queries_partition_id_check: false) + end + + it 'does not analyze the query' do + expect(analyzer).not_to receive(:analyze) + + process_sql(Ci::BuildMetadata, "SELECT 1 FROM ci_builds_metadata") + end + end + + context 'when ci_partitioning_analyze_queries_partition_id_check is enabled' do + context 'when querying a routing table' do + shared_examples 'a good query' do |sql| + it 'does not raise error' do + expect { process_sql(Ci::BuildMetadata, sql) }.not_to raise_error + end + end + + shared_examples 'a bad query' do |sql| + it 'raises PartitionIdMissingError' do + expect { process_sql(Ci::BuildMetadata, sql) }.to raise_error(described_class::PartitionIdMissingError) + end + end + + context 'when partition_id is present' do + context 'when selecting data' do + it_behaves_like 'a good query', 'SELECT * FROM p_ci_builds_metadata WHERE partition_id = 100' + end + + context 'with a join query' do + sql = <<~SQL + SELECT ci_builds.id + FROM p_ci_builds + JOIN p_ci_builds_metadata ON p_ci_builds_metadata.build_id = ci_builds.id + WHERE ci_builds.type = 'Ci::Build' + AND ci_builds.partition_id = 100 + AND (NOT p_ci_builds_metadata.id IN + (SELECT p_ci_builds_metadata.id + FROM p_ci_builds_metadata + WHERE p_ci_builds_metadata.build_id = ci_builds.id + AND p_ci_builds_metadata.interruptible = TRUE + AND p_ci_builds_metadata.partition_id = 100 )); + SQL + + it_behaves_like 'a good query', sql + end + + context 'when removing data' do + it_behaves_like 'a good query', 'DELETE FROM p_ci_builds_metadata WHERE partition_id = 100' + end + + context 'when updating data' do + sql = 'UPDATE p_ci_builds_metadata SET interruptible = false WHERE partition_id = 100' + + it_behaves_like 'a good query', sql + end + + context 'when inserting a record' do + it_behaves_like 'a good query', 'INSERT INTO p_ci_builds_metadata (id, partition_id) VALUES(1, 1)' + end + end + + context 'when partition_id is missing' do + context 'when inserting a record' do + it_behaves_like 'a bad query', 'INSERT INTO p_ci_builds_metadata (id) VALUES(1)' + end + + context 'when selecting data' do + it_behaves_like 'a bad query', 'SELECT * FROM p_ci_builds_metadata WHERE id = 1' + end + + context 'when removing data' do + it_behaves_like 'a bad query', 'DELETE FROM p_ci_builds_metadata WHERE id = 1' + end + + context 'when updating data' do + it_behaves_like 'a bad query', 'UPDATE p_ci_builds_metadata SET interruptible = false WHERE id = 1' + end + + context 'with a join query' do + sql = <<~SQL + SELECT ci_builds.id + FROM ci_builds + JOIN p_ci_builds_metadata ON p_ci_builds_metadata.build_id = ci_builds.id + WHERE ci_builds.type = 'Ci::Build' + AND ci_builds.partition_id = 100 + AND (NOT p_ci_builds_metadata.id IN + (SELECT p_ci_builds_metadata.id + FROM p_ci_builds_metadata + WHERE p_ci_builds_metadata.build_id = ci_builds.id + AND p_ci_builds_metadata.interruptible = TRUE )); + SQL + + it_behaves_like 'a bad query', sql + end + end + end + end + + private + + def process_sql(model, sql) + Gitlab::Database::QueryAnalyzer.instance.within do + # Skip load balancer and retrieve connection assigned to model + Gitlab::Database::QueryAnalyzer.instance.send(:process_sql, sql, model.retrieve_connection) + end + end +end diff --git a/spec/lib/gitlab/database/query_analyzers/ci/partitioning_routing_analyzer_spec.rb b/spec/lib/gitlab/database/query_analyzers/ci/partitioning_routing_analyzer_spec.rb new file mode 100644 index 00000000000..1f86c2ccbb0 --- /dev/null +++ b/spec/lib/gitlab/database/query_analyzers/ci/partitioning_routing_analyzer_spec.rb @@ -0,0 +1,70 @@ +# frozen_string_literal: true + +require 'spec_helper' + +RSpec.describe Gitlab::Database::QueryAnalyzers::Ci::PartitioningRoutingAnalyzer, query_analyzers: false do + let(:analyzer) { described_class } + + before do + allow(Gitlab::Database::QueryAnalyzer.instance).to receive(:all_analyzers).and_return([analyzer]) + end + + context 'when ci_partitioning_analyze_queries is disabled' do + before do + stub_feature_flags(ci_partitioning_analyze_queries: false) + end + + it 'does not analyze the query' do + expect(analyzer).not_to receive(:analyze) + + process_sql(Ci::BuildMetadata, "SELECT 1 FROM ci_builds_metadata") + end + end + + context 'when ci_partitioning_analyze_queries is enabled' do + context 'when analyzing targeted tables' do + described_class::ENABLED_TABLES.each do |enabled_table| + context 'when querying a non routing table' do + it 'tracks exception' do + expect(::Gitlab::ErrorTracking).to receive(:track_and_raise_for_dev_exception) + process_sql(Ci::ApplicationRecord, "SELECT 1 FROM #{enabled_table}") + end + + it 'raises RoutingTableNotUsedError' do + expect { process_sql(Ci::ApplicationRecord, "SELECT 1 FROM #{enabled_table}") } + .to raise_error(described_class::RoutingTableNotUsedError) + end + end + end + + context 'when updating a record' do + it 'raises RoutingTableNotUsedError' do + expect { process_sql(Ci::BuildMetadata, "UPDATE ci_builds_metadata SET id = 1") } + .to raise_error(described_class::RoutingTableNotUsedError) + end + end + + context 'when inserting a record' do + it 'raises RoutingTableNotUsedError' do + expect { process_sql(Ci::BuildMetadata, "INSERT INTO ci_builds_metadata (id) VALUES(1)") } + .to raise_error(described_class::RoutingTableNotUsedError) + end + end + end + + context 'when analyzing non targeted table' do + it 'does not raise error' do + expect { process_sql(Ci::BuildMetadata, "SELECT 1 FROM projects") }.not_to raise_error + end + end + end + + private + + def process_sql(model, sql) + Gitlab::Database::QueryAnalyzer.instance.within do + # Skip load balancer and retrieve connection assigned to model + Gitlab::Database::QueryAnalyzer.instance.send(:process_sql, sql, model.retrieve_connection) + end + end +end diff --git a/spec/lib/gitlab/slash_commands/incident_management/incident_new_spec.rb b/spec/lib/gitlab/slash_commands/incident_management/incident_new_spec.rb deleted file mode 100644 index ee54f29aec7..00000000000 --- a/spec/lib/gitlab/slash_commands/incident_management/incident_new_spec.rb +++ /dev/null @@ -1,60 +0,0 @@ -# frozen_string_literal: true - -require 'spec_helper' - -RSpec.describe Gitlab::SlashCommands::IncidentManagement::IncidentNew do - let_it_be(:project) { create(:project) } - let_it_be(:user) { create(:user) } - let_it_be(:chat_name) { create(:chat_name, user: user) } - let_it_be(:regex_match) { described_class.match('declare') } - - subject do - described_class.new(project, chat_name) - end - - describe '#execute' do - context 'when invoked' do - it 'sends ephemeral response' do - response = subject.execute(regex_match) - - expect(response[:response_type]).to be(:ephemeral) - expect(response[:text]).to eq('It works!') - end - end - end - - describe '#allowed?' do - context 'when user has permissions' do - before do - project.add_developer(user) - end - - it 'returns true' do - expect(described_class).to be_allowed(project, user) - end - end - - context 'when feature flag is disabled' do - before do - project.add_developer(user) - stub_feature_flags(incident_declare_slash_command: false) - end - - it 'returns false in allowed?' do - expect(described_class).not_to be_allowed(project, user) - end - end - end - - describe '#collection' do - context 'when collection method id called' do - it 'calls IssuesFinder' do - expect_next_instance_of(IssuesFinder) do |finder| - expect(finder).to receive(:execute) - end - - subject.collection - end - end - end -end diff --git a/spec/workers/concerns/reenqueuer_spec.rb b/spec/workers/concerns/reenqueuer_spec.rb index 56db2239bb1..e7287b55af2 100644 --- a/spec/workers/concerns/reenqueuer_spec.rb +++ b/spec/workers/concerns/reenqueuer_spec.rb @@ -121,14 +121,7 @@ RSpec.describe Reenqueuer::ReenqueuerSleeper do # Unit test ensure_minimum_duration describe '#ensure_minimum_duration' do around do |example| - # Allow Timecop.travel without the block form - Timecop.safe_mode = false - - Timecop.freeze do - example.run - end - - Timecop.safe_mode = true + freeze_time { example.run } end let(:minimum_duration) { 4.seconds } @@ -140,31 +133,31 @@ RSpec.describe Reenqueuer::ReenqueuerSleeper do expect(dummy).to receive(:sleep).with(a_value_within(0.01).of(time_left)) dummy.ensure_minimum_duration(minimum_duration) do - Timecop.travel(minimum_duration - time_left) + travel(minimum_duration - time_left) end end end context 'when the block completes just before the minimum duration' do - let(:time_left) { 0.1.seconds } + let(:time_left) { 1.second } it 'sleeps until the minimum duration' do expect(dummy).to receive(:sleep).with(a_value_within(0.01).of(time_left)) dummy.ensure_minimum_duration(minimum_duration) do - Timecop.travel(minimum_duration - time_left) + travel(minimum_duration - time_left) end end end context 'when the block completes just after the minimum duration' do - let(:time_over) { 0.1.seconds } + let(:time_over) { 1.second } it 'does not sleep' do expect(dummy).not_to receive(:sleep) dummy.ensure_minimum_duration(minimum_duration) do - Timecop.travel(minimum_duration + time_over) + travel(minimum_duration + time_over) end end end @@ -176,7 +169,7 @@ RSpec.describe Reenqueuer::ReenqueuerSleeper do expect(dummy).not_to receive(:sleep) dummy.ensure_minimum_duration(minimum_duration) do - Timecop.travel(minimum_duration + time_over) + travel(minimum_duration + time_over) end end end diff --git a/spec/workers/gitlab_shell_worker_spec.rb b/spec/workers/gitlab_shell_worker_spec.rb index c46ef87333a..a5419291d35 100644 --- a/spec/workers/gitlab_shell_worker_spec.rb +++ b/spec/workers/gitlab_shell_worker_spec.rb @@ -2,37 +2,45 @@ require 'spec_helper' -RSpec.describe GitlabShellWorker do - let(:worker) { described_class.new } - +RSpec.describe GitlabShellWorker, :sidekiq_inline do describe '#perform' do - describe '#add_key' do - it 'delegates to Gitlab::AuthorizedKeys' do - expect_next_instance_of(Gitlab::AuthorizedKeys) do |instance| - expect(instance).to receive(:add_key).with('foo', 'bar') + Gitlab::Shell::PERMITTED_ACTIONS.each do |action| + describe "with the #{action} action" do + it 'forwards the message to Gitlab::Shell' do + expect_next_instance_of(Gitlab::Shell) do |instance| + expect(instance).to respond_to(action) + expect(instance).to receive(action).with('foo', 'bar') + end + + described_class.perform_async(action, 'foo', 'bar') end - - worker.perform('add_key', 'foo', 'bar') end end - describe '#remove_key' do - it 'delegates to Gitlab::AuthorizedKeys' do - expect_next_instance_of(Gitlab::AuthorizedKeys) do |instance| - expect(instance).to receive(:remove_key).with('foo', 'bar') + describe 'all other commands' do + context 'when verify_gitlab_shell_worker_method_names is enabled' do + it 'raises ArgumentError' do + allow_next_instance_of(described_class) do |job_instance| + expect(job_instance).not_to receive(:gitlab_shell) + end + + expect { described_class.perform_async('foo', 'bar', 'baz') } + .to raise_error(ArgumentError, 'foo not allowed for GitlabShellWorker') end - - worker.perform('remove_key', 'foo', 'bar') end - end - describe 'all other commands' do - it 'delegates them to Gitlab::Shell' do - expect_next_instance_of(Gitlab::Shell) do |instance| - expect(instance).to receive(:foo).with('bar', 'baz') + context 'when verify_gitlab_shell_worker_method_names is disabled' do + before do + stub_feature_flags(verify_gitlab_shell_worker_method_names: false) end - worker.perform('foo', 'bar', 'baz') + it 'forwards the message to Gitlab::Shell' do + expect_next_instance_of(Gitlab::Shell) do |instance| + expect(instance).to receive('foo').with('bar', 'baz') + end + + described_class.perform_async('foo', 'bar', 'baz') + end end end end |