summaryrefslogtreecommitdiff
path: root/spec/support
diff options
context:
space:
mode:
authorGitLab Bot <gitlab-bot@gitlab.com>2021-11-18 13:16:36 +0000
committerGitLab Bot <gitlab-bot@gitlab.com>2021-11-18 13:16:36 +0000
commit311b0269b4eb9839fa63f80c8d7a58f32b8138a0 (patch)
tree07e7870bca8aed6d61fdcc810731c50d2c40af47 /spec/support
parent27909cef6c4170ed9205afa7426b8d3de47cbb0c (diff)
downloadgitlab-ce-311b0269b4eb9839fa63f80c8d7a58f32b8138a0.tar.gz
Add latest changes from gitlab-org/gitlab@14-5-stable-eev14.5.0-rc42
Diffstat (limited to 'spec/support')
-rw-r--r--spec/support/capybara.rb4
-rw-r--r--spec/support/database/cross-database-modification-allowlist.yml1259
-rw-r--r--spec/support/database/cross-join-allowlist.yml54
-rw-r--r--spec/support/database/gitlab_schema.rb25
-rw-r--r--spec/support/database/multiple_databases.rb27
-rw-r--r--spec/support/database/prevent_cross_database_modification.rb122
-rw-r--r--spec/support/database/prevent_cross_joins.rb4
-rw-r--r--spec/support/database/query_analyzer.rb14
-rw-r--r--spec/support/database_load_balancing.rb16
-rw-r--r--spec/support/flaky_tests.rb36
-rw-r--r--spec/support/gitlab/usage/metrics_instrumentation_shared_examples.rb4
-rw-r--r--spec/support/graphql/fake_query_type.rb15
-rw-r--r--spec/support/graphql/fake_tracer.rb15
-rw-r--r--spec/support/helpers/cycle_analytics_helpers.rb4
-rw-r--r--spec/support/helpers/features/invite_members_modal_helper.rb2
-rw-r--r--spec/support/helpers/gitaly_setup.rb2
-rw-r--r--spec/support/helpers/gpg_helpers.rb1
-rw-r--r--spec/support/helpers/graphql_helpers.rb3
-rw-r--r--spec/support/helpers/migrations_helpers.rb6
-rw-r--r--spec/support/helpers/navbar_structure_helper.rb13
-rw-r--r--spec/support/helpers/project_forks_helper.rb6
-rw-r--r--spec/support/helpers/require_migration.rb6
-rw-r--r--spec/support/helpers/stub_gitlab_calls.rb9
-rw-r--r--spec/support/helpers/stub_object_storage.rb12
-rw-r--r--spec/support/helpers/test_env.rb4
-rw-r--r--spec/support/helpers/usage_data_helpers.rb2
-rw-r--r--spec/support/helpers/workhorse_helpers.rb7
-rw-r--r--spec/support/matchers/access_matchers.rb2
-rw-r--r--spec/support/matchers/project_namespace_matcher.rb28
-rw-r--r--spec/support/patches/rspec_example_prepended_methods.rb26
-rw-r--r--spec/support/redis/redis_shared_examples.rb37
-rw-r--r--spec/support/retriable.rb7
-rw-r--r--spec/support/shared_contexts/graphql/requests/packages_shared_context.rb6
-rw-r--r--spec/support/shared_contexts/lib/gitlab/database/background_migration_job_shared_context.rb21
-rw-r--r--spec/support/shared_contexts/navbar_structure_context.rb2
-rw-r--r--spec/support/shared_contexts/policies/project_policy_shared_context.rb11
-rw-r--r--spec/support/shared_contexts/requests/api/debian_repository_shared_context.rb120
-rw-r--r--spec/support/shared_contexts/services/projects/container_repository/delete_tags_service_shared_context.rb4
-rw-r--r--spec/support/shared_contexts/services/service_ping/stubbed_service_ping_metrics_definitions_shared_context.rb5
-rw-r--r--spec/support/shared_contexts/url_shared_context.rb39
-rw-r--r--spec/support/shared_examples/bulk_imports/common/pipelines/wiki_pipeline_examples.rb31
-rw-r--r--spec/support/shared_examples/controllers/concerns/integrations/integrations_actions_shared_examples.rb (renamed from spec/support/shared_examples/controllers/concerns/integrations_actions_shared_examples.rb)2
-rw-r--r--spec/support/shared_examples/controllers/create_notes_rate_limit_shared_examples.rb58
-rw-r--r--spec/support/shared_examples/features/2fa_shared_examples.rb1
-rw-r--r--spec/support/shared_examples/features/dependency_proxy_shared_examples.rb2
-rw-r--r--spec/support/shared_examples/features/manage_applications_shared_examples.rb2
-rw-r--r--spec/support/shared_examples/features/packages_shared_examples.rb30
-rw-r--r--spec/support/shared_examples/features/resolving_discussions_in_issues_shared_examples.rb38
-rw-r--r--spec/support/shared_examples/features/sidebar_shared_examples.rb11
-rw-r--r--spec/support/shared_examples/graphql/notes_creation_shared_examples.rb26
-rw-r--r--spec/support/shared_examples/lib/gitlab/ci/ci_trace_shared_examples.rb67
-rw-r--r--spec/support/shared_examples/lib/gitlab/cycle_analytics/deployment_metrics.rb2
-rw-r--r--spec/support/shared_examples/lib/gitlab/database/cte_materialized_shared_examples.rb6
-rw-r--r--spec/support/shared_examples/lib/gitlab/import_export/attributes_permitter_shared_examples.rb4
-rw-r--r--spec/support/shared_examples/lib/gitlab/sidekiq_middleware/strategy_shared_examples.rb44
-rw-r--r--spec/support/shared_examples/lib/sidebars/projects/menus/zentao_menu_shared_examples.rb42
-rw-r--r--spec/support/shared_examples/loose_foreign_keys/have_loose_foreign_key.rb52
-rw-r--r--spec/support/shared_examples/metrics/transaction_metrics_with_labels_shared_examples.rb219
-rw-r--r--spec/support/shared_examples/models/concerns/analytics/cycle_analytics/stage_event_model_examples.rb117
-rw-r--r--spec/support/shared_examples/models/concerns/ttl_expirable_shared_examples.rb15
-rw-r--r--spec/support/shared_examples/models/member_shared_examples.rb31
-rw-r--r--spec/support/shared_examples/models/reviewer_state_shared_examples.rb15
-rw-r--r--spec/support/shared_examples/namespaces/traversal_examples.rb22
-rw-r--r--spec/support/shared_examples/namespaces/traversal_scope_examples.rb81
-rw-r--r--spec/support/shared_examples/quick_actions/issue/promote_to_incident_quick_action_shared_examples.rb40
-rw-r--r--spec/support/shared_examples/requests/api/debian_common_shared_examples.rb17
-rw-r--r--spec/support/shared_examples/requests/api/debian_distributions_shared_examples.rb192
-rw-r--r--spec/support/shared_examples/requests/api/debian_packages_shared_examples.rb369
-rw-r--r--spec/support/shared_examples/requests/api/graphql/mutations/destroy_list_shared_examples.rb2
-rw-r--r--spec/support/shared_examples/requests/api/graphql/packages/package_details_shared_examples.rb18
-rw-r--r--spec/support/shared_examples/requests/api/notes_shared_examples.rb2
-rw-r--r--spec/support/shared_examples/requests/api/npm_packages_shared_examples.rb15
-rw-r--r--spec/support/shared_examples/requests/api/pypi_packages_shared_examples.rb4
-rw-r--r--spec/support/shared_examples/requests/api/status_shared_examples.rb29
-rw-r--r--spec/support/shared_examples/requests/applications_controller_shared_examples.rb44
-rw-r--r--spec/support/shared_examples/requests/self_monitoring_shared_examples.rb4
-rw-r--r--spec/support/shared_examples/requests/snippet_shared_examples.rb1
-rw-r--r--spec/support/shared_examples/service_desk_issue_templates_examples.rb8
-rw-r--r--spec/support/shared_examples/services/alert_management/alert_processing/alert_firing_shared_examples.rb6
-rw-r--r--spec/support/shared_examples/services/jira/requests/base_shared_examples.rb11
-rw-r--r--spec/support/shared_examples/services/resource_events/synthetic_notes_builder_shared_examples.rb25
-rw-r--r--spec/support/shared_examples/workers/self_monitoring_shared_examples.rb2
-rw-r--r--spec/support/stub_snowplow.rb2
-rw-r--r--spec/support/test_reports/test_reports_helper.rb6
-rw-r--r--spec/support/time_travel.rb21
85 files changed, 1715 insertions, 2001 deletions
diff --git a/spec/support/capybara.rb b/spec/support/capybara.rb
index ac35662ec93..14ef0f1b7e0 100644
--- a/spec/support/capybara.rb
+++ b/spec/support/capybara.rb
@@ -28,6 +28,8 @@ JS_CONSOLE_FILTER = Regexp.union([
CAPYBARA_WINDOW_SIZE = [1366, 768].freeze
+SCREENSHOT_FILENAME_LENGTH = ENV['CI'] || ENV['CI_SERVER'] ? 255 : 99
+
# Run Workhorse on the given host and port, proxying to Puma on a UNIX socket,
# for a closer-to-production experience
Capybara.register_server :puma_via_workhorse do |app, port, host, **options|
@@ -113,7 +115,7 @@ Capybara.enable_aria_label = true
Capybara::Screenshot.append_timestamp = false
Capybara::Screenshot.register_filename_prefix_formatter(:rspec) do |example|
- example.full_description.downcase.parameterize(separator: "_")[0..99]
+ example.full_description.downcase.parameterize(separator: "_")[0..SCREENSHOT_FILENAME_LENGTH]
end
# Keep only the screenshots generated from the last failing test suite
Capybara::Screenshot.prune_strategy = :keep_last_run
diff --git a/spec/support/database/cross-database-modification-allowlist.yml b/spec/support/database/cross-database-modification-allowlist.yml
index 627967f65f3..d05812a64eb 100644
--- a/spec/support/database/cross-database-modification-allowlist.yml
+++ b/spec/support/database/cross-database-modification-allowlist.yml
@@ -1,1343 +1,90 @@
-- "./ee/spec/controllers/admin/geo/nodes_controller_spec.rb"
-- "./ee/spec/controllers/admin/geo/projects_controller_spec.rb"
-- "./ee/spec/controllers/admin/projects_controller_spec.rb"
-- "./ee/spec/controllers/concerns/internal_redirect_spec.rb"
-- "./ee/spec/controllers/ee/projects/jobs_controller_spec.rb"
-- "./ee/spec/controllers/oauth/geo_auth_controller_spec.rb"
-- "./ee/spec/controllers/projects/approver_groups_controller_spec.rb"
-- "./ee/spec/controllers/projects/approvers_controller_spec.rb"
-- "./ee/spec/controllers/projects/merge_requests_controller_spec.rb"
-- "./ee/spec/controllers/projects/merge_requests/creations_controller_spec.rb"
- "./ee/spec/controllers/projects/settings/access_tokens_controller_spec.rb"
-- "./ee/spec/controllers/projects/subscriptions_controller_spec.rb"
-- "./ee/spec/features/account_recovery_regular_check_spec.rb"
-- "./ee/spec/features/admin/admin_audit_logs_spec.rb"
-- "./ee/spec/features/admin/admin_credentials_inventory_spec.rb"
-- "./ee/spec/features/admin/admin_dashboard_spec.rb"
-- "./ee/spec/features/admin/admin_dev_ops_report_spec.rb"
-- "./ee/spec/features/admin/admin_merge_requests_approvals_spec.rb"
-- "./ee/spec/features/admin/admin_reset_pipeline_minutes_spec.rb"
-- "./ee/spec/features/admin/admin_sends_notification_spec.rb"
-- "./ee/spec/features/admin/admin_settings_spec.rb"
-- "./ee/spec/features/admin/admin_show_new_user_signups_cap_alert_spec.rb"
-- "./ee/spec/features/admin/admin_users_spec.rb"
-- "./ee/spec/features/admin/geo/admin_geo_nodes_spec.rb"
-- "./ee/spec/features/admin/geo/admin_geo_projects_spec.rb"
-- "./ee/spec/features/admin/geo/admin_geo_replication_nav_spec.rb"
-- "./ee/spec/features/admin/geo/admin_geo_sidebar_spec.rb"
-- "./ee/spec/features/admin/geo/admin_geo_uploads_spec.rb"
-- "./ee/spec/features/admin/groups/admin_changes_plan_spec.rb"
-- "./ee/spec/features/admin/licenses/admin_uploads_license_spec.rb"
-- "./ee/spec/features/admin/licenses/show_user_count_threshold_spec.rb"
-- "./ee/spec/features/admin/subscriptions/admin_views_subscription_spec.rb"
-- "./ee/spec/features/analytics/code_analytics_spec.rb"
-- "./ee/spec/features/billings/billing_plans_spec.rb"
-- "./ee/spec/features/billings/extend_reactivate_trial_spec.rb"
-- "./ee/spec/features/billings/qrtly_reconciliation_alert_spec.rb"
-- "./ee/spec/features/boards/boards_licensed_features_spec.rb"
-- "./ee/spec/features/boards/boards_spec.rb"
-- "./ee/spec/features/boards/group_boards/board_deletion_spec.rb"
-- "./ee/spec/features/boards/group_boards/multiple_boards_spec.rb"
-- "./ee/spec/features/boards/new_issue_spec.rb"
-- "./ee/spec/features/boards/scoped_issue_board_spec.rb"
-- "./ee/spec/features/boards/sidebar_spec.rb"
-- "./ee/spec/features/boards/swimlanes/epics_swimlanes_drag_drop_spec.rb"
-- "./ee/spec/features/boards/swimlanes/epics_swimlanes_filtering_spec.rb"
-- "./ee/spec/features/boards/swimlanes/epics_swimlanes_sidebar_labels_spec.rb"
-- "./ee/spec/features/boards/swimlanes/epics_swimlanes_sidebar_spec.rb"
-- "./ee/spec/features/boards/swimlanes/epics_swimlanes_spec.rb"
-- "./ee/spec/features/boards/user_adds_lists_to_board_spec.rb"
-- "./ee/spec/features/boards/user_visits_board_spec.rb"
-- "./ee/spec/features/burndown_charts_spec.rb"
-- "./ee/spec/features/burnup_charts_spec.rb"
-- "./ee/spec/features/ci/ci_minutes_spec.rb"
-- "./ee/spec/features/ci_shared_runner_warnings_spec.rb"
-- "./ee/spec/features/clusters/create_agent_spec.rb"
-- "./ee/spec/features/dashboards/activity_spec.rb"
-- "./ee/spec/features/dashboards/groups_spec.rb"
-- "./ee/spec/features/dashboards/issues_spec.rb"
-- "./ee/spec/features/dashboards/merge_requests_spec.rb"
-- "./ee/spec/features/dashboards/operations_spec.rb"
-- "./ee/spec/features/dashboards/projects_spec.rb"
-- "./ee/spec/features/dashboards/todos_spec.rb"
-- "./ee/spec/features/discussion_comments/epic_quick_actions_spec.rb"
-- "./ee/spec/features/discussion_comments/epic_spec.rb"
-- "./ee/spec/features/epic_boards/epic_boards_sidebar_spec.rb"
-- "./ee/spec/features/epic_boards/epic_boards_spec.rb"
-- "./ee/spec/features/epic_boards/multiple_epic_boards_spec.rb"
-- "./ee/spec/features/epic_boards/new_epic_spec.rb"
-- "./ee/spec/features/epics/delete_epic_spec.rb"
-- "./ee/spec/features/epics/epic_issues_spec.rb"
-- "./ee/spec/features/epics/epic_labels_spec.rb"
-- "./ee/spec/features/epics/epic_show_spec.rb"
-- "./ee/spec/features/epics/epics_list_spec.rb"
-- "./ee/spec/features/epics/filtered_search/visual_tokens_spec.rb"
-- "./ee/spec/features/epics/gfm_autocomplete_spec.rb"
-- "./ee/spec/features/epics/issue_promotion_spec.rb"
-- "./ee/spec/features/epics/referencing_epics_spec.rb"
-- "./ee/spec/features/epics/shortcuts_epic_spec.rb"
-- "./ee/spec/features/epics/todo_spec.rb"
-- "./ee/spec/features/epics/update_epic_spec.rb"
-- "./ee/spec/features/epics/user_uses_quick_actions_spec.rb"
-- "./ee/spec/features/geo_node_spec.rb"
-- "./ee/spec/features/groups/analytics/ci_cd_analytics_spec.rb"
-- "./ee/spec/features/groups/analytics/cycle_analytics/charts_spec.rb"
-- "./ee/spec/features/groups/analytics/cycle_analytics/filters_and_data_spec.rb"
-- "./ee/spec/features/groups/analytics/cycle_analytics/multiple_value_streams_spec.rb"
-- "./ee/spec/features/groups/audit_events_spec.rb"
-- "./ee/spec/features/groups/billing_spec.rb"
-- "./ee/spec/features/groups/contribution_analytics_spec.rb"
-- "./ee/spec/features/groups/group_overview_spec.rb"
-- "./ee/spec/features/groups/group_roadmap_spec.rb"
-- "./ee/spec/features/groups/group_settings_spec.rb"
-- "./ee/spec/features/groups/groups_security_credentials_spec.rb"
-- "./ee/spec/features/groups/hooks/user_tests_hooks_spec.rb"
-- "./ee/spec/features/groups/insights_spec.rb"
-- "./ee/spec/features/groups/issues_spec.rb"
-- "./ee/spec/features/groups/iterations/iterations_list_spec.rb"
-- "./ee/spec/features/groups/iteration_spec.rb"
-- "./ee/spec/features/groups/iterations/user_creates_iteration_in_cadence_spec.rb"
-- "./ee/spec/features/groups/iterations/user_edits_iteration_cadence_spec.rb"
-- "./ee/spec/features/groups/iterations/user_edits_iteration_spec.rb"
-- "./ee/spec/features/groups/iterations/user_views_iteration_cadence_spec.rb"
-- "./ee/spec/features/groups/iterations/user_views_iteration_spec.rb"
-- "./ee/spec/features/groups/ldap_group_links_spec.rb"
-- "./ee/spec/features/groups/ldap_settings_spec.rb"
-- "./ee/spec/features/groups/members/leave_group_spec.rb"
-- "./ee/spec/features/groups/members/list_members_spec.rb"
-- "./ee/spec/features/groups/members/override_ldap_memberships_spec.rb"
-- "./ee/spec/features/groups/new_spec.rb"
-- "./ee/spec/features/groups/push_rules_spec.rb"
-- "./ee/spec/features/groups/saml_providers_spec.rb"
-- "./ee/spec/features/groups/scim_token_spec.rb"
-- "./ee/spec/features/groups/seat_usage/seat_usage_spec.rb"
-- "./ee/spec/features/groups/security/compliance_dashboards_spec.rb"
-- "./ee/spec/features/groups/settings/user_configures_insights_spec.rb"
-- "./ee/spec/features/groups/settings/user_searches_in_settings_spec.rb"
-- "./ee/spec/features/groups/sso_spec.rb"
-- "./ee/spec/features/groups/wikis_spec.rb"
-- "./ee/spec/features/groups/wiki/user_views_wiki_empty_spec.rb"
-- "./ee/spec/features/ide/user_commits_changes_spec.rb"
-- "./ee/spec/features/ide/user_opens_ide_spec.rb"
-- "./ee/spec/features/integrations/jira/jira_issues_list_spec.rb"
-- "./ee/spec/features/issues/blocking_issues_spec.rb"
-- "./ee/spec/features/issues/epic_in_issue_sidebar_spec.rb"
-- "./ee/spec/features/issues/filtered_search/filter_issues_by_iteration_spec.rb"
-- "./ee/spec/features/issues/filtered_search/filter_issues_epic_spec.rb"
-- "./ee/spec/features/issues/filtered_search/filter_issues_weight_spec.rb"
-- "./ee/spec/features/issues/form_spec.rb"
-- "./ee/spec/features/issues/gfm_autocomplete_ee_spec.rb"
-- "./ee/spec/features/issues/issue_actions_spec.rb"
-- "./ee/spec/features/issues/issue_sidebar_spec.rb"
-- "./ee/spec/features/issues/move_issue_resource_weight_events_spec.rb"
-- "./ee/spec/features/issues/related_issues_spec.rb"
-- "./ee/spec/features/issues/resource_weight_events_spec.rb"
-- "./ee/spec/features/issues/user_bulk_edits_issues_spec.rb"
-- "./ee/spec/features/issues/user_edits_issue_spec.rb"
-- "./ee/spec/features/issues/user_uses_quick_actions_spec.rb"
-- "./ee/spec/features/issues/user_views_issues_spec.rb"
-- "./ee/spec/features/labels_hierarchy_spec.rb"
-- "./ee/spec/features/markdown/metrics_spec.rb"
-- "./ee/spec/features/merge_requests/user_filters_by_approvers_spec.rb"
-- "./ee/spec/features/merge_requests/user_resets_approvers_spec.rb"
-- "./ee/spec/features/merge_requests/user_views_all_merge_requests_spec.rb"
-- "./ee/spec/features/merge_request/user_approves_with_password_spec.rb"
-- "./ee/spec/features/merge_request/user_creates_merge_request_spec.rb"
-- "./ee/spec/features/merge_request/user_creates_merge_request_with_blocking_mrs_spec.rb"
-- "./ee/spec/features/merge_request/user_creates_multiple_assignees_mr_spec.rb"
-- "./ee/spec/features/merge_request/user_creates_multiple_reviewers_mr_spec.rb"
-- "./ee/spec/features/merge_request/user_edits_approval_rules_mr_spec.rb"
-- "./ee/spec/features/merge_request/user_edits_merge_request_blocking_mrs_spec.rb"
-- "./ee/spec/features/merge_request/user_edits_multiple_assignees_mr_spec.rb"
-- "./ee/spec/features/merge_request/user_edits_multiple_reviewers_mr_spec.rb"
-- "./ee/spec/features/merge_request/user_merges_immediately_spec.rb"
-- "./ee/spec/features/merge_request/user_merges_with_push_rules_spec.rb"
-- "./ee/spec/features/merge_request/user_sees_approval_widget_spec.rb"
-- "./ee/spec/features/merge_request/user_sees_closing_issues_message_spec.rb"
-- "./ee/spec/features/merge_request/user_sees_merge_widget_spec.rb"
-- "./ee/spec/features/merge_request/user_sees_status_checks_widget_spec.rb"
-- "./ee/spec/features/merge_request/user_selects_branches_for_new_mr_spec.rb"
-- "./ee/spec/features/merge_request/user_sets_approval_rules_spec.rb"
-- "./ee/spec/features/merge_request/user_sets_approvers_spec.rb"
-- "./ee/spec/features/merge_request/user_uses_slash_commands_spec.rb"
-- "./ee/spec/features/merge_request/user_views_blocked_merge_request_spec.rb"
-- "./ee/spec/features/merge_trains/user_adds_merge_request_to_merge_train_spec.rb"
-- "./ee/spec/features/merge_trains/user_adds_to_merge_train_when_pipeline_succeeds_spec.rb"
-- "./ee/spec/features/oncall_schedules/user_creates_schedule_spec.rb"
-- "./ee/spec/features/operations_nav_link_spec.rb"
-- "./ee/spec/features/profiles/account_spec.rb"
-- "./ee/spec/features/profiles/billing_spec.rb"
-- "./ee/spec/features/projects/audit_events_spec.rb"
-- "./ee/spec/features/projects/cluster_agents_spec.rb"
-- "./ee/spec/features/projects/custom_projects_template_spec.rb"
-- "./ee/spec/features/projects/environments/environments_spec.rb"
-- "./ee/spec/features/projects/feature_flags/feature_flag_issues_spec.rb"
-- "./ee/spec/features/projects/feature_flags/user_creates_feature_flag_spec.rb"
-- "./ee/spec/features/projects/feature_flags/user_deletes_feature_flag_spec.rb"
-- "./ee/spec/features/projects/feature_flags/user_sees_feature_flag_list_spec.rb"
-- "./ee/spec/features/projects/insights_spec.rb"
-- "./ee/spec/features/projects/integrations/user_activates_jira_spec.rb"
-- "./ee/spec/features/projects/issues/user_creates_issue_spec.rb"
-- "./ee/spec/features/projects/iterations/iteration_cadences_list_spec.rb"
-- "./ee/spec/features/projects/iterations/iterations_list_spec.rb"
-- "./ee/spec/features/projects/iterations/user_views_iteration_spec.rb"
-- "./ee/spec/features/projects/jobs_spec.rb"
-- "./ee/spec/features/projects/kerberos_clone_instructions_spec.rb"
-- "./ee/spec/features/projects/licenses/maintainer_views_policies_spec.rb"
-- "./ee/spec/features/projects/members/member_is_removed_from_project_spec.rb"
-- "./ee/spec/features/projects/merge_requests/user_approves_merge_request_spec.rb"
-- "./ee/spec/features/projects/merge_requests/user_edits_merge_request_spec.rb"
-- "./ee/spec/features/projects/mirror_spec.rb"
-- "./ee/spec/features/projects/new_project_from_template_spec.rb"
-- "./ee/spec/features/projects/new_project_spec.rb"
-- "./ee/spec/features/projects/path_locks_spec.rb"
-- "./ee/spec/features/projects/pipelines/pipeline_spec.rb"
-- "./ee/spec/features/projects/push_rules_spec.rb"
-- "./ee/spec/features/projects/quality/test_case_create_spec.rb"
-- "./ee/spec/features/projects/quality/test_case_list_spec.rb"
-- "./ee/spec/features/projects/quality/test_case_show_spec.rb"
-- "./ee/spec/features/projects/releases/user_views_release_spec.rb"
-- "./ee/spec/features/projects/requirements_management/requirements_list_spec.rb"
-- "./ee/spec/features/projects/security/dast_scanner_profiles_spec.rb"
-- "./ee/spec/features/projects/security/dast_site_profiles_spec.rb"
-- "./ee/spec/features/projects/security/user_creates_on_demand_scan_spec.rb"
-- "./ee/spec/features/projects/security/user_views_security_configuration_spec.rb"
-- "./ee/spec/features/projects/services/prometheus_custom_metrics_spec.rb"
-- "./ee/spec/features/projects/services/user_activates_github_spec.rb"
-- "./ee/spec/features/projects/settings/disable_merge_trains_setting_spec.rb"
-- "./ee/spec/features/projects/settings/ee/repository_mirrors_settings_spec.rb"
-- "./ee/spec/features/projects/settings/ee/service_desk_setting_spec.rb"
-- "./ee/spec/features/projects/settings/issues_settings_spec.rb"
-- "./ee/spec/features/projects/settings/merge_request_approvals_settings_spec.rb"
-- "./ee/spec/features/projects/settings/merge_requests_settings_spec.rb"
-- "./ee/spec/features/projects/settings/pipeline_subscriptions_spec.rb"
-- "./ee/spec/features/projects/settings/protected_environments_spec.rb"
-- "./ee/spec/features/projects/settings/user_manages_merge_pipelines_spec.rb"
-- "./ee/spec/features/projects/settings/user_manages_merge_trains_spec.rb"
-- "./ee/spec/features/projects_spec.rb"
-- "./ee/spec/features/projects/user_applies_custom_file_template_spec.rb"
-- "./ee/spec/features/projects/view_blob_with_code_owners_spec.rb"
-- "./ee/spec/features/projects/wiki/user_views_wiki_empty_spec.rb"
-- "./ee/spec/features/promotion_spec.rb"
-- "./ee/spec/features/protected_branches_spec.rb"
-- "./ee/spec/features/protected_tags_spec.rb"
-- "./ee/spec/features/registrations/combined_registration_spec.rb"
-- "./ee/spec/features/registrations/trial_during_signup_flow_spec.rb"
-- "./ee/spec/features/registrations/user_sees_new_onboarding_flow_spec.rb"
-- "./ee/spec/features/registrations/welcome_spec.rb"
-- "./ee/spec/features/search/elastic/global_search_spec.rb"
-- "./ee/spec/features/search/elastic/group_search_spec.rb"
-- "./ee/spec/features/search/elastic/project_search_spec.rb"
-- "./ee/spec/features/search/elastic/snippet_search_spec.rb"
-- "./ee/spec/features/search/user_searches_for_epics_spec.rb"
-- "./ee/spec/features/subscriptions/groups/edit_spec.rb"
-- "./ee/spec/features/trial_registrations/signup_spec.rb"
-- "./ee/spec/features/trials/capture_lead_spec.rb"
-- "./ee/spec/features/trials/select_namespace_spec.rb"
-- "./ee/spec/features/trials/show_trial_banner_spec.rb"
-- "./ee/spec/features/users/login_spec.rb"
-- "./ee/spec/finders/geo/attachment_legacy_registry_finder_spec.rb"
-- "./ee/spec/finders/geo/container_repository_registry_finder_spec.rb"
-- "./ee/spec/finders/geo/lfs_object_registry_finder_spec.rb"
-- "./ee/spec/finders/geo/merge_request_diff_registry_finder_spec.rb"
-- "./ee/spec/finders/geo/package_file_registry_finder_spec.rb"
-- "./ee/spec/finders/geo/pages_deployment_registry_finder_spec.rb"
-- "./ee/spec/finders/geo/pipeline_artifact_registry_finder_spec.rb"
-- "./ee/spec/finders/geo/project_registry_finder_spec.rb"
-- "./ee/spec/finders/merge_requests/by_approvers_finder_spec.rb"
-- "./ee/spec/frontend/fixtures/analytics/value_streams.rb"
-- "./ee/spec/graphql/mutations/dast_on_demand_scans/create_spec.rb"
-- "./ee/spec/graphql/mutations/dast/profiles/create_spec.rb"
-- "./ee/spec/graphql/mutations/dast/profiles/run_spec.rb"
-- "./ee/spec/graphql/mutations/dast/profiles/update_spec.rb"
-- "./ee/spec/graphql/mutations/merge_requests/accept_spec.rb"
-- "./ee/spec/graphql/resolvers/geo/group_wiki_repository_registries_resolver_spec.rb"
-- "./ee/spec/graphql/resolvers/geo/lfs_object_registries_resolver_spec.rb"
-- "./ee/spec/graphql/resolvers/geo/merge_request_diff_registries_resolver_spec.rb"
-- "./ee/spec/graphql/resolvers/geo/package_file_registries_resolver_spec.rb"
-- "./ee/spec/graphql/resolvers/geo/pages_deployment_registries_resolver_spec.rb"
-- "./ee/spec/graphql/resolvers/geo/pipeline_artifact_registries_resolver_spec.rb"
-- "./ee/spec/graphql/resolvers/geo/snippet_repository_registries_resolver_spec.rb"
-- "./ee/spec/graphql/resolvers/geo/terraform_state_version_registries_resolver_spec.rb"
-- "./ee/spec/graphql/resolvers/geo/upload_registries_resolver_spec.rb"
-- "./ee/spec/helpers/application_helper_spec.rb"
-- "./ee/spec/helpers/ee/geo_helper_spec.rb"
-- "./ee/spec/lib/analytics/devops_adoption/snapshot_calculator_spec.rb"
-- "./ee/spec/lib/ee/gitlab/background_migration/backfill_iteration_cadence_id_for_boards_spec.rb"
-- "./ee/spec/lib/ee/gitlab/background_migration/backfill_version_data_from_gitaly_spec.rb"
-- "./ee/spec/lib/ee/gitlab/background_migration/create_security_setting_spec.rb"
-- "./ee/spec/lib/ee/gitlab/background_migration/fix_ruby_object_in_audit_events_spec.rb"
-- "./ee/spec/lib/ee/gitlab/background_migration/migrate_approver_to_approval_rules_check_progress_spec.rb"
-- "./ee/spec/lib/ee/gitlab/background_migration/migrate_approver_to_approval_rules_in_batch_spec.rb"
-- "./ee/spec/lib/ee/gitlab/background_migration/migrate_approver_to_approval_rules_spec.rb"
-- "./ee/spec/lib/ee/gitlab/background_migration/migrate_devops_segments_to_groups_spec.rb"
-- "./ee/spec/lib/ee/gitlab/background_migration/migrate_security_scans_spec.rb"
-- "./ee/spec/lib/ee/gitlab/background_migration/move_epic_issues_after_epics_spec.rb"
-- "./ee/spec/lib/ee/gitlab/background_migration/populate_any_approval_rule_for_merge_requests_spec.rb"
-- "./ee/spec/lib/ee/gitlab/background_migration/populate_any_approval_rule_for_projects_spec.rb"
-- "./ee/spec/lib/ee/gitlab/background_migration/populate_latest_pipeline_ids_spec.rb"
-- "./ee/spec/lib/ee/gitlab/background_migration/populate_namespace_statistics_spec.rb"
-- "./ee/spec/lib/ee/gitlab/background_migration/populate_resolved_on_default_branch_column_spec.rb"
-- "./ee/spec/lib/ee/gitlab/background_migration/populate_uuids_for_security_findings_spec.rb"
-- "./ee/spec/lib/ee/gitlab/background_migration/populate_vulnerability_feedback_pipeline_id_spec.rb"
-- "./ee/spec/lib/ee/gitlab/background_migration/populate_vulnerability_historical_statistics_spec.rb"
-- "./ee/spec/lib/ee/gitlab/background_migration/prune_orphaned_geo_events_spec.rb"
-- "./ee/spec/lib/ee/gitlab/background_migration/remove_duplicate_cs_findings_spec.rb"
-- "./ee/spec/lib/ee/gitlab/background_migration/remove_duplicated_cs_findings_without_vulnerability_id_spec.rb"
-- "./ee/spec/lib/ee/gitlab/background_migration/remove_inaccessible_epic_todos_spec.rb"
-- "./ee/spec/lib/ee/gitlab/background_migration/remove_undefined_occurrence_confidence_level_spec.rb"
-- "./ee/spec/lib/ee/gitlab/background_migration/remove_undefined_occurrence_severity_level_spec.rb"
-- "./ee/spec/lib/ee/gitlab/background_migration/remove_undefined_vulnerability_confidence_level_spec.rb"
-- "./ee/spec/lib/ee/gitlab/background_migration/remove_undefined_vulnerability_severity_level_spec.rb"
-- "./ee/spec/lib/ee/gitlab/background_migration/update_location_fingerprint_for_container_scanning_findings_spec.rb"
-- "./ee/spec/lib/ee/gitlab/background_migration/update_vulnerabilities_from_dismissal_feedback_spec.rb"
-- "./ee/spec/lib/ee/gitlab/background_migration/update_vulnerabilities_to_dismissed_spec.rb"
-- "./ee/spec/lib/ee/gitlab/background_migration/update_vulnerability_confidence_spec.rb"
-- "./ee/spec/lib/ee/gitlab/database/connection_spec.rb"
-- "./ee/spec/lib/ee/gitlab/database_spec.rb"
-- "./ee/spec/lib/ee/gitlab/middleware/read_only_spec.rb"
-- "./ee/spec/lib/ee/gitlab/usage_data_spec.rb"
-- "./ee/spec/lib/gitlab/background_migration/fix_orphan_promoted_issues_spec.rb"
-- "./ee/spec/lib/gitlab/background_migration/user_mentions/create_resource_user_mention_spec.rb"
- "./ee/spec/lib/gitlab/ci/templates/Jobs/dast_default_branch_gitlab_ci_yaml_spec.rb"
-- "./ee/spec/lib/gitlab/geo/base_request_spec.rb"
-- "./ee/spec/lib/gitlab/geo/database_tasks_spec.rb"
-- "./ee/spec/lib/gitlab/geo/event_gap_tracking_spec.rb"
-- "./ee/spec/lib/gitlab/geo/geo_tasks_spec.rb"
-- "./ee/spec/lib/gitlab/geo/jwt_request_decoder_spec.rb"
-- "./ee/spec/lib/gitlab/geo/log_cursor/events/design_repository_updated_event_spec.rb"
-- "./ee/spec/lib/gitlab/geo/log_cursor/events/job_artifact_deleted_event_spec.rb"
-- "./ee/spec/lib/gitlab/geo/log_cursor/events/repository_created_event_spec.rb"
-- "./ee/spec/lib/gitlab/geo/log_cursor/events/repository_updated_event_spec.rb"
-- "./ee/spec/lib/gitlab/geo/oauth/login_state_spec.rb"
-- "./ee/spec/lib/gitlab/geo/oauth/logout_token_spec.rb"
-- "./ee/spec/lib/gitlab/geo/oauth/session_spec.rb"
-- "./ee/spec/lib/gitlab/geo/registry_batcher_spec.rb"
-- "./ee/spec/lib/gitlab/geo/replicable_model_spec.rb"
-- "./ee/spec/lib/gitlab/geo/replication/blob_downloader_spec.rb"
-- "./ee/spec/lib/gitlab/geo/replication/file_transfer_spec.rb"
-- "./ee/spec/lib/gitlab/geo/replicator_spec.rb"
-- "./ee/spec/lib/gitlab/git_access_spec.rb"
-- "./ee/spec/lib/pseudonymizer/dumper_spec.rb"
-- "./ee/spec/lib/system_check/geo/geo_database_configured_check_spec.rb"
-- "./ee/spec/lib/system_check/geo/http_connection_check_spec.rb"
-- "./ee/spec/lib/system_check/rake_task/geo_task_spec.rb"
- "./ee/spec/mailers/notify_spec.rb"
-- "./ee/spec/migrations/20190926180443_schedule_epic_issues_after_epics_move_spec.rb"
-- "./ee/spec/migrations/add_non_null_constraint_for_escalation_rule_on_pending_alert_escalations_spec.rb"
-- "./ee/spec/migrations/add_unique_constraint_to_software_licenses_spec.rb"
-- "./ee/spec/migrations/backfill_namespace_statistics_with_wiki_size_spec.rb"
-- "./ee/spec/migrations/backfill_operations_feature_flags_iid_spec.rb"
-- "./ee/spec/migrations/backfill_software_licenses_spdx_identifiers_spec.rb"
-- "./ee/spec/migrations/backfill_version_author_and_created_at_spec.rb"
-- "./ee/spec/migrations/cleanup_deploy_access_levels_for_removed_groups_spec.rb"
-- "./ee/spec/migrations/create_elastic_reindexing_subtasks_spec.rb"
-- "./ee/spec/migrations/fix_any_approver_rule_for_projects_spec.rb"
-- "./ee/spec/migrations/migrate_design_notes_mentions_to_db_spec.rb"
-- "./ee/spec/migrations/migrate_epic_mentions_to_db_spec.rb"
-- "./ee/spec/migrations/migrate_epic_notes_mentions_to_db_spec.rb"
-- "./ee/spec/migrations/migrate_license_management_artifacts_to_license_scanning_spec.rb"
-- "./ee/spec/migrations/migrate_saml_identities_to_scim_identities_spec.rb"
-- "./ee/spec/migrations/migrate_scim_identities_to_saml_for_new_users_spec.rb"
-- "./ee/spec/migrations/migrate_vulnerability_dismissal_feedback_spec.rb"
-- "./ee/spec/migrations/migrate_vulnerability_dismissals_spec.rb"
-- "./ee/spec/migrations/nullify_feature_flag_plaintext_tokens_spec.rb"
-- "./ee/spec/migrations/populate_vulnerability_historical_statistics_for_year_spec.rb"
-- "./ee/spec/migrations/remove_creations_in_gitlab_subscription_histories_spec.rb"
-- "./ee/spec/migrations/remove_cycle_analytics_total_stage_data_spec.rb"
-- "./ee/spec/migrations/remove_duplicated_cs_findings_spec.rb"
-- "./ee/spec/migrations/remove_duplicated_cs_findings_without_vulnerability_id_spec.rb"
-- "./ee/spec/migrations/remove_schedule_and_status_null_constraints_from_pending_escalations_alert_spec.rb"
-- "./ee/spec/migrations/schedule_fix_orphan_promoted_issues_spec.rb"
-- "./ee/spec/migrations/schedule_fix_ruby_object_in_audit_events_spec.rb"
-- "./ee/spec/migrations/schedule_merge_request_any_approval_rule_migration_spec.rb"
-- "./ee/spec/migrations/schedule_populate_dismissed_state_for_vulnerabilities_spec.rb"
-- "./ee/spec/migrations/schedule_populate_resolved_on_default_branch_column_spec.rb"
-- "./ee/spec/migrations/schedule_populate_vulnerability_historical_statistics_spec.rb"
-- "./ee/spec/migrations/schedule_project_any_approval_rule_migration_spec.rb"
-- "./ee/spec/migrations/schedule_remove_inaccessible_epic_todos_spec.rb"
-- "./ee/spec/migrations/schedule_sync_blocking_issues_count_spec.rb"
-- "./ee/spec/migrations/schedule_uuid_population_for_security_findings2_spec.rb"
-- "./ee/spec/migrations/set_report_type_for_vulnerabilities_spec.rb"
-- "./ee/spec/migrations/set_resolved_state_on_vulnerabilities_spec.rb"
-- "./ee/spec/migrations/update_cs_vulnerability_confidence_column_spec.rb"
-- "./ee/spec/migrations/update_gitlab_subscriptions_start_at_post_eoa_spec.rb"
-- "./ee/spec/migrations/update_location_fingerprint_column_for_cs_spec.rb"
-- "./ee/spec/migrations/update_occurrence_severity_column_spec.rb"
-- "./ee/spec/migrations/update_undefined_confidence_from_occurrences_spec.rb"
-- "./ee/spec/migrations/update_undefined_confidence_from_vulnerabilities_spec.rb"
-- "./ee/spec/migrations/update_vulnerability_severity_column_spec.rb"
-- "./ee/spec/models/analytics/cycle_analytics/group_level_spec.rb"
-- "./ee/spec/models/approval_merge_request_rule_spec.rb"
-- "./ee/spec/models/approval_project_rule_spec.rb"
-- "./ee/spec/models/approval_state_spec.rb"
-- "./ee/spec/models/approval_wrapped_code_owner_rule_spec.rb"
-- "./ee/spec/models/approval_wrapped_rule_spec.rb"
-- "./ee/spec/models/approver_group_spec.rb"
- "./ee/spec/models/ci/bridge_spec.rb"
- "./ee/spec/models/ci/build_spec.rb"
- "./ee/spec/models/ci/minutes/additional_pack_spec.rb"
-- "./ee/spec/models/ci/pipeline_spec.rb"
-- "./ee/spec/models/ci/subscriptions/project_spec.rb"
-- "./ee/spec/models/concerns/approval_rule_like_spec.rb"
-- "./ee/spec/models/concerns/approver_migrate_hook_spec.rb"
-- "./ee/spec/models/dora/daily_metrics_spec.rb"
- "./ee/spec/models/ee/ci/job_artifact_spec.rb"
-- "./ee/spec/models/ee/ci/pipeline_artifact_spec.rb"
-- "./ee/spec/models/ee/ci/runner_spec.rb"
-- "./ee/spec/models/ee/merge_request_diff_spec.rb"
-- "./ee/spec/models/ee/pages_deployment_spec.rb"
-- "./ee/spec/models/ee/terraform/state_version_spec.rb"
-- "./ee/spec/models/geo/container_repository_registry_spec.rb"
-- "./ee/spec/models/geo/deleted_project_spec.rb"
-- "./ee/spec/models/geo/design_registry_spec.rb"
-- "./ee/spec/models/geo/job_artifact_registry_spec.rb"
-- "./ee/spec/models/geo_node_namespace_link_spec.rb"
-- "./ee/spec/models/geo_node_spec.rb"
-- "./ee/spec/models/geo_node_status_spec.rb"
-- "./ee/spec/models/geo/package_file_registry_spec.rb"
-- "./ee/spec/models/geo/project_registry_spec.rb"
- "./ee/spec/models/group_member_spec.rb"
-- "./ee/spec/models/group_wiki_repository_spec.rb"
-- "./ee/spec/models/merge_request_spec.rb"
-- "./ee/spec/models/packages/package_file_spec.rb"
-- "./ee/spec/models/project_spec.rb"
-- "./ee/spec/models/requirements_management/requirement_spec.rb"
-- "./ee/spec/models/snippet_repository_spec.rb"
-- "./ee/spec/models/upload_spec.rb"
-- "./ee/spec/models/visible_approvable_spec.rb"
-- "./ee/spec/policies/ci/build_policy_spec.rb"
-- "./ee/spec/presenters/approval_rule_presenter_spec.rb"
-- "./ee/spec/presenters/merge_request_presenter_spec.rb"
- "./ee/spec/replicators/geo/pipeline_artifact_replicator_spec.rb"
- "./ee/spec/replicators/geo/terraform_state_version_replicator_spec.rb"
-- "./ee/spec/requests/api/ci/pipelines_spec.rb"
-- "./ee/spec/requests/api/geo_nodes_spec.rb"
-- "./ee/spec/requests/api/geo_replication_spec.rb"
-- "./ee/spec/requests/api/graphql/mutations/dast_on_demand_scans/create_spec.rb"
-- "./ee/spec/requests/api/graphql/mutations/dast/profiles/create_spec.rb"
-- "./ee/spec/requests/api/graphql/mutations/dast/profiles/run_spec.rb"
-- "./ee/spec/requests/api/graphql/mutations/dast/profiles/update_spec.rb"
-- "./ee/spec/requests/api/graphql/project/pipeline/dast_profile_spec.rb"
-- "./ee/spec/requests/api/merge_request_approval_rules_spec.rb"
-- "./ee/spec/requests/api/merge_requests_spec.rb"
-- "./ee/spec/requests/api/project_approval_rules_spec.rb"
-- "./ee/spec/requests/api/project_approval_settings_spec.rb"
-- "./ee/spec/requests/api/project_approvals_spec.rb"
-- "./ee/spec/requests/api/project_snapshots_spec.rb"
-- "./ee/spec/requests/api/status_checks_spec.rb"
-- "./ee/spec/requests/api/vulnerability_findings_spec.rb"
-- "./ee/spec/requests/projects/merge_requests_controller_spec.rb"
-- "./ee/spec/routing/admin_routing_spec.rb"
-- "./ee/spec/serializers/dashboard_operations_project_entity_spec.rb"
-- "./ee/spec/serializers/ee/evidences/release_entity_spec.rb"
-- "./ee/spec/serializers/ee/user_serializer_spec.rb"
-- "./ee/spec/serializers/evidences/evidence_entity_spec.rb"
-- "./ee/spec/serializers/merge_request_widget_entity_spec.rb"
-- "./ee/spec/serializers/pipeline_serializer_spec.rb"
-- "./ee/spec/services/approval_rules/create_service_spec.rb"
-- "./ee/spec/services/approval_rules/finalize_service_spec.rb"
-- "./ee/spec/services/approval_rules/merge_request_rule_destroy_service_spec.rb"
-- "./ee/spec/services/approval_rules/params_filtering_service_spec.rb"
-- "./ee/spec/services/approval_rules/project_rule_destroy_service_spec.rb"
-- "./ee/spec/services/approval_rules/update_service_spec.rb"
-- "./ee/spec/services/app_sec/dast/profiles/create_service_spec.rb"
-- "./ee/spec/services/app_sec/dast/profiles/update_service_spec.rb"
-- "./ee/spec/services/app_sec/dast/scans/create_service_spec.rb"
-- "./ee/spec/services/app_sec/dast/scans/run_service_spec.rb"
-- "./ee/spec/services/ci/compare_license_scanning_reports_service_spec.rb"
-- "./ee/spec/services/ci/compare_metrics_reports_service_spec.rb"
-- "./ee/spec/services/ci/create_pipeline_service/dast_configuration_spec.rb"
- "./ee/spec/services/ci/destroy_pipeline_service_spec.rb"
-- "./ee/spec/services/ci/minutes/track_live_consumption_service_spec.rb"
-- "./ee/spec/services/ci/minutes/update_build_minutes_service_spec.rb"
-- "./ee/spec/services/ci/register_job_service_spec.rb"
- "./ee/spec/services/ci/retry_build_service_spec.rb"
-- "./ee/spec/services/ci/run_dast_scan_service_spec.rb"
- "./ee/spec/services/ci/subscribe_bridge_service_spec.rb"
-- "./ee/spec/services/ci/sync_reports_to_approval_rules_service_spec.rb"
-- "./ee/spec/services/ci/trigger_downstream_subscription_service_spec.rb"
-- "./ee/spec/services/dast_on_demand_scans/create_service_spec.rb"
- "./ee/spec/services/deployments/auto_rollback_service_spec.rb"
- "./ee/spec/services/ee/ci/job_artifacts/destroy_all_expired_service_spec.rb"
-- "./ee/spec/services/ee/ci/job_artifacts/destroy_batch_service_spec.rb"
-- "./ee/spec/services/ee/integrations/test/project_service_spec.rb"
-- "./ee/spec/services/ee/issuable/destroy_service_spec.rb"
-- "./ee/spec/services/ee/merge_requests/refresh_service_spec.rb"
-- "./ee/spec/services/ee/merge_requests/update_service_spec.rb"
-- "./ee/spec/services/ee/notification_service_spec.rb"
-- "./ee/spec/services/ee/post_receive_service_spec.rb"
-- "./ee/spec/services/ee/releases/create_evidence_service_spec.rb"
- "./ee/spec/services/ee/users/destroy_service_spec.rb"
-- "./ee/spec/services/external_status_checks/create_service_spec.rb"
-- "./ee/spec/services/external_status_checks/destroy_service_spec.rb"
-- "./ee/spec/services/external_status_checks/update_service_spec.rb"
-- "./ee/spec/services/geo/container_repository_sync_service_spec.rb"
-- "./ee/spec/services/geo/hashed_storage_migrated_event_store_spec.rb"
-- "./ee/spec/services/geo/hashed_storage_migration_service_spec.rb"
-- "./ee/spec/services/geo/node_create_service_spec.rb"
-- "./ee/spec/services/geo/node_status_request_service_spec.rb"
-- "./ee/spec/services/geo/node_update_service_spec.rb"
-- "./ee/spec/services/geo/project_housekeeping_service_spec.rb"
-- "./ee/spec/services/geo/registry_consistency_service_spec.rb"
-- "./ee/spec/services/geo/repositories_changed_event_store_spec.rb"
-- "./ee/spec/services/geo/repository_updated_event_store_spec.rb"
-- "./ee/spec/services/geo/repository_verification_reset_spec.rb"
-- "./ee/spec/services/geo/repository_verification_secondary_service_spec.rb"
-- "./ee/spec/services/merge_requests/merge_service_spec.rb"
-- "./ee/spec/services/merge_requests/reset_approvals_service_spec.rb"
-- "./ee/spec/services/merge_requests/sync_report_approver_approval_rules_spec.rb"
- "./ee/spec/services/projects/transfer_service_spec.rb"
- "./ee/spec/services/security/security_orchestration_policies/rule_schedule_service_spec.rb"
-- "./ee/spec/services/todo_service_spec.rb"
-- "./ee/spec/services/vulnerability_feedback/create_service_spec.rb"
-- "./ee/spec/services/wiki_pages/create_service_spec.rb"
-- "./ee/spec/services/wiki_pages/destroy_service_spec.rb"
-- "./ee/spec/services/wiki_pages/update_service_spec.rb"
-- "./ee/spec/support/shared_examples/fixtures/analytics_value_streams_shared_examples.rb"
-- "./ee/spec/support/shared_examples/graphql/geo/geo_registries_resolver_shared_examples.rb"
-- "./ee/spec/support/shared_examples/graphql/mutations/dast_on_demand_scans_shared_examples.rb"
-- "./ee/spec/support/shared_examples/graphql/mutations/dast_on_demand_scan_with_user_abilities_shared_examples.rb"
-- "./ee/spec/support/shared_examples/lib/gitlab/geo/geo_log_cursor_event_shared_examples.rb"
-- "./ee/spec/support/shared_examples/lib/gitlab/geo/geo_logs_event_source_info_shared_examples.rb"
-- "./ee/spec/support/shared_examples/models/concerns/blob_replicator_strategy_shared_examples.rb"
-- "./ee/spec/support/shared_examples/models/concerns/replicable_model_shared_examples.rb"
-- "./ee/spec/support/shared_examples/models/concerns/verifiable_replicator_shared_examples.rb"
-- "./ee/spec/support/shared_examples/policies/protected_environments_shared_examples.rb"
-- "./ee/spec/support/shared_examples/requests/api/project_approval_rules_api_shared_examples.rb"
-- "./ee/spec/support/shared_examples/services/audit_event_logging_shared_examples.rb"
-- "./ee/spec/support/shared_examples/services/build_execute_shared_examples.rb"
-- "./ee/spec/support/shared_examples/services/dast_on_demand_scans_shared_examples.rb"
-- "./ee/spec/support/shared_examples/services/geo_event_store_shared_examples.rb"
-- "./ee/spec/tasks/geo_rake_spec.rb"
-- "./ee/spec/tasks/gitlab/geo_rake_spec.rb"
-- "./ee/spec/workers/geo/file_download_dispatch_worker_spec.rb"
-- "./ee/spec/workers/geo/metrics_update_worker_spec.rb"
-- "./ee/spec/workers/geo/prune_event_log_worker_spec.rb"
-- "./ee/spec/workers/geo/registry_sync_worker_spec.rb"
-- "./ee/spec/workers/geo/repository_cleanup_worker_spec.rb"
-- "./ee/spec/workers/geo/repository_sync_worker_spec.rb"
-- "./ee/spec/workers/geo/repository_verification/secondary/scheduler_worker_spec.rb"
-- "./ee/spec/workers/geo/repository_verification/secondary/single_worker_spec.rb"
-- "./ee/spec/workers/geo/verification_worker_spec.rb"
-- "./ee/spec/workers/refresh_license_compliance_checks_worker_spec.rb"
- "./spec/controllers/abuse_reports_controller_spec.rb"
- "./spec/controllers/admin/spam_logs_controller_spec.rb"
- "./spec/controllers/admin/users_controller_spec.rb"
- "./spec/controllers/omniauth_callbacks_controller_spec.rb"
- "./spec/controllers/projects/issues_controller_spec.rb"
-- "./spec/controllers/projects/jobs_controller_spec.rb"
-- "./spec/controllers/projects/merge_requests/content_controller_spec.rb"
-- "./spec/controllers/projects/merge_requests_controller_spec.rb"
- "./spec/controllers/projects/pipelines_controller_spec.rb"
-- "./spec/controllers/projects/pipelines/tests_controller_spec.rb"
- "./spec/controllers/projects/settings/access_tokens_controller_spec.rb"
-- "./spec/controllers/projects/tags_controller_spec.rb"
-- "./spec/controllers/sent_notifications_controller_spec.rb"
-- "./spec/factories_spec.rb"
-- "./spec/features/action_cable_logging_spec.rb"
-- "./spec/features/admin/admin_abuse_reports_spec.rb"
-- "./spec/features/admin/admin_appearance_spec.rb"
-- "./spec/features/admin/admin_broadcast_messages_spec.rb"
-- "./spec/features/admin/admin_builds_spec.rb"
-- "./spec/features/admin/admin_dev_ops_report_spec.rb"
-- "./spec/features/admin/admin_disables_git_access_protocol_spec.rb"
-- "./spec/features/admin/admin_disables_two_factor_spec.rb"
-- "./spec/features/admin/admin_groups_spec.rb"
-- "./spec/features/admin/admin_hooks_spec.rb"
-- "./spec/features/admin/admin_labels_spec.rb"
-- "./spec/features/admin/admin_mode/login_spec.rb"
-- "./spec/features/admin/admin_mode/logout_spec.rb"
-- "./spec/features/admin/admin_mode_spec.rb"
-- "./spec/features/admin/admin_mode/workers_spec.rb"
-- "./spec/features/admin/admin_projects_spec.rb"
-- "./spec/features/admin/admin_runners_spec.rb"
-- "./spec/features/admin/admin_search_settings_spec.rb"
-- "./spec/features/admin/admin_serverless_domains_spec.rb"
-- "./spec/features/admin/admin_settings_spec.rb"
-- "./spec/features/admin/admin_users_impersonation_tokens_spec.rb"
-- "./spec/features/admin/admin_uses_repository_checks_spec.rb"
-- "./spec/features/admin/clusters/eks_spec.rb"
-- "./spec/features/admin/dashboard_spec.rb"
-- "./spec/features/admin/integrations/user_activates_mattermost_slash_command_spec.rb"
-- "./spec/features/admin/users/user_spec.rb"
-- "./spec/features/admin/users/users_spec.rb"
-- "./spec/features/alert_management/alert_details_spec.rb"
-- "./spec/features/alert_management/alert_management_list_spec.rb"
-- "./spec/features/alert_management_spec.rb"
-- "./spec/features/alert_management/user_filters_alerts_by_status_spec.rb"
-- "./spec/features/alert_management/user_searches_alerts_spec.rb"
-- "./spec/features/alert_management/user_updates_alert_status_spec.rb"
-- "./spec/features/alerts_settings/user_views_alerts_settings_spec.rb"
-- "./spec/features/atom/dashboard_spec.rb"
-- "./spec/features/boards/boards_spec.rb"
-- "./spec/features/boards/focus_mode_spec.rb"
-- "./spec/features/boards/issue_ordering_spec.rb"
-- "./spec/features/boards/keyboard_shortcut_spec.rb"
-- "./spec/features/boards/multiple_boards_spec.rb"
-- "./spec/features/boards/new_issue_spec.rb"
-- "./spec/features/boards/reload_boards_on_browser_back_spec.rb"
-- "./spec/features/boards/sidebar_due_date_spec.rb"
-- "./spec/features/boards/sidebar_labels_in_namespaces_spec.rb"
-- "./spec/features/boards/sidebar_labels_spec.rb"
-- "./spec/features/boards/sidebar_milestones_spec.rb"
-- "./spec/features/boards/sidebar_spec.rb"
-- "./spec/features/boards/user_adds_lists_to_board_spec.rb"
-- "./spec/features/boards/user_visits_board_spec.rb"
-- "./spec/features/broadcast_messages_spec.rb"
-- "./spec/features/calendar_spec.rb"
-- "./spec/features/callouts/registration_enabled_spec.rb"
-- "./spec/features/clusters/cluster_detail_page_spec.rb"
-- "./spec/features/clusters/cluster_health_dashboard_spec.rb"
-- "./spec/features/commit_spec.rb"
-- "./spec/features/commits_spec.rb"
-- "./spec/features/commits/user_uses_quick_actions_spec.rb"
-- "./spec/features/contextual_sidebar_spec.rb"
-- "./spec/features/cycle_analytics_spec.rb"
-- "./spec/features/dashboard/activity_spec.rb"
-- "./spec/features/dashboard/archived_projects_spec.rb"
-- "./spec/features/dashboard/datetime_on_tooltips_spec.rb"
-- "./spec/features/dashboard/group_dashboard_with_external_authorization_service_spec.rb"
-- "./spec/features/dashboard/groups_list_spec.rb"
-- "./spec/features/dashboard/group_spec.rb"
-- "./spec/features/dashboard/issues_filter_spec.rb"
-- "./spec/features/dashboard/issues_spec.rb"
-- "./spec/features/dashboard/label_filter_spec.rb"
-- "./spec/features/dashboard/merge_requests_spec.rb"
-- "./spec/features/dashboard/milestones_spec.rb"
-- "./spec/features/dashboard/project_member_activity_index_spec.rb"
-- "./spec/features/dashboard/projects_spec.rb"
-- "./spec/features/dashboard/root_spec.rb"
-- "./spec/features/dashboard/shortcuts_spec.rb"
-- "./spec/features/dashboard/snippets_spec.rb"
-- "./spec/features/dashboard/todos/todos_filtering_spec.rb"
-- "./spec/features/dashboard/todos/todos_spec.rb"
-- "./spec/features/dashboard/user_filters_projects_spec.rb"
-- "./spec/features/discussion_comments/commit_spec.rb"
-- "./spec/features/discussion_comments/issue_spec.rb"
-- "./spec/features/discussion_comments/merge_request_spec.rb"
-- "./spec/features/discussion_comments/snippets_spec.rb"
-- "./spec/features/error_pages_spec.rb"
-- "./spec/features/error_tracking/user_filters_errors_by_status_spec.rb"
-- "./spec/features/error_tracking/user_searches_sentry_errors_spec.rb"
-- "./spec/features/error_tracking/user_sees_error_details_spec.rb"
-- "./spec/features/error_tracking/user_sees_error_index_spec.rb"
-- "./spec/features/expand_collapse_diffs_spec.rb"
-- "./spec/features/explore/groups_list_spec.rb"
-- "./spec/features/explore/groups_spec.rb"
-- "./spec/features/explore/user_explores_projects_spec.rb"
-- "./spec/features/file_uploads/attachment_spec.rb"
-- "./spec/features/file_uploads/ci_artifact_spec.rb"
-- "./spec/features/file_uploads/git_lfs_spec.rb"
-- "./spec/features/file_uploads/graphql_add_design_spec.rb"
-- "./spec/features/file_uploads/group_import_spec.rb"
-- "./spec/features/file_uploads/maven_package_spec.rb"
-- "./spec/features/file_uploads/multipart_invalid_uploads_spec.rb"
-- "./spec/features/file_uploads/nuget_package_spec.rb"
-- "./spec/features/file_uploads/project_import_spec.rb"
-- "./spec/features/file_uploads/rubygem_package_spec.rb"
-- "./spec/features/file_uploads/user_avatar_spec.rb"
-- "./spec/features/frequently_visited_projects_and_groups_spec.rb"
-- "./spec/features/gitlab_experiments_spec.rb"
-- "./spec/features/global_search_spec.rb"
-- "./spec/features/groups/activity_spec.rb"
-- "./spec/features/groups/board_sidebar_spec.rb"
-- "./spec/features/groups/board_spec.rb"
-- "./spec/features/groups/clusters/eks_spec.rb"
-- "./spec/features/groups/clusters/user_spec.rb"
-- "./spec/features/groups/container_registry_spec.rb"
-- "./spec/features/groups/dependency_proxy_spec.rb"
-- "./spec/features/groups/empty_states_spec.rb"
-- "./spec/features/groups/import_export/connect_instance_spec.rb"
-- "./spec/features/groups/import_export/export_file_spec.rb"
-- "./spec/features/groups/import_export/import_file_spec.rb"
-- "./spec/features/groups/integrations/user_activates_mattermost_slash_command_spec.rb"
-- "./spec/features/groups/issues_spec.rb"
-- "./spec/features/groups/labels/index_spec.rb"
-- "./spec/features/groups/labels/search_labels_spec.rb"
-- "./spec/features/groups/labels/sort_labels_spec.rb"
-- "./spec/features/groups/labels/subscription_spec.rb"
-- "./spec/features/groups/members/filter_members_spec.rb"
-- "./spec/features/groups/members/leave_group_spec.rb"
-- "./spec/features/groups/members/list_members_spec.rb"
-- "./spec/features/groups/members/manage_groups_spec.rb"
-- "./spec/features/groups/members/manage_members_spec.rb"
-- "./spec/features/groups/members/master_adds_member_with_expiration_date_spec.rb"
-- "./spec/features/groups/members/master_manages_access_requests_spec.rb"
-- "./spec/features/groups/members/search_members_spec.rb"
-- "./spec/features/groups/members/sort_members_spec.rb"
-- "./spec/features/groups/members/tabs_spec.rb"
-- "./spec/features/groups/merge_requests_spec.rb"
-- "./spec/features/groups/milestones/gfm_autocomplete_spec.rb"
-- "./spec/features/groups/milestone_spec.rb"
-- "./spec/features/groups/milestones_sorting_spec.rb"
-- "./spec/features/groups/packages_spec.rb"
-- "./spec/features/groups/settings/group_badges_spec.rb"
-- "./spec/features/groups/settings/packages_and_registries_spec.rb"
-- "./spec/features/groups/settings/repository_spec.rb"
-- "./spec/features/groups/settings/user_searches_in_settings_spec.rb"
-- "./spec/features/groups/show_spec.rb"
-- "./spec/features/groups_spec.rb"
-- "./spec/features/groups/user_browse_projects_group_page_spec.rb"
-- "./spec/features/groups/user_sees_users_dropdowns_in_issuables_list_spec.rb"
-- "./spec/features/help_pages_spec.rb"
-- "./spec/features/ide_spec.rb"
-- "./spec/features/ide/user_commits_changes_spec.rb"
-- "./spec/features/ide/user_opens_merge_request_spec.rb"
-- "./spec/features/import/manifest_import_spec.rb"
-- "./spec/features/incidents/incident_details_spec.rb"
-- "./spec/features/incidents/incidents_list_spec.rb"
-- "./spec/features/incidents/user_creates_new_incident_spec.rb"
-- "./spec/features/incidents/user_filters_incidents_by_status_spec.rb"
-- "./spec/features/incidents/user_searches_incidents_spec.rb"
-- "./spec/features/incidents/user_views_incident_spec.rb"
-- "./spec/features/issuables/issuable_list_spec.rb"
-- "./spec/features/issuables/markdown_references/internal_references_spec.rb"
-- "./spec/features/issuables/markdown_references/jira_spec.rb"
-- "./spec/features/issuables/sorting_list_spec.rb"
-- "./spec/features/issuables/user_sees_sidebar_spec.rb"
-- "./spec/features/issues/create_issue_for_discussions_in_merge_request_spec.rb"
-- "./spec/features/issues/create_issue_for_single_discussion_in_merge_request_spec.rb"
-- "./spec/features/issues/csv_spec.rb"
-- "./spec/features/issues/discussion_lock_spec.rb"
-- "./spec/features/issues/filtered_search/dropdown_assignee_spec.rb"
-- "./spec/features/issues/filtered_search/dropdown_author_spec.rb"
-- "./spec/features/issues/filtered_search/dropdown_base_spec.rb"
-- "./spec/features/issues/filtered_search/dropdown_emoji_spec.rb"
-- "./spec/features/issues/filtered_search/dropdown_hint_spec.rb"
-- "./spec/features/issues/filtered_search/dropdown_label_spec.rb"
-- "./spec/features/issues/filtered_search/dropdown_milestone_spec.rb"
-- "./spec/features/issues/filtered_search/dropdown_release_spec.rb"
-- "./spec/features/issues/filtered_search/filter_issues_spec.rb"
-- "./spec/features/issues/filtered_search/recent_searches_spec.rb"
-- "./spec/features/issues/filtered_search/search_bar_spec.rb"
-- "./spec/features/issues/filtered_search/visual_tokens_spec.rb"
-- "./spec/features/issues/form_spec.rb"
-- "./spec/features/issues/gfm_autocomplete_spec.rb"
-- "./spec/features/issues/group_label_sidebar_spec.rb"
-- "./spec/features/issues/incident_issue_spec.rb"
- "./spec/features/issues/issue_detail_spec.rb"
-- "./spec/features/issues/issue_header_spec.rb"
-- "./spec/features/issues/issue_sidebar_spec.rb"
-- "./spec/features/issues/keyboard_shortcut_spec.rb"
-- "./spec/features/issues/markdown_toolbar_spec.rb"
-- "./spec/features/issues/move_spec.rb"
-- "./spec/features/issues/note_polling_spec.rb"
-- "./spec/features/issues/notes_on_issues_spec.rb"
-- "./spec/features/issues/related_issues_spec.rb"
-- "./spec/features/issues/resource_label_events_spec.rb"
-- "./spec/features/issues/service_desk_spec.rb"
-- "./spec/features/issues/spam_issues_spec.rb"
-- "./spec/features/issues/todo_spec.rb"
-- "./spec/features/issues/user_bulk_edits_issues_labels_spec.rb"
-- "./spec/features/issues/user_bulk_edits_issues_spec.rb"
-- "./spec/features/issues/user_comments_on_issue_spec.rb"
-- "./spec/features/issues/user_creates_branch_and_merge_request_spec.rb"
-- "./spec/features/issues/user_creates_confidential_merge_request_spec.rb"
-- "./spec/features/issues/user_creates_issue_by_email_spec.rb"
-- "./spec/features/issues/user_creates_issue_spec.rb"
-- "./spec/features/issues/user_edits_issue_spec.rb"
-- "./spec/features/issues/user_filters_issues_spec.rb"
-- "./spec/features/issues/user_interacts_with_awards_spec.rb"
-- "./spec/features/issues/user_invites_from_a_comment_spec.rb"
-- "./spec/features/issues/user_resets_their_incoming_email_token_spec.rb"
-- "./spec/features/issues/user_sees_empty_state_spec.rb"
-- "./spec/features/issues/user_sees_live_update_spec.rb"
-- "./spec/features/issues/user_sees_sidebar_updates_in_realtime_spec.rb"
-- "./spec/features/issues/user_sorts_issue_comments_spec.rb"
-- "./spec/features/issues/user_sorts_issues_spec.rb"
-- "./spec/features/issues/user_toggles_subscription_spec.rb"
-- "./spec/features/issues/user_uses_quick_actions_spec.rb"
-- "./spec/features/issues/user_views_issue_spec.rb"
-- "./spec/features/issues/user_views_issues_spec.rb"
-- "./spec/features/jira_connect/branches_spec.rb"
-- "./spec/features/labels_hierarchy_spec.rb"
-- "./spec/features/markdown/copy_as_gfm_spec.rb"
-- "./spec/features/markdown/gitlab_flavored_markdown_spec.rb"
-- "./spec/features/markdown/keyboard_shortcuts_spec.rb"
-- "./spec/features/markdown/math_spec.rb"
-- "./spec/features/markdown/mermaid_spec.rb"
-- "./spec/features/markdown/metrics_spec.rb"
-- "./spec/features/merge_request/batch_comments_spec.rb"
-- "./spec/features/merge_request/close_reopen_report_toggle_spec.rb"
-- "./spec/features/merge_request/maintainer_edits_fork_spec.rb"
-- "./spec/features/merge_request/merge_request_discussion_lock_spec.rb"
-- "./spec/features/merge_requests/filters_generic_behavior_spec.rb"
-- "./spec/features/merge_requests/user_exports_as_csv_spec.rb"
-- "./spec/features/merge_requests/user_filters_by_approvals_spec.rb"
-- "./spec/features/merge_requests/user_filters_by_assignees_spec.rb"
-- "./spec/features/merge_requests/user_filters_by_deployments_spec.rb"
-- "./spec/features/merge_requests/user_filters_by_draft_spec.rb"
-- "./spec/features/merge_requests/user_filters_by_labels_spec.rb"
-- "./spec/features/merge_requests/user_filters_by_milestones_spec.rb"
-- "./spec/features/merge_requests/user_filters_by_multiple_criteria_spec.rb"
-- "./spec/features/merge_requests/user_filters_by_target_branch_spec.rb"
-- "./spec/features/merge_requests/user_mass_updates_spec.rb"
-- "./spec/features/merge_request/user_accepts_merge_request_spec.rb"
-- "./spec/features/merge_request/user_allows_commits_from_memebers_who_can_merge_spec.rb"
-- "./spec/features/merge_request/user_approves_spec.rb"
-- "./spec/features/merge_request/user_assigns_themselves_spec.rb"
-- "./spec/features/merge_request/user_awards_emoji_spec.rb"
-- "./spec/features/merge_request/user_clicks_merge_request_tabs_spec.rb"
-- "./spec/features/merge_request/user_comments_on_commit_spec.rb"
-- "./spec/features/merge_request/user_comments_on_diff_spec.rb"
-- "./spec/features/merge_request/user_comments_on_merge_request_spec.rb"
-- "./spec/features/merge_request/user_creates_image_diff_notes_spec.rb"
-- "./spec/features/merge_request/user_creates_merge_request_spec.rb"
-- "./spec/features/merge_request/user_creates_mr_spec.rb"
-- "./spec/features/merge_request/user_customizes_merge_commit_message_spec.rb"
-- "./spec/features/merge_request/user_edits_assignees_sidebar_spec.rb"
-- "./spec/features/merge_request/user_edits_merge_request_spec.rb"
-- "./spec/features/merge_request/user_edits_mr_spec.rb"
-- "./spec/features/merge_request/user_edits_reviewers_sidebar_spec.rb"
-- "./spec/features/merge_request/user_expands_diff_spec.rb"
-- "./spec/features/merge_request/user_interacts_with_batched_mr_diffs_spec.rb"
-- "./spec/features/merge_request/user_invites_from_a_comment_spec.rb"
-- "./spec/features/merge_request/user_jumps_to_discussion_spec.rb"
-- "./spec/features/merge_request/user_locks_discussion_spec.rb"
-- "./spec/features/merge_request/user_manages_subscription_spec.rb"
-- "./spec/features/merge_request/user_marks_merge_request_as_draft_spec.rb"
-- "./spec/features/merge_request/user_merges_immediately_spec.rb"
-- "./spec/features/merge_request/user_merges_merge_request_spec.rb"
-- "./spec/features/merge_request/user_merges_only_if_pipeline_succeeds_spec.rb"
-- "./spec/features/merge_request/user_merges_when_pipeline_succeeds_spec.rb"
-- "./spec/features/merge_request/user_posts_diff_notes_spec.rb"
-- "./spec/features/merge_request/user_posts_notes_spec.rb"
-- "./spec/features/merge_request/user_rebases_merge_request_spec.rb"
-- "./spec/features/merge_request/user_resolves_conflicts_spec.rb"
-- "./spec/features/merge_request/user_resolves_diff_notes_and_discussions_resolve_spec.rb"
-- "./spec/features/merge_request/user_resolves_outdated_diff_discussions_spec.rb"
-- "./spec/features/merge_request/user_resolves_wip_mr_spec.rb"
-- "./spec/features/merge_request/user_reverts_merge_request_spec.rb"
-- "./spec/features/merge_request/user_reviews_image_spec.rb"
-- "./spec/features/merge_request/user_scrolls_to_note_on_load_spec.rb"
-- "./spec/features/merge_request/user_sees_avatar_on_diff_notes_spec.rb"
-- "./spec/features/merge_request/user_sees_check_out_branch_modal_spec.rb"
-- "./spec/features/merge_request/user_sees_cherry_pick_modal_spec.rb"
-- "./spec/features/merge_request/user_sees_closing_issues_message_spec.rb"
-- "./spec/features/merge_request/user_sees_deleted_target_branch_spec.rb"
-- "./spec/features/merge_request/user_sees_deployment_widget_spec.rb"
-- "./spec/features/merge_request/user_sees_diff_spec.rb"
-- "./spec/features/merge_request/user_sees_discussions_spec.rb"
-- "./spec/features/merge_request/user_sees_merge_button_depending_on_unresolved_discussions_spec.rb"
-- "./spec/features/merge_request/user_sees_merge_request_pipelines_spec.rb"
-- "./spec/features/merge_request/user_sees_merge_widget_spec.rb"
-- "./spec/features/merge_request/user_sees_mini_pipeline_graph_spec.rb"
-- "./spec/features/merge_request/user_sees_mr_from_deleted_forked_project_spec.rb"
-- "./spec/features/merge_request/user_sees_mr_with_deleted_source_branch_spec.rb"
-- "./spec/features/merge_request/user_sees_notes_from_forked_project_spec.rb"
-- "./spec/features/merge_request/user_sees_pipelines_from_forked_project_spec.rb"
-- "./spec/features/merge_request/user_sees_pipelines_spec.rb"
-- "./spec/features/merge_request/user_sees_suggest_pipeline_spec.rb"
-- "./spec/features/merge_request/user_sees_system_notes_spec.rb"
-- "./spec/features/merge_request/user_sees_versions_spec.rb"
-- "./spec/features/merge_request/user_selects_branches_for_new_mr_spec.rb"
-- "./spec/features/merge_request/user_squashes_merge_request_spec.rb"
-- "./spec/features/merge_request/user_suggests_changes_on_diff_spec.rb"
-- "./spec/features/merge_request/user_toggles_whitespace_changes_spec.rb"
-- "./spec/features/merge_request/user_uses_quick_actions_spec.rb"
-- "./spec/features/merge_request/user_views_auto_expanding_diff_spec.rb"
-- "./spec/features/merge_request/user_views_diffs_commit_spec.rb"
-- "./spec/features/merge_request/user_views_diffs_file_by_file_spec.rb"
-- "./spec/features/merge_request/user_views_diffs_spec.rb"
-- "./spec/features/merge_request/user_views_open_merge_request_spec.rb"
-- "./spec/features/merge_request/user_views_user_status_on_merge_request_spec.rb"
-- "./spec/features/milestone_spec.rb"
-- "./spec/features/milestones/user_creates_milestone_spec.rb"
-- "./spec/features/milestones/user_deletes_milestone_spec.rb"
-- "./spec/features/milestones/user_edits_milestone_spec.rb"
-- "./spec/features/milestones/user_views_milestone_spec.rb"
-- "./spec/features/milestones/user_views_milestones_spec.rb"
-- "./spec/features/nav/top_nav_responsive_spec.rb"
-- "./spec/features/oauth_login_spec.rb"
-- "./spec/features/participants_autocomplete_spec.rb"
-- "./spec/features/populate_new_pipeline_vars_with_params_spec.rb"
-- "./spec/features/profiles/account_spec.rb"
-- "./spec/features/profiles/active_sessions_spec.rb"
-- "./spec/features/profiles/keys_spec.rb"
-- "./spec/features/profiles/oauth_applications_spec.rb"
-- "./spec/features/profile_spec.rb"
-- "./spec/features/profiles/personal_access_tokens_spec.rb"
-- "./spec/features/profiles/user_changes_notified_of_own_activity_spec.rb"
-- "./spec/features/profiles/user_edit_preferences_spec.rb"
-- "./spec/features/profiles/user_edit_profile_spec.rb"
-- "./spec/features/profiles/user_search_settings_spec.rb"
-- "./spec/features/profiles/user_visits_notifications_tab_spec.rb"
-- "./spec/features/profiles/user_visits_profile_preferences_page_spec.rb"
-- "./spec/features/profiles/user_visits_profile_spec.rb"
-- "./spec/features/project_group_variables_spec.rb"
-- "./spec/features/projects/activity/user_sees_activity_spec.rb"
-- "./spec/features/projects/activity/user_sees_design_activity_spec.rb"
-- "./spec/features/projects/activity/user_sees_design_comment_spec.rb"
-- "./spec/features/projects/activity/user_sees_private_activity_spec.rb"
-- "./spec/features/projects/artifacts/file_spec.rb"
-- "./spec/features/projects/artifacts/raw_spec.rb"
-- "./spec/features/projects/artifacts/user_browses_artifacts_spec.rb"
-- "./spec/features/projects/badges/list_spec.rb"
-- "./spec/features/projects/badges/pipeline_badge_spec.rb"
-- "./spec/features/projects/blobs/balsamiq_spec.rb"
-- "./spec/features/projects/blobs/blob_line_permalink_updater_spec.rb"
-- "./spec/features/projects/blobs/blob_show_spec.rb"
-- "./spec/features/projects/blobs/edit_spec.rb"
-- "./spec/features/projects/blobs/shortcuts_blob_spec.rb"
-- "./spec/features/projects/blobs/user_creates_new_blob_in_new_project_spec.rb"
-- "./spec/features/projects/blobs/user_follows_pipeline_suggest_nudge_spec.rb"
-- "./spec/features/projects/blobs/user_views_pipeline_editor_button_spec.rb"
-- "./spec/features/projects/branches/new_branch_ref_dropdown_spec.rb"
-- "./spec/features/projects/branches_spec.rb"
-- "./spec/features/projects/branches/user_creates_branch_spec.rb"
-- "./spec/features/projects/branches/user_deletes_branch_spec.rb"
-- "./spec/features/projects/branches/user_views_branches_spec.rb"
-- "./spec/features/projects/ci/editor_spec.rb"
-- "./spec/features/projects/clusters/eks_spec.rb"
-- "./spec/features/projects/clusters/gcp_spec.rb"
-- "./spec/features/projects/clusters_spec.rb"
-- "./spec/features/projects/clusters/user_spec.rb"
-- "./spec/features/projects/commit/builds_spec.rb"
-- "./spec/features/projects/commit/cherry_pick_spec.rb"
-- "./spec/features/projects/commit/comments/user_adds_comment_spec.rb"
-- "./spec/features/projects/commit/comments/user_deletes_comments_spec.rb"
-- "./spec/features/projects/commit/comments/user_edits_comments_spec.rb"
-- "./spec/features/projects/commit/diff_notes_spec.rb"
-- "./spec/features/projects/commit/mini_pipeline_graph_spec.rb"
-- "./spec/features/projects/commits/user_browses_commits_spec.rb"
-- "./spec/features/projects/commit/user_comments_on_commit_spec.rb"
-- "./spec/features/projects/commit/user_reverts_commit_spec.rb"
-- "./spec/features/projects/commit/user_views_user_status_on_commit_spec.rb"
-- "./spec/features/projects/compare_spec.rb"
-- "./spec/features/projects/container_registry_spec.rb"
-- "./spec/features/projects/deploy_keys_spec.rb"
-- "./spec/features/projects/diffs/diff_show_spec.rb"
-- "./spec/features/projects/environments/environment_metrics_spec.rb"
-- "./spec/features/projects/environments/environment_spec.rb"
-- "./spec/features/projects/environments/environments_spec.rb"
-- "./spec/features/projects/environments_pod_logs_spec.rb"
-- "./spec/features/projects/feature_flags/user_creates_feature_flag_spec.rb"
-- "./spec/features/projects/feature_flags/user_deletes_feature_flag_spec.rb"
-- "./spec/features/projects/feature_flags/user_sees_feature_flag_list_spec.rb"
-- "./spec/features/projects/feature_flags/user_updates_feature_flag_spec.rb"
-- "./spec/features/projects/feature_flag_user_lists/user_deletes_feature_flag_user_list_spec.rb"
-- "./spec/features/projects/feature_flag_user_lists/user_edits_feature_flag_user_list_spec.rb"
-- "./spec/features/projects/feature_flag_user_lists/user_sees_feature_flag_user_list_details_spec.rb"
-- "./spec/features/projects/features_visibility_spec.rb"
-- "./spec/features/projects/files/dockerfile_dropdown_spec.rb"
-- "./spec/features/projects/files/edit_file_soft_wrap_spec.rb"
-- "./spec/features/projects/files/files_sort_submodules_with_folders_spec.rb"
-- "./spec/features/projects/files/find_file_keyboard_spec.rb"
-- "./spec/features/projects/files/gitignore_dropdown_spec.rb"
-- "./spec/features/projects/files/gitlab_ci_yml_dropdown_spec.rb"
-- "./spec/features/projects/files/project_owner_creates_license_file_spec.rb"
-- "./spec/features/projects/files/project_owner_sees_link_to_create_license_file_in_empty_project_spec.rb"
-- "./spec/features/projects/files/template_selector_menu_spec.rb"
-- "./spec/features/projects/files/template_type_dropdown_spec.rb"
-- "./spec/features/projects/files/undo_template_spec.rb"
-- "./spec/features/projects/files/user_browses_a_tree_with_a_folder_containing_only_a_folder_spec.rb"
-- "./spec/features/projects/files/user_browses_files_spec.rb"
-- "./spec/features/projects/files/user_browses_lfs_files_spec.rb"
-- "./spec/features/projects/files/user_creates_directory_spec.rb"
-- "./spec/features/projects/files/user_creates_files_spec.rb"
-- "./spec/features/projects/files/user_deletes_files_spec.rb"
-- "./spec/features/projects/files/user_edits_files_spec.rb"
-- "./spec/features/projects/files/user_find_file_spec.rb"
-- "./spec/features/projects/files/user_reads_pipeline_status_spec.rb"
-- "./spec/features/projects/files/user_replaces_files_spec.rb"
-- "./spec/features/projects/files/user_uploads_files_spec.rb"
-- "./spec/features/projects/fork_spec.rb"
-- "./spec/features/projects/gfm_autocomplete_load_spec.rb"
-- "./spec/features/projects/graph_spec.rb"
-- "./spec/features/projects/import_export/export_file_spec.rb"
-- "./spec/features/projects/import_export/import_file_spec.rb"
-- "./spec/features/projects/infrastructure_registry_spec.rb"
-- "./spec/features/projects/integrations/user_activates_asana_spec.rb"
-- "./spec/features/projects/integrations/user_activates_assembla_spec.rb"
-- "./spec/features/projects/integrations/user_activates_atlassian_bamboo_ci_spec.rb"
-- "./spec/features/projects/integrations/user_activates_flowdock_spec.rb"
-- "./spec/features/projects/integrations/user_activates_jira_spec.rb"
-- "./spec/features/projects/integrations/user_activates_pivotaltracker_spec.rb"
-- "./spec/features/projects/integrations/user_uses_inherited_settings_spec.rb"
-- "./spec/features/projects/issuable_templates_spec.rb"
-- "./spec/features/projects/issues/design_management/user_paginates_designs_spec.rb"
-- "./spec/features/projects/issues/design_management/user_permissions_upload_spec.rb"
-- "./spec/features/projects/issues/design_management/user_uploads_designs_spec.rb"
-- "./spec/features/projects/issues/design_management/user_views_design_spec.rb"
-- "./spec/features/projects/issues/design_management/user_views_designs_spec.rb"
-- "./spec/features/projects/issues/design_management/user_views_designs_with_svg_xss_spec.rb"
-- "./spec/features/projects/issues/email_participants_spec.rb"
-- "./spec/features/projects/jobs/permissions_spec.rb"
-- "./spec/features/projects/jobs_spec.rb"
-- "./spec/features/projects/jobs/user_browses_job_spec.rb"
-- "./spec/features/projects/jobs/user_browses_jobs_spec.rb"
-- "./spec/features/projects/labels/issues_sorted_by_priority_spec.rb"
-- "./spec/features/projects/labels/search_labels_spec.rb"
-- "./spec/features/projects/labels/sort_labels_spec.rb"
-- "./spec/features/projects/labels/subscription_spec.rb"
-- "./spec/features/projects/labels/update_prioritization_spec.rb"
-- "./spec/features/projects/labels/user_removes_labels_spec.rb"
-- "./spec/features/projects/members/anonymous_user_sees_members_spec.rb"
-- "./spec/features/projects/members/group_member_cannot_leave_group_project_spec.rb"
-- "./spec/features/projects/members/group_members_spec.rb"
-- "./spec/features/projects/members/group_requester_cannot_request_access_to_project_spec.rb"
-- "./spec/features/projects/members/groups_with_access_list_spec.rb"
-- "./spec/features/projects/members/invite_group_spec.rb"
-- "./spec/features/projects/members/list_spec.rb"
-- "./spec/features/projects/members/master_adds_member_with_expiration_date_spec.rb"
-- "./spec/features/projects/members/master_manages_access_requests_spec.rb"
-- "./spec/features/projects/members/sorting_spec.rb"
-- "./spec/features/projects/members/tabs_spec.rb"
-- "./spec/features/projects/members/user_requests_access_spec.rb"
-- "./spec/features/projects/merge_request_button_spec.rb"
-- "./spec/features/projects/milestones/gfm_autocomplete_spec.rb"
-- "./spec/features/projects/milestones/milestones_sorting_spec.rb"
-- "./spec/features/projects/milestones/new_spec.rb"
-- "./spec/features/projects/milestones/user_interacts_with_labels_spec.rb"
-- "./spec/features/projects/network_graph_spec.rb"
-- "./spec/features/projects/new_project_from_template_spec.rb"
-- "./spec/features/projects/new_project_spec.rb"
-- "./spec/features/projects/packages_spec.rb"
-- "./spec/features/projects/pages/user_adds_domain_spec.rb"
-- "./spec/features/projects/pages/user_edits_lets_encrypt_settings_spec.rb"
-- "./spec/features/projects/pages/user_edits_settings_spec.rb"
-- "./spec/features/projects/pipeline_schedules_spec.rb"
- "./spec/features/projects/pipelines/pipeline_spec.rb"
-- "./spec/features/projects/pipelines/pipelines_spec.rb"
-- "./spec/features/projects/product_analytics/graphs_spec.rb"
-- "./spec/features/projects/releases/user_creates_release_spec.rb"
-- "./spec/features/projects/releases/user_views_edit_release_spec.rb"
-- "./spec/features/projects/releases/user_views_release_spec.rb"
-- "./spec/features/projects/releases/user_views_releases_spec.rb"
-- "./spec/features/projects/remote_mirror_spec.rb"
-- "./spec/features/projects/serverless/functions_spec.rb"
-- "./spec/features/projects/services/disable_triggers_spec.rb"
-- "./spec/features/projects/services/prometheus_external_alerts_spec.rb"
-- "./spec/features/projects/services/user_activates_emails_on_push_spec.rb"
-- "./spec/features/projects/services/user_activates_irker_spec.rb"
-- "./spec/features/projects/services/user_activates_issue_tracker_spec.rb"
-- "./spec/features/projects/services/user_activates_jetbrains_teamcity_ci_spec.rb"
-- "./spec/features/projects/services/user_activates_mattermost_slash_command_spec.rb"
-- "./spec/features/projects/services/user_activates_packagist_spec.rb"
-- "./spec/features/projects/services/user_activates_prometheus_spec.rb"
-- "./spec/features/projects/services/user_activates_pushover_spec.rb"
-- "./spec/features/projects/services/user_activates_slack_notifications_spec.rb"
-- "./spec/features/projects/services/user_activates_slack_slash_command_spec.rb"
-- "./spec/features/projects/services/user_views_services_spec.rb"
-- "./spec/features/projects/settings/access_tokens_spec.rb"
-- "./spec/features/projects/settings/lfs_settings_spec.rb"
-- "./spec/features/projects/settings/monitor_settings_spec.rb"
-- "./spec/features/projects/settings/packages_settings_spec.rb"
-- "./spec/features/projects/settings/project_badges_spec.rb"
-- "./spec/features/projects/settings/project_settings_spec.rb"
-- "./spec/features/projects/settings/registry_settings_spec.rb"
-- "./spec/features/projects/settings/repository_settings_spec.rb"
-- "./spec/features/projects/settings/service_desk_setting_spec.rb"
-- "./spec/features/projects/settings/user_changes_default_branch_spec.rb"
-- "./spec/features/projects/settings/user_interacts_with_deploy_keys_spec.rb"
-- "./spec/features/projects/settings/user_manages_merge_requests_settings_spec.rb"
-- "./spec/features/projects/settings/user_manages_project_members_spec.rb"
-- "./spec/features/projects/settings/user_searches_in_settings_spec.rb"
-- "./spec/features/projects/settings/user_sees_revoke_deploy_token_modal_spec.rb"
-- "./spec/features/projects/settings/user_tags_project_spec.rb"
-- "./spec/features/projects/settings/user_transfers_a_project_spec.rb"
-- "./spec/features/projects/settings/visibility_settings_spec.rb"
-- "./spec/features/projects/settings/webhooks_settings_spec.rb"
-- "./spec/features/projects/show/schema_markup_spec.rb"
-- "./spec/features/projects/show/user_interacts_with_auto_devops_banner_spec.rb"
-- "./spec/features/projects/show/user_interacts_with_stars_spec.rb"
-- "./spec/features/projects/show/user_manages_notifications_spec.rb"
-- "./spec/features/projects/show/user_sees_collaboration_links_spec.rb"
-- "./spec/features/projects/show/user_sees_last_commit_ci_status_spec.rb"
-- "./spec/features/projects/show/user_sees_readme_spec.rb"
-- "./spec/features/projects/show/user_uploads_files_spec.rb"
-- "./spec/features/projects/snippets/create_snippet_spec.rb"
-- "./spec/features/projects/snippets/show_spec.rb"
-- "./spec/features/projects/snippets/user_comments_on_snippet_spec.rb"
-- "./spec/features/projects/snippets/user_deletes_snippet_spec.rb"
-- "./spec/features/projects/snippets/user_updates_snippet_spec.rb"
-- "./spec/features/projects_spec.rb"
-- "./spec/features/projects/sub_group_issuables_spec.rb"
-- "./spec/features/projects/tags/user_edits_tags_spec.rb"
-- "./spec/features/projects/terraform_spec.rb"
-- "./spec/features/projects/tree/create_directory_spec.rb"
-- "./spec/features/projects/tree/create_file_spec.rb"
-- "./spec/features/projects/tree/tree_show_spec.rb"
-- "./spec/features/projects/tree/upload_file_spec.rb"
-- "./spec/features/projects/user_changes_project_visibility_spec.rb"
-- "./spec/features/projects/user_creates_project_spec.rb"
-- "./spec/features/projects/user_sees_sidebar_spec.rb"
-- "./spec/features/projects/user_sees_user_popover_spec.rb"
-- "./spec/features/projects/user_uses_shortcuts_spec.rb"
-- "./spec/features/projects/user_views_empty_project_spec.rb"
-- "./spec/features/projects/view_on_env_spec.rb"
-- "./spec/features/projects/wikis_spec.rb"
-- "./spec/features/projects/wiki/user_views_wiki_empty_spec.rb"
-- "./spec/features/project_variables_spec.rb"
-- "./spec/features/promotion_spec.rb"
-- "./spec/features/protected_branches_spec.rb"
-- "./spec/features/protected_tags_spec.rb"
-- "./spec/features/reportable_note/commit_spec.rb"
-- "./spec/features/reportable_note/issue_spec.rb"
-- "./spec/features/reportable_note/merge_request_spec.rb"
-- "./spec/features/reportable_note/snippets_spec.rb"
-- "./spec/features/runners_spec.rb"
-- "./spec/features/search/user_searches_for_code_spec.rb"
-- "./spec/features/search/user_searches_for_commits_spec.rb"
-- "./spec/features/search/user_searches_for_issues_spec.rb"
-- "./spec/features/search/user_searches_for_merge_requests_spec.rb"
-- "./spec/features/search/user_searches_for_milestones_spec.rb"
-- "./spec/features/search/user_searches_for_projects_spec.rb"
-- "./spec/features/search/user_searches_for_users_spec.rb"
-- "./spec/features/search/user_searches_for_wiki_pages_spec.rb"
-- "./spec/features/search/user_uses_header_search_field_spec.rb"
-- "./spec/features/search/user_uses_search_filters_spec.rb"
- "./spec/features/signed_commits_spec.rb"
-- "./spec/features/snippets/embedded_snippet_spec.rb"
-- "./spec/features/snippets/internal_snippet_spec.rb"
-- "./spec/features/snippets/notes_on_personal_snippets_spec.rb"
-- "./spec/features/snippets/private_snippets_spec.rb"
-- "./spec/features/snippets/public_snippets_spec.rb"
-- "./spec/features/snippets/show_spec.rb"
-- "./spec/features/snippets/user_creates_snippet_spec.rb"
-- "./spec/features/snippets/user_deletes_snippet_spec.rb"
-- "./spec/features/snippets/user_edits_snippet_spec.rb"
-- "./spec/features/tags/developer_creates_tag_spec.rb"
-- "./spec/features/tags/developer_deletes_tag_spec.rb"
-- "./spec/features/tags/developer_updates_tag_spec.rb"
-- "./spec/features/task_lists_spec.rb"
-- "./spec/features/triggers_spec.rb"
-- "./spec/features/u2f_spec.rb"
-- "./spec/features/uploads/user_uploads_avatar_to_profile_spec.rb"
-- "./spec/features/uploads/user_uploads_file_to_note_spec.rb"
-- "./spec/features/user_can_display_performance_bar_spec.rb"
-- "./spec/features/user_opens_link_to_comment_spec.rb"
-- "./spec/features/user_sees_revert_modal_spec.rb"
-- "./spec/features/users/login_spec.rb"
-- "./spec/features/users/logout_spec.rb"
-- "./spec/features/users/overview_spec.rb"
-- "./spec/features/users/signup_spec.rb"
-- "./spec/features/users/snippets_spec.rb"
-- "./spec/features/users/terms_spec.rb"
-- "./spec/features/users/user_browses_projects_on_user_page_spec.rb"
-- "./spec/features/webauthn_spec.rb"
-- "./spec/features/whats_new_spec.rb"
-- "./spec/finders/ci/pipeline_schedules_finder_spec.rb"
-- "./spec/finders/ci/pipelines_finder_spec.rb"
-- "./spec/finders/ci/pipelines_for_merge_request_finder_spec.rb"
-- "./spec/finders/projects_finder_spec.rb"
-- "./spec/finders/releases/evidence_pipeline_finder_spec.rb"
-- "./spec/frontend/fixtures/analytics.rb"
-- "./spec/frontend/fixtures/jobs.rb"
-- "./spec/frontend/fixtures/pipeline_schedules.rb"
-- "./spec/frontend/fixtures/pipelines.rb"
-- "./spec/graphql/mutations/design_management/upload_spec.rb"
-- "./spec/graphql/mutations/merge_requests/accept_spec.rb"
-- "./spec/graphql/resolvers/ci/test_report_summary_resolver_spec.rb"
- "./spec/helpers/issuables_helper_spec.rb"
-- "./spec/initializers/active_record_locking_spec.rb"
-- "./spec/initializers/database_config_spec.rb"
- "./spec/lib/gitlab/auth_spec.rb"
-- "./spec/lib/gitlab/ci/badge/pipeline/status_spec.rb"
-- "./spec/lib/gitlab/ci/build/policy/changes_spec.rb"
-- "./spec/lib/gitlab/ci/charts_spec.rb"
-- "./spec/lib/gitlab/ci/config_spec.rb"
- "./spec/lib/gitlab/ci/pipeline/chain/create_spec.rb"
- "./spec/lib/gitlab/ci/pipeline/chain/seed_block_spec.rb"
- "./spec/lib/gitlab/ci/pipeline/seed/build_spec.rb"
-- "./spec/lib/gitlab/ci/pipeline/seed/stage_spec.rb"
-- "./spec/lib/gitlab/ci/status/stage/common_spec.rb"
-- "./spec/lib/gitlab/ci/status/stage/factory_spec.rb"
-- "./spec/lib/gitlab/ci/status/stage/play_manual_spec.rb"
- "./spec/lib/gitlab/ci/templates/5_minute_production_app_ci_yaml_spec.rb"
-- "./spec/lib/gitlab/ci/templates/auto_devops_gitlab_ci_yaml_spec.rb"
- "./spec/lib/gitlab/ci/templates/AWS/deploy_ecs_gitlab_ci_yaml_spec.rb"
- "./spec/lib/gitlab/ci/templates/Jobs/deploy_gitlab_ci_yaml_spec.rb"
+- "./spec/lib/gitlab/ci/templates/auto_devops_gitlab_ci_yaml_spec.rb"
- "./spec/lib/gitlab/ci/templates/managed_cluster_applications_gitlab_ci_yaml_spec.rb"
-- "./spec/lib/gitlab/database/bulk_update_spec.rb"
-- "./spec/lib/gitlab/database/connection_spec.rb"
-- "./spec/lib/gitlab/database/load_balancing/host_spec.rb"
-- "./spec/lib/gitlab/database/load_balancing_spec.rb"
-- "./spec/lib/gitlab/database/postgresql_adapter/force_disconnectable_mixin_spec.rb"
-- "./spec/lib/gitlab/database/postgresql_adapter/type_map_cache_spec.rb"
-- "./spec/lib/gitlab/database/schema_migrations/context_spec.rb"
-- "./spec/lib/gitlab/database/with_lock_retries_outside_transaction_spec.rb"
-- "./spec/lib/gitlab/database/with_lock_retries_spec.rb"
-- "./spec/lib/gitlab/data_builder/pipeline_spec.rb"
- "./spec/lib/gitlab/email/handler/create_issue_handler_spec.rb"
- "./spec/lib/gitlab/email/handler/create_merge_request_handler_spec.rb"
- "./spec/lib/gitlab/email/handler/create_note_handler_spec.rb"
- "./spec/lib/gitlab/email/handler/create_note_on_issuable_handler_spec.rb"
-- "./spec/lib/gitlab/email/handler/unsubscribe_handler_spec.rb"
-- "./spec/lib/gitlab/usage_data_spec.rb"
- "./spec/lib/peek/views/active_record_spec.rb"
-- "./spec/mailers/emails/pipelines_spec.rb"
-- "./spec/migrations/20210205174154_remove_bad_dependency_proxy_manifests_spec.rb"
-- "./spec/migrations/20210722150102_operations_feature_flags_correct_flexible_rollout_values_spec.rb"
-- "./spec/migrations/backfill_escalation_policies_for_oncall_schedules_spec.rb"
-- "./spec/migrations/insert_ci_daily_pipeline_schedule_triggers_plan_limits_spec.rb"
-- "./spec/migrations/remove_duplicate_dast_site_tokens_with_same_token_spec.rb"
-- "./spec/models/ci/bridge_spec.rb"
- "./spec/models/ci/build_need_spec.rb"
-- "./spec/models/ci/build_spec.rb"
- "./spec/models/ci/build_trace_chunk_spec.rb"
-- "./spec/models/ci/commit_with_pipeline_spec.rb"
-- "./spec/models/ci/group_spec.rb"
- "./spec/models/ci/group_variable_spec.rb"
-- "./spec/models/ci/instance_variable_spec.rb"
- "./spec/models/ci/job_artifact_spec.rb"
- "./spec/models/ci/job_variable_spec.rb"
-- "./spec/models/ci/legacy_stage_spec.rb"
-- "./spec/models/ci/pipeline_schedule_spec.rb"
- "./spec/models/ci/pipeline_spec.rb"
-- "./spec/models/ci/runner_namespace_spec.rb"
-- "./spec/models/ci/runner_project_spec.rb"
- "./spec/models/ci/runner_spec.rb"
-- "./spec/models/ci/running_build_spec.rb"
-- "./spec/models/ci/stage_spec.rb"
- "./spec/models/ci/variable_spec.rb"
-- "./spec/models/clusters/applications/jupyter_spec.rb"
- "./spec/models/clusters/applications/runner_spec.rb"
-- "./spec/models/commit_collection_spec.rb"
- "./spec/models/commit_status_spec.rb"
- "./spec/models/concerns/batch_destroy_dependent_associations_spec.rb"
- "./spec/models/concerns/bulk_insertable_associations_spec.rb"
-- "./spec/models/concerns/cron_schedulable_spec.rb"
- "./spec/models/concerns/has_environment_scope_spec.rb"
-- "./spec/models/concerns/schedulable_spec.rb"
- "./spec/models/concerns/token_authenticatable_spec.rb"
- "./spec/models/design_management/version_spec.rb"
-- "./spec/models/environment_status_spec.rb"
- "./spec/models/hooks/system_hook_spec.rb"
-- "./spec/models/issue_spec.rb"
- "./spec/models/members/project_member_spec.rb"
-- "./spec/models/merge_request_spec.rb"
-- "./spec/models/plan_spec.rb"
-- "./spec/models/project_feature_usage_spec.rb"
-- "./spec/models/project_spec.rb"
- "./spec/models/spam_log_spec.rb"
- "./spec/models/user_spec.rb"
- "./spec/models/user_status_spec.rb"
-- "./spec/policies/ci/build_policy_spec.rb"
-- "./spec/policies/ci/pipeline_policy_spec.rb"
-- "./spec/presenters/ci/stage_presenter_spec.rb"
-- "./spec/requests/api/admin/ci/variables_spec.rb"
-- "./spec/requests/api/admin/plan_limits_spec.rb"
-- "./spec/requests/api/ci/jobs_spec.rb"
- "./spec/requests/api/ci/pipeline_schedules_spec.rb"
- "./spec/requests/api/ci/pipelines_spec.rb"
-- "./spec/requests/api/ci/runner/runners_post_spec.rb"
-- "./spec/requests/api/ci/runners_spec.rb"
-- "./spec/requests/api/commits_spec.rb"
- "./spec/requests/api/commit_statuses_spec.rb"
-- "./spec/requests/api/graphql/ci/runner_spec.rb"
+- "./spec/requests/api/commits_spec.rb"
- "./spec/requests/api/graphql/mutations/ci/pipeline_destroy_spec.rb"
-- "./spec/requests/api/graphql/project/issues_spec.rb"
-- "./spec/requests/api/graphql/project/merge_request_spec.rb"
-- "./spec/requests/api/graphql/project_query_spec.rb"
-- "./spec/requests/api/issues/issues_spec.rb"
-- "./spec/requests/api/merge_requests_spec.rb"
-- "./spec/requests/api/projects_spec.rb"
- "./spec/requests/api/resource_access_tokens_spec.rb"
- "./spec/requests/api/users_spec.rb"
-- "./spec/requests/lfs_http_spec.rb"
-- "./spec/requests/projects/cycle_analytics_events_spec.rb"
-- "./spec/serializers/ci/downloadable_artifact_entity_spec.rb"
-- "./spec/serializers/ci/downloadable_artifact_serializer_spec.rb"
-- "./spec/serializers/ci/pipeline_entity_spec.rb"
-- "./spec/serializers/merge_request_poll_cached_widget_entity_spec.rb"
-- "./spec/serializers/merge_request_poll_widget_entity_spec.rb"
-- "./spec/serializers/merge_request_widget_entity_spec.rb"
-- "./spec/serializers/pipeline_details_entity_spec.rb"
-- "./spec/serializers/pipeline_serializer_spec.rb"
-- "./spec/serializers/stage_entity_spec.rb"
-- "./spec/serializers/stage_serializer_spec.rb"
-- "./spec/serializers/test_report_entity_spec.rb"
-- "./spec/serializers/test_report_summary_entity_spec.rb"
-- "./spec/serializers/test_suite_entity_spec.rb"
-- "./spec/serializers/test_suite_summary_entity_spec.rb"
-- "./spec/services/auto_merge/merge_when_pipeline_succeeds_service_spec.rb"
-- "./spec/services/ci/compare_accessibility_reports_service_spec.rb"
-- "./spec/services/ci/compare_codequality_reports_service_spec.rb"
-- "./spec/services/ci/compare_reports_base_service_spec.rb"
-- "./spec/services/ci/compare_test_reports_service_spec.rb"
- "./spec/services/ci/create_pipeline_service/environment_spec.rb"
- "./spec/services/ci/create_pipeline_service_spec.rb"
- "./spec/services/ci/destroy_pipeline_service_spec.rb"
-- "./spec/services/ci/disable_user_pipeline_schedules_service_spec.rb"
- "./spec/services/ci/ensure_stage_service_spec.rb"
- "./spec/services/ci/expire_pipeline_cache_service_spec.rb"
-- "./spec/services/ci/generate_codequality_mr_diff_report_service_spec.rb"
-- "./spec/services/ci/generate_coverage_reports_service_spec.rb"
- "./spec/services/ci/job_artifacts/destroy_all_expired_service_spec.rb"
- "./spec/services/ci/job_artifacts/destroy_associations_service_spec.rb"
-- "./spec/services/ci/job_artifacts/destroy_batch_service_spec.rb"
-- "./spec/services/ci/pipeline_artifacts/coverage_report_service_spec.rb"
-- "./spec/services/ci/pipeline_artifacts/create_code_quality_mr_diff_report_service_spec.rb"
- "./spec/services/ci/pipeline_bridge_status_service_spec.rb"
-- "./spec/services/ci/pipeline_processing/shared_processing_service.rb"
- "./spec/services/ci/pipelines/add_job_service_spec.rb"
-- "./spec/services/ci/pipeline_schedule_service_spec.rb"
-- "./spec/services/ci/pipeline_trigger_service_spec.rb"
-- "./spec/services/ci/register_job_service_spec.rb"
- "./spec/services/ci/retry_build_service_spec.rb"
-- "./spec/services/ci/test_failure_history_service_spec.rb"
-- "./spec/services/ci/update_instance_variables_service_spec.rb"
-- "./spec/services/deployments/update_environment_service_spec.rb"
-- "./spec/services/design_management/save_designs_service_spec.rb"
-- "./spec/services/environments/stop_service_spec.rb"
- "./spec/services/groups/transfer_service_spec.rb"
-- "./spec/services/integrations/test/project_service_spec.rb"
-- "./spec/services/issuable/destroy_service_spec.rb"
-- "./spec/services/issue_links/list_service_spec.rb"
-- "./spec/services/merge_requests/add_todo_when_build_fails_service_spec.rb"
-- "./spec/services/merge_requests/mergeability_check_service_spec.rb"
-- "./spec/services/merge_requests/post_merge_service_spec.rb"
-- "./spec/services/merge_requests/refresh_service_spec.rb"
-- "./spec/services/pages/migrate_from_legacy_storage_service_spec.rb"
- "./spec/services/projects/destroy_service_spec.rb"
+- "./spec/services/projects/overwrite_project_service_spec.rb"
- "./spec/services/projects/transfer_service_spec.rb"
-- "./spec/services/projects/update_service_spec.rb"
-- "./spec/services/releases/create_service_spec.rb"
- "./spec/services/resource_access_tokens/revoke_service_spec.rb"
-- "./spec/services/todo_service_spec.rb"
-- "./spec/services/users/activity_service_spec.rb"
- "./spec/services/users/destroy_service_spec.rb"
- "./spec/services/users/reject_service_spec.rb"
-- "./spec/support/shared_contexts/email_shared_context.rb"
-- "./spec/support/shared_examples/controllers/access_tokens_controller_shared_examples.rb"
-- "./spec/support/shared_examples/features/master_manages_access_requests_shared_example.rb"
-- "./spec/support/shared_examples/integrations/test_examples.rb"
-- "./spec/support/shared_examples/models/atomic_internal_id_shared_examples.rb"
-- "./spec/support/shared_examples/models/cluster_application_status_shared_examples.rb"
-- "./spec/support/shared_examples/models/cluster_application_version_shared_examples.rb"
-- "./spec/support/shared_examples/models/concerns/cron_schedulable_shared_examples.rb"
-- "./spec/support/shared_examples/models/concerns/limitable_shared_examples.rb"
-- "./spec/support/shared_examples/models/update_highest_role_shared_examples.rb"
-- "./spec/support/shared_examples/models/update_project_statistics_shared_examples.rb"
-- "./spec/support/shared_examples/models/with_uploads_shared_examples.rb"
-- "./spec/support/shared_examples/requests/api/status_shared_examples.rb"
-- "./spec/support/shared_examples/requests/lfs_http_shared_examples.rb"
-- "./spec/support/shared_examples/services/destroy_label_links_shared_examples.rb"
-- "./spec/support/shared_examples/services/issuable/destroy_service_shared_examples.rb"
-- "./spec/support/shared_examples/services/notification_service_shared_examples.rb"
-- "./spec/support/shared_examples/services/wiki_pages/create_service_shared_examples.rb"
-- "./spec/support/shared_examples/services/wiki_pages/destroy_service_shared_examples.rb"
-- "./spec/support/shared_examples/services/wiki_pages/update_service_shared_examples.rb"
-- "./spec/support/shared_examples/workers/idempotency_shared_examples.rb"
-- "./spec/views/projects/artifacts/_artifact.html.haml_spec.rb"
-- "./spec/views/projects/commits/_commit.html.haml_spec.rb"
-- "./spec/views/projects/jobs/_build.html.haml_spec.rb"
-- "./spec/views/projects/jobs/_generic_commit_status.html.haml_spec.rb"
-- "./spec/views/projects/merge_requests/creations/_new_submit.html.haml_spec.rb"
-- "./spec/views/projects/pipeline_schedules/_pipeline_schedule.html.haml_spec.rb"
-- "./spec/views/shared/runners/_runner_details.html.haml_spec.rb"
-- "./spec/workers/authorized_project_update/user_refresh_from_replica_worker_spec.rb"
-- "./spec/workers/ci/pipeline_artifacts/create_quality_report_worker_spec.rb"
-- "./spec/workers/container_expiration_policy_worker_spec.rb"
- "./spec/workers/merge_requests/create_pipeline_worker_spec.rb"
-- "./spec/workers/pipeline_metrics_worker_spec.rb"
-- "./spec/workers/pipeline_schedule_worker_spec.rb"
-- "./spec/workers/releases/create_evidence_worker_spec.rb"
- "./spec/workers/remove_expired_members_worker_spec.rb"
- "./spec/workers/repository_cleanup_worker_spec.rb"
-- "./spec/workers/stage_update_worker_spec.rb"
-- "./spec/workers/stuck_merge_jobs_worker_spec.rb"
-- "./ee/spec/requests/api/graphql/project/pipelines/dast_profile_spec.rb"
-- "./spec/services/projects/overwrite_project_service_spec.rb"
diff --git a/spec/support/database/cross-join-allowlist.yml b/spec/support/database/cross-join-allowlist.yml
index c209d275fc8..19b1ce30d5f 100644
--- a/spec/support/database/cross-join-allowlist.yml
+++ b/spec/support/database/cross-join-allowlist.yml
@@ -1,58 +1,6 @@
-- "./ee/spec/features/ci/ci_minutes_spec.rb"
-- "./ee/spec/features/merge_trains/two_merge_requests_on_train_spec.rb"
-- "./ee/spec/features/merge_trains/user_adds_merge_request_to_merge_train_spec.rb"
-- "./ee/spec/finders/ee/namespaces/projects_finder_spec.rb"
-- "./ee/spec/graphql/ee/resolvers/namespace_projects_resolver_spec.rb"
-- "./ee/spec/models/ci/minutes/project_monthly_usage_spec.rb"
-- "./ee/spec/models/project_spec.rb"
-- "./ee/spec/models/security/finding_spec.rb"
-- "./ee/spec/models/security/scan_spec.rb"
-- "./ee/spec/requests/api/ci/minutes_spec.rb"
-- "./ee/spec/requests/api/graphql/ci/minutes/usage_spec.rb"
-- "./ee/spec/requests/api/namespaces_spec.rb"
-- "./ee/spec/services/ci/minutes/additional_packs/change_namespace_service_spec.rb"
-- "./ee/spec/services/ci/minutes/additional_packs/create_service_spec.rb"
-- "./ee/spec/services/ci/minutes/refresh_cached_data_service_spec.rb"
-- "./spec/controllers/admin/runners_controller_spec.rb"
-- "./spec/controllers/groups/settings/ci_cd_controller_spec.rb"
-- "./spec/controllers/projects/settings/ci_cd_controller_spec.rb"
-- "./spec/features/admin/admin_runners_spec.rb"
-- "./spec/features/ide/user_opens_merge_request_spec.rb"
-- "./spec/features/merge_request/user_sees_merge_request_pipelines_spec.rb"
-- "./spec/features/projects/infrastructure_registry_spec.rb"
-- "./spec/finders/ci/pipelines_for_merge_request_finder_spec.rb"
-- "./spec/finders/ci/runners_finder_spec.rb"
-- "./spec/frontend/fixtures/runner.rb"
-- "./spec/graphql/resolvers/ci/group_runners_resolver_spec.rb"
-- "./spec/lib/api/entities/package_spec.rb"
- "./spec/lib/gitlab/background_migration/copy_ci_builds_columns_to_security_scans_spec.rb"
- "./spec/lib/gitlab/background_migration/migrate_pages_metadata_spec.rb"
- "./spec/migrations/20210907211557_finalize_ci_builds_bigint_conversion_spec.rb"
- "./spec/migrations/associate_existing_dast_builds_with_variables_spec.rb"
+- "./spec/migrations/disable_job_token_scope_when_unused_spec.rb"
- "./spec/migrations/schedule_copy_ci_builds_columns_to_security_scans2_spec.rb"
-- "./spec/migrations/schedule_pages_metadata_migration_spec.rb"
-- "./spec/models/ci/pipeline_spec.rb"
-- "./spec/models/ci/runner_spec.rb"
-- "./spec/models/merge_request_spec.rb"
-- "./spec/models/project_spec.rb"
-- "./spec/models/user_spec.rb"
-- "./spec/presenters/packages/detail/package_presenter_spec.rb"
-- "./spec/requests/api/ci/runner/runners_post_spec.rb"
-- "./spec/requests/api/ci/runners_spec.rb"
-- "./spec/requests/api/graphql/ci/runner_spec.rb"
-- "./spec/requests/api/graphql/group_query_spec.rb"
-- "./spec/requests/api/graphql/packages/composer_spec.rb"
-- "./spec/requests/api/graphql/packages/conan_spec.rb"
-- "./spec/requests/api/graphql/packages/maven_spec.rb"
-- "./spec/requests/api/graphql/packages/nuget_spec.rb"
-- "./spec/requests/api/graphql/packages/package_spec.rb"
-- "./spec/requests/api/graphql/packages/pypi_spec.rb"
-- "./spec/requests/api/package_files_spec.rb"
-- "./spec/services/environments/stop_service_spec.rb"
-- "./spec/services/merge_requests/post_merge_service_spec.rb"
-- "./spec/support/shared_examples/features/packages_shared_examples.rb"
-- "./spec/support/shared_examples/models/concerns/limitable_shared_examples.rb"
-- "./spec/support/shared_examples/requests/api/graphql/packages/group_and_project_packages_list_shared_examples.rb"
-- "./spec/support/shared_examples/requests/api/graphql/packages/package_details_shared_examples.rb"
-- "./spec/support/shared_examples/requests/graphql_shared_examples.rb"
-- "./spec/support/shared_examples/services/packages_shared_examples.rb"
diff --git a/spec/support/database/gitlab_schema.rb b/spec/support/database/gitlab_schema.rb
deleted file mode 100644
index fe05fb998e6..00000000000
--- a/spec/support/database/gitlab_schema.rb
+++ /dev/null
@@ -1,25 +0,0 @@
-# frozen_string_literal: true
-
-# This module gathes information about table to schema mapping
-# to understand table affinity
-module Database
- module GitlabSchema
- def self.table_schemas(tables)
- tables.map { |table| table_schema(table) }.to_set
- end
-
- def self.table_schema(name)
- tables_to_schema[name] || :undefined
- end
-
- def self.tables_to_schema
- @tables_to_schema ||= all_classes_with_schema.to_h do |klass|
- [klass.table_name, klass.gitlab_schema]
- end
- end
-
- def self.all_classes_with_schema
- ActiveRecord::Base.descendants.reject(&:abstract_class?).select(&:gitlab_schema?) # rubocop:disable Database/MultipleDatabases
- end
- end
-end
diff --git a/spec/support/database/multiple_databases.rb b/spec/support/database/multiple_databases.rb
index 5e1ae60536f..9e72ea589e3 100644
--- a/spec/support/database/multiple_databases.rb
+++ b/spec/support/database/multiple_databases.rb
@@ -6,6 +6,18 @@ module Database
skip 'Skipping because multiple databases not set up' unless Gitlab::Database.has_config?(:ci)
end
+ def reconfigure_db_connection(name: nil, config_hash: {}, model: ActiveRecord::Base, config_model: nil)
+ db_config = (config_model || model).connection_db_config
+
+ new_db_config = ActiveRecord::DatabaseConfigurations::HashConfig.new(
+ db_config.env_name,
+ name ? name.to_s : db_config.name,
+ db_config.configuration_hash.merge(config_hash)
+ )
+
+ model.establish_connection(new_db_config)
+ end
+
# The usage of this method switches temporarily used `connection_handler`
# allowing full manipulation of ActiveRecord::Base connections without
# having side effects like:
@@ -56,6 +68,21 @@ RSpec.configure do |config|
example.run
end
end
+
+ config.around(:each, :mocked_ci_connection) do |example|
+ with_reestablished_active_record_base(reconnect: true) do
+ reconfigure_db_connection(
+ name: :ci,
+ model: Ci::ApplicationRecord,
+ config_model: ActiveRecord::Base
+ )
+
+ example.run
+
+ # Cleanup connection_specification_name for Ci::ApplicationRecord
+ Ci::ApplicationRecord.remove_connection
+ end
+ end
end
ActiveRecord::Base.singleton_class.prepend(::Database::ActiveRecordBaseEstablishConnection) # rubocop:disable Database/MultipleDatabases
diff --git a/spec/support/database/prevent_cross_database_modification.rb b/spec/support/database/prevent_cross_database_modification.rb
index 7ded85b65ce..c509aecf9b8 100644
--- a/spec/support/database/prevent_cross_database_modification.rb
+++ b/spec/support/database/prevent_cross_database_modification.rb
@@ -1,123 +1,31 @@
# frozen_string_literal: true
-module Database
- module PreventCrossDatabaseModification
- CrossDatabaseModificationAcrossUnsupportedTablesError = Class.new(StandardError)
-
- module GitlabDatabaseMixin
- def allow_cross_database_modification_within_transaction(url:)
- cross_database_context = Database::PreventCrossDatabaseModification.cross_database_context
- return yield unless cross_database_context && cross_database_context[:enabled]
-
- transaction_tracker_enabled_was = cross_database_context[:enabled]
- cross_database_context[:enabled] = false
-
- yield
- ensure
- cross_database_context[:enabled] = transaction_tracker_enabled_was if cross_database_context
- end
- end
-
- module SpecHelpers
- def with_cross_database_modification_prevented
- subscriber = ActiveSupport::Notifications.subscribe('sql.active_record') do |name, start, finish, id, payload|
- PreventCrossDatabaseModification.prevent_cross_database_modification!(payload[:connection], payload[:sql])
- end
-
- PreventCrossDatabaseModification.reset_cross_database_context!
- PreventCrossDatabaseModification.cross_database_context.merge!(enabled: true, subscriber: subscriber)
-
- yield if block_given?
- ensure
- cleanup_with_cross_database_modification_prevented if block_given?
- end
-
- def cleanup_with_cross_database_modification_prevented
- if PreventCrossDatabaseModification.cross_database_context
- ActiveSupport::Notifications.unsubscribe(PreventCrossDatabaseModification.cross_database_context[:subscriber])
- PreventCrossDatabaseModification.cross_database_context[:enabled] = false
- end
- end
- end
-
- def self.cross_database_context
- Thread.current[:transaction_tracker]
- end
-
- def self.reset_cross_database_context!
- Thread.current[:transaction_tracker] = initial_data
- end
-
- def self.initial_data
- {
- enabled: false,
- transaction_depth_by_db: Hash.new { |h, k| h[k] = 0 },
- modified_tables_by_db: Hash.new { |h, k| h[k] = Set.new }
- }
- end
-
- def self.prevent_cross_database_modification!(connection, sql)
- return unless cross_database_context
- return unless cross_database_context[:enabled]
-
- return if connection.pool.instance_of?(ActiveRecord::ConnectionAdapters::NullPool)
-
- database = connection.pool.db_config.name
-
- if sql.start_with?('SAVEPOINT')
- cross_database_context[:transaction_depth_by_db][database] += 1
-
- return
- elsif sql.start_with?('RELEASE SAVEPOINT', 'ROLLBACK TO SAVEPOINT')
- cross_database_context[:transaction_depth_by_db][database] -= 1
- if cross_database_context[:transaction_depth_by_db][database] <= 0
- cross_database_context[:modified_tables_by_db][database].clear
- end
-
- return
- end
-
- return if cross_database_context[:transaction_depth_by_db].values.all?(&:zero?)
-
- # PgQuery might fail in some cases due to limited nesting:
- # https://github.com/pganalyze/pg_query/issues/209
- parsed_query = PgQuery.parse(sql)
- tables = sql.downcase.include?(' for update') ? parsed_query.tables : parsed_query.dml_tables
-
- return if tables.empty?
-
- cross_database_context[:modified_tables_by_db][database].merge(tables)
-
- all_tables = cross_database_context[:modified_tables_by_db].values.map(&:to_a).flatten
- schemas = Database::GitlabSchema.table_schemas(all_tables)
-
- if schemas.many?
- raise Database::PreventCrossDatabaseModification::CrossDatabaseModificationAcrossUnsupportedTablesError,
- "Cross-database data modification of '#{schemas.to_a.join(", ")}' were detected within " \
- "a transaction modifying the '#{all_tables.to_a.join(", ")}' tables." \
- "Please refer to https://docs.gitlab.com/ee/development/database/multiple_databases.html#removing-cross-database-transactions for details on how to resolve this exception."
- end
- end
- end
+module PreventCrossDatabaseModificationSpecHelpers
+ delegate :with_cross_database_modification_prevented,
+ :allow_cross_database_modification_within_transaction,
+ to: :'::Gitlab::Database::QueryAnalyzers::PreventCrossDatabaseModification'
end
-Gitlab::Database.singleton_class.prepend(
- Database::PreventCrossDatabaseModification::GitlabDatabaseMixin)
-
CROSS_DB_MODIFICATION_ALLOW_LIST = Set.new(YAML.load_file(File.join(__dir__, 'cross-database-modification-allowlist.yml'))).freeze
RSpec.configure do |config|
- config.include(::Database::PreventCrossDatabaseModification::SpecHelpers)
+ config.include(PreventCrossDatabaseModificationSpecHelpers)
+
+ # By default allow cross-modifications as we want to observe only transactions
+ # within a specific block of execution which is defined be `before(:each)` and `after(:each)`
+ config.before(:all) do
+ ::Gitlab::Database::QueryAnalyzers::PreventCrossDatabaseModification.suppress = true
+ end
# Using before and after blocks because the around block causes problems with the let_it_be
# record creations. It makes an extra savepoint which breaks the transaction count logic.
config.before do |example_file|
- if CROSS_DB_MODIFICATION_ALLOW_LIST.exclude?(example_file.file_path)
- with_cross_database_modification_prevented
- end
+ ::Gitlab::Database::QueryAnalyzers::PreventCrossDatabaseModification.suppress =
+ CROSS_DB_MODIFICATION_ALLOW_LIST.include?(example_file.file_path_rerun_argument)
end
+ # Reset after execution to preferred state
config.after do |example_file|
- cleanup_with_cross_database_modification_prevented
+ ::Gitlab::Database::QueryAnalyzers::PreventCrossDatabaseModification.suppress = true
end
end
diff --git a/spec/support/database/prevent_cross_joins.rb b/spec/support/database/prevent_cross_joins.rb
index f5ed2a8f22e..e69374fbc70 100644
--- a/spec/support/database/prevent_cross_joins.rb
+++ b/spec/support/database/prevent_cross_joins.rb
@@ -35,7 +35,7 @@ module Database
# https://github.com/pganalyze/pg_query/issues/209
tables = PgQuery.parse(sql).tables
- schemas = Database::GitlabSchema.table_schemas(tables)
+ schemas = ::Gitlab::Database::GitlabSchema.table_schemas(tables)
if schemas.include?(:gitlab_ci) && schemas.include?(:gitlab_main)
Thread.current[:has_cross_join_exception] = true
@@ -96,7 +96,7 @@ RSpec.configure do |config|
config.around do |example|
Thread.current[:has_cross_join_exception] = false
- if ALLOW_LIST.include?(example.file_path)
+ if ALLOW_LIST.include?(example.file_path_rerun_argument)
example.run
else
with_cross_joins_prevented { example.run }
diff --git a/spec/support/database/query_analyzer.rb b/spec/support/database/query_analyzer.rb
new file mode 100644
index 00000000000..85fa55f81ef
--- /dev/null
+++ b/spec/support/database/query_analyzer.rb
@@ -0,0 +1,14 @@
+# frozen_string_literal: true
+
+# With the usage of `describe '...', query_analyzers: false`
+# can be disabled selectively
+
+RSpec.configure do |config|
+ config.around do |example|
+ if example.metadata.fetch(:query_analyzers, true)
+ ::Gitlab::Database::QueryAnalyzer.instance.within { example.run }
+ else
+ example.run
+ end
+ end
+end
diff --git a/spec/support/database_load_balancing.rb b/spec/support/database_load_balancing.rb
index 014575e8a82..d2902ddcc7c 100644
--- a/spec/support/database_load_balancing.rb
+++ b/spec/support/database_load_balancing.rb
@@ -2,17 +2,17 @@
RSpec.configure do |config|
config.around(:each, :database_replica) do |example|
- old_proxies = []
+ old_proxies = {}
Gitlab::Database::LoadBalancing.base_models.each do |model|
+ old_proxies[model] = [model.load_balancer, model.connection, model.sticking]
+
config = Gitlab::Database::LoadBalancing::Configuration
.new(model, [model.connection_db_config.configuration_hash[:host]])
- lb = Gitlab::Database::LoadBalancing::LoadBalancer.new(config)
-
- old_proxies << [model, model.connection]
- model.connection =
- Gitlab::Database::LoadBalancing::ConnectionProxy.new(lb)
+ model.load_balancer = Gitlab::Database::LoadBalancing::LoadBalancer.new(config)
+ model.sticking = Gitlab::Database::LoadBalancing::Sticking.new(model.load_balancer)
+ model.connection = Gitlab::Database::LoadBalancing::ConnectionProxy.new(model.load_balancer)
end
Gitlab::Database::LoadBalancing::Session.clear_session
@@ -23,8 +23,8 @@ RSpec.configure do |config|
Gitlab::Database::LoadBalancing::Session.clear_session
redis_shared_state_cleanup!
- old_proxies.each do |(model, proxy)|
- model.connection = proxy
+ old_proxies.each do |model, proxy|
+ model.load_balancer, model.connection, model.sticking = proxy
end
end
end
diff --git a/spec/support/flaky_tests.rb b/spec/support/flaky_tests.rb
new file mode 100644
index 00000000000..30a064d8705
--- /dev/null
+++ b/spec/support/flaky_tests.rb
@@ -0,0 +1,36 @@
+# frozen_string_literal: true
+
+return unless ENV['CI']
+return unless ENV['SKIP_FLAKY_TESTS_AUTOMATICALLY'] == "true"
+return if ENV['CI_MERGE_REQUEST_LABELS'].to_s.include?('pipeline:run-flaky-tests')
+
+require_relative '../../tooling/rspec_flaky/report'
+
+RSpec.configure do |config|
+ $flaky_test_example_ids = begin # rubocop:disable Style/GlobalVars
+ raise "$SUITE_FLAKY_RSPEC_REPORT_PATH is empty." if ENV['SUITE_FLAKY_RSPEC_REPORT_PATH'].to_s.empty?
+ raise "#{ENV['SUITE_FLAKY_RSPEC_REPORT_PATH']} doesn't exist" unless File.exist?(ENV['SUITE_FLAKY_RSPEC_REPORT_PATH'])
+
+ RspecFlaky::Report.load(ENV['SUITE_FLAKY_RSPEC_REPORT_PATH']).map { |_, flaky_test_data| flaky_test_data["example_id"] }
+ rescue => e # rubocop:disable Style/RescueStandardError
+ puts e
+ []
+ end
+ $skipped_flaky_tests_report = [] # rubocop:disable Style/GlobalVars
+
+ config.around do |example|
+ # Skip flaky tests automatically
+ if $flaky_test_example_ids.include?(example.id) # rubocop:disable Style/GlobalVars
+ puts "Skipping #{example.id} '#{example.full_description}' because it's flaky."
+ $skipped_flaky_tests_report << example.id # rubocop:disable Style/GlobalVars
+ else
+ example.run
+ end
+ end
+
+ config.after(:suite) do
+ next unless ENV['SKIPPED_FLAKY_TESTS_REPORT_PATH']
+
+ File.write(ENV['SKIPPED_FLAKY_TESTS_REPORT_PATH'], "#{$skipped_flaky_tests_report.join("\n")}\n") # rubocop:disable Style/GlobalVars
+ end
+end
diff --git a/spec/support/gitlab/usage/metrics_instrumentation_shared_examples.rb b/spec/support/gitlab/usage/metrics_instrumentation_shared_examples.rb
index de9735df546..4624a8ac82a 100644
--- a/spec/support/gitlab/usage/metrics_instrumentation_shared_examples.rb
+++ b/spec/support/gitlab/usage/metrics_instrumentation_shared_examples.rb
@@ -6,7 +6,9 @@ RSpec.shared_examples 'a correct instrumented metric value' do |params|
let(:metric) { described_class.new(time_frame: time_frame, options: options) }
before do
- allow(ActiveRecord::Base.connection).to receive(:transaction_open?).and_return(false)
+ if described_class.respond_to?(:relation) && described_class.relation.respond_to?(:connection)
+ allow(described_class.relation.connection).to receive(:transaction_open?).and_return(false)
+ end
end
it 'has correct value' do
diff --git a/spec/support/graphql/fake_query_type.rb b/spec/support/graphql/fake_query_type.rb
new file mode 100644
index 00000000000..ffd851a6e6a
--- /dev/null
+++ b/spec/support/graphql/fake_query_type.rb
@@ -0,0 +1,15 @@
+# frozen_string_literal: true
+
+module Graphql
+ class FakeQueryType < Types::BaseObject
+ graphql_name 'FakeQuery'
+
+ field :hello_world, String, null: true do
+ argument :message, String, required: false
+ end
+
+ def hello_world(message: "world")
+ "Hello #{message}!"
+ end
+ end
+end
diff --git a/spec/support/graphql/fake_tracer.rb b/spec/support/graphql/fake_tracer.rb
new file mode 100644
index 00000000000..c2fb7ed12d8
--- /dev/null
+++ b/spec/support/graphql/fake_tracer.rb
@@ -0,0 +1,15 @@
+# frozen_string_literal: true
+
+module Graphql
+ class FakeTracer
+ def initialize(trace_callback)
+ @trace_callback = trace_callback
+ end
+
+ def trace(*args)
+ @trace_callback.call(*args)
+
+ yield
+ end
+ end
+end
diff --git a/spec/support/helpers/cycle_analytics_helpers.rb b/spec/support/helpers/cycle_analytics_helpers.rb
index 3ec52f8c832..722d484609c 100644
--- a/spec/support/helpers/cycle_analytics_helpers.rb
+++ b/spec/support/helpers/cycle_analytics_helpers.rb
@@ -63,6 +63,10 @@ module CycleAnalyticsHelpers
wait_for_requests
end
+ def click_save_value_stream_button
+ click_button(_('Save value stream'))
+ end
+
def create_custom_value_stream(custom_value_stream_name)
toggle_value_stream_dropdown
page.find_button(_('Create new Value Stream')).click
diff --git a/spec/support/helpers/features/invite_members_modal_helper.rb b/spec/support/helpers/features/invite_members_modal_helper.rb
index 69ba20c1ca4..3502558b2c2 100644
--- a/spec/support/helpers/features/invite_members_modal_helper.rb
+++ b/spec/support/helpers/features/invite_members_modal_helper.rb
@@ -8,7 +8,7 @@ module Spec
def invite_member(name, role: 'Guest', expires_at: nil, area_of_focus: false)
click_on 'Invite members'
- page.within '#invite-members-modal' do
+ page.within '[data-testid="invite-members-modal"]' do
find('[data-testid="members-token-select-input"]').set(name)
wait_for_requests
diff --git a/spec/support/helpers/gitaly_setup.rb b/spec/support/helpers/gitaly_setup.rb
index 5cfd03ecea8..8a329c2f9dd 100644
--- a/spec/support/helpers/gitaly_setup.rb
+++ b/spec/support/helpers/gitaly_setup.rb
@@ -98,7 +98,7 @@ module GitalySetup
end
def build_gitaly
- system(env, 'make', chdir: tmp_tests_gitaly_dir) # rubocop:disable GitlabSecurity/SystemCommandInjection
+ system(env.merge({ 'GIT_VERSION' => nil }), 'make all git', chdir: tmp_tests_gitaly_dir) # rubocop:disable GitlabSecurity/SystemCommandInjection
end
def start_gitaly
diff --git a/spec/support/helpers/gpg_helpers.rb b/spec/support/helpers/gpg_helpers.rb
index 813c6176317..81e669aab57 100644
--- a/spec/support/helpers/gpg_helpers.rb
+++ b/spec/support/helpers/gpg_helpers.rb
@@ -4,6 +4,7 @@ module GpgHelpers
SIGNED_COMMIT_SHA = '8a852d50dda17cc8fd1408d2fd0c5b0f24c76ca4'
SIGNED_AND_AUTHORED_SHA = '3c1d9a0266cb0c62d926f4a6c649beed561846f5'
DIFFERING_EMAIL_SHA = 'a17a9f66543673edf0a3d1c6b93bdda3fe600f32'
+ MULTIPLE_SIGNATURES_SHA = 'c7794c14268d67ad8a2d5f066d706539afc75a96'
module User1
extend self
diff --git a/spec/support/helpers/graphql_helpers.rb b/spec/support/helpers/graphql_helpers.rb
index 6f17d3cb496..ee4621deb2d 100644
--- a/spec/support/helpers/graphql_helpers.rb
+++ b/spec/support/helpers/graphql_helpers.rb
@@ -522,8 +522,7 @@ module GraphqlHelpers
end
end
- # See note at graphql_data about memoization and multiple requests
- def graphql_errors(body = json_response)
+ def graphql_errors(body = fresh_response_data)
case body
when Hash # regular query
body['errors']
diff --git a/spec/support/helpers/migrations_helpers.rb b/spec/support/helpers/migrations_helpers.rb
index 7799e49d4c1..0c5bf09f6b7 100644
--- a/spec/support/helpers/migrations_helpers.rb
+++ b/spec/support/helpers/migrations_helpers.rb
@@ -2,7 +2,7 @@
module MigrationsHelpers
def active_record_base
- ActiveRecord::Base
+ Gitlab::Database.database_base_models.fetch(self.class.metadata[:database] || :main)
end
def table(name)
@@ -34,7 +34,7 @@ module MigrationsHelpers
end
def migrations_paths
- ActiveRecord::Migrator.migrations_paths
+ active_record_base.connection.migrations_paths
end
def migration_context
@@ -52,7 +52,7 @@ module MigrationsHelpers
end
def foreign_key_exists?(source, target = nil, column: nil)
- ActiveRecord::Base.connection.foreign_keys(source).any? do |key|
+ active_record_base.connection.foreign_keys(source).any? do |key|
if column
key.options[:column].to_s == column.to_s
else
diff --git a/spec/support/helpers/navbar_structure_helper.rb b/spec/support/helpers/navbar_structure_helper.rb
index 96e79427278..c2ec82155cd 100644
--- a/spec/support/helpers/navbar_structure_helper.rb
+++ b/spec/support/helpers/navbar_structure_helper.rb
@@ -29,6 +29,19 @@ module NavbarStructureHelper
)
end
+ def insert_customer_relations_nav(within)
+ insert_after_nav_item(
+ within,
+ new_nav_item: {
+ nav_item: _('Customer relations'),
+ nav_sub_items: [
+ _('Contacts'),
+ _('Organizations')
+ ]
+ }
+ )
+ end
+
def insert_container_nav
insert_after_sub_nav_item(
_('Package Registry'),
diff --git a/spec/support/helpers/project_forks_helper.rb b/spec/support/helpers/project_forks_helper.rb
index 4b4285f251e..84b5dbc1d23 100644
--- a/spec/support/helpers/project_forks_helper.rb
+++ b/spec/support/helpers/project_forks_helper.rb
@@ -28,11 +28,15 @@ module ProjectForksHelper
unless params[:target_project] || params[:using_service]
target_level = [project.visibility_level, namespace.visibility_level].min
visibility_level = Gitlab::VisibilityLevel.closest_allowed_level(target_level)
+ # Builds and MRs can't have higher visibility level than repository access level.
+ builds_access_level = [project.builds_access_level, project.repository_access_level].min
params[:target_project] =
create(:project,
(:repository if create_repository),
- visibility_level: visibility_level, creator: user, namespace: namespace)
+ visibility_level: visibility_level,
+ builds_access_level: builds_access_level,
+ creator: user, namespace: namespace)
end
service = Projects::ForkService.new(project, user, params)
diff --git a/spec/support/helpers/require_migration.rb b/spec/support/helpers/require_migration.rb
index de3a8a81ab5..ee28f8e504c 100644
--- a/spec/support/helpers/require_migration.rb
+++ b/spec/support/helpers/require_migration.rb
@@ -15,7 +15,7 @@ class RequireMigration
end
MIGRATION_FOLDERS = %w[db/migrate db/post_migrate].freeze
- SPEC_FILE_PATTERN = %r{.+/(?<file_name>.+)_spec\.rb}.freeze
+ SPEC_FILE_PATTERN = %r{.+/(?:\d+_)?(?<file_name>.+)_spec\.rb}.freeze
class << self
def require_migration!(file_name)
@@ -26,10 +26,12 @@ class RequireMigration
end
def search_migration_file(file_name)
+ migration_file_pattern = /\A\d+_#{file_name}\.rb\z/
+
migration_folders.flat_map do |path|
migration_path = Rails.root.join(path).to_s
- Find.find(migration_path).select { |m| File.basename(m).match? /\A\d+_#{file_name}\.rb\z/ }
+ Find.find(migration_path).select { |m| migration_file_pattern.match? File.basename(m) }
end
end
diff --git a/spec/support/helpers/stub_gitlab_calls.rb b/spec/support/helpers/stub_gitlab_calls.rb
index 6f530d57caf..ef3c39c83c2 100644
--- a/spec/support/helpers/stub_gitlab_calls.rb
+++ b/spec/support/helpers/stub_gitlab_calls.rb
@@ -92,9 +92,16 @@ module StubGitlabCalls
end
def stub_commonmark_sourcepos_disabled
+ render_options =
+ if Feature.enabled?(:use_cmark_renderer)
+ Banzai::Filter::MarkdownEngines::CommonMark::RENDER_OPTIONS_C
+ else
+ Banzai::Filter::MarkdownEngines::CommonMark::RENDER_OPTIONS_RUBY
+ end
+
allow_any_instance_of(Banzai::Filter::MarkdownEngines::CommonMark)
.to receive(:render_options)
- .and_return(Banzai::Filter::MarkdownEngines::CommonMark::RENDER_OPTIONS)
+ .and_return(render_options)
end
private
diff --git a/spec/support/helpers/stub_object_storage.rb b/spec/support/helpers/stub_object_storage.rb
index 56177d445d6..5e86b08aa45 100644
--- a/spec/support/helpers/stub_object_storage.rb
+++ b/spec/support/helpers/stub_object_storage.rb
@@ -4,7 +4,6 @@ module StubObjectStorage
def stub_dependency_proxy_object_storage(**params)
stub_object_storage_uploader(config: ::Gitlab.config.dependency_proxy.object_store,
uploader: ::DependencyProxy::FileUploader,
- remote_directory: 'dependency_proxy',
**params)
end
@@ -16,7 +15,6 @@ module StubObjectStorage
def stub_object_storage_uploader(
config:,
uploader:,
- remote_directory:,
enabled: true,
proxy_download: false,
background_upload: false,
@@ -40,7 +38,7 @@ module StubObjectStorage
return unless enabled
stub_object_storage(connection_params: uploader.object_store_credentials,
- remote_directory: remote_directory)
+ remote_directory: config.remote_directory)
end
def stub_object_storage(connection_params:, remote_directory:)
@@ -60,56 +58,48 @@ module StubObjectStorage
def stub_artifacts_object_storage(uploader = JobArtifactUploader, **params)
stub_object_storage_uploader(config: Gitlab.config.artifacts.object_store,
uploader: uploader,
- remote_directory: 'artifacts',
**params)
end
def stub_external_diffs_object_storage(uploader = described_class, **params)
stub_object_storage_uploader(config: Gitlab.config.external_diffs.object_store,
uploader: uploader,
- remote_directory: 'external-diffs',
**params)
end
def stub_lfs_object_storage(**params)
stub_object_storage_uploader(config: Gitlab.config.lfs.object_store,
uploader: LfsObjectUploader,
- remote_directory: 'lfs-objects',
**params)
end
def stub_package_file_object_storage(**params)
stub_object_storage_uploader(config: Gitlab.config.packages.object_store,
uploader: ::Packages::PackageFileUploader,
- remote_directory: 'packages',
**params)
end
def stub_composer_cache_object_storage(**params)
stub_object_storage_uploader(config: Gitlab.config.packages.object_store,
uploader: ::Packages::Composer::CacheUploader,
- remote_directory: 'packages',
**params)
end
def stub_uploads_object_storage(uploader = described_class, **params)
stub_object_storage_uploader(config: Gitlab.config.uploads.object_store,
uploader: uploader,
- remote_directory: 'uploads',
**params)
end
def stub_terraform_state_object_storage(**params)
stub_object_storage_uploader(config: Gitlab.config.terraform_state.object_store,
uploader: Terraform::StateUploader,
- remote_directory: 'terraform',
**params)
end
def stub_pages_object_storage(uploader = described_class, **params)
stub_object_storage_uploader(config: Gitlab.config.pages.object_store,
uploader: uploader,
- remote_directory: 'pages',
**params)
end
diff --git a/spec/support/helpers/test_env.rb b/spec/support/helpers/test_env.rb
index badd4e8212c..acbc15f7b62 100644
--- a/spec/support/helpers/test_env.rb
+++ b/spec/support/helpers/test_env.rb
@@ -9,7 +9,7 @@ module TestEnv
# When developing the seed repository, comment out the branch you will modify.
BRANCH_SHA = {
- 'signed-commits' => '6101e87',
+ 'signed-commits' => 'c7794c1',
'not-merged-branch' => 'b83d6e3',
'branch-merged' => '498214d',
'empty-branch' => '7efb185',
@@ -53,7 +53,7 @@ module TestEnv
'wip' => 'b9238ee',
'csv' => '3dd0896',
'v1.1.0' => 'b83d6e3',
- 'add-ipython-files' => 'f6b7a70',
+ 'add-ipython-files' => '2b5ef814',
'add-pdf-file' => 'e774ebd',
'squash-large-files' => '54cec52',
'add-pdf-text-binary' => '79faa7b',
diff --git a/spec/support/helpers/usage_data_helpers.rb b/spec/support/helpers/usage_data_helpers.rb
index 5ead1813439..5865bafd382 100644
--- a/spec/support/helpers/usage_data_helpers.rb
+++ b/spec/support/helpers/usage_data_helpers.rb
@@ -162,6 +162,8 @@ module UsageDataHelpers
def stub_usage_data_connections
allow(ActiveRecord::Base.connection).to receive(:transaction_open?).and_return(false)
+ allow(::Ci::ApplicationRecord.connection).to receive(:transaction_open?).and_return(false) if ::Ci::ApplicationRecord.connection_class?
+
allow(Gitlab::Prometheus::Internal).to receive(:prometheus_enabled?).and_return(false)
end
diff --git a/spec/support/helpers/workhorse_helpers.rb b/spec/support/helpers/workhorse_helpers.rb
index cd8387de686..83bda6e03b1 100644
--- a/spec/support/helpers/workhorse_helpers.rb
+++ b/spec/support/helpers/workhorse_helpers.rb
@@ -24,7 +24,12 @@ module WorkhorseHelpers
# workhorse_post_with_file will transform file_key inside params as if it was disk accelerated by workhorse
def workhorse_post_with_file(url, file_key:, params:)
- workhorse_request_with_file(:post, url,
+ workhorse_form_with_file(url, method: :post, file_key: file_key, params: params)
+ end
+
+ # workhorse_form_with_file will transform file_key inside params as if it was disk accelerated by workhorse
+ def workhorse_form_with_file(url, file_key:, params:, method: :post)
+ workhorse_request_with_file(method, url,
file_key: file_key,
params: params,
env: { 'CONTENT_TYPE' => 'multipart/form-data' },
diff --git a/spec/support/matchers/access_matchers.rb b/spec/support/matchers/access_matchers.rb
index acf5fb0944f..1b460fbdbf7 100644
--- a/spec/support/matchers/access_matchers.rb
+++ b/spec/support/matchers/access_matchers.rb
@@ -52,7 +52,7 @@ module AccessMatchers
emulate_user(user, @membership)
visit(url)
- status_code == 200 && !current_path.in?([new_user_session_path, new_admin_session_path])
+ [200, 204].include?(status_code) && !current_path.in?([new_user_session_path, new_admin_session_path])
end
chain :of do |membership|
diff --git a/spec/support/matchers/project_namespace_matcher.rb b/spec/support/matchers/project_namespace_matcher.rb
new file mode 100644
index 00000000000..95aa5429679
--- /dev/null
+++ b/spec/support/matchers/project_namespace_matcher.rb
@@ -0,0 +1,28 @@
+# frozen_string_literal: true
+
+RSpec::Matchers.define :be_in_sync_with_project do |project|
+ match do |project_namespace|
+ # if project is not persisted make sure we do not have a persisted project_namespace for it
+ break false if project.new_record? && project_namespace&.persisted?
+ # don't really care if project is not in sync if the project was never persisted.
+ break true if project.new_record? && !project_namespace.present?
+
+ project_namespace.present? &&
+ project.name == project_namespace.name &&
+ project.path == project_namespace.path &&
+ project.namespace == project_namespace.parent &&
+ project.visibility_level == project_namespace.visibility_level &&
+ project.shared_runners_enabled == project_namespace.shared_runners_enabled
+ end
+
+ failure_message_when_negated do |project_namespace|
+ if project.new_record? && project_namespace&.persisted?
+ "expected that a non persisted project #{project} does not have a persisted project namespace #{project_namespace}"
+ else
+ <<-MSG
+ expected that the project's attributes name, path, namespace_id, visibility_level, shared_runners_enabled
+ are in sync with the corresponding project namespace attributes
+ MSG
+ end
+ end
+end
diff --git a/spec/support/patches/rspec_example_prepended_methods.rb b/spec/support/patches/rspec_example_prepended_methods.rb
new file mode 100644
index 00000000000..ea918b1e08f
--- /dev/null
+++ b/spec/support/patches/rspec_example_prepended_methods.rb
@@ -0,0 +1,26 @@
+# frozen_string_literal: true
+
+module RSpec
+ module Core
+ module ExamplePrependedMethods
+ # Based on https://github.com/rspec/rspec-core/blob/d57c371ee92b16211b80ac7b0b025968438f5297/lib/rspec/core/example.rb#L96-L104,
+ # Same as location_rerun_argument but with line number
+ def file_path_rerun_argument
+ loaded_spec_files = RSpec.configuration.loaded_spec_files
+
+ RSpec::Core::Metadata.ascending(metadata) do |meta|
+ break meta[:file_path] if loaded_spec_files.include?(meta[:absolute_file_path])
+ end
+ end
+ end
+
+ module ExampleProcsyPrependedMethods
+ def file_path_rerun_argument
+ example.file_path_rerun_argument
+ end
+ end
+ end
+end
+
+RSpec::Core::Example.prepend(RSpec::Core::ExamplePrependedMethods)
+RSpec::Core::Example::Procsy.prepend(RSpec::Core::ExampleProcsyPrependedMethods)
diff --git a/spec/support/redis/redis_shared_examples.rb b/spec/support/redis/redis_shared_examples.rb
index dd916aea3e8..72b3a72f9d4 100644
--- a/spec/support/redis/redis_shared_examples.rb
+++ b/spec/support/redis/redis_shared_examples.rb
@@ -87,6 +87,43 @@ RSpec.shared_examples "redis_shared_examples" do
end
end
+ describe '.store' do
+ let(:rails_env) { 'development' }
+
+ subject { described_class.new(rails_env).store }
+
+ shared_examples 'redis store' do
+ it 'instantiates Redis::Store' do
+ is_expected.to be_a(::Redis::Store)
+ expect(subject.to_s).to eq("Redis Client connected to #{host} against DB #{redis_database}")
+ end
+
+ context 'with the namespace' do
+ let(:namespace) { 'namespace_name' }
+
+ subject { described_class.new(rails_env).store(namespace: namespace) }
+
+ it "uses specified namespace" do
+ expect(subject.to_s).to eq("Redis Client connected to #{host} against DB #{redis_database} with namespace #{namespace}")
+ end
+ end
+ end
+
+ context 'with old format' do
+ it_behaves_like 'redis store' do
+ let(:config_file_name) { config_old_format_host }
+ let(:host) { "localhost:#{redis_port}" }
+ end
+ end
+
+ context 'with new format' do
+ it_behaves_like 'redis store' do
+ let(:config_file_name) { config_new_format_host }
+ let(:host) { "development-host:#{redis_port}" }
+ end
+ end
+ end
+
describe '.params' do
subject { described_class.new(rails_env).params }
diff --git a/spec/support/retriable.rb b/spec/support/retriable.rb
new file mode 100644
index 00000000000..be4c2d62752
--- /dev/null
+++ b/spec/support/retriable.rb
@@ -0,0 +1,7 @@
+# frozen_string_literal: true
+
+Retriable.configure do |config|
+ config.multiplier = 1.0
+ config.rand_factor = 0.0
+ config.base_interval = 0
+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
index 645ea742f07..9ac3d4a04f9 100644
--- a/spec/support/shared_contexts/graphql/requests/packages_shared_context.rb
+++ b/spec/support/shared_contexts/graphql/requests/packages_shared_context.rb
@@ -10,6 +10,7 @@ RSpec.shared_context 'package details setup' do
let(:excluded) { %w[metadata apiFuzzingCiConfiguration pipeline packageFiles] }
let(:package_files) { all_graphql_fields_for('PackageFile') }
let(:dependency_links) { all_graphql_fields_for('PackageDependencyLink') }
+ let(:pipelines) { all_graphql_fields_for('Pipeline', max_depth: 1) }
let(:user) { project.owner }
let(:package_details) { graphql_data_at(:package) }
let(:metadata_response) { graphql_data_at(:package, :metadata) }
@@ -34,6 +35,11 @@ RSpec.shared_context 'package details setup' do
#{dependency_links}
}
}
+ pipelines {
+ nodes {
+ #{pipelines}
+ }
+ }
FIELDS
end
end
diff --git a/spec/support/shared_contexts/lib/gitlab/database/background_migration_job_shared_context.rb b/spec/support/shared_contexts/lib/gitlab/database/background_migration_job_shared_context.rb
deleted file mode 100644
index 382eb796f8e..00000000000
--- a/spec/support/shared_contexts/lib/gitlab/database/background_migration_job_shared_context.rb
+++ /dev/null
@@ -1,21 +0,0 @@
-# frozen_string_literal: true
-
-RSpec.shared_context 'background migration job class' do
- let!(:job_class_name) { 'TestJob' }
- let!(:job_class) { Class.new }
- let!(:job_perform_method) do
- ->(*arguments) do
- Gitlab::Database::BackgroundMigrationJob.mark_all_as_succeeded(
- # Value is 'TestJob' defined by :job_class_name in the let! above.
- # Scoping prohibits us from directly referencing job_class_name.
- RSpec.current_example.example_group_instance.job_class_name,
- arguments
- )
- end
- end
-
- before do
- job_class.define_method(:perform, job_perform_method)
- expect(Gitlab::BackgroundMigration).to receive(:migration_class_for).with(job_class_name).at_least(:once) { job_class }
- end
-end
diff --git a/spec/support/shared_contexts/navbar_structure_context.rb b/spec/support/shared_contexts/navbar_structure_context.rb
index 2abc52fce85..bcc6abdc308 100644
--- a/spec/support/shared_contexts/navbar_structure_context.rb
+++ b/spec/support/shared_contexts/navbar_structure_context.rb
@@ -119,7 +119,7 @@ RSpec.shared_context 'project navbar structure' do
_('Repository'),
_('CI/CD'),
_('Monitor'),
- (s_('UsageQuota|Usage Quotas') if Feature.enabled?(:project_storage_ui, default_enabled: :yaml))
+ s_('UsageQuota|Usage Quotas')
]
}
].compact
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 d7e4864cb08..8a90f887381 100644
--- a/spec/support/shared_contexts/policies/project_policy_shared_context.rb
+++ b/spec/support/shared_contexts/policies/project_policy_shared_context.rb
@@ -15,7 +15,7 @@ RSpec.shared_context 'ProjectPolicy context' do
let(:base_guest_permissions) do
%i[
- award_emoji create_issue create_incident create_merge_request_in create_note
+ award_emoji create_issue create_merge_request_in create_note
create_project read_issue_board read_issue read_issue_iid read_issue_link
read_label read_issue_board_list read_milestone read_note read_project
read_project_for_iids read_project_member read_release read_snippet
@@ -25,10 +25,11 @@ 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
- 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
+ admin_issue admin_issue_link admin_label admin_issue_board_list
+ create_snippet create_incident 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
read_sentry_issue update_issue
]
diff --git a/spec/support/shared_contexts/requests/api/debian_repository_shared_context.rb b/spec/support/shared_contexts/requests/api/debian_repository_shared_context.rb
new file mode 100644
index 00000000000..95b8b7ed9f8
--- /dev/null
+++ b/spec/support/shared_contexts/requests/api/debian_repository_shared_context.rb
@@ -0,0 +1,120 @@
+# frozen_string_literal: true
+
+RSpec.shared_context 'Debian repository shared context' do |container_type, can_freeze|
+ include_context 'workhorse headers'
+
+ before do
+ stub_feature_flags(debian_packages: true, debian_group_packages: true)
+ end
+
+ let_it_be(:private_container, freeze: can_freeze) { create(container_type, :private) }
+ let_it_be(:public_container, freeze: can_freeze) { create(container_type, :public) }
+ let_it_be(:user, freeze: true) { create(:user) }
+ let_it_be(:personal_access_token, freeze: true) { create(:personal_access_token, user: user) }
+
+ let_it_be(:private_distribution, freeze: true) { create("debian_#{container_type}_distribution", :with_file, container: private_container, codename: 'existing-codename') }
+ let_it_be(:private_distribution_key, freeze: true) { create("debian_#{container_type}_distribution_key", distribution: private_distribution) }
+ 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(:private_component_file) { create("debian_#{container_type}_component_file", component: private_component, architecture: private_architecture) }
+
+ let_it_be(:public_distribution, freeze: true) { create("debian_#{container_type}_distribution", :with_file, container: public_container, codename: 'existing-codename') }
+ let_it_be(:public_distribution_key, freeze: true) { create("debian_#{container_type}_distribution_key", distribution: public_distribution) }
+ 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') }
+ let_it_be(:public_component_file) { create("debian_#{container_type}_component_file", component: public_component, architecture: public_architecture) }
+
+ 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') }
+
+ let(:project) { { private: private_project, public: public_project }[visibility_level] }
+ 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(:architecture) { { private: private_architecture, public: public_architecture }[visibility_level] }
+ let(:component) { { private: private_component, public: public_component }[visibility_level] }
+ let(:component_file) { { private: private_component_file, public: public_component_file }[visibility_level] }
+ let(:package) { { private: private_package, public: public_package }[visibility_level] }
+ let(:letter) { package.name[0..2] == 'lib' ? package.name[0..3] : package.name[0] }
+
+ let(:method) { :get }
+
+ let(:workhorse_params) do
+ if method == :put
+ file_upload = fixture_file_upload("spec/fixtures/packages/debian/#{file_name}")
+ { file: file_upload }
+ else
+ {}
+ end
+ end
+
+ let(:api_params) { workhorse_params }
+
+ let(:auth_headers) { {} }
+ let(:wh_headers) do
+ if method == :put
+ workhorse_headers
+ else
+ {}
+ end
+ end
+
+ let(:headers) { auth_headers.merge(wh_headers) }
+
+ let(:send_rewritten_field) { true }
+
+ subject do
+ if method == :put
+ workhorse_finalize(
+ api(url),
+ method: method,
+ file_key: :file,
+ params: api_params,
+ headers: headers,
+ send_rewritten_field: send_rewritten_field
+ )
+ else
+ send method, api(url), headers: headers, params: api_params
+ end
+ end
+end
+
+RSpec.shared_context 'Debian repository auth headers' do |user_type, auth_method = :private_token|
+ let(:token) { user_type == :invalid_token ? 'wrong' : personal_access_token.token }
+
+ let(:auth_headers) do
+ if user_type == :anonymous
+ {}
+ elsif auth_method == :private_token
+ { 'Private-Token' => token }
+ else
+ basic_auth_header(user.username, token)
+ end
+ end
+end
+
+RSpec.shared_context 'Debian repository access' do |visibility_level, user_type, auth_method|
+ include_context 'Debian repository auth headers', user_type, auth_method do
+ let(:containers) { { private: private_container, public: public_container } }
+ let(:container) { containers[visibility_level] }
+
+ before do
+ container.send("add_#{user_type}", user) if user_type != :anonymous && user_type != :not_a_member && user_type != :invalid_token
+ end
+ end
+end
diff --git a/spec/support/shared_contexts/services/projects/container_repository/delete_tags_service_shared_context.rb b/spec/support/shared_contexts/services/projects/container_repository/delete_tags_service_shared_context.rb
index 80f011f622b..21be989d697 100644
--- a/spec/support/shared_contexts/services/projects/container_repository/delete_tags_service_shared_context.rb
+++ b/spec/support/shared_contexts/services/projects/container_repository/delete_tags_service_shared_context.rb
@@ -31,14 +31,14 @@ RSpec.shared_context 'container repository delete tags service shared context' d
end
end
- def stub_put_manifest_request(tag, status = 200, headers = { 'docker-content-digest' => 'sha256:dummy' })
+ def stub_put_manifest_request(tag, status = 200, headers = { DependencyProxy::Manifest::DIGEST_HEADER => 'sha256:dummy' })
stub_request(:put, "http://registry.gitlab/v2/#{repository.path}/manifests/#{tag}")
.to_return(status: status, body: '', headers: headers)
end
def stub_tag_digest(tag, digest)
stub_request(:head, "http://registry.gitlab/v2/#{repository.path}/manifests/#{tag}")
- .to_return(status: 200, body: '', headers: { 'docker-content-digest' => digest })
+ .to_return(status: 200, body: '', headers: { DependencyProxy::Manifest::DIGEST_HEADER => digest })
end
def stub_digest_config(digest, created_at)
diff --git a/spec/support/shared_contexts/services/service_ping/stubbed_service_ping_metrics_definitions_shared_context.rb b/spec/support/shared_contexts/services/service_ping/stubbed_service_ping_metrics_definitions_shared_context.rb
index 2b810e790f0..e1d864213b5 100644
--- a/spec/support/shared_contexts/services/service_ping/stubbed_service_ping_metrics_definitions_shared_context.rb
+++ b/spec/support/shared_contexts/services/service_ping/stubbed_service_ping_metrics_definitions_shared_context.rb
@@ -38,6 +38,11 @@ RSpec.shared_context 'stubbed service ping metrics definitions' do
)
end
+ after do |example|
+ Gitlab::Usage::Metric.instance_variable_set(:@all, nil)
+ Gitlab::Usage::MetricDefinition.instance_variable_set(:@all, nil)
+ end
+
def metric_attributes(key_path, category, value_type = 'string')
{
'key_path' => key_path,
diff --git a/spec/support/shared_contexts/url_shared_context.rb b/spec/support/shared_contexts/url_shared_context.rb
index f3d227b6e2b..da1d6e0049c 100644
--- a/spec/support/shared_contexts/url_shared_context.rb
+++ b/spec/support/shared_contexts/url_shared_context.rb
@@ -1,19 +1,32 @@
# frozen_string_literal: true
+RSpec.shared_context 'valid urls with CRLF' do
+ let(:valid_urls_with_CRLF) do
+ [
+ "http://example.com/pa%0dth",
+ "http://example.com/pa%0ath",
+ "http://example.com/pa%0d%0th",
+ "http://example.com/pa%0D%0Ath",
+ "http://gitlab.com/path?param=foo%0Abar",
+ "https://gitlab.com/path?param=foo%0Dbar",
+ "http://example.org:1024/path?param=foo%0D%0Abar",
+ "https://storage.googleapis.com/bucket/import_export_upload/import_file/57265/express.tar.gz?GoogleAccessId=hello@example.org&Signature=ABCD%0AEFGHik&Expires=1634663304"
+ ]
+ end
+end
+
RSpec.shared_context 'invalid urls' do
let(:urls_with_CRLF) do
- ["http://127.0.0.1:333/pa\rth",
- "http://127.0.0.1:333/pa\nth",
- "http://127.0a.0.1:333/pa\r\nth",
- "http://127.0.0.1:333/path?param=foo\r\nbar",
- "http://127.0.0.1:333/path?param=foo\rbar",
- "http://127.0.0.1:333/path?param=foo\nbar",
- "http://127.0.0.1:333/pa%0dth",
- "http://127.0.0.1:333/pa%0ath",
- "http://127.0a.0.1:333/pa%0d%0th",
- "http://127.0.0.1:333/pa%0D%0Ath",
- "http://127.0.0.1:333/path?param=foo%0Abar",
- "http://127.0.0.1:333/path?param=foo%0Dbar",
- "http://127.0.0.1:333/path?param=foo%0D%0Abar"]
+ [
+ "git://example.com/pa%0dth",
+ "git://example.com/pa%0ath",
+ "git://example.com/pa%0d%0th",
+ "http://example.com/pa\rth",
+ "http://example.com/pa\nth",
+ "http://example.com/pa\r\nth",
+ "http://example.com/path?param=foo\r\nbar",
+ "http://example.com/path?param=foo\rbar",
+ "http://example.com/path?param=foo\nbar"
+ ]
end
end
diff --git a/spec/support/shared_examples/bulk_imports/common/pipelines/wiki_pipeline_examples.rb b/spec/support/shared_examples/bulk_imports/common/pipelines/wiki_pipeline_examples.rb
new file mode 100644
index 00000000000..e8cc666605b
--- /dev/null
+++ b/spec/support/shared_examples/bulk_imports/common/pipelines/wiki_pipeline_examples.rb
@@ -0,0 +1,31 @@
+# frozen_string_literal: true
+
+RSpec.shared_examples 'wiki pipeline imports a wiki for an entity' do
+ describe '#run' do
+ let_it_be(:bulk_import_configuration) { create(:bulk_import_configuration, bulk_import: bulk_import) }
+
+ let_it_be(:tracker) { create(:bulk_import_tracker, entity: entity) }
+ let_it_be(:context) { BulkImports::Pipeline::Context.new(tracker) }
+
+ let(:extracted_data) { BulkImports::Pipeline::ExtractedData.new(data: {}) }
+
+ context 'successfully imports wiki for an entity' do
+ subject { described_class.new(context) }
+
+ before do
+ allow_next_instance_of(BulkImports::Common::Extractors::GraphqlExtractor) do |extractor|
+ allow(extractor).to receive(:extract).and_return(extracted_data)
+ end
+ end
+
+ it 'imports new wiki into destination project' do
+ expect_next_instance_of(Gitlab::GitalyClient::RepositoryService) do |repository_service|
+ url = "https://oauth2:token@gitlab.example/#{entity.source_full_path}.wiki.git"
+ expect(repository_service).to receive(:fetch_remote).with(url, any_args).and_return 0
+ end
+
+ subject.run
+ end
+ end
+ end
+end
diff --git a/spec/support/shared_examples/controllers/concerns/integrations_actions_shared_examples.rb b/spec/support/shared_examples/controllers/concerns/integrations/integrations_actions_shared_examples.rb
index 748a3acf17b..a8aed0c1f0b 100644
--- a/spec/support/shared_examples/controllers/concerns/integrations_actions_shared_examples.rb
+++ b/spec/support/shared_examples/controllers/concerns/integrations/integrations_actions_shared_examples.rb
@@ -1,6 +1,6 @@
# frozen_string_literal: true
-RSpec.shared_examples IntegrationsActions do
+RSpec.shared_examples Integrations::Actions do
let(:integration) do
create(:datadog_integration,
integration_attributes.merge(
diff --git a/spec/support/shared_examples/controllers/create_notes_rate_limit_shared_examples.rb b/spec/support/shared_examples/controllers/create_notes_rate_limit_shared_examples.rb
index 74a98c20383..8affe4ac8f5 100644
--- a/spec/support/shared_examples/controllers/create_notes_rate_limit_shared_examples.rb
+++ b/spec/support/shared_examples/controllers/create_notes_rate_limit_shared_examples.rb
@@ -6,39 +6,41 @@
# - request_full_path
RSpec.shared_examples 'request exceeding rate limit' do
- before do
- stub_application_setting(notes_create_limit: 2)
- 2.times { post :create, params: params }
- end
+ context 'with rate limiter', :freeze_time, :clean_gitlab_redis_rate_limiting do
+ before do
+ stub_application_setting(notes_create_limit: 2)
+ 2.times { post :create, params: params }
+ end
- it 'prevents from creating more notes', :request_store do
- expect { post :create, params: params }
- .to change { Note.count }.by(0)
+ it 'prevents from creating more notes' do
+ expect { post :create, params: params }
+ .to change { Note.count }.by(0)
- expect(response).to have_gitlab_http_status(:too_many_requests)
- expect(response.body).to eq(_('This endpoint has been requested too many times. Try again later.'))
- end
+ expect(response).to have_gitlab_http_status(:too_many_requests)
+ expect(response.body).to eq(_('This endpoint has been requested too many times. Try again later.'))
+ end
- it 'logs the event in auth.log' do
- attributes = {
- message: 'Application_Rate_Limiter_Request',
- env: :notes_create_request_limit,
- remote_ip: '0.0.0.0',
- request_method: 'POST',
- path: request_full_path,
- user_id: user.id,
- username: user.username
- }
+ it 'logs the event in auth.log' do
+ attributes = {
+ message: 'Application_Rate_Limiter_Request',
+ env: :notes_create_request_limit,
+ remote_ip: '0.0.0.0',
+ request_method: 'POST',
+ path: request_full_path,
+ user_id: user.id,
+ username: user.username
+ }
- expect(Gitlab::AuthLogger).to receive(:error).with(attributes).once
- post :create, params: params
- end
+ expect(Gitlab::AuthLogger).to receive(:error).with(attributes).once
+ post :create, params: params
+ end
- it 'allows user in allow-list to create notes, even if the case is different' do
- user.update_attribute(:username, user.username.titleize)
- stub_application_setting(notes_create_limit_allowlist: ["#{user.username.downcase}"])
+ it 'allows user in allow-list to create notes, even if the case is different' do
+ user.update_attribute(:username, user.username.titleize)
+ stub_application_setting(notes_create_limit_allowlist: ["#{user.username.downcase}"])
- post :create, params: params
- expect(response).to have_gitlab_http_status(:found)
+ post :create, params: params
+ expect(response).to have_gitlab_http_status(:found)
+ end
end
end
diff --git a/spec/support/shared_examples/features/2fa_shared_examples.rb b/spec/support/shared_examples/features/2fa_shared_examples.rb
index ddc03e178ba..94c91556ea7 100644
--- a/spec/support/shared_examples/features/2fa_shared_examples.rb
+++ b/spec/support/shared_examples/features/2fa_shared_examples.rb
@@ -18,6 +18,7 @@ RSpec.shared_examples 'hardware device for 2fa' do |device_type|
let(:user) { create(:user) }
before do
+ stub_feature_flags(bootstrap_confirmation_modals: false)
gitlab_sign_in(user)
user.update_attribute(:otp_required_for_login, true)
end
diff --git a/spec/support/shared_examples/features/dependency_proxy_shared_examples.rb b/spec/support/shared_examples/features/dependency_proxy_shared_examples.rb
index d29c677a962..5d1488502d2 100644
--- a/spec/support/shared_examples/features/dependency_proxy_shared_examples.rb
+++ b/spec/support/shared_examples/features/dependency_proxy_shared_examples.rb
@@ -26,7 +26,7 @@ RSpec.shared_examples 'a successful manifest pull' do
subject
expect(response).to have_gitlab_http_status(:ok)
- expect(response.headers['Docker-Content-Digest']).to eq(manifest.digest)
+ expect(response.headers[DependencyProxy::Manifest::DIGEST_HEADER]).to eq(manifest.digest)
expect(response.headers['Content-Length']).to eq(manifest.size)
expect(response.headers['Docker-Distribution-Api-Version']).to eq(DependencyProxy::DISTRIBUTION_API_VERSION)
expect(response.headers['Etag']).to eq("\"#{manifest.digest}\"")
diff --git a/spec/support/shared_examples/features/manage_applications_shared_examples.rb b/spec/support/shared_examples/features/manage_applications_shared_examples.rb
index 0161899cb76..27d50c67f24 100644
--- a/spec/support/shared_examples/features/manage_applications_shared_examples.rb
+++ b/spec/support/shared_examples/features/manage_applications_shared_examples.rb
@@ -18,6 +18,7 @@ RSpec.shared_examples 'manage applications' do
click_on 'Save application'
validate_application(application_name, 'Yes')
+ expect(page).to have_link('Continue', href: index_path)
application = Doorkeeper::Application.find_by(name: application_name)
expect(page).to have_css("button[title=\"Copy secret\"][data-clipboard-text=\"#{application.secret}\"]", text: 'Copy')
@@ -33,6 +34,7 @@ RSpec.shared_examples 'manage applications' do
click_on 'Save application'
validate_application(application_name_changed, 'No')
+ expect(page).not_to have_link('Continue')
visit_applications_path
diff --git a/spec/support/shared_examples/features/packages_shared_examples.rb b/spec/support/shared_examples/features/packages_shared_examples.rb
index 96be30b9f1f..d14b4638ca5 100644
--- a/spec/support/shared_examples/features/packages_shared_examples.rb
+++ b/spec/support/shared_examples/features/packages_shared_examples.rb
@@ -21,10 +21,6 @@ end
RSpec.shared_examples 'package details link' do |property|
let(:package) { packages.first }
- before do
- stub_feature_flags(packages_details_one_column: false)
- end
-
it 'navigates to the correct url' do
page.within(packages_table_selector) do
click_link package.name
@@ -32,7 +28,7 @@ RSpec.shared_examples 'package details link' do |property|
expect(page).to have_current_path(project_package_path(package.project, package))
- expect(page).to have_css('.packages-app h1[data-testid="title"]', text: package.name)
+ expect(page).to have_css('.packages-app h2[data-testid="title"]', text: package.name)
expect(page).to have_content('Installation')
expect(page).to have_content('Registry setup')
@@ -94,16 +90,24 @@ def packages_table_selector
end
def click_sort_option(option, ascending)
- page.within('.gl-sorting') do
- # Reset the sort direction
- click_button 'Sort direction' if page.has_selector?('svg[aria-label="Sorting Direction: Ascending"]', wait: 0)
+ wait_for_requests
- find('button.gl-dropdown-toggle').click
+ # Reset the sort direction
+ if page.has_selector?('button[aria-label="Sorting Direction: Ascending"]', wait: 0) && !ascending
+ click_button 'Sort direction'
- page.within('.dropdown-menu') do
- click_button option
- end
+ wait_for_requests
+ end
+
+ find('button.gl-dropdown-toggle').click
+
+ page.within('.dropdown-menu') do
+ click_button option
+ end
+
+ if ascending
+ wait_for_requests
- click_button 'Sort direction' if ascending
+ click_button 'Sort direction'
end
end
diff --git a/spec/support/shared_examples/features/resolving_discussions_in_issues_shared_examples.rb b/spec/support/shared_examples/features/resolving_discussions_in_issues_shared_examples.rb
index 6d44a6fde85..337b3f3cbd0 100644
--- a/spec/support/shared_examples/features/resolving_discussions_in_issues_shared_examples.rb
+++ b/spec/support/shared_examples/features/resolving_discussions_in_issues_shared_examples.rb
@@ -1,43 +1,29 @@
# frozen_string_literal: true
RSpec.shared_examples 'creating an issue for a thread' do
- it 'shows an issue with the title filled in' do
+ it 'shows an issue creation form' do
+ # Title field is filled in
title_field = page.find_field('issue[title]')
-
expect(title_field.value).to include(merge_request.title)
- end
- it 'has a mention of the discussion in the description' do
- description_field = page.find_field('issue[description]')
+ # Has a hidden field for the merge request
+ merge_request_field = find('#merge_request_to_resolve_discussions_of', visible: false)
+ expect(merge_request_field.value).to eq(merge_request.iid.to_s)
+ # Has a mention of the discussion in the description
+ description_field = page.find_field('issue[description]')
expect(description_field.value).to include(discussion.first_note.note)
end
- it 'can create a new issue for the project' do
+ it 'creates a new issue for the project' do
+ # Actually creates an issue for the project
expect { click_button 'Create issue' }.to change { project.issues.reload.size }.by(1)
- end
-
- it 'resolves the discussion in the merge request' do
- click_button 'Create issue'
+ # Resolves the discussion in the merge request
discussion.first_note.reload
-
expect(discussion.resolved?).to eq(true)
- end
-
- it 'shows a flash messaage after resolving a discussion' do
- click_button 'Create issue'
-
- page.within '.flash-notice' do
- # Only check for the word 'Resolved' since the spec might have resolved
- # multiple discussions
- expect(page).to have_content('Resolved')
- end
- end
-
- it 'has a hidden field for the merge request' do
- merge_request_field = find('#merge_request_to_resolve_discussions_of', visible: false)
- expect(merge_request_field.value).to eq(merge_request.iid.to_s)
+ # Issue title inludes MR title
+ expect(page).to have_content(%Q(Follow-up from "#{merge_request.title}"))
end
end
diff --git a/spec/support/shared_examples/features/sidebar_shared_examples.rb b/spec/support/shared_examples/features/sidebar_shared_examples.rb
index 5bfe929e957..d509d124de0 100644
--- a/spec/support/shared_examples/features/sidebar_shared_examples.rb
+++ b/spec/support/shared_examples/features/sidebar_shared_examples.rb
@@ -52,16 +52,17 @@ RSpec.shared_examples 'issue boards sidebar' do
it 'shows toggle as on then as off as user toggles to subscribe and unsubscribe', :aggregate_failures do
wait_for_requests
+ subscription_button = find('[data-testid="subscription-toggle"]')
- click_button 'Notifications'
+ subscription_button.click
- expect(page).to have_button('Notifications', class: 'is-checked')
+ expect(subscription_button).to have_css("button.is-checked")
- click_button 'Notifications'
+ subscription_button.click
wait_for_requests
- expect(page).not_to have_button('Notifications', class: 'is-checked')
+ expect(subscription_button).to have_css("button:not(.is-checked)")
end
context 'when notifications have been disabled' do
@@ -73,7 +74,7 @@ RSpec.shared_examples 'issue boards sidebar' do
it 'displays a message that notifications have been disabled' do
page.within('[data-testid="sidebar-notifications"]') do
- expect(page).to have_button('Notifications', class: 'is-disabled')
+ expect(page).to have_selector('[data-testid="subscription-toggle"]', class: 'is-disabled')
expect(page).to have_content('Disabled by project owner')
end
end
diff --git a/spec/support/shared_examples/graphql/notes_creation_shared_examples.rb b/spec/support/shared_examples/graphql/notes_creation_shared_examples.rb
index fb598b978f6..56b6dc682eb 100644
--- a/spec/support/shared_examples/graphql/notes_creation_shared_examples.rb
+++ b/spec/support/shared_examples/graphql/notes_creation_shared_examples.rb
@@ -66,20 +66,22 @@ RSpec.shared_examples 'a Note mutation when the given resource id is not for a N
end
RSpec.shared_examples 'a Note mutation when there are rate limit validation errors' do
- before do
- stub_application_setting(notes_create_limit: 3)
- 3.times { post_graphql_mutation(mutation, current_user: current_user) }
- end
-
- it_behaves_like 'a Note mutation that does not create a Note'
- it_behaves_like 'a mutation that returns top-level errors',
- errors: ['This endpoint has been requested too many times. Try again later.']
-
- context 'when the user is in the allowlist' do
+ context 'with rate limiter', :freeze_time, :clean_gitlab_redis_rate_limiting do
before do
- stub_application_setting(notes_create_limit_allowlist: ["#{current_user.username}"])
+ stub_application_setting(notes_create_limit: 3)
+ 3.times { post_graphql_mutation(mutation, current_user: current_user) }
end
- it_behaves_like 'a Note mutation that creates a Note'
+ it_behaves_like 'a Note mutation that does not create a Note'
+ it_behaves_like 'a mutation that returns top-level errors',
+ errors: ['This endpoint has been requested too many times. Try again later.']
+
+ context 'when the user is in the allowlist' do
+ before do
+ stub_application_setting(notes_create_limit_allowlist: ["#{current_user.username}"])
+ end
+
+ it_behaves_like 'a Note mutation that creates a Note'
+ 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 8b4ecd7d5ae..a3c67210a4a 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
@@ -35,8 +35,8 @@ RSpec.shared_examples 'common trace features' do
stub_feature_flags(gitlab_ci_archived_trace_consistent_reads: trace.job.project)
end
- it 'calls ::ApplicationRecord.sticking.unstick_or_continue_sticking' do
- expect(::ApplicationRecord.sticking).to receive(:unstick_or_continue_sticking)
+ it 'calls ::Ci::Build.sticking.unstick_or_continue_sticking' do
+ expect(::Ci::Build.sticking).to receive(:unstick_or_continue_sticking)
.with(described_class::LOAD_BALANCING_STICKING_NAMESPACE, trace.job.id)
.and_call_original
@@ -49,8 +49,8 @@ RSpec.shared_examples 'common trace features' do
stub_feature_flags(gitlab_ci_archived_trace_consistent_reads: false)
end
- it 'does not call ::ApplicationRecord.sticking.unstick_or_continue_sticking' do
- expect(::ApplicationRecord.sticking).not_to receive(:unstick_or_continue_sticking)
+ it 'does not call ::Ci::Build.sticking.unstick_or_continue_sticking' do
+ expect(::Ci::Build.sticking).not_to receive(:unstick_or_continue_sticking)
trace.read { |stream| stream }
end
@@ -305,8 +305,8 @@ RSpec.shared_examples 'common trace features' do
stub_feature_flags(gitlab_ci_archived_trace_consistent_reads: trace.job.project)
end
- it 'calls ::ApplicationRecord.sticking.stick' do
- expect(::ApplicationRecord.sticking).to receive(:stick)
+ it 'calls ::Ci::Build.sticking.stick' do
+ expect(::Ci::Build.sticking).to receive(:stick)
.with(described_class::LOAD_BALANCING_STICKING_NAMESPACE, trace.job.id)
.and_call_original
@@ -319,8 +319,8 @@ RSpec.shared_examples 'common trace features' do
stub_feature_flags(gitlab_ci_archived_trace_consistent_reads: false)
end
- it 'does not call ::ApplicationRecord.sticking.stick' do
- expect(::ApplicationRecord.sticking).not_to receive(:stick)
+ it 'does not call ::Ci::Build.sticking.stick' do
+ expect(::Ci::Build.sticking).not_to receive(:stick)
subject
end
@@ -808,7 +808,19 @@ RSpec.shared_examples 'trace with enabled live trace feature' do
create(:ci_job_artifact, :trace, job: build)
end
- it { is_expected.to be_truthy }
+ it 'is truthy' do
+ is_expected.to be_truthy
+ end
+ end
+
+ context 'when archived trace record exists but file is not stored' do
+ before do
+ create(:ci_job_artifact, :unarchived_trace_artifact, job: build)
+ end
+
+ it 'is falsy' do
+ is_expected.to be_falsy
+ end
end
context 'when live trace exists' do
@@ -872,13 +884,35 @@ RSpec.shared_examples 'trace with enabled live trace feature' do
build.reload
expect(build.trace.exist?).to be_truthy
- expect(build.job_artifacts_trace).to be_nil
Gitlab::Ci::Trace::ChunkedIO.new(build) do |stream|
expect(stream.read).to eq(trace_raw)
end
end
end
+ shared_examples 'a pre-commit error' do |error:|
+ it_behaves_like 'source trace in ChunkedIO stays intact', error: error
+
+ it 'does not save the trace artifact' do
+ expect { subject }.to raise_error(error)
+
+ build.reload
+ expect(build.job_artifacts_trace).to be_nil
+ end
+ end
+
+ shared_examples 'a post-commit error' do |error:|
+ it_behaves_like 'source trace in ChunkedIO stays intact', error: error
+
+ it 'saves the trace artifact but not the file' do
+ expect { subject }.to raise_error(error)
+
+ build.reload
+ expect(build.job_artifacts_trace).to be_present
+ expect(build.job_artifacts_trace.file.exists?).to be_falsy
+ end
+ end
+
context 'when job does not have trace artifact' do
context 'when trace is stored in ChunkedIO' do
let!(:build) { create(:ci_build, :success, :trace_live) }
@@ -892,7 +926,7 @@ RSpec.shared_examples 'trace with enabled live trace feature' do
allow(IO).to receive(:copy_stream).and_return(0)
end
- it_behaves_like 'source trace in ChunkedIO stays intact', error: Gitlab::Ci::Trace::ArchiveError
+ it_behaves_like 'a pre-commit error', error: Gitlab::Ci::Trace::ArchiveError
end
context 'when failed to create job artifact record' do
@@ -902,7 +936,16 @@ RSpec.shared_examples 'trace with enabled live trace feature' do
.and_return(%w[Error Error])
end
- it_behaves_like 'source trace in ChunkedIO stays intact', error: ActiveRecord::RecordInvalid
+ it_behaves_like 'a pre-commit error', error: ActiveRecord::RecordInvalid
+ end
+
+ context 'when storing the file raises an error' do
+ before do
+ stub_artifacts_object_storage(direct_upload: true)
+ allow_any_instance_of(Ci::JobArtifact).to receive(:store_file!).and_raise(Excon::Error::BadGateway, 'S3 is down lol')
+ end
+
+ it_behaves_like 'a post-commit error', error: Excon::Error::BadGateway
end
end
end
diff --git a/spec/support/shared_examples/lib/gitlab/cycle_analytics/deployment_metrics.rb b/spec/support/shared_examples/lib/gitlab/cycle_analytics/deployment_metrics.rb
index 6342064beb8..bea7cca2744 100644
--- a/spec/support/shared_examples/lib/gitlab/cycle_analytics/deployment_metrics.rb
+++ b/spec/support/shared_examples/lib/gitlab/cycle_analytics/deployment_metrics.rb
@@ -6,7 +6,7 @@ shared_examples 'deployment metrics examples' do
environment = project.environments.production.first || create(:environment, :production, project: project)
create(:deployment, :success, args.merge(environment: environment))
- # this is needed for the dora_deployment_frequency_in_vsa feature flag so we have aggregated data
+ # this is needed for the DORA API so we have aggregated data
::Dora::DailyMetrics::RefreshWorker.new.perform(environment.id, Time.current.to_date.to_s) if Gitlab.ee?
end
diff --git a/spec/support/shared_examples/lib/gitlab/database/cte_materialized_shared_examples.rb b/spec/support/shared_examples/lib/gitlab/database/cte_materialized_shared_examples.rb
index a617342ff8c..df795723874 100644
--- a/spec/support/shared_examples/lib/gitlab/database/cte_materialized_shared_examples.rb
+++ b/spec/support/shared_examples/lib/gitlab/database/cte_materialized_shared_examples.rb
@@ -11,7 +11,7 @@ RSpec.shared_examples 'CTE with MATERIALIZED keyword examples' do
context 'when PG version is <12' do
it 'does not add MATERIALIZE keyword' do
- allow(Gitlab::Database.main).to receive(:version).and_return('11.1')
+ allow(ApplicationRecord.database).to receive(:version).and_return('11.1')
expect(query).to include(expected_query_block_without_materialized)
end
@@ -19,14 +19,14 @@ RSpec.shared_examples 'CTE with MATERIALIZED keyword examples' do
context 'when PG version is >=12' do
it 'adds MATERIALIZE keyword' do
- allow(Gitlab::Database.main).to receive(:version).and_return('12.1')
+ allow(ApplicationRecord.database).to receive(:version).and_return('12.1')
expect(query).to include(expected_query_block_with_materialized)
end
context 'when version is higher than 12' do
it 'adds MATERIALIZE keyword' do
- allow(Gitlab::Database.main).to receive(:version).and_return('15.1')
+ allow(ApplicationRecord.database).to receive(:version).and_return('15.1')
expect(query).to include(expected_query_block_with_materialized)
end
diff --git a/spec/support/shared_examples/lib/gitlab/import_export/attributes_permitter_shared_examples.rb b/spec/support/shared_examples/lib/gitlab/import_export/attributes_permitter_shared_examples.rb
index 5ce698c4701..41d3d76b66b 100644
--- a/spec/support/shared_examples/lib/gitlab/import_export/attributes_permitter_shared_examples.rb
+++ b/spec/support/shared_examples/lib/gitlab/import_export/attributes_permitter_shared_examples.rb
@@ -1,5 +1,5 @@
# frozen_string_literal: true
-RSpec.shared_examples 'a permitted attribute' do |relation_sym, permitted_attributes|
+RSpec.shared_examples 'a permitted attribute' do |relation_sym, permitted_attributes, additional_attributes = []|
let(:prohibited_attributes) { %i[remote_url my_attributes my_ids token my_id test] }
let(:import_export_config) { Gitlab::ImportExport::Config.new.to_h }
@@ -26,7 +26,7 @@ RSpec.shared_examples 'a permitted attribute' do |relation_sym, permitted_attrib
end
it 'does not contain attributes that would be cleaned with AttributeCleaner' do
- expect(cleaned_hash.keys).to include(*permitted_hash.keys)
+ expect(cleaned_hash.keys + additional_attributes.to_a).to include(*permitted_hash.keys)
end
it 'does not contain prohibited attributes that are not related to given relation' do
diff --git a/spec/support/shared_examples/lib/gitlab/sidekiq_middleware/strategy_shared_examples.rb b/spec/support/shared_examples/lib/gitlab/sidekiq_middleware/strategy_shared_examples.rb
index 708bc71ae96..ff03051ed37 100644
--- a/spec/support/shared_examples/lib/gitlab/sidekiq_middleware/strategy_shared_examples.rb
+++ b/spec/support/shared_examples/lib/gitlab/sidekiq_middleware/strategy_shared_examples.rb
@@ -2,7 +2,7 @@
RSpec.shared_examples 'deduplicating jobs when scheduling' do |strategy_name|
let(:fake_duplicate_job) do
- instance_double(Gitlab::SidekiqMiddleware::DuplicateJobs::DuplicateJob)
+ instance_double(Gitlab::SidekiqMiddleware::DuplicateJobs::DuplicateJob, duplicate_key_ttl: Gitlab::SidekiqMiddleware::DuplicateJobs::DuplicateJob::DEFAULT_DUPLICATE_KEY_TTL)
end
let(:expected_message) { "dropped #{strategy_name.to_s.humanize.downcase}" }
@@ -11,14 +11,14 @@ RSpec.shared_examples 'deduplicating jobs when scheduling' do |strategy_name|
describe '#schedule' do
before do
- allow(Gitlab::SidekiqLogging::DeduplicationLogger.instance).to receive(:log)
+ allow(Gitlab::SidekiqLogging::DeduplicationLogger.instance).to receive(:deduplicated_log)
end
it 'checks for duplicates before yielding' do
expect(fake_duplicate_job).to receive(:scheduled?).twice.ordered.and_return(false)
expect(fake_duplicate_job).to(
receive(:check!)
- .with(Gitlab::SidekiqMiddleware::DuplicateJobs::DuplicateJob::DUPLICATE_KEY_TTL)
+ .with(fake_duplicate_job.duplicate_key_ttl)
.ordered
.and_return('a jid'))
expect(fake_duplicate_job).to receive(:duplicate?).ordered.and_return(false)
@@ -40,6 +40,7 @@ RSpec.shared_examples 'deduplicating jobs when scheduling' do |strategy_name|
allow(fake_duplicate_job).to receive(:check!).and_return('the jid')
allow(fake_duplicate_job).to receive(:idempotent?).and_return(true)
allow(fake_duplicate_job).to receive(:update_latest_wal_location!)
+ allow(fake_duplicate_job).to receive(:set_deduplicated_flag!)
allow(fake_duplicate_job).to receive(:options).and_return({})
job_hash = {}
@@ -61,10 +62,11 @@ RSpec.shared_examples 'deduplicating jobs when scheduling' do |strategy_name|
allow(fake_duplicate_job).to receive(:options).and_return({ including_scheduled: true })
allow(fake_duplicate_job).to(
receive(:check!)
- .with(Gitlab::SidekiqMiddleware::DuplicateJobs::DuplicateJob::DUPLICATE_KEY_TTL)
+ .with(fake_duplicate_job.duplicate_key_ttl)
.and_return('the jid'))
allow(fake_duplicate_job).to receive(:idempotent?).and_return(true)
allow(fake_duplicate_job).to receive(:update_latest_wal_location!)
+ allow(fake_duplicate_job).to receive(:set_deduplicated_flag!)
job_hash = {}
expect(fake_duplicate_job).to receive(:duplicate?).and_return(true)
@@ -83,9 +85,10 @@ RSpec.shared_examples 'deduplicating jobs when scheduling' do |strategy_name|
allow(fake_duplicate_job).to receive(:scheduled_at).and_return(Time.now + time_diff)
allow(fake_duplicate_job).to receive(:options).and_return({ including_scheduled: true })
allow(fake_duplicate_job).to(
- receive(:check!).with(time_diff.to_i).and_return('the jid'))
+ receive(:check!).with(time_diff.to_i + fake_duplicate_job.duplicate_key_ttl).and_return('the jid'))
allow(fake_duplicate_job).to receive(:idempotent?).and_return(true)
allow(fake_duplicate_job).to receive(:update_latest_wal_location!)
+ allow(fake_duplicate_job).to receive(:set_deduplicated_flag!)
job_hash = {}
expect(fake_duplicate_job).to receive(:duplicate?).and_return(true)
@@ -100,6 +103,26 @@ RSpec.shared_examples 'deduplicating jobs when scheduling' do |strategy_name|
end
end
+ context "when the job is not duplicate" do
+ before do
+ allow(fake_duplicate_job).to receive(:scheduled?).and_return(false)
+ allow(fake_duplicate_job).to receive(:check!).and_return('the jid')
+ allow(fake_duplicate_job).to receive(:duplicate?).and_return(false)
+ allow(fake_duplicate_job).to receive(:options).and_return({})
+ allow(fake_duplicate_job).to receive(:existing_jid).and_return('the jid')
+ end
+
+ it 'does not return false nor drop the job' do
+ schedule_result = nil
+
+ expect(fake_duplicate_job).not_to receive(:set_deduplicated_flag!)
+
+ expect { |b| schedule_result = strategy.schedule({}, &b) }.to yield_control
+
+ expect(schedule_result).to be_nil
+ end
+ end
+
context "when the job is droppable" do
before do
allow(fake_duplicate_job).to receive(:scheduled?).and_return(false)
@@ -109,6 +132,7 @@ RSpec.shared_examples 'deduplicating jobs when scheduling' do |strategy_name|
allow(fake_duplicate_job).to receive(:existing_jid).and_return('the jid')
allow(fake_duplicate_job).to receive(:idempotent?).and_return(true)
allow(fake_duplicate_job).to receive(:update_latest_wal_location!)
+ allow(fake_duplicate_job).to receive(:set_deduplicated_flag!)
end
it 'updates latest wal location' do
@@ -117,10 +141,11 @@ RSpec.shared_examples 'deduplicating jobs when scheduling' do |strategy_name|
strategy.schedule({ 'jid' => 'new jid' }) {}
end
- it 'drops the job' do
+ it 'returns false to drop the job' do
schedule_result = nil
expect(fake_duplicate_job).to receive(:idempotent?).and_return(true)
+ expect(fake_duplicate_job).to receive(:set_deduplicated_flag!).once
expect { |b| schedule_result = strategy.schedule({}, &b) }.not_to yield_control
expect(schedule_result).to be(false)
@@ -130,7 +155,7 @@ RSpec.shared_examples 'deduplicating jobs when scheduling' do |strategy_name|
fake_logger = instance_double(Gitlab::SidekiqLogging::DeduplicationLogger)
expect(Gitlab::SidekiqLogging::DeduplicationLogger).to receive(:instance).and_return(fake_logger)
- expect(fake_logger).to receive(:log).with(a_hash_including({ 'jid' => 'new jid' }), expected_message, {})
+ expect(fake_logger).to receive(:deduplicated_log).with(a_hash_including({ 'jid' => 'new jid' }), expected_message, {})
strategy.schedule({ 'jid' => 'new jid' }) {}
end
@@ -140,7 +165,7 @@ RSpec.shared_examples 'deduplicating jobs when scheduling' do |strategy_name|
expect(Gitlab::SidekiqLogging::DeduplicationLogger).to receive(:instance).and_return(fake_logger)
allow(fake_duplicate_job).to receive(:options).and_return({ foo: :bar })
- expect(fake_logger).to receive(:log).with(a_hash_including({ 'jid' => 'new jid' }), expected_message, { foo: :bar })
+ expect(fake_logger).to receive(:deduplicated_log).with(a_hash_including({ 'jid' => 'new jid' }), expected_message, { foo: :bar })
strategy.schedule({ 'jid' => 'new jid' }) {}
end
@@ -159,6 +184,9 @@ RSpec.shared_examples 'deduplicating jobs when scheduling' do |strategy_name|
before do
allow(fake_duplicate_job).to receive(:delete!)
+ allow(fake_duplicate_job).to receive(:scheduled?) { false }
+ allow(fake_duplicate_job).to receive(:options) { {} }
+ allow(fake_duplicate_job).to receive(:should_reschedule?) { false }
allow(fake_duplicate_job).to receive(:latest_wal_locations).and_return( wal_locations )
end
diff --git a/spec/support/shared_examples/lib/sidebars/projects/menus/zentao_menu_shared_examples.rb b/spec/support/shared_examples/lib/sidebars/projects/menus/zentao_menu_shared_examples.rb
new file mode 100644
index 00000000000..d3fd28727b5
--- /dev/null
+++ b/spec/support/shared_examples/lib/sidebars/projects/menus/zentao_menu_shared_examples.rb
@@ -0,0 +1,42 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.shared_examples 'ZenTao menu with CE version' do
+ let(:project) { create(:project, has_external_issue_tracker: true) }
+ let(:user) { project.owner }
+ let(:context) { Sidebars::Projects::Context.new(current_user: user, container: project) }
+ let(:zentao_integration) { create(:zentao_integration, project: project) }
+
+ subject { described_class.new(context) }
+
+ describe '#render?' do
+ context 'when issues integration is disabled' do
+ before do
+ zentao_integration.update!(active: false)
+ end
+
+ it 'returns false' do
+ expect(subject.render?).to eq false
+ end
+ end
+
+ context 'when issues integration is enabled' do
+ before do
+ zentao_integration.update!(active: true)
+ end
+
+ it 'returns true' do
+ expect(subject.render?).to eq true
+ end
+
+ it 'renders menu link' do
+ expect(subject.link).to eq zentao_integration.url
+ end
+
+ it 'contains only open ZenTao item' do
+ expect(subject.renderable_items.map(&:item_id)).to match_array [:open_zentao]
+ end
+ end
+ end
+end
diff --git a/spec/support/shared_examples/loose_foreign_keys/have_loose_foreign_key.rb b/spec/support/shared_examples/loose_foreign_keys/have_loose_foreign_key.rb
new file mode 100644
index 00000000000..7ccd9533811
--- /dev/null
+++ b/spec/support/shared_examples/loose_foreign_keys/have_loose_foreign_key.rb
@@ -0,0 +1,52 @@
+# frozen_string_literal: true
+
+RSpec.shared_examples 'it has loose foreign keys' do
+ let(:factory_name) { nil }
+ let(:table_name) { described_class.table_name }
+ let(:connection) { described_class.connection }
+
+ it 'includes the LooseForeignKey module' do
+ expect(described_class.ancestors).to include(LooseForeignKey)
+ end
+
+ it 'responds to #loose_foreign_key_definitions' do
+ expect(described_class).to respond_to(:loose_foreign_key_definitions)
+ end
+
+ it 'has at least one loose foreign key definition' do
+ expect(described_class.loose_foreign_key_definitions.size).to be > 0
+ end
+
+ it 'has the deletion trigger present' do
+ sql = <<-SQL
+ SELECT trigger_name
+ FROM information_schema.triggers
+ WHERE event_object_table = '#{table_name}'
+ SQL
+
+ triggers = connection.execute(sql)
+
+ expected_trigger_name = "#{table_name}_loose_fk_trigger"
+ expect(triggers.pluck('trigger_name')).to include(expected_trigger_name)
+ end
+
+ it 'records record deletions' do
+ model = create(factory_name) # rubocop: disable Rails/SaveBang
+ model.destroy!
+
+ deleted_record = LooseForeignKeys::DeletedRecord.find_by(fully_qualified_table_name: "#{connection.current_schema}.#{table_name}", primary_key_value: model.id)
+
+ expect(deleted_record).not_to be_nil
+ end
+
+ it 'cleans up record deletions' do
+ model = create(factory_name) # rubocop: disable Rails/SaveBang
+
+ expect { model.destroy! }.to change { LooseForeignKeys::DeletedRecord.count }.by(1)
+
+ LooseForeignKeys::ProcessDeletedRecordsService.new(connection: connection).execute
+
+ expect(LooseForeignKeys::DeletedRecord.status_pending.count).to be(0)
+ expect(LooseForeignKeys::DeletedRecord.status_processed.count).to be(1)
+ end
+end
diff --git a/spec/support/shared_examples/metrics/transaction_metrics_with_labels_shared_examples.rb b/spec/support/shared_examples/metrics/transaction_metrics_with_labels_shared_examples.rb
new file mode 100644
index 00000000000..286c60f1f4f
--- /dev/null
+++ b/spec/support/shared_examples/metrics/transaction_metrics_with_labels_shared_examples.rb
@@ -0,0 +1,219 @@
+# frozen_string_literal: true
+
+RSpec.shared_examples 'transaction metrics with labels' do
+ let(:sensitive_tags) do
+ {
+ path: 'private',
+ branch: 'sensitive'
+ }
+ end
+
+ around do |example|
+ described_class.reload_metric!
+ example.run
+ described_class.reload_metric!
+ end
+
+ describe '.prometheus_metric' do
+ let(:prometheus_metric) { instance_double(Prometheus::Client::Histogram, observe: nil, base_labels: {}) }
+
+ it 'adds a metric' do
+ expect(::Gitlab::Metrics).to receive(:histogram).with(
+ :meow_observe, 'Meow observe histogram', hash_including(*described_class::BASE_LABEL_KEYS), be_a(Array)
+ ).and_return(prometheus_metric)
+
+ expect do |block|
+ metric = described_class.prometheus_metric(:meow_observe, :histogram, &block)
+ expect(metric).to be(prometheus_metric)
+ end.to yield_control
+ end
+ end
+
+ describe '#method_call_for' do
+ it 'returns a MethodCall' do
+ method = transaction_obj.method_call_for('Foo#bar', :Foo, '#bar')
+
+ expect(method).to be_an_instance_of(Gitlab::Metrics::MethodCall)
+ end
+ end
+
+ describe '#add_event' do
+ let(:prometheus_metric) { instance_double(Prometheus::Client::Counter, increment: nil, base_labels: {}) }
+
+ it 'adds a metric' do
+ expect(prometheus_metric).to receive(:increment).with(labels)
+ expect(described_class).to receive(:fetch_metric).with(:counter, :gitlab_transaction_event_meow_total).and_return(prometheus_metric)
+
+ transaction_obj.add_event(:meow)
+ end
+
+ it 'allows tracking of custom tags' do
+ expect(prometheus_metric).to receive(:increment).with(labels.merge(animal: "dog"))
+ expect(described_class).to receive(:fetch_metric).with(:counter, :gitlab_transaction_event_bau_total).and_return(prometheus_metric)
+
+ transaction_obj.add_event(:bau, animal: 'dog')
+ end
+
+ context 'with sensitive tags' do
+ it 'filters tags' do
+ expect(described_class).to receive(:fetch_metric).with(:counter, :gitlab_transaction_event_bau_total).and_return(prometheus_metric)
+ expect(prometheus_metric).not_to receive(:increment).with(hash_including(sensitive_tags))
+
+ transaction_obj.add_event(:bau, **sensitive_tags.merge(sane: 'yes'))
+ end
+ end
+ end
+
+ describe '#increment' do
+ let(:prometheus_metric) { instance_double(Prometheus::Client::Counter, increment: nil, base_labels: {}) }
+
+ it 'adds a metric' do
+ expect(::Gitlab::Metrics).to receive(:counter).with(
+ :meow, 'Meow counter', hash_including(*described_class::BASE_LABEL_KEYS)
+ ).and_return(prometheus_metric)
+ expect(prometheus_metric).to receive(:increment).with(labels, 1)
+
+ transaction_obj.increment(:meow, 1)
+ end
+
+ context 'with block' do
+ it 'overrides docstring' do
+ expect(::Gitlab::Metrics).to receive(:counter).with(
+ :block_docstring, 'test', hash_including(*described_class::BASE_LABEL_KEYS)
+ ).and_return(prometheus_metric)
+ expect(prometheus_metric).to receive(:increment).with(labels, 1)
+
+ transaction_obj.increment(:block_docstring, 1) do
+ docstring 'test'
+ end
+ end
+
+ it 'overrides labels' do
+ expect(::Gitlab::Metrics).to receive(:counter).with(
+ :block_labels, 'Block labels counter', hash_including(*described_class::BASE_LABEL_KEYS)
+ ).and_return(prometheus_metric)
+ expect(prometheus_metric).to receive(:increment).with(labels.merge(sane: 'yes'), 1)
+
+ transaction_obj.increment(:block_labels, 1, sane: 'yes') do
+ label_keys %i(sane)
+ end
+ end
+
+ it 'filters sensitive tags' do
+ labels_keys = sensitive_tags.keys
+
+ expect(::Gitlab::Metrics).to receive(:counter).with(
+ :metric_with_sensitive_block, 'Metric with sensitive block counter', hash_excluding(labels_keys)
+ ).and_return(prometheus_metric)
+ expect(prometheus_metric).to receive(:increment).with(labels, 1)
+
+ transaction_obj.increment(:metric_with_sensitive_block, 1, sensitive_tags) do
+ label_keys labels_keys
+ end
+ end
+ end
+ end
+
+ describe '#set' do
+ let(:prometheus_metric) { instance_double(Prometheus::Client::Gauge, set: nil, base_labels: {}) }
+
+ it 'adds a metric' do
+ expect(::Gitlab::Metrics).to receive(:gauge).with(
+ :meow_set, 'Meow set gauge', hash_including(*described_class::BASE_LABEL_KEYS), :all
+ ).and_return(prometheus_metric)
+ expect(prometheus_metric).to receive(:set).with(labels, 99)
+
+ transaction_obj.set(:meow_set, 99)
+ end
+
+ context 'with block' do
+ it 'overrides docstring' do
+ expect(::Gitlab::Metrics).to receive(:gauge).with(
+ :block_docstring_set, 'test', hash_including(*described_class::BASE_LABEL_KEYS), :all
+ ).and_return(prometheus_metric)
+ expect(prometheus_metric).to receive(:set).with(labels, 99)
+
+ transaction_obj.set(:block_docstring_set, 99) do
+ docstring 'test'
+ end
+ end
+
+ it 'overrides labels' do
+ expect(::Gitlab::Metrics).to receive(:gauge).with(
+ :block_labels_set, 'Block labels set gauge', hash_including(*described_class::BASE_LABEL_KEYS), :all
+ ).and_return(prometheus_metric)
+ expect(prometheus_metric).to receive(:set).with(labels.merge(sane: 'yes'), 99)
+
+ transaction_obj.set(:block_labels_set, 99, sane: 'yes') do
+ label_keys %i(sane)
+ end
+ end
+
+ it 'filters sensitive tags' do
+ labels_keys = sensitive_tags.keys
+
+ expect(::Gitlab::Metrics).to receive(:gauge).with(
+ :metric_set_with_sensitive_block, 'Metric set with sensitive block gauge', hash_excluding(*labels_keys), :all
+ ).and_return(prometheus_metric)
+ expect(prometheus_metric).to receive(:set).with(labels, 99)
+
+ transaction_obj.set(:metric_set_with_sensitive_block, 99, sensitive_tags) do
+ label_keys label_keys
+ end
+ end
+ end
+ end
+
+ describe '#observe' do
+ let(:prometheus_metric) { instance_double(Prometheus::Client::Histogram, observe: nil, base_labels: {}) }
+
+ it 'adds a metric' do
+ expect(::Gitlab::Metrics).to receive(:histogram).with(
+ :meow_observe, 'Meow observe histogram', hash_including(*described_class::BASE_LABEL_KEYS), kind_of(Array)
+ ).and_return(prometheus_metric)
+ expect(prometheus_metric).to receive(:observe).with(labels, 2.0)
+
+ transaction_obj.observe(:meow_observe, 2.0)
+ end
+
+ context 'with block' do
+ it 'overrides docstring' do
+ expect(::Gitlab::Metrics).to receive(:histogram).with(
+ :block_docstring_observe, 'test', hash_including(*described_class::BASE_LABEL_KEYS), kind_of(Array)
+ ).and_return(prometheus_metric)
+ expect(prometheus_metric).to receive(:observe).with(labels, 2.0)
+
+ transaction_obj.observe(:block_docstring_observe, 2.0) do
+ docstring 'test'
+ end
+ end
+
+ it 'overrides labels' do
+ expect(::Gitlab::Metrics).to receive(:histogram).with(
+ :block_labels_observe, 'Block labels observe histogram', hash_including(*described_class::BASE_LABEL_KEYS), kind_of(Array)
+ ).and_return(prometheus_metric)
+ expect(prometheus_metric).to receive(:observe).with(labels.merge(sane: 'yes'), 2.0)
+
+ transaction_obj.observe(:block_labels_observe, 2.0, sane: 'yes') do
+ label_keys %i(sane)
+ end
+ end
+
+ it 'filters sensitive tags' do
+ labels_keys = sensitive_tags.keys
+
+ expect(::Gitlab::Metrics).to receive(:histogram).with(
+ :metric_observe_with_sensitive_block,
+ 'Metric observe with sensitive block histogram',
+ hash_excluding(labels_keys),
+ kind_of(Array)
+ ).and_return(prometheus_metric)
+ expect(prometheus_metric).to receive(:observe).with(labels, 2.0)
+
+ transaction_obj.observe(:metric_observe_with_sensitive_block, 2.0, sensitive_tags) do
+ label_keys label_keys
+ end
+ end
+ end
+ end
+end
diff --git a/spec/support/shared_examples/models/concerns/analytics/cycle_analytics/stage_event_model_examples.rb b/spec/support/shared_examples/models/concerns/analytics/cycle_analytics/stage_event_model_examples.rb
index f928fb1eb43..d823e7ac221 100644
--- a/spec/support/shared_examples/models/concerns/analytics/cycle_analytics/stage_event_model_examples.rb
+++ b/spec/support/shared_examples/models/concerns/analytics/cycle_analytics/stage_event_model_examples.rb
@@ -12,6 +12,7 @@ RSpec.shared_examples 'StageEventModel' do
project_id: 4,
author_id: 5,
milestone_id: 6,
+ state_id: 1,
start_event_timestamp: time,
end_event_timestamp: time
},
@@ -22,6 +23,7 @@ RSpec.shared_examples 'StageEventModel' do
project_id: 11,
author_id: 12,
milestone_id: 13,
+ state_id: 1,
start_event_timestamp: time,
end_event_timestamp: time
}
@@ -34,8 +36,9 @@ RSpec.shared_examples 'StageEventModel' do
described_class.issuable_id_column,
:group_id,
:project_id,
- :milestone_id,
:author_id,
+ :milestone_id,
+ :state_id,
:start_event_timestamp,
:end_event_timestamp
]
@@ -59,10 +62,120 @@ RSpec.shared_examples 'StageEventModel' do
upsert_data
output_data = described_class.all.map do |record|
- column_order.map { |column| record[column] }
+ column_order.map do |column|
+ if column == :state_id
+ described_class.states[record[column]]
+ else
+ record[column]
+ end
+ end
end.sort
expect(input_data.map(&:values).sort).to eq(output_data)
end
end
+
+ describe 'scopes' do
+ def attributes(array)
+ array.map(&:attributes)
+ end
+
+ RSpec::Matchers.define :match_attributes do |expected|
+ match do |actual|
+ actual.map(&:attributes) == expected.map(&:attributes)
+ end
+ end
+
+ let_it_be(:user) { create(:user) }
+ let_it_be(:project) { create(:user) }
+ let_it_be(:milestone) { create(:milestone) }
+ let_it_be(:issuable_with_assignee) { create(issuable_factory, assignees: [user])}
+
+ let_it_be(:record) { create(stage_event_factory, start_event_timestamp: 3.years.ago.to_date, end_event_timestamp: 2.years.ago.to_date) }
+ let_it_be(:record_with_author) { create(stage_event_factory, author_id: user.id) }
+ let_it_be(:record_with_project) { create(stage_event_factory, project_id: project.id) }
+ let_it_be(:record_with_group) { create(stage_event_factory, group_id: project.namespace_id) }
+ let_it_be(:record_with_assigned_issuable) { create(stage_event_factory, described_class.issuable_id_column => issuable_with_assignee.id) }
+ let_it_be(:record_with_milestone) { create(stage_event_factory, milestone_id: milestone.id) }
+
+ it 'filters by stage_event_hash_id' do
+ records = described_class.by_stage_event_hash_id(record.stage_event_hash_id)
+
+ expect(records).to match_attributes([record])
+ end
+
+ it 'filters by project_id' do
+ records = described_class.by_project_id(project.id)
+
+ expect(records).to match_attributes([record_with_project])
+ end
+
+ it 'filters by group_id' do
+ records = described_class.by_group_id(project.namespace_id)
+
+ expect(records).to match_attributes([record_with_group])
+ end
+
+ it 'filters by author_id' do
+ records = described_class.authored(user)
+
+ expect(records).to match_attributes([record_with_author])
+ end
+
+ it 'filters by assignee' do
+ records = described_class.assigned_to(user)
+
+ expect(records).to match_attributes([record_with_assigned_issuable])
+ end
+
+ it 'filters by milestone_id' do
+ records = described_class.with_milestone_id(milestone.id)
+
+ expect(records).to match_attributes([record_with_milestone])
+ end
+
+ describe 'start_event_timestamp filtering' do
+ it 'when range is given' do
+ records = described_class
+ .start_event_timestamp_after(4.years.ago)
+ .start_event_timestamp_before(2.years.ago)
+
+ expect(records).to match_attributes([record])
+ end
+
+ it 'when specifying upper bound' do
+ records = described_class.start_event_timestamp_before(2.years.ago)
+
+ expect(attributes(records)).to include(attributes([record]).first)
+ end
+
+ it 'when specifying the lower bound' do
+ records = described_class.start_event_timestamp_after(4.years.ago)
+
+ expect(attributes(records)).to include(attributes([record]).first)
+ end
+ end
+
+ describe 'end_event_timestamp filtering' do
+ it 'when range is given' do
+ records = described_class
+ .end_event_timestamp_after(3.years.ago)
+ .end_event_timestamp_before(1.year.ago)
+
+ expect(records).to match_attributes([record])
+ end
+
+ it 'when specifying upper bound' do
+ records = described_class.end_event_timestamp_before(1.year.ago)
+
+ expect(attributes(records)).to include(attributes([record]).first)
+ end
+
+ it 'when specifying the lower bound' do
+ records = described_class.end_event_timestamp_after(3.years.ago)
+
+ expect(attributes(records)).to include(attributes([record]).first)
+ end
+ end
+ end
end
diff --git a/spec/support/shared_examples/models/concerns/ttl_expirable_shared_examples.rb b/spec/support/shared_examples/models/concerns/ttl_expirable_shared_examples.rb
index a4e0d6c871e..2d08de297a3 100644
--- a/spec/support/shared_examples/models/concerns/ttl_expirable_shared_examples.rb
+++ b/spec/support/shared_examples/models/concerns/ttl_expirable_shared_examples.rb
@@ -11,18 +11,18 @@ RSpec.shared_examples 'ttl_expirable' do
it { is_expected.to validate_presence_of(:status) }
end
- describe '.updated_before' do
+ describe '.read_before' do
# rubocop:disable Rails/SaveBang
let_it_be_with_reload(:item1) { create(class_symbol) }
let_it_be(:item2) { create(class_symbol) }
# rubocop:enable Rails/SaveBang
before do
- item1.update_column(:updated_at, 1.month.ago)
+ item1.update_column(:read_at, 1.month.ago)
end
it 'returns items with created at older than the supplied number of days' do
- expect(described_class.updated_before(10)).to contain_exactly(item1)
+ expect(described_class.read_before(10)).to contain_exactly(item1)
end
end
@@ -48,4 +48,13 @@ RSpec.shared_examples 'ttl_expirable' do
expect(described_class.lock_next_by(:created_at)).to contain_exactly(item3)
end
end
+
+ describe '#read', :freeze_time do
+ let_it_be(:old_read_at) { 1.day.ago }
+ let_it_be(:item1) { create(class_symbol, read_at: old_read_at) }
+
+ it 'updates read_at' do
+ expect { item1.read! }.to change { item1.reload.read_at }
+ end
+ end
end
diff --git a/spec/support/shared_examples/models/member_shared_examples.rb b/spec/support/shared_examples/models/member_shared_examples.rb
index 56c202cb228..a2909c66e22 100644
--- a/spec/support/shared_examples/models/member_shared_examples.rb
+++ b/spec/support/shared_examples/models/member_shared_examples.rb
@@ -299,6 +299,22 @@ RSpec.shared_examples_for "member creation" do
end
end
end
+
+ context 'when `tasks_to_be_done` and `tasks_project_id` are passed' do
+ before do
+ stub_experiments(invite_members_for_task: true)
+ end
+
+ it 'creates a member_task with the correct attributes', :aggregate_failures do
+ task_project = source.is_a?(Group) ? create(:project, group: source) : source
+ described_class.new(source, user, :developer, tasks_to_be_done: %w(ci code), tasks_project_id: task_project.id).execute
+
+ member = source.members.last
+
+ expect(member.tasks_to_be_done).to match_array([:ci, :code])
+ expect(member.member_task.project).to eq(task_project)
+ end
+ end
end
end
@@ -379,5 +395,20 @@ RSpec.shared_examples_for "bulk member creation" do
expect(members).to all(be_persisted)
end
end
+
+ context 'when `tasks_to_be_done` and `tasks_project_id` are passed' do
+ before do
+ stub_experiments(invite_members_for_task: true)
+ end
+
+ it 'creates a member_task with the correct attributes', :aggregate_failures do
+ task_project = source.is_a?(Group) ? create(:project, group: source) : source
+ members = described_class.add_users(source, [user1], :developer, tasks_to_be_done: %w(ci code), tasks_project_id: task_project.id)
+ member = members.last
+
+ expect(member.tasks_to_be_done).to match_array([:ci, :code])
+ expect(member.member_task.project).to eq(task_project)
+ end
+ end
end
end
diff --git a/spec/support/shared_examples/models/reviewer_state_shared_examples.rb b/spec/support/shared_examples/models/reviewer_state_shared_examples.rb
new file mode 100644
index 00000000000..f1392768b06
--- /dev/null
+++ b/spec/support/shared_examples/models/reviewer_state_shared_examples.rb
@@ -0,0 +1,15 @@
+# frozen_string_literal: true
+
+RSpec.shared_examples 'having reviewer state' do
+ describe 'mr_attention_requests feature flag is disabled' do
+ before do
+ stub_feature_flags(mr_attention_requests: false)
+ end
+
+ it { is_expected.to have_attributes(state: 'unreviewed') }
+ end
+
+ describe 'mr_attention_requests feature flag is enabled' do
+ it { is_expected.to have_attributes(state: 'attention_requested') }
+ end
+end
diff --git a/spec/support/shared_examples/namespaces/traversal_examples.rb b/spec/support/shared_examples/namespaces/traversal_examples.rb
index d126b242fb0..ac6a843663f 100644
--- a/spec/support/shared_examples/namespaces/traversal_examples.rb
+++ b/spec/support/shared_examples/namespaces/traversal_examples.rb
@@ -22,6 +22,8 @@ RSpec.shared_examples 'namespace traversal' do
let_it_be(:deep_nested_group) { create(:group, parent: nested_group) }
let_it_be(:very_deep_nested_group) { create(:group, parent: deep_nested_group) }
let_it_be(:groups) { [group, nested_group, deep_nested_group, very_deep_nested_group] }
+ let_it_be(:project) { create(:project, group: nested_group) }
+ let_it_be(:project_namespace) { project.project_namespace }
describe '#root_ancestor' do
it 'returns the correct root ancestor' do
@@ -65,6 +67,7 @@ RSpec.shared_examples 'namespace traversal' do
expect(deep_nested_group.ancestors).to contain_exactly(group, nested_group)
expect(nested_group.ancestors).to contain_exactly(group)
expect(group.ancestors).to eq([])
+ expect(project_namespace.ancestors).to be_empty
end
context 'with asc hierarchy_order' do
@@ -73,6 +76,7 @@ RSpec.shared_examples 'namespace traversal' do
expect(deep_nested_group.ancestors(hierarchy_order: :asc)).to eq [nested_group, group]
expect(nested_group.ancestors(hierarchy_order: :asc)).to eq [group]
expect(group.ancestors(hierarchy_order: :asc)).to eq([])
+ expect(project_namespace.ancestors(hierarchy_order: :asc)).to be_empty
end
end
@@ -82,6 +86,7 @@ RSpec.shared_examples 'namespace traversal' do
expect(deep_nested_group.ancestors(hierarchy_order: :desc)).to eq [group, nested_group]
expect(nested_group.ancestors(hierarchy_order: :desc)).to eq [group]
expect(group.ancestors(hierarchy_order: :desc)).to eq([])
+ expect(project_namespace.ancestors(hierarchy_order: :desc)).to be_empty
end
end
@@ -98,6 +103,7 @@ RSpec.shared_examples 'namespace traversal' do
expect(deep_nested_group.ancestor_ids).to contain_exactly(group.id, nested_group.id)
expect(nested_group.ancestor_ids).to contain_exactly(group.id)
expect(group.ancestor_ids).to be_empty
+ expect(project_namespace.ancestor_ids).to be_empty
end
context 'with asc hierarchy_order' do
@@ -106,6 +112,7 @@ RSpec.shared_examples 'namespace traversal' do
expect(deep_nested_group.ancestor_ids(hierarchy_order: :asc)).to eq [nested_group.id, group.id]
expect(nested_group.ancestor_ids(hierarchy_order: :asc)).to eq [group.id]
expect(group.ancestor_ids(hierarchy_order: :asc)).to eq([])
+ expect(project_namespace.ancestor_ids(hierarchy_order: :asc)).to eq([])
end
end
@@ -115,6 +122,7 @@ RSpec.shared_examples 'namespace traversal' do
expect(deep_nested_group.ancestor_ids(hierarchy_order: :desc)).to eq [group.id, nested_group.id]
expect(nested_group.ancestor_ids(hierarchy_order: :desc)).to eq [group.id]
expect(group.ancestor_ids(hierarchy_order: :desc)).to eq([])
+ expect(project_namespace.ancestor_ids(hierarchy_order: :desc)).to eq([])
end
end
@@ -131,6 +139,7 @@ RSpec.shared_examples 'namespace traversal' do
expect(deep_nested_group.self_and_ancestors).to contain_exactly(group, nested_group, deep_nested_group)
expect(nested_group.self_and_ancestors).to contain_exactly(group, nested_group)
expect(group.self_and_ancestors).to contain_exactly(group)
+ expect(project_namespace.self_and_ancestors).to contain_exactly(project_namespace)
end
context 'with asc hierarchy_order' do
@@ -139,6 +148,7 @@ RSpec.shared_examples 'namespace traversal' do
expect(deep_nested_group.self_and_ancestors(hierarchy_order: :asc)).to eq [deep_nested_group, nested_group, group]
expect(nested_group.self_and_ancestors(hierarchy_order: :asc)).to eq [nested_group, group]
expect(group.self_and_ancestors(hierarchy_order: :asc)).to eq([group])
+ expect(project_namespace.self_and_ancestors(hierarchy_order: :asc)).to eq([project_namespace])
end
end
@@ -148,6 +158,7 @@ RSpec.shared_examples 'namespace traversal' do
expect(deep_nested_group.self_and_ancestors(hierarchy_order: :desc)).to eq [group, nested_group, deep_nested_group]
expect(nested_group.self_and_ancestors(hierarchy_order: :desc)).to eq [group, nested_group]
expect(group.self_and_ancestors(hierarchy_order: :desc)).to eq([group])
+ expect(project_namespace.self_and_ancestors(hierarchy_order: :desc)).to eq([project_namespace])
end
end
@@ -164,6 +175,7 @@ RSpec.shared_examples 'namespace traversal' do
expect(deep_nested_group.self_and_ancestor_ids).to contain_exactly(group.id, nested_group.id, deep_nested_group.id)
expect(nested_group.self_and_ancestor_ids).to contain_exactly(group.id, nested_group.id)
expect(group.self_and_ancestor_ids).to contain_exactly(group.id)
+ expect(project_namespace.self_and_ancestor_ids).to contain_exactly(project_namespace.id)
end
context 'with asc hierarchy_order' do
@@ -172,6 +184,7 @@ RSpec.shared_examples 'namespace traversal' do
expect(deep_nested_group.self_and_ancestor_ids(hierarchy_order: :asc)).to eq [deep_nested_group.id, nested_group.id, group.id]
expect(nested_group.self_and_ancestor_ids(hierarchy_order: :asc)).to eq [nested_group.id, group.id]
expect(group.self_and_ancestor_ids(hierarchy_order: :asc)).to eq([group.id])
+ expect(project_namespace.self_and_ancestor_ids(hierarchy_order: :asc)).to eq([project_namespace.id])
end
end
@@ -181,6 +194,7 @@ RSpec.shared_examples 'namespace traversal' do
expect(deep_nested_group.self_and_ancestor_ids(hierarchy_order: :desc)).to eq [group.id, nested_group.id, deep_nested_group.id]
expect(nested_group.self_and_ancestor_ids(hierarchy_order: :desc)).to eq [group.id, nested_group.id]
expect(group.self_and_ancestor_ids(hierarchy_order: :desc)).to eq([group.id])
+ expect(project_namespace.self_and_ancestor_ids(hierarchy_order: :desc)).to eq([project_namespace.id])
end
end
@@ -205,6 +219,10 @@ RSpec.shared_examples 'namespace traversal' do
describe '#recursive_descendants' do
it_behaves_like 'recursive version', :descendants
end
+
+ it 'does not include project namespaces' do
+ expect(group.descendants.to_a).not_to include(project_namespace)
+ end
end
describe '#self_and_descendants' do
@@ -223,6 +241,10 @@ RSpec.shared_examples 'namespace traversal' do
it_behaves_like 'recursive version', :self_and_descendants
end
+
+ it 'does not include project namespaces' do
+ expect(group.self_and_descendants.to_a).not_to include(project_namespace)
+ end
end
describe '#self_and_descendant_ids' do
diff --git a/spec/support/shared_examples/namespaces/traversal_scope_examples.rb b/spec/support/shared_examples/namespaces/traversal_scope_examples.rb
index 74b1bacc560..4c09c1c2a3b 100644
--- a/spec/support/shared_examples/namespaces/traversal_scope_examples.rb
+++ b/spec/support/shared_examples/namespaces/traversal_scope_examples.rb
@@ -25,12 +25,6 @@ RSpec.shared_examples 'namespace traversal scopes' do
it { is_expected.to contain_exactly(group_1.id, group_2.id) }
end
- describe '.without_sti_condition' do
- subject { described_class.without_sti_condition }
-
- it { expect(subject.where_values_hash).not_to have_key(:type) }
- end
-
describe '.order_by_depth' do
subject { described_class.where(id: [group_1, nested_group_1, deep_nested_group_1]).order_by_depth(direction) }
@@ -55,6 +49,53 @@ RSpec.shared_examples 'namespace traversal scopes' do
it { is_expected.to eq described_class.column_names }
end
+ shared_examples '.roots' do
+ context 'with only sub-groups' do
+ subject { described_class.where(id: [deep_nested_group_1, nested_group_1, deep_nested_group_2]).roots }
+
+ it { is_expected.to contain_exactly(group_1, group_2) }
+ end
+
+ context 'with only root groups' do
+ subject { described_class.where(id: [group_1, group_2]).roots }
+
+ it { is_expected.to contain_exactly(group_1, group_2) }
+ end
+
+ context 'with all groups' do
+ subject { described_class.where(id: groups).roots }
+
+ it { is_expected.to contain_exactly(group_1, group_2) }
+ end
+ end
+
+ describe '.roots' do
+ context "use_traversal_ids_roots feature flag is true" do
+ before do
+ stub_feature_flags(use_traversal_ids: true)
+ stub_feature_flags(use_traversal_ids_roots: true)
+ end
+
+ it_behaves_like '.roots'
+
+ it 'not make recursive queries' do
+ expect { described_class.where(id: [nested_group_1]).roots.load }.not_to make_queries_matching(/WITH RECURSIVE/)
+ end
+ end
+
+ context "use_traversal_ids_roots feature flag is false" do
+ before do
+ stub_feature_flags(use_traversal_ids_roots: false)
+ end
+
+ it_behaves_like '.roots'
+
+ it 'make recursive queries' do
+ expect { described_class.where(id: [nested_group_1]).roots.load }.to make_queries_matching(/WITH RECURSIVE/)
+ end
+ end
+ end
+
shared_examples '.self_and_ancestors' do
subject { described_class.where(id: [nested_group_1, nested_group_2]).self_and_ancestors }
@@ -156,7 +197,7 @@ RSpec.shared_examples 'namespace traversal scopes' do
end
end
- describe '.self_and_descendants' do
+ shared_examples '.self_and_descendants' do
subject { described_class.where(id: [nested_group_1, nested_group_2]).self_and_descendants }
it { is_expected.to contain_exactly(nested_group_1, deep_nested_group_1, nested_group_2, deep_nested_group_2) }
@@ -174,7 +215,19 @@ RSpec.shared_examples 'namespace traversal scopes' do
end
end
- describe '.self_and_descendant_ids' do
+ describe '.self_and_descendants' do
+ include_examples '.self_and_descendants'
+
+ context 'with traversal_ids_btree feature flag disabled' do
+ before do
+ stub_feature_flags(traversal_ids_btree: false)
+ end
+
+ include_examples '.self_and_descendants'
+ end
+ end
+
+ shared_examples '.self_and_descendant_ids' do
subject { described_class.where(id: [nested_group_1, nested_group_2]).self_and_descendant_ids.pluck(:id) }
it { is_expected.to contain_exactly(nested_group_1.id, deep_nested_group_1.id, nested_group_2.id, deep_nested_group_2.id) }
@@ -190,4 +243,16 @@ RSpec.shared_examples 'namespace traversal scopes' do
it { is_expected.to contain_exactly(deep_nested_group_1.id, deep_nested_group_2.id) }
end
end
+
+ describe '.self_and_descendant_ids' do
+ include_examples '.self_and_descendant_ids'
+
+ context 'with traversal_ids_btree feature flag disabled' do
+ before do
+ stub_feature_flags(traversal_ids_btree: false)
+ end
+
+ include_examples '.self_and_descendant_ids'
+ end
+ end
end
diff --git a/spec/support/shared_examples/quick_actions/issue/promote_to_incident_quick_action_shared_examples.rb b/spec/support/shared_examples/quick_actions/issue/promote_to_incident_quick_action_shared_examples.rb
new file mode 100644
index 00000000000..5167d27f8b9
--- /dev/null
+++ b/spec/support/shared_examples/quick_actions/issue/promote_to_incident_quick_action_shared_examples.rb
@@ -0,0 +1,40 @@
+# frozen_string_literal: true
+
+RSpec.shared_examples 'promote_to_incident quick action' do
+ describe '/promote_to_incident' do
+ context 'when issue can be promoted' do
+ it 'promotes issue to incident' do
+ add_note('/promote_to_incident')
+
+ expect(issue.reload.issue_type).to eq('incident')
+ expect(page).to have_content('Issue has been promoted to incident')
+ end
+ end
+
+ context 'when issue is already an incident' do
+ let(:issue) { create(:incident, project: project) }
+
+ it 'does not promote the issue' do
+ add_note('/promote_to_incident')
+
+ expect(page).to have_content('Could not apply promote_to_incident command')
+ end
+ end
+
+ context 'when user does not have permissions' do
+ let(:guest) { create(:user) }
+
+ before do
+ sign_in(guest)
+ visit project_issue_path(project, issue)
+ wait_for_all_requests
+ end
+
+ it 'does not promote the issue' do
+ add_note('/promote_to_incident')
+
+ expect(page).to have_content('Could not apply promote_to_incident command')
+ end
+ end
+ end
+end
diff --git a/spec/support/shared_examples/requests/api/debian_common_shared_examples.rb b/spec/support/shared_examples/requests/api/debian_common_shared_examples.rb
new file mode 100644
index 00000000000..e0225070986
--- /dev/null
+++ b/spec/support/shared_examples/requests/api/debian_common_shared_examples.rb
@@ -0,0 +1,17 @@
+# frozen_string_literal: true
+
+RSpec.shared_examples 'rejects Debian access with unknown container id' do |anonymous_status, auth_method|
+ context 'with an unknown container' do
+ let(:container) { double(id: non_existing_record_id) }
+
+ context 'as anonymous' do
+ it_behaves_like 'Debian packages GET request', anonymous_status, nil
+ end
+
+ context 'as authenticated user' do
+ include_context 'Debian repository auth headers', :not_a_member, auth_method do
+ it_behaves_like 'Debian packages GET request', :not_found, nil
+ end
+ end
+ end
+end
diff --git a/spec/support/shared_examples/requests/api/debian_distributions_shared_examples.rb b/spec/support/shared_examples/requests/api/debian_distributions_shared_examples.rb
new file mode 100644
index 00000000000..5cd63c33936
--- /dev/null
+++ b/spec/support/shared_examples/requests/api/debian_distributions_shared_examples.rb
@@ -0,0 +1,192 @@
+# frozen_string_literal: true
+
+RSpec.shared_examples 'Debian distributions GET request' do |status, body = nil|
+ and_body = body.nil? ? '' : ' and expected body'
+
+ it "returns #{status}#{and_body}" do
+ subject
+
+ expect(response).to have_gitlab_http_status(status)
+
+ unless body.nil?
+ expect(response.body).to match(body)
+ end
+ end
+end
+
+RSpec.shared_examples 'Debian distributions PUT 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 'Debian distributions DELETE 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 'Debian distributions POST 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 distributions read endpoint' do |desired_behavior, success_status, success_body|
+ context 'with valid container' do
+ using RSpec::Parameterized::TableSyntax
+
+ where(:visibility_level, :user_type, :auth_method, :expected_status, :expected_body) do
+ :public | :guest | :private_token | success_status | success_body
+ :public | :not_a_member | :private_token | success_status | success_body
+ :public | :anonymous | :private_token | success_status | success_body
+ :public | :invalid_token | :private_token | :unauthorized | nil
+ :private | :developer | :private_token | success_status | success_body
+ :private | :developer | :basic | :not_found | nil
+ :private | :guest | :private_token | :forbidden | nil
+ :private | :not_a_member | :private_token | :not_found | nil
+ :private | :anonymous | :private_token | :not_found | nil
+ :private | :invalid_token | :private_token | :unauthorized | nil
+ end
+
+ with_them do
+ include_context 'Debian repository access', params[:visibility_level], params[:user_type], params[:auth_method] do
+ it_behaves_like "Debian distributions #{desired_behavior} request", params[:expected_status], params[:expected_body]
+ end
+ end
+ end
+
+ it_behaves_like 'rejects Debian access with unknown container id', :not_found, :private_token
+end
+
+RSpec.shared_examples 'Debian distributions write endpoint' do |desired_behavior, success_status, success_body|
+ context 'with valid container' do
+ using RSpec::Parameterized::TableSyntax
+
+ where(:visibility_level, :user_type, :auth_method, :expected_status, :expected_body) do
+ :public | :developer | :private_token | success_status | success_body
+ :public | :developer | :basic | :unauthorized | nil
+ :public | :guest | :private_token | :forbidden | nil
+ :public | :not_a_member | :private_token | :forbidden | nil
+ :public | :anonymous | :private_token | :unauthorized | nil
+ :public | :invalid_token | :private_token | :unauthorized | nil
+ :private | :developer | :private_token | success_status | success_body
+ :private | :guest | :private_token | :forbidden | nil
+ :private | :not_a_member | :private_token | :not_found | nil
+ :private | :anonymous | :private_token | :not_found | nil
+ :private | :invalid_token | :private_token | :unauthorized | nil
+ end
+
+ with_them do
+ include_context 'Debian repository access', params[:visibility_level], params[:user_type], params[:auth_method] do
+ it_behaves_like "Debian distributions #{desired_behavior} request", params[:expected_status], params[:expected_body]
+ end
+ end
+ end
+
+ it_behaves_like 'rejects Debian access with unknown container id', :not_found, :private_token
+end
+
+RSpec.shared_examples 'Debian distributions maintainer write endpoint' do |desired_behavior, success_status, success_body|
+ context 'with valid container' do
+ using RSpec::Parameterized::TableSyntax
+
+ where(:visibility_level, :user_type, :auth_method, :expected_status, :expected_body) do
+ :public | :maintainer | :private_token | success_status | success_body
+ :public | :maintainer | :basic | :unauthorized | nil
+ :public | :developer | :private_token | :forbidden | nil
+ :public | :not_a_member | :private_token | :forbidden | nil
+ :public | :anonymous | :private_token | :unauthorized | nil
+ :public | :invalid_token | :private_token | :unauthorized | nil
+ :private | :maintainer | :private_token | success_status | success_body
+ :private | :developer | :private_token | :forbidden | nil
+ :private | :not_a_member | :private_token | :not_found | nil
+ :private | :anonymous | :private_token | :not_found | nil
+ :private | :invalid_token | :private_token | :unauthorized | nil
+ end
+
+ with_them do
+ include_context 'Debian repository access', params[:visibility_level], params[:user_type], params[:auth_method] do
+ it_behaves_like "Debian distributions #{desired_behavior} request", params[:expected_status], params[:expected_body]
+ end
+ end
+ end
+
+ it_behaves_like 'rejects Debian access with unknown container id', :not_found, :private_token
+end
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 a3ed74085fb..2fd5e6a5f91 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
@@ -1,127 +1,6 @@
# frozen_string_literal: true
-RSpec.shared_context 'Debian repository shared context' do |container_type, can_freeze|
- include_context 'workhorse headers'
-
- before do
- stub_feature_flags(debian_packages: true, debian_group_packages: true)
- end
-
- let_it_be(:private_container, freeze: can_freeze) { create(container_type, :private) }
- let_it_be(:public_container, freeze: can_freeze) { create(container_type, :public) }
- let_it_be(:user, freeze: true) { create(:user) }
- let_it_be(:personal_access_token, freeze: true) { create(:personal_access_token, user: user) }
-
- let_it_be(:private_distribution, freeze: true) { create("debian_#{container_type}_distribution", :with_file, 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(:private_component_file) { create("debian_#{container_type}_component_file", component: private_component, architecture: private_architecture) }
-
- let_it_be(:public_distribution, freeze: true) { create("debian_#{container_type}_distribution", :with_file, 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') }
- let_it_be(:public_component_file) { create("debian_#{container_type}_component_file", component: public_component, architecture: public_architecture) }
-
- 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') }
-
- let(:project) { { private: private_project, public: public_project }[visibility_level] }
- 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(:architecture) { { private: private_architecture, public: public_architecture }[visibility_level] }
- let(:component) { { private: private_component, public: public_component }[visibility_level] }
- let(:component_file) { { private: private_component_file, public: public_component_file }[visibility_level] }
- let(:package) { { private: private_package, public: public_package }[visibility_level] }
- let(:letter) { package.name[0..2] == 'lib' ? package.name[0..3] : package.name[0] }
-
- let(:method) { :get }
-
- let(:workhorse_params) do
- if method == :put
- file_upload = fixture_file_upload("spec/fixtures/packages/debian/#{file_name}")
- { file: file_upload }
- else
- {}
- end
- end
-
- let(:api_params) { workhorse_params }
-
- let(:auth_headers) { {} }
- let(:wh_headers) do
- if method == :put
- workhorse_headers
- else
- {}
- end
- end
-
- let(:headers) { auth_headers.merge(wh_headers) }
-
- let(:send_rewritten_field) { true }
-
- subject do
- if method == :put
- workhorse_finalize(
- api(url),
- method: method,
- file_key: :file,
- params: api_params,
- headers: headers,
- send_rewritten_field: send_rewritten_field
- )
- else
- send method, api(url), headers: headers, params: api_params
- end
- end
-end
-
-RSpec.shared_context 'with file_name' do |file_name|
- let(:file_name) { file_name }
-end
-
-RSpec.shared_context 'Debian repository auth headers' do |user_role, user_token, auth_method = :token|
- let(:token) { user_token ? personal_access_token.token : 'wrong' }
-
- let(:auth_headers) do
- if user_role == :anonymous
- {}
- elsif auth_method == :token
- { 'Private-Token' => token }
- else
- basic_auth_header(user.username, token)
- end
- end
-end
-
-RSpec.shared_context 'Debian repository access' do |visibility_level, user_role, add_member, user_token, auth_method|
- include_context 'Debian repository auth headers', user_role, user_token, auth_method do
- let(:containers) { { private: private_container, public: public_container } }
- let(:container) { containers[visibility_level] }
-
- before do
- container.send("add_#{user_role}", user) if add_member && user_role != :anonymous
- end
- end
-end
-
-RSpec.shared_examples 'Debian repository GET request' do |status, body = nil|
+RSpec.shared_examples 'Debian packages GET request' do |status, body = nil|
and_body = body.nil? ? '' : ' and expected body'
it "returns #{status}#{and_body}" do
@@ -135,7 +14,7 @@ RSpec.shared_examples 'Debian repository GET request' do |status, body = nil|
end
end
-RSpec.shared_examples 'Debian repository upload request' do |status, body = nil|
+RSpec.shared_examples 'Debian packages upload request' do |status, body = nil|
and_body = body.nil? ? '' : ' and expected body'
if status == :created
@@ -175,7 +54,7 @@ RSpec.shared_examples 'Debian repository upload request' do |status, body = nil|
end
end
-RSpec.shared_examples 'Debian repository upload authorize request' do |status, body = nil|
+RSpec.shared_examples 'Debian packages upload authorize request' do |status, body = nil|
and_body = body.nil? ? '' : ' and expected body'
if status == :created
@@ -221,237 +100,57 @@ RSpec.shared_examples 'Debian repository upload authorize request' do |status, b
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 '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', hidden_status, nil
- end
-
- context 'as authenticated user' do
- subject { get api(url), headers: basic_auth_header(user.username, personal_access_token.token) }
-
- it_behaves_like 'Debian repository GET request', :not_found, nil
- end
- end
-end
-
-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 | :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 | :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
- :private | :developer | true | false | :unauthorized | nil
- :private | :guest | true | false | :unauthorized | nil
- :private | :developer | false | true | :not_found | nil
- :private | :guest | false | true | :not_found | nil
- :private | :developer | false | false | :unauthorized | nil
- :private | :guest | false | false | :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 write endpoint' do |desired_behavior, success_status, success_body, authenticate_non_public: true|
- hidden_status = if authenticate_non_public
- :unauthorized
- else
- :not_found
- end
-
+RSpec.shared_examples 'Debian packages read endpoint' do |desired_behavior, success_status, success_body|
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 | :forbidden | nil
- :public | :developer | true | false | :unauthorized | nil
- :public | :guest | true | false | :unauthorized | nil
- :public | :developer | false | true | :forbidden | nil
- :public | :guest | false | true | :forbidden | nil
- :public | :developer | false | false | :unauthorized | nil
- :public | :guest | false | false | :unauthorized | nil
- :public | :anonymous | false | true | :unauthorized | nil
- :private | :developer | true | true | success_status | success_body
- :private | :guest | true | true | :forbidden | nil
- :private | :developer | true | false | :unauthorized | nil
- :private | :guest | true | false | :unauthorized | nil
- :private | :developer | false | true | :not_found | nil
- :private | :guest | false | true | :not_found | nil
- :private | :developer | false | false | :unauthorized | nil
- :private | :guest | false | false | :unauthorized | nil
- :private | :anonymous | false | true | hidden_status | nil
+ where(:visibility_level, :user_type, :auth_method, :expected_status, :expected_body) do
+ :public | :guest | :basic | success_status | success_body
+ :public | :not_a_member | :basic | success_status | success_body
+ :public | :anonymous | :basic | success_status | success_body
+ :public | :invalid_token | :basic | :unauthorized | nil
+ :private | :developer | :basic | success_status | success_body
+ :private | :developer | :private_token | :unauthorized | nil
+ :private | :guest | :basic | :forbidden | nil
+ :private | :not_a_member | :basic | :not_found | nil
+ :private | :anonymous | :basic | :unauthorized | nil
+ :private | :invalid_token | :basic | :unauthorized | 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]
+ include_context 'Debian repository access', params[:visibility_level], params[:user_type], params[:auth_method] do
+ it_behaves_like "Debian packages #{desired_behavior} request", params[:expected_status], params[:expected_body]
end
end
end
- it_behaves_like 'rejects Debian access with unknown container id', hidden_status
+ it_behaves_like 'rejects Debian access with unknown container id', :unauthorized, :basic
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
-
+RSpec.shared_examples 'Debian packages write endpoint' do |desired_behavior, success_status, success_body|
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
+ where(:visibility_level, :user_type, :auth_method, :expected_status, :expected_body) do
+ :public | :developer | :basic | success_status | success_body
+ :public | :developer | :private_token | :unauthorized | nil
+ :public | :guest | :basic | :forbidden | nil
+ :public | :not_a_member | :basic | :forbidden | nil
+ :public | :anonymous | :basic | :unauthorized | nil
+ :public | :invalid_token | :basic | :unauthorized | nil
+ :private | :developer | :basic | success_status | success_body
+ :private | :guest | :basic | :forbidden | nil
+ :private | :not_a_member | :basic | :not_found | nil
+ :private | :anonymous | :basic | :unauthorized | nil
+ :private | :invalid_token | :basic | :unauthorized | 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]
+ include_context 'Debian repository access', params[:visibility_level], params[:user_type], params[:auth_method] do
+ it_behaves_like "Debian packages #{desired_behavior} request", params[:expected_status], params[:expected_body]
end
end
end
- it_behaves_like 'rejects Debian access with unknown container id', hidden_status
+ it_behaves_like 'rejects Debian access with unknown container id', :unauthorized, :basic
end
diff --git a/spec/support/shared_examples/requests/api/graphql/mutations/destroy_list_shared_examples.rb b/spec/support/shared_examples/requests/api/graphql/mutations/destroy_list_shared_examples.rb
index 0cec67ff541..dca152223fb 100644
--- a/spec/support/shared_examples/requests/api/graphql/mutations/destroy_list_shared_examples.rb
+++ b/spec/support/shared_examples/requests/api/graphql/mutations/destroy_list_shared_examples.rb
@@ -28,7 +28,7 @@ RSpec.shared_examples 'board lists destroy request' do
it 'returns an error' do
subject
- expect(graphql_errors.first['message']).to include("The resource that you are attempting to access does not exist or you don't have permission to perform this action")
+ expect(graphql_errors.first['message']).to include(Gitlab::Graphql::Authorize::AuthorizeResource::RESOURCE_ACCESS_ERROR)
end
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
index 41a61ba5fd7..d576a5874fd 100644
--- 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
@@ -2,12 +2,26 @@
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')
+ it_behaves_like 'matching the package details schema'
+ end
+
+ context 'with pipelines' do
+ let_it_be(:build_info1) { create(:package_build_info, :with_pipeline, package: package) }
+ let_it_be(:build_info2) { create(:package_build_info, :with_pipeline, package: package) }
+ let_it_be(:build_info3) { create(:package_build_info, :with_pipeline, package: package) }
+
+ it_behaves_like 'a working graphql query' do
+ it_behaves_like 'matching the package details schema'
end
end
end
+RSpec.shared_examples 'matching the package details schema' do
+ it 'matches the JSON schema' do
+ expect(package_details).to match_schema('graphql/packages/package_details')
+ 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)
diff --git a/spec/support/shared_examples/requests/api/notes_shared_examples.rb b/spec/support/shared_examples/requests/api/notes_shared_examples.rb
index 40799688144..0434d0beb7e 100644
--- a/spec/support/shared_examples/requests/api/notes_shared_examples.rb
+++ b/spec/support/shared_examples/requests/api/notes_shared_examples.rb
@@ -281,7 +281,7 @@ RSpec.shared_examples 'noteable API' do |parent_type, noteable_type, id_name|
end
end
- context 'when request exceeds the rate limit' do
+ context 'when request exceeds the rate limit', :freeze_time, :clean_gitlab_redis_rate_limiting do
before do
stub_application_setting(notes_create_limit: 1)
allow(::Gitlab::ApplicationRateLimiter).to receive(:increment).and_return(2)
diff --git a/spec/support/shared_examples/requests/api/npm_packages_shared_examples.rb b/spec/support/shared_examples/requests/api/npm_packages_shared_examples.rb
index 2af7b616659..19677e92001 100644
--- a/spec/support/shared_examples/requests/api/npm_packages_shared_examples.rb
+++ b/spec/support/shared_examples/requests/api/npm_packages_shared_examples.rb
@@ -8,6 +8,8 @@ RSpec.shared_examples 'handling get metadata requests' do |scope: :project|
let_it_be(:package_dependency_link3) { create(:packages_dependency_link, package: package, dependency_type: :bundleDependencies) }
let_it_be(:package_dependency_link4) { create(:packages_dependency_link, package: package, dependency_type: :peerDependencies) }
+ let_it_be(:package_metadatum) { create(:npm_metadatum, package: package) }
+
let(:headers) { {} }
subject { get(url, headers: headers) }
@@ -39,6 +41,19 @@ RSpec.shared_examples 'handling get metadata requests' do |scope: :project|
# query count can slightly change between the examples so we're using a custom threshold
expect { get(url, headers: headers) }.not_to exceed_query_limit(control).with_threshold(4)
end
+
+ context 'with packages_npm_abbreviated_metadata disabled' do
+ before do
+ stub_feature_flags(packages_npm_abbreviated_metadata: false)
+ end
+
+ it 'calls the presenter without including metadata' do
+ expect(::Packages::Npm::PackagePresenter)
+ .to receive(:new).with(anything, anything, include_metadata: false).and_call_original
+
+ subject
+ end
+ end
end
shared_examples 'reject metadata request' do |status:|
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 ed6d9ed43c8..06c51add438 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
@@ -167,7 +167,7 @@ end
RSpec.shared_examples 'rejects PyPI access with unknown project id' do
context 'with an unknown project' do
- let(:project) { OpenStruct.new(id: 1234567890) }
+ let(:project) { double('access', id: 1234567890) }
it_behaves_like 'unknown PyPI scope id'
end
@@ -175,7 +175,7 @@ end
RSpec.shared_examples 'rejects PyPI access with unknown group id' do
context 'with an unknown project' do
- let(:group) { OpenStruct.new(id: 1234567890) }
+ let(:group) { double('access', id: 1234567890) }
it_behaves_like 'unknown PyPI scope id'
end
diff --git a/spec/support/shared_examples/requests/api/status_shared_examples.rb b/spec/support/shared_examples/requests/api/status_shared_examples.rb
index 8207190b1dc..40843ccbd15 100644
--- a/spec/support/shared_examples/requests/api/status_shared_examples.rb
+++ b/spec/support/shared_examples/requests/api/status_shared_examples.rb
@@ -76,3 +76,32 @@ RSpec.shared_examples '412 response' do
end
end
end
+
+RSpec.shared_examples '422 response' do
+ let(:message) { nil }
+
+ before do
+ # Fires the request
+ request
+ end
+
+ it 'returns 422' do
+ expect(response).to have_gitlab_http_status(:unprocessable_entity)
+ expect(json_response).to be_an Object
+
+ if message.present?
+ expect(json_response['message']).to eq(message)
+ end
+ end
+end
+
+RSpec.shared_examples '503 response' do
+ before do
+ # Fires the request
+ request
+ end
+
+ it 'returns 503' do
+ expect(response).to have_gitlab_http_status(:service_unavailable)
+ end
+end
diff --git a/spec/support/shared_examples/requests/applications_controller_shared_examples.rb b/spec/support/shared_examples/requests/applications_controller_shared_examples.rb
new file mode 100644
index 00000000000..8f852d42c2c
--- /dev/null
+++ b/spec/support/shared_examples/requests/applications_controller_shared_examples.rb
@@ -0,0 +1,44 @@
+# frozen_string_literal: true
+
+RSpec.shared_examples 'applications controller - GET #show' do
+ describe 'GET #show' do
+ it 'renders template' do
+ get show_path
+
+ expect(response).to render_template :show
+ end
+
+ context 'when application is viewed after being created' do
+ before do
+ create_application
+ end
+
+ it 'sets `@created` instance variable to `true`' do
+ get show_path
+
+ expect(assigns[:created]).to eq(true)
+ end
+ end
+
+ context 'when application is reviewed' do
+ it 'sets `@created` instance variable to `false`' do
+ get show_path
+
+ expect(assigns[:created]).to eq(false)
+ end
+ end
+ end
+end
+
+RSpec.shared_examples 'applications controller - POST #create' do
+ it "sets `#{OauthApplications::CREATED_SESSION_KEY}` session key to `true`" do
+ create_application
+
+ expect(session[OauthApplications::CREATED_SESSION_KEY]).to eq(true)
+ end
+end
+
+def create_application
+ create_params = attributes_for(:application, trusted: true, confidential: false, scopes: ['api'])
+ post create_path, params: { doorkeeper_application: create_params }
+end
diff --git a/spec/support/shared_examples/requests/self_monitoring_shared_examples.rb b/spec/support/shared_examples/requests/self_monitoring_shared_examples.rb
index ff87fc5d8df..f8a752a5673 100644
--- a/spec/support/shared_examples/requests/self_monitoring_shared_examples.rb
+++ b/spec/support/shared_examples/requests/self_monitoring_shared_examples.rb
@@ -39,6 +39,10 @@ end
# let(:status_api) { status_create_self_monitoring_project_admin_application_settings_path }
# subject { post create_self_monitoring_project_admin_application_settings_path }
RSpec.shared_examples 'triggers async worker, returns sidekiq job_id with response accepted' do
+ before do
+ allow(worker_class).to receive(:with_status).and_return(worker_class)
+ end
+
it 'returns sidekiq job_id of expected length' do
subject
diff --git a/spec/support/shared_examples/requests/snippet_shared_examples.rb b/spec/support/shared_examples/requests/snippet_shared_examples.rb
index dae3a3e74be..b13c4da0bed 100644
--- a/spec/support/shared_examples/requests/snippet_shared_examples.rb
+++ b/spec/support/shared_examples/requests/snippet_shared_examples.rb
@@ -86,6 +86,7 @@ RSpec.shared_examples 'snippet blob content' do
expect(response.header[Gitlab::Workhorse::DETECT_HEADER]).to eq 'true'
expect(response.header[Gitlab::Workhorse::SEND_DATA_HEADER]).to start_with('git-blob:')
+ expect(response.parsed_body).to be_empty
end
context 'when snippet repository is empty' do
diff --git a/spec/support/shared_examples/service_desk_issue_templates_examples.rb b/spec/support/shared_examples/service_desk_issue_templates_examples.rb
index fd9645df7a3..ed6c5199936 100644
--- a/spec/support/shared_examples/service_desk_issue_templates_examples.rb
+++ b/spec/support/shared_examples/service_desk_issue_templates_examples.rb
@@ -3,10 +3,10 @@
RSpec.shared_examples 'issue description templates from current project only' do
it 'loads issue description templates from the project only' do
within('#service-desk-template-select') do
- expect(page).to have_content('project-issue-bar')
- expect(page).to have_content('project-issue-foo')
- expect(page).not_to have_content('group-issue-bar')
- expect(page).not_to have_content('group-issue-foo')
+ expect(page).to have_content(:all, 'project-issue-bar')
+ expect(page).to have_content(:all, 'project-issue-foo')
+ expect(page).not_to have_content(:all, 'group-issue-bar')
+ expect(page).not_to have_content(:all, 'group-issue-foo')
end
end
end
diff --git a/spec/support/shared_examples/services/alert_management/alert_processing/alert_firing_shared_examples.rb b/spec/support/shared_examples/services/alert_management/alert_processing/alert_firing_shared_examples.rb
index 92a7d7ab3a3..ca86cb082a7 100644
--- a/spec/support/shared_examples/services/alert_management/alert_processing/alert_firing_shared_examples.rb
+++ b/spec/support/shared_examples/services/alert_management/alert_processing/alert_firing_shared_examples.rb
@@ -3,7 +3,10 @@
# This shared_example requires the following variables:
# - `service`, the service which includes AlertManagement::AlertProcessing
RSpec.shared_examples 'creates an alert management alert or errors' do
- it { is_expected.to be_success }
+ specify do
+ expect(subject).to be_success
+ expect(subject.payload).to match(alerts: all(a_kind_of(AlertManagement::Alert)))
+ end
it 'creates AlertManagement::Alert' do
expect(Gitlab::AppLogger).not_to receive(:warn)
@@ -89,6 +92,7 @@ RSpec.shared_examples 'adds an alert management alert event' do
expect { subject }.to change { alert.reload.events }.by(1)
expect(subject).to be_success
+ expect(subject.payload).to match(alerts: all(a_kind_of(AlertManagement::Alert)))
end
it_behaves_like 'does not create an alert management alert'
diff --git a/spec/support/shared_examples/services/jira/requests/base_shared_examples.rb b/spec/support/shared_examples/services/jira/requests/base_shared_examples.rb
index 56a6d24d557..c4f6273b46c 100644
--- a/spec/support/shared_examples/services/jira/requests/base_shared_examples.rb
+++ b/spec/support/shared_examples/services/jira/requests/base_shared_examples.rb
@@ -26,11 +26,14 @@ RSpec.shared_examples 'a service that handles Jira API errors' do
expect(subject).to be_a(ServiceResponse)
expect(subject).to be_error
- expect(subject.message).to include(expected_message)
+ expect(subject.message).to start_with(expected_message)
end
end
context 'when the JSON in JIRA::HTTPError is unsafe' do
+ config_docs_link_url = Rails.application.routes.url_helpers.help_page_path('integration/jira/configure')
+ let(:docs_link_start) { '<a href="%{url}" target="_blank" rel="noopener noreferrer">'.html_safe % { url: config_docs_link_url } }
+
before do
stub_client_and_raise(JIRA::HTTPError, error)
end
@@ -39,7 +42,8 @@ RSpec.shared_examples 'a service that handles Jira API errors' do
let(:error) { '{"errorMessages":' }
it 'returns the default error message' do
- expect(subject.message).to eq('An error occurred while requesting data from Jira. Check your Jira integration configuration and try again.')
+ error_message = 'An error occurred while requesting data from Jira. Check your %{docs_link_start}Jira integration configuration</a> and try again.' % { docs_link_start: docs_link_start }
+ expect(subject.message).to eq(error_message)
end
end
@@ -47,7 +51,8 @@ RSpec.shared_examples 'a service that handles Jira API errors' do
let(:error) { '{"errorMessages":["<script>alert(true)</script>foo"]}' }
it 'sanitizes it' do
- expect(subject.message).to eq('An error occurred while requesting data from Jira: foo. Check your Jira integration configuration and try again.')
+ error_message = 'An error occurred while requesting data from Jira: foo. Check your %{docs_link_start}Jira integration configuration</a> and try again.' % { docs_link_start: docs_link_start }
+ expect(subject.message).to eq(error_message)
end
end
end
diff --git a/spec/support/shared_examples/services/resource_events/synthetic_notes_builder_shared_examples.rb b/spec/support/shared_examples/services/resource_events/synthetic_notes_builder_shared_examples.rb
new file mode 100644
index 00000000000..716bee39fca
--- /dev/null
+++ b/spec/support/shared_examples/services/resource_events/synthetic_notes_builder_shared_examples.rb
@@ -0,0 +1,25 @@
+# frozen_string_literal: true
+
+RSpec.shared_examples 'filters by paginated notes' do |event_type|
+ let(:event) { create(event_type) } # rubocop:disable Rails/SaveBang
+
+ before do
+ create(event_type, issue: event.issue)
+ end
+
+ it 'only returns given notes' do
+ paginated_notes = { event_type.to_s.pluralize => [double(id: event.id)] }
+ notes = described_class.new(event.issue, user, paginated_notes: paginated_notes).execute
+
+ expect(notes.size).to eq(1)
+ expect(notes.first.event).to eq(event)
+ end
+
+ context 'when paginated notes is empty' do
+ it 'does not return any notes' do
+ notes = described_class.new(event.issue, user, paginated_notes: {}).execute
+
+ expect(notes.size).to eq(0)
+ end
+ end
+end
diff --git a/spec/support/shared_examples/workers/self_monitoring_shared_examples.rb b/spec/support/shared_examples/workers/self_monitoring_shared_examples.rb
index 89c0841fbd6..e6da96e12ec 100644
--- a/spec/support/shared_examples/workers/self_monitoring_shared_examples.rb
+++ b/spec/support/shared_examples/workers/self_monitoring_shared_examples.rb
@@ -17,7 +17,7 @@ end
RSpec.shared_examples 'returns in_progress based on Sidekiq::Status' do
it 'returns true when job is enqueued' do
- jid = described_class.perform_async
+ jid = described_class.with_status.perform_async
expect(described_class.in_progress?(jid)).to eq(true)
end
diff --git a/spec/support/stub_snowplow.rb b/spec/support/stub_snowplow.rb
index a21ce2399d7..c6e3b40972f 100644
--- a/spec/support/stub_snowplow.rb
+++ b/spec/support/stub_snowplow.rb
@@ -8,8 +8,6 @@ module StubSnowplow
host = 'localhost'
# rubocop:disable RSpec/AnyInstanceOf
- allow_any_instance_of(Gitlab::Tracking::Destinations::ProductAnalytics).to receive(:event)
-
allow_any_instance_of(Gitlab::Tracking::Destinations::Snowplow)
.to receive(:emitter)
.and_return(SnowplowTracker::Emitter.new(host, buffer_size: buffer_size))
diff --git a/spec/support/test_reports/test_reports_helper.rb b/spec/support/test_reports/test_reports_helper.rb
index 18b40a20cf1..85483062958 100644
--- a/spec/support/test_reports/test_reports_helper.rb
+++ b/spec/support/test_reports/test_reports_helper.rb
@@ -95,9 +95,9 @@ module TestReportsHelper
<<-EOF.strip_heredoc
junit.framework.AssertionFailedError: expected:&lt;1&gt; but was:&lt;3&gt;
at CalculatorTest.subtractExpression(Unknown Source)
- at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
- at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
- at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
+ at java.base/jdk.internal.database.NativeMethodAccessorImpl.invoke0(Native Method)
+ at java.base/jdk.internal.database.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
+ at java.base/jdk.internal.database.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
EOF
end
end
diff --git a/spec/support/time_travel.rb b/spec/support/time_travel.rb
new file mode 100644
index 00000000000..9dfbfd20524
--- /dev/null
+++ b/spec/support/time_travel.rb
@@ -0,0 +1,21 @@
+# frozen_string_literal: true
+
+require 'active_support/testing/time_helpers'
+
+RSpec.configure do |config|
+ config.include ActiveSupport::Testing::TimeHelpers
+
+ config.around(:example, :freeze_time) do |example|
+ freeze_time { example.run }
+ end
+
+ config.around(:example, :time_travel_to) do |example|
+ date_or_time = example.metadata[:time_travel_to]
+
+ unless date_or_time.respond_to?(:to_time) && date_or_time.to_time.present?
+ raise 'The time_travel_to RSpec metadata must have a Date or Time value.'
+ end
+
+ travel_to(date_or_time) { example.run }
+ end
+end