From 43a25d93ebdabea52f99b05e15b06250cd8f07d7 Mon Sep 17 00:00:00 2001 From: GitLab Bot Date: Wed, 17 May 2023 16:05:49 +0000 Subject: Add latest changes from gitlab-org/gitlab@16-0-stable-ee --- spec/benchmarks/banzai_benchmark.rb | 24 +- spec/bin/sidekiq_cluster_spec.rb | 7 +- spec/channels/awareness_channel_spec.rb | 81 -- .../commands/metrics_server/metrics_server_spec.rb | 2 +- spec/commands/sidekiq_cluster/cli_spec.rb | 121 +- .../layouts/horizontal_section_component_spec.rb | 30 +- spec/components/pajamas/alert_component_spec.rb | 4 +- spec/components/pajamas/avatar_component_spec.rb | 2 +- spec/components/pajamas/banner_component_spec.rb | 10 +- spec/components/pajamas/card_component_spec.rb | 12 +- spec/components/pajamas/checkbox_component_spec.rb | 8 +- .../pajamas/checkbox_tag_component_spec.rb | 8 +- spec/components/pajamas/radio_component_spec.rb | 8 +- .../inject_enterprise_edition_module_spec.rb | 2 +- spec/config/mail_room_spec.rb | 21 +- spec/config/object_store_settings_spec.rb | 18 +- spec/config/settings_spec.rb | 18 +- spec/config/smime_signature_settings_spec.rb | 8 +- .../provider/helpers/contract_source_helper.rb | 5 +- .../provider/contract_source_helper_spec.rb | 8 +- spec/contracts/publish-contracts.sh | 3 +- .../admin/application_settings_controller_spec.rb | 47 +- .../admin/applications_controller_spec.rb | 100 +- spec/controllers/admin/clusters_controller_spec.rb | 45 +- spec/controllers/admin/cohorts_controller_spec.rb | 1 - .../admin/dev_ops_report_controller_spec.rb | 1 - .../admin/instance_review_controller_spec.rb | 2 +- .../admin/integrations_controller_spec.rb | 7 +- .../admin/runner_projects_controller_spec.rb | 18 +- spec/controllers/admin/runners_controller_spec.rb | 47 +- spec/controllers/admin/sessions_controller_spec.rb | 25 +- .../controllers/admin/spam_logs_controller_spec.rb | 10 +- .../admin/usage_trends_controller_spec.rb | 1 - spec/controllers/admin/users_controller_spec.rb | 29 +- spec/controllers/application_controller_spec.rb | 51 +- .../cycle_analytics/value_stream_actions_spec.rb | 3 +- .../concerns/confirm_email_warning_spec.rb | 2 +- .../concerns/content_security_policy_patch_spec.rb | 2 +- spec/controllers/concerns/continue_params_spec.rb | 5 +- ...troller_with_cross_project_access_check_spec.rb | 11 +- spec/controllers/concerns/kas_cookie_spec.rb | 122 ++ .../controllers/concerns/metrics_dashboard_spec.rb | 2 +- .../concerns/product_analytics_tracking_spec.rb | 38 +- spec/controllers/concerns/redis_tracking_spec.rb | 135 -- spec/controllers/concerns/renders_commits_spec.rb | 2 +- spec/controllers/concerns/send_file_upload_spec.rb | 24 +- .../concerns/sorting_preference_spec.rb | 41 +- spec/controllers/confirmations_controller_spec.rb | 72 +- .../dashboard/projects_controller_spec.rb | 46 + spec/controllers/every_controller_spec.rb | 3 +- spec/controllers/explore/groups_controller_spec.rb | 4 +- .../explore/projects_controller_spec.rb | 20 + spec/controllers/graphql_controller_spec.rb | 82 +- .../controllers/groups/children_controller_spec.rb | 12 + .../controllers/groups/clusters_controller_spec.rb | 43 +- ...endency_proxy_for_containers_controller_spec.rb | 2 +- .../groups/group_members_controller_spec.rb | 43 +- .../groups/milestones_controller_spec.rb | 62 +- spec/controllers/groups/runners_controller_spec.rb | 134 +- .../settings/applications_controller_spec.rb | 141 ++- .../settings/integrations_controller_spec.rb | 1 + .../groups/variables_controller_spec.rb | 10 +- spec/controllers/groups_controller_spec.rb | 23 - spec/controllers/help_controller_spec.rb | 27 +- .../import/bitbucket_controller_spec.rb | 33 +- .../import/bitbucket_server_controller_spec.rb | 2 +- .../import/bulk_imports_controller_spec.rb | 65 +- spec/controllers/import/fogbugz_controller_spec.rb | 7 +- spec/controllers/import/gitea_controller_spec.rb | 26 +- spec/controllers/import/github_controller_spec.rb | 114 +- spec/controllers/import/gitlab_controller_spec.rb | 313 ----- .../controllers/import/manifest_controller_spec.rb | 6 +- .../import/phabricator_controller_spec.rb | 83 -- spec/controllers/invites_controller_spec.rb | 20 + .../jira_connect/app_descriptor_controller_spec.rb | 2 +- .../jira_connect/branches_controller_spec.rb | 4 +- .../jira_connect/events_controller_spec.rb | 2 +- .../jira_connect/subscriptions_controller_spec.rb | 22 +- .../oauth/applications_controller_spec.rb | 60 +- .../oauth/authorizations_controller_spec.rb | 3 +- .../omniauth_callbacks_controller_spec.rb | 75 +- spec/controllers/passwords_controller_spec.rb | 3 +- .../profiles/accounts_controller_spec.rb | 16 +- .../profiles/preferences_controller_spec.rb | 31 +- .../profiles/two_factor_auths_controller_spec.rb | 2 +- spec/controllers/profiles_controller_spec.rb | 32 +- .../projects/artifacts_controller_spec.rb | 62 +- .../controllers/projects/badges_controller_spec.rb | 12 +- spec/controllers/projects/blame_controller_spec.rb | 58 +- spec/controllers/projects/blob_controller_spec.rb | 52 +- .../projects/branches_controller_spec.rb | 294 ++--- .../projects/clusters_controller_spec.rb | 58 +- .../controllers/projects/commit_controller_spec.rb | 255 ++-- .../projects/commits_controller_spec.rb | 88 +- .../projects/compare_controller_spec.rb | 27 +- .../projects/cycle_analytics_controller_spec.rb | 7 +- .../projects/deploy_keys_controller_spec.rb | 10 +- .../projects/deployments_controller_spec.rb | 4 +- .../designs/raw_images_controller_spec.rb | 6 +- .../designs/resized_image_controller_spec.rb | 11 +- .../environments/prometheus_api_controller_spec.rb | 2 +- .../environments/sample_metrics_controller_spec.rb | 2 +- .../projects/environments_controller_spec.rb | 170 +-- .../projects/feature_flags_controller_spec.rb | 11 +- .../projects/find_file_controller_spec.rb | 15 +- spec/controllers/projects/forks_controller_spec.rb | 7 +- .../projects/grafana_api_controller_spec.rb | 29 +- .../controllers/projects/graphs_controller_spec.rb | 1 - .../projects/group_links_controller_spec.rb | 2 +- spec/controllers/projects/hooks_controller_spec.rb | 12 +- .../projects/imports_controller_spec.rb | 16 +- .../controllers/projects/issues_controller_spec.rb | 72 +- spec/controllers/projects/jobs_controller_spec.rb | 69 +- .../projects/mattermosts_controller_spec.rb | 20 +- .../merge_requests/conflicts_controller_spec.rb | 84 +- .../merge_requests/creations_controller_spec.rb | 43 +- .../merge_requests/diffs_controller_spec.rb | 21 +- .../merge_requests/drafts_controller_spec.rb | 16 +- .../projects/merge_requests_controller_spec.rb | 159 ++- .../projects/milestones_controller_spec.rb | 21 + spec/controllers/projects/notes_controller_spec.rb | 57 +- spec/controllers/projects/pages_controller_spec.rb | 121 +- .../dashboards_controller_spec.rb | 40 +- .../projects/pipeline_schedules_controller_spec.rb | 6 +- .../projects/pipelines_controller_spec.rb | 242 +--- .../projects/project_members_controller_spec.rb | 8 - .../projects/prometheus/alerts_controller_spec.rb | 5 +- spec/controllers/projects/raw_controller_spec.rb | 10 +- spec/controllers/projects/refs_controller_spec.rb | 13 +- .../registry/repositories_controller_spec.rb | 16 +- .../projects/registry/tags_controller_spec.rb | 29 +- .../projects/releases_controller_spec.rb | 6 +- .../projects/repositories_controller_spec.rb | 10 +- .../projects/runner_projects_controller_spec.rb | 62 + .../projects/runners_controller_spec.rb | 137 +- .../projects/service_desk_controller_spec.rb | 4 +- .../projects/settings/ci_cd_controller_spec.rb | 15 +- .../settings/merge_requests_controller_spec.rb | 11 +- .../settings/operations_controller_spec.rb | 32 +- .../projects/snippets/blobs_controller_spec.rb | 17 +- .../projects/snippets_controller_spec.rb | 11 +- spec/controllers/projects/tree_controller_spec.rb | 38 +- spec/controllers/projects/wikis_controller_spec.rb | 2 +- .../projects/work_items_controller_spec.rb | 156 +++ spec/controllers/projects_controller_spec.rb | 146 +-- .../registrations/welcome_controller_spec.rb | 38 +- spec/controllers/registrations_controller_spec.rb | 231 ++-- .../repositories/git_http_controller_spec.rb | 67 +- spec/controllers/search_controller_spec.rb | 113 +- spec/controllers/sessions_controller_spec.rb | 48 +- spec/controllers/snippets/blobs_controller_spec.rb | 8 +- spec/db/schema_spec.rb | 115 +- spec/deprecation_warnings.rb | 21 + spec/experiments/application_experiment_spec.rb | 8 +- ...ation_for_namespace_creation_experiment_spec.rb | 49 - ...ity_reports_mr_widget_prompt_experiment_spec.rb | 9 - spec/factories/abuse/trust_score.rb | 10 + spec/factories/abuse_reports.rb | 8 + spec/factories/achievements/user_achievements.rb | 14 + spec/factories/airflow/dags.rb | 8 - spec/factories/bulk_import/batch_trackers.rb | 37 + spec/factories/bulk_import/export_batches.rb | 24 + spec/factories/bulk_import/exports.rb | 4 + spec/factories/chat_names.rb | 1 - spec/factories/ci/builds.rb | 12 +- spec/factories/ci/catalog/resources.rb | 7 + spec/factories/ci/pipelines.rb | 12 +- spec/factories/ci/processable.rb | 20 +- spec/factories/ci/reports/security/findings.rb | 1 + spec/factories/ci/reports/security/reports.rb | 13 + spec/factories/ci/runner_machine_builds.rb | 8 + spec/factories/ci/runner_machines.rb | 13 - spec/factories/ci/runner_managers.rb | 13 + spec/factories/ci/runners.rb | 6 + .../ci_access/group_authorizations.rb | 18 + .../ci_access/project_authorizations.rb | 18 + .../user_access/group_authorizations.rb | 10 + .../user_access/project_authorizations.rb | 10 + .../clusters/agents/group_authorizations.rb | 18 - .../clusters/agents/project_authorizations.rb | 18 - spec/factories/clusters/applications/helm.rb | 124 -- spec/factories/clusters/clusters.rb | 15 - .../container_registry/data_repair_detail.rb | 20 + spec/factories/customer_relations/contacts.rb | 4 - spec/factories/customer_relations/organizations.rb | 2 +- spec/factories/design_management/repositories.rb | 7 + spec/factories/draft_note.rb | 4 +- spec/factories/environments.rb | 27 +- .../postgres_async_constraint_validation.rb | 17 + .../postgres_async_foreign_key_validation.rb | 9 - .../background_migration/schema_inconsistencies.rb | 11 + spec/factories/group_members.rb | 16 +- spec/factories/import_failures.rb | 4 + spec/factories/integrations.rb | 50 +- spec/factories/issues.rb | 15 + spec/factories/member_roles.rb | 11 - spec/factories/merge_requests_diff_llm_summary.rb | 10 + spec/factories/ml/candidates.rb | 14 +- spec/factories/notes.rb | 49 +- spec/factories/notes/notes_metadata.rb | 8 + spec/factories/organizations.rb | 16 + spec/factories/packages/debian/component_file.rb | 7 +- spec/factories/packages/debian/distribution.rb | 6 +- spec/factories/packages/debian/file_metadatum.rb | 80 +- spec/factories/packages/npm/metadata_cache.rb | 10 + spec/factories/packages/package_files.rb | 30 +- spec/factories/packages/packages.rb | 7 +- spec/factories/project_error_tracking_settings.rb | 5 + spec/factories/project_hooks.rb | 2 +- spec/factories/project_members.rb | 6 + spec/factories/projects.rb | 38 +- spec/factories/projects/data_transfers.rb | 4 + .../resource_events/abuse_report_events.rb | 9 + .../resource_events/issue_assignment_events.rb | 9 + .../merge_request_assignment_events.rb | 9 + spec/factories/search_index.rb | 10 + spec/factories/serverless/domain.rb | 11 - spec/factories/serverless/domain_cluster.rb | 17 - .../service_desk/custom_email_credential.rb | 11 + .../service_desk/custom_email_verification.rb | 11 + spec/factories/slack_integrations.rb | 25 + spec/factories/u2f_registrations.rb | 12 - spec/factories/users.rb | 17 +- spec/factories/users/banned_users.rb | 7 + spec/factories/work_items.rb | 30 + spec/factories/work_items/resource_link_events.rb | 10 + spec/fast_spec_helper.rb | 26 +- spec/features/abuse_report_spec.rb | 24 +- spec/features/action_cable_logging_spec.rb | 2 +- spec/features/admin/admin_abuse_reports_spec.rb | 260 +++- spec/features/admin/admin_appearance_spec.rb | 268 ++-- spec/features/admin/admin_browse_spam_logs_spec.rb | 2 +- spec/features/admin/admin_deploy_keys_spec.rb | 2 +- spec/features/admin/admin_groups_spec.rb | 4 +- spec/features/admin/admin_health_check_spec.rb | 6 +- spec/features/admin/admin_hook_logs_spec.rb | 2 +- spec/features/admin/admin_hooks_spec.rb | 4 +- spec/features/admin/admin_labels_spec.rb | 7 +- spec/features/admin/admin_mode/login_spec.rb | 344 ++--- spec/features/admin/admin_mode/logout_spec.rb | 4 +- spec/features/admin/admin_mode/workers_spec.rb | 4 +- spec/features/admin/admin_mode_spec.rb | 10 +- spec/features/admin/admin_projects_spec.rb | 44 +- spec/features/admin/admin_runners_spec.rb | 77 +- .../admin/admin_sees_background_migrations_spec.rb | 2 +- spec/features/admin/admin_settings_spec.rb | 69 +- spec/features/admin/admin_system_info_spec.rb | 2 +- .../admin/admin_users_impersonation_tokens_spec.rb | 4 +- .../admin/admin_uses_repository_checks_spec.rb | 2 +- spec/features/admin/broadcast_messages_spec.rb | 73 ++ .../integrations/instance_integrations_spec.rb | 4 + spec/features/admin/users/user_spec.rb | 7 +- spec/features/admin/users/users_spec.rb | 36 +- spec/features/admin_variables_spec.rb | 16 +- .../user_views_alerts_settings_spec.rb | 1 + spec/features/boards/board_filters_spec.rb | 2 +- spec/features/boards/boards_spec.rb | 13 +- spec/features/boards/issue_ordering_spec.rb | 4 +- spec/features/boards/new_issue_spec.rb | 50 +- spec/features/boards/sidebar_spec.rb | 2 +- spec/features/breadcrumbs_schema_markup_spec.rb | 2 +- spec/features/broadcast_messages_spec.rb | 32 +- spec/features/calendar_spec.rb | 381 ++++-- .../features/callouts/registration_enabled_spec.rb | 2 +- spec/features/canonical_link_spec.rb | 2 +- spec/features/clusters/cluster_detail_page_spec.rb | 2 +- .../clusters/cluster_health_dashboard_spec.rb | 22 +- spec/features/clusters/create_agent_spec.rb | 2 +- spec/features/commit_spec.rb | 42 +- .../commits/user_uses_quick_actions_spec.rb | 2 +- spec/features/commits_spec.rb | 28 +- spec/features/contextual_sidebar_spec.rb | 69 - spec/features/cycle_analytics_spec.rb | 9 +- spec/features/dashboard/activity_spec.rb | 2 +- ...ard_with_external_authorization_service_spec.rb | 12 +- spec/features/dashboard/groups_list_spec.rb | 9 +- spec/features/dashboard/issuables_counter_spec.rb | 2 +- spec/features/dashboard/issues_filter_spec.rb | 79 +- spec/features/dashboard/issues_spec.rb | 45 +- spec/features/dashboard/label_filter_spec.rb | 34 - spec/features/dashboard/merge_requests_spec.rb | 4 +- spec/features/dashboard/milestones_spec.rb | 2 +- spec/features/dashboard/projects_spec.rb | 28 +- spec/features/dashboard/root_explore_spec.rb | 6 +- spec/features/dashboard/shortcuts_spec.rb | 2 +- spec/features/dashboard/snippets_spec.rb | 12 +- spec/features/dashboard/todos/todos_spec.rb | 2 +- .../display_system_header_and_footer_bar_spec.rb | 2 +- spec/features/emails/issues_spec.rb | 110 ++ spec/features/expand_collapse_diffs_spec.rb | 14 +- spec/features/explore/groups_spec.rb | 44 +- spec/features/explore/navbar_spec.rb | 13 + .../explore/user_explores_projects_spec.rb | 12 + spec/features/file_uploads/project_import_spec.rb | 4 + .../frequently_visited_projects_and_groups_spec.rb | 4 +- spec/features/global_search_spec.rb | 58 +- spec/features/group_variables_spec.rb | 15 +- spec/features/groups/board_spec.rb | 6 +- spec/features/groups/container_registry_spec.rb | 4 + spec/features/groups/crm/contacts/create_spec.rb | 2 +- spec/features/groups/dependency_proxy_spec.rb | 10 + spec/features/groups/group_runners_spec.rb | 38 +- spec/features/groups/group_settings_spec.rb | 92 +- .../groups/import_export/connect_instance_spec.rb | 2 +- .../groups/integrations/group_integrations_spec.rb | 16 + spec/features/groups/issues_spec.rb | 22 +- spec/features/groups/labels/index_spec.rb | 3 +- .../features/groups/members/filter_members_spec.rb | 2 +- spec/features/groups/members/leave_group_spec.rb | 2 +- spec/features/groups/members/list_members_spec.rb | 2 +- spec/features/groups/members/manage_groups_spec.rb | 4 +- .../features/groups/members/manage_members_spec.rb | 4 +- ...master_adds_member_with_expiration_date_spec.rb | 4 +- .../features/groups/members/search_members_spec.rb | 2 +- spec/features/groups/members/sort_members_spec.rb | 4 +- spec/features/groups/milestone_spec.rb | 6 +- .../groups/milestones/milestone_editing_spec.rb | 18 + spec/features/groups/new_group_page_spec.rb | 50 +- spec/features/groups/packages_spec.rb | 8 +- .../features/groups/settings/access_tokens_spec.rb | 2 +- .../settings/packages_and_registries_spec.rb | 9 + spec/features/groups/show_spec.rb | 2 +- spec/features/groups_spec.rb | 41 + spec/features/help_dropdown_spec.rb | 2 +- spec/features/help_pages_spec.rb | 2 +- spec/features/ide/user_opens_merge_request_spec.rb | 4 + spec/features/ide_spec.rb | 13 +- spec/features/import/manifest_import_spec.rb | 2 + spec/features/incidents/incident_details_spec.rb | 2 + .../incidents/incident_timeline_events_spec.rb | 7 +- .../incidents/user_uses_quick_actions_spec.rb | 2 +- .../incidents/user_views_alert_details_spec.rb | 34 + spec/features/integrations_settings_spec.rb | 29 + spec/features/invites_spec.rb | 47 +- spec/features/issuables/issuable_list_spec.rb | 2 +- .../internal_references_spec.rb | 2 +- .../issuables/markdown_references/jira_spec.rb | 2 +- ..._issue_for_discussions_in_merge_request_spec.rb | 11 +- spec/features/issues/csv_spec.rb | 1 + spec/features/issues/discussion_lock_spec.rb | 3 +- .../issues/filtered_search/dropdown_hint_spec.rb | 4 +- .../issues/filtered_search/filter_issues_spec.rb | 12 +- .../issues/filtered_search/recent_searches_spec.rb | 2 +- .../issues/filtered_search/search_bar_spec.rb | 3 +- .../issues/filtered_search/visual_tokens_spec.rb | 42 +- spec/features/issues/form_spec.rb | 510 ++++++-- spec/features/issues/gfm_autocomplete_spec.rb | 3 + spec/features/issues/incident_issue_spec.rb | 4 +- spec/features/issues/issue_detail_spec.rb | 29 +- spec/features/issues/issue_sidebar_spec.rb | 14 +- spec/features/issues/move_spec.rb | 7 +- spec/features/issues/rss_spec.rb | 12 +- spec/features/issues/service_desk_spec.rb | 4 +- .../issues/user_bulk_edits_issues_labels_spec.rb | 4 +- .../features/issues/user_bulk_edits_issues_spec.rb | 14 +- .../features/issues/user_comments_on_issue_spec.rb | 4 +- .../user_creates_branch_and_merge_request_spec.rb | 24 +- spec/features/issues/user_creates_issue_spec.rb | 89 +- spec/features/issues/user_edits_issue_spec.rb | 43 +- .../issues/user_sorts_issue_comments_spec.rb | 3 +- .../issues/user_toggles_subscription_spec.rb | 4 +- .../issues/user_uses_quick_actions_spec.rb | 2 +- spec/features/jira_connect/branches_spec.rb | 2 +- .../features/jira_oauth_provider_authorize_spec.rb | 35 +- spec/features/labels_hierarchy_spec.rb | 73 +- spec/features/markdown/markdown_spec.rb | 4 +- spec/features/markdown/metrics_spec.rb | 41 +- spec/features/markdown/observability_spec.rb | 124 +- spec/features/markdown/sandboxed_mermaid_spec.rb | 24 + spec/features/merge_request/batch_comments_spec.rb | 4 + .../merge_request/maintainer_edits_fork_spec.rb | 2 +- .../user_accepts_merge_request_spec.rb | 20 +- .../merge_request/user_comments_on_diff_spec.rb | 4 +- .../user_comments_on_merge_request_spec.rb | 2 + .../user_creates_image_diff_notes_spec.rb | 2 +- .../features/merge_request/user_creates_mr_spec.rb | 151 ++- .../user_edits_assignees_sidebar_spec.rb | 4 +- .../merge_request/user_edits_merge_request_spec.rb | 2 + spec/features/merge_request/user_edits_mr_spec.rb | 228 +++- .../user_edits_reviewers_sidebar_spec.rb | 2 - .../user_manages_subscription_spec.rb | 4 +- .../user_merges_only_if_pipeline_succeeds_spec.rb | 160 ++- .../user_merges_when_pipeline_succeeds_spec.rb | 110 +- .../user_opens_checkout_branch_modal_spec.rb | 2 + .../merge_request/user_posts_diff_notes_spec.rb | 2 +- .../merge_request/user_posts_notes_spec.rb | 4 +- .../merge_request/user_resolves_conflicts_spec.rb | 2 +- ...lves_diff_notes_and_discussions_resolve_spec.rb | 2 +- .../user_reverts_merge_request_spec.rb | 7 +- .../user_sees_check_out_branch_modal_spec.rb | 3 + spec/features/merge_request/user_sees_diff_spec.rb | 2 +- .../user_sees_discussions_navigation_spec.rb | 8 +- ...ton_depending_on_unresolved_discussions_spec.rb | 8 +- .../user_sees_merge_request_pipelines_spec.rb | 46 + .../merge_request/user_sees_merge_widget_spec.rb | 7 +- .../merge_request/user_sees_pipelines_spec.rb | 21 +- .../user_sees_real_time_reviewers_spec.rb | 24 + .../merge_request/user_sees_versions_spec.rb | 2 +- .../user_selects_branches_for_new_mr_spec.rb | 2 + .../merge_request/user_uses_quick_actions_spec.rb | 2 +- .../user_views_open_merge_request_spec.rb | 32 +- .../filters_generic_behavior_spec.rb | 2 +- spec/features/merge_requests/rss_spec.rb | 4 +- .../merge_requests/user_exports_as_csv_spec.rb | 1 + .../user_lists_merge_requests_spec.rb | 39 +- .../merge_requests/user_mass_updates_spec.rb | 8 +- .../user_sorts_merge_requests_spec.rb | 2 +- .../milestones/user_deletes_milestone_spec.rb | 2 + spec/features/monitor_sidebar_link_spec.rb | 3 +- spec/features/nav/new_nav_invite_members_spec.rb | 50 + spec/features/nav/new_nav_toggle_spec.rb | 2 +- spec/features/nav/pinned_nav_items_spec.rb | 195 +++ spec/features/nav/top_nav_responsive_spec.rb | 26 +- spec/features/nav/top_nav_spec.rb | 14 +- spec/features/oauth_login_spec.rb | 2 +- spec/features/oauth_registration_spec.rb | 1 - .../populate_new_pipeline_vars_with_params_spec.rb | 2 +- spec/features/profiles/chat_names_spec.rb | 44 +- spec/features/profiles/gpg_keys_spec.rb | 3 +- .../profiles/list_users_comment_template_spec.rb | 21 + .../profiles/list_users_saved_replies_spec.rb | 21 - .../profiles/personal_access_tokens_spec.rb | 2 +- .../profiles/user_creates_comment_template_spec.rb | 29 + .../profiles/user_deletes_comment_template_spec.rb | 28 + .../profiles/user_edit_preferences_spec.rb | 29 - spec/features/profiles/user_edit_profile_spec.rb | 30 +- .../profiles/user_updates_comment_template_spec.rb | 30 + .../profiles/user_uses_comment_template_spec.rb | 29 + .../user_visits_profile_authentication_log_spec.rb | 2 +- spec/features/project_group_variables_spec.rb | 2 +- spec/features/project_variables_spec.rb | 15 +- spec/features/projects/badges/list_spec.rb | 39 +- spec/features/projects/blobs/blame_spec.rb | 43 +- spec/features/projects/blobs/blob_show_spec.rb | 28 +- spec/features/projects/blobs/edit_spec.rb | 6 +- .../user_views_pipeline_editor_button_spec.rb | 2 +- .../projects/branches/user_creates_branch_spec.rb | 6 +- spec/features/projects/branches_spec.rb | 24 + spec/features/projects/ci/editor_spec.rb | 8 +- spec/features/projects/ci/lint_spec.rb | 4 +- spec/features/projects/clusters/gcp_spec.rb | 2 +- spec/features/projects/clusters/user_spec.rb | 2 +- spec/features/projects/commit/cherry_pick_spec.rb | 2 +- .../commit/comments/user_adds_comment_spec.rb | 6 +- .../commit/comments/user_deletes_comments_spec.rb | 4 +- .../commit/comments/user_edits_comments_spec.rb | 2 +- spec/features/projects/commit/diff_notes_spec.rb | 13 +- .../commit/user_comments_on_commit_spec.rb | 6 +- .../projects/commit/user_reverts_commit_spec.rb | 2 +- .../commit/user_sees_pipelines_tab_spec.rb | 58 + spec/features/projects/compare_spec.rb | 19 +- spec/features/projects/container_registry_spec.rb | 21 +- .../environments/environment_metrics_spec.rb | 15 + .../projects/environments/environment_spec.rb | 30 + .../projects/environments/environments_spec.rb | 56 +- .../projects/files/dockerfile_dropdown_spec.rb | 2 +- .../features/projects/files/editing_a_file_spec.rb | 50 +- .../projects/files/gitignore_dropdown_spec.rb | 2 +- .../projects/files/gitlab_ci_yml_dropdown_spec.rb | 2 +- ...to_create_license_file_in_empty_project_spec.rb | 2 +- .../projects/files/user_browses_files_spec.rb | 7 +- .../projects/files/user_creates_files_spec.rb | 4 +- .../projects/files/user_edits_files_spec.rb | 4 +- spec/features/projects/fork_spec.rb | 28 +- .../projects/import_export/export_file_spec.rb | 61 +- .../projects/import_export/import_file_spec.rb | 1 + .../import_export/test_project_export.tar.gz | Bin 3176 -> 4799 bytes .../projects/integrations/apple_app_store_spec.rb | 24 + .../projects/integrations/google_play_spec.rb | 24 + .../integrations/project_integrations_spec.rb | 12 + ...user_activates_mattermost_slash_command_spec.rb | 8 +- .../integrations/user_activates_prometheus_spec.rb | 1 + .../user_activates_slack_notifications_spec.rb | 1 - .../user_activates_slack_slash_command_spec.rb | 2 +- .../user_uses_inherited_settings_spec.rb | 10 +- spec/features/projects/issuable_templates_spec.rb | 2 + .../issues/viewing_relocated_issues_spec.rb | 2 +- ...user_triggers_manual_job_with_variables_spec.rb | 2 +- spec/features/projects/jobs_spec.rb | 19 +- .../projects/labels/update_prioritization_spec.rb | 2 +- .../members/anonymous_user_sees_members_spec.rb | 2 +- .../projects/members/group_members_spec.rb | 2 +- .../members/groups_with_access_list_spec.rb | 4 +- .../projects/members/manage_groups_spec.rb | 4 +- .../projects/members/manage_members_spec.rb | 4 +- ...master_adds_member_with_expiration_date_spec.rb | 4 +- .../projects/members/member_leaves_project_spec.rb | 2 +- spec/features/projects/members/sorting_spec.rb | 4 +- spec/features/projects/members/tabs_spec.rb | 2 +- .../projects/milestones/milestone_editing_spec.rb | 18 + spec/features/projects/navbar_spec.rb | 17 +- spec/features/projects/network_graph_spec.rb | 9 + spec/features/projects/new_project_spec.rb | 106 +- spec/features/projects/packages_spec.rb | 4 +- .../pages/user_edits_lets_encrypt_settings_spec.rb | 12 +- spec/features/projects/pipeline_schedules_spec.rb | 474 ++++--- spec/features/projects/pipelines/pipeline_spec.rb | 55 +- spec/features/projects/pipelines/pipelines_spec.rb | 39 +- .../projects/releases/user_creates_release_spec.rb | 17 +- .../projects/settings/access_tokens_spec.rb | 2 +- .../settings/branch_rules_settings_spec.rb | 11 + .../settings/forked_project_settings_spec.rb | 2 +- .../projects/settings/monitor_settings_spec.rb | 5 +- .../registry_settings_cleanup_tags_spec.rb | 13 +- .../projects/settings/registry_settings_spec.rb | 13 +- .../projects/settings/repository_settings_spec.rb | 39 +- .../projects/settings/service_desk_setting_spec.rb | 10 +- .../settings/user_manages_project_members_spec.rb | 2 +- .../settings/user_renames_a_project_spec.rb | 4 +- .../projects/settings/webhooks_settings_spec.rb | 2 +- .../projects/snippets/create_snippet_spec.rb | 2 +- .../projects/snippets/user_updates_snippet_spec.rb | 2 +- spec/features/projects/terraform_spec.rb | 2 +- .../projects/tree/create_directory_spec.rb | 2 +- spec/features/projects/tree/create_file_spec.rb | 2 +- spec/features/projects/tree/tree_show_spec.rb | 2 +- spec/features/projects/tree/upload_file_spec.rb | 2 +- .../user_changes_project_visibility_spec.rb | 19 - .../projects/user_sees_user_popover_spec.rb | 2 +- spec/features/projects/user_uses_shortcuts_spec.rb | 13 +- .../projects/user_views_empty_project_spec.rb | 2 +- .../projects/work_items/work_item_children_spec.rb | 179 +++ .../features/projects/work_items/work_item_spec.rb | 92 ++ spec/features/protected_branches_spec.rb | 9 + spec/features/protected_tags_spec.rb | 34 +- spec/features/reportable_note/issue_spec.rb | 4 +- spec/features/runners_spec.rb | 51 +- .../features/search/user_searches_for_code_spec.rb | 55 +- .../search/user_uses_header_search_field_spec.rb | 18 +- spec/features/security/admin_access_spec.rb | 2 +- spec/features/security/dashboard_access_spec.rb | 2 +- .../security/group/internal_access_spec.rb | 2 +- .../features/security/group/private_access_spec.rb | 2 +- spec/features/security/group/public_access_spec.rb | 2 +- .../security/project/internal_access_spec.rb | 2 +- .../security/project/private_access_spec.rb | 2 +- .../security/project/public_access_spec.rb | 2 +- .../project/snippet/internal_access_spec.rb | 2 +- .../project/snippet/private_access_spec.rb | 2 +- .../security/project/snippet/public_access_spec.rb | 2 +- spec/features/signed_commits_spec.rb | 9 +- .../snippets/notes_on_personal_snippets_spec.rb | 37 +- spec/features/snippets/show_spec.rb | 9 +- .../features/snippets/user_creates_snippet_spec.rb | 6 +- spec/features/snippets/user_edits_snippet_spec.rb | 2 +- spec/features/tags/developer_creates_tag_spec.rb | 2 +- spec/features/tags/developer_deletes_tag_spec.rb | 22 +- spec/features/tags/developer_views_tags_spec.rb | 1 - .../tags/maintainer_deletes_protected_tag_spec.rb | 7 +- spec/features/topic_show_spec.rb | 2 +- spec/features/u2f_spec.rb | 216 ---- spec/features/unsubscribe_links_spec.rb | 2 +- .../user_can_display_performance_bar_spec.rb | 2 +- spec/features/user_sees_revert_modal_spec.rb | 5 +- spec/features/user_sorts_things_spec.rb | 2 +- spec/features/users/login_spec.rb | 358 ++++-- spec/features/users/show_spec.rb | 74 +- spec/features/users/signup_spec.rb | 18 +- spec/features/webauthn_spec.rb | 249 ++-- spec/features/whats_new_spec.rb | 6 +- .../features/work_items/work_item_children_spec.rb | 136 -- spec/features/work_items/work_item_spec.rb | 37 - spec/finders/abuse_reports_finder_spec.rb | 129 +- spec/finders/access_requests_finder_spec.rb | 9 - .../achievements/achievements_finder_spec.rb | 26 + .../finders/alert_management/alerts_finder_spec.rb | 17 +- .../ci/pipelines_for_merge_request_finder_spec.rb | 68 +- .../clusters/agent_authorizations_finder_spec.rb | 140 -- spec/finders/clusters/agent_tokens_finder_spec.rb | 9 + .../agents/authorizations/ci_access/finder_spec.rb | 140 ++ .../authorizations/user_access/finder_spec.rb | 198 +++ .../concerns/finder_with_group_hierarchy_spec.rb | 76 -- spec/finders/context_commits_finder_spec.rb | 21 +- spec/finders/crm/contacts_finder_spec.rb | 4 +- spec/finders/crm/organizations_finder_spec.rb | 22 +- .../group_data_transfer_finder_spec.rb | 84 ++ .../data_transfer/mocked_transfer_finder_spec.rb | 22 + .../project_data_transfer_finder_spec.rb | 80 ++ spec/finders/deployments_finder_spec.rb | 71 +- spec/finders/fork_targets_finder_spec.rb | 25 +- spec/finders/group_descendants_finder_spec.rb | 22 +- spec/finders/group_members_finder_spec.rb | 149 ++- .../accepting_group_transfers_finder_spec.rb | 14 +- .../accepting_project_creations_finder_spec.rb | 104 ++ .../accepting_project_imports_finder_spec.rb | 105 ++ .../groups/accepting_project_shares_finder_spec.rb | 122 ++ .../accepting_project_transfers_finder_spec.rb | 42 +- spec/finders/groups/user_groups_finder_spec.rb | 20 +- .../issuables/crm_organization_filter_spec.rb | 22 +- spec/finders/members_finder_spec.rb | 39 +- spec/finders/merge_requests_finder_spec.rb | 76 +- spec/finders/milestones_finder_spec.rb | 92 +- spec/finders/notes_finder_spec.rb | 57 +- spec/finders/packages/conan/package_finder_spec.rb | 25 +- .../finders/packages/group_packages_finder_spec.rb | 4 +- spec/finders/packages/npm/package_finder_spec.rb | 8 + spec/finders/pending_todos_finder_spec.rb | 57 +- spec/finders/personal_access_tokens_finder_spec.rb | 2 +- spec/finders/projects_finder_spec.rb | 48 +- spec/finders/serverless_domain_finder_spec.rb | 103 -- spec/finders/snippets_finder_spec.rb | 21 +- spec/finders/template_finder_spec.rb | 14 + spec/finders/users_finder_spec.rb | 8 +- spec/fixtures/api/schemas/cluster_status.json | 11 +- .../fixtures/api/schemas/entities/diff_viewer.json | 6 + spec/fixtures/api/schemas/entities/discussion.json | 11 +- .../api/schemas/internal/pages/lookup_path.json | 66 +- spec/fixtures/api/schemas/public_api/v4/notes.json | 5 +- spec/fixtures/auth_key.p8 | 16 + spec/fixtures/diagram.drawio.svg | 38 + .../valid_reply_with_references_in_comma.eml | 42 + .../import_export/corrupted_project_export.tar.gz | Bin 4603 -> 5288 bytes .../lightweight_project_export.tar.gz | Bin 3758 -> 4950 bytes .../sample_event.yml | 1 - .../sample_event_ee.yml | 1 - .../sample_metric.yml | 1 - .../sample_metric_with_ee.yml | 1 - .../sample_metric_with_name_suggestions.yml | 1 - spec/fixtures/lib/gitlab/email/basic.html | 6 +- .../lib/gitlab/import_export/complex/project.json | 174 ++- .../complex/tree/project/ci_pipelines.ndjson | 8 +- .../complex/tree/project/commit_notes.ndjson | 2 + .../project/design_management_repository.ndjson | 1 + .../tree/project/protected_environments.ndjson | 2 +- .../gitlab/import_export/designs/tree/project.json | 15 + .../designs/tree/project/issues.ndjson | 2 + .../designs/tree/project/project_members.ndjson | 2 + spec/fixtures/markdown.md.erb | 39 + spec/fixtures/packages/debian/README.md | 2 +- .../debian/sample-ddeb_1.2.3~alpha2_amd64.ddeb | Bin 0 -> 1068 bytes .../packages/debian/sample/debian/.gitignore | 2 +- .../fixtures/packages/debian/sample/debian/control | 4 + spec/fixtures/packages/debian/sample/debian/rules | 7 + .../packages/debian/sample_1.2.3~alpha2.dsc | 9 +- .../packages/debian/sample_1.2.3~alpha2.tar.xz | Bin 864 -> 964 bytes .../debian/sample_1.2.3~alpha2_amd64.buildinfo | 306 ++--- .../debian/sample_1.2.3~alpha2_amd64.changes | 21 +- spec/fixtures/packages/npm/metadata.json | 20 + .../npm/payload_with_empty_attachment.json | 29 + spec/fixtures/pages_with_custom_root.zip | Bin 0 -> 631 bytes spec/fixtures/pages_with_custom_root.zip.meta | Bin 0 -> 175 bytes spec/fixtures/pages_with_custom_root.zip.meta0 | Bin 0 -> 197 bytes spec/fixtures/scripts/test_report.json | 2 +- .../feature-branch/gl-sast-report.json | 22 +- .../feature-branch/gl-secret-detection-report.json | 36 +- .../master/gl-sast-missing-scanner.json | 52 +- .../master/gl-sast-report-bandit.json | 13 +- .../master/gl-sast-report-gosec.json | 13 +- .../master/gl-sast-report-minimal.json | 18 +- .../master/gl-sast-report-semgrep-for-bandit.json | 13 +- .../master/gl-sast-report-semgrep-for-gosec.json | 13 +- ...-sast-report-semgrep-for-multiple-findings.json | 13 +- .../security_reports/master/gl-sast-report.json | 22 +- .../master/gl-secret-detection-report.json | 35 +- spec/fixtures/service_account.json | 12 + spec/fixtures/structure.sql | 79 ++ spec/fixtures/work_items_invalid_types.csv | 4 + spec/fixtures/work_items_missing_header.csv | 3 + spec/fixtures/work_items_valid.csv | 3 + spec/fixtures/work_items_valid_types.csv | 3 + spec/frontend/.eslintrc.yml | 1 + spec/frontend/__helpers__/assert_props.js | 41 + .../create_mock_source_editor_extension.js | 12 + .../frontend/__helpers__/experimentation_helper.js | 7 - spec/frontend/__helpers__/fixtures.js | 5 +- spec/frontend/__helpers__/gon_helper.js | 5 + .../__helpers__/init_vue_mr_page_helper.js | 10 +- .../keep_alive_component_helper_spec.js | 4 - spec/frontend/__helpers__/shared_test_setup.js | 16 +- spec/frontend/__helpers__/vue_mock_directive.js | 32 +- spec/frontend/__helpers__/vue_test_utils_helper.js | 18 + .../__helpers__/vue_test_utils_helper_spec.js | 49 + spec/frontend/__helpers__/vuex_action_helper.js | 2 + .../__helpers__/vuex_action_helper_spec.js | 14 + spec/frontend/__helpers__/wait_for_text.js | 2 +- spec/frontend/__mocks__/@gitlab/ui.js | 18 +- spec/frontend/__mocks__/file_mock.js | 2 +- spec/frontend/__mocks__/lodash/debounce.js | 19 +- spec/frontend/__mocks__/lodash/throttle.js | 2 +- spec/frontend/__mocks__/mousetrap/index.js | 6 - .../components/abuse_category_selector_spec.js | 4 - .../components/expires_at_field_spec.js | 4 - .../components/new_access_token_app_spec.js | 5 +- .../access_tokens/components/token_spec.js | 4 - .../access_tokens/components/tokens_app_spec.js | 4 - spec/frontend/access_tokens/index_spec.js | 2 +- spec/frontend/activities_spec.js | 6 +- .../add_context_commits_modal_spec.js.snap | 12 +- .../components/add_context_commits_modal_spec.js | 37 +- .../components/review_tab_container_spec.js | 4 - .../store/actions_spec.js | 2 +- .../components/abuse_report_app_spec.js | 76 ++ .../abuse_report/components/history_items_spec.js | 66 + .../abuse_report/components/report_header_spec.js | 59 + .../components/reported_content_spec.js | 193 +++ .../abuse_report/components/user_detail_spec.js | 66 + .../abuse_report/components/user_details_spec.js | 210 +++ spec/frontend/admin/abuse_report/mock_data.js | 61 + .../components/abuse_report_actions_spec.js | 202 +++ .../components/abuse_report_row_spec.js | 91 ++ .../abuse_reports_filtered_search_bar_spec.js | 225 ++++ .../admin/abuse_reports/components/app_spec.js | 104 ++ spec/frontend/admin/abuse_reports/mock_data.js | 18 + spec/frontend/admin/abuse_reports/utils_spec.js | 31 + .../components/devops_score_callout_spec.js | 4 - .../components/form_spec.js | 4 - .../application_settings/network_outbound_spec.js | 70 + .../components/delete_application_spec.js | 1 - .../components/database_listbox_spec.js | 4 - .../broadcast_messages/components/base_spec.js | 9 +- .../components/message_form_spec.js | 39 +- .../components/messages_table_spec.js | 19 +- .../frontend/admin/broadcast_messages/mock_data.js | 5 +- .../admin/deploy_keys/components/table_spec.js | 10 +- .../components/signup_checkbox_spec.js | 4 - .../components/signup_form_spec.js | 20 +- .../admin/signup_restrictions/mock_data.js | 4 - .../admin/statistics_panel/components/app_spec.js | 4 - .../admin/topics/components/remove_avatar_spec.js | 6 +- .../admin/topics/components/topic_select_spec.js | 1 - .../admin/users/components/actions/actions_spec.js | 13 +- .../actions/delete_with_contributions_spec.js | 12 +- spec/frontend/admin/users/components/app_spec.js | 5 - .../__snapshots__/associations_list_spec.js.snap | 34 - .../associations/associations_list_spec.js | 52 +- .../components/modals/delete_user_modal_spec.js | 13 +- .../admin/users/components/user_actions_spec.js | 19 +- .../admin/users/components/user_avatar_spec.js | 7 +- .../admin/users/components/user_date_spec.js | 5 - .../admin/users/components/users_table_spec.js | 11 +- spec/frontend/admin/users/index_spec.js | 4 - spec/frontend/admin/users/new_spec.js | 7 +- spec/frontend/airflow/dags/components/dags_spec.js | 115 -- spec/frontend/airflow/dags/components/mock_data.js | 67 - .../alert_management_empty_state_spec.js | 6 - .../alert_management_list_wrapper_spec.js | 6 - .../components/alert_management_table_spec.js | 5 +- spec/frontend/alert_spec.js | 276 ++++ .../__snapshots__/alerts_form_spec.js.snap | 34 +- .../components/alert_mapping_builder_spec.js | 9 +- .../alerts_settings/components/alerts_form_spec.js | 6 - .../components/alerts_integrations_list_spec.js | 7 - .../components/alerts_settings_form_spec.js | 20 +- .../components/alerts_settings_wrapper_spec.js | 14 +- .../analytics/components/activity_chart_spec.js | 39 - .../__snapshots__/total_time_spec.js.snap | 28 - .../analytics/cycle_analytics/base_spec.js | 265 ---- .../__snapshots__/total_time_spec.js.snap | 28 + .../cycle_analytics/components/base_spec.js | 283 +++++ .../cycle_analytics/components/filter_bar_spec.js | 228 ++++ .../components/formatted_stage_count_spec.js | 30 + .../components/path_navigation_spec.js | 148 +++ .../cycle_analytics/components/stage_table_spec.js | 366 ++++++ .../cycle_analytics/components/total_time_spec.js | 41 + .../components/value_stream_filters_spec.js | 89 ++ .../components/value_stream_metrics_spec.js | 205 +++ .../analytics/cycle_analytics/filter_bar_spec.js | 229 ---- .../cycle_analytics/formatted_stage_count_spec.js | 34 - .../analytics/cycle_analytics/mock_data.js | 4 +- .../cycle_analytics/path_navigation_spec.js | 150 --- .../analytics/cycle_analytics/stage_table_spec.js | 371 ------ .../cycle_analytics/store/actions_spec.js | 31 +- .../cycle_analytics/store/mutations_spec.js | 13 +- .../analytics/cycle_analytics/total_time_spec.js | 45 - .../analytics/cycle_analytics/utils_spec.js | 30 +- .../cycle_analytics/value_stream_filters_spec.js | 91 -- .../cycle_analytics/value_stream_metrics_spec.js | 185 --- .../components/service_ping_disabled_spec.js | 4 - .../components/activity_chart_spec.js | 34 + .../analytics/shared/components/daterange_spec.js | 15 +- .../shared/components/metric_popover_spec.js | 4 - .../shared/components/metric_tile_spec.js | 10 +- .../components/projects_dropdown_filter_spec.js | 30 +- spec/frontend/analytics/shared/utils_spec.js | 28 + .../analytics/usage_trends/components/app_spec.js | 5 - .../usage_trends/components/usage_counts_spec.js | 4 - .../components/usage_trends_count_chart_spec.js | 5 - .../usage_trends/components/users_chart_spec.js | 5 - .../api/alert_management_alerts_api_spec.js | 3 - spec/frontend/api/groups_api_spec.js | 13 +- spec/frontend/api/packages_api_spec.js | 12 +- spec/frontend/api/projects_api_spec.js | 25 +- spec/frontend/api/tags_api_spec.js | 3 - spec/frontend/api/user_api_spec.js | 26 +- spec/frontend/api_spec.js | 25 +- spec/frontend/approvals/mock_data.js | 10 + spec/frontend/artifacts/components/app_spec.js | 109 -- .../artifacts/components/artifact_row_spec.js | 80 -- .../components/artifacts_table_row_details_spec.js | 123 -- .../artifacts/components/feedback_banner_spec.js | 63 - .../components/job_artifacts_table_spec.js | 363 ------ .../artifacts/graphql/cache_update_spec.js | 67 - .../keep_latest_artifact_checkbox_spec.js | 20 +- .../password/components/password_input_spec.js | 64 + .../components/manage_two_factor_form_spec.js | 25 +- .../authentication/u2f/authenticate_spec.js | 104 -- .../frontend/authentication/u2f/mock_u2f_device.js | 23 - spec/frontend/authentication/u2f/register_spec.js | 84 -- spec/frontend/authentication/u2f/util_spec.js | 61 - .../authentication/webauthn/authenticate_spec.js | 5 +- .../webauthn/components/registration_spec.js | 255 ++++ .../frontend/authentication/webauthn/error_spec.js | 13 +- .../authentication/webauthn/register_spec.js | 5 +- spec/frontend/authentication/webauthn/util_spec.js | 31 +- spec/frontend/awards_handler_spec.js | 10 +- spec/frontend/badges/components/badge_form_spec.js | 1 - .../badges/components/badge_list_row_spec.js | 1 - spec/frontend/badges/components/badge_list_spec.js | 4 - .../badges/components/badge_settings_spec.js | 4 - spec/frontend/badges/components/badge_spec.js | 4 - .../components/diff_file_drafts_spec.js | 4 - .../batch_comments/components/draft_note_spec.js | 4 - .../batch_comments/components/drafts_count_spec.js | 4 - .../components/preview_dropdown_spec.js | 19 +- .../batch_comments/components/preview_item_spec.js | 4 - .../batch_comments/components/review_bar_spec.js | 8 +- .../components/submit_dropdown_spec.js | 21 +- .../stores/modules/batch_comments/actions_spec.js | 6 + .../modules/batch_comments/mutations_spec.js | 26 +- .../components/diagram_performance_warning_spec.js | 4 - .../behaviors/components/json_table_spec.js | 7 +- spec/frontend/behaviors/copy_to_clipboard_spec.js | 2 +- spec/frontend/behaviors/gl_emoji_spec.js | 14 +- .../markdown/highlight_current_user_spec.js | 10 - .../frontend/behaviors/markdown/render_gfm_spec.js | 26 + .../markdown/render_observability_spec.js | 61 +- spec/frontend/behaviors/quick_submit_spec.js | 18 +- spec/frontend/behaviors/requires_input_spec.js | 5 +- .../behaviors/shortcuts/keybindings_spec.js | 6 +- .../behaviors/shortcuts/shortcuts_issuable_spec.js | 7 +- spec/frontend/blame/blame_redirect_spec.js | 5 +- spec/frontend/blame/streaming/index_spec.js | 110 ++ .../__snapshots__/blob_edit_header_spec.js.snap | 2 +- .../blob_header_filepath_spec.js.snap | 2 +- .../blob/components/blob_content_error_spec.js | 4 - spec/frontend/blob/components/blob_content_spec.js | 4 - .../blob/components/blob_edit_header_spec.js | 24 +- .../components/blob_header_default_actions_spec.js | 11 +- .../blob/components/blob_header_filepath_spec.js | 4 - spec/frontend/blob/components/blob_header_spec.js | 170 +-- .../components/blob_header_viewer_switcher_spec.js | 53 +- spec/frontend/blob/components/mock_data.js | 2 + .../blob/components/table_contents_spec.js | 1 - spec/frontend/blob/csv/csv_viewer_spec.js | 4 - spec/frontend/blob/file_template_selector_spec.js | 2 +- spec/frontend/blob/line_highlighter_spec.js | 6 +- .../frontend/blob/notebook/notebook_viever_spec.js | 2 - spec/frontend/blob/pdf/pdf_viewer_spec.js | 5 - .../blob/pipeline_tour_success_modal_spec.js | 1 - spec/frontend/blob/sketch/index_spec.js | 5 +- .../components/popover_spec.js | 5 - spec/frontend/blob_edit/blob_bundle_spec.js | 11 +- spec/frontend/blob_edit/edit_blob_spec.js | 2 +- spec/frontend/boards/board_card_inner_spec.js | 12 +- spec/frontend/boards/board_list_helper.js | 1 + spec/frontend/boards/board_list_spec.js | 124 +- .../components/board_add_new_column_form_spec.js | 124 +- .../boards/components/board_add_new_column_spec.js | 61 +- .../board_add_new_column_trigger_spec.js | 6 +- spec/frontend/boards/components/board_app_spec.js | 51 +- spec/frontend/boards/components/board_card_spec.js | 47 +- .../boards/components/board_column_spec.js | 8 +- .../components/board_configuration_options_spec.js | 8 +- .../components/board_content_sidebar_spec.js | 93 +- .../boards/components/board_content_spec.js | 91 +- .../components/board_filtered_search_spec.js | 52 +- spec/frontend/boards/components/board_form_spec.js | 79 +- .../boards/components/board_list_header_spec.js | 178 ++- .../boards/components/board_new_issue_spec.js | 4 - .../boards/components/board_new_item_spec.js | 4 - .../components/board_settings_sidebar_spec.js | 48 +- .../boards/components/board_top_bar_spec.js | 19 +- .../boards/components/boards_selector_spec.js | 17 +- .../boards/components/config_toggle_spec.js | 4 - .../components/issue_board_filtered_search_spec.js | 16 +- .../boards/components/issue_due_date_spec.js | 4 - .../boards/components/issue_time_estimate_spec.js | 4 - spec/frontend/boards/components/item_count_spec.js | 8 - .../boards/components/new_board_button_spec.js | 6 - .../components/sidebar/board_editable_item_spec.js | 5 - .../sidebar/board_sidebar_time_tracker_spec.js | 5 - .../components/sidebar/board_sidebar_title_spec.js | 118 +- .../boards/components/toggle_focus_spec.js | 6 +- spec/frontend/boards/mock_data.js | 195 ++- spec/frontend/boards/project_select_spec.js | 5 - spec/frontend/boards/stores/actions_spec.js | 22 +- spec/frontend/boards/stores/getters_spec.js | 8 - spec/frontend/bootstrap_linked_tabs_spec.js | 5 +- .../delete_merged_branches_spec.js.snap | 41 +- .../components/delete_branch_button_spec.js | 4 - .../components/delete_branch_modal_spec.js | 94 +- .../components/delete_merged_branches_spec.js | 44 +- .../branches/components/divergence_graph_spec.js | 4 - .../frontend/branches/components/graph_bar_spec.js | 4 - .../branches/components/sort_dropdown_spec.js | 6 - spec/frontend/captcha/captcha_modal_spec.js | 74 +- .../frontend/captcha/init_recaptcha_script_spec.js | 2 +- spec/frontend/ci/artifacts/components/app_spec.js | 118 ++ .../ci/artifacts/components/artifact_row_spec.js | 127 ++ .../components/artifacts_bulk_delete_spec.js | 58 + .../components/artifacts_table_row_details_spec.js | 138 ++ .../artifacts/components/feedback_banner_spec.js | 59 + .../components/job_artifacts_table_spec.js | 684 ++++++++++ .../ci/artifacts/components/job_checkbox_spec.js | 132 ++ .../ci/artifacts/graphql/cache_update_spec.js | 67 + .../frontend/ci/ci_lint/components/ci_lint_spec.js | 1 - .../ci_variable_list/ci_variable_list_spec.js | 10 +- .../native_form_variable_list_spec.js | 5 +- .../components/ci_admin_variables_spec.js | 26 +- .../components/ci_environments_dropdown_spec.js | 153 ++- .../components/ci_group_variables_spec.js | 26 +- .../components/ci_project_variables_spec.js | 31 +- .../components/ci_variable_modal_spec.js | 57 +- .../components/ci_variable_settings_spec.js | 67 +- .../components/ci_variable_shared_spec.js | 749 +++++++---- .../components/ci_variable_table_spec.js | 189 +-- spec/frontend/ci/ci_variable_list/mocks.js | 5 + .../code_snippet_alert/code_snippet_alert_spec.js | 4 - .../components/commit/commit_form_spec.js | 12 +- .../components/commit/commit_section_spec.js | 46 +- .../drawer/cards/first_pipeline_card_spec.js | 4 - .../drawer/cards/getting_started_card_spec.js | 4 - .../cards/pipeline_config_reference_card_spec.js | 6 +- .../drawer/cards/visualize_and_lint_card_spec.js | 4 - .../drawer/pipeline_editor_drawer_spec.js | 4 - .../components/drawer/ui/demo_job_pill_spec.js | 4 - .../editor/ci_config_merged_preview_spec.js | 4 - .../components/editor/ci_editor_header_spec.js | 43 +- .../components/editor/text_editor_spec.js | 76 +- .../components/file-nav/branch_switcher_spec.js | 6 +- .../file-nav/pipeline_editor_file_nav_spec.js | 4 - .../components/file-tree/container_spec.js | 9 +- .../components/file-tree/file_item_spec.js | 4 - .../header/pipeline_editor_header_spec.js | 5 - .../header/pipeline_editor_mini_graph_spec.js | 2 +- .../components/header/pipeline_status_spec.js | 3 +- .../components/header/validation_segment_spec.js | 102 +- .../artifacts_and_cache_item_spec.js | 127 ++ .../accordion_items/image_item_spec.js | 39 + .../accordion_items/job_setup_item_spec.js | 60 + .../accordion_items/rules_item_spec.js | 70 + .../accordion_items/services_item_spec.js | 79 ++ .../job_assistant_drawer_spec.js | 252 +++- .../components/lint/ci_lint_results_spec.js | 4 - .../components/lint/ci_lint_warnings_spec.js | 5 - .../components/pipeline_editor_tabs_spec.js | 7 +- .../components/popovers/file_tree_popover_spec.js | 5 +- .../popovers/validate_pipeline_popover_spec.js | 6 +- .../popovers/walkthrough_popover_spec.js | 6 +- .../ui/confirm_unsaved_changes_dialog_spec.js | 4 +- .../components/ui/editor_tab_spec.js | 4 +- .../ui/pipeline_editor_empty_state_spec.js | 4 - .../components/validate/ci_validate_spec.js | 10 +- .../ci/pipeline_editor/graphql/resolvers_spec.js | 2 +- spec/frontend/ci/pipeline_editor/mock_data.js | 32 +- .../ci/pipeline_editor/pipeline_editor_app_spec.js | 20 +- .../pipeline_editor/pipeline_editor_home_spec.js | 2 +- .../components/pipeline_new_form_spec.js | 113 +- .../pipeline_new/components/refs_dropdown_spec.js | 190 +-- spec/frontend/ci/pipeline_new/mock_data.js | 15 +- .../delete_pipeline_schedule_modal_spec.js | 8 +- .../components/pipeline_schedules_spec.js | 6 +- .../table/cells/pipeline_schedule_actions_spec.js | 20 +- .../cells/pipeline_schedule_last_pipeline_spec.js | 4 - .../table/cells/pipeline_schedule_next_run_spec.js | 4 - .../table/cells/pipeline_schedule_owner_spec.js | 4 - .../table/cells/pipeline_schedule_target_spec.js | 4 - .../table/pipeline_schedules_table_spec.js | 7 +- .../components/take_ownership_modal_legacy_spec.js | 14 +- .../components/take_ownership_modal_spec.js | 4 +- spec/frontend/ci/pipeline_schedules/mock_data.js | 2 + .../components/codequality_issue_body_spec.js | 9 +- .../reports/components/grouped_issues_list_spec.js | 4 - .../reports/components/issue_status_icon_spec.js | 5 - .../ci/reports/components/report_link_spec.js | 4 - .../ci/reports/components/report_section_spec.js | 4 - .../ci/reports/components/summary_row_spec.js | 5 - .../admin_new_runner_app_spec.js | 127 +- .../admin_register_runner_app_spec.js | 122 ++ .../admin_runner_show_app_spec.js | 15 +- .../runner/admin_runners/admin_runners_app_spec.js | 44 +- .../components/cells/runner_actions_cell_spec.js | 4 - .../components/cells/runner_owner_cell_spec.js | 6 +- .../components/cells/runner_status_cell_spec.js | 12 +- .../components/cells/runner_summary_cell_spec.js | 58 +- .../components/cells/runner_summary_field_spec.js | 6 +- .../registration/__snapshots__/utils_spec.js.snap | 201 +++ .../components/registration/cli_command_spec.js | 39 + .../registration/platforms_drawer_spec.js | 108 ++ .../registration_compatibility_alert_spec.js | 53 + .../registration/registration_dropdown_spec.js | 149 ++- .../registration_feedback_banner_spec.js | 52 + .../registration/registration_instructions_spec.js | 326 +++++ .../registration_token_reset_dropdown_item_spec.js | 16 +- .../registration/registration_token_spec.js | 46 +- .../runner/components/registration/utils_spec.js | 94 ++ .../runner/components/runner_assigned_item_spec.js | 4 - .../runner/components/runner_bulk_delete_spec.js | 18 +- .../runner/components/runner_create_form_spec.js | 189 +++ .../runner/components/runner_delete_button_spec.js | 24 +- .../ci/runner/components/runner_details_spec.js | 4 - .../runner/components/runner_edit_button_spec.js | 6 +- .../components/runner_filtered_search_bar_spec.js | 18 +- .../ci/runner/components/runner_groups_spec.js | 4 - .../ci/runner/components/runner_header_spec.js | 4 - .../components/runner_jobs_empty_state_spec.js | 35 + .../ci/runner/components/runner_jobs_spec.js | 16 +- .../ci/runner/components/runner_jobs_table_spec.js | 4 - .../components/runner_list_empty_state_spec.js | 78 +- .../ci/runner/components/runner_list_spec.js | 6 +- .../components/runner_membership_toggle_spec.js | 4 - .../ci/runner/components/runner_pagination_spec.js | 4 - .../runner/components/runner_pause_button_spec.js | 12 +- .../runner/components/runner_paused_badge_spec.js | 6 +- .../runner_platforms_radio_group_spec.js | 14 +- .../components/runner_platforms_radio_spec.js | 4 +- .../ci/runner/components/runner_projects_spec.js | 9 +- .../runner/components/runner_status_badge_spec.js | 4 +- .../ci/runner/components/runner_tag_spec.js | 8 +- .../ci/runner/components/runner_tags_spec.js | 4 - .../ci/runner/components/runner_type_badge_spec.js | 9 +- .../ci/runner/components/runner_type_tabs_spec.js | 7 +- .../runner/components/runner_update_form_spec.js | 14 +- .../components/search_tokens/tag_token_spec.js | 5 +- .../ci/runner/components/stat/runner_count_spec.js | 14 +- .../components/stat/runner_single_stat_spec.js | 4 - .../ci/runner/components/stat/runner_stats_spec.js | 4 - .../group_new_runner_app_spec.js | 124 ++ .../group_register_runner_app_spec.js | 120 ++ .../group_runner_show_app_spec.js | 13 +- .../runner/group_runners/group_runners_app_spec.js | 89 +- .../show_alert_from_local_storage_spec.js | 4 +- spec/frontend/ci/runner/mock_data.js | 138 +- .../project_new_runner_app_spec.js | 125 ++ .../project_register_runner_app_spec.js | 120 ++ .../ci/runner/runner_edit/runner_edit_app_spec.js | 5 +- .../frontend/ci/runner/runner_search_utils_spec.js | 5 +- spec/frontend/ci/runner/sentry_utils_spec.js | 2 +- .../metadata/__snapshots__/modal_spec.js.snap | 6 +- .../components/metadata/button_spec.js | 4 - .../components/metadata/modal_spec.js | 1 - .../components/secure_files_list_spec.js | 13 +- spec/frontend/ci_secure_files/mock_data.js | 4 +- .../agents/components/activity_events_list_spec.js | 4 - .../components/activity_history_item_spec.js | 4 - .../agent_integration_status_row_spec.js | 4 - .../agents/components/create_token_button_spec.js | 8 +- .../agents/components/create_token_modal_spec.js | 7 +- .../agents/components/integration_status_spec.js | 4 - .../agents/components/revoke_token_button_spec.js | 10 +- .../clusters/agents/components/show_spec.js | 7 +- .../clusters/agents/components/token_table_spec.js | 4 - spec/frontend/clusters/clusters_bundle_spec.js | 5 +- .../__snapshots__/new_cluster_spec.js.snap | 2 +- .../remove_cluster_confirmation_spec.js.snap | 209 +++ .../clusters/components/new_cluster_spec.js | 4 - .../components/remove_cluster_confirmation_spec.js | 22 +- .../forms/components/integration_form_spec.js | 31 +- .../components/agent_empty_state_spec.js | 6 - .../clusters_list/components/agent_table_spec.js | 204 +-- .../clusters_list/components/agent_token_spec.js | 4 - .../clusters_list/components/agents_spec.js | 2 - .../components/ancestor_notice_spec.js | 4 - .../components/clusters_actions_spec.js | 5 +- .../components/clusters_empty_state_spec.js | 4 - .../components/clusters_main_view_spec.js | 4 - .../clusters_list/components/clusters_spec.js | 5 +- .../components/clusters_view_all_spec.js | 4 - .../components/delete_agent_button_spec.js | 9 +- .../components/install_agent_modal_spec.js | 5 +- .../frontend/clusters_list/components/mock_data.js | 108 +- .../components/node_error_help_text_spec.js | 4 - spec/frontend/clusters_list/store/actions_spec.js | 6 +- .../code_navigation/components/app_spec.js | 4 - .../code_navigation/components/popover_spec.js | 4 - spec/frontend/code_review/signals_spec.js | 145 +++ .../__snapshots__/list_item_spec.js.snap | 140 ++ .../comment_templates/components/form_spec.js | 145 +++ .../comment_templates/components/list_item_spec.js | 154 +++ .../comment_templates/components/list_spec.js | 46 + .../frontend/comment_templates/pages/index_spec.js | 45 + .../commit/commit_box_pipeline_mini_graph_spec.js | 18 +- .../commit_pipeline_status_component_spec.js | 11 +- .../components/commit_box_pipeline_status_spec.js | 16 +- .../commit/components/signature_badge_spec.js | 134 ++ .../components/x509_certificate_details_spec.js | 36 + spec/frontend/commit/mock_data.js | 31 + .../commit/pipelines/pipelines_table_spec.js | 118 +- .../commons/nav/user_merge_requests_spec.js | 33 + .../components/project_form_group_spec.js | 1 - .../__snapshots__/toolbar_button_spec.js.snap | 2 +- .../__snapshots__/toolbar_link_button_spec.js.snap | 33 - .../components/bubble_menus/bubble_menu_spec.js | 6 +- .../bubble_menus/code_block_bubble_menu_spec.js | 10 +- .../bubble_menus/formatting_bubble_menu_spec.js | 91 -- .../bubble_menus/link_bubble_menu_spec.js | 101 +- .../bubble_menus/media_bubble_menu_spec.js | 184 ++- .../components/content_editor_alert_spec.js | 6 +- .../components/content_editor_spec.js | 70 +- .../components/editor_state_observer_spec.js | 4 - .../components/formatting_toolbar_spec.js | 25 +- .../components/loading_indicator_spec.js | 4 - .../components/suggestions_dropdown_spec.js | 22 +- .../components/toolbar_attachment_button_spec.js | 60 + .../components/toolbar_button_spec.js | 6 +- .../components/toolbar_image_button_spec.js | 97 -- .../components/toolbar_link_button_spec.js | 224 ---- .../components/toolbar_more_dropdown_spec.js | 42 +- .../components/toolbar_table_button_spec.js | 1 - .../components/toolbar_text_style_dropdown_spec.js | 5 - .../__snapshots__/table_of_contents_spec.js.snap | 52 +- .../components/wrappers/code_block_spec.js | 8 +- .../components/wrappers/details_spec.js | 6 +- .../wrappers/footnote_definition_spec.js | 6 +- .../components/wrappers/label_spec.js | 36 - .../components/wrappers/reference_label_spec.js | 32 + .../components/wrappers/reference_spec.js | 46 + .../components/wrappers/table_cell_base_spec.js | 32 +- .../components/wrappers/table_cell_body_spec.js | 6 +- .../components/wrappers/table_cell_header_spec.js | 6 +- .../components/wrappers/table_of_contents_spec.js | 6 +- .../content_editor/extensions/attachment_spec.js | 556 +++++++- .../extensions/drawio_diagram_spec.js | 103 ++ .../content_editor/extensions/link_spec.js | 5 - .../extensions/paste_markdown_spec.js | 54 +- .../content_editor/markdown_snapshot_spec.js | 6 +- .../remark_markdown_processing_spec.js | 2 +- .../render_html_and_json_for_all_examples.js | 2 +- .../content_editor/services/content_editor_spec.js | 4 +- .../services/create_content_editor_spec.js | 18 +- .../services/gl_api_markdown_deserializer_spec.js | 24 +- .../services/markdown_serializer_spec.js | 112 +- .../track_input_rules_and_shortcuts_spec.js | 4 +- spec/frontend/content_editor/test_constants.js | 12 + spec/frontend/content_editor/test_utils.js | 27 + .../__snapshots__/contributors_spec.js.snap | 66 +- .../contributors/component/contributors_spec.js | 6 +- spec/frontend/contributors/store/actions_spec.js | 6 +- spec/frontend/create_item_dropdown_spec.js | 5 +- spec/frontend/crm/contact_form_wrapper_spec.js | 1 - spec/frontend/crm/contacts_root_spec.js | 1 - spec/frontend/crm/crm_form_spec.js | 4 - .../frontend/crm/organization_form_wrapper_spec.js | 4 - spec/frontend/crm/organizations_root_spec.js | 1 - .../components/custom_metrics_form_fields_spec.js | 3 +- .../components/custom_metrics_form_spec.js | 4 - .../components/deploy_freeze_modal_spec.js | 9 +- .../components/deploy_freeze_settings_spec.js | 5 - .../components/deploy_freeze_table_spec.js | 5 - spec/frontend/deploy_freeze/store/actions_spec.js | 4 +- spec/frontend/deploy_keys/components/app_spec.js | 1 - spec/frontend/deploy_keys/components/key_spec.js | 38 +- .../deploy_keys/components/keys_panel_spec.js | 5 - .../components/new_deploy_token_spec.js | 51 +- .../deploy_tokens/components/revoke_button_spec.js | 4 - spec/frontend/deprecated_jquery_dropdown_spec.js | 5 +- .../components/delete_button_spec.js | 6 +- .../__snapshots__/design_note_spec.js.snap | 3 + .../design_notes/design_discussion_spec.js | 170 ++- .../design_notes/design_note_signed_out_spec.js | 4 - .../components/design_notes/design_note_spec.js | 56 +- .../design_notes/design_reply_form_spec.js | 258 ++-- .../design_notes/toggle_replies_widget_spec.js | 4 - .../components/design_overlay_spec.js | 48 +- .../components/design_presentation_spec.js | 6 - .../components/design_scaler_spec.js | 7 +- .../components/design_sidebar_spec.js | 10 +- .../components/design_todo_button_spec.js | 6 +- .../design_management/components/image_spec.js | 4 - .../list/__snapshots__/item_spec.js.snap | 10 +- .../design_management/components/list/item_spec.js | 4 - .../__snapshots__/design_navigation_spec.js.snap | 39 - .../components/toolbar/design_navigation_spec.js | 71 +- .../components/toolbar/index_spec.js | 46 +- .../components/upload/button_spec.js | 4 - .../upload/design_version_dropdown_spec.js | 49 +- .../components/upload/mock_data/all_versions.js | 20 - .../design_management/mock_data/all_versions.js | 8 +- .../design_management/mock_data/apollo_mock.js | 205 ++- .../design_management/mock_data/project.js | 17 + .../pages/__snapshots__/index_spec.js.snap | 8 +- .../pages/design/__snapshots__/index_spec.js.snap | 4 +- .../design_management/pages/design/index_spec.js | 83 +- .../frontend/design_management/pages/index_spec.js | 54 +- spec/frontend/design_management/router_spec.js | 6 - .../design_management/utils/cache_update_spec.js | 4 +- spec/frontend/diffs/components/app_spec.js | 135 +- .../components/collapsed_files_warning_spec.js | 4 - spec/frontend/diffs/components/commit_item_spec.js | 27 +- .../components/compare_dropdown_layout_spec.js | 5 - .../diffs/components/compare_versions_spec.js | 24 +- .../components/diff_code_quality_item_spec.js | 66 + .../diffs/components/diff_code_quality_spec.js | 44 +- .../frontend/diffs/components/diff_content_spec.js | 5 - .../diffs/components/diff_discussion_reply_spec.js | 4 - .../diffs/components/diff_discussions_spec.js | 4 - .../diffs/components/diff_file_header_spec.js | 10 +- .../diffs/components/diff_file_row_spec.js | 4 - spec/frontend/diffs/components/diff_file_spec.js | 40 +- .../diffs/components/diff_gutter_avatars_spec.js | 4 - .../diffs/components/diff_line_note_form_spec.js | 17 - spec/frontend/diffs/components/diff_row_spec.js | 4 - spec/frontend/diffs/components/diff_view_spec.js | 19 +- .../diffs/components/hidden_files_warning_spec.js | 8 +- .../diffs/components/image_diff_overlay_spec.js | 4 - .../components/merge_conflict_warning_spec.js | 4 - spec/frontend/diffs/components/no_changes_spec.js | 5 - .../diffs/components/settings_dropdown_spec.js | 1 - .../__snapshots__/findings_drawer_spec.js.snap | 126 ++ .../components/shared/findings_drawer_spec.js | 19 + spec/frontend/diffs/components/tree_list_spec.js | 83 +- spec/frontend/diffs/create_diffs_store.js | 2 + spec/frontend/diffs/mock_data/diff_code_quality.js | 5 + spec/frontend/diffs/mock_data/findings_drawer.js | 21 + spec/frontend/diffs/store/actions_spec.js | 499 +++++++- spec/frontend/diffs/store/getters_spec.js | 25 +- spec/frontend/diffs/store/mutations_spec.js | 9 +- spec/frontend/diffs/store/utils_spec.js | 57 + spec/frontend/diffs/utils/merge_request_spec.js | 94 +- .../frontend/diffs/utils/tree_worker_utils_spec.js | 30 + spec/frontend/drawio/content_editor_facade_spec.js | 138 ++ spec/frontend/drawio/drawio_editor_spec.js | 479 +++++++ .../drawio/markdown_field_editor_facade_spec.js | 148 +++ spec/frontend/dropzone_input_spec.js | 7 +- spec/frontend/editor/components/helpers.js | 3 +- .../source_editor_toolbar_button_spec.js | 36 +- .../components/source_editor_toolbar_spec.js | 37 +- spec/frontend/editor/schema/ci/ci_schema_spec.js | 12 +- .../ci/yaml_tests/negative_tests/rules_needs.yml | 46 + .../ci/yaml_tests/negative_tests/services.yml | 38 + .../ci/yaml_tests/positive_tests/rules_needs.yml | 32 + .../ci/yaml_tests/positive_tests/services.yml | 31 + .../editor/source_editor_ci_schema_ext_spec.js | 11 +- .../editor/source_editor_extension_base_spec.js | 112 +- .../editor/source_editor_markdown_ext_spec.js | 25 +- .../source_editor_markdown_livepreview_ext_spec.js | 106 +- .../editor/source_editor_webide_ext_spec.js | 1 - spec/frontend/editor/utils_spec.js | 30 +- .../emoji/awards_app/store/actions_spec.js | 4 +- spec/frontend/emoji/components/category_spec.js | 21 +- spec/frontend/emoji/components/emoji_group_spec.js | 4 - spec/frontend/emoji/components/emoji_list_spec.js | 33 +- spec/frontend/environment.js | 19 +- spec/frontend/environments/canary_ingress_spec.js | 10 +- .../environments/canary_update_modal_spec.js | 10 +- .../environments/confirm_rollback_modal_spec.js | 36 +- .../environments/delete_environment_modal_spec.js | 6 +- .../environments/deploy_board_component_spec.js | 4 +- .../environments/deploy_freeze_alert_spec.js | 111 ++ .../frontend/environments/edit_environment_spec.js | 5 +- spec/frontend/environments/empty_state_spec.js | 69 +- .../environments/enable_review_app_modal_spec.js | 6 +- .../environments/environment_actions_spec.js | 115 +- .../components/deployment_actions_spec.js | 119 +- .../environment_details/deployments_table_spec.js | 58 + .../environments/environment_details/index_spec.js | 109 ++ .../environments/environment_details/page_spec.js | 69 - .../environments/environment_external_url_spec.js | 33 +- .../environments/environment_folder_spec.js | 4 +- .../frontend/environments/environment_form_spec.js | 20 +- .../frontend/environments/environment_item_spec.js | 34 +- spec/frontend/environments/environment_pin_spec.js | 12 - .../frontend/environments/environment_stop_spec.js | 2 +- .../environments/environment_table_spec.js | 8 - .../frontend/environments/environments_app_spec.js | 16 +- .../environments_detail_header_spec.js | 57 +- .../environments/environments_folder_view_spec.js | 1 - .../folder/environments_folder_view_spec.js | 18 - spec/frontend/environments/graphql/mock_data.js | 109 ++ .../environments/graphql/resolvers_spec.js | 182 ++- ...loyment_data_transformation_helper_spec.js.snap | 34 + .../environments/kubernetes_agent_info_spec.js | 124 ++ .../environments/kubernetes_overview_spec.js | 131 ++ spec/frontend/environments/kubernetes_pods_spec.js | 114 ++ .../environments/kubernetes_summary_spec.js | 115 ++ spec/frontend/environments/kubernetes_tabs_spec.js | 168 +++ spec/frontend/environments/mock_data.js | 3 + .../environments/new_environment_item_spec.js | 127 +- spec/frontend/environments/new_environment_spec.js | 5 +- .../stop_stale_environments_modal_spec.js | 10 +- .../components/error_details_info_spec.js | 190 +++ .../components/error_details_spec.js | 132 +- .../components/error_tracking_actions_spec.js | 6 - .../components/error_tracking_list_spec.js | 49 +- .../components/stacktrace_entry_spec.js | 6 - .../error_tracking/components/stacktrace_spec.js | 6 - .../error_tracking/events_tracking_spec.js | 16 + spec/frontend/error_tracking/store/actions_spec.js | 4 +- .../error_tracking/store/details/actions_spec.js | 6 +- .../error_tracking/store/list/actions_spec.js | 6 +- spec/frontend/error_tracking/utils_spec.js | 16 - .../error_tracking_settings/components/app_spec.js | 8 +- .../components/error_tracking_form_spec.js | 6 - .../components/project_dropdown_spec.js | 6 - .../components/gitlab_experiment_spec.js | 7 - spec/frontend/experimentation/utils_spec.js | 3 - .../configure_feature_flags_modal_spec.js | 19 +- .../components/edit_feature_flag_spec.js | 5 - .../feature_flags/components/empty_state_spec.js | 8 - .../components/environments_dropdown_spec.js | 1 - .../feature_flags/components/feature_flags_spec.js | 64 +- .../components/feature_flags_table_spec.js | 48 +- .../frontend/feature_flags/components/form_spec.js | 4 - .../components/new_environments_dropdown_spec.js | 4 - .../components/new_feature_flag_spec.js | 8 - .../components/strategies/flexible_rollout_spec.js | 8 - .../strategies/parameter_form_group_spec.js | 8 - .../components/strategies/percent_rollout_spec.js | 8 - .../components/strategies/users_with_id_spec.js | 8 - .../components/strategy_parameters_spec.js | 8 - .../feature_flags/components/strategy_spec.js | 11 - .../feature_highlight_helper_spec.js | 6 +- .../feature_highlight_popover_spec.js | 5 - .../recent_searches_dropdown_content_spec.js | 5 - .../frontend/filtered_search/dropdown_user_spec.js | 11 +- .../filtered_search/dropdown_utils_spec.js | 7 +- .../filtered_search_manager_spec.js | 4 +- .../filtered_search/visual_token_value_spec.js | 4 +- spec/frontend/fixtures/abuse_reports.rb | 2 + spec/frontend/fixtures/api_deploy_keys.rb | 5 +- spec/frontend/fixtures/api_projects.rb | 15 +- spec/frontend/fixtures/comment_templates.rb | 74 ++ spec/frontend/fixtures/environments.rb | 2 +- spec/frontend/fixtures/issues.rb | 9 - spec/frontend/fixtures/job_artifacts.rb | 2 +- spec/frontend/fixtures/jobs.rb | 84 +- spec/frontend/fixtures/merge_requests.rb | 6 +- spec/frontend/fixtures/metrics_dashboard.rb | 1 + spec/frontend/fixtures/milestones.rb | 43 + spec/frontend/fixtures/pipelines.rb | 25 + spec/frontend/fixtures/projects.rb | 2 +- spec/frontend/fixtures/prometheus_integration.rb | 1 + spec/frontend/fixtures/runner.rb | 48 +- spec/frontend/fixtures/saved_replies.rb | 46 - spec/frontend/fixtures/startup_css.rb | 17 +- .../fixtures/static/oauth_remember_me.html | 2 +- .../fixtures/static/search_autocomplete.html | 15 - spec/frontend/fixtures/timelogs.rb | 53 + spec/frontend/fixtures/u2f.rb | 48 - spec/frontend/fixtures/users.rb | 75 ++ spec/frontend/fixtures/webauthn.rb | 1 + spec/frontend/flash_spec.js | 276 ---- .../frontend/frequent_items/components/app_spec.js | 2 - .../components/frequent_items_list_item_spec.js | 2 - .../components/frequent_items_list_spec.js | 6 +- spec/frontend/frequent_items/store/actions_spec.js | 1 - spec/frontend/gfm_auto_complete_spec.js | 5 +- .../new/pages/pages_pipeline_wizard_spec.js | 8 +- .../components/gitlab_version_check_badge_spec.js | 1 - spec/frontend/gl_field_errors_spec.js | 5 +- spec/frontend/google_cloud/aiml/panel_spec.js | 43 + .../google_cloud/aiml/service_table_spec.js | 34 + .../components/google_cloud_menu_spec.js | 11 +- .../components/incubation_banner_spec.js | 4 - .../google_cloud/components/revoke_oauth_spec.js | 4 - .../google_cloud/configuration/panel_spec.js | 4 - .../cloudsql/create_instance_form_spec.js | 4 - .../databases/cloudsql/instance_table_spec.js | 4 - spec/frontend/google_cloud/databases/panel_spec.js | 4 - .../google_cloud/databases/service_table_spec.js | 4 - .../google_cloud/deployments/panel_spec.js | 4 - .../google_cloud/deployments/service_table_spec.js | 4 - .../frontend/google_cloud/gcp_regions/form_spec.js | 4 - .../frontend/google_cloud/gcp_regions/list_spec.js | 4 - .../google_cloud/service_accounts/form_spec.js | 4 - .../google_cloud/service_accounts/list_spec.js | 4 - spec/frontend/google_tag_manager/index_spec.js | 4 - .../components/grafana_integration_spec.js | 13 +- spec/frontend/graphql_shared/utils_spec.js | 124 +- .../components/shared_runners_form_spec.js | 69 +- spec/frontend/groups/components/app_spec.js | 15 +- .../archived_projects_empty_state_spec.js | 4 +- .../shared_projects_empty_state_spec.js | 4 +- .../subgroups_and_projects_empty_state_spec.js | 5 +- .../groups/components/group_folder_spec.js | 4 - spec/frontend/groups/components/group_item_spec.js | 4 - .../groups/components/group_name_and_path_spec.js | 4 +- spec/frontend/groups/components/groups_spec.js | 6 +- .../components/invite_members_banner_spec.js | 9 - .../groups/components/item_actions_spec.js | 5 - spec/frontend/groups/components/item_caret_spec.js | 7 - spec/frontend/groups/components/item_stats_spec.js | 7 - .../groups/components/item_stats_value_spec.js | 7 - .../groups/components/item_type_icon_spec.js | 7 - .../components/new_top_level_group_alert_spec.js | 4 - .../groups/components/overview_tabs_spec.js | 2 +- .../groups/components/transfer_group_form_spec.js | 6 +- .../components/group_settings_readme_spec.js | 112 ++ spec/frontend/groups/settings/mock_data.js | 6 + .../components/transfer_locations_spec.js | 4 - spec/frontend/header_search/components/app_spec.js | 90 +- .../header_search_autocomplete_items_spec.js | 11 +- .../components/header_search_default_items_spec.js | 4 - .../components/header_search_scoped_items_spec.js | 7 +- spec/frontend/header_search/init_spec.js | 18 - spec/frontend/header_search/mock_data.js | 10 +- spec/frontend/header_search/store/actions_spec.js | 2 +- spec/frontend/header_search/store/getters_spec.js | 7 + spec/frontend/header_spec.js | 6 +- .../helpers/init_simple_app_helper_spec.js | 6 +- spec/frontend/helpers/startup_css_helper_spec.js | 7 - spec/frontend/ide/components/activity_bar_spec.js | 59 +- spec/frontend/ide/components/branches/item_spec.js | 4 - .../ide/components/branches/search_list_spec.js | 5 - .../ide/components/cannot_push_code_alert_spec.js | 6 +- .../ide/components/commit_sidebar/actions_spec.js | 4 - .../commit_sidebar/editor_header_spec.js | 39 +- .../components/commit_sidebar/empty_state_spec.js | 4 - .../ide/components/commit_sidebar/form_spec.js | 27 +- .../components/commit_sidebar/list_item_spec.js | 4 - .../ide/components/commit_sidebar/list_spec.js | 6 +- .../commit_sidebar/message_field_spec.js | 4 - .../new_merge_request_option_spec.js | 8 +- .../components/commit_sidebar/radio_group_spec.js | 6 +- .../commit_sidebar/success_message_spec.js | 4 - spec/frontend/ide/components/error_message_spec.js | 5 - .../frontend/ide/components/file_row_extra_spec.js | 2 - .../ide/components/file_templates/bar_spec.js | 4 - .../ide/components/file_templates/dropdown_spec.js | 5 - spec/frontend/ide/components/ide_file_row_spec.js | 5 - .../ide/components/ide_project_header_spec.js | 4 - spec/frontend/ide/components/ide_review_spec.js | 6 +- spec/frontend/ide/components/ide_side_bar_spec.js | 5 - .../ide/components/ide_sidebar_nav_spec.js | 11 +- spec/frontend/ide/components/ide_spec.js | 13 +- .../frontend/ide/components/ide_status_bar_spec.js | 4 - .../ide/components/ide_status_list_spec.js | 3 - spec/frontend/ide/components/ide_status_mr_spec.js | 4 - spec/frontend/ide/components/ide_tree_list_spec.js | 4 - spec/frontend/ide/components/ide_tree_spec.js | 74 +- .../ide/components/jobs/detail/description_spec.js | 4 - .../components/jobs/detail/scroll_button_spec.js | 6 +- spec/frontend/ide/components/jobs/detail_spec.js | 16 +- spec/frontend/ide/components/jobs/item_spec.js | 4 - spec/frontend/ide/components/jobs/list_spec.js | 5 - spec/frontend/ide/components/jobs/stage_spec.js | 5 - .../ide/components/merge_requests/item_spec.js | 5 - .../ide/components/merge_requests/list_spec.js | 5 - .../ide/components/nav_dropdown_button_spec.js | 4 - spec/frontend/ide/components/nav_dropdown_spec.js | 4 - .../ide/components/new_dropdown/button_spec.js | 4 - .../ide/components/new_dropdown/index_spec.js | 60 +- .../ide/components/new_dropdown/modal_spec.js | 21 +- .../ide/components/new_dropdown/upload_spec.js | 60 +- .../components/panes/collapsible_sidebar_spec.js | 5 - spec/frontend/ide/components/panes/right_spec.js | 5 - .../ide/components/pipelines/empty_state_spec.js | 4 - .../frontend/ide/components/pipelines/list_spec.js | 5 - .../ide/components/repo_commit_section_spec.js | 22 - spec/frontend/ide/components/repo_editor_spec.js | 16 +- spec/frontend/ide/components/repo_tab_spec.js | 84 +- spec/frontend/ide/components/repo_tabs_spec.js | 4 - .../ide/components/resizable_panel_spec.js | 5 - .../components/shared/commit_message_field_spec.js | 6 +- .../ide/components/shared/tokened_input_spec.js | 4 - .../ide/components/terminal/empty_state_spec.js | 4 - .../ide/components/terminal/terminal_spec.js | 4 - spec/frontend/ide/components/terminal/view_spec.js | 4 - .../terminal_sync_status_safe_spec.js | 4 - .../terminal_sync/terminal_sync_status_spec.js | 4 - spec/frontend/ide/init_gitlab_web_ide_spec.js | 7 +- .../ide/lib/gitlab_web_ide/get_base_config_spec.js | 7 +- spec/frontend/ide/lib/languages/codeowners_spec.js | 85 ++ spec/frontend/ide/services/index_spec.js | 3 - spec/frontend/ide/services/terminals_spec.js | 2 - spec/frontend/ide/stores/actions/file_spec.js | 4 - .../ide/stores/actions/merge_request_spec.js | 8 +- spec/frontend/ide/stores/actions/project_spec.js | 6 +- spec/frontend/ide/stores/actions_spec.js | 10 +- spec/frontend/ide/stores/extend_spec.js | 5 +- spec/frontend/ide/stores/getters_spec.js | 7 - .../ide/stores/modules/commit/actions_spec.js | 10 +- .../terminal/actions/session_controls_spec.js | 8 +- .../terminal/actions/session_status_spec.js | 6 +- .../details/components/import_details_app_spec.js | 18 + .../components/import_details_table_spec.js | 113 ++ spec/frontend/import/details/mock_data.js | 53 + .../components/group_dropdown_spec.js | 8 +- .../components/import_status_spec.js | 78 +- .../components/import_actions_cell_spec.js | 47 +- .../components/import_source_cell_spec.js | 4 - .../import_groups/components/import_table_spec.js | 62 +- .../components/import_target_cell_spec.js | 11 +- .../import_groups/graphql/client_factory_spec.js | 4 +- .../import_groups/services/status_poller_spec.js | 6 +- .../components/advanced_settings_spec.js | 8 +- .../components/bitbucket_status_table_spec.js | 24 +- .../components/github_organizations_box_spec.js | 97 ++ .../components/github_status_table_spec.js | 125 ++ .../components/import_projects_table_spec.js | 11 +- .../components/provider_repo_table_row_spec.js | 19 +- .../import_projects/store/actions_spec.js | 18 +- .../import_projects/store/mutations_spec.js | 13 +- .../incidents/components/incidents_list_spec.js | 9 +- .../incidents_settings_tabs_spec.js.snap | 59 - .../components/incidents_settings_service_spec.js | 6 +- .../components/incidents_settings_tabs_spec.js | 30 +- .../components/pagerduty_form_spec.js | 4 - .../edit/components/active_checkbox_spec.js | 8 +- .../edit/components/confirmation_modal_spec.js | 4 - .../edit/components/dynamic_field_spec.js | 4 - .../edit/components/integration_form_spec.js | 53 +- .../edit/components/jira_issues_fields_spec.js | 9 +- .../edit/components/jira_trigger_fields_spec.js | 6 +- .../edit/components/override_dropdown_spec.js | 4 - .../components/sections/apple_app_store_spec.js | 57 + .../edit/components/sections/configuration_spec.js | 4 - .../edit/components/sections/connection_spec.js | 4 - .../edit/components/sections/google_play_spec.js | 54 + .../edit/components/sections/jira_issues_spec.js | 4 - .../edit/components/sections/jira_trigger_spec.js | 4 - .../edit/components/sections/trigger_spec.js | 4 - .../edit/components/trigger_field_spec.js | 6 +- .../edit/components/trigger_fields_spec.js | 4 - .../edit/components/upload_dropzone_field_spec.js | 88 ++ .../index/components/integrations_list_spec.js | 4 - .../index/components/integrations_table_spec.js | 61 +- spec/frontend/integrations/index/mock_data.js | 9 + .../components/integration_overrides_spec.js | 1 - .../overrides/components/integration_tabs_spec.js | 4 - .../invite_members/components/confetti_spec.js | 8 +- .../invite_members/components/group_select_spec.js | 8 +- .../import_project_members_modal_spec.js | 18 +- .../import_project_members_trigger_spec.js | 4 - .../components/invite_group_notification_spec.js | 14 +- .../components/invite_group_trigger_spec.js | 5 - .../components/invite_groups_modal_spec.js | 43 +- .../components/invite_members_modal_spec.js | 302 ++--- .../components/invite_members_trigger_spec.js | 72 +- .../components/invite_modal_base_spec.js | 31 +- .../components/members_token_select_spec.js | 5 - .../components/project_select_spec.js | 4 - .../invite_members/mock_data/member_modal.js | 31 + .../invite_members/utils/member_utils_spec.js | 30 +- .../utils/trigger_successful_invite_alert_spec.js | 8 +- .../issuable/components/csv_export_modal_spec.js | 18 +- .../components/csv_import_export_buttons_spec.js | 92 +- .../issuable/components/csv_import_modal_spec.js | 4 - .../issuable/components/issuable_by_email_spec.js | 2 - .../components/issuable_header_warnings_spec.js | 7 +- .../issuable/components/issue_assignees_spec.js | 5 - .../issuable/components/issue_milestone_spec.js | 159 +-- .../components/related_issuable_item_spec.js | 63 +- .../issuable/components/status_box_spec.js | 5 - spec/frontend/issuable/issuable_form_spec.js | 69 +- .../popover/components/issue_popover_spec.js | 4 - .../issuable/popover/components/mr_popover_spec.js | 8 +- .../components/add_issuable_form_spec.js | 245 ++-- .../related_issues/components/issue_token_spec.js | 7 - .../components/related_issues_block_spec.js | 152 +-- .../components/related_issues_list_spec.js | 98 +- .../components/related_issues_root_spec.js | 8 +- .../issues/create_merge_request_dropdown_spec.js | 8 + .../components/issues_dashboard_app_spec.js | 70 +- spec/frontend/issues/issue_spec.js | 8 +- .../empty_state_without_any_issues_spec.js | 5 +- .../list/components/issue_card_time_info_spec.js | 4 - .../issues/list/components/issues_list_app_spec.js | 192 +-- .../jira_issues_import_status_app_spec.js | 7 +- spec/frontend/issues/list/mock_data.js | 25 +- spec/frontend/issues/list/utils_spec.js | 20 +- .../new/components/title_suggestions_item_spec.js | 4 - .../new/components/title_suggestions_spec.js | 123 +- .../issues/new/components/type_popover_spec.js | 4 - .../issues/new/components/type_select_spec.js | 141 +++ spec/frontend/issues/new/mock_data.js | 64 + .../components/related_merge_requests_spec.js | 1 - .../related_merge_requests/store/actions_spec.js | 4 +- spec/frontend/issues/show/components/app_spec.js | 592 ++++----- .../show/components/delete_issue_modal_spec.js | 4 - .../issues/show/components/description_spec.js | 263 +--- .../issues/show/components/edit_actions_spec.js | 6 +- .../frontend/issues/show/components/edited_spec.js | 73 +- .../show/components/fields/description_spec.js | 25 +- .../components/fields/description_template_spec.js | 4 - .../issues/show/components/fields/title_spec.js | 5 - .../issues/show/components/fields/type_spec.js | 8 +- spec/frontend/issues/show/components/form_spec.js | 4 - .../issues/show/components/header_actions_spec.js | 366 ++++-- .../incidents/create_timeline_events_form_spec.js | 6 +- .../components/incidents/highlight_bar_spec.js | 7 - .../components/incidents/incident_tabs_spec.js | 57 +- .../incidents/timeline_events_form_spec.js | 19 +- .../incidents/timeline_events_list_spec.js | 8 +- .../incidents/timeline_events_tab_spec.js | 10 +- .../issues/show/components/incidents/utils_spec.js | 4 +- .../issues/show/components/locked_warning_spec.js | 9 +- .../components/new_header_actions_popover_spec.js | 77 ++ .../components/sentry_error_stack_trace_spec.js | 6 - .../show/components/task_list_item_actions_spec.js | 19 +- spec/frontend/issues/show/components/title_spec.js | 89 +- spec/frontend/issues/show/mock_data/mock_data.js | 74 +- .../branches/components/new_branch_form_spec.js | 4 - .../branches/components/project_dropdown_spec.js | 4 - .../components/source_branch_dropdown_spec.js | 8 +- .../jira_connect/branches/pages/index_spec.js | 4 - .../jira_connect/subscriptions/api_spec.js | 28 - .../components/add_namespace_button_spec.js | 6 +- .../add_namespace_modal_spec.js | 4 - .../add_namespace_modal/groups_list_item_spec.js | 108 +- .../add_namespace_modal/groups_list_spec.js | 4 - .../subscriptions/components/app_spec.js | 298 +++-- .../components/browser_support_alert_spec.js | 4 - .../components/group_item_name_spec.js | 4 - .../components/sign_in_legacy_button_spec.js | 58 - .../components/sign_in_oauth_button_spec.js | 6 +- .../components/subscriptions_list_spec.js | 4 - .../subscriptions/components/user_link_spec.js | 80 +- .../pages/sign_in/sign_in_gitlab_com_spec.js | 74 +- .../sign_in_gitlab_multiversion/index_spec.js | 35 +- .../setup_instructions_spec.js | 18 +- .../version_select_form_spec.js | 97 +- .../pages/sign_in/sign_in_page_spec.js | 34 +- .../subscriptions/pages/subscriptions_page_spec.js | 4 - .../subscriptions/store/actions_spec.js | 20 +- .../subscriptions/store/mutations_spec.js | 16 - .../jira_connect/subscriptions/utils_spec.js | 46 - .../__snapshots__/jira_import_form_spec.js.snap | 18 +- .../jira_import/components/jira_import_app_spec.js | 5 - .../components/jira_import_form_spec.js | 5 +- .../components/jira_import_progress_spec.js | 5 - .../components/jira_import_setup_spec.js | 5 - .../filtered_search/jobs_filtered_search_spec.js | 4 - .../tokens/job_status_token_spec.js | 4 - .../jobs/components/job/artifacts_block_spec.js | 5 - .../jobs/components/job/commit_block_spec.js | 4 - .../jobs/components/job/empty_state_spec.js | 7 - .../jobs/components/job/environments_block_spec.js | 5 - .../jobs/components/job/erased_block_spec.js | 4 - spec/frontend/jobs/components/job/job_app_spec.js | 3 +- .../jobs/components/job/job_container_item_spec.js | 5 - .../components/job/job_log_controllers_spec.js | 17 +- .../job/job_retry_forward_deployment_modal_spec.js | 19 +- .../job/job_sidebar_details_container_spec.js | 7 - .../job/job_sidebar_retry_button_spec.js | 6 - .../jobs/components/job/jobs_container_spec.js | 4 - .../components/job/manual_variables_form_spec.js | 112 +- spec/frontend/jobs/components/job/mock_data.js | 27 +- .../jobs/components/job/sidebar_detail_row_spec.js | 32 +- .../jobs/components/job/sidebar_header_spec.js | 2 +- spec/frontend/jobs/components/job/sidebar_spec.js | 8 +- .../jobs/components/job/stages_dropdown_spec.js | 6 +- .../jobs/components/job/stuck_block_spec.js | 7 - .../jobs/components/job/trigger_block_spec.js | 4 - .../job/unmet_prerequisites_block_spec.js | 4 - .../components/log/collapsible_section_spec.js | 4 - .../jobs/components/log/duration_badge_spec.js | 4 - .../jobs/components/log/line_header_spec.js | 4 - .../jobs/components/log/line_number_spec.js | 4 - spec/frontend/jobs/components/log/log_spec.js | 77 +- spec/frontend/jobs/components/log/mock_data.js | 24 + .../components/table/cells/actions_cell_spec.js | 8 +- .../components/table/cells/duration_cell_spec.js | 4 - .../jobs/components/table/cells/job_cell_spec.js | 4 - .../components/table/cells/pipeline_cell_spec.js | 4 - .../components/table/graphql/cache_config_spec.js | 19 + .../jobs/components/table/job_table_app_spec.js | 144 ++- .../jobs/components/table/jobs_table_spec.js | 84 +- .../jobs/components/table/jobs_table_tabs_spec.js | 23 +- .../frontend/jobs/mixins/delayed_job_mixin_spec.js | 5 - spec/frontend/jobs/mock_data.js | 20 + spec/frontend/jobs/store/utils_spec.js | 8 + .../labels/components/delete_label_modal_spec.js | 83 +- .../labels/components/promote_label_modal_spec.js | 1 - .../language_switcher/components/app_spec.js | 4 - .../apollo/indexed_db_persistent_storage_spec.js | 90 ++ .../cache_with_persist_directive_and_field.json | 151 --- spec/frontend/lib/apollo/persist_link_spec.js | 4 +- ...s_network_errors_during_navigation_link_spec.js | 5 - spec/frontend/lib/dompurify_spec.js | 14 +- spec/frontend/lib/mousetrap_spec.js | 113 ++ .../frontend/lib/utils/axios_startup_calls_spec.js | 7 - spec/frontend/lib/utils/chart_utils_spec.js | 55 +- spec/frontend/lib/utils/color_utils_spec.js | 42 +- spec/frontend/lib/utils/common_utils_spec.js | 8 - .../confirm_via_gl_modal/confirm_action_spec.js | 3 +- .../confirm_via_gl_modal/confirm_modal_spec.js | 18 +- spec/frontend/lib/utils/css_utils_spec.js | 22 + .../lib/utils/datetime/date_format_utility_spec.js | 12 - .../lib/utils/datetime/time_spent_utility_spec.js | 25 + .../lib/utils/datetime/timeago_utility_spec.js | 37 +- spec/frontend/lib/utils/datetime_utility_spec.js | 40 +- spec/frontend/lib/utils/error_message_spec.js | 48 + spec/frontend/lib/utils/file_upload_spec.js | 22 +- .../lib/utils/intersection_observer_spec.js | 2 +- spec/frontend/lib/utils/number_utility_spec.js | 29 + spec/frontend/lib/utils/poll_spec.js | 2 +- spec/frontend/lib/utils/ref_validator_spec.js | 79 ++ spec/frontend/lib/utils/secret_detection_spec.js | 68 + spec/frontend/lib/utils/sticky_spec.js | 77 -- spec/frontend/lib/utils/tappable_promise_spec.js | 63 + spec/frontend/lib/utils/text_markdown_spec.js | 62 + spec/frontend/lib/utils/text_utility_spec.js | 32 + spec/frontend/lib/utils/url_utility_spec.js | 20 - .../frontend/lib/utils/vuex_module_mappers_spec.js | 4 - spec/frontend/lib/utils/web_ide_navigator_spec.js | 38 + spec/frontend/listbox/redirect_behavior_spec.js | 6 +- spec/frontend/locale/sprintf_spec.js | 11 + .../access_request_action_buttons_spec.js | 4 - .../approve_access_request_button_spec.js | 6 +- .../action_buttons/invite_action_buttons_spec.js | 4 - .../remove_group_link_button_spec.js | 7 +- .../action_buttons/remove_member_button_spec.js | 6 +- .../action_buttons/resend_invite_button_spec.js | 6 +- .../leave_group_dropdown_item_spec.js | 6 +- .../remove_member_dropdown_item_spec.js | 4 - .../action_dropdowns/user_action_dropdown_spec.js | 6 +- spec/frontend/members/components/app_spec.js | 1 - .../components/avatars/group_avatar_spec.js | 4 - .../components/avatars/invite_avatar_spec.js | 4 - .../members/components/avatars/user_avatar_spec.js | 4 - .../members_filtered_search_bar_spec.js | 9 +- .../components/filter_sort/sort_dropdown_spec.js | 2 +- .../members/components/members_tabs_spec.js | 4 - .../members/components/modals/leave_modal_spec.js | 4 - .../modals/remove_group_link_modal_spec.js | 5 - .../components/modals/remove_member_modal_spec.js | 4 - .../members/components/table/created_at_spec.js | 4 - .../components/table/expiration_datepicker_spec.js | 6 +- .../components/table/member_action_buttons_spec.js | 4 - .../members/components/table/member_avatar_spec.js | 4 - .../members/components/table/member_source_spec.js | 6 +- .../components/table/members_table_cell_spec.js | 5 - .../members/components/table/members_table_spec.js | 4 - .../members/components/table/role_dropdown_spec.js | 96 +- spec/frontend/members/index_spec.js | 3 - spec/frontend/members/utils_spec.js | 2 +- .../components/merge_conflict_resolver_app_spec.js | 4 - .../frontend/merge_conflicts/store/actions_spec.js | 6 +- spec/frontend/merge_request_spec.js | 12 +- spec/frontend/merge_request_tabs_spec.js | 47 +- .../merge_requests/components/compare_app_spec.js | 4 - .../components/compare_dropdown_spec.js | 1 - .../components/delete_milestone_modal_spec.js | 14 +- .../components/milestone_combobox_spec.js | 5 - .../components/promote_milestone_modal_spec.js | 8 +- spec/frontend/milestones/index_spec.js | 38 + .../__snapshots__/ml_candidate_spec.js.snap | 268 ---- .../components/delete_button_spec.js | 68 + .../components/ml_candidate_spec.js | 47 - .../components/ml_experiment_spec.js | 316 ----- .../components/model_experiments_header_spec.js | 35 + .../show/components/candidate_detail_row_spec.js | 49 + .../candidates/show/ml_candidates_show_spec.js | 119 ++ .../routes/candidates/show/mock_data.js | 23 + .../index/components/ml_experiments_index_spec.js | 19 +- .../experiments/show/ml_experiments_show_spec.js | 321 +++++ .../routes/experiments/show/mock_data.js | 58 + .../monitoring/components/charts/column_spec.js | 4 - .../monitoring/components/charts/gauge_spec.js | 5 - .../monitoring/components/charts/heatmap_spec.js | 4 - .../components/charts/single_stat_spec.js | 4 - .../components/charts/time_series_spec.js | 4 - .../components/create_dashboard_modal_spec.js | 4 - .../components/dashboard_actions_menu_spec.js | 17 +- .../monitoring/components/dashboard_header_spec.js | 25 +- .../components/dashboard_panel_builder_spec.js | 2 - .../monitoring/components/dashboard_panel_spec.js | 16 - .../monitoring/components/dashboard_spec.js | 5 +- .../components/dashboard_url_time_spec.js | 11 +- .../components/embeds/embed_group_spec.js | 3 - .../components/embeds/metric_embed_spec.js | 3 - .../monitoring/components/graph_group_spec.js | 4 - .../components/group_empty_state_spec.js | 4 - .../monitoring/components/refresh_button_spec.js | 1 + .../components/variables/dropdown_field_spec.js | 8 +- .../components/variables/text_field_spec.js | 6 +- spec/frontend/monitoring/mock_data.js | 26 - .../monitoring/pages/dashboard_page_spec.js | 10 +- .../monitoring/pages/panel_new_page_spec.js | 4 - spec/frontend/monitoring/store/actions_spec.js | 11 +- .../frontend/nav/components/new_nav_toggle_spec.js | 222 +++- .../frontend/nav/components/responsive_app_spec.js | 4 - .../nav/components/responsive_header_spec.js | 6 +- .../nav/components/responsive_home_spec.js | 6 +- spec/frontend/nav/components/top_nav_app_spec.js | 4 - .../nav/components/top_nav_container_view_spec.js | 4 - .../nav/components/top_nav_dropdown_menu_spec.js | 4 - .../nav/components/top_nav_menu_sections_spec.js | 4 - .../nav/components/top_nav_new_dropdown_spec.js | 29 +- spec/frontend/new_branch_spec.js | 7 +- spec/frontend/notebook/cells/code_spec.js | 4 - spec/frontend/notebook/cells/markdown_spec.js | 6 +- .../notebook/cells/output/dataframe_spec.js | 59 + .../notebook/cells/output/dataframe_util_spec.js | 133 ++ spec/frontend/notebook/cells/output/error_spec.js | 48 + spec/frontend/notebook/cells/output/index_spec.js | 22 +- spec/frontend/notebook/cells/prompt_spec.js | 4 - spec/frontend/notebook/index_spec.js | 6 +- spec/frontend/notebook/mock_data.js | 102 ++ .../frontend/notes/components/comment_form_spec.js | 154 ++- .../notes/components/comment_type_dropdown_spec.js | 4 - .../components/diff_discussion_header_spec.js | 4 - .../notes/components/discussion_actions_spec.js | 11 +- .../notes/components/discussion_counter_spec.js | 3 - .../components/discussion_filter_note_spec.js | 5 - .../notes/components/discussion_filter_spec.js | 133 +- .../notes/components/discussion_navigator_spec.js | 10 +- .../discussion_notes_replies_wrapper_spec.js | 4 - .../notes/components/discussion_notes_spec.js | 5 - .../discussion_reply_placeholder_spec.js | 4 - .../components/discussion_resolve_button_spec.js | 4 - .../discussion_resolve_with_issue_button_spec.js | 4 - .../components/email_participants_warning_spec.js | 5 - .../notes/components/mr_discussion_filter_spec.js | 110 ++ .../components/note_actions/reply_button_spec.js | 5 - .../note_actions/timeline_event_button_spec.js | 6 +- .../frontend/notes/components/note_actions_spec.js | 42 +- .../notes/components/note_attachment_spec.js | 5 - .../notes/components/note_awards_list_spec.js | 236 ++-- spec/frontend/notes/components/note_body_spec.js | 12 - .../notes/components/note_edited_text_spec.js | 69 +- spec/frontend/notes/components/note_form_spec.js | 230 +--- spec/frontend/notes/components/note_header_spec.js | 33 +- .../components/note_signed_out_widget_spec.js | 4 - .../notes/components/noteable_discussion_spec.js | 15 - .../notes/components/noteable_note_spec.js | 64 +- .../notes/components/notes_activity_header_spec.js | 4 - spec/frontend/notes/components/notes_app_spec.js | 19 +- .../notes/components/timeline_toggle_spec.js | 4 - .../notes/components/toggle_replies_widget_spec.js | 4 - spec/frontend/notes/deprecated_notes_spec.js | 12 +- spec/frontend/notes/stores/actions_spec.js | 32 +- .../components/custom_notifications_modal_spec.js | 54 +- .../components/notifications_dropdown_spec.js | 4 +- .../components/oauth_secret_spec.js | 116 ++ spec/frontend/oauth_remember_me_spec.js | 14 +- spec/frontend/observability/index_spec.js | 64 + .../observability/observability_app_spec.js | 144 ++- spec/frontend/observability/skeleton_spec.js | 15 +- .../components/metrics_settings_spec.js | 9 +- .../explorer/components/delete_button_spec.js | 5 - .../explorer/components/delete_image_spec.js | 5 - .../explorer/components/delete_modal_spec.js | 158 +++ .../components/details_page/delete_alert_spec.js | 5 - .../components/details_page/delete_modal_spec.js | 152 --- .../components/details_page/details_header_spec.js | 48 +- .../details_page/partial_cleanup_alert_spec.js | 5 - .../components/details_page/status_alert_spec.js | 5 - .../components/details_page/tags_list_row_spec.js | 45 +- .../components/details_page/tags_list_spec.js | 313 ++++- .../components/details_page/tags_loader_spec.js | 5 - .../components/list_page/cleanup_status_spec.js | 4 - .../components/list_page/group_empty_state_spec.js | 4 - .../components/list_page/image_list_row_spec.js | 22 +- .../components/list_page/image_list_spec.js | 5 - .../list_page/project_empty_state_spec.js | 4 - .../components/list_page/registry_header_spec.js | 11 +- .../container_registry/explorer/mock_data.js | 4 +- .../explorer/pages/details_spec.js | 124 +- .../container_registry/explorer/pages/list_spec.js | 77 +- .../container_registry/explorer/stubs.js | 2 +- .../container_registry/explorer/utils_spec.js | 19 +- .../dependency_proxy/app_spec.js | 84 +- .../components/manifest_list_spec.js | 35 +- .../components/manifest_row_spec.js | 55 +- .../dependency_proxy/mock_data.js | 4 +- .../components/details/artifacts_list_row_spec.js | 4 - .../components/details/artifacts_list_spec.js | 4 - .../components/details/details_header_spec.js | 4 - .../components/list/harbor_list_header_spec.js | 4 - .../components/list/harbor_list_row_spec.js | 4 - .../components/list/harbor_list_spec.js | 4 - .../components/tags/tags_header_spec.js | 4 - .../components/tags/tags_list_row_spec.js | 4 - .../components/tags/tags_list_spec.js | 4 - .../harbor_registry/pages/details_spec.js | 4 - .../harbor_registry/pages/list_spec.js | 8 +- .../harbor_registry/pages/tags_spec.js | 4 - .../components/details/components/app_spec.js | 4 - .../details/components/details_title_spec.js | 4 - .../components/details/components/file_sha_spec.js | 4 - .../details/components/package_files_spec.js | 5 - .../details/components/package_history_spec.js | 5 - .../components/terraform_installation_spec.js | 4 - .../components/details/store/actions_spec.js | 10 +- .../__snapshots__/packages_list_app_spec.js.snap | 2 - .../list/components/infrastructure_search_spec.js | 5 - .../list/components/infrastructure_title_spec.js | 7 +- .../list/components/packages_list_app_spec.js | 10 +- .../list/components/packages_list_spec.js | 35 +- .../components/list/stores/actions_spec.js | 8 +- .../components/shared/package_list_row_spec.js | 9 +- .../components/delete_modal_spec.js | 92 +- .../__snapshots__/maven_installation_spec.js.snap | 3 +- .../__snapshots__/package_title_spec.js.snap | 199 --- .../__snapshots__/pypi_installation_spec.js.snap | 14 +- .../components/details/additional_metadata_spec.js | 5 - .../details/composer_installation_spec.js | 4 - .../components/details/conan_installation_spec.js | 4 - .../components/details/dependency_row_spec.js | 4 - .../components/details/file_sha_spec.js | 4 - .../components/details/installation_title_spec.js | 4 - .../details/installations_commands_spec.js | 4 - .../components/details/maven_installation_spec.js | 6 +- .../components/details/metadata/composer_spec.js | 5 - .../components/details/metadata/conan_spec.js | 5 - .../components/details/metadata/maven_spec.js | 5 - .../components/details/metadata/nuget_spec.js | 5 - .../components/details/metadata/pypi_spec.js | 5 - .../components/details/npm_installation_spec.js | 4 - .../components/details/nuget_installation_spec.js | 4 - .../components/details/package_files_spec.js | 4 - .../components/details/package_history_spec.js | 5 - .../components/details/package_title_spec.js | 10 +- .../details/package_versions_list_spec.js | 236 +++- .../components/details/pypi_installation_spec.js | 17 +- .../components/details/version_row_spec.js | 34 +- .../components/functional/delete_packages_spec.js | 8 +- .../__snapshots__/package_list_row_spec.js.snap | 12 +- .../components/list/package_list_row_spec.js | 18 +- .../components/list/packages_list_spec.js | 53 +- .../components/list/packages_search_spec.js | 6 +- .../components/list/packages_title_spec.js | 5 - .../components/list/publish_method_spec.js | 4 - .../list/tokens/package_type_token_spec.js | 5 - .../package_registry/mock_data.js | 83 +- .../package_registry/pages/details_spec.js | 218 ++-- .../package_registry/pages/list_spec.js | 98 +- .../components/dependency_proxy_settings_spec.js | 6 +- .../group/components/exceptions_input_spec.js | 6 +- .../group/components/group_settings_app_spec.js | 6 +- .../group/components/package_settings_spec.js | 10 +- .../packages_forwarding_settings_spec.js | 23 +- .../settings/components/cleanup_image_tags_spec.js | 6 +- .../container_expiration_policy_form_spec.js | 6 +- .../components/container_expiration_policy_spec.js | 6 +- .../components/expiration_dropdown_spec.js | 5 - .../settings/components/expiration_input_spec.js | 5 - .../components/expiration_run_text_spec.js | 5 - .../settings/components/expiration_toggle_spec.js | 5 - .../packages_cleanup_policy_form_spec.js | 3 +- .../components/packages_cleanup_policy_spec.js | 1 - .../components/registry_settings_app_spec.js | 7 +- .../__snapshots__/registry_breadcrumb_spec.js.snap | 29 +- .../shared/components/cli_commands_spec.js | 5 - .../shared/components/delete_package_modal_spec.js | 5 - .../components/package_icon_and_name_spec.js | 32 - .../shared/components/package_path_spec.js | 11 +- .../shared/components/package_tags_spec.js | 4 - .../shared/components/packages_list_loader_spec.js | 5 - .../shared/components/persisted_search_spec.js | 6 +- .../shared/components/publish_method_spec.js | 5 - .../shared/components/registry_breadcrumb_spec.js | 4 - .../shared/components/registry_list_spec.js | 23 +- .../shared/components/settings_block_spec.js | 4 - .../admin/abuse_reports/abuse_reports_spec.js | 6 +- .../account_and_limits_spec.js | 7 +- .../metrics_and_profiling/usage_statistics_spec.js | 6 +- .../jobs/components/cancel_jobs_modal_spec.js | 66 + .../admin/jobs/components/cancel_jobs_spec.js | 57 + .../jobs/components/jobs_skeleton_loader_spec.js | 28 + .../components/table/admin_job_table_app_spec.js | 394 ++++++ .../components/table/cells/project_cell_spec.js | 32 + .../components/table/cells/runner_cell_spec.js | 64 + .../components/table/graphql/cache_config_spec.js | 106 ++ .../index/components/cancel_jobs_modal_spec.js | 66 - .../jobs/index/components/cancel_jobs_spec.js | 57 - .../projects/components/namespace_select_spec.js | 4 +- .../pages/dashboard/todos/index/todos_spec.js | 5 +- .../pages/groups/new/components/app_spec.js | 28 +- .../create_group_description_details_spec.js | 4 - .../bitbucket_server_status_table_spec.js | 9 +- .../components/bulk_imports_history_app_spec.js | 10 +- .../components/import_error_details_spec.js | 11 +- .../history/components/import_history_app_spec.js | 14 +- .../password_prompt/password_prompt_modal_spec.js | 7 +- .../projects/forks/new/components/app_spec.js | 4 - .../forks/new/components/fork_form_spec.js | 13 +- .../forks/new/components/project_namespace_spec.js | 17 +- .../pages/projects/graphs/code_coverage_spec.js | 11 +- .../components/interval_pattern_input_spec.js | 6 - .../components/pipeline_schedule_callout_spec.js | 8 - .../components/project_feature_settings_spec.js | 5 - .../components/project_setting_row_spec.js | 4 - .../permissions/components/settings_panel_spec.js | 9 +- .../sessions/new/preserve_url_fragment_spec.js | 15 +- .../sessions/new/signin_tabs_memoizer_spec.js | 6 +- .../shared/wikis/components/wiki_alert_spec.js | 5 - .../shared/wikis/components/wiki_content_spec.js | 5 - .../shared/wikis/components/wiki_form_spec.js | 10 +- spec/frontend/pdf/index_spec.js | 4 - spec/frontend/pdf/page_spec.js | 4 - .../performance_bar/components/add_request_spec.js | 4 - .../components/detailed_metric_spec.js | 4 - .../components/performance_bar_app_spec.js | 55 +- .../components/request_warning_spec.js | 4 - spec/frontend/performance_bar/index_spec.js | 10 +- .../services/performance_bar_service_spec.js | 2 +- .../stores/performance_bar_store_spec.js | 8 + spec/frontend/persistent_user_callout_spec.js | 4 +- .../pipeline_wizard/components/commit_spec.js | 22 +- .../pipeline_wizard/components/editor_spec.js | 4 - .../components/input_wrapper_spec.js | 8 - .../pipeline_wizard/components/step_nav_spec.js | 14 +- .../pipeline_wizard/components/step_spec.js | 6 +- .../components/widgets/checklist_spec.js | 4 - .../components/widgets/list_spec.js | 12 +- .../components/widgets/text_spec.js | 8 +- .../pipeline_wizard/components/wrapper_spec.js | 33 +- .../pipeline_wizard/pipeline_wizard_spec.js | 4 - .../components/dag/dag_annotations_spec.js | 9 - .../pipelines/components/dag/dag_graph_spec.js | 5 - spec/frontend/pipelines/components/dag/dag_spec.js | 21 +- .../components/jobs/failed_jobs_app_spec.js | 15 +- .../components/jobs/failed_jobs_table_spec.js | 46 +- .../pipelines/components/jobs/jobs_app_spec.js | 10 +- .../pipelines/components/jobs/utils_spec.js | 14 - .../linked_pipelines_mini_list_spec.js | 12 +- .../pipeline_mini_graph_spec.js | 15 - .../pipeline_mini_graph/pipeline_stage_spec.js | 7 +- .../pipeline_mini_graph/pipeline_stages_spec.js | 5 - .../pipelines/components/pipeline_tabs_spec.js | 5 - .../components/pipelines_filtered_search_spec.js | 2 - .../empty_state/ci_templates_spec.js | 5 - .../empty_state/ios_templates_spec.js | 5 - .../empty_state/pipelines_ci_templates_spec.js | 109 +- spec/frontend/pipelines/empty_state_spec.js | 5 - .../pipelines/graph/action_component_spec.js | 1 - .../graph/graph_component_wrapper_spec.js | 175 +-- .../pipelines/graph/graph_view_selector_spec.js | 19 +- .../pipelines/graph/job_group_dropdown_spec.js | 4 - spec/frontend/pipelines/graph/job_item_spec.js | 51 +- .../pipelines/graph/linked_pipeline_spec.js | 170 +-- .../graph/linked_pipelines_column_spec.js | 4 - .../pipelines/graph/stage_column_component_spec.js | 4 - .../pipelines/graph_shared/links_inner_spec.js | 1 - .../pipelines/graph_shared/links_layer_spec.js | 4 - spec/frontend/pipelines/header_component_spec.js | 11 +- spec/frontend/pipelines/mock_data.js | 87 +- spec/frontend/pipelines/nav_controls_spec.js | 37 +- .../pipeline_graph/pipeline_graph_spec.js | 4 - spec/frontend/pipelines/pipeline_labels_spec.js | 4 - .../pipelines/pipeline_multi_actions_spec.js | 2 - .../frontend/pipelines/pipeline_operations_spec.js | 77 ++ spec/frontend/pipelines/pipeline_tabs_spec.js | 2 - spec/frontend/pipelines/pipeline_triggerer_spec.js | 6 +- spec/frontend/pipelines/pipeline_url_spec.js | 4 - spec/frontend/pipelines/pipelines_actions_spec.js | 171 --- .../frontend/pipelines/pipelines_artifacts_spec.js | 5 - .../pipelines/pipelines_manual_actions_spec.js | 216 ++++ spec/frontend/pipelines/pipelines_spec.js | 33 +- spec/frontend/pipelines/pipelines_table_spec.js | 6 - .../pipelines/test_reports/stores/actions_spec.js | 6 +- .../test_reports/stores/mutations_spec.js | 6 +- .../test_reports/test_case_details_spec.js | 5 - .../pipelines/test_reports/test_reports_spec.js | 4 - .../test_reports/test_suite_table_spec.js | 4 - spec/frontend/pipelines/time_ago_spec.js | 5 - .../tokens/pipeline_branch_name_token_spec.js | 5 - .../pipelines/tokens/pipeline_status_token_spec.js | 5 - .../tokens/pipeline_tag_name_token_spec.js | 5 - .../tokens/pipeline_trigger_author_token_spec.js | 5 - spec/frontend/popovers/components/popovers_spec.js | 5 - .../components/delete_account_modal_spec.js | 6 - .../account/components/update_username_spec.js | 52 +- .../profile/components/activity_calendar_spec.js | 120 ++ .../profile/components/followers_tab_spec.js | 21 +- .../profile/components/following_tab_spec.js | 21 +- .../profile/components/overview_tab_spec.js | 60 +- .../profile/components/profile_tabs_spec.js | 57 +- .../profile/components/user_achievements_spec.js | 122 ++ spec/frontend/profile/mock_data.js | 22 + .../components/diffs_colors_preview_spec.js | 5 - .../preferences/components/diffs_colors_spec.js | 14 +- .../components/integration_view_spec.js | 5 - .../components/profile_preferences_spec.js | 9 +- spec/frontend/profile/utils_spec.js | 15 + .../components/clusters_deprecation_alert_spec.js | 4 - .../commit/components/branches_dropdown_spec.js | 10 +- .../components/commit_options_dropdown_spec.js | 2 +- .../projects/commit/components/form_modal_spec.js | 77 +- .../commit/components/projects_dropdown_spec.js | 15 +- .../frontend/projects/commit/store/actions_spec.js | 6 +- .../commit_box/info/init_details_button_spec.js | 47 + .../projects/commit_box/info/load_branches_spec.js | 10 + .../commits/components/author_select_spec.js | 52 +- .../projects/commits/store/actions_spec.js | 8 +- .../projects/compare/components/app_spec.js | 5 - .../compare/components/repo_dropdown_spec.js | 5 - .../compare/components/revision_card_spec.js | 5 - .../components/revision_dropdown_legacy_spec.js | 51 +- .../compare/components/revision_dropdown_spec.js | 48 +- .../components/project_delete_button_spec.js | 5 - .../components/shared/delete_button_spec.js | 7 +- .../projects/details/upload_button_spec.js | 4 - spec/frontend/projects/new/components/app_spec.js | 46 +- .../components/deployment_target_select_spec.js | 3 +- .../new_project_push_tip_popover_spec.js | 1 - .../new/components/new_project_url_select_spec.js | 23 +- .../ci_cd_analytics_area_chart_spec.js.snap | 30 +- .../pipelines/charts/components/app_spec.js | 4 - .../components/ci_cd_analytics_area_chart_spec.js | 5 - .../components/ci_cd_analytics_charts_spec.js | 7 - .../charts/components/pipeline_charts_spec.js | 5 - .../charts/components/statistics_list_spec.js | 4 - .../prune_unreachable_objects_button_spec.js | 7 +- .../components/edit/branch_dropdown_spec.js | 8 +- .../branch_rules/components/edit/index_spec.js | 4 - .../components/edit/protections/index_spec.js | 4 - .../edit/protections/merge_protections_spec.js | 4 - .../edit/protections/push_protections_spec.js | 4 - .../branch_rules/components/view/index_spec.js | 48 +- .../components/view/protection_row_spec.js | 2 - .../components/view/protection_spec.js | 2 - .../components/default_branch_selector_spec.js | 5 - .../components/new_access_dropdown_spec.js | 20 +- .../components/shared_runners_toggle_spec.js | 20 +- .../components/transfer_project_form_spec.js | 12 +- .../settings/repository/branch_rules/app_spec.js | 6 +- .../branch_rules/components/branch_rule_spec.js | 4 +- .../settings/repository/branch_rules/mock_data.js | 2 +- .../components/topics_token_selector_spec.js | 3 +- spec/frontend/projects/settings/utils_spec.js | 24 +- .../components/service_desk_root_spec.js | 5 +- .../components/service_desk_setting_spec.js | 6 - .../service_desk_template_dropdown_spec.js | 6 - .../terraform_notification_spec.js | 4 - .../prometheus_metrics/custom_metrics_spec.js | 6 +- .../prometheus_metrics/prometheus_metrics_spec.js | 7 +- .../protected_branch_edit_spec.js | 8 +- spec/frontend/read_more_spec.js | 9 +- .../__snapshots__/ref_selector_spec.js.snap | 80 -- spec/frontend/ref/components/ref_selector_spec.js | 81 +- spec/frontend/ref/stores/actions_spec.js | 7 + spec/frontend/ref/stores/mutations_spec.js | 10 + .../releases/__snapshots__/util_spec.js.snap | 8 - .../releases/components/app_edit_new_spec.js | 30 +- .../frontend/releases/components/app_index_spec.js | 29 +- spec/frontend/releases/components/app_show_spec.js | 15 +- .../releases/components/asset_links_form_spec.js | 5 - .../components/confirm_delete_modal_spec.js | 4 - .../releases/components/evidence_block_spec.js | 4 - .../releases/components/issuable_stats_spec.js | 5 - .../components/release_block_assets_spec.js | 7 +- .../components/release_block_footer_spec.js | 5 - .../components/release_block_header_spec.js | 4 - .../release_block_milestone_info_spec.js | 5 - .../releases/components/release_block_spec.js | 4 - .../components/releases_pagination_spec.js | 4 - .../releases/components/releases_sort_spec.js | 7 +- .../releases/components/tag_create_spec.js | 107 ++ .../releases/components/tag_field_exsting_spec.js | 5 - .../releases/components/tag_field_new_spec.js | 231 ++-- .../frontend/releases/components/tag_field_spec.js | 5 - .../releases/components/tag_search_spec.js | 144 +++ .../releases/release_notification_service_spec.js | 107 +- .../releases/stores/modules/detail/actions_spec.js | 35 +- .../releases/stores/modules/detail/getters_spec.js | 108 +- spec/frontend/repository/commits_service_spec.js | 4 +- .../__snapshots__/last_commit_spec.js.snap | 2 + .../components/blob_button_group_spec.js | 38 +- .../components/blob_content_viewer_spec.js | 10 +- .../repository/components/blob_controls_spec.js | 2 - .../components/blob_viewers/lfs_viewer_spec.js | 2 - .../blob_viewers/notebook_viewer_spec.js | 22 +- .../repository/components/breadcrumbs_spec.js | 107 +- .../components/delete_blob_modal_spec.js | 16 +- .../components/directory_download_links_spec.js | 4 - .../repository/components/fork_info_spec.js | 292 ++++- .../repository/components/fork_suggestion_spec.js | 2 - .../components/fork_sync_conflicts_modal_spec.js | 46 + .../repository/components/last_commit_spec.js | 57 +- .../components/new_directory_modal_spec.js | 14 +- .../preview/__snapshots__/index_spec.js.snap | 42 - .../repository/components/preview/index_spec.js | 95 +- .../table/__snapshots__/row_spec.js.snap | 3 + .../repository/components/table/index_spec.js | 4 - .../repository/components/table/parent_row_spec.js | 4 - .../repository/components/table/row_spec.js | 293 +++-- .../repository/components/tree_content_spec.js | 269 ++-- .../components/upload_blob_modal_spec.js | 52 +- .../repository/mixins/highlight_mixin_spec.js | 2 - spec/frontend/repository/mock_data.js | 72 ++ spec/frontend/repository/pages/blob_spec.js | 4 - spec/frontend/repository/pages/index_spec.js | 2 - spec/frontend/repository/pages/tree_spec.js | 2 - spec/frontend/right_sidebar_spec.js | 6 +- .../__snapshots__/list_item_spec.js.snap | 21 - .../saved_replies/components/list_item_spec.js | 22 - .../frontend/saved_replies/components/list_spec.js | 68 - .../frontend/__fixtures__/locale/de/converted.json | 21 + .../frontend/__fixtures__/locale/de/gitlab.po | 13 + spec/frontend/scripts/frontend/po_to_json_spec.js | 244 ++++ .../search/highlight_blob_search_result_spec.js | 6 +- spec/frontend/search/mock_data.js | 307 ++--- .../frontend/search/sidebar/components/app_spec.js | 36 +- .../sidebar/components/checkbox_filter_spec.js | 59 +- .../components/confidentiality_filter_spec.js | 35 +- .../search/sidebar/components/filters_spec.js | 23 +- .../sidebar/components/language_filter_spec.js | 222 ++++ .../sidebar/components/language_filters_spec.js | 152 --- .../search/sidebar/components/radio_filter_spec.js | 10 +- .../sidebar/components/scope_navigation_spec.js | 57 +- .../components/scope_new_navigation_spec.js | 83 ++ .../sidebar/components/status_filter_spec.js | 35 +- spec/frontend/search/sort/components/app_spec.js | 5 - spec/frontend/search/store/actions_spec.js | 48 +- spec/frontend/search/store/getters_spec.js | 55 +- spec/frontend/search/store/utils_spec.js | 50 +- spec/frontend/search/topbar/components/app_spec.js | 4 - .../search/topbar/components/group_filter_spec.js | 4 - .../topbar/components/project_filter_spec.js | 4 - .../components/searchable_dropdown_item_spec.js | 4 - .../topbar/components/searchable_dropdown_spec.js | 49 +- spec/frontend/search_autocomplete_spec.js | 293 ----- spec/frontend/search_autocomplete_utils_spec.js | 114 -- .../components/search_settings_spec.js | 4 - .../security_configuration/components/app_spec.js | 160 +-- .../components/auto_dev_ops_alert_spec.js | 4 - .../components/auto_dev_ops_enabled_alert_spec.js | 4 - .../components/feature_card_spec.js | 107 +- .../components/training_provider_list_spec.js | 7 +- .../components/upgrade_banner_spec.js | 107 -- spec/frontend/security_configuration/constants.js | 1 + spec/frontend/security_configuration/mock_data.js | 32 +- spec/frontend/security_configuration/utils_spec.js | 38 +- .../__snapshots__/self_monitor_form_spec.js.snap | 85 -- .../components/self_monitor_form_spec.js | 95 -- spec/frontend/self_monitor/store/actions_spec.js | 254 ---- spec/frontend/self_monitor/store/mutations_spec.js | 64 - spec/frontend/sentry/index_spec.js | 52 +- spec/frontend/sentry/legacy_index_spec.js | 7 - .../frontend/sentry/sentry_browser_wrapper_spec.js | 2 +- spec/frontend/sentry/sentry_config_spec.js | 7 - .../set_status_modal_wrapper_spec.js | 58 +- .../user_profile_set_status_wrapper_spec.js | 4 - spec/frontend/settings_panels_spec.js | 5 +- spec/frontend/shortcuts_spec.js | 135 +- .../assignees/assignee_avatar_link_spec.js | 4 - .../components/assignees/assignee_avatar_spec.js | 7 - .../components/assignees/assignee_title_spec.js | 5 - .../assignees/assignees_realtime_spec.js | 1 - .../sidebar/components/assignees/assignees_spec.js | 4 - .../assignees/collapsed_assignee_list_spec.js | 4 - .../assignees/collapsed_assignee_spec.js | 4 - .../assignees/issuable_assignees_spec.js | 5 - .../components/assignees/sidebar_assignees_spec.js | 3 - .../assignees/sidebar_assignees_widget_spec.js | 11 +- .../assignees/sidebar_editable_item_spec.js | 5 - .../assignees/sidebar_invite_members_spec.js | 4 - .../assignees/sidebar_participant_spec.js | 13 +- .../assignees/uncollapsed_assignee_list_spec.js | 4 - .../assignees/user_name_with_status_spec.js | 8 +- .../sidebar_confidentiality_content_spec.js | 4 - .../sidebar_confidentiality_form_spec.js | 12 +- .../sidebar_confidentiality_widget_spec.js | 7 +- .../sidebar/components/copy/copyable_field_spec.js | 4 - .../copy/sidebar_reference_widget_spec.js | 8 +- .../components/crm_contacts/crm_contacts_spec.js | 5 +- .../components/date/sidebar_date_widget_spec.js | 42 +- .../components/date/sidebar_formatted_date_spec.js | 4 - .../components/date/sidebar_inherit_date_spec.js | 4 - .../components/incidents/escalation_status_spec.js | 4 - .../incidents/sidebar_escalation_status_spec.js | 6 +- .../labels_select_vue/dropdown_button_spec.js | 4 - .../dropdown_contents_create_view_spec.js | 101 +- .../dropdown_contents_labels_view_spec.js | 354 +++--- .../labels_select_vue/dropdown_contents_spec.js | 18 +- .../labels_select_vue/dropdown_title_spec.js | 4 - .../dropdown_value_collapsed_spec.js | 6 +- .../labels_select_vue/dropdown_value_spec.js | 4 - .../labels/labels_select_vue/label_item_spec.js | 4 - .../labels_select_vue/labels_select_root_spec.js | 13 +- .../labels/labels_select_vue/store/actions_spec.js | 8 +- .../dropdown_contents_create_view_spec.js | 40 +- .../dropdown_contents_labels_view_spec.js | 16 +- .../labels_select_widget/dropdown_contents_spec.js | 32 +- .../labels_select_widget/dropdown_footer_spec.js | 4 - .../labels_select_widget/dropdown_header_spec.js | 8 +- .../labels_select_widget/dropdown_value_spec.js | 4 - .../embedded_labels_list_spec.js | 4 - .../labels/labels_select_widget/label_item_spec.js | 4 - .../labels_select_root_spec.js | 22 +- .../labels/labels_select_widget/mock_data.js | 11 + .../components/lock/edit_form_buttons_spec.js | 15 +- .../sidebar/components/lock/edit_form_spec.js | 5 - .../components/lock/issuable_lock_form_spec.js | 28 +- .../milestone/milestone_dropdown_spec.js | 4 +- .../components/move/issuable_move_dropdown_spec.js | 267 ++-- .../components/move/move_issue_button_spec.js | 10 +- .../components/move/move_issues_button_spec.js | 27 +- .../components/participants/participants_spec.js | 197 +-- .../sidebar_participants_widget_spec.js | 1 - .../components/reviewers/reviewer_title_spec.js | 5 - .../sidebar/components/reviewers/reviewers_spec.js | 4 - .../components/reviewers/sidebar_reviewers_spec.js | 3 - .../reviewers/uncollapsed_reviewer_list_spec.js | 153 ++- .../sidebar/components/severity/severity_spec.js | 7 - .../components/severity/sidebar_severity_spec.js | 157 --- .../severity/sidebar_severity_widget_spec.js | 160 +++ .../sidebar/components/sidebar_dropdown_spec.js | 4 +- .../components/sidebar_dropdown_widget_spec.js | 37 +- .../components/status/status_dropdown_spec.js | 4 - .../sidebar_subscriptions_widget_spec.js | 7 +- .../subscriptions/subscriptions_dropdown_spec.js | 4 - .../components/subscriptions/subscriptions_spec.js | 66 +- .../time_tracking/create_timelog_form_spec.js | 4 +- .../components/time_tracking/report_spec.js | 5 +- .../components/time_tracking/time_tracker_spec.js | 8 +- .../todo_toggle/sidebar_todo_widget_spec.js | 7 +- .../components/todo_toggle/todo_button_spec.js | 1 - .../sidebar/components/todo_toggle/todo_spec.js | 4 - .../components/toggle/toggle_sidebar_spec.js | 6 +- spec/frontend/sidebar/mock_data.js | 12 + spec/frontend/sidebar/sidebar_mediator_spec.js | 2 +- .../snippet_description_edit_spec.js.snap | 7 +- .../snippet_visibility_edit_spec.js.snap | 2 +- spec/frontend/snippets/components/edit_spec.js | 31 +- .../snippets/components/embed_dropdown_spec.js | 5 - spec/frontend/snippets/components/show_spec.js | 4 - .../components/snippet_blob_actions_edit_spec.js | 5 - .../snippets/components/snippet_blob_edit_spec.js | 8 +- .../snippets/components/snippet_blob_view_spec.js | 222 ++-- .../components/snippet_description_edit_spec.js | 4 - .../components/snippet_description_view_spec.js | 4 - .../snippets/components/snippet_header_spec.js | 138 +- .../snippets/components/snippet_title_spec.js | 4 - .../components/snippet_visibility_edit_spec.js | 4 - spec/frontend/snippets/mock_data.js | 19 + spec/frontend/streaming/chunk_writer_spec.js | 214 ++++ .../streaming/handle_streamed_anchor_link_spec.js | 132 ++ spec/frontend/streaming/html_stream_spec.js | 46 + .../streaming/rate_limit_stream_requests_spec.js | 155 +++ spec/frontend/streaming/render_balancer_spec.js | 69 + .../frontend/streaming/render_html_streams_spec.js | 96 ++ .../components/context_switcher_spec.js | 309 +++++ .../components/context_switcher_toggle_spec.js | 50 + .../super_sidebar/components/counter_spec.js | 11 + .../super_sidebar/components/create_menu_spec.js | 69 +- .../components/frequent_items_list_spec.js | 79 ++ .../global_search_autocomplete_items_spec.js | 128 ++ .../components/global_search_default_items_spec.js | 75 ++ .../components/global_search_scoped_items_spec.js | 91 ++ .../global_search/components/global_search_spec.js | 372 ++++++ .../components/global_search/mock_data.js | 456 +++++++ .../components/global_search/store/actions_spec.js | 111 ++ .../components/global_search/store/getters_spec.js | 334 +++++ .../global_search/store/mutations_spec.js | 63 + .../components/global_search/utils_spec.js | 60 + .../super_sidebar/components/groups_list_spec.js | 90 ++ .../super_sidebar/components/help_center_spec.js | 163 ++- .../super_sidebar/components/items_list_spec.js | 101 ++ .../super_sidebar/components/menu_section_spec.js | 102 ++ .../components/merge_request_menu_spec.js | 42 +- .../super_sidebar/components/nav_item_link_spec.js | 37 + .../components/nav_item_router_link_spec.js | 56 + .../super_sidebar/components/nav_item_spec.js | 156 +++ .../components/pinned_section_spec.js | 75 ++ .../super_sidebar/components/projects_list_spec.js | 85 ++ .../components/search_results_spec.js | 69 + .../super_sidebar/components/sidebar_menu_spec.js | 184 +++ .../components/sidebar_peek_behavior_spec.js | 207 +++ .../components/sidebar_portal_spec.js | 68 + .../super_sidebar/components/super_sidebar_spec.js | 224 +++- .../components/super_sidebar_toggle_spec.js | 106 ++ .../super_sidebar/components/user_bar_spec.js | 180 ++- .../super_sidebar/components/user_menu_spec.js | 502 ++++++++ .../components/user_name_group_spec.js | 114 ++ spec/frontend/super_sidebar/mock_data.js | 224 +++- .../super_sidebar_collapsed_state_manager_spec.js | 139 ++ .../super_sidebar/user_counts_manager_spec.js | 166 +++ spec/frontend/super_sidebar/utils_spec.js | 171 +++ .../surveys/merge_request_performance/app_spec.js | 28 +- spec/frontend/syntax_highlight_spec.js | 6 +- .../tags/components/delete_tag_modal_spec.js | 6 +- .../frontend/tags/components/sort_dropdown_spec.js | 6 - spec/frontend/terms/components/app_spec.js | 5 - .../terraform/components/empty_state_spec.js | 27 +- .../components/init_command_modal_spec.js | 74 +- .../components/states_table_actions_spec.js | 10 +- .../terraform/components/states_table_spec.js | 7 +- .../terraform/components/terraform_list_spec.js | 13 +- spec/frontend/test_setup.js | 13 + .../components/timelog_source_cell_spec.js | 136 ++ .../time_tracking/components/timelogs_app_spec.js | 238 ++++ .../components/timelogs_table_spec.js | 223 ++++ spec/frontend/toggles/index_spec.js | 3 +- .../token_access/inbound_token_access_spec.js | 4 +- spec/frontend/token_access/mock_data.js | 34 +- spec/frontend/token_access/opt_in_jwt_spec.js | 144 --- .../token_access/outbound_token_access_spec.js | 72 +- .../frontend/token_access/token_access_app_spec.js | 20 +- .../token_access/token_projects_table_spec.js | 38 +- spec/frontend/tooltips/components/tooltips_spec.js | 5 - .../tracking/tracking_initialization_spec.js | 22 +- spec/frontend/tracking/tracking_spec.js | 91 +- .../components/usage_quotas_app_spec.js | 4 - .../storage/components/project_storage_app_spec.js | 4 - .../components/project_storage_detail_spec.js | 52 +- .../storage/components/storage_type_icon_spec.js | 5 - .../storage/components/usage_graph_spec.js | 28 +- spec/frontend/usage_quotas/storage/mock_data.js | 26 +- .../user_lists/components/edit_user_list_spec.js | 6 +- .../user_lists/components/new_user_list_spec.js | 4 +- .../user_lists/components/user_lists_spec.js | 7 +- .../user_lists/components/user_lists_table_spec.js | 4 - .../frontend/user_lists/store/edit/actions_spec.js | 4 +- spec/frontend/user_lists/store/new/actions_spec.js | 4 +- spec/frontend/user_popovers_spec.js | 26 +- spec/frontend/validators/length_validator_spec.js | 91 ++ spec/frontend/vue3migration/compiler_spec.js | 38 + .../components/comments_on_root_level.vue | 5 + .../components/default_slot_with_comment.vue | 18 + .../components/key_inside_template.vue | 7 + spec/frontend/vue3migration/components/simple.vue | 10 + .../vue3migration/components/slot_with_comment.vue | 20 + .../components/slots_with_same_name.vue | 14 + .../components/v_once_inside_v_if.vue | 12 + spec/frontend/vue_compat_test_setup.js | 141 +++ .../components/action_buttons.js | 4 - .../components/added_commit_message_spec.js | 4 - .../components/approvals/approvals_spec.js | 257 ++-- .../approvals/approvals_summary_optional_spec.js | 5 - .../components/approvals/approvals_summary_spec.js | 48 +- .../components/artifacts_list_app_spec.js | 5 +- .../components/artifacts_list_spec.js | 4 - .../components/extensions/child_content_spec.js | 5 - .../components/extensions/status_icon_spec.js | 4 - .../components/mr_collapsible_extension_spec.js | 4 - .../components/mr_widget_alert_message_spec.js | 4 - .../components/mr_widget_author_spec.js | 1 - .../components/mr_widget_author_time_spec.js | 4 - .../components/mr_widget_container_spec.js | 4 - .../components/mr_widget_icon_spec.js | 4 - .../components/mr_widget_memory_usage_spec.js | 245 ++-- .../mr_widget_pipeline_container_spec.js | 4 - .../components/mr_widget_pipeline_spec.js | 7 - .../components/mr_widget_rebase_spec.js | 353 ++++-- .../components/mr_widget_related_links_spec.js | 4 - .../components/mr_widget_status_icon_spec.js | 5 - .../components/mr_widget_suggest_pipeline_spec.js | 4 - .../components/review_app_link_spec.js | 9 +- .../components/states/commit_edit_spec.js | 4 - .../components/states/merge_checks_failed_spec.js | 4 - ...rge_failed_pipeline_confirmation_dialog_spec.js | 10 +- .../components/states/mr_widget_archived_spec.js | 5 - .../states/mr_widget_auto_merge_enabled_spec.js | 2 - .../states/mr_widget_auto_merge_failed_spec.js | 6 +- .../components/states/mr_widget_checking_spec.js | 5 - .../components/states/mr_widget_closed_spec.js | 6 - .../mr_widget_commit_message_dropdown_spec.js | 4 - .../states/mr_widget_commits_header_spec.js | 4 - .../components/states/mr_widget_conflicts_spec.js | 4 - .../states/mr_widget_failed_to_merge_spec.js | 4 - .../components/states/mr_widget_merged_spec.js | 4 - .../components/states/mr_widget_merging_spec.js | 16 +- .../states/mr_widget_missing_branch_spec.js | 4 - .../states/mr_widget_not_allowed_spec.js | 5 - .../states/mr_widget_nothing_to_merge_spec.js | 62 +- .../states/mr_widget_pipeline_blocked_spec.js | 5 - .../states/mr_widget_pipeline_failed_spec.js | 5 - .../states/mr_widget_ready_to_merge_spec.js | 7 +- .../states/mr_widget_sha_mismatch_spec.js | 4 - .../states/mr_widget_squash_before_merge_spec.js | 4 - .../mr_widget_unresolved_discussions_spec.js | 44 +- .../components/states/new_ready_to_merge_spec.js | 4 - .../components/states/work_in_progress_spec.js | 6 +- .../__snapshots__/dynamic_content_spec.js.snap | 82 +- .../components/widget/action_buttons_spec.js | 4 - .../components/widget/dynamic_content_spec.js | 2 + .../components/widget/widget_spec.js | 26 +- .../deployment/deployment_action_button_spec.js | 4 - .../deployment/deployment_actions_spec.js | 10 +- .../deployment/deployment_list_spec.js | 1 - .../deployment/deployment_spec.js | 8 - .../deployment/deployment_view_button_spec.js | 98 +- .../extensions/test_report/index_spec.js | 1 - .../extentions/accessibility/index_spec.js | 3 +- .../extentions/code_quality/index_spec.js | 25 +- .../extentions/code_quality/mock_data.js | 14 + .../extentions/terraform/index_spec.js | 3 +- .../mr_widget_how_to_merge_modal_spec.js | 5 - .../mr_widget_options_spec.js | 189 +-- .../stores/get_state_key_spec.js | 2 +- .../vue_shared/alert_details/alert_details_spec.js | 10 +- .../alert_management_sidebar_todo_spec.js | 4 - .../vue_shared/alert_details/alert_metrics_spec.js | 63 - .../vue_shared/alert_details/alert_status_spec.js | 6 - .../alert_details/alert_summary_row_spec.js | 7 - .../vue_shared/alert_details/router_spec.js | 35 - .../sidebar/alert_sidebar_assignees_spec.js | 157 +-- .../alert_details/sidebar/alert_sidebar_spec.js | 3 - .../sidebar/alert_sidebar_status_spec.js | 6 - .../alert_management_system_note_spec.js | 7 - .../__snapshots__/expand_button_spec.js.snap | 8 +- .../__snapshots__/file_row_header_spec.js.snap | 40 - .../vue_shared/components/actions_button_spec.js | 4 - .../components/alert_details_table_spec.js | 5 - .../vue_shared/components/awards_list_spec.js | 10 - .../components/blob_viewers/rich_viewer_spec.js | 4 - .../components/blob_viewers/simple_viewer_spec.js | 4 - .../components/changed_file_icon_spec.js | 4 - .../components/chronic_duration_input_spec.js | 6 - .../vue_shared/components/ci_badge_link_spec.js | 4 - .../frontend/vue_shared/components/ci_icon_spec.js | 5 - .../vue_shared/components/clipboard_button_spec.js | 5 - .../vue_shared/components/clone_dropdown_spec.js | 5 - .../components/code_block_highlighted_spec.js | 4 - .../vue_shared/components/code_block_spec.js | 4 - .../components/color_picker/color_picker_spec.js | 6 +- .../color_select_dropdown/color_item_spec.js | 12 +- .../color_select_root_spec.js | 12 +- .../dropdown_contents_color_view_spec.js | 6 +- .../dropdown_contents_spec.js | 23 +- .../color_select_dropdown/dropdown_header_spec.js | 4 - .../color_select_dropdown/dropdown_value_spec.js | 15 +- spec/frontend/vue_shared/components/commit_spec.js | 4 - .../components/confidentiality_badge_spec.js | 17 +- .../confirm_danger/confirm_danger_modal_spec.js | 6 +- .../confirm_danger/confirm_danger_spec.js | 6 +- .../components/confirm_fork_modal_spec.js | 4 - .../vue_shared/components/confirm_modal_spec.js | 4 - .../components/content_transition_spec.js | 5 - .../date_time_picker_input_spec.js | 4 - .../date_time_picker/date_time_picker_spec.js | 4 - .../deployment_instance_spec.js | 12 - .../design_management/design_note_pin_spec.js | 4 - .../components/diff_stats_dropdown_spec.js | 34 +- .../components/diff_viewer/diff_viewer_spec.js | 4 - .../components/diff_viewer/utils_spec.js | 33 + .../diff_viewer/viewers/image_diff_viewer_spec.js | 4 - .../diff_viewer/viewers/mode_changed_spec.js | 4 - .../components/diff_viewer/viewers/renamed_spec.js | 250 ++-- .../components/dismissible_alert_spec.js | 4 - .../components/dismissible_container_spec.js | 4 - .../components/dismissible_feedback_alert_spec.js | 29 +- .../components/dom_element_listener_spec.js | 4 - .../components/dropdown/dropdown_button_spec.js | 4 - .../components/dropdown/dropdown_widget_spec.js | 11 +- .../dropdown_keyboard_navigation_spec.js | 25 +- .../vue_shared/components/ensure_data_spec.js | 1 - .../components/entity_select/entity_select_spec.js | 18 +- .../entity_select/project_select_spec.js | 18 +- .../vue_shared/components/expand_button_spec.js | 4 - .../components/file_finder/index_spec.js | 250 ++-- .../vue_shared/components/file_finder/item_spec.js | 14 +- .../vue_shared/components/file_icon_spec.js | 4 - .../vue_shared/components/file_row_header_spec.js | 28 +- .../vue_shared/components/file_row_spec.js | 14 +- .../vue_shared/components/file_tree_spec.js | 4 - .../filtered_search_bar_root_spec.js | 6 +- .../store/modules/filters/actions_spec.js | 22 +- .../filtered_search_bar/tokens/base_token_spec.js | 7 +- .../tokens/branch_token_spec.js | 98 +- .../tokens/crm_contact_token_spec.js | 8 +- .../tokens/crm_organization_token_spec.js | 8 +- .../filtered_search_bar/tokens/emoji_token_spec.js | 89 +- .../filtered_search_bar/tokens/label_token_spec.js | 140 +- .../tokens/milestone_token_spec.js | 111 +- .../tokens/release_token_spec.js | 9 +- .../filtered_search_bar/tokens/user_token_spec.js | 129 +- .../__snapshots__/form_footer_actions_spec.js.snap | 14 +- .../components/form/form_footer_actions_spec.js | 4 - .../form/input_copy_toggle_visibility_spec.js | 6 +- .../vue_shared/components/form/title_spec.js | 4 - .../vue_shared/components/gl_countdown_spec.js | 8 +- .../components/header_ci_component_spec.js | 5 - .../vue_shared/components/help_popover_spec.js | 4 - .../components/integration_help_text_spec.js | 5 - .../vue_shared/components/keep_alive_slots_spec.js | 4 - .../components/listbox_input/listbox_input_spec.js | 10 +- .../components/local_storage_sync_spec.js | 1 - .../components/markdown/apply_suggestion_spec.js | 5 - .../markdown/comment_templates_dropdown_spec.js | 76 ++ .../markdown/drawio_toolbar_button_spec.js | 66 + .../markdown/editor_mode_dropdown_spec.js | 58 - .../markdown/editor_mode_switcher_spec.js | 37 + .../vue_shared/components/markdown/field_spec.js | 70 +- .../components/markdown/field_view_spec.js | 8 +- .../vue_shared/components/markdown/header_spec.js | 84 +- .../components/markdown/markdown_editor_spec.js | 310 ++++- .../markdown/suggestion_diff_header_spec.js | 6 +- .../markdown/suggestion_diff_row_spec.js | 4 - .../components/markdown/suggestion_diff_spec.js | 5 - .../components/markdown/suggestions_spec.js | 54 +- .../components/markdown/toolbar_button_spec.js | 5 - .../vue_shared/components/markdown/toolbar_spec.js | 19 - .../markdown_drawer/markdown_drawer_spec.js | 10 +- .../vue_shared/components/memory_graph_spec.js | 20 +- .../metric_images/metric_images_tab_spec.js | 7 - .../metric_images/metric_images_table_spec.js | 7 - .../components/metric_images/store/actions_spec.js | 4 +- .../components/modal_copy_button_spec.js | 11 - .../vue_shared/components/navigation_tabs_spec.js | 5 - .../new_resource_dropdown_spec.js | 2 +- .../__snapshots__/placeholder_note_spec.js.snap | 4 +- .../components/notes/noteable_warning_spec.js | 13 - .../components/notes/placeholder_note_spec.js | 5 - .../notes/placeholder_system_note_spec.js | 5 - .../components/notes/system_note_spec.js | 3 +- .../components/notes/timeline_entry_item_spec.js | 4 - .../vue_shared/components/ordered_layout_spec.js | 4 - .../components/page_size_selector_spec.js | 4 - .../vue_shared/components/paginated_list_spec.js | 4 - .../paginated_table_with_search_and_tabs_spec.js | 69 +- .../pagination_bar/pagination_bar_spec.js | 4 - .../vue_shared/components/pagination_links_spec.js | 4 - .../vue_shared/components/panel_resizer_spec.js | 4 - .../vue_shared/components/papa_parse_alert_spec.js | 4 - .../vue_shared/components/project_avatar_spec.js | 5 +- .../project_selector/project_list_item_spec.js | 136 +- .../project_selector/project_selector_spec.js | 4 +- .../projects_list/projects_list_item_spec.js | 266 ++++ .../components/projects_list/projects_list_spec.js | 34 + .../__snapshots__/code_instruction_spec.js.snap | 32 +- .../__snapshots__/history_item_spec.js.snap | 2 +- .../components/registry/code_instruction_spec.js | 8 +- .../components/registry/details_row_spec.js | 5 - .../components/registry/history_item_spec.js | 5 - .../components/registry/list_item_spec.js | 5 - .../components/registry/metadata_item_spec.js | 7 +- .../registry/persisted_dropdown_selection_spec.js | 4 - .../components/registry/registry_search_spec.js | 5 - .../components/registry/title_area_spec.js | 5 - .../resizable_chart_container_spec.js.snap | 23 - .../__snapshots__/skeleton_loader_spec.js.snap | 4 +- .../resizable_chart_container_spec.js | 64 - .../resizable_chart/skeleton_loader_spec.js | 6 - .../components/rich_timestamp_tooltip_spec.js | 4 - .../runner_docker_instructions_spec.js.snap | 3 - .../runner_kubernetes_instructions_spec.js.snap | 3 - .../instructions/runner_cli_instructions_spec.js | 10 +- .../runner_docker_instructions_spec.js | 6 +- .../runner_kubernetes_instructions_spec.js | 6 +- .../runner_instructions_modal_spec.js | 81 +- .../runner_instructions_spec.js | 6 +- .../merge_request_artifact_download_spec.js | 8 +- .../components/security_reports/help_icon_spec.js | 5 - .../security_reports/security_summary_spec.js | 5 - .../segmented_control_button_group_spec.js | 4 - .../components/settings/settings_block_spec.js | 4 - .../vue_shared/components/slot_switch_spec.js | 11 +- .../components/smart_virtual_list_spec.js | 5 +- .../vue_shared/components/source_editor_spec.js | 4 - .../components/chunk_deprecated_spec.js | 2 - .../source_viewer/components/chunk_line_spec.js | 8 - .../source_viewer/components/chunk_spec.js | 3 - .../source_viewer/source_viewer_deprecated_spec.js | 23 +- .../components/source_viewer/source_viewer_spec.js | 2 - .../vue_shared/components/split_button_spec.js | 5 +- .../components/stacked_progress_bar_spec.js | 4 - .../vue_shared/components/table_pagination_spec.js | 4 - .../vue_shared/components/time_ago_tooltip_spec.js | 26 +- .../timezone_dropdown/timezone_dropdown_spec.js | 36 +- .../components/tooltip_on_truncate_spec.js | 36 +- .../truncated_text/truncated_text_spec.js | 113 ++ .../__snapshots__/upload_dropzone_spec.js.snap | 14 +- .../upload_dropzone/upload_dropzone_spec.js | 7 - .../vue_shared/components/url_sync_spec.js | 4 - .../components/usage_quotas/usage_banner_spec.js | 4 - .../user_avatar/user_avatar_image_spec.js | 4 - .../user_avatar/user_avatar_link_spec.js | 4 - .../user_avatar/user_avatar_list_spec.js | 33 +- .../components/user_callout_dismisser_spec.js | 22 +- .../user_deletion_obstacles_list_spec.js | 6 +- .../components/user_popover/user_popover_spec.js | 16 +- .../vue_shared/components/user_select_spec.js | 5 +- .../components/vuex_module_provider_spec.js | 15 +- .../vue_shared/components/web_ide_link_spec.js | 158 +-- .../vue_shared/directives/track_event_spec.js | 61 +- .../vue_shared/directives/validation_spec.js | 5 - .../issuable_blocked_icon_spec.js.snap | 2 +- .../create/components/issuable_create_root_spec.js | 4 - .../create/components/issuable_form_spec.js | 4 - .../components/issuable_label_selector_spec.js | 37 +- .../issuable/issuable_blocked_icon_spec.js | 32 +- .../components/issuable_bulk_edit_sidebar_spec.js | 1 - .../issuable/list/components/issuable_item_spec.js | 8 +- .../list/components/issuable_list_root_spec.js | 8 +- .../issuable/list/components/issuable_tabs_spec.js | 1 - .../frontend/vue_shared/issuable/list/mock_data.js | 6 + .../issuable/show/components/issuable_body_spec.js | 149 +-- .../show/components/issuable_description_spec.js | 4 - .../show/components/issuable_edit_form_spec.js | 7 +- .../show/components/issuable_header_spec.js | 24 +- .../show/components/issuable_show_root_spec.js | 4 - .../show/components/issuable_title_spec.js | 28 +- .../components/issuable_sidebar_root_spec.js | 1 - .../components/legacy_container_spec.js | 2 - .../new_namespace/components/welcome_spec.js | 2 - .../new_namespace/new_namespace_page_spec.js | 33 +- .../vue_shared/plugins/global_toast_spec.js | 22 +- .../components/section_layout_spec.js | 4 - .../components/manage_via_mr_spec.js | 42 +- .../security_report_download_dropdown_spec.js | 5 - .../security_reports/security_reports_app_spec.js | 8 +- .../webhooks/components/form_url_app_spec.js | 4 - .../webhooks/components/form_url_mask_item_spec.js | 6 +- .../webhooks/components/push_events_spec.js | 2 +- .../webhooks/components/test_dropdown_spec.js | 13 +- spec/frontend/whats_new/components/app_spec.js | 3 +- spec/frontend/whats_new/components/feature_spec.js | 5 - .../whats_new/utils/get_drawer_body_height_spec.js | 4 - spec/frontend/whats_new/utils/notification_spec.js | 5 +- spec/frontend/work_items/components/app_spec.js | 4 - .../work_items/components/item_state_spec.js | 4 - .../work_items/components/item_title_spec.js | 6 +- .../work_item_note_replying_spec.js.snap | 2 +- .../components/notes/activity_filter_spec.js | 74 -- .../notes/work_item_activity_sort_filter_spec.js | 109 ++ .../components/notes/work_item_add_note_spec.js | 112 +- .../notes/work_item_comment_form_spec.js | 100 +- .../components/notes/work_item_discussion_spec.js | 44 +- .../work_item_history_only_filter_note_spec.js | 44 + .../notes/work_item_note_actions_spec.js | 207 ++- .../components/notes/work_item_note_spec.js | 137 +- .../notes/work_item_notes_activity_header_spec.js | 63 + .../work_items/components/widget_wrapper_spec.js | 2 +- .../components/work_item_actions_spec.js | 235 +++- .../components/work_item_assignees_spec.js | 37 +- .../components/work_item_award_emoji_spec.js | 170 +++ .../components/work_item_created_updated_spec.js | 85 +- .../work_item_description_rendered_spec.js | 4 - .../components/work_item_description_spec.js | 56 +- .../components/work_item_detail_modal_spec.js | 137 +- .../work_items/components/work_item_detail_spec.js | 213 ++-- .../components/work_item_due_date_spec.js | 4 - .../work_items/components/work_item_labels_spec.js | 58 +- .../okr_actions_split_button_spec.js | 4 - .../work_item_children_wrapper_spec.js | 98 ++ .../work_item_link_child_metadata_spec.js | 19 +- .../work_item_links/work_item_link_child_spec.js | 152 ++- .../work_item_links/work_item_links_form_spec.js | 8 +- .../work_item_links/work_item_links_menu_spec.js | 6 +- .../work_item_links/work_item_links_spec.js | 228 ++-- .../work_item_links/work_item_tree_spec.js | 100 +- .../components/work_item_milestone_spec.js | 64 +- .../work_items/components/work_item_notes_spec.js | 158 +-- .../work_items/components/work_item_state_spec.js | 4 - .../work_items/components/work_item_title_spec.js | 4 - .../work_items/components/work_item_todos_spec.js | 97 ++ .../components/work_item_type_icon_spec.js | 6 +- spec/frontend/work_items/mock_data.js | 1336 +++++++++++++------- .../work_items/pages/create_work_item_spec.js | 25 +- .../work_items/pages/work_item_root_spec.js | 6 +- spec/frontend/work_items/router_spec.js | 17 +- spec/frontend/work_items/utils_spec.js | 21 +- .../work_items_hierarchy/components/app_spec.js | 4 - .../components/hierarchy_spec.js | 4 - spec/frontend/zen_mode_spec.js | 37 +- spec/frontend_integration/README.md | 2 + .../content_editor_integration_spec.js | 8 +- .../ide/ide_integration_spec.js | 1 - .../ide/user_opens_file_spec.js | 1 - .../ide/user_opens_ide_spec.js | 5 +- .../frontend_integration/ide/user_opens_mr_spec.js | 1 - .../snippets/snippets_notes_spec.js | 7 +- spec/graphql/graphql_triggers_spec.rb | 52 +- spec/graphql/mutations/achievements/award_spec.rb | 53 + spec/graphql/mutations/achievements/delete_spec.rb | 56 + spec/graphql/mutations/achievements/revoke_spec.rb | 57 + spec/graphql/mutations/achievements/update_spec.rb | 57 + .../alert_management/alerts/set_assignees_spec.rb | 1 - .../alert_management/alerts/todo/create_spec.rb | 1 - .../alert_management/create_alert_issue_spec.rb | 2 - .../alert_management/update_alert_status_spec.rb | 1 - .../ci/job_token_scope/add_project_spec.rb | 52 +- .../concerns/mutations/finds_by_gid_spec.rb | 26 - .../container_repositories/destroy_spec.rb | 2 +- .../container_repositories/destroy_tags_spec.rb | 4 +- .../customer_relations/contacts/create_spec.rb | 12 +- .../organizations/create_spec.rb | 2 +- .../organizations/update_spec.rb | 12 +- .../mutations/design_management/delete_spec.rb | 31 +- spec/graphql/mutations/environments/stop_spec.rb | 72 ++ .../mutations/members/bulk_update_base_spec.rb | 16 + .../mutations/release_asset_links/create_spec.rb | 2 +- .../mutations/release_asset_links/delete_spec.rb | 14 +- .../mutations/release_asset_links/update_spec.rb | 2 +- spec/graphql/mutations/work_items/update_spec.rb | 21 + .../achievements/achievements_resolver_spec.rb | 44 + spec/graphql/resolvers/base_resolver_spec.rb | 2 +- spec/graphql/resolvers/blobs_resolver_spec.rb | 8 + .../graphql/resolvers/ci/all_jobs_resolver_spec.rb | 2 +- .../resolvers/ci/group_runners_resolver_spec.rb | 2 +- .../ci/inherited_variables_resolver_spec.rb | 40 + spec/graphql/resolvers/ci/jobs_resolver_spec.rb | 21 +- .../resolvers/ci/project_runners_resolver_spec.rb | 2 +- .../resolvers/ci/runner_projects_resolver_spec.rb | 26 +- .../resolvers/ci/runner_status_resolver_spec.rb | 28 +- spec/graphql/resolvers/ci/runners_resolver_spec.rb | 10 +- .../resolvers/ci/variables_resolver_spec.rb | 2 +- .../clusters/agent_tokens_resolver_spec.rb | 13 +- .../authorizations/ci_access_resolver_spec.rb | 28 + .../authorizations/user_access_resolver_spec.rb | 29 + .../resolvers/crm/contacts_resolver_spec.rb | 2 +- .../crm/organization_state_counts_resolver_spec.rb | 10 +- .../resolvers/crm/organizations_resolver_spec.rb | 44 +- .../group_data_transfer_resolver_spec.rb | 65 + .../project_data_transfer_resolver_spec.rb | 68 + .../resolvers/data_transfer_resolver_spec.rb | 31 - .../resolvers/group_labels_resolver_spec.rb | 34 + .../resolvers/group_milestones_resolver_spec.rb | 66 +- spec/graphql/resolvers/labels_resolver_spec.rb | 34 + .../resolvers/metrics/dashboard_resolver_spec.rb | 14 +- .../metrics/dashboards/annotation_resolver_spec.rb | 16 +- .../resolvers/paginated_tree_resolver_spec.rb | 12 +- .../resolvers/project_issues_resolver_spec.rb | 10 +- .../resolvers/project_milestones_resolver_spec.rb | 38 - spec/graphql/resolvers/timelog_resolver_spec.rb | 22 +- .../types/achievements/achievement_type_spec.rb | 1 + .../achievements/user_achievement_type_spec.rb | 24 + .../graphql/types/ci/catalog/resource_type_spec.rb | 18 + .../types/ci/config/include_type_enum_spec.rb | 2 +- .../types/ci/inherited_ci_variable_type_spec.rb | 19 + spec/graphql/types/ci/job_trace_type_spec.rb | 27 + spec/graphql/types/ci/job_type_spec.rb | 9 +- spec/graphql/types/ci/runner_manager_type_spec.rb | 18 + spec/graphql/types/ci/runner_type_spec.rb | 8 +- spec/graphql/types/ci/variable_sort_enum_spec.rb | 2 +- .../clusters/agent_activity_event_type_spec.rb | 2 +- .../types/clusters/agent_token_type_spec.rb | 2 +- spec/graphql/types/clusters/agent_type_spec.rb | 2 +- .../agents/authorizations/ci_access_type_spec.rb | 11 + .../agents/authorizations/user_access_type_spec.rb | 11 + .../types/commit_signature_interface_spec.rb | 5 + .../commit_signatures/ssh_signature_type_spec.rb | 2 +- .../project_data_transfer_type_spec.rb | 38 + .../design_at_version_type_spec.rb | 2 +- .../types/design_management/design_type_spec.rb | 7 +- spec/graphql/types/group_type_spec.rb | 2 +- spec/graphql/types/issue_type_spec.rb | 45 +- spec/graphql/types/key_type_spec.rb | 2 +- spec/graphql/types/merge_request_type_spec.rb | 4 +- spec/graphql/types/permission_types/issue_spec.rb | 2 +- .../types/permission_types/work_item_spec.rb | 3 +- .../types/project_member_relation_enum_spec.rb | 3 +- .../types/project_statistics_redirect_type_spec.rb | 10 + spec/graphql/types/project_type_spec.rb | 13 +- .../types/projects/fork_details_type_spec.rb | 2 + spec/graphql/types/release_asset_link_type_spec.rb | 2 +- .../types/root_storage_statistics_type_spec.rb | 2 +- .../time_tracking/timelog_connection_type_spec.rb | 2 +- spec/graphql/types/timelog_type_spec.rb | 2 +- spec/graphql/types/user_preferences_type_spec.rb | 3 +- spec/graphql/types/user_type_spec.rb | 3 +- .../types/visibility_pipeline_id_type_enum_spec.rb | 13 + spec/graphql/types/work_item_type_spec.rb | 5 +- .../available_export_fields_enum_spec.rb | 27 + .../types/work_items/widget_interface_spec.rb | 13 +- .../work_items/widgets/award_emoji_type_spec.rb | 12 + .../widgets/current_user_todos_input_type_spec.rb | 9 + .../widgets/current_user_todos_type_spec.rb | 11 + .../widgets/hierarchy_update_input_type_spec.rb | 8 +- .../work_items/widgets/notifications_type_spec.rb | 12 + .../notifications_update_input_type_spec.rb | 9 + spec/haml_lint/linter/no_plain_nodes_spec.rb | 34 +- spec/helpers/abuse_reports_helper_spec.rb | 13 + spec/helpers/access_tokens_helper_spec.rb | 2 +- spec/helpers/admin/abuse_reports_helper_spec.rb | 34 + .../analytics/cycle_analytics_helper_spec.rb | 61 - spec/helpers/application_helper_spec.rb | 80 +- spec/helpers/application_settings_helper_spec.rb | 74 +- spec/helpers/artifacts_helper_spec.rb | 1 + spec/helpers/avatars_helper_spec.rb | 159 ++- spec/helpers/blame_helper_spec.rb | 12 +- spec/helpers/blob_helper_spec.rb | 26 +- spec/helpers/broadcast_messages_helper_spec.rb | 79 +- spec/helpers/ci/builds_helper_spec.rb | 59 - spec/helpers/ci/catalog/resources_helper_spec.rb | 35 + spec/helpers/ci/jobs_helper_spec.rb | 53 +- spec/helpers/ci/pipeline_editor_helper_spec.rb | 7 +- spec/helpers/ci/pipelines_helper_spec.rb | 36 +- spec/helpers/ci/runners_helper_spec.rb | 38 +- spec/helpers/ci/variables_helper_spec.rb | 2 +- spec/helpers/clusters_helper_spec.rb | 84 ++ spec/helpers/commits_helper_spec.rb | 15 +- spec/helpers/device_registration_helper_spec.rb | 37 + spec/helpers/diff_helper_spec.rb | 59 +- spec/helpers/emoji_helper_spec.rb | 22 +- spec/helpers/environment_helper_spec.rb | 18 +- spec/helpers/environments_helper_spec.rb | 18 +- spec/helpers/explore_helper_spec.rb | 2 +- spec/helpers/feature_flags_helper_spec.rb | 14 +- spec/helpers/groups/observability_helper_spec.rb | 91 +- spec/helpers/groups_helper_spec.rb | 7 +- spec/helpers/ide_helper_spec.rb | 191 +-- spec/helpers/integrations_helper_spec.rb | 7 +- spec/helpers/issuables_helper_spec.rb | 117 +- spec/helpers/issues_helper_spec.rb | 26 +- spec/helpers/jira_connect_helper_spec.rb | 35 +- spec/helpers/labels_helper_spec.rb | 14 +- spec/helpers/markup_helper_spec.rb | 39 + spec/helpers/merge_requests_helper_spec.rb | 72 ++ spec/helpers/namespaces_helper_spec.rb | 37 +- spec/helpers/nav/new_dropdown_helper_spec.rb | 71 +- spec/helpers/nav/top_nav_helper_spec.rb | 58 +- spec/helpers/nav_helper_spec.rb | 76 +- spec/helpers/notes_helper_spec.rb | 13 +- spec/helpers/notify_helper_spec.rb | 17 +- spec/helpers/packages_helper_spec.rb | 140 +- spec/helpers/page_layout_helper_spec.rb | 21 +- spec/helpers/plan_limits_helper_spec.rb | 28 + spec/helpers/profiles_helper_spec.rb | 44 +- .../helpers/projects/ml/experiments_helper_spec.rb | 48 +- spec/helpers/projects/pipeline_helper_spec.rb | 3 +- .../projects/settings/branch_rules_helper_spec.rb | 25 + spec/helpers/projects_helper_spec.rb | 190 ++- spec/helpers/protected_refs_helper_spec.rb | 51 + spec/helpers/registrations_helper_spec.rb | 16 - .../routing/pseudonymization_helper_spec.rb | 228 ++-- spec/helpers/safe_format_helper_spec.rb | 41 + spec/helpers/search_helper_spec.rb | 55 + spec/helpers/sessions_helper_spec.rb | 34 +- spec/helpers/sidebars_helper_spec.rb | 422 ++++++- spec/helpers/sorting_helper_spec.rb | 54 + spec/helpers/storage_helper_spec.rb | 28 +- spec/helpers/todos_helper_spec.rb | 60 +- spec/helpers/tree_helper_spec.rb | 1 + spec/helpers/users/callouts_helper_spec.rb | 70 +- spec/helpers/users/group_callouts_helper_spec.rb | 10 +- spec/helpers/users_helper_spec.rb | 103 +- spec/helpers/version_check_helper_spec.rb | 30 + spec/helpers/visibility_level_helper_spec.rb | 25 +- spec/helpers/work_items_helper_spec.rb | 24 + .../active_record_transaction_observer_spec.rb | 49 + .../check_forced_decomposition_spec.rb | 8 +- spec/initializers/circuitbox_spec.rb | 15 + spec/initializers/direct_upload_support_spec.rb | 4 +- spec/initializers/google_cloud_profiler_spec.rb | 87 ++ spec/initializers/load_balancing_spec.rb | 2 +- spec/initializers/mail_starttls_patch_spec.rb | 86 ++ spec/initializers/net_http_patch_spec.rb | 6 + spec/initializers/net_http_response_patch_spec.rb | 10 +- spec/initializers/safe_session_store_patch_spec.rb | 62 + spec/initializers/settings_spec.rb | 7 +- spec/lib/api/ci/helpers/runner_spec.rb | 74 +- .../entities/clusters/agent_authorization_spec.rb | 36 - .../agents/authorizations/ci_access_spec.rb | 36 + spec/lib/api/entities/ml/mlflow/run_info_spec.rb | 4 +- spec/lib/api/entities/ml/mlflow/run_spec.rb | 2 +- .../lib/api/entities/personal_access_token_spec.rb | 2 +- spec/lib/api/entities/plan_limit_spec.rb | 1 - .../api/entities/project_job_token_scope_spec.rb | 38 + spec/lib/api/entities/project_spec.rb | 22 + spec/lib/api/entities/ssh_key_spec.rb | 2 +- spec/lib/api/entities/user_spec.rb | 52 +- spec/lib/api/github/entities_spec.rb | 2 +- spec/lib/api/helpers/internal_helpers_spec.rb | 60 + spec/lib/api/helpers/members_helpers_spec.rb | 18 - spec/lib/api/helpers/packages/npm_spec.rb | 133 ++ spec/lib/api/helpers/packages_helpers_spec.rb | 3 +- spec/lib/api/helpers_spec.rb | 2 +- .../jira_connect/serializers/branch_entity_spec.rb | 49 +- .../jira_connect/serializers/build_entity_spec.rb | 21 +- .../serializers/feature_flag_entity_spec.rb | 10 +- spec/lib/atlassian/jira_connect_spec.rb | 2 +- .../lib/atlassian/jira_issue_key_extractor_spec.rb | 10 +- .../jira_issue_key_extractors/branch_spec.rb | 57 + spec/lib/backup/database_spec.rb | 111 +- spec/lib/backup/gitaly_backup_spec.rb | 22 +- spec/lib/backup/manager_spec.rb | 52 +- spec/lib/backup/repositories_spec.rb | 11 +- .../banzai/filter/blockquote_fence_filter_spec.rb | 4 + .../lib/banzai/filter/code_language_filter_spec.rb | 82 ++ .../banzai/filter/commit_trailers_filter_spec.rb | 21 +- .../lib/banzai/filter/external_link_filter_spec.rb | 32 +- .../filter/inline_grafana_metrics_filter_spec.rb | 6 +- .../filter/inline_observability_filter_spec.rb | 88 +- .../issuable_reference_expansion_filter_spec.rb | 196 ++- spec/lib/banzai/filter/kroki_filter_spec.rb | 42 +- .../banzai/filter/markdown_engines/base_spec.rb | 17 + .../filter/markdown_engines/common_mark_spec.rb | 17 + spec/lib/banzai/filter/markdown_filter_spec.rb | 21 +- spec/lib/banzai/filter/math_filter_spec.rb | 11 +- spec/lib/banzai/filter/mermaid_filter_spec.rb | 2 +- spec/lib/banzai/filter/plantuml_filter_spec.rb | 12 +- .../references/design_reference_filter_spec.rb | 10 +- .../references/issue_reference_filter_spec.rb | 9 + .../merge_request_reference_filter_spec.rb | 9 + .../filter/references/reference_cache_spec.rb | 5 +- .../references/work_item_reference_filter_spec.rb | 314 +++++ .../banzai/filter/repository_link_filter_spec.rb | 13 +- spec/lib/banzai/filter/suggestion_filter_spec.rb | 2 +- .../banzai/filter/syntax_highlight_filter_spec.rb | 84 +- .../filter/timeout_html_pipeline_filter_spec.rb | 2 +- .../filter/timeout_text_pipeline_filter_spec.rb | 15 + spec/lib/banzai/issuable_extractor_spec.rb | 15 +- spec/lib/banzai/pipeline/gfm_pipeline_spec.rb | 2 +- .../timeline_event_pipeline_spec.rb | 6 +- .../pipeline/plain_markdown_pipeline_spec.rb | 4 +- spec/lib/banzai/pipeline/wiki_pipeline_spec.rb | 40 +- .../banzai/reference_parser/commit_parser_spec.rb | 31 +- .../reference_parser/work_item_parser_spec.rb | 46 + spec/lib/banzai/reference_redactor_spec.rb | 17 +- spec/lib/banzai/renderer_spec.rb | 4 - spec/lib/bulk_imports/clients/graphql_spec.rb | 31 - spec/lib/bulk_imports/clients/http_spec.rb | 37 +- spec/lib/bulk_imports/features_spec.rb | 43 - .../pipelines/project_entities_pipeline_spec.rb | 18 +- spec/lib/bulk_imports/groups/stage_spec.rb | 58 +- .../group_attributes_transformer_spec.rb | 130 +- spec/lib/bulk_imports/ndjson_pipeline_spec.rb | 54 +- .../pipelines/ci_pipelines_pipeline_spec.rb | 8 + .../pipelines/commit_notes_pipeline_spec.rb | 69 + .../projects/pipelines/project_pipeline_spec.rb | 2 +- .../projects/pipelines/references_pipeline_spec.rb | 10 + .../project_attributes_transformer_spec.rb | 92 +- .../container_registry/gitlab_api_client_spec.rb | 357 +++++- spec/lib/container_registry/path_spec.rb | 10 +- .../collector/payload_validator_spec.rb | 2 +- .../lib/error_tracking/sentry_client/token_spec.rb | 21 + .../lib/feature_groups/gitlab_team_members_spec.rb | 65 - spec/lib/feature_spec.rb | 57 +- .../batched_background_migration_generator_spec.rb | 82 ++ .../expected_files/my_batched_migration.txt | 22 + .../my_batched_migration_dictionary_matcher.txt | 6 + .../my_batched_migration_spec_matcher.txt | 7 + .../expected_files/queue_my_batched_migration.txt | 28 + .../queue_my_batched_migration_spec.txt | 26 + .../snowplow_event_definition_generator_spec.rb | 26 +- .../analytics/cycle_analytics/average_spec.rb | 4 +- .../cycle_analytics/request_params_spec.rb | 40 + .../stage_events/stage_event_spec.rb | 4 +- .../api_authentication/token_resolver_spec.rb | 2 +- spec/lib/gitlab/app_logger_spec.rb | 20 +- spec/lib/gitlab/asciidoc_spec.rb | 12 +- spec/lib/gitlab/audit/auditor_spec.rb | 33 +- spec/lib/gitlab/auth/auth_finders_spec.rb | 13 +- spec/lib/gitlab/auth/o_auth/auth_hash_spec.rb | 81 +- spec/lib/gitlab/auth/o_auth/provider_spec.rb | 2 +- spec/lib/gitlab/auth/o_auth/user_spec.rb | 83 +- .../otp/strategies/duo_auth/manual_otp_spec.rb | 94 ++ .../lib/gitlab/auth/u2f_webauthn_converter_spec.rb | 29 - spec/lib/gitlab/auth_spec.rb | 120 +- spec/lib/gitlab/avatar_cache_spec.rb | 54 +- ...n_mode_scope_for_personal_access_tokens_spec.rb | 11 +- ...fill_cluster_agents_has_vulnerabilities_spec.rb | 10 +- ...backfill_design_management_repositories_spec.rb | 68 + .../backfill_environment_tiers_spec.rb | 10 +- .../backfill_group_features_spec.rb | 18 +- .../backfill_imported_issue_search_data_spec.rb | 16 +- .../backfill_namespace_details_spec.rb | 43 +- ...ckfill_namespace_id_for_namespace_route_spec.rb | 35 +- ...ill_namespace_id_of_vulnerability_reads_spec.rb | 17 +- ...ckfill_namespace_traversal_ids_children_spec.rb | 21 - .../backfill_namespace_traversal_ids_roots_spec.rb | 21 - .../backfill_partitioned_table_spec.rb | 140 ++ .../backfill_prepared_at_merge_requests_spec.rb | 55 + ...t_feature_package_registry_access_level_spec.rb | 17 +- .../backfill_project_member_namespace_id_spec.rb | 70 +- .../backfill_project_namespace_details_spec.rb | 47 +- .../backfill_project_wiki_repositories_spec.rb | 65 + .../backfill_releases_author_id_spec.rb | 59 +- .../backfill_snippet_repositories_spec.rb | 68 +- .../backfill_upvotes_count_on_issues_spec.rb | 46 - .../backfill_user_namespace_spec.rb | 39 - ...kfill_vulnerability_reads_cluster_agent_spec.rb | 10 +- .../backfill_work_item_type_id_for_issues_spec.rb | 29 +- .../batched_migration_job_spec.rb | 22 + .../cleanup_orphaned_lfs_objects_projects_spec.rb | 85 -- ...sonal_access_tokens_with_nil_expires_at_spec.rb | 38 + .../delete_orphaned_deployments_spec.rb | 54 - .../delete_orphaned_packages_dependencies_spec.rb | 57 + ..._policies_linked_to_no_container_images_spec.rb | 142 --- .../drop_invalid_security_findings_spec.rb | 57 - .../drop_invalid_vulnerabilities_spec.rb | 126 -- .../encrypt_ci_trigger_token_spec.rb | 4 +- ...ract_project_topics_into_separate_table_spec.rb | 46 - .../fix_first_mentioned_in_commit_at_spec.rb | 166 --- .../fix_merge_request_diff_commit_users_spec.rb | 25 - .../fix_vulnerability_reads_has_issues_spec.rb | 100 ++ .../issues_internal_id_scope_updater_spec.rb | 90 ++ ...te_evidences_for_vulnerability_findings_spec.rb | 119 ++ .../migrate_human_user_type_spec.rb | 43 + ...igrate_links_for_vulnerability_findings_spec.rb | 192 +++ ...migrate_merge_request_diff_commit_users_spec.rb | 413 ------ ...ct_taggings_context_from_tags_to_topics_spec.rb | 30 - ...remediations_for_vulnerability_findings_spec.rb | 173 +++ .../migrate_u2f_webauthn_spec.rb | 67 - ...ner_registry_enabled_to_project_feature_spec.rb | 98 -- ..._creator_id_column_of_orphaned_projects_spec.rb | 3 +- .../nullify_orphan_runner_id_on_ci_builds_spec.rb | 2 +- ...ulate_topics_total_projects_count_cache_spec.rb | 35 - ...populate_vulnerability_dismissal_fields_spec.rb | 114 ++ .../prune_stale_project_export_jobs_spec.rb | 17 +- ...culate_vulnerabilities_occurrences_uuid_spec.rb | 530 -------- ...move_backfilled_job_artifacts_expire_at_spec.rb | 6 +- ...move_duplicate_vulnerabilities_findings_spec.rb | 171 --- ..._and_duplicate_vulnerabilities_findings_spec.rb | 2 +- ..._project_group_link_with_missing_groups_spec.rb | 124 ++ .../remove_self_managed_wiki_notes_spec.rb | 17 +- .../remove_vulnerability_finding_links_spec.rb | 2 +- ..._too_many_tags_skipped_registry_imports_spec.rb | 72 +- .../set_correct_vulnerability_state_spec.rb | 16 +- ...cense_available_for_non_public_projects_spec.rb | 33 +- ...migrate_merge_request_diff_commit_users_spec.rb | 50 - ...ect_removal_to_null_for_user_namespaces_spec.rb | 2 +- ...acker_data_deployment_type_based_on_url_spec.rb | 10 +- .../update_timelogs_project_id_spec.rb | 52 - ...ere_two_factor_auth_required_from_group_spec.rb | 84 -- spec/lib/gitlab/background_task_spec.rb | 4 +- .../gitlab/bare_repository_import/importer_spec.rb | 197 --- .../bare_repository_import/repository_spec.rb | 123 -- spec/lib/gitlab/bitbucket_import/importer_spec.rb | 2 +- .../bitbucket_import/project_creator_spec.rb | 4 +- spec/lib/gitlab/bullet/exclusions_spec.rb | 15 +- spec/lib/gitlab/cache/client_spec.rb | 162 +++ spec/lib/gitlab/cache/metadata_spec.rb | 13 - spec/lib/gitlab/cache/metrics_spec.rb | 5 - spec/lib/gitlab/changes_list_spec.rb | 2 +- spec/lib/gitlab/chat/responder_spec.rb | 68 +- spec/lib/gitlab/checks/changes_access_spec.rb | 12 +- spec/lib/gitlab/checks/diff_check_spec.rb | 12 +- spec/lib/gitlab/ci/ansi2json/state_spec.rb | 68 + spec/lib/gitlab/ci/ansi2json_spec.rb | 2 +- spec/lib/gitlab/ci/badge/release/template_spec.rb | 23 +- spec/lib/gitlab/ci/build/auto_retry_spec.rb | 2 +- spec/lib/gitlab/ci/build/cache_spec.rb | 47 +- spec/lib/gitlab/ci/build/context/build_spec.rb | 25 +- spec/lib/gitlab/ci/build/context/global_spec.rb | 11 +- spec/lib/gitlab/ci/build/hook_spec.rb | 2 +- spec/lib/gitlab/ci/build/rules_spec.rb | 144 ++- .../lib/gitlab/ci/components/instance_path_spec.rb | 35 +- spec/lib/gitlab/ci/config/entry/cache_spec.rb | 26 +- spec/lib/gitlab/ci/config/entry/job_spec.rb | 78 +- spec/lib/gitlab/ci/config/entry/policy_spec.rb | 4 +- .../lib/gitlab/ci/config/entry/processable_spec.rb | 2 +- .../ci/config/entry/product/parallel_spec.rb | 6 +- spec/lib/gitlab/ci/config/entry/publish_spec.rb | 40 + .../lib/gitlab/ci/config/entry/pull_policy_spec.rb | 4 +- .../config/entry/reports/coverage_report_spec.rb | 2 +- spec/lib/gitlab/ci/config/entry/reports_spec.rb | 2 +- spec/lib/gitlab/ci/config/entry/root_spec.rb | 18 +- spec/lib/gitlab/ci/config/entry/trigger_spec.rb | 2 +- spec/lib/gitlab/ci/config/external/context_spec.rb | 70 +- .../ci/config/external/file/artifact_spec.rb | 43 +- .../gitlab/ci/config/external/file/base_spec.rb | 133 +- .../ci/config/external/file/component_spec.rb | 35 +- .../gitlab/ci/config/external/file/local_spec.rb | 30 +- .../gitlab/ci/config/external/file/project_spec.rb | 71 +- .../gitlab/ci/config/external/file/remote_spec.rb | 41 +- .../ci/config/external/file/template_spec.rb | 35 +- .../gitlab/ci/config/external/interpolator_spec.rb | 319 +++++ .../gitlab/ci/config/external/mapper/base_spec.rb | 2 +- .../ci/config/external/mapper/filter_spec.rb | 2 +- .../external/mapper/location_expander_spec.rb | 2 +- .../ci/config/external/mapper/matcher_spec.rb | 68 +- .../ci/config/external/mapper/normalizer_spec.rb | 2 +- .../external/mapper/variables_expander_spec.rb | 2 +- .../ci/config/external/mapper/verifier_spec.rb | 275 +++- spec/lib/gitlab/ci/config/external/mapper_spec.rb | 13 +- .../gitlab/ci/config/external/processor_spec.rb | 4 +- spec/lib/gitlab/ci/config/external/rules_spec.rb | 2 +- spec/lib/gitlab/ci/config/header/input_spec.rb | 70 + spec/lib/gitlab/ci/config/header/root_spec.rb | 133 ++ spec/lib/gitlab/ci/config/header/spec_spec.rb | 56 + .../ci/config/normalizer/number_strategy_spec.rb | 22 + spec/lib/gitlab/ci/config/yaml/result_spec.rb | 54 + spec/lib/gitlab/ci/config/yaml_spec.rb | 159 ++- spec/lib/gitlab/ci/config_spec.rb | 2 +- spec/lib/gitlab/ci/input/arguments/base_spec.rb | 19 + spec/lib/gitlab/ci/input/arguments/default_spec.rb | 53 + spec/lib/gitlab/ci/input/arguments/options_spec.rb | 54 + .../lib/gitlab/ci/input/arguments/required_spec.rb | 45 + spec/lib/gitlab/ci/input/arguments/unknown_spec.rb | 18 + spec/lib/gitlab/ci/input/inputs_spec.rb | 126 ++ spec/lib/gitlab/ci/interpolation/access_spec.rb | 2 +- spec/lib/gitlab/ci/interpolation/block_spec.rb | 2 +- spec/lib/gitlab/ci/interpolation/config_spec.rb | 2 +- spec/lib/gitlab/ci/interpolation/context_spec.rb | 2 +- spec/lib/gitlab/ci/interpolation/template_spec.rb | 2 +- spec/lib/gitlab/ci/jwt_spec.rb | 17 +- spec/lib/gitlab/ci/jwt_v2_spec.rb | 78 +- spec/lib/gitlab/ci/lint_spec.rb | 6 +- spec/lib/gitlab/ci/parsers/security/common_spec.rb | 8 +- spec/lib/gitlab/ci/parsers/security/sast_spec.rb | 4 +- .../ci/parsers/security/secret_detection_spec.rb | 2 +- .../security/validators/schema_validator_spec.rb | 190 +-- .../ci/pipeline/chain/config/content_spec.rb | 11 +- spec/lib/gitlab/ci/pipeline/duration_spec.rb | 156 ++- .../gitlab/ci/pipeline/seed/build/cache_spec.rb | 48 +- spec/lib/gitlab/ci/pipeline/seed/build_spec.rb | 128 +- spec/lib/gitlab/ci/pipeline/seed/stage_spec.rb | 2 +- .../gitlab/ci/project_config/repository_spec.rb | 8 +- spec/lib/gitlab/ci/project_config/source_spec.rb | 8 +- .../gitlab/ci/reports/codequality_mr_diff_spec.rb | 2 +- .../lib/gitlab/ci/reports/security/scanner_spec.rb | 2 +- .../vulnerability_reports_comparer_spec.rb | 163 --- spec/lib/gitlab/ci/runner_releases_spec.rb | 32 + spec/lib/gitlab/ci/secure_files/cer_spec.rb | 4 +- .../ci/secure_files/mobile_provision_spec.rb | 2 +- spec/lib/gitlab/ci/secure_files/p12_spec.rb | 2 +- spec/lib/gitlab/ci/status/composite_spec.rb | 18 +- .../processable/waiting_for_resource_spec.rb | 21 +- .../ci/templates/Jobs/build_gitlab_ci_yaml_spec.rb | 2 +- .../Jobs/sast_iac_latest_gitlab_ci_yaml_spec.rb | 34 +- spec/lib/gitlab/ci/trace/chunked_io_spec.rb | 10 - .../gitlab/ci/variables/builder/pipeline_spec.rb | 91 +- spec/lib/gitlab/ci/variables/builder_spec.rb | 165 ++- spec/lib/gitlab/ci/variables/collection_spec.rb | 2 +- spec/lib/gitlab/ci/yaml_processor/result_spec.rb | 4 +- spec/lib/gitlab/ci/yaml_processor_spec.rb | 244 +++- spec/lib/gitlab/color_schemes_spec.rb | 8 +- spec/lib/gitlab/color_spec.rb | 10 +- spec/lib/gitlab/config/entry/validators_spec.rb | 2 +- .../gitlab/config/loader/multi_doc_yaml_spec.rb | 220 +++- spec/lib/gitlab/config/loader/yaml_spec.rb | 28 +- .../external_database_checker_spec.rb | 6 +- spec/lib/gitlab/console_spec.rb | 4 +- spec/lib/gitlab/consul/internal_spec.rb | 8 +- .../content_security_policy/config_loader_spec.rb | 6 +- spec/lib/gitlab/data_builder/deployment_spec.rb | 3 +- .../async_constraints/migration_helpers_spec.rb | 288 +++++ .../postgres_async_constraint_validation_spec.rb | 109 ++ .../validators/check_constraint_spec.rb | 20 + .../validators/foreign_key_spec.rb | 35 + .../database/async_constraints/validators_spec.rb | 21 + spec/lib/gitlab/database/async_constraints_spec.rb | 29 + .../foreign_key_validator_spec.rb | 152 --- .../async_foreign_keys/migration_helpers_spec.rb | 167 --- .../postgres_async_foreign_key_validation_spec.rb | 52 - .../lib/gitlab/database/async_foreign_keys_spec.rb | 23 - .../async_indexes/migration_helpers_spec.rb | 86 ++ .../background_migration/batch_optimizer_spec.rb | 9 + .../background_migration/batched_job_spec.rb | 151 +++ .../background_migration/batched_migration_spec.rb | 13 +- .../batched_migration_wrapper_spec.rb | 15 +- .../health_status/indicators/patroni_apdex_spec.rb | 148 +++ .../background_migration/health_status_spec.rb | 26 +- .../database/background_migration_job_spec.rb | 20 - .../gitlab/database/consistency_checker_spec.rb | 2 +- .../gitlab/database/dynamic_model_helpers_spec.rb | 44 + spec/lib/gitlab/database/gitlab_schema_spec.rb | 80 +- .../load_balancing/action_cable_callbacks_spec.rb | 11 +- .../gitlab/database/load_balancing/logger_spec.rb | 13 + .../load_balancing/service_discovery_spec.rb | 17 +- .../sidekiq_client_middleware_spec.rb | 78 +- .../sidekiq_server_middleware_spec.rb | 65 +- spec/lib/gitlab/database/load_balancing_spec.rb | 7 +- .../gitlab/database/lock_writes_manager_spec.rb | 24 +- .../lib/gitlab/database/loose_foreign_keys_spec.rb | 49 +- .../automatic_lock_writes_on_tables_spec.rb | 25 +- .../migration_helpers/convert_to_bigint_spec.rb | 35 + .../loose_foreign_key_helpers_spec.rb | 16 +- .../restrict_gitlab_schema_spec.rb | 4 +- .../gitlab/database/migration_helpers/v2_spec.rb | 79 ++ .../wraparound_vacuum_helpers_spec.rb | 97 ++ spec/lib/gitlab/database/migration_helpers_spec.rb | 365 +++--- .../batched_background_migration_helpers_spec.rb | 44 +- .../migrations/constraints_helpers_spec.rb | 35 +- .../database/migrations/instrumentation_spec.rb | 19 +- .../database/migrations/pg_backend_pid_spec.rb | 52 + .../runner_backoff/active_record_mixin_spec.rb | 106 ++ .../migrations/runner_backoff/communicator_spec.rb | 84 ++ .../runner_backoff/migration_helpers_spec.rb | 41 + spec/lib/gitlab/database/migrations/runner_spec.rb | 2 +- .../database/migrations/sidekiq_helpers_spec.rb | 264 ++-- .../test_batched_background_runner_spec.rb | 21 +- .../database/no_cross_db_foreign_keys_spec.rb | 2 +- .../database/obsolete_ignored_columns_spec.rb | 7 +- .../partitioning/ci_sliding_list_strategy_spec.rb | 178 +++ .../convert_table_to_first_list_partition_spec.rb | 273 ---- .../detached_partition_dropper_spec.rb | 48 +- .../partitioning/list/convert_table_spec.rb | 365 ++++++ .../list/locking_configuration_spec.rb | 46 + .../partitioning/partition_manager_spec.rb | 35 +- .../backfill_partitioned_table_spec.rb | 7 +- .../foreign_key_helpers_spec.rb | 122 +- .../table_management_helpers_spec.rb | 225 +--- spec/lib/gitlab/database/partitioning_spec.rb | 80 +- spec/lib/gitlab/database/pg_depend_spec.rb | 21 + .../gitlab/database/postgres_foreign_key_spec.rb | 58 +- .../lib/gitlab/database/postgres_partition_spec.rb | 14 +- .../query_analyzers/gitlab_schemas_metrics_spec.rb | 16 +- .../gitlab_schemas_validate_connection_spec.rb | 17 +- .../prevent_cross_database_modification_spec.rb | 29 +- spec/lib/gitlab/database/reflection_spec.rb | 8 +- spec/lib/gitlab/database/reindexing_spec.rb | 4 +- .../adapters/column_database_adapter_spec.rb | 72 ++ .../adapters/column_structure_sql_adapter_spec.rb | 78 ++ .../database/schema_validation/database_spec.rb | 96 +- .../schema_validation/inconsistency_spec.rb | 96 ++ .../database/schema_validation/index_spec.rb | 22 - .../database/schema_validation/indexes_spec.rb | 56 - .../database/schema_validation/runner_spec.rb | 50 + .../schema_validation/schema_inconsistency_spec.rb | 17 + .../schema_objects/column_spec.rb | 25 + .../schema_validation/schema_objects/index_spec.rb | 11 + .../schema_validation/schema_objects/table_spec.rb | 45 + .../schema_objects/trigger_spec.rb | 11 + .../schema_validation/structure_sql_spec.rb | 66 + .../schema_validation/track_inconsistency_spec.rb | 82 ++ .../validators/base_validator_spec.rb | 36 + .../different_definition_indexes_spec.rb | 8 + .../validators/different_definition_tables_spec.rb | 7 + .../different_definition_triggers_spec.rb | 8 + .../validators/extra_indexes_spec.rb | 7 + .../validators/extra_table_columns_spec.rb | 7 + .../validators/extra_tables_spec.rb | 7 + .../validators/extra_triggers_spec.rb | 7 + .../validators/missing_indexes_spec.rb | 14 + .../validators/missing_table_columns_spec.rb | 7 + .../validators/missing_tables_spec.rb | 9 + .../validators/missing_triggers_spec.rb | 9 + spec/lib/gitlab/database/tables_locker_spec.rb | 237 ++-- spec/lib/gitlab/database/tables_truncate_spec.rb | 20 +- .../database/transaction_timeout_settings_spec.rb | 2 +- .../with_lock_retries_outside_transaction_spec.rb | 4 +- spec/lib/gitlab/database/with_lock_retries_spec.rb | 4 +- .../instance_administrators/create_group_spec.rb | 169 --- .../self_monitoring/project/create_service_spec.rb | 315 ----- .../self_monitoring/project/delete_service_spec.rb | 53 - spec/lib/gitlab/database_spec.rb | 44 +- .../gitlab/diff/formatters/image_formatter_spec.rb | 10 +- spec/lib/gitlab/diff/highlight_cache_spec.rb | 16 +- spec/lib/gitlab/diff/highlight_spec.rb | 15 +- .../discussions_diff/highlight_cache_spec.rb | 88 +- .../secret/pbkdf2_sha512_spec.rb | 11 - .../email/handler/create_issue_handler_spec.rb | 2 +- .../email/handler/create_note_handler_spec.rb | 22 + .../email/hook/silent_mode_interceptor_spec.rb | 74 ++ .../hook/validate_addresses_interceptor_spec.rb | 52 - .../gitlab/email/html_to_markdown_parser_spec.rb | 12 +- spec/lib/gitlab/email/incoming_email_spec.rb | 34 + .../email/message/build_ios_app_guide_spec.rb | 6 +- .../message/in_product_marketing/helper_spec.rb | 6 +- .../gitlab/email/message/repository_push_spec.rb | 2 +- spec/lib/gitlab/email/receiver_spec.rb | 13 +- spec/lib/gitlab/email/reply_parser_spec.rb | 77 +- spec/lib/gitlab/email/service_desk_email_spec.rb | 53 + spec/lib/gitlab/emoji_spec.rb | 17 - spec/lib/gitlab/endpoint_attributes_spec.rb | 7 +- spec/lib/gitlab/error_tracking_spec.rb | 43 +- spec/lib/gitlab/etag_caching/middleware_spec.rb | 7 +- spec/lib/gitlab/exception_log_formatter_spec.rb | 6 + .../gitlab/external_authorization/config_spec.rb | 2 +- spec/lib/gitlab/favicon_spec.rb | 12 +- spec/lib/gitlab/file_finder_spec.rb | 126 +- .../gitlab/fogbugz_import/project_creator_spec.rb | 6 +- spec/lib/gitlab/git/blame_mode_spec.rb | 62 + spec/lib/gitlab/git/blame_pagination_spec.rb | 175 +++ spec/lib/gitlab/git/commit_spec.rb | 38 +- spec/lib/gitlab/git/diff_collection_spec.rb | 20 + spec/lib/gitlab/git/repository_spec.rb | 201 +-- spec/lib/gitlab/git/wraps_gitaly_errors_spec.rb | 81 +- spec/lib/gitlab/git_access_spec.rb | 30 +- spec/lib/gitlab/git_ref_validator_spec.rb | 5 + .../gitlab/gitaly_client/commit_service_spec.rb | 52 +- spec/lib/gitlab/gitaly_client/ref_service_spec.rb | 20 +- .../gitaly_client/repository_service_spec.rb | 41 +- .../gitaly_client/with_feature_flag_actors_spec.rb | 16 +- .../gitlab/github_import/bulk_importing_spec.rb | 232 ++-- spec/lib/gitlab/github_import/client_spec.rb | 78 +- .../lib/gitlab/github_import/clients/proxy_spec.rb | 123 +- .../importer/attachments/issues_importer_spec.rb | 2 + .../attachments/merge_requests_importer_spec.rb | 2 + .../importer/attachments/releases_importer_spec.rb | 2 + .../importer/collaborator_importer_spec.rb | 86 ++ .../importer/collaborators_importer_spec.rb | 156 +++ .../importer/label_links_importer_spec.rb | 18 + .../github_import/importer/labels_importer_spec.rb | 4 +- .../importer/milestones_importer_spec.rb | 6 +- .../importer/note_attachments_importer_spec.rb | 45 +- .../pull_request_merged_by_importer_spec.rb | 84 -- .../importer/pull_request_review_importer_spec.rb | 314 ----- .../pull_requests/all_merged_by_importer_spec.rb | 65 + .../pull_requests/merged_by_importer_spec.rb | 88 ++ .../importer/pull_requests/review_importer_spec.rb | 314 +++++ .../pull_requests/review_requests_importer_spec.rb | 2 + .../pull_requests/reviews_importer_spec.rb | 95 ++ .../pull_requests_merged_by_importer_spec.rb | 61 - .../pull_requests_reviews_importer_spec.rb | 86 -- .../importer/releases_importer_spec.rb | 6 +- spec/lib/gitlab/github_import/logger_spec.rb | 34 +- .../github_import/markdown/attachment_spec.rb | 58 +- .../github_import/parallel_scheduling_spec.rb | 89 +- .../github_import/project_relation_type_spec.rb | 49 + .../representation/collaborator_spec.rb | 50 + .../github_import/representation/diff_note_spec.rb | 2 +- .../representation/issue_event_spec.rb | 6 +- .../github_import/representation/issue_spec.rb | 3 +- .../representation/lfs_object_spec.rb | 3 +- .../github_import/representation/note_spec.rb | 24 +- .../github_import/representation/note_text_spec.rb | 110 +- .../representation/pull_request_review_spec.rb | 2 +- .../representation/pull_request_spec.rb | 3 +- .../pull_requests/review_requests_spec.rb | 23 + spec/lib/gitlab/github_import/settings_spec.rb | 15 +- spec/lib/gitlab/github_import/user_finder_spec.rb | 35 + spec/lib/gitlab/gitlab_import/client_spec.rb | 111 -- spec/lib/gitlab/gitlab_import/importer_spec.rb | 57 - .../gitlab/gitlab_import/project_creator_spec.rb | 37 - spec/lib/gitlab/gl_repository/identifier_spec.rb | 6 +- spec/lib/gitlab/gl_repository/repo_type_spec.rb | 23 +- spec/lib/gitlab/gl_repository_spec.rb | 9 +- .../grape_logging/loggers/response_logger_spec.rb | 6 + .../graphql/authorize/authorize_resource_spec.rb | 10 +- .../graphql/deprecations/deprecation_spec.rb | 2 +- spec/lib/gitlab/graphql/known_operations_spec.rb | 1 - .../loaders/lazy_relation_loader/registry_spec.rb | 24 + .../lazy_relation_loader/relation_proxy_spec.rb | 29 + .../graphql/loaders/lazy_relation_loader_spec.rb | 123 ++ .../action_cable_with_load_balancing_spec.rb | 138 ++ .../gitlab/graphql/tracers/metrics_tracer_spec.rb | 1 - .../gitlab/graphql/tracers/timer_tracer_spec.rb | 2 - spec/lib/gitlab/harbor/client_spec.rb | 12 +- spec/lib/gitlab/http_connection_adapter_spec.rb | 40 +- spec/lib/gitlab/i18n/pluralization_spec.rb | 53 + spec/lib/gitlab/i18n_spec.rb | 17 +- spec/lib/gitlab/import/errors_spec.rb | 48 + spec/lib/gitlab/import/logger_spec.rb | 32 +- spec/lib/gitlab/import/metrics_spec.rb | 130 +- spec/lib/gitlab/import_export/all_models.yml | 155 ++- .../import_export/attribute_configuration_spec.rb | 2 +- .../gitlab/import_export/attributes_finder_spec.rb | 18 +- .../import_export/attributes_permitter_spec.rb | 22 +- .../base/relation_object_saver_spec.rb | 30 +- .../gitlab/import_export/command_line_util_spec.rb | 61 +- spec/lib/gitlab/import_export/config_spec.rb | 10 +- .../import_export/fast_hash_serializer_spec.rb | 12 +- spec/lib/gitlab/import_export/fork_spec.rb | 59 - .../group/relation_tree_restorer_spec.rb | 92 +- .../import_export/group/tree_restorer_spec.rb | 4 +- .../import_export_equivalence_spec.rb | 67 - .../import_export/import_failure_service_spec.rb | 2 +- .../import_export/json/legacy_reader/file_spec.rb | 32 - .../import_export/json/legacy_reader/hash_spec.rb | 35 - .../json/legacy_reader/shared_example.rb | 102 -- .../import_export/json/legacy_writer_spec.rb | 101 -- .../import_export/json/ndjson_reader_spec.rb | 40 +- .../json/streaming_serializer_spec.rb | 2 +- .../import_export/model_configuration_spec.rb | 4 +- .../import_export/project/export_task_spec.rb | 8 +- .../project/exported_relations_merger_spec.rb | 4 +- .../import_export/project/import_task_spec.rb | 2 +- .../import_export/project/object_builder_spec.rb | 7 +- .../project/relation_tree_restorer_spec.rb | 52 +- .../import_export/project/tree_restorer_spec.rb | 213 ++-- .../import_export/project/tree_saver_spec.rb | 61 +- .../import_export/references_configuration_spec.rb | 2 +- .../gitlab/import_export/safe_model_attributes.yml | 135 +- spec/lib/gitlab/import_sources_spec.rb | 20 +- spec/lib/gitlab/incoming_email_spec.rb | 34 - spec/lib/gitlab/instrumentation/redis_base_spec.rb | 12 + .../instrumentation/redis_interceptor_spec.rb | 35 +- .../gitlab/internal_post_receive/response_spec.rb | 2 +- spec/lib/gitlab/issuable_sorter_spec.rb | 42 +- .../lib/gitlab/jira_import/issues_importer_spec.rb | 2 +- spec/lib/gitlab/json_logger_spec.rb | 29 +- spec/lib/gitlab/jwt_authenticatable_spec.rb | 8 +- spec/lib/gitlab/kas/client_spec.rb | 29 + spec/lib/gitlab/kas/user_access_spec.rb | 96 ++ spec/lib/gitlab/kroki_spec.rb | 2 +- spec/lib/gitlab/kubernetes/config_map_spec.rb | 16 +- spec/lib/gitlab/kubernetes/helm/api_spec.rb | 269 ---- spec/lib/gitlab/kubernetes/helm/pod_spec.rb | 89 -- .../gitlab/kubernetes/helm/v2/base_command_spec.rb | 50 - .../gitlab/kubernetes/helm/v2/certificate_spec.rb | 28 - .../kubernetes/helm/v2/delete_command_spec.rb | 38 - .../gitlab/kubernetes/helm/v2/init_command_spec.rb | 35 - .../kubernetes/helm/v2/install_command_spec.rb | 183 --- .../kubernetes/helm/v2/patch_command_spec.rb | 87 -- .../kubernetes/helm/v2/reset_command_spec.rb | 32 - .../gitlab/kubernetes/helm/v3/base_command_spec.rb | 44 - .../kubernetes/helm/v3/delete_command_spec.rb | 35 - .../kubernetes/helm/v3/install_command_spec.rb | 168 --- .../kubernetes/helm/v3/patch_command_spec.rb | 81 -- .../lib/gitlab/legacy_github_import/client_spec.rb | 4 +- .../gitlab/legacy_github_import/importer_spec.rb | 31 +- .../legacy_github_import/project_creator_spec.rb | 4 +- .../legacy_github_import/user_formatter_spec.rb | 23 +- spec/lib/gitlab/loggable_spec.rb | 68 + .../gitlab/manifest_import/project_creator_spec.rb | 4 +- .../watchdog/monitor/rss_memory_limit_spec.rb | 3 +- spec/lib/gitlab/metrics/boot_time_tracker_spec.rb | 4 +- spec/lib/gitlab/metrics/dashboard/finder_spec.rb | 37 - .../metrics/dashboard/service_selector_spec.rb | 6 - .../dashboard/stages/grafana_formatter_spec.rb | 4 +- spec/lib/gitlab/metrics/sidekiq_slis_spec.rb | 65 + .../metrics/subscribers/action_cable_spec.rb | 126 +- .../metrics/subscribers/active_record_spec.rb | 14 +- .../metrics/subscribers/external_http_spec.rb | 47 +- .../metrics/subscribers/load_balancing_spec.rb | 2 +- .../gitlab/metrics/subscribers/rack_attack_spec.rb | 27 - .../gitlab/metrics/subscribers/rails_cache_spec.rb | 35 +- spec/lib/gitlab/middleware/compressed_json_spec.rb | 66 +- spec/lib/gitlab/middleware/go_spec.rb | 2 +- spec/lib/gitlab/middleware/multipart_spec.rb | 4 +- spec/lib/gitlab/middleware/request_context_spec.rb | 8 +- spec/lib/gitlab/monitor/demo_projects_spec.rb | 6 +- spec/lib/gitlab/multi_collection_paginator_spec.rb | 7 + spec/lib/gitlab/nav/top_nav_menu_item_spec.rb | 3 +- spec/lib/gitlab/net_http_adapter_spec.rb | 3 +- spec/lib/gitlab/observability_spec.rb | 186 ++- spec/lib/gitlab/octokit/middleware_spec.rb | 31 +- spec/lib/gitlab/omniauth_initializer_spec.rb | 8 - spec/lib/gitlab/optimistic_locking_spec.rb | 13 + spec/lib/gitlab/other_markup_spec.rb | 4 +- spec/lib/gitlab/pages/random_domain_spec.rb | 44 + spec/lib/gitlab/pages/virtual_host_finder_spec.rb | 214 ++++ spec/lib/gitlab/patch/draw_route_spec.rb | 4 +- spec/lib/gitlab/patch/node_loader_spec.rb | 80 ++ spec/lib/gitlab/path_regex_spec.rb | 7 +- .../gitlab/phabricator_import/cache/map_spec.rb | 85 -- .../phabricator_import/conduit/client_spec.rb | 59 - .../phabricator_import/conduit/maniphest_spec.rb | 39 - .../phabricator_import/conduit/response_spec.rb | 79 -- .../conduit/tasks_response_spec.rb | 27 - .../gitlab/phabricator_import/conduit/user_spec.rb | 49 - .../conduit/users_response_spec.rb | 21 - .../lib/gitlab/phabricator_import/importer_spec.rb | 35 - .../phabricator_import/issues/importer_spec.rb | 61 - .../issues/task_importer_spec.rb | 83 -- .../phabricator_import/project_creator_spec.rb | 59 - .../phabricator_import/representation/task_spec.rb | 49 - .../phabricator_import/representation/user_spec.rb | 28 - .../gitlab/phabricator_import/user_finder_spec.rb | 93 -- .../gitlab/phabricator_import/worker_state_spec.rb | 49 - spec/lib/gitlab/project_authorizations_spec.rb | 567 +++++---- spec/lib/gitlab/prometheus/internal_spec.rb | 4 +- .../queries/knative_invocation_query_spec.rb | 31 - spec/lib/gitlab/quick_actions/extractor_spec.rb | 41 +- .../rack_attack/instrumented_cache_store_spec.rb | 89 -- spec/lib/gitlab/rack_attack/request_spec.rb | 2 +- spec/lib/gitlab/rack_attack/store_spec.rb | 113 ++ spec/lib/gitlab/reactive_cache_set_cache_spec.rb | 28 +- spec/lib/gitlab/redis/cache_spec.rb | 26 - .../lib/gitlab/redis/cluster_rate_limiting_spec.rb | 7 - spec/lib/gitlab/redis/db_load_balancing_spec.rb | 8 - spec/lib/gitlab/redis/feature_flag_spec.rb | 13 + spec/lib/gitlab/redis/multi_store_spec.rb | 251 +--- spec/lib/gitlab/redis/queues_spec.rb | 9 - spec/lib/gitlab/redis/rate_limiting_spec.rb | 15 +- spec/lib/gitlab/redis/repository_cache_spec.rb | 23 - spec/lib/gitlab/redis/shared_state_spec.rb | 9 - spec/lib/gitlab/redis/sidekiq_status_spec.rb | 9 - spec/lib/gitlab/reference_extractor_spec.rb | 6 +- spec/lib/gitlab/regex_spec.rb | 99 +- spec/lib/gitlab/repository_set_cache_spec.rb | 64 +- spec/lib/gitlab/request_context_spec.rb | 40 +- .../assignment_event_recorder_spec.rb | 91 ++ spec/lib/gitlab/runtime_spec.rb | 18 +- spec/lib/gitlab/safe_device_detector_spec.rb | 2 +- .../gitlab/sanitizers/exception_message_spec.rb | 3 +- .../seeders/ci/runner/runner_fleet_seeder_spec.rb | 24 + .../seeders/ci/variables_group_seeder_spec.rb | 92 ++ .../seeders/ci/variables_instance_seeder_spec.rb | 54 + .../seeders/ci/variables_project_seeder_spec.rb | 92 ++ .../seeders/project_environment_seeder_spec.rb | 52 + spec/lib/gitlab/serverless/service_spec.rb | 136 -- spec/lib/gitlab/service_desk_email_spec.rb | 53 - spec/lib/gitlab/service_desk_spec.rb | 8 +- .../gitlab/sidekiq_config/worker_router_spec.rb | 30 +- spec/lib/gitlab/sidekiq_config_spec.rb | 21 + .../gitlab/sidekiq_daemon/memory_killer_spec.rb | 562 -------- .../sidekiq_logging/structured_logger_spec.rb | 4 +- .../duplicate_jobs/duplicate_job_spec.rb | 7 +- .../duplicate_jobs/server_spec.rb | 8 +- .../sidekiq_middleware/server_metrics_spec.rb | 81 +- .../worker_context/client_spec.rb | 8 +- .../worker_context/server_spec.rb | 6 +- spec/lib/gitlab/sidekiq_migrate_jobs_spec.rb | 8 +- spec/lib/gitlab/sidekiq_queue_spec.rb | 10 +- .../slash_commands/global_slack_handler_spec.rb | 91 ++ spec/lib/gitlab/slug/environment_spec.rb | 59 +- spec/lib/gitlab/slug/path_spec.rb | 2 +- spec/lib/gitlab/source_spec.rb | 57 + spec/lib/gitlab/spamcheck/client_spec.rb | 75 +- spec/lib/gitlab/spamcheck/result_spec.rb | 43 + spec/lib/gitlab/subscription_portal_spec.rb | 85 -- .../finders/global_template_finder_spec.rb | 10 +- spec/lib/gitlab/timeless_spec.rb | 37 + .../destinations/database_events_snowplow_spec.rb | 136 ++ .../tracking/destinations/snowplow_micro_spec.rb | 2 +- spec/lib/gitlab/tracking/event_definition_spec.rb | 2 - spec/lib/gitlab/tracking/standard_context_spec.rb | 6 +- spec/lib/gitlab/tracking_spec.rb | 125 +- spec/lib/gitlab/untrusted_regexp_spec.rb | 59 +- spec/lib/gitlab/url_blocker_spec.rb | 235 +++- .../gitlab/url_blockers/ip_allowlist_entry_spec.rb | 24 +- spec/lib/gitlab/url_builder_spec.rb | 26 +- spec/lib/gitlab/usage/metric_definition_spec.rb | 2 - spec/lib/gitlab/usage/metric_spec.rb | 1 - .../count_bulk_imports_entities_metric_spec.rb | 119 +- .../count_ci_internal_pipelines_metric_spec.rb | 26 +- ...unt_ci_runners_group_type_active_metric_spec.rb | 17 + ...runners_group_type_active_online_metric_spec.rb | 18 + ..._ci_runners_instance_type_active_metric_spec.rb | 13 + ...ners_instance_type_active_online_metric_spec.rb | 13 + .../count_ci_runners_metric_spec.rb | 13 + ...t_ci_runners_project_type_active_metric_spec.rb | 17 + ...nners_project_type_active_online_metric_spec.rb | 18 + ...ues_created_manually_from_alerts_metric_spec.rb | 6 +- .../metrics/instrumentations/database_mode_spec.rb | 9 + .../instrumentations/edition_metric_spec.rb | 13 + .../gitlab_dedicated_metric_spec.rb | 9 + ..._email_encrypted_secrets_enabled_metric_spec.rb | 2 +- .../index_inconsistencies_metric_spec.rb | 30 + ...tion_creation_date_approximation_metric_spec.rb | 22 + .../installation_creation_date_metric_spec.rb | 20 + .../installation_type_metric_spec.rb | 21 + ..._email_encrypted_secrets_enabled_metric_spec.rb | 2 +- .../instrumentations/version_metric_spec.rb | 9 + .../metrics/names_suggestions/generator_spec.rb | 2 +- spec/lib/gitlab/usage/service_ping_report_spec.rb | 29 +- .../usage_data_counters/code_review_events_spec.rb | 16 +- .../container_registry_event_counter_spec.rb | 11 + .../editor_unique_counter_spec.rb | 26 +- .../gitlab_cli_activity_unique_counter_spec.rb | 13 +- .../usage_data_counters/hll_redis_counter_spec.rb | 204 ++- .../issue_activity_unique_counter_spec.rb | 79 +- .../merge_request_activity_unique_counter_spec.rb | 2 - .../track_unique_events_spec.rb | 72 -- spec/lib/gitlab/usage_data_metrics_spec.rb | 12 - spec/lib/gitlab/usage_data_spec.rb | 123 +- spec/lib/gitlab/user_access_spec.rb | 6 +- spec/lib/gitlab/utils/email_spec.rb | 32 +- spec/lib/gitlab/utils/error_message_spec.rb | 28 + spec/lib/gitlab/utils/measuring_spec.rb | 2 +- spec/lib/gitlab/utils/nokogiri_spec.rb | 4 +- spec/lib/gitlab/utils/strong_memoize_spec.rb | 69 +- spec/lib/gitlab/utils/uniquify_spec.rb | 44 + spec/lib/gitlab/utils/usage_data_spec.rb | 4 +- .../utils/username_and_email_generator_spec.rb | 24 + spec/lib/gitlab/workhorse_spec.rb | 32 +- spec/lib/gitlab_settings/options_spec.rb | 155 +++ spec/lib/gitlab_settings/settings_spec.rb | 67 + spec/lib/gitlab_spec.rb | 22 + spec/lib/json_web_token/hmac_token_spec.rb | 4 +- spec/lib/object_storage/config_spec.rb | 9 +- spec/lib/object_storage/direct_upload_spec.rb | 2 +- .../object_storage/pending_direct_upload_spec.rb | 70 + spec/lib/product_analytics/settings_spec.rb | 101 ++ spec/lib/product_analytics/tracker_spec.rb | 8 - spec/lib/security/weak_passwords_spec.rb | 2 +- spec/lib/service_ping/build_payload_spec.rb | 8 +- .../admin/menus/abuse_reports_menu_spec.rb | 42 + .../admin/menus/admin_overview_menu_spec.rb | 12 + .../admin/menus/admin_settings_menu_spec.rb | 13 + .../sidebars/admin/menus/analytics_menu_spec.rb | 12 + .../sidebars/admin/menus/applications_menu_spec.rb | 12 + spec/lib/sidebars/admin/menus/ci_cd_menu_spec.rb | 12 + .../sidebars/admin/menus/deploy_keys_menu_spec.rb | 12 + spec/lib/sidebars/admin/menus/labels_menu_spec.rb | 12 + .../lib/sidebars/admin/menus/messages_menu_spec.rb | 12 + .../sidebars/admin/menus/monitoring_menu_spec.rb | 12 + .../sidebars/admin/menus/system_hooks_menu_spec.rb | 12 + spec/lib/sidebars/admin/panel_spec.rb | 31 + .../sidebars/concerns/super_sidebar_panel_spec.rb | 141 +++ .../groups/menus/group_information_menu_spec.rb | 6 +- .../groups/menus/invite_team_members_menu_spec.rb | 55 - spec/lib/sidebars/groups/menus/issues_menu_spec.rb | 14 +- .../sidebars/groups/menus/kubernetes_menu_spec.rb | 11 +- .../groups/menus/merge_requests_menu_spec.rb | 13 +- .../groups/menus/observability_menu_spec.rb | 60 +- .../groups/menus/packages_registries_menu_spec.rb | 4 +- spec/lib/sidebars/groups/menus/scope_menu_spec.rb | 16 +- .../sidebars/groups/menus/settings_menu_spec.rb | 6 + .../super_sidebar_menus/analyze_menu_spec.rb | 28 + .../groups/super_sidebar_menus/build_menu_spec.rb | 21 + .../groups/super_sidebar_menus/manage_menu_spec.rb | 23 + .../super_sidebar_menus/monitor_menu_spec.rb | 22 + .../super_sidebar_menus/operations_menu_spec.rb | 24 + .../groups/super_sidebar_menus/plan_menu_spec.rb | 30 + .../groups/super_sidebar_menus/secure_menu_spec.rb | 25 + .../sidebars/groups/super_sidebar_panel_spec.rb | 55 + spec/lib/sidebars/menu_item_spec.rb | 10 + spec/lib/sidebars/menu_spec.rb | 132 +- spec/lib/sidebars/panel_spec.rb | 28 +- .../lib/sidebars/projects/menus/ci_cd_menu_spec.rb | 16 +- .../projects/menus/confluence_menu_spec.rb | 9 + .../projects/menus/deployments_menu_spec.rb | 8 +- .../projects/menus/infrastructure_menu_spec.rb | 84 +- .../menus/invite_team_members_menu_spec.rb | 52 - .../sidebars/projects/menus/issues_menu_spec.rb | 25 +- .../projects/menus/merge_requests_menu_spec.rb | 27 +- .../sidebars/projects/menus/monitor_menu_spec.rb | 4 + .../menus/packages_registries_menu_spec.rb | 29 +- .../menus/project_information_menu_spec.rb | 6 +- .../projects/menus/repository_menu_spec.rb | 47 +- .../lib/sidebars/projects/menus/scope_menu_spec.rb | 14 +- .../menus/security_compliance_menu_spec.rb | 4 +- .../sidebars/projects/menus/settings_menu_spec.rb | 6 + .../sidebars/projects/menus/snippets_menu_spec.rb | 12 +- spec/lib/sidebars/projects/menus/wiki_menu_spec.rb | 12 +- spec/lib/sidebars/projects/panel_spec.rb | 2 +- .../super_sidebar_menus/analyze_menu_spec.rb | 30 + .../super_sidebar_menus/build_menu_spec.rb | 29 + .../projects/super_sidebar_menus/code_menu_spec.rb | 29 + .../super_sidebar_menus/manage_menu_spec.rb | 23 + .../super_sidebar_menus/monitor_menu_spec.rb | 27 + .../super_sidebar_menus/operations_menu_spec.rb | 27 + .../projects/super_sidebar_menus/plan_menu_spec.rb | 26 + .../super_sidebar_menus/secure_menu_spec.rb | 29 + .../sidebars/projects/super_sidebar_panel_spec.rb | 66 + spec/lib/sidebars/search/panel_spec.rb | 31 + spec/lib/sidebars/static_menu_spec.rb | 44 + spec/lib/sidebars/uncategorized_menu_spec.rb | 12 + .../user_profile/menus/activity_menu_spec.rb | 12 + .../menus/contributed_projects_menu_spec.rb | 12 + .../user_profile/menus/followers_menu_spec.rb | 14 + .../user_profile/menus/following_menu_spec.rb | 14 + .../user_profile/menus/groups_menu_spec.rb | 12 + .../user_profile/menus/overview_menu_spec.rb | 12 + .../menus/personal_projects_menu_spec.rb | 12 + .../user_profile/menus/snippets_menu_spec.rb | 12 + .../menus/starred_projects_menu_spec.rb | 12 + spec/lib/sidebars/user_profile/panel_spec.rb | 26 + .../user_settings/menus/access_tokens_menu_spec.rb | 65 + .../user_settings/menus/account_menu_spec.rb | 13 + .../menus/active_sessions_menu_spec.rb | 13 + .../user_settings/menus/applications_menu_spec.rb | 13 + .../menus/authentication_log_menu_spec.rb | 13 + .../sidebars/user_settings/menus/chat_menu_spec.rb | 13 + .../menus/comment_templates_menu_spec.rb | 65 + .../user_settings/menus/emails_menu_spec.rb | 13 + .../user_settings/menus/gpg_keys_menu_spec.rb | 13 + .../user_settings/menus/notifications_menu_spec.rb | 13 + .../user_settings/menus/password_menu_spec.rb | 38 + .../user_settings/menus/preferences_menu_spec.rb | 13 + .../user_settings/menus/profile_menu_spec.rb | 13 + .../user_settings/menus/ssh_keys_menu_spec.rb | 13 + spec/lib/sidebars/user_settings/panel_spec.rb | 17 + spec/lib/sidebars/your_work/panel_spec.rb | 17 + spec/lib/slack/api_spec.rb | 41 + spec/lib/slack/block_kit/app_home_opened_spec.rb | 62 + .../incident_modal_opened_spec.rb | 41 + spec/lib/unnested_in_filters/rewriter_spec.rb | 26 +- spec/lib/uploaded_file_spec.rb | 42 +- spec/mailers/emails/in_product_marketing_spec.rb | 6 +- spec/mailers/emails/issues_spec.rb | 36 +- spec/mailers/emails/merge_requests_spec.rb | 15 +- spec/mailers/emails/pages_domains_spec.rb | 10 +- spec/mailers/emails/pipelines_spec.rb | 18 +- spec/mailers/emails/profile_spec.rb | 38 +- spec/mailers/emails/service_desk_spec.rb | 347 +++-- spec/mailers/emails/work_items_spec.rb | 17 + spec/mailers/notify_spec.rb | 217 +++- spec/metrics_server/metrics_server_spec.rb | 4 +- ...10831203408_upsert_base_work_item_types_spec.rb | 69 - ...columns_and_triggers_for_ci_build_needs_spec.rb | 21 - ..._and_triggers_for_ci_build_trace_chunks_spec.rb | 21 - ...orary_columns_and_triggers_for_taggings_spec.rb | 23 - ...igint_conversion_for_ci_builds_metadata_spec.rb | 23 - ...57_finalize_ci_builds_bigint_conversion_spec.rb | 18 - ...ype_for_existing_approval_project_rules_spec.rb | 48 - ...10_cleanup_orphan_project_access_tokens_spec.rb | 47 - ...cleanup_bigint_conversion_for_ci_builds_spec.rb | 23 - ...culate_vulnerabilities_occurrences_uuid_spec.rb | 47 - ..._drop_int4_columns_for_ci_job_artifacts_spec.rb | 23 - ...op_int4_column_for_ci_sources_pipelines_spec.rb | 21 - ...10922082019_drop_int4_column_for_events_spec.rb | 21 - ...rop_int4_column_for_push_event_payloads_spec.rb | 21 - ...ulate_topics_total_projects_count_cache_spec.rb | 29 - ...migrate_merge_request_diff_commit_users_spec.rb | 48 - ...ove_duplicate_vulnerabilities_findings3_spec.rb | 166 --- ...rge_request_diff_commit_users_migration_spec.rb | 63 - ...4_consume_remaining_user_namespace_jobs_spec.rb | 21 - ...ll_constraint_to_security_findings_uuid_spec.rb | 23 - ...schedule_drop_invalid_security_findings_spec.rb | 72 -- ...1_change_namespace_type_default_to_user_spec.rb | 5 - ..._and_duplicate_vulnerabilities_findings_spec.rb | 190 --- ...814_migrate_remaining_u2f_registrations_spec.rb | 43 - ...tic_objects_external_storage_auth_token_spec.rb | 78 -- ...11126204445_add_task_to_work_item_types_spec.rb | 54 - ...kfill_sequence_column_for_sprints_table_spec.rb | 42 - ...culate_vulnerabilities_occurrences_uuid_spec.rb | 2 +- .../20220124130028_dedup_runner_projects_spec.rb | 2 +- ...28155251_remove_dangling_running_builds_spec.rb | 2 +- ...0_remove_duplicate_project_tag_releases_spec.rb | 4 +- ...eftover_external_pull_request_deletions_spec.rb | 2 +- ...e_dependency_list_usage_data_from_redis_spec.rb | 2 +- ...grate_shimo_confluence_service_category_spec.rb | 5 +- ...move_leftover_ci_job_artifact_deletions_spec.rb | 2 +- ...utomatic_iterations_cadences_start_date_spec.rb | 12 +- ...3043344_reschedule_expire_o_auth_tokens_spec.rb | 2 +- ..._success_index_to_authentication_events_spec.rb | 2 +- ...misassociated_vulnerability_occurrences_spec.rb | 2 +- ...misassociated_vulnerability_occurrences_spec.rb | 2 +- ...2902_finalise_project_namespace_members_spec.rb | 8 +- ...urce_licence_for_recent_public_projects_spec.rb | 4 +- ...ove_deactivated_user_highest_role_stats_spec.rb | 2 +- ...date_start_date_for_iterations_cadences_spec.rb | 30 +- ...y_to_sbom_vulnerable_component_versions_spec.rb | 2 +- ...y_to_sbom_vulnerable_component_versions_spec.rb | 2 +- ...1144258_remove_orphan_group_token_users_spec.rb | 16 +- ...ate_ci_pipeline_artifacts_locked_status_spec.rb | 4 +- ...ize_group_member_namespace_id_migration_spec.rb | 8 +- ...ective_and_keyresult_to_work_item_types_spec.rb | 35 +- ..._renaming_background_migration_finished_spec.rb | 6 +- ...0_finalize_backfill_user_details_fields_spec.rb | 4 + ...stics_storage_size_without_uploads_size_spec.rb | 2 +- ...k_item_type_backfill_migration_finished_spec.rb | 4 + ...auth_access_tokens_with_null_expires_in_spec.rb | 2 +- ...22_schedule_backfill_releases_author_id_spec.rb | 30 +- ...roject_statistics_upload_size_migration_spec.rb | 2 +- ...ed_on_ci_namespace_monthly_usages_table_spec.rb | 2 +- ...4623_schedule_migration_for_remediation_spec.rb | 25 + ...03_queue_backfill_compliance_violations_spec.rb | 32 + ...le_create_vulnerability_links_migration_spec.rb | 30 + ...ize_backfill_environment_tier_migration_spec.rb | 6 +- ...20230202131928_encrypt_ci_trigger_token_spec.rb | 27 - .../20230202211434_migrate_redis_slot_keys_spec.rb | 54 + ...0208125736_schedule_migration_for_links_spec.rb | 25 + ..._project_group_link_with_missing_groups_spec.rb | 32 + ...alize_ci_build_needs_big_int_conversion_spec.rb | 43 + ...lumns_ci_build_needs_big_int_conversion_spec.rb | 60 + ...ial_index_on_vulnerability_report_types_spec.rb | 22 + ...ded_namespaces_from_onboarding_progress_spec.rb | 59 + ...nullify_creator_id_of_orphaned_projects_spec.rb | 97 ++ ...4085743_update_issues_internal_id_scope_spec.rb | 28 + ...233_migrate_evidences_from_raw_metadata_spec.rb | 25 + ...2350_add_notifications_work_item_widget_spec.rb | 8 + ...ueue_fix_vulnerability_reads_has_issues_spec.rb | 27 + ...230302811133_re_migrate_redis_slot_keys_spec.rb | 77 ++ ...e_delete_orphaned_packages_dependencies_spec.rb | 26 + ...071242_delete_security_policy_bot_users_spec.rb | 24 + ...42631_backfill_ml_candidates_package_id_spec.rb | 61 + ...31_reschedule_migration_for_remediation_spec.rb | 31 + ...14144640_reschedule_migration_for_links_spec.rb | 25 + ..._redis_hll_events_to_weekly_aggregation_spec.rb | 124 ++ ...add_current_user_todos_work_item_widget_spec.rb | 8 + ..._created_at_desc_index_to_package_files_spec.rb | 20 + ...63947_backfill_ml_candidates_project_id_spec.rb | 50 + ...0823_backfill_ml_candidates_internal_id_spec.rb | 64 + ..._namespace_records_from_vsa_aggregation_spec.rb | 41 + ...ign_key_to_packages_npm_metadata_caches_spec.rb | 24 + ...101138_add_award_emoji_work_item_widget_spec.rb | 8 + ...327103401_queue_migrate_human_user_type_spec.rb | 26 + ...l_product_analytics_data_collector_host_spec.rb | 47 + ...030101_add_secureflag_training_provider_spec.rb | 25 + ...28100534_truncate_error_tracking_tables_spec.rb | 56 + ...00222_drop_software_licenses_temp_index_spec.rb | 20 + ...0330103104_reschedule_migrate_evidences_spec.rb | 25 + ...al_index_on_vulnerability_report_types2_spec.rb | 49 + ...ueue_backfill_project_wiki_repositories_spec.rb | 26 + ...backfill_design_management_repositories_spec.rb | 26 + ...igint_conversion_for_sent_notifications_spec.rb | 21 + ...1_reschedule_links_avoiding_duplication_spec.rb | 31 + ...populate_vulnerability_dismissal_fields_spec.rb | 37 + ...14119_finalize_encrypt_ci_trigger_token_spec.rb | 96 ++ ...215853_add_assignee_widget_to_incidents_spec.rb | 47 + ...e_phabricator_from_application_settings_spec.rb | 22 + ...tion_settings_after_phabricator_removal_spec.rb | 34 + ...remove_shimo_zentao_integration_records_spec.rb | 46 + ...ers_on_source_and_type_and_access_level_spec.rb | 22 + ...orizations_on_project_user_access_level_spec.rb | 22 + ...30504084524_remove_gitlab_import_source_spec.rb | 22 + ...9_reschedule_evidences_handling_unicode_spec.rb | 31 + ...fill_corrected_secure_files_expirations_spec.rb | 24 + ...20230509131736_add_default_organization_spec.rb | 20 + ...sonal_access_tokens_with_nil_expires_at_spec.rb | 26 + spec/migrations/add_open_source_plan_spec.rb | 86 -- ...alue_with_progress_work_item_progresses_spec.rb | 48 + ...ll_integrations_enable_ssl_verification_spec.rb | 2 +- spec/migrations/backfill_user_namespace_spec.rb | 29 - .../bulk_insert_cluster_enabled_grants_spec.rb | 2 +- ...ll_integrations_enable_ssl_verification_spec.rb | 2 +- ...ansitions_with_same_from_state_to_state_spec.rb | 2 +- ...e_migrate_shared_vulnerability_scanners_spec.rb | 58 +- .../disable_job_token_scope_when_unused_spec.rb | 10 - spec/migrations/drop_packages_events_table_spec.rb | 24 + ...backfill_is_finished_for_gitlab_dot_com_spec.rb | 35 + ...backfill_is_finished_for_gitlab_dot_com_spec.rb | 35 + ...backfill_is_finished_for_gitlab_dot_com_spec.rb | 35 + ...backfill_is_finished_for_gitlab_dot_com_spec.rb | 35 + ...backfill_is_finished_for_gitlab_dot_com_spec.rb | 35 + ...backfill_is_finished_for_gitlab_dot_com_spec.rb | 37 + ...int_backfill_is_finished_for_self_hosts_spec.rb | 25 + ...backfill_is_finished_for_gitlab_dot_com_spec.rb | 35 + ...backfill_is_finished_for_gitlab_dot_com_spec.rb | 35 + ...backfill_is_finished_for_gitlab_dot_com_spec.rb | 35 + ...backfill_is_finished_for_gitlab_dot_com_spec.rb | 35 + ...backfill_is_finished_for_gitlab_dot_com_spec.rb | 35 + ...backfill_is_finished_for_gitlab_dot_com_spec.rb | 35 + ...backfill_is_finished_for_gitlab_dot_com_spec.rb | 35 + ...backfill_is_finished_for_gitlab_dot_com_spec.rb | 35 + .../ensure_unique_debian_packages_spec.rb | 56 + ...int_backfill_is_finished_for_gl_dot_com_spec.rb | 35 + .../finalize_invalid_member_cleanup_spec.rb | 4 + ...inalize_issues_iid_scoping_to_namespace_spec.rb | 72 ++ ...inalize_issues_namespace_id_backfilling_spec.rb | 8 +- .../finalize_orphaned_routes_cleanup_spec.rb | 8 +- .../finalize_project_namespaces_backfill_spec.rb | 8 +- ...inalize_routes_backfilling_for_projects_spec.rb | 8 +- ...ize_traversal_ids_background_migrations_spec.rb | 60 - .../insert_daily_invites_trial_plan_limits_spec.rb | 51 + ...n_mode_scope_for_personal_access_tokens_spec.rb | 18 - .../queue_backfill_prepared_at_data_spec.rb | 24 + ...i_builds_on_name_and_id_parser_features_spec.rb | 28 - .../remove_invalid_deploy_access_level_spec.rb | 48 - .../remove_packages_events_package_id_fk_spec.rb | 23 + ..._provider_and_identities_non_root_group_spec.rb | 53 + ...d_status_from_pending_alert_escalations_spec.rb | 37 - ..._token_and_scim_identity_non_root_group_spec.rb | 58 + ...n_mode_scope_for_personal_access_tokens_spec.rb | 19 + ...erun_remove_invalid_deploy_access_level_spec.rb | 86 ++ ...ule_incident_work_item_type_id_backfill_spec.rb | 70 + ...tatus_on_merge_requests_corrected_regex_spec.rb | 2 +- .../schedule_fixing_security_scan_statuses_spec.rb | 4 +- ...igrate_shared_vulnerability_identifiers_spec.rb | 32 + .../schedule_purging_stale_security_scans_spec.rb | 2 +- ...ability_finding_signatures_for_findings_spec.rb | 90 -- ...ing_send_user_confirmation_email_column_spec.rb | 2 +- ...setting_from_soft_email_confirmation_ff_spec.rb | 62 + ...ce_merge_request_diff_commit_migrations_spec.rb | 70 - .../start_backfill_ci_queuing_tables_spec.rb | 2 +- ...ji_note_id_to_bigint_for_gitlab_dot_com_spec.rb | 67 + ...ns_note_id_to_bigint_for_gitlab_dot_com_spec.rb | 66 + ...ns_note_id_to_bigint_for_gitlab_dot_com_spec.rb | 66 + ...ns_note_id_to_bigint_for_gitlab_dot_com_spec.rb | 66 + ..._note_id_to_bigint_for_gitlab_dot_com_2_spec.rb | 84 ++ ...metrics_id_to_bigint_for_gitlab_dot_com_spec.rb | 76 ++ ...est_metrics_id_to_bigint_for_self_hosts_spec.rb | 155 +++ ...request_user_mentions_note_id_to_bigint_spec.rb | 66 + ...es_note_id_to_bigint_for_gitlab_dot_com_spec.rb | 66 + .../swap_sent_notifications_id_columns_spec.rb | 71 ++ ...ns_note_id_to_bigint_for_gitlab_dot_com_spec.rb | 66 + ...ns_note_id_to_bigint_for_gitlab_dot_com_spec.rb | 66 + ...ta_note_id_to_bigint_for_gitlab_dot_com_spec.rb | 66 + ...gs_note_id_to_bigint_for_gitlab_dot_com_spec.rb | 66 + ...os_note_id_to_bigint_for_gitlab_dot_com_spec.rb | 66 + ...ns_note_id_to_bigint_for_gitlab_dot_com_spec.rb | 66 + ...nt_used_for_ci_namespace_monthly_usages_spec.rb | 2 +- ...ount_used_for_ci_project_monthly_usages_spec.rb | 2 +- ...egistry_exp_pol_worker_capacity_default_spec.rb | 2 +- ...te_application_settings_protected_paths_spec.rb | 2 +- ...efault_scan_method_of_dast_site_profile_spec.rb | 22 +- spec/models/abuse/trust_score_spec.rb | 57 + spec/models/abuse_report_spec.rb | 212 ++++ spec/models/achievements/user_achievement_spec.rb | 29 +- spec/models/active_session_spec.rb | 46 +- spec/models/airflow/dags_spec.rb | 17 - .../models/alert_management/alert_assignee_spec.rb | 6 +- spec/models/alert_management/alert_spec.rb | 10 +- .../alert_management/alert_user_mention_spec.rb | 6 +- .../models/analytics/cycle_analytics/stage_spec.rb | 74 +- spec/models/application_record_spec.rb | 10 +- spec/models/application_setting_spec.rb | 104 +- spec/models/audit_event_spec.rb | 4 + spec/models/authentication_event_spec.rb | 15 + spec/models/award_emoji_spec.rb | 35 +- spec/models/awareness_session_spec.rb | 163 --- .../blob_viewer/metrics_dashboard_yml_spec.rb | 16 +- spec/models/blob_viewer/package_json_spec.rb | 13 +- spec/models/board_spec.rb | 8 +- spec/models/broadcast_message_spec.rb | 52 +- spec/models/bulk_import_spec.rb | 29 +- spec/models/bulk_imports/batch_tracker_spec.rb | 16 + spec/models/bulk_imports/entity_spec.rb | 95 +- spec/models/bulk_imports/export_batch_spec.rb | 17 + spec/models/bulk_imports/export_spec.rb | 3 +- .../file_transfer/group_config_spec.rb | 49 +- .../file_transfer/project_config_spec.rb | 41 +- spec/models/bulk_imports/tracker_spec.rb | 5 +- spec/models/chat_name_spec.rb | 7 - spec/models/ci/bridge_spec.rb | 32 +- spec/models/ci/build_dependencies_spec.rb | 11 +- spec/models/ci/build_metadata_spec.rb | 12 +- spec/models/ci/build_need_spec.rb | 2 +- spec/models/ci/build_pending_state_spec.rb | 7 +- spec/models/ci/build_report_result_spec.rb | 13 + spec/models/ci/build_runner_session_spec.rb | 2 +- spec/models/ci/build_spec.rb | 671 +++++++--- spec/models/ci/build_trace_chunk_spec.rb | 9 +- spec/models/ci/build_trace_metadata_spec.rb | 2 +- spec/models/ci/build_trace_spec.rb | 6 +- spec/models/ci/catalog/listing_spec.rb | 66 + spec/models/ci/catalog/resource_spec.rb | 42 + spec/models/ci/commit_with_pipeline_spec.rb | 45 +- .../ci/daily_build_group_report_result_spec.rb | 6 +- spec/models/ci/group_spec.rb | 12 +- spec/models/ci/group_variable_spec.rb | 14 +- spec/models/ci/job_artifact_spec.rb | 31 +- spec/models/ci/job_token/allowlist_spec.rb | 24 +- spec/models/ci/job_token/scope_spec.rb | 18 +- spec/models/ci/job_variable_spec.rb | 2 +- spec/models/ci/pipeline_schedule_spec.rb | 17 +- spec/models/ci/pipeline_spec.rb | 479 +++++-- spec/models/ci/processable_spec.rb | 20 +- spec/models/ci/ref_spec.rb | 7 +- spec/models/ci/resource_group_spec.rb | 21 +- spec/models/ci/runner_machine_spec.rb | 197 --- spec/models/ci/runner_manager_build_spec.rb | 100 ++ spec/models/ci/runner_manager_spec.rb | 291 +++++ spec/models/ci/runner_spec.rb | 302 +++-- spec/models/ci/runner_version_spec.rb | 13 +- spec/models/ci/secure_file_spec.rb | 29 +- spec/models/ci/sources/pipeline_spec.rb | 7 +- spec/models/ci/stage_spec.rb | 24 +- spec/models/ci/variable_spec.rb | 2 +- spec/models/clusters/agent_spec.rb | 195 ++- spec/models/clusters/agent_token_spec.rb | 22 +- .../ci_access/group_authorization_spec.rb | 16 + .../ci_access/implicit_authorization_spec.rb | 14 + .../ci_access/project_authorization_spec.rb | 16 + .../user_access/group_authorization_spec.rb | 71 ++ .../user_access/project_authorization_spec.rb | 50 + .../clusters/agents/group_authorization_spec.rb | 16 - .../clusters/agents/implicit_authorization_spec.rb | 14 - .../clusters/agents/project_authorization_spec.rb | 16 - .../clusters/applications/crossplane_spec.rb | 62 - spec/models/clusters/applications/helm_spec.rb | 116 -- spec/models/clusters/applications/ingress_spec.rb | 180 --- spec/models/clusters/applications/jupyter_spec.rb | 130 -- spec/models/clusters/applications/knative_spec.rb | 260 ---- .../clusters/applications/prometheus_spec.rb | 349 ----- spec/models/clusters/applications/runner_spec.rb | 127 -- spec/models/clusters/cluster_spec.rb | 254 +--- .../clusters/integrations/prometheus_spec.rb | 4 +- spec/models/clusters/kubernetes_namespace_spec.rb | 10 +- spec/models/clusters/platforms/kubernetes_spec.rb | 43 +- spec/models/commit_collection_spec.rb | 33 +- spec/models/commit_spec.rb | 152 ++- spec/models/commit_status_spec.rb | 55 +- spec/models/compare_spec.rb | 34 +- spec/models/concerns/atomic_internal_id_spec.rb | 99 +- spec/models/concerns/awareness_spec.rb | 39 - spec/models/concerns/ci/has_status_spec.rb | 26 +- spec/models/concerns/ci/maskable_spec.rb | 2 +- .../ci/partitionable/partitioned_filter_spec.rb | 80 -- .../concerns/ci/partitionable/switch_spec.rb | 9 +- spec/models/concerns/ci/partitionable_spec.rb | 12 +- .../concerns/ci/track_environment_usage_spec.rb | 20 +- .../agents/authorization_config_scopes_spec.rb | 21 - .../authorizations/ci_access/config_scopes_spec.rb | 21 + .../authorizations/user_access/scopes_spec.rb | 27 + .../concerns/database_event_tracking_spec.rb | 44 +- spec/models/concerns/deployment_platform_spec.rb | 45 +- spec/models/concerns/each_batch_spec.rb | 32 + spec/models/concerns/expirable_spec.rb | 66 +- spec/models/concerns/has_user_type_spec.rb | 18 +- spec/models/concerns/issuable_spec.rb | 36 +- spec/models/concerns/mentionable_spec.rb | 2 +- spec/models/concerns/prometheus_adapter_spec.rb | 2 +- spec/models/concerns/protected_ref_access_spec.rb | 45 - spec/models/concerns/redis_cacheable_spec.rb | 52 + .../concerns/require_email_verification_spec.rb | 16 +- spec/models/concerns/routable_spec.rb | 11 + spec/models/concerns/subscribable_spec.rb | 26 + spec/models/concerns/taskable_spec.rb | 7 +- spec/models/concerns/token_authenticatable_spec.rb | 5 +- .../token_authenticatable_strategies/base_spec.rb | 37 +- .../encrypted_spec.rb | 149 +-- .../encryption_helper_spec.rb | 92 +- spec/models/concerns/uniquify_spec.rb | 44 - .../concerns/web_hooks/has_web_hooks_spec.rb | 41 + .../container_registry/data_repair_detail_spec.rb | 29 + spec/models/container_registry/event_spec.rb | 24 +- spec/models/container_repository_spec.rb | 100 +- spec/models/customer_relations/contact_spec.rb | 8 +- .../models/customer_relations/organization_spec.rb | 74 +- spec/models/deployment_spec.rb | 24 +- .../design_management/design_collection_spec.rb | 2 +- spec/models/design_management/design_spec.rb | 17 +- .../design_management/git_repository_spec.rb | 64 + spec/models/design_management/repository_spec.rb | 57 +- spec/models/design_management/version_spec.rb | 10 +- spec/models/diff_note_spec.rb | 35 +- spec/models/environment_spec.rb | 33 +- spec/models/environment_status_spec.rb | 39 +- .../project_error_tracking_setting_spec.rb | 38 +- spec/models/event_collection_spec.rb | 3 +- spec/models/event_spec.rb | 26 +- spec/models/generic_commit_status_spec.rb | 3 +- spec/models/group_group_link_spec.rb | 127 +- spec/models/group_label_spec.rb | 43 +- spec/models/group_spec.rb | 62 +- spec/models/hooks/web_hook_spec.rb | 24 +- spec/models/import_export_upload_spec.rb | 2 +- spec/models/import_failure_spec.rb | 27 +- spec/models/instance_configuration_spec.rb | 6 +- spec/models/integration_spec.rb | 2 +- spec/models/integrations/apple_app_store_spec.rb | 15 +- spec/models/integrations/buildkite_spec.rb | 9 +- spec/models/integrations/campfire_spec.rb | 14 +- .../chat_message/deployment_message_spec.rb | 2 +- spec/models/integrations/every_integration_spec.rb | 4 +- spec/models/integrations/ewm_spec.rb | 12 +- spec/models/integrations/field_spec.rb | 16 +- .../integrations/gitlab_slack_application_spec.rb | 337 +++++ spec/models/integrations/google_play_spec.rb | 101 ++ spec/models/integrations/hangouts_chat_spec.rb | 17 +- spec/models/integrations/harbor_spec.rb | 2 +- spec/models/integrations/jira_spec.rb | 164 ++- .../integrations/mattermost_slash_commands_spec.rb | 9 +- spec/models/integrations/prometheus_spec.rb | 50 +- spec/models/integrations/redmine_spec.rb | 4 +- .../integrations/slack_slash_commands_spec.rb | 9 +- .../integrations/slack_workspace/api_scope_spec.rb | 20 + spec/models/integrations/squash_tm_spec.rb | 117 ++ spec/models/integrations/youtrack_spec.rb | 6 +- spec/models/internal_id_spec.rb | 12 +- spec/models/issue_spec.rb | 260 +++- spec/models/key_spec.rb | 2 +- spec/models/label_spec.rb | 11 + spec/models/member_spec.rb | 117 +- spec/models/members/member_role_spec.rb | 107 -- spec/models/members/project_member_spec.rb | 20 +- spec/models/merge_request/diff_llm_summary_spec.rb | 17 + spec/models/merge_request/metrics_spec.rb | 8 + spec/models/merge_request_spec.rb | 138 +- spec/models/milestone_spec.rb | 12 +- spec/models/ml/candidate_spec.rb | 127 +- spec/models/ml/experiment_spec.rb | 26 +- spec/models/namespace/aggregation_schedule_spec.rb | 26 +- spec/models/namespace/package_setting_spec.rb | 52 +- .../namespace/root_storage_statistics_spec.rb | 162 ++- spec/models/namespace_setting_spec.rb | 92 +- spec/models/namespace_spec.rb | 483 ++++--- .../namespaces/randomized_suffix_path_spec.rb | 2 +- spec/models/note_spec.rb | 53 +- spec/models/notes/note_metadata_spec.rb | 35 + spec/models/oauth_access_token_spec.rb | 4 +- spec/models/onboarding/completion_spec.rb | 73 +- spec/models/onboarding/progress_spec.rb | 6 +- spec/models/operations/feature_flag_spec.rb | 6 +- spec/models/organization_spec.rb | 98 ++ spec/models/packages/debian/file_metadatum_spec.rb | 44 +- .../packages/debian/group_distribution_spec.rb | 7 +- .../packages/debian/project_distribution_spec.rb | 7 +- spec/models/packages/dependency_spec.rb | 19 +- spec/models/packages/event_spec.rb | 51 + spec/models/packages/npm/metadata_cache_spec.rb | 150 +++ spec/models/packages/npm/metadatum_spec.rb | 14 +- spec/models/packages/package_file_spec.rb | 12 + spec/models/packages/package_spec.rb | 79 +- spec/models/pages/lookup_path_spec.rb | 92 +- spec/models/pages_deployment_spec.rb | 60 + spec/models/pages_domain_spec.rb | 39 - spec/models/personal_access_token_spec.rb | 93 +- spec/models/plan_limits_spec.rb | 3 + spec/models/preloaders/labels_preloader_spec.rb | 14 +- .../runner_manager_policy_preloader_spec.rb | 38 + ...er_max_access_level_in_groups_preloader_spec.rb | 16 - ...s_max_access_level_by_project_preloader_spec.rb | 61 + ..._max_access_level_in_projects_preloader_spec.rb | 51 - spec/models/project_ci_cd_setting_spec.rb | 18 +- spec/models/project_feature_spec.rb | 36 +- spec/models/project_label_spec.rb | 35 + spec/models/project_setting_spec.rb | 70 +- spec/models/project_spec.rb | 598 +++++---- spec/models/project_wiki_spec.rb | 29 +- spec/models/projects/data_transfer_spec.rb | 32 + spec/models/projects/forks/details_spec.rb | 162 +++ .../projects/forks/divergence_counts_spec.rb | 98 -- .../projects/import_export/relation_export_spec.rb | 22 +- .../protected_branch/merge_access_level_spec.rb | 5 +- .../protected_branch/push_access_level_spec.rb | 5 +- spec/models/protected_branch_spec.rb | 169 ++- .../protected_tag/create_access_level_spec.rb | 13 +- spec/models/releases/link_spec.rb | 9 - spec/models/releases/source_spec.rb | 6 +- spec/models/repository_spec.rb | 313 +++-- .../resource_events/abuse_report_event_spec.rb | 17 + .../resource_events/issue_assignment_event_spec.rb | 17 + .../merge_request_assignment_event_spec.rb | 17 + spec/models/resource_state_event_spec.rb | 14 +- spec/models/serverless/domain_cluster_spec.rb | 75 -- spec/models/serverless/domain_spec.rb | 97 -- spec/models/serverless/function_spec.rb | 21 - .../service_desk/custom_email_credential_spec.rb | 67 + .../service_desk/custom_email_verification_spec.rb | 170 +++ spec/models/service_desk_setting_spec.rb | 65 +- spec/models/slack_integration_spec.rb | 147 +++ spec/models/snippet_spec.rb | 32 +- spec/models/spam_log_spec.rb | 3 +- spec/models/terraform/state_spec.rb | 2 +- spec/models/terraform/state_version_spec.rb | 4 +- spec/models/u2f_registration_spec.rb | 141 --- spec/models/upload_spec.rb | 8 +- spec/models/user_detail_spec.rb | 20 +- spec/models/user_preference_spec.rb | 63 +- spec/models/user_spec.rb | 526 ++++++-- spec/models/users/credit_card_validation_spec.rb | 103 ++ spec/models/wiki_directory_spec.rb | 9 +- spec/models/wiki_page/meta_spec.rb | 10 +- spec/models/wiki_page_spec.rb | 14 + spec/models/work_item_spec.rb | 244 +++- spec/models/work_items/resource_link_event_spec.rb | 16 + spec/models/work_items/widget_definition_spec.rb | 5 +- spec/models/work_items/widgets/award_emoji_spec.rb | 30 + .../work_items/widgets/notifications_spec.rb | 19 + spec/policies/abuse_report_policy_spec.rb | 25 + .../achievements/user_achievement_policy_spec.rb | 78 ++ spec/policies/ci/build_policy_spec.rb | 32 +- spec/policies/ci/pipeline_policy_spec.rb | 18 +- spec/policies/ci/pipeline_schedule_policy_spec.rb | 14 +- spec/policies/ci/runner_manager_policy_spec.rb | 176 +++ spec/policies/clusters/agent_policy_spec.rb | 18 + spec/policies/concerns/policy_actor_spec.rb | 18 +- .../design_management/design_policy_spec.rb | 4 +- spec/policies/environment_policy_spec.rb | 3 +- spec/policies/global_policy_spec.rb | 142 ++- spec/policies/group_policy_spec.rb | 272 +++- spec/policies/identity_provider_policy_spec.rb | 10 +- spec/policies/issue_policy_spec.rb | 4 +- .../metrics/dashboard/annotation_policy_spec.rb | 16 +- .../namespaces/user_namespace_policy_spec.rb | 28 +- spec/policies/project_group_link_policy_spec.rb | 2 +- spec/policies/project_hook_policy_spec.rb | 6 +- spec/policies/project_policy_spec.rb | 279 +++- spec/presenters/blob_presenter_spec.rb | 10 +- spec/presenters/ci/build_presenter_spec.rb | 16 + spec/presenters/ci/build_runner_presenter_spec.rb | 78 +- .../code_quality_mr_diff_presenter_spec.rb | 2 +- spec/presenters/commit_presenter_spec.rb | 13 +- .../issue_email_participant_presenter_spec.rb | 43 +- spec/presenters/issue_presenter_spec.rb | 28 +- spec/presenters/merge_request_presenter_spec.rb | 9 +- .../ml/candidate_details_presenter_spec.rb | 111 ++ .../presenters/ml/candidates_csv_presenter_spec.rb | 84 ++ .../packages/detail/package_presenter_spec.rb | 3 +- .../packages/npm/package_presenter_spec.rb | 161 +-- spec/presenters/pages_domain_presenter_spec.rb | 44 +- .../project_clusterable_presenter_spec.rb | 10 +- spec/presenters/project_hook_presenter_spec.rb | 4 +- spec/presenters/releases/link_presenter_spec.rb | 2 +- spec/presenters/service_hook_presenter_spec.rb | 4 +- spec/rails_autoload.rb | 56 + spec/requests/abuse_reports_controller_spec.rb | 1 + .../admin/abuse_reports_controller_spec.rb | 92 ++ .../requests/admin/applications_controller_spec.rb | 2 +- .../admin/background_migrations_controller_spec.rb | 11 + .../admin/broadcast_messages_controller_spec.rb | 5 +- .../admin/impersonation_tokens_controller_spec.rb | 2 +- .../requests/admin/integrations_controller_spec.rb | 14 + spec/requests/admin/projects_controller_spec.rb | 86 ++ spec/requests/admin/users_controller_spec.rb | 42 + .../admin/version_check_controller_spec.rb | 2 +- spec/requests/api/access_requests_spec.rb | 2 +- .../admin/batched_background_migrations_spec.rb | 93 +- spec/requests/api/admin/ci/variables_spec.rb | 131 +- spec/requests/api/admin/instance_clusters_spec.rb | 139 +- spec/requests/api/admin/plan_limits_spec.rb | 64 +- spec/requests/api/admin/sidekiq_spec.rb | 27 +- .../api/api_guard/admin_mode_middleware_spec.rb | 2 +- .../api_guard/response_coercer_middleware_spec.rb | 2 +- spec/requests/api/api_spec.rb | 24 +- spec/requests/api/appearance_spec.rb | 22 +- spec/requests/api/applications_spec.rb | 10 +- spec/requests/api/avatar_spec.rb | 1 + spec/requests/api/award_emoji_spec.rb | 2 +- spec/requests/api/badges_spec.rb | 4 +- spec/requests/api/broadcast_messages_spec.rb | 87 +- spec/requests/api/bulk_imports_spec.rb | 87 +- spec/requests/api/ci/job_artifacts_spec.rb | 6 +- spec/requests/api/ci/jobs_spec.rb | 52 +- spec/requests/api/ci/pipeline_schedules_spec.rb | 4 +- spec/requests/api/ci/pipelines_spec.rb | 197 ++- spec/requests/api/ci/runner/jobs_artifacts_spec.rb | 63 +- spec/requests/api/ci/runner/jobs_put_spec.rb | 6 +- .../api/ci/runner/jobs_request_post_spec.rb | 115 +- spec/requests/api/ci/runner/runners_delete_spec.rb | 92 +- spec/requests/api/ci/runner/runners_post_spec.rb | 81 +- .../api/ci/runner/runners_verify_post_spec.rb | 69 +- .../ci/runners_reset_registration_token_spec.rb | 15 +- spec/requests/api/ci/runners_spec.rb | 166 ++- spec/requests/api/ci/secure_files_spec.rb | 2 +- spec/requests/api/ci/variables_spec.rb | 2 +- spec/requests/api/clusters/agent_tokens_spec.rb | 19 +- spec/requests/api/clusters/agents_spec.rb | 2 +- spec/requests/api/commit_statuses_spec.rb | 4 +- spec/requests/api/commits_spec.rb | 63 +- spec/requests/api/composer_packages_spec.rb | 6 +- spec/requests/api/conan_project_packages_spec.rb | 23 + spec/requests/api/debian_group_packages_spec.rb | 69 +- spec/requests/api/debian_project_packages_spec.rb | 89 +- spec/requests/api/deploy_keys_spec.rb | 134 +- spec/requests/api/deploy_tokens_spec.rb | 45 +- spec/requests/api/deployments_spec.rb | 6 +- spec/requests/api/doorkeeper_access_spec.rb | 2 +- spec/requests/api/draft_notes_spec.rb | 214 +++- spec/requests/api/environments_spec.rb | 40 +- .../api/error_tracking/project_settings_spec.rb | 359 ++++-- spec/requests/api/files_spec.rb | 35 +- spec/requests/api/freeze_periods_spec.rb | 68 +- .../achievements/user_achievements_query_spec.rb | 80 ++ spec/requests/api/graphql/ci/ci_cd_setting_spec.rb | 1 - .../api/graphql/ci/config_variables_spec.rb | 4 +- .../api/graphql/ci/group_variables_spec.rb | 2 +- .../api/graphql/ci/inherited_ci_variables_spec.rb | 108 ++ .../api/graphql/ci/instance_variables_spec.rb | 2 +- spec/requests/api/graphql/ci/job_spec.rb | 3 +- spec/requests/api/graphql/ci/jobs_spec.rb | 186 +++ .../api/graphql/ci/manual_variables_spec.rb | 2 +- .../api/graphql/ci/project_variables_spec.rb | 2 +- spec/requests/api/graphql/ci/runner_spec.rb | 350 +++-- spec/requests/api/graphql/ci/runners_spec.rb | 31 +- .../api/graphql/current_user/todos_query_spec.rb | 2 +- .../api/graphql/current_user_query_spec.rb | 2 +- .../api/graphql/custom_emoji_query_spec.rb | 2 +- .../api/graphql/group/data_transfer_spec.rb | 115 ++ .../graphql/group/dependency_proxy_blobs_spec.rb | 10 +- .../api/graphql/group/labels_query_spec.rb | 19 - spec/requests/api/graphql/group/milestones_spec.rb | 6 - spec/requests/api/graphql/issues_spec.rb | 34 + spec/requests/api/graphql/jobs_query_spec.rb | 41 +- .../graphql/metrics/dashboard/annotations_spec.rb | 16 + .../api/graphql/metrics/dashboard_query_spec.rb | 15 + .../api/graphql/multiplexed_queries_spec.rb | 2 +- .../graphql/mutations/achievements/award_spec.rb | 106 ++ .../graphql/mutations/achievements/delete_spec.rb | 79 ++ .../graphql/mutations/achievements/revoke_spec.rb | 91 ++ .../graphql/mutations/achievements/update_spec.rb | 90 ++ .../admin/sidekiq_queues/delete_jobs_spec.rb | 2 +- .../api/graphql/mutations/award_emojis/add_spec.rb | 2 +- .../graphql/mutations/award_emojis/remove_spec.rb | 2 +- .../graphql/mutations/award_emojis/toggle_spec.rb | 2 +- .../api/graphql/mutations/ci/job/cancel_spec.rb | 45 + .../api/graphql/mutations/ci/job/play_spec.rb | 79 ++ .../api/graphql/mutations/ci/job/retry_spec.rb | 92 ++ .../graphql/mutations/ci/job/unschedule_spec.rb | 48 + .../mutations/ci/job_artifact/bulk_destroy_spec.rb | 197 +++ .../api/graphql/mutations/ci/job_cancel_spec.rb | 45 - .../api/graphql/mutations/ci/job_play_spec.rb | 79 -- .../api/graphql/mutations/ci/job_retry_spec.rb | 92 -- .../ci/job_token_scope/add_project_spec.rb | 19 +- .../graphql/mutations/ci/job_unschedule_spec.rb | 48 - .../ci/project_ci_cd_settings_update_spec.rb | 108 +- .../api/graphql/mutations/ci/runner/create_spec.rb | 313 +++++ .../agent_tokens/agent_tokens/create_spec.rb | 2 +- .../mutations/clusters/agents/create_spec.rb | 2 +- .../mutations/clusters/agents/delete_spec.rb | 2 +- .../mutations/container_repository/destroy_spec.rb | 4 +- .../container_repository/destroy_tags_spec.rb | 8 +- .../graphql/mutations/custom_emoji/create_spec.rb | 2 +- .../graphql/mutations/custom_emoji/destroy_spec.rb | 2 +- .../mutations/design_management/update_spec.rb | 77 ++ .../graphql/mutations/issues/bulk_update_spec.rb | 68 +- .../api/graphql/mutations/issues/create_spec.rb | 1 - .../mutations/members/groups/bulk_update_spec.rb | 128 +- .../mutations/members/projects/bulk_update_spec.rb | 18 + .../mutations/merge_requests/set_assignees_spec.rb | 2 +- .../metrics/dashboard/annotations/create_spec.rb | 15 +- .../metrics/dashboard/annotations/delete_spec.rb | 15 +- .../graphql/mutations/notes/create/note_spec.rb | 17 +- .../graphql/mutations/projects/sync_fork_spec.rb | 153 +++ .../mutations/release_asset_links/create_spec.rb | 4 +- .../mutations/release_asset_links/delete_spec.rb | 4 +- .../mutations/release_asset_links/update_spec.rb | 4 +- .../api/graphql/mutations/releases/create_spec.rb | 2 - .../api/graphql/mutations/snippets/update_spec.rb | 3 - .../mutations/user_preferences/update_spec.rb | 12 +- .../graphql/mutations/work_items/convert_spec.rb | 61 + .../mutations/work_items/create_from_task_spec.rb | 3 +- .../graphql/mutations/work_items/create_spec.rb | 152 ++- .../graphql/mutations/work_items/export_spec.rb | 71 ++ .../graphql/mutations/work_items/update_spec.rb | 730 ++++++++++- .../mutations/work_items/update_task_spec.rb | 2 +- .../api/graphql/namespace/projects_spec.rb | 2 +- spec/requests/api/graphql/packages/package_spec.rb | 25 + .../alert/metrics_dashboard_url_spec.rb | 25 +- .../project/alert_management/alert/notes_spec.rb | 2 +- .../api/graphql/project/base_service_spec.rb | 2 +- .../project/ci_access_authorized_agents_spec.rb | 122 ++ .../api/graphql/project/cluster_agents_spec.rb | 5 +- .../api/graphql/project/commit_references_spec.rb | 240 ++++ .../graphql/project/container_repositories_spec.rb | 4 +- .../api/graphql/project/data_transfer_spec.rb | 112 ++ .../api/graphql/project/environments_spec.rb | 2 +- .../api/graphql/project/flow_metrics_spec.rb | 23 + .../api/graphql/project/fork_details_spec.rb | 34 +- .../api/graphql/project/merge_request_spec.rb | 27 + .../api/graphql/project/merge_requests_spec.rb | 27 +- .../api/graphql/project/milestones_spec.rb | 29 - .../project/project_statistics_redirect_spec.rb | 78 ++ spec/requests/api/graphql/project/release_spec.rb | 8 +- .../project/user_access_authorized_agents_spec.rb | 129 ++ .../api/graphql/project/work_items_spec.rb | 132 +- spec/requests/api/graphql/project_query_spec.rb | 61 + spec/requests/api/graphql/query_spec.rb | 36 +- .../graphql/user/user_achievements_query_spec.rb | 95 ++ spec/requests/api/graphql/user_spec.rb | 18 +- spec/requests/api/graphql/work_item_spec.rb | 186 ++- spec/requests/api/graphql_spec.rb | 2 +- spec/requests/api/group_clusters_spec.rb | 2 +- spec/requests/api/group_milestones_spec.rb | 78 +- spec/requests/api/group_variables_spec.rb | 2 +- spec/requests/api/groups_spec.rb | 367 +++--- spec/requests/api/helm_packages_spec.rb | 15 +- spec/requests/api/helpers_spec.rb | 2 +- spec/requests/api/import_github_spec.rb | 74 +- .../requests/api/integrations/slack/events_spec.rb | 91 ++ .../api/integrations/slack/interactions_spec.rb | 69 + .../api/integrations/slack/options_spec.rb | 64 + spec/requests/api/integrations_spec.rb | 54 +- spec/requests/api/internal/base_spec.rb | 98 +- spec/requests/api/internal/kubernetes_spec.rb | 177 ++- spec/requests/api/internal/pages_spec.rb | 382 +++--- spec/requests/api/internal/workhorse_spec.rb | 2 +- spec/requests/api/issue_links_spec.rb | 6 +- spec/requests/api/issues/get_group_issues_spec.rb | 30 +- .../requests/api/issues/get_project_issues_spec.rb | 62 +- spec/requests/api/issues/issues_spec.rb | 82 +- .../api/issues/post_projects_issues_spec.rb | 24 +- .../api/issues/put_projects_issues_spec.rb | 69 +- spec/requests/api/keys_spec.rb | 47 +- spec/requests/api/lint_spec.rb | 228 +--- spec/requests/api/maven_packages_spec.rb | 246 +++- spec/requests/api/members_spec.rb | 40 +- spec/requests/api/merge_requests_spec.rb | 149 ++- spec/requests/api/metadata_spec.rb | 2 +- .../api/metrics/dashboard/annotations_spec.rb | 15 +- .../api/metrics/user_starred_dashboards_spec.rb | 28 + spec/requests/api/ml/mlflow/experiments_spec.rb | 215 ++++ spec/requests/api/ml/mlflow/runs_spec.rb | 354 ++++++ spec/requests/api/ml/mlflow_spec.rb | 630 --------- spec/requests/api/namespaces_spec.rb | 74 +- spec/requests/api/notes_spec.rb | 10 +- spec/requests/api/npm_instance_packages_spec.rb | 34 +- spec/requests/api/npm_project_packages_spec.rb | 127 +- spec/requests/api/nuget_group_packages_spec.rb | 12 +- spec/requests/api/nuget_project_packages_spec.rb | 11 +- spec/requests/api/oauth_tokens_spec.rb | 4 +- spec/requests/api/package_files_spec.rb | 84 ++ spec/requests/api/pages/internal_access_spec.rb | 68 +- spec/requests/api/pages/pages_spec.rb | 22 +- spec/requests/api/pages/private_access_spec.rb | 68 +- spec/requests/api/pages/public_access_spec.rb | 68 +- spec/requests/api/pages_domains_spec.rb | 44 +- .../self_information_spec.rb | 6 +- spec/requests/api/personal_access_tokens_spec.rb | 72 +- spec/requests/api/project_attributes.yml | 20 +- spec/requests/api/project_clusters_spec.rb | 2 +- spec/requests/api/project_export_spec.rb | 123 +- spec/requests/api/project_import_spec.rb | 108 +- spec/requests/api/project_job_token_scope_spec.rb | 76 ++ spec/requests/api/project_milestones_spec.rb | 87 +- spec/requests/api/project_snapshots_spec.rb | 13 +- spec/requests/api/project_snippets_spec.rb | 136 +- spec/requests/api/project_templates_spec.rb | 25 + spec/requests/api/projects_spec.rb | 1036 +++++++++------ spec/requests/api/protected_branches_spec.rb | 124 +- spec/requests/api/protected_tags_spec.rb | 15 + spec/requests/api/pypi_packages_spec.rb | 30 +- spec/requests/api/release/links_spec.rb | 28 +- spec/requests/api/releases_spec.rb | 37 +- spec/requests/api/repositories_spec.rb | 1 - spec/requests/api/resource_access_tokens_spec.rb | 112 +- spec/requests/api/rubygem_packages_spec.rb | 30 +- spec/requests/api/search_spec.rb | 23 +- spec/requests/api/settings_spec.rb | 66 +- spec/requests/api/sidekiq_metrics_spec.rb | 17 +- spec/requests/api/snippets_spec.rb | 20 +- spec/requests/api/statistics_spec.rb | 8 +- spec/requests/api/tags_spec.rb | 2 +- .../api/terraform/modules/v1/packages_spec.rb | 7 +- spec/requests/api/terraform/state_spec.rb | 92 +- spec/requests/api/terraform/state_version_spec.rb | 10 +- spec/requests/api/topics_spec.rb | 95 +- spec/requests/api/unleash_spec.rb | 8 + .../api/usage_data_non_sql_metrics_spec.rb | 10 +- spec/requests/api/usage_data_queries_spec.rb | 12 +- spec/requests/api/users_preferences_spec.rb | 5 +- spec/requests/api/users_spec.rb | 1223 ++++++++++++------ spec/requests/api/v3/github_spec.rb | 70 +- spec/requests/dashboard_controller_spec.rb | 2 +- spec/requests/git_http_spec.rb | 29 +- .../groups/achievements_controller_spec.rb | 78 ++ .../groups/email_campaigns_controller_spec.rb | 6 +- .../groups/observability_controller_spec.rb | 18 +- .../settings/access_tokens_controller_spec.rb | 2 +- .../settings/applications_controller_spec.rb | 2 +- .../groups/usage_quotas_controller_spec.rb | 2 +- spec/requests/ide_controller_spec.rb | 153 +-- spec/requests/import/github_controller_spec.rb | 42 + .../import/github_groups_controller_spec.rb | 2 + .../import/gitlab_projects_controller_spec.rb | 14 + spec/requests/jira_authorizations_spec.rb | 10 + .../oauth_application_ids_controller_spec.rb | 6 +- .../jira_connect/public_keys_controller_spec.rb | 21 +- .../requests/jira_connect/users_controller_spec.rb | 46 - spec/requests/jwks_controller_spec.rb | 11 +- spec/requests/jwt_controller_spec.rb | 10 +- .../requests/oauth/applications_controller_spec.rb | 2 +- .../oauth/authorizations_controller_spec.rb | 2 +- spec/requests/oauth/tokens_controller_spec.rb | 2 +- spec/requests/oauth_tokens_spec.rb | 2 +- spec/requests/openid_connect_spec.rb | 6 +- .../profiles/comment_templates_controller_spec.rb | 35 + .../profiles/saved_replies_controller_spec.rb | 35 - .../projects/airflow/dags_controller_spec.rb | 105 -- .../projects/aws/configuration_controller_spec.rb | 59 + .../histograms_controller_spec.rb | 2 +- .../projects/cluster_agents_controller_spec.rb | 2 +- .../projects/cycle_analytics_events_spec.rb | 2 +- .../projects/environments_controller_spec.rb | 4 +- .../google_cloud/configuration_controller_spec.rb | 2 +- .../google_cloud/databases_controller_spec.rb | 2 +- .../google_cloud/deployments_controller_spec.rb | 114 +- .../google_cloud/gcp_regions_controller_spec.rb | 2 +- .../google_cloud/revoke_oauth_controller_spec.rb | 2 +- .../service_accounts_controller_spec.rb | 2 +- .../incident_management/timeline_events_spec.rb | 4 +- .../projects/issue_links_controller_spec.rb | 26 +- spec/requests/projects/issues_controller_spec.rb | 39 +- .../projects/merge_requests_controller_spec.rb | 5 +- .../projects/merge_requests_discussions_spec.rb | 295 ++--- spec/requests/projects/merge_requests_spec.rb | 11 +- .../projects/metrics/dashboards/builder_spec.rb | 16 + spec/requests/projects/metrics_dashboard_spec.rb | 12 + .../projects/ml/candidates_controller_spec.rb | 53 +- .../projects/ml/experiments_controller_spec.rb | 230 ++-- .../requests/projects/pipelines_controller_spec.rb | 36 +- .../settings/access_tokens_controller_spec.rb | 2 +- spec/requests/projects/uploads_spec.rb | 2 +- spec/requests/projects/usage_quotas_spec.rb | 2 +- spec/requests/projects/wikis_controller_spec.rb | 72 ++ spec/requests/projects/work_items_spec.rb | 178 ++- spec/requests/rack_attack_global_spec.rb | 2 +- spec/requests/registrations_controller_spec.rb | 24 + spec/requests/sandbox_controller_spec.rb | 2 +- spec/requests/search_controller_spec.rb | 10 +- spec/requests/self_monitoring_project_spec.rb | 213 ---- spec/requests/sessions_spec.rb | 48 +- .../time_tracking/timelogs_controller_spec.rb | 46 + spec/requests/users/pins_spec.rb | 67 + spec/requests/users_controller_spec.rb | 142 ++- spec/requests/verifies_with_email_spec.rb | 4 +- .../requests/web_ide/remote_ide_controller_spec.rb | 2 +- spec/routing/directs/subscription_portal_spec.rb | 63 + spec/routing/import_routing_spec.rb | 42 +- spec/routing/project_routing_spec.rb | 102 +- spec/routing/user_routing_spec.rb | 2 +- .../background_migration/feature_category_spec.rb | 2 - .../missing_dictionary_file_spec.rb | 137 ++ spec/rubocop/cop/gettext/static_identifier_spec.rb | 174 +++ spec/rubocop/cop/gitlab/avoid_feature_get_spec.rb | 2 - .../gitlab/deprecate_track_redis_hll_event_spec.rb | 17 - spec/rubocop/cop/gitlab/doc_url_spec.rb | 2 +- .../cop/gitlab/keys_first_and_values_first_spec.rb | 2 - .../cop/gitlab/mark_used_feature_flags_spec.rb | 15 +- spec/rubocop/cop/gitlab/service_response_spec.rb | 2 - spec/rubocop/cop/graphql/authorize_types_spec.rb | 22 + .../rubocop/cop/lint/last_keyword_argument_spec.rb | 2 +- .../migration/add_columns_to_wide_tables_spec.rb | 2 - .../migration/add_concurrent_foreign_key_spec.rb | 2 - .../migration/add_limit_to_text_columns_spec.rb | 24 - spec/rubocop/cop/migration/add_reference_spec.rb | 2 - .../cop/migration/background_migrations_spec.rb | 2 - .../migration/batch_migrations_post_only_spec.rb | 2 - .../create_table_with_foreign_keys_spec.rb | 8 +- spec/rubocop/cop/migration/schedule_async_spec.rb | 1 - .../cop/migration/update_column_in_batches_spec.rb | 1 - .../cop/rspec/avoid_conditional_statements_spec.rb | 42 + spec/rubocop/cop/rspec/avoid_test_prof_spec.rb | 2 +- .../rubocop/cop/rspec/htt_party_basic_auth_spec.rb | 40 - spec/rubocop/cop/rspec/httparty_basic_auth_spec.rb | 40 + .../cop/rspec/invalid_feature_category_spec.rb | 14 +- .../rspec/misspelled_aggregate_failures_spec.rb | 136 ++ .../cop/rspec/shared_groups_metadata_spec.rb | 70 + .../cop/ruby_interpolation_in_translation_spec.rb | 48 - spec/rubocop/cop/search/namespaced_class_spec.rb | 100 ++ .../worker_data_consistency_spec.rb | 123 +- .../api/create_merge_request_discussion_spec.rb | 40 + spec/scripts/api/get_package_and_test_job_spec.rb | 147 +++ .../create_pipeline_failure_incident_spec.rb | 120 -- spec/scripts/database/schema_validator_spec.rb | 67 + spec/scripts/failed_tests_spec.rb | 6 +- ...rate_failed_package_and_test_mr_message_spec.rb | 79 ++ spec/scripts/generate_rspec_pipeline_spec.rb | 253 ++++ spec/scripts/lib/glfm/shared_spec.rb | 3 +- .../lib/glfm/update_example_snapshots_spec.rb | 3 + .../pipeline/create_test_failure_issues_spec.rb | 188 +++ spec/scripts/pipeline_test_report_builder_spec.rb | 5 + spec/scripts/review_apps/automated_cleanup_spec.rb | 262 ++++ spec/serializers/access_token_entity_base_spec.rb | 2 +- .../admin/abuse_report_details_entity_spec.rb | 158 +++ .../admin/abuse_report_details_serializer_spec.rb | 20 + spec/serializers/admin/abuse_report_entity_spec.rb | 40 + .../admin/abuse_report_serializer_spec.rb | 23 + spec/serializers/analytics_issue_entity_spec.rb | 6 +- spec/serializers/build_details_entity_spec.rb | 10 +- .../ci/codequality_mr_diff_entity_spec.rb | 2 +- .../ci/downloadable_artifact_entity_spec.rb | 3 +- spec/serializers/ci/job_entity_spec.rb | 6 +- spec/serializers/ci/pipeline_entity_spec.rb | 8 +- .../serializers/cluster_application_entity_spec.rb | 81 -- spec/serializers/cluster_entity_spec.rb | 14 - spec/serializers/cluster_serializer_spec.rb | 4 +- .../deploy_keys/basic_deploy_key_entity_spec.rb | 1 + .../deploy_keys/deploy_key_entity_spec.rb | 1 + spec/serializers/diff_file_entity_spec.rb | 4 +- spec/serializers/diff_viewer_entity_spec.rb | 47 +- .../discussion_diff_file_entity_spec.rb | 3 +- spec/serializers/entity_date_helper_spec.rb | 10 +- spec/serializers/environment_entity_spec.rb | 44 +- spec/serializers/environment_serializer_spec.rb | 5 +- spec/serializers/environment_status_entity_spec.rb | 3 + spec/serializers/group_child_entity_spec.rb | 9 +- spec/serializers/group_deploy_key_entity_spec.rb | 1 + .../group_issuable_autocomplete_entity_spec.rb | 3 +- spec/serializers/import/bulk_import_entity_spec.rb | 2 +- .../import/github_failure_entity_spec.rb | 319 +++++ .../import/github_failure_serializer_spec.rb | 71 ++ spec/serializers/integrations/field_entity_spec.rb | 11 +- spec/serializers/issue_board_entity_spec.rb | 24 +- spec/serializers/issue_entity_spec.rb | 25 +- .../serializers/issue_sidebar_basic_entity_spec.rb | 5 +- .../jira_connect/app_data_serializer_spec.rb | 11 +- .../linked_project_issue_entity_spec.rb | 12 +- .../merge_request_metrics_helper_spec.rb | 12 +- ...merge_request_poll_cached_widget_entity_spec.rb | 42 +- .../merge_request_poll_widget_entity_spec.rb | 8 +- spec/serializers/note_entity_spec.rb | 63 + spec/serializers/pipeline_details_entity_spec.rb | 34 +- spec/serializers/pipeline_serializer_spec.rb | 48 +- spec/serializers/profile/event_entity_spec.rb | 149 +++ spec/serializers/project_import_entity_spec.rb | 30 +- spec/serializers/runner_entity_spec.rb | 18 + .../access_token_validation_service_spec.rb | 2 +- spec/services/achievements/award_service_spec.rb | 80 ++ spec/services/achievements/destroy_service_spec.rb | 39 + spec/services/achievements/revoke_service_spec.rb | 66 + spec/services/achievements/update_service_spec.rb | 48 + .../admin/abuse_report_update_service_spec.rb | 199 +++ .../admin/set_feature_flag_service_spec.rb | 2 +- .../alerts/todo/create_service_spec.rb | 2 +- .../alert_management/alerts/update_service_spec.rb | 2 +- .../create_alert_issue_service_spec.rb | 2 +- .../http_integrations/create_service_spec.rb | 2 +- .../http_integrations/destroy_service_spec.rb | 2 +- .../http_integrations/update_service_spec.rb | 2 +- .../metric_images/upload_service_spec.rb | 2 +- .../process_prometheus_alert_service_spec.rb | 2 +- .../cycle_analytics/stages/list_service_spec.rb | 2 +- .../application_settings/update_service_spec.rb | 6 +- spec/services/audit_event_service_spec.rb | 2 +- spec/services/audit_events/build_service_spec.rb | 2 +- ...ntainer_registry_authentication_service_spec.rb | 2 +- ...dependency_proxy_authentication_service_spec.rb | 2 +- .../find_records_due_for_refresh_service_spec.rb | 2 +- .../periodic_recalculate_service_spec.rb | 2 +- .../project_access_changed_service_spec.rb | 2 +- .../project_recalculate_per_user_service_spec.rb | 2 +- .../project_recalculate_service_spec.rb | 2 +- spec/services/auto_merge/base_service_spec.rb | 2 +- .../merge_when_pipeline_succeeds_service_spec.rb | 2 +- spec/services/auto_merge_service_spec.rb | 2 +- spec/services/award_emojis/add_service_spec.rb | 2 +- spec/services/award_emojis/base_service_spec.rb | 2 +- .../collect_user_emoji_service_spec.rb | 2 +- spec/services/award_emojis/copy_service_spec.rb | 2 +- spec/services/award_emojis/destroy_service_spec.rb | 2 +- spec/services/award_emojis/toggle_service_spec.rb | 2 +- spec/services/base_container_service_spec.rb | 2 +- spec/services/base_count_service_spec.rb | 2 +- spec/services/boards/create_service_spec.rb | 2 +- spec/services/boards/destroy_service_spec.rb | 2 +- spec/services/boards/issues/create_service_spec.rb | 2 +- spec/services/boards/issues/list_service_spec.rb | 14 +- spec/services/boards/issues/move_service_spec.rb | 2 +- spec/services/boards/lists/create_service_spec.rb | 2 +- spec/services/boards/lists/destroy_service_spec.rb | 2 +- spec/services/boards/lists/list_service_spec.rb | 2 +- spec/services/boards/lists/move_service_spec.rb | 2 +- spec/services/boards/lists/update_service_spec.rb | 2 +- spec/services/boards/visits/create_service_spec.rb | 2 +- spec/services/branches/create_service_spec.rb | 4 +- .../branches/delete_merged_service_spec.rb | 2 +- spec/services/branches/delete_service_spec.rb | 2 +- .../diverging_commit_counts_service_spec.rb | 2 +- .../services/branches/validate_new_service_spec.rb | 2 +- .../bulk_create_integration_service_spec.rb | 2 +- .../archive_extraction_service_spec.rb | 2 +- .../batched_relation_export_service_spec.rb | 104 ++ spec/services/bulk_imports/create_service_spec.rb | 321 ++++- spec/services/bulk_imports/export_service_spec.rb | 53 +- .../file_decompression_service_spec.rb | 2 +- .../bulk_imports/file_download_service_spec.rb | 2 +- .../bulk_imports/file_export_service_spec.rb | 64 +- .../lfs_objects_export_service_spec.rb | 25 +- .../relation_batch_export_service_spec.rb | 67 + .../bulk_imports/relation_export_service_spec.rb | 24 +- .../repository_bundle_export_service_spec.rb | 2 +- .../bulk_imports/tree_export_service_spec.rb | 12 +- .../bulk_imports/uploads_export_service_spec.rb | 35 +- .../bulk_push_event_payload_service_spec.rb | 2 +- .../bulk_update_integration_service_spec.rb | 10 +- .../captcha/captcha_verification_service_spec.rb | 2 +- spec/services/chat_names/find_user_service_spec.rb | 2 +- spec/services/ci/abort_pipelines_service_spec.rb | 2 +- .../services/ci/append_build_trace_service_spec.rb | 2 +- spec/services/ci/archive_trace_service_spec.rb | 34 +- spec/services/ci/build_cancel_service_spec.rb | 2 +- spec/services/ci/build_erase_service_spec.rb | 2 +- .../ci/build_report_result_service_spec.rb | 2 +- spec/services/ci/build_unschedule_service_spec.rb | 2 +- .../ci/catalog/validate_resource_service_spec.rb | 57 + spec/services/ci/change_variable_service_spec.rb | 2 +- spec/services/ci/change_variables_service_spec.rb | 2 +- .../compare_accessibility_reports_service_spec.rb | 2 +- .../ci/compare_codequality_reports_service_spec.rb | 2 +- .../ci/compare_reports_base_service_spec.rb | 2 +- .../ci/compare_test_reports_service_spec.rb | 2 +- spec/services/ci/components/fetch_service_spec.rb | 2 +- ...opy_cross_database_associations_service_spec.rb | 2 +- .../ci/create_downstream_pipeline_service_spec.rb | 14 +- .../ci/create_pipeline_service/artifacts_spec.rb | 2 +- .../ci/create_pipeline_service/cache_spec.rb | 18 +- .../creation_errors_and_warnings_spec.rb | 2 +- .../cross_project_pipeline_spec.rb | 11 +- .../custom_config_content_spec.rb | 2 +- .../custom_yaml_tags_spec.rb | 3 +- .../ci/create_pipeline_service/dry_run_spec.rb | 3 +- .../ci/create_pipeline_service/environment_spec.rb | 3 +- .../evaluate_runner_tags_spec.rb | 3 +- .../ci/create_pipeline_service/include_spec.rb | 2 +- .../limit_active_jobs_spec.rb | 3 +- .../ci/create_pipeline_service/logger_spec.rb | 6 +- .../create_pipeline_service/merge_requests_spec.rb | 15 +- .../ci/create_pipeline_service/needs_spec.rb | 3 +- .../ci/create_pipeline_service/parallel_spec.rb | 3 +- .../parameter_content_spec.rb | 3 +- .../parent_child_pipeline_spec.rb | 3 +- .../create_pipeline_service/partitioning_spec.rb | 2 +- .../pre_post_stages_spec.rb | 3 +- .../ci/create_pipeline_service/rate_limit_spec.rb | 5 +- .../ci/create_pipeline_service/rules_spec.rb | 139 +- .../ci/create_pipeline_service/scripts_spec.rb | 28 +- .../ci/create_pipeline_service/tags_spec.rb | 2 +- .../ci/create_pipeline_service/variables_spec.rb | 3 +- spec/services/ci/create_pipeline_service_spec.rb | 333 ++++- .../ci/create_web_ide_terminal_service_spec.rb | 2 +- ...daily_build_group_report_result_service_spec.rb | 2 +- spec/services/ci/delete_objects_service_spec.rb | 2 +- spec/services/ci/delete_unit_tests_service_spec.rb | 2 +- .../ci/deployments/destroy_service_spec.rb | 2 +- spec/services/ci/destroy_pipeline_service_spec.rb | 2 +- .../ci/destroy_secure_file_service_spec.rb | 2 +- ...disable_user_pipeline_schedules_service_spec.rb | 2 +- spec/services/ci/drop_pipeline_service_spec.rb | 2 +- spec/services/ci/ensure_stage_service_spec.rb | 2 +- .../ci/expire_pipeline_cache_service_spec.rb | 2 +- .../create_pipeline_service_spec.rb | 2 +- .../ci/find_exposed_artifacts_service_spec.rb | 2 +- ...rate_codequality_mr_diff_report_service_spec.rb | 2 +- .../ci/generate_coverage_reports_service_spec.rb | 2 +- .../ci/generate_kubeconfig_service_spec.rb | 14 +- .../ci/generate_terraform_reports_service_spec.rb | 2 +- .../bulk_delete_by_project_service_spec.rb | 121 ++ .../ci/job_artifacts/create_service_spec.rb | 525 +++++--- .../delete_project_artifacts_service_spec.rb | 2 +- .../ci/job_artifacts/delete_service_spec.rb | 2 +- .../destroy_all_expired_service_spec.rb | 40 +- .../destroy_associations_service_spec.rb | 31 +- .../ci/job_artifacts/destroy_batch_service_spec.rb | 15 +- .../expire_project_build_artifacts_service_spec.rb | 2 +- .../track_artifact_report_service_spec.rb | 62 +- .../update_unknown_locked_status_service_spec.rb | 3 +- .../ci/job_token_scope/add_project_service_spec.rb | 4 +- .../ci/list_config_variables_service_spec.rb | 2 +- .../coverage_report_service_spec.rb | 2 +- ...ate_code_quality_mr_diff_report_service_spec.rb | 2 +- .../destroy_all_expired_service_spec.rb | 3 +- .../ci/pipeline_bridge_status_service_spec.rb | 2 +- .../start_pipeline_service_spec.rb | 2 +- .../status_collection_spec.rb | 58 +- .../atomic_processing_service_spec.rb | 21 +- .../test_cases/dag_test_on_failure_no_needs.yml | 31 + ...age_build_cancels_test1_and_test2_have_when.yml | 46 + ...ith_allow_failure_test1_and_test2_have_when.yml | 47 + .../stage_test_on_failure_no_prev_stage.yml | 29 + .../take_ownership_service_spec.rb | 2 +- spec/services/ci/pipeline_trigger_service_spec.rb | 2 +- spec/services/ci/pipelines/add_job_service_spec.rb | 12 +- spec/services/ci/pipelines/hook_service_spec.rb | 2 +- spec/services/ci/play_bridge_service_spec.rb | 2 +- spec/services/ci/play_build_service_spec.rb | 5 +- spec/services/ci/play_manual_stage_service_spec.rb | 7 +- spec/services/ci/prepare_build_service_spec.rb | 2 +- spec/services/ci/process_build_service_spec.rb | 2 +- spec/services/ci/process_pipeline_service_spec.rb | 2 +- .../ci/process_sync_events_service_spec.rb | 5 +- .../observe_histograms_service_spec.rb | 2 +- .../ci/queue/pending_builds_strategy_spec.rb | 2 +- spec/services/ci/register_job_service_spec.rb | 1166 ++++++++--------- .../services/ci/reset_skipped_jobs_service_spec.rb | 487 ++++++- ...gn_resource_from_resource_group_service_spec.rb | 2 +- spec/services/ci/retry_job_service_spec.rb | 15 +- spec/services/ci/retry_pipeline_service_spec.rb | 22 +- .../ci/run_scheduled_build_service_spec.rb | 5 +- .../ci/runners/create_runner_service_spec.rb | 203 ++- .../process_runner_version_update_service_spec.rb | 13 + .../ci/runners/register_runner_service_spec.rb | 64 +- .../runners/stale_machines_cleanup_service_spec.rb | 45 - .../runners/stale_managers_cleanup_service_spec.rb | 45 + .../unregister_runner_manager_service_spec.rb | 63 + .../ci/stuck_builds/drop_pending_service_spec.rb | 2 +- .../ci/stuck_builds/drop_running_service_spec.rb | 2 +- .../ci/stuck_builds/drop_scheduled_service_spec.rb | 2 +- .../ci/test_failure_history_service_spec.rb | 2 +- .../services/ci/track_failed_build_service_spec.rb | 2 +- spec/services/ci/unlock_artifacts_service_spec.rb | 20 +- .../services/ci/update_build_queue_service_spec.rb | 2 +- .../ci/update_instance_variables_service_spec.rb | 2 +- .../ci/update_pending_build_service_spec.rb | 2 +- .../clusters/agent_tokens/create_service_spec.rb | 8 +- .../clusters/agent_tokens/revoke_service_spec.rb | 77 ++ .../agent_tokens/track_usage_service_spec.rb | 2 +- .../ci_access/filter_service_spec.rb | 100 ++ .../ci_access/refresh_service_spec.rb | 154 +++ .../user_access/refresh_service_spec.rb | 181 +++ .../agents/authorize_proxy_user_service_spec.rb | 65 + .../agents/create_activity_event_service_spec.rb | 13 +- .../clusters/agents/create_service_spec.rb | 2 +- .../agents/delete_expired_events_service_spec.rb | 2 +- .../clusters/agents/delete_service_spec.rb | 2 +- .../agents/filter_authorizations_service_spec.rb | 100 -- .../agents/refresh_authorization_service_spec.rb | 154 --- .../build_kubernetes_namespace_service_spec.rb | 2 +- spec/services/clusters/build_service_spec.rb | 2 +- .../cleanup/project_namespace_service_spec.rb | 2 +- .../cleanup/service_account_service_spec.rb | 18 +- spec/services/clusters/create_service_spec.rb | 4 +- spec/services/clusters/destroy_service_spec.rb | 2 +- .../clusters/integrations/create_service_spec.rb | 2 +- .../prometheus_health_check_service_spec.rb | 2 +- .../create_or_update_namespace_service_spec.rb | 4 +- ...reate_or_update_service_account_service_spec.rb | 2 +- .../fetch_kubernetes_token_service_spec.rb | 2 +- spec/services/clusters/kubernetes_spec.rb | 2 +- ..._management_project_permissions_service_spec.rb | 2 +- spec/services/clusters/update_service_spec.rb | 2 +- spec/services/cohorts_service_spec.rb | 2 +- spec/services/commits/cherry_pick_service_spec.rb | 2 +- spec/services/commits/commit_patch_service_spec.rb | 2 +- spec/services/commits/tag_service_spec.rb | 2 +- spec/services/compare_service_spec.rb | 2 +- .../concerns/audit_event_save_type_spec.rb | 2 +- .../concerns/exclusive_lease_guard_spec.rb | 48 +- .../merge_requests/assigns_merge_params_spec.rb | 2 +- .../services/concerns/rate_limited_service_spec.rb | 2 +- .../cleanup_service_spec.rb | 3 +- .../update_service_spec.rb | 2 +- .../contacts/create_service_spec.rb | 6 +- .../contacts/update_service_spec.rb | 2 +- .../organizations/create_service_spec.rb | 8 +- .../organizations/update_service_spec.rb | 14 +- .../database/consistency_check_service_spec.rb | 2 +- .../database/consistency_fix_service_spec.rb | 2 +- .../dependency_proxy/auth_token_service_spec.rb | 2 +- .../find_cached_manifest_service_spec.rb | 2 +- .../group_settings/update_service_spec.rb | 2 +- .../dependency_proxy/head_manifest_service_spec.rb | 2 +- .../update_service_spec.rb | 2 +- .../dependency_proxy/request_token_service_spec.rb | 2 +- spec/services/deploy_keys/create_service_spec.rb | 2 +- .../deployments/archive_in_project_service_spec.rb | 2 +- .../deployments/create_for_build_service_spec.rb | 2 +- spec/services/deployments/create_service_spec.rb | 2 +- .../link_merge_requests_service_spec.rb | 2 +- .../older_deployments_drop_service_spec.rb | 2 +- .../deployments/update_environment_service_spec.rb | 2 +- spec/services/deployments/update_service_spec.rb | 2 +- .../copy_design_collection/copy_service_spec.rb | 3 +- .../copy_design_collection/queue_service_spec.rb | 3 +- .../delete_designs_service_spec.rb | 4 +- .../design_user_notes_count_service_spec.rb | 2 +- .../generate_image_versions_service_spec.rb | 2 +- .../design_management/move_designs_service_spec.rb | 2 +- .../design_management/save_designs_service_spec.rb | 5 +- .../capture_diff_note_position_service_spec.rb | 2 +- .../capture_diff_note_positions_service_spec.rb | 2 +- .../update_diff_position_service_spec.rb | 2 +- spec/services/draft_notes/create_service_spec.rb | 2 +- spec/services/draft_notes/destroy_service_spec.rb | 2 +- spec/services/draft_notes/publish_service_spec.rb | 2 +- spec/services/emails/confirm_service_spec.rb | 2 +- spec/services/emails/create_service_spec.rb | 2 +- spec/services/emails/destroy_service_spec.rb | 2 +- .../environments/auto_stop_service_spec.rb | 3 +- .../canary_ingress/update_service_spec.rb | 3 +- .../environments/create_for_build_service_spec.rb | 2 +- .../environments/reset_auto_stop_service_spec.rb | 2 +- .../schedule_to_delete_review_apps_service_spec.rb | 2 +- spec/services/environments/stop_service_spec.rb | 2 +- spec/services/error_tracking/base_service_spec.rb | 2 +- .../error_tracking/collect_error_service_spec.rb | 2 +- .../error_tracking/issue_details_service_spec.rb | 2 +- .../issue_latest_event_service_spec.rb | 2 +- .../error_tracking/issue_update_service_spec.rb | 2 +- .../error_tracking/list_issues_service_spec.rb | 2 +- spec/services/event_create_service_spec.rb | 60 +- spec/services/events/destroy_service_spec.rb | 2 +- spec/services/events/render_service_spec.rb | 2 +- spec/services/feature_flags/create_service_spec.rb | 10 +- .../services/feature_flags/destroy_service_spec.rb | 5 +- spec/services/feature_flags/hook_service_spec.rb | 2 +- spec/services/feature_flags/update_service_spec.rb | 7 +- spec/services/files/create_service_spec.rb | 2 +- spec/services/files/delete_service_spec.rb | 6 +- spec/services/files/multi_service_spec.rb | 16 +- spec/services/files/update_service_spec.rb | 6 +- spec/services/git/base_hooks_service_spec.rb | 38 +- spec/services/git/branch_hooks_service_spec.rb | 2 +- spec/services/git/branch_push_service_spec.rb | 2 +- .../git/process_ref_changes_service_spec.rb | 2 +- spec/services/git/tag_hooks_service_spec.rb | 2 +- spec/services/git/tag_push_service_spec.rb | 2 +- spec/services/git/wiki_push_service/change_spec.rb | 12 +- .../create_cloudsql_instance_service_spec.rb | 2 +- .../create_service_accounts_service_spec.rb | 2 +- .../google_cloud/enable_cloud_run_service_spec.rb | 2 +- .../google_cloud/enable_cloudsql_service_spec.rb | 2 +- .../gcp_region_add_or_replace_service_spec.rb | 2 +- .../google_cloud/generate_pipeline_service_spec.rb | 2 +- .../get_cloudsql_instances_service_spec.rb | 2 +- .../google_cloud/service_accounts_service_spec.rb | 2 +- .../setup_cloudsql_instance_service_spec.rb | 2 +- spec/services/gpg_keys/create_service_spec.rb | 2 +- spec/services/grafana/proxy_service_spec.rb | 2 +- spec/services/gravatar_service_spec.rb | 2 +- spec/services/groups/auto_devops_service_spec.rb | 2 +- spec/services/groups/autocomplete_service_spec.rb | 2 +- .../groups/deploy_tokens/create_service_spec.rb | 2 +- .../groups/deploy_tokens/destroy_service_spec.rb | 2 +- .../groups/deploy_tokens/revoke_service_spec.rb | 2 +- .../groups/group_links/create_service_spec.rb | 2 +- .../groups/group_links/destroy_service_spec.rb | 2 +- .../groups/group_links/update_service_spec.rb | 4 +- .../groups/import_export/export_service_spec.rb | 2 +- .../groups/import_export/import_service_spec.rb | 2 +- .../groups/merge_requests_count_service_spec.rb | 2 +- spec/services/groups/nested_create_service_spec.rb | 2 +- .../groups/open_issues_count_service_spec.rb | 2 +- spec/services/groups/participants_service_spec.rb | 2 +- spec/services/groups/transfer_service_spec.rb | 61 +- spec/services/groups/update_service_spec.rb | 2 +- .../groups/update_shared_runners_service_spec.rb | 2 +- .../groups/update_statistics_service_spec.rb | 2 +- spec/services/ide/base_config_service_spec.rb | 2 +- spec/services/ide/schemas_config_service_spec.rb | 2 +- spec/services/ide/terminal_config_service_spec.rb | 2 +- .../import/bitbucket_server_service_spec.rb | 4 +- spec/services/import/fogbugz_service_spec.rb | 5 +- .../github/cancel_project_import_service_spec.rb | 14 +- .../import/github/notes/create_service_spec.rb | 2 +- spec/services/import/github_service_spec.rb | 7 +- .../gitlab_projects/create_project_service_spec.rb | 12 +- .../file_upload_spec.rb | 2 +- .../remote_file_s3_spec.rb | 2 +- spec/services/import/prepare_service_spec.rb | 2 +- .../validate_remote_git_endpoint_service_spec.rb | 24 +- spec/services/import_csv/base_service_spec.rb | 69 +- .../import_export_clean_up_service_spec.rb | 2 +- .../incidents/create_service_spec.rb | 2 +- .../after_update_service_spec.rb | 3 +- .../build_service_spec.rb | 2 +- .../create_service_spec.rb | 2 +- .../prepare_update_service_spec.rb | 3 +- .../create_incident_issue_service_spec.rb | 2 +- .../pager_duty/process_webhook_service_spec.rb | 2 +- .../timeline_event_tags/create_service_spec.rb | 2 +- .../timeline_events/create_service_spec.rb | 4 +- .../timeline_events/destroy_service_spec.rb | 3 +- .../timeline_events/update_service_spec.rb | 1 - .../integrations/propagate_service_spec.rb | 2 +- .../integrations/slack_event_service_spec.rb | 56 + .../slack_events/app_home_opened_service_spec.rb | 113 ++ .../slack_events/url_verification_service_spec.rb | 11 + .../integrations/slack_interaction_service_spec.rb | 70 + .../block_action_service_spec.rb | 48 + .../incident_modal_closed_service_spec.rb | 78 ++ .../incident_modal_opened_service_spec.rb | 141 +++ .../incident_modal_submit_service_spec.rb | 296 +++++ .../project_update_handler_spec.rb | 158 +++ .../integrations/slack_option_service_spec.rb | 76 ++ .../slack_options/label_search_handler_spec.rb | 47 + .../slack_options/user_search_handler_spec.rb | 52 + .../integrations/test/project_service_spec.rb | 2 +- spec/services/issuable/bulk_update_service_spec.rb | 2 +- spec/services/issuable/callbacks/milestone_spec.rb | 101 ++ .../issuable/common_system_notes_service_spec.rb | 2 +- .../issuable/destroy_label_links_service_spec.rb | 2 +- spec/services/issuable/destroy_service_spec.rb | 2 +- .../issuable/discussions_list_service_spec.rb | 2 +- spec/services/issuable/process_assignees_spec.rb | 2 +- spec/services/issue_links/create_service_spec.rb | 3 +- spec/services/issue_links/destroy_service_spec.rb | 3 +- spec/services/issue_links/list_service_spec.rb | 2 +- spec/services/issues/after_create_service_spec.rb | 9 +- spec/services/issues/base_service_spec.rb | 9 + spec/services/issues/build_service_spec.rb | 36 +- spec/services/issues/clone_service_spec.rb | 2 +- spec/services/issues/close_service_spec.rb | 75 +- spec/services/issues/create_service_spec.rb | 77 +- spec/services/issues/duplicate_service_spec.rb | 2 +- spec/services/issues/import_csv_service_spec.rb | 3 +- spec/services/issues/issuable_base_service_spec.rb | 9 + .../issues/prepare_import_csv_service_spec.rb | 2 +- .../referenced_merge_requests_service_spec.rb | 2 +- .../issues/related_branches_service_spec.rb | 2 +- .../relative_position_rebalancing_service_spec.rb | 2 +- spec/services/issues/reopen_service_spec.rb | 12 +- spec/services/issues/reorder_service_spec.rb | 2 +- spec/services/issues/resolve_discussions_spec.rb | 14 +- .../issues/set_crm_contacts_service_spec.rb | 2 +- spec/services/issues/update_service_spec.rb | 101 +- spec/services/issues/zoom_link_service_spec.rb | 3 +- .../jira/requests/projects/list_service_spec.rb | 2 +- spec/services/jira_connect/sync_service_spec.rb | 12 +- .../destroy_service_spec.rb | 2 +- .../proxy_lifecycle_event_service_spec.rb | 6 +- .../create_service_spec.rb | 2 +- .../jira_import/cloud_users_mapper_service_spec.rb | 2 +- .../server_users_mapper_service_spec.rb | 2 +- .../jira_import/start_import_service_spec.rb | 2 +- spec/services/jira_import/users_importer_spec.rb | 2 +- spec/services/keys/create_service_spec.rb | 2 +- spec/services/keys/destroy_service_spec.rb | 2 +- .../keys/expiry_notification_service_spec.rb | 2 +- spec/services/keys/last_used_service_spec.rb | 60 +- spec/services/keys/revoke_service_spec.rb | 13 - .../labels/available_labels_service_spec.rb | 2 +- spec/services/labels/create_service_spec.rb | 2 +- .../services/labels/find_or_create_service_spec.rb | 2 +- spec/services/labels/promote_service_spec.rb | 2 +- spec/services/labels/transfer_service_spec.rb | 2 +- spec/services/labels/update_service_spec.rb | 2 +- spec/services/lfs/lock_file_service_spec.rb | 2 +- spec/services/lfs/locks_finder_service_spec.rb | 2 +- spec/services/lfs/push_service_spec.rb | 2 +- spec/services/lfs/unlock_file_service_spec.rb | 2 +- .../batch_cleaner_service_spec.rb | 2 +- .../loose_foreign_keys/cleaner_service_spec.rb | 2 +- .../process_deleted_records_service_spec.rb | 2 +- .../markdown_content_rewriter_service_spec.rb | 2 +- spec/services/markup/rendering_service_spec.rb | 19 +- .../mattermost/create_team_service_spec.rb | 28 + .../members/approve_access_request_service_spec.rb | 20 +- spec/services/members/base_service_spec.rb | 5 +- spec/services/members/create_service_spec.rb | 3 +- spec/services/members/creator_service_spec.rb | 2 +- spec/services/members/destroy_service_spec.rb | 143 ++- .../members/groups/creator_service_spec.rb | 4 +- .../members/import_project_team_service_spec.rb | 2 +- .../invitation_reminder_email_service_spec.rb | 2 +- .../services/members/invite_member_builder_spec.rb | 2 +- spec/services/members/invite_service_spec.rb | 3 +- .../members/projects/creator_service_spec.rb | 4 +- .../members/request_access_service_spec.rb | 2 +- .../members/standard_member_builder_spec.rb | 2 +- .../members/unassign_issuables_service_spec.rb | 2 +- spec/services/members/update_service_spec.rb | 2 +- .../merge_requests/add_context_service_spec.rb | 2 +- .../merge_requests/add_spent_time_service_spec.rb | 2 +- .../add_todo_when_build_fails_service_spec.rb | 24 +- .../merge_requests/after_create_service_spec.rb | 23 +- .../merge_requests/approval_service_spec.rb | 2 +- .../merge_requests/assign_issues_service_spec.rb | 16 +- spec/services/merge_requests/base_service_spec.rb | 38 +- .../merge_requests/cleanup_refs_service_spec.rb | 2 +- spec/services/merge_requests/close_service_spec.rb | 6 +- .../merge_requests/conflicts/list_service_spec.rb | 2 +- .../conflicts/resolve_service_spec.rb | 21 +- .../create_approval_event_service_spec.rb | 2 +- .../merge_requests/create_pipeline_service_spec.rb | 2 +- .../services/merge_requests/create_service_spec.rb | 55 +- .../delete_non_latest_diffs_service_spec.rb | 3 +- .../execute_approval_hooks_service_spec.rb | 2 +- .../merge_requests/ff_merge_service_spec.rb | 14 +- .../merge_requests/get_urls_service_spec.rb | 2 +- .../handle_assignees_change_service_spec.rb | 2 +- .../mark_reviewer_reviewed_service_spec.rb | 2 +- .../merge_orchestration_service_spec.rb | 9 +- spec/services/merge_requests/merge_service_spec.rb | 122 +- .../merge_requests/merge_to_ref_service_spec.rb | 28 +- .../mergeability/check_base_service_spec.rb | 2 +- .../check_broken_status_service_spec.rb | 2 +- .../mergeability/check_ci_status_service_spec.rb | 2 +- .../check_discussions_status_service_spec.rb | 2 +- .../check_draft_status_service_spec.rb | 2 +- .../mergeability/check_open_status_service_spec.rb | 2 +- .../detailed_merge_status_service_spec.rb | 27 +- .../merge_requests/mergeability/logger_spec.rb | 2 +- .../mergeability/run_checks_service_spec.rb | 2 +- .../mergeability_check_service_spec.rb | 22 +- .../migrate_external_diffs_service_spec.rb | 2 +- .../merge_requests/post_merge_service_spec.rb | 8 +- .../push_options_handler_service_spec.rb | 2 +- .../services/merge_requests/rebase_service_spec.rb | 28 +- .../merge_requests/refresh_service_spec.rb | 238 ++-- .../merge_requests/reload_diffs_service_spec.rb | 10 +- .../reload_merge_head_diff_service_spec.rb | 2 +- .../services/merge_requests/reopen_service_spec.rb | 8 +- .../merge_requests/request_review_service_spec.rb | 2 +- .../merge_requests/resolve_todos_service_spec.rb | 2 +- ...esolved_discussion_notification_service_spec.rb | 2 +- .../services/merge_requests/squash_service_spec.rb | 26 +- .../update_assignees_service_spec.rb | 36 +- .../update_reviewers_service_spec.rb | 20 +- .../services/merge_requests/update_service_spec.rb | 65 +- .../dashboard/annotations/create_service_spec.rb | 2 +- .../dashboard/annotations/delete_service_spec.rb | 2 +- .../dashboard/clone_dashboard_service_spec.rb | 6 +- .../dashboard/cluster_dashboard_service_spec.rb | 3 +- .../cluster_metrics_embed_service_spec.rb | 3 +- .../dashboard/custom_dashboard_service_spec.rb | 3 +- .../dashboard/custom_metric_embed_service_spec.rb | 2 +- .../dashboard/default_embed_service_spec.rb | 3 +- .../dashboard/dynamic_embed_service_spec.rb | 3 +- .../dashboard/gitlab_alert_embed_service_spec.rb | 2 +- .../dashboard/grafana_metric_embed_service_spec.rb | 2 +- .../dashboard/panel_preview_service_spec.rb | 22 +- .../dashboard/pod_dashboard_service_spec.rb | 3 +- .../self_monitoring_dashboard_service_spec.rb | 88 -- .../dashboard/system_dashboard_service_spec.rb | 3 +- .../dashboard/transient_embed_service_spec.rb | 3 +- .../dashboard/update_dashboard_service_spec.rb | 2 +- .../metrics/global_metrics_update_service_spec.rb | 14 + .../metrics/sample_metrics_service_spec.rb | 2 +- .../create_service_spec.rb | 2 +- .../delete_service_spec.rb | 2 +- spec/services/milestones/close_service_spec.rb | 2 +- .../milestones/closed_issues_count_service_spec.rb | 3 +- spec/services/milestones/create_service_spec.rb | 2 +- spec/services/milestones/destroy_service_spec.rb | 2 +- .../milestones/find_or_create_service_spec.rb | 2 +- .../milestones/issues_count_service_spec.rb | 3 +- .../merge_requests_count_service_spec.rb | 3 +- spec/services/milestones/promote_service_spec.rb | 2 +- spec/services/milestones/transfer_service_spec.rb | 2 +- spec/services/milestones/update_service_spec.rb | 2 +- .../candidate_repository_spec.rb | 32 +- .../experiment_repository_spec.rb | 2 +- ...andle_candidate_gitlab_metadata_service_spec.rb | 40 + .../namespace_settings/update_service_spec.rb | 2 +- .../in_product_marketing_emails_service_spec.rb | 2 +- .../package_settings/update_service_spec.rb | 2 +- .../statistics_refresher_service_spec.rb | 2 +- spec/services/note_summary_spec.rb | 2 +- spec/services/notes/build_service_spec.rb | 12 +- spec/services/notes/copy_service_spec.rb | 8 +- spec/services/notes/create_service_spec.rb | 141 ++- spec/services/notes/destroy_service_spec.rb | 14 +- spec/services/notes/post_process_service_spec.rb | 2 +- spec/services/notes/quick_actions_service_spec.rb | 106 +- spec/services/notes/render_service_spec.rb | 16 +- spec/services/notes/resolve_service_spec.rb | 2 +- spec/services/notes/update_service_spec.rb | 4 +- .../notification_recipients/build_service_spec.rb | 2 +- .../builder/default_spec.rb | 2 +- .../builder/new_note_spec.rb | 2 +- spec/services/notification_service_spec.rb | 34 +- spec/services/onboarding/progress_service_spec.rb | 2 +- .../cleanup/execute_policy_service_spec.rb | 2 +- .../packages/cleanup/update_policy_service_spec.rb | 2 +- .../composer/composer_json_service_spec.rb | 2 +- .../composer/create_package_service_spec.rb | 2 +- .../composer/version_parser_service_spec.rb | 2 +- .../conan/create_package_file_service_spec.rb | 2 +- .../packages/conan/create_package_service_spec.rb | 2 +- .../services/packages/conan/search_service_spec.rb | 28 +- .../conan/single_package_search_service_spec.rb | 45 + .../packages/create_dependency_service_spec.rb | 2 +- .../services/packages/create_event_service_spec.rb | 48 +- .../packages/create_package_file_service_spec.rb | 2 +- .../create_temporary_package_service_spec.rb | 2 +- .../debian/create_package_file_service_spec.rb | 2 +- .../extract_changes_metadata_service_spec.rb | 2 +- .../debian/extract_metadata_service_spec.rb | 86 +- .../debian/find_or_create_package_service_spec.rb | 21 +- .../debian/generate_distribution_service_spec.rb | 28 +- .../debian/parse_debian822_service_spec.rb | 20 +- .../debian/process_changes_service_spec.rb | 36 +- .../debian/process_package_file_service_spec.rb | 41 +- .../generic/create_package_file_service_spec.rb | 16 +- .../generic/find_or_create_package_service_spec.rb | 2 +- .../packages/go/create_package_service_spec.rb | 2 +- .../packages/go/sync_packages_service_spec.rb | 2 +- .../helm/extract_file_metadata_service_spec.rb | 2 +- .../packages/helm/process_file_service_spec.rb | 2 +- ...k_package_files_for_destruction_service_spec.rb | 3 +- .../mark_package_for_destruction_service_spec.rb | 8 +- .../mark_packages_for_destruction_service_spec.rb | 7 +- .../packages/maven/create_package_service_spec.rb | 2 +- .../maven/find_or_create_package_service_spec.rb | 51 +- .../metadata/append_package_file_service_spec.rb | 2 +- .../metadata/create_plugins_xml_service_spec.rb | 2 +- .../metadata/create_versions_xml_service_spec.rb | 2 +- .../packages/maven/metadata/sync_service_spec.rb | 2 +- .../npm/create_metadata_cache_service_spec.rb | 83 ++ .../packages/npm/create_package_service_spec.rb | 178 ++- .../packages/npm/create_tag_service_spec.rb | 2 +- .../packages/npm/deprecate_package_service_spec.rb | 115 ++ .../packages/npm/generate_metadata_service_spec.rb | 173 +++ .../nuget/create_dependency_service_spec.rb | 2 +- .../nuget/metadata_extraction_service_spec.rb | 2 +- .../services/packages/nuget/search_service_spec.rb | 2 +- .../packages/nuget/sync_metadatum_service_spec.rb | 2 +- .../update_package_from_metadata_service_spec.rb | 23 +- .../packages/pypi/create_package_service_spec.rb | 2 +- spec/services/packages/remove_tag_service_spec.rb | 2 +- .../packages/rpm/parse_package_service_spec.rb | 2 +- .../build_filelist_xml_service_spec.rb | 2 +- .../build_other_xml_service_spec.rb | 2 +- .../build_primary_xml_service_spec.rb | 2 +- .../build_repomd_xml_service_spec.rb | 2 +- .../repository_metadata/update_xml_service_spec.rb | 2 +- .../rubygems/create_dependencies_service_spec.rb | 2 +- .../rubygems/create_gemspec_service_spec.rb | 2 +- .../rubygems/dependency_resolver_service_spec.rb | 2 +- .../rubygems/metadata_extraction_service_spec.rb | 2 +- .../packages/rubygems/process_gem_service_spec.rb | 2 +- .../create_package_service_spec.rb | 2 +- .../packages/update_package_file_service_spec.rb | 2 +- spec/services/packages/update_tags_service_spec.rb | 2 +- spec/services/pages/delete_service_spec.rb | 2 +- ...te_legacy_storage_to_deployment_service_spec.rb | 2 +- spec/services/pages/zip_directory_service_spec.rb | 2 +- .../create_acme_order_service_spec.rb | 2 +- ...obtain_lets_encrypt_certificate_service_spec.rb | 2 +- .../personal_access_tokens/create_service_spec.rb | 20 +- .../last_used_service_spec.rb | 2 +- .../personal_access_tokens/revoke_service_spec.rb | 2 +- .../personal_access_tokens/rotate_service_spec.rb | 67 + spec/services/post_receive_service_spec.rb | 2 +- spec/services/preview_markdown_service_spec.rb | 12 +- .../build_activity_graph_service_spec.rb | 2 +- .../product_analytics/build_graph_service_spec.rb | 2 +- .../services/projects/after_rename_service_spec.rb | 2 +- .../projects/alerting/notify_service_spec.rb | 2 +- .../projects/all_issues_count_service_spec.rb | 2 +- .../all_merge_requests_count_service_spec.rb | 17 +- ...ndroid_target_platform_detector_service_spec.rb | 30 - .../apple_target_platform_detector_service_spec.rb | 2 +- .../projects/auto_devops/disable_service_spec.rb | 2 +- .../services/projects/autocomplete_service_spec.rb | 2 +- .../batch_open_issues_count_service_spec.rb | 2 +- ...batch_open_merge_requests_count_service_spec.rb | 32 + spec/services/projects/blame_service_spec.rb | 131 -- .../projects/branches_by_mode_service_spec.rb | 2 +- spec/services/projects/cleanup_service_spec.rb | 2 +- .../cleanup_tags_service_spec.rb | 7 +- .../delete_tags_service_spec.rb | 2 +- .../container_repository/destroy_service_spec.rb | 2 +- .../gitlab/cleanup_tags_service_spec.rb | 54 +- .../gitlab/delete_tags_service_spec.rb | 2 +- .../third_party/cleanup_tags_service_spec.rb | 174 +-- .../third_party/delete_tags_service_spec.rb | 2 +- spec/services/projects/count_service_spec.rb | 2 +- .../projects/create_from_template_service_spec.rb | 2 +- spec/services/projects/create_service_spec.rb | 68 +- .../projects/deploy_tokens/create_service_spec.rb | 2 +- .../projects/deploy_tokens/destroy_service_spec.rb | 2 +- spec/services/projects/destroy_service_spec.rb | 17 +- .../detect_repository_languages_service_spec.rb | 2 +- spec/services/projects/download_service_spec.rb | 2 +- .../projects/enable_deploy_key_service_spec.rb | 2 +- .../fetch_statistics_increment_service_spec.rb | 2 +- spec/services/projects/fork_service_spec.rb | 40 +- spec/services/projects/forks/sync_service_spec.rb | 185 +++ spec/services/projects/forks_count_service_spec.rb | 2 +- .../projects/git_deduplication_service_spec.rb | 4 +- .../gitlab_projects_import_service_spec.rb | 2 +- .../projects/group_links/create_service_spec.rb | 15 +- .../projects/group_links/destroy_service_spec.rb | 11 +- .../projects/group_links/update_service_spec.rb | 11 +- .../hashed_storage/base_attachment_service_spec.rb | 2 +- .../migrate_attachments_service_spec.rb | 2 +- .../migrate_repository_service_spec.rb | 2 +- .../hashed_storage/migration_service_spec.rb | 18 +- .../rollback_attachments_service_spec.rb | 2 +- .../rollback_repository_service_spec.rb | 2 +- .../hashed_storage/rollback_service_spec.rb | 2 +- spec/services/projects/import_error_filter_spec.rb | 2 +- .../import_export/relation_export_service_spec.rb | 4 +- ...oduct_marketing_campaign_emails_service_spec.rb | 2 +- .../lfs_download_link_list_service_spec.rb | 2 +- .../lfs_pointers/lfs_download_service_spec.rb | 2 +- .../lfs_pointers/lfs_import_service_spec.rb | 2 +- .../projects/lfs_pointers/lfs_link_service_spec.rb | 35 +- .../lfs_object_download_list_service_spec.rb | 2 +- spec/services/projects/move_access_service_spec.rb | 2 +- .../move_deploy_keys_projects_service_spec.rb | 2 +- spec/services/projects/move_forks_service_spec.rb | 2 +- .../move_lfs_objects_projects_service_spec.rb | 2 +- .../move_notification_settings_service_spec.rb | 2 +- .../move_project_authorizations_service_spec.rb | 2 +- .../move_project_group_links_service_spec.rb | 2 +- .../projects/move_project_members_service_spec.rb | 2 +- .../move_users_star_projects_service_spec.rb | 2 +- .../projects/open_issues_count_service_spec.rb | 2 +- .../open_merge_requests_count_service_spec.rb | 7 +- .../projects/operations/update_service_spec.rb | 2 +- .../projects/overwrite_project_service_spec.rb | 2 +- .../services/projects/participants_service_spec.rb | 2 +- .../prometheus/alerts/notify_service_spec.rb | 26 +- .../prometheus/metrics/destroy_service_spec.rb | 2 +- .../protect_default_branch_service_spec.rb | 4 +- .../projects/readme_renderer_service_spec.rb | 4 +- .../record_target_platforms_service_spec.rb | 70 +- ...build_artifacts_size_statistics_service_spec.rb | 2 +- .../projects/repository_languages_service_spec.rb | 2 +- ...ule_bulk_repository_shard_moves_service_spec.rb | 2 +- spec/services/projects/transfer_service_spec.rb | 52 +- spec/services/projects/unlink_fork_service_spec.rb | 8 +- .../services/projects/update_pages_service_spec.rb | 68 +- .../projects/update_remote_mirror_service_spec.rb | 2 +- .../update_repository_storage_service_spec.rb | 2 +- spec/services/projects/update_service_spec.rb | 247 ++-- .../projects/update_statistics_service_spec.rb | 4 +- spec/services/prometheus/proxy_service_spec.rb | 2 +- .../proxy_variable_substitution_service_spec.rb | 2 +- .../protected_branches/api_service_spec.rb | 2 +- .../protected_branches/cache_service_spec.rb | 3 +- .../protected_branches/destroy_service_spec.rb | 2 +- .../protected_branches/update_service_spec.rb | 2 +- .../services/protected_tags/create_service_spec.rb | 2 +- .../protected_tags/destroy_service_spec.rb | 2 +- .../services/protected_tags/update_service_spec.rb | 2 +- spec/services/push_event_payload_service_spec.rb | 2 +- .../quick_actions/interpret_service_spec.rb | 267 ++-- spec/services/quick_actions/target_service_spec.rb | 2 +- .../releases/create_evidence_service_spec.rb | 2 +- spec/services/releases/create_service_spec.rb | 20 + spec/services/releases/destroy_service_spec.rb | 2 +- .../services/releases/links/create_service_spec.rb | 84 ++ .../releases/links/destroy_service_spec.rb | 72 ++ .../services/releases/links/update_service_spec.rb | 89 ++ .../repositories/changelog_service_spec.rb | 2 +- spec/services/repositories/destroy_service_spec.rb | 2 +- .../repository_archive_clean_up_service_spec.rb | 2 +- spec/services/reset_project_cache_service_spec.rb | 2 +- .../resource_access_tokens/create_service_spec.rb | 108 +- .../resource_access_tokens/revoke_service_spec.rb | 2 +- .../resource_events/change_labels_service_spec.rb | 2 +- .../change_milestone_service_spec.rb | 2 +- .../resource_events/change_state_service_spec.rb | 2 +- .../merge_into_notes_service_spec.rb | 2 +- .../synthetic_label_notes_builder_service_spec.rb | 2 +- ...nthetic_milestone_notes_builder_service_spec.rb | 8 +- .../synthetic_state_notes_builder_service_spec.rb | 2 +- spec/services/search/global_service_spec.rb | 2 +- spec/services/search/group_service_spec.rb | 2 +- spec/services/search/snippet_service_spec.rb | 2 +- .../container_scanning_create_service_spec.rb | 2 +- .../dependency_scanning_create_service_spec.rb | 2 +- .../sast_iac_create_service_spec.rb | 2 +- .../ci_configuration/sast_parser_service_spec.rb | 2 +- .../secret_detection_create_service_spec.rb | 2 +- .../security/merge_reports_service_spec.rb | 2 +- .../serverless/associate_domain_service_spec.rb | 91 -- .../service_desk_settings/update_service_spec.rb | 2 +- .../submit_service_ping_service_spec.rb | 2 +- spec/services/service_response_spec.rb | 2 +- .../services/snippets/bulk_destroy_service_spec.rb | 2 +- spec/services/snippets/count_service_spec.rb | 2 +- spec/services/snippets/create_service_spec.rb | 2 +- spec/services/snippets/destroy_service_spec.rb | 4 +- .../snippets/repository_validation_service_spec.rb | 2 +- ...ule_bulk_repository_shard_moves_service_spec.rb | 2 +- .../update_repository_storage_service_spec.rb | 2 +- spec/services/snippets/update_service_spec.rb | 2 +- .../snippets/update_statistics_service_spec.rb | 2 +- .../spam/akismet_mark_as_spam_service_spec.rb | 2 +- spec/services/spam/akismet_service_spec.rb | 2 +- spec/services/spam/ham_service_spec.rb | 2 +- spec/services/spam/spam_action_service_spec.rb | 32 +- spec/services/spam/spam_params_spec.rb | 2 +- spec/services/spam/spam_verdict_service_spec.rb | 255 ++-- spec/services/submodules/update_service_spec.rb | 2 +- spec/services/suggestions/apply_service_spec.rb | 2 +- spec/services/suggestions/create_service_spec.rb | 2 +- spec/services/suggestions/outdate_service_spec.rb | 2 +- spec/services/system_hooks_service_spec.rb | 2 +- spec/services/system_note_service_spec.rb | 4 +- .../system_notes/alert_management_service_spec.rb | 2 +- spec/services/system_notes/base_service_spec.rb | 2 +- spec/services/system_notes/commit_service_spec.rb | 82 +- .../system_notes/design_management_service_spec.rb | 2 +- .../services/system_notes/incident_service_spec.rb | 2 +- .../system_notes/incidents_service_spec.rb | 2 +- .../system_notes/issuables_service_spec.rb | 26 +- .../system_notes/merge_requests_service_spec.rb | 2 +- .../system_notes/time_tracking_service_spec.rb | 8 +- spec/services/system_notes/zoom_service_spec.rb | 2 +- spec/services/tags/create_service_spec.rb | 2 +- spec/services/tags/destroy_service_spec.rb | 2 +- spec/services/task_list_toggle_service_spec.rb | 21 +- .../services/tasks_to_be_done/base_service_spec.rb | 6 +- .../terraform/remote_state_handler_spec.rb | 3 +- .../terraform/states/destroy_service_spec.rb | 2 +- .../states/trigger_destroy_service_spec.rb | 2 +- spec/services/test_hooks/project_service_spec.rb | 2 +- spec/services/test_hooks/system_service_spec.rb | 2 +- spec/services/timelogs/delete_service_spec.rb | 2 +- spec/services/todo_service_spec.rb | 102 +- .../todos/allowed_target_filter_service_spec.rb | 2 +- .../destroy/confidential_issue_service_spec.rb | 2 +- spec/services/todos/destroy/design_service_spec.rb | 2 +- .../destroy/destroyed_issuable_service_spec.rb | 2 +- .../todos/destroy/project_private_service_spec.rb | 2 +- .../destroy/unauthorized_features_service_spec.rb | 2 +- spec/services/topics/merge_service_spec.rb | 4 +- spec/services/two_factor/destroy_service_spec.rb | 2 +- .../update_container_registry_info_service_spec.rb | 2 +- .../update_merge_request_metrics_service_spec.rb | 2 +- spec/services/upload_service_spec.rb | 2 +- spec/services/uploads/destroy_service_spec.rb | 2 +- .../user_preferences/update_service_spec.rb | 6 +- .../user_project_access_changed_service_spec.rb | 2 +- spec/services/users/activity_service_spec.rb | 3 +- spec/services/users/approve_service_spec.rb | 20 +- .../users/authorized_build_service_spec.rb | 2 +- spec/services/users/ban_service_spec.rb | 2 +- .../users/banned_user_base_service_spec.rb | 2 +- .../users/batch_status_cleaner_service_spec.rb | 2 +- spec/services/users/block_service_spec.rb | 2 +- spec/services/users/build_service_spec.rb | 2 +- spec/services/users/create_service_spec.rb | 2 +- spec/services/users/deactivate_service_spec.rb | 86 ++ spec/services/users/destroy_service_spec.rb | 2 +- .../services/users/dismiss_callout_service_spec.rb | 2 +- .../users/dismiss_group_callout_service_spec.rb | 2 +- .../users/dismiss_project_callout_service_spec.rb | 2 +- .../generate_token_service_spec.rb | 23 +- .../validate_token_service_spec.rb | 7 +- .../in_product_marketing_email_records_spec.rb | 2 +- spec/services/users/keys_count_service_spec.rb | 2 +- .../services/users/last_push_event_service_spec.rb | 2 +- ...ecords_to_ghost_user_in_batches_service_spec.rb | 2 +- .../migrate_records_to_ghost_user_service_spec.rb | 2 +- .../refresh_authorized_projects_service_spec.rb | 2 +- .../users/registrations_build_service_spec.rb | 2 +- spec/services/users/reject_service_spec.rb | 2 +- .../users/repair_ldap_blocked_service_spec.rb | 2 +- .../users/respond_to_terms_service_spec.rb | 2 +- .../users/saved_replies/create_service_spec.rb | 2 +- .../users/saved_replies/destroy_service_spec.rb | 2 +- .../users/saved_replies/update_service_spec.rb | 2 +- spec/services/users/set_status_service_spec.rb | 2 +- spec/services/users/signup_service_spec.rb | 8 +- spec/services/users/unban_service_spec.rb | 2 +- spec/services/users/unblock_service_spec.rb | 2 +- .../users/update_canonical_email_service_spec.rb | 28 +- .../update_highest_member_role_service_spec.rb | 2 +- spec/services/users/update_service_spec.rb | 48 +- .../users/update_todo_count_cache_service_spec.rb | 2 +- .../upsert_credit_card_validation_service_spec.rb | 10 +- .../users/validate_manual_otp_service_spec.rb | 33 +- .../users/validate_push_otp_service_spec.rb | 2 +- spec/services/verify_pages_domain_service_spec.rb | 2 +- spec/services/web_hooks/destroy_service_spec.rb | 2 +- .../services/web_hooks/log_destroy_service_spec.rb | 2 +- .../web_hooks/log_execution_service_spec.rb | 2 +- .../services/webauthn/authenticate_service_spec.rb | 2 +- spec/services/webauthn/register_service_spec.rb | 2 +- spec/services/wiki_pages/base_service_spec.rb | 2 +- spec/services/wiki_pages/create_service_spec.rb | 2 +- spec/services/wiki_pages/destroy_service_spec.rb | 2 +- .../wiki_pages/event_create_service_spec.rb | 2 +- spec/services/wiki_pages/update_service_spec.rb | 2 +- .../wikis/create_attachment_service_spec.rb | 2 +- spec/services/work_items/build_service_spec.rb | 2 +- .../work_items/create_from_task_service_spec.rb | 2 +- spec/services/work_items/create_service_spec.rb | 335 +++-- spec/services/work_items/delete_service_spec.rb | 2 +- .../work_items/delete_task_service_spec.rb | 2 +- .../services/work_items/export_csv_service_spec.rb | 28 +- .../services/work_items/import_csv_service_spec.rb | 122 ++ .../work_items/parent_links/base_service_spec.rb | 31 + .../work_items/parent_links/create_service_spec.rb | 94 +- .../parent_links/destroy_service_spec.rb | 38 +- .../parent_links/reorder_service_spec.rb | 176 +++ .../work_items/prepare_import_csv_service_spec.rb | 52 + .../task_list_reference_removal_service_spec.rb | 2 +- ...task_list_reference_replacement_service_spec.rb | 2 +- spec/services/work_items/update_service_spec.rb | 29 +- .../assignees_service/update_service_spec.rb | 24 +- .../award_emoji_service/update_service_spec.rb | 96 ++ .../update_service_spec.rb | 106 ++ .../description_service/update_service_spec.rb | 23 +- .../hierarchy_service/create_service_spec.rb | 31 + .../hierarchy_service/update_service_spec.rb | 98 +- .../widgets/labels_service/update_service_spec.rb | 48 + .../milestone_service/create_service_spec.rb | 28 - .../milestone_service/update_service_spec.rb | 58 - .../notifications_service/update_service_spec.rb | 117 ++ .../update_service_spec.rb | 24 +- .../x509_certificate_revoke_service_spec.rb | 2 +- spec/simplecov_env.rb | 1 + spec/spec_helper.rb | 120 +- spec/support/ability_check.rb | 73 ++ spec/support/ability_check_todo.yml | 73 ++ .../banzai/filter_timeout_shared_examples.rb | 37 - .../banzai/reference_filter_shared_examples.rb | 88 -- spec/support/capybara.rb | 63 +- spec/support/capybara_wait_for_all_requests.rb | 47 + spec/support/chunked_io/chunked_io_helpers.rb | 13 - .../project_import_rate_limiter_shared_examples.rb | 22 - .../cycle_analytics_helpers/test_generation.rb | 160 --- spec/support/database/prevent_cross_joins.rb | 2 +- spec/support/fast_quarantine.rb | 37 + spec/support/finder_collection_allowlist.yml | 5 +- spec/support/flaky_tests.rb | 37 - .../metrics_instrumentation_shared_examples.rb | 44 - spec/support/google_api/cloud_platform_helpers.rb | 166 --- spec/support/graphql/arguments.rb | 71 -- spec/support/graphql/fake_query_type.rb | 22 - spec/support/graphql/fake_tracer.rb | 15 - spec/support/graphql/field_inspection.rb | 35 - spec/support/graphql/field_selection.rb | 69 - spec/support/graphql/resolver_factories.rb | 40 - .../action_cable/mock_action_cable.rb | 100 -- .../action_cable/mock_gitlab_schema.rb | 41 - spec/support/graphql/subscriptions/notes/helper.rb | 94 -- spec/support/graphql/var.rb | 59 - spec/support/helpers/api_internal_base_helpers.rb | 16 +- spec/support/helpers/board_helpers.rb | 16 +- spec/support/helpers/callouts_test_helper.rb | 9 - spec/support/helpers/chunked_io_helpers.rb | 13 + spec/support/helpers/ci/source_pipeline_helpers.rb | 12 +- spec/support/helpers/ci/template_helpers.rb | 4 + spec/support/helpers/content_editor_helpers.rb | 49 + spec/support/helpers/cycle_analytics_helpers.rb | 15 +- .../cycle_analytics_helpers/test_generation.rb | 166 +++ spec/support/helpers/database/database_helpers.rb | 8 +- .../helpers/database/inject_failure_helpers.rb | 41 + .../helpers/database/multiple_databases_helpers.rb | 22 + spec/support/helpers/email_helpers.rb | 21 + .../helpers/every_sidekiq_worker_test_helper.rb | 9 + spec/support/helpers/fake_u2f_device.rb | 47 - spec/support/helpers/fake_webauthn_device.rb | 2 +- spec/support/helpers/feature_flag_helpers.rb | 24 +- .../helpers/features/access_token_helpers.rb | 23 +- .../helpers/features/admin_users_helpers.rb | 28 +- spec/support/helpers/features/blob_spec_helpers.rb | 18 +- spec/support/helpers/features/branches_helpers.rb | 33 +- .../helpers/features/canonical_link_helpers.rb | 22 +- .../features/invite_members_modal_helper.rb | 154 --- .../features/invite_members_modal_helpers.rb | 148 +++ spec/support/helpers/features/iteration_helpers.rb | 9 +- spec/support/helpers/features/list_rows_helpers.rb | 28 - spec/support/helpers/features/members_helpers.rb | 114 +- .../helpers/features/merge_request_helpers.rb | 32 +- spec/support/helpers/features/mirroring_helpers.rb | 28 + spec/support/helpers/features/notes_helpers.rb | 76 +- spec/support/helpers/features/releases_helpers.rb | 107 +- .../helpers/features/responsive_table_helpers.rb | 22 +- spec/support/helpers/features/runners_helpers.rb | 92 +- spec/support/helpers/features/snippet_helpers.rb | 89 -- .../helpers/features/snippet_spec_helpers.rb | 83 ++ spec/support/helpers/features/sorting_helpers.rb | 36 +- .../helpers/features/source_editor_spec_helpers.rb | 26 +- .../helpers/features/top_nav_spec_helpers.rb | 46 +- .../support/helpers/features/two_factor_helpers.rb | 123 +- .../helpers/features/web_ide_spec_helpers.rb | 167 +-- spec/support/helpers/filtered_search_helpers.rb | 19 +- spec/support/helpers/fixture_helpers.rb | 2 +- spec/support/helpers/gitaly_setup.rb | 54 - .../helpers/google_api/cloud_platform_helpers.rb | 168 +++ spec/support/helpers/graphql/arguments.rb | 71 ++ spec/support/helpers/graphql/fake_query_type.rb | 23 + spec/support/helpers/graphql/fake_tracer.rb | 15 + spec/support/helpers/graphql/field_inspection.rb | 35 + spec/support/helpers/graphql/field_selection.rb | 69 + spec/support/helpers/graphql/resolver_factories.rb | 40 + .../action_cable/mock_action_cable.rb | 100 ++ .../action_cable/mock_gitlab_schema.rb | 41 + .../helpers/graphql/subscriptions/notes/helper.rb | 94 ++ spec/support/helpers/graphql/var.rb | 59 + spec/support/helpers/graphql_helpers.rb | 46 +- spec/support/helpers/http_io_helpers.rb | 49 + spec/support/helpers/jira_integration_helpers.rb | 2 +- spec/support/helpers/keyset_pagination_helpers.rb | 23 + spec/support/helpers/login_helpers.rb | 26 +- spec/support/helpers/markdown_feature.rb | 8 + spec/support/helpers/metrics_dashboard_helpers.rb | 4 - spec/support/helpers/migrations_helpers.rb | 2 +- .../helpers/migrations_helpers/cluster_helpers.rb | 71 ++ .../migrations_helpers/namespaces_helper.rb | 15 + .../migrations_helpers/schema_version_finder.rb | 35 + .../vulnerabilities_findings_helper.rb | 118 ++ .../ci/partitioning_testing/cascade_check.rb | 34 + .../partitioning_testing/partition_identifiers.rb | 13 + .../models/ci/partitioning_testing/rspec_hooks.rb | 23 + .../ci/partitioning_testing/schema_helpers.rb | 91 ++ .../merge_request_without_merge_request_diff.rb | 7 + spec/support/helpers/navbar_structure_helper.rb | 20 +- spec/support/helpers/note_interaction_helpers.rb | 2 +- .../helpers/project_template_test_helper.rb | 4 +- spec/support/helpers/prometheus/metric_builders.rb | 29 + spec/support/helpers/query_recorder.rb | 4 + spec/support/helpers/redis_helpers.rb | 9 + spec/support/helpers/repo_helpers.rb | 4 + spec/support/helpers/search_helpers.rb | 8 +- spec/support/helpers/session_helpers.rb | 6 + spec/support/helpers/snowplow_helpers.rb | 10 +- spec/support/helpers/stub_configuration.rb | 6 +- spec/support/helpers/stub_gitlab_calls.rb | 6 +- spec/support/helpers/stub_object_storage.rb | 126 +- spec/support/helpers/test_env.rb | 4 +- spec/support/helpers/test_reports_helper.rb | 103 ++ spec/support/helpers/trace_helpers.rb | 29 + spec/support/helpers/usage_data_helpers.rb | 13 +- spec/support/helpers/user_login_helper.rb | 16 + spec/support/helpers/wait_for_requests.rb | 3 + spec/support/helpers/workhorse_helpers.rb | 58 +- spec/support/http_io/http_io_helpers.rb | 51 - spec/support/import_export/common_util.rb | 25 +- spec/support/import_export/export_file_helper.rb | 22 +- .../matchers/background_migrations_matchers.rb | 14 + .../support/matchers/be_a_foreign_key_column_of.rb | 19 + spec/support/matchers/be_indexed_by.rb | 26 + spec/support/matchers/exceed_redis_call_limit.rb | 57 + spec/support/matchers/have_plain_text_content.rb | 16 + spec/support/matchers/markdown_matchers.rb | 13 +- spec/support/matchers/request_urgency_matcher.rb | 29 + spec/support/matchers/snapshot_matcher.rb | 55 + spec/support/migrations_helpers/cluster_helpers.rb | 71 -- .../migrations_helpers/namespaces_helper.rb | 14 - .../migrations_helpers/schema_version_finder.rb | 34 - .../vulnerabilities_findings_helper.rb | 118 -- .../ci/partitioning_testing/cascade_check.rb | 34 - .../partitioning_testing/partition_identifiers.rb | 13 - .../models/ci/partitioning_testing/rspec_hooks.rb | 19 - .../ci/partitioning_testing/schema_helpers.rb | 91 -- .../merge_request_without_merge_request_diff.rb | 7 - spec/support/permissions_check.rb | 18 + .../additional_metrics_shared_examples.rb | 159 --- spec/support/prometheus/metric_builders.rb | 29 - spec/support/protected_branch_helpers.rb | 23 +- .../access_control_ce_shared_examples.rb | 49 - spec/support/redis/redis_helpers.rb | 9 - .../redis/redis_new_instance_shared_examples.rb | 111 -- spec/support/redis/redis_shared_examples.rb | 459 ------- spec/support/rspec.rb | 12 +- spec/support/rspec_order.rb | 2 + spec/support/rspec_order_todo.yml | 358 +----- .../services/clusters/create_service_shared.rb | 64 - .../services/deploy_token_shared_examples.rb | 86 -- ...le_description_quick_actions_shared_examples.rb | 62 - .../issuable_import_csv_service_shared_examples.rb | 138 -- .../issuable_update_service_shared_examples.rb | 99 -- .../move_and_clone_services_shared_examples.rb | 22 - ...igrate_to_ghost_user_service_shared_examples.rb | 89 -- .../services/service_response_shared_examples.rb | 25 - .../bulk_imports_requests_shared_context.rb | 25 +- .../design_management_shared_contexts.rb | 33 +- ...stance_and_group_integrations_shared_context.rb | 2 +- .../integrations/integrations_shared_context.rb | 209 +-- .../project_integrations_jira_context.rb | 1 + .../project_integrations_shared_context.rb | 2 +- .../finders/issues_finder_shared_contexts.rb | 78 +- .../merge_requests_finder_shared_contexts.rb | 42 +- .../finders/work_items_finder_shared_contexts.rb | 78 +- .../glfm/example_snapshot_fixtures.rb | 2 +- .../graphql/types/query_type_shared_context.rb | 1 + .../issuable/merge_request_shared_context.rb | 2 +- .../load_balancing/wal_tracking_shared_context.rb | 68 + .../list_partitioning_shared_context.rb | 92 ++ .../merge_request_create_shared_context.rb | 15 +- .../merge_request_edit_shared_context.rb | 12 +- ...quests_allowing_collaboration_shared_context.rb | 12 +- .../models/distribution_shared_context.rb | 22 + .../shared_contexts/navbar_structure_context.rb | 56 +- .../policies/group_policy_shared_context.rb | 7 +- .../policies/project_policy_shared_context.rb | 15 +- .../shared_contexts/rack_attack_shared_context.rb | 3 +- .../api/debian_repository_shared_context.rb | 3 + .../releases_and_group_releases_shared_context.rb | 56 +- ...ty_and_compliance_permissions_shared_context.rb | 4 +- .../clusters/create_service_shared_context.rb | 19 + .../delete_tags_service_shared_context.rb | 8 +- ...vice_ping_metrics_definitions_shared_context.rb | 3 +- .../cycle_analytics/flow_metrics_examples.rb | 629 +++++++++ .../cycle_analytics/request_params_examples.rb | 131 ++ .../filters/filter_timeout_shared_examples.rb | 70 + .../filters/inline_embeds_shared_examples.rb | 16 + .../filters/reference_filter_shared_examples.rb | 88 ++ .../multiple_issue_boards_shared_examples.rb | 2 +- .../bulk_imports/visibility_level_examples.rb | 37 - .../githubish_import_controller_shared_examples.rb | 13 + .../import_controller_status_shared_examples.rb | 22 + .../project_import_rate_limiter_shared_examples.rb | 22 + .../git_http_controller_shared_examples.rb | 25 +- .../snippets_sort_order_shared_examples.rb | 10 +- .../controllers/unique_hll_events_examples.rb | 3 + .../controllers/wiki_actions_shared_examples.rb | 56 +- .../db/seeds/data_seeder_shared_examples.rb | 111 ++ .../features/2fa_shared_examples.rb | 8 +- .../features/abuse_report_shared_examples.rb | 18 + .../features/access_tokens_shared_examples.rb | 2 +- .../features/confidential_notes_shared_examples.rb | 2 +- .../features/content_editor_shared_examples.rb | 415 ++++-- .../creatable_merge_request_shared_examples.rb | 6 +- .../features/dashboard/sidebar_shared_examples.rb | 11 +- .../features/deploy_token_shared_examples.rb | 8 +- .../editable_merge_request_shared_examples.rb | 16 +- .../features/explore/sidebar_shared_examples.rb | 28 + .../incident_details_routing_shared_examples.rb | 14 +- ...st_slash_command_integration_shared_examples.rb | 2 +- .../issuable_invite_members_shared_examples.rb | 4 +- .../manage_applications_shared_examples.rb | 93 +- ...aster_manages_access_requests_shared_example.rb | 2 +- .../features/milestone_editing_shared_examples.rb | 21 + .../features/packages_shared_examples.rb | 69 +- ...d_branches_access_control_ce_shared_examples.rb | 105 +- .../protected_tags_with_deploy_keys_examples.rb | 61 + .../features/reportable_note_shared_examples.rb | 6 +- .../features/rss_shared_examples.rb | 14 + .../features/runners_shared_examples.rb | 45 +- .../redacted_search_results_shared_examples.rb | 202 +-- .../secure_oauth_authorizations_shared_examples.rb | 2 +- .../trial_email_validation_shared_example.rb | 67 +- .../variable_list_pagination_shared_examples.rb | 66 + .../features/variable_list_shared_examples.rb | 10 +- .../wiki/file_attachments_shared_examples.rb | 2 +- .../user_previews_wiki_changes_shared_examples.rb | 6 +- .../wiki/user_updates_wiki_page_shared_examples.rb | 1 + .../wiki/user_views_wiki_page_shared_examples.rb | 8 +- .../user_views_wiki_sidebar_shared_examples.rb | 38 + .../features/work_items_shared_examples.rb | 265 +++- .../finders/issues_finder_shared_examples.rb | 39 +- .../graphql/members_shared_examples.rb | 12 +- .../graphql/mutation_shared_examples.rb | 4 +- .../members/bulk_update_shared_examples.rb | 123 ++ .../mutations/set_assignees_shared_examples.rb | 10 +- .../graphql/notes_on_noteables_shared_examples.rb | 10 +- ...quick_actions_for_work_items_shared_examples.rb | 195 +++ .../data_transfer_resolver_shared_examples.rb | 23 + .../gitlab_style_deprecations_shared_examples.rb | 6 +- ...ge_request_interactions_type_shared_examples.rb | 5 + .../helpers/callouts_for_web_hooks.rb | 49 + .../integrations/integration_settings_form.rb | 6 +- .../lib/api/ai_workhorse_shared_examples.rb | 43 + .../api/terraform_state_enabled_shared_examples.rb | 29 + .../gitlab/cycle_analytics/deployment_metrics.rb | 9 +- .../cycle_analytics/event_shared_examples.rb | 61 + ...async_constraints_validation_shared_examples.rb | 131 ++ .../database/index_validators_shared_examples.rb | 38 + .../database/schema_objects_shared_examples.rb | 26 + .../database/table_validators_shared_examples.rb | 84 ++ .../database/trigger_validators_shared_examples.rb | 33 + .../lib/gitlab/gitaly_client_shared_examples.rb | 10 +- .../lib/gitlab/json_logger_shared_examples.rb | 29 + ...and_remote_storage_migration_shared_examples.rb | 4 +- .../project_search_results_shared_examples.rb | 14 +- .../lib/gitlab/repo_type_shared_examples.rb | 2 +- .../search_language_filter_shared_examples.rb | 25 - .../sidekiq_middleware/strategy_shared_examples.rb | 6 +- .../issuable_activity_shared_examples.rb | 28 +- ...username_and_email_generator_shared_examples.rb | 104 ++ .../shared_examples/lib/menus_shared_examples.rb | 55 + .../lib/sentry/client_shared_examples.rb | 6 +- .../admin/menus/admin_menus_shared_examples.rb | 78 ++ .../user_profile_menus_shared_examples.rb | 93 ++ .../menus/user_settings_menus_shared_examples.rb | 52 + .../mailers/export_csv_shared_examples.rb | 37 + .../mailers/notify_shared_examples.rb | 16 +- .../metrics_instrumentation_shared_examples.rb | 44 + .../add_work_item_widget_shared_examples.rb | 33 + .../models/active_record_enum_shared_examples.rb | 10 + .../models/chat_integration_shared_examples.rb | 28 +- .../models/ci/token_format_shared_examples.rb | 29 + .../models/clusters/prometheus_client_shared.rb | 10 +- .../auto_disabling_hooks_shared_examples.rb | 114 +- .../cascading_namespace_setting_shared_examples.rb | 84 +- .../concerns/counter_attribute_shared_examples.rb | 61 +- .../base_slack_notification_shared_examples.rb | 1 - .../slack_mattermost_notifier_shared_examples.rb | 40 +- .../concerns/protected_branch_access_examples.rb | 19 + ...ed_ref_access_allowed_access_levels_examples.rb | 36 + .../concerns/protected_ref_access_examples.rb | 106 ++ .../concerns/protected_tag_access_examples.rb | 21 + .../models/concerns/timebox_shared_examples.rb | 9 +- .../concerns/unstoppable_hooks_shared_examples.rb | 14 +- .../web_hooks/has_web_hooks_shared_examples.rb | 4 +- .../cycle_analytics_stage_shared_examples.rb | 9 +- .../database_event_tracking_shared_examples.rb | 56 + .../diff_note_after_commit_shared_examples.rb | 10 +- .../base_slash_commands_shared_examples.rb | 3 +- .../issue_tracker_service_shared_examples.rb | 10 +- .../models/member_shared_examples.rb | 48 +- .../models/members_notifications_shared_example.rb | 2 +- .../debian/component_file_shared_example.rb | 21 +- .../debian/distribution_shared_examples.rb | 265 ++-- .../project_ci_cd_settings_shared_examples.rb | 4 +- .../models/resource_event_shared_examples.rb | 40 +- .../shared_examples/models/wiki_shared_examples.rb | 49 + .../observability/csp_shared_examples.rb | 25 +- .../embed_observabilities_examples.rb | 61 + .../policies/project_policy_shared_examples.rb | 21 + .../cleanup_tags_service_shared_examples.rb | 60 +- .../additional_metrics_shared_examples.rb | 161 +++ .../access_control_ce_shared_examples.rb | 32 + .../issuable/close_quick_action_shared_examples.rb | 2 +- .../issuable/max_issuable_examples.rb | 20 +- .../issue_links_quick_actions_shared_examples.rb | 123 ++ ...ote_to_incident_quick_action_shared_examples.rb | 6 +- .../redis/redis_new_instance_shared_examples.rb | 84 ++ .../shared_examples/redis/redis_shared_examples.rb | 429 +++++++ .../access_tokens_controller_shared_examples.rb | 2 +- .../requests/admin_mode_shared_examples.rb | 111 +- .../api/container_repositories_shared_examples.rb | 4 +- .../api/custom_attributes_shared_examples.rb | 36 +- .../api/debian_packages_shared_examples.rb | 38 + .../requests/api/discussions_shared_examples.rb | 15 +- .../api/graphql/issue_list_shared_examples.rb | 3 +- .../graphql/mutations/snippets_shared_examples.rb | 2 +- .../mutations/subscription_shared_examples.rb | 6 +- ...up_and_project_packages_list_shared_examples.rb | 4 +- .../packages/package_details_shared_examples.rb | 2 +- .../access_level_request_examples.rb | 16 +- .../requests/api/hooks_shared_examples.rb | 100 +- ...rprise_jira_dvcs_end_of_life_shared_examples.rb | 23 + .../slack_request_verification_shared_examples.rb | 70 + .../api/issuable_update_shared_examples.rb | 9 + .../requests/api/labels_api_shared_examples.rb | 2 +- .../requests/api/milestones_shared_examples.rb | 8 +- .../api/ml/mlflow/mlflow_shared_examples.rb | 69 + .../requests/api/notes_shared_examples.rb | 88 +- .../requests/api/npm_packages_shared_examples.rb | 448 ++++--- .../api/npm_packages_tags_shared_examples.rb | 29 +- .../api/nuget_endpoints_shared_examples.rb | 5 + .../requests/api/packages_shared_examples.rb | 46 +- .../pipelines/visibility_table_shared_examples.rb | 4 +- .../requests/api/pypi_packages_shared_examples.rb | 9 +- .../repository_storage_moves_shared_examples.rb | 20 +- .../api/resolvable_discussions_shared_examples.rb | 3 +- .../requests/api/snippets_shared_examples.rb | 27 +- .../requests/api/status_shared_examples.rb | 21 +- .../requests/api/time_tracking_shared_examples.rb | 3 +- .../applications_controller_shared_examples.rb | 30 +- .../requests/graphql_shared_examples.rb | 2 +- .../requests/projects/aws/aws__ff_examples.rb | 18 + .../requests/rack_attack_shared_examples.rb | 4 +- .../requests/self_monitoring_shared_examples.rb | 130 -- .../requests/user_activity_shared_examples.rb | 2 +- .../security_training_providers_importer.rb | 4 +- .../diff_file_entity_shared_examples.rb | 81 +- .../serializers/note_entity_shared_examples.rb | 3 +- .../services/base_helm_service_shared_examples.rb | 22 - .../clusters/create_service_shared_examples.rb | 28 + ...tainer_registry_auth_service_shared_examples.rb | 55 +- .../services/deploy_token_shared_examples.rb | 88 ++ .../services/import_csv_service_shared_examples.rb | 38 + .../services/incident_shared_examples.rb | 2 - ...le_description_quick_actions_shared_examples.rb | 62 + .../issuable_import_csv_service_shared_examples.rb | 107 ++ .../issuable_update_service_shared_examples.rb | 137 ++ .../issuable/update_service_shared_examples.rb | 29 - .../issuable_links/create_links_shared_examples.rb | 6 +- .../move_and_clone_services_shared_examples.rb | 22 + ...igrate_to_ghost_user_service_shared_examples.rb | 89 ++ .../generate_distribution_shared_examples.rb | 141 ++- .../services/packages_shared_examples.rb | 18 +- ...e_repository_storage_service_shared_examples.rb | 29 - .../create_service_shared_examples.rb | 7 +- .../services/service_response_shared_examples.rb | 21 + .../services/snowplow_tracking_shared_examples.rb | 1 - .../widgets/milestone_service_shared_examples.rb | 42 - .../views/pipeline_status_changes_email.rb | 14 +- .../export_and_import_shared_examples.rb | 39 + ...nd_migration_execution_worker_shared_example.rb | 14 +- ..._background_migration_worker_shared_examples.rb | 206 +-- .../workers/self_monitoring_shared_examples.rb | 28 - spec/support/stub_dot_com_check.rb | 20 + spec/support/stub_member_access_level.rb | 46 + spec/support/test_reports/test_reports_helper.rb | 103 -- spec/support/tmpdir.rb | 2 + spec/support/trace/trace_helpers.rb | 29 - spec/support_specs/ability_check_spec.rb | 148 +++ .../capybara_wait_for_all_requests_spec.rb | 61 + .../helpers/keyset_pagination_helpers_spec.rb | 88 ++ .../helpers/migrations_helpers_spec.rb | 38 +- spec/support_specs/matchers/event_store_spec.rb | 2 +- .../matchers/exceed_redis_call_limit_spec.rb | 59 + .../support_specs/stub_member_access_level_spec.rb | 69 + spec/tasks/dev_rake_spec.rb | 4 +- spec/tasks/gettext_rake_spec.rb | 90 +- .../gitlab/background_migrations_rake_spec.rb | 45 +- spec/tasks/gitlab/backup_rake_spec.rb | 98 +- .../db/decomposition/connection_status_spec.rb | 61 + .../rollback/bump_ci_sequences_rake_spec.rb | 8 +- spec/tasks/gitlab/db/lock_writes_rake_spec.rb | 2 +- .../gitlab/db/truncate_legacy_tables_rake_spec.rb | 25 +- spec/tasks/gitlab/db/validate_config_rake_spec.rb | 2 +- spec/tasks/gitlab/db_rake_spec.rb | 227 +++- spec/tasks/gitlab/feature_categories_rake_spec.rb | 2 +- spec/tasks/gitlab/gitaly_rake_spec.rb | 22 +- ...ct_statistics_build_artifacts_size_rake_spec.rb | 41 +- .../security/update_banned_ssh_keys_rake_spec.rb | 2 +- spec/tasks/gitlab/setup_rake_spec.rb | 4 + spec/tasks/gitlab/storage_rake_spec.rb | 2 +- .../danger/analytics_instrumentation_spec.rb | 234 ++++ spec/tooling/danger/database_dictionary_spec.rb | 152 +++ spec/tooling/danger/feature_flag_spec.rb | 22 + spec/tooling/danger/multiversion_spec.rb | 79 ++ spec/tooling/danger/product_intelligence_spec.rb | 223 ---- spec/tooling/danger/project_helper_spec.rb | 162 +-- spec/tooling/danger/sidekiq_args_spec.rb | 125 ++ .../specs/feature_category_suggestion_spec.rb | 99 ++ .../specs/match_with_array_suggestion_spec.rb | 99 ++ .../specs/project_factory_suggestion_spec.rb | 112 ++ spec/tooling/danger/specs_spec.rb | 263 +--- spec/tooling/danger/stable_branch_spec.rb | 41 +- spec/tooling/docs/deprecation_handling_spec.rb | 2 +- spec/tooling/graphql/docs/renderer_spec.rb | 8 +- spec/tooling/lib/tooling/fast_quarantine_spec.rb | 193 +++ spec/tooling/lib/tooling/find_changes_spec.rb | 289 +++++ .../tooling/find_files_using_feature_flags_spec.rb | 122 ++ spec/tooling/lib/tooling/find_tests_spec.rb | 159 +++ spec/tooling/lib/tooling/gettext_extractor_spec.rb | 276 ++++ .../lib/tooling/helpers/file_handler_spec.rb | 127 ++ .../helpers/predictive_tests_helper_spec.rb | 51 + spec/tooling/lib/tooling/kubernetes_client_spec.rb | 376 +++--- spec/tooling/lib/tooling/mappings/base_spec.rb | 44 - .../mappings/graphql_base_type_mappings_spec.rb | 251 ++++ .../mappings/js_to_system_specs_mappings_spec.rb | 109 +- .../mappings/partial_to_views_mappings_spec.rb | 280 ++++ .../tooling/mappings/view_to_js_mappings_spec.rb | 89 +- .../mappings/view_to_system_specs_mappings_spec.rb | 127 ++ .../lib/tooling/parallel_rspec_runner_spec.rb | 96 +- spec/tooling/lib/tooling/predictive_tests_spec.rb | 134 ++ spec/tooling/quality/test_level_spec.rb | 11 +- spec/tooling/rspec_flaky/config_spec.rb | 19 - spec/uploaders/attachment_uploader_spec.rb | 10 +- spec/uploaders/avatar_uploader_spec.rb | 10 +- .../ci/pipeline_artifact_uploader_spec.rb | 6 +- .../dependency_proxy/file_uploader_spec.rb | 9 +- .../design_v432x230_uploader_spec.rb | 14 +- spec/uploaders/external_diff_uploader_spec.rb | 8 +- spec/uploaders/file_uploader_spec.rb | 22 +- spec/uploaders/gitlab_uploader_spec.rb | 17 +- spec/uploaders/job_artifact_uploader_spec.rb | 8 +- spec/uploaders/lfs_object_uploader_spec.rb | 8 +- .../object_storage/cdn/google_cdn_spec.rb | 13 +- spec/uploaders/object_storage/cdn_spec.rb | 88 +- spec/uploaders/object_storage_spec.rb | 329 ++++- .../packages/composer/cache_uploader_spec.rb | 8 +- .../debian/component_file_uploader_spec.rb | 12 +- .../distribution_release_file_uploader_spec.rb | 12 +- .../packages/npm/metadata_cache_uploader_spec.rb | 34 + .../packages/package_file_uploader_spec.rb | 8 +- .../packages/rpm/repository_file_uploader_spec.rb | 8 +- spec/uploaders/pages/deployment_uploader_spec.rb | 6 +- spec/uploaders/personal_file_uploader_spec.rb | 10 +- spec/validators/addressable_url_validator_spec.rb | 70 +- .../application_settings/_ci_cd.html.haml_spec.rb | 5 +- .../_repository_check.html.haml_spec.rb | 13 +- .../application_settings/ci_cd.html.haml_spec.rb | 5 +- .../application_settings/network.html.haml_spec.rb | 21 + spec/views/admin/groups/_form.html.haml_spec.rb | 42 + spec/views/admin/projects/_form.html.haml_spec.rb | 41 + spec/views/admin/sessions/new.html.haml_spec.rb | 4 +- .../admin/sessions/two_factor.html.haml_spec.rb | 10 +- spec/views/ci/status/_badge.html.haml_spec.rb | 10 +- spec/views/ci/status/_icon.html.haml_spec.rb | 10 +- .../confirmations/almost_there.html.haml_spec.rb | 17 +- spec/views/devise/sessions/new.html.haml_spec.rb | 97 +- .../shared/_error_messages.html.haml_spec.rb | 43 + .../devise/shared/_signup_box.html.haml_spec.rb | 11 +- spec/views/events/event/_common.html.haml_spec.rb | 15 +- spec/views/groups/edit.html.haml_spec.rb | 6 +- .../groups/group_members/index.html.haml_spec.rb | 1 - spec/views/groups/packages/index.html.haml_spec.rb | 39 + .../groups/settings/_general.html.haml_spec.rb | 21 + spec/views/groups/show.html.haml_spec.rb | 38 + spec/views/help/index.html.haml_spec.rb | 9 +- spec/views/layouts/_head.html.haml_spec.rb | 2 +- spec/views/layouts/_search.html.haml_spec.rb | 77 -- spec/views/layouts/application.html.haml_spec.rb | 4 - spec/views/layouts/devise.html.haml_spec.rb | 10 +- spec/views/layouts/group.html.haml_spec.rb | 30 + .../layouts/header/_new_dropdown.haml_spec.rb | 27 +- spec/views/layouts/minimal.html.haml_spec.rb | 13 + .../layouts/nav/sidebar/_admin.html.haml_spec.rb | 11 +- .../layouts/nav/sidebar/_project.html.haml_spec.rb | 38 +- spec/views/layouts/project.html.haml_spec.rb | 29 + .../autodevops_disabled_email.text.erb_spec.rb | 14 +- .../import_issues_csv_email.html.haml_spec.rb | 4 +- .../import_work_items_csv_email.html.haml_spec.rb | 133 ++ .../notify/new_achievement_email.html.haml_spec.rb | 26 + .../notify/pipeline_failed_email.text.erb_spec.rb | 14 +- spec/views/profiles/keys/_key.html.haml_spec.rb | 39 +- .../profiles/preferences/show.html.haml_spec.rb | 4 +- spec/views/projects/_home_panel.html.haml_spec.rb | 24 - .../projects/commit/_commit_box.html.haml_spec.rb | 3 +- spec/views/projects/commit/show.html.haml_spec.rb | 13 - spec/views/projects/edit.html.haml_spec.rb | 32 +- spec/views/projects/empty.html.haml_spec.rb | 4 - .../issues/_related_issues.html.haml_spec.rb | 37 + .../projects/merge_requests/edit.html.haml_spec.rb | 78 +- .../projects/packages/index.html.haml_spec.rb | 39 + .../_pipeline_schedule.html.haml_spec.rb | 4 +- .../projects/pipelines/show.html.haml_spec.rb | 19 +- .../project_members/index.html.haml_spec.rb | 1 - .../runners/_project_runners.html.haml_spec.rb | 62 +- .../settings/merge_requests/show.html.haml_spec.rb | 8 +- spec/views/projects/tags/index.html.haml_spec.rb | 4 +- .../registrations/welcome/show.html.haml_spec.rb | 2 +- spec/views/search/_results.html.haml_spec.rb | 6 - spec/views/search/show.html.haml_spec.rb | 6 + spec/views/shared/_label_row.html.haml_spec.rb | 4 +- .../shared/milestones/_issuables.html.haml_spec.rb | 9 +- .../runners/_runner_details.html.haml_spec.rb | 49 +- spec/workers/admin_email_worker_spec.rb | 2 +- .../usage_trends/count_job_trigger_worker_spec.rb | 2 +- .../usage_trends/counter_job_worker_spec.rb | 2 +- ...e_blocked_pending_approval_users_worker_spec.rb | 2 +- spec/workers/authorized_keys_worker_spec.rb | 2 +- .../periodic_recalculate_worker_spec.rb | 2 +- .../project_recalculate_per_user_worker_spec.rb | 2 +- .../project_recalculate_worker_spec.rb | 2 +- .../user_refresh_from_replica_worker_spec.rb | 2 +- .../user_refresh_over_user_range_worker_spec.rb | 6 +- .../user_refresh_with_low_urgency_worker_spec.rb | 2 +- spec/workers/authorized_projects_worker_spec.rb | 2 +- spec/workers/auto_devops/disable_worker_spec.rb | 2 +- spec/workers/auto_merge_process_worker_spec.rb | 2 +- .../ci_database_worker_spec.rb | 6 +- spec/workers/background_migration_worker_spec.rb | 2 +- spec/workers/build_hooks_worker_spec.rb | 6 +- spec/workers/build_queue_worker_spec.rb | 6 +- spec/workers/build_success_worker_spec.rb | 2 +- spec/workers/bulk_imports/entity_worker_spec.rb | 2 +- .../bulk_imports/export_request_worker_spec.rb | 2 +- .../finish_batched_relation_export_worker_spec.rb | 80 ++ .../relation_batch_export_worker_spec.rb | 26 + .../bulk_imports/relation_export_worker_spec.rb | 65 +- .../bulk_imports/stuck_import_worker_spec.rb | 2 +- spec/workers/chat_notification_worker_spec.rb | 2 +- spec/workers/ci/archive_trace_worker_spec.rb | 2 +- spec/workers/ci/archive_traces_cron_worker_spec.rb | 14 - spec/workers/ci/build_finished_worker_spec.rb | 2 +- spec/workers/ci/build_prepare_worker_spec.rb | 2 +- spec/workers/ci/build_schedule_worker_spec.rb | 2 +- .../ci/build_trace_chunk_flush_worker_spec.rb | 2 +- spec/workers/ci/cancel_pipeline_worker_spec.rb | 2 +- .../create_cross_project_pipeline_worker_spec.rb | 37 - .../ci/create_downstream_pipeline_worker_spec.rb | 2 +- ...daily_build_group_report_results_worker_spec.rb | 2 +- spec/workers/ci/delete_objects_worker_spec.rb | 2 +- spec/workers/ci/delete_unit_tests_worker_spec.rb | 2 +- spec/workers/ci/drop_pipeline_worker_spec.rb | 2 +- .../expire_project_build_artifacts_worker_spec.rb | 2 +- .../track_artifact_report_worker_spec.rb | 5 +- .../add_todo_when_build_fails_worker_spec.rb | 2 +- .../ci/parse_secure_file_metadata_worker_spec.rb | 2 +- .../ci/pending_builds/update_group_worker_spec.rb | 2 +- .../pending_builds/update_project_worker_spec.rb | 2 +- .../coverage_report_worker_spec.rb | 2 +- .../create_quality_report_worker_spec.rb | 2 +- .../expire_artifacts_worker_spec.rb | 2 +- .../ci/pipeline_bridge_status_worker_spec.rb | 2 +- ...ipeline_success_unlock_artifacts_worker_spec.rb | 2 +- .../ci/ref_delete_unlock_artifacts_worker_spec.rb | 2 +- ...ign_resource_from_resource_group_worker_spec.rb | 2 +- spec/workers/ci/retry_pipeline_worker_spec.rb | 2 +- .../stale_machines_cleanup_cron_worker_spec.rb | 18 +- .../ci/schedule_delete_objects_cron_worker_spec.rb | 2 +- .../ci/stuck_builds/drop_running_worker_spec.rb | 2 +- .../ci/stuck_builds/drop_scheduled_worker_spec.rb | 2 +- .../workers/ci/test_failure_history_worker_spec.rb | 2 +- spec/workers/ci/track_failed_build_worker_spec.rb | 2 +- .../update_locked_unknown_artifacts_worker_spec.rb | 2 +- .../ci_platform_metrics_update_cron_worker_spec.rb | 2 +- .../cleanup_container_repository_worker_spec.rb | 2 +- .../agents/delete_expired_events_worker_spec.rb | 2 +- .../clusters/agents/notify_git_push_worker_spec.rb | 41 + .../activate_integration_worker_spec.rb | 2 +- .../deactivate_integration_worker_spec.rb | 2 +- .../cleanup/project_namespace_worker_spec.rb | 3 +- .../cleanup/service_account_worker_spec.rb | 2 +- .../check_prometheus_health_worker_spec.rb | 2 +- spec/workers/concerns/application_worker_spec.rb | 2 +- spec/workers/concerns/cluster_agent_queue_spec.rb | 5 +- spec/workers/concerns/cluster_queue_spec.rb | 21 - spec/workers/concerns/cronjob_queue_spec.rb | 8 +- .../gitlab/github_import/object_importer_spec.rb | 92 +- .../concerns/gitlab/github_import/queue_spec.rb | 18 - .../github_import/rescheduling_methods_spec.rb | 18 +- .../gitlab/github_import/stage_methods_spec.rb | 2 +- .../concerns/gitlab/notify_upon_death_spec.rb | 2 +- .../concerns/limited_capacity/job_tracker_spec.rb | 2 +- .../concerns/limited_capacity/worker_spec.rb | 2 +- .../packages/cleanup_artifact_worker_spec.rb | 2 +- .../concerns/pipeline_background_queue_spec.rb | 21 - spec/workers/concerns/pipeline_queue_spec.rb | 21 - .../concerns/project_import_options_spec.rb | 2 +- spec/workers/concerns/reenqueuer_spec.rb | 2 +- .../concerns/repository_check_queue_spec.rb | 6 +- spec/workers/concerns/waitable_worker_spec.rb | 53 - spec/workers/concerns/worker_attributes_spec.rb | 2 +- spec/workers/concerns/worker_context_spec.rb | 20 +- .../cleanup_container_repository_worker_spec.rb | 30 +- .../container_expiration_policy_worker_spec.rb | 12 +- .../container_registry/cleanup_worker_spec.rb | 73 +- .../delete_container_repository_worker_spec.rb | 2 +- .../migration/enqueuer_worker_spec.rb | 3 +- .../migration/guard_worker_spec.rb | 2 +- .../migration/observer_worker_spec.rb | 2 +- .../record_data_repair_detail_worker_spec.rb | 191 +++ .../counters/cleanup_refresh_worker_spec.rb | 2 +- .../workers/create_commit_signature_worker_spec.rb | 2 +- spec/workers/create_note_diff_file_worker_spec.rb | 2 +- spec/workers/create_pipeline_worker_spec.rb | 2 +- .../ci_database_worker_spec.rb | 3 +- .../batched_background_migration_worker_spec.rb | 2 +- ...espace_mirrors_consistency_check_worker_spec.rb | 2 +- ...roject_mirrors_consistency_check_worker_spec.rb | 2 +- .../drop_detached_partitions_worker_spec.rb | 2 +- .../database/partition_management_worker_spec.rb | 2 +- .../delete_container_repository_worker_spec.rb | 2 +- spec/workers/delete_diff_files_worker_spec.rb | 2 +- spec/workers/delete_merged_branches_worker_spec.rb | 2 +- spec/workers/delete_user_worker_spec.rb | 52 +- .../dependency_proxy/cleanup_blob_worker_spec.rb | 2 +- .../cleanup_dependency_proxy_worker_spec.rb | 2 +- .../cleanup_manifest_worker_spec.rb | 2 +- .../image_ttl_group_policy_worker_spec.rb | 2 +- .../deployments/archive_in_project_worker_spec.rb | 2 +- .../drop_older_deployments_worker_spec.rb | 18 - spec/workers/deployments/hooks_worker_spec.rb | 6 +- .../deployments/link_merge_request_worker_spec.rb | 2 +- .../deployments/update_environment_worker_spec.rb | 2 +- .../copy_design_collection_worker_spec.rb | 2 +- .../design_management/new_version_worker_spec.rb | 10 +- .../destroy_pages_deployments_worker_spec.rb | 2 +- .../detect_repository_languages_worker_spec.rb | 2 +- .../disallow_two_factor_for_group_worker_spec.rb | 2 +- ...isallow_two_factor_for_subgroups_worker_spec.rb | 2 +- spec/workers/email_receiver_worker_spec.rb | 6 +- spec/workers/emails_on_push_worker_spec.rb | 10 +- .../environments/auto_delete_cron_worker_spec.rb | 2 +- .../environments/auto_stop_cron_worker_spec.rb | 2 +- spec/workers/environments/auto_stop_worker_spec.rb | 2 +- .../canary_ingress/update_worker_spec.rb | 2 +- .../error_tracking_issue_link_worker_spec.rb | 2 +- spec/workers/every_sidekiq_worker_spec.rb | 26 +- spec/workers/expire_build_artifacts_worker_spec.rb | 2 +- spec/workers/export_csv_worker_spec.rb | 2 +- ...xternal_service_reactive_caching_worker_spec.rb | 2 +- spec/workers/file_hook_worker_spec.rb | 2 +- .../flush_counter_increments_worker_spec.rb | 2 +- .../github_gists_import/import_gist_worker_spec.rb | 66 +- .../github_import/advance_stage_worker_spec.rb | 2 +- .../attachments/import_issue_worker_spec.rb | 17 +- .../import_merge_request_worker_spec.rb | 17 +- .../attachments/import_note_worker_spec.rb | 3 +- .../attachments/import_release_worker_spec.rb | 3 +- .../import_collaborator_worker_spec.rb | 38 + .../github_import/import_diff_note_worker_spec.rb | 2 +- .../import_issue_event_worker_spec.rb | 2 +- .../github_import/import_issue_worker_spec.rb | 2 +- .../github_import/import_note_worker_spec.rb | 2 +- .../import_protected_branch_worker_spec.rb | 2 +- .../import_pull_request_merged_by_worker_spec.rb | 4 +- .../import_pull_request_review_worker_spec.rb | 4 +- .../import_pull_request_worker_spec.rb | 18 +- .../import_release_attachments_worker_spec.rb | 8 +- .../pull_requests/import_merged_by_worker_spec.rb | 19 + .../import_review_request_worker_spec.rb | 2 +- .../pull_requests/import_review_worker_spec.rb | 19 + .../refresh_import_jid_worker_spec.rb | 2 +- .../stage/finish_import_worker_spec.rb | 2 +- .../stage/import_attachments_worker_spec.rb | 2 +- .../stage/import_base_data_worker_spec.rb | 2 +- .../stage/import_collaborators_worker_spec.rb | 90 ++ .../stage/import_issue_events_worker_spec.rb | 2 +- .../import_issues_and_diff_notes_worker_spec.rb | 2 +- .../stage/import_lfs_objects_worker_spec.rb | 2 +- .../stage/import_notes_worker_spec.rb | 2 +- .../stage/import_protected_branches_worker_spec.rb | 2 +- .../import_pull_requests_merged_by_worker_spec.rb | 4 +- ...rt_pull_requests_review_requests_worker_spec.rb | 2 +- .../import_pull_requests_reviews_worker_spec.rb | 4 +- .../stage/import_pull_requests_worker_spec.rb | 4 +- .../stage/import_repository_worker_spec.rb | 10 +- .../workers/gitlab/import/stuck_import_job_spec.rb | 2 +- .../stuck_project_import_jobs_worker_spec.rb | 2 +- .../gitlab/jira_import/import_issue_worker_spec.rb | 2 +- .../jira_import/stage/finish_import_worker_spec.rb | 2 +- .../stage/import_attachments_worker_spec.rb | 2 +- .../jira_import/stage/import_issues_worker_spec.rb | 2 +- .../jira_import/stage/import_labels_worker_spec.rb | 2 +- .../jira_import/stage/import_notes_worker_spec.rb | 2 +- .../jira_import/stage/start_import_worker_spec.rb | 2 +- .../stuck_jira_import_jobs_worker_spec.rb | 2 +- .../gitlab/phabricator_import/base_worker_spec.rb | 74 -- .../phabricator_import/import_tasks_worker_spec.rb | 16 - .../gitlab_performance_bar_stats_worker_spec.rb | 2 +- spec/workers/gitlab_service_ping_worker_spec.rb | 8 +- spec/workers/gitlab_shell_worker_spec.rb | 2 +- .../create_cloudsql_instance_worker_spec.rb | 2 +- spec/workers/group_destroy_worker_spec.rb | 23 +- spec/workers/group_export_worker_spec.rb | 2 +- spec/workers/group_import_worker_spec.rb | 2 +- .../groups/update_statistics_worker_spec.rb | 2 +- ...o_factor_requirement_for_members_worker_spec.rb | 2 +- .../workers/hashed_storage/migrator_worker_spec.rb | 2 +- .../hashed_storage/project_migrate_worker_spec.rb | 2 +- .../hashed_storage/project_rollback_worker_spec.rb | 2 +- .../hashed_storage/rollbacker_worker_spec.rb | 2 +- spec/workers/import_issues_csv_worker_spec.rb | 2 +- .../add_severity_system_note_worker_spec.rb | 2 +- .../close_incident_worker_spec.rb | 4 +- .../pager_duty/process_incident_worker_spec.rb | 2 +- .../process_alert_worker_v2_spec.rb | 2 +- .../create_external_cross_reference_worker_spec.rb | 2 +- spec/workers/integrations/execute_worker_spec.rb | 2 +- spec/workers/integrations/irker_worker_spec.rb | 13 +- .../integrations/slack_event_worker_spec.rb | 129 ++ .../invalid_gpg_signature_update_worker_spec.rb | 2 +- .../issuable/label_links_destroy_worker_spec.rb | 2 +- spec/workers/issuable_export_csv_worker_spec.rb | 49 +- .../clear_groups_issue_counter_worker_spec.rb | 2 +- spec/workers/issue_due_scheduler_worker_spec.rb | 2 +- spec/workers/issues/close_worker_spec.rb | 2 +- spec/workers/issues/placement_worker_spec.rb | 2 +- spec/workers/issues/rebalancing_worker_spec.rb | 2 +- ...eschedule_stuck_issue_rebalances_worker_spec.rb | 2 +- .../jira_connect/forward_event_worker_spec.rb | 2 +- .../jira_connect/retry_request_worker_spec.rb | 2 +- .../jira_connect/sync_branch_worker_spec.rb | 6 +- .../jira_connect/sync_builds_worker_spec.rb | 6 +- .../jira_connect/sync_deployments_worker_spec.rb | 6 +- .../jira_connect/sync_feature_flags_worker_spec.rb | 6 +- .../jira_connect/sync_merge_request_worker_spec.rb | 35 +- .../jira_connect/sync_project_worker_spec.rb | 60 +- .../loose_foreign_keys/cleanup_worker_spec.rb | 2 +- .../mail_scheduler/issue_due_worker_spec.rb | 2 +- .../notification_service_worker_spec.rb | 2 +- ...ember_invitation_reminder_emails_worker_spec.rb | 2 +- .../unassign_issuables_worker_spec.rb | 2 +- .../merge_request_cleanup_refs_worker_spec.rb | 8 +- ...merge_request_mergeability_check_worker_spec.rb | 2 +- .../merge_requests/close_issue_worker_spec.rb | 2 +- .../create_approval_event_worker_spec.rb | 2 +- .../create_approval_note_worker_spec.rb | 2 +- .../delete_source_branch_worker_spec.rb | 16 +- .../execute_approval_hooks_worker_spec.rb | 2 +- .../handle_assignees_change_worker_spec.rb | 2 +- .../resolve_todos_after_approval_worker_spec.rb | 2 +- .../merge_requests/resolve_todos_worker_spec.rb | 2 +- .../set_reviewer_reviewed_worker_spec.rb | 57 + .../update_head_pipeline_worker_spec.rb | 40 +- spec/workers/merge_worker_spec.rb | 2 +- .../dashboard/prune_old_annotations_worker_spec.rb | 2 +- .../schedule_annotations_prune_worker_spec.rb | 2 +- .../dashboard/sync_dashboards_worker_spec.rb | 2 +- .../metrics/global_metrics_update_worker_spec.rb | 30 + spec/workers/migrate_external_diffs_worker_spec.rb | 2 +- ...ssociate_ml_candidate_to_package_worker_spec.rb | 105 ++ .../in_product_marketing_emails_worker_spec.rb | 2 +- .../namespaces/process_sync_events_worker_spec.rb | 6 +- .../prune_aggregation_schedules_worker_spec.rb | 5 +- .../namespaces/root_statistics_worker_spec.rb | 12 +- .../namespaces/schedule_aggregation_worker_spec.rb | 4 +- .../update_root_statistics_worker_spec.rb | 2 +- spec/workers/new_issue_worker_spec.rb | 2 +- spec/workers/new_merge_request_worker_spec.rb | 12 - spec/workers/new_note_worker_spec.rb | 2 +- spec/workers/object_pool/create_worker_spec.rb | 2 +- spec/workers/object_pool/destroy_worker_spec.rb | 12 +- spec/workers/object_pool/join_worker_spec.rb | 2 +- .../onboarding/issue_created_worker_spec.rb | 2 +- .../onboarding/pipeline_created_worker_spec.rb | 2 +- spec/workers/onboarding/progress_worker_spec.rb | 2 +- spec/workers/onboarding/user_added_worker_spec.rb | 2 +- .../delete_orphaned_dependencies_worker_spec.rb | 118 ++ .../packages/cleanup/execute_policy_worker_spec.rb | 2 +- .../packages/cleanup_package_file_worker_spec.rb | 2 +- .../cleanup_package_registry_worker_spec.rb | 2 +- .../packages/composer/cache_cleanup_worker_spec.rb | 2 +- .../packages/composer/cache_update_worker_spec.rb | 2 +- .../cleanup_dangling_package_files_worker_spec.rb | 85 ++ .../debian/generate_distribution_worker_spec.rb | 10 +- .../packages/debian/process_changes_worker_spec.rb | 6 +- .../debian/process_package_file_worker_spec.rb | 2 + .../packages/go/sync_packages_worker_spec.rb | 2 +- .../packages/helm/extraction_worker_spec.rb | 2 +- ...rk_package_files_for_destruction_worker_spec.rb | 2 +- .../packages/npm/deprecate_package_worker_spec.rb | 35 + .../packages/nuget/extraction_worker_spec.rb | 27 +- .../packages/rubygems/extraction_worker_spec.rb | 2 +- .../pages_domain_removal_cron_worker_spec.rb | 2 +- .../pages_domain_ssl_renewal_cron_worker_spec.rb | 2 +- .../pages_domain_ssl_renewal_worker_spec.rb | 2 +- .../pages_domain_verification_cron_worker_spec.rb | 2 +- .../pages_domain_verification_worker_spec.rb | 2 +- spec/workers/pages_worker_spec.rb | 2 +- spec/workers/partition_creation_worker_spec.rb | 2 +- .../expired_notification_worker_spec.rb | 2 +- .../personal_access_tokens/expiring_worker_spec.rb | 2 +- spec/workers/pipeline_hooks_worker_spec.rb | 6 +- spec/workers/pipeline_metrics_worker_spec.rb | 22 +- spec/workers/pipeline_notification_worker_spec.rb | 2 +- spec/workers/pipeline_process_worker_spec.rb | 10 +- spec/workers/post_receive_spec.rb | 3 +- spec/workers/process_commit_worker_spec.rb | 14 +- spec/workers/project_cache_worker_spec.rb | 11 +- spec/workers/project_destroy_worker_spec.rb | 25 +- spec/workers/project_export_worker_spec.rb | 2 +- spec/workers/projects/after_import_worker_spec.rb | 2 +- ...alize_project_statistics_refresh_worker_spec.rb | 2 +- .../create_relation_exports_worker_spec.rb | 67 + .../import_export/relation_export_worker_spec.rb | 49 +- .../wait_relation_exports_worker_spec.rb | 123 ++ .../inactive_projects_deletion_cron_worker_spec.rb | 28 +- ...e_projects_deletion_notification_worker_spec.rb | 11 +- spec/workers/projects/post_creation_worker_spec.rb | 2 +- .../projects/process_sync_events_worker_spec.rb | 6 +- .../record_target_platforms_worker_spec.rb | 69 +- ..._build_artifacts_size_statistics_worker_spec.rb | 2 +- ...dule_bulk_repository_shard_moves_worker_spec.rb | 2 +- ..._build_artifacts_size_statistics_worker_spec.rb | 2 +- .../update_repository_storage_worker_spec.rb | 2 +- .../propagate_integration_group_worker_spec.rb | 2 +- ...e_integration_inherit_descendant_worker_spec.rb | 2 +- .../propagate_integration_inherit_worker_spec.rb | 2 +- spec/workers/propagate_integration_worker_spec.rb | 2 +- spec/workers/prune_old_events_worker_spec.rb | 14 +- .../purge_dependency_proxy_cache_worker_spec.rb | 2 +- spec/workers/reactive_caching_worker_spec.rb | 2 +- spec/workers/rebase_worker_spec.rb | 14 +- .../releases/create_evidence_worker_spec.rb | 2 +- .../releases/manage_evidence_worker_spec.rb | 2 +- .../remote_mirror_notification_worker_spec.rb | 8 +- .../remove_expired_group_links_worker_spec.rb | 2 +- spec/workers/remove_expired_members_worker_spec.rb | 17 +- ...remove_unaccepted_member_invites_worker_spec.rb | 58 +- .../remove_unreferenced_lfs_objects_worker_spec.rb | 16 +- spec/workers/repository_check/batch_worker_spec.rb | 2 +- spec/workers/repository_check/clear_worker_spec.rb | 2 +- .../repository_check/dispatch_worker_spec.rb | 2 +- .../single_repository_worker_spec.rb | 2 +- spec/workers/repository_cleanup_worker_spec.rb | 2 +- spec/workers/repository_fork_worker_spec.rb | 2 +- .../repository_update_remote_mirror_worker_spec.rb | 20 +- spec/workers/run_pipeline_schedule_worker_spec.rb | 8 +- ...edule_merge_request_cleanup_refs_worker_spec.rb | 2 +- .../schedule_migrate_external_diffs_worker_spec.rb | 2 +- .../self_monitoring_project_create_worker_spec.rb | 16 - .../self_monitoring_project_delete_worker_spec.rb | 19 - .../service_desk_email_receiver_worker_spec.rb | 2 +- ...dule_bulk_repository_shard_moves_worker_spec.rb | 2 +- .../update_repository_storage_worker_spec.rb | 2 +- .../ssh_keys/expired_notification_worker_spec.rb | 3 +- .../expiring_soon_notification_worker_spec.rb | 3 +- .../ssh_keys/update_last_used_at_worker_spec.rb | 23 + spec/workers/stage_update_worker_spec.rb | 2 +- spec/workers/stuck_ci_jobs_worker_spec.rb | 2 +- spec/workers/stuck_export_jobs_worker_spec.rb | 2 +- spec/workers/stuck_merge_jobs_worker_spec.rb | 2 +- spec/workers/system_hook_push_worker_spec.rb | 2 +- .../workers/tasks_to_be_done/create_worker_spec.rb | 2 +- .../terraform/states/destroy_worker_spec.rb | 2 +- .../confidential_issue_worker_spec.rb | 2 +- .../destroyed_designs_worker_spec.rb | 2 +- .../destroyed_issuable_worker_spec.rb | 2 +- .../todos_destroyer/entity_leave_worker_spec.rb | 2 +- .../todos_destroyer/group_private_worker_spec.rb | 2 +- .../private_features_worker_spec.rb | 2 +- .../todos_destroyer/project_private_worker_spec.rb | 2 +- spec/workers/trending_projects_worker_spec.rb | 2 +- .../update_container_registry_info_worker_spec.rb | 2 +- .../update_external_pull_requests_worker_spec.rb | 2 +- ..._head_pipeline_for_merge_request_worker_spec.rb | 14 +- spec/workers/update_highest_role_worker_spec.rb | 2 +- spec/workers/update_merge_requests_worker_spec.rb | 2 +- .../update_project_statistics_worker_spec.rb | 2 +- spec/workers/upload_checksum_worker_spec.rb | 2 +- .../user_status_cleanup/batch_worker_spec.rb | 2 +- .../workers/users/create_statistics_worker_spec.rb | 2 +- .../users/deactivate_dormant_users_worker_spec.rb | 8 +- ...records_to_ghost_user_in_batches_worker_spec.rb | 2 +- spec/workers/web_hook_worker_spec.rb | 6 +- spec/workers/web_hooks/log_destroy_worker_spec.rb | 2 +- .../import_work_items_csv_worker_spec.rb | 44 + .../workers/x509_certificate_revoke_worker_spec.rb | 2 +- spec/workers/x509_issuer_crl_check_worker_spec.rb | 2 +- 6368 files changed, 152435 insertions(+), 79776 deletions(-) delete mode 100644 spec/channels/awareness_channel_spec.rb create mode 100644 spec/controllers/concerns/kas_cookie_spec.rb delete mode 100644 spec/controllers/concerns/redis_tracking_spec.rb delete mode 100644 spec/controllers/import/gitlab_controller_spec.rb delete mode 100644 spec/controllers/import/phabricator_controller_spec.rb create mode 100644 spec/controllers/projects/runner_projects_controller_spec.rb create mode 100644 spec/controllers/projects/work_items_controller_spec.rb create mode 100644 spec/deprecation_warnings.rb delete mode 100644 spec/experiments/require_verification_for_namespace_creation_experiment_spec.rb delete mode 100644 spec/experiments/security_reports_mr_widget_prompt_experiment_spec.rb create mode 100644 spec/factories/abuse/trust_score.rb create mode 100644 spec/factories/achievements/user_achievements.rb delete mode 100644 spec/factories/airflow/dags.rb create mode 100644 spec/factories/bulk_import/batch_trackers.rb create mode 100644 spec/factories/bulk_import/export_batches.rb create mode 100644 spec/factories/ci/catalog/resources.rb create mode 100644 spec/factories/ci/runner_machine_builds.rb delete mode 100644 spec/factories/ci/runner_machines.rb create mode 100644 spec/factories/ci/runner_managers.rb create mode 100644 spec/factories/clusters/agents/authorizations/ci_access/group_authorizations.rb create mode 100644 spec/factories/clusters/agents/authorizations/ci_access/project_authorizations.rb create mode 100644 spec/factories/clusters/agents/authorizations/user_access/group_authorizations.rb create mode 100644 spec/factories/clusters/agents/authorizations/user_access/project_authorizations.rb delete mode 100644 spec/factories/clusters/agents/group_authorizations.rb delete mode 100644 spec/factories/clusters/agents/project_authorizations.rb delete mode 100644 spec/factories/clusters/applications/helm.rb create mode 100644 spec/factories/container_registry/data_repair_detail.rb create mode 100644 spec/factories/design_management/repositories.rb create mode 100644 spec/factories/gitlab/database/async_foreign_keys/postgres_async_constraint_validation.rb delete mode 100644 spec/factories/gitlab/database/async_foreign_keys/postgres_async_foreign_key_validation.rb create mode 100644 spec/factories/gitlab/database/background_migration/schema_inconsistencies.rb delete mode 100644 spec/factories/member_roles.rb create mode 100644 spec/factories/merge_requests_diff_llm_summary.rb create mode 100644 spec/factories/notes/notes_metadata.rb create mode 100644 spec/factories/organizations.rb create mode 100644 spec/factories/packages/npm/metadata_cache.rb create mode 100644 spec/factories/resource_events/abuse_report_events.rb create mode 100644 spec/factories/resource_events/issue_assignment_events.rb create mode 100644 spec/factories/resource_events/merge_request_assignment_events.rb create mode 100644 spec/factories/search_index.rb delete mode 100644 spec/factories/serverless/domain.rb delete mode 100644 spec/factories/serverless/domain_cluster.rb create mode 100644 spec/factories/service_desk/custom_email_credential.rb create mode 100644 spec/factories/service_desk/custom_email_verification.rb create mode 100644 spec/factories/slack_integrations.rb delete mode 100644 spec/factories/u2f_registrations.rb create mode 100644 spec/factories/users/banned_users.rb create mode 100644 spec/factories/work_items/resource_link_events.rb create mode 100644 spec/features/admin/broadcast_messages_spec.rb delete mode 100644 spec/features/dashboard/label_filter_spec.rb create mode 100644 spec/features/emails/issues_spec.rb create mode 100644 spec/features/explore/navbar_spec.rb create mode 100644 spec/features/groups/milestones/milestone_editing_spec.rb create mode 100644 spec/features/incidents/user_views_alert_details_spec.rb create mode 100644 spec/features/integrations_settings_spec.rb create mode 100644 spec/features/merge_request/user_sees_real_time_reviewers_spec.rb create mode 100644 spec/features/nav/new_nav_invite_members_spec.rb create mode 100644 spec/features/nav/pinned_nav_items_spec.rb create mode 100644 spec/features/profiles/list_users_comment_template_spec.rb delete mode 100644 spec/features/profiles/list_users_saved_replies_spec.rb create mode 100644 spec/features/profiles/user_creates_comment_template_spec.rb create mode 100644 spec/features/profiles/user_deletes_comment_template_spec.rb create mode 100644 spec/features/profiles/user_updates_comment_template_spec.rb create mode 100644 spec/features/profiles/user_uses_comment_template_spec.rb create mode 100644 spec/features/projects/commit/user_sees_pipelines_tab_spec.rb create mode 100644 spec/features/projects/integrations/apple_app_store_spec.rb create mode 100644 spec/features/projects/integrations/google_play_spec.rb create mode 100644 spec/features/projects/milestones/milestone_editing_spec.rb create mode 100644 spec/features/projects/work_items/work_item_children_spec.rb create mode 100644 spec/features/projects/work_items/work_item_spec.rb delete mode 100644 spec/features/u2f_spec.rb delete mode 100644 spec/features/work_items/work_item_children_spec.rb delete mode 100644 spec/features/work_items/work_item_spec.rb create mode 100644 spec/finders/achievements/achievements_finder_spec.rb delete mode 100644 spec/finders/clusters/agent_authorizations_finder_spec.rb create mode 100644 spec/finders/clusters/agents/authorizations/ci_access/finder_spec.rb create mode 100644 spec/finders/clusters/agents/authorizations/user_access/finder_spec.rb create mode 100644 spec/finders/data_transfer/group_data_transfer_finder_spec.rb create mode 100644 spec/finders/data_transfer/mocked_transfer_finder_spec.rb create mode 100644 spec/finders/data_transfer/project_data_transfer_finder_spec.rb create mode 100644 spec/finders/groups/accepting_project_creations_finder_spec.rb create mode 100644 spec/finders/groups/accepting_project_imports_finder_spec.rb create mode 100644 spec/finders/groups/accepting_project_shares_finder_spec.rb delete mode 100644 spec/finders/serverless_domain_finder_spec.rb create mode 100644 spec/fixtures/auth_key.p8 create mode 100644 spec/fixtures/diagram.drawio.svg create mode 100644 spec/fixtures/emails/valid_reply_with_references_in_comma.eml create mode 100644 spec/fixtures/lib/gitlab/import_export/complex/tree/project/commit_notes.ndjson create mode 100644 spec/fixtures/lib/gitlab/import_export/complex/tree/project/design_management_repository.ndjson create mode 100644 spec/fixtures/lib/gitlab/import_export/designs/tree/project.json create mode 100644 spec/fixtures/lib/gitlab/import_export/designs/tree/project/issues.ndjson create mode 100644 spec/fixtures/lib/gitlab/import_export/designs/tree/project/project_members.ndjson create mode 100644 spec/fixtures/packages/debian/sample-ddeb_1.2.3~alpha2_amd64.ddeb create mode 100644 spec/fixtures/packages/npm/metadata.json create mode 100644 spec/fixtures/packages/npm/payload_with_empty_attachment.json create mode 100644 spec/fixtures/pages_with_custom_root.zip create mode 100644 spec/fixtures/pages_with_custom_root.zip.meta create mode 100644 spec/fixtures/pages_with_custom_root.zip.meta0 create mode 100644 spec/fixtures/service_account.json create mode 100644 spec/fixtures/work_items_invalid_types.csv create mode 100644 spec/fixtures/work_items_missing_header.csv create mode 100644 spec/fixtures/work_items_valid.csv create mode 100644 spec/fixtures/work_items_valid_types.csv create mode 100644 spec/frontend/__helpers__/assert_props.js create mode 100644 spec/frontend/__helpers__/create_mock_source_editor_extension.js create mode 100644 spec/frontend/__helpers__/gon_helper.js delete mode 100644 spec/frontend/__mocks__/mousetrap/index.js create mode 100644 spec/frontend/admin/abuse_report/components/abuse_report_app_spec.js create mode 100644 spec/frontend/admin/abuse_report/components/history_items_spec.js create mode 100644 spec/frontend/admin/abuse_report/components/report_header_spec.js create mode 100644 spec/frontend/admin/abuse_report/components/reported_content_spec.js create mode 100644 spec/frontend/admin/abuse_report/components/user_detail_spec.js create mode 100644 spec/frontend/admin/abuse_report/components/user_details_spec.js create mode 100644 spec/frontend/admin/abuse_report/mock_data.js create mode 100644 spec/frontend/admin/abuse_reports/components/abuse_report_actions_spec.js create mode 100644 spec/frontend/admin/abuse_reports/components/abuse_report_row_spec.js create mode 100644 spec/frontend/admin/abuse_reports/components/abuse_reports_filtered_search_bar_spec.js create mode 100644 spec/frontend/admin/abuse_reports/components/app_spec.js create mode 100644 spec/frontend/admin/abuse_reports/mock_data.js create mode 100644 spec/frontend/admin/abuse_reports/utils_spec.js create mode 100644 spec/frontend/admin/application_settings/network_outbound_spec.js delete mode 100644 spec/frontend/admin/users/components/associations/__snapshots__/associations_list_spec.js.snap delete mode 100644 spec/frontend/airflow/dags/components/dags_spec.js delete mode 100644 spec/frontend/airflow/dags/components/mock_data.js create mode 100644 spec/frontend/alert_spec.js delete mode 100644 spec/frontend/analytics/components/activity_chart_spec.js delete mode 100644 spec/frontend/analytics/cycle_analytics/__snapshots__/total_time_spec.js.snap delete mode 100644 spec/frontend/analytics/cycle_analytics/base_spec.js create mode 100644 spec/frontend/analytics/cycle_analytics/components/__snapshots__/total_time_spec.js.snap create mode 100644 spec/frontend/analytics/cycle_analytics/components/base_spec.js create mode 100644 spec/frontend/analytics/cycle_analytics/components/filter_bar_spec.js create mode 100644 spec/frontend/analytics/cycle_analytics/components/formatted_stage_count_spec.js create mode 100644 spec/frontend/analytics/cycle_analytics/components/path_navigation_spec.js create mode 100644 spec/frontend/analytics/cycle_analytics/components/stage_table_spec.js create mode 100644 spec/frontend/analytics/cycle_analytics/components/total_time_spec.js create mode 100644 spec/frontend/analytics/cycle_analytics/components/value_stream_filters_spec.js create mode 100644 spec/frontend/analytics/cycle_analytics/components/value_stream_metrics_spec.js delete mode 100644 spec/frontend/analytics/cycle_analytics/filter_bar_spec.js delete mode 100644 spec/frontend/analytics/cycle_analytics/formatted_stage_count_spec.js delete mode 100644 spec/frontend/analytics/cycle_analytics/path_navigation_spec.js delete mode 100644 spec/frontend/analytics/cycle_analytics/stage_table_spec.js delete mode 100644 spec/frontend/analytics/cycle_analytics/total_time_spec.js delete mode 100644 spec/frontend/analytics/cycle_analytics/value_stream_filters_spec.js delete mode 100644 spec/frontend/analytics/cycle_analytics/value_stream_metrics_spec.js create mode 100644 spec/frontend/analytics/product_analytics/components/activity_chart_spec.js create mode 100644 spec/frontend/approvals/mock_data.js delete mode 100644 spec/frontend/artifacts/components/app_spec.js delete mode 100644 spec/frontend/artifacts/components/artifact_row_spec.js delete mode 100644 spec/frontend/artifacts/components/artifacts_table_row_details_spec.js delete mode 100644 spec/frontend/artifacts/components/feedback_banner_spec.js delete mode 100644 spec/frontend/artifacts/components/job_artifacts_table_spec.js delete mode 100644 spec/frontend/artifacts/graphql/cache_update_spec.js create mode 100644 spec/frontend/authentication/password/components/password_input_spec.js delete mode 100644 spec/frontend/authentication/u2f/authenticate_spec.js delete mode 100644 spec/frontend/authentication/u2f/mock_u2f_device.js delete mode 100644 spec/frontend/authentication/u2f/register_spec.js delete mode 100644 spec/frontend/authentication/u2f/util_spec.js create mode 100644 spec/frontend/authentication/webauthn/components/registration_spec.js create mode 100644 spec/frontend/blame/streaming/index_spec.js create mode 100644 spec/frontend/ci/artifacts/components/app_spec.js create mode 100644 spec/frontend/ci/artifacts/components/artifact_row_spec.js create mode 100644 spec/frontend/ci/artifacts/components/artifacts_bulk_delete_spec.js create mode 100644 spec/frontend/ci/artifacts/components/artifacts_table_row_details_spec.js create mode 100644 spec/frontend/ci/artifacts/components/feedback_banner_spec.js create mode 100644 spec/frontend/ci/artifacts/components/job_artifacts_table_spec.js create mode 100644 spec/frontend/ci/artifacts/components/job_checkbox_spec.js create mode 100644 spec/frontend/ci/artifacts/graphql/cache_update_spec.js create mode 100644 spec/frontend/ci/pipeline_editor/components/job_assistant_drawer/accordion_items/artifacts_and_cache_item_spec.js create mode 100644 spec/frontend/ci/pipeline_editor/components/job_assistant_drawer/accordion_items/image_item_spec.js create mode 100644 spec/frontend/ci/pipeline_editor/components/job_assistant_drawer/accordion_items/job_setup_item_spec.js create mode 100644 spec/frontend/ci/pipeline_editor/components/job_assistant_drawer/accordion_items/rules_item_spec.js create mode 100644 spec/frontend/ci/pipeline_editor/components/job_assistant_drawer/accordion_items/services_item_spec.js create mode 100644 spec/frontend/ci/runner/admin_register_runner/admin_register_runner_app_spec.js create mode 100644 spec/frontend/ci/runner/components/registration/__snapshots__/utils_spec.js.snap create mode 100644 spec/frontend/ci/runner/components/registration/cli_command_spec.js create mode 100644 spec/frontend/ci/runner/components/registration/platforms_drawer_spec.js create mode 100644 spec/frontend/ci/runner/components/registration/registration_compatibility_alert_spec.js create mode 100644 spec/frontend/ci/runner/components/registration/registration_feedback_banner_spec.js create mode 100644 spec/frontend/ci/runner/components/registration/registration_instructions_spec.js create mode 100644 spec/frontend/ci/runner/components/registration/utils_spec.js create mode 100644 spec/frontend/ci/runner/components/runner_create_form_spec.js create mode 100644 spec/frontend/ci/runner/components/runner_jobs_empty_state_spec.js create mode 100644 spec/frontend/ci/runner/group_new_runner_app/group_new_runner_app_spec.js create mode 100644 spec/frontend/ci/runner/group_register_runner_app/group_register_runner_app_spec.js create mode 100644 spec/frontend/ci/runner/project_new_runner_app/project_new_runner_app_spec.js create mode 100644 spec/frontend/ci/runner/project_register_runner_app/project_register_runner_app_spec.js create mode 100644 spec/frontend/code_review/signals_spec.js create mode 100644 spec/frontend/comment_templates/components/__snapshots__/list_item_spec.js.snap create mode 100644 spec/frontend/comment_templates/components/form_spec.js create mode 100644 spec/frontend/comment_templates/components/list_item_spec.js create mode 100644 spec/frontend/comment_templates/components/list_spec.js create mode 100644 spec/frontend/comment_templates/pages/index_spec.js create mode 100644 spec/frontend/commit/components/signature_badge_spec.js create mode 100644 spec/frontend/commit/components/x509_certificate_details_spec.js delete mode 100644 spec/frontend/content_editor/components/__snapshots__/toolbar_link_button_spec.js.snap delete mode 100644 spec/frontend/content_editor/components/bubble_menus/formatting_bubble_menu_spec.js create mode 100644 spec/frontend/content_editor/components/toolbar_attachment_button_spec.js delete mode 100644 spec/frontend/content_editor/components/toolbar_image_button_spec.js delete mode 100644 spec/frontend/content_editor/components/toolbar_link_button_spec.js delete mode 100644 spec/frontend/content_editor/components/wrappers/label_spec.js create mode 100644 spec/frontend/content_editor/components/wrappers/reference_label_spec.js create mode 100644 spec/frontend/content_editor/components/wrappers/reference_spec.js create mode 100644 spec/frontend/content_editor/extensions/drawio_diagram_spec.js delete mode 100644 spec/frontend/design_management/components/toolbar/__snapshots__/design_navigation_spec.js.snap delete mode 100644 spec/frontend/design_management/components/upload/mock_data/all_versions.js create mode 100644 spec/frontend/design_management/mock_data/project.js create mode 100644 spec/frontend/diffs/components/diff_code_quality_item_spec.js create mode 100644 spec/frontend/diffs/components/shared/__snapshots__/findings_drawer_spec.js.snap create mode 100644 spec/frontend/diffs/components/shared/findings_drawer_spec.js create mode 100644 spec/frontend/diffs/mock_data/findings_drawer.js create mode 100644 spec/frontend/drawio/content_editor_facade_spec.js create mode 100644 spec/frontend/drawio/drawio_editor_spec.js create mode 100644 spec/frontend/drawio/markdown_field_editor_facade_spec.js create mode 100644 spec/frontend/editor/schema/ci/yaml_tests/negative_tests/rules_needs.yml create mode 100644 spec/frontend/editor/schema/ci/yaml_tests/negative_tests/services.yml create mode 100644 spec/frontend/editor/schema/ci/yaml_tests/positive_tests/rules_needs.yml create mode 100644 spec/frontend/editor/schema/ci/yaml_tests/positive_tests/services.yml create mode 100644 spec/frontend/environments/deploy_freeze_alert_spec.js create mode 100644 spec/frontend/environments/environment_details/deployments_table_spec.js create mode 100644 spec/frontend/environments/environment_details/index_spec.js delete mode 100644 spec/frontend/environments/environment_details/page_spec.js create mode 100644 spec/frontend/environments/kubernetes_agent_info_spec.js create mode 100644 spec/frontend/environments/kubernetes_overview_spec.js create mode 100644 spec/frontend/environments/kubernetes_pods_spec.js create mode 100644 spec/frontend/environments/kubernetes_summary_spec.js create mode 100644 spec/frontend/environments/kubernetes_tabs_spec.js create mode 100644 spec/frontend/error_tracking/components/error_details_info_spec.js create mode 100644 spec/frontend/error_tracking/events_tracking_spec.js delete mode 100644 spec/frontend/error_tracking/utils_spec.js create mode 100644 spec/frontend/fixtures/comment_templates.rb create mode 100644 spec/frontend/fixtures/milestones.rb delete mode 100644 spec/frontend/fixtures/saved_replies.rb delete mode 100644 spec/frontend/fixtures/static/search_autocomplete.html create mode 100644 spec/frontend/fixtures/timelogs.rb delete mode 100644 spec/frontend/fixtures/u2f.rb create mode 100644 spec/frontend/fixtures/users.rb delete mode 100644 spec/frontend/flash_spec.js create mode 100644 spec/frontend/google_cloud/aiml/panel_spec.js create mode 100644 spec/frontend/google_cloud/aiml/service_table_spec.js create mode 100644 spec/frontend/groups/settings/components/group_settings_readme_spec.js create mode 100644 spec/frontend/groups/settings/mock_data.js create mode 100644 spec/frontend/ide/lib/languages/codeowners_spec.js create mode 100644 spec/frontend/import/details/components/import_details_app_spec.js create mode 100644 spec/frontend/import/details/components/import_details_table_spec.js create mode 100644 spec/frontend/import/details/mock_data.js create mode 100644 spec/frontend/import_entities/import_projects/components/github_organizations_box_spec.js create mode 100644 spec/frontend/import_entities/import_projects/components/github_status_table_spec.js delete mode 100644 spec/frontend/incidents_settings/components/__snapshots__/incidents_settings_tabs_spec.js.snap create mode 100644 spec/frontend/integrations/edit/components/sections/apple_app_store_spec.js create mode 100644 spec/frontend/integrations/edit/components/sections/google_play_spec.js create mode 100644 spec/frontend/integrations/edit/components/upload_dropzone_field_spec.js create mode 100644 spec/frontend/issues/new/components/type_select_spec.js create mode 100644 spec/frontend/issues/show/components/new_header_actions_popover_spec.js delete mode 100644 spec/frontend/jira_connect/subscriptions/components/sign_in_legacy_button_spec.js create mode 100644 spec/frontend/lib/apollo/indexed_db_persistent_storage_spec.js create mode 100644 spec/frontend/lib/mousetrap_spec.js create mode 100644 spec/frontend/lib/utils/css_utils_spec.js create mode 100644 spec/frontend/lib/utils/datetime/time_spent_utility_spec.js create mode 100644 spec/frontend/lib/utils/error_message_spec.js create mode 100644 spec/frontend/lib/utils/ref_validator_spec.js create mode 100644 spec/frontend/lib/utils/secret_detection_spec.js delete mode 100644 spec/frontend/lib/utils/sticky_spec.js create mode 100644 spec/frontend/lib/utils/tappable_promise_spec.js create mode 100644 spec/frontend/lib/utils/web_ide_navigator_spec.js create mode 100644 spec/frontend/milestones/index_spec.js delete mode 100644 spec/frontend/ml/experiment_tracking/components/__snapshots__/ml_candidate_spec.js.snap create mode 100644 spec/frontend/ml/experiment_tracking/components/delete_button_spec.js delete mode 100644 spec/frontend/ml/experiment_tracking/components/ml_candidate_spec.js delete mode 100644 spec/frontend/ml/experiment_tracking/components/ml_experiment_spec.js create mode 100644 spec/frontend/ml/experiment_tracking/components/model_experiments_header_spec.js create mode 100644 spec/frontend/ml/experiment_tracking/routes/candidates/show/components/candidate_detail_row_spec.js create mode 100644 spec/frontend/ml/experiment_tracking/routes/candidates/show/ml_candidates_show_spec.js create mode 100644 spec/frontend/ml/experiment_tracking/routes/candidates/show/mock_data.js create mode 100644 spec/frontend/ml/experiment_tracking/routes/experiments/show/ml_experiments_show_spec.js create mode 100644 spec/frontend/ml/experiment_tracking/routes/experiments/show/mock_data.js create mode 100644 spec/frontend/notebook/cells/output/dataframe_spec.js create mode 100644 spec/frontend/notebook/cells/output/dataframe_util_spec.js create mode 100644 spec/frontend/notebook/cells/output/error_spec.js create mode 100644 spec/frontend/notes/components/mr_discussion_filter_spec.js create mode 100644 spec/frontend/oauth_application/components/oauth_secret_spec.js create mode 100644 spec/frontend/observability/index_spec.js create mode 100644 spec/frontend/packages_and_registries/container_registry/explorer/components/delete_modal_spec.js delete mode 100644 spec/frontend/packages_and_registries/container_registry/explorer/components/details_page/delete_modal_spec.js delete mode 100644 spec/frontend/packages_and_registries/package_registry/components/details/__snapshots__/package_title_spec.js.snap delete mode 100644 spec/frontend/packages_and_registries/shared/components/package_icon_and_name_spec.js create mode 100644 spec/frontend/pages/admin/jobs/components/cancel_jobs_modal_spec.js create mode 100644 spec/frontend/pages/admin/jobs/components/cancel_jobs_spec.js create mode 100644 spec/frontend/pages/admin/jobs/components/jobs_skeleton_loader_spec.js create mode 100644 spec/frontend/pages/admin/jobs/components/table/admin_job_table_app_spec.js create mode 100644 spec/frontend/pages/admin/jobs/components/table/cells/project_cell_spec.js create mode 100644 spec/frontend/pages/admin/jobs/components/table/cells/runner_cell_spec.js create mode 100644 spec/frontend/pages/admin/jobs/components/table/graphql/cache_config_spec.js delete mode 100644 spec/frontend/pages/admin/jobs/index/components/cancel_jobs_modal_spec.js delete mode 100644 spec/frontend/pages/admin/jobs/index/components/cancel_jobs_spec.js delete mode 100644 spec/frontend/pipelines/components/jobs/utils_spec.js create mode 100644 spec/frontend/pipelines/pipeline_operations_spec.js delete mode 100644 spec/frontend/pipelines/pipelines_actions_spec.js create mode 100644 spec/frontend/pipelines/pipelines_manual_actions_spec.js create mode 100644 spec/frontend/profile/components/activity_calendar_spec.js create mode 100644 spec/frontend/profile/components/user_achievements_spec.js create mode 100644 spec/frontend/profile/mock_data.js create mode 100644 spec/frontend/profile/utils_spec.js create mode 100644 spec/frontend/projects/commit_box/info/init_details_button_spec.js delete mode 100644 spec/frontend/ref/components/__snapshots__/ref_selector_spec.js.snap create mode 100644 spec/frontend/releases/components/tag_create_spec.js create mode 100644 spec/frontend/releases/components/tag_search_spec.js create mode 100644 spec/frontend/repository/components/fork_sync_conflicts_modal_spec.js delete mode 100644 spec/frontend/repository/components/preview/__snapshots__/index_spec.js.snap delete mode 100644 spec/frontend/saved_replies/components/__snapshots__/list_item_spec.js.snap delete mode 100644 spec/frontend/saved_replies/components/list_item_spec.js delete mode 100644 spec/frontend/saved_replies/components/list_spec.js create mode 100644 spec/frontend/scripts/frontend/__fixtures__/locale/de/converted.json create mode 100644 spec/frontend/scripts/frontend/__fixtures__/locale/de/gitlab.po create mode 100644 spec/frontend/scripts/frontend/po_to_json_spec.js create mode 100644 spec/frontend/search/sidebar/components/language_filter_spec.js delete mode 100644 spec/frontend/search/sidebar/components/language_filters_spec.js create mode 100644 spec/frontend/search/sidebar/components/scope_new_navigation_spec.js delete mode 100644 spec/frontend/search_autocomplete_spec.js delete mode 100644 spec/frontend/search_autocomplete_utils_spec.js delete mode 100644 spec/frontend/security_configuration/components/upgrade_banner_spec.js create mode 100644 spec/frontend/security_configuration/constants.js delete mode 100644 spec/frontend/self_monitor/components/__snapshots__/self_monitor_form_spec.js.snap delete mode 100644 spec/frontend/self_monitor/components/self_monitor_form_spec.js delete mode 100644 spec/frontend/self_monitor/store/actions_spec.js delete mode 100644 spec/frontend/self_monitor/store/mutations_spec.js delete mode 100644 spec/frontend/sidebar/components/severity/sidebar_severity_spec.js create mode 100644 spec/frontend/sidebar/components/severity/sidebar_severity_widget_spec.js create mode 100644 spec/frontend/snippets/mock_data.js create mode 100644 spec/frontend/streaming/chunk_writer_spec.js create mode 100644 spec/frontend/streaming/handle_streamed_anchor_link_spec.js create mode 100644 spec/frontend/streaming/html_stream_spec.js create mode 100644 spec/frontend/streaming/rate_limit_stream_requests_spec.js create mode 100644 spec/frontend/streaming/render_balancer_spec.js create mode 100644 spec/frontend/streaming/render_html_streams_spec.js create mode 100644 spec/frontend/super_sidebar/components/context_switcher_spec.js create mode 100644 spec/frontend/super_sidebar/components/context_switcher_toggle_spec.js create mode 100644 spec/frontend/super_sidebar/components/frequent_items_list_spec.js create mode 100644 spec/frontend/super_sidebar/components/global_search/components/global_search_autocomplete_items_spec.js create mode 100644 spec/frontend/super_sidebar/components/global_search/components/global_search_default_items_spec.js create mode 100644 spec/frontend/super_sidebar/components/global_search/components/global_search_scoped_items_spec.js create mode 100644 spec/frontend/super_sidebar/components/global_search/components/global_search_spec.js create mode 100644 spec/frontend/super_sidebar/components/global_search/mock_data.js create mode 100644 spec/frontend/super_sidebar/components/global_search/store/actions_spec.js create mode 100644 spec/frontend/super_sidebar/components/global_search/store/getters_spec.js create mode 100644 spec/frontend/super_sidebar/components/global_search/store/mutations_spec.js create mode 100644 spec/frontend/super_sidebar/components/global_search/utils_spec.js create mode 100644 spec/frontend/super_sidebar/components/groups_list_spec.js create mode 100644 spec/frontend/super_sidebar/components/items_list_spec.js create mode 100644 spec/frontend/super_sidebar/components/menu_section_spec.js create mode 100644 spec/frontend/super_sidebar/components/nav_item_link_spec.js create mode 100644 spec/frontend/super_sidebar/components/nav_item_router_link_spec.js create mode 100644 spec/frontend/super_sidebar/components/nav_item_spec.js create mode 100644 spec/frontend/super_sidebar/components/pinned_section_spec.js create mode 100644 spec/frontend/super_sidebar/components/projects_list_spec.js create mode 100644 spec/frontend/super_sidebar/components/search_results_spec.js create mode 100644 spec/frontend/super_sidebar/components/sidebar_menu_spec.js create mode 100644 spec/frontend/super_sidebar/components/sidebar_peek_behavior_spec.js create mode 100644 spec/frontend/super_sidebar/components/sidebar_portal_spec.js create mode 100644 spec/frontend/super_sidebar/components/super_sidebar_toggle_spec.js create mode 100644 spec/frontend/super_sidebar/components/user_menu_spec.js create mode 100644 spec/frontend/super_sidebar/components/user_name_group_spec.js create mode 100644 spec/frontend/super_sidebar/super_sidebar_collapsed_state_manager_spec.js create mode 100644 spec/frontend/super_sidebar/user_counts_manager_spec.js create mode 100644 spec/frontend/super_sidebar/utils_spec.js create mode 100644 spec/frontend/time_tracking/components/timelog_source_cell_spec.js create mode 100644 spec/frontend/time_tracking/components/timelogs_app_spec.js create mode 100644 spec/frontend/time_tracking/components/timelogs_table_spec.js delete mode 100644 spec/frontend/token_access/opt_in_jwt_spec.js create mode 100644 spec/frontend/validators/length_validator_spec.js create mode 100644 spec/frontend/vue3migration/compiler_spec.js create mode 100644 spec/frontend/vue3migration/components/comments_on_root_level.vue create mode 100644 spec/frontend/vue3migration/components/default_slot_with_comment.vue create mode 100644 spec/frontend/vue3migration/components/key_inside_template.vue create mode 100644 spec/frontend/vue3migration/components/simple.vue create mode 100644 spec/frontend/vue3migration/components/slot_with_comment.vue create mode 100644 spec/frontend/vue3migration/components/slots_with_same_name.vue create mode 100644 spec/frontend/vue3migration/components/v_once_inside_v_if.vue create mode 100644 spec/frontend/vue_compat_test_setup.js delete mode 100644 spec/frontend/vue_shared/alert_details/alert_metrics_spec.js delete mode 100644 spec/frontend/vue_shared/alert_details/router_spec.js delete mode 100644 spec/frontend/vue_shared/components/__snapshots__/file_row_header_spec.js.snap create mode 100644 spec/frontend/vue_shared/components/diff_viewer/utils_spec.js create mode 100644 spec/frontend/vue_shared/components/markdown/comment_templates_dropdown_spec.js create mode 100644 spec/frontend/vue_shared/components/markdown/drawio_toolbar_button_spec.js delete mode 100644 spec/frontend/vue_shared/components/markdown/editor_mode_dropdown_spec.js create mode 100644 spec/frontend/vue_shared/components/markdown/editor_mode_switcher_spec.js create mode 100644 spec/frontend/vue_shared/components/projects_list/projects_list_item_spec.js create mode 100644 spec/frontend/vue_shared/components/projects_list/projects_list_spec.js delete mode 100644 spec/frontend/vue_shared/components/resizable_chart/__snapshots__/resizable_chart_container_spec.js.snap delete mode 100644 spec/frontend/vue_shared/components/resizable_chart/resizable_chart_container_spec.js delete mode 100644 spec/frontend/vue_shared/components/runner_instructions/instructions/__snapshots__/runner_docker_instructions_spec.js.snap delete mode 100644 spec/frontend/vue_shared/components/runner_instructions/instructions/__snapshots__/runner_kubernetes_instructions_spec.js.snap create mode 100644 spec/frontend/vue_shared/components/truncated_text/truncated_text_spec.js delete mode 100644 spec/frontend/work_items/components/notes/activity_filter_spec.js create mode 100644 spec/frontend/work_items/components/notes/work_item_activity_sort_filter_spec.js create mode 100644 spec/frontend/work_items/components/notes/work_item_history_only_filter_note_spec.js create mode 100644 spec/frontend/work_items/components/notes/work_item_notes_activity_header_spec.js create mode 100644 spec/frontend/work_items/components/work_item_award_emoji_spec.js create mode 100644 spec/frontend/work_items/components/work_item_links/work_item_children_wrapper_spec.js create mode 100644 spec/frontend/work_items/components/work_item_todos_spec.js create mode 100644 spec/graphql/mutations/achievements/award_spec.rb create mode 100644 spec/graphql/mutations/achievements/delete_spec.rb create mode 100644 spec/graphql/mutations/achievements/revoke_spec.rb create mode 100644 spec/graphql/mutations/achievements/update_spec.rb delete mode 100644 spec/graphql/mutations/concerns/mutations/finds_by_gid_spec.rb create mode 100644 spec/graphql/mutations/environments/stop_spec.rb create mode 100644 spec/graphql/mutations/members/bulk_update_base_spec.rb create mode 100644 spec/graphql/mutations/work_items/update_spec.rb create mode 100644 spec/graphql/resolvers/achievements/achievements_resolver_spec.rb create mode 100644 spec/graphql/resolvers/ci/inherited_variables_resolver_spec.rb create mode 100644 spec/graphql/resolvers/clusters/agents/authorizations/ci_access_resolver_spec.rb create mode 100644 spec/graphql/resolvers/clusters/agents/authorizations/user_access_resolver_spec.rb create mode 100644 spec/graphql/resolvers/data_transfer/group_data_transfer_resolver_spec.rb create mode 100644 spec/graphql/resolvers/data_transfer/project_data_transfer_resolver_spec.rb delete mode 100644 spec/graphql/resolvers/data_transfer_resolver_spec.rb create mode 100644 spec/graphql/types/achievements/user_achievement_type_spec.rb create mode 100644 spec/graphql/types/ci/catalog/resource_type_spec.rb create mode 100644 spec/graphql/types/ci/inherited_ci_variable_type_spec.rb create mode 100644 spec/graphql/types/ci/job_trace_type_spec.rb create mode 100644 spec/graphql/types/ci/runner_manager_type_spec.rb create mode 100644 spec/graphql/types/clusters/agents/authorizations/ci_access_type_spec.rb create mode 100644 spec/graphql/types/clusters/agents/authorizations/user_access_type_spec.rb create mode 100644 spec/graphql/types/data_transfer/project_data_transfer_type_spec.rb create mode 100644 spec/graphql/types/project_statistics_redirect_type_spec.rb create mode 100644 spec/graphql/types/visibility_pipeline_id_type_enum_spec.rb create mode 100644 spec/graphql/types/work_items/available_export_fields_enum_spec.rb create mode 100644 spec/graphql/types/work_items/widgets/award_emoji_type_spec.rb create mode 100644 spec/graphql/types/work_items/widgets/current_user_todos_input_type_spec.rb create mode 100644 spec/graphql/types/work_items/widgets/current_user_todos_type_spec.rb create mode 100644 spec/graphql/types/work_items/widgets/notifications_type_spec.rb create mode 100644 spec/graphql/types/work_items/widgets/notifications_update_input_type_spec.rb create mode 100644 spec/helpers/abuse_reports_helper_spec.rb create mode 100644 spec/helpers/admin/abuse_reports_helper_spec.rb delete mode 100644 spec/helpers/analytics/cycle_analytics_helper_spec.rb create mode 100644 spec/helpers/ci/catalog/resources_helper_spec.rb create mode 100644 spec/helpers/device_registration_helper_spec.rb create mode 100644 spec/helpers/plan_limits_helper_spec.rb create mode 100644 spec/helpers/projects/settings/branch_rules_helper_spec.rb create mode 100644 spec/helpers/protected_refs_helper_spec.rb create mode 100644 spec/helpers/safe_format_helper_spec.rb create mode 100644 spec/helpers/work_items_helper_spec.rb create mode 100644 spec/initializers/active_record_transaction_observer_spec.rb create mode 100644 spec/initializers/circuitbox_spec.rb create mode 100644 spec/initializers/google_cloud_profiler_spec.rb create mode 100644 spec/initializers/mail_starttls_patch_spec.rb create mode 100644 spec/initializers/safe_session_store_patch_spec.rb delete mode 100644 spec/lib/api/entities/clusters/agent_authorization_spec.rb create mode 100644 spec/lib/api/entities/clusters/agents/authorizations/ci_access_spec.rb create mode 100644 spec/lib/api/entities/project_job_token_scope_spec.rb create mode 100644 spec/lib/api/helpers/internal_helpers_spec.rb create mode 100644 spec/lib/api/helpers/packages/npm_spec.rb create mode 100644 spec/lib/atlassian/jira_issue_key_extractors/branch_spec.rb create mode 100644 spec/lib/banzai/filter/code_language_filter_spec.rb create mode 100644 spec/lib/banzai/filter/markdown_engines/base_spec.rb create mode 100644 spec/lib/banzai/filter/markdown_engines/common_mark_spec.rb create mode 100644 spec/lib/banzai/filter/references/work_item_reference_filter_spec.rb create mode 100644 spec/lib/banzai/filter/timeout_text_pipeline_filter_spec.rb create mode 100644 spec/lib/banzai/reference_parser/work_item_parser_spec.rb delete mode 100644 spec/lib/bulk_imports/features_spec.rb create mode 100644 spec/lib/bulk_imports/projects/pipelines/commit_notes_pipeline_spec.rb create mode 100644 spec/lib/error_tracking/sentry_client/token_spec.rb delete mode 100644 spec/lib/feature_groups/gitlab_team_members_spec.rb create mode 100644 spec/lib/generators/batched_background_migration/batched_background_migration_generator_spec.rb create mode 100644 spec/lib/generators/batched_background_migration/expected_files/my_batched_migration.txt create mode 100644 spec/lib/generators/batched_background_migration/expected_files/my_batched_migration_dictionary_matcher.txt create mode 100644 spec/lib/generators/batched_background_migration/expected_files/my_batched_migration_spec_matcher.txt create mode 100644 spec/lib/generators/batched_background_migration/expected_files/queue_my_batched_migration.txt create mode 100644 spec/lib/generators/batched_background_migration/expected_files/queue_my_batched_migration_spec.txt create mode 100644 spec/lib/gitlab/analytics/cycle_analytics/request_params_spec.rb create mode 100644 spec/lib/gitlab/auth/otp/strategies/duo_auth/manual_otp_spec.rb delete mode 100644 spec/lib/gitlab/auth/u2f_webauthn_converter_spec.rb create mode 100644 spec/lib/gitlab/background_migration/backfill_design_management_repositories_spec.rb delete mode 100644 spec/lib/gitlab/background_migration/backfill_namespace_traversal_ids_children_spec.rb delete mode 100644 spec/lib/gitlab/background_migration/backfill_namespace_traversal_ids_roots_spec.rb create mode 100644 spec/lib/gitlab/background_migration/backfill_partitioned_table_spec.rb create mode 100644 spec/lib/gitlab/background_migration/backfill_prepared_at_merge_requests_spec.rb create mode 100644 spec/lib/gitlab/background_migration/backfill_project_wiki_repositories_spec.rb delete mode 100644 spec/lib/gitlab/background_migration/backfill_upvotes_count_on_issues_spec.rb delete mode 100644 spec/lib/gitlab/background_migration/backfill_user_namespace_spec.rb delete mode 100644 spec/lib/gitlab/background_migration/cleanup_orphaned_lfs_objects_projects_spec.rb create mode 100644 spec/lib/gitlab/background_migration/cleanup_personal_access_tokens_with_nil_expires_at_spec.rb delete mode 100644 spec/lib/gitlab/background_migration/delete_orphaned_deployments_spec.rb create mode 100644 spec/lib/gitlab/background_migration/delete_orphaned_packages_dependencies_spec.rb delete mode 100644 spec/lib/gitlab/background_migration/disable_expiration_policies_linked_to_no_container_images_spec.rb delete mode 100644 spec/lib/gitlab/background_migration/drop_invalid_security_findings_spec.rb delete mode 100644 spec/lib/gitlab/background_migration/drop_invalid_vulnerabilities_spec.rb delete mode 100644 spec/lib/gitlab/background_migration/extract_project_topics_into_separate_table_spec.rb delete mode 100644 spec/lib/gitlab/background_migration/fix_first_mentioned_in_commit_at_spec.rb delete mode 100644 spec/lib/gitlab/background_migration/fix_merge_request_diff_commit_users_spec.rb create mode 100644 spec/lib/gitlab/background_migration/fix_vulnerability_reads_has_issues_spec.rb create mode 100644 spec/lib/gitlab/background_migration/issues_internal_id_scope_updater_spec.rb create mode 100644 spec/lib/gitlab/background_migration/migrate_evidences_for_vulnerability_findings_spec.rb create mode 100644 spec/lib/gitlab/background_migration/migrate_human_user_type_spec.rb create mode 100644 spec/lib/gitlab/background_migration/migrate_links_for_vulnerability_findings_spec.rb delete mode 100644 spec/lib/gitlab/background_migration/migrate_merge_request_diff_commit_users_spec.rb delete mode 100644 spec/lib/gitlab/background_migration/migrate_project_taggings_context_from_tags_to_topics_spec.rb create mode 100644 spec/lib/gitlab/background_migration/migrate_remediations_for_vulnerability_findings_spec.rb delete mode 100644 spec/lib/gitlab/background_migration/migrate_u2f_webauthn_spec.rb delete mode 100644 spec/lib/gitlab/background_migration/move_container_registry_enabled_to_project_feature_spec.rb delete mode 100644 spec/lib/gitlab/background_migration/populate_topics_total_projects_count_cache_spec.rb create mode 100644 spec/lib/gitlab/background_migration/populate_vulnerability_dismissal_fields_spec.rb delete mode 100644 spec/lib/gitlab/background_migration/recalculate_vulnerabilities_occurrences_uuid_spec.rb delete mode 100644 spec/lib/gitlab/background_migration/remove_duplicate_vulnerabilities_findings_spec.rb create mode 100644 spec/lib/gitlab/background_migration/remove_project_group_link_with_missing_groups_spec.rb delete mode 100644 spec/lib/gitlab/background_migration/steal_migrate_merge_request_diff_commit_users_spec.rb delete mode 100644 spec/lib/gitlab/background_migration/update_timelogs_project_id_spec.rb delete mode 100644 spec/lib/gitlab/background_migration/update_users_where_two_factor_auth_required_from_group_spec.rb delete mode 100644 spec/lib/gitlab/bare_repository_import/importer_spec.rb delete mode 100644 spec/lib/gitlab/bare_repository_import/repository_spec.rb create mode 100644 spec/lib/gitlab/cache/client_spec.rb create mode 100644 spec/lib/gitlab/ci/ansi2json/state_spec.rb create mode 100644 spec/lib/gitlab/ci/config/entry/publish_spec.rb create mode 100644 spec/lib/gitlab/ci/config/external/interpolator_spec.rb create mode 100644 spec/lib/gitlab/ci/config/header/input_spec.rb create mode 100644 spec/lib/gitlab/ci/config/header/root_spec.rb create mode 100644 spec/lib/gitlab/ci/config/header/spec_spec.rb create mode 100644 spec/lib/gitlab/ci/config/yaml/result_spec.rb create mode 100644 spec/lib/gitlab/ci/input/arguments/base_spec.rb create mode 100644 spec/lib/gitlab/ci/input/arguments/default_spec.rb create mode 100644 spec/lib/gitlab/ci/input/arguments/options_spec.rb create mode 100644 spec/lib/gitlab/ci/input/arguments/required_spec.rb create mode 100644 spec/lib/gitlab/ci/input/arguments/unknown_spec.rb create mode 100644 spec/lib/gitlab/ci/input/inputs_spec.rb delete mode 100644 spec/lib/gitlab/ci/reports/security/vulnerability_reports_comparer_spec.rb create mode 100644 spec/lib/gitlab/database/async_constraints/migration_helpers_spec.rb create mode 100644 spec/lib/gitlab/database/async_constraints/postgres_async_constraint_validation_spec.rb create mode 100644 spec/lib/gitlab/database/async_constraints/validators/check_constraint_spec.rb create mode 100644 spec/lib/gitlab/database/async_constraints/validators/foreign_key_spec.rb create mode 100644 spec/lib/gitlab/database/async_constraints/validators_spec.rb create mode 100644 spec/lib/gitlab/database/async_constraints_spec.rb delete mode 100644 spec/lib/gitlab/database/async_foreign_keys/foreign_key_validator_spec.rb delete mode 100644 spec/lib/gitlab/database/async_foreign_keys/migration_helpers_spec.rb delete mode 100644 spec/lib/gitlab/database/async_foreign_keys/postgres_async_foreign_key_validation_spec.rb delete mode 100644 spec/lib/gitlab/database/async_foreign_keys_spec.rb create mode 100644 spec/lib/gitlab/database/background_migration/health_status/indicators/patroni_apdex_spec.rb create mode 100644 spec/lib/gitlab/database/load_balancing/logger_spec.rb create mode 100644 spec/lib/gitlab/database/migration_helpers/convert_to_bigint_spec.rb create mode 100644 spec/lib/gitlab/database/migration_helpers/wraparound_vacuum_helpers_spec.rb create mode 100644 spec/lib/gitlab/database/migrations/pg_backend_pid_spec.rb create mode 100644 spec/lib/gitlab/database/migrations/runner_backoff/active_record_mixin_spec.rb create mode 100644 spec/lib/gitlab/database/migrations/runner_backoff/communicator_spec.rb create mode 100644 spec/lib/gitlab/database/migrations/runner_backoff/migration_helpers_spec.rb create mode 100644 spec/lib/gitlab/database/partitioning/ci_sliding_list_strategy_spec.rb delete mode 100644 spec/lib/gitlab/database/partitioning/convert_table_to_first_list_partition_spec.rb create mode 100644 spec/lib/gitlab/database/partitioning/list/convert_table_spec.rb create mode 100644 spec/lib/gitlab/database/partitioning/list/locking_configuration_spec.rb create mode 100644 spec/lib/gitlab/database/pg_depend_spec.rb create mode 100644 spec/lib/gitlab/database/schema_validation/adapters/column_database_adapter_spec.rb create mode 100644 spec/lib/gitlab/database/schema_validation/adapters/column_structure_sql_adapter_spec.rb create mode 100644 spec/lib/gitlab/database/schema_validation/inconsistency_spec.rb delete mode 100644 spec/lib/gitlab/database/schema_validation/index_spec.rb delete mode 100644 spec/lib/gitlab/database/schema_validation/indexes_spec.rb create mode 100644 spec/lib/gitlab/database/schema_validation/runner_spec.rb create mode 100644 spec/lib/gitlab/database/schema_validation/schema_inconsistency_spec.rb create mode 100644 spec/lib/gitlab/database/schema_validation/schema_objects/column_spec.rb create mode 100644 spec/lib/gitlab/database/schema_validation/schema_objects/index_spec.rb create mode 100644 spec/lib/gitlab/database/schema_validation/schema_objects/table_spec.rb create mode 100644 spec/lib/gitlab/database/schema_validation/schema_objects/trigger_spec.rb create mode 100644 spec/lib/gitlab/database/schema_validation/structure_sql_spec.rb create mode 100644 spec/lib/gitlab/database/schema_validation/track_inconsistency_spec.rb create mode 100644 spec/lib/gitlab/database/schema_validation/validators/base_validator_spec.rb create mode 100644 spec/lib/gitlab/database/schema_validation/validators/different_definition_indexes_spec.rb create mode 100644 spec/lib/gitlab/database/schema_validation/validators/different_definition_tables_spec.rb create mode 100644 spec/lib/gitlab/database/schema_validation/validators/different_definition_triggers_spec.rb create mode 100644 spec/lib/gitlab/database/schema_validation/validators/extra_indexes_spec.rb create mode 100644 spec/lib/gitlab/database/schema_validation/validators/extra_table_columns_spec.rb create mode 100644 spec/lib/gitlab/database/schema_validation/validators/extra_tables_spec.rb create mode 100644 spec/lib/gitlab/database/schema_validation/validators/extra_triggers_spec.rb create mode 100644 spec/lib/gitlab/database/schema_validation/validators/missing_indexes_spec.rb create mode 100644 spec/lib/gitlab/database/schema_validation/validators/missing_table_columns_spec.rb create mode 100644 spec/lib/gitlab/database/schema_validation/validators/missing_tables_spec.rb create mode 100644 spec/lib/gitlab/database/schema_validation/validators/missing_triggers_spec.rb delete mode 100644 spec/lib/gitlab/database_importers/instance_administrators/create_group_spec.rb delete mode 100644 spec/lib/gitlab/database_importers/self_monitoring/project/create_service_spec.rb delete mode 100644 spec/lib/gitlab/database_importers/self_monitoring/project/delete_service_spec.rb create mode 100644 spec/lib/gitlab/email/hook/silent_mode_interceptor_spec.rb delete mode 100644 spec/lib/gitlab/email/hook/validate_addresses_interceptor_spec.rb create mode 100644 spec/lib/gitlab/email/incoming_email_spec.rb create mode 100644 spec/lib/gitlab/email/service_desk_email_spec.rb create mode 100644 spec/lib/gitlab/git/blame_mode_spec.rb create mode 100644 spec/lib/gitlab/git/blame_pagination_spec.rb create mode 100644 spec/lib/gitlab/github_import/importer/collaborator_importer_spec.rb create mode 100644 spec/lib/gitlab/github_import/importer/collaborators_importer_spec.rb delete mode 100644 spec/lib/gitlab/github_import/importer/pull_request_merged_by_importer_spec.rb delete mode 100644 spec/lib/gitlab/github_import/importer/pull_request_review_importer_spec.rb create mode 100644 spec/lib/gitlab/github_import/importer/pull_requests/all_merged_by_importer_spec.rb create mode 100644 spec/lib/gitlab/github_import/importer/pull_requests/merged_by_importer_spec.rb create mode 100644 spec/lib/gitlab/github_import/importer/pull_requests/review_importer_spec.rb create mode 100644 spec/lib/gitlab/github_import/importer/pull_requests/reviews_importer_spec.rb delete mode 100644 spec/lib/gitlab/github_import/importer/pull_requests_merged_by_importer_spec.rb delete mode 100644 spec/lib/gitlab/github_import/importer/pull_requests_reviews_importer_spec.rb create mode 100644 spec/lib/gitlab/github_import/project_relation_type_spec.rb create mode 100644 spec/lib/gitlab/github_import/representation/collaborator_spec.rb delete mode 100644 spec/lib/gitlab/gitlab_import/client_spec.rb delete mode 100644 spec/lib/gitlab/gitlab_import/importer_spec.rb delete mode 100644 spec/lib/gitlab/gitlab_import/project_creator_spec.rb create mode 100644 spec/lib/gitlab/graphql/loaders/lazy_relation_loader/registry_spec.rb create mode 100644 spec/lib/gitlab/graphql/loaders/lazy_relation_loader/relation_proxy_spec.rb create mode 100644 spec/lib/gitlab/graphql/loaders/lazy_relation_loader_spec.rb create mode 100644 spec/lib/gitlab/graphql/subscriptions/action_cable_with_load_balancing_spec.rb create mode 100644 spec/lib/gitlab/i18n/pluralization_spec.rb create mode 100644 spec/lib/gitlab/import/errors_spec.rb delete mode 100644 spec/lib/gitlab/import_export/fork_spec.rb delete mode 100644 spec/lib/gitlab/import_export/import_export_equivalence_spec.rb delete mode 100644 spec/lib/gitlab/import_export/json/legacy_reader/file_spec.rb delete mode 100644 spec/lib/gitlab/import_export/json/legacy_reader/hash_spec.rb delete mode 100644 spec/lib/gitlab/import_export/json/legacy_reader/shared_example.rb delete mode 100644 spec/lib/gitlab/import_export/json/legacy_writer_spec.rb delete mode 100644 spec/lib/gitlab/incoming_email_spec.rb create mode 100644 spec/lib/gitlab/kas/user_access_spec.rb delete mode 100644 spec/lib/gitlab/kubernetes/helm/api_spec.rb delete mode 100644 spec/lib/gitlab/kubernetes/helm/pod_spec.rb delete mode 100644 spec/lib/gitlab/kubernetes/helm/v2/base_command_spec.rb delete mode 100644 spec/lib/gitlab/kubernetes/helm/v2/certificate_spec.rb delete mode 100644 spec/lib/gitlab/kubernetes/helm/v2/delete_command_spec.rb delete mode 100644 spec/lib/gitlab/kubernetes/helm/v2/init_command_spec.rb delete mode 100644 spec/lib/gitlab/kubernetes/helm/v2/install_command_spec.rb delete mode 100644 spec/lib/gitlab/kubernetes/helm/v2/patch_command_spec.rb delete mode 100644 spec/lib/gitlab/kubernetes/helm/v2/reset_command_spec.rb delete mode 100644 spec/lib/gitlab/kubernetes/helm/v3/base_command_spec.rb delete mode 100644 spec/lib/gitlab/kubernetes/helm/v3/delete_command_spec.rb delete mode 100644 spec/lib/gitlab/kubernetes/helm/v3/install_command_spec.rb delete mode 100644 spec/lib/gitlab/kubernetes/helm/v3/patch_command_spec.rb create mode 100644 spec/lib/gitlab/loggable_spec.rb create mode 100644 spec/lib/gitlab/metrics/sidekiq_slis_spec.rb create mode 100644 spec/lib/gitlab/pages/random_domain_spec.rb create mode 100644 spec/lib/gitlab/pages/virtual_host_finder_spec.rb create mode 100644 spec/lib/gitlab/patch/node_loader_spec.rb delete mode 100644 spec/lib/gitlab/phabricator_import/cache/map_spec.rb delete mode 100644 spec/lib/gitlab/phabricator_import/conduit/client_spec.rb delete mode 100644 spec/lib/gitlab/phabricator_import/conduit/maniphest_spec.rb delete mode 100644 spec/lib/gitlab/phabricator_import/conduit/response_spec.rb delete mode 100644 spec/lib/gitlab/phabricator_import/conduit/tasks_response_spec.rb delete mode 100644 spec/lib/gitlab/phabricator_import/conduit/user_spec.rb delete mode 100644 spec/lib/gitlab/phabricator_import/conduit/users_response_spec.rb delete mode 100644 spec/lib/gitlab/phabricator_import/importer_spec.rb delete mode 100644 spec/lib/gitlab/phabricator_import/issues/importer_spec.rb delete mode 100644 spec/lib/gitlab/phabricator_import/issues/task_importer_spec.rb delete mode 100644 spec/lib/gitlab/phabricator_import/project_creator_spec.rb delete mode 100644 spec/lib/gitlab/phabricator_import/representation/task_spec.rb delete mode 100644 spec/lib/gitlab/phabricator_import/representation/user_spec.rb delete mode 100644 spec/lib/gitlab/phabricator_import/user_finder_spec.rb delete mode 100644 spec/lib/gitlab/phabricator_import/worker_state_spec.rb delete mode 100644 spec/lib/gitlab/prometheus/queries/knative_invocation_query_spec.rb delete mode 100644 spec/lib/gitlab/rack_attack/instrumented_cache_store_spec.rb create mode 100644 spec/lib/gitlab/rack_attack/store_spec.rb delete mode 100644 spec/lib/gitlab/redis/cluster_rate_limiting_spec.rb create mode 100644 spec/lib/gitlab/redis/feature_flag_spec.rb create mode 100644 spec/lib/gitlab/resource_events/assignment_event_recorder_spec.rb create mode 100644 spec/lib/gitlab/seeders/ci/variables_group_seeder_spec.rb create mode 100644 spec/lib/gitlab/seeders/ci/variables_instance_seeder_spec.rb create mode 100644 spec/lib/gitlab/seeders/ci/variables_project_seeder_spec.rb create mode 100644 spec/lib/gitlab/seeders/project_environment_seeder_spec.rb delete mode 100644 spec/lib/gitlab/serverless/service_spec.rb delete mode 100644 spec/lib/gitlab/service_desk_email_spec.rb delete mode 100644 spec/lib/gitlab/sidekiq_daemon/memory_killer_spec.rb create mode 100644 spec/lib/gitlab/slash_commands/global_slack_handler_spec.rb create mode 100644 spec/lib/gitlab/source_spec.rb create mode 100644 spec/lib/gitlab/spamcheck/result_spec.rb create mode 100644 spec/lib/gitlab/timeless_spec.rb create mode 100644 spec/lib/gitlab/tracking/destinations/database_events_snowplow_spec.rb create mode 100644 spec/lib/gitlab/usage/metrics/instrumentations/count_ci_runners_group_type_active_metric_spec.rb create mode 100644 spec/lib/gitlab/usage/metrics/instrumentations/count_ci_runners_group_type_active_online_metric_spec.rb create mode 100644 spec/lib/gitlab/usage/metrics/instrumentations/count_ci_runners_instance_type_active_metric_spec.rb create mode 100644 spec/lib/gitlab/usage/metrics/instrumentations/count_ci_runners_instance_type_active_online_metric_spec.rb create mode 100644 spec/lib/gitlab/usage/metrics/instrumentations/count_ci_runners_metric_spec.rb create mode 100644 spec/lib/gitlab/usage/metrics/instrumentations/count_ci_runners_project_type_active_metric_spec.rb create mode 100644 spec/lib/gitlab/usage/metrics/instrumentations/count_ci_runners_project_type_active_online_metric_spec.rb create mode 100644 spec/lib/gitlab/usage/metrics/instrumentations/database_mode_spec.rb create mode 100644 spec/lib/gitlab/usage/metrics/instrumentations/edition_metric_spec.rb create mode 100644 spec/lib/gitlab/usage/metrics/instrumentations/gitlab_dedicated_metric_spec.rb create mode 100644 spec/lib/gitlab/usage/metrics/instrumentations/index_inconsistencies_metric_spec.rb create mode 100644 spec/lib/gitlab/usage/metrics/instrumentations/installation_creation_date_approximation_metric_spec.rb create mode 100644 spec/lib/gitlab/usage/metrics/instrumentations/installation_creation_date_metric_spec.rb create mode 100644 spec/lib/gitlab/usage/metrics/instrumentations/installation_type_metric_spec.rb create mode 100644 spec/lib/gitlab/usage/metrics/instrumentations/version_metric_spec.rb create mode 100644 spec/lib/gitlab/usage_data_counters/container_registry_event_counter_spec.rb delete mode 100644 spec/lib/gitlab/usage_data_counters/track_unique_events_spec.rb create mode 100644 spec/lib/gitlab/utils/error_message_spec.rb create mode 100644 spec/lib/gitlab/utils/uniquify_spec.rb create mode 100644 spec/lib/gitlab/utils/username_and_email_generator_spec.rb create mode 100644 spec/lib/gitlab_settings/options_spec.rb create mode 100644 spec/lib/gitlab_settings/settings_spec.rb create mode 100644 spec/lib/object_storage/pending_direct_upload_spec.rb create mode 100644 spec/lib/product_analytics/settings_spec.rb delete mode 100644 spec/lib/product_analytics/tracker_spec.rb create mode 100644 spec/lib/sidebars/admin/menus/abuse_reports_menu_spec.rb create mode 100644 spec/lib/sidebars/admin/menus/admin_overview_menu_spec.rb create mode 100644 spec/lib/sidebars/admin/menus/admin_settings_menu_spec.rb create mode 100644 spec/lib/sidebars/admin/menus/analytics_menu_spec.rb create mode 100644 spec/lib/sidebars/admin/menus/applications_menu_spec.rb create mode 100644 spec/lib/sidebars/admin/menus/ci_cd_menu_spec.rb create mode 100644 spec/lib/sidebars/admin/menus/deploy_keys_menu_spec.rb create mode 100644 spec/lib/sidebars/admin/menus/labels_menu_spec.rb create mode 100644 spec/lib/sidebars/admin/menus/messages_menu_spec.rb create mode 100644 spec/lib/sidebars/admin/menus/monitoring_menu_spec.rb create mode 100644 spec/lib/sidebars/admin/menus/system_hooks_menu_spec.rb create mode 100644 spec/lib/sidebars/admin/panel_spec.rb create mode 100644 spec/lib/sidebars/concerns/super_sidebar_panel_spec.rb delete mode 100644 spec/lib/sidebars/groups/menus/invite_team_members_menu_spec.rb create mode 100644 spec/lib/sidebars/groups/super_sidebar_menus/analyze_menu_spec.rb create mode 100644 spec/lib/sidebars/groups/super_sidebar_menus/build_menu_spec.rb create mode 100644 spec/lib/sidebars/groups/super_sidebar_menus/manage_menu_spec.rb create mode 100644 spec/lib/sidebars/groups/super_sidebar_menus/monitor_menu_spec.rb create mode 100644 spec/lib/sidebars/groups/super_sidebar_menus/operations_menu_spec.rb create mode 100644 spec/lib/sidebars/groups/super_sidebar_menus/plan_menu_spec.rb create mode 100644 spec/lib/sidebars/groups/super_sidebar_menus/secure_menu_spec.rb create mode 100644 spec/lib/sidebars/groups/super_sidebar_panel_spec.rb delete mode 100644 spec/lib/sidebars/projects/menus/invite_team_members_menu_spec.rb create mode 100644 spec/lib/sidebars/projects/super_sidebar_menus/analyze_menu_spec.rb create mode 100644 spec/lib/sidebars/projects/super_sidebar_menus/build_menu_spec.rb create mode 100644 spec/lib/sidebars/projects/super_sidebar_menus/code_menu_spec.rb create mode 100644 spec/lib/sidebars/projects/super_sidebar_menus/manage_menu_spec.rb create mode 100644 spec/lib/sidebars/projects/super_sidebar_menus/monitor_menu_spec.rb create mode 100644 spec/lib/sidebars/projects/super_sidebar_menus/operations_menu_spec.rb create mode 100644 spec/lib/sidebars/projects/super_sidebar_menus/plan_menu_spec.rb create mode 100644 spec/lib/sidebars/projects/super_sidebar_menus/secure_menu_spec.rb create mode 100644 spec/lib/sidebars/projects/super_sidebar_panel_spec.rb create mode 100644 spec/lib/sidebars/search/panel_spec.rb create mode 100644 spec/lib/sidebars/static_menu_spec.rb create mode 100644 spec/lib/sidebars/uncategorized_menu_spec.rb create mode 100644 spec/lib/sidebars/user_profile/menus/activity_menu_spec.rb create mode 100644 spec/lib/sidebars/user_profile/menus/contributed_projects_menu_spec.rb create mode 100644 spec/lib/sidebars/user_profile/menus/followers_menu_spec.rb create mode 100644 spec/lib/sidebars/user_profile/menus/following_menu_spec.rb create mode 100644 spec/lib/sidebars/user_profile/menus/groups_menu_spec.rb create mode 100644 spec/lib/sidebars/user_profile/menus/overview_menu_spec.rb create mode 100644 spec/lib/sidebars/user_profile/menus/personal_projects_menu_spec.rb create mode 100644 spec/lib/sidebars/user_profile/menus/snippets_menu_spec.rb create mode 100644 spec/lib/sidebars/user_profile/menus/starred_projects_menu_spec.rb create mode 100644 spec/lib/sidebars/user_profile/panel_spec.rb create mode 100644 spec/lib/sidebars/user_settings/menus/access_tokens_menu_spec.rb create mode 100644 spec/lib/sidebars/user_settings/menus/account_menu_spec.rb create mode 100644 spec/lib/sidebars/user_settings/menus/active_sessions_menu_spec.rb create mode 100644 spec/lib/sidebars/user_settings/menus/applications_menu_spec.rb create mode 100644 spec/lib/sidebars/user_settings/menus/authentication_log_menu_spec.rb create mode 100644 spec/lib/sidebars/user_settings/menus/chat_menu_spec.rb create mode 100644 spec/lib/sidebars/user_settings/menus/comment_templates_menu_spec.rb create mode 100644 spec/lib/sidebars/user_settings/menus/emails_menu_spec.rb create mode 100644 spec/lib/sidebars/user_settings/menus/gpg_keys_menu_spec.rb create mode 100644 spec/lib/sidebars/user_settings/menus/notifications_menu_spec.rb create mode 100644 spec/lib/sidebars/user_settings/menus/password_menu_spec.rb create mode 100644 spec/lib/sidebars/user_settings/menus/preferences_menu_spec.rb create mode 100644 spec/lib/sidebars/user_settings/menus/profile_menu_spec.rb create mode 100644 spec/lib/sidebars/user_settings/menus/ssh_keys_menu_spec.rb create mode 100644 spec/lib/sidebars/user_settings/panel_spec.rb create mode 100644 spec/lib/sidebars/your_work/panel_spec.rb create mode 100644 spec/lib/slack/api_spec.rb create mode 100644 spec/lib/slack/block_kit/app_home_opened_spec.rb create mode 100644 spec/lib/slack/block_kit/incident_management/incident_modal_opened_spec.rb create mode 100644 spec/mailers/emails/work_items_spec.rb delete mode 100644 spec/migrations/20210831203408_upsert_base_work_item_types_spec.rb delete mode 100644 spec/migrations/20210902144144_drop_temporary_columns_and_triggers_for_ci_build_needs_spec.rb delete mode 100644 spec/migrations/20210906100316_drop_temporary_columns_and_triggers_for_ci_build_trace_chunks_spec.rb delete mode 100644 spec/migrations/20210906130643_drop_temporary_columns_and_triggers_for_taggings_spec.rb delete mode 100644 spec/migrations/20210907013944_cleanup_bigint_conversion_for_ci_builds_metadata_spec.rb delete mode 100644 spec/migrations/20210907211557_finalize_ci_builds_bigint_conversion_spec.rb delete mode 100644 spec/migrations/20210910194952_update_report_type_for_existing_approval_project_rules_spec.rb delete mode 100644 spec/migrations/20210914095310_cleanup_orphan_project_access_tokens_spec.rb delete mode 100644 spec/migrations/20210915022415_cleanup_bigint_conversion_for_ci_builds_spec.rb delete mode 100644 spec/migrations/20210918201050_remove_old_pending_jobs_for_recalculate_vulnerabilities_occurrences_uuid_spec.rb delete mode 100644 spec/migrations/20210922021816_drop_int4_columns_for_ci_job_artifacts_spec.rb delete mode 100644 spec/migrations/20210922025631_drop_int4_column_for_ci_sources_pipelines_spec.rb delete mode 100644 spec/migrations/20210922082019_drop_int4_column_for_events_spec.rb delete mode 100644 spec/migrations/20210922091402_drop_int4_column_for_push_event_payloads_spec.rb delete mode 100644 spec/migrations/20211006060436_schedule_populate_topics_total_projects_count_cache_spec.rb delete mode 100644 spec/migrations/20211012134316_clean_up_migrate_merge_request_diff_commit_users_spec.rb delete mode 100644 spec/migrations/20211018152654_schedule_remove_duplicate_vulnerabilities_findings3_spec.rb delete mode 100644 spec/migrations/20211028155449_schedule_fix_merge_request_diff_commit_users_migration_spec.rb delete mode 100644 spec/migrations/20211101222614_consume_remaining_user_namespace_jobs_spec.rb delete mode 100644 spec/migrations/20211110143306_add_not_null_constraint_to_security_findings_uuid_spec.rb delete mode 100644 spec/migrations/20211110151350_schedule_drop_invalid_security_findings_spec.rb delete mode 100644 spec/migrations/20211116091751_change_namespace_type_default_to_user_spec.rb delete mode 100644 spec/migrations/20211116111644_schedule_remove_occurrence_pipelines_and_duplicate_vulnerabilities_findings_spec.rb delete mode 100644 spec/migrations/20211117084814_migrate_remaining_u2f_registrations_spec.rb delete mode 100644 spec/migrations/20211126115449_encrypt_static_objects_external_storage_auth_token_spec.rb delete mode 100644 spec/migrations/20211126204445_add_task_to_work_item_types_spec.rb delete mode 100644 spec/migrations/20211130165043_backfill_sequence_column_for_sprints_table_spec.rb create mode 100644 spec/migrations/20230118144623_schedule_migration_for_remediation_spec.rb create mode 100644 spec/migrations/20230125195503_queue_backfill_compliance_violations_spec.rb create mode 100644 spec/migrations/20230130182412_schedule_create_vulnerability_links_migration_spec.rb create mode 100644 spec/migrations/20230202211434_migrate_redis_slot_keys_spec.rb create mode 100644 spec/migrations/20230208125736_schedule_migration_for_links_spec.rb create mode 100644 spec/migrations/20230209222452_schedule_remove_project_group_link_with_missing_groups_spec.rb create mode 100644 spec/migrations/20230214181633_finalize_ci_build_needs_big_int_conversion_spec.rb create mode 100644 spec/migrations/20230220102212_swap_columns_ci_build_needs_big_int_conversion_spec.rb create mode 100644 spec/migrations/20230221093533_add_tmp_partial_index_on_vulnerability_report_types_spec.rb create mode 100644 spec/migrations/20230221214519_remove_incorrectly_onboarded_namespaces_from_onboarding_progress_spec.rb create mode 100644 spec/migrations/20230223065753_finalize_nullify_creator_id_of_orphaned_projects_spec.rb create mode 100644 spec/migrations/20230224085743_update_issues_internal_id_scope_spec.rb create mode 100644 spec/migrations/20230224144233_migrate_evidences_from_raw_metadata_spec.rb create mode 100644 spec/migrations/20230228142350_add_notifications_work_item_widget_spec.rb create mode 100644 spec/migrations/20230302185739_queue_fix_vulnerability_reads_has_issues_spec.rb create mode 100644 spec/migrations/20230302811133_re_migrate_redis_slot_keys_spec.rb create mode 100644 spec/migrations/20230303105806_queue_delete_orphaned_packages_dependencies_spec.rb create mode 100644 spec/migrations/20230309071242_delete_security_policy_bot_users_spec.rb create mode 100644 spec/migrations/20230313142631_backfill_ml_candidates_package_id_spec.rb create mode 100644 spec/migrations/20230313150531_reschedule_migration_for_remediation_spec.rb create mode 100644 spec/migrations/20230314144640_reschedule_migration_for_links_spec.rb create mode 100644 spec/migrations/20230317004428_migrate_daily_redis_hll_events_to_weekly_aggregation_spec.rb create mode 100644 spec/migrations/20230317162059_add_current_user_todos_work_item_widget_spec.rb create mode 100644 spec/migrations/20230321153035_add_package_id_created_at_desc_index_to_package_files_spec.rb create mode 100644 spec/migrations/20230321163947_backfill_ml_candidates_project_id_spec.rb create mode 100644 spec/migrations/20230321170823_backfill_ml_candidates_internal_id_spec.rb create mode 100644 spec/migrations/20230322085041_remove_user_namespace_records_from_vsa_aggregation_spec.rb create mode 100644 spec/migrations/20230322145403_add_project_id_foreign_key_to_packages_npm_metadata_caches_spec.rb create mode 100644 spec/migrations/20230323101138_add_award_emoji_work_item_widget_spec.rb create mode 100644 spec/migrations/20230327103401_queue_migrate_human_user_type_spec.rb create mode 100644 spec/migrations/20230327123333_backfill_product_analytics_data_collector_host_spec.rb create mode 100644 spec/migrations/20230328030101_add_secureflag_training_provider_spec.rb create mode 100644 spec/migrations/20230328100534_truncate_error_tracking_tables_spec.rb create mode 100644 spec/migrations/20230329100222_drop_software_licenses_temp_index_spec.rb create mode 100644 spec/migrations/20230330103104_reschedule_migrate_evidences_spec.rb create mode 100644 spec/migrations/20230403085957_add_tmp_partial_index_on_vulnerability_report_types2_spec.rb create mode 100644 spec/migrations/20230405200858_requeue_backfill_project_wiki_repositories_spec.rb create mode 100644 spec/migrations/20230406121544_queue_backfill_design_management_repositories_spec.rb create mode 100644 spec/migrations/20230411153310_cleanup_bigint_conversion_for_sent_notifications_spec.rb create mode 100644 spec/migrations/20230412141541_reschedule_links_avoiding_duplication_spec.rb create mode 100644 spec/migrations/20230412185837_queue_populate_vulnerability_dismissal_fields_spec.rb create mode 100644 spec/migrations/20230412214119_finalize_encrypt_ci_trigger_token_spec.rb create mode 100644 spec/migrations/20230418215853_add_assignee_widget_to_incidents_spec.rb create mode 100644 spec/migrations/20230419105225_remove_phabricator_from_application_settings_spec.rb create mode 100644 spec/migrations/20230426102200_fix_import_sources_on_application_settings_after_phabricator_removal_spec.rb create mode 100644 spec/migrations/20230428085332_remove_shimo_zentao_integration_records_spec.rb create mode 100644 spec/migrations/20230502102832_schedule_index_to_members_on_source_and_type_and_access_level_spec.rb create mode 100644 spec/migrations/20230502120021_schedule_index_to_project_authorizations_on_project_user_access_level_spec.rb create mode 100644 spec/migrations/20230504084524_remove_gitlab_import_source_spec.rb create mode 100644 spec/migrations/20230508150219_reschedule_evidences_handling_unicode_spec.rb create mode 100644 spec/migrations/20230508175057_backfill_corrected_secure_files_expirations_spec.rb create mode 100644 spec/migrations/20230509131736_add_default_organization_spec.rb create mode 100644 spec/migrations/20230510062502_queue_cleanup_personal_access_tokens_with_nil_expires_at_spec.rb delete mode 100644 spec/migrations/add_open_source_plan_spec.rb create mode 100644 spec/migrations/backfill_current_value_with_progress_work_item_progresses_spec.rb delete mode 100644 spec/migrations/backfill_user_namespace_spec.rb delete mode 100644 spec/migrations/disable_job_token_scope_when_unused_spec.rb create mode 100644 spec/migrations/drop_packages_events_table_spec.rb create mode 100644 spec/migrations/ensure_award_emoji_bigint_backfill_is_finished_for_gitlab_dot_com_spec.rb create mode 100644 spec/migrations/ensure_commit_user_mentions_note_id_bigint_backfill_is_finished_for_gitlab_dot_com_spec.rb create mode 100644 spec/migrations/ensure_design_user_mentions_note_id_bigint_backfill_is_finished_for_gitlab_dot_com_spec.rb create mode 100644 spec/migrations/ensure_epic_user_mentions_bigint_backfill_is_finished_for_gitlab_dot_com_spec.rb create mode 100644 spec/migrations/ensure_issue_user_mentions_bigint_backfill_is_finished_for_gitlab_dot_com_spec.rb create mode 100644 spec/migrations/ensure_merge_request_metrics_id_bigint_backfill_is_finished_for_gitlab_dot_com_spec.rb create mode 100644 spec/migrations/ensure_merge_request_metrics_id_bigint_backfill_is_finished_for_self_hosts_spec.rb create mode 100644 spec/migrations/ensure_mr_user_mentions_note_id_bigint_backfill_is_finished_for_gitlab_dot_com_spec.rb create mode 100644 spec/migrations/ensure_note_diff_files_bigint_backfill_is_finished_for_gitlab_dot_com_spec.rb create mode 100644 spec/migrations/ensure_notes_bigint_backfill_is_finished_for_gitlab_dot_com_spec.rb create mode 100644 spec/migrations/ensure_snippet_user_mentions_bigint_backfill_is_finished_for_gitlab_dot_com_spec.rb create mode 100644 spec/migrations/ensure_suggestions_note_id_bigint_backfill_is_finished_for_gitlab_dot_com_spec.rb create mode 100644 spec/migrations/ensure_system_note_metadata_bigint_backfill_is_finished_for_gitlab_dot_com_spec.rb create mode 100644 spec/migrations/ensure_timelogs_note_id_bigint_backfill_is_finished_for_gitlab_dot_com_spec.rb create mode 100644 spec/migrations/ensure_todos_bigint_backfill_is_finished_for_gitlab_dot_com_spec.rb create mode 100644 spec/migrations/ensure_unique_debian_packages_spec.rb create mode 100644 spec/migrations/ensure_vum_bigint_backfill_is_finished_for_gl_dot_com_spec.rb create mode 100644 spec/migrations/finalize_issues_iid_scoping_to_namespace_spec.rb delete mode 100644 spec/migrations/finalize_traversal_ids_background_migrations_spec.rb create mode 100644 spec/migrations/insert_daily_invites_trial_plan_limits_spec.rb delete mode 100644 spec/migrations/queue_backfill_admin_mode_scope_for_personal_access_tokens_spec.rb create mode 100644 spec/migrations/queue_backfill_prepared_at_data_spec.rb delete mode 100644 spec/migrations/recreate_index_security_ci_builds_on_name_and_id_parser_features_spec.rb delete mode 100644 spec/migrations/remove_invalid_deploy_access_level_spec.rb create mode 100644 spec/migrations/remove_packages_events_package_id_fk_spec.rb create mode 100644 spec/migrations/remove_saml_provider_and_identities_non_root_group_spec.rb delete mode 100644 spec/migrations/remove_schedule_and_status_from_pending_alert_escalations_spec.rb create mode 100644 spec/migrations/remove_scim_token_and_scim_identity_non_root_group_spec.rb create mode 100644 spec/migrations/requeue_backfill_admin_mode_scope_for_personal_access_tokens_spec.rb create mode 100644 spec/migrations/rerun_remove_invalid_deploy_access_level_spec.rb create mode 100644 spec/migrations/reschedule_incident_work_item_type_id_backfill_spec.rb create mode 100644 spec/migrations/schedule_migrate_shared_vulnerability_identifiers_spec.rb delete mode 100644 spec/migrations/schedule_recalculate_vulnerability_finding_signatures_for_findings_spec.rb create mode 100644 spec/migrations/set_email_confirmation_setting_from_soft_email_confirmation_ff_spec.rb delete mode 100644 spec/migrations/slice_merge_request_diff_commit_migrations_spec.rb create mode 100644 spec/migrations/swap_award_emoji_note_id_to_bigint_for_gitlab_dot_com_spec.rb create mode 100644 spec/migrations/swap_commit_user_mentions_note_id_to_bigint_for_gitlab_dot_com_spec.rb create mode 100644 spec/migrations/swap_design_user_mentions_note_id_to_bigint_for_gitlab_dot_com_spec.rb create mode 100644 spec/migrations/swap_epic_user_mentions_note_id_to_bigint_for_gitlab_dot_com_spec.rb create mode 100644 spec/migrations/swap_issue_user_mentions_note_id_to_bigint_for_gitlab_dot_com_2_spec.rb create mode 100644 spec/migrations/swap_merge_request_metrics_id_to_bigint_for_gitlab_dot_com_spec.rb create mode 100644 spec/migrations/swap_merge_request_metrics_id_to_bigint_for_self_hosts_spec.rb create mode 100644 spec/migrations/swap_merge_request_user_mentions_note_id_to_bigint_spec.rb create mode 100644 spec/migrations/swap_note_diff_files_note_id_to_bigint_for_gitlab_dot_com_spec.rb create mode 100644 spec/migrations/swap_sent_notifications_id_columns_spec.rb create mode 100644 spec/migrations/swap_snippet_user_mentions_note_id_to_bigint_for_gitlab_dot_com_spec.rb create mode 100644 spec/migrations/swap_suggestions_note_id_to_bigint_for_gitlab_dot_com_spec.rb create mode 100644 spec/migrations/swap_system_note_metadata_note_id_to_bigint_for_gitlab_dot_com_spec.rb create mode 100644 spec/migrations/swap_timelogs_note_id_to_bigint_for_gitlab_dot_com_spec.rb create mode 100644 spec/migrations/swap_todos_note_id_to_bigint_for_gitlab_dot_com_spec.rb create mode 100644 spec/migrations/swap_vulnerability_user_mentions_note_id_to_bigint_for_gitlab_dot_com_spec.rb create mode 100644 spec/models/abuse/trust_score_spec.rb delete mode 100644 spec/models/airflow/dags_spec.rb delete mode 100644 spec/models/awareness_session_spec.rb create mode 100644 spec/models/bulk_imports/batch_tracker_spec.rb create mode 100644 spec/models/bulk_imports/export_batch_spec.rb create mode 100644 spec/models/ci/catalog/listing_spec.rb create mode 100644 spec/models/ci/catalog/resource_spec.rb delete mode 100644 spec/models/ci/runner_machine_spec.rb create mode 100644 spec/models/ci/runner_manager_build_spec.rb create mode 100644 spec/models/ci/runner_manager_spec.rb create mode 100644 spec/models/clusters/agents/authorizations/ci_access/group_authorization_spec.rb create mode 100644 spec/models/clusters/agents/authorizations/ci_access/implicit_authorization_spec.rb create mode 100644 spec/models/clusters/agents/authorizations/ci_access/project_authorization_spec.rb create mode 100644 spec/models/clusters/agents/authorizations/user_access/group_authorization_spec.rb create mode 100644 spec/models/clusters/agents/authorizations/user_access/project_authorization_spec.rb delete mode 100644 spec/models/clusters/agents/group_authorization_spec.rb delete mode 100644 spec/models/clusters/agents/implicit_authorization_spec.rb delete mode 100644 spec/models/clusters/agents/project_authorization_spec.rb delete mode 100644 spec/models/clusters/applications/crossplane_spec.rb delete mode 100644 spec/models/clusters/applications/helm_spec.rb delete mode 100644 spec/models/clusters/applications/ingress_spec.rb delete mode 100644 spec/models/clusters/applications/jupyter_spec.rb delete mode 100644 spec/models/clusters/applications/knative_spec.rb delete mode 100644 spec/models/clusters/applications/prometheus_spec.rb delete mode 100644 spec/models/clusters/applications/runner_spec.rb delete mode 100644 spec/models/concerns/awareness_spec.rb delete mode 100644 spec/models/concerns/ci/partitionable/partitioned_filter_spec.rb delete mode 100644 spec/models/concerns/clusters/agents/authorization_config_scopes_spec.rb create mode 100644 spec/models/concerns/clusters/agents/authorizations/ci_access/config_scopes_spec.rb create mode 100644 spec/models/concerns/clusters/agents/authorizations/user_access/scopes_spec.rb delete mode 100644 spec/models/concerns/protected_ref_access_spec.rb delete mode 100644 spec/models/concerns/uniquify_spec.rb create mode 100644 spec/models/concerns/web_hooks/has_web_hooks_spec.rb create mode 100644 spec/models/container_registry/data_repair_detail_spec.rb create mode 100644 spec/models/design_management/git_repository_spec.rb create mode 100644 spec/models/integrations/gitlab_slack_application_spec.rb create mode 100644 spec/models/integrations/google_play_spec.rb create mode 100644 spec/models/integrations/slack_workspace/api_scope_spec.rb create mode 100644 spec/models/integrations/squash_tm_spec.rb delete mode 100644 spec/models/members/member_role_spec.rb create mode 100644 spec/models/merge_request/diff_llm_summary_spec.rb create mode 100644 spec/models/notes/note_metadata_spec.rb create mode 100644 spec/models/organization_spec.rb create mode 100644 spec/models/packages/event_spec.rb create mode 100644 spec/models/packages/npm/metadata_cache_spec.rb create mode 100644 spec/models/preloaders/runner_manager_policy_preloader_spec.rb create mode 100644 spec/models/preloaders/users_max_access_level_by_project_preloader_spec.rb delete mode 100644 spec/models/preloaders/users_max_access_level_in_projects_preloader_spec.rb create mode 100644 spec/models/projects/forks/details_spec.rb delete mode 100644 spec/models/projects/forks/divergence_counts_spec.rb create mode 100644 spec/models/resource_events/abuse_report_event_spec.rb create mode 100644 spec/models/resource_events/issue_assignment_event_spec.rb create mode 100644 spec/models/resource_events/merge_request_assignment_event_spec.rb delete mode 100644 spec/models/serverless/domain_cluster_spec.rb delete mode 100644 spec/models/serverless/domain_spec.rb delete mode 100644 spec/models/serverless/function_spec.rb create mode 100644 spec/models/service_desk/custom_email_credential_spec.rb create mode 100644 spec/models/service_desk/custom_email_verification_spec.rb create mode 100644 spec/models/slack_integration_spec.rb delete mode 100644 spec/models/u2f_registration_spec.rb create mode 100644 spec/models/work_items/resource_link_event_spec.rb create mode 100644 spec/models/work_items/widgets/award_emoji_spec.rb create mode 100644 spec/models/work_items/widgets/notifications_spec.rb create mode 100644 spec/policies/abuse_report_policy_spec.rb create mode 100644 spec/policies/achievements/user_achievement_policy_spec.rb create mode 100644 spec/policies/ci/runner_manager_policy_spec.rb create mode 100644 spec/presenters/ml/candidate_details_presenter_spec.rb create mode 100644 spec/presenters/ml/candidates_csv_presenter_spec.rb create mode 100644 spec/rails_autoload.rb create mode 100644 spec/requests/admin/abuse_reports_controller_spec.rb create mode 100644 spec/requests/admin/projects_controller_spec.rb create mode 100644 spec/requests/admin/users_controller_spec.rb create mode 100644 spec/requests/api/graphql/achievements/user_achievements_query_spec.rb create mode 100644 spec/requests/api/graphql/ci/inherited_ci_variables_spec.rb create mode 100644 spec/requests/api/graphql/group/data_transfer_spec.rb delete mode 100644 spec/requests/api/graphql/group/labels_query_spec.rb create mode 100644 spec/requests/api/graphql/mutations/achievements/award_spec.rb create mode 100644 spec/requests/api/graphql/mutations/achievements/delete_spec.rb create mode 100644 spec/requests/api/graphql/mutations/achievements/revoke_spec.rb create mode 100644 spec/requests/api/graphql/mutations/achievements/update_spec.rb create mode 100644 spec/requests/api/graphql/mutations/ci/job/cancel_spec.rb create mode 100644 spec/requests/api/graphql/mutations/ci/job/play_spec.rb create mode 100644 spec/requests/api/graphql/mutations/ci/job/retry_spec.rb create mode 100644 spec/requests/api/graphql/mutations/ci/job/unschedule_spec.rb create mode 100644 spec/requests/api/graphql/mutations/ci/job_artifact/bulk_destroy_spec.rb delete mode 100644 spec/requests/api/graphql/mutations/ci/job_cancel_spec.rb delete mode 100644 spec/requests/api/graphql/mutations/ci/job_play_spec.rb delete mode 100644 spec/requests/api/graphql/mutations/ci/job_retry_spec.rb delete mode 100644 spec/requests/api/graphql/mutations/ci/job_unschedule_spec.rb create mode 100644 spec/requests/api/graphql/mutations/ci/runner/create_spec.rb create mode 100644 spec/requests/api/graphql/mutations/design_management/update_spec.rb create mode 100644 spec/requests/api/graphql/mutations/members/projects/bulk_update_spec.rb create mode 100644 spec/requests/api/graphql/mutations/projects/sync_fork_spec.rb create mode 100644 spec/requests/api/graphql/mutations/work_items/convert_spec.rb create mode 100644 spec/requests/api/graphql/mutations/work_items/export_spec.rb create mode 100644 spec/requests/api/graphql/project/ci_access_authorized_agents_spec.rb create mode 100644 spec/requests/api/graphql/project/commit_references_spec.rb create mode 100644 spec/requests/api/graphql/project/data_transfer_spec.rb create mode 100644 spec/requests/api/graphql/project/flow_metrics_spec.rb create mode 100644 spec/requests/api/graphql/project/project_statistics_redirect_spec.rb create mode 100644 spec/requests/api/graphql/project/user_access_authorized_agents_spec.rb create mode 100644 spec/requests/api/graphql/user/user_achievements_query_spec.rb create mode 100644 spec/requests/api/integrations/slack/events_spec.rb create mode 100644 spec/requests/api/integrations/slack/interactions_spec.rb create mode 100644 spec/requests/api/integrations/slack/options_spec.rb create mode 100644 spec/requests/api/ml/mlflow/experiments_spec.rb create mode 100644 spec/requests/api/ml/mlflow/runs_spec.rb delete mode 100644 spec/requests/api/ml/mlflow_spec.rb create mode 100644 spec/requests/api/project_job_token_scope_spec.rb create mode 100644 spec/requests/groups/achievements_controller_spec.rb create mode 100644 spec/requests/import/github_controller_spec.rb delete mode 100644 spec/requests/jira_connect/users_controller_spec.rb create mode 100644 spec/requests/profiles/comment_templates_controller_spec.rb delete mode 100644 spec/requests/profiles/saved_replies_controller_spec.rb delete mode 100644 spec/requests/projects/airflow/dags_controller_spec.rb create mode 100644 spec/requests/projects/aws/configuration_controller_spec.rb create mode 100644 spec/requests/projects/wikis_controller_spec.rb create mode 100644 spec/requests/registrations_controller_spec.rb delete mode 100644 spec/requests/self_monitoring_project_spec.rb create mode 100644 spec/requests/time_tracking/timelogs_controller_spec.rb create mode 100644 spec/requests/users/pins_spec.rb create mode 100644 spec/routing/directs/subscription_portal_spec.rb create mode 100644 spec/rubocop/cop/background_migration/missing_dictionary_file_spec.rb create mode 100644 spec/rubocop/cop/gettext/static_identifier_spec.rb delete mode 100644 spec/rubocop/cop/gitlab/deprecate_track_redis_hll_event_spec.rb create mode 100644 spec/rubocop/cop/rspec/avoid_conditional_statements_spec.rb delete mode 100644 spec/rubocop/cop/rspec/htt_party_basic_auth_spec.rb create mode 100644 spec/rubocop/cop/rspec/httparty_basic_auth_spec.rb create mode 100644 spec/rubocop/cop/rspec/misspelled_aggregate_failures_spec.rb create mode 100644 spec/rubocop/cop/rspec/shared_groups_metadata_spec.rb delete mode 100644 spec/rubocop/cop/ruby_interpolation_in_translation_spec.rb create mode 100644 spec/rubocop/cop/search/namespaced_class_spec.rb create mode 100644 spec/scripts/api/create_merge_request_discussion_spec.rb create mode 100644 spec/scripts/api/get_package_and_test_job_spec.rb delete mode 100644 spec/scripts/create_pipeline_failure_incident_spec.rb create mode 100644 spec/scripts/database/schema_validator_spec.rb create mode 100644 spec/scripts/generate_failed_package_and_test_mr_message_spec.rb create mode 100644 spec/scripts/generate_rspec_pipeline_spec.rb create mode 100644 spec/scripts/pipeline/create_test_failure_issues_spec.rb create mode 100644 spec/scripts/review_apps/automated_cleanup_spec.rb create mode 100644 spec/serializers/admin/abuse_report_details_entity_spec.rb create mode 100644 spec/serializers/admin/abuse_report_details_serializer_spec.rb create mode 100644 spec/serializers/admin/abuse_report_entity_spec.rb create mode 100644 spec/serializers/admin/abuse_report_serializer_spec.rb delete mode 100644 spec/serializers/cluster_application_entity_spec.rb create mode 100644 spec/serializers/import/github_failure_entity_spec.rb create mode 100644 spec/serializers/import/github_failure_serializer_spec.rb create mode 100644 spec/serializers/profile/event_entity_spec.rb create mode 100644 spec/services/achievements/award_service_spec.rb create mode 100644 spec/services/achievements/destroy_service_spec.rb create mode 100644 spec/services/achievements/revoke_service_spec.rb create mode 100644 spec/services/achievements/update_service_spec.rb create mode 100644 spec/services/admin/abuse_report_update_service_spec.rb create mode 100644 spec/services/bulk_imports/batched_relation_export_service_spec.rb create mode 100644 spec/services/bulk_imports/relation_batch_export_service_spec.rb create mode 100644 spec/services/ci/catalog/validate_resource_service_spec.rb create mode 100644 spec/services/ci/job_artifacts/bulk_delete_by_project_service_spec.rb create mode 100644 spec/services/ci/pipeline_processing/test_cases/dag_test_on_failure_no_needs.yml create mode 100644 spec/services/ci/pipeline_processing/test_cases/stage_build_cancels_test1_and_test2_have_when.yml create mode 100644 spec/services/ci/pipeline_processing/test_cases/stage_build_cancels_with_allow_failure_test1_and_test2_have_when.yml create mode 100644 spec/services/ci/pipeline_processing/test_cases/stage_test_on_failure_no_prev_stage.yml delete mode 100644 spec/services/ci/runners/stale_machines_cleanup_service_spec.rb create mode 100644 spec/services/ci/runners/stale_managers_cleanup_service_spec.rb create mode 100644 spec/services/ci/runners/unregister_runner_manager_service_spec.rb create mode 100644 spec/services/clusters/agent_tokens/revoke_service_spec.rb create mode 100644 spec/services/clusters/agents/authorizations/ci_access/filter_service_spec.rb create mode 100644 spec/services/clusters/agents/authorizations/ci_access/refresh_service_spec.rb create mode 100644 spec/services/clusters/agents/authorizations/user_access/refresh_service_spec.rb create mode 100644 spec/services/clusters/agents/authorize_proxy_user_service_spec.rb delete mode 100644 spec/services/clusters/agents/filter_authorizations_service_spec.rb delete mode 100644 spec/services/clusters/agents/refresh_authorization_service_spec.rb create mode 100644 spec/services/integrations/slack_event_service_spec.rb create mode 100644 spec/services/integrations/slack_events/app_home_opened_service_spec.rb create mode 100644 spec/services/integrations/slack_events/url_verification_service_spec.rb create mode 100644 spec/services/integrations/slack_interaction_service_spec.rb create mode 100644 spec/services/integrations/slack_interactions/block_action_service_spec.rb create mode 100644 spec/services/integrations/slack_interactions/incident_management/incident_modal_closed_service_spec.rb create mode 100644 spec/services/integrations/slack_interactions/incident_management/incident_modal_opened_service_spec.rb create mode 100644 spec/services/integrations/slack_interactions/incident_management/incident_modal_submit_service_spec.rb create mode 100644 spec/services/integrations/slack_interactions/slack_block_actions/incident_management/project_update_handler_spec.rb create mode 100644 spec/services/integrations/slack_option_service_spec.rb create mode 100644 spec/services/integrations/slack_options/label_search_handler_spec.rb create mode 100644 spec/services/integrations/slack_options/user_search_handler_spec.rb create mode 100644 spec/services/issuable/callbacks/milestone_spec.rb create mode 100644 spec/services/issues/base_service_spec.rb create mode 100644 spec/services/issues/issuable_base_service_spec.rb create mode 100644 spec/services/mattermost/create_team_service_spec.rb delete mode 100644 spec/services/metrics/dashboard/self_monitoring_dashboard_service_spec.rb create mode 100644 spec/services/metrics/global_metrics_update_service_spec.rb create mode 100644 spec/services/ml/experiment_tracking/handle_candidate_gitlab_metadata_service_spec.rb create mode 100644 spec/services/packages/conan/single_package_search_service_spec.rb create mode 100644 spec/services/packages/npm/create_metadata_cache_service_spec.rb create mode 100644 spec/services/packages/npm/deprecate_package_service_spec.rb create mode 100644 spec/services/packages/npm/generate_metadata_service_spec.rb create mode 100644 spec/services/personal_access_tokens/rotate_service_spec.rb delete mode 100644 spec/services/projects/android_target_platform_detector_service_spec.rb create mode 100644 spec/services/projects/batch_open_merge_requests_count_service_spec.rb delete mode 100644 spec/services/projects/blame_service_spec.rb create mode 100644 spec/services/projects/forks/sync_service_spec.rb create mode 100644 spec/services/releases/links/create_service_spec.rb create mode 100644 spec/services/releases/links/destroy_service_spec.rb create mode 100644 spec/services/releases/links/update_service_spec.rb delete mode 100644 spec/services/serverless/associate_domain_service_spec.rb create mode 100644 spec/services/users/deactivate_service_spec.rb create mode 100644 spec/services/work_items/import_csv_service_spec.rb create mode 100644 spec/services/work_items/parent_links/base_service_spec.rb create mode 100644 spec/services/work_items/parent_links/reorder_service_spec.rb create mode 100644 spec/services/work_items/prepare_import_csv_service_spec.rb create mode 100644 spec/services/work_items/widgets/award_emoji_service/update_service_spec.rb create mode 100644 spec/services/work_items/widgets/current_user_todos_service/update_service_spec.rb create mode 100644 spec/services/work_items/widgets/hierarchy_service/create_service_spec.rb create mode 100644 spec/services/work_items/widgets/labels_service/update_service_spec.rb delete mode 100644 spec/services/work_items/widgets/milestone_service/create_service_spec.rb delete mode 100644 spec/services/work_items/widgets/milestone_service/update_service_spec.rb create mode 100644 spec/services/work_items/widgets/notifications_service/update_service_spec.rb create mode 100644 spec/support/ability_check.rb create mode 100644 spec/support/ability_check_todo.yml delete mode 100644 spec/support/banzai/filter_timeout_shared_examples.rb delete mode 100644 spec/support/banzai/reference_filter_shared_examples.rb create mode 100644 spec/support/capybara_wait_for_all_requests.rb delete mode 100644 spec/support/chunked_io/chunked_io_helpers.rb delete mode 100644 spec/support/controllers/project_import_rate_limiter_shared_examples.rb delete mode 100644 spec/support/cycle_analytics_helpers/test_generation.rb create mode 100644 spec/support/fast_quarantine.rb delete mode 100644 spec/support/flaky_tests.rb delete mode 100644 spec/support/gitlab/usage/metrics_instrumentation_shared_examples.rb delete mode 100644 spec/support/google_api/cloud_platform_helpers.rb delete mode 100644 spec/support/graphql/arguments.rb delete mode 100644 spec/support/graphql/fake_query_type.rb delete mode 100644 spec/support/graphql/fake_tracer.rb delete mode 100644 spec/support/graphql/field_inspection.rb delete mode 100644 spec/support/graphql/field_selection.rb delete mode 100644 spec/support/graphql/resolver_factories.rb delete mode 100644 spec/support/graphql/subscriptions/action_cable/mock_action_cable.rb delete mode 100644 spec/support/graphql/subscriptions/action_cable/mock_gitlab_schema.rb delete mode 100644 spec/support/graphql/subscriptions/notes/helper.rb delete mode 100644 spec/support/graphql/var.rb delete mode 100644 spec/support/helpers/callouts_test_helper.rb create mode 100644 spec/support/helpers/chunked_io_helpers.rb create mode 100644 spec/support/helpers/content_editor_helpers.rb create mode 100644 spec/support/helpers/cycle_analytics_helpers/test_generation.rb create mode 100644 spec/support/helpers/database/inject_failure_helpers.rb create mode 100644 spec/support/helpers/every_sidekiq_worker_test_helper.rb delete mode 100644 spec/support/helpers/fake_u2f_device.rb delete mode 100644 spec/support/helpers/features/invite_members_modal_helper.rb create mode 100644 spec/support/helpers/features/invite_members_modal_helpers.rb delete mode 100644 spec/support/helpers/features/list_rows_helpers.rb create mode 100644 spec/support/helpers/features/mirroring_helpers.rb delete mode 100644 spec/support/helpers/features/snippet_helpers.rb create mode 100644 spec/support/helpers/features/snippet_spec_helpers.rb create mode 100644 spec/support/helpers/google_api/cloud_platform_helpers.rb create mode 100644 spec/support/helpers/graphql/arguments.rb create mode 100644 spec/support/helpers/graphql/fake_query_type.rb create mode 100644 spec/support/helpers/graphql/fake_tracer.rb create mode 100644 spec/support/helpers/graphql/field_inspection.rb create mode 100644 spec/support/helpers/graphql/field_selection.rb create mode 100644 spec/support/helpers/graphql/resolver_factories.rb create mode 100644 spec/support/helpers/graphql/subscriptions/action_cable/mock_action_cable.rb create mode 100644 spec/support/helpers/graphql/subscriptions/action_cable/mock_gitlab_schema.rb create mode 100644 spec/support/helpers/graphql/subscriptions/notes/helper.rb create mode 100644 spec/support/helpers/graphql/var.rb create mode 100644 spec/support/helpers/http_io_helpers.rb create mode 100644 spec/support/helpers/keyset_pagination_helpers.rb create mode 100644 spec/support/helpers/migrations_helpers/cluster_helpers.rb create mode 100644 spec/support/helpers/migrations_helpers/namespaces_helper.rb create mode 100644 spec/support/helpers/migrations_helpers/schema_version_finder.rb create mode 100644 spec/support/helpers/migrations_helpers/vulnerabilities_findings_helper.rb create mode 100644 spec/support/helpers/models/ci/partitioning_testing/cascade_check.rb create mode 100644 spec/support/helpers/models/ci/partitioning_testing/partition_identifiers.rb create mode 100644 spec/support/helpers/models/ci/partitioning_testing/rspec_hooks.rb create mode 100644 spec/support/helpers/models/ci/partitioning_testing/schema_helpers.rb create mode 100644 spec/support/helpers/models/merge_request_without_merge_request_diff.rb create mode 100644 spec/support/helpers/prometheus/metric_builders.rb create mode 100644 spec/support/helpers/redis_helpers.rb create mode 100644 spec/support/helpers/test_reports_helper.rb create mode 100644 spec/support/helpers/trace_helpers.rb delete mode 100644 spec/support/http_io/http_io_helpers.rb create mode 100644 spec/support/matchers/be_a_foreign_key_column_of.rb create mode 100644 spec/support/matchers/be_indexed_by.rb create mode 100644 spec/support/matchers/exceed_redis_call_limit.rb create mode 100644 spec/support/matchers/have_plain_text_content.rb create mode 100644 spec/support/matchers/request_urgency_matcher.rb create mode 100644 spec/support/matchers/snapshot_matcher.rb delete mode 100644 spec/support/migrations_helpers/cluster_helpers.rb delete mode 100644 spec/support/migrations_helpers/namespaces_helper.rb delete mode 100644 spec/support/migrations_helpers/schema_version_finder.rb delete mode 100644 spec/support/migrations_helpers/vulnerabilities_findings_helper.rb delete mode 100644 spec/support/models/ci/partitioning_testing/cascade_check.rb delete mode 100644 spec/support/models/ci/partitioning_testing/partition_identifiers.rb delete mode 100644 spec/support/models/ci/partitioning_testing/rspec_hooks.rb delete mode 100644 spec/support/models/ci/partitioning_testing/schema_helpers.rb delete mode 100644 spec/support/models/merge_request_without_merge_request_diff.rb create mode 100644 spec/support/permissions_check.rb delete mode 100644 spec/support/prometheus/additional_metrics_shared_examples.rb delete mode 100644 spec/support/prometheus/metric_builders.rb delete mode 100644 spec/support/protected_tags/access_control_ce_shared_examples.rb delete mode 100644 spec/support/redis/redis_helpers.rb delete mode 100644 spec/support/redis/redis_new_instance_shared_examples.rb delete mode 100644 spec/support/redis/redis_shared_examples.rb delete mode 100644 spec/support/services/clusters/create_service_shared.rb delete mode 100644 spec/support/services/deploy_token_shared_examples.rb delete mode 100644 spec/support/services/issuable_description_quick_actions_shared_examples.rb delete mode 100644 spec/support/services/issuable_import_csv_service_shared_examples.rb delete mode 100644 spec/support/services/issuable_update_service_shared_examples.rb delete mode 100644 spec/support/services/issues/move_and_clone_services_shared_examples.rb delete mode 100644 spec/support/services/migrate_to_ghost_user_service_shared_examples.rb delete mode 100644 spec/support/services/service_response_shared_examples.rb create mode 100644 spec/support/shared_contexts/lib/gitlab/database/load_balancing/wal_tracking_shared_context.rb create mode 100644 spec/support/shared_contexts/lib/gitlab/database/partitioning/list_partitioning_shared_context.rb create mode 100644 spec/support/shared_contexts/models/distribution_shared_context.rb create mode 100644 spec/support/shared_contexts/services/clusters/create_service_shared_context.rb create mode 100644 spec/support/shared_examples/analytics/cycle_analytics/flow_metrics_examples.rb create mode 100644 spec/support/shared_examples/analytics/cycle_analytics/request_params_examples.rb create mode 100644 spec/support/shared_examples/banzai/filters/filter_timeout_shared_examples.rb create mode 100644 spec/support/shared_examples/banzai/filters/reference_filter_shared_examples.rb create mode 100644 spec/support/shared_examples/controllers/project_import_rate_limiter_shared_examples.rb create mode 100644 spec/support/shared_examples/db/seeds/data_seeder_shared_examples.rb create mode 100644 spec/support/shared_examples/features/abuse_report_shared_examples.rb create mode 100644 spec/support/shared_examples/features/explore/sidebar_shared_examples.rb create mode 100644 spec/support/shared_examples/features/milestone_editing_shared_examples.rb create mode 100644 spec/support/shared_examples/features/protected_tags_with_deploy_keys_examples.rb create mode 100644 spec/support/shared_examples/features/variable_list_pagination_shared_examples.rb create mode 100644 spec/support/shared_examples/graphql/mutations/members/bulk_update_shared_examples.rb create mode 100644 spec/support/shared_examples/graphql/notes_quick_actions_for_work_items_shared_examples.rb create mode 100644 spec/support/shared_examples/graphql/resolvers/data_transfer_resolver_shared_examples.rb create mode 100644 spec/support/shared_examples/helpers/callouts_for_web_hooks.rb create mode 100644 spec/support/shared_examples/lib/api/ai_workhorse_shared_examples.rb create mode 100644 spec/support/shared_examples/lib/api/terraform_state_enabled_shared_examples.rb create mode 100644 spec/support/shared_examples/lib/gitlab/database/async_constraints_validation_shared_examples.rb create mode 100644 spec/support/shared_examples/lib/gitlab/database/index_validators_shared_examples.rb create mode 100644 spec/support/shared_examples/lib/gitlab/database/schema_objects_shared_examples.rb create mode 100644 spec/support/shared_examples/lib/gitlab/database/table_validators_shared_examples.rb create mode 100644 spec/support/shared_examples/lib/gitlab/database/trigger_validators_shared_examples.rb create mode 100644 spec/support/shared_examples/lib/gitlab/json_logger_shared_examples.rb create mode 100644 spec/support/shared_examples/lib/gitlab/utils/username_and_email_generator_shared_examples.rb create mode 100644 spec/support/shared_examples/lib/sidebars/admin/menus/admin_menus_shared_examples.rb create mode 100644 spec/support/shared_examples/lib/sidebars/user_profile/user_profile_menus_shared_examples.rb create mode 100644 spec/support/shared_examples/lib/sidebars/user_settings/menus/user_settings_menus_shared_examples.rb create mode 100644 spec/support/shared_examples/mailers/export_csv_shared_examples.rb create mode 100644 spec/support/shared_examples/metrics_instrumentation_shared_examples.rb create mode 100644 spec/support/shared_examples/migrations/add_work_item_widget_shared_examples.rb create mode 100644 spec/support/shared_examples/models/ci/token_format_shared_examples.rb create mode 100644 spec/support/shared_examples/models/concerns/protected_branch_access_examples.rb create mode 100644 spec/support/shared_examples/models/concerns/protected_ref_access_allowed_access_levels_examples.rb create mode 100644 spec/support/shared_examples/models/concerns/protected_ref_access_examples.rb create mode 100644 spec/support/shared_examples/models/concerns/protected_tag_access_examples.rb create mode 100644 spec/support/shared_examples/models/database_event_tracking_shared_examples.rb create mode 100644 spec/support/shared_examples/observability/embed_observabilities_examples.rb create mode 100644 spec/support/shared_examples/prometheus/additional_metrics_shared_examples.rb create mode 100644 spec/support/shared_examples/protected_tags/access_control_ce_shared_examples.rb create mode 100644 spec/support/shared_examples/quick_actions/issue/issue_links_quick_actions_shared_examples.rb create mode 100644 spec/support/shared_examples/redis/redis_new_instance_shared_examples.rb create mode 100644 spec/support/shared_examples/redis/redis_shared_examples.rb create mode 100644 spec/support/shared_examples/requests/api/integrations/github_enterprise_jira_dvcs_end_of_life_shared_examples.rb create mode 100644 spec/support/shared_examples/requests/api/integrations/slack/slack_request_verification_shared_examples.rb create mode 100644 spec/support/shared_examples/requests/api/ml/mlflow/mlflow_shared_examples.rb create mode 100644 spec/support/shared_examples/requests/projects/aws/aws__ff_examples.rb delete mode 100644 spec/support/shared_examples/requests/self_monitoring_shared_examples.rb delete mode 100644 spec/support/shared_examples/services/base_helm_service_shared_examples.rb create mode 100644 spec/support/shared_examples/services/clusters/create_service_shared_examples.rb create mode 100644 spec/support/shared_examples/services/deploy_token_shared_examples.rb create mode 100644 spec/support/shared_examples/services/import_csv_service_shared_examples.rb create mode 100644 spec/support/shared_examples/services/issuable/issuable_description_quick_actions_shared_examples.rb create mode 100644 spec/support/shared_examples/services/issuable/issuable_import_csv_service_shared_examples.rb create mode 100644 spec/support/shared_examples/services/issuable/issuable_update_service_shared_examples.rb delete mode 100644 spec/support/shared_examples/services/issuable/update_service_shared_examples.rb create mode 100644 spec/support/shared_examples/services/issues/move_and_clone_services_shared_examples.rb create mode 100644 spec/support/shared_examples/services/migrate_to_ghost_user_service_shared_examples.rb create mode 100644 spec/support/shared_examples/services/service_response_shared_examples.rb delete mode 100644 spec/support/shared_examples/services/work_items/widgets/milestone_service_shared_examples.rb create mode 100644 spec/support/shared_examples/work_items/export_and_import_shared_examples.rb delete mode 100644 spec/support/shared_examples/workers/self_monitoring_shared_examples.rb create mode 100644 spec/support/stub_dot_com_check.rb create mode 100644 spec/support/stub_member_access_level.rb delete mode 100644 spec/support/test_reports/test_reports_helper.rb delete mode 100644 spec/support/trace/trace_helpers.rb create mode 100644 spec/support_specs/ability_check_spec.rb create mode 100644 spec/support_specs/capybara_wait_for_all_requests_spec.rb create mode 100644 spec/support_specs/helpers/keyset_pagination_helpers_spec.rb create mode 100644 spec/support_specs/matchers/exceed_redis_call_limit_spec.rb create mode 100644 spec/support_specs/stub_member_access_level_spec.rb create mode 100644 spec/tasks/gitlab/db/decomposition/connection_status_spec.rb create mode 100644 spec/tooling/danger/analytics_instrumentation_spec.rb create mode 100644 spec/tooling/danger/database_dictionary_spec.rb create mode 100644 spec/tooling/danger/multiversion_spec.rb delete mode 100644 spec/tooling/danger/product_intelligence_spec.rb create mode 100644 spec/tooling/danger/sidekiq_args_spec.rb create mode 100644 spec/tooling/danger/specs/feature_category_suggestion_spec.rb create mode 100644 spec/tooling/danger/specs/match_with_array_suggestion_spec.rb create mode 100644 spec/tooling/danger/specs/project_factory_suggestion_spec.rb create mode 100644 spec/tooling/lib/tooling/fast_quarantine_spec.rb create mode 100644 spec/tooling/lib/tooling/find_changes_spec.rb create mode 100644 spec/tooling/lib/tooling/find_files_using_feature_flags_spec.rb create mode 100644 spec/tooling/lib/tooling/find_tests_spec.rb create mode 100644 spec/tooling/lib/tooling/gettext_extractor_spec.rb create mode 100644 spec/tooling/lib/tooling/helpers/file_handler_spec.rb create mode 100644 spec/tooling/lib/tooling/helpers/predictive_tests_helper_spec.rb delete mode 100644 spec/tooling/lib/tooling/mappings/base_spec.rb create mode 100644 spec/tooling/lib/tooling/mappings/graphql_base_type_mappings_spec.rb create mode 100644 spec/tooling/lib/tooling/mappings/partial_to_views_mappings_spec.rb create mode 100644 spec/tooling/lib/tooling/mappings/view_to_system_specs_mappings_spec.rb create mode 100644 spec/tooling/lib/tooling/predictive_tests_spec.rb create mode 100644 spec/uploaders/packages/npm/metadata_cache_uploader_spec.rb create mode 100644 spec/views/admin/application_settings/network.html.haml_spec.rb create mode 100644 spec/views/admin/groups/_form.html.haml_spec.rb create mode 100644 spec/views/admin/projects/_form.html.haml_spec.rb create mode 100644 spec/views/devise/shared/_error_messages.html.haml_spec.rb create mode 100644 spec/views/groups/packages/index.html.haml_spec.rb create mode 100644 spec/views/groups/settings/_general.html.haml_spec.rb create mode 100644 spec/views/groups/show.html.haml_spec.rb delete mode 100644 spec/views/layouts/_search.html.haml_spec.rb create mode 100644 spec/views/layouts/group.html.haml_spec.rb create mode 100644 spec/views/layouts/minimal.html.haml_spec.rb create mode 100644 spec/views/layouts/project.html.haml_spec.rb create mode 100644 spec/views/notify/import_work_items_csv_email.html.haml_spec.rb create mode 100644 spec/views/notify/new_achievement_email.html.haml_spec.rb create mode 100644 spec/views/projects/issues/_related_issues.html.haml_spec.rb create mode 100644 spec/views/projects/packages/index.html.haml_spec.rb create mode 100644 spec/workers/bulk_imports/finish_batched_relation_export_worker_spec.rb create mode 100644 spec/workers/bulk_imports/relation_batch_export_worker_spec.rb delete mode 100644 spec/workers/ci/create_cross_project_pipeline_worker_spec.rb create mode 100644 spec/workers/clusters/agents/notify_git_push_worker_spec.rb delete mode 100644 spec/workers/concerns/cluster_queue_spec.rb delete mode 100644 spec/workers/concerns/gitlab/github_import/queue_spec.rb delete mode 100644 spec/workers/concerns/pipeline_background_queue_spec.rb delete mode 100644 spec/workers/concerns/pipeline_queue_spec.rb delete mode 100644 spec/workers/concerns/waitable_worker_spec.rb create mode 100644 spec/workers/container_registry/record_data_repair_detail_worker_spec.rb delete mode 100644 spec/workers/deployments/drop_older_deployments_worker_spec.rb create mode 100644 spec/workers/gitlab/github_import/import_collaborator_worker_spec.rb create mode 100644 spec/workers/gitlab/github_import/pull_requests/import_merged_by_worker_spec.rb create mode 100644 spec/workers/gitlab/github_import/pull_requests/import_review_worker_spec.rb create mode 100644 spec/workers/gitlab/github_import/stage/import_collaborators_worker_spec.rb delete mode 100644 spec/workers/gitlab/phabricator_import/base_worker_spec.rb delete mode 100644 spec/workers/gitlab/phabricator_import/import_tasks_worker_spec.rb create mode 100644 spec/workers/integrations/slack_event_worker_spec.rb create mode 100644 spec/workers/merge_requests/set_reviewer_reviewed_worker_spec.rb create mode 100644 spec/workers/metrics/global_metrics_update_worker_spec.rb create mode 100644 spec/workers/ml/experiment_tracking/associate_ml_candidate_to_package_worker_spec.rb create mode 100644 spec/workers/packages/cleanup/delete_orphaned_dependencies_worker_spec.rb create mode 100644 spec/workers/packages/debian/cleanup_dangling_package_files_worker_spec.rb create mode 100644 spec/workers/packages/npm/deprecate_package_worker_spec.rb create mode 100644 spec/workers/projects/import_export/create_relation_exports_worker_spec.rb create mode 100644 spec/workers/projects/import_export/wait_relation_exports_worker_spec.rb delete mode 100644 spec/workers/self_monitoring_project_create_worker_spec.rb delete mode 100644 spec/workers/self_monitoring_project_delete_worker_spec.rb create mode 100644 spec/workers/ssh_keys/update_last_used_at_worker_spec.rb create mode 100644 spec/workers/work_items/import_work_items_csv_worker_spec.rb (limited to 'spec') diff --git a/spec/benchmarks/banzai_benchmark.rb b/spec/benchmarks/banzai_benchmark.rb index 7a60825c1e6..45f45bcc8dd 100644 --- a/spec/benchmarks/banzai_benchmark.rb +++ b/spec/benchmarks/banzai_benchmark.rb @@ -16,8 +16,15 @@ require 'benchmark/ips' # or # rake benchmark:banzai # +# A specific filter can also be benchmarked by using the `FILTER` +# environment variable. +# +# BENCHMARK=1 FILTER=MathFilter rspec spec/benchmarks/banzai_benchmark.rb --tag specific_filter +# or +# FILTER=MathFilter rake benchmark:banzai +# # rubocop: disable RSpec/TopLevelDescribePath -RSpec.describe 'GitLab Markdown Benchmark', :aggregate_failures do +RSpec.describe 'GitLab Markdown Benchmark', :aggregate_failures, feature_category: :team_planning do include MarkupHelper let_it_be(:feature) { MarkdownFeature.new } @@ -83,9 +90,15 @@ RSpec.describe 'GitLab Markdown Benchmark', :aggregate_failures do benchmark_pipeline_filters(:plain_markdown) end - it 'benchmarks specified filters in the FullPipeline' do - filter_klass_list = [Banzai::Filter::MathFilter] - benchmark_pipeline_filters(:full, filter_klass_list) + it 'benchmarks specified filters in the FullPipeline', :specific_filter do + begin + filter = ENV['FILTER'] || 'MarkdownFilter' + filter_klass = "Banzai::Filter::#{filter}".constantize + rescue NameError + raise 'Incorrect filter specified. Correct example: FILTER=MathFilter' + end + + benchmark_pipeline_filters(:full, [filter_klass]) end end @@ -114,7 +127,8 @@ RSpec.describe 'GitLab Markdown Benchmark', :aggregate_failures do pipeline = Banzai::Pipeline[pipeline_type] filter_source = build_filter_text(pipeline, markdown_text) - puts "\n--> Benchmarking #{pipeline.name.demodulize} filters\n" + filter_msg = filter_klass_list ? filter_klass_list.first.name.demodulize : 'all filters' + puts "\n--> Benchmarking #{filter_msg} for #{pipeline.name.demodulize}\n" Benchmark.ips do |x| x.config(time: 10, warmup: 2) diff --git a/spec/bin/sidekiq_cluster_spec.rb b/spec/bin/sidekiq_cluster_spec.rb index eb014c511e3..b36fb82c295 100644 --- a/spec/bin/sidekiq_cluster_spec.rb +++ b/spec/bin/sidekiq_cluster_spec.rb @@ -12,7 +12,8 @@ RSpec.describe 'bin/sidekiq-cluster', :aggregate_failures do context 'when selecting some queues and excluding others' do where(:args, :included, :excluded) do %w[--negate cronjob] | '-qdefault,1' | '-qcronjob,1' - %w[--queue-selector resource_boundary=cpu] | '-qupdate_merge_requests,1' | '-qdefault,1' + %w[--queue-selector resource_boundary=cpu] | %w[-qupdate_merge_requests,1 -qdefault,1 -qmailers,1] | + '-qauthorized_keys_worker,1' end with_them do @@ -23,8 +24,8 @@ RSpec.describe 'bin/sidekiq-cluster', :aggregate_failures do expect(status).to be(0) expect(output).to include('bundle exec sidekiq') - expect(Shellwords.split(output)).to include(included) - expect(Shellwords.split(output)).not_to include(excluded) + expect(Shellwords.split(output)).to include(*included) + expect(Shellwords.split(output)).not_to include(*excluded) end end end diff --git a/spec/channels/awareness_channel_spec.rb b/spec/channels/awareness_channel_spec.rb deleted file mode 100644 index 47b1cd0188f..00000000000 --- a/spec/channels/awareness_channel_spec.rb +++ /dev/null @@ -1,81 +0,0 @@ -# frozen_string_literal: true - -require 'spec_helper' - -RSpec.describe AwarenessChannel, :clean_gitlab_redis_shared_state, type: :channel do - before do - stub_action_cable_connection(current_user: user) - end - - context "with user" do - let(:user) { create(:user) } - - describe "when no path parameter given" do - it "rejects subscription" do - subscribe path: nil - - expect(subscription).to be_rejected - end - end - - describe "with valid path parameter" do - it "successfully subscribes" do - subscribe path: "/test" - - session = AwarenessSession.for("/test") - - expect(subscription).to be_confirmed - # check if we can use session object instead - expect(subscription).to have_stream_from("awareness:#{session.to_param}") - end - - it "broadcasts set of collaborators when subscribing" do - session = AwarenessSession.for("/test") - - freeze_time do - collaborator = { - id: user.id, - name: user.name, - username: user.username, - avatar_url: user.avatar_url(size: 36), - last_activity: Time.zone.now, - last_activity_humanized: ActionController::Base.helpers.distance_of_time_in_words( - Time.zone.now, Time.zone.now - ) - } - - expect do - subscribe path: "/test" - end.to have_broadcasted_to("awareness:#{session.to_param}") - .with(collaborators: [collaborator]) - end - end - - it "transmits payload when user is touched" do - subscribe path: "/test" - - perform :touch - - expect(transmissions.size).to be 1 - end - - it "unsubscribes from channel" do - subscribe path: "/test" - session = AwarenessSession.for("/test") - - expect { subscription.unsubscribe_from_channel } - .to change { session.size }.by(-1) - end - end - end - - context "with guest" do - let(:user) { nil } - - it "rejects subscription" do - subscribe path: "/test" - - expect(subscription).to be_rejected - end - end -end diff --git a/spec/commands/metrics_server/metrics_server_spec.rb b/spec/commands/metrics_server/metrics_server_spec.rb index 310e31da045..88a28b02903 100644 --- a/spec/commands/metrics_server/metrics_server_spec.rb +++ b/spec/commands/metrics_server/metrics_server_spec.rb @@ -71,7 +71,7 @@ RSpec.describe 'GitLab metrics server', :aggregate_failures do if use_golang_server stub_env('GITLAB_GOLANG_METRICS_SERVER', '1') allow(Settings).to receive(:monitoring).and_return( - Settingslogic.new(config.dig('test', 'monitoring'))) + GitlabSettings::Options.build(config.dig('test', 'monitoring'))) else config_file.write(YAML.dump(config)) config_file.close diff --git a/spec/commands/sidekiq_cluster/cli_spec.rb b/spec/commands/sidekiq_cluster/cli_spec.rb index 0c32fa2571a..085be1ceac2 100644 --- a/spec/commands/sidekiq_cluster/cli_spec.rb +++ b/spec/commands/sidekiq_cluster/cli_spec.rb @@ -1,13 +1,12 @@ # frozen_string_literal: true -require 'fast_spec_helper' -require 'rspec-parameterized' +require 'spec_helper' require_relative '../../support/stub_settings_source' require_relative '../../../sidekiq_cluster/cli' require_relative '../../support/helpers/next_instance_of' -RSpec.describe Gitlab::SidekiqCluster::CLI, stub_settings_source: true do # rubocop:disable RSpec/FilePath +RSpec.describe Gitlab::SidekiqCluster::CLI, feature_category: :gitlab_cli, stub_settings_source: true do # rubocop:disable RSpec/FilePath include NextInstanceOf let(:cli) { described_class.new('/dev/null') } @@ -19,17 +18,12 @@ RSpec.describe Gitlab::SidekiqCluster::CLI, stub_settings_source: true do # rubo let(:sidekiq_exporter_enabled) { false } let(:sidekiq_exporter_port) { '3807' } - let(:config_file) { Tempfile.new('gitlab.yml') } let(:config) do { - 'test' => { - 'monitoring' => { - 'sidekiq_exporter' => { - 'address' => 'localhost', - 'enabled' => sidekiq_exporter_enabled, - 'port' => sidekiq_exporter_port - } - } + 'sidekiq_exporter' => { + 'address' => 'localhost', + 'enabled' => sidekiq_exporter_enabled, + 'port' => sidekiq_exporter_port } } end @@ -38,23 +32,22 @@ RSpec.describe Gitlab::SidekiqCluster::CLI, stub_settings_source: true do # rubo let(:metrics_cleanup_service) { instance_double(Prometheus::CleanupMultiprocDirService, execute: nil) } before do - stub_env('RAILS_ENV', 'test') - - config_file.write(YAML.dump(config)) - config_file.close - - allow(::Settings).to receive(:source).and_return(config_file.path) - ::Settings.reload! - allow(Gitlab::ProcessManagement).to receive(:write_pid) allow(Gitlab::SidekiqCluster::SidekiqProcessSupervisor).to receive(:instance).and_return(supervisor) allow(supervisor).to receive(:supervise) allow(Prometheus::CleanupMultiprocDirService).to receive(:new).and_return(metrics_cleanup_service) + + stub_config(sidekiq: { routing_rules: [] }) end - after do - config_file.unlink + around do |example| + original = Settings['monitoring'] + Settings['monitoring'] = config + + example.run + + Settings['monitoring'] = original end describe '#run' do @@ -67,7 +60,7 @@ RSpec.describe Gitlab::SidekiqCluster::CLI, stub_settings_source: true do # rubo context 'with arguments' do it 'starts the Sidekiq workers' do expect(Gitlab::SidekiqCluster).to receive(:start) - .with([['foo']], default_options) + .with([['foo'] + described_class::DEFAULT_QUEUES], default_options) .and_return([]) cli.run(%w(foo)) @@ -101,7 +94,7 @@ RSpec.describe Gitlab::SidekiqCluster::CLI, stub_settings_source: true do # rubo it 'starts Sidekiq workers for all queues in all_queues.yml except the ones in argv' do expect(Gitlab::SidekiqConfig::CliMethods).to receive(:worker_queues).and_return(['baz']) expect(Gitlab::SidekiqCluster).to receive(:start) - .with([['baz']], default_options) + .with([['baz'] + described_class::DEFAULT_QUEUES], default_options) .and_return([]) cli.run(%w(foo -n)) @@ -110,9 +103,10 @@ RSpec.describe Gitlab::SidekiqCluster::CLI, stub_settings_source: true do # rubo context 'with --max-concurrency flag' do it 'starts Sidekiq workers for specified queues with a max concurrency' do + expected_queues = [%w(foo bar baz), %w(solo)].each { |queues| queues.concat(described_class::DEFAULT_QUEUES) } expect(Gitlab::SidekiqConfig::CliMethods).to receive(:worker_queues).and_return(%w(foo bar baz)) expect(Gitlab::SidekiqCluster).to receive(:start) - .with([%w(foo bar baz), %w(solo)], default_options.merge(max_concurrency: 2)) + .with(expected_queues, default_options.merge(max_concurrency: 2)) .and_return([]) cli.run(%w(foo,bar,baz solo -m 2)) @@ -121,9 +115,10 @@ RSpec.describe Gitlab::SidekiqCluster::CLI, stub_settings_source: true do # rubo context 'with --min-concurrency flag' do it 'starts Sidekiq workers for specified queues with a min concurrency' do + expected_queues = [%w(foo bar baz), %w(solo)].each { |queues| queues.concat(described_class::DEFAULT_QUEUES) } expect(Gitlab::SidekiqConfig::CliMethods).to receive(:worker_queues).and_return(%w(foo bar baz)) expect(Gitlab::SidekiqCluster).to receive(:start) - .with([%w(foo bar baz), %w(solo)], default_options.merge(min_concurrency: 2)) + .with(expected_queues, default_options.merge(min_concurrency: 2)) .and_return([]) cli.run(%w(foo,bar,baz solo --min-concurrency 2)) @@ -133,7 +128,7 @@ RSpec.describe Gitlab::SidekiqCluster::CLI, stub_settings_source: true do # rubo context 'with --timeout flag' do it 'when given', 'starts Sidekiq workers with given timeout' do expect(Gitlab::SidekiqCluster).to receive(:start) - .with([['foo']], default_options.merge(timeout: 10)) + .with([['foo'] + described_class::DEFAULT_QUEUES], default_options.merge(timeout: 10)) .and_return([]) cli.run(%w(foo --timeout 10)) @@ -141,7 +136,8 @@ RSpec.describe Gitlab::SidekiqCluster::CLI, stub_settings_source: true do # rubo it 'when not given', 'starts Sidekiq workers with default timeout' do expect(Gitlab::SidekiqCluster).to receive(:start) - .with([['foo']], default_options.merge(timeout: Gitlab::SidekiqCluster::DEFAULT_SOFT_TIMEOUT_SECONDS)) + .with([['foo'] + described_class::DEFAULT_QUEUES], default_options.merge(timeout: + Gitlab::SidekiqCluster::DEFAULT_SOFT_TIMEOUT_SECONDS)) .and_return([]) cli.run(%w(foo)) @@ -155,8 +151,10 @@ RSpec.describe Gitlab::SidekiqCluster::CLI, stub_settings_source: true do # rubo it 'prints out a list of queues in alphabetical order' do expected_queues = [ + 'default', 'epics:epics_update_epics_dates', 'epics_new_epic_issue', + 'mailers', 'new_epic', 'todos_destroyer:todos_destroyer_confidential_epic' ] @@ -173,7 +171,8 @@ RSpec.describe Gitlab::SidekiqCluster::CLI, stub_settings_source: true do # rubo it 'starts Sidekiq workers for all queues in all_queues.yml with a namespace in argv' do expect(Gitlab::SidekiqConfig::CliMethods).to receive(:worker_queues).and_return(['cronjob:foo', 'cronjob:bar']) expect(Gitlab::SidekiqCluster).to receive(:start) - .with([['cronjob', 'cronjob:foo', 'cronjob:bar']], default_options) + .with([['cronjob', 'cronjob:foo', 'cronjob:bar'] + + described_class::DEFAULT_QUEUES], default_options) .and_return([]) cli.run(%w(cronjob)) @@ -211,7 +210,7 @@ RSpec.describe Gitlab::SidekiqCluster::CLI, stub_settings_source: true do # rubo 'CI and SCM queues' => { query: 'feature_category=continuous_integration|feature_category=source_code_management', included_queues: %w(pipeline_default:ci_drop_pipeline merge), - excluded_queues: %w(mailers) + excluded_queues: %w() } } end @@ -222,6 +221,7 @@ RSpec.describe Gitlab::SidekiqCluster::CLI, stub_settings_source: true do # rubo expect(opts).to eq(default_options) expect(queues.first).to include(*included_queues) expect(queues.first).not_to include(*excluded_queues) + expect(queues.first).to include(*described_class::DEFAULT_QUEUES) [] end @@ -234,6 +234,7 @@ RSpec.describe Gitlab::SidekiqCluster::CLI, stub_settings_source: true do # rubo expect(opts).to eq(default_options) expect(queues.first).not_to include(*included_queues) expect(queues.first).to include(*excluded_queues) + expect(queues.first).to include(*described_class::DEFAULT_QUEUES) [] end @@ -246,13 +247,15 @@ RSpec.describe Gitlab::SidekiqCluster::CLI, stub_settings_source: true do # rubo expected_workers = if Gitlab.ee? [ - %w[cronjob:clusters_integrations_check_prometheus_health incident_management_close_incident status_page_publish], - %w[project_export projects_import_export_parallel_project_export projects_import_export_relation_export project_template_export] + %w[cronjob:clusters_integrations_check_prometheus_health incident_management_close_incident status_page_publish] + described_class::DEFAULT_QUEUES, + %w[bulk_imports_pipeline bulk_imports_relation_export project_export projects_import_export_parallel_project_export projects_import_export_relation_export repository_import project_template_export] + + described_class::DEFAULT_QUEUES ] else [ - %w[cronjob:clusters_integrations_check_prometheus_health incident_management_close_incident], - %w[project_export projects_import_export_parallel_project_export projects_import_export_relation_export] + %w[cronjob:clusters_integrations_check_prometheus_health incident_management_close_incident] + described_class::DEFAULT_QUEUES, + %w[bulk_imports_pipeline bulk_imports_relation_export project_export projects_import_export_parallel_project_export projects_import_export_relation_export repository_import] + + described_class::DEFAULT_QUEUES ] end @@ -290,6 +293,40 @@ RSpec.describe Gitlab::SidekiqCluster::CLI, stub_settings_source: true do # rubo .to raise_error(Gitlab::SidekiqConfig::WorkerMatcher::QueryError) end end + + context "with routing rules specified" do + before do + stub_config(sidekiq: { routing_rules: [['resource_boundary=cpu', 'foo']] }) + end + + it "starts Sidekiq workers only for given queues without any additional DEFAULT_QUEUES" do + expect(Gitlab::SidekiqCluster).to receive(:start) + .with([['foo']], default_options) + .and_return([]) + + cli.run(%w(foo)) + end + end + + context "with sidekiq settings not specified" do + before do + stub_config(sidekiq: nil) + end + + it "does not throw an error" do + allow(Gitlab::SidekiqCluster).to receive(:start).and_return([]) + + expect { cli.run(%w(foo)) }.not_to raise_error + end + + it "starts Sidekiq workers with given queues, and additional default and mailers queues (DEFAULT_QUEUES)" do + expect(Gitlab::SidekiqCluster).to receive(:start) + .with([['foo'] + described_class::DEFAULT_QUEUES], default_options) + .and_return([]) + + cli.run(%w(foo)) + end + end end context 'metrics server' do @@ -319,13 +356,7 @@ RSpec.describe Gitlab::SidekiqCluster::CLI, stub_settings_source: true do # rubo context 'when sidekiq_exporter is not set up' do let(:config) do - { - 'test' => { - 'monitoring' => { - 'sidekiq_exporter' => {} - } - } - } + { 'sidekiq_exporter' => {} } end it 'does not start a sidekiq metrics server' do @@ -337,13 +368,7 @@ RSpec.describe Gitlab::SidekiqCluster::CLI, stub_settings_source: true do # rubo context 'with missing sidekiq_exporter setting' do let(:config) do - { - 'test' => { - 'monitoring' => { - 'sidekiq_exporter' => nil - } - } - } + { 'sidekiq_exporter' => nil } end it 'does not start a sidekiq metrics server' do diff --git a/spec/components/layouts/horizontal_section_component_spec.rb b/spec/components/layouts/horizontal_section_component_spec.rb index efc48213911..b0a749e58d6 100644 --- a/spec/components/layouts/horizontal_section_component_spec.rb +++ b/spec/components/layouts/horizontal_section_component_spec.rb @@ -9,8 +9,8 @@ RSpec.describe Layouts::HorizontalSectionComponent, type: :component do describe 'slots' do it 'renders title' do render_inline described_class.new do |c| - c.title { title } - c.body { body } + c.with_title { title } + c.with_body { body } end expect(page).to have_css('h4', text: title) @@ -18,8 +18,8 @@ RSpec.describe Layouts::HorizontalSectionComponent, type: :component do it 'renders body slot' do render_inline described_class.new do |c| - c.title { title } - c.body { body } + c.with_title { title } + c.with_body { body } end expect(page).to have_content(body) @@ -28,9 +28,9 @@ RSpec.describe Layouts::HorizontalSectionComponent, type: :component do context 'when description slot is provided' do before do render_inline described_class.new do |c| - c.title { title } - c.description { description } - c.body { body } + c.with_title { title } + c.with_description { description } + c.with_body { body } end end @@ -42,8 +42,8 @@ RSpec.describe Layouts::HorizontalSectionComponent, type: :component do context 'when description slot is not provided' do before do render_inline described_class.new do |c| - c.title { title } - c.body { body } + c.with_title { title } + c.with_body { body } end end @@ -57,8 +57,8 @@ RSpec.describe Layouts::HorizontalSectionComponent, type: :component do describe 'border' do it 'defaults to true and adds gl-border-b CSS class' do render_inline described_class.new do |c| - c.title { title } - c.body { body } + c.with_title { title } + c.with_body { body } end expect(page).to have_css('.gl-border-b') @@ -66,8 +66,8 @@ RSpec.describe Layouts::HorizontalSectionComponent, type: :component do it 'does not add gl-border-b CSS class when set to false' do render_inline described_class.new(border: false) do |c| - c.title { title } - c.body { body } + c.with_title { title } + c.with_body { body } end expect(page).not_to have_css('.gl-border-b') @@ -77,8 +77,8 @@ RSpec.describe Layouts::HorizontalSectionComponent, type: :component do describe 'options' do it 'adds options to wrapping element' do render_inline described_class.new(options: { data: { testid: 'foo-bar' }, class: 'foo-bar' }) do |c| - c.title { title } - c.body { body } + c.with_title { title } + c.with_body { body } end expect(page).to have_css('.foo-bar[data-testid="foo-bar"]') diff --git a/spec/components/pajamas/alert_component_spec.rb b/spec/components/pajamas/alert_component_spec.rb index 4a90a9e0b88..8f02979357e 100644 --- a/spec/components/pajamas/alert_component_spec.rb +++ b/spec/components/pajamas/alert_component_spec.rb @@ -8,8 +8,8 @@ RSpec.describe Pajamas::AlertComponent, :aggregate_failures, type: :component do before do render_inline described_class.new do |c| - c.body { body } - c.actions { actions } + c.with_body { body } + c.with_actions { actions } end end diff --git a/spec/components/pajamas/avatar_component_spec.rb b/spec/components/pajamas/avatar_component_spec.rb index 3b4e4e49fc2..d59ef390fad 100644 --- a/spec/components/pajamas/avatar_component_spec.rb +++ b/spec/components/pajamas/avatar_component_spec.rb @@ -92,7 +92,7 @@ RSpec.describe Pajamas::AvatarComponent, type: :component do let(:record) { user } it "uses a gravatar" do - expect(rendered_component).to match /gravatar\.com/ + expect(rendered_content).to match /gravatar\.com/ end end end diff --git a/spec/components/pajamas/banner_component_spec.rb b/spec/components/pajamas/banner_component_spec.rb index 861b10c3f69..6b99b4c1d76 100644 --- a/spec/components/pajamas/banner_component_spec.rb +++ b/spec/components/pajamas/banner_component_spec.rb @@ -13,7 +13,7 @@ RSpec.describe Pajamas::BannerComponent, type: :component do describe 'basic usage' do before do render_inline(subject) do |c| - c.title { title } + c.with_title { title } content end end @@ -124,8 +124,8 @@ RSpec.describe Pajamas::BannerComponent, type: :component do context 'with illustration slot' do before do render_inline(subject) do |c| - c.title { title } - c.illustration { "".html_safe } + c.with_title { title } + c.with_illustration { "".html_safe } content end end @@ -147,8 +147,8 @@ RSpec.describe Pajamas::BannerComponent, type: :component do context 'with primary_action slot' do before do render_inline(subject) do |c| - c.title { title } - c.primary_action { "Special".html_safe } + c.with_title { title } + c.with_primary_action { "Special".html_safe } content end end diff --git a/spec/components/pajamas/card_component_spec.rb b/spec/components/pajamas/card_component_spec.rb index 38d23cfca9c..6328385754d 100644 --- a/spec/components/pajamas/card_component_spec.rb +++ b/spec/components/pajamas/card_component_spec.rb @@ -9,9 +9,9 @@ RSpec.describe Pajamas::CardComponent, :aggregate_failures, type: :component do context 'slots' do before do render_inline described_class.new do |c| - c.header { header } - c.body { body } - c.footer { footer } + c.with_header { header } + c.with_body { body } + c.with_footer { footer } end end @@ -51,9 +51,9 @@ RSpec.describe Pajamas::CardComponent, :aggregate_failures, type: :component do header_options: { class: '_header_class_', data: { testid: '_header_testid_' } }, body_options: { class: '_body_class_', data: { testid: '_body_testid_' } }, footer_options: { class: '_footer_class_', data: { testid: '_footer_testid_' } }) do |c| - c.header { header } - c.body { body } - c.footer { footer } + c.with_header { header } + c.with_body { body } + c.with_footer { footer } end end diff --git a/spec/components/pajamas/checkbox_component_spec.rb b/spec/components/pajamas/checkbox_component_spec.rb index 3d50509ef10..ea3ebe77811 100644 --- a/spec/components/pajamas/checkbox_component_spec.rb +++ b/spec/components/pajamas/checkbox_component_spec.rb @@ -76,7 +76,7 @@ RSpec.describe Pajamas::CheckboxComponent, :aggregate_failures, type: :component method: method ) ) do |c| - c.label { label } + c.with_label { label } end end end @@ -94,7 +94,7 @@ RSpec.describe Pajamas::CheckboxComponent, :aggregate_failures, type: :component label: label ) ) do |c| - c.help_text { help_text } + c.with_help_text { help_text } end end end @@ -112,8 +112,8 @@ RSpec.describe Pajamas::CheckboxComponent, :aggregate_failures, type: :component method: method ) ) do |c| - c.label { label } - c.help_text { help_text } + c.with_label { label } + c.with_help_text { help_text } end end end diff --git a/spec/components/pajamas/checkbox_tag_component_spec.rb b/spec/components/pajamas/checkbox_tag_component_spec.rb index bca7a6005d5..fb5f927469b 100644 --- a/spec/components/pajamas/checkbox_tag_component_spec.rb +++ b/spec/components/pajamas/checkbox_tag_component_spec.rb @@ -9,7 +9,7 @@ RSpec.describe Pajamas::CheckboxTagComponent, :aggregate_failures, type: :compon context 'with default options' do before do render_inline(described_class.new(name: name)) do |c| - c.label { label } + c.with_label { label } end end @@ -32,7 +32,7 @@ RSpec.describe Pajamas::CheckboxTagComponent, :aggregate_failures, type: :compon label_options: label_options ) ) do |c| - c.label { label } + c.with_label { label } end end @@ -48,8 +48,8 @@ RSpec.describe Pajamas::CheckboxTagComponent, :aggregate_failures, type: :compon context 'with `help_text` slot' do before do render_inline(described_class.new(name: name)) do |c| - c.label { label } - c.help_text { help_text } + c.with_label { label } + c.with_help_text { help_text } end end diff --git a/spec/components/pajamas/radio_component_spec.rb b/spec/components/pajamas/radio_component_spec.rb index 8df432746d0..5b12e7c2785 100644 --- a/spec/components/pajamas/radio_component_spec.rb +++ b/spec/components/pajamas/radio_component_spec.rb @@ -76,7 +76,7 @@ RSpec.describe Pajamas::RadioComponent, :aggregate_failures, type: :component do value: value ) ) do |c| - c.label { label } + c.with_label { label } end end end @@ -95,7 +95,7 @@ RSpec.describe Pajamas::RadioComponent, :aggregate_failures, type: :component do label: label ) ) do |c| - c.help_text { help_text } + c.with_help_text { help_text } end end end @@ -114,8 +114,8 @@ RSpec.describe Pajamas::RadioComponent, :aggregate_failures, type: :component do value: value ) ) do |c| - c.label { label } - c.help_text { help_text } + c.with_label { label } + c.with_help_text { help_text } end end end diff --git a/spec/config/inject_enterprise_edition_module_spec.rb b/spec/config/inject_enterprise_edition_module_spec.rb index e8c0905ff89..6689fed02f5 100644 --- a/spec/config/inject_enterprise_edition_module_spec.rb +++ b/spec/config/inject_enterprise_edition_module_spec.rb @@ -2,7 +2,7 @@ require 'fast_spec_helper' -RSpec.describe InjectEnterpriseEditionModule, feature_category: :not_owned do +RSpec.describe InjectEnterpriseEditionModule, feature_category: :shared do let(:extension_name) { 'FF' } let(:extension_namespace) { Module.new } let(:fish_name) { 'Fish' } diff --git a/spec/config/mail_room_spec.rb b/spec/config/mail_room_spec.rb index a3806fb3cb6..05230b65956 100644 --- a/spec/config/mail_room_spec.rb +++ b/spec/config/mail_room_spec.rb @@ -9,24 +9,13 @@ RSpec.describe 'mail_room.yml', feature_category: :service_desk do let(:gitlab_config_path) { 'config/mail_room.yml' } let(:queues_config_path) { 'config/redis.queues.yml' } - let(:configuration) do - vars = { - 'MAIL_ROOM_GITLAB_CONFIG_FILE' => absolute_path(gitlab_config_path), - 'GITLAB_REDIS_QUEUES_CONFIG_FILE' => absolute_path(queues_config_path) - } - cmd = "puts ERB.new(File.read(#{absolute_path(mailroom_config_path).inspect})).result" - - result = Gitlab::Popen.popen_with_detail(%W(ruby -rerb -e #{cmd}), absolute_path('config'), vars) - output = result.stdout - errors = result.stderr - status = result.status - raise "Error interpreting #{mailroom_config_path}: #{output}\n#{errors}" unless status == 0 - - YAML.safe_load(output, permitted_classes: [Symbol]) - end + let(:configuration) { YAML.safe_load(ERB.new(File.read(mailroom_config_path)).result, permitted_classes: [Symbol]) } before do - stub_env('GITLAB_REDIS_QUEUES_CONFIG_FILE', absolute_path(queues_config_path)) + stub_env('MAIL_ROOM_GITLAB_CONFIG_FILE', absolute_path(gitlab_config_path)) + allow(Gitlab::Redis::Queues).to receive(:config_file_name).and_return(queues_config_path) + Gitlab::MailRoom.instance_variable_set(:@enabled_configs, nil) + Gitlab::MailRoom.instance_variable_set(:@yaml, nil) end context 'when incoming email is disabled' do diff --git a/spec/config/object_store_settings_spec.rb b/spec/config/object_store_settings_spec.rb index 7b4fa495288..b8e46affc2a 100644 --- a/spec/config/object_store_settings_spec.rb +++ b/spec/config/object_store_settings_spec.rb @@ -3,9 +3,9 @@ require 'spec_helper' require Rails.root.join('config', 'object_store_settings.rb') -RSpec.describe ObjectStoreSettings, feature_category: :not_owned do +RSpec.describe ObjectStoreSettings, feature_category: :shared do describe '#parse!' do - let(:settings) { Settingslogic.new(config) } + let(:settings) { GitlabSettings::Options.build(config) } subject { described_class.new(settings).parse! } @@ -68,7 +68,7 @@ RSpec.describe ObjectStoreSettings, feature_category: :not_owned do expect(settings.artifacts['enabled']).to be true expect(settings.artifacts['object_store']['enabled']).to be true - expect(settings.artifacts['object_store']['connection']).to eq(connection) + expect(settings.artifacts['object_store']['connection'].to_hash).to eq(connection) expect(settings.artifacts['object_store']['direct_upload']).to be true expect(settings.artifacts['object_store']['proxy_download']).to be false expect(settings.artifacts['object_store']['remote_directory']).to eq('artifacts') @@ -78,7 +78,7 @@ RSpec.describe ObjectStoreSettings, feature_category: :not_owned do expect(settings.lfs['enabled']).to be true expect(settings.lfs['object_store']['enabled']).to be true - expect(settings.lfs['object_store']['connection']).to eq(connection) + expect(settings.lfs['object_store']['connection'].to_hash).to eq(connection) expect(settings.lfs['object_store']['direct_upload']).to be true expect(settings.lfs['object_store']['proxy_download']).to be true expect(settings.lfs['object_store']['remote_directory']).to eq('lfs-objects') @@ -88,7 +88,7 @@ RSpec.describe ObjectStoreSettings, feature_category: :not_owned do expect(settings.pages['enabled']).to be true expect(settings.pages['object_store']['enabled']).to be true - expect(settings.pages['object_store']['connection']).to eq(connection) + expect(settings.pages['object_store']['connection'].to_hash).to eq(connection) expect(settings.pages['object_store']['remote_directory']).to eq('pages') expect(settings.pages['object_store']['bucket_prefix']).to eq(nil) expect(settings.pages['object_store']['consolidated_settings']).to be true @@ -128,7 +128,7 @@ RSpec.describe ObjectStoreSettings, feature_category: :not_owned do it 'populates artifacts CDN config' do subject - expect(settings.artifacts['object_store']['cdn']).to eq(cdn_config) + expect(settings.artifacts['object_store']['cdn'].to_hash).to eq(cdn_config) end end @@ -163,7 +163,7 @@ RSpec.describe ObjectStoreSettings, feature_category: :not_owned do it 'allows pages to define its own connection' do expect { subject }.not_to raise_error - expect(settings.pages['object_store']['connection']).to eq(pages_connection) + expect(settings.pages['object_store']['connection'].to_hash).to eq(pages_connection) expect(settings.pages['object_store']['consolidated_settings']).to be_falsey end end @@ -230,7 +230,7 @@ RSpec.describe ObjectStoreSettings, feature_category: :not_owned do end it 'respects original values' do - original_settings = Settingslogic.new({ + original_settings = GitlabSettings::Options.build({ 'enabled' => true, 'remote_directory' => 'artifacts' }) @@ -244,7 +244,7 @@ RSpec.describe ObjectStoreSettings, feature_category: :not_owned do end it 'supports bucket prefixes' do - original_settings = Settingslogic.new({ + original_settings = GitlabSettings::Options.build({ 'enabled' => true, 'remote_directory' => 'gitlab/artifacts' }) diff --git a/spec/config/settings_spec.rb b/spec/config/settings_spec.rb index 0928f2b72ff..55e675d5107 100644 --- a/spec/config/settings_spec.rb +++ b/spec/config/settings_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' -RSpec.describe Settings, feature_category: :authentication_and_authorization do +RSpec.describe Settings, feature_category: :system_access do using RSpec::Parameterized::TableSyntax describe 'omniauth' do @@ -31,7 +31,7 @@ RSpec.describe Settings, feature_category: :authentication_and_authorization do with_them do before do allow(Gitlab.config).to receive(:gitlab).and_return( - Settingslogic.new({ + GitlabSettings::Options.build({ 'host' => host, 'https' => true, 'port' => port, @@ -198,4 +198,18 @@ RSpec.describe Settings, feature_category: :authentication_and_authorization do end end end + + describe '.build_sidekiq_routing_rules' do + using RSpec::Parameterized::TableSyntax + + where(:input_rules, :result) do + nil | [['*', 'default']] + [] | [['*', 'default']] + [['name=foobar', 'foobar']] | [['name=foobar', 'foobar']] + end + + with_them do + it { expect(described_class.send(:build_sidekiq_routing_rules, input_rules)).to eq(result) } + end + end end diff --git a/spec/config/smime_signature_settings_spec.rb b/spec/config/smime_signature_settings_spec.rb index 477ad4a74ed..53e70f1f2cc 100644 --- a/spec/config/smime_signature_settings_spec.rb +++ b/spec/config/smime_signature_settings_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' -RSpec.describe SmimeSignatureSettings, feature_category: :not_owned do +RSpec.describe SmimeSignatureSettings, feature_category: :shared do describe '.parse' do let(:default_smime_key) { Rails.root.join('.gitlab_smime_key') } let(:default_smime_cert) { Rails.root.join('.gitlab_smime_cert') } @@ -19,7 +19,7 @@ RSpec.describe SmimeSignatureSettings, feature_category: :not_owned do context 'when providing custom values' do it 'sets correct default values to disabled' do - custom_settings = Settingslogic.new({}) + custom_settings = GitlabSettings::Options.build({}) parsed_settings = described_class.parse(custom_settings) @@ -30,7 +30,7 @@ RSpec.describe SmimeSignatureSettings, feature_category: :not_owned do end it 'enables smime with default key and cert' do - custom_settings = Settingslogic.new({ + custom_settings = GitlabSettings::Options.build({ 'enabled' => true }) @@ -46,7 +46,7 @@ RSpec.describe SmimeSignatureSettings, feature_category: :not_owned do custom_key = '/custom/key' custom_cert = '/custom/cert' custom_ca_certs = '/custom/ca_certs' - custom_settings = Settingslogic.new({ + custom_settings = GitlabSettings::Options.build({ 'enabled' => true, 'key_file' => custom_key, 'cert_file' => custom_cert, diff --git a/spec/contracts/provider/helpers/contract_source_helper.rb b/spec/contracts/provider/helpers/contract_source_helper.rb index f59f228722d..e1891b316f3 100644 --- a/spec/contracts/provider/helpers/contract_source_helper.rb +++ b/spec/contracts/provider/helpers/contract_source_helper.rb @@ -2,7 +2,6 @@ module Provider module ContractSourceHelper - QA_PACT_BROKER_HOST = "http://localhost:9292/pacts" PREFIX_PATHS = { rake: { ce: "../../contracts/project", @@ -10,7 +9,7 @@ module Provider }, spec: "../contracts/project" }.freeze - SUB_PATH_REGEX = %r{project/(?.*?)_helper.rb}.freeze + SUB_PATH_REGEX = %r{project/(?.*?)_helper.rb} class << self def contract_location(requester:, file_path:, edition: :ce) @@ -26,7 +25,7 @@ module Provider provider_url = "provider/#{construct_provider_url_path(file_path)}" consumer_url = "consumer/#{construct_consumer_url_path(file_path)}" - "#{QA_PACT_BROKER_HOST}/#{provider_url}/#{consumer_url}/latest" + "#{ENV['QA_PACT_BROKER_HOST']}/pacts/#{provider_url}/#{consumer_url}/latest" end def construct_provider_url_path(file_path) diff --git a/spec/contracts/provider_specs/helpers/provider/contract_source_helper_spec.rb b/spec/contracts/provider_specs/helpers/provider/contract_source_helper_spec.rb index 39537aa153d..18da71e0601 100644 --- a/spec/contracts/provider_specs/helpers/provider/contract_source_helper_spec.rb +++ b/spec/contracts/provider_specs/helpers/provider/contract_source_helper_spec.rb @@ -3,7 +3,7 @@ require 'spec_helper' require_relative '../../../provider/helpers/contract_source_helper' -RSpec.describe Provider::ContractSourceHelper, feature_category: :not_owned do +RSpec.describe Provider::ContractSourceHelper, feature_category: :shared do let(:pact_helper_path) { 'pact_helpers/project/pipelines/new/post_create_pipeline_helper.rb' } let(:split_pact_helper_path) { %w[pipelines new post_create_pipeline] } let(:provider_url_path) { 'POST%20create%20pipeline' } @@ -54,8 +54,12 @@ RSpec.describe Provider::ContractSourceHelper, feature_category: :not_owned do end describe '#pact_broker_url' do + before do + stub_env('QA_PACT_BROKER_HOST', 'http://localhost') + end + it 'returns the full url to the contract that the provider test is verifying' do - contract_url_path = "http://localhost:9292/pacts/provider/" \ + contract_url_path = "http://localhost/pacts/provider/" \ "#{provider_url_path}/consumer/#{consumer_url_path}/latest" expect(subject.pact_broker_url(split_pact_helper_path)).to eq(contract_url_path) diff --git a/spec/contracts/publish-contracts.sh b/spec/contracts/publish-contracts.sh index 8b9d4b6ecc6..b50ba9afae8 100644 --- a/spec/contracts/publish-contracts.sh +++ b/spec/contracts/publish-contracts.sh @@ -1,6 +1,5 @@ LATEST_SHA=$(git rev-parse HEAD) GIT_BRANCH=$(git rev-parse --abbrev-ref HEAD) -BROKER_BASE_URL="http://localhost:9292" cd "${0%/*}" || exit 1 @@ -18,7 +17,7 @@ function publish_contract () { for contract in $CONTRACTS do printf "\e[32mPublishing %s...\033[0m\n" "$contract" - pact-broker publish "$contract" --consumer-app-version "$LATEST_SHA" --branch "$GIT_BRANCH" --broker-base-url "$BROKER_BASE_URL" --output json + pact-broker publish "$contract" --consumer-app-version "$LATEST_SHA" --branch "$GIT_BRANCH" --broker-base-url "$QA_PACT_BROKER_HOST" --output json done if [ ${ERROR} = 1 ]; then diff --git a/spec/controllers/admin/application_settings_controller_spec.rb b/spec/controllers/admin/application_settings_controller_spec.rb index 32ac0f8dc07..a721722a5c3 100644 --- a/spec/controllers/admin/application_settings_controller_spec.rb +++ b/spec/controllers/admin/application_settings_controller_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' -RSpec.describe Admin::ApplicationSettingsController, :do_not_mock_admin_mode_setting do +RSpec.describe Admin::ApplicationSettingsController, :do_not_mock_admin_mode_setting, feature_category: :shared do include StubENV include UsageDataHelpers @@ -204,8 +204,29 @@ RSpec.describe Admin::ApplicationSettingsController, :do_not_mock_admin_mode_set expect(ApplicationSetting.current.valid_runner_registrars).to eq(['project']) end + it 'updates GitLab for Slack app settings' do + settings = { + slack_app_enabled: true, + slack_app_id: 'slack_app_id', + slack_app_secret: 'slack_app_secret', + slack_app_signing_secret: 'slack_app_signing_secret', + slack_app_verification_token: 'slack_app_verification_token' + } + + put :update, params: { application_setting: settings } + + expect(response).to redirect_to(general_admin_application_settings_path) + expect(ApplicationSetting.current).to have_attributes( + slack_app_enabled: true, + slack_app_id: 'slack_app_id', + slack_app_secret: 'slack_app_secret', + slack_app_signing_secret: 'slack_app_signing_secret', + slack_app_verification_token: 'slack_app_verification_token' + ) + end + context 'boolean attributes' do - shared_examples_for 'updates booolean attribute' do |attribute| + shared_examples_for 'updates boolean attribute' do |attribute| specify do existing_value = ApplicationSetting.current.public_send(attribute) new_value = !existing_value @@ -217,10 +238,11 @@ RSpec.describe Admin::ApplicationSettingsController, :do_not_mock_admin_mode_set end end - it_behaves_like 'updates booolean attribute', :user_defaults_to_private_profile - it_behaves_like 'updates booolean attribute', :can_create_group - it_behaves_like 'updates booolean attribute', :admin_mode - it_behaves_like 'updates booolean attribute', :require_admin_approval_after_user_signup + it_behaves_like 'updates boolean attribute', :user_defaults_to_private_profile + it_behaves_like 'updates boolean attribute', :can_create_group + it_behaves_like 'updates boolean attribute', :admin_mode + it_behaves_like 'updates boolean attribute', :require_admin_approval_after_user_signup + it_behaves_like 'updates boolean attribute', :remember_me_enabled end context "personal access token prefix settings" do @@ -398,9 +420,20 @@ RSpec.describe Admin::ApplicationSettingsController, :do_not_mock_admin_mode_set expect(application_settings.reload.invitation_flow_enforcement).to eq(true) end end + + context 'maximum includes' do + let(:application_settings) { ApplicationSetting.current } + + it 'updates ci_max_includes setting' do + put :update, params: { application_setting: { ci_max_includes: 200 } } + + expect(response).to redirect_to(general_admin_application_settings_path) + expect(application_settings.reload.ci_max_includes).to eq(200) + end + end end - describe 'PUT #reset_registration_token', feature_category: :credential_management do + describe 'PUT #reset_registration_token', feature_category: :user_management do before do sign_in(admin) end diff --git a/spec/controllers/admin/applications_controller_spec.rb b/spec/controllers/admin/applications_controller_spec.rb index bf7707f177c..1feda0ed36f 100644 --- a/spec/controllers/admin/applications_controller_spec.rb +++ b/spec/controllers/admin/applications_controller_spec.rb @@ -38,44 +38,49 @@ RSpec.describe Admin::ApplicationsController do end end - describe 'POST #create' do - context 'with hash_oauth_secrets flag off' do - before do - stub_feature_flags(hash_oauth_secrets: false) - end + describe 'PUT #renew' do + let(:oauth_params) do + { + id: application.id + } + end - it 'creates the application' do - create_params = attributes_for(:application, trusted: true, confidential: false, scopes: ['api']) + subject { put :renew, params: oauth_params } - expect do - post :create, params: { doorkeeper_application: create_params } - end.to change { Doorkeeper::Application.count }.by(1) + it { is_expected.to have_gitlab_http_status(:ok) } + it { expect { subject }.to change { application.reload.secret } } - application = Doorkeeper::Application.last + it 'returns the secret in json format' do + subject - expect(response).to redirect_to(admin_application_path(application)) - expect(application).to have_attributes(create_params.except(:uid, :owner_type)) - end + expect(json_response['secret']).not_to be_nil end - context 'with hash_oauth_secrets flag on' do + context 'when renew fails' do before do - stub_feature_flags(hash_oauth_secrets: true) + allow_next_found_instance_of(Doorkeeper::Application) do |application| + allow(application).to receive(:save).and_return(false) + end end - it 'creates the application' do - create_params = attributes_for(:application, trusted: true, confidential: false, scopes: ['api']) + it { expect { subject }.not_to change { application.reload.secret } } + it { is_expected.to have_gitlab_http_status(:unprocessable_entity) } + end + end - expect do - post :create, params: { doorkeeper_application: create_params } - end.to change { Doorkeeper::Application.count }.by(1) + describe 'POST #create' do + it 'creates the application' do + create_params = attributes_for(:application, trusted: true, confidential: false, scopes: ['api']) - application = Doorkeeper::Application.last + expect do + post :create, params: { doorkeeper_application: create_params } + end.to change { Doorkeeper::Application.count }.by(1) - expect(response).to have_gitlab_http_status(:ok) - expect(response).to render_template :show - expect(application).to have_attributes(create_params.except(:uid, :owner_type)) - end + application = Doorkeeper::Application.last + + expect(response).to have_gitlab_http_status(:ok) + expect(response).to render_template :show + expect(application).to have_attributes(create_params.except(:uid, :owner_type)) end it 'renders the application form on errors' do @@ -88,43 +93,18 @@ RSpec.describe Admin::ApplicationsController do end context 'when the params are for a confidential application' do - context 'with hash_oauth_secrets flag off' do - before do - stub_feature_flags(hash_oauth_secrets: false) - end - - it 'creates a confidential application' do - create_params = attributes_for(:application, confidential: true, scopes: ['read_user']) - - expect do - post :create, params: { doorkeeper_application: create_params } - end.to change { Doorkeeper::Application.count }.by(1) - - application = Doorkeeper::Application.last - - expect(response).to redirect_to(admin_application_path(application)) - expect(application).to have_attributes(create_params.except(:uid, :owner_type)) - end - end + it 'creates a confidential application' do + create_params = attributes_for(:application, confidential: true, scopes: ['read_user']) - context 'with hash_oauth_secrets flag on' do - before do - stub_feature_flags(hash_oauth_secrets: true) - end - - it 'creates a confidential application' do - create_params = attributes_for(:application, confidential: true, scopes: ['read_user']) - - expect do - post :create, params: { doorkeeper_application: create_params } - end.to change { Doorkeeper::Application.count }.by(1) + expect do + post :create, params: { doorkeeper_application: create_params } + end.to change { Doorkeeper::Application.count }.by(1) - application = Doorkeeper::Application.last + application = Doorkeeper::Application.last - expect(response).to have_gitlab_http_status(:ok) - expect(response).to render_template :show - expect(application).to have_attributes(create_params.except(:uid, :owner_type)) - end + expect(response).to have_gitlab_http_status(:ok) + expect(response).to render_template :show + expect(application).to have_attributes(create_params.except(:uid, :owner_type)) end end diff --git a/spec/controllers/admin/clusters_controller_spec.rb b/spec/controllers/admin/clusters_controller_spec.rb index 8e62aeed7d0..d04cd20f4e6 100644 --- a/spec/controllers/admin/clusters_controller_spec.rb +++ b/spec/controllers/admin/clusters_controller_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' -RSpec.describe Admin::ClustersController, feature_category: :kubernetes_management do +RSpec.describe Admin::ClustersController, feature_category: :deployment_management do include AccessMatchersForController include GoogleApi::CloudPlatformHelpers @@ -259,14 +259,6 @@ RSpec.describe Admin::ClustersController, feature_category: :kubernetes_manageme expect(response).to have_gitlab_http_status(:ok) expect(response).to match_response_schema('cluster_status') end - - it 'invokes schedule_status_update on each application' do - expect_next_instance_of(Clusters::Applications::Ingress) do |instance| - expect(instance).to receive(:schedule_status_update) - end - - get_cluster_status - end end describe 'security' do @@ -292,20 +284,37 @@ RSpec.describe Admin::ClustersController, feature_category: :kubernetes_manageme end describe 'functionality' do - render_views + context 'when remove_monitor_metrics FF is disabled' do + before do + stub_feature_flags(remove_monitor_metrics: false) + end - it 'responds successfully' do - get_show + render_views - expect(response).to have_gitlab_http_status(:ok) - expect(assigns(:cluster)).to eq(cluster) + it 'responds successfully' do + get_show + + expect(response).to have_gitlab_http_status(:ok) + expect(assigns(:cluster)).to eq(cluster) + end + + it 'renders integration tab view' do + get_show(tab: 'integrations') + + expect(response).to render_template('clusters/clusters/_integrations') + expect(response).to have_gitlab_http_status(:ok) + end end - it 'renders integration tab view' do - get_show(tab: 'integrations') + context 'when remove_monitor_metrics FF is enabled' do + render_views - expect(response).to render_template('clusters/clusters/_integrations') - expect(response).to have_gitlab_http_status(:ok) + it 'renders details tab view' do + get_show(tab: 'integrations') + + expect(response).to render_template('clusters/clusters/_details') + expect(response).to have_gitlab_http_status(:ok) + end end end diff --git a/spec/controllers/admin/cohorts_controller_spec.rb b/spec/controllers/admin/cohorts_controller_spec.rb index 50626a5da91..26f6540258e 100644 --- a/spec/controllers/admin/cohorts_controller_spec.rb +++ b/spec/controllers/admin/cohorts_controller_spec.rb @@ -17,7 +17,6 @@ RSpec.describe Admin::CohortsController do it_behaves_like 'Snowplow event tracking with RedisHLL context' do subject { get :index } - let(:feature_flag_name) { :route_hll_to_snowplow_phase2 } let(:category) { described_class.name } let(:action) { 'perform_analytics_usage_action' } let(:label) { 'redis_hll_counters.analytics.analytics_total_unique_counts_monthly' } diff --git a/spec/controllers/admin/dev_ops_report_controller_spec.rb b/spec/controllers/admin/dev_ops_report_controller_spec.rb index 52a46b5e99a..d8166380760 100644 --- a/spec/controllers/admin/dev_ops_report_controller_spec.rb +++ b/spec/controllers/admin/dev_ops_report_controller_spec.rb @@ -32,7 +32,6 @@ RSpec.describe Admin::DevOpsReportController do it_behaves_like 'Snowplow event tracking with RedisHLL context' do subject { get :show, format: :html } - let(:feature_flag_name) { :route_hll_to_snowplow_phase2 } let(:category) { described_class.name } let(:action) { 'perform_analytics_usage_action' } let(:label) { 'redis_hll_counters.analytics.analytics_total_unique_counts_monthly' } diff --git a/spec/controllers/admin/instance_review_controller_spec.rb b/spec/controllers/admin/instance_review_controller_spec.rb index 6eab135b3a6..f0225a71e00 100644 --- a/spec/controllers/admin/instance_review_controller_spec.rb +++ b/spec/controllers/admin/instance_review_controller_spec.rb @@ -6,7 +6,7 @@ RSpec.describe Admin::InstanceReviewController, feature_category: :service_ping include UsageDataHelpers let(:admin) { create(:admin) } - let(:subscriptions_instance_review_url) { Gitlab::SubscriptionPortal.subscriptions_instance_review_url } + let(:subscriptions_instance_review_url) { ::Gitlab::Routing.url_helpers.subscription_portal_instance_review_url } before do sign_in(admin) diff --git a/spec/controllers/admin/integrations_controller_spec.rb b/spec/controllers/admin/integrations_controller_spec.rb index e75f27589d7..9e2a2900b33 100644 --- a/spec/controllers/admin/integrations_controller_spec.rb +++ b/spec/controllers/admin/integrations_controller_spec.rb @@ -6,6 +6,7 @@ RSpec.describe Admin::IntegrationsController do let(:admin) { create(:admin) } before do + stub_feature_flags(remove_monitor_metrics: false) sign_in(admin) end @@ -29,11 +30,7 @@ RSpec.describe Admin::IntegrationsController do end end - context 'when GitLab.com' do - before do - allow(::Gitlab).to receive(:com?) { true } - end - + context 'when GitLab.com', :saas do it 'returns 404' do get :edit, params: { id: Integration.available_integration_names.sample } diff --git a/spec/controllers/admin/runner_projects_controller_spec.rb b/spec/controllers/admin/runner_projects_controller_spec.rb index 38cc2d171ac..06a73984ac0 100644 --- a/spec/controllers/admin/runner_projects_controller_spec.rb +++ b/spec/controllers/admin/runner_projects_controller_spec.rb @@ -21,30 +21,32 @@ RSpec.describe Admin::RunnerProjectsController, feature_category: :runner_fleet } end - context 'assigning runner to same project' do - let(:project_runner) { create(:ci_runner, :project, projects: [project]) } + context 'when assigning to another project' do + let(:project_runner) { create(:ci_runner, :project, projects: [source_project]) } + let(:source_project) { create(:project) } it 'redirects to the admin runner edit page' do send_create + expect(flash[:success]).to be_present expect(response).to have_gitlab_http_status(:redirect) expect(response).to redirect_to edit_admin_runner_url(project_runner) end end - context 'assigning runner to another project' do - let(:project_runner) { create(:ci_runner, :project, projects: [source_project]) } - let(:source_project) { create(:project) } + context 'when assigning to same project' do + let(:project_runner) { create(:ci_runner, :project, projects: [project]) } it 'redirects to the admin runner edit page' do send_create + expect(flash[:alert]).to be_present expect(response).to have_gitlab_http_status(:redirect) expect(response).to redirect_to edit_admin_runner_url(project_runner) end end - context 'for unknown project' do + context 'when assigning to an unknown project' do let_it_be(:project_runner) { create(:ci_runner, :project, projects: [project]) } let(:project_id) { 0 } @@ -70,7 +72,7 @@ RSpec.describe Admin::RunnerProjectsController, feature_category: :runner_fleet } end - context 'unassigning runner from project' do + context 'when unassigning runner from project' do let(:runner_project_id) { project_runner.runner_projects.last.id } it 'redirects to the admin runner edit page' do @@ -81,7 +83,7 @@ RSpec.describe Admin::RunnerProjectsController, feature_category: :runner_fleet end end - context 'for unknown project runner relationship' do + context 'when unassigning from unknown project' do let(:runner_project_id) { 0 } it 'shows 404 for unknown project runner relationship' do diff --git a/spec/controllers/admin/runners_controller_spec.rb b/spec/controllers/admin/runners_controller_spec.rb index a39a1f38a11..b1a2d90589a 100644 --- a/spec/controllers/admin/runners_controller_spec.rb +++ b/spec/controllers/admin/runners_controller_spec.rb @@ -35,26 +35,59 @@ RSpec.describe Admin::RunnersController, feature_category: :runner_fleet do end describe '#new' do - context 'when create_runner_workflow is enabled' do + it 'renders a :new template' do + get :new + + expect(response).to have_gitlab_http_status(:ok) + expect(response).to render_template(:new) + end + + context 'when create_runner_workflow_for_admin is disabled' do before do - stub_feature_flags(create_runner_workflow: true) + stub_feature_flags(create_runner_workflow_for_admin: false) end - it 'renders a :new template' do + it 'returns :not_found' do get :new + expect(response).to have_gitlab_http_status(:not_found) + end + end + end + + describe '#register' do + subject(:register) { get :register, params: { id: new_runner.id } } + + context 'when runner can be registered after creation' do + let_it_be(:new_runner) { create(:ci_runner, registration_type: :authenticated_user) } + + it 'renders a :register template' do + register + expect(response).to have_gitlab_http_status(:ok) - expect(response).to render_template(:new) + expect(response).to render_template(:register) end end - context 'when create_runner_workflow is disabled' do + context 'when runner cannot be registered after creation' do + let_it_be(:new_runner) { runner } + + it 'returns :not_found' do + register + + expect(response).to have_gitlab_http_status(:not_found) + end + end + + context 'when create_runner_workflow_for_admin is disabled' do + let_it_be(:new_runner) { create(:ci_runner, registration_type: :authenticated_user) } + before do - stub_feature_flags(create_runner_workflow: false) + stub_feature_flags(create_runner_workflow_for_admin: false) end it 'returns :not_found' do - get :new + register expect(response).to have_gitlab_http_status(:not_found) end diff --git a/spec/controllers/admin/sessions_controller_spec.rb b/spec/controllers/admin/sessions_controller_spec.rb index 5fa7a7f278d..07088eed6d4 100644 --- a/spec/controllers/admin/sessions_controller_spec.rb +++ b/spec/controllers/admin/sessions_controller_spec.rb @@ -220,7 +220,9 @@ RSpec.describe Admin::SessionsController, :do_not_mock_admin_mode do end end - shared_examples 'when using two-factor authentication via hardware device' do + context 'when using two-factor authentication via WebAuthn' do + let(:user) { create(:admin, :two_factor_via_webauthn) } + def authenticate_2fa(user_params) post(:create, params: { user: user_params }, session: { otp_user_id: user.id }) end @@ -237,10 +239,6 @@ RSpec.describe Admin::SessionsController, :do_not_mock_admin_mode do end it 'can login with valid auth' do - # we can stub both without an differentiation between webauthn / u2f - # as these not interfere with each other und this saves us passing aroud - # parameters - allow(U2fRegistration).to receive(:authenticate).and_return(true) allow_any_instance_of(Webauthn::AuthenticateService).to receive(:execute).and_return(true) expect(controller.current_user_mode.admin_mode?).to be(false) @@ -255,7 +253,6 @@ RSpec.describe Admin::SessionsController, :do_not_mock_admin_mode do end it 'cannot login with invalid auth' do - allow(U2fRegistration).to receive(:authenticate).and_return(false) allow_any_instance_of(Webauthn::AuthenticateService).to receive(:execute).and_return(false) expect(controller.current_user_mode.admin_mode?).to be(false) @@ -267,22 +264,6 @@ RSpec.describe Admin::SessionsController, :do_not_mock_admin_mode do expect(controller.current_user_mode.admin_mode?).to be(false) end end - - context 'when using two-factor authentication via U2F' do - it_behaves_like 'when using two-factor authentication via hardware device' do - let(:user) { create(:admin, :two_factor_via_u2f) } - - before do - stub_feature_flags(webauthn: false) - end - end - end - - context 'when using two-factor authentication via WebAuthn' do - it_behaves_like 'when using two-factor authentication via hardware device' do - let(:user) { create(:admin, :two_factor_via_webauthn) } - end - end end end diff --git a/spec/controllers/admin/spam_logs_controller_spec.rb b/spec/controllers/admin/spam_logs_controller_spec.rb index 51f7ecdece6..b39c3bd009b 100644 --- a/spec/controllers/admin/spam_logs_controller_spec.rb +++ b/spec/controllers/admin/spam_logs_controller_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' -RSpec.describe Admin::SpamLogsController do +RSpec.describe Admin::SpamLogsController, feature_category: :instance_resiliency do let(:admin) { create(:admin) } let(:user) { create(:user) } let!(:first_spam) { create(:spam_log, user: user) } @@ -13,9 +13,10 @@ RSpec.describe Admin::SpamLogsController do end describe '#index' do - it 'lists all spam logs' do + it 'lists paginated spam logs' do get :index + expect(assigns(:spam_logs)).to be_kind_of(Kaminari::PaginatableWithoutCount) expect(response).to have_gitlab_http_status(:ok) end end @@ -33,10 +34,7 @@ RSpec.describe Admin::SpamLogsController do end.not_to change { SpamLog.count } expect(response).to have_gitlab_http_status(:found) - expect( - Users::GhostUserMigration.where(user: user, - initiator_user: admin) - ).to be_exists + expect(Users::GhostUserMigration.where(user: user, initiator_user: admin)).to be_exists expect(flash[:notice]).to eq("User #{user.username} was successfully removed.") end end diff --git a/spec/controllers/admin/usage_trends_controller_spec.rb b/spec/controllers/admin/usage_trends_controller_spec.rb index 87cf8988b4e..7b801d53f14 100644 --- a/spec/controllers/admin/usage_trends_controller_spec.rb +++ b/spec/controllers/admin/usage_trends_controller_spec.rb @@ -17,7 +17,6 @@ RSpec.describe Admin::UsageTrendsController do it_behaves_like 'Snowplow event tracking with RedisHLL context' do subject { get :index } - let(:feature_flag_name) { :route_hll_to_snowplow_phase2 } let(:category) { described_class.name } let(:action) { 'perform_analytics_usage_action' } let(:label) { 'redis_hll_counters.analytics.analytics_total_unique_counts_monthly' } diff --git a/spec/controllers/admin/users_controller_spec.rb b/spec/controllers/admin/users_controller_spec.rb index 63e68118066..9b00451de30 100644 --- a/spec/controllers/admin/users_controller_spec.rb +++ b/spec/controllers/admin/users_controller_spec.rb @@ -185,22 +185,14 @@ RSpec.describe Admin::UsersController do delete :destroy, params: { id: user.username }, format: :json expect(response).to have_gitlab_http_status(:ok) - expect( - Users::GhostUserMigration.where(user: user, - initiator_user: admin, - hard_delete: false) - ).to be_exists + expect(Users::GhostUserMigration.where(user: user, initiator_user: admin, hard_delete: false)).to be_exists end it 'initiates user removal and passes hard delete option' do delete :destroy, params: { id: user.username, hard_delete: true }, format: :json expect(response).to have_gitlab_http_status(:ok) - expect( - Users::GhostUserMigration.where(user: user, - initiator_user: admin, - hard_delete: true) - ).to be_exists + expect(Users::GhostUserMigration.where(user: user, initiator_user: admin, hard_delete: true)).to be_exists end context 'prerequisites for account deletion' do @@ -231,11 +223,7 @@ RSpec.describe Admin::UsersController do expect(response).to redirect_to(admin_users_path) expect(flash[:notice]).to eq(_('The user is being deleted.')) - expect( - Users::GhostUserMigration.where(user: user, - initiator_user: admin, - hard_delete: true) - ).to be_exists + expect(Users::GhostUserMigration.where(user: user, initiator_user: admin, hard_delete: true)).to be_exists end end end @@ -252,10 +240,7 @@ RSpec.describe Admin::UsersController do it 'initiates user removal', :sidekiq_inline do subject - expect( - Users::GhostUserMigration.where(user: user, - initiator_user: admin) - ).to be_exists + expect(Users::GhostUserMigration.where(user: user, initiator_user: admin)).to be_exists end it 'displays the rejection message' do @@ -403,7 +388,7 @@ RSpec.describe Admin::UsersController do put :deactivate, params: { id: user.username } user.reload expect(user.deactivated?).to be_falsey - expect(flash[:notice]).to eq("The user you are trying to deactivate has been active in the past #{Gitlab::CurrentSettings.deactivate_dormant_users_period} days and cannot be deactivated") + expect(flash[:alert]).to eq("The user you are trying to deactivate has been active in the past #{Gitlab::CurrentSettings.deactivate_dormant_users_period} days and cannot be deactivated") end end end @@ -425,7 +410,7 @@ RSpec.describe Admin::UsersController do put :deactivate, params: { id: user.username } user.reload expect(user.deactivated?).to be_falsey - expect(flash[:notice]).to eq('Error occurred. A blocked user cannot be deactivated') + expect(flash[:alert]).to eq('Error occurred. A blocked user cannot be deactivated') end end @@ -436,7 +421,7 @@ RSpec.describe Admin::UsersController do put :deactivate, params: { id: internal_user.username } expect(internal_user.reload.deactivated?).to be_falsey - expect(flash[:notice]).to eq('Internal users cannot be deactivated') + expect(flash[:alert]).to eq('Internal users cannot be deactivated') end end end diff --git a/spec/controllers/application_controller_spec.rb b/spec/controllers/application_controller_spec.rb index f1adb9020fa..ce76be9f509 100644 --- a/spec/controllers/application_controller_spec.rb +++ b/spec/controllers/application_controller_spec.rb @@ -1,7 +1,7 @@ # frozen_string_literal: true require 'spec_helper' -RSpec.describe ApplicationController do +RSpec.describe ApplicationController, feature_category: :shared do include TermsHelper let(:user) { create(:user) } @@ -736,23 +736,11 @@ RSpec.describe ApplicationController do end end - context 'user not logged in' do - it 'sets the default headers' do - get :index - - expect(response.headers['Cache-Control']).to be_nil - expect(response.headers['Pragma']).to be_nil - end - end - - context 'user logged in' do - it 'sets the default headers' do - sign_in(user) - - get :index + it 'sets the default headers' do + get :index - expect(response.headers['Pragma']).to eq 'no-cache' - end + expect(response.headers['Cache-Control']).to be_nil + expect(response.headers['Pragma']).to be_nil end end @@ -779,7 +767,6 @@ RSpec.describe ApplicationController do subject expect(response.headers['Cache-Control']).to eq 'private, no-store' - expect(response.headers['Pragma']).to eq 'no-cache' expect(response.headers['Expires']).to eq 'Fri, 01 Jan 1990 00:00:00 GMT' end @@ -905,12 +892,12 @@ RSpec.describe ApplicationController do end end - describe 'rescue_from Gitlab::Auth::IpBlacklisted' do + describe 'rescue_from Gitlab::Auth::IpBlocked' do controller(described_class) do skip_before_action :authenticate_user! def index - raise Gitlab::Auth::IpBlacklisted + raise Gitlab::Auth::IpBlocked end end @@ -1130,4 +1117,28 @@ RSpec.describe ApplicationController do end end end + + context 'when Gitlab::Git::ResourceExhaustedError exception is raised' do + before do + sign_in user + end + + controller(described_class) do + def index + raise Gitlab::Git::ResourceExhaustedError.new( + "Upstream Gitaly has been exhausted: maximum time in concurrency queue reached. Try again later", 50 + ) + end + end + + it 'returns a plaintext error response with 429 status' do + get :index + + expect(response).to have_gitlab_http_status(:too_many_requests) + expect(response.body).to include( + "Upstream Gitaly has been exhausted: maximum time in concurrency queue reached. Try again later" + ) + expect(response.headers['Retry-After']).to eq(50) + end + end end diff --git a/spec/controllers/concerns/analytics/cycle_analytics/value_stream_actions_spec.rb b/spec/controllers/concerns/analytics/cycle_analytics/value_stream_actions_spec.rb index 246119a8118..28a0ce437de 100644 --- a/spec/controllers/concerns/analytics/cycle_analytics/value_stream_actions_spec.rb +++ b/spec/controllers/concerns/analytics/cycle_analytics/value_stream_actions_spec.rb @@ -1,8 +1,9 @@ # frozen_string_literal: true + require 'spec_helper' RSpec.describe Analytics::CycleAnalytics::ValueStreamActions, type: :controller, -feature_category: :planning_analytics do + feature_category: :team_planning do subject(:controller) do Class.new(ApplicationController) do include Analytics::CycleAnalytics::ValueStreamActions diff --git a/spec/controllers/concerns/confirm_email_warning_spec.rb b/spec/controllers/concerns/confirm_email_warning_spec.rb index b8a4b94aa66..7cfbd86cdcb 100644 --- a/spec/controllers/concerns/confirm_email_warning_spec.rb +++ b/spec/controllers/concerns/confirm_email_warning_spec.rb @@ -4,7 +4,7 @@ require 'spec_helper' RSpec.describe ConfirmEmailWarning, feature_category: :system_access do before do - stub_feature_flags(soft_email_confirmation: true) + stub_application_setting_enum('email_confirmation_setting', 'soft') end controller(ApplicationController) do diff --git a/spec/controllers/concerns/content_security_policy_patch_spec.rb b/spec/controllers/concerns/content_security_policy_patch_spec.rb index 6322950977c..9b4ddb35993 100644 --- a/spec/controllers/concerns/content_security_policy_patch_spec.rb +++ b/spec/controllers/concerns/content_security_policy_patch_spec.rb @@ -3,7 +3,7 @@ require "spec_helper" # Based on https://github.com/rails/rails/pull/45115/files#diff-35ef6d1bd8b8d3b037ec819a704cd78db55db916a57abfc2859882826fc679b6 -RSpec.describe ContentSecurityPolicyPatch, feature_category: :not_owned do +RSpec.describe ContentSecurityPolicyPatch, feature_category: :shared do include Rack::Test::Methods let(:routes) do diff --git a/spec/controllers/concerns/continue_params_spec.rb b/spec/controllers/concerns/continue_params_spec.rb index ba600b8156a..9ac7087430e 100644 --- a/spec/controllers/concerns/continue_params_spec.rb +++ b/spec/controllers/concerns/continue_params_spec.rb @@ -31,10 +31,7 @@ RSpec.describe ContinueParams do it 'cleans up any params that are not allowed' do allow(controller).to receive(:params) do - strong_continue_params(to: '/hello', - notice: 'world', - notice_now: '!', - something: 'else') + strong_continue_params(to: '/hello', notice: 'world', notice_now: '!', something: 'else') end expect(controller.continue_params.keys).to contain_exactly(*%w(to notice notice_now)) diff --git a/spec/controllers/concerns/controller_with_cross_project_access_check_spec.rb b/spec/controllers/concerns/controller_with_cross_project_access_check_spec.rb index a58b83dc42c..fc8b1efd226 100644 --- a/spec/controllers/concerns/controller_with_cross_project_access_check_spec.rb +++ b/spec/controllers/concerns/controller_with_cross_project_access_check_spec.rb @@ -25,9 +25,7 @@ RSpec.describe ControllerWithCrossProjectAccessCheck do # `described_class` is not available in this context include ControllerWithCrossProjectAccessCheck - requires_cross_project_access :index, show: false, - unless: -> { unless_condition }, - if: -> { if_condition } + requires_cross_project_access :index, show: false, unless: -> { unless_condition }, if: -> { if_condition } def index head :ok @@ -86,9 +84,10 @@ RSpec.describe ControllerWithCrossProjectAccessCheck do requires_cross_project_access - skip_cross_project_access_check index: true, show: false, - unless: -> { unless_condition }, - if: -> { if_condition } + skip_cross_project_access_check index: true, + show: false, + unless: -> { unless_condition }, + if: -> { if_condition } def index head :ok diff --git a/spec/controllers/concerns/kas_cookie_spec.rb b/spec/controllers/concerns/kas_cookie_spec.rb new file mode 100644 index 00000000000..d80df106cfd --- /dev/null +++ b/spec/controllers/concerns/kas_cookie_spec.rb @@ -0,0 +1,122 @@ +# frozen_string_literal: true + +require 'spec_helper' + +RSpec.describe KasCookie, feature_category: :deployment_management do + describe '#set_kas_cookie' do + controller(ApplicationController) do + include KasCookie + + def index + set_kas_cookie + + render json: {}, status: :ok + end + end + + before do + allow(::Gitlab::Kas).to receive(:enabled?).and_return(true) + end + + subject(:kas_cookie) do + get :index + + request.env['action_dispatch.cookies'][Gitlab::Kas::COOKIE_KEY] + end + + context 'when user is signed out' do + it { is_expected.to be_blank } + end + + context 'when user is signed in' do + let_it_be(:user) { create(:user) } + + before do + sign_in(user) + end + + it 'sets the KAS cookie', :aggregate_failures do + allow(::Gitlab::Kas::UserAccess).to receive(:cookie_data).and_return('foobar') + + expect(kas_cookie).to be_present + expect(kas_cookie).to eq('foobar') + expect(::Gitlab::Kas::UserAccess).to have_received(:cookie_data) + end + + context 'when feature flag is disabled' do + before do + stub_feature_flags(kas_user_access: false) + end + + it { is_expected.to be_blank } + end + end + end + + describe '#content_security_policy' do + let_it_be(:user) { create(:user) } + + controller(ApplicationController) do + include KasCookie + + def index + render json: {}, status: :ok + end + end + + before do + stub_config_setting(host: 'gitlab.example.com') + sign_in(user) + allow(::Gitlab::Kas).to receive(:enabled?).and_return(true) + allow(::Gitlab::Kas).to receive(:tunnel_url).and_return(kas_tunnel_url) + end + + subject(:kas_csp_connect_src) do + get :index + + request.env['action_dispatch.content_security_policy'].directives['connect-src'] + end + + context "when feature flag is disabled" do + let_it_be(:kas_tunnel_url) { 'ws://gitlab.example.com/-/k8s-proxy/' } + + before do + stub_feature_flags(kas_user_access: false) + end + + it 'does not add KAS url to connect-src directives' do + expect(kas_csp_connect_src).not_to include(::Gitlab::Kas.tunnel_url) + end + end + + context 'when feature flag is enabled' do + before do + stub_feature_flags(kas_user_access: true) + end + + context 'when KAS is on same domain as rails' do + let_it_be(:kas_tunnel_url) { 'ws://gitlab.example.com/-/k8s-proxy/' } + + it 'does not add KAS url to CSP connect-src directive' do + expect(kas_csp_connect_src).not_to include(::Gitlab::Kas.tunnel_url) + end + end + + context 'when KAS is on subdomain' do + let_it_be(:kas_tunnel_url) { 'ws://kas.gitlab.example.com/k8s-proxy/' } + + it 'adds KAS url to CSP connect-src directive' do + expect(kas_csp_connect_src).to include(::Gitlab::Kas.tunnel_url) + end + end + + context 'when KAS tunnel url is configured without trailing slash' do + let_it_be(:kas_tunnel_url) { 'ws://kas.gitlab.example.com/k8s-proxy' } + + it 'adds KAS url to CSP connect-src directive with trailing slash' do + expect(kas_csp_connect_src).to include("#{::Gitlab::Kas.tunnel_url}/") + end + end + end + end +end diff --git a/spec/controllers/concerns/metrics_dashboard_spec.rb b/spec/controllers/concerns/metrics_dashboard_spec.rb index 83546403ce5..d68a9d70ec6 100644 --- a/spec/controllers/concerns/metrics_dashboard_spec.rb +++ b/spec/controllers/concerns/metrics_dashboard_spec.rb @@ -113,7 +113,7 @@ RSpec.describe MetricsDashboard do it 'includes project_blob_path only for project dashboards' do expect(system_dashboard['project_blob_path']).to be_nil - expect(project_dashboard['project_blob_path']).to eq("/#{project.namespace.path}/#{project.name}/-/blob/master/.gitlab/dashboards/test.yml") + expect(project_dashboard['project_blob_path']).to eq("/#{project.namespace.path}/#{project.path}/-/blob/master/.gitlab/dashboards/test.yml") end it 'allows editing only for project dashboards' do diff --git a/spec/controllers/concerns/product_analytics_tracking_spec.rb b/spec/controllers/concerns/product_analytics_tracking_spec.rb index 12b4065b89c..65c2c77c027 100644 --- a/spec/controllers/concerns/product_analytics_tracking_spec.rb +++ b/spec/controllers/concerns/product_analytics_tracking_spec.rb @@ -8,7 +8,11 @@ RSpec.describe ProductAnalyticsTracking, :snowplow, feature_category: :product_a let(:user) { create(:user) } let(:event_name) { 'an_event' } + let(:event_action) { 'an_action' } + let(:event_label) { 'a_label' } + let!(:group) { create(:group) } + let_it_be(:project) { create(:project) } before do allow(Gitlab::UsageDataCounters::HLLRedisCounter).to receive(:track_event) @@ -19,8 +23,15 @@ RSpec.describe ProductAnalyticsTracking, :snowplow, feature_category: :product_a include ProductAnalyticsTracking skip_before_action :authenticate_user!, only: :show - track_event(:index, :show, name: 'an_event', destinations: [:redis_hll, :snowplow], - conditions: [:custom_condition_one?, :custom_condition_two?]) { |controller| controller.get_custom_id } + track_event( + :index, + :show, + name: 'an_event', + action: 'an_action', + label: 'a_label', + destinations: [:redis_hll, :snowplow], + conditions: [:custom_condition_one?, :custom_condition_two?] + ) { |controller| controller.get_custom_id } def index render html: 'index' @@ -44,6 +55,10 @@ RSpec.describe ProductAnalyticsTracking, :snowplow, feature_category: :product_a Group.first end + def tracking_project_source + Project.first + end + def custom_condition_one? true end @@ -64,7 +79,10 @@ RSpec.describe ProductAnalyticsTracking, :snowplow, feature_category: :product_a expect_snowplow_event( category: anything, - action: event_name, + action: event_action, + property: event_name, + label: event_label, + project: project, namespace: group, user: user, context: [context] @@ -89,20 +107,6 @@ RSpec.describe ProductAnalyticsTracking, :snowplow, feature_category: :product_a expect_snowplow_tracking(user) end - context 'when FF is disabled' do - before do - stub_const("#{described_class}::MIGRATED_EVENTS", []) - allow(Feature).to receive(:enabled?).and_call_original - allow(Feature).to receive(:enabled?).with('route_hll_to_snowplow', anything).and_return(false) - end - - it 'doesnt track snowplow event' do - get :index - - expect_no_snowplow_event - end - end - it 'tracks the event if DNT is not enabled' do stub_do_not_track('0') diff --git a/spec/controllers/concerns/redis_tracking_spec.rb b/spec/controllers/concerns/redis_tracking_spec.rb deleted file mode 100644 index 0ad8fa79e5e..00000000000 --- a/spec/controllers/concerns/redis_tracking_spec.rb +++ /dev/null @@ -1,135 +0,0 @@ -# frozen_string_literal: true - -require "spec_helper" - -RSpec.describe RedisTracking do - include TrackingHelpers - - let(:user) { create(:user) } - - controller(ApplicationController) do - include RedisTracking - - skip_before_action :authenticate_user!, only: :show - track_redis_hll_event(:index, :show, - name: 'g_compliance_approval_rules', - if: [:custom_condition_one?, :custom_condition_two?]) { |controller| controller.get_custom_id } - - def index - render html: 'index' - end - - def new - render html: 'new' - end - - def show - render html: 'show' - end - - def get_custom_id - 'some_custom_id' - end - - private - - def custom_condition_one? - true - end - - def custom_condition_two? - true - end - end - - def expect_tracking - expect(Gitlab::UsageDataCounters::HLLRedisCounter).to receive(:track_event) - .with('g_compliance_approval_rules', values: instance_of(String)) - end - - def expect_no_tracking - expect(Gitlab::UsageDataCounters::HLLRedisCounter).not_to receive(:track_event) - end - - context 'when user is logged in' do - before do - sign_in(user) - end - - it 'tracks the event' do - expect_tracking - - get :index - end - - it 'tracks the event if DNT is not enabled' do - stub_do_not_track('0') - - expect_tracking - - get :index - end - - it 'does not track the event if DNT is enabled' do - stub_do_not_track('1') - - expect_no_tracking - - get :index - end - - it 'does not track the event if the format is not HTML' do - expect_no_tracking - - get :index, format: :json - end - - it 'does not track the event if a custom condition returns false' do - expect(controller).to receive(:custom_condition_two?).and_return(false) - - expect_no_tracking - - get :index - end - - it 'does not track the event for untracked actions' do - expect_no_tracking - - get :new - end - end - - context 'when user is not logged in' do - let(:visitor_id) { SecureRandom.uuid } - - it 'tracks the event when there is a visitor id' do - cookies[:visitor_id] = { value: visitor_id, expires: 24.months } - - expect_tracking - - get :show, params: { id: 1 } - end - end - - context 'when user is not logged in and there is no visitor_id' do - it 'does not track the event' do - expect_no_tracking - - get :index - end - - it 'tracks the event when there is custom id' do - expect_tracking - - get :show, params: { id: 1 } - end - - it 'does not track the event when there is no custom id' do - expect(controller).to receive(:get_custom_id).and_return(nil) - - expect_no_tracking - - get :show, params: { id: 2 } - end - end -end diff --git a/spec/controllers/concerns/renders_commits_spec.rb b/spec/controllers/concerns/renders_commits_spec.rb index 6a504681527..45f194b63e7 100644 --- a/spec/controllers/concerns/renders_commits_spec.rb +++ b/spec/controllers/concerns/renders_commits_spec.rb @@ -15,7 +15,7 @@ RSpec.describe RendersCommits do @merge_request = MergeRequest.find(params[:id]) @commits = set_commits_for_rendering( @merge_request.recent_commits.with_latest_pipeline(@merge_request.source_branch), - commits_count: @merge_request.commits_count + commits_count: @merge_request.commits_count ) render json: { html: view_to_html_string('projects/merge_requests/_commits') } diff --git a/spec/controllers/concerns/send_file_upload_spec.rb b/spec/controllers/concerns/send_file_upload_spec.rb index 6acbff6e745..bf6b68df54e 100644 --- a/spec/controllers/concerns/send_file_upload_spec.rb +++ b/spec/controllers/concerns/send_file_upload_spec.rb @@ -2,12 +2,12 @@ require 'spec_helper' -RSpec.describe SendFileUpload do +RSpec.describe SendFileUpload, feature_category: :user_profile do let(:uploader_class) do Class.new(GitlabUploader) do include ObjectStorage::Concern - storage_options Gitlab.config.uploads + storage_location :uploads private @@ -77,26 +77,6 @@ RSpec.describe SendFileUpload do allow(uploader).to receive(:model).and_return(image_owner) end - it_behaves_like 'handles image resize requests allowed by FF' - - context 'when FF is disabled' do - before do - stub_feature_flags(dynamic_image_resizing: false) - end - - it_behaves_like 'bypasses image resize requests not allowed by FF' - end - end - - shared_examples 'bypasses image resize requests not allowed by FF' do - it 'does not write workhorse command header' do - expect(headers).not_to receive(:store).with(Gitlab::Workhorse::SEND_DATA_HEADER, /^send-scaled-img:/) - - subject - end - end - - shared_examples 'handles image resize requests allowed by FF' do context 'with valid width parameter' do it 'renders OK with workhorse command header' do expect(controller).not_to receive(:send_file) diff --git a/spec/controllers/concerns/sorting_preference_spec.rb b/spec/controllers/concerns/sorting_preference_spec.rb index 82a920215ca..6880d83142d 100644 --- a/spec/controllers/concerns/sorting_preference_spec.rb +++ b/spec/controllers/concerns/sorting_preference_spec.rb @@ -26,11 +26,14 @@ RSpec.describe SortingPreference do describe '#set_sort_order' do let(:group) { build(:group) } + let(:controller_name) { 'issues' } + let(:action_name) { 'issues' } let(:issue_weights_available) { true } before do allow(controller).to receive(:default_sort_order).and_return('updated_desc') - allow(controller).to receive(:action_name).and_return('issues') + allow(controller).to receive(:controller_name).and_return(controller_name) + allow(controller).to receive(:action_name).and_return(action_name) allow(controller).to receive(:can_sort_by_issue_weight?).and_return(issue_weights_available) user.user_preference.update!(issues_sort: sorting_field) end @@ -62,6 +65,42 @@ RSpec.describe SortingPreference do end end end + + context 'when user preference contains merged date sorting' do + let(:sorting_field) { 'merged_at_desc' } + let(:can_sort_by_merged_date?) { false } + + before do + allow(controller) + .to receive(:can_sort_by_merged_date?) + .with(can_sort_by_merged_date?) + .and_return(can_sort_by_merged_date?) + end + + it 'sets default sort order' do + is_expected.to eq('updated_desc') + end + + shared_examples 'user can sort by merged date' do + it 'sets sort order from user_preference' do + is_expected.to eq('merged_at_desc') + end + end + + context 'when controller_name is merge_requests' do + let(:controller_name) { 'merge_requests' } + let(:can_sort_by_merged_date?) { true } + + it_behaves_like 'user can sort by merged date' + end + + context 'when action_name is merge_requests' do + let(:action_name) { 'merge_requests' } + let(:can_sort_by_merged_date?) { true } + + it_behaves_like 'user can sort by merged date' + end + end end describe '#set_sort_order_from_user_preference' do diff --git a/spec/controllers/confirmations_controller_spec.rb b/spec/controllers/confirmations_controller_spec.rb index 773a416dcb4..fea43894f1c 100644 --- a/spec/controllers/confirmations_controller_spec.rb +++ b/spec/controllers/confirmations_controller_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' -RSpec.describe ConfirmationsController do +RSpec.describe ConfirmationsController, feature_category: :system_access do include DeviseHelpers before do @@ -58,8 +58,7 @@ RSpec.describe ConfirmationsController do m.call(*args) expect(Gitlab::ApplicationContext.current) - .to include('meta.user' => user.username, - 'meta.caller_id' => 'ConfirmationsController#show') + .to include('meta.user' => user.username, 'meta.caller_id' => 'ConfirmationsController#show') end perform_request @@ -94,8 +93,7 @@ RSpec.describe ConfirmationsController do m.call(*args) expect(Gitlab::ApplicationContext.current) - .to include('meta.user' => user.username, - 'meta.caller_id' => 'ConfirmationsController#show') + .to include('meta.user' => user.username, 'meta.caller_id' => 'ConfirmationsController#show') end travel_to(3.days.from_now) { perform_request } @@ -150,51 +148,67 @@ RSpec.describe ConfirmationsController do end end - context 'when reCAPTCHA is disabled' do + context "when `email_confirmation_setting` is set to `soft`" do before do - stub_application_setting(recaptcha_enabled: false) + stub_application_setting_enum('email_confirmation_setting', 'soft') end - it 'successfully sends password reset when reCAPTCHA is not solved' do - perform_request + context 'when reCAPTCHA is disabled' do + before do + stub_application_setting(recaptcha_enabled: false) + end - expect(response).to redirect_to(dashboard_projects_path) - end - end + it 'successfully sends password reset when reCAPTCHA is not solved' do + perform_request - context 'when reCAPTCHA is enabled' do - before do - stub_application_setting(recaptcha_enabled: true) + expect(response).to redirect_to(dashboard_projects_path) + end end - context 'when the reCAPTCHA is not solved' do + context 'when reCAPTCHA is enabled' do before do - Recaptcha.configuration.skip_verify_env.delete('test') + stub_application_setting(recaptcha_enabled: true) end - it 'displays an error' do - perform_request + context 'when the reCAPTCHA is not solved' do + before do + Recaptcha.configuration.skip_verify_env.delete('test') + end + + it 'displays an error' do + alert_text = _('There was an error with the reCAPTCHA. Please solve the reCAPTCHA again.') + + perform_request + + expect(response).to render_template(:new) + expect(flash[:alert]).to include alert_text + end - expect(response).to render_template(:new) - expect(flash[:alert]).to include _('There was an error with the reCAPTCHA. Please solve the reCAPTCHA again.') + it 'sets gon variables' do + Gon.clear + + perform_request + + expect(response).to render_template(:new) + expect(Gon.all_variables).not_to be_empty + end end - it 'sets gon variables' do - Gon.clear + it 'successfully sends password reset when reCAPTCHA is solved' do + Recaptcha.configuration.skip_verify_env << 'test' perform_request - expect(response).to render_template(:new) - expect(Gon.all_variables).not_to be_empty + expect(response).to redirect_to(dashboard_projects_path) end end + end - it 'successfully sends password reset when reCAPTCHA is solved' do - Recaptcha.configuration.skip_verify_env << 'test' - + context "when `email_confirmation_setting` is not set to `soft`" do + it 'redirects to the users_almost_there path' do perform_request - expect(response).to redirect_to(dashboard_projects_path) + expect(response).to redirect_to(users_almost_there_path) end end end diff --git a/spec/controllers/dashboard/projects_controller_spec.rb b/spec/controllers/dashboard/projects_controller_spec.rb index e8ee146a13a..893546def5a 100644 --- a/spec/controllers/dashboard/projects_controller_spec.rb +++ b/spec/controllers/dashboard/projects_controller_spec.rb @@ -17,6 +17,7 @@ RSpec.describe Dashboard::ProjectsController, :aggregate_failures, feature_categ before_all do project.add_developer(user) project2.add_developer(user) + user.toggle_star(project2) end before do @@ -39,6 +40,21 @@ RSpec.describe Dashboard::ProjectsController, :aggregate_failures, feature_categ expect(assigns(:projects)).to eq(projects) end + it 'assigns the correct all_user_projects' do + get :index + all_user_projects = assigns(:all_user_projects) + + expect(all_user_projects.count).to eq(2) + end + + it 'assigns the correct all_starred_projects' do + get :index + all_starred_projects = assigns(:all_starred_projects) + + expect(all_starred_projects.count).to eq(1) + expect(all_starred_projects).to include(project2) + end + context 'project sorting' do it_behaves_like 'set sort order from user preference' do let(:sorting_param) { 'created_asc' } @@ -62,6 +78,36 @@ RSpec.describe Dashboard::ProjectsController, :aggregate_failures, feature_categ end end + context 'with archived project' do + let_it_be(:archived_project) do + project2.tap { |p| p.update!(archived: true) } + end + + it 'does not display archived project' do + get :index + projects_result = assigns(:projects) + + expect(projects_result).not_to include(archived_project) + expect(projects_result).to include(project) + end + + it 'excludes archived project from all_user_projects' do + get :index + all_user_projects = assigns(:all_user_projects) + + expect(all_user_projects.count).to eq(1) + expect(all_user_projects).not_to include(archived_project) + end + + it 'excludes archived project from all_starred_projects' do + get :index + all_starred_projects = assigns(:all_starred_projects) + + expect(all_starred_projects.count).to eq(0) + expect(all_starred_projects).not_to include(archived_project) + end + end + context 'with deleted project' do let!(:pending_delete_project) do project.tap { |p| p.update!(pending_delete: true) } diff --git a/spec/controllers/every_controller_spec.rb b/spec/controllers/every_controller_spec.rb index 902872b6e92..b76da85ad72 100644 --- a/spec/controllers/every_controller_spec.rb +++ b/spec/controllers/every_controller_spec.rb @@ -1,6 +1,7 @@ # frozen_string_literal: true require 'spec_helper' + RSpec.describe "Every controller" do context "feature categories" do let_it_be(:feature_categories) do @@ -52,7 +53,7 @@ RSpec.describe "Every controller" do non_existing_used_actions = used_actions - existing_actions expect(non_existing_used_actions).to be_empty, - "#{controller} used #{non_existing_used_actions} to define feature category, but the route does not exist" + "#{controller} used #{non_existing_used_actions} to define feature category, but the route does not exist" end end end diff --git a/spec/controllers/explore/groups_controller_spec.rb b/spec/controllers/explore/groups_controller_spec.rb index a3bd8102462..76bd94fd681 100644 --- a/spec/controllers/explore/groups_controller_spec.rb +++ b/spec/controllers/explore/groups_controller_spec.rb @@ -41,9 +41,9 @@ RSpec.describe Explore::GroupsController do it_behaves_like 'explore groups' - context 'generic_explore_groups flag is disabled' do + context 'gitlab.com' do before do - stub_feature_flags(generic_explore_groups: false) + allow(Gitlab).to receive(:com?).and_return(true) end it_behaves_like 'explore groups' diff --git a/spec/controllers/explore/projects_controller_spec.rb b/spec/controllers/explore/projects_controller_spec.rb index c4f0feb21e2..c2bdb0171e7 100644 --- a/spec/controllers/explore/projects_controller_spec.rb +++ b/spec/controllers/explore/projects_controller_spec.rb @@ -239,9 +239,14 @@ RSpec.describe Explore::ProjectsController, feature_category: :projects do context 'when user is signed in' do let(:user) { create(:user) } + let_it_be(:project) { create(:project, name: 'Project 1') } + let_it_be(:project2) { create(:project, name: 'Project 2') } before do sign_in(user) + project.add_developer(user) + project2.add_developer(user) + user.toggle_star(project2) end include_examples 'explore projects' @@ -260,6 +265,21 @@ RSpec.describe Explore::ProjectsController, feature_category: :projects do let(:controller_action) { :index } let(:params_with_name) { { name: 'some project' } } + it 'assigns the correct all_user_projects' do + get :index + all_user_projects = assigns(:all_user_projects) + + expect(all_user_projects.count).to eq(2) + end + + it 'assigns the correct all_starred_projects' do + get :index + all_starred_projects = assigns(:all_starred_projects) + + expect(all_starred_projects.count).to eq(1) + expect(all_starred_projects).to include(project2) + end + context 'when disable_anonymous_project_search is enabled' do before do stub_feature_flags(disable_anonymous_project_search: true) diff --git a/spec/controllers/graphql_controller_spec.rb b/spec/controllers/graphql_controller_spec.rb index 7aad67b01e8..92b228b6836 100644 --- a/spec/controllers/graphql_controller_spec.rb +++ b/spec/controllers/graphql_controller_spec.rb @@ -43,8 +43,9 @@ RSpec.describe GraphqlController, feature_category: :integrations do post :execute expect(json_response).to include( - 'errors' => include(a_hash_including('message' => /Internal server error/, - 'raisedAt' => /graphql_controller_spec.rb/)) + 'errors' => include( + a_hash_including('message' => /Internal server error/, 'raisedAt' => /graphql_controller_spec.rb/) + ) ) end @@ -64,6 +65,22 @@ RSpec.describe GraphqlController, feature_category: :integrations do ) expect(response).to have_gitlab_http_status(:forbidden) end + + it 'handles Gitlab::Git::ResourceExhaustedError', :aggregate_failures do + allow(controller).to receive(:execute) do + raise Gitlab::Git::ResourceExhaustedError.new("Upstream Gitaly has been exhausted. Try again later", 50) + end + + post :execute + + expect(json_response).to include( + 'errors' => include( + a_hash_including('message' => 'Upstream Gitaly has been exhausted. Try again later') + ) + ) + expect(response).to have_gitlab_http_status(:too_many_requests) + expect(response.headers['Retry-After']).to be(50) + end end describe 'POST #execute' do @@ -108,6 +125,41 @@ RSpec.describe GraphqlController, feature_category: :integrations do ]) end + it 'executes a multiplexed queries with variables with no errors' do + query = <<~GQL + mutation($a: String!, $b: String!) { + echoCreate(input: { messages: [$a, $b] }) { echoes } + } + GQL + multiplex = [ + { query: query, variables: { a: 'A', b: 'B' } }, + { query: query, variables: { a: 'a', b: 'b' } } + ] + + post :execute, params: { _json: multiplex } + + expect(response).to have_gitlab_http_status(:ok) + expect(json_response).to eq( + [ + { 'data' => { 'echoCreate' => { 'echoes' => %w[A B] } } }, + { 'data' => { 'echoCreate' => { 'echoes' => %w[a b] } } } + ]) + end + + it 'does not allow string as _json parameter (a malformed multiplex query)' do + post :execute, params: { _json: 'bad' } + + expect(response).to have_gitlab_http_status(:ok) + expect(json_response).to eq({ + "errors" => [ + { + "message" => "Unexpected end of document", + "locations" => [] + } + ] + }) + end + it 'sets a limit on the total query size' do graphql_query = "{#{(['__typename'] * 1000).join(' ')}}" @@ -172,14 +224,28 @@ RSpec.describe GraphqlController, feature_category: :integrations do post :execute end - it 'calls the track gitlab cli when trackable method' do - agent = 'GLab - GitLab CLI' - request.env['HTTP_USER_AGENT'] = agent + context 'if using the GitLab CLI' do + it 'call trackable for the old UserAgent' do + agent = 'GLab - GitLab CLI' - expect(Gitlab::UsageDataCounters::GitLabCliActivityUniqueCounter) - .to receive(:track_api_request_when_trackable).with(user_agent: agent, user: user) + request.env['HTTP_USER_AGENT'] = agent - post :execute + expect(Gitlab::UsageDataCounters::GitLabCliActivityUniqueCounter) + .to receive(:track_api_request_when_trackable).with(user_agent: agent, user: user) + + post :execute + end + + it 'call trackable for the current UserAgent' do + agent = 'glab/v1.25.3-27-g7ec258fb (built 2023-02-16), darwin' + + request.env['HTTP_USER_AGENT'] = agent + + expect(Gitlab::UsageDataCounters::GitLabCliActivityUniqueCounter) + .to receive(:track_api_request_when_trackable).with(user_agent: agent, user: user) + + post :execute + end end it "assigns username in ApplicationContext" do diff --git a/spec/controllers/groups/children_controller_spec.rb b/spec/controllers/groups/children_controller_spec.rb index d0656ee47ce..2e37ed95c1c 100644 --- a/spec/controllers/groups/children_controller_spec.rb +++ b/spec/controllers/groups/children_controller_spec.rb @@ -275,6 +275,18 @@ RSpec.describe Groups::ChildrenController, feature_category: :subgroups do allow(Kaminari.config).to receive(:default_per_page).and_return(per_page) end + it 'rejects negative per_page parameter' do + get :index, params: { group_id: group.to_param, per_page: -1 }, format: :json + + expect(response).to have_gitlab_http_status(:bad_request) + end + + it 'rejects non-numeric per_page parameter' do + get :index, params: { group_id: group.to_param, per_page: 'abc' }, format: :json + + expect(response).to have_gitlab_http_status(:bad_request) + end + context 'with only projects' do let!(:other_project) { create(:project, :public, namespace: group) } let!(:first_page_projects) { create_list(:project, per_page, :public, namespace: group) } diff --git a/spec/controllers/groups/clusters_controller_spec.rb b/spec/controllers/groups/clusters_controller_spec.rb index 01ea7101f2e..f36494c3d78 100644 --- a/spec/controllers/groups/clusters_controller_spec.rb +++ b/spec/controllers/groups/clusters_controller_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' -RSpec.describe Groups::ClustersController, feature_category: :kubernetes_management do +RSpec.describe Groups::ClustersController, feature_category: :deployment_management do include AccessMatchersForController include GoogleApi::CloudPlatformHelpers @@ -322,12 +322,6 @@ RSpec.describe Groups::ClustersController, feature_category: :kubernetes_managem expect(response).to have_gitlab_http_status(:ok) expect(response).to match_response_schema('cluster_status') end - - it 'invokes schedule_status_update on each application' do - expect_any_instance_of(Clusters::Applications::Ingress).to receive(:schedule_status_update) - - go - end end describe 'security' do @@ -360,20 +354,37 @@ RSpec.describe Groups::ClustersController, feature_category: :kubernetes_managem end describe 'functionality' do - render_views + context 'when remove_monitor_metrics FF is disabled' do + before do + stub_feature_flags(remove_monitor_metrics: false) + end - it 'renders view' do - go + render_views - expect(response).to have_gitlab_http_status(:ok) - expect(assigns(:cluster)).to eq(cluster) + it 'renders view' do + go + + expect(response).to have_gitlab_http_status(:ok) + expect(assigns(:cluster)).to eq(cluster) + end + + it 'renders integration tab view', :aggregate_failures do + go(tab: 'integrations') + + expect(response).to render_template('clusters/clusters/_integrations') + expect(response).to have_gitlab_http_status(:ok) + end end - it 'renders integration tab view', :aggregate_failures do - go(tab: 'integrations') + context 'when remove_monitor_metrics FF is enabled' do + render_views - expect(response).to render_template('clusters/clusters/_integrations') - expect(response).to have_gitlab_http_status(:ok) + it 'renders details tab view', :aggregate_failures do + go(tab: 'integrations') + + expect(response).to render_template('clusters/clusters/_details') + expect(response).to have_gitlab_http_status(:ok) + end end end diff --git a/spec/controllers/groups/dependency_proxy_for_containers_controller_spec.rb b/spec/controllers/groups/dependency_proxy_for_containers_controller_spec.rb index f1ca9e11a1a..a59c90a3cf2 100644 --- a/spec/controllers/groups/dependency_proxy_for_containers_controller_spec.rb +++ b/spec/controllers/groups/dependency_proxy_for_containers_controller_spec.rb @@ -249,7 +249,7 @@ RSpec.describe Groups::DependencyProxyForContainersController do expect(send_data_type).to eq('send-dependency') expect(header).to eq( "Authorization" => ["Bearer abcd1234"], - "Accept" => ::ContainerRegistry::Client::ACCEPTED_TYPES + "Accept" => ::DependencyProxy::Manifest::ACCEPTED_TYPES ) expect(url).to eq(DependencyProxy::Registry.manifest_url(image, tag)) expect(response.headers['Content-Type']).to eq('application/gzip') diff --git a/spec/controllers/groups/group_members_controller_spec.rb b/spec/controllers/groups/group_members_controller_spec.rb index 4e5dc01f466..fe4b80e12fe 100644 --- a/spec/controllers/groups/group_members_controller_spec.rb +++ b/spec/controllers/groups/group_members_controller_spec.rb @@ -55,6 +55,20 @@ RSpec.describe Groups::GroupMembersController do expect(assigns(:invited_members).count).to eq(1) end + + context 'when filtering by user type' do + let_it_be(:service_account) { create(:user, :service_account) } + + before do + group.add_developer(service_account) + end + + it 'returns only service accounts' do + get :index, params: { group_id: group, user_type: 'service_account' } + + expect(assigns(:members).map(&:user_id)).to match_array([service_account.id]) + end + end end context 'when user cannot manage members' do @@ -67,6 +81,21 @@ RSpec.describe Groups::GroupMembersController do expect(assigns(:invited_members)).to be_nil end + + context 'when filtering by user type' do + let_it_be(:service_account) { create(:user, :service_account) } + + before do + group.add_developer(user) + group.add_developer(service_account) + end + + it 'returns only service accounts' do + get :index, params: { group_id: group, user_type: 'service_account' } + + expect(assigns(:members).map(&:user_id)).to match_array([user.id, service_account.id]) + end + end end context 'when user has owner access to subgroup' do @@ -489,13 +518,11 @@ RSpec.describe Groups::GroupMembersController do describe 'PUT #update' do it 'is successful' do - put :update, - params: { - group_member: { access_level: Gitlab::Access::GUEST }, - group_id: group, - id: membership - }, - format: :json + put :update, params: { + group_member: { access_level: Gitlab::Access::GUEST }, + group_id: group, + id: membership + }, format: :json expect(response).to have_gitlab_http_status(:ok) end @@ -505,7 +532,7 @@ RSpec.describe Groups::GroupMembersController do it 'is successful' do delete :destroy, params: { group_id: group, id: membership } - expect(response).to have_gitlab_http_status(:found) + expect(response).to have_gitlab_http_status(:see_other) end end diff --git a/spec/controllers/groups/milestones_controller_spec.rb b/spec/controllers/groups/milestones_controller_spec.rb index a3c4c47ab15..87030448b30 100644 --- a/spec/controllers/groups/milestones_controller_spec.rb +++ b/spec/controllers/groups/milestones_controller_spec.rb @@ -230,11 +230,10 @@ RSpec.describe Groups::MilestonesController do describe "#create" do it "creates group milestone with Chinese title" do - post :create, - params: { - group_id: group.to_param, - milestone: milestone_params - } + post :create, params: { + group_id: group.to_param, + milestone: milestone_params + } milestone = Milestone.find_by_title(title) @@ -251,17 +250,31 @@ RSpec.describe Groups::MilestonesController do it "updates group milestone" do milestone_params[:title] = "title changed" - put :update, - params: { - id: milestone.iid, - group_id: group.to_param, - milestone: milestone_params - } + put :update, params: { + id: milestone.iid, + group_id: group.to_param, + milestone: milestone_params + } milestone.reload expect(response).to redirect_to(group_milestone_path(group, milestone.iid)) expect(milestone.title).to eq("title changed") end + + it "handles ActiveRecord::StaleObjectError" do + milestone_params[:title] = "title changed" + # Purposely reduce the lock_version to trigger an ActiveRecord::StaleObjectError + milestone_params[:lock_version] = milestone.lock_version - 1 + + put :update, params: { + id: milestone.iid, + group_id: group.to_param, + milestone: milestone_params + } + + expect(response).not_to redirect_to(group_milestone_path(group, milestone.iid)) + expect(response).to render_template(:edit) + end end describe "#destroy" do @@ -390,21 +403,19 @@ RSpec.describe Groups::MilestonesController do context 'for a non-GET request' do context 'when requesting the canonical path with different casing' do it 'does not 404' do - post :create, - params: { - group_id: group.to_param, - milestone: { title: title } - } + post :create, params: { + group_id: group.to_param, + milestone: { title: title } + } expect(response).not_to have_gitlab_http_status(:not_found) end it 'does not redirect to the correct casing' do - post :create, - params: { - group_id: group.to_param, - milestone: { title: title } - } + post :create, params: { + group_id: group.to_param, + milestone: { title: title } + } expect(response).not_to have_gitlab_http_status(:moved_permanently) end @@ -414,11 +425,10 @@ RSpec.describe Groups::MilestonesController do let(:redirect_route) { group.redirect_routes.create!(path: 'old-path') } it 'returns not found' do - post :create, - params: { - group_id: redirect_route.path, - milestone: { title: title } - } + post :create, params: { + group_id: redirect_route.path, + milestone: { title: title } + } expect(response).to have_gitlab_http_status(:not_found) end diff --git a/spec/controllers/groups/runners_controller_spec.rb b/spec/controllers/groups/runners_controller_spec.rb index 1a60f7d824e..9ae5cb6f87c 100644 --- a/spec/controllers/groups/runners_controller_spec.rb +++ b/spec/controllers/groups/runners_controller_spec.rb @@ -6,8 +6,8 @@ RSpec.describe Groups::RunnersController, feature_category: :runner_fleet do let_it_be(:user) { create(:user) } let_it_be(:group) { create(:group) } let_it_be(:project) { create(:project, group: group) } + let_it_be(:runner) { create(:ci_runner, :group, groups: [group]) } - let!(:runner) { create(:ci_runner, :group, groups: [group]) } let!(:project_runner) { create(:ci_runner, :project, projects: [project]) } let!(:instance_runner) { create(:ci_runner, :instance) } @@ -37,6 +37,12 @@ RSpec.describe Groups::RunnersController, feature_category: :runner_fleet do expect_snowplow_event(category: described_class.name, action: 'index', user: user, namespace: group) end + + it 'assigns variables' do + get :index, params: { group_id: group } + + expect(assigns(:group_new_runner_path)).to eq(new_group_runner_path(group)) + end end context 'when user is not owner' do @@ -58,6 +64,130 @@ RSpec.describe Groups::RunnersController, feature_category: :runner_fleet do end end + describe '#new' do + context 'when create_runner_workflow_for_namespace is enabled' do + before do + stub_feature_flags(create_runner_workflow_for_namespace: [group]) + end + + context 'when user is owner' do + before do + group.add_owner(user) + end + + it 'renders new with 200 status code' do + get :new, params: { group_id: group } + + expect(response).to have_gitlab_http_status(:ok) + expect(response).to render_template(:new) + end + end + + context 'when user is not owner' do + before do + group.add_maintainer(user) + end + + it 'renders a 404' do + get :new, params: { group_id: group } + + expect(response).to have_gitlab_http_status(:not_found) + end + end + end + + context 'when create_runner_workflow_for_namespace is disabled' do + before do + stub_feature_flags(create_runner_workflow_for_namespace: false) + end + + context 'when user is owner' do + before do + group.add_owner(user) + end + + it 'renders a 404' do + get :new, params: { group_id: group } + + expect(response).to have_gitlab_http_status(:not_found) + end + end + end + end + + describe '#register' do + subject(:register) { get :register, params: { group_id: group, id: new_runner } } + + context 'when create_runner_workflow_for_namespace is enabled' do + before do + stub_feature_flags(create_runner_workflow_for_namespace: [group]) + end + + context 'when user is owner' do + before do + group.add_owner(user) + end + + context 'when runner can be registered after creation' do + let_it_be(:new_runner) { create(:ci_runner, :group, groups: [group], registration_type: :authenticated_user) } + + it 'renders a :register template' do + register + + expect(response).to have_gitlab_http_status(:ok) + expect(response).to render_template(:register) + end + end + + context 'when runner cannot be registered after creation' do + let_it_be(:new_runner) { runner } + + it 'returns :not_found' do + register + + expect(response).to have_gitlab_http_status(:not_found) + end + end + end + + context 'when user is not owner' do + before do + group.add_maintainer(user) + end + + context 'when runner can be registered after creation' do + let_it_be(:new_runner) { create(:ci_runner, :group, groups: [group], registration_type: :authenticated_user) } + + it 'returns :not_found' do + register + + expect(response).to have_gitlab_http_status(:not_found) + end + end + end + end + + context 'when create_runner_workflow_for_namespace is disabled' do + let_it_be(:new_runner) { create(:ci_runner, :group, groups: [group], registration_type: :authenticated_user) } + + before do + stub_feature_flags(create_runner_workflow_for_namespace: false) + end + + context 'when user is owner' do + before do + group.add_owner(user) + end + + it 'returns :not_found' do + register + + expect(response).to have_gitlab_http_status(:not_found) + end + end + end + end + describe '#show' do context 'when user is owner' do before do @@ -158,6 +288,8 @@ RSpec.describe Groups::RunnersController, feature_category: :runner_fleet do end describe '#update' do + let!(:runner) { create(:ci_runner, :group, groups: [group]) } + context 'when user is an owner' do before do group.add_owner(user) diff --git a/spec/controllers/groups/settings/applications_controller_spec.rb b/spec/controllers/groups/settings/applications_controller_spec.rb index b9457770ed6..c398fd044c2 100644 --- a/spec/controllers/groups/settings/applications_controller_spec.rb +++ b/spec/controllers/groups/settings/applications_controller_spec.rb @@ -71,43 +71,18 @@ RSpec.describe Groups::Settings::ApplicationsController do group.add_owner(user) end - context 'with hash_oauth_secrets flag on' do - before do - stub_feature_flags(hash_oauth_secrets: true) - end - - it 'creates the application' do - create_params = attributes_for(:application, trusted: false, confidential: false, scopes: ['api']) - - expect do - post :create, params: { group_id: group, doorkeeper_application: create_params } - end.to change { Doorkeeper::Application.count }.by(1) - - application = Doorkeeper::Application.last - - expect(response).to have_gitlab_http_status(:ok) - expect(response).to render_template :show - expect(application).to have_attributes(create_params.except(:uid, :owner_type)) - end - end + it 'creates the application' do + create_params = attributes_for(:application, trusted: false, confidential: false, scopes: ['api']) - context 'with hash_oauth_secrets flag off' do - before do - stub_feature_flags(hash_oauth_secrets: false) - end - - it 'creates the application' do - create_params = attributes_for(:application, trusted: false, confidential: false, scopes: ['api']) - - expect do - post :create, params: { group_id: group, doorkeeper_application: create_params } - end.to change { Doorkeeper::Application.count }.by(1) + expect do + post :create, params: { group_id: group, doorkeeper_application: create_params } + end.to change { Doorkeeper::Application.count }.by(1) - application = Doorkeeper::Application.last + application = Doorkeeper::Application.last - expect(response).to redirect_to(group_settings_application_path(group, application)) - expect(application).to have_attributes(create_params.except(:uid, :owner_type)) - end + expect(response).to have_gitlab_http_status(:ok) + expect(response).to render_template :show + expect(application).to have_attributes(create_params.except(:uid, :owner_type)) end it 'renders the application form on errors' do @@ -120,43 +95,18 @@ RSpec.describe Groups::Settings::ApplicationsController do end context 'when the params are for a confidential application' do - context 'with hash_oauth_secrets flag off' do - before do - stub_feature_flags(hash_oauth_secrets: false) - end - - it 'creates a confidential application' do - create_params = attributes_for(:application, confidential: true, scopes: ['read_user']) - - expect do - post :create, params: { group_id: group, doorkeeper_application: create_params } - end.to change { Doorkeeper::Application.count }.by(1) + it 'creates a confidential application' do + create_params = attributes_for(:application, confidential: true, scopes: ['read_user']) - application = Doorkeeper::Application.last - - expect(response).to redirect_to(group_settings_application_path(group, application)) - expect(application).to have_attributes(create_params.except(:uid, :owner_type)) - end - end - - context 'with hash_oauth_secrets flag on' do - before do - stub_feature_flags(hash_oauth_secrets: true) - end - - it 'creates a confidential application' do - create_params = attributes_for(:application, confidential: true, scopes: ['read_user']) - - expect do - post :create, params: { group_id: group, doorkeeper_application: create_params } - end.to change { Doorkeeper::Application.count }.by(1) + expect do + post :create, params: { group_id: group, doorkeeper_application: create_params } + end.to change { Doorkeeper::Application.count }.by(1) - application = Doorkeeper::Application.last + application = Doorkeeper::Application.last - expect(response).to have_gitlab_http_status(:ok) - expect(response).to render_template :show - expect(application).to have_attributes(create_params.except(:uid, :owner_type)) - end + expect(response).to have_gitlab_http_status(:ok) + expect(response).to render_template :show + expect(application).to have_attributes(create_params.except(:uid, :owner_type)) end end @@ -188,6 +138,61 @@ RSpec.describe Groups::Settings::ApplicationsController do end end + describe 'PUT #renew' do + context 'when user is owner' do + before do + group.add_owner(user) + end + + let(:oauth_params) do + { + group_id: group, + id: application.id + } + end + + subject { put :renew, params: oauth_params } + + it { is_expected.to have_gitlab_http_status(:ok) } + it { expect { subject }.to change { application.reload.secret } } + + it 'returns the secret in json format' do + subject + + expect(json_response['secret']).not_to be_nil + end + + context 'when renew fails' do + before do + allow_next_found_instance_of(Doorkeeper::Application) do |application| + allow(application).to receive(:save).and_return(false) + end + end + + it { expect { subject }.not_to change { application.reload.secret } } + it { is_expected.to have_gitlab_http_status(:unprocessable_entity) } + end + end + + context 'when user is not owner' do + before do + group.add_maintainer(user) + end + + let(:oauth_params) do + { + group_id: group, + id: application.id + } + end + + it 'renders a 404' do + put :renew, params: oauth_params + expect(response).to have_gitlab_http_status(:not_found) + end + end + end + describe 'PATCH #update' do context 'when user is owner' do before do diff --git a/spec/controllers/groups/settings/integrations_controller_spec.rb b/spec/controllers/groups/settings/integrations_controller_spec.rb index 377c38ce087..3ae43c8ab7c 100644 --- a/spec/controllers/groups/settings/integrations_controller_spec.rb +++ b/spec/controllers/groups/settings/integrations_controller_spec.rb @@ -7,6 +7,7 @@ RSpec.describe Groups::Settings::IntegrationsController do let_it_be(:group) { create(:group) } before do + stub_feature_flags(remove_monitor_metrics: false) sign_in(user) end diff --git a/spec/controllers/groups/variables_controller_spec.rb b/spec/controllers/groups/variables_controller_spec.rb index 6dbe75bb1df..8c6efae89c3 100644 --- a/spec/controllers/groups/variables_controller_spec.rb +++ b/spec/controllers/groups/variables_controller_spec.rb @@ -77,12 +77,10 @@ RSpec.describe Groups::VariablesController do describe 'PATCH #update' do it 'is successful' do - patch :update, - params: { - group_id: group, - variables_attributes: [{ id: variable.id, key: 'hello' }] - }, - format: :json + patch :update, params: { + group_id: group, + variables_attributes: [{ id: variable.id, key: 'hello' }] + }, format: :json expect(response).to have_gitlab_http_status(:ok) end diff --git a/spec/controllers/groups_controller_spec.rb b/spec/controllers/groups_controller_spec.rb index 9184cd2263e..8617cc8af8f 100644 --- a/spec/controllers/groups_controller_spec.rb +++ b/spec/controllers/groups_controller_spec.rb @@ -152,29 +152,6 @@ RSpec.describe GroupsController, factory_default: :keep, feature_category: :code end end end - - describe 'require_verification_for_namespace_creation experiment', :experiment do - before do - sign_in(owner) - stub_experiments(require_verification_for_namespace_creation: :candidate) - end - - it 'tracks a "start_create_group" event' do - expect(experiment(:require_verification_for_namespace_creation)).to track( - :start_create_group - ).on_next_instance.with_context(user: owner) - - get :new - end - - context 'when creating a sub-group' do - it 'does not track a "start_create_group" event' do - expect(experiment(:require_verification_for_namespace_creation)).not_to track(:start_create_group) - - get :new, params: { parent_id: group.id } - end - end - end end describe 'GET #activity' do diff --git a/spec/controllers/help_controller_spec.rb b/spec/controllers/help_controller_spec.rb index 2375146f346..056df213209 100644 --- a/spec/controllers/help_controller_spec.rb +++ b/spec/controllers/help_controller_spec.rb @@ -181,6 +181,7 @@ RSpec.describe HelpController do context 'when requested file exists' do before do stub_doc_file_read(file_name: 'user/ssh.md', content: fixture_file('blockquote_fence_after.md')) + stub_application_setting(help_page_documentation_base_url: '') subject end @@ -223,13 +224,13 @@ RSpec.describe HelpController do context 'when gitlab_docs is disabled' do let(:docs_enabled) { false } - it_behaves_like 'documentation pages local render' + it_behaves_like 'documentation pages redirect', 'https://docs.gitlab.com' end context 'when host is missing' do let(:host) { nil } - it_behaves_like 'documentation pages local render' + it_behaves_like 'documentation pages redirect', 'https://docs.gitlab.com' end end @@ -251,6 +252,10 @@ RSpec.describe HelpController do end context 'when requested file is missing' do + before do + stub_application_setting(help_page_documentation_base_url: '') + end + it 'renders not found' do get :show, params: { path: 'foo/bar' }, format: :md expect(response).to be_not_found @@ -261,11 +266,7 @@ RSpec.describe HelpController do context 'for image formats' do context 'when requested file exists' do it 'renders the raw file' do - get :show, - params: { - path: 'user/img/markdown_logo' - }, - format: :png + get :show, params: { path: 'user/img/markdown_logo' }, format: :png aggregate_failures do expect(response).to be_successful @@ -277,11 +278,7 @@ RSpec.describe HelpController do context 'when requested file is missing' do it 'renders not found' do - get :show, - params: { - path: 'foo/bar' - }, - format: :png + get :show, params: { path: 'foo/bar' }, format: :png expect(response).to be_not_found end end @@ -289,11 +286,7 @@ RSpec.describe HelpController do context 'for other formats' do it 'always renders not found' do - get :show, - params: { - path: 'user/ssh' - }, - format: :foo + get :show, params: { path: 'user/ssh' }, format: :foo expect(response).to be_not_found end end diff --git a/spec/controllers/import/bitbucket_controller_spec.rb b/spec/controllers/import/bitbucket_controller_spec.rb index 35f712dc50d..906cc5cb336 100644 --- a/spec/controllers/import/bitbucket_controller_spec.rb +++ b/spec/controllers/import/bitbucket_controller_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' -RSpec.describe Import::BitbucketController do +RSpec.describe Import::BitbucketController, feature_category: :importers do include ImportSpecHelper let(:user) { create(:user) } @@ -48,11 +48,13 @@ RSpec.describe Import::BitbucketController do let(:expires_at) { Time.current + 1.day } let(:expires_in) { 1.day } let(:access_token) do - double(token: token, - secret: secret, - expires_at: expires_at, - expires_in: expires_in, - refresh_token: refresh_token) + double( + token: token, + secret: secret, + expires_at: expires_at, + expires_in: expires_in, + refresh_token: refresh_token + ) end before do @@ -63,10 +65,10 @@ RSpec.describe Import::BitbucketController do allow_any_instance_of(OAuth2::Client) .to receive(:get_token) .with(hash_including( - 'grant_type' => 'authorization_code', - 'code' => code, - 'redirect_uri' => users_import_bitbucket_callback_url), - {}) + 'grant_type' => 'authorization_code', + 'code' => code, + 'redirect_uri' => users_import_bitbucket_callback_url), + {}) .and_return(access_token) stub_omniauth_provider('bitbucket') @@ -443,5 +445,16 @@ RSpec.describe Import::BitbucketController do ) end end + + context 'when user can not import projects' do + let!(:other_namespace) { create(:group, name: 'other_namespace').tap { |other_namespace| other_namespace.add_developer(user) } } + + it 'returns 422 response' do + post :create, params: { target_namespace: other_namespace.name }, format: :json + + expect(response).to have_gitlab_http_status(:unprocessable_entity) + expect(response.parsed_body['errors']).to eq('You are not allowed to import projects in this namespace.') + end + end end end diff --git a/spec/controllers/import/bitbucket_server_controller_spec.rb b/spec/controllers/import/bitbucket_server_controller_spec.rb index ac56d3af54f..b2a56423253 100644 --- a/spec/controllers/import/bitbucket_server_controller_spec.rb +++ b/spec/controllers/import/bitbucket_server_controller_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' -RSpec.describe Import::BitbucketServerController do +RSpec.describe Import::BitbucketServerController, feature_category: :importers do let(:user) { create(:user) } let(:project_key) { 'test-project' } let(:repo_slug) { 'some-repo' } diff --git a/spec/controllers/import/bulk_imports_controller_spec.rb b/spec/controllers/import/bulk_imports_controller_spec.rb index a3992ae850e..c5e5aa03669 100644 --- a/spec/controllers/import/bulk_imports_controller_spec.rb +++ b/spec/controllers/import/bulk_imports_controller_spec.rb @@ -121,12 +121,12 @@ RSpec.describe Import::BulkImportsController, feature_category: :importers do params = { page: 1, per_page: 20, filter: '' }.merge(params_override) get :status, - params: params, - format: format, - session: { - bulk_import_gitlab_url: 'https://gitlab.example.com', - bulk_import_gitlab_access_token: 'demo-pat' - } + params: params, + format: format, + session: { + bulk_import_gitlab_url: 'https://gitlab.example.com', + bulk_import_gitlab_access_token: 'demo-pat' + } end include_context 'bulk imports requests context', 'https://gitlab.example.com' @@ -157,8 +157,7 @@ RSpec.describe Import::BulkImportsController, feature_category: :importers do end let(:source_version) do - Gitlab::VersionInfo.new(::BulkImport::MIN_MAJOR_VERSION, - ::BulkImport::MIN_MINOR_VERSION_FOR_PROJECT) + Gitlab::VersionInfo.new(::BulkImport::MIN_MAJOR_VERSION, ::BulkImport::MIN_MINOR_VERSION_FOR_PROJECT) end before do @@ -214,36 +213,41 @@ RSpec.describe Import::BulkImportsController, feature_category: :importers do end end - context 'when host url is local or not http' do - %w[https://localhost:3000 http://192.168.0.1 ftp://testing].each do |url| - before do - stub_application_setting(allow_local_requests_from_web_hooks_and_services: false) - - session[:bulk_import_gitlab_access_token] = 'test' - session[:bulk_import_gitlab_url] = url - end + shared_examples 'unacceptable url' do |url, expected_error| + before do + stub_application_setting(allow_local_requests_from_web_hooks_and_services: false) - it 'denies network request' do - get :status + session[:bulk_import_gitlab_access_token] = 'test' + session[:bulk_import_gitlab_url] = url + end - expect(controller).to redirect_to(new_group_path(anchor: 'import-group-pane')) - expect(flash[:alert]).to eq('Specified URL cannot be used: "Only allowed schemes are http, https"') - end + it 'denies network request' do + get :status + expect(controller).to redirect_to(new_group_path(anchor: 'import-group-pane')) + expect(flash[:alert]).to eq("Specified URL cannot be used: \"#{expected_error}\"") end + end + + context 'when host url is local or not http' do + include_examples 'unacceptable url', 'https://localhost:3000', "Only allowed schemes are http, https" + include_examples 'unacceptable url', 'http://192.168.0.1', "Only allowed schemes are http, https" + include_examples 'unacceptable url', 'ftp://testing', "Only allowed schemes are http, https" context 'when local requests are allowed' do %w[https://localhost:3000 http://192.168.0.1].each do |url| - before do - stub_application_setting(allow_local_requests_from_web_hooks_and_services: true) + context "with #{url}" do + before do + stub_application_setting(allow_local_requests_from_web_hooks_and_services: true) - session[:bulk_import_gitlab_access_token] = 'test' - session[:bulk_import_gitlab_url] = url - end + session[:bulk_import_gitlab_access_token] = 'test' + session[:bulk_import_gitlab_url] = url + end - it 'allows network request' do - get :status + it 'allows network request' do + get :status - expect(response).to have_gitlab_http_status(:ok) + expect(response).to have_gitlab_http_status(:ok) + end end end end @@ -270,8 +274,7 @@ RSpec.describe Import::BulkImportsController, feature_category: :importers do context 'when connection error occurs' do let(:source_version) do - Gitlab::VersionInfo.new(::BulkImport::MIN_MAJOR_VERSION, - ::BulkImport::MIN_MINOR_VERSION_FOR_PROJECT) + Gitlab::VersionInfo.new(::BulkImport::MIN_MAJOR_VERSION, ::BulkImport::MIN_MINOR_VERSION_FOR_PROJECT) end before do diff --git a/spec/controllers/import/fogbugz_controller_spec.rb b/spec/controllers/import/fogbugz_controller_spec.rb index ed2a588eadf..3b099ba2613 100644 --- a/spec/controllers/import/fogbugz_controller_spec.rb +++ b/spec/controllers/import/fogbugz_controller_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' -RSpec.describe Import::FogbugzController do +RSpec.describe Import::FogbugzController, feature_category: :importers do include ImportSpecHelper let(:user) { create(:user) } @@ -11,6 +11,8 @@ RSpec.describe Import::FogbugzController do let(:namespace_id) { 5 } before do + stub_application_setting(import_sources: ['fogbugz']) + sign_in(user) end @@ -116,8 +118,7 @@ RSpec.describe Import::FogbugzController do describe 'GET status' do let(:repo) do - instance_double(Gitlab::FogbugzImport::Repository, - id: 'demo', name: 'vim', safe_name: 'vim', path: 'vim') + instance_double(Gitlab::FogbugzImport::Repository, id: 'demo', name: 'vim', safe_name: 'vim', path: 'vim') end it 'redirects to new page form when client is invalid' do diff --git a/spec/controllers/import/gitea_controller_spec.rb b/spec/controllers/import/gitea_controller_spec.rb index 568712d29cb..3dfda909a93 100644 --- a/spec/controllers/import/gitea_controller_spec.rb +++ b/spec/controllers/import/gitea_controller_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' -RSpec.describe Import::GiteaController do +RSpec.describe Import::GiteaController, feature_category: :importers do include ImportSpecHelper let(:provider) { :gitea } @@ -10,6 +10,10 @@ RSpec.describe Import::GiteaController do include_context 'a GitHub-ish import controller' + before do + stub_application_setting(import_sources: ['gitea']) + end + def assign_host_url session[:gitea_host_url] = host_url end @@ -42,19 +46,23 @@ RSpec.describe Import::GiteaController do expect(response).to have_gitlab_http_status(:ok) end - context 'when host url is local or not http' do - %w[https://localhost:3000 http://192.168.0.1 ftp://testing].each do |url| - let(:host_url) { url } + shared_examples "unacceptable url" do |url, expected_error| + let(:host_url) { url } - it 'denies network request' do - get :status, format: :json + it 'denies network request' do + get :status, format: :json - expect(controller).to redirect_to(new_import_url) - expect(flash[:alert]).to eq('Specified URL cannot be used: "Only allowed schemes are http, https"') - end + expect(controller).to redirect_to(new_import_url) + expect(flash[:alert]).to eq("Specified URL cannot be used: \"#{expected_error}\"") end end + context 'when host url is local or not http' do + include_examples 'unacceptable url', 'https://localhost:3000', 'Only allowed schemes are http, https' + include_examples 'unacceptable url', 'http://192.168.0.1', 'Only allowed schemes are http, https' + include_examples 'unacceptable url', 'ftp://testing', 'Only allowed schemes are http, https' + end + context 'when DNS Rebinding protection is enabled' do let(:token) { 'gitea token' } diff --git a/spec/controllers/import/github_controller_spec.rb b/spec/controllers/import/github_controller_spec.rb index 406a3604b23..fdc0ddda9f4 100644 --- a/spec/controllers/import/github_controller_spec.rb +++ b/spec/controllers/import/github_controller_spec.rb @@ -139,7 +139,7 @@ RSpec.describe Import::GithubController, feature_category: :importers do expect_next_instance_of(Gitlab::GithubImport::Clients::Proxy) do |client| expect(client).to receive(:repos) .with(expected_filter, expected_options) - .and_return({ repos: [], page_info: {} }) + .and_return({ repos: [], page_info: {}, count: 0 }) end get :status, params: params, format: :json @@ -149,6 +149,7 @@ RSpec.describe Import::GithubController, feature_category: :importers do expect(json_response['provider_repos'].size).to eq 0 expect(json_response['incompatible_repos'].size).to eq 0 expect(json_response['page_info']).to eq({}) + expect(json_response['provider_repo_count']).to eq(0) end end @@ -161,9 +162,7 @@ RSpec.describe Import::GithubController, feature_category: :importers do let(:provider_repos) { [] } let(:expected_filter) { '' } let(:expected_options) do - pagination_params.merge(relation_params).merge( - first: 25, page: 1, per_page: 25 - ) + pagination_params.merge(relation_params).merge(first: 25) end before do @@ -171,6 +170,9 @@ RSpec.describe Import::GithubController, feature_category: :importers do if client_auth_success allow(proxy).to receive(:repos).and_return({ repos: provider_repos }) allow(proxy).to receive(:client).and_return(client_stub) + allow_next_instance_of(Gitlab::GithubImport::ProjectRelationType) do |instance| + allow(instance).to receive(:for).with('example/repo').and_return('owned') + end else allow(proxy).to receive(:repos).and_raise(Octokit::Unauthorized) end @@ -279,22 +281,12 @@ RSpec.describe Import::GithubController, feature_category: :importers do it_behaves_like 'calls repos through Clients::Proxy with expected args' end - - context 'when page is specified' do - let(:pagination_params) { { before: nil, after: nil, page: 2 } } - let(:params) { pagination_params } - let(:expected_options) do - pagination_params.merge(relation_params).merge(first: 25, page: 2, per_page: 25) - end - - it_behaves_like 'calls repos through Clients::Proxy with expected args' - end end context 'when relation type params present' do let(:organization_login) { 'test-login' } let(:params) { pagination_params.merge(relation_type: 'organization', organization_login: organization_login) } - let(:pagination_defaults) { { first: 25, page: 1, per_page: 25 } } + let(:pagination_defaults) { { first: 25 } } let(:expected_options) do pagination_defaults.merge(pagination_params).merge( relation_type: 'organization', organization_login: organization_login @@ -359,7 +351,13 @@ RSpec.describe Import::GithubController, feature_category: :importers do end end - describe "POST create" do + describe "POST create", :clean_gitlab_redis_cache do + before do + allow_next_instance_of(Gitlab::GithubImport::ProjectRelationType) do |instance| + allow(instance).to receive(:for).with("#{provider_username}/vim").and_return('owned') + end + end + it_behaves_like 'a GitHub-ish import controller: POST create' it_behaves_like 'project import rate limiter' @@ -387,14 +385,74 @@ RSpec.describe Import::GithubController, feature_category: :importers do end end + describe "GET failures" do + let_it_be_with_reload(:project) { create(:project, import_type: 'github', import_status: :started, import_source: 'example/repo', import_url: 'https://fake.url') } + let!(:import_failure) do + create(:import_failure, + project: project, + source: 'Gitlab::GithubImport::Importer::PullRequestImporter', + external_identifiers: { iid: 2, object_type: 'pull_request', title: 'My Pull Request' } + ) + end + + context 'when import is not finished' do + it 'return bad_request' do + get :failures, params: { project_id: project.id } + + expect(response).to have_gitlab_http_status(:bad_request) + expect(json_response['message']).to eq('The import is not complete.') + end + end + + context 'when import is finished' do + before do + project.import_state.finish + end + + it 'includes failure details in response' do + get :failures, params: { project_id: project.id } + + expect(json_response[0]['type']).to eq('pull_request') + expect(json_response[0]['title']).to eq('My Pull Request') + expect(json_response[0]['provider_url']).to eq("https://fake.url/example/repo/pull/2") + expect(json_response[0]['details']['source']).to eq(import_failure.source) + end + + it 'paginates records' do + issue_title = 'My Issue' + + create( + :import_failure, + project: project, + source: 'Gitlab::GithubImport::Importer::IssueAndLabelLinksImporter', + external_identifiers: { iid: 3, object_type: 'issue', title: issue_title } + ) + + get :failures, params: { project_id: project.id, page: 2, per_page: 1 } + + expect(json_response.size).to eq(1) + expect(json_response.first['title']).to eq(issue_title) + end + end + end + describe "POST cancel" do - let_it_be(:project) { create(:project, :import_started, import_type: 'github', import_url: 'https://fake.url') } + let_it_be(:project) do + create( + :project, :import_started, + import_type: 'github', import_url: 'https://fake.url', import_source: 'login/repo' + ) + end context 'when project import was canceled' do before do allow(Import::Github::CancelProjectImportService) .to receive(:new).with(project, user) .and_return(double(execute: { status: :success, project: project })) + + allow_next_instance_of(Gitlab::GithubImport::ProjectRelationType) do |instance| + allow(instance).to receive(:for).with('login/repo').and_return('owned') + end end it 'returns success' do @@ -471,4 +529,26 @@ RSpec.describe Import::GithubController, feature_category: :importers do end end end + + describe 'GET counts' do + let(:expected_result) do + { + 'owned' => 3, + 'collaborated' => 2, + 'organization' => 1 + } + end + + it 'returns repos count by type' do + expect_next_instance_of(Gitlab::GithubImport::Clients::Proxy) do |client_proxy| + expect(client_proxy).to receive(:count_repos_by).with('owned', user.id).and_return(3) + expect(client_proxy).to receive(:count_repos_by).with('collaborated', user.id).and_return(2) + expect(client_proxy).to receive(:count_repos_by).with('organization', user.id).and_return(1) + end + + get :counts + + expect(json_response).to eq(expected_result) + end + end end diff --git a/spec/controllers/import/gitlab_controller_spec.rb b/spec/controllers/import/gitlab_controller_spec.rb deleted file mode 100644 index 7b3978297fb..00000000000 --- a/spec/controllers/import/gitlab_controller_spec.rb +++ /dev/null @@ -1,313 +0,0 @@ -# frozen_string_literal: true - -require 'spec_helper' - -RSpec.describe Import::GitlabController do - include ImportSpecHelper - - let(:user) { create(:user) } - let(:token) { "asdasd12345" } - let(:access_params) { { gitlab_access_token: token } } - - def assign_session_token - session[:gitlab_access_token] = token - end - - before do - sign_in(user) - allow(controller).to receive(:gitlab_import_enabled?).and_return(true) - end - - describe "GET callback" do - it "updates access token" do - allow_next_instance_of(Gitlab::GitlabImport::Client) do |instance| - allow(instance).to receive(:get_token).and_return(token) - end - stub_omniauth_provider('gitlab') - - get :callback - - expect(session[:gitlab_access_token]).to eq(token) - expect(controller).to redirect_to(status_import_gitlab_url) - end - - it "importable_repos should return an array" do - allow_next_instance_of(Gitlab::GitlabImport::Client) do |instance| - allow(instance).to receive(:projects).and_return([{ "id": 1 }].to_enum) - end - - expect(controller.send(:importable_repos)).to be_an_instance_of(Array) - end - - it "passes namespace_id query param to status if provided" do - namespace_id = 30 - - allow_next_instance_of(Gitlab::GitlabImport::Client) do |instance| - allow(instance).to receive(:get_token).and_return(token) - end - - get :callback, params: { namespace_id: namespace_id } - - expect(controller).to redirect_to(status_import_gitlab_url(namespace_id: namespace_id)) - end - end - - describe "GET status" do - let(:repo_fake) { Struct.new(:id, :path, :path_with_namespace, :web_url, keyword_init: true) } - let(:repo) { repo_fake.new(id: 1, path: 'vim', path_with_namespace: 'asd/vim', web_url: 'https://gitlab.com/asd/vim') } - - context 'when session contains access token' do - before do - assign_session_token - end - - it_behaves_like 'import controller status' do - let(:repo_id) { repo.id } - let(:import_source) { repo.path_with_namespace } - let(:provider_name) { 'gitlab' } - let(:client_repos_field) { :projects } - end - end - - it 'redirects to auth if session does not contain access token' do - remote_gitlab_url = 'https://test.host/auth/gitlab' - - allow(Gitlab::GitlabImport::Client) - .to receive(:new) - .and_return(double(authorize_url: remote_gitlab_url)) - - get :status - - expect(response).to redirect_to(remote_gitlab_url) - end - end - - describe "POST create" do - let(:project) { create(:project) } - let(:gitlab_username) { user.username } - let(:gitlab_user) do - { username: gitlab_username }.with_indifferent_access - end - - let(:gitlab_repo) do - { - path: 'vim', - path_with_namespace: "#{gitlab_username}/vim", - owner: { name: gitlab_username }, - namespace: { path: gitlab_username } - }.with_indifferent_access - end - - before do - stub_client(user: gitlab_user, project: gitlab_repo) - assign_session_token - end - - it 'returns 200 response when the project is imported successfully' do - allow(Gitlab::GitlabImport::ProjectCreator) - .to receive(:new).with(gitlab_repo, user.namespace, user, access_params) - .and_return(double(execute: project)) - - post :create, format: :json - - expect(response).to have_gitlab_http_status(:ok) - end - - it 'returns 422 response when the project could not be imported' do - allow(Gitlab::GitlabImport::ProjectCreator) - .to receive(:new).with(gitlab_repo, user.namespace, user, access_params) - .and_return(double(execute: build(:project))) - - post :create, format: :json - - expect(response).to have_gitlab_http_status(:unprocessable_entity) - end - - context "when the repository owner is the GitLab.com user" do - context "when the GitLab.com user and GitLab server user's usernames match" do - it "takes the current user's namespace" do - expect(Gitlab::GitlabImport::ProjectCreator) - .to receive(:new).with(gitlab_repo, user.namespace, user, access_params) - .and_return(double(execute: project)) - - post :create, format: :json - end - end - - context "when the GitLab.com user and GitLab server user's usernames don't match" do - let(:gitlab_username) { "someone_else" } - - it "takes the current user's namespace" do - expect(Gitlab::GitlabImport::ProjectCreator) - .to receive(:new).with(gitlab_repo, user.namespace, user, access_params) - .and_return(double(execute: project)) - - post :create, format: :json - end - end - end - - context "when the repository owner is not the GitLab.com user" do - let(:other_username) { "someone_else" } - - before do - gitlab_repo["namespace"]["path"] = other_username - assign_session_token - end - - context "when a namespace with the GitLab.com user's username already exists" do - let!(:existing_namespace) { create(:group, name: other_username) } - - context "when the namespace is owned by the GitLab server user" do - before do - existing_namespace.add_owner(user) - end - - it "takes the existing namespace" do - expect(Gitlab::GitlabImport::ProjectCreator) - .to receive(:new).with(gitlab_repo, existing_namespace, user, access_params) - .and_return(double(execute: project)) - - post :create, format: :json - end - end - - context "when the namespace is not owned by the GitLab server user" do - it "doesn't create a project" do - expect(Gitlab::GitlabImport::ProjectCreator) - .not_to receive(:new) - - post :create, format: :json - end - end - end - - context "when a namespace with the GitLab.com user's username doesn't exist" do - context "when current user can create namespaces" do - it "creates the namespace" do - expect(Gitlab::GitlabImport::ProjectCreator) - .to receive(:new).and_return(double(execute: project)) - - expect { post :create, format: :json }.to change(Namespace, :count).by(1) - end - - it "takes the new namespace" do - expect(Gitlab::GitlabImport::ProjectCreator) - .to receive(:new).with(gitlab_repo, an_instance_of(Group), user, access_params) - .and_return(double(execute: project)) - - post :create, format: :json - end - end - - context "when current user can't create namespaces" do - before do - user.update_attribute(:can_create_group, false) - end - - it "doesn't create the namespace" do - expect(Gitlab::GitlabImport::ProjectCreator) - .to receive(:new).and_return(double(execute: project)) - - expect { post :create, format: :json }.not_to change(Namespace, :count) - end - - it "takes the current user's namespace" do - expect(Gitlab::GitlabImport::ProjectCreator) - .to receive(:new).with(gitlab_repo, user.namespace, user, access_params) - .and_return(double(execute: project)) - - post :create, format: :json - end - end - end - - context 'user has chosen an existing nested namespace for the project' do - let(:parent_namespace) { create(:group, name: 'foo') } - let(:nested_namespace) { create(:group, name: 'bar', parent: parent_namespace) } - - before do - parent_namespace.add_owner(user) - nested_namespace.add_owner(user) - end - - it 'takes the selected namespace and name' do - expect(Gitlab::GitlabImport::ProjectCreator) - .to receive(:new).with(gitlab_repo, nested_namespace, user, access_params) - .and_return(double(execute: project)) - - post :create, params: { target_namespace: nested_namespace.full_path }, format: :json - end - end - - context 'user has chosen a non-existent nested namespaces for the project' do - let(:test_name) { 'test_name' } - - it 'takes the selected namespace and name' do - expect(Gitlab::GitlabImport::ProjectCreator) - .to receive(:new).with(gitlab_repo, kind_of(Namespace), user, access_params) - .and_return(double(execute: project)) - - post :create, params: { target_namespace: 'foo/bar' }, format: :json - end - - it 'creates the namespaces' do - allow(Gitlab::GitlabImport::ProjectCreator) - .to receive(:new).with(gitlab_repo, kind_of(Namespace), user, access_params) - .and_return(double(execute: project)) - - expect { post :create, params: { target_namespace: 'foo/bar' }, format: :json } - .to change { Namespace.count }.by(2) - end - - it 'new namespace has the right parent' do - allow(Gitlab::GitlabImport::ProjectCreator) - .to receive(:new).with(gitlab_repo, kind_of(Namespace), user, access_params) - .and_return(double(execute: project)) - - post :create, params: { target_namespace: 'foo/bar' }, format: :json - - expect(Namespace.find_by_path_or_name('bar').parent.path).to eq('foo') - end - end - - context 'user has chosen existent and non-existent nested namespaces and name for the project' do - let(:test_name) { 'test_name' } - let!(:parent_namespace) { create(:group, name: 'foo') } - - before do - parent_namespace.add_owner(user) - end - - it 'takes the selected namespace and name' do - expect(Gitlab::GitlabImport::ProjectCreator) - .to receive(:new).with(gitlab_repo, kind_of(Namespace), user, access_params) - .and_return(double(execute: project)) - - post :create, params: { target_namespace: 'foo/foobar/bar' }, format: :json - end - - it 'creates the namespaces' do - allow(Gitlab::GitlabImport::ProjectCreator) - .to receive(:new).with(gitlab_repo, kind_of(Namespace), user, access_params) - .and_return(double(execute: project)) - - expect { post :create, params: { target_namespace: 'foo/foobar/bar' }, format: :json } - .to change { Namespace.count }.by(2) - end - end - - context 'when user can not create projects in the chosen namespace' do - it 'returns 422 response' do - other_namespace = create(:group, name: 'other_namespace') - - post :create, params: { target_namespace: other_namespace.name }, format: :json - - expect(response).to have_gitlab_http_status(:unprocessable_entity) - end - end - - it_behaves_like 'project import rate limiter' - end - end -end diff --git a/spec/controllers/import/manifest_controller_spec.rb b/spec/controllers/import/manifest_controller_spec.rb index 6f805b44e89..69eb736375c 100644 --- a/spec/controllers/import/manifest_controller_spec.rb +++ b/spec/controllers/import/manifest_controller_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' -RSpec.describe Import::ManifestController, :clean_gitlab_redis_shared_state do +RSpec.describe Import::ManifestController, :clean_gitlab_redis_shared_state, feature_category: :importers do include ImportSpecHelper let_it_be(:user) { create(:user) } @@ -13,6 +13,8 @@ RSpec.describe Import::ManifestController, :clean_gitlab_redis_shared_state do end before do + stub_application_setting(import_sources: ['manifest']) + sign_in(user) end @@ -45,7 +47,7 @@ RSpec.describe Import::ManifestController, :clean_gitlab_redis_shared_state do end end - context 'when the user cannot create projects in the group' do + context 'when the user cannot import projects in the group' do it 'displays an error' do sign_in(create(:user)) diff --git a/spec/controllers/import/phabricator_controller_spec.rb b/spec/controllers/import/phabricator_controller_spec.rb deleted file mode 100644 index 9be85a40d82..00000000000 --- a/spec/controllers/import/phabricator_controller_spec.rb +++ /dev/null @@ -1,83 +0,0 @@ -# frozen_string_literal: true - -require 'spec_helper' - -RSpec.describe Import::PhabricatorController do - let(:current_user) { create(:user) } - - before do - sign_in current_user - end - - describe 'GET #new' do - subject { get :new } - - context 'when the import source is not available' do - before do - stub_application_setting(import_sources: []) - end - - it { is_expected.to have_gitlab_http_status(:not_found) } - end - - context 'when the import source is available' do - before do - stub_application_setting(import_sources: ['phabricator']) - end - - it { is_expected.to have_gitlab_http_status(:ok) } - end - end - - describe 'POST #create' do - subject(:post_create) { post :create, params: params } - - context 'with valid params' do - let(:params) do - { path: 'phab-import', - name: 'Phab import', - phabricator_server_url: 'https://phabricator.example.com', - api_token: 'hazaah', - namespace_id: current_user.namespace_id } - end - - it 'creates a project to import', :sidekiq_might_not_need_inline do - expect_next_instance_of(Gitlab::PhabricatorImport::Importer) do |importer| - expect(importer).to receive(:execute) - end - - expect { post_create }.to change { current_user.namespace.projects.reload.size }.from(0).to(1) - - expect(current_user.namespace.projects.last).to be_import - end - end - - context 'when an import param is missing' do - let(:params) do - { path: 'phab-import', - name: 'Phab import', - phabricator_server_url: nil, - api_token: 'hazaah', - namespace_id: current_user.namespace_id } - end - - it 'does not create the project' do - expect { post_create }.not_to change { current_user.namespace.projects.reload.size } - end - end - - context 'when a project param is missing' do - let(:params) do - { phabricator_server_url: 'https://phabricator.example.com', - api_token: 'hazaah', - namespace_id: current_user.namespace_id } - end - - it 'does not create the project' do - expect { post_create }.not_to change { current_user.namespace.projects.reload.size } - end - end - - it_behaves_like 'project import rate limiter' - end -end diff --git a/spec/controllers/invites_controller_spec.rb b/spec/controllers/invites_controller_spec.rb index b3b7753df61..f3b21e191c4 100644 --- a/spec/controllers/invites_controller_spec.rb +++ b/spec/controllers/invites_controller_spec.rb @@ -192,6 +192,26 @@ RSpec.describe InvitesController do expect(session[:invite_email]).to eq(member.invite_email) end + context 'with stored location for user' do + it 'stores the correct path for user' do + request + + expect(controller.stored_location_for(:user)).to eq(activity_project_path(member.source)) + end + + context 'with relative root' do + before do + stub_default_url_options(script_name: '/gitlab') + end + + it 'stores the correct path for user' do + request + + expect(controller.stored_location_for(:user)).to eq(activity_project_path(member.source)) + end + end + end + context 'when it is part of our invite email experiment' do let(:extra_params) { { invite_type: 'initial_email' } } diff --git a/spec/controllers/jira_connect/app_descriptor_controller_spec.rb b/spec/controllers/jira_connect/app_descriptor_controller_spec.rb index 4f8b2b90637..48b315646de 100644 --- a/spec/controllers/jira_connect/app_descriptor_controller_spec.rb +++ b/spec/controllers/jira_connect/app_descriptor_controller_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' -RSpec.describe JiraConnect::AppDescriptorController do +RSpec.describe JiraConnect::AppDescriptorController, feature_category: :integrations do describe '#show' do let(:descriptor) do json_response.deep_symbolize_keys diff --git a/spec/controllers/jira_connect/branches_controller_spec.rb b/spec/controllers/jira_connect/branches_controller_spec.rb index 45daf3b5309..1d3ddc2e33b 100644 --- a/spec/controllers/jira_connect/branches_controller_spec.rb +++ b/spec/controllers/jira_connect/branches_controller_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' -RSpec.describe JiraConnect::BranchesController do +RSpec.describe JiraConnect::BranchesController, feature_category: :integrations do describe '#new' do context 'when logged in' do let_it_be(:user) { create(:user) } @@ -17,7 +17,7 @@ RSpec.describe JiraConnect::BranchesController do expect(response).to be_successful expect(assigns(:new_branch_data)).to include( initial_branch_name: 'ACME-123-my-issue', - success_state_svg_path: start_with('/assets/illustrations/merge_requests-') + success_state_svg_path: start_with('/assets/illustrations/empty-state/empty-merge-requests-md-') ) end diff --git a/spec/controllers/jira_connect/events_controller_spec.rb b/spec/controllers/jira_connect/events_controller_spec.rb index 7da9eb7ac16..ffad3aa7b02 100644 --- a/spec/controllers/jira_connect/events_controller_spec.rb +++ b/spec/controllers/jira_connect/events_controller_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' -RSpec.describe JiraConnect::EventsController do +RSpec.describe JiraConnect::EventsController, feature_category: :integrations do shared_examples 'verifies asymmetric JWT token' do context 'when token is valid' do include_context 'valid JWT token' diff --git a/spec/controllers/jira_connect/subscriptions_controller_spec.rb b/spec/controllers/jira_connect/subscriptions_controller_spec.rb index e9c94f09c99..a05f18f1a16 100644 --- a/spec/controllers/jira_connect/subscriptions_controller_spec.rb +++ b/spec/controllers/jira_connect/subscriptions_controller_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' -RSpec.describe JiraConnect::SubscriptionsController do +RSpec.describe JiraConnect::SubscriptionsController, feature_category: :integrations do let_it_be(:installation) { create(:jira_connect_installation) } describe '#index' do @@ -56,26 +56,6 @@ RSpec.describe JiraConnect::SubscriptionsController do expect(json_response).to include('subscriptions_path' => jira_connect_subscriptions_path) end - context 'when not signed in to GitLab' do - it 'contains a login path' do - expect(json_response).to include('login_path' => jira_connect_users_path) - end - end - - context 'when signed in to GitLab' do - let(:user) { create(:user) } - - before do - sign_in(user) - - get :index, params: { jwt: jwt } - end - - it 'does not contain a login path' do - expect(json_response).to include('login_path' => nil) - end - end - context 'with context qsh' do # The JSON endpoint will be requested by frontend using a JWT that Atlassian provides via Javascript. # This JWT will likely use a context-qsh because Atlassian don't know for which endpoint it will be used. diff --git a/spec/controllers/oauth/applications_controller_spec.rb b/spec/controllers/oauth/applications_controller_spec.rb index 9b16dc9a463..5b9fd192ad4 100644 --- a/spec/controllers/oauth/applications_controller_spec.rb +++ b/spec/controllers/oauth/applications_controller_spec.rb @@ -71,6 +71,39 @@ RSpec.describe Oauth::ApplicationsController do it_behaves_like 'redirects to 2fa setup page when the user requires it' end + describe 'PUT #renew' do + let(:oauth_params) do + { + id: application.id + } + end + + subject { put :renew, params: oauth_params } + + it { is_expected.to have_gitlab_http_status(:ok) } + it { expect { subject }.to change { application.reload.secret } } + + it_behaves_like 'redirects to login page when the user is not signed in' + it_behaves_like 'redirects to 2fa setup page when the user requires it' + + it 'returns the secret in json format' do + subject + + expect(json_response['secret']).not_to be_nil + end + + context 'when renew fails' do + before do + allow_next_found_instance_of(Doorkeeper::Application) do |application| + allow(application).to receive(:save).and_return(false) + end + end + + it { expect { subject }.not_to change { application.reload.secret } } + it { is_expected.to have_gitlab_http_status(:unprocessable_entity) } + end + end + describe 'GET #show' do subject { get :show, params: { id: application.id } } @@ -113,30 +146,11 @@ RSpec.describe Oauth::ApplicationsController do subject { post :create, params: oauth_params } - context 'when hash_oauth_tokens flag set' do - before do - stub_feature_flags(hash_oauth_secrets: true) - end - - it 'creates an application' do - subject - - expect(response).to have_gitlab_http_status(:ok) - expect(response).to render_template :show - end - end - - context 'when hash_oauth_tokens flag not set' do - before do - stub_feature_flags(hash_oauth_secrets: false) - end - - it 'creates an application' do - subject + it 'creates an application' do + subject - expect(response).to have_gitlab_http_status(:found) - expect(response).to redirect_to(oauth_application_path(Doorkeeper::Application.last)) - end + expect(response).to have_gitlab_http_status(:ok) + expect(response).to render_template :show end it 'redirects back to profile page if OAuth applications are disabled' do diff --git a/spec/controllers/oauth/authorizations_controller_spec.rb b/spec/controllers/oauth/authorizations_controller_spec.rb index 5185aa64d9f..3476c7b8465 100644 --- a/spec/controllers/oauth/authorizations_controller_spec.rb +++ b/spec/controllers/oauth/authorizations_controller_spec.rb @@ -7,8 +7,7 @@ RSpec.describe Oauth::AuthorizationsController do let(:application_scopes) { 'api read_user' } let!(:application) do - create(:oauth_application, scopes: application_scopes, - redirect_uri: 'http://example.com') + create(:oauth_application, scopes: application_scopes, redirect_uri: 'http://example.com') end let(:params) do diff --git a/spec/controllers/omniauth_callbacks_controller_spec.rb b/spec/controllers/omniauth_callbacks_controller_spec.rb index ab3f3fd397d..ebfa48870a9 100644 --- a/spec/controllers/omniauth_callbacks_controller_spec.rb +++ b/spec/controllers/omniauth_callbacks_controller_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' -RSpec.describe OmniauthCallbacksController, type: :controller do +RSpec.describe OmniauthCallbacksController, type: :controller, feature_category: :system_access do include LoginHelpers describe 'omniauth' do @@ -202,20 +202,30 @@ RSpec.describe OmniauthCallbacksController, type: :controller do end end - context 'when user with 2FA is unconfirmed' do + context 'when a user has 2FA enabled' do render_views let(:user) { create(:omniauth_user, :two_factor, extern_uid: 'my-uid', provider: provider) } - before do - user.update_column(:confirmed_at, nil) - end + context 'when a user is unconfirmed' do + before do + stub_application_setting_enum('email_confirmation_setting', 'hard') - it 'redirects to login page' do - post provider + user.update!(confirmed_at: nil) + end + + it 'redirects to login page' do + post provider + + expect(response).to redirect_to(new_user_session_path) + expect(flash[:alert]).to match(/You have to confirm your email address before continuing./) + end + end - expect(response).to redirect_to(new_user_session_path) - expect(flash[:alert]).to match(/You have to confirm your email address before continuing./) + context 'when a user is confirmed' do + it 'returns 200 response' do + expect(response).to have_gitlab_http_status(:ok) + end end end @@ -324,9 +334,10 @@ RSpec.describe OmniauthCallbacksController, type: :controller do expect(controller).to receive(:atlassian_oauth2).and_wrap_original do |m, *args| m.call(*args) - expect(Gitlab::ApplicationContext.current) - .to include('meta.user' => user.username, - 'meta.caller_id' => 'OmniauthCallbacksController#atlassian_oauth2') + expect(Gitlab::ApplicationContext.current).to include( + 'meta.user' => user.username, + 'meta.caller_id' => 'OmniauthCallbacksController#atlassian_oauth2' + ) end post :atlassian_oauth2 @@ -419,6 +430,31 @@ RSpec.describe OmniauthCallbacksController, type: :controller do end end + describe '#openid_connect' do + let(:user) { create(:omniauth_user, extern_uid: extern_uid, provider: provider) } + let(:extern_uid) { 'my-uid' } + let(:provider) { 'openid_connect' } + + before do + prepare_provider_route('openid_connect') + + mock_auth_hash(provider, extern_uid, user.email, additional_info: {}) + + request.env['devise.mapping'] = Devise.mappings[:user] + request.env['omniauth.auth'] = Rails.application.env_config['omniauth.auth'] + end + + it_behaves_like 'known sign in' do + let(:post_action) { post provider } + end + + it 'allows sign in' do + post provider + + expect(request.env['warden']).to be_authenticated + end + end + describe '#saml' do let(:last_request_id) { 'ONELOGIN_4fee3b046395c4e751011e97f8900b5273d56685' } let(:user) { create(:omniauth_user, :two_factor, extern_uid: 'my-uid', provider: 'saml') } @@ -431,8 +467,12 @@ RSpec.describe OmniauthCallbacksController, type: :controller do before do stub_last_request_id(last_request_id) - stub_omniauth_saml_config(enabled: true, auto_link_saml_user: true, allow_single_sign_on: ['saml'], - providers: [saml_config]) + stub_omniauth_saml_config( + enabled: true, + auto_link_saml_user: true, + allow_single_sign_on: ['saml'], + providers: [saml_config] + ) mock_auth_hash_with_saml_xml('saml', +'my-uid', user.email, mock_saml_response) request.env['devise.mapping'] = Devise.mappings[:user] request.env['omniauth.auth'] = Rails.application.env_config['omniauth.auth'] @@ -523,9 +563,10 @@ RSpec.describe OmniauthCallbacksController, type: :controller do expect(controller).to receive(:saml).and_wrap_original do |m, *args| m.call(*args) - expect(Gitlab::ApplicationContext.current) - .to include('meta.user' => user.username, - 'meta.caller_id' => 'OmniauthCallbacksController#saml') + expect(Gitlab::ApplicationContext.current).to include( + 'meta.user' => user.username, + 'meta.caller_id' => 'OmniauthCallbacksController#saml' + ) end post :saml, params: { SAMLResponse: mock_saml_response } diff --git a/spec/controllers/passwords_controller_spec.rb b/spec/controllers/passwords_controller_spec.rb index 9494f55c631..aad946acad4 100644 --- a/spec/controllers/passwords_controller_spec.rb +++ b/spec/controllers/passwords_controller_spec.rb @@ -99,8 +99,7 @@ RSpec.describe PasswordsController do m.call(*args) expect(Gitlab::ApplicationContext.current) - .to include('meta.user' => user.username, - 'meta.caller_id' => 'PasswordsController#update') + .to include('meta.user' => user.username, 'meta.caller_id' => 'PasswordsController#update') end subject diff --git a/spec/controllers/profiles/accounts_controller_spec.rb b/spec/controllers/profiles/accounts_controller_spec.rb index ba349768b0f..f0ee2e178cf 100644 --- a/spec/controllers/profiles/accounts_controller_spec.rb +++ b/spec/controllers/profiles/accounts_controller_spec.rb @@ -16,18 +16,16 @@ RSpec.describe Profiles::AccountsController do expect(response).to have_gitlab_http_status(:not_found) end - [:saml, :cas3].each do |provider| - describe "#{provider} provider" do - let(:user) { create(:omniauth_user, provider: provider.to_s) } + describe "saml provider" do + let(:user) { create(:omniauth_user, provider: 'saml') } - it "does not allow to unlink connected account" do - identity = user.identities.last + it "does not allow to unlink connected account" do + identity = user.identities.last - delete :unlink, params: { provider: provider.to_s } + delete :unlink, params: { provider: 'saml' } - expect(response).to have_gitlab_http_status(:found) - expect(user.reload.identities).to include(identity) - end + expect(response).to have_gitlab_http_status(:found) + expect(user.reload.identities).to include(identity) end end diff --git a/spec/controllers/profiles/preferences_controller_spec.rb b/spec/controllers/profiles/preferences_controller_spec.rb index e2a216bb462..e2ade5e3de9 100644 --- a/spec/controllers/profiles/preferences_controller_spec.rb +++ b/spec/controllers/profiles/preferences_controller_spec.rb @@ -53,8 +53,7 @@ RSpec.describe Profiles::PreferencesController do first_day_of_week: '1', preferred_language: 'jp', tab_width: '5', - render_whitespace_in_code: 'true', - use_legacy_web_ide: 'true' + render_whitespace_in_code: 'true' }.with_indifferent_access expect(user).to receive(:assign_attributes).with(ActionController::Parameters.new(prefs).permit!) @@ -109,5 +108,33 @@ RSpec.describe Profiles::PreferencesController do expect(response.parsed_body['type']).to eq('alert') end end + + context 'on disable_follow_users feature flag' do + context 'with feature flag disabled' do + before do + stub_feature_flags(disable_follow_users: false) + end + + it 'does not update enabled_following preference of user' do + prefs = { enabled_following: false } + + go params: prefs + user.reload + + expect(user.enabled_following).to eq(true) + end + end + + context 'with feature flag enabled' do + it 'does not update enabled_following preference of user' do + prefs = { enabled_following: false } + + go params: prefs + user.reload + + expect(user.enabled_following).to eq(false) + end + end + end end end diff --git a/spec/controllers/profiles/two_factor_auths_controller_spec.rb b/spec/controllers/profiles/two_factor_auths_controller_spec.rb index 7d7cdededdb..dde0af3c543 100644 --- a/spec/controllers/profiles/two_factor_auths_controller_spec.rb +++ b/spec/controllers/profiles/two_factor_auths_controller_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' -RSpec.describe Profiles::TwoFactorAuthsController, feature_category: :authentication_and_authorization do +RSpec.describe Profiles::TwoFactorAuthsController, feature_category: :system_access do before do # `user` should be defined within the action-specific describe blocks sign_in(user) diff --git a/spec/controllers/profiles_controller_spec.rb b/spec/controllers/profiles_controller_spec.rb index daf0f36c28b..b1c43a33386 100644 --- a/spec/controllers/profiles_controller_spec.rb +++ b/spec/controllers/profiles_controller_spec.rb @@ -11,8 +11,7 @@ RSpec.describe ProfilesController, :request_store do sign_in(user) new_password = User.random_password expect do - post :update, - params: { user: { password: new_password, password_confirmation: new_password } } + post :update, params: { user: { password: new_password, password_confirmation: new_password } } end.not_to change { user.reload.encrypted_password } expect(response).to have_gitlab_http_status(:found) @@ -23,8 +22,7 @@ RSpec.describe ProfilesController, :request_store do it 'allows an email update from a user without an external email address' do sign_in(user) - put :update, - params: { user: { email: "john@gmail.com", name: "John", validation_password: password } } + put :update, params: { user: { email: "john@gmail.com", name: "John", validation_password: password } } user.reload @@ -37,8 +35,7 @@ RSpec.describe ProfilesController, :request_store do create(:email, :confirmed, user: user, email: 'john@gmail.com') sign_in(user) - put :update, - params: { user: { email: "john@gmail.com", name: "John" } } + put :update, params: { user: { email: "john@gmail.com", name: "John" } } user.reload @@ -54,8 +51,7 @@ RSpec.describe ProfilesController, :request_store do ldap_user.create_user_synced_attributes_metadata(provider: 'ldap', name_synced: true, email_synced: true) sign_in(ldap_user) - put :update, - params: { user: { email: "john@gmail.com", name: "John" } } + put :update, params: { user: { email: "john@gmail.com", name: "John" } } ldap_user.reload @@ -71,8 +67,7 @@ RSpec.describe ProfilesController, :request_store do ldap_user.create_user_synced_attributes_metadata(provider: 'ldap', name_synced: true, email_synced: true, location_synced: false) sign_in(ldap_user) - put :update, - params: { user: { email: "john@gmail.com", name: "John", location: "City, Country" } } + put :update, params: { user: { email: "john@gmail.com", name: "John", location: "City, Country" } } ldap_user.reload @@ -85,10 +80,7 @@ RSpec.describe ProfilesController, :request_store do it 'allows setting a user status', :freeze_time do sign_in(user) - put( - :update, - params: { user: { status: { message: 'Working hard!', availability: 'busy', clear_status_after: '8_hours' } } } - ) + put :update, params: { user: { status: { message: 'Working hard!', availability: 'busy', clear_status_after: '8_hours' } } } expect(user.reload.status.message).to eq('Working hard!') expect(user.reload.status.availability).to eq('busy') @@ -183,22 +175,14 @@ RSpec.describe ProfilesController, :request_store do end it 'updates a username using JSON request' do - put :update_username, - params: { - user: { username: new_username } - }, - format: :json + put :update_username, params: { user: { username: new_username } }, format: :json expect(response).to have_gitlab_http_status(:ok) expect(json_response['message']).to eq(s_('Profiles|Username successfully changed')) end it 'renders an error message when the username was not updated' do - put :update_username, - params: { - user: { username: 'invalid username.git' } - }, - format: :json + put :update_username, params: { user: { username: 'invalid username.git' } }, format: :json expect(response).to have_gitlab_http_status(:unprocessable_entity) expect(json_response['message']).to match(/Username change failed/) diff --git a/spec/controllers/projects/artifacts_controller_spec.rb b/spec/controllers/projects/artifacts_controller_spec.rb index c707b5dc39d..c7b74b5cf68 100644 --- a/spec/controllers/projects/artifacts_controller_spec.rb +++ b/spec/controllers/projects/artifacts_controller_spec.rb @@ -9,11 +9,13 @@ RSpec.describe Projects::ArtifactsController, feature_category: :build_artifacts let_it_be(:project) { create(:project, :repository, :public) } let_it_be(:pipeline, reload: true) do - create(:ci_pipeline, - project: project, - sha: project.commit.sha, - ref: project.default_branch, - status: 'success') + create( + :ci_pipeline, + project: project, + sha: project.commit.sha, + ref: project.default_branch, + status: 'success' + ) end let!(:job) { create(:ci_build, :success, :artifacts, pipeline: pipeline) } @@ -25,31 +27,13 @@ RSpec.describe Projects::ArtifactsController, feature_category: :build_artifacts describe 'GET index' do subject { get :index, params: { namespace_id: project.namespace, project_id: project } } - context 'when feature flag is on' do - render_views - - before do - stub_feature_flags(artifacts_management_page: true) - end - - it 'renders the page with data for the artifacts app' do - subject + render_views - expect(response).to have_gitlab_http_status(:ok) - expect(response).to render_template('projects/artifacts/index') - end - end - - context 'when feature flag is off' do - before do - stub_feature_flags(artifacts_management_page: false) - end - - it 'renders no content' do - subject + it 'renders the page with data for the artifacts app' do + subject - expect(response).to have_gitlab_http_status(:no_content) - end + expect(response).to have_gitlab_http_status(:ok) + expect(response).to render_template('projects/artifacts/index') end end @@ -177,9 +161,10 @@ RSpec.describe Projects::ArtifactsController, feature_category: :build_artifacts end it 'sends the codequality report' do - expect(controller).to receive(:send_file) - .with(job.job_artifacts_codequality.file.path, - hash_including(disposition: 'attachment', filename: filename)).and_call_original + expect(controller).to receive(:send_file).with( + job.job_artifacts_codequality.file.path, + hash_including(disposition: 'attachment', filename: filename) + ).and_call_original download_artifact(file_type: file_type) @@ -557,8 +542,7 @@ RSpec.describe Projects::ArtifactsController, feature_category: :build_artifacts context 'with regular branch' do before do - pipeline.update!(ref: 'master', - sha: project.commit('master').sha) + pipeline.update!(ref: 'master', sha: project.commit('master').sha) get :latest_succeeded, params: params_from_ref('master') end @@ -568,8 +552,7 @@ RSpec.describe Projects::ArtifactsController, feature_category: :build_artifacts context 'with branch name containing slash' do before do - pipeline.update!(ref: 'improve/awesome', - sha: project.commit('improve/awesome').sha) + pipeline.update!(ref: 'improve/awesome', sha: project.commit('improve/awesome').sha) get :latest_succeeded, params: params_from_ref('improve/awesome') end @@ -579,8 +562,7 @@ RSpec.describe Projects::ArtifactsController, feature_category: :build_artifacts context 'with branch name and path containing slashes' do before do - pipeline.update!(ref: 'improve/awesome', - sha: project.commit('improve/awesome').sha) + pipeline.update!(ref: 'improve/awesome', sha: project.commit('improve/awesome').sha) get :latest_succeeded, params: params_from_ref('improve/awesome', job.name, 'file/README.md') end @@ -596,11 +578,13 @@ RSpec.describe Projects::ArtifactsController, feature_category: :build_artifacts before do create_file_in_repo(project, 'master', 'master', 'test.txt', 'This is test') - create(:ci_pipeline, + create( + :ci_pipeline, project: project, sha: project.commit.sha, ref: project.default_branch, - status: 'failed') + status: 'failed' + ) get :latest_succeeded, params: params_from_ref(project.default_branch) end diff --git a/spec/controllers/projects/badges_controller_spec.rb b/spec/controllers/projects/badges_controller_spec.rb index d41e8d6169f..ef2afd7ca38 100644 --- a/spec/controllers/projects/badges_controller_spec.rb +++ b/spec/controllers/projects/badges_controller_spec.rb @@ -98,6 +98,16 @@ RSpec.describe Projects::BadgesController do expect(response.body).to include('123') end end + + if badge_type == :release + context 'when value_width param is used' do + it 'sets custom value width' do + get_badge(badge_type, value_width: '123') + + expect(response.body).to include('123') + end + end + end end shared_examples 'a badge resource' do |badge_type| @@ -186,7 +196,7 @@ RSpec.describe Projects::BadgesController do namespace_id: project.namespace.to_param, project_id: project, ref: pipeline.ref - }.merge(args.slice(:style, :key_text, :key_width, :ignore_skipped)) + }.merge(args.slice(:style, :key_text, :key_width, :value_width, :ignore_skipped)) get badge, params: params, format: :svg end diff --git a/spec/controllers/projects/blame_controller_spec.rb b/spec/controllers/projects/blame_controller_spec.rb index 62a544bb3fc..50556bdb652 100644 --- a/spec/controllers/projects/blame_controller_spec.rb +++ b/spec/controllers/projects/blame_controller_spec.rb @@ -2,9 +2,9 @@ require 'spec_helper' -RSpec.describe Projects::BlameController do - let(:project) { create(:project, :repository) } - let(:user) { create(:user) } +RSpec.describe Projects::BlameController, feature_category: :source_code_management do + let_it_be(:project) { create(:project, :repository) } + let_it_be(:user) { create(:user) } before do sign_in(user) @@ -13,37 +13,55 @@ RSpec.describe Projects::BlameController do controller.instance_variable_set(:@project, project) end - describe "GET show" do - render_views - - before do - get(:show, - params: { - namespace_id: project.namespace, - project_id: project, - id: id - }) - end - - context "valid branch, valid file" do + shared_examples 'blame_response' do + context 'valid branch, valid file' do let(:id) { 'master/files/ruby/popen.rb' } it { is_expected.to respond_with(:success) } end - context "valid branch, invalid file" do + context 'valid branch, invalid file' do let(:id) { 'master/files/ruby/invalid-path.rb' } it 'redirects' do - expect(subject) - .to redirect_to("/#{project.full_path}/-/tree/master") + expect(subject).to redirect_to("/#{project.full_path}/-/tree/master") end end - context "invalid branch, valid file" do + context 'invalid branch, valid file' do let(:id) { 'invalid-branch/files/ruby/missing_file.rb' } it { is_expected.to respond_with(:not_found) } end end + + describe 'GET show' do + render_views + + before do + get :show, params: { namespace_id: project.namespace, project_id: project, id: id } + end + + it_behaves_like 'blame_response' + end + + describe 'GET page' do + render_views + + before do + get :page, params: { namespace_id: project.namespace, project_id: project, id: id } + end + + it_behaves_like 'blame_response' + end + + describe 'GET streaming' do + render_views + + before do + get :streaming, params: { namespace_id: project.namespace, project_id: project, id: id } + end + + it_behaves_like 'blame_response' + end end diff --git a/spec/controllers/projects/blob_controller_spec.rb b/spec/controllers/projects/blob_controller_spec.rb index ec92d92e2a9..b07cb7a228d 100644 --- a/spec/controllers/projects/blob_controller_spec.rb +++ b/spec/controllers/projects/blob_controller_spec.rb @@ -100,13 +100,7 @@ RSpec.describe Projects::BlobController, feature_category: :source_code_manageme let(:id) { 'master/README.md' } before do - get(:show, - params: { - namespace_id: project.namespace, - project_id: project, - id: id - }, - format: :json) + get :show, params: { namespace_id: project.namespace, project_id: project, id: id }, format: :json end it do @@ -120,14 +114,7 @@ RSpec.describe Projects::BlobController, feature_category: :source_code_manageme let(:id) { 'master/README.md' } before do - get(:show, - params: { - namespace_id: project.namespace, - project_id: project, - id: id, - viewer: 'none' - }, - format: :json) + get :show, params: { namespace_id: project.namespace, project_id: project, id: id, viewer: 'none' }, format: :json end it do @@ -140,12 +127,8 @@ RSpec.describe Projects::BlobController, feature_category: :source_code_manageme context 'with tree path' do before do - get(:show, - params: { - namespace_id: project.namespace, - project_id: project, - id: id - }) + get :show, params: { namespace_id: project.namespace, project_id: project, id: id } + controller.instance_variable_set(:@blob, nil) end @@ -387,11 +370,22 @@ RSpec.describe Projects::BlobController, feature_category: :source_code_manageme end end - it_behaves_like 'tracking unique hll events' do + context 'events tracking' do + let(:target_event) { 'g_edit_by_sfe' } + subject(:request) { put :update, params: default_params } - let(:target_event) { 'g_edit_by_sfe' } - let(:expected_value) { instance_of(Integer) } + it_behaves_like 'tracking unique hll events' do + let(:expected_value) { instance_of(Integer) } + end + + it_behaves_like 'Snowplow event tracking with RedisHLL context' do + let(:action) { 'perform_sfe_action' } + let(:category) { described_class.to_s } + let(:namespace) { project.namespace.reload } + let(:property) { target_event } + let(:label) { 'usage_activity_by_stage_monthly.create.action_monthly_active_users_sfe_edit' } + end end end @@ -519,6 +513,7 @@ RSpec.describe Projects::BlobController, feature_category: :source_code_manageme describe 'POST create' do let(:user) { create(:user) } + let(:target_event) { 'g_edit_by_sfe' } let(:default_params) do { namespace_id: project.namespace, @@ -540,10 +535,17 @@ RSpec.describe Projects::BlobController, feature_category: :source_code_manageme subject(:request) { post :create, params: default_params } it_behaves_like 'tracking unique hll events' do - let(:target_event) { 'g_edit_by_sfe' } let(:expected_value) { instance_of(Integer) } end + it_behaves_like 'Snowplow event tracking with RedisHLL context' do + let(:action) { 'perform_sfe_action' } + let(:category) { described_class.to_s } + let(:namespace) { project.namespace } + let(:property) { target_event } + let(:label) { 'usage_activity_by_stage_monthly.create.action_monthly_active_users_sfe_edit' } + end + it 'redirects to blob' do request diff --git a/spec/controllers/projects/branches_controller_spec.rb b/spec/controllers/projects/branches_controller_spec.rb index dcde22c1fd6..600f8047a1d 100644 --- a/spec/controllers/projects/branches_controller_spec.rb +++ b/spec/controllers/projects/branches_controller_spec.rb @@ -22,13 +22,12 @@ RSpec.describe Projects::BranchesController, feature_category: :source_code_mana before do sign_in(developer) - post :create, - params: { - namespace_id: project.namespace, - project_id: project, - branch_name: branch, - ref: ref - } + post :create, params: { + namespace_id: project.namespace, + project_id: project, + branch_name: branch, + ref: ref + } end context "valid branch name, valid source" do @@ -83,13 +82,12 @@ RSpec.describe Projects::BranchesController, feature_category: :source_code_mana end it 'redirects' do - post :create, - params: { - namespace_id: project.namespace, - project_id: project, - branch_name: branch, - issue_iid: issue.iid - } + post :create, params: { + namespace_id: project.namespace, + project_id: project, + branch_name: branch, + issue_iid: issue.iid + } expect(subject) .to redirect_to("/#{project.full_path}/-/tree/1-feature-branch") @@ -98,13 +96,12 @@ RSpec.describe Projects::BranchesController, feature_category: :source_code_mana it 'posts a system note' do expect(SystemNoteService).to receive(:new_issue_branch).with(issue, project, developer, "1-feature-branch", branch_project: project) - post :create, - params: { - namespace_id: project.namespace, - project_id: project, - branch_name: branch, - issue_iid: issue.iid - } + post :create, params: { + namespace_id: project.namespace, + project_id: project, + branch_name: branch, + issue_iid: issue.iid + } end context 'confidential_issue_project_id is present' do @@ -167,13 +164,12 @@ RSpec.describe Projects::BranchesController, feature_category: :source_code_mana expect_any_instance_of(::Branches::CreateService).to receive(:execute).and_return(result) expect(SystemNoteService).to receive(:new_issue_branch).and_return(true) - post :create, - params: { - namespace_id: project.namespace.to_param, - project_id: project.to_param, - branch_name: branch, - issue_iid: issue.iid - } + post :create, params: { + namespace_id: project.namespace.to_param, + project_id: project.to_param, + branch_name: branch, + issue_iid: issue.iid + } expect(response).to redirect_to project_tree_path(project, branch) end @@ -189,13 +185,12 @@ RSpec.describe Projects::BranchesController, feature_category: :source_code_mana expect_any_instance_of(::Branches::CreateService).to receive(:execute).and_return(result) expect(SystemNoteService).to receive(:new_issue_branch).and_return(true) - post :create, - params: { - namespace_id: project.namespace.to_param, - project_id: project.to_param, - branch_name: branch, - issue_iid: issue.iid - } + post :create, params: { + namespace_id: project.namespace.to_param, + project_id: project.to_param, + branch_name: branch, + issue_iid: issue.iid + } expect(response.location).to include(project_new_blob_path(project, branch)) expect(response).to have_gitlab_http_status(:found) @@ -210,13 +205,12 @@ RSpec.describe Projects::BranchesController, feature_category: :source_code_mana expect_any_instance_of(::Branches::CreateService).to receive(:execute).and_return(result) expect(SystemNoteService).to receive(:new_issue_branch).and_return(true) - post :create, - params: { - namespace_id: project.namespace.to_param, - project_id: project.to_param, - branch_name: branch, - issue_iid: issue.iid - } + post :create, params: { + namespace_id: project.namespace.to_param, + project_id: project.to_param, + branch_name: branch, + issue_iid: issue.iid + } expect(response.location).to include(project_new_blob_path(project, branch)) expect(response).to have_gitlab_http_status(:found) @@ -229,13 +223,12 @@ RSpec.describe Projects::BranchesController, feature_category: :source_code_mana it "doesn't post a system note" do expect(SystemNoteService).not_to receive(:new_issue_branch) - post :create, - params: { - namespace_id: project.namespace, - project_id: project, - branch_name: branch, - issue_iid: issue.iid - } + post :create, params: { + namespace_id: project.namespace, + project_id: project, + branch_name: branch, + issue_iid: issue.iid + } end end @@ -249,13 +242,12 @@ RSpec.describe Projects::BranchesController, feature_category: :source_code_mana it "doesn't post a system note" do expect(SystemNoteService).not_to receive(:new_issue_branch) - post :create, - params: { - namespace_id: project.namespace, - project_id: project, - branch_name: branch, - issue_iid: issue.iid - } + post :create, params: { + namespace_id: project.namespace, + project_id: project, + branch_name: branch, + issue_iid: issue.iid + } end end end @@ -285,18 +277,17 @@ RSpec.describe Projects::BranchesController, feature_category: :source_code_mana create_branch name: "", ref: "" expect(response).to have_gitlab_http_status(:unprocessable_entity) + expect(response.body).to include 'Failed to create branch' end end def create_branch(name:, ref:) - post :create, - format: :json, - params: { - namespace_id: project.namespace.to_param, - project_id: project.to_param, - branch_name: name, - ref: ref - } + post :create, format: :json, params: { + namespace_id: project.namespace.to_param, + project_id: project.to_param, + branch_name: name, + ref: ref + } end end @@ -345,13 +336,11 @@ RSpec.describe Projects::BranchesController, feature_category: :source_code_mana before do sign_in(developer) - post :destroy, - format: format, - params: { - id: branch, - namespace_id: project.namespace, - project_id: project - } + post :destroy, format: format, params: { + id: branch, + namespace_id: project.namespace, + project_id: project + } end context 'as JS' do @@ -445,11 +434,10 @@ RSpec.describe Projects::BranchesController, feature_category: :source_code_mana describe "DELETE destroy_all_merged" do def destroy_all_merged - delete :destroy_all_merged, - params: { - namespace_id: project.namespace, - project_id: project - } + delete :destroy_all_merged, params: { + namespace_id: project.namespace, + project_id: project + } end context 'when user is allowed to push' do @@ -492,13 +480,11 @@ RSpec.describe Projects::BranchesController, feature_category: :source_code_mana context 'when rendering a JSON format' do it 'filters branches by name' do - get :index, - format: :json, - params: { - namespace_id: project.namespace, - project_id: project, - search: 'master' - } + get :index, format: :json, params: { + namespace_id: project.namespace, + project_id: project, + search: 'master' + } expect(json_response.length).to eq 1 expect(json_response.first).to eq 'master' @@ -523,13 +509,11 @@ RSpec.describe Projects::BranchesController, feature_category: :source_code_mana status: :success, created_at: 2.months.ago) - get :index, - format: :html, - params: { - namespace_id: project.namespace, - project_id: project, - state: 'all' - } + get :index, format: :html, params: { + namespace_id: project.namespace, + project_id: project, + state: 'all' + } expect(assigns[:branch_pipeline_statuses]["master"].group).to eq("success") expect(assigns[:sort]).to eq('updated_desc') @@ -555,13 +539,11 @@ RSpec.describe Projects::BranchesController, feature_category: :source_code_mana status: :success, created_at: 2.months.ago) - get :index, - format: :html, - params: { - namespace_id: project.namespace, - project_id: project, - state: 'all' - } + get :index, format: :html, params: { + namespace_id: project.namespace, + project_id: project, + state: 'all' + } expect(assigns[:branch_pipeline_statuses]["master"].group).to eq("running") expect(assigns[:branch_pipeline_statuses]["test"].group).to eq("success") @@ -570,13 +552,11 @@ RSpec.describe Projects::BranchesController, feature_category: :source_code_mana context 'when a branch contains no pipelines' do it 'no commit statuses are received' do - get :index, - format: :html, - params: { - namespace_id: project.namespace, - project_id: project, - state: 'stale' - } + get :index, format: :html, params: { + namespace_id: project.namespace, + project_id: project, + state: 'stale' + } expect(assigns[:branch_pipeline_statuses]).to be_blank expect(assigns[:sort]).to eq('updated_asc') @@ -589,14 +569,12 @@ RSpec.describe Projects::BranchesController, feature_category: :source_code_mana # was not raised whenever the cache is enabled yet cold. context 'when cache is enabled yet cold', :request_store do it 'return with a status 200' do - get :index, - format: :html, - params: { - namespace_id: project.namespace, - project_id: project, - sort: 'name_asc', - state: 'all' - } + get :index, format: :html, params: { + namespace_id: project.namespace, + project_id: project, + sort: 'name_asc', + state: 'all' + } expect(response).to have_gitlab_http_status(:ok) expect(assigns[:sort]).to eq('name_asc') @@ -609,13 +587,11 @@ RSpec.describe Projects::BranchesController, feature_category: :source_code_mana end it 'return with a status 200' do - get :index, - format: :html, - params: { - namespace_id: project.namespace, - project_id: project, - state: 'all' - } + get :index, format: :html, params: { + namespace_id: project.namespace, + project_id: project, + state: 'all' + } expect(response).to have_gitlab_http_status(:ok) end @@ -623,37 +599,31 @@ RSpec.describe Projects::BranchesController, feature_category: :source_code_mana context 'when deprecated sort/search/page parameters are specified' do it 'returns with a status 301 when sort specified' do - get :index, - format: :html, - params: { - namespace_id: project.namespace, - project_id: project, - sort: 'updated_asc' - } + get :index, format: :html, params: { + namespace_id: project.namespace, + project_id: project, + sort: 'updated_asc' + } expect(response).to redirect_to project_branches_filtered_path(project, state: 'all') end it 'returns with a status 301 when search specified' do - get :index, - format: :html, - params: { - namespace_id: project.namespace, - project_id: project, - search: 'feature' - } + get :index, format: :html, params: { + namespace_id: project.namespace, + project_id: project, + search: 'feature' + } expect(response).to redirect_to project_branches_filtered_path(project, state: 'all') end it 'returns with a status 301 when page specified' do - get :index, - format: :html, - params: { - namespace_id: project.namespace, - project_id: project, - page: 2 - } + get :index, format: :html, params: { + namespace_id: project.namespace, + project_id: project, + page: 2 + } expect(response).to redirect_to project_branches_filtered_path(project, state: 'all') end @@ -747,13 +717,11 @@ RSpec.describe Projects::BranchesController, feature_category: :source_code_mana end it 'returns the commit counts behind and ahead of default branch' do - get :diverging_commit_counts, - format: :json, - params: { - namespace_id: project.namespace, - project_id: project, - names: %w[fix add-pdf-file branch-merged] - } + get :diverging_commit_counts, format: :json, params: { + namespace_id: project.namespace, + project_id: project, + names: %w[fix add-pdf-file branch-merged] + } expect(response).to have_gitlab_http_status(:ok) expect(json_response).to eq( @@ -766,12 +734,10 @@ RSpec.describe Projects::BranchesController, feature_category: :source_code_mana it 'returns the commits counts with no names provided' do allow_any_instance_of(Repository).to receive(:branch_count).and_return(Kaminari.config.default_per_page) - get :diverging_commit_counts, - format: :json, - params: { - namespace_id: project.namespace, - project_id: project - } + get :diverging_commit_counts, format: :json, params: { + namespace_id: project.namespace, + project_id: project + } expect(response).to have_gitlab_http_status(:ok) expect(json_response.count).to be > 1 @@ -783,25 +749,21 @@ RSpec.describe Projects::BranchesController, feature_category: :source_code_mana end it 'returns 422 if no names are specified' do - get :diverging_commit_counts, - format: :json, - params: { - namespace_id: project.namespace, - project_id: project - } + get :diverging_commit_counts, format: :json, params: { + namespace_id: project.namespace, + project_id: project + } expect(response).to have_gitlab_http_status(:unprocessable_entity) expect(json_response['error']).to eq("Specify at least one and at most #{Kaminari.config.default_per_page} branch names") end it 'returns the list of counts' do - get :diverging_commit_counts, - format: :json, - params: { - namespace_id: project.namespace, - project_id: project, - names: %w[fix add-pdf-file branch-merged] - } + get :diverging_commit_counts, format: :json, params: { + namespace_id: project.namespace, + project_id: project, + names: %w[fix add-pdf-file branch-merged] + } expect(response).to have_gitlab_http_status(:ok) expect(json_response.count).to be > 1 diff --git a/spec/controllers/projects/clusters_controller_spec.rb b/spec/controllers/projects/clusters_controller_spec.rb index c7d2b1fa3af..f976b5bfe67 100644 --- a/spec/controllers/projects/clusters_controller_spec.rb +++ b/spec/controllers/projects/clusters_controller_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' -RSpec.describe Projects::ClustersController, feature_category: :kubernetes_management do +RSpec.describe Projects::ClustersController, feature_category: :deployment_management do include AccessMatchersForController include GoogleApi::CloudPlatformHelpers include KubernetesHelpers @@ -123,7 +123,7 @@ RSpec.describe Projects::ClustersController, feature_category: :kubernetes_manag { id: proxyable.id.to_s, namespace_id: project.namespace.full_path, - project_id: project.name + project_id: project.path } end @@ -171,7 +171,7 @@ RSpec.describe Projects::ClustersController, feature_category: :kubernetes_manag { id: cluster.id, namespace_id: project.namespace.full_path, - project_id: project.name + project_id: project.path } end end @@ -358,12 +358,6 @@ RSpec.describe Projects::ClustersController, feature_category: :kubernetes_manag expect(response).to have_gitlab_http_status(:ok) expect(response).to match_response_schema('cluster_status') end - - it 'invokes schedule_status_update on each application' do - expect_any_instance_of(Clusters::Applications::Ingress).to receive(:schedule_status_update) - - go - end end describe 'security' do @@ -403,20 +397,37 @@ RSpec.describe Projects::ClustersController, feature_category: :kubernetes_manag end describe 'functionality' do - render_views + context 'when remove_monitor_metrics FF is disabled' do + before do + stub_feature_flags(remove_monitor_metrics: false) + end - it "renders view" do - go + render_views - expect(response).to have_gitlab_http_status(:ok) - expect(assigns(:cluster)).to eq(cluster) + it "renders view" do + go + + expect(response).to have_gitlab_http_status(:ok) + expect(assigns(:cluster)).to eq(cluster) + end + + it 'renders integration tab view' do + go(tab: 'integrations') + + expect(response).to render_template('clusters/clusters/_integrations') + expect(response).to have_gitlab_http_status(:ok) + end end - it 'renders integration tab view' do - go(tab: 'integrations') + context 'when remove_monitor_metrics FF is enabled' do + render_views - expect(response).to render_template('clusters/clusters/_integrations') - expect(response).to have_gitlab_http_status(:ok) + it 'renders details tab view', :aggregate_failures do + go(tab: 'integrations') + + expect(response).to render_template('clusters/clusters/_details') + expect(response).to have_gitlab_http_status(:ok) + end end end @@ -441,11 +452,12 @@ RSpec.describe Projects::ClustersController, feature_category: :kubernetes_manag describe 'PUT update' do def go(format: :html) - put :update, params: params.merge(namespace_id: project.namespace.to_param, - project_id: project.to_param, - id: cluster, - format: format - ) + put :update, params: params.merge( + namespace_id: project.namespace.to_param, + project_id: project.to_param, + id: cluster, + format: format + ) end before do diff --git a/spec/controllers/projects/commit_controller_spec.rb b/spec/controllers/projects/commit_controller_spec.rb index 8d3939d8133..44486d0ed41 100644 --- a/spec/controllers/projects/commit_controller_spec.rb +++ b/spec/controllers/projects/commit_controller_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' -RSpec.describe Projects::CommitController do +RSpec.describe Projects::CommitController, feature_category: :source_code_management do include ProjectForksHelper let_it_be(:project) { create(:project, :repository) } @@ -84,22 +84,6 @@ RSpec.describe Projects::CommitController do expect(response).to be_successful end - it 'only loads blobs in the current page' do - stub_feature_flags(async_commit_diff_files: false) - stub_const('Projects::CommitController::COMMIT_DIFFS_PER_PAGE', 1) - - commit = project.commit('1a0b36b3cdad1d2ee32457c102a8c0b7056fa863') - - expect_next_instance_of(Repository) do |repository| - # This commit contains 3 changed files but we expect only the blobs for the first one to be loaded - expect(repository).to receive(:blobs_at).with([[commit.id, '.gitignore']], anything).and_call_original - end - - go(id: commit.id) - - expect(response).to be_ok - end - shared_examples "export as" do |format| it "does generally work" do go(id: commit.id, format: format) @@ -155,12 +139,7 @@ RSpec.describe Projects::CommitController do let(:commit) { fork_project.commit('remove-submodule') } it 'renders it' do - get(:show, - params: { - namespace_id: fork_project.namespace, - project_id: fork_project, - id: commit.id - }) + get :show, params: { namespace_id: fork_project.namespace, project_id: fork_project, id: commit.id } expect(response).to be_successful end @@ -174,10 +153,10 @@ RSpec.describe Projects::CommitController do go(id: commit.id, merge_request_iid: merge_request.iid) expect(assigns(:new_diff_note_attrs)).to eq({ - noteable_type: 'MergeRequest', - noteable_id: merge_request.id, - commit_id: commit.id - }) + noteable_type: 'MergeRequest', + noteable_id: merge_request.id, + commit_id: commit.id + }) expect(response).to be_ok end end @@ -187,12 +166,7 @@ RSpec.describe Projects::CommitController do it 'contains branch and tags information' do commit = project.commit('5937ac0a7beb003549fc5fd26fc247adbce4a52e') - get(:branches, - params: { - namespace_id: project.namespace, - project_id: project, - id: commit.id - }) + get :branches, params: { namespace_id: project.namespace, project_id: project, id: commit.id } expect(assigns(:branches)).to include('master', 'feature_conflict') expect(assigns(:branches_limit_exceeded)).to be_falsey @@ -205,12 +179,7 @@ RSpec.describe Projects::CommitController do allow_any_instance_of(Repository).to receive(:branch_count).and_return(1001) allow_any_instance_of(Repository).to receive(:tag_count).and_return(1001) - get(:branches, - params: { - namespace_id: project.namespace, - project_id: project, - id: commit.id - }) + get :branches, params: { namespace_id: project.namespace, project_id: project, id: commit.id } expect(assigns(:branches)).to eq([]) expect(assigns(:branches_limit_exceeded)).to be_truthy @@ -234,12 +203,7 @@ RSpec.describe Projects::CommitController do describe 'POST revert' do context 'when target branch is not provided' do it 'renders the 404 page' do - post(:revert, - params: { - namespace_id: project.namespace, - project_id: project, - id: commit.id - }) + post :revert, params: { namespace_id: project.namespace, project_id: project, id: commit.id } expect(response).not_to be_successful expect(response).to have_gitlab_http_status(:not_found) @@ -248,13 +212,7 @@ RSpec.describe Projects::CommitController do context 'when the revert commit is missing' do it 'renders the 404 page' do - post(:revert, - params: { - namespace_id: project.namespace, - project_id: project, - start_branch: 'master', - id: '1234567890' - }) + post :revert, params: { namespace_id: project.namespace, project_id: project, start_branch: 'master', id: '1234567890' } expect(response).not_to be_successful expect(response).to have_gitlab_http_status(:not_found) @@ -263,13 +221,7 @@ RSpec.describe Projects::CommitController do context 'when the revert was successful' do it 'redirects to the commits page' do - post(:revert, - params: { - namespace_id: project.namespace, - project_id: project, - start_branch: 'master', - id: commit.id - }) + post :revert, params: { namespace_id: project.namespace, project_id: project, start_branch: 'master', id: commit.id } expect(response).to redirect_to project_commits_path(project, 'master') expect(flash[:notice]).to eq('The commit has been successfully reverted.') @@ -278,27 +230,53 @@ RSpec.describe Projects::CommitController do context 'when the revert failed' do before do - post(:revert, - params: { - namespace_id: project.namespace, - project_id: project, - start_branch: 'master', - id: commit.id - }) + post :revert, params: { namespace_id: project.namespace, project_id: project, start_branch: 'master', id: commit.id } end it 'redirects to the commit page' do # Reverting a commit that has been already reverted. - post(:revert, - params: { - namespace_id: project.namespace, - project_id: project, - start_branch: 'master', - id: commit.id - }) + post :revert, params: { namespace_id: project.namespace, project_id: project, start_branch: 'master', id: commit.id } expect(response).to redirect_to project_commit_path(project, commit.id) - expect(flash[:alert]).to match('Sorry, we cannot revert this commit automatically.') + expect(flash[:alert]).to match('Commit revert failed:') + end + end + + context 'in the context of a merge_request' do + let(:merge_request) { create(:merge_request, :merged, source_project: project) } + let(:repository) { project.repository } + + before do + merge_commit_id = repository.merge(user, + merge_request.diff_head_sha, + merge_request, + 'Test message') + + repository.commit(merge_commit_id) + merge_request.update!(merge_commit_sha: merge_commit_id) + end + + context 'when the revert was successful' do + it 'redirects to the merge request page' do + post :revert, params: { namespace_id: project.namespace, project_id: project, start_branch: 'master', id: merge_request.merge_commit_sha } + + expect(response).to redirect_to project_merge_request_path(project, merge_request) + expect(flash[:notice]).to eq('The merge request has been successfully reverted.') + end + end + + context 'when the revert failed' do + before do + post :revert, params: { namespace_id: project.namespace, project_id: project, start_branch: 'master', id: merge_request.merge_commit_sha } + end + + it 'redirects to the merge request page' do + # Reverting a merge request that has been already reverted. + post :revert, params: { namespace_id: project.namespace, project_id: project, start_branch: 'master', id: merge_request.merge_commit_sha } + + expect(response).to redirect_to project_merge_request_path(project, merge_request) + expect(flash[:alert]).to match('Merge request revert failed:') + end end end end @@ -306,12 +284,7 @@ RSpec.describe Projects::CommitController do describe 'POST cherry_pick' do context 'when target branch is not provided' do it 'renders the 404 page' do - post(:cherry_pick, - params: { - namespace_id: project.namespace, - project_id: project, - id: master_pickable_commit.id - }) + post :cherry_pick, params: { namespace_id: project.namespace, project_id: project, id: master_pickable_commit.id } expect(response).not_to be_successful expect(response).to have_gitlab_http_status(:not_found) @@ -320,13 +293,7 @@ RSpec.describe Projects::CommitController do context 'when the cherry-pick commit is missing' do it 'renders the 404 page' do - post(:cherry_pick, - params: { - namespace_id: project.namespace, - project_id: project, - start_branch: 'master', - id: '1234567890' - }) + post :cherry_pick, params: { namespace_id: project.namespace, project_id: project, start_branch: 'master', id: '1234567890' } expect(response).not_to be_successful expect(response).to have_gitlab_http_status(:not_found) @@ -335,13 +302,7 @@ RSpec.describe Projects::CommitController do context 'when the cherry-pick was successful' do it 'redirects to the commits page' do - post(:cherry_pick, - params: { - namespace_id: project.namespace, - project_id: project, - start_branch: 'master', - id: master_pickable_commit.id - }) + post :cherry_pick, params: { namespace_id: project.namespace, project_id: project, start_branch: 'master', id: master_pickable_commit.id } expect(response).to redirect_to project_commits_path(project, 'master') expect(flash[:notice]).to eq('The commit has been successfully cherry-picked into master.') @@ -350,27 +311,52 @@ RSpec.describe Projects::CommitController do context 'when the cherry_pick failed' do before do - post(:cherry_pick, - params: { - namespace_id: project.namespace, - project_id: project, - start_branch: 'master', - id: master_pickable_commit.id - }) + post :cherry_pick, params: { namespace_id: project.namespace, project_id: project, start_branch: 'master', id: master_pickable_commit.id } end it 'redirects to the commit page' do # Cherry-picking a commit that has been already cherry-picked. - post(:cherry_pick, - params: { - namespace_id: project.namespace, - project_id: project, - start_branch: 'master', - id: master_pickable_commit.id - }) + post :cherry_pick, params: { namespace_id: project.namespace, project_id: project, start_branch: 'master', id: master_pickable_commit.id } expect(response).to redirect_to project_commit_path(project, master_pickable_commit.id) - expect(flash[:alert]).to match('Sorry, we cannot cherry-pick this commit automatically.') + expect(flash[:alert]).to match('Commit cherry-pick failed:') + end + end + + context 'in the context of a merge_request' do + let(:merge_request) { create(:merge_request, :merged, source_project: project) } + let(:repository) { project.repository } + + before do + merge_commit_id = repository.merge(user, + merge_request.diff_head_sha, + merge_request, + 'Test message') + repository.commit(merge_commit_id) + merge_request.update!(merge_commit_sha: merge_commit_id) + end + + context 'when the cherry_pick was successful' do + it 'redirects to the merge request page' do + post :cherry_pick, params: { namespace_id: project.namespace, project_id: project, start_branch: 'merge-test', id: merge_request.merge_commit_sha } + + expect(response).to redirect_to project_merge_request_path(project, merge_request) + expect(flash[:notice]).to eq('The merge request has been successfully cherry-picked into merge-test.') + end + end + + context 'when the cherry_pick failed' do + before do + post :cherry_pick, params: { namespace_id: project.namespace, project_id: project, start_branch: 'merge-test', id: merge_request.merge_commit_sha } + end + + it 'redirects to the merge request page' do + # Reverting a merge request that has been already cherry-picked. + post :cherry_pick, params: { namespace_id: project.namespace, project_id: project, start_branch: 'merge-test', id: merge_request.merge_commit_sha } + + expect(response).to redirect_to project_merge_request_path(project, merge_request) + expect(flash[:alert]).to match('Merge request cherry-pick failed:') + end end end @@ -381,15 +367,14 @@ RSpec.describe Projects::CommitController do let(:create_merge_request) { nil } def send_request - post(:cherry_pick, - params: { - namespace_id: forked_project.namespace, - project_id: forked_project, - target_project_id: target_project.id, - start_branch: 'feature', - id: forked_project.commit.id, - create_merge_request: create_merge_request - }) + post :cherry_pick, params: { + namespace_id: forked_project.namespace, + project_id: forked_project, + target_project_id: target_project.id, + start_branch: 'feature', + id: forked_project.commit.id, + create_merge_request: create_merge_request + } end def merge_request_url(source_project, branch) @@ -458,6 +443,37 @@ RSpec.describe Projects::CommitController do end end + describe 'GET #diff_files' do + subject(:send_request) { get :diff_files, params: params } + + let(:format) { :html } + let(:params) do + { + namespace_id: project.namespace, + project_id: project, + id: commit.id, + format: format + } + end + + it 'renders diff files' do + send_request + + expect(assigns(:diffs)).to be_a(Gitlab::Diff::FileCollection::Commit) + expect(assigns(:environment)).to be_nil + end + + context 'when format is not html' do + let(:format) { :json } + + it 'returns 404 page' do + send_request + + expect(response).to have_gitlab_http_status(:not_found) + end + end + end + describe 'GET diff_for_path' do def diff_for_path(extra_params = {}) params = { @@ -478,8 +494,7 @@ RSpec.describe Projects::CommitController do diff_for_path(id: commit2.id, old_path: existing_path, new_path: existing_path) expect(assigns(:diff_notes_disabled)).to be_falsey - expect(assigns(:new_diff_note_attrs)).to eq(noteable_type: 'Commit', - commit_id: commit2.id) + expect(assigns(:new_diff_note_attrs)).to eq(noteable_type: 'Commit', commit_id: commit2.id) end it 'only renders the diffs for the path given' do diff --git a/spec/controllers/projects/commits_controller_spec.rb b/spec/controllers/projects/commits_controller_spec.rb index 67aa82dacbb..956167ce838 100644 --- a/spec/controllers/projects/commits_controller_spec.rb +++ b/spec/controllers/projects/commits_controller_spec.rb @@ -3,8 +3,9 @@ require 'spec_helper' RSpec.describe Projects::CommitsController, feature_category: :source_code_management do - let(:project) { create(:project, :repository) } - let(:user) { create(:user) } + let_it_be(:project) { create(:project, :repository) } + let_it_be(:repository) { project.repository } + let_it_be(:user) { create(:user) } before do project.add_maintainer(user) @@ -18,11 +19,7 @@ RSpec.describe Projects::CommitsController, feature_category: :source_code_manag describe "GET commits_root" do context "no ref is provided" do it 'redirects to the default branch of the project' do - get(:commits_root, - params: { - namespace_id: project.namespace, - project_id: project - }) + get :commits_root, params: { namespace_id: project.namespace, project_id: project } expect(response).to redirect_to project_commits_path(project) end @@ -34,12 +31,7 @@ RSpec.describe Projects::CommitsController, feature_category: :source_code_manag context 'with file path' do before do - get(:show, - params: { - namespace_id: project.namespace, - project_id: project, - id: id - }) + get :show, params: { namespace_id: project.namespace, project_id: project, id: id } end context "valid branch, valid file" do @@ -48,6 +40,12 @@ RSpec.describe Projects::CommitsController, feature_category: :source_code_manag it { is_expected.to respond_with(:success) } end + context "HEAD, valid file" do + let(:id) { 'HEAD/README.md' } + + it { is_expected.to respond_with(:success) } + end + context "valid branch, invalid file" do let(:id) { 'master/invalid-path.rb' } @@ -78,13 +76,7 @@ RSpec.describe Projects::CommitsController, feature_category: :source_code_manag offset: 0 ).and_call_original - get(:show, - params: { - namespace_id: project.namespace, - project_id: project, - id: id, - limit: "foo" - }) + get :show, params: { namespace_id: project.namespace, project_id: project, id: id, limit: "foo" } expect(response).to be_successful end @@ -98,27 +90,44 @@ RSpec.describe Projects::CommitsController, feature_category: :source_code_manag offset: 0 ).and_call_original - get(:show, params: { + get :show, params: { namespace_id: project.namespace, project_id: project, id: id, limit: { 'broken' => 'value' } - }) + } expect(response).to be_successful end end end + it 'loads tags for commits' do + expect_next_instance_of(CommitCollection) do |collection| + expect(collection).to receive(:load_tags) + end + + get :show, params: { namespace_id: project.namespace, project_id: project, id: 'master/README.md' } + + expect(response).to have_gitlab_http_status(:ok) + end + + context 'when tag has a non-ASCII encoding' do + before do + repository.add_tag(user, 'tést', 'master') + end + + it 'does not raise an exception' do + get :show, params: { namespace_id: project.namespace, project_id: project, id: 'master' } + + expect(response).to have_gitlab_http_status(:ok) + end + end + context "when the ref name ends in .atom" do context "when the ref does not exist with the suffix" do before do - get(:show, - params: { - namespace_id: project.namespace, - project_id: project, - id: "master.atom" - }) + get :show, params: { namespace_id: project.namespace, project_id: project, id: "master.atom" } end it "renders as atom" do @@ -138,12 +147,11 @@ RSpec.describe Projects::CommitsController, feature_category: :source_code_manag allow_any_instance_of(Repository).to receive(:commit).and_call_original allow_any_instance_of(Repository).to receive(:commit).with('master.atom').and_return(commit) - get(:show, - params: { - namespace_id: project.namespace, - project_id: project, - id: "master.atom" - }) + get :show, params: { + namespace_id: project.namespace, + project_id: project, + id: "master.atom" + } end it "renders as HTML" do @@ -182,13 +190,11 @@ RSpec.describe Projects::CommitsController, feature_category: :source_code_manag before do expect(::Gitlab::GitalyClient).to receive(:allow_ref_name_caching).and_call_original unless id.include?(' ') - get(:signatures, - params: { - namespace_id: project.namespace, - project_id: project, - id: id - }, - format: :json) + get :signatures, params: { + namespace_id: project.namespace, + project_id: project, + id: id + }, format: :json end context "valid branch" do diff --git a/spec/controllers/projects/compare_controller_spec.rb b/spec/controllers/projects/compare_controller_spec.rb index 3751b89951c..a49f8b51c12 100644 --- a/spec/controllers/projects/compare_controller_spec.rb +++ b/spec/controllers/projects/compare_controller_spec.rb @@ -284,14 +284,18 @@ RSpec.describe Projects::CompareController do let(:to_ref) { '5937ac0a7beb003549fc5fd26fc247adbce4a52e' } let(:page) { 1 } - it 'shows the diff' do - show_request + shared_examples 'valid compare page' do + it 'shows the diff' do + show_request - expect(response).to be_successful - expect(assigns(:diffs).diff_files.first).to be_present - expect(assigns(:commits).length).to be >= 1 + expect(response).to be_successful + expect(assigns(:diffs).diff_files.first).to be_present + expect(assigns(:commits).length).to be >= 1 + end end + it_behaves_like 'valid compare page' + it 'only loads blobs in the current page' do stub_const('Projects::CompareController::COMMIT_DIFFS_PER_PAGE', 1) @@ -306,6 +310,19 @@ RSpec.describe Projects::CompareController do expect(response).to be_successful end + + context 'when from_ref is HEAD ref' do + let(:from_ref) { 'HEAD' } + let(:to_ref) { 'feature' } # Need to change to_ref too so there's something to compare with HEAD + + it_behaves_like 'valid compare page' + end + + context 'when to_ref is HEAD ref' do + let(:to_ref) { 'HEAD' } + + it_behaves_like 'valid compare page' + end end context 'when page is not valid' do diff --git a/spec/controllers/projects/cycle_analytics_controller_spec.rb b/spec/controllers/projects/cycle_analytics_controller_spec.rb index 034e6104f99..4ff8c21706b 100644 --- a/spec/controllers/projects/cycle_analytics_controller_spec.rb +++ b/spec/controllers/projects/cycle_analytics_controller_spec.rb @@ -15,11 +15,7 @@ RSpec.describe Projects::CycleAnalyticsController do it 'increases the counter' do expect(Gitlab::UsageDataCounters::CycleAnalyticsCounter).to receive(:count).with(:views) - get(:show, - params: { - namespace_id: project.namespace, - project_id: project - }) + get :show, params: { namespace_id: project.namespace, project_id: project } expect(response).to be_successful end @@ -35,7 +31,6 @@ RSpec.describe Projects::CycleAnalyticsController do subject { get :show, params: request_params, format: :html } let(:request_params) { { namespace_id: project.namespace, project_id: project } } - let(:feature_flag_name) { :route_hll_to_snowplow_phase2 } let(:category) { described_class.name } let(:action) { 'perform_analytics_usage_action' } let(:namespace) { project.namespace } diff --git a/spec/controllers/projects/deploy_keys_controller_spec.rb b/spec/controllers/projects/deploy_keys_controller_spec.rb index ec63bad22b5..52a605cf548 100644 --- a/spec/controllers/projects/deploy_keys_controller_spec.rb +++ b/spec/controllers/projects/deploy_keys_controller_spec.rb @@ -276,9 +276,9 @@ RSpec.describe Projects::DeployKeysController do let(:extra_params) { {} } subject do - put :update, params: extra_params.reverse_merge(id: deploy_key.id, - namespace_id: project.namespace, - project_id: project) + put :update, params: extra_params.reverse_merge( + id: deploy_key.id, namespace_id: project.namespace, project_id: project + ) end def deploy_key_params(title, can_push) @@ -330,9 +330,7 @@ RSpec.describe Projects::DeployKeysController do context 'when a different deploy key id param is injected' do let(:extra_params) { deploy_key_params('updated title', '1') } let(:hacked_params) do - extra_params.reverse_merge(id: other_deploy_key_id, - namespace_id: project.namespace, - project_id: project) + extra_params.reverse_merge(id: other_deploy_key_id, namespace_id: project.namespace, project_id: project) end subject { put :update, params: hacked_params } diff --git a/spec/controllers/projects/deployments_controller_spec.rb b/spec/controllers/projects/deployments_controller_spec.rb index c6532e83441..a696eb933e9 100644 --- a/spec/controllers/projects/deployments_controller_spec.rb +++ b/spec/controllers/projects/deployments_controller_spec.rb @@ -210,8 +210,6 @@ RSpec.describe Projects::DeploymentsController do end def deployment_params(opts = {}) - opts.reverse_merge(namespace_id: project.namespace, - project_id: project, - environment_id: environment.id) + opts.reverse_merge(namespace_id: project.namespace, project_id: project, environment_id: environment.id) end end diff --git a/spec/controllers/projects/design_management/designs/raw_images_controller_spec.rb b/spec/controllers/projects/design_management/designs/raw_images_controller_spec.rb index 2d39e0e5317..a7f3212a6f9 100644 --- a/spec/controllers/projects/design_management/designs/raw_images_controller_spec.rb +++ b/spec/controllers/projects/design_management/designs/raw_images_controller_spec.rb @@ -80,8 +80,12 @@ RSpec.describe Projects::DesignManagement::Designs::RawImagesController do let(:oldest_version) { design.versions.ordered.last } shared_examples 'a successful request for sha' do + before do + allow(DesignManagement::GitRepository).to receive(:new).and_call_original + end + it do - expect_next_instance_of(DesignManagement::Repository) do |repository| + expect_next_instance_of(DesignManagement::GitRepository) do |repository| expect(repository).to receive(:blob_at).with(expected_ref, design.full_path).and_call_original end diff --git a/spec/controllers/projects/design_management/designs/resized_image_controller_spec.rb b/spec/controllers/projects/design_management/designs/resized_image_controller_spec.rb index 5cc6e1b1bb4..1bb5112681c 100644 --- a/spec/controllers/projects/design_management/designs/resized_image_controller_spec.rb +++ b/spec/controllers/projects/design_management/designs/resized_image_controller_spec.rb @@ -139,10 +139,13 @@ RSpec.describe Projects::DesignManagement::Designs::ResizedImageController, feat let(:sha) { newest_version.sha } before do - create(:design, :with_smaller_image_versions, - issue: create(:issue, project: project), - versions_count: 1, - versions_sha: sha) + create( + :design, + :with_smaller_image_versions, + issue: create(:issue, project: project), + versions_count: 1, + versions_sha: sha + ) end it 'serves the newest image' do diff --git a/spec/controllers/projects/environments/prometheus_api_controller_spec.rb b/spec/controllers/projects/environments/prometheus_api_controller_spec.rb index 6b0c164e432..ef2d743c82f 100644 --- a/spec/controllers/projects/environments/prometheus_api_controller_spec.rb +++ b/spec/controllers/projects/environments/prometheus_api_controller_spec.rb @@ -18,7 +18,7 @@ RSpec.describe Projects::Environments::PrometheusApiController do { id: proxyable.id.to_s, namespace_id: project.namespace.full_path, - project_id: project.name + project_id: project.path } end diff --git a/spec/controllers/projects/environments/sample_metrics_controller_spec.rb b/spec/controllers/projects/environments/sample_metrics_controller_spec.rb index 14e3ded76f2..b266c569edd 100644 --- a/spec/controllers/projects/environments/sample_metrics_controller_spec.rb +++ b/spec/controllers/projects/environments/sample_metrics_controller_spec.rb @@ -46,7 +46,7 @@ RSpec.describe Projects::Environments::SampleMetricsController do { id: environment.id.to_s, namespace_id: project.namespace.full_path, - project_id: project.name, + project_id: project.path, identifier: 'sample_metric_query_result', start: '2019-12-02T23:31:45.000Z', end: '2019-12-03T00:01:45.000Z' diff --git a/spec/controllers/projects/environments_controller_spec.rb b/spec/controllers/projects/environments_controller_spec.rb index 169fed1ab17..f097d08fe1b 100644 --- a/spec/controllers/projects/environments_controller_spec.rb +++ b/spec/controllers/projects/environments_controller_spec.rb @@ -15,6 +15,7 @@ RSpec.describe Projects::EnvironmentsController, feature_category: :continuous_d let!(:environment) { create(:environment, name: 'production', project: project) } before do + stub_feature_flags(remove_monitor_metrics: false) sign_in(user) end @@ -44,17 +45,9 @@ RSpec.describe Projects::EnvironmentsController, feature_category: :continuous_d allow_any_instance_of(Environment).to receive(:has_terminals?).and_return(true) allow_any_instance_of(Environment).to receive(:rollout_status).and_return(kube_deployment_rollout_status) - create(:environment, project: project, - name: 'staging/review-1', - state: :available) - - create(:environment, project: project, - name: 'staging/review-2', - state: :available) - - create(:environment, project: project, - name: 'staging/review-3', - state: :stopped) + create(:environment, project: project, name: 'staging/review-1', state: :available) + create(:environment, project: project, name: 'staging/review-2', state: :available) + create(:environment, project: project, name: 'staging/review-3', state: :stopped) end let(:environments) { json_response['environments'] } @@ -84,9 +77,7 @@ RSpec.describe Projects::EnvironmentsController, feature_category: :continuous_d it 'ignores search option if is shorter than a minimum' do get :index, params: environment_params(format: :json, search: 'st') - expect(environments.map { |env| env['name'] }).to contain_exactly('production', - 'staging/review-1', - 'staging/review-2') + expect(environments.map { |env| env['name'] }).to contain_exactly('production', 'staging/review-1', 'staging/review-2') expect(json_response['available_count']).to eq 3 expect(json_response['stopped_count']).to eq 1 end @@ -96,9 +87,7 @@ RSpec.describe Projects::EnvironmentsController, feature_category: :continuous_d get :index, params: environment_params(format: :json, search: 'review') - expect(environments.map { |env| env['name'] }).to contain_exactly('review-app', - 'staging/review-1', - 'staging/review-2') + expect(environments.map { |env| env['name'] }).to contain_exactly('review-app', 'staging/review-1', 'staging/review-2') expect(json_response['available_count']).to eq 3 expect(json_response['stopped_count']).to eq 1 end @@ -245,23 +234,18 @@ RSpec.describe Projects::EnvironmentsController, feature_category: :continuous_d context 'when using JSON format' do before do - create(:environment, project: project, - name: 'staging-1.0/review', - state: :available) - create(:environment, project: project, - name: 'staging-1.0/zzz', - state: :available) + create(:environment, project: project, name: 'staging-1.0/review', state: :available) + create(:environment, project: project, name: 'staging-1.0/zzz', state: :available) end let(:environments) { json_response['environments'] } it 'sorts the subfolders lexicographically' do get :folder, params: { - namespace_id: project.namespace, - project_id: project, - id: 'staging-1.0' - }, - format: :json + namespace_id: project.namespace, + project_id: project, + id: 'staging-1.0' + }, format: :json expect(response).to be_ok expect(response).not_to render_template 'folder' @@ -560,6 +544,18 @@ RSpec.describe Projects::EnvironmentsController, feature_category: :continuous_d expect(response).to redirect_to(project_metrics_dashboard_path(project)) end + + context 'when metrics dashboard feature is unavailable' do + before do + stub_feature_flags(remove_monitor_metrics: true) + end + + it 'returns 404 not found' do + get :metrics_redirect, params: { namespace_id: project.namespace, project_id: project } + + expect(response).to have_gitlab_http_status(:not_found) + end + end end describe 'GET #metrics' do @@ -631,6 +627,20 @@ RSpec.describe Projects::EnvironmentsController, feature_category: :continuous_d expect(response).to redirect_to(project_metrics_dashboard_path(project, environment: environment)) end end + + context 'when metrics dashboard feature is unavailable' do + before do + stub_feature_flags(remove_monitor_metrics: true) + end + + it 'returns 404 not found' do + expect(environment).not_to receive(:metrics) + + get :metrics, params: environment_params + + expect(response).to have_gitlab_http_status(:not_found) + end + end end describe 'GET #additional_metrics' do @@ -726,6 +736,18 @@ RSpec.describe Projects::EnvironmentsController, feature_category: :continuous_d expect(response).to have_gitlab_http_status(:ok) end end + + context 'when metrics dashboard feature is unavailable' do + before do + stub_feature_flags(remove_monitor_metrics: true) + end + + it 'returns 404 not found' do + additional_metrics(window_params) + + expect(response).to have_gitlab_http_status(:not_found) + end + end end describe 'GET #metrics_dashboard' do @@ -1016,98 +1038,8 @@ RSpec.describe Projects::EnvironmentsController, feature_category: :continuous_d end end - describe '#append_info_to_payload' do - let(:search_param) { 'my search param' } - - context 'when search_environment_logging feature is disabled' do - before do - stub_feature_flags(environments_search_logging: false) - end - - it 'does not log search params in meta.environment.search' do - expect(controller).to receive(:append_info_to_payload).and_wrap_original do |method, payload| - method.call(payload) - - expect(payload[:metadata]).not_to have_key('meta.environment.search') - expect(payload[:action]).to eq("search") - expect(payload[:controller]).to eq("Projects::EnvironmentsController") - end - - get :search, params: environment_params(format: :json, search: search_param) - end - - it 'logs params correctly when search params are missing' do - expect(controller).to receive(:append_info_to_payload).and_wrap_original do |method, payload| - method.call(payload) - - expect(payload[:metadata]).not_to have_key('meta.environment.search') - expect(payload[:action]).to eq("search") - expect(payload[:controller]).to eq("Projects::EnvironmentsController") - end - - get :search, params: environment_params(format: :json) - end - - it 'logs params correctly when search params is empty string' do - expect(controller).to receive(:append_info_to_payload).and_wrap_original do |method, payload| - method.call(payload) - - expect(payload[:metadata]).not_to have_key('meta.environment.search') - expect(payload[:action]).to eq("search") - expect(payload[:controller]).to eq("Projects::EnvironmentsController") - end - - get :search, params: environment_params(format: :json, search: "") - end - end - - context 'when search_environment_logging feature is enabled' do - before do - stub_feature_flags(environments_search_logging: true) - end - - it 'logs search params in meta.environment.search' do - expect(controller).to receive(:append_info_to_payload).and_wrap_original do |method, payload| - method.call(payload) - - expect(payload[:metadata]['meta.environment.search']).to eq(search_param) - expect(payload[:action]).to eq("search") - expect(payload[:controller]).to eq("Projects::EnvironmentsController") - end - - get :search, params: environment_params(format: :json, search: search_param) - end - - it 'logs params correctly when search params are missing' do - expect(controller).to receive(:append_info_to_payload).and_wrap_original do |method, payload| - method.call(payload) - - expect(payload[:metadata]).not_to have_key('meta.environment.search') - expect(payload[:action]).to eq("search") - expect(payload[:controller]).to eq("Projects::EnvironmentsController") - end - - get :search, params: environment_params(format: :json) - end - - it 'logs params correctly when search params is empty string' do - expect(controller).to receive(:append_info_to_payload).and_wrap_original do |method, payload| - method.call(payload) - - expect(payload[:metadata]).not_to have_key('meta.environment.search') - expect(payload[:action]).to eq("search") - expect(payload[:controller]).to eq("Projects::EnvironmentsController") - end - - get :search, params: environment_params(format: :json, search: "") - end - end - end - def environment_params(opts = {}) - opts.reverse_merge(namespace_id: project.namespace, - project_id: project, - id: environment.id) + opts.reverse_merge(namespace_id: project.namespace, project_id: project, id: environment.id) end def additional_metrics(opts = {}) diff --git a/spec/controllers/projects/feature_flags_controller_spec.rb b/spec/controllers/projects/feature_flags_controller_spec.rb index 29ad51d590f..ac2e4233709 100644 --- a/spec/controllers/projects/feature_flags_controller_spec.rb +++ b/spec/controllers/projects/feature_flags_controller_spec.rb @@ -193,8 +193,7 @@ RSpec.describe Projects::FeatureFlagsController do it 'routes based on iid' do other_project = create(:project) other_project.add_developer(user) - other_feature_flag = create(:operations_feature_flag, project: other_project, - name: 'other_flag') + other_feature_flag = create(:operations_feature_flag, project: other_project, name: 'other_flag') params = { namespace_id: other_project.namespace, project_id: other_project, @@ -485,8 +484,7 @@ RSpec.describe Projects::FeatureFlagsController do context 'when creating a version 2 feature flag with a gitlabUserList strategy' do let!(:user_list) do - create(:operations_feature_flag_user_list, project: project, - name: 'My List', user_xids: 'user1,user2') + create(:operations_feature_flag_user_list, project: project, name: 'My List', user_xids: 'user1,user2') end let(:params) do @@ -627,10 +625,7 @@ RSpec.describe Projects::FeatureFlagsController do context 'with a version 2 feature flag' do let!(:new_version_flag) do - create(:operations_feature_flag, - name: 'new-feature', - active: true, - project: project) + create(:operations_feature_flag, name: 'new-feature', active: true, project: project) end it 'creates a new strategy and scope' do diff --git a/spec/controllers/projects/find_file_controller_spec.rb b/spec/controllers/projects/find_file_controller_spec.rb index a6c71cff74b..68810bae368 100644 --- a/spec/controllers/projects/find_file_controller_spec.rb +++ b/spec/controllers/projects/find_file_controller_spec.rb @@ -18,12 +18,7 @@ RSpec.describe Projects::FindFileController do render_views before do - get(:show, - params: { - namespace_id: project.namespace, - project_id: project, - id: id - }) + get :show, params: { namespace_id: project.namespace, project_id: project, id: id } end context "valid branch" do @@ -41,13 +36,7 @@ RSpec.describe Projects::FindFileController do describe "GET #list" do def go(format: 'json') - get :list, - params: { - namespace_id: project.namespace, - project_id: project, - id: id - }, - format: format + get :list, params: { namespace_id: project.namespace, project_id: project, id: id }, format: format end context "valid branch" do diff --git a/spec/controllers/projects/forks_controller_spec.rb b/spec/controllers/projects/forks_controller_spec.rb index 25c722173c1..3ea7054a64c 100644 --- a/spec/controllers/projects/forks_controller_spec.rb +++ b/spec/controllers/projects/forks_controller_spec.rb @@ -168,12 +168,7 @@ RSpec.describe Projects::ForksController, feature_category: :source_code_managem let(:format) { :html } subject(:do_request) do - get :new, - format: format, - params: { - namespace_id: project.namespace, - project_id: project - } + get :new, format: format, params: { namespace_id: project.namespace, project_id: project } end context 'when user is signed in' do diff --git a/spec/controllers/projects/grafana_api_controller_spec.rb b/spec/controllers/projects/grafana_api_controller_spec.rb index 90ab49f9467..fa20fc5037f 100644 --- a/spec/controllers/projects/grafana_api_controller_spec.rb +++ b/spec/controllers/projects/grafana_api_controller_spec.rb @@ -15,6 +15,7 @@ RSpec.describe Projects::GrafanaApiController, feature_category: :metrics do end before do + stub_feature_flags(remove_monitor_metrics: false) sign_in(user) if user end @@ -23,7 +24,7 @@ RSpec.describe Projects::GrafanaApiController, feature_category: :metrics do let(:params) do { namespace_id: project.namespace.full_path, - project_id: project.name, + project_id: project.path, proxy_path: 'api/v1/query_range', datasource_id: '1', query: 'rate(relevant_metric)', @@ -87,13 +88,15 @@ RSpec.describe Projects::GrafanaApiController, feature_category: :metrics do it 'returns a grafana datasource response' do get :proxy, params: params - expect(Grafana::ProxyService) - .to have_received(:new) - .with(project, '1', 'api/v1/query_range', - { 'query' => params[:query], - 'start' => params[:start_time], - 'end' => params[:end_time], - 'step' => params[:step] }) + expect(Grafana::ProxyService).to have_received(:new).with( + project, '1', 'api/v1/query_range', + { + 'query' => params[:query], + 'start' => params[:start_time], + 'end' => params[:end_time], + 'step' => params[:step] + } + ) expect(response).to have_gitlab_http_status(:ok) expect(json_response).to eq({}) @@ -168,6 +171,14 @@ RSpec.describe Projects::GrafanaApiController, feature_category: :metrics do it_behaves_like 'accessible' end end + + context 'when metrics dashboard feature is unavailable' do + before do + stub_feature_flags(remove_monitor_metrics: true) + end + + it_behaves_like 'not accessible' + end end describe 'GET #metrics_dashboard' do @@ -178,7 +189,7 @@ RSpec.describe Projects::GrafanaApiController, feature_category: :metrics do embedded: true, grafana_url: 'https://grafana.example.com', namespace_id: project.namespace.full_path, - project_id: project.name + project_id: project.path } end diff --git a/spec/controllers/projects/graphs_controller_spec.rb b/spec/controllers/projects/graphs_controller_spec.rb index 1e9d999311a..3e5bcbbc9ba 100644 --- a/spec/controllers/projects/graphs_controller_spec.rb +++ b/spec/controllers/projects/graphs_controller_spec.rb @@ -141,7 +141,6 @@ RSpec.describe Projects::GraphsController do end let(:request_params) { { namespace_id: project.namespace.path, project_id: project.path, id: 'master' } } - let(:feature_flag_name) { :route_hll_to_snowplow_phase2 } let(:category) { described_class.name } let(:action) { 'perform_analytics_usage_action' } let(:namespace) { project.namespace } diff --git a/spec/controllers/projects/group_links_controller_spec.rb b/spec/controllers/projects/group_links_controller_spec.rb index a5c00d24e30..2075dd3e7a7 100644 --- a/spec/controllers/projects/group_links_controller_spec.rb +++ b/spec/controllers/projects/group_links_controller_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' -RSpec.describe Projects::GroupLinksController, feature_category: :authentication_and_authorization do +RSpec.describe Projects::GroupLinksController, feature_category: :system_access do let_it_be(:group) { create(:group, :private) } let_it_be(:group2) { create(:group, :private) } let_it_be(:project) { create(:project, :private, group: group2) } diff --git a/spec/controllers/projects/hooks_controller_spec.rb b/spec/controllers/projects/hooks_controller_spec.rb index 815370d428d..c056e7a33aa 100644 --- a/spec/controllers/projects/hooks_controller_spec.rb +++ b/spec/controllers/projects/hooks_controller_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' -RSpec.describe Projects::HooksController do +RSpec.describe Projects::HooksController, feature_category: :integrations do include AfterNextHelpers let_it_be(:project) { create(:project) } @@ -173,6 +173,16 @@ RSpec.describe Projects::HooksController do let(:params) { { namespace_id: project.namespace, project_id: project, id: hook } } it_behaves_like 'Web hook destroyer' + + context 'when user does not have permission' do + let(:user) { create(:user, developer_projects: [project]) } + + it 'renders a 404' do + delete :destroy, params: params + + expect(response).to have_gitlab_http_status(:not_found) + end + end end describe '#test' do diff --git a/spec/controllers/projects/imports_controller_spec.rb b/spec/controllers/projects/imports_controller_spec.rb index 65a80b9e8ec..4502f3d7bd9 100644 --- a/spec/controllers/projects/imports_controller_spec.rb +++ b/spec/controllers/projects/imports_controller_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' -RSpec.describe Projects::ImportsController do +RSpec.describe Projects::ImportsController, feature_category: :importers do let(:user) { create(:user) } let(:project) { create(:project) } @@ -27,7 +27,7 @@ RSpec.describe Projects::ImportsController do project.add_maintainer(user) end - context 'when repository does not exists' do + context 'when repository does not exist' do it 'renders template' do get :show, params: { namespace_id: project.namespace.to_param, project_id: project } @@ -149,17 +149,7 @@ RSpec.describe Projects::ImportsController do import_state.update!(status: :started) end - context 'when group allows developers to create projects' do - let(:group) { create(:group, project_creation_level: Gitlab::Access::DEVELOPER_MAINTAINER_PROJECT_ACCESS) } - - it 'renders template' do - get :show, params: { namespace_id: project.namespace.to_param, project_id: project } - - expect(response).to render_template :show - end - end - - context 'when group prohibits developers to create projects' do + context 'when group prohibits developers to import projects' do let(:group) { create(:group, project_creation_level: Gitlab::Access::MAINTAINER_PROJECT_ACCESS) } it 'returns 404 response' do diff --git a/spec/controllers/projects/issues_controller_spec.rb b/spec/controllers/projects/issues_controller_spec.rb index 9c272872a73..5f606b1f4f3 100644 --- a/spec/controllers/projects/issues_controller_spec.rb +++ b/spec/controllers/projects/issues_controller_spec.rb @@ -183,22 +183,10 @@ RSpec.describe Projects::IssuesController, feature_category: :team_planning do let_it_be(:task) { create(:issue, :task, project: project) } shared_examples 'redirects to show work item page' do - context 'when use_iid_in_work_items_path feature flag is disabled' do - before do - stub_feature_flags(use_iid_in_work_items_path: false) - end - - it 'redirects to work item page' do - make_request - - expect(response).to redirect_to(project_work_items_path(project, task.id, query)) - end - end - it 'redirects to work item page using iid' do make_request - expect(response).to redirect_to(project_work_items_path(project, task.iid, query.merge(iid_path: true))) + expect(response).to redirect_to(project_work_items_path(project, task.iid, query)) end end @@ -255,7 +243,7 @@ RSpec.describe Projects::IssuesController, feature_category: :team_planning do get :new, params: { namespace_id: project.namespace, project_id: project } expect(assigns(:issue)).to be_a_new(Issue) - expect(assigns(:issue).issue_type).to eq('issue') + expect(assigns(:issue).work_item_type.base_type).to eq('issue') end where(:conf_value, :conf_result) do @@ -292,7 +280,7 @@ RSpec.describe Projects::IssuesController, feature_category: :team_planning do get :new, params: { namespace_id: project.namespace, project_id: project, issue: { issue_type: issue_type } } end - subject { assigns(:issue).issue_type } + subject { assigns(:issue).work_item_type.base_type } it { is_expected.to eq('issue') } @@ -585,15 +573,13 @@ RSpec.describe Projects::IssuesController, feature_category: :team_planning do end def reorder_issue(issue, move_after_id: nil, move_before_id: nil) - put :reorder, - params: { - namespace_id: project.namespace.to_param, - project_id: project, - id: issue.iid, - move_after_id: move_after_id, - move_before_id: move_before_id - }, - format: :json + put :reorder, params: { + namespace_id: project.namespace.to_param, + project_id: project, + id: issue.iid, + move_after_id: move_after_id, + move_before_id: move_before_id + }, format: :json end end @@ -601,14 +587,12 @@ RSpec.describe Projects::IssuesController, feature_category: :team_planning do let(:issue_params) { { title: 'New title' } } subject do - put :update, - params: { - namespace_id: project.namespace, - project_id: project, - id: issue.to_param, - issue: issue_params - }, - format: :json + put :update, params: { + namespace_id: project.namespace, + project_id: project, + id: issue.to_param, + issue: issue_params + }, format: :json end before do @@ -635,7 +619,7 @@ RSpec.describe Projects::IssuesController, feature_category: :team_planning do subject expect(response).to have_gitlab_http_status(:ok) - expect(issue.reload.issue_type).to eql('incident') + expect(issue.reload.work_item_type.base_type).to eq('incident') end end @@ -746,7 +730,7 @@ RSpec.describe Projects::IssuesController, feature_category: :team_planning do go(id: issue.iid) expect(json_response).to include('title_text', 'description', 'description_text') - expect(json_response).to include('task_status', 'lock_version') + expect(json_response).to include('task_completion_status', 'lock_version') end end end @@ -1091,7 +1075,6 @@ RSpec.describe Projects::IssuesController, feature_category: :team_planning do it 'sets the correct issue_type' do issue = post_new_issue(issue_type: 'incident') - expect(issue.issue_type).to eq('incident') expect(issue.work_item_type.base_type).to eq('incident') end end @@ -1100,7 +1083,6 @@ RSpec.describe Projects::IssuesController, feature_category: :team_planning do it 'defaults to issue type' do issue = post_new_issue(issue_type: 'task') - expect(issue.issue_type).to eq('issue') expect(issue.work_item_type.base_type).to eq('issue') end end @@ -1109,7 +1091,6 @@ RSpec.describe Projects::IssuesController, feature_category: :team_planning do it 'defaults to issue type' do issue = post_new_issue(issue_type: 'objective') - expect(issue.issue_type).to eq('issue') expect(issue.work_item_type.base_type).to eq('issue') end end @@ -1118,7 +1099,6 @@ RSpec.describe Projects::IssuesController, feature_category: :team_planning do it 'defaults to issue type' do issue = post_new_issue(issue_type: 'key_result') - expect(issue.issue_type).to eq('issue') expect(issue.work_item_type.base_type).to eq('issue') end end @@ -1168,7 +1148,6 @@ RSpec.describe Projects::IssuesController, feature_category: :team_planning do expect(issue).to be_a(Issue) expect(issue.persisted?).to eq(true) - expect(issue.issue_type).to eq('issue') expect(issue.work_item_type.base_type).to eq('issue') end @@ -1419,7 +1398,7 @@ RSpec.describe Projects::IssuesController, feature_category: :team_planning do context 'setting issue type' do let(:issue_type) { 'issue' } - subject { post_new_issue(issue_type: issue_type)&.issue_type } + subject { post_new_issue(issue_type: issue_type)&.work_item_type&.base_type } it { is_expected.to eq('issue') } @@ -1484,7 +1463,7 @@ RSpec.describe Projects::IssuesController, feature_category: :team_planning do it "deletes the issue" do delete :destroy, params: { namespace_id: project.namespace, project_id: project, id: issue.iid, destroy_confirm: true } - expect(response).to have_gitlab_http_status(:found) + expect(response).to have_gitlab_http_status(:see_other) expect(controller).to set_flash[:notice].to(/The issue was successfully deleted\./) end @@ -1927,12 +1906,11 @@ RSpec.describe Projects::IssuesController, feature_category: :team_planning do end it 'redirects from an old issue/designs correctly' do - get :designs, - params: { - namespace_id: project.namespace, - project_id: project, - id: issue - } + get :designs, params: { + namespace_id: project.namespace, + project_id: project, + id: issue + } expect(response).to redirect_to(designs_project_issue_path(new_project, issue)) expect(response).to have_gitlab_http_status(:moved_permanently) diff --git a/spec/controllers/projects/jobs_controller_spec.rb b/spec/controllers/projects/jobs_controller_spec.rb index 2d047957430..ede26ebd032 100644 --- a/spec/controllers/projects/jobs_controller_spec.rb +++ b/spec/controllers/projects/jobs_controller_spec.rb @@ -1,11 +1,13 @@ # frozen_string_literal: true require 'spec_helper' -RSpec.describe Projects::JobsController, :clean_gitlab_redis_shared_state, feature_category: :continuous_integration do +RSpec.describe Projects::JobsController, :clean_gitlab_redis_shared_state, feature_category: :continuous_integration, factory_default: :keep do include ApiHelpers include HttpIOHelpers + let_it_be(:namespace) { create_default(:namespace) } let_it_be(:project) { create(:project, :public, :repository) } + let_it_be(:merge_request) { create(:merge_request, source_project: project) } let_it_be(:owner) { create(:owner) } let_it_be(:admin) { create(:admin) } let_it_be(:maintainer) { create(:user) } @@ -19,11 +21,16 @@ RSpec.describe Projects::JobsController, :clean_gitlab_redis_shared_state, featu project.add_developer(developer) project.add_reporter(reporter) project.add_guest(guest) + create_default(:owner) + create_default(:user) + create_default(:ci_trigger_request) + create_default(:ci_stage) end let(:user) { developer } - let(:pipeline) { create(:ci_pipeline, project: project) } + let_it_be_with_reload(:pipeline) { create(:ci_pipeline, project: project) } + let_it_be(:default_pipeline) { create_default(:ci_pipeline) } before do stub_feature_flags(ci_enable_live_trace: true) @@ -106,9 +113,10 @@ RSpec.describe Projects::JobsController, :clean_gitlab_redis_shared_state, featu def create_job(name, status) user = create(:user) pipeline = create(:ci_pipeline, project: project, user: user) - create(:ci_build, :tags, :triggered, :artifacts, - pipeline: pipeline, name: name, status: status, - user: user) + create( + :ci_build, :tags, :triggered, :artifacts, + pipeline: pipeline, name: name, status: status, user: user + ) end end @@ -151,7 +159,6 @@ RSpec.describe Projects::JobsController, :clean_gitlab_redis_shared_state, featu end context 'when requesting JSON' do - let(:merge_request) { create(:merge_request, source_project: project) } let(:user) { developer } before do @@ -210,9 +217,9 @@ RSpec.describe Projects::JobsController, :clean_gitlab_redis_shared_state, featu end context 'when job has artifacts' do - context 'with not expiry date' do - let(:job) { create(:ci_build, :success, :artifacts, pipeline: pipeline) } + let_it_be(:job) { create(:ci_build, :success, :artifacts, pipeline: pipeline) } + context 'with not expiry date' do context 'when artifacts are unlocked' do before do job.pipeline.unlocked! @@ -233,7 +240,7 @@ RSpec.describe Projects::JobsController, :clean_gitlab_redis_shared_state, featu context 'when artifacts are locked' do before do - job.pipeline.artifacts_locked! + job.pipeline.reload.artifacts_locked! end it 'exposes needed information' do @@ -251,11 +258,13 @@ RSpec.describe Projects::JobsController, :clean_gitlab_redis_shared_state, featu end context 'with expired artifacts' do - let(:job) { create(:ci_build, :success, :artifacts, :expired, pipeline: pipeline) } + before do + job.update!(artifacts_expire_at: 1.minute.ago) + end context 'when artifacts are unlocked' do before do - job.pipeline.unlocked! + job.pipeline.reload.unlocked! end it 'exposes needed information' do @@ -274,7 +283,7 @@ RSpec.describe Projects::JobsController, :clean_gitlab_redis_shared_state, featu context 'when artifacts are locked' do before do - job.pipeline.artifacts_locked! + job.pipeline.reload.artifacts_locked! end it 'exposes needed information' do @@ -291,19 +300,17 @@ RSpec.describe Projects::JobsController, :clean_gitlab_redis_shared_state, featu end end end - end - - context 'when job passed with no trace' do - let(:job) { create(:ci_build, :success, :artifacts, pipeline: pipeline) } - it 'exposes empty state illustrations' do - get_show_json + context 'when job passed with no trace' do + it 'exposes empty state illustrations' do + get_show_json - expect(response).to have_gitlab_http_status(:ok) - expect(response).to match_response_schema('job/job_details') - expect(json_response['status']['illustration']).to have_key('image') - expect(json_response['status']['illustration']).to have_key('size') - expect(json_response['status']['illustration']).to have_key('title') + expect(response).to have_gitlab_http_status(:ok) + expect(response).to match_response_schema('job/job_details') + expect(json_response['status']['illustration']).to have_key('image') + expect(json_response['status']['illustration']).to have_key('size') + expect(json_response['status']['illustration']).to have_key('title') + end end end @@ -319,7 +326,6 @@ RSpec.describe Projects::JobsController, :clean_gitlab_redis_shared_state, featu end context 'with deployment' do - let(:merge_request) { create(:merge_request, source_project: project) } let(:environment) { create(:environment, project: project, name: 'staging', state: :available) } let(:job) { create(:ci_build, :running, environment: environment.name, pipeline: pipeline) } @@ -511,7 +517,6 @@ RSpec.describe Projects::JobsController, :clean_gitlab_redis_shared_state, featu end context 'when requesting triggered job JSON' do - let!(:merge_request) { create(:merge_request, source_project: project) } let(:trigger) { create(:ci_trigger, project: project) } let(:trigger_request) { create(:ci_trigger_request, pipeline: pipeline, trigger: trigger) } let(:job) { create(:ci_build, pipeline: pipeline, trigger_request: trigger_request) } @@ -832,8 +837,7 @@ RSpec.describe Projects::JobsController, :clean_gitlab_redis_shared_state, featu retried_build = Ci::Build.last Ci::Build.clone_accessors.each do |accessor| - expect(job.read_attribute(accessor)) - .to eq(retried_build.read_attribute(accessor)), + expect(job.read_attribute(accessor)).to eq(retried_build.read_attribute(accessor)), "Mismatched attribute on \"#{accessor}\". " \ "It was \"#{job.read_attribute(accessor)}\" but changed to \"#{retried_build.read_attribute(accessor)}\"" end @@ -855,10 +859,10 @@ RSpec.describe Projects::JobsController, :clean_gitlab_redis_shared_state, featu def post_retry post :retry, params: { - namespace_id: project.namespace, - project_id: project, - id: job.id - } + namespace_id: project.namespace, + project_id: project, + id: job.id + } end end @@ -869,8 +873,7 @@ RSpec.describe Projects::JobsController, :clean_gitlab_redis_shared_state, featu before do project.add_developer(user) - create(:protected_branch, :developers_can_merge, - name: 'protected-branch', project: project) + create(:protected_branch, :developers_can_merge, name: 'protected-branch', project: project) sign_in(user) end diff --git a/spec/controllers/projects/mattermosts_controller_spec.rb b/spec/controllers/projects/mattermosts_controller_spec.rb index 19a04654114..b5092a0f091 100644 --- a/spec/controllers/projects/mattermosts_controller_spec.rb +++ b/spec/controllers/projects/mattermosts_controller_spec.rb @@ -19,11 +19,10 @@ RSpec.describe Projects::MattermostsController do end it 'accepts the request' do - get(:new, - params: { - namespace_id: project.namespace.to_param, - project_id: project - }) + get :new, params: { + namespace_id: project.namespace.to_param, + project_id: project + } expect(response).to have_gitlab_http_status(:ok) end @@ -33,12 +32,11 @@ RSpec.describe Projects::MattermostsController do let(:mattermost_params) { { trigger: 'http://localhost:3000/trigger', team_id: 'abc' } } subject do - post(:create, - params: { - namespace_id: project.namespace.to_param, - project_id: project, - mattermost: mattermost_params - }) + post :create, params: { + namespace_id: project.namespace.to_param, + project_id: project, + mattermost: mattermost_params + } end context 'no request can be made to mattermost' do diff --git a/spec/controllers/projects/merge_requests/conflicts_controller_spec.rb b/spec/controllers/projects/merge_requests/conflicts_controller_spec.rb index 311af26abf6..926cd7ea681 100644 --- a/spec/controllers/projects/merge_requests/conflicts_controller_spec.rb +++ b/spec/controllers/projects/merge_requests/conflicts_controller_spec.rb @@ -22,13 +22,11 @@ RSpec.describe Projects::MergeRequests::ConflictsController do allow(Gitlab::UsageDataCounters::MergeRequestActivityUniqueCounter) .to receive(:track_loading_conflict_ui_action) - get :show, - params: { - namespace_id: merge_request_with_conflicts.project.namespace.to_param, - project_id: merge_request_with_conflicts.project, - id: merge_request_with_conflicts.iid - }, - format: 'html' + get :show, params: { + namespace_id: merge_request_with_conflicts.project.namespace.to_param, + project_id: merge_request_with_conflicts.project, + id: merge_request_with_conflicts.iid + }, format: 'html' end it 'does tracks the resolve call' do @@ -45,13 +43,11 @@ RSpec.describe Projects::MergeRequests::ConflictsController do allow(Gitlab::Git::Conflict::Parser).to receive(:parse) .and_raise(Gitlab::Git::Conflict::Parser::UnmergeableFile) - get :show, - params: { - namespace_id: merge_request_with_conflicts.project.namespace.to_param, - project_id: merge_request_with_conflicts.project, - id: merge_request_with_conflicts.iid - }, - format: 'json' + get :show, params: { + namespace_id: merge_request_with_conflicts.project.namespace.to_param, + project_id: merge_request_with_conflicts.project, + id: merge_request_with_conflicts.iid + }, format: 'json' end it 'returns a 200 status code' do @@ -70,13 +66,11 @@ RSpec.describe Projects::MergeRequests::ConflictsController do context 'with valid conflicts' do before do - get :show, - params: { - namespace_id: merge_request_with_conflicts.project.namespace.to_param, - project_id: merge_request_with_conflicts.project, - id: merge_request_with_conflicts.iid - }, - format: 'json' + get :show, params: { + namespace_id: merge_request_with_conflicts.project.namespace.to_param, + project_id: merge_request_with_conflicts.project, + id: merge_request_with_conflicts.iid + }, format: 'json' end it 'matches the schema' do @@ -91,7 +85,7 @@ RSpec.describe Projects::MergeRequests::ConflictsController do end it 'includes each file that has conflicts' do - filenames = json_response['files'].map { |file| file['new_path'] } + filenames = json_response['files'].pluck('new_path') expect(filenames).to contain_exactly('files/ruby/popen.rb', 'files/ruby/regex.rb') end @@ -120,7 +114,7 @@ RSpec.describe Projects::MergeRequests::ConflictsController do it 'has unique section IDs across files' do section_ids = json_response['files'].flat_map do |file| - file['sections'].map { |section| section['id'] }.compact + file['sections'].pluck('id').compact end expect(section_ids.uniq).to eq(section_ids) @@ -130,15 +124,13 @@ RSpec.describe Projects::MergeRequests::ConflictsController do describe 'GET conflict_for_path' do def conflict_for_path(path) - get :conflict_for_path, - params: { - namespace_id: merge_request_with_conflicts.project.namespace.to_param, - project_id: merge_request_with_conflicts.project, - id: merge_request_with_conflicts.iid, - old_path: path, - new_path: path - }, - format: 'json' + get :conflict_for_path, params: { + namespace_id: merge_request_with_conflicts.project.namespace.to_param, + project_id: merge_request_with_conflicts.project, + id: merge_request_with_conflicts.iid, + old_path: path, + new_path: path + }, format: 'json' end context 'when the conflicts cannot be resolved in the UI' do @@ -178,11 +170,13 @@ RSpec.describe Projects::MergeRequests::ConflictsController do aggregate_failures do expect(response).to have_gitlab_http_status(:ok) - expect(json_response).to include('old_path' => path, - 'new_path' => path, - 'blob_icon' => 'doc-text', - 'blob_path' => a_string_ending_with(path), - 'content' => content) + expect(json_response).to include( + 'old_path' => path, + 'new_path' => path, + 'blob_icon' => 'doc-text', + 'blob_path' => a_string_ending_with(path), + 'content' => content + ) end end end @@ -197,15 +191,13 @@ RSpec.describe Projects::MergeRequests::ConflictsController do end def resolve_conflicts(files) - post :resolve_conflicts, - params: { - namespace_id: merge_request_with_conflicts.project.namespace.to_param, - project_id: merge_request_with_conflicts.project, - id: merge_request_with_conflicts.iid, - files: files, - commit_message: 'Commit message' - }, - format: 'json' + post :resolve_conflicts, params: { + namespace_id: merge_request_with_conflicts.project.namespace.to_param, + project_id: merge_request_with_conflicts.project, + id: merge_request_with_conflicts.iid, + files: files, + commit_message: 'Commit message' + }, format: 'json' end context 'with valid params' do diff --git a/spec/controllers/projects/merge_requests/creations_controller_spec.rb b/spec/controllers/projects/merge_requests/creations_controller_spec.rb index 3d4a884587f..c6a4dcbfdf0 100644 --- a/spec/controllers/projects/merge_requests/creations_controller_spec.rb +++ b/spec/controllers/projects/merge_requests/creations_controller_spec.rb @@ -99,9 +99,7 @@ RSpec.describe Projects::MergeRequests::CreationsController, feature_category: : describe 'GET pipelines' do before do - create(:ci_pipeline, sha: fork_project.commit('remove-submodule').id, - ref: 'remove-submodule', - project: fork_project) + create(:ci_pipeline, sha: fork_project.commit('remove-submodule').id, ref: 'remove-submodule', project: fork_project) end it 'renders JSON including serialized pipelines' do @@ -188,13 +186,12 @@ RSpec.describe Projects::MergeRequests::CreationsController, feature_category: : expect(Ability).to receive(:allowed?).with(user, :read_project, project) { true } expect(Ability).to receive(:allowed?).with(user, :create_merge_request_in, project) { true }.at_least(:once) - get :branch_to, - params: { - namespace_id: fork_project.namespace, - project_id: fork_project, - target_project_id: project.id, - ref: 'master' - } + get :branch_to, params: { + namespace_id: fork_project.namespace, + project_id: fork_project, + target_project_id: project.id, + ref: 'master' + } expect(assigns(:commit)).not_to be_nil expect(response).to have_gitlab_http_status(:ok) @@ -204,13 +201,12 @@ RSpec.describe Projects::MergeRequests::CreationsController, feature_category: : expect(Ability).to receive(:allowed?).with(user, :read_project, project) { true } expect(Ability).to receive(:allowed?).with(user, :create_merge_request_in, project) { false }.at_least(:once) - get :branch_to, - params: { - namespace_id: fork_project.namespace, - project_id: fork_project, - target_project_id: project.id, - ref: 'master' - } + get :branch_to, params: { + namespace_id: fork_project.namespace, + project_id: fork_project, + target_project_id: project.id, + ref: 'master' + } expect(assigns(:commit)).to be_nil expect(response).to have_gitlab_http_status(:ok) @@ -220,13 +216,12 @@ RSpec.describe Projects::MergeRequests::CreationsController, feature_category: : expect(Ability).to receive(:allowed?).with(user, :read_project, project) { false } expect(Ability).to receive(:allowed?).with(user, :create_merge_request_in, project) { true }.at_least(:once) - get :branch_to, - params: { - namespace_id: fork_project.namespace, - project_id: fork_project, - target_project_id: project.id, - ref: 'master' - } + get :branch_to, params: { + namespace_id: fork_project.namespace, + project_id: fork_project, + target_project_id: project.id, + ref: 'master' + } expect(assigns(:commit)).to be_nil expect(response).to have_gitlab_http_status(:ok) diff --git a/spec/controllers/projects/merge_requests/diffs_controller_spec.rb b/spec/controllers/projects/merge_requests/diffs_controller_spec.rb index 23a33d7e0b1..3b562b4c151 100644 --- a/spec/controllers/projects/merge_requests/diffs_controller_spec.rb +++ b/spec/controllers/projects/merge_requests/diffs_controller_spec.rb @@ -247,9 +247,11 @@ RSpec.describe Projects::MergeRequests::DiffsController, feature_category: :code straight: true) end - go(diff_head: true, - diff_id: merge_request.merge_request_diff.id, - start_sha: merge_request.merge_request_diff.start_commit_sha) + go( + diff_head: true, + diff_id: merge_request.merge_request_diff.id, + start_sha: merge_request.merge_request_diff.start_commit_sha + ) end end end @@ -329,15 +331,17 @@ RSpec.describe Projects::MergeRequests::DiffsController, feature_category: :code diff_for_path(old_path: existing_path, new_path: existing_path) expect(assigns(:diff_notes_disabled)).to be_falsey - expect(assigns(:new_diff_note_attrs)).to eq(noteable_type: 'MergeRequest', - noteable_id: merge_request.id, - commit_id: nil) + expect(assigns(:new_diff_note_attrs)).to eq( + noteable_type: 'MergeRequest', + noteable_id: merge_request.id, + commit_id: nil + ) end it 'only renders the diffs for the path given' do diff_for_path(old_path: existing_path, new_path: existing_path) - paths = json_response['diff_files'].map { |file| file['new_path'] } + paths = json_response['diff_files'].pluck('new_path') expect(paths).to include(existing_path) end @@ -528,8 +532,7 @@ RSpec.describe Projects::MergeRequests::DiffsController, feature_category: :code context 'with diff_id and start_sha params' do subject do - go(diff_id: merge_request.merge_request_diff.id, - start_sha: merge_request.merge_request_diff.start_commit_sha) + go(diff_id: merge_request.merge_request_diff.id, start_sha: merge_request.merge_request_diff.start_commit_sha) end it_behaves_like 'serializes diffs with expected arguments' do diff --git a/spec/controllers/projects/merge_requests/drafts_controller_spec.rb b/spec/controllers/projects/merge_requests/drafts_controller_spec.rb index 39482938a8b..6632473a85c 100644 --- a/spec/controllers/projects/merge_requests/drafts_controller_spec.rb +++ b/spec/controllers/projects/merge_requests/drafts_controller_spec.rb @@ -299,8 +299,7 @@ RSpec.describe Projects::MergeRequests::DraftsController do it 'publishes a draft note with quick actions and applies them', :sidekiq_inline do project.add_developer(user2) - create(:draft_note, merge_request: merge_request, author: user, - note: "/assign #{user2.to_reference}") + create(:draft_note, merge_request: merge_request, author: user, note: "/assign #{user2.to_reference}") expect(merge_request.assignees).to be_empty @@ -350,12 +349,13 @@ RSpec.describe Projects::MergeRequests::DraftsController do let(:note) { create(:discussion_note_on_merge_request, noteable: merge_request, project: project) } def create_reply(discussion_id, resolves: false) - create(:draft_note, - merge_request: merge_request, - author: user, - discussion_id: discussion_id, - resolve_discussion: resolves - ) + create( + :draft_note, + merge_request: merge_request, + author: user, + discussion_id: discussion_id, + resolve_discussion: resolves + ) end it 'resolves a thread if the draft note resolves it' do diff --git a/spec/controllers/projects/merge_requests_controller_spec.rb b/spec/controllers/projects/merge_requests_controller_spec.rb index ceb3f803db5..f78d50bba24 100644 --- a/spec/controllers/projects/merge_requests_controller_spec.rb +++ b/spec/controllers/projects/merge_requests_controller_spec.rb @@ -210,9 +210,7 @@ RSpec.describe Projects::MergeRequestsController, feature_category: :code_review diff = merge_request.merge_request_diff diff.clean! - diff.update!(real_size: nil, - start_commit_sha: nil, - base_commit_sha: nil) + diff.update!(real_size: nil, start_commit_sha: nil, base_commit_sha: nil) go(format: :html) @@ -270,24 +268,22 @@ RSpec.describe Projects::MergeRequestsController, feature_category: :code_review end it 'redirects from an old merge request correctly' do - get :show, - params: { - namespace_id: project.namespace, - project_id: project, - id: merge_request - } + get :show, params: { + namespace_id: project.namespace, + project_id: project, + id: merge_request + } expect(response).to redirect_to(project_merge_request_path(new_project, merge_request)) expect(response).to have_gitlab_http_status(:moved_permanently) end it 'redirects from an old merge request commits correctly' do - get :commits, - params: { - namespace_id: project.namespace, - project_id: project, - id: merge_request - } + get :commits, params: { + namespace_id: project.namespace, + project_id: project, + id: merge_request + } expect(response).to redirect_to(commits_project_merge_request_path(new_project, merge_request)) expect(response).to have_gitlab_http_status(:moved_permanently) @@ -385,13 +381,12 @@ RSpec.describe Projects::MergeRequestsController, feature_category: :code_review let(:merge_request) { create(:merge_request_with_diffs, target_project: project, source_project: project) } def get_merge_requests(page = nil) - get :index, - params: { - namespace_id: project.namespace.to_param, - project_id: project, - state: 'opened', - page: page.to_param - } + get :index, params: { + namespace_id: project.namespace.to_param, + project_id: project, + state: 'opened', + page: page.to_param + } end it_behaves_like "issuables list meta-data", :merge_request @@ -580,6 +575,16 @@ RSpec.describe Projects::MergeRequestsController, feature_category: :code_review it 'returns :failed' do expect(json_response).to eq('status' => 'failed') end + + context 'for logging' do + let(:expected_params) { { merge_action_status: 'failed' } } + let(:subject_proc) { proc { subject } } + + subject { post :merge, params: base_params } + + it_behaves_like 'storing arguments in the application context' + it_behaves_like 'not executing any extra queries for the application context' + end end context 'when the sha parameter does not match the source SHA' do @@ -590,6 +595,16 @@ RSpec.describe Projects::MergeRequestsController, feature_category: :code_review it 'returns :sha_mismatch' do expect(json_response).to eq('status' => 'sha_mismatch') end + + context 'for logging' do + let(:expected_params) { { merge_action_status: 'sha_mismatch' } } + let(:subject_proc) { proc { subject } } + + subject { post :merge, params: base_params.merge(sha: 'foo') } + + it_behaves_like 'storing arguments in the application context' + it_behaves_like 'not executing any extra queries for the application context' + end end context 'when the sha parameter matches the source SHA' do @@ -611,6 +626,16 @@ RSpec.describe Projects::MergeRequestsController, feature_category: :code_review merge_with_sha end + context 'for logging' do + let(:expected_params) { { merge_action_status: 'success' } } + let(:subject_proc) { proc { subject } } + + subject { merge_with_sha } + + it_behaves_like 'storing arguments in the application context' + it_behaves_like 'not executing any extra queries for the application context' + end + context 'when squash is passed as 1' do it 'updates the squash attribute on the MR to true' do merge_request.update!(squash: false) @@ -678,6 +703,16 @@ RSpec.describe Projects::MergeRequestsController, feature_category: :code_review merge_when_pipeline_succeeds end + context 'for logging' do + let(:expected_params) { { merge_action_status: 'merge_when_pipeline_succeeds' } } + let(:subject_proc) { proc { subject } } + + subject { merge_when_pipeline_succeeds } + + it_behaves_like 'storing arguments in the application context' + it_behaves_like 'not executing any extra queries for the application context' + end + context 'when project.only_allow_merge_if_pipeline_succeeds? is true' do before do project.update_column(:only_allow_merge_if_pipeline_succeeds, true) @@ -816,7 +851,7 @@ RSpec.describe Projects::MergeRequestsController, feature_category: :code_review it "deletes the merge request" do delete :destroy, params: { namespace_id: project.namespace, project_id: project, id: merge_request.iid, destroy_confirm: true } - expect(response).to have_gitlab_http_status(:found) + expect(response).to have_gitlab_http_status(:see_other) expect(controller).to set_flash[:notice].to(/The merge request was successfully deleted\./) end @@ -842,15 +877,13 @@ RSpec.describe Projects::MergeRequestsController, feature_category: :code_review describe 'GET commits' do def go(page: nil, per_page: 1, format: 'html') - get :commits, - params: { - namespace_id: project.namespace.to_param, - project_id: project, - id: merge_request.iid, - page: page, - per_page: per_page - }, - format: format + get :commits, params: { + namespace_id: project.namespace.to_param, + project_id: project, + id: merge_request.iid, + page: page, + per_page: per_page + }, format: format end it 'renders the commits template to a string' do @@ -884,17 +917,18 @@ RSpec.describe Projects::MergeRequestsController, feature_category: :code_review describe 'GET pipelines' do before do - create(:ci_pipeline, project: merge_request.source_project, - ref: merge_request.source_branch, - sha: merge_request.diff_head_sha) + create( + :ci_pipeline, + project: merge_request.source_project, + ref: merge_request.source_branch, + sha: merge_request.diff_head_sha + ) - get :pipelines, - params: { - namespace_id: project.namespace.to_param, - project_id: project, - id: merge_request.iid - }, - format: :json + get :pipelines, params: { + namespace_id: project.namespace.to_param, + project_id: project, + id: merge_request.iid + }, format: :json end context 'with "enabled" builds on a public project' do @@ -1955,17 +1989,18 @@ RSpec.describe Projects::MergeRequestsController, feature_category: :code_review let(:issue2) { create(:issue, project: project) } def post_assign_issues - merge_request.update!(description: "Closes #{issue1.to_reference} and #{issue2.to_reference}", - author: user, - source_branch: 'feature', - target_branch: 'master') + merge_request.update!( + description: "Closes #{issue1.to_reference} and #{issue2.to_reference}", + author: user, + source_branch: 'feature', + target_branch: 'master' + ) - post :assign_related_issues, - params: { - namespace_id: project.namespace.to_param, - project_id: project, - id: merge_request.iid - } + post :assign_related_issues, params: { + namespace_id: project.namespace.to_param, + project_id: project, + id: merge_request.iid + } end it 'displays an flash error message on fail' do @@ -2143,10 +2178,13 @@ RSpec.describe Projects::MergeRequestsController, feature_category: :code_review describe 'GET pipeline_status.json' do context 'when head_pipeline exists' do let!(:pipeline) do - create(:ci_pipeline, project: merge_request.source_project, - ref: merge_request.source_branch, - sha: merge_request.diff_head_sha, - head_pipeline_of: merge_request) + create( + :ci_pipeline, + project: merge_request.source_project, + ref: merge_request.source_branch, + sha: merge_request.diff_head_sha, + head_pipeline_of: merge_request + ) end let(:status) { pipeline.detailed_status(double('user')) } @@ -2199,11 +2237,10 @@ RSpec.describe Projects::MergeRequestsController, feature_category: :code_review def get_pipeline_status get :pipeline_status, params: { - namespace_id: project.namespace, - project_id: project, - id: merge_request.iid - }, - format: :json + namespace_id: project.namespace, + project_id: project, + id: merge_request.iid + }, format: :json end end diff --git a/spec/controllers/projects/milestones_controller_spec.rb b/spec/controllers/projects/milestones_controller_spec.rb index 28da7eff8fc..e2b73e55145 100644 --- a/spec/controllers/projects/milestones_controller_spec.rb +++ b/spec/controllers/projects/milestones_controller_spec.rb @@ -156,6 +156,27 @@ RSpec.describe Projects::MilestonesController do end end + describe "#update" do + let(:milestone_params) do + { title: "title changed" } + end + + it "handles ActiveRecord::StaleObjectError" do + # Purposely reduce the lock_version to trigger an ActiveRecord::StaleObjectError + milestone_params[:lock_version] = milestone.lock_version - 1 + + put :update, params: { + id: milestone.iid, + milestone: milestone_params, + namespace_id: project.namespace.id, + project_id: project.id + } + + expect(response).not_to redirect_to(project_milestone_path(project, milestone.iid)) + expect(response).to render_template(:edit) + end + end + describe "#destroy" do it "removes milestone" do expect(issue.milestone_id).to eq(milestone.id) diff --git a/spec/controllers/projects/notes_controller_spec.rb b/spec/controllers/projects/notes_controller_spec.rb index 23b0b58158f..5e4e47be2c5 100644 --- a/spec/controllers/projects/notes_controller_spec.rb +++ b/spec/controllers/projects/notes_controller_spec.rb @@ -37,6 +37,8 @@ RSpec.describe Projects::NotesController, type: :controller, feature_category: : project.add_developer(user) end + specify { expect(get(:index, params: request_params)).to have_request_urgency(:medium) } + it 'passes last_fetched_at from headers to NotesFinder and MergeIntoNotesService' do last_fetched_at = Time.zone.at(3.hours.ago.to_i) # remove nanoseconds @@ -244,6 +246,8 @@ RSpec.describe Projects::NotesController, type: :controller, feature_category: : sign_in(user) end + specify { expect(create!).to have_request_urgency(:low) } + describe 'making the creation request' do before do create! @@ -432,6 +436,13 @@ RSpec.describe Projects::NotesController, type: :controller, feature_category: : expect(json_response['commands_changes']).to include('emoji_award', 'time_estimate', 'spend_time') expect(json_response['commands_changes']).not_to include('target_project', 'title') end + + it 'includes command_names' do + create! + + expect(response).to have_gitlab_http_status(:ok) + expect(json_response['command_names']).to include('award', 'estimate', 'spend') + end end context 'with commands that do not return changes' do @@ -450,6 +461,13 @@ RSpec.describe Projects::NotesController, type: :controller, feature_category: : expect(response).to have_gitlab_http_status(:ok) expect(json_response['commands_changes']).not_to include('target_project', 'title') end + + it 'includes command_names' do + create! + + expect(response).to have_gitlab_http_status(:ok) + expect(json_response['command_names']).to include('move', 'title') + end end end end @@ -484,10 +502,7 @@ RSpec.describe Projects::NotesController, type: :controller, feature_category: : let(:commit) { create(:commit, project: project) } let(:existing_comment) do - create(:note_on_commit, - note: 'first', - project: project, - commit_id: merge_request.commit_shas.first) + create(:note_on_commit, note: 'first', project: project, commit_id: merge_request.commit_shas.first) end let(:discussion) { existing_comment.discussion } @@ -735,19 +750,21 @@ RSpec.describe Projects::NotesController, type: :controller, feature_category: : end describe 'PUT update' do - context "should update the note with a valid issue" do - let(:request_params) do - { - namespace_id: project.namespace, - project_id: project, - id: note, - format: :json, - note: { - note: "New comment" - } + let(:request_params) do + { + namespace_id: project.namespace, + project_id: project, + id: note, + format: :json, + note: { + note: "New comment" } - end + } + end + + specify { expect(put(:update, params: request_params)).to have_request_urgency(:low) } + context "should update the note with a valid issue" do before do sign_in(note.author) project.add_developer(note.author) @@ -793,6 +810,8 @@ RSpec.describe Projects::NotesController, type: :controller, feature_category: : } end + specify { expect(delete(:destroy, params: request_params)).to have_request_urgency(:low) } + context 'user is the author of a note' do before do sign_in(note.author) @@ -834,6 +853,8 @@ RSpec.describe Projects::NotesController, type: :controller, feature_category: : let(:emoji_name) { 'thumbsup' } + it { is_expected.to have_request_urgency(:low) } + it "toggles the award emoji" do expect do subject @@ -869,6 +890,8 @@ RSpec.describe Projects::NotesController, type: :controller, feature_category: : sign_in user end + specify { expect(post(:resolve, params: request_params)).to have_request_urgency(:low) } + context "when the user is not authorized to resolve the note" do it "returns status 404" do post :resolve, params: request_params @@ -932,6 +955,8 @@ RSpec.describe Projects::NotesController, type: :controller, feature_category: : note.resolve!(user) end + specify { expect(delete(:unresolve, params: request_params)).to have_request_urgency(:low) } + context "when the user is not authorized to resolve the note" do it "returns status 404" do delete :unresolve, params: request_params @@ -1001,6 +1026,8 @@ RSpec.describe Projects::NotesController, type: :controller, feature_category: : expect(json_response.count).to eq(1) expect(json_response.first).to include({ "line_text" => "Test" }) end + + specify { expect(get(:outdated_line_change, params: request_params)).to have_request_urgency(:low) } end # Convert a time to an integer number of microseconds diff --git a/spec/controllers/projects/pages_controller_spec.rb b/spec/controllers/projects/pages_controller_spec.rb index 136f98ac907..ded5dd57e3e 100644 --- a/spec/controllers/projects/pages_controller_spec.rb +++ b/spec/controllers/projects/pages_controller_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' -RSpec.describe Projects::PagesController do +RSpec.describe Projects::PagesController, feature_category: :pages do let(:user) { create(:user) } let(:project) { create(:project, :public) } @@ -14,7 +14,12 @@ RSpec.describe Projects::PagesController do end before do - allow(Gitlab.config.pages).to receive(:enabled).and_return(true) + stub_config(pages: { + enabled: true, + external_https: true, + access_control: false + }) + sign_in(user) project.add_maintainer(user) end @@ -123,49 +128,99 @@ RSpec.describe Projects::PagesController do end describe 'PATCH update' do - let(:request_params) do - { - namespace_id: project.namespace, - project_id: project, - project: { pages_https_only: 'false' } - } - end + context 'when updating pages_https_only' do + let(:request_params) do + { + namespace_id: project.namespace, + project_id: project, + project: { pages_https_only: 'true' } + } + end - let(:update_service) { double(execute: { status: :success }) } + it 'updates project field and redirects back to the pages settings' do + project.update!(pages_https_only: false) - before do - allow(Projects::UpdateService).to receive(:new) { update_service } - end + expect { patch :update, params: request_params } + .to change { project.reload.pages_https_only } + .from(false).to(true) - it 'returns 302 status' do - patch :update, params: request_params + expect(response).to have_gitlab_http_status(:found) + expect(response).to redirect_to(project_pages_path(project)) + end - expect(response).to have_gitlab_http_status(:found) - end + context 'when it fails to update' do + it 'adds an error message' do + expect_next_instance_of(Projects::UpdateService) do |service| + expect(service) + .to receive(:execute) + .and_return(status: :error, message: 'some error happened') + end - it 'redirects back to the pages settings' do - patch :update, params: request_params + expect { patch :update, params: request_params } + .not_to change { project.reload.pages_https_only } - expect(response).to redirect_to(project_pages_path(project)) + expect(response).to redirect_to(project_pages_path(project)) + expect(flash[:alert]).to eq('some error happened') + end + end end - it 'calls the update service' do - expect(Projects::UpdateService) - .to receive(:new) - .with(project, user, ActionController::Parameters.new(request_params[:project]).permit!) - .and_return(update_service) + context 'when updating pages_unique_domain' do + let(:request_params) do + { + namespace_id: project.namespace, + project_id: project, + project: { + project_setting_attributes: { + pages_unique_domain_enabled: 'true' + } + } + } + end - patch :update, params: request_params - end + before do + create(:project_setting, project: project, pages_unique_domain_enabled: false) + end - context 'when update_service returns an error message' do - let(:update_service) { double(execute: { status: :error, message: 'some error happened' }) } + context 'with pages_unique_domain feature flag disabled' do + it 'does not update pages unique domain' do + stub_feature_flags(pages_unique_domain: false) - it 'adds an error message' do - patch :update, params: request_params + expect { patch :update, params: request_params } + .not_to change { project.project_setting.reload.pages_unique_domain_enabled } + end + end - expect(response).to redirect_to(project_pages_path(project)) - expect(flash[:alert]).to eq('some error happened') + context 'with pages_unique_domain feature flag enabled' do + before do + stub_feature_flags(pages_unique_domain: true) + end + + it 'updates pages_https_only and pages_unique_domain and redirects back to pages settings' do + expect { patch :update, params: request_params } + .to change { project.project_setting.reload.pages_unique_domain_enabled } + .from(false).to(true) + + expect(project.project_setting.pages_unique_domain).not_to be_nil + expect(response).to have_gitlab_http_status(:found) + expect(response).to redirect_to(project_pages_path(project)) + end + + context 'when it fails to update' do + it 'adds an error message' do + expect_next_instance_of(Projects::UpdateService) do |service| + expect(service) + .to receive(:execute) + .and_return(status: :error, message: 'some error happened') + end + + expect { patch :update, params: request_params } + .not_to change { project.project_setting.reload.pages_unique_domain_enabled } + + expect(response).to redirect_to(project_pages_path(project)) + expect(flash[:alert]).to eq('some error happened') + end + end end end end diff --git a/spec/controllers/projects/performance_monitoring/dashboards_controller_spec.rb b/spec/controllers/projects/performance_monitoring/dashboards_controller_spec.rb index 939366e5b0b..02407e31756 100644 --- a/spec/controllers/projects/performance_monitoring/dashboards_controller_spec.rb +++ b/spec/controllers/projects/performance_monitoring/dashboards_controller_spec.rb @@ -2,11 +2,11 @@ require 'spec_helper' -RSpec.describe Projects::PerformanceMonitoring::DashboardsController do +RSpec.describe Projects::PerformanceMonitoring::DashboardsController, feature_category: :metrics do let_it_be(:user) { create(:user) } let_it_be(:namespace) { create(:namespace) } - let!(:project) { create(:project, :repository, name: 'dashboard-project', namespace: namespace) } + let_it_be(:project) { create(:project, :repository, namespace: namespace) } let(:repository) { project.repository } let(:branch) { double(name: branch_name) } let(:commit_message) { 'test' } @@ -25,6 +25,10 @@ RSpec.describe Projects::PerformanceMonitoring::DashboardsController do } end + before do + stub_feature_flags(remove_monitor_metrics: false) + end + describe 'POST #create' do context 'authenticated user' do before do @@ -64,7 +68,7 @@ RSpec.describe Projects::PerformanceMonitoring::DashboardsController do post :create, params: params expect(response).to have_gitlab_http_status :created - expect(controller).to set_flash[:notice].to eq("Your dashboard has been copied. You can edit it here.") + expect(controller).to set_flash[:notice].to eq("Your dashboard has been copied. You can edit it here.") expect(json_response).to eq('status' => 'success', 'dashboard' => { 'path' => ".gitlab/dashboards/#{file_name}" }) end @@ -102,6 +106,18 @@ RSpec.describe Projects::PerformanceMonitoring::DashboardsController do expect(json_response).to eq('error' => "Request parameter branch is missing.") end end + + context 'when metrics dashboard feature is unavailable' do + before do + stub_feature_flags(remove_monitor_metrics: true) + end + + it 'returns 404 not found' do + post :create, params: params + + expect(response).to have_gitlab_http_status :not_found + end + end end end end @@ -120,7 +136,7 @@ RSpec.describe Projects::PerformanceMonitoring::DashboardsController do end context 'project without repository feature' do - let!(:project) { create(:project, name: 'dashboard-project', namespace: namespace) } + let_it_be(:project) { create(:project, namespace: namespace) } it 'responds with :not_found status code' do post :create, params: params @@ -203,7 +219,7 @@ RSpec.describe Projects::PerformanceMonitoring::DashboardsController do put :update, params: params expect(response).to have_gitlab_http_status :created - expect(controller).to set_flash[:notice].to eq("Your dashboard has been updated. You can edit it here.") + expect(controller).to set_flash[:notice].to eq("Your dashboard has been updated. You can edit it here.") expect(json_response).to eq('status' => 'success', 'dashboard' => { 'default' => false, 'display_name' => "custom_dashboard.yml", 'path' => ".gitlab/dashboards/#{file_name}", 'system_dashboard' => false }) end @@ -217,6 +233,18 @@ RSpec.describe Projects::PerformanceMonitoring::DashboardsController do expect(json_response).to eq('error' => 'something went wrong') end end + + context 'when metrics dashboard feature is unavailable' do + before do + stub_feature_flags(remove_monitor_metrics: true) + end + + it 'returns 404 not found' do + put :update, params: params + + expect(response).to have_gitlab_http_status :not_found + end + end end end @@ -246,7 +274,7 @@ RSpec.describe Projects::PerformanceMonitoring::DashboardsController do end context 'project without repository feature' do - let!(:project) { create(:project, name: 'dashboard-project', namespace: namespace) } + let_it_be(:project) { create(:project, namespace: namespace) } it 'responds with :not_found status code' do put :update, params: params diff --git a/spec/controllers/projects/pipeline_schedules_controller_spec.rb b/spec/controllers/projects/pipeline_schedules_controller_spec.rb index a628c1ab230..6d810fdcd51 100644 --- a/spec/controllers/projects/pipeline_schedules_controller_spec.rb +++ b/spec/controllers/projects/pipeline_schedules_controller_spec.rb @@ -410,9 +410,9 @@ RSpec.describe Projects::PipelineSchedulesController, feature_category: :continu it { expect { go }.to be_denied_for(:visitor) } context 'when user is schedule owner' do - it { expect { go }.to be_denied_for(:owner).of(project).own(pipeline_schedule) } - it { expect { go }.to be_denied_for(:maintainer).of(project).own(pipeline_schedule) } - it { expect { go }.to be_denied_for(:developer).of(project).own(pipeline_schedule) } + it { expect { go }.to be_allowed_for(:owner).of(project).own(pipeline_schedule) } + it { expect { go }.to be_allowed_for(:maintainer).of(project).own(pipeline_schedule) } + it { expect { go }.to be_allowed_for(:developer).of(project).own(pipeline_schedule) } it { expect { go }.to be_denied_for(:reporter).of(project).own(pipeline_schedule) } it { expect { go }.to be_denied_for(:guest).of(project).own(pipeline_schedule) } it { expect { go }.to be_denied_for(:user).own(pipeline_schedule) } diff --git a/spec/controllers/projects/pipelines_controller_spec.rb b/spec/controllers/projects/pipelines_controller_spec.rb index 4e0c098ad81..8c5f8fc6259 100644 --- a/spec/controllers/projects/pipelines_controller_spec.rb +++ b/spec/controllers/projects/pipelines_controller_spec.rb @@ -203,18 +203,16 @@ RSpec.describe Projects::PipelinesController, feature_category: :continuous_inte def get_pipelines_index_html(params = {}) get :index, params: { - namespace_id: project.namespace, - project_id: project - }.merge(params), - format: :html + namespace_id: project.namespace, + project_id: project + }.merge(params), format: :html end def get_pipelines_index_json(params = {}) get :index, params: { - namespace_id: project.namespace, - project_id: project - }.merge(params), - format: :json + namespace_id: project.namespace, + project_id: project + }.merge(params), format: :json end def create_all_pipeline_types @@ -236,12 +234,15 @@ RSpec.describe Projects::PipelinesController, feature_category: :continuous_inte def create_pipeline(status, sha, merge_request: nil) user = create(:user) - pipeline = create(:ci_empty_pipeline, status: status, - project: project, - sha: sha.id, - ref: sha.id.first(8), - user: user, - merge_request: merge_request) + pipeline = create( + :ci_empty_pipeline, + status: status, + project: project, + sha: sha.id, + ref: sha.id.first(8), + user: user, + merge_request: merge_request + ) build_stage = create(:ci_stage, name: 'build', pipeline: pipeline) test_stage = create(:ci_stage, name: 'test', pipeline: pipeline) @@ -279,23 +280,6 @@ RSpec.describe Projects::PipelinesController, feature_category: :continuous_inte end end - describe 'GET #index' do - before do - stub_application_setting(auto_devops_enabled: false) - end - - context 'with runners_availability_section experiment' do - it 'tracks the assignment', :experiment do - stub_experiments(runners_availability_section: true) - - expect(experiment(:runners_availability_section)) - .to track(:assignment).with_context(namespace: project.namespace).on_next_instance - - get :index, params: { namespace_id: project.namespace, project_id: project } - end - end - end - describe 'GET #show' do def get_pipeline_html get :show, params: { namespace_id: project.namespace, project_id: project, id: pipeline }, format: :html @@ -378,9 +362,7 @@ RSpec.describe Projects::PipelinesController, feature_category: :continuous_inte let(:project) { create(:project, :repository) } let(:pipeline) do - create(:ci_empty_pipeline, project: project, - user: user, - sha: project.commit.id) + create(:ci_empty_pipeline, project: project, user: user, sha: project.commit.id) end let(:build_stage) { create(:ci_stage, name: 'build', pipeline: pipeline) } @@ -598,9 +580,7 @@ RSpec.describe Projects::PipelinesController, feature_category: :continuous_inte def create_pipeline(project) create(:ci_empty_pipeline, project: project).tap do |pipeline| - create(:ci_build, pipeline: pipeline, - ci_stage: create(:ci_stage, name: 'test', pipeline: pipeline), - name: 'rspec') + create(:ci_build, pipeline: pipeline, ci_stage: create(:ci_stage, name: 'test', pipeline: pipeline), name: 'rspec') end end @@ -771,11 +751,8 @@ RSpec.describe Projects::PipelinesController, feature_category: :continuous_inte before do get :status, params: { - namespace_id: project.namespace, - project_id: project, - id: pipeline.id - }, - format: :json + namespace_id: project.namespace, project_id: project, id: pipeline.id + }, format: :json end it 'return a detailed pipeline status in json' do @@ -825,7 +802,6 @@ RSpec.describe Projects::PipelinesController, feature_category: :continuous_inte subject { get :charts, params: request_params, format: :html } let(:request_params) { { namespace_id: project.namespace, project_id: project, id: pipeline.id, chart: tab[:chart_param] } } - let(:feature_flag_name) { :route_hll_to_snowplow_phase2 } let(:category) { described_class.name } let(:action) { 'perform_analytics_usage_action' } let(:namespace) { project.namespace } @@ -868,9 +844,7 @@ RSpec.describe Projects::PipelinesController, feature_category: :continuous_inte context 'when latest commit contains [ci skip]' do before do - project.repository.create_file(user, 'new-file.txt', 'A new file', - message: '[skip ci] This is a test', - branch_name: 'master') + project.repository.create_file(user, 'new-file.txt', 'A new file', message: '[skip ci] This is a test', branch_name: 'master') end it_behaves_like 'creates a pipeline' @@ -906,11 +880,8 @@ RSpec.describe Projects::PipelinesController, feature_category: :continuous_inte subject do post :create, params: { - namespace_id: project.namespace, - project_id: project, - pipeline: { ref: 'master' } - }, - format: :json + namespace_id: project.namespace, project_id: project, pipeline: { ref: 'master' } + }, format: :json end before do @@ -969,11 +940,8 @@ RSpec.describe Projects::PipelinesController, feature_category: :continuous_inte describe 'POST retry.json' do subject(:post_retry) do post :retry, params: { - namespace_id: project.namespace, - project_id: project, - id: pipeline.id - }, - format: :json + namespace_id: project.namespace, project_id: project, id: pipeline.id + }, format: :json end let!(:pipeline) { create(:ci_pipeline, :failed, project: project) } @@ -1036,11 +1004,8 @@ RSpec.describe Projects::PipelinesController, feature_category: :continuous_inte before do post :cancel, params: { - namespace_id: project.namespace, - project_id: project, - id: pipeline.id - }, - format: :json + namespace_id: project.namespace, project_id: project, id: pipeline.id + }, format: :json end it 'cancels a pipeline without returning any content', :sidekiq_might_not_need_inline do @@ -1183,7 +1148,7 @@ RSpec.describe Projects::PipelinesController, feature_category: :continuous_inte def clear_controller_memoization controller.clear_memoization(:pipeline_test_report) - controller.instance_variable_set(:@pipeline, nil) + controller.remove_instance_variable(:@pipeline) end end @@ -1192,17 +1157,11 @@ RSpec.describe Projects::PipelinesController, feature_category: :continuous_inte let(:branch_secondary) { project.repository.branches[1] } let!(:pipeline_master) do - create(:ci_pipeline, - ref: branch_main.name, - sha: branch_main.target, - project: project) + create(:ci_pipeline, ref: branch_main.name, sha: branch_main.target, project: project) end let!(:pipeline_secondary) do - create(:ci_pipeline, - ref: branch_secondary.name, - sha: branch_secondary.target, - project: project) + create(:ci_pipeline, ref: branch_secondary.name, sha: branch_secondary.target, project: project) end before do @@ -1319,149 +1278,6 @@ RSpec.describe Projects::PipelinesController, feature_category: :continuous_inte end end - describe 'GET config_variables.json', :use_clean_rails_memory_store_caching do - include ReactiveCachingHelpers - - let(:ci_config) { '' } - let(:files) { { '.gitlab-ci.yml' => YAML.dump(ci_config) } } - let(:project) { create(:project, :auto_devops_disabled, :custom_repo, files: files) } - let(:service) { Ci::ListConfigVariablesService.new(project, user) } - - before do - allow(Ci::ListConfigVariablesService) - .to receive(:new) - .and_return(service) - end - - context 'when sending a valid ref' do - let(:ref) { 'master' } - let(:ci_config) do - { - variables: { - KEY1: { value: 'val 1', description: 'description 1' } - }, - test: { - stage: 'test', - script: 'echo' - } - } - end - - before do - synchronous_reactive_cache(service) - end - - it 'returns variable list' do - get_config_variables - - expect(response).to have_gitlab_http_status(:ok) - expect(json_response['KEY1']).to eq({ 'value' => 'val 1', 'description' => 'description 1' }) - end - end - - context 'when sending an invalid ref' do - let(:ref) { 'invalid-ref' } - - before do - synchronous_reactive_cache(service) - end - - it 'returns empty json' do - get_config_variables - - expect(response).to have_gitlab_http_status(:ok) - expect(json_response).to eq({}) - end - end - - context 'when sending an invalid config' do - let(:ref) { 'master' } - let(:ci_config) do - { - variables: { - KEY1: { value: 'val 1', description: 'description 1' } - }, - test: { - stage: 'invalid', - script: 'echo' - } - } - end - - before do - synchronous_reactive_cache(service) - end - - it 'returns empty result' do - get_config_variables - - expect(response).to have_gitlab_http_status(:ok) - expect(json_response).to eq({}) - end - end - - context 'when the cache is empty' do - let(:ref) { 'master' } - let(:ci_config) do - { - variables: { - KEY1: { value: 'val 1', description: 'description 1' } - }, - test: { - stage: 'test', - script: 'echo' - } - } - end - - it 'returns no content' do - get_config_variables - - expect(response).to have_gitlab_http_status(:no_content) - end - end - - context 'when project uses external project ci config' do - let(:other_project) { create(:project, :custom_repo, files: other_project_files) } - let(:other_project_files) { { '.gitlab-ci.yml' => YAML.dump(other_project_ci_config) } } - let(:ref) { 'master' } - - let(:other_project_ci_config) do - { - variables: { - KEY1: { value: 'val 1', description: 'description 1' } - }, - test: { - stage: 'test', - script: 'echo' - } - } - end - - before do - other_project.add_developer(user) - project.update!(ci_config_path: ".gitlab-ci.yml@#{other_project.full_path}:master") - synchronous_reactive_cache(service) - end - - it 'returns other project config variables' do - get_config_variables - - expect(response).to have_gitlab_http_status(:ok) - expect(json_response['KEY1']).to eq({ 'value' => 'val 1', 'description' => 'description 1' }) - end - end - - private - - def get_config_variables - get :config_variables, params: { namespace_id: project.namespace, - project_id: project, - sha: ref }, - format: :json - end - end - describe 'GET downloadable_artifacts.json' do context 'when pipeline is empty' do let(:pipeline) { create(:ci_empty_pipeline) } diff --git a/spec/controllers/projects/project_members_controller_spec.rb b/spec/controllers/projects/project_members_controller_spec.rb index ab33195eb83..dbea3592e24 100644 --- a/spec/controllers/projects/project_members_controller_spec.rb +++ b/spec/controllers/projects/project_members_controller_spec.rb @@ -560,12 +560,4 @@ RSpec.describe Projects::ProjectMembersController do end it_behaves_like 'controller actions' - - context 'when project_members_index_by_project_namespace feature flag is disabled' do - before do - stub_feature_flags(project_members_index_by_project_namespace: false) - end - - it_behaves_like 'controller actions' - end end diff --git a/spec/controllers/projects/prometheus/alerts_controller_spec.rb b/spec/controllers/projects/prometheus/alerts_controller_spec.rb index 09b9f25c0c6..91d3ba7e106 100644 --- a/spec/controllers/projects/prometheus/alerts_controller_spec.rb +++ b/spec/controllers/projects/prometheus/alerts_controller_spec.rb @@ -117,10 +117,7 @@ RSpec.describe Projects::Prometheus::AlertsController do describe 'GET #metrics_dashboard' do let!(:alert) do - create(:prometheus_alert, - project: project, - environment: environment, - prometheus_metric: metric) + create(:prometheus_alert, project: project, environment: environment, prometheus_metric: metric) end it 'returns a json object with the correct keys' do diff --git a/spec/controllers/projects/raw_controller_spec.rb b/spec/controllers/projects/raw_controller_spec.rb index 40252cf65cd..b15a37d8d90 100644 --- a/spec/controllers/projects/raw_controller_spec.rb +++ b/spec/controllers/projects/raw_controller_spec.rb @@ -12,13 +12,9 @@ RSpec.describe Projects::RawController, feature_category: :source_code_managemen describe 'GET #show' do def get_show - get(:show, - params: { - namespace_id: project.namespace, - project_id: project, - id: file_path, - inline: inline - }.merge(params)) + get :show, params: { + namespace_id: project.namespace, project_id: project, id: file_path, inline: inline + }.merge(params) end subject { get_show } diff --git a/spec/controllers/projects/refs_controller_spec.rb b/spec/controllers/projects/refs_controller_spec.rb index 7a511ab676e..0b1d0b75de7 100644 --- a/spec/controllers/projects/refs_controller_spec.rb +++ b/spec/controllers/projects/refs_controller_spec.rb @@ -26,7 +26,7 @@ RSpec.describe Projects::RefsController, feature_category: :source_code_manageme 'tree' | nil | lazy { project_tree_path(project, id) } 'tree' | 'heads' | lazy { project_tree_path(project, id) } 'blob' | nil | lazy { project_blob_path(project, id) } - 'blob' | 'heads' | lazy { project_blob_path(project, id, ref_type: 'heads') } + 'blob' | 'heads' | lazy { project_blob_path(project, id) } 'graph' | nil | lazy { project_network_path(project, id) } 'graph' | 'heads' | lazy { project_network_path(project, id, ref_type: 'heads') } 'graphs' | nil | lazy { project_graph_path(project, id) } @@ -54,14 +54,9 @@ RSpec.describe Projects::RefsController, feature_category: :source_code_manageme let(:path) { 'foo/bar/baz.html' } def default_get(format = :html) - get :logs_tree, - params: { - namespace_id: project.namespace.to_param, - project_id: project, - id: 'master', - path: path - }, - format: format + get :logs_tree, params: { + namespace_id: project.namespace.to_param, project_id: project, id: 'master', path: path + }, format: format end def xhr_get(format = :html, params = {}) diff --git a/spec/controllers/projects/registry/repositories_controller_spec.rb b/spec/controllers/projects/registry/repositories_controller_spec.rb index 59bc1ba04e7..834fdddd583 100644 --- a/spec/controllers/projects/registry/repositories_controller_spec.rb +++ b/spec/controllers/projects/registry/repositories_controller_spec.rb @@ -59,8 +59,7 @@ RSpec.describe Projects::Registry::RepositoriesController do context 'when root container repository is not created' do context 'when there are tags for this repository' do before do - stub_container_registry_tags(repository: :any, - tags: %w[rc1 latest]) + stub_container_registry_tags(repository: :any, tags: %w[rc1 latest]) end it 'creates a root container repository' do @@ -139,19 +138,12 @@ RSpec.describe Projects::Registry::RepositoriesController do end def go_to_index(format: :html, params: {}) - get :index, params: params.merge({ - namespace_id: project.namespace, - project_id: project - }), - format: format + get :index, params: params.merge({ namespace_id: project.namespace, project_id: project }), format: format end def delete_repository(repository) delete :destroy, params: { - namespace_id: project.namespace, - project_id: project, - id: repository - }, - format: :json + namespace_id: project.namespace, project_id: project, id: repository + }, format: :json end end diff --git a/spec/controllers/projects/registry/tags_controller_spec.rb b/spec/controllers/projects/registry/tags_controller_spec.rb index 7b786f4a8af..afa7bd6a60d 100644 --- a/spec/controllers/projects/registry/tags_controller_spec.rb +++ b/spec/controllers/projects/registry/tags_controller_spec.rb @@ -76,11 +76,8 @@ RSpec.describe Projects::Registry::TagsController do def get_tags get :index, params: { - namespace_id: project.namespace, - project_id: project, - repository_id: repository - }, - format: :json + namespace_id: project.namespace, project_id: project, repository_id: repository + }, format: :json end end @@ -121,12 +118,11 @@ RSpec.describe Projects::Registry::TagsController do def destroy_tag(name) post :destroy, params: { - namespace_id: project.namespace, - project_id: project, - repository_id: repository, - id: name - }, - format: :json + namespace_id: project.namespace, + project_id: project, + repository_id: repository, + id: name + }, format: :json end end @@ -162,12 +158,11 @@ RSpec.describe Projects::Registry::TagsController do def bulk_destroy_tags(names) post :bulk_destroy, params: { - namespace_id: project.namespace, - project_id: project, - repository_id: repository, - ids: names - }, - format: :json + namespace_id: project.namespace, + project_id: project, + repository_id: repository, + ids: names + }, format: :json end end diff --git a/spec/controllers/projects/releases_controller_spec.rb b/spec/controllers/projects/releases_controller_spec.rb index 2afd080344d..17bf9308834 100644 --- a/spec/controllers/projects/releases_controller_spec.rb +++ b/spec/controllers/projects/releases_controller_spec.rb @@ -158,9 +158,9 @@ RSpec.describe Projects::ReleasesController do it_behaves_like 'successful request' - it 'is accesible at a URL encoded path' do + it 'is accessible at a URL encoded path' do expect(edit_project_release_path(project, release)) - .to eq("/#{project.namespace.path}/#{project.name}/-/releases/awesome%2Fv1.0/edit") + .to eq("/#{project.full_path}/-/releases/awesome%2Fv1.0/edit") end end @@ -199,7 +199,7 @@ RSpec.describe Projects::ReleasesController do it 'is accesible at a URL encoded path' do expect(project_release_path(project, release)) - .to eq("/#{project.namespace.path}/#{project.name}/-/releases/awesome%2Fv1.0") + .to eq("/#{project.full_path}/-/releases/awesome%2Fv1.0") end end diff --git a/spec/controllers/projects/repositories_controller_spec.rb b/spec/controllers/projects/repositories_controller_spec.rb index 8186176a46b..0efed45336f 100644 --- a/spec/controllers/projects/repositories_controller_spec.rb +++ b/spec/controllers/projects/repositories_controller_spec.rb @@ -106,19 +106,11 @@ RSpec.describe Projects::RepositoriesController, feature_category: :source_code_ end end - context "when the request format is HTML" do - it "renders 404" do - get :archive, params: { namespace_id: project.namespace, project_id: project, id: 'master' }, format: "html" - - expect(response).to have_gitlab_http_status(:not_found) - end - end - describe 'rate limiting' do it 'rate limits user when thresholds hit' do allow(Gitlab::ApplicationRateLimiter).to receive(:throttled?).and_return(true) - get :archive, params: { namespace_id: project.namespace, project_id: project, id: 'master' }, format: "html" + get :archive, params: { namespace_id: project.namespace, project_id: project, id: 'master' }, format: "zip" expect(response).to have_gitlab_http_status(:too_many_requests) end diff --git a/spec/controllers/projects/runner_projects_controller_spec.rb b/spec/controllers/projects/runner_projects_controller_spec.rb new file mode 100644 index 00000000000..beedaad0fa9 --- /dev/null +++ b/spec/controllers/projects/runner_projects_controller_spec.rb @@ -0,0 +1,62 @@ +# frozen_string_literal: true + +require 'spec_helper' + +RSpec.describe Projects::RunnerProjectsController, feature_category: :runner_fleet do + let_it_be(:user) { create(:user) } + let_it_be(:group) { create(:group) } + let_it_be(:project) { create(:project, group: group) } + let_it_be(:source_project) { create(:project) } + + before do + sign_in(user) + project.add_maintainer(user) + end + + describe '#create' do + subject(:send_create) do + post :create, params: { + namespace_id: group.path, + project_id: project.path, + runner_project: { runner_id: project_runner.id } + } + end + + context 'when assigning runner to another project' do + let(:project_runner) { create(:ci_runner, :project, projects: [source_project]) } + + it 'redirects to the project runners page' do + source_project.add_maintainer(user) + + send_create + + expect(flash[:success]).to be_present + expect(response).to have_gitlab_http_status(:redirect) + expect(response).to redirect_to project_runners_path(project) + end + end + end + + describe '#destroy' do + subject(:send_destroy) do + delete :destroy, params: { + namespace_id: group.path, + project_id: project.path, + id: runner_project_id + } + end + + context 'when unassigning runner from project' do + let(:project_runner) { create(:ci_runner, :project, projects: [project]) } + let(:runner_project_id) { project_runner.runner_projects.last.id } + + it 'redirects to the project runners page' do + send_destroy + + expect(flash[:success]).to be_present + expect(response).to have_gitlab_http_status(:redirect) + expect(response).to redirect_to project_runners_path(project) + end + end + end +end diff --git a/spec/controllers/projects/runners_controller_spec.rb b/spec/controllers/projects/runners_controller_spec.rb index 5733b8114d4..e0e4d0f7bc5 100644 --- a/spec/controllers/projects/runners_controller_spec.rb +++ b/spec/controllers/projects/runners_controller_spec.rb @@ -3,9 +3,9 @@ require 'spec_helper' RSpec.describe Projects::RunnersController, feature_category: :runner_fleet do - let(:user) { create(:user) } - let(:project) { create(:project) } - let(:runner) { create(:ci_runner, :project, projects: [project]) } + let_it_be(:user) { create(:user) } + let_it_be(:project) { create(:project) } + let_it_be(:runner) { create(:ci_runner, :project, projects: [project]) } let(:params) do { @@ -20,6 +20,137 @@ RSpec.describe Projects::RunnersController, feature_category: :runner_fleet do project.add_maintainer(user) end + describe '#new' do + let(:params) do + { + namespace_id: project.namespace, + project_id: project + } + end + + context 'when create_runner_workflow_for_namespace is enabled' do + before do + stub_feature_flags(create_runner_workflow_for_namespace: [project.namespace]) + end + + context 'when user is maintainer' do + before do + project.add_maintainer(user) + end + + it 'renders new with 200 status code' do + get :new, params: params + + expect(response).to have_gitlab_http_status(:ok) + expect(response).to render_template(:new) + end + end + + context 'when user is not maintainer' do + before do + project.add_developer(user) + end + + it 'renders a 404' do + get :new, params: params + + expect(response).to have_gitlab_http_status(:not_found) + end + end + end + + context 'when create_runner_workflow_for_namespace is disabled' do + before do + stub_feature_flags(create_runner_workflow_for_namespace: false) + end + + context 'when user is maintainer' do + before do + project.add_maintainer(user) + end + + it 'renders a 404' do + get :new, params: params + + expect(response).to have_gitlab_http_status(:not_found) + end + end + end + end + + describe '#register' do + subject(:register) { get :register, params: { namespace_id: project.namespace, project_id: project, id: new_runner } } + + context 'when create_runner_workflow_for_namespace is enabled' do + before do + stub_feature_flags(create_runner_workflow_for_namespace: [project.namespace]) + end + + context 'when user is maintainer' do + before do + project.add_maintainer(user) + end + + context 'when runner can be registered after creation' do + let_it_be(:new_runner) { create(:ci_runner, :project, projects: [project], registration_type: :authenticated_user) } + + it 'renders a :register template' do + register + + expect(response).to have_gitlab_http_status(:ok) + expect(response).to render_template(:register) + end + end + + context 'when runner cannot be registered after creation' do + let_it_be(:new_runner) { runner } + + it 'returns :not_found' do + register + + expect(response).to have_gitlab_http_status(:not_found) + end + end + end + + context 'when user is not maintainer' do + before do + project.add_developer(user) + end + + context 'when runner can be registered after creation' do + let_it_be(:new_runner) { create(:ci_runner, :project, projects: [project], registration_type: :authenticated_user) } + + it 'returns :not_found' do + register + + expect(response).to have_gitlab_http_status(:not_found) + end + end + end + end + + context 'when create_runner_workflow_for_namespace is disabled' do + let_it_be(:new_runner) { create(:ci_runner, :project, projects: [project], registration_type: :authenticated_user) } + + before do + stub_feature_flags(create_runner_workflow_for_namespace: false) + end + + context 'when user is maintainer' do + before do + project.add_maintainer(user) + end + + it 'returns :not_found' do + register + + expect(response).to have_gitlab_http_status(:not_found) + end + end + end + end + describe '#update' do it 'updates the runner and ticks the queue' do new_desc = runner.description.swapcase diff --git a/spec/controllers/projects/service_desk_controller_spec.rb b/spec/controllers/projects/service_desk_controller_spec.rb index e078bf9461e..6b914ac8f19 100644 --- a/spec/controllers/projects/service_desk_controller_spec.rb +++ b/spec/controllers/projects/service_desk_controller_spec.rb @@ -12,8 +12,8 @@ RSpec.describe Projects::ServiceDeskController do let_it_be(:user) { create(:user) } before do - allow(Gitlab::IncomingEmail).to receive(:enabled?) { true } - allow(Gitlab::IncomingEmail).to receive(:supports_wildcard?) { true } + allow(Gitlab::Email::IncomingEmail).to receive(:enabled?) { true } + allow(Gitlab::Email::IncomingEmail).to receive(:supports_wildcard?) { true } project.add_maintainer(user) sign_in(user) diff --git a/spec/controllers/projects/settings/ci_cd_controller_spec.rb b/spec/controllers/projects/settings/ci_cd_controller_spec.rb index ba917fa3a31..1c332eadc42 100644 --- a/spec/controllers/projects/settings/ci_cd_controller_spec.rb +++ b/spec/controllers/projects/settings/ci_cd_controller_spec.rb @@ -173,12 +173,11 @@ RSpec.describe Projects::Settings::CiCdController, feature_category: :continuous let(:params) { { ci_config_path: '' } } subject do - patch :update, - params: { - namespace_id: project.namespace.to_param, - project_id: project, - project: params - } + patch :update, params: { + namespace_id: project.namespace.to_param, + project_id: project, + project: params + } end it 'redirects to the settings page' do @@ -241,9 +240,7 @@ RSpec.describe Projects::Settings::CiCdController, feature_category: :continuous end it 'creates a pipeline', :sidekiq_inline do - project.repository.create_file(user, 'Gemfile', 'Gemfile contents', - message: 'Add Gemfile', - branch_name: 'master') + project.repository.create_file(user, 'Gemfile', 'Gemfile contents', message: 'Add Gemfile', branch_name: 'master') expect { subject }.to change { Ci::Pipeline.count }.by(1) end diff --git a/spec/controllers/projects/settings/merge_requests_controller_spec.rb b/spec/controllers/projects/settings/merge_requests_controller_spec.rb index 106ec62bea0..398fc97a00d 100644 --- a/spec/controllers/projects/settings/merge_requests_controller_spec.rb +++ b/spec/controllers/projects/settings/merge_requests_controller_spec.rb @@ -36,12 +36,11 @@ RSpec.describe Projects::Settings::MergeRequestsController do merge_method: :ff } - put :update, - params: { - namespace_id: project.namespace, - project_id: project.id, - project: params - } + put :update, params: { + namespace_id: project.namespace, + project_id: project.id, + project: params + } expect(response).to redirect_to project_settings_merge_requests_path(project) params.each do |param, value| diff --git a/spec/controllers/projects/settings/operations_controller_spec.rb b/spec/controllers/projects/settings/operations_controller_spec.rb index 76d8191e342..04dbd9ab671 100644 --- a/spec/controllers/projects/settings/operations_controller_spec.rb +++ b/spec/controllers/projects/settings/operations_controller_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' -RSpec.describe Projects::Settings::OperationsController do +RSpec.describe Projects::Settings::OperationsController, feature_category: :incident_management do let_it_be(:user) { create(:user) } let_it_be(:project, reload: true) { create(:project) } @@ -11,6 +11,8 @@ RSpec.describe Projects::Settings::OperationsController do end before do + stub_feature_flags(remove_monitor_metrics: false) + sign_in(user) end @@ -65,6 +67,20 @@ RSpec.describe Projects::Settings::OperationsController do end end + shared_examples 'PATCHable without metrics dashboard' do + context 'when metrics dashboard feature is unavailable' do + before do + stub_feature_flags(remove_monitor_metrics: true) + end + + include_examples 'PATCHable' do + let(:permitted_params) do + ActionController::Parameters.new({}).permit! + end + end + end + end + describe 'GET #show' do it 'renders show template' do get :show, params: project_params(project) @@ -124,7 +140,7 @@ RSpec.describe Projects::Settings::OperationsController do end end - context 'incident management' do + context 'incident management', feature_category: :incident_management do describe 'GET #show' do context 'with existing setting' do let!(:incident_management_setting) do @@ -278,7 +294,7 @@ RSpec.describe Projects::Settings::OperationsController do end end - context 'error tracking' do + context 'error tracking', feature_category: :error_tracking do describe 'GET #show' do context 'with existing setting' do let!(:error_tracking_setting) do @@ -323,7 +339,7 @@ RSpec.describe Projects::Settings::OperationsController do end end - context 'metrics dashboard setting' do + context 'metrics dashboard setting', feature_category: :metrics do describe 'PATCH #update' do let(:params) do { @@ -333,11 +349,12 @@ RSpec.describe Projects::Settings::OperationsController do } end - it_behaves_like 'PATCHable' + include_examples 'PATCHable' + include_examples 'PATCHable without metrics dashboard' end end - context 'grafana integration' do + context 'grafana integration', feature_category: :metrics do describe 'PATCH #update' do let(:params) do { @@ -349,7 +366,8 @@ RSpec.describe Projects::Settings::OperationsController do } end - it_behaves_like 'PATCHable' + include_examples 'PATCHable' + include_examples 'PATCHable without metrics dashboard' end end diff --git a/spec/controllers/projects/snippets/blobs_controller_spec.rb b/spec/controllers/projects/snippets/blobs_controller_spec.rb index ca656705e07..4d12452e3d5 100644 --- a/spec/controllers/projects/snippets/blobs_controller_spec.rb +++ b/spec/controllers/projects/snippets/blobs_controller_spec.rb @@ -26,15 +26,14 @@ RSpec.describe Projects::Snippets::BlobsController do let(:inline) { nil } subject do - get(:raw, - params: { - namespace_id: project.namespace, - project_id: project, - snippet_id: snippet, - path: filepath, - ref: ref, - inline: inline - }) + get :raw, params: { + namespace_id: project.namespace, + project_id: project, + snippet_id: snippet, + path: filepath, + ref: ref, + inline: inline + } end context 'with a snippet without a repository' do diff --git a/spec/controllers/projects/snippets_controller_spec.rb b/spec/controllers/projects/snippets_controller_spec.rb index a388fc4620f..119e52480db 100644 --- a/spec/controllers/projects/snippets_controller_spec.rb +++ b/spec/controllers/projects/snippets_controller_spec.rb @@ -102,12 +102,11 @@ RSpec.describe Projects::SnippetsController do project.add_maintainer(admin) sign_in(admin) - post :mark_as_spam, - params: { - namespace_id: project.namespace, - project_id: project, - id: snippet.id - } + post :mark_as_spam, params: { + namespace_id: project.namespace, + project_id: project, + id: snippet.id + } end it 'updates the snippet', :enable_admin_mode do diff --git a/spec/controllers/projects/tree_controller_spec.rb b/spec/controllers/projects/tree_controller_spec.rb index 37149e1d3ca..61998d516e8 100644 --- a/spec/controllers/projects/tree_controller_spec.rb +++ b/spec/controllers/projects/tree_controller_spec.rb @@ -136,12 +136,9 @@ RSpec.describe Projects::TreeController, feature_category: :source_code_manageme allow(::Gitlab::GitalyClient).to receive(:call).and_call_original expect(::Gitlab::GitalyClient).not_to receive(:call).with(anything, :commit_service, :find_commit, anything, anything) - get(:show, - params: { - namespace_id: project.namespace.to_param, - project_id: project, - id: id - }) + get :show, params: { + namespace_id: project.namespace.to_param, project_id: project, id: id + } expect(response).to have_gitlab_http_status(:not_found) end @@ -151,12 +148,9 @@ RSpec.describe Projects::TreeController, feature_category: :source_code_manageme render_views before do - get(:show, - params: { - namespace_id: project.namespace.to_param, - project_id: project, - id: id - }) + get :show, params: { + namespace_id: project.namespace.to_param, project_id: project, id: id + } end context 'redirect to blob' do @@ -164,8 +158,7 @@ RSpec.describe Projects::TreeController, feature_category: :source_code_manageme it 'redirects' do redirect_url = "/#{project.full_path}/-/blob/master/README.md" - expect(subject) - .to redirect_to(redirect_url) + expect(subject).to redirect_to(redirect_url) end end end @@ -174,15 +167,14 @@ RSpec.describe Projects::TreeController, feature_category: :source_code_manageme render_views before do - post(:create_dir, - params: { - namespace_id: project.namespace.to_param, - project_id: project, - id: 'master', - dir_name: path, - branch_name: branch_name, - commit_message: 'Test commit message' - }) + post :create_dir, params: { + namespace_id: project.namespace.to_param, + project_id: project, + id: 'master', + dir_name: path, + branch_name: branch_name, + commit_message: 'Test commit message' + } end context 'successful creation' do diff --git a/spec/controllers/projects/wikis_controller_spec.rb b/spec/controllers/projects/wikis_controller_spec.rb index 7243588681d..353cd62686f 100644 --- a/spec/controllers/projects/wikis_controller_spec.rb +++ b/spec/controllers/projects/wikis_controller_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' -RSpec.describe Projects::WikisController do +RSpec.describe Projects::WikisController, feature_category: :wiki do it_behaves_like 'wiki controller actions' do let(:container) { create(:project, :public, namespace: user.namespace) } let(:routing_params) { { namespace_id: container.namespace, project_id: container } } diff --git a/spec/controllers/projects/work_items_controller_spec.rb b/spec/controllers/projects/work_items_controller_spec.rb new file mode 100644 index 00000000000..e0f61a4977b --- /dev/null +++ b/spec/controllers/projects/work_items_controller_spec.rb @@ -0,0 +1,156 @@ +# frozen_string_literal: true + +require 'spec_helper' + +RSpec.describe Projects::WorkItemsController, feature_category: :team_planning do + let_it_be(:reporter) { create(:user) } + let_it_be(:guest) { create(:user) } + let_it_be(:project) { create(:project) } + let_it_be(:work_item) { create(:work_item, project: project) } + + let(:file) { 'file' } + + before do + project.add_reporter(reporter) + project.add_guest(guest) + end + + shared_examples 'response with 404 status' do + it 'renders a not found message' do + expect(WorkItems::ImportWorkItemsCsvWorker).not_to receive(:perform_async) + + subject + + expect(response).to have_gitlab_http_status(:not_found) + end + end + + shared_examples 'redirects to new session path' do + it 'redirects to sign in' do + subject + + expect(response).to have_gitlab_http_status(:found) + expect(response).to redirect_to(new_user_session_path) + end + end + + describe 'GET index' do + specify do + expect( + get(:index, params: { namespace_id: project.namespace, project_id: project, work_items_path: work_item.id }) + ).to have_request_urgency(:low) + end + end + + describe 'POST authorize' do + subject do + post(:authorize, params: { namespace_id: project.namespace, project_id: project, file: file }) + end + + specify do + expect(subject).to have_request_urgency(:high) + end + + context 'when user is anonymous' do + it_behaves_like 'redirects to new session path' + end + end + + describe 'POST import_csv' do + subject { post :import_csv, params: { namespace_id: project.namespace, project_id: project, file: file } } + + let(:upload_service) { double } + let(:uploader) { double } + let(:upload) { double } + let(:upload_id) { 99 } + + specify do + expect(subject).to have_request_urgency(:low) + end + + context 'with authorized user' do + before do + sign_in(reporter) + allow(controller).to receive(:file_is_valid?).and_return(true) + end + + context 'when feature is available' do + context 'when the upload is processed successfully' do + before do + mock_upload + end + + it 'renders the correct message' do + expect(WorkItems::ImportWorkItemsCsvWorker).to receive(:perform_async) + .with(reporter.id, project.id, upload_id) + + subject + + expect(response).to have_gitlab_http_status(:ok) + expect(json_response['message']).to eq( + "Your work items are being imported. Once finished, you'll receive a confirmation email." + ) + end + end + + context 'when file is not valid' do + before do + allow(controller).to receive(:file_is_valid?).and_return(false) + end + + it 'renders the error message' do + expect(WorkItems::ImportWorkItemsCsvWorker).not_to receive(:perform_async) + + subject + + expect(response).to have_gitlab_http_status(:bad_request) + expect(json_response['errors']) + .to eq('The uploaded file was invalid. Supported file extensions are .csv.') + end + end + + context 'when service response includes errors' do + before do + mock_upload(false) + end + + it 'renders the error message' do + subject + + expect(response).to have_gitlab_http_status(:bad_request) + expect(json_response['errors']).to eq('File upload error.') + end + end + end + + context 'when feature is not available' do + before do + stub_feature_flags(import_export_work_items_csv: false) + end + + it_behaves_like 'response with 404 status' + end + end + + context 'with unauthorised user' do + before do + mock_upload + sign_in(guest) + allow(controller).to receive(:file_is_valid?).and_return(true) + end + + it_behaves_like 'response with 404 status' + end + + context 'with anonymous user' do + it 'redirects to sign in page' do + expect(WorkItems::ImportWorkItemsCsvWorker).not_to receive(:perform_async) + + subject + + expect(response).to have_gitlab_http_status(:found) + expect(response).to redirect_to(new_user_session_path) + end + end + end +end diff --git a/spec/controllers/projects_controller_spec.rb b/spec/controllers/projects_controller_spec.rb index c5ec6651ab3..b652aba1fff 100644 --- a/spec/controllers/projects_controller_spec.rb +++ b/spec/controllers/projects_controller_spec.rb @@ -571,11 +571,7 @@ RSpec.describe ProjectsController, feature_category: :projects do it 'allows an admin user to access the page', :enable_admin_mode do sign_in(create(:user, :admin)) - get :edit, - params: { - namespace_id: project.namespace.path, - id: project.path - } + get :edit, params: { namespace_id: project.namespace.path, id: project.path } expect(response).to have_gitlab_http_status(:ok) end @@ -584,11 +580,7 @@ RSpec.describe ProjectsController, feature_category: :projects do sign_in(user) project.add_maintainer(user) - get :edit, - params: { - namespace_id: project.namespace.path, - id: project.path - } + get :edit, params: { namespace_id: project.namespace.path, id: project.path } expect(assigns(:badge_api_endpoint)).not_to be_nil end @@ -606,10 +598,7 @@ RSpec.describe ProjectsController, feature_category: :projects do before do group.add_owner(user) - post :archive, params: { - namespace_id: project.namespace.path, - id: project.path - } + post :archive, params: { namespace_id: project.namespace.path, id: project.path } end it 'archives the project' do @@ -853,12 +842,7 @@ RSpec.describe ProjectsController, feature_category: :projects do merge_method: :ff } - put :update, - params: { - namespace_id: project.namespace, - id: project.id, - project: params - } + put :update, params: { namespace_id: project.namespace, id: project.id, project: params } expect(response).to have_gitlab_http_status(:found) params.each do |param, value| @@ -874,22 +858,12 @@ RSpec.describe ProjectsController, feature_category: :projects do } expect do - put :update, - params: { - namespace_id: project.namespace, - id: project.id, - project: params - } + put :update, params: { namespace_id: project.namespace, id: project.id, project: params } end.not_to change { project.namespace.reload } end def update_project(**parameters) - put :update, - params: { - namespace_id: project.namespace.path, - id: project.path, - project: parameters - } + put :update, params: { namespace_id: project.namespace.path, id: project.path, project: parameters } end end @@ -913,12 +887,9 @@ RSpec.describe ProjectsController, feature_category: :projects do it_behaves_like 'unauthorized when external service denies access' do subject do - put :update, - params: { - namespace_id: project.namespace, - id: project, - project: { description: 'Hello world' } - } + put :update, params: { + namespace_id: project.namespace, id: project, project: { description: 'Hello world' } + } project.reload end @@ -1038,13 +1009,9 @@ RSpec.describe ProjectsController, feature_category: :projects do old_namespace = project.namespace - put :transfer, - params: { - namespace_id: old_namespace.path, - new_namespace_id: new_namespace_id, - id: project.path - }, - format: :js + put :transfer, params: { + namespace_id: old_namespace.path, new_namespace_id: new_namespace_id, id: project.path + }, format: :js project.reload @@ -1057,13 +1024,9 @@ RSpec.describe ProjectsController, feature_category: :projects do it 'updates namespace' do sign_in(admin) - put :transfer, - params: { - namespace_id: project.namespace.path, - new_namespace_id: new_namespace.id, - id: project.path - }, - format: :js + put :transfer, params: { + namespace_id: project.namespace.path, new_namespace_id: new_namespace.id, id: project.path + }, format: :js project.reload @@ -1183,32 +1146,19 @@ RSpec.describe ProjectsController, feature_category: :projects do it "toggles star if user is signed in" do sign_in(user) expect(user.starred?(public_project)).to be_falsey - post(:toggle_star, - params: { - namespace_id: public_project.namespace, - id: public_project - }) + + post :toggle_star, params: { namespace_id: public_project.namespace, id: public_project } expect(user.starred?(public_project)).to be_truthy - post(:toggle_star, - params: { - namespace_id: public_project.namespace, - id: public_project - }) + + post :toggle_star, params: { namespace_id: public_project.namespace, id: public_project } expect(user.starred?(public_project)).to be_falsey end it "does nothing if user is not signed in" do - post(:toggle_star, - params: { - namespace_id: project.namespace, - id: public_project - }) + post :toggle_star, params: { namespace_id: project.namespace, id: public_project } expect(user.starred?(public_project)).to be_falsey - post(:toggle_star, - params: { - namespace_id: project.namespace, - id: public_project - }) + + post :toggle_star, params: { namespace_id: project.namespace, id: public_project } expect(user.starred?(public_project)).to be_falsey end end @@ -1223,12 +1173,9 @@ RSpec.describe ProjectsController, feature_category: :projects do let(:forked_project) { fork_project(create(:project, :public), user) } it 'removes fork from project' do - delete(:remove_fork, - params: { - namespace_id: forked_project.namespace.to_param, - id: forked_project.to_param - }, - format: :js) + delete :remove_fork, params: { + namespace_id: forked_project.namespace.to_param, id: forked_project.to_param + }, format: :js expect(forked_project.reload.forked?).to be_falsey expect(flash[:notice]).to eq(s_('The fork relationship has been removed.')) @@ -1240,12 +1187,9 @@ RSpec.describe ProjectsController, feature_category: :projects do let(:unforked_project) { create(:project, namespace: user.namespace) } it 'does nothing if project was not forked' do - delete(:remove_fork, - params: { - namespace_id: unforked_project.namespace, - id: unforked_project - }, - format: :js) + delete :remove_fork, params: { + namespace_id: unforked_project.namespace, id: unforked_project + }, format: :js expect(flash[:notice]).to be_nil expect(response).to redirect_to(edit_project_path(unforked_project)) @@ -1254,12 +1198,10 @@ RSpec.describe ProjectsController, feature_category: :projects do end it "does nothing if user is not signed in" do - delete(:remove_fork, - params: { - namespace_id: project.namespace, - id: project - }, - format: :js) + delete :remove_fork, params: { + namespace_id: project.namespace, id: project + }, format: :js + expect(response).to have_gitlab_http_status(:unauthorized) end end @@ -1352,6 +1294,19 @@ RSpec.describe ProjectsController, feature_category: :projects do expect(response).to have_gitlab_http_status(:success) end end + + context 'when sort param is invalid' do + let(:request) { get :refs, params: { namespace_id: project.namespace, id: project, sort: 'invalid' } } + + it 'uses default sort by name' do + request + + expect(response).to have_gitlab_http_status(:success) + expect(json_response['Branches']).to include('master') + expect(json_response['Tags']).to include('v1.0.0') + expect(json_response['Commits']).to be_nil + end + end end describe 'POST #preview_markdown' do @@ -1818,18 +1773,13 @@ RSpec.describe ProjectsController, feature_category: :projects do it 'updates Service Desk attributes' do project.add_maintainer(user) sign_in(user) - allow(Gitlab::IncomingEmail).to receive(:enabled?) { true } - allow(Gitlab::IncomingEmail).to receive(:supports_wildcard?) { true } + allow(Gitlab::Email::IncomingEmail).to receive(:enabled?) { true } + allow(Gitlab::Email::IncomingEmail).to receive(:supports_wildcard?) { true } params = { service_desk_enabled: true } - put :update, - params: { - namespace_id: project.namespace, - id: project, - project: params - } + put :update, params: { namespace_id: project.namespace, id: project, project: params } project.reload expect(response).to have_gitlab_http_status(:found) diff --git a/spec/controllers/registrations/welcome_controller_spec.rb b/spec/controllers/registrations/welcome_controller_spec.rb index b5416d226e1..4118754144c 100644 --- a/spec/controllers/registrations/welcome_controller_spec.rb +++ b/spec/controllers/registrations/welcome_controller_spec.rb @@ -2,10 +2,10 @@ require 'spec_helper' -RSpec.describe Registrations::WelcomeController, feature_category: :authentication_and_authorization do +RSpec.describe Registrations::WelcomeController, feature_category: :system_access do let(:user) { create(:user) } - describe '#welcome' do + describe '#show' do subject(:show) { get :show } context 'without a signed in user' do @@ -27,6 +27,14 @@ RSpec.describe Registrations::WelcomeController, feature_category: :authenticati end it { is_expected.to render_template(:show) } + + render_views + + it 'has the expected submission url' do + show + + expect(response.body).to include("action=\"#{users_sign_up_welcome_path}\"") + end end context 'when role and setup_for_company is set' do @@ -57,6 +65,32 @@ RSpec.describe Registrations::WelcomeController, feature_category: :authenticati expect(subject).not_to redirect_to(profile_two_factor_auth_path) end end + + context 'when welcome step is completed' do + before do + user.update!(setup_for_company: true) + end + + context 'when user is confirmed' do + before do + sign_in(user) + end + + it { is_expected.to redirect_to dashboard_projects_path } + end + + context 'when user is not confirmed' do + before do + stub_application_setting_enum('email_confirmation_setting', 'hard') + + sign_in(user) + + user.update!(confirmed_at: nil) + end + + it { is_expected.to redirect_to user_session_path } + end + end end describe '#update' do diff --git a/spec/controllers/registrations_controller_spec.rb b/spec/controllers/registrations_controller_spec.rb index b217b100349..9aa8a2ae605 100644 --- a/spec/controllers/registrations_controller_spec.rb +++ b/spec/controllers/registrations_controller_spec.rb @@ -12,15 +12,23 @@ RSpec.describe RegistrationsController, feature_category: :user_profile do end describe '#new' do - subject { get :new } + subject(:new) { get :new } it 'renders new template and sets the resource variable' do - expect(subject).to render_template(:new) + expect(new).to render_template(:new) expect(response).to have_gitlab_http_status(:ok) expect(assigns(:resource)).to be_a(User) end it_behaves_like "switches to user preferred language", 'Sign up' + + render_views + + it 'has the expected registration url' do + new + + expect(response.body).to include("action=\"#{user_registration_path}\"") + end end describe '#create' do @@ -75,7 +83,7 @@ RSpec.describe RegistrationsController, feature_category: :user_profile do end context 'email confirmation' do - context 'when `email_confirmation_setting` is set to `hard`' do + context 'when email confirmation setting is set to `hard`' do before do stub_application_setting_enum('email_confirmation_setting', 'hard') end @@ -122,7 +130,7 @@ RSpec.describe RegistrationsController, feature_category: :user_profile do end context 'email confirmation' do - context 'when `email_confirmation_setting` is set to `hard`' do + context 'when email confirmation setting is set to `hard`' do before do stub_application_setting_enum('email_confirmation_setting', 'hard') stub_feature_flags(identity_verification: false) @@ -157,7 +165,7 @@ RSpec.describe RegistrationsController, feature_category: :user_profile do stub_feature_flags(identity_verification: false) end - context 'when `email_confirmation_setting` is set to `off`' do + context 'when email confirmation setting is set to `off`' do it 'signs the user in' do stub_application_setting_enum('email_confirmation_setting', 'off') @@ -166,103 +174,97 @@ RSpec.describe RegistrationsController, feature_category: :user_profile do end end - context 'when `email_confirmation_setting` is set to `hard`' do + context 'when email confirmation setting is set to `hard`' do before do stub_application_setting_enum('email_confirmation_setting', 'hard') + allow(User).to receive(:allow_unconfirmed_access_for).and_return 0 end - context 'when soft email confirmation is not enabled' do - before do - stub_feature_flags(soft_email_confirmation: false) - allow(User).to receive(:allow_unconfirmed_access_for).and_return 0 - end + it 'does not authenticate the user and sends a confirmation email' do + expect { subject }.to have_enqueued_mail(DeviseMailer, :confirmation_instructions) + expect(controller.current_user).to be_nil + end - it 'does not authenticate the user and sends a confirmation email' do - expect { subject }.to have_enqueued_mail(DeviseMailer, :confirmation_instructions) - expect(controller.current_user).to be_nil - end + it 'tracks an almost there redirect' do + post_create - it 'tracks an almost there redirect' do - post_create + expect_snowplow_event( + category: described_class.name, + action: 'render', + user: User.find_by(email: base_user_params[:email]) + ) + end - expect_snowplow_event( - category: described_class.name, - action: 'render', - user: User.find_by(email: base_user_params[:email]) - ) - end + context 'when registration is triggered from an accepted invite' do + context 'when it is part from the initial invite email', :snowplow do + let_it_be(:member) { create(:project_member, :invited, invite_email: user_params.dig(:user, :email)) } - context 'when registration is triggered from an accepted invite' do - context 'when it is part from the initial invite email', :snowplow do - let_it_be(:member) { create(:project_member, :invited, invite_email: user_params.dig(:user, :email)) } + let(:originating_member_id) { member.id } + let(:session_params) do + { + invite_email: user_params.dig(:user, :email), + originating_member_id: originating_member_id + } + end - let(:originating_member_id) { member.id } - let(:session_params) do - { - invite_email: user_params.dig(:user, :email), - originating_member_id: originating_member_id - } + context 'when member exists from the session key value' do + it 'tracks the invite acceptance' do + subject + + expect_snowplow_event( + category: 'RegistrationsController', + action: 'accepted', + label: 'invite_email', + property: member.id.to_s, + user: member.reload.user + ) + + expect_snowplow_event( + category: 'RegistrationsController', + action: 'create_user', + label: 'invited', + user: member.reload.user + ) end + end - context 'when member exists from the session key value' do - it 'tracks the invite acceptance' do - subject - - expect_snowplow_event( - category: 'RegistrationsController', - action: 'accepted', - label: 'invite_email', - property: member.id.to_s, - user: member.reload.user - ) - - expect_snowplow_event( - category: 'RegistrationsController', - action: 'create_user', - label: 'invited', - user: member.reload.user - ) - end - end + context 'when member does not exist from the session key value' do + let(:originating_member_id) { nil } + + it 'does not track invite acceptance' do + subject + + expect_no_snowplow_event( + category: 'RegistrationsController', + action: 'accepted', + label: 'invite_email' + ) - context 'when member does not exist from the session key value' do - let(:originating_member_id) { nil } - - it 'does not track invite acceptance' do - subject - - expect_no_snowplow_event( - category: 'RegistrationsController', - action: 'accepted', - label: 'invite_email' - ) - - expect_snowplow_event( - category: 'RegistrationsController', - action: 'create_user', - label: 'signup', - user: member.reload.user - ) - end + expect_snowplow_event( + category: 'RegistrationsController', + action: 'create_user', + label: 'signup', + user: member.reload.user + ) end end + end - context 'when invite email matches email used on registration' do - let(:session_params) { { invite_email: user_params.dig(:user, :email) } } + context 'when invite email matches email used on registration' do + let(:session_params) { { invite_email: user_params.dig(:user, :email) } } - it 'signs the user in without sending a confirmation email', :aggregate_failures do - expect { subject }.not_to have_enqueued_mail(DeviseMailer, :confirmation_instructions) - expect(controller.current_user).to be_confirmed - end + it 'signs the user in without sending a confirmation email', :aggregate_failures do + expect { subject }.not_to have_enqueued_mail(DeviseMailer, :confirmation_instructions) + expect(controller.current_user).to be_confirmed end + end - context 'when invite email does not match the email used on registration' do - let(:session_params) { { invite_email: 'bogus@email.com' } } + context 'when invite email does not match the email used on registration' do + let(:session_params) { { invite_email: 'bogus@email.com' } } - it 'does not authenticate the user and sends a confirmation email', :aggregate_failures do - expect { subject }.to have_enqueued_mail(DeviseMailer, :confirmation_instructions) - expect(controller.current_user).to be_nil - end + it 'does not authenticate the user and sends a confirmation email', :aggregate_failures do + expect { subject }.to have_enqueued_mail(DeviseMailer, :confirmation_instructions) + expect(controller.current_user).to be_nil end end end @@ -286,45 +288,45 @@ RSpec.describe RegistrationsController, feature_category: :user_profile do expect(controller.current_user).to be_nil end end + end - context 'when soft email confirmation is enabled' do - before do - stub_feature_flags(soft_email_confirmation: true) - allow(User).to receive(:allow_unconfirmed_access_for).and_return 2.days - end + context 'when email confirmation setting is set to `soft`' do + before do + stub_application_setting_enum('email_confirmation_setting', 'soft') + allow(User).to receive(:allow_unconfirmed_access_for).and_return 2.days + end - it 'authenticates the user and sends a confirmation email' do - expect { subject }.to have_enqueued_mail(DeviseMailer, :confirmation_instructions) - expect(controller.current_user).to be_present - expect(response).to redirect_to(users_sign_up_welcome_path) - end + it 'authenticates the user and sends a confirmation email' do + expect { subject }.to have_enqueued_mail(DeviseMailer, :confirmation_instructions) + expect(controller.current_user).to be_present + expect(response).to redirect_to(users_sign_up_welcome_path) + end - it 'does not track an almost there redirect' do - post_create + it 'does not track an almost there redirect' do + post_create - expect_no_snowplow_event( - category: described_class.name, - action: 'render', - user: User.find_by(email: base_user_params[:email]) - ) - end + expect_no_snowplow_event( + category: described_class.name, + action: 'render', + user: User.find_by(email: base_user_params[:email]) + ) + end - context 'when invite email matches email used on registration' do - let(:session_params) { { invite_email: user_params.dig(:user, :email) } } + context 'when invite email matches email used on registration' do + let(:session_params) { { invite_email: user_params.dig(:user, :email) } } - it 'signs the user in without sending a confirmation email', :aggregate_failures do - expect { subject }.not_to have_enqueued_mail(DeviseMailer, :confirmation_instructions) - expect(controller.current_user).to be_confirmed - end + it 'signs the user in without sending a confirmation email', :aggregate_failures do + expect { subject }.not_to have_enqueued_mail(DeviseMailer, :confirmation_instructions) + expect(controller.current_user).to be_confirmed end + end - context 'when invite email does not match the email used on registration' do - let(:session_params) { { invite_email: 'bogus@email.com' } } + context 'when invite email does not match the email used on registration' do + let(:session_params) { { invite_email: 'bogus@email.com' } } - it 'authenticates the user and sends a confirmation email without confirming', :aggregate_failures do - expect { subject }.to have_enqueued_mail(DeviseMailer, :confirmation_instructions) - expect(controller.current_user).not_to be_confirmed - end + it 'authenticates the user and sends a confirmation email without confirming', :aggregate_failures do + expect { subject }.to have_enqueued_mail(DeviseMailer, :confirmation_instructions) + expect(controller.current_user).not_to be_confirmed end end end @@ -756,8 +758,7 @@ RSpec.describe RegistrationsController, feature_category: :user_profile do m.call(*args) expect(Gitlab::ApplicationContext.current) - .to include('meta.user' => user.username, - 'meta.caller_id' => 'RegistrationsController#destroy') + .to include('meta.user' => user.username, 'meta.caller_id' => 'RegistrationsController#destroy') end post :destroy diff --git a/spec/controllers/repositories/git_http_controller_spec.rb b/spec/controllers/repositories/git_http_controller_spec.rb index da62acb1fda..276bd9b65b9 100644 --- a/spec/controllers/repositories/git_http_controller_spec.rb +++ b/spec/controllers/repositories/git_http_controller_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' -RSpec.describe Repositories::GitHttpController do +RSpec.describe Repositories::GitHttpController, feature_category: :source_code_management do let_it_be(:project) { create(:project, :public, :repository) } let_it_be(:personal_snippet) { create(:personal_snippet, :public, :repository) } let_it_be(:project_snippet) { create(:project_snippet, :public, :repository, project: project) } @@ -14,7 +14,7 @@ RSpec.describe Repositories::GitHttpController do request.headers.merge! auth_env(user.username, user.password, nil) end - context 'when Gitaly is unavailable' do + context 'when Gitaly is unavailable', :use_clean_rails_redis_caching do it 'responds with a 503 message' do expect(Gitlab::GitalyClient).to receive(:call).and_raise(GRPC::Unavailable) @@ -26,6 +26,58 @@ RSpec.describe Repositories::GitHttpController do end end + shared_examples 'handles user activity' do + it 'updates the user activity' do + activity_project = container.is_a?(PersonalSnippet) ? nil : project + + activity_service = instance_double(Users::ActivityService) + + args = { author: user, project: activity_project, namespace: activity_project&.namespace } + expect(Users::ActivityService).to receive(:new).with(args).and_return(activity_service) + + expect(activity_service).to receive(:execute) + + get :info_refs, params: params + end + end + + shared_examples 'handles logging git upload pack operation' do + before do + password = user.try(:password) || user.try(:token) + request.headers.merge! auth_env(user.username, password, nil) + end + + context 'with git pull/fetch/clone action' do + let(:params) { super().merge(service: 'git-upload-pack') } + + it_behaves_like 'handles user activity' + end + end + + shared_examples 'handles logging git receive pack operation' do + let(:params) { super().merge(service: 'git-receive-pack') } + + before do + request.headers.merge! auth_env(user.username, user.password, nil) + end + + context 'with git push action when log_user_git_push_activity is enabled' do + it_behaves_like 'handles user activity' + end + + context 'when log_user_git_push_activity is disabled' do + before do + stub_feature_flags(log_user_git_push_activity: false) + end + + it 'does not log user activity' do + expect(controller).not_to receive(:log_user_activity) + + get :info_refs, params: params + end + end + end + context 'when repository container is a project' do it_behaves_like Repositories::GitHttpController do let(:container) { project } @@ -33,6 +85,8 @@ RSpec.describe Repositories::GitHttpController do let(:access_checker_class) { Gitlab::GitAccess } it_behaves_like 'handles unavailable Gitaly' + it_behaves_like 'handles logging git upload pack operation' + it_behaves_like 'handles logging git receive pack operation' describe 'POST #git_upload_pack' do before do @@ -83,6 +137,8 @@ RSpec.describe Repositories::GitHttpController do let(:container) { project } let(:user) { create(:deploy_token, :project, projects: [project]) } let(:access_checker_class) { Gitlab::GitAccess } + + it_behaves_like 'handles logging git upload pack operation' end end end @@ -92,6 +148,9 @@ RSpec.describe Repositories::GitHttpController do let(:container) { create(:project_wiki, :empty_repo, project: project) } let(:user) { project.first_owner } let(:access_checker_class) { Gitlab::GitAccessWiki } + + it_behaves_like 'handles logging git upload pack operation' + it_behaves_like 'handles logging git receive pack operation' end end @@ -102,6 +161,8 @@ RSpec.describe Repositories::GitHttpController do let(:access_checker_class) { Gitlab::GitAccessSnippet } it_behaves_like 'handles unavailable Gitaly' + it_behaves_like 'handles logging git upload pack operation' + it_behaves_like 'handles logging git receive pack operation' end end @@ -112,6 +173,8 @@ RSpec.describe Repositories::GitHttpController do let(:access_checker_class) { Gitlab::GitAccessSnippet } it_behaves_like 'handles unavailable Gitaly' + it_behaves_like 'handles logging git upload pack operation' + it_behaves_like 'handles logging git receive pack operation' end end end diff --git a/spec/controllers/search_controller_spec.rb b/spec/controllers/search_controller_spec.rb index 0f7f4a1910b..497e2d84f4f 100644 --- a/spec/controllers/search_controller_spec.rb +++ b/spec/controllers/search_controller_spec.rb @@ -38,6 +38,41 @@ RSpec.describe SearchController, feature_category: :global_search do it_behaves_like 'with external authorization service enabled', :show, { search: 'hello' } it_behaves_like 'support for active record query timeouts', :show, { search: 'hello' }, :search_objects, :html + describe 'rate limit scope' do + it 'uses current_user and search scope' do + %w[projects blobs users issues merge_requests].each do |scope| + expect(::Gitlab::ApplicationRateLimiter).to receive(:throttled?).with(:search_rate_limit, scope: [user, scope]) + get :show, params: { search: 'hello', scope: scope } + end + end + + it 'uses just current_user when no search scope is used' do + expect(::Gitlab::ApplicationRateLimiter).to receive(:throttled?).with(:search_rate_limit, scope: [user]) + get :show, params: { search: 'hello' } + end + + it 'uses just current_user when search scope is abusive' do + expect(::Gitlab::ApplicationRateLimiter).to receive(:throttled?).with(:search_rate_limit, scope: [user]) + get(:show, params: { search: 'hello', scope: 'hack-the-mainframe' }) + + expect(::Gitlab::ApplicationRateLimiter).to receive(:throttled?).with(:search_rate_limit, scope: [user]) + get :show, params: { search: 'hello', scope: 'blobs' * 1000 } + end + + context 'when search_rate_limited_scopes feature flag is disabled' do + before do + stub_feature_flags(search_rate_limited_scopes: false) + end + + it 'uses just current_user' do + %w[projects blobs users issues merge_requests].each do |scope| + expect(::Gitlab::ApplicationRateLimiter).to receive(:throttled?).with(:search_rate_limit, scope: [user]) + get :show, params: { search: 'hello', scope: scope } + end + end + end + end + context 'uses the right partials depending on scope' do using RSpec::Parameterized::TableSyntax render_views @@ -227,12 +262,10 @@ RSpec.describe SearchController, feature_category: :global_search do let(:label) { 'redis_hll_counters.search.search_total_unique_counts_monthly' } let(:property) { 'i_search_total' } let(:context) do - [Gitlab::Tracking::ServicePingContext.new(data_source: :redis_hll, - event: property).to_context] + [Gitlab::Tracking::ServicePingContext.new(data_source: :redis_hll, event: property).to_context] end let(:namespace) { create(:group) } - let(:feature_flag_name) { :route_hll_to_snowplow_phase2 } end context 'on restricted projects' do @@ -347,6 +380,36 @@ RSpec.describe SearchController, feature_category: :global_search do expect(json_response).to eq({ 'count' => '1' }) end + describe 'rate limit scope' do + it 'uses current_user and search scope' do + %w[projects blobs users issues merge_requests].each do |scope| + expect(::Gitlab::ApplicationRateLimiter).to receive(:throttled?).with(:search_rate_limit, scope: [user, scope]) + get :count, params: { search: 'hello', scope: scope } + end + end + + it 'uses just current_user when search scope is abusive' do + expect(::Gitlab::ApplicationRateLimiter).to receive(:throttled?).with(:search_rate_limit, scope: [user]) + get :count, params: { search: 'hello', scope: 'hack-the-mainframe' } + + expect(::Gitlab::ApplicationRateLimiter).to receive(:throttled?).with(:search_rate_limit, scope: [user]) + get :count, params: { search: 'hello', scope: 'blobs' * 1000 } + end + + context 'when search_rate_limited_scopes feature flag is disabled' do + before do + stub_feature_flags(search_rate_limited_scopes: false) + end + + it 'uses just current_user' do + %w[projects blobs users issues merge_requests].each do |scope| + expect(::Gitlab::ApplicationRateLimiter).to receive(:throttled?).with(:search_rate_limit, scope: [user]) + get :count, params: { search: 'hello', scope: scope } + end + end + end + end + it 'raises an error if search term is missing' do expect do get :count, params: { scope: 'projects' } @@ -408,6 +471,36 @@ RSpec.describe SearchController, feature_category: :global_search do expect(json_response).to match_array([]) end + describe 'rate limit scope' do + it 'uses current_user and search scope' do + %w[projects blobs users issues merge_requests].each do |scope| + expect(::Gitlab::ApplicationRateLimiter).to receive(:throttled?).with(:search_rate_limit, scope: [user, scope]) + get :autocomplete, params: { term: 'hello', scope: scope } + end + end + + it 'uses just current_user when search scope is abusive' do + expect(::Gitlab::ApplicationRateLimiter).to receive(:throttled?).with(:search_rate_limit, scope: [user]) + get :autocomplete, params: { term: 'hello', scope: 'hack-the-mainframe' } + + expect(::Gitlab::ApplicationRateLimiter).to receive(:throttled?).with(:search_rate_limit, scope: [user]) + get :autocomplete, params: { term: 'hello', scope: 'blobs' * 1000 } + end + + context 'when search_rate_limited_scopes feature flag is disabled' do + before do + stub_feature_flags(search_rate_limited_scopes: false) + end + + it 'uses just current_user' do + %w[projects blobs users issues merge_requests].each do |scope| + expect(::Gitlab::ApplicationRateLimiter).to receive(:throttled?).with(:search_rate_limit, scope: [user]) + get :autocomplete, params: { term: 'hello', scope: scope } + end + end + end + end + it_behaves_like 'rate limited endpoint', rate_limit_key: :search_rate_limit do let(:current_user) { user } @@ -428,6 +521,15 @@ RSpec.describe SearchController, feature_category: :global_search do get :autocomplete, params: { term: 'setting', filter: 'generic' } end + + it 'sets correct cache control headers' do + get :autocomplete, params: { term: 'setting', filter: 'generic' } + + expect(response).to have_gitlab_http_status(:ok) + + expect(response.headers['Cache-Control']).to eq('max-age=60, private') + expect(response.headers['Pragma']).to be_nil + end end describe '#append_info_to_payload' do @@ -518,6 +620,11 @@ RSpec.describe SearchController, feature_category: :global_search do get endpoint, params: params.merge(project_id: project.id) end end + + it 'uses request IP as rate limiting scope' do + expect(::Gitlab::ApplicationRateLimiter).to receive(:throttled?).with(:search_rate_limit_unauthenticated, scope: [request.ip]) + get endpoint, params: params.merge(project_id: project.id) + end end end diff --git a/spec/controllers/sessions_controller_spec.rb b/spec/controllers/sessions_controller_spec.rb index 1f7d169bae5..80856512bba 100644 --- a/spec/controllers/sessions_controller_spec.rb +++ b/spec/controllers/sessions_controller_spec.rb @@ -375,8 +375,7 @@ RSpec.describe SessionsController do context 'when OTP is valid for another user' do it 'does not authenticate' do - authenticate_2fa(login: another_user.username, - otp_attempt: another_user.current_otp) + authenticate_2fa(login: another_user.username, otp_attempt: another_user.current_otp) expect(subject.current_user).not_to eq another_user end @@ -384,8 +383,7 @@ RSpec.describe SessionsController do context 'when OTP is invalid for another user' do it 'does not authenticate' do - authenticate_2fa(login: another_user.username, - otp_attempt: 'invalid') + authenticate_2fa(login: another_user.username, otp_attempt: 'invalid') expect(subject.current_user).not_to eq another_user end @@ -495,51 +493,49 @@ RSpec.describe SessionsController do end end - context 'when using two-factor authentication via U2F device' do - let(:user) { create(:user, :two_factor) } + context 'when using two-factor authentication via WebAuthn device' do + let(:user) { create(:user, :two_factor_via_webauthn) } - def authenticate_2fa_u2f(user_params) + def authenticate_2fa(user_params) post(:create, params: { user: user_params }, session: { otp_user_id: user.id }) end - before do - stub_feature_flags(webauthn: false) - end - context 'remember_me field' do it 'sets a remember_user_token cookie when enabled' do - allow(U2fRegistration).to receive(:authenticate).and_return(true) + allow_any_instance_of(Webauthn::AuthenticateService).to receive(:execute).and_return(true) allow(controller).to receive(:find_user).and_return(user) - expect(controller) - .to receive(:remember_me).with(user).and_call_original + expect(controller).to receive(:remember_me).with(user).and_call_original - authenticate_2fa_u2f(remember_me: '1', login: user.username, device_response: "{}") + authenticate_2fa(remember_me: '1', login: user.username, device_response: "{}") expect(response.cookies['remember_user_token']).to be_present end it 'does nothing when disabled' do - allow(U2fRegistration).to receive(:authenticate).and_return(true) + allow_any_instance_of(Webauthn::AuthenticateService).to receive(:execute).and_return(true) allow(controller).to receive(:find_user).and_return(user) expect(controller).not_to receive(:remember_me) - authenticate_2fa_u2f(remember_me: '0', login: user.username, device_response: "{}") + authenticate_2fa(remember_me: '0', login: user.username, device_response: "{}") expect(response.cookies['remember_user_token']).to be_nil end end it "creates an audit log record" do - allow(U2fRegistration).to receive(:authenticate).and_return(true) - expect { authenticate_2fa_u2f(login: user.username, device_response: "{}") }.to change { AuditEvent.count }.by(1) - expect(AuditEvent.last.details[:with]).to eq("two-factor-via-u2f-device") + allow_any_instance_of(Webauthn::AuthenticateService).to receive(:execute).and_return(true) + + expect { authenticate_2fa(login: user.username, device_response: "{}") }.to( + change { AuditEvent.count }.by(1)) + expect(AuditEvent.last.details[:with]).to eq("two-factor-via-webauthn-device") end it "creates an authentication event record" do - allow(U2fRegistration).to receive(:authenticate).and_return(true) + allow_any_instance_of(Webauthn::AuthenticateService).to receive(:execute).and_return(true) - expect { authenticate_2fa_u2f(login: user.username, device_response: "{}") }.to change { AuthenticationEvent.count }.by(1) - expect(AuthenticationEvent.last.provider).to eq("two-factor-via-u2f-device") + expect { authenticate_2fa(login: user.username, device_response: "{}") }.to( + change { AuthenticationEvent.count }.by(1)) + expect(AuthenticationEvent.last.provider).to eq("two-factor-via-webauthn-device") end end end @@ -567,8 +563,7 @@ RSpec.describe SessionsController do it 'sets the username and caller_id in the context' do expect(controller).to receive(:destroy).and_wrap_original do |m, *args| expect(Gitlab::ApplicationContext.current) - .to include('meta.user' => user.username, - 'meta.caller_id' => 'SessionsController#destroy') + .to include('meta.user' => user.username, 'meta.caller_id' => 'SessionsController#destroy') m.call(*args) end @@ -607,8 +602,7 @@ RSpec.describe SessionsController do m.call(*args) end - post(:create, - params: { user: { login: user.username, password: user.password.succ } }) + post :create, params: { user: { login: user.username, password: user.password.succ } } end end end diff --git a/spec/controllers/snippets/blobs_controller_spec.rb b/spec/controllers/snippets/blobs_controller_spec.rb index b9f58587a58..b92621d4041 100644 --- a/spec/controllers/snippets/blobs_controller_spec.rb +++ b/spec/controllers/snippets/blobs_controller_spec.rb @@ -17,13 +17,7 @@ RSpec.describe Snippets::BlobsController do let(:inline) { nil } subject do - get(:raw, - params: { - snippet_id: snippet, - path: filepath, - ref: ref, - inline: inline - }) + get :raw, params: { snippet_id: snippet, path: filepath, ref: ref, inline: inline } end where(:snippet_visibility_level, :user, :status) do diff --git a/spec/db/schema_spec.rb b/spec/db/schema_spec.rb index 6019f10eeeb..9f228c75127 100644 --- a/spec/db/schema_spec.rb +++ b/spec/db/schema_spec.rb @@ -10,14 +10,21 @@ RSpec.describe 'Database schema', feature_category: :database do let(:columns_name_with_jsonb) { retrieve_columns_name_with_jsonb } IGNORED_INDEXES_ON_FKS = { - slack_integrations_scopes: %w[slack_api_scope_id], - # Will be removed in https://gitlab.com/gitlab-org/gitlab/-/issues/391312 - approval_project_rules: %w[scan_result_policy_id], - approval_merge_request_rules: %w[scan_result_policy_id] + # `search_index_id index_type` is the composite foreign key configured for `search_namespace_index_assignments`, + # but in Search::NamespaceIndexAssignment model, only `search_index_id` is used as foreign key and indexed + search_namespace_index_assignments: [%w[search_index_id index_type]], + slack_integrations_scopes: [%w[slack_api_scope_id]] }.with_indifferent_access.freeze TABLE_PARTITIONS = %w[ci_builds_metadata].freeze + # If splitting FK and table removal into two MRs as suggested in the docs, use this constant in the initial FK removal MR. + # In the subsequent table removal MR, remove the entries. + # See: https://docs.gitlab.com/ee/development/migration_style_guide.html#dropping-a-database-table + REMOVED_FKS = { + # example_table: %w[example_column] + }.with_indifferent_access.freeze + # List of columns historically missing a FK, don't add more columns # See: https://docs.gitlab.com/ee/development/database/foreign_keys.html#naming-foreign-keys IGNORED_FK_COLUMNS = { @@ -33,29 +40,17 @@ RSpec.describe 'Database schema', feature_category: :database do award_emoji: %w[awardable_id user_id], aws_roles: %w[role_external_id], boards: %w[milestone_id iteration_id], + broadcast_messages: %w[namespace_id], chat_names: %w[chat_id team_id user_id integration_id], chat_teams: %w[team_id], - ci_build_needs: %w[partition_id], - ci_build_pending_states: %w[partition_id build_id], - ci_build_report_results: %w[partition_id], - ci_build_trace_chunks: %w[partition_id build_id], - ci_build_trace_metadata: %w[partition_id], ci_builds: %w[erased_by_id trigger_request_id partition_id], - ci_builds_runner_session: %w[partition_id build_id], - p_ci_builds_metadata: %w[partition_id], - ci_job_artifacts: %w[partition_id], - ci_job_variables: %w[partition_id], ci_namespace_monthly_usages: %w[namespace_id], - ci_pending_builds: %w[partition_id], ci_pipeline_variables: %w[partition_id], ci_pipelines: %w[partition_id], - ci_resources: %w[partition_id build_id], ci_runner_projects: %w[runner_id], - ci_running_builds: %w[partition_id], - ci_sources_pipelines: %w[partition_id source_partition_id], + ci_sources_pipelines: %w[partition_id source_partition_id source_job_id], ci_stages: %w[partition_id], ci_trigger_requests: %w[commit_id], - ci_unit_test_failures: %w[partition_id build_id], cluster_providers_aws: %w[security_group_id vpc_id access_key_id], cluster_providers_gcp: %w[gcp_project_id operation_id], compliance_management_frameworks: %w[group_id], @@ -91,13 +86,13 @@ RSpec.describe 'Database schema', feature_category: :database do oauth_access_grants: %w[resource_owner_id application_id], oauth_access_tokens: %w[resource_owner_id application_id], oauth_applications: %w[owner_id], + p_ci_runner_machine_builds: %w[partition_id build_id], product_analytics_events_experimental: %w[event_id txn_id user_id], project_build_artifacts_size_refreshes: %w[last_job_artifact_id], project_data_transfers: %w[project_id namespace_id], project_error_tracking_settings: %w[sentry_project_id], - project_group_links: %w[group_id], project_statistics: %w[namespace_id], - projects: %w[creator_id ci_id mirror_user_id], + projects: %w[ci_id mirror_user_id], redirect_routes: %w[source_id], repository_languages: %w[programming_language_id], routes: %w[source_id], @@ -121,7 +116,10 @@ RSpec.describe 'Database schema', feature_category: :database do vulnerability_reads: %w[cluster_agent_id], # See: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/87584 # Fixes performance issues with the deletion of web-hooks with many log entries - web_hook_logs: %w[web_hook_id] + web_hook_logs: %w[web_hook_id], + webauthn_registrations: %w[u2f_registration_id], # this column will be dropped + ml_candidates: %w[internal_id], + value_stream_dashboard_counts: %w[namespace_id] }.with_indifferent_access.freeze context 'for table' do @@ -134,48 +132,52 @@ RSpec.describe 'Database schema', feature_category: :database do describe table do let(:indexes) { connection.indexes(table) } let(:columns) { connection.columns(table) } - let(:foreign_keys) { connection.foreign_keys(table) } + let(:foreign_keys) { to_foreign_keys(Gitlab::Database::PostgresForeignKey.by_constrained_table_name(table)) } let(:loose_foreign_keys) { Gitlab::Database::LooseForeignKeys.definitions.group_by(&:from_table).fetch(table, []) } let(:all_foreign_keys) { foreign_keys + loose_foreign_keys } - # take the first column in case we're using a composite primary key - let(:primary_key_column) { Array(connection.primary_key(table)).first } + let(:composite_primary_key) { Array.wrap(connection.primary_key(table)) } context 'all foreign keys' do # for index to be effective, the FK constraint has to be at first place it 'are indexed' do - first_indexed_column = indexes.filter_map do |index| + indexed_columns = indexes.filter_map do |index| columns = index.columns # In cases of complex composite indexes, a string is returned eg: # "lower((extern_uid)::text), group_id" - columns = columns.split(',') if columns.is_a?(String) - column = columns.first.chomp + columns = columns.split(',').map(&:chomp) if columns.is_a?(String) # A partial index is not suitable for a foreign key column, unless # the only condition is for the presence of the foreign key itself - column if index.where.nil? || index.where == "(#{column} IS NOT NULL)" + columns if index.where.nil? || index.where == "(#{columns.first} IS NOT NULL)" end foreign_keys_columns = all_foreign_keys.map(&:column) - required_indexed_columns = foreign_keys_columns - ignored_index_columns(table) + required_indexed_columns = to_columns(foreign_keys_columns - ignored_index_columns(table)) - # Add the primary key column to the list of indexed columns because + # Add the composite primary key to the list of indexed columns because # postgres and mysql both automatically create an index on the primary # key. Also, the rails connection.indexes() method does not return # automatically generated indexes (like the primary key index). - first_indexed_column.push(primary_key_column) + indexed_columns.push(composite_primary_key) - expect(first_indexed_column.uniq).to include(*required_indexed_columns) + expect(required_indexed_columns).to be_indexed_by(indexed_columns) end end context 'columns ending with _id' do let(:column_names) { columns.map(&:name) } let(:column_names_with_id) { column_names.select { |column_name| column_name.ends_with?('_id') } } - let(:foreign_keys_columns) { all_foreign_keys.reject { |fk| fk.name&.end_with?("_p") }.map(&:column).uniq } # we can have FK and loose FK present at the same time let(:ignored_columns) { ignored_fk_columns(table) } + let(:foreign_keys_columns) do + to_columns( + all_foreign_keys + .reject { |fk| fk.name&.end_with?("_id_convert_to_bigint") } + .map(&:column) + ) + end it 'do have the foreign keys' do - expect(column_names_with_id - ignored_columns).to match_array(foreign_keys_columns) + expect(column_names_with_id - ignored_columns).to be_a_foreign_key_column_of(foreign_keys_columns) end it 'and having foreign key are not in the ignore list' do @@ -200,7 +202,6 @@ RSpec.describe 'Database schema', feature_category: :database do 'Ci::Processable' => %w[failure_reason], 'Ci::Runner' => %w[access_level], 'Ci::Stage' => %w[status], - 'Clusters::Applications::Ingress' => %w[ingress_type], 'Clusters::Cluster' => %w[platform_type provider_type], 'CommitStatus' => %w[failure_reason], 'GenericCommitStatus' => %w[failure_reason], @@ -308,6 +309,28 @@ RSpec.describe 'Database schema', feature_category: :database do expect(problematic_tables).to be_empty end end + + context 'for CI partitioned table' do + # Check that each partitionable model with more than 1 column has the partition_id column at the trailing + # position. Using PARTITIONABLE_MODELS instead of iterating tables since when partitioning existing tables, + # the routing table only gets created after the PK has already been created, which would be too late for a check. + + skip_tables = %w[] + partitionable_models = Ci::Partitionable::Testing::PARTITIONABLE_MODELS + (partitionable_models - skip_tables).each do |klass| + model = klass.safe_constantize + table_name = model.table_name + + primary_key_columns = Array.wrap(model.connection.primary_key(table_name)) + next if primary_key_columns.count == 1 + + describe table_name do + it 'expects every PK to have partition_id at trailing position' do + expect(primary_key_columns).to match([an_instance_of(String), 'partition_id']) + end + end + end + end end context 'index names' do @@ -338,12 +361,32 @@ RSpec.describe 'Database schema', feature_category: :database do ApplicationRecord.connection.select_all(sql).to_a end + def to_foreign_keys(constraints) + constraints.map do |constraint| + from_table = constraint.constrained_table_identifier + ActiveRecord::ConnectionAdapters::ForeignKeyDefinition.new( + from_table, + constraint.referenced_table_identifier, + { + name: constraint.name, + column: constraint.constrained_columns, + on_delete: constraint.on_delete_action&.to_sym, + gitlab_schema: Gitlab::Database::GitlabSchema.table_schema!(from_table) + } + ) + end + end + + def to_columns(items) + items.map { |item| Array.wrap(item) }.uniq + end + def models_by_table_name @models_by_table_name ||= ApplicationRecord.descendants.reject(&:abstract_class).group_by(&:table_name) end def ignored_fk_columns(table) - IGNORED_FK_COLUMNS.fetch(table, []) + REMOVED_FKS.merge(IGNORED_FK_COLUMNS).fetch(table, []) end def ignored_index_columns(table) diff --git a/spec/deprecation_warnings.rb b/spec/deprecation_warnings.rb new file mode 100644 index 00000000000..45fed5fecca --- /dev/null +++ b/spec/deprecation_warnings.rb @@ -0,0 +1,21 @@ +# frozen_string_literal: true + +require_relative '../lib/gitlab/utils' +return if Gitlab::Utils.to_boolean(ENV['SILENCE_DEPRECATIONS'], default: false) + +# Enable deprecation warnings by default and make them more visible +# to developers to ease upgrading to newer Ruby versions. +Warning[:deprecated] = true + +# rubocop:disable Layout/LineLength +case RUBY_VERSION[/\d+\.\d+/, 0] +when '3.2' + warn "#{__FILE__}:#{__LINE__}: warning: Ignored warnings for Ruby < 3.2 are no longer necessary." +else + require 'warning' + # Ignore Ruby warnings until Ruby 3.2. + # ... ruby/3.1.3/lib/ruby/gems/3.1.0/gems/rspec-parameterized-table_syntax-1.0.0/lib/rspec/parameterized/table_syntax.rb:38: warning: Refinement#include is deprecated and will be removed in Ruby 3.2 + + Warning.ignore(%r{rspec-parameterized-table_syntax-1\.0\.0/lib/rspec/parameterized/table_syntax\.rb:\d+: warning: Refinement#include is deprecated}) +end +# rubocop:enable Layout/LineLength diff --git a/spec/experiments/application_experiment_spec.rb b/spec/experiments/application_experiment_spec.rb index 7aca5e492f4..ef8f8cbce3b 100644 --- a/spec/experiments/application_experiment_spec.rb +++ b/spec/experiments/application_experiment_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' -RSpec.describe ApplicationExperiment, :experiment do +RSpec.describe ApplicationExperiment, :experiment, feature_category: :experimentation_conversion do subject(:application_experiment) { described_class.new('namespaced/stub', **context) } let(:context) { {} } @@ -187,13 +187,11 @@ RSpec.describe ApplicationExperiment, :experiment do end with_them do - it "returns the url or nil if invalid" do - allow(Gitlab).to receive(:com?).and_return(true) + it "returns the url or nil if invalid on SaaS", :saas do expect(application_experiment.process_redirect_url(url)).to eq(processed_url) end - it "considers all urls invalid when not on dev or com" do - allow(Gitlab).to receive(:com?).and_return(false) + it "considers all urls invalid when not on SaaS" do expect(application_experiment.process_redirect_url(url)).to be_nil end end diff --git a/spec/experiments/require_verification_for_namespace_creation_experiment_spec.rb b/spec/experiments/require_verification_for_namespace_creation_experiment_spec.rb deleted file mode 100644 index c91a8f1950e..00000000000 --- a/spec/experiments/require_verification_for_namespace_creation_experiment_spec.rb +++ /dev/null @@ -1,49 +0,0 @@ -# frozen_string_literal: true - -require 'spec_helper' - -RSpec.describe RequireVerificationForNamespaceCreationExperiment, :experiment do - subject(:experiment) { described_class.new(user: user) } - - let(:user_created_at) { RequireVerificationForNamespaceCreationExperiment::EXPERIMENT_START_DATE + 1.hour } - let(:user) { create(:user, created_at: user_created_at) } - - describe '#candidate?' do - context 'when experiment subject is candidate' do - before do - stub_experiments(require_verification_for_namespace_creation: :candidate) - end - - it 'returns true' do - expect(experiment.candidate?).to eq(true) - end - end - - context 'when experiment subject is control' do - before do - stub_experiments(require_verification_for_namespace_creation: :control) - end - - it 'returns false' do - expect(experiment.candidate?).to eq(false) - end - end - end - - describe 'exclusions' do - context 'when user is new' do - it 'is not excluded' do - expect(subject).not_to exclude(user: user) - end - end - - context 'when user is NOT new' do - let(:user_created_at) { RequireVerificationForNamespaceCreationExperiment::EXPERIMENT_START_DATE - 1.day } - let(:user) { create(:user, created_at: user_created_at) } - - it 'is excluded' do - expect(subject).to exclude(user: user) - end - end - end -end diff --git a/spec/experiments/security_reports_mr_widget_prompt_experiment_spec.rb b/spec/experiments/security_reports_mr_widget_prompt_experiment_spec.rb deleted file mode 100644 index ee02fa5f1f2..00000000000 --- a/spec/experiments/security_reports_mr_widget_prompt_experiment_spec.rb +++ /dev/null @@ -1,9 +0,0 @@ -# frozen_string_literal: true - -require 'spec_helper' - -RSpec.describe SecurityReportsMrWidgetPromptExperiment do - it "defines a control and candidate" do - expect(subject.behaviors.keys).to match_array(%w[control candidate]) - end -end diff --git a/spec/factories/abuse/trust_score.rb b/spec/factories/abuse/trust_score.rb new file mode 100644 index 00000000000..a5ea7666945 --- /dev/null +++ b/spec/factories/abuse/trust_score.rb @@ -0,0 +1,10 @@ +# frozen_string_literal: true + +FactoryBot.define do + factory :abuse_trust_score, class: 'Abuse::TrustScore' do + user + score { 0.1 } + source { :spamcheck } + correlation_id_value { 'abcdefg' } + end +end diff --git a/spec/factories/abuse_reports.rb b/spec/factories/abuse_reports.rb index 355fb142994..699da744fab 100644 --- a/spec/factories/abuse_reports.rb +++ b/spec/factories/abuse_reports.rb @@ -7,5 +7,13 @@ FactoryBot.define do message { 'User sends spam' } reported_from_url { 'http://gitlab.com' } links_to_spam { ['https://gitlab.com/issue1', 'https://gitlab.com/issue2'] } + + trait :closed do + status { 'closed' } + end + + trait :with_screenshot do + screenshot { fixture_file_upload('spec/fixtures/dk.png') } + end end end diff --git a/spec/factories/achievements/user_achievements.rb b/spec/factories/achievements/user_achievements.rb new file mode 100644 index 00000000000..a5fd1df38dd --- /dev/null +++ b/spec/factories/achievements/user_achievements.rb @@ -0,0 +1,14 @@ +# frozen_string_literal: true + +FactoryBot.define do + factory :user_achievement, class: 'Achievements::UserAchievement' do + user + achievement + awarded_by_user factory: :user + + trait :revoked do + revoked_by_user factory: :user + revoked_at { Time.now } + end + end +end diff --git a/spec/factories/airflow/dags.rb b/spec/factories/airflow/dags.rb deleted file mode 100644 index ca4276e2c8f..00000000000 --- a/spec/factories/airflow/dags.rb +++ /dev/null @@ -1,8 +0,0 @@ -# frozen_string_literal: true -FactoryBot.define do - factory :airflow_dags, class: '::Airflow::Dags' do - sequence(:dag_name) { |n| "dag_name_#{n}" } - - project - end -end diff --git a/spec/factories/bulk_import/batch_trackers.rb b/spec/factories/bulk_import/batch_trackers.rb new file mode 100644 index 00000000000..427eefc5f3e --- /dev/null +++ b/spec/factories/bulk_import/batch_trackers.rb @@ -0,0 +1,37 @@ +# frozen_string_literal: true + +FactoryBot.define do + factory :bulk_import_batch_tracker, class: 'BulkImports::BatchTracker' do + association :tracker, factory: :bulk_import_tracker + + status { 0 } + fetched_objects_count { 1000 } + imported_objects_count { 1000 } + + sequence(:batch_number) { |n| n } + + trait :created do + status { 0 } + end + + trait :started do + status { 1 } + end + + trait :finished do + status { 2 } + end + + trait :timeout do + status { 3 } + end + + trait :failed do + status { -1 } + end + + trait :skipped do + status { -2 } + end + end +end diff --git a/spec/factories/bulk_import/export_batches.rb b/spec/factories/bulk_import/export_batches.rb new file mode 100644 index 00000000000..f5f12696f5f --- /dev/null +++ b/spec/factories/bulk_import/export_batches.rb @@ -0,0 +1,24 @@ +# frozen_string_literal: true + +FactoryBot.define do + factory :bulk_import_export_batch, class: 'BulkImports::ExportBatch' do + association :export, factory: :bulk_import_export + + upload { association(:bulk_import_export_upload) } + + status { 0 } + batch_number { 1 } + + trait :started do + status { 0 } + end + + trait :finished do + status { 1 } + end + + trait :failed do + status { -1 } + end + end +end diff --git a/spec/factories/bulk_import/exports.rb b/spec/factories/bulk_import/exports.rb index dd8831ce33a..795a9bbfe20 100644 --- a/spec/factories/bulk_import/exports.rb +++ b/spec/factories/bulk_import/exports.rb @@ -20,5 +20,9 @@ FactoryBot.define do trait :failed do status { -1 } end + + trait :batched do + batched { true } + end end end diff --git a/spec/factories/chat_names.rb b/spec/factories/chat_names.rb index 56567394bf5..c872694ee64 100644 --- a/spec/factories/chat_names.rb +++ b/spec/factories/chat_names.rb @@ -3,7 +3,6 @@ FactoryBot.define do factory :chat_name, class: 'ChatName' do user - integration team_id { 'T0001' } team_domain { 'Awesome Team' } diff --git a/spec/factories/ci/builds.rb b/spec/factories/ci/builds.rb index 224f460488b..dc75e17499c 100644 --- a/spec/factories/ci/builds.rb +++ b/spec/factories/ci/builds.rb @@ -415,7 +415,7 @@ FactoryBot.define do runner factory: :ci_runner after(:create) do |build| - build.create_runtime_metadata! + ::Ci::RunningBuild.upsert_shared_runner_build!(build) end end @@ -694,7 +694,7 @@ FactoryBot.define do end end - trait :non_public_artifacts do + trait :with_private_artifacts_config do options do { artifacts: { public: false } @@ -702,6 +702,14 @@ FactoryBot.define do end end + trait :with_public_artifacts_config do + options do + { + artifacts: { public: true } + } + end + end + trait :non_playable do status { 'created' } self.when { 'manual' } diff --git a/spec/factories/ci/catalog/resources.rb b/spec/factories/ci/catalog/resources.rb new file mode 100644 index 00000000000..66c2e58cdd9 --- /dev/null +++ b/spec/factories/ci/catalog/resources.rb @@ -0,0 +1,7 @@ +# frozen_string_literal: true + +FactoryBot.define do + factory :catalog_resource, class: 'Ci::Catalog::Resource' do + project factory: :project + end +end diff --git a/spec/factories/ci/pipelines.rb b/spec/factories/ci/pipelines.rb index d68562c0aa5..2b6bddd2f6d 100644 --- a/spec/factories/ci/pipelines.rb +++ b/spec/factories/ci/pipelines.rb @@ -21,6 +21,12 @@ FactoryBot.define do transient { name { nil } } + transient { ci_ref_presence { true } } + + before(:create) do |pipeline, evaluator| + pipeline.ensure_ci_ref! if evaluator.ci_ref_presence && pipeline.ci_ref_id.nil? + end + after(:build) do |pipeline, evaluator| if evaluator.child_of pipeline.project = evaluator.child_of.project @@ -54,12 +60,6 @@ FactoryBot.define do end factory :ci_pipeline do - transient { ci_ref_presence { true } } - - before(:create) do |pipeline, evaluator| - pipeline.ensure_ci_ref! if evaluator.ci_ref_presence && pipeline.ci_ref_id.nil? - end - trait :invalid do status { :failed } yaml_errors { 'invalid YAML' } diff --git a/spec/factories/ci/processable.rb b/spec/factories/ci/processable.rb index 49e66368f94..49756433713 100644 --- a/spec/factories/ci/processable.rb +++ b/spec/factories/ci/processable.rb @@ -26,13 +26,19 @@ FactoryBot.define do before(:create) do |processable, evaluator| next if processable.ci_stage - if ci_stage = processable.pipeline.stages.find_by(name: evaluator.stage) - processable.ci_stage = ci_stage - else - processable.ci_stage = create(:ci_stage, pipeline: processable.pipeline, - project: processable.project || evaluator.project, - name: evaluator.stage, position: evaluator.stage_idx, status: 'created') - end + processable.ci_stage = + if ci_stage = processable.pipeline.stages.find_by(name: evaluator.stage) + ci_stage + else + create( + :ci_stage, + pipeline: processable.pipeline, + project: processable.project || evaluator.project, + name: evaluator.stage, + position: evaluator.stage_idx, + status: 'created' + ) + end end trait :waiting_for_resource do diff --git a/spec/factories/ci/reports/security/findings.rb b/spec/factories/ci/reports/security/findings.rb index 78c11210f97..c57a2dd479f 100644 --- a/spec/factories/ci/reports/security/findings.rb +++ b/spec/factories/ci/reports/security/findings.rb @@ -27,6 +27,7 @@ FactoryBot.define do url: "https://crypto.stackexchange.com/questions/31428/pbewithmd5anddes-cipher-does-not-check-for-integrity-first" } ], + raw_source_code_extract: 'AES/ECB/NoPadding', evidence: { summary: 'Credit card detected', request: { diff --git a/spec/factories/ci/reports/security/reports.rb b/spec/factories/ci/reports/security/reports.rb index 5699b8fee3e..60d1f4615ac 100644 --- a/spec/factories/ci/reports/security/reports.rb +++ b/spec/factories/ci/reports/security/reports.rb @@ -19,6 +19,19 @@ FactoryBot.define do evaluator.findings.each { |o| report.add_finding(o) } end + factory :dependency_scanning_security_report do + type { :dependency_scanning } + + after :create do |report| + artifact = report.pipeline.job_artifacts.dependency_scanning.last + if artifact.present? + content = File.read(artifact.file.path) + + Gitlab::Ci::Parsers::Security::DependencyScanning.parse!(content, report) + end + end + end + skip_create initialize_with do diff --git a/spec/factories/ci/runner_machine_builds.rb b/spec/factories/ci/runner_machine_builds.rb new file mode 100644 index 00000000000..34238760112 --- /dev/null +++ b/spec/factories/ci/runner_machine_builds.rb @@ -0,0 +1,8 @@ +# frozen_string_literal: true + +FactoryBot.define do + factory :ci_runner_machine_build, class: 'Ci::RunnerManagerBuild' do + build factory: :ci_build, scheduling_type: :dag + runner_manager factory: :ci_runner_machine + end +end diff --git a/spec/factories/ci/runner_machines.rb b/spec/factories/ci/runner_machines.rb deleted file mode 100644 index 9d601caa634..00000000000 --- a/spec/factories/ci/runner_machines.rb +++ /dev/null @@ -1,13 +0,0 @@ -# frozen_string_literal: true - -FactoryBot.define do - factory :ci_runner_machine, class: 'Ci::RunnerMachine' do - runner factory: :ci_runner - system_xid { "r_#{SecureRandom.hex.slice(0, 10)}" } - - trait :stale do - created_at { 1.year.ago } - contacted_at { Ci::RunnerMachine::STALE_TIMEOUT.ago } - end - end -end diff --git a/spec/factories/ci/runner_managers.rb b/spec/factories/ci/runner_managers.rb new file mode 100644 index 00000000000..7a2b0c37215 --- /dev/null +++ b/spec/factories/ci/runner_managers.rb @@ -0,0 +1,13 @@ +# frozen_string_literal: true + +FactoryBot.define do + factory :ci_runner_machine, class: 'Ci::RunnerManager' do + runner factory: :ci_runner + system_xid { "r_#{SecureRandom.hex.slice(0, 10)}" } + + trait :stale do + created_at { 1.year.ago } + contacted_at { Ci::RunnerManager::STALE_TIMEOUT.ago } + end + end +end diff --git a/spec/factories/ci/runners.rb b/spec/factories/ci/runners.rb index 4758986b47c..f001cecd28e 100644 --- a/spec/factories/ci/runners.rb +++ b/spec/factories/ci/runners.rb @@ -66,6 +66,12 @@ FactoryBot.define do end end + trait :with_runner_manager do + after(:build) do |runner, evaluator| + runner.runner_managers << build(:ci_runner_machine, runner: runner) + end + end + trait :inactive do active { false } end diff --git a/spec/factories/clusters/agents/authorizations/ci_access/group_authorizations.rb b/spec/factories/clusters/agents/authorizations/ci_access/group_authorizations.rb new file mode 100644 index 00000000000..659114eef8e --- /dev/null +++ b/spec/factories/clusters/agents/authorizations/ci_access/group_authorizations.rb @@ -0,0 +1,18 @@ +# frozen_string_literal: true + +FactoryBot.define do + factory :agent_ci_access_group_authorization, class: 'Clusters::Agents::Authorizations::CiAccess::GroupAuthorization' do + association :agent, factory: :cluster_agent + group + + transient do + environments { nil } + end + + config do + { default_namespace: 'production' }.tap do |c| + c[:environments] = environments if environments + end + end + end +end diff --git a/spec/factories/clusters/agents/authorizations/ci_access/project_authorizations.rb b/spec/factories/clusters/agents/authorizations/ci_access/project_authorizations.rb new file mode 100644 index 00000000000..10d4f8fb946 --- /dev/null +++ b/spec/factories/clusters/agents/authorizations/ci_access/project_authorizations.rb @@ -0,0 +1,18 @@ +# frozen_string_literal: true + +FactoryBot.define do + factory :agent_ci_access_project_authorization, class: 'Clusters::Agents::Authorizations::CiAccess::ProjectAuthorization' do + association :agent, factory: :cluster_agent + project + + transient do + environments { nil } + end + + config do + { default_namespace: 'production' }.tap do |c| + c[:environments] = environments if environments + end + end + end +end diff --git a/spec/factories/clusters/agents/authorizations/user_access/group_authorizations.rb b/spec/factories/clusters/agents/authorizations/user_access/group_authorizations.rb new file mode 100644 index 00000000000..203aadbd741 --- /dev/null +++ b/spec/factories/clusters/agents/authorizations/user_access/group_authorizations.rb @@ -0,0 +1,10 @@ +# frozen_string_literal: true + +FactoryBot.define do + factory :agent_user_access_group_authorization, + class: 'Clusters::Agents::Authorizations::UserAccess::GroupAuthorization' do + association :agent, factory: :cluster_agent + config { {} } + group + end +end diff --git a/spec/factories/clusters/agents/authorizations/user_access/project_authorizations.rb b/spec/factories/clusters/agents/authorizations/user_access/project_authorizations.rb new file mode 100644 index 00000000000..8171607f578 --- /dev/null +++ b/spec/factories/clusters/agents/authorizations/user_access/project_authorizations.rb @@ -0,0 +1,10 @@ +# frozen_string_literal: true + +FactoryBot.define do + factory :agent_user_access_project_authorization, + class: 'Clusters::Agents::Authorizations::UserAccess::ProjectAuthorization' do + association :agent, factory: :cluster_agent + config { {} } + project + end +end diff --git a/spec/factories/clusters/agents/group_authorizations.rb b/spec/factories/clusters/agents/group_authorizations.rb deleted file mode 100644 index abe25794234..00000000000 --- a/spec/factories/clusters/agents/group_authorizations.rb +++ /dev/null @@ -1,18 +0,0 @@ -# frozen_string_literal: true - -FactoryBot.define do - factory :agent_group_authorization, class: 'Clusters::Agents::GroupAuthorization' do - association :agent, factory: :cluster_agent - group - - transient do - environments { nil } - end - - config do - { default_namespace: 'production' }.tap do |c| - c[:environments] = environments if environments - end - end - end -end diff --git a/spec/factories/clusters/agents/project_authorizations.rb b/spec/factories/clusters/agents/project_authorizations.rb deleted file mode 100644 index eecbfe95bfc..00000000000 --- a/spec/factories/clusters/agents/project_authorizations.rb +++ /dev/null @@ -1,18 +0,0 @@ -# frozen_string_literal: true - -FactoryBot.define do - factory :agent_project_authorization, class: 'Clusters::Agents::ProjectAuthorization' do - association :agent, factory: :cluster_agent - project - - transient do - environments { nil } - end - - config do - { default_namespace: 'production' }.tap do |c| - c[:environments] = environments if environments - end - end - end -end diff --git a/spec/factories/clusters/applications/helm.rb b/spec/factories/clusters/applications/helm.rb deleted file mode 100644 index 0647058d63a..00000000000 --- a/spec/factories/clusters/applications/helm.rb +++ /dev/null @@ -1,124 +0,0 @@ -# frozen_string_literal: true - -FactoryBot.define do - factory :clusters_applications_helm, class: 'Clusters::Applications::Helm' do - cluster factory: %i(cluster provided_by_gcp) - - transient do - helm_installed { true } - end - - before(:create) do |_record, evaluator| - if evaluator.helm_installed - stub_method(Gitlab::Kubernetes::Helm::V2::Certificate, :generate_root) do - OpenStruct.new( # rubocop: disable Style/OpenStructUse - key_string: File.read(Rails.root.join('spec/fixtures/clusters/sample_key.key')), - cert_string: File.read(Rails.root.join('spec/fixtures/clusters/sample_cert.pem')) - ) - end - end - end - - after(:create) do |_record, evaluator| - if evaluator.helm_installed - restore_original_methods(Gitlab::Kubernetes::Helm::V2::Certificate) - end - end - - trait :not_installable do - status { -2 } - end - - trait :errored do - status { -1 } - status_reason { 'something went wrong' } - end - - trait :installable do - status { 0 } - end - - trait :scheduled do - status { 1 } - end - - trait :installing do - status { 2 } - end - - trait :installed do - status { 3 } - end - - trait :updating do - status { 4 } - end - - trait :updated do - status { 5 } - end - - trait :update_errored do - status { 6 } - status_reason { 'something went wrong' } - end - - trait :uninstalling do - status { 7 } - end - - trait :uninstall_errored do - status { 8 } - status_reason { 'something went wrong' } - end - - trait :uninstalled do - status { 10 } - end - - trait :externally_installed do - status { 11 } - end - - trait :timed_out do - installing - updated_at { ClusterWaitForAppInstallationWorker::TIMEOUT.ago } - end - - # Common trait used by the apps below - trait :no_helm_installed do - cluster factory: %i(cluster provided_by_gcp) - - transient do - helm_installed { false } - end - end - - factory :clusters_applications_ingress, class: 'Clusters::Applications::Ingress' do - cluster factory: %i(cluster with_installed_helm provided_by_gcp) - end - - factory :clusters_applications_crossplane, class: 'Clusters::Applications::Crossplane' do - stack { 'gcp' } - cluster factory: %i(cluster with_installed_helm provided_by_gcp) - end - - factory :clusters_applications_prometheus, class: 'Clusters::Applications::Prometheus' do - cluster factory: %i(cluster with_installed_helm provided_by_gcp) - end - - factory :clusters_applications_runner, class: 'Clusters::Applications::Runner' do - cluster factory: %i(cluster with_installed_helm provided_by_gcp) - end - - factory :clusters_applications_knative, class: 'Clusters::Applications::Knative' do - hostname { 'example.com' } - cluster factory: %i(cluster with_installed_helm provided_by_gcp) - end - - factory :clusters_applications_jupyter, class: 'Clusters::Applications::Jupyter' do - oauth_application factory: :oauth_application - cluster factory: %i(cluster with_installed_helm provided_by_gcp project) - end - end -end diff --git a/spec/factories/clusters/clusters.rb b/spec/factories/clusters/clusters.rb index 32cd6beb7ea..2785a8c9946 100644 --- a/spec/factories/clusters/clusters.rb +++ b/spec/factories/clusters/clusters.rb @@ -82,25 +82,10 @@ FactoryBot.define do sequence(:environment_scope) { |n| "production#{n}/*" } end - trait :with_installed_helm do - application_helm factory: %i(clusters_applications_helm installed) - end - trait :with_installed_prometheus do - application_prometheus factory: %i(clusters_applications_prometheus installed) integration_prometheus factory: %i(clusters_integrations_prometheus) end - trait :with_all_applications do - application_helm factory: %i(clusters_applications_helm installed) - application_ingress factory: %i(clusters_applications_ingress installed) - application_crossplane factory: %i(clusters_applications_crossplane installed) - application_prometheus factory: %i(clusters_applications_prometheus installed) - application_runner factory: %i(clusters_applications_runner installed) - application_jupyter factory: %i(clusters_applications_jupyter installed) - application_knative factory: %i(clusters_applications_knative installed) - end - trait :with_domain do domain { 'example.com' } end diff --git a/spec/factories/container_registry/data_repair_detail.rb b/spec/factories/container_registry/data_repair_detail.rb new file mode 100644 index 00000000000..79467c464db --- /dev/null +++ b/spec/factories/container_registry/data_repair_detail.rb @@ -0,0 +1,20 @@ +# frozen_string_literal: true + +FactoryBot.define do + factory :container_registry_data_repair_detail, class: 'ContainerRegistry::DataRepairDetail' do + project + updated_at { 1.hour.ago } + + trait :ongoing do + status { :ongoing } + end + + trait :completed do + status { :completed } + end + + trait :failed do + status { :failed } + end + end +end diff --git a/spec/factories/customer_relations/contacts.rb b/spec/factories/customer_relations/contacts.rb index 1896510d362..6410e298bc3 100644 --- a/spec/factories/customer_relations/contacts.rb +++ b/spec/factories/customer_relations/contacts.rb @@ -8,10 +8,6 @@ FactoryBot.define do last_name { generate(:name) } email { generate(:email) } - trait :with_organization do - organization - end - trait :inactive do state { :inactive } end diff --git a/spec/factories/customer_relations/organizations.rb b/spec/factories/customer_relations/organizations.rb index b6efd46f1a4..789099190ac 100644 --- a/spec/factories/customer_relations/organizations.rb +++ b/spec/factories/customer_relations/organizations.rb @@ -1,7 +1,7 @@ # frozen_string_literal: true FactoryBot.define do - factory :organization, class: 'CustomerRelations::Organization' do + factory :crm_organization, class: 'CustomerRelations::Organization' do group name { generate(:name) } diff --git a/spec/factories/design_management/repositories.rb b/spec/factories/design_management/repositories.rb new file mode 100644 index 00000000000..d903fd88c13 --- /dev/null +++ b/spec/factories/design_management/repositories.rb @@ -0,0 +1,7 @@ +# frozen_string_literal: true + +FactoryBot.define do + factory :design_management_repository, class: 'DesignManagement::Repository' do + project + end +end diff --git a/spec/factories/draft_note.rb b/spec/factories/draft_note.rb index cde8831f169..8433271a3c5 100644 --- a/spec/factories/draft_note.rb +++ b/spec/factories/draft_note.rb @@ -28,9 +28,7 @@ FactoryBot.define do end position do - association(:image_diff_position, - file: path, - diff_refs: diff_refs) + association(:image_diff_position, file: path, diff_refs: diff_refs) end end end diff --git a/spec/factories/environments.rb b/spec/factories/environments.rb index 34843dab0fe..2df9f482bb9 100644 --- a/spec/factories/environments.rb +++ b/spec/factories/environments.rb @@ -46,20 +46,19 @@ FactoryBot.define do after(:create) do |environment, evaluator| pipeline = create(:ci_pipeline, project: environment.project) - deployable = create(:ci_build, :success, name: "#{environment.name}:deploy", - pipeline: pipeline) - - deployment = create(:deployment, - :success, - environment: environment, - project: environment.project, - deployable: deployable, - ref: evaluator.ref, - sha: environment.project.commit(evaluator.ref).id) - - teardown_build = create(:ci_build, :manual, - name: "#{environment.name}:teardown", - pipeline: pipeline) + deployable = create(:ci_build, :success, name: "#{environment.name}:deploy", pipeline: pipeline) + + deployment = create( + :deployment, + :success, + environment: environment, + project: environment.project, + deployable: deployable, + ref: evaluator.ref, + sha: environment.project.commit(evaluator.ref).id + ) + + teardown_build = create(:ci_build, :manual, name: "#{environment.name}:teardown", pipeline: pipeline) deployment.update_column(:on_stop, teardown_build.name) environment.update_attribute(:deployments, [deployment]) diff --git a/spec/factories/gitlab/database/async_foreign_keys/postgres_async_constraint_validation.rb b/spec/factories/gitlab/database/async_foreign_keys/postgres_async_constraint_validation.rb new file mode 100644 index 00000000000..81f67e958c0 --- /dev/null +++ b/spec/factories/gitlab/database/async_foreign_keys/postgres_async_constraint_validation.rb @@ -0,0 +1,17 @@ +# frozen_string_literal: true + +FactoryBot.define do + factory :postgres_async_constraint_validation, + class: 'Gitlab::Database::AsyncConstraints::PostgresAsyncConstraintValidation' do + sequence(:name) { |n| "fk_users_id_#{n}" } + table_name { "users" } + + trait :foreign_key do + constraint_type { :foreign_key } + end + + trait :check_constraint do + constraint_type { :check_constraint } + end + end +end diff --git a/spec/factories/gitlab/database/async_foreign_keys/postgres_async_foreign_key_validation.rb b/spec/factories/gitlab/database/async_foreign_keys/postgres_async_foreign_key_validation.rb deleted file mode 100644 index a61b5cde7a0..00000000000 --- a/spec/factories/gitlab/database/async_foreign_keys/postgres_async_foreign_key_validation.rb +++ /dev/null @@ -1,9 +0,0 @@ -# frozen_string_literal: true - -FactoryBot.define do - factory :postgres_async_foreign_key_validation, - class: 'Gitlab::Database::AsyncForeignKeys::PostgresAsyncForeignKeyValidation' do - sequence(:name) { |n| "fk_users_id_#{n}" } - table_name { "users" } - end -end diff --git a/spec/factories/gitlab/database/background_migration/schema_inconsistencies.rb b/spec/factories/gitlab/database/background_migration/schema_inconsistencies.rb new file mode 100644 index 00000000000..b71b0971417 --- /dev/null +++ b/spec/factories/gitlab/database/background_migration/schema_inconsistencies.rb @@ -0,0 +1,11 @@ +# frozen_string_literal: true + +FactoryBot.define do + factory :schema_inconsistency, class: '::Gitlab::Database::SchemaValidation::SchemaInconsistency' do + issue factory: :issue + + object_name { 'name' } + table_name { 'table' } + valitador_name { 'validator' } + end +end diff --git a/spec/factories/group_members.rb b/spec/factories/group_members.rb index 702db45554e..e1841745cb4 100644 --- a/spec/factories/group_members.rb +++ b/spec/factories/group_members.rb @@ -30,6 +30,12 @@ FactoryBot.define do after(:build) { |group_member, _| group_member.user.block! } end + trait :banned do + after(:create) do |member| + create(:namespace_ban, namespace: member.member_namespace.root_ancestor, user: member.user) unless member.owner? + end + end + trait :minimal_access do to_create { |instance| instance.save!(validate: false) } @@ -54,10 +60,12 @@ FactoryBot.define do after(:build) do |group_member, evaluator| if evaluator.tasks_to_be_done.present? - build(:member_task, - member: group_member, - project: build(:project, namespace: group_member.source), - tasks_to_be_done: evaluator.tasks_to_be_done) + build( + :member_task, + member: group_member, + project: build(:project, namespace: group_member.source), + tasks_to_be_done: evaluator.tasks_to_be_done + ) end end end diff --git a/spec/factories/import_failures.rb b/spec/factories/import_failures.rb index df0793664f4..b4a7c6c46b1 100644 --- a/spec/factories/import_failures.rb +++ b/spec/factories/import_failures.rb @@ -21,5 +21,9 @@ FactoryBot.define do trait :soft_failure do retry_count { 1 } end + + trait :github_import_failure do + external_identifiers { { iid: 2, object_type: 'pull_request', title: 'Implement cool feature' } } + end end end diff --git a/spec/factories/integrations.rb b/spec/factories/integrations.rb index 7740b2da911..10568d7f1cd 100644 --- a/spec/factories/integrations.rb +++ b/spec/factories/integrations.rb @@ -43,6 +43,29 @@ FactoryBot.define do end end + factory :gitlab_slack_application_integration, class: 'Integrations::GitlabSlackApplication' do + project + active { true } + type { 'Integrations::GitlabSlackApplication' } + slack_integration { association :slack_integration, integration: instance } + + transient do + all_channels { true } + end + + after(:build) do |integration, evaluator| + next unless evaluator.all_channels + + integration.event_channel_names.each do |name| + integration.send("#{name}=".to_sym, "##{name}") + end + end + + trait :all_features_supported do + slack_integration { association :slack_integration, :all_features_supported, integration: instance } + end + end + factory :packagist_integration, class: 'Integrations::Packagist' do project type { 'Integrations::Packagist' } @@ -85,9 +108,12 @@ FactoryBot.define do api_url { '' } username { 'jira_username' } password { 'jira_password' } + jira_auth_type { 0 } jira_issue_transition_automatic { false } jira_issue_transition_id { '56-1' } issues_enabled { false } + jira_issue_prefix { '' } + jira_issue_regex { '' } project_key { nil } vulnerabilities_enabled { false } vulnerabilities_issuetype { nil } @@ -98,6 +124,7 @@ FactoryBot.define do if evaluator.create_data integration.jira_tracker_data = build(:jira_tracker_data, integration: integration, url: evaluator.url, api_url: evaluator.api_url, + jira_auth_type: evaluator.jira_auth_type, jira_issue_transition_automatic: evaluator.jira_issue_transition_automatic, jira_issue_transition_id: evaluator.jira_issue_transition_id, username: evaluator.username, password: evaluator.password, issues_enabled: evaluator.issues_enabled, @@ -199,6 +226,7 @@ FactoryBot.define do url { 'https://mysite.atlassian.net' } username { 'jira_user' } password { 'my-secret-password' } + jira_auth_type { 0 } end trait :chat_notification do @@ -261,7 +289,27 @@ FactoryBot.define do app_store_issuer_id { 'aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee' } app_store_key_id { 'ABC1' } - app_store_private_key { File.read('spec/fixtures/ssl_key.pem') } + app_store_private_key_file_name { 'auth_key.p8' } + app_store_private_key { File.read('spec/fixtures/auth_key.p8') } + end + + factory :google_play_integration, class: 'Integrations::GooglePlay' do + project + active { true } + type { 'Integrations::GooglePlay' } + + package_name { 'com.gitlab.foo.bar' } + service_account_key_file_name { 'service_account.json' } + service_account_key { File.read('spec/fixtures/service_account.json') } + end + + factory :squash_tm_integration, class: 'Integrations::SquashTm' do + project + active { true } + type { 'Integrations::SquashTm' } + + url { 'https://url-to-squash.com' } + token { 'squash_tm_token' } end # this is for testing storing values inside properties, which is deprecated and will be removed in diff --git a/spec/factories/issues.rb b/spec/factories/issues.rb index 70a4a3ec822..67824a10288 100644 --- a/spec/factories/issues.rb +++ b/spec/factories/issues.rb @@ -66,6 +66,11 @@ FactoryBot.define do end end + trait :requirement do + issue_type { :requirement } + association :work_item_type, :default, :requirement + end + trait :task do issue_type { :task } association :work_item_type, :default, :task @@ -81,6 +86,16 @@ FactoryBot.define do association :work_item_type, :default, :key_result end + trait :incident do + issue_type { :incident } + association :work_item_type, :default, :incident + end + + trait :test_case do + issue_type { :test_case } + association :work_item_type, :default, :test_case + end + factory :incident do issue_type { :incident } association :work_item_type, :default, :incident diff --git a/spec/factories/member_roles.rb b/spec/factories/member_roles.rb deleted file mode 100644 index 503438d2521..00000000000 --- a/spec/factories/member_roles.rb +++ /dev/null @@ -1,11 +0,0 @@ -# frozen_string_literal: true - -FactoryBot.define do - factory :member_role do - namespace { association(:group) } - base_access_level { Gitlab::Access::DEVELOPER } - - trait(:developer) { base_access_level { Gitlab::Access::DEVELOPER } } - trait(:guest) { base_access_level { Gitlab::Access::GUEST } } - end -end diff --git a/spec/factories/merge_requests_diff_llm_summary.rb b/spec/factories/merge_requests_diff_llm_summary.rb new file mode 100644 index 00000000000..c72ce97efcb --- /dev/null +++ b/spec/factories/merge_requests_diff_llm_summary.rb @@ -0,0 +1,10 @@ +# frozen_string_literal: true + +FactoryBot.define do + factory :merge_request_diff_llm_summary, class: 'MergeRequest::DiffLlmSummary' do + association :user, factory: :user + association :merge_request_diff, factory: :merge_request_diff + provider { 0 } + content { 'test' } + end +end diff --git a/spec/factories/ml/candidates.rb b/spec/factories/ml/candidates.rb index 1b41e39d711..b9a2320138a 100644 --- a/spec/factories/ml/candidates.rb +++ b/spec/factories/ml/candidates.rb @@ -1,9 +1,11 @@ # frozen_string_literal: true FactoryBot.define do factory :ml_candidates, class: '::Ml::Candidate' do - association :experiment, factory: :ml_experiments + association :project, factory: :project association :user + experiment { association :ml_experiments, project_id: project.id } + trait :with_metrics_and_params do after(:create) do |candidate| candidate.metrics = FactoryBot.create_list(:ml_candidate_metrics, 2, candidate: candidate ) @@ -19,10 +21,12 @@ FactoryBot.define do trait :with_artifact do after(:create) do |candidate| - FactoryBot.create(:generic_package, - name: candidate.package_name, - version: candidate.package_version, - project: candidate.project) + candidate.package = FactoryBot.create( + :generic_package, + name: candidate.package_name, + version: candidate.package_version, + project: candidate.project + ) end end end diff --git a/spec/factories/notes.rb b/spec/factories/notes.rb index 530b4616765..b1e7866f9ce 100644 --- a/spec/factories/notes.rb +++ b/spec/factories/notes.rb @@ -12,6 +12,7 @@ FactoryBot.define do factory :note_on_commit, traits: [:on_commit] factory :note_on_issue, traits: [:on_issue], aliases: [:votable_note] + factory :note_on_work_item, traits: [:on_work_item] factory :note_on_merge_request, traits: [:on_merge_request] factory :note_on_project_snippet, traits: [:on_project_snippet] factory :note_on_personal_snippet, traits: [:on_personal_snippet] @@ -54,28 +55,34 @@ FactoryBot.define do end position do - association(:text_diff_position, - file: "files/ruby/popen.rb", - old_line: nil, - new_line: line_number, - diff_refs: diff_refs) + association( + :text_diff_position, + file: "files/ruby/popen.rb", + old_line: nil, + new_line: line_number, + diff_refs: diff_refs + ) end trait :folded_position do position do - association(:text_diff_position, - file: "files/ruby/popen.rb", - old_line: 1, - new_line: 1, - diff_refs: diff_refs) + association( + :text_diff_position, + file: "files/ruby/popen.rb", + old_line: 1, + new_line: 1, + diff_refs: diff_refs + ) end end factory :image_diff_note_on_merge_request do position do - association(:image_diff_position, - file: "files/images/any_image.png", - diff_refs: diff_refs) + association( + :image_diff_position, + file: "files/images/any_image.png", + diff_refs: diff_refs + ) end end end @@ -100,9 +107,11 @@ FactoryBot.define do factory :diff_note_on_design, parent: :note, traits: [:on_design], class: 'DiffNote' do position do - association(:image_diff_position, - file: noteable.full_path, - diff_refs: noteable.diff_refs) + association( + :image_diff_position, + file: noteable.full_path, + diff_refs: noteable.diff_refs + ) end end @@ -122,6 +131,10 @@ FactoryBot.define do noteable { association(:issue, project: project) } end + trait :on_work_item do + noteable { association(:work_item, project: project) } + end + trait :on_merge_request do noteable { association(:merge_request, source_project: project) } end @@ -191,6 +204,10 @@ FactoryBot.define do confidential { true } end + trait :internal do + internal { true } + end + trait :with_review do review end diff --git a/spec/factories/notes/notes_metadata.rb b/spec/factories/notes/notes_metadata.rb new file mode 100644 index 00000000000..555debbc0e5 --- /dev/null +++ b/spec/factories/notes/notes_metadata.rb @@ -0,0 +1,8 @@ +# frozen_string_literal: true + +FactoryBot.define do + factory :note_metadata, class: 'Notes::NoteMetadata' do + note + email_participant { 'email@example.com' } + end +end diff --git a/spec/factories/organizations.rb b/spec/factories/organizations.rb new file mode 100644 index 00000000000..7ff0493d140 --- /dev/null +++ b/spec/factories/organizations.rb @@ -0,0 +1,16 @@ +# frozen_string_literal: true + +FactoryBot.define do + factory :organization do + sequence(:name) { |n| "Organization ##{n}" } + + trait :default do + id { Organization::DEFAULT_ORGANIZATION_ID } + name { 'Default' } + initialize_with do + # Ensure we only use one default organization + Organization.find_by(id: Organization::DEFAULT_ORGANIZATION_ID) || new(**attributes) + end + end + end +end diff --git a/spec/factories/packages/debian/component_file.rb b/spec/factories/packages/debian/component_file.rb index a2422e4a126..0a134ee16c4 100644 --- a/spec/factories/packages/debian/component_file.rb +++ b/spec/factories/packages/debian/component_file.rb @@ -20,7 +20,6 @@ FactoryBot.define do component_file.file = fixture_file_upload(evaluator.file_fixture) if evaluator.file_fixture.present? end - file_md5 { '12345abcde' } file_sha256 { 'be93151dc23ac34a82752444556fe79b32c7a1ad' } trait(:packages) do @@ -47,5 +46,11 @@ FactoryBot.define do trait(:object_storage) do file_store { Packages::PackageFileUploader::Store::REMOTE } end + + trait(:empty) do + file_sha256 { 'e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855' } + file_fixture { nil } + size { 0 } + end end end diff --git a/spec/factories/packages/debian/distribution.rb b/spec/factories/packages/debian/distribution.rb index 48892d16efb..7a9d8561a9c 100644 --- a/spec/factories/packages/debian/distribution.rb +++ b/spec/factories/packages/debian/distribution.rb @@ -4,14 +4,14 @@ FactoryBot.define do factory :debian_project_distribution, class: 'Packages::Debian::ProjectDistribution' do container { association(:project) } - sequence(:codename) { |n| "#{FFaker::Lorem.word}#{n}" } + sequence(:codename) { |n| "codename-#{n}" } factory :debian_group_distribution, class: 'Packages::Debian::GroupDistribution' do container { association(:group) } end trait(:with_suite) do - sequence(:suite) { |n| "#{FFaker::Lorem.word}#{n}" } + sequence(:suite) { |n| "suite-#{n}" } end trait(:with_file) do @@ -24,7 +24,7 @@ FactoryBot.define do FILESIGNATURE end - after(:build) do |distribution, evaluator| + after(:build) do |distribution, _evaluator| distribution.file = fixture_file_upload('spec/fixtures/packages/debian/distribution/Release') distribution.signed_file = fixture_file_upload('spec/fixtures/packages/debian/distribution/InRelease') end diff --git a/spec/factories/packages/debian/file_metadatum.rb b/spec/factories/packages/debian/file_metadatum.rb index 505b9975f79..6b6cd9c51f3 100644 --- a/spec/factories/packages/debian/file_metadatum.rb +++ b/spec/factories/packages/debian/file_metadatum.rb @@ -2,11 +2,18 @@ FactoryBot.define do factory :debian_file_metadatum, class: 'Packages::Debian::FileMetadatum' do - package_file { association(:debian_package_file, without_loaded_metadatum: true) } + package_file do + if file_type == 'unknown' + association(:debian_package_file, :unknown, without_loaded_metadatum: true) + else + association(:debian_package_file, without_loaded_metadatum: true) + end + end + file_type { 'deb' } component { 'main' } architecture { 'amd64' } - fields { { 'a': 'b' } } + fields { { 'a' => 'b' } } trait(:unknown) do file_type { 'unknown' } @@ -30,21 +37,23 @@ FactoryBot.define do { 'Format' => '3.0 (native)', 'Source' => package_file.package.name, - 'Binary' => 'sample-dev, libsample0, sample-udeb', + 'Binary' => 'sample-dev, libsample0, sample-udeb, sample-ddeb', 'Architecture' => 'any', - 'Version': package_file.package.version, + 'Version' => package_file.package.version, 'Maintainer' => "#{FFaker::Name.name} <#{FFaker::Internet.email}>", 'Homepage' => FFaker::Internet.http_url, 'Standards-Version' => '4.5.0', 'Build-Depends' => 'debhelper-compat (= 13)', - 'Package-List' => <<~EOF.rstrip, - libsample0 deb libs optional arch=any', - sample-dev deb libdevel optional arch=any', - sample-udeb udeb libs optional arch=any', - EOF - 'Checksums-Sha1' => "\nc5cfc111ea924842a89a06d5673f07dfd07de8ca 864 sample_1.2.3~alpha2.tar.xz", - 'Checksums-Sha256' => "\n40e4682bb24a73251ccd7c7798c0094a649091e5625d6a14bcec9b4e7174f3da 864 sample_1.2.3~alpha2.tar.xz", - 'Files' => "\nd5ca476e4229d135a88f9c729c7606c9 864 sample_1.2.3~alpha2.tar.xz" + 'Package-List' => <<~PACKAGELIST.rstrip, + libsample0 deb libs optional arch=any + sample-ddeb deb libs optional arch=any + sample-dev deb libdevel optional arch=any + sample-udeb udeb libs optional arch=any + PACKAGELIST + 'Checksums-Sha1' => "\n4a9cb2a7c77a68dc0fe54ba8ecef133a7c949e9d 964 sample_1.2.3~alpha2.tar.xz", + 'Checksums-Sha256' => + "\nc9d05185ca158bb804977fa9d7b922e8a0f644a2da41f99d2787dd61b1e2e2c5 964 sample_1.2.3~alpha2.tar.xz", + 'Files' => "\nadc69e57cda38d9bb7c8d59cacfb6869 964 sample_1.2.3~alpha2.tar.xz" } end end @@ -55,22 +64,22 @@ FactoryBot.define do architecture { 'amd64' } fields do { - 'Package' => 'libsample0', - 'Source' => package_file.package.name, - 'Version' => package_file.package.version, - 'Architecture' => 'amd64', - 'Maintainer' => "#{FFaker::Name.name} <#{FFaker::Internet.email}>", - 'Installed-Size' => '7', - 'Section' => 'libs', - 'Priority' => 'optional', - 'Multi-Arch' => 'same', - 'Homepage' => FFaker::Internet.http_url, - 'Description' => <<~EOF.rstrip - Some mostly empty lib - Used in GitLab tests. + 'Package' => 'libsample0', + 'Source' => package_file.package.name, + 'Version' => package_file.package.version, + 'Architecture' => 'amd64', + 'Maintainer' => "#{FFaker::NameCN.name} #{FFaker::Name.name} <#{FFaker::Internet.email}>", + 'Installed-Size' => '7', + 'Section' => 'libs', + 'Priority' => 'optional', + 'Multi-Arch' => 'same', + 'Homepage' => FFaker::Internet.http_url, + 'Description' => <<~DESCRIPTION.rstrip + Some mostly empty lib + Used in GitLab tests. - Testing another paragraph. - EOF + Testing another paragraph. + DESCRIPTION } end end @@ -92,12 +101,12 @@ FactoryBot.define do 'Priority' => 'optional', 'Multi-Arch' => 'same', 'Homepage' => FFaker::Internet.http_url, - 'Description' => <<~EOF.rstrip + 'Description' => <<~DESCRIPTION.rstrip Some mostly empty development files Used in GitLab tests. Testing another paragraph. - EOF + DESCRIPTION } end end @@ -106,21 +115,28 @@ FactoryBot.define do file_type { 'udeb' } component { 'main' } architecture { 'amd64' } - fields { { 'a': 'b' } } + fields { { 'a' => 'b' } } + end + + trait(:ddeb) do + file_type { 'ddeb' } + component { 'main' } + architecture { 'amd64' } + fields { { 'a' => 'b' } } end trait(:buildinfo) do file_type { 'buildinfo' } component { 'main' } architecture { nil } - fields { { 'Architecture': 'amd64 source' } } + fields { { 'Architecture' => 'amd64 source' } } end trait(:changes) do file_type { 'changes' } component { nil } architecture { nil } - fields { { 'Architecture': 'source amd64' } } + fields { { 'Architecture' => 'source amd64' } } end end end diff --git a/spec/factories/packages/npm/metadata_cache.rb b/spec/factories/packages/npm/metadata_cache.rb new file mode 100644 index 00000000000..e76ddf3c983 --- /dev/null +++ b/spec/factories/packages/npm/metadata_cache.rb @@ -0,0 +1,10 @@ +# frozen_string_literal: true + +FactoryBot.define do + factory :npm_metadata_cache, class: 'Packages::Npm::MetadataCache' do + project + sequence(:package_name) { |n| "@#{project.root_namespace.path}/package-#{n}" } + file { fixture_file_upload('spec/fixtures/packages/npm/metadata.json') } + size { 401.bytes } + end +end diff --git a/spec/factories/packages/package_files.rb b/spec/factories/packages/package_files.rb index 7d3dd274777..4a2d412832c 100644 --- a/spec/factories/packages/package_files.rb +++ b/spec/factories/packages/package_files.rb @@ -131,9 +131,9 @@ FactoryBot.define do trait(:source) do file_name { 'sample_1.2.3~alpha2.tar.xz' } - file_md5 { 'd5ca476e4229d135a88f9c729c7606c9' } - file_sha1 { 'c5cfc111ea924842a89a06d5673f07dfd07de8ca' } - file_sha256 { '40e4682bb24a73251ccd7c7798c0094a649091e5625d6a14bcec9b4e7174f3da' } + file_md5 { 'adc69e57cda38d9bb7c8d59cacfb6869' } + file_sha1 { '4a9cb2a7c77a68dc0fe54ba8ecef133a7c949e9d' } + file_sha256 { 'c9d05185ca158bb804977fa9d7b922e8a0f644a2da41f99d2787dd61b1e2e2c5' } transient do file_metadatum_trait { :source } @@ -142,9 +142,9 @@ FactoryBot.define do trait(:dsc) do file_name { 'sample_1.2.3~alpha2.dsc' } - file_md5 { 'ceccb6bb3e45ce6550b24234d4023e0f' } - file_sha1 { '375ba20ea1789e1e90d469c3454ce49a431d0442' } - file_sha256 { '81fc156ba937cdb6215362cc4bf6b8dc47be9b4253ba0f1a4ab10c7ea0c4c4e5' } + file_md5 { '629921cfc477bfa84adfd2ccaba89783' } + file_sha1 { '443c98a4cf4acd21e2259ae8f2d60fc9932de353' } + file_sha256 { 'f91070524a59bbb3a1f05a78409e92cb9ee86470b34018bc0b93bd5b2dd3868c' } transient do file_metadatum_trait { :dsc } @@ -184,11 +184,22 @@ FactoryBot.define do end end + trait(:ddeb) do + file_name { 'sample-ddeb_1.2.3~alpha2_amd64.ddeb' } + file_md5 { '90d1107471eed48c73ad78b19ac83639' } + file_sha1 { '9c5af97cf8dfbe8126c807f540c88757f382b307' } + file_sha256 { 'a6bcc8a4b010f99ce0ea566ac69088e1910e754593c77f2b4942e3473e784e4d' } + + transient do + file_metadatum_trait { :ddeb } + end + end + trait(:buildinfo) do file_name { 'sample_1.2.3~alpha2_amd64.buildinfo' } - file_md5 { '12a5ac4f16ad75f8741327ac23b4c0d7' } - file_sha1 { '661f7507efa6fdd3763c95581d0baadb978b7ef5' } - file_sha256 { 'd0c169e9caa5b303a914b27b5adf69768fe6687d4925905b7d0cd9c0f9d4e56c' } + file_md5 { 'cc07ff4d741aec132816f9bd67c6875d' } + file_sha1 { 'bcc4ca85f17a31066b726cd4e04485ab24a682c6' } + file_sha256 { '5a3dac17c4ff0d49fa5f47baa973902b59ad2ee05147062b8ed8f19d196731d1' } transient do file_metadatum_trait { :buildinfo } @@ -204,6 +215,7 @@ FactoryBot.define do end trait(:keep) do + # do not override attributes end end diff --git a/spec/factories/packages/packages.rb b/spec/factories/packages/packages.rb index d0fde0a16cd..283df3428db 100644 --- a/spec/factories/packages/packages.rb +++ b/spec/factories/packages/packages.rb @@ -78,19 +78,24 @@ FactoryBot.define do after :build do |package, evaluator| if evaluator.published_in == :create - create(:debian_publication, package: package) + build(:debian_publication, package: package) elsif !evaluator.published_in.nil? create(:debian_publication, package: package, distribution: evaluator.published_in) end end after :create do |package, evaluator| + if evaluator.published_in == :create + package.debian_publication.save! + end + unless evaluator.without_package_files create :debian_package_file, :source, evaluator.file_metadatum_trait, package: package create :debian_package_file, :dsc, evaluator.file_metadatum_trait, package: package create :debian_package_file, :deb, evaluator.file_metadatum_trait, package: package create :debian_package_file, :deb_dev, evaluator.file_metadatum_trait, package: package create :debian_package_file, :udeb, evaluator.file_metadatum_trait, package: package + create :debian_package_file, :ddeb, evaluator.file_metadatum_trait, package: package create :debian_package_file, :buildinfo, evaluator.file_metadatum_trait, package: package create :debian_package_file, :changes, evaluator.file_metadatum_trait, package: package end diff --git a/spec/factories/project_error_tracking_settings.rb b/spec/factories/project_error_tracking_settings.rb index a8ad1af6345..dc0277cb58d 100644 --- a/spec/factories/project_error_tracking_settings.rb +++ b/spec/factories/project_error_tracking_settings.rb @@ -16,7 +16,12 @@ FactoryBot.define do end trait :integrated do + api_url { nil } integrated { true } + token { nil } + project_name { nil } + organization_name { nil } + sentry_project_id { nil } end end end diff --git a/spec/factories/project_hooks.rb b/spec/factories/project_hooks.rb index d84e287d765..3e70b897df6 100644 --- a/spec/factories/project_hooks.rb +++ b/spec/factories/project_hooks.rb @@ -35,7 +35,7 @@ FactoryBot.define do end trait :permanently_disabled do - recent_failures { WebHook::FAILURE_THRESHOLD + 1 } + recent_failures { WebHooks::AutoDisabling::FAILURE_THRESHOLD + 1 } end end end diff --git a/spec/factories/project_members.rb b/spec/factories/project_members.rb index 57f228650a1..fb62b2ed951 100644 --- a/spec/factories/project_members.rb +++ b/spec/factories/project_members.rb @@ -26,6 +26,12 @@ FactoryBot.define do after(:build) { |project_member, _| project_member.user.block! } end + trait :banned do + after(:create) do |member| + create(:namespace_ban, namespace: member.member_namespace.root_ancestor, user: member.user) unless member.owner? + end + end + trait :awaiting do after(:create) do |member| member.update!(state: ::Member::STATE_AWAITING) diff --git a/spec/factories/projects.rb b/spec/factories/projects.rb index f113ca2425f..856f0f6cd05 100644 --- a/spec/factories/projects.rb +++ b/spec/factories/projects.rb @@ -8,8 +8,8 @@ FactoryBot.define do # Project does not have bare repository. # Use this factory if you don't need repository in tests factory :project, class: 'Project' do - sequence(:name) { |n| "project#{n}" } - path { name.downcase.gsub(/\s/, '_') } + sequence(:path) { |n| "project-#{n}" } + name { "#{path.humanize} Name" } # Behaves differently to nil due to cache_has_external_* methods. has_external_issue_tracker { false } @@ -222,7 +222,7 @@ FactoryBot.define do # the transient `files` attribute. Each file will be created in its own # commit, operating against the master branch. So, the following call: # - # create(:project, :custom_repo, files: { 'foo/a.txt' => 'foo', 'b.txt' => bar' }) + # create(:project, :custom_repo, files: { 'foo/a.txt' => 'foo', 'b.txt' => 'bar' }) # # will create a repository containing two files, and two commits, in master trait :custom_repo do @@ -245,6 +245,19 @@ FactoryBot.define do end end + # A basic repository with a single file 'test.txt'. It also has the HEAD as the default branch. + trait :small_repo do + custom_repo + + files { { 'test.txt' => 'test' } } + + after(:create) do |project| + Sidekiq::Worker.skipping_transaction_check do + raise "Failed to assign the repository head!" unless project.change_head(project.default_branch_or_main) + end + end + end + # Test repository - https://gitlab.com/gitlab-org/gitlab-test trait :repository do test_repo @@ -354,6 +367,18 @@ FactoryBot.define do end end + trait :stubbed_commit_count do + after(:build) do |project| + stub_method(project.repository, :commit_count) { 2 } + end + end + + trait :stubbed_branch_count do + after(:build) do |project| + stub_method(project.repository, :branch_count) { 2 } + end + end + trait :wiki_repo do after(:create) do |project| stub_feature_flags(main_branch_over_master: false) @@ -510,4 +535,11 @@ FactoryBot.define do trait :in_subgroup do namespace factory: [:group, :nested] end + + trait :readme do + custom_repo + + path { 'gitlab-profile' } + files { { 'README.md' => 'Hello World' } } + end end diff --git a/spec/factories/projects/data_transfers.rb b/spec/factories/projects/data_transfers.rb index 4184f475663..3c335c876e4 100644 --- a/spec/factories/projects/data_transfers.rb +++ b/spec/factories/projects/data_transfers.rb @@ -5,5 +5,9 @@ FactoryBot.define do project factory: :project namespace { project.root_namespace } date { Time.current.utc.beginning_of_month } + repository_egress { 1 } + artifacts_egress { 2 } + packages_egress { 3 } + registry_egress { 4 } end end diff --git a/spec/factories/resource_events/abuse_report_events.rb b/spec/factories/resource_events/abuse_report_events.rb new file mode 100644 index 00000000000..0771a37f01b --- /dev/null +++ b/spec/factories/resource_events/abuse_report_events.rb @@ -0,0 +1,9 @@ +# frozen_string_literal: true + +FactoryBot.define do + factory :abuse_report_event, class: 'ResourceEvents::AbuseReportEvent' do + action { :ban_user } + abuse_report + user + end +end diff --git a/spec/factories/resource_events/issue_assignment_events.rb b/spec/factories/resource_events/issue_assignment_events.rb new file mode 100644 index 00000000000..72319905d0d --- /dev/null +++ b/spec/factories/resource_events/issue_assignment_events.rb @@ -0,0 +1,9 @@ +# frozen_string_literal: true + +FactoryBot.define do + factory :issue_assignment_event, class: 'ResourceEvents::IssueAssignmentEvent' do + action { :add } + issue + user + end +end diff --git a/spec/factories/resource_events/merge_request_assignment_events.rb b/spec/factories/resource_events/merge_request_assignment_events.rb new file mode 100644 index 00000000000..6d388543648 --- /dev/null +++ b/spec/factories/resource_events/merge_request_assignment_events.rb @@ -0,0 +1,9 @@ +# frozen_string_literal: true + +FactoryBot.define do + factory :merge_request_assignment_event, class: 'ResourceEvents::MergeRequestAssignmentEvent' do + action { :add } + merge_request + user + end +end diff --git a/spec/factories/search_index.rb b/spec/factories/search_index.rb new file mode 100644 index 00000000000..15d7024dbf1 --- /dev/null +++ b/spec/factories/search_index.rb @@ -0,0 +1,10 @@ +# frozen_string_literal: true + +FactoryBot.define do + factory :search_index, class: 'Search::Index' do + initialize_with { type.present? ? type.new : Search::Index.new } + sequence(:path) { |n| "index-path-#{n}" } + sequence(:bucket_number) { |n| n } + type { Search::NoteIndex } + end +end diff --git a/spec/factories/serverless/domain.rb b/spec/factories/serverless/domain.rb deleted file mode 100644 index c09af068d19..00000000000 --- a/spec/factories/serverless/domain.rb +++ /dev/null @@ -1,11 +0,0 @@ -# frozen_string_literal: true - -FactoryBot.define do - factory :serverless_domain, class: '::Serverless::Domain' do - function_name { 'test-function' } - serverless_domain_cluster { association(:serverless_domain_cluster) } - environment { association(:environment) } - - skip_create - end -end diff --git a/spec/factories/serverless/domain_cluster.rb b/spec/factories/serverless/domain_cluster.rb deleted file mode 100644 index e8ff6cf42b2..00000000000 --- a/spec/factories/serverless/domain_cluster.rb +++ /dev/null @@ -1,17 +0,0 @@ -# frozen_string_literal: true - -FactoryBot.define do - factory :serverless_domain_cluster, class: '::Serverless::DomainCluster' do - pages_domain { association(:pages_domain) } - knative { association(:clusters_applications_knative) } - creator { association(:user) } - - certificate do - File.read(Rails.root.join('spec/fixtures/', 'ssl_certificate.pem')) - end - - key do - File.read(Rails.root.join('spec/fixtures/', 'ssl_key.pem')) - end - end -end diff --git a/spec/factories/service_desk/custom_email_credential.rb b/spec/factories/service_desk/custom_email_credential.rb new file mode 100644 index 00000000000..da131dd8250 --- /dev/null +++ b/spec/factories/service_desk/custom_email_credential.rb @@ -0,0 +1,11 @@ +# frozen_string_literal: true + +FactoryBot.define do + factory :service_desk_custom_email_credential, class: '::ServiceDesk::CustomEmailCredential' do + project + smtp_address { "smtp.example.com" } + smtp_username { "text@example.com" } + smtp_port { 587 } + smtp_password { "supersecret" } + end +end diff --git a/spec/factories/service_desk/custom_email_verification.rb b/spec/factories/service_desk/custom_email_verification.rb new file mode 100644 index 00000000000..3f3a2ea570d --- /dev/null +++ b/spec/factories/service_desk/custom_email_verification.rb @@ -0,0 +1,11 @@ +# frozen_string_literal: true + +FactoryBot.define do + factory :service_desk_custom_email_verification, class: '::ServiceDesk::CustomEmailVerification' do + state { 'started' } + token { 'XXXXXXXXXXXX' } + project + triggerer factory: :user + triggered_at { Time.current } + end +end diff --git a/spec/factories/slack_integrations.rb b/spec/factories/slack_integrations.rb new file mode 100644 index 00000000000..a43ba8e7453 --- /dev/null +++ b/spec/factories/slack_integrations.rb @@ -0,0 +1,25 @@ +# frozen_string_literal: true + +FactoryBot.define do + factory :slack_integration do + sequence(:team_id) { |n| "T123#{n}" } + sequence(:user_id) { |n| "U123#{n}" } + sequence(:bot_user_id) { |n| "U123#{n}" } + sequence(:bot_access_token) { |n| OpenSSL::Digest::SHA256.hexdigest(n.to_s) } + sequence(:team_name) { |n| "team#{n}" } + sequence(:alias) { |n| "namespace#{n}/project_name#{n}" } + + integration { association :gitlab_slack_application_integration, slack_integration: instance } + + trait :legacy do + bot_user_id { nil } + bot_access_token { nil } + end + + trait :all_features_supported do + after(:build) do |slack_integration, _evaluator| + slack_integration.authorized_scope_names = %w[commands chat:write chat:write.public] + end + end + end +end diff --git a/spec/factories/u2f_registrations.rb b/spec/factories/u2f_registrations.rb deleted file mode 100644 index 40ad221415c..00000000000 --- a/spec/factories/u2f_registrations.rb +++ /dev/null @@ -1,12 +0,0 @@ -# frozen_string_literal: true - -FactoryBot.define do - factory :u2f_registration do - user - - certificate { FFaker::BaconIpsum.characters(728) } - key_handle { FFaker::BaconIpsum.characters(86) } - public_key { FFaker::BaconIpsum.characters(88) } - counter { 0 } - end -end diff --git a/spec/factories/users.rb b/spec/factories/users.rb index e641f925758..351583b7ef6 100644 --- a/spec/factories/users.rb +++ b/spec/factories/users.rb @@ -10,6 +10,7 @@ FactoryBot.define do confirmed_at { Time.now } confirmation_token { nil } can_create_group { true } + color_scheme_id { 1 } trait :admin do admin { true } @@ -59,6 +60,10 @@ FactoryBot.define do user_type { :project_bot } end + trait :service_account do + user_type { :service_account } + end + trait :migration_bot do user_type { :migration_bot } end @@ -67,6 +72,10 @@ FactoryBot.define do user_type { :security_bot } end + trait :llm_bot do + user_type { :llm_bot } + end + trait :external do external { true } end @@ -111,14 +120,6 @@ FactoryBot.define do end end - trait :two_factor_via_u2f do - transient { registrations_count { 5 } } - - after(:create) do |user, evaluator| - create_list(:u2f_registration, evaluator.registrations_count, user: user) - end - end - trait :two_factor_via_webauthn do transient { registrations_count { 5 } } diff --git a/spec/factories/users/banned_users.rb b/spec/factories/users/banned_users.rb new file mode 100644 index 00000000000..f2b6eb5893a --- /dev/null +++ b/spec/factories/users/banned_users.rb @@ -0,0 +1,7 @@ +# frozen_string_literal: true + +FactoryBot.define do + factory :banned_user, class: 'Users::BannedUser' do + user { association(:user) } + end +end diff --git a/spec/factories/work_items.rb b/spec/factories/work_items.rb index cff246d4071..10764457d84 100644 --- a/spec/factories/work_items.rb +++ b/spec/factories/work_items.rb @@ -14,6 +14,19 @@ FactoryBot.define do confidential { true } end + trait :opened do + state_id { WorkItem.available_states[:opened] } + end + + trait :locked do + discussion_locked { true } + end + + trait :closed do + state_id { WorkItem.available_states[:closed] } + closed_at { Time.now } + end + trait :task do issue_type { :task } association :work_item_type, :default, :task @@ -24,6 +37,16 @@ FactoryBot.define do association :work_item_type, :default, :incident end + trait :requirement do + issue_type { :requirement } + association :work_item_type, :default, :requirement + end + + trait :test_case do + issue_type { :test_case } + association :work_item_type, :default, :test_case + end + trait :last_edited_by_user do association :last_edited_by, factory: :user end @@ -37,5 +60,12 @@ FactoryBot.define do issue_type { :key_result } association :work_item_type, :default, :key_result end + + before(:create, :build) do |work_item, evaluator| + if evaluator.namespace.present? + work_item.project = nil + work_item.namespace = evaluator.namespace + end + end end end diff --git a/spec/factories/work_items/resource_link_events.rb b/spec/factories/work_items/resource_link_events.rb new file mode 100644 index 00000000000..696f6dcc43f --- /dev/null +++ b/spec/factories/work_items/resource_link_events.rb @@ -0,0 +1,10 @@ +# frozen_string_literal: true + +FactoryBot.define do + factory :resource_link_event, class: 'WorkItems::ResourceLinkEvent' do + action { :add } + issue { association(:issue) } + user { issue&.author || association(:user) } + child_work_item { association(:work_item, :task) } + end +end diff --git a/spec/fast_spec_helper.rb b/spec/fast_spec_helper.rb index 0df771b4025..fcf0c43243f 100644 --- a/spec/fast_spec_helper.rb +++ b/spec/fast_spec_helper.rb @@ -11,34 +11,24 @@ require_relative '../config/bundler_setup' ENV['GITLAB_ENV'] = 'test' ENV['IN_MEMORY_APPLICATION_SETTINGS'] = 'true' +require './spec/deprecation_warnings' + # Enable zero monkey patching mode before loading any other RSpec code. RSpec.configure(&:disable_monkey_patching!) -require 'active_support/dependencies' -require_relative '../config/initializers/0_inject_enterprise_edition_module' +require 'active_support/all' +require 'pry' +require_relative 'rails_autoload' + require_relative '../config/settings' require_relative 'support/rspec' require_relative '../lib/gitlab/utils' require_relative '../lib/gitlab/utils/strong_memoize' -require 'active_support/all' -require 'pry' require_relative 'simplecov_env' SimpleCovEnv.start! -unless ActiveSupport::Dependencies.autoload_paths.frozen? - ActiveSupport::Dependencies.autoload_paths << 'lib' - ActiveSupport::Dependencies.autoload_paths << 'ee/lib' - ActiveSupport::Dependencies.autoload_paths << 'jh/lib' -end - ActiveSupport::XmlMini.backend = 'Nokogiri' -RSpec.configure do |config| - # Makes diffs show entire non-truncated values. - config.before(:each, unlimited_max_formatted_output_length: true) do |_example| - config.expect_with :rspec do |c| - c.max_formatted_output_length = nil - end - end -end +# Consider tweaking configuration in `spec/support/rspec.rb` which is also +# used by `spec/spec_helper.rb`. diff --git a/spec/features/abuse_report_spec.rb b/spec/features/abuse_report_spec.rb index 1267025a7bf..82b7379b67c 100644 --- a/spec/features/abuse_report_spec.rb +++ b/spec/features/abuse_report_spec.rb @@ -12,28 +12,10 @@ RSpec.describe 'Abuse reports', :js, feature_category: :insider_threat do before do sign_in(reporter1) + stub_feature_flags(moved_mr_sidebar: false) end describe 'report abuse to administrator' do - shared_examples 'reports the user with an abuse category' do - it do - fill_and_submit_abuse_category_form - fill_and_submit_report_abuse_form - - expect(page).to have_content 'Thank you for your report' - end - end - - shared_examples 'reports the user without an abuse category' do - it do - click_link 'Report abuse to administrator' - - fill_and_submit_report_abuse_form - - expect(page).to have_content 'Thank you for your report' - end - end - context 'when reporting an issue for abuse' do before do visit project_issue_path(project, issue) @@ -133,7 +115,7 @@ RSpec.describe 'Abuse reports', :js, feature_category: :insider_threat do before do visit project_issue_path(project, issue) - click_button 'More actions' + find('.more-actions-toggle button').click end it_behaves_like 'reports the user with an abuse category' @@ -143,7 +125,7 @@ RSpec.describe 'Abuse reports', :js, feature_category: :insider_threat do private def fill_and_submit_abuse_category_form(category = "They're posting spam.") - click_button 'Report abuse to administrator' + click_button 'Report abuse' choose category click_button 'Next' diff --git a/spec/features/action_cable_logging_spec.rb b/spec/features/action_cable_logging_spec.rb index c02a41c4c59..c8a4e1efb7a 100644 --- a/spec/features/action_cable_logging_spec.rb +++ b/spec/features/action_cable_logging_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' -RSpec.describe 'ActionCable logging', :js, feature_category: :not_owned do +RSpec.describe 'ActionCable logging', :js, feature_category: :shared do let_it_be(:project) { create(:project, :public) } let_it_be(:issue) { create(:issue, project: project) } let_it_be(:user) { create(:user) } diff --git a/spec/features/admin/admin_abuse_reports_spec.rb b/spec/features/admin/admin_abuse_reports_spec.rb index 10f12d7116f..9739ea53f81 100644 --- a/spec/features/admin/admin_abuse_reports_spec.rb +++ b/spec/features/admin/admin_abuse_reports_spec.rb @@ -2,79 +2,247 @@ require 'spec_helper' -RSpec.describe "Admin::AbuseReports", :js, feature_category: :not_owned do - let(:user) { create(:user) } +RSpec.describe "Admin::AbuseReports", :js, feature_category: :shared do + let_it_be(:user) { create(:user) } + let_it_be(:admin) { create(:admin) } context 'as an admin' do - before do - admin = create(:admin) - sign_in(admin) - gitlab_enable_admin_mode_sign_in(admin) - end + describe 'displayed reports' do + include FilteredSearchHelpers - describe 'if a user has been reported for abuse' do - let!(:abuse_report) { create(:abuse_report, user: user) } + let_it_be(:open_report) { create(:abuse_report, created_at: 5.days.ago, updated_at: 2.days.ago) } + let_it_be(:open_report2) { create(:abuse_report, created_at: 4.days.ago, updated_at: 3.days.ago, category: 'phishing') } + let_it_be(:closed_report) { create(:abuse_report, :closed) } - describe 'in the abuse report view' do - it 'presents information about abuse report' do - visit admin_abuse_reports_path + let(:abuse_report_row_selector) { '[data-testid="abuse-report-row"]' } - expect(page).to have_content('Abuse Reports') - expect(page).to have_content(abuse_report.message) - expect(page).to have_link(user.name, href: user_path(user)) - expect(page).to have_link('Remove user') - end + before do + sign_in(admin) + gitlab_enable_admin_mode_sign_in(admin) + + visit admin_abuse_reports_path end - describe 'in the profile page of the user' do - it 'shows a link to the admin view of the user' do - visit user_path(user) + it 'only includes open reports by default' do + expect_displayed_reports_count(2) + + expect_report_shown(open_report, open_report2) - expect(page).to have_link '', href: admin_user_path(user) + within '[data-testid="abuse-reports-filtered-search-bar"]' do + expect(page).to have_content 'Status = Open' end end - end - describe 'if a many users have been reported for abuse' do - let(:report_count) { AbuseReport.default_per_page + 3 } + it 'can be filtered by status, user, reporter, and category', :aggregate_failures do + # filter by status + filter %w[Status Closed] + expect_displayed_reports_count(1) + expect_report_shown(closed_report) + expect_report_not_shown(open_report, open_report2) - before do - report_count.times do - create(:abuse_report, user: create(:user)) + filter %w[Status Open] + expect_displayed_reports_count(2) + expect_report_shown(open_report, open_report2) + expect_report_not_shown(closed_report) + + # filter by user + filter(['User', open_report2.user.username]) + + expect_displayed_reports_count(1) + expect_report_shown(open_report2) + expect_report_not_shown(open_report, closed_report) + + # filter by reporter + filter(['Reporter', open_report.reporter.username]) + + expect_displayed_reports_count(1) + expect_report_shown(open_report) + expect_report_not_shown(open_report2, closed_report) + + # filter by category + filter(['Category', open_report2.category]) + + expect_displayed_reports_count(1) + expect_report_shown(open_report2) + expect_report_not_shown(open_report, closed_report) + end + + it 'can be sorted by created_at and updated_at in desc and asc order', :aggregate_failures do + # created_at desc (default) + expect(report_rows[0].text).to include(report_text(open_report2)) + expect(report_rows[1].text).to include(report_text(open_report)) + + # created_at asc + toggle_sort_direction + + expect(report_rows[0].text).to include(report_text(open_report)) + expect(report_rows[1].text).to include(report_text(open_report2)) + + # updated_at ascending + sort_by 'Updated date' + + expect(report_rows[0].text).to include(report_text(open_report2)) + expect(report_rows[1].text).to include(report_text(open_report)) + + # updated_at descending + toggle_sort_direction + + expect(report_rows[0].text).to include(report_text(open_report)) + expect(report_rows[1].text).to include(report_text(open_report2)) + end + + def report_rows + page.all(abuse_report_row_selector) + end + + def report_text(report) + "#{report.user.name} reported for #{report.category}" + end + + def expect_report_shown(*reports) + reports.each do |r| + expect(page).to have_content(report_text(r)) end end - describe 'in the abuse report view' do - it 'presents information about abuse report' do - visit admin_abuse_reports_path + def expect_report_not_shown(*reports) + reports.each do |r| + expect(page).not_to have_content(report_text(r)) + end + end + + def expect_displayed_reports_count(count) + expect(page).to have_css(abuse_report_row_selector, count: count) + end + + def filter(tokens) + # remove all existing filters first + page.find_all('.gl-token-close').each(&:click) - expect(page).to have_selector('.pagination') - expect(page).to have_selector('.pagination .js-pagination-page', count: (report_count.to_f / AbuseReport.default_per_page).ceil) + select_tokens(*tokens, submit: true, input_text: 'Filter reports') + end + + def sort_by(sort) + page.within('.vue-filtered-search-bar-container .sort-dropdown-container') do + page.find('.gl-dropdown-toggle').click + + page.within('.dropdown-menu') do + click_button sort + wait_for_requests + end end end end - describe 'filtering by user' do - let!(:user2) { create(:user) } - let!(:abuse_report) { create(:abuse_report, user: user) } - let!(:abuse_report_2) { create(:abuse_report, user: user2) } + context 'when abuse_reports_list feature flag is disabled' do + before do + stub_feature_flags(abuse_reports_list: false) - it 'shows only single user report' do - visit admin_abuse_reports_path + sign_in(admin) + gitlab_enable_admin_mode_sign_in(admin) + end + + describe 'if a user has been reported for abuse' do + let_it_be(:abuse_report) { create(:abuse_report, user: user) } + + describe 'in the abuse report view' do + before do + visit admin_abuse_reports_path + end + + it 'presents information about abuse report' do + expect(page).to have_content('Abuse Reports') + + expect(page).to have_content(user.name) + expect(page).to have_content(abuse_report.reporter.name) + expect(page).to have_content(abuse_report.message) + expect(page).to have_link(user.name, href: user_path(user)) + end + + it 'present actions items' do + expect(page).to have_link('Remove user & report') + expect(page).to have_link('Block user') + expect(page).to have_link('Remove user') + end + end + + describe 'in the profile page of the user' do + it 'shows a link to view user in the admin area' do + visit user_path(user) + + expect(page).to have_link 'View user in admin area', href: admin_user_path(user) + end + end + end + + describe 'if an admin has been reported for abuse' do + let_it_be(:admin_abuse_report) { create(:abuse_report, user: admin) } + + describe 'in the abuse report view' do + before do + visit admin_abuse_reports_path + end - page.within '.filter-form' do - click_button 'User' - wait_for_requests + it 'presents information about abuse report' do + page.within(:table_row, { "User" => admin.name }) do + expect(page).to have_content(admin.name) + expect(page).to have_content(admin_abuse_report.reporter.name) + expect(page).to have_content(admin_abuse_report.message) + expect(page).to have_link(admin.name, href: user_path(admin)) + end + end - page.within '.dropdown-menu-user' do - click_link user2.name + it 'does not present actions items' do + page.within(:table_row, { "User" => admin.name }) do + expect(page).not_to have_link('Remove user & report') + expect(page).not_to have_link('Block user') + expect(page).not_to have_link('Remove user') + end end + end + end + + describe 'if a many users have been reported for abuse' do + let(:report_count) { AbuseReport.default_per_page + 3 } - wait_for_requests + before do + report_count.times do + create(:abuse_report, user: create(:user)) + end end - expect(page).to have_content(user2.name) - expect(page).not_to have_content(user.name) + describe 'in the abuse report view' do + it 'presents information about abuse report' do + visit admin_abuse_reports_path + + expect(page).to have_selector('.pagination') + expect(page).to have_selector('.pagination .js-pagination-page', count: (report_count.to_f / AbuseReport.default_per_page).ceil) + end + end + end + + describe 'filtering by user' do + let!(:user2) { create(:user) } + let!(:abuse_report) { create(:abuse_report, user: user) } + let!(:abuse_report_2) { create(:abuse_report, user: user2) } + + it 'shows only single user report' do + visit admin_abuse_reports_path + + page.within '.filter-form' do + click_button 'User' + wait_for_requests + + page.within '.dropdown-menu-user' do + click_link user2.name + end + + wait_for_requests + end + + expect(page).to have_content(user2.name) + expect(page).not_to have_content(user.name) + end end end end diff --git a/spec/features/admin/admin_appearance_spec.rb b/spec/features/admin/admin_appearance_spec.rb index 252d9ac5bac..db0ae79c9c4 100644 --- a/spec/features/admin/admin_appearance_spec.rb +++ b/spec/features/admin/admin_appearance_spec.rb @@ -2,190 +2,192 @@ require 'spec_helper' -RSpec.describe 'Admin Appearance', feature_category: :not_owned do +RSpec.describe 'Admin Appearance', feature_category: :shared do let!(:appearance) { create(:appearance) } let(:admin) { create(:admin) } flag_values = [true, false] flag_values.each do |val| - before do - stub_feature_flags(restyle_login_page: val) - end - - it 'create new appearance' do - sign_in(admin) - gitlab_enable_admin_mode_sign_in(admin) - visit admin_application_settings_appearances_path - - fill_in 'appearance_title', with: 'MyCompany' - fill_in 'appearance_description', with: 'dev server' - fill_in 'appearance_pwa_name', with: 'GitLab PWA' - fill_in 'appearance_pwa_short_name', with: 'GitLab' - fill_in 'appearance_pwa_description', with: 'GitLab as PWA' - fill_in 'appearance_new_project_guidelines', with: 'Custom project guidelines' - fill_in 'appearance_profile_image_guidelines', with: 'Custom profile image guidelines' - click_button 'Update appearance settings' - - expect(page).to have_current_path admin_application_settings_appearances_path, ignore_query: true - expect(page).to have_content 'Appearance' - - expect(page).to have_field('appearance_title', with: 'MyCompany') - expect(page).to have_field('appearance_description', with: 'dev server') - expect(page).to have_field('appearance_pwa_name', with: 'GitLab PWA') - expect(page).to have_field('appearance_pwa_short_name', with: 'GitLab') - expect(page).to have_field('appearance_pwa_description', with: 'GitLab as PWA') - expect(page).to have_field('appearance_new_project_guidelines', with: 'Custom project guidelines') - expect(page).to have_field('appearance_profile_image_guidelines', with: 'Custom profile image guidelines') - expect(page).to have_content 'Last edit' - end + context "with #{val}" do + before do + stub_feature_flags(restyle_login_page: val) + end - it 'preview sign-in page appearance' do - sign_in(admin) - gitlab_enable_admin_mode_sign_in(admin) + it 'create new appearance' do + sign_in(admin) + gitlab_enable_admin_mode_sign_in(admin) + visit admin_application_settings_appearances_path - visit admin_application_settings_appearances_path - click_link "Sign-in page" + fill_in 'appearance_title', with: 'MyCompany' + fill_in 'appearance_description', with: 'dev server' + fill_in 'appearance_pwa_name', with: 'GitLab PWA' + fill_in 'appearance_pwa_short_name', with: 'GitLab' + fill_in 'appearance_pwa_description', with: 'GitLab as PWA' + fill_in 'appearance_new_project_guidelines', with: 'Custom project guidelines' + fill_in 'appearance_profile_image_guidelines', with: 'Custom profile image guidelines' + click_button 'Update appearance settings' - expect(find('#login')).to be_disabled - expect(find('#password')).to be_disabled - expect(find('button')).to be_disabled + expect(page).to have_current_path admin_application_settings_appearances_path, ignore_query: true + expect(page).to have_content 'Appearance' + + expect(page).to have_field('appearance_title', with: 'MyCompany') + expect(page).to have_field('appearance_description', with: 'dev server') + expect(page).to have_field('appearance_pwa_name', with: 'GitLab PWA') + expect(page).to have_field('appearance_pwa_short_name', with: 'GitLab') + expect(page).to have_field('appearance_pwa_description', with: 'GitLab as PWA') + expect(page).to have_field('appearance_new_project_guidelines', with: 'Custom project guidelines') + expect(page).to have_field('appearance_profile_image_guidelines', with: 'Custom profile image guidelines') + expect(page).to have_content 'Last edit' + end - expect_custom_sign_in_appearance(appearance) - end + it 'preview sign-in page appearance' do + sign_in(admin) + gitlab_enable_admin_mode_sign_in(admin) - it 'preview new project page appearance', :js do - sign_in(admin) - gitlab_enable_admin_mode_sign_in(admin) + visit admin_application_settings_appearances_path + click_link "Sign-in page" - visit admin_application_settings_appearances_path - click_link "New project page" + expect(find('#login')).to be_disabled + expect(find('#password')).to be_disabled + expect(find('button')).to be_disabled - expect_custom_new_project_appearance(appearance) - end + expect_custom_sign_in_appearance(appearance) + end - context 'Custom system header and footer' do - before do + it 'preview new project page appearance', :js do sign_in(admin) gitlab_enable_admin_mode_sign_in(admin) - end - context 'when system header and footer messages are empty' do - it 'shows custom system header and footer fields' do - visit admin_application_settings_appearances_path + visit admin_application_settings_appearances_path + click_link "New project page" - expect(page).to have_field('appearance_header_message', with: '') - expect(page).to have_field('appearance_footer_message', with: '') - expect(page).to have_field('appearance_message_background_color') - expect(page).to have_field('appearance_message_font_color') - end + expect_custom_new_project_appearance(appearance) end - context 'when system header and footer messages are not empty' do + context 'Custom system header and footer' do before do - appearance.update!(header_message: 'Foo', footer_message: 'Bar') + sign_in(admin) + gitlab_enable_admin_mode_sign_in(admin) end - it 'shows custom system header and footer fields' do - visit admin_application_settings_appearances_path + context 'when system header and footer messages are empty' do + it 'shows custom system header and footer fields' do + visit admin_application_settings_appearances_path - expect(page).to have_field('appearance_header_message', with: appearance.header_message) - expect(page).to have_field('appearance_footer_message', with: appearance.footer_message) - expect(page).to have_field('appearance_message_background_color') - expect(page).to have_field('appearance_message_font_color') + expect(page).to have_field('appearance_header_message', with: '') + expect(page).to have_field('appearance_footer_message', with: '') + expect(page).to have_field('appearance_message_background_color') + expect(page).to have_field('appearance_message_font_color') + end end - end - end - it 'custom sign-in page' do - visit new_user_session_path + context 'when system header and footer messages are not empty' do + before do + appearance.update!(header_message: 'Foo', footer_message: 'Bar') + end - expect_custom_sign_in_appearance(appearance) - end + it 'shows custom system header and footer fields' do + visit admin_application_settings_appearances_path - it 'custom new project page', :js do - sign_in(admin) - gitlab_enable_admin_mode_sign_in(admin) - visit new_project_path - click_link 'Create blank project' + expect(page).to have_field('appearance_header_message', with: appearance.header_message) + expect(page).to have_field('appearance_footer_message', with: appearance.footer_message) + expect(page).to have_field('appearance_message_background_color') + expect(page).to have_field('appearance_message_font_color') + end + end + end - expect_custom_new_project_appearance(appearance) - end + it 'custom sign-in page' do + visit new_user_session_path - context 'Profile page with custom profile image guidelines' do - before do + expect_custom_sign_in_appearance(appearance) + end + + it 'custom new project page', :js do sign_in(admin) gitlab_enable_admin_mode_sign_in(admin) - visit admin_application_settings_appearances_path - fill_in 'appearance_profile_image_guidelines', with: 'Custom profile image guidelines, please :smile:!' - click_button 'Update appearance settings' + visit new_project_path + click_link 'Create blank project' + + expect_custom_new_project_appearance(appearance) end - it 'renders guidelines when set' do - sign_in create(:user) - visit profile_path + context 'Profile page with custom profile image guidelines' do + before do + sign_in(admin) + gitlab_enable_admin_mode_sign_in(admin) + visit admin_application_settings_appearances_path + fill_in 'appearance_profile_image_guidelines', with: 'Custom profile image guidelines, please :smile:!' + click_button 'Update appearance settings' + end + + it 'renders guidelines when set' do + sign_in create(:user) + visit profile_path - expect(page).to have_content 'Custom profile image guidelines, please 😄!' + expect(page).to have_content 'Custom profile image guidelines, please 😄!' + end end - end - it 'appearance logo' do - sign_in(admin) - gitlab_enable_admin_mode_sign_in(admin) - visit admin_application_settings_appearances_path + it 'appearance logo' do + sign_in(admin) + gitlab_enable_admin_mode_sign_in(admin) + visit admin_application_settings_appearances_path - attach_file(:appearance_logo, logo_fixture) - click_button 'Update appearance settings' - expect(page).to have_css(logo_selector) + attach_file(:appearance_logo, logo_fixture) + click_button 'Update appearance settings' + expect(page).to have_css(logo_selector) - click_link 'Remove logo' - expect(page).not_to have_css(logo_selector) - end + click_link 'Remove logo' + expect(page).not_to have_css(logo_selector) + end - it 'appearance pwa icon' do - sign_in(admin) - gitlab_enable_admin_mode_sign_in(admin) - visit admin_application_settings_appearances_path + it 'appearance pwa icon' do + sign_in(admin) + gitlab_enable_admin_mode_sign_in(admin) + visit admin_application_settings_appearances_path - attach_file(:appearance_pwa_icon, logo_fixture) - click_button 'Update appearance settings' - expect(page).to have_css(pwa_icon_selector) + attach_file(:appearance_pwa_icon, logo_fixture) + click_button 'Update appearance settings' + expect(page).to have_css(pwa_icon_selector) - click_link 'Remove icon' - expect(page).not_to have_css(pwa_icon_selector) - end + click_link 'Remove icon' + expect(page).not_to have_css(pwa_icon_selector) + end - it 'header logos' do - sign_in(admin) - gitlab_enable_admin_mode_sign_in(admin) - visit admin_application_settings_appearances_path + it 'header logos' do + sign_in(admin) + gitlab_enable_admin_mode_sign_in(admin) + visit admin_application_settings_appearances_path - attach_file(:appearance_header_logo, logo_fixture) - click_button 'Update appearance settings' - expect(page).to have_css(header_logo_selector) + attach_file(:appearance_header_logo, logo_fixture) + click_button 'Update appearance settings' + expect(page).to have_css(header_logo_selector) - click_link 'Remove header logo' - expect(page).not_to have_css(header_logo_selector) - end + click_link 'Remove header logo' + expect(page).not_to have_css(header_logo_selector) + end - it 'Favicon' do - sign_in(admin) - gitlab_enable_admin_mode_sign_in(admin) - visit admin_application_settings_appearances_path + it 'Favicon' do + sign_in(admin) + gitlab_enable_admin_mode_sign_in(admin) + visit admin_application_settings_appearances_path - attach_file(:appearance_favicon, logo_fixture) - click_button 'Update appearance settings' + attach_file(:appearance_favicon, logo_fixture) + click_button 'Update appearance settings' - expect(page).to have_css('.appearance-light-logo-preview') + expect(page).to have_css('.appearance-light-logo-preview') - click_link 'Remove favicon' + click_link 'Remove favicon' - expect(page).not_to have_css('.appearance-light-logo-preview') + expect(page).not_to have_css('.appearance-light-logo-preview') - # allowed file types - attach_file(:appearance_favicon, Rails.root.join('spec', 'fixtures', 'sanitized.svg')) - click_button 'Update appearance settings' + # allowed file types + attach_file(:appearance_favicon, Rails.root.join('spec', 'fixtures', 'sanitized.svg')) + click_button 'Update appearance settings' - expect(page).to have_content 'Favicon You are not allowed to upload "svg" files, allowed types: png, ico' + expect(page).to have_content 'Favicon You are not allowed to upload "svg" files, allowed types: png, ico' + end end end diff --git a/spec/features/admin/admin_browse_spam_logs_spec.rb b/spec/features/admin/admin_browse_spam_logs_spec.rb index 461c9d08273..c272a8630b7 100644 --- a/spec/features/admin/admin_browse_spam_logs_spec.rb +++ b/spec/features/admin/admin_browse_spam_logs_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' -RSpec.describe 'Admin browse spam logs', feature_category: :not_owned do +RSpec.describe 'Admin browse spam logs', feature_category: :shared do let!(:spam_log) { create(:spam_log, description: 'abcde ' * 20) } before do diff --git a/spec/features/admin/admin_deploy_keys_spec.rb b/spec/features/admin/admin_deploy_keys_spec.rb index e55e1cce6b9..f59b4db5cc2 100644 --- a/spec/features/admin/admin_deploy_keys_spec.rb +++ b/spec/features/admin/admin_deploy_keys_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' -RSpec.describe 'admin deploy keys', :js, feature_category: :authentication_and_authorization do +RSpec.describe 'admin deploy keys', :js, feature_category: :system_access do include Spec::Support::Helpers::ModalHelpers let_it_be(:admin) { create(:admin) } diff --git a/spec/features/admin/admin_groups_spec.rb b/spec/features/admin/admin_groups_spec.rb index a07a5c48713..34fe98d22bd 100644 --- a/spec/features/admin/admin_groups_spec.rb +++ b/spec/features/admin/admin_groups_spec.rb @@ -3,8 +3,8 @@ require 'spec_helper' RSpec.describe 'Admin Groups', feature_category: :subgroups do - include Spec::Support::Helpers::Features::MembersHelpers - include Spec::Support::Helpers::Features::InviteMembersModalHelper + include Features::MembersHelpers + include Features::InviteMembersModalHelpers include Spec::Support::Helpers::ModalHelpers let(:internal) { Gitlab::VisibilityLevel::INTERNAL } diff --git a/spec/features/admin/admin_health_check_spec.rb b/spec/features/admin/admin_health_check_spec.rb index de71a48d2dc..66014e676d5 100644 --- a/spec/features/admin/admin_health_check_spec.rb +++ b/spec/features/admin/admin_health_check_spec.rb @@ -2,8 +2,9 @@ require 'spec_helper' -RSpec.describe "Admin Health Check", feature_category: :continuous_verification do +RSpec.describe "Admin Health Check", :js, feature_category: :error_budgets do include StubENV + include Spec::Support::Helpers::ModalHelpers let_it_be(:admin) { create(:admin) } before do @@ -30,7 +31,8 @@ RSpec.describe "Admin Health Check", feature_category: :continuous_verification describe 'reload access token' do it 'changes the access token' do orig_token = Gitlab::CurrentSettings.health_check_access_token - click_button 'Reset health check access token' + click_link 'Reset health check access token' + accept_gl_confirm('Are you sure you want to reset the health check token?') expect(page).to have_content('New health check access token has been generated!') expect(find('#health-check-token').text).not_to eq orig_token diff --git a/spec/features/admin/admin_hook_logs_spec.rb b/spec/features/admin/admin_hook_logs_spec.rb index d6507e68692..34208cca113 100644 --- a/spec/features/admin/admin_hook_logs_spec.rb +++ b/spec/features/admin/admin_hook_logs_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' -RSpec.describe 'Admin::HookLogs', feature_category: :continuous_verification do +RSpec.describe 'Admin::HookLogs', feature_category: :integrations do let_it_be(:system_hook) { create(:system_hook) } let_it_be(:hook_log) { create(:web_hook_log, web_hook: system_hook, internal_error_message: 'some error') } let_it_be(:admin) { create(:admin) } diff --git a/spec/features/admin/admin_hooks_spec.rb b/spec/features/admin/admin_hooks_spec.rb index 363c152371e..a8aa2680b55 100644 --- a/spec/features/admin/admin_hooks_spec.rb +++ b/spec/features/admin/admin_hooks_spec.rb @@ -106,7 +106,7 @@ RSpec.describe 'Admin::Hooks', feature_category: :integrations do visit admin_hooks_path click_button 'Test' - click_button 'Push events' + click_link 'Push events' end it { expect(page).to have_current_path(admin_hooks_path, ignore_query: true) } @@ -142,7 +142,7 @@ RSpec.describe 'Admin::Hooks', feature_category: :integrations do visit admin_hooks_path click_button 'Test' - click_button 'Merge request events' + click_link 'Merge request events' expect(page).to have_content 'Hook executed successfully' end diff --git a/spec/features/admin/admin_labels_spec.rb b/spec/features/admin/admin_labels_spec.rb index 8d2813d26f7..68d63ac321e 100644 --- a/spec/features/admin/admin_labels_spec.rb +++ b/spec/features/admin/admin_labels_spec.rb @@ -37,8 +37,11 @@ RSpec.describe 'admin issues labels', feature_category: :team_planning do end it 'deletes all labels', :js do - page.all('.labels .js-remove-label').each do |remove| - accept_gl_confirm(button_text: 'Delete label') { remove.click } + page.all('.labels .label-actions-list').each do |label| + label.click + accept_gl_confirm(button_text: 'Delete label') do + click_link 'Delete' + end wait_for_requests end diff --git a/spec/features/admin/admin_mode/login_spec.rb b/spec/features/admin/admin_mode/login_spec.rb index 393721fe451..c0c8b12342a 100644 --- a/spec/features/admin/admin_mode/login_spec.rb +++ b/spec/features/admin/admin_mode/login_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' -RSpec.describe 'Admin Mode Login', feature_category: :authentication_and_authorization do +RSpec.describe 'Admin Mode Login', feature_category: :system_access do include TermsHelper include UserLoginHelper include LdapHelpers @@ -15,249 +15,251 @@ RSpec.describe 'Admin Mode Login', feature_category: :authentication_and_authori flag_values = [true, false] flag_values.each do |val| - before do - stub_feature_flags(restyle_login_page: val) - end - context 'with valid username/password' do - let(:user) { create(:admin, :two_factor) } + context "with #{val}" do + before do + stub_feature_flags(restyle_login_page: val) + end + context 'with valid username/password' do + let(:user) { create(:admin, :two_factor) } - context 'using one-time code' do - it 'blocks login if we reuse the same code immediately' do - gitlab_sign_in(user, remember: true) + context 'using one-time code' do + it 'blocks login if we reuse the same code immediately' do + gitlab_sign_in(user, remember: true) - expect(page).to have_content('Two-Factor Authentication') + expect(page).to have_content(_('Enter verification code')) - repeated_otp = user.current_otp - enter_code(repeated_otp) - gitlab_enable_admin_mode_sign_in(user) + repeated_otp = user.current_otp + enter_code(repeated_otp) + gitlab_enable_admin_mode_sign_in(user) - expect(page).to have_content('Two-Factor Authentication') + expect(page).to have_content(_('Enter verification code')) - enter_code(repeated_otp) + enter_code(repeated_otp) - expect(page).to have_current_path admin_session_path, ignore_query: true - expect(page).to have_content('Invalid two-factor code') - end + expect(page).to have_current_path admin_session_path, ignore_query: true + expect(page).to have_content('Invalid two-factor code') + end - context 'not re-using codes' do - before do - gitlab_sign_in(user, remember: true) + context 'not re-using codes' do + before do + gitlab_sign_in(user, remember: true) - expect(page).to have_content('Two-factor authentication code') + expect(page).to have_content('Enter verification code') - enter_code(user.current_otp) - gitlab_enable_admin_mode_sign_in(user) + enter_code(user.current_otp) + gitlab_enable_admin_mode_sign_in(user) - expect(page).to have_content('Two-Factor Authentication') - end + expect(page).to have_content(_('Enter verification code')) + end - it 'allows login with valid code' do - # Cannot reuse the TOTP - travel_to(30.seconds.from_now) do - enter_code(user.current_otp) + it 'allows login with valid code' do + # Cannot reuse the TOTP + travel_to(30.seconds.from_now) do + enter_code(user.current_otp) - expect(page).to have_current_path admin_root_path, ignore_query: true - expect(page).to have_content('Admin mode enabled') + expect(page).to have_current_path admin_root_path, ignore_query: true + expect(page).to have_content('Admin mode enabled') + end end - end - it 'blocks login with invalid code' do - # Cannot reuse the TOTP - travel_to(30.seconds.from_now) do - enter_code('foo') + it 'blocks login with invalid code' do + # Cannot reuse the TOTP + travel_to(30.seconds.from_now) do + enter_code('foo') - expect(page).to have_content('Invalid two-factor code') + expect(page).to have_content('Invalid two-factor code') + end end - end - it 'allows login with invalid code, then valid code' do - # Cannot reuse the TOTP - travel_to(30.seconds.from_now) do - enter_code('foo') + it 'allows login with invalid code, then valid code' do + # Cannot reuse the TOTP + travel_to(30.seconds.from_now) do + enter_code('foo') - expect(page).to have_content('Invalid two-factor code') + expect(page).to have_content('Invalid two-factor code') - enter_code(user.current_otp) + enter_code(user.current_otp) - expect(page).to have_current_path admin_root_path, ignore_query: true - expect(page).to have_content('Admin mode enabled') + expect(page).to have_current_path admin_root_path, ignore_query: true + expect(page).to have_content('Admin mode enabled') + end end - end - context 'using backup code' do - let(:codes) { user.generate_otp_backup_codes! } + context 'using backup code' do + let(:codes) { user.generate_otp_backup_codes! } - before do - expect(codes.size).to eq 10 + before do + expect(codes.size).to eq 10 - # Ensure the generated codes get saved - user.save! - end + # Ensure the generated codes get saved + user.save! + end - context 'with valid code' do - it 'allows login' do - enter_code(codes.sample) + context 'with valid code' do + it 'allows login' do + enter_code(codes.sample) - expect(page).to have_current_path admin_root_path, ignore_query: true - expect(page).to have_content('Admin mode enabled') - end + expect(page).to have_current_path admin_root_path, ignore_query: true + expect(page).to have_content('Admin mode enabled') + end - it 'invalidates the used code' do - expect { enter_code(codes.sample) } - .to change { user.reload.otp_backup_codes.size }.by(-1) + it 'invalidates the used code' do + expect { enter_code(codes.sample) } + .to change { user.reload.otp_backup_codes.size }.by(-1) + end end - end - context 'with invalid code' do - it 'blocks login' do - code = codes.sample - expect(user.invalidate_otp_backup_code!(code)).to eq true + context 'with invalid code' do + it 'blocks login' do + code = codes.sample + expect(user.invalidate_otp_backup_code!(code)).to eq true - user.save! - expect(user.reload.otp_backup_codes.size).to eq 9 + user.save! + expect(user.reload.otp_backup_codes.size).to eq 9 - enter_code(code) + enter_code(code) - expect(page).to have_content('Invalid two-factor code.') + expect(page).to have_content('Invalid two-factor code.') + end end end end end - end - - context 'when logging in via omniauth' do - let(:user) { create(:omniauth_user, :admin, :two_factor, extern_uid: 'my-uid', provider: 'saml', password_automatically_set: false) } - let(:mock_saml_response) do - File.read('spec/fixtures/authentication/saml_response.xml') - end - before do - stub_omniauth_saml_config(enabled: true, auto_link_saml_user: true, allow_single_sign_on: ['saml'], providers: [mock_saml_config_with_upstream_two_factor_authn_contexts]) - end - - context 'when authn_context is worth two factors' do + context 'when logging in via omniauth' do + let(:user) { create(:omniauth_user, :admin, :two_factor, extern_uid: 'my-uid', provider: 'saml', password_automatically_set: false) } let(:mock_saml_response) do File.read('spec/fixtures/authentication/saml_response.xml') - .gsub('urn:oasis:names:tc:SAML:2.0:ac:classes:Password', - 'urn:oasis:names:tc:SAML:2.0:ac:classes:SecondFactorOTPSMS') end - it 'signs user in without prompting for second factor' do - sign_in_using_saml! + before do + stub_omniauth_saml_config(enabled: true, auto_link_saml_user: true, allow_single_sign_on: ['saml'], providers: [mock_saml_config_with_upstream_two_factor_authn_contexts]) + end + + context 'when authn_context is worth two factors' do + let(:mock_saml_response) do + File.read('spec/fixtures/authentication/saml_response.xml') + .gsub('urn:oasis:names:tc:SAML:2.0:ac:classes:Password', + 'urn:oasis:names:tc:SAML:2.0:ac:classes:SecondFactorOTPSMS') + end - expect(page).not_to have_content('Two-Factor Authentication') + it 'signs user in without prompting for second factor' do + sign_in_using_saml! - enable_admin_mode_using_saml! + expect(page).not_to have_content(_('Enter verification code')) - expect(page).not_to have_content('Two-Factor Authentication') - expect(page).to have_current_path admin_root_path, ignore_query: true - expect(page).to have_content('Admin mode enabled') + enable_admin_mode_using_saml! + + expect(page).not_to have_content(_('Enter verification code')) + expect(page).to have_current_path admin_root_path, ignore_query: true + expect(page).to have_content('Admin mode enabled') + end end - end - context 'when two factor authentication is required' do - it 'shows 2FA prompt after omniauth login' do - sign_in_using_saml! + context 'when two factor authentication is required' do + it 'shows 2FA prompt after omniauth login' do + sign_in_using_saml! - expect(page).to have_content('Two-Factor Authentication') - enter_code(user.current_otp) + expect(page).to have_content(_('Enter verification code')) + enter_code(user.current_otp) - enable_admin_mode_using_saml! + enable_admin_mode_using_saml! - expect(page).to have_content('Two-Factor Authentication') + expect(page).to have_content(_('Enter verification code')) - # Cannot reuse the TOTP - travel_to(30.seconds.from_now) do - enter_code(user.current_otp) + # Cannot reuse the TOTP + travel_to(30.seconds.from_now) do + enter_code(user.current_otp) - expect(page).to have_current_path admin_root_path, ignore_query: true - expect(page).to have_content('Admin mode enabled') + expect(page).to have_current_path admin_root_path, ignore_query: true + expect(page).to have_content('Admin mode enabled') + end end end - end - def sign_in_using_saml! - gitlab_sign_in_via('saml', user, 'my-uid', mock_saml_response) - end + def sign_in_using_saml! + gitlab_sign_in_via('saml', user, 'my-uid', mock_saml_response) + end - def enable_admin_mode_using_saml! - gitlab_enable_admin_mode_sign_in_via('saml', user, 'my-uid', mock_saml_response) + def enable_admin_mode_using_saml! + gitlab_enable_admin_mode_sign_in_via('saml', user, 'my-uid', mock_saml_response) + end end - end - context 'when logging in via ldap' do - let(:uid) { 'my-uid' } - let(:provider_label) { 'Main LDAP' } - let(:provider_name) { 'main' } - let(:provider) { "ldap#{provider_name}" } - let(:ldap_server_config) do - { - 'label' => provider_label, - 'provider_name' => provider, - 'attributes' => {}, - 'encryption' => 'plain', - 'uid' => 'uid', - 'base' => 'dc=example,dc=com' - } - end + context 'when logging in via ldap' do + let(:uid) { 'my-uid' } + let(:provider_label) { 'Main LDAP' } + let(:provider_name) { 'main' } + let(:provider) { "ldap#{provider_name}" } + let(:ldap_server_config) do + { + 'label' => provider_label, + 'provider_name' => provider, + 'attributes' => {}, + 'encryption' => 'plain', + 'uid' => 'uid', + 'base' => 'dc=example,dc=com' + } + end - let(:user) { create(:omniauth_user, :admin, :two_factor, extern_uid: uid, provider: provider) } + let(:user) { create(:omniauth_user, :admin, :two_factor, extern_uid: uid, provider: provider) } - before do - setup_ldap(provider, user, uid, ldap_server_config) - end + before do + setup_ldap(provider, user, uid, ldap_server_config) + end - context 'when two factor authentication is required' do - it 'shows 2FA prompt after ldap login' do - sign_in_using_ldap!(user, provider_label) - expect(page).to have_content('Two-Factor Authentication') + context 'when two factor authentication is required' do + it 'shows 2FA prompt after ldap login' do + sign_in_using_ldap!(user, provider_label) + expect(page).to have_content(_('Enter verification code')) - enter_code(user.current_otp) - enable_admin_mode_using_ldap!(user) + enter_code(user.current_otp) + enable_admin_mode_using_ldap!(user) - expect(page).to have_content('Two-Factor Authentication') + expect(page).to have_content(_('Enter verification code')) - # Cannot reuse the TOTP - travel_to(30.seconds.from_now) do - enter_code(user.current_otp) + # Cannot reuse the TOTP + travel_to(30.seconds.from_now) do + enter_code(user.current_otp) - expect(page).to have_current_path admin_root_path, ignore_query: true - expect(page).to have_content('Admin mode enabled') + expect(page).to have_current_path admin_root_path, ignore_query: true + expect(page).to have_content('Admin mode enabled') + end end end - end - def setup_ldap(provider, user, uid, ldap_server_config) - stub_ldap_setting(enabled: true) + def setup_ldap(provider, user, uid, ldap_server_config) + stub_ldap_setting(enabled: true) - allow(::Gitlab::Auth::Ldap::Config).to receive_messages(enabled: true, servers: [ldap_server_config]) - allow(Gitlab::Auth::OAuth::Provider).to receive_messages(providers: [provider.to_sym]) + allow(::Gitlab::Auth::Ldap::Config).to receive_messages(enabled: true, servers: [ldap_server_config]) + allow(Gitlab::Auth::OAuth::Provider).to receive_messages(providers: [provider.to_sym]) - Ldap::OmniauthCallbacksController.define_providers! - Rails.application.reload_routes! + Ldap::OmniauthCallbacksController.define_providers! + Rails.application.reload_routes! - mock_auth_hash(provider, uid, user.email) - allow(Gitlab::Auth::Ldap::Access).to receive(:allowed?).with(user).and_return(true) + mock_auth_hash(provider, uid, user.email) + allow(Gitlab::Auth::Ldap::Access).to receive(:allowed?).with(user).and_return(true) - allow_any_instance_of(ActionDispatch::Routing::RoutesProxy) - .to receive(:"user_#{provider}_omniauth_callback_path") - .and_return("/users/auth/#{provider}/callback") - end + allow_any_instance_of(ActionDispatch::Routing::RoutesProxy) + .to receive(:"user_#{provider}_omniauth_callback_path") + .and_return("/users/auth/#{provider}/callback") + end - def sign_in_using_ldap!(user, provider_label) - visit new_user_session_path - click_link provider_label - fill_in 'username', with: user.username - fill_in 'password', with: user.password - click_button 'Sign in' - end + def sign_in_using_ldap!(user, provider_label) + visit new_user_session_path + click_link provider_label + fill_in 'username', with: user.username + fill_in 'password', with: user.password + click_button 'Sign in' + end - def enable_admin_mode_using_ldap!(user) - visit new_admin_session_path - click_link provider_label - fill_in 'username', with: user.username - fill_in 'password', with: user.password - click_button 'Enter Admin Mode' + def enable_admin_mode_using_ldap!(user) + visit new_admin_session_path + click_link provider_label + fill_in 'username', with: user.username + fill_in 'password', with: user.password + click_button 'Enter admin mode' + end end end end diff --git a/spec/features/admin/admin_mode/logout_spec.rb b/spec/features/admin/admin_mode/logout_spec.rb index f4e8941d25a..a64d3f241f6 100644 --- a/spec/features/admin/admin_mode/logout_spec.rb +++ b/spec/features/admin/admin_mode/logout_spec.rb @@ -2,10 +2,10 @@ require 'spec_helper' -RSpec.describe 'Admin Mode Logout', :js, feature_category: :authentication_and_authorization do +RSpec.describe 'Admin Mode Logout', :js, feature_category: :system_access do include TermsHelper include UserLoginHelper - include Spec::Support::Helpers::Features::TopNavSpecHelpers + include Features::TopNavSpecHelpers let(:user) { create(:admin) } diff --git a/spec/features/admin/admin_mode/workers_spec.rb b/spec/features/admin/admin_mode/workers_spec.rb index f3639fd0800..124c43eef9d 100644 --- a/spec/features/admin/admin_mode/workers_spec.rb +++ b/spec/features/admin/admin_mode/workers_spec.rb @@ -3,8 +3,8 @@ require 'spec_helper' # Test an operation that triggers background jobs requiring administrative rights -RSpec.describe 'Admin mode for workers', :request_store, feature_category: :authentication_and_authorization do - include Spec::Support::Helpers::Features::AdminUsersHelpers +RSpec.describe 'Admin mode for workers', :request_store, feature_category: :system_access do + include Features::AdminUsersHelpers let(:user) { create(:user) } let(:user_to_delete) { create(:user) } diff --git a/spec/features/admin/admin_mode_spec.rb b/spec/features/admin/admin_mode_spec.rb index 769ff75b5a2..65249fa0235 100644 --- a/spec/features/admin/admin_mode_spec.rb +++ b/spec/features/admin/admin_mode_spec.rb @@ -2,9 +2,9 @@ require 'spec_helper' -RSpec.describe 'Admin mode', :js, feature_category: :not_owned do +RSpec.describe 'Admin mode', :js, feature_category: :shared do include MobileHelpers - include Spec::Support::Helpers::Features::TopNavSpecHelpers + include Features::TopNavSpecHelpers include StubENV let(:admin) { create(:admin) } @@ -50,7 +50,7 @@ RSpec.describe 'Admin mode', :js, feature_category: :not_owned do fill_in 'user_password', with: admin.password - click_button 'Enter Admin Mode' + click_button 'Enter admin mode' expect(page).to have_current_path(admin_root_path) end @@ -65,7 +65,7 @@ RSpec.describe 'Admin mode', :js, feature_category: :not_owned do fill_in 'user_password', with: admin.password - click_button 'Enter Admin Mode' + click_button 'Enter admin mode' expect(page).to have_current_path(admin_root_path) end @@ -111,7 +111,7 @@ RSpec.describe 'Admin mode', :js, feature_category: :not_owned do open_top_nav expect(page).to have_link(text: 'Admin', href: admin_root_path, visible: true) - expect(page).to have_link(text: 'Leave Admin Mode', href: destroy_admin_session_path, visible: true) + expect(page).to have_link(text: 'Leave admin mode', href: destroy_admin_session_path, visible: true) end end diff --git a/spec/features/admin/admin_projects_spec.rb b/spec/features/admin/admin_projects_spec.rb index f08e6521184..ac2e9de7aee 100644 --- a/spec/features/admin/admin_projects_spec.rb +++ b/spec/features/admin/admin_projects_spec.rb @@ -3,8 +3,8 @@ require 'spec_helper' RSpec.describe "Admin::Projects", feature_category: :projects do - include Spec::Support::Helpers::Features::MembersHelpers - include Spec::Support::Helpers::Features::InviteMembersModalHelper + include Features::MembersHelpers + include Features::InviteMembersModalHelpers include Spec::Support::Helpers::ModalHelpers include ListboxHelpers @@ -161,4 +161,44 @@ RSpec.describe "Admin::Projects", feature_category: :projects do expect(page).to have_current_path(dashboard_projects_path, ignore_query: true, url: false) end end + + describe 'project edit' do + it 'updates project details' do + project = create(:project, :private, name: 'Garfield', description: 'Funny Cat') + + visit edit_admin_namespace_project_path({ id: project.to_param, namespace_id: project.namespace.to_param }) + + aggregate_failures do + expect(page).to have_content(project.name) + expect(page).to have_content(project.description) + end + + fill_in 'Project name', with: 'Scooby-Doo' + fill_in 'Project description (optional)', with: 'Funny Dog' + + click_button 'Save changes' + + visit edit_admin_namespace_project_path({ id: project.to_param, namespace_id: project.namespace.to_param }) + + aggregate_failures do + expect(page).to have_content('Scooby-Doo') + expect(page).to have_content('Funny Dog') + end + end + end + + describe 'project runner registration edit' do + it 'updates runner registration' do + visit edit_admin_namespace_project_path({ id: project.to_param, namespace_id: project.namespace.to_param }) + + expect(find_field('New project runners can be registered')).to be_checked + + uncheck 'New project runners can be registered' + click_button 'Save changes' + + visit edit_admin_namespace_project_path({ id: project.to_param, namespace_id: project.namespace.to_param }) + + expect(find_field('New project runners can be registered')).not_to be_checked + end + end end diff --git a/spec/features/admin/admin_runners_spec.rb b/spec/features/admin/admin_runners_spec.rb index 04dc206f052..582535790bd 100644 --- a/spec/features/admin/admin_runners_spec.rb +++ b/spec/features/admin/admin_runners_spec.rb @@ -3,7 +3,7 @@ require 'spec_helper' RSpec.describe "Admin Runners", feature_category: :runner_fleet do - include Spec::Support::Helpers::Features::RunnersHelpers + include Features::RunnersHelpers include Spec::Support::Helpers::ModalHelpers let_it_be(:admin) { create(:admin) } @@ -23,8 +23,6 @@ RSpec.describe "Admin Runners", feature_category: :runner_fleet do describe "runners creation" do before do - stub_feature_flags(create_runner_workflow: true) - visit admin_runners_path end @@ -34,15 +32,30 @@ RSpec.describe "Admin Runners", feature_category: :runner_fleet do end describe "runners registration" do - before do - stub_feature_flags(create_runner_workflow: false) + context 'when create_runner_workflow_for_namespace is enabled' do + before do + stub_feature_flags(create_runner_workflow_for_admin: true) - visit admin_runners_path + visit admin_runners_path + end + + it_behaves_like "shows and resets runner registration token" do + let(:dropdown_text) { s_('Runners|Register an instance runner') } + let(:registration_token) { Gitlab::CurrentSettings.runners_registration_token } + end end - it_behaves_like "shows and resets runner registration token" do - let(:dropdown_text) { s_('Runners|Register an instance runner') } - let(:registration_token) { Gitlab::CurrentSettings.runners_registration_token } + context 'when create_runner_workflow_for_namespace is disabled' do + before do + stub_feature_flags(create_runner_workflow_for_admin: false) + + visit admin_runners_path + end + + it_behaves_like "shows and resets runner registration token" do + let(:dropdown_text) { s_('Runners|Register an instance runner') } + let(:registration_token) { Gitlab::CurrentSettings.runners_registration_token } + end end end @@ -373,11 +386,9 @@ RSpec.describe "Admin Runners", feature_category: :runner_fleet do it_behaves_like 'shows no runners found' - it 'shows active tab' do + it 'shows active tab with no runner' do expect(page).to have_link('Instance', class: 'active') - end - it 'shows no runner' do expect(page).not_to have_content 'runner-project' expect(page).not_to have_content 'runner-group' end @@ -471,10 +482,12 @@ RSpec.describe "Admin Runners", feature_category: :runner_fleet do it_behaves_like 'shows no runners registered' it 'shows tabs with total counts equal to 0' do - expect(page).to have_link('All 0') - expect(page).to have_link('Instance 0') - expect(page).to have_link('Group 0') - expect(page).to have_link('Project 0') + aggregate_failures do + expect(page).to have_link('All 0') + expect(page).to have_link('Instance 0') + expect(page).to have_link('Group 0') + expect(page).to have_link('Project 0') + end end end @@ -493,6 +506,16 @@ RSpec.describe "Admin Runners", feature_category: :runner_fleet do end end + describe "Runner create page", :js do + before do + visit new_admin_runner_path + end + + it_behaves_like 'creates runner and shows register page' do + let(:register_path_pattern) { register_admin_runner_path('.*') } + end + end + describe "Runner show page", :js do let_it_be(:runner) do create( @@ -546,11 +569,8 @@ RSpec.describe "Admin Runners", feature_category: :runner_fleet do end end - it 'deletes runner' do + it 'deletes runner and redirects to runner list' do expect(page.find('[data-testid="alert-success"]')).to have_content('deleted') - end - - it 'redirects to runner list' do expect(current_url).to match(admin_runners_path) end end @@ -593,12 +613,9 @@ RSpec.describe "Admin Runners", feature_category: :runner_fleet do wait_for_requests end - it 'show success alert' do - expect(page.find('[data-testid="alert-success"]')).to have_content('saved') - end - - it 'redirects to runner page' do + it 'show success alert and redirects to runner page' do expect(current_url).to match(admin_runner_path(project_runner)) + expect(page.find('[data-testid="alert-success"]')).to have_content('saved') end end @@ -632,12 +649,12 @@ RSpec.describe "Admin Runners", feature_category: :runner_fleet do assigned_project = page.find('[data-testid="assigned-projects"]') expect(page).to have_content('Runner assigned to project.') - expect(assigned_project).to have_content(project2.path) + expect(assigned_project).to have_content(project2.name) end end context 'with project runner' do - let(:project_runner) { create(:ci_runner, :project, projects: [project1]) } + let_it_be(:project_runner) { create(:ci_runner, :project, projects: [project1]) } before do visit edit_admin_runner_path(project_runner) @@ -647,7 +664,7 @@ RSpec.describe "Admin Runners", feature_category: :runner_fleet do end context 'with locked runner' do - let(:locked_runner) { create(:ci_runner, :project, projects: [project1], locked: true) } + let_it_be(:locked_runner) { create(:ci_runner, :project, projects: [project1], locked: true) } before do visit edit_admin_runner_path(locked_runner) @@ -658,7 +675,7 @@ RSpec.describe "Admin Runners", feature_category: :runner_fleet do end describe 'disable/destroy' do - let(:runner) { create(:ci_runner, :project, projects: [project1]) } + let_it_be(:runner) { create(:ci_runner, :project, projects: [project1]) } before do visit edit_admin_runner_path(runner) @@ -672,7 +689,7 @@ RSpec.describe "Admin Runners", feature_category: :runner_fleet do new_runner_project = page.find('[data-testid="unassigned-projects"]') expect(page).to have_content('Runner unassigned from project.') - expect(new_runner_project).to have_content(project1.path) + expect(new_runner_project).to have_content(project1.name) end end end diff --git a/spec/features/admin/admin_sees_background_migrations_spec.rb b/spec/features/admin/admin_sees_background_migrations_spec.rb index cad1bf74d2e..77266e65e4c 100644 --- a/spec/features/admin/admin_sees_background_migrations_spec.rb +++ b/spec/features/admin/admin_sees_background_migrations_spec.rb @@ -191,7 +191,7 @@ RSpec.describe "Admin > Admin sees background migrations", feature_category: :da visit admin_background_migrations_path within '#content-body' do - expect(page).to have_link('Learn more', href: help_page_path('user/admin_area/monitoring/background_migrations')) + expect(page).to have_link('Learn more', href: help_page_path('update/background_migrations')) end end diff --git a/spec/features/admin/admin_settings_spec.rb b/spec/features/admin/admin_settings_spec.rb index 26efed85513..1f43caf37e7 100644 --- a/spec/features/admin/admin_settings_spec.rb +++ b/spec/features/admin/admin_settings_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' -RSpec.describe 'Admin updates settings', feature_category: :not_owned do +RSpec.describe 'Admin updates settings', feature_category: :shared do include StubENV include TermsHelper include UsageDataHelpers @@ -53,17 +53,6 @@ RSpec.describe 'Admin updates settings', feature_category: :not_owned do end it 'modify import sources' do - expect(current_settings.import_sources).not_to be_empty - - page.within('[data-testid="admin-visibility-access-settings"]') do - Gitlab::ImportSources.options.map do |name, _| - uncheck name - end - - click_button 'Save changes' - end - - expect(page).to have_content "Application settings saved successfully" expect(current_settings.import_sources).to be_empty page.within('[data-testid="admin-visibility-access-settings"]') do @@ -157,7 +146,7 @@ RSpec.describe 'Admin updates settings', feature_category: :not_owned do expect(user_internal_regex['placeholder']).to eq 'Regex pattern' end - context 'Dormant users' do + context 'Dormant users', feature_category: :user_management do context 'when Gitlab.com' do let(:dot_com?) { true } @@ -182,7 +171,7 @@ RSpec.describe 'Admin updates settings', feature_category: :not_owned do expect(page).to have_field('Days of inactivity before deactivation') end - it 'changes dormant users' do + it 'changes dormant users', quarantine: 'https://gitlab.com/gitlab-org/gitlab/-/issues/408224' do expect(page).to have_unchecked_field('Deactivate dormant users after a period of inactivity') expect(current_settings.deactivate_dormant_users).to be_falsey @@ -199,7 +188,7 @@ RSpec.describe 'Admin updates settings', feature_category: :not_owned do expect(page).to have_checked_field('Deactivate dormant users after a period of inactivity') end - it 'change dormant users period' do + it 'change dormant users period', quarantine: 'https://gitlab.com/gitlab-org/gitlab/-/issues/408224' do expect(page).to have_field _('Days of inactivity before deactivation') page.within(find('[data-testid="account-limit"]')) do @@ -360,8 +349,8 @@ RSpec.describe 'Admin updates settings', feature_category: :not_owned do end end - context 'GitLab for Jira App settings' do - it 'changes the setting' do + context 'GitLab for Jira App settings', feature_category: :integrations do + it 'changes the settings' do page.within('#js-jira_connect-settings') do fill_in 'Jira Connect Application ID', with: '1234' fill_in 'Jira Connect Proxy URL', with: 'https://example.com' @@ -375,6 +364,28 @@ RSpec.describe 'Admin updates settings', feature_category: :not_owned do expect(page).to have_content "Application settings saved successfully" end end + + context 'GitLab for Slack app settings', feature_category: :integrations do + it 'changes the settings' do + page.within('.as-slack') do + check 'Enable Slack application' + fill_in 'Client ID', with: 'slack_app_id' + fill_in 'Client secret', with: 'slack_app_secret' + fill_in 'Signing secret', with: 'slack_app_signing_secret' + fill_in 'Verification token', with: 'slack_app_verification_token' + click_button 'Save changes' + end + + expect(current_settings).to have_attributes( + slack_app_enabled: true, + slack_app_id: 'slack_app_id', + slack_app_secret: 'slack_app_secret', + slack_app_signing_secret: 'slack_app_signing_secret', + slack_app_verification_token: 'slack_app_verification_token' + ) + expect(page).to have_content 'Application settings saved successfully' + end + end end context 'Integrations page' do @@ -426,6 +437,7 @@ RSpec.describe 'Admin updates settings', feature_category: :not_owned do fill_in 'application_setting_auto_devops_domain', with: 'domain.com' uncheck 'Keep the latest artifacts for all jobs in the latest successful pipelines' uncheck 'Enable pipeline suggestion banner' + fill_in 'application_setting_ci_max_includes', with: 200 click_button 'Save changes' end @@ -433,6 +445,7 @@ RSpec.describe 'Admin updates settings', feature_category: :not_owned do expect(current_settings.auto_devops_domain).to eq('domain.com') expect(current_settings.keep_latest_artifact).to be false expect(current_settings.suggest_pipeline_enabled).to be false + expect(current_settings.ci_max_includes).to be 200 expect(page).to have_content "Application settings saved successfully" end @@ -442,7 +455,6 @@ RSpec.describe 'Admin updates settings', feature_category: :not_owned do page.within('.as-ci-cd') do fill_in 'plan_limits_ci_pipeline_size', with: 10 fill_in 'plan_limits_ci_active_jobs', with: 20 - fill_in 'plan_limits_ci_active_pipelines', with: 25 fill_in 'plan_limits_ci_project_subscriptions', with: 30 fill_in 'plan_limits_ci_pipeline_schedules', with: 40 fill_in 'plan_limits_ci_needs_size_limit', with: 50 @@ -454,7 +466,6 @@ RSpec.describe 'Admin updates settings', feature_category: :not_owned do limits = default_plan.reload.limits expect(limits.ci_pipeline_size).to eq(10) expect(limits.ci_active_jobs).to eq(20) - expect(limits.ci_active_pipelines).to eq(25) expect(limits.ci_project_subscriptions).to eq(30) expect(limits.ci_pipeline_schedules).to eq(40) expect(limits.ci_needs_size_limit).to eq(50) @@ -487,7 +498,7 @@ RSpec.describe 'Admin updates settings', feature_category: :not_owned do container_registry_delete_tags_service_timeout: 'Container Registry delete tags service execution timeout', container_registry_expiration_policies_worker_capacity: 'Cleanup policy maximum workers running concurrently', container_registry_cleanup_tags_service_max_list_size: 'Cleanup policy maximum number of tags to be deleted', - container_registry_expiration_policies_caching: 'Enable container expiration caching' + container_registry_expiration_policies_caching: 'Enable cleanup policy caching' } end @@ -638,6 +649,8 @@ RSpec.describe 'Admin updates settings', feature_category: :not_owned do end it 'loads togglable usage ping payload on click', :js do + allow(Gitlab::Usage::ServicePingReport).to receive(:for).and_return({ uuid: '12345678', hostname: '127.0.0.1' }) + stub_usage_data_connections stub_database_flavor_check @@ -666,11 +679,11 @@ RSpec.describe 'Admin updates settings', feature_category: :not_owned do visit network_admin_application_settings_path page.within('.as-outbound') do - check 'Allow requests to the local network from web hooks and services' + check 'Allow requests to the local network from webhooks and integrations' # Enabled by default uncheck 'Allow requests to the local network from system hooks' # Enabled by default - uncheck 'Enforce DNS rebinding attack protection' + uncheck 'Enforce DNS-rebinding attack protection' click_button 'Save changes' end @@ -762,6 +775,18 @@ RSpec.describe 'Admin updates settings', feature_category: :not_owned do expect(current_settings.users_get_by_id_limit_allowlist).to eq(%w[someone someone_else]) end + it 'changes Projects API rate limits settings' do + visit network_admin_application_settings_path + + page.within('.as-projects-api-limits') do + fill_in 'Maximum requests per 10 minutes per IP address', with: 100 + click_button 'Save changes' + end + + expect(page).to have_content "Application settings saved successfully" + expect(current_settings.projects_api_rate_limit_unauthenticated).to eq(100) + end + shared_examples 'regular throttle rate limit settings' do it 'changes rate limit settings' do visit network_admin_application_settings_path diff --git a/spec/features/admin/admin_system_info_spec.rb b/spec/features/admin/admin_system_info_spec.rb index 6c4a316ae77..21a001f12c3 100644 --- a/spec/features/admin/admin_system_info_spec.rb +++ b/spec/features/admin/admin_system_info_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' -RSpec.describe 'Admin System Info', feature_category: :not_owned do +RSpec.describe 'Admin System Info', feature_category: :shared do before do admin = create(:admin) sign_in(admin) diff --git a/spec/features/admin/admin_users_impersonation_tokens_spec.rb b/spec/features/admin/admin_users_impersonation_tokens_spec.rb index 5e6cc206883..0350c8ab066 100644 --- a/spec/features/admin/admin_users_impersonation_tokens_spec.rb +++ b/spec/features/admin/admin_users_impersonation_tokens_spec.rb @@ -2,9 +2,9 @@ require 'spec_helper' -RSpec.describe 'Admin > Users > Impersonation Tokens', :js, feature_category: :authentication_and_authorization do +RSpec.describe 'Admin > Users > Impersonation Tokens', :js, feature_category: :system_access do include Spec::Support::Helpers::ModalHelpers - include Spec::Support::Helpers::AccessTokenHelpers + include Features::AccessTokenHelpers let(:admin) { create(:admin) } let!(:user) { create(:user) } diff --git a/spec/features/admin/admin_uses_repository_checks_spec.rb b/spec/features/admin/admin_uses_repository_checks_spec.rb index 318572a7664..d9d36ec3bae 100644 --- a/spec/features/admin/admin_uses_repository_checks_spec.rb +++ b/spec/features/admin/admin_uses_repository_checks_spec.rb @@ -19,7 +19,7 @@ RSpec.describe 'Admin uses repository checks', :request_store, feature_category: visit_admin_project_page(project) expect(page).not_to have_css('.repository-check') - expect(page).to have_content('Enter Admin Mode') + expect(page).to have_content('Enter admin mode') end end diff --git a/spec/features/admin/broadcast_messages_spec.rb b/spec/features/admin/broadcast_messages_spec.rb new file mode 100644 index 00000000000..fca4cdb0ff4 --- /dev/null +++ b/spec/features/admin/broadcast_messages_spec.rb @@ -0,0 +1,73 @@ +# frozen_string_literal: true + +require 'spec_helper' + +RSpec.describe 'Admin Broadcast Messages', :js, feature_category: :onboarding do + context 'when creating and editing' do + it 'previews, creates and edits a broadcast message' do + admin = create(:admin) + sign_in(admin) + gitlab_enable_admin_mode_sign_in(admin) + + # create + visit admin_broadcast_messages_path + + fill_in 'Message', with: 'test message' + + wait_for_requests + + page.within(preview_container) do + expect(page).to have_content('test message') + end + + click_button 'Add broadcast message' + + wait_for_requests + + page.within(preview_container) do + expect(page).to have_content('Your message here') + end + + page.within(first_message_container) do + expect(page).to have_content('test message') + end + + # edit + page.within(first_message_container) do + find('[data-testid="edit-message"]').click + end + + wait_for_requests + + expect(find('[data-testid="message-input"]').value).to eq('test message') + + fill_in 'Message', with: 'changed test message' + + wait_for_requests + + page.within(preview_container) do + expect(page).to have_content('changed test message') + end + + click_button 'Update broadcast message' + + wait_for_requests + + page.within(preview_container) do + expect(page).to have_content('Your message here') + end + + page.within(first_message_container) do + expect(page).to have_content('changed test message') + end + end + + def preview_container + find('[data-testid="preview-broadcast-message"]') + end + + def first_message_container + find('[data-testid="message-row"]', match: :first) + end + end +end diff --git a/spec/features/admin/integrations/instance_integrations_spec.rb b/spec/features/admin/integrations/instance_integrations_spec.rb index 3b2ed1d9810..d963aa700eb 100644 --- a/spec/features/admin/integrations/instance_integrations_spec.rb +++ b/spec/features/admin/integrations/instance_integrations_spec.rb @@ -5,6 +5,10 @@ require 'spec_helper' RSpec.describe 'Instance integrations', :js, feature_category: :integrations do include_context 'instance integration activation' + before do + stub_feature_flags(remove_monitor_metrics: false) + end + it_behaves_like 'integration settings form' do let(:integrations) { Integration.find_or_initialize_all_non_project_specific(Integration.for_instance) } diff --git a/spec/features/admin/users/user_spec.rb b/spec/features/admin/users/user_spec.rb index 66129617220..18d62cb585f 100644 --- a/spec/features/admin/users/user_spec.rb +++ b/spec/features/admin/users/user_spec.rb @@ -3,7 +3,7 @@ require 'spec_helper' RSpec.describe 'Admin::Users::User', feature_category: :user_management do - include Spec::Support::Helpers::Features::AdminUsersHelpers + include Features::AdminUsersHelpers include Spec::Support::Helpers::ModalHelpers let_it_be(:user) { create(:omniauth_user, provider: 'twitter', extern_uid: '123456') } @@ -273,8 +273,11 @@ RSpec.describe 'Admin::Users::User', feature_category: :user_management do end context 'when viewing the confirm email warning', :js do - let_it_be(:another_user) { create(:user, :unconfirmed) } + before do + stub_application_setting_enum('email_confirmation_setting', 'soft') + end + let_it_be(:another_user) { create(:user, :unconfirmed) } let(:warning_alert) { page.find(:css, '[data-testid="alert-warning"]') } let(:expected_styling) { { 'pointer-events' => 'none', 'cursor' => 'default' } } diff --git a/spec/features/admin/users/users_spec.rb b/spec/features/admin/users/users_spec.rb index 07db0750074..8e80ce5edd9 100644 --- a/spec/features/admin/users/users_spec.rb +++ b/spec/features/admin/users/users_spec.rb @@ -3,7 +3,7 @@ require 'spec_helper' RSpec.describe 'Admin::Users', feature_category: :user_management do - include Spec::Support::Helpers::Features::AdminUsersHelpers + include Features::AdminUsersHelpers include Spec::Support::Helpers::ModalHelpers include ListboxHelpers @@ -311,6 +311,40 @@ RSpec.describe 'Admin::Users', feature_category: :user_management do end end + describe 'users pending approval' do + it 'sends a welcome email and a password reset email to the user upon admin approval', :sidekiq_inline do + user = create(:user, :blocked_pending_approval, created_by_id: current_user.id) + + visit admin_users_path + + click_link 'Pending approval' + + click_user_dropdown_toggle(user.id) + + find('[data-testid="approve"]').click + + expect(page).to have_content("Approve user #{user.name}?") + + within_modal do + perform_enqueued_jobs do + click_button 'Approve' + end + end + + expect(page).to have_content('Successfully approved') + + welcome_email = ActionMailer::Base.deliveries.find { |m| m.subject == 'Welcome to GitLab!' } + expect(welcome_email.to).to eq([user.email]) + expect(welcome_email.text_part.body).to have_content('Your GitLab account request has been approved!') + + password_reset_email = ActionMailer::Base.deliveries.find { |m| m.subject == 'Account was created for you' } + expect(password_reset_email.to).to eq([user.email]) + expect(password_reset_email.text_part.body).to have_content('Click here to set your password') + + expect(ActionMailer::Base.deliveries.count).to eq(2) + end + end + describe 'internal users' do context 'when showing a `Ghost User`' do let_it_be(:ghost_user) { create(:user, :ghost) } diff --git a/spec/features/admin_variables_spec.rb b/spec/features/admin_variables_spec.rb index d1adbf59984..744d18a3b6d 100644 --- a/spec/features/admin_variables_spec.rb +++ b/spec/features/admin_variables_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' -RSpec.describe 'Instance variables', :js, feature_category: :pipeline_authoring do +RSpec.describe 'Instance variables', :js, feature_category: :secrets_management do let(:admin) { create(:admin) } let(:page_path) { ci_cd_admin_application_settings_path } @@ -12,9 +12,21 @@ RSpec.describe 'Instance variables', :js, feature_category: :pipeline_authoring stub_env('IN_MEMORY_APPLICATION_SETTINGS', 'false') sign_in(admin) gitlab_enable_admin_mode_sign_in(admin) + visit page_path wait_for_requests end - it_behaves_like 'variable list', isAdmin: true + context 'when ci_variables_pages FF is enabled' do + it_behaves_like 'variable list', is_admin: true + it_behaves_like 'variable list pagination', :ci_instance_variable + end + + context 'when ci_variables_pages FF is disabled' do + before do + stub_feature_flags(ci_variables_pages: false) + end + + it_behaves_like 'variable list', is_admin: true + end end diff --git a/spec/features/alerts_settings/user_views_alerts_settings_spec.rb b/spec/features/alerts_settings/user_views_alerts_settings_spec.rb index 70223b2c0d4..94f5cf8f5b2 100644 --- a/spec/features/alerts_settings/user_views_alerts_settings_spec.rb +++ b/spec/features/alerts_settings/user_views_alerts_settings_spec.rb @@ -19,6 +19,7 @@ RSpec.describe 'Alert integrations settings form', :js, feature_category: :incid describe 'when viewing alert integrations as a maintainer' do context 'with the default page permissions' do before do + stub_feature_flags(remove_monitor_metrics: false) visit project_settings_operations_path(project, anchor: 'js-alert-management-settings') wait_for_requests end diff --git a/spec/features/boards/board_filters_spec.rb b/spec/features/boards/board_filters_spec.rb index dee63be8119..006b7ce45d4 100644 --- a/spec/features/boards/board_filters_spec.rb +++ b/spec/features/boards/board_filters_spec.rb @@ -50,7 +50,7 @@ RSpec.describe 'Issue board filters', :js, feature_category: :team_planning do set_filter('assignee') end - it_behaves_like 'loads all the users when opened' do + it_behaves_like 'loads all the users when opened', quarantine: 'https://gitlab.com/gitlab-org/gitlab/-/issues/351426' do let(:issue) { issue_2 } end end diff --git a/spec/features/boards/boards_spec.rb b/spec/features/boards/boards_spec.rb index 3e2e391d060..1ea6e079104 100644 --- a/spec/features/boards/boards_spec.rb +++ b/spec/features/boards/boards_spec.rb @@ -150,8 +150,7 @@ RSpec.describe 'Project issue boards', :js, feature_category: :team_planning do find('.board .board-list') inspect_requests(inject_headers: { 'X-GITLAB-DISABLE-SQL-QUERY-LIMIT' => 'https://gitlab.com/gitlab-org/gitlab/-/issues/323426' }) do - evaluate_script("window.scrollTo(0, document.body.scrollHeight)") - evaluate_script("document.querySelectorAll('.board .board-list')[1].scrollTop = document.querySelectorAll('.board .board-list')[1].scrollHeight") + evaluate_script("[...document.querySelectorAll('.board:nth-child(2) .board-list [data-testid=\"board-card-gl-io\"]')].pop().scrollIntoView()") end expect(page).to have_selector('.board-card', count: 20) @@ -160,8 +159,7 @@ RSpec.describe 'Project issue boards', :js, feature_category: :team_planning do find('.board .board-list') inspect_requests(inject_headers: { 'X-GITLAB-DISABLE-SQL-QUERY-LIMIT' => 'https://gitlab.com/gitlab-org/gitlab/-/issues/323426' }) do - evaluate_script("window.scrollTo(0, document.body.scrollHeight)") - evaluate_script("document.querySelectorAll('.board .board-list')[1].scrollTop = document.querySelectorAll('.board .board-list')[1].scrollHeight") + evaluate_script("[...document.querySelectorAll('.board:nth-child(2) .board-list [data-testid=\"board-card-gl-io\"]')].pop().scrollIntoView()") end expect(page).to have_selector('.board-card', count: 30) @@ -170,8 +168,7 @@ RSpec.describe 'Project issue boards', :js, feature_category: :team_planning do find('.board .board-list') inspect_requests(inject_headers: { 'X-GITLAB-DISABLE-SQL-QUERY-LIMIT' => 'https://gitlab.com/gitlab-org/gitlab/-/issues/323426' }) do - evaluate_script("window.scrollTo(0, document.body.scrollHeight)") - evaluate_script("document.querySelectorAll('.board .board-list')[1].scrollTop = document.querySelectorAll('.board .board-list')[1].scrollHeight") + evaluate_script("[...document.querySelectorAll('.board:nth-child(2) .board-list [data-testid=\"board-card-gl-io\"]')].pop().scrollIntoView()") end expect(page).to have_selector('.board-card', count: 38) @@ -594,7 +591,9 @@ RSpec.describe 'Project issue boards', :js, feature_category: :team_planning do def remove_list page.within(find('.board:nth-child(2)')) do - find('button[title="List settings"]').click + dropdown = first("[data-testid='header-list-actions']") + dropdown.click + click_button('Edit list settings') end page.within(find('.js-board-settings-sidebar')) do diff --git a/spec/features/boards/issue_ordering_spec.rb b/spec/features/boards/issue_ordering_spec.rb index 8aecaab42c2..b6196fa6a1d 100644 --- a/spec/features/boards/issue_ordering_spec.rb +++ b/spec/features/boards/issue_ordering_spec.rb @@ -138,7 +138,7 @@ RSpec.describe 'Issue Boards', :js, feature_category: :team_planning do wait_for_requests end - it 'moves to end of list' do + it 'moves to end of list', quarantine: 'https://gitlab.com/gitlab-org/gitlab/-/issues/410100' do expect(all('.board-card').first).to have_content(issue3.title) page.within(find('.board:nth-child(2)')) do @@ -151,7 +151,7 @@ RSpec.describe 'Issue Boards', :js, feature_category: :team_planning do expect(all('.board-card').last).to have_content(issue3.title) end - it 'moves to start of list' do + it 'moves to start of list', quarantine: 'https://gitlab.com/gitlab-org/gitlab/-/issues/410100' do expect(all('.board-card').last).to have_content(issue1.title) page.within(find('.board:nth-child(2)')) do diff --git a/spec/features/boards/new_issue_spec.rb b/spec/features/boards/new_issue_spec.rb index d597c57ac1c..6753f0ea009 100644 --- a/spec/features/boards/new_issue_spec.rb +++ b/spec/features/boards/new_issue_spec.rb @@ -32,18 +32,23 @@ RSpec.describe 'Issue Boards new issue', :js, feature_category: :team_planning d end it 'displays new issue button' do - expect(first('.board')).to have_button('New issue', count: 1) + dropdown = first("[data-testid='header-list-actions']") + dropdown.click + expect(first('.board')).to have_button('Create new issue', count: 1) end it 'does not display new issue button in closed list' do page.within('.board:nth-child(3)') do - expect(page).not_to have_button('New issue') + expect(page).not_to have_selector("[data-testid='header-list-actions']") + expect(page).not_to have_button('Create new issue') end end it 'shows form when clicking button' do page.within(first('.board')) do - click_button 'New issue' + dropdown = first("[data-testid='header-list-actions']") + dropdown.click + click_button 'Create new issue' expect(page).to have_selector('.board-new-issue-form') end @@ -51,7 +56,9 @@ RSpec.describe 'Issue Boards new issue', :js, feature_category: :team_planning d it 'hides form when clicking cancel' do page.within(first('.board')) do - click_button 'New issue' + dropdown = first("[data-testid='header-list-actions']") + dropdown.click + click_button 'Create new issue' expect(page).to have_selector('.board-new-issue-form') @@ -63,7 +70,9 @@ RSpec.describe 'Issue Boards new issue', :js, feature_category: :team_planning d it 'creates new issue, places it on top of the list, and opens sidebar' do page.within(first('.board')) do - click_button 'New issue' + dropdown = first("[data-testid='header-list-actions']") + dropdown.click + click_button 'Create new issue' end page.within(first('.board-new-issue-form')) do @@ -91,7 +100,9 @@ RSpec.describe 'Issue Boards new issue', :js, feature_category: :team_planning d it 'successfuly loads labels to be added to newly created issue' do page.within(first('.board')) do - click_button 'New issue' + dropdown = first("[data-testid='header-list-actions']") + dropdown.click + click_button 'Create new issue' end page.within(first('.board-new-issue-form')) do @@ -121,7 +132,9 @@ RSpec.describe 'Issue Boards new issue', :js, feature_category: :team_planning d wait_for_all_requests page.within('.board:nth-child(2)') do - click_button('New issue') + dropdown = first("[data-testid='header-list-actions']") + dropdown.click + click_button('Create new issue') page.within(first('.board-new-issue-form')) do find('.form-control').set('new issue') @@ -144,12 +157,14 @@ RSpec.describe 'Issue Boards new issue', :js, feature_category: :team_planning d end it 'does not display new issue button in open list' do - expect(first('.board')).not_to have_button('New issue') + expect(page).not_to have_selector("[data-testid='header-list-actions']") + expect(first('.board')).not_to have_button('Create new issue') end it 'does not display new issue button in label list' do page.within('.board:nth-child(2)') do - expect(page).not_to have_button('New issue') + expect(page).not_to have_selector("[data-testid='header-list-actions']") + expect(page).not_to have_button('Create new issue') end end end @@ -173,7 +188,8 @@ RSpec.describe 'Issue Boards new issue', :js, feature_category: :team_planning d context 'when backlog does not exist' do it 'does not display new issue button in label list' do page.within('.board.is-draggable') do - expect(page).not_to have_button('New issue') + expect(page).not_to have_selector("[data-testid='header-list-actions']") + expect(page).not_to have_button('Create new issue') end end end @@ -182,12 +198,14 @@ RSpec.describe 'Issue Boards new issue', :js, feature_category: :team_planning d let_it_be(:backlog_list) { create(:backlog_list, board: group_board) } it 'does not display new issue button in open list' do - expect(first('.board')).not_to have_button('New issue') + expect(page).not_to have_selector("[data-testid='header-list-actions']") + expect(first('.board')).not_to have_button('Create new issue') end it 'does not display new issue button in label list' do page.within('.board.is-draggable') do - expect(page).not_to have_button('New issue') + expect(page).not_to have_selector("[data-testid='header-list-actions']") + expect(page).not_to have_button('Create new issue') end end end @@ -205,7 +223,9 @@ RSpec.describe 'Issue Boards new issue', :js, feature_category: :team_planning d context 'when backlog does not exist' do it 'display new issue button in label list' do - expect(board_list_header).to have_button('New issue') + dropdown = first("[data-testid='header-list-actions']") + dropdown.click + expect(board_list_header).to have_button('Create new issue') end end @@ -214,7 +234,9 @@ RSpec.describe 'Issue Boards new issue', :js, feature_category: :team_planning d before do page.within(board_list_header) do - click_button 'New issue' + dropdown = first("[data-testid='header-list-actions']") + dropdown.click + click_button 'Create new issue' end project_select_dropdown.click diff --git a/spec/features/boards/sidebar_spec.rb b/spec/features/boards/sidebar_spec.rb index 0a16e95c0bf..358da1e1279 100644 --- a/spec/features/boards/sidebar_spec.rb +++ b/spec/features/boards/sidebar_spec.rb @@ -9,7 +9,7 @@ RSpec.describe 'Project issue boards sidebar', :js, feature_category: :team_plan let_it_be(:group) { create(:group, :public) } let_it_be(:project) { create(:project, :public, namespace: group) } let_it_be(:board) { create(:board, project: project) } - let_it_be(:label) { create(:label, project: project, name: 'Label') } + let_it_be(:label) { create(:label, project: project, name: 'Label') } let_it_be(:list) { create(:list, board: board, label: label, position: 0) } let_it_be(:issue, reload: true) { create(:issue, project: project, relative_position: 1) } diff --git a/spec/features/breadcrumbs_schema_markup_spec.rb b/spec/features/breadcrumbs_schema_markup_spec.rb index d924423c9a9..6610519cd24 100644 --- a/spec/features/breadcrumbs_schema_markup_spec.rb +++ b/spec/features/breadcrumbs_schema_markup_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' -RSpec.describe 'Breadcrumbs schema markup', :aggregate_failures, feature_category: :not_owned do +RSpec.describe 'Breadcrumbs schema markup', :aggregate_failures, feature_category: :shared do let_it_be(:user) { create(:user) } let_it_be(:project) { create(:project, :public, namespace: user.namespace) } let_it_be(:issue) { create(:issue, project: project) } diff --git a/spec/features/broadcast_messages_spec.rb b/spec/features/broadcast_messages_spec.rb index 3e4289347e3..2fad15c8a1f 100644 --- a/spec/features/broadcast_messages_spec.rb +++ b/spec/features/broadcast_messages_spec.rb @@ -7,7 +7,7 @@ RSpec.describe 'Broadcast Messages', feature_category: :onboarding do shared_examples 'a Broadcast Messages' do |type| it 'shows broadcast message' do - visit root_path + visit explore_projects_path expect(page).to have_content 'SampleMessage' end @@ -15,17 +15,17 @@ RSpec.describe 'Broadcast Messages', feature_category: :onboarding do it 'renders styled links' do create(:broadcast_message, type, message: "click me") - visit root_path + visit explore_projects_path expected_html = "

click me

" expect(page.body).to include(expected_html) end end - shared_examples 'a dismissable Broadcast Messages' do + shared_examples 'a dismissible Broadcast Messages' do it 'hides broadcast message after dismiss', :js, quarantine: 'https://gitlab.com/gitlab-org/gitlab/-/issues/390900' do - visit root_path + visit explore_projects_path find('.js-dismiss-current-broadcast-notification').click @@ -34,25 +34,25 @@ RSpec.describe 'Broadcast Messages', feature_category: :onboarding do it 'broadcast message is still hidden after refresh', :js, quarantine: 'https://gitlab.com/gitlab-org/gitlab/-/issues/391406' do - visit root_path + visit explore_projects_path find('.js-dismiss-current-broadcast-notification').click wait_for_cookie_set("hide_broadcast_message_#{broadcast_message.id}") - visit root_path + visit explore_projects_path expect(page).not_to have_content 'SampleMessage' end end describe 'banner type' do - let!(:broadcast_message) { create(:broadcast_message, message: 'SampleMessage') } + let_it_be(:broadcast_message) { create(:broadcast_message, message: 'SampleMessage') } it_behaves_like 'a Broadcast Messages' - it 'is not dismissable' do - visit root_path + it 'is not dismissible' do + visit explore_projects_path expect(page).not_to have_selector('.js-dismiss-current-broadcast-notification') end @@ -62,33 +62,33 @@ RSpec.describe 'Broadcast Messages', feature_category: :onboarding do sign_in(user) - visit root_path + visit explore_projects_path expect(page).to have_content 'Hi {{name}}' end end - describe 'dismissable banner type' do - let!(:broadcast_message) { create(:broadcast_message, dismissable: true, message: 'SampleMessage') } + describe 'dismissible banner type' do + let_it_be(:broadcast_message) { create(:broadcast_message, dismissable: true, message: 'SampleMessage') } it_behaves_like 'a Broadcast Messages' - it_behaves_like 'a dismissable Broadcast Messages' + it_behaves_like 'a dismissible Broadcast Messages' end describe 'notification type' do - let!(:broadcast_message) { create(:broadcast_message, :notification, message: 'SampleMessage') } + let_it_be(:broadcast_message) { create(:broadcast_message, :notification, message: 'SampleMessage') } it_behaves_like 'a Broadcast Messages', :notification - it_behaves_like 'a dismissable Broadcast Messages' + it_behaves_like 'a dismissible Broadcast Messages' it 'replaces placeholders' do create(:broadcast_message, :notification, message: 'Hi {{name}}') sign_in(user) - visit root_path + visit explore_projects_path expect(page).to have_content "Hi #{user.name}" end diff --git a/spec/features/calendar_spec.rb b/spec/features/calendar_spec.rb index b2a29c88b68..67baed5dc91 100644 --- a/spec/features/calendar_spec.rb +++ b/spec/features/calendar_spec.rb @@ -44,15 +44,25 @@ RSpec.describe 'Contributions Calendar', :js, feature_category: :user_profile do "#{get_cell_level_selector(contributions)}[title='#{contribution_text}
#{date}']" end + def get_days_of_week + page.all('[data-testid="user-contrib-cell-group"]')[1] + .all('[data-testid="user-contrib-cell"]') + .map do |node| + node[:title].match(/(Monday|Tuesday|Wednesday|Thursday|Friday|Saturday|Sunday)/)[0] + end + end + def push_code_contribution event = create(:push_event, project: contributed_project, author: user) - create(:push_event_payload, - event: event, - commit_from: '11f9ac0a48b62cef25eedede4c1819964f08d5ce', - commit_to: '1cf19a015df3523caf0a1f9d40c98a267d6a2fc2', - commit_count: 3, - ref: 'master') + create( + :push_event_payload, + event: event, + commit_from: '11f9ac0a48b62cef25eedede4c1819964f08d5ce', + commit_to: '1cf19a015df3523caf0a1f9d40c98a267d6a2fc2', + commit_count: 3, + ref: 'master' + ) end def note_comment_contribution @@ -70,162 +80,331 @@ RSpec.describe 'Contributions Calendar', :js, feature_category: :user_profile do find('#js-overview .user-calendar-activities', visible: visible).text end - before do - stub_feature_flags(profile_tabs_vue: false) - sign_in user - end - - describe 'calendar day selection' do + shared_context 'when user page is visited' do before do visit user.username - page.find('.js-overview-tab a').click + page.click_link('Overview') wait_for_requests end + end - it 'displays calendar' do - expect(find('#js-overview')).to have_css('.js-contrib-calendar') + context 'with `profile_tabs_vue` feature flag disabled' do + before do + stub_feature_flags(profile_tabs_vue: false) + sign_in user end - describe 'select calendar day' do - let(:cells) { page.all('#js-overview .user-contrib-cell') } + describe 'calendar day selection' do + include_context 'when user page is visited' - before do - cells[0].click - wait_for_requests - @first_day_activities = selected_day_activities + it 'displays calendar' do + expect(find('#js-overview')).to have_css('.js-contrib-calendar') end - it 'displays calendar day activities' do - expect(selected_day_activities).not_to be_empty - end + describe 'select calendar day' do + let(:cells) { page.all('#js-overview .user-contrib-cell') } - describe 'select another calendar day' do before do - cells[1].click + cells[0].click wait_for_requests end - it 'displays different calendar day activities' do - expect(selected_day_activities).not_to eq(@first_day_activities) + it 'displays calendar day activities' do + expect(selected_day_activities).not_to be_empty end - end - describe 'deselect calendar day' do - before do - cells[0].click - wait_for_requests - cells[0].click + describe 'select another calendar day' do + it 'displays different calendar day activities' do + first_day_activities = selected_day_activities + + cells[1].click + wait_for_requests + + expect(selected_day_activities).not_to eq(first_day_activities) + end end - it 'hides calendar day activities' do - expect(selected_day_activities(visible: false)).to be_empty + describe 'deselect calendar day' do + before do + cells[0].click + wait_for_requests + cells[0].click + end + + it 'hides calendar day activities' do + expect(selected_day_activities(visible: false)).to be_empty + end end end end - end - shared_context 'visit user page' do - before do - visit user.username - page.find('.js-overview-tab a').click - wait_for_requests - end - end + describe 'calendar daily activities' do + shared_examples 'a day with activity' do |contribution_count:| + include_context 'when user page is visited' + + it 'displays calendar activity square for 1 contribution', :sidekiq_inline do + expect(find('#js-overview')).to have_selector(get_cell_level_selector(contribution_count), count: 1) + + today = Date.today.strftime(date_format) + expect(find('#js-overview')).to have_selector(get_cell_date_selector(contribution_count, today), count: 1) + end + end - describe 'calendar daily activities' do - shared_examples 'a day with activity' do |contribution_count:| - include_context 'visit user page' + describe '1 issue and 1 work item creation calendar activity' do + before do + Issues::CreateService.new( + container: contributed_project, + current_user: user, + params: issue_params, + spam_params: nil + ).execute + WorkItems::CreateService.new( + container: contributed_project, + current_user: user, + params: { title: 'new task' }, + spam_params: nil + ).execute + end - it 'displays calendar activity square for 1 contribution', :sidekiq_might_not_need_inline do - expect(find('#js-overview')).to have_selector(get_cell_level_selector(contribution_count), count: 1) + it_behaves_like 'a day with activity', contribution_count: 2 - today = Date.today.strftime(date_format) - expect(find('#js-overview')).to have_selector(get_cell_date_selector(contribution_count, today), count: 1) + describe 'issue title is shown on activity page' do + include_context 'when user page is visited' + + it 'displays calendar activity log', :sidekiq_inline do + expect(all('#js-overview .overview-content-list .event-target-title').map(&:text)).to contain_exactly( + match(/#{issue_title}/), + match(/new task/) + ) + end + end end - end - describe '1 issue and 1 work item creation calendar activity' do - before do - Issues::CreateService.new(container: contributed_project, current_user: user, params: issue_params, spam_params: nil).execute - WorkItems::CreateService.new( - container: contributed_project, - current_user: user, - params: { title: 'new task' }, - spam_params: nil - ).execute + describe '1 comment calendar activity' do + before do + note_comment_contribution + end + + it_behaves_like 'a day with activity', contribution_count: 1 end - it_behaves_like 'a day with activity', contribution_count: 2 + describe '10 calendar activities' do + before do + 10.times { push_code_contribution } + end + + it_behaves_like 'a day with activity', contribution_count: 10 + end + + describe 'calendar activity on two days' do + before do + push_code_contribution + + travel_to(Date.yesterday) do + Issues::CreateService.new( + container: contributed_project, + current_user: user, + params: issue_params, + spam_params: nil + ).execute + end + end + + include_context 'when user page is visited' - describe 'issue title is shown on activity page' do - include_context 'visit user page' + it 'displays calendar activity squares for both days', :sidekiq_inline do + expect(find('#js-overview')).to have_selector(get_cell_level_selector(1), count: 2) + end - it 'displays calendar activity log', :sidekiq_inline do - expect(all('#js-overview .overview-content-list .event-target-title').map(&:text)).to contain_exactly( - match(/#{issue_title}/), - match(/new task/) - ) + it 'displays calendar activity square for yesterday', :sidekiq_inline do + yesterday = Date.yesterday.strftime(date_format) + expect(find('#js-overview')).to have_selector(get_cell_date_selector(1, yesterday), count: 1) + end + + it 'displays calendar activity square for today' do + today = Date.today.strftime(date_format) + expect(find('#js-overview')).to have_selector(get_cell_date_selector(1, today), count: 1) end end end - describe '1 comment calendar activity' do - before do - note_comment_contribution + describe 'on smaller screens' do + shared_examples 'hidden activity calendar' do + include_context 'when user page is visited' + + it 'hides the activity calender' do + expect(find('#js-overview')).not_to have_css('.js-contrib-calendar') + end end - it_behaves_like 'a day with activity', contribution_count: 1 + context 'when screen size is xs' do + before do + resize_screen_xs + end + + it_behaves_like 'hidden activity calendar' + end end - describe '10 calendar activities' do - before do - 10.times { push_code_contribution } + describe 'first_day_of_week setting' do + context 'when first day of the week is set to Monday' do + before do + stub_application_setting(first_day_of_week: 1) + end + + include_context 'when user page is visited' + + it 'shows calendar with Monday as the first day of the week' do + expect(get_days_of_week).to eq(%w[Monday Tuesday Wednesday Thursday Friday Saturday Sunday]) + end + end + + context 'when first day of the week is set to Sunday' do + before do + stub_application_setting(first_day_of_week: 0) + end + + include_context 'when user page is visited' + + it 'shows calendar with Sunday as the first day of the week' do + expect(get_days_of_week).to eq(%w[Sunday Monday Tuesday Wednesday Thursday Friday Saturday]) + end end + end + end + + context 'with `profile_tabs_vue` feature flag enabled' do + before do + sign_in user + end - it_behaves_like 'a day with activity', contribution_count: 10 + include_context 'when user page is visited' + + it 'displays calendar' do + expect(page).to have_css('[data-testid="contrib-calendar"]') end - describe 'calendar activity on two days' do - before do - push_code_contribution + describe 'calendar daily activities' do + shared_examples 'a day with activity' do |contribution_count:| + include_context 'when user page is visited' - travel_to(Date.yesterday) do - Issues::CreateService.new(container: contributed_project, current_user: user, params: issue_params, spam_params: nil).execute + it 'displays calendar activity square for 1 contribution', :sidekiq_inline do + expect(page).to have_selector(get_cell_level_selector(contribution_count), count: 1) + + today = Date.today.strftime(date_format) + expect(page).to have_selector(get_cell_date_selector(contribution_count, today), count: 1) end end - include_context 'visit user page' - it 'displays calendar activity squares for both days', :sidekiq_might_not_need_inline do - expect(find('#js-overview')).to have_selector(get_cell_level_selector(1), count: 2) + describe '1 issue and 1 work item creation calendar activity' do + before do + Issues::CreateService.new( + container: contributed_project, + current_user: user, + params: issue_params, + spam_params: nil + ).execute + WorkItems::CreateService.new( + container: contributed_project, + current_user: user, + params: { title: 'new task' }, + spam_params: nil + ).execute + end + + it_behaves_like 'a day with activity', contribution_count: 2 end - it 'displays calendar activity square for yesterday', :sidekiq_might_not_need_inline do - yesterday = Date.yesterday.strftime(date_format) - expect(find('#js-overview')).to have_selector(get_cell_date_selector(1, yesterday), count: 1) + describe '1 comment calendar activity' do + before do + note_comment_contribution + end + + it_behaves_like 'a day with activity', contribution_count: 1 end - it 'displays calendar activity square for today' do - today = Date.today.strftime(date_format) - expect(find('#js-overview')).to have_selector(get_cell_date_selector(1, today), count: 1) + describe '10 calendar activities' do + before do + 10.times { push_code_contribution } + end + + it_behaves_like 'a day with activity', contribution_count: 10 + end + + describe 'calendar activity on two days' do + before do + push_code_contribution + + travel_to(Date.yesterday) do + Issues::CreateService.new( + container: contributed_project, + current_user: user, + params: issue_params, + spam_params: nil + ).execute + end + end + + include_context 'when user page is visited' + + it 'displays calendar activity squares for both days', :sidekiq_inline do + expect(page).to have_selector(get_cell_level_selector(1), count: 2) + end + + it 'displays calendar activity square for yesterday', :sidekiq_inline do + yesterday = Date.yesterday.strftime(date_format) + expect(page).to have_selector(get_cell_date_selector(1, yesterday), count: 1) + end + + it 'displays calendar activity square for today' do + today = Date.today.strftime(date_format) + expect(page).to have_selector(get_cell_date_selector(1, today), count: 1) + end end end - end - describe 'on smaller screens' do - shared_examples 'hidden activity calendar' do - include_context 'visit user page' + describe 'on smaller screens' do + shared_examples 'hidden activity calendar' do + include_context 'when user page is visited' - it 'hides the activity calender' do - expect(find('#js-overview')).not_to have_css('.js-contrib-calendar') + it 'hides the activity calender' do + expect(page).not_to have_css('[data-testid="contrib-calendar"]') + end + end + + context 'when screen size is xs' do + before do + resize_screen_xs + end + + it_behaves_like 'hidden activity calendar' end end - context 'size xs' do - before do - resize_screen_xs + describe 'first_day_of_week setting' do + context 'when first day of the week is set to Monday' do + before do + stub_application_setting(first_day_of_week: 1) + end + + include_context 'when user page is visited' + + it 'shows calendar with Monday as the first day of the week' do + expect(get_days_of_week).to eq(%w[Monday Tuesday Wednesday Thursday Friday Saturday Sunday]) + end end - it_behaves_like 'hidden activity calendar' + context 'when first day of the week is set to Sunday' do + before do + stub_application_setting(first_day_of_week: 0) + end + + include_context 'when user page is visited' + + it 'shows calendar with Sunday as the first day of the week' do + expect(get_days_of_week).to eq(%w[Sunday Monday Tuesday Wednesday Thursday Friday Saturday]) + end + end end end end diff --git a/spec/features/callouts/registration_enabled_spec.rb b/spec/features/callouts/registration_enabled_spec.rb index 15c900592a1..3282a40854d 100644 --- a/spec/features/callouts/registration_enabled_spec.rb +++ b/spec/features/callouts/registration_enabled_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' -RSpec.describe 'Registration enabled callout', feature_category: :authentication_and_authorization do +RSpec.describe 'Registration enabled callout', feature_category: :system_access do let_it_be(:admin) { create(:admin) } let_it_be(:non_admin) { create(:user) } let_it_be(:project) { create(:project) } diff --git a/spec/features/canonical_link_spec.rb b/spec/features/canonical_link_spec.rb index d8f9a7584e7..0ed76c30ce4 100644 --- a/spec/features/canonical_link_spec.rb +++ b/spec/features/canonical_link_spec.rb @@ -3,7 +3,7 @@ require 'spec_helper' RSpec.describe 'Canonical link', feature_category: :remote_development do - include Spec::Support::Helpers::Features::CanonicalLinkHelpers + include Features::CanonicalLinkHelpers let_it_be(:user) { create(:user) } let_it_be(:project) { create(:project, :public, namespace: user.namespace) } diff --git a/spec/features/clusters/cluster_detail_page_spec.rb b/spec/features/clusters/cluster_detail_page_spec.rb index e8fb5f4105d..31dec5e38da 100644 --- a/spec/features/clusters/cluster_detail_page_spec.rb +++ b/spec/features/clusters/cluster_detail_page_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' -RSpec.describe 'Clusterable > Show page', feature_category: :kubernetes_management do +RSpec.describe 'Clusterable > Show page', feature_category: :deployment_management do include KubernetesHelpers let(:current_user) { create(:user) } diff --git a/spec/features/clusters/cluster_health_dashboard_spec.rb b/spec/features/clusters/cluster_health_dashboard_spec.rb index b557f803a99..e932f8c6b98 100644 --- a/spec/features/clusters/cluster_health_dashboard_spec.rb +++ b/spec/features/clusters/cluster_health_dashboard_spec.rb @@ -3,7 +3,7 @@ require 'spec_helper' RSpec.describe 'Cluster Health board', :js, :kubeclient, :use_clean_rails_memory_store_caching, :sidekiq_inline, -feature_category: :kubernetes_management do +feature_category: :deployment_management do include KubernetesHelpers include PrometheusHelpers @@ -13,6 +13,8 @@ feature_category: :kubernetes_management do let_it_be(:cluster_path) { project_cluster_path(clusterable, cluster) } before do + stub_feature_flags(remove_monitor_metrics: false) + clusterable.add_maintainer(current_user) sign_in(current_user) @@ -28,6 +30,24 @@ feature_category: :kubernetes_management do expect(page).to have_css('.cluster-health-graphs') end + context 'feature remove_monitor_metrics enabled' do + before do + stub_feature_flags(remove_monitor_metrics: true) + end + + it 'does not show the cluster health tab' do + visit cluster_path + + expect(page).not_to have_text('Health') + end + + it 'does not show the cluster health section' do + visit project_cluster_path(clusterable, cluster, { tab: 'health' }) + + expect(page).not_to have_text('you must first enable Prometheus in the Integrations tab') + end + end + context 'no prometheus available' do it 'shows enable Prometheus message' do visit cluster_path diff --git a/spec/features/clusters/create_agent_spec.rb b/spec/features/clusters/create_agent_spec.rb index 01902c36e99..93a49151978 100644 --- a/spec/features/clusters/create_agent_spec.rb +++ b/spec/features/clusters/create_agent_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' -RSpec.describe 'Cluster agent registration', :js, feature_category: :kubernetes_management do +RSpec.describe 'Cluster agent registration', :js, feature_category: :deployment_management do let_it_be(:project) { create(:project, :custom_repo, files: { '.gitlab/agents/example-agent-1/config.yaml' => '' }) } let_it_be(:current_user) { create(:user, maintainer_projects: [project]) } let_it_be(:token) { Devise.friendly_token } diff --git a/spec/features/commit_spec.rb b/spec/features/commit_spec.rb index a9672569a4a..dd96b763e55 100644 --- a/spec/features/commit_spec.rb +++ b/spec/features/commit_spec.rb @@ -6,7 +6,7 @@ RSpec.describe 'Commit', feature_category: :source_code_management do let_it_be(:project) { create(:project, :repository) } let_it_be(:user) { create(:user) } - describe "single commit view" do + shared_examples "single commit view" do let(:commit) do project.repository.commits(nil, limit: 100).find do |commit| commit.diffs.size > 1 @@ -16,7 +16,6 @@ RSpec.describe 'Commit', feature_category: :source_code_management do let(:files) { commit.diffs.diff_files.to_a } before do - stub_feature_flags(async_commit_diff_files: false) project.add_maintainer(user) sign_in(user) end @@ -28,15 +27,9 @@ RSpec.describe 'Commit', feature_category: :source_code_management do visit project_commit_path(project, commit) end - it "shows the short commit message" do + it "shows the short commit message, number of total changes and stats", :js, :aggregate_failures do expect(page).to have_content(commit.title) - end - - it "reports the correct number of total changes" do expect(page).to have_content("Changes #{commit.diffs.size}") - end - - it 'renders diff stats', :js do expect(page).to have_selector(".diff-stats") end @@ -50,23 +43,36 @@ RSpec.describe 'Commit', feature_category: :source_code_management do visit project_commit_path(project, commit) end - it "shows an adjusted count for changed files on this page", :js do - expect(page).to have_content("Showing 1 changed file") + def diff_files_on_page + page.all('.files .diff-file').pluck(:id) end - it "shows only the first diff on the first page" do - expect(page).to have_selector(".files ##{files[0].file_hash}") - expect(page).not_to have_selector(".files ##{files[1].file_hash}") - end + it "shows paginated content and controls to navigate", :js, :aggregate_failures do + expect(page).to have_content("Showing 1 changed file") + + wait_for_requests + + expect(diff_files_on_page).to eq([files[0].file_hash]) - it "can navigate to the second page" do within(".files .gl-pagination") do click_on("2") end - expect(page).not_to have_selector(".files ##{files[0].file_hash}") - expect(page).to have_selector(".files ##{files[1].file_hash}") + wait_for_requests + + expect(diff_files_on_page).to eq([files[1].file_hash]) end end end + + it_behaves_like "single commit view" + + context "when super sidebar is enabled" do + before do + user.update!(use_new_navigation: true) + stub_feature_flags(super_sidebar_nav: true) + end + + it_behaves_like "single commit view" + end end diff --git a/spec/features/commits/user_uses_quick_actions_spec.rb b/spec/features/commits/user_uses_quick_actions_spec.rb index 6d043a0bb2f..c83a30c99c3 100644 --- a/spec/features/commits/user_uses_quick_actions_spec.rb +++ b/spec/features/commits/user_uses_quick_actions_spec.rb @@ -3,7 +3,7 @@ require 'spec_helper' RSpec.describe 'Commit > User uses quick actions', :js, feature_category: :source_code_management do - include Spec::Support::Helpers::Features::NotesHelpers + include Features::NotesHelpers include RepoHelpers let(:project) { create(:project, :public, :repository) } diff --git a/spec/features/commits_spec.rb b/spec/features/commits_spec.rb index eafe74f4b0b..c38ae0c2b0d 100644 --- a/spec/features/commits_spec.rb +++ b/spec/features/commits_spec.rb @@ -107,7 +107,7 @@ RSpec.describe 'Commits', feature_category: :source_code_management do describe 'Cancel all builds' do it 'cancels commit', :js, :sidekiq_might_not_need_inline do visit pipeline_path(pipeline) - click_on 'Cancel running' + click_on 'Cancel pipeline' expect(page).to have_content 'canceled' end end @@ -133,7 +133,7 @@ RSpec.describe 'Commits', feature_category: :source_code_management do expect(page).to have_content pipeline.sha[0..7] expect(page).to have_content pipeline.git_commit_message.gsub!(/\s+/, ' ') expect(page).to have_content pipeline.user.name - expect(page).not_to have_link('Cancel running') + expect(page).not_to have_link('Cancel pipeline') expect(page).not_to have_link('Retry') end @@ -156,7 +156,7 @@ RSpec.describe 'Commits', feature_category: :source_code_management do expect(page).to have_content pipeline.git_commit_message.gsub!(/\s+/, ' ') expect(page).to have_content pipeline.user.name - expect(page).not_to have_link('Cancel running') + expect(page).not_to have_link('Cancel pipeline') expect(page).not_to have_link('Retry') end end @@ -165,10 +165,24 @@ RSpec.describe 'Commits', feature_category: :source_code_management do context 'viewing commits for a branch' do let(:branch_name) { 'master' } + let(:ref_selector) { '.ref-selector' } + let(:ref_with_hash) { 'ref-#-hash' } + + def switch_ref_to(ref_name) + first(ref_selector).click + wait_for_requests + + page.within ref_selector do + fill_in 'Search by Git revision', with: ref_name + wait_for_requests + find('li', text: ref_name, match: :prefer_exact).click + end + end before do project.add_maintainer(user) sign_in(user) + project.repository.create_branch(ref_with_hash, branch_name) visit project_commits_path(project, branch_name) end @@ -180,11 +194,17 @@ RSpec.describe 'Commits', feature_category: :source_code_management do end end + it 'switches ref to ref containing a hash', :js do + switch_ref_to(ref_with_hash) + + expect(page).to have_selector ref_selector, text: ref_with_hash + end + it 'shows the ref switcher with the multi-file editor enabled', :js do set_cookie('new_repo', 'true') visit project_commits_path(project, branch_name) - expect(find('.ref-selector')).to have_content branch_name + expect(find(ref_selector)).to have_content branch_name end end diff --git a/spec/features/contextual_sidebar_spec.rb b/spec/features/contextual_sidebar_spec.rb index 2b671d4b3f1..132c8eb7192 100644 --- a/spec/features/contextual_sidebar_spec.rb +++ b/spec/features/contextual_sidebar_spec.rb @@ -39,74 +39,5 @@ RSpec.describe 'Contextual sidebar', :js, feature_category: :remote_development expect(page).to have_selector('.is-showing-fly-out') end end - - context 'with invite_members_in_side_nav experiment', :experiment do - it 'allows opening of modal for the candidate experience' do - stub_experiments(invite_members_in_side_nav: :candidate) - expect(experiment(:invite_members_in_side_nav)).to track(:assignment) - .with_context(group: project.group) - .on_next_instance - - visit project_path(project) - - page.within '[data-test-id="side-nav-invite-members"' do - find('[data-test-id="invite-members-button"').click - end - - expect(page).to have_content("You're inviting members to the") - end - - it 'does not have invite members link in side nav for the control experience' do - stub_experiments(invite_members_in_side_nav: :control) - expect(experiment(:invite_members_in_side_nav)).to track(:assignment) - .with_context(group: project.group) - .on_next_instance - - visit project_path(project) - - expect(page).not_to have_css('[data-test-id="side-nav-invite-members"') - end - end - end - - context 'when context is a group' do - let_it_be(:user) { create(:user) } - let_it_be(:group) do - create(:group).tap do |g| - g.add_owner(user) - end - end - - before do - sign_in(user) - end - - context 'with invite_members_in_side_nav experiment', :experiment do - it 'allows opening of modal for the candidate experience' do - stub_experiments(invite_members_in_side_nav: :candidate) - expect(experiment(:invite_members_in_side_nav)).to track(:assignment) - .with_context(group: group) - .on_next_instance - - visit group_path(group) - - page.within '[data-test-id="side-nav-invite-members"' do - find('[data-test-id="invite-members-button"').click - end - - expect(page).to have_content("You're inviting members to the") - end - - it 'does not have invite members link in side nav for the control experience' do - stub_experiments(invite_members_in_side_nav: :control) - expect(experiment(:invite_members_in_side_nav)).to track(:assignment) - .with_context(group: group) - .on_next_instance - - visit group_path(group) - - expect(page).not_to have_css('[data-test-id="side-nav-invite-members"') - end - end end end diff --git a/spec/features/cycle_analytics_spec.rb b/spec/features/cycle_analytics_spec.rb index 55bf77d00b1..56272f58e0d 100644 --- a/spec/features/cycle_analytics_spec.rb +++ b/spec/features/cycle_analytics_spec.rb @@ -47,12 +47,12 @@ RSpec.describe 'Value Stream Analytics', :js, feature_category: :value_stream_ma end it 'displays metrics with relevant values' do - expect(metrics_values).to eq(['-'] * 4) + expect(metrics_values).to eq(['-'] * 3) end it 'shows active stage with empty message' do expect(page).to have_selector('.gl-path-active-item-indigo', text: 'Issue') - expect(page).to have_content("We don't have enough data to show this stage.") + expect(page).to have_content("There are 0 items to show in this stage, for these filters, within this time range.") end end @@ -98,7 +98,6 @@ RSpec.describe 'Value Stream Analytics', :js, feature_category: :value_stream_ma aggregate_failures 'with relevant values' do expect(metrics_tiles).to have_content('Commit') expect(metrics_tiles).to have_content('Deploy') - expect(metrics_tiles).to have_content('Deployment Frequency') expect(metrics_tiles).to have_content('New Issue') end end @@ -132,11 +131,11 @@ RSpec.describe 'Value Stream Analytics', :js, feature_category: :value_stream_ma end it 'can filter the metrics by date' do - expect(metrics_values).to match_array(%w[21 2 1 0]) + expect(metrics_values).to match_array(%w[21 2 1]) set_daterange(from, to) - expect(metrics_values).to eq(['-'] * 4) + expect(metrics_values).to eq(['-'] * 3) end it 'can sort records', quarantine: 'https://gitlab.com/gitlab-org/gitlab/-/issues/338332' do diff --git a/spec/features/dashboard/activity_spec.rb b/spec/features/dashboard/activity_spec.rb index 2f9b7bb7e0f..2345e4be722 100644 --- a/spec/features/dashboard/activity_spec.rb +++ b/spec/features/dashboard/activity_spec.rb @@ -9,7 +9,7 @@ RSpec.describe 'Dashboard > Activity', feature_category: :user_profile do sign_in(user) end - it_behaves_like 'a dashboard page with sidebar', :activity_dashboard_path, :activity + it_behaves_like 'a "Your work" page with sidebar and breadcrumbs', :activity_dashboard_path, :activity context 'tabs' do it 'shows Your Activity' do diff --git a/spec/features/dashboard/group_dashboard_with_external_authorization_service_spec.rb b/spec/features/dashboard/group_dashboard_with_external_authorization_service_spec.rb index f5b02a87758..3040c97a16f 100644 --- a/spec/features/dashboard/group_dashboard_with_external_authorization_service_spec.rb +++ b/spec/features/dashboard/group_dashboard_with_external_authorization_service_spec.rb @@ -4,7 +4,7 @@ require 'spec_helper' RSpec.describe 'The group dashboard', :js, feature_category: :subgroups do include ExternalAuthorizationServiceHelpers - include Spec::Support::Helpers::Features::TopNavSpecHelpers + include Features::TopNavSpecHelpers let(:user) { create(:user) } @@ -21,9 +21,8 @@ RSpec.describe 'The group dashboard', :js, feature_category: :subgroups do within_top_nav do expect(page).to have_button('Projects') expect(page).to have_button('Groups') - expect(page).to have_link('Activity') - expect(page).to have_link('Milestones') - expect(page).to have_link('Snippets') + expect(page).to have_link('Your work') + expect(page).to have_link('Explore') end end @@ -36,9 +35,8 @@ RSpec.describe 'The group dashboard', :js, feature_category: :subgroups do within_top_nav do expect(page).to have_button('Projects') expect(page).to have_button('Groups') - expect(page).not_to have_link('Activity') - expect(page).not_to have_link('Milestones') - expect(page).to have_link('Snippets') + expect(page).to have_link('Your work') + expect(page).to have_link('Explore') end end end diff --git a/spec/features/dashboard/groups_list_spec.rb b/spec/features/dashboard/groups_list_spec.rb index a45e0a58ed6..7112b30957a 100644 --- a/spec/features/dashboard/groups_list_spec.rb +++ b/spec/features/dashboard/groups_list_spec.rb @@ -19,7 +19,7 @@ RSpec.describe 'Dashboard Groups page', :js, feature_category: :subgroups do page.find("[data-testid='group-#{group.id}-dropdown-button'").click end - it_behaves_like 'a dashboard page with sidebar', :dashboard_groups_path, :groups + it_behaves_like 'a "Your work" page with sidebar and breadcrumbs', :dashboard_groups_path, :groups it 'shows groups user is member of' do group.add_owner(user) @@ -230,4 +230,11 @@ RSpec.describe 'Dashboard Groups page', :js, feature_category: :subgroups do expect(page).not_to have_content(another_group.name) end end + + it 'links to the "Explore groups" page' do + sign_in(user) + visit dashboard_groups_path + + expect(page).to have_link("Explore groups", href: explore_groups_path) + end end diff --git a/spec/features/dashboard/issuables_counter_spec.rb b/spec/features/dashboard/issuables_counter_spec.rb index 5dc59cfa841..5e6ec007569 100644 --- a/spec/features/dashboard/issuables_counter_spec.rb +++ b/spec/features/dashboard/issuables_counter_spec.rb @@ -14,7 +14,7 @@ RSpec.describe 'Navigation bar counter', :use_clean_rails_memory_store_caching, sign_in(user) end - it 'reflects dashboard issues count' do + it 'reflects dashboard issues count', :js do visit issues_path expect_counters('issues', '1', n_("%d assigned issue", "%d assigned issues", 1) % 1) diff --git a/spec/features/dashboard/issues_filter_spec.rb b/spec/features/dashboard/issues_filter_spec.rb index a7734ed50c2..964ac2f714d 100644 --- a/spec/features/dashboard/issues_filter_spec.rb +++ b/spec/features/dashboard/issues_filter_spec.rb @@ -3,48 +3,60 @@ require 'spec_helper' RSpec.describe 'Dashboard Issues filtering', :js, feature_category: :team_planning do - include Spec::Support::Helpers::Features::SortingHelpers + include Features::SortingHelpers include FilteredSearchHelpers - let(:user) { create(:user) } - let(:project) { create(:project) } - let(:milestone) { create(:milestone, project: project) } + let_it_be(:user) { create(:user) } + let_it_be(:project) { create(:project) } + let_it_be(:milestone) { create(:milestone, project: project) } - let!(:issue) { create(:issue, project: project, author: user, assignees: [user]) } - let!(:issue2) { create(:issue, project: project, author: user, assignees: [user], milestone: milestone) } + let_it_be(:issue) { create(:issue, project: project, author: user, assignees: [user]) } + let_it_be(:issue2) { create(:issue, project: project, author: user, assignees: [user], milestone: milestone) } + let_it_be(:label) { create(:label, project: project, title: 'bug') } + let_it_be(:label_link) { create(:label_link, label: label, target: issue) } + + let_it_be(:project2) { create(:project, namespace: user.namespace) } + let_it_be(:label2) { create(:label, title: 'bug') } before do + project.labels << label + project2.labels << label2 project.add_maintainer(user) sign_in(user) - - visit_issues end context 'without any filter' do it 'shows error message' do + visit issues_dashboard_path + expect(page).to have_content 'Please select at least one filter to see results' end end context 'filtering by milestone' do it 'shows all issues with no milestone' do - input_filtered_search("milestone:=none") + visit issues_dashboard_path + + select_tokens 'Milestone', '=', 'None', submit: true expect(page).to have_issuable_counts(open: 1, closed: 0, all: 1) expect(page).to have_selector('.issue', count: 1) end it 'shows all issues with the selected milestone' do - input_filtered_search("milestone:=%\"#{milestone.title}\"") + visit issues_dashboard_path + + select_tokens 'Milestone', '=', milestone.title, submit: true expect(page).to have_issuable_counts(open: 1, closed: 0, all: 1) expect(page).to have_selector('.issue', count: 1) end it 'updates atom feed link' do - visit_issues(milestone_title: '', assignee_username: user.username) + visit issues_dashboard_path(milestone_title: '', assignee_username: user.username) + click_button 'Actions' - link = find('[data-testid="rss-feed-link"]') + link = find_link('Subscribe to RSS feed') params = CGI.parse(URI.parse(link[:href]).query) auto_discovery_link = find('link[type="application/atom+xml"]', visible: false) auto_discovery_params = CGI.parse(URI.parse(auto_discovery_link[:href]).query) @@ -59,40 +71,47 @@ RSpec.describe 'Dashboard Issues filtering', :js, feature_category: :team_planni end context 'filtering by label' do - let(:label) { create(:label, project: project) } - let!(:label_link) { create(:label_link, label: label, target: issue) } + before do + visit issues_dashboard_path + end it 'shows all issues with the selected label' do - input_filtered_search("label:=~#{label.title}") + select_tokens 'Label', '=', label.title, submit: true - page.within 'ul.content-list' do - expect(page).to have_content issue.title - expect(page).not_to have_content issue2.title - end + expect(page).to have_content issue.title + expect(page).not_to have_content issue2.title + end + + it 'removes duplicate labels' do + select_tokens 'Label', '=' + send_keys 'bu' + + expect_suggestion('bug') + expect_suggestion_count(3) # Expect None, Any, and bug end end context 'sorting' do before do - visit_issues(assignee_username: user.username) + visit issues_dashboard_path(assignee_username: user.username) end - it 'remembers last sorting value' do - pajamas_sort_by(s_('SortOptions|Created date')) - visit_issues(assignee_username: user.username) + it 'remembers last sorting value', quarantine: 'https://gitlab.com/gitlab-org/gitlab/-/issues/408749' do + click_button 'Created date' + click_button 'Updated date' + + visit issues_dashboard_path(assignee_username: user.username) - expect(page).to have_button('Created date') + expect(page).to have_button('Updated date') end it 'keeps sorting issues after visiting Projects Issues page' do - pajamas_sort_by(s_('SortOptions|Created date')) + click_button 'Created date' + click_button 'Due date' + visit project_issues_path(project) - expect(page).to have_button('Created date') + expect(page).to have_button('Due date') end end - - def visit_issues(...) - visit issues_dashboard_path(...) - end end diff --git a/spec/features/dashboard/issues_spec.rb b/spec/features/dashboard/issues_spec.rb index 654cc9978a7..70d9f7e5137 100644 --- a/spec/features/dashboard/issues_spec.rb +++ b/spec/features/dashboard/issues_spec.rb @@ -5,15 +5,15 @@ require 'spec_helper' RSpec.describe 'Dashboard Issues', feature_category: :team_planning do include FilteredSearchHelpers - let(:current_user) { create :user } - let(:user) { current_user } # Shared examples depend on this being available - let!(:public_project) { create(:project, :public) } - let(:project) { create(:project) } - let(:project_with_issues_disabled) { create(:project, :issues_disabled) } - let!(:authored_issue) { create :issue, author: current_user, project: project } - let!(:authored_issue_on_public_project) { create :issue, author: current_user, project: public_project } - let!(:assigned_issue) { create :issue, assignees: [current_user], project: project } - let!(:other_issue) { create :issue, project: project } + let_it_be(:current_user) { create :user } + let_it_be(:user) { current_user } # Shared examples depend on this being available + let_it_be(:public_project) { create(:project, :public) } + let_it_be(:project) { create(:project) } + let_it_be(:project_with_issues_disabled) { create(:project, :issues_disabled) } + let_it_be(:authored_issue) { create :issue, author: current_user, project: project } + let_it_be(:authored_issue_on_public_project) { create :issue, author: current_user, project: public_project } + let_it_be(:assigned_issue) { create :issue, assignees: [current_user], project: project } + let_it_be(:other_issue) { create :issue, project: project } before do [project, project_with_issues_disabled].each { |project| project.add_maintainer(current_user) } @@ -21,18 +21,18 @@ RSpec.describe 'Dashboard Issues', feature_category: :team_planning do visit issues_dashboard_path(assignee_username: current_user.username) end - it_behaves_like 'a dashboard page with sidebar', :issues_dashboard_path, :issues + it_behaves_like 'a "Your work" page with sidebar and breadcrumbs', :issues_dashboard_path, :issues - describe 'issues' do + describe 'issues', :js do it 'shows issues assigned to current user' do expect(page).to have_content(assigned_issue.title) expect(page).not_to have_content(authored_issue.title) expect(page).not_to have_content(other_issue.title) end - it 'shows issues when current user is author', :js do - reset_filters - input_filtered_search("author:=#{current_user.to_reference}") + it 'shows issues when current user is author' do + click_button 'Clear' + select_tokens 'Author', '=', current_user.to_reference, submit: true expect(page).to have_content(authored_issue.title) expect(page).to have_content(authored_issue_on_public_project.title) @@ -41,12 +41,21 @@ RSpec.describe 'Dashboard Issues', feature_category: :team_planning do end it 'state filter tabs work' do - find('#state-closed').click - expect(page).to have_current_path(issues_dashboard_url(assignee_username: current_user.username, state: 'closed'), url: true) + click_link 'Closed' + + expect(page).not_to have_content(assigned_issue.title) + expect(page).not_to have_content(authored_issue.title) + expect(page).not_to have_content(other_issue.title) end - it_behaves_like "it has an RSS button with current_user's feed token" - it_behaves_like "an autodiscoverable RSS feed with current_user's feed token" + describe 'RSS link' do + before do + click_button 'Actions' + end + + it_behaves_like "it has an RSS link with current_user's feed token" + it_behaves_like "an autodiscoverable RSS feed with current_user's feed token" + end end describe 'new issue dropdown' do diff --git a/spec/features/dashboard/label_filter_spec.rb b/spec/features/dashboard/label_filter_spec.rb deleted file mode 100644 index f116c84ff40..00000000000 --- a/spec/features/dashboard/label_filter_spec.rb +++ /dev/null @@ -1,34 +0,0 @@ -# frozen_string_literal: true - -require 'spec_helper' - -RSpec.describe 'Dashboard > label filter', :js, feature_category: :team_planning do - include FilteredSearchHelpers - - let(:filtered_search) { find('.filtered-search') } - let(:filter_dropdown) { find("#js-dropdown-label .filter-dropdown") } - - let(:user) { create(:user) } - let(:project) { create(:project, name: 'test', namespace: user.namespace) } - let(:project2) { create(:project, name: 'test2', path: 'test2', namespace: user.namespace) } - let(:label) { create(:label, title: 'bug', color: '#ff0000') } - let(:label2) { create(:label, title: 'bug') } - - before do - project.labels << label - project2.labels << label2 - - sign_in(user) - visit issues_dashboard_path - - init_label_search - end - - context 'duplicate labels' do - it 'removes duplicate labels' do - filtered_search.send_keys('bu') - - expect(filter_dropdown).to have_selector('.filter-dropdown-item', text: 'bug', count: 1) - end - end -end diff --git a/spec/features/dashboard/merge_requests_spec.rb b/spec/features/dashboard/merge_requests_spec.rb index 34bab9dffd0..d53f5affe64 100644 --- a/spec/features/dashboard/merge_requests_spec.rb +++ b/spec/features/dashboard/merge_requests_spec.rb @@ -3,7 +3,7 @@ require 'spec_helper' RSpec.describe 'Dashboard Merge Requests', feature_category: :code_review_workflow do - include Spec::Support::Helpers::Features::SortingHelpers + include Features::SortingHelpers include FilteredSearchHelpers include ProjectForksHelper @@ -19,7 +19,7 @@ RSpec.describe 'Dashboard Merge Requests', feature_category: :code_review_workfl sign_in(current_user) end - it_behaves_like 'a dashboard page with sidebar', :merge_requests_dashboard_path, :merge_requests + it_behaves_like 'a "Your work" page with sidebar and breadcrumbs', :merge_requests_dashboard_path, :merge_requests it 'disables target branch filter' do visit merge_requests_dashboard_path diff --git a/spec/features/dashboard/milestones_spec.rb b/spec/features/dashboard/milestones_spec.rb index 3b197bbf009..0dd25ffaa94 100644 --- a/spec/features/dashboard/milestones_spec.rb +++ b/spec/features/dashboard/milestones_spec.rb @@ -26,7 +26,7 @@ RSpec.describe 'Dashboard > Milestones', feature_category: :team_planning do visit dashboard_milestones_path end - it_behaves_like 'a dashboard page with sidebar', :dashboard_milestones_path, :milestones + it_behaves_like 'a "Your work" page with sidebar and breadcrumbs', :dashboard_milestones_path, :milestones it 'sees milestones' do expect(page).to have_current_path dashboard_milestones_path, ignore_query: true diff --git a/spec/features/dashboard/projects_spec.rb b/spec/features/dashboard/projects_spec.rb index 779fbb48ddb..32bce32ec6c 100644 --- a/spec/features/dashboard/projects_spec.rb +++ b/spec/features/dashboard/projects_spec.rb @@ -4,7 +4,7 @@ require 'spec_helper' RSpec.describe 'Dashboard Projects', feature_category: :projects do let_it_be(:user) { create(:user) } - let_it_be(:project, reload: true) { create(:project, :repository) } + let_it_be(:project, reload: true) { create(:project, :repository, creator: build(:user)) } # ensure creator != owner to avoid N+1 false-positive let_it_be(:project2) { create(:project, :public) } before do @@ -18,7 +18,13 @@ RSpec.describe 'Dashboard Projects', feature_category: :projects do end end - it_behaves_like "a dashboard page with sidebar", :dashboard_projects_path, :projects + it_behaves_like 'a "Your work" page with sidebar and breadcrumbs', :dashboard_projects_path, :projects + + it 'links to the "Explore projects" page' do + visit dashboard_projects_path + + expect(page).to have_link("Explore projects", href: explore_projects_path) + end context 'when user has access to the project' do it 'shows role badge' do @@ -106,6 +112,8 @@ RSpec.describe 'Dashboard Projects', feature_category: :projects do end context 'when on Starred projects tab', :js do + it_behaves_like 'a "Your work" page with sidebar and breadcrumbs', :starred_dashboard_projects_path, :projects + it 'shows the empty state when there are no starred projects' do visit(starred_dashboard_projects_path) @@ -239,7 +247,7 @@ RSpec.describe 'Dashboard Projects', feature_category: :projects do create(:ci_pipeline, :with_job, status: :success, project: project, ref: project.default_branch, sha: project.commit.sha) visit dashboard_projects_path - control_count = ActiveRecord::QueryRecorder.new { visit dashboard_projects_path }.count + control = ActiveRecord::QueryRecorder.new { visit dashboard_projects_path } new_project = create(:project, :repository, name: 'new project') create(:ci_pipeline, :with_job, status: :success, project: new_project, ref: new_project.commit.sha) @@ -247,15 +255,11 @@ RSpec.describe 'Dashboard Projects', feature_category: :projects do ActiveRecord::QueryRecorder.new { visit dashboard_projects_path }.count - # There are seven known N+1 queries: https://gitlab.com/gitlab-org/gitlab/-/issues/214037 - # 1. Project#open_issues_count - # 2. Project#open_merge_requests_count - # 3. Project#forks_count - # 4. ProjectsHelper#load_pipeline_status - # 5. RendersMemberAccess#preload_max_member_access_for_collection - # 6. User#max_member_access_for_project_ids - # 7. Ci::CommitWithPipeline#last_pipeline + # There are a few known N+1 queries: https://gitlab.com/gitlab-org/gitlab/-/issues/214037 + # - User#max_member_access_for_project_ids + # - ProjectsHelper#load_pipeline_status / Ci::CommitWithPipeline#last_pipeline + # - Ci::Pipeline#detailed_status - expect { visit dashboard_projects_path }.not_to exceed_query_limit(control_count + 7) + expect { visit dashboard_projects_path }.not_to exceed_query_limit(control).with_threshold(4) end end diff --git a/spec/features/dashboard/root_explore_spec.rb b/spec/features/dashboard/root_explore_spec.rb index a232ebec68e..9e844f81a29 100644 --- a/spec/features/dashboard/root_explore_spec.rb +++ b/spec/features/dashboard/root_explore_spec.rb @@ -2,16 +2,12 @@ require 'spec_helper' -RSpec.describe 'Root explore', feature_category: :not_owned do +RSpec.describe 'Root explore', :saas, feature_category: :shared do let_it_be(:public_project) { create(:project, :public) } let_it_be(:archived_project) { create(:project, :archived) } let_it_be(:internal_project) { create(:project, :internal) } let_it_be(:private_project) { create(:project, :private) } - before do - allow(Gitlab).to receive(:com?).and_return(true) - end - context 'when logged in' do let_it_be(:user) { create(:user) } diff --git a/spec/features/dashboard/shortcuts_spec.rb b/spec/features/dashboard/shortcuts_spec.rb index 30587756505..155f7e93961 100644 --- a/spec/features/dashboard/shortcuts_spec.rb +++ b/spec/features/dashboard/shortcuts_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' -RSpec.describe 'Dashboard shortcuts', :js, feature_category: :not_owned do +RSpec.describe 'Dashboard shortcuts', :js, feature_category: :shared do context 'logged in' do let(:user) { create(:user) } let(:project) { create(:project) } diff --git a/spec/features/dashboard/snippets_spec.rb b/spec/features/dashboard/snippets_spec.rb index ba40290d866..da985c6dc07 100644 --- a/spec/features/dashboard/snippets_spec.rb +++ b/spec/features/dashboard/snippets_spec.rb @@ -5,7 +5,14 @@ require 'spec_helper' RSpec.describe 'Dashboard snippets', feature_category: :source_code_management do let_it_be(:user) { create(:user) } - it_behaves_like 'a dashboard page with sidebar', :dashboard_snippets_path, :snippets + it_behaves_like 'a "Your work" page with sidebar and breadcrumbs', :dashboard_snippets_path, :snippets + + it 'links to the "Explore snippets" page' do + sign_in(user) + visit dashboard_snippets_path + + expect(page).to have_link("Explore snippets", href: explore_snippets_path) + end context 'when the project has snippets' do let(:project) { create(:project, :public, creator: user) } @@ -37,7 +44,8 @@ RSpec.describe 'Dashboard snippets', feature_category: :source_code_management d element = page.find('.row.empty-state') expect(element).to have_content("Code snippets") - expect(element.find('.svg-content img.js-lazy-loaded')['src']).to have_content('illustrations/snippets_empty') + expect(element.find('.svg-content img.js-lazy-loaded')['src']) + .to have_content('illustrations/empty-state/empty-snippets-md') end it 'shows new snippet button in main content area' do diff --git a/spec/features/dashboard/todos/todos_spec.rb b/spec/features/dashboard/todos/todos_spec.rb index 59bb1a452c9..d0003b69415 100644 --- a/spec/features/dashboard/todos/todos_spec.rb +++ b/spec/features/dashboard/todos/todos_spec.rb @@ -15,7 +15,7 @@ RSpec.describe 'Dashboard Todos', feature_category: :team_planning do project.add_developer(user) end - it_behaves_like 'a dashboard page with sidebar', :dashboard_todos_path, :todos + it_behaves_like 'a "Your work" page with sidebar and breadcrumbs', :dashboard_todos_path, :todos context 'User does not have todos' do before do diff --git a/spec/features/display_system_header_and_footer_bar_spec.rb b/spec/features/display_system_header_and_footer_bar_spec.rb index 22fd0987418..9b2bf0ef1fa 100644 --- a/spec/features/display_system_header_and_footer_bar_spec.rb +++ b/spec/features/display_system_header_and_footer_bar_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' -RSpec.describe 'Display system header and footer bar', feature_category: :not_owned do +RSpec.describe 'Display system header and footer bar', feature_category: :shared do let(:header_message) { "Foo" } let(:footer_message) { "Bar" } diff --git a/spec/features/emails/issues_spec.rb b/spec/features/emails/issues_spec.rb new file mode 100644 index 00000000000..c425dad88aa --- /dev/null +++ b/spec/features/emails/issues_spec.rb @@ -0,0 +1,110 @@ +# frozen_string_literal: true + +require "spec_helper" + +RSpec.describe "E-Mails > Issues", :js, feature_category: :team_planning do + let_it_be(:project) { create(:project_empty_repo, :public, name: 'Long Earth') } + let_it_be(:author) { create(:user, username: 'author', name: 'Sally Linsay') } + let_it_be(:current_user) { create(:user, username: 'current_user', name: 'Shi-mi') } + + before do + project.add_developer(current_user) + sign_in(current_user) + end + + describe 'assignees' do + let_it_be(:assignee) { create(:user, username: 'assignee', name: 'Joshua Valienté') } + let_it_be(:issue_without_assignee) { create(:issue, project: project, author: author, title: 'No milk today!') } + + let_it_be(:issue_with_assignee) do + create( + :issue, project: project, author: author, assignees: [assignee], + title: 'All your base are belong to us') + end + + it 'sends confirmation e-mail for assigning' do + synchronous_notifications + expect(Notify).to receive(:reassigned_issue_email) + .with(author.id, issue_without_assignee.id, [], current_user.id, nil) + .once + .and_call_original + expect(Notify).to receive(:reassigned_issue_email) + .with(assignee.id, issue_without_assignee.id, [], current_user.id, NotificationReason::ASSIGNED) + .once + .and_call_original + + visit issue_path(issue_without_assignee) + assign_to(assignee) + + expect(find('#notes-list')).to have_text("Shi-mi assigned to @assignee just now") + end + + it 'sends confirmation e-mail for reassigning' do + synchronous_notifications + expect(Notify).to receive(:reassigned_issue_email) + .with(author.id, issue_with_assignee.id, [assignee.id], current_user.id, NotificationReason::ASSIGNED) + .once + .and_call_original + expect(Notify).to receive(:reassigned_issue_email) + .with(assignee.id, issue_with_assignee.id, [assignee.id], current_user.id, nil) + .once + .and_call_original + + visit issue_path(issue_with_assignee) + assign_to(author) + + expect(find('#notes-list')).to have_text("Shi-mi assigned to @author and unassigned @assignee just now") + end + + it 'sends confirmation e-mail for unassigning' do + synchronous_notifications + expect(Notify).to receive(:reassigned_issue_email) + .with(author.id, issue_with_assignee.id, [assignee.id], current_user.id, nil) + .once + .and_call_original + expect(Notify).to receive(:reassigned_issue_email) + .with(assignee.id, issue_with_assignee.id, [assignee.id], current_user.id, nil) + .once + .and_call_original + + visit issue_path(issue_with_assignee) + quick_action('/unassign') + + expect(find('#notes-list')).to have_text("Shi-mi unassigned @assignee just now") + end + end + + describe 'closing' do + let_it_be(:issue) { create(:issue, project: project, author: author, title: 'Public Holiday') } + + it 'sends confirmation e-mail for closing' do + synchronous_notifications + expect(Notify).to receive(:closed_issue_email) + .with(author.id, issue.id, current_user.id, { closed_via: nil, reason: nil }) + .once + .and_call_original + + visit issue_path(issue) + quick_action("/close") + + expect(find('#notes-list')).to have_text("Shi-mi closed just now") + end + end + + private + + def assign_to(user) + quick_action("/assign @#{user.username}") + end + + def quick_action(command) + fill_in 'note[note]', with: command + click_button 'Comment' + end + + def synchronous_notifications + expect_next_instance_of(NotificationService) do |service| + expect(service).to receive(:async).and_return(service) + end + end +end diff --git a/spec/features/expand_collapse_diffs_spec.rb b/spec/features/expand_collapse_diffs_spec.rb index 1f09b01ddec..43dd80187ce 100644 --- a/spec/features/expand_collapse_diffs_spec.rb +++ b/spec/features/expand_collapse_diffs_spec.rb @@ -19,6 +19,8 @@ RSpec.describe 'Expand and collapse diffs', :js, feature_category: :source_code_ # Ensure that undiffable.md is in .gitattributes project.repository.copy_gitattributes(branch) visit project_commit_path(project, project.commit(branch)) + + wait_for_requests end def file_container(filename) @@ -222,10 +224,16 @@ RSpec.describe 'Expand and collapse diffs', :js, feature_category: :source_code_ let(:branch) { 'expand-collapse-files' } # safe-files -> 100 | safe-lines -> 5000 | commit-files -> 105 - it 'does collapsing from the safe number of files to the end on small files' do - expect(page).to have_link('Expand all') + it 'does collapsing from the safe number of files to the end on small files', :aggregate_failures do + expect(page).not_to have_link('Expand all') + expect(page).to have_selector('.diff-content', count: 20) + expect(page).to have_selector('.diff-collapsed', count: 0) - expect(page).to have_selector('.diff-content', count: 105) + visit project_commit_path(project, project.commit(branch), page: 6) + wait_for_requests + + expect(page).to have_link('Expand all') + expect(page).to have_selector('.diff-content', count: 5) expect(page).to have_selector('.diff-collapsed', count: 5) %w(file-95.txt file-96.txt file-97.txt file-98.txt file-99.txt).each do |filename| diff --git a/spec/features/explore/groups_spec.rb b/spec/features/explore/groups_spec.rb index 458f83dffb4..57a7e8ea523 100644 --- a/spec/features/explore/groups_spec.rb +++ b/spec/features/explore/groups_spec.rb @@ -29,8 +29,8 @@ RSpec.describe 'Explore Groups', :js, feature_category: :subgroups do shared_examples 'renders public and internal projects' do it do visit_page - expect(page).to have_content(public_project.name) - expect(page).to have_content(internal_project.name) + expect(page).to have_content(public_project.name).or(have_content(public_project.path)) + expect(page).to have_content(internal_project.name).or(have_content(internal_project.path)) expect(page).not_to have_content(private_project.name) end end @@ -38,7 +38,7 @@ RSpec.describe 'Explore Groups', :js, feature_category: :subgroups do shared_examples 'renders only public project' do it do visit_page - expect(page).to have_content(public_project.name) + expect(page).to have_content(public_project.name).or(have_content(public_project.path)) expect(page).not_to have_content(internal_project.name) expect(page).not_to have_content(private_project.name) end @@ -47,7 +47,7 @@ RSpec.describe 'Explore Groups', :js, feature_category: :subgroups do shared_examples 'renders group in public groups area' do it do visit explore_groups_path - expect(page).to have_content(group.name) + expect(page).to have_content(group.path) end end @@ -56,32 +56,44 @@ RSpec.describe 'Explore Groups', :js, feature_category: :subgroups do sign_in(user) end - it_behaves_like 'renders public and internal projects' do - subject(:visit_page) { visit group_path(group) } + context 'for group_path' do + it_behaves_like 'renders public and internal projects' do + subject(:visit_page) { visit group_path(group) } + end end - it_behaves_like 'renders public and internal projects' do - subject(:visit_page) { visit issues_group_path(group) } + context 'for issues_group_path' do + it_behaves_like 'renders public and internal projects' do + subject(:visit_page) { visit issues_group_path(group) } + end end - it_behaves_like 'renders public and internal projects' do - subject(:visit_page) { visit merge_requests_group_path(group) } + context 'for merge_requests_group_path' do + it_behaves_like 'renders public and internal projects' do + subject(:visit_page) { visit merge_requests_group_path(group) } + end end it_behaves_like 'renders group in public groups area' end context 'when signed out' do - it_behaves_like 'renders only public project' do - subject(:visit_page) { visit group_path(group) } + context 'for group_path' do + it_behaves_like 'renders only public project' do + subject(:visit_page) { visit group_path(group) } + end end - it_behaves_like 'renders only public project' do - subject(:visit_page) { visit issues_group_path(group) } + context 'for issues_group_path' do + it_behaves_like 'renders only public project' do + subject(:visit_page) { visit issues_group_path(group) } + end end - it_behaves_like 'renders only public project' do - subject(:visit_page) { visit merge_requests_group_path(group) } + context 'for merge_requests_group_path' do + it_behaves_like 'renders only public project' do + subject(:visit_page) { visit merge_requests_group_path(group) } + end end it_behaves_like 'renders group in public groups area' diff --git a/spec/features/explore/navbar_spec.rb b/spec/features/explore/navbar_spec.rb new file mode 100644 index 00000000000..8f281abe6a7 --- /dev/null +++ b/spec/features/explore/navbar_spec.rb @@ -0,0 +1,13 @@ +# frozen_string_literal: true + +require 'spec_helper' + +RSpec.describe '"Explore" navbar', feature_category: :navigation do + include_context '"Explore" navbar structure' + + it_behaves_like 'verified navigation bar' do + before do + visit explore_projects_path + end + end +end diff --git a/spec/features/explore/user_explores_projects_spec.rb b/spec/features/explore/user_explores_projects_spec.rb index 14fddf5d84c..f259ba6a167 100644 --- a/spec/features/explore/user_explores_projects_spec.rb +++ b/spec/features/explore/user_explores_projects_spec.rb @@ -3,6 +3,18 @@ require 'spec_helper' RSpec.describe 'User explores projects', feature_category: :user_profile do + describe '"All" tab' do + it_behaves_like 'an "Explore" page with sidebar and breadcrumbs', :explore_projects_path, :projects + end + + describe '"Most starred" tab' do + it_behaves_like 'an "Explore" page with sidebar and breadcrumbs', :starred_explore_projects_path, :projects + end + + describe '"Trending" tab' do + it_behaves_like 'an "Explore" page with sidebar and breadcrumbs', :trending_explore_projects_path, :projects + end + context 'when some projects exist' do let_it_be(:archived_project) { create(:project, :archived) } let_it_be(:internal_project) { create(:project, :internal) } diff --git a/spec/features/file_uploads/project_import_spec.rb b/spec/features/file_uploads/project_import_spec.rb index c261834206d..3934e0319ad 100644 --- a/spec/features/file_uploads/project_import_spec.rb +++ b/spec/features/file_uploads/project_import_spec.rb @@ -22,6 +22,10 @@ RSpec.describe 'Upload a project export archive', :api, :js, feature_category: : ) end + before do + stub_application_setting(import_sources: ['gitlab_project']) + end + RSpec.shared_examples 'for a project export archive' do it { expect { subject }.to change { Project.count }.by(1) } diff --git a/spec/features/frequently_visited_projects_and_groups_spec.rb b/spec/features/frequently_visited_projects_and_groups_spec.rb index 50e20910e16..514b642a2d4 100644 --- a/spec/features/frequently_visited_projects_and_groups_spec.rb +++ b/spec/features/frequently_visited_projects_and_groups_spec.rb @@ -2,8 +2,8 @@ require 'spec_helper' -RSpec.describe 'Frequently visited items', :js, feature_category: :not_owned do - include Spec::Support::Helpers::Features::TopNavSpecHelpers +RSpec.describe 'Frequently visited items', :js, feature_category: :shared do + include Features::TopNavSpecHelpers let_it_be(:user) { create(:user) } diff --git a/spec/features/global_search_spec.rb b/spec/features/global_search_spec.rb index 15393ec4cd6..f94f0288f99 100644 --- a/spec/features/global_search_spec.rb +++ b/spec/features/global_search_spec.rb @@ -13,64 +13,8 @@ RSpec.describe 'Global search', :js, feature_category: :global_search do sign_in(user) end - describe 'when new_header_search feature is disabled' do + describe 'when header search' do before do - # TODO: Remove this along with feature flag #339348 - stub_feature_flags(new_header_search: false) - visit dashboard_projects_path - end - - it 'increases usage ping searches counter' do - expect(Gitlab::UsageDataCounters::SearchCounter).to receive(:count).with(:navbar_searches) - expect(Gitlab::UsageDataCounters::SearchCounter).to receive(:count).with(:all_searches) - - submit_search('foobar') - end - - describe 'I search through the issues and I see pagination' do - before do - allow_next(SearchService).to receive(:per_page).and_return(1) - create_list(:issue, 2, project: project, title: 'initial') - end - - it "has a pagination" do - submit_search('initial') - select_search_scope('Issues') - - expect(page).to have_selector('.gl-pagination .next') - end - end - - it 'closes the dropdown on blur' do - find('#search').click - fill_in 'search', with: "a" - - expect(page).to have_selector("div[data-testid='dashboard-search-options'].show") - - find('#search').send_keys(:backspace) - find('body').click - - expect(page).to have_no_selector("div[data-testid='dashboard-search-options'].show") - end - - it 'renders legacy search bar' do - expect(page).to have_selector('.search-form') - expect(page).to have_no_selector('#js-header-search') - end - - it 'focuses search input when shortcut "s" is pressed' do - expect(page).not_to have_selector('#search:focus') - - find('body').native.send_key('s') - - expect(page).to have_selector('#search:focus') - end - end - - describe 'when new_header_search feature is enabled' do - before do - # TODO: Remove this along with feature flag #339348 - stub_feature_flags(new_header_search: true) visit dashboard_projects_path end diff --git a/spec/features/group_variables_spec.rb b/spec/features/group_variables_spec.rb index 117f50aefc6..3e87c90e7dc 100644 --- a/spec/features/group_variables_spec.rb +++ b/spec/features/group_variables_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' -RSpec.describe 'Group variables', :js, feature_category: :pipeline_authoring do +RSpec.describe 'Group variables', :js, feature_category: :secrets_management do let(:user) { create(:user) } let(:group) { create(:group) } let!(:variable) { create(:ci_group_variable, key: 'test_key', value: 'test_value', masked: true, group: group) } @@ -15,5 +15,16 @@ RSpec.describe 'Group variables', :js, feature_category: :pipeline_authoring do wait_for_requests end - it_behaves_like 'variable list' + context 'when ci_variables_pages FF is enabled' do + it_behaves_like 'variable list' + it_behaves_like 'variable list pagination', :ci_group_variable + end + + context 'when ci_variables_pages FF is disabled' do + before do + stub_feature_flags(ci_variables_pages: false) + end + + it_behaves_like 'variable list' + end end diff --git a/spec/features/groups/board_spec.rb b/spec/features/groups/board_spec.rb index c451a97bed5..8acf3ffe441 100644 --- a/spec/features/groups/board_spec.rb +++ b/spec/features/groups/board_spec.rb @@ -25,8 +25,10 @@ RSpec.describe 'Group Boards', feature_category: :team_planning do it 'adds an issue to the backlog' do page.within(find('.board', match: :first)) do - issue_title = 'New Issue' - click_button 'New issue' + dropdown = first("[data-testid='header-list-actions']") + dropdown.click + issue_title = 'Create new issue' + click_button issue_title wait_for_requests diff --git a/spec/features/groups/container_registry_spec.rb b/spec/features/groups/container_registry_spec.rb index 11f94967aaf..ab8d8238bdc 100644 --- a/spec/features/groups/container_registry_spec.rb +++ b/spec/features/groups/container_registry_spec.rb @@ -95,7 +95,11 @@ RSpec.describe 'Container Registry', :js, feature_category: :container_registry first('[data-testid="additional-actions"]').click first('[data-testid="single-delete-button"]').click expect(find('.modal .modal-title')).to have_content _('Remove tag') + stub_container_registry_tags(repository: %r{my/image}, tags: [], with_manifest: true) find('.modal .modal-footer .btn-danger').click + + expect(page).to have_content '0 tags' + expect(page).not_to have_content '1 tag' end end end diff --git a/spec/features/groups/crm/contacts/create_spec.rb b/spec/features/groups/crm/contacts/create_spec.rb index 860cadd322d..aa05ef82a8b 100644 --- a/spec/features/groups/crm/contacts/create_spec.rb +++ b/spec/features/groups/crm/contacts/create_spec.rb @@ -5,7 +5,7 @@ require 'spec_helper' RSpec.describe 'Create a CRM contact', :js, feature_category: :service_desk do let(:user) { create(:user) } let(:group) { create(:group, :crm_enabled) } - let!(:organization) { create(:organization, group: group, name: 'GitLab') } + let!(:crm_organization) { create(:crm_organization, group: group, name: 'GitLab') } before do group.add_owner(user) diff --git a/spec/features/groups/dependency_proxy_spec.rb b/spec/features/groups/dependency_proxy_spec.rb index 05984d40ea6..60922f813df 100644 --- a/spec/features/groups/dependency_proxy_spec.rb +++ b/spec/features/groups/dependency_proxy_spec.rb @@ -52,6 +52,12 @@ RSpec.describe 'Group Dependency Proxy', feature_category: :dependency_proxy do expect(find('input[data-testid="proxy-url"]').value).to have_content('/dependency_proxy/containers') end + it 'has link to settings' do + visit path + + expect(page).to have_link s_('DependencyProxy|Configure in settings') + end + it 'hides the proxy URL when feature is disabled' do visit settings_path wait_for_requests @@ -80,6 +86,10 @@ RSpec.describe 'Group Dependency Proxy', feature_category: :dependency_proxy do it 'does not show the feature toggle but shows the proxy URL' do expect(find('input[data-testid="proxy-url"]').value).to have_content('/dependency_proxy/containers') end + + it 'does not have link to settings' do + expect(page).not_to have_link s_('DependencyProxy|Configure in settings') + end end end diff --git a/spec/features/groups/group_runners_spec.rb b/spec/features/groups/group_runners_spec.rb index ae757e04716..514110d78ae 100644 --- a/spec/features/groups/group_runners_spec.rb +++ b/spec/features/groups/group_runners_spec.rb @@ -3,7 +3,7 @@ require 'spec_helper' RSpec.describe "Group Runners", feature_category: :runner_fleet do - include Spec::Support::Helpers::Features::RunnersHelpers + include Features::RunnersHelpers include Spec::Support::Helpers::ModalHelpers let_it_be(:group_owner) { create(:user) } @@ -16,10 +16,12 @@ RSpec.describe "Group Runners", feature_category: :runner_fleet do end describe "Group runners page", :js do - let!(:group_registration_token) { group.runners_token } + describe "legacy runners registration" do + let_it_be(:group_registration_token) { group.runners_token } - describe "runners registration" do before do + stub_feature_flags(create_runner_workflow_for_namespace: false) + visit group_runners_path(group) end @@ -60,15 +62,11 @@ RSpec.describe "Group Runners", feature_category: :runner_fleet do let(:runner) { group_runner } end - it 'shows a group badge' do - within_runner_row(group_runner.id) do - expect(page).to have_selector '.badge', text: s_('Runners|Group') - end - end - - it 'can edit runner information' do + it 'shows an editable group badge' do within_runner_row(group_runner.id) do expect(find_link('Edit')[:href]).to end_with(edit_group_runner_path(group, group_runner)) + + expect(page).to have_selector '.badge', text: s_('Runners|Group') end end @@ -102,15 +100,11 @@ RSpec.describe "Group Runners", feature_category: :runner_fleet do let(:runner) { project_runner } end - it 'shows a project badge' do - within_runner_row(project_runner.id) do - expect(page).to have_selector '.badge', text: s_('Runners|Project') - end - end - - it 'can edit runner information' do + it 'shows an editable project runner' do within_runner_row(project_runner.id) do expect(find_link('Edit')[:href]).to end_with(edit_group_runner_path(group, project_runner)) + + expect(page).to have_selector '.badge', text: s_('Runners|Project') end end end @@ -202,6 +196,16 @@ RSpec.describe "Group Runners", feature_category: :runner_fleet do end end + describe "Group runner create page", :js do + before do + visit new_group_runner_path(group) + end + + it_behaves_like 'creates runner and shows register page' do + let(:register_path_pattern) { register_group_runner_path(group, '.*') } + end + end + describe "Group runner show page", :js do let_it_be(:group_runner) do create(:ci_runner, :group, groups: [group], description: 'runner-foo') diff --git a/spec/features/groups/group_settings_spec.rb b/spec/features/groups/group_settings_spec.rb index 5510e73ef0f..6443f4a6c38 100644 --- a/spec/features/groups/group_settings_spec.rb +++ b/spec/features/groups/group_settings_spec.rb @@ -3,6 +3,8 @@ require 'spec_helper' RSpec.describe 'Edit group settings', feature_category: :subgroups do + include Spec::Support::Helpers::ModalHelpers + let(:user) { create(:user) } let(:group) { create(:group, path: 'foo') } @@ -72,7 +74,7 @@ RSpec.describe 'Edit group settings', feature_category: :subgroups do visit new_project_full_path expect(page).to have_current_path(new_project_full_path, ignore_query: true) - expect(find('.breadcrumbs')).to have_content(project.path) + expect(find('.breadcrumbs')).to have_content(project.name) end it 'the old project path redirects to the new path' do @@ -80,7 +82,7 @@ RSpec.describe 'Edit group settings', feature_category: :subgroups do visit old_project_full_path expect(page).to have_current_path(new_project_full_path, ignore_query: true) - expect(find('.breadcrumbs')).to have_content(project.path) + expect(find('.breadcrumbs')).to have_content(project.name) end end end @@ -147,14 +149,16 @@ RSpec.describe 'Edit group settings', feature_category: :subgroups do selected_group.add_owner(user) end - it 'can successfully transfer the group', quarantine: 'https://gitlab.com/gitlab-org/gitlab/-/issues/384966' do + it 'can successfully transfer the group' do + selected_group_path = selected_group.path + visit edit_group_path(selected_group) page.within('[data-testid="transfer-locations-dropdown"]') do click_button _('Select parent group') - fill_in _('Search'), with: target_group_name + fill_in _('Search'), with: target_group&.name || '' wait_for_requests - click_button target_group_name + click_button(target_group&.name || 'No parent group') end click_button s_('GroupSettings|Transfer group') @@ -166,8 +170,16 @@ RSpec.describe 'Edit group settings', feature_category: :subgroups do click_button 'Confirm' end - expect(page).to have_text "Group '#{selected_group.name}' was successfully transferred." - expect(current_url).to include(selected_group.reload.full_path) + within('[data-testid="breadcrumb-links"]') do + expect(page).to have_content(target_group.name) if target_group + expect(page).to have_content(selected_group.name) + end + + if target_group + expect(current_url).to include("#{target_group.path}/#{selected_group_path}") + else + expect(current_url).to include(selected_group_path) + end end end @@ -175,14 +187,13 @@ RSpec.describe 'Edit group settings', feature_category: :subgroups do let(:selected_group) { create(:group, path: 'foo-subgroup', parent: group) } context 'when transfering to no parent group' do - let(:target_group_name) { 'No parent group' } + let(:target_group) { nil } it_behaves_like 'can transfer the group' end context 'when transfering to a parent group' do let(:target_group) { create(:group, path: 'foo-parentgroup') } - let(:target_group_name) { target_group.name } before do target_group.add_owner(user) @@ -194,7 +205,7 @@ RSpec.describe 'Edit group settings', feature_category: :subgroups do context 'when transfering from a root group to a parent group' do let(:selected_group) { create(:group, path: 'foo-rootgroup') } - let(:target_group_name) { group.name } + let(:target_group) { group } it_behaves_like 'can transfer the group' end @@ -235,6 +246,67 @@ RSpec.describe 'Edit group settings', feature_category: :subgroups do end end + describe 'group README', :js do + let_it_be(:group) { create(:group) } + + context 'with gitlab-profile project and README.md' do + let_it_be(:project) { create(:project, :readme, namespace: group) } + + it 'renders link to Group README and navigates to it on click' do + visit edit_group_path(group) + wait_for_requests + + click_link('README') + wait_for_requests + + expect(page).to have_current_path(project_blob_path(project, "#{project.default_branch}/README.md")) + expect(page).to have_text('README.md') + end + end + + context 'with gitlab-profile project and no README.md' do + let_it_be(:project) { create(:project, path: 'gitlab-profile', namespace: group) } + + it 'renders Add README button and allows user to create a README via the IDE' do + visit edit_group_path(group) + wait_for_requests + + expect(page).not_to have_selector('.ide') + + click_button('Add README') + + accept_gl_confirm("This will create a README.md for project #{group.readme_project.present.path_with_namespace}.", button_text: 'Add README') + wait_for_requests + + expect(page).to have_current_path("/-/ide/project/#{group.readme_project.present.path_with_namespace}/edit/main/-/README.md/") + + page.within('.ide') do + expect(page).to have_text('README.md') + end + end + end + + context 'with no gitlab-profile project and no README.md' do + it 'renders Add README button and allows user to create both the gitlab-profile project and README via the IDE' do + visit edit_group_path(group) + wait_for_requests + + expect(page).not_to have_selector('.ide') + + click_button('Add README') + + accept_gl_confirm("This will create a project #{group.full_path}/gitlab-profile and add a README.md.", button_text: 'Create and add README') + wait_for_requests + + expect(page).to have_current_path("/-/ide/project/#{group.full_path}/gitlab-profile/edit/main/-/README.md/") + + page.within('.ide') do + expect(page).to have_text('README.md') + end + end + end + end + def update_path(new_group_path) visit edit_group_path(group) diff --git a/spec/features/groups/import_export/connect_instance_spec.rb b/spec/features/groups/import_export/connect_instance_spec.rb index 8aea18a268b..f6548c035f0 100644 --- a/spec/features/groups/import_export/connect_instance_spec.rb +++ b/spec/features/groups/import_export/connect_instance_spec.rb @@ -26,7 +26,7 @@ RSpec.describe 'Import/Export - Connect to another instance', :js, feature_categ pat = 'demo-pat' expect(page).to have_content 'Import groups by direct transfer' - expect(page).to have_content 'Not all related objects are migrated' + expect(page).to have_content 'Not all group items are migrated' fill_in :bulk_import_gitlab_url, with: source_url fill_in :bulk_import_gitlab_access_token, with: pat diff --git a/spec/features/groups/integrations/group_integrations_spec.rb b/spec/features/groups/integrations/group_integrations_spec.rb index 0d65fa5964b..8cddda91e89 100644 --- a/spec/features/groups/integrations/group_integrations_spec.rb +++ b/spec/features/groups/integrations/group_integrations_spec.rb @@ -5,6 +5,10 @@ require 'spec_helper' RSpec.describe 'Group integrations', :js do include_context 'group integration activation' + before do + stub_feature_flags(remove_monitor_metrics: false) + end + it_behaves_like 'integration settings form' do let(:integrations) { Integration.find_or_initialize_all_non_project_specific(Integration.for_group(group)) } @@ -12,4 +16,16 @@ RSpec.describe 'Group integrations', :js do visit_group_integration(integration.title) end end + + context 'with remove_monitor_metrics flag enabled' do + before do + stub_feature_flags(remove_monitor_metrics: true) + end + + it 'returns a 404 for the prometheus edit page' do + visit edit_group_settings_integration_path(group, :prometheus) + + expect(page).to have_content "Page Not Found" + end + end end diff --git a/spec/features/groups/issues_spec.rb b/spec/features/groups/issues_spec.rb index 00c0d4c3ebe..6d0d768d356 100644 --- a/spec/features/groups/issues_spec.rb +++ b/spec/features/groups/issues_spec.rb @@ -23,6 +23,10 @@ RSpec.describe 'Group issues page', feature_category: :subgroups do context 'rss feed' do let(:access_level) { ProjectFeature::ENABLED } + before do + click_button 'Actions' + end + context 'when signed in' do let(:user) do user_in_group.ensure_feed_token @@ -30,29 +34,15 @@ RSpec.describe 'Group issues page', feature_category: :subgroups do user_in_group end + it_behaves_like "it has an RSS link with current_user's feed token" it_behaves_like "an autodiscoverable RSS feed with current_user's feed token" - - # Note: The one from rss_shared_example.rb uses a css pseudo-class `:has` - # which is VERY experimental and only supported in Nokogiri used by Capybara - # However,`:js` option forces Capybara to use Selenium that doesn't support`:has` - context "it has an RSS button with current_user's feed token" do - it "shows the RSS button with current_user's feed token" do - expect(page).to have_link 'Subscribe to RSS feed', href: /feed_token=#{user.feed_token}/ - end - end end context 'when signed out' do let(:user) { nil } + it_behaves_like "it has an RSS link without a feed token" it_behaves_like "an autodiscoverable RSS feed without a feed token" - - # Note: please see the above - context "it has an RSS button without a feed token" do - it "shows the RSS button without a feed token" do - expect(page).not_to have_link 'Subscribe to RSS feed', href: /feed_token/ - end - end end end diff --git a/spec/features/groups/labels/index_spec.rb b/spec/features/groups/labels/index_spec.rb index ea27fa2c5d9..7b0a38a83db 100644 --- a/spec/features/groups/labels/index_spec.rb +++ b/spec/features/groups/labels/index_spec.rb @@ -24,6 +24,7 @@ RSpec.describe 'Group labels', feature_category: :team_planning do end it 'shows an edit label button', :js do - expect(page).to have_selector('.edit') + click_button 'Label actions dropdown' + expect(page).to have_link('Edit') end end diff --git a/spec/features/groups/members/filter_members_spec.rb b/spec/features/groups/members/filter_members_spec.rb index dc33bb11bea..c2ec709576b 100644 --- a/spec/features/groups/members/filter_members_spec.rb +++ b/spec/features/groups/members/filter_members_spec.rb @@ -3,7 +3,7 @@ require 'spec_helper' RSpec.describe 'Groups > Members > Filter members', :js, feature_category: :subgroups do - include Spec::Support::Helpers::Features::MembersHelpers + include Features::MembersHelpers let(:user) { create(:user) } let(:nested_group_user) { create(:user) } diff --git a/spec/features/groups/members/leave_group_spec.rb b/spec/features/groups/members/leave_group_spec.rb index cfb1b24bccb..e1c2d8c0547 100644 --- a/spec/features/groups/members/leave_group_spec.rb +++ b/spec/features/groups/members/leave_group_spec.rb @@ -3,7 +3,7 @@ require 'spec_helper' RSpec.describe 'Groups > Members > Leave group', feature_category: :subgroups do - include Spec::Support::Helpers::Features::MembersHelpers + include Features::MembersHelpers include Spec::Support::Helpers::ModalHelpers let(:user) { create(:user) } diff --git a/spec/features/groups/members/list_members_spec.rb b/spec/features/groups/members/list_members_spec.rb index 1aea5a76b41..6e20f92c16b 100644 --- a/spec/features/groups/members/list_members_spec.rb +++ b/spec/features/groups/members/list_members_spec.rb @@ -3,7 +3,7 @@ require 'spec_helper' RSpec.describe 'Groups > Members > List members', :js, feature_category: :subgroups do - include Spec::Support::Helpers::Features::MembersHelpers + include Features::MembersHelpers let(:user1) { create(:user, name: 'John Doe') } let(:user2) { create(:user, name: 'Mary Jane') } diff --git a/spec/features/groups/members/manage_groups_spec.rb b/spec/features/groups/members/manage_groups_spec.rb index ee8786a2e36..f9c11dd0183 100644 --- a/spec/features/groups/members/manage_groups_spec.rb +++ b/spec/features/groups/members/manage_groups_spec.rb @@ -3,8 +3,8 @@ require 'spec_helper' RSpec.describe 'Groups > Members > Manage groups', :js, feature_category: :subgroups do - include Spec::Support::Helpers::Features::MembersHelpers - include Spec::Support::Helpers::Features::InviteMembersModalHelper + include Features::MembersHelpers + include Features::InviteMembersModalHelpers include Spec::Support::Helpers::ModalHelpers let_it_be(:user) { create(:user) } diff --git a/spec/features/groups/members/manage_members_spec.rb b/spec/features/groups/members/manage_members_spec.rb index 5cd5908b359..2d5a3dbb8f8 100644 --- a/spec/features/groups/members/manage_members_spec.rb +++ b/spec/features/groups/members/manage_members_spec.rb @@ -3,8 +3,8 @@ require 'spec_helper' RSpec.describe 'Groups > Members > Manage members', feature_category: :subgroups do - include Spec::Support::Helpers::Features::MembersHelpers - include Spec::Support::Helpers::Features::InviteMembersModalHelper + include Features::MembersHelpers + include Features::InviteMembersModalHelpers include Spec::Support::Helpers::ModalHelpers let_it_be(:user1) { create(:user, name: 'John Doe') } diff --git a/spec/features/groups/members/master_adds_member_with_expiration_date_spec.rb b/spec/features/groups/members/master_adds_member_with_expiration_date_spec.rb index e9f80b05fa7..4f56c807ec8 100644 --- a/spec/features/groups/members/master_adds_member_with_expiration_date_spec.rb +++ b/spec/features/groups/members/master_adds_member_with_expiration_date_spec.rb @@ -3,8 +3,8 @@ require 'spec_helper' RSpec.describe 'Groups > Members > Owner adds member with expiration date', :js, feature_category: :subgroups do - include Spec::Support::Helpers::Features::MembersHelpers - include Spec::Support::Helpers::Features::InviteMembersModalHelper + include Features::MembersHelpers + include Features::InviteMembersModalHelpers let_it_be(:user1) { create(:user, name: 'John Doe') } let_it_be(:group) { create(:group) } diff --git a/spec/features/groups/members/search_members_spec.rb b/spec/features/groups/members/search_members_spec.rb index 6b2896b194c..80de1cabd1e 100644 --- a/spec/features/groups/members/search_members_spec.rb +++ b/spec/features/groups/members/search_members_spec.rb @@ -3,7 +3,7 @@ require 'spec_helper' RSpec.describe 'Search group member', :js, feature_category: :subgroups do - include Spec::Support::Helpers::Features::MembersHelpers + include Features::MembersHelpers let(:user) { create :user } let(:member) { create :user } diff --git a/spec/features/groups/members/sort_members_spec.rb b/spec/features/groups/members/sort_members_spec.rb index 5634122ec16..d2e5445deae 100644 --- a/spec/features/groups/members/sort_members_spec.rb +++ b/spec/features/groups/members/sort_members_spec.rb @@ -3,7 +3,7 @@ require 'spec_helper' RSpec.describe 'Groups > Members > Sort members', :js, feature_category: :subgroups do - include Spec::Support::Helpers::Features::MembersHelpers + include Features::MembersHelpers let(:owner) { create(:user, name: 'John Doe', created_at: 5.days.ago, last_activity_on: Date.today) } let(:developer) { create(:user, name: 'Mary Jane', created_at: 1.day.ago, last_sign_in_at: 5.days.ago, last_activity_on: Date.today - 5) } @@ -18,7 +18,7 @@ RSpec.describe 'Groups > Members > Sort members', :js, feature_category: :subgro def expect_sort_by(text, sort_direction) within('[data-testid="members-sort-dropdown"]') do - expect(page).to have_css('button[aria-haspopup="true"]', text: text) + expect(page).to have_css('button[aria-haspopup="menu"]', text: text) expect(page).to have_button("Sorting Direction: #{sort_direction == :asc ? 'Ascending' : 'Descending'}") end end diff --git a/spec/features/groups/milestone_spec.rb b/spec/features/groups/milestone_spec.rb index a70a1e2e70b..376e1e6063f 100644 --- a/spec/features/groups/milestone_spec.rb +++ b/spec/features/groups/milestone_spec.rb @@ -25,17 +25,17 @@ RSpec.describe 'Group milestones', feature_category: :subgroups do description.native.send_keys('') - click_button('Preview') + click_button("Preview") preview = find('.js-md-preview') expect(preview).to have_content('Nothing to preview.') - click_button('Write') + click_button("Continue editing") description.native.send_keys(':+1: Nice') - click_button('Preview') + click_button("Preview") expect(preview).to have_css('gl-emoji') expect(find('#milestone_description', visible: false)).not_to be_visible diff --git a/spec/features/groups/milestones/milestone_editing_spec.rb b/spec/features/groups/milestones/milestone_editing_spec.rb new file mode 100644 index 00000000000..b3c7cfe88af --- /dev/null +++ b/spec/features/groups/milestones/milestone_editing_spec.rb @@ -0,0 +1,18 @@ +# frozen_string_literal: true + +require 'spec_helper' + +RSpec.describe "Milestone editing", feature_category: :team_planning do + let_it_be(:group) { create(:group, owner: user) } + let_it_be(:user) { create(:group_member, :maintainer, user: create(:user), group: group).user } + + let(:milestone) { create(:milestone, group: group, title: "12345676543") } + + before do + sign_in(user) + + visit(edit_group_milestone_path(group, milestone)) + end + + it_behaves_like 'milestone handling version conflicts' +end diff --git a/spec/features/groups/new_group_page_spec.rb b/spec/features/groups/new_group_page_spec.rb index a07c27331d9..1efdc3fff07 100644 --- a/spec/features/groups/new_group_page_spec.rb +++ b/spec/features/groups/new_group_page_spec.rb @@ -3,15 +3,14 @@ require 'spec_helper' RSpec.describe 'New group page', :js, feature_category: :subgroups do - let(:user) { create(:user) } - let(:group) { create(:group) } + let_it_be(:user) { create(:user) } + let_it_be(:parent_group) { create(:group) } before do + parent_group.add_owner(user) sign_in(user) end - it_behaves_like 'a dashboard page with sidebar', :new_group_path, :groups - describe 'new top level group alert' do context 'when a user visits the new group page' do it 'shows the new top level group alert' do @@ -22,8 +21,6 @@ RSpec.describe 'New group page', :js, feature_category: :subgroups do end context 'when a user visits the new sub group page' do - let(:parent_group) { create(:group) } - it 'does not show the new top level group alert' do visit new_group_path(parent_id: parent_group.id, anchor: 'create-group-pane') @@ -31,4 +28,45 @@ RSpec.describe 'New group page', :js, feature_category: :subgroups do end end end + + describe 'sidebar' do + context 'in the current navigation' do + before do + user.update!(use_new_navigation: false) + end + + context 'for a new top-level group' do + it_behaves_like 'a "Your work" page with sidebar and breadcrumbs', :new_group_path, :groups + end + + context 'for a new subgroup' do + it 'shows the group sidebar of the parent group' do + visit new_group_path(parent_id: parent_group.id, anchor: 'create-group-pane') + expect(page).to have_selector( + ".nav-sidebar[aria-label=\"Group navigation\"] .context-header[title=\"#{parent_group.name}\"]" + ) + end + end + end + + context 'in the new navigation' do + before do + user.update!(use_new_navigation: true) + end + + context 'for a new top-level group' do + it 'shows the "Your work" navigation' do + visit new_group_path + expect(page).to have_selector(".super-sidebar .context-switcher-toggle", text: "Your work") + end + end + + context 'for a new subgroup' do + it 'shows the group navigation of the parent group' do + visit new_group_path(parent_id: parent_group.id, anchor: 'create-group-pane') + expect(page).to have_selector(".super-sidebar .context-switcher-toggle", text: parent_group.name) + end + end + end + end end diff --git a/spec/features/groups/packages_spec.rb b/spec/features/groups/packages_spec.rb index dd238657fbc..b7f9cd3e93a 100644 --- a/spec/features/groups/packages_spec.rb +++ b/spec/features/groups/packages_spec.rb @@ -37,8 +37,8 @@ RSpec.describe 'Group Packages', feature_category: :package_registry do end context 'when there are packages' do - let_it_be(:second_project) { create(:project, name: 'second-project', group: group) } - let_it_be(:npm_package) { create(:npm_package, project: project, name: 'zzz', created_at: 1.day.ago, version: '1.0.0') } + let_it_be(:second_project) { create(:project, group: group) } + let_it_be(:npm_package) { create(:npm_package, :with_build, project: project, name: 'zzz', created_at: 1.day.ago, version: '1.0.0') } let_it_be(:maven_package) { create(:maven_package, project: second_project, name: 'aaa', created_at: 2.days.ago, version: '2.0.0') } let_it_be(:packages) { [npm_package, maven_package] } @@ -47,10 +47,12 @@ RSpec.describe 'Group Packages', feature_category: :package_registry do it_behaves_like 'packages list', check_project_name: true + it_behaves_like 'pipelines on packages list' + it_behaves_like 'package details link' it 'allows you to navigate to the project page' do - find('[data-testid="root-link"]', text: project.name).click + find('[data-testid="root-link"]', text: project.path).click expect(page).to have_current_path(project_path(project)) expect(page).to have_content(project.name) diff --git a/spec/features/groups/settings/access_tokens_spec.rb b/spec/features/groups/settings/access_tokens_spec.rb index 1bee3be1ddb..cb92f9abdf5 100644 --- a/spec/features/groups/settings/access_tokens_spec.rb +++ b/spec/features/groups/settings/access_tokens_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' -RSpec.describe 'Group > Settings > Access Tokens', :js, feature_category: :authentication_and_authorization do +RSpec.describe 'Group > Settings > Access Tokens', :js, feature_category: :system_access do include Spec::Support::Helpers::ModalHelpers let_it_be(:user) { create(:user) } diff --git a/spec/features/groups/settings/packages_and_registries_spec.rb b/spec/features/groups/settings/packages_and_registries_spec.rb index 80e2dcd5174..8ea8dc9219a 100644 --- a/spec/features/groups/settings/packages_and_registries_spec.rb +++ b/spec/features/groups/settings/packages_and_registries_spec.rb @@ -56,6 +56,15 @@ RSpec.describe 'Group Package and registry settings', feature_category: :package expect(sidebar).to have_link _('Packages and registries') end + it 'passes axe automated accessibility testing', :js do + visit_settings_page + + wait_for_requests + + expect(page).to be_axe_clean.within('[data-testid="packages-and-registries-group-settings"]') + .skipping :'link-in-text-block' + end + it 'has a Duplicate packages section', :js do visit_settings_page diff --git a/spec/features/groups/show_spec.rb b/spec/features/groups/show_spec.rb index 5cab79b40cf..0f936173e5d 100644 --- a/spec/features/groups/show_spec.rb +++ b/spec/features/groups/show_spec.rb @@ -3,7 +3,7 @@ require 'spec_helper' RSpec.describe 'Group show page', feature_category: :subgroups do - include Spec::Support::Helpers::Features::InviteMembersModalHelper + include Features::InviteMembersModalHelpers let_it_be(:user) { create(:user) } let_it_be(:group) { create(:group) } diff --git a/spec/features/groups_spec.rb b/spec/features/groups_spec.rb index 8806d1c2219..088b5b11a9a 100644 --- a/spec/features/groups_spec.rb +++ b/spec/features/groups_spec.rb @@ -510,6 +510,47 @@ RSpec.describe 'Group', feature_category: :subgroups do end end end + + context 'when in a private group' do + before do + group.update!( + visibility_level: Gitlab::VisibilityLevel::PRIVATE, + project_creation_level: Gitlab::Access::MAINTAINER_PROJECT_ACCESS + ) + end + + context 'when visibility levels have been restricted to private only by an administrator' do + before do + stub_application_setting( + restricted_visibility_levels: [ + Gitlab::VisibilityLevel::PRIVATE + ] + ) + end + + it 'does not display the "New project" button' do + visit group_path(group) + + page.within '[data-testid="group-buttons"]' do + expect(page).not_to have_link('New project') + end + end + end + end + end + + describe 'group README', :js do + context 'with gitlab-profile project and README.md' do + let_it_be(:group) { create(:group) } + let_it_be(:project) { create(:project, :readme, namespace: group) } + + it 'renders README block on group page' do + visit group_path(group) + wait_for_requests + + expect(page).to have_text('README.md') + end + end end def remove_with_confirm(button_text, confirm_with) diff --git a/spec/features/help_dropdown_spec.rb b/spec/features/help_dropdown_spec.rb index a5c9221ad26..5f1d3a5e2b7 100644 --- a/spec/features/help_dropdown_spec.rb +++ b/spec/features/help_dropdown_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' -RSpec.describe "Help Dropdown", :js, feature_category: :not_owned do +RSpec.describe "Help Dropdown", :js, feature_category: :shared do let_it_be(:user) { create(:user) } let_it_be(:admin) { create(:admin) } diff --git a/spec/features/help_pages_spec.rb b/spec/features/help_pages_spec.rb index 6c0901d6169..905c5e25f6e 100644 --- a/spec/features/help_pages_spec.rb +++ b/spec/features/help_pages_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' -RSpec.describe 'Help Pages', feature_category: :not_owned do +RSpec.describe 'Help Pages', feature_category: :shared do describe 'Get the main help page' do before do allow(File).to receive(:read).and_call_original diff --git a/spec/features/ide/user_opens_merge_request_spec.rb b/spec/features/ide/user_opens_merge_request_spec.rb index 0074b4b1eb0..dc280133a20 100644 --- a/spec/features/ide/user_opens_merge_request_spec.rb +++ b/spec/features/ide/user_opens_merge_request_spec.rb @@ -3,6 +3,8 @@ require 'spec_helper' RSpec.describe 'IDE merge request', :js, feature_category: :web_ide do + include CookieHelper + let(:merge_request) { create(:merge_request, :simple, source_project: project) } let(:project) { create(:project, :public, :repository) } let(:user) { project.first_owner } @@ -12,6 +14,8 @@ RSpec.describe 'IDE merge request', :js, feature_category: :web_ide do sign_in(user) + set_cookie('new-actions-popover-viewed', 'true') + visit(merge_request_path(merge_request)) end diff --git a/spec/features/ide_spec.rb b/spec/features/ide_spec.rb index 2ca8d3f7156..bdf8be95415 100644 --- a/spec/features/ide_spec.rb +++ b/spec/features/ide_spec.rb @@ -3,7 +3,7 @@ require 'spec_helper' RSpec.describe 'IDE', :js, feature_category: :web_ide do - include WebIdeSpecHelpers + include Features::WebIdeSpecHelpers let_it_be(:ide_iframe_selector) { '#ide iframe' } let_it_be(:normal_project) { create(:project, :repository) } @@ -48,17 +48,6 @@ RSpec.describe 'IDE', :js, feature_category: :web_ide do it_behaves_like 'legacy Web IDE' end - context 'with vscode feature flag on and use_legacy_web_ide=true' do - let(:vscode_ff) { true } - let(:user) { create(:user, use_legacy_web_ide: true) } - - before do - ide_visit(project) - end - - it_behaves_like 'legacy Web IDE' - end - describe 'sub-groups' do let_it_be(:group) { create(:group) } let_it_be(:subgroup) { create(:group, parent: group) } diff --git a/spec/features/import/manifest_import_spec.rb b/spec/features/import/manifest_import_spec.rb index bb3eb34637b..aba38eb0196 100644 --- a/spec/features/import/manifest_import_spec.rb +++ b/spec/features/import/manifest_import_spec.rb @@ -7,6 +7,8 @@ RSpec.describe 'Import multiple repositories by uploading a manifest file', :js, let(:group) { create(:group) } before do + stub_application_setting(import_sources: ['manifest']) + sign_in(user) group.add_owner(user) diff --git a/spec/features/incidents/incident_details_spec.rb b/spec/features/incidents/incident_details_spec.rb index 709919d0196..a166ff46177 100644 --- a/spec/features/incidents/incident_details_spec.rb +++ b/spec/features/incidents/incident_details_spec.rb @@ -94,6 +94,7 @@ RSpec.describe 'Incident details', :js, feature_category: :incident_management d end it 'routes the user to the incident details page when the `issue_type` is set to incident' do + set_cookie('new-actions-popover-viewed', 'true') visit project_issue_path(project, issue) wait_for_requests @@ -113,6 +114,7 @@ RSpec.describe 'Incident details', :js, feature_category: :incident_management d end it 'routes the user to the issue details page when the `issue_type` is set to issue' do + set_cookie('new-actions-popover-viewed', 'true') visit incident_project_issues_path(project, incident) wait_for_requests diff --git a/spec/features/incidents/incident_timeline_events_spec.rb b/spec/features/incidents/incident_timeline_events_spec.rb index 7404ac64cc9..4d51ed652c9 100644 --- a/spec/features/incidents/incident_timeline_events_spec.rb +++ b/spec/features/incidents/incident_timeline_events_spec.rb @@ -43,9 +43,7 @@ RSpec.describe 'Incident timeline events', :js, feature_category: :incident_mana expect(page).to have_content(s_('Incident|No timeline items have been added yet.')) end - it 'submits event data on save with feature flag on' do - stub_feature_flags(incident_event_tags: true) - + it 'submits event data on save' do # Add event click_button(s_('Incident|Add new timeline event')) @@ -96,5 +94,6 @@ RSpec.describe 'Incident timeline events', :js, feature_category: :incident_mana it_behaves_like 'for each incident details route', 'add, edit, and delete timeline events', - tab_text: s_('Incident|Timeline') + tab_text: s_('Incident|Timeline'), + tab: 'timeline' end diff --git a/spec/features/incidents/user_uses_quick_actions_spec.rb b/spec/features/incidents/user_uses_quick_actions_spec.rb index 3740f2fca47..27facbcafe8 100644 --- a/spec/features/incidents/user_uses_quick_actions_spec.rb +++ b/spec/features/incidents/user_uses_quick_actions_spec.rb @@ -3,7 +3,7 @@ require 'spec_helper' RSpec.describe 'Incidents > User uses quick actions', :js, feature_category: :incident_management do - include Spec::Support::Helpers::Features::NotesHelpers + include Features::NotesHelpers describe 'incident-only commands' do let_it_be(:user) { create(:user) } diff --git a/spec/features/incidents/user_views_alert_details_spec.rb b/spec/features/incidents/user_views_alert_details_spec.rb new file mode 100644 index 00000000000..f3d0273071c --- /dev/null +++ b/spec/features/incidents/user_views_alert_details_spec.rb @@ -0,0 +1,34 @@ +# frozen_string_literal: true + +require 'spec_helper' + +RSpec.describe 'User uploads alerts to incident', :js, feature_category: :incident_management do + let_it_be(:incident) { create(:incident) } + let_it_be(:project) { incident.project } + let_it_be(:user) { create(:user, developer_projects: [project]) } + + context 'with alert' do + let_it_be(:alert) { create(:alert_management_alert, issue_id: incident.id, project: project) } + + shared_examples 'shows alert tab with details' do + specify do + expect(page).to have_link(s_('Incident|Alert details')) + expect(page).to have_content(alert.title) + end + end + + it_behaves_like 'for each incident details route', + 'shows alert tab with details', + tab_text: s_('Incident|Alert details'), + tab: 'alerts' + end + + context 'with no alerts' do + it 'hides the Alert details tab' do + sign_in(user) + visit project_issue_path(project, incident) + + expect(page).not_to have_link(s_('Incident|Alert details')) + end + end +end diff --git a/spec/features/integrations_settings_spec.rb b/spec/features/integrations_settings_spec.rb new file mode 100644 index 00000000000..70ce2f55161 --- /dev/null +++ b/spec/features/integrations_settings_spec.rb @@ -0,0 +1,29 @@ +# frozen_string_literal: true + +require 'spec_helper' + +RSpec.describe 'Integration settings', feature_category: :integrations do + let_it_be(:project) { create(:project) } + let_it_be(:user) { create(:user) } + + before do + project.add_maintainer(user) + sign_in(user) + end + + context 'with Shimo Zentao integration records' do + before do + create(:integration, project: project, type_new: 'Integrations::Shimo', category: 'issue_tracker') + create(:integration, project: project, type_new: 'Integrations::Zentao', category: 'issue_tracker') + end + + it 'shows settings without Shimo Zentao', :js do + visit namespace_project_settings_integrations_path(namespace_id: project.namespace.full_path, + project_id: project.path) + + expect(page).to have_content('Add an integration') + expect(page).not_to have_content('ZenTao') + expect(page).not_to have_content('Shimo') + end + end +end diff --git a/spec/features/invites_spec.rb b/spec/features/invites_spec.rb index 1091bea1ce3..a3d4b30b59c 100644 --- a/spec/features/invites_spec.rb +++ b/spec/features/invites_spec.rb @@ -28,14 +28,10 @@ RSpec.describe 'Group or Project invitations', :aggregate_failures, feature_cate fill_in 'new_user_username', with: new_user.username fill_in 'new_user_email', with: new_user.email fill_in 'new_user_password', with: new_user.password - click_button submit_button_text - end - def fill_in_sign_in_form(user) - fill_in 'user_login', with: user.email - fill_in 'user_password', with: user.password - check 'user_remember_me' - click_button 'Sign in' + wait_for_all_requests + + click_button submit_button_text end def fill_in_welcome_form @@ -73,7 +69,7 @@ RSpec.describe 'Group or Project invitations', :aggregate_failures, feature_cate end end - context 'when invite is sent before account is created - ldap or service sign in for manual acceptance edge case' do + context 'when invite is sent before account is created;ldap or service sign in for manual acceptance edge case' do let(:user) { create(:user, email: 'user@example.com') } context 'when invite clicked and not signed in' do @@ -84,7 +80,7 @@ RSpec.describe 'Group or Project invitations', :aggregate_failures, feature_cate it 'sign in, grants access and redirects to group activity page' do click_link 'Sign in' - fill_in_sign_in_form(user) + gitlab_sign_in(user, remember: true, visit: false) expect(page).to have_current_path(activity_group_path(group), ignore_query: true) end @@ -151,7 +147,7 @@ RSpec.describe 'Group or Project invitations', :aggregate_failures, feature_cate end end - context 'when inviting an unregistered user' do + context 'when inviting an unregistered user', :js do let(:new_user) { build_stubbed(:user) } let(:invite_email) { new_user.email } let(:group_invite) { create(:group_member, :invited, group: group, invite_email: invite_email, created_by: owner) } @@ -175,17 +171,19 @@ RSpec.describe 'Group or Project invitations', :aggregate_failures, feature_cate fill_in_sign_up_form(new_user) expect(page).to have_current_path(new_user_session_path, ignore_query: true) - expect(page).to have_content('You have signed up successfully. However, we could not sign you in because your account is awaiting approval from your GitLab administrator') + sign_up_message = 'You have signed up successfully. However, we could not sign you in because your account ' \ + 'is awaiting approval from your GitLab administrator.' + expect(page).to have_content(sign_up_message) end end - context 'email confirmation disabled' do + context 'with email confirmation disabled' do before do stub_application_setting_enum('email_confirmation_setting', 'off') end - context 'the user signs up for an account with the invitation email address' do - it 'redirects to the most recent membership activity page with all the projects/groups invitations automatically accepted' do + context 'when the user signs up for an account with the invitation email address' do + it 'redirects to the most recent membership activity page with all invitations automatically accepted' do fill_in_sign_up_form(new_user) fill_in_welcome_form @@ -194,7 +192,7 @@ RSpec.describe 'Group or Project invitations', :aggregate_failures, feature_cate end end - context 'the user sign-up using a different email address' do + context 'when the user sign-up using a different email address' do let(:invite_email) { build_stubbed(:user).email } it 'signs up and redirects to the activity page' do @@ -206,9 +204,9 @@ RSpec.describe 'Group or Project invitations', :aggregate_failures, feature_cate end end - context 'email confirmation enabled' do + context 'with email confirmation enabled' do context 'when user is not valid in sign up form' do - let(:new_user) { build_stubbed(:user, first_name: '', last_name: '') } + let(:new_user) { build_stubbed(:user, password: '11111111') } it 'fails sign up and redirects back to sign up', :aggregate_failures do expect { fill_in_sign_up_form(new_user) }.not_to change { User.count } @@ -232,8 +230,8 @@ RSpec.describe 'Group or Project invitations', :aggregate_failures, feature_cate end end - context 'the user signs up for an account with the invitation email address' do - it 'redirects to the most recent membership activity page with all the projects/groups invitations automatically accepted' do + context 'when the user signs up for an account with the invitation email address' do + it 'redirects to the most recent membership activity page with all invitations automatically accepted' do fill_in_sign_up_form(new_user) fill_in_welcome_form @@ -241,12 +239,11 @@ RSpec.describe 'Group or Project invitations', :aggregate_failures, feature_cate end end - context 'the user sign-up using a different email address' do + context 'when the user signs up using a different email address' do let(:invite_email) { build_stubbed(:user).email } - context 'when soft email confirmation is not enabled' do + context 'when email confirmation is not set to `soft`' do before do - stub_feature_flags(soft_email_confirmation: false) allow(User).to receive(:allow_unconfirmed_access_for).and_return 0 stub_feature_flags(identity_verification: false) end @@ -254,16 +251,16 @@ RSpec.describe 'Group or Project invitations', :aggregate_failures, feature_cate it 'signs up and redirects to the group activity page' do fill_in_sign_up_form(new_user) confirm_email(new_user) - fill_in_sign_in_form(new_user) + gitlab_sign_in(new_user, remember: true, visit: false) fill_in_welcome_form expect(page).to have_current_path(activity_group_path(group), ignore_query: true) end end - context 'when soft email confirmation is enabled' do + context 'when email confirmation setting is set to `soft`' do before do - stub_feature_flags(soft_email_confirmation: true) + stub_application_setting_enum('email_confirmation_setting', 'soft') allow(User).to receive(:allow_unconfirmed_access_for).and_return 2.days end diff --git a/spec/features/issuables/issuable_list_spec.rb b/spec/features/issuables/issuable_list_spec.rb index 350b0582565..c979aff2147 100644 --- a/spec/features/issuables/issuable_list_spec.rb +++ b/spec/features/issuables/issuable_list_spec.rb @@ -48,7 +48,7 @@ RSpec.describe 'issuable list', :js, feature_category: :team_planning do end end - it 'displays a warning if counting the number of issues times out' do + it 'displays a warning if counting the number of issues times out', quarantine: 'https://gitlab.com/gitlab-org/gitlab/-/issues/393344' do allow_any_instance_of(IssuesFinder).to receive(:count_by_state).and_raise(ActiveRecord::QueryCanceled) visit_issuable_list(:issue) diff --git a/spec/features/issuables/markdown_references/internal_references_spec.rb b/spec/features/issuables/markdown_references/internal_references_spec.rb index aeae76b1b77..04950c7c7d4 100644 --- a/spec/features/issuables/markdown_references/internal_references_spec.rb +++ b/spec/features/issuables/markdown_references/internal_references_spec.rb @@ -3,7 +3,7 @@ require 'spec_helper' RSpec.describe "Internal references", :js, feature_category: :team_planning do - include Spec::Support::Helpers::Features::NotesHelpers + include Features::NotesHelpers let(:private_project_user) { private_project.first_owner } let(:private_project) { create(:project, :private, :repository) } diff --git a/spec/features/issuables/markdown_references/jira_spec.rb b/spec/features/issuables/markdown_references/jira_spec.rb index 52464c6be8b..887bc7d0c87 100644 --- a/spec/features/issuables/markdown_references/jira_spec.rb +++ b/spec/features/issuables/markdown_references/jira_spec.rb @@ -29,7 +29,7 @@ RSpec.describe "Jira", :js, feature_category: :team_planning do end it "creates a link to the referenced issue on the preview" do - find(".js-md-preview-button").click + click_button("Preview") wait_for_requests diff --git a/spec/features/issues/create_issue_for_discussions_in_merge_request_spec.rb b/spec/features/issues/create_issue_for_discussions_in_merge_request_spec.rb index 0bdb5930f30..c982052fc0e 100644 --- a/spec/features/issues/create_issue_for_discussions_in_merge_request_spec.rb +++ b/spec/features/issues/create_issue_for_discussions_in_merge_request_spec.rb @@ -20,6 +20,7 @@ RSpec.describe 'Resolving all open threads in a merge request from an issue', :j before do stub_feature_flags(moved_mr_sidebar: false) + stub_feature_flags(hide_create_issue_resolve_all: false) end describe 'as a user with access to the project' do @@ -33,7 +34,7 @@ RSpec.describe 'Resolving all open threads in a merge request from an issue', :j find('.discussions-counter .dropdown-toggle').click within('.discussions-counter') do - expect(page).to have_link(_("Create issue to resolve all threads"), href: new_project_issue_path(project, merge_request_to_resolve_discussions_of: merge_request.iid)) + expect(page).to have_link(_("Resolve all with new issue"), href: new_project_issue_path(project, merge_request_to_resolve_discussions_of: merge_request.iid)) end end @@ -44,7 +45,7 @@ RSpec.describe 'Resolving all open threads in a merge request from an issue', :j it 'hides the link for creating a new issue' do expect(page).not_to have_selector resolve_all_discussions_link_selector - expect(page).not_to have_content "Create issue to resolve all threads" + expect(page).not_to have_content "Resolve all with new issue" end end @@ -69,7 +70,7 @@ RSpec.describe 'Resolving all open threads in a merge request from an issue', :j end it 'does not show a link to create a new issue' do - expect(page).not_to have_link 'Create issue to resolve all threads' + expect(page).not_to have_link 'Resolve all with new issue' end end @@ -83,13 +84,13 @@ RSpec.describe 'Resolving all open threads in a merge request from an issue', :j end it 'has a link to resolve all threads by creating an issue' do - expect(page).to have_link 'Create issue to resolve all threads', href: new_project_issue_path(project, merge_request_to_resolve_discussions_of: merge_request.iid) + expect(page).to have_link 'Resolve all with new issue', href: new_project_issue_path(project, merge_request_to_resolve_discussions_of: merge_request.iid) end context 'creating an issue for threads' do before do page.within '.mr-state-widget' do - page.click_link 'Create issue to resolve all threads', href: new_project_issue_path(project, merge_request_to_resolve_discussions_of: merge_request.iid) + page.click_link 'Resolve all with new issue', href: new_project_issue_path(project, merge_request_to_resolve_discussions_of: merge_request.iid) wait_for_all_requests end diff --git a/spec/features/issues/csv_spec.rb b/spec/features/issues/csv_spec.rb index 8629201459f..21d5041b210 100644 --- a/spec/features/issues/csv_spec.rb +++ b/spec/features/issues/csv_spec.rb @@ -16,6 +16,7 @@ RSpec.describe 'Issues csv', :js, feature_category: :team_planning do def request_csv(params = {}) visit project_issues_path(project, params) + click_button 'Actions' click_button 'Export as CSV' click_on 'Export issues' end diff --git a/spec/features/issues/discussion_lock_spec.rb b/spec/features/issues/discussion_lock_spec.rb index 33fc9a6fd96..fb9addff1a2 100644 --- a/spec/features/issues/discussion_lock_spec.rb +++ b/spec/features/issues/discussion_lock_spec.rb @@ -9,6 +9,7 @@ RSpec.describe 'Discussion Lock', :js, feature_category: :team_planning do before do sign_in(user) + stub_feature_flags(moved_mr_sidebar: false) end context 'when a user is a team member' do @@ -99,7 +100,7 @@ RSpec.describe 'Discussion Lock', :js, feature_category: :team_planning do it 'the user can not create a comment' do page.within('#notes') do expect(page).not_to have_selector('js-main-target-form') - expect(page.find('.disabled-comment')) + expect(page.find('.disabled-comments')) .to have_content('This issue is locked. Only project members can comment.') end end diff --git a/spec/features/issues/filtered_search/dropdown_hint_spec.rb b/spec/features/issues/filtered_search/dropdown_hint_spec.rb index 39034a40b1f..1cd8326c5fe 100644 --- a/spec/features/issues/filtered_search/dropdown_hint_spec.rb +++ b/spec/features/issues/filtered_search/dropdown_hint_spec.rb @@ -52,8 +52,8 @@ RSpec.describe 'Dropdown hint', :js, feature_category: :team_planning do click_filtered_search_bar send_keys 'as' - # Expect Assignee and Release - expect_suggestion_count 2 + # Expect Assignee, Release, Search for this text + expect_suggestion_count 3 end end diff --git a/spec/features/issues/filtered_search/filter_issues_spec.rb b/spec/features/issues/filtered_search/filter_issues_spec.rb index f67d5c40efd..a65befc3115 100644 --- a/spec/features/issues/filtered_search/filter_issues_spec.rb +++ b/spec/features/issues/filtered_search/filter_issues_spec.rb @@ -61,7 +61,7 @@ RSpec.describe 'Filter issues', :js, feature_category: :team_planning do it 'filters by all available tokens' do search_term = 'issue' select_tokens 'Assignee', '=', user.username, 'Author', '=', user.username, 'Label', '=', caps_sensitive_label.title, 'Milestone', '=', milestone.title - send_keys search_term, :enter + send_keys search_term, :enter, :enter expect_assignee_token(user.name) expect_author_token(user.name) @@ -261,7 +261,7 @@ RSpec.describe 'Filter issues', :js, feature_category: :team_planning do it 'filters issues by searched label, label2, author, assignee, milestone and text' do search_term = 'bug' select_tokens 'Label', '=', bug_label.title, 'Label', '=', caps_sensitive_label.title, 'Author', '=', user.username, 'Assignee', '=', user.username, 'Milestone', '=', milestone.title - send_keys search_term, :enter + send_keys search_term, :enter, :enter expect_label_token(bug_label.title) expect_label_token(caps_sensitive_label.title) @@ -275,7 +275,7 @@ RSpec.describe 'Filter issues', :js, feature_category: :team_planning do it 'filters issues by searched label, label2, author, assignee, not included in a milestone' do search_term = 'bug' select_tokens 'Label', '=', bug_label.title, 'Label', '=', caps_sensitive_label.title, 'Author', '=', user.username, 'Assignee', '=', user.username, 'Milestone', '!=', milestone.title - send_keys search_term, :enter + send_keys search_term, :enter, :enter expect_label_token(bug_label.title) expect_label_token(caps_sensitive_label.title) @@ -488,13 +488,13 @@ RSpec.describe 'Filter issues', :js, feature_category: :team_planning do context 'searched text with other filters' do it 'filters issues by searched text, author, text, assignee, text, label1, text, label2, text, milestone and text' do click_filtered_search_bar - send_keys 'bug ' + send_keys 'bug', :enter select_tokens 'Author', '=', user.username - send_keys 'report ' + send_keys 'report', :enter select_tokens 'Label', '=', bug_label.title select_tokens 'Label', '=', caps_sensitive_label.title select_tokens 'Milestone', '=', milestone.title - send_keys 'foo', :enter + send_keys 'foo', :enter, :enter expect_issues_list_count(1) expect_search_term('bug report foo') diff --git a/spec/features/issues/filtered_search/recent_searches_spec.rb b/spec/features/issues/filtered_search/recent_searches_spec.rb index 2d9c73f2756..0efa2f49e36 100644 --- a/spec/features/issues/filtered_search/recent_searches_spec.rb +++ b/spec/features/issues/filtered_search/recent_searches_spec.rb @@ -100,7 +100,7 @@ RSpec.describe 'Recent searches', :js, feature_category: :team_planning do def submit_then_clear_search(search) click_filtered_search_bar - send_keys(search, :enter) + send_keys(search, :enter, :enter) click_button 'Clear' end end diff --git a/spec/features/issues/filtered_search/search_bar_spec.rb b/spec/features/issues/filtered_search/search_bar_spec.rb index c975df2a531..35c099b29aa 100644 --- a/spec/features/issues/filtered_search/search_bar_spec.rb +++ b/spec/features/issues/filtered_search/search_bar_spec.rb @@ -70,7 +70,8 @@ RSpec.describe 'Search bar', :js, feature_category: :team_planning do original_size = get_suggestion_count send_keys 'autho' - expect_suggestion_count 1 + # Expect Author, Search for this text + expect_suggestion_count 2 click_button 'Clear' click_filtered_search_bar diff --git a/spec/features/issues/filtered_search/visual_tokens_spec.rb b/spec/features/issues/filtered_search/visual_tokens_spec.rb index f25925ed33d..3031b20eb7c 100644 --- a/spec/features/issues/filtered_search/visual_tokens_spec.rb +++ b/spec/features/issues/filtered_search/visual_tokens_spec.rb @@ -79,10 +79,10 @@ RSpec.describe 'Visual tokens', :js, feature_category: :team_planning do describe 'editing a search term while editing another filter token' do before do click_filtered_search_bar - send_keys 'foo ' + send_keys 'foo', :enter select_tokens 'Assignee', '=' click_token_segment 'foo' - send_keys ' ' + send_keys :enter end it 'opens author dropdown' do @@ -98,44 +98,6 @@ RSpec.describe 'Visual tokens', :js, feature_category: :team_planning do end end - describe 'add new token after editing existing token' do - before do - select_tokens 'Assignee', '=', user.username, 'Label', '=', 'None' - click_token_segment(user.name) - send_keys ' ' - end - - describe 'opens dropdowns' do - it 'opens hint dropdown' do - expect_visible_suggestions_list - end - - it 'opens token dropdown' do - click_on 'Author' - - expect_visible_suggestions_list - end - end - - describe 'visual tokens' do - it 'creates visual token' do - click_on 'Author' - click_on '= is' - click_on 'The Rock' - - expect_author_token 'The Rock' - end - end - - it 'does not tokenize incomplete token' do - click_on 'Author' - find('.js-navbar').click - - expect_empty_search_term - expect_token_segment 'Assignee' - end - end - describe 'search using incomplete visual tokens' do before do select_tokens 'Author', '=', user.username, 'Assignee', '=', 'None' diff --git a/spec/features/issues/form_spec.rb b/spec/features/issues/form_spec.rb index 585740f7782..9702e43a559 100644 --- a/spec/features/issues/form_spec.rb +++ b/spec/features/issues/form_spec.rb @@ -4,6 +4,7 @@ require 'spec_helper' RSpec.describe 'New/edit issue', :js, feature_category: :team_planning do include ActionView::Helpers::JavaScriptHelper + include ListboxHelpers let_it_be(:project) { create(:project, :repository) } let_it_be(:user) { create(:user) } @@ -13,9 +14,11 @@ RSpec.describe 'New/edit issue', :js, feature_category: :team_planning do let_it_be(:label) { create(:label, project: project) } let_it_be(:label2) { create(:label, project: project) } let_it_be(:issue) { create(:issue, project: project, assignees: [user], milestone: milestone) } + let_it_be(:issue2) { create(:issue, project: project, assignees: [user], milestone: milestone) } let_it_be(:confidential_issue) { create(:issue, project: project, assignees: [user], milestone: milestone, confidential: true) } let(:current_user) { user } + let(:visible_label_selection_on_metadata) { false } before_all do project.add_maintainer(user) @@ -25,6 +28,7 @@ RSpec.describe 'New/edit issue', :js, feature_category: :team_planning do before do stub_licensed_features(multiple_issue_assignees: false, issue_weights: false) + stub_feature_flags(visible_label_selection_on_metadata: visible_label_selection_on_metadata) sign_in(current_user) end @@ -112,110 +116,240 @@ RSpec.describe 'New/edit issue', :js, feature_category: :team_planning do end end - it 'allows user to create new issue' do - fill_in 'issue_title', with: 'title' - fill_in 'issue_description', with: 'title' + context 'with the visible_label_selection_on_metadata feature flag enabled' do + let(:visible_label_selection_on_metadata) { true } - expect(find('a', text: 'Assign to me')).to be_visible - click_button 'Unassigned' + it 'allows user to create new issue' do + fill_in 'issue_title', with: 'title' + fill_in 'issue_description', with: 'title' - wait_for_requests + expect(find('a', text: 'Assign to me')).to be_visible + click_button 'Unassigned' - page.within '.dropdown-menu-user' do - click_link user2.name - end - expect(find('input[name="issue[assignee_ids][]"]', visible: false).value).to match(user2.id.to_s) - page.within '.js-assignee-search' do - expect(page).to have_content user2.name - end - expect(find('a', text: 'Assign to me')).to be_visible + wait_for_requests + + page.within '.dropdown-menu-user' do + click_link user2.name + end + expect(find('input[name="issue[assignee_ids][]"]', visible: false).value).to match(user2.id.to_s) + page.within '.js-assignee-search' do + expect(page).to have_content user2.name + end + expect(find('a', text: 'Assign to me')).to be_visible + + click_link 'Assign to me' + assignee_ids = page.all('input[name="issue[assignee_ids][]"]', visible: false) + + expect(assignee_ids[0].value).to match(user.id.to_s) + + page.within '.js-assignee-search' do + expect(page).to have_content user.name + end + expect(find('a', text: 'Assign to me', visible: false)).not_to be_visible + + click_button 'Select milestone' + click_button milestone.title + expect(find('input[name="issue[milestone_id]"]', visible: false).value).to match(milestone.id.to_s) + expect(page).to have_button milestone.title + + click_button _('Select label') + wait_for_all_requests + page.within '[data-testid="sidebar-labels"]' do + click_button label.title + click_button label2.title + click_button _('Close') + wait_for_requests + page.within('[data-testid="embedded-labels-list"]') do + expect(page).to have_content(label.title) + expect(page).to have_content(label2.title) + end + end + + click_button 'Create issue' + + page.within '.issuable-sidebar' do + page.within '.assignee' do + expect(page).to have_content "Assignee" + end - click_link 'Assign to me' - assignee_ids = page.all('input[name="issue[assignee_ids][]"]', visible: false) + page.within '.milestone' do + expect(page).to have_content milestone.title + end + + page.within '.labels' do + expect(page).to have_content label.title + expect(page).to have_content label2.title + end + end - expect(assignee_ids[0].value).to match(user.id.to_s) + page.within '.breadcrumbs' do + issue = Issue.find_by(title: 'title') - page.within '.js-assignee-search' do - expect(page).to have_content user.name + expect(page).to have_text("Issues #{issue.to_reference}") + end end - expect(find('a', text: 'Assign to me', visible: false)).not_to be_visible - click_button 'Select milestone' - click_button milestone.title - expect(find('input[name="issue[milestone_id]"]', visible: false).value).to match(milestone.id.to_s) - expect(page).to have_button milestone.title + it 'correctly updates the dropdown toggle when removing a label' do + click_button _('Select label') + + wait_for_all_requests - click_button 'Labels' - page.within '.dropdown-menu-labels' do - click_link label.title - click_link label2.title + page.within '[data-testid="sidebar-labels"]' do + click_button label.title + click_button _('Close') + + wait_for_requests + + page.within('[data-testid="embedded-labels-list"]') do + expect(page).to have_content(label.title) + end + + expect(page.find('.gl-dropdown-button-text')).to have_content(label.title) + end + + click_button label.title, class: 'gl-dropdown-toggle' + + wait_for_all_requests + + page.within '[data-testid="sidebar-labels"]' do + click_button label.title, class: 'dropdown-item' + click_button _('Close') + + wait_for_requests + + expect(page).not_to have_selector('[data-testid="embedded-labels-list"]') + expect(page.find('.gl-dropdown-button-text')).to have_content(_('Select label')) + end end - find('.js-issuable-form-dropdown.js-label-select').click + it 'clears label search input field when a label is selected', :js do + click_button _('Select label') - page.within '.js-label-select' do - expect(page).to have_content label.title + wait_for_all_requests + + page.within '[data-testid="sidebar-labels"]' do + search_field = find('input[type="search"]') + + search_field.native.send_keys(label.title) + + expect(page).to have_css('.gl-search-box-by-type-clear') + + click_button label.title, class: 'dropdown-item' + + expect(page).not_to have_css('.gl-search-box-by-type-clear') + expect(search_field.value).to eq '' + end end - expect(page.all('input[name="issue[label_ids][]"]', visible: false)[1].value).to match(label.id.to_s) - expect(page.all('input[name="issue[label_ids][]"]', visible: false)[2].value).to match(label2.id.to_s) + end - click_button 'Create issue' + context 'with the visible_label_selection_on_metadata feature flag disabled' do + let(:visible_label_selection_on_metadata) { false } + + it 'allows user to create new issue' do + fill_in 'issue_title', with: 'title' + fill_in 'issue_description', with: 'title' - page.within '.issuable-sidebar' do - page.within '.assignee' do - expect(page).to have_content "Assignee" + expect(find('a', text: 'Assign to me')).to be_visible + click_button 'Unassigned' + + wait_for_requests + + page.within '.dropdown-menu-user' do + click_link user2.name end + expect(find('input[name="issue[assignee_ids][]"]', visible: false).value).to match(user2.id.to_s) + page.within '.js-assignee-search' do + expect(page).to have_content user2.name + end + expect(find('a', text: 'Assign to me')).to be_visible + + click_link 'Assign to me' + assignee_ids = page.all('input[name="issue[assignee_ids][]"]', visible: false) + + expect(assignee_ids[0].value).to match(user.id.to_s) + + page.within '.js-assignee-search' do + expect(page).to have_content user.name + end + expect(find('a', text: 'Assign to me', visible: false)).not_to be_visible - page.within '.milestone' do - expect(page).to have_content milestone.title + click_button 'Select milestone' + click_button milestone.title + expect(find('input[name="issue[milestone_id]"]', visible: false).value).to match(milestone.id.to_s) + expect(page).to have_button milestone.title + + click_button 'Labels' + page.within '.dropdown-menu-labels' do + click_link label.title + click_link label2.title end - page.within '.labels' do + find('.js-issuable-form-dropdown.js-label-select').click + + page.within '.js-label-select' do expect(page).to have_content label.title - expect(page).to have_content label2.title end - end + expect(page.all('input[name="issue[label_ids][]"]', visible: false)[1].value).to match(label.id.to_s) + expect(page.all('input[name="issue[label_ids][]"]', visible: false)[2].value).to match(label2.id.to_s) - page.within '.breadcrumbs' do - issue = Issue.find_by(title: 'title') + click_button 'Create issue' - expect(page).to have_text("Issues #{issue.to_reference}") - end - end + page.within '.issuable-sidebar' do + page.within '.assignee' do + expect(page).to have_content "Assignee" + end - it 'displays an error message when submitting an invalid form' do - click_button 'Create issue' + page.within '.milestone' do + expect(page).to have_content milestone.title + end - page.within('[data-testid="issue-title-input-field"]') do - expect(page).to have_text(_('This field is required.')) - end - end + page.within '.labels' do + expect(page).to have_content label.title + expect(page).to have_content label2.title + end + end - it 'correctly updates the dropdown toggle when removing a label' do - click_button 'Labels' + page.within '.breadcrumbs' do + issue = Issue.find_by(title: 'title') - page.within '.dropdown-menu-labels' do - click_link label.title + expect(page).to have_text("Issues #{issue.to_reference}") + end end - expect(find('.js-label-select')).to have_content(label.title) + it 'correctly updates the dropdown toggle when removing a label' do + click_button 'Labels' + + page.within '.dropdown-menu-labels' do + click_link label.title + end + + expect(find('.js-label-select')).to have_content(label.title) + + page.within '.dropdown-menu-labels' do + click_link label.title + end - page.within '.dropdown-menu-labels' do - click_link label.title + expect(find('.js-label-select')).to have_content('Labels') end - expect(find('.js-label-select')).to have_content('Labels') - end + it 'clears label search input field when a label is selected' do + click_button 'Labels' + + page.within '.dropdown-menu-labels' do + search_field = find('input[type="search"]') - it 'clears label search input field when a label is selected' do - click_button 'Labels' + search_field.set(label2.title) + click_link label2.title + expect(search_field.value).to eq '' + end + end + end - page.within '.dropdown-menu-labels' do - search_field = find('input[type="search"]') + it 'displays an error message when submitting an invalid form' do + click_button 'Create issue' - search_field.set(label2.title) - click_link label2.title - expect(search_field.value).to eq '' + page.within('[data-testid="issue-title-input-field"]') do + expect(page).to have_text(_('This field is required.')) end end @@ -248,19 +382,15 @@ RSpec.describe 'New/edit issue', :js, feature_category: :team_planning do describe 'displays issue type options in the dropdown' do shared_examples 'type option is visible' do |label:, identifier:| it "shows #{identifier} option", :aggregate_failures do - page.within('[data-testid="issue-type-select-dropdown"]') do - expect(page).to have_selector(%([data-testid="issue-type-#{identifier}-icon"])) - expect(page).to have_content(label) - end + wait_for_requests + expect_listbox_item(label) end end shared_examples 'type option is missing' do |label:, identifier:| it "does not show #{identifier} option", :aggregate_failures do - page.within('[data-testid="issue-type-select-dropdown"]') do - expect(page).not_to have_selector(%([data-testid="issue-type-#{identifier}-icon"])) - expect(page).not_to have_content(label) - end + wait_for_requests + expect_no_listbox_item(label) end end @@ -428,42 +558,100 @@ RSpec.describe 'New/edit issue', :js, feature_category: :team_planning do visit edit_project_issue_path(project, issue) end - it 'allows user to update issue' do - expect(find('input[name="issue[assignee_ids][]"]', visible: false).value).to match(user.id.to_s) - expect(find('input[name="issue[milestone_id]"]', visible: false).value).to match(milestone.id.to_s) - expect(find('a', text: 'Assign to me', visible: false)).not_to be_visible + context 'with the visible_label_selection_on_metadata feature flag enabled' do + let(:visible_label_selection_on_metadata) { true } - page.within '.js-user-search' do - expect(page).to have_content user.name - end + it 'allows user to update issue' do + expect(find('input[name="issue[assignee_ids][]"]', visible: false).value).to match(user.id.to_s) + expect(find('input[name="issue[milestone_id]"]', visible: false).value).to match(milestone.id.to_s) + expect(find('a', text: 'Assign to me', visible: false)).not_to be_visible + + page.within '.js-user-search' do + expect(page).to have_content user.name + end - expect(page).to have_button milestone.title + expect(page).to have_button milestone.title - click_button 'Labels' - page.within '.dropdown-menu-labels' do - click_link label.title - click_link label2.title - end - page.within '.js-label-select' do - expect(page).to have_content label.title + click_button _('Select label') + + wait_for_all_requests + + page.within '[data-testid="sidebar-labels"]' do + click_button label.title + click_button label2.title + click_button _('Close') + + wait_for_requests + + page.within('[data-testid="embedded-labels-list"]') do + expect(page).to have_content(label.title) + expect(page).to have_content(label2.title) + end + end + + expect(page.all('input[name="issue[label_ids][]"]', visible: false) + .map(&:value)) + .to contain_exactly(label.id.to_s, label2.id.to_s) + + click_button 'Save changes' + + page.within '.issuable-sidebar' do + page.within '.assignee' do + expect(page).to have_content user.name + end + + page.within '.milestone' do + expect(page).to have_content milestone.title + end + + page.within '.labels' do + expect(page).to have_content label.title + expect(page).to have_content label2.title + end + end end - expect(page.all('input[name="issue[label_ids][]"]', visible: false)[1].value).to match(label.id.to_s) - expect(page.all('input[name="issue[label_ids][]"]', visible: false)[2].value).to match(label2.id.to_s) + end + + context 'with the visible_label_selection_on_metadata feature flag disabled' do + let(:visible_label_selection_on_metadata) { false } - click_button 'Save changes' + it 'allows user to update issue' do + expect(find('input[name="issue[assignee_ids][]"]', visible: false).value).to match(user.id.to_s) + expect(find('input[name="issue[milestone_id]"]', visible: false).value).to match(milestone.id.to_s) + expect(find('a', text: 'Assign to me', visible: false)).not_to be_visible - page.within '.issuable-sidebar' do - page.within '.assignee' do + page.within '.js-user-search' do expect(page).to have_content user.name end - page.within '.milestone' do - expect(page).to have_content milestone.title - end + expect(page).to have_button milestone.title - page.within '.labels' do + click_button 'Labels' + page.within '.dropdown-menu-labels' do + click_link label.title + click_link label2.title + end + page.within '.js-label-select' do expect(page).to have_content label.title - expect(page).to have_content label2.title + end + expect(page.all('input[name="issue[label_ids][]"]', visible: false)[1].value).to match(label.id.to_s) + expect(page.all('input[name="issue[label_ids][]"]', visible: false)[2].value).to match(label2.id.to_s) + + click_button 'Save changes' + + page.within '.issuable-sidebar' do + page.within '.assignee' do + expect(page).to have_content user.name + end + + page.within '.milestone' do + expect(page).to have_content milestone.title + end + + page.within '.labels' do + expect(page).to have_content label.title + expect(page).to have_content label2.title + end end end end @@ -477,14 +665,69 @@ RSpec.describe 'New/edit issue', :js, feature_category: :team_planning do end describe 'inline edit' do - before do - visit project_issue_path(project, issue) + context 'within issue 1' do + before do + visit project_issue_path(project, issue) + wait_for_requests + end + + it 'opens inline edit form with shortcut' do + find('body').send_keys('e') + + expect(page).to have_selector('.detail-page-description form') + end + + describe 'when user has made no changes' do + it 'let user leave the page without warnings' do + expected_content = 'Issue created' + expect(page).to have_content(expected_content) + + find('body').send_keys('e') + + click_link 'Boards' + + expect(page).not_to have_content(expected_content) + end + end + + describe 'when user has made changes' do + it 'shows a warning and can stay on page', quarantine: 'https://gitlab.com/gitlab-org/gitlab/-/issues/397683' do + content = 'new issue content' + + find('body').send_keys('e') + fill_in 'issue-description', with: content + + click_link 'Boards' + + page.driver.browser.switch_to.alert.dismiss + + click_button 'Save changes' + wait_for_requests + + expect(page).to have_content(content) + end + end end - it 'opens inline edit form with shortcut' do - find('body').send_keys('e') + context 'within issue 2' do + before do + visit project_issue_path(project, issue2) + wait_for_requests + end - expect(page).to have_selector('.detail-page-description form') + describe 'when user has made changes' do + it 'shows a warning and can leave page', quarantine: 'https://gitlab.com/gitlab-org/gitlab/-/issues/410497' do + content = 'new issue content' + find('body').send_keys('e') + fill_in 'issue-description', with: content + + click_link 'Boards' + + page.driver.browser.switch_to.alert.accept + + expect(page).not_to have_content(content) + end + end end end @@ -499,22 +742,55 @@ RSpec.describe 'New/edit issue', :js, feature_category: :team_planning do visit new_project_issue_path(sub_group_project) end - it 'creates project label from dropdown' do - click_button 'Labels' + context 'with the visible_label_selection_on_metadata feature flag enabled', :js do + let(:visible_label_selection_on_metadata) { true } - click_link 'Create project label' + it 'creates project label from dropdown' do + find('[data-testid="labels-select-dropdown-contents"] button').click - page.within '.dropdown-new-label' do - fill_in 'new_label_name', with: 'test label' - first('.suggest-colors-dropdown a').click + wait_for_all_requests - click_button 'Create' + page.within '[data-testid="sidebar-labels"]' do + click_button _('Create project label') - wait_for_requests + wait_for_requests + end + + page.within '.js-labels-create' do + find('[data-testid="label-title-input"]').fill_in with: 'test label' + first('.suggest-colors-dropdown a').click + + click_button 'Create' + + wait_for_all_requests + end + + page.within '.js-labels-list' do + expect(page).to have_button 'test label' + end end + end + + context 'with the visible_label_selection_on_metadata feature flag disabled' do + let(:visible_label_selection_on_metadata) { false } + + it 'creates project label from dropdown' do + click_button 'Labels' + + click_link 'Create project label' - page.within '.dropdown-menu-labels' do - expect(page).to have_link 'test label' + page.within '.dropdown-new-label' do + fill_in 'new_label_name', with: 'test label' + first('.suggest-colors-dropdown a').click + + click_button 'Create' + + wait_for_requests + end + + page.within '.dropdown-menu-labels' do + expect(page).to have_link 'test label' + end end end end diff --git a/spec/features/issues/gfm_autocomplete_spec.rb b/spec/features/issues/gfm_autocomplete_spec.rb index 2bd5373b715..665c7307231 100644 --- a/spec/features/issues/gfm_autocomplete_spec.rb +++ b/spec/features/issues/gfm_autocomplete_spec.rb @@ -3,6 +3,8 @@ require 'spec_helper' RSpec.describe 'GFM autocomplete', :js, feature_category: :team_planning do + include CookieHelper + let_it_be(:user) { create(:user, name: '💃speciąl someone💃', username: 'someone.special') } let_it_be(:user2) { create(:user, name: 'Marge Simpson', username: 'msimpson') } @@ -45,6 +47,7 @@ RSpec.describe 'GFM autocomplete', :js, feature_category: :team_planning do before do sign_in(user) + set_cookie('new-actions-popover-viewed', 'true') visit project_issue_path(project, issue_to_edit) wait_for_requests diff --git a/spec/features/issues/incident_issue_spec.rb b/spec/features/issues/incident_issue_spec.rb index 41bbd79202f..145b51d207a 100644 --- a/spec/features/issues/incident_issue_spec.rb +++ b/spec/features/issues/incident_issue_spec.rb @@ -51,8 +51,8 @@ RSpec.describe 'Incident Detail', :js, feature_category: :team_planning do aggregate_failures 'when on summary tab (default tab)' do hidden_items = find_all('.js-issue-widgets') - # Linked Issues/MRs and comment box and emoji block - expect(hidden_items.count).to eq(3) + # Description footer + Linked Issues/MRs + comment box + emoji block + expect(hidden_items.count).to eq(4) expect(hidden_items).to all(be_visible) edit_button = find_all('[aria-label="Edit title and description"]') diff --git a/spec/features/issues/issue_detail_spec.rb b/spec/features/issues/issue_detail_spec.rb index 20a69c61871..29a61d584ee 100644 --- a/spec/features/issues/issue_detail_spec.rb +++ b/spec/features/issues/issue_detail_spec.rb @@ -48,6 +48,30 @@ RSpec.describe 'Issue Detail', :js, feature_category: :team_planning do end end + context 'when issue description has task list items' do + before do + description = '- [ ] I am a task + +| Table | +|-------| +|
  • [ ] I am inside a table
    • |' + issue.update!(description: description) + + sign_in(user) + visit project_issue_path(project, issue) + end + + it 'shows task actions ellipsis button when hovering over the task list item, but not within a table', :aggregate_failures do + find('li', text: 'I am a task').hover + + expect(page).to have_button 'Task actions' + + find('li', text: 'I am inside a table').hover + + expect(page).not_to have_button 'Task actions' + end + end + context 'when issue description has xss snippet' do before do issue.update!(description: '![xss" onload=alert(1);//](a)') @@ -74,6 +98,7 @@ RSpec.describe 'Issue Detail', :js, feature_category: :team_planning do project.add_developer(user_to_be_deleted) sign_in(user_to_be_deleted) + stub_feature_flags(moved_mr_sidebar: false) visit project_issue_path(project, issue) wait_for_requests @@ -105,7 +130,7 @@ RSpec.describe 'Issue Detail', :js, feature_category: :team_planning do describe 'when an issue `issue_type` is edited' do before do sign_in(user) - + set_cookie('new-actions-popover-viewed', 'true') visit project_issue_path(project, issue) wait_for_requests end @@ -139,7 +164,7 @@ RSpec.describe 'Issue Detail', :js, feature_category: :team_planning do describe 'when an incident `issue_type` is edited' do before do sign_in(user) - + set_cookie('new-actions-popover-viewed', 'true') visit project_issue_path(project, incident) wait_for_requests end diff --git a/spec/features/issues/issue_sidebar_spec.rb b/spec/features/issues/issue_sidebar_spec.rb index 686074f7412..ee71181fba2 100644 --- a/spec/features/issues/issue_sidebar_spec.rb +++ b/spec/features/issues/issue_sidebar_spec.rb @@ -4,7 +4,8 @@ require 'spec_helper' RSpec.describe 'Issue Sidebar', feature_category: :team_planning do include MobileHelpers - include Spec::Support::Helpers::Features::InviteMembersModalHelper + include Features::InviteMembersModalHelpers + include CookieHelper let_it_be(:group) { create(:group, :nested) } let_it_be(:project) { create(:project, :public, namespace: group) } @@ -20,6 +21,7 @@ RSpec.describe 'Issue Sidebar', feature_category: :team_planning do context 'when signed in' do before do sign_in(user) + set_cookie('new-actions-popover-viewed', 'true') end context 'when concerning the assignee', :js do @@ -86,12 +88,12 @@ RSpec.describe 'Issue Sidebar', feature_category: :team_planning do end within '.js-right-sidebar' do - find('.block.assignee').click(x: 0, y: 0) + find('.block.assignee').click(x: 0, y: 0, offset: 0) find('.block.assignee .edit-link').click end - expect(page.all('.dropdown-menu-user li').length).to eq(1) - expect(find('.dropdown-input-field').value).to eq(user2.name) + expect(page.all('.dropdown-menu-user li').length).to eq(6) + expect(find('.dropdown-input-field').value).to eq('') end it 'shows label text as "Apply" when assignees are changed' do @@ -119,8 +121,6 @@ RSpec.describe 'Issue Sidebar', feature_category: :team_planning do page.within '.dropdown-menu-user' do expect(page).to have_link('Invite members') - expect(page).to have_selector('[data-track-action="click_invite_members"]') - expect(page).to have_selector('[data-track-label="edit_assignee"]') click_link 'Invite members' end @@ -207,6 +207,7 @@ RSpec.describe 'Issue Sidebar', feature_category: :team_planning do context 'as an allowed user' do before do + stub_feature_flags(moved_mr_sidebar: false) project.add_developer(user) visit_issue(project, issue) end @@ -295,6 +296,7 @@ RSpec.describe 'Issue Sidebar', feature_category: :team_planning do context 'as a guest' do before do + stub_feature_flags(moved_mr_sidebar: false) project.add_guest(user) visit_issue(project, issue) end diff --git a/spec/features/issues/move_spec.rb b/spec/features/issues/move_spec.rb index ea68f2266b3..4512e88ae72 100644 --- a/spec/features/issues/move_spec.rb +++ b/spec/features/issues/move_spec.rb @@ -97,7 +97,7 @@ RSpec.describe 'issue move to another project', feature_category: :team_planning end end - context 'service desk issue moved to a project with service desk disabled', :js do + context 'service desk issue moved to a project with service desk disabled', :saas, :js do let(:project_title) { 'service desk disabled project' } let(:warning_selector) { '.js-alert-moved-from-service-desk-warning' } let(:namespace) { create(:namespace) } @@ -106,9 +106,8 @@ RSpec.describe 'issue move to another project', feature_category: :team_planning let(:service_desk_issue) { create(:issue, project: service_desk_project, author: ::User.support_bot) } before do - allow(Gitlab).to receive(:com?).and_return(true) - allow(Gitlab::IncomingEmail).to receive(:enabled?).and_return(true) - allow(Gitlab::IncomingEmail).to receive(:supports_wildcard?).and_return(true) + allow(Gitlab::Email::IncomingEmail).to receive(:enabled?).and_return(true) + allow(Gitlab::Email::IncomingEmail).to receive(:supports_wildcard?).and_return(true) regular_project.add_reporter(user) service_desk_project.add_reporter(user) diff --git a/spec/features/issues/rss_spec.rb b/spec/features/issues/rss_spec.rb index 36dffeded50..eb45d3c8d8b 100644 --- a/spec/features/issues/rss_spec.rb +++ b/spec/features/issues/rss_spec.rb @@ -23,24 +23,20 @@ RSpec.describe 'Project Issues RSS', :js, feature_category: :team_planning do before do sign_in(user) visit path + click_button 'Actions' end - it "shows the RSS button with current_user's feed token" do - expect(page).to have_link 'Subscribe to RSS feed', href: /feed_token=#{user.feed_token}/ - end - + it_behaves_like "it has an RSS link with current_user's feed token" it_behaves_like "an autodiscoverable RSS feed with current_user's feed token" end context 'when signed out' do before do visit path + click_button 'Actions' end - it "shows the RSS button without a feed token" do - expect(page).not_to have_link 'Subscribe to RSS feed', href: /feed_token/ - end - + it_behaves_like "it has an RSS link without a feed token" it_behaves_like "an autodiscoverable RSS feed without a feed token" end diff --git a/spec/features/issues/service_desk_spec.rb b/spec/features/issues/service_desk_spec.rb index 922ab95538b..0cadeb62fa2 100644 --- a/spec/features/issues/service_desk_spec.rb +++ b/spec/features/issues/service_desk_spec.rb @@ -10,8 +10,8 @@ RSpec.describe 'Service Desk Issue Tracker', :js, feature_category: :team_planni before do # The following two conditions equate to Gitlab::ServiceDesk.supported == true - allow(Gitlab::IncomingEmail).to receive(:enabled?).and_return(true) - allow(Gitlab::IncomingEmail).to receive(:supports_wildcard?).and_return(true) + allow(Gitlab::Email::IncomingEmail).to receive(:enabled?).and_return(true) + allow(Gitlab::Email::IncomingEmail).to receive(:supports_wildcard?).and_return(true) project.add_maintainer(user) sign_in(user) diff --git a/spec/features/issues/user_bulk_edits_issues_labels_spec.rb b/spec/features/issues/user_bulk_edits_issues_labels_spec.rb index 1fc6609d1f5..a01ae9ae0c2 100644 --- a/spec/features/issues/user_bulk_edits_issues_labels_spec.rb +++ b/spec/features/issues/user_bulk_edits_issues_labels_spec.rb @@ -406,7 +406,7 @@ RSpec.describe 'Issues > Labels bulk assignment', feature_category: :team_planni context 'cannot bulk assign labels' do it do - expect(page).not_to have_button 'Edit issues' + expect(page).not_to have_button 'Bulk edit' expect(page).not_to have_unchecked_field 'Select all' expect(page).not_to have_unchecked_field issue1.title end @@ -462,7 +462,7 @@ RSpec.describe 'Issues > Labels bulk assignment', feature_category: :team_planni def enable_bulk_update visit project_issues_path(project) wait_for_requests - click_button 'Edit issues' + click_button 'Bulk edit' end def disable_bulk_update diff --git a/spec/features/issues/user_bulk_edits_issues_spec.rb b/spec/features/issues/user_bulk_edits_issues_spec.rb index 5696bde4069..3e119d86c05 100644 --- a/spec/features/issues/user_bulk_edits_issues_spec.rb +++ b/spec/features/issues/user_bulk_edits_issues_spec.rb @@ -16,7 +16,7 @@ RSpec.describe 'Multiple issue updating from issues#index', :js, feature_categor it 'sets to closed', :js do visit project_issues_path(project) - click_button 'Edit issues' + click_button 'Bulk edit' check 'Select all' click_button 'Select status' click_button 'Closed' @@ -29,7 +29,7 @@ RSpec.describe 'Multiple issue updating from issues#index', :js, feature_categor create_closed visit project_issues_path(project, state: 'closed') - click_button 'Edit issues' + click_button 'Bulk edit' check 'Select all' click_button 'Select status' click_button 'Open' @@ -43,7 +43,7 @@ RSpec.describe 'Multiple issue updating from issues#index', :js, feature_categor it 'updates to current user' do visit project_issues_path(project) - click_button 'Edit issues' + click_button 'Bulk edit' check 'Select all' click_update_assignee_button click_button user.username @@ -61,7 +61,7 @@ RSpec.describe 'Multiple issue updating from issues#index', :js, feature_categor expect(find('.issue:first-of-type')).to have_link "Assigned to #{user.name}" - click_button 'Edit issues' + click_button 'Bulk edit' check 'Select all' click_update_assignee_button click_button 'Unassigned' @@ -77,7 +77,7 @@ RSpec.describe 'Multiple issue updating from issues#index', :js, feature_categor it 'updates milestone' do visit project_issues_path(project) - click_button 'Edit issues' + click_button 'Bulk edit' check 'Select all' click_button 'Select milestone' click_button milestone.title @@ -94,7 +94,7 @@ RSpec.describe 'Multiple issue updating from issues#index', :js, feature_categor expect(find('.issue:first-of-type')).to have_text milestone.title - click_button 'Edit issues' + click_button 'Bulk edit' check 'Select all' click_button 'Select milestone' click_button 'No milestone' @@ -110,7 +110,7 @@ RSpec.describe 'Multiple issue updating from issues#index', :js, feature_categor it 'after selecting all issues, unchecking one issue only unselects that one issue' do visit project_issues_path(project) - click_button 'Edit issues' + click_button 'Bulk edit' check 'Select all' uncheck issue.title diff --git a/spec/features/issues/user_comments_on_issue_spec.rb b/spec/features/issues/user_comments_on_issue_spec.rb index 59e1413fc97..3ace560fb40 100644 --- a/spec/features/issues/user_comments_on_issue_spec.rb +++ b/spec/features/issues/user_comments_on_issue_spec.rb @@ -3,7 +3,7 @@ require "spec_helper" RSpec.describe "User comments on issue", :js, feature_category: :team_planning do - include Spec::Support::Helpers::Features::NotesHelpers + include Features::NotesHelpers let_it_be(:project) { create(:project, :public) } let_it_be(:issue) { create(:issue, project: project) } @@ -32,6 +32,8 @@ RSpec.describe "User comments on issue", :js, feature_category: :team_planning d end end + it_behaves_like 'edits content using the content editor' + it "adds comment with code block" do code_block_content = "Command [1]: /usr/local/bin/git , see [text](doc/text)" comment = "```\n#{code_block_content}\n```" diff --git a/spec/features/issues/user_creates_branch_and_merge_request_spec.rb b/spec/features/issues/user_creates_branch_and_merge_request_spec.rb index bbc14368d82..6d9eb3a7191 100644 --- a/spec/features/issues/user_creates_branch_and_merge_request_spec.rb +++ b/spec/features/issues/user_creates_branch_and_merge_request_spec.rb @@ -73,8 +73,8 @@ RSpec.describe 'User creates branch and merge request on issue page', :js, featu expect(page).to have_content('New merge request') expect(page).to have_content("From #{issue.to_branch_name} into #{project.default_branch}") - expect(page).to have_content("Closes ##{issue.iid}") expect(page).to have_field("Title", with: "Draft: Resolve \"Cherry-Coloured Funk\"") + expect(page).to have_field("Description", with: "Closes ##{issue.iid}") expect(page).to have_current_path(project_new_merge_request_path(project, merge_request: { source_branch: issue.to_branch_name, target_branch: project.default_branch, issue_iid: issue.iid })) end end @@ -98,8 +98,8 @@ RSpec.describe 'User creates branch and merge request on issue page', :js, featu expect(page).to have_content('New merge request') expect(page).to have_content("From #{branch_name} into #{project.default_branch}") - expect(page).to have_content("Closes ##{issue.iid}") expect(page).to have_field("Title", with: "Draft: Resolve \"Cherry-Coloured Funk\"") + expect(page).to have_field("Description", with: "Closes ##{issue.iid}") expect(page).to have_current_path(project_new_merge_request_path(project, merge_request: { source_branch: branch_name, target_branch: project.default_branch, issue_iid: issue.iid })) end end @@ -113,6 +113,26 @@ RSpec.describe 'User creates branch and merge request on issue page', :js, featu expect(page).to have_current_path project_tree_path(project, branch_name), ignore_query: true end end + + context 'when branch name is invalid' do + shared_examples 'has error message' do |dropdown| + it 'has error message' do + select_dropdown_option(dropdown, 'custom-branch-name w~th ^bad chars?') + + wait_for_requests + + expect(page).to have_text("Can't contain spaces, ~, ^, ?") + end + end + + context 'when creating a merge request', :sidekiq_might_not_need_inline do + it_behaves_like 'has error message', 'create-mr' + end + + context 'when creating a branch', :sidekiq_might_not_need_inline do + it_behaves_like 'has error message', 'create-branch' + end + end end context "when there is a referenced merge request" do diff --git a/spec/features/issues/user_creates_issue_spec.rb b/spec/features/issues/user_creates_issue_spec.rb index c5d0791dc57..d4148717f0a 100644 --- a/spec/features/issues/user_creates_issue_spec.rb +++ b/spec/features/issues/user_creates_issue_spec.rb @@ -8,16 +8,20 @@ RSpec.describe "User creates issue", feature_category: :team_planning do let_it_be(:project) { create(:project_empty_repo, :public) } let_it_be(:user) { create(:user) } + let(:visible_label_selection_on_metadata) { false } + context "when unauthenticated" do before do sign_out(:user) end - it "redirects to signin then back to new issue after signin", :js do + it "redirects to signin then back to new issue after signin", :js, quarantine: 'https://gitlab.com/gitlab-org/quality/engineering-productivity/master-broken-incidents/-/issues/1486' do create(:issue, project: project) visit project_issues_path(project) + wait_for_all_requests + page.within ".nav-controls" do click_link "New issue" end @@ -32,6 +36,7 @@ RSpec.describe "User creates issue", feature_category: :team_planning do context "when signed in as guest", :js do before do + stub_feature_flags(visible_label_selection_on_metadata: visible_label_selection_on_metadata) project.add_guest(user) sign_in(user) @@ -61,18 +66,18 @@ RSpec.describe "User creates issue", feature_category: :team_planning do page.within(form) do click_button("Preview") - preview = find(".js-md-preview") # this element is findable only when the "Preview" link is clicked. + preview = find(".js-vue-md-preview") # this element is findable only when the "Preview" link is clicked. expect(preview).to have_content("Nothing to preview.") - click_button("Write") + click_button("Continue editing") fill_in("Description", with: "Bug fixed :smile:") click_button("Preview") expect(preview).to have_css("gl-emoji") expect(textarea).not_to be_visible - click_button("Write") + click_button("Continue editing") fill_in("Description", with: "/confidential") click_button("Preview") @@ -90,18 +95,50 @@ RSpec.describe "User creates issue", feature_category: :team_planning do end end - it "creates issue" do - issue_title = "500 error on profile" + context 'with the visible_label_selection_on_metadata feature flag enabled' do + let(:visible_label_selection_on_metadata) { true } + + it "creates issue" do + issue_title = "500 error on profile" + + fill_in("Title", with: issue_title) + + click_button _('Select label') + + wait_for_all_requests + + page.within '[data-testid="sidebar-labels"]' do + click_button label_titles.first + click_button _('Close') + + wait_for_requests + end + + click_button("Create issue") + + expect(page).to have_content(issue_title) + .and have_content(user.name) + .and have_content(project.name) + .and have_content(label_titles.first) + end + end + + context 'with the visible_label_selection_on_metadata feature flag disabled' do + let(:visible_label_selection_on_metadata) { false } + + it "creates issue" do + issue_title = "500 error on profile" - fill_in("Title", with: issue_title) - click_button("Label") - click_link(label_titles.first) - click_button("Create issue") + fill_in("Title", with: issue_title) + click_button("Label") + click_link(label_titles.first) + click_button("Create issue") - expect(page).to have_content(issue_title) - .and have_content(user.name) - .and have_content(project.name) - .and have_content(label_titles.first) + expect(page).to have_content(issue_title) + .and have_content(user.name) + .and have_content(project.name) + .and have_content(label_titles.first) + end end end @@ -127,6 +164,8 @@ RSpec.describe "User creates issue", feature_category: :team_planning do end end + it_behaves_like 'edits content using the content editor' + context 'dropzone upload file', :js do before do visit new_project_issue_path(project) @@ -184,7 +223,7 @@ RSpec.describe "User creates issue", feature_category: :team_planning do end it 'pre-fills the issue type dropdown with issue type' do - expect(find('.js-issuable-type-filter-dropdown-wrap .dropdown-toggle-text')).to have_content('Issue') + expect(find('.js-issuable-type-filter-dropdown-wrap .gl-button-text')).to have_content('Issue') end it 'does not hide the milestone select' do @@ -200,7 +239,7 @@ RSpec.describe "User creates issue", feature_category: :team_planning do end it 'does not pre-fill the issue type dropdown with incident type' do - expect(find('.js-issuable-type-filter-dropdown-wrap .dropdown-toggle-text')).not_to have_content('Incident') + expect(find('.js-issuable-type-filter-dropdown-wrap .gl-button-text')).not_to have_content('Incident') end it 'shows the milestone select' do @@ -231,6 +270,7 @@ RSpec.describe "User creates issue", feature_category: :team_planning do wait_for_requests expect(page).to have_field('Title', with: '') + expect(page).to have_field('Description', with: '') fill_in 'issue_title', with: 'bug 345' fill_in 'issue_description', with: 'bug description' @@ -238,6 +278,21 @@ RSpec.describe "User creates issue", feature_category: :team_planning do click_button 'Create issue' end end + + it 'clears local storage after cancelling a new issue creation', :js do + 2.times do + visit new_project_issue_path(project) + wait_for_requests + + expect(page).to have_field('Title', with: '') + expect(page).to have_field('Description', with: '') + + fill_in 'issue_title', with: 'bug 345' + fill_in 'issue_description', with: 'bug description' + + click_link 'Cancel' + end + end end context 'when signed in as reporter', :js do @@ -257,7 +312,7 @@ RSpec.describe "User creates issue", feature_category: :team_planning do end it 'pre-fills the issue type dropdown with incident type' do - expect(find('.js-issuable-type-filter-dropdown-wrap .dropdown-toggle-text')).to have_content('Incident') + expect(find('.js-issuable-type-filter-dropdown-wrap .gl-button-text')).to have_content('Incident') end it 'hides the epic select' do diff --git a/spec/features/issues/user_edits_issue_spec.rb b/spec/features/issues/user_edits_issue_spec.rb index bf2af918f39..bc20660d2a0 100644 --- a/spec/features/issues/user_edits_issue_spec.rb +++ b/spec/features/issues/user_edits_issue_spec.rb @@ -3,6 +3,8 @@ require "spec_helper" RSpec.describe "Issues > User edits issue", :js, feature_category: :team_planning do + include CookieHelper + let_it_be(:project) { create(:project_empty_repo, :public) } let_it_be(:project_with_milestones) { create(:project_empty_repo, :public) } let_it_be(:user) { create(:user) } @@ -18,6 +20,7 @@ RSpec.describe "Issues > User edits issue", :js, feature_category: :team_plannin project.add_developer(user) project_with_milestones.add_developer(user) sign_in(user) + set_cookie('new-actions-popover-viewed', 'true') end context "from edit page" do @@ -26,6 +29,8 @@ RSpec.describe "Issues > User edits issue", :js, feature_category: :team_plannin visit edit_project_issue_path(project, issue) end + it_behaves_like 'edits content using the content editor' + it "previews content", quarantine: 'https://gitlab.com/gitlab-org/gitlab/-/issues/391757' do form = first(".gfm-form") @@ -34,9 +39,7 @@ RSpec.describe "Issues > User edits issue", :js, feature_category: :team_plannin click_button("Preview") end - expect(form).to have_button("Write") - - click_button("Write") + click_button("Continue editing") fill_in("Description", with: "/confidential") click_button("Preview") @@ -51,7 +54,7 @@ RSpec.describe "Issues > User edits issue", :js, feature_category: :team_plannin first('.js-user-search').click click_link 'Unassigned' - click_button 'Save changes' + click_button _('Save changes') page.within('.assignee') do expect(page).to have_content 'None - assign yourself' @@ -76,7 +79,7 @@ RSpec.describe "Issues > User edits issue", :js, feature_category: :team_plannin expect(find('#issuable-due-date').value).to eq date.to_s - click_button 'Save changes' + click_button _('Save changes') page.within '.issuable-sidebar' do expect(page).to have_content date.to_s(:medium) @@ -89,9 +92,15 @@ RSpec.describe "Issues > User edits issue", :js, feature_category: :team_plannin fill_in 'issue_title', with: 'bug 345' fill_in 'issue_description', with: 'bug description' - click_button 'Save changes' + click_button _('Save changes') - expect(page).to have_content 'Someone edited the issue the same time you did' + expect(page).to have_content( + format( + _("Someone edited this %{model_name} at the same time you did. Please check out the %{link_to_model} and make sure your changes will not unintentionally remove theirs."), # rubocop:disable Layout/LineLength + model_name: _('issue'), + link_to_model: _('issue') + ) + ) end end end @@ -111,23 +120,27 @@ RSpec.describe "Issues > User edits issue", :js, feature_category: :team_plannin markdown_field_focused_selector = 'textarea:focus' click_edit_issue_description - expect(page).to have_selector(markdown_field_focused_selector) + issuable_form = find('[data-testid="issuable-form"]') - click_on _('View rich text') - click_on _('Rich text') + expect(issuable_form).to have_selector(markdown_field_focused_selector) - expect(page).not_to have_selector(content_editor_focused_selector) + page.within issuable_form do + click_button("Switch to rich text") + end + + expect(issuable_form).not_to have_selector(content_editor_focused_selector) refresh click_edit_issue_description - expect(page).to have_selector(content_editor_focused_selector) + expect(issuable_form).to have_selector(content_editor_focused_selector) - click_on _('View markdown') - click_on _('Markdown') + page.within issuable_form do + click_button("Switch to Markdown") + end - expect(page).not_to have_selector(markdown_field_focused_selector) + expect(issuable_form).not_to have_selector(markdown_field_focused_selector) end end diff --git a/spec/features/issues/user_sorts_issue_comments_spec.rb b/spec/features/issues/user_sorts_issue_comments_spec.rb index ca52e620ea7..153066343f2 100644 --- a/spec/features/issues/user_sorts_issue_comments_spec.rb +++ b/spec/features/issues/user_sorts_issue_comments_spec.rb @@ -16,9 +16,8 @@ RSpec.describe 'Comment sort direction', feature_category: :team_planning do it 'saves sort order' do # open dropdown, and select 'Newest first' page.within('.issuable-details') do - find('#discussion-preferences-dropdown').click + click_button('Sort or filter') click_button('Oldest first') - find('#discussion-preferences-dropdown').click click_button('Newest first') end diff --git a/spec/features/issues/user_toggles_subscription_spec.rb b/spec/features/issues/user_toggles_subscription_spec.rb index 904fafdf56a..00b04c10d33 100644 --- a/spec/features/issues/user_toggles_subscription_spec.rb +++ b/spec/features/issues/user_toggles_subscription_spec.rb @@ -10,6 +10,7 @@ RSpec.describe "User toggles subscription", :js, feature_category: :team_plannin context 'user is not logged in' do before do + stub_feature_flags(moved_mr_sidebar: false) visit(project_issue_path(project, issue)) end @@ -20,9 +21,9 @@ RSpec.describe "User toggles subscription", :js, feature_category: :team_plannin context 'user is logged in' do before do + stub_feature_flags(moved_mr_sidebar: false) project.add_developer(user) sign_in(user) - visit(project_issue_path(project, issue)) end @@ -52,6 +53,7 @@ RSpec.describe "User toggles subscription", :js, feature_category: :team_plannin context 'user is logged in without edit permission' do before do + stub_feature_flags(moved_mr_sidebar: false) sign_in(user2) visit(project_issue_path(project, issue)) diff --git a/spec/features/issues/user_uses_quick_actions_spec.rb b/spec/features/issues/user_uses_quick_actions_spec.rb index 963f1c56fef..e85a521e242 100644 --- a/spec/features/issues/user_uses_quick_actions_spec.rb +++ b/spec/features/issues/user_uses_quick_actions_spec.rb @@ -8,7 +8,7 @@ require 'spec_helper' # Because this kind of spec takes more time to run there is no need to add new ones # for each existing quick action unless they test something not tested by existing tests. RSpec.describe 'Issues > User uses quick actions', :js, feature_category: :team_planning do - include Spec::Support::Helpers::Features::NotesHelpers + include Features::NotesHelpers context "issuable common quick actions" do let(:new_url_opts) { {} } diff --git a/spec/features/jira_connect/branches_spec.rb b/spec/features/jira_connect/branches_spec.rb index c90c0d2dda9..25dc14a1dc9 100644 --- a/spec/features/jira_connect/branches_spec.rb +++ b/spec/features/jira_connect/branches_spec.rb @@ -75,7 +75,7 @@ RSpec.describe 'Create GitLab branches from Jira', :js, feature_category: :integ select_listbox_item(source_branch) fill_in 'Branch name', with: new_branch - click_on 'Create branch' + click_button 'Create branch' expect(page).to have_text('New branch was successfully created. You can now close this window and return to Jira.') diff --git a/spec/features/jira_oauth_provider_authorize_spec.rb b/spec/features/jira_oauth_provider_authorize_spec.rb index a542aaa7619..e873d9c219f 100644 --- a/spec/features/jira_oauth_provider_authorize_spec.rb +++ b/spec/features/jira_oauth_provider_authorize_spec.rb @@ -4,18 +4,39 @@ require 'spec_helper' RSpec.describe 'JIRA OAuth Provider', feature_category: :integrations do describe 'JIRA DVCS OAuth Authorization' do - let(:application) { create(:oauth_application, redirect_uri: oauth_jira_dvcs_callback_url, scopes: 'read_user') } + let_it_be(:application) do + create(:oauth_application, redirect_uri: oauth_jira_dvcs_callback_url, scopes: 'read_user') + end + + let(:authorize_path) do + oauth_jira_dvcs_authorize_path(client_id: application.uid, + redirect_uri: oauth_jira_dvcs_callback_url, + response_type: 'code', + state: 'my_state', + scope: 'read_user') + end before do sign_in(user) + end - visit oauth_jira_dvcs_authorize_path(client_id: application.uid, - redirect_uri: oauth_jira_dvcs_callback_url, - response_type: 'code', - state: 'my_state', - scope: 'read_user') + it_behaves_like 'Secure OAuth Authorizations' do + before do + visit authorize_path + end end - it_behaves_like 'Secure OAuth Authorizations' + context 'when the flag is disabled' do + let_it_be(:user) { create(:user) } + + before do + stub_feature_flags(jira_dvcs_end_of_life_amnesty: false) + visit authorize_path + end + + it 'presents as an endpoint that does not exist' do + expect(page).to have_gitlab_http_status(:not_found) + end + end end end diff --git a/spec/features/labels_hierarchy_spec.rb b/spec/features/labels_hierarchy_spec.rb index d6e607e80df..e8f40a1ceab 100644 --- a/spec/features/labels_hierarchy_spec.rb +++ b/spec/features/labels_hierarchy_spec.rb @@ -157,28 +157,71 @@ RSpec.describe 'Labels Hierarchy', :js, feature_category: :team_planning do end end - context 'when creating new issuable' do + context 'with the visible_label_selection_on_metadata feature flag enabled' do before do - visit new_project_issue_path(project_1) + stub_feature_flags(visible_label_selection_on_metadata: true) end - it 'is able to assign ancestor group labels' do - fill_in 'issue_title', with: 'new created issue' - fill_in 'issue_description', with: 'new issue description' + context 'when creating new issuable' do + before do + visit new_project_issue_path(project_1) + end + + it 'is able to assign ancestor group labels' do + fill_in 'issue_title', with: 'new created issue' + fill_in 'issue_description', with: 'new issue description' + + click_button _('Select label') + + wait_for_all_requests + + page.within '[data-testid="sidebar-labels"]' do + click_button grandparent_group_label.title + click_button parent_group_label.title + click_button project_label_1.title + click_button _('Close') + + wait_for_requests + end + + find('.btn-confirm').click + + expect(page.find('.issue-details h1.title')).to have_content('new created issue') + expect(page).to have_selector('span.gl-label-text', text: grandparent_group_label.title) + expect(page).to have_selector('span.gl-label-text', text: parent_group_label.title) + expect(page).to have_selector('span.gl-label-text', text: project_label_1.title) + end + end + end - find(".js-label-select").click - wait_for_requests + context 'with the visible_label_selection_on_metadata feature flag disabled' do + before do + stub_feature_flags(visible_label_selection_on_metadata: false) + end - find('a.label-item', text: grandparent_group_label.title).click - find('a.label-item', text: parent_group_label.title).click - find('a.label-item', text: project_label_1.title).click + context 'when creating new issuable' do + before do + visit new_project_issue_path(project_1) + end + + it 'is able to assign ancestor group labels' do + fill_in 'issue_title', with: 'new created issue' + fill_in 'issue_description', with: 'new issue description' + + find(".js-label-select").click + wait_for_requests - find('.btn-confirm').click + find('a.label-item', text: grandparent_group_label.title).click + find('a.label-item', text: parent_group_label.title).click + find('a.label-item', text: project_label_1.title).click - expect(page.find('.issue-details h1.title')).to have_content('new created issue') - expect(page).to have_selector('span.gl-label-text', text: grandparent_group_label.title) - expect(page).to have_selector('span.gl-label-text', text: parent_group_label.title) - expect(page).to have_selector('span.gl-label-text', text: project_label_1.title) + find('.btn-confirm').click + + expect(page.find('.issue-details h1.title')).to have_content('new created issue') + expect(page).to have_selector('span.gl-label-text', text: grandparent_group_label.title) + expect(page).to have_selector('span.gl-label-text', text: parent_group_label.title) + expect(page).to have_selector('span.gl-label-text', text: project_label_1.title) + end end end diff --git a/spec/features/markdown/markdown_spec.rb b/spec/features/markdown/markdown_spec.rb index 6e62aa892bb..a31ad5a868e 100644 --- a/spec/features/markdown/markdown_spec.rb +++ b/spec/features/markdown/markdown_spec.rb @@ -68,7 +68,7 @@ RSpec.describe 'GitLab Markdown', :aggregate_failures, feature_category: :team_p end aggregate_failures 'parses mermaid code block' do - expect(doc).to have_selector('pre[lang=mermaid] > code.js-render-mermaid') + expect(doc).to have_selector('pre[data-canonical-lang=mermaid] > code.js-render-mermaid') end aggregate_failures 'parses strikethroughs' do @@ -250,6 +250,7 @@ RSpec.describe 'GitLab Markdown', :aggregate_failures, feature_category: :team_p aggregate_failures 'all reference filters' do expect(doc).to reference_users expect(doc).to reference_issues + expect(doc).to reference_work_items expect(doc).to reference_merge_requests expect(doc).to reference_snippets expect(doc).to reference_commit_ranges @@ -345,6 +346,7 @@ RSpec.describe 'GitLab Markdown', :aggregate_failures, feature_category: :team_p aggregate_failures 'all reference filters' do expect(doc).to reference_users expect(doc).to reference_issues + expect(doc).to reference_work_items expect(doc).to reference_merge_requests expect(doc).to reference_snippets expect(doc).to reference_commit_ranges diff --git a/spec/features/markdown/metrics_spec.rb b/spec/features/markdown/metrics_spec.rb index b5e42b16f87..1b68f78e993 100644 --- a/spec/features/markdown/metrics_spec.rb +++ b/spec/features/markdown/metrics_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' -RSpec.describe 'Metrics rendering', :js, :kubeclient, :use_clean_rails_memory_store_caching, :sidekiq_inline, feature_category: :team_planning do +RSpec.describe 'Metrics rendering', :js, :kubeclient, :use_clean_rails_memory_store_caching, :sidekiq_inline, feature_category: :metrics do include PrometheusHelpers include KubernetesHelpers include GrafanaApiHelpers @@ -17,6 +17,7 @@ RSpec.describe 'Metrics rendering', :js, :kubeclient, :use_clean_rails_memory_st let(:metrics_url) { urls.metrics_project_environment_url(project, environment) } before do + stub_feature_flags(remove_monitor_metrics: false) clear_host_from_memoized_variables stub_gitlab_domain @@ -28,6 +29,20 @@ RSpec.describe 'Metrics rendering', :js, :kubeclient, :use_clean_rails_memory_st clear_host_from_memoized_variables end + shared_examples_for 'metrics dashboard unavailable' do + context 'when metrics dashboard feature is unavailable' do + before do + stub_feature_flags(remove_monitor_metrics: true) + end + + it 'shows no embedded metrics' do + visit project_issue_path(project, issue) + + expect(page).to have_no_css('div.prometheus-graph') + end + end + end + context 'internal metrics embeds' do before do import_common_metrics @@ -36,6 +51,8 @@ RSpec.describe 'Metrics rendering', :js, :kubeclient, :use_clean_rails_memory_st allow(Prometheus::ProxyService).to receive(:new).and_call_original end + include_examples 'metrics dashboard unavailable' + it 'shows embedded metrics' do visit project_issue_path(project, issue) @@ -50,6 +67,20 @@ RSpec.describe 'Metrics rendering', :js, :kubeclient, :use_clean_rails_memory_st .at_least(:once) end + context 'with remove_monitor_metrics flag enabled' do + before do + stub_feature_flags(remove_monitor_metrics: true) + end + + it 'does not show embedded metrics' do + visit project_issue_path(project, issue) + + expect(page).not_to have_css('div.prometheus-graph') + expect(page).not_to have_text('Memory Usage (Total)') + expect(page).not_to have_text('Core Usage (Total)') + end + end + context 'when dashboard params are in included the url' do let(:metrics_url) { urls.metrics_project_environment_url(project, environment, **chart_params) } @@ -120,7 +151,9 @@ RSpec.describe 'Metrics rendering', :js, :kubeclient, :use_clean_rails_memory_st allow(Grafana::ProxyService).to receive(:new).and_call_original end - it 'shows embedded metrics' do + include_examples 'metrics dashboard unavailable' + + it 'shows embedded metrics', quarantine: 'https://gitlab.com/gitlab-org/gitlab/-/issues/402973' do visit project_issue_path(project, issue) expect(page).to have_css('div.prometheus-graph') @@ -157,6 +190,8 @@ RSpec.describe 'Metrics rendering', :js, :kubeclient, :use_clean_rails_memory_st stub_any_prometheus_request_with_response end + include_examples 'metrics dashboard unavailable' + it 'shows embedded metrics' do visit project_issue_path(project, issue) @@ -186,6 +221,8 @@ RSpec.describe 'Metrics rendering', :js, :kubeclient, :use_clean_rails_memory_st let(:metrics_url) { urls.namespace_project_cluster_url(*params, **query_params) } let(:description) { "# Summary \n[](#{metrics_url})" } + include_examples 'metrics dashboard unavailable' + it 'shows embedded metrics' do visit project_issue_path(project, issue) diff --git a/spec/features/markdown/observability_spec.rb b/spec/features/markdown/observability_spec.rb index 86caf3eb1b1..ec414d4396e 100644 --- a/spec/features/markdown/observability_spec.rb +++ b/spec/features/markdown/observability_spec.rb @@ -2,82 +2,44 @@ require 'spec_helper' -RSpec.describe 'Observability rendering', :js do +RSpec.describe 'Observability rendering', :js, feature_category: :metrics do let_it_be(:group) { create(:group, :public) } let_it_be(:project) { create(:project, :repository, group: group) } let_it_be(:user) { create(:user) } - let_it_be(:observable_url) { "https://observe.gitlab.com/" } - - let_it_be(:expected) do - %(