From 7021455bd1ed7b125c55eb1b33c5a01f2bc55ee0 Mon Sep 17 00:00:00 2001 From: GitLab Bot Date: Thu, 17 Nov 2022 11:33:21 +0000 Subject: Add latest changes from gitlab-org/gitlab@15-6-stable-ee --- spec/bin/audit_event_type_spec.rb | 293 +++++ spec/components/pajamas/spinner_component_spec.rb | 4 +- .../previews/pajamas/alert_component_preview.rb | 2 +- .../previews/pajamas/avatar_component_preview.rb | 6 +- .../previews/pajamas/badge_component_preview.rb | 4 +- .../previews/pajamas/banner_component_preview.rb | 2 +- .../previews/pajamas/button_component_preview.rb | 8 +- .../previews/pajamas/progress_component_preview.rb | 4 +- .../previews/pajamas/spinner_component_preview.rb | 22 +- .../inject_enterprise_edition_module_spec.rb | 18 + .../metrics/aggregates/aggregated_metrics_spec.rb | 95 -- ...pipelines#index-get_list_project_pipelines.json | 6 + .../provider/helpers/publish_contract_helper.rb | 17 + .../merge_request/show/diffs_batch_helper.rb | 2 + .../merge_request/show/diffs_metadata_helper.rb | 4 + .../merge_request/show/discussions_helper.rb | 4 + .../pipeline/index/create_a_new_pipeline_helper.rb | 4 + .../index/get_list_project_pipelines_helper.rb | 4 + .../pipeline/show/delete_pipeline_helper.rb | 5 + .../show/get_pipeline_header_data_helper.rb | 6 + .../update_pipeline_schedule_helper.rb | 4 + spec/contracts/publish-contracts.sh | 23 + spec/controllers/admin/groups_controller_spec.rb | 8 + spec/controllers/admin/hooks_controller_spec.rb | 24 +- .../admin/integrations_controller_spec.rb | 2 +- .../controllers/admin/spam_logs_controller_spec.rb | 35 +- spec/controllers/admin/topics_controller_spec.rb | 2 +- spec/controllers/admin/users_controller_spec.rb | 313 +++-- spec/controllers/concerns/issuable_actions_spec.rb | 13 +- .../concerns/preferred_language_switcher_spec.rb | 51 + spec/controllers/concerns/renders_commits_spec.rb | 4 +- spec/controllers/concerns/send_file_upload_spec.rb | 29 + spec/controllers/confirmations_controller_spec.rb | 31 +- spec/controllers/dashboard_controller_spec.rb | 14 - spec/controllers/explore/groups_controller_spec.rb | 46 +- .../explore/projects_controller_spec.rb | 25 +- spec/controllers/graphql_controller_spec.rb | 114 +- .../controllers/groups/children_controller_spec.rb | 2 +- .../groups/group_members_controller_spec.rb | 35 + .../registry/repositories_controller_spec.rb | 2 +- .../controllers/groups/releases_controller_spec.rb | 4 +- spec/controllers/groups/runners_controller_spec.rb | 12 +- .../groups/settings/repository_controller_spec.rb | 117 +- spec/controllers/groups_controller_spec.rb | 28 +- .../oauth/authorizations_controller_spec.rb | 69 ++ .../omniauth_callbacks_controller_spec.rb | 2 +- spec/controllers/passwords_controller_spec.rb | 16 + .../personal_access_tokens_controller_spec.rb | 95 +- .../alerting/notifications_controller_spec.rb | 20 +- .../projects/artifacts_controller_spec.rb | 70 +- .../projects/environments_controller_spec.rb | 8 +- spec/controllers/projects/hooks_controller_spec.rb | 59 +- .../controllers/projects/issues_controller_spec.rb | 114 +- spec/controllers/projects/jobs_controller_spec.rb | 90 +- .../projects/learn_gitlab_controller_spec.rb | 11 +- .../merge_requests/diffs_controller_spec.rb | 12 +- .../projects/merge_requests_controller_spec.rb | 32 +- .../projects/pipelines_controller_spec.rb | 65 +- .../projects/product_analytics_controller_spec.rb | 95 -- .../projects/prometheus/alerts_controller_spec.rb | 11 +- .../registry/repositories_controller_spec.rb | 25 +- .../projects/releases_controller_spec.rb | 2 +- .../projects/runners_controller_spec.rb | 2 +- .../settings/integrations_controller_spec.rb | 17 + .../settings/repository_controller_spec.rb | 172 ++- .../projects/starrers_controller_spec.rb | 6 + spec/controllers/projects_controller_spec.rb | 1 + spec/controllers/registrations_controller_spec.rb | 73 +- spec/controllers/search_controller_spec.rb | 9 +- spec/controllers/sessions_controller_spec.rb | 2 + spec/db/schema_spec.rb | 9 +- spec/experiments/application_experiment_spec.rb | 66 - ...ation_for_namespace_creation_experiment_spec.rb | 28 - ...ity_reports_mr_widget_prompt_experiment_spec.rb | 6 - spec/factories/ci/builds.rb | 25 +- spec/factories/ci/job_artifacts.rb | 2 + spec/factories/ci/pipeline_metadata.rb | 2 +- spec/factories/ci/pipelines.rb | 10 +- spec/factories/ci/processable.rb | 2 +- .../ci/reports/codequality_degradations.rb | 9 +- spec/factories/ci/reports/sbom/components.rb | 14 + spec/factories/ci/reports/sbom/reports.rb | 6 + spec/factories/ci/secure_files.rb | 9 + spec/factories/ci/stages.rb | 2 +- spec/factories/container_repositories.rb | 4 + spec/factories/dependency_proxy.rb | 9 +- spec/factories/experiment_subjects.rb | 9 - spec/factories/experiment_users.rb | 10 - spec/factories/experiments.rb | 7 - spec/factories/integrations.rb | 13 + spec/factories/member_roles.rb | 2 + spec/factories/merge_request_reviewers.rb | 9 + .../factories/packages/rpm/rpm_repository_files.rb | 9 +- spec/factories/project_hooks.rb | 4 + spec/factories/projects.rb | 13 + .../projects/import_export/export_relation.rb | 11 - .../projects/import_export/relation_export.rb | 27 + .../import_export/relation_export_upload.rb | 8 + spec/factories/projects/wiki_repositories.rb | 7 + spec/factories/protected_branches.rb | 37 +- spec/factories/user_statuses.rb | 4 + spec/factories/users.rb | 4 + spec/factories/users/ghost_user_migrations.rb | 1 + spec/factories/users/namespace_commit_emails.rb | 9 + spec/features/admin/admin_dev_ops_reports_spec.rb | 4 +- spec/features/admin/admin_hook_logs_spec.rb | 7 +- spec/features/admin/admin_hooks_spec.rb | 2 +- spec/features/admin/admin_mode/workers_spec.rb | 54 +- spec/features/admin/admin_runners_spec.rb | 15 +- spec/features/admin/admin_settings_spec.rb | 18 + .../admin/admin_users_impersonation_tokens_spec.rb | 31 +- spec/features/admin/users/user_spec.rb | 79 +- spec/features/admin_variables_spec.rb | 18 +- spec/features/boards/board_filters_spec.rb | 5 +- spec/features/boards/boards_spec.rb | 35 +- spec/features/boards/issue_ordering_spec.rb | 1 + spec/features/boards/sidebar_labels_spec.rb | 1 + spec/features/boards/sidebar_spec.rb | 1 + .../boards/user_adds_lists_to_board_spec.rb | 6 +- spec/features/boards/user_visits_board_spec.rb | 5 +- spec/features/broadcast_messages_spec.rb | 3 +- spec/features/commits_spec.rb | 4 +- spec/features/cycle_analytics_spec.rb | 8 +- .../dashboard/datetime_on_tooltips_spec.rb | 4 +- spec/features/dashboard/projects_spec.rb | 6 +- spec/features/global_search_spec.rb | 15 +- spec/features/graphql_known_operations_spec.rb | 2 +- spec/features/group_variables_spec.rb | 18 +- spec/features/groups/activity_spec.rb | 2 +- spec/features/groups/board_sidebar_spec.rb | 3 +- spec/features/groups/empty_states_spec.rb | 2 +- spec/features/groups/group_runners_spec.rb | 46 +- spec/features/groups/group_settings_spec.rb | 27 +- spec/features/groups/issues_spec.rb | 12 +- spec/features/groups/milestone_spec.rb | 2 +- spec/features/groups/milestones_sorting_spec.rb | 2 +- spec/features/groups/settings/repository_spec.rb | 23 +- spec/features/help_pages_spec.rb | 2 +- spec/features/ide/user_opens_merge_request_spec.rb | 2 +- spec/features/ide_spec.rb | 95 +- .../features/incidents/user_views_incident_spec.rb | 60 +- .../internal_references_spec.rb | 18 +- spec/features/issues/confidential_notes_spec.rb | 13 + .../filtered_search/dropdown_assignee_spec.rb | 4 + .../issues/filtered_search/dropdown_author_spec.rb | 1 + .../issues/filtered_search/dropdown_hint_spec.rb | 1 + .../issues/filtered_search/filter_issues_spec.rb | 1 + .../issues/filtered_search/visual_tokens_spec.rb | 1 + spec/features/issues/form_spec.rb | 23 +- .../issues/user_bulk_edits_issues_labels_spec.rb | 2 +- .../features/issues/user_bulk_edits_issues_spec.rb | 4 +- .../features/issues/user_comments_on_issue_spec.rb | 6 +- spec/features/issues/user_creates_issue_spec.rb | 6 +- spec/features/issues/user_edits_issue_spec.rb | 33 +- .../issues/user_interacts_with_awards_spec.rb | 7 +- spec/features/issues/user_sees_empty_state_spec.rb | 4 +- spec/features/issues/user_sorts_issues_spec.rb | 2 +- spec/features/jira_connect/subscriptions_spec.rb | 2 +- spec/features/markdown/sandboxed_mermaid_spec.rb | 60 +- .../user_accepts_merge_request_spec.rb | 2 + .../user_edits_assignees_sidebar_spec.rb | 2 +- .../user_merges_when_pipeline_succeeds_spec.rb | 4 +- .../user_scrolls_to_note_on_load_spec.rb | 2 +- .../user_sees_deployment_widget_spec.rb | 19 +- spec/features/merge_request/user_sees_diff_spec.rb | 14 + .../user_sees_discussions_navigation_spec.rb | 222 ++++ .../merge_request/user_sees_merge_widget_spec.rb | 141 ++- .../merge_requests/user_mass_updates_spec.rb | 2 +- spec/features/monitor_sidebar_link_spec.rb | 5 - spec/features/nav/top_nav_tooltip_spec.rb | 3 +- spec/features/one_trust_spec.rb | 2 +- spec/features/profile_spec.rb | 41 +- spec/features/profiles/password_spec.rb | 44 + .../profiles/personal_access_tokens_spec.rb | 39 +- spec/features/profiles/two_factor_auths_spec.rb | 2 +- spec/features/project_variables_spec.rb | 63 +- .../projects/branches/user_views_branches_spec.rb | 2 +- spec/features/projects/branches_spec.rb | 42 +- spec/features/projects/container_registry_spec.rb | 5 +- .../projects/environments/environment_spec.rb | 28 +- .../projects/environments/environments_spec.rb | 5 + spec/features/projects/fork_spec.rb | 4 +- .../projects/import_export/import_file_spec.rb | 2 - .../user_activates_issue_tracker_spec.rb | 2 +- ...ues_with_external_authorization_enabled_spec.rb | 10 +- spec/features/projects/jobs/permissions_spec.rb | 44 + .../projects/jobs/user_browses_jobs_spec.rb | 6 +- spec/features/projects/jobs_spec.rb | 4 +- .../projects/members/manage_members_spec.rb | 2 +- spec/features/projects/network_graph_spec.rb | 138 ++- spec/features/projects/pipeline_schedules_spec.rb | 10 +- .../projects/pipelines/legacy_pipeline_spec.rb | 7 +- .../projects/pipelines/legacy_pipelines_spec.rb | 1 - spec/features/projects/pipelines/pipeline_spec.rb | 52 +- spec/features/projects/pipelines/pipelines_spec.rb | 5 +- .../projects/product_analytics/events_spec.rb | 30 - .../projects/product_analytics/graphs_spec.rb | 25 - .../projects/product_analytics/setup_spec.rb | 19 - .../projects/product_analytics/test_spec.rb | 27 - .../releases/user_views_edit_release_spec.rb | 2 +- .../projects/releases/user_views_releases_spec.rb | 2 +- .../settings/branch_names_settings_spec.rb | 48 + .../projects/settings/repository_settings_spec.rb | 1 - .../settings/user_changes_default_branch_spec.rb | 4 +- .../user_sees_revoke_deploy_token_modal_spec.rb | 1 - .../projects/settings/webhooks_settings_spec.rb | 51 +- .../user_changes_project_visibility_spec.rb | 3 + .../features/search/user_searches_for_code_spec.rb | 323 ++--- .../search/user_searches_for_comments_spec.rb | 61 +- .../search/user_searches_for_commits_spec.rb | 74 +- .../search/user_searches_for_issues_spec.rb | 177 +-- .../user_searches_for_merge_requests_spec.rb | 84 +- .../search/user_searches_for_milestones_spec.rb | 67 +- .../search/user_searches_for_projects_spec.rb | 5 +- .../search/user_searches_for_users_spec.rb | 118 +- .../search/user_searches_for_wiki_pages_spec.rb | 70 +- .../search/user_uses_header_search_field_spec.rb | 6 +- spec/features/snippets/search_snippets_spec.rb | 6 +- spec/features/user_sees_marketing_header_spec.rb | 52 +- spec/features/users/active_sessions_spec.rb | 4 +- .../features/work_items/work_item_children_spec.rb | 30 +- spec/finders/autocomplete/users_finder_spec.rb | 49 +- spec/finders/branches_finder_spec.rb | 2 +- .../clusters/agent_authorizations_finder_spec.rb | 16 - spec/finders/clusters/agent_tokens_finder_spec.rb | 48 + .../timeline_event_tags_finder_spec.rb | 58 + spec/finders/projects_finder_spec.rb | 46 +- spec/finders/users_star_projects_finder_spec.rb | 10 + .../schemas/entities/codequality_degradation.json | 5 +- .../entities/codequality_reports_comparer.json | 16 +- .../api/schemas/entities/protected_ref_access.json | 25 + .../schemas/graphql/packages/package_details.json | 12 +- spec/fixtures/api/schemas/ml/run.json | 46 +- .../api/schemas/pipeline_schedule_variable.json | 17 +- spec/fixtures/api/schemas/project_mirror.json | 48 + spec/fixtures/api/schemas/protected_branch.json | 33 + spec/fixtures/api/schemas/protected_branches.json | 6 + spec/fixtures/api/schemas/protected_tag.json | 19 + spec/fixtures/api/schemas/protected_tags.json | 6 + .../api/schemas/public_api/v4/metadata.json | 34 +- spec/fixtures/gitlab/import_export/project.tar.gz | Bin 0 -> 1113 bytes spec/fixtures/gitlab/import_export/uploads.tar.gz | Bin 0 -> 1843 bytes .../sample_metric.yml | 2 +- .../sample_metric_with_ee.yml | 2 +- .../sample_metric_with_name_suggestions.yml | 2 +- .../lib/gitlab/import_export/complex/project.json | 2 +- .../complex/tree/project/ci_pipelines.ndjson | 2 +- spec/fixtures/lib/sbom/package-url-test-cases.json | 502 ++++++++ .../markdown/markdown_golden_master_examples.yml | 14 +- spec/fixtures/packages/rpm/payload.json | 18 +- ...06c4fd0696dcad506f527329b818eb0f5db3-repomd.xml | 30 + spec/fixtures/packages/rpm/repodata/repomd.xml | 27 - spec/frontend/__helpers__/raw_transformer.js | 6 + .../__snapshots__/expires_at_field_spec.js.snap | 1 + .../components/new_access_token_app_spec.js | 1 - .../components/signup_form_spec.js | 18 +- .../admin/signup_restrictions/mock_data.js | 6 + .../admin/users/components/actions/actions_spec.js | 57 +- .../actions/delete_with_contributions_spec.js | 107 ++ .../associations_list_item_spec.js.snap | 3 + .../__snapshots__/associations_list_spec.js.snap | 34 + .../associations/associations_list_item_spec.js | 25 + .../associations/associations_list_spec.js | 78 ++ .../components/modals/delete_user_modal_spec.js | 22 + .../admin/users/components/user_actions_spec.js | 7 +- spec/frontend/admin/users/mock_data.js | 14 + .../analytics/shared/components/daterange_spec.js | 2 +- spec/frontend/api/groups_api_spec.js | 27 +- spec/frontend/api/user_api_spec.js | 17 +- .../artifacts/components/artifact_row_spec.js | 67 + .../components/artifacts_table_row_details_spec.js | 122 ++ .../components/job_artifacts_table_spec.js | 341 ++++++ .../artifacts/graphql/cache_update_spec.js | 67 + .../markdown/render_sandboxed_mermaid_spec.js | 145 ++- spec/frontend/blob/blob_blame_link_spec.js | 12 +- .../__snapshots__/blob_edit_content_spec.js.snap | 18 - .../blob/components/blob_edit_content_spec.js | 105 -- spec/frontend/blob/utils_spec.js | 62 +- spec/frontend/blob_edit/edit_blob_spec.js | 48 + spec/frontend/boards/board_card_inner_spec.js | 241 ++-- spec/frontend/boards/board_list_helper.js | 2 + spec/frontend/boards/board_list_spec.js | 6 + .../boards/components/board_add_new_column_spec.js | 2 +- spec/frontend/boards/components/board_app_spec.js | 1 + .../components/board_card_move_to_position_spec.js | 1 + spec/frontend/boards/components/board_card_spec.js | 2 +- .../boards/components/board_content_spec.js | 84 +- .../components/board_filtered_search_spec.js | 44 +- .../boards/components/board_list_header_spec.js | 2 +- .../components/board_settings_sidebar_spec.js | 1 + .../boards/components/board_top_bar_spec.js | 11 +- spec/frontend/boards/mock_data.js | 81 +- spec/frontend/boards/stores/actions_spec.js | 18 +- .../delete_merged_branches_spec.js.snap | 139 +++ .../components/delete_merged_branches_spec.js | 143 +++ spec/frontend/branches/mock_data.js | 7 + .../delete_pipeline_schedule_modal_spec.js | 38 + .../components/pipeline_schedules_form_spec.js | 25 + .../components/pipeline_schedules_spec.js | 280 +++++ .../table/cells/pipeline_schedule_actions_spec.js | 64 + .../cells/pipeline_schedule_last_pipeline_spec.js | 42 + .../table/cells/pipeline_schedule_next_run_spec.js | 43 + .../table/cells/pipeline_schedule_owner_spec.js | 40 + .../table/cells/pipeline_schedule_target_spec.js | 41 + .../table/pipeline_schedules_table_spec.js | 39 + .../components/take_ownership_modal_legacy_spec.js | 44 + .../components/take_ownership_modal_spec.js | 40 + spec/frontend/ci/pipeline_schedules/mock_data.js | 62 + .../admin_runner_show_app_spec.js | 266 ++++ .../runner/admin_runners/admin_runners_app_spec.js | 473 +++++++ .../runner_status_popover_spec.js.snap | 3 + .../ci/runner/components/cells/link_cell_spec.js | 72 ++ .../components/cells/runner_actions_cell_spec.js | 138 +++ .../components/cells/runner_owner_cell_spec.js | 111 ++ .../cells/runner_stacked_summary_cell_spec.js | 164 +++ .../components/cells/runner_status_cell_spec.js | 77 ++ .../components/cells/runner_summary_field_spec.js | 49 + .../registration/registration_dropdown_spec.js | 198 +++ .../registration_token_reset_dropdown_item_spec.js | 209 ++++ .../registration/registration_token_spec.js | 62 + .../runner/components/runner_assigned_item_spec.js | 68 ++ .../components/runner_bulk_delete_checkbox_spec.js | 140 +++ .../runner/components/runner_bulk_delete_spec.js | 295 +++++ .../runner/components/runner_delete_button_spec.js | 275 +++++ .../runner/components/runner_delete_modal_spec.js | 60 + .../ci/runner/components/runner_details_spec.js | 130 ++ .../runner/components/runner_edit_button_spec.js | 41 + .../components/runner_filtered_search_bar_spec.js | 188 +++ .../ci/runner/components/runner_groups_spec.js | 67 + .../ci/runner/components/runner_header_spec.js | 124 ++ .../ci/runner/components/runner_jobs_spec.js | 155 +++ .../ci/runner/components/runner_jobs_table_spec.js | 137 +++ .../components/runner_list_empty_state_spec.js | 103 ++ .../ci/runner/components/runner_list_spec.js | 231 ++++ .../components/runner_membership_toggle_spec.js | 57 + .../ci/runner/components/runner_pagination_spec.js | 115 ++ .../runner/components/runner_pause_button_spec.js | 263 ++++ .../runner/components/runner_paused_badge_spec.js | 46 + .../ci/runner/components/runner_projects_spec.js | 251 ++++ .../runner/components/runner_status_badge_spec.js | 133 ++ .../components/runner_status_popover_spec.js | 36 + .../ci/runner/components/runner_tag_spec.js | 79 ++ .../ci/runner/components/runner_tags_spec.js | 54 + .../ci/runner/components/runner_type_badge_spec.js | 66 + .../ci/runner/components/runner_type_tabs_spec.js | 214 ++++ .../runner/components/runner_update_form_spec.js | 288 +++++ .../components/search_tokens/tag_token_spec.js | 208 ++++ .../ci/runner/components/stat/runner_count_spec.js | 148 +++ .../components/stat/runner_single_stat_spec.js | 61 + .../ci/runner/components/stat/runner_stats_spec.js | 81 ++ .../frontend/ci/runner/graphql/local_state_spec.js | 167 +++ .../group_runner_show_app_spec.js | 215 ++++ .../runner/group_runners/group_runners_app_spec.js | 492 ++++++++ .../save_alert_to_local_storage_spec.js | 24 + .../show_alert_from_local_storage_spec.js | 40 + spec/frontend/ci/runner/mock_data.js | 322 +++++ .../ci/runner/runner_edit/runner_edit_app_spec.js | 114 ++ .../frontend/ci/runner/runner_search_utils_spec.js | 138 +++ .../ci/runner/runner_update_form_utils_spec.js | 96 ++ spec/frontend/ci/runner/sentry_utils_spec.js | 39 + spec/frontend/ci/runner/utils_spec.js | 85 ++ .../components/ci_admin_variables_spec.js | 175 +-- .../components/ci_group_variables_spec.js | 181 +-- .../components/ci_project_variables_spec.js | 202 +-- .../components/ci_variable_modal_spec.js | 90 +- .../components/ci_variable_popover_spec.js | 48 - .../components/ci_variable_settings_spec.js | 2 + .../components/ci_variable_shared_spec.js | 428 +++++++ .../legacy_ci_environments_dropdown_spec.js | 119 -- .../components/legacy_ci_variable_modal_spec.js | 323 ----- .../components/legacy_ci_variable_settings_spec.js | 38 - .../components/legacy_ci_variable_table_spec.js | 86 -- spec/frontend/ci_variable_list/mocks.js | 77 ++ .../ci_variable_list/store/actions_spec.js | 319 ----- .../ci_variable_list/store/getters_spec.js | 21 - .../ci_variable_list/store/mutations_spec.js | 136 --- spec/frontend/ci_variable_list/store/utils_spec.js | 49 - .../bubble_menus/formatting_bubble_menu_spec.js | 1 + .../content_editor/markdown_snapshot_spec.js | 9 +- .../markdown_snapshot_spec_helper.js | 26 +- .../render_html_and_json_for_all_examples.js | 83 +- .../services/markdown_serializer_spec.js | 55 +- spec/frontend/content_editor/test_utils.js | 85 ++ .../components/new_deploy_token_spec.js | 67 +- spec/frontend/deprecated_jquery_dropdown_spec.js | 14 +- .../pages/__snapshots__/index_spec.js.snap | 4 +- .../diffs/components/diff_row_utils_spec.js | 56 +- spec/frontend/diffs/mock_data/diff_file.js | 30 + spec/frontend/diffs/store/actions_spec.js | 38 +- spec/frontend/diffs/store/utils_spec.js | 54 +- .../frontend/diffs/utils/tree_worker_utils_spec.js | 64 + spec/frontend/editor/schema/ci/ci_schema_spec.js | 71 +- .../default_no_additional_properties.json | 2 +- .../inherit_default_no_additional_properties.json | 6 +- .../job_variables_must_not_contain_objects.json | 6 +- .../negative_tests/release_assets_links.json | 44 + .../negative_tests/release_assets_links_empty.json | 13 - .../release_assets_links_invalid_link_type.json | 24 - .../release_assets_links_missing.json | 11 - .../negative_tests/retry_unknown_when.json | 2 +- .../schema/ci/yaml_tests/negative_tests/cache.yml | 63 +- .../ci/yaml_tests/negative_tests/include.yml | 3 - .../ci/yaml_tests/negative_tests/job_when.yml | 11 + .../project_path/trigger/include/empty.yml | 5 - .../trigger/include/invalid_variable.yml | 5 - .../project_path/trigger/include/leading_slash.yml | 5 - .../project_path/trigger/include/no_slash.yml | 5 - .../project_path/trigger/include/tailing_slash.yml | 5 - .../project_path/trigger/minimal/empty.yml | 2 - .../trigger/minimal/invalid_variable.yml | 2 - .../project_path/trigger/minimal/leading_slash.yml | 2 - .../project_path/trigger/minimal/no_slash.yml | 2 - .../project_path/trigger/minimal/tailing_slash.yml | 2 - .../project_path/trigger/project/empty.yml | 3 - .../trigger/project/invalid_variable.yml | 3 - .../project_path/trigger/project/leading_slash.yml | 3 - .../project_path/trigger/project/no_slash.yml | 3 - .../project_path/trigger/project/tailing_slash.yml | 3 - .../ci/yaml_tests/negative_tests/trigger.yml | 64 + .../ci/yaml_tests/negative_tests/variables.yml | 5 - .../variables/invalid_syntax_desc.yml | 4 + .../variables/wrong_syntax_usage_expand.yml | 4 + .../schema/ci/yaml_tests/positive_tests/cache.yml | 112 +- .../ci/yaml_tests/positive_tests/job_when.yml | 10 + .../ci/yaml_tests/positive_tests/variables.yml | 10 + .../source_editor_markdown_livepreview_ext_spec.js | 9 + .../environments/environment_actions_spec.js | 6 +- .../environments/environment_rollback_spec.js | 2 +- spec/frontend/environments/graphql/mock_data.js | 1 + .../droplab/plugins/ajax_filter_spec.js | 7 +- spec/frontend/fixtures/api_merge_requests.rb | 2 +- spec/frontend/fixtures/api_projects.rb | 2 +- spec/frontend/fixtures/application_settings.rb | 2 +- spec/frontend/fixtures/blob.rb | 2 +- spec/frontend/fixtures/branches.rb | 2 +- spec/frontend/fixtures/clusters.rb | 2 +- spec/frontend/fixtures/deploy_keys.rb | 2 +- spec/frontend/fixtures/freeze_period.rb | 2 +- spec/frontend/fixtures/integrations.rb | 2 +- spec/frontend/fixtures/issues.rb | 2 +- spec/frontend/fixtures/job_artifacts.rb | 28 + spec/frontend/fixtures/jobs.rb | 2 +- spec/frontend/fixtures/labels.rb | 2 +- spec/frontend/fixtures/merge_requests.rb | 16 +- spec/frontend/fixtures/merge_requests_diffs.rb | 2 +- spec/frontend/fixtures/metrics_dashboard.rb | 2 +- spec/frontend/fixtures/namespaces.rb | 20 + spec/frontend/fixtures/pipeline_schedules.rb | 13 +- spec/frontend/fixtures/pipelines.rb | 2 +- spec/frontend/fixtures/projects.rb | 2 +- spec/frontend/fixtures/prometheus_integration.rb | 2 +- spec/frontend/fixtures/raw.rb | 2 +- spec/frontend/fixtures/runner.rb | 4 +- spec/frontend/fixtures/snippet.rb | 2 +- spec/frontend/fixtures/static/gl_field_errors.html | 3 + spec/frontend/fixtures/todos.rb | 2 +- spec/frontend/flash_spec.js | 14 + spec/frontend/gfm_auto_complete/mock_data.js | 57 + spec/frontend/gfm_auto_complete_spec.js | 95 +- .../components/gitlab_version_check_badge_spec.js | 102 ++ spec/frontend/gitlab_version_check/index_spec.js | 116 ++ spec/frontend/gl_field_errors_spec.js | 2 +- .../google_cloud/service_accounts/list_spec.js | 29 +- .../groups/components/overview_tabs_spec.js | 48 +- .../groups/components/transfer_group_form_spec.js | 56 +- .../components/transfer_locations_spec.js | 377 ++++++ spec/frontend/ide/components/ide_spec.js | 31 +- .../components/panes/collapsible_sidebar_spec.js | 26 +- spec/frontend/ide/components/panes/right_spec.js | 45 + .../switch_editors/switch_editors_view_spec.js | 214 ++++ spec/frontend/ide/stores/mutations_spec.js | 2 + .../import_groups/components/import_table_spec.js | 27 +- .../edit/components/integration_form_spec.js | 86 +- .../edit/components/trigger_fields_spec.js | 45 + .../components/invite_members_modal_spec.js | 76 +- .../components/invite_modal_base_spec.js | 57 +- .../components/user_limit_notification_spec.js | 60 +- .../invite_members/mock_data/member_modal.js | 2 +- .../components/move_issues_button_spec.js | 554 +++++++++ .../components/related_issues_block_spec.js | 48 +- .../components/related_issues_root_spec.js | 8 +- .../components/issues_dashboard_app_spec.js | 58 + .../issues/list/components/issues_list_app_spec.js | 86 +- spec/frontend/issues/list/mock_data.js | 117 +- .../show/components/fields/description_spec.js | 2 +- .../incidents/timeline_events_form_spec.js | 30 + .../components/job/legacy_sidebar_header_spec.js | 20 +- spec/frontend/jobs/components/job/sidebar_spec.js | 72 +- spec/frontend/jobs/mock_data.js | 24 + spec/frontend/lib/utils/common_utils_spec.js | 39 - .../confirm_via_gl_modal/confirm_action_spec.js | 103 ++ .../confirm_via_gl_modal_spec.js | 80 ++ .../datetime/date_calculation_utility_spec.js | 37 +- spec/frontend/lib/utils/dom_utils_spec.js | 28 + spec/frontend/lib/utils/unit_format/index_spec.js | 6 + .../access_request_action_buttons_spec.js | 90 +- .../members/components/members_tabs_spec.js | 5 +- .../__snapshots__/experiment_spec.js.snap | 223 ++++ .../components/experiment_spec.js | 44 + .../components/incubation_alert_spec.js | 27 + spec/frontend/notebook/cells/markdown_spec.js | 101 +- spec/frontend/notebook/cells/output/index_spec.js | 14 + .../notebook/cells/output/markdown_spec.js | 44 + spec/frontend/notebook/mock_data.js | 2 + .../__snapshots__/notes_app_spec.js.snap | 4 +- .../frontend/notes/components/note_actions_spec.js | 74 +- spec/frontend/notes/components/note_header_spec.js | 2 +- .../notes/mixins/discussion_navigation_spec.js | 2 +- spec/frontend/notes/stores/getters_spec.js | 22 +- .../observability/observability_app_spec.js | 73 ++ .../components/list_page/image_list_row_spec.js | 60 +- .../components/list_page/registry_header_spec.js | 6 + .../explorer/pages/details_spec.js | 24 +- .../list/components/packages_list_spec.js | 57 +- .../components/delete_modal_spec.js | 71 ++ .../details/package_versions_list_spec.js | 152 +++ .../__snapshots__/package_list_row_spec.js.snap | 9 +- .../components/list/package_list_row_spec.js | 43 +- .../components/list/packages_list_spec.js | 104 +- .../package_registry/mock_data.js | 34 + .../pages/__snapshots__/list_spec.js.snap | 54 +- .../package_registry/pages/details_spec.js | 33 +- .../package_registry/pages/list_spec.js | 158 ++- .../group/components/forwarding_settings_spec.js | 78 ++ .../group/components/group_settings_app_spec.js | 17 +- .../group/components/package_settings_spec.js | 14 +- .../packages_forwarding_settings_spec.js | 280 +++++ .../settings/group/mock_data.js | 75 +- .../shared/components/delete_package_modal_spec.js | 82 ++ .../__snapshots__/learn_gitlab_spec.js.snap | 7 + .../shared/components/timezone_dropdown_spec.js | 134 +- .../permissions/components/settings_panel_spec.js | 20 + .../shared/wikis/components/wiki_form_spec.js | 2 +- .../components/pipeline_editor_tabs_spec.js | 2 +- .../components/pipeline_schedules_form_spec.js | 25 - .../components/pipeline_schedules_spec.js | 161 --- .../table/cells/pipeline_schedule_actions_spec.js | 49 - .../cells/pipeline_schedule_last_pipeline_spec.js | 42 - .../table/cells/pipeline_schedule_next_run_spec.js | 43 - .../table/cells/pipeline_schedule_owner_spec.js | 40 - .../table/cells/pipeline_schedule_target_spec.js | 41 - .../table/pipeline_schedules_table_spec.js | 39 - .../components/take_ownership_modal_spec.js | 54 - spec/frontend/pipeline_schedules/mock_data.js | 35 - .../pipelines/components/pipeline_tabs_spec.js | 26 +- spec/frontend/pipelines/mock_data.js | 4 + .../pipelines/pipeline_graph/utils_spec.js | 17 +- spec/frontend/pipelines/pipeline_tabs_spec.js | 32 +- spec/frontend/pipelines/pipeline_url_spec.js | 16 +- spec/frontend/pipelines/pipelines_actions_spec.js | 6 +- .../project_delete_button_spec.js.snap | 2 + .../__snapshots__/delete_button_spec.js.snap | 2 + .../new_project_push_tip_popover_spec.js | 2 +- .../pipelines/charts/components/app_spec.js | 68 +- .../branch_rules/components/view/index_spec.js | 24 +- .../branch_rules/components/view/mock_data.js | 47 +- .../components/view/protection_row_spec.js | 5 + .../components/view/protection_spec.js | 11 + .../components/transfer_project_form_spec.js | 268 +--- .../settings/repository/branch_rules/app_spec.js | 4 + .../branch_rules/components/branch_rule_spec.js | 37 +- .../settings/repository/branch_rules/mock_data.js | 45 +- .../components/service_desk_setting_spec.js | 20 +- .../releases/components/asset_links_form_spec.js | 42 +- .../grouped_codequality_reports_app_spec.js | 151 --- .../codequality_report/store/actions_spec.js | 1 - .../__snapshots__/grouped_issues_list_spec.js.snap | 2 +- .../reports/components/grouped_issues_list_spec.js | 2 +- .../reports/components/report_item_spec.js | 4 +- .../grouped_test_report/components/modal_spec.js | 68 -- .../components/test_issue_body_spec.js | 96 -- .../grouped_test_reports_app_spec.js | 355 ------ .../grouped_test_report/store/actions_spec.js | 168 --- .../grouped_test_report/store/mutations_spec.js | 162 --- .../grouped_test_report/store/utils_spec.js | 255 ---- .../admin_runner_show_app_spec.js | 266 ---- .../runner/admin_runners/admin_runners_app_spec.js | 480 -------- .../runner_status_popover_spec.js.snap | 3 - .../runner/components/cells/link_cell_spec.js | 72 -- .../components/cells/runner_actions_cell_spec.js | 138 --- .../components/cells/runner_owner_cell_spec.js | 111 -- .../cells/runner_stacked_summary_cell_spec.js | 164 --- .../components/cells/runner_status_cell_spec.js | 77 -- .../components/cells/runner_summary_field_spec.js | 49 - .../registration/registration_dropdown_spec.js | 198 --- .../registration_token_reset_dropdown_item_spec.js | 209 ---- .../registration/registration_token_spec.js | 62 - .../runner/components/runner_assigned_item_spec.js | 68 -- .../components/runner_bulk_delete_checkbox_spec.js | 140 --- .../runner/components/runner_bulk_delete_spec.js | 243 ---- .../runner/components/runner_delete_button_spec.js | 266 ---- .../runner/components/runner_delete_modal_spec.js | 60 - .../runner/components/runner_details_spec.js | 130 -- .../runner/components/runner_edit_button_spec.js | 41 - .../components/runner_filtered_search_bar_spec.js | 188 --- .../runner/components/runner_groups_spec.js | 67 - .../runner/components/runner_header_spec.js | 119 -- .../frontend/runner/components/runner_jobs_spec.js | 155 --- .../runner/components/runner_jobs_table_spec.js | 119 -- .../components/runner_list_empty_state_spec.js | 103 -- .../frontend/runner/components/runner_list_spec.js | 231 ---- .../components/runner_membership_toggle_spec.js | 57 - .../runner/components/runner_pagination_spec.js | 115 -- .../runner/components/runner_pause_button_spec.js | 263 ---- .../runner/components/runner_paused_badge_spec.js | 46 - .../runner/components/runner_projects_spec.js | 251 ---- .../runner_stacked_layout_banner_spec.js | 41 - .../runner/components/runner_status_badge_spec.js | 133 -- .../components/runner_status_popover_spec.js | 36 - spec/frontend/runner/components/runner_tag_spec.js | 79 -- .../frontend/runner/components/runner_tags_spec.js | 54 - .../runner/components/runner_type_badge_spec.js | 66 - .../runner/components/runner_type_tabs_spec.js | 214 ---- .../runner/components/runner_update_form_spec.js | 288 ----- .../components/search_tokens/tag_token_spec.js | 208 ---- .../runner/components/stat/runner_count_spec.js | 148 --- .../components/stat/runner_single_stat_spec.js | 61 - .../runner/components/stat/runner_stats_spec.js | 81 -- spec/frontend/runner/graphql/local_state_spec.js | 167 --- .../group_runner_show_app_spec.js | 215 ---- .../runner/group_runners/group_runners_app_spec.js | 499 -------- .../save_alert_to_local_storage_spec.js | 24 - .../show_alert_from_local_storage_spec.js | 40 - spec/frontend/runner/mock_data.js | 322 ----- .../runner/runner_edit/runner_edit_app_spec.js | 114 -- spec/frontend/runner/runner_search_utils_spec.js | 138 --- .../runner/runner_update_form_utils_spec.js | 93 -- spec/frontend/runner/sentry_utils_spec.js | 39 - spec/frontend/runner/utils_spec.js | 80 -- spec/frontend/search/mock_data.js | 84 ++ .../frontend/search/sidebar/components/app_spec.js | 120 +- .../search/sidebar/components/filters_spec.js | 132 ++ .../sidebar/components/scope_navigation_spec.js | 80 ++ spec/frontend/search/store/actions_spec.js | 35 + spec/frontend/search/store/mutations_spec.js | 22 +- .../__snapshots__/self_monitor_form_spec.js.snap | 16 +- .../components/self_monitor_form_spec.js | 10 +- spec/frontend/self_monitor/store/actions_spec.js | 6 +- spec/frontend/self_monitor/store/mutations_spec.js | 2 +- .../milestone/milestone_dropdown_spec.js | 93 ++ .../reviewers/sidebar_reviewers_inputs_spec.js | 36 + .../sidebar/components/sidebar_dropdown_spec.js | 285 +++++ .../components/sidebar_dropdown_widget_spec.js | 202 +-- spec/frontend/token_access/mock_data.js | 12 + spec/frontend/token_access/token_access_spec.js | 7 +- .../token_access/token_projects_table_spec.js | 13 +- spec/frontend/users_select/utils_spec.js | 13 +- .../components/mr_widget_container_spec.js | 2 +- .../components/mr_widget_pipeline_spec.js | 2 + .../components/mr_widget_rebase_spec.js | 425 +++---- .../mr_widget_auto_merge_enabled_spec.js.snap | 202 +-- .../components/states/merge_checks_failed_spec.js | 8 +- .../states/mr_widget_auto_merge_enabled_spec.js | 182 +-- .../states/mr_widget_auto_merge_failed_spec.js | 60 +- .../components/states/mr_widget_conflicts_spec.js | 342 +++--- .../states/mr_widget_missing_branch_spec.js | 43 +- .../states/mr_widget_ready_to_merge_spec.js | 70 +- .../components/states/mr_widget_wip_spec.js | 109 +- .../__snapshots__/dynamic_content_spec.js.snap | 6 +- .../components/widget/dynamic_content_spec.js | 4 + .../components/widget/widget_content_row_spec.js | 37 + .../components/widget/widget_spec.js | 129 +- .../deployment/deployment_actions_spec.js | 6 +- .../deployment/deployment_info_spec.js | 42 + .../mr_widget_options_spec.js | 72 +- .../stores/mr_widget_store_spec.js | 13 - .../vue_shared/alert_details/alert_details_spec.js | 4 +- .../vue_shared/alert_details/router_spec.js | 35 + .../vue_shared/components/file_row_spec.js | 2 +- .../components/gitlab_version_check_spec.js | 135 -- .../components/group_select/group_select_spec.js | 202 +++ .../vue_shared/components/help_popover_spec.js | 14 + .../components/markdown/markdown_editor_spec.js | 29 +- .../markdown_drawer/markdown_drawer_spec.js | 205 ++++ .../components/markdown_drawer/mock_data.js | 42 + .../components/markdown_drawer/utils/fetch_spec.js | 43 + .../components/namespace_select/mock_data.js | 6 - .../namespace_select_deprecated_spec.js | 236 ---- .../sidebar/issuable_move_dropdown_spec.js | 24 +- .../labels_select_root_spec.js | 13 +- .../source_viewer/components/chunk_spec.js | 43 +- .../plugins/link_dependencies_spec.js | 38 +- .../components/source_viewer/plugins/mock_data.js | 30 + .../plugins/utils/composer_json_linker_spec.js | 38 + .../plugins/utils/dependency_linker_util_spec.js | 14 +- .../plugins/utils/gemfile_linker_spec.js | 13 + .../plugins/utils/gemspec_linker_spec.js | 2 +- .../plugins/utils/godeps_json_linker_spec.js | 27 + .../plugins/utils/package_json_linker_spec.js | 2 +- .../plugins/utils/podspec_json_linker_spec.js | 14 + .../source_viewer/plugins/wrap_child_nodes_spec.js | 3 +- .../components/source_viewer/source_viewer_spec.js | 54 +- .../issuable/list/components/issuable_item_spec.js | 18 - .../list/components/issuable_list_root_spec.js | 12 + .../__snapshots__/push_events_spec.js.snap | 453 +++++++ .../webhooks/components/form_url_app_spec.js | 125 +- .../webhooks/components/form_url_mask_item_spec.js | 78 +- .../webhooks/components/push_events_spec.js | 117 ++ .../components/work_item_assignees_spec.js | 4 +- .../work_item_description_rendered_spec.js | 108 ++ .../components/work_item_description_spec.js | 295 +++-- .../components/work_item_detail_modal_spec.js | 1 + .../work_items/components/work_item_detail_spec.js | 103 +- .../components/work_item_due_date_spec.js | 2 +- .../work_items/components/work_item_labels_spec.js | 25 + .../work_item_links/work_item_links_form_spec.js | 205 +++- .../work_item_links/work_item_links_spec.js | 31 +- .../components/work_item_milestone_spec.js | 32 +- spec/frontend/work_items/mock_data.js | 118 +- .../work_items/pages/create_work_item_spec.js | 39 +- .../work_items/pages/work_item_root_spec.js | 11 +- spec/frontend/work_items/router_spec.js | 28 + spec/graphql/graphql_triggers_spec.rb | 69 +- .../mutations/ci/runner/bulk_delete_spec.rb | 73 +- spec/graphql/mutations/ci/runner/update_spec.rb | 46 +- spec/graphql/mutations/commits/create_spec.rb | 2 +- .../concerns/mutations/resolves_group_spec.rb | 2 +- .../container_repositories/destroy_spec.rb | 22 +- .../timeline_event/create_spec.rb | 101 ++ .../timeline_event_tag/create_spec.rb | 52 + .../base_security_analyzer_spec.rb | 2 +- spec/graphql/mutations/todos/restore_many_spec.rb | 2 +- .../resolvers/board_list_issues_resolver_spec.rb | 2 +- .../graphql/resolvers/board_lists_resolver_spec.rb | 4 +- spec/graphql/resolvers/board_resolver_spec.rb | 2 +- spec/graphql/resolvers/boards_resolver_spec.rb | 2 +- .../container_repositories_resolver_spec.rb | 4 +- .../resolvers/group_packages_resolver_spec.rb | 8 +- .../timeline_event_tags_resolver_spec.rb | 92 ++ spec/graphql/resolvers/issues_resolver_spec.rb | 677 ---------- .../resolvers/project_issues_resolver_spec.rb | 677 ++++++++++ spec/graphql/resolvers/projects_resolver_spec.rb | 2 +- .../resolvers/recent_boards_resolver_spec.rb | 2 +- spec/graphql/resolvers/users_resolver_spec.rb | 14 +- spec/graphql/resolvers/work_item_resolver_spec.rb | 8 - .../resolvers/work_items/types_resolver_spec.rb | 20 - .../types/ci/pipeline_schedule_status_enum_spec.rb | 2 +- spec/graphql/types/ci/pipeline_type_spec.rb | 5 +- .../types/commit_signature_interface_spec.rb | 25 + .../commit_signatures/gpg_signature_type_spec.rb | 18 + .../verification_status_enum_spec.rb | 16 + .../commit_signatures/x509_signature_type_spec.rb | 18 + spec/graphql/types/commit_type_spec.rb | 4 +- spec/graphql/types/deployment_details_type_spec.rb | 2 +- .../timeline_event_tag_type_spec.rb | 18 + .../timeline_event_type_spec.rb | 1 + spec/graphql/types/issue_type_enum_spec.rb | 4 +- spec/graphql/types/issue_type_spec.rb | 2 +- .../types/permission_types/ci/runner_spec.rb | 2 +- spec/graphql/types/project_type_spec.rb | 127 +- .../types/projects/branch_rule_type_spec.rb | 5 +- .../projects/repository_language_type_spec.rb | 15 + spec/graphql/types/release_links_type_spec.rb | 10 +- spec/graphql/types/release_source_type_spec.rb | 2 +- spec/graphql/types/repository_type_spec.rb | 2 +- spec/graphql/types/subscription_type_spec.rb | 1 + spec/graphql/types/x509_certificate_type_spec.rb | 14 + spec/graphql/types/x509_issuer_type_spec.rb | 13 + spec/helpers/appearances_helper_spec.rb | 9 + spec/helpers/application_helper_spec.rb | 83 +- spec/helpers/application_settings_helper_spec.rb | 4 +- spec/helpers/diff_helper_spec.rb | 61 +- spec/helpers/environments_helper_spec.rb | 2 +- spec/helpers/events_helper_spec.rb | 24 + spec/helpers/form_helper_spec.rb | 42 +- spec/helpers/groups/group_members_helper_spec.rb | 15 +- spec/helpers/groups/observability_helper_spec.rb | 92 ++ spec/helpers/groups_helper_spec.rb | 72 +- spec/helpers/hooks_helper_spec.rb | 35 +- spec/helpers/icons_helper_spec.rb | 2 +- spec/helpers/ide_helper_spec.rb | 2 + spec/helpers/integrations_helper_spec.rb | 50 + spec/helpers/json_helper_spec.rb | 36 + spec/helpers/markup_helper_spec.rb | 149 +-- spec/helpers/nav/top_nav_helper_spec.rb | 126 +- .../projects/alert_management_helper_spec.rb | 2 + .../helpers/projects/ml/experiments_helper_spec.rb | 49 + spec/helpers/projects/pipeline_helper_spec.rb | 1 + .../projects/project_members_helper_spec.rb | 3 +- spec/helpers/projects_helper_spec.rb | 3 +- spec/helpers/recaptcha_helper_spec.rb | 25 +- spec/helpers/routing/packages_helper_spec.rb | 13 + spec/helpers/search_helper_spec.rb | 179 ++- spec/helpers/snippets_helper_spec.rb | 4 +- spec/helpers/todos_helper_spec.rb | 45 +- .../hashie_mash_permitted_patch_spec.rb | 29 + spec/initializers/memory_watchdog_spec.rb | 126 +- spec/initializers/sawyer_patch_spec.rb | 70 +- spec/lib/api/entities/merge_request_basic_spec.rb | 16 +- spec/lib/api/entities/ml/mlflow/run_info_spec.rb | 4 +- spec/lib/api/entities/release_spec.rb | 8 +- spec/lib/api/entities/user_counts_spec.rb | 24 + .../packages/dependency_proxy_helpers_spec.rb | 17 +- spec/lib/api/helpers/packages_helpers_spec.rb | 119 +- spec/lib/api/helpers_spec.rb | 6 +- .../validators/email_or_email_list_spec.rb | 2 + .../lib/api/validations/validators/git_ref_spec.rb | 2 +- spec/lib/api/validations/validators/limit_spec.rb | 4 +- .../atlassian/jira_connect/jwt/asymmetric_spec.rb | 35 +- spec/lib/backup/database_backup_error_spec.rb | 8 +- spec/lib/backup/file_backup_error_spec.rb | 4 +- spec/lib/banzai/filter/autolink_filter_spec.rb | 2 +- .../issuable_reference_expansion_filter_spec.rb | 2 +- spec/lib/banzai/filter/math_filter_spec.rb | 13 +- .../references/alert_reference_filter_spec.rb | 2 +- .../references/commit_reference_filter_spec.rb | 2 +- .../references/issue_reference_filter_spec.rb | 4 +- .../references/label_reference_filter_spec.rb | 10 +- .../references/milestone_reference_filter_spec.rb | 10 +- .../references/project_reference_filter_spec.rb | 4 +- .../references/user_reference_filter_spec.rb | 2 +- .../banzai/filter/repository_link_filter_spec.rb | 1 - .../banzai/filter/syntax_highlight_filter_spec.rb | 43 +- .../banzai/reference_parser/base_parser_spec.rb | 2 +- .../banzai/reference_parser/commit_parser_spec.rb | 26 +- .../reference_parser/commit_range_parser_spec.rb | 40 +- .../banzai/reference_parser/issue_parser_spec.rb | 8 +- spec/lib/bulk_imports/clients/http_spec.rb | 16 + .../common/pipelines/entity_finisher_spec.rb | 2 + spec/lib/bulk_imports/pipeline/runner_spec.rb | 25 +- .../projects/pipelines/references_pipeline_spec.rb | 131 ++ .../lib/error_tracking/sentry_client/issue_spec.rb | 2 +- spec/lib/feature/gitaly_spec.rb | 229 +++- spec/lib/feature_spec.rb | 48 +- .../analytics/cycle_analytics/median_spec.rb | 2 +- spec/lib/gitlab/app_logger_spec.rb | 7 +- spec/lib/gitlab/application_context_spec.rb | 8 +- spec/lib/gitlab/asciidoc_spec.rb | 23 +- spec/lib/gitlab/auth/auth_finders_spec.rb | 5 +- .../backfill_project_namespace_details_spec.rb | 62 + .../backfill_project_namespace_on_issues_spec.rb | 17 + .../backfill_projects_with_coverage_spec.rb | 95 -- .../backfill_user_details_fields_spec.rb | 222 ++++ .../batched_migration_job_spec.rb | 77 +- .../legacy_upload_mover_spec.rb | 2 +- .../populate_projects_star_count_spec.rb | 72 ++ .../populate_vulnerability_reads_spec.rb | 2 +- ...move_backfilled_job_artifacts_expire_at_spec.rb | 5 +- ...icate_ci_runners_token_encrypted_values_spec.rb | 70 -- ...reset_duplicate_ci_runners_token_values_spec.rb | 70 -- .../sanitize_confidential_todos_spec.rb | 89 ++ ...ipeline_artifacts_unknown_locked_status_spec.rb | 4 +- spec/lib/gitlab/bitbucket_import/importer_spec.rb | 1 - spec/lib/gitlab/cache/metrics_spec.rb | 118 ++ spec/lib/gitlab/checks/lfs_integrity_spec.rb | 21 +- .../ci/build/rules/rule/clause/exists_spec.rb | 42 +- spec/lib/gitlab/ci/config/entry/bridge_spec.rb | 36 +- spec/lib/gitlab/ci/config/entry/job_spec.rb | 22 +- .../lib/gitlab/ci/config/entry/processable_spec.rb | 27 +- spec/lib/gitlab/ci/config/entry/root_spec.rb | 29 + spec/lib/gitlab/ci/config/entry/variable_spec.rb | 118 ++ spec/lib/gitlab/ci/config/entry/variables_spec.rb | 34 + .../gitlab/ci/config/external/file/base_spec.rb | 22 + spec/lib/gitlab/ci/config/external/mapper_spec.rb | 16 +- spec/lib/gitlab/ci/config_spec.rb | 4 +- .../ci/parsers/codequality/code_climate_spec.rb | 62 +- .../ci/parsers/coverage/sax_document_spec.rb | 31 + .../ci/parsers/sbom/cyclonedx_properties_spec.rb | 8 +- spec/lib/gitlab/ci/parsers/sbom/cyclonedx_spec.rb | 41 +- spec/lib/gitlab/ci/parsers/security/common_spec.rb | 37 +- spec/lib/gitlab/ci/pipeline/chain/command_spec.rb | 17 + .../ci/pipeline/chain/limit/active_jobs_spec.rb | 4 +- .../ci/pipeline/chain/populate_metadata_spec.rb | 136 +++ spec/lib/gitlab/ci/pipeline/chain/populate_spec.rb | 43 - spec/lib/gitlab/ci/pipeline/chain/sequence_spec.rb | 2 +- .../lib/gitlab/ci/pipeline/seed/deployment_spec.rb | 119 -- .../gitlab/ci/pipeline/seed/environment_spec.rb | 224 ---- spec/lib/gitlab/ci/pipeline/seed/pipeline_spec.rb | 12 +- spec/lib/gitlab/ci/reports/sbom/component_spec.rb | 70 +- spec/lib/gitlab/ci/reports/sbom/report_spec.rb | 15 + spec/lib/gitlab/ci/reports/security/flag_spec.rb | 6 + .../lib/gitlab/ci/reports/security/reports_spec.rb | 26 + spec/lib/gitlab/ci/reports/test_suite_spec.rb | 2 +- .../5_minute_production_app_ci_yaml_spec.rb | 2 +- .../AWS/deploy_ecs_gitlab_ci_yaml_spec.rb | 2 +- .../ci/templates/Jobs/build_gitlab_ci_yaml_spec.rb | 14 +- .../Jobs/code_quality_gitlab_ci_yaml_spec.rb | 11 +- .../templates/Jobs/deploy_gitlab_ci_yaml_spec.rb | 15 +- .../templates/Jobs/sast_iac_gitlab_ci_yaml_spec.rb | 10 +- .../Jobs/sast_iac_latest_gitlab_ci_yaml_spec.rb | 10 +- .../ci/templates/Jobs/test_gitlab_ci_yaml_spec.rb | 11 +- spec/lib/gitlab/ci/templates/MATLAB_spec.rb | 2 +- .../Terraform/base_gitlab_ci_yaml_spec.rb | 2 +- .../Terraform/base_latest_gitlab_ci_yaml_spec.rb | 2 +- ...load_performance_testing_gitlab_ci_yaml_spec.rb | 2 +- .../templates/auto_devops_gitlab_ci_yaml_spec.rb | 2 +- .../ci/templates/flutter_gitlab_ci_yaml_spec.rb | 2 +- .../ci/templates/kaniko_gitlab_ci_yaml_spec.rb | 2 +- .../ci/templates/katalon_gitlab_ci_yaml_spec.rb | 2 +- spec/lib/gitlab/ci/templates/npm_spec.rb | 5 +- .../ci/templates/terraform_gitlab_ci_yaml_spec.rb | 23 +- .../terraform_latest_gitlab_ci_yaml_spec.rb | 38 +- .../ci/templates/themekit_gitlab_ci_yaml_spec.rb | 7 +- .../gitlab/ci/variables/collection/item_spec.rb | 6 +- spec/lib/gitlab/ci/variables/collection_spec.rb | 53 +- spec/lib/gitlab/ci/yaml_processor_spec.rb | 77 +- spec/lib/gitlab/cluster/lifecycle_events_spec.rb | 59 +- .../cluster/puma_worker_killer_initializer_spec.rb | 30 + .../external_database_checker_spec.rb | 21 +- spec/lib/gitlab/conflict/file_spec.rb | 25 +- .../content_security_policy/config_loader_spec.rb | 12 + spec/lib/gitlab/data_builder/build_spec.rb | 98 +- spec/lib/gitlab/data_builder/pipeline_spec.rb | 1 + .../background_migration/batched_job_spec.rb | 18 +- .../background_migration/batched_migration_spec.rb | 96 ++ spec/lib/gitlab/database/batch_count_spec.rb | 2 +- .../database/load_balancing/configuration_spec.rb | 12 +- .../load_balancing/connection_proxy_spec.rb | 4 +- .../service_discovery/sampler_spec.rb | 80 ++ .../load_balancing/service_discovery_spec.rb | 34 +- .../sidekiq_server_middleware_spec.rb | 2 +- .../load_balancing/transaction_leaking_spec.rb | 15 +- spec/lib/gitlab/database/load_balancing_spec.rb | 5 +- .../gitlab/database/migration_helpers/v2_spec.rb | 94 +- spec/lib/gitlab/database/migration_helpers_spec.rb | 1292 ++++++-------------- .../background_migration_helpers_spec.rb | 3 - .../batched_background_migration_helpers_spec.rb | 95 ++ .../migrations/constraints_helpers_spec.rb | 679 ++++++++++ .../database/migrations/extension_helpers_spec.rb | 65 + .../migrations/lock_retries_helpers_spec.rb | 52 + spec/lib/gitlab/database/migrations/runner_spec.rb | 63 +- .../database/migrations/timeout_helpers_spec.rb | 91 ++ .../convert_table_to_first_list_partition_spec.rb | 14 +- .../detached_partition_dropper_spec.rb | 8 +- .../index_helpers_spec.rb | 170 ++- .../table_management_helpers_spec.rb | 9 +- .../lib/gitlab/database/postgres_partition_spec.rb | 32 + spec/lib/gitlab/database/query_analyzer_spec.rb | 8 + .../ci/partitioning_analyzer_spec.rb | 78 -- .../ci/partitioning_id_analyzer_spec.rb | 121 ++ .../ci/partitioning_routing_analyzer_spec.rb | 70 ++ .../query_analyzers/query_recorder_spec.rb | 38 + spec/lib/gitlab/database/tables_truncate_spec.rb | 20 + .../gitlab/database/type/symbolized_jsonb_spec.rb | 64 + .../self_monitoring/project/delete_service_spec.rb | 4 +- spec/lib/gitlab/database_spec.rb | 6 +- .../dependency_linker/composer_json_linker_spec.rb | 3 +- spec/lib/gitlab/diff/file_spec.rb | 32 +- .../token/pbkdf2_sha512_spec.rb | 10 - .../email/handler/unsubscribe_handler_spec.rb | 10 +- spec/lib/gitlab/email/handler_spec.rb | 2 +- spec/lib/gitlab/email/receiver_spec.rb | 62 +- spec/lib/gitlab/error_tracking_spec.rb | 19 + .../lib/gitlab/experimentation/group_types_spec.rb | 13 - spec/lib/gitlab/feature_categories_spec.rb | 24 +- spec/lib/gitlab/git/object_pool_spec.rb | 66 +- spec/lib/gitlab/git/repository_spec.rb | 12 +- spec/lib/gitlab/git/tree_spec.rb | 2 +- spec/lib/gitlab/git_ref_validator_spec.rb | 4 + .../gitaly_client/object_pool_service_spec.rb | 33 +- .../gitlab/gitaly_client/operation_service_spec.rb | 227 +++- spec/lib/gitlab/gitaly_client/ref_service_spec.rb | 20 +- .../gitaly_client/with_feature_flag_actors_spec.rb | 275 +++++ spec/lib/gitlab/gitaly_client_spec.rb | 134 ++ .../github_import/attachments_downloader_spec.rb | 2 +- spec/lib/gitlab/github_import/client_spec.rb | 118 +- .../importer/events/changed_label_spec.rb | 75 +- .../importer/protected_branch_importer_spec.rb | 149 ++- .../importer/protected_branches_importer_spec.rb | 16 +- .../importer/pull_request_review_importer_spec.rb | 83 +- .../pull_requests/review_request_importer_spec.rb | 35 + .../pull_requests/review_requests_importer_spec.rb | 141 +++ .../representation/protected_branch_spec.rb | 15 +- .../pull_requests/review_requests_spec.rb | 49 + spec/lib/gitlab/gon_helper_spec.rb | 52 + .../loggers/filter_parameters_spec.rb | 62 + spec/lib/gitlab/health_checks/gitaly_check_spec.rb | 4 +- .../gitlab/hook_data/merge_request_builder_spec.rb | 1 + spec/lib/gitlab/import_export/all_models.yml | 6 + .../decompressed_archive_size_validator_spec.rb | 2 +- .../import_export/design_repo_restorer_spec.rb | 8 +- spec/lib/gitlab/import_export/fork_spec.rb | 6 +- .../gitlab/import_export/group/tree_saver_spec.rb | 2 +- .../import_export/import_test_coverage_spec.rb | 10 +- .../import_export/merge_request_parser_spec.rb | 4 +- .../project/exported_relations_merger_spec.rb | 75 ++ .../import_export/project/relation_saver_spec.rb | 8 +- .../import_export/project/tree_restorer_spec.rb | 2 +- .../import_export/recursive_merge_folders_spec.rb | 54 + .../lib/gitlab/import_export/repo_restorer_spec.rb | 2 - .../gitlab/import_export/safe_model_attributes.yml | 4 +- .../import_export/snippets_repo_restorer_spec.rb | 2 - ...ctive_projects_deletion_warning_tracker_spec.rb | 4 +- spec/lib/gitlab/incoming_email_spec.rb | 99 +- .../redis_cluster_validator_spec.rb | 29 +- .../instrumentation/redis_interceptor_spec.rb | 19 +- spec/lib/gitlab/json_logger_spec.rb | 20 + spec/lib/gitlab/json_spec.rb | 56 + spec/lib/gitlab/kas_spec.rb | 12 + spec/lib/gitlab/kroki_spec.rb | 3 +- .../gitlab/memory/watchdog/configuration_spec.rb | 61 +- .../gitlab/memory/watchdog/configurator_spec.rb | 199 +++ .../watchdog/monitor/rss_memory_limit_spec.rb | 39 + spec/lib/gitlab/memory/watchdog_spec.rb | 10 +- .../mergeability/check_result_spec.rb | 4 +- .../mergeability/redis_interface_spec.rb | 2 +- .../mergeability/results_store_spec.rb | 6 +- spec/lib/gitlab/metrics/dashboard/finder_spec.rb | 6 +- .../metrics/dashboard/service_selector_spec.rb | 2 +- spec/lib/gitlab/metrics/dashboard/url_spec.rb | 2 +- spec/lib/gitlab/metrics/global_search_slis_spec.rb | 8 +- .../gitlab/metrics/loose_foreign_keys_slis_spec.rb | 81 ++ spec/lib/gitlab/metrics/method_call_spec.rb | 47 +- .../gitlab/metrics/samplers/ruby_sampler_spec.rb | 20 +- spec/lib/gitlab/metrics/system_spec.rb | 25 +- spec/lib/gitlab/observability_spec.rb | 33 + spec/lib/gitlab/octokit/middleware_spec.rb | 8 + .../gitlab/pagination/gitaly_keyset_pager_spec.rb | 2 +- spec/lib/gitlab/pagination_delegate_spec.rb | 157 +++ .../redis_adapter_when_peek_enabled_spec.rb | 4 +- spec/lib/gitlab/project_template_spec.rb | 14 + spec/lib/gitlab/qa_spec.rb | 29 + spec/lib/gitlab/query_limiting/transaction_spec.rb | 3 + spec/lib/gitlab/redis/multi_store_spec.rb | 544 +++------ spec/lib/gitlab/request_forgery_protection_spec.rb | 6 + spec/lib/gitlab/runtime_spec.rb | 2 +- spec/lib/gitlab/service_desk_email_spec.rb | 40 +- spec/lib/gitlab/sidekiq_config_spec.rb | 2 +- .../gitlab/sidekiq_daemon/memory_killer_spec.rb | 4 +- .../duplicate_jobs/client_spec.rb | 3 +- .../duplicate_jobs/duplicate_job_spec.rb | 312 ++--- .../sidekiq_middleware/server_metrics_spec.rb | 4 +- spec/lib/gitlab/sidekiq_middleware_spec.rb | 2 +- spec/lib/gitlab/sidekiq_migrate_jobs_spec.rb | 322 ++++- .../gitlab/slash_commands/application_help_spec.rb | 22 +- spec/lib/gitlab/slash_commands/command_spec.rb | 20 + .../incident_management/incident_new_spec.rb | 15 + spec/lib/gitlab/sql/pattern_spec.rb | 45 +- .../helpers/weak_password_error_event_spec.rb | 45 + spec/lib/gitlab/url_builder_spec.rb | 51 +- spec/lib/gitlab/usage/metric_definition_spec.rb | 20 +- .../usage/metrics/aggregates/aggregate_spec.rb | 434 ++----- .../count_merge_request_authors_metric_spec.rb | 25 + .../instrumentations/database_metric_spec.rb | 63 +- ..._with_expiration_policy_disabled_metric_spec.rb | 19 - ..._projects_with_expiration_policy_metric_spec.rb | 33 + .../dormant_user_period_setting_metric_spec.rb | 21 + .../dormant_user_setting_enabled_metric_spec.rb | 21 + ...duct_marketing_email_cta_clicked_metric_spec.rb | 55 + .../in_product_marketing_email_sent_metric_spec.rb | 52 + .../work_items_activity_aggregated_metric_spec.rb | 24 +- .../gitlab/usage/metrics/name_suggestion_spec.rb | 13 +- .../relation_parsers/constraints_spec.rb | 17 - .../relation_parsers/having_constraints_spec.rb | 19 + .../relation_parsers/where_constraints_spec.rb | 18 + .../ci_template_unique_counter_spec.rb | 35 +- .../usage_data_counters/hll_redis_counter_spec.rb | 1 + .../kubernetes_agent_counter_spec.rb | 6 + .../work_item_activity_unique_counter_spec.rb | 8 + spec/lib/gitlab/usage_data_spec.rb | 196 +-- spec/lib/gitlab/utils/strong_memoize_spec.rb | 57 +- spec/lib/gitlab/utils_spec.rb | 14 +- spec/lib/gitlab/webpack/file_loader_spec.rb | 4 +- spec/lib/grafana/client_spec.rb | 2 +- spec/lib/object_storage/direct_upload_spec.rb | 147 ++- spec/lib/omni_auth/strategies/jwt_spec.rb | 2 + spec/lib/rouge/formatters/html_gitlab_spec.rb | 10 + .../sbom/package_url/argument_validator_spec.rb | 51 + spec/lib/sbom/package_url/decoder_spec.rb | 121 ++ spec/lib/sbom/package_url/encoder_spec.rb | 29 + spec/lib/sbom/package_url/normalizer_spec.rb | 76 ++ spec/lib/sbom/package_url_spec.rb | 162 +++ spec/lib/serializers/symbolized_json_spec.rb | 42 - .../projects/menus/infrastructure_menu_spec.rb | 46 + .../sidebars/projects/menus/monitor_menu_spec.rb | 14 - spec/lib/unnested_in_filters/rewriter_spec.rb | 91 ++ spec/mailers/emails/identity_verification_spec.rb | 42 + spec/mailers/emails/releases_spec.rb | 1 + spec/mailers/notify_spec.rb | 2 +- ...8185845_backfill_projects_with_coverage_spec.rb | 71 -- ...0107064845_populate_vulnerability_reads_spec.rb | 2 +- ...1144258_remove_orphan_group_token_users_spec.rb | 9 +- ...ective_and_keyresult_to_work_item_types_spec.rb | 66 + ...dule_backfill_project_namespace_details_spec.rb | 37 + ..._renaming_background_migration_finished_spec.rb | 91 ++ ...te_routing_table_for_builds_metadata_v2_spec.rb | 36 + ...assword_last_changed_at_to_user_details_spec.rb | 37 + ...assword_last_changed_at_to_user_details_spec.rb | 16 + ...ferred_language_to_application_settings_spec.rb | 27 + ...ferred_language_on_application_settings_spec.rb | 29 + ...090940_create_next_ci_partitions_record_spec.rb | 63 + ...te_second_partition_for_builds_metadata_spec.rb | 61 + ...ansitions_with_same_from_state_to_state_spec.rb | 49 + ...e_migrate_shared_vulnerability_scanners_spec.rb | 69 ++ .../finalize_invalid_member_cleanup_spec.rb | 72 ++ .../queue_backfill_user_details_fields_spec.rb | 24 + .../queue_populate_projects_star_count_spec.rb | 24 + spec/migrations/recount_epic_cache_counts_spec.rb | 32 + ...e_migrate_shared_vulnerability_scanners_spec.rb | 41 + .../sanitize_confidential_note_todos_spec.rb | 33 + ...e_migrate_shared_vulnerability_scanners_spec.rb | 59 - ...om_send_user_confirmation_email_setting_spec.rb | 41 + ...nt_used_for_ci_namespace_monthly_usages_spec.rb | 42 + ...ount_used_for_ci_project_monthly_usages_spec.rb | 42 + spec/models/active_session_spec.rb | 22 +- .../alert_management/http_integration_spec.rb | 9 +- spec/models/appearance_spec.rb | 14 + spec/models/application_setting_spec.rb | 17 + spec/models/broadcast_message_spec.rb | 7 + spec/models/ci/bridge_spec.rb | 93 +- spec/models/ci/build_metadata_spec.rb | 32 + spec/models/ci/build_runner_session_spec.rb | 6 +- spec/models/ci/build_spec.rb | 121 +- spec/models/ci/build_trace_chunk_spec.rb | 5 + spec/models/ci/build_trace_spec.rb | 4 +- spec/models/ci/pipeline_metadata_spec.rb | 2 +- spec/models/ci/pipeline_spec.rb | 39 +- spec/models/ci/processable_spec.rb | 22 +- spec/models/ci/secure_file_spec.rb | 11 +- spec/models/ci/sources/pipeline_spec.rb | 4 +- spec/models/ci/stage_spec.rb | 2 +- spec/models/ci/trigger_request_spec.rb | 2 +- spec/models/ci/unit_test_spec.rb | 2 +- .../clusters/applications/cert_manager_spec.rb | 5 + .../clusters/applications/crossplane_spec.rb | 5 + spec/models/clusters/applications/helm_spec.rb | 4 + spec/models/clusters/applications/ingress_spec.rb | 5 + spec/models/clusters/applications/jupyter_spec.rb | 4 + spec/models/clusters/applications/knative_spec.rb | 4 + .../clusters/applications/prometheus_spec.rb | 11 +- spec/models/clusters/applications/runner_spec.rb | 4 + spec/models/clusters/cluster_spec.rb | 4 + .../clusters/integrations/prometheus_spec.rb | 10 + spec/models/clusters/platforms/kubernetes_spec.rb | 57 +- spec/models/clusters/providers/aws_spec.rb | 2 +- spec/models/clusters/providers/gcp_spec.rb | 3 +- .../models/commit_signatures/gpg_signature_spec.rb | 6 + spec/models/commit_status_spec.rb | 1 + spec/models/concerns/bulk_insert_safe_spec.rb | 6 +- spec/models/concerns/ci/has_variable_spec.rb | 1 + .../concerns/ci/partitionable/switch_spec.rb | 316 +++++ spec/models/concerns/ci/partitionable_spec.rb | 21 +- .../concerns/encrypted_user_password_spec.rb | 138 +++ spec/models/concerns/file_store_mounter_spec.rb | 93 ++ spec/models/concerns/has_user_type_spec.rb | 42 + spec/models/concerns/issuable_spec.rb | 41 +- .../concerns/pg_full_text_searchable_spec.rb | 38 +- .../project_features_compatibility_spec.rb | 2 +- spec/models/concerns/sha_attribute_spec.rb | 10 +- spec/models/concerns/subquery_spec.rb | 61 + spec/models/concerns/token_authenticatable_spec.rb | 10 +- spec/models/container_repository_spec.rb | 32 + spec/models/dependency_proxy/group_setting_spec.rb | 5 + spec/models/deploy_token_spec.rb | 2 +- spec/models/deployment_spec.rb | 26 +- spec/models/diff_discussion_spec.rb | 2 +- spec/models/diff_viewer/server_side_spec.rb | 28 - spec/models/environment_spec.rb | 4 +- spec/models/environment_status_spec.rb | 2 +- .../project_error_tracking_setting_spec.rb | 28 - spec/models/event_collection_spec.rb | 254 ++-- spec/models/event_spec.rb | 8 +- spec/models/experiment_spec.rb | 428 ------- spec/models/experiment_subject_spec.rb | 72 -- spec/models/experiment_user_spec.rb | 14 - spec/models/exported_protected_branch_spec.rb | 2 +- spec/models/factories_spec.rb | 136 ++- spec/models/group_spec.rb | 180 ++- spec/models/hooks/active_hook_filter_spec.rb | 113 +- spec/models/hooks/project_hook_spec.rb | 20 +- spec/models/hooks/system_hook_spec.rb | 11 +- spec/models/hooks/web_hook_log_spec.rb | 19 +- spec/models/hooks/web_hook_spec.rb | 142 ++- .../incident_management/timeline_event_spec.rb | 1 + .../incident_management/timeline_event_tag_spec.rb | 37 +- spec/models/instance_metadata_spec.rb | 3 +- spec/models/integration_spec.rb | 55 +- spec/models/integrations/assembla_spec.rb | 4 + spec/models/integrations/bamboo_spec.rb | 46 +- .../integrations/base_chat_notification_spec.rb | 22 +- .../models/integrations/base_issue_tracker_spec.rb | 4 + .../integrations/base_third_party_wiki_spec.rb | 4 + spec/models/integrations/buildkite_spec.rb | 6 +- spec/models/integrations/campfire_spec.rb | 4 +- .../chat_message/pipeline_message_spec.rb | 41 +- spec/models/integrations/confluence_spec.rb | 5 +- spec/models/integrations/datadog_spec.rb | 8 + spec/models/integrations/discord_spec.rb | 2 +- spec/models/integrations/drone_ci_spec.rb | 7 +- spec/models/integrations/emails_on_push_spec.rb | 2 +- spec/models/integrations/hangouts_chat_spec.rb | 6 +- spec/models/integrations/harbor_spec.rb | 11 +- spec/models/integrations/jenkins_spec.rb | 142 +-- spec/models/integrations/jira_spec.rb | 77 +- .../integrations/mattermost_slash_commands_spec.rb | 4 +- spec/models/integrations/microsoft_teams_spec.rb | 36 +- spec/models/integrations/mock_ci_spec.rb | 2 + spec/models/integrations/packagist_spec.rb | 84 +- spec/models/integrations/pipelines_email_spec.rb | 2 +- spec/models/integrations/prometheus_spec.rb | 8 +- spec/models/integrations/pushover_spec.rb | 4 +- spec/models/integrations/shimo_spec.rb | 6 +- .../integrations/slack_slash_commands_spec.rb | 2 +- spec/models/integrations/slack_spec.rb | 140 +-- spec/models/integrations/teamcity_spec.rb | 50 +- spec/models/integrations/zentao_spec.rb | 6 +- spec/models/issue_spec.rb | 32 +- spec/models/jira_connect_installation_spec.rb | 16 +- spec/models/member_spec.rb | 8 +- spec/models/members/group_member_spec.rb | 6 + .../members/last_group_owner_assigner_spec.rb | 88 +- spec/models/members/project_member_spec.rb | 4 + spec/models/merge_request_diff_file_spec.rb | 10 - spec/models/merge_request_diff_spec.rb | 13 + spec/models/merge_request_spec.rb | 73 +- spec/models/metrics/dashboard/annotation_spec.rb | 2 +- spec/models/ml/candidate_metric_spec.rb | 13 + spec/models/ml/candidate_spec.rb | 36 +- spec/models/namespace_setting_spec.rb | 6 +- spec/models/namespace_spec.rb | 20 +- spec/models/network/graph_spec.rb | 24 +- spec/models/note_spec.rb | 68 +- spec/models/notification_setting_spec.rb | 6 + spec/models/oauth_access_token_spec.rb | 31 - spec/models/operations/feature_flag_spec.rb | 5 + spec/models/packages/package_file_spec.rb | 2 +- spec/models/packages/package_spec.rb | 12 +- spec/models/pages_domain_spec.rb | 4 + spec/models/personal_access_token_spec.rb | 57 +- spec/models/preloaders/labels_preloader_spec.rb | 5 +- .../project_root_ancestor_preloader_spec.rb | 8 + ..._max_access_level_in_projects_preloader_spec.rb | 58 +- spec/models/project_authorization_spec.rb | 77 +- spec/models/project_ci_cd_setting_spec.rb | 6 + spec/models/project_setting_spec.rb | 9 +- spec/models/project_spec.rb | 108 +- spec/models/projects/wiki_repository_spec.rb | 16 + spec/models/protected_branch_spec.rb | 45 +- spec/models/repository_spec.rb | 7 +- spec/models/serverless/domain_cluster_spec.rb | 10 + spec/models/spam_log_spec.rb | 37 +- spec/models/terraform/state_spec.rb | 6 + spec/models/terraform/state_version_spec.rb | 9 + spec/models/time_tracking/timelog_category_spec.rb | 4 + spec/models/todo_spec.rb | 2 +- spec/models/user_spec.rb | 274 +---- spec/models/users/calloutable_spec.rb | 4 +- spec/models/users/ghost_user_migration_spec.rb | 13 +- spec/models/users/namespace_commit_email_spec.rb | 21 + spec/models/users_star_project_spec.rb | 80 ++ spec/models/work_items/type_spec.rb | 7 +- spec/models/work_items/widgets/hierarchy_spec.rb | 32 - spec/models/work_items/widgets/milestone_spec.rb | 27 + spec/policies/global_policy_spec.rb | 30 - spec/policies/group_member_policy_spec.rb | 130 +- spec/policies/group_policy_spec.rb | 13 + spec/policies/issuable_policy_spec.rb | 8 +- spec/policies/note_policy_spec.rb | 24 +- spec/policies/project_member_policy_spec.rb | 32 +- spec/policies/project_policy_spec.rb | 138 ++- spec/policies/user_policy_spec.rb | 44 + spec/presenters/blob_presenter_spec.rb | 12 + spec/presenters/ci/build_runner_presenter_spec.rb | 41 +- spec/presenters/ci/pipeline_presenter_spec.rb | 4 +- .../deployments/deployment_presenter_spec.rb | 2 +- spec/presenters/issue_presenter_spec.rb | 36 +- .../packages/npm/package_presenter_spec.rb | 8 +- spec/presenters/project_presenter_spec.rb | 8 +- spec/rack_servers/configs/config.ru | 2 +- .../admin/broadcast_messages_controller_spec.rb | 89 ++ spec/requests/api/admin/ci/variables_spec.rb | 27 +- spec/requests/api/alert_management_alerts_spec.rb | 8 +- spec/requests/api/boards_spec.rb | 4 +- spec/requests/api/ci/job_artifacts_spec.rb | 16 +- spec/requests/api/ci/jobs_spec.rb | 26 + spec/requests/api/ci/pipelines_spec.rb | 14 +- spec/requests/api/ci/resource_groups_spec.rb | 44 + spec/requests/api/ci/runner/jobs_artifacts_spec.rb | 24 +- .../api/ci/runner/jobs_request_post_spec.rb | 2 +- .../ci/runners_reset_registration_token_spec.rb | 2 +- spec/requests/api/ci/runners_spec.rb | 2 +- spec/requests/api/ci/secure_files_spec.rb | 12 + spec/requests/api/ci/triggers_spec.rb | 2 +- spec/requests/api/ci/variables_spec.rb | 25 +- spec/requests/api/clusters/agent_tokens_spec.rb | 12 +- spec/requests/api/dependency_proxy_spec.rb | 2 +- spec/requests/api/deployments_spec.rb | 4 +- spec/requests/api/features_spec.rb | 39 +- spec/requests/api/files_spec.rb | 35 +- spec/requests/api/go_proxy_spec.rb | 31 +- .../graphql/boards/board_list_issues_query_spec.rb | 40 +- .../api/graphql/boards/board_lists_query_spec.rb | 63 +- spec/requests/api/graphql/ci/jobs_spec.rb | 4 +- spec/requests/api/graphql/ci/pipelines_spec.rb | 6 +- spec/requests/api/graphql/ci/runner_spec.rb | 3 +- .../api/graphql/group/work_item_types_spec.rb | 11 - spec/requests/api/graphql/issues_spec.rb | 117 ++ spec/requests/api/graphql/metadata_query_spec.rb | 3 +- .../graphql/mutations/award_emojis/remove_spec.rb | 2 +- .../graphql/mutations/award_emojis/toggle_spec.rb | 2 +- .../ci/pipeline_schedule_take_ownership_spec.rb | 41 + .../ci/runners_registration_token/reset_spec.rb | 2 +- .../mutations/container_repository/destroy_spec.rb | 23 +- .../timeline_event/create_spec.rb | 32 +- .../timeline_event/promote_from_note_spec.rb | 2 +- .../timeline_event/update_spec.rb | 12 +- .../timeline_event_tag/create_spec.rb | 57 + .../api/graphql/mutations/issues/create_spec.rb | 33 +- .../mutations/work_items/create_from_task_spec.rb | 14 - .../graphql/mutations/work_items/create_spec.rb | 64 +- .../graphql/mutations/work_items/delete_spec.rb | 14 - .../mutations/work_items/delete_task_spec.rb | 14 - .../graphql/mutations/work_items/update_spec.rb | 105 +- .../mutations/work_items/update_task_spec.rb | 16 - spec/requests/api/graphql/packages/package_spec.rb | 20 + .../branch_protections/merge_access_levels_spec.rb | 104 +- .../branch_protections/push_access_levels_spec.rb | 104 +- .../api/graphql/project/branch_rules_spec.rb | 143 ++- .../incident_management/timeline_events_spec.rb | 43 + spec/requests/api/graphql/project/issues_spec.rb | 286 ++--- .../requests/api/graphql/project/languages_spec.rb | 62 + .../requests/api/graphql/project/tree/tree_spec.rb | 86 +- .../api/graphql/project/work_item_types_spec.rb | 11 - .../api/graphql/project/work_items_spec.rb | 25 +- spec/requests/api/graphql/work_item_spec.rb | 46 +- spec/requests/api/group_boards_spec.rb | 2 +- .../api/group_container_repositories_spec.rb | 8 + spec/requests/api/group_variables_spec.rb | 25 +- spec/requests/api/groups_spec.rb | 26 +- spec/requests/api/import_github_spec.rb | 22 + spec/requests/api/internal/kubernetes_spec.rb | 42 - spec/requests/api/invitations_spec.rb | 133 +- spec/requests/api/issues/issues_spec.rb | 4 +- .../api/issues/post_projects_issues_spec.rb | 4 +- spec/requests/api/labels_spec.rb | 2 +- spec/requests/api/markdown_spec.rb | 2 +- spec/requests/api/maven_packages_spec.rb | 10 + spec/requests/api/members_spec.rb | 125 +- spec/requests/api/merge_requests_spec.rb | 6 +- .../api/metrics/dashboard/annotations_spec.rb | 2 +- spec/requests/api/ml/mlflow_spec.rb | 7 +- spec/requests/api/npm_project_packages_spec.rb | 33 +- spec/requests/api/pages/pages_spec.rb | 2 +- spec/requests/api/personal_access_tokens_spec.rb | 19 +- spec/requests/api/project_attributes.yml | 1 + .../api/project_container_repositories_spec.rb | 22 +- spec/requests/api/project_import_spec.rb | 4 +- spec/requests/api/project_milestones_spec.rb | 2 +- spec/requests/api/project_snippets_spec.rb | 2 +- spec/requests/api/projects_spec.rb | 64 +- spec/requests/api/protected_branches_spec.rb | 55 +- spec/requests/api/protected_tags_spec.rb | 8 +- spec/requests/api/pypi_packages_spec.rb | 3 + spec/requests/api/release/links_spec.rb | 18 +- spec/requests/api/resource_access_tokens_spec.rb | 101 +- spec/requests/api/rpm_project_packages_spec.rb | 70 +- spec/requests/api/rubygem_packages_spec.rb | 5 +- spec/requests/api/search_spec.rb | 64 +- spec/requests/api/snippets_spec.rb | 10 +- spec/requests/api/submodules_spec.rb | 2 +- spec/requests/api/suggestions_spec.rb | 15 +- spec/requests/api/tags_spec.rb | 2 +- .../api/terraform/modules/v1/packages_spec.rb | 5 +- spec/requests/api/terraform/state_spec.rb | 37 +- spec/requests/api/todos_spec.rb | 2 +- spec/requests/api/unleash_spec.rb | 12 - spec/requests/api/user_counts_spec.rb | 26 +- spec/requests/api/users_spec.rb | 188 +-- .../groups/observability_controller_spec.rb | 218 ++-- .../settings/access_tokens_controller_spec.rb | 25 +- .../cors_preflight_checks_controller_spec.rb | 59 + .../oauth_application_ids_controller_spec.rb | 34 +- .../jira_connect/subscriptions_controller_spec.rb | 42 +- spec/requests/oauth/tokens_controller_spec.rb | 7 +- .../product_analytics/collector_app_attack_spec.rb | 41 - .../product_analytics/collector_app_spec.rb | 58 - .../projects/cycle_analytics_events_spec.rb | 4 +- .../google_cloud/deployments_controller_spec.rb | 6 +- .../service_accounts_controller_spec.rb | 2 +- .../projects/issue_links_controller_spec.rb | 20 +- .../merge_requests/context_commit_diffs_spec.rb | 2 +- .../requests/projects/merge_requests/diffs_spec.rb | 18 +- .../projects/ml/experiments_controller_spec.rb | 100 ++ .../settings/access_tokens_controller_spec.rb | 25 +- spec/requests/projects/work_items_spec.rb | 20 +- spec/requests/search_controller_spec.rb | 14 +- spec/requests/self_monitoring_project_spec.rb | 8 +- spec/requests/verifies_with_email_spec.rb | 152 ++- spec/routing/group_routing_spec.rb | 12 +- spec/routing/project_routing_spec.rb | 4 +- spec/rubocop/cop/api/ensure_string_detail_spec.rb | 136 +++ .../cop/gitlab/duplicate_spec_location_spec.rb | 98 -- spec/rubocop/cop/gitlab/json_spec.rb | 45 +- .../cop/gitlab/mark_used_feature_flags_spec.rb | 4 + spec/rubocop/cop/gitlab/rspec/avoid_setup_spec.rb | 36 + spec/rubocop/cop/graphql/enum_names_spec.rb | 52 + spec/rubocop/cop/graphql/enum_values_spec.rb | 79 ++ .../schema_addition_methods_no_post_spec.rb | 24 + spec/rubocop/cop/rake/require_spec.rb | 60 + .../cop/rspec/duplicate_spec_location_spec.rb | 98 ++ .../rspec/factory_bot/strategy_in_callback_spec.rb | 71 ++ spec/rubocop/migration_helpers_spec.rb | 17 + spec/rubocop_spec_helper.rb | 5 +- spec/scripts/failed_tests_spec.rb | 2 +- .../lib/glfm/update_example_snapshots_spec.rb | 57 +- spec/scripts/lib/glfm/update_specification_spec.rb | 240 ++-- ...rify_all_generated_files_are_up_to_date_spec.rb | 9 +- spec/scripts/pipeline_test_report_builder_spec.rb | 2 +- spec/serializers/ci/pipeline_entity_spec.rb | 20 +- .../codequality_degradation_entity_spec.rb | 3 + spec/serializers/diff_file_entity_spec.rb | 44 +- spec/serializers/diffs_entity_spec.rb | 73 +- spec/serializers/diffs_metadata_entity_spec.rb | 53 +- spec/serializers/integrations/event_entity_spec.rb | 1 + spec/serializers/integrations/field_entity_spec.rb | 34 +- spec/serializers/issue_board_entity_spec.rb | 14 +- spec/serializers/issue_entity_spec.rb | 16 +- .../linked_project_issue_entity_spec.rb | 16 +- ...merge_request_poll_cached_widget_entity_spec.rb | 16 - .../merge_request_poll_widget_entity_spec.rb | 6 - .../merge_requests/pipeline_entity_spec.rb | 21 +- spec/serializers/paginated_diff_entity_spec.rb | 76 +- spec/serializers/pipeline_serializer_spec.rb | 3 +- spec/serializers/remote_mirror_entity_spec.rb | 3 +- .../admin/set_feature_flag_service_spec.rb | 9 + .../merge_when_pipeline_succeeds_service_spec.rb | 2 +- spec/services/boards/issues/list_service_spec.rb | 4 +- spec/services/branches/create_service_spec.rb | 23 - .../create_pipeline_trackers_service_spec.rb | 4 + spec/services/ci/after_requeue_job_service_spec.rb | 36 - .../ci/compare_test_reports_service_spec.rb | 2 +- .../create_pipeline_service/partitioning_spec.rb | 5 +- .../ci/create_pipeline_service/rules_spec.rb | 38 + .../ci/create_pipeline_service/variables_spec.rb | 136 +++ spec/services/ci/create_pipeline_service_spec.rb | 47 +- .../ci/job_artifacts/create_service_spec.rb | 6 +- .../ci/job_artifacts/destroy_batch_service_spec.rb | 81 +- .../track_artifact_report_service_spec.rb | 127 +- .../status_collection_spec.rb | 2 +- .../atomic_processing_service_spec.rb | 23 +- ...ne_manual_test_fails_and_retry_manual_build.yml | 54 + ...ds_one_manual_test_fails_and_retry_pipeline.yml | 53 + .../take_ownership_service_spec.rb | 63 + spec/services/ci/play_build_service_spec.rb | 10 +- spec/services/ci/process_build_service_spec.rb | 189 ++- spec/services/ci/register_job_service_spec.rb | 13 +- spec/services/ci/retry_job_service_spec.rb | 284 ++++- spec/services/ci/retry_pipeline_service_spec.rb | 23 +- .../ci/runners/bulk_delete_runners_service_spec.rb | 170 ++- .../set_runner_associated_projects_service_spec.rb | 13 + .../check_ingress_ip_address_service_spec.rb | 44 - .../check_installation_progress_service_spec.rb | 204 ---- .../check_uninstall_progress_service_spec.rb | 155 --- .../check_upgrade_progress_service_spec.rb | 94 -- .../clusters/applications/create_service_spec.rb | 279 ----- .../clusters/applications/patch_service_spec.rb | 80 -- .../applications/prometheus_update_service_spec.rb | 111 -- .../clusters/applications/update_service_spec.rb | 91 -- .../clusters/gcp/provision_service_spec.rb | 2 +- .../gcp/verify_provision_status_service_spec.rb | 10 +- .../configure_istio_ingress_service_spec.rb | 223 ---- ...reate_or_update_service_account_service_spec.rb | 2 +- .../find_cached_manifest_service_spec.rb | 30 +- .../deployments/create_for_build_service_spec.rb | 87 +- .../environments/create_for_build_service_spec.rb | 304 +++++ spec/services/event_create_service_spec.rb | 107 +- spec/services/git/base_hooks_service_spec.rb | 94 +- spec/services/git/tag_push_service_spec.rb | 1 - .../google_cloud/generate_pipeline_service_spec.rb | 11 +- spec/services/groups/create_service_spec.rb | 29 - spec/services/groups/destroy_service_spec.rb | 40 +- spec/services/groups/transfer_service_spec.rb | 4 +- spec/services/groups/update_service_spec.rb | 9 + .../groups/update_shared_runners_service_spec.rb | 2 +- spec/services/import/fogbugz_service_spec.rb | 2 +- .../file_upload_spec.rb | 2 +- .../timeline_event_tags/create_service_spec.rb | 71 ++ .../timeline_events/create_service_spec.rb | 107 ++ .../timeline_events/update_service_spec.rb | 6 + .../issuable/discussions_list_service_spec.rb | 27 + spec/services/issues/close_service_spec.rb | 21 +- spec/services/issues/create_service_spec.rb | 61 +- spec/services/issues/export_csv_service_spec.rb | 2 +- spec/services/issues/move_service_spec.rb | 48 +- .../relative_position_rebalancing_service_spec.rb | 12 +- spec/services/issues/reopen_service_spec.rb | 20 +- spec/services/issues/update_service_spec.rb | 33 +- spec/services/labels/promote_service_spec.rb | 2 +- .../process_deleted_records_service_spec.rb | 198 +++ spec/services/markup/rendering_service_spec.rb | 163 +++ spec/services/members/destroy_service_spec.rb | 25 +- spec/services/members/invite_service_spec.rb | 6 +- spec/services/members/update_service_spec.rb | 356 ++++-- .../merge_requests/approval_service_spec.rb | 32 + spec/services/merge_requests/build_service_spec.rb | 14 +- .../services/merge_requests/create_service_spec.rb | 43 +- .../mergeability/run_checks_service_spec.rb | 22 +- .../mergeability_check_service_spec.rb | 30 - .../merge_requests/remove_approval_service_spec.rb | 16 + .../services/merge_requests/squash_service_spec.rb | 9 +- .../services/merge_requests/update_service_spec.rb | 4 +- spec/services/milestones/transfer_service_spec.rb | 4 +- .../statistics_refresher_service_spec.rb | 19 + spec/services/notes/build_service_spec.rb | 8 +- spec/services/notes/update_service_spec.rb | 2 +- spec/services/notification_service_spec.rb | 17 + .../composer/composer_json_service_spec.rb | 2 +- .../metadata/create_versions_xml_service_spec.rb | 17 + .../packages/npm/create_package_service_spec.rb | 4 +- .../rpm/repository_metadata/base_builder_spec.rb | 33 - .../build_filelist_xml_service_spec.rb | 54 + .../repository_metadata/build_filelist_xml_spec.rb | 21 - .../build_other_xml_service_spec.rb | 27 + .../repository_metadata/build_other_xml_spec.rb | 21 - .../build_primary_xml_service_spec.rb | 23 + .../repository_metadata/build_primary_xml_spec.rb | 35 - .../build_repomd_xml_service_spec.rb | 86 ++ .../repository_metadata/build_repomd_xml_spec.rb | 86 -- .../repository_metadata/update_xml_service_spec.rb | 177 +++ .../migrate_repository_service_spec.rb | 2 - .../lfs_pointers/lfs_download_service_spec.rb | 2 +- .../move_users_star_projects_service_spec.rb | 5 + .../prometheus/alerts/notify_service_spec.rb | 10 +- .../protected_branches/api_service_spec.rb | 34 + .../protected_branches/cache_service_spec.rb | 11 + .../quick_actions/interpret_service_spec.rb | 15 + .../resource_access_tokens/revoke_service_spec.rb | 34 +- .../change_milestone_service_spec.rb | 31 + .../resource_events/change_state_service_spec.rb | 10 +- spec/services/search/group_service_spec.rb | 2 +- spec/services/search_service_spec.rb | 154 +-- .../ci_configuration/sast_parser_service_spec.rb | 8 +- .../security/merge_reports_service_spec.rb | 4 +- .../system_notes/issuables_service_spec.rb | 4 +- spec/services/tags/create_service_spec.rb | 20 + spec/services/todo_service_spec.rb | 2 +- .../todos/destroy/entity_leave_service_spec.rb | 6 +- spec/services/topics/merge_service_spec.rb | 8 +- spec/services/users/approve_service_spec.rb | 2 +- spec/services/users/ban_service_spec.rb | 2 +- spec/services/users/destroy_service_spec.rb | 620 +++------- ...ecords_to_ghost_user_in_batches_service_spec.rb | 29 + .../migrate_records_to_ghost_user_service_spec.rb | 92 +- .../users/migrate_to_ghost_user_service_spec.rb | 97 -- spec/services/users/reject_service_spec.rb | 31 +- spec/services/users/unban_service_spec.rb | 2 +- spec/services/web_hook_service_spec.rb | 43 +- spec/services/work_items/create_service_spec.rb | 10 - spec/services/work_items/update_service_spec.rb | 28 + .../hierarchy_service/update_service_spec.rb | 22 - .../milestone_service/create_service_spec.rb | 28 + .../milestone_service/update_service_spec.rb | 58 + .../x509_certificate_revoke_service_spec.rb | 6 +- spec/spec_helper.rb | 11 +- spec/support/database/multiple_databases.rb | 161 --- spec/support/database/query_recorder.rb | 9 + .../metrics_instrumentation_shared_examples.rb | 4 +- spec/support/google_api/cloud_platform_helpers.rb | 2 +- spec/support/helpers/bare_repo_operations.rb | 44 - spec/support/helpers/ci/template_helpers.rb | 45 + .../helpers/content_security_policy_helpers.rb | 20 +- .../helpers/database/multiple_databases_helpers.rb | 112 ++ .../helpers/features/access_token_helpers.rb | 19 + spec/support/helpers/features/releases_helpers.rb | 2 +- spec/support/helpers/filter_spec_helper.rb | 5 +- spec/support/helpers/filtered_search_helpers.rb | 4 + spec/support/helpers/full_name_helper.rb | 9 + spec/support/helpers/git_helpers.rb | 11 - spec/support/helpers/graphql_helpers.rb | 2 +- spec/support/helpers/kubernetes_helpers.rb | 25 +- spec/support/helpers/navbar_structure_helper.rb | 6 +- spec/support/helpers/reference_parser_helpers.rb | 4 +- spec/support/helpers/search_helpers.rb | 4 +- spec/support/helpers/stub_configuration.rb | 4 + spec/support/helpers/stub_feature_flags.rb | 4 + spec/support/helpers/test_env.rb | 42 +- spec/support/helpers/usage_data_helpers.rb | 12 - spec/support/matchers/exceed_query_limit.rb | 2 +- spec/support/matchers/graphql_matchers.rb | 6 +- spec/support/migration.rb | 36 +- .../ci/partitioning_testing/cascade_check.rb | 27 + .../partitioning_testing/partition_identifiers.rb | 13 + .../models/ci/partitioning_testing/rspec_hooks.rb | 19 + .../ci/partitioning_testing/schema_helpers.rb | 86 ++ spec/support/models/partitionable_check.rb | 46 - spec/support/multiple_databases.rb | 25 + spec/support/rate_limiter.rb | 7 + spec/support/redis.rb | 6 + spec/support/rspec.rb | 3 + spec/support/rspec_order_todo.yml | 27 - .../issuable_update_service_shared_examples.rb | 40 +- ...igrate_to_ghost_user_service_shared_examples.rb | 3 +- .../container_repositories_shared_context.rb | 1 - .../resolvers/runners_resolver_shared_context.rb | 2 +- .../jobs/handling_retried_jobs_shared_context.rb | 26 + .../lib/sbom/package_url_shared_contexts.rb | 26 + .../shared_contexts/navbar_structure_context.rb | 5 +- .../policies/group_policy_shared_context.rb | 1 + .../policies/project_policy_shared_context.rb | 4 +- .../project_policy_table_shared_context.rb | 57 + .../multiple_issue_boards_shared_examples.rb | 2 + .../common/pipelines/wiki_pipeline_examples.rb | 4 +- .../ci/retryable_shared_examples.rb | 16 + .../preferred_language_switcher_shared_examples.rb | 22 + .../features/access_tokens_shared_examples.rb | 34 +- .../features/confidential_notes_shared_examples.rb | 34 + .../features/content_editor_shared_examples.rb | 16 + .../creatable_merge_request_shared_examples.rb | 11 +- .../editable_merge_request_shared_examples.rb | 10 +- .../features/packages_shared_examples.rb | 2 +- .../features/runners_shared_examples.rb | 19 +- .../redacted_search_results_shared_examples.rb | 304 +++++ .../search/search_timeouts_shared_examples.rb | 8 +- .../features/variable_list_shared_examples.rb | 19 +- .../finders/issues_finder_shared_examples.rb | 2 +- .../timeline_events_shared_examples.rb | 10 + .../graphql/notes_creation_shared_examples.rb | 2 +- .../packages_resolvers_shared_examples.rb | 4 +- .../gitlab_style_deprecations_shared_examples.rb | 21 + .../lib/cache_helpers_shared_examples.rb | 1 + .../lib/email/email_shared_examples.rb | 140 +++ ...established_connection_stack_shared_examples.rb | 3 - .../lib/gitlab/event_store_shared_examples.rb | 10 + .../lib/gitlab/experimentation_shared_examples.rb | 22 - .../lib/gitlab/gitaly_client_shared_examples.rb | 46 + .../gitlab/template/template_shared_examples.rb | 2 +- .../lib/sentry/client_shared_examples.rb | 37 +- .../mailers/notify_shared_examples.rb | 4 +- .../active_record_subscriber_shared_examples.rb | 5 +- .../base_slack_notification_shared_examples.rb | 150 +++ .../slack_mattermost_notifier_shared_examples.rb | 34 +- .../models/concerns/limitable_shared_examples.rb | 4 +- .../concerns/ttl_expirable_shared_examples.rb | 7 +- .../models/integrations/base_ci_shared_examples.rb | 7 + .../base_monitoring_shared_examples.rb | 7 + .../base_slash_commands_shared_examples.rb | 4 + .../integrations/has_web_hook_shared_examples.rb | 2 +- .../debian/component_file_shared_example.rb | 2 +- .../shared_examples/models/wiki_shared_examples.rb | 84 +- .../issuable/max_issuable_examples.rb | 75 +- .../access_tokens_controller_shared_examples.rb | 119 +- .../requests/api/discussions_shared_examples.rb | 2 +- .../api/graphql/issuable_search_shared_examples.rb | 8 +- .../api/graphql/issue_list_shared_examples.rb | 170 +++ ...up_and_project_packages_list_shared_examples.rb | 2 +- .../access_level_request_examples.rb | 77 ++ .../requests/api/issues_shared_examples.rb | 2 +- .../requests/api/members_shared_examples.rb | 8 + ...iple_and_scoped_issue_boards_shared_examples.rb | 1 + .../requests/api/notes_shared_examples.rb | 7 +- .../requests/api/pypi_packages_shared_examples.rb | 21 + .../modules/v1/packages_shared_examples.rb | 4 +- .../services/alert_management_shared_examples.rb | 4 +- .../services/base_rpm_service_shared_examples.rb | 52 - .../issuable/discussions_list_shared_examples.rb | 112 ++ ...merge_status_updated_trigger_shared_examples.rb | 17 + ...dismiss_user_callout_service_shared_examples.rb | 2 +- .../widgets/milestone_service_shared_examples.rb | 42 + .../uploaders/object_storage_shared_examples.rb | 5 +- ..._background_migration_worker_shared_examples.rb | 56 +- spec/support/sidekiq_middleware.rb | 9 + spec/support/webmock.rb | 7 + .../database/multiple_databases_helpers_spec.rb | 121 ++ .../database/multiple_databases_spec.rb | 120 -- spec/support_specs/graphql/arguments_spec.rb | 4 +- spec/tasks/gitlab/sidekiq_rake_spec.rb | 42 +- spec/tasks/gitlab/update_templates_rake_spec.rb | 7 +- spec/tooling/danger/project_helper_spec.rb | 6 + spec/tooling/lib/tooling/find_codeowners_spec.rb | 4 +- spec/tooling/lib/tooling/helm3_client_spec.rb | 26 +- spec/tooling/rspec_flaky/example_spec.rb | 9 +- spec/tooling/rspec_flaky/flaky_example_spec.rb | 79 +- .../rspec_flaky/flaky_examples_collection_spec.rb | 3 + spec/tooling/rspec_flaky/listener_spec.rb | 2 + spec/tooling/rspec_flaky/report_spec.rb | 1 + spec/uploaders/job_artifact_uploader_spec.rb | 2 +- .../object_storage/cdn/google_cdn_spec.rb | 46 +- spec/uploaders/object_storage/cdn_spec.rb | 27 +- spec/validators/branch_filter_validator_spec.rb | 44 - .../wildcard_branch_filter_validator_spec.rb | 44 + .../_jira_connect.html.haml_spec.rb | 23 + .../application_settings/general.html.haml_spec.rb | 10 +- spec/views/admin/dashboard/index.html.haml_spec.rb | 2 +- .../confirmations/almost_there.html.haml_spec.rb | 37 + spec/views/events/event/_common.html.haml_spec.rb | 17 +- spec/views/groups/observability.html.haml_spec.rb | 18 - .../observability/observability.html.haml_spec.rb | 18 + .../header/_gitlab_version.html.haml_spec.rb | 17 +- .../layouts/nav/sidebar/_project.html.haml_spec.rb | 18 - .../projects/artifacts/_artifact.html.haml_spec.rb | 85 -- .../projects/commit/_commit_box.html.haml_spec.rb | 2 +- spec/views/projects/commit/show.html.haml_spec.rb | 8 + ...se_reopen_draft_report_toggle.html.haml_spec.rb | 4 +- .../merge_requests/_commits.html.haml_spec.rb | 12 - .../creations/_new_submit.html.haml_spec.rb | 13 - .../projects/merge_requests/edit.html.haml_spec.rb | 4 +- spec/views/search/show.html.haml_spec.rb | 10 +- .../shared/access_tokens/_table.html.haml_spec.rb | 151 --- .../shared/deploy_tokens/_form.html.haml_spec.rb | 62 - .../shared/issuable/_sidebar.html.haml_spec.rb | 6 +- spec/workers/bulk_imports/entity_worker_spec.rb | 25 +- .../bulk_imports/export_request_worker_spec.rb | 95 +- spec/workers/bulk_imports/pipeline_worker_spec.rb | 54 +- .../track_artifact_report_worker_spec.rb | 23 +- .../workers/cluster_configure_istio_worker_spec.rb | 41 - spec/workers/cluster_update_app_worker_spec.rb | 112 -- .../cluster_wait_for_app_update_worker_spec.rb | 27 - ...ster_wait_for_ingress_ip_address_worker_spec.rb | 32 - .../wait_for_uninstall_app_worker_spec.rb | 32 - spec/workers/concerns/reenqueuer_spec.rb | 21 +- .../container_registry/cleanup_worker_spec.rb | 81 ++ .../delete_container_repository_worker_spec.rb | 146 +++ .../execution_worker_spec.rb | 141 +++ spec/workers/every_sidekiq_worker_spec.rb | 5 + .../import_review_request_worker_spec.rb | 46 + .../import_pull_requests_merged_by_worker_spec.rb | 2 +- ...rt_pull_requests_review_requests_worker_spec.rb | 31 + .../import_pull_requests_reviews_worker_spec.rb | 3 +- spec/workers/gitlab_shell_worker_spec.rb | 50 +- .../add_severity_system_note_worker_spec.rb | 25 +- .../loose_foreign_keys/cleanup_worker_spec.rb | 36 +- .../notification_service_worker_spec.rb | 39 +- .../merge_requests/delete_branch_worker_spec.rb | 65 + .../delete_source_branch_worker_spec.rb | 120 +- .../namespaces/root_statistics_worker_spec.rb | 13 + .../pages/invalidate_domain_cache_worker_spec.rb | 61 +- spec/workers/pages_worker_spec.rb | 24 +- spec/workers/projects/after_import_worker_spec.rb | 2 - spec/workers/projects/post_creation_worker_spec.rb | 34 + spec/workers/remove_expired_members_worker_spec.rb | 26 +- .../single_repository_worker_spec.rb | 62 +- spec/workers/repository_import_worker_spec.rb | 32 +- spec/workers/run_pipeline_schedule_worker_spec.rb | 53 +- ...records_to_ghost_user_in_batches_worker_spec.rb | 12 - 1724 files changed, 51466 insertions(+), 32516 deletions(-) create mode 100644 spec/bin/audit_event_type_spec.rb delete mode 100644 spec/config/metrics/aggregates/aggregated_metrics_spec.rb create mode 100644 spec/contracts/provider/helpers/publish_contract_helper.rb create mode 100644 spec/contracts/publish-contracts.sh create mode 100644 spec/controllers/concerns/preferred_language_switcher_spec.rb delete mode 100644 spec/controllers/projects/product_analytics_controller_spec.rb delete mode 100644 spec/factories/experiment_subjects.rb delete mode 100644 spec/factories/experiment_users.rb delete mode 100644 spec/factories/experiments.rb create mode 100644 spec/factories/merge_request_reviewers.rb delete mode 100644 spec/factories/projects/import_export/export_relation.rb create mode 100644 spec/factories/projects/import_export/relation_export.rb create mode 100644 spec/factories/projects/import_export/relation_export_upload.rb create mode 100644 spec/factories/projects/wiki_repositories.rb create mode 100644 spec/factories/users/namespace_commit_emails.rb create mode 100644 spec/features/issues/confidential_notes_spec.rb create mode 100644 spec/features/merge_request/user_sees_discussions_navigation_spec.rb delete mode 100644 spec/features/projects/product_analytics/events_spec.rb delete mode 100644 spec/features/projects/product_analytics/graphs_spec.rb delete mode 100644 spec/features/projects/product_analytics/setup_spec.rb delete mode 100644 spec/features/projects/product_analytics/test_spec.rb create mode 100644 spec/features/projects/settings/branch_names_settings_spec.rb create mode 100644 spec/finders/clusters/agent_tokens_finder_spec.rb create mode 100644 spec/finders/incident_management/timeline_event_tags_finder_spec.rb create mode 100644 spec/fixtures/api/schemas/entities/protected_ref_access.json create mode 100644 spec/fixtures/api/schemas/project_mirror.json create mode 100644 spec/fixtures/api/schemas/protected_branch.json create mode 100644 spec/fixtures/api/schemas/protected_branches.json create mode 100644 spec/fixtures/api/schemas/protected_tag.json create mode 100644 spec/fixtures/api/schemas/protected_tags.json create mode 100644 spec/fixtures/gitlab/import_export/project.tar.gz create mode 100644 spec/fixtures/gitlab/import_export/uploads.tar.gz create mode 100644 spec/fixtures/lib/sbom/package-url-test-cases.json create mode 100644 spec/fixtures/packages/rpm/repodata/364c77dd49e8f814d56e621d0b3306c4fd0696dcad506f527329b818eb0f5db3-repomd.xml delete mode 100644 spec/fixtures/packages/rpm/repodata/repomd.xml create mode 100644 spec/frontend/__helpers__/raw_transformer.js create mode 100644 spec/frontend/admin/users/components/actions/delete_with_contributions_spec.js create mode 100644 spec/frontend/admin/users/components/associations/__snapshots__/associations_list_item_spec.js.snap create mode 100644 spec/frontend/admin/users/components/associations/__snapshots__/associations_list_spec.js.snap create mode 100644 spec/frontend/admin/users/components/associations/associations_list_item_spec.js create mode 100644 spec/frontend/admin/users/components/associations/associations_list_spec.js create mode 100644 spec/frontend/artifacts/components/artifact_row_spec.js create mode 100644 spec/frontend/artifacts/components/artifacts_table_row_details_spec.js create mode 100644 spec/frontend/artifacts/components/job_artifacts_table_spec.js create mode 100644 spec/frontend/artifacts/graphql/cache_update_spec.js delete mode 100644 spec/frontend/blob/components/__snapshots__/blob_edit_content_spec.js.snap delete mode 100644 spec/frontend/blob/components/blob_edit_content_spec.js create mode 100644 spec/frontend/branches/components/__snapshots__/delete_merged_branches_spec.js.snap create mode 100644 spec/frontend/branches/components/delete_merged_branches_spec.js create mode 100644 spec/frontend/branches/mock_data.js create mode 100644 spec/frontend/ci/pipeline_schedules/components/delete_pipeline_schedule_modal_spec.js create mode 100644 spec/frontend/ci/pipeline_schedules/components/pipeline_schedules_form_spec.js create mode 100644 spec/frontend/ci/pipeline_schedules/components/pipeline_schedules_spec.js create mode 100644 spec/frontend/ci/pipeline_schedules/components/table/cells/pipeline_schedule_actions_spec.js create mode 100644 spec/frontend/ci/pipeline_schedules/components/table/cells/pipeline_schedule_last_pipeline_spec.js create mode 100644 spec/frontend/ci/pipeline_schedules/components/table/cells/pipeline_schedule_next_run_spec.js create mode 100644 spec/frontend/ci/pipeline_schedules/components/table/cells/pipeline_schedule_owner_spec.js create mode 100644 spec/frontend/ci/pipeline_schedules/components/table/cells/pipeline_schedule_target_spec.js create mode 100644 spec/frontend/ci/pipeline_schedules/components/table/pipeline_schedules_table_spec.js create mode 100644 spec/frontend/ci/pipeline_schedules/components/take_ownership_modal_legacy_spec.js create mode 100644 spec/frontend/ci/pipeline_schedules/components/take_ownership_modal_spec.js create mode 100644 spec/frontend/ci/pipeline_schedules/mock_data.js create mode 100644 spec/frontend/ci/runner/admin_runner_show/admin_runner_show_app_spec.js create mode 100644 spec/frontend/ci/runner/admin_runners/admin_runners_app_spec.js create mode 100644 spec/frontend/ci/runner/components/__snapshots__/runner_status_popover_spec.js.snap create mode 100644 spec/frontend/ci/runner/components/cells/link_cell_spec.js create mode 100644 spec/frontend/ci/runner/components/cells/runner_actions_cell_spec.js create mode 100644 spec/frontend/ci/runner/components/cells/runner_owner_cell_spec.js create mode 100644 spec/frontend/ci/runner/components/cells/runner_stacked_summary_cell_spec.js create mode 100644 spec/frontend/ci/runner/components/cells/runner_status_cell_spec.js create mode 100644 spec/frontend/ci/runner/components/cells/runner_summary_field_spec.js create mode 100644 spec/frontend/ci/runner/components/registration/registration_dropdown_spec.js create mode 100644 spec/frontend/ci/runner/components/registration/registration_token_reset_dropdown_item_spec.js create mode 100644 spec/frontend/ci/runner/components/registration/registration_token_spec.js create mode 100644 spec/frontend/ci/runner/components/runner_assigned_item_spec.js create mode 100644 spec/frontend/ci/runner/components/runner_bulk_delete_checkbox_spec.js create mode 100644 spec/frontend/ci/runner/components/runner_bulk_delete_spec.js create mode 100644 spec/frontend/ci/runner/components/runner_delete_button_spec.js create mode 100644 spec/frontend/ci/runner/components/runner_delete_modal_spec.js create mode 100644 spec/frontend/ci/runner/components/runner_details_spec.js create mode 100644 spec/frontend/ci/runner/components/runner_edit_button_spec.js create mode 100644 spec/frontend/ci/runner/components/runner_filtered_search_bar_spec.js create mode 100644 spec/frontend/ci/runner/components/runner_groups_spec.js create mode 100644 spec/frontend/ci/runner/components/runner_header_spec.js create mode 100644 spec/frontend/ci/runner/components/runner_jobs_spec.js create mode 100644 spec/frontend/ci/runner/components/runner_jobs_table_spec.js create mode 100644 spec/frontend/ci/runner/components/runner_list_empty_state_spec.js create mode 100644 spec/frontend/ci/runner/components/runner_list_spec.js create mode 100644 spec/frontend/ci/runner/components/runner_membership_toggle_spec.js create mode 100644 spec/frontend/ci/runner/components/runner_pagination_spec.js create mode 100644 spec/frontend/ci/runner/components/runner_pause_button_spec.js create mode 100644 spec/frontend/ci/runner/components/runner_paused_badge_spec.js create mode 100644 spec/frontend/ci/runner/components/runner_projects_spec.js create mode 100644 spec/frontend/ci/runner/components/runner_status_badge_spec.js create mode 100644 spec/frontend/ci/runner/components/runner_status_popover_spec.js create mode 100644 spec/frontend/ci/runner/components/runner_tag_spec.js create mode 100644 spec/frontend/ci/runner/components/runner_tags_spec.js create mode 100644 spec/frontend/ci/runner/components/runner_type_badge_spec.js create mode 100644 spec/frontend/ci/runner/components/runner_type_tabs_spec.js create mode 100644 spec/frontend/ci/runner/components/runner_update_form_spec.js create mode 100644 spec/frontend/ci/runner/components/search_tokens/tag_token_spec.js create mode 100644 spec/frontend/ci/runner/components/stat/runner_count_spec.js create mode 100644 spec/frontend/ci/runner/components/stat/runner_single_stat_spec.js create mode 100644 spec/frontend/ci/runner/components/stat/runner_stats_spec.js create mode 100644 spec/frontend/ci/runner/graphql/local_state_spec.js create mode 100644 spec/frontend/ci/runner/group_runner_show/group_runner_show_app_spec.js create mode 100644 spec/frontend/ci/runner/group_runners/group_runners_app_spec.js create mode 100644 spec/frontend/ci/runner/local_storage_alert/save_alert_to_local_storage_spec.js create mode 100644 spec/frontend/ci/runner/local_storage_alert/show_alert_from_local_storage_spec.js create mode 100644 spec/frontend/ci/runner/mock_data.js create mode 100644 spec/frontend/ci/runner/runner_edit/runner_edit_app_spec.js create mode 100644 spec/frontend/ci/runner/runner_search_utils_spec.js create mode 100644 spec/frontend/ci/runner/runner_update_form_utils_spec.js create mode 100644 spec/frontend/ci/runner/sentry_utils_spec.js create mode 100644 spec/frontend/ci/runner/utils_spec.js delete mode 100644 spec/frontend/ci_variable_list/components/ci_variable_popover_spec.js create mode 100644 spec/frontend/ci_variable_list/components/ci_variable_shared_spec.js delete mode 100644 spec/frontend/ci_variable_list/components/legacy_ci_environments_dropdown_spec.js delete mode 100644 spec/frontend/ci_variable_list/components/legacy_ci_variable_modal_spec.js delete mode 100644 spec/frontend/ci_variable_list/components/legacy_ci_variable_settings_spec.js delete mode 100644 spec/frontend/ci_variable_list/components/legacy_ci_variable_table_spec.js delete mode 100644 spec/frontend/ci_variable_list/store/actions_spec.js delete mode 100644 spec/frontend/ci_variable_list/store/getters_spec.js delete mode 100644 spec/frontend/ci_variable_list/store/mutations_spec.js delete mode 100644 spec/frontend/ci_variable_list/store/utils_spec.js create mode 100644 spec/frontend/editor/schema/ci/json_tests/negative_tests/release_assets_links.json delete mode 100644 spec/frontend/editor/schema/ci/json_tests/negative_tests/release_assets_links_empty.json delete mode 100644 spec/frontend/editor/schema/ci/json_tests/negative_tests/release_assets_links_invalid_link_type.json delete mode 100644 spec/frontend/editor/schema/ci/json_tests/negative_tests/release_assets_links_missing.json create mode 100644 spec/frontend/editor/schema/ci/yaml_tests/negative_tests/job_when.yml delete mode 100644 spec/frontend/editor/schema/ci/yaml_tests/negative_tests/project_path/trigger/include/empty.yml delete mode 100644 spec/frontend/editor/schema/ci/yaml_tests/negative_tests/project_path/trigger/include/invalid_variable.yml delete mode 100644 spec/frontend/editor/schema/ci/yaml_tests/negative_tests/project_path/trigger/include/leading_slash.yml delete mode 100644 spec/frontend/editor/schema/ci/yaml_tests/negative_tests/project_path/trigger/include/no_slash.yml delete mode 100644 spec/frontend/editor/schema/ci/yaml_tests/negative_tests/project_path/trigger/include/tailing_slash.yml delete mode 100644 spec/frontend/editor/schema/ci/yaml_tests/negative_tests/project_path/trigger/minimal/empty.yml delete mode 100644 spec/frontend/editor/schema/ci/yaml_tests/negative_tests/project_path/trigger/minimal/invalid_variable.yml delete mode 100644 spec/frontend/editor/schema/ci/yaml_tests/negative_tests/project_path/trigger/minimal/leading_slash.yml delete mode 100644 spec/frontend/editor/schema/ci/yaml_tests/negative_tests/project_path/trigger/minimal/no_slash.yml delete mode 100644 spec/frontend/editor/schema/ci/yaml_tests/negative_tests/project_path/trigger/minimal/tailing_slash.yml delete mode 100644 spec/frontend/editor/schema/ci/yaml_tests/negative_tests/project_path/trigger/project/empty.yml delete mode 100644 spec/frontend/editor/schema/ci/yaml_tests/negative_tests/project_path/trigger/project/invalid_variable.yml delete mode 100644 spec/frontend/editor/schema/ci/yaml_tests/negative_tests/project_path/trigger/project/leading_slash.yml delete mode 100644 spec/frontend/editor/schema/ci/yaml_tests/negative_tests/project_path/trigger/project/no_slash.yml delete mode 100644 spec/frontend/editor/schema/ci/yaml_tests/negative_tests/project_path/trigger/project/tailing_slash.yml create mode 100644 spec/frontend/editor/schema/ci/yaml_tests/negative_tests/trigger.yml delete mode 100644 spec/frontend/editor/schema/ci/yaml_tests/negative_tests/variables.yml create mode 100644 spec/frontend/editor/schema/ci/yaml_tests/negative_tests/variables/invalid_syntax_desc.yml create mode 100644 spec/frontend/editor/schema/ci/yaml_tests/negative_tests/variables/wrong_syntax_usage_expand.yml create mode 100644 spec/frontend/editor/schema/ci/yaml_tests/positive_tests/job_when.yml create mode 100644 spec/frontend/fixtures/job_artifacts.rb create mode 100644 spec/frontend/gitlab_version_check/components/gitlab_version_check_badge_spec.js create mode 100644 spec/frontend/gitlab_version_check/index_spec.js create mode 100644 spec/frontend/groups_projects/components/transfer_locations_spec.js create mode 100644 spec/frontend/ide/components/switch_editors/switch_editors_view_spec.js create mode 100644 spec/frontend/issuable/bulk_update_sidebar/components/move_issues_button_spec.js create mode 100644 spec/frontend/issues/dashboard/components/issues_dashboard_app_spec.js create mode 100644 spec/frontend/lib/utils/confirm_via_gl_modal/confirm_action_spec.js create mode 100644 spec/frontend/lib/utils/confirm_via_gl_modal/confirm_via_gl_modal_spec.js create mode 100644 spec/frontend/ml/experiment_tracking/components/__snapshots__/experiment_spec.js.snap create mode 100644 spec/frontend/ml/experiment_tracking/components/experiment_spec.js create mode 100644 spec/frontend/ml/experiment_tracking/components/incubation_alert_spec.js create mode 100644 spec/frontend/notebook/cells/output/markdown_spec.js create mode 100644 spec/frontend/notebook/mock_data.js create mode 100644 spec/frontend/observability/observability_app_spec.js create mode 100644 spec/frontend/packages_and_registries/package_registry/components/delete_modal_spec.js create mode 100644 spec/frontend/packages_and_registries/package_registry/components/details/package_versions_list_spec.js create mode 100644 spec/frontend/packages_and_registries/settings/group/components/forwarding_settings_spec.js create mode 100644 spec/frontend/packages_and_registries/settings/group/components/packages_forwarding_settings_spec.js create mode 100644 spec/frontend/packages_and_registries/shared/components/delete_package_modal_spec.js delete mode 100644 spec/frontend/pipeline_schedules/components/pipeline_schedules_form_spec.js delete mode 100644 spec/frontend/pipeline_schedules/components/pipeline_schedules_spec.js delete mode 100644 spec/frontend/pipeline_schedules/components/table/cells/pipeline_schedule_actions_spec.js delete mode 100644 spec/frontend/pipeline_schedules/components/table/cells/pipeline_schedule_last_pipeline_spec.js delete mode 100644 spec/frontend/pipeline_schedules/components/table/cells/pipeline_schedule_next_run_spec.js delete mode 100644 spec/frontend/pipeline_schedules/components/table/cells/pipeline_schedule_owner_spec.js delete mode 100644 spec/frontend/pipeline_schedules/components/table/cells/pipeline_schedule_target_spec.js delete mode 100644 spec/frontend/pipeline_schedules/components/table/pipeline_schedules_table_spec.js delete mode 100644 spec/frontend/pipeline_schedules/components/take_ownership_modal_spec.js delete mode 100644 spec/frontend/pipeline_schedules/mock_data.js delete mode 100644 spec/frontend/reports/codequality_report/grouped_codequality_reports_app_spec.js delete mode 100644 spec/frontend/reports/grouped_test_report/components/modal_spec.js delete mode 100644 spec/frontend/reports/grouped_test_report/components/test_issue_body_spec.js delete mode 100644 spec/frontend/reports/grouped_test_report/grouped_test_reports_app_spec.js delete mode 100644 spec/frontend/reports/grouped_test_report/store/actions_spec.js delete mode 100644 spec/frontend/reports/grouped_test_report/store/mutations_spec.js delete mode 100644 spec/frontend/reports/grouped_test_report/store/utils_spec.js delete mode 100644 spec/frontend/runner/admin_runner_show/admin_runner_show_app_spec.js delete mode 100644 spec/frontend/runner/admin_runners/admin_runners_app_spec.js delete mode 100644 spec/frontend/runner/components/__snapshots__/runner_status_popover_spec.js.snap delete mode 100644 spec/frontend/runner/components/cells/link_cell_spec.js delete mode 100644 spec/frontend/runner/components/cells/runner_actions_cell_spec.js delete mode 100644 spec/frontend/runner/components/cells/runner_owner_cell_spec.js delete mode 100644 spec/frontend/runner/components/cells/runner_stacked_summary_cell_spec.js delete mode 100644 spec/frontend/runner/components/cells/runner_status_cell_spec.js delete mode 100644 spec/frontend/runner/components/cells/runner_summary_field_spec.js delete mode 100644 spec/frontend/runner/components/registration/registration_dropdown_spec.js delete mode 100644 spec/frontend/runner/components/registration/registration_token_reset_dropdown_item_spec.js delete mode 100644 spec/frontend/runner/components/registration/registration_token_spec.js delete mode 100644 spec/frontend/runner/components/runner_assigned_item_spec.js delete mode 100644 spec/frontend/runner/components/runner_bulk_delete_checkbox_spec.js delete mode 100644 spec/frontend/runner/components/runner_bulk_delete_spec.js delete mode 100644 spec/frontend/runner/components/runner_delete_button_spec.js delete mode 100644 spec/frontend/runner/components/runner_delete_modal_spec.js delete mode 100644 spec/frontend/runner/components/runner_details_spec.js delete mode 100644 spec/frontend/runner/components/runner_edit_button_spec.js delete mode 100644 spec/frontend/runner/components/runner_filtered_search_bar_spec.js delete mode 100644 spec/frontend/runner/components/runner_groups_spec.js delete mode 100644 spec/frontend/runner/components/runner_header_spec.js delete mode 100644 spec/frontend/runner/components/runner_jobs_spec.js delete mode 100644 spec/frontend/runner/components/runner_jobs_table_spec.js delete mode 100644 spec/frontend/runner/components/runner_list_empty_state_spec.js delete mode 100644 spec/frontend/runner/components/runner_list_spec.js delete mode 100644 spec/frontend/runner/components/runner_membership_toggle_spec.js delete mode 100644 spec/frontend/runner/components/runner_pagination_spec.js delete mode 100644 spec/frontend/runner/components/runner_pause_button_spec.js delete mode 100644 spec/frontend/runner/components/runner_paused_badge_spec.js delete mode 100644 spec/frontend/runner/components/runner_projects_spec.js delete mode 100644 spec/frontend/runner/components/runner_stacked_layout_banner_spec.js delete mode 100644 spec/frontend/runner/components/runner_status_badge_spec.js delete mode 100644 spec/frontend/runner/components/runner_status_popover_spec.js delete mode 100644 spec/frontend/runner/components/runner_tag_spec.js delete mode 100644 spec/frontend/runner/components/runner_tags_spec.js delete mode 100644 spec/frontend/runner/components/runner_type_badge_spec.js delete mode 100644 spec/frontend/runner/components/runner_type_tabs_spec.js delete mode 100644 spec/frontend/runner/components/runner_update_form_spec.js delete mode 100644 spec/frontend/runner/components/search_tokens/tag_token_spec.js delete mode 100644 spec/frontend/runner/components/stat/runner_count_spec.js delete mode 100644 spec/frontend/runner/components/stat/runner_single_stat_spec.js delete mode 100644 spec/frontend/runner/components/stat/runner_stats_spec.js delete mode 100644 spec/frontend/runner/graphql/local_state_spec.js delete mode 100644 spec/frontend/runner/group_runner_show/group_runner_show_app_spec.js delete mode 100644 spec/frontend/runner/group_runners/group_runners_app_spec.js delete mode 100644 spec/frontend/runner/local_storage_alert/save_alert_to_local_storage_spec.js delete mode 100644 spec/frontend/runner/local_storage_alert/show_alert_from_local_storage_spec.js delete mode 100644 spec/frontend/runner/mock_data.js delete mode 100644 spec/frontend/runner/runner_edit/runner_edit_app_spec.js delete mode 100644 spec/frontend/runner/runner_search_utils_spec.js delete mode 100644 spec/frontend/runner/runner_update_form_utils_spec.js delete mode 100644 spec/frontend/runner/sentry_utils_spec.js delete mode 100644 spec/frontend/runner/utils_spec.js create mode 100644 spec/frontend/search/sidebar/components/filters_spec.js create mode 100644 spec/frontend/search/sidebar/components/scope_navigation_spec.js create mode 100644 spec/frontend/sidebar/components/milestone/milestone_dropdown_spec.js create mode 100644 spec/frontend/sidebar/components/reviewers/sidebar_reviewers_inputs_spec.js create mode 100644 spec/frontend/sidebar/components/sidebar_dropdown_spec.js create mode 100644 spec/frontend/vue_merge_request_widget/deployment/deployment_info_spec.js create mode 100644 spec/frontend/vue_shared/alert_details/router_spec.js delete mode 100644 spec/frontend/vue_shared/components/gitlab_version_check_spec.js create mode 100644 spec/frontend/vue_shared/components/group_select/group_select_spec.js create mode 100644 spec/frontend/vue_shared/components/markdown_drawer/markdown_drawer_spec.js create mode 100644 spec/frontend/vue_shared/components/markdown_drawer/mock_data.js create mode 100644 spec/frontend/vue_shared/components/markdown_drawer/utils/fetch_spec.js delete mode 100644 spec/frontend/vue_shared/components/namespace_select/mock_data.js delete mode 100644 spec/frontend/vue_shared/components/namespace_select/namespace_select_deprecated_spec.js create mode 100644 spec/frontend/vue_shared/components/source_viewer/plugins/utils/composer_json_linker_spec.js create mode 100644 spec/frontend/vue_shared/components/source_viewer/plugins/utils/gemfile_linker_spec.js create mode 100644 spec/frontend/vue_shared/components/source_viewer/plugins/utils/godeps_json_linker_spec.js create mode 100644 spec/frontend/vue_shared/components/source_viewer/plugins/utils/podspec_json_linker_spec.js create mode 100644 spec/frontend/webhooks/components/__snapshots__/push_events_spec.js.snap create mode 100644 spec/frontend/webhooks/components/push_events_spec.js create mode 100644 spec/frontend/work_items/components/work_item_description_rendered_spec.js create mode 100644 spec/graphql/mutations/incident_management/timeline_event_tag/create_spec.rb create mode 100644 spec/graphql/resolvers/incident_management/timeline_event_tags_resolver_spec.rb delete mode 100644 spec/graphql/resolvers/issues_resolver_spec.rb create mode 100644 spec/graphql/resolvers/project_issues_resolver_spec.rb create mode 100644 spec/graphql/types/commit_signature_interface_spec.rb create mode 100644 spec/graphql/types/commit_signatures/gpg_signature_type_spec.rb create mode 100644 spec/graphql/types/commit_signatures/verification_status_enum_spec.rb create mode 100644 spec/graphql/types/commit_signatures/x509_signature_type_spec.rb create mode 100644 spec/graphql/types/incident_management/timeline_event_tag_type_spec.rb create mode 100644 spec/graphql/types/projects/repository_language_type_spec.rb create mode 100644 spec/graphql/types/x509_certificate_type_spec.rb create mode 100644 spec/graphql/types/x509_issuer_type_spec.rb create mode 100644 spec/helpers/groups/observability_helper_spec.rb create mode 100644 spec/helpers/json_helper_spec.rb create mode 100644 spec/helpers/projects/ml/experiments_helper_spec.rb create mode 100644 spec/helpers/routing/packages_helper_spec.rb create mode 100644 spec/initializers/hashie_mash_permitted_patch_spec.rb create mode 100644 spec/lib/api/entities/user_counts_spec.rb create mode 100644 spec/lib/bulk_imports/projects/pipelines/references_pipeline_spec.rb create mode 100644 spec/lib/gitlab/background_migration/backfill_project_namespace_details_spec.rb delete mode 100644 spec/lib/gitlab/background_migration/backfill_projects_with_coverage_spec.rb create mode 100644 spec/lib/gitlab/background_migration/backfill_user_details_fields_spec.rb create mode 100644 spec/lib/gitlab/background_migration/populate_projects_star_count_spec.rb delete mode 100644 spec/lib/gitlab/background_migration/reset_duplicate_ci_runners_token_encrypted_values_spec.rb delete mode 100644 spec/lib/gitlab/background_migration/reset_duplicate_ci_runners_token_values_spec.rb create mode 100644 spec/lib/gitlab/background_migration/sanitize_confidential_todos_spec.rb create mode 100644 spec/lib/gitlab/cache/metrics_spec.rb create mode 100644 spec/lib/gitlab/ci/pipeline/chain/populate_metadata_spec.rb delete mode 100644 spec/lib/gitlab/ci/pipeline/seed/deployment_spec.rb delete mode 100644 spec/lib/gitlab/ci/pipeline/seed/environment_spec.rb create mode 100644 spec/lib/gitlab/cluster/puma_worker_killer_initializer_spec.rb create mode 100644 spec/lib/gitlab/database/load_balancing/service_discovery/sampler_spec.rb create mode 100644 spec/lib/gitlab/database/migrations/constraints_helpers_spec.rb create mode 100644 spec/lib/gitlab/database/migrations/extension_helpers_spec.rb create mode 100644 spec/lib/gitlab/database/migrations/lock_retries_helpers_spec.rb create mode 100644 spec/lib/gitlab/database/migrations/timeout_helpers_spec.rb delete mode 100644 spec/lib/gitlab/database/query_analyzers/ci/partitioning_analyzer_spec.rb create mode 100644 spec/lib/gitlab/database/query_analyzers/ci/partitioning_id_analyzer_spec.rb create mode 100644 spec/lib/gitlab/database/query_analyzers/ci/partitioning_routing_analyzer_spec.rb create mode 100644 spec/lib/gitlab/database/query_analyzers/query_recorder_spec.rb create mode 100644 spec/lib/gitlab/database/type/symbolized_jsonb_spec.rb delete mode 100644 spec/lib/gitlab/experimentation/group_types_spec.rb create mode 100644 spec/lib/gitlab/gitaly_client/with_feature_flag_actors_spec.rb create mode 100644 spec/lib/gitlab/github_import/importer/pull_requests/review_request_importer_spec.rb create mode 100644 spec/lib/gitlab/github_import/importer/pull_requests/review_requests_importer_spec.rb create mode 100644 spec/lib/gitlab/github_import/representation/pull_requests/review_requests_spec.rb create mode 100644 spec/lib/gitlab/grape_logging/loggers/filter_parameters_spec.rb create mode 100644 spec/lib/gitlab/import_export/project/exported_relations_merger_spec.rb create mode 100644 spec/lib/gitlab/import_export/recursive_merge_folders_spec.rb create mode 100644 spec/lib/gitlab/memory/watchdog/configurator_spec.rb create mode 100644 spec/lib/gitlab/memory/watchdog/monitor/rss_memory_limit_spec.rb create mode 100644 spec/lib/gitlab/metrics/loose_foreign_keys_slis_spec.rb create mode 100644 spec/lib/gitlab/observability_spec.rb create mode 100644 spec/lib/gitlab/pagination_delegate_spec.rb create mode 100644 spec/lib/gitlab/qa_spec.rb create mode 100644 spec/lib/gitlab/slash_commands/presenters/incident_management/incident_new_spec.rb create mode 100644 spec/lib/gitlab/tracking/helpers/weak_password_error_event_spec.rb create mode 100644 spec/lib/gitlab/usage/metrics/instrumentations/count_merge_request_authors_metric_spec.rb delete mode 100644 spec/lib/gitlab/usage/metrics/instrumentations/distinct_count_projects_with_expiration_policy_disabled_metric_spec.rb create mode 100644 spec/lib/gitlab/usage/metrics/instrumentations/distinct_count_projects_with_expiration_policy_metric_spec.rb create mode 100644 spec/lib/gitlab/usage/metrics/instrumentations/dormant_user_period_setting_metric_spec.rb create mode 100644 spec/lib/gitlab/usage/metrics/instrumentations/dormant_user_setting_enabled_metric_spec.rb create mode 100644 spec/lib/gitlab/usage/metrics/instrumentations/in_product_marketing_email_cta_clicked_metric_spec.rb create mode 100644 spec/lib/gitlab/usage/metrics/instrumentations/in_product_marketing_email_sent_metric_spec.rb delete mode 100644 spec/lib/gitlab/usage/metrics/names_suggestions/relation_parsers/constraints_spec.rb create mode 100644 spec/lib/gitlab/usage/metrics/names_suggestions/relation_parsers/having_constraints_spec.rb create mode 100644 spec/lib/gitlab/usage/metrics/names_suggestions/relation_parsers/where_constraints_spec.rb create mode 100644 spec/lib/sbom/package_url/argument_validator_spec.rb create mode 100644 spec/lib/sbom/package_url/decoder_spec.rb create mode 100644 spec/lib/sbom/package_url/encoder_spec.rb create mode 100644 spec/lib/sbom/package_url/normalizer_spec.rb create mode 100644 spec/lib/sbom/package_url_spec.rb delete mode 100644 spec/lib/serializers/symbolized_json_spec.rb create mode 100644 spec/mailers/emails/identity_verification_spec.rb delete mode 100644 spec/migrations/20210818185845_backfill_projects_with_coverage_spec.rb create mode 100644 spec/migrations/20221018050323_add_objective_and_keyresult_to_work_item_types_spec.rb create mode 100644 spec/migrations/20221018062308_schedule_backfill_project_namespace_details_spec.rb create mode 100644 spec/migrations/20221018193635_ensure_task_note_renaming_background_migration_finished_spec.rb create mode 100644 spec/migrations/20221021145820_create_routing_table_for_builds_metadata_v2_spec.rb create mode 100644 spec/migrations/20221025043930_change_default_value_on_password_last_changed_at_to_user_details_spec.rb create mode 100644 spec/migrations/20221028022627_add_index_on_password_last_changed_at_to_user_details_spec.rb create mode 100644 spec/migrations/20221101032521_add_default_preferred_language_to_application_settings_spec.rb create mode 100644 spec/migrations/20221101032600_add_text_limit_to_default_preferred_language_on_application_settings_spec.rb create mode 100644 spec/migrations/20221102090940_create_next_ci_partitions_record_spec.rb create mode 100644 spec/migrations/20221102090943_create_second_partition_for_builds_metadata_spec.rb create mode 100644 spec/migrations/cleanup_vulnerability_state_transitions_with_same_from_state_to_state_spec.rb create mode 100644 spec/migrations/delete_migrate_shared_vulnerability_scanners_spec.rb create mode 100644 spec/migrations/finalize_invalid_member_cleanup_spec.rb create mode 100644 spec/migrations/queue_backfill_user_details_fields_spec.rb create mode 100644 spec/migrations/queue_populate_projects_star_count_spec.rb create mode 100644 spec/migrations/recount_epic_cache_counts_spec.rb create mode 100644 spec/migrations/reschedule_migrate_shared_vulnerability_scanners_spec.rb create mode 100644 spec/migrations/sanitize_confidential_note_todos_spec.rb delete mode 100644 spec/migrations/schedule_migrate_shared_vulnerability_scanners_spec.rb create mode 100644 spec/migrations/set_email_confirmation_setting_from_send_user_confirmation_email_setting_spec.rb create mode 100644 spec/migrations/sync_new_amount_used_for_ci_namespace_monthly_usages_spec.rb create mode 100644 spec/migrations/sync_new_amount_used_for_ci_project_monthly_usages_spec.rb create mode 100644 spec/models/concerns/ci/partitionable/switch_spec.rb create mode 100644 spec/models/concerns/encrypted_user_password_spec.rb create mode 100644 spec/models/concerns/file_store_mounter_spec.rb create mode 100644 spec/models/concerns/subquery_spec.rb delete mode 100644 spec/models/experiment_spec.rb delete mode 100644 spec/models/experiment_subject_spec.rb delete mode 100644 spec/models/experiment_user_spec.rb create mode 100644 spec/models/projects/wiki_repository_spec.rb create mode 100644 spec/models/users/namespace_commit_email_spec.rb create mode 100644 spec/models/work_items/widgets/milestone_spec.rb create mode 100644 spec/requests/api/graphql/issues_spec.rb create mode 100644 spec/requests/api/graphql/mutations/ci/pipeline_schedule_take_ownership_spec.rb create mode 100644 spec/requests/api/graphql/mutations/incident_management/timeline_event_tag/create_spec.rb create mode 100644 spec/requests/api/graphql/project/languages_spec.rb create mode 100644 spec/requests/jira_connect/cors_preflight_checks_controller_spec.rb delete mode 100644 spec/requests/product_analytics/collector_app_attack_spec.rb delete mode 100644 spec/requests/product_analytics/collector_app_spec.rb create mode 100644 spec/requests/projects/ml/experiments_controller_spec.rb create mode 100644 spec/rubocop/cop/api/ensure_string_detail_spec.rb delete mode 100644 spec/rubocop/cop/gitlab/duplicate_spec_location_spec.rb create mode 100644 spec/rubocop/cop/gitlab/rspec/avoid_setup_spec.rb create mode 100644 spec/rubocop/cop/graphql/enum_names_spec.rb create mode 100644 spec/rubocop/cop/graphql/enum_values_spec.rb create mode 100644 spec/rubocop/cop/migration/schema_addition_methods_no_post_spec.rb create mode 100644 spec/rubocop/cop/rake/require_spec.rb create mode 100644 spec/rubocop/cop/rspec/duplicate_spec_location_spec.rb create mode 100644 spec/rubocop/cop/rspec/factory_bot/strategy_in_callback_spec.rb create mode 100644 spec/services/ci/create_pipeline_service/variables_spec.rb create mode 100644 spec/services/ci/pipeline_processing/test_cases/stage_one_test_succeeds_one_manual_test_fails_and_retry_manual_build.yml create mode 100644 spec/services/ci/pipeline_processing/test_cases/stage_one_test_succeeds_one_manual_test_fails_and_retry_pipeline.yml create mode 100644 spec/services/ci/pipeline_schedules/take_ownership_service_spec.rb delete mode 100644 spec/services/clusters/applications/check_ingress_ip_address_service_spec.rb delete mode 100644 spec/services/clusters/applications/check_installation_progress_service_spec.rb delete mode 100644 spec/services/clusters/applications/check_uninstall_progress_service_spec.rb delete mode 100644 spec/services/clusters/applications/check_upgrade_progress_service_spec.rb delete mode 100644 spec/services/clusters/applications/create_service_spec.rb delete mode 100644 spec/services/clusters/applications/patch_service_spec.rb delete mode 100644 spec/services/clusters/applications/prometheus_update_service_spec.rb delete mode 100644 spec/services/clusters/applications/update_service_spec.rb delete mode 100644 spec/services/clusters/kubernetes/configure_istio_ingress_service_spec.rb create mode 100644 spec/services/environments/create_for_build_service_spec.rb create mode 100644 spec/services/incident_management/timeline_event_tags/create_service_spec.rb create mode 100644 spec/services/issuable/discussions_list_service_spec.rb create mode 100644 spec/services/loose_foreign_keys/process_deleted_records_service_spec.rb create mode 100644 spec/services/markup/rendering_service_spec.rb delete mode 100644 spec/services/packages/rpm/repository_metadata/base_builder_spec.rb create mode 100644 spec/services/packages/rpm/repository_metadata/build_filelist_xml_service_spec.rb delete mode 100644 spec/services/packages/rpm/repository_metadata/build_filelist_xml_spec.rb create mode 100644 spec/services/packages/rpm/repository_metadata/build_other_xml_service_spec.rb delete mode 100644 spec/services/packages/rpm/repository_metadata/build_other_xml_spec.rb create mode 100644 spec/services/packages/rpm/repository_metadata/build_primary_xml_service_spec.rb delete mode 100644 spec/services/packages/rpm/repository_metadata/build_primary_xml_spec.rb create mode 100644 spec/services/packages/rpm/repository_metadata/build_repomd_xml_service_spec.rb delete mode 100644 spec/services/packages/rpm/repository_metadata/build_repomd_xml_spec.rb create mode 100644 spec/services/packages/rpm/repository_metadata/update_xml_service_spec.rb create mode 100644 spec/services/protected_branches/api_service_spec.rb delete mode 100644 spec/services/users/migrate_to_ghost_user_service_spec.rb create mode 100644 spec/services/work_items/widgets/milestone_service/create_service_spec.rb create mode 100644 spec/services/work_items/widgets/milestone_service/update_service_spec.rb delete mode 100644 spec/support/database/multiple_databases.rb create mode 100644 spec/support/database/query_recorder.rb delete mode 100644 spec/support/helpers/bare_repo_operations.rb create mode 100644 spec/support/helpers/database/multiple_databases_helpers.rb create mode 100644 spec/support/helpers/features/access_token_helpers.rb create mode 100644 spec/support/helpers/full_name_helper.rb delete mode 100644 spec/support/helpers/git_helpers.rb create mode 100644 spec/support/models/ci/partitioning_testing/cascade_check.rb create mode 100644 spec/support/models/ci/partitioning_testing/partition_identifiers.rb create mode 100644 spec/support/models/ci/partitioning_testing/rspec_hooks.rb create mode 100644 spec/support/models/ci/partitioning_testing/schema_helpers.rb delete mode 100644 spec/support/models/partitionable_check.rb create mode 100644 spec/support/multiple_databases.rb create mode 100644 spec/support/rate_limiter.rb create mode 100644 spec/support/shared_contexts/jobs/handling_retried_jobs_shared_context.rb create mode 100644 spec/support/shared_contexts/lib/sbom/package_url_shared_contexts.rb create mode 100644 spec/support/shared_examples/ci/retryable_shared_examples.rb create mode 100644 spec/support/shared_examples/controllers/preferred_language_switcher_shared_examples.rb create mode 100644 spec/support/shared_examples/features/confidential_notes_shared_examples.rb create mode 100644 spec/support/shared_examples/features/search/redacted_search_results_shared_examples.rb create mode 100644 spec/support/shared_examples/graphql/mutations/incident_management/timeline_events_shared_examples.rb create mode 100644 spec/support/shared_examples/lib/email/email_shared_examples.rb delete mode 100644 spec/support/shared_examples/lib/gitlab/experimentation_shared_examples.rb create mode 100644 spec/support/shared_examples/lib/gitlab/gitaly_client_shared_examples.rb create mode 100644 spec/support/shared_examples/models/concerns/integrations/base_slack_notification_shared_examples.rb create mode 100644 spec/support/shared_examples/models/integrations/base_ci_shared_examples.rb create mode 100644 spec/support/shared_examples/models/integrations/base_monitoring_shared_examples.rb create mode 100644 spec/support/shared_examples/requests/api/graphql/issue_list_shared_examples.rb create mode 100644 spec/support/shared_examples/requests/api/graphql/projects/branch_protections/access_level_request_examples.rb delete mode 100644 spec/support/shared_examples/services/base_rpm_service_shared_examples.rb create mode 100644 spec/support/shared_examples/services/issuable/discussions_list_shared_examples.rb create mode 100644 spec/support/shared_examples/services/merge_status_updated_trigger_shared_examples.rb create mode 100644 spec/support/shared_examples/services/work_items/widgets/milestone_service_shared_examples.rb create mode 100644 spec/support_specs/database/multiple_databases_helpers_spec.rb delete mode 100644 spec/support_specs/database/multiple_databases_spec.rb delete mode 100644 spec/validators/branch_filter_validator_spec.rb create mode 100644 spec/validators/web_hooks/wildcard_branch_filter_validator_spec.rb create mode 100644 spec/views/admin/application_settings/_jira_connect.html.haml_spec.rb create mode 100644 spec/views/devise/confirmations/almost_there.html.haml_spec.rb delete mode 100644 spec/views/groups/observability.html.haml_spec.rb create mode 100644 spec/views/groups/observability/observability.html.haml_spec.rb delete mode 100644 spec/views/projects/artifacts/_artifact.html.haml_spec.rb delete mode 100644 spec/views/shared/access_tokens/_table.html.haml_spec.rb delete mode 100644 spec/views/shared/deploy_tokens/_form.html.haml_spec.rb delete mode 100644 spec/workers/cluster_configure_istio_worker_spec.rb delete mode 100644 spec/workers/cluster_update_app_worker_spec.rb delete mode 100644 spec/workers/cluster_wait_for_app_update_worker_spec.rb delete mode 100644 spec/workers/cluster_wait_for_ingress_ip_address_worker_spec.rb delete mode 100644 spec/workers/clusters/applications/wait_for_uninstall_app_worker_spec.rb create mode 100644 spec/workers/container_registry/cleanup_worker_spec.rb create mode 100644 spec/workers/container_registry/delete_container_repository_worker_spec.rb create mode 100644 spec/workers/database/batched_background_migration/execution_worker_spec.rb create mode 100644 spec/workers/gitlab/github_import/pull_requests/import_review_request_worker_spec.rb create mode 100644 spec/workers/gitlab/github_import/stage/import_pull_requests_review_requests_worker_spec.rb create mode 100644 spec/workers/merge_requests/delete_branch_worker_spec.rb (limited to 'spec') diff --git a/spec/bin/audit_event_type_spec.rb b/spec/bin/audit_event_type_spec.rb new file mode 100644 index 00000000000..d4b1ebf08de --- /dev/null +++ b/spec/bin/audit_event_type_spec.rb @@ -0,0 +1,293 @@ +# frozen_string_literal: true + +require 'fast_spec_helper' +require 'rspec-parameterized' + +load File.expand_path('../../bin/audit-event-type', __dir__) + +RSpec.describe 'bin/audit-event-type' do + using RSpec::Parameterized::TableSyntax + + describe AuditEventTypeCreator do + let(:argv) { %w[test_audit_event -d test -g govern::compliance -s -t -i https://url -m http://url] } + let(:options) { AuditEventTypeOptionParser.parse(argv) } + let(:creator) { described_class.new(options) } + let(:existing_audit_event_types) do + { 'existing_audit_event_type' => File.join('config', 'audit_events', 'types', 'existing_audit_event_type.yml') } + end + + before do + allow(creator).to receive(:all_audit_event_type_names) { existing_audit_event_types } + allow(creator).to receive(:branch_name).and_return('feature-branch') + allow(creator).to receive(:editor).and_return(nil) + + # ignore writes + allow(File).to receive(:write).and_return(true) + + # ignore stdin + allow(Readline).to receive(:readline).and_raise('EOF') + end + + subject(:create_audit_event_type) { creator.execute } + + it 'properly creates an audit event type' do + expect(File).to receive(:write).with( + File.join('config', 'audit_events', 'types', 'test_audit_event.yml'), + anything) + + expect do + create_audit_event_type + end.to output(/name: test_audit_event/).to_stdout + end + + context 'when running on master' do + it 'requires feature branch' do + expect(creator).to receive(:branch_name).and_return('master') + + expect { create_audit_event_type }.to raise_error(AuditEventTypeHelpers::Abort, /Create a branch first/) + end + end + + context 'with invalid audit event type names' do + where(:argv, :ex) do + %w[.invalid.audit.type] | /Provide a name for the audit event type that is/ + %w[existing_audit_event_type] | /already exists!/ + end + + with_them do + it do + expect { create_audit_event_type }.to raise_error(ex) + end + end + end + end + + describe AuditEventTypeOptionParser do + describe '.parse' do + where(:param, :argv, :result) do + :name | %w[foo] | 'foo' + :amend | %w[foo --amend] | true + :force | %w[foo -f] | true + :force | %w[foo --force] | true + :description | %w[foo -d desc] | 'desc' + :description | %w[foo --description desc] | 'desc' + :group | %w[foo -g govern::compliance] | 'govern::compliance' + :group | %w[foo --group govern::compliance] | 'govern::compliance' + :milestone | %w[foo -M 15.6] | '15.6' + :milestone | %w[foo --milestone 15.6] | '15.6' + :saved_to_database | %w[foo -s] | true + :saved_to_database | %w[foo --saved-to-database] | true + :saved_to_database | %w[foo --no-saved-to-database] | false + :streamed | %w[foo -t] | true + :streamed | %w[foo --streamed] | true + :streamed | %w[foo --no-streamed] | false + :dry_run | %w[foo -n] | true + :dry_run | %w[foo --dry-run] | true + :ee | %w[foo -e] | true + :ee | %w[foo --ee] | true + :jh | %w[foo -j] | true + :jh | %w[foo --jh] | true + :introduced_by_mr | %w[foo -m https://url] | 'https://url' + :introduced_by_mr | %w[foo --introduced-by-mr https://url] | 'https://url' + :introduced_by_issue | %w[foo -i https://url] | 'https://url' + :introduced_by_issue | %w[foo --introduced-by-issue https://url] | 'https://url' + end + + with_them do + it do + options = described_class.parse(Array(argv)) + + expect(options.public_send(param)).to eq(result) + end + end + + it 'raises an error when name of the audit event type is missing' do + expect do + expect do + described_class.parse(%w[--amend]) + end.to output(/Name for the type of audit event is required/).to_stdout + end.to raise_error(AuditEventTypeHelpers::Abort) + end + + it 'parses -h' do + expect do + expect { described_class.parse(%w[foo -h]) }.to output(%r{Usage: bin/audit-event-type}).to_stdout + end.to raise_error(AuditEventTypeHelpers::Done) + end + end + + describe '.read_description' do + let(:description) { 'This is a test description for an audit event type.' } + + it 'reads description from stdin' do + expect(Readline).to receive(:readline).and_return(description) + expect do + expect(described_class.read_description).to eq('This is a test description for an audit event type.') + end.to output(/Specify a human-readable description of how this event is triggered:/).to_stdout + end + + context 'when description is empty' do + let(:description) { '' } + + it 'shows error message and retries' do + expect(Readline).to receive(:readline).and_return(description) + expect(Readline).to receive(:readline).and_raise('EOF') + + expect do + expect { described_class.read_description }.to raise_error(/EOF/) + end.to output(/Specify a human-readable description of how this event is triggered:/) + .to_stdout.and output(/description is a required field/).to_stderr + end + end + end + + describe '.read_group' do + let(:group) { 'govern::compliance' } + + it 'reads group from stdin' do + expect(Readline).to receive(:readline).and_return(group) + expect do + expect(described_class.read_group).to eq('govern::compliance') + end.to output(/Specify the group introducing the audit event type, like `govern::compliance`:/).to_stdout + end + + context 'when group is empty' do + let(:group) { '' } + + it 'shows error message and retries' do + expect(Readline).to receive(:readline).and_return(group) + expect(Readline).to receive(:readline).and_raise('EOF') + + expect do + expect { described_class.read_group }.to raise_error(/EOF/) + end.to output(/Specify the group introducing the audit event type, like `govern::compliance`:/) + .to_stdout.and output(/group is a required field/).to_stderr + end + end + end + + describe '.read_saved_to_database' do + let(:saved_to_database) { 'true' } + + it 'reads saved_to_database from stdin' do + expect(Readline).to receive(:readline).and_return(saved_to_database) + expect do + expect(described_class.read_saved_to_database).to eq(true) + end.to output(/Specify whether to persist events to database and JSON logs \[yes, no\]:/).to_stdout + end + + context 'when saved_to_database is invalid' do + let(:saved_to_database) { 'non boolean value' } + + it 'shows error message and retries' do + expect(Readline).to receive(:readline).and_return(saved_to_database) + expect(Readline).to receive(:readline).and_raise('EOF') + + expect do + expect { described_class.read_saved_to_database }.to raise_error(/EOF/) + end.to output(/Specify whether to persist events to database and JSON logs \[yes, no\]:/) + .to_stdout.and output(/saved_to_database is a required boolean field/).to_stderr + end + end + end + + describe '.read_streamed' do + let(:streamed) { 'true' } + + it 'reads streamed from stdin' do + expect(Readline).to receive(:readline).and_return(streamed) + expect do + expect(described_class.read_streamed).to eq(true) + end.to output(/Specify if events should be streamed to external services \(if configured\) \[yes, no\]:/) + .to_stdout + end + + context 'when streamed is invalid' do + let(:streamed) { 'non boolean value' } + + it 'shows error message and retries' do + expect(Readline).to receive(:readline).and_return(streamed) + expect(Readline).to receive(:readline).and_raise('EOF') + + expect do + expect { described_class.read_streamed }.to raise_error(/EOF/) + end.to output(/Specify if events should be streamed to external services \(if configured\) \[yes, no\]:/) + .to_stdout.and output(/streamed is a required boolean field/).to_stderr + end + end + end + + describe '.read_introduced_by_mr' do + let(:url) { 'https://merge-request' } + + it 'reads introduced_by_mr from stdin' do + expect(Readline).to receive(:readline).and_return(url) + expect do + expect(described_class.read_introduced_by_mr).to eq('https://merge-request') + end.to output(/URL to GitLab merge request that added this type of audit event:/).to_stdout + end + + context 'when URL is empty' do + let(:url) { '' } + + it 'does not raise an error' do + expect(Readline).to receive(:readline).and_return(url) + + expect do + expect(described_class.read_introduced_by_mr).to be_nil + end.to output(/URL to GitLab merge request that added this type of audit event:/).to_stdout + end + end + + context 'when URL is invalid' do + let(:url) { 'invalid' } + + it 'shows error message and retries' do + expect(Readline).to receive(:readline).and_return(url) + expect(Readline).to receive(:readline).and_raise('EOF') + + expect do + expect { described_class.read_introduced_by_mr }.to raise_error(/EOF/) + end.to output(/URL to GitLab merge request that added this type of audit event:/) + .to_stdout.and output(/URL needs to start with https/).to_stderr + end + end + end + + describe '.read_introduced_by_issue' do + let(:url) { 'https://issue' } + + it 'reads type from stdin' do + expect(Readline).to receive(:readline).and_return(url) + expect do + expect(described_class.read_introduced_by_issue).to eq('https://issue') + end.to output(/URL to GitLab issue that added this type of audit event:/).to_stdout + end + + context 'when URL is invalid' do + let(:type) { 'invalid' } + + it 'shows error message and retries' do + expect(Readline).to receive(:readline).and_return(type) + expect(Readline).to receive(:readline).and_raise('EOF') + + expect do + expect { described_class.read_introduced_by_issue }.to raise_error(/EOF/) + end.to output(/URL to GitLab issue that added this type of audit event:/) + .to_stdout.and output(/URL needs to start with https/).to_stderr + end + end + end + + describe '.read_milestone' do + before do + allow(File).to receive(:read).with('VERSION').and_return('15.6.0-pre') + allow(File).to receive(:read).and_call_original + end + + it 'returns the correct milestone from the VERSION file' do + expect(described_class.read_milestone).to eq('15.6') + end + end + end +end diff --git a/spec/components/pajamas/spinner_component_spec.rb b/spec/components/pajamas/spinner_component_spec.rb index 9aac9a0085c..f03d8c9561b 100644 --- a/spec/components/pajamas/spinner_component_spec.rb +++ b/spec/components/pajamas/spinner_component_spec.rb @@ -35,7 +35,7 @@ RSpec.describe Pajamas::SpinnerComponent, type: :component do describe 'inline' do context 'by default' do it 'renders a div' do - expect(page).to have_css 'div.gl-spinner' + expect(page).to have_css 'div.gl-spinner-container' end end @@ -43,7 +43,7 @@ RSpec.describe Pajamas::SpinnerComponent, type: :component do let(:options) { { inline: true } } it 'renders a span' do - expect(page).to have_css 'span.gl-spinner' + expect(page).to have_css 'span.gl-spinner-container' end end end diff --git a/spec/components/previews/pajamas/alert_component_preview.rb b/spec/components/previews/pajamas/alert_component_preview.rb index e1889032c8b..4768ef47975 100644 --- a/spec/components/previews/pajamas/alert_component_preview.rb +++ b/spec/components/previews/pajamas/alert_component_preview.rb @@ -4,7 +4,7 @@ module Pajamas # @param title text # @param body text # @param dismissible toggle - # @param variant select [info, warning, success, danger, tip] + # @param variant select {{ Pajamas::AlertComponent::VARIANT_ICONS.keys }} def default(title: "Alert title (optional)", body: "Alert message goes here.", dismissible: true, variant: :info) render(Pajamas::AlertComponent.new( title: title, diff --git a/spec/components/previews/pajamas/avatar_component_preview.rb b/spec/components/previews/pajamas/avatar_component_preview.rb index e5cdde1ccef..147d89169b0 100644 --- a/spec/components/previews/pajamas/avatar_component_preview.rb +++ b/spec/components/previews/pajamas/avatar_component_preview.rb @@ -9,17 +9,17 @@ module Pajamas end # We show user avatars in a circle. - # @param size select [16, 24, 32, 48, 64, 96] + # @param size select {{ Pajamas::AvatarComponent::SIZE_OPTIONS }} def user(size: 64) render(Pajamas::AvatarComponent.new(User.first, size: size)) end - # @param size select [16, 24, 32, 48, 64, 96] + # @param size select {{ Pajamas::AvatarComponent::SIZE_OPTIONS }} def project(size: 64) render(Pajamas::AvatarComponent.new(Project.first, size: size)) end - # @param size select [16, 24, 32, 48, 64, 96] + # @param size select {{ Pajamas::AvatarComponent::SIZE_OPTIONS }} def group(size: 64) render(Pajamas::AvatarComponent.new(Group.first, size: size)) end diff --git a/spec/components/previews/pajamas/badge_component_preview.rb b/spec/components/previews/pajamas/badge_component_preview.rb index e740a4a38aa..e833c4e458d 100644 --- a/spec/components/previews/pajamas/badge_component_preview.rb +++ b/spec/components/previews/pajamas/badge_component_preview.rb @@ -10,9 +10,9 @@ module Pajamas # @param icon select [~, star-o, issue-closed, tanuki] # @param icon_only toggle # @param href url - # @param size select [sm, md, lg] + # @param size select {{ Pajamas::BadgeComponent::SIZE_OPTIONS }} # @param text text - # @param variant select [muted, neutral, info, success, warning, danger] + # @param variant select {{ Pajamas::BadgeComponent::VARIANT_OPTIONS }} def default(icon: :tanuki, icon_only: false, href: nil, size: :md, text: "Tanuki", variant: :muted) render Pajamas::BadgeComponent.new( text, diff --git a/spec/components/previews/pajamas/banner_component_preview.rb b/spec/components/previews/pajamas/banner_component_preview.rb index 861e3ff95dc..19f4f5243c0 100644 --- a/spec/components/previews/pajamas/banner_component_preview.rb +++ b/spec/components/previews/pajamas/banner_component_preview.rb @@ -9,7 +9,7 @@ module Pajamas # @param button_link text # @param content textarea # @param embedded toggle - # @param variant select [introduction, promotion] + # @param variant select {{ Pajamas::BannerComponent::VARIANT_OPTIONS }} def default( button_text: "Learn more", button_link: "https://about.gitlab.com/", diff --git a/spec/components/previews/pajamas/button_component_preview.rb b/spec/components/previews/pajamas/button_component_preview.rb index 1f61d9cf2bc..c07d898d9cd 100644 --- a/spec/components/previews/pajamas/button_component_preview.rb +++ b/spec/components/previews/pajamas/button_component_preview.rb @@ -5,10 +5,10 @@ module Pajamas # ---- # See its design reference [here](https://design.gitlab.com/components/banner). # - # @param category select [primary, secondary, tertiary] - # @param variant select [default, confirm, danger, dashed, link, reset] - # @param size select [small, medium] - # @param type select [button, reset, submit] + # @param category select {{ Pajamas::ButtonComponent::CATEGORY_OPTIONS }} + # @param variant select {{ Pajamas::ButtonComponent::VARIANT_OPTIONS }} + # @param size select {{ Pajamas::ButtonComponent::SIZE_OPTIONS }} + # @param type select {{ Pajamas::ButtonComponent::TYPE_OPTIONS }} # @param disabled toggle # @param loading toggle # @param block toggle diff --git a/spec/components/previews/pajamas/progress_component_preview.rb b/spec/components/previews/pajamas/progress_component_preview.rb index 4de07872a80..1562ffddf7e 100644 --- a/spec/components/previews/pajamas/progress_component_preview.rb +++ b/spec/components/previews/pajamas/progress_component_preview.rb @@ -7,8 +7,8 @@ module Pajamas # # See its design reference [here](https://design.gitlab.com/components/progress-bar). # - # @param value number - # @param variant select [primary, success] + # @param value range { min: 0, max: 100, step: 1 } + # @param variant select {{ Pajamas::ProgressComponent::VARIANT_OPTIONS }} def default(value: 50, variant: :primary) render Pajamas::ProgressComponent.new(value: value, variant: variant) end diff --git a/spec/components/previews/pajamas/spinner_component_preview.rb b/spec/components/previews/pajamas/spinner_component_preview.rb index 149bfddcfc2..34cc386763f 100644 --- a/spec/components/previews/pajamas/spinner_component_preview.rb +++ b/spec/components/previews/pajamas/spinner_component_preview.rb @@ -7,16 +7,30 @@ module Pajamas # # @param inline toggle # @param label text - # @param size select [[small, sm], [medium, md], [large, lg], [extra large, xl]] + # @param size select {{ Pajamas::SpinnerComponent::SIZE_OPTIONS }} def default(inline: false, label: "Loading", size: :md) - render(Pajamas::SpinnerComponent.new(inline: inline, label: label, size: size)) + render Pajamas::SpinnerComponent.new( + inline: inline, + label: label, + size: size + ) end - # Use a light spinner on dark backgrounds + # Use a light spinner on dark backgrounds. # - # @display bg_color "#222" + # @display bg_dark true def light render(Pajamas::SpinnerComponent.new(color: :light)) end + + # Any extra HTML attributes like `class`, `data` or `id` get automatically applied to the spinner container element. + # + def extra_attributes + render Pajamas::SpinnerComponent.new( + class: "js-do-something", + data: { foo: "bar" }, + id: "my-special-spinner" + ) + end end end diff --git a/spec/config/inject_enterprise_edition_module_spec.rb b/spec/config/inject_enterprise_edition_module_spec.rb index 6ef74a2b616..96fc26fc80a 100644 --- a/spec/config/inject_enterprise_edition_module_spec.rb +++ b/spec/config/inject_enterprise_edition_module_spec.rb @@ -126,4 +126,22 @@ RSpec.describe InjectEnterpriseEditionModule do describe '#include_mod' do it_behaves_like 'expand the assumed extension with', :include end + + describe '#gitlab_extensions' do + context 'when there are no extension modules' do + it 'returns the class itself' do + expect(fish_class.gitlab_extensions).to contain_exactly(fish_class) + end + end + + context 'when there are extension modules' do + it 'returns the class itself and any extensions' do + stub_const(extension_name, extension_namespace) + extension_namespace.const_set(fish_name, fish_extension) + fish_class.prepend_mod + + expect(fish_class.gitlab_extensions).to contain_exactly(fish_class, fish_extension) + end + end + end end diff --git a/spec/config/metrics/aggregates/aggregated_metrics_spec.rb b/spec/config/metrics/aggregates/aggregated_metrics_spec.rb deleted file mode 100644 index 1984aff01db..00000000000 --- a/spec/config/metrics/aggregates/aggregated_metrics_spec.rb +++ /dev/null @@ -1,95 +0,0 @@ -# frozen_string_literal: true - -require 'spec_helper' - -RSpec.describe 'aggregated metrics' do - RSpec::Matchers.define :be_known_event do - match do |event| - Gitlab::UsageDataCounters::HLLRedisCounter.known_event?(event) - end - - failure_message do |event| - "Event with name: `#{event}` can not be found within `#{Gitlab::UsageDataCounters::HLLRedisCounter::KNOWN_EVENTS_PATH}`" - end - end - - RSpec::Matchers.define :has_known_source do - match do |aggregate| - Gitlab::Usage::Metrics::Aggregates::SOURCES.include?(aggregate[:source]) - end - - failure_message do |aggregate| - "Aggregate with name: `#{aggregate[:name]}` uses not allowed source `#{aggregate[:source]}`" - end - end - - RSpec::Matchers.define :have_known_time_frame do - allowed_time_frames = [ - Gitlab::Usage::TimeFrame::ALL_TIME_TIME_FRAME_NAME, - Gitlab::Usage::TimeFrame::TWENTY_EIGHT_DAYS_TIME_FRAME_NAME, - Gitlab::Usage::TimeFrame::SEVEN_DAYS_TIME_FRAME_NAME - ] - - match do |aggregate| - (aggregate[:time_frame] - allowed_time_frames).empty? - end - - failure_message do |aggregate| - "Aggregate with name: `#{aggregate[:name]}` uses not allowed time_frame`#{aggregate[:time_frame] - allowed_time_frames}`" - end - end - - let_it_be(:known_events) do - Gitlab::UsageDataCounters::HLLRedisCounter.known_events - end - - Gitlab::Usage::Metrics::Aggregates::Aggregate.new(Time.current).send(:aggregated_metrics).tap do |aggregated_metrics| - it 'all events has unique name' do - event_names = aggregated_metrics&.map { |event| event[:name] } - - expect(event_names).to eq(event_names&.uniq) - end - - it 'all aggregated metrics has known source' do - expect(aggregated_metrics).to all has_known_source - end - - it 'all aggregated metrics has known time frame' do - expect(aggregated_metrics).to all have_known_time_frame - end - - aggregated_metrics&.select { |agg| agg[:source] == Gitlab::Usage::Metrics::Aggregates::REDIS_SOURCE }&.each do |aggregate| - context "for #{aggregate[:name]} aggregate of #{aggregate[:events].join(' ')}" do - let_it_be(:events_records) { known_events.select { |event| aggregate[:events].include?(event[:name]) } } - - it "does not include 'all' time frame for Redis sourced aggregate" do - expect(aggregate[:time_frame]).not_to include(Gitlab::Usage::TimeFrame::ALL_TIME_TIME_FRAME_NAME) - end - - it "only refers to known events", :skip do - expect(aggregate[:events]).to all be_known_event - end - - it "has expected structure" do - expect(aggregate.keys).to include(*%w[name operator events]) - end - - it "uses allowed aggregation operators" do - expect(Gitlab::Usage::Metrics::Aggregates::ALLOWED_METRICS_AGGREGATIONS).to include aggregate[:operator] - end - - it "uses events from the same Redis slot" do - event_slots = events_records.map { |event| event[:redis_slot] }.uniq - - expect(event_slots).to contain_exactly(be_present) - end - - it "uses events with the same aggregation period" do - event_slots = events_records.map { |event| event[:aggregation] }.uniq - - expect(event_slots).to contain_exactly(be_present) - end - end - end - end -end diff --git a/spec/contracts/contracts/project/pipeline/index/pipelines#index-get_list_project_pipelines.json b/spec/contracts/contracts/project/pipeline/index/pipelines#index-get_list_project_pipelines.json index b725ae400a7..2ebfd1bfdf2 100644 --- a/spec/contracts/contracts/project/pipeline/index/pipelines#index-get_list_project_pipelines.json +++ b/spec/contracts/contracts/project/pipeline/index/pipelines#index-get_list_project_pipelines.json @@ -198,6 +198,9 @@ "match": "regex", "regex": "^(push|web|trigger|schedule|api|external|pipeline|chat|webide|merge_request_event|external_pull_request_event|parent_pipeline|ondemand_dast_scan|ondemand_dast_validation)$" }, + "$.body.pipelines[*].name": { + "match": "type" + }, "$.body.pipelines[*].created_at": { "match": "regex", "regex": "^\\d{4}-[01]\\d-[0-3]\\dT[0-2]\\d:[0-5]\\d:[0-5]\\d\\.\\d+([+-][0-2]\\d(:?[0-5]\\d)?|Z)$" @@ -335,6 +338,9 @@ "$.body.pipelines[*].details.name": { "match": "type" }, + "$.body.pipelines[*].details.event_type_name": { + "match": "type" + }, "$.body.pipelines[*].details.manual_actions": { "min": 1 }, diff --git a/spec/contracts/provider/helpers/publish_contract_helper.rb b/spec/contracts/provider/helpers/publish_contract_helper.rb new file mode 100644 index 00000000000..102a73d87ee --- /dev/null +++ b/spec/contracts/provider/helpers/publish_contract_helper.rb @@ -0,0 +1,17 @@ +# frozen_string_literal: true + +module Provider + module PublishContractHelper + PROVIDER_VERSION = ENV['GIT_COMMIT'] || `git rev-parse --verify HEAD`.strip + PROVIDER_BRANCH = ENV['GIT_BRANCH'] || `git name-rev --name-only HEAD`.strip + PUBLISH_FLAG = true + + def self.publish_contract_setup + @setup ||= -> { + app_version PROVIDER_VERSION + app_version_branch PROVIDER_BRANCH + publish_verification_results PUBLISH_FLAG + } + end + end +end diff --git a/spec/contracts/provider/pact_helpers/project/merge_request/show/diffs_batch_helper.rb b/spec/contracts/provider/pact_helpers/project/merge_request/show/diffs_batch_helper.rb index f94ce47b1f3..71f302f2c44 100644 --- a/spec/contracts/provider/pact_helpers/project/merge_request/show/diffs_batch_helper.rb +++ b/spec/contracts/provider/pact_helpers/project/merge_request/show/diffs_batch_helper.rb @@ -11,6 +11,8 @@ module Provider honours_pact_with 'MergeRequest#show' do pact_uri '../contracts/project/merge_request/show/mergerequest#show-merge_request_diffs_batch_endpoint.json' end + + Provider::PublishContractHelper.publish_contract_setup.call end end end diff --git a/spec/contracts/provider/pact_helpers/project/merge_request/show/diffs_metadata_helper.rb b/spec/contracts/provider/pact_helpers/project/merge_request/show/diffs_metadata_helper.rb index 61567214b7a..60a3abea5ae 100644 --- a/spec/contracts/provider/pact_helpers/project/merge_request/show/diffs_metadata_helper.rb +++ b/spec/contracts/provider/pact_helpers/project/merge_request/show/diffs_metadata_helper.rb @@ -11,6 +11,10 @@ module Provider honours_pact_with 'MergeRequest#show' do pact_uri '../contracts/project/merge_request/show/mergerequest#show-merge_request_diffs_metadata_endpoint.json' end + + app_version Provider::PublishContractHelper::PROVIDER_VERSION + app_version_branch Provider::PublishContractHelper::PROVIDER_BRANCH + publish_verification_results Provider::PublishContractHelper::PUBLISH_FLAG end end end diff --git a/spec/contracts/provider/pact_helpers/project/merge_request/show/discussions_helper.rb b/spec/contracts/provider/pact_helpers/project/merge_request/show/discussions_helper.rb index fa76ce8889a..b9308af0a1a 100644 --- a/spec/contracts/provider/pact_helpers/project/merge_request/show/discussions_helper.rb +++ b/spec/contracts/provider/pact_helpers/project/merge_request/show/discussions_helper.rb @@ -11,6 +11,10 @@ module Provider honours_pact_with 'MergeRequest#show' do pact_uri '../contracts/project/merge_request/show/mergerequest#show-merge_request_discussions_endpoint.json' end + + app_version Provider::PublishContractHelper::PROVIDER_VERSION + app_version_branch Provider::PublishContractHelper::PROVIDER_BRANCH + publish_verification_results Provider::PublishContractHelper::PUBLISH_FLAG end end end diff --git a/spec/contracts/provider/pact_helpers/project/pipeline/index/create_a_new_pipeline_helper.rb b/spec/contracts/provider/pact_helpers/project/pipeline/index/create_a_new_pipeline_helper.rb index 247a7c4ca8e..2af960bc9fd 100644 --- a/spec/contracts/provider/pact_helpers/project/pipeline/index/create_a_new_pipeline_helper.rb +++ b/spec/contracts/provider/pact_helpers/project/pipeline/index/create_a_new_pipeline_helper.rb @@ -11,6 +11,10 @@ module Provider honours_pact_with 'Pipelines#new' do pact_uri '../contracts/project/pipeline/new/pipelines#new-post_create_a_new_pipeline.json' end + + app_version Provider::PublishContractHelper::PROVIDER_VERSION + app_version_branch Provider::PublishContractHelper::PROVIDER_BRANCH + publish_verification_results Provider::PublishContractHelper::PUBLISH_FLAG end end end diff --git a/spec/contracts/provider/pact_helpers/project/pipeline/index/get_list_project_pipelines_helper.rb b/spec/contracts/provider/pact_helpers/project/pipeline/index/get_list_project_pipelines_helper.rb index 80cbbe3b4dd..37cddd1b80e 100644 --- a/spec/contracts/provider/pact_helpers/project/pipeline/index/get_list_project_pipelines_helper.rb +++ b/spec/contracts/provider/pact_helpers/project/pipeline/index/get_list_project_pipelines_helper.rb @@ -11,6 +11,10 @@ module Provider honours_pact_with 'Pipelines#index' do pact_uri '../contracts/project/project/pipeline/index/pipelines#index-get_list_project_pipelines.json' end + + app_version Provider::PublishContractHelper::PROVIDER_VERSION + app_version_branch Provider::PublishContractHelper::PROVIDER_BRANCH + publish_verification_results Provider::PublishContractHelper::PUBLISH_FLAG end end end diff --git a/spec/contracts/provider/pact_helpers/project/pipeline/show/delete_pipeline_helper.rb b/spec/contracts/provider/pact_helpers/project/pipeline/show/delete_pipeline_helper.rb index 2d29fabfeca..0455281fcd7 100644 --- a/spec/contracts/provider/pact_helpers/project/pipeline/show/delete_pipeline_helper.rb +++ b/spec/contracts/provider/pact_helpers/project/pipeline/show/delete_pipeline_helper.rb @@ -1,6 +1,7 @@ # frozen_string_literal: true require_relative '../../../../spec_helper' +require_relative '../../../../helpers/publish_contract_helper' require_relative '../../../../states/project/pipeline/show_state' module Provider @@ -11,6 +12,10 @@ module Provider honours_pact_with 'Pipelines#show' do pact_uri '../contracts/project/pipeline/show/pipelines#show-delete_pipeline.json' end + + app_version Provider::PublishContractHelper::PROVIDER_VERSION + app_version_branch Provider::PublishContractHelper::PROVIDER_BRANCH + publish_verification_results Provider::PublishContractHelper::PUBLISH_FLAG end end end diff --git a/spec/contracts/provider/pact_helpers/project/pipeline/show/get_pipeline_header_data_helper.rb b/spec/contracts/provider/pact_helpers/project/pipeline/show/get_pipeline_header_data_helper.rb index bc8c04cc455..bce1c4ab3f4 100644 --- a/spec/contracts/provider/pact_helpers/project/pipeline/show/get_pipeline_header_data_helper.rb +++ b/spec/contracts/provider/pact_helpers/project/pipeline/show/get_pipeline_header_data_helper.rb @@ -1,6 +1,7 @@ # frozen_string_literal: true require_relative '../../../../spec_helper' +require_relative '../../../../helpers/publish_contract_helper' require_relative '../../../../states/project/pipeline/show_state' module Provider @@ -10,7 +11,12 @@ module Provider honours_pact_with 'Pipelines#show' do pact_uri '../contracts/project/pipeline/show/pipelines#show-get_project_pipeline_header_data.json' + # pact_uri 'http://localhost:9292/pacts/provider/GET%20pipeline%20header%20data/consumer/Pipelines%23show/latest' end + + app_version Provider::PublishContractHelper::PROVIDER_VERSION + app_version_branch Provider::PublishContractHelper::PROVIDER_BRANCH + publish_verification_results Provider::PublishContractHelper::PUBLISH_FLAG end end end diff --git a/spec/contracts/provider/pact_helpers/project/pipeline_schedule/update_pipeline_schedule_helper.rb b/spec/contracts/provider/pact_helpers/project/pipeline_schedule/update_pipeline_schedule_helper.rb index a83aa9524dc..d95a09abd8d 100644 --- a/spec/contracts/provider/pact_helpers/project/pipeline_schedule/update_pipeline_schedule_helper.rb +++ b/spec/contracts/provider/pact_helpers/project/pipeline_schedule/update_pipeline_schedule_helper.rb @@ -11,6 +11,10 @@ module Provider honours_pact_with 'PipelineSchedule#edit' do pact_uri '../contracts/project/pipeline_schedule/edit/pipelineschedules#edit-put_edit_a_pipeline_schedule.json' end + + app_version Provider::PublishContractHelper::PROVIDER_VERSION + app_version_branch Provider::PublishContractHelper::PROVIDER_BRANCH + publish_verification_results Provider::PublishContractHelper::PUBLISH_FLAG end end end diff --git a/spec/contracts/publish-contracts.sh b/spec/contracts/publish-contracts.sh new file mode 100644 index 00000000000..f20cc43e258 --- /dev/null +++ b/spec/contracts/publish-contracts.sh @@ -0,0 +1,23 @@ +LATEST_SHA=$(git rev-parse HEAD) +GIT_BRANCH=$(git rev-parse --abbrev-ref HEAD) +BROKER_BASE_URL="http://localhost:9292" + +CONTRACTS=$(find ./contracts -name "*.json") +ERROR=0 + +trap 'catch' ERR + +function catch() { + printf "\e[31mAn error occured while trying to publish the pact.\033[0m\n" + ERROR=1 +} + +for contract in $CONTRACTS +do + printf "\e[32mPublishing ${contract}...\033[0m\n" + pact-broker publish $contract --consumer-app-version $LATEST_SHA --branch $GIT_BRANCH --broker-base-url $BROKER_BASE_URL --output json +done + +if [ ${ERROR} = 1 ]; then + exit 1; +fi \ No newline at end of file diff --git a/spec/controllers/admin/groups_controller_spec.rb b/spec/controllers/admin/groups_controller_spec.rb index 37cb0a1f289..6085f0e1239 100644 --- a/spec/controllers/admin/groups_controller_spec.rb +++ b/spec/controllers/admin/groups_controller_spec.rb @@ -43,5 +43,13 @@ RSpec.describe Admin::GroupsController do post :create, params: { group: { path: 'test', name: 'test', admin_note_attributes: { note: 'test' } } } end.to change { Namespace::AdminNote.count }.by(1) end + + it 'delegates to Groups::CreateService service instance' do + expect_next_instance_of(::Groups::CreateService) do |service| + expect(service).to receive(:execute).once.and_call_original + end + + post :create, params: { group: { path: 'test', name: 'test' } } + end end end diff --git a/spec/controllers/admin/hooks_controller_spec.rb b/spec/controllers/admin/hooks_controller_spec.rb index 14f4a2f40e7..82e4b873bf6 100644 --- a/spec/controllers/admin/hooks_controller_spec.rb +++ b/spec/controllers/admin/hooks_controller_spec.rb @@ -3,7 +3,7 @@ require 'spec_helper' RSpec.describe Admin::HooksController do - let(:admin) { create(:admin) } + let_it_be(:admin) { create(:admin) } before do sign_in(admin) @@ -33,7 +33,23 @@ RSpec.describe Admin::HooksController do end describe 'POST #update' do - let!(:hook) { create(:system_hook) } + let_it_be_with_reload(:hook) { create(:system_hook) } + + context 'with an existing token' do + hook_params = { + token: WebHook::SECRET_MASK, + url: "http://example.com" + } + + it 'does not change a token' do + expect do + post :update, params: { id: hook.id, hook: hook_params } + end.not_to change { hook.reload.token } + + expect(response).to have_gitlab_http_status(:found) + expect(flash[:alert]).to be_blank + end + end it 'sets all parameters' do hook.update!(url_variables: { 'foo' => 'bar', 'baz' => 'woo' }) @@ -61,8 +77,8 @@ RSpec.describe Admin::HooksController do end describe 'DELETE #destroy' do - let!(:hook) { create(:system_hook) } - let!(:log) { create(:web_hook_log, web_hook: hook) } + let_it_be(:hook) { create(:system_hook) } + let_it_be(:log) { create(:web_hook_log, web_hook: hook) } let(:params) { { id: hook } } it_behaves_like 'Web hook destroyer' diff --git a/spec/controllers/admin/integrations_controller_spec.rb b/spec/controllers/admin/integrations_controller_spec.rb index 0e456858b49..e75f27589d7 100644 --- a/spec/controllers/admin/integrations_controller_spec.rb +++ b/spec/controllers/admin/integrations_controller_spec.rb @@ -19,7 +19,7 @@ RSpec.describe Admin::IntegrationsController do describe '#edit' do Integration.available_integration_names.each do |integration_name| - context "#{integration_name}" do + context integration_name.to_s do it 'successfully displays the template' do get :edit, params: { id: integration_name } diff --git a/spec/controllers/admin/spam_logs_controller_spec.rb b/spec/controllers/admin/spam_logs_controller_spec.rb index 48221f496fb..51f7ecdece6 100644 --- a/spec/controllers/admin/spam_logs_controller_spec.rb +++ b/spec/controllers/admin/spam_logs_controller_spec.rb @@ -27,34 +27,17 @@ RSpec.describe Admin::SpamLogsController do expect(response).to have_gitlab_http_status(:ok) end - context 'when user_destroy_with_limited_execution_time_worker is enabled' do - it 'initiates user removal', :sidekiq_inline do - expect do - delete :destroy, params: { id: first_spam.id, remove_user: true } - 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(flash[:notice]).to eq("User #{user.username} was successfully removed.") - end - end - - context 'when user_destroy_with_limited_execution_time_worker is disabled' do - before do - stub_feature_flags(user_destroy_with_limited_execution_time_worker: false) - end - - it 'removes user and their spam logs when removing the user', :sidekiq_inline do + it 'initiates user removal', :sidekiq_inline do + expect do delete :destroy, params: { id: first_spam.id, remove_user: true } + end.not_to change { SpamLog.count } - expect(flash[:notice]).to eq "User #{user.username} was successfully removed." - expect(response).to have_gitlab_http_status(:found) - expect(SpamLog.count).to eq(0) - expect { User.find(user.id) }.to raise_error(ActiveRecord::RecordNotFound) - end + expect(response).to have_gitlab_http_status(:found) + 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/topics_controller_spec.rb b/spec/controllers/admin/topics_controller_spec.rb index 111fdcc3be6..e640f8bb7ec 100644 --- a/spec/controllers/admin/topics_controller_spec.rb +++ b/spec/controllers/admin/topics_controller_spec.rb @@ -176,7 +176,7 @@ RSpec.describe Admin::TopicsController do describe 'POST #merge' do let_it_be(:source_topic) { create(:topic, name: 'source_topic') } - let_it_be(:project) { create(:project, topic_list: source_topic.name ) } + let_it_be(:project) { create(:project, topic_list: source_topic.name) } it 'merges source topic into target topic' do post :merge, params: { source_topic_id: source_topic.id, target_topic_id: topic.id } diff --git a/spec/controllers/admin/users_controller_spec.rb b/spec/controllers/admin/users_controller_spec.rb index 682399f4dd9..eecb803fb1a 100644 --- a/spec/controllers/admin/users_controller_spec.rb +++ b/spec/controllers/admin/users_controller_spec.rb @@ -63,130 +63,179 @@ RSpec.describe Admin::UsersController do expect(response).to be_redirect expect(response.location).to end_with(user.username) end - end - describe 'DELETE #destroy', :sidekiq_might_not_need_inline do - let(:project) { create(:project, namespace: user.namespace) } - let!(:issue) { create(:issue, author: user) } + describe 'impersonation_error_text' do + context 'when user can be impersonated' do + it 'sets impersonation_error_text to nil' do + get :show, params: { id: user.username.downcase } - before do - project.add_developer(user) - end + expect(assigns(:impersonation_error_text)).to eq(nil) + end + end - context 'when user_destroy_with_limited_execution_time_worker is enabled' do - it 'initiates user removal' do - delete :destroy, params: { id: user.username }, format: :json + context 'when impersonation is already in progress' do + let(:admin2) { create(:admin) } - expect(response).to have_gitlab_http_status(:ok) - expect( - Users::GhostUserMigration.where(user: user, - initiator_user: admin, - hard_delete: false) - ).to be_exists + before do + post :impersonate, params: { id: admin2.username } + end + + it 'sets impersonation_error_text' do + get :show, params: { id: user.username.downcase } + + expect(assigns(:impersonation_error_text)).to eq(_("You are already impersonating another user")) + end end - it 'initiates user removal and passes hard delete option' do - delete :destroy, params: { id: user.username, hard_delete: true }, format: :json + context 'when user is blocked' do + before do + user.block + end - expect(response).to have_gitlab_http_status(:ok) - expect( - Users::GhostUserMigration.where(user: user, - initiator_user: admin, - hard_delete: true) - ).to be_exists + it 'sets impersonation_error_text' do + get :show, params: { id: user.username.downcase } + + expect(assigns(:impersonation_error_text)).to eq(_("You cannot impersonate a blocked user")) + end end - context 'prerequisites for account deletion' do - context 'solo-owned groups' do - let(:group) { create(:group) } + context "when the user's password is expired" do + before do + user.update!(password_expires_at: 1.day.ago) + end - context 'if the user is the sole owner of at least one group' do - before do - create(:group_member, :owner, group: group, user: user) - end + it 'sets impersonation_error_text' do + get :show, params: { id: user.username.downcase } + + expect(assigns(:impersonation_error_text)).to eq(_("You cannot impersonate a user with an expired password")) + end + end - context 'soft-delete' do - it 'fails' do - delete :destroy, params: { id: user.username } + context "when the user is internal" do + before do + user.update!(user_type: :migration_bot) + end - message = s_('AdminUsers|You must transfer ownership or delete the groups owned by this user before you can delete their account') + it 'sets impersonation_error_text' do + get :show, params: { id: user.username.downcase } - expect(flash[:alert]).to eq(message) - expect(response).to have_gitlab_http_status(:see_other) - expect(response).to redirect_to admin_user_path(user) - expect(Users::GhostUserMigration).not_to exist - end - end + expect(assigns(:impersonation_error_text)).to eq(_("You cannot impersonate an internal user")) + end + end - context 'hard-delete' do - it 'succeeds' do - delete :destroy, params: { id: user.username, hard_delete: true } - - 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 - end - end - end + context "when the user is a project bot" do + before do + user.update!(user_type: :project_bot) + end + + it 'sets impersonation_error_text' do + get :show, params: { id: user.username.downcase } + + expect(assigns(:impersonation_error_text)).to eq(_("You cannot impersonate a user who cannot log in")) end end end - context 'when user_destroy_with_limited_execution_time_worker is disabled' do - before do - stub_feature_flags(user_destroy_with_limited_execution_time_worker: false) + describe 'can_impersonate' do + context 'when user can be impersonated' do + it 'sets can_impersonate to true' do + get :show, params: { id: user.username.downcase } + + expect(assigns(:can_impersonate)).to eq(true) + end end - it 'deletes user and ghosts their contributions' do - delete :destroy, params: { id: user.username }, format: :json + context 'when impersonation is already in progress' do + let(:admin2) { create(:admin) } - expect(response).to have_gitlab_http_status(:ok) - expect(User.exists?(user.id)).to be_falsy - expect(issue.reload.author).to be_ghost + before do + post :impersonate, params: { id: admin2.username } + end + + it 'sets can_impersonate to false' do + get :show, params: { id: user.username.downcase } + + expect(assigns(:can_impersonate)).to eq(false) + end end - it 'deletes the user and their contributions when hard delete is specified' do - delete :destroy, params: { id: user.username, hard_delete: true }, format: :json + context 'when user cannot log in' do + before do + user.update!(user_type: :project_bot) + end + + it 'sets can_impersonate to false' do + get :show, params: { id: user.username.downcase } - expect(response).to have_gitlab_http_status(:ok) - expect(User.exists?(user.id)).to be_falsy - expect(Issue.exists?(issue.id)).to be_falsy + expect(assigns(:can_impersonate)).to eq(false) + end end + end + end - context 'prerequisites for account deletion' do - context 'solo-owned groups' do - let(:group) { create(:group) } + describe 'DELETE #destroy', :sidekiq_might_not_need_inline do + let(:project) { create(:project, namespace: user.namespace) } + let!(:issue) { create(:issue, author: user) } - context 'if the user is the sole owner of at least one group' do - before do - create(:group_member, :owner, group: group, user: user) - end + before do + project.add_developer(user) + end - context 'soft-delete' do - it 'fails' do - delete :destroy, params: { id: user.username } + it 'initiates user removal' do + delete :destroy, params: { id: user.username }, format: :json - message = s_('AdminUsers|You must transfer ownership or delete the groups owned by this user before you can delete their account') + expect(response).to have_gitlab_http_status(:ok) + expect( + Users::GhostUserMigration.where(user: user, + initiator_user: admin, + hard_delete: false) + ).to be_exists + end - expect(flash[:alert]).to eq(message) - expect(response).to have_gitlab_http_status(:see_other) - expect(response).to redirect_to admin_user_path(user) - expect(User.exists?(user.id)).to be_truthy - end - 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 + end - context 'hard-delete' do - it 'succeeds' do - delete :destroy, params: { id: user.username, hard_delete: true } + context 'prerequisites for account deletion' do + context 'solo-owned groups' do + let(:group) { create(:group) } + + context 'if the user is the sole owner of at least one group' do + before do + create(:group_member, :owner, group: group, user: user) + end + + context 'soft-delete' do + it 'fails' do + delete :destroy, params: { id: user.username } + + message = s_('AdminUsers|You must transfer ownership or delete the groups owned by this user before you can delete their account') + + expect(flash[:alert]).to eq(message) + expect(response).to have_gitlab_http_status(:see_other) + expect(response).to redirect_to admin_user_path(user) + expect(Users::GhostUserMigration).not_to exist + end + end - expect(response).to redirect_to(admin_users_path) - expect(flash[:notice]).to eq(_('The user is being deleted.')) - expect(User.exists?(user.id)).to be_falsy - end + context 'hard-delete' do + it 'succeeds' do + delete :destroy, params: { id: user.username, hard_delete: true } + + 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 end end end @@ -200,27 +249,13 @@ RSpec.describe Admin::UsersController do context 'when rejecting a pending user' do let(:user) { create(:user, :blocked_pending_approval) } - context 'when user_destroy_with_limited_execution_time_worker is enabled' do - it 'initiates user removal', :sidekiq_inline do - subject - - expect( - Users::GhostUserMigration.where(user: user, - initiator_user: admin) - ).to be_exists - end - end - - context 'when user_destroy_with_limited_execution_time_worker is disabled' do - before do - stub_feature_flags(user_destroy_with_limited_execution_time_worker: false) - end - - it 'hard deletes the user', :sidekiq_inline do - subject + it 'initiates user removal', :sidekiq_inline do + subject - expect(User.exists?(user.id)).to be_falsy - end + expect( + Users::GhostUserMigration.where(user: user, + initiator_user: admin) + ).to be_exists end it 'displays the rejection message' do @@ -909,6 +944,60 @@ RSpec.describe Admin::UsersController do expect(session[:github_access_token]).to be_nil end + + context "when the user's password is expired" do + before do + user.update!(password_expires_at: 1.day.ago) + end + + it "shows a notice" do + post :impersonate, params: { id: user.username } + + expect(flash[:alert]).to eq(_('You cannot impersonate a user with an expired password')) + end + + it "doesn't sign us in as the user" do + post :impersonate, params: { id: user.username } + + expect(warden.user).to eq(admin) + end + end + + context "when the user is internal" do + before do + user.update!(user_type: :migration_bot) + end + + it "shows a notice" do + post :impersonate, params: { id: user.username } + + expect(flash[:alert]).to eq(_("You cannot impersonate an internal user")) + end + + it "doesn't sign us in as the user" do + post :impersonate, params: { id: user.username } + + expect(warden.user).to eq(admin) + end + end + + context "when the user is a project bot" do + before do + user.update!(user_type: :project_bot) + end + + it "shows a notice" do + post :impersonate, params: { id: user.username } + + expect(flash[:alert]).to eq(_("You cannot impersonate a user who cannot log in")) + end + + it "doesn't sign us in as the user" do + post :impersonate, params: { id: user.username } + + expect(warden.user).to eq(admin) + end + end end context "when impersonation is disabled" do diff --git a/spec/controllers/concerns/issuable_actions_spec.rb b/spec/controllers/concerns/issuable_actions_spec.rb index c3fef591b91..37d9dc080e1 100644 --- a/spec/controllers/concerns/issuable_actions_spec.rb +++ b/spec/controllers/concerns/issuable_actions_spec.rb @@ -6,8 +6,8 @@ RSpec.describe IssuableActions do let(:project) { double('project') } let(:user) { double('user') } let(:issuable) { double('issuable') } - let(:finder_params_for_issuable) { {} } - let(:notes_result) { double('notes_result') } + let(:finder_params_for_issuable) { { project: project, target: issuable } } + let(:notes_result) { [] } let(:discussion_serializer) { double('discussion_serializer') } let(:controller) do @@ -55,13 +55,20 @@ RSpec.describe IssuableActions do end it 'instantiates and calls NotesFinder as expected' do + expect(issuable).to receive(:to_ability_name).and_return('issue') + expect(issuable).to receive(:project).and_return(project) + expect(Ability).to receive(:allowed?).at_least(1).and_return(true) expect(Discussion).to receive(:build_collection).and_return([]) expect(DiscussionSerializer).to receive(:new).and_return(discussion_serializer) expect(NotesFinder).to receive(:new).with(user, finder_params_for_issuable).and_call_original expect_any_instance_of(NotesFinder).to receive(:execute).and_return(notes_result) - expect(notes_result).to receive_messages(inc_relations_for_view: notes_result, includes: notes_result, fresh: notes_result) + expect(notes_result).to receive_messages( + with_web_entity_associations: notes_result, + inc_relations_for_view: notes_result, + fresh: notes_result + ) controller.discussions end diff --git a/spec/controllers/concerns/preferred_language_switcher_spec.rb b/spec/controllers/concerns/preferred_language_switcher_spec.rb new file mode 100644 index 00000000000..40d6ac10c37 --- /dev/null +++ b/spec/controllers/concerns/preferred_language_switcher_spec.rb @@ -0,0 +1,51 @@ +# frozen_string_literal: true + +require 'spec_helper' + +RSpec.describe PreferredLanguageSwitcher, type: :controller do + controller(ActionController::Base) do + include PreferredLanguageSwitcher # rubocop:disable RSpec/DescribedClass + + before_action :init_preferred_language, only: :new + + def new + render html: 'new page' + end + end + + context 'when first visit' do + before do + get :new + end + + it 'sets preferred_language to default' do + expect(cookies[:preferred_language]).to eq Gitlab::CurrentSettings.default_preferred_language + end + end + + context 'when preferred language in cookies has been modified' do + let(:user_preferred_language) { nil } + + before do + cookies[:preferred_language] = user_preferred_language + + get :new + end + + context 'with a valid value' do + let(:user_preferred_language) { 'zh_CN' } + + it 'keeps preferred language unchanged' do + expect(cookies[:preferred_language]).to eq user_preferred_language + end + end + + context 'with an invalid value' do + let(:user_preferred_language) { 'xxx' } + + it 'sets preferred_language to default' do + expect(cookies[:preferred_language]).to eq Gitlab::CurrentSettings.default_preferred_language + end + end + end +end diff --git a/spec/controllers/concerns/renders_commits_spec.rb b/spec/controllers/concerns/renders_commits_spec.rb index acdeb98bb16..6a504681527 100644 --- a/spec/controllers/concerns/renders_commits_spec.rb +++ b/spec/controllers/concerns/renders_commits_spec.rb @@ -43,7 +43,7 @@ RSpec.describe RendersCommits do context 'rendering commits' do render_views - it 'avoids N + 1' do + it 'avoids N + 1', :request_store do stub_const("MergeRequestDiff::COMMITS_SAFE_SIZE", 5) control_count = ActiveRecord::QueryRecorder.new do @@ -59,7 +59,7 @@ RSpec.describe RendersCommits do end describe '.prepare_commits_for_rendering' do - it 'avoids N+1' do + it 'avoids N+1', :request_store do control = ActiveRecord::QueryRecorder.new do subject.prepare_commits_for_rendering(merge_request.commits.take(1)) end diff --git a/spec/controllers/concerns/send_file_upload_spec.rb b/spec/controllers/concerns/send_file_upload_spec.rb index 32304815bbb..0b24387483b 100644 --- a/spec/controllers/concerns/send_file_upload_spec.rb +++ b/spec/controllers/concerns/send_file_upload_spec.rb @@ -18,6 +18,12 @@ RSpec.describe SendFileUpload do end end + let(:cdn_uploader_class) do + Class.new(uploader_class) do + include ObjectStorage::CDN::Concern + end + end + let(:controller_class) do Class.new do include SendFileUpload @@ -269,5 +275,28 @@ RSpec.describe SendFileUpload do it_behaves_like 'handles image resize requests' end + + context 'when CDN-enabled remote file is used' do + let(:uploader) { cdn_uploader_class.new(object, :file) } + let(:request) { instance_double('ActionDispatch::Request', remote_ip: '18.245.0.42') } + let(:signed_url) { 'https://cdn.example.org.test' } + let(:cdn_provider) { instance_double('ObjectStorage::CDN::GoogleCDN', signed_url: signed_url) } + + before do + stub_uploads_object_storage(uploader: cdn_uploader_class) + uploader.object_store = ObjectStorage::Store::REMOTE + uploader.store!(temp_file) + allow(Gitlab.config.uploads.object_store).to receive(:proxy_download) { false } + end + + it 'sends a file when CDN URL' do + expect(uploader).to receive(:use_cdn?).and_return(true) + expect(uploader).to receive(:cdn_provider).and_return(cdn_provider) + expect(controller).to receive(:request).and_return(request) + expect(controller).to receive(:redirect_to).with(signed_url) + + subject + end + end end end diff --git a/spec/controllers/confirmations_controller_spec.rb b/spec/controllers/confirmations_controller_spec.rb index 111bfb24c7e..773a416dcb4 100644 --- a/spec/controllers/confirmations_controller_spec.rb +++ b/spec/controllers/confirmations_controller_spec.rb @@ -10,17 +10,27 @@ RSpec.describe ConfirmationsController do end describe '#show' do + let_it_be_with_reload(:user) { create(:user, :unconfirmed) } + let(:confirmation_token) { user.confirmation_token } + render_views def perform_request get :show, params: { confirmation_token: confirmation_token } end - context 'user is already confirmed' do - let_it_be_with_reload(:user) { create(:user, :unconfirmed) } + context 'when signup info is required' do + before do + allow(controller).to receive(:current_user) { user } + user.set_role_required! + end - let(:confirmation_token) { user.confirmation_token } + it 'does not redirect' do + expect(perform_request).not_to redirect_to(users_sign_up_welcome_path) + end + end + context 'user is already confirmed' do before do user.confirm end @@ -57,10 +67,6 @@ RSpec.describe ConfirmationsController do end context 'user accesses the link after the expiry of confirmation token has passed' do - let_it_be_with_reload(:user) { create(:user, :unconfirmed) } - - let(:confirmation_token) { user.confirmation_token } - before do allow(Devise).to receive(:confirm_within).and_return(1.day) end @@ -133,6 +139,17 @@ RSpec.describe ConfirmationsController do stub_feature_flags(identity_verification: false) end + context 'when signup info is required' do + before do + allow(controller).to receive(:current_user) { user } + user.set_role_required! + end + + it 'does not redirect' do + expect(perform_request).not_to redirect_to(users_sign_up_welcome_path) + end + end + context 'when reCAPTCHA is disabled' do before do stub_application_setting(recaptcha_enabled: false) diff --git a/spec/controllers/dashboard_controller_spec.rb b/spec/controllers/dashboard_controller_spec.rb index 21810f64cb4..ea12b0c5ad7 100644 --- a/spec/controllers/dashboard_controller_spec.rb +++ b/spec/controllers/dashboard_controller_spec.rb @@ -41,20 +41,6 @@ RSpec.describe DashboardController do expect(assigns[:issues].map(&:id)).to include(task.id) end - - context 'when work_items is disabled' do - before do - stub_feature_flags(work_items: false) - end - - it 'does not include tasks in issue list' do - task = create(:work_item, :task, project: project, author: user) - - get :issues, params: { author_id: user.id } - - expect(assigns[:issues].map(&:id)).not_to include(task.id) - end - end end describe 'GET merge requests' do diff --git a/spec/controllers/explore/groups_controller_spec.rb b/spec/controllers/explore/groups_controller_spec.rb index 310fe609cf1..a3bd8102462 100644 --- a/spec/controllers/explore/groups_controller_spec.rb +++ b/spec/controllers/explore/groups_controller_spec.rb @@ -9,31 +9,43 @@ RSpec.describe Explore::GroupsController do sign_in(user) end - it 'renders group trees' do - expect(described_class).to include(GroupTree) - end + shared_examples 'explore groups' do + it 'renders group trees' do + expect(described_class).to include(GroupTree) + end - it 'includes public projects' do - member_of_group = create(:group) - member_of_group.add_developer(user) - public_group = create(:group, :public) + it 'includes public projects' do + member_of_group = create(:group) + member_of_group.add_developer(user) + public_group = create(:group, :public) - get :index + get :index - expect(assigns(:groups)).to contain_exactly(member_of_group, public_group) - end + expect(assigns(:groups)).to contain_exactly(member_of_group, public_group) + end - context 'restricted visibility level is public' do - before do - sign_out(user) + context 'restricted visibility level is public' do + before do + sign_out(user) - stub_application_setting(restricted_visibility_levels: [Gitlab::VisibilityLevel::PUBLIC]) + stub_application_setting(restricted_visibility_levels: [Gitlab::VisibilityLevel::PUBLIC]) + end + + it 'redirects to login page' do + get :index + + expect(response).to redirect_to new_user_session_path + end end + end - it 'redirects to login page' do - get :index + it_behaves_like 'explore groups' - expect(response).to redirect_to new_user_session_path + context 'generic_explore_groups flag is disabled' do + before do + stub_feature_flags(generic_explore_groups: false) end + + it_behaves_like 'explore groups' end end diff --git a/spec/controllers/explore/projects_controller_spec.rb b/spec/controllers/explore/projects_controller_spec.rb index bf578489916..5c977439af4 100644 --- a/spec/controllers/explore/projects_controller_spec.rb +++ b/spec/controllers/explore/projects_controller_spec.rb @@ -208,19 +208,26 @@ RSpec.describe Explore::ProjectsController do render_views # some N+1 queries still exist - it 'avoids N+1 queries' do - projects = create_list(:project, 3, :repository, :public) - projects.each do |project| - pipeline = create(:ci_pipeline, :success, project: project, sha: project.commit.id) - create(:commit_status, :success, pipeline: pipeline, ref: pipeline.ref) + it 'avoids N+1 queries', :request_store do + # Because we enable the request store for this spec, Gitaly may report too many invocations. + # Allow N+1s here and when creating additional objects below because we're just creating test objects. + Gitlab::GitalyClient.allow_n_plus_1_calls do + projects = create_list(:project, 3, :repository, :public) + + projects.each do |project| + pipeline = create(:ci_pipeline, :success, project: project, sha: project.commit.id) + create(:commit_status, :success, pipeline: pipeline, ref: pipeline.ref) + end end control = ActiveRecord::QueryRecorder.new { get endpoint } - new_projects = create_list(:project, 2, :repository, :public) - new_projects.each do |project| - pipeline = create(:ci_pipeline, :success, project: project, sha: project.commit.id) - create(:commit_status, :success, pipeline: pipeline, ref: pipeline.ref) + Gitlab::GitalyClient.allow_n_plus_1_calls do + new_projects = create_list(:project, 2, :repository, :public) + new_projects.each do |project| + pipeline = create(:ci_pipeline, :success, project: project, sha: project.commit.id) + create(:commit_status, :success, pipeline: pipeline, ref: pipeline.ref) + end end expect { get endpoint }.not_to exceed_query_limit(control).with_threshold(8) diff --git a/spec/controllers/graphql_controller_spec.rb b/spec/controllers/graphql_controller_spec.rb index 7c9236704ec..fe8b0291733 100644 --- a/spec/controllers/graphql_controller_spec.rb +++ b/spec/controllers/graphql_controller_spec.rb @@ -8,10 +8,6 @@ RSpec.describe GraphqlController do # two days is enough to make timezones irrelevant let_it_be(:last_activity_on) { 2.days.ago.to_date } - before do - stub_feature_flags(graphql: true) - end - describe 'rescue_from' do let_it_be(:message) { 'green ideas sleep furiously' } @@ -418,4 +414,114 @@ RSpec.describe GraphqlController do expect(log_payload.dig(:exception_object)).to eq(exception) end end + + describe 'removal of deprecated items' do + let(:mock_schema) do + Class.new(GraphQL::Schema) do + lazy_resolve ::Gitlab::Graphql::Lazy, :force + + query(Class.new(::Types::BaseObject) do + graphql_name 'Query' + + field :foo, GraphQL::Types::Boolean, + deprecated: { milestone: '0.1', reason: :renamed } + + field :bar, (Class.new(::Types::BaseEnum) do + graphql_name 'BarEnum' + + value 'FOOBAR', value: 'foobar', deprecated: { milestone: '0.1', reason: :renamed } + end) + + field :baz, GraphQL::Types::Boolean do + argument :arg, String, required: false, deprecated: { milestone: '0.1', reason: :renamed } + end + + def foo + false + end + + def bar + 'foobar' + end + + def baz(arg:) + false + end + end) + end + end + + before do + allow(GitlabSchema).to receive(:execute).and_wrap_original do |method, *args| + mock_schema.execute(*args) + end + end + + context 'without `remove_deprecated` param' do + let(:params) { { query: '{ foo bar baz(arg: "test") }' } } + + subject { post :execute, params: params } + + it "sets context's `remove_deprecated` value to false" do + subject + + expect(assigns(:context)[:remove_deprecated]).to be false + end + + it 'returns deprecated items in response' do + subject + + expect(json_response).to include('data' => { 'foo' => false, 'bar' => 'FOOBAR', 'baz' => false }) + end + end + + context 'with `remove_deprecated` param' do + let(:params) { { remove_deprecated: 'true' } } + + subject { post :execute, params: params } + + it "sets context's `remove_deprecated` value to true" do + subject + + expect(assigns(:context)[:remove_deprecated]).to be true + end + + it 'does not allow deprecated field' do + params[:query] = '{ foo }' + + subject + + expect(json_response).not_to include('data' => { 'foo' => false }) + expect(json_response).to include( + 'errors' => include(a_hash_including('message' => /Field 'foo' doesn't exist on type 'Query'/)) + ) + end + + it 'does not allow deprecated enum value' do + params[:query] = '{ bar }' + + subject + + expect(json_response).not_to include('data' => { 'bar' => 'FOOBAR' }) + expect(json_response).to include( + 'errors' => include( + a_hash_including( + 'message' => /`Query.bar` returned `"foobar"` at `bar`, but this isn't a valid value for `BarEnum`/ + ) + ) + ) + end + + it 'does not allow deprecated argument' do + params[:query] = '{ baz(arg: "test") }' + + subject + + expect(json_response).not_to include('data' => { 'bar' => 'FOOBAR' }) + expect(json_response).to include( + 'errors' => include(a_hash_including('message' => /Field 'baz' doesn't accept argument 'arg'/)) + ) + end + end + end end diff --git a/spec/controllers/groups/children_controller_spec.rb b/spec/controllers/groups/children_controller_spec.rb index 04cf7785f1e..f05551432fa 100644 --- a/spec/controllers/groups/children_controller_spec.rb +++ b/spec/controllers/groups/children_controller_spec.rb @@ -277,7 +277,7 @@ RSpec.describe Groups::ChildrenController do 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 ) } + let!(:first_page_projects) { create_list(:project, per_page, :public, namespace: group) } it 'has projects on the first page' do get :index, params: { group_id: group.to_param, sort: 'id_desc' }, format: :json diff --git a/spec/controllers/groups/group_members_controller_spec.rb b/spec/controllers/groups/group_members_controller_spec.rb index a3659ae9163..4e5dc01f466 100644 --- a/spec/controllers/groups/group_members_controller_spec.rb +++ b/spec/controllers/groups/group_members_controller_spec.rb @@ -342,6 +342,41 @@ RSpec.describe Groups::GroupMembersController do end end + context 'with owners from a parent' do + context 'when top-level group' do + context 'with group sharing' do + let!(:subgroup) { create(:group, parent: group) } + + before do + create(:group_group_link, :owner, shared_group: group, shared_with_group: subgroup) + create(:group_member, :owner, group: subgroup) + end + + it 'does not allow removal of last direct group owner' do + delete :leave, params: { group_id: group } + + expect(response).to have_gitlab_http_status(:forbidden) + end + end + end + + context 'when subgroup' do + let!(:subgroup) { create(:group, parent: group) } + + before do + subgroup.add_owner(user) + end + + it 'allows removal of last direct group owner', :aggregate_failures do + delete :leave, params: { group_id: subgroup } + + expect(controller).to set_flash.to "You left the \"#{subgroup.human_name}\" group." + expect(response).to redirect_to(dashboard_groups_path) + expect(subgroup.users).not_to include user + end + end + end + context 'and there is another owner' do before do create(:group_member, :owner, source: group) diff --git a/spec/controllers/groups/registry/repositories_controller_spec.rb b/spec/controllers/groups/registry/repositories_controller_spec.rb index 9ac19b06718..62c15201a95 100644 --- a/spec/controllers/groups/registry/repositories_controller_spec.rb +++ b/spec/controllers/groups/registry/repositories_controller_spec.rb @@ -117,7 +117,7 @@ RSpec.describe Groups::Registry::RepositoriesController do it_behaves_like 'a package tracking event', described_class.name, 'list_repositories' context 'with project in subgroup' do - let_it_be(:test_group) { create(:group, parent: group ) } + let_it_be(:test_group) { create(:group, parent: group) } it_behaves_like 'renders a list of repositories' diff --git a/spec/controllers/groups/releases_controller_spec.rb b/spec/controllers/groups/releases_controller_spec.rb index 7dd0bc6206a..40e8cb4efc5 100644 --- a/spec/controllers/groups/releases_controller_spec.rb +++ b/spec/controllers/groups/releases_controller_spec.rb @@ -42,7 +42,7 @@ RSpec.describe Groups::ReleasesController do end it 'does not return any releases' do - expect(json_response.map { |r| r['tag'] } ).to be_empty + expect(json_response.map { |r| r['tag'] }).to be_empty end it 'returns OK' do @@ -56,7 +56,7 @@ RSpec.describe Groups::ReleasesController do index - expect(json_response.map { |r| r['tag'] } ).to match_array(%w(p2 p1 v2 v1)) + expect(json_response.map { |r| r['tag'] }).to match_array(%w(p2 p1 v2 v1)) end end diff --git a/spec/controllers/groups/runners_controller_spec.rb b/spec/controllers/groups/runners_controller_spec.rb index 6dbf0803892..2add3cd3b18 100644 --- a/spec/controllers/groups/runners_controller_spec.rb +++ b/spec/controllers/groups/runners_controller_spec.rb @@ -168,7 +168,7 @@ RSpec.describe Groups::RunnersController do new_desc = runner.description.swapcase expect do - post :update, params: params.merge(runner: { description: new_desc } ) + post :update, params: params.merge(runner: { description: new_desc }) end.to change { runner.ensure_runner_queue_value } expect(response).to have_gitlab_http_status(:found) @@ -179,7 +179,7 @@ RSpec.describe Groups::RunnersController do new_desc = instance_runner.description.swapcase expect do - post :update, params: params_runner_instance.merge(runner: { description: new_desc } ) + post :update, params: params_runner_instance.merge(runner: { description: new_desc }) end.to not_change { instance_runner.ensure_runner_queue_value } .and not_change { instance_runner.description } @@ -190,7 +190,7 @@ RSpec.describe Groups::RunnersController do new_desc = project_runner.description.swapcase expect do - post :update, params: params_runner_project.merge(runner: { description: new_desc } ) + post :update, params: params_runner_project.merge(runner: { description: new_desc }) end.to change { project_runner.ensure_runner_queue_value } expect(response).to have_gitlab_http_status(:found) @@ -207,7 +207,7 @@ RSpec.describe Groups::RunnersController do old_desc = runner.description expect do - post :update, params: params.merge(runner: { description: old_desc.swapcase } ) + post :update, params: params.merge(runner: { description: old_desc.swapcase }) end.not_to change { runner.ensure_runner_queue_value } expect(response).to have_gitlab_http_status(:not_found) @@ -218,7 +218,7 @@ RSpec.describe Groups::RunnersController do old_desc = instance_runner.description expect do - post :update, params: params_runner_instance.merge(runner: { description: old_desc.swapcase } ) + post :update, params: params_runner_instance.merge(runner: { description: old_desc.swapcase }) end.not_to change { instance_runner.ensure_runner_queue_value } expect(response).to have_gitlab_http_status(:not_found) @@ -229,7 +229,7 @@ RSpec.describe Groups::RunnersController do old_desc = project_runner.description expect do - post :update, params: params_runner_project.merge(runner: { description: old_desc.swapcase } ) + post :update, params: params_runner_project.merge(runner: { description: old_desc.swapcase }) end.not_to change { project_runner.ensure_runner_queue_value } expect(response).to have_gitlab_http_status(:not_found) diff --git a/spec/controllers/groups/settings/repository_controller_spec.rb b/spec/controllers/groups/settings/repository_controller_spec.rb index cbf55218b94..73a205069f5 100644 --- a/spec/controllers/groups/settings/repository_controller_spec.rb +++ b/spec/controllers/groups/settings/repository_controller_spec.rb @@ -13,88 +13,73 @@ RSpec.describe Groups::Settings::RepositoryController do end describe 'POST create_deploy_token' do - context 'when ajax_new_deploy_token feature flag is disabled for the project' do - before do - stub_feature_flags(ajax_new_deploy_token: false) - entity.add_owner(user) - end + let(:good_deploy_token_params) do + { + name: 'name', + expires_at: 1.day.from_now.to_s, + username: 'deployer', + read_repository: '1', + deploy_token_type: DeployToken.deploy_token_types[:group_type] + } + end - it_behaves_like 'a created deploy token' do - let(:entity) { group } - let(:create_entity_params) { { group_id: group } } - let(:deploy_token_type) { DeployToken.deploy_token_types[:group_type] } - end + let(:request_params) do + { + group_id: group.to_param, + deploy_token: deploy_token_params + } end - context 'when ajax_new_deploy_token feature flag is enabled for the project' do - let(:good_deploy_token_params) do - { - name: 'name', - expires_at: 1.day.from_now.to_s, - username: 'deployer', - read_repository: '1', - deploy_token_type: DeployToken.deploy_token_types[:group_type] - } - end + before do + group.add_owner(user) + end + + subject { post :create_deploy_token, params: request_params, format: :json } - let(:request_params) do + context('a good request') do + let(:deploy_token_params) { good_deploy_token_params } + let(:expected_response) do { - group_id: group.to_param, - deploy_token: deploy_token_params + 'id' => be_a(Integer), + 'name' => deploy_token_params[:name], + 'username' => deploy_token_params[:username], + 'expires_at' => Time.zone.parse(deploy_token_params[:expires_at]), + 'token' => be_a(String), + 'expired' => false, + 'revoked' => false, + 'scopes' => deploy_token_params.inject([]) do |scopes, kv| + key, value = kv + key.to_s.start_with?('read_') && value.to_i != 0 ? scopes << key.to_s : scopes + end } end - before do - group.add_owner(user) - end + it 'creates the deploy token' do + subject - subject { post :create_deploy_token, params: request_params, format: :json } - - context('a good request') do - let(:deploy_token_params) { good_deploy_token_params } - let(:expected_response) do - { - 'id' => be_a(Integer), - 'name' => deploy_token_params[:name], - 'username' => deploy_token_params[:username], - 'expires_at' => Time.zone.parse(deploy_token_params[:expires_at]), - 'token' => be_a(String), - 'expired' => false, - 'revoked' => false, - 'scopes' => deploy_token_params.inject([]) do |scopes, kv| - key, value = kv - key.to_s.start_with?('read_') && value.to_i != 0 ? scopes << key.to_s : scopes - end - } - end - - it 'creates the deploy token' do - subject - - expect(response).to have_gitlab_http_status(:created) - expect(response).to match_response_schema('public_api/v4/deploy_token') - expect(json_response).to match(expected_response) - end + expect(response).to have_gitlab_http_status(:created) + expect(response).to match_response_schema('public_api/v4/deploy_token') + expect(json_response).to match(expected_response) end + end - context('a bad request') do - let(:deploy_token_params) { good_deploy_token_params.except(:read_repository) } - let(:expected_response) { { 'message' => "Scopes can't be blank" } } + context('a bad request') do + let(:deploy_token_params) { good_deploy_token_params.except(:read_repository) } + let(:expected_response) { { 'message' => "Scopes can't be blank" } } - it 'does not create the deploy token' do - subject + it 'does not create the deploy token' do + subject - expect(response).to have_gitlab_http_status(:bad_request) - expect(json_response).to match(expected_response) - end + expect(response).to have_gitlab_http_status(:bad_request) + expect(json_response).to match(expected_response) end + end - context('an invalid request') do - let(:deploy_token_params) { good_deploy_token_params.except(:name) } + context('an invalid request') do + let(:deploy_token_params) { good_deploy_token_params.except(:name) } - it 'raises a validation error' do - expect { subject }.to raise_error(ActiveRecord::StatementInvalid) - end + it 'raises a validation error' do + expect { subject }.to raise_error(ActiveRecord::StatementInvalid) end end end diff --git a/spec/controllers/groups_controller_spec.rb b/spec/controllers/groups_controller_spec.rb index 5bbe236077c..22a406b3197 100644 --- a/spec/controllers/groups_controller_spec.rb +++ b/spec/controllers/groups_controller_spec.rb @@ -42,21 +42,15 @@ RSpec.describe GroupsController, factory_default: :keep do end end - shared_examples 'details view' do - let(:namespace) { group } + shared_examples 'details view as atom' do + let!(:event) { create(:event, project: project) } + let(:format) { :atom } it { is_expected.to render_template('groups/show') } - context 'as atom' do - let!(:event) { create(:event, project: project) } - let(:format) { :atom } - - it { is_expected.to render_template('groups/show') } - - it 'assigns events for all the projects in the group', :sidekiq_might_not_need_inline do - subject - expect(assigns(:events).map(&:id)).to contain_exactly(event.id) - end + it 'assigns events for all the projects in the group' do + subject + expect(assigns(:events).map(&:id)).to contain_exactly(event.id) end end @@ -70,7 +64,9 @@ RSpec.describe GroupsController, factory_default: :keep do subject { get :show, params: { id: group.to_param }, format: format } context 'when the group is not importing' do - it_behaves_like 'details view' + it { is_expected.to render_template('groups/show') } + + it_behaves_like 'details view as atom' it 'tracks page views', :snowplow do subject @@ -115,7 +111,9 @@ RSpec.describe GroupsController, factory_default: :keep do subject { get :details, params: { id: group.to_param }, format: format } - it_behaves_like 'details view' + it { is_expected.to redirect_to(group_path(group)) } + + it_behaves_like 'details view as atom' end describe 'GET edit' do @@ -672,7 +670,7 @@ RSpec.describe GroupsController, factory_default: :keep do end context 'when there is a conflicting group path' do - let!(:conflict_group) { create(:group, path: SecureRandom.hex(12) ) } + let!(:conflict_group) { create(:group, path: SecureRandom.hex(12)) } let!(:old_name) { group.name } it 'does not render references to the conflicting group' do diff --git a/spec/controllers/oauth/authorizations_controller_spec.rb b/spec/controllers/oauth/authorizations_controller_spec.rb index fb90a70d91d..5185aa64d9f 100644 --- a/spec/controllers/oauth/authorizations_controller_spec.rb +++ b/spec/controllers/oauth/authorizations_controller_spec.rb @@ -213,6 +213,75 @@ RSpec.describe Oauth::AuthorizationsController do expect(response).to redirect_to(new_user_session_path) end end + + context 'when the user is admin' do + context 'when disable_admin_oauth_scopes is set' do + before do + stub_application_setting(disable_admin_oauth_scopes: true) + scopes = Doorkeeper::OAuth::Scopes.from_string('api') + + allow(Doorkeeper.configuration).to receive(:scopes).and_return(scopes) + end + + let(:user) { create(:user, :admin) } + + it 'returns 200 and renders forbidden view' do + subject + + expect(response).to have_gitlab_http_status(:ok) + expect(response).to render_template('doorkeeper/authorizations/forbidden') + end + end + + context 'when disable_admin_oauth_scopes is set and the application is trusted' do + before do + stub_application_setting(disable_admin_oauth_scopes: true) + + application.update!(trusted: true) + end + + let(:application_scopes) { 'api' } + let(:user) { create(:user, :admin) } + + it 'returns 200 and renders redirect view' do + subject + + expect(response).to have_gitlab_http_status(:ok) + expect(response).to render_template('doorkeeper/authorizations/redirect') + end + end + + context 'when disable_admin_oauth_scopes is disabled' do + before do + stub_application_setting(disable_admin_oauth_scopes: false) + end + + let(:application_scopes) { 'api' } + let(:user) { create(:user, :admin) } + + it 'returns 200 and renders new view' do + subject + + expect(response).to have_gitlab_http_status(:ok) + expect(response).to render_template('doorkeeper/authorizations/new') + end + end + end + + context 'when the user is not admin' do + context 'when disable_admin_oauth_scopes is enabled' do + before do + stub_application_setting(disable_admin_oauth_scopes: true) + end + + it 'returns 200 and renders new view' do + subject + + expect(response).to have_gitlab_http_status(:ok) + expect(response).to render_template('doorkeeper/authorizations/new') + end + end + end end describe 'POST #create' do diff --git a/spec/controllers/omniauth_callbacks_controller_spec.rb b/spec/controllers/omniauth_callbacks_controller_spec.rb index df5da29495e..0560ccb25dd 100644 --- a/spec/controllers/omniauth_callbacks_controller_spec.rb +++ b/spec/controllers/omniauth_callbacks_controller_spec.rb @@ -10,7 +10,7 @@ RSpec.describe OmniauthCallbacksController, type: :controller do let(:additional_info) { {} } before do - @original_env_config_omniauth_auth = mock_auth_hash(provider.to_s, extern_uid, user.email, additional_info: additional_info ) + @original_env_config_omniauth_auth = mock_auth_hash(provider.to_s, extern_uid, user.email, additional_info: additional_info) stub_omniauth_provider(provider, context: request) end diff --git a/spec/controllers/passwords_controller_spec.rb b/spec/controllers/passwords_controller_spec.rb index e4be2fbef3c..9494f55c631 100644 --- a/spec/controllers/passwords_controller_spec.rb +++ b/spec/controllers/passwords_controller_spec.rb @@ -78,6 +78,22 @@ RSpec.describe PasswordsController do end end + context 'password is weak' do + let(:password) { "password" } + + it 'tracks the event' do + subject + + expect(response.body).to have_content("must not contain commonly used combinations of words and letters") + expect_snowplow_event( + category: 'Gitlab::Tracking::Helpers::WeakPasswordErrorEvent', + action: 'track_weak_password_error', + controller: 'PasswordsController', + method: 'create' + ) + end + end + it 'sets the username and caller_id in the context' do expect(controller).to receive(:update).and_wrap_original do |m, *args| m.call(*args) diff --git a/spec/controllers/profiles/personal_access_tokens_controller_spec.rb b/spec/controllers/profiles/personal_access_tokens_controller_spec.rb index 8dee0490fd6..044ce8f397a 100644 --- a/spec/controllers/profiles/personal_access_tokens_controller_spec.rb +++ b/spec/controllers/profiles/personal_access_tokens_controller_spec.rb @@ -3,11 +3,11 @@ require 'spec_helper' RSpec.describe Profiles::PersonalAccessTokensController do - let(:user) { create(:user) } + let(:access_token_user) { create(:user) } let(:token_attributes) { attributes_for(:personal_access_token) } before do - sign_in(user) + sign_in(access_token_user) end describe '#create' do @@ -49,13 +49,27 @@ RSpec.describe Profiles::PersonalAccessTokensController do end end + describe 'GET /-/profile/personal_access_tokens' do + let(:get_access_tokens) do + get :index + response + end + + subject(:get_access_tokens_with_page) do + get :index, params: { page: 1 } + response + end + + it_behaves_like 'GET access tokens are paginated and ordered' + end + describe '#index' do - let!(:active_personal_access_token) { create(:personal_access_token, user: user) } + let!(:active_personal_access_token) { create(:personal_access_token, user: access_token_user) } before do # Impersonation and inactive personal tokens are ignored - create(:personal_access_token, :impersonation, user: user) - create(:personal_access_token, :revoked, user: user) + create(:personal_access_token, :impersonation, user: access_token_user) + create(:personal_access_token, :revoked, user: access_token_user) get :index end @@ -63,7 +77,7 @@ RSpec.describe Profiles::PersonalAccessTokensController do active_personal_access_tokens_detail = ::PersonalAccessTokenSerializer.new.represent([active_personal_access_token]) - expect(assigns(:active_personal_access_tokens).to_json).to eq(active_personal_access_tokens_detail.to_json) + expect(assigns(:active_access_tokens).to_json).to eq(active_personal_access_tokens_detail.to_json) end it "sets PAT name and scopes" do @@ -86,73 +100,10 @@ RSpec.describe Profiles::PersonalAccessTokensController do expect(response).to have_gitlab_http_status(:not_found) end - context "access_token_pagination feature flag is enabled" do - before do - stub_feature_flags(access_token_pagination: true) - allow(Kaminari.config).to receive(:default_per_page).and_return(1) - create(:personal_access_token, user: user) - end - - it "returns paginated response" do - get :index, params: { page: 1 } - expect(assigns(:active_personal_access_tokens).count).to eq(1) - end - - it 'adds appropriate headers' do - get :index, params: { page: 1 } - expect_header('X-Per-Page', '1') - expect_header('X-Page', '1') - expect_header('X-Next-Page', '2') - expect_header('X-Total', '2') - end - end - - context "tokens returned are ordered" do - let(:expires_1_day_from_now) { 1.day.from_now.to_date } - let(:expires_2_day_from_now) { 2.days.from_now.to_date } - - before do - create(:personal_access_token, user: user, name: "Token1", expires_at: expires_1_day_from_now) - create(:personal_access_token, user: user, name: "Token2", expires_at: expires_2_day_from_now) - end - - it "orders token list ascending on expires_at" do - get :index - - first_token = assigns(:active_personal_access_tokens).first.as_json - expect(first_token['name']).to eq("Token1") - expect(first_token['expires_at']).to eq(expires_1_day_from_now.strftime("%Y-%m-%d")) - end - - it "orders tokens on id in case token has same expires_at" do - create(:personal_access_token, user: user, name: "Token3", expires_at: expires_1_day_from_now) - - get :index - - first_token = assigns(:active_personal_access_tokens).first.as_json - expect(first_token['name']).to eq("Token3") - expect(first_token['expires_at']).to eq(expires_1_day_from_now.strftime("%Y-%m-%d")) - - second_token = assigns(:active_personal_access_tokens).second.as_json - expect(second_token['name']).to eq("Token1") - expect(second_token['expires_at']).to eq(expires_1_day_from_now.strftime("%Y-%m-%d")) - end - end - - context "access_token_pagination feature flag is disabled" do - before do - stub_feature_flags(access_token_pagination: false) - create(:personal_access_token, user: user) - end + it 'returns tokens for json format' do + get :index, params: { format: :json } - it "returns all tokens in system" do - get :index, params: { page: 1 } - expect(assigns(:active_personal_access_tokens).count).to eq(2) - end + expect(json_response.count).to eq(1) end end - - def expect_header(header_name, header_val) - expect(response.headers[header_name]).to eq(header_val) - end end diff --git a/spec/controllers/projects/alerting/notifications_controller_spec.rb b/spec/controllers/projects/alerting/notifications_controller_spec.rb index b3feeb7c07b..5ce2950f95f 100644 --- a/spec/controllers/projects/alerting/notifications_controller_spec.rb +++ b/spec/controllers/projects/alerting/notifications_controller_spec.rb @@ -16,9 +16,6 @@ RSpec.describe Projects::Alerting::NotificationsController do end shared_examples 'process alert payload' do |notify_service_class| - let(:alert_1) { build(:alert_management_alert, project: project) } - let(:alert_2) { build(:alert_management_alert, project: project) } - let(:service_response) { ServiceResponse.success(payload: { alerts: [alert_1, alert_2] }) } let(:notify_service) { instance_double(notify_service_class, execute: service_response) } before do @@ -35,11 +32,14 @@ RSpec.describe Projects::Alerting::NotificationsController do it 'responds with the alert data' do make_request - expect(json_response).to contain_exactly( - { 'iid' => alert_1.iid, 'title' => alert_1.title }, - { 'iid' => alert_2.iid, 'title' => alert_2.title } - ) - expect(response).to have_gitlab_http_status(:ok) + if service_response.payload.present? + expect(json_response).to contain_exactly( + { 'iid' => alert_1.iid, 'title' => alert_1.title }, + { 'iid' => alert_2.iid, 'title' => alert_2.title } + ) + end + + expect(response).to have_gitlab_http_status(service_response.http_status) end it 'does not pass excluded parameters to the notify service' do @@ -146,6 +146,9 @@ RSpec.describe Projects::Alerting::NotificationsController do context 'with generic alert payload' do it_behaves_like 'process alert payload', Projects::Alerting::NotifyService do + let(:alert_1) { build(:alert_management_alert, project: project) } + let(:alert_2) { build(:alert_management_alert, project: project) } + let(:service_response) { ServiceResponse.success(payload: { alerts: [alert_1, alert_2] }) } let(:payload) { { title: 'Alert title' } } end end @@ -154,6 +157,7 @@ RSpec.describe Projects::Alerting::NotificationsController do include PrometheusHelpers it_behaves_like 'process alert payload', Projects::Prometheus::Alerts::NotifyService do + let(:service_response) { ServiceResponse.success(http_status: :created) } let(:payload) { prometheus_alert_payload } end end diff --git a/spec/controllers/projects/artifacts_controller_spec.rb b/spec/controllers/projects/artifacts_controller_spec.rb index f79a2c6a6d0..00efd7d7b56 100644 --- a/spec/controllers/projects/artifacts_controller_spec.rb +++ b/spec/controllers/projects/artifacts_controller_spec.rb @@ -30,28 +30,10 @@ RSpec.describe Projects::ArtifactsController do stub_feature_flags(artifacts_management_page: true) end - it 'sets the artifacts variable' do + it 'renders the page' do subject - expect(assigns(:artifacts)).to contain_exactly(*project.job_artifacts) - end - - it 'sets the total size variable' do - subject - - expect(assigns(:total_size)).to eq(project.job_artifacts.total_size) - end - - describe 'pagination' do - before do - stub_const("#{described_class}::MAX_PER_PAGE", 1) - end - - it 'paginates artifacts' do - subject - - expect(assigns(:artifacts)).to contain_exactly(project.reload.job_artifacts.last) - end + expect(response).to have_gitlab_http_status(:ok) end end @@ -65,18 +47,6 @@ RSpec.describe Projects::ArtifactsController do expect(response).to have_gitlab_http_status(:no_content) end - - it 'does not set the artifacts variable' do - subject - - expect(assigns(:artifacts)).to eq(nil) - end - - it 'does not set the total size variable' do - subject - - expect(assigns(:total_size)).to eq(nil) - end end end @@ -183,12 +153,17 @@ RSpec.describe Projects::ArtifactsController do end context 'when file is stored remotely' do + let(:cdn_config) {} + before do - stub_artifacts_object_storage + stub_artifacts_object_storage(cdn: cdn_config) create(:ci_job_artifact, :remote_store, :codequality, job: job) + allow(Gitlab::ApplicationContext).to receive(:push).and_call_original end it 'sends the codequality report' do + expect(Gitlab::ApplicationContext).to receive(:push).with(artifact: an_instance_of(Ci::JobArtifact)).and_call_original + expect(controller).to receive(:redirect_to).and_call_original download_artifact(file_type: file_type) @@ -201,6 +176,30 @@ RSpec.describe Projects::ArtifactsController do download_artifact(file_type: file_type, proxy: true) end end + + context 'when Google CDN is configured' do + let(:cdn_config) do + { + 'provider' => 'Google', + 'url' => 'https://cdn.example.org', + 'key_name' => 'some-key', + 'key' => Base64.urlsafe_encode64(SecureRandom.hex) + } + end + + before do + request.env['action_dispatch.remote_ip'] = '18.245.0.42' + end + + it 'redirects to a Google CDN request' do + expect(Gitlab::ApplicationContext).to receive(:push).with(artifact: an_instance_of(Ci::JobArtifact)).and_call_original + expect(Gitlab::ApplicationContext).to receive(:push).with(artifact_used_cdn: true).and_call_original + + download_artifact(file_type: file_type) + + expect(response.redirect_url).to start_with("https://cdn.example.org/") + end + end end end end @@ -228,8 +227,9 @@ RSpec.describe Projects::ArtifactsController do expect(response).to have_gitlab_http_status(:forbidden) expect(response.body).to include( 'You must have developer or higher permissions in the associated project to view job logs when debug trace is enabled. ' \ - 'To disable debug trace, set the 'CI_DEBUG_TRACE' variable to 'false' in your pipeline configuration or CI/CD settings. ' \ - 'If you need to view this job log, a project maintainer or owner must add you to the project with developer permissions or higher.' + 'To disable debug trace, set the 'CI_DEBUG_TRACE' and 'CI_DEBUG_SERVICES' variables to 'false' ' \ + 'in your pipeline configuration or CI/CD settings. If you must view this job log, a project maintainer or owner must ' \ + 'add you to the project with developer permissions or higher.' ) end end diff --git a/spec/controllers/projects/environments_controller_spec.rb b/spec/controllers/projects/environments_controller_spec.rb index 16a43bae674..5927f20df97 100644 --- a/spec/controllers/projects/environments_controller_spec.rb +++ b/spec/controllers/projects/environments_controller_spec.rb @@ -76,7 +76,7 @@ RSpec.describe Projects::EnvironmentsController do it 'handles search option properly' do get :index, params: environment_params(format: :json, search: 'staging/r') - expect(environments.map { |env| env['name'] } ).to contain_exactly('staging/review-1', 'staging/review-2') + expect(environments.map { |env| env['name'] }).to contain_exactly('staging/review-1', 'staging/review-2') expect(json_response['available_count']).to eq 2 expect(json_response['stopped_count']).to eq 1 end @@ -84,7 +84,7 @@ RSpec.describe Projects::EnvironmentsController do 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', + expect(environments.map { |env| env['name'] }).to contain_exactly('production', 'staging/review-1', 'staging/review-2') expect(json_response['available_count']).to eq 3 @@ -233,7 +233,7 @@ RSpec.describe Projects::EnvironmentsController do search: 'staging-1.0/z' }, format: :json) - expect(environments.map { |env| env['name'] } ).to eq(['staging-1.0/zzz']) + expect(environments.map { |env| env['name'] }).to eq(['staging-1.0/zzz']) expect(json_response['available_count']).to eq 1 expect(json_response['stopped_count']).to eq 0 end @@ -705,7 +705,7 @@ RSpec.describe Projects::EnvironmentsController do expect(json_response).to have_key('all_dashboards') expect(json_response['all_dashboards']).to be_an_instance_of(Array) - expect(json_response['all_dashboards']).to all( include('path', 'default', 'display_name') ) + expect(json_response['all_dashboards']).to all(include('path', 'default', 'display_name')) end end diff --git a/spec/controllers/projects/hooks_controller_spec.rb b/spec/controllers/projects/hooks_controller_spec.rb index ba7b712964c..18f16937505 100644 --- a/spec/controllers/projects/hooks_controller_spec.rb +++ b/spec/controllers/projects/hooks_controller_spec.rb @@ -29,6 +29,22 @@ RSpec.describe Projects::HooksController do { namespace_id: project.namespace, project_id: project, id: hook.id } end + context 'with an existing token' do + hook_params = { + token: WebHook::SECRET_MASK, + url: "http://example.com" + } + + it 'does not change a token' do + expect do + post :update, params: params.merge({ hook: hook_params }) + end.not_to change { hook.reload.token } + + expect(response).to have_gitlab_http_status(:found) + expect(flash[:alert]).to be_blank + end + end + it 'adds, updates and deletes URL variables' do hook.update!(url_variables: { 'a' => 'bar', 'b' => 'woo' }) @@ -106,8 +122,9 @@ RSpec.describe Projects::HooksController do it 'sets all parameters' do hook_params = { enable_ssl_verification: true, - token: "TEST TOKEN", - url: "http://example.com", + token: 'TEST TOKEN', + url: 'http://example.com', + branch_filter_strategy: 'regex', push_events: true, tag_push_events: true, @@ -124,13 +141,39 @@ RSpec.describe Projects::HooksController do url_variables: [{ key: 'token', value: 'some secret value' }] } - post :create, params: { namespace_id: project.namespace, project_id: project, hook: hook_params } + params = { namespace_id: project.namespace, project_id: project, hook: hook_params } + + expect { post :create, params: params }.to change(ProjectHook, :count).by(1) + + project_hook = ProjectHook.order_id_desc.take + + expect(project_hook).to have_attributes( + **hook_params.merge(url_variables: { 'token' => 'some secret value' }) + ) + expect(response).to have_gitlab_http_status(:found) + expect(flash[:alert]).to be_blank + end + + it 'ignores branch_filter_strategy when flag is disabled' do + stub_feature_flags(enhanced_webhook_support_regex: false) + hook_params = { + url: 'http://example.com', + branch_filter_strategy: 'regex', + push_events: true + } + params = { namespace_id: project.namespace, project_id: project, hook: hook_params } + + expect { post :create, params: params }.to change(ProjectHook, :count).by(1) + + project_hook = ProjectHook.order_id_desc.take + + expect(project_hook).to have_attributes( + url: 'http://example.com', + branch_filter_strategy: 'wildcard' + ) expect(response).to have_gitlab_http_status(:found) expect(flash[:alert]).to be_blank - expect(ProjectHook.count).to eq(1) - expect(ProjectHook.first).to have_attributes(hook_params.except(:url_variables)) - expect(ProjectHook.first).to have_attributes(url_variables: { 'token' => 'some secret value' }) end it 'alerts the user if the new hook is invalid' do @@ -186,7 +229,7 @@ RSpec.describe Projects::HooksController do context 'when the hook fails completely' do before do allow_next(::TestHooks::ProjectService) - .to receive(:execute).and_return({ message: 'All is woe' }) + .to receive(:execute).and_return(ServiceResponse.error(message: 'All is woe')) end it 'informs the user' do @@ -204,7 +247,7 @@ RSpec.describe Projects::HooksController do it 'prevents making test requests' do expect_next_instance_of(TestHooks::ProjectService) do |service| - expect(service).to receive(:execute).and_return(http_status: 200) + expect(service).to receive(:execute).and_return(ServiceResponse.success(payload: { http_status: 200 })) end 2.times { post :test, params: { namespace_id: project.namespace, project_id: project, id: hook } } diff --git a/spec/controllers/projects/issues_controller_spec.rb b/spec/controllers/projects/issues_controller_spec.rb index 0c3795540e0..8f26be442a7 100644 --- a/spec/controllers/projects/issues_controller_spec.rb +++ b/spec/controllers/projects/issues_controller_spec.rb @@ -168,75 +168,56 @@ RSpec.describe Projects::IssuesController do let_it_be(:task) { create(:issue, :task, project: project) } - context 'when work_items feature flag is enabled' do - shared_examples 'redirects to show work item page' do - it 'redirects to work item page' do - expect(response).to redirect_to(project_work_items_path(project, task.id, query)) - end - end - - context 'show action' do - let(:query) { { query: 'any' } } - + shared_examples 'redirects to show work item page' do + context 'when use_iid_in_work_items_path feature flag is disabled' do before do - get :show, params: { namespace_id: project.namespace, project_id: project, id: task.iid, **query } + stub_feature_flags(use_iid_in_work_items_path: false) end - it_behaves_like 'redirects to show work item page' - end - - context 'edit action' do - let(:query) { { query: 'any' } } + it 'redirects to work item page' do + make_request - before do - get :edit, params: { namespace_id: project.namespace, project_id: project, id: task.iid, **query } + expect(response).to redirect_to(project_work_items_path(project, task.id, query)) end - - it_behaves_like 'redirects to show work item page' end - context 'update action' do - before do - put :update, params: { namespace_id: project.namespace, project_id: project, id: task.iid, issue: { title: 'New title' } } - end + it 'redirects to work item page using iid' do + make_request - it_behaves_like 'redirects to show work item page' + expect(response).to redirect_to(project_work_items_path(project, task.iid, query.merge(iid_path: true))) end end - context 'when work_items feature flag is disabled' do - before do - stub_feature_flags(work_items: false) - end + context 'show action' do + let(:query) { { query: 'any' } } - shared_examples 'renders 404' do - it 'renders 404 for show action' do - expect(response).to have_gitlab_http_status(:not_found) + it_behaves_like 'redirects to show work item page' do + subject(:make_request) do + get :show, params: { namespace_id: project.namespace, project_id: project, id: task.iid, **query } end end + end - context 'show action' do - before do - get :show, params: { namespace_id: project.namespace, project_id: project, id: task.iid } - end - - it_behaves_like 'renders 404' - end + context 'edit action' do + let(:query) { { query: 'any' } } - context 'edit action' do - before do - get :edit, params: { namespace_id: project.namespace, project_id: project, id: task.iid } + it_behaves_like 'redirects to show work item page' do + subject(:make_request) do + get :edit, params: { namespace_id: project.namespace, project_id: project, id: task.iid, **query } end - - it_behaves_like 'renders 404' end + end - context 'update action' do - before do - put :update, params: { namespace_id: project.namespace, project_id: project, id: task.iid, issue: { title: 'New title' } } + context 'update action' do + it_behaves_like 'redirects to show work item page' do + subject(:make_request) do + put :update, params: { + namespace_id: project.namespace, + project_id: project, + id: task.iid, + issue: { title: 'New title' } + } end - - it_behaves_like 'renders 404' end end end @@ -1107,6 +1088,24 @@ RSpec.describe Projects::IssuesController do end end + context 'when trying to create a objective' 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 + + context 'when trying to create a key_result' 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 + context 'when create service return an unrecoverable error with http_status' do let(:http_status) { 403 } @@ -1291,7 +1290,7 @@ RSpec.describe Projects::IssuesController do let!(:last_spam_log) { spam_logs.last } def post_verified_issue - post_new_issue({}, { spam_log_id: last_spam_log.id, 'g-recaptcha-response': 'abc123' } ) + post_new_issue({}, { spam_log_id: last_spam_log.id, 'g-recaptcha-response': 'abc123' }) end before do @@ -1311,7 +1310,7 @@ RSpec.describe Projects::IssuesController do it 'does not mark spam log as recaptcha_verified when it does not belong to current_user' do spam_log = create(:spam_log) - expect { post_new_issue({}, { spam_log_id: spam_log.id, 'g-recaptcha-response': true } ) } + expect { post_new_issue({}, { spam_log_id: spam_log.id, 'g-recaptcha-response': true }) } .not_to change { last_spam_log.recaptcha_verified } end end @@ -1709,19 +1708,6 @@ RSpec.describe Projects::IssuesController do expect(response).to redirect_to(project_issues_path(project)) expect(controller).to set_flash[:notice].to match(/\AYour CSV export has started/i) end - - context 'when work_items is disabled' do - before do - stub_feature_flags(work_items: false) - end - - it 'does not include tasks in CSV export' do - expect(IssuableExportCsvWorker).to receive(:perform_async) - .with(:issue, viewer.id, project.id, hash_including('issue_types' => Issue::TYPES_FOR_LIST.excluding('task'))) - - request_csv - end - end end context 'when not logged in' do diff --git a/spec/controllers/projects/jobs_controller_spec.rb b/spec/controllers/projects/jobs_controller_spec.rb index 556dd23c135..3dc89365530 100644 --- a/spec/controllers/projects/jobs_controller_spec.rb +++ b/spec/controllers/projects/jobs_controller_spec.rb @@ -660,6 +660,38 @@ RSpec.describe Projects::JobsController, :clean_gitlab_redis_shared_state do end end end + + context 'when CI_DEBUG_SERVICES enabled' do + let!(:variable) { create(:ci_instance_variable, key: 'CI_DEBUG_SERVICES', value: 'true') } + + context 'with proper permissions on a project' do + let(:user) { developer } + + before do + sign_in(user) + end + + it 'returns response ok' do + get_trace + + expect(response).to have_gitlab_http_status(:ok) + end + end + + context 'without proper permissions for debug logging' do + let(:user) { guest } + + before do + sign_in(user) + end + + it 'returns response forbidden' do + get_trace + + expect(response).to have_gitlab_http_status(:forbidden) + end + end + end end context 'when job has a live trace' do @@ -1184,36 +1216,51 @@ RSpec.describe Projects::JobsController, :clean_gitlab_redis_shared_state do expect(response.header[Gitlab::Workhorse::DETECT_HEADER]).to eq "true" end - context 'when CI_DEBUG_TRACE enabled' do - before do - create(:ci_instance_variable, key: 'CI_DEBUG_TRACE', value: 'true') + context 'when CI_DEBUG_TRACE and/or CI_DEBUG_SERVICES are enabled' do + using RSpec::Parameterized::TableSyntax + where(:ci_debug_trace, :ci_debug_services) do + 'true' | 'true' + 'true' | 'false' + 'false' | 'true' + 'false' | 'false' end - context 'with proper permissions for debug logging on a project' do - let(:user) { developer } - + with_them do before do - sign_in(user) + create(:ci_instance_variable, key: 'CI_DEBUG_TRACE', value: ci_debug_trace) + create(:ci_instance_variable, key: 'CI_DEBUG_SERVICES', value: ci_debug_services) end - it 'returns response ok' do - response = subject + context 'with proper permissions for debug logging on a project' do + let(:user) { developer } - expect(response).to have_gitlab_http_status(:ok) - end - end + before do + sign_in(user) + end - context 'without proper permissions for debug logging on a project' do - let(:user) { reporter } + it 'returns response ok' do + response = subject - before do - sign_in(user) + expect(response).to have_gitlab_http_status(:ok) + end end - it 'returns response forbidden' do - response = subject + context 'without proper permissions for debug logging on a project' do + let(:user) { reporter } - expect(response).to have_gitlab_http_status(:forbidden) + before do + sign_in(user) + end + + it 'returns response forbidden if dev mode enabled' do + response = subject + + if ci_debug_trace == 'true' || ci_debug_services == 'true' + expect(response).to have_gitlab_http_status(:forbidden) + else + expect(response).to have_gitlab_http_status(:ok) + end + end end end end @@ -1380,7 +1427,7 @@ RSpec.describe Projects::JobsController, :clean_gitlab_redis_shared_state do { 'Channel' => { 'Subprotocols' => ["terminal.gitlab.com"], - 'Url' => 'wss://localhost/proxy/build/default_port/', + 'Url' => 'wss://gitlab.example.com/proxy/build/default_port/', 'Header' => { 'Authorization' => [nil] }, @@ -1536,7 +1583,8 @@ RSpec.describe Projects::JobsController, :clean_gitlab_redis_shared_state do allow(Gitlab::Workhorse).to receive(:verify_api_request!).and_return(nil) expect(job.runner_session_url).to start_with('https://') - expect(Gitlab::Workhorse).to receive(:channel_websocket).with(a_hash_including(url: "wss://localhost/proxy/build/default_port/")) + expect(Gitlab::Workhorse).to receive(:channel_websocket) + .with(a_hash_including(url: "wss://gitlab.example.com/proxy/build/default_port/")) make_request end diff --git a/spec/controllers/projects/learn_gitlab_controller_spec.rb b/spec/controllers/projects/learn_gitlab_controller_spec.rb index 2d00fcbccf3..a93da82d948 100644 --- a/spec/controllers/projects/learn_gitlab_controller_spec.rb +++ b/spec/controllers/projects/learn_gitlab_controller_spec.rb @@ -34,8 +34,15 @@ RSpec.describe Projects::LearnGitlabController do it { is_expected.to have_gitlab_http_status(:not_found) } end - it_behaves_like 'tracks assignment and records the subject', :invite_for_help_continuous_onboarding, :namespace do - subject { project.namespace } + context 'with invite_for_help_continuous_onboarding experiment' do + it 'tracks the assignment', :experiment do + stub_experiments(invite_for_help_continuous_onboarding: true) + + expect(experiment(:invite_for_help_continuous_onboarding)) + .to track(:assignment).with_context(namespace: project.namespace).on_next_instance + + action + end end end end diff --git a/spec/controllers/projects/merge_requests/diffs_controller_spec.rb b/spec/controllers/projects/merge_requests/diffs_controller_spec.rb index 367781c0e76..613d82efd06 100644 --- a/spec/controllers/projects/merge_requests/diffs_controller_spec.rb +++ b/spec/controllers/projects/merge_requests/diffs_controller_spec.rb @@ -213,7 +213,7 @@ RSpec.describe Projects::MergeRequests::DiffsController do commit: nil, latest_diff: true, only_context_commits: false, - allow_tree_conflicts: true, + merge_conflicts_in_diff: true, merge_ref_head_diff: false } end @@ -281,7 +281,7 @@ RSpec.describe Projects::MergeRequests::DiffsController do commit: nil, latest_diff: true, only_context_commits: false, - allow_tree_conflicts: true, + merge_conflicts_in_diff: true, merge_ref_head_diff: nil } end @@ -303,7 +303,7 @@ RSpec.describe Projects::MergeRequests::DiffsController do commit: merge_request.diff_head_commit, latest_diff: nil, only_context_commits: false, - allow_tree_conflicts: true, + merge_conflicts_in_diff: true, merge_ref_head_diff: nil } end @@ -329,7 +329,7 @@ RSpec.describe Projects::MergeRequests::DiffsController do commit: nil, latest_diff: true, only_context_commits: false, - allow_tree_conflicts: false, + merge_conflicts_in_diff: false, merge_ref_head_diff: nil } end @@ -488,7 +488,7 @@ RSpec.describe Projects::MergeRequests::DiffsController do commit: nil, diff_view: :inline, merge_ref_head_diff: nil, - allow_tree_conflicts: true, + merge_conflicts_in_diff: true, pagination_data: { total_pages: nil }.merge(pagination_data) @@ -616,7 +616,7 @@ RSpec.describe Projects::MergeRequests::DiffsController do it_behaves_like 'serializes diffs with expected arguments' do let(:collection) { Gitlab::Diff::FileCollection::MergeRequestDiffBatch } - let(:expected_options) { collection_arguments(total_pages: 20).merge(allow_tree_conflicts: false) } + let(:expected_options) { collection_arguments(total_pages: 20).merge(merge_conflicts_in_diff: false) } end it_behaves_like 'successful request' diff --git a/spec/controllers/projects/merge_requests_controller_spec.rb b/spec/controllers/projects/merge_requests_controller_spec.rb index a41abd8c16d..026cf19bde5 100644 --- a/spec/controllers/projects/merge_requests_controller_spec.rb +++ b/spec/controllers/projects/merge_requests_controller_spec.rb @@ -5,6 +5,7 @@ require 'spec_helper' RSpec.describe Projects::MergeRequestsController do include ProjectForksHelper include Gitlab::Routing + using RSpec::Parameterized::TableSyntax let_it_be_with_refind(:project) { create(:project, :repository) } let_it_be_with_reload(:project_public_with_private_builds) { create(:project, :repository, :public, :builds_private) } @@ -708,12 +709,14 @@ RSpec.describe Projects::MergeRequestsController do end describe 'GET commits' do - def go(format: 'html') + 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 + id: merge_request.iid, + page: page, + per_page: per_page }, format: format end @@ -723,6 +726,27 @@ RSpec.describe Projects::MergeRequestsController do expect(response).to render_template('projects/merge_requests/_commits') expect(json_response).to have_key('html') + expect(json_response).to have_key('next_page') + expect(json_response['next_page']).to eq(2) + end + + describe 'pagination' do + where(:page, :next_page) do + 1 | 2 + 2 | 3 + 3 | nil + end + + with_them do + it "renders the commits for page #{params[:page]}" do + go format: 'json', page: page, per_page: 10 + + expect(response).to render_template('projects/merge_requests/_commits') + expect(json_response).to have_key('html') + expect(json_response).to have_key('next_page') + expect(json_response['next_page']).to eq(next_page) + end + end end end @@ -1756,7 +1780,7 @@ RSpec.describe Projects::MergeRequestsController do end it 'renders MergeRequest as JSON' do - expect(json_response.keys).to include('id', 'iid', 'title', 'has_ci', 'merge_status', 'can_be_merged', 'current_user') + expect(json_response.keys).to include('id', 'iid', 'title', 'has_ci', 'current_user') end end @@ -1790,7 +1814,7 @@ RSpec.describe Projects::MergeRequestsController do it 'renders MergeRequest as JSON' do subject - expect(json_response.keys).to include('id', 'iid', 'title', 'has_ci', 'merge_status', 'can_be_merged', 'current_user') + expect(json_response.keys).to include('id', 'iid', 'title', 'has_ci', 'current_user') end end diff --git a/spec/controllers/projects/pipelines_controller_spec.rb b/spec/controllers/projects/pipelines_controller_spec.rb index b132c0b5a69..f66e4b133ca 100644 --- a/spec/controllers/projects/pipelines_controller_spec.rb +++ b/spec/controllers/projects/pipelines_controller_spec.rb @@ -20,23 +20,11 @@ RSpec.describe Projects::PipelinesController do end shared_examples 'the show page' do |param| - it 'redirects to pipeline path with param' do + it 'renders the show template' do get param, params: { namespace_id: project.namespace, project_id: project, id: pipeline } - expect(response).to redirect_to(pipeline_path(pipeline, tab: param)) - end - - context 'when the FF pipeline_tabs_vue is disabled' do - before do - stub_feature_flags(pipeline_tabs_vue: false) - end - - it 'renders the show template' do - get param, params: { namespace_id: project.namespace, project_id: project, id: pipeline } - - expect(response).to have_gitlab_http_status(:ok) - expect(response).to render_template :show - end + expect(response).to have_gitlab_http_status(:ok) + expect(response).to render_template :show end end @@ -311,14 +299,15 @@ RSpec.describe Projects::PipelinesController do stub_application_setting(auto_devops_enabled: false) end - def action - get :index, params: { namespace_id: project.namespace, project_id: project } - end + context 'with runners_availability_section experiment' do + it 'tracks the assignment', :experiment do + stub_experiments(runners_availability_section: true) - subject { project.namespace } + expect(experiment(:runners_availability_section)) + .to track(:assignment).with_context(namespace: project.namespace).on_next_instance - context 'runners_availability_section experiment' do - it_behaves_like 'tracks assignment and records the subject', :runners_availability_section, :namespace + get :index, params: { namespace_id: project.namespace, project_id: project } + end end end @@ -710,37 +699,25 @@ RSpec.describe Projects::PipelinesController do describe 'GET failures' do let(:pipeline) { create(:ci_pipeline, project: project) } - context 'with ff `pipeline_tabs_vue` disabled' do + context 'with failed jobs' do before do - stub_feature_flags(pipeline_tabs_vue: false) + create(:ci_build, :failed, pipeline: pipeline, name: 'hello') end - context 'with failed jobs' do - before do - create(:ci_build, :failed, pipeline: pipeline, name: 'hello') - end - - it 'shows the page' do - get :failures, params: { namespace_id: project.namespace, project_id: project, id: pipeline } - - expect(response).to have_gitlab_http_status(:ok) - expect(response).to render_template :show - end - end - - context 'without failed jobs' do - it 'redirects to the main pipeline page' do - get :failures, params: { namespace_id: project.namespace, project_id: project, id: pipeline } + it 'shows the page' do + get :failures, params: { namespace_id: project.namespace, project_id: project, id: pipeline } - expect(response).to redirect_to(pipeline_path(pipeline)) - end + expect(response).to have_gitlab_http_status(:ok) + expect(response).to render_template :show end end - it 'redirects to the pipeline page with `failures` query param' do - get :failures, params: { namespace_id: project.namespace, project_id: project, id: pipeline } + context 'without failed jobs' do + it 'redirects to the main pipeline page' do + get :failures, params: { namespace_id: project.namespace, project_id: project, id: pipeline } - expect(response).to redirect_to(pipeline_path(pipeline, tab: 'failures')) + expect(response).to redirect_to(pipeline_path(pipeline)) + end end end diff --git a/spec/controllers/projects/product_analytics_controller_spec.rb b/spec/controllers/projects/product_analytics_controller_spec.rb deleted file mode 100644 index 47f1d96c70b..00000000000 --- a/spec/controllers/projects/product_analytics_controller_spec.rb +++ /dev/null @@ -1,95 +0,0 @@ -# frozen_string_literal: true - -require 'spec_helper' - -RSpec.describe Projects::ProductAnalyticsController do - let_it_be(:project) { create(:project) } - let_it_be(:user) { create(:user) } - - before(:all) do - project.add_maintainer(user) - end - - before do - sign_in(user) - stub_feature_flags(product_analytics: true) - end - - describe 'GET #index' do - it 'renders index with 200 status code' do - get :index, params: project_params - - expect(response).to have_gitlab_http_status(:ok) - expect(response).to render_template(:index) - end - - context 'with an anonymous user' do - before do - sign_out(user) - end - - it 'redirects to sign-in page' do - get :index, params: project_params - - expect(response).to redirect_to(new_user_session_path) - end - end - - context 'feature flag disabled' do - before do - stub_feature_flags(product_analytics: false) - end - - it 'returns not found' do - get :index, params: project_params - - expect(response).to have_gitlab_http_status(:not_found) - end - end - end - - describe 'GET #test' do - it 'renders test with 200 status code' do - get :test, params: project_params - - expect(response).to have_gitlab_http_status(:ok) - expect(response).to render_template(:test) - end - end - - describe 'GET #setup' do - it 'renders setup with 200 status code' do - get :setup, params: project_params - - expect(response).to have_gitlab_http_status(:ok) - expect(response).to render_template(:setup) - end - end - - describe 'GET #graphs' do - it 'renders graphs with 200 status code' do - get :graphs, params: project_params - - expect(response).to have_gitlab_http_status(:ok) - expect(response).to render_template(:graphs) - end - - context 'feature flag disabled' do - before do - stub_feature_flags(product_analytics: false) - end - - it 'returns not found' do - get :graphs, params: project_params - - expect(response).to have_gitlab_http_status(:not_found) - end - end - end - - private - - def project_params(opts = {}) - opts.reverse_merge(namespace_id: project.namespace, project_id: project) - end -end diff --git a/spec/controllers/projects/prometheus/alerts_controller_spec.rb b/spec/controllers/projects/prometheus/alerts_controller_spec.rb index 2c2c8180143..09b9f25c0c6 100644 --- a/spec/controllers/projects/prometheus/alerts_controller_spec.rb +++ b/spec/controllers/projects/prometheus/alerts_controller_spec.rb @@ -56,7 +56,7 @@ RSpec.describe Projects::Prometheus::AlertsController do describe 'POST #notify' do let(:alert_1) { build(:alert_management_alert, :prometheus, project: project) } let(:alert_2) { build(:alert_management_alert, :prometheus, project: project) } - let(:service_response) { ServiceResponse.success(payload: { alerts: [alert_1, alert_2] }) } + let(:service_response) { ServiceResponse.success(http_status: :created) } let(:notify_service) { instance_double(Projects::Prometheus::Alerts::NotifyService, execute: service_response) } before do @@ -68,17 +68,12 @@ RSpec.describe Projects::Prometheus::AlertsController do .and_return(notify_service) end - it 'returns ok if notification succeeds' do + it 'returns created if notification succeeds' do expect(notify_service).to receive(:execute).and_return(service_response) post :notify, params: project_params, session: { as: :json } - expect(json_response).to contain_exactly( - { 'iid' => alert_1.iid, 'title' => alert_1.title }, - { 'iid' => alert_2.iid, 'title' => alert_2.title } - ) - - expect(response).to have_gitlab_http_status(:ok) + expect(response).to have_gitlab_http_status(:created) end it 'returns unprocessable entity if notification fails' do diff --git a/spec/controllers/projects/registry/repositories_controller_spec.rb b/spec/controllers/projects/registry/repositories_controller_spec.rb index a5faaaf5969..f4f5c182850 100644 --- a/spec/controllers/projects/registry/repositories_controller_spec.rb +++ b/spec/controllers/projects/registry/repositories_controller_spec.rb @@ -103,10 +103,11 @@ RSpec.describe Projects::Registry::RepositoriesController do stub_container_registry_tags(repository: :any, tags: []) end - it 'schedules a job to delete a repository' do - expect(DeleteContainerRepositoryWorker).to receive(:perform_async).with(user.id, repository.id) + it 'marks the repository as delete_scheduled' do + expect(DeleteContainerRepositoryWorker).not_to receive(:perform_async).with(user.id, repository.id) - delete_repository(repository) + expect { delete_repository(repository) } + .to change { repository.reload.status }.from(nil).to('delete_scheduled') expect(repository.reload).to be_delete_scheduled expect(response).to have_gitlab_http_status(:no_content) @@ -119,6 +120,22 @@ RSpec.describe Projects::Registry::RepositoriesController do expect_snowplow_event(category: anything, action: 'delete_repository') end + + context 'with container_registry_delete_repository_with_cron_worker disabled' do + before do + stub_feature_flags(container_registry_delete_repository_with_cron_worker: false) + end + + it 'schedules a job to delete a repository' do + expect(DeleteContainerRepositoryWorker).to receive(:perform_async).with(user.id, repository.id) + + expect { delete_repository(repository) } + .to change { repository.reload.status }.from(nil).to('delete_scheduled') + + expect(repository.reload).to be_delete_scheduled + expect(response).to have_gitlab_http_status(:no_content) + end + end end end end @@ -137,7 +154,7 @@ RSpec.describe Projects::Registry::RepositoriesController do end end - def go_to_index(format: :html, params: {} ) + def go_to_index(format: :html, params: {}) get :index, params: params.merge({ namespace_id: project.namespace, project_id: project diff --git a/spec/controllers/projects/releases_controller_spec.rb b/spec/controllers/projects/releases_controller_spec.rb index b307bb357fa..2afd080344d 100644 --- a/spec/controllers/projects/releases_controller_spec.rb +++ b/spec/controllers/projects/releases_controller_spec.rb @@ -112,7 +112,7 @@ RSpec.describe Projects::ReleasesController do it "returns the project's releases as JSON, ordered by released_at" do get_index - expect(json_response.map { |release| release["id"] } ).to eq([release_2.id, release_1.id]) + expect(json_response.map { |release| release["id"] }).to eq([release_2.id, release_1.id]) end it_behaves_like 'common access controls' diff --git a/spec/controllers/projects/runners_controller_spec.rb b/spec/controllers/projects/runners_controller_spec.rb index 57d1695b842..1066c4ec9f6 100644 --- a/spec/controllers/projects/runners_controller_spec.rb +++ b/spec/controllers/projects/runners_controller_spec.rb @@ -25,7 +25,7 @@ RSpec.describe Projects::RunnersController do new_desc = runner.description.swapcase expect do - post :update, params: params.merge(runner: { description: new_desc } ) + post :update, params: params.merge(runner: { description: new_desc }) end.to change { runner.ensure_runner_queue_value } runner.reload diff --git a/spec/controllers/projects/settings/integrations_controller_spec.rb b/spec/controllers/projects/settings/integrations_controller_spec.rb index b76269f6f93..2b23f177a9d 100644 --- a/spec/controllers/projects/settings/integrations_controller_spec.rb +++ b/spec/controllers/projects/settings/integrations_controller_spec.rb @@ -334,6 +334,23 @@ RSpec.describe Projects::Settings::IntegrationsController do ) end end + + context 'with chat notification integration' do + let_it_be(:integration) { project.create_microsoft_teams_integration(webhook: 'http://webhook.com') } + let(:message) { 'Microsoft Teams notifications settings saved and active.' } + + it_behaves_like 'integration update' + + context 'with masked token' do + let(:integration_params) { { active: true, webhook: '************' } } + + it_behaves_like 'integration update' + + it 'does not update the webhook' do + expect(integration.reload.webhook).to eq('http://webhook.com') + end + end + end end describe 'as JSON' do diff --git a/spec/controllers/projects/settings/repository_controller_spec.rb b/spec/controllers/projects/settings/repository_controller_spec.rb index 22287fea82c..ea50ff6caa0 100644 --- a/spec/controllers/projects/settings/repository_controller_spec.rb +++ b/spec/controllers/projects/settings/repository_controller_spec.rb @@ -5,6 +5,7 @@ require 'spec_helper' RSpec.describe Projects::Settings::RepositoryController do let(:project) { create(:project_empty_repo, :public) } let(:user) { create(:user) } + let(:base_params) { { namespace_id: project.namespace, project_id: project } } before do project.add_maintainer(user) @@ -13,7 +14,7 @@ RSpec.describe Projects::Settings::RepositoryController do describe 'GET show' do it 'renders show with 200 status code' do - get :show, params: { namespace_id: project.namespace, project_id: project } + get :show, params: base_params expect(response).to have_gitlab_http_status(:ok) expect(response).to render_template(:show) @@ -29,7 +30,7 @@ RSpec.describe Projects::Settings::RepositoryController do .with(project, user, anything) .and_return(status: :success) - put :cleanup, params: { namespace_id: project.namespace, project_id: project, project: { bfg_object_map: object_map } } + put :cleanup, params: base_params.merge({ project: { bfg_object_map: object_map } }) expect(response).to redirect_to project_settings_repository_path(project) end @@ -41,7 +42,7 @@ RSpec.describe Projects::Settings::RepositoryController do .with(project, user, anything) .and_return(status: :error, message: 'error message') - put :cleanup, params: { namespace_id: project.namespace, project_id: project, project: { bfg_object_map: object_map } } + put :cleanup, params: base_params.merge({ project: { bfg_object_map: object_map } }) expect(controller).to set_flash[:alert].to('error message') expect(response).to redirect_to project_settings_repository_path(project) @@ -50,83 +51,138 @@ RSpec.describe Projects::Settings::RepositoryController do end describe 'POST create_deploy_token' do - context 'when ajax_new_deploy_token feature flag is disabled for the project' do - before do - stub_feature_flags(ajax_new_deploy_token: false) + let(:good_deploy_token_params) do + { + name: 'name', + expires_at: 1.day.from_now.to_s, + username: 'deployer', + read_repository: '1', + deploy_token_type: DeployToken.deploy_token_types[:project_type] + } + end + + let(:request_params) { base_params.merge({ deploy_token: deploy_token_params }) } + + subject { post :create_deploy_token, params: request_params, format: :json } + + context('a good request') do + let(:deploy_token_params) { good_deploy_token_params } + let(:expected_response) do + { + 'id' => be_a(Integer), + 'name' => deploy_token_params[:name], + 'username' => deploy_token_params[:username], + 'expires_at' => Time.zone.parse(deploy_token_params[:expires_at]), + 'token' => be_a(String), + 'expired' => false, + 'revoked' => false, + 'scopes' => deploy_token_params.inject([]) do |scopes, kv| + key, value = kv + key.to_s.start_with?('read_') && value.to_i != 0 ? scopes << key.to_s : scopes + end + } end - it_behaves_like 'a created deploy token' do - let(:entity) { project } - let(:create_entity_params) { { namespace_id: project.namespace, project_id: project } } - let(:deploy_token_type) { DeployToken.deploy_token_types[:project_type] } + it 'creates the deploy token' do + subject + + expect(response).to have_gitlab_http_status(:created) + expect(response).to match_response_schema('public_api/v4/deploy_token') + expect(json_response).to match(expected_response) end end - context 'when ajax_new_deploy_token feature flag is enabled for the project' do - let(:good_deploy_token_params) do - { - name: 'name', - expires_at: 1.day.from_now.to_s, - username: 'deployer', - read_repository: '1', - deploy_token_type: DeployToken.deploy_token_types[:project_type] - } + context('a bad request') do + let(:deploy_token_params) { good_deploy_token_params.except(:read_repository) } + let(:expected_response) { { 'message' => "Scopes can't be blank" } } + + it 'does not create the deploy token' do + subject + + expect(response).to have_gitlab_http_status(:bad_request) + expect(json_response).to match(expected_response) end + end - let(:request_params) do - { - namespace_id: project.namespace.to_param, - project_id: project.to_param, - deploy_token: deploy_token_params - } + context('an invalid request') do + let(:deploy_token_params) { good_deploy_token_params.except(:name) } + + it 'raises a validation error' do + expect { subject }.to raise_error(ActiveRecord::StatementInvalid) end + end + end - subject { post :create_deploy_token, params: request_params, format: :json } - - context('a good request') do - let(:deploy_token_params) { good_deploy_token_params } - let(:expected_response) do - { - 'id' => be_a(Integer), - 'name' => deploy_token_params[:name], - 'username' => deploy_token_params[:username], - 'expires_at' => Time.zone.parse(deploy_token_params[:expires_at]), - 'token' => be_a(String), - 'expired' => false, - 'revoked' => false, - 'scopes' => deploy_token_params.inject([]) do |scopes, kv| - key, value = kv - key.to_s.start_with?('read_') && value.to_i != 0 ? scopes << key.to_s : scopes - end - } + describe 'PUT update' do + let(:project) { create(:project, :repository) } + + context 'when updating default branch' do + let!(:previous_default_branch) { project.default_branch } + + let(:new_default_branch) { 'feature' } + let(:request_params) { base_params.merge({ project: project_params_attributes }) } + + subject { put :update, params: request_params } + + context('with a good request') do + let(:project_params_attributes) { { default_branch: new_default_branch } } + + it "updates default branch and redirect to project_settings_repository_path" do + expect do + subject + end.to change { + Project.find(project.id).default_branch # refind to reset the default branch cache + }.from(previous_default_branch).to(new_default_branch) + + expect(response).to redirect_to project_settings_repository_path(project) + expect(controller).to set_flash[:notice].to("Project settings were successfully updated.") end + end - it 'creates the deploy token' do - subject + context('with a bad input') do + let(:project_params_attributes) { { default_branch: 'non_existent_branch' } } - expect(response).to have_gitlab_http_status(:created) - expect(response).to match_response_schema('public_api/v4/deploy_token') - expect(json_response).to match(expected_response) + it "does not update default branch and shows an alert" do + expect do + subject + end.not_to change { + Project.find(project.id).default_branch # refind to reset the default branch cache + } + + expect(response).to redirect_to project_settings_repository_path(project) + expect(controller).to set_flash[:alert].to("Could not set the default branch") end end + end + + context 'when updating branch names template from issues' do + let(:branch_name_template) { 'feat/GL-%{id}-%{title}' } - context('a bad request') do - let(:deploy_token_params) { good_deploy_token_params.except(:read_repository) } - let(:expected_response) { { 'message' => "Scopes can't be blank" } } + let(:request_params) { base_params.merge({ project: project_params_attributes }) } - it 'does not create the deploy token' do + subject { put :update, params: request_params } + + context('with a good request') do + let(:project_params_attributes) { { issue_branch_template: branch_name_template } } + + it "updates issue_branch_template and redirect to project_settings_repository_path" do subject - expect(response).to have_gitlab_http_status(:bad_request) - expect(json_response).to match(expected_response) + expect(response).to redirect_to project_settings_repository_path(project) + expect(controller).to set_flash[:notice].to("Project settings were successfully updated.") + expect(project.reload.issue_branch_template).to eq(branch_name_template) end end - context('an invalid request') do - let(:deploy_token_params) { good_deploy_token_params.except(:name) } + context('with a bad input') do + let(:project_params_attributes) { { issue_branch_template: 'a' * 260 } } + + it "updates issue_branch_template and redirect to project_settings_repository_path" do + subject - it 'raises a validation error' do - expect { subject }.to raise_error(ActiveRecord::StatementInvalid) + expect(response).to redirect_to project_settings_repository_path(project) + expect(controller).to set_flash[:alert].to("Project setting issue branch template is too long (maximum is 255 characters)") + expect(project.reload.issue_branch_template).to eq(nil) end end end diff --git a/spec/controllers/projects/starrers_controller_spec.rb b/spec/controllers/projects/starrers_controller_spec.rb index 8d03600cd58..2148f495c31 100644 --- a/spec/controllers/projects/starrers_controller_spec.rb +++ b/spec/controllers/projects/starrers_controller_spec.rb @@ -6,6 +6,7 @@ RSpec.describe Projects::StarrersController do let(:user_1) { create(:user, name: 'John') } let(:user_2) { create(:user, name: 'Michael') } let(:private_user) { create(:user, name: 'Michael Douglas', private_profile: true) } + let(:blocked_user) { create(:user, state: 'blocked') } let(:admin) { create(:user, admin: true) } let(:project) { create(:project, :public) } @@ -13,6 +14,7 @@ RSpec.describe Projects::StarrersController do user_1.toggle_star(project) user_2.toggle_star(project) private_user.toggle_star(project) + blocked_user.toggle_star(project) end describe 'GET index' do @@ -61,6 +63,10 @@ RSpec.describe Projects::StarrersController do expect(user_ids).to contain_exactly(user_1.id, user_2.id) end + it 'non-active users are not visible' do + expect(user_ids).not_to include(blocked_user.id) + end + include_examples 'starrers counts' end diff --git a/spec/controllers/projects_controller_spec.rb b/spec/controllers/projects_controller_spec.rb index b5797e374f3..446e5e38865 100644 --- a/spec/controllers/projects_controller_spec.rb +++ b/spec/controllers/projects_controller_spec.rb @@ -921,6 +921,7 @@ RSpec.describe ProjectsController do feature_flags_access_level releases_access_level monitor_access_level + infrastructure_access_level ] end diff --git a/spec/controllers/registrations_controller_spec.rb b/spec/controllers/registrations_controller_spec.rb index 637c774c38b..8775f68a5de 100644 --- a/spec/controllers/registrations_controller_spec.rb +++ b/spec/controllers/registrations_controller_spec.rb @@ -4,6 +4,7 @@ require 'spec_helper' RSpec.describe RegistrationsController do include TermsHelper + include FullNameHelper before do stub_application_setting(require_admin_approval_after_user_signup: false) @@ -18,6 +19,8 @@ RSpec.describe RegistrationsController do 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' end describe '#create' do @@ -463,7 +466,7 @@ RSpec.describe RegistrationsController do expect(User.last.first_name).to eq(base_user_params[:first_name]) expect(User.last.last_name).to eq(base_user_params[:last_name]) - expect(User.last.name).to eq("#{base_user_params[:first_name]} #{base_user_params[:last_name]}") + expect(User.last.name).to eq full_name(base_user_params[:first_name], base_user_params[:last_name]) end it 'sets the caller_id in the context' do @@ -477,28 +480,6 @@ RSpec.describe RegistrationsController do subject end - describe 'logged_out_marketing_header experiment', :experiment do - before do - stub_experiments(logged_out_marketing_header: :candidate) - end - - it 'tracks signed_up event' do - expect(experiment(:logged_out_marketing_header)).to track(:signed_up).on_next_instance - - subject - end - - context 'when registration fails' do - let_it_be(:user_params) { { user: base_user_params.merge({ username: '' }) } } - - it 'does not track signed_up event' do - expect(experiment(:logged_out_marketing_header)).not_to track(:signed_up) - - subject - end - end - end - context 'when the password is weak' do render_views let_it_be(:new_user_params) { { new_user: base_user_params.merge({ password: "password" }) } } @@ -513,6 +494,16 @@ RSpec.describe RegistrationsController do expect(response).to render_template(:new) expect(response.body).to include(_('Password must not contain commonly used combinations of words and letters')) end + + it 'tracks the error' do + subject + expect_snowplow_event( + category: 'Gitlab::Tracking::Helpers::WeakPasswordErrorEvent', + action: 'track_weak_password_error', + controller: 'RegistrationsController', + method: 'create' + ) + end end context 'when block_weak_passwords is disabled' do @@ -525,6 +516,42 @@ RSpec.describe RegistrationsController do end end end + + context 'when the password is not weak' do + it 'does not track a weak password error' do + subject + expect_no_snowplow_event( + category: 'Gitlab::Tracking::Helpers::WeakPasswordErrorEvent', + action: 'track_weak_password_error' + ) + end + end + + context 'with preferred language' do + let(:user_preferred_language) { nil } + + before do + cookies['preferred_language'] = user_preferred_language + + post :create, params: { new_user: base_user_params } + end + + subject { User.last.preferred_language } + + context 'with default behavior' do + it 'sets preferred language to default' do + is_expected.to eq(Gitlab::CurrentSettings.default_preferred_language) + end + end + + context 'when user sets preferred language' do + let(:user_preferred_language) { 'zh_CN' } + + it 'sets name from first and last name' do + is_expected.to eq(user_preferred_language) + end + end + end end describe '#destroy' do diff --git a/spec/controllers/search_controller_spec.rb b/spec/controllers/search_controller_spec.rb index 392dc2229aa..21df53fb074 100644 --- a/spec/controllers/search_controller_spec.rb +++ b/spec/controllers/search_controller_spec.rb @@ -223,7 +223,14 @@ RSpec.describe SearchController do let(:project) { nil } let(:category) { described_class.to_s } - let(:action) { 'i_search_total' } + let(:action) { 'executed' } + 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] + end + let(:namespace) { create(:group) } let(:feature_flag_name) { :route_hll_to_snowplow_phase2 } end diff --git a/spec/controllers/sessions_controller_spec.rb b/spec/controllers/sessions_controller_spec.rb index 80cf060bc45..69282f951f9 100644 --- a/spec/controllers/sessions_controller_spec.rb +++ b/spec/controllers/sessions_controller_spec.rb @@ -69,6 +69,8 @@ RSpec.describe SessionsController do expect(controller.stored_location_for(:redirect)).to eq(search_path) end + + it_behaves_like "switches to user preferred language", 'Sign in' end describe '#create' do diff --git a/spec/db/schema_spec.rb b/spec/db/schema_spec.rb index 4aeafed5712..ad49a763361 100644 --- a/spec/db/schema_spec.rb +++ b/spec/db/schema_spec.rb @@ -14,8 +14,10 @@ RSpec.describe 'Database schema' do issues: %w[work_item_type_id] }.with_indifferent_access.freeze + TABLE_PARTITIONS = %w[ci_builds_metadata].freeze + # List of columns historically missing a FK, don't add more columns - # See: https://docs.gitlab.com/ee/development/foreign_keys.html#naming-foreign-keys + # See: https://docs.gitlab.com/ee/development/database/foreign_keys.html#naming-foreign-keys IGNORED_FK_COLUMNS = { abuse_reports: %w[reporter_id user_id], application_settings: %w[performance_bar_allowed_group_id slack_app_id snowplow_app_id eks_account_id eks_access_key_id], @@ -32,7 +34,7 @@ RSpec.describe 'Database schema' do chat_names: %w[chat_id team_id user_id], chat_teams: %w[team_id], ci_builds: %w[erased_by_id trigger_request_id partition_id], - ci_builds_metadata: %w[partition_id], + p_ci_builds_metadata: %w[partition_id], ci_job_artifacts: %w[partition_id], ci_namespace_monthly_usages: %w[namespace_id], ci_pipeline_variables: %w[partition_id], @@ -107,7 +109,7 @@ RSpec.describe 'Database schema' do }.with_indifferent_access.freeze context 'for table' do - ActiveRecord::Base.connection.tables.sort.each do |table| + (ActiveRecord::Base.connection.tables - TABLE_PARTITIONS).sort.each do |table| describe table do let(:indexes) { connection.indexes(table) } let(:columns) { connection.columns(table) } @@ -213,6 +215,7 @@ RSpec.describe 'Database schema' do "ApplicationSetting" => %w[repository_storages_weighted], "AlertManagement::Alert" => %w[payload], "Ci::BuildMetadata" => %w[config_options config_variables], + "Ci::BuildMetadata::Partitioned" => %w[config_options config_variables id_tokens runtime_runner_features secrets], "ExperimentSubject" => %w[context], "ExperimentUser" => %w[context], "Geo::Event" => %w[payload], diff --git a/spec/experiments/application_experiment_spec.rb b/spec/experiments/application_experiment_spec.rb index b144e6f77d2..7aca5e492f4 100644 --- a/spec/experiments/application_experiment_spec.rb +++ b/spec/experiments/application_experiment_spec.rb @@ -43,72 +43,6 @@ RSpec.describe ApplicationExperiment, :experiment do variant: 'control' ) end - - describe '#publish_to_database' do - using RSpec::Parameterized::TableSyntax - - let(:publish_to_database) { ActiveSupport::Deprecation.silence { application_experiment.publish_to_database } } - - shared_examples 'does not record to the database' do - it 'does not create an experiment record' do - expect { publish_to_database }.not_to change(Experiment, :count) - end - - it 'does not create an experiment subject record' do - expect { publish_to_database }.not_to change(ExperimentSubject, :count) - end - end - - context 'when there is a usable subject' do - let(:context) { { context_key => context_value } } - - where(:context_key, :context_value, :object_type) do - :namespace | build(:namespace, id: non_existing_record_id) | :namespace - :group | build(:namespace, id: non_existing_record_id) | :namespace - :project | build(:project, id: non_existing_record_id) | :project - :user | build(:user, id: non_existing_record_id) | :user - :actor | build(:user, id: non_existing_record_id) | :user - end - - with_them do - it 'creates an experiment and experiment subject record' do - expect { publish_to_database }.to change(Experiment, :count).by(1) - - expect(Experiment.last.name).to eq('namespaced/stub') - expect(ExperimentSubject.last.send(object_type)).to eq(context[context_key]) - end - end - end - - context "when experiment hasn't ran" do - let(:context) { { user: create(:user) } } - - it 'sets a variant on the experiment subject' do - publish_to_database - - expect(ExperimentSubject.last.variant).to eq('control') - end - end - - context 'when there is not a usable subject' do - let(:context) { { context_key => context_value } } - - where(:context_key, :context_value) do - :namespace | nil - :foo | :bar - end - - with_them do - include_examples 'does not record to the database' - end - end - - context 'but we should not track' do - let(:should_track) { false } - - include_examples 'does not record to the database' - end - end end describe "#track", :snowplow do diff --git a/spec/experiments/require_verification_for_namespace_creation_experiment_spec.rb b/spec/experiments/require_verification_for_namespace_creation_experiment_spec.rb index 269b6222020..c91a8f1950e 100644 --- a/spec/experiments/require_verification_for_namespace_creation_experiment_spec.rb +++ b/spec/experiments/require_verification_for_namespace_creation_experiment_spec.rb @@ -30,34 +30,6 @@ RSpec.describe RequireVerificationForNamespaceCreationExperiment, :experiment do end end - describe '#record_conversion' do - let_it_be(:namespace) { create(:namespace) } - - context 'when should_track? is false' do - before do - allow(experiment).to receive(:should_track?).and_return(false) - end - - it 'does not record a conversion event' do - expect(experiment.publish_to_database).to be_nil - expect(experiment.record_conversion(namespace)).to be_nil - end - end - - context 'when should_track? is true' do - before do - allow(experiment).to receive(:should_track?).and_return(true) - end - - it 'records a conversion event' do - experiment_subject = experiment.publish_to_database - - expect { experiment.record_conversion(namespace) }.to change { experiment_subject.reload.converted_at }.from(nil) - .and change { experiment_subject.context }.to include('namespace_id' => namespace.id) - end - end - end - describe 'exclusions' do context 'when user is new' do it 'is not excluded' do diff --git a/spec/experiments/security_reports_mr_widget_prompt_experiment_spec.rb b/spec/experiments/security_reports_mr_widget_prompt_experiment_spec.rb index 4328ff12d42..ee02fa5f1f2 100644 --- a/spec/experiments/security_reports_mr_widget_prompt_experiment_spec.rb +++ b/spec/experiments/security_reports_mr_widget_prompt_experiment_spec.rb @@ -6,10 +6,4 @@ RSpec.describe SecurityReportsMrWidgetPromptExperiment do it "defines a control and candidate" do expect(subject.behaviors.keys).to match_array(%w[control candidate]) end - - it "publishes to the database" do - expect(subject).to receive(:publish_to_database) - - subject.publish - end end diff --git a/spec/factories/ci/builds.rb b/spec/factories/ci/builds.rb index 9a3b2837ab8..b88d6b5fda4 100644 --- a/spec/factories/ci/builds.rb +++ b/spec/factories/ci/builds.rb @@ -24,6 +24,16 @@ FactoryBot.define do project { pipeline.project } + trait :with_token do + transient do + generate_token { true } + end + + after(:build) do |build, evaluator| + build.ensure_token if evaluator.generate_token + end + end + trait :degenerated do options { nil } yaml_variables { nil } @@ -93,6 +103,7 @@ FactoryBot.define do end trait :pending do + with_token queued_at { 'Di 29. Okt 09:50:59 CET 2013' } status { 'pending' } @@ -100,6 +111,7 @@ FactoryBot.define do trait :created do status { 'created' } + generate_token { false } end trait :preparing do @@ -303,14 +315,11 @@ FactoryBot.define do # Build deployment/environment relations if environment name is set # to the job. If `build.deployment` has already been set, it doesn't # build a new instance. - environment = Gitlab::Ci::Pipeline::Seed::Environment.new(build).to_resource + Environments::CreateForBuildService.new.execute(build) + end - build.assign_attributes( - deployment: Gitlab::Ci::Pipeline::Seed::Deployment.new(build, environment).to_resource, - metadata_attributes: { - expanded_environment_name: environment.name - } - ) + after(:create) do |build, evaluator| + Deployments::CreateForBuildService.new.execute(build) end end @@ -716,7 +725,7 @@ FactoryBot.define do trait :with_runner_session do after(:build) do |build| - build.build_runner_session(url: 'https://localhost') + build.build_runner_session(url: 'https://gitlab.example.com') end end diff --git a/spec/factories/ci/job_artifacts.rb b/spec/factories/ci/job_artifacts.rb index 304d77e8521..7569e832c60 100644 --- a/spec/factories/ci/job_artifacts.rb +++ b/spec/factories/ci/job_artifacts.rb @@ -20,6 +20,8 @@ FactoryBot.define do after :build do |artifact| artifact.project ||= artifact.job.project + + artifact.job&.valid? end trait :raw do diff --git a/spec/factories/ci/pipeline_metadata.rb b/spec/factories/ci/pipeline_metadata.rb index 600cfaa92c6..7849fa1fd4b 100644 --- a/spec/factories/ci/pipeline_metadata.rb +++ b/spec/factories/ci/pipeline_metadata.rb @@ -2,7 +2,7 @@ FactoryBot.define do factory :ci_pipeline_metadata, class: 'Ci::PipelineMetadata' do - title { 'Pipeline title' } + name { 'Pipeline name' } pipeline factory: :ci_empty_pipeline project diff --git a/spec/factories/ci/pipelines.rb b/spec/factories/ci/pipelines.rb index 650b8647237..891628a0fc2 100644 --- a/spec/factories/ci/pipelines.rb +++ b/spec/factories/ci/pipelines.rb @@ -8,7 +8,7 @@ FactoryBot.define do sha { 'b83d6e391c22777fca1ed3012fce84f633d7fed0' } status { 'pending' } add_attribute(:protected) { false } - partition_id { 1234 } + partition_id { 100 } project @@ -19,7 +19,7 @@ FactoryBot.define do transient { child_of { nil } } transient { upstream_of { nil } } - transient { title { nil } } + transient { name { nil } } after(:build) do |pipeline, evaluator| if evaluator.child_of @@ -29,8 +29,8 @@ FactoryBot.define do pipeline.ensure_project_iid! - if evaluator.title - pipeline.pipeline_metadata = build(:ci_pipeline_metadata, title: evaluator.title, project: pipeline.project, pipeline: pipeline) + if evaluator.name + pipeline.pipeline_metadata = build(:ci_pipeline_metadata, name: evaluator.name, project: pipeline.project, pipeline: pipeline) end end @@ -54,7 +54,7 @@ FactoryBot.define do end factory :ci_pipeline do - partition_id { 1234 } + partition_id { 100 } transient { ci_ref_presence { true } } before(:create) do |pipeline, evaluator| diff --git a/spec/factories/ci/processable.rb b/spec/factories/ci/processable.rb index 0550f4c23fa..76c7376d24a 100644 --- a/spec/factories/ci/processable.rb +++ b/spec/factories/ci/processable.rb @@ -4,7 +4,7 @@ FactoryBot.define do factory :ci_processable, class: 'Ci::Processable' do name { 'processable' } stage { 'test' } - stage_idx { 0 } + stage_idx { ci_stage.try(:position) || 0 } ref { 'master' } tag { false } pipeline factory: :ci_pipeline diff --git a/spec/factories/ci/reports/codequality_degradations.rb b/spec/factories/ci/reports/codequality_degradations.rb index 8b53f2bf46e..632f5a3ecaa 100644 --- a/spec/factories/ci/reports/codequality_degradations.rb +++ b/spec/factories/ci/reports/codequality_degradations.rb @@ -26,7 +26,8 @@ FactoryBot.define do "remediation_points": 900000, "severity": "major", "type": "issue", - "engine_name": "structure" + "engine_name": "structure", + "web_url": "http://localhost/root/test-project/-/blob/f572d396fae9206628714fb2ce00f72e94f2258f/file_a.rb#L10" }.with_indifferent_access end end @@ -56,7 +57,8 @@ FactoryBot.define do "remediation_points": 900000, "severity": "major", "type": "issue", - "engine_name": "structure" + "engine_name": "structure", + "web_url": "http://localhost/root/test-project/-/blob/f572d396fae9206628714fb2ce00f72e94f2258f/file_a.rb#L10" }.with_indifferent_access end end @@ -91,7 +93,8 @@ FactoryBot.define do }, "engine_name": "rubocop", "fingerprint": "ab5f8b935886b942d621399f5a2ca16e", - "severity": "minor" + "severity": "minor", + "web_url": "http://localhost/root/test-project/-/blob/f572d396fae9206628714fb2ce00f72e94f2258f/file_b.rb#L10" }.with_indifferent_access end end diff --git a/spec/factories/ci/reports/sbom/components.rb b/spec/factories/ci/reports/sbom/components.rb index fd9b4386130..8f2c00b695a 100644 --- a/spec/factories/ci/reports/sbom/components.rb +++ b/spec/factories/ci/reports/sbom/components.rb @@ -3,15 +3,29 @@ FactoryBot.define do factory :ci_reports_sbom_component, class: '::Gitlab::Ci::Reports::Sbom::Component' do type { "library" } + sequence(:name) { |n| "component-#{n}" } sequence(:version) { |n| "v0.0.#{n}" } + transient do + purl_type { 'npm' } + end + + purl do + ::Sbom::PackageUrl.new( + type: purl_type, + name: name, + version: version + ).to_s + end + skip_create initialize_with do ::Gitlab::Ci::Reports::Sbom::Component.new( type: type, name: name, + purl: purl, version: version ) end diff --git a/spec/factories/ci/reports/sbom/reports.rb b/spec/factories/ci/reports/sbom/reports.rb index 4a83b5898ef..7a076282915 100644 --- a/spec/factories/ci/reports/sbom/reports.rb +++ b/spec/factories/ci/reports/sbom/reports.rb @@ -8,6 +8,12 @@ FactoryBot.define do source { association :ci_reports_sbom_source } end + trait :invalid do + after(:build) do |report, options| + report.add_error('This report is invalid because it contains errors.') + end + end + after(:build) do |report, options| options.components.each { |component| report.add_component(component) } report.set_source(options.source) diff --git a/spec/factories/ci/secure_files.rb b/spec/factories/ci/secure_files.rb index 74988202c71..31dbcd15cb1 100644 --- a/spec/factories/ci/secure_files.rb +++ b/spec/factories/ci/secure_files.rb @@ -13,4 +13,13 @@ FactoryBot.define do end end end + + factory :ci_secure_file_with_metadata, class: 'Ci::SecureFile' do + sequence(:name) { |n| "file#{n}.cer" } + file { fixture_file_upload('spec/fixtures/ci_secure_files/sample.cer', 'application/octet-stream') } + checksum { 'foo1234' } + project + + after(:create, &:update_metadata!) + end end diff --git a/spec/factories/ci/stages.rb b/spec/factories/ci/stages.rb index 41297b01f92..d9dff4d9a86 100644 --- a/spec/factories/ci/stages.rb +++ b/spec/factories/ci/stages.rb @@ -2,7 +2,7 @@ FactoryBot.define do factory :ci_stage, class: 'Ci::Stage' do - project factory: :project + project { pipeline.project } pipeline factory: :ci_empty_pipeline name { 'test' } diff --git a/spec/factories/container_repositories.rb b/spec/factories/container_repositories.rb index 210441430b0..66ac72fb5d7 100644 --- a/spec/factories/container_repositories.rb +++ b/spec/factories/container_repositories.rb @@ -21,6 +21,10 @@ FactoryBot.define do status { :delete_failed } end + trait :status_delete_ongoing do + status { :delete_ongoing } + end + trait :cleanup_scheduled do expiration_policy_cleanup_status { :cleanup_scheduled } end diff --git a/spec/factories/dependency_proxy.rb b/spec/factories/dependency_proxy.rb index afa6c61116a..33356a701df 100644 --- a/spec/factories/dependency_proxy.rb +++ b/spec/factories/dependency_proxy.rb @@ -4,13 +4,20 @@ FactoryBot.define do factory :dependency_proxy_blob, class: 'DependencyProxy::Blob' do group size { 1234 } - file { fixture_file_upload('spec/fixtures/dependency_proxy/a3ed95caeb02ffe68cdd9fd84406680ae93d633cb16422d00e8a7c22955b46d4.gz') } file_name { 'a3ed95caeb02ffe68cdd9fd84406680ae93d633cb16422d00e8a7c22955b46d4.gz' } status { :default } + after(:build) do |blob, _evaluator| + blob.file = fixture_file_upload('spec/fixtures/dependency_proxy/a3ed95caeb02ffe68cdd9fd84406680ae93d633cb16422d00e8a7c22955b46d4.gz') + end + trait :pending_destruction do status { :pending_destruction } end + + trait :remote_store do + file_store { DependencyProxy::FileUploader::Store::REMOTE } + end end factory :dependency_proxy_manifest, class: 'DependencyProxy::Manifest' do diff --git a/spec/factories/experiment_subjects.rb b/spec/factories/experiment_subjects.rb deleted file mode 100644 index c35bc370bad..00000000000 --- a/spec/factories/experiment_subjects.rb +++ /dev/null @@ -1,9 +0,0 @@ -# frozen_string_literal: true - -FactoryBot.define do - factory :experiment_subject do - experiment - user - variant { :control } - end -end diff --git a/spec/factories/experiment_users.rb b/spec/factories/experiment_users.rb deleted file mode 100644 index 66c39d684eb..00000000000 --- a/spec/factories/experiment_users.rb +++ /dev/null @@ -1,10 +0,0 @@ -# frozen_string_literal: true - -FactoryBot.define do - factory :experiment_user do - experiment - user - group_type { :control } - converted_at { nil } - end -end diff --git a/spec/factories/experiments.rb b/spec/factories/experiments.rb deleted file mode 100644 index 2c51a6585f4..00000000000 --- a/spec/factories/experiments.rb +++ /dev/null @@ -1,7 +0,0 @@ -# frozen_string_literal: true - -FactoryBot.define do - factory :experiment do - name { generate(:title) } - end -end diff --git a/spec/factories/integrations.rb b/spec/factories/integrations.rb index 5ac26b7a260..ebbf1b560e5 100644 --- a/spec/factories/integrations.rb +++ b/spec/factories/integrations.rb @@ -43,6 +43,19 @@ FactoryBot.define do end end + factory :packagist_integration, class: 'Integrations::Packagist' do + project + type { 'Integrations::Packagist' } + active { true } + properties do + { + username: 'username', + token: 'test', + server: 'https://packagist.example.com' + } + end + end + factory :prometheus_integration, class: 'Integrations::Prometheus' do project active { true } diff --git a/spec/factories/member_roles.rb b/spec/factories/member_roles.rb index bd211844f5a..08df45a85f8 100644 --- a/spec/factories/member_roles.rb +++ b/spec/factories/member_roles.rb @@ -4,5 +4,7 @@ FactoryBot.define do factory :member_role do namespace { association(:group) } base_access_level { Gitlab::Access::DEVELOPER } + + trait(:guest) { base_access_level { GroupMember::GUEST } } end end diff --git a/spec/factories/merge_request_reviewers.rb b/spec/factories/merge_request_reviewers.rb new file mode 100644 index 00000000000..26e047a3fbf --- /dev/null +++ b/spec/factories/merge_request_reviewers.rb @@ -0,0 +1,9 @@ +# frozen_string_literal: true + +FactoryBot.define do + factory :merge_request_reviewer do + merge_request + reviewer { association(:user) } + state { 'unreviewed' } + end +end diff --git a/spec/factories/packages/rpm/rpm_repository_files.rb b/spec/factories/packages/rpm/rpm_repository_files.rb index 079d32b3995..00755f49d98 100644 --- a/spec/factories/packages/rpm/rpm_repository_files.rb +++ b/spec/factories/packages/rpm/rpm_repository_files.rb @@ -4,9 +4,10 @@ FactoryBot.define do factory :rpm_repository_file, class: 'Packages::Rpm::RepositoryFile' do project - file_name { 'repomd.xml' } + file_name { '364c77dd49e8f814d56e621d0b3306c4fd0696dcad506f527329b818eb0f5db3-repomd.xml' } file_sha1 { 'efae869b4e95d54796a46481f3a211d6a88d0323' } file_md5 { 'ddf8a75330c896a8d7709e75f8b5982a' } + file_sha256 { '364c77dd49e8f814d56e621d0b3306c4fd0696dcad506f527329b818eb0f5db3' } size { 3127.kilobytes } status { :default } @@ -15,7 +16,11 @@ FactoryBot.define do end transient do - file_fixture { 'spec/fixtures/packages/rpm/repodata/repomd.xml' } + file_fixture do + # rubocop:disable Layout/LineLength + 'spec/fixtures/packages/rpm/repodata/364c77dd49e8f814d56e621d0b3306c4fd0696dcad506f527329b818eb0f5db3-repomd.xml' + # rubocop:enable Layout/LineLength + end end after(:build) do |package_file, evaluator| diff --git a/spec/factories/project_hooks.rb b/spec/factories/project_hooks.rb index dbb5c357acb..946b3925ee9 100644 --- a/spec/factories/project_hooks.rb +++ b/spec/factories/project_hooks.rb @@ -6,6 +6,10 @@ FactoryBot.define do enable_ssl_verification { false } project + trait :url_variables do + url_variables { { 'abc' => 'supers3cret' } } + end + trait :token do token { generate(:token) } end diff --git a/spec/factories/projects.rb b/spec/factories/projects.rb index b62995dce42..6e3a7a3f5ef 100644 --- a/spec/factories/projects.rb +++ b/spec/factories/projects.rb @@ -41,6 +41,7 @@ FactoryBot.define do environments_access_level { ProjectFeature::ENABLED } feature_flags_access_level { ProjectFeature::ENABLED } releases_access_level { ProjectFeature::ENABLED } + infrastructure_access_level { ProjectFeature::ENABLED } # we can't assign the delegated `#ci_cd_settings` attributes directly, as the # `#ci_cd_settings` relation needs to be created first @@ -251,6 +252,7 @@ FactoryBot.define do transient do create_templates { nil } create_branch { nil } + create_tag { nil } end after :create do |project, evaluator| @@ -287,6 +289,13 @@ FactoryBot.define do end + if evaluator.create_tag + project.repository.add_tag( + project.creator, + evaluator.create_tag, + project.repository.commit.sha) + end + project.track_project_repository end end @@ -467,6 +476,10 @@ FactoryBot.define do end end + trait :in_group do + namespace factory: [:group] + end + trait :in_subgroup do namespace factory: [:group, :nested] end diff --git a/spec/factories/projects/import_export/export_relation.rb b/spec/factories/projects/import_export/export_relation.rb deleted file mode 100644 index 2b6419dcecb..00000000000 --- a/spec/factories/projects/import_export/export_relation.rb +++ /dev/null @@ -1,11 +0,0 @@ -# frozen_string_literal: true - -FactoryBot.define do - factory :project_relation_export, class: 'Projects::ImportExport::RelationExport' do - project_export_job factory: :project_export_job - - relation { 'labels' } - status { 0 } - sequence(:jid) { |n| "project_relation_export_#{n}" } - end -end diff --git a/spec/factories/projects/import_export/relation_export.rb b/spec/factories/projects/import_export/relation_export.rb new file mode 100644 index 00000000000..7fab5808d2f --- /dev/null +++ b/spec/factories/projects/import_export/relation_export.rb @@ -0,0 +1,27 @@ +# frozen_string_literal: true + +FactoryBot.define do + factory :project_relation_export, class: 'Projects::ImportExport::RelationExport' do + project_export_job factory: :project_export_job + + relation { 'labels' } + status { Projects::ImportExport::RelationExport::STATUS[:queued] } + sequence(:jid) { |n| "project_relation_export_#{n}" } + + trait :queued do + status { Projects::ImportExport::RelationExport::STATUS[:queued] } + end + + trait :started do + status { Projects::ImportExport::RelationExport::STATUS[:started] } + end + + trait :finished do + status { Projects::ImportExport::RelationExport::STATUS[:finished] } + end + + trait :failed do + status { Projects::ImportExport::RelationExport::STATUS[:failed] } + end + end +end diff --git a/spec/factories/projects/import_export/relation_export_upload.rb b/spec/factories/projects/import_export/relation_export_upload.rb new file mode 100644 index 00000000000..eaa57d6ee59 --- /dev/null +++ b/spec/factories/projects/import_export/relation_export_upload.rb @@ -0,0 +1,8 @@ +# frozen_string_literal: true + +FactoryBot.define do + factory :project_relation_export_upload, class: 'Projects::ImportExport::RelationExportUpload' do + relation_export factory: :project_relation_export + export_file { fixture_file_upload("spec/fixtures/gitlab/import_export/labels.tar.gz") } + end +end diff --git a/spec/factories/projects/wiki_repositories.rb b/spec/factories/projects/wiki_repositories.rb new file mode 100644 index 00000000000..78e02ff297b --- /dev/null +++ b/spec/factories/projects/wiki_repositories.rb @@ -0,0 +1,7 @@ +# frozen_string_literal: true + +FactoryBot.define do + factory :project_wiki_repository, class: 'Projects::WikiRepository' do + project + end +end diff --git a/spec/factories/protected_branches.rb b/spec/factories/protected_branches.rb index 425352783dd..75b375733a6 100644 --- a/spec/factories/protected_branches.rb +++ b/spec/factories/protected_branches.rb @@ -13,7 +13,8 @@ FactoryBot.define do end after(:create) do |protected_branch, evaluator| - break unless protected_branch.project&.persisted? + # Do not use `break` because it will cause `LocalJumpError` + next unless protected_branch.project&.persisted? ProtectedBranches::CacheService.new(protected_branch.project).refresh end @@ -39,63 +40,63 @@ FactoryBot.define do end end - trait :maintainers_can_push do + trait :no_one_can_merge do transient do - default_push_level { false } + default_merge_level { false } end after(:build) do |protected_branch| - protected_branch.push_access_levels.new(access_level: Gitlab::Access::MAINTAINER) + protected_branch.merge_access_levels.new(access_level: Gitlab::Access::NO_ACCESS) end end - trait :maintainers_can_merge do + trait :developers_can_merge do transient do - default_push_level { false } + default_merge_level { false } end after(:build) do |protected_branch| - protected_branch.push_access_levels.new(access_level: Gitlab::Access::MAINTAINER) + protected_branch.merge_access_levels.new(access_level: Gitlab::Access::DEVELOPER) end end - trait :developers_can_push do + trait :maintainers_can_merge do transient do - default_push_level { false } + default_merge_level { false } end after(:build) do |protected_branch| - protected_branch.push_access_levels.new(access_level: Gitlab::Access::DEVELOPER) + protected_branch.merge_access_levels.new(access_level: Gitlab::Access::MAINTAINER) end end - trait :developers_can_merge do + trait :no_one_can_push do transient do - default_merge_level { false } + default_push_level { false } end after(:build) do |protected_branch| - protected_branch.merge_access_levels.new(access_level: Gitlab::Access::DEVELOPER) + protected_branch.push_access_levels.new(access_level: Gitlab::Access::NO_ACCESS) end end - trait :no_one_can_push do + trait :developers_can_push do transient do default_push_level { false } end after(:build) do |protected_branch| - protected_branch.push_access_levels.new(access_level: Gitlab::Access::NO_ACCESS) + protected_branch.push_access_levels.new(access_level: Gitlab::Access::DEVELOPER) end end - trait :no_one_can_merge do + trait :maintainers_can_push do transient do - default_merge_level { false } + default_push_level { false } end after(:build) do |protected_branch| - protected_branch.merge_access_levels.new(access_level: Gitlab::Access::NO_ACCESS) + protected_branch.push_access_levels.new(access_level: Gitlab::Access::MAINTAINER) end end end diff --git a/spec/factories/user_statuses.rb b/spec/factories/user_statuses.rb index dbed6031ce1..79dc1eb7931 100644 --- a/spec/factories/user_statuses.rb +++ b/spec/factories/user_statuses.rb @@ -5,5 +5,9 @@ FactoryBot.define do user emoji { 'coffee' } message { 'I crave coffee' } + + trait :busy do + availability { 'busy' } + end end end diff --git a/spec/factories/users.rb b/spec/factories/users.rb index 2e7c6116fe6..2b53a469841 100644 --- a/spec/factories/users.rb +++ b/spec/factories/users.rb @@ -27,6 +27,10 @@ FactoryBot.define do after(:build) { |user, _| user.block! } end + trait :locked do + after(:build) { |user, _| user.lock_access! } + end + trait :disallowed_password do password { User::DISALLOWED_PASSWORDS.first } end diff --git a/spec/factories/users/ghost_user_migrations.rb b/spec/factories/users/ghost_user_migrations.rb index 0fe7cded4f3..77b7f7e6df4 100644 --- a/spec/factories/users/ghost_user_migrations.rb +++ b/spec/factories/users/ghost_user_migrations.rb @@ -5,5 +5,6 @@ FactoryBot.define do association :user initiator_user { association(:user) } hard_delete { false } + consume_after { Time.current } end end diff --git a/spec/factories/users/namespace_commit_emails.rb b/spec/factories/users/namespace_commit_emails.rb new file mode 100644 index 00000000000..2f7e89bf766 --- /dev/null +++ b/spec/factories/users/namespace_commit_emails.rb @@ -0,0 +1,9 @@ +# frozen_string_literal: true + +FactoryBot.define do + factory :namespace_commit_email, class: 'Users::NamespaceCommitEmail' do + email + user { email.user } + namespace + end +end diff --git a/spec/features/admin/admin_dev_ops_reports_spec.rb b/spec/features/admin/admin_dev_ops_reports_spec.rb index bf32819cb52..f65862c568f 100644 --- a/spec/features/admin/admin_dev_ops_reports_spec.rb +++ b/spec/features/admin/admin_dev_ops_reports_spec.rb @@ -9,9 +9,9 @@ RSpec.describe 'DevOps Report page', :js do gitlab_enable_admin_mode_sign_in(admin) end - context 'with devops_adoption feature flag disabled' do + context 'without licensed feature devops adoption' do before do - stub_feature_flags(devops_adoption: false) + stub_licensed_features(devops_adoption: false) end it 'has dismissable intro callout' do diff --git a/spec/features/admin/admin_hook_logs_spec.rb b/spec/features/admin/admin_hook_logs_spec.rb index 6caf2b24555..a2ee6343886 100644 --- a/spec/features/admin/admin_hook_logs_spec.rb +++ b/spec/features/admin/admin_hook_logs_spec.rb @@ -3,12 +3,11 @@ require 'spec_helper' RSpec.describe 'Admin::HookLogs' do - let(:project) { create(:project) } - let(:system_hook) { create(:system_hook) } - let(:hook_log) { create(:web_hook_log, web_hook: system_hook, internal_error_message: 'some error') } + 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) } before do - admin = create(:admin) sign_in(admin) gitlab_enable_admin_mode_sign_in(admin) end diff --git a/spec/features/admin/admin_hooks_spec.rb b/spec/features/admin/admin_hooks_spec.rb index 901315752d6..dc5b0ae009e 100644 --- a/spec/features/admin/admin_hooks_spec.rb +++ b/spec/features/admin/admin_hooks_spec.rb @@ -5,7 +5,7 @@ require 'spec_helper' RSpec.describe 'Admin::Hooks' do include Spec::Support::Helpers::ModalHelpers - let(:user) { create(:admin) } + let_it_be(:user) { create(:admin) } before do sign_in(user) diff --git a/spec/features/admin/admin_mode/workers_spec.rb b/spec/features/admin/admin_mode/workers_spec.rb index 12f5e20e176..8405e9132b6 100644 --- a/spec/features/admin/admin_mode/workers_spec.rb +++ b/spec/features/admin/admin_mode/workers_spec.rb @@ -37,56 +37,26 @@ RSpec.describe 'Admin mode for workers', :request_store do gitlab_enable_admin_mode_sign_in(user) end - context 'when user_destroy_with_limited_execution_time_worker is enabled' do - it 'can delete user', :js do - visit admin_user_path(user_to_delete) - - click_action_in_user_dropdown(user_to_delete.id, 'Delete user') - - page.within '.modal-dialog' do - find("input[name='username']").send_keys(user_to_delete.name) - click_button 'Delete user' - - wait_for_requests - end - - expect(page).to have_content('The user is being deleted.') - - # Perform jobs while logged out so that admin mode is only enabled in job metadata - execute_jobs_signed_out(user) + it 'can delete user', :js do + visit admin_user_path(user_to_delete) - visit admin_user_path(user_to_delete) + click_action_in_user_dropdown(user_to_delete.id, 'Delete user') - expect(find('h1.page-title')).to have_content('(Blocked)') - end - end + page.within '.modal-dialog' do + find("input[name='username']").send_keys(user_to_delete.name) + click_button 'Delete user' - context 'when user_destroy_with_limited_execution_time_worker is disabled' do - before do - stub_feature_flags(user_destroy_with_limited_execution_time_worker: false) + wait_for_requests end - it 'can delete user', :js do - visit admin_user_path(user_to_delete) - - click_action_in_user_dropdown(user_to_delete.id, 'Delete user') - - page.within '.modal-dialog' do - find("input[name='username']").send_keys(user_to_delete.name) - click_button 'Delete user' - - wait_for_requests - end + expect(page).to have_content('The user is being deleted.') - expect(page).to have_content('The user is being deleted.') + # Perform jobs while logged out so that admin mode is only enabled in job metadata + execute_jobs_signed_out(user) - # Perform jobs while logged out so that admin mode is only enabled in job metadata - execute_jobs_signed_out(user) - - visit admin_user_path(user_to_delete) + visit admin_user_path(user_to_delete) - expect(page).to have_title('Not Found') - end + expect(find('h1.page-title')).to have_content('(Blocked)') end end end diff --git a/spec/features/admin/admin_runners_spec.rb b/spec/features/admin/admin_runners_spec.rb index 35e57213bdb..92a3b388994 100644 --- a/spec/features/admin/admin_runners_spec.rb +++ b/spec/features/admin/admin_runners_spec.rb @@ -72,19 +72,8 @@ RSpec.describe "Admin Runners" do expect(page).to have_text "#{s_('Runners|Stale')} 1" end - describe 'delete all runners in bulk' do - before do - check s_('Runners|Select all') - click_button s_('Runners|Delete selected') - - within_modal do - click_on 'Permanently delete 3 runners' - end - - wait_for_requests - end - - it_behaves_like 'shows no runners registered' + it_behaves_like 'deletes runners in bulk' do + let(:runner_count) { '3' } end end diff --git a/spec/features/admin/admin_settings_spec.rb b/spec/features/admin/admin_settings_spec.rb index 94c5f397670..72c9053ba49 100644 --- a/spec/features/admin/admin_settings_spec.rb +++ b/spec/features/admin/admin_settings_spec.rb @@ -205,6 +205,22 @@ RSpec.describe 'Admin updates settings' do expect(page).to have_content "Application settings saved successfully" end end + + context 'Email confirmation settings' do + it "is set to 'hard' by default" do + expect(current_settings.email_confirmation_setting).to eq('off') + end + + it 'changes the setting', :js do + page.within('.as-signup') do + choose 'Hard' + click_button 'Save changes' + end + + expect(current_settings.email_confirmation_setting).to eq('hard') + expect(page).to have_content "Application settings saved successfully" + end + end end it 'change Sign-in restrictions' do @@ -304,10 +320,12 @@ RSpec.describe 'Admin updates settings' do it 'changes the setting' 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' click_button 'Save changes' end expect(current_settings.jira_connect_application_key).to eq('1234') + expect(current_settings.jira_connect_proxy_url).to eq('https://example.com') expect(page).to have_content "Application settings saved successfully" end end diff --git a/spec/features/admin/admin_users_impersonation_tokens_spec.rb b/spec/features/admin/admin_users_impersonation_tokens_spec.rb index 45dccf9921f..d93dac4834e 100644 --- a/spec/features/admin/admin_users_impersonation_tokens_spec.rb +++ b/spec/features/admin/admin_users_impersonation_tokens_spec.rb @@ -4,18 +4,11 @@ require 'spec_helper' RSpec.describe 'Admin > Users > Impersonation Tokens', :js do include Spec::Support::Helpers::ModalHelpers + include Spec::Support::Helpers::AccessTokenHelpers let(:admin) { create(:admin) } let!(:user) { create(:user) } - def active_impersonation_tokens - find("[data-testid='active-tokens']") - end - - def created_impersonation_token - find_field('new-access-token').value - end - before do sign_in(admin) gitlab_enable_admin_mode_sign_in(admin) @@ -39,12 +32,12 @@ RSpec.describe 'Admin > Users > Impersonation Tokens', :js do click_on "Create impersonation token" - expect(active_impersonation_tokens).to have_text(name) - expect(active_impersonation_tokens).to have_text('in') - expect(active_impersonation_tokens).to have_text('read_api') - expect(active_impersonation_tokens).to have_text('read_user') + expect(active_access_tokens).to have_text(name) + expect(active_access_tokens).to have_text('in') + expect(active_access_tokens).to have_text('read_api') + expect(active_access_tokens).to have_text('read_user') expect(PersonalAccessTokensFinder.new(impersonation: true).execute.count).to equal(1) - expect(created_impersonation_token).not_to be_empty + expect(created_access_token).to match(/[\w-]{20}/) end end @@ -55,16 +48,16 @@ RSpec.describe 'Admin > Users > Impersonation Tokens', :js do it 'only shows impersonation tokens' do visit admin_user_impersonation_tokens_path(user_id: user.username) - expect(active_impersonation_tokens).to have_text(impersonation_token.name) - expect(active_impersonation_tokens).not_to have_text(personal_access_token.name) - expect(active_impersonation_tokens).to have_text('in') + expect(active_access_tokens).to have_text(impersonation_token.name) + expect(active_access_tokens).not_to have_text(personal_access_token.name) + expect(active_access_tokens).to have_text('in') end it 'shows absolute times' do admin.update!(time_display_relative: false) visit admin_user_impersonation_tokens_path(user_id: user.username) - expect(active_impersonation_tokens).to have_text(personal_access_token.expires_at.strftime('%b %-d')) + expect(active_access_tokens).to have_text(personal_access_token.expires_at.strftime('%b %-d')) end end @@ -76,7 +69,7 @@ RSpec.describe 'Admin > Users > Impersonation Tokens', :js do accept_gl_confirm(button_text: 'Revoke') { click_on "Revoke" } - expect(active_impersonation_tokens).to have_text("This user has no active impersonation tokens.") + expect(active_access_tokens).to have_text("This user has no active impersonation tokens.") end it "removes expired tokens from 'active' section" do @@ -84,7 +77,7 @@ RSpec.describe 'Admin > Users > Impersonation Tokens', :js do visit admin_user_impersonation_tokens_path(user_id: user.username) - expect(active_impersonation_tokens).to have_text("This user has no active impersonation tokens.") + expect(active_access_tokens).to have_text("This user has no active impersonation tokens.") end end diff --git a/spec/features/admin/users/user_spec.rb b/spec/features/admin/users/user_spec.rb index 86acf5a05d4..35b5c755b66 100644 --- a/spec/features/admin/users/user_spec.rb +++ b/spec/features/admin/users/user_spec.rb @@ -150,13 +150,32 @@ RSpec.describe 'Admin::Users::User' do context 'before impersonating' do subject { visit admin_user_path(user_to_visit) } - let(:user_to_visit) { another_user } + let_it_be(:user_to_visit) { another_user } + + shared_examples "user that cannot be impersonated" do + it 'disables impersonate button' do + subject + + impersonate_btn = find('[data-testid="impersonate_user_link"]') + + expect(impersonate_btn).not_to be_nil + expect(impersonate_btn['disabled']).not_to be_nil + end + + it "shows tooltip with correct error message" do + subject + + expect(find("span[title='#{impersonation_error_msg}']")).not_to be_nil + end + end context 'for other users' do it 'shows impersonate button for other users' do subject expect(page).to have_content('Impersonate') + impersonate_btn = find('[data-testid="impersonate_user_link"]') + expect(impersonate_btn['disabled']).to be_nil end end @@ -171,15 +190,51 @@ RSpec.describe 'Admin::Users::User' do end context 'for blocked user' do - before do - another_user.block + let_it_be(:blocked_user) { create(:user, :blocked) } + let(:user_to_visit) { blocked_user } + let(:impersonation_error_msg) { _('You cannot impersonate a blocked user') } + + it_behaves_like "user that cannot be impersonated" + end + + context 'for user with expired password' do + let(:user_to_visit) do + another_user.update!(password_expires_at: Time.zone.now - 5.minutes) + another_user end - it 'does not show impersonate button for blocked user' do - subject + let(:impersonation_error_msg) { _("You cannot impersonate a user with an expired password") } - expect(page).not_to have_content('Impersonate') + it_behaves_like "user that cannot be impersonated" + end + + context 'for internal user' do + let_it_be(:internal_user) { create(:user, :bot) } + let(:user_to_visit) { internal_user } + let(:impersonation_error_msg) { _("You cannot impersonate an internal user") } + + it_behaves_like "user that cannot be impersonated" + end + + context 'for locked user' do + let_it_be(:locked_user) { create(:user, :locked) } + let(:user_to_visit) { locked_user } + let(:impersonation_error_msg) { _("You cannot impersonate a user who cannot log in") } + + it_behaves_like "user that cannot be impersonated" + end + + context 'when already impersonating another user' do + let_it_be(:admin_user) { create(:user, :admin) } + let(:impersonation_error_msg) { _("You are already impersonating another user") } + + subject do + visit admin_user_path(admin_user) + click_link 'Impersonate' + visit admin_user_path(another_user) end + + it_behaves_like "user that cannot be impersonated" end context 'when impersonation is disabled' do @@ -216,18 +271,6 @@ RSpec.describe 'Admin::Users::User' do icon = first('[data-testid="incognito-icon"]') expect(icon).not_to be nil end - - context 'a user with an expired password' do - before do - another_user.update!(password_expires_at: Time.zone.now - 5.minutes) - end - - it 'does not redirect to password change page' do - subject - - expect(page).to have_current_path('/') - end - end end context 'ending impersonation' do diff --git a/spec/features/admin_variables_spec.rb b/spec/features/admin_variables_spec.rb index 174d4567520..9ec22bbe948 100644 --- a/spec/features/admin_variables_spec.rb +++ b/spec/features/admin_variables_spec.rb @@ -12,23 +12,9 @@ RSpec.describe 'Instance variables', :js do stub_env('IN_MEMORY_APPLICATION_SETTINGS', 'false') sign_in(admin) gitlab_enable_admin_mode_sign_in(admin) + visit page_path wait_for_requests end - context 'with disabled ff `ci_variable_settings_graphql' do - before do - stub_feature_flags(ci_variable_settings_graphql: false) - visit page_path - end - - it_behaves_like 'variable list', isAdmin: true - end - - context 'with enabled ff `ci_variable_settings_graphql' do - before do - visit page_path - end - - it_behaves_like 'variable list', isAdmin: true - end + it_behaves_like 'variable list', isAdmin: true end diff --git a/spec/features/boards/board_filters_spec.rb b/spec/features/boards/board_filters_spec.rb index 2e4dc4a29fc..eab92de7e8a 100644 --- a/spec/features/boards/board_filters_spec.rb +++ b/spec/features/boards/board_filters_spec.rb @@ -7,8 +7,8 @@ RSpec.describe 'Issue board filters', :js do let_it_be(:user) { create(:user) } let_it_be(:board) { create(:board, project: project) } let_it_be(:project_label) { create(:label, project: project, title: 'Label') } - let_it_be(:milestone_1) { create(:milestone, project: project, due_date: 3.days.from_now ) } - let_it_be(:milestone_2) { create(:milestone, project: project, due_date: Date.tomorrow ) } + let_it_be(:milestone_1) { create(:milestone, project: project, due_date: 3.days.from_now) } + let_it_be(:milestone_2) { create(:milestone, project: project, due_date: Date.tomorrow) } let_it_be(:release) { create(:release, tag: 'v1.0', project: project, milestones: [milestone_1]) } let_it_be(:release_2) { create(:release, tag: 'v2.0', project: project, milestones: [milestone_2]) } let_it_be(:issue_1) { create(:issue, project: project, milestone: milestone_1, author: user) } @@ -22,6 +22,7 @@ RSpec.describe 'Issue board filters', :js do let(:filter_submit) { find('.gl-search-box-by-click-search-button') } before do + stub_feature_flags(apollo_boards: false) project.add_maintainer(user) sign_in(user) diff --git a/spec/features/boards/boards_spec.rb b/spec/features/boards/boards_spec.rb index a09c9d258dc..fee9b5b378e 100644 --- a/spec/features/boards/boards_spec.rb +++ b/spec/features/boards/boards_spec.rb @@ -19,6 +19,7 @@ RSpec.describe 'Project issue boards', :js do context 'signed in user' do before do + stub_feature_flags(apollo_boards: false) project.add_maintainer(user) project.add_maintainer(user2) @@ -29,7 +30,7 @@ RSpec.describe 'Project issue boards', :js do context 'no lists' do before do - visit_project_board_path_without_query_limit(project, board) + visit_project_board(project, board) end it 'creates default lists' do @@ -73,7 +74,7 @@ RSpec.describe 'Project issue boards', :js do let_it_be(:issue10) { create(:labeled_issue, project: project, title: 'issue +', description: 'A+ great issue', labels: [a_plus]) } before do - visit_project_board_path_without_query_limit(project, board) + visit_project_board(project, board) end it 'shows description tooltip on list title', :quarantine do @@ -124,7 +125,7 @@ RSpec.describe 'Project issue boards', :js do it 'infinite scrolls list' do create_list(:labeled_issue, 30, project: project, labels: [planning]) - visit_project_board_path_without_query_limit(project, board) + visit_project_board(project, board) page.within(find('.board:nth-child(2)')) do expect(page.find('.board-header')).to have_content('38') @@ -203,7 +204,7 @@ RSpec.describe 'Project issue boards', :js do expect(find('.board:nth-child(3) [data-testid="board-list-header"]')).to have_content(planning.title) # Make sure list positions are preserved after a reload - visit_project_board_path_without_query_limit(project, board) + visit_project_board(project, board) expect(find('.board:nth-child(2) [data-testid="board-list-header"]')).to have_content(development.title) expect(find('.board:nth-child(3) [data-testid="board-list-header"]')).to have_content(planning.title) @@ -215,15 +216,19 @@ RSpec.describe 'Project issue boards', :js do let_it_be(:list2) { create(:list, board: board, label: development, position: 1) } it 'changes position of list' do - visit_project_board_path_without_query_limit(project, board) + inspect_requests(inject_headers: { 'X-GITLAB-DISABLE-SQL-QUERY-LIMIT' => 'https://gitlab.com/gitlab-org/gitlab/-/issues/323426' }) do + visit_project_board(project, board) + end drag(list_from_index: 0, list_to_index: 1, selector: '.board-header') expect(find('.board:nth-child(1) [data-testid="board-list-header"]')).to have_content(development.title) expect(find('.board:nth-child(2) [data-testid="board-list-header"]')).to have_content(planning.title) - # Make sure list positions are preserved after a reload - visit_project_board_path_without_query_limit(project, board) + inspect_requests(inject_headers: { 'X-GITLAB-DISABLE-SQL-QUERY-LIMIT' => 'https://gitlab.com/gitlab-org/gitlab/-/issues/323426' }) do + # Make sure list positions are preserved after a reload + visit_project_board(project, board) + end expect(find('.board:nth-child(1) [data-testid="board-list-header"]')).to have_content(development.title) expect(find('.board:nth-child(2) [data-testid="board-list-header"]')).to have_content(planning.title) @@ -234,7 +239,9 @@ RSpec.describe 'Project issue boards', :js do selector = '.board:not(.is-ghost) .board-header' expect(page).to have_selector(selector, text: development.title, count: 1) - drag(list_from_index: 2, list_to_index: 1, selector: '.board-header', perform_drop: false) + inspect_requests(inject_headers: { 'X-GITLAB-DISABLE-SQL-QUERY-LIMIT' => 'https://gitlab.com/gitlab-org/gitlab/-/issues/323426' }) do + drag(list_from_index: 2, list_to_index: 1, selector: '.board-header', perform_drop: false) + end expect(page).to have_selector(selector, text: development.title, count: 1) end @@ -492,7 +499,7 @@ RSpec.describe 'Project issue boards', :js do context 'keyboard shortcuts' do before do - visit_project_board_path_without_query_limit(project, board) + visit_project_board(project, board) wait_for_requests end @@ -505,6 +512,7 @@ RSpec.describe 'Project issue boards', :js do context 'signed out user' do before do + stub_feature_flags(apollo_boards: false) visit project_board_path(project, board) wait_for_requests end @@ -526,6 +534,7 @@ RSpec.describe 'Project issue boards', :js do let_it_be(:user_guest) { create(:user) } before do + stub_feature_flags(apollo_boards: false) project.add_guest(user_guest) sign_in(user_guest) visit project_board_path(project, board) @@ -587,11 +596,9 @@ RSpec.describe 'Project issue boards', :js do end end - def visit_project_board_path_without_query_limit(project, board) - inspect_requests(inject_headers: { 'X-GITLAB-DISABLE-SQL-QUERY-LIMIT' => 'https://gitlab.com/gitlab-org/gitlab/-/issues/323426' }) do - visit project_board_path(project, board) + def visit_project_board(project, board) + visit project_board_path(project, board) - wait_for_requests - end + wait_for_requests end end diff --git a/spec/features/boards/issue_ordering_spec.rb b/spec/features/boards/issue_ordering_spec.rb index 57f2bf26752..a3dda3b9d2f 100644 --- a/spec/features/boards/issue_ordering_spec.rb +++ b/spec/features/boards/issue_ordering_spec.rb @@ -15,6 +15,7 @@ RSpec.describe 'Issue Boards', :js do let!(:issue3) { create(:labeled_issue, project: project, title: 'testing 3', labels: [label], relative_position: 1) } before do + stub_feature_flags(apollo_boards: false) project.add_maintainer(user) sign_in(user) diff --git a/spec/features/boards/sidebar_labels_spec.rb b/spec/features/boards/sidebar_labels_spec.rb index 511233b50c0..12d91e9c5a8 100644 --- a/spec/features/boards/sidebar_labels_spec.rb +++ b/spec/features/boards/sidebar_labels_spec.rb @@ -20,6 +20,7 @@ RSpec.describe 'Project issue boards sidebar labels', :js do let(:card) { find('.board:nth-child(2)').first('.board-card') } before do + stub_feature_flags(apollo_boards: false) project.add_maintainer(user) sign_in(user) diff --git a/spec/features/boards/sidebar_spec.rb b/spec/features/boards/sidebar_spec.rb index 0e914ae19d1..2b2a412194a 100644 --- a/spec/features/boards/sidebar_spec.rb +++ b/spec/features/boards/sidebar_spec.rb @@ -15,6 +15,7 @@ RSpec.describe 'Project issue boards sidebar', :js do let_it_be(:issue, reload: true) { create(:issue, project: project, relative_position: 1) } before do + stub_feature_flags(apollo_boards: false) project.add_maintainer(user) sign_in(user) diff --git a/spec/features/boards/user_adds_lists_to_board_spec.rb b/spec/features/boards/user_adds_lists_to_board_spec.rb index 26c310a6f56..480a88a6b84 100644 --- a/spec/features/boards/user_adds_lists_to_board_spec.rb +++ b/spec/features/boards/user_adds_lists_to_board_spec.rb @@ -31,13 +31,15 @@ RSpec.describe 'User adds lists', :js do with_them do before do + stub_feature_flags(apollo_boards: false) sign_in(user) set_cookie('sidebar_collapsed', 'true') - if board_type == :project + case board_type + when :project visit project_board_path(project, project_board) - elsif board_type == :group + when :group visit group_board_path(group, group_board) end diff --git a/spec/features/boards/user_visits_board_spec.rb b/spec/features/boards/user_visits_board_spec.rb index 7fe32557d6a..c386477fa9d 100644 --- a/spec/features/boards/user_visits_board_spec.rb +++ b/spec/features/boards/user_visits_board_spec.rb @@ -21,7 +21,7 @@ RSpec.describe 'User visits issue boards', :js do let_it_be(:label1) { create(:group_label, group: group, name: label_name1) } let_it_be(:label2) { create(:group_label, group: group, name: label_name2) } - let_it_be(:assignee) { create_default(:group_member, :maintainer, user: create(:user, username: assignee_username), group: group ).user } + let_it_be(:assignee) { create_default(:group_member, :maintainer, user: create(:user, username: assignee_username), group: group).user } let_it_be(:milestone) { create_default(:milestone, project: project, start_date: Date.today - 1, due_date: 7.days.from_now) } before_all do @@ -44,6 +44,7 @@ RSpec.describe 'User visits issue boards', :js do with_them do before do + stub_feature_flags(apollo_boards: false) visit board_path wait_for_requests @@ -59,6 +60,7 @@ RSpec.describe 'User visits issue boards', :js do end context "project boards" do + stub_feature_flags(apollo_boards: false) let_it_be(:board) { create_default(:board, project: project) } let_it_be(:backlog_list) { create_default(:backlog_list, board: board) } @@ -68,6 +70,7 @@ RSpec.describe 'User visits issue boards', :js do end context "group boards" do + stub_feature_flags(apollo_boards: false) let_it_be(:board) { create_default(:board, group: group) } let_it_be(:backlog_list) { create_default(:backlog_list, board: board) } diff --git a/spec/features/broadcast_messages_spec.rb b/spec/features/broadcast_messages_spec.rb index f339d45671d..1fec68a1d98 100644 --- a/spec/features/broadcast_messages_spec.rb +++ b/spec/features/broadcast_messages_spec.rb @@ -31,7 +31,8 @@ RSpec.describe 'Broadcast Messages' do expect(page).not_to have_content 'SampleMessage' end - it 'broadcast message is still hidden after refresh', :js do + it 'broadcast message is still hidden after refresh', :js, + quarantine: 'https://gitlab.com/gitlab-org/gitlab/-/issues/347118' do visit root_path find('.js-dismiss-current-broadcast-notification').click diff --git a/spec/features/commits_spec.rb b/spec/features/commits_spec.rb index db841ffc627..97f820c1518 100644 --- a/spec/features/commits_spec.rb +++ b/spec/features/commits_spec.rb @@ -212,13 +212,13 @@ RSpec.describe 'Commits' do end context 'author is just a name' do - let(:author) { "#{author_commit.author_name}" } + let(:author) { author_commit.author_name.to_s } it_behaves_like 'show commits by author' end context 'author is just an email' do - let(:author) { "#{author_commit.author_email}" } + let(:author) { author_commit.author_email.to_s } it_behaves_like 'show commits by author' end diff --git a/spec/features/cycle_analytics_spec.rb b/spec/features/cycle_analytics_spec.rb index 488a4f84297..8de4c66c62f 100644 --- a/spec/features/cycle_analytics_spec.rb +++ b/spec/features/cycle_analytics_spec.rb @@ -56,7 +56,7 @@ RSpec.describe 'Value Stream Analytics', :js do end end - context "when there's value stream analytics data" do + context "when there's value stream analytics data", :sidekiq_inline do # NOTE: in https://gitlab.com/gitlab-org/gitlab/-/merge_requests/68595 travel back # 5 days in time before we create data for these specs, to mitigate some flakiness # So setting the date range to be the last 2 days should skip past the existing data @@ -103,7 +103,7 @@ RSpec.describe 'Value Stream Analytics', :js do end end - it 'shows data on each stage', :sidekiq_might_not_need_inline, quarantine: 'https://gitlab.com/gitlab-org/gitlab/-/issues/338332' do + it 'shows data on each stage', quarantine: 'https://gitlab.com/gitlab-org/gitlab/-/issues/338332' do expect_issue_to_be_present click_stage('Plan') @@ -207,11 +207,11 @@ RSpec.describe 'Value Stream Analytics', :js do wait_for_requests end - it 'does not show the commit stats' do + it 'does not show the commit stats', :sidekiq_inline do expect(page.find(metrics_selector)).not_to have_selector("#commits") end - it 'does not show restricted stages', :aggregate_failures do + it 'does not show restricted stages', :aggregate_failures, :sidekiq_inline do expect(find(stage_table_selector)).to have_content(issue.title) expect(page).to have_selector('.gl-path-nav-list-item', text: 'Issue') diff --git a/spec/features/dashboard/datetime_on_tooltips_spec.rb b/spec/features/dashboard/datetime_on_tooltips_spec.rb index 875ae41c55d..de8858fa8fa 100644 --- a/spec/features/dashboard/datetime_on_tooltips_spec.rb +++ b/spec/features/dashboard/datetime_on_tooltips_spec.rb @@ -14,8 +14,8 @@ RSpec.describe 'Tooltips on .timeago dates', :js do context 'on the activity tab' do before do - Event.create!( project: project, author_id: user.id, action: :joined, - updated_at: created_date, created_at: created_date) + Event.create!(project: project, author_id: user.id, action: :joined, + updated_at: created_date, created_at: created_date) sign_in user visit user_activity_path(user) diff --git a/spec/features/dashboard/projects_spec.rb b/spec/features/dashboard/projects_spec.rb index 0b468854322..c132caa88c8 100644 --- a/spec/features/dashboard/projects_spec.rb +++ b/spec/features/dashboard/projects_spec.rb @@ -139,7 +139,7 @@ RSpec.describe 'Dashboard Projects' do end describe 'with a pipeline', :clean_gitlab_redis_shared_state do - let_it_be(:pipeline) { create(:ci_pipeline, project: project, sha: project.commit.sha, ref: project.default_branch) } + let!(:pipeline) { create(:ci_pipeline, project: project, sha: project.commit.sha, ref: project.default_branch) } before do # Since the cache isn't updated when a new pipeline is created @@ -151,7 +151,7 @@ RSpec.describe 'Dashboard Projects' do it 'shows that the last pipeline passed' do visit dashboard_projects_path - page.within('.controls') do + page.within('[data-testid="project_controls"]') do expect(page).to have_xpath("//a[@href='#{pipelines_project_commit_path(project, project.commit, ref: pipeline.ref)}']") expect(page).to have_css('.ci-status-link') expect(page).to have_css('.ci-status-icon-success') @@ -163,7 +163,7 @@ RSpec.describe 'Dashboard Projects' do it 'does not show the pipeline status' do visit dashboard_projects_path - page.within('.controls') do + page.within('[data-testid="project_controls"]') do expect(page).not_to have_xpath("//a[@href='#{pipelines_project_commit_path(project, project.commit, ref: pipeline.ref)}']") expect(page).not_to have_css('.ci-status-link') expect(page).not_to have_css('.ci-status-icon-success') diff --git a/spec/features/global_search_spec.rb b/spec/features/global_search_spec.rb index 666bf3594de..2e63ec2d4f2 100644 --- a/spec/features/global_search_spec.rb +++ b/spec/features/global_search_spec.rb @@ -2,14 +2,13 @@ require 'spec_helper' -RSpec.describe 'Global search' do +RSpec.describe 'Global search', :js do include AfterNextHelpers - let(:user) { create(:user) } - let(:project) { create(:project, namespace: user.namespace) } + let_it_be(:user) { create(:user) } + let_it_be(:project) { create(:project, namespace: user.namespace) } before do - stub_feature_flags(search_page_vertical_nav: false) project.add_maintainer(user) sign_in(user) end @@ -42,7 +41,7 @@ RSpec.describe 'Global search' do end end - it 'closes the dropdown on blur', :js do + it 'closes the dropdown on blur' do find('#search').click fill_in 'search', with: "a" @@ -59,7 +58,7 @@ RSpec.describe 'Global search' do expect(page).to have_no_selector('#js-header-search') end - it 'focuses search input when shortcut "s" is pressed', :js do + it 'focuses search input when shortcut "s" is pressed' do expect(page).not_to have_selector('#search:focus') find('body').native.send_key('s') @@ -74,7 +73,7 @@ RSpec.describe 'Global search' do stub_feature_flags(new_header_search: true) visit dashboard_projects_path - # intialize javascript loaded input search input field + # initialize javascript loaded input search input field find('#search').click find('body').click end @@ -84,7 +83,7 @@ RSpec.describe 'Global search' do expect(page).to have_selector('#js-header-search') end - it 'focuses search input when shortcut "s" is pressed', :js do + it 'focuses search input when shortcut "s" is pressed' do expect(page).not_to have_selector('#search:focus') find('body').native.send_key('s') diff --git a/spec/features/graphql_known_operations_spec.rb b/spec/features/graphql_known_operations_spec.rb index ef406f12902..80214307be3 100644 --- a/spec/features/graphql_known_operations_spec.rb +++ b/spec/features/graphql_known_operations_spec.rb @@ -24,6 +24,6 @@ RSpec.describe 'Graphql known operations', :js do expect(known_operations).to include("searchProjects") expect(known_operations.length).to be > 20 - expect(known_operations).to all( match(%r{^[a-z]+}i) ) + expect(known_operations).to all(match(%r{^[a-z]+}i)) end end diff --git a/spec/features/group_variables_spec.rb b/spec/features/group_variables_spec.rb index ab24162ad5a..e2c659d7dfe 100644 --- a/spec/features/group_variables_spec.rb +++ b/spec/features/group_variables_spec.rb @@ -11,23 +11,9 @@ RSpec.describe 'Group variables', :js do before do group.add_owner(user) gitlab_sign_in(user) + visit page_path wait_for_requests end - context 'with disabled ff `ci_variable_settings_graphql' do - before do - stub_feature_flags(ci_variable_settings_graphql: false) - visit page_path - end - - it_behaves_like 'variable list' - end - - context 'with enabled ff `ci_variable_settings_graphql' do - before do - visit page_path - end - - it_behaves_like 'variable list' - end + it_behaves_like 'variable list' end diff --git a/spec/features/groups/activity_spec.rb b/spec/features/groups/activity_spec.rb index 6ca69e76d33..5bac80959b1 100644 --- a/spec/features/groups/activity_spec.rb +++ b/spec/features/groups/activity_spec.rb @@ -3,7 +3,7 @@ require 'spec_helper' RSpec.describe 'Group activity page' do - let(:user) { create(:group_member, :developer, user: create(:user), group: group ).user } + let(:user) { create(:group_member, :developer, user: create(:user), group: group).user } let(:group) { create(:group) } let(:path) { activity_group_path(group) } diff --git a/spec/features/groups/board_sidebar_spec.rb b/spec/features/groups/board_sidebar_spec.rb index 69a6788e438..10ef28f3fbc 100644 --- a/spec/features/groups/board_sidebar_spec.rb +++ b/spec/features/groups/board_sidebar_spec.rb @@ -6,7 +6,7 @@ RSpec.describe 'Group Issue Boards', :js do include BoardHelpers let(:group) { create(:group) } - let(:user) { create(:group_member, user: create(:user), group: group ).user } + let(:user) { create(:group_member, user: create(:user), group: group).user } let!(:project_1) { create(:project, :public, group: group) } let!(:project_2) { create(:project, :public, group: group) } let!(:project_1_label) { create(:label, project: project_1, name: 'Development 1') } @@ -19,6 +19,7 @@ RSpec.describe 'Group Issue Boards', :js do let(:card) { find('.board:nth-child(1)').first('.board-card') } before do + stub_feature_flags(apollo_boards: false) sign_in(user) visit group_board_path(group, board) diff --git a/spec/features/groups/empty_states_spec.rb b/spec/features/groups/empty_states_spec.rb index 84882fc674e..f1a8f97461a 100644 --- a/spec/features/groups/empty_states_spec.rb +++ b/spec/features/groups/empty_states_spec.rb @@ -4,7 +4,7 @@ require 'spec_helper' RSpec.describe 'Group empty states' do let(:group) { create(:group) } - let(:user) { create(:group_member, :developer, user: create(:user), group: group ).user } + let(:user) { create(:group_member, :developer, user: create(:user), group: group).user } before do sign_in(user) diff --git a/spec/features/groups/group_runners_spec.rb b/spec/features/groups/group_runners_spec.rb index e9807c487d5..c9d1c69e9e1 100644 --- a/spec/features/groups/group_runners_spec.rb +++ b/spec/features/groups/group_runners_spec.rb @@ -4,6 +4,7 @@ require 'spec_helper' RSpec.describe "Group Runners" do include Spec::Support::Helpers::Features::RunnersHelpers + include Spec::Support::Helpers::ModalHelpers let_it_be(:group_owner) { create(:user) } let_it_be(:group) { create(:group) } @@ -157,6 +158,19 @@ RSpec.describe "Group Runners" do end end + context "with multiple runners" do + before do + create(:ci_runner, :group, groups: [group], description: 'runner-foo') + create(:ci_runner, :group, groups: [group], description: 'runner-bar') + + visit group_runners_path(group) + end + + it_behaves_like 'deletes runners in bulk' do + let(:runner_count) { '2' } + end + end + describe 'filtered search' do before do visit group_runners_path(group) @@ -201,18 +215,32 @@ RSpec.describe "Group Runners" do end describe "Group runner edit page", :js do - let!(:group_runner) do - create(:ci_runner, :group, groups: [group]) - end + context 'when updating a group runner' do + let_it_be(:group_runner) { create(:ci_runner, :group, groups: [group]) } - before do - visit edit_group_runner_path(group, group_runner) - wait_for_requests + before do + visit edit_group_runner_path(group, group_runner) + wait_for_requests + end + + it_behaves_like 'submits edit runner form' do + let(:runner) { group_runner } + let(:runner_page_path) { group_runner_path(group, group_runner) } + end end - it_behaves_like 'submits edit runner form' do - let(:runner) { group_runner } - let(:runner_page_path) { group_runner_path(group, group_runner) } + context 'when updating a project runner' do + let_it_be(:project_runner) { create(:ci_runner, :project, projects: [project]) } + + before do + visit edit_group_runner_path(group, project_runner) + wait_for_requests + end + + it_behaves_like 'submits edit runner form' do + let(:runner) { project_runner } + let(:runner_page_path) { group_runner_path(group, project_runner) } + end end end end diff --git a/spec/features/groups/group_settings_spec.rb b/spec/features/groups/group_settings_spec.rb index 2f599d24b01..81ff0088e1e 100644 --- a/spec/features/groups/group_settings_spec.rb +++ b/spec/features/groups/group_settings_spec.rb @@ -150,13 +150,15 @@ RSpec.describe 'Edit group settings' do it 'can successfully transfer the group' do visit edit_group_path(selected_group) - page.within('.js-group-transfer-form') do - namespace_select.find('button').click - namespace_select.find('.dropdown-menu p', text: target_group_name, match: :first).click - - click_button 'Transfer group' + page.within('[data-testid="transfer-locations-dropdown"]') do + click_button _('Select parent group') + fill_in _('Search'), with: target_group_name + wait_for_requests + click_button target_group_name end + click_button s_('GroupSettings|Transfer group') + page.within(confirm_modal) do expect(page).to have_text "You are going to transfer #{selected_group.name} to another namespace. Are you ABSOLUTELY sure?" @@ -169,16 +171,16 @@ RSpec.describe 'Edit group settings' do end end - context 'from a subgroup' do + context 'when transfering from a subgroup' do let(:selected_group) { create(:group, path: 'foo-subgroup', parent: group) } - context 'to no parent group' do + context 'when transfering to no parent group' do let(:target_group_name) { 'No parent group' } it_behaves_like 'can transfer the group' end - context 'to a different parent group' do + context 'when transfering to a parent group' do let(:target_group) { create(:group, path: 'foo-parentgroup') } let(:target_group_name) { target_group.name } @@ -190,14 +192,11 @@ RSpec.describe 'Edit group settings' do end end - context 'from a root group' 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 } - context 'to a parent group' do - let(:target_group_name) { group.name } - - it_behaves_like 'can transfer the group' - end + it_behaves_like 'can transfer the group' end end diff --git a/spec/features/groups/issues_spec.rb b/spec/features/groups/issues_spec.rb index eec07c84cde..d4e88505118 100644 --- a/spec/features/groups/issues_spec.rb +++ b/spec/features/groups/issues_spec.rb @@ -69,7 +69,7 @@ RSpec.describe 'Group issues page' do context 'issues list', :js do let(:subgroup) { create(:group, parent: group) } let(:subgroup_project) { create(:project, :public, group: subgroup) } - let(:user_in_group) { create(:group_member, :maintainer, user: create(:user), group: group ).user } + let(:user_in_group) { create(:group_member, :maintainer, user: create(:user), group: group).user } let!(:issue) { create(:issue, project: project, title: 'root group issue') } let!(:subgroup_issue) { create(:issue, project: subgroup_project, title: 'subgroup issue') } @@ -111,7 +111,7 @@ RSpec.describe 'Group issues page' do context 'projects with issues disabled' do describe 'issue dropdown' do - let(:user_in_group) { create(:group_member, :maintainer, user: create(:user), group: group ).user } + let(:user_in_group) { create(:group_member, :maintainer, user: create(:user), group: group).user } before do [project, project_with_issues_disabled].each { |project| project.add_maintainer(user_in_group) } @@ -129,7 +129,7 @@ RSpec.describe 'Group issues page' do end context 'manual ordering', :js do - let(:user_in_group) { create(:group_member, :maintainer, user: create(:user), group: group ).user } + let(:user_in_group) { create(:group_member, :maintainer, user: create(:user), group: group).user } let!(:issue1) { create(:issue, project: project, title: 'Issue #1', relative_position: 1) } let!(:issue2) { create(:issue, project: project, title: 'Issue #2', relative_position: 2) } @@ -161,6 +161,8 @@ RSpec.describe 'Group issues page' do visit issues_group_path(group) select_manual_sort + wait_for_requests + drag_to(selector: '.manual-ordering', from_index: 0, to_index: 2) expect_issue_order @@ -176,6 +178,8 @@ RSpec.describe 'Group issues page' do visit issues_group_path(group) select_manual_sort + wait_for_requests + drag_to(selector: '.manual-ordering', from_index: 0, to_index: 2) expect(page).to have_text 'An error occurred while reordering issues.' @@ -195,7 +199,7 @@ RSpec.describe 'Group issues page' do end context 'issues pagination', :js do - let(:user_in_group) { create(:group_member, :maintainer, user: create(:user), group: group ).user } + let(:user_in_group) { create(:group_member, :maintainer, user: create(:user), group: group).user } let!(:issues) do (1..25).to_a.map { |index| create(:issue, project: project, title: "Issue #{index}") } diff --git a/spec/features/groups/milestone_spec.rb b/spec/features/groups/milestone_spec.rb index 42eaa8358a1..92a40459737 100644 --- a/spec/features/groups/milestone_spec.rb +++ b/spec/features/groups/milestone_spec.rb @@ -5,7 +5,7 @@ require 'spec_helper' RSpec.describe 'Group milestones' do let_it_be(:group) { create(:group) } let_it_be(:project) { create(:project_empty_repo, group: group) } - let_it_be(:user) { create(:group_member, :maintainer, user: create(:user), group: group ).user } + let_it_be(:user) { create(:group_member, :maintainer, user: create(:user), group: group).user } around do |example| freeze_time { example.run } diff --git a/spec/features/groups/milestones_sorting_spec.rb b/spec/features/groups/milestones_sorting_spec.rb index 125bf9ce3a7..6f3fc72775f 100644 --- a/spec/features/groups/milestones_sorting_spec.rb +++ b/spec/features/groups/milestones_sorting_spec.rb @@ -11,7 +11,7 @@ RSpec.describe 'Milestones sorting', :js do let!(:project_milestone2) { create(:milestone, project: project, title: 'v2.0', due_date: 5.days.from_now) } let!(:other_project_milestone2) { create(:milestone, project: other_project, title: 'v2.0', due_date: 5.days.from_now) } let!(:group_milestone) { create(:milestone, group: group, title: 'v3.0', due_date: 7.days.from_now) } - let(:user) { create(:group_member, :maintainer, user: create(:user), group: group ).user } + let(:user) { create(:group_member, :maintainer, user: create(:user), group: group).user } before do sign_in(user) diff --git a/spec/features/groups/settings/repository_spec.rb b/spec/features/groups/settings/repository_spec.rb index f6b8bbdd35f..cd7dcbdb28d 100644 --- a/spec/features/groups/settings/repository_spec.rb +++ b/spec/features/groups/settings/repository_spec.rb @@ -23,26 +23,9 @@ RSpec.describe 'Group Repository settings', :js do stub_container_registry_config(enabled: true) end - context 'when ajax deploy tokens is enabled' do - before do - stub_feature_flags(ajax_new_deploy_token: true) - end - - it_behaves_like 'a deploy token in settings' do - let(:entity_type) { 'group' } - let(:page_path) { group_settings_repository_path(group) } - end - end - - context 'when ajax deploy tokens is disabled' do - before do - stub_feature_flags(ajax_new_deploy_token: false) - end - - it_behaves_like 'a deploy token in settings' do - let(:entity_type) { 'group' } - let(:page_path) { group_settings_repository_path(group) } - end + it_behaves_like 'a deploy token in settings' do + let(:entity_type) { 'group' } + let(:page_path) { group_settings_repository_path(group) } end end diff --git a/spec/features/help_pages_spec.rb b/spec/features/help_pages_spec.rb index 546257b9f10..eef48d09f32 100644 --- a/spec/features/help_pages_spec.rb +++ b/spec/features/help_pages_spec.rb @@ -41,7 +41,7 @@ RSpec.describe 'Help Pages' do end it 'renders the version check badge' do - expect(page).to have_selector('.js-gitlab-version-check') + expect(page).to have_selector('.js-gitlab-version-check-badge') end end diff --git a/spec/features/ide/user_opens_merge_request_spec.rb b/spec/features/ide/user_opens_merge_request_spec.rb index 8a95d7c5544..4ffa5212970 100644 --- a/spec/features/ide/user_opens_merge_request_spec.rb +++ b/spec/features/ide/user_opens_merge_request_spec.rb @@ -21,6 +21,6 @@ RSpec.describe 'IDE merge request', :js do wait_for_requests - expect(page).to have_selector('.monaco-diff-editor') + expect(page).not_to have_selector('.monaco-diff-editor') end end diff --git a/spec/features/ide_spec.rb b/spec/features/ide_spec.rb index c7c740c2293..1f6d34efc0f 100644 --- a/spec/features/ide_spec.rb +++ b/spec/features/ide_spec.rb @@ -3,47 +3,90 @@ require 'spec_helper' RSpec.describe 'IDE', :js do - describe 'sub-groups' do - let(:ide_iframe_selector) { '#ide iframe' } - let(:user) { create(:user) } - let(:group) { create(:group) } - let(:subgroup) { create(:group, parent: group) } - let(:subgroup_project) { create(:project, :repository, namespace: subgroup) } + include WebIdeSpecHelpers + + let_it_be(:ide_iframe_selector) { '#ide iframe' } + let_it_be(:normal_project) { create(:project, :repository) } + + let(:project) { normal_project } + let(:vscode_ff) { false } + let(:user) { create(:user) } + + before do + project.add_maintainer(user) + stub_feature_flags(vscode_web_ide: vscode_ff) + + sign_in(user) + end + + shared_examples "legacy Web IDE" do + it 'loads legacy Web IDE', :aggregate_failures do + expect(page).to have_selector('.context-header', text: project.name) + + # Assert new Web IDE is not loaded + expect(page).not_to have_selector(ide_iframe_selector) + end + end + + shared_examples "new Web IDE" do + it 'loads new Web IDE', :aggregate_failures do + expect(page).not_to have_selector('.context-header') + + iframe = find(ide_iframe_selector) + + page.within_frame(iframe) do + expect(page).to have_selector('.title', text: project.name.upcase) + end + end + end + context 'with vscode feature flag off' do before do - stub_feature_flags(vscode_web_ide: vscode_ff) - subgroup_project.add_maintainer(user) - sign_in(user) + ide_visit(project) + end - visit project_path(subgroup_project) + it_behaves_like 'legacy Web IDE' - click_link('Web IDE') + it 'does not show switch button' do + expect(page).not_to have_button('Switch to new Web IDE') + end + 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) } - wait_for_requests + before do + ide_visit(project) end - context 'with vscode feature flag on' do - let(:vscode_ff) { true } + it_behaves_like 'legacy Web IDE' - it 'loads project in Web IDE' do - iframe = find(ide_iframe_selector) + describe 'when user switches to new Web IDE' do + before do + click_button('Switch to new Web IDE') - page.within_frame(iframe) do - expect(page).to have_selector('.title', text: subgroup_project.name.upcase) + # Confirm modal + page.within('#confirmationModal') do + click_button('Switch editors') end end + + it_behaves_like 'new Web IDE' end + end - context 'with vscode feature flag off' do - let(:vscode_ff) { false } + describe 'sub-groups' do + let_it_be(:group) { create(:group) } + let_it_be(:subgroup) { create(:group, parent: group) } + let_it_be(:subgroup_project) { create(:project, :repository, namespace: subgroup) } - it 'loads project in legacy Web IDE' do - expect(page).to have_selector('.context-header', text: subgroup_project.name) - end + let(:project) { subgroup_project } - it 'does not load new Web IDE' do - expect(page).not_to have_selector(ide_iframe_selector) - end + before do + ide_visit(project) end + + it_behaves_like 'legacy Web IDE' end end diff --git a/spec/features/incidents/user_views_incident_spec.rb b/spec/features/incidents/user_views_incident_spec.rb index a669966502e..054a084ea9c 100644 --- a/spec/features/incidents/user_views_incident_spec.rb +++ b/spec/features/incidents/user_views_incident_spec.rb @@ -4,12 +4,16 @@ require "spec_helper" RSpec.describe "User views incident" do let_it_be(:project) { create(:project_empty_repo, :public) } - let_it_be(:user) { create(:user) } - let_it_be(:incident) { create(:incident, project: project, description: "# Description header\n\n**Lorem** _ipsum_ dolor sit [amet](https://example.com)", author: user) } - let_it_be(:note) { create(:note, noteable: incident, project: project, author: user) } + let_it_be(:guest) { create(:user) } + let_it_be(:developer) { create(:user) } + let_it_be(:user) { developer } + let(:author) { developer } + let(:description) { "# Description header\n\n**Lorem** _ipsum_ dolor sit [amet](https://example.com)" } + let(:incident) { create(:incident, project: project, description: description, author: author) } before_all do - project.add_developer(user) + project.add_developer(developer) + project.add_guest(guest) end before do @@ -18,57 +22,61 @@ RSpec.describe "User views incident" do visit(project_issues_incident_path(project, incident)) end - it { expect(page).to have_header_with_correct_id_and_link(1, "Description header", "description-header") } + specify do + expect(page).to have_header_with_correct_id_and_link(1, 'Description header', 'description-header') + end it_behaves_like 'page meta description', ' Description header Lorem ipsum dolor sit amet' describe 'user actions' do it 'shows the merge request and incident actions', :js, :aggregate_failures do + expected_href = new_project_issue_path(project, + issuable_template: 'incident', + issue: { issue_type: 'incident' }, + add_related_issue: incident.iid) + click_button 'Incident actions' - expect(page).to have_link('New related incident', href: new_project_issue_path(project, { issuable_template: 'incident', issue: { issue_type: 'incident' }, add_related_issue: incident.iid })) + expect(page).to have_link('New related incident', href: expected_href) expect(page).to have_button('Create merge request') expect(page).to have_button('Close incident') end - context 'when user is a guest' do - before do - project.add_guest(user) + context 'when user is guest' do + let(:user) { guest } - login_as(user) + context 'and author' do + let(:author) { guest } - visit(project_issues_incident_path(project, incident)) + it 'does not show the incident actions', :js do + expect(page).not_to have_button('Incident actions') + end end - it 'does not show the incident actions', :js, :aggregate_failures do - expect(page).not_to have_button('Incident actions') + context 'and not author' do + it 'shows incident actions', :js do + click_button 'Incident actions' + + expect(page).to have_link 'Report abuse' + end end end end context 'when the project is archived' do - before do + before_all do project.update!(archived: true) - visit(project_issues_incident_path(project, incident)) end - it 'hides the merge request and incident actions', :aggregate_failures do - expect(page).not_to have_link('New incident') - expect(page).not_to have_button('Create merge request') - expect(page).not_to have_link('Close incident') + it 'does not show the incident actions', :js do + expect(page).not_to have_button('Incident actions') end end describe 'user status' do - subject { visit(project_issues_incident_path(project, incident)) } - context 'when showing status of the author of the incident' do - it_behaves_like 'showing user status' do - let(:user_with_status) { user } - end - end + subject { visit(project_issues_incident_path(project, incident)) } - context 'when showing status of a user who commented on an incident', :js do it_behaves_like 'showing user status' do let(:user_with_status) { user } end diff --git a/spec/features/issuables/markdown_references/internal_references_spec.rb b/spec/features/issuables/markdown_references/internal_references_spec.rb index ab7c0ce2891..c5a8e9f367c 100644 --- a/spec/features/issuables/markdown_references/internal_references_spec.rb +++ b/spec/features/issuables/markdown_references/internal_references_spec.rb @@ -21,15 +21,17 @@ RSpec.describe "Internal references", :js do sign_in(private_project_user) visit(project_issue_path(private_project, private_project_issue)) + wait_for_requests add_note("##{public_project_issue.to_reference(private_project)}") end - context "when user doesn't have access to private project", quarantine: 'https://gitlab.com/gitlab-org/gitlab/-/issues/257832' do + context "when user doesn't have access to private project" do before do sign_in(public_project_user) visit(project_issue_path(public_project, public_project_issue)) + wait_for_requests end it { expect(page).not_to have_css(".note") } @@ -41,6 +43,7 @@ RSpec.describe "Internal references", :js do sign_in(private_project_user) visit(project_merge_request_path(private_project, private_project_merge_request)) + wait_for_requests add_note("##{public_project_issue.to_reference(private_project)}") end @@ -50,9 +53,10 @@ RSpec.describe "Internal references", :js do sign_in(public_project_user) visit(project_issue_path(public_project, public_project_issue)) + wait_for_requests end - it "doesn't show any references", quarantine: 'https://gitlab.com/gitlab-org/gitlab/-/issues/257832' do + it "doesn't show any references" do expect(page).not_to have_text 'Related merge requests' end end @@ -60,6 +64,7 @@ RSpec.describe "Internal references", :js do context "when user has access to private project" do before do visit(project_issue_path(public_project, public_project_issue)) + wait_for_requests end it "shows references", :sidekiq_might_not_need_inline do @@ -85,15 +90,17 @@ RSpec.describe "Internal references", :js do sign_in(private_project_user) visit(project_issue_path(private_project, private_project_issue)) + wait_for_requests add_note("##{public_project_merge_request.to_reference(private_project)}") end - context "when user doesn't have access to private project", quarantine: 'https://gitlab.com/gitlab-org/gitlab/-/issues/257832' do + context "when user doesn't have access to private project" do before do sign_in(public_project_user) visit(project_merge_request_path(public_project, public_project_merge_request)) + wait_for_requests end it { expect(page).not_to have_css(".note") } @@ -105,6 +112,7 @@ RSpec.describe "Internal references", :js do sign_in(private_project_user) visit(project_merge_request_path(private_project, private_project_merge_request)) + wait_for_requests add_note("##{public_project_merge_request.to_reference(private_project)}") end @@ -114,9 +122,10 @@ RSpec.describe "Internal references", :js do sign_in(public_project_user) visit(project_merge_request_path(public_project, public_project_merge_request)) + wait_for_requests end - it "doesn't show any references", quarantine: 'https://gitlab.com/gitlab-org/gitlab/-/issues/257832' do + it "doesn't show any references" do expect(page).not_to have_text 'Related merge requests' end end @@ -124,6 +133,7 @@ RSpec.describe "Internal references", :js do context "when user has access to private project" do before do visit(project_merge_request_path(public_project, public_project_merge_request)) + wait_for_requests end it "shows references", :sidekiq_might_not_need_inline do diff --git a/spec/features/issues/confidential_notes_spec.rb b/spec/features/issues/confidential_notes_spec.rb new file mode 100644 index 00000000000..858c054c803 --- /dev/null +++ b/spec/features/issues/confidential_notes_spec.rb @@ -0,0 +1,13 @@ +# frozen_string_literal: true + +require "spec_helper" + +RSpec.describe "Confidential notes on issues", :js do + it_behaves_like 'confidential notes on issuables' do + let_it_be(:issuable_parent) { create(:project) } + let_it_be(:issuable) { create(:issue, project: issuable_parent) } + let_it_be(:user) { create(:user) } + + let(:issuable_path) { project_issue_path(issuable_parent, issuable) } + end +end diff --git a/spec/features/issues/filtered_search/dropdown_assignee_spec.rb b/spec/features/issues/filtered_search/dropdown_assignee_spec.rb index 05eb656461e..40b0bfd9aa4 100644 --- a/spec/features/issues/filtered_search/dropdown_assignee_spec.rb +++ b/spec/features/issues/filtered_search/dropdown_assignee_spec.rb @@ -9,6 +9,10 @@ RSpec.describe 'Dropdown assignee', :js do let_it_be(:user) { create(:user) } let_it_be(:issue) { create(:issue, project: project) } + before do + stub_feature_flags(or_issuable_queries: false) + end + describe 'behavior' do before do project.add_maintainer(user) diff --git a/spec/features/issues/filtered_search/dropdown_author_spec.rb b/spec/features/issues/filtered_search/dropdown_author_spec.rb index 36a8f1f3902..a67d114c6d1 100644 --- a/spec/features/issues/filtered_search/dropdown_author_spec.rb +++ b/spec/features/issues/filtered_search/dropdown_author_spec.rb @@ -10,6 +10,7 @@ RSpec.describe 'Dropdown author', :js do let_it_be(:issue) { create(:issue, project: project) } before do + stub_feature_flags(or_issuable_queries: false) project.add_maintainer(user) sign_in(user) diff --git a/spec/features/issues/filtered_search/dropdown_hint_spec.rb b/spec/features/issues/filtered_search/dropdown_hint_spec.rb index dcbab308efa..cbe917931aa 100644 --- a/spec/features/issues/filtered_search/dropdown_hint_spec.rb +++ b/spec/features/issues/filtered_search/dropdown_hint_spec.rb @@ -10,6 +10,7 @@ RSpec.describe 'Dropdown hint', :js do let_it_be(:issue) { create(:issue, project: project) } before do + stub_feature_flags(or_issuable_queries: false) project.add_maintainer(user) end diff --git a/spec/features/issues/filtered_search/filter_issues_spec.rb b/spec/features/issues/filtered_search/filter_issues_spec.rb index 8d96bbc38cb..e48df1b1c53 100644 --- a/spec/features/issues/filtered_search/filter_issues_spec.rb +++ b/spec/features/issues/filtered_search/filter_issues_spec.rb @@ -19,6 +19,7 @@ RSpec.describe 'Filter issues', :js do end before do + stub_feature_flags(or_issuable_queries: false) project.add_maintainer(user) create(:issue, project: project, author: user2, title: "Bug report 1") diff --git a/spec/features/issues/filtered_search/visual_tokens_spec.rb b/spec/features/issues/filtered_search/visual_tokens_spec.rb index c44181a60e4..854b88c3f81 100644 --- a/spec/features/issues/filtered_search/visual_tokens_spec.rb +++ b/spec/features/issues/filtered_search/visual_tokens_spec.rb @@ -15,6 +15,7 @@ RSpec.describe 'Visual tokens', :js do let_it_be(:issue) { create(:issue, project: project) } before do + stub_feature_flags(or_issuable_queries: false) project.add_member(user, :maintainer) project.add_member(user_rock, :maintainer) sign_in(user) diff --git a/spec/features/issues/form_spec.rb b/spec/features/issues/form_spec.rb index e749c555dcf..fe591d7fe3a 100644 --- a/spec/features/issues/form_spec.rb +++ b/spec/features/issues/form_spec.rb @@ -140,14 +140,10 @@ RSpec.describe 'New/edit issue', :js do end expect(find('a', text: 'Assign to me', visible: false)).not_to be_visible - click_button 'Milestone' - page.within '.issue-milestone' do - click_link milestone.title - end + click_button 'Select milestone' + click_button milestone.title expect(find('input[name="issue[milestone_id]"]', visible: false).value).to match(milestone.id.to_s) - page.within '.js-milestone-select' do - expect(page).to have_content milestone.title - end + expect(page).to have_button milestone.title click_button 'Labels' page.within '.dropdown-menu-labels' do @@ -307,14 +303,11 @@ RSpec.describe 'New/edit issue', :js do end it 'escapes milestone' do - click_button 'Milestone' + click_button 'Select milestone' + click_button milestone.title page.within '.issue-milestone' do - click_link milestone.title - end - - page.within '.js-milestone-select' do - expect(page).to have_content milestone.title + expect(page).to have_button milestone.title expect(page).not_to have_selector 'img' end end @@ -444,9 +437,7 @@ RSpec.describe 'New/edit issue', :js do expect(page).to have_content user.name end - page.within '.js-milestone-select' do - expect(page).to have_content milestone.title - end + expect(page).to have_button milestone.title click_button 'Labels' page.within '.dropdown-menu-labels' do 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 4837d13574c..2a201e0bc23 100644 --- a/spec/features/issues/user_bulk_edits_issues_labels_spec.rb +++ b/spec/features/issues/user_bulk_edits_issues_labels_spec.rb @@ -417,7 +417,7 @@ RSpec.describe 'Issues > Labels bulk assignment' do click_button 'Select milestone' wait_for_requests items.map do |item| - click_link item + click_button item end end diff --git a/spec/features/issues/user_bulk_edits_issues_spec.rb b/spec/features/issues/user_bulk_edits_issues_spec.rb index 1ef2918adec..d7fad355cb4 100644 --- a/spec/features/issues/user_bulk_edits_issues_spec.rb +++ b/spec/features/issues/user_bulk_edits_issues_spec.rb @@ -80,7 +80,7 @@ RSpec.describe 'Multiple issue updating from issues#index', :js do click_button 'Edit issues' check 'Select all' click_button 'Select milestone' - click_link milestone.title + click_button milestone.title click_update_issues_button expect(page.find('.issue')).to have_content milestone.title @@ -97,7 +97,7 @@ RSpec.describe 'Multiple issue updating from issues#index', :js do click_button 'Edit issues' check 'Select all' click_button 'Select milestone' - click_link 'No milestone' + click_button 'No milestone' click_update_issues_button expect(find('.issue:first-of-type')).not_to have_text milestone.title diff --git a/spec/features/issues/user_comments_on_issue_spec.rb b/spec/features/issues/user_comments_on_issue_spec.rb index a1e7c007b90..ef00e66af7e 100644 --- a/spec/features/issues/user_comments_on_issue_spec.rb +++ b/spec/features/issues/user_comments_on_issue_spec.rb @@ -5,9 +5,9 @@ require "spec_helper" RSpec.describe "User comments on issue", :js do include Spec::Support::Helpers::Features::NotesHelpers - let(:project) { create(:project_empty_repo, :public) } - let(:issue) { create(:issue, project: project) } - let(:user) { create(:user) } + let_it_be(:project) { create(:project, :public) } + let_it_be(:issue) { create(:issue, project: project) } + let_it_be(:user) { create(:user) } before do project.add_guest(user) diff --git a/spec/features/issues/user_creates_issue_spec.rb b/spec/features/issues/user_creates_issue_spec.rb index b96490bd7e7..1d023a15159 100644 --- a/spec/features/issues/user_creates_issue_spec.rb +++ b/spec/features/issues/user_creates_issue_spec.rb @@ -188,7 +188,7 @@ RSpec.describe "User creates issue" do end it 'does not hide the milestone select' do - expect(page).to have_selector('[data-testid="issuable-milestone-dropdown"]') + expect(page).to have_button 'Select milestone' end end @@ -204,7 +204,7 @@ RSpec.describe "User creates issue" do end it 'shows the milestone select' do - expect(page).to have_selector('[data-testid="issuable-milestone-dropdown"]') + expect(page).to have_button 'Select milestone' end it 'hides the incident help text' do @@ -265,7 +265,7 @@ RSpec.describe "User creates issue" do end it 'shows the milestone select' do - expect(page).to have_selector('[data-testid="issuable-milestone-dropdown"]') + expect(page).to have_button 'Select milestone' end it 'hides the weight input' do diff --git a/spec/features/issues/user_edits_issue_spec.rb b/spec/features/issues/user_edits_issue_spec.rb index 4eecb63c47e..75df85f362f 100644 --- a/spec/features/issues/user_edits_issue_spec.rb +++ b/spec/features/issues/user_edits_issue_spec.rb @@ -101,6 +101,35 @@ RSpec.describe "Issues > User edits issue", :js do visit project_issue_path(project, issue) end + describe 'edit description' do + def click_edit_issue_description + click_on 'Edit title and description' + end + + it 'places focus on the web editor' do + toggle_editing_mode_selector = '[data-testid="toggle-editing-mode-button"] label' + content_editor_focused_selector = '[data-testid="content-editor"].is-focused' + markdown_field_focused_selector = 'textarea:focus' + click_edit_issue_description + + expect(page).to have_selector(markdown_field_focused_selector) + + find(toggle_editing_mode_selector, text: 'Rich text').click + + expect(page).not_to have_selector(content_editor_focused_selector) + + refresh + + click_edit_issue_description + + expect(page).to have_selector(content_editor_focused_selector) + + find(toggle_editing_mode_selector, text: 'Source').click + + expect(page).not_to have_selector(markdown_field_focused_selector) + end + end + describe 'update labels' do it 'will not send ajax request when no data is changed' do page.within '.labels' do @@ -186,7 +215,7 @@ RSpec.describe "Issues > User edits issue", :js do visit project_issue_path(project, issue) page.within('.assignee') do - expect(page).to have_content "#{user.name}" + expect(page).to have_content user.name.to_s click_link 'Edit' click_link 'Unassigned' @@ -261,7 +290,7 @@ RSpec.describe "Issues > User edits issue", :js do visit project_issue_path(project, issue) page.within('.assignee') do - expect(page).to have_content "#{user.name}" + expect(page).to have_content user.name.to_s click_button('Edit') wait_for_requests diff --git a/spec/features/issues/user_interacts_with_awards_spec.rb b/spec/features/issues/user_interacts_with_awards_spec.rb index 47b28b88108..a2dea7f048b 100644 --- a/spec/features/issues/user_interacts_with_awards_spec.rb +++ b/spec/features/issues/user_interacts_with_awards_spec.rb @@ -209,22 +209,25 @@ RSpec.describe 'User interacts with awards' do it 'adds award to issue' do first('[data-testid="award-button"]').click - + wait_for_requests expect(page).to have_selector('[data-testid="award-button"].selected') expect(first('[data-testid="award-button"]')).to have_content '1' visit project_issue_path(project, issue) + wait_for_requests expect(first('[data-testid="award-button"]')).to have_content '1' end it 'removes award from issue', quarantine: 'https://gitlab.com/gitlab-org/gitlab/-/issues/375241' do first('[data-testid="award-button"]').click + wait_for_requests find('[data-testid="award-button"].selected').click - + wait_for_requests expect(first('[data-testid="award-button"]')).to have_content '0' visit project_issue_path(project, issue) + wait_for_requests expect(first('[data-testid="award-button"]')).to have_content '0' end diff --git a/spec/features/issues/user_sees_empty_state_spec.rb b/spec/features/issues/user_sees_empty_state_spec.rb index 0e2a7cb4358..b4c5a57de4f 100644 --- a/spec/features/issues/user_sees_empty_state_spec.rb +++ b/spec/features/issues/user_sees_empty_state_spec.rb @@ -22,9 +22,9 @@ RSpec.describe 'Issues > User sees empty state', :js do it 'user sees empty state' do visit project_issues_path(project) + expect(page).to have_content('Use issues to collaborate on ideas, solve problems, and plan work') + expect(page).to have_content('Learn more about issues.') expect(page).to have_content('Register / Sign In') - expect(page).to have_content('The Issue Tracker is the place to add things that need to be improved or solved in a project.') - expect(page).to have_content('You can register or sign in to create issues for this project.') end it_behaves_like 'empty state with filters' diff --git a/spec/features/issues/user_sorts_issues_spec.rb b/spec/features/issues/user_sorts_issues_spec.rb index 7add6c782f7..2716d742be3 100644 --- a/spec/features/issues/user_sorts_issues_spec.rb +++ b/spec/features/issues/user_sorts_issues_spec.rb @@ -24,7 +24,7 @@ RSpec.describe "User sorts issues" do sign_in(user) end - it 'keeps the sort option', :js do + it 'keeps the sort option', :js, quarantine: 'https://gitlab.com/gitlab-org/gitlab/-/issues/378184' do visit(project_issues_path(project)) click_button 'Created date' diff --git a/spec/features/jira_connect/subscriptions_spec.rb b/spec/features/jira_connect/subscriptions_spec.rb index 94c293c88b9..0468cfd70fc 100644 --- a/spec/features/jira_connect/subscriptions_spec.rb +++ b/spec/features/jira_connect/subscriptions_spec.rb @@ -30,7 +30,7 @@ RSpec.describe 'Subscriptions Content Security Policy' do p.style_src :self, 'https://some-cdn.test' end - setup_existing_csp_for_controller(JiraConnect::SubscriptionsController, csp) + setup_csp_for_controller(JiraConnect::SubscriptionsController, csp) end it 'appends to CSP directives' do diff --git a/spec/features/markdown/sandboxed_mermaid_spec.rb b/spec/features/markdown/sandboxed_mermaid_spec.rb index 05fe83b3107..2bf88d7882d 100644 --- a/spec/features/markdown/sandboxed_mermaid_spec.rb +++ b/spec/features/markdown/sandboxed_mermaid_spec.rb @@ -3,30 +3,54 @@ require 'spec_helper' RSpec.describe 'Sandboxed Mermaid rendering', :js do - let_it_be(:project) { create(:project, :public) } + let_it_be(:project) { create(:project, :public, :repository) } + let_it_be(:description) do + <<~MERMAID + ```mermaid + graph TD; + A-->B; + A-->C; + B-->D; + C-->D; + ``` + MERMAID + end - before do - stub_feature_flags(sandboxed_mermaid: true) + let_it_be(:expected) do + %(